李勇

1.修改视频模块数据的PDU

2.推流和播流地址根据类型拼接
3.在会议模块增加对视频模块的无效的占用channel的释放
@@ -77,6 +77,8 @@ export default class MessageEntrance extends Emiter { @@ -77,6 +77,8 @@ export default class MessageEntrance extends Emiter {
77 _confer_ape.on(MessageTypes.CLASS_EXIT, this._doClassExit.bind(this));//监听自己的关闭事件 77 _confer_ape.on(MessageTypes.CLASS_EXIT, this._doClassExit.bind(this));//监听自己的关闭事件
78 _confer_ape.on(MessageTypes.CLASS_STATUS_INFO_CHANGE, this._onClassStatusInfoChange.bind(this));//当前会议状态信息发生改变 78 _confer_ape.on(MessageTypes.CLASS_STATUS_INFO_CHANGE, this._onClassStatusInfoChange.bind(this));//当前会议状态信息发生改变
79 _confer_ape.on(MessageTypes.CLASS_DELETE_ROSTER, this._onClassDeleteRoster.bind(this));//当前会议人员离开 79 _confer_ape.on(MessageTypes.CLASS_DELETE_ROSTER, this._onClassDeleteRoster.bind(this));//当前会议人员离开
  80 + _confer_ape.on(MessageTypes.CLASS_NONENTITY_ROSTER,this._onClassNonentityRoster.bind(this));//当前会议中视频或音频占用channel的nodeId ,在人员列表中不存在
  81 +
80 82
81 _chat_ape = new ChatApe(); 83 _chat_ape = new ChatApe();
82 _chat_ape.on('*', (type, data) => this._emit(type, data)); 84 _chat_ape.on('*', (type, data) => this._emit(type, data));
@@ -180,11 +182,24 @@ export default class MessageEntrance extends Emiter { @@ -180,11 +182,24 @@ export default class MessageEntrance extends Emiter {
180 if(_data!=null&&_data.nodeId!=null&&GlobalConfig.isHost){ 182 if(_data!=null&&_data.nodeId!=null&&GlobalConfig.isHost){
181 loger.log("有人员离开,检查一下离开的人员是否关闭推流"); 183 loger.log("有人员离开,检查一下离开的人员是否关闭推流");
182 if(_video_ape){ 184 if(_video_ape){
183 - _video_ape.stopPublishVideo(_data.nodeId); 185 + _video_ape.stopPublishVideo(_data);
184 } 186 }
185 } 187 }
186 } 188 }
187 189
  190 + //当前会议中视频或音频占用channel的nodeId ,在人员列表中不存在,这种情况是占用channel的人员掉线或离开的时候没有释放channel
  191 + //的占用状态导致,对于这种情况,需要释放掉
  192 + _onClassNonentityRoster(_param){
  193 + if(_param==null||_param.fromNodeId==null){
  194 + loger.warn("onClassNonentityRoster.参数错误")
  195 + return;
  196 + }
  197 + if(_video_ape){
  198 + _video_ape.stopPublishVideo({"nodeId":_param.fromNodeId});
  199 + }
  200 + }
  201 +
  202 +
188 //Sass 203 //Sass
189 //初始化 204 //初始化
190 _init(_param, _onSuccess, _mcuErrorCallBack) { 205 _init(_param, _onSuccess, _mcuErrorCallBack) {
@@ -397,13 +412,14 @@ export default class MessageEntrance extends Emiter { @@ -397,13 +412,14 @@ export default class MessageEntrance extends Emiter {
397 //包含整个会议最全的信息,储存数据 412 //包含整个会议最全的信息,储存数据
398 if (_data) { 413 if (_data) {
399 GlobalConfig.setDocListPrepare(_data.docListPrepare); //提前上传的文档列表 414 GlobalConfig.setDocListPrepare(_data.docListPrepare); //提前上传的文档列表
400 - GlobalConfig.setDocRecordList(_data.docRecordList);//  
401 - GlobalConfig.setDocList(_data.docList);//  
402 - GlobalConfig.setMsList(_data.msList);//  
403 - GlobalConfig.setMcuList(_data.mcuList);// 415 + GlobalConfig.setDocRecordList(_data.docRecordList);//录制回放地址??
  416 + GlobalConfig.setDocList(_data.docList);//文档地址
  417 + GlobalConfig.setMsList(_data.msList);//推流播流服务器地址
  418 + GlobalConfig.setRsList(_data.rsList);//播放m3u8格式的地址
  419 + GlobalConfig.setMcuList(_data.mcuList);//mcu
404 GlobalConfig.setMusicList(_data.musicList);// 420 GlobalConfig.setMusicList(_data.musicList);//
405 - GlobalConfig.setMusicListPrepare(_data.musicListPrepare);//  
406 - GlobalConfig.setRsList(_data.rsList);// 421 + GlobalConfig.setMusicListPrepare(_data.musicListPrepare);//提前上传的声音文件列表
  422 +
407 423
408 } 424 }
409 if (_data.currentInfo) { 425 if (_data.currentInfo) {
@@ -16,8 +16,10 @@ MessageTypes.CLASS_JOIN_SUCCESS = 'join.class.success'; @@ -16,8 +16,10 @@ MessageTypes.CLASS_JOIN_SUCCESS = 'join.class.success';
16 //会议信息和操作事件定义 16 //会议信息和操作事件定义
17 //MessageTypes.CLASS_SHOW_DETAIL = 'class_detail.message'; 17 //MessageTypes.CLASS_SHOW_DETAIL = 'class_detail.message';
18 MessageTypes.CLASS_SHOW_ROSTER_NUM = 'roster_num.message'; 18 MessageTypes.CLASS_SHOW_ROSTER_NUM = 'roster_num.message';
19 -MessageTypes.CLASS_INSERT_ROSTER = 'roster_insert.message';  
20 -MessageTypes.CLASS_DELETE_ROSTER = 'roster_delete.message'; 19 +MessageTypes.CLASS_INSERT_ROSTER = 'roster.insert.message';
  20 +MessageTypes.CLASS_DELETE_ROSTER = 'roster.delete.message';
  21 +MessageTypes.CLASS_NONENTITY_ROSTER = 'roster.nonentity.message';
  22 +
21 MessageTypes.CLASS_EXIT = 'class.exit';//退出 关闭会议 23 MessageTypes.CLASS_EXIT = 'class.exit';//退出 关闭会议
22 MessageTypes.CLASS_UPTATE_STATUS = 'class.update.status';//更新会议状态信息 24 MessageTypes.CLASS_UPTATE_STATUS = 'class.update.status';//更新会议状态信息
23 MessageTypes.CLASS_STATUS_INFO_CHANGE= 'class.status.info.change';//会议状态信息发生改变,需要保存数据到sass和同步MCU 25 MessageTypes.CLASS_STATUS_INFO_CHANGE= 'class.status.info.change';//会议状态信息发生改变,需要保存数据到sass和同步MCU
@@ -97,7 +97,7 @@ ApeConsts.CHANNEL_STATUS_OPENING = 1;///< 已经占用成功 @@ -97,7 +97,7 @@ ApeConsts.CHANNEL_STATUS_OPENING = 1;///< 已经占用成功
97 //媒体类型 97 //媒体类型
98 ApeConsts.MEDIA_TYPE_DEFAULT=0;//没有类型 98 ApeConsts.MEDIA_TYPE_DEFAULT=0;//没有类型
99 ApeConsts.MEDIA_TYPE_VIDEO=1;//视频流(包含音频) 99 ApeConsts.MEDIA_TYPE_VIDEO=1;//视频流(包含音频)
100 -ApeConsts.MEDIA_TYPE_VIDEO=2;//音频流 100 +ApeConsts.MEDIA_TYPE_AUDIO=2;//音频流
101 101
102 //FLASH中使用下面4个 102 //FLASH中使用下面4个
103 ApeConsts.CGS_RELEASED = 0;///< 无人占用状态 103 ApeConsts.CGS_RELEASED = 0;///< 无人占用状态
@@ -12,16 +12,9 @@ import Loger from 'Loger'; @@ -12,16 +12,9 @@ import Loger from 'Loger';
12 import GlobalConfig from 'GlobalConfig'; 12 import GlobalConfig from 'GlobalConfig';
13 import EngineUtils from 'EngineUtils'; 13 import EngineUtils from 'EngineUtils';
14 14
15 -  
16 let loger = Loger.getLoger('ConferApe'); 15 let loger = Loger.getLoger('ConferApe');
17 let itemIdx=0;//table插入新数据的计数id,目前用时间戳 16 let itemIdx=0;//table插入新数据的计数id,目前用时间戳
18 -let timerCounter;  
19 17
20 -//const ACTION_TYPE_0=0;  
21 -//const ACTION_TYPE_1=1;  
22 -//const ACTION_TYPE_2=2;  
23 -//const ACTION_TYPE_3=3;  
24 -//const ACTION_TYPE_4=4;  
25 class ConferApe extends Ape { 18 class ConferApe extends Ape {
26 constructor() { 19 constructor() {
27 super( 20 super(
@@ -460,9 +453,22 @@ class ConferApe extends Ape { @@ -460,9 +453,22 @@ class ConferApe extends Ape {
460 453
461 //视频模块发生更新,人员状态需要更新 454 //视频模块发生更新,人员状态需要更新
462 updaterRosterStatus(_param){ 455 updaterRosterStatus(_param){
463 - loger.log("视频模块发生更新,人员状态需要更新");  
464 - console.log(_param); 456 + if(_param){
  457 + loger.log("视频模块发生更新,人员状态需要更新,fromNodeId->",_param.fromNodeId);
  458 + loger.log(_param.status,_param.fromNodeId,this.rosters[_param.fromNodeId]);
  459 + //console.log(_param.fromNodeId);
465 //如果是自己。改变自己的状态同步到MCU 460 //如果是自己。改变自己的状态同步到MCU
  461 + //if(_param.fromNodeId==GlobalConfig.nodeId){
  462 + //
  463 + //}
  464 +
  465 +
  466 + //如果视频消息中channel的占用人 fromNodeId在人员列表中不存在,需要释放这channel,因为这个有可能是之前没释放成功的
  467 + if(_param.status==ApeConsts.CHANNEL_STATUS_OPENING&&this.rosters[_param.fromNodeId]==null){
  468 + loger.log("视频模块被占用,占有人已经不存在课堂中,释放Channel,_param->",_param);
  469 + this._emit(MessageTypes.CLASS_NONENTITY_ROSTER,_param.fromNodeId);
  470 + }
  471 + }
466 } 472 }
467 //删除用户 473 //删除用户
468 rosterDelHandler(nodeId) { 474 rosterDelHandler(nodeId) {
@@ -570,7 +576,6 @@ class ConferApe extends Ape { @@ -570,7 +576,6 @@ class ConferApe extends Ape {
570 return null; 576 return null;
571 } 577 }
572 578
573 -  
574 } 579 }
575 580
576 export default ConferApe; 581 export default ConferApe;
@@ -56,18 +56,21 @@ class VideoChat extends Ape { @@ -56,18 +56,21 @@ class VideoChat extends Ape {
56 } 56 }
57 57
58 let path = ""; 58 let path = "";
  59 + let port="";
59 if (_param.type == "m3u8") { 60 if (_param.type == "m3u8") {
60 - //M3U8 默认用80端口  
61 - //http://123.56.73.119/hls/h5dev_403074980_0_983042_1487641745/index.m3u8 61 + //M3U8
  62 + //http://123.56.73.119:6001/hls/h5dev_403074980_0_983041_1487663265/index.m3u8
  63 + port = (GlobalConfig.RSServerPort == "" || GlobalConfig.RSServerPort == null) ? "":":" + GlobalConfig.RSServerPort;
62 path = "http://" + GlobalConfig.RSServerIP 64 path = "http://" + GlobalConfig.RSServerIP
63 - +"/hls/" + _param.siteId 65 + + port + "/live/"
  66 + + _param.siteId
64 + "_" + _param.classId 67 + "_" + _param.classId
65 + "_" + _param.userId 68 + "_" + _param.userId
66 + "_" + _param.channelId 69 + "_" + _param.channelId
67 + "_" + _param.timestamp 70 + "_" + _param.timestamp
68 + "/index.m3u8"; 71 + "/index.m3u8";
69 } else { 72 } else {
70 - let port = (GlobalConfig.MSServerPort == "" || GlobalConfig.MSServerPort == null) ? "" : ":" + GlobalConfig.MSServerPort; 73 + port = (GlobalConfig.MSServerPort == "" || GlobalConfig.MSServerPort == null) ? "":":" + GlobalConfig.MSServerPort;
71 path = "rtmp://" + GlobalConfig.MSServerIP 74 path = "rtmp://" + GlobalConfig.MSServerIP
72 + port + "/live/" 75 + port + "/live/"
73 + _param.siteId 76 + _param.siteId
@@ -82,21 +85,40 @@ class VideoChat extends Ape { @@ -82,21 +85,40 @@ class VideoChat extends Ape {
82 //获取推流地址 85 //获取推流地址
83 getPublishVideoPath(_param) { 86 getPublishVideoPath(_param) {
84 loger.log('getPublishVideoPath'); 87 loger.log('getPublishVideoPath');
85 - //if(_param==null){  
86 - // loger.warn('getPublishVideoPath,参数错误',_param);  
87 - // this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG);  
88 - // return {"code":1,"data":"getPublishVideoPath,参数错误"};;  
89 - //} 88 +
90 //判断当前开启的视频数量是否已经是最大值,如果已经是最大值,不能再开启 89 //判断当前开启的视频数量是否已经是最大值,如果已经是最大值,不能再开启
91 let freeChannel = this.getFreeVideoChannel(); 90 let freeChannel = this.getFreeVideoChannel();
92 if (freeChannel == 0) { 91 if (freeChannel == 0) {
93 return {"code": 1, "data": "不能再打开更多的设备"}; 92 return {"code": 1, "data": "不能再打开更多的设备"};
94 } 93 }
95 94
96 - let port = (GlobalConfig.MSServerPort == "" || GlobalConfig.MSServerPort == null) ? "" : ":" + GlobalConfig.MSServerPort; 95 + //默认方式推流
  96 + let pubType="live";
  97 + //flash推流
  98 + if(_param&&_param.type=="flash"){
  99 + pubType ="flash";
  100 + }
  101 +
  102 + //端口,有端口就显示 ":xxx",没有端口就是""
  103 + let port = (GlobalConfig.MSServerPort == "" || GlobalConfig.MSServerPort == null) ? "":":" + GlobalConfig.MSServerPort;
  104 + //时间戳
97 let timestamp = EngineUtils.creatTimestamp(); 105 let timestamp = EngineUtils.creatTimestamp();
98 - let publishUrl = "rtmp://" + GlobalConfig.MSServerIP + port + "/flash/" +GlobalConfig.siteId+"_"+ GlobalConfig.classId + "_"+GlobalConfig.userId+"_" + freeChannel + "_" + timestamp;  
99 - return {"code": 0, "data": {"siteId":GlobalConfig.siteId,"classId":GlobalConfig.classId,"userId":GlobalConfig.userId,"channelId": freeChannel, "timestamp": timestamp, "publishUrl": publishUrl}}; 106 +
  107 + //生成推流地址和推流数据(同步数据的时候用)
  108 + let publishUrl = "rtmp://" + GlobalConfig.MSServerIP
  109 + + port + "/"+pubType+"/" +GlobalConfig.siteId+"_"
  110 + + GlobalConfig.classId + "_"+GlobalConfig.userId
  111 + +"_" + freeChannel + "_" + timestamp;
  112 + return {"code": 0,
  113 + "data":
  114 + { "siteId":GlobalConfig.siteId,
  115 + "classId":GlobalConfig.classId,
  116 + "userId":GlobalConfig.userId,
  117 + "channelId": freeChannel,
  118 + "timestamp": timestamp,
  119 + "publishUrl": publishUrl
  120 + }
  121 + };
100 } 122 }
101 123
102 //推流 124 //推流
@@ -148,7 +170,12 @@ class VideoChat extends Ape { @@ -148,7 +170,12 @@ class VideoChat extends Ape {
148 stopPublishVideo(_param) { 170 stopPublishVideo(_param) {
149 loger.log('stopPublishVideo -> maxVideoChannels', GlobalConfig.maxVideoChannels); 171 loger.log('stopPublishVideo -> maxVideoChannels', GlobalConfig.maxVideoChannels);
150 //_param如果为空,那么默认就是当前自己的nodeId,否则用_param 172 //_param如果为空,那么默认就是当前自己的nodeId,否则用_param
151 - let nodeId=_param||GlobalConfig.nodeId; 173 + let nodeId;
  174 + if(_param&&parseInt(_param.nodeId)>=0){
  175 + nodeId=parseInt(_param.nodeId);
  176 + }else {
  177 + nodeId=GlobalConfig.nodeId;
  178 + }
152 179
153 let openingChannel = this.getOpeningVideoChannel(nodeId); 180 let openingChannel = this.getOpeningVideoChannel(nodeId);
154 if (openingChannel == 0) { 181 if (openingChannel == 0) {
@@ -351,11 +378,12 @@ class VideoChat extends Ape { @@ -351,11 +378,12 @@ class VideoChat extends Ape {
351 packPduModel.channelId = _itemIdx; 378 packPduModel.channelId = _itemIdx;
352 packPduModel.siteId=_param.siteId||GlobalConfig.siteId;//GlobalConfig.siteId; 379 packPduModel.siteId=_param.siteId||GlobalConfig.siteId;//GlobalConfig.siteId;
353 packPduModel.classId =parseInt(_param.classId)||parseInt(GlobalConfig.classId); 380 packPduModel.classId =parseInt(_param.classId)||parseInt(GlobalConfig.classId);
  381 + packPduModel.userId =_param.userId||"0";
354 packPduModel.mediaType =_param.mediaType|| ApeConsts.MEDIA_TYPE_VIDEO; 382 packPduModel.mediaType =_param.mediaType|| ApeConsts.MEDIA_TYPE_VIDEO;
355 packPduModel.timestamp =_param.timestamp||EngineUtils.creatTimestamp(); 383 packPduModel.timestamp =_param.timestamp||EngineUtils.creatTimestamp();
356 packPduModel.fromNodeId = GlobalConfig.nodeId; 384 packPduModel.fromNodeId = GlobalConfig.nodeId;
357 packPduModel.toNodeId = 0; 385 packPduModel.toNodeId = 0;
358 - console.log(packPduModel); 386 + console.log("packPdu",packPduModel);
359 return packPduModel; 387 return packPduModel;
360 } 388 }
361 389
@@ -768,6 +768,8 @@ message RCVideoChannelInfoPdu { @@ -768,6 +768,8 @@ message RCVideoChannelInfoPdu {
768 optional uint32 to_node_id = 5;//接收者的id,(如果是0,所有人都接收) 768 optional uint32 to_node_id = 5;//接收者的id,(如果是0,所有人都接收)
769 optional uint32 media_type = 6;//媒体类型:视频(包含音频)或音频 769 optional uint32 media_type = 6;//媒体类型:视频(包含音频)或音频
770 optional uint32 class_id = 7;//课堂号 770 optional uint32 class_id = 7;//课堂号
  771 + optional string site_id = 8;//站点号
  772 + optional string user_id = 9;//用户的userId
771 } 773 }
772 774
773 message RCVideoChannelInfoRecordPdu { 775 message RCVideoChannelInfoRecordPdu {