From 7ade461a4ce5728e8dbef690f860c2766fca5d48 Mon Sep 17 00:00:00 2001 From: Enrico Schwendig Date: Fri, 26 May 2023 09:56:49 +0200 Subject: [PATCH] Refactor naming of webrtc stats reporter (#3404) * Refactor names in webrtc stats * Refactor summary stats reporter to gatherer * Add test for signal change * rename test --- ...pec.ts => callStatsReportGatherer.spec.ts} | 49 ++++++++++++++-- ...s => connectionStatsReportBuilder.spec.ts} | 4 +- .../stats/connectionStatsReporter.spec.ts | 10 ++-- spec/unit/webrtc/stats/groupCallStats.spec.ts | 4 +- ....ts => summaryStatsReportGatherer.spec.ts} | 8 +-- ...rter.spec.ts => trackStatsBuilder.spec.ts} | 50 ++++++++--------- ....spec.ts => transportStatsBuilder.spec.ts} | 12 ++-- ...rmatter.spec.ts => valueFormatter.spec.ts} | 14 ++--- ...Gatherer.ts => callStatsReportGatherer.ts} | 56 +++++++++---------- ...maryStats.ts => callStatsReportSummary.ts} | 2 +- ...sReporter.ts => connectionStatsBuilder.ts} | 2 +- ...der.ts => connectionStatsReportBuilder.ts} | 8 +-- src/webrtc/stats/groupCallStats.ts | 18 +++--- ...orter.ts => summaryStatsReportGatherer.ts} | 18 +++--- ...kStatsReporter.ts => trackStatsBuilder.ts} | 20 +++---- ...tsReporter.ts => transportStatsBuilder.ts} | 2 +- ...atsValueFormatter.ts => valueFormatter.ts} | 2 +- 17 files changed, 160 insertions(+), 119 deletions(-) rename spec/unit/webrtc/stats/{statsReportGatherer.spec.ts => callStatsReportGatherer.spec.ts} (75%) rename spec/unit/webrtc/stats/{statsReportBuilder.spec.ts => connectionStatsReportBuilder.spec.ts} (96%) rename spec/unit/webrtc/stats/{summaryStatsReporter.spec.ts => summaryStatsReportGatherer.spec.ts} (98%) rename spec/unit/webrtc/stats/{trackStatsReporter.spec.ts => trackStatsBuilder.spec.ts} (89%) rename spec/unit/webrtc/stats/{transportStatsReporter.spec.ts => transportStatsBuilder.spec.ts} (87%) rename spec/unit/webrtc/stats/{statsValueFormatter.spec.ts => valueFormatter.spec.ts} (58%) rename src/webrtc/stats/{statsReportGatherer.ts => callStatsReportGatherer.ts} (79%) rename src/webrtc/stats/{summaryStats.ts => callStatsReportSummary.ts} (95%) rename src/webrtc/stats/{connectionStatsReporter.ts => connectionStatsBuilder.ts} (96%) rename src/webrtc/stats/{statsReportBuilder.ts => connectionStatsReportBuilder.ts} (93%) rename src/webrtc/stats/{summaryStatsReporter.ts => summaryStatsReportGatherer.ts} (86%) rename src/webrtc/stats/{trackStatsReporter.ts => trackStatsBuilder.ts} (90%) rename src/webrtc/stats/{transportStatsReporter.ts => transportStatsBuilder.ts} (98%) rename src/webrtc/stats/{statsValueFormatter.ts => valueFormatter.ts} (96%) diff --git a/spec/unit/webrtc/stats/statsReportGatherer.spec.ts b/spec/unit/webrtc/stats/callStatsReportGatherer.spec.ts similarity index 75% rename from spec/unit/webrtc/stats/statsReportGatherer.spec.ts rename to spec/unit/webrtc/stats/callStatsReportGatherer.spec.ts index fdd2ffd50..8f81cc17a 100644 --- a/spec/unit/webrtc/stats/statsReportGatherer.spec.ts +++ b/spec/unit/webrtc/stats/callStatsReportGatherer.spec.ts @@ -14,21 +14,22 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { StatsReportGatherer } from "../../../../src/webrtc/stats/statsReportGatherer"; +import { CallStatsReportGatherer } from "../../../../src/webrtc/stats/callStatsReportGatherer"; import { StatsReportEmitter } from "../../../../src/webrtc/stats/statsReportEmitter"; +import { MediaSsrcHandler } from "../../../../src/webrtc/stats/media/mediaSsrcHandler"; const CALL_ID = "CALL_ID"; const USER_ID = "USER_ID"; -describe("StatsReportGatherer", () => { - let collector: StatsReportGatherer; +describe("CallStatsReportGatherer", () => { + let collector: CallStatsReportGatherer; let rtcSpy: RTCPeerConnection; let emitter: StatsReportEmitter; beforeEach(() => { rtcSpy = { getStats: () => new Promise(() => null) } as RTCPeerConnection; rtcSpy.addEventListener = jest.fn(); emitter = new StatsReportEmitter(); - collector = new StatsReportGatherer(CALL_ID, USER_ID, rtcSpy, emitter); + collector = new CallStatsReportGatherer(CALL_ID, USER_ID, rtcSpy, emitter); }); describe("on process stats", () => { @@ -145,4 +146,44 @@ describe("StatsReportGatherer", () => { expect(collector.getActive()).toBeTruthy(); }); }); + + describe("on signal state change event", () => { + let events: { [key: string]: any }; + beforeEach(() => { + events = []; + // Define the addEventListener method with a Jest mock function + rtcSpy.addEventListener = jest.fn((event: any, callback: any) => { + events[event] = callback; + }); + + collector = new CallStatsReportGatherer(CALL_ID, USER_ID, rtcSpy, emitter); + }); + it("in case of stable, parse remote and local description", async () => { + // @ts-ignore + const mediaSsrcHandler = { + parse: jest.fn(), + ssrcToMid: jest.fn(), + findMidBySsrc: jest.fn(), + getSsrcToMidMap: jest.fn(), + } as MediaSsrcHandler; + + const remoteSDP = "sdp"; + const localSDP = "sdp"; + + // @ts-ignore + rtcSpy.signalingState = "stable"; + + // @ts-ignore + rtcSpy.currentRemoteDescription = { sdp: remoteSDP }; + // @ts-ignore + rtcSpy.currentLocalDescription = { sdp: localSDP }; + + // @ts-ignore + collector.trackStats.mediaSsrcHandler = mediaSsrcHandler; + + events["signalingstatechange"](); + expect(mediaSsrcHandler.parse).toHaveBeenCalledWith(remoteSDP, "remote"); + expect(mediaSsrcHandler.parse).toHaveBeenCalledWith(localSDP, "local"); + }); + }); }); diff --git a/spec/unit/webrtc/stats/statsReportBuilder.spec.ts b/spec/unit/webrtc/stats/connectionStatsReportBuilder.spec.ts similarity index 96% rename from spec/unit/webrtc/stats/statsReportBuilder.spec.ts rename to spec/unit/webrtc/stats/connectionStatsReportBuilder.spec.ts index 4b4faa1ca..d8fb9a756 100644 --- a/spec/unit/webrtc/stats/statsReportBuilder.spec.ts +++ b/spec/unit/webrtc/stats/connectionStatsReportBuilder.spec.ts @@ -16,7 +16,7 @@ limitations under the License. import { TrackID } from "../../../../src/webrtc/stats/statsReport"; import { MediaTrackStats } from "../../../../src/webrtc/stats/media/mediaTrackStats"; -import { StatsReportBuilder } from "../../../../src/webrtc/stats/statsReportBuilder"; +import { ConnectionStatsReportBuilder } from "../../../../src/webrtc/stats/connectionStatsReportBuilder"; describe("StatsReportBuilder", () => { const LOCAL_VIDEO_TRACK_ID = "LOCAL_VIDEO_TRACK_ID"; @@ -39,7 +39,7 @@ describe("StatsReportBuilder", () => { describe("should build stats", () => { it("by media track stats.", async () => { - expect(StatsReportBuilder.build(stats)).toEqual({ + expect(ConnectionStatsReportBuilder.build(stats)).toEqual({ bitrate: { audio: { download: 4000, diff --git a/spec/unit/webrtc/stats/connectionStatsReporter.spec.ts b/spec/unit/webrtc/stats/connectionStatsReporter.spec.ts index 1c9b21233..7356f2576 100644 --- a/spec/unit/webrtc/stats/connectionStatsReporter.spec.ts +++ b/spec/unit/webrtc/stats/connectionStatsReporter.spec.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 { ConnectionStatsReporter } from "../../../../src/webrtc/stats/connectionStatsReporter"; +import { ConnectionStatsBuilder } from "../../../../src/webrtc/stats/connectionStatsBuilder"; describe("ConnectionStatsReporter", () => { describe("should on bandwidth stats", () => { @@ -22,11 +22,11 @@ describe("ConnectionStatsReporter", () => { availableIncomingBitrate: 1000, availableOutgoingBitrate: 2000, } as RTCIceCandidatePairStats; - expect(ConnectionStatsReporter.buildBandwidthReport(stats)).toEqual({ download: 1, upload: 2 }); + expect(ConnectionStatsBuilder.buildBandwidthReport(stats)).toEqual({ download: 1, upload: 2 }); }); it("build empty bandwidth report if chromium starts attributes not available", () => { const stats = {} as RTCIceCandidatePairStats; - expect(ConnectionStatsReporter.buildBandwidthReport(stats)).toEqual({ download: 0, upload: 0 }); + expect(ConnectionStatsBuilder.buildBandwidthReport(stats)).toEqual({ download: 0, upload: 0 }); }); }); @@ -36,11 +36,11 @@ describe("ConnectionStatsReporter", () => { availableIncomingBitrate: 1000, availableOutgoingBitrate: 2000, } as RTCIceCandidatePairStats; - expect(ConnectionStatsReporter.buildBandwidthReport(stats)).toEqual({ download: 1, upload: 2 }); + expect(ConnectionStatsBuilder.buildBandwidthReport(stats)).toEqual({ download: 1, upload: 2 }); }); it("build empty bandwidth report if chromium starts attributes not available", () => { const stats = {} as RTCIceCandidatePairStats; - expect(ConnectionStatsReporter.buildBandwidthReport(stats)).toEqual({ download: 0, upload: 0 }); + expect(ConnectionStatsBuilder.buildBandwidthReport(stats)).toEqual({ download: 0, upload: 0 }); }); }); }); diff --git a/spec/unit/webrtc/stats/groupCallStats.spec.ts b/spec/unit/webrtc/stats/groupCallStats.spec.ts index 672e79d68..6aa45f307 100644 --- a/spec/unit/webrtc/stats/groupCallStats.spec.ts +++ b/spec/unit/webrtc/stats/groupCallStats.spec.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ import { GroupCallStats } from "../../../../src/webrtc/stats/groupCallStats"; -import { SummaryStats } from "../../../../src/webrtc/stats/summaryStats"; +import { CallStatsReportSummary } from "../../../../src/webrtc/stats/callStatsReportSummary"; const GROUP_CALL_ID = "GROUP_ID"; const LOCAL_USER_ID = "LOCAL_USER_ID"; @@ -112,7 +112,7 @@ describe("GroupCallStats", () => { concealedAudio: 0, totalAudio: 0, }, - } as SummaryStats; + } as CallStatsReportSummary; let processStatsSpy; if (collector) { processStatsSpy = jest.spyOn(collector, "processStats").mockResolvedValue(summaryStats); diff --git a/spec/unit/webrtc/stats/summaryStatsReporter.spec.ts b/spec/unit/webrtc/stats/summaryStatsReportGatherer.spec.ts similarity index 98% rename from spec/unit/webrtc/stats/summaryStatsReporter.spec.ts rename to spec/unit/webrtc/stats/summaryStatsReportGatherer.spec.ts index e448c3b16..eefff0d9b 100644 --- a/spec/unit/webrtc/stats/summaryStatsReporter.spec.ts +++ b/spec/unit/webrtc/stats/summaryStatsReportGatherer.spec.ts @@ -13,16 +13,16 @@ 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 { SummaryStatsReporter } from "../../../../src/webrtc/stats/summaryStatsReporter"; +import { SummaryStatsReportGatherer } from "../../../../src/webrtc/stats/summaryStatsReportGatherer"; import { StatsReportEmitter } from "../../../../src/webrtc/stats/statsReportEmitter"; -describe("SummaryStatsReporter", () => { - let reporter: SummaryStatsReporter; +describe("SummaryStatsReportGatherer", () => { + let reporter: SummaryStatsReportGatherer; let emitter: StatsReportEmitter; beforeEach(() => { emitter = new StatsReportEmitter(); emitter.emitSummaryStatsReport = jest.fn(); - reporter = new SummaryStatsReporter(emitter); + reporter = new SummaryStatsReportGatherer(emitter); }); describe("build Summary Stats Report", () => { diff --git a/spec/unit/webrtc/stats/trackStatsReporter.spec.ts b/spec/unit/webrtc/stats/trackStatsBuilder.spec.ts similarity index 89% rename from spec/unit/webrtc/stats/trackStatsReporter.spec.ts rename to spec/unit/webrtc/stats/trackStatsBuilder.spec.ts index 0c22cdaf6..9bfe1169c 100644 --- a/spec/unit/webrtc/stats/trackStatsReporter.spec.ts +++ b/spec/unit/webrtc/stats/trackStatsBuilder.spec.ts @@ -13,20 +13,20 @@ 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 { TrackStatsReporter } from "../../../../src/webrtc/stats/trackStatsReporter"; +import { TrackStatsBuilder } from "../../../../src/webrtc/stats/trackStatsBuilder"; import { MediaTrackStats } from "../../../../src/webrtc/stats/media/mediaTrackStats"; -describe("TrackStatsReporter", () => { +describe("TrackStatsBuilder", () => { describe("should on frame and resolution stats", () => { it("creating empty frame and resolution report, if no data available.", async () => { const trackStats = new MediaTrackStats("1", "local", "video"); - TrackStatsReporter.buildFramerateResolution(trackStats, {}); + TrackStatsBuilder.buildFramerateResolution(trackStats, {}); expect(trackStats.getFramerate()).toEqual(0); expect(trackStats.getResolution()).toEqual({ width: -1, height: -1 }); }); it("creating empty frame and resolution report.", async () => { const trackStats = new MediaTrackStats("1", "remote", "video"); - TrackStatsReporter.buildFramerateResolution(trackStats, { + TrackStatsBuilder.buildFramerateResolution(trackStats, { framesPerSecond: 22.2, frameHeight: 180, frameWidth: 360, @@ -39,7 +39,7 @@ describe("TrackStatsReporter", () => { describe("should on simulcast", () => { it("creating simulcast framerate.", async () => { const trackStats = new MediaTrackStats("1", "local", "video"); - TrackStatsReporter.calculateSimulcastFramerate( + TrackStatsBuilder.calculateSimulcastFramerate( trackStats, { framesSent: 100, @@ -58,7 +58,7 @@ describe("TrackStatsReporter", () => { describe("should on bytes received stats", () => { it("creating build bitrate received report.", async () => { const trackStats = new MediaTrackStats("1", "remote", "video"); - TrackStatsReporter.buildBitrateReceived( + TrackStatsBuilder.buildBitrateReceived( trackStats, { bytesReceived: 2001000, @@ -73,7 +73,7 @@ describe("TrackStatsReporter", () => { describe("should on bytes send stats", () => { it("creating build bitrate send report.", async () => { const trackStats = new MediaTrackStats("1", "local", "video"); - TrackStatsReporter.buildBitrateSend( + TrackStatsBuilder.buildBitrateSend( trackStats, { bytesSent: 2001000, @@ -90,7 +90,7 @@ describe("TrackStatsReporter", () => { const trackStats = new MediaTrackStats("1", "remote", "video"); const remote = {} as RTCStatsReport; remote.get = jest.fn().mockReturnValue({ mimeType: "video/v8" }); - TrackStatsReporter.buildCodec(remote, trackStats, { codecId: "codecID" }); + TrackStatsBuilder.buildCodec(remote, trackStats, { codecId: "codecID" }); expect(trackStats.getCodec()).toEqual("v8"); }); }); @@ -98,7 +98,7 @@ describe("TrackStatsReporter", () => { describe("should on package lost stats", () => { it("creating build package lost on send report.", async () => { const trackStats = new MediaTrackStats("1", "local", "video"); - TrackStatsReporter.buildPacketsLost( + TrackStatsBuilder.buildPacketsLost( trackStats, { type: "outbound-rtp", @@ -114,7 +114,7 @@ describe("TrackStatsReporter", () => { }); it("creating build package lost on received report.", async () => { const trackStats = new MediaTrackStats("1", "remote", "video"); - TrackStatsReporter.buildPacketsLost( + TrackStatsBuilder.buildPacketsLost( trackStats, { type: "inbound-rtp", @@ -133,7 +133,7 @@ describe("TrackStatsReporter", () => { describe("should set state of a TrackStats", () => { it("to not alive if Transceiver undefined", async () => { const trackStats = new MediaTrackStats("1", "remote", "video"); - TrackStatsReporter.setTrackStatsState(trackStats, undefined); + TrackStatsBuilder.setTrackStatsState(trackStats, undefined); expect(trackStats.alive).toBeFalsy(); }); @@ -145,7 +145,7 @@ describe("TrackStatsReporter", () => { } as RTCRtpSender, } as RTCRtpTransceiver; - TrackStatsReporter.setTrackStatsState(trackStats, ts); + TrackStatsBuilder.setTrackStatsState(trackStats, ts); expect(trackStats.alive).toBeFalsy(); }); @@ -162,7 +162,7 @@ describe("TrackStatsReporter", () => { } as RTCRtpReceiver, } as RTCRtpTransceiver; - TrackStatsReporter.setTrackStatsState(trackStats, ts); + TrackStatsBuilder.setTrackStatsState(trackStats, ts); expect(trackStats.alive).toBeTruthy(); }); @@ -179,7 +179,7 @@ describe("TrackStatsReporter", () => { } as RTCRtpSender, } as RTCRtpTransceiver; - TrackStatsReporter.setTrackStatsState(trackStats, ts); + TrackStatsBuilder.setTrackStatsState(trackStats, ts); expect(trackStats.alive).toBeTruthy(); }); @@ -195,7 +195,7 @@ describe("TrackStatsReporter", () => { } as RTCRtpReceiver, } as RTCRtpTransceiver; - TrackStatsReporter.setTrackStatsState(trackStats, ts); + TrackStatsBuilder.setTrackStatsState(trackStats, ts); expect(trackStats.alive).toBeFalsy(); }); @@ -211,7 +211,7 @@ describe("TrackStatsReporter", () => { } as RTCRtpReceiver, } as RTCRtpTransceiver; - TrackStatsReporter.setTrackStatsState(trackStats, ts); + TrackStatsBuilder.setTrackStatsState(trackStats, ts); expect(trackStats.alive).toBeTruthy(); expect(trackStats.muted).toBeTruthy(); }); @@ -219,7 +219,7 @@ describe("TrackStatsReporter", () => { describe("should build Track Summary", () => { it("and returns empty summary if stats list empty", async () => { - const summary = TrackStatsReporter.buildTrackSummary([]); + const summary = TrackStatsBuilder.buildTrackSummary([]); expect(summary).toEqual({ audioTrackSummary: { count: 0, @@ -242,7 +242,7 @@ describe("TrackStatsReporter", () => { it("and returns summary if stats list not empty and ignore local summery", async () => { const trackStatsList = buildMockTrackStatsList(); - const summary = TrackStatsReporter.buildTrackSummary(trackStatsList); + const summary = TrackStatsBuilder.buildTrackSummary(trackStatsList); expect(summary).toEqual({ audioTrackSummary: { count: 2, @@ -267,7 +267,7 @@ describe("TrackStatsReporter", () => { const trackStatsList = buildMockTrackStatsList(); trackStatsList[1].muted = true; trackStatsList[5].muted = true; - const summary = TrackStatsReporter.buildTrackSummary(trackStatsList); + const summary = TrackStatsBuilder.buildTrackSummary(trackStatsList); expect(summary).toEqual({ audioTrackSummary: { count: 2, @@ -292,7 +292,7 @@ describe("TrackStatsReporter", () => { const trackStatsList = buildMockTrackStatsList(); trackStatsList[1].muted = true; trackStatsList[1].alive = false; - const summary = TrackStatsReporter.buildTrackSummary(trackStatsList); + const summary = TrackStatsBuilder.buildTrackSummary(trackStatsList); expect(summary).toEqual({ audioTrackSummary: { count: 2, @@ -330,7 +330,7 @@ describe("TrackStatsReporter", () => { trackStatsList[2].setAudioConcealment(220, 2000); trackStatsList[5].setAudioConcealment(180, 2000); - const summary = TrackStatsReporter.buildTrackSummary(trackStatsList); + const summary = TrackStatsBuilder.buildTrackSummary(trackStatsList); expect(summary).toEqual({ audioTrackSummary: { count: 2, @@ -355,25 +355,25 @@ describe("TrackStatsReporter", () => { describe("should build jitter value in Track Stats", () => { it("and returns track stats without jitter if report not 'inbound-rtp'", async () => { const trackStats = new MediaTrackStats("1", "remote", "video"); - TrackStatsReporter.buildJitter(trackStats, { jitter: 0.01 }); + TrackStatsBuilder.buildJitter(trackStats, { jitter: 0.01 }); expect(trackStats.getJitter()).toEqual(0); }); it("and returns track stats with jitter", async () => { const trackStats = new MediaTrackStats("1", "remote", "video"); - TrackStatsReporter.buildJitter(trackStats, { type: "inbound-rtp", jitter: 0.01 }); + TrackStatsBuilder.buildJitter(trackStats, { type: "inbound-rtp", jitter: 0.01 }); expect(trackStats.getJitter()).toEqual(10); }); it("and returns negative jitter if stats has no jitter value", async () => { const trackStats = new MediaTrackStats("1", "remote", "video"); - TrackStatsReporter.buildJitter(trackStats, { type: "inbound-rtp" }); + TrackStatsBuilder.buildJitter(trackStats, { type: "inbound-rtp" }); expect(trackStats.getJitter()).toEqual(-1); }); it("and returns jitter as number", async () => { const trackStats = new MediaTrackStats("1", "remote", "video"); - TrackStatsReporter.buildJitter(trackStats, { type: "inbound-rtp", jitter: "0.5" }); + TrackStatsBuilder.buildJitter(trackStats, { type: "inbound-rtp", jitter: "0.5" }); expect(trackStats.getJitter()).toEqual(500); }); }); diff --git a/spec/unit/webrtc/stats/transportStatsReporter.spec.ts b/spec/unit/webrtc/stats/transportStatsBuilder.spec.ts similarity index 87% rename from spec/unit/webrtc/stats/transportStatsReporter.spec.ts rename to spec/unit/webrtc/stats/transportStatsBuilder.spec.ts index bd3288b15..17283f31e 100644 --- a/spec/unit/webrtc/stats/transportStatsReporter.spec.ts +++ b/spec/unit/webrtc/stats/transportStatsBuilder.spec.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { TransportStatsReporter } from "../../../../src/webrtc/stats/transportStatsReporter"; +import { TransportStatsBuilder } from "../../../../src/webrtc/stats/transportStatsBuilder"; import { TransportStats } from "../../../../src/webrtc/stats/transportStats"; describe("TransportStatsReporter", () => { @@ -35,7 +35,7 @@ describe("TransportStatsReporter", () => { it("build new transport stats if all properties there", () => { const { report, stats } = mockStatsReport(isFocus, 0); const conferenceStatsTransport: TransportStats[] = []; - const transportStats = TransportStatsReporter.buildReport(report, stats, conferenceStatsTransport, isFocus); + const transportStats = TransportStatsBuilder.buildReport(report, stats, conferenceStatsTransport, isFocus); expect(transportStats).toEqual([ { ip: `${remoteIC.ip + 0}:${remoteIC.port}`, @@ -54,8 +54,8 @@ describe("TransportStatsReporter", () => { const mock1 = mockStatsReport(isFocus, 0); const mock2 = mockStatsReport(isFocus, 1); let transportStats: TransportStats[] = []; - transportStats = TransportStatsReporter.buildReport(mock1.report, mock1.stats, transportStats, isFocus); - transportStats = TransportStatsReporter.buildReport(mock2.report, mock2.stats, transportStats, isFocus); + transportStats = TransportStatsBuilder.buildReport(mock1.report, mock1.stats, transportStats, isFocus); + transportStats = TransportStatsBuilder.buildReport(mock2.report, mock2.stats, transportStats, isFocus); expect(transportStats).toEqual([ { ip: `${remoteIC.ip + 0}:${remoteIC.port}`, @@ -84,8 +84,8 @@ describe("TransportStatsReporter", () => { const mock1 = mockStatsReport(isFocus, 0); const mock2 = mockStatsReport(isFocus, 0); let transportStats: TransportStats[] = []; - transportStats = TransportStatsReporter.buildReport(mock1.report, mock1.stats, transportStats, isFocus); - transportStats = TransportStatsReporter.buildReport(mock2.report, mock2.stats, transportStats, isFocus); + transportStats = TransportStatsBuilder.buildReport(mock1.report, mock1.stats, transportStats, isFocus); + transportStats = TransportStatsBuilder.buildReport(mock2.report, mock2.stats, transportStats, isFocus); expect(transportStats).toEqual([ { ip: `${remoteIC.ip + 0}:${remoteIC.port}`, diff --git a/spec/unit/webrtc/stats/statsValueFormatter.spec.ts b/spec/unit/webrtc/stats/valueFormatter.spec.ts similarity index 58% rename from spec/unit/webrtc/stats/statsValueFormatter.spec.ts rename to spec/unit/webrtc/stats/valueFormatter.spec.ts index 1ce563e91..5009960b1 100644 --- a/spec/unit/webrtc/stats/statsValueFormatter.spec.ts +++ b/spec/unit/webrtc/stats/valueFormatter.spec.ts @@ -13,16 +13,16 @@ 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 { StatsValueFormatter } from "../../../../src/webrtc/stats/statsValueFormatter"; +import { ValueFormatter } from "../../../../src/webrtc/stats/valueFormatter"; -describe("StatsValueFormatter", () => { +describe("ValueFormatter", () => { describe("on get non negative values", () => { it("formatter shod return number", async () => { - expect(StatsValueFormatter.getNonNegativeValue("2")).toEqual(2); - expect(StatsValueFormatter.getNonNegativeValue(0)).toEqual(0); - expect(StatsValueFormatter.getNonNegativeValue("-2")).toEqual(0); - expect(StatsValueFormatter.getNonNegativeValue("")).toEqual(0); - expect(StatsValueFormatter.getNonNegativeValue(NaN)).toEqual(0); + expect(ValueFormatter.getNonNegativeValue("2")).toEqual(2); + expect(ValueFormatter.getNonNegativeValue(0)).toEqual(0); + expect(ValueFormatter.getNonNegativeValue("-2")).toEqual(0); + expect(ValueFormatter.getNonNegativeValue("")).toEqual(0); + expect(ValueFormatter.getNonNegativeValue(NaN)).toEqual(0); }); }); }); diff --git a/src/webrtc/stats/statsReportGatherer.ts b/src/webrtc/stats/callStatsReportGatherer.ts similarity index 79% rename from src/webrtc/stats/statsReportGatherer.ts rename to src/webrtc/stats/callStatsReportGatherer.ts index 485f35ecf..ad1e079c3 100644 --- a/src/webrtc/stats/statsReportGatherer.ts +++ b/src/webrtc/stats/callStatsReportGatherer.ts @@ -17,17 +17,17 @@ limitations under the License. import { ConnectionStats } from "./connectionStats"; import { StatsReportEmitter } from "./statsReportEmitter"; import { ByteSend, ByteSentStatsReport, TrackID } from "./statsReport"; -import { ConnectionStatsReporter } from "./connectionStatsReporter"; -import { TransportStatsReporter } from "./transportStatsReporter"; +import { ConnectionStatsBuilder } from "./connectionStatsBuilder"; +import { TransportStatsBuilder } from "./transportStatsBuilder"; import { MediaSsrcHandler } from "./media/mediaSsrcHandler"; import { MediaTrackHandler } from "./media/mediaTrackHandler"; import { MediaTrackStatsHandler } from "./media/mediaTrackStatsHandler"; -import { TrackStatsReporter } from "./trackStatsReporter"; -import { StatsReportBuilder } from "./statsReportBuilder"; -import { StatsValueFormatter } from "./statsValueFormatter"; -import { SummaryStats } from "./summaryStats"; +import { TrackStatsBuilder } from "./trackStatsBuilder"; +import { ConnectionStatsReportBuilder } from "./connectionStatsReportBuilder"; +import { ValueFormatter } from "./valueFormatter"; +import { CallStatsReportSummary } from "./callStatsReportSummary"; -export class StatsReportGatherer { +export class CallStatsReportGatherer { private isActive = true; private previousStatsReport: RTCStatsReport | undefined; private currentStatsReport: RTCStatsReport | undefined; @@ -46,7 +46,7 @@ export class StatsReportGatherer { this.trackStats = new MediaTrackStatsHandler(new MediaSsrcHandler(), new MediaTrackHandler(pc)); } - public async processStats(groupCallId: string, localUserId: string): Promise { + public async processStats(groupCallId: string, localUserId: string): Promise { const summary = { isFirstCollection: this.previousStatsReport === undefined, receivedMedia: 0, @@ -54,7 +54,7 @@ export class StatsReportGatherer { receivedVideoMedia: 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; + } as CallStatsReportSummary; if (this.isActive) { const statsPromise = this.pc.getStats(); if (typeof statsPromise?.then === "function") { @@ -73,7 +73,7 @@ export class StatsReportGatherer { summary.receivedMedia = this.connectionStats.bitrate.download; summary.receivedAudioMedia = this.connectionStats.bitrate.audio?.download || 0; summary.receivedVideoMedia = this.connectionStats.bitrate.video?.download || 0; - const trackSummary = TrackStatsReporter.buildTrackSummary( + const trackSummary = TrackStatsBuilder.buildTrackSummary( Array.from(this.trackStats.getTrack2stats().values()), ); return { @@ -93,14 +93,14 @@ export class StatsReportGatherer { } private processStatsReport(groupCallId: string, localUserId: string): void { - const byteSentStats: ByteSentStatsReport = new Map(); + const byteSentStatsReport: ByteSentStatsReport = new Map(); this.currentStatsReport?.forEach((now) => { const before = this.previousStatsReport ? this.previousStatsReport.get(now.id) : null; // RTCIceCandidatePairStats - https://w3c.github.io/webrtc-stats/#candidatepair-dict* if (now.type === "candidate-pair" && now.nominated && now.state === "succeeded") { - this.connectionStats.bandwidth = ConnectionStatsReporter.buildBandwidthReport(now); - this.connectionStats.transport = TransportStatsReporter.buildReport( + this.connectionStats.bandwidth = ConnectionStatsBuilder.buildBandwidthReport(now); + this.connectionStats.transport = TransportStatsBuilder.buildReport( this.currentStatsReport, now, this.connectionStats.transport, @@ -121,7 +121,7 @@ export class StatsReportGatherer { } if (before) { - TrackStatsReporter.buildPacketsLost(trackStats, now, before); + TrackStatsBuilder.buildPacketsLost(trackStats, now, before); } // Get the resolution and framerate for only remote video sources here. For the local video sources, @@ -130,26 +130,26 @@ export class StatsReportGatherer { // more calculations needed to determine what is the highest resolution stream sent by the client if the // 'outbound-rtp' stats are used. if (now.type === "inbound-rtp") { - TrackStatsReporter.buildFramerateResolution(trackStats, now); + TrackStatsBuilder.buildFramerateResolution(trackStats, now); if (before) { - TrackStatsReporter.buildBitrateReceived(trackStats, now, before); + TrackStatsBuilder.buildBitrateReceived(trackStats, now, before); } const ts = this.trackStats.findTransceiverByTrackId(trackStats.trackId); - TrackStatsReporter.setTrackStatsState(trackStats, ts); - TrackStatsReporter.buildJitter(trackStats, now); - TrackStatsReporter.buildAudioConcealment(trackStats, now); + TrackStatsBuilder.setTrackStatsState(trackStats, ts); + TrackStatsBuilder.buildJitter(trackStats, now); + TrackStatsBuilder.buildAudioConcealment(trackStats, now); } else if (before) { - byteSentStats.set(trackStats.trackId, StatsValueFormatter.getNonNegativeValue(now.bytesSent)); - TrackStatsReporter.buildBitrateSend(trackStats, now, before); + byteSentStatsReport.set(trackStats.trackId, ValueFormatter.getNonNegativeValue(now.bytesSent)); + TrackStatsBuilder.buildBitrateSend(trackStats, now, before); } - TrackStatsReporter.buildCodec(this.currentStatsReport, trackStats, now); + TrackStatsBuilder.buildCodec(this.currentStatsReport, trackStats, now); } else if (now.type === "track" && now.kind === "video" && !now.remoteSource) { const trackStats = this.trackStats.findLocalVideoTrackStats(now); if (!trackStats) { return; } - TrackStatsReporter.buildFramerateResolution(trackStats, now); - TrackStatsReporter.calculateSimulcastFramerate( + TrackStatsBuilder.buildFramerateResolution(trackStats, now); + TrackStatsBuilder.calculateSimulcastFramerate( trackStats, now, before, @@ -158,8 +158,8 @@ export class StatsReportGatherer { } }); - this.emitter.emitByteSendReport(byteSentStats); - this.processAndEmitReport(); + this.emitter.emitByteSendReport(byteSentStatsReport); + this.processAndEmitConnectionStatsReport(); } public setActive(isActive: boolean): void { @@ -174,8 +174,8 @@ export class StatsReportGatherer { this.isActive = false; } - private processAndEmitReport(): void { - const report = StatsReportBuilder.build(this.trackStats.getTrack2stats()); + private processAndEmitConnectionStatsReport(): void { + const report = ConnectionStatsReportBuilder.build(this.trackStats.getTrack2stats()); this.connectionStats.bandwidth = report.bandwidth; this.connectionStats.bitrate = report.bitrate; diff --git a/src/webrtc/stats/summaryStats.ts b/src/webrtc/stats/callStatsReportSummary.ts similarity index 95% rename from src/webrtc/stats/summaryStats.ts rename to src/webrtc/stats/callStatsReportSummary.ts index e8189be3a..fc62ae3b3 100644 --- a/src/webrtc/stats/summaryStats.ts +++ b/src/webrtc/stats/callStatsReportSummary.ts @@ -10,7 +10,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. */ -export interface SummaryStats { +export interface CallStatsReportSummary { receivedMedia: number; receivedAudioMedia: number; receivedVideoMedia: number; diff --git a/src/webrtc/stats/connectionStatsReporter.ts b/src/webrtc/stats/connectionStatsBuilder.ts similarity index 96% rename from src/webrtc/stats/connectionStatsReporter.ts rename to src/webrtc/stats/connectionStatsBuilder.ts index c43b9b40c..f954fed49 100644 --- a/src/webrtc/stats/connectionStatsReporter.ts +++ b/src/webrtc/stats/connectionStatsBuilder.ts @@ -15,7 +15,7 @@ limitations under the License. */ import { Bitrate } from "./media/mediaTrackStats"; -export class ConnectionStatsReporter { +export class ConnectionStatsBuilder { public static buildBandwidthReport(now: RTCIceCandidatePairStats): Bitrate { const availableIncomingBitrate = now.availableIncomingBitrate; const availableOutgoingBitrate = now.availableOutgoingBitrate; diff --git a/src/webrtc/stats/statsReportBuilder.ts b/src/webrtc/stats/connectionStatsReportBuilder.ts similarity index 93% rename from src/webrtc/stats/statsReportBuilder.ts rename to src/webrtc/stats/connectionStatsReportBuilder.ts index 566648fb0..5ed99d59b 100644 --- a/src/webrtc/stats/statsReportBuilder.ts +++ b/src/webrtc/stats/connectionStatsReportBuilder.ts @@ -16,7 +16,7 @@ limitations under the License. import { AudioConcealment, CodecMap, ConnectionStatsReport, FramerateMap, ResolutionMap, TrackID } from "./statsReport"; import { MediaTrackStats, Resolution } from "./media/mediaTrackStats"; -export class StatsReportBuilder { +export class ConnectionStatsReportBuilder { public static build(stats: Map): ConnectionStatsReport { const report = {} as ConnectionStatsReport; @@ -103,12 +103,12 @@ export class StatsReportBuilder { }; report.packetLoss = { - total: StatsReportBuilder.calculatePacketLoss( + total: ConnectionStatsReportBuilder.calculatePacketLoss( lostPackets.download + lostPackets.upload, totalPackets.download + totalPackets.upload, ), - download: StatsReportBuilder.calculatePacketLoss(lostPackets.download, totalPackets.download), - upload: StatsReportBuilder.calculatePacketLoss(lostPackets.upload, totalPackets.upload), + download: ConnectionStatsReportBuilder.calculatePacketLoss(lostPackets.download, totalPackets.download), + upload: ConnectionStatsReportBuilder.calculatePacketLoss(lostPackets.upload, totalPackets.upload), }; report.audioConcealment = audioConcealment; report.totalAudioConcealment = { diff --git a/src/webrtc/stats/groupCallStats.ts b/src/webrtc/stats/groupCallStats.ts index 898424846..054d51f81 100644 --- a/src/webrtc/stats/groupCallStats.ts +++ b/src/webrtc/stats/groupCallStats.ts @@ -13,16 +13,16 @@ 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 { StatsReportGatherer } from "./statsReportGatherer"; +import { CallStatsReportGatherer } from "./callStatsReportGatherer"; import { StatsReportEmitter } from "./statsReportEmitter"; -import { SummaryStats } from "./summaryStats"; -import { SummaryStatsReporter } from "./summaryStatsReporter"; +import { CallStatsReportSummary } from "./callStatsReportSummary"; +import { SummaryStatsReportGatherer } from "./summaryStatsReportGatherer"; export class GroupCallStats { private timer: undefined | ReturnType; - private readonly gatherers: Map = new Map(); + private readonly gatherers: Map = new Map(); public readonly reports = new StatsReportEmitter(); - private readonly summaryStatsReporter = new SummaryStatsReporter(this.reports); + private readonly summaryStatsReportGatherer = new SummaryStatsReportGatherer(this.reports); public constructor(private groupCallId: string, private userId: string, private interval: number = 10000) {} @@ -49,7 +49,7 @@ export class GroupCallStats { if (this.hasStatsReportGatherer(callId)) { return false; } - this.gatherers.set(callId, new StatsReportGatherer(callId, userId, peerConnection, this.reports)); + this.gatherers.set(callId, new CallStatsReportGatherer(callId, userId, peerConnection, this.reports)); return true; } @@ -57,17 +57,17 @@ export class GroupCallStats { return this.gatherers.delete(callId); } - public getStatsReportGatherer(callId: string): StatsReportGatherer | undefined { + public getStatsReportGatherer(callId: string): CallStatsReportGatherer | undefined { return this.hasStatsReportGatherer(callId) ? this.gatherers.get(callId) : undefined; } private processStats(): void { - const summary: Promise[] = []; + const summary: Promise[] = []; this.gatherers.forEach((c) => { summary.push(c.processStats(this.groupCallId, this.userId)); }); - Promise.all(summary).then((s: Awaited[]) => this.summaryStatsReporter.build(s)); + Promise.all(summary).then((s: Awaited[]) => this.summaryStatsReportGatherer.build(s)); } public setInterval(interval: number): void { diff --git a/src/webrtc/stats/summaryStatsReporter.ts b/src/webrtc/stats/summaryStatsReportGatherer.ts similarity index 86% rename from src/webrtc/stats/summaryStatsReporter.ts rename to src/webrtc/stats/summaryStatsReportGatherer.ts index 79cf20dcf..87601dcac 100644 --- a/src/webrtc/stats/summaryStatsReporter.ts +++ b/src/webrtc/stats/summaryStatsReportGatherer.ts @@ -11,10 +11,10 @@ See the License for the specific language governing permissions and limitations under the License. */ import { StatsReportEmitter } from "./statsReportEmitter"; -import { SummaryStats } from "./summaryStats"; +import { CallStatsReportSummary } from "./callStatsReportSummary"; import { SummaryStatsReport } from "./statsReport"; -interface SummaryCounter { +interface CallStatsReportSummaryCounter { receivedAudio: number; receivedVideo: number; receivedMedia: number; @@ -22,10 +22,10 @@ interface SummaryCounter { totalAudio: number; } -export class SummaryStatsReporter { +export class SummaryStatsReportGatherer { public constructor(private emitter: StatsReportEmitter) {} - public build(allSummary: SummaryStats[]): void { + public build(allSummary: CallStatsReportSummary[]): void { // Filter all stats which collect the first time webrtc stats. // Because stats based on time interval and the first collection of a summery stats has no previous // webrtcStats as basement all the calculation are 0. We don't want track the 0 stats. @@ -34,7 +34,7 @@ export class SummaryStatsReporter { if (summaryTotalCount === 0) { return; } - const summaryCounter: SummaryCounter = { + const summaryCounter: CallStatsReportSummaryCounter = { receivedAudio: 0, receivedVideo: 0, receivedMedia: 0, @@ -70,7 +70,7 @@ export class SummaryStatsReporter { this.emitter.emitSummaryStatsReport(report); } - private countTrackListReceivedMedia(counter: SummaryCounter, stats: SummaryStats): void { + private countTrackListReceivedMedia(counter: CallStatsReportSummaryCounter, stats: CallStatsReportSummary): void { let hasReceivedAudio = false; let hasReceivedVideo = false; if (stats.receivedAudioMedia > 0 || stats.audioTrackSummary.count === 0) { @@ -92,7 +92,7 @@ export class SummaryStatsReporter { } } - private buildMaxJitter(maxJitter: number, stats: SummaryStats): number { + private buildMaxJitter(maxJitter: number, stats: CallStatsReportSummary): number { if (maxJitter < stats.videoTrackSummary.maxJitter) { maxJitter = stats.videoTrackSummary.maxJitter; } @@ -103,7 +103,7 @@ export class SummaryStatsReporter { return maxJitter; } - private buildMaxPacketLoss(maxPacketLoss: number, stats: SummaryStats): number { + private buildMaxPacketLoss(maxPacketLoss: number, stats: CallStatsReportSummary): number { if (maxPacketLoss < stats.videoTrackSummary.maxPacketLoss) { maxPacketLoss = stats.videoTrackSummary.maxPacketLoss; } @@ -114,7 +114,7 @@ export class SummaryStatsReporter { return maxPacketLoss; } - private countConcealedAudio(summaryCounter: SummaryCounter, stats: SummaryStats): void { + private countConcealedAudio(summaryCounter: CallStatsReportSummaryCounter, stats: CallStatsReportSummary): void { summaryCounter.concealedAudio += stats.audioTrackSummary.concealedAudio; summaryCounter.totalAudio += stats.audioTrackSummary.totalAudio; } diff --git a/src/webrtc/stats/trackStatsReporter.ts b/src/webrtc/stats/trackStatsBuilder.ts similarity index 90% rename from src/webrtc/stats/trackStatsReporter.ts rename to src/webrtc/stats/trackStatsBuilder.ts index 75409f26a..c670fddbb 100644 --- a/src/webrtc/stats/trackStatsReporter.ts +++ b/src/webrtc/stats/trackStatsBuilder.ts @@ -1,8 +1,8 @@ import { MediaTrackStats } from "./media/mediaTrackStats"; -import { StatsValueFormatter } from "./statsValueFormatter"; -import { TrackSummary } from "./summaryStats"; +import { ValueFormatter } from "./valueFormatter"; +import { TrackSummary } from "./callStatsReportSummary"; -export class TrackStatsReporter { +export class TrackStatsBuilder { public static buildFramerateResolution(trackStats: MediaTrackStats, now: any): void { const resolution = { height: now.frameHeight, @@ -56,7 +56,7 @@ export class TrackStatsReporter { public static buildBitrateReceived(trackStats: MediaTrackStats, now: any, before: any): void { trackStats.setBitrate({ - download: TrackStatsReporter.calculateBitrate( + download: TrackStatsBuilder.calculateBitrate( now.bytesReceived, before.bytesReceived, now.timestamp, @@ -81,11 +81,11 @@ export class TrackStatsReporter { packetsNow = 0; } - const packetsBefore = StatsValueFormatter.getNonNegativeValue(before[key]); + const packetsBefore = ValueFormatter.getNonNegativeValue(before[key]); const packetsDiff = Math.max(0, packetsNow - packetsBefore); - const packetsLostNow = StatsValueFormatter.getNonNegativeValue(now.packetsLost); - const packetsLostBefore = StatsValueFormatter.getNonNegativeValue(before.packetsLost); + const packetsLostNow = ValueFormatter.getNonNegativeValue(now.packetsLost); + const packetsLostBefore = ValueFormatter.getNonNegativeValue(before.packetsLost); const packetsLostDiff = Math.max(0, packetsLostNow - packetsLostBefore); trackStats.setLoss({ @@ -101,8 +101,8 @@ export class TrackStatsReporter { nowTimestamp: number, beforeTimestamp: number, ): number { - const bytesNow = StatsValueFormatter.getNonNegativeValue(bytesNowAny); - const bytesBefore = StatsValueFormatter.getNonNegativeValue(bytesBeforeAny); + const bytesNow = ValueFormatter.getNonNegativeValue(bytesNowAny); + const bytesBefore = ValueFormatter.getNonNegativeValue(bytesBeforeAny); const bytesProcessed = Math.max(0, bytesNow - bytesBefore); const timeMs = nowTimestamp - beforeTimestamp; @@ -188,7 +188,7 @@ export class TrackStatsReporter { const jitterStr = statsReport?.jitter; if (jitterStr !== undefined) { - const jitter = StatsValueFormatter.getNonNegativeValue(jitterStr); + const jitter = ValueFormatter.getNonNegativeValue(jitterStr); trackStats.setJitter(Math.round(jitter * 1000)); } else { trackStats.setJitter(-1); diff --git a/src/webrtc/stats/transportStatsReporter.ts b/src/webrtc/stats/transportStatsBuilder.ts similarity index 98% rename from src/webrtc/stats/transportStatsReporter.ts rename to src/webrtc/stats/transportStatsBuilder.ts index d419a7397..12ed7b0cb 100644 --- a/src/webrtc/stats/transportStatsReporter.ts +++ b/src/webrtc/stats/transportStatsBuilder.ts @@ -1,6 +1,6 @@ import { TransportStats } from "./transportStats"; -export class TransportStatsReporter { +export class TransportStatsBuilder { public static buildReport( report: RTCStatsReport | undefined, now: RTCIceCandidatePairStats, diff --git a/src/webrtc/stats/statsValueFormatter.ts b/src/webrtc/stats/valueFormatter.ts similarity index 96% rename from src/webrtc/stats/statsValueFormatter.ts rename to src/webrtc/stats/valueFormatter.ts index c658fa665..bf75ce29f 100644 --- a/src/webrtc/stats/statsValueFormatter.ts +++ b/src/webrtc/stats/valueFormatter.ts @@ -10,7 +10,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. */ -export class StatsValueFormatter { +export class ValueFormatter { public static getNonNegativeValue(imput: any): number { let value = imput;