正在显示
9 个修改的文件
包含
316 行增加
和
53 行删除
doc/nodeJs调用接口数据.txt
0 → 100644
| 1 | +1.开启录制(开始推流)共用一个接口 | ||
| 2 | +{ | ||
| 3 | + "appId": "xxxxxxx", | ||
| 4 | + "channel": "xxxxx_xxxx", | ||
| 5 | + "channelKey": "xxxxxx", | ||
| 6 | + "uid": 11111, | ||
| 7 | + "userId": "xxx", | ||
| 8 | + "userName": "xxx", | ||
| 9 | + "userRole": "xxx", | ||
| 10 | + "timestamp": "发送消息的的客户端时间戳", | ||
| 11 | + "recordTimestamp": "当前录制进行的时间戳(回放时使用)" | ||
| 12 | +} | ||
| 13 | + | ||
| 14 | +2.停止推流 | ||
| 15 | +{ | ||
| 16 | + "appId": "xxxxxxx", | ||
| 17 | + "channel": "xxxxx_xxxx", | ||
| 18 | + "channelKey": "xxxxxx", | ||
| 19 | + "uid": 11111, | ||
| 20 | + "userId": "xxx", | ||
| 21 | + "userName": "xxx", | ||
| 22 | + "userRole": "xxx", | ||
| 23 | + "timestamp": "发送消息的的客户端时间戳", | ||
| 24 | + "recordTimestamp": "当前录制进行的时间戳(回放时使用)" | ||
| 25 | +} | ||
| 26 | + | ||
| 27 | +3.停止录制 | ||
| 28 | +{ | ||
| 29 | + "appId": "xxxxxxx", | ||
| 30 | + "channel": "xxxxx_xxxx", | ||
| 31 | + "channelKey": "xxxxxx", | ||
| 32 | + "uid": 11111, | ||
| 33 | + "userId": "xxx", | ||
| 34 | + "userName": "xxx", | ||
| 35 | + "userRole": "xxx", | ||
| 36 | + "timestamp": "发送消息的的客户端时间戳", | ||
| 37 | + "recordTimestamp": "当前录制进行的时间戳(回放时使用)" | ||
| 38 | +} |
doc/录制.txt
0 → 100644
| 1 | +1.时间戳 recordTimestamp | ||
| 2 | +2.开始录制 startRecord | ||
| 3 | +3.停止录制 stopRecord | ||
| 4 | +4.录制权限 : | ||
| 5 | + A.第一个进入课堂的人开启录制; | ||
| 6 | + B.老师或最后一个离开课堂的人停止录制(课堂中没有人的时候10分钟后会停止录制) | ||
| 7 | + C.课堂录制时间更新:老师->1个人->多个人且没有老师的时候,按nodeId值最小的人来更新(人员离开或更新的时候需要选择一个人) | ||
| 8 | +5.课堂进行时间单独更新,和之前的逻辑一致,暂停和未开始的时候不记录; | ||
| 9 | +6.录制的时间更新只要开启录制之后就更新,10秒一次发送到Saas和MCU同步; | ||
| 10 | + | ||
| 11 | +7.刚进入的人员的录制时间从Saas获取默认的,MCU同步更新的时候更改为最新时间; | ||
| 12 | + | ||
| 13 | +8.计时器: | ||
| 14 | + updateTimer(){ | ||
| 15 | + //1.更新课堂时间,课堂开始上课的情况下更新 | ||
| 16 | + | ||
| 17 | + //2.更新录制时间,开启录制的情况下更新 | ||
| 18 | + | ||
| 19 | + } |
doc/日志上传.txt
0 → 100644
doc/腾讯云视频录制回调数据结构.txt
0 → 100644
| 1 | +[ | ||
| 2 | + { | ||
| 3 | + "app": "txlivepush.xuedianyun.com ", | ||
| 4 | + "appid": 1251457656, | ||
| 5 | + "appname": "live", | ||
| 6 | + "channel_id": "marketflashtest_1966232762_user_627052_983041_1506308668", | ||
| 7 | + "errcode": 0, | ||
| 8 | + "errmsg": "Maybe Error return Data no record!", | ||
| 9 | + "event_time": 1506308670, | ||
| 10 | + "event_type": 1, | ||
| 11 | + "idc_id": 34, | ||
| 12 | + "node": "125.39.15.21", | ||
| 13 | + "sequence": "7037777160241646428", | ||
| 14 | + "set_id": 2, | ||
| 15 | + "sign": "2eb0dcbd2ac7c3bade3089bb9aa999be", | ||
| 16 | + "stream_id": "marketflashtest_1966232762_user_627052_983041_1506308668", | ||
| 17 | + "stream_param": "bizid=11220&txSecret=339c4094afe1ae427e7bcd7f1f8d1128&txTime=59c91afc&record=hls&record_interval=5400", | ||
| 18 | + "t": 1506309271, | ||
| 19 | + "user_ip": "61.135.194.200" | ||
| 20 | + }, | ||
| 21 | + { | ||
| 22 | + "appid": 1251457656, | ||
| 23 | + "channel_id": "marketflashtest_1966232762_user_627052_983041_1506308688", | ||
| 24 | + "duration": 63, | ||
| 25 | + "end_time": 1506308756, | ||
| 26 | + "event_type": 100, | ||
| 27 | + "file_format": "hls", | ||
| 28 | + "file_id": "9031868223267109922", | ||
| 29 | + "file_size": 1349, | ||
| 30 | + "media_start_time": 2931, | ||
| 31 | + "record_file_id": "9031868223267109922", | ||
| 32 | + "sign": "21f73f7e75f9e75196d1b16a536eaff2", | ||
| 33 | + "start_time": 1506308695, | ||
| 34 | + "stream_id": "marketflashtest_1966232762_user_627052_983041_1506308688", | ||
| 35 | + "stream_param": "bizid=11220&txSecret=2a53a100442dbd5d660ff14edb4af853&txTime=59c91b10&record=hls&record_interval=5400", | ||
| 36 | + "t": 1506309357, | ||
| 37 | + "task_id": "479501701", | ||
| 38 | + "video_id": "5158_e9a44513cce1471790f8b0c50c983ccc", | ||
| 39 | + "video_url": "http://1251457656.vod2.myqcloud.com/9425a3e9vodgzp1251457656/6367ba459031868223267109922/playlist.m3u8 " | ||
| 40 | + }, | ||
| 41 | + { | ||
| 42 | + "app": "txlivepush.xuedianyun.com", | ||
| 43 | + "appid": 1251457656, | ||
| 44 | + "appname": "live", | ||
| 45 | + "channel_id": "marketflashtest_1966232762_user_627052_983041_1506308688", | ||
| 46 | + "errcode": 2, | ||
| 47 | + "errmsg": "recv rtmpcloseStream", | ||
| 48 | + "event_time": 1506308756, | ||
| 49 | + "event_type": 0, | ||
| 50 | + "idc_id": 34, | ||
| 51 | + "node": "125.39.15.21", | ||
| 52 | + "sequence": "7037777160241957731", | ||
| 53 | + "set_id": 2, | ||
| 54 | + "sign": "21f73f7e75f9e75196d1b16a536eaff2", | ||
| 55 | + "stream_id": "marketflashtest_1966232762_user_627052_983041_1506308688", | ||
| 56 | + "stream_param": "bizid=11220&txSecret=2a53a100442dbd5d660ff14edb4af853&txTime=59c91b10&record=hls&record_interval=5400", | ||
| 57 | + "t": 1506309357, | ||
| 58 | + "user_ip": "61.135.194.200" | ||
| 59 | + } | ||
| 60 | +] |
| @@ -62,7 +62,7 @@ export default class MessageEntrance extends Emiter { | @@ -62,7 +62,7 @@ export default class MessageEntrance extends Emiter { | ||
| 62 | constructor() { | 62 | constructor() { |
| 63 | super(); | 63 | super(); |
| 64 | //sdk 信息 | 64 | //sdk 信息 |
| 65 | - GlobalConfig.sdkVersion = "v2.10.7.20170921"; | 65 | + GlobalConfig.sdkVersion = "v2.11.13.20170925"; |
| 66 | loger.warn("sdkVersion:" + GlobalConfig.sdkVersion); | 66 | loger.warn("sdkVersion:" + GlobalConfig.sdkVersion); |
| 67 | 67 | ||
| 68 | //设置 | 68 | //设置 |
| @@ -493,7 +493,7 @@ export default class MessageEntrance extends Emiter { | @@ -493,7 +493,7 @@ export default class MessageEntrance extends Emiter { | ||
| 493 | if(!_data){ | 493 | if(!_data){ |
| 494 | return; | 494 | return; |
| 495 | } | 495 | } |
| 496 | - if(GlobalConfig.deviceType==1||GlobalConfig.deviceType==2||_data.nodeId==GlobalConfig.nodeId){ | 496 | + if(GlobalConfig.deviceType==1||GlobalConfig.deviceType==2||GlobalConfig.deviceType==3||_data.nodeId==GlobalConfig.nodeId){ |
| 497 | return; | 497 | return; |
| 498 | } | 498 | } |
| 499 | if(_webRtc){ | 499 | if(_webRtc){ |
| @@ -552,6 +552,7 @@ export default class MessageEntrance extends Emiter { | @@ -552,6 +552,7 @@ export default class MessageEntrance extends Emiter { | ||
| 552 | GlobalConfig.isRecordPlayBack = false; //设置为非录制回放状态 | 552 | GlobalConfig.isRecordPlayBack = false; //设置为非录制回放状态 |
| 553 | GlobalConfig.classId = parseInt(_param.classId); | 553 | GlobalConfig.classId = parseInt(_param.classId); |
| 554 | GlobalConfig.portal = _param.portal||""; | 554 | GlobalConfig.portal = _param.portal||""; |
| 555 | + GlobalConfig.openFlash=Boolean(_param.openFlash); | ||
| 555 | if(GlobalConfig.isHttps==true){ | 556 | if(GlobalConfig.isHttps==true){ |
| 556 | //https的时候替换所有80端口 | 557 | //https的时候替换所有80端口 |
| 557 | GlobalConfig.portal= GlobalConfig.replacePort(GlobalConfig.portal,":80",""); | 558 | GlobalConfig.portal= GlobalConfig.replacePort(GlobalConfig.portal,":80",""); |
| @@ -1292,11 +1293,13 @@ export default class MessageEntrance extends Emiter { | @@ -1292,11 +1293,13 @@ export default class MessageEntrance extends Emiter { | ||
| 1292 | //加入课堂成功,广播消息 | 1293 | //加入课堂成功,广播消息 |
| 1293 | this._emit(MessageTypes.CLASS_JOIN_SUCCESS, joinClassSuccessCallBackData); | 1294 | this._emit(MessageTypes.CLASS_JOIN_SUCCESS, joinClassSuccessCallBackData); |
| 1294 | 1295 | ||
| 1296 | + if(GlobalConfig.appId&&!GlobalConfig.openFlash){ | ||
| 1295 | setTimeout(()=>{ | 1297 | setTimeout(()=>{ |
| 1296 | //加入音视频通话模块,延迟一秒处理,因为视频需要根据用户列表信息来判断放的位置,太早的话用户列表没有数据 | 1298 | //加入音视频通话模块,延迟一秒处理,因为视频需要根据用户列表信息来判断放的位置,太早的话用户列表没有数据 |
| 1297 | this._joinChannel({channelId:GlobalConfig.channelId,channelKey:GlobalConfig.channelKey ,uid:GlobalConfig.userUid,info:""+GlobalConfig.userRole}); | 1299 | this._joinChannel({channelId:GlobalConfig.channelId,channelKey:GlobalConfig.channelKey ,uid:GlobalConfig.userUid,info:""+GlobalConfig.userRole}); |
| 1298 | },1000); | 1300 | },1000); |
| 1299 | } | 1301 | } |
| 1302 | + } | ||
| 1300 | 1303 | ||
| 1301 | //切换MCU ->_param->{reConnect:false} //reConnect(是否立即替换当前的ip并且重新连接) | 1304 | //切换MCU ->_param->{reConnect:false} //reConnect(是否立即替换当前的ip并且重新连接) |
| 1302 | _switchMcuIpHandler(_param) { | 1305 | _switchMcuIpHandler(_param) { |
| @@ -1889,14 +1892,22 @@ export default class MessageEntrance extends Emiter { | @@ -1889,14 +1892,22 @@ export default class MessageEntrance extends Emiter { | ||
| 1889 | loger.warn("开启录制回放流程失败->还未创建模块"); | 1892 | loger.warn("开启录制回放流程失败->还未创建模块"); |
| 1890 | } | 1893 | } |
| 1891 | } else { | 1894 | } else { |
| 1892 | - | ||
| 1893 | //初始化音视频通话sdk | 1895 | //初始化音视频通话sdk |
| 1896 | + if(GlobalConfig.appId&&!GlobalConfig.openFlash){ | ||
| 1897 | + loger.log("使用webRtc通话模式"); | ||
| 1898 | + //加入webRtc | ||
| 1894 | this._initWebRtcSdk({ | 1899 | this._initWebRtcSdk({ |
| 1895 | appId:GlobalConfig.appId | 1900 | appId:GlobalConfig.appId |
| 1896 | },()=>{ | 1901 | },()=>{ |
| 1897 | //音视频通话SDK初始化完成之后,根据用户的userIp获取信息,获取服务列表选点,选点测速完成后才加入MCU | 1902 | //音视频通话SDK初始化完成之后,根据用户的userIp获取信息,获取服务列表选点,选点测速完成后才加入MCU |
| 1898 | this.loadServerJsonAndgetUserIpInfo(); | 1903 | this.loadServerJsonAndgetUserIpInfo(); |
| 1899 | }); | 1904 | }); |
| 1905 | + }else { | ||
| 1906 | + //加入flash | ||
| 1907 | + loger.log("使用flash通话模式"); | ||
| 1908 | + this.loadServerJsonAndgetUserIpInfo(); | ||
| 1909 | + } | ||
| 1910 | + | ||
| 1900 | /* | 1911 | /* |
| 1901 | //根据用户的userIp获取信息,获取服务列表选点,选点测速完成后才加入MCU | 1912 | //根据用户的userIp获取信息,获取服务列表选点,选点测速完成后才加入MCU |
| 1902 | this.loadServerJsonAndgetUserIpInfo(); | 1913 | this.loadServerJsonAndgetUserIpInfo(); |
| @@ -371,6 +371,19 @@ class GlobalConfig { | @@ -371,6 +371,19 @@ class GlobalConfig { | ||
| 371 | } | 371 | } |
| 372 | 372 | ||
| 373 | } | 373 | } |
| 374 | + //通过IP查找IP对象 | ||
| 375 | + static getIpItem(ip,ipList){ | ||
| 376 | + if(!ip||!ipList) { | ||
| 377 | + return null; | ||
| 378 | + } | ||
| 379 | + for(let i=0;i<ipList.length;i++){ | ||
| 380 | + let item=ipList[i]; | ||
| 381 | + if(item&&item.ip==ip){ | ||
| 382 | + return item; | ||
| 383 | + } | ||
| 384 | + } | ||
| 385 | + return null; | ||
| 386 | + } | ||
| 374 | } | 387 | } |
| 375 | 388 | ||
| 376 | GlobalConfig.statusCode_0 = { "code": 0, message: "SDK 未初始化" }; | 389 | GlobalConfig.statusCode_0 = { "code": 0, message: "SDK 未初始化" }; |
| @@ -578,7 +591,7 @@ GlobalConfig.locationProtocol="http://";//https;或http: | @@ -578,7 +591,7 @@ GlobalConfig.locationProtocol="http://";//https;或http: | ||
| 578 | GlobalConfig.websocketProtocol="ws://";//wss或ws | 591 | GlobalConfig.websocketProtocol="ws://";//wss或ws |
| 579 | GlobalConfig.isHttps=false;//是否是https | 592 | GlobalConfig.isHttps=false;//是否是https |
| 580 | 593 | ||
| 581 | - | 594 | +GlobalConfig.openFlash=false;//使用flash通话模式。默认为false,使用的是webRtc |
| 582 | //webRtc | 595 | //webRtc |
| 583 | GlobalConfig.appId = ''; | 596 | GlobalConfig.appId = ''; |
| 584 | GlobalConfig.appCertificate = ""; | 597 | GlobalConfig.appCertificate = ""; |
| @@ -123,7 +123,6 @@ class RecordPlayBackParse extends Emiter { | @@ -123,7 +123,6 @@ class RecordPlayBackParse extends Emiter { | ||
| 123 | 123 | ||
| 124 | //解析和储存,录制回放EverSocket底层消息处理 data-数据;timestamp-数据对应的时间戳 | 124 | //解析和储存,录制回放EverSocket底层消息处理 data-数据;timestamp-数据对应的时间戳 |
| 125 | _parseSaveSocketMsgReceivedHandler(data, timestamp) { | 125 | _parseSaveSocketMsgReceivedHandler(data, timestamp) { |
| 126 | - | ||
| 127 | let pduMsg = pdu.decode_pdu(data); | 126 | let pduMsg = pdu.decode_pdu(data); |
| 128 | let pduType = pduMsg.get("type"); | 127 | let pduType = pduMsg.get("type"); |
| 129 | let pduData = pduMsg.get("data"); | 128 | let pduData = pduMsg.get("data"); |
| @@ -135,7 +134,7 @@ class RecordPlayBackParse extends Emiter { | @@ -135,7 +134,7 @@ class RecordPlayBackParse extends Emiter { | ||
| 135 | pduMsg.type = PduType.RCPDU_SEND_DATA_REQUEST; | 134 | pduMsg.type = PduType.RCPDU_SEND_DATA_REQUEST; |
| 136 | pduType = PduType.RCPDU_SEND_DATA_REQUEST; | 135 | pduType = PduType.RCPDU_SEND_DATA_REQUEST; |
| 137 | } | 136 | } |
| 138 | - loger.log('解析和储存->pduType', pduType); | 137 | + //loger.log('解析和储存->pduType', pduType); |
| 139 | switch (pduType) { | 138 | switch (pduType) { |
| 140 | case PduType.RCPDU_CONNECT_PROVIDER_RESPONSE: | 139 | case PduType.RCPDU_CONNECT_PROVIDER_RESPONSE: |
| 141 | //加入课堂请求返回数据处理 | 140 | //加入课堂请求返回数据处理 |
| @@ -161,7 +160,7 @@ class RecordPlayBackParse extends Emiter { | @@ -161,7 +160,7 @@ class RecordPlayBackParse extends Emiter { | ||
| 161 | let ape = this._apes[pduMsg.sessionId]; | 160 | let ape = this._apes[pduMsg.sessionId]; |
| 162 | let sessionLabel = ApeConsts(pduMsg.sessionId); | 161 | let sessionLabel = ApeConsts(pduMsg.sessionId); |
| 163 | //只做解析存储,不对外发送 | 162 | //只做解析存储,不对外发送 |
| 164 | - loger.log('解析数据-timestamp->', timestamp, 'sessionId->', pduMsg.sessionId, 'sessionLabel->', sessionLabel,"subType:"+pduMsg.subType); | 163 | + //loger.log('解析数据-timestamp->', timestamp, 'sessionId->', pduMsg.sessionId, 'sessionLabel->', sessionLabel,"subType:"+pduMsg.subType); |
| 165 | switch (pduMsg.sessionId) { | 164 | switch (pduMsg.sessionId) { |
| 166 | case ApeConsts.CONFERENCE_SESSION_ID: | 165 | case ApeConsts.CONFERENCE_SESSION_ID: |
| 167 | this.saveParseData(data, timestamp, this._conferApeMssages); | 166 | this.saveParseData(data, timestamp, this._conferApeMssages); |
| @@ -183,11 +182,12 @@ class RecordPlayBackParse extends Emiter { | @@ -183,11 +182,12 @@ class RecordPlayBackParse extends Emiter { | ||
| 183 | break; | 182 | break; |
| 184 | case ApeConsts.VIDEO_SESSION_ID: | 183 | case ApeConsts.VIDEO_SESSION_ID: |
| 185 | this.saveParseData(data, timestamp, this._videoApeMssages); | 184 | this.saveParseData(data, timestamp, this._videoApeMssages); |
| 186 | - this.unPackpduRegAdapterHandler(pduMsg.data,timestamp,data,ApeConsts.VIDEO_SESSION_ID) | 185 | + this.unpackVideoBroadcastMessage(pduMsg,timestamp,data); |
| 186 | + this.unPackpduRegAdapterHandler(pduMsg.data,timestamp,data,ApeConsts.VIDEO_SESSION_ID,pduMsg.subType) | ||
| 187 | break; | 187 | break; |
| 188 | case ApeConsts.AUDIO_SESSION_ID: | 188 | case ApeConsts.AUDIO_SESSION_ID: |
| 189 | this.saveParseData(data, timestamp, this._audioApeMssages); | 189 | this.saveParseData(data, timestamp, this._audioApeMssages); |
| 190 | - this.unPackpduRegAdapterHandler(pduMsg.data,timestamp,data,ApeConsts.AUDIO_SESSION_ID) | 190 | + this.unPackpduRegAdapterHandler(pduMsg.data,timestamp,data,ApeConsts.AUDIO_SESSION_ID,pduMsg.subType) |
| 191 | break; | 191 | break; |
| 192 | default: | 192 | default: |
| 193 | break; | 193 | break; |
| @@ -625,10 +625,62 @@ class RecordPlayBackParse extends Emiter { | @@ -625,10 +625,62 @@ class RecordPlayBackParse extends Emiter { | ||
| 625 | } | 625 | } |
| 626 | } | 626 | } |
| 627 | } | 627 | } |
| 628 | + //解析视频模块的广播消息 | ||
| 629 | + unpackVideoBroadcastMessage(pduMsg,timestamp,data){ | ||
| 630 | + //console.log("VIDEO_SESSION_ID-pduMsg",pduMsg); | ||
| 631 | + if(!pduMsg){ | ||
| 632 | + return; | ||
| 633 | + } | ||
| 634 | + if(pduMsg.subType!=pdu.RCPDU_SEND_VIDEO_DATA_REQUEST){ | ||
| 635 | + //视频广播消息,只处理501消息 | ||
| 636 | + return; | ||
| 637 | + } | ||
| 638 | + try{ | ||
| 639 | + let videoReceivePdu = pdu['RCVideoSendDataRequestPdu'].decode(pduMsg.data); | ||
| 640 | + if (videoReceivePdu == null) { | ||
| 641 | + loger.warn("视频模块广播消息-decode->失败"); | ||
| 642 | + return; | ||
| 643 | + } | ||
| 644 | + videoReceivePdu.data = ArrayBufferUtil.uint8ArrayToStr(videoReceivePdu.data, 2);//开头两个字会乱码 | ||
| 645 | + let dataObj = {}; | ||
| 646 | + try { | ||
| 647 | + dataObj = JSON.parse(videoReceivePdu.data); | ||
| 648 | + } catch (err) { | ||
| 649 | + loger.warn('视频模块广播消息->JSON转换失败'); | ||
| 650 | + dataObj = videoReceivePdu.data; | ||
| 651 | + } | ||
| 652 | + videoReceivePdu.data = dataObj; | ||
| 653 | + //actionType:40 | ||
| 654 | + //data :Object | ||
| 655 | + //fromNodeId :902994631 | ||
| 656 | + //toNodeId : 0 | ||
| 657 | + if(videoReceivePdu.actionType==40){ | ||
| 658 | + if(!this._videoApeBroadcastMssages[videoReceivePdu.fromNodeId]){ | ||
| 659 | + this._videoApeBroadcastMssages[videoReceivePdu.fromNodeId]={}; | ||
| 660 | + } | ||
| 661 | + /* | ||
| 662 | + //结构 | ||
| 663 | + { | ||
| 664 | + nodeId:{ | ||
| 665 | + 时间戳:{数据} | ||
| 666 | + }, | ||
| 667 | + nodeId:{ | ||
| 668 | + 时间戳:{数据} | ||
| 669 | + },..... | ||
| 670 | + }*/ | ||
| 671 | + | ||
| 672 | + this._videoApeBroadcastMssages[videoReceivePdu.fromNodeId][timestamp]={parseData:videoReceivePdu,byteData:data,timestamp: timestamp}; | ||
| 673 | + //this._videoApeBroadcastMssages[timestamp]={parseData:videoReceivePdu,byteData:data,timestamp: timestamp}; | ||
| 674 | + } | ||
| 675 | + | ||
| 676 | + }catch (err){ | ||
| 677 | + console.log("视频模块广播消息->解析失败",err.message); | ||
| 678 | + } | ||
| 679 | + } | ||
| 628 | 680 | ||
| 629 | //音视频的数据需要解析,然后按频道储存数据 | 681 | //音视频的数据需要解析,然后按频道储存数据 |
| 630 | // 解析pdu RCAdapterPdu的数据: regBuffer(RCAdapterPdu数据),timestamp(时间戳), data(mcu的原始数据) sessionId(类型) | 682 | // 解析pdu RCAdapterPdu的数据: regBuffer(RCAdapterPdu数据),timestamp(时间戳), data(mcu的原始数据) sessionId(类型) |
| 631 | - unPackpduRegAdapterHandler(regBuffer, timestamp, data, sessionId) { | 683 | + unPackpduRegAdapterHandler(regBuffer, timestamp, data, sessionId,subType) { |
| 632 | let regPdu; | 684 | let regPdu; |
| 633 | let regItems ; | 685 | let regItems ; |
| 634 | let regItemSize ; | 686 | let regItemSize ; |
| @@ -639,13 +691,7 @@ class RecordPlayBackParse extends Emiter { | @@ -639,13 +691,7 @@ class RecordPlayBackParse extends Emiter { | ||
| 639 | regItemSize = regItems.length; | 691 | regItemSize = regItems.length; |
| 640 | 692 | ||
| 641 | }catch (err){ | 693 | }catch (err){ |
| 642 | - console.warn('RCAdapterPdu->unpack-error->type类型不对'); | ||
| 643 | - try { | ||
| 644 | - let sendDataPdu = pdu['RCVideoSendDataRequestPdu'].decode(regBuffer); | ||
| 645 | - console.log("RCVideoSendDataRequestPdu",sendDataPdu); | ||
| 646 | - }catch (err){ | ||
| 647 | - | ||
| 648 | - } | 694 | + console.warn('RCAdapterPdu->unpack-error->type类型不对',"subType:"+subType); |
| 649 | return; | 695 | return; |
| 650 | } | 696 | } |
| 651 | 697 | ||
| @@ -670,7 +716,8 @@ class RecordPlayBackParse extends Emiter { | @@ -670,7 +716,8 @@ class RecordPlayBackParse extends Emiter { | ||
| 670 | let sub_type = regUpdatedItem.subType; | 716 | let sub_type = regUpdatedItem.subType; |
| 671 | let object_id = regUpdatedItem.objId; | 717 | let object_id = regUpdatedItem.objId; |
| 672 | let user_data = regUpdatedItem.userData; | 718 | let user_data = regUpdatedItem.userData; |
| 673 | - //console.log('RCRegistryUpdateObjPdu',regUpdatedItem) | 719 | + |
| 720 | + console.log('RCRegistryUpdateObjPdu',regUpdatedItem) | ||
| 674 | 721 | ||
| 675 | switch (sub_type) { | 722 | switch (sub_type) { |
| 676 | case pdu.RCPDU_REG_ROSTER_INSERT_PDU: | 723 | case pdu.RCPDU_REG_ROSTER_INSERT_PDU: |
| @@ -723,7 +770,7 @@ class RecordPlayBackParse extends Emiter { | @@ -723,7 +770,7 @@ class RecordPlayBackParse extends Emiter { | ||
| 723 | loger.warn("视频控制消息处理,收到的消息为null,不做处理"); | 770 | loger.warn("视频控制消息处理,收到的消息为null,不做处理"); |
| 724 | return; | 771 | return; |
| 725 | } | 772 | } |
| 726 | - videoReceivePdu.data = this._rCArrayBufferUtil.uint8ArrayToStr(videoReceivePdu.data, 2);//开头两个字会乱码 | 773 | + videoReceivePdu.data = ArrayBufferUtil.uint8ArrayToStr(videoReceivePdu.data, 2);//开头两个字会乱码 |
| 727 | let dataObj = {}; | 774 | let dataObj = {}; |
| 728 | try { | 775 | try { |
| 729 | dataObj = JSON.parse(videoReceivePdu.data); | 776 | dataObj = JSON.parse(videoReceivePdu.data); |
| @@ -52,28 +52,6 @@ class SystemConfig { | @@ -52,28 +52,6 @@ class SystemConfig { | ||
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | //获取浏览器和信息 | 54 | //获取浏览器和信息 |
| 55 | - /* static getBrowserInfo() { | ||
| 56 | - var Sys = {}; | ||
| 57 | - var ua = navigator.userAgent.toLowerCase(); | ||
| 58 | - var re = /(trident|msie|firefox|chrome|opera|version).*?([\d.]+)/; | ||
| 59 | - var m = ua.match(re); | ||
| 60 | - if (!m) m = ["version/1.0.0", "version", "1.0.0"]; | ||
| 61 | - Sys.explorer = m[1].replace(/version/, "'safari"); | ||
| 62 | - //判断是否是IE11 | ||
| 63 | - if (Sys.explorer == "trident") { | ||
| 64 | - Sys.explorer = "IE11" | ||
| 65 | - Sys.explorerVersion = "11.0"; | ||
| 66 | - } else if (Sys.explorer == "msie") { | ||
| 67 | - //IE | ||
| 68 | - Sys.explorer = "IE" | ||
| 69 | - Sys.explorerVersion = m[2]; | ||
| 70 | - } else { | ||
| 71 | - //非IE | ||
| 72 | - Sys.explorerVersion = m[2]; | ||
| 73 | - } | ||
| 74 | - return Sys; | ||
| 75 | - }*/ | ||
| 76 | - //获取浏览器和信息 | ||
| 77 | static getBrowserInfo() { | 55 | static getBrowserInfo() { |
| 78 | let Sys = {}; | 56 | let Sys = {}; |
| 79 | Sys.explorer = "unknow"; | 57 | Sys.explorer = "unknow"; |
| @@ -83,7 +61,7 @@ class SystemConfig { | @@ -83,7 +61,7 @@ class SystemConfig { | ||
| 83 | let re = /(trident|msie|firefox|chrome|version).*?([\d.]+)/; | 61 | let re = /(trident|msie|firefox|chrome|version).*?([\d.]+)/; |
| 84 | let m = ua.match(re); | 62 | let m = ua.match(re); |
| 85 | if (!m) m = ["version/1.0.0", "version", "1.0.0"]; | 63 | if (!m) m = ["version/1.0.0", "version", "1.0.0"]; |
| 86 | - Sys.explorer = m[1].replace(/version/, "'safari"); | 64 | + Sys.explorer = m[1].replace(/version/, "safari"); |
| 87 | //判断是否是IE11 | 65 | //判断是否是IE11 |
| 88 | if (Sys.explorer == "trident") { | 66 | if (Sys.explorer == "trident") { |
| 89 | Sys.explorer = "IE11" | 67 | Sys.explorer = "IE11" |
| @@ -7,6 +7,7 @@ import Loger from 'Loger'; | @@ -7,6 +7,7 @@ import Loger from 'Loger'; | ||
| 7 | import MessageTypes from 'MessageTypes'; | 7 | import MessageTypes from 'MessageTypes'; |
| 8 | import GlobalConfig from 'GlobalConfig'; | 8 | import GlobalConfig from 'GlobalConfig'; |
| 9 | import EngineUtils from 'EngineUtils'; | 9 | import EngineUtils from 'EngineUtils'; |
| 10 | +import MD5 from "md5"; | ||
| 10 | 11 | ||
| 11 | let loger = Loger.getLoger('MediaModule'); | 12 | let loger = Loger.getLoger('MediaModule'); |
| 12 | 13 | ||
| @@ -37,22 +38,36 @@ class MediaModule { | @@ -37,22 +38,36 @@ class MediaModule { | ||
| 37 | if (!GlobalConfig.MS_PLAY_HLS_IP) { | 38 | if (!GlobalConfig.MS_PLAY_HLS_IP) { |
| 38 | loger.error("HLS拉流地址地址无效"); | 39 | loger.error("HLS拉流地址地址无效"); |
| 39 | } | 40 | } |
| 40 | - //http://123.56.73.119:6001/live/h5dev_2106728010_8ab3b0ed5a3a9220015a3a958f0d0003_983041_1489113860/index.m3u8 | 41 | + /* //http://123.56.73.119:6001/live/h5dev_2106728010_8ab3b0ed5a3a9220015a3a958f0d0003_983041_1489113860/index.m3u8 |
| 41 | if (GlobalConfig.siteId == GlobalConfig.siteId_letv) { | 42 | if (GlobalConfig.siteId == GlobalConfig.siteId_letv) { |
| 42 | //乐视的hls地址规则 | 43 | //乐视的hls地址规则 |
| 43 | fileName = 'desc.m3u8'; | 44 | fileName = 'desc.m3u8'; |
| 44 | } else { | 45 | } else { |
| 45 | //fileName='index.m3u8'; | 46 | //fileName='index.m3u8'; |
| 46 | fileName = 'playlist.m3u8'; | 47 | fileName = 'playlist.m3u8'; |
| 47 | - } | 48 | + }*/ |
| 48 | port = (GlobalConfig.MS_PLAY_HLS_PORT == "" || GlobalConfig.MS_PLAY_HLS_PORT == null) ? "" : ":" + GlobalConfig.MS_PLAY_HLS_PORT; | 49 | port = (GlobalConfig.MS_PLAY_HLS_PORT == "" || GlobalConfig.MS_PLAY_HLS_PORT == null) ? "" : ":" + GlobalConfig.MS_PLAY_HLS_PORT; |
| 49 | //path = "http://" + GlobalConfig.MS_PLAY_HLS_IP | 50 | //path = "http://" + GlobalConfig.MS_PLAY_HLS_IP |
| 51 | + let ipItem=GlobalConfig.getIpItem(GlobalConfig.MS_PLAY_HLS_IP,GlobalConfig.hlsPullListFinal);//获取IP对象 | ||
| 52 | + let type="live";//默认值 | ||
| 53 | + let hlsSuffix="/playlist.m3u8"; | ||
| 54 | + if(ipItem){ | ||
| 55 | + type=ipItem.type||"live"; | ||
| 56 | + hlsSuffix=ipItem.hlsSuffix||"/playlist.m3u8"; | ||
| 57 | + } | ||
| 58 | + | ||
| 50 | path =GlobalConfig.locationProtocol + GlobalConfig.MS_PLAY_HLS_IP | 59 | path =GlobalConfig.locationProtocol + GlobalConfig.MS_PLAY_HLS_IP |
| 60 | + + port + "/"+type+"/" | ||
| 61 | + + _param.streamId | ||
| 62 | + +hlsSuffix;// | ||
| 63 | + //+ "/"+fileName;// | ||
| 64 | + | ||
| 65 | + /*path =GlobalConfig.locationProtocol + GlobalConfig.MS_PLAY_HLS_IP | ||
| 51 | + port + "/live/" | 66 | + port + "/live/" |
| 52 | + _param.streamId | 67 | + _param.streamId |
| 53 | + ".m3u8";// | 68 | + ".m3u8";// |
| 54 | //+ "/"+fileName;// | 69 | //+ "/"+fileName;// |
| 55 | - | 70 | + */ |
| 56 | 71 | ||
| 57 | } else { | 72 | } else { |
| 58 | //RTMP | 73 | //RTMP |
| @@ -60,12 +75,20 @@ class MediaModule { | @@ -60,12 +75,20 @@ class MediaModule { | ||
| 60 | loger.error("RTMP拉流地址地址无效"); | 75 | loger.error("RTMP拉流地址地址无效"); |
| 61 | } | 76 | } |
| 62 | port = (GlobalConfig.MS_PLAY_RTMP_PORT == "" || GlobalConfig.MS_PLAY_RTMP_PORT == null) ? "" : ":" + GlobalConfig.MS_PLAY_RTMP_PORT; | 77 | port = (GlobalConfig.MS_PLAY_RTMP_PORT == "" || GlobalConfig.MS_PLAY_RTMP_PORT == null) ? "" : ":" + GlobalConfig.MS_PLAY_RTMP_PORT; |
| 78 | + | ||
| 79 | + let ipItem=GlobalConfig.getIpItem(GlobalConfig.MS_PLAY_RTMP_IP,GlobalConfig.rtmpPullListFinal);//获取IP对象 | ||
| 80 | + let type="live";//默认值 | ||
| 81 | + if(ipItem){ | ||
| 82 | + type=ipItem.type||"live"; | ||
| 83 | + } | ||
| 63 | path = "rtmp://" + GlobalConfig.MS_PLAY_RTMP_IP | 84 | path = "rtmp://" + GlobalConfig.MS_PLAY_RTMP_IP |
| 64 | - + port + "/live/" | 85 | + + port + "/"+type+"/" |
| 65 | + _param.streamId; | 86 | + _param.streamId; |
| 66 | - } | ||
| 67 | - | 87 | + //path = "rtmp://" + GlobalConfig.MS_PLAY_RTMP_IP |
| 88 | + // + port + "/live/" | ||
| 89 | + // + _param.streamId; | ||
| 68 | 90 | ||
| 91 | + } | ||
| 69 | path = path.replace("::", ":");//如果ip和port之间有多的:需要去掉 | 92 | path = path.replace("::", ":");//如果ip和port之间有多的:需要去掉 |
| 70 | return {"code": ApeConsts.RETURN_SUCCESS, "data": "", "playUrl": path}; | 93 | return {"code": ApeConsts.RETURN_SUCCESS, "data": "", "playUrl": path}; |
| 71 | } | 94 | } |
| @@ -81,15 +104,41 @@ class MediaModule { | @@ -81,15 +104,41 @@ class MediaModule { | ||
| 81 | //M3U8 http://123.56.73.119:6001/live/h5dev_2106728010_8ab3b0ed5a3a9220015a3a958f0d0003_983041_1489113860/total.m3u8 | 104 | //M3U8 http://123.56.73.119:6001/live/h5dev_2106728010_8ab3b0ed5a3a9220015a3a958f0d0003_983041_1489113860/total.m3u8 |
| 82 | let port = (GlobalConfig.RS_RECORD_PLAY_PORT == "" || GlobalConfig.RS_RECORD_PLAY_PORT == null) ? "" : ":" + GlobalConfig.RS_RECORD_PLAY_PORT; | 105 | let port = (GlobalConfig.RS_RECORD_PLAY_PORT == "" || GlobalConfig.RS_RECORD_PLAY_PORT == null) ? "" : ":" + GlobalConfig.RS_RECORD_PLAY_PORT; |
| 83 | //let path = "http://" + GlobalConfig.RS_RECORD_PLAY_IP | 106 | //let path = "http://" + GlobalConfig.RS_RECORD_PLAY_IP |
| 107 | + let ipItem=GlobalConfig.getIpItem(GlobalConfig.RS_RECORD_PLAY_IP,GlobalConfig.rsPullListFinal);//获取IP对象 | ||
| 108 | + let type="live";//默认值 | ||
| 109 | + let rHlsSuffix="/total.m3u8"; | ||
| 110 | + if(ipItem){ | ||
| 111 | + type=ipItem.type||"live"; | ||
| 112 | + rHlsSuffix=ipItem.rHlsSuffix||"/total.m3u8"; | ||
| 113 | + } | ||
| 114 | + | ||
| 84 | let path =GlobalConfig.locationProtocol + GlobalConfig.RS_RECORD_PLAY_IP | 115 | let path =GlobalConfig.locationProtocol + GlobalConfig.RS_RECORD_PLAY_IP |
| 85 | - + port + "/live/" | 116 | + + port + "/"+type+"/" |
| 86 | + _param.streamId | 117 | + _param.streamId |
| 87 | - + "/total.m3u8"; | 118 | + +rHlsSuffix; |
| 88 | 119 | ||
| 89 | path = path.replace("::", ":");//如果ip和port之间有多的:需要去掉 | 120 | path = path.replace("::", ":");//如果ip和port之间有多的:需要去掉 |
| 90 | return {"code": ApeConsts.RETURN_SUCCESS, "data": "", "playUrl": path}; | 121 | return {"code": ApeConsts.RETURN_SUCCESS, "data": "", "playUrl": path}; |
| 91 | } | 122 | } |
| 92 | 123 | ||
| 124 | + //推流地址后缀拼接参数 | ||
| 125 | + setPublishSuffix(url,publishSuffix,streamId){ | ||
| 126 | + let newUrl= url; | ||
| 127 | + if(!url||!publishSuffix){ | ||
| 128 | + return newUrl; | ||
| 129 | + } | ||
| 130 | + //publishSuffix就是外部传入的key | ||
| 131 | + //txSecret = MD5(key + stream+txTime) | ||
| 132 | + let txTime=new Date().getTime()/1000+(12*60*60); | ||
| 133 | + //过去时间精确到分钟,转为16进制 | ||
| 134 | + txTime=parseInt(txTime); | ||
| 135 | + txTime=txTime.toString(16); | ||
| 136 | + let txSecret= MD5(publishSuffix + streamId+txTime); | ||
| 137 | + //rtmp://11220.livepush.myqcloud.com/live/11220_c5a1ea0bce?bizid=11220&txSecret=b1d8af72bf62366eef31cbb5dc5c8778&txTime=59C5337F | ||
| 138 | + newUrl=url +"?bizid=11220&txSecret="+txSecret+"&txTime="+txTime+"&record=hls&record_interval=5400"; | ||
| 139 | + loger.log("生成的推流地址->"+newUrl); | ||
| 140 | + return newUrl; | ||
| 141 | + } | ||
| 93 | //获取推流地址 | 142 | //获取推流地址 |
| 94 | getMediaPublishPath(_param) { | 143 | getMediaPublishPath(_param) { |
| 95 | loger.log('获取推流地址->'); | 144 | loger.log('获取推流地址->'); |
| @@ -116,8 +165,21 @@ class MediaModule { | @@ -116,8 +165,21 @@ class MediaModule { | ||
| 116 | + "_" + freeChannel + "_" + timestamp; | 165 | + "_" + freeChannel + "_" + timestamp; |
| 117 | 166 | ||
| 118 | //生成推流地址和推流数据(同步数据的时候用) | 167 | //生成推流地址和推流数据(同步数据的时候用) |
| 168 | + //let publishUrl = "rtmp://" + GlobalConfig.MS_PUBLISH_IP | ||
| 169 | + // + port + "/" + pubType + "/" + streamId; | ||
| 170 | + | ||
| 171 | + let ipItem=GlobalConfig.getIpItem(GlobalConfig.MS_PUBLISH_IP,GlobalConfig.msListFinal);//获取IP对象 | ||
| 172 | + let type="live";//默认值 | ||
| 173 | + if(ipItem){ | ||
| 174 | + type=ipItem.type||"live"; | ||
| 175 | + } | ||
| 119 | let publishUrl = "rtmp://" + GlobalConfig.MS_PUBLISH_IP | 176 | let publishUrl = "rtmp://" + GlobalConfig.MS_PUBLISH_IP |
| 120 | - + port + "/" + pubType + "/" + streamId; | 177 | + + port + "/"+ type + "/" + streamId; |
| 178 | + | ||
| 179 | + //设置推流地址的后缀,有的推流地址需要在地址后面加一些参数 | ||
| 180 | + if(ipItem&&ipItem.publishSuffix){ | ||
| 181 | + publishUrl=this.setPublishSuffix(publishUrl,ipItem.publishSuffix,streamId); | ||
| 182 | + } | ||
| 121 | 183 | ||
| 122 | publishUrl = publishUrl.replace("::", ":");//如果ip和port之间有多的:需要去掉 | 184 | publishUrl = publishUrl.replace("::", ":");//如果ip和port之间有多的:需要去掉 |
| 123 | this.needPublishMediaChannel[publishUrl] = { | 185 | this.needPublishMediaChannel[publishUrl] = { |
| @@ -169,9 +231,21 @@ class MediaModule { | @@ -169,9 +231,21 @@ class MediaModule { | ||
| 169 | + "_" + freeChannel + "_" + timestamp; | 231 | + "_" + freeChannel + "_" + timestamp; |
| 170 | 232 | ||
| 171 | //生成推流地址和推流数据(同步数据的时候用) | 233 | //生成推流地址和推流数据(同步数据的时候用) |
| 234 | + //let publishUrl = "rtmp://" + GlobalConfig.MS_PUBLISH_IP | ||
| 235 | + // + port + "/" + pubType + "/" + streamId; | ||
| 236 | + | ||
| 237 | + let ipItem=GlobalConfig.getIpItem(GlobalConfig.MS_PUBLISH_IP,GlobalConfig.msListFinal);//获取IP对象 | ||
| 238 | + let type="live";//默认值 | ||
| 239 | + if(ipItem){ | ||
| 240 | + type=ipItem.type||"live"; | ||
| 241 | + } | ||
| 172 | let publishUrl = "rtmp://" + GlobalConfig.MS_PUBLISH_IP | 242 | let publishUrl = "rtmp://" + GlobalConfig.MS_PUBLISH_IP |
| 173 | - + port + "/" + pubType + "/" + streamId; | 243 | + + port + "/"+ type + "/" + streamId; |
| 174 | 244 | ||
| 245 | + //设置推流地址的后缀,有的推流地址需要在地址后面加一些参数 | ||
| 246 | + if(ipItem&&ipItem.publishSuffix){ | ||
| 247 | + publishUrl=this.setPublishSuffix(publishUrl,ipItem.publishSuffix,streamId); | ||
| 248 | + } | ||
| 175 | publishUrl = publishUrl.replace("::", ":");//如果ip和port之间有多的:需要去掉 | 249 | publishUrl = publishUrl.replace("::", ":");//如果ip和port之间有多的:需要去掉 |
| 176 | this.needPublishMediaChannel[publishUrl] = { | 250 | this.needPublishMediaChannel[publishUrl] = { |
| 177 | "channelId": freeChannel, | 251 | "channelId": freeChannel, |
| @@ -213,8 +287,20 @@ class MediaModule { | @@ -213,8 +287,20 @@ class MediaModule { | ||
| 213 | + "_" + shareChannel + "_" + timestamp; | 287 | + "_" + shareChannel + "_" + timestamp; |
| 214 | 288 | ||
| 215 | //生成推流地址和推流数据(同步数据的时候用) | 289 | //生成推流地址和推流数据(同步数据的时候用) |
| 290 | + //let publishUrl = "rtmp://" + GlobalConfig.MS_PUBLISH_IP | ||
| 291 | + // + port + "/" + pubType + "/" + streamId; | ||
| 292 | + let ipItem=GlobalConfig.getIpItem(GlobalConfig.MS_PUBLISH_IP,GlobalConfig.msListFinal);//获取IP对象 | ||
| 293 | + let type="live";//默认值 | ||
| 294 | + if(ipItem){ | ||
| 295 | + type=ipItem.type||"live"; | ||
| 296 | + } | ||
| 216 | let publishUrl = "rtmp://" + GlobalConfig.MS_PUBLISH_IP | 297 | let publishUrl = "rtmp://" + GlobalConfig.MS_PUBLISH_IP |
| 217 | - + port + "/" + pubType + "/" + streamId; | 298 | + + port + "/"+ type + "/" + streamId; |
| 299 | + | ||
| 300 | + //设置推流地址的后缀,有的推流地址需要在地址后面加一些参数 | ||
| 301 | + if(ipItem&&ipItem.publishSuffix){ | ||
| 302 | + publishUrl=this.setPublishSuffix(publishUrl,ipItem.publishSuffix,streamId); | ||
| 303 | + } | ||
| 218 | 304 | ||
| 219 | publishUrl = publishUrl.replace("::", ":");//如果ip和port之间有多的:需要去掉 | 305 | publishUrl = publishUrl.replace("::", ":");//如果ip和port之间有多的:需要去掉 |
| 220 | /* this.needPublishMediaChannel[publishUrl]={ | 306 | /* this.needPublishMediaChannel[publishUrl]={ |
-
请 注册 或 登录 后发表评论