考生端、监考端集成示例源码

本文为您介绍远程监考考生端、监考端的代码示例及集成说明。

项目构成

本次开源代码包含两个前端仓库:

  1. 监考端:exam-invigilator

  2. 考生端:exam-examinee

前提条件

已接入、运行、部署开源的Appserver服务。具体操作,请参见服务端集成示例源码

已创建OSS Bucket,并配置好直播推拉流域名。如未配置,请参见控制台创建存储空间快速开始视频直播完成Bucket与推拉流域名配置。

项目框架

本项目使用UmiJS框架开发,技术栈为React+TypeScript。详细说明请参见UmiJS 官方文档

项目运行

开源项目地址

项目地址:阿里云考场场景方案

准备环境

安装Node环境,详细信息请参见UmiJS 快速上手教程

配置AppServer的地址

修改src/config.ts里的 appServer 配置项,将其填写为您的服务端域名和路径前缀,更多配置项请参考下文扩展配置项章节。

 // 配置 APPServer
  appServer: {
    origin: "", // 配置 APPServer 服务域名,例子: https://xxx.xxx.xxx,结尾请勿包含 /
    apiPrefixPath: "/exam/", // 配置api接口路径前缀
  },

创建考场生成体验链接

远程监控Web开源项目不包含考试管理、考场管理、用户管理等业务功能,需要您根据开源的AppServer 自行实现。本地开发时,监考端、考生端正常运行需要通过URL传入roomId(考场ID)、userId(用户ID)、token(身份检验字符串)。因此,你首先需要通过服务端createRoom 接口(详情见服务端接口文档)创建一个考场,创建成功后返回的ID即为考场ID、createTeacher为监考员ID;而 userId、token 是需要您自行实现,开源工程中并不会校验token,随意传入字符串即可,userId设定为examinee1 、examinee2至 examinee5。

若创建考场接口返回的数据如下所示:

{
  "success":true,
  "data":{
    "id":"12345",
    "createdAt":"2023-10-20T14:34:40+08:00",
    "updatedAt":"2023-10-20T14:34:40+08:00",
    "name":"test exam",
    "examId":"12345",
    "status":0,
    "audioStatus":0,
    "imGroupId":"12345",
    "createTeacher":"teacher1"
  }
}

则本地体验URL为:

// 若考生端本地服务端口为 8001,则体验地址为
http://localhost:8001?roomId=12345&userId=examinee1&token=xxxx

// 若监考端本地服务端口为 8002,则体验地址为
http://localhost:8002?roomId=12345&userId=teacher1&token=xxxx&role=0

考场链接生成脚本

我们还开源了创建考场的脚本,脚本为监考端工程内的script/genroom.mjs文件。在运行项目前需要先生成考场的URL,具体操作步骤如下。

  1. 打开监考端工程内的script/genroom.mjs文件,并将您的AppServer域名赋值给apiOrigin变量,根据具体监考端和考生端项目的运行端口号修改对应的变量。

    // 请输入您的服务端的域名,结尾请勿是 /
    const apiOrigin = '';
    // 监考端域名,请根据您的实际情况更改,特别是本地运行时,要注意监考端的端口是否一致
    const invigilatorBasePath = 'http://localhost:8000';
    // 考生端域名,请根据您的实际情况更改,特别是本地运行时,要注意考生端的端口是否一致
    const examineeBasePath = 'http://localhost:8001';
  2. 执行如下命令,运行genroom.mjs脚本生成本地体验URL,

    npm install axios --save
    node script/genroom.mjs
  3. 得到的体验格式如下。

    监考端体验地址 ->  http://localhost:8000?roomId=***&userId=teacher&token=xxx&role=0
    考生端副机位体验地址 ->  http://localhost:8001?roomId=***&userId=examinee1&token=xxxx
    考生端主机位体验地址 ->  http://localhost:8001?roomId=***&userId=examinee1&token=xxxx#/pc

    其中8000端口对应的是监考端项目的运行端口,8001端口对应的是考生端项目的运行端口,开发者可以根据自己项目的运行端口号进行调整。

推流/播放地址规则说明

在远程监考的集成过程中,考生画面的推流/播放地址、老师音频的推流/播放地址均需要您按照一定的规则进行生成,本节为您介绍远程监考的推流/播放地址生成规则。

  1. 了解阿里云推流和播放地址格式。详细说明,请参见生成推流地址和播放地址鉴权代码示例

  2. 基于阿里云的客户服务经验,推荐您使用如下格式。

    • 考生画面的推流地址:artc://webrtcpush.example.com/appname/examid-roomid-userid?token=*********

      • appname:通常是一个固定值,如您的应用名称或公司名称等。您需要设置的appname需要与上文配置的录制模板、转码模板指定的appname一致,此时录制和转码才会生效。

      • examid:建议设置为本场考试编号。

      • roomid:某场考试中,具体某个考场的编号。

      • userid:具体参与考试的用户编号。

    • 考生画面的播放地址(原始画面):artc://webrtcpull.example.com/appname/examid-roomid-userid?token=*********。

    • 考生画面的播放地址(转码后的画面): artc://webrtcpull.example.com/appname/examid-roomid-userid_templateName?token=*********。

    • templateName为上文您设置的转码模板的名称。

    • 老师音频的推流地址:artc://webrtcpush.example.com/appname/examid-roomid-userid?token=*********。

    • 老师音频的播放地址:artc://webrtcpull.example.com/appname/examid-roomid-userid?token=*********。

运行项目

按照以下步骤进行操作:

  1. 参考考场链接生成脚本,生成体验考场及对应监考端和考生端页面的体验URL。

  2. 先在监考端工程中运行如下指令,然后在考生端工程中运行如下指令。

    // 安装 npm 包
    npm install
    
    // 安装完成后,执行 dev 指令,运行成功后根据提示使用浏览器访问即可
    npm run dev

    运行成功,界面如下。

    image

    image

  3. 复制第一步生成的URL到浏览器中打开即可开始体验。

构建配置

// 运行build指令即可构建最终产物至./dist目录下
npm run build

构建的文件主要包括index.html、umi.js和umi.css,其余的是按需加载的资源文件。您可以将生成的./dist目录下的所有文件上传至您的服务器或CDN服务中,也可以使用您的内部部署系统进行部署。

您需要根据您的实际情况,配置位于根目录下的 .umirc.ts文件中的publicPath参数。

  • 若您最终访问的页面是单独加载生成的js、css资源,则无需配置publicPath。

  • 若需直接使用index.html,请参考以下示例,并根据您的实际情况进行配置。

import fs from 'fs';
import path from 'path';

const packagejson = fs.readFileSync(path.resolve('./package.json'));
const json = JSON.parse(packagejson.toString());

export default {
  // 省略其他配置参数

  // 生成的 index.html 里使用的umi.js 、umi.css地址的公共路径的默认值是 /
  // 若 index.html 部署的地址是 http://g.alicdn.com/publicPath/exam/0.0.1/index.html
  // 若不配置 publicPath 直接访问测试、线上环境 index.html,所加载的umi.js将会是 http://g.alicdn.com/umi.js
  // 显然不是跟index.html目录下了,所以请根据您实际情况配置为真实路径 或者使用相对路径 ./
  // 例子中使用了项目的name 、version在部署目录中,请根据您实际情况配置
  publicPath:
    process.env.NODE_ENV === 'production'
      ? `/publicPath/${json.name}/${json.version}/`
      : './',
}

扩展配置项

在远程监考系统中,考生端和监考端的功能配置项均存储在对应项目中的src/config.ts文件中,您可以根据实际业务需求进行配置,具体说明如下:

考生端

const config: IConfig = {
  aliyunUid: "",
  // pagePath当前用于本地开发调试时设置PC考生页上的副机位二维码的 url
  pagePath: "",
  // 配置 APPServer
  appServer: {
    origin: "", // 配置 APPServer 服务域名,例子: https://xxx.xxx.xxx
    apiPrefixPath: "/exam/", // 配置api接口路径前缀
  },
  // 配置日志服务
  reporter: {
    enable: false, // 是否开启埋点
    host: "", // 所在地域的服务入口
    projectName: "", // sls 的工程名称
    logstore: "", // sls 的 logstore
  },
  // 配置本地录制
  localRecorder: {
    enable: false, // 是否开启本地录制
    // 模式支持 OSS 或 VOD
    mode: "OSS",
    // OSS 模式时有用,注意:开头、结束字符必须要是 /
    // 若遇到 403 问题,检查服务端获取 STS 接口的 policy 里的仓库路径与 basePath 是否匹配
    basePath: "/record/local/",
    // VOD 模式时有用
    vod: {
      region: "cn-shanghai",
      // 创建的额外参数,详情请看 https://help.aliyun.com/zh/vod/developer-reference/api-vod-2017-03-21-createuploadvideo#api-detail-35
      // 注意 Title、StorageLocation 这里设置无效,若有特殊要求,请至 VODUploader 文件中修改
      params: {
        Tags: "AUIExam",
      },
    },
  },
  // 防作弊服务配置项
  cheatDetect: { 
    licenseKey: "", // 防作弊 SDK 的 license
    licenseDomain: "", // 防作弊 SDK 允许运行的域名(localhost不受限制)
  },
  // 移动端摄像头切换模块的配置项
  mobileCameraSwitcher: {
    enable: false, // 是否展示该模块
  },
  // 默认摄像头流参数
  defaultVideoProfile: {
    name: "custom_360_800k", // 名称,可根据实际情况修改
    data: {
      // 低配低版本安卓手机,若高于 360P 可能取到的画面是黑屏
      // 正式考试时建议请勿配置高于 360P(640*360/360*640)
      width: 640, // 视频宽度
      height: 360, // 视频高度
      frameRate: 30, // 帧率
      maxBitrate: 800, // 最大码率
    },
  },
};

appServer

配置您部署的服务端appServer的域名和API前缀路径。

pagePath

当前页面的域名+路径,主要应用于主机位页面(src->pages->pc)本地开发调试时,设置进入考生移动端二维码的URL,当域名为localhost或127.0.0.1时,将自动替换为此配置值,其他情况则使用当前的origin+pathname。

aliyunUid

开通直播、点播、OSS等服务的阿里云userId(主账号的userid),当使用VOD上传时,该字段为必填项。

reporter

SLS日志的配置项。若要使用埋点统计功能,则需要将enable设为true,同时填写projectName、hostlogstore。有关projectName和logstore的获取方法,请参见快速入门

重要

使用SLS日志,将会产生相应费用。计费说明请参见按量付费

localRecorder

考生端还可以通过localRecorder设置是否开启本地录制功能。该功能在推流失败时(例如网络异常),会将本地音视频内容录制并存储在浏览器中,然后在有网络条件时上传至您配置的OSS Bucket。

支持OSS和VOD两种存储模式,请根据实际情况选择。两种模式的上传均使用STS临时授权方案。对于VOD模式,请参阅使用STS临时授权方案上传视频;对于OSS模式,请参阅使用STS临时访问凭证访问OSS 文档。

cheatDetect

在工程中,我们支持使用防作弊SDK来辅助远程监考。请查看远程监考智能防作弊SDK以了解其功能及购买License,并配置相应的licenseKey、licenseDomain等参数。

mobileCameraSwitcher

考生在移动端默认使用前置摄像头,如果您将enable参数设置为true,那么考生界面将支持切换前后摄像头。

defaultVideoProfile

您可以在此配置项中设置默认摄像头流的分辨率、码率和帧率。

监考端

const config: IConfig = {
  aliyunUid: "",
  // 配置 APPServer
  appServer: {
    origin: "", // 配置 APPServer 服务域名,例子: https://xxx.xxx.xxx,结尾请勿包含 /
    apiPrefixPath: "/exam/", // 配置api接口路径前缀
  },
  // 配置日志服务
  reporter: {
    enable: false, // 是否开启埋点
    host: "", // 所在地域的服务入口
    projectName: "", // sls 的工程名称
    logstore: "", // sls 的 logstore
  },
  // 防作弊检测消息相关功能
  detectList: {
    enable: true,
  },
  // 多机位配置项
  mutilMonitor: {
    enable: true, // 是否需要多机位,若不开启,则仅展示 mobile 副机位的流
    preferMainMonitor: true, // 是否优先展示 pc 主机位的流
  },
};

appServer

配置您部署的服务端appServer的域名和API前缀路径。

aliyunUid

开通直播、点播、OSS等服务的阿里云userId,注意是主账号的userid。

reporter

SLS日志的配置项。若要使用埋点统计功能,则需要将enable设为true,并填写projectName、hostlogstore。有关projectName和logstore的获取方法,请参见快速入门

重要

使用SLS日志,将会产生相应费用。计费说明,请参见按使用功能计费

detectList

如果考生端开启了防作弊检测,您可以在监考端启用此参数,启用后将在左侧显示疑似作弊消息列表模块。

mutilMonitor

监考端默认展示考生副机位(移动端)的画面。如果您需要支持切换至考生画面,并默认显示主机位(PC)画面,您可以使用enablepreferMainMonitor参数。

技术细节

本节为您介绍项目中的一些技术细节,方便您对源码进行修改,进行更具定制化的开发扩展。

主副机位

考生端目前支持同时打开主副机位两个页面,默认哈希路由 #/ 时为副机位,#/pc 时为主机位。

主机位

主机位页面是为考生正面监考,运行在 PC 设备上,包含环境设备检测页(路由:#/pc/deviceTest),以及 PC 监考页(路由:#/pc)。建议默认打开检测页(URL示例:localhost:8001?roomId=12345&userId=examinee1&token=xxxx#/pc/deviceTest),检测通过后将自测跳转 PC 监考页。

设备检测

image.png

image.png

如截图所示,正式进入考场时会对摄像头、麦克风、扬声器、屏幕共享这四项设备进行检测,通过后跳转 PC 监考页。

PC监考页

image.png

PC监考页左边侧边栏将展示当前 PC 摄像头的画面,底下为移动端副机位的二维码,当副机位监考页也进入推流后将加载移动端的画面。

考题区域需要由您根据您的实际情况进行开发。

副机位

副机位也称为侧机位,运行于移动端浏览器或 webview 中,考生扫主机位上的二维码即可进入(注意:本地开发时要配置 pagePath,或者直接在 PC 上打开本地的副机位页面)。

image.png

监考端

image.png

监考端支持切换查看考生的主副机位画面,当使用口播、连麦等功能时将于当前查看的机位进行通信。

重要类说明

工程中的src->core文件夹下的文件为核心逻辑,您可重点阅读以下类的源码。

  • core/Interaction.ts

    对阿里云互动消息SDK做二次封装,使更好地适配考试业务。详细说明,请参见互动消息SDK文档

  • core/RadioTimer.ts

    用于定时系统广播。

  • core/rts-publisher.ts

    推流组件src->components->rts->Publish中所用的核心推流逻辑,详细说明,请参见aliyun-rts-sdk文档

  • core/rts-subscriber.ts

    拉流组件src->components->rts->Subscribe中所用的核心拉流逻辑,详细说明,请参见aliyun-rts-sdk文档

  • core/AudioPlayer.ts

    用于iOS系统播放音频,解决部分iOS环境播放音频的异常。

  • utils/Reporter.ts

    用于埋点统计。

  • utils/LocalMock.ts

    用于本地开发初期提供mock数据,可以在页面URL上增加mock=1参数(例如:http://localhost:8000/?mock=1),那么就会使用到本地的mock数据。大部分数据都可以静态mock,有鉴权的推拉流地址需要替换。

    getIMToken方法中的accessToken字段需要设置为互动消息服务取到的Token,可参考互动消息建立长连接文档生成。