VideoApe.js 13.8 KB
// //////////////////////////////////////////////////////////////////////////////
//视频模块
// //////////////////////////////////////////////////////////////////////////////

import Ape from './Ape';
import ApeConsts from './ApeConsts';
import pdu from 'pdus';
import Loger from 'Loger';
import MessageTypes from 'MessageTypes';
import GlobalConfig from 'GlobalConfig';
import EngineUtils from 'EngineUtils';
import MediaModule from "./MediaModule";

let loger = Loger.getLoger('VideoApe');

class VideoApe extends Ape {
    constructor() {
        super(
            ApeConsts.VIDEO_SESSION_ID,
            ApeConsts.VIDEO_SESSION_NAME,
            ApeConsts.VIDEO_SESSION_TAG
        );

        this.mediaModule=new MediaModule();
        this.mediaModule.MEDIA_OBJ_TABLE_ID=ApeConsts.VIDEO_OBJ_TABLE_ID;
        this.mediaModule.mediaChannels={};

        // Ape Models
        this.registerKey(this._session_id, this._session_name, this._session_tag, new ArrayBuffer);
        this.registerObj(pdu.RCPDU_REG_REGISTER_TABLE, ApeConsts.VIDEO_OBJ_TABLE_ID, ApeConsts.VIDEO_OBJ_TABLE_NAME, ApeConsts.VIDEO_OBJ_TABLE_TAG, 0, new ArrayBuffer);

        // videoApe 监听视频控制消息,用户之间的消息传递
        this.on(pdu.RCPDU_SEND_VIDEO_DATA_REQUEST, this.receiveVideoCommandHandler.bind(this));
    }
    //ape加入成功
    onJoinChannelHandlerSuccess(){
        //这个设置很重要,因为只有Sass流程完成之后,APE才能取得GlobalConfig中的数据
        this.mediaModule.maxMediaChannel=GlobalConfig.maxVideoChannels;
    }

    /////////////发送数据操作////////////////////////////////////////////
    //获取播流地址
    getPlayVideoPath(_param) {
        loger.log('getPlayVideoPath');
        return this.mediaModule.getMediaPlayPath(_param);
    }

    //获取推流地址
    getPublishVideoPath(_param) {
        loger.log('getPublishVideoPath');
        return this.mediaModule.getMediaPublishPath(_param);
    }

    //推流
    publishVideo(_param) {
        if(!this.mcu.connected){
            loger.warn(GlobalConfig.getCurrentStatus());
            return {"code": ApeConsts.RETURN_FAILED, "data": "已经断开连接"};
        }

        if (_param == null||_param.channelId == null||
            _param.classId == null||_param.userId == null||_param.userId == ""||
            _param.siteId == null|| _param.timestamp==null)
        {
            loger.warn('publishVideo,参数错误', _param);
            this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG);
            return {"code": ApeConsts.RETURN_FAILED,  "data": "参数错误"};
        }

        loger.log('publishVideo -> maxVideoChannels', GlobalConfig.maxVideoChannels);

        //同一个nodeId只允许推一个流,如果已经推了就不能再推
        if(this.mediaModule.getOpeningMediaChannel(GlobalConfig.nodeId)!=0){
            loger.warn("publishVideo,已经存在一个流,不能再推");
            return {"code": ApeConsts.RETURN_FAILED,  "data": "已经存在一个流,不能再推"};
        }

        //判断当前是否还有空闲的channle
        let freeChannel = this.mediaModule.getFreeMediaChannel();
        if (freeChannel == 0) {
            loger.warn("publishVideo,没有空闲的channel ");
            return {"code": ApeConsts.RETURN_FAILED,  "data": "不能再打开更多的设备"};
        }

        //判断当前的频道是否已经占用
        if(this.mediaModule.checkChannelIsOpening(_param.channelId)){
            loger.warn(_param.channelId,"频道已经被占用");
            return {"code": ApeConsts.RETURN_FAILED, "data":"频道已经被占用!"};
        }

        let channelInfo={};
        channelInfo.status=ApeConsts.CHANNEL_STATUS_OPENING;
        channelInfo.fromNodeId=GlobalConfig.nodeId;
        channelInfo.channelId=_param.channelId;//freeChannel
        channelInfo.timestamp=_param.timestamp;//EngineUtils.creatTimestamp();
        channelInfo.classId=_param.classId;//GlobalConfig.classId;
        channelInfo.siteId=_param.siteId;//GlobalConfig.siteId;
        channelInfo.toNodeId=0;
        channelInfo.mediaType=ApeConsts.MEDIA_TYPE_VIDEO;
        channelInfo.userId=_param.userId;

        this.sendTableUpdateHandler(channelInfo);
        return {"code": ApeConsts.RETURN_SUCCESS, "data":"推流成功!"}
    }

    //停止推流,
    stopPublishVideo(_param) {
        if(!this.mcu.connected){
            loger.warn(GlobalConfig.getCurrentStatus());
            return {"code": ApeConsts.RETURN_FAILED, "data": "已经断开连接"};
        }

        loger.log('stopPublishVideo -> maxVideoChannels', GlobalConfig.maxVideoChannels);
        //_param如果为空,那么默认就是当前自己的nodeId,否则用_param
        let nodeId;
        if(_param&&parseInt(_param.nodeId)>=0){
            nodeId=parseInt(_param.nodeId);
        }else {
            nodeId=GlobalConfig.nodeId;
        }

        let openingChannel = this.mediaModule.getOpeningMediaChannel(nodeId);
        if (openingChannel == 0) {
            loger.warn(nodeId,"stopPublishVideo,没有占用channel,不需要关闭");
            return {"code": ApeConsts.RETURN_FAILED, "data": "没有占用channel,不需要关闭"};
        }

        let channelInfo={};
        channelInfo.status=ApeConsts.CHANNEL_STATUS_RELEASED;
        channelInfo.fromNodeId=0;
        channelInfo.channelId=openingChannel;
        channelInfo.timestamp=0;
        channelInfo.classId=GlobalConfig.classId;
        channelInfo.toNodeId=0;
        channelInfo.mediaType=ApeConsts.MEDIA_TYPE_DEFAULT;
        this.sendTableUpdateHandler(channelInfo);
    }

    sendVideoBroadcastMsg(_param) {
        if(!this.mcu.connected){
            loger.warn(GlobalConfig.getCurrentStatus());
            return {"code": ApeConsts.RETURN_FAILED, "data": "已经断开连接"};
        }

        if (this._classInfo === null || EngineUtils.isEmptyObject(this._classInfo)) {
            loger.log('不能发送Video消息.McuClient还未初始化数据!');
            if (GlobalConfig.getCurrentStatus().code == 0 || GlobalConfig.getCurrentStatus().code == 1) {
                this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_SEND_FAILED_NO_JOIN);
                return {"code": 1, "data": "不能发送Video消息.McuClient还未初始化数据"};
            }
            return {"code": ApeConsts.RETURN_FAILED,  "data": "不能发送Video消息.McuClient还未初始化数据"};
        }
        if (_param == null) {
            loger.warn('sendVideoCommandMsg失败,参数错误', _param);
            this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG);
            return {"code": ApeConsts.RETURN_FAILED,  "data": "sendVideoCommandMsg失败,参数错误"};
        }
        // to, message
        loger.log('发送Video消息.', _param);

        if (_param.actionType != null && _param.actionType == ApeConsts.MEDIA_ACTION_OPEN_CAMERA) {
            //判断当前开启的视频数量是否已经是最大值,如果已经是最大值,不能再开启
            let freeChannel = this.mediaModule.getFreeMediaChannel();
            if (freeChannel == 0) {
                loger.warn('sendVideoCommandMsg,不能再打开更多的设备', _param);
                return {"code": ApeConsts.RETURN_FAILED,  "data": "不能再打开更多的设备"};
            }
        }
        /* message RCVideoSendDataRequestPdu {
         required uint32 from_node_id = 1;//发起人
         optional uint32 to_node_id = 2;//接收人,如果是0就是所有人都接收
         optional uint32 actionType = 3;//消息指令类型;
         optional bytes  data = 4;//其他数据,这个根据actionType来确定数据的结构
         }*/

        let videoSendPdu = new pdu['RCVideoSendDataRequestPdu'];
        videoSendPdu.type = pdu.RCPDU_SEND_VIDEO_DATA_REQUEST;
        videoSendPdu.isPublic = true;

        videoSendPdu.fromNodeId = GlobalConfig.nodeId;//发起人
        videoSendPdu.toNodeId = parseInt(_param.toNodeID) || 0;//接收者,0就是所有人
        videoSendPdu.actionType = parseInt(_param.actionType) || ApeConsts.MEDIA_ACTION_DEFAULT;

        videoSendPdu.data = this._rCArrayBufferUtil.strToUint8Array("h5" + _param.data);//开头两个字会乱码

        if (!videoSendPdu.isPublic && 0 != videoSendPdu.toNodeId) {
            //发送给制定的人
            loger.log('发送私聊Video消息.');
            this.send(videoSendPdu);
        } else {
            //发送给所有人
            loger.log('发送公聊Video消息.');
            this.sendChatUniform(videoSendPdu);
        }
        return {"code": ApeConsts.RETURN_SUCCESS,  "data": ""};
    }

    sendTableUpdateHandler(_channelInfo) {
        loger.log("video===sendTableUpdateHandler ");
        /* //验证坐标点集合数组是否合法
         if(_docDataModel==null||_itemIdx==null){
         this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG);
         return null;
         }*/

        //let freeChannel=this.getFreeVideoChannel();
        //if(freeChannel==0){
        //  loger.warn("sendTableUpdateHandler,没有空闲的channel ");
        //  return;
        //}
        let updateModelPdu = this.packPdu(_channelInfo, _channelInfo.channelId);//let updateModelPdu=this.packPdu({},ApeConsts.VIDEO_OBJ_TABLE_ID+2);
        if(updateModelPdu==null){
            loger.warn("sendTableUpdateHandler error,updateModelPdu=null");
            return;
        }

        let tableItemPdu = new pdu['RCRegistryTableItemPdu'];
        tableItemPdu.itemIdx = _channelInfo.channelId;//tableItemPdu.itemIdx=ApeConsts.VIDEO_OBJ_TABLE_ID+2;
        tableItemPdu.owner = 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("发送更新VIDEO.itemIdx=" + tableItemPdu.itemIdx);
        this.sendUniform(adapterPdu, true);
    }

    /////收到消息处理//////////////////////////////////////////////////

    // 视频消息处理,内部处理,不需要告诉应用层
    receiveVideoCommandHandler(_data) {
        let videoReceivePdu = pdu['RCVideoSendDataRequestPdu'].decode(_data);
        if (videoReceivePdu == null) {
            loger.warn("视频消息处理,收到的消息为null,不做处理");
            return;
        }
        videoReceivePdu.data = this._rCArrayBufferUtil.uint8ArrayToStr(videoReceivePdu.data, 2);//开头两个字会乱码
        loger.log('视频消息处理 receiveVideoCommandHandler.');
        console.log(videoReceivePdu);

        //判断接收者的id,如果不是0,并且也不是自己的nodeId,那么消息不做处理
        if (videoReceivePdu.toNodeId != 0 && videoReceivePdu.toNodeId != GlobalConfig.nodeId) {
            loger.log('视频消息不处理 toNodeId=', videoReceivePdu.toNodeId, "my nodeId=", GlobalConfig.nodeId);
        } else {
            this._emit(MessageTypes.VIDEO_BROADCAST, videoReceivePdu);
        }
    }

    tableUpdateHandler(owner, itemIdx, itemData) {
        // debugger;
        let videoChannelInfo = this.unPackPdu(owner, itemIdx, itemData);
        this.mediaModule.mediaChannels[itemIdx] = videoChannelInfo;
        this._emit(MessageTypes.VIDEO_UPDATE, videoChannelInfo);
    }

    ///////数据的封包和解包/////////////////////////////////////////
    packPdu(_param, _itemIdx) {
        loger.log("packPdu ");
        //验证坐标点集合数组是否合法
        if (_param == null || _itemIdx == null) {
            this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG);
            return null;
        }

        //判断type类型,根据type设置不同的参数
        let packPduModel = new pdu['RCVideoChannelInfoPdu'];
        packPduModel.status = _param.status||ApeConsts.CHANNEL_STATUS_RELEASED;
        packPduModel.channelId = _itemIdx;
        packPduModel.siteId=_param.siteId||GlobalConfig.siteId;//GlobalConfig.siteId;
        packPduModel.classId =parseInt(_param.classId)||parseInt(GlobalConfig.classId);
        packPduModel.userId =_param.userId||"0";
        packPduModel.mediaType =_param.mediaType|| ApeConsts.MEDIA_TYPE_VIDEO;
        packPduModel.timestamp =_param.timestamp||EngineUtils.creatTimestamp();
        packPduModel.fromNodeId = GlobalConfig.nodeId;
        packPduModel.toNodeId = 0;
        console.log("packPdu",packPduModel);
        return packPduModel;
    }

    unPackPdu(owner, itemIdx, itemData) {
        loger.log("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("unPackPdu",videoChannelInfo);
            return videoChannelInfo;
        } catch (err) {
            loger.log("unPackPdu error,itemIdx=" + itemIdx + "  err:" + err.message);
        }
        return null;
    }
}

export default VideoApe;