李勇

1.Sass增加保存开始录制信息的接口,储存录制文件名

2.增加录制的协议号和录制的pdu结构
3.会议模块增加开始录制和停止录制的接口
@@ -65,6 +65,7 @@ export default class MessageEntrance extends Emiter { @@ -65,6 +65,7 @@ export default class MessageEntrance extends Emiter {
65 _sass.on(_sass.CLASS_GET_CLASS_DETAIL, this._sassGetClassDetailSuccessHandler.bind(this));//获取会议的基本信息 65 _sass.on(_sass.CLASS_GET_CLASS_DETAIL, this._sassGetClassDetailSuccessHandler.bind(this));//获取会议的基本信息
66 _sass.on(_sass.CLASS_GET_CLASS_PARAM, this._sassGetClassParamSuccessHandler.bind(this));//获取会议的最全信息和历史保存的数据 66 _sass.on(_sass.CLASS_GET_CLASS_PARAM, this._sassGetClassParamSuccessHandler.bind(this));//获取会议的最全信息和历史保存的数据
67 _sass.on(_sass.CLASS_SAVE_STATUS_INFO_SUCCESS, this._sassSaveClassStatusInfoSuccessHandler.bind(this));//保存会议状态信息 67 _sass.on(_sass.CLASS_SAVE_STATUS_INFO_SUCCESS, this._sassSaveClassStatusInfoSuccessHandler.bind(this));//保存会议状态信息
  68 + _sass.on(_sass.CLASS_SAVE_RECORD_INFO_SUCCESS, this._sassSaveClassRecordInfoSuccessHandler.bind(this));//保存会议录制信息
68 _sass.on(_sass.DELETE_DOCUMENT_SUCCESS, this._sassDeleteDocumentSuccess.bind(this));//sass删除文档成功 69 _sass.on(_sass.DELETE_DOCUMENT_SUCCESS, this._sassDeleteDocumentSuccess.bind(this));//sass删除文档成功
69 70
70 // 底层MCU消息层 71 // 底层MCU消息层
@@ -80,6 +81,7 @@ export default class MessageEntrance extends Emiter { @@ -80,6 +81,7 @@ export default class MessageEntrance extends Emiter {
80 _confer_ape.on(MessageTypes.CLASS_STATUS_INFO_CHANGE, this._onClassStatusInfoChange.bind(this));//当前会议状态信息发生改变 81 _confer_ape.on(MessageTypes.CLASS_STATUS_INFO_CHANGE, this._onClassStatusInfoChange.bind(this));//当前会议状态信息发生改变
81 _confer_ape.on(MessageTypes.CLASS_DELETE_ROSTER, this._onClassDeleteRoster.bind(this));//当前会议人员离开 82 _confer_ape.on(MessageTypes.CLASS_DELETE_ROSTER, this._onClassDeleteRoster.bind(this));//当前会议人员离开
82 _confer_ape.on(MessageTypes.CLASS_NONENTITY_ROSTER,this._onClassNonentityRoster.bind(this));//当前会议中视频或音频占用channel的nodeId ,在人员列表中不存在 83 _confer_ape.on(MessageTypes.CLASS_NONENTITY_ROSTER,this._onClassNonentityRoster.bind(this));//当前会议中视频或音频占用channel的nodeId ,在人员列表中不存在
  84 + _confer_ape.on(MessageTypes.CLASS_RECORD_START,this._onClassRecordStart.bind(this));//会议开始录制
83 85
84 86
85 _chat_ape = new ChatApe(); 87 _chat_ape = new ChatApe();
@@ -117,6 +119,7 @@ export default class MessageEntrance extends Emiter { @@ -117,6 +119,7 @@ export default class MessageEntrance extends Emiter {
117 this.sendPauseClass = this._sendPauseClass; 119 this.sendPauseClass = this._sendPauseClass;
118 this.sendCloseClass = this._sendCloseClass; 120 this.sendCloseClass = this._sendCloseClass;
119 121
  122 +
120 //chatApe 123 //chatApe
121 this.sendChatMsg = this._sendChatMsg; 124 this.sendChatMsg = this._sendChatMsg;
122 125
@@ -197,6 +200,18 @@ export default class MessageEntrance extends Emiter { @@ -197,6 +200,18 @@ export default class MessageEntrance extends Emiter {
197 this._sassSaveClassStatusInfo(); 200 this._sassSaveClassStatusInfo();
198 } 201 }
199 202
  203 + //如果是第一次点击开始上课,需要创建录制时的文件名
  204 + _onClassRecordStart(_param){
  205 + if(GlobalConfig.getCurrentStatus().code!=GlobalConfig.statusCode_2.code){
  206 + loger.warn("不能保存会议状态",GlobalConfig.getCurrentStatus());
  207 + return;
  208 + }
  209 + if(_sass){
  210 + _sass.saveClassRecordContrlInfo(_param);
  211 + }
  212 + }
  213 +
  214 +
200 //有人员离开 215 //有人员离开
201 _onClassDeleteRoster(_data){ 216 _onClassDeleteRoster(_data){
202 //{"nodeId":nodeId} 217 //{"nodeId":nodeId}
@@ -507,7 +522,7 @@ export default class MessageEntrance extends Emiter { @@ -507,7 +522,7 @@ export default class MessageEntrance extends Emiter {
507 //根据从Sass获取的数据信息,同步最后一次保存的会议状态信息 522 //根据从Sass获取的数据信息,同步最后一次保存的会议状态信息
508 loger.log("同步最后一次保存过的会议状态信息"); 523 loger.log("同步最后一次保存过的会议状态信息");
509 GlobalConfig.setClassStatusInfo(_data.currentInfo); 524 GlobalConfig.setClassStatusInfo(_data.currentInfo);
510 - console.log(GlobalConfig.classStatusInfo) 525 + console.log(GlobalConfig.classStatusInfo);
511 } else { 526 } else {
512 loger.log("还没有保存过会议状信息"); 527 loger.log("还没有保存过会议状信息");
513 } 528 }
@@ -535,6 +550,9 @@ export default class MessageEntrance extends Emiter { @@ -535,6 +550,9 @@ export default class MessageEntrance extends Emiter {
535 _sassSaveClassStatusInfoSuccessHandler(_data) { 550 _sassSaveClassStatusInfoSuccessHandler(_data) {
536 loger.log('保存会议状态信息成功.', _data); 551 loger.log('保存会议状态信息成功.', _data);
537 } 552 }
  553 + _sassSaveClassRecordInfoSuccessHandler(_data){
  554 + loger.log('保存会议录制信息成功.', _data);
  555 + }
538 556
539 //Sass校验流程结束之后,开始加入MCU 557 //Sass校验流程结束之后,开始加入MCU
540 _joinMCU() { 558 _joinMCU() {
@@ -671,6 +689,7 @@ export default class MessageEntrance extends Emiter { @@ -671,6 +689,7 @@ export default class MessageEntrance extends Emiter {
671 } 689 }
672 //离开会议 690 //离开会议
673 if(_confer_ape){ 691 if(_confer_ape){
  692 + _confer_ape.stopRecord();
674 _confer_ape.leaveClass(); 693 _confer_ape.leaveClass();
675 } 694 }
676 //断开MCU连接 695 //断开MCU连接
@@ -680,6 +699,7 @@ export default class MessageEntrance extends Emiter { @@ -680,6 +699,7 @@ export default class MessageEntrance extends Emiter {
680 } 699 }
681 } 700 }
682 701
  702 +
683 //ChatApe 703 //ChatApe
684 // 发送聊天消息 704 // 发送聊天消息
685 _sendChatMsg(_messageInfo) { 705 _sendChatMsg(_messageInfo) {
@@ -52,6 +52,21 @@ class EngineUtils{ @@ -52,6 +52,21 @@ class EngineUtils{
52 return timeStr; 52 return timeStr;
53 } 53 }
54 54
  55 + //生成时间戳 格式:"20170209"
  56 + static creatTimestampYMD(){
  57 + let curTime = new Date();
  58 + let year = "" + curTime.getFullYear();
  59 + let month = "" +(curTime.getMonth()+1);
  60 + let day = "" + curTime.getDate();
  61 +
  62 + if(month.length<2){
  63 + month="0"+month;
  64 + }
  65 + if(day.length<2){
  66 + day="0"+day;
  67 + }
  68 + return year+month+day;
  69 + }
55 static objectToBase64(_object){ 70 static objectToBase64(_object){
56 try{ 71 try{
57 let _objectStr=JSON.stringify(_object); 72 let _objectStr=JSON.stringify(_object);
@@ -307,7 +307,7 @@ GlobalConfig.classTimestamp=0;//从课堂开始到现在的时 @@ -307,7 +307,7 @@ GlobalConfig.classTimestamp=0;//从课堂开始到现在的时
307 307
308 GlobalConfig.recordStatus=false;//当前录制状态 308 GlobalConfig.recordStatus=false;//当前录制状态
309 GlobalConfig.recordTimestamp=0;//相对于首次开始录制的进行时间 309 GlobalConfig.recordTimestamp=0;//相对于首次开始录制的进行时间
310 -GlobalConfig.recordFileName="";//录制的文件名 310 +GlobalConfig.recordFileName="";//录制的文件名,如 果为空就创建一个
311 GlobalConfig.recordDownloadUrl="";//下载地址 311 GlobalConfig.recordDownloadUrl="";//下载地址
312 GlobalConfig.recordReplaytickValues={}; // 滚动条关键点,用于快进快退 312 GlobalConfig.recordReplaytickValues={}; // 滚动条关键点,用于快进快退
313 313
@@ -26,6 +26,7 @@ MessageTypes.CLASS_STATUS_INFO_CHANGE= 'class.status.info.change';//会议状态 @@ -26,6 +26,7 @@ MessageTypes.CLASS_STATUS_INFO_CHANGE= 'class.status.info.change';//会议状态
26 26
27 MessageTypes.CLASS_UPDATE_TIMER='class.update.timer';//更新当前上课的时间 27 MessageTypes.CLASS_UPDATE_TIMER='class.update.timer';//更新当前上课的时间
28 28
  29 +MessageTypes.CLASS_RECORD_START='class.record.start';//开始录制
29 30
30 31
31 32
@@ -10,428 +10,436 @@ const loger = Loger.getLoger('Sass'); @@ -10,428 +10,436 @@ const loger = Loger.getLoger('Sass');
10 10
11 let confInfo = {}; 11 let confInfo = {};
12 class Sass extends Emiter { 12 class Sass extends Emiter {
13 - constructor() {  
14 - super();  
15 - }  
16 -  
17 - ///////////////////////////////////////Sass 接口///////////////////////////////////////////////////  
18 - //Sass init初始化获取课堂校验信息-----------------------------------------------------------------  
19 - getJoinParams(_initInfo) {  
20 - /* 获取用于加入课堂的参数  
21 - /3m/api/meeting/joinParams.do  
22 - 参数 (application/x-www-form-urlencoded):  
23 - 名称 类型 可选 默认值 说明  
24 - meetingNumber String 否 null 课堂号  
25 - userID String 是 0 用户id  
26 - 返回 (application/json):  
27 - code int 0 正常  
28 - 1 课堂号必填  
29 - 2 无效的课堂号  
30 - 3 没有对应的站点  
31 - 4 站点已过期  
32 - siteId String 站点号  
33 - passwordRequired Boolean 是否需要输入密码  
34 - md5 String 用于后续加入课堂验证  
35 - msType int 媒体服务器类型  
36 - classType 课堂类型  
37 - */  
38 - let url = `http://${_initInfo.portal}/3m/api/meeting/joinParams.do?meetingNumber=${_initInfo.classId}&userID=${_initInfo.userId}`;  
39 - loger.log('1.初始化init获取课堂校验信息.');  
40 - console.log(url);  
41 - console.log(_initInfo);  
42 - fetch(url, {  
43 - timeout: 5000  
44 - })  
45 - .then(ret => {  
46 - if (ret.ok) {  
47 - return ret.json();  
48 - } else {  
49 - loger.error(`初始化init获取课堂校验信息-网络异常.状态码:${ret.status}`);  
50 - this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_CLASS_INIT_NETWORK);  
51 - throw '';  
52 - }  
53 - })  
54 - .then(ret => {  
55 - // code int 0 正常  
56 - // 1 课堂号必填  
57 - //2 无效的课堂号  
58 - //3 没有对应的站点  
59 - //4 站点已过期  
60 - if (ret.code === 0) {  
61 - loger.log('初始化init获取课堂校验信息-完成');  
62 - this._emit(Sass.CLASS_INIT_SUCCESS,ret);  
63 - } else if(ret.code === 1) {  
64 - //loger.warn('Sass获取课堂校验信息失败.');  
65 - this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_CLASS_INIT_FAILED_1);  
66 - } else if(ret.code === 2) {  
67 - //loger.warn('Sass获取课堂校验信息失败.');  
68 - this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_CLASS_INIT_FAILED_2);  
69 - } else if(ret.code === 3) {  
70 - //loger.warn('Sass获取课堂校验信息失败.');  
71 - this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_CLASS_INIT_FAILED_3);  
72 - } else if(ret.code === 4) {  
73 - //loger.warn('Sass获取课堂校验信息失败.');  
74 - this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_CLASS_INIT_FAILED_4);  
75 - }else {  
76 - this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_CLASS_INIT_FAILED,ret);  
77 - }  
78 - })  
79 - .catch(err => {  
80 - loger.error(`初始化init获取课堂校验信息-异常.状态码:${err}`);  
81 - this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_CLASS_INIT_PROTOCOL,err);  
82 - });  
83 - }  
84 -  
85 - // Sass校验开始-->密码校验(如果需要密码)--->MD5校验----------------------------------------------------  
86 - passwordAndMd5Checking(_param) {  
87 - loger.log('2.开始Sass校验');  
88 - console.log(_param);  
89 - confInfo = _param;  
90 - // 密码校验  
91 - if (confInfo.passwordRequired === 'true'||confInfo.passwordRequired === true) {  
92 - this.sendPWDChecking();  
93 - return ; 13 + constructor() {
  14 + super();
94 } 15 }
95 - // MD5校验  
96 - this.sendMD5Checking();  
97 - }  
98 16
99 - // 入会密码校验---------------------------------------------------------------------------------------  
100 - sendPWDChecking() {  
101 - //let url = `http://${classInfo.portal}/3m/getCheckMeetinig.do?siteId=${classInfo.siteId}&classId=${classInfo.classId}&password=${classInfo.password}`;  
102 - /*  
103 - /3m/api/meeting/signIn.do  
104 - siteId 站点号  
105 - classId 课堂号(meetingNumber)  
106 - isTeacher 是否是老师:1 是 0 否  
107 - password 输入的密码  
108 - // 请求格式 http://112.126.80.182/3m/api/meeting/signIn.do?siteId=h5test&classId=526661904&password=111111&isTeacher=0  
109 - */  
110 - //判断是否是老师  
111 - let isTeacher=0;  
112 - if(confInfo.userRole==ApeConsts.host){  
113 - isTeacher=1 17 + ///////////////////////////////////////Sass 接口///////////////////////////////////////////////////
  18 + //Sass init初始化获取课堂校验信息-----------------------------------------------------------------
  19 + getJoinParams(_initInfo) {
  20 + /* 获取用于加入课堂的参数
  21 + /3m/api/meeting/joinParams.do
  22 + 参数 (application/x-www-form-urlencoded):
  23 + 名称 类型 可选 默认值 说明
  24 + meetingNumber String 否 null 课堂号
  25 + userID String 是 0 用户id
  26 + 返回 (application/json):
  27 + code int 0 正常
  28 + 1 课堂号必填
  29 + 2 无效的课堂号
  30 + 3 没有对应的站点
  31 + 4 站点已过期
  32 + siteId String 站点号
  33 + passwordRequired Boolean 是否需要输入密码
  34 + md5 String 用于后续加入课堂验证
  35 + msType int 媒体服务器类型
  36 + classType 课堂类型
  37 + */
  38 + let url = `http://${_initInfo.portal}/3m/api/meeting/joinParams.do?meetingNumber=${_initInfo.classId}&userID=${_initInfo.userId}`;
  39 + loger.log('1.初始化init获取课堂校验信息.');
  40 + console.log(url);
  41 + console.log(_initInfo);
  42 + fetch(url, {
  43 + timeout: 5000
  44 + })
  45 + .then(ret => {
  46 + if (ret.ok) {
  47 + return ret.json();
  48 + } else {
  49 + loger.error(`初始化init获取课堂校验信息-网络异常.状态码:${ret.status}`);
  50 + this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_INIT_NETWORK);
  51 + throw '';
  52 + }
  53 + })
  54 + .then(ret => {
  55 + // code int 0 正常
  56 + // 1 课堂号必填
  57 + //2 无效的课堂号
  58 + //3 没有对应的站点
  59 + //4 站点已过期
  60 + if (ret.code === 0) {
  61 + loger.log('初始化init获取课堂校验信息-完成');
  62 + this._emit(Sass.CLASS_INIT_SUCCESS, ret);
  63 + } else if (ret.code === 1) {
  64 + //loger.warn('Sass获取课堂校验信息失败.');
  65 + this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_INIT_FAILED_1);
  66 + } else if (ret.code === 2) {
  67 + //loger.warn('Sass获取课堂校验信息失败.');
  68 + this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_INIT_FAILED_2);
  69 + } else if (ret.code === 3) {
  70 + //loger.warn('Sass获取课堂校验信息失败.');
  71 + this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_INIT_FAILED_3);
  72 + } else if (ret.code === 4) {
  73 + //loger.warn('Sass获取课堂校验信息失败.');
  74 + this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_INIT_FAILED_4);
  75 + } else {
  76 + this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_INIT_FAILED, ret);
  77 + }
  78 + })
  79 + .catch(err => {
  80 + loger.error(`初始化init获取课堂校验信息-异常.状态码:${err}`);
  81 + this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_INIT_PROTOCOL, err);
  82 + });
114 } 83 }
115 84
116 - let url = `http://${confInfo.portal}/3m/api/meeting/signIn.do?siteId=${confInfo.siteId}&classId=${confInfo.classId}&isTeacher=${isTeacher}&password=${confInfo.password}`;  
117 - loger.log('3.会议密码校验', url);  
118 - fetch(url, {  
119 - timeout: 5000  
120 - })  
121 - .then(ret => {  
122 - if (ret.status === 200) {  
123 - return ret.text();  
124 - } else {  
125 - loger.error(`会议密码校验-网络异常.状态码:${ret.status}`);  
126 - this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_CLASS_JOIN_NETWORK);  
127 - throw '';  
128 - }  
129 - })  
130 - .then(ret => {  
131 - let rectObj=JSON.parse(ret);  
132 - if (rectObj.flag === 'false'||rectObj.flag === false) {  
133 - loger.error(`会议密码校验-失败.`);  
134 - this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_CLASS_PASSWORD_WRONG);  
135 - return ; 85 + // Sass校验开始-->密码校验(如果需要密码)--->MD5校验----------------------------------------------------
  86 + passwordAndMd5Checking(_param) {
  87 + loger.log('2.开始Sass校验');
  88 + console.log(_param);
  89 + confInfo = _param;
  90 + // 密码校验
  91 + if (confInfo.passwordRequired === 'true' || confInfo.passwordRequired === true) {
  92 + this.sendPWDChecking();
  93 + return;
136 } 94 }
137 - if (rectObj.flag=== 'true'||rectObj.flag === true) {  
138 - loger.log(`会议密码校验-成功.`);  
139 - this.sendMD5Checking();  
140 - return;  
141 - }  
142 - loger.error(`会议密码校验-协议异常.`,rectObj);  
143 - this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_CLASS_JOIN_PROTOCOL);  
144 - })  
145 - .catch(err => {  
146 - loger.error(`会议密码校验-异常.状态码:${err}`);  
147 - this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_CLASS_JOIN_FAILED);  
148 - });  
149 - } 95 + // MD5校验
  96 + this.sendMD5Checking();
  97 + }
150 98
151 - //MD5校验-----------------------------------------------------------------------------------------  
152 - sendMD5Checking() {  
153 - let url = `http://${confInfo.portal}/3m/meeting/md5CheckMeeting.do?siteId=${confInfo.siteId}&meetingNumber=${confInfo.classId}&userId=${confInfo.userId}&userName=${confInfo.userName}&userType=${confInfo.userType}&nopassword=${confInfo.passwordRequired}&md5=${confInfo.md5}`;  
154 - loger.log('4.MD5校验', url);  
155 - fetch(url, {  
156 - timeout: 5000  
157 - })  
158 - .then(ret => {  
159 - if (ret.status === 200) {  
160 - return ret.json();  
161 - } else {  
162 - loger.error(`MD5校验-网络异常.状态码:${ret.status}`);  
163 - this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_CLASS_JOIN_NETWORK);  
164 - throw ''; 99 + // 入会密码校验---------------------------------------------------------------------------------------
  100 + sendPWDChecking() {
  101 + //let url = `http://${classInfo.portal}/3m/getCheckMeetinig.do?siteId=${classInfo.siteId}&classId=${classInfo.classId}&password=${classInfo.password}`;
  102 + /*
  103 + /3m/api/meeting/signIn.do
  104 + siteId 站点号
  105 + classId 课堂号(meetingNumber)
  106 + isTeacher 是否是老师:1 是 0 否
  107 + password 输入的密码
  108 + // 请求格式 http://112.126.80.182/3m/api/meeting/signIn.do?siteId=h5test&classId=526661904&password=111111&isTeacher=0
  109 + */
  110 + //判断是否是老师
  111 + let isTeacher = 0;
  112 + if (confInfo.userRole == ApeConsts.host) {
  113 + isTeacher = 1
165 } 114 }
166 - })  
167 - .then(ret => {  
168 - if (ret.flag == "true"||ret.flag == true) {  
169 - /* if (ret.h5_mcu_list) {  
170 - let server = ret.h5_mcu_list.split(";")[0];  
171 - confInfo.MCUServerIP = server.split(":")[0];  
172 - confInfo.MCUServerPort = server.split(":")[1];  
173 115
174 - GlobalConfig.MCUServerIP=confInfo.MCUServerIP;  
175 - GlobalConfig.MCUServerPort=confInfo.MCUServerPort;  
176 - }  
177 - confInfo.maxVideoChannels = ret.maxVideoChannels;  
178 - confInfo.maxAudioChannels = ret.maxAudioChannels;  
179 - confInfo.maxMediaChannels = confInfo.maxVideoChannels + confInfo.maxAudioChannels; 116 + let url = `http://${confInfo.portal}/3m/api/meeting/signIn.do?siteId=${confInfo.siteId}&classId=${confInfo.classId}&isTeacher=${isTeacher}&password=${confInfo.password}`;
  117 + loger.log('3.会议密码校验', url);
  118 + fetch(url, {
  119 + timeout: 5000
  120 + })
  121 + .then(ret => {
  122 + if (ret.status === 200) {
  123 + return ret.text();
  124 + } else {
  125 + loger.error(`会议密码校验-网络异常.状态码:${ret.status}`);
  126 + this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_JOIN_NETWORK);
  127 + throw '';
  128 + }
  129 + })
  130 + .then(ret => {
  131 + let rectObj = JSON.parse(ret);
  132 + if (rectObj.flag === 'false' || rectObj.flag === false) {
  133 + loger.error(`会议密码校验-失败.`);
  134 + this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_PASSWORD_WRONG);
  135 + return;
  136 + }
  137 + if (rectObj.flag === 'true' || rectObj.flag === true) {
  138 + loger.log(`会议密码校验-成功.`);
  139 + this.sendMD5Checking();
  140 + return;
  141 + }
  142 + loger.error(`会议密码校验-协议异常.`, rectObj);
  143 + this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_JOIN_PROTOCOL);
  144 + })
  145 + .catch(err => {
  146 + loger.error(`会议密码校验-异常.状态码:${err}`);
  147 + this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_JOIN_FAILED);
  148 + });
  149 + }
180 150
181 - GlobalConfig.maxVideoChannels=confInfo.maxVideoChannels;  
182 - GlobalConfig.maxAudioChannels=confInfo.maxAudioChannels;  
183 - GlobalConfig.maxMediaChannels=confInfo.maxMediaChannels;*/  
184 - loger.log('MD5校验完成');  
185 - console.log(ret);  
186 - this._emit(Sass.SUCCESS,ret);  
187 - } else {  
188 - loger.log('MD5校验-失败.');  
189 - this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_CLASS_MD5_WRONG); 151 + //MD5校验-----------------------------------------------------------------------------------------
  152 + sendMD5Checking() {
  153 + let url = `http://${confInfo.portal}/3m/meeting/md5CheckMeeting.do?siteId=${confInfo.siteId}&meetingNumber=${confInfo.classId}&userId=${confInfo.userId}&userName=${confInfo.userName}&userType=${confInfo.userType}&nopassword=${confInfo.passwordRequired}&md5=${confInfo.md5}`;
  154 + loger.log('4.MD5校验', url);
  155 + fetch(url, {
  156 + timeout: 5000
  157 + })
  158 + .then(ret => {
  159 + if (ret.status === 200) {
  160 + return ret.json();
  161 + } else {
  162 + loger.error(`MD5校验-网络异常.状态码:${ret.status}`);
  163 + this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_JOIN_NETWORK);
  164 + throw '';
  165 + }
  166 + })
  167 + .then(ret => {
  168 + if (ret.flag == "true" || ret.flag == true) {
  169 + /* if (ret.h5_mcu_list) {
  170 + let server = ret.h5_mcu_list.split(";")[0];
  171 + confInfo.MCUServerIP = server.split(":")[0];
  172 + confInfo.MCUServerPort = server.split(":")[1];
190 173
191 - }  
192 - })  
193 - .catch(err => {  
194 - loger.error(`MD5校验-异常.状态码:${err}`);  
195 - this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_CLASS_JOIN_FAILED);  
196 - });  
197 - } 174 + GlobalConfig.MCUServerIP=confInfo.MCUServerIP;
  175 + GlobalConfig.MCUServerPort=confInfo.MCUServerPort;
  176 + }
  177 + confInfo.maxVideoChannels = ret.maxVideoChannels;
  178 + confInfo.maxAudioChannels = ret.maxAudioChannels;
  179 + confInfo.maxMediaChannels = confInfo.maxVideoChannels + confInfo.maxAudioChannels;
198 180
199 - // 获取会议基本详情------------------------------------------------------------------------------------  
200 - getClassDetail() {  
201 - let url = `http://${confInfo.portal}/3m/meeting/getClassH5.do?classNumber=${confInfo.classId}`;  
202 - loger.log('获取Class详情.', url);  
203 - fetch(url, {  
204 - timeout: 5000  
205 - })  
206 - .then(ret => {  
207 - if (ret.ok) {  
208 - return ret.json();  
209 - } else {  
210 - loger.error(`获取Class详情-网络异常.状态码:${ret.status}`);  
211 - this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_GET_CLASS_DETAIL);  
212 - throw '';  
213 - }  
214 - })  
215 - .then(ret => {  
216 - if (ret.errorCode === 0) {  
217 - loger.log('获取Class详情完成');  
218 - this._emit(Sass.CLASS_GET_CLASS_DETAIL, ret);  
219 - } else {  
220 - loger.warn('获取Class详情失败.');  
221 - this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_GET_CLASS_DETAIL);  
222 - }  
223 - })  
224 - .catch(err => {  
225 - loger.error(`获取Class详情异常.状态码:${err}`);  
226 - this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_GET_CLASS_DETAIL);  
227 - });  
228 - } 181 + GlobalConfig.maxVideoChannels=confInfo.maxVideoChannels;
  182 + GlobalConfig.maxAudioChannels=confInfo.maxAudioChannels;
  183 + GlobalConfig.maxMediaChannels=confInfo.maxMediaChannels;*/
  184 + loger.log('MD5校验完成');
  185 + console.log(ret);
  186 + this._emit(Sass.SUCCESS, ret);
  187 + } else {
  188 + loger.log('MD5校验-失败.');
  189 + this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_MD5_WRONG);
229 190
230 - //获取课堂会议的完整信息--------------------------------------------------------------------------------  
231 - getClassParam(){  
232 - /*  
233 - 参数 (application/x-www-form-urlencoded):  
234 - 名称 类型 可选 默认值 说明  
235 - meetingNumber String 否 null 课堂号  
236 - timestamp String 否 null 时间戳  
237 - authId String 否 null 验证信息 md5(meetingNumber + timestamp)  
238 - 返回 (application/json):  
239 - 名称 类型 说明  
240 - code int 0 正常  
241 - 1 课堂号必填  
242 - 2 无效的课堂号  
243 - 3 没有对应的站点  
244 - 4 站点已过期  
245 - siteId String 站点号  
246 - meetingNumber String 课堂号 对应的是classId  
247 - */  
248 - var timestamp=new Date().getTime();  
249 - var authId=MD5(confInfo.classId+""+timestamp);//课堂号+时间戳 的字符串,转成MD5  
250 - let url = `http://${confInfo.portal}/3m/api/meeting/detail.do?meetingNumber=${confInfo.classId}&timestamp=${timestamp}&authId=${authId}`;  
251 - loger.log('5.获取课堂会议的完整信息 ');  
252 - console.log(url);  
253 - fetch(url, {  
254 - timeout: 5000  
255 - })  
256 - .then(ret => {  
257 - if (ret.ok) {  
258 - return ret.json();  
259 - } else {  
260 - loger.error(`获取课堂会议的完整信息-网络异常.状态码:${ret.status}`);  
261 - this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_GET_CLASS_PARAML); 191 + }
  192 + })
  193 + .catch(err => {
  194 + loger.error(`MD5校验-异常.状态码:${err}`);
  195 + this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_JOIN_FAILED);
  196 + });
  197 + }
262 198
263 - throw '';  
264 - } 199 + // 获取会议基本详情------------------------------------------------------------------------------------
  200 + getClassDetail() {
  201 + let url = `http://${confInfo.portal}/3m/meeting/getClassH5.do?classNumber=${confInfo.classId}`;
  202 + loger.log('获取Class详情.', url);
  203 + fetch(url, {
  204 + timeout: 5000
265 }) 205 })
266 - .then(ret => {  
267 - if (ret.code === 0) {  
268 - loger.log('获取课堂会议的完整信息完成');  
269 - this._emit(Sass.CLASS_GET_CLASS_PARAM, ret);  
270 - } else {  
271 - loger.warn('获取课堂会议的完整信息 失败.');  
272 - this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_GET_CLASS_PARAML);  
273 - } 206 + .then(ret => {
  207 + if (ret.ok) {
  208 + return ret.json();
  209 + } else {
  210 + loger.error(`获取Class详情-网络异常.状态码:${ret.status}`);
  211 + this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_GET_CLASS_DETAIL);
  212 + throw '';
  213 + }
  214 + })
  215 + .then(ret => {
  216 + if (ret.errorCode === 0) {
  217 + loger.log('获取Class详情完成');
  218 + this._emit(Sass.CLASS_GET_CLASS_DETAIL, ret);
  219 + } else {
  220 + loger.warn('获取Class详情失败.');
  221 + this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_GET_CLASS_DETAIL);
  222 + }
  223 + })
  224 + .catch(err => {
  225 + loger.error(`获取Class详情异常.状态码:${err}`);
  226 + this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_GET_CLASS_DETAIL);
  227 + });
  228 + }
  229 +
  230 + //获取课堂会议的完整信息--------------------------------------------------------------------------------
  231 + getClassParam() {
  232 + /*
  233 + 参数 (application/x-www-form-urlencoded):
  234 + 名称 类型 可选 默认值 说明
  235 + meetingNumber String 否 null 课堂号
  236 + timestamp String 否 null 时间戳
  237 + authId String 否 null 验证信息 md5(meetingNumber + timestamp)
  238 + 返回 (application/json):
  239 + 名称 类型 说明
  240 + code int 0 正常
  241 + 1 课堂号必填
  242 + 2 无效的课堂号
  243 + 3 没有对应的站点
  244 + 4 站点已过期
  245 + siteId String 站点号
  246 + meetingNumber String 课堂号 对应的是classId
  247 + */
  248 + var timestamp = new Date().getTime();
  249 + var authId = MD5(confInfo.classId + "" + timestamp);//课堂号+时间戳 的字符串,转成MD5
  250 + let url = `http://${confInfo.portal}/3m/api/meeting/detail.do?meetingNumber=${confInfo.classId}&timestamp=${timestamp}&authId=${authId}`;
  251 + loger.log('5.获取课堂会议的完整信息 ');
  252 + console.log(url);
  253 + fetch(url, {
  254 + timeout: 5000
274 }) 255 })
275 - .catch(err => {  
276 - loger.error(`获取课堂会议的完整信息异常.状态码:${err}`);  
277 - this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_GET_CLASS_PARAML);  
278 - });  
279 - } 256 + .then(ret => {
  257 + if (ret.ok) {
  258 + return ret.json();
  259 + } else {
  260 + loger.error(`获取课堂会议的完整信息-网络异常.状态码:${ret.status}`);
  261 + this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_GET_CLASS_PARAML);
  262 +
  263 + throw '';
  264 + }
  265 + })
  266 + .then(ret => {
  267 + if (ret.code === 0) {
  268 + loger.log('获取课堂会议的完整信息完成');
  269 + this._emit(Sass.CLASS_GET_CLASS_PARAM, ret);
  270 + } else {
  271 + loger.warn('获取课堂会议的完整信息 失败.');
  272 + this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_GET_CLASS_PARAML);
  273 + }
  274 + })
  275 + .catch(err => {
  276 + loger.error(`获取课堂会议的完整信息异常.状态码:${err}`);
  277 + this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_GET_CLASS_PARAML);
  278 + });
  279 + }
280 280
281 - //删除文档----------------------------------------------------------------------------------------------------- 281 + //删除文档-----------------------------------------------------------------------------------------------------
282 /* 282 /*
283 - 删除课堂中的文档,即删除课堂与文档的关联 283 + 删除课堂中的文档,即删除课堂与文档的关联
284 /api/document/deleteRelation.do 284 /api/document/deleteRelation.do
285 - 参数  
286 - docId 文档的唯一id  
287 - classId 课堂号  
288 - timestamp 时间戳  
289 - authId md5(docId+classId+timestamp) 285 + 参数
  286 + docId 文档的唯一id
  287 + classId 课堂号
  288 + timestamp 时间戳
  289 + authId md5(docId+classId+timestamp)
290 返回 (application/json): 290 返回 (application/json):
291 - 0 成功, 1 验证信息错误  
292 - */  
293 - sassDeleteDocument(_param){  
294 - var timestamp=new Date().getTime();  
295 - var authId=MD5(_param.docId+""+_param.classId+""+timestamp);// docId+classId+timestamp的字符串,转成MD5  
296 - let url = `http://${confInfo.portal}/3m/api/document/deleteRelation.do?docId=${_param.docId}&classId=${confInfo.classId}&timestamp=${timestamp}&authId=${authId}`;  
297 - loger.log('sassDeleteDocument', url);  
298 -  
299 - fetch(url, {  
300 - timeout: 5000  
301 - })  
302 - .then(ret => {  
303 - if (ret.ok) {  
304 - return ret.json();  
305 - } else {  
306 - loger.error(`sassDeleteDocument-网络异常.状态码:${ret.status}`);  
307 - this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_DOC_DELETE_FAILED); 291 + 0 成功, 1 验证信息错误
  292 + */
  293 + sassDeleteDocument(_param) {
  294 + var timestamp = new Date().getTime();
  295 + var authId = MD5(_param.docId + "" + _param.classId + "" + timestamp);// docId+classId+timestamp的字符串,转成MD5
  296 + let url = `http://${confInfo.portal}/3m/api/document/deleteRelation.do?docId=${_param.docId}&classId=${confInfo.classId}&timestamp=${timestamp}&authId=${authId}`;
  297 + loger.log('sassDeleteDocument', url);
308 298
309 - throw '';  
310 - }  
311 - })  
312 - .then(ret => {  
313 - if (ret.code === 0) {  
314 - loger.log('sassDeleteDocument 完成');  
315 - this._emit(Sass.DELETE_DOCUMENT_SUCCESS, _param);  
316 - } else {  
317 - loger.warn('sassDeleteDocumnt 失败.');  
318 - this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_DOC_DELETE_FAILED);  
319 - } 299 + fetch(url, {
  300 + timeout: 5000
320 }) 301 })
321 - .catch(err => {  
322 - loger.error(`sassDeleteDocument异常.状态码:${err}`);  
323 - this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_DOC_DELETE_FAILED);  
324 - });  
325 - } 302 + .then(ret => {
  303 + if (ret.ok) {
  304 + return ret.json();
  305 + } else {
  306 + loger.error(`sassDeleteDocument-网络异常.状态码:${ret.status}`);
  307 + this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_DOC_DELETE_FAILED);
326 308
327 - //保存课堂的当前信息-------------------------------------------------------------------------------------------------  
328 - /*保存课堂的当前信息,首次是插入,后面是更新  
329 - /api/meeting/saveInfo.do  
330 - 参数(application/x-www-form-urlencoded):  
331 - info Json字符串课堂信息,由前端自己维护  
332 - classId 课堂号  
333 - timestamp 时间戳  
334 - authId 做基本验证,md5(classId+timestamp) 309 + throw '';
  310 + }
  311 + })
  312 + .then(ret => {
  313 + if (ret.code === 0) {
  314 + loger.log('sassDeleteDocument 完成');
  315 + this._emit(Sass.DELETE_DOCUMENT_SUCCESS, _param);
  316 + } else {
  317 + loger.warn('sassDeleteDocumnt 失败.');
  318 + this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_DOC_DELETE_FAILED);
  319 + }
  320 + })
  321 + .catch(err => {
  322 + loger.error(`sassDeleteDocument异常.状态码:${err}`);
  323 + this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_DOC_DELETE_FAILED);
  324 + });
  325 + }
335 326
336 - 返回 (application/json):  
337 - code 0 成功 1 课堂号为空 2 无效的课堂号 3 验证信息错误*/ 327 + //保存课堂的当前信息-------------------------------------------------------------------------------------------------
  328 + /*保存课堂的当前信息,首次是插入,后面是更新
  329 + /api/meeting/saveInfo.do
  330 + 参数(application/x-www-form-urlencoded):
  331 + info Json字符串课堂信息,由前端自己维护
  332 + classId 课堂号
  333 + timestamp 时间戳
  334 + authId 做基本验证,md5(classId+timestamp)
338 335
339 - saveClassStatusInfo(_param){  
340 - //{"classStatusInfo":classStatusInfo}  
341 - var timestamp=new Date().getTime();  
342 - var authId=MD5(confInfo.classId+""+timestamp);// (classId+timestamp)的字符串,转成MD5  
343 - let classStatusInfo=JSON.stringify(_param.classStatusInfo);  
344 - let url = `http://${confInfo.portal}/3m/api/meeting/saveInfo.do`;  
345 - loger.log('saveClassStatusInfo', url);  
346 - fetch(url, {  
347 - method: 'POST',  
348 - headers: {  
349 - "Content-Type": "application/x-www-form-urlencoded"  
350 - },  
351 - body:`classId=${confInfo.classId}&info=${classStatusInfo}&timestamp=${timestamp}&authId=${authId}`,  
352 - timeout: 5000  
353 - })  
354 - .then(ret => {  
355 - if (ret.ok) {  
356 - return ret.json();  
357 - } else {  
358 - loger.error(`saveClassStatusInfo-网络异常.状态码:${ret.status}`);  
359 - //this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_DOC_DELETE_FAILED);  
360 - throw '';  
361 - }  
362 - })  
363 - .then(ret => {  
364 - if (ret.code === 0) {  
365 - loger.log('saveClassStatusInfo 完成');  
366 - this._emit(Sass.CLASS_SAVE_STATUS_INFO_SUCCESS, _param);  
367 - } else if (ret.code ===1) {  
368 - loger.log('saveClassStatusInfo 失败 课堂号为空');  
369 - }else if (ret.code === 2) {  
370 - loger.log('saveClassStatusInfo 失败 无效的课堂号');  
371 - }else if (ret.code === 3) {  
372 - loger.log('saveClassStatusInfo 失败 验证信息错误');  
373 - }else {  
374 - loger.warn('saveClassStatusInfo 失败.',ret);  
375 - //this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_DOC_DELETE_FAILED);  
376 - }  
377 - })  
378 - .catch(err => {  
379 - loger.error(`saveClassStatusInfo.状态码:${err}`);  
380 - //this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_DOC_DELETE_FAILED);  
381 - });  
382 - } 336 + 返回 (application/json):
  337 + code 0 成功 1 课堂号为空 2 无效的课堂号 3 验证信息错误*/
383 338
384 - /*  
385 - //用get的方式保存数据  
386 - saveClassStatusInfo(_param){  
387 - //{"classStatusInfo":"JSON数据的字符串"}  
388 - var timestamp=new Date().getTime();  
389 - var authId=MD5(confInfo.classId+""+timestamp);// (classId+timestamp)的字符串,转成MD5  
390 - let url = `http://${confInfo.portal}/3m/api/meeting/saveInfo.do?classId=${confInfo.classId}&info=${_param.classStatusInfo}&timestamp=${timestamp}&authId=${authId}`; 339 + saveClassStatusInfo(_param) {
  340 + //{"classStatusInfo":classStatusInfo}
  341 + var timestamp = new Date().getTime();
  342 + var authId = MD5(confInfo.classId + "" + timestamp);// (classId+timestamp)的字符串,转成MD5
  343 + let classStatusInfo = JSON.stringify(_param.classStatusInfo);
  344 + let url = `http://${confInfo.portal}/3m/api/meeting/saveInfo.do`;
391 loger.log('saveClassStatusInfo', url); 345 loger.log('saveClassStatusInfo', url);
392 -  
393 fetch(url, { 346 fetch(url, {
394 - timeout: 5000 347 + method: 'POST',
  348 + headers: {
  349 + "Content-Type": "application/x-www-form-urlencoded"
  350 + },
  351 + body: `classId=${confInfo.classId}&info=${classStatusInfo}&timestamp=${timestamp}&authId=${authId}`,
  352 + timeout: 5000
395 }) 353 })
396 .then(ret => { 354 .then(ret => {
397 - if (ret.ok) {  
398 - return ret.json();  
399 - } else {  
400 - loger.error(`saveClassStatusInfo-网络异常.状态码:${ret.status}`);  
401 - //this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_DOC_DELETE_FAILED);  
402 - throw '';  
403 - } 355 + if (ret.ok) {
  356 + return ret.json();
  357 + } else {
  358 + loger.error(`saveClassStatusInfo-网络异常.状态码:${ret.status}`);
  359 + //this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_DOC_DELETE_FAILED);
  360 + throw '';
  361 + }
404 }) 362 })
405 .then(ret => { 363 .then(ret => {
406 - if (ret.code === 0) {  
407 - loger.log('saveClassStatusInfo 完成');  
408 - this._emit(Sass.CLASS_SAVE_STATUS_INFO_SUCCESS, _param);  
409 - } else if (ret.code ===1) {  
410 - loger.log('saveClassStatusInfo 失败 课堂号为空');  
411 - }else if (ret.code === 2) {  
412 - loger.log('saveClassStatusInfo 失败 无效的课堂号');  
413 - }else if (ret.code === 3) {  
414 - loger.log('saveClassStatusInfo 失败 验证信息错误');  
415 - }else {  
416 - loger.warn('saveClassStatusInfo 失败.',ret); 364 + if (ret.code === 0) {
  365 + loger.log('saveClassStatusInfo 完成');
  366 + this._emit(Sass.CLASS_SAVE_STATUS_INFO_SUCCESS, _param);
  367 + } else if (ret.code === 1) {
  368 + loger.log('saveClassStatusInfo 失败 课堂号为空');
  369 + } else if (ret.code === 2) {
  370 + loger.log('saveClassStatusInfo 失败 无效的课堂号');
  371 + } else if (ret.code === 3) {
  372 + loger.log('saveClassStatusInfo 失败 验证信息错误');
  373 + } else {
  374 + loger.warn('saveClassStatusInfo 失败.', ret);
  375 + //this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_DOC_DELETE_FAILED);
  376 + }
  377 + })
  378 + .catch(err => {
  379 + loger.error(`saveClassStatusInfo.状态码:${err}`);
417 //this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_DOC_DELETE_FAILED); 380 //this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_DOC_DELETE_FAILED);
418 - } 381 + });
  382 + }
  383 +
  384 + //保存录制的信息,主要是录制文件的名称,必须和MCU录制的文件名相同
  385 + saveClassRecordContrlInfo(_param) {
  386 + loger.log('保存开始录制信息');
  387 + let key = "3mang123A";
  388 + let siteID = GlobalConfig.siteId;
  389 + let meetingID = GlobalConfig.classId;
  390 + let userID = GlobalConfig.userId;
  391 + let userName = GlobalConfig.userName;
  392 + let meetingName = GlobalConfig.className;
  393 + let startTime =GlobalConfig.classBeginTime;
  394 + let endTime = GlobalConfig.classEndTime;
  395 + let playUrl = "";
  396 + let streamName = GlobalConfig.recordFileName;
  397 + let confRecordFileName=GlobalConfig.recordFileName;
  398 + let downloadUrl = "";
  399 + let recordStatus = GlobalConfig.classStatus;
  400 + let recordTimestamp =GlobalConfig.classTimestamp;
  401 +
  402 + let timestamp = new Date().getTime();;
  403 + let authId = MD5(key + siteID + meetingID + timestamp);
  404 + let url = `http://${confInfo.portal}/3m/recordingMeeting/insertRecordingMeeting.do?siteID=${siteID}&meetingID=${meetingID}&userID=${userID}&userName=${userName}&meetingName=${meetingName}&startTime=${startTime}&endTime=${endTime}&playUrl=${playUrl}&streamName=${streamName}&downloadUrl=${downloadUrl}&configFile=${confRecordFileName}&timestamp=${timestamp}&recordTimestamp=${recordTimestamp}&authId=${authId}`;
  405 + loger.log('saveClassRecordContrlInfo', url);
  406 +
  407 + fetch(url, {
  408 + timeout: 5000
  409 + })
  410 + .then(ret => {
  411 + if (ret.ok) {
  412 + return ret.json();
  413 + } else {
  414 + loger.error(`保存开始录制信息-网络异常.状态码:${ret.status}`);
  415 + throw '';
  416 + }
  417 + })
  418 + .then(ret => {
  419 + if (ret.code === 0) {
  420 + loger.log('保存开始录制信息 完成');
  421 + this._emit(Sass.CLASS_SAVE_RECORD_INFO_SUCCESS, _param);
  422 + } else {
  423 + loger.warn('保存开始录制信息 失败.');
  424 + }
419 }) 425 })
420 .catch(err => { 426 .catch(err => {
421 - loger.error(`saveClassStatusInfo.状态码:${err}`);  
422 - //this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_DOC_DELETE_FAILED); 427 + loger.error(`保存开始录制信息异常.状态码:${err}`);
423 }); 428 });
424 - }*/  
425 429
  430 + }
426 431
427 } 432 }
428 433
429 Sass.prototype.SUCCESS = Sass.SUCCESS = 'Sass.success'; 434 Sass.prototype.SUCCESS = Sass.SUCCESS = 'Sass.success';
430 Sass.prototype.CLASS_INIT_SUCCESS = Sass.CLASS_INIT_SUCCESS = 'sass.class.init.success'; 435 Sass.prototype.CLASS_INIT_SUCCESS = Sass.CLASS_INIT_SUCCESS = 'sass.class.init.success';
431 -Sass.prototype.CLASS_GET_CLASS_PARAM= Sass.CLASS_GET_CLASS_PARAM = 'class.getClassParam.message';  
432 -Sass.prototype.CLASS_GET_CLASS_DETAIL= Sass.CLASS_GET_CLASS_DETAIL = 'class.getClassDetail.message';  
433 -Sass.prototype.DELETE_DOCUMENT_SUCCESS= Sass.DELETE_DOCUMENT_SUCCESS = 'class.deleteDocumentSuccess.message';//删除文档成功 436 +Sass.prototype.CLASS_GET_CLASS_PARAM = Sass.CLASS_GET_CLASS_PARAM = 'class.getClassParam.message';
  437 +Sass.prototype.CLASS_GET_CLASS_DETAIL = Sass.CLASS_GET_CLASS_DETAIL = 'class.getClassDetail.message';
  438 +Sass.prototype.DELETE_DOCUMENT_SUCCESS = Sass.DELETE_DOCUMENT_SUCCESS = 'class.deleteDocumentSuccess.message';//删除文档成功
  439 +
  440 +Sass.prototype.CLASS_SAVE_STATUS_INFO_SUCCESS = Sass.CLASS_SAVE_STATUS_INFO_SUCCESS = 'class.saveClassStatusInfoSuccess.message';//保存会议状态信息
  441 +Sass.prototype.CLASS_SAVE_RECORD_INFO_SUCCESS = Sass.CLASS_SAVE_RECORD_INFO_SUCCESS = 'class.saveClassRecordInfoSuccess.message';//保存录制会议信息
  442 +
434 443
435 -Sass.prototype.CLASS_SAVE_STATUS_INFO_SUCCESS= Sass.CLASS_SAVE_STATUS_INFO_SUCCESS = 'class.saveClassStatusInfoSuccess.message';//保存会议状态信息  
436 export default new Sass; 444 export default new Sass;
437 445
@@ -2,25 +2,13 @@ @@ -2,25 +2,13 @@
2 // 计时器 2 // 计时器
3 // ////////////////////////////////////////////////////////////////////////////// 3 // //////////////////////////////////////////////////////////////////////////////
4 4
5 -//import ApeConsts from './ApeConsts';  
6 -//import Loger from 'Loger';  
7 -//import MessageTypes from 'MessageTypes';  
8 -//import GlobalConfig from 'GlobalConfig';  
9 -//import EngineUtils from 'EngineUtils';  
10 -  
11 -//let loger = Loger.getLoger('MediaModule');  
12 -  
13 -/*let counter=0;  
14 -let callBackDelay=1;  
15 -let callBackFun;  
16 -let isStart=false;*/  
17 class TimerCounter { 5 class TimerCounter {
18 constructor() { 6 constructor() {
19 this.timer=0; 7 this.timer=0;
20 this.delay=1000; 8 this.delay=1000;
21 this.counter=0; 9 this.counter=0;
22 - this.callBackDelay=1;  
23 - this.callBackFun=null; 10 + this.callBackDelay=1;//回调间隔,单位(秒)
  11 + this.callBackFun=null;//回调函数
24 this.isStart=false; 12 this.isStart=false;
25 } 13 }
26 14
@@ -55,6 +55,7 @@ class ConferApe extends Ape { @@ -55,6 +55,7 @@ class ConferApe extends Ape {
55 this.on(pdu.RCPDU_SESSION_JOIN_RESPONSE, this._joinSessionHandler.bind(this)); 55 this.on(pdu.RCPDU_SESSION_JOIN_RESPONSE, this._joinSessionHandler.bind(this));
56 56
57 this.on(pdu.RCPDU_CONFERENCE_SEND_DATA_REQUEST, this.conferMsgComingHandler.bind(this));//这个是会议消息类型,flash里在使用这里不再使用,各个模块的消息由模块自己来处理 57 this.on(pdu.RCPDU_CONFERENCE_SEND_DATA_REQUEST, this.conferMsgComingHandler.bind(this));//这个是会议消息类型,flash里在使用这里不再使用,各个模块的消息由模块自己来处理
  58 + this.on(pdu.RCPDU_CONFERENCE_RECORD_REQUEST,this.onSendConferRecordRequestHandler.bind(this));//发送录制和停止录制消息
58 } 59 }
59 60
60 //加入会议 61 //加入会议
@@ -114,27 +115,87 @@ class ConferApe extends Ape { @@ -114,27 +115,87 @@ class ConferApe extends Ape {
114 } 115 }
115 */ 116 */
116 117
117 - let chatSendPdu = new pdu['RCConferenceSendDataRequestPdu'];  
118 - chatSendPdu.type = pdu.RCPDU_CONFERENCE_SEND_DATA_REQUEST;  
119 - chatSendPdu.initiator = this._classInfo.nodeId;//发起人  
120 - chatSendPdu.peer = parseInt(_messageInfo.to);//发送给谁,公聊的时候是0,私聊的时候是指定的用户id  
121 -  
122 - chatSendPdu.userData = this._rCArrayBufferUtil.strToUint8Array("h5" + _messageInfo.message);  
123 - //chatSendPdu.userData =UTF8.setBytesFromString(_messageInfo.message);  
124 - chatSendPdu.isPublic = true;  
125 - chatSendPdu.actionType=_messageInfo.actionType;  
126 - // if (!(chatSendPdu.isPublic || 0 === chatSendPdu.peer)) {  
127 - if (!chatSendPdu.isPublic && 0!=chatSendPdu.peer) { 118 + let conferSendPdu = new pdu['RCConferenceSendDataRequestPdu'];
  119 + conferSendPdu.type = pdu.RCPDU_CONFERENCE_SEND_DATA_REQUEST;
  120 + conferSendPdu.initiator = this._classInfo.nodeId;//发起人
  121 + conferSendPdu.peer = parseInt(_messageInfo.to);//发送给谁,公聊的时候是0,私聊的时候是指定的用户id
  122 +
  123 + conferSendPdu.userData = this._rCArrayBufferUtil.strToUint8Array("h5" + _messageInfo.message);
  124 + //conferSendPdu.userData =UTF8.setBytesFromString(_messageInfo.message);
  125 + conferSendPdu.isPublic = true;
  126 + conferSendPdu.actionType=_messageInfo.actionType;
  127 + // if (!(conferSendPdu.isPublic || 0 === conferSendPdu.peer)) {
  128 + if (!conferSendPdu.isPublic && 0!=conferSendPdu.peer) {
128 //发送给制定的人 129 //发送给制定的人
129 loger.log('发送私聊会议消息.'); 130 loger.log('发送私聊会议消息.');
130 - this.send(chatSendPdu); 131 + this.send(conferSendPdu);
131 } else { 132 } else {
132 //发送给所有人 133 //发送给所有人
133 loger.log('发送公聊会议消息.'); 134 loger.log('发送公聊会议消息.');
134 - this.sendChatUniform(chatSendPdu); 135 + this.sendChatUniform(conferSendPdu);
135 } 136 }
136 } 137 }
137 138
  139 + //发送录制或停止录制的消息,{"recordStatus":true};true为开始录制,false为停止录制
  140 + sendConferRecordMsg(_param) {
  141 + if(!this.mcu.connected){
  142 + loger.warn(GlobalConfig.getCurrentStatus());
  143 + return {"code": ApeConsts.RETURN_FAILED, "data": "已经断开连接"};
  144 + }
  145 + // to, message
  146 + loger.log('发送录制消息.', _param);
  147 +
  148 + if(_param==null){
  149 + loger.warn("控制录制状的消息发送失败,参数错误",_param);
  150 + return;
  151 + }
  152 +
  153 + /* message RCConferenceRecordRequestPdu {
  154 + optional uint32 initiator = 1; // 发起录像指令的node id
  155 + optional bool record = 2; // 录像指令 true:开始录像, false:停止录像
  156 + optional uint32 class_time = 3; // 课堂进行时间(秒)
  157 + optional string filename = 4; // 录像文件名称,filename中增加目录部分
  158 + }*/
  159 +
  160 + //保存当前的录制状态
  161 + GlobalConfig.recordStatus=_param.recordStatus||false;
  162 +
  163 + let conferRecordSendPdu = new pdu['RCConferenceRecordRequestPdu'];
  164 + conferRecordSendPdu.type = pdu.RCPDU_CONFERENCE_RECORD_REQUEST;
  165 + conferRecordSendPdu.peer = 0;//channel 为0
  166 + conferRecordSendPdu.isPublic = true;
  167 +
  168 + conferRecordSendPdu.initiator = this._classInfo.nodeId;//发起人
  169 + conferRecordSendPdu.record =GlobalConfig.recordStatus;
  170 + conferRecordSendPdu.classTime=GlobalConfig.classTimestamp;
  171 + conferRecordSendPdu.filename=GlobalConfig.recordFileName||GlobalConfig.classId+"_"+EngineUtils.creatTimestampYMD()+".rec";
  172 + this.sendChatUniform(conferRecordSendPdu);
  173 + }
  174 +
  175 + //开启录制
  176 + startRecord(){
  177 + loger.log('startRecord',"isHost",GlobalConfig.isHost,"recordStatus",GlobalConfig.recordStatus);
  178 + //如果是host
  179 + if(GlobalConfig.isHost){
  180 + GlobalConfig.classStopTime=EngineUtils.creatTimestampStr();
  181 + this.sendConferRecordMsg({"recordStatus":true});
  182 + this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE);
  183 + this._emit(MessageTypes.CLASS_RECORD_START);//会议开始录制
  184 + }
  185 + }
  186 +
  187 + //停止录制
  188 + stopRecord(){
  189 + loger.log('stopRecord',"isHost",GlobalConfig.isHost,"recordStatus",GlobalConfig.recordStatus);
  190 + //如果是host,并且当前正在录制中
  191 + if(GlobalConfig.isHost&&GlobalConfig.recordStatus){
  192 + GlobalConfig.classStopTime=EngineUtils.creatTimestampStr();
  193 + this.sendConferRecordMsg({"recordStatus":false});
  194 + this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE);
  195 + }
  196 + }
  197 +
  198 +
138 //主动离开会议,发送通知到服务器 199 //主动离开会议,发送通知到服务器
139 leaveClass(){ 200 leaveClass(){
140 let nodeInfoRecordPdu = this.mcu.mcuClassInfo.self; 201 let nodeInfoRecordPdu = this.mcu.mcuClassInfo.self;
@@ -169,32 +230,48 @@ class ConferApe extends Ape { @@ -169,32 +230,48 @@ class ConferApe extends Ape {
169 this.sendUniform(adapterPdu, true); 230 this.sendUniform(adapterPdu, true);
170 } 231 }
171 232
172 -  
173 //还原课堂状态 233 //还原课堂状态
174 restorClass(){ 234 restorClass(){
175 GlobalConfig.classTimestamp=0; 235 GlobalConfig.classTimestamp=0;
176 GlobalConfig.classStatus=ApeConsts.CLASS_STATUS_WAIT; 236 GlobalConfig.classStatus=ApeConsts.CLASS_STATUS_WAIT;
177 GlobalConfig.classStopTime=EngineUtils.creatTimestampStr(); 237 GlobalConfig.classStopTime=EngineUtils.creatTimestampStr();
  238 + this.stopRecord();
178 this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE); 239 this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE);
179 this.sendUpdaterClassStatusInfo({"actionType":0}); 240 this.sendUpdaterClassStatusInfo({"actionType":0});
  241 + loger.log('restorClass');
180 } 242 }
181 243
182 //开始上课 244 //开始上课
183 startClass(_param){ 245 startClass(_param){
184 - let timestamp=EngineUtils.creatTimestampStr();  
185 - GlobalConfig.classStopTime=timestamp; 246 + if(GlobalConfig.isHost){
186 247
187 - if(GlobalConfig.classStatus==ApeConsts.CLASS_STATUS_WAIT){  
188 - GlobalConfig.classStartTime=timestamp;  
189 - } 248 + let timestamp=EngineUtils.creatTimestampStr();
  249 + GlobalConfig.classStopTime=timestamp;
190 250
191 - GlobalConfig.classStatus=ApeConsts.CLASS_STATUS_STARTED;  
192 - //_param.actionType=ACTION_TYPE_1;  
193 - this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE);  
194 - this.sendUpdaterClassStatusInfo({"actionType":1}); 251 + //如果录制的文件名不存在,需要创建一个名字
  252 + let timestampYMD=EngineUtils.creatTimestampYMD();
  253 + GlobalConfig.recordFileName=GlobalConfig.recordFileName||
  254 + GlobalConfig.siteId+"/"+timestampYMD+"/"
  255 + +GlobalConfig.classId+"_"+timestampYMD+".rec";//4、文件名称 $RECORD_HOME/`site id`/`日期`/`filename` 例:/data/record/su/20161216/`filename`
  256 +
  257 + if(GlobalConfig.classStatus==ApeConsts.CLASS_STATUS_WAIT){
  258 + //之前是为开始状态,第一次点开始
  259 + GlobalConfig.classStartTime=timestamp;
  260 + }
  261 +
  262 + GlobalConfig.classStatus=ApeConsts.CLASS_STATUS_STARTED;
  263 + //开始录制
  264 + this.startRecord();
  265 + //会议状态改变
  266 + this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE);
  267 + //同步会议状态
  268 + this.sendUpdaterClassStatusInfo({"actionType":1});
195 269
196 - //开始计时  
197 - this.startTimerCounter(); 270 + //开始计时
  271 + this.startTimerCounter();
  272 + }else {
  273 + loger.warn('没有权限');
  274 + }
198 } 275 }
199 //暂停上课 276 //暂停上课
200 pauseClass(_param){ 277 pauseClass(_param){
@@ -205,7 +282,8 @@ class ConferApe extends Ape { @@ -205,7 +282,8 @@ class ConferApe extends Ape {
205 282
206 GlobalConfig.classStatus=ApeConsts.CLASS_STATUS_PAUSE; 283 GlobalConfig.classStatus=ApeConsts.CLASS_STATUS_PAUSE;
207 GlobalConfig.classStopTime=EngineUtils.creatTimestampStr(); 284 GlobalConfig.classStopTime=EngineUtils.creatTimestampStr();
208 - //_param.actionType=ACTION_TYPE_2; 285 +
  286 + this.stopRecord();
209 this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE); 287 this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE);
210 this.sendUpdaterClassStatusInfo({"actionType":2}); 288 this.sendUpdaterClassStatusInfo({"actionType":2});
211 this.stopTimerCounter(); 289 this.stopTimerCounter();
@@ -280,12 +358,15 @@ class ConferApe extends Ape { @@ -280,12 +358,15 @@ class ConferApe extends Ape {
280 /////收到消息处理///////////////////////////////////////////////////////////////////////////////// 358 /////收到消息处理/////////////////////////////////////////////////////////////////////////////////
281 //加入channel成功 359 //加入channel成功
282 onJoinChannelHandlerSuccess(){ 360 onJoinChannelHandlerSuccess(){
283 - loger.log('ConferApe onJoinChannelHandlerSuccess'); 361 + loger.log('ConferApe.onJoinChannelHandlerSuccess',GlobalConfig.classStatus);
284 this.timerCounter.addTimerCallBack(this.timerCounterUptate.bind(this),1); 362 this.timerCounter.addTimerCallBack(this.timerCounterUptate.bind(this),1);
285 //如果当前会议正在进行中,开启计时器 363 //如果当前会议正在进行中,开启计时器
286 if(GlobalConfig.classStatus==ApeConsts.CLASS_STATUS_STARTED){ 364 if(GlobalConfig.classStatus==ApeConsts.CLASS_STATUS_STARTED){
287 //开始计时 365 //开始计时
288 this.startTimerCounter(); 366 this.startTimerCounter();
  367 +
  368 + //如果是host ,开始录制
  369 + this.startRecord();
289 } 370 }
290 } 371 }
291 //开启计时器 372 //开启计时器
@@ -307,7 +388,7 @@ class ConferApe extends Ape { @@ -307,7 +388,7 @@ class ConferApe extends Ape {
307 return; 388 return;
308 } 389 }
309 GlobalConfig.classTimestamp=GlobalConfig.classTimestamp+1;//计时 390 GlobalConfig.classTimestamp=GlobalConfig.classTimestamp+1;//计时
310 - loger.log('课堂进行时间',GlobalConfig.classTimestamp); 391 + //loger.log('课堂进行时间',GlobalConfig.classTimestamp);
311 this._emit(MessageTypes.CLASS_UPDATE_TIMER,{"classTimestamp":GlobalConfig.classTimestamp}); 392 this._emit(MessageTypes.CLASS_UPDATE_TIMER,{"classTimestamp":GlobalConfig.classTimestamp});
312 393
313 if(GlobalConfig.classTimestamp%GlobalConfig.updateClassInfoDelay==0){ 394 if(GlobalConfig.classTimestamp%GlobalConfig.updateClassInfoDelay==0){
@@ -380,6 +461,17 @@ class ConferApe extends Ape { @@ -380,6 +461,17 @@ class ConferApe extends Ape {
380 } 461 }
381 } 462 }
382 463
  464 + onSendConferRecordRequestHandler(_data){
  465 + loger.log("onSendConferRecordRequestHandler");
  466 + try{
  467 + let conferRecordSendPdu =pdu['RCConferenceRecordRequestPdu'].decode(_data);
  468 + console.log(conferRecordSendPdu);
  469 + }catch (err){
  470 + loger.warn("onSendConferRecordRequestHandler err",err.message);
  471 + }
  472 +
  473 + }
  474 +
383 rosterInsertHandler(nodeId, nodeData) { 475 rosterInsertHandler(nodeId, nodeData) {
384 if(GlobalConfig.nodeId==nodeId){ 476 if(GlobalConfig.nodeId==nodeId){
385 loger.log("自己加入 rosterInsertHandler"); 477 loger.log("自己加入 rosterInsertHandler");
@@ -25,7 +25,7 @@ class MediaModule { @@ -25,7 +25,7 @@ class MediaModule {
25 _param.channelId == null|| _param.timestamp==null) 25 _param.channelId == null|| _param.timestamp==null)
26 { 26 {
27 loger.warn('getMediaPlayPath,参数错误', _param); 27 loger.warn('getMediaPlayPath,参数错误', _param);
28 - this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG); 28 + //this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG);
29 return {"code": ApeConsts.RETURN_FAILED, "data": ""}; 29 return {"code": ApeConsts.RETURN_FAILED, "data": ""};
30 } 30 }
31 31
@@ -88,6 +88,7 @@ RCPduPackage.RCPDU_AUDIO_SEND_DATA_REQUEST = 261; @@ -88,6 +88,7 @@ RCPduPackage.RCPDU_AUDIO_SEND_DATA_REQUEST = 261;
88 RCPduPackage.RCPDU_GIFT_SEND_DATA_REQUEST = 262; 88 RCPduPackage.RCPDU_GIFT_SEND_DATA_REQUEST = 262;
89 RCPduPackage.RCPDU_CHAT_SEND_DATA_REQUEST = 263; 89 RCPduPackage.RCPDU_CHAT_SEND_DATA_REQUEST = 263;
90 RCPduPackage.RCPDU_VOTING_POLL_RECORD = 265; 90 RCPduPackage.RCPDU_VOTING_POLL_RECORD = 265;
  91 +RCPduPackage.RCPDU_CONFERENCE_RECORD_REQUEST = 270;//录制和停止录制的协议号
91 92
92 RCPduPackage.RCPDU_REG_REQUEST_OBJ = 290; 93 RCPduPackage.RCPDU_REG_REQUEST_OBJ = 290;
93 RCPduPackage.RCPDU_REG_RESPONSE_OBJ = 291; 94 RCPduPackage.RCPDU_REG_RESPONSE_OBJ = 291;
@@ -121,6 +121,7 @@ enum RCPduType_E { @@ -121,6 +121,7 @@ enum RCPduType_E {
121 RCPDU_GIFT_SEND_DATA_REQUEST = 262; 121 RCPDU_GIFT_SEND_DATA_REQUEST = 262;
122 RCPDU_CHAT_SEND_DATA_REQUEST = 263; 122 RCPDU_CHAT_SEND_DATA_REQUEST = 263;
123 RCPDU_VOTING_POLL_RECORD = 265; 123 RCPDU_VOTING_POLL_RECORD = 265;
  124 + RCPDU_CONFERENCE_RECORD_REQUEST = 270;
124 125
125 // Registry resource request or response PDU 126 // Registry resource request or response PDU
126 RCPDU_REG_REQUEST_OBJ = 290; 127 RCPDU_REG_REQUEST_OBJ = 290;
@@ -924,6 +925,12 @@ message RCClassStatusInfoPdu { @@ -924,6 +925,12 @@ message RCClassStatusInfoPdu {
924 optional uint32 active_doc_cur_page=21;//当前激活的文档的当前页 925 optional uint32 active_doc_cur_page=21;//当前激活的文档的当前页
925 } 926 }
926 927
  928 +message RCConferenceRecordRequestPdu {
  929 + optional uint32 initiator = 1; // 发起录像指令的node id
  930 + optional bool record = 2; // 录像指令 true:开始录像, false:停止录像
  931 + optional uint32 class_time = 3; // 课堂进行时间(秒)
  932 + optional string filename = 4; // 录像文件名称,filename中增加目录部分
  933 +}
927 934
928 //end 935 //end
929 `; 936 `;