From d304cc4b92bba1db992627e3a739a2957f3190df Mon Sep 17 00:00:00 2001 From: Timo K Date: Mon, 8 May 2023 15:00:34 +0200 Subject: [PATCH 01/16] add audio concealment to stats report --- src/webrtc/stats/connectionStats.ts | 4 +-- src/webrtc/stats/media/mediaTrackStats.ts | 32 +++++++++++++++++++++-- src/webrtc/stats/statsReport.ts | 11 ++++++-- src/webrtc/stats/statsReportBuilder.ts | 13 ++++++++- src/webrtc/stats/statsReportGatherer.ts | 1 + src/webrtc/stats/trackStatsReporter.ts | 10 +++++++ 6 files changed, 64 insertions(+), 7 deletions(-) diff --git a/src/webrtc/stats/connectionStats.ts b/src/webrtc/stats/connectionStats.ts index dbde6e50327..ef1c36797ea 100644 --- a/src/webrtc/stats/connectionStats.ts +++ b/src/webrtc/stats/connectionStats.ts @@ -33,7 +33,7 @@ export interface ConnectionStatsBitrate extends Bitrate { video?: Bitrate; } -export interface PacketLoos { +export interface PacketLoss { total: number; download: number; upload: number; @@ -42,6 +42,6 @@ export interface PacketLoos { export class ConnectionStats { public bandwidth: ConnectionStatsBitrate = {} as ConnectionStatsBitrate; public bitrate: ConnectionStatsBitrate = {} as ConnectionStatsBitrate; - public packetLoss: PacketLoos = {} as PacketLoos; + public packetLoss: PacketLoss = {} as PacketLoss; public transport: TransportStats[] = []; } diff --git a/src/webrtc/stats/media/mediaTrackStats.ts b/src/webrtc/stats/media/mediaTrackStats.ts index 66475e19ce6..0071e749486 100644 --- a/src/webrtc/stats/media/mediaTrackStats.ts +++ b/src/webrtc/stats/media/mediaTrackStats.ts @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +import { AudioConcealment } from "../statsReport"; import { TrackId } from "./mediaTrackHandler"; export interface PacketLoss { @@ -32,7 +33,14 @@ export interface Bitrate { */ upload: number; } +export interface ConcealedAudio { + /** + * durtation in ms + */ + duration: number; + ratio: number; +} export interface Resolution { width: number; height: number; @@ -44,6 +52,7 @@ export class MediaTrackStats { private loss: PacketLoss = { packetsTotal: 0, packetsLost: 0, isDownloadStream: false }; private bitrate: Bitrate = { download: 0, upload: 0 }; private resolution: Resolution = { width: -1, height: -1 }; + private audioConcealment: AudioConcealment = { ratio: 0, concealedAudio: 0, totalAudioDuration: 0 }; private framerate = 0; private jitter = 0; private codec = ""; @@ -61,8 +70,8 @@ export class MediaTrackStats { return this.type; } - public setLoss(loos: PacketLoss): void { - this.loss = loos; + public setLoss(loss: PacketLoss): void { + this.loss = loss; } public getLoss(): PacketLoss { @@ -152,4 +161,23 @@ export class MediaTrackStats { public getJitter(): number { return this.jitter; } + + /** + * Audio concealment ration (conceled duration / total duration) + */ + public setConcealedAudioDuration(duration: number): void { + this.audioConcealment.concealedAudio = duration; + } + + public setConcealedAudioRatio(ratio: number): void { + this.audioConcealment.ratio = ratio; + } + + public setTrackDuration(duration: number): void { + this.audioConcealment.totalAudioDuration = duration; + } + + public getAudioConcealment(): AudioConcealment { + return this.audioConcealment; + } } diff --git a/src/webrtc/stats/statsReport.ts b/src/webrtc/stats/statsReport.ts index 64bb6aba440..da52bd9f5da 100644 --- a/src/webrtc/stats/statsReport.ts +++ b/src/webrtc/stats/statsReport.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { ConnectionStatsBandwidth, ConnectionStatsBitrate, PacketLoos } from "./connectionStats"; +import { ConnectionStatsBandwidth, ConnectionStatsBitrate, PacketLoss } from "./connectionStats"; import { TransportStats } from "./transportStats"; import { Resolution } from "./media/mediaTrackStats"; @@ -34,7 +34,8 @@ export interface ByteSentStatsReport extends Map { export interface ConnectionStatsReport { bandwidth: ConnectionStatsBandwidth; bitrate: ConnectionStatsBitrate; - packetLoss: PacketLoos; + packetLoss: PacketLoss; + audioConcealment: AudioConcealment; resolution: ResolutionMap; framerate: FramerateMap; codec: CodecMap; @@ -42,6 +43,12 @@ export interface ConnectionStatsReport { transport: TransportStats[]; } +export interface AudioConcealment { + ratio: number; + concealedAudio: number; + totalAudioDuration: number; +} + export interface ResolutionMap { local: Map; remote: Map; diff --git a/src/webrtc/stats/statsReportBuilder.ts b/src/webrtc/stats/statsReportBuilder.ts index eeca4ed4074..931284f5540 100644 --- a/src/webrtc/stats/statsReportBuilder.ts +++ b/src/webrtc/stats/statsReportBuilder.ts @@ -13,7 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -import { CodecMap, ConnectionStatsReport, FramerateMap, ResolutionMap, TrackID } from "./statsReport"; +import { AudioConcealment, CodecMap, ConnectionStatsReport, FramerateMap, ResolutionMap, TrackID } from "./statsReport"; import { MediaTrackStats, Resolution } from "./media/mediaTrackStats"; export class StatsReportBuilder { @@ -38,12 +38,16 @@ export class StatsReportBuilder { const framerates: FramerateMap = { local: new Map(), remote: new Map() }; const codecs: CodecMap = { local: new Map(), remote: new Map() }; const jitter = new Map(); + const audioConcealment = new Map(); let audioBitrateDownload = 0; let audioBitrateUpload = 0; let videoBitrateDownload = 0; let videoBitrateUpload = 0; + let concealedAudio = 0; + let totalAudioDuration = 0; + for (const [trackId, trackStats] of stats) { // process packet loss stats const loss = trackStats.getLoss(); @@ -56,6 +60,11 @@ export class StatsReportBuilder { bitrateDownload += trackStats.getBitrate().download; bitrateUpload += trackStats.getBitrate().upload; + // process audio quality stats + const audioConcealmentForTrack = trackStats.getAudioConcealment(); + concealedAudio += audioConcealmentForTrack.concealedAudio; + totalAudioDuration += audioConcealmentForTrack.totalAudioDuration; + // collect resolutions and framerates if (trackStats.kind === "audio") { audioBitrateDownload += trackStats.getBitrate().download; @@ -70,6 +79,7 @@ export class StatsReportBuilder { codecs[trackStats.getType()].set(trackId, trackStats.getCodec()); if (trackStats.getType() === "remote") { jitter.set(trackId, trackStats.getJitter()); + audioConcealment.set(trackId, trackStats.getAudioConcealment()); } trackStats.resetBitrate(); @@ -98,6 +108,7 @@ export class StatsReportBuilder { download: StatsReportBuilder.calculatePacketLoss(lostPackets.download, totalPackets.download), upload: StatsReportBuilder.calculatePacketLoss(lostPackets.upload, totalPackets.upload), }; + report.audioConcealment = { ratio: concealedAudio / totalAudioDuration, concealedAudio, totalAudioDuration }; report.framerate = framerates; report.resolution = resolutions; report.codec = codecs; diff --git a/src/webrtc/stats/statsReportGatherer.ts b/src/webrtc/stats/statsReportGatherer.ts index 25f9b93c862..acc80e5d4ee 100644 --- a/src/webrtc/stats/statsReportGatherer.ts +++ b/src/webrtc/stats/statsReportGatherer.ts @@ -138,6 +138,7 @@ export class StatsReportGatherer { const ts = this.trackStats.findTransceiverByTrackId(trackStats.trackId); TrackStatsReporter.setTrackStatsState(trackStats, ts); TrackStatsReporter.buildJitter(trackStats, now); + TrackStatsReporter.buildAudioConcealment(trackStats, now); } else if (before) { byteSentStats.set(trackStats.trackId, StatsValueFormatter.getNonNegativeValue(now.bytesSent)); TrackStatsReporter.buildBitrateSend(trackStats, now, before); diff --git a/src/webrtc/stats/trackStatsReporter.ts b/src/webrtc/stats/trackStatsReporter.ts index e243cb32603..0e3591f7dd8 100644 --- a/src/webrtc/stats/trackStatsReporter.ts +++ b/src/webrtc/stats/trackStatsReporter.ts @@ -173,4 +173,14 @@ export class TrackStatsReporter { trackStats.setJitter(-1); } } + + public static buildAudioConcealment(trackStats: MediaTrackStats, statsReport: any): void { + if(statsReport !== "inbound-rtp"){ + return; + } + const msPerSample = Math.round(1000 * statsReport?.totalSamplesDuration / statsReport?.totalSamplesReceived); + trackStats.setTrackDuration(1000 * statsReport?.totalSamplesDuration); + trackStats.setConcealedAudioDuration(msPerSample * statsReport?.concealedSamples); + trackStats.setConcealedAudioRatio(statsReport?.concealedSamples / statsReport?.totalSamplesReceived); + } } From 874cd96aa71d18c1b6e7e22801a9c7418722ca2a Mon Sep 17 00:00:00 2001 From: Timo K Date: Tue, 9 May 2023 20:27:07 +0200 Subject: [PATCH 02/16] audio concealment to summary --- src/webrtc/stats/statsReport.ts | 4 +- src/webrtc/stats/statsReportBuilder.ts | 27 ++++++++---- src/webrtc/stats/statsReportGatherer.ts | 2 +- src/webrtc/stats/summaryStats.ts | 5 ++- src/webrtc/stats/summaryStatsReporter.ts | 45 +++++++++++-------- src/webrtc/stats/trackStatsReporter.ts | 55 ++++++++++++++---------- 6 files changed, 86 insertions(+), 52 deletions(-) diff --git a/src/webrtc/stats/statsReport.ts b/src/webrtc/stats/statsReport.ts index da52bd9f5da..7f5d4fde350 100644 --- a/src/webrtc/stats/statsReport.ts +++ b/src/webrtc/stats/statsReport.ts @@ -35,7 +35,8 @@ export interface ConnectionStatsReport { bandwidth: ConnectionStatsBandwidth; bitrate: ConnectionStatsBitrate; packetLoss: PacketLoss; - audioConcealment: AudioConcealment; + audioConcealment: Map; + totalAudioConcealment: AudioConcealment; resolution: ResolutionMap; framerate: FramerateMap; codec: CodecMap; @@ -77,4 +78,5 @@ export interface SummaryStatsReport { percentageReceivedVideoMedia: number; maxJitter: number; maxPacketLoss: number; + percentageConcealedAudio: number; } diff --git a/src/webrtc/stats/statsReportBuilder.ts b/src/webrtc/stats/statsReportBuilder.ts index 931284f5540..cd2d6009b6e 100644 --- a/src/webrtc/stats/statsReportBuilder.ts +++ b/src/webrtc/stats/statsReportBuilder.ts @@ -45,7 +45,7 @@ export class StatsReportBuilder { let videoBitrateDownload = 0; let videoBitrateUpload = 0; - let concealedAudio = 0; + let totalConcealedAudio = 0; let totalAudioDuration = 0; for (const [trackId, trackStats] of stats) { @@ -60,26 +60,29 @@ export class StatsReportBuilder { bitrateDownload += trackStats.getBitrate().download; bitrateUpload += trackStats.getBitrate().upload; - // process audio quality stats - const audioConcealmentForTrack = trackStats.getAudioConcealment(); - concealedAudio += audioConcealmentForTrack.concealedAudio; - totalAudioDuration += audioConcealmentForTrack.totalAudioDuration; - // collect resolutions and framerates if (trackStats.kind === "audio") { + // process audio quality stats + const audioConcealmentForTrack = trackStats.getAudioConcealment(); + totalConcealedAudio += audioConcealmentForTrack.concealedAudio; + totalAudioDuration += audioConcealmentForTrack.totalAudioDuration; + audioBitrateDownload += trackStats.getBitrate().download; audioBitrateUpload += trackStats.getBitrate().upload; } else { videoBitrateDownload += trackStats.getBitrate().download; videoBitrateUpload += trackStats.getBitrate().upload; } - + resolutions[trackStats.getType()].set(trackId, trackStats.getResolution()); framerates[trackStats.getType()].set(trackId, trackStats.getFramerate()); codecs[trackStats.getType()].set(trackId, trackStats.getCodec()); if (trackStats.getType() === "remote") { jitter.set(trackId, trackStats.getJitter()); - audioConcealment.set(trackId, trackStats.getAudioConcealment()); + // TODO: decide if we even want per track audio concealment + if (trackStats.kind === "audio") { + audioConcealment.set(trackId, trackStats.getAudioConcealment()); + } } trackStats.resetBitrate(); @@ -108,7 +111,13 @@ export class StatsReportBuilder { download: StatsReportBuilder.calculatePacketLoss(lostPackets.download, totalPackets.download), upload: StatsReportBuilder.calculatePacketLoss(lostPackets.upload, totalPackets.upload), }; - report.audioConcealment = { ratio: concealedAudio / totalAudioDuration, concealedAudio, totalAudioDuration }; + report.audioConcealment = audioConcealment; + report.totalAudioConcealment = { + ratio: totalConcealedAudio / totalAudioDuration, + concealedAudio: totalConcealedAudio, + totalAudioDuration, + }; + report.framerate = framerates; report.resolution = resolutions; report.codec = codecs; diff --git a/src/webrtc/stats/statsReportGatherer.ts b/src/webrtc/stats/statsReportGatherer.ts index acc80e5d4ee..9d79fb92c36 100644 --- a/src/webrtc/stats/statsReportGatherer.ts +++ b/src/webrtc/stats/statsReportGatherer.ts @@ -53,7 +53,7 @@ export class StatsReportGatherer { receivedMedia: 0, receivedAudioMedia: 0, receivedVideoMedia: 0, - audioTrackSummary: { count: 0, muted: 0, maxPacketLoss: 0, maxJitter: 0 }, + audioTrackSummary: { count: 0, muted: 0, maxPacketLoss: 0, maxJitter: 0, percentageConcealedAudio: 0 }, videoTrackSummary: { count: 0, muted: 0, maxPacketLoss: 0, maxJitter: 0 }, } as SummaryStats; if (this.isActive) { diff --git a/src/webrtc/stats/summaryStats.ts b/src/webrtc/stats/summaryStats.ts index f708a5bad09..b18ae973b85 100644 --- a/src/webrtc/stats/summaryStats.ts +++ b/src/webrtc/stats/summaryStats.ts @@ -14,7 +14,7 @@ export interface SummaryStats { receivedMedia: number; receivedAudioMedia: number; receivedVideoMedia: number; - audioTrackSummary: TrackSummary; + audioTrackSummary: AudioTrackSummary; videoTrackSummary: TrackSummary; } @@ -24,3 +24,6 @@ export interface TrackSummary { maxJitter: number; maxPacketLoss: number; } +export interface AudioTrackSummary extends TrackSummary { + percentageConcealedAudio: number; +} diff --git a/src/webrtc/stats/summaryStatsReporter.ts b/src/webrtc/stats/summaryStatsReporter.ts index 66f738b1ca5..3d1aacdf87f 100644 --- a/src/webrtc/stats/summaryStatsReporter.ts +++ b/src/webrtc/stats/summaryStatsReporter.ts @@ -14,59 +14,61 @@ import { StatsReportEmitter } from "./statsReportEmitter"; import { SummaryStats } from "./summaryStats"; import { SummaryStatsReport } from "./statsReport"; -interface ReceivedMedia { - audio: number; - video: number; - media: number; +interface SummaryCounter { + receivedAudio: number; + receivedVideo: number; + receivedMedia: number; + concealedAudio: number; } export class SummaryStatsReporter { public constructor(private emitter: StatsReportEmitter) {} public build(summary: SummaryStats[]): void { - const entiretyTracksCount = summary.length; - if (entiretyTracksCount === 0) { + const summaryTotalCount = summary.length; + if (summaryTotalCount === 0) { return; } - const receivedCounter: ReceivedMedia = { audio: 0, video: 0, media: 0 }; + const summaryCounter: SummaryCounter = { receivedAudio: 0, receivedVideo: 0, receivedMedia: 0, concealedAudio:0 }; let maxJitter = 0; let maxPacketLoss = 0; - summary.forEach((stats) => { - this.countTrackListReceivedMedia(receivedCounter, stats); + this.countTrackListReceivedMedia(summaryCounter, stats); + this.countPercentageConcealedAudio(summaryCounter, stats); maxJitter = this.buildMaxJitter(maxJitter, stats); maxPacketLoss = this.buildMaxPacketLoss(maxPacketLoss, stats); }); - + const digitsForPercentages = 5; const report = { - percentageReceivedMedia: Math.round((receivedCounter.media / entiretyTracksCount) * 100) / 100, - percentageReceivedVideoMedia: Math.round((receivedCounter.video / entiretyTracksCount) * 100) / 100, - percentageReceivedAudioMedia: Math.round((receivedCounter.audio / entiretyTracksCount) * 100) / 100, + percentageReceivedMedia: Number((summaryCounter.receivedMedia / summaryTotalCount).toFixed(digitsForPercentages)), + percentageReceivedVideoMedia: Number((summaryCounter.receivedVideo / summaryTotalCount).toFixed(digitsForPercentages)), + percentageReceivedAudioMedia: Number((summaryCounter.receivedAudio / summaryTotalCount).toFixed(digitsForPercentages)), maxJitter, maxPacketLoss, + percentageConcealedAudio: Number((summaryCounter.concealedAudio / summaryTotalCount).toFixed(digitsForPercentages)), } as SummaryStatsReport; this.emitter.emitSummaryStatsReport(report); } - private countTrackListReceivedMedia(counter: ReceivedMedia, stats: SummaryStats): void { + private countTrackListReceivedMedia(counter: SummaryCounter, stats: SummaryStats): void { let hasReceivedAudio = false; let hasReceivedVideo = false; if (stats.receivedAudioMedia > 0 || stats.audioTrackSummary.count === 0) { - counter.audio++; + counter.receivedAudio++; hasReceivedAudio = true; } if (stats.receivedVideoMedia > 0 || stats.videoTrackSummary.count === 0) { - counter.video++; + counter.receivedVideo++; hasReceivedVideo = true; } else { if (stats.videoTrackSummary.muted > 0 && stats.videoTrackSummary.muted === stats.videoTrackSummary.count) { - counter.video++; + counter.receivedVideo++; hasReceivedVideo = true; } } if (hasReceivedVideo && hasReceivedAudio) { - counter.media++; + counter.receivedMedia++; } } @@ -91,4 +93,11 @@ export class SummaryStatsReporter { } return maxPacketLoss; } + + private countPercentageConcealedAudio( + summaryCounter: SummaryCounter, + stats: SummaryStats, + ): void { + summaryCounter.concealedAudio += stats.audioTrackSummary.percentageConcealedAudio; + } } diff --git a/src/webrtc/stats/trackStatsReporter.ts b/src/webrtc/stats/trackStatsReporter.ts index 0e3591f7dd8..90102aada64 100644 --- a/src/webrtc/stats/trackStatsReporter.ts +++ b/src/webrtc/stats/trackStatsReporter.ts @@ -1,6 +1,6 @@ import { MediaTrackStats } from "./media/mediaTrackStats"; import { StatsValueFormatter } from "./statsValueFormatter"; -import { TrackSummary } from "./summaryStats"; +import { AudioTrackSummary, TrackSummary } from "./summaryStats"; export class TrackStatsReporter { public static buildFramerateResolution(trackStats: MediaTrackStats, now: any): void { @@ -137,26 +137,37 @@ export class TrackStatsReporter { } public static buildTrackSummary(trackStatsList: MediaTrackStats[]): { - audioTrackSummary: TrackSummary; + audioTrackSummary: AudioTrackSummary; videoTrackSummary: TrackSummary; } { - const audioTrackSummary = { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0 }; - const videoTrackSummary = { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0 }; - trackStatsList - .filter((t) => t.getType() === "remote") - .forEach((stats) => { - const trackSummary = stats.kind === "video" ? videoTrackSummary : audioTrackSummary; - trackSummary.count++; - if (stats.alive && stats.muted) { - trackSummary.muted++; - } - if (trackSummary.maxJitter < stats.getJitter()) { - trackSummary.maxJitter = stats.getJitter(); - } - if (trackSummary.maxPacketLoss < stats.getLoss().packetsLost) { - trackSummary.maxPacketLoss = stats.getLoss().packetsLost; - } - }); + const videoTrackSummary: TrackSummary = { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0 }; + const audioTrackSummary: AudioTrackSummary = { + count: 0, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + percentageConcealedAudio: 0, + }; + + const remoteTrackList = trackStatsList.filter((t) => t.getType() === "remote"); + remoteTrackList.forEach((stats) => { + const trackSummary = stats.kind === "video" ? videoTrackSummary : audioTrackSummary; + trackSummary.count++; + if (stats.alive && stats.muted) { + trackSummary.muted++; + } + if (trackSummary.maxJitter < stats.getJitter()) { + trackSummary.maxJitter = stats.getJitter(); + } + if (trackSummary.maxPacketLoss < stats.getLoss().packetsLost) { + trackSummary.maxPacketLoss = stats.getLoss().packetsLost; + } + }); + + const audioTrackList = remoteTrackList.filter((t) => t.kind === "audio"); + audioTrackList.forEach((stats) => { + audioTrackSummary.percentageConcealedAudio += stats.getAudioConcealment()?.ratio / audioTrackList.length; + }); return { audioTrackSummary, videoTrackSummary }; } @@ -175,10 +186,10 @@ export class TrackStatsReporter { } public static buildAudioConcealment(trackStats: MediaTrackStats, statsReport: any): void { - if(statsReport !== "inbound-rtp"){ + if (statsReport.type !== "inbound-rtp") { return; - } - const msPerSample = Math.round(1000 * statsReport?.totalSamplesDuration / statsReport?.totalSamplesReceived); + } + const msPerSample = (1000 * statsReport?.totalSamplesDuration) / statsReport?.totalSamplesReceived; trackStats.setTrackDuration(1000 * statsReport?.totalSamplesDuration); trackStats.setConcealedAudioDuration(msPerSample * statsReport?.concealedSamples); trackStats.setConcealedAudioRatio(statsReport?.concealedSamples / statsReport?.totalSamplesReceived); From cb577f49c7d5753868d111852a14d2218f8259ec Mon Sep 17 00:00:00 2001 From: Timo K Date: Wed, 10 May 2023 12:38:04 +0200 Subject: [PATCH 03/16] make ts linter happy --- .../webrtc/stats/summaryStatsReporter.spec.ts | 112 +++++++++++++++--- src/rust-crypto/rust-crypto.ts | 2 +- 2 files changed, 99 insertions(+), 15 deletions(-) diff --git a/spec/unit/webrtc/stats/summaryStatsReporter.spec.ts b/spec/unit/webrtc/stats/summaryStatsReporter.spec.ts index 2692dbf03eb..63f260e03db 100644 --- a/spec/unit/webrtc/stats/summaryStatsReporter.spec.ts +++ b/spec/unit/webrtc/stats/summaryStatsReporter.spec.ts @@ -37,28 +37,52 @@ describe("SummaryStatsReporter", () => { receivedMedia: 10, receivedAudioMedia: 4, receivedVideoMedia: 6, - audioTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, + audioTrackSummary: { + count: 1, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + percentageConcealedAudio: 0, + }, videoTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, }, { receivedMedia: 13, receivedAudioMedia: 0, receivedVideoMedia: 13, - audioTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, + audioTrackSummary: { + count: 1, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + percentageConcealedAudio: 0, + }, videoTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, }, { receivedMedia: 0, receivedAudioMedia: 0, receivedVideoMedia: 0, - audioTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, + audioTrackSummary: { + count: 1, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + percentageConcealedAudio: 0, + }, videoTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, }, { receivedMedia: 15, receivedAudioMedia: 6, receivedVideoMedia: 9, - audioTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, + audioTrackSummary: { + count: 1, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + percentageConcealedAudio: 0, + }, videoTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, }, ]; @@ -78,7 +102,13 @@ describe("SummaryStatsReporter", () => { receivedMedia: 10, receivedAudioMedia: 10, receivedVideoMedia: 0, - audioTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, + audioTrackSummary: { + count: 1, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + percentageConcealedAudio: 0, + }, videoTrackSummary: { count: 1, muted: 1, maxJitter: 0, maxPacketLoss: 0 }, }, ]; @@ -98,7 +128,13 @@ describe("SummaryStatsReporter", () => { receivedMedia: 10, receivedAudioMedia: 10, receivedVideoMedia: 0, - audioTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, + audioTrackSummary: { + count: 1, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + percentageConcealedAudio: 0, + }, videoTrackSummary: { count: 2, muted: 1, maxJitter: 0, maxPacketLoss: 0 }, }, ]; @@ -118,7 +154,13 @@ describe("SummaryStatsReporter", () => { receivedMedia: 100, receivedAudioMedia: 0, receivedVideoMedia: 100, - audioTrackSummary: { count: 1, muted: 1, maxJitter: 0, maxPacketLoss: 0 }, + audioTrackSummary: { + count: 1, + muted: 1, + maxJitter: 0, + maxPacketLoss: 0, + percentageConcealedAudio: 0, + }, videoTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, }, ]; @@ -138,28 +180,52 @@ describe("SummaryStatsReporter", () => { receivedMedia: 1, receivedAudioMedia: 1, receivedVideoMedia: 1, - audioTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, + audioTrackSummary: { + count: 1, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + percentageConcealedAudio: 0, + }, videoTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, }, { receivedMedia: 1, receivedAudioMedia: 1, receivedVideoMedia: 1, - audioTrackSummary: { count: 1, muted: 0, maxJitter: 20, maxPacketLoss: 5 }, + audioTrackSummary: { + count: 1, + muted: 0, + maxJitter: 20, + maxPacketLoss: 5, + percentageConcealedAudio: 0, + }, videoTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, }, { receivedMedia: 1, receivedAudioMedia: 1, receivedVideoMedia: 1, - audioTrackSummary: { count: 1, muted: 0, maxJitter: 2, maxPacketLoss: 5 }, + audioTrackSummary: { + count: 1, + muted: 0, + maxJitter: 2, + maxPacketLoss: 5, + percentageConcealedAudio: 0, + }, videoTrackSummary: { count: 1, muted: 0, maxJitter: 2, maxPacketLoss: 5 }, }, { receivedMedia: 1, receivedAudioMedia: 1, receivedVideoMedia: 1, - audioTrackSummary: { count: 1, muted: 0, maxJitter: 2, maxPacketLoss: 5 }, + audioTrackSummary: { + count: 1, + muted: 0, + maxJitter: 2, + maxPacketLoss: 5, + percentageConcealedAudio: 0, + }, videoTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 40 }, }, ]; @@ -179,7 +245,13 @@ describe("SummaryStatsReporter", () => { receivedMedia: 10, receivedAudioMedia: 0, receivedVideoMedia: 10, - audioTrackSummary: { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, + audioTrackSummary: { + count: 0, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + percentageConcealedAudio: 0, + }, videoTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, }, ]; @@ -199,7 +271,13 @@ describe("SummaryStatsReporter", () => { receivedMedia: 1, receivedAudioMedia: 22, receivedVideoMedia: 0, - audioTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, + audioTrackSummary: { + count: 1, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + percentageConcealedAudio: 0, + }, videoTrackSummary: { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, }, ]; @@ -219,7 +297,13 @@ describe("SummaryStatsReporter", () => { receivedMedia: 0, receivedAudioMedia: 0, receivedVideoMedia: 0, - audioTrackSummary: { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, + audioTrackSummary: { + count: 0, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + percentageConcealedAudio: 0, + }, videoTrackSummary: { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, }, ]; diff --git a/src/rust-crypto/rust-crypto.ts b/src/rust-crypto/rust-crypto.ts index 0d5b4a4f30e..d5ad87eb63a 100644 --- a/src/rust-crypto/rust-crypto.ts +++ b/src/rust-crypto/rust-crypto.ts @@ -331,7 +331,7 @@ export class RustCrypto implements CryptoBackend { events ? JSON.stringify(events) : "[]", devices, oneTimeKeysCounts, - unusedFallbackKeys, + unusedFallbackKeys ?? new Set(), ); // receiveSyncChanges returns a JSON-encoded list of decrypted to-device messages. From 8ce978368be1ead105805cbb55a576125b964aa5 Mon Sep 17 00:00:00 2001 From: Timo K Date: Wed, 10 May 2023 13:09:22 +0200 Subject: [PATCH 04/16] format and rename --- .../webrtc/stats/summaryStatsReporter.spec.ts | 112 +++--------------- src/webrtc/stats/statsReportGatherer.ts | 2 +- src/webrtc/stats/summaryStats.ts | 2 +- src/webrtc/stats/summaryStatsReporter.ts | 2 +- src/webrtc/stats/trackStatsReporter.ts | 4 +- 5 files changed, 19 insertions(+), 103 deletions(-) diff --git a/spec/unit/webrtc/stats/summaryStatsReporter.spec.ts b/spec/unit/webrtc/stats/summaryStatsReporter.spec.ts index 63f260e03db..7b95c6b794f 100644 --- a/spec/unit/webrtc/stats/summaryStatsReporter.spec.ts +++ b/spec/unit/webrtc/stats/summaryStatsReporter.spec.ts @@ -37,52 +37,28 @@ describe("SummaryStatsReporter", () => { receivedMedia: 10, receivedAudioMedia: 4, receivedVideoMedia: 6, - audioTrackSummary: { - count: 1, - muted: 0, - maxJitter: 0, - maxPacketLoss: 0, - percentageConcealedAudio: 0, - }, + audioTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0, concealedAudioRatio: 0 }, videoTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, }, { receivedMedia: 13, receivedAudioMedia: 0, receivedVideoMedia: 13, - audioTrackSummary: { - count: 1, - muted: 0, - maxJitter: 0, - maxPacketLoss: 0, - percentageConcealedAudio: 0, - }, + audioTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0, concealedAudioRatio: 0 }, videoTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, }, { receivedMedia: 0, receivedAudioMedia: 0, receivedVideoMedia: 0, - audioTrackSummary: { - count: 1, - muted: 0, - maxJitter: 0, - maxPacketLoss: 0, - percentageConcealedAudio: 0, - }, + audioTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0, concealedAudioRatio: 0 }, videoTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, }, { receivedMedia: 15, receivedAudioMedia: 6, receivedVideoMedia: 9, - audioTrackSummary: { - count: 1, - muted: 0, - maxJitter: 0, - maxPacketLoss: 0, - percentageConcealedAudio: 0, - }, + audioTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0, concealedAudioRatio: 0 }, videoTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, }, ]; @@ -102,13 +78,7 @@ describe("SummaryStatsReporter", () => { receivedMedia: 10, receivedAudioMedia: 10, receivedVideoMedia: 0, - audioTrackSummary: { - count: 1, - muted: 0, - maxJitter: 0, - maxPacketLoss: 0, - percentageConcealedAudio: 0, - }, + audioTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0, concealedAudioRatio: 0 }, videoTrackSummary: { count: 1, muted: 1, maxJitter: 0, maxPacketLoss: 0 }, }, ]; @@ -128,13 +98,7 @@ describe("SummaryStatsReporter", () => { receivedMedia: 10, receivedAudioMedia: 10, receivedVideoMedia: 0, - audioTrackSummary: { - count: 1, - muted: 0, - maxJitter: 0, - maxPacketLoss: 0, - percentageConcealedAudio: 0, - }, + audioTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0, concealedAudioRatio: 0 }, videoTrackSummary: { count: 2, muted: 1, maxJitter: 0, maxPacketLoss: 0 }, }, ]; @@ -154,13 +118,7 @@ describe("SummaryStatsReporter", () => { receivedMedia: 100, receivedAudioMedia: 0, receivedVideoMedia: 100, - audioTrackSummary: { - count: 1, - muted: 1, - maxJitter: 0, - maxPacketLoss: 0, - percentageConcealedAudio: 0, - }, + audioTrackSummary: { count: 1, muted: 1, maxJitter: 0, maxPacketLoss: 0, concealedAudioRatio: 0 }, videoTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, }, ]; @@ -180,52 +138,28 @@ describe("SummaryStatsReporter", () => { receivedMedia: 1, receivedAudioMedia: 1, receivedVideoMedia: 1, - audioTrackSummary: { - count: 1, - muted: 0, - maxJitter: 0, - maxPacketLoss: 0, - percentageConcealedAudio: 0, - }, + audioTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0, concealedAudioRatio: 0 }, videoTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, }, { receivedMedia: 1, receivedAudioMedia: 1, receivedVideoMedia: 1, - audioTrackSummary: { - count: 1, - muted: 0, - maxJitter: 20, - maxPacketLoss: 5, - percentageConcealedAudio: 0, - }, + audioTrackSummary: { count: 1, muted: 0, maxJitter: 20, maxPacketLoss: 5, concealedAudioRatio: 0 }, videoTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, }, { receivedMedia: 1, receivedAudioMedia: 1, receivedVideoMedia: 1, - audioTrackSummary: { - count: 1, - muted: 0, - maxJitter: 2, - maxPacketLoss: 5, - percentageConcealedAudio: 0, - }, + audioTrackSummary: { count: 1, muted: 0, maxJitter: 2, maxPacketLoss: 5, concealedAudioRatio: 0 }, videoTrackSummary: { count: 1, muted: 0, maxJitter: 2, maxPacketLoss: 5 }, }, { receivedMedia: 1, receivedAudioMedia: 1, receivedVideoMedia: 1, - audioTrackSummary: { - count: 1, - muted: 0, - maxJitter: 2, - maxPacketLoss: 5, - percentageConcealedAudio: 0, - }, + audioTrackSummary: { count: 1, muted: 0, maxJitter: 2, maxPacketLoss: 5, concealedAudioRatio: 0 }, videoTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 40 }, }, ]; @@ -245,13 +179,7 @@ describe("SummaryStatsReporter", () => { receivedMedia: 10, receivedAudioMedia: 0, receivedVideoMedia: 10, - audioTrackSummary: { - count: 0, - muted: 0, - maxJitter: 0, - maxPacketLoss: 0, - percentageConcealedAudio: 0, - }, + audioTrackSummary: { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0, concealedAudioRatio: 0 }, videoTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, }, ]; @@ -271,13 +199,7 @@ describe("SummaryStatsReporter", () => { receivedMedia: 1, receivedAudioMedia: 22, receivedVideoMedia: 0, - audioTrackSummary: { - count: 1, - muted: 0, - maxJitter: 0, - maxPacketLoss: 0, - percentageConcealedAudio: 0, - }, + audioTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0, concealedAudioRatio: 0 }, videoTrackSummary: { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, }, ]; @@ -297,13 +219,7 @@ describe("SummaryStatsReporter", () => { receivedMedia: 0, receivedAudioMedia: 0, receivedVideoMedia: 0, - audioTrackSummary: { - count: 0, - muted: 0, - maxJitter: 0, - maxPacketLoss: 0, - percentageConcealedAudio: 0, - }, + audioTrackSummary: { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0, concealedAudioRatio: 0 }, videoTrackSummary: { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, }, ]; diff --git a/src/webrtc/stats/statsReportGatherer.ts b/src/webrtc/stats/statsReportGatherer.ts index 9d79fb92c36..d8c1f3f01f1 100644 --- a/src/webrtc/stats/statsReportGatherer.ts +++ b/src/webrtc/stats/statsReportGatherer.ts @@ -53,7 +53,7 @@ export class StatsReportGatherer { receivedMedia: 0, receivedAudioMedia: 0, receivedVideoMedia: 0, - audioTrackSummary: { count: 0, muted: 0, maxPacketLoss: 0, maxJitter: 0, percentageConcealedAudio: 0 }, + audioTrackSummary: { count: 0, muted: 0, maxPacketLoss: 0, maxJitter: 0, concealedAudioRatio: 0 }, videoTrackSummary: { count: 0, muted: 0, maxPacketLoss: 0, maxJitter: 0 }, } as SummaryStats; if (this.isActive) { diff --git a/src/webrtc/stats/summaryStats.ts b/src/webrtc/stats/summaryStats.ts index b18ae973b85..f4c7e9bbe0d 100644 --- a/src/webrtc/stats/summaryStats.ts +++ b/src/webrtc/stats/summaryStats.ts @@ -25,5 +25,5 @@ export interface TrackSummary { maxPacketLoss: number; } export interface AudioTrackSummary extends TrackSummary { - percentageConcealedAudio: number; + concealedAudioRatio: number; } diff --git a/src/webrtc/stats/summaryStatsReporter.ts b/src/webrtc/stats/summaryStatsReporter.ts index 3d1aacdf87f..15375ad571f 100644 --- a/src/webrtc/stats/summaryStatsReporter.ts +++ b/src/webrtc/stats/summaryStatsReporter.ts @@ -98,6 +98,6 @@ export class SummaryStatsReporter { summaryCounter: SummaryCounter, stats: SummaryStats, ): void { - summaryCounter.concealedAudio += stats.audioTrackSummary.percentageConcealedAudio; + summaryCounter.concealedAudio += stats.audioTrackSummary.concealedAudioRatio; } } diff --git a/src/webrtc/stats/trackStatsReporter.ts b/src/webrtc/stats/trackStatsReporter.ts index 90102aada64..06403016b8c 100644 --- a/src/webrtc/stats/trackStatsReporter.ts +++ b/src/webrtc/stats/trackStatsReporter.ts @@ -146,7 +146,7 @@ export class TrackStatsReporter { muted: 0, maxJitter: 0, maxPacketLoss: 0, - percentageConcealedAudio: 0, + concealedAudioRatio: 0, }; const remoteTrackList = trackStatsList.filter((t) => t.getType() === "remote"); @@ -166,7 +166,7 @@ export class TrackStatsReporter { const audioTrackList = remoteTrackList.filter((t) => t.kind === "audio"); audioTrackList.forEach((stats) => { - audioTrackSummary.percentageConcealedAudio += stats.getAudioConcealment()?.ratio / audioTrackList.length; + audioTrackSummary.concealedAudioRatio += stats.getAudioConcealment()?.ratio / audioTrackList.length; }); return { audioTrackSummary, videoTrackSummary }; } From a6a1aadb8ab965afe08db059e6277cad279e62e4 Mon Sep 17 00:00:00 2001 From: Timo K Date: Wed, 10 May 2023 14:59:42 +0200 Subject: [PATCH 05/16] fix and add tests --- .../unit/webrtc/stats/statsReportBuilder.spec.ts | 9 +++++++++ .../webrtc/stats/statsReportGatherer.spec.ts | 4 ++-- .../webrtc/stats/summaryStatsReporter.spec.ts | 12 ++++++++++-- .../unit/webrtc/stats/trackStatsReporter.spec.ts | 9 ++++++++- src/webrtc/stats/media/mediaTrackStats.ts | 16 ++++++---------- src/webrtc/stats/trackStatsReporter.ts | 6 +++--- 6 files changed, 38 insertions(+), 18 deletions(-) diff --git a/spec/unit/webrtc/stats/statsReportBuilder.spec.ts b/spec/unit/webrtc/stats/statsReportBuilder.spec.ts index fd75c90546d..389e8262b33 100644 --- a/spec/unit/webrtc/stats/statsReportBuilder.spec.ts +++ b/spec/unit/webrtc/stats/statsReportBuilder.spec.ts @@ -91,6 +91,14 @@ describe("StatsReportBuilder", () => { ["REMOTE_AUDIO_TRACK_ID", 0.1], ["REMOTE_VIDEO_TRACK_ID", 50], ]), + audioConcealment: new Map([ + ["REMOTE_AUDIO_TRACK_ID", { concealedAudio: 3000, ratio: 1 / 20, totalAudioDuration: 3000 * 20 }], + ]), + totalAudioConcealment: { + concealedAudio: 3000, + ratio: 0.05, + totalAudioDuration: 60000, + }, }); }); }); @@ -104,6 +112,7 @@ describe("StatsReportBuilder", () => { remoteAudioTrack.setLoss({ packetsTotal: 20, packetsLost: 0, isDownloadStream: true }); remoteAudioTrack.setBitrate({ download: 4000, upload: 0 }); remoteAudioTrack.setJitter(0.1); + remoteAudioTrack.setAudioConcealment(3000,3000 * 20); localVideoTrack.setCodec("v8"); localVideoTrack.setLoss({ packetsTotal: 30, packetsLost: 6, isDownloadStream: false }); diff --git a/spec/unit/webrtc/stats/statsReportGatherer.spec.ts b/spec/unit/webrtc/stats/statsReportGatherer.spec.ts index aad12b4a36a..05ac0865904 100644 --- a/spec/unit/webrtc/stats/statsReportGatherer.spec.ts +++ b/spec/unit/webrtc/stats/statsReportGatherer.spec.ts @@ -43,7 +43,7 @@ describe("StatsReportGatherer", () => { receivedMedia: 0, receivedAudioMedia: 0, receivedVideoMedia: 0, - audioTrackSummary: { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, + audioTrackSummary: { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0, concealedAudioRatio: 0 }, videoTrackSummary: { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, }); expect(collector.getActive()).toBeTruthy(); @@ -74,7 +74,7 @@ describe("StatsReportGatherer", () => { receivedMedia: 0, receivedAudioMedia: 0, receivedVideoMedia: 0, - audioTrackSummary: { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, + audioTrackSummary: { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0, concealedAudioRatio: 0 }, videoTrackSummary: { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, }); expect(getStats).toHaveBeenCalled(); diff --git a/spec/unit/webrtc/stats/summaryStatsReporter.spec.ts b/spec/unit/webrtc/stats/summaryStatsReporter.spec.ts index 7b95c6b794f..2df53e74f47 100644 --- a/spec/unit/webrtc/stats/summaryStatsReporter.spec.ts +++ b/spec/unit/webrtc/stats/summaryStatsReporter.spec.ts @@ -44,14 +44,14 @@ describe("SummaryStatsReporter", () => { receivedMedia: 13, receivedAudioMedia: 0, receivedVideoMedia: 13, - audioTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0, concealedAudioRatio: 0 }, + audioTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0, concealedAudioRatio: 5 }, videoTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, }, { receivedMedia: 0, receivedAudioMedia: 0, receivedVideoMedia: 0, - audioTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0, concealedAudioRatio: 0 }, + audioTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0, concealedAudioRatio: 10 }, videoTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, }, { @@ -69,6 +69,7 @@ describe("SummaryStatsReporter", () => { percentageReceivedVideoMedia: 0.75, maxJitter: 0, maxPacketLoss: 0, + percentageConcealedAudio: 3.75, }); }); @@ -89,6 +90,7 @@ describe("SummaryStatsReporter", () => { percentageReceivedVideoMedia: 1, maxJitter: 0, maxPacketLoss: 0, + percentageConcealedAudio: 0, }); }); @@ -109,6 +111,7 @@ describe("SummaryStatsReporter", () => { percentageReceivedVideoMedia: 0, maxJitter: 0, maxPacketLoss: 0, + percentageConcealedAudio: 0, }); }); @@ -129,6 +132,7 @@ describe("SummaryStatsReporter", () => { percentageReceivedVideoMedia: 1, maxJitter: 0, maxPacketLoss: 0, + percentageConcealedAudio: 0, }); }); @@ -170,6 +174,7 @@ describe("SummaryStatsReporter", () => { percentageReceivedVideoMedia: 1, maxJitter: 20, maxPacketLoss: 40, + percentageConcealedAudio: 0, }); }); @@ -190,6 +195,7 @@ describe("SummaryStatsReporter", () => { percentageReceivedVideoMedia: 1, maxJitter: 0, maxPacketLoss: 0, + percentageConcealedAudio: 0, }); }); @@ -210,6 +216,7 @@ describe("SummaryStatsReporter", () => { percentageReceivedVideoMedia: 1, maxJitter: 0, maxPacketLoss: 0, + percentageConcealedAudio: 0, }); }); @@ -230,6 +237,7 @@ describe("SummaryStatsReporter", () => { percentageReceivedVideoMedia: 1, maxJitter: 0, maxPacketLoss: 0, + percentageConcealedAudio: 0, }); }); }); diff --git a/spec/unit/webrtc/stats/trackStatsReporter.spec.ts b/spec/unit/webrtc/stats/trackStatsReporter.spec.ts index 79b1ad680aa..cffb64f57ca 100644 --- a/spec/unit/webrtc/stats/trackStatsReporter.spec.ts +++ b/spec/unit/webrtc/stats/trackStatsReporter.spec.ts @@ -226,6 +226,7 @@ describe("TrackStatsReporter", () => { muted: 0, maxJitter: 0, maxPacketLoss: 0, + concealedAudioRatio: 0, }, videoTrackSummary: { count: 0, @@ -245,6 +246,7 @@ describe("TrackStatsReporter", () => { muted: 0, maxJitter: 0, maxPacketLoss: 0, + concealedAudioRatio: 0, }, videoTrackSummary: { count: 3, @@ -266,6 +268,7 @@ describe("TrackStatsReporter", () => { muted: 1, maxJitter: 0, maxPacketLoss: 0, + concealedAudioRatio: 0, }, videoTrackSummary: { count: 3, @@ -287,6 +290,7 @@ describe("TrackStatsReporter", () => { muted: 0, maxJitter: 0, maxPacketLoss: 0, + concealedAudioRatio: 0, }, videoTrackSummary: { count: 3, @@ -297,7 +301,7 @@ describe("TrackStatsReporter", () => { }); }); - it("and returns summary and build max jitter and packet loss", async () => { + it("and returns summary and build max jitter, packet loss and audio conealment", async () => { const trackStatsList = buildMockTrackStatsList(); // video remote trackStatsList[1].setJitter(12); @@ -311,6 +315,8 @@ describe("TrackStatsReporter", () => { trackStatsList[5].setJitter(15); trackStatsList[2].setLoss({ packetsLost: 5, packetsTotal: 0, isDownloadStream: true }); trackStatsList[5].setLoss({ packetsLost: 0, packetsTotal: 0, isDownloadStream: true }); + trackStatsList[2].setAudioConcealment(220, 2000); + trackStatsList[5].setAudioConcealment(180, 2000); const summary = TrackStatsReporter.buildTrackSummary(trackStatsList); expect(summary).toEqual({ @@ -319,6 +325,7 @@ describe("TrackStatsReporter", () => { muted: 0, maxJitter: 15, maxPacketLoss: 5, + concealedAudioRatio: 0.1, }, videoTrackSummary: { count: 3, diff --git a/src/webrtc/stats/media/mediaTrackStats.ts b/src/webrtc/stats/media/mediaTrackStats.ts index 0071e749486..9422b978350 100644 --- a/src/webrtc/stats/media/mediaTrackStats.ts +++ b/src/webrtc/stats/media/mediaTrackStats.ts @@ -165,16 +165,12 @@ export class MediaTrackStats { /** * Audio concealment ration (conceled duration / total duration) */ - public setConcealedAudioDuration(duration: number): void { - this.audioConcealment.concealedAudio = duration; - } - - public setConcealedAudioRatio(ratio: number): void { - this.audioConcealment.ratio = ratio; - } - - public setTrackDuration(duration: number): void { - this.audioConcealment.totalAudioDuration = duration; + public setAudioConcealment(concealedAudioDuration: number, totalAudioDuration: number): void { + this.audioConcealment.concealedAudio = concealedAudioDuration; + this.audioConcealment.totalAudioDuration = totalAudioDuration; + if (totalAudioDuration > 0) { + this.audioConcealment.ratio = concealedAudioDuration / totalAudioDuration; + } } public getAudioConcealment(): AudioConcealment { diff --git a/src/webrtc/stats/trackStatsReporter.ts b/src/webrtc/stats/trackStatsReporter.ts index 06403016b8c..7b14db3c758 100644 --- a/src/webrtc/stats/trackStatsReporter.ts +++ b/src/webrtc/stats/trackStatsReporter.ts @@ -190,8 +190,8 @@ export class TrackStatsReporter { return; } const msPerSample = (1000 * statsReport?.totalSamplesDuration) / statsReport?.totalSamplesReceived; - trackStats.setTrackDuration(1000 * statsReport?.totalSamplesDuration); - trackStats.setConcealedAudioDuration(msPerSample * statsReport?.concealedSamples); - trackStats.setConcealedAudioRatio(statsReport?.concealedSamples / statsReport?.totalSamplesReceived); + const concealedAudioDuration = msPerSample * statsReport?.concealedSamples; + const totalAudioDuration = 1000 * statsReport?.totalSamplesDuration; + trackStats.setAudioConcealment(concealedAudioDuration, totalAudioDuration); } } From ee54c8d28f27657f7dce44812257eafb2714cad2 Mon Sep 17 00:00:00 2001 From: Timo K Date: Wed, 10 May 2023 16:08:52 +0200 Subject: [PATCH 06/16] make it prettier! --- .../webrtc/stats/statsReportBuilder.spec.ts | 2 +- src/webrtc/stats/statsReportBuilder.ts | 4 +-- src/webrtc/stats/summaryStatsReporter.ts | 30 ++++++++++++------- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/spec/unit/webrtc/stats/statsReportBuilder.spec.ts b/spec/unit/webrtc/stats/statsReportBuilder.spec.ts index 389e8262b33..74ca71df2e2 100644 --- a/spec/unit/webrtc/stats/statsReportBuilder.spec.ts +++ b/spec/unit/webrtc/stats/statsReportBuilder.spec.ts @@ -112,7 +112,7 @@ describe("StatsReportBuilder", () => { remoteAudioTrack.setLoss({ packetsTotal: 20, packetsLost: 0, isDownloadStream: true }); remoteAudioTrack.setBitrate({ download: 4000, upload: 0 }); remoteAudioTrack.setJitter(0.1); - remoteAudioTrack.setAudioConcealment(3000,3000 * 20); + remoteAudioTrack.setAudioConcealment(3000, 3000 * 20); localVideoTrack.setCodec("v8"); localVideoTrack.setLoss({ packetsTotal: 30, packetsLost: 6, isDownloadStream: false }); diff --git a/src/webrtc/stats/statsReportBuilder.ts b/src/webrtc/stats/statsReportBuilder.ts index cd2d6009b6e..eddddf091ea 100644 --- a/src/webrtc/stats/statsReportBuilder.ts +++ b/src/webrtc/stats/statsReportBuilder.ts @@ -66,14 +66,14 @@ export class StatsReportBuilder { const audioConcealmentForTrack = trackStats.getAudioConcealment(); totalConcealedAudio += audioConcealmentForTrack.concealedAudio; totalAudioDuration += audioConcealmentForTrack.totalAudioDuration; - + audioBitrateDownload += trackStats.getBitrate().download; audioBitrateUpload += trackStats.getBitrate().upload; } else { videoBitrateDownload += trackStats.getBitrate().download; videoBitrateUpload += trackStats.getBitrate().upload; } - + resolutions[trackStats.getType()].set(trackId, trackStats.getResolution()); framerates[trackStats.getType()].set(trackId, trackStats.getFramerate()); codecs[trackStats.getType()].set(trackId, trackStats.getCodec()); diff --git a/src/webrtc/stats/summaryStatsReporter.ts b/src/webrtc/stats/summaryStatsReporter.ts index 15375ad571f..a289d2ade7b 100644 --- a/src/webrtc/stats/summaryStatsReporter.ts +++ b/src/webrtc/stats/summaryStatsReporter.ts @@ -29,7 +29,12 @@ export class SummaryStatsReporter { if (summaryTotalCount === 0) { return; } - const summaryCounter: SummaryCounter = { receivedAudio: 0, receivedVideo: 0, receivedMedia: 0, concealedAudio:0 }; + const summaryCounter: SummaryCounter = { + receivedAudio: 0, + receivedVideo: 0, + receivedMedia: 0, + concealedAudio: 0, + }; let maxJitter = 0; let maxPacketLoss = 0; summary.forEach((stats) => { @@ -38,14 +43,22 @@ export class SummaryStatsReporter { maxJitter = this.buildMaxJitter(maxJitter, stats); maxPacketLoss = this.buildMaxPacketLoss(maxPacketLoss, stats); }); - const digitsForPercentages = 5; + const decimalPlaces = 5; const report = { - percentageReceivedMedia: Number((summaryCounter.receivedMedia / summaryTotalCount).toFixed(digitsForPercentages)), - percentageReceivedVideoMedia: Number((summaryCounter.receivedVideo / summaryTotalCount).toFixed(digitsForPercentages)), - percentageReceivedAudioMedia: Number((summaryCounter.receivedAudio / summaryTotalCount).toFixed(digitsForPercentages)), + percentageReceivedMedia: Number( + (summaryCounter.receivedMedia / summaryTotalCount).toFixed(decimalPlaces), + ), + percentageReceivedVideoMedia: Number( + (summaryCounter.receivedVideo / summaryTotalCount).toFixed(decimalPlaces), + ), + percentageReceivedAudioMedia: Number( + (summaryCounter.receivedAudio / summaryTotalCount).toFixed(decimalPlaces), + ), maxJitter, maxPacketLoss, - percentageConcealedAudio: Number((summaryCounter.concealedAudio / summaryTotalCount).toFixed(digitsForPercentages)), + percentageConcealedAudio: Number( + (summaryCounter.concealedAudio / summaryTotalCount).toFixed(decimalPlaces), + ), } as SummaryStatsReport; this.emitter.emitSummaryStatsReport(report); } @@ -94,10 +107,7 @@ export class SummaryStatsReporter { return maxPacketLoss; } - private countPercentageConcealedAudio( - summaryCounter: SummaryCounter, - stats: SummaryStats, - ): void { + private countPercentageConcealedAudio(summaryCounter: SummaryCounter, stats: SummaryStats): void { summaryCounter.concealedAudio += stats.audioTrackSummary.concealedAudioRatio; } } From fb3bdc39ecfdb12c0d6c3a3dd6e346d771517fde Mon Sep 17 00:00:00 2001 From: Timo K Date: Wed, 10 May 2023 16:15:42 +0200 Subject: [PATCH 07/16] we can make it even prettier ?! --- src/webrtc/stats/summaryStatsReporter.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/webrtc/stats/summaryStatsReporter.ts b/src/webrtc/stats/summaryStatsReporter.ts index a289d2ade7b..bfd29d9889d 100644 --- a/src/webrtc/stats/summaryStatsReporter.ts +++ b/src/webrtc/stats/summaryStatsReporter.ts @@ -45,9 +45,7 @@ export class SummaryStatsReporter { }); const decimalPlaces = 5; const report = { - percentageReceivedMedia: Number( - (summaryCounter.receivedMedia / summaryTotalCount).toFixed(decimalPlaces), - ), + percentageReceivedMedia: Number((summaryCounter.receivedMedia / summaryTotalCount).toFixed(decimalPlaces)), percentageReceivedVideoMedia: Number( (summaryCounter.receivedVideo / summaryTotalCount).toFixed(decimalPlaces), ), From 31c03d45dab30f7148dc205aa764a858ddc8d716 Mon Sep 17 00:00:00 2001 From: Timo K Date: Fri, 12 May 2023 12:01:27 +0200 Subject: [PATCH 08/16] review --- .../webrtc/stats/statsReportBuilder.spec.ts | 2 +- src/rust-crypto/rust-crypto.ts | 2 +- src/webrtc/stats/media/mediaTrackStats.ts | 2 +- src/webrtc/stats/statsReportGatherer.ts | 4 +-- src/webrtc/stats/summaryStats.ts | 9 +++--- src/webrtc/stats/summaryStatsReporter.ts | 13 ++++++--- src/webrtc/stats/trackStatsReporter.ts | 28 +++++++++++++------ 7 files changed, 37 insertions(+), 23 deletions(-) diff --git a/spec/unit/webrtc/stats/statsReportBuilder.spec.ts b/spec/unit/webrtc/stats/statsReportBuilder.spec.ts index 74ca71df2e2..f9f1f44e552 100644 --- a/spec/unit/webrtc/stats/statsReportBuilder.spec.ts +++ b/spec/unit/webrtc/stats/statsReportBuilder.spec.ts @@ -97,7 +97,7 @@ describe("StatsReportBuilder", () => { totalAudioConcealment: { concealedAudio: 3000, ratio: 0.05, - totalAudioDuration: 60000, + totalAudioDuration: (1 / 0.05) * 3000, }, }); }); diff --git a/src/rust-crypto/rust-crypto.ts b/src/rust-crypto/rust-crypto.ts index d5ad87eb63a..0d5b4a4f30e 100644 --- a/src/rust-crypto/rust-crypto.ts +++ b/src/rust-crypto/rust-crypto.ts @@ -331,7 +331,7 @@ export class RustCrypto implements CryptoBackend { events ? JSON.stringify(events) : "[]", devices, oneTimeKeysCounts, - unusedFallbackKeys ?? new Set(), + unusedFallbackKeys, ); // receiveSyncChanges returns a JSON-encoded list of decrypted to-device messages. diff --git a/src/webrtc/stats/media/mediaTrackStats.ts b/src/webrtc/stats/media/mediaTrackStats.ts index 9422b978350..4df595c313c 100644 --- a/src/webrtc/stats/media/mediaTrackStats.ts +++ b/src/webrtc/stats/media/mediaTrackStats.ts @@ -35,7 +35,7 @@ export interface Bitrate { } export interface ConcealedAudio { /** - * durtation in ms + * duration in ms */ duration: number; diff --git a/src/webrtc/stats/statsReportGatherer.ts b/src/webrtc/stats/statsReportGatherer.ts index d8c1f3f01f1..e5146122fb6 100644 --- a/src/webrtc/stats/statsReportGatherer.ts +++ b/src/webrtc/stats/statsReportGatherer.ts @@ -53,8 +53,8 @@ export class StatsReportGatherer { receivedMedia: 0, receivedAudioMedia: 0, receivedVideoMedia: 0, - audioTrackSummary: { count: 0, muted: 0, maxPacketLoss: 0, maxJitter: 0, concealedAudioRatio: 0 }, - videoTrackSummary: { count: 0, muted: 0, maxPacketLoss: 0, maxJitter: 0 }, + audioTrackSummary: { count: 0, muted: 0, maxPacketLoss: 0, maxJitter: 0, concealedAudio: 0, totalAudio: 0 }, + videoTrackSummary: { count: 0, muted: 0, maxPacketLoss: 0, maxJitter: 0, concealedAudio: 0, totalAudio: 0 }, } as SummaryStats; if (this.isActive) { const statsPromise = this.pc.getStats(); diff --git a/src/webrtc/stats/summaryStats.ts b/src/webrtc/stats/summaryStats.ts index f4c7e9bbe0d..072d9c72353 100644 --- a/src/webrtc/stats/summaryStats.ts +++ b/src/webrtc/stats/summaryStats.ts @@ -14,7 +14,7 @@ export interface SummaryStats { receivedMedia: number; receivedAudioMedia: number; receivedVideoMedia: number; - audioTrackSummary: AudioTrackSummary; + audioTrackSummary: TrackSummary; videoTrackSummary: TrackSummary; } @@ -23,7 +23,6 @@ export interface TrackSummary { muted: number; maxJitter: number; maxPacketLoss: number; -} -export interface AudioTrackSummary extends TrackSummary { - concealedAudioRatio: number; -} + concealedAudio: number; + totalAudio: number; +} \ No newline at end of file diff --git a/src/webrtc/stats/summaryStatsReporter.ts b/src/webrtc/stats/summaryStatsReporter.ts index bfd29d9889d..8ad0c5591d3 100644 --- a/src/webrtc/stats/summaryStatsReporter.ts +++ b/src/webrtc/stats/summaryStatsReporter.ts @@ -19,6 +19,7 @@ interface SummaryCounter { receivedVideo: number; receivedMedia: number; concealedAudio: number; + totalAudio: number; } export class SummaryStatsReporter { @@ -34,12 +35,13 @@ export class SummaryStatsReporter { receivedVideo: 0, receivedMedia: 0, concealedAudio: 0, + totalAudio: 0, }; let maxJitter = 0; let maxPacketLoss = 0; summary.forEach((stats) => { this.countTrackListReceivedMedia(summaryCounter, stats); - this.countPercentageConcealedAudio(summaryCounter, stats); + this.countConcealedAudio(summaryCounter, stats); maxJitter = this.buildMaxJitter(maxJitter, stats); maxPacketLoss = this.buildMaxPacketLoss(maxPacketLoss, stats); }); @@ -55,7 +57,9 @@ export class SummaryStatsReporter { maxJitter, maxPacketLoss, percentageConcealedAudio: Number( - (summaryCounter.concealedAudio / summaryTotalCount).toFixed(decimalPlaces), + summaryCounter.totalAudio > 0 + ? (summaryCounter.concealedAudio / summaryCounter.totalAudio).toFixed(decimalPlaces) + : 0, ), } as SummaryStatsReport; this.emitter.emitSummaryStatsReport(report); @@ -105,7 +109,8 @@ export class SummaryStatsReporter { return maxPacketLoss; } - private countPercentageConcealedAudio(summaryCounter: SummaryCounter, stats: SummaryStats): void { - summaryCounter.concealedAudio += stats.audioTrackSummary.concealedAudioRatio; + private countConcealedAudio(summaryCounter: SummaryCounter, stats: SummaryStats): void { + summaryCounter.concealedAudio += stats.audioTrackSummary.concealedAudio; + summaryCounter.totalAudio += stats.audioTrackSummary.totalAudio; } } diff --git a/src/webrtc/stats/trackStatsReporter.ts b/src/webrtc/stats/trackStatsReporter.ts index 7b14db3c758..75409f26afa 100644 --- a/src/webrtc/stats/trackStatsReporter.ts +++ b/src/webrtc/stats/trackStatsReporter.ts @@ -1,6 +1,6 @@ import { MediaTrackStats } from "./media/mediaTrackStats"; import { StatsValueFormatter } from "./statsValueFormatter"; -import { AudioTrackSummary, TrackSummary } from "./summaryStats"; +import { TrackSummary } from "./summaryStats"; export class TrackStatsReporter { public static buildFramerateResolution(trackStats: MediaTrackStats, now: any): void { @@ -137,19 +137,29 @@ export class TrackStatsReporter { } public static buildTrackSummary(trackStatsList: MediaTrackStats[]): { - audioTrackSummary: AudioTrackSummary; + audioTrackSummary: TrackSummary; videoTrackSummary: TrackSummary; } { - const videoTrackSummary: TrackSummary = { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0 }; - const audioTrackSummary: AudioTrackSummary = { + const videoTrackSummary: TrackSummary = { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0, - concealedAudioRatio: 0, + concealedAudio: 0, + totalAudio: 0, + }; + const audioTrackSummary: TrackSummary = { + count: 0, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + concealedAudio: 0, + totalAudio: 0, }; const remoteTrackList = trackStatsList.filter((t) => t.getType() === "remote"); + const audioTrackList = remoteTrackList.filter((t) => t.kind === "audio"); + remoteTrackList.forEach((stats) => { const trackSummary = stats.kind === "video" ? videoTrackSummary : audioTrackSummary; trackSummary.count++; @@ -162,12 +172,12 @@ export class TrackStatsReporter { if (trackSummary.maxPacketLoss < stats.getLoss().packetsLost) { trackSummary.maxPacketLoss = stats.getLoss().packetsLost; } + if (audioTrackList.length > 0) { + trackSummary.concealedAudio += stats.getAudioConcealment()?.concealedAudio; + trackSummary.totalAudio += stats.getAudioConcealment()?.totalAudioDuration; + } }); - const audioTrackList = remoteTrackList.filter((t) => t.kind === "audio"); - audioTrackList.forEach((stats) => { - audioTrackSummary.concealedAudioRatio += stats.getAudioConcealment()?.ratio / audioTrackList.length; - }); return { audioTrackSummary, videoTrackSummary }; } From dbe458984571d240f409ade6ac0e33a87f40f5ac Mon Sep 17 00:00:00 2001 From: Timo K Date: Fri, 12 May 2023 13:52:05 +0200 Subject: [PATCH 09/16] fix tests --- .../webrtc/stats/statsReportGatherer.spec.ts | 8 +- .../webrtc/stats/summaryStatsReporter.spec.ts | 254 ++++++++++++++++-- .../webrtc/stats/trackStatsReporter.spec.ts | 25 +- 3 files changed, 249 insertions(+), 38 deletions(-) diff --git a/spec/unit/webrtc/stats/statsReportGatherer.spec.ts b/spec/unit/webrtc/stats/statsReportGatherer.spec.ts index 05ac0865904..555a6fc0553 100644 --- a/spec/unit/webrtc/stats/statsReportGatherer.spec.ts +++ b/spec/unit/webrtc/stats/statsReportGatherer.spec.ts @@ -43,8 +43,8 @@ describe("StatsReportGatherer", () => { receivedMedia: 0, receivedAudioMedia: 0, receivedVideoMedia: 0, - audioTrackSummary: { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0, concealedAudioRatio: 0 }, - videoTrackSummary: { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, + audioTrackSummary: { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0,concealedAudio: 0, totalAudio:0 }, + videoTrackSummary: { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0,concealedAudio: 0, totalAudio:0 }, }); expect(collector.getActive()).toBeTruthy(); }); @@ -74,8 +74,8 @@ describe("StatsReportGatherer", () => { receivedMedia: 0, receivedAudioMedia: 0, receivedVideoMedia: 0, - audioTrackSummary: { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0, concealedAudioRatio: 0 }, - videoTrackSummary: { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, + audioTrackSummary: { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0,concealedAudio: 0, totalAudio:0}, + videoTrackSummary: { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0,concealedAudio: 0, totalAudio:0 }, }); expect(getStats).toHaveBeenCalled(); expect(collector.getActive()).toBeFalsy(); diff --git a/spec/unit/webrtc/stats/summaryStatsReporter.spec.ts b/spec/unit/webrtc/stats/summaryStatsReporter.spec.ts index 2df53e74f47..117231ee2de 100644 --- a/spec/unit/webrtc/stats/summaryStatsReporter.spec.ts +++ b/spec/unit/webrtc/stats/summaryStatsReporter.spec.ts @@ -37,29 +37,85 @@ describe("SummaryStatsReporter", () => { receivedMedia: 10, receivedAudioMedia: 4, receivedVideoMedia: 6, - audioTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0, concealedAudioRatio: 0 }, - videoTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, + audioTrackSummary: { + count: 1, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + concealedAudio: 0, + totalAudio: 100, + }, + videoTrackSummary: { + count: 1, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + concealedAudio: 0, + totalAudio: 0, + }, }, { receivedMedia: 13, receivedAudioMedia: 0, receivedVideoMedia: 13, - audioTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0, concealedAudioRatio: 5 }, - videoTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, + audioTrackSummary: { + count: 1, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + concealedAudio: 5, + totalAudio: 100, + }, + videoTrackSummary: { + count: 1, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + concealedAudio: 0, + totalAudio: 0, + }, }, { receivedMedia: 0, receivedAudioMedia: 0, receivedVideoMedia: 0, - audioTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0, concealedAudioRatio: 10 }, - videoTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, + audioTrackSummary: { + count: 1, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + concealedAudio: 10, + totalAudio: 100, + }, + videoTrackSummary: { + count: 1, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + concealedAudio: 0, + totalAudio: 0, + }, }, { receivedMedia: 15, receivedAudioMedia: 6, receivedVideoMedia: 9, - audioTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0, concealedAudioRatio: 0 }, - videoTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, + audioTrackSummary: { + count: 1, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + concealedAudio: 0, + totalAudio: 100, + }, + videoTrackSummary: { + count: 1, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + concealedAudio: 0, + totalAudio: 0, + }, }, ]; reporter.build(summary); @@ -69,7 +125,7 @@ describe("SummaryStatsReporter", () => { percentageReceivedVideoMedia: 0.75, maxJitter: 0, maxPacketLoss: 0, - percentageConcealedAudio: 3.75, + percentageConcealedAudio: 0.0375, }); }); @@ -79,8 +135,22 @@ describe("SummaryStatsReporter", () => { receivedMedia: 10, receivedAudioMedia: 10, receivedVideoMedia: 0, - audioTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0, concealedAudioRatio: 0 }, - videoTrackSummary: { count: 1, muted: 1, maxJitter: 0, maxPacketLoss: 0 }, + audioTrackSummary: { + count: 1, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + concealedAudio: 0, + totalAudio: 0, + }, + videoTrackSummary: { + count: 1, + muted: 1, + maxJitter: 0, + maxPacketLoss: 0, + concealedAudio: 0, + totalAudio: 0, + }, }, ]; reporter.build(summary); @@ -100,8 +170,22 @@ describe("SummaryStatsReporter", () => { receivedMedia: 10, receivedAudioMedia: 10, receivedVideoMedia: 0, - audioTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0, concealedAudioRatio: 0 }, - videoTrackSummary: { count: 2, muted: 1, maxJitter: 0, maxPacketLoss: 0 }, + audioTrackSummary: { + count: 1, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + concealedAudio: 0, + totalAudio: 0, + }, + videoTrackSummary: { + count: 2, + muted: 1, + maxJitter: 0, + maxPacketLoss: 0, + concealedAudio: 0, + totalAudio: 0, + }, }, ]; reporter.build(summary); @@ -121,8 +205,22 @@ describe("SummaryStatsReporter", () => { receivedMedia: 100, receivedAudioMedia: 0, receivedVideoMedia: 100, - audioTrackSummary: { count: 1, muted: 1, maxJitter: 0, maxPacketLoss: 0, concealedAudioRatio: 0 }, - videoTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, + audioTrackSummary: { + count: 1, + muted: 1, + maxJitter: 0, + maxPacketLoss: 0, + concealedAudio: 0, + totalAudio: 0, + }, + videoTrackSummary: { + count: 1, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + concealedAudio: 0, + totalAudio: 0, + }, }, ]; reporter.build(summary); @@ -142,29 +240,85 @@ describe("SummaryStatsReporter", () => { receivedMedia: 1, receivedAudioMedia: 1, receivedVideoMedia: 1, - audioTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0, concealedAudioRatio: 0 }, - videoTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, + audioTrackSummary: { + count: 1, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + concealedAudio: 0, + totalAudio: 0, + }, + videoTrackSummary: { + count: 1, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + concealedAudio: 0, + totalAudio: 0, + }, }, { receivedMedia: 1, receivedAudioMedia: 1, receivedVideoMedia: 1, - audioTrackSummary: { count: 1, muted: 0, maxJitter: 20, maxPacketLoss: 5, concealedAudioRatio: 0 }, - videoTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, + audioTrackSummary: { + count: 1, + muted: 0, + maxJitter: 20, + maxPacketLoss: 5, + concealedAudio: 0, + totalAudio: 0, + }, + videoTrackSummary: { + count: 1, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + concealedAudio: 0, + totalAudio: 0, + }, }, { receivedMedia: 1, receivedAudioMedia: 1, receivedVideoMedia: 1, - audioTrackSummary: { count: 1, muted: 0, maxJitter: 2, maxPacketLoss: 5, concealedAudioRatio: 0 }, - videoTrackSummary: { count: 1, muted: 0, maxJitter: 2, maxPacketLoss: 5 }, + audioTrackSummary: { + count: 1, + muted: 0, + maxJitter: 2, + maxPacketLoss: 5, + concealedAudio: 0, + totalAudio: 0, + }, + videoTrackSummary: { + count: 1, + muted: 0, + maxJitter: 2, + maxPacketLoss: 5, + concealedAudio: 0, + totalAudio: 0, + }, }, { receivedMedia: 1, receivedAudioMedia: 1, receivedVideoMedia: 1, - audioTrackSummary: { count: 1, muted: 0, maxJitter: 2, maxPacketLoss: 5, concealedAudioRatio: 0 }, - videoTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 40 }, + audioTrackSummary: { + count: 1, + muted: 0, + maxJitter: 2, + maxPacketLoss: 5, + concealedAudio: 0, + totalAudio: 0, + }, + videoTrackSummary: { + count: 1, + muted: 0, + maxJitter: 0, + maxPacketLoss: 40, + concealedAudio: 0, + totalAudio: 0, + }, }, ]; reporter.build(summary); @@ -184,8 +338,22 @@ describe("SummaryStatsReporter", () => { receivedMedia: 10, receivedAudioMedia: 0, receivedVideoMedia: 10, - audioTrackSummary: { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0, concealedAudioRatio: 0 }, - videoTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, + audioTrackSummary: { + count: 0, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + concealedAudio: 0, + totalAudio: 0, + }, + videoTrackSummary: { + count: 1, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + concealedAudio: 0, + totalAudio: 0, + }, }, ]; reporter.build(summary); @@ -205,8 +373,22 @@ describe("SummaryStatsReporter", () => { receivedMedia: 1, receivedAudioMedia: 22, receivedVideoMedia: 0, - audioTrackSummary: { count: 1, muted: 0, maxJitter: 0, maxPacketLoss: 0, concealedAudioRatio: 0 }, - videoTrackSummary: { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, + audioTrackSummary: { + count: 1, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + concealedAudio: 0, + totalAudio: 0, + }, + videoTrackSummary: { + count: 0, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + concealedAudio: 0, + totalAudio: 0, + }, }, ]; reporter.build(summary); @@ -226,8 +408,22 @@ describe("SummaryStatsReporter", () => { receivedMedia: 0, receivedAudioMedia: 0, receivedVideoMedia: 0, - audioTrackSummary: { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0, concealedAudioRatio: 0 }, - videoTrackSummary: { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0 }, + audioTrackSummary: { + count: 0, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + concealedAudio: 0, + totalAudio: 0, + }, + videoTrackSummary: { + count: 0, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + concealedAudio: 0, + totalAudio: 0, + }, }, ]; reporter.build(summary); diff --git a/spec/unit/webrtc/stats/trackStatsReporter.spec.ts b/spec/unit/webrtc/stats/trackStatsReporter.spec.ts index cffb64f57ca..0c22cdaf6a0 100644 --- a/spec/unit/webrtc/stats/trackStatsReporter.spec.ts +++ b/spec/unit/webrtc/stats/trackStatsReporter.spec.ts @@ -226,13 +226,16 @@ describe("TrackStatsReporter", () => { muted: 0, maxJitter: 0, maxPacketLoss: 0, - concealedAudioRatio: 0, + concealedAudio: 0, + totalAudio: 0, }, videoTrackSummary: { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0, + concealedAudio: 0, + totalAudio: 0, }, }); }); @@ -246,13 +249,16 @@ describe("TrackStatsReporter", () => { muted: 0, maxJitter: 0, maxPacketLoss: 0, - concealedAudioRatio: 0, + concealedAudio: 0, + totalAudio: 0, }, videoTrackSummary: { count: 3, muted: 0, maxJitter: 0, maxPacketLoss: 0, + concealedAudio: 0, + totalAudio: 0, }, }); }); @@ -268,13 +274,16 @@ describe("TrackStatsReporter", () => { muted: 1, maxJitter: 0, maxPacketLoss: 0, - concealedAudioRatio: 0, + concealedAudio: 0, + totalAudio: 0, }, videoTrackSummary: { count: 3, muted: 1, maxJitter: 0, maxPacketLoss: 0, + concealedAudio: 0, + totalAudio: 0, }, }); }); @@ -290,13 +299,16 @@ describe("TrackStatsReporter", () => { muted: 0, maxJitter: 0, maxPacketLoss: 0, - concealedAudioRatio: 0, + concealedAudio: 0, + totalAudio: 0, }, videoTrackSummary: { count: 3, muted: 0, maxJitter: 0, maxPacketLoss: 0, + concealedAudio: 0, + totalAudio: 0, }, }); }); @@ -325,13 +337,16 @@ describe("TrackStatsReporter", () => { muted: 0, maxJitter: 15, maxPacketLoss: 5, - concealedAudioRatio: 0.1, + concealedAudio: 400, + totalAudio: 4000, }, videoTrackSummary: { count: 3, muted: 0, maxJitter: 66, maxPacketLoss: 55, + concealedAudio: 0, + totalAudio: 0, }, }); }); From 8da4dde38d6ba1e31cc3a46a46c6b838b62f3b53 Mon Sep 17 00:00:00 2001 From: Timo K Date: Fri, 12 May 2023 13:59:52 +0200 Subject: [PATCH 10/16] pretty --- .../webrtc/stats/statsReportGatherer.spec.ts | 36 ++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/spec/unit/webrtc/stats/statsReportGatherer.spec.ts b/spec/unit/webrtc/stats/statsReportGatherer.spec.ts index 555a6fc0553..0eb847ce01d 100644 --- a/spec/unit/webrtc/stats/statsReportGatherer.spec.ts +++ b/spec/unit/webrtc/stats/statsReportGatherer.spec.ts @@ -43,8 +43,22 @@ describe("StatsReportGatherer", () => { receivedMedia: 0, receivedAudioMedia: 0, receivedVideoMedia: 0, - audioTrackSummary: { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0,concealedAudio: 0, totalAudio:0 }, - videoTrackSummary: { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0,concealedAudio: 0, totalAudio:0 }, + audioTrackSummary: { + count: 0, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + concealedAudio: 0, + totalAudio: 0, + }, + videoTrackSummary: { + count: 0, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + concealedAudio: 0, + totalAudio: 0, + }, }); expect(collector.getActive()).toBeTruthy(); }); @@ -74,8 +88,22 @@ describe("StatsReportGatherer", () => { receivedMedia: 0, receivedAudioMedia: 0, receivedVideoMedia: 0, - audioTrackSummary: { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0,concealedAudio: 0, totalAudio:0}, - videoTrackSummary: { count: 0, muted: 0, maxJitter: 0, maxPacketLoss: 0,concealedAudio: 0, totalAudio:0 }, + audioTrackSummary: { + count: 0, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + concealedAudio: 0, + totalAudio: 0, + }, + videoTrackSummary: { + count: 0, + muted: 0, + maxJitter: 0, + maxPacketLoss: 0, + concealedAudio: 0, + totalAudio: 0, + }, }); expect(getStats).toHaveBeenCalled(); expect(collector.getActive()).toBeFalsy(); From 01dbc7199eb99211100adda05d46c84a51fd97fb Mon Sep 17 00:00:00 2001 From: Timo K Date: Fri, 12 May 2023 14:03:18 +0200 Subject: [PATCH 11/16] one empty line to ... --- src/webrtc/stats/summaryStats.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webrtc/stats/summaryStats.ts b/src/webrtc/stats/summaryStats.ts index 072d9c72353..e5591749db9 100644 --- a/src/webrtc/stats/summaryStats.ts +++ b/src/webrtc/stats/summaryStats.ts @@ -25,4 +25,4 @@ export interface TrackSummary { maxPacketLoss: number; concealedAudio: number; totalAudio: number; -} \ No newline at end of file +} From a7d4c32c6c4d89660fb3f4f2595be30e77936274 Mon Sep 17 00:00:00 2001 From: Timo K Date: Fri, 12 May 2023 15:00:28 +0200 Subject: [PATCH 12/16] remove ratio in audio concealment (ratio is now done in the summary) --- spec/unit/webrtc/stats/statsReportBuilder.spec.ts | 1 - src/webrtc/stats/media/mediaTrackStats.ts | 5 +---- src/webrtc/stats/statsReport.ts | 1 - src/webrtc/stats/statsReportBuilder.ts | 1 - 4 files changed, 1 insertion(+), 7 deletions(-) diff --git a/spec/unit/webrtc/stats/statsReportBuilder.spec.ts b/spec/unit/webrtc/stats/statsReportBuilder.spec.ts index f9f1f44e552..17063a260a4 100644 --- a/spec/unit/webrtc/stats/statsReportBuilder.spec.ts +++ b/spec/unit/webrtc/stats/statsReportBuilder.spec.ts @@ -96,7 +96,6 @@ describe("StatsReportBuilder", () => { ]), totalAudioConcealment: { concealedAudio: 3000, - ratio: 0.05, totalAudioDuration: (1 / 0.05) * 3000, }, }); diff --git a/src/webrtc/stats/media/mediaTrackStats.ts b/src/webrtc/stats/media/mediaTrackStats.ts index 4df595c313c..7835ceb8a65 100644 --- a/src/webrtc/stats/media/mediaTrackStats.ts +++ b/src/webrtc/stats/media/mediaTrackStats.ts @@ -52,7 +52,7 @@ export class MediaTrackStats { private loss: PacketLoss = { packetsTotal: 0, packetsLost: 0, isDownloadStream: false }; private bitrate: Bitrate = { download: 0, upload: 0 }; private resolution: Resolution = { width: -1, height: -1 }; - private audioConcealment: AudioConcealment = { ratio: 0, concealedAudio: 0, totalAudioDuration: 0 }; + private audioConcealment: AudioConcealment = { concealedAudio: 0, totalAudioDuration: 0 }; private framerate = 0; private jitter = 0; private codec = ""; @@ -168,9 +168,6 @@ export class MediaTrackStats { public setAudioConcealment(concealedAudioDuration: number, totalAudioDuration: number): void { this.audioConcealment.concealedAudio = concealedAudioDuration; this.audioConcealment.totalAudioDuration = totalAudioDuration; - if (totalAudioDuration > 0) { - this.audioConcealment.ratio = concealedAudioDuration / totalAudioDuration; - } } public getAudioConcealment(): AudioConcealment { diff --git a/src/webrtc/stats/statsReport.ts b/src/webrtc/stats/statsReport.ts index 7f5d4fde350..67fd3513bcc 100644 --- a/src/webrtc/stats/statsReport.ts +++ b/src/webrtc/stats/statsReport.ts @@ -45,7 +45,6 @@ export interface ConnectionStatsReport { } export interface AudioConcealment { - ratio: number; concealedAudio: number; totalAudioDuration: number; } diff --git a/src/webrtc/stats/statsReportBuilder.ts b/src/webrtc/stats/statsReportBuilder.ts index eddddf091ea..c34b35831df 100644 --- a/src/webrtc/stats/statsReportBuilder.ts +++ b/src/webrtc/stats/statsReportBuilder.ts @@ -113,7 +113,6 @@ export class StatsReportBuilder { }; report.audioConcealment = audioConcealment; report.totalAudioConcealment = { - ratio: totalConcealedAudio / totalAudioDuration, concealedAudio: totalConcealedAudio, totalAudioDuration, }; From 9c4bf19749521502771fd442c3d4559d1b180f30 Mon Sep 17 00:00:00 2001 From: Timo K Date: Fri, 12 May 2023 15:03:27 +0200 Subject: [PATCH 13/16] remove comment --- src/webrtc/stats/statsReportBuilder.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/webrtc/stats/statsReportBuilder.ts b/src/webrtc/stats/statsReportBuilder.ts index c34b35831df..566648fb0e9 100644 --- a/src/webrtc/stats/statsReportBuilder.ts +++ b/src/webrtc/stats/statsReportBuilder.ts @@ -79,7 +79,6 @@ export class StatsReportBuilder { codecs[trackStats.getType()].set(trackId, trackStats.getCodec()); if (trackStats.getType() === "remote") { jitter.set(trackId, trackStats.getJitter()); - // TODO: decide if we even want per track audio concealment if (trackStats.kind === "audio") { audioConcealment.set(trackId, trackStats.getAudioConcealment()); } From 18360da989700a27a2d7cf4beca3e44d8277e18f Mon Sep 17 00:00:00 2001 From: Timo K Date: Fri, 12 May 2023 15:18:25 +0200 Subject: [PATCH 14/16] fix test --- spec/unit/webrtc/stats/statsReportBuilder.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/unit/webrtc/stats/statsReportBuilder.spec.ts b/spec/unit/webrtc/stats/statsReportBuilder.spec.ts index 17063a260a4..4b4faa1ca05 100644 --- a/spec/unit/webrtc/stats/statsReportBuilder.spec.ts +++ b/spec/unit/webrtc/stats/statsReportBuilder.spec.ts @@ -92,7 +92,7 @@ describe("StatsReportBuilder", () => { ["REMOTE_VIDEO_TRACK_ID", 50], ]), audioConcealment: new Map([ - ["REMOTE_AUDIO_TRACK_ID", { concealedAudio: 3000, ratio: 1 / 20, totalAudioDuration: 3000 * 20 }], + ["REMOTE_AUDIO_TRACK_ID", { concealedAudio: 3000, totalAudioDuration: 3000 * 20 }], ]), totalAudioConcealment: { concealedAudio: 3000, From 113056ceffc628195e74ef01e481632e76188970 Mon Sep 17 00:00:00 2001 From: Timo K Date: Wed, 10 May 2023 18:05:20 +0200 Subject: [PATCH 15/16] add peer connections to summary report --- src/webrtc/stats/statsReport.ts | 1 + src/webrtc/stats/summaryStatsReporter.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src/webrtc/stats/statsReport.ts b/src/webrtc/stats/statsReport.ts index 67fd3513bcc..cdfa751f464 100644 --- a/src/webrtc/stats/statsReport.ts +++ b/src/webrtc/stats/statsReport.ts @@ -78,4 +78,5 @@ export interface SummaryStatsReport { maxJitter: number; maxPacketLoss: number; percentageConcealedAudio: number; + peerConnections: number; } diff --git a/src/webrtc/stats/summaryStatsReporter.ts b/src/webrtc/stats/summaryStatsReporter.ts index 8ad0c5591d3..7fd594c5099 100644 --- a/src/webrtc/stats/summaryStatsReporter.ts +++ b/src/webrtc/stats/summaryStatsReporter.ts @@ -61,6 +61,7 @@ export class SummaryStatsReporter { ? (summaryCounter.concealedAudio / summaryCounter.totalAudio).toFixed(decimalPlaces) : 0, ), + peerConnections: summaryTotalCount, } as SummaryStatsReport; this.emitter.emitSummaryStatsReport(report); } From 006ccdf7a3876adbe2d19f0741370ca26cc14d20 Mon Sep 17 00:00:00 2001 From: Timo K Date: Sun, 14 May 2023 16:48:15 +0200 Subject: [PATCH 16/16] tests --- spec/unit/webrtc/stats/summaryStatsReporter.spec.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/spec/unit/webrtc/stats/summaryStatsReporter.spec.ts b/spec/unit/webrtc/stats/summaryStatsReporter.spec.ts index 117231ee2de..22c7f60c3ad 100644 --- a/spec/unit/webrtc/stats/summaryStatsReporter.spec.ts +++ b/spec/unit/webrtc/stats/summaryStatsReporter.spec.ts @@ -125,6 +125,7 @@ describe("SummaryStatsReporter", () => { percentageReceivedVideoMedia: 0.75, maxJitter: 0, maxPacketLoss: 0, + peerConnections: 4, percentageConcealedAudio: 0.0375, }); }); @@ -160,6 +161,7 @@ describe("SummaryStatsReporter", () => { percentageReceivedVideoMedia: 1, maxJitter: 0, maxPacketLoss: 0, + peerConnections: 1, percentageConcealedAudio: 0, }); }); @@ -195,6 +197,7 @@ describe("SummaryStatsReporter", () => { percentageReceivedVideoMedia: 0, maxJitter: 0, maxPacketLoss: 0, + peerConnections: 1, percentageConcealedAudio: 0, }); }); @@ -230,6 +233,7 @@ describe("SummaryStatsReporter", () => { percentageReceivedVideoMedia: 1, maxJitter: 0, maxPacketLoss: 0, + peerConnections: 1, percentageConcealedAudio: 0, }); }); @@ -328,6 +332,7 @@ describe("SummaryStatsReporter", () => { percentageReceivedVideoMedia: 1, maxJitter: 20, maxPacketLoss: 40, + peerConnections: 4, percentageConcealedAudio: 0, }); }); @@ -363,6 +368,7 @@ describe("SummaryStatsReporter", () => { percentageReceivedVideoMedia: 1, maxJitter: 0, maxPacketLoss: 0, + peerConnections: 1, percentageConcealedAudio: 0, }); }); @@ -398,6 +404,7 @@ describe("SummaryStatsReporter", () => { percentageReceivedVideoMedia: 1, maxJitter: 0, maxPacketLoss: 0, + peerConnections: 1, percentageConcealedAudio: 0, }); }); @@ -433,6 +440,7 @@ describe("SummaryStatsReporter", () => { percentageReceivedVideoMedia: 1, maxJitter: 0, maxPacketLoss: 0, + peerConnections: 1, percentageConcealedAudio: 0, }); });