RecordPlayBackParse.js 17.0 KB
import ByteBuffer  from 'libs/bytebuffer.min';
import Emiter from 'Emiter';
import MessageTypes from 'MessageTypes';
import Loger from 'Loger';

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';
import EngineUtils from 'EngineUtils';
import TimerCounter from "TimerCounter";


let parseBuffer;
// 日志对象
const loger = Loger.getLoger('RecordPlayBackParse');
const Default = 0;//未开始
const PLAY = 1;//播放中
const PAUSE = 2;//暂停
const SEEK = 3;//seek
const STOP = 4;//停止

class RecordPlayBackParse extends Emiter {
    constructor() {
        super();
        loger.log("RecordPlayBackParse");
        parseBuffer = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN);
        parseBuffer.clear();
        console.log(parseBuffer);
        this._recordPlaybackTimestamp = 0;//回放的时间
        this._recordPlaybackMaxTime = 0;//录制回放的总时间
        this._isReady = false;//录制回放是否已经准备完成
        this._apes = {};
        this._messages = {};

        this._conferApeMssages = {};//会议数据
        this._chatApeMssages = {};//聊天数据
        this._videoApeMssages = {};//视频数据
        this._audioApeMssages = {};//音频数据
        this._docApeMssages = {};//文档数据
        this._whiteApeMssages = {};//白板数据

        this._timerCounter = new TimerCounter();//计时器
        this._timerCounter.addTimerCallBack(this._timerCounterUptate.bind(this), 1);
    }

    //method--------------------内部---------------------------------------------
    // 注册Ape
    registerApe(ape) {
        this._apes[ape._session_id] = ape;
    }

    // 录制回放EverSocket底层消息处理  data-数据;timestamp-数据对应的时间戳
    // 1.如果第二个参数timestamp不为空,数据就不往外发送,只做解析和储存
    // 2.如果第二个参数timestamp为空,数据就发送给各个ape处理;
    _everSocketMsgReceivedHandler(data, timestamp) {
        let pduMsg = pdu.decode_pdu(data);
        let pduType = pduMsg.get("type");
        let pduData = pduMsg.get("data");
        //*************非常重要******************
        //客户端发送的所有125消息,MCU收到之后会痛120把消息返回给客户端,
        //所以需要把125消息type转换为120,因为MCU在录制的时候是直接录制客户端发送的消息而不是MCU转换之后的
        if (pduType == PduType.RCPDU_UNIFORM_SEND_DATA_REQUEST) {
            pduMsg.type = PduType.RCPDU_SEND_DATA_REQUEST;
            pduType = PduType.RCPDU_SEND_DATA_REQUEST;
        }
        loger.log('pduType', pduType);
        switch (pduType) {
            case PduType.RCPDU_CONNECT_PROVIDER_RESPONSE:
                //加入课堂请求返回数据处理
                let joinConfPdu = pdu['RCConferenceJoinResponsePdu'].decode(pduData);
                let pduResultCode = joinConfPdu.result;
                loger.warn('RCPDU_CONNECT_PROVIDER_RESPONSE  ->pduResultCode:' + pduResultCode);
                switch (pduResultCode) {
                    case PduConsts.RET_SUCCESS:
                        //加入成功
                        this._updateMCUConfInfoDescription(joinConfPdu.classDescription);
                        this._emit(MessageTypes.CLASS_JOIN_MCU_SUCCESS, this.classInfo);
                        break;
                    case PduConsts.RET_FULL_CAPACITY:
                        this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_JOIN_FULL);
                        break;
                    default:
                        loger.warn('JoinConfPdu-未知类型-等待处理.', pduResultCode);
                        break
                }
                break;
            case PduType.RCPDU_SEND_DATA_REQUEST:
                //先判断当前消息属于哪个APE 根据 sessionId来判断
                let ape = this._apes[pduMsg.sessionId];
                let sessionLabel = ApeConsts(pduMsg.sessionId);
                if (timestamp) {
                    //只做解析存储,不对外发送
                    loger.log('解析数据-timestamp->', timestamp, 'sessionId->', pduMsg.sessionId, 'sessionLabel->', sessionLabel);
                    switch (pduMsg.sessionId) {
                        case ApeConsts.CONFERENCE_SESSION_ID:
                            this.saveParseData(data, timestamp, this._conferApeMssages);
                            break;
                        case ApeConsts.CHAT_SESSION_ID:
                            this.saveParseData(data, timestamp, this._chatApeMssages);
                            break;
                        case ApeConsts.DOCSHARING_SESSION_ID:
                            this.saveParseData(data, timestamp, this._docApeMssages);
                            break;
                        case ApeConsts.WHITEBOARD_SESSION_ID:
                            this.saveParseData(data, timestamp, this._whiteApeMssages);
                            break;
                        case ApeConsts.VIDEO_SESSION_ID:
                            this.saveParseData(data, timestamp, this._videoApeMssages);
                            break;
                        case ApeConsts.AUDIO_SESSION_ID:
                            this.saveParseData(data, timestamp, this._audioApeMssages);
                            break;
                        default:
                            break;
                    }
                } else {
                    //对方发送消息
                    if (ape) {
                        let subTypeLabel = pdu.id2type(pduMsg.subType);
                        //loger.log('MCU-SecondLayer封装消息', 'sessionId', sessionLabel, pduMsg.sessionId, 'subtype', subTypeLabel, pduMsg.subType);
                        //ape广播事件,只要ape中监听就能收到
                        ape._emit(pduMsg.subType, pduMsg.data);
                    } else {
                        loger.warn(sessionLabel + '尚未注册');
                    }
                }
                break;
            default:
                loger.warn('PDU-未知类型-等待处理.', pduType);
        }
    }

    //保存数据
    saveParseData(data, timestamp, apeMessages) {
        let messageItem = apeMessages[timestamp];
        if (!messageItem) {
            apeMessages[timestamp] = [];//数组存数据,因为有1秒内收到多个消息的情况,timestamp是按秒记录的
            messageItem = apeMessages[timestamp];
        }
        messageItem.push({"timestamp": timestamp, "byteData": data});

    }

    //开启计时器
    _startTimerCounter() {
        this._timerCounter.startTimer();
    }

    //停止计时器
    _stopTimerCounter() {
        this._timerCounter.stopTimer();
    }

    _timerCounterUptate() {
        this._recordPlaybackTimestamp = this._recordPlaybackTimestamp + 1;//计时
        if (this._recordPlaybackTimestamp >= this._recordPlaybackMaxTime) {
            this._stopTimerCounter();
            loger.log("录制回放结束...当前时间->", this._recordPlaybackTimestamp, " 总时间->", this._recordPlaybackMaxTime);
            this._emit(MessageTypes.RECORD_PLAYBACK_UPDATE, {"status": STOP});
            return;
        }

        loger.log("录制回放中...", this._recordPlaybackTimestamp);
        this._emit(MessageTypes.CLASS_UPDATE_TIMER, {"classTimestamp": this._recordPlaybackTimestamp});

        //各个APE模块根据时间查找消息数据
        this._searchMessageFromTime(this._recordPlaybackTimestamp, this._conferApeMssages);
        this._searchMessageFromTime(this._recordPlaybackTimestamp, this._chatApeMssages);
        this._searchMessageFromTime(this._recordPlaybackTimestamp, this._docApeMssages);
        this._searchMessageFromTime(this._recordPlaybackTimestamp, this._whiteApeMssages);
        this._searchMessageFromTime(this._recordPlaybackTimestamp, this._videoApeMssages);
        this._searchMessageFromTime(this._recordPlaybackTimestamp, this._audioApeMssages);
    }

    //加载录制文件
    readyRecordPlay() {
        this._isReady = false;
        this._stopTimerCounter();
        loger.log("读取回放数据");
        //let url = `http://123.56.73.119:80/h5dev/20170306/1357644520_20170306.rec`;
        let url = `http://${ GlobalConfig.RecordServerIP}:${ GlobalConfig.RecordServerPort}/${GlobalConfig.recordFileName}`;
        console.log(url);
        fetch(url, {
            timeout: 90000 //加载文件超时时间1分30秒
        })
            .then(ret => {
                if (ret.ok) {
                    return ret.arrayBuffer();
                } else {
                    loger.error(`读取回放数据-网络异常.状态码:${ret.status}`);
                    this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_GET_RECORD_PLAY_BACK_DATA_FAILED);
                    throw '';
                }
            })
            .then(ret => {
                if (ret) {
                    loger.log('读取回放数据-完成');
                    this._loadRecordDataSuccess(ret);
                } else {
                    loger.warn('读取回放数据-失败.');
                    this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_GET_RECORD_PLAY_BACK_DATA_FAILED);
                }
            })
            .catch(err => {
                loger.error(`读取回放数据.状态码:${err}`);
                this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_GET_RECORD_PLAY_BACK_DATA_FAILED);
            });
    }

    _loadRecordDataSuccess(arrayBuffer) {
        loger.log("获取录制回放数据的长度", arrayBuffer.byteLength);
        if (parseBuffer) {
            parseBuffer.clear();
            parseBuffer.append(arrayBuffer);
            //解析数据
            this.parseArrayBuf();
        }
    }

    //解析数据
    parseArrayBuf() {
        this._messages = {};
        let byteLength = parseBuffer.offset;
        parseBuffer.byteOffset = 0;
        var position = 0;
        while (position < byteLength) {
            let timestamp = parseBuffer.readUInt32(position);
            position += 4;//4字节
            let byteLen = parseBuffer.readUInt32(position);
            position += 4;//4字节
            let byteData = parseBuffer.buffer.slice(position, (position + byteLen));
            position += byteLen;
            console.log(timestamp, byteLen, byteData);

            let messageItem = this._messages[timestamp];
            if (!messageItem) {
                this._messages[timestamp] = [];//数组存数据,因为有1秒内收到多个消息的情况,timestamp是按秒记录的
                messageItem = this._messages[timestamp];
            }
            messageItem.push({"timestamp": timestamp, "byteData": byteData});

            this._everSocketMsgReceivedHandler(byteData, timestamp);
            //记录最后一个数据的时间戳作为整个录制回放的总时间戳
            this._recordPlaybackMaxTime = timestamp;
        }
        this._recordPlaybackTimestamp = 0;
        this._isReady = true;
        this._stopTimerCounter();

        GlobalConfig.recordPlaybackMaxTime = this._recordPlaybackMaxTime;
        loger.log("录制回放数据解析完成,录制回放的总时间长为->", this._recordPlaybackMaxTime);
        console.log("_messages", this._messages);
        console.log("_conferApeMssages", this._conferApeMssages);
        console.log("_chatApeMssages", this._chatApeMssages);
        console.log("_docApeMssages", this._docApeMssages);
        console.log("_whiteApeMssages", this._whiteApeMssages);
        console.log("_videoApeMssages", this._videoApeMssages);
        console.log("_audioApeMssages", this._audioApeMssages);

        this._emit(RecordPlayBackParse.CLASS_JOIN_RECORD_PLAYBACK_SUCCESS, {"recordPlaybackMaxTime": this._recordPlaybackMaxTime});
    }

    //根据时间查找数据
    _searchMessageFromTime(_timestamp, _apeMessages) {
        let msgDataArr = _apeMessages[_timestamp];
        if (!msgDataArr) {
            //没有数据,需要查找当前时间点属于哪一个时间戳关键帧
        } else {
            //把时间点对应的数据发送,同一秒内有存在多个数据的情况
            for (let i = 0; i < msgDataArr.length; i++) {
                this._everSocketMsgReceivedHandler(msgDataArr[i].byteData);
            }
        }
    }

    /*_searchMessageFromTime(_timestamp,_apeMessages){
     let msgDataArr=this._messages[_timestamp];
     if(!msgDataArr){
     //没有数据,需要查找当前时间点属于哪一个时间戳关键帧
     }else {
     //把时间点对应的数据发送,同一秒内有存在多个数据的情况
     for(let i=0;i<msgDataArr.length;i++){
     this._everSocketMsgReceivedHandler(msgDataArr[i].byteData);
     }
     }
     }*/

    //method------------外部接口-------------------------------------

    //开始播放
    startRecordPlayback(_param) {
        if (!this._isReady) {
            return {"code": ApeConsts.RETURN_FAILED, "data": "录制回放还未准备完成"};
        }
        this._startTimerCounter();
        this._emit(MessageTypes.RECORD_PLAYBACK_UPDATE, {"status": PLAY});
    }

    //停止播放
    stopRecordPlayback(_param) {
        this._recordPlaybackTimestamp = 0;
        this._stopTimerCounter();
        this._emit(MessageTypes.RECORD_PLAYBACK_UPDATE, {"status": STOP});
    }

    //暂停播放
    pauseRecordPlayback(_param) {
        this._stopTimerCounter();
        this._emit(MessageTypes.RECORD_PLAYBACK_UPDATE, {"status": PAUSE});
    }

    //跳转到指定时间点播放
    seekRecordPlayback(_param) {
        if (!this._isReady) {
            return {"code": ApeConsts.RETURN_FAILED, "data": "录制回放还未准备完成"};
        }
        if (!_param || !_param.time) {
            return {"code": ApeConsts.RETURN_FAILED, "data": "参数不正确"};
        }
        //先暂停,更改进行的时间
        this._stopTimerCounter()
        this._recordPlaybackTimestamp = _param.time || 0;

        //各个ape模块查找关键帧数据
        this._searchKeyfram();
    }

    _searchKeyfram() {
        //查找关键帧,找到关键帧后再继续播放
        this._searchApeMessageKeyfram(this._conferApeMssages,ApeConsts.CONFERENCE_SESSION_ID);
        this._searchApeMessageKeyfram(this._docApeMssages,ApeConsts.DOCSHARING_SESSION_ID);
        this._searchApeMessageKeyfram(this._whiteApeMssages,ApeConsts.WHITEBOARD_SESSION_ID);
        this._searchApeMessageKeyfram(this._videoApeMssages,ApeConsts.VIDEO_SESSION_ID);
        this._searchApeMessageKeyfram(this._audioApeMssages,ApeConsts.AUDIO_SESSION_ID);

        //聊天模块的比较特殊,消息是累计的
        this._searchChatApeMessageKeyfram(this._chatApeMssages,ApeConsts.CHAT_SESSION_ID);


        //各个ape模块无论有没有找到关键帧数据,都继续播放
        this._startTimerCounter();
    }

    //查找ape关键帧数据
    _searchApeMessageKeyfram(_apeMessages,_apeId) {
        let messageItem;
        let keyFrameSeek = 0;
        for (let i = this._recordPlaybackTimestamp; i > 0; i--) {
            messageItem = _apeMessages[i];
            if (messageItem) {
                keyFrameSeek = (this._recordPlaybackTimestamp - i)
                loger.log("SEEK->APE",_apeId, this._recordPlaybackTimestamp, "查找到相连的数据, messageItem.timestamp->",i, this._recordPlaybackTimestamp,keyFrameSeek, "秒");
                //把时间点对应的数据发送,同一秒内有存在多个数据的情况
                for (let k = 0; k < messageItem.length; k++) {
                    this._everSocketMsgReceivedHandler(messageItem[k].byteData);
                }
                if(_apeId==ApeConsts.AUDIO_SESSION_ID||_apeId==ApeConsts.VIDEO_SESSION_ID){
                    this._emit(MessageTypes.RECORD_PLAYBACK_UPDATE, {"status": SEEK, "keyFrameSeek": keyFrameSeek});
                }
                return;
            }
        }
        loger.log("SEEK->APE",_apeId, this._recordPlaybackTimestamp, "没有查找到相连的数据");
        //this._emit(MessageTypes.RECORD_PLAYBACK_UPDATE,{"status":SEEK,"keyFrameSeek":keyFrameSeek});
    }

    //查找聊天模块ape关键帧数据,聊天模块比较特殊,消息是累积的,当前时间戳之前的都需要显示
    _searchChatApeMessageKeyfram(_apeMessages) {
        let messageItem;
        let keyFrameSeek = 0;
        for (let i = this._recordPlaybackTimestamp; i > 0; i--) {
            messageItem = _apeMessages[i];
            if (messageItem) {
                //把时间点对应的数据发送,同一秒内有存在多个数据的情况
                for (let i = 0; i < messageItem.length; i++) {
                    this._everSocketMsgReceivedHandler(messageItem[i].byteData);
                }
            }
        }
    }

}

RecordPlayBackParse.prototype.CLASS_JOIN_RECORD_PLAYBACK_SUCCESS = RecordPlayBackParse.CLASS_JOIN_RECORD_PLAYBACK_SUCCESS = 'class_join_recordPlayback_success';//加入录制回放成功

export default new RecordPlayBackParse;