Stop sending livekit_alias in memberships

It's been many versions since anything used the value.
This commit is contained in:
Robin
2026-09-30 00:45:19 +02:00
parent 81233e5cfb
commit f9b601504b
19 changed files with 88 additions and 139 deletions
+2 -2
View File
@@ -43,7 +43,7 @@ import {
import { type Logger, logger as rootLogger } from "matrix-js-sdk/lib/logger";
import {
MembershipManagerEvent,
type LivekitTransportConfig,
type LivekitTransport,
type MatrixRTCSession,
type RTCCallIntent,
type RTCNotificationType,
@@ -624,7 +624,7 @@ export function createCallViewModel$(
),
muteStates,
joinMatrixRTC: (
transport: LivekitTransportConfig,
transport: LivekitTransport,
delayedLeaveTimings: ResolvedDelayedLeaveTimings,
) => {
return enterRTCSession(
@@ -8,7 +8,7 @@ Please see LICENSE in the repository root for full details.
import {
Status as RTCMemberStatus,
type LivekitTransportConfig,
type LivekitTransport,
type MatrixRTCSession,
} from "matrix-js-sdk/lib/matrixrtc";
import {
@@ -121,8 +121,7 @@ const mockedClient = {
};
describe("enterRTCSession", () => {
const transport: LivekitTransportConfig = {
livekit_alias: "roomId",
const transport: LivekitTransport = {
livekit_service_url: "http://my-livekit-service-url.com",
type: "livekit",
};
@@ -256,7 +255,7 @@ describe("LocalMembership", () => {
it("throws error on missing RTC config error", () => {
withTestScheduler(({ scope, hot, expectObservable }) => {
const localTransport$ = scope.behavior<null | LivekitTransportConfig>(
const localTransport$ = scope.behavior<null | LivekitTransport>(
hot("1ms #", {}, new MatrixRTCTransportMissingError("domain.com")),
null,
);
@@ -321,7 +320,7 @@ describe("LocalMembership", () => {
const mockTransportConfig = {
livekit_service_url: "a",
} as LivekitTransportConfig;
} as LivekitTransport;
const mockTransport = {
transport: mockTransportConfig,
@@ -19,7 +19,6 @@ import { type MatrixClient } from "matrix-js-sdk";
import {
Status as RTCSessionStatus,
type LivekitTransport,
type LivekitTransportConfig,
type MatrixRTCSession,
type RTCCallIntent,
type RTCNotificationType,
@@ -144,7 +143,7 @@ interface Props {
connectionManager: IConnectionManager;
createPublisherFactory: (connection: Connection) => Publisher;
joinMatrixRTC: (
transport: LivekitTransportConfig,
transport: LivekitTransport,
delayedLeaveTimings: ResolvedDelayedLeaveTimings,
) => void;
homeserverConnected: HomeserverConnected;
@@ -966,7 +965,7 @@ interface EnterRTCSessionOptions {
export function enterRTCSession(
rtcSession: MatrixRTCSession,
ownMembershipIdentity: CallMembershipIdentityParts,
transport: LivekitTransportConfig,
transport: LivekitTransport,
{
encryptMedia,
matrixRTCMode,
@@ -988,18 +987,6 @@ export function enterRTCSession(
} = Config.get();
const retryInterval = sessionConfig.network_error_retry_ms;
// For backwards compatibility with Element Call versions that do not do Matrix 2.0,
// we add the livekit alias to the transport.
let backwardCompatibleTransport: LivekitTransport | LivekitTransportConfig;
if (matrixRTCMode === MatrixRTCMode.Matrix_2_0) {
backwardCompatibleTransport = transport;
} else {
backwardCompatibleTransport = {
livekit_alias: rtcSession.room.roomId,
...transport,
};
}
// Set maximumNetworkErrorRetryCount such that we will consider the client
// disconnected as soon as either it fails to sync for longer than the grace
// period, or it is likely that a delayed leave event has been sent.
@@ -1011,24 +998,19 @@ export function enterRTCSession(
// Multi-sfu does not need a preferred foci list. just the focus that is actually used.
// TODO where/how do we track errors originating from the ongoing rtcSession?
rtcSession.joinRTCSession(
ownMembershipIdentity,
[],
backwardCompatibleTransport,
{
notificationType,
callIntent,
manageMediaKeys: encryptMedia,
delayedLeaveEventRestartMs: delayedLeaveTimings.restart_ms,
delayedLeaveEventDelayMs: delayedLeaveTimings.delay_ms,
delayedLeaveEventRestartLocalTimeoutMs:
delayedLeaveTimings.restart_timeout_ms,
networkErrorRetryMs: sessionConfig.network_error_retry_ms,
makeKeyDelay: sessionConfig.wait_for_key_rotation_ms,
membershipEventExpiryMs: sessionConfig.membership_event_expiry_ms,
keyRotationParticipantLimit: sessionConfig.key_rotation_participant_limit,
unstableSendStickyEvents: matrixRTCMode === MatrixRTCMode.Matrix_2_0,
maximumNetworkErrorRetryCount: maximumNetworkErrorRetryCount,
},
);
rtcSession.joinRTCSession(ownMembershipIdentity, [], transport, {
notificationType,
callIntent,
manageMediaKeys: encryptMedia,
delayedLeaveEventRestartMs: delayedLeaveTimings.restart_ms,
delayedLeaveEventDelayMs: delayedLeaveTimings.delay_ms,
delayedLeaveEventRestartLocalTimeoutMs:
delayedLeaveTimings.restart_timeout_ms,
networkErrorRetryMs: sessionConfig.network_error_retry_ms,
makeKeyDelay: sessionConfig.wait_for_key_rotation_ms,
membershipEventExpiryMs: sessionConfig.membership_event_expiry_ms,
keyRotationParticipantLimit: sessionConfig.key_rotation_participant_limit,
unstableSendStickyEvents: matrixRTCMode === MatrixRTCMode.Matrix_2_0,
maximumNetworkErrorRetryCount: maximumNetworkErrorRetryCount,
});
}
@@ -5,7 +5,7 @@ SPDX-License-IdFentifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE in the repository root for full details.
*/
import { type LivekitTransportConfig } from "matrix-js-sdk/lib/matrixrtc";
import { type LivekitTransport } from "matrix-js-sdk/lib/matrixrtc";
import { type MatrixClient } from "matrix-js-sdk";
import { logger as rootLogger, type Logger } from "matrix-js-sdk/lib/logger";
import { type CallMembershipIdentityParts } from "matrix-js-sdk/lib/matrixrtc/EncryptionManager";
@@ -34,34 +34,13 @@ interface Props {
matrixRTCMode: MatrixRTCMode;
}
// TODO livekit_alias-cleanup
// 1. We need to move away from transports map to connections!!!
//
// 2. We need to stop sending livekit_alias all together
//
//
// 1.
// Transports are just the jwt service adress but do not contain the information which room on this transport to use.
// That requires slot and roomId.
//
// We need one connection per room on the transport.
//
// We need an object that contains:
// transport
// roomId
// slotId
//
// To map to the connections. Prosposal: `ConnectionIdentifier`
//
// 2.
// We need to make sure we do not sent livekit_alias in sticky events and that we drop all code for sending state events!
export interface LocalTransport {
transport: LivekitTransportConfig;
transport: LivekitTransport;
sfuConfig: SFUConfig;
}
export function isLocalTransport(
obj: LivekitTransportConfig | LocalTransport,
obj: LivekitTransport | LocalTransport,
): obj is LocalTransport {
return "transport" in obj && "sfuConfig" in obj;
}
@@ -90,7 +69,7 @@ export async function getLocalTransport({
const customUrl = customLivekitUrl.value$.value;
// Respect the user's custom URL, if set
const transport: LivekitTransportConfig | null = customUrl
const transport: LivekitTransport | null = customUrl
? { type: "livekit", livekit_service_url: customUrl }
: await discovery.discoverPreferredTransport();
@@ -131,7 +110,7 @@ export async function getLocalTransport({
* @throws FailToGetOpenIdToken, NoMatrix2AuthorizationService
*/
async function doOpenIdAndJWTFromUrl(
transport: LivekitTransportConfig,
transport: LivekitTransport,
matrixRTCMode: MatrixRTCMode,
membership: CallMembershipIdentityParts,
roomId: string,
@@ -16,7 +16,7 @@ import {
import { MatrixError } from "matrix-js-sdk";
import { logger as rootLogger } from "matrix-js-sdk/lib/logger";
import {
type LivekitTransportConfig,
type LivekitTransport,
type Transport,
} from "matrix-js-sdk/lib/matrixrtc";
@@ -28,12 +28,12 @@ import {
type DiscoveryClient = RtcTransportAutoDiscoveryProps["client"];
const backendTransport: LivekitTransportConfig = {
const backendTransport: LivekitTransport = {
type: "livekit",
livekit_service_url: "https://backend.example.org",
};
const configTransport: LivekitTransportConfig = {
const configTransport: LivekitTransport = {
type: "livekit",
livekit_service_url: "https://config.example.org",
};
@@ -5,8 +5,8 @@ SPDX-License-IdFentifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE in the repository root for full details.
*/
import {
isLivekitTransportConfig,
type LivekitTransportConfig,
isLivekitTransport,
type LivekitTransport,
} from "matrix-js-sdk/lib/matrixrtc";
import { type MatrixClient } from "matrix-js-sdk";
import { type Logger } from "matrix-js-sdk/lib/logger";
@@ -40,7 +40,7 @@ export class RtcTransportAutoDiscovery {
this.logger = logger.getChild("[RtcTransportAutoDiscovery]");
}
public async discoverPreferredTransport(): Promise<LivekitTransportConfig | null> {
public async discoverPreferredTransport(): Promise<LivekitTransport | null> {
// 1) backend transports
const backendTransport = await this.tryBackendTransports();
if (backendTransport) {
@@ -67,7 +67,7 @@ export class RtcTransportAutoDiscovery {
* This will not throw errors, but instead just log them and return null if the expected config is not found or malformed.
* @private
*/
private async tryBackendTransports(): Promise<LivekitTransportConfig | null> {
private async tryBackendTransports(): Promise<LivekitTransport | null> {
const client = this.client;
// MSC4143: Attempt to fetch transports from backend.
this.logger.info("First try to use getRTCTransports end point ...");
@@ -75,7 +75,7 @@ export class RtcTransportAutoDiscovery {
const transportList = await doNetworkOperationWithRetry(async () =>
client._unstable_getRTCTransports(),
);
const first = transportList.find(isLivekitTransportConfig);
const first = transportList.find(isLivekitTransport);
if (first) {
return first;
} else {
@@ -90,7 +90,7 @@ export class RtcTransportAutoDiscovery {
return null;
}
private tryConfigTransport(): LivekitTransportConfig | null {
private tryConfigTransport(): LivekitTransport | null {
const url = this.resolvedConfig.livekit?.livekit_service_url;
if (url) {
return {
@@ -30,7 +30,7 @@ import fetchMock from "fetch-mock";
import EventEmitter from "events";
import { type IOpenIDToken } from "matrix-js-sdk";
import { logger, type Logger } from "matrix-js-sdk/lib/logger";
import { type LivekitTransportConfig } from "matrix-js-sdk/lib/matrixrtc";
import { type LivekitTransport } from "matrix-js-sdk/lib/matrixrtc";
import {
Connection,
@@ -57,7 +57,7 @@ let fakeLocalParticipant: MockedObject<LocalParticipant>;
const ROOM_ID = "!roomID:example.org";
const livekitFocus: LivekitTransportConfig = {
const livekitFocus: LivekitTransport = {
livekit_service_url: "https://matrix-rtc.example.org/livekit/jwt",
type: "livekit",
};
@@ -228,9 +228,7 @@ describe("Start connection states", () => {
capturedState = capturedStates.pop();
if (capturedState instanceof Error) {
expect(capturedState.message).toEqual("Something went wrong");
expect(connection.transport.livekit_alias).toEqual(
livekitFocus.livekit_alias,
);
expect(connection.transport).toEqual(livekitFocus);
} else {
expect.fail("Expected FailedToStart state but got " + capturedState);
}
@@ -290,9 +288,7 @@ describe("Start connection states", () => {
expect(capturedState.cause.message).toContain(
"Failed to look up user info from homeserver",
);
expect(connection.transport.livekit_alias).toEqual(
livekitFocus.livekit_alias,
);
expect(connection.transport).toEqual(livekitFocus);
} else {
expect.fail("Expected FailedToStart state but got " + capturedState);
}
@@ -357,9 +353,7 @@ describe("Start connection states", () => {
expect(capturedState.cause.message).toContain(
"Failed to connect to livekit",
);
expect(connection.transport.livekit_alias).toEqual(
livekitFocus.livekit_alias,
);
expect(connection.transport).toEqual(livekitFocus);
} else {
expect.fail(
"Expected FailedToStart state but got " + JSON.stringify(capturedState),
@@ -22,7 +22,7 @@ import {
type Track,
type TrackPublication,
} from "livekit-client";
import { type LivekitTransportConfig } from "matrix-js-sdk/lib/matrixrtc";
import { type LivekitTransport } from "matrix-js-sdk/lib/matrixrtc";
import { BehaviorSubject, map } from "rxjs";
import { type Logger } from "matrix-js-sdk/lib/logger";
import { type CallMembershipIdentityParts } from "matrix-js-sdk/lib/matrixrtc/EncryptionManager";
@@ -52,7 +52,7 @@ export interface ConnectionOpts {
/** The identity parts to use on this connection */
ownMembershipIdentity: CallMembershipIdentityParts;
/** The media transport to connect to. */
transport: LivekitTransportConfig;
transport: LivekitTransport;
/** The Matrix client to use for OpenID and SFU config requests. */
client: OpenIDClientParts;
/** The room ID this connection is associated with. */
@@ -107,7 +107,7 @@ export class Connection {
/**
* The media transport to connect to.
*/
public readonly transport: LivekitTransportConfig;
public readonly transport: LivekitTransport;
public readonly livekitRoom: LivekitRoom;
@@ -16,7 +16,7 @@ import { logger, type Logger } from "matrix-js-sdk/lib/logger";
// imported as inline to support worker when loaded from a cdn (cross domain)
import E2EEWorker from "livekit-client/e2ee-worker?worker&inline";
import { type CallMembershipIdentityParts } from "matrix-js-sdk/lib/matrixrtc/EncryptionManager";
import { type LivekitTransportConfig } from "matrix-js-sdk/lib/matrixrtc";
import { type LivekitTransport } from "matrix-js-sdk/lib/matrixrtc";
import { type ObservableScope } from "../../ObservableScope.ts";
import { Connection } from "./Connection.ts";
@@ -44,7 +44,7 @@ import {
export interface ConnectionFactory {
createConnection(
scope: ObservableScope,
transport: LivekitTransportConfig,
transport: LivekitTransport,
ownMembershipIdentity: CallMembershipIdentityParts,
logger: Logger,
sfuConfig?: SFUConfig,
@@ -103,7 +103,7 @@ export class ECConnectionFactory implements ConnectionFactory {
*/
public createConnection(
scope: ObservableScope,
transport: LivekitTransportConfig,
transport: LivekitTransport,
ownMembershipIdentity: CallMembershipIdentityParts,
logger: Logger,
sfuConfig?: SFUConfig,
@@ -7,7 +7,7 @@ Please see LICENSE in the repository root for full details.
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
import { BehaviorSubject, NEVER } from "rxjs";
import { type LivekitTransportConfig } from "matrix-js-sdk/lib/matrixrtc";
import { type LivekitTransport } from "matrix-js-sdk/lib/matrixrtc";
import { type RemoteParticipant } from "livekit-client";
import { logger } from "matrix-js-sdk/lib/logger";
@@ -24,12 +24,12 @@ import { type Behavior } from "../../Behavior.ts";
// Some test constants
const TRANSPORT_1: LivekitTransportConfig = {
const TRANSPORT_1: LivekitTransport = {
type: "livekit",
livekit_service_url: "https://lk.example.org",
};
const TRANSPORT_2: LivekitTransportConfig = {
const TRANSPORT_2: LivekitTransport = {
type: "livekit",
livekit_service_url: "https://lk.sample.com",
};
@@ -47,7 +47,7 @@ beforeEach(() => {
vi.mocked(fakeConnectionFactory).createConnection = vi
.fn()
.mockImplementation(
(scope: ObservableScope, transport: LivekitTransportConfig) => {
(scope: ObservableScope, transport: LivekitTransport) => {
const mockConnection = {
transport,
remoteParticipants$: new BehaviorSubject([]),
@@ -225,7 +225,7 @@ describe("connectionManagerData$ stream", () => {
// Used in test to control fake connections' remoteParticipants$ streams
let fakeRemoteParticipantsStreams: Map<string, Behavior<RemoteParticipant[]>>;
function keyForTransport(transport: LivekitTransportConfig): string {
function keyForTransport(transport: LivekitTransport): string {
return `${transport.livekit_service_url}`;
}
@@ -233,7 +233,7 @@ describe("connectionManagerData$ stream", () => {
fakeRemoteParticipantsStreams = new Map();
function getRemoteParticipantsFor(
transport: LivekitTransportConfig,
transport: LivekitTransport,
): Behavior<RemoteParticipant[]> {
return (
fakeRemoteParticipantsStreams.get(keyForTransport(transport)) ??
@@ -245,7 +245,7 @@ describe("connectionManagerData$ stream", () => {
vi.mocked(fakeConnectionFactory).createConnection = vi
.fn()
.mockImplementation(
(scope: ObservableScope, transport: LivekitTransportConfig) => {
(scope: ObservableScope, transport: LivekitTransport) => {
const fakeRemoteParticipants$ = new BehaviorSubject<
RemoteParticipant[]
>([]);
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE in the repository root for full details.
*/
import { type LivekitTransportConfig } from "matrix-js-sdk/lib/matrixrtc";
import { type LivekitTransport } from "matrix-js-sdk/lib/matrixrtc";
import {
combineLatest,
map,
@@ -56,7 +56,7 @@ export class ConnectionManagerData {
}
}
private getKey(transport: LivekitTransportConfig): string {
private getKey(transport: LivekitTransport): string {
// This is enough as a key because the ConnectionManager is already scoped by room.
// We also do not need to consider the slotId at this point since each `MatrixRTCSession` is already scoped by `slotDescription: {id, application}`.
return transport.livekit_service_url;
@@ -67,13 +67,13 @@ export class ConnectionManagerData {
}
public getConnectionForTransport(
transport: LivekitTransportConfig,
transport: LivekitTransport,
): Connection | null {
return this.store.get(this.getKey(transport))?.connection ?? null;
}
public getParticipantsForTransport(
transport: LivekitTransportConfig,
transport: LivekitTransport,
): RemoteParticipant[] {
const key = this.getKey(transport);
const existing = this.store.get(key);
@@ -88,7 +88,7 @@ interface Props {
scope: ObservableScope;
connectionFactory: ConnectionFactory;
localTransport$: Observable<LocalTransport>;
remoteTransports$: Behavior<Epoch<LivekitTransportConfig[]>>;
remoteTransports$: Behavior<Epoch<LivekitTransport[]>>;
logger: Logger;
ownMembershipIdentity: CallMembershipIdentityParts;
@@ -147,7 +147,7 @@ export function createConnectionManager$({
* externally this is modified via `registerTransports()`.
*/
const localAndRemoteTransports$: Behavior<
Epoch<(LivekitTransportConfig | LocalTransport)[]>
Epoch<(LivekitTransport | LocalTransport)[]>
> = scope.behavior(
combineLatest([localTransportAsArray$, remoteTransports$]).pipe(
// Combine local and remote transports into one transport array
@@ -271,7 +271,7 @@ export function createConnectionManager$({
return { connectionManagerData$ };
}
function removeDuplicateTransports<T extends LivekitTransportConfig>(
function removeDuplicateTransports<T extends LivekitTransport>(
transports: T[],
): T[] {
return transports.reduce((acc, transport) => {
@@ -42,13 +42,11 @@ const fallbackMemberId = (userId: string, deviceId: string): string =>
const transportA: LivekitTransport = {
type: "livekit",
livekit_service_url: "https://lk.example.org",
livekit_alias: "!alias:example.org",
};
const transportB: LivekitTransport = {
type: "livekit",
livekit_service_url: "https://lk.sample.com",
livekit_alias: "!alias:sample.com",
};
const bobMembership = mockRtcMembership("@bob:example.org", "DEV000", {
@@ -8,7 +8,7 @@ Please see LICENSE in the repository root for full details.
import { type LocalParticipant, type RemoteParticipant } from "livekit-client";
import {
type CallMembership,
type LivekitTransportConfig,
type LivekitTransport,
} from "matrix-js-sdk/lib/matrixrtc";
import { combineLatest, filter, map } from "rxjs";
import { logger } from "matrix-js-sdk/lib/logger";
@@ -60,7 +60,7 @@ export interface RemoteMatrixLivekitMember extends MatrixLivekitMember {
interface Props {
scope: ObservableScope;
membershipsWithTransport$: Behavior<
Epoch<{ membership: CallMembership; transport?: LivekitTransportConfig }[]>
Epoch<{ membership: CallMembership; transport?: LivekitTransport }[]>
>;
connectionManager: IConnectionManager;
localUser: { deviceId: string; userId: string };
@@ -165,7 +165,7 @@ export function createRemoteMatrixLivekitMembers$({
// TODO add back in the callviewmodel pauseWhen(this.pretendToBeDisconnected$)
// TODO add this to the JS-SDK
export function areLivekitTransportsEqual<T extends LivekitTransportConfig>(
export function areLivekitTransportsEqual<T extends LivekitTransport>(
t1: T | null,
t2: T | null,
): boolean {
@@ -10,7 +10,7 @@ import { BehaviorSubject, NEVER } from "rxjs";
import { type Room as LivekitRoom } from "livekit-client";
import EventEmitter from "events";
import fetchMock from "fetch-mock";
import { type LivekitTransportConfig } from "matrix-js-sdk/lib/matrixrtc";
import { type LivekitTransport } from "matrix-js-sdk/lib/matrixrtc";
import { logger } from "matrix-js-sdk/lib/logger";
import {
@@ -149,7 +149,7 @@ test("bob, carl, then bob joining no tracks yet", () => {
a: expect.toSatisfy((co) =>
areLivekitTransportsEqual(
co.transport,
bobMembership.transports[0]! as LivekitTransportConfig,
bobMembership.transports[0]! as LivekitTransport,
),
),
});
@@ -186,7 +186,7 @@ test("bob, carl, then bob joining no tracks yet", () => {
expect(
areLivekitTransportsEqual(
connection.transport,
carlMembership.transports[0]! as LivekitTransportConfig,
carlMembership.transports[0]! as LivekitTransport,
),
).toBe(true);
return true;
@@ -216,7 +216,7 @@ test("bob, carl, then bob joining no tracks yet", () => {
expect(
areLivekitTransportsEqual(
connection.transport,
daveMembership.transports[0]! as LivekitTransportConfig,
daveMembership.transports[0]! as LivekitTransport,
),
).toBe(true);
return true;
+7 -9
View File
@@ -7,10 +7,10 @@ Please see LICENSE in the repository root for full details.
import {
type CallMembership,
type LivekitTransportConfig,
type LivekitTransport,
type MatrixRTCSession,
MatrixRTCSessionEvent,
isLivekitTransportConfig,
isLivekitTransport,
} from "matrix-js-sdk/lib/matrixrtc";
import { fromEvent } from "rxjs";
@@ -31,15 +31,15 @@ export const membershipsAndTransports$ = (
memberships$: Behavior<Epoch<CallMembership[]>>,
): {
membershipsWithTransport$: Behavior<
Epoch<{ membership: CallMembership; transport?: LivekitTransportConfig }[]>
Epoch<{ membership: CallMembership; transport?: LivekitTransport }[]>
>;
transports$: Behavior<Epoch<LivekitTransportConfig[]>>;
transports$: Behavior<Epoch<LivekitTransport[]>>;
} => {
const membershipsWithTransport$: Behavior<
Epoch<
{
membership: CallMembership;
transport: LivekitTransportConfig | undefined;
transport: LivekitTransport | undefined;
}[]
>
> = scope.behavior(
@@ -50,16 +50,14 @@ export const membershipsAndTransports$ = (
const transport = membership.getTransport(oldestMembership);
return {
membership,
transport: isLivekitTransportConfig(transport)
? transport
: undefined,
transport: isLivekitTransport(transport) ? transport : undefined,
};
});
}),
),
);
const transports$: Behavior<Epoch<LivekitTransportConfig[]>> = scope.behavior(
const transports$: Behavior<Epoch<LivekitTransport[]>> = scope.behavior(
membershipsWithTransport$.pipe(
mapEpoch((mts) => mts.flatMap(({ transport: t }) => (t ? [t] : []))),
),
-1
View File
@@ -212,7 +212,6 @@ export function mockEmitter<T>(): EmitterMock<T> {
export const exampleTransport: LivekitTransport = {
type: "livekit",
livekit_service_url: "https://lk.example.org",
livekit_alias: "!alias:example.org",
};
export const exampleSfuConfig: SFUConfig = {