From 52e34a05382c3adfb79650431b272b4a77312a2e Mon Sep 17 00:00:00 2001
From: liyong <liyong@3mang.com>
Date: Mon, 20 Nov 2017 19:53:39 +0800
Subject: [PATCH] 1.修改nodeId和userId的生成规则,避免重复;2.统一设备类型定义;3.处理课堂模块和视频模块离开课堂后的消息处理

---
 src/EngineEntrance.js | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------
 src/EverSocket.js     | 28 ++++++++++++++++++++++------
 src/GlobalConfig.js   | 10 ++++++++--
 src/apes/ApeConsts.js |  6 +++---
 src/apes/AudioApe.js  |  2 +-
 src/apes/ConferApe.js | 22 ++++++++++++----------
 src/apes/VideoApe.js  | 17 ++++++++++++-----
 src/apes/WebRtcApe.js |  2 +-
 src/mcu.js            | 16 ++++++++++++----
 9 files changed, 130 insertions(+), 68 deletions(-)

diff --git a/src/EngineEntrance.js b/src/EngineEntrance.js
index a51c0e0..cc0edea 100644
--- a/src/EngineEntrance.js
+++ b/src/EngineEntrance.js
@@ -63,7 +63,7 @@ export default class MessageEntrance extends Emiter {
     super();
     this.lastClassActiveTime=0;//最后一次课堂激活的时间戳
     //sdk 信息
-    GlobalConfig.sdkVersion = "v2.30.5.20171117";
+    GlobalConfig.sdkVersion = "v2.31.1.20171120";
     loger.warn("sdkVersion:" + GlobalConfig.sdkVersion);
     console.log("sdkVersion:" + GlobalConfig.sdkVersion);
     //设置
@@ -456,8 +456,23 @@ export default class MessageEntrance extends Emiter {
       LogManager.IS_OPEN_SEND_LOG = false;//断开之后不再上报日志
     },2000);
 
+    this.clearClientData();
+  }
+  //清除所有客户端数据
+  clearClientData(){
+    GlobalConfig.MCUServerIP="";
+    GlobalConfig.MCUServerPort="";
+    GlobalConfig.mcuListFinal=[];
+    if(_mcu){
+      _mcu.leaveMCU();
+    }
+    if(_confer_ape){
+      _confer_ape.stopApe();
+    }
+    if(_video_ape){
+      _video_ape.stopApe();
+    }
   }
-
   //当前的课堂状态信息发生改变,需要保存课堂状态到Sass
   _onClassStatusInfoChange(_param) {
     //如果MCU连接已经断开,不发送
@@ -493,6 +508,10 @@ export default class MessageEntrance extends Emiter {
     if (GlobalConfig.isRecordPlayBack || !_confer_ape) {
       return;
     }
+    if(GlobalConfig.classType==ApeConsts.CLASS_TYPE_ZHIBO){
+      //直播的时候不再同步所有模块的消息
+      return
+    }
     //老师身份和非录制回放的时候执行,录制状态发送改变,需要更新当前的数据,否则已有的消息会录制不上
     if (_confer_ape.checkHasRecordControl()) {
       loger.warn('录制状态发送改变->更新所有模块的当前数据发送到MCU');
@@ -529,7 +548,10 @@ export default class MessageEntrance extends Emiter {
     if (!_data) {
       return;
     }
-    if (GlobalConfig.deviceType == 1 || GlobalConfig.deviceType == 2 || GlobalConfig.deviceType == 3 || _data.nodeId == GlobalConfig.nodeId) {
+    if (GlobalConfig.deviceType == GlobalConfig.deviceIOS ||
+      GlobalConfig.deviceType == GlobalConfig.deviceAndroid ||
+      GlobalConfig.deviceType == GlobalConfig.deviceH5 ||
+      _data.nodeId == GlobalConfig.nodeId) {
       return;
     }
     if (_webRtc) {
@@ -600,7 +622,7 @@ export default class MessageEntrance extends Emiter {
     GlobalConfig.isH5 = _param.isH5 || false;//外部传入的参数,是否是H5
     if (GlobalConfig.isH5 == true) {
       GlobalConfig.platform = "h5";
-      GlobalConfig.deviceType = 3//3是H5
+      GlobalConfig.deviceType = GlobalConfig.deviceH5;
       loger.warn("设备类型是H5");
     }
 
@@ -619,25 +641,27 @@ export default class MessageEntrance extends Emiter {
       GlobalConfig.userRole != ApeConsts.invisible) {
       GlobalConfig.userRole = ApeConsts.normal;
     }
-    //如果没有名字或没有userId的时候,需要随机生成
-    let timestampStr = new Date().getTime().toString();
-    timestampStr = timestampStr.substr(timestampStr.length - 4);
+
+
+    //如果没有名字的时候需要随机生成
+    let randUserId =parseInt(Math.random()*1000)+""+parseInt(Math.random()*1000)+""+parseInt(Math.random()*1000);
     if (GlobalConfig.userRole == ApeConsts.host) {
-      timestampStr = "T" + timestampStr;
+      randUserId = "T" + randUserId;
     } else if (GlobalConfig.userRole == ApeConsts.assistant) {
-      timestampStr = "A" + timestampStr;
+      randUserId = "A" + randUserId;
     } else if (GlobalConfig.userRole == ApeConsts.presenter) {
-      timestampStr = "P" + timestampStr;
+      randUserId = "P" + randUserId;
     } else {
-      timestampStr = "S" + timestampStr;
+      randUserId = "S" + randUserId;
     }
+
     //如果没有名字,随机起一个名字
-    GlobalConfig.userName = _param.userName || timestampStr;
+    GlobalConfig.userName = _param.userName || randUserId;
     //如果没有userId或者为"0",随机生成
     if (!GlobalConfig.userId || GlobalConfig.userId == "0") {
-      GlobalConfig.userId = timestampStr;
+      GlobalConfig.userId = randUserId;
     }
-
+    console.log("userId", GlobalConfig.userId);
     //客户端决定是否延迟接收消息
     GlobalConfig.messageDelay = _param.messageDelay || false;
 
@@ -696,7 +720,7 @@ export default class MessageEntrance extends Emiter {
     GlobalConfig.md5 = _data.md5 || ""; //这个暂时用假数据,后台接口写完就有数据了
     GlobalConfig.msType = _data.msType || 1;
     GlobalConfig.siteId = _data.siteId || "";
-    GlobalConfig.classType = _data.meetingType || ApeConsts.CLASS_TYPE_1;
+    GlobalConfig.classType = _data.meetingType || ApeConsts.CLASS_TYPE_1v1;
 
     //host默认需要密码,Sass服务器只判断学生是否需要密码,没有判断老师的
     GlobalConfig.passwordRequired = _data.passwordRequired || false; //md5验证的时候需要Sass返回的值,不能更改
@@ -1211,7 +1235,7 @@ export default class MessageEntrance extends Emiter {
     joinClassSuccessCallBackData.userRole = GlobalConfig.userRole;
     joinClassSuccessCallBackData.userId = GlobalConfig.userId;
     joinClassSuccessCallBackData.passwordRequired = GlobalConfig.passwordRequired;
-    joinClassSuccessCallBackData.classType = GlobalConfig.classType || ApeConsts.CLASS_TYPE_1;
+    joinClassSuccessCallBackData.classType = GlobalConfig.classType || ApeConsts.CLASS_TYPE_1v1;
 
     joinClassSuccessCallBackData.country = GlobalConfig.country; //国家
     joinClassSuccessCallBackData.city = GlobalConfig.city; //城市
@@ -1360,12 +1384,12 @@ export default class MessageEntrance extends Emiter {
   //用更状态数据发送变更
   _onRosterUpdateHandler(_data) {
     //数据无效/ios/android  不处理数据
-    if (!_data || GlobalConfig.deviceType == 1 || GlobalConfig.deviceType == 2) {
+    if (!_data || GlobalConfig.deviceType == GlobalConfig.deviceIOS || GlobalConfig.deviceType == GlobalConfig.deviceAndroid) {
       return;
     }
     let nodeData = _data.nodeData;
     //数据用户是pc或H5不处理
-    if (!nodeData || nodeData.deviceType == 0 || nodeData.deviceType == 3) {
+    if (!nodeData || nodeData.deviceType == GlobalConfig.devicePC || nodeData.deviceType == GlobalConfig.deviceH5) {
       return;
     }
     if (nodeData.openCamera > 0 && _webRtc) {
@@ -1572,7 +1596,6 @@ export default class MessageEntrance extends Emiter {
       //开始上课
       _confer_ape.startClass(_param);
       ////开始录制
-      //_confer_ape.startRecord();
     }
   }
 
@@ -2564,8 +2587,8 @@ export default class MessageEntrance extends Emiter {
 
     //如果是主持人,那么需要判断一下文档模块同步的数据和从sass获取的文档数据是否相同,如果mcu服务器不存在的,需要上传
     if (GlobalConfig.docListPrepare && GlobalConfig.docListPrepare.length > 0) {
-      //如果当前身份是老师或者当前课堂内只有一个人,有权限同步文档到MCU
-      if (GlobalConfig.isHost || GlobalConfig.rosterNumber <= 1&&GlobalConfig.deviceType!=3) {
+      //如果当前身份是老师或者当前课堂内只有一个人并且不是H5,有权限同步文档到MCU
+      if (GlobalConfig.isHost || (GlobalConfig.rosterNumber <= 1&&GlobalConfig.deviceType!=GlobalConfig.deviceH5)) {
         for (let i = 0; i < GlobalConfig.docListPrepare.length; i++) {
           let value = GlobalConfig.docListPrepare[i];
           if (value) {
@@ -2759,7 +2782,7 @@ export default class MessageEntrance extends Emiter {
     //loger.log("伴音MUSIC模块加入频道成功->isHost=", GlobalConfig.isHost, "length=", GlobalConfig.musicListPrepare.length);
     //console.log("伴音MUSIC模块共享模数据->", GlobalConfig.musicListPrepare);
     //如果是主持人,那么需要判断一下文档模块同步的数据和从sass获取的文档数据是否相同,如果mcu服务器不存在的,需要上传
-    if (GlobalConfig.isHost && GlobalConfig.musicListPrepare.length > 0&&GlobalConfig.deviceType!=3) {
+    if (GlobalConfig.isHost && GlobalConfig.musicListPrepare.length > 0&&GlobalConfig.deviceType!=GlobalConfig.deviceH5) {
       for (let i = 0; i < GlobalConfig.musicListPrepare.length; i++) {
         let value = GlobalConfig.musicListPrepare[i];
         if (value) {
@@ -2790,7 +2813,7 @@ export default class MessageEntrance extends Emiter {
     //loger.log("媒体共享模块加入频道成功->isHost=", GlobalConfig.isHost, "length=", GlobalConfig.sharedMediaList.length);
     //console.log("媒体共享模数据->", GlobalConfig.sharedMediaList);
     //如果是主持人,那么需要判断一下文档模块同步的数据和从sass获取的文档数据是否相同,如果mcu服务器不存在的,需要上传
-    if (GlobalConfig.isHost && GlobalConfig.sharedMediaList.length > 0&&GlobalConfig.deviceType!=3) {
+    if (GlobalConfig.isHost && GlobalConfig.sharedMediaList.length > 0&&GlobalConfig.deviceType!=GlobalConfig.deviceH5) {
       for (let i = 0; i < GlobalConfig.sharedMediaList.length; i++) {
         let value = GlobalConfig.sharedMediaList[i];
         if (value) {
@@ -2943,7 +2966,7 @@ export default class MessageEntrance extends Emiter {
     joinClassSuccessCallBackData.userRole = GlobalConfig.userRole;
     joinClassSuccessCallBackData.userId = GlobalConfig.userId;
     joinClassSuccessCallBackData.passwordRequired = GlobalConfig.passwordRequired;
-    joinClassSuccessCallBackData.classType = GlobalConfig.classType || ApeConsts.CLASS_TYPE_1;
+    joinClassSuccessCallBackData.classType = GlobalConfig.classType || ApeConsts.CLASS_TYPE_1v1;
 
     joinClassSuccessCallBackData.country = GlobalConfig.country; //国家
     joinClassSuccessCallBackData.city = GlobalConfig.city; //城市
@@ -3029,7 +3052,7 @@ export default class MessageEntrance extends Emiter {
    * 初始化webRtc
    * */
   _initWebRtcSdk(_params, _callback) {
-    if (GlobalConfig.deviceType == 1 || GlobalConfig.deviceType == 2 || GlobalConfig.deviceType == 3) {
+    if (GlobalConfig.deviceType == GlobalConfig.deviceIOS || GlobalConfig.deviceType == GlobalConfig.deviceAndroid || GlobalConfig.deviceType == GlobalConfig.deviceH5) {
       loger.warn("移动端不需要处理初始化webRtc");
       if (_callback) {
         _callback();
@@ -3104,7 +3127,7 @@ export default class MessageEntrance extends Emiter {
    * 加入视频通话
    * */
   _joinChannel(_params) {
-    if (GlobalConfig.deviceType == 1 || GlobalConfig.deviceType == 2) {
+    if (GlobalConfig.deviceType == GlobalConfig.deviceIOS || GlobalConfig.deviceType == GlobalConfig.deviceAndroid) {
       loger.warn("移动端不需要处理加入视频房间");
       return;
     }
@@ -3117,7 +3140,7 @@ export default class MessageEntrance extends Emiter {
    * 离开视频通话频道
    * */
   _leaveChannel(_params) {
-    if (GlobalConfig.deviceType == 1 || GlobalConfig.deviceType == 2) {
+    if (GlobalConfig.deviceType == GlobalConfig.deviceIOS || GlobalConfig.deviceType == GlobalConfig.deviceAndroid) {
       return;
     }
     if (_webRtc) {
@@ -3139,7 +3162,7 @@ export default class MessageEntrance extends Emiter {
       return;
     }
     //ios和安卓的只需要更新数据即可
-    if (GlobalConfig.deviceType == 1 || GlobalConfig.deviceType == 2) {
+    if (GlobalConfig.deviceType == GlobalConfig.deviceIOS || GlobalConfig.deviceType == GlobalConfig.deviceAndroid) {
       loger.log("调用webRtc推流");
       GlobalConfig.openCamera = EngineUtils.creatTimestamp();
       GlobalConfig.openMicrophones = GlobalConfig.openCamera;
@@ -3167,7 +3190,7 @@ export default class MessageEntrance extends Emiter {
    * */
   _unpublishMedia(_params) {
     //ios和安卓的只需要更新数据即可
-    if (GlobalConfig.deviceType == 1 || GlobalConfig.deviceType == 2) {
+    if (GlobalConfig.deviceType == GlobalConfig.deviceIOS || GlobalConfig.deviceType == GlobalConfig.deviceAndroid) {
       loger.log("调用webRtc停止推流");
       GlobalConfig.openCamera = 0;
       GlobalConfig.openMicrophones = 0;
@@ -3193,7 +3216,7 @@ export default class MessageEntrance extends Emiter {
    * 切换摄像头和麦克风设备
    * */
   _changeDevices(_params) {
-    if (GlobalConfig.deviceType == 1 || GlobalConfig.deviceType == 2) {
+    if (GlobalConfig.deviceType == GlobalConfig.deviceIOS || GlobalConfig.deviceType == GlobalConfig.deviceAndroid) {
       return;
     }
     if (_webRtc) {
@@ -3205,7 +3228,7 @@ export default class MessageEntrance extends Emiter {
    * 设置旁路推流
    * */
   _setConfigPublisher(_params) {
-    if (GlobalConfig.deviceType == 1 || GlobalConfig.deviceType == 2) {
+    if (GlobalConfig.deviceType == GlobalConfig.deviceIOS || GlobalConfig.deviceType == GlobalConfig.deviceAndroid) {
       return;
     }
     if (_webRtc) {
@@ -3217,7 +3240,7 @@ export default class MessageEntrance extends Emiter {
    * 设置本地video视图
    * */
   _setLocalMediaView(_params) {
-    if (GlobalConfig.deviceType == 1 || GlobalConfig.deviceType == 2) {
+    if (GlobalConfig.deviceType == GlobalConfig.deviceIOS || GlobalConfig.deviceType == GlobalConfig.deviceAndroid) {
       return;
     }
     if (_webRtc) {
@@ -3229,7 +3252,7 @@ export default class MessageEntrance extends Emiter {
    * 设置房间内老师身份的视图
    * */
   _setHostRemoteMediaView(_params) {
-    if (GlobalConfig.deviceType == 1 || GlobalConfig.deviceType == 2) {
+    if (GlobalConfig.deviceType == GlobalConfig.deviceIOS || GlobalConfig.deviceType == GlobalConfig.deviceAndroid) {
       return;
     }
     if (_webRtc) {
@@ -3241,7 +3264,7 @@ export default class MessageEntrance extends Emiter {
    * 设置房间内普通身份的视图
    * */
   _setNormalRemoteMediaView(_params) {
-    if (GlobalConfig.deviceType == 1 || GlobalConfig.deviceType == 2) {
+    if (GlobalConfig.deviceType == GlobalConfig.deviceIOS || GlobalConfig.deviceType == GlobalConfig.deviceAndroid) {
       return;
     }
     if (_webRtc) {
@@ -3257,7 +3280,7 @@ export default class MessageEntrance extends Emiter {
     if (!_params) {
       return;
     }
-    if (GlobalConfig.deviceType == 1 || GlobalConfig.deviceType == 2) {
+    if (GlobalConfig.deviceType == GlobalConfig.deviceIOS || GlobalConfig.deviceType == GlobalConfig.deviceAndroid) {
       return;
     }
     if (_webRtc) {
@@ -3283,7 +3306,7 @@ export default class MessageEntrance extends Emiter {
    * 设置监课和需要隐藏显示的用户视图
    * */
   _setInvisibleMediaView(_params) {
-    if (GlobalConfig.deviceType == 1 || GlobalConfig.deviceType == 2) {
+    if (GlobalConfig.deviceType == GlobalConfig.deviceIOS || GlobalConfig.deviceType == GlobalConfig.deviceAndroid) {
       return;
     }
     if (_webRtc) {
diff --git a/src/EverSocket.js b/src/EverSocket.js
index 215d74f..db2f15b 100644
--- a/src/EverSocket.js
+++ b/src/EverSocket.js
@@ -15,18 +15,20 @@
 import Emiter from 'Emiter';
 import Loger from 'Loger';
 import GlobalConfig from 'GlobalConfig';
+import EngineUtils from 'EngineUtils';
 import LogManager from 'LogManager';
 let loger = Loger.getLoger('EverSocket');
 const MCU_MAX_RECONNECTION = 3;//最多重连次数
 class EverSocket extends Emiter {
   constructor() {
     super();
+    this.sendToMcuList=[];//发送到MCU的数据记录
+    this.receiveFromMcuList=[];//接到MCU的数据记录
     this.mcuReconnectCounter=0;//(重要)记录mcu连续重连的次数,最大连续8次就不再重连
     this._connected = false;
     this._lastActiveTime = 0;//最后一次收到消息的时间
     this._enableEverSocket = false;
     this.reConnectionCounter = 0;//重连次数
-
   }
 
   begin(ip, port) {
@@ -68,17 +70,25 @@ class EverSocket extends Emiter {
     return this._connected;
   }
 
-  send(data) {
+  send(data,type) {
     if (this._connected) {
       if (data) {
         let len=data.byteLength;
+        //超过1024 警告提示
         if (len> 1024) {
-          loger.warn('发送到MCU的数据文件超过1k-->byteLength->', len);
+          loger.warn('发送到MCU的数据文件超过1k-->byteLength->'+len,"type:"+type);
         }
+        //大于10k 不发送
         if (len>=1024*10) {
-          loger.warn('发送到MCU的数据文件超过10k-->byteLength->', len);
+          loger.warn('发送到MCU的数据文件超过10k-->byteLength->'+len,"type:"+type);
           return;
         }
+
+        this.sendToMcuList.push("c2s_"+EngineUtils.creatTimestampStr()+"_"+len+"_"+type);
+        if(this.sendToMcuList.length>80){
+          loger.log("发送到MCU数据统计->",this.sendToMcuList);
+          this.sendToMcuList=[];
+        }
       }
       this.websocket.send(data);
     } else {
@@ -206,8 +216,14 @@ class EverSocket extends Emiter {
   _onMessage(messageEvent) {
     this._lastActiveTime = Date.now();
     const bufferData = messageEvent.data;
-    //loger.log('RECEIVE MESSAGE-->byteLength->',bufferData.byteLength);
-    if (bufferData.byteLength > 0) {
+    //loger.log('RECEIVE-->byteLength->',bufferData.byteLength);
+    let len=bufferData.byteLength;
+    this.receiveFromMcuList.push("s2c_"+EngineUtils.creatTimestampStr()+"_"+len);
+    if(this.receiveFromMcuList.length>80){
+      loger.log("收到MCU数据统计->",this.receiveFromMcuList);
+      this.receiveFromMcuList=[];
+    }
+    if (len> 0) {
       this._emit(EverSocket.MESSAGE, bufferData);
     }
   }
diff --git a/src/GlobalConfig.js b/src/GlobalConfig.js
index 69fc1b9..5a2c9cb 100644
--- a/src/GlobalConfig.js
+++ b/src/GlobalConfig.js
@@ -542,7 +542,13 @@ GlobalConfig.hasCamera = false; //摄像头是否可用
 GlobalConfig.hasMicrophone = false; //麦克风是否可用
 
 GlobalConfig.returnCitySN = null;//获取的ip数据  {"cip":"60.253.214.122","cid":"110000","cname":"北京市"}
-GlobalConfig.deviceType = 0; //设备类型  0:电脑  1:ios  2:安卓
+//设备类型  0:电脑  1:ios  2:安卓 3 h5
+GlobalConfig.deviceType = 0;
+GlobalConfig.devicePC=0;
+GlobalConfig.deviceIOS=1;
+GlobalConfig.deviceAndroid=2;
+GlobalConfig.deviceH5=3;
+
 GlobalConfig.userIp = ""; //用户当前IP
 GlobalConfig.userId = 0;
 GlobalConfig.paramUserId=0;
@@ -588,7 +594,7 @@ GlobalConfig.topNodeID = 101; //现在固定值,还不知道是做什么用
 GlobalConfig.siteId = ""; //站点号
 GlobalConfig.className = ""; // 课程名称
 GlobalConfig.classId = 0; //课堂号=classId=meetingNumber  之后统一修改为classId
-GlobalConfig.classType = ApeConsts.CLASS_TYPE_1; //课堂类型
+GlobalConfig.classType = ApeConsts.CLASS_TYPE_1v1; //课堂类型
 GlobalConfig.classStatus = ApeConsts.CLASS_STATUS_WAIT; // 0;//课堂还未开始  1;//直播中  2 //课间休息  3已经停止
 GlobalConfig.classStartTime = ""; //课堂点击开始时间
 GlobalConfig.classStopTime = ""; //最后一次停止的时间(点暂停或结束),每次发送数据都获取当前时间戳
diff --git a/src/apes/ApeConsts.js b/src/apes/ApeConsts.js
index 694f84f..73f5ae0 100644
--- a/src/apes/ApeConsts.js
+++ b/src/apes/ApeConsts.js
@@ -29,9 +29,9 @@ ApeConsts.STOP_ALL_PUBLISH=5; //所有人停止推流
 ApeConsts.CLASS_ACTION_DRAW_STATUS_CHANGE = 6; //更改用户的画笔状态
 
 //课堂类型 1:1v1(2路流) 2:直播(1路流) 3:小班课(可以多路流)
-ApeConsts.CLASS_TYPE_1 = 1; // 互动课堂,通过MS转发音视频,不能进行H5观看 1v1(2路流)
-ApeConsts.CLASS_TYPE_2 = 2; // 直播课堂,通过CDN转发音视频,不能进行音视频互动 :直播(1路流)
-ApeConsts.CLASS_TYPE_3 = 3; // 小班课,通过CDN转发音视频,不能进行音视频互动 ::小班课(可以多路流)
+ApeConsts.CLASS_TYPE_1v1 = 1; // 互动课堂,通过MS转发音视频,不能进行H5观看 1v1(2路流)
+ApeConsts.CLASS_TYPE_ZHIBO = 2; // 直播课堂,通过CDN转发音视频,不能进行音视频互动 :直播(1路流)
+ApeConsts.CLASS_TYPE_XIAOBAN = 3; // 小班课,通过CDN转发音视频,不能进行音视频互动 ::小班课(可以多路流)
 
 //角色身份
 //ApeConsts.NR_GUEST = 0; // 客人
diff --git a/src/apes/AudioApe.js b/src/apes/AudioApe.js
index 626bc3b..16c10fc 100644
--- a/src/apes/AudioApe.js
+++ b/src/apes/AudioApe.js
@@ -410,7 +410,7 @@ class AudioApe extends Ape {
       receiveChannelInfo.mediaType = unpackChannelInfo.mediaType || ApeConsts.MEDIA_TYPE_DEFAULT;
       receiveChannelInfo.screenWidth = unpackChannelInfo.screenWidth || GlobalConfig.screenWidth;
       receiveChannelInfo.screenHeight = unpackChannelInfo.screenHeight || GlobalConfig.screenHeight;
-      receiveChannelInfo.deviceType = unpackChannelInfo.deviceType || 0;
+      receiveChannelInfo.deviceType = unpackChannelInfo.deviceType || GlobalConfig.devicePC;
       receiveChannelInfo.optionJsonData = unpackChannelInfo.optionJsonData || "";
 
       //消息不是自己同步的,需要处理
diff --git a/src/apes/ConferApe.js b/src/apes/ConferApe.js
index 2788775..8efec74 100644
--- a/src/apes/ConferApe.js
+++ b/src/apes/ConferApe.js
@@ -23,7 +23,7 @@ class ConferApe extends Ape {
       ApeConsts.CONFERENCE_SESSION_NAME,
       ApeConsts.CONFERENCE_SESSION_TAG
     );
-
+    this.isLeave=false;//记录自己是否已经离开
     this.rosters = {}; //用户列表
     this.rosterLen = 0;//当前课堂人数
     this.timerCounter = new TimerCounter(); //计时器
@@ -160,7 +160,7 @@ class ConferApe extends Ape {
 
   //更新角色数据
   updateUserInfo() {
-    if(GlobalConfig.classType==ApeConsts.CLASS_TYPE_2&&GlobalConfig.isH5==true){
+    if(GlobalConfig.classType==ApeConsts.CLASS_TYPE_ZHIBO&&GlobalConfig.isH5==true){
       //直播模式下H5不处理更新信息
       console.log("直播模式下H5不处理用户更新信息");
       return;
@@ -207,7 +207,7 @@ class ConferApe extends Ape {
       }
       return;
     }
-    if(GlobalConfig.classType==ApeConsts.CLASS_TYPE_2&&GlobalConfig.isH5){
+    if(GlobalConfig.classType==ApeConsts.CLASS_TYPE_ZHIBO&&GlobalConfig.isH5){
       loger.warn("直播模式H5不能发送课堂控制消息");
       return;
     }
@@ -308,7 +308,7 @@ class ConferApe extends Ape {
   checkHasRecordControl() {
     //loger.warn('检测是否有控制录制操作的权限', "isHost", GlobalConfig.isHost, "recordStatus", GlobalConfig.recordStatus,"当前人数:"+this.rosterLen);
     //1.如果自己是老师或者当前课堂只有一个人
-    if (GlobalConfig.isHost || (this.rosterLen <= 1&&GlobalConfig.deviceType!=3)) {
+    if (GlobalConfig.isHost || (this.rosterLen <= 1&&GlobalConfig.deviceType!=GlobalConfig.deviceH5)) {
       return true;
     }
     //2.如果自己不是老师,需要判断当前课堂内是否有老师,如果有老师就不做操作
@@ -1022,7 +1022,7 @@ class ConferApe extends Ape {
       this.rosterLen = Object.keys(this.rosters).length;
       GlobalConfig.rosterNumber = this.rosterLen;//记录当前的总人数
       newNodeData.rosterLen = this.rosterLen;
-      if(GlobalConfig.classType!= ApeConsts.CLASS_TYPE_2){
+      if(GlobalConfig.classType!= ApeConsts.CLASS_TYPE_ZHIBO){
         loger.log("人员加入->", newNodeData);
       }
 
@@ -1034,7 +1034,7 @@ class ConferApe extends Ape {
       GlobalConfig.rosterNumber = this.rosterLen;//记录当前的总人数
       newNodeData.rosterLen = this.rosterLen;
       if (nodeId != GlobalConfig.nodeId) {
-        if(GlobalConfig.classType!= ApeConsts.CLASS_TYPE_2){
+        if(GlobalConfig.classType!= ApeConsts.CLASS_TYPE_ZHIBO){
           loger.log("人员更新信息->", newNodeData);
         }
       }
@@ -1065,7 +1065,7 @@ class ConferApe extends Ape {
       // 因为会出现先收到视频消息后收到人员加入和更新的消息
       if(this.rosters[_param.fromNodeId] == null&&this.rosterLen>0){
         //H5不做释放处理
-        if(GlobalConfig.deviceType==3){
+        if(GlobalConfig.deviceType==GlobalConfig.deviceH5){
           loger.warn("H5不做媒体模块的频道释放->当前总人数->"+this.rosterLen, _param);
           return ;
         }
@@ -1084,8 +1084,9 @@ class ConferApe extends Ape {
   //删除用户
   rosterDelHandler(nodeId) {
     if (GlobalConfig.nodeId == nodeId) {
-      if(GlobalConfig.classExit==false){
-        loger.log("自己离开课堂");
+      if(GlobalConfig.classExit==false||this.isLeave==false){
+        this.isLeave=true;
+        loger.log("自己离开课堂","classExit:"+GlobalConfig.classExit);
         // 自己退出
         this._emit(MessageTypes.CLASS_RUN_EXIT, {'type': 0});
       }
@@ -1094,7 +1095,7 @@ class ConferApe extends Ape {
     } else {
       let user = this.rosters[nodeId];
       if (user) {
-        if(GlobalConfig.classType!= ApeConsts.CLASS_TYPE_2){
+        if(GlobalConfig.classType!= ApeConsts.CLASS_TYPE_ZHIBO){
           loger.log(nodeId, "->离开课堂->身份->", user.userRole);
         }
 
@@ -1204,6 +1205,7 @@ class ConferApe extends Ape {
     this.rosterLen = 0;
     GlobalConfig.rosterNumber = this.rosterLen;
     GlobalConfig.rosters = this.rosters;
+    this.isLeave=true;
   }
 
 }
diff --git a/src/apes/VideoApe.js b/src/apes/VideoApe.js
index 9be89e9..d24f3ce 100644
--- a/src/apes/VideoApe.js
+++ b/src/apes/VideoApe.js
@@ -20,7 +20,7 @@ class VideoApe extends Ape {
       ApeConsts.VIDEO_SESSION_NAME,
       ApeConsts.VIDEO_SESSION_TAG
     );
-
+    this.isLeave=false;
     this.mediaModule = new MediaModule();
     this.mediaModule.MEDIA_OBJ_TABLE_ID = ApeConsts.VIDEO_OBJ_TABLE_ID;
     this.mediaModule.mediaChannels = {};
@@ -37,7 +37,6 @@ class VideoApe extends Ape {
     // Ape Models
     this.registerKey(this._session_id, this._session_name, this._session_tag, new ArrayBuffer);
     this.registerObj(pdu.RCPDU_REG_REGISTER_TABLE, ApeConsts.VIDEO_OBJ_TABLE_ID, ApeConsts.VIDEO_OBJ_TABLE_NAME, ApeConsts.VIDEO_OBJ_TABLE_TAG, 0, new ArrayBuffer);
-
     // videoApe 监听视频控制消息,用户之间的消息传递
     this.on(pdu.RCPDU_SEND_VIDEO_DATA_REQUEST, this.receiveVideoCommandHandler.bind(this));
   }
@@ -425,7 +424,7 @@ class VideoApe extends Ape {
     this.sendTableUpdateHandler(channelInfo);
     //递归检查,800毫秒之后执行
     clearTimeout(this.releaseTimeId);
-    if(GlobalConfig.classType==ApeConsts.CLASS_TYPE_2&&GlobalConfig.isH5){
+    if(GlobalConfig.classType==ApeConsts.CLASS_TYPE_ZHIBO&&GlobalConfig.isH5){
       return;
     }
     this.releaseTimeId = setTimeout(function () {
@@ -498,6 +497,11 @@ class VideoApe extends Ape {
   //发送到mcu同步(更新数据)
   sendTableUpdateHandler(_channelInfo) {
     //loger.log("video===sendTableUpdateHandler ");
+    if(GlobalConfig.classExit||this.isLeave){
+      //已经离开课堂就不再做处理
+      return;
+    }
+
     let updateModelPdu = this.packPdu(_channelInfo, _channelInfo.channelId);//let updateModelPdu=this.packPdu({},ApeConsts.VIDEO_OBJ_TABLE_ID+2);
 
     if (updateModelPdu == null) {
@@ -662,7 +666,7 @@ class VideoApe extends Ape {
       receiveChannelInfo.mediaType = unpackChannelInfo.mediaType || ApeConsts.MEDIA_TYPE_DEFAULT;
       receiveChannelInfo.screenWidth = unpackChannelInfo.screenWidth || GlobalConfig.screenWidth;
       receiveChannelInfo.screenHeight = unpackChannelInfo.screenHeight || GlobalConfig.screenHeight;
-      receiveChannelInfo.deviceType = unpackChannelInfo.deviceType || 0;
+      receiveChannelInfo.deviceType = unpackChannelInfo.deviceType || GlobalConfig.devicePC;
       receiveChannelInfo.optionJsonData = unpackChannelInfo.optionJsonData || "";
       //消息不是自己同步的,需要处理
       if (unpackChannelInfo.status == ApeConsts.CHANNEL_STATUS_OPENING) {
@@ -782,7 +786,7 @@ class VideoApe extends Ape {
     mediaChannelInfo.mediaType = _param.mediaType || ApeConsts.MEDIA_TYPE_DEFAULT;
     mediaChannelInfo.screenWidth = _param.screenWidth || GlobalConfig.screenWidth;
     mediaChannelInfo.screenHeight = _param.screenHeight || GlobalConfig.screenHeight;
-    mediaChannelInfo.deviceType = _param.deviceType || 0;
+    mediaChannelInfo.deviceType = _param.deviceType || GlobalConfig.devicePC;
     mediaChannelInfo.optionJsonData = _param.optionJsonData || "";
     mediaChannelInfo.m3u8Url = "";
     mediaChannelInfo.rtmpUrl = "";
@@ -884,6 +888,9 @@ class VideoApe extends Ape {
     }
     return null;
   }
+  stopApe(){
+    this.isLeave=true;
+  }
 }
 
 export default VideoApe;
diff --git a/src/apes/WebRtcApe.js b/src/apes/WebRtcApe.js
index 4470837..0634b5d 100644
--- a/src/apes/WebRtcApe.js
+++ b/src/apes/WebRtcApe.js
@@ -245,7 +245,7 @@ class WebRtcApe extends Emiter {
           $("#"+this.xdyRemote + uid).remove();
         }
       }
-      if (user && (user.deviceType == 1 || user.deviceType == 2)) {
+      if (user && (user.deviceType == GlobalConfig.deviceIOS || user.deviceType == GlobalConfig.deviceAndroid)) {
         this.remoteVideoList[user.nodeId] = stream;
       }
     }
diff --git a/src/mcu.js b/src/mcu.js
index 60d385e..a922485 100644
--- a/src/mcu.js
+++ b/src/mcu.js
@@ -105,7 +105,7 @@ class MCU extends Emiter {
     pduMsg.set("deviceType", "" + GlobalConfig.deviceType);
     pduMsg.set("data", joinRequestPdu.toArrayBuffer());
 
-    this._everSocket.send(pduMsg.toArrayBuffer());
+    this._everSocket.send(pduMsg.toArrayBuffer(),joinRequestPdu.type);
   }
 
   // EverSocket底层消息处理
@@ -197,7 +197,7 @@ class MCU extends Emiter {
   send(msg) {
     if (this.connected) {
      // loger.log('发送数据到服务端-------------------->');
-      this._everSocket.send(msg.toArrayBuffer());
+      this._everSocket.send(msg.toArrayBuffer(),msg.type);
     } else {
       loger.warn('发送数据到服务端-------------------->失败->未连接到服务端');
       this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_SOCKET_DISCONNECT);
@@ -209,7 +209,9 @@ class MCU extends Emiter {
     loger.log('leaveMCU');
     GlobalConfig.setCurrentStatus(GlobalConfig.statusCode_3);
     GlobalConfig.classJoinSuccess = false;
-    this._everSocket.end();
+    if( this._everSocket){
+      this._everSocket.end();
+    }
   }
 
   // 主动建立MCU连接
@@ -223,9 +225,15 @@ class MCU extends Emiter {
     loger.log(_classInfo);
     _classInfo.classId = parseInt(_classInfo.classId); // classId 必须整形
     this.classInfo = _classInfo;
+
     // 创建刷新nodeId
-    this.classInfo.nodeId = EngineUtils.creatSoleNumberFromTimestamp();
+    let randNodeId =parseInt(Math.random()*1000)+""+parseInt(Math.random()*1000)+""+parseInt(Math.random()*1000);
+    //生成的字符串nodeId转换为数字
+    randNodeId=parseInt(randNodeId);
+
+    this.classInfo.nodeId =randNodeId; //EngineUtils.creatSoleNumberFromTimestamp();
     GlobalConfig.nodeId = this.classInfo.nodeId; //这是标识自己身份的id
+    console.log("创建nodeId",GlobalConfig.nodeId);
 
     let nodeInfoRecordPdu = new pdu['RCNodeInfoRecordPdu'];
     nodeInfoRecordPdu.name = this.classInfo.userName;
--
libgit2 0.24.0