diff --git a/spec/test-utils/webrtc.ts b/spec/test-utils/webrtc.ts index ba93a6c1c97..18b2f3050ad 100644 --- a/spec/test-utils/webrtc.ts +++ b/spec/test-utils/webrtc.ts @@ -585,6 +585,7 @@ export function makeMockGroupCallStateEvent( "m.type": GroupCallType.Video, "m.intent": GroupCallIntent.Prompt, }, + redacted?: boolean, ): MatrixEvent { return { getType: jest.fn().mockReturnValue(EventType.GroupCallPrefix), @@ -592,6 +593,7 @@ export function makeMockGroupCallStateEvent( getTs: jest.fn().mockReturnValue(0), getContent: jest.fn().mockReturnValue(content), getStateKey: jest.fn().mockReturnValue(groupCallId), + isRedacted: jest.fn().mockReturnValue(redacted ?? false), } as unknown as MatrixEvent; } diff --git a/spec/unit/webrtc/groupCallEventHandler.spec.ts b/spec/unit/webrtc/groupCallEventHandler.spec.ts index 6c97988bf46..c8d65538c60 100644 --- a/spec/unit/webrtc/groupCallEventHandler.spec.ts +++ b/spec/unit/webrtc/groupCallEventHandler.spec.ts @@ -98,6 +98,23 @@ describe("Group Call Event Handler", function () { expect(groupCall.state).toBe(GroupCallState.Ended); }); + + it("terminates call when redacted", async () => { + await groupCallEventHandler.start(); + mockClient.emitRoomState(makeMockGroupCallStateEvent(FAKE_ROOM_ID, FAKE_GROUP_CALL_ID), { + roomId: FAKE_ROOM_ID, + } as unknown as RoomState); + + const groupCall = groupCallEventHandler.groupCalls.get(FAKE_ROOM_ID)!; + + expect(groupCall.state).toBe(GroupCallState.LocalCallFeedUninitialized); + + mockClient.emitRoomState(makeMockGroupCallStateEvent(FAKE_ROOM_ID, FAKE_GROUP_CALL_ID, undefined, true), { + roomId: FAKE_ROOM_ID, + } as unknown as RoomState); + + expect(groupCall.state).toBe(GroupCallState.Ended); + }); }); it("waits until client starts syncing", async () => { @@ -222,9 +239,9 @@ describe("Group Call Event Handler", function () { jest.clearAllMocks(); }); - const setupCallAndStart = async (content?: IContent) => { + const setupCallAndStart = async (content?: IContent, redacted?: boolean) => { mocked(mockRoom.currentState.getStateEvents).mockReturnValue([ - makeMockGroupCallStateEvent(FAKE_ROOM_ID, FAKE_GROUP_CALL_ID, content), + makeMockGroupCallStateEvent(FAKE_ROOM_ID, FAKE_GROUP_CALL_ID, content, redacted), ] as unknown as MatrixEvent); mockClient.getRooms.mockReturnValue([mockRoom]); await groupCallEventHandler.start(); @@ -285,5 +302,24 @@ describe("Group Call Event Handler", function () { }), ); }); + + it("ignores redacted calls", async () => { + await setupCallAndStart( + { + // Real event contents to make sure that it's specifically the + // event being redacted that causes it to be ignored + "m.type": GroupCallType.Video, + "m.intent": GroupCallIntent.Prompt, + }, + true, + ); + + expect(mockClientEmit).not.toHaveBeenCalledWith( + GroupCallEventHandlerEvent.Incoming, + expect.objectContaining({ + groupCallId: FAKE_GROUP_CALL_ID, + }), + ); + }); }); }); diff --git a/src/webrtc/groupCallEventHandler.ts b/src/webrtc/groupCallEventHandler.ts index 7be97771447..08487bdd234 100644 --- a/src/webrtc/groupCallEventHandler.ts +++ b/src/webrtc/groupCallEventHandler.ts @@ -118,7 +118,7 @@ export class GroupCallEventHandler { for (const callEvent of sortedCallEvents) { const content = callEvent.getContent(); - if (content["m.terminated"]) { + if (content["m.terminated"] || callEvent.isRedacted()) { continue; } @@ -210,10 +210,10 @@ export class GroupCallEventHandler { const currentGroupCall = this.groupCalls.get(state.roomId); - if (!currentGroupCall && !content["m.terminated"]) { + if (!currentGroupCall && !content["m.terminated"] && !event.isRedacted()) { this.createGroupCallFromRoomStateEvent(event); } else if (currentGroupCall && currentGroupCall.groupCallId === groupCallId) { - if (content["m.terminated"]) { + if (content["m.terminated"] || event.isRedacted()) { currentGroupCall.terminate(false); } else if (content["m.type"] !== currentGroupCall.type) { // TODO: Handle the callType changing when the room state changes