Add ringing for matrixRTC (#11870)

* Add ringing for matrixRTC
 - since we are using m.mentions we start with the Notifier
 - an event in the Notifier will result in a IncomingCall toast
 -  incomingCallToast is responsible for ringing (as long as one can see the toast it rings)
 This should make sure visual and audio signal are in sync.

Signed-off-by: Timo K <toger5@hotmail.de>

* use typed CallNotifyContent

Signed-off-by: Timo K <toger5@hotmail.de>

* update tests

Signed-off-by: Timo K <toger5@hotmail.de>

* change to callId

Signed-off-by: Timo K <toger5@hotmail.de>

* fix tests

Signed-off-by: Timo K <toger5@hotmail.de>

* only ring in 1:1 calls
notify in rooms < 15 member

Signed-off-by: Timo K <toger5@hotmail.de>

* call_id fallback

Signed-off-by: Timo K <toger5@hotmail.de>

* Update src/Notifier.ts

Co-authored-by: Robin <robin@robin.town>

* review

Signed-off-by: Timo K <toger5@hotmail.de>

* add tests

Signed-off-by: Timo K <toger5@hotmail.de>

* more tests

Signed-off-by: Timo K <toger5@hotmail.de>

* unused import

Signed-off-by: Timo K <toger5@hotmail.de>

* String -> string

Signed-off-by: Timo K <toger5@hotmail.de>

---------

Signed-off-by: Timo K <toger5@hotmail.de>
Co-authored-by: Robin <robin@robin.town>
This commit is contained in:
Timo 2023-11-21 18:12:08 +01:00 committed by GitHub
parent 7ca0cd13d0
commit a26c2d3c78
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 230 additions and 50 deletions

View file

@ -19,6 +19,12 @@ import { render, screen, cleanup, fireEvent, waitFor } from "@testing-library/re
import { mocked, Mocked } from "jest-mock";
import { Room, RoomStateEvent, MatrixEvent, MatrixEventEvent, MatrixClient } from "matrix-js-sdk/src/matrix";
import { ClientWidgetApi, Widget } from "matrix-widget-api";
// eslint-disable-next-line no-restricted-imports
import { MatrixRTCSessionManagerEvents } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSessionManager";
// eslint-disable-next-line no-restricted-imports
import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
// eslint-disable-next-line no-restricted-imports
import { ICallNotifyContent } from "matrix-js-sdk/src/matrixrtc/types";
import type { RoomMember } from "matrix-js-sdk/src/matrix";
import {
@ -37,6 +43,7 @@ import { WidgetMessagingStore } from "../../src/stores/widgets/WidgetMessagingSt
import DMRoomMap from "../../src/utils/DMRoomMap";
import ToastStore from "../../src/stores/ToastStore";
import { getIncomingCallToastKey, IncomingCallToast } from "../../src/toasts/IncomingCallToast";
import { AudioID } from "../../src/LegacyCallHandler";
describe("IncomingCallEvent", () => {
useMockedCalls();
@ -44,6 +51,7 @@ describe("IncomingCallEvent", () => {
let client: Mocked<MatrixClient>;
let room: Room;
let notifyContent: ICallNotifyContent;
let alice: RoomMember;
let bob: RoomMember;
let call: MockedCall;
@ -59,8 +67,15 @@ describe("IncomingCallEvent", () => {
stubClient();
client = mocked(MatrixClientPeg.safeGet());
room = new Room("!1:example.org", client, "@alice:example.org");
const audio = document.createElement("audio");
audio.id = AudioID.Ring;
document.body.appendChild(audio);
room = new Room("!1:example.org", client, "@alice:example.org");
notifyContent = {
call_id: "",
getRoomId: () => room.roomId,
} as unknown as ICallNotifyContent;
alice = mkRoomMember(room.roomId, "@alice:example.org");
bob = mkRoomMember(room.roomId, "@bob:example.org");
@ -97,7 +112,8 @@ describe("IncomingCallEvent", () => {
});
const renderToast = () => {
render(<IncomingCallToast callEvent={call.event} />);
call.event.getContent = () => notifyContent as any;
render(<IncomingCallToast notifyEvent={call.event} />);
};
it("correctly shows all the information", () => {
@ -115,6 +131,20 @@ describe("IncomingCallEvent", () => {
screen.getByRole("button", { name: "Close" });
});
it("start ringing on ring notify event", () => {
call.event.getContent = () =>
({
...notifyContent,
notify_type: "ring",
} as any);
const playMock = jest.fn();
const audio = { play: playMock, paused: true };
jest.spyOn(document, "getElementById").mockReturnValue(audio as any);
render(<IncomingCallToast notifyEvent={call.event} />);
expect(playMock).toHaveBeenCalled();
});
it("correctly renders toast without a call", () => {
call.destroy();
renderToast();
@ -141,7 +171,9 @@ describe("IncomingCallEvent", () => {
}),
);
await waitFor(() =>
expect(toastStore.dismissToast).toHaveBeenCalledWith(getIncomingCallToastKey(call.event.getStateKey()!)),
expect(toastStore.dismissToast).toHaveBeenCalledWith(
getIncomingCallToastKey(notifyContent.call_id, room.roomId),
),
);
defaultDispatcher.unregister(dispatcherRef);
@ -155,7 +187,9 @@ describe("IncomingCallEvent", () => {
fireEvent.click(screen.getByRole("button", { name: "Close" }));
await waitFor(() =>
expect(toastStore.dismissToast).toHaveBeenCalledWith(getIncomingCallToastKey(call.event.getStateKey()!)),
expect(toastStore.dismissToast).toHaveBeenCalledWith(
getIncomingCallToastKey(notifyContent.call_id, room.roomId),
),
);
defaultDispatcher.unregister(dispatcherRef);
@ -171,7 +205,9 @@ describe("IncomingCallEvent", () => {
});
await waitFor(() =>
expect(toastStore.dismissToast).toHaveBeenCalledWith(getIncomingCallToastKey(call.event.getStateKey()!)),
expect(toastStore.dismissToast).toHaveBeenCalledWith(
getIncomingCallToastKey(notifyContent.call_id, room.roomId),
),
);
});
@ -182,7 +218,24 @@ describe("IncomingCallEvent", () => {
event.emit(MatrixEventEvent.BeforeRedaction, event, {} as unknown as MatrixEvent);
await waitFor(() =>
expect(toastStore.dismissToast).toHaveBeenCalledWith(getIncomingCallToastKey(call.event.getStateKey()!)),
expect(toastStore.dismissToast).toHaveBeenCalledWith(
getIncomingCallToastKey(notifyContent.call_id, room.roomId),
),
);
});
it("closes toast when the matrixRTC session has ended", async () => {
renderToast();
client.matrixRTC.emit(MatrixRTCSessionManagerEvents.SessionEnded, room.roomId, {
callId: notifyContent.call_id,
room: room,
} as unknown as MatrixRTCSession);
await waitFor(() =>
expect(toastStore.dismissToast).toHaveBeenCalledWith(
getIncomingCallToastKey(notifyContent.call_id, room.roomId),
),
);
});
});