Skip to content

Commit

Permalink
Filter all summary stats which collect the first time webrtc metrics. (
Browse files Browse the repository at this point in the history
…#3377)

* remove comment

* Filter all summery stats which collect the first time webrtc stats

* Fix lint issues

* Fix lint second issues
  • Loading branch information
Enrico Schwendig authored May 17, 2023
1 parent bb5bccb commit a7b1dca
Show file tree
Hide file tree
Showing 6 changed files with 206 additions and 6 deletions.
19 changes: 17 additions & 2 deletions spec/unit/webrtc/stats/groupCallStats.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,26 @@ describe("GroupCallStats", () => {
const collector = stats.getStatsReportGatherer("CALL_ID");
stats.reports.emitSummaryStatsReport = jest.fn();
const summaryStats = {
isFirstCollection: true,
receivedMedia: 0,
receivedAudioMedia: 0,
receivedVideoMedia: 0,
audioTrackSummary: { count: 0, muted: 0 },
videoTrackSummary: { count: 0, muted: 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,
},
} as SummaryStats;
let processStatsSpy;
if (collector) {
Expand Down
38 changes: 37 additions & 1 deletion spec/unit/webrtc/stats/statsReportGatherer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ describe("StatsReportGatherer", () => {
const actual = await collector.processStats("GROUP_CALL_ID", "LOCAL_USER_ID");
expect(getStats).toHaveBeenCalled();
expect(actual).toEqual({
isFirstCollection: true,
receivedMedia: 0,
receivedAudioMedia: 0,
receivedVideoMedia: 0,
Expand Down Expand Up @@ -79,12 +80,13 @@ describe("StatsReportGatherer", () => {
expect(collector.getActive()).toBeFalsy();
});

it("if active an RTCStatsReport not a promise the collector becomes inactive", async () => {
it("if active and getStats returns not an RTCStatsReport inside a promise the collector fails and becomes inactive", async () => {
const getStats = jest.spyOn(rtcSpy, "getStats");
// @ts-ignore
getStats.mockReturnValue({});
const actual = await collector.processStats("GROUP_CALL_ID", "LOCAL_USER_ID");
expect(actual).toEqual({
isFirstCollection: true,
receivedMedia: 0,
receivedAudioMedia: 0,
receivedVideoMedia: 0,
Expand All @@ -108,5 +110,39 @@ describe("StatsReportGatherer", () => {
expect(getStats).toHaveBeenCalled();
expect(collector.getActive()).toBeFalsy();
});

it("if active and the collector runs not the first time the Summery Stats is marked as not fits collection", async () => {
const getStats = jest.spyOn(rtcSpy, "getStats");
// @ts-ignore
collector.previousStatsReport = {} as RTCStatsReport;
const report = {} as RTCStatsReport;
report.forEach = jest.fn().mockReturnValue([]);
getStats.mockResolvedValue(report);
const actual = await collector.processStats("GROUP_CALL_ID", "LOCAL_USER_ID");
expect(getStats).toHaveBeenCalled();
expect(actual).toEqual({
isFirstCollection: false,
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,
},
});
expect(collector.getActive()).toBeTruthy();
});
});
});
144 changes: 144 additions & 0 deletions spec/unit/webrtc/stats/summaryStatsReporter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,38 @@ describe("SummaryStatsReporter", () => {
reporter.build([]);
expect(emitter.emitSummaryStatsReport).not.toHaveBeenCalled();
});
it("should do nothing if a summary stats element collection the is first time", async () => {
reporter.build([
{
isFirstCollection: true,
receivedMedia: 10,
receivedAudioMedia: 4,
receivedVideoMedia: 6,
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,
},
},
]);
expect(emitter.emitSummaryStatsReport).not.toHaveBeenCalled();
});

it("should trigger new summary report", async () => {
const summary = [
{
isFirstCollection: false,
receivedMedia: 10,
receivedAudioMedia: 4,
receivedVideoMedia: 6,
Expand All @@ -55,6 +83,7 @@ describe("SummaryStatsReporter", () => {
},
},
{
isFirstCollection: false,
receivedMedia: 13,
receivedAudioMedia: 0,
receivedVideoMedia: 13,
Expand All @@ -76,6 +105,7 @@ describe("SummaryStatsReporter", () => {
},
},
{
isFirstCollection: false,
receivedMedia: 0,
receivedAudioMedia: 0,
receivedVideoMedia: 0,
Expand All @@ -97,6 +127,7 @@ describe("SummaryStatsReporter", () => {
},
},
{
isFirstCollection: false,
receivedMedia: 15,
receivedAudioMedia: 6,
receivedVideoMedia: 9,
Expand Down Expand Up @@ -133,6 +164,7 @@ describe("SummaryStatsReporter", () => {
it("as received video Media, although video was not received, but because video muted", async () => {
const summary = [
{
isFirstCollection: false,
receivedMedia: 10,
receivedAudioMedia: 10,
receivedVideoMedia: 0,
Expand Down Expand Up @@ -169,6 +201,7 @@ describe("SummaryStatsReporter", () => {
it("as received no video Media, because only on video was muted", async () => {
const summary = [
{
isFirstCollection: false,
receivedMedia: 10,
receivedAudioMedia: 10,
receivedVideoMedia: 0,
Expand Down Expand Up @@ -205,6 +238,7 @@ describe("SummaryStatsReporter", () => {
it("as received no audio Media, although audio not received and audio muted", async () => {
const summary = [
{
isFirstCollection: false,
receivedMedia: 100,
receivedAudioMedia: 0,
receivedVideoMedia: 100,
Expand Down Expand Up @@ -241,6 +275,7 @@ describe("SummaryStatsReporter", () => {
it("should find max jitter and max packet loss", async () => {
const summary = [
{
isFirstCollection: false,
receivedMedia: 1,
receivedAudioMedia: 1,
receivedVideoMedia: 1,
Expand All @@ -262,6 +297,7 @@ describe("SummaryStatsReporter", () => {
},
},
{
isFirstCollection: false,
receivedMedia: 1,
receivedAudioMedia: 1,
receivedVideoMedia: 1,
Expand All @@ -283,6 +319,7 @@ describe("SummaryStatsReporter", () => {
},
},
{
isFirstCollection: false,
receivedMedia: 1,
receivedAudioMedia: 1,
receivedVideoMedia: 1,
Expand All @@ -304,6 +341,7 @@ describe("SummaryStatsReporter", () => {
},
},
{
isFirstCollection: false,
receivedMedia: 1,
receivedAudioMedia: 1,
receivedVideoMedia: 1,
Expand Down Expand Up @@ -340,6 +378,7 @@ describe("SummaryStatsReporter", () => {
it("as received video Media, if no audio track received should count as received Media", async () => {
const summary = [
{
isFirstCollection: false,
receivedMedia: 10,
receivedAudioMedia: 0,
receivedVideoMedia: 10,
Expand Down Expand Up @@ -376,6 +415,7 @@ describe("SummaryStatsReporter", () => {
it("as received audio Media, if no video track received should count as received Media", async () => {
const summary = [
{
isFirstCollection: false,
receivedMedia: 1,
receivedAudioMedia: 22,
receivedVideoMedia: 0,
Expand Down Expand Up @@ -412,6 +452,7 @@ describe("SummaryStatsReporter", () => {
it("as received no media at all, as received Media", async () => {
const summary = [
{
isFirstCollection: false,
receivedMedia: 0,
receivedAudioMedia: 0,
receivedVideoMedia: 0,
Expand Down Expand Up @@ -444,5 +485,108 @@ describe("SummaryStatsReporter", () => {
percentageConcealedAudio: 0,
});
});

it("should filter the first time summery stats", async () => {
const summary = [
{
isFirstCollection: false,
receivedMedia: 1,
receivedAudioMedia: 1,
receivedVideoMedia: 1,
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,
},
},
{
isFirstCollection: true,
receivedMedia: 1,
receivedAudioMedia: 1,
receivedVideoMedia: 1,
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,
},
},
{
isFirstCollection: false,
receivedMedia: 1,
receivedAudioMedia: 1,
receivedVideoMedia: 1,
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,
},
},
{
isFirstCollection: false,
receivedMedia: 1,
receivedAudioMedia: 1,
receivedVideoMedia: 1,
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);
expect(emitter.emitSummaryStatsReport).toHaveBeenCalledWith({
percentageReceivedMedia: 1,
percentageReceivedAudioMedia: 1,
percentageReceivedVideoMedia: 1,
maxJitter: 2,
maxPacketLoss: 40,
peerConnections: 3,
percentageConcealedAudio: 0,
});
});
});
});
3 changes: 1 addition & 2 deletions src/webrtc/stats/statsReportGatherer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ export class StatsReportGatherer {

private readonly trackStats: MediaTrackStatsHandler;

// private readonly ssrcToMid = { local: new Map<Mid, Ssrc[]>(), remote: new Map<Mid, Ssrc[]>() };

public constructor(
public readonly callId: string,
public readonly remoteUserId: string,
Expand All @@ -50,6 +48,7 @@ export class StatsReportGatherer {

public async processStats(groupCallId: string, localUserId: string): Promise<SummaryStats> {
const summary = {
isFirstCollection: this.previousStatsReport === undefined,
receivedMedia: 0,
receivedAudioMedia: 0,
receivedVideoMedia: 0,
Expand Down
2 changes: 2 additions & 0 deletions src/webrtc/stats/summaryStats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export interface SummaryStats {
receivedVideoMedia: number;
audioTrackSummary: TrackSummary;
videoTrackSummary: TrackSummary;

isFirstCollection: Boolean;
}

export interface TrackSummary {
Expand Down
6 changes: 5 additions & 1 deletion src/webrtc/stats/summaryStatsReporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ interface SummaryCounter {
export class SummaryStatsReporter {
public constructor(private emitter: StatsReportEmitter) {}

public build(summary: SummaryStats[]): void {
public build(allSummary: SummaryStats[]): 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.
const summary = allSummary.filter((s) => !s.isFirstCollection);
const summaryTotalCount = summary.length;
if (summaryTotalCount === 0) {
return;
Expand Down

0 comments on commit a7b1dca

Please sign in to comment.