diff --git a/src/EngineEntrance.js b/src/EngineEntrance.js
index 82f5f49..e0d3e18 100644
--- a/src/EngineEntrance.js
+++ b/src/EngineEntrance.js
@@ -59,7 +59,7 @@ export default class MessageEntrance extends Emiter {
   constructor() {
     super();
     //sdk 信息
-    GlobalConfig.sdkVersion = "v2.1.22.20170904";
+    GlobalConfig.sdkVersion = "v2.2.7.20170904";
     loger.warn("sdkVersion:" + GlobalConfig.sdkVersion);
 
     //设置
@@ -131,8 +131,10 @@ export default class MessageEntrance extends Emiter {
     _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_UPDATE_ROSTER, this._onClassUpdateRoster.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)); //课堂开启录制成功
 
@@ -277,6 +279,7 @@ export default class MessageEntrance extends Emiter {
     //webrtc
     this.publishMedia=this._publishMedia.bind(this);
     this.unpublishMedia=this._unpublishMedia.bind(this);
+    this.changeDevices=this._changeDevices.bind(this);
     this.setLocalMediaView=this._setLocalMediaView.bind(this);
     this.setRemoteMediaView=this._setRemoteMediaView.bind(this);
     this.setInvisibleMediaView=this._setInvisibleMediaView.bind(this);
@@ -469,10 +472,25 @@ export default class MessageEntrance extends Emiter {
     }
   }
 
-  //有人员离开
+  //人员离开
   _onClassDeleteRoster(_data) {
 
   }
+  //人员更新
+  _onClassUpdateRoster(_data){
+    if(!_data){
+      return;
+    }
+    if(GlobalConfig.deviceType==1||GlobalConfig.deviceType==2||_data.nodeId==GlobalConfig.nodeId){
+      return;
+    }
+    if(_webRtc){
+      let user=GlobalConfig.rosters[_data.nodeId];
+      if(user&&user.openCamera==0){
+        _webRtc.closeRemoteVideoView(_data);
+      }
+    }
+  }
 
   //当前课堂中视频或音频占用channel的nodeId ,在人员列表中不存在,这种情况是占用channel的人员掉线或离开的时候没有释放channel
   //的占用状态导致,对于这种情况,需要释放掉
@@ -1544,6 +1562,13 @@ export default class MessageEntrance extends Emiter {
       return {"code": ApeConsts.RETURN_FAILED, "data": ""};
     }
 
+    //离开视频通话频道
+    if(GlobalConfig.deviceType==0||GlobalConfig.deviceType==3){
+      if(_webRtc){
+        _webRtc.leaveChannel();;
+      }
+    }
+
     //停止推流
     if (_video_ape) {
       _video_ape.stopPublishVideo();
@@ -1704,10 +1729,16 @@ export default class MessageEntrance extends Emiter {
         loger.warn("开启录制回放流程失败->还未创建模块");
       }
     } else {
+
+      //初始化音视频通话sdk
+      this._initWebRtcSdk(null,()=>{
+        //音视频通话SDK初始化完成之后,根据用户的userIp获取信息,获取服务列表选点,选点测速完成后才加入MCU
+        this.loadServerJsonAndgetUserIpInfo();
+      });
+     /*
       //根据用户的userIp获取信息,获取服务列表选点,选点测速完成后才加入MCU
       this.loadServerJsonAndgetUserIpInfo();
-      //初始化音视频通话sdk
-      this._initWebRtcSdk();
+      */
     }
   }
 
@@ -2581,13 +2612,26 @@ export default class MessageEntrance extends Emiter {
   /*
   * 初始化webRtc
   * */
-  _initWebRtcSdk(_params){
+  _initWebRtcSdk(_params,_callback){
     if(GlobalConfig.deviceType==1||GlobalConfig.deviceType==2){
       loger.warn("移动端不需要处理初始化webRtc");
+      if(_callback){
+        _callback();
+      }
       return ;
     }
     if(_webRtc){
-      _webRtc.initApp(_params)
+      _webRtc.initApp(_params,(_callbackData)=>{
+        //_callback({isSuccess:false,error:err});
+        if(_callbackData&&_callbackData.isSuccess==true){
+          this._emit(MessageTypes.WEB_RTC_INIT_SUCCESS,_callbackData);
+        }else {
+          this._emit(MessageTypes.WEB_RTC_INIT_FAILED,_callbackData);
+        }
+        if(_callback){
+          _callback();
+        }
+      });
     }
   }
   /*
@@ -2661,18 +2705,26 @@ export default class MessageEntrance extends Emiter {
       _webRtc.unpublish(_params);
     }
   }
+
   /*
-  * 获取设备信息
-  * */
-  _getDevices(_params, _callback){
+   * 切换摄像头和麦克风设备
+   * */
+  _changeDevices(_params){
+    if(GlobalConfig.deviceType==1||GlobalConfig.deviceType==2){
+      return;
+    }
     if(_webRtc){
-      _webRtc.getDevices(_params,_callback);
+      _webRtc.changeDevices(_params);
     }
   }
+
   /*
   * 设置本地video视图
   * */
   _setLocalMediaView(_params){
+    if(GlobalConfig.deviceType==1||GlobalConfig.deviceType==2){
+      return;
+    }
     if(_webRtc){
       _webRtc.setLoaclView(_params);
     }
@@ -2681,6 +2733,9 @@ export default class MessageEntrance extends Emiter {
   * 设置房间内其他人的视图
   * */
   _setRemoteMediaView(_params){
+    if(GlobalConfig.deviceType==1||GlobalConfig.deviceType==2){
+      return;
+    }
    if(_webRtc){
       _webRtc.setRemoteView(_params);
     }
@@ -2689,6 +2744,9 @@ export default class MessageEntrance extends Emiter {
   * 设置监课和需要隐藏显示的用户视图
   * */
   _setInvisibleMediaView(_params){
+    if(GlobalConfig.deviceType==1||GlobalConfig.deviceType==2){
+      return;
+    }
     if(_webRtc){
       _webRtc.setInvisibleMediaView(_params);
     }
diff --git a/src/MessageTypes.js b/src/MessageTypes.js
index 3d4498b..31a9b01 100644
--- a/src/MessageTypes.js
+++ b/src/MessageTypes.js
@@ -103,6 +103,15 @@ MessageTypes.UPDATE_QUESTION_TIME = "update_question_time"; //更新答题时间
 //白板笔记事件定义
 MessageTypes.WHITEBOARD_ANNOTATION_UPDATE = "whiteboard_annotation_update"; // 'whiteboard.annotation.update';
 
+//webRtc
+MessageTypes.WEB_RTC_INIT_SUCCESS = "web_rtc_init_success";
+MessageTypes.WEB_RTC_INIT_FAILED = "web_rtc_init_failed";
+MessageTypes.WEB_RTC_JOIN_SUCCESS = "web_rtc_join_success";
+MessageTypes.WEB_RTC_JOIN_FAILED = "web_rtc_join_failed";
+MessageTypes.WEB_RTC_PUBLISH_FAILED = "web_rtc_publish_failed";
+MessageTypes.GET_DEVICES_SUCCESS = "get_devices_success";
+
+
 //MCU MS
 MessageTypes.SWITCH_MCU_IP = "switch_mcu_ip"; //切换mcu 重新选点
 MessageTypes.SWITCH_MS_IP = "switch_ms_ip"; //切换ms 重新选点
diff --git a/src/apes/WebRtcApe.js b/src/apes/WebRtcApe.js
index 8c3a9f1..3f4cfba 100644
--- a/src/apes/WebRtcApe.js
+++ b/src/apes/WebRtcApe.js
@@ -28,11 +28,14 @@ class WebRtcApe extends Emiter {
     this.localStream = null;
     this.cameras = [];
     this.microphones = [];
-    this.curCamera = "";
-    this.curMicrophone = "";
+    this.curCameraId = "";
+    this.curMicrophoneId = "";
+
     this.videoResolution = "240P";
     this.isOpenVideo = true;
 
+    this.isPublish=false;//当前是否正在推流
+
     this.localViewId = "";
     this.localStyle = "";
 
@@ -45,10 +48,20 @@ class WebRtcApe extends Emiter {
     this.xdyRemote = "xdy_remote";
     //webRtc sdk
     this.client = AgoraRTC.createClient({mode: this.mode});
-    this.getDevices();
+
+    this.getDevices(null,(devices)=>{
+      if (this.cameras && this.cameras.length > 0) {
+        this.curCameraId = this.cameras[0].deviceId || "";
+        GlobalConfig.curCamera =this.cameras[0].label || "";
+      }
+      if (this.microphones && this.microphones.length > 0) {
+        this.curMicrophoneId = this.microphones[0].deviceId || "";
+        GlobalConfig.curMicrophone = this.microphones[0].label || "";
+      }
+    });
   }
 
-  initApp(_params) {
+  initApp(_params,_callback) {
     loger.log("初始化WebRtc");
     if (_params) {
       this.appId = _params.appId;
@@ -56,9 +69,14 @@ class WebRtcApe extends Emiter {
     if (this.client) {
       this.client.init(this.appId, () => {
         loger.log("初始化WebRtc->成功");
+        if(_callback){
+          _callback({isSuccess:true});
+        }
       }, (err)=> {
         loger.error("初始化WebRtc->失败", err);
-
+        if(_callback){
+          _callback({isSuccess:false,error:err});
+        }
       });
       this.addEvent();
     }
@@ -93,14 +111,18 @@ class WebRtcApe extends Emiter {
 
     this.client.on('stream-subscribed', (evt)=> {
       let stream = evt.stream;
-      loger.log("Subscribe remote stream successfully: " + stream.getId());
-      if(GlobalConfig.getUserRoleFromeNodeId(stream.getId())==ApeConsts.invisible){
-        //显示隐藏用户
-        $(this.invisibleViewId).append('<div id="' + this.xdyRemote + stream.getId() + '" style="float:left; width:320px;height:240px;"></div>');
-      }else {
-        $(this.remoteViewId).append('<div id="' + this.xdyRemote + stream.getId() + '" style="float:left; width:320px;height:240px;"></div>');
+      if(stream){
+        loger.log("获取远程视频流成功: " + stream.getId());
+        let viewDiv=`<div id="${this.xdyRemote + stream.getId()}" style="width:320px;height:240px;"></div>`;
+        if(GlobalConfig.getUserRoleFromeNodeId(stream.getId())==ApeConsts.invisible){
+          //显示隐藏用户
+          $(this.invisibleViewId).append(viewDiv);
+        }else {
+          $(this.remoteViewId).append(viewDiv);
+        }
+        stream.play(this.xdyRemote + stream.getId());
       }
-      stream.play('' + this.xdyRemote + stream.getId());
+
     });
 
     this.client.on('stream-removed', (evt)=> {
@@ -134,25 +156,45 @@ class WebRtcApe extends Emiter {
     this.client.join(this.channelKey , ""+this.channelId, this.uid, (uid)=> {
       this.uid = uid;
       loger.log("加入视频通话频道->成功->channelId:"+this.channelId,"uid:"+this.uid);
+      this._emit(MessageTypes.WEB_RTC_JOIN_SUCCESS);
       this.openLoaclStream();
     }, (err)=> {
-      loger.log("加入视频通话频道->失败->", err);
+      loger.error("加入视频通话频道->失败->", err);
+      this._emit(MessageTypes.WEB_RTC_JOIN_FAILED);
     });
   }
+  //重新获取摄像头和麦克风并重新推流
+  reGetLoaclStream(){
+    if(this.isPublish){
+      loger.log("重新获取摄像头和麦克风并重新推流");
+      this.unpublish();
+      this.openLoaclStream();
+      //切换设备后自动重推流
+      this.rePublishDelay=setTimeout(()=>{
+        this.publish();
+      },1200);
+      this.publish();
+    }else {
+      this.openLoaclStream();
+    }
+  }
 
   openLoaclStream() {
-    loger.log("摄像头", this.curCamera);
-    loger.log("麦克风", this.curMicrophone);
+   /* if(this.localStream){
+      this.localStream.close();
+      this.localStream=null;
+    }*/
     this.localStream = AgoraRTC.createStream({
       streamID: this.uid,
       audio: true,
-      microphoneId: this.curMicrophone,
-      cameraId: this.curCamera,
+      microphoneId: this.curMicrophoneId,
+      cameraId: this.curCameraId,
       video: this.isOpenVideo,
       screen: false
     });
 
     if (this.isOpenVideo) {
+      //设置分辨率
       this.localStream.setVideoProfile(this.videoResolution);
     }
   }
@@ -162,26 +204,41 @@ class WebRtcApe extends Emiter {
     if (!this.client) {
       return;
     }
-    this.client.leaveChannel(() => {
-      loger.log("Leavel channel successfully");
+    this.client.leave(() => {
+      loger.log("离开视频通话频道->成功");
     }, (err)=> {
-      loger.log("Leave channel failed");
+      loger.log("离开视频通话频道->失败");
     });
   }
 
-  publish() {
+  closeRemoteVideoView(_data){
+    if(!_data){
+      return;
+    }
+    //根据nodeId查找视频
+    try{
+      loger.log("立即删除停止推流人员的视图");
+      $('#' + this.xdyRemote + _data.nodeId).remove();
+    }catch (err){
+
+    }
+
+  }
+  publish(_params) {
     if (!this.client||!this.localStream) {
       return;
     }
     this.localStream.init(()=> {
-      loger.log("webRtc->推流: ");
       let viewName = this.localViewId.replace("#", "");
+      loger.log("webRtc->推流->",viewName);
       this.localStream.play(viewName);
       this.client.publish(this.localStream, (err)=> {
         loger.log("webRtc->推流失败: " + err);
         GlobalConfig.openCamera =0;
         GlobalConfig.openMicrophones =0;
+        this.isPublish=false;
       });
+      this.isPublish=true;
       GlobalConfig.openCamera = EngineUtils.creatTimestamp();
       GlobalConfig.openMicrophones = GlobalConfig.openCamera;
 
@@ -195,11 +252,13 @@ class WebRtcApe extends Emiter {
       });
 
     }, (err)=> {
-      loger.log("webRtc->推流->本地流开启失败", err);
+      loger.error("webRtc->推流->本地流开启失败", err);
+      this._emit(MessageTypes.WEB_RTC_PUBLISH_FAILED,err);
     });
   }
 
   unpublish() {
+    clearTimeout(this.rePublishDelay);
     loger.log("webRtc->停止推流 ");
     if (!this.client||!this.localStream) {
       return;
@@ -209,6 +268,7 @@ class WebRtcApe extends Emiter {
     });
     this.localStream.close();
     $(this.localViewId).html("");
+    this.isPublish=false;
     GlobalConfig.openCamera =0;
     GlobalConfig.openMicrophones =0;
     this._emit(MessageTypes.USER_DEVICE_STATUS_CHAANGE, {
@@ -247,29 +307,80 @@ class WebRtcApe extends Emiter {
     this.invisibleViewId = _params.divId||"";
     this.invisibleStyle = _params.styleStr||"";
   }
+  /*
+  * 切换当前使用的设备
+  * */
+  changeDevices(_params){
+    loger.log("切换设备->",_params);
+    if(!_params){
+      return;
+    }
+    //设置摄像头
+    if(_params.curCamera){
+      for(let k in this.cameras){
+        let item=this.cameras[k];
+        if(item&&item.label==_params.curCamera){
+          this.curCameraId=item.deviceId;
+          GlobalConfig.curCamera=_params.curCamera;
+          break;
+        }
+      }
+    }
+    //设置麦克风
+    if(_params.curMicrophone){
+      for(let k in this.microphones){
+        let item=this.microphones[k];
+        if(item&&item.label==_params.curMicrophone){
+          this.curMicrophoneId=item.deviceId;
+          GlobalConfig.curMicrophone=_params.curMicrophone;
+          break;
+        }
+      }
+    }
+    //分辨率
+    if(_params.videoResolution){
+      this.videoResolution=_params.videoResolution||"240P";//默认是240P 	20	320x240	15	200
+    }
+
+    clearTimeout(this.changeDevicesDelay);
+    this.changeDevicesDelay=setTimeout(()=>{
+      //重新获取本地视图流
+      this.reGetLoaclStream();
+    },1400);
+  }
 
+  /*
+  * 获取设备信息
+  * */
   getDevices(_params,_callback) {
     AgoraRTC.getDevices((devices)=> {
-      console.log("devices", devices)
+      //下面的数组存的是对象
+      this.microphones=[];
+      this.cameras=[];
+
+      //选的数组存的是设备名称
+      GlobalConfig.cameras=[];
+      GlobalConfig.microphones=[];
+
+      loger.log("devices", devices)
       for (let i = 0; i < devices.length; i++) {
         let device = devices[i];
-        if (device.kind === 'audioinput') {
+        //{"deviceId":"default","kind":"audiooutput","label":"默认","groupId":"cf49a03ca26700235629fc13d3e6630bd34407c66438d157056a34dd3ae03ef5"}
+        if (device.kind == 'audioinput') {
           this.microphones.push(device);
-        } else if (device.kind === 'videoinput') {
+          GlobalConfig.microphones.push(device.label);
+        } else if (device.kind == 'videoinput') {
           this.cameras.push(device);
+          GlobalConfig.cameras.push(device.label);
         } else {
-          loger.warn('未知的设备: ', device);
+          loger.warn('其他设备: ', device);
         }
       }
-      if (this.cameras && this.cameras.length > 0) {
-        this.curCamera = this.cameras[0].deviceId || "";
-      }
-      if (this.microphones && this.microphones.length > 0) {
-        this.curMicrophone = this.microphones[0].deviceId || "";
-      }
+      let _deviceData={cameras:GlobalConfig.cameras,microphones:GlobalConfig.microphones};
       if(_callback){
-        _callback({cameras:this.cameras,microphones:this.microphones});
+        _callback(_deviceData);
       }
+      this._emit(MessageTypes.GET_DEVICES_SUCCESS,_deviceData);
     });
   }
 }