李勇

1.修改ape消息延迟处理的 mcuDelay

2.增加离开人员音视频模块channel占用的检查,如果存在占用,由当前人员列表中最早进入的人来释放channle
... ... @@ -89,11 +89,12 @@ 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));//这个监听事件不能删除,需要通知会议模块,检查channel占用
_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));//这个监听事件不能删除,需要通知会议模块,检查channel占用
_whiteboard_ape = new WhiteBoardApe();
_whiteboard_ape.on('*', (type, data) => this._emit(type, data));
... ... @@ -220,8 +221,7 @@ export default class MessageEntrance extends Emiter {
_onClassDeleteRoster(_data){
//{"nodeId":nodeId}
//当有人员离开的时候,如果离开的人员已经推流,那么需要停止推流,然后释放channel;
//只有自己是主持人的时候出才处理下面的事情
if(_data!=null&&_data.nodeId!=null&&GlobalConfig.isHost){
/* if(_data!=null&&_data.nodeId!=null){
loger.log("有人员离开,检查一下离开的人员是否关闭推流");
if(_video_ape){
_video_ape.stopPublishVideo(_data);
... ... @@ -229,7 +229,7 @@ export default class MessageEntrance extends Emiter {
if(_audio_ape){
_audio_ape.stopPublishAudio(_data);
}
}
}*/
}
//当前会议中视频或音频占用channel的nodeId ,在人员列表中不存在,这种情况是占用channel的人员掉线或离开的时候没有释放channel
... ... @@ -469,6 +469,7 @@ export default class MessageEntrance extends Emiter {
// console.log(_data);
//包含整个会议最全的信息,储存数据
if (_data) {
GlobalConfig.mcuDelay=_data.mcuDelay || 60;//mcu消息延迟,用于文档模块
GlobalConfig.className = _data.meetingName || "";
GlobalConfig.classBeginTime = _data.beginTime || "";
GlobalConfig.classEndTime = _data.endTime || "";
... ...
... ... @@ -241,7 +241,7 @@ GlobalConfig.statusCode_4={"code":4,message:"未知状态"};
GlobalConfig.md5="";
GlobalConfig.msType=1;//目前固定用这个
GlobalConfig.mcuDelay=3000;//默认的延迟时间
GlobalConfig.mcuDelay=60;//默认的延迟时间 flash中使用的是3000毫秒
GlobalConfig.docDelay=1600;//文档模块加入成功之后延迟发送送成功的消息给主模块
GlobalConfig.portal="112.126.80.182:80";//Sass IP
... ...
... ... @@ -37,13 +37,13 @@ MessageTypes.CHAT_RECEIVE ="chat_receive_message";// 'chat.receive';
//视频模块事件定义
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_UPDATE ="video_update";// //这个监听事件不能删除,需要通知会议模块,检查channel占用(内部使用)
MessageTypes.VIDEO_BROADCAST= "video_broadcast";//'video.broadcast';
//音频模块事件定义
MessageTypes.AUDIO_PLAY ="audio_play";// 'audio.play';//播放
MessageTypes.AUDIO_STOP = "audio_stop";//'audio.stop';//停止
//MessageTypes.AUDIO_UPDATE = "502";//'audio.update';
MessageTypes.AUDIO_UPDATE = "audio_update";//这个监听事件不能删除,需要通知会议模块,检查channel占用(内部使用)
MessageTypes.AUDIO_BROADCAST= "audio_broadcast";//'audio.broadcast';
... ...
... ... @@ -70,7 +70,7 @@ export default class Ape extends Emiter {
// this._apeDelayedStart();
setTimeout(() => {
this._pduRegAdapterHandler(regBuffer);
},GlobalConfig.mcuDelay|| 12000);
},GlobalConfig.mcuDelay|| 2000);
return;
}
this._pduRegAdapterHandler(regBuffer);
... ...
... ... @@ -71,18 +71,19 @@ class AudioApe extends Ape {
return {"code": ApeConsts.RETURN_FAILED, "data": "推流数据已经无效"};
}
/* //20170302 修改频道占用规则,同一个人可以推多路流,暂停下面的限制
//同一个nodeId只允许推一个流,如果已经推了就不能再推
if(this.mediaModule.getOpeningMediaChannel(GlobalConfig.nodeId)!=0){
loger.warn("publishAudio,已经存在一个流,不能再推");
return {"code": ApeConsts.RETURN_FAILED, "data": "已经存在一个流,不能再推"};
}
return {"code": ApeConsts.RETURN_FAILED, "data": "已经存在一个流,不能再推","mediaChannels":this.mediaModule.mediaChannels};
}*/
//判断当前是否还有空闲的channle
let freeChannel = this.mediaModule.getFreeMediaChannel();
if (freeChannel == 0) {
loger.warn("publishAudio,没有空闲的channel ");
return {"code": ApeConsts.RETURN_FAILED, "data": "不能再打开更多的设备"};
return {"code": ApeConsts.RETURN_FAILED, "data": "不能再打开更多的设备","mediaChannels":this.mediaModule.mediaChannels};
}
//判断当前的频道是否已经占用
... ... @@ -100,6 +101,7 @@ class AudioApe extends Ape {
channelInfo.classId=GlobalConfig.classId;//GlobalConfig.classId;
channelInfo.siteId=GlobalConfig.siteId;//GlobalConfig.siteId;
channelInfo.toNodeId=0;
channelInfo.userId=GlobalConfig.userId;
channelInfo.mediaType=ApeConsts.MEDIA_TYPE_AUDIO;
this.sendTableUpdateHandler(channelInfo);
return {"code": ApeConsts.RETURN_SUCCESS, "data":"推流成功!"}
... ... @@ -133,11 +135,13 @@ class AudioApe extends Ape {
channelInfo.timestamp=0;
channelInfo.classId=GlobalConfig.classId;
channelInfo.toNodeId=0;
channelInfo.userId=GlobalConfig.userId;
channelInfo.mediaType=ApeConsts.MEDIA_TYPE_DEFAULT;
this.sendTableUpdateHandler(channelInfo);
}
sendAudioBroadcastMsg(_param) {
loger.log('sendAudioBroadcastMsg',_param);
if(!this.mcu.connected){
loger.warn(GlobalConfig.getCurrentStatus());
return {"code": ApeConsts.RETURN_FAILED, "data": "已经断开连接"};
... ... @@ -163,7 +167,7 @@ class AudioApe extends Ape {
let freeChannel = this.mediaModule.getFreeMediaChannel();
if (freeChannel == 0) {
loger.warn('sendAudioBroadcastMsg,不能再打开更多的设备', _param);
return {"code": ApeConsts.RETURN_FAILED, "data": "不能再打开更多的设备"};
return {"code": ApeConsts.RETURN_FAILED, "data": "不能再打开更多的设备","mediaChannels":this.mediaModule.mediaChannels};
}
}
... ... @@ -173,7 +177,7 @@ class AudioApe extends Ape {
audioSendPdu.isPublic = true;
audioSendPdu.fromNodeId = GlobalConfig.nodeId;//发起人
audioSendPdu.toNodeId = parseInt(_param.toNodeID) || 0;//接收者,0就是所有人
audioSendPdu.toNodeId = parseInt(_param.toNodeId) || 0;//接收者,0就是所有人
audioSendPdu.actionType = parseInt(_param.actionType) || ApeConsts.MEDIA_ACTION_DEFAULT;
audioSendPdu.data = this._rCArrayBufferUtil.strToUint8Array("h5" + _param.data);//开头两个字会乱码
... ... @@ -291,6 +295,7 @@ class AudioApe extends Ape {
console.log(unpackChannelInfo);
}
this._emit(MessageTypes.AUDIO_UPDATE, unpackChannelInfo);
}
///////数据的封包和解包/////////////////////////////////////////
... ...
... ... @@ -493,6 +493,10 @@ class ConferApe extends Ape {
this.hostNodeId = -1;
this.hostUserId = '';
}
//判断进入的用户身份,如果进入的人身份是host,助教,监课,并且和自己的身份冲突,自己会被踢掉
let rosterExists = this.rosters[nodeId];
this.rosters[nodeId] = nodeData;
let userDataObj=null;
... ... @@ -508,6 +512,8 @@ class ConferApe extends Ape {
loger.log("更新人员列表数据 rosterUpdateHandler",{"nodeId":nodeId});
this._emit(MessageTypes.CLASS_INSERT_ROSTER, {"nodeId":nodeId,"nodeData":newNodeData});
this.emitRosterChange();
}else {
//loger.log("更新人员列表数据,rosterExists已经存在",rosterExists);
}
... ... @@ -516,15 +522,14 @@ class ConferApe extends Ape {
//视频模块发生更新,人员状态需要更新
updaterRosterStatus(_param){
if(_param){
loger.log("媒体模块发生更新,人员状态需要更新,fromNodeId->",_param.fromNodeId);
loger.log(_param.status,_param.fromNodeId);
//loger.log("媒体模块发生更新,人员状态需要更新,fromNodeId->",_param.fromNodeId);
//loger.log(_param.status,_param.fromNodeId);
//console.log(_param.fromNodeId);
//如果是自己。改变自己的状态同步到MCU
//if(_param.fromNodeId==GlobalConfig.nodeId){
//
//}
//如果视频消息中channel的占用人 fromNodeId在人员列表中不存在,需要释放这channel,因为这个有可能是之前没释放成功的
if(_param.status==ApeConsts.CHANNEL_STATUS_OPENING&&this.rosters[_param.fromNodeId]==null){
loger.log("媒体模块被占用,占有人已经不存在课堂中,释放Channel,_param->",_param);
... ... @@ -541,8 +546,20 @@ class ConferApe extends Ape {
}else {
loger.log("有人离开 rosterDelHandler");
delete this.rosters[nodeId];
this._emit(MessageTypes.CLASS_DELETE_ROSTER, {"nodeId":nodeId});
this.emitRosterChange();
this._emit(MessageTypes.CLASS_DELETE_ROSTER, {"nodeId":nodeId});
//当前人员列表中抽一个人来检查离开人员是否占用频道
for (let key in this.rosters){
let randNodeId=parseInt(key);
if(randNodeId==GlobalConfig.nodeId){
loger.log(randNodeId,"有权限检查离开的人员是否占用channel");
this._emit(MessageTypes.CLASS_NONENTITY_ROSTER, {"nodeId":nodeId});
}else {
loger.warn(GlobalConfig.nodeId,"没有权限检查离开的人员是否占用channel");
}
return;
}
}
}
... ...
... ... @@ -35,7 +35,7 @@ class DocApe extends Ape {
//this.activeDocItemIdx =0;//当前激活的文档itemIdx
//this.activeDocCurPage=1;//当前激活的文档的当前页
// 延迟
this._apeDelayed = true;
this._apeDelayed = false;
// Ape Models
this.registerKey(this._session_id, this._session_name, this._session_tag, new ArrayBuffer);
... ... @@ -440,7 +440,9 @@ class DocApe extends Ape {
this._emit(DocApe.DOC_JOIN_CHANNEL_SUCCESS);
},(GlobalConfig.mcuDelay+GlobalConfig.docDelay)|| 12000+GlobalConfig.docDelay);
}else {
this._emit(DocApe.DOC_JOIN_CHANNEL_SUCCESS);
setTimeout(() => {
this._emit(DocApe.DOC_JOIN_CHANNEL_SUCCESS);
},GlobalConfig.docDelay);
}
}
... ...
... ... @@ -112,6 +112,7 @@ class MediaModule {
//获取当前属于nodeId的已经打开的的channel,返回值为0代表没有打开的,否则返回的就是打开的channelId
getOpeningMediaChannel(_nodeId){
loger.log("getOpeningMediaChannel","nodeId",_nodeId,"mediaChannels:",this.mediaChannels);
if(_nodeId==null||_nodeId==0){
return 0;
}
... ...
... ... @@ -72,24 +72,28 @@ class VideoApe extends Ape {
return {"code": ApeConsts.RETURN_FAILED, "data": "推流数据已经无效"};
}
/* //20170302 修改频道占用规则,同一个人可以推多路流,暂停下面的限制
//同一个nodeId只允许推一个流,如果已经推了就不能再推
if(this.mediaModule.getOpeningMediaChannel(GlobalConfig.nodeId)!=0){
loger.warn("publishVideo,已经存在一个流,不能再推");
return {"code": ApeConsts.RETURN_FAILED, "data": "已经存在一个流,不能再推"};
}
}*/
//判断当前是否还有空闲的channle
let freeChannel = this.mediaModule.getFreeMediaChannel();
if (freeChannel == 0) {
loger.warn("publishVideo,没有空闲的channel ");
return {"code": ApeConsts.RETURN_FAILED, "data": "不能再打开更多的设备"};
return {"code": ApeConsts.RETURN_FAILED, "data": "不能再打开更多的设备","mediaChannels":this.mediaModule.mediaChannels};
}
//判断当前的频道是否已经占用
if(this.mediaModule.checkChannelIsOpening(needPublishChannelInfo.channelId)){
loger.warn(needPublishChannelInfo.channelId,"频道已经被占用");
return {"code": ApeConsts.RETURN_FAILED, "data":"频道已经被占用!"};
return {"code": ApeConsts.RETURN_FAILED, "data":"频道已经被占用!","mediaChannels":this.mediaModule.mediaChannels};
}
let channelInfo={};
... ... @@ -100,6 +104,7 @@ class VideoApe extends Ape {
channelInfo.classId=GlobalConfig.classId;
channelInfo.siteId=GlobalConfig.siteId;
channelInfo.toNodeId=0;
channelInfo.userId=GlobalConfig.userId;
channelInfo.mediaType=ApeConsts.MEDIA_TYPE_VIDEO;
this.sendTableUpdateHandler(channelInfo);
return {"code": ApeConsts.RETURN_SUCCESS, "data":"推流成功!"}
... ... @@ -112,7 +117,6 @@ class VideoApe extends Ape {
return {"code": ApeConsts.RETURN_FAILED, "data": "已经断开连接"};
}
loger.log('stopPublishVideo -> maxVideoChannels', GlobalConfig.maxVideoChannels);
//_param如果为空,那么默认就是当前自己的nodeId,否则用_param
let nodeId;
if(_param&&parseInt(_param.nodeId)>0){
... ... @@ -121,6 +125,8 @@ class VideoApe extends Ape {
nodeId=GlobalConfig.nodeId;
}
loger.log('stopPublishVideo ->nodeId',nodeId,' maxVideoChannels', GlobalConfig.maxVideoChannels);
let openingChannel = this.mediaModule.getOpeningMediaChannel(nodeId);
if (openingChannel == 0) {
loger.warn(nodeId,"没有占用channel不需要处理");
... ... @@ -134,6 +140,7 @@ class VideoApe extends Ape {
channelInfo.timestamp=0;
channelInfo.classId=GlobalConfig.classId;
channelInfo.toNodeId=0;
channelInfo.userId=GlobalConfig.userId;
channelInfo.mediaType=ApeConsts.MEDIA_TYPE_DEFAULT;
this.sendTableUpdateHandler(channelInfo);
}
... ... @@ -180,7 +187,7 @@ class VideoApe extends Ape {
videoSendPdu.isPublic = true;
videoSendPdu.fromNodeId = GlobalConfig.nodeId;//发起人
videoSendPdu.toNodeId = parseInt(_param.toNodeID) || 0;//接收者,0就是所有人
videoSendPdu.toNodeId = parseInt(_param.toNodeId) || 0;//接收者,0就是所有人
videoSendPdu.actionType = parseInt(_param.actionType) || ApeConsts.MEDIA_ACTION_DEFAULT;
videoSendPdu.data = this._rCArrayBufferUtil.strToUint8Array("h5" + _param.data);//开头两个字会乱码
... ... @@ -199,17 +206,6 @@ class VideoApe extends Ape {
sendTableUpdateHandler(_channelInfo) {
loger.log("video===sendTableUpdateHandler ");
/* //验证坐标点集合数组是否合法
if(_docDataModel==null||_itemIdx==null){
this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG);
return null;
}*/
//let freeChannel=this.getFreeVideoChannel();
//if(freeChannel==0){
// loger.warn("sendTableUpdateHandler,没有空闲的channel ");
// return;
//}
let updateModelPdu = this.packPdu(_channelInfo, _channelInfo.channelId);//let updateModelPdu=this.packPdu({},ApeConsts.VIDEO_OBJ_TABLE_ID+2);
if(updateModelPdu==null){
loger.warn("sendTableUpdateHandler error,updateModelPdu=null");
... ... @@ -306,7 +302,7 @@ class VideoApe extends Ape {
}
//this._emit(MessageTypes.VIDEO_UPDATE, videoChannelInfo);
this._emit(MessageTypes.VIDEO_UPDATE, unpackChannelInfo);
}
///////数据的封包和解包/////////////////////////////////////////
... ...