// ////////////////////////////////////////////////////////////////////////////// // VideoApe、AudioApe 共用的方法单独提取处理 // ////////////////////////////////////////////////////////////////////////////// import ApeConsts from './ApeConsts'; import Loger from 'Loger'; import MessageTypes from 'MessageTypes'; import GlobalConfig from 'GlobalConfig'; import EngineUtils from 'EngineUtils'; let loger = Loger.getLoger('MediaModule'); class MediaModule { constructor() { this.needPublishMediaChannel={};//记录准备推流的频道信息 this.mediaChannels = {}; this.maxMediaChannel=0; this.mediaType=ApeConsts.MEDIA_TYPE_DEFAULT; this.MEDIA_OBJ_TABLE_ID=0; this.SCREENSHARING_OBJ_TABLE_ID=ApeConsts.SCREENSHARING_OBJ_TABLE_ID; } //获取播流地址 getMediaPlayPath(_param) { loger.log('获取播放地址->'); if (_param == null||_param.streamId == null) { loger.warn('获取播放地址->参数错误', _param); //this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG); return {"code": ApeConsts.RETURN_FAILED, "data": ""}; } let path = ""; let port=""; let fileName=''; if (_param.type == "m3u8") { //M3U8 //http://123.56.73.119:6001/live/h5dev_2106728010_8ab3b0ed5a3a9220015a3a958f0d0003_983041_1489113860/index.m3u8 if(GlobalConfig.siteId==GlobalConfig.siteId_letv){ //乐视的hls地址规则 fileName='desc.m3u8'; }else { //fileName='index.m3u8'; fileName='playlist.m3u8'; } port = (GlobalConfig.MS_PLAY_HLS_PORT == "" || GlobalConfig.MS_PLAY_HLS_PORT == null) ? "":":" + GlobalConfig.MS_PLAY_HLS_PORT; path = "http://" + GlobalConfig.MS_PLAY_HLS_IP + port + "/live/" + _param.streamId + "/"+fileName; } else { //RTMP port = (GlobalConfig.MS_PLAY_RTMP_PORT == "" || GlobalConfig.MS_PLAY_RTMP_PORT == null) ? "":":" + GlobalConfig.MS_PLAY_RTMP_PORT; path = "rtmp://" + GlobalConfig.MS_PLAY_RTMP_IP + port + "/live/" + _param.streamId; } path=path.replace("::",":");//如果ip和port之间有多的:需要去掉 return {"code": ApeConsts.RETURN_SUCCESS, "data": "","playUrl": path}; } //获取录制回放时点播的地址,只有m3u8 getMediaRecordPlaybackPath(_param) { loger.log('获取录制回放时点播的地址->m3u8'); if (_param == null||_param.streamId == null) { loger.warn('获取录制回放时点播的地址->参数错误', _param); return {"code": ApeConsts.RETURN_FAILED, "data": ""}; } //M3U8 http://123.56.73.119:6001/live/h5dev_2106728010_8ab3b0ed5a3a9220015a3a958f0d0003_983041_1489113860/total.m3u8 let port = (GlobalConfig.RS_RECORD_PLAY_PORT == "" || GlobalConfig.RS_RECORD_PLAY_PORT == null) ? "":":" + GlobalConfig.RS_RECORD_PLAY_PORT; let path = "http://" + GlobalConfig.RS_RECORD_PLAY_IP + port + "/live/" + _param.streamId + "/total.m3u8"; path=path.replace("::",":");//如果ip和port之间有多的:需要去掉 return {"code": ApeConsts.RETURN_SUCCESS, "data": "","playUrl": path}; } //获取推流地址 getMediaPublishPath(_param) { loger.log('获取推流地址->'); //判断当前开启的视频数量是否已经是最大值,如果已经是最大值,不能再开启 let freeChannel = this.getFreeMediaChannel(); if (freeChannel == 0) { return {"code":ApeConsts.RETURN_FAILED, "data": "不能再打开更多的设备","mediaChannels":this.mediaChannels}; } //默认方式推流 let pubType="live"; ////flash推流 //if(_param&&_param.type=="flash"){ // pubType ="flash"; //} //端口,有端口就显示 ":xxx",没有端口就是"" let port = (GlobalConfig.MS_PUBLISH_PORT == "" || GlobalConfig.MS_PUBLISH_PORT == null) ? "":":" + GlobalConfig.MS_PUBLISH_PORT; //时间戳 let timestamp = EngineUtils.creatTimestamp(); let streamId=GlobalConfig.siteId+"_" + GlobalConfig.classId + "_"+GlobalConfig.userId +"_" + freeChannel + "_" + timestamp; //生成推流地址和推流数据(同步数据的时候用) let publishUrl = "rtmp://" + GlobalConfig.MS_PUBLISH_IP + port + "/"+pubType+"/" +streamId; publishUrl=publishUrl.replace("::",":");//如果ip和port之间有多的:需要去掉 this.needPublishMediaChannel[publishUrl]={ "channelId":freeChannel, "publishUrl":publishUrl, "streamId":streamId, "timestamp":timestamp, "nodeId":GlobalConfig.nodeId }; return {"code": ApeConsts.RETURN_SUCCESS, "data":"", "mediaId":freeChannel, "publishUrl": publishUrl }; } //监课获取推流地址 getMediaPublishPathForInVisible(_param) { let mediaLen=Object.keys(MediaModule.allMediaChannelsList).length; let freeChannel=(this.MEDIA_OBJ_TABLE_ID-20-mediaLen)||GlobalConfig.nodeId; loger.log('监课获取推流地址->'+freeChannel+" mediaLen:"+mediaLen); //默认方式推流 let pubType="live"; ////flash推流 //if(_param&&_param.type=="flash"){ // pubType ="flash"; //} //端口,有端口就显示 ":xxx",没有端口就是"" let port = (GlobalConfig.MS_PUBLISH_PORT == "" || GlobalConfig.MS_PUBLISH_PORT == null) ? "":":" + GlobalConfig.MS_PUBLISH_PORT; //时间戳 let timestamp = EngineUtils.creatTimestamp(); let streamId=GlobalConfig.siteId+"_" + GlobalConfig.classId + "_"+GlobalConfig.userId +"_" + freeChannel + "_" + timestamp; //生成推流地址和推流数据(同步数据的时候用) let publishUrl = "rtmp://" + GlobalConfig.MS_PUBLISH_IP + port + "/"+pubType+"/" +streamId; publishUrl=publishUrl.replace("::",":");//如果ip和port之间有多的:需要去掉 this.needPublishMediaChannel[publishUrl]={ "channelId":freeChannel, "publishUrl":publishUrl, "streamId":streamId, "timestamp":timestamp, "nodeId":GlobalConfig.nodeId }; return {"code": ApeConsts.RETURN_SUCCESS, "data":"", "mediaId":freeChannel, "publishUrl": publishUrl }; } //桌面共享获取推流地址,频道号由外部传入 getMediaPublishPathForScreenShare(_shareChannel,_publishType) { let shareChannel=_shareChannel||this.SCREENSHARING_OBJ_TABLE_ID; loger.log('桌面共享获取推流地址->'+shareChannel); //默认方式推流 let pubType="live";//统一使用live 20170615 /*//flash推流 if(_publishType=="live"){ pubType ="live"; }*/ //端口,有端口就显示 ":xxx",没有端口就是"" let port = (GlobalConfig.MS_PUBLISH_PORT == "" || GlobalConfig.MS_PUBLISH_PORT == null) ? "":":" + GlobalConfig.MS_PUBLISH_PORT; //时间戳 let timestamp = EngineUtils.creatTimestamp(); let streamId=GlobalConfig.siteId+"_" + GlobalConfig.classId + "_"+GlobalConfig.userId +"_" + shareChannel + "_" + timestamp; //生成推流地址和推流数据(同步数据的时候用) let publishUrl = "rtmp://" + GlobalConfig.MS_PUBLISH_IP + port + "/"+pubType+"/" +streamId; publishUrl=publishUrl.replace("::",":");//如果ip和port之间有多的:需要去掉 /* this.needPublishMediaChannel[publishUrl]={ "channelId":shareChannel, "publishUrl":publishUrl, "streamId":streamId, "timestamp":timestamp, "nodeId":GlobalConfig.nodeId };*/ return {"code": ApeConsts.RETURN_SUCCESS, "data":"", "mediaId":shareChannel, "publishUrl": publishUrl, "streamId":streamId }; } //获取当前空闲的channel,返回值为0代表没有空闲的,否则返回的就是空闲的channelId getFreeMediaChannel() { let counter = 0; for (let key in this.mediaChannels) { let item = this.mediaChannels[key]; if (item && item.status == ApeConsts.CHANNEL_STATUS_RELEASED) { loger.log("已获取空闲的通道->channelId:"+item.channelId); return item.channelId; } counter++; } loger.log("获取空闲的通道","mediaChannels",this.mediaChannels,"counter:",counter); //loger.log(this.mediaChannels); if (counter < this.maxMediaChannel) { return this.MEDIA_OBJ_TABLE_ID + (counter); } return 0;//没有空闲的 } //获取准备推流的频道信息 getNeedPublishMediaChannel(_publishUrl){ return this.needPublishMediaChannel[_publishUrl]; } //获取当前属于nodeId的已经打开的的channel,返回值为0代表没有打开的,否则返回的就是打开的channelId getOpeningMediaChannel(_nodeId){ loger.log("getOpeningMediaChannel","nodeId",_nodeId,"mediaChannels:",this.mediaChannels); if(_nodeId==null||_nodeId==0){ return 0; } for (let key in this.mediaChannels) { let item = this.mediaChannels[key]; if (item && item.status == ApeConsts.CHANNEL_STATUS_OPENING&&item.fromNodeId==_nodeId) { return item.channelId; } } return 0; } //检查频道是否已经被占用 checkChannelIsOpening(_channelId){ if(_channelId==null){ loger.warn("checkChannelIsOpening error,channel=",_channelId); return true; } let channelInfo=this.mediaChannels[_channelId]; if(channelInfo==null||channelInfo.status==ApeConsts.CHANNEL_STATUS_RELEASED){ return false; } return true; } //获取当前所有频道的信息 getAllMediaChannelInfo(){ let channels=[]; for (let key in this.mediaChannels){ let channel=this.mediaChannels[key]; if(channel){ channels.push({"mediaId":channel.channelId,"status":channel.status,"fromNodeId":channel.fromNodeId}); } } if(channels.length<this.maxMediaChannel){ for (let i=channels.length;i<this.maxMediaChannel;i++){ let channelId=this.MEDIA_OBJ_TABLE_ID + (i); channels.push({"mediaId":channelId,"status":ApeConsts.CHANNEL_STATUS_RELEASED,"fromNodeId":0}); } } return channels; } //获取默认的频道信息 getDefaultChannelInfo(){ let channelInfo={}; channelInfo.owner=0;//这个很重要,释放的时候必须设置为0,占用的时候设置为自己的nodeId channelInfo.status=ApeConsts.CHANNEL_STATUS_RELEASED; channelInfo.fromNodeId=GlobalConfig.nodeId; channelInfo.channelId=0;//channelId不能为0 channelInfo.streamId=""; channelInfo.classId=GlobalConfig.classId; channelInfo.siteId=GlobalConfig.siteId; channelInfo.toNodeId=0; channelInfo.userId=GlobalConfig.userId; channelInfo.mediaType=this.mediaType||ApeConsts.MEDIA_TYPE_DEFAULT; return channelInfo; } } MediaModule.allMediaChannelsList={};//当前已经创建的所有音视频通道(包含释放或未未释放的) export default MediaModule;