Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Make video rooms compatible with matrix RTC #11829

Merged
merged 3 commits into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 14 additions & 12 deletions src/models/Call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import ActiveWidgetStore, { ActiveWidgetStoreEvent } from "../stores/ActiveWidge
import { getCurrentLanguage } from "../languageHandler";
import { FontWatcher } from "../settings/watchers/FontWatcher";
import { PosthogAnalytics } from "../PosthogAnalytics";
import { UPDATE_EVENT } from "../stores/AsyncStore";

const TIMEOUT_MS = 16000;

Expand Down Expand Up @@ -225,7 +226,7 @@ export abstract class Call extends TypedEventEmitter<CallEvent, CallEventHandler
const messagingStore = WidgetMessagingStore.instance;
this.messaging = messagingStore.getMessagingForUid(this.widgetUid) ?? null;
if (!this.messaging) {
// The widget might still be initializing, so wait for it
// The widget might still be initializing, so wait for it.
try {
await waitForEvent(
messagingStore,
Expand Down Expand Up @@ -632,12 +633,10 @@ export class ElementCall extends Call {
this.emit(CallEvent.Layout, value);
}

private static createCallWidget(roomId: string, client: MatrixClient): IApp {
private static createOrGetCallWidget(roomId: string, client: MatrixClient): IApp {
const ecWidget = WidgetStore.instance.getApps(roomId).find((app) => WidgetType.CALL.matches(app.type));
if (ecWidget) {
logger.log("There is already a widget in this room, so we recreate it");
ActiveWidgetStore.instance.destroyPersistentWidget(ecWidget.id, ecWidget.roomId);
WidgetStore.instance.removeVirtualWidget(ecWidget.id, ecWidget.roomId);
return ecWidget;
}
const accountAnalyticsData = client.getAccountData(PosthogAnalytics.ANALYTICS_EVENT_TYPE);
// The analyticsID is passed directly to element call (EC) since this codepath is only for EC and no other widget.
Expand Down Expand Up @@ -707,23 +706,24 @@ export class ElementCall extends Call {
}

public static get(room: Room): ElementCall | null {
// Only supported in the new group call experience or in video rooms
// Only supported in the new group call experience or in video rooms.
if (
SettingsStore.getValue("feature_group_calls") ||
(SettingsStore.getValue("feature_video_rooms") &&
SettingsStore.getValue("feature_element_call_video_rooms") &&
room.isCallRoom())
) {
const apps = WidgetStore.instance.getApps(room.roomId);
const ecWidget = apps.find((app) => WidgetType.CALL.matches(app.type));
const hasEcWidget = apps.some((app) => WidgetType.CALL.matches(app.type));
const session = room.client.matrixRTC.getRoomSession(room);

// A call is present if we
// - have a widget: This means the create function was called
// - have a widget: This means the create function was called.
// - or there is a running session where we have not yet created a widget for.
if (ecWidget || session.memberships.length !== 0) {
// - or this this is a call room. Then we also always want to show a call.
if (hasEcWidget || session.memberships.length !== 0 || room.isCallRoom()) {
// create a widget for the case we are joining a running call and don't have on yet.
const availableOrCreatedWidget = ecWidget ?? ElementCall.createCallWidget(room.roomId, room.client);
const availableOrCreatedWidget = ElementCall.createOrGetCallWidget(room.roomId, room.client);
return new ElementCall(session, availableOrCreatedWidget, room.client);
}
}
Expand All @@ -738,7 +738,8 @@ export class ElementCall extends Call {
room.isCallRoom();

console.log("Intend is ", isVideoRoom ? "VideoRoom" : "Prompt", " TODO, handle intent appropriately");
ElementCall.createCallWidget(room.roomId, room.client);
ElementCall.createOrGetCallWidget(room.roomId, room.client);
WidgetStore.instance.emit(UPDATE_EVENT, null);
}

protected async performConnection(
Expand Down Expand Up @@ -790,7 +791,8 @@ export class ElementCall extends Call {
}

private onRTCSessionEnded = (roomId: string, session: MatrixRTCSession): void => {
if (roomId == this.roomId) {
// Don't destroy widget on hangup for video call rooms.
if (roomId == this.roomId && !this.room.isCallRoom()) {
this.destroy();
}
};
Expand Down
1 change: 0 additions & 1 deletion src/stores/WidgetStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,6 @@ export default class WidgetStore extends AsyncStoreWithClient<IState> {
const app = WidgetUtils.makeAppConfig(widget.id, widget, widget.creatorUserId, roomId, undefined);
this.widgetMap.set(WidgetUtils.getWidgetUid(app), app);
this.roomMap.get(roomId)!.widgets.push(app);
this.emit(UPDATE_EVENT, roomId);
return app;
}

Expand Down
8 changes: 7 additions & 1 deletion test/models/Call-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -596,16 +596,19 @@ describe("ElementCall", () => {
it("finds calls", async () => {
await ElementCall.create(room);
expect(Call.get(room)).toBeInstanceOf(ElementCall);
Call.get(room)?.destroy();
});

it("finds ongoing calls that are created by the session manager", async () => {
// There is an existing session created by another user in this room.
client.matrixRTC.getRoomSession.mockReturnValue({
on: (ev: any, fn: any) => {},
off: (ev: any, fn: any) => {},
memberships: [{ fakeVal: "fake membership" }],
} as unknown as MatrixRTCSession);
const call = Call.get(room);
if (!(call instanceof ElementCall)) throw new Error("Failed to create call");
call.destroy();
});

it("passes font settings through widget URL", async () => {
Expand Down Expand Up @@ -642,6 +645,7 @@ describe("ElementCall", () => {

const urlParams1 = new URLSearchParams(new URL(call1.widget.url).hash.slice(1));
expect(urlParams1.has("allowIceFallback")).toBe(false);
call1.destroy();

// Now test with the preference set to true
const originalGetValue = SettingsStore.getValue;
Expand All @@ -654,13 +658,14 @@ describe("ElementCall", () => {
}
};

await ElementCall.create(room);
ElementCall.create(room);
const call2 = Call.get(room);
if (!(call2 instanceof ElementCall)) throw new Error("Failed to create call");

const urlParams2 = new URLSearchParams(new URL(call2.widget.url).hash.slice(1));
expect(urlParams2.has("allowIceFallback")).toBe(true);

call2.destroy();
SettingsStore.getValue = originalGetValue;
});

Expand All @@ -677,6 +682,7 @@ describe("ElementCall", () => {

const urlParams = new URLSearchParams(new URL(call.widget.url).hash.slice(1));
expect(urlParams.get("analyticsID")).toBe("123456789987654321");
call.destroy();
});

it("does not pass analyticsID if `pseudonymousAnalyticsOptIn` set to false", async () => {
Expand Down
Loading