李勇

1.简化了音视频模块的推流和播流接口,收到的音视频消息分为(播放、停止)

2.修改事件消息定义
... ... @@ -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);
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,8 +325,6 @@ export default class MessageEntrance extends Emiter {
//设置当前的会议状态
GlobalConfig.setCurrentStatus(GlobalConfig.statusCode_1);
if (_initSuccessCallBackFun) {
//返回给客户端初始化成功的数据
let initSuccessCallBackData = {};
initSuccessCallBackData.siteId = GlobalConfig.siteId;
... ... @@ -341,8 +340,12 @@ export default class MessageEntrance extends Emiter {
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,12 +569,10 @@ export default class MessageEntrance extends Emiter {
}
// MCU 会议成功
_mcuJoinClassSuccessHandler(_data) {
_mcuJoinMCUClassSuccessHandler(_data) {
loger.log('MCU 会议成功.');
GlobalConfig.setCurrentStatus(GlobalConfig.statusCode_2);
//返回给客户数据
if (_joinClassSuccessCallBackFun) {
//返回给客户端初始化成功的数据
let initSuccessCallBackData = {};
... ... @@ -606,8 +609,14 @@ export default class MessageEntrance extends Emiter {
initSuccessCallBackData.classType = GlobalConfig.classType || ApeConsts.CLASS_TYPE_INTERACT;
loger.log('加入会议成功');
console.log(initSuccessCallBackData);
//加入会议成功,广播消息
this._emit(MessageTypes.CLASS_JOIN_SUCCESS,initSuccessCallBackData);
/* //返回给客户数据
if (_joinClassSuccessCallBackFun) {
_joinClassSuccessCallBackFun(initSuccessCallBackData);
}
}*/
}
//Sass删除文档数据
... ...
... ... @@ -42,7 +42,11 @@ class EverSocket extends Emiter {
send(data) {
if (this._connected) {
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() {
... ...
/**
*事件定义和错误码定义
*事件消息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鍦ㄦ帴鍙h皟鐢ㄦ椂鍙傛暟閿欒
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]="未知错误";
... ...
... ... @@ -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;
... ...
... ... @@ -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);
}
... ...
... ... @@ -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);
/* let updateChannelInfo = this.unPackPdu(owner, itemIdx, itemData);
this.mediaModule.mediaChannels[itemIdx] = updateChannelInfo;
this._emit(MessageTypes.AUDIO_UPDATE, 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);
}
}
///////数据的封包和解包/////////////////////////////////////////
... ... @@ -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);
... ...
... ... @@ -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);
}
///////数据的封包和解包/////////////////////////////////////////
... ...
... ... @@ -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];
... ...
... ... @@ -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){
... ...
... ... @@ -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);
... ...
... ... @@ -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);
... ...
... ... @@ -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 {
... ...