正在显示
2 个修改的文件
包含
469 行增加
和
0 行删除
src/apes/AudioApe.js
0 → 100644
| 1 | +// ////////////////////////////////////////////////////////////////////////////// | ||
| 2 | +//音频模块 | ||
| 3 | +// ////////////////////////////////////////////////////////////////////////////// | ||
| 4 | + | ||
| 5 | +import Ape from './Ape'; | ||
| 6 | +import ApeConsts from './ApeConsts'; | ||
| 7 | +import pdu from 'pdus'; | ||
| 8 | +import Loger from 'Loger'; | ||
| 9 | +import MessageTypes from 'MessageTypes'; | ||
| 10 | +import GlobalConfig from 'GlobalConfig'; | ||
| 11 | +import EngineUtils from 'EngineUtils'; | ||
| 12 | +import MediaModule from "./MediaModule"; | ||
| 13 | + | ||
| 14 | +let loger = Loger.getLoger('AudioApe'); | ||
| 15 | + | ||
| 16 | +class AudioApe extends Ape { | ||
| 17 | + constructor() { | ||
| 18 | + super( | ||
| 19 | + ApeConsts.AUDIO_SESSION_ID, | ||
| 20 | + ApeConsts.AUDIO_SESSION_NAME, | ||
| 21 | + ApeConsts.AUDIO_SESSION_TAG | ||
| 22 | + ); | ||
| 23 | + | ||
| 24 | + this.mediaModule=new MediaModule(); | ||
| 25 | + this.mediaModule.MEDIA_OBJ_TABLE_ID=ApeConsts.AUDIO_OBJ_TABLE_ID; | ||
| 26 | + this.mediaModule.mediaChannels={}; | ||
| 27 | + // Ape Models | ||
| 28 | + this.registerKey(this._session_id, this._session_name, this._session_tag, new ArrayBuffer); | ||
| 29 | + this.registerObj(pdu.RCPDU_REG_REGISTER_TABLE, ApeConsts.AUDIO_OBJ_TABLE_ID, ApeConsts.AUDIO_OBJ_TABLE_NAME, ApeConsts.AUDIO_OBJ_TABLE_TAG, 0, new ArrayBuffer); | ||
| 30 | + | ||
| 31 | + // 广播消息,用户之间的消息传递 | ||
| 32 | + this.on(pdu.RCPDU_AUDIO_SEND_DATA_REQUEST, this.receiveAudiooCommandHandler.bind(this)); | ||
| 33 | + } | ||
| 34 | + //ape加入成功 | ||
| 35 | + onJoinChannelHandlerSuccess(){ | ||
| 36 | + //这个设置很重要,因为只有Sass流程完成之后,APE才能取得GlobalConfig中的数据 | ||
| 37 | + this.mediaModule.maxMediaChannel=GlobalConfig.maxAudioChannels; | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + /////////////发送数据操作//////////////////////////////////////////// | ||
| 41 | + //获取播流地址 | ||
| 42 | + getAudioPlayPath(_param) { | ||
| 43 | + loger.log('getAudioPlayPath'); | ||
| 44 | + return this.mediaModule.getMediaPlayPath(_param); | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + //获取推流地址 | ||
| 48 | + getAudioPublishPath(_param) { | ||
| 49 | + loger.log('getAudioPublishPath'); | ||
| 50 | + return this.mediaModule.getMediaPublishPath(_param); | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + //推流 | ||
| 54 | + publishAudio(_param) { | ||
| 55 | + if (_param == null||_param.channelId == null|| | ||
| 56 | + _param.classId == null||_param.userId == null|| | ||
| 57 | + _param.siteId == null|| _param.timestamp==null) | ||
| 58 | + { | ||
| 59 | + loger.warn('publishAudio,参数错误', _param); | ||
| 60 | + this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG); | ||
| 61 | + return {"code": 1, "data": ""}; | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + //同一个nodeId只允许推一个流,如果已经推了就不能再推 | ||
| 65 | + if(this.mediaModule.getOpeningMediaChannel(GlobalConfig.nodeId)!=0){ | ||
| 66 | + loger.warn("publishVideo,已经存在一个流,不能再推"); | ||
| 67 | + return; | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + //判断当前是否还有空闲的channle | ||
| 71 | + let freeChannel = this.mediaModule.getFreeMediaChannel(); | ||
| 72 | + if (freeChannel == 0) { | ||
| 73 | + loger.warn("publishAudio,没有空闲的channel "); | ||
| 74 | + return {"code": 1, "data": "不能再打开更多的设备"}; | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + //判断当前的频道是否已经占用 | ||
| 78 | + if(this.mediaModule.checkChannelIsOpening(_param.channelId)){ | ||
| 79 | + loger.warn(_param.channelId,"频道已经被占用"); | ||
| 80 | + return {"code":1,"data":"频道已经被占用!"}; | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + let channelInfo={}; | ||
| 84 | + channelInfo.status=ApeConsts.CHANNEL_STATUS_OPENING; | ||
| 85 | + channelInfo.fromNodeId=GlobalConfig.nodeId; | ||
| 86 | + channelInfo.channelId=_param.channelId;//freeChannel | ||
| 87 | + channelInfo.timestamp=_param.timestamp;//EngineUtils.creatTimestamp(); | ||
| 88 | + channelInfo.classId=_param.classId;//GlobalConfig.classId; | ||
| 89 | + channelInfo.siteId=_param.siteId;//GlobalConfig.siteId; | ||
| 90 | + channelInfo.toNodeId=0; | ||
| 91 | + channelInfo.mediaType=ApeConsts.MEDIA_TYPE_AUDIO; | ||
| 92 | + this.sendTableUpdateHandler(channelInfo); | ||
| 93 | + return {"code":0,"data":"推流成功!"} | ||
| 94 | + } | ||
| 95 | + | ||
| 96 | + //停止推流, | ||
| 97 | + stopPublishAudio(_param) { | ||
| 98 | + loger.log('stopPublishAudio'); | ||
| 99 | + //_param如果为空,那么默认就是当前自己的nodeId,否则用_param | ||
| 100 | + let nodeId; | ||
| 101 | + if(_param&&parseInt(_param.nodeId)>=0){ | ||
| 102 | + nodeId=parseInt(_param.nodeId); | ||
| 103 | + }else { | ||
| 104 | + nodeId=GlobalConfig.nodeId; | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + let openingChannel = this.mediaModule.getOpeningMediaChannel(nodeId); | ||
| 108 | + if (openingChannel == 0) { | ||
| 109 | + loger.warn(nodeId,"stopPublishAudio,没有打开的channel,不需要关闭"); | ||
| 110 | + return {"code": 1, "data": "没有打开的channel,不需要关闭"}; | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + let channelInfo={}; | ||
| 114 | + channelInfo.status=ApeConsts.CHANNEL_STATUS_RELEASED; | ||
| 115 | + channelInfo.fromNodeId=0; | ||
| 116 | + channelInfo.channelId=openingChannel; | ||
| 117 | + channelInfo.timestamp=0; | ||
| 118 | + channelInfo.classId=GlobalConfig.classId; | ||
| 119 | + channelInfo.toNodeId=0; | ||
| 120 | + channelInfo.mediaType=ApeConsts.MEDIA_TYPE_DEFAULT; | ||
| 121 | + this.sendTableUpdateHandler(channelInfo); | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + sendAudioBroadcastMsg(_param) { | ||
| 125 | + if (this._classInfo === null || EngineUtils.isEmptyObject(this._classInfo)) { | ||
| 126 | + loger.log('sendAudioBroadcastMsg.McuClient还未初始化数据!'); | ||
| 127 | + if (GlobalConfig.getCurrentStatus().code == 0 || GlobalConfig.getCurrentStatus().code == 1) { | ||
| 128 | + this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_SEND_FAILED_NO_JOIN); | ||
| 129 | + return {"code": 1, "data": "sendAudioBroadcastMsg.McuClient还未初始化数据"}; | ||
| 130 | + } | ||
| 131 | + return {"code": 1, "data": "sendAudioBroadcastMsg.McuClient还未初始化数据"}; | ||
| 132 | + } | ||
| 133 | + if (_param == null) { | ||
| 134 | + loger.warn('sendAudioBroadcastMsg,参数错误', _param); | ||
| 135 | + this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG); | ||
| 136 | + return {"code": 1, "data": "sendAudioBroadcastMsg,参数错误"}; | ||
| 137 | + ; | ||
| 138 | + } | ||
| 139 | + // to, message | ||
| 140 | + loger.log('发送Audio消息.', _param); | ||
| 141 | + | ||
| 142 | + if (_param.actionType != null && _param.actionType == ApeConsts.MEDIA_ACTION_OPEN_CAMERA) { | ||
| 143 | + //判断当前开启的视频数量是否已经是最大值,如果已经是最大值,不能再开启 | ||
| 144 | + let freeChannel = this.mediaModule.getFreeMediaChannel(); | ||
| 145 | + if (freeChannel == 0) { | ||
| 146 | + loger.warn('sendAudioBroadcastMsg,不能再打开更多的设备', _param); | ||
| 147 | + return {"code": 1, "data": "不能再打开更多的设备"}; | ||
| 148 | + } | ||
| 149 | + } | ||
| 150 | + /* message RCVideoSendDataRequestPdu { | ||
| 151 | + required uint32 from_node_id = 1;//发起人 | ||
| 152 | + optional uint32 to_node_id = 2;//接收人,如果是0就是所有人都接收 | ||
| 153 | + optional uint32 actionType = 3;//消息指令类型; | ||
| 154 | + optional bytes data = 4;//其他数据,这个根据actionType来确定数据的结构 | ||
| 155 | + }*/ | ||
| 156 | + | ||
| 157 | + let audioSendPdu = new pdu['RCAudioSendDataRequestPdu']; | ||
| 158 | + audioSendPdu.type = pdu.RCPDU_AUDIO_SEND_DATA_REQUEST; | ||
| 159 | + audioSendPdu.isPublic = true; | ||
| 160 | + | ||
| 161 | + audioSendPdu.fromNodeId = GlobalConfig.nodeId;//发起人 | ||
| 162 | + audioSendPdu.toNodeId = parseInt(_param.toNodeID) || 0;//接收者,0就是所有人 | ||
| 163 | + audioSendPdu.actionType = parseInt(_param.actionType) || ApeConsts.MEDIA_ACTION_DEFAULT; | ||
| 164 | + | ||
| 165 | + audioSendPdu.data = this._rCArrayBufferUtil.strToUint8Array("h5" + _param.data);//开头两个字会乱码 | ||
| 166 | + | ||
| 167 | + if (!audioSendPdu.isPublic && 0 != audioSendPdu.toNodeId) { | ||
| 168 | + //发送给制定的人 | ||
| 169 | + loger.log('发送私聊消息.'); | ||
| 170 | + this.send(audioSendPdu); | ||
| 171 | + } else { | ||
| 172 | + //发送给所有人 | ||
| 173 | + loger.log('发送公聊消息.'); | ||
| 174 | + this.sendChatUniform(audioSendPdu); | ||
| 175 | + } | ||
| 176 | + return {"code": 0, "data": ""}; | ||
| 177 | + } | ||
| 178 | + | ||
| 179 | + sendTableUpdateHandler(_channelInfo) { | ||
| 180 | + loger.log("audio,sendTableUpdateHandler "); | ||
| 181 | + let updateModelPdu = this.packPdu(_channelInfo, _channelInfo.channelId);//let updateModelPdu=this.packPdu({},ApeConsts.VIDEO_OBJ_TABLE_ID+2); | ||
| 182 | + if(updateModelPdu==null){ | ||
| 183 | + loger.warn("sendTableUpdateHandler error,updateModelPdu=null"); | ||
| 184 | + return; | ||
| 185 | + } | ||
| 186 | + | ||
| 187 | + let tableItemPdu = new pdu['RCRegistryTableItemPdu']; | ||
| 188 | + tableItemPdu.itemIdx = _channelInfo.channelId;//tableItemPdu.itemIdx=ApeConsts.VIDEO_OBJ_TABLE_ID+2; | ||
| 189 | + tableItemPdu.owner = 0;//收到flash的是这个值,不清楚先写固定 | ||
| 190 | + tableItemPdu.itemData = updateModelPdu.toArrayBuffer(); | ||
| 191 | + | ||
| 192 | + //insert | ||
| 193 | + let tableInsertItemPdu = new pdu['RCRegistryTableUpdateItemPdu']; | ||
| 194 | + //optional RCPduType_E type = 1 [default = RCPDU_REG_TABLE_UPDATE_PDU]; | ||
| 195 | + //repeated RCRegistryTableItemPdu items = 2; | ||
| 196 | + tableInsertItemPdu.type = pdu.RCPDU_REG_TABLE_UPDATE_PDU;// | ||
| 197 | + tableInsertItemPdu.items.push(tableItemPdu); | ||
| 198 | + | ||
| 199 | + let updateObjPdu = new pdu['RCRegistryUpdateObjPdu']; | ||
| 200 | + updateObjPdu.objId = ApeConsts.AUDIO_OBJ_TABLE_ID;// | ||
| 201 | + updateObjPdu.subType = tableInsertItemPdu.type; | ||
| 202 | + updateObjPdu.userData = tableInsertItemPdu.toArrayBuffer(); | ||
| 203 | + | ||
| 204 | + //同步 | ||
| 205 | + let adapterItemPdu = new pdu['RCAdapterItemPdu']; | ||
| 206 | + adapterItemPdu.type = pdu.RCPDU_REG_UPDATE_OBJ; | ||
| 207 | + adapterItemPdu.itemData = updateObjPdu.toArrayBuffer(); | ||
| 208 | + | ||
| 209 | + let adapterPdu = new pdu['RCAdapterPdu']; | ||
| 210 | + adapterPdu.type = pdu.RCPDU_REG_ADAPTER; | ||
| 211 | + adapterPdu.item.push(adapterItemPdu); | ||
| 212 | + | ||
| 213 | + loger.log("发送更新AUDIO.itemIdx=" + tableItemPdu.itemIdx); | ||
| 214 | + this.sendUniform(adapterPdu, true); | ||
| 215 | + } | ||
| 216 | + | ||
| 217 | + /////收到消息处理////////////////////////////////////////////////// | ||
| 218 | + | ||
| 219 | + // 消息处理,内部处理,不需要告诉应用层 | ||
| 220 | + receiveAudiooCommandHandler(_data) { | ||
| 221 | + let audioReceivePdu = pdu['RCAudioSendDataRequestPdu'].decode(_data); | ||
| 222 | + if (audioReceivePdu == null) { | ||
| 223 | + loger.warn("音频消息处理,收到的消息为null,不做处理"); | ||
| 224 | + return; | ||
| 225 | + } | ||
| 226 | + audioReceivePdu.data = this._rCArrayBufferUtil.uint8ArrayToStr(audioReceivePdu.data, 2);//开头两个字会乱码 | ||
| 227 | + loger.log('音频消息处理 receiveAudiooCommandHandler.', audioReceivePdu); | ||
| 228 | + | ||
| 229 | + //判断接收者的id,如果不是0,并且也不是自己的nodeId,那么消息不做处理 | ||
| 230 | + if (audioReceivePdu.toNodeId != 0 && audioReceivePdu.toNodeId != GlobalConfig.nodeId) { | ||
| 231 | + loger.log('音频消息不处理 toNodeId=', audioReceivePdu.toNodeId, "my nodeId=", GlobalConfig.nodeId); | ||
| 232 | + } else { | ||
| 233 | + this._emit(MessageTypes.AUDIO_COMMAND, audioReceivePdu); | ||
| 234 | + } | ||
| 235 | + } | ||
| 236 | + | ||
| 237 | + tableUpdateHandler(owner, itemIdx, itemData) { | ||
| 238 | + // debugger; | ||
| 239 | + let videoChannelInfo = this.unPackPdu(owner, itemIdx, itemData); | ||
| 240 | + //videoChannelInfo.owner = owner; | ||
| 241 | + //videoChannelInfo.channelId = itemIdx; | ||
| 242 | + //videoChannelInfo.status = owner === 0 ? ApeConsts.CHANNEL_STATUS_RELEASED : videoChannelInfo.status; | ||
| 243 | + //loger.log('视频消息处理 tableUpdateHandler.',videoChannelInfo); | ||
| 244 | + this.mediaModule.mediaChannels[itemIdx] = videoChannelInfo; | ||
| 245 | + | ||
| 246 | + this._emit(MessageTypes.AUDIO_UPDATE, videoChannelInfo); | ||
| 247 | + /* switch (videoChannelInfo.status) { | ||
| 248 | + case ApeConsts.CHANNEL_STATUS_RELEASED: | ||
| 249 | + // 只能关闭自己的流 | ||
| 250 | + if (this.activeChannelId === videoChannelInfo.channelId) { | ||
| 251 | + this.activeChannelId = 0; | ||
| 252 | + this.activeURL = ''; | ||
| 253 | + this.emitVideoChange(); | ||
| 254 | + } | ||
| 255 | + break; | ||
| 256 | + case ApeConsts.CHANNEL_STATUS_OPENING: | ||
| 257 | + //_playUrl = "rtmfp://" + Config.mediaServerAddr + ":" + Config.mediaServerPort + "/message/" + _streamName; | ||
| 258 | + //_cdnUrl = "rtmp://" + Config.mediaCDNServerAddr + ":" + Config.mediaCDNServerPort + "/message/" + _streamName; | ||
| 259 | + //this.activeChannelId = videoChannelInfo.channelId; | ||
| 260 | + //// AMS/FMS | ||
| 261 | + //if (this._classInfo.msType ==ApeConsts.MS_TYPE_FMS) { | ||
| 262 | + // this.activeURL = `http://dazhi.3mang.com/live/${this._classInfo.classId}/${this._classInfo.classId}_${videoChannelInfo.channelId}_flash_cam_mic_aac/playlist.m3u8`; | ||
| 263 | + //}else { | ||
| 264 | + // this.activeURL = `http://hls.3mang.com/live/${this._classInfo.classId}_${videoChannelInfo.channelId}_flash_cam_mic_aac/playlist.m3u8`; | ||
| 265 | + //} | ||
| 266 | + // 任何人都可以打开流 | ||
| 267 | + this.emitVideoChange(); | ||
| 268 | + break; | ||
| 269 | + default: | ||
| 270 | + break; | ||
| 271 | + }*/ | ||
| 272 | + } | ||
| 273 | + | ||
| 274 | + ///////数据的封包和解包///////////////////////////////////////// | ||
| 275 | + packPdu(_param, _itemIdx) { | ||
| 276 | + loger.log("packPdu "); | ||
| 277 | + //验证坐标点集合数组是否合法 | ||
| 278 | + if (_param == null || _itemIdx == null) { | ||
| 279 | + this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG); | ||
| 280 | + return null; | ||
| 281 | + } | ||
| 282 | + | ||
| 283 | + /* message RCVideoChannelInfoPdu { | ||
| 284 | + optional uint32 status = 1;//开启的状态 | ||
| 285 | + optional uint32 channel_id = 2;//唯一的频道id | ||
| 286 | + optional uint32 timestamp = 3;//更新的时间戳 | ||
| 287 | + optional uint32 from_node_id = 4;//发起者的id | ||
| 288 | + optional uint32 to_node_id = 5;//接收者的id,(如果是0,所有人都接收) | ||
| 289 | + }*/ | ||
| 290 | + | ||
| 291 | + //判断type类型,根据type设置不同的参数 | ||
| 292 | + let packPduModel = new pdu['RCAudioChannelInfoPdu']; | ||
| 293 | + packPduModel.status = _param.status||ApeConsts.CHANNEL_STATUS_RELEASED; | ||
| 294 | + packPduModel.channelId = _itemIdx; | ||
| 295 | + packPduModel.siteId=_param.siteId||GlobalConfig.siteId;//GlobalConfig.siteId; | ||
| 296 | + packPduModel.classId =parseInt(_param.classId)||parseInt(GlobalConfig.classId); | ||
| 297 | + packPduModel.userId =_param.userId||"0"; | ||
| 298 | + packPduModel.mediaType =_param.mediaType|| ApeConsts.MEDIA_TYPE_AUDIO; | ||
| 299 | + packPduModel.timestamp =_param.timestamp||EngineUtils.creatTimestamp(); | ||
| 300 | + packPduModel.fromNodeId = GlobalConfig.nodeId; | ||
| 301 | + packPduModel.toNodeId = 0; | ||
| 302 | + console.log("packPdu",packPduModel); | ||
| 303 | + return packPduModel; | ||
| 304 | + } | ||
| 305 | + | ||
| 306 | + unPackPdu(owner, itemIdx, itemData) { | ||
| 307 | + loger.log("unPackPdu "); | ||
| 308 | + if (owner == null || itemIdx == null || itemData == null) { | ||
| 309 | + this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG); | ||
| 310 | + return null; | ||
| 311 | + } | ||
| 312 | + try { | ||
| 313 | + let videoChannelInfo = pdu['RCAudioChannelInfoPdu'].decode(itemData); | ||
| 314 | + loger.log("unPackPdu",videoChannelInfo); | ||
| 315 | + return videoChannelInfo; | ||
| 316 | + } catch (err) { | ||
| 317 | + loger.log("unPackPdu error,itemIdx=" + itemIdx + " err:" + err.message); | ||
| 318 | + } | ||
| 319 | + return null; | ||
| 320 | + } | ||
| 321 | + | ||
| 322 | +} | ||
| 323 | + | ||
| 324 | +export default AudioApe; | ||
| 325 | + |
src/apes/MediaModule.js
0 → 100644
| 1 | +// ////////////////////////////////////////////////////////////////////////////// | ||
| 2 | +// VideoApe、AudioApe 共用的方法单独提取处理 | ||
| 3 | +// ////////////////////////////////////////////////////////////////////////////// | ||
| 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 | +class MediaModule { | ||
| 14 | + constructor() { | ||
| 15 | + this.mediaChannels = {}; | ||
| 16 | + this.maxMediaChannel=0; | ||
| 17 | + this.MEDIA_OBJ_TABLE_ID=0; | ||
| 18 | + } | ||
| 19 | + | ||
| 20 | + //获取播流地址 | ||
| 21 | + getMediaPlayPath(_param) { | ||
| 22 | + loger.log('getMediaPlayPath'); | ||
| 23 | + if (_param == null||_param.siteId == null|| | ||
| 24 | + _param.classId == null||_param.userId == null|| | ||
| 25 | + _param.channelId == null|| _param.timestamp==null) | ||
| 26 | + { | ||
| 27 | + loger.warn('getMediaPlayPath,参数错误', _param); | ||
| 28 | + this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG); | ||
| 29 | + return {"code": 1, "data": ""}; | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + let path = ""; | ||
| 33 | + let port=""; | ||
| 34 | + if (_param.type == "m3u8") { | ||
| 35 | + //M3U8 | ||
| 36 | + //http://123.56.73.119:6001/hls/h5dev_403074980_0_983041_1487663265/index.m3u8 | ||
| 37 | + port = (GlobalConfig.RSServerPort == "" || GlobalConfig.RSServerPort == null) ? "":":" + GlobalConfig.RSServerPort; | ||
| 38 | + path = "http://" + GlobalConfig.RSServerIP | ||
| 39 | + + port + "/live/" | ||
| 40 | + + _param.siteId | ||
| 41 | + + "_" + _param.classId | ||
| 42 | + + "_" + _param.userId | ||
| 43 | + + "_" + _param.channelId | ||
| 44 | + + "_" + _param.timestamp | ||
| 45 | + + "/index.m3u8"; | ||
| 46 | + } else { | ||
| 47 | + port = (GlobalConfig.MSServerPort == "" || GlobalConfig.MSServerPort == null) ? "":":" + GlobalConfig.MSServerPort; | ||
| 48 | + path = "rtmp://" + GlobalConfig.MSServerIP | ||
| 49 | + + port + "/live/" | ||
| 50 | + + _param.siteId | ||
| 51 | + + "_" + _param.classId | ||
| 52 | + + "_" + _param.userId | ||
| 53 | + + "_" + _param.channelId | ||
| 54 | + + "_" + _param.timestamp; | ||
| 55 | + } | ||
| 56 | + return {"code": 0, "data": path}; | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + //获取推流地址 | ||
| 60 | + getMediaPublishPath(_param) { | ||
| 61 | + loger.log('getMediaPublishPath'); | ||
| 62 | + //判断当前开启的视频数量是否已经是最大值,如果已经是最大值,不能再开启 | ||
| 63 | + let freeChannel = this.getFreeMediaChannel(); | ||
| 64 | + if (freeChannel == 0) { | ||
| 65 | + return {"code": 1, "data": "不能再打开更多的设备"}; | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + //默认方式推流 | ||
| 69 | + let pubType="live"; | ||
| 70 | + //flash推流 | ||
| 71 | + if(_param&&_param.type=="flash"){ | ||
| 72 | + pubType ="flash"; | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + //端口,有端口就显示 ":xxx",没有端口就是"" | ||
| 76 | + let port = (GlobalConfig.MSServerPort == "" || GlobalConfig.MSServerPort == null) ? "":":" + GlobalConfig.MSServerPort; | ||
| 77 | + //时间戳 | ||
| 78 | + let timestamp = EngineUtils.creatTimestamp(); | ||
| 79 | + | ||
| 80 | + //生成推流地址和推流数据(同步数据的时候用) | ||
| 81 | + let publishUrl = "rtmp://" + GlobalConfig.MSServerIP | ||
| 82 | + + port + "/"+pubType+"/" +GlobalConfig.siteId+"_" | ||
| 83 | + + GlobalConfig.classId + "_"+GlobalConfig.userId | ||
| 84 | + +"_" + freeChannel + "_" + timestamp; | ||
| 85 | + return {"code": 0, | ||
| 86 | + "data": | ||
| 87 | + { "siteId":GlobalConfig.siteId, | ||
| 88 | + "classId":GlobalConfig.classId, | ||
| 89 | + "userId":GlobalConfig.userId, | ||
| 90 | + "channelId": freeChannel, | ||
| 91 | + "timestamp": timestamp, | ||
| 92 | + "publishUrl": publishUrl | ||
| 93 | + } | ||
| 94 | + }; | ||
| 95 | + } | ||
| 96 | + | ||
| 97 | + //获取当前空闲的channel,返回值为0代表没有空闲的,否则返回的就是空闲的channelId | ||
| 98 | + getFreeMediaChannel() { | ||
| 99 | + let counter = 0; | ||
| 100 | + for (let key in this.mediaChannels) { | ||
| 101 | + let item = this.mediaChannels[key]; | ||
| 102 | + if (item && item.status == ApeConsts.CHANNEL_STATUS_RELEASED) { | ||
| 103 | + return item.channelId; | ||
| 104 | + } | ||
| 105 | + counter++; | ||
| 106 | + } | ||
| 107 | + loger.log("getFreeMediaChannel","maxMediaChannel",this.maxMediaChannel,"counter:",counter); | ||
| 108 | + console.log(this.mediaChannels); | ||
| 109 | + if (counter < this.maxMediaChannel) { | ||
| 110 | + return this.MEDIA_OBJ_TABLE_ID + (counter); | ||
| 111 | + } | ||
| 112 | + return 0;//没有空闲的 | ||
| 113 | + } | ||
| 114 | + | ||
| 115 | + //获取当前属于nodeId的已经打开的的channel,返回值为0代表没有打开的,否则返回的就是打开的channelId | ||
| 116 | + getOpeningMediaChannel(_nodeId){ | ||
| 117 | + if(_nodeId==null||_nodeId==0){ | ||
| 118 | + return 0; | ||
| 119 | + } | ||
| 120 | + for (let key in this.mediaChannels) { | ||
| 121 | + let item = this.mediaChannels[key]; | ||
| 122 | + if (item && item.status == ApeConsts.CHANNEL_STATUS_OPENING&&item.fromNodeId==_nodeId) { | ||
| 123 | + return item.channelId; | ||
| 124 | + } | ||
| 125 | + } | ||
| 126 | + return 0; | ||
| 127 | + } | ||
| 128 | + | ||
| 129 | + //检查频道是否已经被占用 | ||
| 130 | + checkChannelIsOpening(_channelId){ | ||
| 131 | + if(_channelId==null){ | ||
| 132 | + loger.warn("checkChannelIsOpening error,channel=",_channelId); | ||
| 133 | + return true; | ||
| 134 | + } | ||
| 135 | + let channelInfo=this.mediaChannels[_channelId]; | ||
| 136 | + if(channelInfo==null||channelInfo.status==ApeConsts.CHANNEL_STATUS_RELEASED){ | ||
| 137 | + return false; | ||
| 138 | + } | ||
| 139 | + return true; | ||
| 140 | + } | ||
| 141 | +} | ||
| 142 | + | ||
| 143 | +export default MediaModule; | ||
| 144 | + |
-
请 注册 或 登录 后发表评论