1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-07-30 04:23:07 +03:00

Add Jitter to exported webrtc stats (#3270)

* stats: Add Jitter stats

* Update src/webrtc/stats/trackStatsReporter.ts

Co-authored-by: Robin <robin@robin.town>

* stats: Fix typos in tests

* stats: differences between 0 and undefined in jitter val

---------

Co-authored-by: Robin <robin@robin.town>
This commit is contained in:
Enrico Schwendig
2023-04-13 10:51:13 +02:00
committed by GitHub
parent f8a625eddb
commit a0bcb5777f
7 changed files with 65 additions and 0 deletions

View File

@ -87,6 +87,10 @@ describe("StatsReportBuilder", () => {
["REMOTE_VIDEO_TRACK_ID", { height: 960, width: 1080 }],
]),
},
jitter: new Map([
["REMOTE_AUDIO_TRACK_ID", 0.1],
["REMOTE_VIDEO_TRACK_ID", 50],
]),
});
});
});
@ -99,6 +103,7 @@ describe("StatsReportBuilder", () => {
remoteAudioTrack.setCodec("opus");
remoteAudioTrack.setLoss({ packetsTotal: 20, packetsLost: 0, isDownloadStream: true });
remoteAudioTrack.setBitrate({ download: 4000, upload: 0 });
remoteAudioTrack.setJitter(0.1);
localVideoTrack.setCodec("v8");
localVideoTrack.setLoss({ packetsTotal: 30, packetsLost: 6, isDownloadStream: false });
@ -111,5 +116,6 @@ describe("StatsReportBuilder", () => {
remoteVideoTrack.setBitrate({ download: 5000000, upload: 0 });
remoteVideoTrack.setFramerate(60);
remoteVideoTrack.setResolution({ width: 1080, height: 960 });
remoteVideoTrack.setJitter(50);
};
});

View File

@ -246,4 +246,30 @@ 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 });
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 });
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" });
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" });
expect(trackStats.getJitter()).toEqual(500);
});
});
});

View File

@ -45,6 +45,7 @@ export class MediaTrackStats {
private bitrate: Bitrate = { download: 0, upload: 0 };
private resolution: Resolution = { width: -1, height: -1 };
private framerate = 0;
private jitter = 0;
private codec = "";
private isAlive = true;
private isMuted = false;
@ -140,4 +141,15 @@ export class MediaTrackStats {
public get enabled(): boolean {
return this.isEnabled;
}
public setJitter(jitter: number): void {
this.jitter = jitter;
}
/**
* Jitter in milliseconds
*/
public getJitter(): number {
return this.jitter;
}
}

View File

@ -38,6 +38,7 @@ export interface ConnectionStatsReport {
resolution: ResolutionMap;
framerate: FramerateMap;
codec: CodecMap;
jitter: Map<TrackID, number>;
transport: TransportStats[];
}

View File

@ -37,6 +37,7 @@ export class StatsReportBuilder {
};
const framerates: FramerateMap = { local: new Map<TrackID, number>(), remote: new Map<TrackID, number>() };
const codecs: CodecMap = { local: new Map<TrackID, string>(), remote: new Map<TrackID, string>() };
const jitter = new Map<TrackID, number>();
let audioBitrateDownload = 0;
let audioBitrateUpload = 0;
@ -67,6 +68,9 @@ export class StatsReportBuilder {
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());
}
trackStats.resetBitrate();
}
@ -97,6 +101,7 @@ export class StatsReportBuilder {
report.framerate = framerates;
report.resolution = resolutions;
report.codec = codecs;
report.jitter = jitter;
return report;
}

View File

@ -137,6 +137,7 @@ export class StatsReportGatherer {
}
const ts = this.trackStats.findTransceiverByTrackId(trackStats.trackId);
TrackStatsReporter.setTrackStatsState(trackStats, ts);
TrackStatsReporter.buildJitter(trackStats, now);
} else if (before) {
byteSentStats.set(trackStats.trackId, StatsValueFormatter.getNonNegativeValue(now.bytesSent));
TrackStatsReporter.buildBitrateSend(trackStats, now, before);

View File

@ -153,4 +153,18 @@ export class TrackStatsReporter {
});
return { audioTrackSummary, videoTrackSummary };
}
public static buildJitter(trackStats: MediaTrackStats, statsReport: any): void {
if (statsReport.type !== "inbound-rtp") {
return;
}
const jitterStr = statsReport?.jitter;
if (jitterStr !== undefined) {
const jitter = StatsValueFormatter.getNonNegativeValue(jitterStr);
trackStats.setJitter(Math.round(jitter * 1000));
} else {
trackStats.setJitter(-1);
}
}
}