Stop ringing and remove toast if another device answers a RTC call. (#30728)

* Stop ringing if another device answers a call.

* Add test

* fix check
This commit is contained in:
Will Hunt 2025-09-09 16:45:42 +01:00 committed by GitHub
parent d594ce479c
commit a73f4f5803
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 62 additions and 1 deletions

View File

@ -486,13 +486,27 @@ class NotifierClass extends TypedEventEmitter<keyof EmittedEvents, EmittedEvents
private performCustomEventHandling(ev: MatrixEvent): void {
const cli = MatrixClientPeg.safeGet();
const room = cli.getRoom(ev.getRoomId());
const type = ev.getType();
const thisUserHasConnectedDevice =
room && MatrixRTCSession.callMembershipsForRoom(room).some((m) => m.sender === cli.getUserId());
if (EventType.GroupCallMemberPrefix === type && thisUserHasConnectedDevice) {
const content = ev.getContent();
if (typeof content.call_id !== "string") {
logger.warn(
"Received malformatted GroupCallMemberPrefix event. Did not contain 'call_id' of type 'string'",
);
return;
}
// One of our devices has joined the call, so dismiss it.
ToastStore.sharedInstance().dismissToast(getIncomingCallToastKey(content.call_id, room.roomId));
}
// Check maximum age (<= 15 seconds) of a call notify event that will trigger a ringing notification
if (EventType.CallNotify === ev.getType() && (ev.getAge() ?? 0) < 15000 && !thisUserHasConnectedDevice) {
else if (EventType.CallNotify === type && (ev.getAge() ?? 0) < 15000 && !thisUserHasConnectedDevice) {
const content = ev.getContent();
const roomId = ev.getRoomId();
if (typeof content.call_id !== "string") {
logger.warn("Received malformatted CallNotify event. Did not contain 'call_id' of type 'string'");
return;

View File

@ -371,6 +371,7 @@ describe("Notifier", () => {
beforeEach(() => {
jest.spyOn(SettingsStore, "getValue").mockReturnValue(true);
jest.spyOn(ToastStore.sharedInstance(), "addOrReplaceToast");
jest.spyOn(ToastStore.sharedInstance(), "dismissToast");
mockClient.getPushActionsForEvent.mockReturnValue({
notify: true,
@ -443,6 +444,52 @@ describe("Notifier", () => {
spyCallMemberships.mockRestore();
});
it("dismisses call notification when another device answers the call", () => {
const notifyEvent = emitCallNotifyEvent();
const spyCallMemberships = jest.spyOn(MatrixRTCSession, "callMembershipsForRoom");
expect(ToastStore.sharedInstance().addOrReplaceToast).toHaveBeenCalledWith(
expect.objectContaining({
key: getIncomingCallToastKey(notifyEvent.getContent().call_id ?? "", roomId),
priority: 100,
component: IncomingCallToast,
bodyClassName: "mx_IncomingCallToast",
props: { notifyEvent },
}),
);
// Mock ourselves joining the call.
spyCallMemberships.mockReturnValue([
new CallMembership(
mkEvent({
event: true,
room: testRoom.roomId,
user: userId,
type: EventType.GroupCallMemberPrefix,
content: {},
}),
{
call_id: "123",
application: "m.call",
focus_active: { type: "livekit" },
foci_preferred: [],
device_id: "DEVICE",
},
),
]);
const callEvent = mkEvent({
type: EventType.GroupCallMemberPrefix,
user: "@alice:foo",
room: roomId,
content: {
call_id: "abc123",
},
event: true,
});
emitLiveEvent(callEvent);
expect(ToastStore.sharedInstance().dismissToast).toHaveBeenCalled();
spyCallMemberships.mockRestore();
});
it("should not show toast when calling with non-group call event", () => {
emitCallNotifyEvent("event_type");