require('es6-promise').polyfill();
require('whatwg-fetch');
require('jquery-touchswipe');
require('string.fromcodepoint');
//require('messenger');

import Emiter from './Emiter';
import Sass from 'Sass';
import IpManager from 'IpManager';
import RecordPlayBackParse from 'RecordPlayBackParse';
import MD5 from "md5";
import Mcu from 'mcu';
import MessageTypes from 'MessageTypes';
import Loger from 'Loger';
import ConferApe from 'apes/ConferApe';
import ChatApe from 'apes/ChatApe';
import VideoApe from 'apes/VideoApe';
import AudioApe from 'apes/AudioApe';
import DocApe from 'apes/DocApe';
import WhiteBoardApe from 'apes/WhiteBoardApe';

import EngineUtils from "EngineUtils";
import GlobalConfig from 'GlobalConfig';
import ApeConsts from 'apes/ApeConsts';
import Base64 from 'base64-js';
import ArrayBufferUtil from 'libs/ArrayBufferUtil';
import Server from "config/Server";
import MediaModule from 'apes/MediaModule';
import MediaSharedApe from 'apes/MediaSharedApe';
import QuestionApe from 'apes/QuestionApe';

import UTF8 from 'utf-8';

let loger = Loger.getLoger('McuClient');
let _sdkInfo = {"version": "v1.34.2.20170615", "author": "www.3mang.com"};

//APE
let _sass;
let _ipManager;
let _mcu;
let _confer_ape;
let _chat_ape;
let _video_ape;
let _audio_ape;
let _doc_ape;
let _whiteboard_ape;
let _recordPlayback;
let _mediaShareApe;
let _questionApe;

//MCUClient 外部实例化主类
export default class MessageEntrance extends Emiter {
    constructor() {
        super();
        //sdk 信息
        this.sdkInfo = _sdkInfo;
        loger.log(this.sdkInfo);

        //初始化状态
        this.isGetUserIpCallback = false;//是否获取IP信息返回
        this.isGetFastestMcuCallback = false;//是否MCU选点结束
        this.isGetFastestMsCallback = false;//是否MS选点结束

        GlobalConfig.setCurrentStatus(GlobalConfig.statusCode_0);

        //全局的Error处理
        this.on(MessageTypes.MCU_ERROR, this._mcuErrorHandler.bind(this));

        // Sass平台层
        _sass = Sass;
        _sass.on('*', (type, data) => this._emit(type, data));
        _sass.on(_sass.SUCCESS, this._sassJoinSuccessHandler.bind(this));//通过SASS平台验证(密码和MD5)
        _sass.on(_sass.CLASS_INIT_SUCCESS, this._sassInitSuccessHandler.bind(this));//获取课堂初始化信息
        //_sass.on(_sass.CLASS_GET_CLASS_DETAIL, this._sassGetClassDetailSuccessHandler.bind(this));//获取课堂的基本信息
        _sass.on(_sass.CLASS_GET_CLASS_PARAM, this._sassGetClassParamSuccessHandler.bind(this));//获取课堂的最全信息和历史保存的数据

        _sass.on(_sass.CLASS_SAVE_STATUS_INFO_SUCCESS, this._sassSaveClassStatusInfoSuccessHandler.bind(this));//保存课堂状态信息
        _sass.on(_sass.CLASS_SAVE_RECORD_INFO_SUCCESS, this._sassSaveClassRecordInfoSuccessHandler.bind(this));//保存课堂录制信息
        _sass.on(_sass.DELETE_DOCUMENT_SUCCESS, this._sassDeleteDocumentSuccess.bind(this));//sass删除文档成功
        _sass.on(_sass.DELETE_MEDIASHARE_SUCCESS, this._sassDeleteMediaShareSuccess.bind(this));//sass删除媒体文件成功




        //选点模块
        _ipManager = new IpManager();

        // 底层MCU消息层
        _mcu = Mcu;
        _mcu.on('*', (type, data) => this._emit(type, data));
        _mcu.on(MessageTypes.CLASS_JOIN_MCU_SUCCESS, this._mcuJoinMCUClassSuccessHandler.bind(this));//加入MCU课堂完成
        _mcu.on(MessageTypes.SWITCH_MCU_IP, this._switchMcuIpHandler.bind(this));//切换MCU,重新选点

        //录制回放
        _recordPlayback = RecordPlayBackParse;
        _recordPlayback.on('*', (type, data) => this._emit(type, data));
        _recordPlayback.on(RecordPlayBackParse.CLASS_JOIN_RECORD_PLAYBACK_SUCCESS, this._joinRecordPlaybackSuccessHandler.bind(this));//加入录制回放完成
        _recordPlayback.on(RecordPlayBackParse.RECORD_PLAYBACK_CLEAR_DATA, this._recordPlaybackClearDataHandler.bind(this));//录制回放状态更新


        // 注册所有应用Ape
        _confer_ape = new ConferApe();
        _confer_ape.on('*', (type, data) => this._emit(type, data));
        _confer_ape.on(MessageTypes.CLASS_RUN_EXIT, this._runClassExit.bind(this));//监听自己的关闭事件
        _confer_ape.on(MessageTypes.CLASS_STATUS_INFO_CHANGE, this._onClassStatusInfoChange.bind(this));//当前课堂状态信息发生改变
        _confer_ape.on(MessageTypes.CLASS_DELETE_ROSTER, this._onClassDeleteRoster.bind(this));//当前课堂人员离开
        _confer_ape.on(MessageTypes.CLASS_NONENTITY_ROSTER, this._onClassNonentityRoster.bind(this));//当前课堂中视频或音频占用channel的nodeId ,在人员列表中不存在
        _confer_ape.on(MessageTypes.CLASS_RECORD_START, this._onClassRecordStart.bind(this));//课堂开始录制
        _confer_ape.on(MessageTypes.CLASS_RECORD_SUCCESS, this._onClassRecordSuccess.bind(this));//课堂开启录制成功
        _confer_ape.on(MessageTypes.SWITCH_MS_IP, this._switchMsIpHandler.bind(this));//MS动态选点
        _confer_ape.on(MessageTypes.STOP_ALL_MEDIA_PUBLISH, this._stopAllMediaPublishHandler.bind(this));//课堂状态发生改变,需要停止当前的所有推流

        _chat_ape = new ChatApe();
        _chat_ape.on('*', (type, data) => this._emit(type, data));

        _video_ape = new VideoApe();
        _video_ape.on('*', (type, data) => this._emit(type, data));
        _video_ape.on(MessageTypes.VIDEO_UPDATE, this.videoUpdate.bind(this));//这个监听事件不能删除,需要通知课堂模块,检查channel占用
        _video_ape.on(MessageTypes.USER_DEVICE_STATUS_CHAANGE, this.userDeviecStatusChange.bind(this));//监听摄像头和麦克风的开启状态


        _audio_ape = new AudioApe();
        _audio_ape.on('*', (type, data) => this._emit(type, data));
        _audio_ape.on(MessageTypes.AUDIO_UPDATE, this.audioUpdate.bind(this));//这个监听事件不能删除,需要通知课堂模块,检查channel占用
        _audio_ape.on(MessageTypes.USER_DEVICE_STATUS_CHAANGE, this.userDeviecStatusChange.bind(this));//监听摄像头和麦克风的开启状态

        _mediaShareApe=new MediaSharedApe();
        _mediaShareApe.on('*', (type, data) => this._emit(type, data));
        _mediaShareApe.on(MediaSharedApe.MEDIASHARED_JOIN_CHANNEL_SUCCESS, this.mediaShareApeJoinChannelSuccess.bind(this));

        _whiteboard_ape = new WhiteBoardApe();
        _whiteboard_ape.on('*', (type, data) => this._emit(type, data));

        _doc_ape = new DocApe();
        _doc_ape.on('*', (type, data) => this._emit(type, data));
        _doc_ape.on(MessageTypes.DOC_UPDATE, this.docUpdateHandler.bind(this));
        _doc_ape.on(MessageTypes.DOC_DELETE, this.docDeleteHandler.bind(this));
        _doc_ape.on(DocApe.DOC_JOIN_CHANNEL_SUCCESS, this.docJoinChannelSuccess.bind(this));

        _questionApe=new QuestionApe();
        _questionApe.on('*', (type, data) => this._emit(type, data));

        //公开外部调用的方法
        //class
        this.init = this._init.bind(this);
        this.joinClass = this._joinClass.bind(this);
        this.leaveClass = this._leaveClass.bind(this);
        this.getMcuClientStatus = this._getMcuClientStatus.bind(this);
        //this.getClassDetail = this._getClassDetail;//停用
        this.getClassStatusInfo = this._getClassStatusInfo.bind(this);
        this.sendStartClass = this._sendStartClass.bind(this);
        this.sendPauseClass = this._sendPauseClass.bind(this);
        this.sendCloseClass = this._sendCloseClass.bind(this);
        this.changeHandUpStatus = this._changeHandUpStatus.bind(this);//自己切换举手状态
        this.controlHandUpStatus = this._controlHandUpStatus.bind(this);//控制别人的举手状态


        //录制回放
        this.initRecordPlayback = this._initRecordPlayback.bind(this);
        this.startRecordPlayback = this._startRecordPlayback.bind(this);
        this.stopRecordPlayback = this._stopRecordPlayback.bind(this);
        this.pauseRecordPlayback = this._pauseRecordPlayback.bind(this);
        this.seekRecordPlayback = this._seekRecordPlayback.bind(this);

        //chatApe
        this.sendChatMsg = this._sendChatMsg.bind(this);

        //屏幕共享
        this.publishScreenShare = this._publishScreenShare.bind(this);
        this.stopPublishScreenShare = this._stopPublishScreenShare.bind(this);

        //videoApe
        //this.getVideoPlayPath = this._getVideoPlayPath.bind(this);
        this.getVideoPublishPath = this._getVideoPublishPath.bind(this);
        this.getVideoAllChannelInfo = this._getVideoAllChannelInfo.bind(this);
        this.publishVideo = this._publishVideo.bind(this);
        this.stopPublishVideo = this.unPublishVideo = this._stopPublishVideo.bind(this);
        this.sendVideoBroadcastMsg = this._sendVideoBroadcastMsg.bind(this);

        //audioApe
        //this.getAudioPlayPath = this._getPlayAudioPath.bind(this);
        this.getAudioPublishPath = this._getPublishAudioPath.bind(this);
        this.getAudioAllChannelInfo = this._getAudioAllChannelInfo.bind(this);
        this.publishAudio = this._publishAudio.bind(this);
        this.stopPublishAudio = this.unPublishAudio = this._stopPublishAudio.bind(this);
        this.sendAudioBroadcastMsg = this.sendAudioCommandMsg.bind(this);

        //whiteBoradApe
        this.sendInsertAnnotaion = this._sendInsertAnnotaion.bind(this);//添加标注
        this.sendDeleteAllAnnotation = this._sendDeleteAllAnnotation.bind(this);//删除所有标注
        this.sendDeleteCurPageAnnotation = this._sendDeleteCurPageAnnotation.bind(this);//删除当前页的所有标注
        this.sendGotoPrev = this._sendGotoPrev.bind(this);//当前页撤销上一步

        //DocApe
        this.sendDocumentUpload = this._sendDocumentUpload.bind(this);//上传文档
        this.sendDocumentSwitchDoc = this._sendDocumentSwitchDoc.bind(this); //切换文档
        this.sendDocumentSwitchPage = this._sendDocumentSwitchPage.bind(this);//翻页
        this.sendDocumentSwitchAnimation=this._sendDocumentSwitchAnimation.bind(this);//切换当前页码的动画步骤
        this.sendDocumentDelete = this._sassDeleteDocument.bind(this);
        this.sendDocBroadcastMsg = this._sendDocBroadcastMsg.bind(this);
        //删除文档,先通过Sass删除,sass删除成功之后再同步mcu
        //this.sendDocumentDeleteAll= this._documentDeleteAll;//删除所有文档
        this.sendDocumentCommand = this._sendDocumentCommand.bind(this);
        //操作文档(翻页、缩放、滚动...)
        this.getDocImageFullPath = this._getDocImageFullPath.bind(this);
        //获取文档图片的完整路径
        this.getDocPDFFullPath = this._getDocPDFFullPath.bind(this);//获取文档的完整路径
        this.getDocFullAddress = this._getDocFullAddress.bind(this);//获取文档资源地址


        //媒体共享模块
        this.mediaSharedUpload = this._sendMediaSharedUpload.bind(this);//上传
        this.mediaSharedDelete = this._sassDeletMediaShare.bind(this);//删除,先通过Sass删除,删除成功之后才删除MCU的

        this.mediaSharedPlay = this._sendMediaSharedPlay.bind(this); //播放
        this.mediaSharedStop = this._sendMediaSharedStop.bind(this);//停止
        this.mediaSharedUpdate=this._sendMediaSharedUpdate.bind(this); //更新媒体的状态

        //答题卡
        this.creatQuestion=this._creatQuestion.bind(this);
        this.getQuestion=this._getQuestion.bind(this);
        this.getQuestionResult=this._getQuestionResult.bind(this);
        this.sendAnswer=this._sendAnswer.bind(this);
        this.stopQuestion=this._stopQuestion.bind(this);

        this.setDeviceInfo = this._setDeviceInfo.bind(this);//设置设备信息(麦克风,摄像头等等.....)
        this.setMessageDelay = this._setMessageDelay.bind(this);//设置是否延迟消息
        this.switchServer = this._switchMcuIpHandler.bind(this);//切换mcu服务器
        this.switchMediaServer = this._switchMsIpHandler.bind(this);//切换ms服务器
        this.setDebugInfo= this._setDebugInfo.bind(this);//设置debug信息
    }
    _setDebugInfo(_data){
        loger.log("设置debug信息-->", _data);
        if(_data){
            Loger.setLogDebug(_data.isDebug);
        }
    }
    //设置设备信息
    _setDeviceInfo(_data) {
        loger.log("设置设备信息-->", _data);
        if(_data){
           /* GlobalConfig.videoQuality=_data.videoQuality||2;//画面质量 0-低;1-中;2-高;
            GlobalConfig.cameras=_data.cameras||[];//摄像头列表
            GlobalConfig.microphones=_data.microphones||[];//麦克风列表
            GlobalConfig.curCamera=_data.curCamera||'';//当前选择的摄像头
            GlobalConfig.curMicrophone=_data.curMicrophone||'';//当前选择的麦克风
            GlobalConfig.curVideoQuality=_data.curVideoQuality||2;//当前选择的分辨率
            GlobalConfig.micGain=_data.micGain||50;//音量(0-80)*/

            GlobalConfig.cameras=_data.cameras||[];
            GlobalConfig.microphones=_data.microphones||[];
            GlobalConfig.videoQuality=parseInt(_data.videoQuality);
            GlobalConfig.curVideoQuality=parseInt(_data.curVideoQuality);
            GlobalConfig.micGain=_data.micGain||50;
            GlobalConfig.speakerVolume=_data.speakerVolume||50;
            GlobalConfig.micCode=_data.micCode||0;
            GlobalConfig.curCamera=_data.curCamera||'';
            GlobalConfig.curMicrophone=_data.curMicrophone||'';

            if(!GlobalConfig.curCamera&& GlobalConfig.cameras.length>0){
                GlobalConfig.curCamera= GlobalConfig.cameras[0];
            }
            if(!GlobalConfig.curMicrophone&& GlobalConfig.microphones.length>0){
                GlobalConfig.curMicrophone= GlobalConfig.microphones[0];
            }
            this._updateDeviceInfo();
        }
    }

    //设置消息延迟
    _setMessageDelay(_data) {
        loger.warn("延迟消息-->", _data);
        if (_data) {
            GlobalConfig.messageDelay = Boolean(_data.messageDelay);
        }
    }

    //mcu异常监听
    _mcuErrorHandler(_data, _option) {
        let option = _option || "";
        let errorMessage = {"code": _data, "reson": MessageTypes.ErrorReson[_data] + " " + option};
        this._emit(MessageTypes.ERROR_EVENT, errorMessage);
        loger.error("MCU_ERROR", errorMessage);
    }

    //获取当前的状态
    _getMcuClientStatus() {
        return GlobalConfig.getCurrentStatus();
    }

//获取课堂信息
    _getClassDetail() {
        return GlobalConfig.getClassDetail();
    }

    //获取当前课堂的状态信息
    _getClassStatusInfo() {
        return GlobalConfig.classStatusInfo;
    }

    /*
    //关闭课堂,所有人都退出
    _doClassClose(_param) {
        this._leaveClass();
    }*/

    //执行离开课堂断开连接的流程
    _runClassExit(_type) {
        this._leaveClass(_type);
    }

    //当前的课堂状态信息发生改变,需要保存课堂状态到Sass
    _onClassStatusInfoChange(_param) {
        //如果MCU连接已经断开,不发送
        if (GlobalConfig.getCurrentStatus().code != GlobalConfig.statusCode_2.code) {
            loger.warn("不能保存课堂状态", GlobalConfig.getCurrentStatus());
            return;
        }
        this._sassSaveClassStatusInfo(_param);
    }

    //如果是第一次点击开始上课,需要创建录制时的文件名
    _onClassRecordStart(_param) {
        if (GlobalConfig.getCurrentStatus().code != GlobalConfig.statusCode_2.code) {
            loger.warn("不能保存课堂状态", GlobalConfig.getCurrentStatus());
            return;
        }
        if (_sass) {
            _sass.saveClassRecordContrlInfo(_param);
        }
    }

    //开启录制成功
    _onClassRecordSuccess(_param) {
       this.updaterRecordAllApeStatus(_param);
    }

    //录制状态发送改变,更新所有模块的当前数据发送到MCU
    updaterRecordAllApeStatus(_param){
        //老师身份和非录制回放的时候执行,录制状态发送改变,需要更新当前的数据,否则已有的消息会录制不上
        if(GlobalConfig.isHost&&!GlobalConfig.isRecordPlayBack){
            loger.warn('录制状态发送改变->更新所有模块的当前数据发送到MCU');
            //目前录制的模块[文档模块、白板模块、视频模块(包含屏幕共享)、音频模块、媒体共享,聊天模块]
            if (_doc_ape) {
                _doc_ape.updaterRecordApeStatus();
            }
            if (_whiteboard_ape) {
                _whiteboard_ape.updaterRecordApeStatus();
            }
            if (_video_ape) {
                _video_ape.updaterRecordApeStatus();
            }
            if (_audio_ape) {
                _audio_ape.updaterRecordApeStatus();
            }
            if (_mediaShareApe) {
                _mediaShareApe.updaterRecordApeStatus();
            }
            //聊天模块不需要更新
        }
    }

    //有人员离开
    _onClassDeleteRoster(_data) {
    }

    //当前课堂中视频或音频占用channel的nodeId ,在人员列表中不存在,这种情况是占用channel的人员掉线或离开的时候没有释放channel
    //的占用状态导致,对于这种情况,需要释放掉
    _onClassNonentityRoster(_param) {
        if (GlobalConfig.isRecordPlayBack) {
            loger.warn("录制回放中,不处理")
            return;
        }

        if (_param == null || _param.nodeId == null) {
            loger.warn("onClassNonentityRoster.参数错误")
            return;
        }
        let data = {"nodeId": _param.nodeId};
        if (_video_ape) {
            _video_ape.stopPublishVideo(data);

            if(GlobalConfig.nodeId==data.nodeId){
                _video_ape.stopPublishScreenShare(data);
            }
        }
        if (_audio_ape) {
            _audio_ape.stopPublishAudio(data);
        }
    }


    //Sass
    //初始化
    _init(_param) {
        //{"classId":"1653304953","portal":"112.126.80.182:80","userRole":"normal","userId":0}
        //判断传入的参数是否存在
        if (_param == null || EngineUtils.isEmptyObject(_param)) {
            loger.error('初始化课堂失败->参数错误', _param);
            this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_INIT_PARAM);
            return;
        }
        //判断必要的参数字段值
        if (_param.classId == null || isNaN(_param.classId) || _param.portal == null || _param.portal == "") {
            loger.error('初始化课堂失败->参数错误', _param);
            this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_INIT_PARAM);
            return;
        }
        loger.log('初始化课堂->', _param);

        //保存参数
        GlobalConfig.isRecordPlayBack = false;//设置为非录制回放状态
        GlobalConfig.classId = parseInt(_param.classId);
        GlobalConfig.portal = _param.portal;
        GlobalConfig.userId = _param.userId || "0";
        GlobalConfig.userName = _param.userName || "";

        //设置角色身份
        GlobalConfig.userRole = _param.userRole || ApeConsts.normal;
        if (GlobalConfig.userRole != ApeConsts.host &&
            GlobalConfig.userRole != ApeConsts.presenter &&
            GlobalConfig.userRole != ApeConsts.assistant &&
            GlobalConfig.userRole != ApeConsts.record &&
            GlobalConfig.userRole != ApeConsts.invisible) {
            GlobalConfig.userRole = ApeConsts.normal;
        }
        //客户端决定是否延迟接收消息
        GlobalConfig.messageDelay = _param.messageDelay || false;

        //最长允许录制的时间
        if (_param.allowRecordMaxTime) {
            GlobalConfig.allowRecordMaxTime = parseInt(_param.allowRecordMaxTime);
        }

        //获取课堂校验信息
        if (_sass) {
            _sass.getJoinParams(GlobalConfig.getClassInfo());
        }
    }

    //外部请求加入课堂
    _joinClass(_param) {
        if (_param == null || EngineUtils.isEmptyObject(_param)) {
            this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_JOIN_PARAM);
            loger.log('加入课堂失败->参数错误.', _param);
            return;
        }
        //判断userName
        if (_param.userName == null || _param.userName == "") {
            loger.log('加入课堂失败->参数错误->名字不能为空');
            this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_JOIN_PARAM);
            return;
        }
        //{"userName":"名字","password":"","autoLogin":""}
        GlobalConfig.userName = _param.userName || GlobalConfig.userName;//以登陆时的名字为主,登陆之前可以修改名字
        GlobalConfig.autoLogin = _param.autoLogin || "";
        GlobalConfig.password = _param.password || "";
        GlobalConfig.hasCamera = (typeof  _param.hasCamera == "boolean") ? _param.hasCamera : false;
        GlobalConfig.hasMicrophone = (typeof  _param.hasMicrophone == "boolean") ? _param.hasMicrophone : false;

        //loger.log("autoLoginMd5", GlobalConfig.classId, GlobalConfig.userId, GlobalConfig.userRole);
        let autoLoginMd5 = MD5("" + GlobalConfig.classId + GlobalConfig.userId + GlobalConfig.userRole);
        //loger.log("joinClass-GlobalConfig.autoLogin", GlobalConfig.autoLogin, "autoLoginMd5-", autoLoginMd5);
        if (GlobalConfig.autoLogin && autoLoginMd5 == GlobalConfig.autoLogin) {
            // MD5(classId+userId+userRole)==m
            //自动登录,跳过验证流程
            loger.log("自动登录");
            this._sassJoinSuccessHandler();
        } else {
            //不能自动登录,开始校验
            if (_sass) {
                _sass.passwordAndMd5Checking(GlobalConfig.getClassInfo());
            }
        }
    }

    // 用classId向SASS平台获取入会验证信息成功
    _sassInitSuccessHandler(_data) {
        //{"siteId":"h5test","passwordRequired":true,"md5":"de399d5540b3da2fbc1eb0a770d4fd66","code":0,"msType":1}
        //储存数据
        GlobalConfig.md5 = _data.md5 || "";//这个暂时用假数据,后台接口写完就有数据了
        GlobalConfig.msType = _data.msType || 1;
        GlobalConfig.siteId = _data.siteId || "";
        GlobalConfig.classType = _data.meetingType || ApeConsts.CLASS_TYPE_1;

        //host默认需要密码,Sass服务器只判断学生是否需要密码,没有判断老师的
        GlobalConfig.passwordRequired = _data.passwordRequired || false;//md5验证的时候需要Sass返回的值,不能更改

        loger.log('初始化课堂验证完成.');

        //设置当前的课堂状态
        GlobalConfig.setCurrentStatus(GlobalConfig.statusCode_1);
        //返回给客户端初始化成功的数据
        let initSuccessCallBackData = {};
        initSuccessCallBackData.siteId = GlobalConfig.siteId;
        initSuccessCallBackData.classId = GlobalConfig.classId;
        initSuccessCallBackData.userRole = GlobalConfig.userRole;
        initSuccessCallBackData.userId = GlobalConfig.userId;
        initSuccessCallBackData.userName = GlobalConfig.userName;
        initSuccessCallBackData.classType = GlobalConfig.classType;

        //host默认需要密码,Sass服务器只判断学生是否需要密码,没有判断老师的
        if (GlobalConfig.userRole == ApeConsts.host) {
            initSuccessCallBackData.passwordRequired = true;
        } else {
            initSuccessCallBackData.passwordRequired = GlobalConfig.passwordRequired;
        }

        this._emit(MessageTypes.CLASS_INIT_SUCCESS, initSuccessCallBackData);
    }

    // 通过SASS平台验证(密码和MD5)
    _sassJoinSuccessHandler(_data) {
        //获取课堂最完整的数据
        if (_sass) {
            _sass.getClassParam();
        }
    }

    //获取课堂所有参数 api/meeting/detail.do? flash中的接口文件是 getClassParam.do
    _sassGetClassParamSuccessHandler(_data) {
        loger.log('获取课堂课堂信息完成.');
        //包含整个课堂最全的信息,储存数据
        if (_data) {
            GlobalConfig.mcuDelay = _data.h5Delay || 0;//mcu消息延迟的时间间隔,单位(秒),结合客户端传的messageDelay的值使用
            GlobalConfig.className = _data.meetingName || "";
            GlobalConfig.classBeginTime = _data.beginTime || "";
            GlobalConfig.classEndTime = _data.endTime || "";
            GlobalConfig.userIp = _data.userIp || "";

            GlobalConfig.maxVideoChannels = _data.maxVideoChannels;
            GlobalConfig.maxAudioChannels = _data.maxAudioChannels;
            GlobalConfig.maxMediaChannels=Math.max(GlobalConfig.maxVideoChannels,GlobalConfig.maxAudioChannels);

            GlobalConfig.ssTunnelAppURL=_data.ssTunnelAppURL||'';//屏幕共享插件的地址

            //视频质量相关设置,每次加入课堂都按最新的获取设置
            GlobalConfig.fps = _data.fps || 15;
            GlobalConfig.gop = _data.gop || 3;
            GlobalConfig.videoQuality = parseInt(_data.videoQuality);
            GlobalConfig.curVideoQuality= GlobalConfig.videoQuality;

            //是否自动开始(身份是host的时候才用到的)
            GlobalConfig.isAutoStartClass = _data.autoRecord || 0;

            GlobalConfig.setDocListPrepare(_data.docListPrepare);  //提前上传的文档列表
            GlobalConfig.setRecordList(_data.recordList);//录制回放地址
            GlobalConfig.setDocList(_data.docList);//文档地址
            GlobalConfig.setMsList(_data.msList);//推流播流服务器地址(需要对列表中的地址进行分类,里面包含了推流和拉流的地址,目前主要是乐视的需要区分开)
            GlobalConfig.setRsList(_data.rsList);//播放m3u8格式的地址(录制回放时使用)
            GlobalConfig.setMcuList(_data.mcuList);//mcu
            GlobalConfig.setMusicList(_data.musicList);//
            GlobalConfig.setMusicListPrepare(_data.musicListPrepare);//提前上传的声音文件列表
            GlobalConfig.setVideoCDNAddr(_data.videoCDNAddr);//cdn加速的拉流地址,直播的时候才使用
            GlobalConfig.setMediaShareList(_data.sharedMediaList);  //提前上传的媒体共享文件列表


            //MCU地址
            if (_data.mcuList && _data.mcuList.length > 0) {
                //随机选择一个
                let index = parseInt(Math.random() * _data.mcuList.length);
                GlobalConfig.MCUServerIP = _data.mcuList[index].ip || "";
                GlobalConfig.MCUServerPort = _data.mcuList[index].port || "";
                loger.log('初始->MCU->.', GlobalConfig.MCUServerIP, GlobalConfig.MCUServerPort);
            }

            //录制回放时m3u8播流地址
            if (_data.rsList && _data.rsList.length > 0) {
                let index = parseInt(Math.random() * _data.rsList.length);
                GlobalConfig.RS_RECORD_PLAY_IP = _data.rsList[index].ip || "";
                GlobalConfig.RS_RECORD_PLAY_PORT = _data.rsList[index].port || "";
                loger.log('初始->RS->.', GlobalConfig.RS_RECORD_PLAY_IP, GlobalConfig.RS_RECORD_PLAY_PORT);
            }

            //上课中音视频推流地址
            if (GlobalConfig.msList && GlobalConfig.msList.length > 0) {
                let index = parseInt(Math.random() * GlobalConfig.msList.length);
                GlobalConfig.MS_PUBLISH_IP = GlobalConfig.msList[index].ip || "";
                GlobalConfig.MS_PUBLISH_PORT = GlobalConfig.msList[index].port || "";
            }
            loger.log('初始->MS->.', GlobalConfig.MS_PUBLISH_IP, GlobalConfig.MS_PUBLISH_PORT);

            //播流的地址和推流地址需要分开的时候,单独设置拉流的地址 rtmp(目前乐视使用)
            if (GlobalConfig.pullRtmpList &&GlobalConfig.pullRtmpList.length > 0) {
                //有单独的rtmp拉流地址
                let index = parseInt(Math.random() *GlobalConfig.pullRtmpList.length);
                GlobalConfig.MS_PLAY_RTMP_IP =GlobalConfig.pullRtmpList[index].ip || "";
                GlobalConfig.MS_PLAY_RTMP_PORT =GlobalConfig.pullRtmpList[index].port || "";
            }else {
                //如果没有单独的rtmp拉流地址,和推流地址一样即可
                GlobalConfig.MS_PLAY_RTMP_IP= GlobalConfig.MS_PUBLISH_IP;
                GlobalConfig.MS_PLAY_RTMP_PORT =GlobalConfig.MS_PUBLISH_PORT;
            }

            loger.log('初始->MSPull->.', GlobalConfig.MS_PLAY_RTMP_IP, GlobalConfig.MS_PLAY_RTMP_PORT);

            //播流的地址和推流地址需要分开的时候,单独设置拉流的地址 hls(目前乐视使用)
            if (GlobalConfig.hlsList &&GlobalConfig.hlsList.length > 0) {
                //有单独的hls拉流地址
                let index = parseInt(Math.random() *GlobalConfig.hlsList.length);
                GlobalConfig.MS_PLAY_HLS_IP =GlobalConfig.hlsList[index].ip || "";
                GlobalConfig.MS_PLAY_HLS_PORT =GlobalConfig.hlsList[index].port || "";
            }else {
                //没有单独的hls拉流地址,和录制回放地址一样即可
                GlobalConfig.MS_PLAY_HLS_IP =GlobalConfig.RS_RECORD_PLAY_IP;
                GlobalConfig.MS_PLAY_HLS_PORT =GlobalConfig.RS_RECORD_PLAY_PORT ;
            }
            loger.log('初始->MSHls->.', GlobalConfig.MS_PLAY_HLS_IP, GlobalConfig.MS_PLAY_HLS_PORT);


            //直播的时候,拉流(rtmp和hls)需要从 videoCDNAddr中获取
            //20170531-新规则,所有课堂类型都支持加速
            // if(GlobalConfig.classType==ApeConsts.CLASS_TYPE_2&&GlobalConfig.videoCDNAddrList.length>0){
            if(GlobalConfig.videoCDNAddrList.length>0){
                //videoCDNAddrList中rtmppush和hls是混在一起的,需要分离开;
                let listLen=GlobalConfig.videoCDNAddrList.length;
                for(let i=0;i<listLen;i++){
                    let ipItem=GlobalConfig.videoCDNAddrList[i];
                    if(ipItem){
                        if(ipItem.indexOf('hls')>=0){
                            //直播的时候m3u8拉流地址
                            GlobalConfig.MS_PLAY_HLS_IP =ipItem;//ip包含了端口
                            GlobalConfig.MS_PLAY_HLS_PORT ="";
                            loger.log('videoCDNAddr>初始->MSHls', GlobalConfig.MS_PLAY_HLS_IP );
                        }else if(ipItem.indexOf('rtmppull')>=0){
                            //直播的时候rtmp拉流地址
                            GlobalConfig.MS_PLAY_RTMP_IP=ipItem;//ip包含了端口
                            GlobalConfig.MS_PLAY_RTMP_PORT ='';
                            loger.log('videoCDNAddr->初始->MSPull', GlobalConfig.MS_PLAY_RTMP_IP );
                        }
                    }
                }

            }else{
                loger.log('不需要videoCDNAddr->');
            }


            //文档地址
            if (_data.docList && _data.docList.length > 0) {
                //doc上传地址,随机获取一个
                let index = parseInt(Math.random() * _data.docList.length);
                loger.log("docServer->", _data.docList[index]);
                GlobalConfig.DOCServerIP = _data.docList[index].ip || "";
                GlobalConfig.DOCServerPort = _data.docList[index].port || "";
                loger.log('初始->DOC->.', GlobalConfig.DOCServerIP, GlobalConfig.DOCServerPort);
            }

            //record
            if (_data.recordList && _data.recordList.length > 0) {
                let index = parseInt(Math.random() * _data.recordList.length);
                GlobalConfig.RecordServerIP = _data.recordList[index].ip || "";
                GlobalConfig.RecordServerPort = _data.recordList[index].port || "";
                loger.log('初始->RECORD->.', GlobalConfig.RecordServerIP, GlobalConfig.RecordServerPort);
            }

        }
        //这里需要考虑是否加延迟处理,课堂信息刚获取完成,客户端需要根据数据创建界面UI,等创建完成后再加入课堂是最合适的(目前没有加延迟)
        this._emit(MessageTypes.CLASS_GET_INFO_SUCCESS,GlobalConfig.getClassInfo());

        if (_data.currentInfo) {
            //根据从Sass获取的数据信息,同步最后一次保存的课堂状态信息
            loger.log("本地同步最后一次保存过的课堂状态信息");
            try {
                GlobalConfig.setClassStatusInfo(JSON.parse(_data.currentInfo));
            } catch (err) {
                GlobalConfig.setClassStatusInfo(_data.currentInfo);
            }
            loger.log(GlobalConfig.classStatusInfo);
        } else {
            loger.log("还没有保存过课堂状信息");
        }


        //录制回放不需要获取ip信息和选点
        if (GlobalConfig.isRecordPlayBack) {
            if (_recordPlayback) {
                //开启录制回放流程
                loger.log("开启录制回放流程");
                _recordPlayback.readyRecordPlay();
            } else {
                loger.warn("开启录制回放流程失败->还未创建模块");
            }
        } else {
            //根据用户的userIp获取信息,选点
            this.getUserIpInfo();
        }
    }

    //根据UserIp获取ip信息,选点
    getUserIpInfo() {
        let _this=this;
        if (_ipManager) {
            _ipManager.loadServerJosn(function(_data){
                _ipManager.getUserIpInfo("", GlobalConfig.userIp, _this._getUserIpCallbackHandler.bind(_this), 2000);
            })
        }
    }

    //获取IP信息完成
    _getUserIpCallbackHandler(_data) {
        //获取IP信息,返回一次就不再处理
        if (this.isGetUserIpCallback) {
            return;
        }
        this.isGetUserIpCallback = true;
        if (_data && _data.ret == "ok") {
            GlobalConfig.country = _data.country;//国家
            GlobalConfig.city = _data.city;//城市
            GlobalConfig.province = _data.province;//服务商
            GlobalConfig.isp = _data.isp;//服务商
        }

        //合并MCU 、MS的列表
        this._mergeMcuAndMsList();

        //开始选点
        let _this = this;

        //有一些站点不需要进行MS选点,需要先检查一下
        if(GlobalConfig.siteId_letv==GlobalConfig.siteId){
            //MS不需要选点
            loger.log("MS不需要选点->siteId->", GlobalConfig.siteId);
            _this.isGetFastestMcuCallback = true;
            _this._startConnectMCU();
        }else {
            this._getFastestMsServer(function (_data) {
                loger.log("MS选点结束->", _data);
                if (_data && _data.ip) {
                    GlobalConfig.MS_PUBLISH_IP = _data.ip || "";
                    GlobalConfig.MS_PUBLISH_PORT = _data.port || "";
                }
                loger.log("当前使用的MS->", GlobalConfig.MS_PUBLISH_IP, GlobalConfig.MS_PUBLISH_PORT);
                _this.isGetFastestMcuCallback = true;
                _this._startConnectMCU();
            });
        }

        this._getFastestMcuServer(function (_data) {
            loger.log("MCU选点结束->", _data);
            if (_data && _data.ip) {
                GlobalConfig.MCUServerIP = _data.ip || "";
                GlobalConfig.MCUServerPort = _data.port || "";
            }
            loger.log("当前使用的MCU->", GlobalConfig.MCUServerIP, GlobalConfig.MCUServerPort);
            _this.isGetFastestMsCallback = true;
            _this._startConnectMCU();
        });
    }

    //开始连接MCU(MCU和MS都选点结束之后才开始连接)
    _startConnectMCU() {
        if (this.isGetFastestMcuCallback && this.isGetFastestMsCallback) {
            this._joinMCU();
        }
    }

    //合并Sever和Sass的mcu、ms列表
    _mergeMcuAndMsList() {
        if (_ipManager) {
            GlobalConfig.mcuListFromServer = _ipManager.getServerMcuList(
                GlobalConfig.country,
                GlobalConfig.province,
                GlobalConfig.city,
                GlobalConfig.isp,
                Server.serverList);

            GlobalConfig.msListFromServer = _ipManager.getServerMsList(
                GlobalConfig.country,
                GlobalConfig.province,
                GlobalConfig.city,
                GlobalConfig.isp,
                Server.serverList);
        }

        console.log(" GlobalConfig.mcuListFromServer", GlobalConfig.mcuListFromServer);
        console.log(" GlobalConfig.msListFromServer", GlobalConfig.msListFromServer);
        console.log(" GlobalConfig.mcuList", GlobalConfig.mcuList);
        console.log(" GlobalConfig.msList", GlobalConfig.msList);


        //********合并所有MCU、MS 列表********
        //****server.json中的数据和从Sass获取的msList  mcuList 数据需要分开,不能同时共存****
        /*GlobalConfig.mcuListAll.length = 0;
        GlobalConfig.mcuListAll = GlobalConfig.mcuListAll.concat(GlobalConfig.mcuList, GlobalConfig.mcuListFromServer);
        GlobalConfig.msListAll.length = 0;
        GlobalConfig.msListAll = GlobalConfig.msListAll.concat(GlobalConfig.msList, GlobalConfig.msListFromServer);*/

        GlobalConfig.mcuListAll.length = 0;
        if(GlobalConfig.mcuListFromServer.length>0){
            //使用server中的MCU数据
            loger.warn("使用server中的MCU数据")
            GlobalConfig.mcuListAll = GlobalConfig.mcuListFromServer;
        }else {
            //使用Sass中的数据
            loger.warn("使用Sass中的MCU数据")
            GlobalConfig.mcuListAll = GlobalConfig.mcuList;
        }

        GlobalConfig.msListAll.length = 0;
        if(GlobalConfig.msListFromServer.length>0){
            loger.warn("使用server中的MS数据")
            GlobalConfig.msListAll = GlobalConfig.msListFromServer;
        }else {
            loger.warn("使用Sass中的MS数据")
            GlobalConfig.msListAll = GlobalConfig.msList;
        }

        console.warn("mcuListAll", GlobalConfig.mcuListAll);
        console.warn("msListAll", GlobalConfig.msListAll);
    }

    //开始MCU选点操作
    _getFastestMcuServer(_callback) {
        if (_ipManager) {
            _ipManager.getFastestMcuServer(GlobalConfig.mcuListAll, _callback);
        } else {
            if (_callback) {
                _callback({'ip': ""});
            }
        }
    }

    // //开始MS选点操作
    _getFastestMsServer(_callback) {
        if (_ipManager) {
            _ipManager.getFastestMsServer(GlobalConfig.msListAll, _callback);
        } else {
            if (_callback) {
                _callback({ip: ""});
            }
        }
    }

    //保存课堂状态信息
    _sassSaveClassStatusInfo(_param) {
        //{isForce:true}   isForce->是否强制提交(true为是)
        //这个是特殊权限
        let isForce = false;
        if (_param && _param.isForce == true) {
            isForce = true;
        }

        if (GlobalConfig.isHost || isForce) {
            //只有加入课堂之后才能保存数据
            if (GlobalConfig.getCurrentStatus().code == GlobalConfig.statusCode_2.code) {
                //POST 保存数据
                _sass.saveClassStatusInfo({"classStatusInfo": GlobalConfig.classStatusInfo});//保存课堂状态信息
            } else {
                loger.error("不能保存课堂数据", GlobalConfig.getCurrentStatus());
            }
        } else {
            loger.log("没有保存课堂状态信息的权限->身份", GlobalConfig.userRole);
        }
    }

    //保存会态信息成功
    _sassSaveClassStatusInfoSuccessHandler(_data) {
        loger.log('保存课堂状态信息成功.');
        loger.log(_data);
    }

    _sassSaveClassRecordInfoSuccessHandler(_data) {
        loger.log('保存课堂录制信息成功.');
        loger.log(_data);
    }

    //Sass校验流程结束之后,开始加入MCU
    _joinMCU() {
        loger.log('加入课堂->.');
        if (_mcu) {
            _mcu.joinMCU(GlobalConfig.getClassInfo());
        }
    }

    _switchMcuIp() {
        loger.log('切换MCU IP->.');
        if (_mcu) {
            _mcu.switchMCUIp(GlobalConfig.getClassInfo());
        }
    }

    // MCU 课堂成功
    _mcuJoinMCUClassSuccessHandler(_data) {
        //loger.log('MCU 课堂成功.');
        GlobalConfig.setCurrentStatus(GlobalConfig.statusCode_2);
        GlobalConfig.classJoinSuccess=true;

        GlobalConfig.screenWidth=window.screen.width;
        GlobalConfig.screenHeight=window.screen.height;


        //返回给客户端初始化成功的数据
        let joinClassSuccessCallBackData = {};

        joinClassSuccessCallBackData.isRecordPlayBack = GlobalConfig.isRecordPlayBack;

        joinClassSuccessCallBackData.DOCServerIP = GlobalConfig.DOCServerIP;
        joinClassSuccessCallBackData.DOCServerPort = GlobalConfig.DOCServerPort;

        joinClassSuccessCallBackData.classStatus = GlobalConfig.classStatus;
        joinClassSuccessCallBackData.classId = GlobalConfig.classId;
        joinClassSuccessCallBackData.className = GlobalConfig.className;
        joinClassSuccessCallBackData.h5Module = GlobalConfig.h5Module;
        joinClassSuccessCallBackData.isHost = GlobalConfig.isHost;
        joinClassSuccessCallBackData.maxAudioChannels = GlobalConfig.maxAudioChannels;
        joinClassSuccessCallBackData.maxVideoChannels = GlobalConfig.maxVideoChannels;
        joinClassSuccessCallBackData.maxMediaChannels= GlobalConfig.maxMediaChannels;
        joinClassSuccessCallBackData.mcuDelay = GlobalConfig.mcuDelay;

        joinClassSuccessCallBackData.msType = GlobalConfig.msType;
        joinClassSuccessCallBackData.nodeId = GlobalConfig.nodeId;
        joinClassSuccessCallBackData.password = GlobalConfig.password;
        joinClassSuccessCallBackData.passwordRequired = GlobalConfig.passwordRequired;//  老师的默认是true
        //GlobalConfig.passwordRequired  老师的默认是true
        //GlobalConfig.portal=_data.portal;
        joinClassSuccessCallBackData.role = GlobalConfig.role;
        joinClassSuccessCallBackData.siteId = GlobalConfig.siteId;
        joinClassSuccessCallBackData.topNodeID = GlobalConfig.topNodeID;
        joinClassSuccessCallBackData.userId = GlobalConfig.userId;
        joinClassSuccessCallBackData.userName = GlobalConfig.userName;
        joinClassSuccessCallBackData.userRole = GlobalConfig.userRole;
        joinClassSuccessCallBackData.userType = GlobalConfig.userType;

        joinClassSuccessCallBackData.siteId = GlobalConfig.siteId;
        joinClassSuccessCallBackData.classId = GlobalConfig.classId;
        joinClassSuccessCallBackData.userRole = GlobalConfig.userRole;
        joinClassSuccessCallBackData.userId = GlobalConfig.userId;
        joinClassSuccessCallBackData.passwordRequired = GlobalConfig.passwordRequired;
        joinClassSuccessCallBackData.classType = GlobalConfig.classType || ApeConsts.CLASS_TYPE_1;

        joinClassSuccessCallBackData.country = GlobalConfig.country;//国家
        joinClassSuccessCallBackData.city = GlobalConfig.city;//城市
        joinClassSuccessCallBackData.province = GlobalConfig.province;//服务商
        joinClassSuccessCallBackData.isp = GlobalConfig.isp;//服务商

        joinClassSuccessCallBackData.classTimestamp = GlobalConfig.classTimestamp;//课堂进行的累积时间
        joinClassSuccessCallBackData.recordTimestamp = GlobalConfig.recordTimestamp;//课堂录制的累积时间
        joinClassSuccessCallBackData.recordPlaybackMaxTime = GlobalConfig.recordPlaybackMaxTime;//录制回放的总时间

        joinClassSuccessCallBackData.fps = GlobalConfig.fps;
        joinClassSuccessCallBackData.gop = GlobalConfig.gop;
        joinClassSuccessCallBackData.videoQuality = GlobalConfig.videoQuality;


        joinClassSuccessCallBackData.ssTunnelAppURL = GlobalConfig.ssTunnelAppURL;

        loger.log('加入课堂成功->');
        loger.log(joinClassSuccessCallBackData);

        //加入课堂成功,广播消息
        this._emit(MessageTypes.CLASS_JOIN_SUCCESS, joinClassSuccessCallBackData);
    }

    //切换MCU ->_param->{reConnect:false} //reConnect(是否立即替换当前的ip并且重新连接)
    _switchMcuIpHandler(_param) {
        if (GlobalConfig.isRecordPlayBack) {
            loger.log('录制回放->不进行MCU动态选点');
            return;
        }
        loger.log('MCU->动态选点');
        let _this = this;
        this._getFastestMcuServer(function (_data) {
            loger.log("MCU选点结束->", _data);
            //记录当前的IP地址,选点结束后需要判断一下是否是新的IP;
            let oldIp= GlobalConfig.MCUServerIP;

            if (_data && _data.ip) {
                GlobalConfig.MCUServerIP = _data.ip || "";
                GlobalConfig.MCUServerPort = _data.port || "";
            } else {
                //随机选择一个
                if (GlobalConfig.mcuList && GlobalConfig.mcuList.length > 0) {
                    let index = parseInt(Math.random() * GlobalConfig.mcuList.length);
                    GlobalConfig.MCUServerIP = GlobalConfig.mcuList[index].ip || "";
                    GlobalConfig.MCUServerPort = GlobalConfig.mcuList[index].port || "";
                }
            }
            if(oldIp&&oldIp!=GlobalConfig.MCUServerIP){
                loger.log('MCU->最新地址->', GlobalConfig.MCUServerIP, GlobalConfig.MCUServerPort);
                //判断是否需要主动断开当前的连接然后重连新的服务器
                if (_param && _param.reConnect == true) {
                    loger.log('MCU->切换到最新的IP->', GlobalConfig.MCUServerIP, GlobalConfig.MCUServerPort);
                    _this._startConnectMCU();
                }else {
                    //不需要断开当前的连接,更改ip即可
                    _this._switchMcuIp();
                }
            }else {
                //如果选点结束后获得的ip和当前的IP相同,不需要切换
                loger.log('MCU不需要切换->之前的IP->',oldIp,"新的IP->",GlobalConfig.MCUServerIP);
            }
        });
    }

    //课堂状态发生改变,需要停止当前的所有推流
    _stopAllMediaPublishHandler(_data){
        loger.log('课堂状态发生改变,需要停止当前的所有推流');
        this._emit(MessageTypes.MEDIA_STOP_PUBLISH);
       /* let allChannels=MediaModule.allMediaChannelsList;
        let channl=null;
        for(let i in allChannels){
            channl=allChannels[i];
            if(channl&&channl.status==ApeConsts.CHANNEL_STATUS_OPENING&&channl.fromNodeId==GlobalConfig.nodeId){
                this._emit(MessageTypes.MEDIA_STOP_PUBLISH);
                return;
            }
        }*/
    }

    //切换MS ->_param->{reConnect:false} //reConnect(是否立即替换当前的ip并且重新连接)
    _switchMsIpHandler(_param) {
        if (GlobalConfig.isRecordPlayBack) {
            //录制回放不做操作
            loger.log('录制回放->不进行MS动态选点');
            return;
        }
        loger.log('MS->动态选点');
        let _this = this;
        this._getFastestMsServer(function (_data) {
            loger.log("MS选点结束->", _data);
            //记录当前的IP地址,选点结束后需要判断一下是否是新的IP;
            let oldIp= GlobalConfig.MCUServerIP;

            if (_data && _data.ip) {
                GlobalConfig.MS_PUBLISH_IP = _data.ip || "";
                GlobalConfig.MS_PUBLISH_PORT = _data.port || "";
            } else {
                //随机选择一个
                if (GlobalConfig.msList && GlobalConfig.msList.length > 0) {
                    let index = parseInt(Math.random() * GlobalConfig.msList.length);
                    GlobalConfig.MS_PUBLISH_IP = GlobalConfig.msList[index].ip || "";
                    GlobalConfig.MS_PUBLISH_PORT = GlobalConfig.msList[index].port || "";
                }
            }


            if(oldIp&&oldIp!=GlobalConfig.MS_PUBLISH_IP){
               /* loger.log('MS->切换地址->', GlobalConfig.MSServerIP, GlobalConfig.MSServerPort);
                //判断是否需要断开当前的连接重连新的服务器
                if (_param && _param.reConnect == true) {
                    loger.log('MS->最新地址->', GlobalConfig.MSServerIP, GlobalConfig.MSServerPort);
                }*/
                loger.log('MS->最新地址->', GlobalConfig.MS_PUBLISH_IP, GlobalConfig.MS_PUBLISH_PORT);
            }else {
                //如果选点结束后获得的ip和当前的IP相同,不需要切换
                loger.log('MS不需要切换->IP',GlobalConfig.MS_PUBLISH_IP);
            }

        });
    }


    //先通过Sass删除文档数据,删除成功之后才能删除MCU的
    _sassDeleteDocument(_param) {
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return;
        }

        //判断传入的参数是否存在
        if (_param == null || EngineUtils.isEmptyObject(_param)) {
            loger.error('删除文档失败->参数错误', _param);
            this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_DOC_DELETE_FAILED_PARAM);
            return;
        }
        //判断必要的参数字段值
        if (_param.itemIdx == null || isNaN(_param.itemIdx) || _param.docId == null || _param.docId == "") {
            loger.error('删除文档失败->', _param);
            this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_DOC_DELETE_FAILED_PARAM);
            return;
        }
        loger.log('删除文档->', _param);

        if (_sass) {
            _sass.sassDeleteDocument(_param);
        }
    }

    _sendDocBroadcastMsg(_param) {
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return;
        }
        if (_doc_ape) {
            _doc_ape.sendDocBroadcastMsg(_param);
        }
    }

    //Sass删除文档成功之后,同步删除MCU数据
    _sassDeleteDocumentSuccess(_param) {
        loger.log('删除文档成功->', _param);
        this._sendDocumentDelete(_param);
    }
    _sassDeleteMediaShareSuccess(_param){
        loger.log('删除媒体文件成功->', _param);
        this._sendMediaSharedDelete(_param);
    }

    //ConferApe
    //开始上课
    _sendStartClass(_param) {
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return;
        }

        if (_confer_ape) {
            _confer_ape.startClass(_param);
        }
    }

    //暂停上课
    _sendPauseClass(_param) {
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return;
        }
        if (_confer_ape) {
            _confer_ape.pauseClass(_param);
        }
    }
    //更新设备信息
    _updateDeviceInfo(_param){
        if (!_mcu.connected) {
            loger.warn('更新设备信息->失败',GlobalConfig.getCurrentStatus());
            return {"code": ApeConsts.RETURN_FAILED, "data": ""};
        }
        if(!GlobalConfig.classJoinSuccess){
            loger.warn('更新设备信息->失败->还没有加入课堂成功',GlobalConfig.getCurrentStatus());
        }
        if (_confer_ape) {
            _confer_ape.updateDeviceInfo(_param);
        }
    }

    _controlHandUpStatus(_param){
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return {"code": ApeConsts.RETURN_FAILED, "data": ""};
        }
        if (_confer_ape) {
            _confer_ape.controlHandUpStatus(_param);
        }
    }
    _changeHandUpStatus(_param){
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return {"code": ApeConsts.RETURN_FAILED, "data": ""};
        }
        if (_confer_ape) {
            _confer_ape.changeHandUpStatus(_param);
        }
    }
    //停止上课
    _sendCloseClass(_param) {
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return {"code": ApeConsts.RETURN_FAILED, "data": ""};
        }
        if (_confer_ape) {
            _confer_ape.closeClass(_param);
        }
    }

    // 离开课堂 {type:1}   type=1被踢出课堂;type=0自己主动离开
    _leaveClass(_param) {
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return {"code": ApeConsts.RETURN_FAILED, "data": ""};
        }

        //停止推流
        if (_video_ape) {
            _video_ape.stopPublishVideo();
            _video_ape.stopPublishScreenShare();
        }
        if (_audio_ape) {
            _audio_ape.stopPublishAudio();
        }
        //离开课堂
        if (_confer_ape) {
            _confer_ape.stopRecord();
            _confer_ape.leaveClass();
        }

        let callBack={};
        if(_param&&_param.type){
            callBack=_param;
        }else{
            callBack.type=0;
        }
        loger.warn('离开课堂->',MessageTypes.CLASS_EXIT,callBack);
        this._emit(MessageTypes.CLASS_EXIT,callBack);

        //断开MCU连接
        if (_mcu) {
            _mcu.leaveMCU();
            GlobalConfig.setCurrentStatus(GlobalConfig.statusCode_3);
        }
    }


    //ChatApe
    // 发送聊天消息
    _sendChatMsg(_messageInfo) {
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return {"code": ApeConsts.RETURN_FAILED, "data": ""};
        }
        if (_messageInfo === null || EngineUtils.isEmptyObject(_messageInfo)) {
            loger.log('发送聊天消息失败->参数错误', _messageInfo);
            return {"code": ApeConsts.RETURN_FAILED, "data": ""};
        }
        if (_chat_ape) {
            _chat_ape.sendChatMsg(_messageInfo);
        }
    }

    //监听摄像头麦克风状态
    userDeviecStatusChange(_data){
        /*   nodeId:GlobalConfig.nodeId,
            userRole:GlobalConfig.userRole,
            userName:GlobalConfig.userName,
            userId:GlobalConfig.userId,
            openCamera:GlobalConfig.openCamera,
            openMicrophones:GlobalConfig.openMicrophones*/
        if (_confer_ape) {
            _confer_ape.updaterUserDeviecStatusChange(_data);
        }
    }

    //屏幕共享
    //开始屏幕共享
    _publishScreenShare(_param){
        if(_video_ape){
            _video_ape.publishScreenShare(_param);
        }
    }
    //停止屏幕共享
    _stopPublishScreenShare(_param){
        if(_video_ape){
            _video_ape.stopPublishScreenShare(_param);
        }
    }
    //VidoeApe
    videoUpdate(_data) {
        //视频同步的消息发送改变,需要通知ferApe模块中的用户更新状态
        if (_confer_ape) {
            _confer_ape.updaterRosterStatus(_data);
        }
    }

    _sendVideoBroadcastMsg(_param) {
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return {"code": ApeConsts.RETURN_FAILED, "data": ""};
        }
        if (_video_ape) {
            return _video_ape.sendVideoBroadcastMsg(_param);
        }
    }

    _getVideoPlayPath(_param) {
        if (_video_ape) {
            return _video_ape.getPlayVideoPath(_param);
        }
    }

    _getVideoPublishPath(_param) {
        if (_video_ape) {
            return _video_ape.getPublishVideoPath(_param);
        }
    }

    _getVideoAllChannelInfo(_param) {
        if (_video_ape) {
            return _video_ape.getAllChannelInfo(_param);
        }
    }

    _publishVideo(_param) {
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return {"code": ApeConsts.RETURN_FAILED, "data": ""};
        }
        if (_video_ape) {
            return _video_ape.publishVideo(_param);
        }
    }

    _stopPublishVideo(_param) {
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return {"code": ApeConsts.RETURN_FAILED, "data": ""};
        }
        if (_video_ape) {
            return _video_ape.stopPublishVideo(_param);
        }
    }

    //AudioApe
    audioUpdate(_data) {
        //音频同步的消息发送改变,需要通知ferApe模块中的用户更新状态
        if (_confer_ape) {
            _confer_ape.updaterRosterStatus(_data);
        }
    }

    sendAudioCommandMsg(_param) {
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return {"code": ApeConsts.RETURN_FAILED, "data": ""};
        }
        if (_audio_ape) {
            return _audio_ape.sendAudioBroadcastMsg(_param);
        }
    }

    _getPlayAudioPath(_param) {
        if (_audio_ape) {
            return _audio_ape.getAudioPlayPath(_param);
        }
    }

    _getPublishAudioPath(_param) {
        if (_audio_ape) {
            return _audio_ape.getAudioPublishPath(_param);
        }
    }

    _getAudioAllChannelInfo(_param) {
        if (_audio_ape) {
            return _audio_ape.getAllChannelInfo(_param);
        }
    }

    _publishAudio(_param) {
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return {"code": ApeConsts.RETURN_FAILED, "data": ""};
        }
        if (_audio_ape) {
            return _audio_ape.publishAudio(_param);
        }
    }

    _stopPublishAudio(_param) {
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return {"code": ApeConsts.RETURN_FAILED, "data": ""};
        }
        if (_audio_ape) {
            return _audio_ape.stopPublishAudio(_param);
        }
    }


    //WhiteBoardApe
    // 添加标注,发送信息
    _sendInsertAnnotaion(_param) {
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return;
        }
        if (_whiteboard_ape) {
            _whiteboard_ape.sendInsetAnnotaion(_param);
        }
    }

    //删除当前页面上的所有标注
    _sendDeleteCurPageAnnotation(_param) {
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return;
        }
        if (_whiteboard_ape) {
            _whiteboard_ape.sendDeleteCurPageAnnotation(_param);
        }
    }

    //删除所有标注
    _sendDeleteAllAnnotation(_param) {
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return;
        }
        if (_whiteboard_ape) {
            _whiteboard_ape.sendDeleteAllAnnotation(_param);
        }
    }

    //返回上一步标注
    _sendGotoPrev(_param) {
        if (_whiteboard_ape) {
            _whiteboard_ape.sendGotoPrev(_param);
        }
    }


    //DocApe
    //获取文档的所有资源地址
    _getDocFullAddress(_param) {
        if (_doc_ape) {
            return _doc_ape.getDocFullAddress(_param);
        } else {
            loger.error("文档模块还没有创建无法获取");
            return {"code": ApeConsts.RETURN_FAILED, "data": "文档模块还没有创建无法获取"};
        }
    }

    //获取文档完整路径
    _getDocImageFullPath(_param) {
        if (_doc_ape) {
            return _doc_ape.getDocImageFullPath(_param);
        } else {
            loger.error("文档模块还没有创建无法获取");
            return [];
        }
    }

    _getDocPDFFullPath(_param) {
        if (_doc_ape) {
            return _doc_ape.getDocPDFFullPath(_param);
        } else {
            loger.error("文档模块还没有创建,无法获取");
            return [];
        }
    }

    //上传文档
    _sendDocumentUpload(_param) {
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return;
        }
        if (_doc_ape) {
            _doc_ape.documentUpload(_param);
        }
    }

    //切换文档
    _sendDocumentSwitchDoc(_param) {
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return;
        }
        if (_doc_ape) {
            _doc_ape.documentSwitchDoc(_param);
        }
    }

    //操作文档(翻页)
    _sendDocumentSwitchPage(_param) {
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return;
        }
        if (_doc_ape) {
            _doc_ape.documentSwitchPage(_param);
        }
    }
    //操作文档(页码上的动画步骤操作)
    _sendDocumentSwitchAnimation(_param){
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return;
        }
        if (_doc_ape) {
            _doc_ape.documentSwitchAnimation(_param);
        }
    }
    //操作文档(缩放、滚动...)
    _sendDocumentCommand(_param) {
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return;
        }
        if (_doc_ape) {
            _doc_ape.documentCommand(_param);
        }
    }

    //删除文档
    _sendDocumentDelete(_param) {
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return;
        }
        if (_doc_ape) {
            _doc_ape.documentDelete(_param);
        }
    }

    //删除所有文档
    _documentDeleteAll(_param) {
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return;
        }
        if (_doc_ape) {
            _doc_ape.documentDeleteAll(_param);
        }
    }

    //// 文档变更,白板也需要做处理
    docUpdateHandler(_data) {
        if (!_mcu.connected && !GlobalConfig.isRecordPlayBack) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return;
        }
        //loger.log('Doc UpdateId ->');
        //loger.log(_data);
        if (_whiteboard_ape) {
            _whiteboard_ape.docUpdateHandler(_data);
        }
    }

    //文档删除,白板也需要做处理
    docDeleteHandler(_data) {
        if (_whiteboard_ape) {
            _whiteboard_ape.docDeleteHandler(_data);
        }
    }

    //文档加入频道成功,同步到MCU服务器上的数据
    docJoinChannelSuccess() {
        loger.log("docJoinChannelSuccess->isHost=", GlobalConfig.isHost, "length=", GlobalConfig.docListPrepare.length);
        //loger.log("docJoinChannelSuccess  docListPrepare=");
        //如果是主持人,那么需要判断一下文档模块同步的数据和从sass获取的文档数据是否相同,如果mcu服务器不存在的,需要上传
        if (GlobalConfig.isHost && GlobalConfig.docListPrepare.length > 0) {
            for (let i = 0; i < GlobalConfig.docListPrepare.length; i++) {
                let value = GlobalConfig.docListPrepare[i];
                if (value) {
                    //loger.log("判断是否需要把提前上传的文档上传到mcu", value);
                    let paramInfo = {
                        "pageNum": value.pdfSize,
                        "fileName": value.name,
                        "fileType": value.type,
                        "relativeUrl": value.relativeLocation,
                        "url": value.absoluteLocation,
                        "creatUserId": value.createUserID,
                        "docId": value.id,
                        "md5": value.MD5,
                        "visible": false
                    };
                    this._sendDocumentUpload(paramInfo);
                }
            }
        }
    }

    //媒体共享模块的接口
    //上传
    _sendMediaSharedUpload(_param){
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return;
        }
        if (_mediaShareApe) {
            _mediaShareApe.mediaSharedUpload(_param);
        }
    }
    //Sass删除媒体文件数据
    _sassDeletMediaShare(_param){
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return;
        }

        //判断传入的参数是否存在
        if (_param == null || EngineUtils.isEmptyObject(_param)) {
            loger.error('删除媒体文件失败->参数错误', _param);
            this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_MEDIASHARE_DELETE_FAILED_PARAM);
            return;
        }
        //判断必要的参数字段值
        if (_param.itemIdx == null || isNaN(_param.itemIdx) || _param.fileId == null || _param.fileId == "") {
            loger.error('删除媒体文件失败->', _param);
            this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_MEDIASHARE_DELETE_FAILED_PARAM);
            return;
        }
        loger.log('删除媒体文件->', _param);

        if (_sass) {
            _sass.sassDeletMediaShare(_param);
        }
    }
    //删除
    _sendMediaSharedDelete(_param){
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return;
        }
        if (_mediaShareApe) {
            _mediaShareApe.mediaSharedDelete(_param);
        }
    }
    //更新媒体文件的状态信息
    _sendMediaSharedUpdate(_param){
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return;
        }
        if (_mediaShareApe) {
            _mediaShareApe.mediaSharedUpdate(_param);
        }
    }
    //播放
    _sendMediaSharedPlay(_param){
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return;
        }
        if (_mediaShareApe) {
            _mediaShareApe.mediaSharedPlay(_param);
        }
    }
    //停止
    _sendMediaSharedStop(_param){
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return;
        }
        if (_mediaShareApe) {
            _mediaShareApe.mediaSharedStop(_param);
        }
    }

    //媒体共享模块加入频道成功,同步到MCU服务器上的数据
    mediaShareApeJoinChannelSuccess() {
        loger.log("媒体共享模块加入频道成功->isHost=", GlobalConfig.isHost, "length=", GlobalConfig.sharedMediaList.length);
        console.log("媒体共享模数据->", GlobalConfig.sharedMediaList);
        //如果是主持人,那么需要判断一下文档模块同步的数据和从sass获取的文档数据是否相同,如果mcu服务器不存在的,需要上传
       if (GlobalConfig.isHost && GlobalConfig.sharedMediaList.length > 0) {
            for (let i = 0; i < GlobalConfig.sharedMediaList.length; i++) {
                let value = GlobalConfig.sharedMediaList[i];
                if (value) {
                    let paramInfo = {
                        "status": 0,
                        "creatUserId": value.creatUserId,
                        "creatUserName": value.createUserName,
                        "url": value.url,
                        "fileType": value.type,
                        "fileId": ""+value.id,
                        "fileName": value.name,
                        "seek": 0
                    };
                    this._sendMediaSharedUpload(paramInfo);
                }
            }
        }
    }

    //录制回放相关的处理------------------------------------------------
    //录制回放初始化
    _initRecordPlayback(_param) {
        //{"classId":"1653304953","portal":"112.126.80.182:80","userRole":"normal","userId":0}
        if (_param == null) {
            loger.error('录制回放初始化失败->参数错误');
            this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_INIT_RECORD_PLAY_BACK_FAILED);
            return;
        }
        //判断必要的参数字段值
        if (_param.classId == null || isNaN(_param.classId) || _param.portal == null || _param.portal == "") {
            loger.error('录制回放初始化失败->', _param);
            this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_INIT_RECORD_PLAY_BACK_FAILED);
            return;
        }
        loger.log('录制回放初始化->', _param);

        //保存参数
        GlobalConfig.isRecordPlayBack = true;//设置为录制回放状态
        GlobalConfig.classId = parseInt(_param.classId);
        GlobalConfig.portal = _param.portal;
        GlobalConfig.userRole = ApeConsts.normal;//*************很重要,录制回放的时候,身份模式是普通人********
        GlobalConfig.userId = _param.userId || "0";
        GlobalConfig.userName = _param.userName || "";

        //获取课堂最完整的数据,录制回放需要获取课堂数据
        if (_sass) {
            _sass.getClassParam();
        }
    }

    //开始录制回放
    _startRecordPlayback(_param) {
        if (_recordPlayback) {
            _recordPlayback.startRecordPlayback(_param);
        }
    }

    //停止录制回放
    _stopRecordPlayback(_param) {
        if (_recordPlayback) {
            _recordPlayback.stopRecordPlayback(_param);
        }
    }

    //暂停录制回放
    _pauseRecordPlayback(_param) {
        if (_recordPlayback) {
            _recordPlayback.pauseRecordPlayback(_param);
        }
    }

    //seek录制回放
    _seekRecordPlayback(_param) {
        if (_recordPlayback) {
            _recordPlayback.seekRecordPlayback(_param);
        }
    }

    //录制回放状态更新
    _recordPlaybackClearDataHandler(_param) {
        loger.log("录制回放状态更新->")
        if (_doc_ape) {
            _doc_ape.clearData();
        }
        if (_whiteboard_ape) {
            _whiteboard_ape.clearData();
        }
        if(_video_ape){
            _video_ape.clearData();
        }
    }

    //录制回放加入 课堂成功
    _joinRecordPlaybackSuccessHandler(_data) {
        loger.log('加入录制回放成功.');
        GlobalConfig.setCurrentStatus(GlobalConfig.statusCode_2);

        //返回给客户端初始化成功的数据
        let joinClassSuccessCallBackData = {};

        joinClassSuccessCallBackData.isRecordPlayBack = GlobalConfig.isRecordPlayBack;

        joinClassSuccessCallBackData.DOCServerIP = GlobalConfig.DOCServerIP;
        joinClassSuccessCallBackData.DOCServerPort = GlobalConfig.DOCServerPort;

        joinClassSuccessCallBackData.classStatus = GlobalConfig.classStatus;
        joinClassSuccessCallBackData.classId = GlobalConfig.classId;
        joinClassSuccessCallBackData.className = GlobalConfig.className;
        joinClassSuccessCallBackData.h5Module = GlobalConfig.h5Module;
        joinClassSuccessCallBackData.isHost = GlobalConfig.isHost;//
        joinClassSuccessCallBackData.maxAudioChannels = GlobalConfig.maxAudioChannels;
        joinClassSuccessCallBackData.maxVideoChannels = GlobalConfig.maxVideoChannels;
        joinClassSuccessCallBackData.maxMediaChannels = GlobalConfig.maxMediaChannels;

        joinClassSuccessCallBackData.mcuDelay = GlobalConfig.mcuDelay;

        joinClassSuccessCallBackData.msType = GlobalConfig.msType;
        joinClassSuccessCallBackData.nodeId = GlobalConfig.nodeId;
        joinClassSuccessCallBackData.password = GlobalConfig.password;
        joinClassSuccessCallBackData.passwordRequired = GlobalConfig.passwordRequired;//  老师的默认是true
        //GlobalConfig.passwordRequired  老师的默认是true
        //GlobalConfig.portal=_data.portal;
        joinClassSuccessCallBackData.role = GlobalConfig.role;
        joinClassSuccessCallBackData.siteId = GlobalConfig.siteId;
        joinClassSuccessCallBackData.topNodeID = GlobalConfig.topNodeID;
        joinClassSuccessCallBackData.userId = GlobalConfig.userId;
        joinClassSuccessCallBackData.userName = GlobalConfig.userName;
        joinClassSuccessCallBackData.userRole = GlobalConfig.userRole;
        joinClassSuccessCallBackData.userType = GlobalConfig.userType;

        joinClassSuccessCallBackData.siteId = GlobalConfig.siteId;
        joinClassSuccessCallBackData.classId = GlobalConfig.classId;
        joinClassSuccessCallBackData.userRole = GlobalConfig.userRole;
        joinClassSuccessCallBackData.userId = GlobalConfig.userId;
        joinClassSuccessCallBackData.passwordRequired = GlobalConfig.passwordRequired;
        joinClassSuccessCallBackData.classType = GlobalConfig.classType || ApeConsts.CLASS_TYPE_1;

        joinClassSuccessCallBackData.country = GlobalConfig.country;//国家
        joinClassSuccessCallBackData.city = GlobalConfig.city;//城市
        joinClassSuccessCallBackData.province = GlobalConfig.province;//服务商
        joinClassSuccessCallBackData.isp = GlobalConfig.isp;//服务商

        joinClassSuccessCallBackData.classTimestamp = GlobalConfig.classTimestamp;//课堂进行的累积时间
        joinClassSuccessCallBackData.recordTimestamp = GlobalConfig.recordTimestamp;//录制累积的总时间
        joinClassSuccessCallBackData.recordPlaybackMaxTime = GlobalConfig.recordPlaybackMaxTime;//录制回放的总时间

        joinClassSuccessCallBackData.fps = GlobalConfig.fps;
        joinClassSuccessCallBackData.gop = GlobalConfig.gop;
        joinClassSuccessCallBackData.videoQuality = GlobalConfig.videoQuality;

        joinClassSuccessCallBackData.ssTunnelAppURL = GlobalConfig.ssTunnelAppURL;

        loger.log(joinClassSuccessCallBackData);
        //和加入课堂成功使用同样的消息处理
        this._emit(MessageTypes.CLASS_JOIN_SUCCESS, joinClassSuccessCallBackData);
    }

    // //答题卡
    _creatQuestion(_param){
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return;
        }
        if (_questionApe) {
            _questionApe.creatQuestion(_param);
        }
    }
    _getQuestion(_param){
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return;
        }
        if (_questionApe) {
            _questionApe.getQuestion(_param);
        }
    }
    _getQuestionResult(_param){
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return;
        }
        if (_questionApe) {
            _questionApe.getQuestionResult(_param);
        }
    }
    _stopQuestion(_param){
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return;
        }
        if (_questionApe) {
            _questionApe.stopQuestion(_param);
        }
    }
    _sendAnswer(_param){
        if (!_mcu.connected) {
            loger.warn(GlobalConfig.getCurrentStatus());
            return;
        }
        if (_questionApe) {
            _questionApe.sendAnswer(_param);
        }
    }

}