李勇
e2502d91 1 parent 169b80b8 master ... 20170922-1 20171019-1 20171120-1w dev letv-20170426 ly20170622 ly20170622-2 ly20170622-3 ly20170627-2 ly20170706-1 ly20170708-2 ly20170708-3 ly20170710-1 ly20170717-1 ly20170719-1 ly20170723-1 ly20170724-2 ly20170726-1 ly20170731-1 ly20170731-2 ly20170801-2 ly20170802-1 ly20170818-1 ly20170818-2 ly20170820-1 ly20170821-1 ly20170824-1 ly20170829-1 ly20170925-1 ly20170926-1 ly20170927-1 ly20170929-1 ly20171011-1 ly20171013-1 ly20171013-2 ly20171016-1 ly20171021-1 ly20171023-1 ly20171024-1w ly20171025-1w ly20171026-1w ly20171027-1w ly20171030-1 ly20171030-2w ly20171107-1 ly20171110-1w ly20171113-1w ly20171204-1w ly20171208-1w ly20171211-1w ly20171211-2w ly20171214-1w webRtc-dev v2.38.13.20171216 v2.38.11.20171214 v2.38.3.201712011 v2.38.1.201712011 v2.36.11.20171204 v2.36.8.20171206 v2.36.4.20171201 v2.35.11.20171130 v2.34.16.20171128 v2.34.5.20171127 v2.33.6.20171123 v2.32.1.20171123 v2.31.12.20171122 v2.31.10.20171122 v2.30.5.20171117 v2.30.2.20171117 v2.29.5.20171114 v2.28.1.20171110 v2.27.11.20171109 v2.26.9.20171107 v2.26.6.20171103 v2.26.2.20171102 v2.25.7.20171031 v2.25.6.20171031 v2.25.0.20171030 v2.24.2.20171030 v2.23.0.20171030 v2.22.7.20171026 v2.20.5.20171023 v2.20.0.20171021 v2.19.8.20171020 v2.18.14.20171020 v2.18.10.20171019 v2.17.11.20171014 v2.16.8.20171012 v2.16.5.20171012 v2.15.5.20171001 v2.15.3.20170929 v2.14.5.20170927 v2.13.5.20170927 v2.12.14.20170927 v2.12.8.20170926 v2.12.6.20170925 v2.11.13.20170925 v2.10.7.20170921 v2.10.6.20170921 v2.10.5.20170920 v2.10.4.20170920 v2.9.3.20170919 v2.8.17.20170918 v2.8.8.20170917 v2.8.2.20170916 v2.6.2.20170915 v2.5.12.20170915 v2.5.6.20170914 v2.5.5.20170914 v2.4.4.20170908 v2.4.2.20170908 v2.4.0.20170907 v2.3.6.20170907 v2.2.16.20170905 v2.1.22.20170904 v1.84.0.20170912 v1.83.2.20170831 v1.82.11.20170829 v1.81.19.20170828 v1.80.2.20170824 v1.79.6.20170822 v1.79.5.20170821 v1.79.4.20170821 v1.79.3.20170821 v1.78.4.20170820 v1.77.4.20170819 v1.76.2.20170818 v1.75.0.20170815 v1.74.0.20170814 v1.73.2.20170814 v1.73.1.20170814 v1.71.0.20170813 v1.70.5.20170812 v1.68.2.20170812 v1.66.1.20170809 v1.65.25.20170808 v1.65.24.20170806 v1.63.1.20170731 v1.62.3.20170731 v1.61.0.20170729 v1.60.0.20170729 v1.59.0.20170729 v1.58.0.20170729 v1.57.0.20170727 v1.56.1.20170727 v1.56.0.20170727 v1.52.1.20170726 v1.51.0.20170724 v1.50.7.20170724 v1.49.1.20170724 v1.48.2.20170723 v1.46.1.20170722 v1.45.1.20170717 v1.43.1.20170711 v1.42.1.20170708 v1.41.0.20170708 v1.40.0.20170706 v1.39.2.20170706 v1.39.1.20170705 v1.38.4.20170629 v1.37.5.20170627 v1.37.2.20170622 v1.36.7.20170620 v1.36.4.20170620 v1.36.1.20170619 v1.35.4.20170619 v1.34.2.20170615 v1.33.2.20170615 v1.32.1.20170614 v1.31.11.20170613 v1.30.20.20170607 v1.30.7.20170606 v1.30.6.20170606 v1.30.5.20170605 v1.30.3.20170602 v1.29.8.20170601 v1.28.0.201705031 v1.27.16.201705027 v1.27.14.201705027 v1.27.10.201705026 v1.25.2.201705025 v1.23.5.201705023 v1.23.4.201705018

修复录制回放多路音视频,在seek拖动播放的时候,显示数量不正确的问题

此 diff 太大无法显示。
... ... @@ -28,7 +28,7 @@ import MediaModule from 'apes/MediaModule';
import UTF8 from 'utf-8';
let loger = Loger.getLoger('McuClient');
let _sdkInfo = {"version": "v1.22.0.201705017", "author": "www.3mang.com"};
let _sdkInfo = {"version": "v1.23.0.201705018", "author": "www.3mang.com"};
//APE
let _sass;
... ...
... ... @@ -7,6 +7,7 @@ import pdu from 'pdus/index';
import PduType from 'pdus/PduType';
import PduConsts from 'pdus/PduConsts';
import ApeConsts from 'apes/ApeConsts';
import ArrayBufferUtil from 'libs/ArrayBufferUtil';
import Base64 from 'base64-js';
import GlobalConfig from 'GlobalConfig';
... ... @@ -32,7 +33,7 @@ class RecordPlayBackParse extends Emiter {
this._recordPlaybackMaxTime = 0;//录制回放的总时间
this._isReady = false;//录制回放是否已经准备完成
this._apes = {};
this.mediaChannleList={};
this._conferApeMssages = {};//会议数据
this._chatApeMssages = {};//聊天数据
this._videoApeMssages = {};//视频数据
... ... @@ -118,6 +119,7 @@ class RecordPlayBackParse extends Emiter {
//解析和储存,录制回放EverSocket底层消息处理 data-数据;timestamp-数据对应的时间戳
_parseSaveSocketMsgReceivedHandler(data, timestamp) {
loger.log('解析和储存,录制回放EverSocket底层消息处理 ');
let pduMsg = pdu.decode_pdu(data);
let pduType = pduMsg.get("type");
let pduData = pduMsg.get("data");
... ... @@ -170,9 +172,11 @@ class RecordPlayBackParse extends Emiter {
break;
case ApeConsts.VIDEO_SESSION_ID:
this.saveParseData(data, timestamp, this._videoApeMssages);
this._pduRegAdapterHandler(pduMsg.data,timestamp,data,ApeConsts.VIDEO_SESSION_ID)
break;
case ApeConsts.AUDIO_SESSION_ID:
this.saveParseData(data, timestamp, this._audioApeMssages);
this._pduRegAdapterHandler(pduMsg.data,timestamp,data,ApeConsts.AUDIO_SESSION_ID)
break;
default:
break;
... ... @@ -308,6 +312,7 @@ class RecordPlayBackParse extends Emiter {
}
GlobalConfig.recordPlaybackMaxTime = this._recordPlaybackMaxTime;
console.log('MediaChannleList',this.mediaChannleList);
loger.log("录制回放数据解析完成,录制回放的总时间长为->", this._recordPlaybackMaxTime);
this._emit(RecordPlayBackParse.CLASS_JOIN_RECORD_PLAYBACK_SUCCESS, {"recordPlaybackMaxTime": this._recordPlaybackMaxTime});
}
... ... @@ -383,15 +388,19 @@ class RecordPlayBackParse extends Emiter {
GlobalConfig.activeDocCurPage=1;
this._emit(RecordPlayBackParse.RECORD_PLAYBACK_CLEAR_DATA);
//各个ape模块查找关键帧数据
this._searchKeyfram();
this._searchSeekKeyfram();
}
_searchKeyfram() {
//拖动进度条后根据seek时间点查找
_searchSeekKeyfram() {
//查找关键帧,找到关键帧后再继续播放
this._searchApeMessageKeyfram(this._conferApeMssages, ApeConsts.CONFERENCE_SESSION_ID);
this._searchApeMessageKeyfram(this._docApeMssages, ApeConsts.DOCSHARING_SESSION_ID);
this._searchApeMessageKeyfram(this._videoApeMssages, ApeConsts.VIDEO_SESSION_ID);
this._searchApeMessageKeyfram(this._audioApeMssages, ApeConsts.AUDIO_SESSION_ID);
//this._searchApeMessageKeyfram(this._videoApeMssages, ApeConsts.VIDEO_SESSION_ID);
//this._searchApeMessageKeyfram(this._audioApeMssages, ApeConsts.AUDIO_SESSION_ID);
this._searchMediaApeMessageKeyfram(this.mediaChannleList);
//聊天模块、白板标注模块的比较特殊,消息是累计的,默认最多30条
this._searchChatHistoryMessageKeyfram(this._chatApeMssages, ApeConsts.CHAT_SESSION_ID);
... ... @@ -425,7 +434,35 @@ class RecordPlayBackParse extends Emiter {
}
loger.log("SEEK->APE", ApeConsts(_apeId), this._recordPlaybackTimestamp, "没有查找到相连的数据");
}
_searchMediaApeMessageKeyfram(_apeMessages){
loger.log("_searchMediaApeMessageKeyfram->SEEK->APE")
if(_apeMessages) {
for (let k in _apeMessages) {
let channelInfos = _apeMessages[k];
let messageItem;
let keyFrameSeekTime = 0;
for (let i = this._recordPlaybackTimestamp; i > 0; i--) {
messageItem = channelInfos[i];
if (messageItem) {
keyFrameSeekTime = (this._recordPlaybackTimestamp - i);
loger.log("_searchMediaApeMessageKeyfram->SEEK->APE->messageItem",messageItem,'keyFrameSeekTime->',keyFrameSeekTime)
this._everSocketMsgReceivedHandler(messageItem.byteData, keyFrameSeekTime);
/*for (let k = 0; k < messageItem.length; k++) {
this._everSocketMsgReceivedHandler(messageItem[k].byteData, keyFrameSeekTime);
}
if (_apeId == ApeConsts.AUDIO_SESSION_ID || _apeId == ApeConsts.VIDEO_SESSION_ID) {
this._emit(MessageTypes.RECORD_PLAYBACK_UPDATE, {
"status": SEEK,
"keyFrameSeekTime": keyFrameSeekTime
});
}
return;*/
}
}
}
}
}
//查找聊天模块ape关键帧数据,聊天模块比较特殊,消息是累积的,当前时间戳之前的都需要显示
_searchChatHistoryMessageKeyfram(_apeMessages) {
//最多30条数据
... ... @@ -476,6 +513,156 @@ class RecordPlayBackParse extends Emiter {
}
}
}
// 数据同步处理 regBuffer已经解开的数据,timestamp 时间戳,data原始数据 ApeConsts.VIDEO_SESSION_ID
_pduRegAdapterHandler(regBuffer,timestamp,data,sessionId) {
console.log('RCAdapterPdu--->')
let regPdu;
let regItems ;
let regItemSize ;
try{
regPdu = pdu['RCAdapterPdu'].decode(regBuffer);
regItems = regPdu.item;
regItemSize = regItems.length;
}catch (err){
console.warn('RCAdapterPdu->unpack-error',err)
return;
}
//onsole.log('RCAdapterPdu',regPdu)
//loger.log(this._session_name + '数据同步消息');
//loger.log(this._session_name + '数据同步消息.同步条数', regItemSize,"seekTime->",seekTime);
for (var i = 0; i < regItemSize; ++i) {
let regItem = regItems[i];
let regItemType = regItem.type;
let regItemData = regItem.itemData;
//根据数据包中的type处理数据是否同步
if (pdu.RCPDU_REG_UPDATE_OBJ !== regItemType) {
if (pdu.RCPDU_REG_RESPONSE_OBJ == regItemType) {
let regResponsePdu = pdu['RCRegistryResponseObjPdu'].decode(regItemData);
console.log('regResponsePdu',regResponsePdu)
//this.regResponsePduHandler(regResponsePdu);
}
// 只处理两种类型
continue;
}
//具体的数据包
let regUpdatedItem = pdu['RCRegistryUpdateObjPdu'].decode(regItemData);
let sub_type = regUpdatedItem.subType;
let object_id = regUpdatedItem.objId;
let user_data = regUpdatedItem.userData;
//console.log('RCRegistryUpdateObjPdu',regUpdatedItem)
switch (sub_type) {
case pdu.RCPDU_REG_ROSTER_INSERT_PDU:
//let rosterInsertData = pdu['RCRegstryRosterInsertItemPdu'].decode(user_data);
// loger.log('RCPDU_REG_ROSTER_INSERT_PDU---->');
let rosterInsertData = pdu['RCRegistryRosterInsertItemPdu'].decode(user_data);
// console.log('RCRegistryRosterInsertItemPdu',rosterInsertData)
let rosterInsertItems = rosterInsertData.items;
let rosterInsertItemsLen = rosterInsertItems.length;
for (let i = 0; i < rosterInsertItemsLen; ++i) {
let record = rosterInsertItems[i];
let recordId = record.item_id;
let recordData = pdu['RCNodeInfoRecordPdu'].decode(record.item_data);
//this.rosterInsertHandler(recordId, recordData);
//console.log('RCNodeInfoRecordPdu',recordData)
}
break;
case pdu.RCPDU_REG_ROSTER_DELETE_PDU:
let rosterDelData = pdu['RCRegistryRosterDeleteItemPdu'].decode(user_data);
// console.log('RCRegistryRosterDeleteItemPdu',rosterDelData)
// this.rosterDelHandler(rosterDelData.nodeId);
break;
case pdu.RCPDU_REG_ROSTER_UPDATE_PDU:
let rosterUpdateData = pdu['RCRegistryRosterUpdateItemPdu'].decode(user_data);
let rosterUpdateItems = rosterUpdateData.items;
let rosterUpdateItemsLen = rosterUpdateItems.length;
//console.log('RCRegistryRosterUpdateItemPdu',rosterUpdateData)
for (let i = 0; i < rosterUpdateItemsLen; ++i) {
let node = rosterUpdateItems[i];
let nodeId = node.nodeId;
let nodeData = pdu['RCNodeInfoRecordPdu'].decode(node.nodeData);
// console.log('RCNodeInfoRecordPdu',nodeData)
//this.rosterUpdateHandler(nodeId, nodeData);
}
break;
case pdu.RCPDU_REG_TABLE_INSERT_PDU:
let tableInsertData = pdu['RCRegistryTableInsertItemPdu'].decode(user_data);
let tableInsertItems = tableInsertData.items;
let tableInsertItemsLen = tableInsertItems.length;
//console.log('RCRegistryTableInsertItemPdu',tableInsertData)
for (let i = 0; i < tableInsertItemsLen; ++i) {
let insertItem = tableInsertItems[i];
//loger.log("insertItem",insertItem);
//this.tableInsertHandler(insertItem.owner, insertItem.itemIdx, insertItem.itemData);
}
//文档数据数组内部自己处理数组
//this.tableInsertApeHandler(tableInsertItems);
break;
case pdu.RCPDU_REG_TABLE_DELETE_PDU:
let tableDeleteData = pdu['RCRegistryTableDeleteItemPdu'].decode(user_data);
//console.log("tableDeleteData",object_id,tableDeleteData);
// console.log('RCRegistryTableDeleteItemPdu',tableDeleteData)
//this.tableDeleteHandler(object_id, tableDeleteData);
break;
case pdu.RCPDU_REG_TABLE_UPDATE_PDU:
let tableUpdateData = pdu['RCRegistryTableUpdateItemPdu'].decode(user_data);
let tableUpdateItems = tableUpdateData.items;
let tableUpdateItemsLen = tableUpdateItems.length;
//loger.log("RCRegistryTableUpdateItemPdu " + tableUpdateItemsLen);
//loger.log(tableUpdateData);
//console.log('RCRegistryTableUpdateItemPdu',tableUpdateData);
for (let i = 0; i < tableUpdateItemsLen; ++i) {
let tableItem = tableUpdateItems[i];
// this.tableUpdateHandler(tableItem.owner, tableItem.itemIdx, tableItem.itemData,seekTime);
if(sessionId==ApeConsts.VIDEO_SESSION_ID){
try {
let videoChannelInfo = pdu['RCVideoChannelInfoPdu'].decode(tableItem.itemData);
loger.log('RCVideoChannelInfoPdu->timestamp',timestamp,videoChannelInfo);
//储存音视频模块的数据
if(!this.mediaChannleList[videoChannelInfo.channelId]){
this.mediaChannleList[videoChannelInfo.channelId]={};
}
this.mediaChannleList[videoChannelInfo.channelId][timestamp]={parseData:videoChannelInfo,byteData:data,timestamp: timestamp };
} catch (err) {
loger.log("RCVideoChannelInfoPdu->unPackPdu error,itemIdx=" + tableItem.itemIdx + " err:" + err.message);
}
}else if(sessionId==ApeConsts.AUDIO_SESSION_ID){
try {
let audioChannelInfo = pdu['RCAudioChannelInfoPdu'].decode(tableItem.itemData);
loger.log('RCAudioChannelInfoPdu->timestamp',timestamp,audioChannelInfo);
//储存音视频模块的数据
if(!this.mediaChannleList[audioChannelInfo.channelId]){
this.mediaChannleList[audioChannelInfo.channelId]={};
}
this.mediaChannleList[audioChannelInfo.channelId][timestamp]={parseData:audioChannelInfo,byteData:data,timestamp: timestamp };
} catch (err) {
loger.log("RCAudioChannelInfoPdu->unPackPdu error,itemIdx=" + tableItem.itemIdx + " err:" + err.message);
}
}
}
break;
case pdu.RCPDU_REG_QUEUE_UPDATE_PDU:
case pdu.RCPDU_REG_QUEUE_DELETE_PDU:
case pdu.RCPDU_REG_QUEUE_INSERT_PDU:
loger.warn('REG QUEUE ARE IGNORED');
break;
}
}
}
}
... ...
// //////////////////////////////////////////////////////////////////////////////
//视频模块
// //////////////////////////////////////////////////////////////////////////////
import Ape from './Ape';
import ApeConsts from './ApeConsts';
import pdu from 'pdus';
import Loger from 'Loger';
import MessageTypes from 'MessageTypes';
import GlobalConfig from 'GlobalConfig';
import EngineUtils from 'EngineUtils';
import MediaModule from "./MediaModule";
let loger = Loger.getLoger('RecordApe');
class RecordApe extends Ape {
constructor() {
super(
ApeConsts.VIDEO_SESSION_ID,
ApeConsts.VIDEO_SESSION_NAME,
ApeConsts.VIDEO_SESSION_TAG
);
this.mediaModule=new MediaModule();
this.mediaModule.MEDIA_OBJ_TABLE_ID=ApeConsts.VIDEO_OBJ_TABLE_ID;
this.mediaModule.mediaChannels={};
this.mediaModule.mediaType=ApeConsts.MEDIA_TYPE_VIDEO;
// Ape Models
this.registerKey(this._session_id, this._session_name, this._session_tag, new ArrayBuffer);
this.registerObj(pdu.RCPDU_REG_REGISTER_TABLE, ApeConsts.VIDEO_OBJ_TABLE_ID, ApeConsts.VIDEO_OBJ_TABLE_NAME, ApeConsts.VIDEO_OBJ_TABLE_TAG, 0, new ArrayBuffer);
// videoApe 监听视频控制消息,用户之间的消息传递
this.on(pdu.RCPDU_SEND_VIDEO_DATA_REQUEST, this.receiveVideoCommandHandler.bind(this));
}
//ape加入成功
onJoinChannelHandlerSuccess(){
//这个设置很重要,因为只有Sass流程完成之后,APE才能取得GlobalConfig中的数据
this.mediaModule.maxMediaChannel=GlobalConfig.maxVideoChannels;
}
/////////////发送数据操作////////////////////////////////////////////
//获取播流地址
getPlayVideoPath(_param) {
loger.log('getPlayVideoPath');
return this.mediaModule.getMediaPlayPath(_param);
}
//获取推流地址
getPublishVideoPath(_param) {
loger.log('获取推流地址->');
if(!this.mcu.connected){
loger.warn(GlobalConfig.getCurrentStatus());
return {"code": ApeConsts.RETURN_FAILED, "data": "已经断开连接"};
}
//监课比较特殊,不占用课堂内的音视频路数,额外创建
if(GlobalConfig.userRole==ApeConsts.invisible){
let result=this.mediaModule.getMediaPublishPathForInVisible(_param);
//this._emit( MessageTypes.VIDEO_GET_PUBLISH_PATH,result);
return result;
}
//非监课的身份,需要判断是否可以继续推流
//需要判断当前已经使用的流路数
let openChannel=0;
let allChannels= MediaModule.allMediaChannelsList;
for(let i in allChannels){
let channel=allChannels[i];
if(channel&&channel.status==ApeConsts.CHANNEL_STATUS_OPENING){
openChannel++;
}
}
//如果已经开启的数量大于等于最大允许开启的数量,不允许再推流
if(openChannel>=GlobalConfig.maxMediaChannels){
loger.warn('不能再打开设备->当前开启的设备数量->',openChannel);
return {"code": ApeConsts.RETURN_FAILED, "data": "不能再打开设备,当前开启的设备数量"};
}
let result=this.mediaModule.getMediaPublishPath(_param);
//this._emit( MessageTypes.VIDEO_GET_PUBLISH_PATH,result);
return result;
}
//获取当前所有频道信息
getAllChannelInfo(_param){
loger.log('获取当前所有频道信息->');
return this.mediaModule.getAllMediaChannelInfo();
}
//推流
publishVideo(_param) {
if(!this.mcu.connected){
loger.warn(GlobalConfig.getCurrentStatus());
//this._emit( MessageTypes.VIDEO_PUBLISH_RESULT,{"code": ApeConsts.RETURN_FAILED, "data":"已经断开连接!","mediaId":0});
return {"code": ApeConsts.RETURN_FAILED, "data": "已经断开连接"};
}
if (_param == null||_param.publishUrl == null)
{
loger.warn('推流->参数错误', _param);
//this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG);
//this._emit( MessageTypes.VIDEO_PUBLISH_RESULT,{"code": ApeConsts.RETURN_FAILED, "data":"参数错误!","mediaId":0});
return {"code": ApeConsts.RETURN_FAILED, "data": "参数错误"};
}
//根据推流的地址获取对应的频道信息
let needPublishChannelInfo=this.mediaModule.getNeedPublishMediaChannel(_param.publishUrl);
if(needPublishChannelInfo==null){
loger.warn('推流->推流数据已经无效', _param);
//this._emit( MessageTypes.VIDEO_PUBLISH_RESULT,{"code": ApeConsts.RETURN_FAILED, "data":"推流数据已经无效!","mediaId":0});
return {"code": ApeConsts.RETURN_FAILED, "data": "推流数据已经无效"};
}
//判断当前是否还有空闲的channle
let freeChannel = this.mediaModule.getFreeMediaChannel();
if (freeChannel == 0) {
loger.warn("推流->不能再打开更多的设备 ");
//this._emit( MessageTypes.VIDEO_PUBLISH_RESULT,{"code": ApeConsts.RETURN_FAILED, "data":"不能再打开更多的设备!","mediaId":0});
return {"code": ApeConsts.RETURN_FAILED, "data": "不能再打开更多的设备","mediaChannels":this.mediaModule.mediaChannels};
}
//判断当前的频道是否已经占用
if(this.mediaModule.checkChannelIsOpening(needPublishChannelInfo.channelId)){
if(needPublishChannelInfo.nodeId==GlobalConfig.nodeId){
loger.warn(needPublishChannelInfo.channelId,"已经推送过消息,不需要再次推送");
//this._emit( MessageTypes.VIDEO_PUBLISH_RESULT,{"code": ApeConsts.RETURN_SUCCESS, "data":"已经推送过消息,不需要再次推送!","mediaId":needPublishChannelInfo.channelId});
return {"code": ApeConsts.RETURN_SUCCESS, "data":"已经推送过消息,不需要再次推送!","mediaId":needPublishChannelInfo.channelId};
}else {
loger.warn(needPublishChannelInfo.channelId,"频道已经被占用");
//this._emit( MessageTypes.VIDEO_PUBLISH_RESULT,{"code": ApeConsts.RETURN_FAILED, "data":"频道已经被占用!","mediaId":0});
return {"code": ApeConsts.RETURN_FAILED, "data":"频道已经被占用!","mediaChannels":this.mediaModule.mediaChannels};
}
}
let channelInfo=this.mediaModule.getDefaultChannelInfo();
channelInfo.owner=GlobalConfig.nodeId;
channelInfo.status=ApeConsts.CHANNEL_STATUS_OPENING;
channelInfo.channelId=needPublishChannelInfo.channelId;
channelInfo.streamId=needPublishChannelInfo.streamId;//按规则拼接的流名称
channelInfo.timestamp=needPublishChannelInfo.timestamp;//时间戳
channelInfo.mediaType=ApeConsts.MEDIA_TYPE_VIDEO;
this.sendTableUpdateHandler(channelInfo);
//this._emit( MessageTypes.VIDEO_PUBLISH_RESULT,{"code": ApeConsts.RETURN_SUCCESS, "data":"推流成功!","mediaId":needPublishChannelInfo.channelId});
return {"code": ApeConsts.RETURN_SUCCESS, "data":"推流成功!","mediaId":needPublishChannelInfo.channelId};
}
//停止推流,
stopPublishVideo(_param) {
loger.log('停止推流->',_param);
if(!this.mcu.connected){
loger.warn(GlobalConfig.getCurrentStatus());
return {"code": ApeConsts.RETURN_FAILED, "data": "已经断开连接"};
}
//默认为自己的nodeId,_param如果为空,那么默认就是当前自己的nodeId,否则用_param
let nodeId=GlobalConfig.nodeId;
if(_param&&parseInt(_param.nodeId)>0){
nodeId=parseInt(_param.nodeId);
}
//默认为0,如果releaseChannelId 存在就释放releaseChannelId通道
let releaseChannelId=0;
if(_param&&parseInt(_param.mediaId)>0){
releaseChannelId=parseInt(_param.mediaId);
}
//释放channelId 的占用
if(releaseChannelId>0){
//第一种情况,释放nodeId占用的指定mediaId (channelId)
this._releaseChannelForNodeId(nodeId,releaseChannelId);
}else {
//第二种情况,释放nodeId占用的所有channelId
this._releaseNodeIdAllChannel(nodeId);
}
}
//释放nodeId占用的指定的channelId频道
_releaseChannelForNodeId(nodeId,channelId){
loger.log(nodeId,"_releaseChannelForNodeId-->channelId",channelId);
let channelInfo=this.mediaModule.mediaChannels[channelId];
if(channelInfo&&channelInfo.status==ApeConsts.CHANNEL_STATUS_OPENING){
if(channelInfo.fromNodeId==nodeId){
let channelInfo=this.mediaModule.getDefaultChannelInfo();
channelInfo.status=ApeConsts.CHANNEL_STATUS_RELEASED;
channelInfo.channelId=channelId;
this.sendTableUpdateHandler(channelInfo);
}else {
loger.warn(channelId,"不属于nodeId",nodeId,"不能释放",channelInfo);
}
}else {
loger.warn(nodeId,"要释放的channel不存在或者已经释放-->channelId",channelInfo);
}
}
//释放nodeId占用的所有频道
_releaseNodeIdAllChannel(nodeId){
loger.log(nodeId,"_releaseNodeIdAllChannel",this.mcu.connected);
if(!this.mcu.connected){
clearTimeout(this.releaseTimeId);
loger.warn(GlobalConfig.getCurrentStatus());
return {"code": ApeConsts.RETURN_FAILED, "data": "已经断开连接"};
}
let openingChannel = this.mediaModule.getOpeningMediaChannel(nodeId);
if (openingChannel == 0) {
loger.warn(nodeId,"没有占用channel不需要处理");
return {"code": ApeConsts.RETURN_FAILED, "data": "没有占用channel不需要处理"};
}
let channelInfo=this.mediaModule.getDefaultChannelInfo();
channelInfo.status=ApeConsts.CHANNEL_STATUS_RELEASED;
channelInfo.channelId=openingChannel;
this.sendTableUpdateHandler(channelInfo);
//递归检查,800毫秒之后执行
this.releaseTimeId=setTimeout(function(){
loger.warn(nodeId,"检查频道是否占用");
this._releaseNodeIdAllChannel(nodeId);
}.bind(this),800);
}
sendVideoBroadcastMsg(_param) {
if(!this.mcu.connected){
loger.warn(GlobalConfig.getCurrentStatus());
return {"code": ApeConsts.RETURN_FAILED, "data": "已经断开连接"};
}
if (this._classInfo === null || EngineUtils.isEmptyObject(this._classInfo)) {
loger.log('不能发送Video消息.McuClient还未初始化数据!');
if (GlobalConfig.getCurrentStatus().code == 0 || GlobalConfig.getCurrentStatus().code == 1) {
//this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_SEND_FAILED_NO_JOIN);
return {"code": 1, "data": "不能发送Video消息.McuClient还未初始化数据"};
}
return {"code": ApeConsts.RETURN_FAILED, "data": "不能发送Video消息.McuClient还未初始化数据"};
}
if (_param == null) {
loger.warn('sendVideoCommandMsg失败,参数错误', _param);
//this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG);
return {"code": ApeConsts.RETURN_FAILED, "data": "sendVideoCommandMsg失败,参数错误"};
}
// to, message
loger.log('发送Video消息.', _param);
if (_param.actionType != null && _param.actionType == ApeConsts.MEDIA_ACTION_OPEN_CAMERA) {
//判断当前开启的视频数量是否已经是最大值,如果已经是最大值,不能再开启
let freeChannel = this.mediaModule.getFreeMediaChannel();
if (freeChannel == 0) {
loger.warn('sendVideoCommandMsg,不能再打开更多的设备', _param);
return {"code": ApeConsts.RETURN_FAILED, "data": "不能再打开更多的设备","mediaChannels":this.mediaModule.mediaChannels};
}
}
let videoSendPdu = new pdu['RCVideoSendDataRequestPdu'];
videoSendPdu.type = pdu.RCPDU_SEND_VIDEO_DATA_REQUEST;
videoSendPdu.isPublic = true;
videoSendPdu.fromNodeId = GlobalConfig.nodeId;//发起人
videoSendPdu.toNodeId = parseInt(_param.toNodeId) || 0;//接收者,0就是所有人
videoSendPdu.actionType = parseInt(_param.actionType) || ApeConsts.MEDIA_ACTION_DEFAULT;
let dataStr='';
try{
dataStr=JSON.stringify(_param.data);
}catch (err){
loger.warn('控制消息->JSON转换失败');
dataStr=_param.data;
}
videoSendPdu.data = this._rCArrayBufferUtil.strToUint8Array("h5" + dataStr);//开头两个字会乱码
if (!videoSendPdu.isPublic && 0 != videoSendPdu.toNodeId) {
//发送给制定的人
//loger.log('发送私聊Video消息.');
this.send(videoSendPdu);
} else {
//发送给所有人
//loger.log('发送公聊Video消息.');
this.sendChatUniform(videoSendPdu);
}
return {"code": ApeConsts.RETURN_SUCCESS, "data": ""};
}
//发送到mcu同步(更新数据)
sendTableUpdateHandler(_channelInfo) {
loger.log("video===sendTableUpdateHandler ");
let updateModelPdu = this.packPdu(_channelInfo, _channelInfo.channelId);//let updateModelPdu=this.packPdu({},ApeConsts.VIDEO_OBJ_TABLE_ID+2);
if(updateModelPdu==null){
loger.warn("sendTableUpdateHandler error,updateModelPdu=null");
return;
}
let tableItemPdu = new pdu['RCRegistryTableItemPdu'];
tableItemPdu.itemIdx = _channelInfo.channelId;//tableItemPdu.itemIdx=ApeConsts.VIDEO_OBJ_TABLE_ID+2;
tableItemPdu.owner = _channelInfo.owner;//0收到flash的是这个值,MCU做了了用户掉线处理,30秒之后会清理owner为0
tableItemPdu.itemData = updateModelPdu.toArrayBuffer();
//insert
let tableInsertItemPdu = new pdu['RCRegistryTableUpdateItemPdu'];
tableInsertItemPdu.type = pdu.RCPDU_REG_TABLE_UPDATE_PDU;//
tableInsertItemPdu.items.push(tableItemPdu);
let updateObjPdu = new pdu['RCRegistryUpdateObjPdu'];
updateObjPdu.objId = ApeConsts.VIDEO_OBJ_TABLE_ID;//
updateObjPdu.subType = tableInsertItemPdu.type;
updateObjPdu.userData = tableInsertItemPdu.toArrayBuffer();
//同步
let adapterItemPdu = new pdu['RCAdapterItemPdu'];
adapterItemPdu.type = pdu.RCPDU_REG_UPDATE_OBJ;
adapterItemPdu.itemData = updateObjPdu.toArrayBuffer();
let adapterPdu = new pdu['RCAdapterPdu'];
adapterPdu.type = pdu.RCPDU_REG_ADAPTER;
adapterPdu.item.push(adapterItemPdu);
loger.log("发送更新VIDEO.itemIdx=" + tableItemPdu.itemIdx);
this.sendUniform(adapterPdu, true);
}
/////收到消息处理//////////////////////////////////////////////////
// 视频消息处理,内部处理,不需要告诉应用层
receiveVideoCommandHandler(_data) {
let videoReceivePdu = pdu['RCVideoSendDataRequestPdu'].decode(_data);
if (videoReceivePdu == null) {
loger.warn("视频控制消息处理,收到的消息为null,不做处理");
return;
}
videoReceivePdu.data = this._rCArrayBufferUtil.uint8ArrayToStr(videoReceivePdu.data, 2);//开头两个字会乱码
let dataObj= {};
try{
dataObj=JSON.parse(videoReceivePdu.data);
}catch (err){
loger.warn('控制消息->JSON转换失败');
dataObj= videoReceivePdu.data;
}
videoReceivePdu.data=dataObj;
//判断接收者的id,如果不是0,并且也不是自己的nodeId,那么消息不做处理
if (videoReceivePdu.toNodeId != 0 && videoReceivePdu.toNodeId != GlobalConfig.nodeId) {
loger.log('视频消息不处理 toNodeId=', videoReceivePdu.toNodeId, "my nodeId=", GlobalConfig.nodeId);
} else {
loger.log('视频控制消息处理 .',videoReceivePdu);
//this._emit(MessageTypes.VIDEO_BROADCAST, videoReceivePdu);
}
}
tableUpdateHandler(owner, itemIdx, itemData,seek) {
// debugger;
let unpackChannelInfo = this.unPackPdu(owner, itemIdx, itemData);
loger.log("tableUpdateHandler->channel",itemIdx,'status->',unpackChannelInfo.status,"seek->",seek);
//****很重要********
//如果owner的值为0,代表的是这个歌频道已经被释放了(mcu服务端对于占用channel的掉线用户,就是把owner设置为0)
if(owner==0){
loger.log("释放占用的频道,channel",itemIdx);
unpackChannelInfo.status=ApeConsts.CHANNEL_STATUS_RELEASED;
unpackChannelInfo.streamId="";
}
this.mediaModule.mediaChannels[itemIdx] = unpackChannelInfo;
if(unpackChannelInfo&&unpackChannelInfo.fromNodeId!=GlobalConfig.nodeId){
let receiveChannelInfo={};
receiveChannelInfo.mediaId=unpackChannelInfo.channelId;
receiveChannelInfo.fromNodeId=unpackChannelInfo.fromNodeId;
receiveChannelInfo.userName=unpackChannelInfo.userName||"";
receiveChannelInfo.userRole=unpackChannelInfo.userRole||ApeConsts.normal;
//消息不是自己同步的,需要处理
if(unpackChannelInfo.status==ApeConsts.CHANNEL_STATUS_OPENING){
//正在推流
receiveChannelInfo.m3u8Url="";
receiveChannelInfo.rtmpUrl="";
receiveChannelInfo.replay="";
receiveChannelInfo.seek=seek||0;//这个是录制回放时使用的seek
let m3u8Stream=this.mediaModule.getMediaPlayPath({"type":"m3u8","streamId": unpackChannelInfo.streamId});
let rtmpStream=this.mediaModule.getMediaPlayPath({"type":"rtmp","streamId": unpackChannelInfo.streamId});
let replay=this.mediaModule.getMediaRecordPlaybackPath({"type":"m3u8","streamId": unpackChannelInfo.streamId});
if(m3u8Stream.code==0){
receiveChannelInfo.m3u8Url=m3u8Stream.playUrl;
}
if(rtmpStream.code==0){
receiveChannelInfo.rtmpUrl=rtmpStream.playUrl;
}
if(replay.code==0){
receiveChannelInfo.replay=replay.playUrl;
}
loger.log("VIDEO_PLAY",receiveChannelInfo);
//广播播放视频的消息
//this._emit(MessageTypes.VIDEO_PLAY, receiveChannelInfo);
}else {
loger.log("VIDEO_STOP",receiveChannelInfo);
//流已经停止
//this._emit(MessageTypes.VIDEO_STOP, receiveChannelInfo);
}
}else {
loger.warn("视频消息是自己发送的或者是视频消息无效,不需要处理,消息内容如下:");
loger.log(unpackChannelInfo);
if(unpackChannelInfo.status==ApeConsts.CHANNEL_STATUS_OPENING){
GlobalConfig.openCamera=EngineUtils.creatTimestamp();
GlobalConfig.openMicrophones=GlobalConfig.openCamera;
}else {
GlobalConfig.openCamera=0;
GlobalConfig.openMicrophones=0;
}
//this._emit(MessageTypes.USER_DEVICE_STATUS_CHAANGE,{
// nodeId:GlobalConfig.nodeId,
// userRole:GlobalConfig.userRole,
// userName:GlobalConfig.userName,
// userId:GlobalConfig.userId,
// openCamera:GlobalConfig.openCamera,
// openMicrophones:GlobalConfig.openMicrophones
// });
}
MediaModule.allMediaChannelsList[itemIdx]=unpackChannelInfo;
console.log('MediaModule.allMediaChannelsList',MediaModule.allMediaChannelsList);
//this._emit(MessageTypes.VIDEO_UPDATE, unpackChannelInfo);
}
///////数据的封包和解包/////////////////////////////////////////
packPdu(_param, _itemIdx) {
loger.log("packPdu ");
//验证坐标点集合数组是否合法
if (_param == null || _itemIdx == null) {
//this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG);
return null;
}
//判断type类型,根据type设置不同的参数
let packPduModel = new pdu['RCVideoChannelInfoPdu'];
packPduModel.status = _param.status||ApeConsts.CHANNEL_STATUS_RELEASED;
packPduModel.channelId = _itemIdx;
packPduModel.streamId = _param.streamId||"";
packPduModel.siteId=_param.siteId||GlobalConfig.siteId;//GlobalConfig.siteId;
packPduModel.classId =parseInt(_param.classId)||parseInt(GlobalConfig.classId);
packPduModel.userId =_param.userId||"0";
packPduModel.mediaType =_param.mediaType|| ApeConsts.MEDIA_TYPE_VIDEO;
packPduModel.timestamp =_param.timestamp||0;
packPduModel.fromNodeId = GlobalConfig.nodeId;
packPduModel.userName=GlobalConfig.userName||"";
packPduModel.toNodeId = 0;
packPduModel.userRole=GlobalConfig.userRole||ApeConsts.normal;
loger.log(packPduModel);
return packPduModel;
}
unPackPdu(owner, itemIdx, itemData) {
loger.log("unPackPdu->owner:",owner,"itemIdx->",itemIdx);
if (owner == null || itemIdx == null || itemData == null) {
//this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG);
return null;
}
try {
let videoChannelInfo = pdu['RCVideoChannelInfoPdu'].decode(itemData);
loger.log(videoChannelInfo);
return videoChannelInfo;
} catch (err) {
loger.log("unPackPdu error,itemIdx=" + itemIdx + " err:" + err.message);
}
return null;
}
}
export default RecordApe;