Toggle navigation
Toggle navigation
此项目
正在载入...
Sign in
李勇
/
McuClient
转到一个项目
Toggle navigation
项目
群组
代码片段
帮助
Toggle navigation pinning
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Authored by
李勇
2017-05-18 12:20:31 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
e2502d918235a9acde0acbf6c38a5d8c1ae9446e
e2502d91
1 parent
169b80b8
修复录制回放多路音视频,在seek拖动播放的时候,显示数量不正确的问题
隐藏空白字符变更
内嵌
并排对比
正在显示
4 个修改的文件
包含
194 行增加
和
479 行删除
dist/McuClient.js
src/EngineEntrance.js
src/RecordPlayBackParse.js
src/apes/RecordApe.js
dist/McuClient.js
查看文件 @
e2502d9
此 diff 太大无法显示。
src/EngineEntrance.js
查看文件 @
e2502d9
...
...
@@ -28,7 +28,7 @@ import MediaModule from 'apes/MediaModule';
import
UTF8
from
'utf-8'
;
let
loger
=
Loger
.
getLoger
(
'McuClient'
);
let
_sdkInfo
=
{
"version"
:
"v1.2
2.0.201705017
"
,
"author"
:
"www.3mang.com"
};
let
_sdkInfo
=
{
"version"
:
"v1.2
3.0.201705018
"
,
"author"
:
"www.3mang.com"
};
//APE
let
_sass
;
...
...
src/RecordPlayBackParse.js
查看文件 @
e2502d9
...
...
@@ -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
.
_search
Seek
Keyfram
();
}
_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
;
}
}
}
}
...
...
src/apes/RecordApe.js
已删除
100644 → 0
查看文件 @
169b80b
// //////////////////////////////////////////////////////////////////////////////
//视频模块
// //////////////////////////////////////////////////////////////////////////////
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
;
请
注册
或
登录
后发表评论