provide option to use the New MembershipManager

This commit is contained in:
Timo
2025-02-27 12:23:50 +01:00
parent 66899f33e2
commit 3f35eeebe5
9 changed files with 102 additions and 31 deletions

View File

@@ -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": {

View File

@@ -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",

View File

@@ -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<Props> = ({
};
}, [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<Props> = ({
avatarUrl: avatarUrl!,
roomId: rtcSession.room.roomId,
roomName,
roomAlias: rtcSession.room.getCanonicalAlias(),
roomAlias: room.getCanonicalAlias(),
roomAvatar,
e2eeSystem,
};
@@ -156,8 +175,9 @@ export const GroupCallView: FC<Props> = ({
client,
displayName,
avatarUrl,
rtcSession.room,
rtcSession.room.roomId,
roomName,
room,
roomAvatar,
e2eeSystem,
]);
@@ -175,9 +195,14 @@ export const GroupCallView: FC<Props> = ({
const enterRTCSessionOrError = async (
rtcSession: MatrixRTCSession,
perParticipantE2EE: boolean,
newMembershipManager: boolean,
): Promise<void> => {
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<Props> = ({
// 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<Props> = ({
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<Props> = ({
} else {
// No lobby and no preload: we enter the rtc session right away
(async (): Promise<void> => {
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<Props> = ({
perParticipantE2EE,
latestDevices,
latestMuteStates,
newMembershipManager,
]);
const [left, setLeft] = useState(false);
@@ -351,7 +389,7 @@ export const GroupCallView: FC<Props> = ({
}
}, [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<Props> = ({
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<Props> = ({
);
}
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<Props> = ({
const shareModal = (
<InviteModal
room={rtcSession.room}
room={room}
open={shareModalOpen}
onDismiss={onDismissInviteModal}
/>
@@ -430,7 +472,11 @@ export const GroupCallView: FC<Props> = ({
matrixInfo={matrixInfo}
muteStates={muteStates}
onEnter={() =>
void enterRTCSessionOrError(rtcSession, perParticipantE2EE)
void enterRTCSessionOrError(
rtcSession,
perParticipantE2EE,
newMembershipManager,
)
}
confineToRoom={confineToRoom}
hideHeader={hideHeader}

View File

@@ -105,6 +105,7 @@ test("It joins the correct Session", async () => {
{
manageMediaKeys: false,
useLegacyMemberEvents: false,
useNewMembershipManager: true,
},
);
});

View File

@@ -96,6 +96,7 @@ async function makePreferredLivekitFoci(
export async function enterRTCSession(
rtcSession: MatrixRTCSession,
encryptMedia: boolean,
useNewMembershipManager = true,
): Promise<void> {
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,

View File

@@ -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<Props> = ({ 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<Props> = ({ client, livekitRoom }) => {
)}
/>
</FieldRow>
<FieldRow>
<InputField
id="useNewMembershipManager"
type="checkbox"
label={t("developer_mode.use_NewMembershipmanager")}
checked={!!useNewMembershipManager}
onChange={useCallback(
(event: ChangeEvent<HTMLInputElement>): void => {
setNewMembershipManager(event.target.checked);
},
[setNewMembershipManager],
)}
/>
</FieldRow>
{livekitRoom ? (
<>
<p>

View File

@@ -113,4 +113,8 @@ export const soundEffectVolumeSetting = new Setting<number>(
0.5,
);
export const useNewMembershipManagerSetting = new Setting<boolean>(
"new-membership-manager",
true,
);
export const alwaysShowSelf = new Setting<boolean>("always-show-self", true);

View File

@@ -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.

View File

@@ -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"