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); } } }