李勇

修改录制的逻辑;录制的时间和课堂时间完全区分开;课堂的状态控制和录制也区分开;课堂内进入的第一个人有权限开启录制;录制的时间戳每4秒想SAAS保存一次;MCU10同步一次

1 -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.iphunter=t():e.iphunter=t()}(this,function(){return function(e){function t(i){if(n[i])return n[i].exports;var o=n[i]={exports:{},id:i,loaded:!1};return e[i].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){e.exports=n(1)},function(e,t){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:3e3;if(!(e&&e.length&&t))throw new Error("ips and callback are required.");new r(e,t,n)}Object.defineProperty(t,"__esModule",{value:!0});var o=function(){function e(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(t,n,i){return n&&e(t.prototype,n),i&&e(t,i),t}}();t.default=i;var r=function(){function e(t,i,o){n(this,e),this.version="v2.0.1.20170819",this.ip="",this.ipcallback=i,this.timeoutId=null,this.reqsCache=[];for(var r=0;r<t.length;r++)this.reqsCache.push(this.send(t[r],o-10));this.timeoutId=setTimeout(this.notify.bind(this),o)}return o(e,[{key:"clearAll",value:function(){this.reqsCache&&this.reqsCache.length&&this.reqsCache.forEach(function(e){e.abort()}),clearTimeout(this.timeoutId),this.ip="",this.ipcallback=null,this.timeoutId=null,this.reqsCache=[]}},{key:"clearReq",value:function(e){this.reqsCache.splice(this.reqsCache.indexOf(e),1)}},{key:"notify",value:function(){this.ipcallback&&this.ipcallback(this.ip),this.clearAll()}},{key:"send",value:function(e,t){var n=this,i=new XMLHttpRequest;return i.open("HEAD","//"+e+"/?_="+Date.now()),i.timeout=t,i.onload=function(){n.ip=e,n.clearReq(i),i.onload=null,n.notify()},i.ontimeout=function(){n.clearReq(i),i.ontimeout=null},i.onerror=function(){n.clearReq(i),i.onerror=null},i.onabort=function(){n.clearReq(i),i.onabort=null},i.send(),i}}]),e}();(function(){"undefined"!=typeof __REACT_HOT_LOADER__&&(__REACT_HOT_LOADER__.register(r,"IpHunter","D:/work/McuClient/node_modules/iphunter/src/main.js"),__REACT_HOT_LOADER__.register(i,"check","D:/work/McuClient/node_modules/iphunter/src/main.js"))})()}])});  
  1 +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.iphunter=t():e.iphunter=t()}(this,function(){return function(e){function t(i){if(n[i])return n[i].exports;var o=n[i]={exports:{},id:i,loaded:!1};return e[i].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){e.exports=n(1)},function(e,t){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:3e3;if(!(e&&e.length&&t))throw new Error("ips and callback are required.");new r(e,t,n)}Object.defineProperty(t,"__esModule",{value:!0});var o=function(){function e(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(t,n,i){return n&&e(t.prototype,n),i&&e(t,i),t}}();t.default=i;var r=function(){function e(t,i,o){n(this,e),this.version="v2.0.1.20170819",this.ip="",this.ipcallback=i,this.timeoutId=null,this.reqsCache=[];for(var r=0;r<t.length;r++)this.reqsCache.push(this.send(t[r],o));this.timeoutId=setTimeout(this.notify.bind(this),o)}return o(e,[{key:"clearAll",value:function(){this.reqsCache&&this.reqsCache.length&&this.reqsCache.forEach(function(e){e.abort()}),clearTimeout(this.timeoutId),this.ip="",this.ipcallback=null,this.timeoutId=null,this.reqsCache=[]}},{key:"clearReq",value:function(e){this.reqsCache.splice(this.reqsCache.indexOf(e),1)}},{key:"notify",value:function(){this.ipcallback&&this.ipcallback(this.ip),this.clearAll()}},{key:"send",value:function(e,t){var n=this,i=new XMLHttpRequest;return i.open("HEAD","//"+e+"/?_="+Date.now()),i.timeout=t,i.onload=function(){n.ip=e,n.clearReq(i),i.onload=null,n.notify()},i.ontimeout=function(){n.clearReq(i),i.ontimeout=null},i.onerror=function(){n.clearReq(i),i.onerror=null},i.onabort=function(){n.clearReq(i),i.onabort=null},i.send(),i}}]),e}();(function(){"undefined"!=typeof __REACT_HOT_LOADER__&&(__REACT_HOT_LOADER__.register(r,"IpHunter","D:/work/McuClient/node_modules/iphunter/src/main.js"),__REACT_HOT_LOADER__.register(i,"check","D:/work/McuClient/node_modules/iphunter/src/main.js"))})()}])});
@@ -7,7 +7,8 @@ class IpHunter { @@ -7,7 +7,8 @@ class IpHunter {
7 this.reqsCache = []; 7 this.reqsCache = [];
8 8
9 for (let i = 0; i < ips.length; i++) { 9 for (let i = 0; i < ips.length; i++) {
10 - this.reqsCache.push(this.send(ips[i], timeout - 10)); 10 + //this.reqsCache.push(this.send(ips[i], timeout - 10));
  11 + this.reqsCache.push(this.send(ips[i], timeout));
11 } 12 }
12 this.timeoutId = setTimeout(this.notify.bind(this), timeout); 13 this.timeoutId = setTimeout(this.notify.bind(this), timeout);
13 } 14 }
@@ -58,7 +58,7 @@ export default class MessageEntrance extends Emiter { @@ -58,7 +58,7 @@ export default class MessageEntrance extends Emiter {
58 constructor() { 58 constructor() {
59 super(); 59 super();
60 //sdk 信息 60 //sdk 信息
61 - GlobalConfig.sdkVersion = "v1.81.19.20170828"; 61 + GlobalConfig.sdkVersion = "v1.82.11.20170829";
62 loger.warn("sdkVersion:" + GlobalConfig.sdkVersion); 62 loger.warn("sdkVersion:" + GlobalConfig.sdkVersion);
63 63
64 //设置 64 //设置
@@ -87,7 +87,7 @@ export default class MessageEntrance extends Emiter { @@ -87,7 +87,7 @@ export default class MessageEntrance extends Emiter {
87 this.isGetFastestRtmpPullCallback = false; //是否RTMP拉流地址测试结束 87 this.isGetFastestRtmpPullCallback = false; //是否RTMP拉流地址测试结束
88 this.isGetFastestHlsPullCallback = false; //是否HLS拉流地址测试结束 88 this.isGetFastestHlsPullCallback = false; //是否HLS拉流地址测试结束
89 this.isGetFastestRsCallback = false; //是否录制回放HLS拉流地址测试结束 89 this.isGetFastestRsCallback = false; //是否录制回放HLS拉流地址测试结束
90 - 90 + this.saveClassStatusTimer=0;//保存课堂数据的计时器间隔,防止同一瞬间多次提交
91 //全局的Error处理 91 //全局的Error处理
92 this.on(MessageTypes.MCU_ERROR, this._mcuErrorHandler.bind(this)); 92 this.on(MessageTypes.MCU_ERROR, this._mcuErrorHandler.bind(this));
93 93
@@ -420,21 +420,19 @@ export default class MessageEntrance extends Emiter { @@ -420,21 +420,19 @@ export default class MessageEntrance extends Emiter {
420 //开启录制成功 420 //开启录制成功
421 _onClassRecordSuccess(_param) { 421 _onClassRecordSuccess(_param) {
422 clearTimeout(this.classRecordStatusUpdateTimer); 422 clearTimeout(this.classRecordStatusUpdateTimer);
423 - let _this = this;  
424 - this.classRecordStatusUpdateTimer = setTimeout(function () { 423 + this.classRecordStatusUpdateTimer = setTimeout(()=> {
425 clearTimeout(this.classRecordStatusUpdateTimer); 424 clearTimeout(this.classRecordStatusUpdateTimer);
426 - _this.updaterRecordAllApeStatus(_param); 425 + this.updaterRecordAllApeStatus(_param);
427 }, 1600); 426 }, 1600);
428 -  
429 } 427 }
430 428
431 //录制状态发送改变,更新所有模块的当前数据发送到MCU 429 //录制状态发送改变,更新所有模块的当前数据发送到MCU
432 updaterRecordAllApeStatus(_param) { 430 updaterRecordAllApeStatus(_param) {
433 - if(GlobalConfig.isRecordPlayBack){ 431 + if(GlobalConfig.isRecordPlayBack||!_confer_ape){
434 return; 432 return;
435 } 433 }
436 //老师身份和非录制回放的时候执行,录制状态发送改变,需要更新当前的数据,否则已有的消息会录制不上 434 //老师身份和非录制回放的时候执行,录制状态发送改变,需要更新当前的数据,否则已有的消息会录制不上
437 - if (GlobalConfig.isHost||GlobalConfig.rosterNumber<=1) { 435 + if (_confer_ape.checkHasRecordControl()) {
438 loger.warn('录制状态发送改变->更新所有模块的当前数据发送到MCU'); 436 loger.warn('录制状态发送改变->更新所有模块的当前数据发送到MCU');
439 //目前录制的模块[文档模块、白板模块、视频模块(包含屏幕共享)、音频模块、媒体共享,聊天模块] 437 //目前录制的模块[文档模块、白板模块、视频模块(包含屏幕共享)、音频模块、媒体共享,聊天模块]
440 if (_doc_ape) { 438 if (_doc_ape) {
@@ -452,6 +450,9 @@ export default class MessageEntrance extends Emiter { @@ -452,6 +450,9 @@ export default class MessageEntrance extends Emiter {
452 if (_mediaShareApe) { 450 if (_mediaShareApe) {
453 _mediaShareApe.updaterRecordApeStatus(); 451 _mediaShareApe.updaterRecordApeStatus();
454 } 452 }
  453 + if (_musicShareApe) {
  454 + _musicShareApe.updaterRecordApeStatus();
  455 + }
455 //聊天模块不需要更新 456 //聊天模块不需要更新
456 } 457 }
457 } 458 }
@@ -825,11 +826,11 @@ export default class MessageEntrance extends Emiter { @@ -825,11 +826,11 @@ export default class MessageEntrance extends Emiter {
825 loger.warn("课堂最终使用的服务列表->来自本地Server.json"); 826 loger.warn("课堂最终使用的服务列表->来自本地Server.json");
826 } 827 }
827 828
828 - loger.warn("mcuListFinal", GlobalConfig.mcuListFinal);  
829 - loger.warn("msListFinal", GlobalConfig.msListFinal);  
830 - loger.warn("rtmpPullListFinal", GlobalConfig.rtmpPullListFinal);  
831 - loger.warn("hlsListFinal", GlobalConfig.hlsPullListFinal);  
832 - loger.warn("rsListFinal", GlobalConfig.rsPullListFinal); 829 + loger.warn(" MCU-List", GlobalConfig.mcuListFinal);
  830 + loger.warn(" MS-List", GlobalConfig.msListFinal);
  831 + loger.warn(" RTMP-List", GlobalConfig.rtmpPullListFinal);
  832 + loger.warn(" HLS-List", GlobalConfig.hlsPullListFinal);
  833 + loger.warn(" RS-List", GlobalConfig.rsPullListFinal);
833 } 834 }
834 835
835 //从Sass中选择的mcu、ms列表 836 //从Sass中选择的mcu、ms列表
@@ -876,7 +877,6 @@ export default class MessageEntrance extends Emiter { @@ -876,7 +877,6 @@ export default class MessageEntrance extends Emiter {
876 GlobalConfig.isp, 877 GlobalConfig.isp,
877 ServerConfig.serverList); 878 ServerConfig.serverList);
878 } 879 }
879 - loger.warn("Sass中获取的服务器信息;");  
880 880
881 //拉流地址列表的特殊处理, 881 //拉流地址列表的特殊处理,
882 // 1.如果RTMP拉流地址没有配置,就默认使用MS推流地址列表 882 // 1.如果RTMP拉流地址没有配置,就默认使用MS推流地址列表
@@ -889,11 +889,11 @@ export default class MessageEntrance extends Emiter { @@ -889,11 +889,11 @@ export default class MessageEntrance extends Emiter {
889 } 889 }
890 890
891 loger.warn("课堂最终使用的服务列表->来自Sass"); 891 loger.warn("课堂最终使用的服务列表->来自Sass");
892 - loger.warn(" GlobalConfig.mcuListFinal", GlobalConfig.mcuListFinal);  
893 - loger.warn(" GlobalConfig.msListFinal", GlobalConfig.msListFinal);  
894 - loger.warn(" GlobalConfig.rtmpPullListFinal", GlobalConfig.rtmpPullListFinal);  
895 - loger.warn(" GlobalConfig.hlsListFinal", GlobalConfig.hlsPullListFinal);  
896 - loger.warn(" GlobalConfig.rsListFinal", GlobalConfig.rsPullListFinal); 892 + loger.warn(" MCU-List", GlobalConfig.mcuListFinal);
  893 + loger.warn(" MS-List", GlobalConfig.msListFinal);
  894 + loger.warn(" RTMP-List", GlobalConfig.rtmpPullListFinal);
  895 + loger.warn(" HLS-List", GlobalConfig.hlsPullListFinal);
  896 + loger.warn(" RS-List", GlobalConfig.rsPullListFinal);
897 897
898 } 898 }
899 899
@@ -955,54 +955,37 @@ export default class MessageEntrance extends Emiter { @@ -955,54 +955,37 @@ export default class MessageEntrance extends Emiter {
955 955
956 //保存课堂状态信息 956 //保存课堂状态信息
957 _sassSaveClassStatusInfo(_param) { 957 _sassSaveClassStatusInfo(_param) {
  958 + if (!_mcu||!_mcu.connected) {
  959 + loger.warn("不能保存课堂数据->MCU已经断开");
  960 + return ;
  961 + }
  962 + if(!_confer_ape){
  963 + return;
  964 + }
958 //{isForce:true} isForce->是否强制提交(true为是) 965 //{isForce:true} isForce->是否强制提交(true为是)
959 //这个是特殊权限 966 //这个是特殊权限
960 let isForce = false; 967 let isForce = false;
961 if (_param && _param.isForce == true) { 968 if (_param && _param.isForce == true) {
962 isForce = true; 969 isForce = true;
963 } 970 }
964 -  
965 - /* if (GlobalConfig.isHost || isForce) {  
966 - //只有加入课堂之后才能保存数据  
967 - if (GlobalConfig.getCurrentStatus().code == GlobalConfig.statusCode_2.code) {  
968 - //POST 保存数据  
969 - _sass.saveClassStatusInfo({"classStatusInfo": GlobalConfig.classStatusInfo}); //保存课堂状态信息  
970 - } else {  
971 - loger.error("不能保存课堂数据", GlobalConfig.getCurrentStatus());  
972 - }  
973 - } else {  
974 - loger.log("没有保存课堂状态信息的权限->身份", GlobalConfig.userRole);  
975 - }*/  
976 - if (GlobalConfig.isHost || isForce||GlobalConfig.rosterNumber<=1) {  
977 - //只有加入课堂之后才能保存数据  
978 - /*if (GlobalConfig.getCurrentStatus().code == GlobalConfig.statusCode_2.code) { 971 + if (_confer_ape.checkHasRecordControl()||isForce) {
979 //POST 保存数据 972 //POST 保存数据
  973 + clearTimeout(this.saveClassStatusTimer);
  974 + this.saveClassStatusTimer=setTimeout(()=>{
980 _sass.saveClassStatusInfo({"classStatusInfo": GlobalConfig.classStatusInfo}); //保存课堂状态信息 975 _sass.saveClassStatusInfo({"classStatusInfo": GlobalConfig.classStatusInfo}); //保存课堂状态信息
  976 + },600);
981 } else { 977 } else {
982 - loger.error("不能保存课堂数据", GlobalConfig.getCurrentStatus());  
983 - }*/  
984 - if (_mcu&&_mcu.connected) {  
985 - //POST 保存数据  
986 - _sass.saveClassStatusInfo({"classStatusInfo": GlobalConfig.classStatusInfo}); //保存课堂状态信息  
987 - } else {  
988 - loger.error("不能保存课堂数据", GlobalConfig.getCurrentStatus());  
989 - }  
990 -  
991 - } else {  
992 - loger.log("没有保存课堂状态信息的权限->身份", GlobalConfig.userRole); 978 + loger.log("没有保存课堂状态信息的权限->当前身份->"+GlobalConfig.userRole);
993 } 979 }
994 -  
995 } 980 }
996 981
997 //保存会态信息成功 982 //保存会态信息成功
998 _sassSaveClassStatusInfoSuccessHandler(_data) { 983 _sassSaveClassStatusInfoSuccessHandler(_data) {
999 - loger.log('保存课堂状态信息成功.');  
1000 - loger.log(_data); 984 + //loger.log('Saas保存课堂状态信息成功');
1001 } 985 }
1002 986
1003 _sassSaveClassRecordInfoSuccessHandler(_data) { 987 _sassSaveClassRecordInfoSuccessHandler(_data) {
1004 - loger.log('保存课堂录制信息成功.');  
1005 - loger.log(_data); 988 + //loger.log('Saas保存课堂录制信息成功',_data);
1006 } 989 }
1007 990
1008 //Sass校验流程结束之后,开始加入MCU 991 //Sass校验流程结束之后,开始加入MCU
@@ -1208,11 +1191,22 @@ export default class MessageEntrance extends Emiter { @@ -1208,11 +1191,22 @@ export default class MessageEntrance extends Emiter {
1208 GlobalConfig.MS_PUBLISH_IP = _param.ip || ""; 1191 GlobalConfig.MS_PUBLISH_IP = _param.ip || "";
1209 GlobalConfig.MS_PUBLISH_PORT = _param.port || ""; 1192 GlobalConfig.MS_PUBLISH_PORT = _param.port || "";
1210 } 1193 }
  1194 + GlobalConfig.MS_PLAY_RTMP_IP = GlobalConfig.MS_PUBLISH_IP;
  1195 + GlobalConfig.MS_PLAY_RTMP_PORT =GlobalConfig.MS_PUBLISH_PORT;
1211 loger.warn('手动切换MS->', GlobalConfig.MS_PUBLISH_IP + ":" + GlobalConfig.MS_PUBLISH_PORT); 1196 loger.warn('手动切换MS->', GlobalConfig.MS_PUBLISH_IP + ":" + GlobalConfig.MS_PUBLISH_PORT);
  1197 + loger.warn('手动切换RTMP->', GlobalConfig.MS_PLAY_RTMP_IP + ":" + GlobalConfig.MS_PLAY_RTMP_PORT);
1212 //更换完用户当前的MS地址,需要更新用户数据 1198 //更换完用户当前的MS地址,需要更新用户数据
1213 if (_confer_ape) { 1199 if (_confer_ape) {
1214 _confer_ape.updateUserInfo(); 1200 _confer_ape.updateUserInfo();
1215 } 1201 }
  1202 +
  1203 + //音视频模块对当前正在播放的流进行更换MS
  1204 + if(_video_ape){
  1205 + _video_ape.changeMediaMs();
  1206 + }
  1207 + if(_audio_ape){
  1208 + _audio_ape.changeMediaMs();
  1209 + }
1216 } 1210 }
1217 1211
1218 //切换MS ->_param->{reConnect:false} //reConnect(是否立即替换当前的ip并且重新连接) 1212 //切换MS ->_param->{reConnect:false} //reConnect(是否立即替换当前的ip并且重新连接)
@@ -1381,13 +1375,10 @@ export default class MessageEntrance extends Emiter { @@ -1381,13 +1375,10 @@ export default class MessageEntrance extends Emiter {
1381 return; 1375 return;
1382 } 1376 }
1383 if (_confer_ape) { 1377 if (_confer_ape) {
1384 - //开始录制  
1385 - setTimeout(()=> {  
1386 - _confer_ape.startRecord();  
1387 - },2000);  
1388 -  
1389 //开始上课 1378 //开始上课
1390 _confer_ape.startClass(_param); 1379 _confer_ape.startClass(_param);
  1380 + ////开始录制
  1381 + //_confer_ape.startRecord();
1391 } 1382 }
1392 } 1383 }
1393 1384
@@ -2082,7 +2073,7 @@ export default class MessageEntrance extends Emiter { @@ -2082,7 +2073,7 @@ export default class MessageEntrance extends Emiter {
2082 2073
2083 //文档加入频道成功,同步到MCU服务器上的数据 2074 //文档加入频道成功,同步到MCU服务器上的数据
2084 docJoinChannelSuccess() { 2075 docJoinChannelSuccess() {
2085 - loger.log("docJoinChannelSuccess->isHost=", GlobalConfig.isHost, "当前总人数:", GlobalConfig.rosterNumber, "sassDoclength=", GlobalConfig.docListPrepare.length); 2076 + loger.log("文档加入频道成功->isHost=", GlobalConfig.isHost, "当前总人数:", GlobalConfig.rosterNumber, "sassDoclength=", GlobalConfig.docListPrepare.length);
2086 //loger.log("docJoinChannelSuccess docListPrepare="); 2077 //loger.log("docJoinChannelSuccess docListPrepare=");
2087 //如果是主持人,那么需要判断一下文档模块同步的数据和从sass获取的文档数据是否相同,如果mcu服务器不存在的,需要上传 2078 //如果是主持人,那么需要判断一下文档模块同步的数据和从sass获取的文档数据是否相同,如果mcu服务器不存在的,需要上传
2088 if (GlobalConfig.docListPrepare && GlobalConfig.docListPrepare.length > 0) { 2079 if (GlobalConfig.docListPrepare && GlobalConfig.docListPrepare.length > 0) {
@@ -100,9 +100,9 @@ class GlobalConfig { @@ -100,9 +100,9 @@ class GlobalConfig {
100 } 100 }
101 //设置当前的课堂状态的信息 101 //设置当前的课堂状态的信息
102 static setClassStatusInfo(_data) { 102 static setClassStatusInfo(_data) {
103 - loger.log("setClassStatusInfo"); 103 + //loger.log("setClassStatusInfo");
104 if (_data == null) { 104 if (_data == null) {
105 - loger.warn("classStatusInfo error,_data:", _data); 105 + loger.warn("设置当前的课堂状态的信失败:", _data);
106 return; 106 return;
107 } 107 }
108 let data = _data; 108 let data = _data;
@@ -137,7 +137,7 @@ class GlobalConfig { @@ -137,7 +137,7 @@ class GlobalConfig {
137 137
138 //this.recordStatus = data.recordStatus || this.recordStatus; //当前录制状态 138 //this.recordStatus = data.recordStatus || this.recordStatus; //当前录制状态
139 this.recordStatus = data.recordStatus ||false; //当前录制状态 139 this.recordStatus = data.recordStatus ||false; //当前录制状态
140 - this.recordTimestamp = data.recordTimestamp || this.recordTimestamp; //相对于首次开始录制的时间戳 140 + this.recordTimestamp =Math.max(parseInt(data.recordTimestamp), this.recordTimestamp); //录制时间取最大值
141 this.recordFileName = data.recordFileName || this.recordFileName; //录制的文件名 141 this.recordFileName = data.recordFileName || this.recordFileName; //录制的文件名
142 this.recordDownloadUrl = data.recordDownloadUrl || this.recordDownloadUrl; //下载地址 142 this.recordDownloadUrl = data.recordDownloadUrl || this.recordDownloadUrl; //下载地址
143 this.currentSceneTableId = data.currentSceneTableId || 0; //文档区域的模块显示 143 this.currentSceneTableId = data.currentSceneTableId || 0; //文档区域的模块显示
@@ -523,7 +523,8 @@ GlobalConfig.recordReplaytickValues = {}; // 滚动条关键点,用于快进 @@ -523,7 +523,8 @@ GlobalConfig.recordReplaytickValues = {}; // 滚动条关键点,用于快进
523 523
524 GlobalConfig.isAutoStartClass = 0; //是否自动开始上课 0-否 ;1 是 524 GlobalConfig.isAutoStartClass = 0; //是否自动开始上课 0-否 ;1 是
525 525
526 -GlobalConfig.updateClassInfoDelay = 20; //(秒),每隔30秒同步一次课堂状态的并保存到Sass 526 +GlobalConfig.updateRecordTimeDelay = 4; //(秒),同步一次课堂录制状态的并保存到Sass
  527 +GlobalConfig.updateClassInfoDelay = 10; //(秒),同步一次课堂状态的并保存到Sass
527 GlobalConfig.msDynamicChooseIpDelay = 60 * 3; //(秒)MS动态选点的间隔 528 GlobalConfig.msDynamicChooseIpDelay = 60 * 3; //(秒)MS动态选点的间隔
528 //GlobalConfig.serverTimestamp=0;//当前的系统时间戳 用get set 获取 529 //GlobalConfig.serverTimestamp=0;//当前的系统时间戳 用get set 获取
529 530
@@ -404,7 +404,7 @@ class IpManager extends Emiter { @@ -404,7 +404,7 @@ class IpManager extends Emiter {
404 } 404 }
405 405
406 //isp province都没有,使用default 406 //isp province都没有,使用default
407 - let defaultData = countryData.default 407 + let defaultData = countryData.default;
408 if (defaultData) { 408 if (defaultData) {
409 // loger.log("_returnServerMS->defaultData",defaultData); 409 // loger.log("_returnServerMS->defaultData",defaultData);
410 return defaultData; 410 return defaultData;
@@ -148,7 +148,7 @@ class LogManager { @@ -148,7 +148,7 @@ class LogManager {
148 }) 148 })
149 .then(ret => { 149 .then(ret => {
150 if (ret == 0) { 150 if (ret == 0) {
151 - console.log('保存日志信息 完成'); 151 + //console.log('保存日志信息 完成');
152 tempArr=[]; 152 tempArr=[];
153 } else { 153 } else {
154 console.warn('保存日志信息 失败.', ret); 154 console.warn('保存日志信息 失败.', ret);
@@ -440,7 +440,7 @@ class Sass extends Emiter { @@ -440,7 +440,7 @@ class Sass extends Emiter {
440 //let url = `http://${GlobalConfig.portal}/3m/api/meeting/saveInfo.do`; 440 //let url = `http://${GlobalConfig.portal}/3m/api/meeting/saveInfo.do`;
441 let url = `${GlobalConfig.locationProtocol+GlobalConfig.portal}/3m/api/meeting/saveInfo.do`; 441 let url = `${GlobalConfig.locationProtocol+GlobalConfig.portal}/3m/api/meeting/saveInfo.do`;
442 442
443 - loger.log('saveClassStatusInfo', url); 443 + //loger.log('saveClassStatusInfo', url);
444 fetch(url, { 444 fetch(url, {
445 method: 'POST', 445 method: 'POST',
446 headers: { 446 headers: {
@@ -460,7 +460,7 @@ class Sass extends Emiter { @@ -460,7 +460,7 @@ class Sass extends Emiter {
460 }) 460 })
461 .then(ret => { 461 .then(ret => {
462 if (ret.code === 0) { 462 if (ret.code === 0) {
463 - loger.log('saveClassStatusInfo 完成'); 463 + //loger.log('saveClassStatusInfo 完成');
464 this._emit(Sass.CLASS_SAVE_STATUS_INFO_SUCCESS, _param); 464 this._emit(Sass.CLASS_SAVE_STATUS_INFO_SUCCESS, _param);
465 } else if (ret.code === 1) { 465 } else if (ret.code === 1) {
466 loger.log('saveClassStatusInfo 失败 课堂号为空'); 466 loger.log('saveClassStatusInfo 失败 课堂号为空');
@@ -485,7 +485,7 @@ class Sass extends Emiter { @@ -485,7 +485,7 @@ class Sass extends Emiter {
485 loger.log('录制回放中,不需要保存'); 485 loger.log('录制回放中,不需要保存');
486 return; 486 return;
487 } 487 }
488 - loger.log('保存开始录制信息'); 488 + // loger.log('保存开始录制信息');
489 let key = "3mang123A"; 489 let key = "3mang123A";
490 let siteID = GlobalConfig.siteId; 490 let siteID = GlobalConfig.siteId;
491 let meetingID = GlobalConfig.classId; 491 let meetingID = GlobalConfig.classId;
@@ -499,14 +499,14 @@ class Sass extends Emiter { @@ -499,14 +499,14 @@ class Sass extends Emiter {
499 let confRecordFileName = GlobalConfig.recordFileName; 499 let confRecordFileName = GlobalConfig.recordFileName;
500 let downloadUrl = ""; 500 let downloadUrl = "";
501 let recordStatus = GlobalConfig.classStatus; 501 let recordStatus = GlobalConfig.classStatus;
502 - let recordTimestamp = GlobalConfig.classTimestamp; 502 + let recordTimestamp = GlobalConfig.recordTimestamp;//GlobalConfig.classTimestamp;//使用录制时间,不再使用课堂的进行时间
503 503
504 let timestamp = new Date().getTime(); 504 let timestamp = new Date().getTime();
505 let authId = MD5(key + siteID + meetingID + timestamp); 505 let authId = MD5(key + siteID + meetingID + timestamp);
506 //let url = `http://${GlobalConfig.portal}/3m/recordingMeeting/insertRecordingMeeting.do`; 506 //let url = `http://${GlobalConfig.portal}/3m/recordingMeeting/insertRecordingMeeting.do`;
507 let url = `${GlobalConfig.locationProtocol+GlobalConfig.portal}/3m/recordingMeeting/insertRecordingMeeting.do`; 507 let url = `${GlobalConfig.locationProtocol+GlobalConfig.portal}/3m/recordingMeeting/insertRecordingMeeting.do`;
508 508
509 - loger.log('saveClassRecordContrlInfo', url); 509 + loger.log('保存开始录制信息:', url);
510 510
511 fetch(encodeURI(url), { 511 fetch(encodeURI(url), {
512 method: 'POST', 512 method: 'POST',
@@ -25,6 +25,8 @@ ApeConsts.CLASS_ACTION_CLOSE_ALL = 1; //所有人关闭课堂 @@ -25,6 +25,8 @@ ApeConsts.CLASS_ACTION_CLOSE_ALL = 1; //所有人关闭课堂
25 ApeConsts.CLASS_ACTION_HANDUP_STATUS_CHANGE = 2; //更改用户的举手状态 25 ApeConsts.CLASS_ACTION_HANDUP_STATUS_CHANGE = 2; //更改用户的举手状态
26 ApeConsts.USER_ACTION_SILENCE_STATUS_CHANGE = 3; //更改用户的禁言状态 26 ApeConsts.USER_ACTION_SILENCE_STATUS_CHANGE = 3; //更改用户的禁言状态
27 ApeConsts.CLASS_ACTION_KICK_OUT_ROSTER=4; //指定的人踢出课堂 27 ApeConsts.CLASS_ACTION_KICK_OUT_ROSTER=4; //指定的人踢出课堂
  28 +ApeConsts.STOP_ALL_PUBLISH=5; //所有人停止推流
  29 +
28 30
29 //课堂类型 1:1v1(2路流) 2:直播(1路流) 3:小班课(可以多路流) 31 //课堂类型 1:1v1(2路流) 2:直播(1路流) 3:小班课(可以多路流)
30 ApeConsts.CLASS_TYPE_1 = 1; // 互动课堂,通过MS转发音视频,不能进行H5观看 1v1(2路流) 32 ApeConsts.CLASS_TYPE_1 = 1; // 互动课堂,通过MS转发音视频,不能进行H5观看 1v1(2路流)
@@ -384,7 +384,10 @@ class AudioApe extends Ape { @@ -384,7 +384,10 @@ class AudioApe extends Ape {
384 this._emit(MessageTypes.AUDIO_BROADCAST, audioReceivePdu); 384 this._emit(MessageTypes.AUDIO_BROADCAST, audioReceivePdu);
385 } 385 }
386 } 386 }
  387 + //切换了MS,重新更新一下当前正在播放的流地址
  388 + changeMediaMs(){
387 389
  390 + }
388 tableUpdateHandler(owner, itemIdx, itemData, seek) { 391 tableUpdateHandler(owner, itemIdx, itemData, seek) {
389 let unpackChannelInfo = this.unPackPdu(owner, itemIdx, itemData); 392 let unpackChannelInfo = this.unPackPdu(owner, itemIdx, itemData);
390 loger.log("tableUpdateHandler->channel", itemIdx, 'status->', unpackChannelInfo.status, "seek->", seek); 393 loger.log("tableUpdateHandler->channel", itemIdx, 'status->', unpackChannelInfo.status, "seek->", seek);
@@ -479,6 +482,10 @@ class AudioApe extends Ape { @@ -479,6 +482,10 @@ class AudioApe extends Ape {
479 } else { 482 } else {
480 channelInfo.owner = channelInfo.fromNodeId; 483 channelInfo.owner = channelInfo.fromNodeId;
481 } 484 }
  485 + //owner为0就是没有使用
  486 + if(channelInfo.owner==0){
  487 + channelInfo.status = ApeConsts.CHANNEL_STATUS_RELEASED
  488 + }
482 this.sendTableUpdateHandler(channelInfo); 489 this.sendTableUpdateHandler(channelInfo);
483 } 490 }
484 } 491 }
@@ -27,7 +27,7 @@ class ConferApe extends Ape { @@ -27,7 +27,7 @@ class ConferApe extends Ape {
27 this.rosters = {}; //用户列表 27 this.rosters = {}; //用户列表
28 this.rosterLen = 0;//当前课堂人数 28 this.rosterLen = 0;//当前课堂人数
29 this.timerCounter = new TimerCounter(); //计时器 29 this.timerCounter = new TimerCounter(); //计时器
30 - this.startClassTimer;//开始课堂和开始录制的计时器 30 + this.startRecordTimer;//开始录制的计时器
31 31
32 //第三方消息控制 parent和Iframe直接的通讯 32 //第三方消息控制 parent和Iframe直接的通讯
33 this.thirdMessage = new ThirdMessage(); 33 this.thirdMessage = new ThirdMessage();
@@ -271,19 +271,19 @@ class ConferApe extends Ape { @@ -271,19 +271,19 @@ class ConferApe extends Ape {
271 loger.warn('不能再录制,录制时间已经达到最大限制', GlobalConfig.recordTimestamp); 271 loger.warn('不能再录制,录制时间已经达到最大限制', GlobalConfig.recordTimestamp);
272 return; 272 return;
273 } 273 }
274 - loger.warn('检测是否需要开启录制', "isHost", GlobalConfig.isHost, "recordStatus", GlobalConfig.recordStatus,"当前人数:"+this.rosterLen); 274 + //如果已经开始录制就不再开启
  275 + if(GlobalConfig.recordStatus&&this.rosterLen>1){
  276 + loger.warn('目前已经是录制状态->当前课堂人数:'+this.rosterLen);
  277 + return false;
  278 + }
275 //如果是host或者当前课堂只有1个人 279 //如果是host或者当前课堂只有1个人
276 - if (GlobalConfig.isHost||this.rosterLen<=1) {  
277 - /* if(GlobalConfig.recordStatus){  
278 - loger.warn("课堂已经是录制状态不->不需要再开启,isHost", GlobalConfig.isHost, "recordStatus", GlobalConfig.recordStatus,"当前人数:"+this.rosterLen);  
279 - }else{  
280 - loger.warn('开启录制', "isHost", GlobalConfig.isHost, "recordStatus", GlobalConfig.recordStatus,"当前人数:"+this.rosterLen);  
281 - GlobalConfig.classStopTime = EngineUtils.creatTimestampStr();  
282 - this.sendConferRecordMsg({"recordStatus": true});  
283 - this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE);  
284 - this._emit(MessageTypes.CLASS_RECORD_START); //课堂开始录制  
285 - }*/ 280 + if (this.checkHasRecordControl()) {
286 loger.warn('开启录制', "isHost", GlobalConfig.isHost, "recordStatus", GlobalConfig.recordStatus,"当前人数:"+this.rosterLen); 281 loger.warn('开启录制', "isHost", GlobalConfig.isHost, "recordStatus", GlobalConfig.recordStatus,"当前人数:"+this.rosterLen);
  282 + //如果录制的文件名不存在,需要创建一个名字
  283 + let timestampYMD = EngineUtils.creatTimestampYMD();
  284 + if(!GlobalConfig.recordFileName){
  285 + GlobalConfig.recordFileName=GlobalConfig.siteId + "/" + timestampYMD + "/" + GlobalConfig.classId + "_" + timestampYMD + ".rec"; //4、文件名称 $RECORD_HOME/`site id`/`日期`/`filename` 例:/data/record/su/20161216/`filename`
  286 + }
287 GlobalConfig.classStopTime = EngineUtils.creatTimestampStr(); 287 GlobalConfig.classStopTime = EngineUtils.creatTimestampStr();
288 this.sendConferRecordMsg({"recordStatus": true}); 288 this.sendConferRecordMsg({"recordStatus": true});
289 this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE); 289 this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE);
@@ -291,30 +291,44 @@ class ConferApe extends Ape { @@ -291,30 +291,44 @@ class ConferApe extends Ape {
291 } 291 }
292 } 292 }
293 293
  294 + //检测是否有控制录制操作的权限
  295 + checkHasRecordControl(){
  296 + //loger.warn('检测是否有控制录制操作的权限', "isHost", GlobalConfig.isHost, "recordStatus", GlobalConfig.recordStatus,"当前人数:"+this.rosterLen);
  297 + //1.如果自己是老师或者当前课堂只有一个人
  298 + if(GlobalConfig.isHost||this.rosterLen<=1){
  299 + return true;
  300 + }
  301 + //2.如果自己不是老师,需要判断当前课堂内是否有老师,如果有老师就不做操作
  302 + for(let i in this.rosters){
  303 + //如果就老师就停止
  304 + let rosterItem=this.rosters[i];
  305 + if(rosterItem&&rosterItem.userRole==ApeConsts.host){
  306 + return false;
  307 + }
  308 + }
  309 + //3.课堂内有多个人并且都不是老师,选择一个nodeId最小的来操作
  310 + for(let k in this.rosters){
  311 + //如果选择的nodeId是自己就有权限,否则没有权限
  312 + if(k==GlobalConfig.nodeId){
  313 + return true;
  314 + }else {
  315 + return false;
  316 + }
  317 + }
  318 + return false
  319 + }
294 //停止录制 320 //停止录制
295 stopRecord(isForce) { 321 stopRecord(isForce) {
296 - /* if (isForce && isForce == true) {  
297 - //强制停止,可以是host之外的身份(比如当前课堂老师异常退出,没有老师,会随机选择一个人来做释放操作)  
298 - if (GlobalConfig.recordStatus) { 322 + //判断是否有权限
  323 + if (this.checkHasRecordControl()){
299 loger.warn('停止录制', "isHost", GlobalConfig.isHost, "recordStatus", GlobalConfig.recordStatus); 324 loger.warn('停止录制', "isHost", GlobalConfig.isHost, "recordStatus", GlobalConfig.recordStatus);
  325 + //this.sendUpdaterClassStatusInfo({"actionType":GlobalConfig.classStatus, isStopAllPublishMedia: true});
  326 + this.sendConferMsg({"to": 0, "message": "STOP_ALL_PUBLISH", "actionType": ApeConsts.STOP_ALL_PUBLISH});
  327 + setTimeout(()=>{
300 GlobalConfig.classStopTime = EngineUtils.creatTimestampStr(); 328 GlobalConfig.classStopTime = EngineUtils.creatTimestampStr();
301 - this.sendConferRecordMsg({"recordStatus": false});  
302 - this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE);  
303 - }  
304 - } else {  
305 - //身份是host,并且当前正在录制中  
306 - if (GlobalConfig.isHost && GlobalConfig.recordStatus) {  
307 - GlobalConfig.classStopTime = EngineUtils.creatTimestampStr();  
308 - this.sendConferRecordMsg({"recordStatus": false});  
309 this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE); 329 this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE);
310 - }  
311 - }*/  
312 - //身份是host  
313 - if (GlobalConfig.isHost) {  
314 - loger.warn('停止录制', "isHost", GlobalConfig.isHost, "recordStatus", GlobalConfig.recordStatus);  
315 - GlobalConfig.classStopTime = EngineUtils.creatTimestampStr();  
316 this.sendConferRecordMsg({"recordStatus": false}); 330 this.sendConferRecordMsg({"recordStatus": false});
317 - this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE); 331 + },2000);
318 }else { 332 }else {
319 loger.warn('没有权限停止录制', "isHost", GlobalConfig.isHost, "recordStatus", GlobalConfig.recordStatus); 333 loger.warn('没有权限停止录制', "isHost", GlobalConfig.isHost, "recordStatus", GlobalConfig.recordStatus);
320 } 334 }
@@ -363,7 +377,6 @@ class ConferApe extends Ape { @@ -363,7 +377,6 @@ class ConferApe extends Ape {
363 this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE); 377 this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE);
364 //this.sendUpdaterClassStatusInfo({"actionType": 0, isStopAllPublishMedia: true}); 378 //this.sendUpdaterClassStatusInfo({"actionType": 0, isStopAllPublishMedia: true});
365 this.sendUpdaterClassStatusInfo({"actionType": ApeConsts.CLASS_STATUS_WAIT, isStopAllPublishMedia: false}); 379 this.sendUpdaterClassStatusInfo({"actionType": ApeConsts.CLASS_STATUS_WAIT, isStopAllPublishMedia: false});
366 - loger.log('restorClass');  
367 } 380 }
368 381
369 // 全局禁言 382 // 全局禁言
@@ -400,10 +413,12 @@ class ConferApe extends Ape { @@ -400,10 +413,12 @@ class ConferApe extends Ape {
400 let timestamp = EngineUtils.creatTimestampStr(); 413 let timestamp = EngineUtils.creatTimestampStr();
401 GlobalConfig.classStopTime = timestamp; 414 GlobalConfig.classStopTime = timestamp;
402 415
  416 +/*
403 //如果录制的文件名不存在,需要创建一个名字 417 //如果录制的文件名不存在,需要创建一个名字
404 let timestampYMD = EngineUtils.creatTimestampYMD(); 418 let timestampYMD = EngineUtils.creatTimestampYMD();
405 GlobalConfig.recordFileName = GlobalConfig.recordFileName || 419 GlobalConfig.recordFileName = GlobalConfig.recordFileName ||
406 GlobalConfig.siteId + "/" + timestampYMD + "/" + GlobalConfig.classId + "_" + timestampYMD + ".rec"; //4、文件名称 $RECORD_HOME/`site id`/`日期`/`filename` 例:/data/record/su/20161216/`filename` 420 GlobalConfig.siteId + "/" + timestampYMD + "/" + GlobalConfig.classId + "_" + timestampYMD + ".rec"; //4、文件名称 $RECORD_HOME/`site id`/`日期`/`filename` 例:/data/record/su/20161216/`filename`
  421 +*/
407 422
408 if (GlobalConfig.classStatus == ApeConsts.CLASS_STATUS_WAIT) { 423 if (GlobalConfig.classStatus == ApeConsts.CLASS_STATUS_WAIT) {
409 //之前是为开始状态,第一次点开始 424 //之前是为开始状态,第一次点开始
@@ -418,8 +433,8 @@ class ConferApe extends Ape { @@ -418,8 +433,8 @@ class ConferApe extends Ape {
418 //同步课堂状态 433 //同步课堂状态
419 //this.sendUpdaterClassStatusInfo({"actionType": 1, isStopAllPublishMedia: true}); 434 //this.sendUpdaterClassStatusInfo({"actionType": 1, isStopAllPublishMedia: true});
420 this.sendUpdaterClassStatusInfo({"actionType": ApeConsts.CLASS_STATUS_STARTED, isStopAllPublishMedia: false}); 435 this.sendUpdaterClassStatusInfo({"actionType": ApeConsts.CLASS_STATUS_STARTED, isStopAllPublishMedia: false});
421 - //开始计时  
422 - this.startTimerCounter(); 436 + ////开始计时
  437 + //this.startTimerCounter();
423 } else { 438 } else {
424 loger.warn('没有开始课堂的权限'); 439 loger.warn('没有开始课堂的权限');
425 } 440 }
@@ -451,7 +466,7 @@ class ConferApe extends Ape { @@ -451,7 +466,7 @@ class ConferApe extends Ape {
451 loger.warn("调用关闭课堂->"); 466 loger.warn("调用关闭课堂->");
452 this.stopTimerCounter(); 467 this.stopTimerCounter();
453 this.restorClass(); 468 this.restorClass();
454 - //把所有人都踢出课堂 469 + //停止所有人推流,把所有人都踢出课堂
455 this.sendConferMsg({"to": 0, "message": "所有人退出课堂", "actionType": ApeConsts.CLASS_ACTION_CLOSE_ALL}); 470 this.sendConferMsg({"to": 0, "message": "所有人退出课堂", "actionType": ApeConsts.CLASS_ACTION_CLOSE_ALL});
456 this.stopRecord();//关闭课堂的时候停止录制 471 this.stopRecord();//关闭课堂的时候停止录制
457 } 472 }
@@ -557,7 +572,7 @@ class ConferApe extends Ape { @@ -557,7 +572,7 @@ class ConferApe extends Ape {
557 //更新课堂信息 572 //更新课堂信息
558 sendUpdaterClassStatusInfo(_param) { 573 sendUpdaterClassStatusInfo(_param) {
559 //{"actionType": 1,isStopAllPublishMedia:false} //actionType课堂状态 isStopAllPublishMedia是否停止当前的所有推流 574 //{"actionType": 1,isStopAllPublishMedia:false} //actionType课堂状态 isStopAllPublishMedia是否停止当前的所有推流
560 - loger.log('发送更新课堂信息->'); 575 + //loger.log('发送更新课堂信息->');
561 if (_param == null || EngineUtils.isEmptyObject(_param)) { 576 if (_param == null || EngineUtils.isEmptyObject(_param)) {
562 loger.log('发送更新课堂信息->参数错误'); 577 loger.log('发送更新课堂信息->参数错误');
563 this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG); 578 this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG);
@@ -610,21 +625,11 @@ class ConferApe extends Ape { @@ -610,21 +625,11 @@ class ConferApe extends Ape {
610 } 625 }
611 loger.log('课堂模块初始完成->当前课堂状态:'+ GlobalConfig.classStatus,"recordStatus:"+GlobalConfig.recordStatus); 626 loger.log('课堂模块初始完成->当前课堂状态:'+ GlobalConfig.classStatus,"recordStatus:"+GlobalConfig.recordStatus);
612 this.timerCounter.addTimerCallBack(this.timerCounterUptate.bind(this), 1); 627 this.timerCounter.addTimerCallBack(this.timerCounterUptate.bind(this), 1);
613 -  
614 - //2秒后执行开始上课和开始录制的判断逻辑  
615 - clearTimeout(this.startClassTimer);  
616 - this.startClassTimer=setTimeout(()=>{  
617 - //开启录制,录制接口中会自动判断是否需要录制  
618 - this.startRecord();  
619 - //如果当前课堂正在进行中,开启计时器  
620 - if (GlobalConfig.classStatus == ApeConsts.CLASS_STATUS_STARTED) {  
621 - //开始计时  
622 this.startTimerCounter(); 628 this.startTimerCounter();
623 - //this.startRecord();  
624 - } else {  
625 - loger.log('自动开始上课->classStatus:', GlobalConfig.classStatus, " isHost:", GlobalConfig.isHost, " isAutoStartClass:", GlobalConfig.isAutoStartClass, " isRecordPlayBack:", GlobalConfig.isRecordPlayBack);  
626 this.startClass(); 629 this.startClass();
627 - } 630 + clearTimeout(this.startRecordTimer);
  631 + this.startRecordTimer=setTimeout(()=>{
  632 + this.startRecord();
628 },2000); 633 },2000);
629 634
630 /* //如果当前课堂正在进行中,开启计时器 635 /* //如果当前课堂正在进行中,开启计时器
@@ -672,7 +677,7 @@ class ConferApe extends Ape { @@ -672,7 +677,7 @@ class ConferApe extends Ape {
672 //以一定的时间间隔同步课堂内所有人的累积上课时间 677 //以一定的时间间隔同步课堂内所有人的累积上课时间
673 if (GlobalConfig.classTimestamp % GlobalConfig.updateClassInfoDelay == 0) { 678 if (GlobalConfig.classTimestamp % GlobalConfig.updateClassInfoDelay == 0) {
674 //如果是host身份,需要同步时间给其他人,同时把当前的状态上传到服务器 679 //如果是host身份,需要同步时间给其他人,同时把当前的状态上传到服务器
675 - if (GlobalConfig.isHost||this.rosterLen<=1) { 680 + if (this.checkHasRecordControl()) {
676 //保存数据到Sass 681 //保存数据到Sass
677 this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE); 682 this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE);
678 //同步消息给其他人 683 //同步消息给其他人
@@ -690,8 +695,23 @@ class ConferApe extends Ape { @@ -690,8 +695,23 @@ class ConferApe extends Ape {
690 this._emit(MessageTypes.SWITCH_HLS_IP); 695 this._emit(MessageTypes.SWITCH_HLS_IP);
691 } 696 }
692 } 697 }
  698 +
  699 +
693 //更新录制进行时间 700 //更新录制进行时间
  701 + GlobalConfig.recordTimestamp = GlobalConfig.recordTimestamp + 1;
  702 + if (this.checkHasRecordControl()) {
  703 + //以一定的时间间隔同步课堂内所有人的累积上课时间
  704 + if (GlobalConfig.recordTimestamp % GlobalConfig.updateRecordTimeDelay == 0) {
  705 + //保存数据到Sass
  706 + this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE);
  707 + }
  708 +
  709 + if (GlobalConfig.recordTimestamp % GlobalConfig.updateClassInfoDelay == 0) {
  710 + //MCU同步消息给其他人
  711 + this.sendUpdaterClassStatusInfo({"actionType": GlobalConfig.classStatus, isStopAllPublishMedia: false});
  712 + }
694 713
  714 + }
695 /* if (GlobalConfig.classStatus == ApeConsts.CLASS_STATUS_STARTED) { 715 /* if (GlobalConfig.classStatus == ApeConsts.CLASS_STATUS_STARTED) {
696 GlobalConfig.classTimestamp = GlobalConfig.classTimestamp + 1; //计时 716 GlobalConfig.classTimestamp = GlobalConfig.classTimestamp + 1; //计时
697 //老师身份的时候要记录录制的时间 717 //老师身份的时候要记录录制的时间
@@ -774,9 +794,11 @@ class ConferApe extends Ape { @@ -774,9 +794,11 @@ class ConferApe extends Ape {
774 tableUpdateHandler(owner, itemIdx, itemData) { 794 tableUpdateHandler(owner, itemIdx, itemData) {
775 try { 795 try {
776 let model = this.unPackPdu(owner, itemIdx, itemData); 796 let model = this.unPackPdu(owner, itemIdx, itemData);
777 - loger.log("课堂更新->",model); 797 + //loger.log("课堂更新->",model.classStatusInfo);
  798 + //{"itemIdx":720899,"from":976168842,"owner":976168842,"actionType":null,"classStatusInfo":{"nodeId":976168842,"userId":"user_979813","userName":"user_979813","siteId":"markettest","classId":889112694,"className":"ly828-1v1","classType":1,"classStatus":1,"classStartTime":"2017-8-28-16-33-18","classStopTime":"2017-8-29-11-9-28","classTimestamp":1930,"classBeginTime":"2017-08-28 16:00:00","classEndTime":"2017-08-31 18:00:00","recordStatus":false,"recordTimestamp":2825,"recordFileName":"markettest/20170828/889112694_20170828.rec","recordDownloadUrl":"","serverTimestamp":1503976246,"activeDocId":976170739,"activeDocCurPage":1,"isStopAllPublishMedia":false,"currentSceneTableId":0,"silence":false,"silenceUsers":"{}","isEnableDraw":true}}
778 //处理课堂更新的信息 799 //处理课堂更新的信息
779 if (model && model.classStatusInfo) { 800 if (model && model.classStatusInfo) {
  801 + // loger.log("课堂更新->",model.classStatusInfo);
780 try { 802 try {
781 model.classStatusInfo.silenceUsers = JSON.parse(model.classStatusInfo.silenceUsers); 803 model.classStatusInfo.silenceUsers = JSON.parse(model.classStatusInfo.silenceUsers);
782 } catch (err) { 804 } catch (err) {
@@ -801,13 +823,13 @@ class ConferApe extends Ape { @@ -801,13 +823,13 @@ class ConferApe extends Ape {
801 return; 823 return;
802 } 824 }
803 825
804 - if (GlobalConfig.classStatus == ApeConsts.CLASS_STATUS_STARTED) { 826 + /* if (GlobalConfig.classStatus == ApeConsts.CLASS_STATUS_STARTED) {
805 //如果课堂在进行中,开始计时器 827 //如果课堂在进行中,开始计时器
806 this.startTimerCounter(); 828 this.startTimerCounter();
807 } else { 829 } else {
808 //停止计时 830 //停止计时
809 this.stopTimerCounter(); 831 this.stopTimerCounter();
810 - } 832 + }*/
811 } catch (err) { 833 } catch (err) {
812 loger.warn('课堂更新->error', err.message); 834 loger.warn('课堂更新->error', err.message);
813 } 835 }
@@ -825,8 +847,15 @@ class ConferApe extends Ape { @@ -825,8 +847,15 @@ class ConferApe extends Ape {
825 switch (chatMsg.actionType) { 847 switch (chatMsg.actionType) {
826 case ApeConsts.CLASS_ACTION_CLOSE_ALL: 848 case ApeConsts.CLASS_ACTION_CLOSE_ALL:
827 loger.log(chatMsg.message); 849 loger.log(chatMsg.message);
  850 + //关闭之前停止所有推流
  851 + this._emit(MessageTypes.STOP_ALL_MEDIA_PUBLISH);
828 //收到课堂关闭,所有人都退出,执行自己关闭的流程 852 //收到课堂关闭,所有人都退出,执行自己关闭的流程
  853 + setTimeout(()=>{
829 this._emit(MessageTypes.CLASS_RUN_EXIT, {'type': 1}); 854 this._emit(MessageTypes.CLASS_RUN_EXIT, {'type': 1});
  855 + },2000);
  856 + break;
  857 + case ApeConsts.STOP_ALL_PUBLISH:
  858 + this._emit(MessageTypes.STOP_ALL_MEDIA_PUBLISH);
830 break; 859 break;
831 case ApeConsts.CLASS_ACTION_KICK_OUT_ROSTER: 860 case ApeConsts.CLASS_ACTION_KICK_OUT_ROSTER:
832 if (chatMsg.toNodeID == GlobalConfig.nodeId) { 861 if (chatMsg.toNodeID == GlobalConfig.nodeId) {
@@ -1116,23 +1145,15 @@ class ConferApe extends Ape { @@ -1116,23 +1145,15 @@ class ConferApe extends Ape {
1116 //当前人员列表中抽一个人来检查离开人员是否占用频道 1145 //当前人员列表中抽一个人来检查离开人员是否占用频道
1117 for (let key in this.rosters) { 1146 for (let key in this.rosters) {
1118 let randNodeId = parseInt(key); 1147 let randNodeId = parseInt(key);
1119 - //如果抽到的人是自己就处理以下操作 1148 + //判断是否是自己就处理以下操作
1120 if (randNodeId == GlobalConfig.nodeId) { 1149 if (randNodeId == GlobalConfig.nodeId) {
1121 - loger.log(randNodeId, "有权限检查离开的人员是否占用channel"); 1150 + loger.log("检查离开的人员是否占用channel");
1122 this._emit(MessageTypes.CLASS_NONENTITY_ROSTER, {"nodeId": nodeId, "rosterLen": this.rosterLen}); 1151 this._emit(MessageTypes.CLASS_NONENTITY_ROSTER, {"nodeId": nodeId, "rosterLen": this.rosterLen});
1123 //如果离开的人员是老师,需要暂停当前的课堂 1152 //如果离开的人员是老师,需要暂停当前的课堂
1124 -  
1125 if (user && user.role == ApeConsts.NR_HOST) { 1153 if (user && user.role == ApeConsts.NR_HOST) {
1126 this.pauseClass(); 1154 this.pauseClass();
1127 -  
1128 - /* //强制停止录制  
1129 - this.stopRecord(true)*/;  
1130 -  
1131 } 1155 }
1132 - } else {  
1133 - loger.warn(GlobalConfig.nodeId, "没有权限检查离开的人员是否占用channel");  
1134 } 1156 }
1135 - //查找到一个就跳出操作  
1136 return; 1157 return;
1137 } 1158 }
1138 } 1159 }
@@ -1207,7 +1228,7 @@ class ConferApe extends Ape { @@ -1207,7 +1228,7 @@ class ConferApe extends Ape {
1207 let modelPdu = pdu['RCClassSendDataModelPdu'].decode(itemData); 1228 let modelPdu = pdu['RCClassSendDataModelPdu'].decode(itemData);
1208 return modelPdu; 1229 return modelPdu;
1209 } catch (err) { 1230 } catch (err) {
1210 - loger.log("课堂收到数据 unPackPdu Pdu解析错误,itemIdx=" + itemIdx + " err:" + err.message); 1231 + loger.log("课堂收到数据解析错误:" + itemIdx + " err:" + err.message);
1211 } 1232 }
1212 return null; 1233 return null;
1213 } 1234 }
@@ -389,7 +389,7 @@ class DocApe extends Ape { @@ -389,7 +389,7 @@ class DocApe extends Ape {
389 docDataModel.animationStep = 1;//切换文档之后动画步数还原 389 docDataModel.animationStep = 1;//切换文档之后动画步数还原
390 390
391 //loger.log('切换文档,当前文档和上一个显示的文档都需要更新状态'); 391 //loger.log('切换文档,当前文档和上一个显示的文档都需要更新状态');
392 - loger.log({"oldDoc": oldDocModel, "nowDoc": docDataModel}); 392 + //loger.log({"oldDoc": oldDocModel, "nowDoc": docDataModel});
393 //更新当前选择的文档 393 //更新当前选择的文档
394 this.updaterDoc(docDataModel, docDataModel.itemIdx); 394 this.updaterDoc(docDataModel, docDataModel.itemIdx);
395 395
@@ -673,7 +673,7 @@ class DocApe extends Ape { @@ -673,7 +673,7 @@ class DocApe extends Ape {
673 } 673 }
674 674
675 onJoinChannelHandlerSuccess() { 675 onJoinChannelHandlerSuccess() {
676 - loger.log(this._session_name + ' onJoinChannelHandlerSuccess==========================='); 676 + //loger.log(this._session_name + ' onJoinChannelHandlerSuccess===========================');
677 if (this._apeDelayed) { 677 if (this._apeDelayed) {
678 // this._apeDelayedMsgs.push(regBuffer); 678 // this._apeDelayedMsgs.push(regBuffer);
679 // this._apeDelayedStart(); 679 // this._apeDelayedStart();
@@ -309,7 +309,7 @@ class VideoApe extends Ape { @@ -309,7 +309,7 @@ class VideoApe extends Ape {
309 309
310 //释放nodeId占用的指定的channelId频道 310 //释放nodeId占用的指定的channelId频道
311 _releaseChannelForNodeId(nodeId, channelId) { 311 _releaseChannelForNodeId(nodeId, channelId) {
312 - loger.log(nodeId, "_releaseChannelForNodeId-->channelId", channelId); 312 + loger.log(nodeId, "停止-->channelId", channelId);
313 let channelInfo = this.mediaModule.mediaChannels[channelId]; 313 let channelInfo = this.mediaModule.mediaChannels[channelId];
314 if (channelInfo && channelInfo.status == ApeConsts.CHANNEL_STATUS_OPENING) { 314 if (channelInfo && channelInfo.status == ApeConsts.CHANNEL_STATUS_OPENING) {
315 if (channelInfo.fromNodeId == nodeId) { 315 if (channelInfo.fromNodeId == nodeId) {
@@ -480,11 +480,13 @@ class VideoApe extends Ape { @@ -480,11 +480,13 @@ class VideoApe extends Ape {
480 this._emit(MessageTypes.VIDEO_BROADCAST, videoReceivePdu); 480 this._emit(MessageTypes.VIDEO_BROADCAST, videoReceivePdu);
481 } 481 }
482 } 482 }
  483 + //切换了MS,重新更新一下当前正在播放的流地址
  484 + changeMediaMs(){
483 485
484 - 486 + }
485 tableUpdateHandler(owner, itemIdx, itemData, seek) { 487 tableUpdateHandler(owner, itemIdx, itemData, seek) {
486 let unpackChannelInfo = this.unPackPdu(owner, itemIdx, itemData); 488 let unpackChannelInfo = this.unPackPdu(owner, itemIdx, itemData);
487 - loger.log("tableUpdateHandler->channel", itemIdx, 'mediaType', unpackChannelInfo.mediaType, 'status->', unpackChannelInfo.status, "seek->", seek); 489 + loger.log("视频模块数据更新->channel", itemIdx, 'mediaType', unpackChannelInfo.mediaType, 'status->', unpackChannelInfo.status, "seek->", seek);
488 490
489 //****很重要******** 491 //****很重要********
490 //如果owner的值为0,代表的是这个歌频道已经被释放了(mcu服务端对于占用channel的掉线用户,就是把owner设置为0) 492 //如果owner的值为0,代表的是这个歌频道已经被释放了(mcu服务端对于占用channel的掉线用户,就是把owner设置为0)
@@ -586,8 +588,6 @@ class VideoApe extends Ape { @@ -586,8 +588,6 @@ class VideoApe extends Ape {
586 }); 588 });
587 } 589 }
588 } 590 }
589 -  
590 -  
591 if (unpackChannelInfo.mediaType != ApeConsts.MEDIA_TYPE_SHARE) { 591 if (unpackChannelInfo.mediaType != ApeConsts.MEDIA_TYPE_SHARE) {
592 //非屏幕共享情况的处理 592 //非屏幕共享情况的处理
593 MediaModule.allMediaChannelsList[itemIdx] = unpackChannelInfo; 593 MediaModule.allMediaChannelsList[itemIdx] = unpackChannelInfo;
@@ -610,7 +610,7 @@ class VideoApe extends Ape { @@ -610,7 +610,7 @@ class VideoApe extends Ape {
610 } 610 }
611 //owner为0就是没有使用 611 //owner为0就是没有使用
612 if(channelInfo.owner==0){ 612 if(channelInfo.owner==0){
613 - channelInfo.status == ApeConsts.CHANNEL_STATUS_RELEASED 613 + channelInfo.status = ApeConsts.CHANNEL_STATUS_RELEASED
614 } 614 }
615 this.sendTableUpdateHandler(channelInfo); 615 this.sendTableUpdateHandler(channelInfo);
616 } 616 }