李勇

Merge branch 'mcuClientBranch'

此 diff 太大无法显示。
... ... @@ -141,7 +141,7 @@ export default class MessageEntrance extends Emiter {
this.getVideoPublishPath = this._getVideoPublishPath.bind(this);
this.getVideoAllChannelInfo = this._getVideoAllChannelInfo.bind(this);
this.publishVideo = this._publishVideo.bind(this);
this.stopPublishVideo = this._stopPublishVideo.bind(this);
this.stopPublishVideo =this.unPublishVideo= this._stopPublishVideo.bind(this);
this.sendVideoBroadcastMsg = this._sendVideoBroadcastMsg.bind(this);
... ... @@ -150,7 +150,7 @@ export default class MessageEntrance extends Emiter {
this.getAudioPublishPath = this._getPublishAudioPath.bind(this);
this.getAudioAllChannelInfo = this._getAudioAllChannelInfo.bind(this);
this.publishAudio = this._publishAudio.bind(this);
this.stopPublishAudio = this._stopPublishAudio.bind(this);
this.stopPublishAudio =this.unPublishAudio= this._stopPublishAudio.bind(this);
this.sendAudioBroadcastMsg = this.sendAudioCommandMsg.bind(this);
//whiteBoradApe
... ... @@ -296,10 +296,22 @@ export default class MessageEntrance extends Emiter {
GlobalConfig.isRecordPlayBack=false;//设置为非录制回放状态
GlobalConfig.classId = parseInt(_param.classId);
GlobalConfig.portal = _param.portal;
GlobalConfig.userRole = _param.userRole || ApeConsts.normal;
GlobalConfig.userId = _param.userId || "0";
GlobalConfig.userName = _param.userName || "";
//设置角色身份
GlobalConfig.userRole = _param.userRole || ApeConsts.normal;
if(GlobalConfig.userRole!=ApeConsts.host&&
GlobalConfig.userRole!=ApeConsts.presenter&&
GlobalConfig.userRole!=ApeConsts.assistant&&
GlobalConfig.userRole!=ApeConsts.record&&
GlobalConfig.userRole!=ApeConsts.invisible){
GlobalConfig.userRole= ApeConsts.normal;
}
//客户端决定是否延迟接收消息
GlobalConfig.messageDelay = _param.messageDelay || false;
//最长允许录制的时间
if(_param.allowRecordMaxTime){
GlobalConfig.allowRecordMaxTime=parseInt(_param.allowRecordMaxTime);
... ... @@ -412,7 +424,7 @@ export default class MessageEntrance extends Emiter {
// console.log(_data);
//包含整个课堂最全的信息,储存数据
if (_data) {
GlobalConfig.mcuDelay = _data.mcuDelay || 60;//mcu消息延迟,用于文档模块
GlobalConfig.mcuDelay = _data.h5Delay || 0;//mcu消息延迟的时间间隔,单位(秒),结合客户端传的messageDelay的值使用
GlobalConfig.className = _data.meetingName || "";
GlobalConfig.classBeginTime = _data.beginTime || "";
GlobalConfig.classEndTime = _data.endTime || "";
... ... @@ -421,6 +433,14 @@ export default class MessageEntrance extends Emiter {
GlobalConfig.maxVideoChannels = _data.maxVideoChannels;
GlobalConfig.maxAudioChannels = _data.maxAudioChannels;
//视频质量相关设置
GlobalConfig.fps = _data.fps||15;
GlobalConfig.gop = _data.gop||3;;
GlobalConfig.videoQuality = _data.videoQuality||2;
//是否自动开始(身份是host的时候才用到的)
GlobalConfig.isAutoStartClass= _data.autoRecord||0;
GlobalConfig.setDocListPrepare(_data.docListPrepare); //提前上传的文档列表
GlobalConfig.setRecordList(_data.recordList);//录制回放地址
GlobalConfig.setDocList(_data.docList);//文档地址
... ... @@ -592,6 +612,11 @@ export default class MessageEntrance extends Emiter {
joinClassSuccessCallBackData.classTimestamp=GlobalConfig.classTimestamp;//课堂进行的累积时间
joinClassSuccessCallBackData.recordPlaybackMaxTime=GlobalConfig.recordPlaybackMaxTime;//录制回放的总时间
joinClassSuccessCallBackData.fps=GlobalConfig.fps;
joinClassSuccessCallBackData.gop=GlobalConfig.gop;
joinClassSuccessCallBackData.videoQuality=GlobalConfig.videoQuality;
loger.log('加入课堂成功');
loger.log(joinClassSuccessCallBackData);
... ... @@ -1141,6 +1166,10 @@ export default class MessageEntrance extends Emiter {
joinClassSuccessCallBackData.classTimestamp=GlobalConfig.classTimestamp;//课堂进行的累积时间
joinClassSuccessCallBackData.recordPlaybackMaxTime=GlobalConfig.recordPlaybackMaxTime;//录制回放的总时间
joinClassSuccessCallBackData.fps=GlobalConfig.fps;
joinClassSuccessCallBackData.gop=GlobalConfig.gop;
joinClassSuccessCallBackData.videoQuality=GlobalConfig.videoQuality;
loger.log(joinClassSuccessCallBackData);
//和加入课堂成功使用同样的消息处理
this._emit(MessageTypes.CLASS_JOIN_SUCCESS, joinClassSuccessCallBackData);
... ...
... ... @@ -52,6 +52,9 @@ class GlobalConfig {
classInfo.MCUServerPort=this.MCUServerPort;
classInfo.maxVideoChannels= this.maxVideoChannels;
classInfo.maxAudioChannels=this.maxAudioChannels;
classInfo.fps=this.fps;
classInfo.gop=this.gop;
classInfo.videoQuality=this.videoQuality;
return classInfo;
... ... @@ -242,8 +245,10 @@ GlobalConfig.statusCode_4={"code":4,message:"未知状态"};
GlobalConfig.md5="";
GlobalConfig.msType=1;//目前固定用这个
GlobalConfig.mcuDelay=60;//默认的延迟时间 flash中使用的是3000毫秒
GlobalConfig.docDelay=1600;//文档模块加入成功之后延迟发送送成功的消息给主模块
GlobalConfig.messageDelay=false;//是否启用消息延迟
GlobalConfig.mcuDelay=0;//默认的延迟时间(单位-秒)
GlobalConfig.docDelay=1600;//文档模块加入成功之后延迟发送送成功的消息给主模块(sdk内部使用)
GlobalConfig.portal="112.126.80.182:80";//Sass IP
//GlobalConfig.ip="112.126.80.182";
... ... @@ -305,6 +310,8 @@ GlobalConfig.recordFileName="";//录制的文件名,如 果为空就创建一个
GlobalConfig.recordDownloadUrl="";//下载地址
GlobalConfig.recordReplaytickValues={}; // 滚动条关键点,用于快进快退
GlobalConfig.isAutoStartClass=0;//是否自动开始上课 0-否 ;1 是
GlobalConfig.updateClassInfoDelay=30;//(秒),每隔30秒同步一次课堂状态的并保存到Sass
//GlobalConfig.serverTimestamp=0;//当前的系统时间戳 用get set 获取
... ... @@ -312,7 +319,10 @@ GlobalConfig.updateClassInfoDelay=30;//(秒),每隔30秒同步一次课堂状
GlobalConfig.activeDocId=0;//当前激活的文档ID
GlobalConfig.activeDocCurPage=1;//当前激活的文档的当前页
//视频质量相关设置
GlobalConfig.fps=15;//帧频
GlobalConfig.gop=3;//关键帧间隔(秒)
GlobalConfig.videoQuality=2;//画面质量 0-低;1-中;2-高;
GlobalConfig.classAllParam={};//Sass直接返回的所有课堂信息(最全)
... ...
... ... @@ -293,6 +293,8 @@ class RecordPlayBackParse extends Emiter {
position += byteLen;
this._parseSaveSocketMsgReceivedHandler(byteData, timestamp);
//记录最后一个数据的时间戳作为整个录制回放的总时间戳
this._recordPlaybackMaxTime = timestamp;
}
... ... @@ -300,6 +302,12 @@ class RecordPlayBackParse extends Emiter {
this._isReady = true;
this._stopTimerCounter();
//录制回放的总时间长度按课堂最长时间计算,不能按最后一个消息的时间计算
if(this._recordPlaybackMaxTime<GlobalConfig.classTimestamp){
this._recordPlaybackMaxTime=GlobalConfig.classTimestamp;
}
GlobalConfig.recordPlaybackMaxTime = this._recordPlaybackMaxTime;
loger.log("录制回放数据解析完成,录制回放的总时间长为->", this._recordPlaybackMaxTime);
//console.log("_messages", this._messages);
... ... @@ -382,13 +390,13 @@ class RecordPlayBackParse extends Emiter {
//查找关键帧,找到关键帧后再继续播放
this._searchApeMessageKeyfram(this._conferApeMssages, ApeConsts.CONFERENCE_SESSION_ID);
this._searchApeMessageKeyfram(this._docApeMssages, ApeConsts.DOCSHARING_SESSION_ID);
this._searchApeMessageKeyfram(this._whiteApeMssages, ApeConsts.WHITEBOARD_SESSION_ID);
//this._searchApeMessageKeyfram(this._whiteApeMssages, ApeConsts.WHITEBOARD_SESSION_ID);
this._searchApeMessageKeyfram(this._videoApeMssages, ApeConsts.VIDEO_SESSION_ID);
this._searchApeMessageKeyfram(this._audioApeMssages, ApeConsts.AUDIO_SESSION_ID);
//聊天模块的比较特殊,消息是累计的
this._searchChatApeMessageKeyfram(this._chatApeMssages, ApeConsts.CHAT_SESSION_ID);
//聊天模块、白板标注模块的比较特殊,消息是累计的,默认最多30条
this._searchApeHistoryMessageKeyfram(this._chatApeMssages, ApeConsts.CHAT_SESSION_ID);
this._searchApeHistoryMessageKeyfram(this._whiteApeMssages, ApeConsts.WHITEBOARD_SESSION_ID);
//各个ape模块无论有没有找到关键帧数据,都继续播放
this._startTimerCounter();
... ... @@ -420,7 +428,9 @@ class RecordPlayBackParse extends Emiter {
}
//查找聊天模块ape关键帧数据,聊天模块比较特殊,消息是累积的,当前时间戳之前的都需要显示
_searchChatApeMessageKeyfram(_apeMessages) {
_searchApeHistoryMessageKeyfram(_apeMessages) {
//最多30条数据
let counter=0;
let messageItem;
let keyFrameSeek = 0;
for (let i = this._recordPlaybackTimestamp; i > 0; i--) {
... ... @@ -429,9 +439,15 @@ class RecordPlayBackParse extends Emiter {
//把时间点对应的数据发送,同一秒内有存在多个数据的情况
for (let i = 0; i < messageItem.length; i++) {
this._everSocketMsgReceivedHandler(messageItem[i].byteData, 0);
counter++;
if(counter>30){
loger.warn("SEEK->最多处理历史消息30条");
return;
}
}
}
}
}
}
... ...
... ... @@ -201,7 +201,7 @@ class Sass extends Emiter {
// 获取课堂基本详情------------------------------------------------------------------------------------
getClassDetail() {
let url = `http://${confInfo.portal}/3m/meeting/getClassH5.do?classNumber=${confInfo.classId}`;
let url = `http://${GlobalConfig.portal}/3m/meeting/getClassH5.do?classNumber=${GlobalConfig.classId}`;
loger.log('获取Class详情.', url);
fetch(url, {
timeout: 5000
... ... @@ -300,7 +300,7 @@ class Sass extends Emiter {
}
var timestamp = new Date().getTime();
var authId = MD5(_param.docId + "" + _param.classId + "" + timestamp);// docId+classId+timestamp的字符串,转成MD5
let url = `http://${confInfo.portal}/3m/api/document/deleteRelation.do?docId=${_param.docId}&classId=${confInfo.classId}&timestamp=${timestamp}&authId=${authId}`;
let url = `http://${GlobalConfig.portal}/3m/api/document/deleteRelation.do?docId=${_param.docId}&classId=${GlobalConfig.classId}&timestamp=${timestamp}&authId=${authId}`;
loger.log('sassDeleteDocument', url);
fetch(url, {
... ... @@ -350,16 +350,16 @@ class Sass extends Emiter {
}
//{"classStatusInfo":classStatusInfo}
var timestamp = new Date().getTime();
var authId = MD5(confInfo.classId + "" + timestamp);// (classId+timestamp)的字符串,转成MD5
var authId = MD5(GlobalConfig.classId + "" + timestamp);// (classId+timestamp)的字符串,转成MD5
let classStatusInfo = JSON.stringify(_param.classStatusInfo);
let url = `http://${confInfo.portal}/3m/api/meeting/saveInfo.do`;
let url = `http://${GlobalConfig.portal}/3m/api/meeting/saveInfo.do`;
loger.log('saveClassStatusInfo', url);
fetch(url, {
method: 'POST',
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: `classId=${confInfo.classId}&info=${classStatusInfo}&timestamp=${timestamp}&authId=${authId}`,
body: `classId=${GlobalConfig.classId}&info=${classStatusInfo}&timestamp=${timestamp}&authId=${authId}`,
timeout: 5000
})
.then(ret => {
... ... @@ -416,7 +416,7 @@ class Sass extends Emiter {
let timestamp = new Date().getTime();
let authId = MD5(key + siteID + meetingID + timestamp);
let url = `http://${confInfo.portal}/3m/recordingMeeting/insertRecordingMeeting.do?siteID=${siteID}&meetingID=${meetingID}&userID=${userID}&userName=${userName}&meetingName=${meetingName}&startTime=${startTime}&endTime=${endTime}&playUrl=${playUrl}&streamName=${streamName}&downloadUrl=${downloadUrl}&configFile=${confRecordFileName}&timestamp=${timestamp}&recordTimestamp=${recordTimestamp}&authId=${authId}`;
let url = `http://${GlobalConfig.portal}/3m/recordingMeeting/insertRecordingMeeting.do?siteID=${siteID}&meetingID=${meetingID}&userID=${userID}&userName=${userName}&meetingName=${meetingName}&startTime=${startTime}&endTime=${endTime}&playUrl=${playUrl}&streamName=${streamName}&downloadUrl=${downloadUrl}&configFile=${confRecordFileName}&timestamp=${timestamp}&recordTimestamp=${recordTimestamp}&authId=${authId}`;
loger.log('saveClassRecordContrlInfo', url);
fetch(url, {
... ...
... ... @@ -27,6 +27,8 @@ let speedTestPort = ':5555';//测速端口统一
let checkMcuIpGroup =[];//储存MCU需要查询的ip数组
let checkMsIpGroup =[];//储存MCU需要查询的ip数组
const timeOutDelay=1000;//选点超时
class ServerCheck extends Emiter {
constructor() {
super();
... ... @@ -52,7 +54,7 @@ class ServerCheck extends Emiter {
loger.log('获取IP信息 ', userIp, location);
fetchJsonp(location, {
timeout: 3000,
timeout: timeOutDelay,
}).then(function (response) {
return response.json()
}).then(function (json) {
... ... @@ -168,7 +170,7 @@ class ServerCheck extends Emiter {
//loger.log('getBestMcuServer done -> ', fatest_ip_response);
this._getBestMcuServerCallbackHandler(fatest_ip_response)
}
}.bind(this), 3000);
}.bind(this), timeOutDelay);
}
//获取最快的MS服务器地址,参数是一个ip数组
... ... @@ -186,7 +188,7 @@ class ServerCheck extends Emiter {
//loger.log('getBestMsServer done -> ', fatest_ip_response);
this._getBestMsServerCallbackHandler(fatest_ip_response);
}
}.bind(this), 3000);
}.bind(this), timeOutDelay);
}
_getBestMcuServerCallbackHandler(_data) {
... ...
... ... @@ -40,7 +40,7 @@ export default class Ape extends Emiter {
this._adapter_pdu = new pdu['RCAdapterPdu'];
this._classInfo = null;
this._rCArrayBufferUtil = ArrayBufferUtil;
this._apeDelayed = false;
this._apeDelayed = true;
this._apeDelayedMsgs = [];
this._apeDelayedTimer = 0;
... ... @@ -75,15 +75,17 @@ export default class Ape extends Emiter {
// 消息处理
_pduMessageHandler(regBuffer,_seekTime) {
let seekTime=_seekTime||0;//这个只有在录制回放的时候才有
//loger.log("RCPDU_REG_ADAPTER============seekTime",seekTime);
if (this._apeDelayed) {
// this._apeDelayedMsgs.push(regBuffer);
// this._apeDelayedStart();
/* loger.warn('APE->收到消息处理->',GlobalConfig.mcuDelay,GlobalConfig.messageDelay);
//延迟处理消息(3个条件--->ape允许延迟&&客户端设置需要延迟&&Sass设置的延迟时间大于0)
if (this._apeDelayed&&GlobalConfig.messageDelay&&GlobalConfig.mcuDelay>0) {
loger.warn('延迟处理消息->',GlobalConfig.mcuDelay);
setTimeout(() => {
this._pduRegAdapterHandler(regBuffer,seekTime);
}, GlobalConfig.mcuDelay || 2000);
}, GlobalConfig.mcuDelay*1000);//mcuDelay单位是秒,这里需要换算为毫秒
return;
}
*/
//不延迟,立即处理
this._pduRegAdapterHandler(regBuffer,seekTime);
}
... ... @@ -164,7 +166,7 @@ export default class Ape extends Emiter {
let tableUpdateItems = tableUpdateData.items;
let tableUpdateItemsLen = tableUpdateItems.length;
//loger.log("RCRegistryTableUpdateItemPdu " + tableUpdateItemsLen);
loger.log(tableUpdateData);
//loger.log(tableUpdateData);
for (let i = 0; i < tableUpdateItemsLen; ++i) {
let tableItem = tableUpdateItems[i];
... ...
... ... @@ -316,6 +316,7 @@ class AudioApe extends Ape {
let receiveChannelInfo={};
receiveChannelInfo.mediaId=unpackChannelInfo.channelId;
receiveChannelInfo.fromNodeId=unpackChannelInfo.fromNodeId;
receiveChannelInfo.userName=unpackChannelInfo.userName||"";
//消息不是自己同步的,需要处理
if(unpackChannelInfo.status==ApeConsts.CHANNEL_STATUS_OPENING){
... ... @@ -375,6 +376,7 @@ class AudioApe extends Ape {
packPduModel.mediaType =_param.mediaType|| ApeConsts.MEDIA_TYPE_AUDIO;
packPduModel.timestamp =_param.timestamp||EngineUtils.creatTimestamp();
packPduModel.fromNodeId = GlobalConfig.nodeId;
packPduModel.userName=GlobalConfig.userName||"";
packPduModel.toNodeId = 0;
loger.log("packPdu",packPduModel);
return packPduModel;
... ...
... ... @@ -377,6 +377,13 @@ class ConferApe extends Ape {
//如果是host ,开始录制
this.startRecord();
}else if(GlobalConfig.classStatus == ApeConsts.CLASS_STATUS_WAIT&&
GlobalConfig.isHost&& GlobalConfig.isAutoStartClass&&
!GlobalConfig.isRecordPlayBack){
//自动开始上课的4个条件
//1.如果自己是host,2.Sass配置的是自动开始上课,3.并且当前是未开始状态,4.当前不是录制回放,开始自动上课
loger.log('自动开始上课->classStatus:', GlobalConfig.classStatus, " isHost:",GlobalConfig.isHost, " isAutoStartClass:",GlobalConfig.isAutoStartClass, " isRecordPlayBack:",GlobalConfig.isRecordPlayBack);
this.startClass();
}
}
... ...
... ... @@ -34,8 +34,6 @@ class DocApe extends Ape {
this.docList = {};//记录文档的数组this.docList[itemIdx]=itemIdx的数据
//this.activeDocItemIdx =0;//当前激活的文档itemIdx
//this.activeDocCurPage=1;//当前激活的文档的当前页
// 延迟
this._apeDelayed = false;
// Ape Models
this.registerKey(this._session_id, this._session_name, this._session_tag, new ArrayBuffer);
... ...
... ... @@ -243,7 +243,7 @@ class VideoApe extends Ape {
}
return {"code": ApeConsts.RETURN_SUCCESS, "data": ""};
}
//发送到mcu同步(更新数据)
sendTableUpdateHandler(_channelInfo) {
loger.log("video===sendTableUpdateHandler ");
let updateModelPdu = this.packPdu(_channelInfo, _channelInfo.channelId);//let updateModelPdu=this.packPdu({},ApeConsts.VIDEO_OBJ_TABLE_ID+2);
... ... @@ -321,6 +321,7 @@ class VideoApe extends Ape {
let receiveChannelInfo={};
receiveChannelInfo.mediaId=unpackChannelInfo.channelId;
receiveChannelInfo.fromNodeId=unpackChannelInfo.fromNodeId;
receiveChannelInfo.userName=unpackChannelInfo.userName||"";
//消息不是自己同步的,需要处理
if(unpackChannelInfo.status==ApeConsts.CHANNEL_STATUS_OPENING){
//正在推流
... ... @@ -380,6 +381,7 @@ class VideoApe extends Ape {
packPduModel.mediaType =_param.mediaType|| ApeConsts.MEDIA_TYPE_VIDEO;
packPduModel.timestamp =_param.timestamp||0;
packPduModel.fromNodeId = GlobalConfig.nodeId;
packPduModel.userName=GlobalConfig.userName||"";
packPduModel.toNodeId = 0;
loger.log(packPduModel);
return packPduModel;
... ...
... ... @@ -43,8 +43,6 @@ class WhiteBoardApe extends Ape {
this.annoInfos = {};//储存所有的标注数据
this.insertHistory = [];//添加的白板记录,用于撤回操作
// 白板延迟
// this._apeDelayed = true;
//Ape Models
this.registerKey(this._session_id, this._session_name, this._session_tag, new ArrayBuffer);
this.registerObj(pdu.RCPDU_REG_REGISTER_TABLE, ApeConsts.WHITEBOARD_OBJ_TABLE_ID,
... ...
... ... @@ -17,187 +17,199 @@ import EngineUtils from 'EngineUtils';
let loger = Loger.getLoger('MCU');
class MCU extends Emiter {
constructor() {
super();
this._apes = {};
this._everSocket = everSocket;
this._everSocket.on(everSocket.OPEN, this._everSocketOpenHandler.bind(this));
this._everSocket.on(everSocket.MESSAGE, this._everSocketMsgReceivedHandler.bind(this));
this._everSocket.on(everSocket.CLOSED, this._everSocketCloseHandler.bind(this));
}
// 注册Ape
registerApe(ape) {
this._apes[ape._session_id] = ape;
}
// EverSocket建立通道完毕
_everSocketOpenHandler() {
this._sendJoinClassRequest();
}
// EverSocket连接断开
_everSocketCloseHandler() {
GlobalConfig.setCurrentStatus(GlobalConfig.statusCode_3);
this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_SOCKET_DISCONNECT);
}
//MCU-发送加入课堂请求
_sendJoinClassRequest(){
//const classInfo = this.classInfo;
loger.log('MCU-发送加入课堂请求.');
loger.log(this.classInfo);
var descriptorPdu = new pdu['RCConferenceDescriptorPdu'];
descriptorPdu.id = this.classInfo.classId;
descriptorPdu.name = this.classInfo.className||"";
descriptorPdu.mode = 0;
descriptorPdu.capacity = 1;
var joinRequestPdu = new pdu['RCConferenceJoinRequestPdu'];
joinRequestPdu.type = 2;
joinRequestPdu.initiator = this.classInfo.nodeId;
joinRequestPdu.nodeType = PduConsts.NT_TERMINAL; //normal
joinRequestPdu.classDescription = descriptorPdu;// classDescription
let pduMsg = pdu.create_join_class_request_pdu(
joinRequestPdu.type,
this.classInfo.nodeId,
this.classInfo.classId,
0,
ApeConsts.BROADCAST_CHANNEL_ID,
true,
PduConsts.DP_TOP,
this.classInfo.topNodeID,
PduConsts.SEG_ONCE
);
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);
pduMsg.set("deviceType",""+GlobalConfig.deviceType);
pduMsg.set("data", joinRequestPdu.toArrayBuffer());
this._everSocket.send(pduMsg.toArrayBuffer());
}
// EverSocket底层消息处理
_everSocketMsgReceivedHandler(data) {
let pduMsg = pdu.decode_pdu(data);
let pduType = pduMsg.get("type");
let pduData = pduMsg.get("data");
//loger.data('MCU-FirstLayer封装消息', 'type', pdu.id2type(pduMsg.type), pduMsg.type, 'sessionId', ApeConsts(pduMsg.sessionId), pduMsg.sessionId);
//loger.log('MCU-FirstLayer封装消息', 'type', pdu.id2type(pduMsg.type), pduMsg.type, 'sessionId', ApeConsts(pduMsg.sessionId), pduMsg.sessionId);
switch (pduType) {
case PduType.RCPDU_CONNECT_PROVIDER_RESPONSE:
//加入课堂请求返回数据处理
let joinConfPdu = pdu['RCConferenceJoinResponsePdu'].decode(pduData);
let pduResultCode = joinConfPdu.result;
loger.warn( 'RCPDU_CONNECT_PROVIDER_RESPONSE ->pduResultCode:'+pduResultCode);
switch (pduResultCode) {
case PduConsts.RET_SUCCESS:
//加入成功
this._updateMCUConfInfoDescription(joinConfPdu.classDescription);
this._emit(MessageTypes.CLASS_JOIN_MCU_SUCCESS, this.classInfo);
break;
case PduConsts.RET_FULL_CAPACITY:
this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_CLASS_JOIN_FULL);
//this._emit(MessageTypes.CLASS_JOIN_FAILED,MessageTypes.ERR_CLASS_JOIN_FULL);
//this._emit(MessageTypes.CLASS_JOIN_FULL);
break;
default:
loger.arn('JoinConfPdu-未知类型-等待处理.', pduResultCode);
break
constructor() {
super();
this._apes = {};
this._everSocket = everSocket;
this._everSocket.on(everSocket.OPEN, this._everSocketOpenHandler.bind(this));
this._everSocket.on(everSocket.MESSAGE, this._everSocketMsgReceivedHandler.bind(this));
this._everSocket.on(everSocket.CLOSED, this._everSocketCloseHandler.bind(this));
}
// 注册Ape
registerApe(ape) {
this._apes[ape._session_id] = ape;
}
// EverSocket建立通道完毕
_everSocketOpenHandler() {
this._sendJoinClassRequest();
}
// EverSocket连接断开
_everSocketCloseHandler() {
GlobalConfig.setCurrentStatus(GlobalConfig.statusCode_3);
this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_SOCKET_DISCONNECT);
}
//MCU-发送加入课堂请求
_sendJoinClassRequest() {
//const classInfo = this.classInfo;
loger.log('MCU-发送加入课堂请求.');
loger.log(this.classInfo);
var descriptorPdu = new pdu['RCConferenceDescriptorPdu'];
descriptorPdu.id = this.classInfo.classId;
descriptorPdu.name = this.classInfo.className || "";
descriptorPdu.mode = 0;
descriptorPdu.capacity = 1;
var joinRequestPdu = new pdu['RCConferenceJoinRequestPdu'];
joinRequestPdu.type = 2;
joinRequestPdu.initiator = this.classInfo.nodeId;
joinRequestPdu.nodeType = PduConsts.NT_TERMINAL; //normal
joinRequestPdu.classDescription = descriptorPdu;// classDescription
let pduMsg = pdu.create_join_class_request_pdu(
joinRequestPdu.type,
this.classInfo.nodeId,
this.classInfo.classId,
0,
ApeConsts.BROADCAST_CHANNEL_ID,
true,
PduConsts.DP_TOP,
this.classInfo.topNodeID,
PduConsts.SEG_ONCE
);
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);
pduMsg.set("deviceType", "" + GlobalConfig.deviceType);
pduMsg.set("data", joinRequestPdu.toArrayBuffer());
this._everSocket.send(pduMsg.toArrayBuffer());
}
// EverSocket底层消息处理
_everSocketMsgReceivedHandler(data) {
let pduMsg = pdu.decode_pdu(data);
let pduType = pduMsg.get("type");
let pduData = pduMsg.get("data");
//loger.data('MCU-FirstLayer封装消息', 'type', pdu.id2type(pduMsg.type), pduMsg.type, 'sessionId', ApeConsts(pduMsg.sessionId), pduMsg.sessionId);
//loger.log('MCU-FirstLayer封装消息', 'type', pdu.id2type(pduMsg.type), pduMsg.type, 'sessionId', ApeConsts(pduMsg.sessionId), pduMsg.sessionId);
switch (pduType) {
case PduType.RCPDU_CONNECT_PROVIDER_RESPONSE:
//加入课堂请求返回数据处理
let joinConfPdu = pdu['RCConferenceJoinResponsePdu'].decode(pduData);
let pduResultCode = joinConfPdu.result;
loger.warn('RCPDU_CONNECT_PROVIDER_RESPONSE ->pduResultCode:' + pduResultCode);
switch (pduResultCode) {
case PduConsts.RET_SUCCESS:
//加入成功
this._updateMCUConfInfoDescription(joinConfPdu.classDescription);
this._emit(MessageTypes.CLASS_JOIN_MCU_SUCCESS, this.classInfo);
break;
case PduConsts.RET_FULL_CAPACITY:
this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_JOIN_FULL);
//this._emit(MessageTypes.CLASS_JOIN_FAILED,MessageTypes.ERR_CLASS_JOIN_FULL);
//this._emit(MessageTypes.CLASS_JOIN_FULL);
break;
default:
loger.arn('JoinConfPdu-未知类型-等待处理.', pduResultCode);
break
}
break;
case PduType.RCPDU_SEND_DATA_REQUEST:
//先判断当前消息属于哪个APE 根据 sessionId来判断
let ape = this._apes[pduMsg.sessionId];
let sessionLabel = ApeConsts(pduMsg.sessionId);
if (ape) {
let subTypeLabel = pdu.id2type(pduMsg.subType);
//loger.log('MCU-SecondLayer封装消息', 'sessionId', sessionLabel, pduMsg.sessionId, 'subtype', subTypeLabel, pduMsg.subType);
loger.warn('MCU->收到消息处理->', GlobalConfig.mcuDelay, GlobalConfig.messageDelay);
//延迟处理消息(3个条件--->ape允许延迟&&客户端设置需要延迟&&Sass设置的延迟时间大于0)
if (ape._apeDelayed && GlobalConfig.messageDelay && GlobalConfig.mcuDelay > 0) {
loger.warn('延迟处理消息->', GlobalConfig.mcuDelay);
setTimeout(() => {
//this._pduRegAdapterHandler(regBuffer, seekTime);
ape._emit(pduMsg.subType, pduMsg.data);
}, GlobalConfig.mcuDelay * 1000);//mcuDelay单位是秒,
// 这里需要换算为毫秒
return;
}
ape._emit(pduMsg.subType, pduMsg.data);
} else {
loger.warn(sessionLabel + '尚未注册');
}
break;
default:
loger.warn('PDU-未知类型-等待处理.', pduType);
}
break;
case PduType.RCPDU_SEND_DATA_REQUEST:
//先判断当前消息属于哪个APE 根据 sessionId来判断
let ape = this._apes[pduMsg.sessionId];
let sessionLabel = ApeConsts(pduMsg.sessionId);
if (ape) {
let subTypeLabel = pdu.id2type(pduMsg.subType);
//loger.log('MCU-SecondLayer封装消息', 'sessionId', sessionLabel, pduMsg.sessionId, 'subtype', subTypeLabel, pduMsg.subType);
//ape广播事件,只要ape中监听就能收到
ape._emit(pduMsg.subType, pduMsg.data);
} else {
loger.warn(sessionLabel + '尚未注册');
}
break;
default:
loger.warn('PDU-未知类型-等待处理.', pduType);
}
}
_updateMCUConfInfoDescription(_data) {
// let _mcuConfDesc=new pdu['RCConferenceDescriptorPdu'].decode(mcuConfDesc);
loger.log('_updateMCUConfInfoDescription.');
//let classDescription=new pdu['RCConferenceDescriptorPdu'].decode(_data);
loger.log(_data);
//let info = this.mcuClassInfo.info;
//info._conference_name = ArrayBufferUtil.uint8ArrayToStr(mcuConfDesc.name, 0);
//info._capacity = mcuConfDesc.capacity;
//info._mode = mcuConfDesc.mode;
}
// MU服务是否连接
get connected() {
if (this._everSocket && this._everSocket.connected)
return true;
return false;
}
// 课堂发送消息 -- 消息同意序列号
send(msg) {
if (this.connected) {
loger.log('MCU-发送课堂数据....');
this._everSocket.send(msg.toArrayBuffer());
} else {
loger.log('MCU-发送课堂数据失败,MCU底层通道不可用');
this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_SOCKET_DISCONNECT);
_updateMCUConfInfoDescription(_data) {
// let _mcuConfDesc=new pdu['RCConferenceDescriptorPdu'].decode(mcuConfDesc);
loger.log('_updateMCUConfInfoDescription.');
//let classDescription=new pdu['RCConferenceDescriptorPdu'].decode(_data);
loger.log(_data);
//let info = this.mcuClassInfo.info;
//info._conference_name = ArrayBufferUtil.uint8ArrayToStr(mcuConfDesc.name, 0);
//info._capacity = mcuConfDesc.capacity;
//info._mode = mcuConfDesc.mode;
}
// MU服务是否连接
get connected() {
if (this._everSocket && this._everSocket.connected)
return true;
return false;
}
// 课堂发送消息 -- 消息同意序列号
send(msg) {
if (this.connected) {
loger.log('MCU-发送课堂数据....');
this._everSocket.send(msg.toArrayBuffer());
} else {
loger.log('MCU-发送课堂数据失败,MCU底层通道不可用');
this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_SOCKET_DISCONNECT);
}
}
// 主动断开MCU连接
leaveMCU() {
for (let ape in this._apes) {
this._apes[ape].stopApe();
}
loger.log('leaveMCU');
GlobalConfig.setCurrentStatus(GlobalConfig.statusCode_3);
this._everSocket.end();
}
// 主动建立MCU连接
joinMCU(_classInfo) {
loger.log('开始建立EverSocket通道.');
loger.log(_classInfo);
_classInfo.classId = parseInt(_classInfo.classId); // classId 必须整形
this.classInfo = _classInfo;
// 创建刷新nodeId
this.classInfo.nodeId = EngineUtils.creatSoleNumberFromTimestamp();
GlobalConfig.nodeId = this.classInfo.nodeId;//这是标识自己身份的id
let nodeInfoRecordPdu = new pdu['RCNodeInfoRecordPdu'];
nodeInfoRecordPdu.name = this.classInfo.userName;
nodeInfoRecordPdu.nodeId = this.classInfo.nodeId;
nodeInfoRecordPdu.userId = this.classInfo.userId;
nodeInfoRecordPdu.role = ApeConsts.userTypesToId[this.classInfo.userRole] || 1; //NR_NORMAL用户的身份,根据用户登录时的身份设置
nodeInfoRecordPdu.level = 0;
let conferenceRecord = {}; //RCConferenceRecord_T
conferenceRecord._conference_id = this.classInfo.classId;
conferenceRecord._top_node_id = this.classInfo.topNodeID;
this.mcuClassInfo = {}; //RCMeetingInfo_T
this.mcuClassInfo.self = nodeInfoRecordPdu;
this.mcuClassInfo.info = conferenceRecord;
// 内部mcuConfInfo
this.classInfo.mcuClassInfo = this.mcuClassInfo;
//开启EverSocket
this._everSocket.begin(this.classInfo.MCUServerIP, this.classInfo.MCUServerPort);
}
}
// 主动断开MCU连接
leaveMCU() {
for (let ape in this._apes) {
this._apes[ape].stopApe();
}
loger.log('leaveMCU');
GlobalConfig.setCurrentStatus(GlobalConfig.statusCode_3);
this._everSocket.end();
}
// 主动建立MCU连接
joinMCU(_classInfo) {
loger.log('开始建立EverSocket通道.');
loger.log(_classInfo);
_classInfo.classId = parseInt(_classInfo.classId); // classId 必须整形
this.classInfo = _classInfo;
// 创建刷新nodeId
this.classInfo.nodeId =EngineUtils.creatSoleNumberFromTimestamp();
GlobalConfig.nodeId=this.classInfo.nodeId;//这是标识自己身份的id
let nodeInfoRecordPdu = new pdu['RCNodeInfoRecordPdu'];
nodeInfoRecordPdu.name = this.classInfo.userName;
nodeInfoRecordPdu.nodeId = this.classInfo.nodeId;
nodeInfoRecordPdu.userId = this.classInfo.userId;
nodeInfoRecordPdu.role = ApeConsts.userTypesToId[this.classInfo.userRole]||1; //NR_NORMAL用户的身份,根据用户登录时的身份设置
nodeInfoRecordPdu.level = 0;
let conferenceRecord = {}; //RCConferenceRecord_T
conferenceRecord._conference_id = this.classInfo.classId;
conferenceRecord._top_node_id =this.classInfo.topNodeID;
this.mcuClassInfo = {}; //RCMeetingInfo_T
this.mcuClassInfo.self = nodeInfoRecordPdu;
this.mcuClassInfo.info = conferenceRecord;
// 内部mcuConfInfo
this.classInfo.mcuClassInfo = this.mcuClassInfo;
//开启EverSocket
this._everSocket.begin(this.classInfo.MCUServerIP,this.classInfo.MCUServerPort);
}
}
export default new MCU;
... ...
... ... @@ -777,6 +777,7 @@ message RCAudioChannelInfoPdu {
optional string site_id = 8;//站点号
optional string user_id = 9;//用户的userId
optional string stream_id = 10;//流名称
optional string user_name = 11;//用户的名字
}
message RCVideoChannelInfoPdu {
... ... @@ -790,6 +791,7 @@ message RCVideoChannelInfoPdu {
optional string site_id = 8;//站点号
optional string user_id = 9;//用户的userId
optional string stream_id = 10;//流名称
optional string user_name = 11;//用户的名字
}
message RCVideoChannelInfoRecordPdu {
... ...