diff --git a/locales/en/app.json b/locales/en/app.json index 30c134bf..bbcad391 100644 --- a/locales/en/app.json +++ b/locales/en/app.json @@ -70,7 +70,8 @@ "livekit_sfu": "LiveKit SFU: {{url}}", "matrix_id": "Matrix ID: {{id}}", "show_connection_stats": "Show connection statistics", - "show_non_member_tiles": "Show tiles for non-member media" + "show_non_member_tiles": "Show tiles for non-member media", + "use_NewMembershipmanager": "Use the new implementation of the call MembershipManager" }, "disconnected_banner": "Connectivity to the server has been lost.", "error": { diff --git a/package.json b/package.json index 07a9204a..227a1b07 100644 --- a/package.json +++ b/package.json @@ -91,7 +91,7 @@ "livekit-client": "^2.5.7", "lodash-es": "^4.17.21", "loglevel": "^1.9.1", - "matrix-js-sdk": "^36.1.0", + "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#e2d131e2b82a33ba28be9b7700a5e61aa15ab238", "matrix-widget-api": "1.11.0", "normalize.css": "^8.0.1", "observable-hooks": "^4.2.3", diff --git a/src/room/GroupCallView.tsx b/src/room/GroupCallView.tsx index 95d1d12c..487ac549 100644 --- a/src/room/GroupCallView.tsx +++ b/src/room/GroupCallView.tsx @@ -16,12 +16,15 @@ import { } from "react"; import { type MatrixClient } from "matrix-js-sdk/src/client"; import { + Room as LivekitRoom, isE2EESupported as isE2EESupportedBrowser, - Room, } from "livekit-client"; import { logger } from "matrix-js-sdk/src/logger"; -import { type MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession"; -import { JoinRule } from "matrix-js-sdk/src/matrix"; +import { + MatrixRTCSessionEvent, + type MatrixRTCSession, +} from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession"; +import { JoinRule, type Room } from "matrix-js-sdk/src/matrix"; import { OfflineIcon, WebBrowserIcon, @@ -68,6 +71,11 @@ import { ErrorCode, } from "../utils/errors.ts"; import { ElementCallRichError } from "../RichError.tsx"; +import { + useNewMembershipManagerSetting as useNewMembershipManagerSetting, + useSetting, +} from "../settings/settings"; +import { useTypedEventEmitter } from "../useEvents"; declare global { interface Window { @@ -126,19 +134,30 @@ export const GroupCallView: FC = ({ }; }, [rtcSession]); + useTypedEventEmitter( + rtcSession, + MatrixRTCSessionEvent.MembershipManagerError, + // TODO: make this set the error state so that we can render an error page. + (error) => logger.error(error), + ); useEffect(() => { // Sanity check the room object - if (client.getRoom(rtcSession.room.roomId) !== rtcSession.room) + if (client.getRoom(rtcSession.room.roomId) !== rtcSession.room) { logger.warn( `We've ended up with multiple rooms for the same ID (${rtcSession.room.roomId}). This indicates a bug in the group call loading code, and may lead to incomplete room state.`, ); + return undefined; + } }, [client, rtcSession.room]); + const room = rtcSession.room as Room; const { displayName, avatarUrl } = useProfile(client); - const roomName = useRoomName(rtcSession.room); - const roomAvatar = useRoomAvatar(rtcSession.room); + const roomName = useRoomName(room); + const roomAvatar = useRoomAvatar(room); const { perParticipantE2EE, returnToLobby } = useUrlParams(); const e2eeSystem = useRoomEncryptionSystem(rtcSession.room.roomId); + const [newMembershipManager] = useSetting(useNewMembershipManagerSetting); + usePageTitle(roomName); const matrixInfo = useMemo((): MatrixInfo => { @@ -148,7 +167,7 @@ export const GroupCallView: FC = ({ avatarUrl: avatarUrl!, roomId: rtcSession.room.roomId, roomName, - roomAlias: rtcSession.room.getCanonicalAlias(), + roomAlias: room.getCanonicalAlias(), roomAvatar, e2eeSystem, }; @@ -156,8 +175,9 @@ export const GroupCallView: FC = ({ client, displayName, avatarUrl, - rtcSession.room, + rtcSession.room.roomId, roomName, + room, roomAvatar, e2eeSystem, ]); @@ -175,9 +195,14 @@ export const GroupCallView: FC = ({ const enterRTCSessionOrError = async ( rtcSession: MatrixRTCSession, perParticipantE2EE: boolean, + newMembershipManager: boolean, ): Promise => { try { - await enterRTCSession(rtcSession, perParticipantE2EE); + await enterRTCSession( + rtcSession, + perParticipantE2EE, + newMembershipManager, + ); } catch (e) { if (e instanceof ElementCallError) { // e.code === ErrorCode.MISSING_LIVE_KIT_SERVICE_URL) @@ -203,7 +228,7 @@ export const GroupCallView: FC = ({ // permissions and give you device names unless you specify a kind, but // here we want all kinds of devices. This needs a fix in livekit-client // for the following name-matching logic to do anything useful. - const devices = await Room.getLocalDevices(undefined, true); + const devices = await LivekitRoom.getLocalDevices(undefined, true); if (audioInput) { const deviceId = findDeviceByName(audioInput, "audioinput", devices); @@ -243,7 +268,11 @@ export const GroupCallView: FC = ({ await defaultDeviceSetup( ev.detail.data as unknown as JoinCallData, ); - await enterRTCSessionOrError(rtcSession, perParticipantE2EE); + await enterRTCSessionOrError( + rtcSession, + perParticipantE2EE, + newMembershipManager, + ); widget.api.transport.reply(ev.detail, {}); })().catch((e) => { logger.error("Error joining RTC session", e); @@ -256,13 +285,21 @@ export const GroupCallView: FC = ({ } else { // No lobby and no preload: we enter the rtc session right away (async (): Promise => { - await enterRTCSessionOrError(rtcSession, perParticipantE2EE); + await enterRTCSessionOrError( + rtcSession, + perParticipantE2EE, + newMembershipManager, + ); })().catch((e) => { logger.error("Error joining RTC session", e); }); } } else { - void enterRTCSessionOrError(rtcSession, perParticipantE2EE); + void enterRTCSessionOrError( + rtcSession, + perParticipantE2EE, + newMembershipManager, + ); } } }, [ @@ -273,6 +310,7 @@ export const GroupCallView: FC = ({ perParticipantE2EE, latestDevices, latestMuteStates, + newMembershipManager, ]); const [left, setLeft] = useState(false); @@ -351,7 +389,7 @@ export const GroupCallView: FC = ({ } }, [widget, isJoined, rtcSession]); - const joinRule = useJoinRule(rtcSession.room); + const joinRule = useJoinRule(room); const [shareModalOpen, setInviteModalOpen] = useState(false); const onDismissInviteModal = useCallback( @@ -379,8 +417,12 @@ export const GroupCallView: FC = ({ const onReconnect = useCallback(() => { setLeft(false); resetError(); - enterRTCSessionOrError(rtcSession, perParticipantE2EE).catch((e) => { - logger.error("Error re-entering RTC session", e); + enterRTCSessionOrError( + rtcSession, + perParticipantE2EE, + newMembershipManager, + ).catch((e) => { + logger.error("Error re-entering RTC session on reconnect", e); }); }, [resetError]); @@ -402,7 +444,7 @@ export const GroupCallView: FC = ({ ); } return GroupCallErrorPage; - }, [onLeave, rtcSession, perParticipantE2EE, t]); + }, [t, rtcSession, onLeave, perParticipantE2EE, newMembershipManager]); if (!isE2EESupportedBrowser() && e2eeSystem.kind !== E2eeType.NONE) { // If we have a encryption system but the browser does not support it. @@ -417,7 +459,7 @@ export const GroupCallView: FC = ({ const shareModal = ( @@ -430,7 +472,11 @@ export const GroupCallView: FC = ({ matrixInfo={matrixInfo} muteStates={muteStates} onEnter={() => - void enterRTCSessionOrError(rtcSession, perParticipantE2EE) + void enterRTCSessionOrError( + rtcSession, + perParticipantE2EE, + newMembershipManager, + ) } confineToRoom={confineToRoom} hideHeader={hideHeader} diff --git a/src/rtcSessionHelpers.test.ts b/src/rtcSessionHelpers.test.ts index 21ee2cd3..62a2c187 100644 --- a/src/rtcSessionHelpers.test.ts +++ b/src/rtcSessionHelpers.test.ts @@ -105,6 +105,7 @@ test("It joins the correct Session", async () => { { manageMediaKeys: false, useLegacyMemberEvents: false, + useNewMembershipManager: true, }, ); }); diff --git a/src/rtcSessionHelpers.ts b/src/rtcSessionHelpers.ts index 719af998..838dbe95 100644 --- a/src/rtcSessionHelpers.ts +++ b/src/rtcSessionHelpers.ts @@ -96,6 +96,7 @@ async function makePreferredLivekitFoci( export async function enterRTCSession( rtcSession: MatrixRTCSession, encryptMedia: boolean, + useNewMembershipManager = true, ): Promise { PosthogAnalytics.instance.eventCallEnded.cacheStartCall(new Date()); PosthogAnalytics.instance.eventCallStarted.track(rtcSession.room.roomId); @@ -113,6 +114,7 @@ export async function enterRTCSession( await makePreferredLivekitFoci(rtcSession, livekitAlias), makeActiveFocus(), { + useNewMembershipManager, manageMediaKeys: encryptMedia, ...(useDeviceSessionMemberEvents !== undefined && { useLegacyMemberEvents: !useDeviceSessionMemberEvents, diff --git a/src/settings/DeveloperSettingsTab.tsx b/src/settings/DeveloperSettingsTab.tsx index c7c88f5b..31f40a58 100644 --- a/src/settings/DeveloperSettingsTab.tsx +++ b/src/settings/DeveloperSettingsTab.tsx @@ -15,6 +15,7 @@ import { debugTileLayout as debugTileLayoutSetting, showNonMemberTiles as showNonMemberTilesSetting, showConnectionStats as showConnectionStatsSetting, + useNewMembershipManagerSetting, } from "./settings"; import type { MatrixClient } from "matrix-js-sdk/src/client"; import type { Room as LivekitRoom } from "livekit-client"; @@ -38,6 +39,10 @@ export const DeveloperSettingsTab: FC = ({ client, livekitRoom }) => { showConnectionStatsSetting, ); + const [useNewMembershipManager, setNewMembershipManager] = useSetting( + useNewMembershipManagerSetting, + ); + const sfuUrl = useMemo((): URL | null => { if (livekitRoom?.engine.client.ws?.url) { // strip the URL params @@ -134,6 +139,20 @@ export const DeveloperSettingsTab: FC = ({ client, livekitRoom }) => { )} /> + + ): void => { + setNewMembershipManager(event.target.checked); + }, + [setNewMembershipManager], + )} + /> + {livekitRoom ? ( <>

diff --git a/src/settings/settings.ts b/src/settings/settings.ts index 4ec0143f..ee43acc6 100644 --- a/src/settings/settings.ts +++ b/src/settings/settings.ts @@ -113,4 +113,8 @@ export const soundEffectVolumeSetting = new Setting( 0.5, ); +export const useNewMembershipManagerSetting = new Setting( + "new-membership-manager", + true, +); export const alwaysShowSelf = new Setting("always-show-self", true); diff --git a/src/utils/matrix.ts b/src/utils/matrix.ts index c80fa7d9..ee0158cc 100644 --- a/src/utils/matrix.ts +++ b/src/utils/matrix.ts @@ -160,7 +160,6 @@ export async function initClient( ); } - client.setGlobalErrorOnUnknownDevices(false); // Once startClient is called, syncs are run asynchronously. // Also, sync completion is communicated only via events. // So, apply the event listener *before* starting the client. diff --git a/yarn.lock b/yarn.lock index d77c98e8..d3527c12 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1763,10 +1763,10 @@ dependencies: "@bufbuild/protobuf" "^1.10.0" -"@matrix-org/matrix-sdk-crypto-wasm@^12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-wasm/-/matrix-sdk-crypto-wasm-12.1.0.tgz#2aef64eab2d30c0a1ace9c0fe876f53aa2949f14" - integrity sha512-NhJFu/8FOGjnW7mDssRUzaMSwXrYOcCqgAjZyAw9KQ9unNADKEi7KoIKe7GtrG2PWtm36y2bUf+hB8vhSY6Wdw== +"@matrix-org/matrix-sdk-crypto-wasm@^14.0.1": + version "14.0.1" + resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-wasm/-/matrix-sdk-crypto-wasm-14.0.1.tgz#e258ef84bcc7889f0e7eb3a7dbecf0830a6dd606" + integrity sha512-CgLpHs6nTw5pjSsMBi9xbQnBXf2l8YhImQP9cv8nbGSCYdYjFI0FilMXffzjWV5HThpNHri/3pF20ahZtuS3VA== "@matrix-org/olm@3.2.15": version "3.2.15" @@ -6317,13 +6317,12 @@ matrix-events-sdk@0.0.1: resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1.tgz#c8c38911e2cb29023b0bbac8d6f32e0de2c957dd" integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA== -matrix-js-sdk@^36.1.0: - version "36.1.0" - resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-36.1.0.tgz#3685a85c0c1adf4e2c3622bce76c11430963f23d" - integrity sha512-KNPswMSAGKDxBybJedxRpWadaRes9paxmjTCUsQT8t1Jg3ZENraAt6ynIaxh6PxazAH9D5ly6EYKHaLMLbZ1Dg== +"matrix-js-sdk@github:matrix-org/matrix-js-sdk#e2d131e2b82a33ba28be9b7700a5e61aa15ab238": + version "37.0.0" + resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/e2d131e2b82a33ba28be9b7700a5e61aa15ab238" dependencies: "@babel/runtime" "^7.12.5" - "@matrix-org/matrix-sdk-crypto-wasm" "^12.1.0" + "@matrix-org/matrix-sdk-crypto-wasm" "^14.0.1" "@matrix-org/olm" "3.2.15" another-json "^0.2.0" bs58 "^6.0.0"