李勇

1.调整视频模块,把视频和音频模块共用的功能单独分离出来

... ... @@ -91,7 +91,7 @@ export default class MessageEntrance extends Emiter {
_audio_ape= new AudioApe();
_audio_ape.on('*', (type, data) => this._emit(type, data));
_audio_ape.on(MessageTypes.AUDIO_UPDATE, this.videoUpdate.bind(this));
_audio_ape.on(MessageTypes.AUDIO_UPDATE, this.audioUpdate.bind(this));
_whiteboard_ape = new WhiteBoardApe();
_whiteboard_ape.on('*', (type, data) => this._emit(type, data));
... ... @@ -198,7 +198,7 @@ export default class MessageEntrance extends Emiter {
_video_ape.stopPublishVideo(_data);
}
if(_audio_ape){
_video_ape.stopPublishAudio(_data);
_audio_ape.stopPublishAudio(_data);
}
}
}
... ... @@ -206,15 +206,15 @@ export default class MessageEntrance extends Emiter {
//当前会议中视频或音频占用channel的nodeId ,在人员列表中不存在,这种情况是占用channel的人员掉线或离开的时候没有释放channel
//的占用状态导致,对于这种情况,需要释放掉
_onClassNonentityRoster(_param){
if(_param==null||_param.fromNodeId==null){
if(_param==null||_param.nodeId==null){
loger.warn("onClassNonentityRoster.参数错误")
return;
}
if(_video_ape){
_video_ape.stopPublishVideo({"nodeId":_param.fromNodeId});
_video_ape.stopPublishVideo({"nodeId":_param.nodeId});
}
if(_audio_ape){
_audio_ape.stopPublishAudio({"nodeId":_param.fromNodeId});
_audio_ape.stopPublishAudio({"nodeId":_param.nodeId});
}
}
... ... @@ -738,7 +738,7 @@ export default class MessageEntrance extends Emiter {
//AudioApe
audioUpdate(_data){
//频同步的消息发送改变,需要通知ferApe模块中的用户更新状态
//频同步的消息发送改变,需要通知ferApe模块中的用户更新状态
if(_confer_ape){
_confer_ape.updaterRosterStatus(_data);
}
... ...
//对外暴露的对象
import EngineEntrance from 'EngineEntrance';
import MessageTypes from 'MessageTypes';
const MCU_CLIENT=new EngineEntrance();
const MCU_CLIENT=new EngineEntrance();//入口文件
export function createMcuClient() {
return MCU_CLIENT;
}
//监听是事件名和异常定义
export {MessageTypes};
... ...
... ... @@ -454,7 +454,7 @@ class ConferApe extends Ape {
//视频模块发生更新,人员状态需要更新
updaterRosterStatus(_param){
if(_param){
loger.log("视频模块发生更新,人员状态需要更新,fromNodeId->",_param.fromNodeId);
loger.log("媒体模块发生更新,人员状态需要更新,fromNodeId->",_param.fromNodeId);
loger.log(_param.status,_param.fromNodeId,this.rosters[_param.fromNodeId]);
//console.log(_param.fromNodeId);
//如果是自己。改变自己的状态同步到MCU
... ... @@ -465,8 +465,8 @@ class ConferApe extends Ape {
//如果视频消息中channel的占用人 fromNodeId在人员列表中不存在,需要释放这channel,因为这个有可能是之前没释放成功的
if(_param.status==ApeConsts.CHANNEL_STATUS_OPENING&&this.rosters[_param.fromNodeId]==null){
loger.log("视频模块被占用,占有人已经不存在课堂中,释放Channel,_param->",_param);
this._emit(MessageTypes.CLASS_NONENTITY_ROSTER,_param.fromNodeId);
loger.log("媒体模块被占用,占有人已经不存在课堂中,释放Channel,_param->",_param);
this._emit(MessageTypes.CLASS_NONENTITY_ROSTER,{"nodeId":_param.fromNodeId});
}
}
}
... ...
// //////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2016-present All Rights Reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// http://www.apache.org/licenses/LICENSE-2.0
//
// Github Home: https://github.com/AlexWang1987
// Author: AlexWang
// Date: 2016-08-23 18:07:28
// QQ Email: 1669499355@qq.com
// Last Modified time: 2016-09-06 11:13:59
// Description: LiveClass-VideoApe
//
//视频模块
// //////////////////////////////////////////////////////////////////////////////
import Ape from './Ape';
... ... @@ -20,6 +9,7 @@ import Loger from 'Loger';
import MessageTypes from 'MessageTypes';
import GlobalConfig from 'GlobalConfig';
import EngineUtils from 'EngineUtils';
import MediaModule from "./MediaModule";
let loger = Loger.getLoger('VideoApe');
... ... @@ -31,8 +21,9 @@ class VideoApe extends Ape {
ApeConsts.VIDEO_SESSION_TAG
);
//Attributes
this.videoChannels = {};
this.mediaModule=new MediaModule();
this.mediaModule.MEDIA_OBJ_TABLE_ID=ApeConsts.VIDEO_OBJ_TABLE_ID;
this.mediaModule.mediaChannels={};
// Ape Models
this.registerKey(this._session_id, this._session_name, this._session_tag, new ArrayBuffer);
... ... @@ -41,84 +32,23 @@ class VideoApe extends Ape {
// videoApe 监听视频控制消息,用户之间的消息传递
this.on(pdu.RCPDU_VIDEO_SEND_DATA_REQUEST, this.receiveVideoCommandHandler.bind(this));
}
//ape加入成功
onJoinChannelHandlerSuccess(){
//这个设置很重要,因为只有Sass流程完成之后,APE才能取得GlobalConfig中的数据
this.mediaModule.maxMediaChannel=GlobalConfig.maxVideoChannels;
}
/////////////发送数据操作////////////////////////////////////////////
//获取播流地址
getPlayVideoPath(_param) {
loger.log('getPlayVideoPath');
if (_param == null||_param.siteId == null||
_param.classId == null||_param.userId == null||
_param.channelId == null|| _param.timestamp==null)
{
loger.warn('getPlayVideoPath,参数错误', _param);
this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG);
return {"code": 1, "data": ""};
}
let path = "";
let port="";
if (_param.type == "m3u8") {
//M3U8
//http://123.56.73.119:6001/hls/h5dev_403074980_0_983041_1487663265/index.m3u8
port = (GlobalConfig.RSServerPort == "" || GlobalConfig.RSServerPort == null) ? "":":" + GlobalConfig.RSServerPort;
path = "http://" + GlobalConfig.RSServerIP
+ port + "/live/"
+ _param.siteId
+ "_" + _param.classId
+ "_" + _param.userId
+ "_" + _param.channelId
+ "_" + _param.timestamp
+ "/index.m3u8";
} else {
port = (GlobalConfig.MSServerPort == "" || GlobalConfig.MSServerPort == null) ? "":":" + GlobalConfig.MSServerPort;
path = "rtmp://" + GlobalConfig.MSServerIP
+ port + "/live/"
+ _param.siteId
+ "_" + _param.classId
+ "_" + _param.userId
+ "_" + _param.channelId
+ "_" + _param.timestamp;
}
return {"code": 0, "data": path};
return this.mediaModule.getMediaPlayPath(_param);
}
//获取推流地址
getPublishVideoPath(_param) {
loger.log('getPublishVideoPath');
//判断当前开启的视频数量是否已经是最大值,如果已经是最大值,不能再开启
let freeChannel = this.getFreeVideoChannel();
if (freeChannel == 0) {
return {"code": 1, "data": "不能再打开更多的设备"};
}
//默认方式推流
let pubType="live";
//flash推流
if(_param&&_param.type=="flash"){
pubType ="flash";
}
//端口,有端口就显示 ":xxx",没有端口就是""
let port = (GlobalConfig.MSServerPort == "" || GlobalConfig.MSServerPort == null) ? "":":" + GlobalConfig.MSServerPort;
//时间戳
let timestamp = EngineUtils.creatTimestamp();
//生成推流地址和推流数据(同步数据的时候用)
let publishUrl = "rtmp://" + GlobalConfig.MSServerIP
+ port + "/"+pubType+"/" +GlobalConfig.siteId+"_"
+ GlobalConfig.classId + "_"+GlobalConfig.userId
+"_" + freeChannel + "_" + timestamp;
return {"code": 0,
"data":
{ "siteId":GlobalConfig.siteId,
"classId":GlobalConfig.classId,
"userId":GlobalConfig.userId,
"channelId": freeChannel,
"timestamp": timestamp,
"publishUrl": publishUrl
}
};
return this.mediaModule.getMediaPublishPath(_param);
}
//推流
... ... @@ -135,20 +65,20 @@ class VideoApe extends Ape {
loger.log('publishVideo -> maxVideoChannels', GlobalConfig.maxVideoChannels);
//同一个nodeId只允许推一个流,如果已经推了就不能再推
if(this.getOpeningVideoChannel(GlobalConfig.nodeId)!=0){
if(this.mediaModule.getOpeningMediaChannel(GlobalConfig.nodeId)!=0){
loger.warn("publishVideo,已经存在一个流,不能再推");
return;
}
//判断当前是否还有空闲的channle
let freeChannel = this.getFreeVideoChannel();
let freeChannel = this.mediaModule.getFreeMediaChannel();
if (freeChannel == 0) {
loger.warn("publishVideo,没有空闲的channel ");
return {"code": 1, "data": "不能再打开更多的设备"};
}
//判断当前的频道是否已经占用
if(this.checkChannelIsOpening(_param.channelId)){
if(this.mediaModule.checkChannelIsOpening(_param.channelId)){
loger.warn(_param.channelId,"频道已经被占用");
return {"code":1,"data":"频道已经被占用!"};
}
... ... @@ -177,7 +107,7 @@ class VideoApe extends Ape {
nodeId=GlobalConfig.nodeId;
}
let openingChannel = this.getOpeningVideoChannel(nodeId);
let openingChannel = this.mediaModule.getOpeningMediaChannel(nodeId);
if (openingChannel == 0) {
loger.warn(nodeId,"stopPublishVideo,没有打开的channel,不需要关闭");
return {"code": 1, "data": "没有打开的channel,不需要关闭"};
... ... @@ -214,7 +144,7 @@ class VideoApe extends Ape {
if (_param.actionType != null && _param.actionType == ApeConsts.MEDIA_ACTION_OPEN_CAMERA) {
//判断当前开启的视频数量是否已经是最大值,如果已经是最大值,不能再开启
let freeChannel = this.getFreeVideoChannel();
let freeChannel = this.mediaModule.getFreeMediaChannel();
if (freeChannel == 0) {
loger.warn('sendVideoCommandMsg,不能再打开更多的设备', _param);
return {"code": 1, "data": "不能再打开更多的设备"};
... ... @@ -325,7 +255,7 @@ class VideoApe extends Ape {
//videoChannelInfo.channelId = itemIdx;
//videoChannelInfo.status = owner === 0 ? ApeConsts.CHANNEL_STATUS_RELEASED : videoChannelInfo.status;
//loger.log('视频消息处理 tableUpdateHandler.',videoChannelInfo);
this.videoChannels[itemIdx] = videoChannelInfo;
this.mediaModule.mediaChannels[itemIdx] = videoChannelInfo;
this._emit(MessageTypes.VIDEO_UPDATE, videoChannelInfo);
/* switch (videoChannelInfo.status) {
... ... @@ -403,52 +333,6 @@ class VideoApe extends Ape {
}
return null;
}
//获取当前空闲的channel,返回值为0代表没有空闲的,否则返回的就是空闲的channelId
getFreeVideoChannel() {
loger.log("getFreeVideoChannel");
console.log(this.videoChannels);
let counter = 0;
for (let key in this.videoChannels) {
let item = this.videoChannels[key];
if (item && item.status == ApeConsts.CHANNEL_STATUS_RELEASED) {
return item.channelId;
}
counter++;
}
if (counter < GlobalConfig.maxVideoChannels) {
return ApeConsts.VIDEO_OBJ_TABLE_ID + (counter);
}
return 0;//没有空闲的
}
//获取当前属于nodeId的已经打开的的channel,返回值为0代表没有打开的,否则返回的就是打开的channelId
getOpeningVideoChannel(_nodeId){
if(_nodeId==null||_nodeId==0){
return 0;
}
for (let key in this.videoChannels) {
let item = this.videoChannels[key];
if (item && item.status == ApeConsts.CHANNEL_STATUS_OPENING&&item.fromNodeId==_nodeId) {
return item.channelId;
}
}
return 0;
}
//检查频道是否已经被占用
checkChannelIsOpening(_channelId){
if(_channelId==null){
loger.warn("checkChannelIsOpening error,channel=",_channelId);
return true;
}
let channelInfo=this.videoChannels[_channelId];
if(channelInfo==null||channelInfo.status==ApeConsts.CHANNEL_STATUS_RELEASED){
return false;
}
return true;
}
}
export default VideoApe;
... ...