VideoApe.js 12.9 KB
// //////////////////////////////////////////////////////////////////////////////
//
//  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';
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');

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


    );

    //Attributes
    this.videoChannels = {};

    // 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_VIDEO_SEND_DATA_REQUEST, this.videoCommandHandler.bind(this));
  }
  /////////////发送数据操作//////////////////////////////////////////////////////
  //获取播流地址
  getPlayVideoPath(_param){
    loger.log('getPlayVideoPath');
    return {"code":0,"data":"播放流地址XXXXXXXXXXXXXXXXXXXXX"};
  }
  //获取推流地址
  getPublishVideoPath(_param){
    loger.log('getPublishVideoPath');
    //判断当前开启的视频数量是否已经是最大值,如果已经是最大值,不能再开启

    return {"code":0,"data":"推流地址XXXXXXXXXXXXXXXXXXXXXXX"};
  }

  //推流
  publishVideo(_param){
    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 -> 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(_param) {
    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消息.', _param);


   /* 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_VIDEO_SEND_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);
    }
  }

  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);
  }
  /////收到消息处理/////////////////////////////////////////////////////////////////////////////////

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

  tableUpdateHandler(owner, itemIdx, itemData) {
   // debugger;
    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;

    this._emit(MessageTypes.VIDEO_UPDATE,videoChannelInfo);
/*    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;
      default:
            break;
    }*/
  }

  emitVideoChange() {
    this._emit(MessageTypes.VIDEO_UPDATE, {
      activeChannelId: this.activeChannelId,
      HLSURL: this.activeURL,
    });
  };


  ///////数据的封包和解包/////////////////////////////////////////
  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.mediaType=ApeConsts.MEDIA_TYPE_VIDEO;
    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;