2025-11-04 20:24:15 +01:00
|
|
|
/*
|
2025-11-18 10:13:10 +01:00
|
|
|
Copyright 2025 Element Creations Ltd.
|
2025-11-04 20:24:15 +01:00
|
|
|
|
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
|
|
|
|
Please see LICENSE in the repository root for full details.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import {
|
|
|
|
|
type CallMembership,
|
2026-09-22 22:44:15 +02:00
|
|
|
type LivekitTransport,
|
2025-11-04 20:24:15 +01:00
|
|
|
type MatrixRTCSession,
|
|
|
|
|
MatrixRTCSessionEvent,
|
2026-09-22 22:44:15 +02:00
|
|
|
isLivekitTransport,
|
2025-11-04 20:24:15 +01:00
|
|
|
} from "matrix-js-sdk/lib/matrixrtc";
|
2025-11-06 21:54:34 +01:00
|
|
|
import { fromEvent } from "rxjs";
|
2025-11-04 20:24:15 +01:00
|
|
|
|
2025-11-06 21:54:34 +01:00
|
|
|
import {
|
2025-11-07 12:32:29 +01:00
|
|
|
Epoch,
|
2025-11-06 21:54:34 +01:00
|
|
|
mapEpoch,
|
|
|
|
|
trackEpoch,
|
|
|
|
|
type ObservableScope,
|
|
|
|
|
} from "./ObservableScope";
|
2025-11-04 20:24:15 +01:00
|
|
|
import { type Behavior } from "./Behavior";
|
|
|
|
|
|
2026-09-22 09:56:02 +02:00
|
|
|
/**
|
|
|
|
|
* Tracks the transports used by ourselves, plus all other MatrixRTC session
|
|
|
|
|
* members.
|
|
|
|
|
*/
|
2025-11-06 12:08:46 +01:00
|
|
|
export const membershipsAndTransports$ = (
|
|
|
|
|
scope: ObservableScope,
|
2025-11-06 21:54:34 +01:00
|
|
|
memberships$: Behavior<Epoch<CallMembership[]>>,
|
2025-11-06 12:08:46 +01:00
|
|
|
): {
|
2025-11-04 20:24:15 +01:00
|
|
|
membershipsWithTransport$: Behavior<
|
2026-09-22 22:44:15 +02:00
|
|
|
Epoch<{ membership: CallMembership; transport?: LivekitTransport }[]>
|
2025-11-04 20:24:15 +01:00
|
|
|
>;
|
2026-09-22 22:44:15 +02:00
|
|
|
transports$: Behavior<Epoch<LivekitTransport[]>>;
|
2025-11-05 18:57:24 +01:00
|
|
|
} => {
|
2026-01-28 14:22:21 +01:00
|
|
|
const membershipsWithTransport$: Behavior<
|
|
|
|
|
Epoch<
|
|
|
|
|
{
|
|
|
|
|
membership: CallMembership;
|
2026-09-22 22:44:15 +02:00
|
|
|
transport: LivekitTransport | undefined;
|
2026-01-28 14:22:21 +01:00
|
|
|
}[]
|
|
|
|
|
>
|
|
|
|
|
> = scope.behavior(
|
2025-11-04 20:24:15 +01:00
|
|
|
memberships$.pipe(
|
2025-11-06 21:54:34 +01:00
|
|
|
mapEpoch((memberships) => {
|
2025-11-04 20:24:15 +01:00
|
|
|
return memberships.map((membership) => {
|
2026-09-22 23:32:31 +02:00
|
|
|
const transport = membership.getTransport();
|
2025-11-04 20:24:15 +01:00
|
|
|
return {
|
|
|
|
|
membership,
|
2026-09-22 22:44:15 +02:00
|
|
|
transport: isLivekitTransport(transport) ? transport : undefined,
|
2025-11-04 20:24:15 +01:00
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
}),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
|
2026-09-22 22:44:15 +02:00
|
|
|
const transports$: Behavior<Epoch<LivekitTransport[]>> = scope.behavior(
|
2025-11-04 20:24:15 +01:00
|
|
|
membershipsWithTransport$.pipe(
|
2025-11-06 21:54:34 +01:00
|
|
|
mapEpoch((mts) => mts.flatMap(({ transport: t }) => (t ? [t] : []))),
|
2025-11-04 20:24:15 +01:00
|
|
|
),
|
|
|
|
|
);
|
2025-11-06 12:08:46 +01:00
|
|
|
|
2025-11-04 20:24:15 +01:00
|
|
|
return {
|
|
|
|
|
membershipsWithTransport$,
|
|
|
|
|
transports$,
|
|
|
|
|
};
|
|
|
|
|
};
|
2025-11-06 12:08:46 +01:00
|
|
|
|
2025-11-06 15:26:17 +01:00
|
|
|
export const createMemberships$ = (
|
|
|
|
|
scope: ObservableScope,
|
|
|
|
|
matrixRTCSession: MatrixRTCSession,
|
2025-11-06 21:54:34 +01:00
|
|
|
): Behavior<Epoch<CallMembership[]>> => {
|
2025-11-06 12:08:46 +01:00
|
|
|
return scope.behavior(
|
|
|
|
|
fromEvent(
|
|
|
|
|
matrixRTCSession,
|
|
|
|
|
MatrixRTCSessionEvent.MembershipsChanged,
|
|
|
|
|
(_, memberships: CallMembership[]) => memberships,
|
2025-11-06 21:54:34 +01:00
|
|
|
).pipe(trackEpoch()),
|
2025-11-14 10:44:16 +01:00
|
|
|
new Epoch(matrixRTCSession.memberships),
|
2025-11-06 12:08:46 +01:00
|
|
|
);
|
|
|
|
|
};
|
2026-08-15 22:32:23 +02:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Whether the session has grown large enough that MatrixRTC has stopped rotating the media
|
|
|
|
|
* encryption key. While this is true the key in use is still shared with new joiners, but no new
|
|
|
|
|
* key is generated when someone joins or leaves.
|
|
|
|
|
*/
|
|
|
|
|
export const createKeyRotationSuppressed$ = (
|
|
|
|
|
scope: ObservableScope,
|
|
|
|
|
matrixRTCSession: MatrixRTCSession,
|
|
|
|
|
): Behavior<boolean> => {
|
|
|
|
|
return scope.behavior(
|
|
|
|
|
fromEvent(
|
|
|
|
|
matrixRTCSession,
|
|
|
|
|
MatrixRTCSessionEvent.KeyRotationSuppressedChanged,
|
|
|
|
|
(suppressed: boolean) => suppressed,
|
|
|
|
|
),
|
|
|
|
|
matrixRTCSession.isKeyRotationSuppressed,
|
|
|
|
|
);
|
|
|
|
|
};
|