李勇

webRtc增加对移动连续推流和停止推流导致的无法收到流消息处理,解决收不到移动端视频的问题

@@ -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.9.3.20170919"; 65 + GlobalConfig.sdkVersion = "v2.10.4.20170920";
66 loger.warn("sdkVersion:" + GlobalConfig.sdkVersion); 66 loger.warn("sdkVersion:" + GlobalConfig.sdkVersion);
67 67
68 //设置 68 //设置
@@ -147,6 +147,7 @@ export default class MessageEntrance extends Emiter { @@ -147,6 +147,7 @@ export default class MessageEntrance extends Emiter {
147 //_confer_ape.on(MessageTypes.SWITCH_RTMP_PULL_IP, this._switchRtmpPullIpHandler.bind(this)); //MS 拉流地址动态选点 147 //_confer_ape.on(MessageTypes.SWITCH_RTMP_PULL_IP, this._switchRtmpPullIpHandler.bind(this)); //MS 拉流地址动态选点
148 //_confer_ape.on(MessageTypes.SWITCH_HLS_IP, this._switchHlsIpHandler.bind(this)); //MS HLS动态选点 148 //_confer_ape.on(MessageTypes.SWITCH_HLS_IP, this._switchHlsIpHandler.bind(this)); //MS HLS动态选点
149 _confer_ape.on(MessageTypes.STOP_ALL_MEDIA_PUBLISH, this._stopAllMediaPublishHandler.bind(this)); //课堂状态发生改变,需要停止当前的所有推流 149 _confer_ape.on(MessageTypes.STOP_ALL_MEDIA_PUBLISH, this._stopAllMediaPublishHandler.bind(this)); //课堂状态发生改变,需要停止当前的所有推流
  150 + _confer_ape.on(MessageTypes.CLASS_UPDATE_ROSTER,this._onRosterUpdateHandler.bind(this));
150 151
151 _chat_ape = new ChatApe(); 152 _chat_ape = new ChatApe();
152 _chat_ape.on('*', (type, data) => this._emit(type, data)); 153 _chat_ape.on('*', (type, data) => this._emit(type, data));
@@ -1359,6 +1360,22 @@ export default class MessageEntrance extends Emiter { @@ -1359,6 +1360,22 @@ export default class MessageEntrance extends Emiter {
1359 loger.log('课堂状态发生改变,需要停止当前的所有推流'); 1360 loger.log('课堂状态发生改变,需要停止当前的所有推流');
1360 this._emit(MessageTypes.MEDIA_STOP_PUBLISH); 1361 this._emit(MessageTypes.MEDIA_STOP_PUBLISH);
1361 } 1362 }
  1363 + //用更状态数据发送变更
  1364 + _onRosterUpdateHandler(_data){
  1365 + //数据无效/ios/android 不处理数据
  1366 + if(!_data||GlobalConfig.deviceType==1||GlobalConfig.deviceType==2){
  1367 + return;
  1368 + }
  1369 + let nodeData=_data.nodeData;
  1370 + //数据用户是pc或H5不处理
  1371 + if(!nodeData||nodeData.deviceType==0||nodeData.deviceType==3){
  1372 + return;
  1373 + }
  1374 + if(nodeData.openCamera>0&&_webRtc){
  1375 + loger.log("收到移动端用户数据更新,当前是开启摄像头状态,需要尝试添加一个远程视频");
  1376 + _webRtc.tryAddMobileStream(_data.nodeId);
  1377 + }
  1378 + }
1362 1379
1363 //手动切换MS -> {ip;"xxx.xx.xx","port":"xxxx"} 1380 //手动切换MS -> {ip;"xxx.xx.xx","port":"xxxx"}
1364 _switchMediaServer(_param) { 1381 _switchMediaServer(_param) {
@@ -1742,7 +1759,7 @@ export default class MessageEntrance extends Emiter { @@ -1742,7 +1759,7 @@ export default class MessageEntrance extends Emiter {
1742 GlobalConfig.className = _data.meetingName || ""; 1759 GlobalConfig.className = _data.meetingName || "";
1743 GlobalConfig.classBeginTime = _data.beginTime || ""; 1760 GlobalConfig.classBeginTime = _data.beginTime || "";
1744 GlobalConfig.classEndTime = _data.endTime || ""; 1761 GlobalConfig.classEndTime = _data.endTime || "";
1745 - 1762 + GlobalConfig.channelId = ""+GlobalConfig.siteId+"_"+GlobalConfig.classId;
1746 //sdk获取ip失败就使用saas返回的 1763 //sdk获取ip失败就使用saas返回的
1747 if(!GlobalConfig.userIp){ 1764 if(!GlobalConfig.userIp){
1748 GlobalConfig.userIp = _data.userIp || ""; 1765 GlobalConfig.userIp = _data.userIp || "";
@@ -33,6 +33,7 @@ class RecordPlayBackParse extends Emiter { @@ -33,6 +33,7 @@ class RecordPlayBackParse extends Emiter {
33 this._recordPlaybackMaxTime = 0;//录制回放的总时间 33 this._recordPlaybackMaxTime = 0;//录制回放的总时间
34 this._isReady = false;//录制回放是否已经准备完成 34 this._isReady = false;//录制回放是否已经准备完成
35 this._apes = {}; 35 this._apes = {};
  36 + this._videoApeBroadcastMssages={};//视频模块的广播消息
36 this.mediaChannleList={}; 37 this.mediaChannleList={};
37 this._conferApeMssages = {};//会议数据 38 this._conferApeMssages = {};//会议数据
38 this._chatApeMssages = {};//聊天数据 39 this._chatApeMssages = {};//聊天数据
@@ -134,7 +135,7 @@ class RecordPlayBackParse extends Emiter { @@ -134,7 +135,7 @@ class RecordPlayBackParse extends Emiter {
134 pduMsg.type = PduType.RCPDU_SEND_DATA_REQUEST; 135 pduMsg.type = PduType.RCPDU_SEND_DATA_REQUEST;
135 pduType = PduType.RCPDU_SEND_DATA_REQUEST; 136 pduType = PduType.RCPDU_SEND_DATA_REQUEST;
136 } 137 }
137 - //loger.log('pduType', pduType); 138 + loger.log('解析和储存->pduType', pduType);
138 switch (pduType) { 139 switch (pduType) {
139 case PduType.RCPDU_CONNECT_PROVIDER_RESPONSE: 140 case PduType.RCPDU_CONNECT_PROVIDER_RESPONSE:
140 //加入课堂请求返回数据处理 141 //加入课堂请求返回数据处理
@@ -160,7 +161,7 @@ class RecordPlayBackParse extends Emiter { @@ -160,7 +161,7 @@ class RecordPlayBackParse extends Emiter {
160 let ape = this._apes[pduMsg.sessionId]; 161 let ape = this._apes[pduMsg.sessionId];
161 let sessionLabel = ApeConsts(pduMsg.sessionId); 162 let sessionLabel = ApeConsts(pduMsg.sessionId);
162 //只做解析存储,不对外发送 163 //只做解析存储,不对外发送
163 - //loger.log('解析数据-timestamp->', timestamp, 'sessionId->', pduMsg.sessionId, 'sessionLabel->', sessionLabel); 164 + loger.log('解析数据-timestamp->', timestamp, 'sessionId->', pduMsg.sessionId, 'sessionLabel->', sessionLabel,"subType:"+pduMsg.subType);
164 switch (pduMsg.sessionId) { 165 switch (pduMsg.sessionId) {
165 case ApeConsts.CONFERENCE_SESSION_ID: 166 case ApeConsts.CONFERENCE_SESSION_ID:
166 this.saveParseData(data, timestamp, this._conferApeMssages); 167 this.saveParseData(data, timestamp, this._conferApeMssages);
@@ -375,7 +376,7 @@ class RecordPlayBackParse extends Emiter { @@ -375,7 +376,7 @@ class RecordPlayBackParse extends Emiter {
375 console.log('文档数据',this._docApeMssages); 376 console.log('文档数据',this._docApeMssages);
376 console.log('白板数据',this._whiteApeMssages); 377 console.log('白板数据',this._whiteApeMssages);
377 console.log('聊天数据',this._chatApeMssages); 378 console.log('聊天数据',this._chatApeMssages);
378 - 379 + console.log('视频模块广播消息',this._videoApeBroadcastMssages);
379 loger.log("录制回放数据解析完成,录制回放的总时间长为->", this._recordPlaybackMaxTime,"recordTimestamp:"+GlobalConfig.recordTimestamp); 380 loger.log("录制回放数据解析完成,录制回放的总时间长为->", this._recordPlaybackMaxTime,"recordTimestamp:"+GlobalConfig.recordTimestamp);
380 this._emit(RecordPlayBackParse.CLASS_JOIN_RECORD_PLAYBACK_SUCCESS, {"recordPlaybackMaxTime": this._recordPlaybackMaxTime}); 381 this._emit(RecordPlayBackParse.CLASS_JOIN_RECORD_PLAYBACK_SUCCESS, {"recordPlaybackMaxTime": this._recordPlaybackMaxTime});
381 } 382 }
@@ -638,9 +639,16 @@ class RecordPlayBackParse extends Emiter { @@ -638,9 +639,16 @@ class RecordPlayBackParse extends Emiter {
638 regItemSize = regItems.length; 639 regItemSize = regItems.length;
639 640
640 }catch (err){ 641 }catch (err){
641 - console.warn('RCAdapterPdu->unpack-error->type类型不对') 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 + }
642 return; 649 return;
643 } 650 }
  651 +
644 for (var i = 0; i < regItemSize; ++i) { 652 for (var i = 0; i < regItemSize; ++i) {
645 let regItem = regItems[i]; 653 let regItem = regItems[i];
646 let regItemType = regItem.type; 654 let regItemType = regItem.type;
@@ -707,6 +715,28 @@ class RecordPlayBackParse extends Emiter { @@ -707,6 +715,28 @@ class RecordPlayBackParse extends Emiter {
707 let tableDeleteData = pdu['RCRegistryTableDeleteItemPdu'].decode(user_data); 715 let tableDeleteData = pdu['RCRegistryTableDeleteItemPdu'].decode(user_data);
708 //console.log("tableDeleteData",object_id,tableDeleteData); 716 //console.log("tableDeleteData",object_id,tableDeleteData);
709 break; 717 break;
  718 + case pdu.RCPDU_SEND_VIDEO_DATA_REQUEST:
  719 + //视频模块的控制消息
  720 + try{
  721 + let videoReceivePdu = pdu['RCVideoSendDataRequestPdu'].decode(user_data);
  722 + if (videoReceivePdu == null) {
  723 + loger.warn("视频控制消息处理,收到的消息为null,不做处理");
  724 + return;
  725 + }
  726 + videoReceivePdu.data = this._rCArrayBufferUtil.uint8ArrayToStr(videoReceivePdu.data, 2);//开头两个字会乱码
  727 + let dataObj = {};
  728 + try {
  729 + dataObj = JSON.parse(videoReceivePdu.data);
  730 + } catch (err) {
  731 + loger.warn('控制消息->JSON转换失败');
  732 + dataObj = videoReceivePdu.data;
  733 + }
  734 + videoReceivePdu.data = dataObj;
  735 + this._videoApeBroadcastMssages[timestamp]={parseData:videoReceivePdu,byteData:data,timestamp: timestamp};
  736 + }catch (err){
  737 + loger.warn("RCPDU_SEND_VIDEO_DATA_REQUEST->err",err);
  738 + }
  739 + break;
710 case pdu.RCPDU_REG_TABLE_UPDATE_PDU: 740 case pdu.RCPDU_REG_TABLE_UPDATE_PDU:
711 let tableUpdateData = pdu['RCRegistryTableUpdateItemPdu'].decode(user_data); 741 let tableUpdateData = pdu['RCRegistryTableUpdateItemPdu'].decode(user_data);
712 let tableUpdateItems = tableUpdateData.items; 742 let tableUpdateItems = tableUpdateData.items;
@@ -30,7 +30,7 @@ class SystemConfig { @@ -30,7 +30,7 @@ class SystemConfig {
30 } 30 }
31 if (mdetect.isAndroid()) { 31 if (mdetect.isAndroid()) {
32 GlobalConfig.platform = "android"; //"android"; 32 GlobalConfig.platform = "android"; //"android";
33 - GlobalConfig.deviceType = 2; //"ios"; 33 + GlobalConfig.deviceType = 2; //"android";
34 } 34 }
35 35
36 //语言 36 //语言
@@ -35,6 +35,8 @@ class WebRtcApe extends Emiter { @@ -35,6 +35,8 @@ class WebRtcApe extends Emiter {
35 this.curCameraId = ""; 35 this.curCameraId = "";
36 this.curMicrophoneId = ""; 36 this.curMicrophoneId = "";
37 37
  38 + this.remoteVideoList={};//记录远程视频流
  39 +
38 this.videoResolution = "240P"; 40 this.videoResolution = "240P";
39 this.isOpenVideo = true; 41 this.isOpenVideo = true;
40 42
@@ -138,6 +140,10 @@ class WebRtcApe extends Emiter { @@ -138,6 +140,10 @@ class WebRtcApe extends Emiter {
138 }); 140 });
139 this.client.on('stream-subscribed', (evt)=> { 141 this.client.on('stream-subscribed', (evt)=> {
140 let stream = evt.stream; 142 let stream = evt.stream;
  143 + this.addRemoetStreamView(stream);
  144 + });
  145 + /* this.client.on('stream-subscribed', (evt)=> {
  146 + let stream = evt.stream;
141 if(stream){ 147 if(stream){
142 //let viewDiv=`<div id="${this.xdyRemote + stream.getId()}" style="width:${this.hostRemoteVideoWidth}px;height:${this.hostRemoteVideoHeight}px;"></div>`; 148 //let viewDiv=`<div id="${this.xdyRemote + stream.getId()}" style="width:${this.hostRemoteVideoWidth}px;height:${this.hostRemoteVideoHeight}px;"></div>`;
143 let uid=stream.getId(); 149 let uid=stream.getId();
@@ -148,6 +154,7 @@ class WebRtcApe extends Emiter { @@ -148,6 +154,7 @@ class WebRtcApe extends Emiter {
148 userName=user.name||""; 154 userName=user.name||"";
149 userRole=user.userRole; 155 userRole=user.userRole;
150 } 156 }
  157 +
151 let nameDiv=`<div style="width:98%;height:20px; position: absolute; z-index: 1;left: 4px;overflow:hidden;font-size: 14px; color: #cccccc;display:${this.nameDisplay}">${userName}</div>`; 158 let nameDiv=`<div style="width:98%;height:20px; position: absolute; z-index: 1;left: 4px;overflow:hidden;font-size: 14px; color: #cccccc;display:${this.nameDisplay}">${userName}</div>`;
152 159
153 if(userRole==ApeConsts.invisible){ 160 if(userRole==ApeConsts.invisible){
@@ -172,14 +179,21 @@ class WebRtcApe extends Emiter { @@ -172,14 +179,21 @@ class WebRtcApe extends Emiter {
172 stream.play(this.xdyRemote + stream.getId()); 179 stream.play(this.xdyRemote + stream.getId());
173 }catch (err){ 180 }catch (err){
174 } 181 }
  182 + if(user.deviceType==1||user.deviceType==2){
  183 + this.remoteVideoList[user.nodeId]=stream;
  184 + }
  185 + console.log("移动端远程视频流集合->",this.remoteVideoList);
175 } 186 }
176 - }); 187 + });*/
177 188
178 this.client.on('stream-removed', (evt)=> { 189 this.client.on('stream-removed', (evt)=> {
179 let stream = evt.stream; 190 let stream = evt.stream;
180 - stream.stop();  
181 - $('#' + this.xdyRemote + stream.getId()).remove();  
182 - loger.log("远程视频流已经断开:" + stream.getId()); 191 + if(stream){
  192 + stream.stop();
  193 + $('#' + this.xdyRemote + stream.getId()).remove();
  194 + loger.log("远程视频流已经断开:" + stream.getId());
  195 + }
  196 +
183 }); 197 });
184 198
185 this.client.on('peer-leave', (evt)=> { 199 this.client.on('peer-leave', (evt)=> {
@@ -196,6 +210,48 @@ class WebRtcApe extends Emiter { @@ -196,6 +210,48 @@ class WebRtcApe extends Emiter {
196 }); 210 });
197 211
198 } 212 }
  213 + addRemoetStreamView(stream){
  214 + if(stream){
  215 + //let viewDiv=`<div id="${this.xdyRemote + stream.getId()}" style="width:${this.hostRemoteVideoWidth}px;height:${this.hostRemoteVideoHeight}px;"></div>`;
  216 + let uid=stream.getId();
  217 + let user=GlobalConfig.getUserInfoFromeNodeId(uid);
  218 + let userName="";
  219 + let userRole=""
  220 + if(user){
  221 + userName=user.name||"";
  222 + userRole=user.userRole;
  223 + }
  224 + let nameDiv=`<div style="width:98%;height:20px; position: absolute; z-index: 1;left: 4px;overflow:hidden;font-size: 14px; color: #cccccc;display:${this.nameDisplay}">${userName}</div>`;
  225 +
  226 + if(userRole==ApeConsts.invisible){
  227 + //把远程视频添加到监课列表
  228 + loger.log("获取远程视频流成功->监课:"+userName+"->" + uid,new Date().getTime());
  229 + let viewDiv=`<div id="${this.xdyRemote + uid}" style="width:${this.invisibleVideoWidth}px;height:${this.invisibleVideoHeight}px;float: left;margin-right: 1px;pointer-events: none;">${nameDiv}</div>`;
  230 + $(this.invisibleViewId).append(viewDiv);
  231 + }else if(userRole==ApeConsts.host){
  232 + //把远程视图添加到老师列表
  233 + loger.log("获取远程视频流成功->老师:"+userName+"->" + uid,new Date().getTime());
  234 + let viewDiv=`<div id="${this.xdyRemote + uid}" style="width:${this.hostRemoteVideoWidth}px;height:${this.hostRemoteVideoHeight}px;float: left;margin-right: 1px;pointer-events: none;">${nameDiv}</div>`;
  235 + $(this.hostRemoteViewId).append(viewDiv);
  236 + }else {
  237 + //把视图添加到学生列表
  238 + loger.log("获取远程视频流成功->学生:"+userName+"->" +uid,new Date().getTime());
  239 + let viewDiv=`<div id="${this.xdyRemote + uid}" style="width:${this.normalRemoteVideoWidth}px;height:${this.normalRemoteVideoHeight}px;float: left;margin-right: 1px;pointer-events: none;">${nameDiv}</div>`;
  240 + $(this.normalRemoteViewId).append(viewDiv);
  241 + }
  242 + //播放视频,隐藏控制条
  243 + try{
  244 + $("bar_"+stream.getId()).hide();
  245 + stream.play(this.xdyRemote + stream.getId());
  246 + }catch (err){
  247 + }
  248 + if(user.deviceType==1||user.deviceType==2){
  249 + this.remoteVideoList[user.nodeId]=stream;
  250 + }
  251 + console.log("移动端远程视频流集合->",this.remoteVideoList);
  252 + }
  253 + }
  254 +
199 //重新添加远程视频 255 //重新添加远程视频
200 reAddRemoteStream(_stream){ 256 reAddRemoteStream(_stream){
201 if(!_stream){ 257 if(!_stream){
@@ -215,7 +271,6 @@ class WebRtcApe extends Emiter { @@ -215,7 +271,6 @@ class WebRtcApe extends Emiter {
215 return; 271 return;
216 } 272 }
217 if(err=="PEERCONNECTION_FAILED"){ 273 if(err=="PEERCONNECTION_FAILED"){
218 - //this.reAddRemoteStreamDelay=setTimeout(()=>{  
219 setTimeout(()=>{ 274 setTimeout(()=>{
220 loger.warn("连接远程的流失败->尝试重新连接",err); 275 loger.warn("连接远程的流失败->尝试重新连接",err);
221 this.reAddRemoteStream(_stream); 276 this.reAddRemoteStream(_stream);
@@ -224,6 +279,23 @@ class WebRtcApe extends Emiter { @@ -224,6 +279,23 @@ class WebRtcApe extends Emiter {
224 loger.warn("添加一个远程视频流->失败", err); } 279 loger.warn("添加一个远程视频流->失败", err); }
225 }); 280 });
226 } 281 }
  282 + //尝试添加远程的移动设备视频流
  283 + tryAddMobileStream(nodeId){
  284 + let stream=this.remoteVideoList[nodeId];
  285 + if(!stream){
  286 + return;
  287 + }
  288 + let remoteView=document.getElementById(this.xdyRemote +nodeId)
  289 + console.log("remoteView->",remoteView)
  290 + if(remoteView){
  291 + loger.log(nodeId+" 流已经添加显示,不需要再处理");
  292 + return;
  293 + }
  294 + if(stream) {
  295 + loger.log("收到移动端推流的消息,主动添加一个远程视频流");
  296 + this.addRemoetStreamView(stream);
  297 + }
  298 + }
227 299
228 joinChannel(_params) { 300 joinChannel(_params) {
229 this.channelId = _params.channelId||""; 301 this.channelId = _params.channelId||"";