UNPKG

@observertc/client-monitor-js

Version:

ObserveRTC Client Integration Javascript Library

1 lines 2.65 kB
export class AudioConcealmentDetector{trackMonitor;static ISSUE_TYPE="audio-concealment";name="audio-concealment-detector";disabled=!1;static MAX_WINDOW_ENTRIES=128;issueKey;_window=[];_sumAudible=0;_sumTotal=0;_sumEvents=0;_alertOn=!1;_startedAt;constructor(t){this.trackMonitor=t,this.issueKey=`${AudioConcealmentDetector.ISSUE_TYPE}-track-${t.track.id}`}get config(){return this.peerConnection.parent.config.audioConcealmentDetector}get peerConnection(){return this.trackMonitor.getPeerConnection()}update(){if(this.disabled)return;const t=this.trackMonitor.getInboundRtp();if(!t||"audio"!==t.kind)return;if(this.trackMonitor.remoteOutboundTrackPaused)return this._resetWindow(),this._alertOn?this._clear("remote track paused"):void 0;const e=t.deltaTotalSamplesReceived;if(void 0===e)return;const n=Math.max(0,(t.deltaConcealedSamples??0)-(t.deltaSilentConcealedSamples??0)),s=Date.now(),i=t.deltaConcealmentEvents??0;this._window.push({timestamp:s,audibleConcealedSamples:n,totalSamplesReceived:e,concealmentEvents:i}),this._sumAudible+=n,this._sumTotal+=e,this._sumEvents+=i;const o=this.config.windowInMs;for(let t=this._window[0];t&&(t.timestamp<s-o||AudioConcealmentDetector.MAX_WINDOW_ENTRIES<this._window.length);t=this._window[0])this._sumAudible-=t.audibleConcealedSamples,this._sumTotal-=t.totalSamplesReceived,this._sumEvents-=t.concealmentEvents,this._window.shift();const a=this._window[0];if(!a)return;if(this._sumTotal<this.config.minSamplesInWindow)return;const r=this._sumAudible/this._sumTotal,c=Math.max(1,s-a.timestamp)/1e3,l=this._sumEvents/c;if(this._alertOn)return void(r<this.config.offThreshold&&this._clear("concealment back to normal"));if(r<=this.config.onThreshold)return;this._alertOn=!0,this._startedAt=s;const d=this.peerConnection.parent;d.emit("audio-concealment",{clientMonitor:d,trackMonitor:this.trackMonitor,concealmentRate:r,concealmentEventRate:l}),d.raiseIssue(this.issueKey,{type:AudioConcealmentDetector.ISSUE_TYPE,payload:{peerConnectionId:this.peerConnection.peerConnectionId,trackId:this.trackMonitor.track.id,concealmentRate:r,concealmentEventRate:l,burstiness:this._classifyBurstiness(this._sumAudible,this._sumEvents),windowInMs:o}})}_resetWindow(){this._window.length=0,this._sumAudible=0,this._sumTotal=0,this._sumEvents=0}_classifyBurstiness(t,e){if(e<1)return"unknown";return t/e<4800?"bursty":"continuous"}_clear(t){this._alertOn=!1;const e=this.peerConnection.parent,n=e.activeIssues.get(this.issueKey);let s;n&&(s={...n.payload,durationInMs:this._startedAt?Date.now()-this._startedAt:void 0}),e.resolveIssue(this.issueKey,{comment:t,payload:s,resolvedAt:Date.now()}),this._startedAt=void 0}}