Skip to content

Commit

Permalink
Make webrtc stats collection optional (#3307)
Browse files Browse the repository at this point in the history
* stats: disable stats collection if interval zero

* stats: add groupcall property for stats interval

* stats: disable collecting webrtc stats by default

* add setup methode for group call stats

* suppress lint errors in test
  • Loading branch information
Enrico Schwendig authored Apr 27, 2023
1 parent 8f701f4 commit 261bc81
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 11 deletions.
73 changes: 73 additions & 0 deletions spec/unit/webrtc/groupCall.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1629,4 +1629,77 @@ describe("Group Call", function () {
expect(room.currentState.getStateEvents(EventType.GroupCallMemberPrefix, FAKE_USER_ID_2)).toBe(null);
});
});

describe("collection stats", () => {
let groupCall: GroupCall;

beforeAll(() => {
jest.useFakeTimers();
jest.setSystemTime(0);
});

afterAll(() => jest.useRealTimers());

beforeEach(async () => {
const typedMockClient = new MockCallMatrixClient(FAKE_USER_ID_1, FAKE_DEVICE_ID_1, FAKE_SESSION_ID_1);
const mockClient = typedMockClient.typed();
const room = new Room(FAKE_ROOM_ID, mockClient, FAKE_USER_ID_1);
groupCall = new GroupCall(
mockClient,
room,
GroupCallType.Video,
false,
GroupCallIntent.Prompt,
FAKE_CONF_ID,
);
});
it("should be undefined if not get stats", async () => {
// @ts-ignore
const stats = groupCall.stats;
expect(stats).toBeUndefined();
});

it("should be defined after first access", async () => {
groupCall.getGroupCallStats();
// @ts-ignore
const stats = groupCall.stats;
expect(stats).toBeDefined();
});

it("with every number should do nothing if no stats exists.", async () => {
groupCall.setGroupCallStatsInterval(0);
// @ts-ignore
let stats = groupCall.stats;
expect(stats).toBeUndefined();

groupCall.setGroupCallStatsInterval(10000);
// @ts-ignore
stats = groupCall.stats;
expect(stats).toBeUndefined();
});

it("with number should stop existing stats", async () => {
const stats = groupCall.getGroupCallStats();
// @ts-ignore
const stop = jest.spyOn(stats, "stop");
// @ts-ignore
const start = jest.spyOn(stats, "start");
groupCall.setGroupCallStatsInterval(0);

expect(stop).toHaveBeenCalled();
expect(start).not.toHaveBeenCalled();
});

it("with number should restart existing stats", async () => {
const stats = groupCall.getGroupCallStats();
// @ts-ignore
const stop = jest.spyOn(stats, "stop");
// @ts-ignore
const start = jest.spyOn(stats, "start");
groupCall.setGroupCallStatsInterval(10000);

expect(stop).toHaveBeenCalled();
expect(start).toHaveBeenCalled();
});
});
});
12 changes: 11 additions & 1 deletion spec/unit/webrtc/stats/groupCallStats.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ describe("GroupCallStats", () => {
jest.useRealTimers();
});

it("starting processing as well without stats collectors", async () => {
it("starting processing stats as well without stats collectors", async () => {
// @ts-ignore
stats.processStats = jest.fn();
stats.start();
Expand All @@ -77,6 +77,16 @@ describe("GroupCallStats", () => {
expect(stats.processStats).toHaveBeenCalled();
});

it("not starting processing stats if interval 0", async () => {
const statsDisabled = new GroupCallStats(GROUP_CALL_ID, LOCAL_USER_ID, 0);
// @ts-ignore
statsDisabled.processStats = jest.fn();
statsDisabled.start();
jest.advanceTimersByTime(TIME_INTERVAL);
// @ts-ignore
expect(statsDisabled.processStats).not.toHaveBeenCalled();
});

it("starting processing and calling the collectors", async () => {
stats.addStatsReportGatherer("CALL_ID", "USER_ID", mockRTCPeerConnection());
const collector = stats.getStatsReportGatherer("CALL_ID");
Expand Down
35 changes: 26 additions & 9 deletions src/webrtc/groupCall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,12 @@ export class GroupCall extends TypedEventEmitter<
private initWithVideoMuted = false;
private initCallFeedPromise?: Promise<void>;

private readonly stats: GroupCallStats;
private stats: GroupCallStats | undefined;
/**
* Configure default webrtc stats collection interval in ms
* Disable collecting webrtc stats by setting interval to 0
*/
private statsCollectIntervalTime = 0;

public constructor(
private client: MatrixClient,
Expand All @@ -261,12 +266,6 @@ export class GroupCall extends TypedEventEmitter<
this.on(GroupCallEvent.GroupCallStateChanged, this.onStateChanged);
this.on(GroupCallEvent.LocalScreenshareStateChanged, this.onLocalFeedsChanged);
this.allowCallWithoutVideoAndAudio = !!isCallWithoutVideoAndAudio;

const userID = this.client.getUserId() || "unknown";
this.stats = new GroupCallStats(this.groupCallId, userID);
this.stats.reports.on(StatsReport.CONNECTION_STATS, this.onConnectionStats);
this.stats.reports.on(StatsReport.BYTE_SENT_STATS, this.onByteSentStats);
this.stats.reports.on(StatsReport.SUMMARY_STATS, this.onSummaryStats);
}

private onConnectionStats = (report: ConnectionStatsReport): void => {
Expand Down Expand Up @@ -553,7 +552,7 @@ export class GroupCall extends TypedEventEmitter<
clearInterval(this.retryCallLoopInterval);

this.client.removeListener(CallEventHandlerEvent.Incoming, this.onIncomingCall);
this.stats.stop();
this.stats?.stop();
}

public leave(): void {
Expand Down Expand Up @@ -1087,7 +1086,7 @@ export class GroupCall extends TypedEventEmitter<

this.reEmitter.reEmit(call, Object.values(CallEvent));

call.initStats(this.stats);
call.initStats(this.getGroupCallStats());

onCallFeedsChanged();
}
Expand Down Expand Up @@ -1609,6 +1608,24 @@ export class GroupCall extends TypedEventEmitter<
};

public getGroupCallStats(): GroupCallStats {
if (this.stats === undefined) {
const userID = this.client.getUserId() || "unknown";
this.stats = new GroupCallStats(this.groupCallId, userID, this.statsCollectIntervalTime);
this.stats.reports.on(StatsReport.CONNECTION_STATS, this.onConnectionStats);
this.stats.reports.on(StatsReport.BYTE_SENT_STATS, this.onByteSentStats);
this.stats.reports.on(StatsReport.SUMMARY_STATS, this.onSummaryStats);
}
return this.stats;
}

public setGroupCallStatsInterval(interval: number): void {
this.statsCollectIntervalTime = interval;
if (this.stats !== undefined) {
this.stats.stop();
this.stats.setInterval(interval);
if (interval > 0) {
this.stats.start();
}
}
}
}
6 changes: 5 additions & 1 deletion src/webrtc/stats/groupCallStats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export class GroupCallStats {
public constructor(private groupCallId: string, private userId: string, private interval: number = 10000) {}

public start(): void {
if (this.timer === undefined) {
if (this.timer === undefined && this.interval > 0) {
this.timer = setInterval(() => {
this.processStats();
}, this.interval);
Expand Down Expand Up @@ -69,4 +69,8 @@ export class GroupCallStats {

Promise.all(summary).then((s: Awaited<SummaryStats>[]) => this.summaryStatsReporter.build(s));
}

public setInterval(interval: number): void {
this.interval = interval;
}
}

0 comments on commit 261bc81

Please sign in to comment.