李勇

1.视频音频模块 获取播放地址增加录制回放的地址和发起人的nodeId

2.录制回放模块增加seek的逻辑
此 diff 太大无法显示。
@@ -421,14 +421,14 @@ export default class MessageEntrance extends Emiter { @@ -421,14 +421,14 @@ export default class MessageEntrance extends Emiter {
421 GlobalConfig.MCUServerPort = _data.mcuList[0].port || ""; 421 GlobalConfig.MCUServerPort = _data.mcuList[0].port || "";
422 } 422 }
423 423
424 - //视频推流播流地址 424 + //上课中视频推流播流地址
425 if (_data.msList&&_data.msList.length>0) { 425 if (_data.msList&&_data.msList.length>0) {
426 //MS地址默认使用第一个 426 //MS地址默认使用第一个
427 GlobalConfig.MSServerIP = _data.msList[0].ip || ""; 427 GlobalConfig.MSServerIP = _data.msList[0].ip || "";
428 GlobalConfig.MSServerPort = _data.msList[0].port || ""; 428 GlobalConfig.MSServerPort = _data.msList[0].port || "";
429 } 429 }
430 430
431 - //m3u8播流地址 431 + //录制回放时m3u8播流地址
432 if (_data.rsList&&_data.rsList.length>0) { 432 if (_data.rsList&&_data.rsList.length>0) {
433 //RS地址默认使用第一个 433 //RS地址默认使用第一个
434 GlobalConfig.RSServerIP = _data.rsList[0].ip || ""; 434 GlobalConfig.RSServerIP = _data.rsList[0].ip || "";
@@ -323,7 +323,7 @@ GlobalConfig.mcuList=[];//录制服务器地址集合 @@ -323,7 +323,7 @@ GlobalConfig.mcuList=[];//录制服务器地址集合
323 GlobalConfig.msList=[];//ms服务器地址集合 323 GlobalConfig.msList=[];//ms服务器地址集合
324 GlobalConfig.musicList=[];//music服务器地址集合 324 GlobalConfig.musicList=[];//music服务器地址集合
325 GlobalConfig.musicListPrepare=[];//提提前上传的music集合 325 GlobalConfig.musicListPrepare=[];//提提前上传的music集合
326 -GlobalConfig.rsList=[]; 326 +GlobalConfig.rsList=[];//录制回放中视频点播地址
327 327
328 328
329 GlobalConfig.country ="";//国家 329 GlobalConfig.country ="";//国家
@@ -32,6 +32,7 @@ class RecordPlayBackParse extends Emiter { @@ -32,6 +32,7 @@ class RecordPlayBackParse extends Emiter {
32 console.log(parseBuffer); 32 console.log(parseBuffer);
33 this._recordPlaybackTimestamp = 0;//回放的时间 33 this._recordPlaybackTimestamp = 0;//回放的时间
34 this._recordPlaybackMaxTime = 0;//录制回放的总时间 34 this._recordPlaybackMaxTime = 0;//录制回放的总时间
  35 + this._isReady=false;//录制回放是否已经准备完成
35 this._apes = {}; 36 this._apes = {};
36 this._messages = {}; 37 this._messages = {};
37 this._timerCounter = new TimerCounter();//计时器 38 this._timerCounter = new TimerCounter();//计时器
@@ -109,7 +110,7 @@ class RecordPlayBackParse extends Emiter { @@ -109,7 +110,7 @@ class RecordPlayBackParse extends Emiter {
109 this._recordPlaybackTimestamp = this._recordPlaybackTimestamp + 1;//计时 110 this._recordPlaybackTimestamp = this._recordPlaybackTimestamp + 1;//计时
110 if(this._recordPlaybackTimestamp>=this._recordPlaybackMaxTime){ 111 if(this._recordPlaybackTimestamp>=this._recordPlaybackMaxTime){
111 this._stopTimerCounter(); 112 this._stopTimerCounter();
112 - loger.log("录制结束...当前时间->", this._recordPlaybackTimestamp," 总时间->",this._recordPlaybackMaxTime); 113 + loger.log("录制回放结束...当前时间->", this._recordPlaybackTimestamp," 总时间->",this._recordPlaybackMaxTime);
113 this._emit(MessageTypes.RECORD_PLAYBACK_UPDATE,{"status":STOP}); 114 this._emit(MessageTypes.RECORD_PLAYBACK_UPDATE,{"status":STOP});
114 return; 115 return;
115 } 116 }
@@ -123,6 +124,7 @@ class RecordPlayBackParse extends Emiter { @@ -123,6 +124,7 @@ class RecordPlayBackParse extends Emiter {
123 124
124 //加载录制文件 125 //加载录制文件
125 readyRecordPlay() { 126 readyRecordPlay() {
  127 + this._isReady=false;
126 this._stopTimerCounter(); 128 this._stopTimerCounter();
127 loger.log("读取回放数据"); 129 loger.log("读取回放数据");
128 //let url = `http://123.56.73.119:80/h5dev/20170306/1357644520_20170306.rec`; 130 //let url = `http://123.56.73.119:80/h5dev/20170306/1357644520_20170306.rec`;
@@ -191,6 +193,7 @@ class RecordPlayBackParse extends Emiter { @@ -191,6 +193,7 @@ class RecordPlayBackParse extends Emiter {
191 this._recordPlaybackMaxTime=timestamp; 193 this._recordPlaybackMaxTime=timestamp;
192 } 194 }
193 this._recordPlaybackTimestamp=0; 195 this._recordPlaybackTimestamp=0;
  196 + this._isReady=true;
194 this._stopTimerCounter(); 197 this._stopTimerCounter();
195 198
196 GlobalConfig.recordPlaybackMaxTime=this._recordPlaybackMaxTime; 199 GlobalConfig.recordPlaybackMaxTime=this._recordPlaybackMaxTime;
@@ -204,7 +207,6 @@ class RecordPlayBackParse extends Emiter { @@ -204,7 +207,6 @@ class RecordPlayBackParse extends Emiter {
204 let msgDataArr=this._messages[_timestamp]; 207 let msgDataArr=this._messages[_timestamp];
205 if(!msgDataArr){ 208 if(!msgDataArr){
206 //没有数据,需要查找当前时间点属于哪一个时间戳关键帧 209 //没有数据,需要查找当前时间点属于哪一个时间戳关键帧
207 -  
208 }else { 210 }else {
209 //把时间点对应的数据发送,同一秒内有存在多个数据的情况 211 //把时间点对应的数据发送,同一秒内有存在多个数据的情况
210 for(let i=0;i<msgDataArr.length;i++){ 212 for(let i=0;i<msgDataArr.length;i++){
@@ -214,31 +216,68 @@ class RecordPlayBackParse extends Emiter { @@ -214,31 +216,68 @@ class RecordPlayBackParse extends Emiter {
214 } 216 }
215 //method------------外部接口------------------------------------- 217 //method------------外部接口-------------------------------------
216 218
  219 + //开始播放
217 startRecordPlayback(_param) { 220 startRecordPlayback(_param) {
  221 + if(!this._isReady){
  222 + return {"code": ApeConsts.RETURN_FAILED,"data": "录制回放还未准备完成"};
  223 + }
218 this._startTimerCounter(); 224 this._startTimerCounter();
219 - return {"code": ApeConsts.RETURN_SUCCESS,"data": "ok"};  
220 - //this._apes(MessageTypes.RECORD_PLAYBACK_UPDATE,{"status":}); 225 + this._emit(MessageTypes.RECORD_PLAYBACK_UPDATE,{"status":PLAY});
221 } 226 }
222 227
  228 + //停止播放
223 stopRecordPlayback(_param) { 229 stopRecordPlayback(_param) {
224 this._recordPlaybackTimestamp = 0; 230 this._recordPlaybackTimestamp = 0;
225 this._stopTimerCounter(); 231 this._stopTimerCounter();
226 - return {"code": ApeConsts.RETURN_SUCCESS,"data": "ok"}; 232 + this._emit(MessageTypes.RECORD_PLAYBACK_UPDATE,{"status":STOP});
227 } 233 }
228 234
  235 + //暂停播放
229 pauseRecordPlayback(_param) { 236 pauseRecordPlayback(_param) {
230 - this._stopTimerCounter()  
231 - return {"code": ApeConsts.RETURN_SUCCESS,"data": "ok"}; 237 + this._stopTimerCounter();
  238 + this._emit(MessageTypes.RECORD_PLAYBACK_UPDATE,{"status":PAUSE});
232 } 239 }
233 240
  241 + //跳转到指定时间点播放
234 seekRecordPlayback(_param) { 242 seekRecordPlayback(_param) {
  243 + if(!this._isReady){
  244 + return {"code": ApeConsts.RETURN_FAILED,"data": "录制回放还未准备完成"};
  245 + }
235 if(!_param||!_param.time){ 246 if(!_param||!_param.time){
236 return {"code": ApeConsts.RETURN_FAILED,"data": "参数不正确"}; 247 return {"code": ApeConsts.RETURN_FAILED,"data": "参数不正确"};
237 } 248 }
  249 + //先暂停,更改进行的时间
238 this._stopTimerCounter() 250 this._stopTimerCounter()
239 this._recordPlaybackTimestamp = _param.time || 0; 251 this._recordPlaybackTimestamp = _param.time || 0;
  252 +
  253 + //查找关键帧
  254 + this._searchKeyFram();
  255 + }
  256 + _searchKeyFram(){
  257 + //查找关键帧,找到关键帧后再继续播放
  258 + let messageItem;
  259 + let keyFrameSeek=0;
  260 + for(let i=this._recordPlaybackTimestamp;i>0;i--){
  261 + messageItem=this._messages[i];
  262 + if(messageItem){
  263 + break;
  264 + }
  265 + }
  266 + if(messageItem){
  267 + keyFrameSeek=(this._recordPlaybackTimestamp-messageItem.timestamp)
  268 + loger.log("SEEK->",this._recordPlaybackTimestamp,"查找到相连的数据,seek和关键帧的位置偏移",keyFrameSeek,"秒");
  269 + //把时间点对应的数据发送,同一秒内有存在多个数据的情况
  270 + for(let i=0;i<messageItem.length;i++){
  271 + this._everSocketMsgReceivedHandler(messageItem[i].byteData);
  272 + }
  273 + }else {
  274 + loger.log("SEEK->",this._recordPlaybackTimestamp,"没有查找到相连的数据");
  275 + }
  276 +
  277 + this._emit(MessageTypes.RECORD_PLAYBACK_UPDATE,{"status":SEEK,"keyFrameSeek":keyFrameSeek});
  278 + //无论有没有找到关键帧数据,都继续播放
240 this._startTimerCounter(); 279 this._startTimerCounter();
241 - return {"code": ApeConsts.RETURN_SUCCESS,"data": "ok"}; 280 +
242 } 281 }
243 } 282 }
244 283
@@ -51,14 +51,6 @@ export default class Ape extends Emiter { @@ -51,14 +51,6 @@ export default class Ape extends Emiter {
51 51
52 //先收到onJoinSessionHandlerSuccess 后收到 onJoinChannelHandlerSuccess 52 //先收到onJoinSessionHandlerSuccess 后收到 onJoinChannelHandlerSuccess
53 53
54 - loger.log('APE-->registerApe->',  
55 - 'SessionId',  
56 - this._session_id,  
57 - 'SessionName',  
58 - this._session_name,  
59 - 'SessionTag',  
60 - this._session_tag);  
61 -  
62 // 监听底层MCU课堂 54 // 监听底层MCU课堂
63 this.mcu = McuObj; 55 this.mcu = McuObj;
64 this.mcu.on(MessageTypes.CLASS_JOIN_MCU_SUCCESS, this._mcuConferenceJoinSuccessHandler.bind(this)); 56 this.mcu.on(MessageTypes.CLASS_JOIN_MCU_SUCCESS, this._mcuConferenceJoinSuccessHandler.bind(this));
@@ -316,14 +316,17 @@ class AudioApe extends Ape { @@ -316,14 +316,17 @@ class AudioApe extends Ape {
316 if(unpackChannelInfo&&unpackChannelInfo.fromNodeId!=GlobalConfig.nodeId){ 316 if(unpackChannelInfo&&unpackChannelInfo.fromNodeId!=GlobalConfig.nodeId){
317 let receiveChannelInfo={}; 317 let receiveChannelInfo={};
318 receiveChannelInfo.mediaId=unpackChannelInfo.channelId; 318 receiveChannelInfo.mediaId=unpackChannelInfo.channelId;
  319 + receiveChannelInfo.fromNodeId=unpackChannelInfo.fromNodeId;
319 320
320 //消息不是自己同步的,需要处理 321 //消息不是自己同步的,需要处理
321 if(unpackChannelInfo.status==ApeConsts.CHANNEL_STATUS_OPENING){ 322 if(unpackChannelInfo.status==ApeConsts.CHANNEL_STATUS_OPENING){
322 //正在推流 323 //正在推流
323 receiveChannelInfo.m3u8Url=""; 324 receiveChannelInfo.m3u8Url="";
324 receiveChannelInfo.rtmpUrl=""; 325 receiveChannelInfo.rtmpUrl="";
  326 + receiveChannelInfo.replay="";
325 let m3u8Stream=this.mediaModule.getMediaPlayPath({"type":"m3u8","streamId": unpackChannelInfo.streamId}); 327 let m3u8Stream=this.mediaModule.getMediaPlayPath({"type":"m3u8","streamId": unpackChannelInfo.streamId});
326 let rtmpStream=this.mediaModule.getMediaPlayPath({"type":"rtmp","streamId": unpackChannelInfo.streamId}); 328 let rtmpStream=this.mediaModule.getMediaPlayPath({"type":"rtmp","streamId": unpackChannelInfo.streamId});
  329 + let replay=this.mediaModule.getMediaRecordPlaybackPath({"type":"m3u8","streamId": unpackChannelInfo.streamId});
327 330
328 if(m3u8Stream.code==0){ 331 if(m3u8Stream.code==0){
329 receiveChannelInfo.m3u8Url=m3u8Stream.playUrl; 332 receiveChannelInfo.m3u8Url=m3u8Stream.playUrl;
@@ -331,6 +334,9 @@ class AudioApe extends Ape { @@ -331,6 +334,9 @@ class AudioApe extends Ape {
331 if(rtmpStream.code==0){ 334 if(rtmpStream.code==0){
332 receiveChannelInfo.rtmpUrl=rtmpStream.playUrl; 335 receiveChannelInfo.rtmpUrl=rtmpStream.playUrl;
333 } 336 }
  337 + if(replay.code==0){
  338 + receiveChannelInfo.replay=replay.playUrl;
  339 + }
334 loger.log("AUDIO_PLAY",receiveChannelInfo); 340 loger.log("AUDIO_PLAY",receiveChannelInfo);
335 //广播播放视频的消息 341 //广播播放视频的消息
336 this._emit(MessageTypes.AUDIO_PLAY, receiveChannelInfo); 342 this._emit(MessageTypes.AUDIO_PLAY, receiveChannelInfo);
@@ -32,7 +32,7 @@ class MediaModule { @@ -32,7 +32,7 @@ class MediaModule {
32 let port=""; 32 let port="";
33 if (_param.type == "m3u8") { 33 if (_param.type == "m3u8") {
34 //M3U8 34 //M3U8
35 - //http://123.56.73.119:6001/hls/h5dev_403074980_0_983041_1487663265/index.m3u8 35 + //http://123.56.73.119:6001/live/h5dev_2106728010_8ab3b0ed5a3a9220015a3a958f0d0003_983041_1489113860/index.m3u8
36 port = (GlobalConfig.RSServerPort == "" || GlobalConfig.RSServerPort == null) ? "":":" + GlobalConfig.RSServerPort; 36 port = (GlobalConfig.RSServerPort == "" || GlobalConfig.RSServerPort == null) ? "":":" + GlobalConfig.RSServerPort;
37 path = "http://" + GlobalConfig.RSServerIP 37 path = "http://" + GlobalConfig.RSServerIP
38 + port + "/live/" 38 + port + "/live/"
@@ -47,6 +47,23 @@ class MediaModule { @@ -47,6 +47,23 @@ class MediaModule {
47 return {"code": ApeConsts.RETURN_SUCCESS, "data": "","playUrl": path}; 47 return {"code": ApeConsts.RETURN_SUCCESS, "data": "","playUrl": path};
48 } 48 }
49 49
  50 + //获取录制回放时点播的地址,只有m3u8
  51 + getMediaRecordPlaybackPath(_param) {
  52 + loger.log('getMediaRecordPlaybackPath');
  53 + if (_param == null||_param.streamId == null)
  54 + {
  55 + loger.warn('getMediaRecordPlaybackPath,参数错误', _param);
  56 + return {"code": ApeConsts.RETURN_FAILED, "data": ""};
  57 + }
  58 + //M3U8 http://123.56.73.119:6001/live/h5dev_2106728010_8ab3b0ed5a3a9220015a3a958f0d0003_983041_1489113860/total.m3u8
  59 + let port = (GlobalConfig.RSServerPort == "" || GlobalConfig.RSServerPort == null) ? "":":" + GlobalConfig.RSServerPort;
  60 + let path = "http://" + GlobalConfig.RSServerIP
  61 + + port + "/live/"
  62 + + _param.streamId
  63 + + "/total.m3u8";
  64 + return {"code": ApeConsts.RETURN_SUCCESS, "data": "","playUrl": path};
  65 + }
  66 +
50 //获取推流地址 67 //获取推流地址
51 getMediaPublishPath(_param) { 68 getMediaPublishPath(_param) {
52 loger.log('getMediaPublishPath'); 69 loger.log('getMediaPublishPath');
@@ -319,14 +319,16 @@ class VideoApe extends Ape { @@ -319,14 +319,16 @@ class VideoApe extends Ape {
319 if(unpackChannelInfo&&unpackChannelInfo.fromNodeId!=GlobalConfig.nodeId){ 319 if(unpackChannelInfo&&unpackChannelInfo.fromNodeId!=GlobalConfig.nodeId){
320 let receiveChannelInfo={}; 320 let receiveChannelInfo={};
321 receiveChannelInfo.mediaId=unpackChannelInfo.channelId; 321 receiveChannelInfo.mediaId=unpackChannelInfo.channelId;
322 - 322 + receiveChannelInfo.fromNodeId=unpackChannelInfo.fromNodeId;
323 //消息不是自己同步的,需要处理 323 //消息不是自己同步的,需要处理
324 if(unpackChannelInfo.status==ApeConsts.CHANNEL_STATUS_OPENING){ 324 if(unpackChannelInfo.status==ApeConsts.CHANNEL_STATUS_OPENING){
325 //正在推流 325 //正在推流
326 receiveChannelInfo.m3u8Url=""; 326 receiveChannelInfo.m3u8Url="";
327 receiveChannelInfo.rtmpUrl=""; 327 receiveChannelInfo.rtmpUrl="";
  328 + receiveChannelInfo.replay="";
328 let m3u8Stream=this.mediaModule.getMediaPlayPath({"type":"m3u8","streamId": unpackChannelInfo.streamId}); 329 let m3u8Stream=this.mediaModule.getMediaPlayPath({"type":"m3u8","streamId": unpackChannelInfo.streamId});
329 let rtmpStream=this.mediaModule.getMediaPlayPath({"type":"rtmp","streamId": unpackChannelInfo.streamId}); 330 let rtmpStream=this.mediaModule.getMediaPlayPath({"type":"rtmp","streamId": unpackChannelInfo.streamId});
  331 + let replay=this.mediaModule.getMediaRecordPlaybackPath({"type":"m3u8","streamId": unpackChannelInfo.streamId});
330 332
331 if(m3u8Stream.code==0){ 333 if(m3u8Stream.code==0){
332 receiveChannelInfo.m3u8Url=m3u8Stream.playUrl; 334 receiveChannelInfo.m3u8Url=m3u8Stream.playUrl;
@@ -334,6 +336,9 @@ class VideoApe extends Ape { @@ -334,6 +336,9 @@ class VideoApe extends Ape {
334 if(rtmpStream.code==0){ 336 if(rtmpStream.code==0){
335 receiveChannelInfo.rtmpUrl=rtmpStream.playUrl; 337 receiveChannelInfo.rtmpUrl=rtmpStream.playUrl;
336 } 338 }
  339 + if(replay.code==0){
  340 + receiveChannelInfo.replay=replay.playUrl;
  341 + }
337 loger.log("VIDEO_PLAY",receiveChannelInfo); 342 loger.log("VIDEO_PLAY",receiveChannelInfo);
338 //广播播放视频的消息 343 //广播播放视频的消息
339 this._emit(MessageTypes.VIDEO_PLAY, receiveChannelInfo); 344 this._emit(MessageTypes.VIDEO_PLAY, receiveChannelInfo);