1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-08-06 12:02:40 +03:00

Add remote user and call id in webrtc call stats (#3413)

* Refactor names in webrtc stats

* Refactor summary stats reporter to gatherer

* Add call and opponent member id to call stats reports

* Update opponent member when we know them

* Add missing return type

* remove async in test

* mark new stats property as optional to avoid braking changes
This commit is contained in:
Enrico Schwendig
2023-06-01 17:07:44 +02:00
committed by GitHub
parent feb424b0a9
commit 9c5c7ddb17
5 changed files with 31 additions and 6 deletions

View File

@@ -158,7 +158,7 @@ describe("CallStatsReportGatherer", () => {
collector = new CallStatsReportGatherer(CALL_ID, USER_ID, rtcSpy, emitter); collector = new CallStatsReportGatherer(CALL_ID, USER_ID, rtcSpy, emitter);
}); });
it("in case of stable, parse remote and local description", async () => { it("in case of stable, parse remote and local description", () => {
// @ts-ignore // @ts-ignore
const mediaSsrcHandler = { const mediaSsrcHandler = {
parse: jest.fn(), parse: jest.fn(),

View File

@@ -2848,7 +2848,9 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
pc.addEventListener("negotiationneeded", this.onNegotiationNeeded); pc.addEventListener("negotiationneeded", this.onNegotiationNeeded);
pc.addEventListener("datachannel", this.onDataChannel); pc.addEventListener("datachannel", this.onDataChannel);
this.stats?.addStatsReportGatherer(this.callId, "unknown", pc); const opponentMember: RoomMember | undefined = this.getOpponentMember();
const opponentMemberId = opponentMember ? opponentMember.userId : "unknown";
this.stats?.addStatsReportGatherer(this.callId, opponentMemberId, pc);
return pc; return pc;
} }
@@ -2882,6 +2884,9 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
} }
this.opponentCaps = msg.capabilities || ({} as CallCapabilities); this.opponentCaps = msg.capabilities || ({} as CallCapabilities);
this.opponentMember = this.client.getRoom(this.roomId)!.getMember(ev.getSender()!) ?? undefined; this.opponentMember = this.client.getRoom(this.roomId)!.getMember(ev.getSender()!) ?? undefined;
if (this.opponentMember) {
this.stats?.updateOpponentMember(this.callId, this.opponentMember.userId);
}
} }
private async addBufferedIceCandidates(): Promise<void> { private async addBufferedIceCandidates(): Promise<void> {

View File

@@ -37,7 +37,7 @@ export class CallStatsReportGatherer {
public constructor( public constructor(
public readonly callId: string, public readonly callId: string,
public readonly remoteUserId: string, private opponentMemberId: string,
private readonly pc: RTCPeerConnection, private readonly pc: RTCPeerConnection,
private readonly emitter: StatsReportEmitter, private readonly emitter: StatsReportEmitter,
private readonly isFocus = true, private readonly isFocus = true,
@@ -93,7 +93,9 @@ export class CallStatsReportGatherer {
} }
private processStatsReport(groupCallId: string, localUserId: string): void { private processStatsReport(groupCallId: string, localUserId: string): void {
const byteSentStatsReport: ByteSentStatsReport = new Map<TrackID, ByteSend>(); const byteSentStatsReport: ByteSentStatsReport = new Map<TrackID, ByteSend>() as ByteSentStatsReport;
byteSentStatsReport.callId = this.callId;
byteSentStatsReport.opponentMemberId = this.opponentMemberId;
this.currentStatsReport?.forEach((now) => { this.currentStatsReport?.forEach((now) => {
const before = this.previousStatsReport ? this.previousStatsReport.get(now.id) : null; const before = this.previousStatsReport ? this.previousStatsReport.get(now.id) : null;
@@ -176,6 +178,8 @@ export class CallStatsReportGatherer {
private processAndEmitConnectionStatsReport(): void { private processAndEmitConnectionStatsReport(): void {
const report = ConnectionStatsReportBuilder.build(this.trackStats.getTrack2stats()); const report = ConnectionStatsReportBuilder.build(this.trackStats.getTrack2stats());
report.callId = this.callId;
report.opponentMemberId = this.opponentMemberId;
this.connectionStats.bandwidth = report.bandwidth; this.connectionStats.bandwidth = report.bandwidth;
this.connectionStats.bitrate = report.bitrate; this.connectionStats.bitrate = report.bitrate;
@@ -201,4 +205,8 @@ export class CallStatsReportGatherer {
} }
} }
} }
public setOpponentMemberId(id: string): void {
this.opponentMemberId = id;
}
} }

View File

@@ -45,11 +45,15 @@ export class GroupCallStats {
return this.gatherers.has(callId); return this.gatherers.has(callId);
} }
public addStatsReportGatherer(callId: string, userId: string, peerConnection: RTCPeerConnection): boolean { public addStatsReportGatherer(
callId: string,
opponentMemberId: string,
peerConnection: RTCPeerConnection,
): boolean {
if (this.hasStatsReportGatherer(callId)) { if (this.hasStatsReportGatherer(callId)) {
return false; return false;
} }
this.gatherers.set(callId, new CallStatsReportGatherer(callId, userId, peerConnection, this.reports)); this.gatherers.set(callId, new CallStatsReportGatherer(callId, opponentMemberId, peerConnection, this.reports));
return true; return true;
} }
@@ -61,6 +65,10 @@ export class GroupCallStats {
return this.hasStatsReportGatherer(callId) ? this.gatherers.get(callId) : undefined; return this.hasStatsReportGatherer(callId) ? this.gatherers.get(callId) : undefined;
} }
public updateOpponentMember(callId: string, opponentMember: string): void {
this.getStatsReportGatherer(callId)?.setOpponentMemberId(opponentMember);
}
private processStats(): void { private processStats(): void {
const summary: Promise<CallStatsReportSummary>[] = []; const summary: Promise<CallStatsReportSummary>[] = [];
this.gatherers.forEach((c) => { this.gatherers.forEach((c) => {

View File

@@ -28,10 +28,14 @@ export type TrackID = string;
export type ByteSend = number; export type ByteSend = number;
export interface ByteSentStatsReport extends Map<TrackID, ByteSend> { export interface ByteSentStatsReport extends Map<TrackID, ByteSend> {
callId?: string;
opponentMemberId?: string;
// is a map: `local trackID` => byte send // is a map: `local trackID` => byte send
} }
export interface ConnectionStatsReport { export interface ConnectionStatsReport {
callId?: string;
opponentMemberId?: string;
bandwidth: ConnectionStatsBandwidth; bandwidth: ConnectionStatsBandwidth;
bitrate: ConnectionStatsBitrate; bitrate: ConnectionStatsBitrate;
packetLoss: PacketLoss; packetLoss: PacketLoss;