AlexWang

合并延迟

此 diff 太大无法显示。
... ... @@ -22,6 +22,8 @@ import CursorApe from 'apes/CursorApe';
import EngineUtils from "EngineUtils";
import GlobalConfig from 'GlobalConfig';
import SystemConfig from 'SystemConfig';
import ApeConsts from 'apes/ApeConsts';
import Base64 from 'base64-js';
import ArrayBufferUtil from 'libs/ArrayBufferUtil';
... ... @@ -30,11 +32,10 @@ import MediaModule from 'apes/MediaModule';
import MediaSharedApe from 'apes/MediaSharedApe';
import MusicSharedApe from 'apes/MusicSharedApe';
import QuestionApe from 'apes/QuestionApe';
import mdetect from "mdetect";
import UTF8 from 'utf-8';
let loger = Loger.getLoger('McuClient');
let _sdkInfo = { "version": "v1.40.0.20170706", "author": "www.3mang.com" };
let _sdkInfo = { "version": "v1.45.1.20170717", "author": "www.3mang.com" };
//APE
let _sass;
... ... @@ -59,14 +60,10 @@ export default class MessageEntrance extends Emiter {
//sdk 信息
this.sdkInfo = _sdkInfo;
loger.warn(this.sdkInfo);
//检查是否是移动端
GlobalConfig.isMobile = mdetect.isMobileUA();
if (GlobalConfig.isMobile) {
loger.warn("当前设备是移动设备");
} else {
loger.warn("当前设备是PC");
}
//获取设备和系统信息
SystemConfig.getSystemInfo();
this.classRecordStatusUpdateTimer=0;//课堂录制状态发生改变后同步当前所有模块数据的计时器
//初始化状态
this.isGetUserIpCallback = false; //是否获取IP信息返回
this.isGetFastestMcuCallback = false; //是否MCU选点结束
... ... @@ -253,6 +250,7 @@ export default class MessageEntrance extends Emiter {
this.switchMediaServer = this._switchMediaServer.bind(this); //手动切换ms服务器
this.setDebugInfo = this._setDebugInfo.bind(this); //设置debug信息
}
_setDebugInfo(_data) {
loger.log("设置debug信息-->", _data);
if (_data) {
... ... @@ -263,14 +261,6 @@ export default class MessageEntrance extends Emiter {
_setDeviceInfo(_data) {
loger.log("设置设备信息-->", _data);
if (_data) {
/* GlobalConfig.videoQuality=_data.videoQuality||2;//画面质量 0-低;1-中;2-高;
GlobalConfig.cameras=_data.cameras||[];//摄像头列表
GlobalConfig.microphones=_data.microphones||[];//麦克风列表
GlobalConfig.curCamera=_data.curCamera||'';//当前选择的摄像头
GlobalConfig.curMicrophone=_data.curMicrophone||'';//当前选择的麦克风
GlobalConfig.curVideoQuality=_data.curVideoQuality||2;//当前选择的分辨率
GlobalConfig.micGain=_data.micGain||50;//音量(0-80)*/
GlobalConfig.cameras = _data.cameras || [];
GlobalConfig.microphones = _data.microphones || [];
GlobalConfig.videoQuality = parseInt(_data.videoQuality);
... ... @@ -356,7 +346,13 @@ export default class MessageEntrance extends Emiter {
//开启录制成功
_onClassRecordSuccess(_param) {
this.updaterRecordAllApeStatus(_param);
clearTimeout(this.classRecordStatusUpdateTimer);
let _this=this;
this.classRecordStatusUpdateTimer=setTimeout(function(){
clearTimeout(this.classRecordStatusUpdateTimer);
_this.updaterRecordAllApeStatus(_param);
},2000);
}
//录制状态发送改变,更新所有模块的当前数据发送到MCU
... ... @@ -803,6 +799,13 @@ export default class MessageEntrance extends Emiter {
joinClassSuccessCallBackData.ssTunnelAppURL = GlobalConfig.ssTunnelAppURL;
joinClassSuccessCallBackData.currentSceneTableId = GlobalConfig.currentSceneTableId; //文档区域的模块显示
joinClassSuccessCallBackData.serverAndLoacTimeDistanc = GlobalConfig.serverAndLoacTimeDistanc;
joinClassSuccessCallBackData.deviceType = GlobalConfig.deviceType;
joinClassSuccessCallBackData.language = GlobalConfig.language;
joinClassSuccessCallBackData.explorer = GlobalConfig.explorer;
joinClassSuccessCallBackData.explorerVersion = GlobalConfig.explorerVersion;
joinClassSuccessCallBackData.os = GlobalConfig.os;
loger.log('加入课堂成功->');
loger.log(joinClassSuccessCallBackData);
... ... @@ -1274,6 +1277,8 @@ export default class MessageEntrance extends Emiter {
try {
GlobalConfig.setClassStatusInfo(JSON.parse(_data.currentInfo));
} catch (err) {
loger.warn("从Sass获取的课堂数据JSON转换失败->");
console.log("currentInfo",_data.currentInfo);
GlobalConfig.setClassStatusInfo(_data.currentInfo);
}
loger.log(GlobalConfig.classStatusInfo);
... ... @@ -1630,10 +1635,12 @@ export default class MessageEntrance extends Emiter {
//文档加入频道成功,同步到MCU服务器上的数据
docJoinChannelSuccess() {
loger.log("docJoinChannelSuccess->isHost=", GlobalConfig.isHost, "length=", GlobalConfig.docListPrepare.length);
loger.log("docJoinChannelSuccess->isHost=", GlobalConfig.isHost,"当前总人数:",GlobalConfig.rosterNumber, "sassDoclength=", GlobalConfig.docListPrepare.length);
//loger.log("docJoinChannelSuccess docListPrepare=");
//如果是主持人,那么需要判断一下文档模块同步的数据和从sass获取的文档数据是否相同,如果mcu服务器不存在的,需要上传
if (GlobalConfig.isHost && GlobalConfig.docListPrepare.length > 0) {
if(GlobalConfig.docListPrepare&& GlobalConfig.docListPrepare.length > 0){
//如果当前身份是老师或者当前课堂内只有一个人,有权限同步文档到MCU
if (GlobalConfig.isHost||GlobalConfig.rosterNumber<=1) {
for (let i = 0; i < GlobalConfig.docListPrepare.length; i++) {
let value = GlobalConfig.docListPrepare[i];
if (value) {
... ... @@ -1654,6 +1661,7 @@ export default class MessageEntrance extends Emiter {
}
}
}
}
//媒体共享模块的接口
//上传
... ... @@ -2002,6 +2010,13 @@ export default class MessageEntrance extends Emiter {
joinClassSuccessCallBackData.ssTunnelAppURL = GlobalConfig.ssTunnelAppURL;
joinClassSuccessCallBackData.currentSceneTableId = GlobalConfig.currentSceneTableId; //文档区域的模块显示
joinClassSuccessCallBackData.serverAndLoacTimeDistanc = GlobalConfig.serverAndLoacTimeDistanc;
joinClassSuccessCallBackData.deviceType = GlobalConfig.deviceType;
joinClassSuccessCallBackData.language = GlobalConfig.language;
joinClassSuccessCallBackData.explorer = GlobalConfig.explorer;
joinClassSuccessCallBackData.explorerVersion = GlobalConfig.explorerVersion;
joinClassSuccessCallBackData.os = GlobalConfig.os;
loger.log(joinClassSuccessCallBackData);
//和加入课堂成功使用同样的消息处理
this._emit(MessageTypes.CLASS_JOIN_SUCCESS, joinClassSuccessCallBackData);
... ...
... ... @@ -133,15 +133,19 @@ class GlobalConfig {
this.classStopTime = data.classStopTime || this.classStopTime; //最后一次停止的时间(点暂停或结束),每次发送数据都获取当前时间戳
this.classTimestamp = data.classTimestamp || this.classTimestamp; //相对于点开始课堂的时间戳
// 全局禁言状态
this.silence = data.silence || false;
this.silenceUsers = JSON.parse(data.silenceUsers || '{}');
this.recordStatus = data.recordStatus || this.recordStatus; //当前录制状态
this.recordTimestamp = data.recordTimestamp || this.recordTimestamp; //相对于首次开始录制的时间戳
this.recordFileName = data.recordFileName || this.recordFileName; //录制的文件名
this.recordDownloadUrl = data.recordDownloadUrl || this.recordDownloadUrl; //下载地址
this.currentSceneTableId = data.currentSceneTableId || 0; //文档区域的模块显示
// 全局禁言状态
this.silence = data.silence || false;
this.silenceUsers =data.silenceUsers || {};
if((typeof this.silenceUsers =='string')&& this.silenceUsers .constructor==String){
this.silenceUsers={};
}
}
// 判断自己是否主持人角色
... ... @@ -364,7 +368,7 @@ GlobalConfig.maxMediaChannels = 0; //最大音视频路数,以音视频路数
GlobalConfig.hasCamera = false; //摄像头是否可用
GlobalConfig.hasMicrophone = false; //麦克风是否可用
GlobalConfig.deviceType = 0; //设备类型 0:电脑 1:安卓 2:ios
GlobalConfig.deviceType = 0; //设备类型 0:电脑 1:ios 2:安卓
GlobalConfig.userIp = ""; //用户当前IP
GlobalConfig.userId = 0;
GlobalConfig.userName = "";
... ... @@ -375,8 +379,8 @@ GlobalConfig.openMicrophones = 0;
//视频质量相关设置
GlobalConfig.fps = 15; //帧频
GlobalConfig.gop = 3; //关键帧间隔(秒)
GlobalConfig.videoQuality = 2; //画面质量 0-低;1-中;2-高;
GlobalConfig.curVideoQuality = 2; //当前分辨率
GlobalConfig.videoQuality = 1; //画面质量 0-低;1-中;2-高;
GlobalConfig.curVideoQuality = 1; //当前分辨率
GlobalConfig.cameras = []; //摄像头列表
GlobalConfig.microphones = []; //麦克风列表
... ... @@ -476,6 +480,13 @@ GlobalConfig.ssTunnelAppURL = ''; //屏幕共享插件的地址
GlobalConfig.serverTime = 0; //服务器当前时间戳
GlobalConfig.serverAndLoacTimeDistanc = 0; //本地时间和服务器时间错的差值;
GlobalConfig.rosterNumber=0;//当前总人数
GlobalConfig.isMobile = false; //是否是移动端
GlobalConfig.language="";//浏览器语言
GlobalConfig.platform="pc";//平台 IOS/ANDROID/PC
GlobalConfig.explorer="未知";//浏览器
GlobalConfig.explorerVersion="未知";//浏览器版本
GlobalConfig.os="未知";//系统
export default GlobalConfig;
... ...
/*
* 全局数据管理
* */
import Loger from 'Loger';
import mdetect from "mdetect";
import GlobalConfig from 'GlobalConfig';
let loger = Loger.getLoger('SystemConfig');
class SystemConfig {
constructor() {
}
//获取系统信息
static getSystemInfo(){
//检查是否是移动端
GlobalConfig.isMobile = mdetect.isMobileUA();
if (GlobalConfig.isMobile) {
loger.warn("当前设备是移动设备");
} else {
loger.warn("当前设备是PC");
}
if(mdetect.isIOS()){
GlobalConfig.deviceType=1;//"ios";
} if(mdetect.isAndroid()){
GlobalConfig.platform=2;//"android";
}else {
GlobalConfig.platform=0;//"pc";
}
//语言
GlobalConfig.language ="unknown";
if(navigator){
let language=navigator.language || navigator.browserLanguage;
GlobalConfig.language = language.toLocaleLowerCase();
}
let browserInfo=this.getBrowserInfo();
GlobalConfig.explorer=browserInfo.explorer||"未知";
GlobalConfig.explorerVersion=browserInfo.explorerVersion||"未知";
GlobalConfig.os=this.detectOS();
loger.log("deviceType:"+GlobalConfig.deviceType);
loger.log("language:"+GlobalConfig.language);
loger.log("explorer:"+GlobalConfig.explorer);
loger.log("explorerVersion:"+GlobalConfig.explorerVersion);
loger.log("os:"+GlobalConfig.os);
}
//获取浏览器和信息
static getBrowserInfo(){
var Sys = {};
var ua = navigator.userAgent.toLowerCase();
var re =/(trident|msie|firefox|chrome|opera|version).*?([\d.]+)/;
var m = ua.match(re);
Sys.explorer = m[1].replace(/version/, "'safari");
//判断是否是IE11
if(Sys.explorer=="trident"){
Sys.explorer="IE11"
Sys.explorerVersion = "11.0";
}else if(Sys.explorer=="msie"){
//IE
Sys.explorer="IE"
Sys.explorerVersion = m[2];
}else {
//非IE
Sys.explorerVersion = m[2];
}
return Sys;
}
//系统信息
static detectOS() {
var sUserAgent = navigator.userAgent;
var isWin = (navigator.platform == "Win32") || (navigator.platform == "Windows");
var isMac = (navigator.platform == "Mac68K") || (navigator.platform == "MacPPC") || (navigator.platform == "Macintosh") || (navigator.platform == "MacIntel");
if (isMac) return "Mac";
var isUnix = (navigator.platform == "X11") && !isWin && !isMac;
if (isUnix) return "Unix";
var isLinux = (String(navigator.platform).indexOf("Linux") > -1);
if (isLinux) return "Linux";
if (isWin) {
var isWin2K = sUserAgent.indexOf("Windows NT 5.0") > -1 || sUserAgent.indexOf("Windows 2000") > -1;
if (isWin2K) return "Win2000";
var isWinXP = sUserAgent.indexOf("Windows NT 5.1") > -1 || sUserAgent.indexOf("Windows XP") > -1;
if (isWinXP) return "WinXP";
var isWin2003 = sUserAgent.indexOf("Windows NT 5.2") > -1 || sUserAgent.indexOf("Windows 2003") > -1;
if (isWin2003) return "Win2003";
var isWinVista= sUserAgent.indexOf("Windows NT 6.0") > -1 || sUserAgent.indexOf("Windows Vista") > -1;
if (isWinVista) return "WinVista";
var isWin7 = sUserAgent.indexOf("Windows NT 6.1") > -1 || sUserAgent.indexOf("Windows 7") > -1;
if (isWin7) return "Win7";
}
return "other";
}
}
export default SystemConfig;
... ...
... ... @@ -143,6 +143,12 @@ class ConferApe extends Ape {
//用户当前选择的MS
nodeInfoRecordPdu.msIpPort = GlobalConfig.MS_PUBLISH_IP + ":" + GlobalConfig.MS_PUBLISH_PORT;
nodeInfoRecordPdu.deviceType = GlobalConfig.deviceType;
nodeInfoRecordPdu.language = GlobalConfig.language;
nodeInfoRecordPdu.explorer = GlobalConfig.explorer;
nodeInfoRecordPdu.explorerVersion = GlobalConfig.explorerVersion;
nodeInfoRecordPdu.os = GlobalConfig.os;
return nodeInfoRecordPdu;
}
... ... @@ -259,7 +265,7 @@ class ConferApe extends Ape {
return;
}
loger.log('startRecord', "isHost", GlobalConfig.isHost, "recordStatus", GlobalConfig.recordStatus);
loger.warn('开启录制', "isHost", GlobalConfig.isHost, "recordStatus", GlobalConfig.recordStatus);
//如果是host
if (GlobalConfig.isHost) {
GlobalConfig.classStopTime = EngineUtils.creatTimestampStr();
... ... @@ -271,7 +277,7 @@ class ConferApe extends Ape {
//停止录制
stopRecord(isForce) {
loger.log('stopRecord', "isHost", GlobalConfig.isHost, "recordStatus", GlobalConfig.recordStatus);
loger.warn('停止录制', "isHost", GlobalConfig.isHost, "recordStatus", GlobalConfig.recordStatus);
if (isForce && isForce == true) {
//强制停止,可以是host之外的身份(比如当前课堂老师异常退出,没有老师,会随机选择一个人来做释放操作)
if (GlobalConfig.recordStatus) {
... ... @@ -609,10 +615,16 @@ class ConferApe extends Ape {
tableUpdateHandler(owner, itemIdx, itemData) {
try {
let model = this.unPackPdu(owner, itemIdx, itemData);
loger.log('课堂数据更新->', model);
console.log('课堂数据更新->', model);
//处理课堂更新的信息
if (model && model.classStatusInfo) {
try{
model.classStatusInfo.silenceUsers=JSON.parse( model.classStatusInfo.silenceUsers);
}catch (err){
}
GlobalConfig.setClassStatusInfo(model.classStatusInfo);
if (model.classStatusInfo.isStopAllPublishMedia) {
... ... @@ -778,6 +790,7 @@ class ConferApe extends Ape {
//自己加入的时候,需要做一下判断操作,如果满足以下3个条件就要暂停课堂:
// 1.当前课堂只有自己;2.自己的身份不是host;3当前的课堂状态为(CLASS_STATUS_STARTED= 1;//直播中)
let rosterLen = Object.keys(this.rosters).length;
GlobalConfig.rosterNumber=rosterLen;//记录当前的总人数
if (rosterLen < 1 && !GlobalConfig.isHost && GlobalConfig.classStatus == ApeConsts.CLASS_STATUS_STARTED) {
loger.warn("当前课堂没有老师->暂停课堂");
this.pauseClass({ isForce: true });
... ...
... ... @@ -623,10 +623,19 @@ class DocApe extends Ape {
//果当前没有显示的文档,默认选择一个显示文档
_showDefaultDoc() {
//显示默认文档条件->1.非录制回放状态下 2.只有host有权限操作 3.当前激活的文档id不为0
/*//显示默认文档条件->1.非录制回放状态下 2.只有host有权限操作 3.当前激活的文档id不为0
if (GlobalConfig.isRecordPlayBack || !GlobalConfig.isHost || GlobalConfig.activeDocId > 0) {
return;
}
*/
//非录制回放状态下和当前激活的文档id不为0的时候也不能操作
if (GlobalConfig.isRecordPlayBack || GlobalConfig.activeDocId > 0) {
return;
}
//如果自己不是老师,并且当前课堂内人数大于1,不能操作
if(!GlobalConfig.isHost&&GlobalConfig.rosterNumber>1){
return;
}
let tempDocItemIdx;//临时记录文档数据,用于显示默认文档
for (let key in this.docList) {
... ...
... ... @@ -123,6 +123,9 @@ class MediaModule {
return {"code": ApeConsts.RETURN_SUCCESS,
"data":"",
"mediaId":freeChannel,
"userId":GlobalConfig.userId,
"userName":GlobalConfig.userName,
"userRole":GlobalConfig.userRole,
"publishUrl": publishUrl
};
}
... ... @@ -161,6 +164,9 @@ class MediaModule {
};
return {"code": ApeConsts.RETURN_SUCCESS,
"data":"",
"userId":GlobalConfig.userId,
"userName":GlobalConfig.userName,
"userRole":GlobalConfig.userRole,
"mediaId":freeChannel,
"publishUrl": publishUrl
};
... ... @@ -202,6 +208,9 @@ class MediaModule {
return {"code": ApeConsts.RETURN_SUCCESS,
"data":"",
"mediaId":shareChannel,
"userId":GlobalConfig.userId,
"userName":GlobalConfig.userName,
"userRole":GlobalConfig.userRole,
"publishUrl": publishUrl,
"streamId":streamId
};
... ...
... ... @@ -298,7 +298,7 @@ class WhiteBoardApe extends Ape {
tableInsertHandler(owner, itemIdx, itemData) {
let whiteBoardModel = this.unPackPdu(owner, itemIdx, itemData);
loger.log('tableInsertHandler',"activeDocId->",GlobalConfig.activeDocId ,"parentId->", whiteBoardModel.parentId);
loger.log(whiteBoardModel);
//loger.log(whiteBoardModel);
if (whiteBoardModel) {
if (GlobalConfig.activeDocId == whiteBoardModel.parentId && GlobalConfig.activeDocCurPage == whiteBoardModel.curPageNo) {
//loger.log('显示新增的标注->');
... ...
... ... @@ -72,7 +72,7 @@ class MCU extends Emiter {
joinRequestPdu.type = 2;
joinRequestPdu.initiator = this.classInfo.nodeId;
joinRequestPdu.nodeType = PduConsts.NT_TERMINAL; //normal
joinRequestPdu.classDescription = descriptorPdu; // classDescription
joinRequestPdu.classDescription = descriptorPdu;// classDescription
let pduMsg = pdu.create_join_class_request_pdu(
joinRequestPdu.type,
... ... @@ -86,7 +86,7 @@ class MCU extends Emiter {
PduConsts.SEG_ONCE
);
pduMsg.set("site", this.classInfo.siteId); //课堂号对应的名称
pduMsg.set("site", this.classInfo.siteId);//课堂号对应的名称
pduMsg.set("userId", this.classInfo.userId);
pduMsg.set("userName", Base64.fromByteArray(ArrayBufferUtil.strToUint8Array(this.classInfo.userName)));
pduMsg.set("userRole", this.classInfo.userRole);
... ... @@ -210,7 +210,7 @@ class MCU extends Emiter {
this.classInfo = _classInfo;
// 创建刷新nodeId
this.classInfo.nodeId = EngineUtils.creatSoleNumberFromTimestamp();
GlobalConfig.nodeId = this.classInfo.nodeId; //这是标识自己身份的id
GlobalConfig.nodeId = this.classInfo.nodeId;//这是标识自己身份的id
let nodeInfoRecordPdu = new pdu['RCNodeInfoRecordPdu'];
nodeInfoRecordPdu.name = this.classInfo.userName;
... ... @@ -223,9 +223,16 @@ class MCU extends Emiter {
nodeInfoRecordPdu.openMicrophones = 0;
nodeInfoRecordPdu.microphones = GlobalConfig.microphones;
nodeInfoRecordPdu.cameras = GlobalConfig.cameras;
nodeInfoRecordPdu.videoQuality = GlobalConfig.videoQuality; //设置分辨率的
nodeInfoRecordPdu.videoQuality = GlobalConfig.videoQuality;//设置分辨率的
nodeInfoRecordPdu.userIp = GlobalConfig.userIp;
nodeInfoRecordPdu.deviceType = GlobalConfig.deviceType;
nodeInfoRecordPdu.language = GlobalConfig.language;
nodeInfoRecordPdu.explorer = GlobalConfig.explorer;
nodeInfoRecordPdu.explorerVersion = GlobalConfig.explorerVersion;
nodeInfoRecordPdu.os = GlobalConfig.os;
let conferenceRecord = {}; //RCConferenceRecord_T
conferenceRecord._conference_id = this.classInfo.classId;
conferenceRecord._top_node_id = this.classInfo.topNodeID;
... ...
... ... @@ -891,7 +891,7 @@ message RCNodeInfoRecordPdu {
optional bytes user_data = 8;
optional string user_id = 9;
optional uint32 handUpTime = 10;
optional uint32 deviceType = 11;
optional uint32 deviceType = 11;//设备类型,0:pc 1:ios 2:安卓
optional uint32 mobileDirection = 12;
repeated string microphones = 13;
repeated string cameras = 14;
... ... @@ -912,6 +912,10 @@ message RCNodeInfoRecordPdu {
repeated MsListItemPdu msList = 29;
optional string selfSilence = 30;
optional string msIpPort = 31;
optional string language = 32;//系统语言
optional string explorer = 33;//浏览器
optional string explorerVersion = 34;//浏览器版本
optional string os = 35;//系统版本
}
message RCVotingPollSettingsPdu {
... ...