李勇

1.增加视频模块,整理数据的pdu

... ... @@ -116,6 +116,8 @@ export default class MessageEntrance extends Emiter {
this.getPublishVideoPath = this._getPublishVideoPath;
this.publishVideo = this._publishVideo;
this.stopPublishVideo = this._stopPublishVideo;
this.sendVideoCommandMsg=this.sendVideoCommandMsg;
//whiteBoradApe
this.sendInsertAnnotaion = this._sendInsertAnnotaion;
... ... @@ -620,6 +622,12 @@ export default class MessageEntrance extends Emiter {
}
//VidoeApe
sendVideoCommandMsg(_param){
if(_video_ape){
_video_ape.sendVideoCommandMsg(_param);
}
}
_getPlayVideoPath(_param){
if(_video_ape){
return _video_ape.getPlayVideoPath(_param);
... ...
... ... @@ -102,8 +102,8 @@ class EverSocket extends Emiter {
loger.log('WebSocket建立成功', this.wsURL);
//启动心跳,检查socket链接状态
//this.pingTimer = window.setInterval(this._sendPingHandler.bind(this), EverSocket.PING_INTERVAL);
//this.pongTimer = window.setInterval(this._checkPongHandler.bind(this), EverSocket.PONG_INTERVAL);
this.pingTimer = window.setInterval(this._sendPingHandler.bind(this), EverSocket.PING_INTERVAL);
this.pongTimer = window.setInterval(this._checkPongHandler.bind(this), EverSocket.PONG_INTERVAL);
this._setConnected();
}
... ...
... ... @@ -253,9 +253,9 @@ GlobalConfig.port="80";
GlobalConfig.MCUServerIP="114.215.195.70";
GlobalConfig.docServer="";//当前的文档地址加载的服务器地址
GlobalConfig.MCUServerPort=9003;
GlobalConfig.maxVideoChannels=1;
GlobalConfig.maxAudioChannels=1;
GlobalConfig.maxMediaChannels=2;
GlobalConfig.maxVideoChannels=0;
GlobalConfig.maxAudioChannels=0;
GlobalConfig.maxMediaChannels=0;
GlobalConfig.isDebug=false;
GlobalConfig.deBugData={};
... ...
... ... @@ -3,6 +3,8 @@ import Loger from 'Loger';
import MessageTypes from 'MessageTypes';
import GlobalConfig from 'GlobalConfig';
import MD5 from "md5";
import ApeConsts from 'apes/ApeConsts';
// 日志对象
const loger = Loger.getLoger('Sass');
... ... @@ -105,7 +107,7 @@ class Sass extends Emiter {
*/
//判断是否是老师
let isTeacher=0;
if(confInfo.userRole=="host"){
if(confInfo.userRole==ApeConsts.host){
isTeacher=1
}
... ...
... ... @@ -6,6 +6,7 @@ export default function ApeConsts(id) {
}
}
//课堂状态
ApeConsts.CLASS_STATUS_WAIT= 0;//课堂还未开始
ApeConsts.CLASS_STATUS_STARTED= 1;//直播中
... ... @@ -27,6 +28,19 @@ ApeConsts.CLASS_ACTION_CLOSE_ALL=1;//所有人关闭会议
ApeConsts.CLASS_TYPE_INTERACT= 1; // 互动课堂,通过MS转发音视频,不能进行H5观看
ApeConsts.CLASS_TYPE_LIVE= 2; // 直播课堂,通过CDN转发音视频,不能进行音视频互动
/*
flash
public static const NR_GUEST:uint = 0; // 客人
public static const NR_NORMAL:uint = 1; // 普通与会者
public static const NR_ADMIN:uint = 2; // 管理员
public static const NR_MASTER:uint = 4; // 主持人
public static const NR_SLAVE:uint = 8; // 主讲人
public static const NR_ASSISTANT:uint = 16; // 助教
public static const NR_INVISIBLE:uint = 32; // 隐身用户
*/
//角色身份
ApeConsts.NR_GUEST = 0; // 客人
ApeConsts.NR_NORMAL = 1;// 普通与会者
... ... @@ -36,7 +50,6 @@ ApeConsts.NR_SLAVE = 8; // 主讲人
ApeConsts.NR_ASSISTANT = 16; // 助教
ApeConsts.NR_INVISIBLE = 32; // 隐身用户
//用户的身份,5种类型:
ApeConsts.host="host";//(主持人/老师)
ApeConsts.presenter="presenter";//(主讲人)
... ... @@ -45,6 +58,37 @@ ApeConsts.normal="normal";//(普通角色/学生)
ApeConsts.record="record";//(暂时没用.
/*msType type*/
ApeConsts.MS_TYPE_DEFAULT= 0;//默认MS,(废弃)
ApeConsts.MS_TYPE_FMS= 1;//第三方FMS,目前一直用这个
//用户状态
ApeConsts.USER_HAND_UP = 0x0020; // 举手
ApeConsts.USER_MIC_OPEN = 0x0040; // 麦克风开启
ApeConsts.USER_CAMERA_OPEN = 0x0080; // 视频开启
//VIDEO MIC
ApeConsts.OPEN_CAMERA= "open.camera";
ApeConsts.CLOSE_CAMERA= "close.camera";
ApeConsts.OPEN_MIC= "open.mic";
ApeConsts.CLOSE_MIC= "close.mic";
// VIDEO AUDIO CHANNEL使用状态
ApeConsts.CHANNEL_STATUS_RELEASED = 0;///< 无人占用状态
ApeConsts.CHANNEL_STATUS_OPENING = 1;///< 已经占用成功
//FLASH中使用下面4个
ApeConsts.CGS_RELEASED = 0;///< 无人占用状态
ApeConsts.CGS_PENDING = 1;///< 占用成功,等待打开
ApeConsts.CGS_OPENNED = 2;///< 打开成功
ApeConsts.CGS_GRABBING = 3; ///< 准备占用中, 属于本地状态机需要用的状态,在多点数据库中不存在。
ApeConsts.INVALIDATE_CHANNEL_ID = -1;
ApeConsts.INVALIDATE_NODE_ID = -1;
... ... @@ -55,12 +99,6 @@ ApeConsts.DOC_ACTION_SWITCH_PAGE=2;//文档翻页
ApeConsts.DOC_ACTION_COMMAND=3;//文档操作:滚动、缩放
// RCChannelGrabStatus
ApeConsts.CGS_RELEASED = 0;///< 无人占用状态
ApeConsts.CGS_PENDING = 1;///< 占用成功,等待打开
ApeConsts.CGS_OPENNED = 2;///< 打开成功
ApeConsts.CGS_GRABBING = 3; ///< 准备占用中, 属于本地状态机需要用的状态,在多点数据库中不存在。
// defs for common session id
ApeConsts.CONFERENCE_SESSION_ID = 11;
ApeConsts.CHAT_SESSION_ID = 12;
... ...
... ... @@ -163,7 +163,7 @@ class DocApe extends Ape {
}
if(fullPath&&fullPath.indexOf("http://")<0){
fullPath="http;//"+fullPath;
fullPath="http://"+fullPath;
}
loger.warn('getDocFullPath ->',fullPath);
return [fullPath];
... ...
... ... @@ -18,6 +18,8 @@ import ApeConsts from './ApeConsts';
import pdu from 'pdus';
import Loger from 'Loger';
import MessageTypes from 'MessageTypes';
import GlobalConfig from 'GlobalConfig';
import EngineUtils from 'EngineUtils';
let loger = Loger.getLoger('VideoChat');
... ... @@ -41,9 +43,8 @@ class VideoChat extends Ape {
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);
// ape listeners
this.on(pdu.RCPDU_VIDEO_SEND_DATA_REQUEST, this.videoIncomingHandler.bind(this));
// videoApe 监听视频控制消息,用户之间的消息传递
this.on(pdu.RCPDU_VIDEO_SEND_DATA_REQUEST, this.videoCommandHandler.bind(this));
}
/////////////发送数据操作//////////////////////////////////////////////////////
//获取播流地址
... ... @@ -54,24 +55,207 @@ class VideoChat extends Ape {
//获取推流地址
getPublishVideoPath(_param){
loger.log('getPublishVideoPath');
//判断当前开启的视频数量是否已经是最大值,如果已经是最大值,不能再开启
return {"code":0,"data":"推流地址XXXXXXXXXXXXXXXXXXXXXXX"};
}
//推流
publishVideo(_param){
loger.log('publishVideo');
loger.log('publishVideo -> maxVideoChannels',GlobalConfig.maxVideoChannels);
this.sendTableUpdateHandler();
/* protected function startPushMessageFlash():void
{
if((!Config.enableCDNServer && !Config.isH5Moudle) ||
Config.customer == Config.customerTaobao ||
Config.msType == Config.MS_TYPE_FMS
)
return;
var obj:Object = new Object;
obj.confID = Config.confID;
obj.streamType = RCNetStream.PRT_CAM_SOUND_FLASH;
obj.uriPush = "rtmp://" + Config.liveServerAddr + ":" + Config.liveServerPort + "/3m/" + streamName;
_streamPublished.send("startPush", obj);
log.info("startPushMessageFlash,startPush streamType:" + obj.streamType);
}*/
/* var rtmpUrl:String = "";
if(Config.msType == Config.MS_TYPE_DEFAULT)
{
rtmpUrl = "rtmp://" + mediaServerAddr + ":" + mediaServerPort;
}
else if(Config.msType == Config.MS_TYPE_FMS)//fms下链接地址 pzm+ 2016.4.12
{
if(Config.clientType == Config.CT_RECORDPLAYER)
{
rtmpUrl = "rtmp://" + mediaServerAddr + ":" + mediaServerPort + "/vod";
}
else
{
rtmpUrl = "rtmp://" + mediaServerAddr + ":" + mediaServerPort + "/live/" + Config.confID;
}
}*/
}
//停止推流
stopPublishVideo(_param){
loger.log('stopPublishVideo.');
loger.log('stopPublishVideo -> maxVideoChannels',GlobalConfig.maxVideoChannels);
this.sendTableUpdateHandler();
}
//
//aaaa(){
// if (event.cmd == ApplicationFacade.OPEN_MIC)
// {
// if (audioDeviceOpenedUsers() >= Config.maxAudioChannels)
// {
// item.closeAudioDevice();
// Alert.show(resourceManager.getString('meeting', 'CannotOpenDeviceAnyMore'),
// resourceManager.getString('meeting', 'AlertWarning'), Alert.OK, item);
// event.stopImmediatePropagation();
// }
// else
// {
// super.updateCamMicStatus(event.camOpened, event.micOpened, event.node_id);
// }
// }
// else if (event.cmd == ApplicationFacade.OPEN_CAMERA)
// {
// if (videoDeviceOpenedUsers() >= Config.maxVideoChannels)
// {
// item.closeVideoDevice();
// Alert.show(resourceManager.getString('meeting', 'CannotOpenDeviceAnyMore'),
// resourceManager.getString('meeting', 'AlertWarning'), Alert.OK, item);
// event.stopImmediatePropagation();
// }
// else
// {
// super.updateCamMicStatus(event.camOpened, event.micOpened, event.node_id);
// }
// }
//}
curAudioDeviceOpenedUsers()
{
//var openedUsers:int = 0;
//var index:int = 0;
//
//for(index = 0; index < _userArray.length; index++)
//{
// var tmpNode:RCNodeInfoRecordPdu = RCNodeInfoRecordPdu(_userArray.getItemAt(index));
// if(tmpNode.status & RCNodeStatus_E.NR_MIC_OPEN)
// {
// openedUsers++;
// }
//}
//
//return openedUsers;
}
curVideoDeviceOpenedUsers()
{
//var openedUsers:int = 0;
//var index:int = 0;
//
//for(index = 0; index < _userArray.length; index++)
//{
// var tmpNode:RCNodeInfoRecordPdu = RCNodeInfoRecordPdu(_userArray.getItemAt(index));
// if(tmpNode.status & RCNodeStatus_E.NR_CAMERA_OPEN)
// {
// openedUsers++;
// }
//}
//return openedUsers;
}
sendVideoCommandMsg(_messageInfo) {
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;
}
return ;
}
// to, message
loger.log('发送Video消息.', _messageInfo);
/* message RCVideoSendDataRequestPdu {
optional uint32 initiator = 1;
optional bool key_frame = 2;
optional uint32 sequence_id = 3;
optional uint32 slice_id = 4;
optional bytes user_data = 5;
}
*/
let videoSendPdu = new pdu['RCVideoSendDataRequestPdu'];
videoSendPdu.type = pdu.RCPDU_VIDEO_SEND_DATA_REQUEST;
videoSendPdu.initiator = GlobalConfig.nodeId;//发起人
videoSendPdu.peer = parseInt(_messageInfo.to);//发送给谁,公聊的时候是0,私聊的时候是指定的用户id
videoSendPdu.userData = this._rCArrayBufferUtil.strToUint8Array("h5" + _messageInfo.message);//开头两个字会乱码
videoSendPdu.isPublic = true;
videoSendPdu.sliceId=_messageInfo.sliceId||0;
if (!videoSendPdu.isPublic && 0!=videoSendPdu.peer) {
//发送给制定的人
loger.log('发送私聊Video消息.');
this.send(videoSendPdu);
} else {
//发送给所有人
loger.log('发送公聊Video消息.');
this.sendChatUniform(videoSendPdu);
}
}
sendTableUpdateHandler(){
loger.log("video===sendTableUpdateHandler ");
/* //验证坐标点集合数组是否合法
if(_docDataModel==null||_itemIdx==null){
this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG);
return null;
}*/
loger.log("video===sendTableUpdateHandler ");
let updateModelPdu=this.packPdu({},ApeConsts.VIDEO_OBJ_TABLE_ID+2);
let tableItemPdu = new pdu['RCRegistryTableItemPdu'];
tableItemPdu.itemIdx=ApeConsts.VIDEO_OBJ_TABLE_ID+2;//直接用时间戳作为id
tableItemPdu.owner = 0;//收到flash的是这个值,不清楚先写固定
tableItemPdu.itemData =updateModelPdu.toArrayBuffer();
//insert
let tableInsertItemPdu = new pdu['RCRegistryTableUpdateItemPdu'];
//optional RCPduType_E type = 1 [default = RCPDU_REG_TABLE_UPDATE_PDU];
//repeated RCRegistryTableItemPdu items = 2;
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("发送更新文档.itemIdx="+tableItemPdu.itemIdx);
this.sendUniform(adapterPdu,true);
}
/////收到消息处理/////////////////////////////////////////////////////////////////////////////////
// 视频消息处理
videoIncomingHandler(videoBuffer) {
let videoReceivePdu = pdu['VideoSendDataRequestPdu'].decode(videoBuffer);
videoCommandHandler(videoBuffer) {
let videoReceivePdu = pdu['RCVideoSendDataRequestPdu'].decode(videoBuffer);
let video_data = { };
video_data._initiator = videoReceivePdu.initiator;
... ... @@ -80,46 +264,45 @@ class VideoChat extends Ape {
video_data._slice_id = videoReceivePdu.sliceId;
video_data._data = videoReceivePdu.userData;
// this._notify(RCApeEvent.E_VIDEO_DATA, videoReceivePdu.sessionId, videoReceivePdu.channelId, video_data);
loger.log('视频消息处理 videoIncomingHandler.', video_data);
this._emit(MessageTypes.VIDEO_RECEIVE, video_data);
loger.log('视频消息处理 videoCommandHandler.', video_data);
//this._emit(MessageTypes.VIDEO_RECEIVE, video_data);
}
tableUpdateHandler(owner, itemIdx, itemData) {
// debugger;
let videoChannelInfo = pdu['RCVideoChannelInfoRecordPdu'].decode(itemData);
videoChannelInfo.owner = owner;
videoChannelInfo.channelId = itemIdx;
videoChannelInfo.status = owner === 0 ? ApeConsts.CGS_RELEASED : videoChannelInfo.status;
loger.log('视频消息处理 tableUpdateHandler.',videoChannelInfo);
let videoChannelInfo =this.unPackPdu(owner, itemIdx, itemData);
//videoChannelInfo.owner = owner;
//videoChannelInfo.channelId = itemIdx;
//videoChannelInfo.status = owner === 0 ? ApeConsts.CHANNEL_STATUS_RELEASED : videoChannelInfo.status;
//loger.log('视频消息处理 tableUpdateHandler.',videoChannelInfo);
this.videoChannels[itemIdx] = videoChannelInfo;
switch (videoChannelInfo.status) {
case ApeConsts.CGS_RELEASED:
case ApeConsts.CGS_PENDING:
case ApeConsts.CGS_GRABBING:
// 只能关闭自己的流
if (this.activeChannelId === videoChannelInfo.channelId) {
this.activeChannelId = 0;
this.activeURL = '';
/* switch (videoChannelInfo.status) {
case ApeConsts.CHANNEL_STATUS_RELEASED:
// 只能关闭自己的流
if (this.activeChannelId === videoChannelInfo.channelId) {
this.activeChannelId = 0;
this.activeURL = '';
this.emitVideoChange();
}
break;
case ApeConsts.CHANNEL_STATUS_OPENING:
//_playUrl = "rtmfp://" + Config.mediaServerAddr + ":" + Config.mediaServerPort + "/message/" + _streamName;
//_cdnUrl = "rtmp://" + Config.mediaCDNServerAddr + ":" + Config.mediaCDNServerPort + "/message/" + _streamName;
//this.activeChannelId = videoChannelInfo.channelId;
//// AMS/FMS
//if (this._classInfo.msType ==ApeConsts.MS_TYPE_FMS) {
// this.activeURL = `http://dazhi.3mang.com/live/${this._classInfo.classId}/${this._classInfo.classId}_${videoChannelInfo.channelId}_flash_cam_mic_aac/playlist.m3u8`;
//}else {
// this.activeURL = `http://hls.3mang.com/live/${this._classInfo.classId}_${videoChannelInfo.channelId}_flash_cam_mic_aac/playlist.m3u8`;
//}
// 任何人都可以打开流
this.emitVideoChange();
}
break;
case ApeConsts.CGS_OPENNED:
this.activeChannelId = videoChannelInfo.channelId;
// AMS
if (this._classInfo.msType === '1') {
this.activeURL = `http://dazhi.3mang.com/live/${this._classInfo.classId}/${this._classInfo.classId}_${videoChannelInfo.channelId}_flash_cam_mic_aac/playlist.m3u8`;
}else {
this.activeURL = `http://hls.3mang.com/live/${this._classInfo.classId}_${videoChannelInfo.channelId}_flash_cam_mic_aac/playlist.m3u8`;
}
// 任何人都可以打开流
this.emitVideoChange();
break;
}
break;
default:
break;
}*/
}
emitVideoChange() {
... ... @@ -129,6 +312,53 @@ class VideoChat extends Ape {
});
};
///////数据的封包和解包/////////////////////////////////////////
packPdu(_param,_itemIdx){
loger.log("VIDEO===packPdu ");
//验证坐标点集合数组是否合法
if(_param==null||_itemIdx==null){
this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG);
return null;
}
/* message RCVideoChannelInfoPdu {
optional uint32 status = 1;//开启的状态
optional uint32 channel_id = 2;//唯一的频道id
optional uint32 timestamp = 3;//更新的时间戳
optional uint32 from_node_id = 4;//发起者的id
optional uint32 to_node_id = 5;//接收者的id,(如果是0,所有人都接收)
}*/
//判断type类型,根据type设置不同的参数
let packPduModel =new pdu['RCVideoChannelInfoPdu'];
packPduModel.status=ApeConsts.CHANNEL_STATUS_OPENING;
packPduModel.channelId=_itemIdx;
packPduModel.timestamp=EngineUtils.creatTimestamp();
packPduModel.fromNodeId =GlobalConfig.nodeId;
packPduModel.toNodeId = 0;
console.log(packPduModel);
return packPduModel;
}
unPackPdu(owner, itemIdx,itemData){
loger.log("VIDEO==unPackPdu ");
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("VIDEO收到数据 unPackPdu Pdu解析错误,itemIdx="+itemIdx+" err:"+err.message);
}
return null;
}
}
export default VideoChat;
... ...
... ... @@ -735,11 +735,12 @@ message RCAudioSendDataRequestPdu {
}
message RCVideoSendDataRequestPdu {
optional uint32 initiator = 1;
required bool key_frame = 2;
required uint32 sequence_id = 3;
required uint32 slice_id = 4;
required bytes user_data = 5;
required uint32 initiator = 1;
optional bool key_frame = 2;
optional uint32 sequence_id = 3;
optional uint32 slice_id = 4;
optional bytes user_data = 5;
optional uint32 action = 6;
}
message RCAudioChannelInfoRecordPdu {
... ... @@ -750,6 +751,14 @@ message RCAudioChannelInfoRecordPdu {
required uint32 codec = 5;
}
message RCVideoChannelInfoPdu {
optional uint32 status = 1;//开启的状态
optional uint32 channel_id = 2;//唯一的频道id
optional uint32 timestamp = 3;//更新的时间戳
optional uint32 from_node_id = 4;//发起者的id
optional uint32 to_node_id = 5;//接收者的id,(如果是0,所有人都接收)
}
message RCVideoChannelInfoRecordPdu {
optional uint32 status = 1;
optional uint32 device_id = 2;
... ...