Merge pull request #3516 from element-hq/toger5/voip-team/rebased-multiSFU-bump-to-new-js-sdk-version

Use updated multi sfu js-sdk
This commit is contained in:
Robin
2025-09-30 11:24:12 -04:00
committed by GitHub
5 changed files with 48 additions and 92 deletions

View File

@@ -1,45 +0,0 @@
/*
Copyright 2023, 2024 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE in the repository root for full details.
*/
import {
type MatrixRTCSession,
MatrixRTCSessionEvent,
} from "matrix-js-sdk/lib/matrixrtc";
import { useCallback, useRef } from "react";
import { deepCompare } from "matrix-js-sdk/lib/utils";
import { logger } from "matrix-js-sdk/lib/logger";
import { type LivekitFocus, isLivekitFocus } from "matrix-js-sdk/lib/matrixrtc";
import { useTypedEventEmitterState } from "../useEvents";
/**
* Gets the currently active (livekit) focus for a MatrixRTC session
* This logic is specific to livekit foci where the whole call must use one
* and the same focus.
*/
export function useActiveLivekitFocus(
rtcSession: MatrixRTCSession,
): LivekitFocus | undefined {
const prevActiveFocus = useRef<LivekitFocus | undefined>(undefined);
return useTypedEventEmitterState(
rtcSession,
MatrixRTCSessionEvent.MembershipsChanged,
useCallback(() => {
const f = rtcSession.getActiveFocus();
// Only handle foci with type="livekit" for now.
if (f && isLivekitFocus(f) && !deepCompare(f, prevActiveFocus.current)) {
const oldestMembership = rtcSession.getOldestMembership();
logger.info(
`Got new active focus from membership: ${oldestMembership?.sender}/${oldestMembership?.deviceId}.
Updated focus (focus switch) from ${JSON.stringify(prevActiveFocus.current)} to ${JSON.stringify(f)}`,
);
prevActiveFocus.current = f;
}
return prevActiveFocus.current;
}, [rtcSession]),
);
}

View File

@@ -6,11 +6,10 @@ Please see LICENSE in the repository root for full details.
*/ */
import { import {
isLivekitFocusConfig,
type LivekitFocusConfig,
type LivekitFocus,
type LivekitFocusSelection,
type MatrixRTCSession, type MatrixRTCSession,
isLivekitTransportConfig,
type LivekitTransportConfig,
type LivekitTransport,
} from "matrix-js-sdk/lib/matrixrtc"; } from "matrix-js-sdk/lib/matrixrtc";
import { logger } from "matrix-js-sdk/lib/logger"; import { logger } from "matrix-js-sdk/lib/logger";
import { AutoDiscovery } from "matrix-js-sdk/lib/autodiscovery"; import { AutoDiscovery } from "matrix-js-sdk/lib/autodiscovery";
@@ -24,13 +23,6 @@ import { getSFUConfigWithOpenID } from "./livekit/openIDSFU.ts";
const FOCI_WK_KEY = "org.matrix.msc4143.rtc_foci"; const FOCI_WK_KEY = "org.matrix.msc4143.rtc_foci";
export function makeActiveFocus(): LivekitFocusSelection {
return {
type: "livekit",
focus_selection: "oldest_membership",
};
}
export function getLivekitAlias(rtcSession: MatrixRTCSession): string { export function getLivekitAlias(rtcSession: MatrixRTCSession): string {
// For now we assume everything is a room-scoped call // For now we assume everything is a room-scoped call
return rtcSession.room.roomId; return rtcSession.room.roomId;
@@ -38,13 +30,13 @@ export function getLivekitAlias(rtcSession: MatrixRTCSession): string {
async function makeFocusInternal( async function makeFocusInternal(
rtcSession: MatrixRTCSession, rtcSession: MatrixRTCSession,
): Promise<LivekitFocus> { ): Promise<LivekitTransport> {
logger.log("Searching for a preferred focus"); logger.log("Searching for a preferred focus");
const livekitAlias = getLivekitAlias(rtcSession); const livekitAlias = getLivekitAlias(rtcSession);
const urlFromStorage = localStorage.getItem("robin-matrixrtc-auth"); const urlFromStorage = localStorage.getItem("robin-matrixrtc-auth");
if (urlFromStorage !== null) { if (urlFromStorage !== null) {
const focusFromStorage: LivekitFocus = { const focusFromStorage: LivekitTransport = {
type: "livekit", type: "livekit",
livekit_service_url: urlFromStorage, livekit_service_url: urlFromStorage,
livekit_alias: livekitAlias, livekit_alias: livekitAlias,
@@ -57,7 +49,7 @@ async function makeFocusInternal(
const domain = rtcSession.room.client.getDomain(); const domain = rtcSession.room.client.getDomain();
if (localStorage.getItem("timo-focus-url")) { if (localStorage.getItem("timo-focus-url")) {
const timoFocusUrl = localStorage.getItem("timo-focus-url")!; const timoFocusUrl = localStorage.getItem("timo-focus-url")!;
const focusFromUrl: LivekitFocus = { const focusFromUrl: LivekitTransport = {
type: "livekit", type: "livekit",
livekit_service_url: timoFocusUrl, livekit_service_url: timoFocusUrl,
livekit_alias: livekitAlias, livekit_alias: livekitAlias,
@@ -72,8 +64,8 @@ async function makeFocusInternal(
FOCI_WK_KEY FOCI_WK_KEY
]; ];
if (Array.isArray(wellKnownFoci)) { if (Array.isArray(wellKnownFoci)) {
const focus: LivekitFocusConfig | undefined = wellKnownFoci.find( const focus: LivekitTransportConfig | undefined = wellKnownFoci.find(
(f) => f && isLivekitFocusConfig(f), (f) => f && isLivekitTransportConfig(f),
); );
if (focus !== undefined) { if (focus !== undefined) {
logger.log("Using LiveKit focus from .well-known: ", focus); logger.log("Using LiveKit focus from .well-known: ", focus);
@@ -84,7 +76,7 @@ async function makeFocusInternal(
const urlFromConf = Config.get().livekit?.livekit_service_url; const urlFromConf = Config.get().livekit?.livekit_service_url;
if (urlFromConf) { if (urlFromConf) {
const focusFromConf: LivekitFocus = { const focusFromConf: LivekitTransport = {
type: "livekit", type: "livekit",
livekit_service_url: urlFromConf, livekit_service_url: urlFromConf,
livekit_alias: livekitAlias, livekit_alias: livekitAlias,
@@ -98,7 +90,7 @@ async function makeFocusInternal(
export async function makeFocus( export async function makeFocus(
rtcSession: MatrixRTCSession, rtcSession: MatrixRTCSession,
): Promise<LivekitFocus> { ): Promise<LivekitTransport> {
const focus = await makeFocusInternal(rtcSession); const focus = await makeFocusInternal(rtcSession);
// this will call the jwt/sfu/get endpoint to pre create the livekit room. // this will call the jwt/sfu/get endpoint to pre create the livekit room.
await getSFUConfigWithOpenID( await getSFUConfigWithOpenID(
@@ -111,10 +103,11 @@ export async function makeFocus(
export async function enterRTCSession( export async function enterRTCSession(
rtcSession: MatrixRTCSession, rtcSession: MatrixRTCSession,
focus: LivekitFocus, focus: LivekitTransport,
encryptMedia: boolean, encryptMedia: boolean,
useNewMembershipManager = true, useNewMembershipManager = true,
useExperimentalToDeviceTransport = false, useExperimentalToDeviceTransport = false,
useMultiSfu = true,
): Promise<void> { ): Promise<void> {
PosthogAnalytics.instance.eventCallEnded.cacheStartCall(new Date()); PosthogAnalytics.instance.eventCallEnded.cacheStartCall(new Date());
PosthogAnalytics.instance.eventCallStarted.track(rtcSession.room.roomId); PosthogAnalytics.instance.eventCallStarted.track(rtcSession.room.roomId);
@@ -127,25 +120,31 @@ export async function enterRTCSession(
const useDeviceSessionMemberEvents = const useDeviceSessionMemberEvents =
features?.feature_use_device_session_member_events; features?.feature_use_device_session_member_events;
const { sendNotificationType: notificationType, callIntent } = getUrlParams(); const { sendNotificationType: notificationType, callIntent } = getUrlParams();
rtcSession.joinRoomSession([focus], focus, { // Multi-sfu does not need a focus preferred list. just the focus that is actually used.
notificationType, rtcSession.joinRoomSession(
callIntent, useMultiSfu ? [focus] : [],
useNewMembershipManager, useMultiSfu ? focus : undefined,
manageMediaKeys: encryptMedia, {
...(useDeviceSessionMemberEvents !== undefined && { notificationType,
useLegacyMemberEvents: !useDeviceSessionMemberEvents, callIntent,
}), useNewMembershipManager,
delayedLeaveEventRestartMs: manageMediaKeys: encryptMedia,
matrixRtcSessionConfig?.delayed_leave_event_restart_ms, ...(useDeviceSessionMemberEvents !== undefined && {
delayedLeaveEventDelayMs: useLegacyMemberEvents: !useDeviceSessionMemberEvents,
matrixRtcSessionConfig?.delayed_leave_event_delay_ms, }),
delayedLeaveEventRestartLocalTimeoutMs: delayedLeaveEventRestartMs:
matrixRtcSessionConfig?.delayed_leave_event_restart_local_timeout_ms, matrixRtcSessionConfig?.delayed_leave_event_restart_ms,
networkErrorRetryMs: matrixRtcSessionConfig?.network_error_retry_ms, delayedLeaveEventDelayMs:
makeKeyDelay: matrixRtcSessionConfig?.wait_for_key_rotation_ms, matrixRtcSessionConfig?.delayed_leave_event_delay_ms,
membershipEventExpiryMs: matrixRtcSessionConfig?.membership_event_expiry_ms, delayedLeaveEventRestartLocalTimeoutMs:
useExperimentalToDeviceTransport, matrixRtcSessionConfig?.delayed_leave_event_restart_local_timeout_ms,
}); networkErrorRetryMs: matrixRtcSessionConfig?.network_error_retry_ms,
makeKeyDelay: matrixRtcSessionConfig?.wait_for_key_rotation_ms,
membershipEventExpiryMs:
matrixRtcSessionConfig?.membership_event_expiry_ms,
useExperimentalToDeviceTransport,
},
);
if (widget) { if (widget) {
try { try {
await widget.api.transport.send(ElementWidgetActions.JoinCall, {}); await widget.api.transport.send(ElementWidgetActions.JoinCall, {});

View File

@@ -64,7 +64,7 @@ import {
import { logger } from "matrix-js-sdk/lib/logger"; import { logger } from "matrix-js-sdk/lib/logger";
import { import {
type CallMembership, type CallMembership,
isLivekitFocus, isLivekitTransport,
type MatrixRTCSession, type MatrixRTCSession,
MatrixRTCSessionEvent, MatrixRTCSessionEvent,
type MatrixRTCSessionEventHandlerMap, type MatrixRTCSessionEventHandlerMap,
@@ -493,7 +493,9 @@ export class CallViewModel extends ViewModel {
map((memberships) => map((memberships) =>
memberships.flatMap((m) => { memberships.flatMap((m) => {
const f = this.matrixRTCSession.resolveActiveFocus(m); const f = this.matrixRTCSession.resolveActiveFocus(m);
return f && isLivekitFocus(f) ? [{ membership: m, focus: f }] : []; return f && isLivekitTransport(f)
? [{ membership: m, focus: f }]
: [];
}), }),
), ),
), ),

View File

@@ -18,7 +18,7 @@ import {
} from "livekit-client"; } from "livekit-client";
import { type MatrixClient } from "matrix-js-sdk"; import { type MatrixClient } from "matrix-js-sdk";
import { import {
type LivekitFocus, type LivekitTransport,
type CallMembership, type CallMembership,
} from "matrix-js-sdk/lib/matrixrtc"; } from "matrix-js-sdk/lib/matrixrtc";
import { import {
@@ -72,12 +72,12 @@ export class Connection {
public connectionState$: Behavior<ConnectionState>; public connectionState$: Behavior<ConnectionState>;
public constructor( public constructor(
protected readonly focus: LivekitFocus, protected readonly focus: LivekitTransport,
protected readonly livekitAlias: string, protected readonly livekitAlias: string,
protected readonly client: MatrixClient, protected readonly client: MatrixClient,
protected readonly scope: ObservableScope, protected readonly scope: ObservableScope,
protected readonly membershipsFocusMap$: Behavior< protected readonly membershipsFocusMap$: Behavior<
{ membership: CallMembership; focus: LivekitFocus }[] { membership: CallMembership; focus: LivekitTransport }[]
>, >,
e2eeLivekitOptions: E2EEOptions | undefined, e2eeLivekitOptions: E2EEOptions | undefined,
livekitRoom: LivekitRoom | undefined = undefined, livekitRoom: LivekitRoom | undefined = undefined,
@@ -141,12 +141,12 @@ export class PublishConnection extends Connection {
} }
public constructor( public constructor(
focus: LivekitFocus, focus: LivekitTransport,
livekitAlias: string, livekitAlias: string,
client: MatrixClient, client: MatrixClient,
scope: ObservableScope, scope: ObservableScope,
membershipsFocusMap$: Behavior< membershipsFocusMap$: Behavior<
{ membership: CallMembership; focus: LivekitFocus }[] { membership: CallMembership; focus: LivekitTransport }[]
>, >,
devices: MediaDevices, devices: MediaDevices,
private readonly muteStates: MuteStates, private readonly muteStates: MuteStates,

View File

@@ -10299,7 +10299,7 @@ __metadata:
"matrix-js-sdk@github:matrix-org/matrix-js-sdk#head=voip-team/multi-SFU": "matrix-js-sdk@github:matrix-org/matrix-js-sdk#head=voip-team/multi-SFU":
version: 38.3.0 version: 38.3.0
resolution: "matrix-js-sdk@https://github.com/matrix-org/matrix-js-sdk.git#commit=ca4a9c655537702daf9a69ed5d94831cebc49666" resolution: "matrix-js-sdk@https://github.com/matrix-org/matrix-js-sdk.git#commit=d94d02d19b9f17c724b5919b185fea3413dbf7a2"
dependencies: dependencies:
"@babel/runtime": "npm:^7.12.5" "@babel/runtime": "npm:^7.12.5"
"@matrix-org/matrix-sdk-crypto-wasm": "npm:^15.3.0" "@matrix-org/matrix-sdk-crypto-wasm": "npm:^15.3.0"
@@ -10315,7 +10315,7 @@ __metadata:
sdp-transform: "npm:^2.14.1" sdp-transform: "npm:^2.14.1"
unhomoglyph: "npm:^1.0.6" unhomoglyph: "npm:^1.0.6"
uuid: "npm:13" uuid: "npm:13"
checksum: 10c0/1fb0933d0bb686b0f290b1a62f75eec290b7c52a410d5968c2ccfb527a64e78a58012e1bd8f90c874d385dace3228b9a8c80e114ee227fc8a60e7c9611112ceb checksum: 10c0/dc43617a9398754275e2025af7d5fdee1f2e01b89241fc7881c1206d925e83ad6fe55f439501ae34e734cfbfa5479f6bee3167f4828c913f4f33817d95850189
languageName: node languageName: node
linkType: hard linkType: hard