trtc-sdk-v5
Version:
Tencent Cloud RTC SDK for Web
1 lines • 9.03 kB
JavaScript
var __defProp=Object.defineProperty,__getOwnPropSymbols=Object.getOwnPropertySymbols,__hasOwnProp=Object.prototype.hasOwnProperty,__propIsEnum=Object.prototype.propertyIsEnumerable,__defNormalProp=(t,e,s)=>e in t?__defProp(t,e,{enumerable:!0,configurable:!0,writable:!0,value:s}):t[e]=s,__spreadValues=(t,e)=>{for(var s in e||(e={}))__hasOwnProp.call(e,s)&&__defNormalProp(t,s,e[s]);if(__getOwnPropSymbols)for(var s of __getOwnPropSymbols(e))__propIsEnum.call(e,s)&&__defNormalProp(t,s,e[s]);return t},__publicField=(t,e,s)=>__defNormalProp(t,"symbol"!=typeof e?e+"":e,s),DEFAULT_OPTIONS={rttPoorLimit:200,lossPoorLimit:20,rttGoodLimit:100,lossGoodLimit:10,sleepTime:3e4,poorDuration:1e4,goodDuration:2e4,maxAutoSwitchToSmallCount:2},ssasSeq=0,_SmallStreamAutoSwitcher=class t{constructor(t){this.core=t,__publicField(this,"log"),__publicField(this,"options",DEFAULT_OPTIONS),__publicField(this,"rttQueue",[]),__publicField(this,"lossQueue",[]),__publicField(this,"autoSwitchToSmallCountMap",new Map),__publicField(this,"sleepMap",new Map),__publicField(this,"fpsSmallQueueMap",new Map),__publicField(this,"fpsBigQueueMap",new Map),__publicField(this,"checkIntervalTime",2e3),__publicField(this,"rttOverCount",0),__publicField(this,"lossOverCount",0),__publicField(this,"rttUnderCount",0),__publicField(this,"lossUnderCount",0),__publicField(this,"checkInterval",null),__publicField(this,"beforeSwitchFpsTrackingMap",new Map),__publicField(this,"isAutoSwitching",!1),__publicField(this,"testCount"),__publicField(this,"poorCount"),__publicField(this,"goodCount"),this.log=t.log.createChild({id:`${this.getAlias()}${ssasSeq}`}),this.log.info(`created id=${this.getAlias()}${ssasSeq}`),ssasSeq+=1}getName(){return t.Name}getAlias(){return"ssas"}getGroup(){return"ssas"}destroy(){this.log.debug("destroy"),this.stop()}getValidateRule(){return{type:this.core.enums.BASIC_TYPE.Object,required:!1}}start(t){const e=this.core.room.scheduleResult.autoSwitchSmallConfig||{};this.options=__spreadValues(__spreadValues(__spreadValues({},DEFAULT_OPTIONS),t),e),this.log.info("start with options:",this.options),this.poorCount=Math.floor(this.options.poorDuration/this.checkIntervalTime),this.goodCount=Math.floor(this.options.goodDuration/this.checkIntervalTime),this.testCount=Math.max(1,this.poorCount,this.goodCount),this.core.trtc.on(this.core.TRTC.EVENT.STATISTICS,this.onStatistics,this),this.core.trtc.on(this.core.TRTC.EVENT.NETWORK_QUALITY,this.onNetworkQuality,this),this.core.room.on(this.core.enums.RoomEvent.SUBSCRIBE_SMALL_VIDEO_CHANGED,this.onSmallVideoChanged,this),this.core.room.on(this.core.enums.RoomEvent.PEER_LEAVE,this.onRemoteUserLeave,this),this.checkInterval=setInterval((()=>{const{room:t}=this.core;if(0===t.remotePublishedUserMap.size)return;for(const[t,e]of this.sleepMap)if(e>0){const s=e-this.checkIntervalTime;s<=0?this.sleepMap.delete(t):this.sleepMap.set(t,s)}const e=this.getShouldSwitchToSmallUserList(),s=this.getShouldSwitchToBigUserList();for(const s of e){if((this.sleepMap.get(s)||0)>0)continue;const e=t.remotePublishedUserMap.get(s),i=this.isBigVideoSubscribed(t,s),o=null==e?void 0:e.muteState.hasSmall;if(!e||!i||!o)continue;const r=this.autoSwitchToSmallCountMap.get(s)||0;r>=this.options.maxAutoSwitchToSmallCount||(this.toggleSmall(e,!0),this.fpsBigQueueMap.set(s,[]),this.autoSwitchToSmallCountMap.set(s,r+1),this.sleepMap.set(s,this.options.sleepTime))}for(const e of s){if((this.sleepMap.get(e)||0)>0)continue;const s=t.remotePublishedUserMap.get(e),i=this.isSmallVideoSubscribed(t,e);if(!s||!i)continue;(this.autoSwitchToSmallCountMap.get(e)||0)===this.options.maxAutoSwitchToSmallCount-1&&(this.toggleSmall(s,!1),this.fpsSmallQueueMap.set(e,[]),this.sleepMap.set(e,this.options.sleepTime))}}),this.checkIntervalTime),this.log.info("started")}update(){this.log.info("update")}stop(){this.core.trtc.off(this.core.TRTC.EVENT.NETWORK_QUALITY,this.onNetworkQuality,this),this.core.trtc.off(this.core.TRTC.EVENT.STATISTICS,this.onStatistics,this),this.core.room.off(this.core.enums.RoomEvent.SUBSCRIBE_SMALL_VIDEO_CHANGED,this.onSmallVideoChanged,this),this.core.room.off(this.core.enums.RoomEvent.PEER_LEAVE,this.onRemoteUserLeave,this),this.fpsBigQueueMap.clear(),this.fpsSmallQueueMap.clear(),this.rttQueue=[],this.lossQueue=[],this.rttOverCount=0,this.lossOverCount=0,this.rttUnderCount=0,this.lossUnderCount=0,this.sleepMap.clear(),this.autoSwitchToSmallCountMap.clear(),this.beforeSwitchFpsTrackingMap.clear(),this.checkInterval&&(clearInterval(this.checkInterval),this.checkInterval=null),this.log.info("stopped")}toggleSmall(t,e){const{userId:s}=t;this.log.info(`autoswitch ${s} to ${e?"small":"big"} stream`),this.isAutoSwitching=!0,this.core.room.changeType(e,t),setTimeout((()=>this.isAutoSwitching=!1),0),this.takeSnapshot(s,e);const i=e?593e3:593001;if(this.core.kvStatManager.addCount({key:i}),e){const t=this.fpsBigQueueMap.get(s);if(!t)return;const e=t.reduce(((t,e)=>t+e),0)/t.length;if(this.fpsSmallQueueMap.set(s,[]),0===e)return;this.beforeSwitchFpsTrackingMap.set(s,e)}}onSmallVideoChanged(t){if(this.isAutoSwitching)return;const{userId:e,isSmall:s}=t;this.log.info(`small video changed: userId=${e}, isSmall=${s}`),s?this.autoSwitchToSmallCountMap.set(e,this.options.maxAutoSwitchToSmallCount):(this.autoSwitchToSmallCountMap.set(e,0),this.sleepMap.set(e,this.options.sleepTime))}onRemoteUserLeave(t){this.fpsBigQueueMap.delete(t),this.fpsSmallQueueMap.delete(t),this.autoSwitchToSmallCountMap.delete(t),this.sleepMap.delete(t),this.beforeSwitchFpsTrackingMap.delete(t)}onNetworkQuality(t){const{downlinkRTT:e,downlinkLoss:s}=t;this.rttQueue.push(e),this.lossQueue.push(s),this.rttQueue.length>this.testCount&&this.rttQueue.shift(),this.lossQueue.length>this.testCount&&this.lossQueue.shift(),this.rttOverCount=e>this.options.rttPoorLimit?this.rttOverCount+1:0,this.lossOverCount=s>this.options.lossPoorLimit?this.lossOverCount+1:0,this.rttUnderCount=e<this.options.rttGoodLimit?this.rttUnderCount+1:0,this.lossUnderCount=s<this.options.lossGoodLimit?this.lossUnderCount+1:0}onStatistics(t){var e;if(null==(e=null==t?void 0:t.remoteStatistics)?void 0:e.length)try{t.remoteStatistics.forEach((t=>{var e,s,i;const{userId:o}=t;if(!o||!(null==(e=t.video)?void 0:e.length))return;const r=(null==(s=t.video.find((t=>"big"===t.videoType)))?void 0:s.frameRate)||0,h=(null==(i=t.video.find((t=>"small"===t.videoType)))?void 0:i.frameRate)||0,l=(t,e)=>{let s=t.get(o);s||(s=[],t.set(o,s)),s.push(e),s.length>this.testCount&&s.shift()};l(this.fpsBigQueueMap,r),l(this.fpsSmallQueueMap,h),this.checkAndReportFpsRatio(o)}))}catch(t){this.log.warn("onStatistics error",t)}}checkAndReportFpsRatio(t){const e=this.beforeSwitchFpsTrackingMap.get(t);if(!e)return;const s=this.fpsSmallQueueMap.get(t);if(!s||s.length<this.testCount)return;const i=s.reduce(((t,e)=>t+e),0)/s.length,o=i/e*100,r=Math.round(Math.max(1,Math.min(1e3,o)));this.core.kvStatManager.addNumber({key:593800,value:r,split:[0,100,200,300,400,500,800,1e3],max:1e3}),this.log.debug(`beforeSwitchFps: ${e}, afterSwitchFps: ${i}, afterSwitchQueue: ${s.join(",")}`),this.log.info(`FPS ratio reported for user ${t}: ${r.toFixed(2)}% (before: ${e.toFixed(1)}, after: ${i.toFixed(1)})`),this.beforeSwitchFpsTrackingMap.delete(t)}getBadFrameRateUserList(){const t=[];for(const[e,s]of this.fpsBigQueueMap){if(!s||0===s.length)continue;const i=Math.max(...s),o=Math.min(...s);s.length!==this.testCount||0!==o||0!==i?0!==i&&i-o>i/3&&t.push(e):t.push(e)}return t}getGoodFrameRateUserList(){const t=[];for(const[e,s]of this.fpsSmallQueueMap){if(!s||0===s.length)continue;const i=Math.max(...s),o=Math.min(...s);0!==i&&(i-o<=i/3&&t.push(e))}return t}getShouldSwitchToSmallUserList(){if(this.rttQueue.length<this.testCount||this.lossQueue.length<this.testCount)return[];if(!(this.rttOverCount>=this.poorCount||this.lossOverCount>=this.poorCount))return[];const t=this.getBadFrameRateUserList();return t.length>0&&this.log.debug(`badFrameRateUserList: ${t.join(",")}`),t}getShouldSwitchToBigUserList(){if(!(this.rttUnderCount>=this.goodCount&&this.lossUnderCount>=this.goodCount))return[];const t=this.getGoodFrameRateUserList();return t.length>0&&this.log.debug(`goodFrameRateUserList: ${t.join(",")}`),t}takeSnapshot(t,e){this.log.info(`Network stats at snapshot: RTTQueue=${this.rttQueue.join(",")}, LossQueue=${this.lossQueue.join(",")}`);const s=e?this.fpsBigQueueMap.get(t):this.fpsSmallQueueMap.get(t);this.log.info(`${e?"big":"small"} frame rate stats at snapshot: ${(null==s?void 0:s.join(","))||"N/A"}`)}isBigVideoSubscribed(t,e){const s=t.remotePublishedUserMap.get(e);return!!s&&s.remoteVideoTrack.mediaType===this.core.enums.MediaType.BIG_VIDEO}isSmallVideoSubscribed(t,e){const s=t.remotePublishedUserMap.get(e);return!!s&&s.remoteVideoTrack.mediaType===this.core.enums.MediaType.SMALL_VIDEO}};__publicField(_SmallStreamAutoSwitcher,"Name","SmallStreamAutoSwitcher");var SmallStreamAutoSwitcher=_SmallStreamAutoSwitcher,index_default=SmallStreamAutoSwitcher;export{index_default as default};export{SmallStreamAutoSwitcher};