李勇

1.增加一个切换视频录制状态的接口;2.对课堂录制的启动逻辑做现在处理,加入课堂之后已经开启录制之后不再继续发生

... ... @@ -63,7 +63,7 @@ export default class MessageEntrance extends Emiter {
super();
this.lastClassActiveTime=0;//最后一次课堂激活的时间戳
//sdk 信息
GlobalConfig.sdkVersion = "v2.27.11.20171109";
GlobalConfig.sdkVersion = "v2.28.1.20171110";
loger.warn("sdkVersion:" + GlobalConfig.sdkVersion);
console.log("sdkVersion:" + GlobalConfig.sdkVersion);
//设置
... ... @@ -304,7 +304,7 @@ export default class MessageEntrance extends Emiter {
this.setInvisibleMediaView = this._setInvisibleMediaView.bind(this);//设置监课身份的视图
this.setAppConfig = this._setAppConfig.bind(this);
this.recordControl = this._mediaRecordControl.bind(this);
this.recordControl = this._changeMediaRecordStatus.bind(this);//切换控制音视频的录制状态
this.changeRtcVideoConfig = this._changeRtcVideoConfig.bind(this);//设置webRtc视频视图的缩放
... ... @@ -2421,7 +2421,7 @@ export default class MessageEntrance extends Emiter {
//上传文档
_sendDocumentUpload(_param) {
if (!_mcu.connected) {
loger.warn(GlobalConfig.getCurrentStatus());
console.warn("连接已经断开->上传文档");
return;
}
if (_doc_ape) {
... ... @@ -2548,9 +2548,16 @@ export default class MessageEntrance extends Emiter {
//如果当前课堂内只有自己或者离开上次课堂的时间大于8分钟,需要停止服务端的视频录制,设备不是H5
if(GlobalConfig.rosterNumber<=1&&interval>=(6*60)&&GlobalConfig.deviceType!=3){
setTimeout(()=>{
//延迟3秒,检测一下当前是否有人在开着视频,如果有开启的就不能再停止了
loger.log("当前开启音视频的人数->"+GlobalConfig.getPublishUser());
if(GlobalConfig.getPublishUser()<1){
loger.log("调用服务端音视频停止录制->interval:"+interval);
this._mediaRecordControl({"status": WebRtcApe.RECORD_STATUS_2});
}
},3000);
}
//如果是主持人,那么需要判断一下文档模块同步的数据和从sass获取的文档数据是否相同,如果mcu服务器不存在的,需要上传
if (GlobalConfig.docListPrepare && GlobalConfig.docListPrepare.length > 0) {
... ... @@ -3352,7 +3359,7 @@ export default class MessageEntrance extends Emiter {
break;
case WebRtcApe.RECORD_STATUS_2:
//停止录制
//_webRtc.stopRecordingMedia();
loger.warn("调用停止音视频录制->");
_webRtc.changePublishStatusAndServerRecord(WebRtcApe.RECORD_STATUS_2);
break;
default :
... ... @@ -3361,6 +3368,14 @@ export default class MessageEntrance extends Emiter {
}
}
/*
* 切换音视频的录制状态 1开启 2停止
* */
_changeMediaRecordStatus(_param){
if(_webRtc){
_webRtc.changeMediaRecordStatus(_param);
}
}
//webRtc-----------------end --------------------------------
//判断是否能推流,当前课堂推流人数是有限制的
_hasFreePublishChannel() {
... ...
... ... @@ -10,6 +10,7 @@ class GlobalConfig {
constructor() {
}
_currentStatus = null;
static getCurrentStatus() {
... ... @@ -18,15 +19,19 @@ class GlobalConfig {
}
return this._currentStatus;
}
static setCurrentStatus(_data) {
this._currentStatus = _data;
}
static getClassDetail() {
return this.classDetail;
}
static setClassDetail(_data) {
this.classDetail = _data;
}
static getClassInfo() {
let classInfo = {};
classInfo.siteId = this.siteId;
... ... @@ -61,8 +66,8 @@ class GlobalConfig {
classInfo.appId = this.appId;
classInfo.appCertificate = this.appCertificate;
classInfo.appRecordingKey = this.appRecordingKey;
classInfo.channelId =this.channelId ;
classInfo.channelKey =this.channelKey ;
classInfo.channelId = this.channelId;
classInfo.channelKey = this.channelKey;
classInfo.userUid = this.userUid;
return classInfo;
... ... @@ -101,9 +106,10 @@ class GlobalConfig {
classStatusInfo.currentSceneTableId = this.currentSceneTableId; //文档区域的模块显示
classStatusInfo.serverAndLoacTimeDistanc = this.serverAndLoacTimeDistanc;
classStatusInfo.videoScale=this.videoScale;
classStatusInfo.videoScale = this.videoScale;
return classStatusInfo;
}
//设置当前的课堂状态的信息
static setClassStatusInfo(_data) {
//loger.log("setClassStatusInfo");
... ... @@ -142,56 +148,77 @@ class GlobalConfig {
//this.recordStatus = data.recordStatus || this.recordStatus; //当前录制状态
this.recordStatus = data.recordStatus ||false; //当前录制状态
this.recordTimestamp =Math.max(parseInt(data.recordTimestamp), this.recordTimestamp); //录制时间取最大值
this.recordStatus = data.recordStatus || false; //当前录制状态
this.recordTimestamp = Math.max(parseInt(data.recordTimestamp), this.recordTimestamp); //录制时间取最大值
this.recordFileName = data.recordFileName || this.recordFileName; //录制的文件名
this.recordDownloadUrl = data.recordDownloadUrl || this.recordDownloadUrl; //下载地址
this.currentSceneTableId = data.currentSceneTableId || 0; //文档区域的模块显示
this.isEnableDraw=data.isEnableDraw||false;//是否开启所有人的绘制权限
this.videoScale=parseInt(data.videoScale)||1;
this.isEnableDraw = data.isEnableDraw || false;//是否开启所有人的绘制权限
this.videoScale = parseInt(data.videoScale) || 1;
// 全局禁言状态
this.silence = data.silence || false;
this.silenceUsers =data.silenceUsers || {};
if((typeof this.silenceUsers =='string')&& this.silenceUsers .constructor==String){
this.silenceUsers={};
this.silenceUsers = data.silenceUsers || {};
if ((typeof this.silenceUsers == 'string') && this.silenceUsers.constructor == String) {
this.silenceUsers = {};
}
}
/*
* 根据nodeId获取用户的身份
* */
static getUserRoleFromeNodeId(_nodeId){
let user=this.rosters[_nodeId];
if(user){
static getUserRoleFromeNodeId(_nodeId) {
let user = this.rosters[_nodeId];
if (user) {
return user.userRole;
}else {
} else {
return "normal"
}
}
/*
* 根据nodeId获取用户的信息
* */
static getUserInfoFromeNodeId(_nodeId){
static getUserInfoFromeNodeId(_nodeId) {
return this.rosters[_nodeId];
}
//获取推流权限,需要检查当前是否可以继续推流
static getPublishPermission(){
if(!this.rosters){
static getPublishPermission() {
if (!this.rosters) {
return true;
}
let openCounter=0;
for (let i in this.rosters){
let item=this.rosters[i];
if(item&&item.userRole!=ApeConsts.invisible&&(item.openCamera>0||item.openMicrophones>0)){
let openCounter = 0;
for (let i in this.rosters) {
let item = this.rosters[i];
if (item && item.userRole != ApeConsts.invisible && (item.openCamera > 0 || item.openMicrophones > 0)) {
openCounter++;
//统计当前已经开启摄像头和麦克风的人数,如果当前开启的人数大于等于最大允许的数量就不允许其他人再打开
if(openCounter>=GlobalConfig.maxMediaChannels){
if (openCounter >= GlobalConfig.maxMediaChannels) {
return false;
}
}
}
return true;
}
/*
* 获取当前推流的人数
* */
static getPublishUser() {
if (!this.rosters) {
return 0;
}
let openCounter = 0;
for (let i in this.rosters) {
let item = this.rosters[i];
if (item && item.userRole != ApeConsts.invisible && (item.openCamera > 0 || item.openMicrophones > 0)) {
openCounter++;
}
}
return openCounter;
}
// 判断自己是否主持人角色
static get isHost() {
if (this.userRole == ApeConsts.host) {
... ... @@ -234,9 +261,9 @@ class GlobalConfig {
//是否是老师或主讲人
static get isTeachOrAssistant() {
if (this.userRole == ApeConsts.host||
this.userRole==ApeConsts.assistant||
this.userRole==ApeConsts.presenter) {
if (this.userRole == ApeConsts.host ||
this.userRole == ApeConsts.assistant ||
this.userRole == ApeConsts.presenter) {
return true;
}
return false;
... ... @@ -245,19 +272,23 @@ class GlobalConfig {
static get serverTimestamp() {
return EngineUtils.creatTimestamp();
}
//储存已经提前上传的文档列表
static setDocListPrepare(_data) {
if (_data == null) return;
this.docListPrepare = _data;
}
static getDocListPrepare() {
return this.docListPrepare;
}
//储存已经提前上传的媒体共享文件列表
static setMediaShareList(_data) {
if (_data == null) return;
this.sharedMediaList = _data;
}
static getMediaShareList() {
return this.sharedMediaList;
}
... ... @@ -267,6 +298,7 @@ class GlobalConfig {
if (_data == null) return;
this.sharedMusicList = _data;
}
static getMusicShareList() {
return this.sharedMusicList;
}
... ... @@ -276,6 +308,7 @@ class GlobalConfig {
if (_data == null) return;
this.recordList = _data;
}
static getRecordList() {
return this.recordList;
}
... ... @@ -285,14 +318,17 @@ class GlobalConfig {
if (_data == null) return;
this.docList = _data;
}
static getDocList() {
return this.docList;
}
//ms列表
static setMsList(_data) {
if (_data == null) return;
this.msList = _data;
}
static getMsList() {
return this.msList;
}
... ... @@ -302,6 +338,7 @@ class GlobalConfig {
if (_data == null) return;
this.rtmpPullList = _data;
}
static getRtmpPullList() {
return this.rtmpPullList;
}
... ... @@ -311,6 +348,7 @@ class GlobalConfig {
if (_data == null) return;
this.hlsPullList = _data;
}
static getHlsPullList() {
return this.hlsPullList;
}
... ... @@ -320,6 +358,7 @@ class GlobalConfig {
if (_data == null) return;
this.rsList = _data;
}
static getRsList() {
return this.rsList;
}
... ... @@ -329,6 +368,7 @@ class GlobalConfig {
if (_data == null) return;
this.mcuList = _data;
}
static getMcuList() {
return this.mcuList;
}
... ... @@ -338,20 +378,22 @@ class GlobalConfig {
if (_data == null) return;
this.musicList = _data;
}
static getMusicList() {
return this.musicList;
}
//已经上传的声音列表
static setMusicListPrepare(_data) {
if (_data == null) return;
this.musicListPrepare = _data;
}
static getMusicListPrepare() {
return this.musicListPrepare;
}
//CDN加速的 拉流地址 rtmp 和hls(m3u8)
static setVideoCDNAddr(_data) {
if (_data == null) return;
... ... @@ -364,33 +406,34 @@ class GlobalConfig {
}
//把IP中的端口换成指定端口
static replacePort(_ipport,_curPort,_newPort){
loger.warn("替换端口->",_ipport,_curPort,_newPort);
if(!_ipport||!_curPort){
static replacePort(_ipport, _curPort, _newPort) {
loger.warn("替换端口->", _ipport, _curPort, _newPort);
if (!_ipport || !_curPort) {
//数据不正确,直接返回原数据
return _ipport;
}
try {
//判断要替换的端口是否在最后的位置,否则是不能替换的,比如替换":80"端口,如果地址是"xxx.xxx.xxx:8080" 不判断的话就会出错
let lastIndex=_ipport.lastIndexOf(_curPort);
if((_ipport.length-_curPort.length)==lastIndex){
let ipportNew=_ipport.replace(_curPort,_newPort);
let lastIndex = _ipport.lastIndexOf(_curPort);
if ((_ipport.length - _curPort.length) == lastIndex) {
let ipportNew = _ipport.replace(_curPort, _newPort);
return ipportNew
}
return _ipport;
}catch (err){
} catch (err) {
return _ipport;
}
}
//通过IP查找IP对象
static getIpItem(ip,ipList){
if(!ip||!ipList) {
static getIpItem(ip, ipList) {
if (!ip || !ipList) {
return null;
}
for(let i=0;i<ipList.length;i++){
let item=ipList[i];
if(item&&item.ip==ip){
for (let i = 0; i < ipList.length; i++) {
let item = ipList[i];
if (item && item.ip == ip) {
return item;
}
}
... ... @@ -398,11 +441,11 @@ class GlobalConfig {
}
}
GlobalConfig.statusCode_0 = { "code": 0, message: "SDK 未初始化" };
GlobalConfig.statusCode_1 = { "code": 1, message: "未加入课堂" };
GlobalConfig.statusCode_2 = { "code": 2, message: "已经加入课堂" };
GlobalConfig.statusCode_3 = { "code": 3, message: "已经离开课堂" };
GlobalConfig.statusCode_4 = { "code": 4, message: "未知状态" };
GlobalConfig.statusCode_0 = {"code": 0, message: "SDK 未初始化"};
GlobalConfig.statusCode_1 = {"code": 1, message: "未加入课堂"};
GlobalConfig.statusCode_2 = {"code": 2, message: "已经加入课堂"};
GlobalConfig.statusCode_3 = {"code": 3, message: "已经离开课堂"};
GlobalConfig.statusCode_4 = {"code": 4, message: "未知状态"};
GlobalConfig.screenWidth = 1024;
GlobalConfig.screenHeight = 768;
... ... @@ -412,7 +455,7 @@ GlobalConfig.msType = 1; //鐩墠鍥哄畾鐢ㄨ繖涓
GlobalConfig.messageDelay = false; //是否启用消息延迟
GlobalConfig.mcuDelay = 0; //默认的延迟时间(单位-秒)
GlobalConfig.classExit=false;//是否关闭课堂,如果关闭之后不再连接MCU
GlobalConfig.classExit = false;//是否关闭课堂,如果关闭之后不再连接MCU
GlobalConfig.docDelay = 1600; //文档模块加入成功之后延迟发送送成功的消息给主模块(sdk内部使用)
GlobalConfig.portal = ""; //Sass IP
... ... @@ -464,7 +507,6 @@ GlobalConfig.hlsPullListFinal = []; //鏈缁堥夋嫨鐨凥LS鎷夋祦鍦板潃闆嗗悎
GlobalConfig.rsPullListFinal = []; //最终选择的录制回放HLS拉流地址集合
//连接MCU的IP+端口
GlobalConfig.MCUServerIP = "";
GlobalConfig.MCUServerPort = '';
... ... @@ -499,7 +541,7 @@ GlobalConfig.maxMediaChannels = 0; //鏈澶ч煶瑙嗛璺暟锛屼互闊宠棰戣矾鏁颁
GlobalConfig.hasCamera = false; //摄像头是否可用
GlobalConfig.hasMicrophone = false; //麦克风是否可用
GlobalConfig.returnCitySN=null;//获取的ip数据 {"cip":"60.253.214.122","cid":"110000","cname":"北京市"}
GlobalConfig.returnCitySN = null;//获取的ip数据 {"cip":"60.253.214.122","cid":"110000","cname":"北京市"}
GlobalConfig.deviceType = 0; //设备类型 0:电脑 1:ios 2:安卓
GlobalConfig.userIp = ""; //用户当前IP
GlobalConfig.userId = 0;
... ... @@ -508,7 +550,7 @@ GlobalConfig.handUpTime = 0;
GlobalConfig.level = 0;
GlobalConfig.openCamera = 0;
GlobalConfig.openMicrophones = 0;
GlobalConfig.selfDisEnableDrawTime=1;//记录是否禁用画笔,0为启用画笔,大于0时被禁用的时间戳
GlobalConfig.selfDisEnableDrawTime = 1;//记录是否禁用画笔,0为启用画笔,大于0时被禁用的时间戳
//视频质量相关设置
GlobalConfig.fps = 15; //帧频
... ... @@ -526,7 +568,7 @@ GlobalConfig.autoGain = false; //鑷姩璋冭妭楹﹀厠椋庨煶閲
GlobalConfig.speakerVolume = 80; //扬声器音量(0-80)
GlobalConfig.micCode = 0; //麦克风模式
GlobalConfig.optionJsonData="";//音视频模块推流时的可选参数,这个由外部传入
GlobalConfig.optionJsonData = "";//音视频模块推流时的可选参数,这个由外部传入
GlobalConfig.audioRecords = [];
GlobalConfig.videoRecords = [];
GlobalConfig.status = 0
... ... @@ -570,7 +612,7 @@ GlobalConfig.updateRecordTimeDelay = 5; //(绉)锛屽悓姝ヤ竴娆¤鍫傚綍鍒剁姸鎬
GlobalConfig.updateClassInfoDelay = 10; //(秒),同步一次课堂状态的并保存到Sass
GlobalConfig.msDynamicChooseIpDelay = 60 * 3; //(秒)MS动态选点的间隔
//GlobalConfig.serverTimestamp=0;//当前的系统时间戳 用get set 获取
GlobalConfig.whiteboardId=2359297;//白板文档的ID
GlobalConfig.whiteboardId = 2359297;//白板文档的ID
GlobalConfig.activeDocId = 0; //当前激活的文档ID
GlobalConfig.activeDocCurPage = 1; //当前激活的文档的当前页
... ... @@ -583,9 +625,8 @@ GlobalConfig.classAllParam = {}; //Sass鐩存帴杩斿洖鐨勬墍鏈夎鍫備俊鎭(鏈鍏)
GlobalConfig.classDetail = {}; //Sass直接返回的当前课堂基本信息
GlobalConfig.isRecordPlayBack = false; //是否是录制回放,默认是否
GlobalConfig.allowRecordMaxTime = 48*60*60; //(秒)允许录制的最长时间
GlobalConfig.allowRecordMaxTime = 48 * 60 * 60; //(秒)允许录制的最长时间
GlobalConfig.siteId_letv = 'shchuanbao'; //乐视,MS不需要动态选点的站点
GlobalConfig.ssTunnelAppURL = ''; //屏幕共享插件的地址
... ... @@ -593,36 +634,36 @@ GlobalConfig.serverTime = 0; //鏈嶅姟鍣ㄥ綋鍓嶆椂闂存埑
GlobalConfig.serverAndLoacTimeDistanc = 0; //本地时间和服务器时间错的差值;
GlobalConfig.logUrl = ""; //日志上报地址;
GlobalConfig.rosterNumber=0;//当前总人数
GlobalConfig.rosters={};//当前课堂内的人员数据
GlobalConfig.rosterNumber = 0;//当前总人数
GlobalConfig.rosters = {};//当前课堂内的人员数据
GlobalConfig.isMobile = false; //是否是移动端
GlobalConfig.language="";//浏览器语言
GlobalConfig.platform="pc";//平台 IOS/ANDROID/PC
GlobalConfig.explorer="未知";//浏览器
GlobalConfig.explorerVersion="未知";//浏览器版本
GlobalConfig.os="未知";//系统
GlobalConfig.language = "";//浏览器语言
GlobalConfig.platform = "pc";//平台 IOS/ANDROID/PC
GlobalConfig.explorer = "未知";//浏览器
GlobalConfig.explorerVersion = "未知";//浏览器版本
GlobalConfig.os = "未知";//系统
GlobalConfig.locationProtocol="http://";//https;或http:
GlobalConfig.websocketProtocol="ws://";//wss或ws
GlobalConfig.isHttps=false;//是否是https
GlobalConfig.locationProtocol = "http://";//https;或http:
GlobalConfig.websocketProtocol = "ws://";//wss或ws
GlobalConfig.isHttps = false;//是否是https
GlobalConfig.openFlash=false;//使用flash通话模式。默认为false,使用的是webRtc
GlobalConfig.openFlash = false;//使用flash通话模式。默认为false,使用的是webRtc
//webRtc
GlobalConfig.appId = '';
GlobalConfig.appCertificate = "";
GlobalConfig.appRecordingKey = "";
GlobalConfig.channelId = "";
GlobalConfig.channelKey ="";
GlobalConfig.channelKey = "";
GlobalConfig.userUid = 0;
GlobalConfig.recordInterfaces="";//控制开启录制和录制状态改变的接口
GlobalConfig.getRecordInfoInterfaces="";//获取媒体录制信息数据的接口
GlobalConfig.stopRecordingInterfaces="";//停止录制的接口
GlobalConfig.getTxRecordInfoInterfaces="";//获取媒体录制信息数据的接口(tx)
GlobalConfig.getRecordFileURLAgoInterfaces="";//获取媒体录制信息数据的接口(ago)
GlobalConfig.getChannelToken="";//获取token的地址
GlobalConfig.recordFileSever="";//录制文件路径和文件地址(ago)
GlobalConfig.videoScale=1;//视频的缩放倍数,默认1倍无缩放
GlobalConfig.recordInterfaces = "";//控制开启录制和录制状态改变的接口
GlobalConfig.getRecordInfoInterfaces = "";//获取媒体录制信息数据的接口
GlobalConfig.stopRecordingInterfaces = "";//停止录制的接口
GlobalConfig.getTxRecordInfoInterfaces = "";//获取媒体录制信息数据的接口(tx)
GlobalConfig.getRecordFileURLAgoInterfaces = "";//获取媒体录制信息数据的接口(ago)
GlobalConfig.getChannelToken = "";//获取token的地址
GlobalConfig.recordFileSever = "";//录制文件路径和文件地址(ago)
GlobalConfig.videoScale = 1;//视频的缩放倍数,默认1倍无缩放
export default GlobalConfig;
... ...
... ... @@ -34,30 +34,30 @@ class RecordPlayBackParse extends Emiter {
this._recordPlaybackTimestamp = 0;//回放的时间
this._recordPlaybackMaxTime = 0;//录制回放的总时间
this._isReady = false;//录制回放是否已经准备完成
this.isLoadTxRecordInfo=false;//是否已经加载TXY的录制数据
this.isLoadAgoRecordInfo=false;//是否已经加载AGO的录制数据
this.isgetRecordFileURLFromAgo=false;//是否已经加载AGO的录制文件地址数据
this.isLoadTxRecordInfo = false;//是否已经加载TXY的录制数据
this.isLoadAgoRecordInfo = false;//是否已经加载AGO的录制数据
this.isgetRecordFileURLFromAgo = false;//是否已经加载AGO的录制文件地址数据
this._apes = {};
this._videoApeBroadcastMssages={};//视频模块的广播消息
this.mediaChannleList={};
this._videoApeBroadcastMssages = {};//视频模块的广播消息
this.mediaChannleList = {};
this._conferApeMssages = {};//会议数据
this._chatApeMssages = {};//聊天数据
this._videoApeMssages = {};//视频数据
this._audioApeMssages = {};//音频数据
this._docApeMssages = {};//文档数据
this._whiteApeMssages = {};//白板数据
this._mediaShareApeMssages={};//媒体共享
this._musicShareApeMssages={};//伴音媒体共享
this._mediaShareApeMssages = {};//媒体共享
this._musicShareApeMssages = {};//伴音媒体共享
this._timerCounter = new TimerCounter();//计时器
this._timerCounter.addTimerCallBack(this._timerCounterUptate.bind(this), 1);
this.agoTiemstampMessages={};//ago推流时间戳消息数据集合
this.agoAllMedias={};//ago录制的文件集合
this.agoTiemstampMessages = {};//ago推流时间戳消息数据集合
this.agoAllMedias = {};//ago录制的文件集合
this.allStreams={};//记录课堂内所有的流id
this.recordInfoMatch=RecordInfoMatch;
this.recordInfoMatch.on(RecordInfoMatch.RECORD_INFO_MATCH_COMPLETE,this.onRecordInfoMatchComplete.bind(this));
this.allStreams = {};//记录课堂内所有的流id
this.recordInfoMatch = RecordInfoMatch;
this.recordInfoMatch.on(RecordInfoMatch.RECORD_INFO_MATCH_COMPLETE, this.onRecordInfoMatchComplete.bind(this));
}
//method--------------------内部---------------------------------------------
... ... @@ -76,7 +76,7 @@ class RecordPlayBackParse extends Emiter {
this._chatApeMssages = {};//聊天数据
this._videoApeMssages = {};//视频数据
this._audioApeMssages = {};//音频数据
this.mediaChannleList={};
this.mediaChannleList = {};
this._docApeMssages = {};//文档数据
this._whiteApeMssages = {};//白板数据
}
... ... @@ -195,12 +195,12 @@ class RecordPlayBackParse extends Emiter {
break;
case ApeConsts.VIDEO_SESSION_ID:
this.saveParseData(data, timestamp, this._videoApeMssages);
this.unpackVideoBroadcastMessage(pduMsg,timestamp,data);
this.unPackpduRegAdapterHandler(pduMsg.data,timestamp,data,ApeConsts.VIDEO_SESSION_ID,pduMsg.subType)
this.unpackVideoBroadcastMessage(pduMsg, timestamp, data);
this.unPackpduRegAdapterHandler(pduMsg.data, timestamp, data, ApeConsts.VIDEO_SESSION_ID, pduMsg.subType)
break;
case ApeConsts.AUDIO_SESSION_ID:
this.saveParseData(data, timestamp, this._audioApeMssages);
this.unPackpduRegAdapterHandler(pduMsg.data,timestamp,data,ApeConsts.AUDIO_SESSION_ID,pduMsg.subType)
this.unPackpduRegAdapterHandler(pduMsg.data, timestamp, data, ApeConsts.AUDIO_SESSION_ID, pduMsg.subType)
break;
default:
break;
... ... @@ -214,17 +214,17 @@ class RecordPlayBackParse extends Emiter {
}
//消息和录制文件匹配完成
onRecordInfoMatchComplete(_data){
console.log("消息和录制文件匹配完成",_data);
if(_data){
for(let k in _data){
onRecordInfoMatchComplete(_data) {
console.log("消息和录制文件匹配完成", _data);
if (_data) {
for (let k in _data) {
//优先使用TXY的,没有的时候再使用AGO
/* if(! MediaModule.streams[k]){
MediaModule.streams[k]=_data[k];
}else {
console.log(k+" 已经存在",MediaModule.streams[k]);
}*/
MediaModule.streams[k]=_data[k];
MediaModule.streams[k] = _data[k];
}
}
... ... @@ -232,6 +232,7 @@ class RecordPlayBackParse extends Emiter {
//解析课堂录制的rec文件
this.parseArrayBuf();
}
//保存各个模块的MCU原始数据
saveParseData(data, timestamp, apeMessages) {
let messageItem = apeMessages[timestamp];
... ... @@ -271,14 +272,14 @@ class RecordPlayBackParse extends Emiter {
}
//各个APE模块根据时间查找消息数据
this._searchMessageFromTime(this._recordPlaybackTimestamp, this._conferApeMssages,"conferApe");
this._searchMessageFromTime(this._recordPlaybackTimestamp, this._chatApeMssages,"chatApe");
this._searchMessageFromTime(this._recordPlaybackTimestamp, this._docApeMssages,"docApe");
this._searchMessageFromTime(this._recordPlaybackTimestamp, this._mediaShareApeMssages,"mediaShareApe");
this._searchMessageFromTime(this._recordPlaybackTimestamp, this._musicShareApeMssages,"musicShareApe");
this._searchMessageFromTime(this._recordPlaybackTimestamp, this._whiteApeMssages,"whiteApe");
this._searchMessageFromTime(this._recordPlaybackTimestamp, this._videoApeMssages,"videoAp");
this._searchMessageFromTime(this._recordPlaybackTimestamp, this._audioApeMssages,"audioApe");
this._searchMessageFromTime(this._recordPlaybackTimestamp, this._conferApeMssages, "conferApe");
this._searchMessageFromTime(this._recordPlaybackTimestamp, this._chatApeMssages, "chatApe");
this._searchMessageFromTime(this._recordPlaybackTimestamp, this._docApeMssages, "docApe");
this._searchMessageFromTime(this._recordPlaybackTimestamp, this._mediaShareApeMssages, "mediaShareApe");
this._searchMessageFromTime(this._recordPlaybackTimestamp, this._musicShareApeMssages, "musicShareApe");
this._searchMessageFromTime(this._recordPlaybackTimestamp, this._whiteApeMssages, "whiteApe");
this._searchMessageFromTime(this._recordPlaybackTimestamp, this._videoApeMssages, "videoAp");
this._searchMessageFromTime(this._recordPlaybackTimestamp, this._audioApeMssages, "audioApe");
}
//加载录制文件rec
... ... @@ -287,11 +288,11 @@ class RecordPlayBackParse extends Emiter {
loger.log("读取录制回放数据");
//let url = `http://123.56.73.119:80/h5dev/20170306/1357644520_20170306.rec`;
//let url = `http://${ GlobalConfig.RecordServerIP}:${ GlobalConfig.RecordServerPort}/${GlobalConfig.recordFileName}`;
let ipport=GlobalConfig.RecordServerIP;//GlobalConfig.RecordServerPort
if(GlobalConfig.RecordServerPort){
ipport=ipport+":"+GlobalConfig.RecordServerPort;
let ipport = GlobalConfig.RecordServerIP;//GlobalConfig.RecordServerPort
if (GlobalConfig.RecordServerPort) {
ipport = ipport + ":" + GlobalConfig.RecordServerPort;
}
let url = `${GlobalConfig.locationProtocol+ ipport}/${GlobalConfig.recordFileName}`;
let url = `${GlobalConfig.locationProtocol + ipport}/${GlobalConfig.recordFileName}`;
loger.log(url);
fetch(url, {
timeout: 240000 //加载文件超时时间4分
... ... @@ -351,115 +352,118 @@ class RecordPlayBackParse extends Emiter {
this.parseArrayBuf();
}
})*/
this.getMediaRecrodInfoFromTx(()=>{
this.getMediaRecrodInfoFromTx(()=> {
//AGO启动录制消息和文件匹配
this.recordInfoMatch.start();
});
}
}
//时间戳转换为UTC 时间字符串
timestampToUTCTime(_timestamp){
let date=new Date(_timestamp);
let y=""+date.getFullYear();
let month=""+(date.getMonth()+1);
let d=""+date.getDate();
let h=""+(date.getHours()-8);//GMT 转UTC 减8
let minutes=""+date.getMinutes();
let s=""+date.getSeconds();
if (month.length<2){
month="0"+month;
}
if (d.length<2){
d="0"+d;
}
if (h.length<2){
h="0"+h;
}
if (minutes.length<2){
minutes="0"+minutes;
}
if (s.length<2){
s="0"+s;
}
let tiemStr=y+month+d+h+minutes+s;
timestampToUTCTime(_timestamp) {
let date = new Date(_timestamp);
let y = "" + date.getFullYear();
let month = "" + (date.getMonth() + 1);
let d = "" + date.getDate();
let h = "" + (date.getHours() - 8);//GMT 转UTC 减8
let minutes = "" + date.getMinutes();
let s = "" + date.getSeconds();
if (month.length < 2) {
month = "0" + month;
}
if (d.length < 2) {
d = "0" + d;
}
if (h.length < 2) {
h = "0" + h;
}
if (minutes.length < 2) {
minutes = "0" + minutes;
}
if (s.length < 2) {
s = "0" + s;
}
let tiemStr = y + month + d + h + minutes + s;
//console.log(_timestamp,tiemStr,date);
return tiemStr
}
//匹配时间戳和录制的视频地址
matchingVideoUrlFromTime(_tiemstampMessages,_allMedias){
if(!_tiemstampMessages||!_allMedias){
console.log("没有数据无法解析匹配",_tiemstampMessages,_allMedias)
matchingVideoUrlFromTime(_tiemstampMessages, _allMedias) {
if (!_tiemstampMessages || !_allMedias) {
console.log("没有数据无法解析匹配", _tiemstampMessages, _allMedias)
return;
}
if(Object.keys(_tiemstampMessages).length<1||Object.keys(_allMedias).length<1){
if (Object.keys(_tiemstampMessages).length < 1 || Object.keys(_allMedias).length < 1) {
console.log("数据没有加载完成->不做匹配");
return;
};
}
;
let finelMediaInfo={};
let unknowFiles={};//记录没有匹配到的,需要再次匹配
let finelMediaInfo = {};
let unknowFiles = {};//记录没有匹配到的,需要再次匹配
let tItem;
for(let j in _tiemstampMessages){
tItem=_tiemstampMessages[j];
let videoUrl="";
if(_allMedias[tItem.uid+"_"+tItem.createTimeUTC]){
videoUrl=_allMedias[tItem.uid+"_"+tItem.createTimeUTC];
for (let j in _tiemstampMessages) {
tItem = _tiemstampMessages[j];
let videoUrl = "";
if (_allMedias[tItem.uid + "_" + tItem.createTimeUTC]) {
videoUrl = _allMedias[tItem.uid + "_" + tItem.createTimeUTC];
//console.log(tItem.uid+"_"+tItem.createTimeUTC,videoUrl);
}else {
let t=parseInt(tItem.createTimeUTC);
console.log(tItem.uid+"_"+t,"没有数据->查找最近的数据");
videoUrl=_allMedias[tItem.uid+"_"+(t-1)];
if(!videoUrl){
videoUrl=_allMedias[tItem.uid+"_"+(t+1)];
} else {
let t = parseInt(tItem.createTimeUTC);
console.log(tItem.uid + "_" + t, "没有数据->查找最近的数据");
videoUrl = _allMedias[tItem.uid + "_" + (t - 1)];
if (!videoUrl) {
videoUrl = _allMedias[tItem.uid + "_" + (t + 1)];
}
if(!videoUrl){
unknowFiles[tItem.timestamp]=tItem;
if (!videoUrl) {
unknowFiles[tItem.timestamp] = tItem;
}
}
//console.log(tItem.uid+"_"+t+" "+videoUrl);
tItem.video_url=videoUrl;
finelMediaInfo[tItem.timestamp]=tItem;
tItem.video_url = videoUrl;
finelMediaInfo[tItem.timestamp] = tItem;
// MediaModule.streams[tItem.stream_id]=tItem.video_url;
MediaModule.streams[tItem.stream_id]={video_url:tItem.video_url,seek:0};
MediaModule.streams[tItem.stream_id] = {video_url: tItem.video_url, seek: 0};
}
console.log("finelMediaInfo",finelMediaInfo);
console.log("finelMediaInfo", finelMediaInfo);
//最后处理没有匹配到的
//检测没有匹配到数据的消息
for(let i in unknowFiles){
let noItem=unknowFiles[i];
for(let k in finelMediaInfo){
let okItem=finelMediaInfo[k];
let seek=(parseInt(noItem.timestamp)-parseInt(okItem.timestamp))/1000;
for (let i in unknowFiles) {
let noItem = unknowFiles[i];
for (let k in finelMediaInfo) {
let okItem = finelMediaInfo[k];
let seek = (parseInt(noItem.timestamp) - parseInt(okItem.timestamp)) / 1000;
//console.log("seek",seek);
if(noItem.uid==okItem.uid&&seek<15&&noItem.timestamp!=okItem.timestamp){
if (noItem.uid == okItem.uid && seek < 15 && noItem.timestamp != okItem.timestamp) {
//console.log(noItem,okItem);
noItem.video_url=okItem.video_url;
noItem.seek=seek;
finelMediaInfo [noItem.timestamp]=noItem;
noItem.video_url = okItem.video_url;
noItem.seek = seek;
finelMediaInfo [noItem.timestamp] = noItem;
//MediaModule.streams[noItem.stream_id]=noItem.video_url;
console.log("根据时间戳查找流",noItem.stream_id,{video_url:noItem.video_url,seek:seek})
MediaModule.streams[noItem.stream_id]={video_url:noItem.video_url,seek:seek};
console.log("根据时间戳查找流", noItem.stream_id, {video_url: noItem.video_url, seek: seek})
MediaModule.streams[noItem.stream_id] = {video_url: noItem.video_url, seek: seek};
}
}
}
console.log("服务端所有m3u8文件",_allMedias);
console.log("所有推流消息",_tiemstampMessages);
console.log("最终匹配结束的文件",finelMediaInfo);
console.log("回放中最终使用的视频流数据",MediaModule.streams);
console.log("服务端所有m3u8文件", _allMedias);
console.log("所有推流消息", _tiemstampMessages);
console.log("最终匹配结束的文件", finelMediaInfo);
console.log("回放中最终使用的视频流数据", MediaModule.streams);
}
//获取媒体录制的地址信息-时间戳流名称和文件地址对应
getRecordFileURLFromAgo(_callback){
if(!GlobalConfig.getRecordFileURLAgoInterfaces){
getRecordFileURLFromAgo(_callback) {
if (!GlobalConfig.getRecordFileURLAgoInterfaces) {
loger.log("AGOR-获取媒体录制信息->失败->接口地址无效");
if(_callback){
if (_callback) {
_callback();
}
return ;
return;
}
let url = `${GlobalConfig.locationProtocol+GlobalConfig.getRecordFileURLAgoInterfaces}`;
let url = `${GlobalConfig.locationProtocol + GlobalConfig.getRecordFileURLAgoInterfaces}`;
loger.log('AGOR-获取媒体录制信息.', url);
//接口中用的是GET
fetch(encodeURI(url), {
... ... @@ -475,7 +479,7 @@ class RecordPlayBackParse extends Emiter {
return ret.json();
} else {
loger.error(`AGOR-获取媒体录制信息-网络异常.状态码:${ret}`);
if(_callback){
if (_callback) {
_callback();
}
throw '';
... ... @@ -491,34 +495,35 @@ class RecordPlayBackParse extends Emiter {
fschannefiles:[]
}
} }*/
if(ret&&ret.code==200){
if(ret.returnData&&ret.returnData.data){
if (ret && ret.code == 200) {
if (ret.returnData && ret.returnData.data) {
this.parseAndSavaStreamInfoFromAgor(ret.returnData.data);
}
}
if(_callback){
if (_callback) {
_callback();
}
})
.catch(err => {
loger.error(`AGOR-获取媒体录制信息-异常.状态码:${err}`);
if(_callback){
if (_callback) {
_callback();
}
});
}
//获取媒体录制信息
getMediaRecrodInfoFromAgora(_callback){
getMediaRecrodInfoFromAgora(_callback) {
//获取课堂录制信息 get localhost:3000/recordInfo/getRecordInfo/7d72365eb9834353397e3e3f9d460bdda
//localhost:3000/recordInfo/getRecordInfo/ 后面直接添加课堂号 channel
if(!GlobalConfig.getRecordInfoInterfaces){
if (!GlobalConfig.getRecordInfoInterfaces) {
loger.log("AG-获取媒体录制信息->失败->接口地址无效");
if(_callback){
if (_callback) {
_callback();
}
return ;
return;
}
let url = `${GlobalConfig.locationProtocol+GlobalConfig.getRecordInfoInterfaces}/${GlobalConfig.channelId}`;
let url = `${GlobalConfig.locationProtocol + GlobalConfig.getRecordInfoInterfaces}/${GlobalConfig.channelId}`;
loger.log('AG-获取媒体录制信息.', url);
fetch(url, {
timeout: 15000
... ... @@ -528,7 +533,7 @@ class RecordPlayBackParse extends Emiter {
return ret.json();
} else {
loger.error(`AG-获取媒体录制信息-网络异常.状态码:${ret}`);
if(_callback){
if (_callback) {
_callback();
}
throw '';
... ... @@ -537,41 +542,42 @@ class RecordPlayBackParse extends Emiter {
.then(ret => {
loger.log('AG-获取媒体录制信息-完成');
//console.log("getRecordInfo success",ret);
if(ret&&ret.returnData&&ret.returnData.data){
let dataArr=ret.returnData.data;
for (let i=0;i<dataArr.length;i++){
let item=dataArr[i];
if(item.status==1){
if (ret && ret.returnData && ret.returnData.data) {
let dataArr = ret.returnData.data;
for (let i = 0; i < dataArr.length; i++) {
let item = dataArr[i];
if (item.status == 1) {
//console.log(JSON.stringify(item));
let time=parseInt(item.createTime);
item.createTimeUTC=this.timestampToUTCTime(time);
item.stream_id=item.channel+"_"+item.userId+"_"+item.timestamp;
this.agoTiemstampMessages[item.timestamp]=item;
let time = parseInt(item.createTime);
item.createTimeUTC = this.timestampToUTCTime(time);
item.stream_id = item.channel + "_" + item.userId + "_" + item.timestamp;
this.agoTiemstampMessages[item.timestamp] = item;
}
}
}
console.log("agoTiemstampMessages", this.agoTiemstampMessages);
if(_callback){
if (_callback) {
_callback();
}
})
.catch(err => {
loger.error(`AG-获取媒体录制信息-异常.状态码:${err}`);
if(_callback){
if (_callback) {
_callback();
}
});
}
//获取媒体录制信息
getMediaRecrodInfoFromTx(_callback){
if(!GlobalConfig.getTxRecordInfoInterfaces){
getMediaRecrodInfoFromTx(_callback) {
if (!GlobalConfig.getTxRecordInfoInterfaces) {
loger.log("TX-获取媒体录制信息->失败->接口地址无效");
if(_callback){
if (_callback) {
_callback();
}
return ;
return;
}
let url = `${GlobalConfig.locationProtocol+GlobalConfig.getTxRecordInfoInterfaces}`;
let url = `${GlobalConfig.locationProtocol + GlobalConfig.getTxRecordInfoInterfaces}`;
loger.log('TX-获取媒体录制信息.', url);
//接口中用的是GET
fetch(encodeURI(url), {
... ... @@ -587,7 +593,7 @@ class RecordPlayBackParse extends Emiter {
return ret.json();
} else {
loger.error(`TX-获取媒体录制信息-网络异常.状态码:${ret}`);
if(_callback){
if (_callback) {
_callback();
}
throw '';
... ... @@ -606,24 +612,25 @@ class RecordPlayBackParse extends Emiter {
}]
}
}*/
if(ret&&ret.code==200){
if(ret.returnData&&ret.returnData.data){
if (ret && ret.code == 200) {
if (ret.returnData && ret.returnData.data) {
this.parseAndSavaStreamInfoFromTx(ret.returnData.data);
}
}
if(_callback){
if (_callback) {
_callback();
}
})
.catch(err => {
loger.error(`获取媒体录制信息-异常.状态码:${err}`);
if(_callback){
if (_callback) {
_callback();
}
});
}
//解析agor录制的视频数据,数组[]
parseAndSavaStreamInfoFromAgor(_data){
parseAndSavaStreamInfoFromAgor(_data) {
//backFile:[
// {
// "channel": "markettest_628050539",
... ... @@ -636,7 +643,7 @@ class RecordPlayBackParse extends Emiter {
// ],//根据时间戳匹配好的播放地址
//fschannefiles:"http://networkschool.xuedianyun.com:8899/20171021/markettest_628050539_053439",//文件目录地址
//fschannefiles:[] //文件列表
if(!_data){
if (!_data) {
loger.log("AGOR-外部录制的视频数据无效");
return;
}
... ... @@ -662,57 +669,57 @@ class RecordPlayBackParse extends Emiter {
}
}
console.log("AGO MediaModule.streams", MediaModule.streams);*/
if(!_data.fschannefiles) return;
let items=_data.fschannefiles;
if (!_data.fschannefiles) return;
let items = _data.fschannefiles;
//console.log(JSON.stringify(items));
for(let k=0;k<items.length;k++) {
for (let k = 0; k < items.length; k++) {
let item=items[k];
let item = items[k];
// if(item.indexOf(".aac")>=0||item.indexOf(".webm")>=0){
// console.log(item)
// }
//console.log("item.indexOf ts",item.indexOf(".ts"))
// if(item.indexOf(".m3u8")>=0&&item.indexOf(".ts")<0&&item.indexOf(".m3u8.swp")<0){
let indexStr=".m3u8";
if(item.lastIndexOf(indexStr)+indexStr.length==item.length){
let indexStr = ".m3u8";
if (item.lastIndexOf(indexStr) + indexStr.length == item.length) {
//http://networkschool.xuedianyun.com:8899/20171021/markettest_188409305_030739/555257911_20171021031224730.mp4
//http://networkschool.xuedianyun.com:8899/20171021/markettest_1785982263_080003/572805001_20171021080041402_av.m3u8
let itemUrl=_data.channefiles+"/"+item;
let itemUrl = _data.channefiles + "/" + item;
//console.log(item,itemUrl);
item=item.substr(0,item.length-11);
this.agoAllMedias[item]=itemUrl;
item = item.substr(0, item.length - 11);
this.agoAllMedias[item] = itemUrl;
}
}
console.log("agoAllMedias",this.agoAllMedias);
console.log("agoAllMedias", this.agoAllMedias);
}
//解析TXY录制的视频数据,数组[]
parseAndSavaStreamInfoFromTx(_dataArr){
parseAndSavaStreamInfoFromTx(_dataArr) {
/* "id": "0zo9GALQdmkwrJVYxqgaE6xM7j8yvOZN",
"channelId": "marketflashtest_1966232762",
"recordInfo":"xxxxx",
"createTime":"xxxx"*/
if(!_dataArr){
if (!_dataArr) {
loger.log("TX-外部录制的视频数据无效");
return;
}
let item;
let itemJson;
loger.log("TX-外部录制的视频数据-length="+_dataArr.length)
for(let i=0;i<_dataArr.length;i++){
item=_dataArr[i];
if(item){
itemJson=item.recordInfo;
try{
itemJson=JSON.parse(itemJson);
}catch (err){
}
if(itemJson&&itemJson.video_url){
if(itemJson.video_url.indexOf(".m3u8")>0){
loger.log("TX-外部录制的视频数据-length=" + _dataArr.length)
for (let i = 0; i < _dataArr.length; i++) {
item = _dataArr[i];
if (item) {
itemJson = item.recordInfo;
try {
itemJson = JSON.parse(itemJson);
} catch (err) {
}
if (itemJson && itemJson.video_url) {
if (itemJson.video_url.indexOf(".m3u8") > 0) {
//MediaModule.streams[itemJson.stream_id]=itemJson.video_url;
MediaModule.streams[itemJson.stream_id]={video_url:itemJson.video_url,seek:0};
MediaModule.streams[itemJson.stream_id] = {video_url: itemJson.video_url, seek: 0};
}
}
}
... ... @@ -748,38 +755,39 @@ class RecordPlayBackParse extends Emiter {
/*if(this._recordPlaybackMaxTime<GlobalConfig.classTimestamp){
this._recordPlaybackMaxTime=GlobalConfig.classTimestamp;
}*/
if(this._recordPlaybackMaxTime<GlobalConfig.recordTimestamp){
this._recordPlaybackMaxTime=GlobalConfig.recordTimestamp;
if (this._recordPlaybackMaxTime < GlobalConfig.recordTimestamp) {
this._recordPlaybackMaxTime = GlobalConfig.recordTimestamp;
}
GlobalConfig.recordPlaybackMaxTime = this._recordPlaybackMaxTime;
console.log('课堂模块',this._conferApeMssages);
console.log('音视频通话模块数据',this.mediaChannleList);
console.log('媒体共享模块数据',this._mediaShareApeMssages);
console.log('伴音模块数据',this._musicShareApeMssages);
console.log('视频数据',this._videoApeMssages);
console.log('音频数据',this._audioApeMssages);
console.log('文档数据',this._docApeMssages);
console.log('白板数据',this._whiteApeMssages);
console.log('聊天数据',this._chatApeMssages);
console.log('视频模块广播消息',this._videoApeBroadcastMssages);
loger.log("录制回放数据解析完成,录制回放的总时间长为->", this._recordPlaybackMaxTime,"recordTimestamp:"+GlobalConfig.recordTimestamp);
console.log('课堂模块', this._conferApeMssages);
console.log('音视频通话模块数据', this.mediaChannleList);
console.log('媒体共享模块数据', this._mediaShareApeMssages);
console.log('伴音模块数据', this._musicShareApeMssages);
console.log('视频数据', this._videoApeMssages);
console.log('音频数据', this._audioApeMssages);
console.log('文档数据', this._docApeMssages);
console.log('白板数据', this._whiteApeMssages);
console.log('聊天数据', this._chatApeMssages);
console.log('视频模块广播消息', this._videoApeBroadcastMssages);
loger.log("录制回放数据解析完成,录制回放的总时间长为->", this._recordPlaybackMaxTime, "recordTimestamp:" + GlobalConfig.recordTimestamp);
this._emit(RecordPlayBackParse.CLASS_JOIN_RECORD_PLAYBACK_SUCCESS, {"recordPlaybackMaxTime": this._recordPlaybackMaxTime});
}
//根据时间查找数据
_searchMessageFromTime(_timestamp, _apeMessages,_ape) {
_searchMessageFromTime(_timestamp, _apeMessages, _ape) {
let msgDataArr = _apeMessages[_timestamp];
if (!msgDataArr) {
//没有数据,需要查找当前时间点属于哪一个时间戳关键帧
} else {
//把时间点对应的数据发送,同一秒内有存在多个数据的情况
loger.log(_ape,"回放数据->length:",msgDataArr.length)
loger.log(_ape, "回放数据->length:", msgDataArr.length)
for (let i = 0; i < msgDataArr.length; i++) {
this._everSocketMsgReceivedHandler(msgDataArr[i].byteData, 0);
}
}
}
//method------------外部接口-------------------------------------
//开始播放
... ... @@ -787,13 +795,13 @@ class RecordPlayBackParse extends Emiter {
if (!this._isReady) {
return {"code": ApeConsts.RETURN_FAILED, "data": "录制回放还未准备完成"};
}
loger.log("classStatusInfo",GlobalConfig.classStatusInfo);
console.log("所有流ID",this.allStreams);
for(let i in this.allStreams){
if(MediaModule.streams[i]){
console.log("匹配成功的流:"+i,MediaModule.streams[i]);
}else {
console.warn("未匹配成功的流:"+i);
loger.log("classStatusInfo", GlobalConfig.classStatusInfo);
console.log("所有流ID", this.allStreams);
for (let i in this.allStreams) {
if (MediaModule.streams[i]) {
console.log("匹配成功的流:" + i, MediaModule.streams[i]);
} else {
console.warn("未匹配成功的流:" + i);
}
}
this._startTimerCounter();
... ... @@ -805,8 +813,8 @@ class RecordPlayBackParse extends Emiter {
this._stopTimerCounter();
this._recordPlaybackTimestamp = 0;
//把记录的文档信息也要清除
GlobalConfig.activeDocId=0;
GlobalConfig.activeDocCurPage=1;
GlobalConfig.activeDocId = 0;
GlobalConfig.activeDocCurPage = 1;
this._emit(RecordPlayBackParse.RECORD_PLAYBACK_CLEAR_DATA);
this._emit(MessageTypes.RECORD_PLAYBACK_UPDATE, {"status": STOP});
}
... ... @@ -829,8 +837,8 @@ class RecordPlayBackParse extends Emiter {
this._stopTimerCounter();
this._recordPlaybackTimestamp = _param.time || 0;
//把记录的文档信息也要清除
GlobalConfig.activeDocId=0;
GlobalConfig.activeDocCurPage=1;
GlobalConfig.activeDocId = 0;
GlobalConfig.activeDocCurPage = 1;
this._emit(RecordPlayBackParse.RECORD_PLAYBACK_CLEAR_DATA);
//各个ape模块查找关键帧数据
this._searchSeekKeyfram();
... ... @@ -862,14 +870,13 @@ class RecordPlayBackParse extends Emiter {
this._searchWhiteboradHistoryMessageKeyfram(this._whiteApeMssages, ApeConsts.WHITEBOARD_SESSION_ID);
//各个ape模块无论有没有找到关键帧数据,都继续播放
this._startTimerCounter();
}
//查找ape关键帧数据
_searchApeMessageKeyfram(_apeMessages, _apeId) {
if(!_apeMessages){
if (!_apeMessages) {
return;
}
let messageItem;
... ... @@ -896,12 +903,12 @@ class RecordPlayBackParse extends Emiter {
}
//音视频模块seek的时候,查找当前seek点的关键帧数据,所有频道的数据都需要查一下,否则多路视频的时候会显示不全
searchMediaApeMessageKeyfram(_apeMessages){
if(!_apeMessages){
searchMediaApeMessageKeyfram(_apeMessages) {
if (!_apeMessages) {
return;
}
console.log('SEEK->查找音视频模块数据',_apeMessages)
if(_apeMessages) {
console.log('SEEK->查找音视频模块数据', _apeMessages)
if (_apeMessages) {
for (let k in _apeMessages) {
let channelInfos = _apeMessages[k];
let messageItem;
... ... @@ -910,18 +917,19 @@ class RecordPlayBackParse extends Emiter {
messageItem = channelInfos[i];
if (messageItem) {
keyFrameSeekTime = (this._recordPlaybackTimestamp - i);
loger.log("频道:"+k+"->SEEK->查找音视频模块数据->",messageItem,'keyFrameSeekTime->',keyFrameSeekTime)
loger.log("频道:" + k + "->SEEK->查找音视频模块数据->", messageItem, 'keyFrameSeekTime->', keyFrameSeekTime)
this._everSocketMsgReceivedHandler(messageItem.byteData, keyFrameSeekTime);
break;
}
}
loger.log("频道:"+k+"—>没有查找到数据")
loger.log("频道:" + k + "—>没有查找到数据")
}
}
}
//媒体共享模块查找关键帧时间戳的消息
searchMediaShareApeMessageKeyfram(_apeMessages){
if(!_apeMessages){
searchMediaShareApeMessageKeyfram(_apeMessages) {
if (!_apeMessages) {
return;
}
let messageItem;
... ... @@ -930,7 +938,7 @@ class RecordPlayBackParse extends Emiter {
messageItem = _apeMessages[i];
if (messageItem) {
keyFrameSeekTime = (this._recordPlaybackTimestamp - i)
loger.log("SEEK->APE",'媒体共享',this._recordPlaybackTimestamp, "查找到相连的timestamp->", i, '需要seek->', keyFrameSeekTime, "秒");
loger.log("SEEK->APE", '媒体共享', this._recordPlaybackTimestamp, "查找到相连的timestamp->", i, '需要seek->', keyFrameSeekTime, "秒");
//把时间点对应的数据发送,同一秒内有存在多个数据的情况
for (let k = 0; k < messageItem.length; k++) {
this._everSocketMsgReceivedHandler(messageItem[k].byteData, keyFrameSeekTime);
... ... @@ -942,8 +950,8 @@ class RecordPlayBackParse extends Emiter {
}
//伴音共享模块查找关键帧时间戳的消息
searchMusicShareApeMessageKeyfram(_apeMessages){
if(!_apeMessages){
searchMusicShareApeMessageKeyfram(_apeMessages) {
if (!_apeMessages) {
return;
}
let messageItem;
... ... @@ -952,7 +960,7 @@ class RecordPlayBackParse extends Emiter {
messageItem = _apeMessages[i];
if (messageItem) {
keyFrameSeekTime = (this._recordPlaybackTimestamp - i)
loger.log("SEEK->APE",'伴音共享',this._recordPlaybackTimestamp, "查找到相连的timestamp->", i, '需要seek->', keyFrameSeekTime, "秒");
loger.log("SEEK->APE", '伴音共享', this._recordPlaybackTimestamp, "查找到相连的timestamp->", i, '需要seek->', keyFrameSeekTime, "秒");
//把时间点对应的数据发送,同一秒内有存在多个数据的情况
for (let k = 0; k < messageItem.length; k++) {
this._everSocketMsgReceivedHandler(messageItem[k].byteData, keyFrameSeekTime);
... ... @@ -965,13 +973,13 @@ class RecordPlayBackParse extends Emiter {
//查找聊天模块ape关键帧数据,聊天模块比较特殊,消息是累积的,当前时间戳之前的都需要显示
_searchChatHistoryMessageKeyfram(_apeMessages) {
if(!_apeMessages){
if (!_apeMessages) {
return;
}
//最多30条数据
let counter=0;
let counter = 0;
let messageItem;
let mssageArr=[];
let mssageArr = [];
for (let i = this._recordPlaybackTimestamp; i > 0; i--) {
messageItem = _apeMessages[i];
if (messageItem) {
... ... @@ -980,7 +988,7 @@ class RecordPlayBackParse extends Emiter {
//this._everSocketMsgReceivedHandler(messageItem[i].byteData, 0);
mssageArr.push(messageItem[i].byteData);
counter++;
if(counter>40){
if (counter > 40) {
loger.warn("SEEK->最多处理历史消息30条");
break;
}
... ... @@ -988,9 +996,9 @@ class RecordPlayBackParse extends Emiter {
}
}
//mssageArr记录的数据是按时间最大排序的,发消息的时候需要从时间小的开始,倒着发数据
let len=mssageArr.length;
if(len>0){
for (let k=len-1;k>=0;k--){
let len = mssageArr.length;
if (len > 0) {
for (let k = len - 1; k >= 0; k--) {
this._everSocketMsgReceivedHandler(mssageArr[k], 0);
}
}
... ... @@ -998,11 +1006,11 @@ class RecordPlayBackParse extends Emiter {
//查找白板标注模块ape关键帧数据,聊天模块比较特殊,消息是累积的,当前时间戳之前的都需要显示
_searchWhiteboradHistoryMessageKeyfram(_apeMessages) {
if(!_apeMessages){
if (!_apeMessages) {
return;
}
//最多100条数据
let counter=0;
let counter = 0;
let messageItem;
for (let i = this._recordPlaybackTimestamp; i > 0; i--) {
messageItem = _apeMessages[i];
... ... @@ -1011,7 +1019,7 @@ class RecordPlayBackParse extends Emiter {
for (let i = 0; i < messageItem.length; i++) {
this._everSocketMsgReceivedHandler(messageItem[i].byteData, 0);
counter++;
if(counter>40){
if (counter > 40) {
loger.warn("SEEK->最多处理历史消息40条");
return;
}
... ... @@ -1019,17 +1027,18 @@ class RecordPlayBackParse extends Emiter {
}
}
}
//解析视频模块的广播消息
unpackVideoBroadcastMessage(pduMsg,timestamp,data){
unpackVideoBroadcastMessage(pduMsg, timestamp, data) {
//console.log("VIDEO_SESSION_ID-pduMsg",pduMsg);
if(!pduMsg){
if (!pduMsg) {
return;
}
if(pduMsg.subType!=pdu.RCPDU_SEND_VIDEO_DATA_REQUEST){
if (pduMsg.subType != pdu.RCPDU_SEND_VIDEO_DATA_REQUEST) {
//视频广播消息,只处理501消息
return;
}
try{
try {
let videoReceivePdu = pdu['RCVideoSendDataRequestPdu'].decode(pduMsg.data);
if (videoReceivePdu == null) {
loger.warn("视频模块广播消息-decode->失败");
... ... @@ -1048,9 +1057,9 @@ class RecordPlayBackParse extends Emiter {
//data :Object
//fromNodeId :902994631
//toNodeId : 0
if(videoReceivePdu.actionType==40){
if(!this._videoApeBroadcastMssages[videoReceivePdu.fromNodeId]){
this._videoApeBroadcastMssages[videoReceivePdu.fromNodeId]={};
if (videoReceivePdu.actionType == 40) {
if (!this._videoApeBroadcastMssages[videoReceivePdu.fromNodeId]) {
this._videoApeBroadcastMssages[videoReceivePdu.fromNodeId] = {};
}
/*
//结构
... ... @@ -1063,29 +1072,33 @@ class RecordPlayBackParse extends Emiter {
},.....
}*/
this._videoApeBroadcastMssages[videoReceivePdu.fromNodeId][timestamp]={parseData:videoReceivePdu,byteData:data,timestamp: timestamp};
this._videoApeBroadcastMssages[videoReceivePdu.fromNodeId][timestamp] = {
parseData: videoReceivePdu,
byteData: data,
timestamp: timestamp
};
//this._videoApeBroadcastMssages[timestamp]={parseData:videoReceivePdu,byteData:data,timestamp: timestamp};
}
}catch (err){
console.log("视频模块广播消息->解析失败",err.message);
} catch (err) {
console.log("视频模块广播消息->解析失败", err.message);
}
}
//音视频的数据需要解析,然后按频道储存数据
// 解析pdu RCAdapterPdu的数据: regBuffer(RCAdapterPdu数据),timestamp(时间戳), data(mcu的原始数据) sessionId(类型)
unPackpduRegAdapterHandler(regBuffer, timestamp, data, sessionId,subType) {
unPackpduRegAdapterHandler(regBuffer, timestamp, data, sessionId, subType) {
let regPdu;
let regItems ;
let regItemSize ;
try{
let regItems;
let regItemSize;
try {
//console.log('RCAdapterPdu--->')
regPdu = pdu['RCAdapterPdu'].decode(regBuffer);
regItems = regPdu.item;
regItemSize = regItems.length;
}catch (err){
console.warn('RCAdapterPdu->unpack-error->type类型不对',"subType:"+subType);
} catch (err) {
console.warn('RCAdapterPdu->unpack-error->type类型不对', "subType:" + subType);
return;
}
... ... @@ -1098,7 +1111,7 @@ class RecordPlayBackParse extends Emiter {
if (pdu.RCPDU_REG_UPDATE_OBJ !== regItemType) {
if (pdu.RCPDU_REG_RESPONSE_OBJ == regItemType) {
let regResponsePdu = pdu['RCRegistryResponseObjPdu'].decode(regItemData);
console.log('regResponsePdu',regResponsePdu)
console.log('regResponsePdu', regResponsePdu)
//this.regResponsePduHandler(regResponsePdu);
}
// 只处理两种类型
... ... @@ -1158,7 +1171,7 @@ class RecordPlayBackParse extends Emiter {
break;
case pdu.RCPDU_SEND_VIDEO_DATA_REQUEST:
//视频模块的控制消息
try{
try {
let videoReceivePdu = pdu['RCVideoSendDataRequestPdu'].decode(user_data);
if (videoReceivePdu == null) {
loger.warn("视频控制消息处理,收到的消息为null,不做处理");
... ... @@ -1173,9 +1186,13 @@ class RecordPlayBackParse extends Emiter {
dataObj = videoReceivePdu.data;
}
videoReceivePdu.data = dataObj;
this._videoApeBroadcastMssages[timestamp]={parseData:videoReceivePdu,byteData:data,timestamp: timestamp};
}catch (err){
loger.warn("RCPDU_SEND_VIDEO_DATA_REQUEST->err",err);
this._videoApeBroadcastMssages[timestamp] = {
parseData: videoReceivePdu,
byteData: data,
timestamp: timestamp
};
} catch (err) {
loger.warn("RCPDU_SEND_VIDEO_DATA_REQUEST->err", err);
}
break;
case pdu.RCPDU_REG_TABLE_UPDATE_PDU:
... ... @@ -1186,37 +1203,47 @@ class RecordPlayBackParse extends Emiter {
let tableItem = tableUpdateItems[i];
//只处理音视频模块的消息
if(sessionId==ApeConsts.VIDEO_SESSION_ID){
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]={};
}
let statusStr="关";
if(videoChannelInfo&&videoChannelInfo.status==1){
statusStr="开";
this.allStreams[videoChannelInfo.streamId]=videoChannelInfo;
console.log("视频流"+videoChannelInfo.streamId);
}
this.mediaChannleList[videoChannelInfo.channelId][timestamp]={parseData:videoChannelInfo,byteData:data,timestamp: timestamp,status:statusStr};
if (!this.mediaChannleList[videoChannelInfo.channelId]) {
this.mediaChannleList[videoChannelInfo.channelId] = {};
}
let statusStr = "关";
if (videoChannelInfo && videoChannelInfo.status == 1) {
statusStr = "开";
this.allStreams[videoChannelInfo.streamId] = videoChannelInfo;
console.log("视频流" + videoChannelInfo.streamId);
}
this.mediaChannleList[videoChannelInfo.channelId][timestamp] = {
parseData: videoChannelInfo,
byteData: data,
timestamp: timestamp,
status: statusStr
};
} catch (err) {
loger.log("RCVideoChannelInfoPdu->unPackPdu->error->" + tableItem.itemIdx + " err:" + err.message);
}
}else if(sessionId==ApeConsts.AUDIO_SESSION_ID){
} else if (sessionId == ApeConsts.AUDIO_SESSION_ID) {
try {
let audioChannelInfo = pdu['RCAudioChannelInfoPdu'].decode(tableItem.itemData);
loger.log('RCAudioChannelInfoPdu->timestamp',timestamp,audioChannelInfo);
loger.log('RCAudioChannelInfoPdu->timestamp', timestamp, audioChannelInfo);
//储存音视频模块的数据
if(!this.mediaChannleList[audioChannelInfo.channelId]){
this.mediaChannleList[audioChannelInfo.channelId]={};
}
let statusStr="关";
if(audioChannelInfo&&audioChannelInfo.status==1){
statusStr="开";
}
this.mediaChannleList[audioChannelInfo.channelId][timestamp]={parseData:audioChannelInfo,byteData:data,timestamp: timestamp,status:statusStr};
if (!this.mediaChannleList[audioChannelInfo.channelId]) {
this.mediaChannleList[audioChannelInfo.channelId] = {};
}
let statusStr = "关";
if (audioChannelInfo && audioChannelInfo.status == 1) {
statusStr = "开";
}
this.mediaChannleList[audioChannelInfo.channelId][timestamp] = {
parseData: audioChannelInfo,
byteData: data,
timestamp: timestamp,
status: statusStr
};
} catch (err) {
loger.log("RCAudioChannelInfoPdu->unPackPdu->error->" + tableItem.itemIdx + " err:" + err.message);
}
... ...
... ... @@ -245,7 +245,7 @@ class ConferApe extends Ape {
optional string filename = 4; // 录像文件名称,filename中增加目录部分
}*/
if(this.recordStatus==conferRecordSendPdu.record){
if(this.recordStatus==true){
//已经有录制文件,不再发送
return;
}
... ... @@ -533,7 +533,6 @@ class ConferApe extends Ape {
});
} else {
loger.warn("踢人失败-参数无效")
console.log(_param);
}
}
... ...
... ... @@ -862,15 +862,18 @@ class WebRtcApe extends Emiter {
});
}
//调用媒体服务停止录制
stopRecordingMedia() {
//192.168.31.8:3000/recordInfo/stopRecording/
if (!GlobalConfig.stopRecordingInterfaces) {
loger.log("调用服务器端开启录制->失败->接口地址无效");
/*
* 切换音视频的录制状态
* */
changeMediaRecordStatus(_params) {
if (!GlobalConfig.recordInterfaces||!_params) {
loger.warn("切换音视频的录制状态->失败->接口地址无效",_params);
return;
}
let url = GlobalConfig.locationProtocol + GlobalConfig.stopRecordingInterfaces;
let data = this.packMediaInfoData(WebRtcApe.RECORD_STATUS_2);
loger.warn("切换音视频的录制状态->"+_params);
let url = GlobalConfig.locationProtocol + GlobalConfig.recordInterfaces;
let curTimestamp = new Date().getTime();
let data = `appId=${GlobalConfig.appId}&channel=${GlobalConfig.channelId}&channelKey=${GlobalConfig.appCertificate}&uid=${GlobalConfig.userUid}&status=${_params.status}&userId=${GlobalConfig.userId}&userName=${GlobalConfig.userName}&userRole=${GlobalConfig.userRole}&timestamp=${curTimestamp}&recordTimestamp=${GlobalConfig.recordTimestamp}`;
fetch(encodeURI(url), {
method: 'POST',
headers: {
... ... @@ -883,19 +886,19 @@ class WebRtcApe extends Emiter {
if (ret.ok) {
return ret.json();
} else {
loger.error(`调用服务器端开启录制-网络异常.状态码:${ret.status}`);
loger.error(`切换音视频的录制状态-网络异常.状态码:${ret.status}`);
throw '';
}
})
.then(ret => {
if (ret) {
loger.log('调用服务器端开启录制完成', ret);
loger.log('切换音视频的录制状态->完成', ret);
} else {
loger.warn('调用服务器端开启录制 失败.', ret);
loger.warn('切换音视频的录制状态 失败.', ret);
}
})
.catch(err => {
loger.error(`调用服务器端开启录制.状态码:${err}`);
loger.error(`切换音视频的录制状态.状态码:${err}`);
});
}
}
... ...