From 283bfd10663dd65ab0ed7ecb9efcdc474eb591d6 Mon Sep 17 00:00:00 2001
From: liyong <liyong@3mang.com>
Date: Fri, 29 Sep 2017 15:51:27 +0800
Subject: [PATCH] 1.新增控制webRtc模块视频窗口缩放的接口,在课堂信息中增加字段videoScale 这个是视频的缩放倍数;

---
 src/EngineEntrance.js |  27 ++++++++++++++++++++++++++-
 src/GlobalConfig.js   |   5 +++++
 src/apes/ConferApe.js | 310 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 src/apes/WebRtcApe.js |  71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 src/pdus/pro.js       |   1 +
 5 files changed, 195 insertions(+), 219 deletions(-)

diff --git a/src/EngineEntrance.js b/src/EngineEntrance.js
index 8178735..d54b9da 100644
--- a/src/EngineEntrance.js
+++ b/src/EngineEntrance.js
@@ -62,7 +62,7 @@ export default class MessageEntrance extends Emiter {
   constructor() {
     super();
     //sdk 信息
-    GlobalConfig.sdkVersion = "v2.14.5.20170927";
+    GlobalConfig.sdkVersion = "v2.15.3.20170929";
     loger.warn("sdkVersion:" + GlobalConfig.sdkVersion);
 
     //设置
@@ -297,6 +297,7 @@ export default class MessageEntrance extends Emiter {
     this.setAppConfig=this._setAppConfig.bind(this);
     this.recordControl=this._mediaRecordControl.bind(this);
 
+    this.changeRtcVideoConfig=this._changeRtcVideoConfig.bind(this);//设置webRtc视频视图的缩放
 
     this.setDeviceInfo = this._setDeviceInfo.bind(this); //设置设备信息(麦克风,摄像头等等.....)
     this.setMessageDelay = this._setMessageDelay.bind(this); //设置是否延迟消息
@@ -2916,6 +2917,30 @@ export default class MessageEntrance extends Emiter {
   }
 
   /*
+  * 设置RTC视频属性
+  * */
+  _changeRtcVideoConfig(_params){
+    loger.log("设置RTC视频属性",_params);
+    if(!_params){
+      return;
+    }
+    if(GlobalConfig.deviceType==1||GlobalConfig.deviceType==2){
+      return;
+    }
+    if(_webRtc){
+      _webRtc.changeRtcVideoConfig(_params);
+
+      //如果是老师操作,需要同步给所有人
+      if(GlobalConfig.isHost){
+        if(_confer_ape){
+          GlobalConfig.videoScale=_params.videoScale||1;
+          _confer_ape.sendUpdaterClassStatusInfo({videoScale:_params.videoScale});
+        }
+      }
+    }
+  }
+
+  /*
   * 设置监课和需要隐藏显示的用户视图
   * */
   _setInvisibleMediaView(_params){
diff --git a/src/GlobalConfig.js b/src/GlobalConfig.js
index 5dc9a63..febc847 100644
--- a/src/GlobalConfig.js
+++ b/src/GlobalConfig.js
@@ -101,6 +101,7 @@ class GlobalConfig {
 
       classStatusInfo.currentSceneTableId = this.currentSceneTableId; //文档区域的模块显示
       classStatusInfo.serverAndLoacTimeDistanc = this.serverAndLoacTimeDistanc;
+      classStatusInfo.videoScale=this.videoScale;
       return classStatusInfo;
     }
     //设置当前的课堂状态的信息
@@ -148,6 +149,7 @@ class GlobalConfig {
     this.currentSceneTableId = data.currentSceneTableId || 0; //文档区域的模块显示
 
     this.isEnableDraw=data.isEnableDraw||false;//是否开启所有人的绘制权限
+    this.videoScale=parseInt(data.videoScale)||1;
     // 全局禁言状态
     this.silence = data.silence || false;
     this.silenceUsers =data.silenceUsers || {};
@@ -607,5 +609,8 @@ GlobalConfig.stopRecordingInterfaces="";//停止录制的接口
 GlobalConfig.getTxRecordInfoInterfaces="";//获取媒体录制信息数据的接口(tx)
 
 GlobalConfig.getChannelToken="";//获取token的地址
+
+GlobalConfig.videoScale=1;//视频的缩放倍数,默认1倍无缩放
+
 export default GlobalConfig;
 
diff --git a/src/apes/ConferApe.js b/src/apes/ConferApe.js
index 8aec0a2..0007e84 100644
--- a/src/apes/ConferApe.js
+++ b/src/apes/ConferApe.js
@@ -130,7 +130,7 @@ class ConferApe extends Ape {
     nodeInfoRecordPdu.city = GlobalConfig.city; //城市
     nodeInfoRecordPdu.province = GlobalConfig.province; //服务商
     nodeInfoRecordPdu.isp = GlobalConfig.isp; //服务商
-    nodeInfoRecordPdu.msList=[];
+    nodeInfoRecordPdu.msList = [];
     //用户的MS列表
     let msListAll = GlobalConfig.msListFinal;
     for (let k = 0; k < msListAll.length; k++) {
@@ -257,10 +257,10 @@ class ConferApe extends Ape {
     //conferRecordSendPdu.classTime = GlobalConfig.classTimestamp;//不能使用课堂进行时间,这个时间结束课堂的时候会被清除
     conferRecordSendPdu.classTime = GlobalConfig.recordTimestamp; //课堂录制的累积时间,不会被清除
     conferRecordSendPdu.filename = GlobalConfig.recordFileName || GlobalConfig.classId + "_" + EngineUtils.creatTimestampYMD() + ".rec";
-    if(GlobalConfig.recordStatus){
-      loger.log("发送录制的指令->开启",conferRecordSendPdu);
-    }else {
-      loger.log("发送录制的指令->停止",conferRecordSendPdu);
+    if (GlobalConfig.recordStatus) {
+      loger.log("发送录制的指令->开启", conferRecordSendPdu);
+    } else {
+      loger.log("发送录制的指令->停止", conferRecordSendPdu);
     }
     this.sendChatUniform(conferRecordSendPdu);
   }
@@ -273,64 +273,65 @@ class ConferApe extends Ape {
       return;
     }
     //如果已经开始录制就不再开启
-    if(GlobalConfig.recordStatus&&this.rosterLen>1){
-      loger.warn('目前已经是录制状态->当前课堂人数:'+this.rosterLen);
+    if (GlobalConfig.recordStatus && this.rosterLen > 1) {
+      loger.warn('目前已经是录制状态->当前课堂人数:' + this.rosterLen);
       return false;
     }
     //如果是host或者当前课堂只有1个人
     if (this.checkHasRecordControl()) {
-        loger.warn('开启录制', "isHost", GlobalConfig.isHost, "recordStatus", GlobalConfig.recordStatus,"当前人数:"+this.rosterLen);
+      loger.warn('开启录制', "isHost", GlobalConfig.isHost, "recordStatus", GlobalConfig.recordStatus, "当前人数:" + this.rosterLen);
       //如果录制的文件名不存在,需要创建一个名字
       let timestampYMD = EngineUtils.creatTimestampYMD();
-      if(!GlobalConfig.recordFileName){
-        GlobalConfig.recordFileName=GlobalConfig.siteId + "/" + timestampYMD + "/" + GlobalConfig.classId + "_" + timestampYMD + ".rec"; //4、文件名称 $RECORD_HOME/`site id`/`日期`/`filename`    例:/data/record/su/20161216/`filename`
+      if (!GlobalConfig.recordFileName) {
+        GlobalConfig.recordFileName = GlobalConfig.siteId + "/" + timestampYMD + "/" + GlobalConfig.classId + "_" + timestampYMD + ".rec"; //4、文件名称 $RECORD_HOME/`site id`/`日期`/`filename`    例:/data/record/su/20161216/`filename`
       }
       GlobalConfig.classStopTime = EngineUtils.creatTimestampStr();
-        this.sendConferRecordMsg({"recordStatus": true});
-        this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE);
-        this._emit(MessageTypes.CLASS_RECORD_START); //课堂开始录制
+      this.sendConferRecordMsg({"recordStatus": true});
+      this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE);
+      this._emit(MessageTypes.CLASS_RECORD_START); //课堂开始录制
     }
   }
 
   //检测是否有控制录制操作的权限
-  checkHasRecordControl(){
+  checkHasRecordControl() {
     //loger.warn('检测是否有控制录制操作的权限', "isHost", GlobalConfig.isHost, "recordStatus", GlobalConfig.recordStatus,"当前人数:"+this.rosterLen);
     //1.如果自己是老师或者当前课堂只有一个人
-    if(GlobalConfig.isHost||this.rosterLen<=1){
+    if (GlobalConfig.isHost || this.rosterLen <= 1) {
       return true;
     }
     //2.如果自己不是老师,需要判断当前课堂内是否有老师,如果有老师就不做操作
-    for(let i in this.rosters){
+    for (let i in this.rosters) {
       //如果就老师就停止
-      let rosterItem=this.rosters[i];
-      if(rosterItem&&rosterItem.userRole==ApeConsts.host){
+      let rosterItem = this.rosters[i];
+      if (rosterItem && rosterItem.userRole == ApeConsts.host) {
         return false;
       }
     }
     //3.课堂内有多个人并且都不是老师,选择一个nodeId最小的来操作
-    for(let k in this.rosters){
+    for (let k in this.rosters) {
       //如果选择的nodeId是自己就有权限,否则没有权限
-      if(k==GlobalConfig.nodeId){
+      if (k == GlobalConfig.nodeId) {
         return true;
-      }else {
+      } else {
         return false;
       }
     }
     return false
   }
+
   //停止录制
   stopRecord(isForce) {
     //判断是否有权限
-    if (this.checkHasRecordControl()){
+    if (this.checkHasRecordControl()) {
       loger.warn('停止录制', "isHost", GlobalConfig.isHost, "recordStatus", GlobalConfig.recordStatus);
       //this.sendUpdaterClassStatusInfo({"actionType":GlobalConfig.classStatus, isStopAllPublishMedia: true});
       this.sendConferMsg({"to": 0, "message": "STOP_ALL_PUBLISH", "actionType": ApeConsts.STOP_ALL_PUBLISH});
-      setTimeout(()=>{
+      setTimeout(()=> {
         GlobalConfig.classStopTime = EngineUtils.creatTimestampStr();
         this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE);
         this.sendConferRecordMsg({"recordStatus": false});
-      },2000);
-    }else {
+      }, 2000);
+    } else {
       loger.warn('没有权限停止录制', "isHost", GlobalConfig.isHost, "recordStatus", GlobalConfig.recordStatus);
     }
   }
@@ -394,8 +395,9 @@ class ConferApe extends Ape {
       loger.warn('学生没有开启禁言的权限');
     }
   }
+
   //全局绘制权限控制
-  changeDrawStatus(params){
+  changeDrawStatus(params) {
     if (!GlobalConfig.isNormal) {
       //同步禁言状态
       if (params && params.isEnableDraw == true) {
@@ -408,12 +410,13 @@ class ConferApe extends Ape {
       loger.warn('学生没有开启绘制的权限');
     }
   }
+
   //控制指定用户的画笔状态
-  changeUserDrawStatus(_param){
+  changeUserDrawStatus(_param) {
     loger.log('控制指定用户的画笔状态->', _param);
     if (_param && _param.isDisEnableDraw == true) {
       //举手
-      GlobalConfig.selfDisEnableDrawTime=EngineUtils.creatTimestamp();//被禁用画笔的时间
+      GlobalConfig.selfDisEnableDrawTime = EngineUtils.creatTimestamp();//被禁用画笔的时间
     } else {
       GlobalConfig.selfDisEnableDrawTime = 0; //取消禁用画笔
     }
@@ -426,12 +429,12 @@ class ConferApe extends Ape {
       let timestamp = EngineUtils.creatTimestampStr();
       GlobalConfig.classStopTime = timestamp;
 
-/*
-      //如果录制的文件名不存在,需要创建一个名字
-      let timestampYMD = EngineUtils.creatTimestampYMD();
-      GlobalConfig.recordFileName = GlobalConfig.recordFileName ||
-        GlobalConfig.siteId + "/" + timestampYMD + "/" + GlobalConfig.classId + "_" + timestampYMD + ".rec"; //4、文件名称 $RECORD_HOME/`site id`/`日期`/`filename`    例:/data/record/su/20161216/`filename`
-*/
+      /*
+       //如果录制的文件名不存在,需要创建一个名字
+       let timestampYMD = EngineUtils.creatTimestampYMD();
+       GlobalConfig.recordFileName = GlobalConfig.recordFileName ||
+       GlobalConfig.siteId + "/" + timestampYMD + "/" + GlobalConfig.classId + "_" + timestampYMD + ".rec"; //4、文件名称 $RECORD_HOME/`site id`/`日期`/`filename`    例:/data/record/su/20161216/`filename`
+       */
 
       if (GlobalConfig.classStatus == ApeConsts.CLASS_STATUS_WAIT) {
         //之前是为开始状态,第一次点开始
@@ -530,25 +533,26 @@ class ConferApe extends Ape {
       console.log(_param);
     }
   }
+
   //控制画笔的使用状态
   controlDrawStatus(_param) {
-      //控制用户的举手状态
-      if (!_param || !_param.nodeId) {
-        loger.log('控制画笔的使用状态->失败->参数错误', _param);
-        return;
-      }
-      let msgObj = {};
-      msgObj.nodeId = _param.nodeId;
-      msgObj.isDisEnableDraw = false;
-      if (_param && _param.isDisEnableDraw == true) {
-        msgObj.isDisEnableDraw = true;
-      }
-      this.sendConferMsg({
-        "to": _param.nodeId,
-        "message": JSON.stringify(msgObj),
-        "actionType": ApeConsts.CLASS_ACTION_DRAW_STATUS_CHANGE
-      });
+    //控制用户的举手状态
+    if (!_param || !_param.nodeId) {
+      loger.log('控制画笔的使用状态->失败->参数错误', _param);
+      return;
+    }
+    let msgObj = {};
+    msgObj.nodeId = _param.nodeId;
+    msgObj.isDisEnableDraw = false;
+    if (_param && _param.isDisEnableDraw == true) {
+      msgObj.isDisEnableDraw = true;
     }
+    this.sendConferMsg({
+      "to": _param.nodeId,
+      "message": JSON.stringify(msgObj),
+      "actionType": ApeConsts.CLASS_ACTION_DRAW_STATUS_CHANGE
+    });
+  }
 
   //控制举手状态
   controlHandUpStatus(_param) {
@@ -589,7 +593,7 @@ class ConferApe extends Ape {
     }
     loger.log('切换文档-媒体-屏幕模块切换->', _param);
     //如果是host身份
-    if (GlobalConfig.isHost) {
+    if (GlobalConfig.isHost||GlobalConfig.isAssistant||GlobalConfig.isPresenter) {
       if (_param) {
         GlobalConfig.currentSceneTableId = parseInt(_param.currentSceneTableId) || 0; //当前场景显示的模块 0=文档模块、1=屏幕共享、2=媒体共享
         //保存数据到Sass
@@ -604,7 +608,7 @@ class ConferApe extends Ape {
   //更新课堂信息
   sendUpdaterClassStatusInfo(_param) {
     //{"actionType": 1,isStopAllPublishMedia:false}    //actionType课堂状态   isStopAllPublishMedia是否停止当前的所有推流
-      //loger.log('发送更新课堂信息->');
+    //loger.log('发送更新课堂信息->');
     if (_param == null || EngineUtils.isEmptyObject(_param)) {
       loger.log('发送更新课堂信息->参数错误');
       this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG);
@@ -651,32 +655,18 @@ class ConferApe extends Ape {
   /////收到消息处理/////////////////////////////////////////////////////////////////////////////////
   //加入channel成功
   onJoinChannelHandlerSuccess() {
-    if(GlobalConfig.isRecordPlayBack){
-      loger.log('课堂模块初始完成->当前是录制回放:'+ GlobalConfig.classStatus);
+    if (GlobalConfig.isRecordPlayBack) {
+      loger.log('课堂模块初始完成->当前是录制回放:' + GlobalConfig.classStatus);
       return;
     }
-    loger.log('课堂模块初始完成->当前课堂状态:'+ GlobalConfig.classStatus,"recordStatus:"+GlobalConfig.recordStatus);
+    loger.log('课堂模块初始完成->当前课堂状态:' + GlobalConfig.classStatus, "recordStatus:" + GlobalConfig.recordStatus);
     this.timerCounter.addTimerCallBack(this.timerCounterUptate.bind(this), 1);
     this.startTimerCounter();
     this.startClass();
     clearTimeout(this.startRecordTimer);
-    this.startRecordTimer=setTimeout(()=>{
-      this.startRecord();
-    },2000);
-
-   /* //如果当前课堂正在进行中,开启计时器
-    if (GlobalConfig.classStatus == ApeConsts.CLASS_STATUS_STARTED) {
-      //开始计时
-      this.startTimerCounter();
+    this.startRecordTimer = setTimeout(()=> {
       this.startRecord();
-    } else if (GlobalConfig.classStatus == ApeConsts.CLASS_STATUS_WAIT &&
-      GlobalConfig.isHost && GlobalConfig.isAutoStartClass && !GlobalConfig.isRecordPlayBack) {
-      //自动开始上课的4个条件
-      //1.如果自己是host,2.Sass配置的是自动开始上课,3.并且当前是未开始状态,4.当前不是录制回放,开始自动上课
-      loger.log('自动开始上课->classStatus:', GlobalConfig.classStatus, " isHost:", GlobalConfig.isHost, " isAutoStartClass:", GlobalConfig.isAutoStartClass, " isRecordPlayBack:", GlobalConfig.isRecordPlayBack);
-      this.startClass();
-    }*/
-
+    }, 2000);
   }
 
   //开启计时器
@@ -707,17 +697,17 @@ class ConferApe extends Ape {
       //向应用层更新当前课堂进行的时间长度 (秒)
       this._emit(MessageTypes.CLASS_UPDATE_TIMER, {"classTimestamp": GlobalConfig.classTimestamp});
 
-     /* 录制消息已经更新了数据,这个课堂内的就不需要再更新,间隔太短了频率太高
-      //以一定的时间间隔同步课堂内所有人的累积上课时间
-      if (GlobalConfig.classTimestamp % GlobalConfig.updateClassInfoDelay == 0) {
-        //如果是host身份,需要同步时间给其他人,同时把当前的状态上传到服务器
-        if (this.checkHasRecordControl()) {
-          //保存数据到Sass
-          this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE);
-          //同步消息给其他人
-          this.sendUpdaterClassStatusInfo({"actionType": ApeConsts.CLASS_STATUS_STARTED, isStopAllPublishMedia: false});
-        }
-      }*/
+      /* 录制消息已经更新了数据,这个课堂内的就不需要再更新,间隔太短了频率太高
+       //以一定的时间间隔同步课堂内所有人的累积上课时间
+       if (GlobalConfig.classTimestamp % GlobalConfig.updateClassInfoDelay == 0) {
+       //如果是host身份,需要同步时间给其他人,同时把当前的状态上传到服务器
+       if (this.checkHasRecordControl()) {
+       //保存数据到Sass
+       this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE);
+       //同步消息给其他人
+       this.sendUpdaterClassStatusInfo({"actionType": ApeConsts.CLASS_STATUS_STARTED, isStopAllPublishMedia: false});
+       }
+       }*/
 
       //进行MS动态选点,选择最快的MS服务器地址(录制回放不做处理)
       if (!GlobalConfig.isRecordPlayBack && GlobalConfig.classTimestamp % GlobalConfig.msDynamicChooseIpDelay == 0) {
@@ -730,7 +720,6 @@ class ConferApe extends Ape {
       }
     }
 
-
     //更新录制进行时间
     GlobalConfig.recordTimestamp = GlobalConfig.recordTimestamp + 1;
     if (this.checkHasRecordControl()) {
@@ -745,83 +734,6 @@ class ConferApe extends Ape {
         this.sendUpdaterClassStatusInfo({"actionType": GlobalConfig.classStatus, isStopAllPublishMedia: false});
       }
     }
-   /* if (GlobalConfig.classStatus == ApeConsts.CLASS_STATUS_STARTED) {
-      GlobalConfig.classTimestamp = GlobalConfig.classTimestamp + 1; //计时
-      //老师身份的时候要记录录制的时间
-      if (GlobalConfig.isHost||this.rosterLen<=1) {
-        GlobalConfig.recordTimestamp = GlobalConfig.recordTimestamp + 1;
-      }
-      //向应用层更新当前课堂进行的时间长度 (秒)
-      this._emit(MessageTypes.CLASS_UPDATE_TIMER, {"classTimestamp": GlobalConfig.classTimestamp});
-
-      //以一定的时间间隔同步课堂内所有人的累积上课时间
-      if (GlobalConfig.classTimestamp % GlobalConfig.updateClassInfoDelay == 0) {
-        //如果是host身份,需要同步时间给其他人,同时把当前的状态上传到服务器
-        if (GlobalConfig.isHost||this.rosterLen<=1) {
-          //保存数据到Sass
-          this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE);
-          //同步消息给其他人
-          this.sendUpdaterClassStatusInfo({"actionType": ApeConsts.CLASS_STATUS_STARTED, isStopAllPublishMedia: false});
-        }
-      }
-
-      //进行MS动态选点,选择最快的MS服务器地址(录制回放不做处理)
-      if (!GlobalConfig.isRecordPlayBack && GlobalConfig.classTimestamp % GlobalConfig.msDynamicChooseIpDelay == 0) {
-        //MS推流选点
-        this._emit(MessageTypes.SWITCH_MS_IP);
-        //MS拉流选点
-        this._emit(MessageTypes.SWITCH_RTMP_PULL_IP);
-        //HLS拉流选点
-        this._emit(MessageTypes.SWITCH_HLS_IP);
-      }
-    }else {
-      //课堂暂停或未开始的情况下,如果已经开始录制,需要更新录制的时间
-      if (GlobalConfig.isHost||this.rosterLen<=1) {
-        GlobalConfig.recordTimestamp = GlobalConfig.recordTimestamp + 1;
-        //以一定的时间间隔同步课堂内所有人的累积上课时间
-        if (GlobalConfig.classTimestamp % GlobalConfig.updateClassInfoDelay == 0) {
-            //保存数据到Sass
-            this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE);
-            //同步消息给其他人
-            this.sendUpdaterClassStatusInfo({"actionType": ApeConsts.CLASS_STATUS_STARTED, isStopAllPublishMedia: false});
-        }
-      }
-    }*/
-
-   /* //如果还没开始或已经暂停、关闭,不做计时处理
-     if (GlobalConfig.classStatus != ApeConsts.CLASS_STATUS_STARTED) {
-     loger.warn('当前课堂已经暂停或者未开始,不计时', "classStatus-->", GlobalConfig.classStatus);
-     return;
-     }
-     GlobalConfig.classTimestamp = GlobalConfig.classTimestamp + 1; //计时
-
-     //老师身份的时候要记录录制的时间
-     if (GlobalConfig.isHost) {
-     GlobalConfig.recordTimestamp = GlobalConfig.recordTimestamp + 1;
-     }
-     //向应用层更新当前课堂进行的时间长度 (秒)
-     this._emit(MessageTypes.CLASS_UPDATE_TIMER, {"classTimestamp": GlobalConfig.classTimestamp});
-
-     //以一定的时间间隔同步课堂内所有人的累积上课时间
-     if (GlobalConfig.classTimestamp % GlobalConfig.updateClassInfoDelay == 0) {
-     //如果是host身份,需要同步时间给其他人,同时把当前的状态上传到服务器
-     if (GlobalConfig.isHost) {
-     //保存数据到Sass
-     this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE);
-     //同步消息给其他人
-     this.sendUpdaterClassStatusInfo({"actionType": ApeConsts.CLASS_STATUS_STARTED, isStopAllPublishMedia: false});
-     }
-     }
-
-     //进行MS动态选点,选择最快的MS服务器地址(录制回放不做处理)
-     if (!GlobalConfig.isRecordPlayBack && GlobalConfig.classTimestamp % GlobalConfig.msDynamicChooseIpDelay == 0) {
-     //MS推流选点
-     this._emit(MessageTypes.SWITCH_MS_IP);
-     //MS拉流选点
-     this._emit(MessageTypes.SWITCH_RTMP_PULL_IP);
-     //HLS拉流选点
-     this._emit(MessageTypes.SWITCH_HLS_IP);
-     }*/
   }
 
   tableUpdateHandler(owner, itemIdx, itemData) {
@@ -831,7 +743,7 @@ class ConferApe extends Ape {
       //{"itemIdx":720899,"from":976168842,"owner":976168842,"actionType":null,"classStatusInfo":{"nodeId":976168842,"userId":"user_979813","userName":"user_979813","siteId":"markettest","classId":889112694,"className":"ly828-1v1","classType":1,"classStatus":1,"classStartTime":"2017-8-28-16-33-18","classStopTime":"2017-8-29-11-9-28","classTimestamp":1930,"classBeginTime":"2017-08-28 16:00:00","classEndTime":"2017-08-31 18:00:00","recordStatus":false,"recordTimestamp":2825,"recordFileName":"markettest/20170828/889112694_20170828.rec","recordDownloadUrl":"","serverTimestamp":1503976246,"activeDocId":976170739,"activeDocCurPage":1,"isStopAllPublishMedia":false,"currentSceneTableId":0,"silence":false,"silenceUsers":"{}","isEnableDraw":true}}
       //处理课堂更新的信息
       if (model && model.classStatusInfo) {
-          // loger.log("课堂更新->",model.classStatusInfo);
+        // loger.log("课堂更新->",model.classStatusInfo);
         try {
           model.classStatusInfo.silenceUsers = JSON.parse(model.classStatusInfo.silenceUsers);
         } catch (err) {
@@ -843,7 +755,7 @@ class ConferApe extends Ape {
           this._emit(MessageTypes.STOP_ALL_MEDIA_PUBLISH);
         }
       }
-     // loger.log('课堂数据更新->');
+      // loger.log('课堂数据更新->');
       //通知应用层更新课堂状态
       let classInfo = GlobalConfig.classStatusInfo;
       //loger.log('通知应用层更新课堂状态->CLASS_UPTATE_STATUS')
@@ -855,14 +767,6 @@ class ConferApe extends Ape {
         this.stopTimerCounter();
         return;
       }
-
-   /* if (GlobalConfig.classStatus == ApeConsts.CLASS_STATUS_STARTED) {
-        //如果课堂在进行中,开始计时器
-        this.startTimerCounter();
-      } else {
-        //停止计时
-        this.stopTimerCounter();
-      }*/
     } catch (err) {
       loger.warn('课堂更新->error', err.message);
     }
@@ -883,9 +787,9 @@ class ConferApe extends Ape {
         //关闭之前停止所有推流
         this._emit(MessageTypes.STOP_ALL_MEDIA_PUBLISH);
         //收到课堂关闭,所有人都退出,执行自己关闭的流程
-        setTimeout(()=>{
+        setTimeout(()=> {
           this._emit(MessageTypes.CLASS_RUN_EXIT, {'type': 1});
-        },2000);
+        }, 2000);
         break;
       case ApeConsts.STOP_ALL_PUBLISH:
         this._emit(MessageTypes.STOP_ALL_MEDIA_PUBLISH);
@@ -1010,12 +914,12 @@ class ConferApe extends Ape {
       //{"initiator":564398684,"record":true,"classTime":39,"filename":"markettest/20170823/1096250804_20170823.rec"}//开启成功
       //{"initiator":564398684,"record":false,"classTime":39,"filename":"markettest/20170823/1096250804_20170823.rec"} //停止成功
       loger.warn("录制回放控制操作成功->", conferRecordSendPdu);
-      if (conferRecordSendPdu ){
-        if(conferRecordSendPdu.record == true || conferRecordSendPdu.record == "true") {
+      if (conferRecordSendPdu) {
+        if (conferRecordSendPdu.record == true || conferRecordSendPdu.record == "true") {
           //每次开启录制的时候,需要把当前显示的文档数据更新一次,否则无法录制已经显示的文件
           loger.warn("MCU已经开启录制");
           this._emit(MessageTypes.CLASS_RECORD_SUCCESS);
-        }else{
+        } else {
           //停止录制成功
           loger.warn("MCU已经停止录制");
         }
@@ -1045,18 +949,16 @@ class ConferApe extends Ape {
       // 1.当前课堂只有自己;2.自己的身份不是host;3当前的课堂状态为(CLASS_STATUS_STARTED= 1;//直播中)
       this.rosterLen = Object.keys(this.rosters).length;
       GlobalConfig.rosterNumber = this.rosterLen;//记录当前的总人数
-    /*  if (this.rosterLen <=1 && !GlobalConfig.isHost && GlobalConfig.classStatus == ApeConsts.CLASS_STATUS_STARTED) {
-        loger.warn("当前课堂没有老师->暂停课堂");
-        this.pauseClass({isForce: true});
-        //this.stopRecord(true);
-      }*/
+      /*  if (this.rosterLen <=1 && !GlobalConfig.isHost && GlobalConfig.classStatus == ApeConsts.CLASS_STATUS_STARTED) {
+       loger.warn("当前课堂没有老师->暂停课堂");
+       this.pauseClass({isForce: true});
+       //this.stopRecord(true);
+       }*/
       //处理用户信息
       this.unPackRosterInfo(nodeId, nodeData);
       return;
     }
 
-    //loger.log(nodeId, "加入课堂,role-->", nodeData.role, ApeConsts.userTypes[nodeData.role]);
-
     //新加入的人员不是自己
     //1.判断进入的用户身份,如果进入的人身份是host,助教,监课,并且和自己的身份冲突,自己会被踢掉
     //2.最后进入的人会踢掉之前进入的人,nodeId是按时间戳生成的,最后进入的人nodeId的值比之前进入的人大
@@ -1069,35 +971,15 @@ class ConferApe extends Ape {
         deviceType: nodeData.deviceType
       }
       if (nodeData.role == ApeConsts.NR_HOST && GlobalConfig.isHost) {
-        loger.warn("相同身份的人进入->自己被踢出->进入的人员信息","userName:"+ nodeData.name,"userId:"+ nodeData.userId,"userRole:"+ nodeData.userRole,"nodeId:"+ nodeData.nodeId,"deviceType:"+ nodeData.deviceType);
+        loger.warn("相同身份的人进入->自己被踢出->进入的人员信息", "userName:" + nodeData.name, "userId:" + nodeData.userId, "userRole:" + nodeData.userRole, "nodeId:" + nodeData.nodeId, "deviceType:" + nodeData.deviceType);
         this.kickOutRoster(newUserInfo);
         return;
       } else if (nodeData.userId == GlobalConfig.userId && GlobalConfig.userId != "0") {
         loger.warn("异地登陆->userId->", GlobalConfig.userId);
-        this._emit(MessageTypes.MCU_ERROR, {type:MessageTypes.ERR_CLASS_REMOTE_LANDING, data:newUserInfo});
+        this._emit(MessageTypes.MCU_ERROR, {type: MessageTypes.ERR_CLASS_REMOTE_LANDING, data: newUserInfo});
         this._emit(MessageTypes.CLASS_RUN_EXIT, {'type': 1});
       }
     }
-    /*if (parseInt(nodeId) > GlobalConfig.nodeId) {
-     if (nodeData.role == ApeConsts.NR_HOST && GlobalConfig.isHost) {
-     this.kickOutRoster();
-     return;
-     } else if (nodeData.role == ApeConsts.NR_PRESENTER && GlobalConfig.isPresenter) {
-     this.kickOutRoster();
-     return;
-     } else if (nodeData.role == ApeConsts.NR_ASSISTANT && GlobalConfig.isAssistant) {
-     this.kickOutRoster();
-     return;
-     } else if (nodeData.role == ApeConsts.NR_INVISIBLE && GlobalConfig.isInvisible) {
-     this.kickOutRoster();
-     return;
-     }else  if(nodeData.userId==GlobalConfig.userId&&GlobalConfig.userId!="0"){
-     loger.log("异地登陆->userId->",GlobalConfig.userId);
-     this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_REMOTE_LANDING);
-     this._emit(MessageTypes.CLASS_RUN_EXIT,{'type':1});
-     }
-     }*/
-
     //处理用户信息
     this.unPackRosterInfo(nodeId, nodeData);
   }
@@ -1106,7 +988,7 @@ class ConferApe extends Ape {
   unPackRosterInfo(nodeId, nodeData) {
     let rosterExists = this.rosters[nodeId];
     this.rosters[nodeId] = nodeData;
-    GlobalConfig.rosters=this.rosters;
+    GlobalConfig.rosters = this.rosters;
     let userDataObj = null;
     try {
       userDataObj = pdu['RCNodeInfoUserDataPdu'].decode(nodeData.userData);
@@ -1133,7 +1015,7 @@ class ConferApe extends Ape {
       this.rosterLen = Object.keys(this.rosters).length;
       GlobalConfig.rosterNumber = this.rosterLen;//记录当前的总人数
       newNodeData.rosterLen = this.rosterLen;
-      if(nodeId!=GlobalConfig.nodeId){
+      if (nodeId != GlobalConfig.nodeId) {
         loger.log("人员更新信息->", newNodeData);
       }
       this._emit(MessageTypes.CLASS_UPDATE_ROSTER, {"nodeId": nodeId, "nodeData": newNodeData});
@@ -1149,7 +1031,7 @@ class ConferApe extends Ape {
      userRole:nodeData.userRole,
      deviceType: nodeData.deviceType
      }*/
-    this._emit(MessageTypes.MCU_ERROR, {type:MessageTypes.ERR_CLASS_KICK_OUT,data: _newUserInfo});
+    this._emit(MessageTypes.MCU_ERROR, {type: MessageTypes.ERR_CLASS_KICK_OUT, data: _newUserInfo});
     this._emit(MessageTypes.CLASS_RUN_EXIT, {'type': 1});
   }
 
@@ -1181,7 +1063,7 @@ class ConferApe extends Ape {
         loger.log(nodeId, "->离开课堂->身份->", user.userRole);
       }
       delete this.rosters[nodeId];
-      GlobalConfig.rosters=this.rosters;
+      GlobalConfig.rosters = this.rosters;
       this.rosterLen = Object.keys(this.rosters).length;
       GlobalConfig.rosterNumber = this.rosterLen;//记录当前的总人数
 
@@ -1244,6 +1126,7 @@ class ConferApe extends Ape {
     classStatusInfo.silence = GlobalConfig.silence;
     classStatusInfo.silenceUsers = JSON.stringify(GlobalConfig.silenceUsers);
     classStatusInfo.isEnableDraw = GlobalConfig.isEnableDraw;
+    classStatusInfo.videoScale=GlobalConfig.videoScale||1;
     //loger.log("classStatusInfo--->", classStatusInfo);
 
     /*
@@ -1278,11 +1161,12 @@ class ConferApe extends Ape {
     }
     return null;
   }
-  stopApe(){
-    this.rosters={};
-    this.rosterLen=0;
-    GlobalConfig.rosterNumber=this.rosterLen;
-    GlobalConfig.rosters=this.rosters;
+
+  stopApe() {
+    this.rosters = {};
+    this.rosterLen = 0;
+    GlobalConfig.rosterNumber = this.rosterLen;
+    GlobalConfig.rosters = this.rosters;
   }
 
 }
diff --git a/src/apes/WebRtcApe.js b/src/apes/WebRtcApe.js
index 54db159..c114089 100644
--- a/src/apes/WebRtcApe.js
+++ b/src/apes/WebRtcApe.js
@@ -44,6 +44,8 @@ class WebRtcApe extends Emiter {
 
     this.isPublish = false;//当前是否正在推流
 
+    this.videoScale=1;//视图的缩放比例,默认为1;
+
     this.normalRemoteViewId = "";
     this.normalRemoteStyle = "";
     this.normalRemoteVideoWidth = 320;
@@ -64,6 +66,12 @@ class WebRtcApe extends Emiter {
     this.invisibleVideoWidth = 320;
     this.invisibleVideoHeight = 240;
     this.xdyRemote = "xdy_remote";
+
+    this.localWebRtcVideoClass='localWebRtcVideoClass';//本地视图统一的class名称
+    this.invisibleWebRtcVideoClass='invisibleWebRtcVideoClass';
+    this.normalWebRtcVideoClass='normalWebRtcVideoClass';
+    this.hostWebRtcVideoClass='hostWebRtcVideoClass'
+
     //webRtc sdk
     this.client = AgoraRTC.createClient({mode: this.mode});
 
@@ -184,17 +192,17 @@ class WebRtcApe extends Emiter {
       if (userRole == ApeConsts.invisible) {
         //把远程视频添加到监课列表
         loger.log("获取远程视频流成功->监课:" + userName + "->" + uid, new Date().getTime());
-        let viewDiv = `<div id="${this.xdyRemote + uid}" style="width:${this.invisibleVideoWidth}px;height:${this.invisibleVideoHeight}px;float: left;margin-right: 1px;pointer-events: none;">${nameDiv}</div>`;
+        let viewDiv = `<div id="${this.xdyRemote + uid}" class="${this.invisibleWebRtcVideoClass}" style="width:${this.invisibleVideoWidth*this.videoScale}px;height:${this.invisibleVideoHeight*this.videoScale}px;float: left;margin-right: 1px;pointer-events: none;">${nameDiv}</div>`;
         $(this.invisibleViewId).append(viewDiv);
       } else if (userRole == ApeConsts.host||userRole == ApeConsts.assistant||userRole == ApeConsts.presenter) {
         //把远程视图添加到老师列表
         loger.log("获取远程视频流成功->userRole:"+userRole+":" + userName + "->" + uid, new Date().getTime());
-        let viewDiv = `<div id="${this.xdyRemote + uid}" style="width:${this.hostRemoteVideoWidth}px;height:${this.hostRemoteVideoHeight}px;float: left;margin-right: 1px;pointer-events: none;">${nameDiv}</div>`;
+        let viewDiv = `<div id="${this.xdyRemote + uid}" class="${this.hostWebRtcVideoClass}" style="width:${this.hostRemoteVideoWidth*this.videoScale}px;height:${this.hostRemoteVideoHeight*this.videoScale}px;float: left;margin-right: 1px;pointer-events: none;">${nameDiv}</div>`;
         $(this.hostRemoteViewId).append(viewDiv);
       } else {
         //把视图添加到学生列表
         loger.log("获取远程视频流成功->学生:" + userName + "->" + uid, new Date().getTime());
-        let viewDiv = `<div id="${this.xdyRemote + uid}" style="width:${this.normalRemoteVideoWidth}px;height:${this.normalRemoteVideoHeight}px;float: left;margin-right: 1px;pointer-events: none;">${nameDiv}</div>`;
+        let viewDiv = `<div id="${this.xdyRemote + uid}" class="${this.normalWebRtcVideoClass}" style="width:${this.normalRemoteVideoWidth*this.videoScale}px;height:${this.normalRemoteVideoHeight*this.videoScale}px;float: left;margin-right: 1px;pointer-events: none;">${nameDiv}</div>`;
         $(this.normalRemoteViewId).append(viewDiv);
       }
       //播放视频,隐藏控制条
@@ -370,8 +378,9 @@ class WebRtcApe extends Emiter {
       let viewName = 'localVideoBox_' + this.uid;
       let videoBox = document.createElement("div");
       videoBox.id = viewName;
-      videoBox.style.width = this.localVideoWidth + 'px';
-      videoBox.style.height = this.localVideoHeight + 'px';
+      videoBox.className=this.localWebRtcVideoClass;
+      videoBox.style.width = (this.localVideoWidth*this.videoScale) + 'px';
+      videoBox.style.height = (this.localVideoHeight*this.videoScale) + 'px';
       videoBox.style.float = 'left';
       videoBox.style.marginRight = "1px";
       videoBox.style.pointerEvents = 'none';
@@ -439,6 +448,50 @@ class WebRtcApe extends Emiter {
   }
 
   /*
+   * 更新所有视频的尺寸大小
+   * */
+  updateAllVideoSize(){
+    $("."+this.localWebRtcVideoClass).css("width",this.localVideoWidth*this.videoScale);
+    $("."+this.localWebRtcVideoClass).css("height",this.localVideoHeight*this.videoScale);
+
+    $("."+this.hostWebRtcVideoClass).css("width",this.hostRemoteVideoWidth*this.videoScale);
+    $("."+this.hostWebRtcVideoClass).css("height",this.hostRemoteVideoHeight*this.videoScale);
+
+    $("."+this.normalWebRtcVideoClass).css("width",this.normalRemoteVideoWidth*this.videoScale);
+    $("."+this.normalWebRtcVideoClass).css("height",this.normalRemoteVideoHeight*this.videoScale);
+
+    //监课的不需要设置
+    //$("."+this.invisibleWebRtcVideoClass).css("width",this.localVideoWidth);
+    //$("."+this.invisibleWebRtcVideoClass).css("height",this.localVideoHeight);
+  }
+
+  /*
+  * 设置rtc视频的属性
+  * */
+  changeRtcVideoConfig(_params){
+    //{videoScale:1}
+    if(!_params){
+      return;
+    }
+    let scale=parseInt(_params.videoScale)||1;//最小值只能为1,这个是按倍数缩放视频
+    if(this.videoScale==scale){
+      return;
+    }
+    this.videoScale=scale;
+    loger.log("更新视频视图大小->videoScale:"+this.videoScale);
+  /*  this.localVideoWidth=this.localVideoWidth*this.videoScale;
+    this.localVideoHeight=this.localVideoHeight*this.videoScale;
+
+    this.hostRemoteVideoWidth=this.hostRemoteVideoWidth*this.videoScale;
+    this.hostRemoteVideoHeight=this.hostRemoteVideoHeight*this.videoScale;
+
+    this.normalRemoteVideoWidth=this.normalRemoteVideoWidth*this.videoScale;
+    this.normalRemoteVideoHeight=this.normalRemoteVideoHeight*this.videoScale;*/
+    this.updateAllVideoSize();
+    
+  }
+
+  /*
    * 设置本地回显视图
    * */
   setLoaclView(_params) {
@@ -448,6 +501,9 @@ class WebRtcApe extends Emiter {
     this.localVideoWidth = parseInt(_params.width) || 320;
     this.localVideoHeight = parseInt(_params.height) || 240;
     this.nameDisplay = _params.nameDisplay || "block";
+
+    this.localVideoWidth=this.localVideoWidth;
+    this.localVideoHeight=this.localVideoHeight;
   }
 
   /*
@@ -459,6 +515,8 @@ class WebRtcApe extends Emiter {
     this.hostRemoteStyle = _params.styleStr || "";
     this.hostRemoteVideoWidth = parseInt(_params.width) || 320;
     this.hostRemoteVideoHeight = parseInt(_params.height) || 240;
+    this.hostRemoteVideoWidth=this.hostRemoteVideoWidth;
+    this.hostRemoteVideoHeight=this.hostRemoteVideoHeight;
   }
 
   /*
@@ -470,6 +528,9 @@ class WebRtcApe extends Emiter {
     this.normalRemoteStyle = _params.styleStr || "";
     this.normalRemoteVideoWidth = parseInt(_params.width) || 320;
     this.normalRemoteVideoHeight = parseInt(_params.height) || 240;
+
+    this.normalRemoteVideoWidth=this.normalRemoteVideoWidth;
+    this.normalRemoteVideoHeight=this.normalRemoteVideoHeight;
   }
 
   /*
diff --git a/src/pdus/pro.js b/src/pdus/pro.js
index 34b8a91..55dcc4a 100644
--- a/src/pdus/pro.js
+++ b/src/pdus/pro.js
@@ -1045,6 +1045,7 @@ message RCClassStatusInfoPdu {
      optional bool silence=24;//课堂禁言
      optional string silenceUsers=25;//课堂用户禁言状态列表
      optional bool isEnableDraw=26;//课堂用户是否开启绘制权限
+     optional uint32 videoScale=27;//视频显示的缩放倍数
 }
 
 message RCConferenceRecordRequestPdu {
--
libgit2 0.24.0