You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-07-31 15:24:23 +03:00
Make webrtc stats collection optional (#3307)
* 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
This commit is contained in:
@ -1629,4 +1629,77 @@ describe("Group Call", function () {
|
|||||||
expect(room.currentState.getStateEvents(EventType.GroupCallMemberPrefix, FAKE_USER_ID_2)).toBe(null);
|
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();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -68,7 +68,7 @@ describe("GroupCallStats", () => {
|
|||||||
jest.useRealTimers();
|
jest.useRealTimers();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("starting processing as well without stats collectors", async () => {
|
it("starting processing stats as well without stats collectors", async () => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
stats.processStats = jest.fn();
|
stats.processStats = jest.fn();
|
||||||
stats.start();
|
stats.start();
|
||||||
@ -77,6 +77,16 @@ describe("GroupCallStats", () => {
|
|||||||
expect(stats.processStats).toHaveBeenCalled();
|
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 () => {
|
it("starting processing and calling the collectors", async () => {
|
||||||
stats.addStatsReportGatherer("CALL_ID", "USER_ID", mockRTCPeerConnection());
|
stats.addStatsReportGatherer("CALL_ID", "USER_ID", mockRTCPeerConnection());
|
||||||
const collector = stats.getStatsReportGatherer("CALL_ID");
|
const collector = stats.getStatsReportGatherer("CALL_ID");
|
||||||
|
@ -236,7 +236,12 @@ export class GroupCall extends TypedEventEmitter<
|
|||||||
private initWithVideoMuted = false;
|
private initWithVideoMuted = false;
|
||||||
private initCallFeedPromise?: Promise<void>;
|
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(
|
public constructor(
|
||||||
private client: MatrixClient,
|
private client: MatrixClient,
|
||||||
@ -261,12 +266,6 @@ export class GroupCall extends TypedEventEmitter<
|
|||||||
this.on(GroupCallEvent.GroupCallStateChanged, this.onStateChanged);
|
this.on(GroupCallEvent.GroupCallStateChanged, this.onStateChanged);
|
||||||
this.on(GroupCallEvent.LocalScreenshareStateChanged, this.onLocalFeedsChanged);
|
this.on(GroupCallEvent.LocalScreenshareStateChanged, this.onLocalFeedsChanged);
|
||||||
this.allowCallWithoutVideoAndAudio = !!isCallWithoutVideoAndAudio;
|
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 => {
|
private onConnectionStats = (report: ConnectionStatsReport): void => {
|
||||||
@ -553,7 +552,7 @@ export class GroupCall extends TypedEventEmitter<
|
|||||||
clearInterval(this.retryCallLoopInterval);
|
clearInterval(this.retryCallLoopInterval);
|
||||||
|
|
||||||
this.client.removeListener(CallEventHandlerEvent.Incoming, this.onIncomingCall);
|
this.client.removeListener(CallEventHandlerEvent.Incoming, this.onIncomingCall);
|
||||||
this.stats.stop();
|
this.stats?.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
public leave(): void {
|
public leave(): void {
|
||||||
@ -1087,7 +1086,7 @@ export class GroupCall extends TypedEventEmitter<
|
|||||||
|
|
||||||
this.reEmitter.reEmit(call, Object.values(CallEvent));
|
this.reEmitter.reEmit(call, Object.values(CallEvent));
|
||||||
|
|
||||||
call.initStats(this.stats);
|
call.initStats(this.getGroupCallStats());
|
||||||
|
|
||||||
onCallFeedsChanged();
|
onCallFeedsChanged();
|
||||||
}
|
}
|
||||||
@ -1609,6 +1608,24 @@ export class GroupCall extends TypedEventEmitter<
|
|||||||
};
|
};
|
||||||
|
|
||||||
public getGroupCallStats(): GroupCallStats {
|
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;
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ export class GroupCallStats {
|
|||||||
public constructor(private groupCallId: string, private userId: string, private interval: number = 10000) {}
|
public constructor(private groupCallId: string, private userId: string, private interval: number = 10000) {}
|
||||||
|
|
||||||
public start(): void {
|
public start(): void {
|
||||||
if (this.timer === undefined) {
|
if (this.timer === undefined && this.interval > 0) {
|
||||||
this.timer = setInterval(() => {
|
this.timer = setInterval(() => {
|
||||||
this.processStats();
|
this.processStats();
|
||||||
}, this.interval);
|
}, this.interval);
|
||||||
@ -69,4 +69,8 @@ export class GroupCallStats {
|
|||||||
|
|
||||||
Promise.all(summary).then((s: Awaited<SummaryStats>[]) => this.summaryStatsReporter.build(s));
|
Promise.all(summary).then((s: Awaited<SummaryStats>[]) => this.summaryStatsReporter.build(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public setInterval(interval: number): void {
|
||||||
|
this.interval = interval;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user