diff --git a/src/EngineEntrance.js b/src/EngineEntrance.js index 56b0e3a..c4f01ae 100644 --- a/src/EngineEntrance.js +++ b/src/EngineEntrance.js @@ -34,14 +34,14 @@ let _audio_ape; let _doc_ape; let _whiteboard_ape; -//初始化成功回调函数 -let _initSuccessCallBackFun; - -//加入会议成功回调函数 -let _joinClassSuccessCallBackFun; - -//监听mcu所有错误异常回调函数 -let _mcuErrorCallBackFun; +////初始化成功回调函数 +//let _initSuccessCallBackFun; +// +////加入会议成功回调函数 +//let _joinClassSuccessCallBackFun; +// +////监听mcu所有错误异常回调函数 +//let _mcuErrorCallBackFun; //MCUClient 外部实例化主类 export default class MessageEntrance extends Emiter { @@ -71,7 +71,7 @@ export default class MessageEntrance extends Emiter { // 底层MCU消息层 _mcu = Mcu; _mcu.on('*', (type, data) => this._emit(type, data)); - _mcu.on(MessageTypes.CLASS_JOIN_SUCCESS, this._mcuJoinClassSuccessHandler.bind(this));//加入MCU会议完成 + _mcu.on(MessageTypes.CLASS_JOIN_MCU_SUCCESS, this._mcuJoinMCUClassSuccessHandler.bind(this));//加入MCU会议完成 // 注册所有应用Ape @@ -89,11 +89,11 @@ export default class MessageEntrance extends Emiter { _video_ape = new VideoApe(); _video_ape.on('*', (type, data) => this._emit(type, data)); - _video_ape.on(MessageTypes.VIDEO_UPDATE, this.videoUpdate.bind(this)); + //_video_ape.on(MessageTypes.VIDEO_UPDATE, this.videoUpdate.bind(this)); _audio_ape= new AudioApe(); _audio_ape.on('*', (type, data) => this._emit(type, data)); - _audio_ape.on(MessageTypes.AUDIO_UPDATE, this.audioUpdate.bind(this)); + //_audio_ape.on(MessageTypes.AUDIO_UPDATE, this.audioUpdate.bind(this)); _whiteboard_ape = new WhiteBoardApe(); _whiteboard_ape.on('*', (type, data) => this._emit(type, data)); @@ -109,62 +109,65 @@ export default class MessageEntrance extends Emiter { //公开外部调用的方法 //class - this.init = this._init; - this.joinClass = this._joinClass; - this.leaveClass = this._leaveClass; - this.getMcuClientStatus = this._getMcuClientStatus; + this.init = this._init.bind(this); + this.joinClass = this._joinClass.bind(this); + this.leaveClass = this._leaveClass.bind(this); + this.getMcuClientStatus = this._getMcuClientStatus.bind(this); //this.getClassDetail = this._getClassDetail;//停用 - this.getClassStatusInfo = this._getClassStatusInfo; - this.sendStartClass = this._sendStartClass; - this.sendPauseClass = this._sendPauseClass; - this.sendCloseClass = this._sendCloseClass; + this.getClassStatusInfo = this._getClassStatusInfo.bind(this); + this.sendStartClass = this._sendStartClass.bind(this); + this.sendPauseClass = this._sendPauseClass.bind(this); + this.sendCloseClass = this._sendCloseClass.bind(this); //chatApe - this.sendChatMsg = this._sendChatMsg; + this.sendChatMsg = this._sendChatMsg.bind(this); //videoApe - this.getVideoPlayPath = this._getVideoPlayPath; - this.getVideoPublishPath = this._getVideoPublishPath; - this.publishVideo = this._publishVideo; - this.stopPublishVideo = this._stopPublishVideo; - this.sendVideoBroadcastMsg=this._sendVideoBroadcastMsg; + this.getVideoPlayPath = this._getVideoPlayPath.bind(this); + this.getVideoPublishPath = this._getVideoPublishPath.bind(this); + this.publishVideo = this._publishVideo.bind(this); + this.stopPublishVideo = this._stopPublishVideo.bind(this); + this.sendVideoBroadcastMsg=this._sendVideoBroadcastMsg.bind(this); //audioApe - this.getAudioPlayPath = this._getPlayAudioPath; - this.getAudioPublishPath = this._getPublishAudioPath; - this.publishAudio = this._publishAudio; - this.stopPublishAudio = this._stopPublishAudio; - this.sendAudioBroadcastMsg=this.sendAudioCommandMsg; + this.getAudioPlayPath = this._getPlayAudioPath.bind(this); + this.getAudioPublishPath = this._getPublishAudioPath.bind(this); + this.publishAudio = this._publishAudio.bind(this); + this.stopPublishAudio = this._stopPublishAudio.bind(this); + this.sendAudioBroadcastMsg=this.sendAudioCommandMsg.bind(this); //whiteBoradApe - this.sendInsertAnnotaion = this._sendInsertAnnotaion; + this.sendInsertAnnotaion = this._sendInsertAnnotaion.bind(this); //this.sendDeleteAnnotaion=this._sendDeleteAnnotaion; - this.sendDeleteAllAnnotation = this._sendDeleteAllAnnotation; - this.sendDeleteCurPageAnnotation = this._sendDeleteCurPageAnnotation; - this.sendGotoPrev = this._sendGotoPrev; + this.sendDeleteAllAnnotation = this._sendDeleteAllAnnotation.bind(this); + this.sendDeleteCurPageAnnotation = this._sendDeleteCurPageAnnotation.bind(this); + this.sendGotoPrev = this._sendGotoPrev.bind(this); //DocApe - this.sendDocumentUpload = this._sendDocumentUpload;//上传文档 - this.sendDocumentSwitchDoc = this._sendDocumentSwitchDoc; //切换文档 - this.sendDocumentSwitchPage = this._sendDocumentSwitchPage;//翻页 - this.sendDocumentDelete = this._sassDeleteDocument;//删除文档,先通过Sass删除,sass删除成功之后再同步mcu + this.sendDocumentUpload = this._sendDocumentUpload.bind(this);;//上传文档 + this.sendDocumentSwitchDoc = this._sendDocumentSwitchDoc.bind(this);; //切换文档 + this.sendDocumentSwitchPage = this._sendDocumentSwitchPage.bind(this);;//翻页 + this.sendDocumentDelete = this._sassDeleteDocument.bind(this);;//删除文档,先通过Sass删除,sass删除成功之后再同步mcu //this.sendDocumentDeleteAll= this._documentDeleteAll;//删除所有文档 - this.sendDocumentCommand = this._sendDocumentCommand;//操作文档(翻页、缩放、滚动...) - this.getDocImageFullPath=this._getDocImageFullPath;//获取文档图片的完整路径 - this.getDocPDFFullPath=this._getDocPDFFullPath;//获取文档的完整路径 + this.sendDocumentCommand = this._sendDocumentCommand.bind(this);;//操作文档(翻页、缩放、滚动...) + this.getDocImageFullPath=this._getDocImageFullPath.bind(this);;//获取文档图片的完整路径 + this.getDocPDFFullPath=this._getDocPDFFullPath.bind(this);;//获取文档的完整路径 } //mcu异常监听 _mcuErrorHandler(_data, _option) { - if (_mcuErrorCallBackFun) { - let option = _option || ""; - let errorMessage = {"code": _data, "reson": MessageTypes.ErrorReson[_data] + " " + option}; - loger.error("MCU_ERROR", errorMessage); + let option = _option || ""; + let errorMessage = {"code": _data, "reson": MessageTypes.ErrorReson[_data] + " " + option}; + loger.error("MCU_ERROR", errorMessage); + + this._emit(MessageTypes.ERROR_EVENT,errorMessage); + +/* if (_mcuErrorCallBackFun) { _mcuErrorCallBackFun(errorMessage); - } + }*/ } //获取当前的状态 @@ -248,12 +251,10 @@ export default class MessageEntrance extends Emiter { //Sass //初始化 - _init(_param, _onSuccess, _mcuErrorCallBack) { - _initSuccessCallBackFun = _onSuccess; - _mcuErrorCallBackFun = _mcuErrorCallBack; + _init(_param) { //{"classId":"1653304953","portal":"112.126.80.182:80","userRole":"normal","userId":0} //判断传入的参数是否存在 - if (_param == null || EngineUtils.isEmptyObject(_param) || _onSuccess == null || _mcuErrorCallBack == null) { + if (_param == null || EngineUtils.isEmptyObject(_param)) { loger.error('init初始化失败,参数错误'); this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_INIT_PARAM); return; @@ -280,10 +281,10 @@ export default class MessageEntrance extends Emiter { } //外部请求加入会议 - _joinClass(_param, _onSuccess) { - _joinClassSuccessCallBackFun = _onSuccess; + _joinClass(_param) { + //_joinClassSuccessCallBackFun = _onSuccess; //{"userName":"名字","password":""} - if (_param == null || EngineUtils.isEmptyObject(_param) || _onSuccess == null) { + if (_param == null || EngineUtils.isEmptyObject(_param)) { this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_JOIN_PARAM); loger.log('不能进入会议,传递的参数不对.', _param); return; @@ -324,25 +325,27 @@ export default class MessageEntrance extends Emiter { //设置当前的会议状态 GlobalConfig.setCurrentStatus(GlobalConfig.statusCode_1); + //返回给客户端初始化成功的数据 + let initSuccessCallBackData = {}; + initSuccessCallBackData.siteId = GlobalConfig.siteId; + initSuccessCallBackData.classId = GlobalConfig.classId; + initSuccessCallBackData.userRole = GlobalConfig.userRole; + initSuccessCallBackData.userId = GlobalConfig.userId; + initSuccessCallBackData.classType = GlobalConfig.classType; + + //host默认需要密码,Sass服务器只判断学生是否需要密码,没有判断老师的 + if (GlobalConfig.userRole== ApeConsts.host) { + initSuccessCallBackData.passwordRequired =true; + } else { + initSuccessCallBackData.passwordRequired = GlobalConfig.passwordRequired; + } - if (_initSuccessCallBackFun) { - //返回给客户端初始化成功的数据 - let initSuccessCallBackData = {}; - initSuccessCallBackData.siteId = GlobalConfig.siteId; - initSuccessCallBackData.classId = GlobalConfig.classId; - initSuccessCallBackData.userRole = GlobalConfig.userRole; - initSuccessCallBackData.userId = GlobalConfig.userId; - initSuccessCallBackData.classType = GlobalConfig.classType; - - //host默认需要密码,Sass服务器只判断学生是否需要密码,没有判断老师的 - if (GlobalConfig.userRole== ApeConsts.host) { - initSuccessCallBackData.passwordRequired =true; - } else { - initSuccessCallBackData.passwordRequired = GlobalConfig.passwordRequired; - } + this._emit(MessageTypes.CLASS_INIT_SUCCESS,initSuccessCallBackData); +/* if (_initSuccessCallBackFun) { _initSuccessCallBackFun(initSuccessCallBackData); - } + }*/ + } // 通过SASS平台验证(密码和MD5) @@ -549,10 +552,12 @@ export default class MessageEntrance extends Emiter { //保存会态信息成功 _sassSaveClassStatusInfoSuccessHandler(_data) { - loger.log('保存会议状态信息成功.', _data); + loger.log('保存会议状态信息成功.'); + console.log(_data); } _sassSaveClassRecordInfoSuccessHandler(_data){ - loger.log('保存会议录制信息成功.', _data); + loger.log('保存会议录制信息成功.'); + console.log(_data); } //Sass校验流程结束之后,开始加入MCU @@ -564,50 +569,54 @@ export default class MessageEntrance extends Emiter { } // MCU 会议成功 - _mcuJoinClassSuccessHandler(_data) { + _mcuJoinMCUClassSuccessHandler(_data) { loger.log('MCU 会议成功.'); GlobalConfig.setCurrentStatus(GlobalConfig.statusCode_2); - //返回给客户数据 + //返回给客户端初始化成功的数据 + let initSuccessCallBackData = {}; + + initSuccessCallBackData.DOCServerIP =GlobalConfig.DOCServerIP; + initSuccessCallBackData.DOCServerPort =GlobalConfig.DOCServerPort; + + initSuccessCallBackData.classId = GlobalConfig.classId; + initSuccessCallBackData.className = GlobalConfig.className; + initSuccessCallBackData.h5Module = GlobalConfig.h5Module; + initSuccessCallBackData.isHost = GlobalConfig.isHost; + initSuccessCallBackData.maxAudioChannels = GlobalConfig.maxAudioChannels; + initSuccessCallBackData.maxVideoChannels = GlobalConfig.maxVideoChannels; + initSuccessCallBackData.mcuDelay = GlobalConfig.mcuDelay; + + initSuccessCallBackData.msType = GlobalConfig.msType; + initSuccessCallBackData.nodeId = GlobalConfig.nodeId; + initSuccessCallBackData.password = GlobalConfig.password; + initSuccessCallBackData.passwordRequired = GlobalConfig.passwordRequired;// 老师的默认是true + //GlobalConfig.passwordRequired 老师的默认是true + //GlobalConfig.portal=_data.portal; + initSuccessCallBackData.role = GlobalConfig.role; + initSuccessCallBackData.siteId = GlobalConfig.siteId; + initSuccessCallBackData.topNodeID = GlobalConfig.topNodeID; + initSuccessCallBackData.userId = GlobalConfig.userId; + initSuccessCallBackData.userName = GlobalConfig.userName; + initSuccessCallBackData.userRole = GlobalConfig.userRole; + initSuccessCallBackData.userType = GlobalConfig.userType; + + initSuccessCallBackData.siteId = GlobalConfig.siteId; + initSuccessCallBackData.classId = GlobalConfig.classId; + initSuccessCallBackData.userRole = GlobalConfig.userRole; + initSuccessCallBackData.userId = GlobalConfig.userId; + initSuccessCallBackData.passwordRequired = GlobalConfig.passwordRequired; + initSuccessCallBackData.classType = GlobalConfig.classType || ApeConsts.CLASS_TYPE_INTERACT; + loger.log('加入会议成功'); + console.log(initSuccessCallBackData); + + //加入会议成功,广播消息 + this._emit(MessageTypes.CLASS_JOIN_SUCCESS,initSuccessCallBackData); + +/* //返回给客户数据 if (_joinClassSuccessCallBackFun) { - //返回给客户端初始化成功的数据 - let initSuccessCallBackData = {}; - - initSuccessCallBackData.DOCServerIP =GlobalConfig.DOCServerIP; - initSuccessCallBackData.DOCServerPort =GlobalConfig.DOCServerPort; - - initSuccessCallBackData.classId = GlobalConfig.classId; - initSuccessCallBackData.className = GlobalConfig.className; - initSuccessCallBackData.h5Module = GlobalConfig.h5Module; - initSuccessCallBackData.isHost = GlobalConfig.isHost; - initSuccessCallBackData.maxAudioChannels = GlobalConfig.maxAudioChannels; - initSuccessCallBackData.maxVideoChannels = GlobalConfig.maxVideoChannels; - initSuccessCallBackData.mcuDelay = GlobalConfig.mcuDelay; - - initSuccessCallBackData.msType = GlobalConfig.msType; - initSuccessCallBackData.nodeId = GlobalConfig.nodeId; - initSuccessCallBackData.password = GlobalConfig.password; - initSuccessCallBackData.passwordRequired = GlobalConfig.passwordRequired;// 老师的默认是true - //GlobalConfig.passwordRequired 老师的默认是true - //GlobalConfig.portal=_data.portal; - initSuccessCallBackData.role = GlobalConfig.role; - initSuccessCallBackData.siteId = GlobalConfig.siteId; - initSuccessCallBackData.topNodeID = GlobalConfig.topNodeID; - initSuccessCallBackData.userId = GlobalConfig.userId; - initSuccessCallBackData.userName = GlobalConfig.userName; - initSuccessCallBackData.userRole = GlobalConfig.userRole; - initSuccessCallBackData.userType = GlobalConfig.userType; - - initSuccessCallBackData.siteId = GlobalConfig.siteId; - initSuccessCallBackData.classId = GlobalConfig.classId; - initSuccessCallBackData.userRole = GlobalConfig.userRole; - initSuccessCallBackData.userId = GlobalConfig.userId; - initSuccessCallBackData.passwordRequired = GlobalConfig.passwordRequired; - initSuccessCallBackData.classType = GlobalConfig.classType || ApeConsts.CLASS_TYPE_INTERACT; - loger.log('加入会议成功'); - console.log(initSuccessCallBackData); _joinClassSuccessCallBackFun(initSuccessCallBackData); - } + }*/ } //Sass删除文档数据 diff --git a/src/EverSocket.js b/src/EverSocket.js index bba2ef6..d3b9e30 100644 --- a/src/EverSocket.js +++ b/src/EverSocket.js @@ -42,7 +42,11 @@ class EverSocket extends Emiter { send(data) { if (this._connected) { - loger.log('SEND MESSAGE---->'); + if(data){ + loger.log('SEND MESSAGE,byteLength---->',data.byteLength); + }else { + loger.log('SEND MESSAGE---->'); + } this.websocket.send(data); } else { loger.warn('WebSocket未建立连接.消息忽略'); @@ -85,6 +89,7 @@ class EverSocket extends Emiter { loger.log('WebSocket,Timers已经销毁'); return; } + this._setConnected(false);//先设置状态 this.websocket.onopen = undefined; this.websocket.onclose = undefined; this.websocket.onerror = undefined; @@ -96,7 +101,6 @@ class EverSocket extends Emiter { } this.websocket = undefined; this._enableEverSocket = false; - this._setConnected(false); } _onOpen() { diff --git a/src/MessageTypes.js b/src/MessageTypes.js index e80e129..7da2795 100644 --- a/src/MessageTypes.js +++ b/src/MessageTypes.js @@ -1,50 +1,55 @@ /** - *事件定义和错误码定义 + *事件消息ID和错误码 定义 */ function MessageTypes() {} //--------------------事件相关的定义-------------------------------------- //初始化相关事件定义 -//MessageTypes.CLASS_INIT_SUCCESS='class.init.success';//初始化成功 +MessageTypes.CLASS_INIT_SUCCESS="class_init_success";//'class.init.success';//初始化成功 //MessageTypes.CLASS_INIT_FAILED='class.init.failed';//初始化失败 //加入会议相关事件定义 -MessageTypes.CLASS_JOIN_SUCCESS = 'join.class.success'; +MessageTypes.CLASS_JOIN_MCU_SUCCESS ="class_join_mcu_success"// 'join.mcu.success'; //MessageTypes.CLASS_JOIN_FAILED = 'join.class.failed'; //会议信息和操作事件定义 //MessageTypes.CLASS_SHOW_DETAIL = 'class_detail.message'; -MessageTypes.CLASS_SHOW_ROSTER_NUM = 'roster_num.message'; -MessageTypes.CLASS_INSERT_ROSTER = 'roster.insert.message'; -MessageTypes.CLASS_DELETE_ROSTER = 'roster.delete.message'; -MessageTypes.CLASS_NONENTITY_ROSTER = 'roster.nonentity.message'; +MessageTypes.CLASS_JOIN_SUCCESS ="class_join_success"// 'join.class.success'; +MessageTypes.CLASS_UPDATE_ROSTER_NUM ="class_update_roster_num";// 'roster_num.message'; +MessageTypes.CLASS_INSERT_ROSTER ="class_insert_roster";// 'roster.insert.message'; +MessageTypes.CLASS_DELETE_ROSTER ="class_delete_roster"// 'roster.delete.message'; +MessageTypes.CLASS_NONENTITY_ROSTER ="class_nonenetity_roster";// 'roster.nonentity.message'; -MessageTypes.CLASS_EXIT = 'class.exit';//退出 关闭会议 -MessageTypes.CLASS_UPTATE_STATUS = 'class.update.status';//更新会议状态信息 -MessageTypes.CLASS_STATUS_INFO_CHANGE= 'class.status.info.change';//会议状态信息发生改变,需要保存数据到sass和同步MCU +MessageTypes.CLASS_EXIT ="class_exit";// 'class.exit';//退出 关闭会议 +MessageTypes.CLASS_UPTATE_STATUS ="class_update_status";// 'class.update.status';//更新会议状态信息 +MessageTypes.CLASS_STATUS_INFO_CHANGE="class_status_info_change";// 'class.status.info.change';//会议状态信息发生改变,需要保存数据到sass和同步MCU -MessageTypes.CLASS_UPDATE_TIMER='class.update.timer';//更新当前上课的时间 +MessageTypes.CLASS_UPDATE_TIMER="class_update_timer";//'class.update.timer';//更新当前上课的时间 -MessageTypes.CLASS_RECORD_START='class.record.start';//开始录制 +MessageTypes.CLASS_RECORD_START="class_record_start";//'class.record.start';//开始录制 //聊天模块事件定义 -MessageTypes.CHAT_RECEIVE = 'chat.receive'; +MessageTypes.CHAT_RECEIVE ="chat_receive_message";// 'chat.receive'; //视频模块事件定义 -MessageTypes.VIDEO_UPDATE = 'video.update'; -MessageTypes.VIDEO_BROADCAST= 'video.broadcast'; +MessageTypes.VIDEO_PLAY ="video_play";// 'video.play';//播放视频 +MessageTypes.VIDEO_STOP ="video_stop"; //'video.stop';//停止视频 +//MessageTypes.VIDEO_UPDATE ="video.update";// 'video.update';//废弃,400、401取代 +MessageTypes.VIDEO_BROADCAST= "video_broadcast";//'video.broadcast'; //音频模块事件定义 -MessageTypes.AUDIO_UPDATE = 'audio.update'; -MessageTypes.AUDIO_BROADCAST= 'audio.broadcast'; +MessageTypes.AUDIO_PLAY ="audio_play";// 'audio.play';//播放 +MessageTypes.AUDIO_STOP = "audio_stop";//'audio.stop';//停止 +//MessageTypes.AUDIO_UPDATE = "502";//'audio.update'; +MessageTypes.AUDIO_BROADCAST= "audio_broadcast";//'audio.broadcast'; //文档模块事件定义 -MessageTypes.DOC_DELETE='document.delete';//删除文档 -MessageTypes.DOC_UPDATE = 'document.update';//更新文档(添加、变更) +MessageTypes.DOC_DELETE="document_delete";//'document.delete';//删除文档 +MessageTypes.DOC_UPDATE ="document_update";// 'document.update';//更新文档(添加、变更) //MessageTypes.DOC_SHOW = 'document.show'; //MessageTypes.DOC_UPLOAD='document.upload';//上传文档 //MessageTypes.DOC_COMMAND='document.command';//操作文档 @@ -55,18 +60,15 @@ MessageTypes.DOC_UPDATE = 'document.update';//更新文档(添加、变更) //白板笔记事件定义 -MessageTypes.WHITEBOARD_ANNOTATION_UPDATE = 'whiteboard.annotation.update'; +MessageTypes.WHITEBOARD_ANNOTATION_UPDATE ="whiteboard_annotation_update";// 'whiteboard.annotation.update'; //MessageTypes.WHITEBOARD_ANNOTAION_INSERT = 'whiteboard.annotation.insert'; //MessageTypes.WHITEBOARD_ANNOTAION_DELETE = 'whiteboard.annotation.delete'; //MessageTypes.WHITEBOARD_ANNOTATION_CLEAR = 'whiteboard.annotation.clear'; -//音频 -MessageTypes.AUDIO_RECEIVE='audio.receive'; - - //错误事件定义 -MessageTypes.MCU_ERROR ="mcuError";//MCU错误 +MessageTypes.MCU_ERROR ="mcu_error";//"mcuError";//MCU错误(内部使用) +MessageTypes.ERROR_EVENT="error_event";//外部监听错误的消息ID(外部使用) //---------------错误消息 ErrorCode 定义------------------------------------------------- @@ -103,6 +105,11 @@ MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG=501;//APE在接口调用时参数错� MessageTypes.ERR_DOC_DELETE_FAILED=600;//删除文档失败 MessageTypes.ERR_DOC_DELETE_FAILED_PARAM=601;//删除文档失败,参数错误 + +MessageTypes.ERR_SDK_FAILED=700;// sdk还没初始化 +MessageTypes.ERR_INTERFACE_NONE=701;//调用的接口不存在 +MessageTypes.ERR_INTERFACE_PARAMS_ERROR=702;//调用的接口,传递的参数不正确 + MessageTypes.ERR_NETWORK=10000;//网络错误 MessageTypes.ERR_UNKNOWN=10001;//未知错误 @@ -143,6 +150,9 @@ MessageTypes.ErrorReson[MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG]="APE在接� MessageTypes.ErrorReson[MessageTypes.ERR_DOC_DELETE_FAILED]="删除文档失败"; MessageTypes.ErrorReson[MessageTypes.ERR_DOC_DELETE_FAILED_PARAM]="删除文档失败,参数错误"; +MessageTypes.ErrorReson[MessageTypes.ERR_SDK_FAILED]="sdk还没初始化"; +MessageTypes.ErrorReson[MessageTypes.ERR_INTERFACE_NONE]="调用的接口不存在"; +MessageTypes.ErrorReson[MessageTypes.ERR_INTERFACE_PARAMS_ERROR]="调用的接口,传递的参数不正确"; MessageTypes.ErrorReson[MessageTypes.ERR_NETWORK]="网络错误"; MessageTypes.ErrorReson[MessageTypes.ERR_UNKNOWN]="未知错误"; diff --git a/src/Sass.js b/src/Sass.js index 055b9b6..2b2c985 100644 --- a/src/Sass.js +++ b/src/Sass.js @@ -431,14 +431,14 @@ class Sass extends Emiter { } -Sass.prototype.SUCCESS = Sass.SUCCESS = 'Sass.success'; -Sass.prototype.CLASS_INIT_SUCCESS = Sass.CLASS_INIT_SUCCESS = 'sass.class.init.success'; -Sass.prototype.CLASS_GET_CLASS_PARAM = Sass.CLASS_GET_CLASS_PARAM = 'class.getClassParam.message'; -Sass.prototype.CLASS_GET_CLASS_DETAIL = Sass.CLASS_GET_CLASS_DETAIL = 'class.getClassDetail.message'; -Sass.prototype.DELETE_DOCUMENT_SUCCESS = Sass.DELETE_DOCUMENT_SUCCESS = 'class.deleteDocumentSuccess.message';//删除文档成功 +Sass.prototype.SUCCESS = Sass.SUCCESS = 'Sass_success'; +Sass.prototype.CLASS_INIT_SUCCESS = Sass.CLASS_INIT_SUCCESS = 'sass_class_init_success'; +Sass.prototype.CLASS_GET_CLASS_PARAM = Sass.CLASS_GET_CLASS_PARAM = 'sass_class_getClassParam.message'; +Sass.prototype.CLASS_GET_CLASS_DETAIL = Sass.CLASS_GET_CLASS_DETAIL = 'sass_class_getClassDetail_message'; +Sass.prototype.DELETE_DOCUMENT_SUCCESS = Sass.DELETE_DOCUMENT_SUCCESS = 'sass_class_deleteDocumentSuccess_message';//删除文档成功 -Sass.prototype.CLASS_SAVE_STATUS_INFO_SUCCESS = Sass.CLASS_SAVE_STATUS_INFO_SUCCESS = 'class.saveClassStatusInfoSuccess.message';//保存会议状态信息 -Sass.prototype.CLASS_SAVE_RECORD_INFO_SUCCESS = Sass.CLASS_SAVE_RECORD_INFO_SUCCESS = 'class.saveClassRecordInfoSuccess.message';//保存录制会议信息 +Sass.prototype.CLASS_SAVE_STATUS_INFO_SUCCESS = Sass.CLASS_SAVE_STATUS_INFO_SUCCESS = 'sass_class_saveClassStatusInfoSuccess_message';//保存会议状态信息 +Sass.prototype.CLASS_SAVE_RECORD_INFO_SUCCESS = Sass.CLASS_SAVE_RECORD_INFO_SUCCESS = 'sass_class_saveClassRecordInfoSuccess_message';//保存录制会议信息 export default new Sass; diff --git a/src/apes/Ape.js b/src/apes/Ape.js index a40fd43..20c36ad 100644 --- a/src/apes/Ape.js +++ b/src/apes/Ape.js @@ -54,7 +54,7 @@ export default class Ape extends Emiter { // 监听底层MCU会议 this.mcu = mcu; - this.mcu.on(MessageTypes.CLASS_JOIN_SUCCESS, this._mcuConferenceJoinSuccessHandler.bind(this)); + this.mcu.on(MessageTypes.CLASS_JOIN_MCU_SUCCESS, this._mcuConferenceJoinSuccessHandler.bind(this)); this.mcu.registerApe(this); } diff --git a/src/apes/AudioApe.js b/src/apes/AudioApe.js index 538aec1..4bbc888 100644 --- a/src/apes/AudioApe.js +++ b/src/apes/AudioApe.js @@ -57,15 +57,21 @@ class AudioApe extends Ape { return {"code": ApeConsts.RETURN_FAILED, "data": "已经断开连接"}; } - if (_param == null||_param.channelId == null|| - _param.classId == null||_param.userId == null||_param.userId==""|| - _param.siteId == null|| _param.timestamp==null) + if (_param == null||_param.publishUrl == null) { loger.warn('publishAudio,参数错误', _param); this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG); return {"code": ApeConsts.RETURN_FAILED, "data": "参数错误"}; } + //根据推流的地址获取对应的频道信息 + let needPublishChannelInfo=this.mediaModule.getNeedPublishMediaChannel(_param.publishUrl); + if(needPublishChannelInfo==null){ + loger.warn('publishVideo,推流数据已经无效', _param); + return {"code": ApeConsts.RETURN_FAILED, "data": "推流数据已经无效"}; + } + + //同一个nodeId只允许推一个流,如果已经推了就不能再推 if(this.mediaModule.getOpeningMediaChannel(GlobalConfig.nodeId)!=0){ loger.warn("publishAudio,已经存在一个流,不能再推"); @@ -80,20 +86,20 @@ class AudioApe extends Ape { } //判断当前的频道是否已经占用 - if(this.mediaModule.checkChannelIsOpening(_param.channelId)){ - loger.warn(_param.channelId,"频道已经被占用"); + if(this.mediaModule.checkChannelIsOpening(needPublishChannelInfo.channelId)){ + loger.warn(needPublishChannelInfo.channelId,"频道已经被占用"); return {"code": ApeConsts.RETURN_FAILED, "data":"频道已经被占用!"}; } let channelInfo={}; channelInfo.status=ApeConsts.CHANNEL_STATUS_OPENING; channelInfo.fromNodeId=GlobalConfig.nodeId; - channelInfo.channelId=_param.channelId;//freeChannel - channelInfo.timestamp=_param.timestamp;//EngineUtils.creatTimestamp(); - channelInfo.classId=_param.classId;//GlobalConfig.classId; - channelInfo.siteId=_param.siteId;//GlobalConfig.siteId; + channelInfo.channelId=needPublishChannelInfo.channelId;//freeChannel + channelInfo.streamId=needPublishChannelInfo.streamId;//按规则拼接的流名称 + channelInfo.timestamp=needPublishChannelInfo.timestamp;//EngineUtils.creatTimestamp(); + channelInfo.classId=GlobalConfig.classId;//GlobalConfig.classId; + channelInfo.siteId=GlobalConfig.siteId;//GlobalConfig.siteId; channelInfo.toNodeId=0; - channelInfo.userId=_param.userId; channelInfo.mediaType=ApeConsts.MEDIA_TYPE_AUDIO; this.sendTableUpdateHandler(channelInfo); return {"code": ApeConsts.RETURN_SUCCESS, "data":"推流成功!"} @@ -106,9 +112,9 @@ class AudioApe extends Ape { loger.warn(GlobalConfig.getCurrentStatus()); return {"code": ApeConsts.RETURN_FAILED, "data": "已经断开连接"}; } - //_param如果为空,那么默认就是当前自己的nodeId,否则用_param + //_param如果为空或者0,那么默认就是当前自己的nodeId,否则用_param let nodeId; - if(_param&&parseInt(_param.nodeId)>=0){ + if(_param&&parseInt(_param.nodeId)>0){ nodeId=parseInt(_param.nodeId); }else { nodeId=GlobalConfig.nodeId; @@ -116,8 +122,8 @@ class AudioApe extends Ape { let openingChannel = this.mediaModule.getOpeningMediaChannel(nodeId); if (openingChannel == 0) { - loger.warn(nodeId,"stopPublishAudio,没有占用channel,不需要关闭"); - return {"code": ApeConsts.RETURN_FAILED, "data": "没有占用channel,不需要关闭"}; + loger.warn(nodeId,"没有占用channel不需要处理"); + return {"code": ApeConsts.RETURN_FAILED, "data": "没有占用channel不需要处理"}; } let channelInfo={}; @@ -244,11 +250,47 @@ class AudioApe extends Ape { tableUpdateHandler(owner, itemIdx, itemData) { // debugger; - let updateChannelInfo = this.unPackPdu(owner, itemIdx, itemData); - - this.mediaModule.mediaChannels[itemIdx] = updateChannelInfo; + /* let updateChannelInfo = this.unPackPdu(owner, itemIdx, itemData); + + this.mediaModule.mediaChannels[itemIdx] = updateChannelInfo; + + this._emit(MessageTypes.AUDIO_UPDATE, updateChannelInfo);*/ + let unpackChannelInfo = this.unPackPdu(owner, itemIdx, itemData); + this.mediaModule.mediaChannels[itemIdx] = unpackChannelInfo; + + if(unpackChannelInfo&&unpackChannelInfo.fromNodeId!=GlobalConfig.nodeId){ + let receiveChannelInfo={}; + receiveChannelInfo.mediaId=unpackChannelInfo.channelId; + + //消息不是自己同步的,需要处理 + if(unpackChannelInfo.status==ApeConsts.CHANNEL_STATUS_OPENING){ + //正在推流 + receiveChannelInfo.m3u8Url=""; + receiveChannelInfo.rtmpUrl=""; + let m3u8Stream=this.mediaModule.getMediaPlayPath({"type":"m3u8","streamId": unpackChannelInfo.streamId}); + let rtmpStream=this.mediaModule.getMediaPlayPath({"type":"rtmp","streamId": unpackChannelInfo.streamId}); + + if(m3u8Stream.code==0){ + receiveChannelInfo.m3u8Url=m3u8Stream.playUrl; + } + if(rtmpStream.code==0){ + receiveChannelInfo.rtmpUrl=rtmpStream.playUrl; + } + loger.log("AUDIO_PLAY"); + console.log(receiveChannelInfo); + //广播播放视频的消息 + this._emit(MessageTypes.AUDIO_PLAY, receiveChannelInfo); + }else { + loger.log("AUDIO_STOP"); + console.log(receiveChannelInfo); + //流已经停止 + this._emit(MessageTypes.AUDIO_STOP, receiveChannelInfo); + } + }else { + loger.warn("消息是自己发送的或者是消息无效,不需要处理,消息内容如下:"); + console.log(unpackChannelInfo); - this._emit(MessageTypes.AUDIO_UPDATE, updateChannelInfo); + } } ///////数据的封包和解包///////////////////////////////////////// @@ -264,6 +306,7 @@ class AudioApe extends Ape { let packPduModel = new pdu['RCAudioChannelInfoPdu']; packPduModel.status = _param.status||ApeConsts.CHANNEL_STATUS_RELEASED; packPduModel.channelId = _itemIdx; + packPduModel.streamId = _param.streamId||""; packPduModel.siteId=_param.siteId||GlobalConfig.siteId;//GlobalConfig.siteId; packPduModel.classId =parseInt(_param.classId)||parseInt(GlobalConfig.classId); packPduModel.userId =_param.userId||"0"; @@ -283,7 +326,7 @@ class AudioApe extends Ape { } try { let packChannelInfo = pdu['RCAudioChannelInfoPdu'].decode(itemData); - loger.log("unPackPdu",packChannelInfo); + console.log(packChannelInfo); return packChannelInfo; } catch (err) { loger.log("unPackPdu error,itemIdx=" + itemIdx + " err:" + err.message); diff --git a/src/apes/ConferApe.js b/src/apes/ConferApe.js index 15b6313..48ed254 100644 --- a/src/apes/ConferApe.js +++ b/src/apes/ConferApe.js @@ -548,7 +548,7 @@ class ConferApe extends Ape { //广播当前的人数 emitRosterChange() { - this._emit(MessageTypes.CLASS_SHOW_ROSTER_NUM, Object.keys(this.rosters).length); + this._emit(MessageTypes.CLASS_UPDATE_ROSTER_NUM, Object.keys(this.rosters).length); } ///////数据的封包和解包///////////////////////////////////////// diff --git a/src/apes/DocApe.js b/src/apes/DocApe.js index f458d41..3beff23 100644 --- a/src/apes/DocApe.js +++ b/src/apes/DocApe.js @@ -171,6 +171,7 @@ class DocApe extends Ape { if(lastIndex>0){ let newPath=fullPath.substr(0,lastIndex); let pathArr=[]; + //页数从1开始 for(let i=1;i<=_param.pageNum;i++){ pathArr.push(newPath+"/"+i+"."+fileType); } @@ -210,6 +211,8 @@ class DocApe extends Ape { //切换文档 documentSwitchDoc(paramInfo){ + loger.log('切换文档,documentSwitchDoc'); + console.log(paramInfo); if(paramInfo==null||paramInfo.itemIdx==null){ loger.warn('documentSwitch失败,参数错误',paramInfo); this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG); @@ -257,6 +260,8 @@ class DocApe extends Ape { //文档翻页 documentSwitchPage(paramInfo){ + loger.log('文档翻页,documentSwitchPage'); + console.log(paramInfo); //console.log(this.docList); //获取已经存在的数据 let docDataModel= this.docList[paramInfo.itemIdx]; diff --git a/src/apes/MediaModule.js b/src/apes/MediaModule.js index 0454a8c..d9912fa 100644 --- a/src/apes/MediaModule.js +++ b/src/apes/MediaModule.js @@ -12,6 +12,7 @@ let loger = Loger.getLoger('MediaModule'); class MediaModule { constructor() { + this.needPublishMediaChannel={};//记录准备推流的频道信息 this.mediaChannels = {}; this.maxMediaChannel=0; this.MEDIA_OBJ_TABLE_ID=0; @@ -20,9 +21,7 @@ class MediaModule { //获取播流地址 getMediaPlayPath(_param) { loger.log('getMediaPlayPath'); - if (_param == null||_param.siteId == null|| - _param.classId == null||_param.userId == null|| - _param.channelId == null|| _param.timestamp==null) + if (_param == null||_param.streamId == null) { loger.warn('getMediaPlayPath,参数错误', _param); //this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG); @@ -37,21 +36,13 @@ class MediaModule { port = (GlobalConfig.RSServerPort == "" || GlobalConfig.RSServerPort == null) ? "":":" + GlobalConfig.RSServerPort; path = "http://" + GlobalConfig.RSServerIP + port + "/live/" - + _param.siteId - + "_" + _param.classId - + "_" + _param.userId - + "_" + _param.channelId - + "_" + _param.timestamp + + _param.streamId + "/index.m3u8"; } else { port = (GlobalConfig.MSServerPort == "" || GlobalConfig.MSServerPort == null) ? "":":" + GlobalConfig.MSServerPort; path = "rtmp://" + GlobalConfig.MSServerIP + port + "/live/" - + _param.siteId - + "_" + _param.classId - + "_" + _param.userId - + "_" + _param.channelId - + "_" + _param.timestamp; + + _param.streamId; } return {"code": ApeConsts.RETURN_SUCCESS, "data": "","playUrl": path}; } @@ -77,18 +68,21 @@ class MediaModule { //时间戳 let timestamp = EngineUtils.creatTimestamp(); - //生成推流地址和推流数据(同步数据的时候用) - let publishUrl = "rtmp://" + GlobalConfig.MSServerIP - + port + "/"+pubType+"/" +GlobalConfig.siteId+"_" + let streamId=GlobalConfig.siteId+"_" + GlobalConfig.classId + "_"+GlobalConfig.userId +"_" + freeChannel + "_" + timestamp; + + //生成推流地址和推流数据(同步数据的时候用) + let publishUrl = "rtmp://" + GlobalConfig.MSServerIP + + port + "/"+pubType+"/" +streamId; + + this.needPublishMediaChannel[publishUrl]={ + "channelId":freeChannel, + "publishUrl":publishUrl, + "streamId":streamId + }; return {"code": ApeConsts.RETURN_SUCCESS, "data":"", - "siteId":GlobalConfig.siteId, - "classId":GlobalConfig.classId, - "userId":GlobalConfig.userId, - "channelId": freeChannel, - "timestamp": timestamp, "publishUrl": publishUrl }; } @@ -111,6 +105,11 @@ class MediaModule { return 0;//没有空闲的 } + //获取准备推流的频道信息 + getNeedPublishMediaChannel(_publishUrl){ + return this.needPublishMediaChannel[_publishUrl]; + } + //获取当前属于nodeId的已经打开的的channel,返回值为0代表没有打开的,否则返回的就是打开的channelId getOpeningMediaChannel(_nodeId){ if(_nodeId==null||_nodeId==0){ diff --git a/src/apes/VideoApe.js b/src/apes/VideoApe.js index cdbd406..eb53ce5 100644 --- a/src/apes/VideoApe.js +++ b/src/apes/VideoApe.js @@ -58,16 +58,19 @@ class VideoApe extends Ape { return {"code": ApeConsts.RETURN_FAILED, "data": "已经断开连接"}; } - if (_param == null||_param.channelId == null|| - _param.classId == null||_param.userId == null||_param.userId == ""|| - _param.siteId == null|| _param.timestamp==null) + if (_param == null||_param.publishUrl == null) { loger.warn('publishVideo,参数错误', _param); this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG); return {"code": ApeConsts.RETURN_FAILED, "data": "参数错误"}; } - loger.log('publishVideo -> maxVideoChannels', GlobalConfig.maxVideoChannels); + //根据推流的地址获取对应的频道信息 + let needPublishChannelInfo=this.mediaModule.getNeedPublishMediaChannel(_param.publishUrl); + if(needPublishChannelInfo==null){ + loger.warn('publishVideo,推流数据已经无效', _param); + return {"code": ApeConsts.RETURN_FAILED, "data": "推流数据已经无效"}; + } //同一个nodeId只允许推一个流,如果已经推了就不能再推 if(this.mediaModule.getOpeningMediaChannel(GlobalConfig.nodeId)!=0){ @@ -82,23 +85,22 @@ class VideoApe extends Ape { return {"code": ApeConsts.RETURN_FAILED, "data": "不能再打开更多的设备"}; } + //判断当前的频道是否已经占用 - if(this.mediaModule.checkChannelIsOpening(_param.channelId)){ - loger.warn(_param.channelId,"频道已经被占用"); + if(this.mediaModule.checkChannelIsOpening(needPublishChannelInfo.channelId)){ + loger.warn(needPublishChannelInfo.channelId,"频道已经被占用"); return {"code": ApeConsts.RETURN_FAILED, "data":"频道已经被占用!"}; } let channelInfo={}; channelInfo.status=ApeConsts.CHANNEL_STATUS_OPENING; channelInfo.fromNodeId=GlobalConfig.nodeId; - channelInfo.channelId=_param.channelId;//freeChannel - channelInfo.timestamp=_param.timestamp;//EngineUtils.creatTimestamp(); - channelInfo.classId=_param.classId;//GlobalConfig.classId; - channelInfo.siteId=_param.siteId;//GlobalConfig.siteId; + channelInfo.channelId=needPublishChannelInfo.channelId; + channelInfo.streamId=needPublishChannelInfo.streamId;//按规则拼接的流名称 + channelInfo.classId=GlobalConfig.classId; + channelInfo.siteId=GlobalConfig.siteId; channelInfo.toNodeId=0; channelInfo.mediaType=ApeConsts.MEDIA_TYPE_VIDEO; - channelInfo.userId=_param.userId; - this.sendTableUpdateHandler(channelInfo); return {"code": ApeConsts.RETURN_SUCCESS, "data":"推流成功!"} } @@ -113,7 +115,7 @@ class VideoApe extends Ape { loger.log('stopPublishVideo -> maxVideoChannels', GlobalConfig.maxVideoChannels); //_param如果为空,那么默认就是当前自己的nodeId,否则用_param let nodeId; - if(_param&&parseInt(_param.nodeId)>=0){ + if(_param&&parseInt(_param.nodeId)>0){ nodeId=parseInt(_param.nodeId); }else { nodeId=GlobalConfig.nodeId; @@ -121,8 +123,8 @@ class VideoApe extends Ape { let openingChannel = this.mediaModule.getOpeningMediaChannel(nodeId); if (openingChannel == 0) { - loger.warn(nodeId,"stopPublishVideo,没有占用channel,不需要关闭"); - return {"code": ApeConsts.RETURN_FAILED, "data": "没有占用channel,不需要关闭"}; + loger.warn(nodeId,"没有占用channel不需要处理"); + return {"code": ApeConsts.RETURN_FAILED, "data": "没有占用channel不需要处理"}; } let channelInfo={}; @@ -267,9 +269,44 @@ class VideoApe extends Ape { tableUpdateHandler(owner, itemIdx, itemData) { // debugger; - let videoChannelInfo = this.unPackPdu(owner, itemIdx, itemData); - this.mediaModule.mediaChannels[itemIdx] = videoChannelInfo; - this._emit(MessageTypes.VIDEO_UPDATE, videoChannelInfo); + let unpackChannelInfo = this.unPackPdu(owner, itemIdx, itemData); + this.mediaModule.mediaChannels[itemIdx] = unpackChannelInfo; + + if(unpackChannelInfo&&unpackChannelInfo.fromNodeId!=GlobalConfig.nodeId){ + let receiveChannelInfo={}; + receiveChannelInfo.mediaId=unpackChannelInfo.channelId; + + //消息不是自己同步的,需要处理 + if(unpackChannelInfo.status==ApeConsts.CHANNEL_STATUS_OPENING){ + //正在推流 + receiveChannelInfo.m3u8Url=""; + receiveChannelInfo.rtmpUrl=""; + let m3u8Stream=this.mediaModule.getMediaPlayPath({"type":"m3u8","streamId": unpackChannelInfo.streamId}); + let rtmpStream=this.mediaModule.getMediaPlayPath({"type":"rtmp","streamId": unpackChannelInfo.streamId}); + + if(m3u8Stream.code==0){ + receiveChannelInfo.m3u8Url=m3u8Stream.playUrl; + } + if(rtmpStream.code==0){ + receiveChannelInfo.rtmpUrl=rtmpStream.playUrl; + } + loger.log("VIDEO_PLAY"); + console.log(receiveChannelInfo); + //广播播放视频的消息 + this._emit(MessageTypes.VIDEO_PLAY, receiveChannelInfo); + }else { + loger.log("VIDEO_STOP"); + console.log(receiveChannelInfo); + //流已经停止 + this._emit(MessageTypes.VIDEO_STOP, receiveChannelInfo); + } + }else { + loger.warn("视频消息是自己发送的或者是视频消息无效,不需要处理,消息内容如下:"); + console.log(unpackChannelInfo); + + } + + //this._emit(MessageTypes.VIDEO_UPDATE, videoChannelInfo); } ///////数据的封包和解包///////////////////////////////////////// @@ -285,6 +322,7 @@ class VideoApe extends Ape { let packPduModel = new pdu['RCVideoChannelInfoPdu']; packPduModel.status = _param.status||ApeConsts.CHANNEL_STATUS_RELEASED; packPduModel.channelId = _itemIdx; + packPduModel.streamId = _param.streamId||""; packPduModel.siteId=_param.siteId||GlobalConfig.siteId;//GlobalConfig.siteId; packPduModel.classId =parseInt(_param.classId)||parseInt(GlobalConfig.classId); packPduModel.userId =_param.userId||"0"; @@ -305,7 +343,7 @@ class VideoApe extends Ape { try { let videoChannelInfo = pdu['RCVideoChannelInfoPdu'].decode(itemData); - loger.log("unPackPdu",videoChannelInfo); + console.log(videoChannelInfo); return videoChannelInfo; } catch (err) { loger.log("unPackPdu error,itemIdx=" + itemIdx + " err:" + err.message); diff --git a/src/mcu.js b/src/mcu.js index ac639bd..f68679b 100644 --- a/src/mcu.js +++ b/src/mcu.js @@ -98,7 +98,7 @@ class MCU extends Emiter { case PduConsts.RET_SUCCESS: //加入成功 this._updateMCUConfInfoDescription(joinConfPdu.classDescription); - this._emit(MessageTypes.CLASS_JOIN_SUCCESS, this.classInfo); + 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); diff --git a/src/pdus/pro.js b/src/pdus/pro.js index b712184..a8d55e1 100644 --- a/src/pdus/pro.js +++ b/src/pdus/pro.js @@ -776,6 +776,7 @@ message RCAudioChannelInfoPdu { optional uint32 class_id = 7;//课堂号 optional string site_id = 8;//站点号 optional string user_id = 9;//用户的userId + optional string stream_id = 10;//流名称 } message RCVideoChannelInfoPdu { @@ -788,6 +789,7 @@ message RCVideoChannelInfoPdu { optional uint32 class_id = 7;//课堂号 optional string site_id = 8;//站点号 optional string user_id = 9;//用户的userId + optional string stream_id = 10;//流名称 } message RCVideoChannelInfoRecordPdu {