From 8506c098e9e7ff1930eb023c8ba48bfdf7a31621 Mon Sep 17 00:00:00 2001 From: "Timo K." Date: Wed, 16 Sep 2026 13:30:05 +0200 Subject: [PATCH] Add rust based createCallViewModel --- component/dev/Harness.tsx | 4 +- component/index.tsx | 122 +- element-call-oxidation-plan.md | 171 +- sdk/main.ts | 10 +- src/driver/MockRtcMatrixDriver.test.ts | 12 +- src/driver/MockRtcMatrixDriver.ts | 45 +- .../JsSdkElementCallMatrixClientDriver.ts | 9 +- src/driver/jsSdk/JsSdkRtcMatrixDriver.test.ts | 70 +- src/driver/jsSdk/JsSdkRtcMatrixDriver.ts | 76 +- src/driver/jsSdk/jsSdkTestFakes.ts | 1 + src/e2ee/participationKeyProvider.test.ts | 75 + src/e2ee/participationKeyProvider.ts | 92 ++ src/matrix-rtc-sdk/generated/VERSION | 4 +- .../generated/matrix_rtc-ffi.ts | 50 +- src/matrix-rtc-sdk/generated/matrix_rtc.ts | 575 ++++++- .../generated/wasm-bindgen/index.js | 1381 +++++++++-------- .../generated/wasm-bindgen/index_bg.wasm | Bin 1553078 -> 1597456 bytes src/matrix-rtc-sdk/index.test.ts | 9 +- src/matrix-rtc-sdk/index.ts | 5 + src/room/InCallView.tsx | 4 +- .../CallNotificationLifecycle.test.ts | 92 +- .../CallNotificationLifecycle.ts | 41 +- .../CallViewModel.participation.test.ts | 224 +++ src/state/CallViewModel/CallViewModel.ts | 357 ++++- .../CallViewModel/CallViewModelTestUtils.ts | 4 +- .../ParticipationCallNotification.test.ts | 142 ++ .../ParticipationCallNotification.ts | 147 ++ .../CallViewModel/localMember/LocalMedia.ts | 565 +++++++ .../CallViewModel/localMember/LocalMember.ts | 489 +----- .../localMember/ParticipationLocalMember.ts | 431 +++++ .../CallViewModel/remoteMembers/Connection.ts | 14 +- .../remoteMembers/ConnectionFactory.ts | 4 +- .../remoteMembers/MatrixLivekitMembers.ts | 20 +- .../remoteMembers/MatrixMemberMetadata.ts | 5 + .../ParticipationConnections.test.ts | 123 ++ .../remoteMembers/ParticipationConnections.ts | 124 ++ .../ParticipationMemberMetadata.ts | 47 + .../ParticipationMembers.test.ts | 121 ++ .../remoteMembers/ParticipationMembers.ts | 132 ++ .../rtc/CallParticipation.backend.test.ts | 517 ++++++ src/state/rtc/CallParticipation.test.ts | 63 +- src/state/rtc/CallParticipation.ts | 61 +- src/state/rtc/joinParams.ts | 24 +- src/state/rtc/slot.ts | 16 + src/utils/test-participation.ts | 110 ++ src/utils/test-viewmodel.ts | 4 +- vitest.config.ts | 1 + 47 files changed, 5165 insertions(+), 1428 deletions(-) create mode 100644 src/e2ee/participationKeyProvider.test.ts create mode 100644 src/e2ee/participationKeyProvider.ts create mode 100644 src/state/CallViewModel/CallViewModel.participation.test.ts create mode 100644 src/state/CallViewModel/ParticipationCallNotification.test.ts create mode 100644 src/state/CallViewModel/ParticipationCallNotification.ts create mode 100644 src/state/CallViewModel/localMember/LocalMedia.ts create mode 100644 src/state/CallViewModel/localMember/ParticipationLocalMember.ts create mode 100644 src/state/CallViewModel/remoteMembers/ParticipationConnections.test.ts create mode 100644 src/state/CallViewModel/remoteMembers/ParticipationConnections.ts create mode 100644 src/state/CallViewModel/remoteMembers/ParticipationMemberMetadata.ts create mode 100644 src/state/CallViewModel/remoteMembers/ParticipationMembers.test.ts create mode 100644 src/state/CallViewModel/remoteMembers/ParticipationMembers.ts create mode 100644 src/state/rtc/CallParticipation.backend.test.ts create mode 100644 src/utils/test-participation.ts diff --git a/component/dev/Harness.tsx b/component/dev/Harness.tsx index ded9155a9..1a3eaf159 100644 --- a/component/dev/Harness.tsx +++ b/component/dev/Harness.tsx @@ -18,7 +18,7 @@ import { type MatrixClient } from "matrix-js-sdk"; import { logger } from "matrix-js-sdk/lib/logger"; import { - ElementCall, + ElementCallClientBased, type ElementCallHandle, supportedLanguages, } from "../index"; @@ -160,7 +160,7 @@ const Pane: FC<{ one of the things we cannot find out from the standalone app */}
{mounted && ( - & export interface ElementCallProps { /** - * The client to place the call with. Element Call does not authenticate - * anyone or manage a session of its own; this one is the host's. + * The MatrixRTC side of the host's Matrix stack, bound to the room to call + * in: what the crate needs to publish a membership, exchange keys and mint + * transport tokens. Element Call does not authenticate anyone or manage a + * session of its own; both drivers are the host's. */ - client: MatrixClient; - /** The room to call in. The host's client must already know about it. */ - roomId: string; + rtcDriver: RtcMatrixDriver; + /** + * Everything else Element Call asks of a Matrix client for that room: who + * is in it, its name and avatar, the timeline for reactions and + * notifications, the user's own profile. + */ + clientDriver: ElementCallMatrixClientDriver; + /** + * The room to call in. Optional, and when given it must be the room the + * drivers are bound to (`clientDriver.roomId`). Kept for one release so + * that hosts written for the client-based component can move over one + * prop at a time; then it goes. + */ + roomId?: string; /** * What the user asked for — whether they started the call or joined one that * was already running, and whether it is a call in a group or a DM. Element @@ -176,6 +207,24 @@ export interface ElementCallProps { language?: string; } +/** + * {@link ElementCall} for a host with a matrix-js-sdk client: the two drivers + * are built here from the client and the room, so the host hands over the + * client as it always has. + */ +export type ElementCallClientBasedProps = Omit< + ElementCallProps, + "rtcDriver" | "clientDriver" | "roomId" +> & { + /** + * The client to place the call with. Element Call does not authenticate + * anyone or manage a session of its own; this one is the host's. + */ + client: MatrixClient; + /** The room to call in. The host's client must already know about it. */ + roomId: string; +}; + /** * Prepares the things Element Call needs before it can be shown: translations, * `Intl` polyfills for older browsers, and its configuration. @@ -230,8 +279,9 @@ const Decoration: FC<{ children: JSX.Element }> = ({ children }) => { }; export const ElementCall: FC = ({ - client, - roomId, + rtcDriver, + clientDriver, + roomId: suppliedRoomId, intent = UserIntent.JoinExistingCall, config, hostBridge: suppliedHostBridge, @@ -240,6 +290,11 @@ export const ElementCall: FC = ({ language, }): ReactNode => { const hostBridge = useComponentHostBridge(suppliedHostBridge, ref, theme); + const roomId = clientDriver.roomId; + if (suppliedRoomId !== undefined && suppliedRoomId !== roomId) + throw new Error( + `Element Call was asked to call in ${suppliedRoomId} with drivers bound to ${roomId}`, + ); useEffect(() => { if (language !== undefined) @@ -288,17 +343,24 @@ export const ElementCall: FC = ({ }; }, [controlledAudioDevices, callIntent]); - const room = client.getRoom(roomId); + // Until the React tree below reads the drivers (plan slice S4), it runs on + // matrix-js-sdk directly, so for now the drivers have to be the matrix-js-sdk + // ones and the client is taken back out of them. `ElementCallClientBased` + // is the way to get here in the meantime; a host with drivers of its own + // cannot be served yet. + if (!(clientDriver instanceof JsSdkElementCallMatrixClientDriver)) + throw new Error( + "Element Call cannot yet run on drivers other than the matrix-js-sdk ones; use ElementCallClientBased", + ); + // `rtcDriver` is what the call will run on once the tree reads it; for now + // it is only checked to be there. + void rtcDriver; + const { client, room } = clientDriver; const rtcSession = useMemo( - () => (room === null ? null : client.matrixRTC.getRoomSession(room)), + () => client.matrixRTC.getRoomSession(room), [client, room], ); - if (rtcSession === null) - logger.error( - `Element Call was asked to call in ${roomId}, which its host's client does not know about`, - ); - // Everything the call needs is in hand once these exist, and the first // render with them is where the call itself appears: the moment the host // is told that Element Call has loaded, as the widget tells its client once @@ -356,3 +418,35 @@ export const ElementCall: FC = ({ ); }; + +export const ElementCallClientBased: FC = ({ + client, + roomId, + ...props +}): ReactNode => { + const room = client.getRoom(roomId); + const drivers = useMemo( + () => + room === null + ? null + : { + rtcDriver: new JsSdkRtcMatrixDriver(client, room), + clientDriver: new JsSdkElementCallMatrixClientDriver(client, room), + }, + [client, room], + ); + // The RTC driver hooks client listeners for the crate's sinks; let go of + // them with the drivers. + useEffect(() => { + if (drivers === null) return; + return (): void => drivers.rtcDriver.detach(); + }, [drivers]); + + if (drivers === null) { + logger.error( + `Element Call was asked to call in ${roomId}, which its host's client does not know about`, + ); + return null; + } + return ; +}; diff --git a/element-call-oxidation-plan.md b/element-call-oxidation-plan.md index e60ab4c74..a1d51ac2c 100644 --- a/element-call-oxidation-plan.md +++ b/element-call-oxidation-plan.md @@ -16,8 +16,10 @@ Status legend: ☐ todo · ◐ in progress · ☑ done. **Where things stand (2026-09-14):** S0a, S0b, S1a, S1b and S2 are implemented and green (`pnpm lint`, `pnpm format:check`, `pnpm test:unit`: 101 files / 785 tests). Nothing is committed yet, in either repository: the -crate changes (C2–C8; C1 was reverted in favour of slot opening; C11 and C12 done; -C9 and C10 are pending) sit uncommitted in +crate changes C2–C12 (C1 reverted in favour of slot opening) are done; C2–C8, +C11 and C12 are committed in the draft repo as `a8e21b3`, C5 (final form), C9 +and C10 are still uncommitted there. In Element Call everything sits +uncommitted in `~/Projects/matrix-rust-rtc/MatrixSdkArchitectureDraft`, and Element Call's branch `toger5/oxidation` holds the vendored bindings, the driver layer (`src/driver/**`), the participation layer (`src/state/rtc/**`) and the @@ -136,8 +138,9 @@ membership, roster, encryption, impairments} | Leaving`. is closed, so a room without an `m.rtc.slot` has no call, in every dialect. `openSlot(application, encrypted)` / `closeSlot()` send the state event; the slot id `m.call#ROOM` matches js-sdk's default. -- `FfiElementCallCompat.{Off, StickyEvents, StateEvents}` today; `StickyEvents` - is removed by C9, leaving `Off` (spec MSC4143) and `StateEvents` (MSC3401). +- `FfiElementCallCompat.{Off, StateEvents}`: spec MSC4143, or MSC3401 state + events for the clients that predate sticky events (C9 removed the never + deployed 2025 sticky dialect). - All `u64` fields are `bigint` in TypeScript; `Vec` is `ArrayBuffer`. - Listener callbacks arrive one timer tick after the emitting call (pumps sleep through `setTimeout`, `executor.rs:86`); getters are fresh. @@ -157,20 +160,21 @@ membership, roster, encryption, impairments} | Leaving`. **Must change in the crate (S0a) — each blocks a later slice:** -| # | Problem | Change | -| --- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| C1 | A successful `read_state("m.rtc.slot")` returning `[]` marks slot state supplied and every slot other than the legacy `""` resolves `Closed` (`session/state.rs`); `join()` then fails with `SlotClosed` and every MSC4143 peer is excluded. Element Call never sent `m.rtc.slot`. | **Kept as the crate has it: no slot means no call.** Element Call opens the slot when nobody has (`CallParticipation.join` with a `SlotPolicy`: `openSlot("m.call", encrypted)`, then wait for the echo), which needs the power level to send `org.matrix.msc4143.rtc.slot`; without it the join fails with `NoOpenSlotError`. Existing rooms keep working because the first call in a room opens its slot. A compat-mode relaxation was tried and reverted. | -| C2 | `manage_media_keys`, `require_cross_signed_sender`, `use_key_delay_ms` are not settable over the FFI; defaults are `true`, `true`, 1000 ms. | New record `FfiParticipationConfig { compat, manage_media_keys, require_cross_signed_sender, use_key_delay_ms }` as the constructor argument (replaces the bare `compat`). | -| C3 | `StickyEvents` compat sent keys as `org.matrix.msc4143.rtc.encryption_key` while deployed clients read only `io.element.call.encryption_keys`. | Made moot by C9 and reverted with it: the sticky dialect goes away entirely, so `Off` sends the spec key message and `StateEvents` the legacy one, with no middle case. | -| C4 | `FfiMember` has no membership `event_id`; reactions relate to it (§4.3). | `Member.event_id: Option` threaded through `session/dispatch.rs` → `convert/*` → `state.rs` (currently dropped at `state.rs:402`) → `FfiMember.event_id`. | -| C5 | Delegating the delayed leave (MSC4195) is split between the crate and the host: the draft's driver method makes the _adapter_ perform the whole delegation, its demo adapter calls a homeserver endpoint that 401s on a widget client, and Element Call today does it differently (probe, then the authorisation service's `get_token` with `delay_id`/`delay_timeout`/`delay_cs_api_url`). Nothing of this exists in the real `crates/` yet. | **The crate owns the policy; the driver keeps two primitives.** (a) `delegate_delayed_leave_via_homeserver(room, slot, member, delay_id)`: one authenticated POST to the CS API endpoint (`/_matrix/client/unstable/io.element.msc4195/rtc/livekit/delegate_delayed_leave`, the spelling Element Call probes today; a widget client answers `Unsupported`). (b) `LivekitTokenRequest.delegation: Option<{ delay_id, delay_timeout_ms }>`: the adapter appends `delay_id`, `delay_timeout` and `delay_cs_api_url` (its own homeserver URL) to the `get_token` / `sfu/get` body it already sends. The own-membership machine tries (a) first and, on `Unsupported` or any failure, (b) against the transport we publish on, i.e. Element Call's OpenID → JWT → scheduled-event path; only if both fail does it keep restarting the switch itself. **Arm-after-confirm:** the short delayed leave stays armed through the join; delegation arms a second, ≥ 1 h delayed leave, delegates _that_, and cancels the short one on success (or the long one on failure), so no moment is left without an armed leave and a failed delegation costs nothing. `KeepAlive::Delegated` says which route succeeded. The interim C5 (service URL and delay on the request) and Element Call's driver-side probe and JWT delegation are replaced by this. | -| C6 | The transport identity is a pure function (`connections/mod.rs:116-135`) but not exported; the own identity is needed before our membership echo to set our own media key. | Export `FfiParticipationManager.own_transport_identity(): Option`. | -| C7 | Doc comment on `FfiMembership.connections` says `ws_url`s. | Fix the comment. | -| C8 | Both converters set `display_name` / `avatar_url` to `None`, so every host would re-derive them from room members. | The session records each `m.room.member` profile (whether or not the roster condition is enforced) and stamps it on members at projection time. | -| C9 | `ElementCallCompat::StickyEvents` models the 2025 Element Call sticky dialect (`member: {user_id, device_id, id}`, flat `rtc_transports`, `versions`, legacy key message). No deployment uses it: sticky-event calls have not shipped. | **Remove the mode.** Delete `own_membership/compat_2025.rs`, the 2025 block in `session/convert/msc4143.rs` and its dispatch arm, the `StickyEvents` variants of `ElementCallCompat` / `FfiElementCallCompat`, and their tests and acceptance tests; `outbound_event_type` / `build_content` keep two arms (`Off`, `StateEvents`). Element Call then maps `Matrix_2_0 → Off`: spec MSC4143 sticky events with slots (which Element Call opens, C1) and the spec key message. | -| C10 | `MediaKeyState` has `holds_our_key`, `have_their_key` and `rejection`, so a tile learns about an unsigned sender only when `require_cross_signed_sender` is on (the key is discarded, `rejection: NotCrossSigned`). With the check off the verdict is dropped on accept and the tile cannot show an unverified sender. | Keep the MSC4153 verdict of the accepted key per member and expose it as `FfiMediaKeyState.sender_cross_signed: Option` (`None` when the host could not tell). Element Call runs with the check off (§5.8) and wants to show the state on the tile until it is turned on. | -| C11 | No way to change `application["m.call.intent"]` while joined; Element Call flips it between `audio` and `video` when the camera is toggled (`updateCallIntent`). | `update_application(intent)` on the own-membership manager, facade and FFI: while connected the membership is re-published at once on the refresh path (a failure retries like a refresh); during a join the join event carries it; refused with `NotJoined` otherwise. | -| C12 | Homeserver connectivity lived only in Element Call's driver; the crate could not tell a dead homeserver from a quiet one, and a participation's status said nothing about it. | **Done.** `ConnectivityDriver` (`is_homeserver_connected`, `subscribe_connectivity`) joins the `MatrixDriver` sum; the FFI adds `ConnectivitySink`, the two callback methods and `FfiParticipationManager.is_homeserver_connected()`; the facade pump consumes the stream and reports `Impairment::HomeserverUnreachable { since_ts }` (Critical, sorted first) in every non-disconnected status until the driver reports the homeserver back. The web-test-app mock and js-sdk driver implement it. A matrix-rust-sdk adapter implements the same two methods later. | +| # | Problem | Change | +| --- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| C1 | A successful `read_state("m.rtc.slot")` returning `[]` marks slot state supplied and every slot other than the legacy `""` resolves `Closed` (`session/state.rs`); `join()` then fails with `SlotClosed` and every MSC4143 peer is excluded. Element Call never sent `m.rtc.slot`. | **Kept as the crate has it: no slot means no call.** Element Call opens the slot when nobody has (`CallParticipation.join` with a `SlotPolicy`: `openSlot("m.call", encrypted)`, then wait for the echo), which needs the power level to send `org.matrix.msc4143.rtc.slot`; without it the join fails with `NoOpenSlotError`. Existing rooms keep working because the first call in a room opens its slot. A compat-mode relaxation was tried and reverted. | +| C2 | `manage_media_keys`, `require_cross_signed_sender`, `use_key_delay_ms` are not settable over the FFI; defaults are `true`, `true`, 1000 ms. | New record `FfiParticipationConfig { compat, manage_media_keys, require_cross_signed_sender, use_key_delay_ms }` as the constructor argument (replaces the bare `compat`). | +| C3 | `StickyEvents` compat sent keys as `org.matrix.msc4143.rtc.encryption_key` while deployed clients read only `io.element.call.encryption_keys`. | Made moot by C9 and reverted with it: the sticky dialect goes away entirely, so `Off` sends the spec key message and `StateEvents` the legacy one, with no middle case. | +| C4 | `FfiMember` has no membership `event_id`; reactions relate to it (§4.3). | `Member.event_id: Option` threaded through `session/dispatch.rs` → `convert/*` → `state.rs` (currently dropped at `state.rs:402`) → `FfiMember.event_id`. | +| C5 | **Done.** Delegating the delayed leave (MSC4195) is split between the crate and the host: the draft's driver method makes the _adapter_ perform the whole delegation, its demo adapter calls a homeserver endpoint that 401s on a widget client, and Element Call today does it differently (probe, then the authorisation service's `get_token` with `delay_id`/`delay_timeout`/`delay_cs_api_url`). Nothing of this exists in the real `crates/` yet. | **The crate owns the policy; the driver keeps two primitives.** (a) `delegate_delayed_leave_via_homeserver(room, slot, member, delay_id)`: one authenticated POST to the CS API endpoint (`/_matrix/client/unstable/io.element.msc4195/rtc/livekit/delegate_delayed_leave`, the spelling Element Call probes today; a widget client answers `Unsupported`). (b) `LivekitTokenRequest.delegation: Option<{ delay_id, delay_timeout_ms }>`: the adapter appends `delay_id`, `delay_timeout` and `delay_cs_api_url` (its own homeserver URL) to the `get_token` / `sfu/get` body it already sends. The own-membership machine tries (a) first and, on `Unsupported` or any failure, (b) against the transport we publish on, i.e. Element Call's OpenID → JWT → scheduled-event path; only if both fail does it keep restarting the switch itself. **Arm-after-confirm:** the short delayed leave stays armed through the join; delegation arms a second, ≥ 1 h delayed leave, delegates _that_, and cancels the short one on success (or the long one on failure), so no moment is left without an armed leave and a failed delegation costs nothing. `KeepAlive::Delegated` says which route succeeded. The interim C5 (service URL and delay on the request) and Element Call's driver-side probe and JWT delegation are replaced by this. **Real-backend check (2026-09-15):** both routes send the MSC4195 `member` _claims_ (`{ id, claimed_user_id, claimed_device_id }`), not the member block of the event. The homeserver route body is what lk-jwt-service 0.7 accepts behind a Synapse that proxies `rtc/livekit/*` to it (MSC4512, `backend/app-service.yaml`): `{ url, room_id, slot_id, member, delay_id, delay_timeout }`, where `url` is the SFU websocket URL the transport's token named (the service checks it is its own). The transport resolver therefore returns `ResolvedTransport { transport, sfu_url }` and the machine carries the url into `Action::DelegateViaHomeserver`; without an SFU url it goes straight to the service route, and a receive-only member (no transport) delegates nothing. Verified end to end against `pnpm backend`: the homeserver route takes the 1 h leave (`KeepAlive::Delegated { via: Homeserver }`, one delayed event of 3 600 000 ms on the server). | +| C6 | The transport identity is a pure function (`connections/mod.rs:116-135`) but not exported; the own identity is needed before our membership echo to set our own media key. | Export `FfiParticipationManager.own_transport_identity(): Option`. | +| C7 | Doc comment on `FfiMembership.connections` says `ws_url`s. | Fix the comment. | +| C8 | Both converters set `display_name` / `avatar_url` to `None`, so every host would re-derive them from room members. | The session records each `m.room.member` profile (whether or not the roster condition is enforced) and stamps it on members at projection time. | +| C9 | `ElementCallCompat::StickyEvents` models the 2025 Element Call sticky dialect (`member: {user_id, device_id, id}`, flat `rtc_transports`, `versions`, legacy key message). No deployment uses it: sticky-event calls have not shipped. | **Done.** Removed: `own_membership/compat_2025.rs`, the 2025 block in `session/convert/msc4143.rs` and its dispatch arm, the `StickyEvents` variants of `ElementCallCompat` / `FfiElementCallCompat`, and their tests and acceptance tests; `outbound_event_type` / `build_content` keep two arms (`Off`, `StateEvents`). Element Call then maps `Matrix_2_0 → Off`: spec MSC4143 sticky events with slots (which Element Call opens, C1) and the spec key message. | +| C10 | `MediaKeyState` has `holds_our_key`, `have_their_key` and `rejection`, so a tile learns about an unsigned sender only when `require_cross_signed_sender` is on (the key is discarded, `rejection: NotCrossSigned`). With the check off the verdict is dropped on accept and the tile cannot show an unverified sender. | **Done.** The inbound key store keeps the MSC4153 verdict of the accepted key per member and exposes it as `FfiMediaKeyState.sender_cross_signed: Option` (`None` when the host could not tell). Element Call runs with the check off (§5.8) and wants to show the state on the tile until it is turned on. | +| C11 | No way to change `application["m.call.intent"]` while joined; Element Call flips it between `audio` and `video` when the camera is toggled (`updateCallIntent`). | `update_application(intent)` on the own-membership manager, facade and FFI: while connected the membership is re-published at once on the refresh path (a failure retries like a refresh); during a join the join event carries it; refused with `NotJoined` otherwise. | +| C12 | Homeserver connectivity lived only in Element Call's driver; the crate could not tell a dead homeserver from a quiet one, and a participation's status said nothing about it. | **Done.** `ConnectivityDriver` (`is_homeserver_connected`, `subscribe_connectivity`) joins the `MatrixDriver` sum; the FFI adds `ConnectivitySink`, the two callback methods and `FfiParticipationManager.is_homeserver_connected()`; the facade pump consumes the stream and reports `Impairment::HomeserverUnreachable { since_ts }` (Critical, sorted first) in every non-disconnected status until the driver reports the homeserver back. The web-test-app mock and js-sdk driver implement it. A matrix-rust-sdk adapter implements the same two methods later. | +| C13 | `session()` moved (seed done, slot opened by somebody else) without any listener firing, so a host's `session$` stayed stale until a membership or status change happened to refresh it. Found by the real-backend check. | **Done.** `SessionListener` / `set_session_listener` on the FFI manager (`on_session_change` on the facade), fired publish-on-change from `refresh_outputs`; `CallParticipation.session$` is fed from it. | No crate work is deferred: `update_application` is C11. @@ -401,9 +405,8 @@ documented as such in `docs/`: `delayed_leave.restart_ms`, `FfiParticipationConfig.useKeyDelayMs`. Compat: `MatrixRTCMode.Compatibility → StateEvents`, `Matrix_2_0 → Off` (spec -MSC4143: sticky member events, slots, the spec key message). Until C9 lands the -code still maps `Matrix_2_0` to the crate's `StickyEvents`; `compatForMode` is -the one place that changes. +MSC4143: sticky member events, slots, the spec key message), in +`compatForMode`. ### 4.4 React tree @@ -485,8 +488,8 @@ Differences from the draft, all required by the widget client: is one `authedRequest` on a full client and `Unsupported` on a widget client; `getLivekitToken` appends `delay_id`, `delay_timeout` and `delay_cs_api_url` (`client.baseUrl`) when the request carries a - delegation. The crate decides when to call which (C5). Until C5 lands the - driver still carries Element Call's probe and JWT delegation; both go then. + delegation. The crate decides when to call which (C5). Element Call carries no + delegation probe or policy. - sticky listener attached after `startClient()` resolves (the widget room only exists then, `embedded.ts:326`). - `getLivekitToken` reuses today's request shapes (`slot_id: "m.call#ROOM"`, @@ -530,8 +533,9 @@ RateLimited`, 403 → `Rejected`, 404/`M_UNRECOGNIZED` → `Unsupported`. 9. **Delegation is the crate's alone.** Element Call always asks for it; the crate tries the CS API, then the authorisation service's token endpoint, then its own restarts, and arms the long delegated leave only once - delegation is confirmed (C5). Element Call keeps no probe and no - delegation code. + delegation is confirmed (C5, done). Element Call keeps no probe and no + delegation code; `delegated_delayed_leave.delay_ms` feeds + `FfiJoinParams.delegatedDelayMs`. 10. **Widget trust model:** origins synthesised from claimed device ids equal today's js-sdk trust level; the crate records them as `DeviceAttribution::Verified` because it cannot tell. Documented in the @@ -539,6 +543,20 @@ RateLimited`, 403 → `Rejected`, 404/`M_UNRECOGNIZED` → `Unsupported`. 11. **Scratch files** go to `agent-workspace/oxidation/`; this plan lives at the repo root because it was asked for by name. 12. **Branch** `toger5/oxidation`, one commit per slice. +13. **Compatibility mode has no slot.** Under `StateEvents` the crate projects + the session from the MSC3401 state events alone and requires the legacy + slot id `""` (`LEGACY_SLOT_ID` in `src/state/rtc/slot.ts`, + `slotIdForCompat`); `CallParticipation` picks it from the config and skips + the slot check and the slot open. Found by the real-backend check: with + `m.call#ROOM` the crate saw its own legacy membership as a candidate but + never projected it. Element Call's own rooms already let every member send + the legacy member state event (`state_default: 0`); a plain room does not, + which the backend test reproduces. +14. **Member events in encrypted rooms are Megolm-encrypted** by matrix-js-sdk + (sticky events are timeline events; the SDK exempts only reactions and + redactions), as they are with the js-sdk MatrixRTC code today. The driver + decrypts them on the way in; the sticky marker (`msc4354_sticky`) stays in + the clear. To cross-check against Element X before relying on it. --- @@ -600,26 +618,50 @@ Gate: `cargo test --features uniffi`, `cargo clippy --all-targets --features uni `Disconnected{LeftByHost}`; join → leave → join; scope end destroys the manager; fallback transport when the host throws or advertises none. -### S3 — view model, four slices ☐ +### S3 — view model, four slices ☑ (side by side with the js-sdk view model) -- **S3a** `Connection`/`ConnectionManager`/`ConnectionFactory` keyed by - `serviceUrl`, fed by `Behavior<{ serviceUrl, wsUrl, jwt, expiresAtTs }[]>`, - with a temporary adapter from today's `SFUConfig` so `openIDSFU` stays - until S3c. Introduces `mockCallParticipation()` and `mockFfiMembership()` in - `src/utils/test.ts`. -- **S3b** `MatrixLivekitMembers` + `MatrixKeyProvider` on `FfiMembership` / - key changes, with an adapter from `CallMembership` for the still-js-sdk - `memberships$`. -- **S3c** `LocalMember` on `callParticipation.join/leave` + status-derived - connectivity; delete `LocalTransport.ts`, `RtcTransportAutoDiscovery.ts`, - `HomeserverConnected.ts`, `openIDSFU.ts`, `enterRTCSession`. -- **S3d** `createCallViewModel$` signature, `CallNotificationLifecycle`, - `MatrixMemberMetadata`, `SessionBehaviors.ts` and - `useMatrixRTCSessionMemberships.ts` deleted, `ReactionsReader` on - `participation` + `TimelineDriver`; test kit swapped - (`MockRTCSession`/`mockRtcMembership` deleted). To stay green before S5, - `CallView` builds a `JsSdkMatrixDriver` from its existing `client` / - `rtcSession.room` props as a temporary shim. +- **Shape (2026-09-15):** the existing factory is renamed + `createJsClientCallViewModel$` and the new `createCallViewModel$(scope, +participation, clientDriver, …)` sits next to it; both build a + `CallViewModelCore` and hand it to the shared `assembleCallViewModel`, so + the layout/tile half is one piece of code and the two Matrix sides can be + reviewed side by side. `MatrixLivekitMember.membership$` is a neutral + `CallMember` (`userId`, `deviceId`, `memberId`, `rtcBackendIdentity`) that + js-sdk's `CallMembership` satisfies; `CallNotificationLifecycle` takes a + neutral `DeclineEvent`. Nothing js-sdk is deleted yet (that is S6). +- **S3a** `remoteMembers/ParticipationConnections.ts`: one `Connection` per + service URL in `participation.connections$`, started with the crate's + token; a refreshed token keeps the connection (used on the next + (re)connect). `Connection`/`ECConnectionFactory` accept a `null` client. + Test fakes live in `src/utils/test-participation.ts` + (`FakeParticipation`, `fakeMembership`, `fakeConnection`, `fakeMediaKey`). +- **S3b** `remoteMembers/ParticipationMembers.ts` (remote members matched by + `transportIdentity`, keyed by `memberId`; `callMemberOf`) and + `e2ee/participationKeyProvider.ts` (`keyMap$` × `memberships$` × + `ownTransportIdentity$` → `onSetEncryptionKey`, once per (member, index, + identity); a key that arrives before the identity waits for the roster). +- **S3c** `localMember/LocalMedia.ts` is the LiveKit half extracted from + `LocalMember.ts` (publisher, tracks, screen share, upstream pausing, host + notify) and shared; `localMember/ParticipationLocalMember.ts` joins and + leaves through the participation (slot policy from `roomInfo`, custom + LiveKit URL as a `Publish` intent, `updateApplication` on camera toggle), + derives connected / reconnecting / `probablyLeft` from `status$` + (`HomeserverUnreachable` → "sync", `RestartFailing`/`Expired` → + "probablyLeft") and the fatal error from `errorForStatus`. Deletions + (`LocalTransport.ts`, `RtcTransportAutoDiscovery.ts`, + `HomeserverConnected.ts`, `openIDSFU.ts`, `enterRTCSession`) wait for S6. +- **S3d** `ParticipationCallNotification.ts` sends `org.matrix.msc4075.rtc.notification` + after our own echo when nobody was in the session before us (resets on + leave) and reads declines from the `TimelineDriver`; + `remoteMembers/ParticipationMemberMetadata.ts` adapts the client driver's + roster to `RoomMemberMap` so `createMatrixMemberMetadata$` and the ringing + name work unchanged. Still open: `ReactionsReader` on `participation` + + `TimelineDriver` (the new factory takes the hands/reactions observables + as inputs like the old one; S4b), `keyRotationSuppressed$` is `constant(false)`, + and the js-sdk test kit stays until S6. Tests: + `CallViewModel.participation.test.ts` (real wasm, mock drivers, mocked + LiveKit: join → connection → own tile → peer → leave; transport-missing → + `fatalError$`), plus one file per module. ### S4 — React tree, two slices ☐ @@ -635,9 +677,17 @@ Gate: `cargo test --features uniffi`, `cargo clippy --all-targets --features uni `ReactionsReader` keyed by `memberId`, `CallNotificationLifecycle` sending through the driver; tests incl. a membership re-send mid-call. -### S5 — hosts ☐ +### S5 — hosts ☐ (component props done 2026-09-15) -- `component/index.tsx`, `component/matrix-js-sdk.ts`, `component/package.json` +- **Done:** `ElementCallProps` takes `rtcDriver` + `clientDriver` (`roomId` + optional, asserted equal); `ElementCallClientBased` takes `client` + + `roomId` and builds the two js-sdk drivers (the dev harness uses it); the + driver types and the js-sdk drivers are exported from the component index. + **Temporary:** until S4 the tree under `CallView` still runs on the + client, so `ElementCall` requires the client driver to be + `JsSdkElementCallMatrixClientDriver` (its `client`/`room` are public for + this) and throws for any other driver. +- `component/matrix-js-sdk.ts`, `component/package.json` (`exports`, peers), `vite-component.config.ts` (two entries, `fileName` function, externals shrink, `?url&no-inline`), `component/tsconfig.build.json`, `component/dev/Harness.tsx`, `README.md`. @@ -691,6 +741,7 @@ Gate: `cargo test --features uniffi`, `cargo clippy --all-targets --features uni | four builds | | ● | | | | | ● | ● | | Playwright standalone + widget + component | | | | | | | ● | ● | | Manual: two harness panes hear each other, E2EE, hand raise, reaction, leave | | | | | | | ● | | +| Real backend (`CallParticipation.backend.test.ts`, opt-in, both modes) | | | | ● | | | ● | | --- @@ -728,3 +779,31 @@ gaps (§2); knip `ignore` vs `ignoreFiles`, oxlint/oxfmt ignores, `.d.ts` for the glue, lazy wasm boot, Storybook `beforeAll`; slice re-cut (S0a/b, S1a/b, S3a–d, S4a/b, temporary `CallView` shim); `sdk/main.ts` status wiring and the Playwright delegation helper. + +**Real-backend check (2026-09-15), `pnpm backend` + `src/state/rtc/CallParticipation.backend.test.ts`** +(`MATRIX_RTC_BACKEND=1 NODE_TLS_REJECT_UNAUTHORIZED=0 pnpm vitest run --project unit src/state/rtc/CallParticipation.backend.test.ts`; +two registered users with rust crypto in an encrypted room, `matrix_2_0` and +`compatibility`): passes end to end — transport discovery from +`/rtc/transports`, slot open + echo, sticky member event with `msc4354_sticky`, +delayed leave, delegation via the homeserver, roster with display names, +Olm-encrypted media keys both ways with `senderCrossSigned`, leave cancelling +the delayed event, and `HomeserverUnreachable` raised and cleared across a +simulated network outage. Fixed on the way: MSC4195 `member` claims and the +homeserver route's body (`url`, `delay_timeout`; C5), the missing session +listener (C13), the legacy slot id under compatibility mode (§5.13). Noted: +`vite-plugin-node-polyfills` shadows `process`, so tests read the environment +through `node:process`; Synapse develop already proxies the MSC4195 endpoint +to lk-jwt-service; member events are Megolm-encrypted in encrypted rooms +(§5.14). Not verified here: the widget host path (Element Web) and the +authorisation-service route (the homeserver route is taken first on this +stack; it is covered by unit tests only). + +**S3 (2026-09-15):** the driver-based `createCallViewModel$` landed next to +the renamed `createJsClientCallViewModel$` (shared `assembleCallViewModel`, +neutral `CallMember`/`DeclineEvent`, `LocalMedia.ts` extracted); component +props moved to the two drivers with `ElementCallClientBased` on top. Gates: +`pnpm lint`, `format:check`, `test:unit` (803), `i18n:check`, +`build:component` green. Open from this slice: reactions reader on the +participation (S4b), the `?url&no-inline` wasm asset for the component build +(the wasm is loaded lazily and inlined into the component bundle today), and +the S6 deletions. diff --git a/sdk/main.ts b/sdk/main.ts index 6cd37032d..9b7526e7e 100644 --- a/sdk/main.ts +++ b/sdk/main.ts @@ -31,7 +31,6 @@ import { tap, } from "rxjs"; import { - type CallMembership, MatrixRTCSessionEvent, MatrixRTCSessionManager, } from "matrix-js-sdk/lib/matrixrtc"; @@ -48,7 +47,7 @@ import { type TextStreamInfo } from "../node_modules/livekit-client/dist/src/roo import { type Behavior, constant } from "../src/state/Behavior"; import { callViewModelOptionsFromParams, - createCallViewModel$, + createJsClientCallViewModel$, } from "../src/state/CallViewModel/CallViewModel"; import { ObservableScope } from "../src/state/ObservableScope"; import { getUrlParams } from "../src/UrlParams"; @@ -59,6 +58,7 @@ import { currentAndPrev, TEXT_LK_TOPIC, tryMakeSticky } from "./helper"; import { logger as rootLogger } from "matrix-js-sdk/lib/logger"; import { initializeWidget } from "../src/widget"; import { type Connection } from "../src/state/CallViewModel/remoteMembers/Connection"; +import { type CallMember } from "../src/state/CallViewModel/remoteMembers/MatrixLivekitMembers"; import { createWidgetHostBridge } from "../src/HostBridge"; import { observeElementSize$ } from "../src/utils/elementSize"; @@ -83,7 +83,7 @@ interface MatrixRTCSdk { remoteMembers$: Behavior< { connection: Connection | null; - membership: CallMembership; + membership: CallMember; participant: LocalParticipant | RemoteParticipant | null; }[] >; @@ -92,7 +92,7 @@ interface MatrixRTCSdk { */ localMember$: Behavior<{ connection: Connection | null; - membership: CallMembership; + membership: CallMember; participant: LocalParticipant | null; } | null>; /** Use the LocalMemberConnectionState returned from `join` for a more detailed connection state */ @@ -142,7 +142,7 @@ export async function createMatrixRTCSdk( ); // call view model - const callViewModel = createCallViewModel$( + const callViewModel = createJsClientCallViewModel$( scope, rtcSession, room, diff --git a/src/driver/MockRtcMatrixDriver.test.ts b/src/driver/MockRtcMatrixDriver.test.ts index 39f87ce1c..58aed4139 100644 --- a/src/driver/MockRtcMatrixDriver.test.ts +++ b/src/driver/MockRtcMatrixDriver.test.ts @@ -28,7 +28,7 @@ import { } from "./MockRtcMatrixDriver"; const config: FfiParticipationConfig = { - compat: FfiElementCallCompat.StickyEvents, + compat: FfiElementCallCompat.Off, manageMediaKeys: true, requireCrossSignedSender: false, useKeyDelayMs: 50n, @@ -41,6 +41,7 @@ const joinParams = { keepAliveTimeoutMs: 15_000n, degradedLifetimeMs: undefined, delegateDelayedLeave: false, + delegatedDelayMs: 3_600_000n, }; const publish = (): FfiTransportIntent => @@ -117,10 +118,15 @@ describe("MockRtcMatrixDriver as the crate's driver", () => { await waitFor("key exchange", () => manager.keyMap().some((k) => k.memberId === peer.memberId), ); - // StickyEvents compat: our key went out in the deployed dialect + // spec MSC4143: the key message Element X's crates read too expect(driver.calls("toDevice")[0].eventType).toBe( - "io.element.call.encryption_keys", + "org.matrix.msc4143.rtc.encryption_key", ); + // the tile carries the sender's MSC4153 verdict even with the check off + expect( + manager.memberships().find((m) => m.member.memberId === peer.memberId) + ?.mediaKey?.senderCrossSigned, + ).toBe(true); driver.peerLeaves(peer); expect( manager.memberships().find((m) => m.member.memberId === peer.memberId) diff --git a/src/driver/MockRtcMatrixDriver.ts b/src/driver/MockRtcMatrixDriver.ts index 77f63ae57..58d68c256 100644 --- a/src/driver/MockRtcMatrixDriver.ts +++ b/src/driver/MockRtcMatrixDriver.ts @@ -29,6 +29,8 @@ import { type FfiSendEventResponse, type FfiToDeviceDelivery, type FfiToDeviceRecipient, + type FfiHomeserverDelegationRequest, + type FfiTransportDelegationRequest, type RoomEventSinkLike, type StateUpdateSinkLike, type ToDeviceSinkLike, @@ -78,14 +80,8 @@ export type OutboundCall = } | { kind: "restartDelayed"; roomId: string; delayId: string } | { kind: "cancelDelayed"; roomId: string; delayId: string } - | { - kind: "delegateDelayedLeave"; - roomId: string; - slotId: string; - delayId: string; - livekitServiceUrl: string | undefined; - delayMs: bigint; - } + | { kind: "delegateViaHomeserver"; request: FfiHomeserverDelegationRequest } + | { kind: "delegateViaTransport"; request: FfiTransportDelegationRequest } | { kind: "toDevice"; recipients: FfiToDeviceRecipient[]; @@ -137,6 +133,10 @@ export class MockRtcMatrixDriver implements RtcMatrixDriver { public refuseStickyEvents = false; /** Make `getRtcTransports` fail rather than answer. */ public failTransportDiscovery = false; + /** No MSC4195 endpoint on the homeserver: the crate falls back to the service. */ + public refuseHomeserverDelegation = false; + /** The authorisation service refuses the delegation too. */ + public refuseTransportDelegation = false; public roomState: RawEvent[]; public transports: FfiRtcTransport[]; /** Simulated peers answer our media key with theirs (index 0). */ @@ -299,22 +299,21 @@ export class MockRtcMatrixDriver implements RtcMatrixDriver { return Promise.resolve(); } - public async delegateLivekitDelayedLeave( - roomId: string, - slotId: string, - _memberJson: string, - delayId: string, - livekitServiceUrl: string | undefined, - delayMs: bigint, + public async delegateDelayedLeaveViaHomeserver( + request: FfiHomeserverDelegationRequest, ): Promise { - this.record({ - kind: "delegateDelayedLeave", - roomId, - slotId, - delayId, - livekitServiceUrl, - delayMs, - }); + this.record({ kind: "delegateViaHomeserver", request }); + if (this.refuseHomeserverDelegation) + throw new RtcError.Unsupported("M_UNRECOGNIZED: no delegation endpoint"); + return Promise.resolve(); + } + + public async delegateDelayedLeaveViaTransport( + request: FfiTransportDelegationRequest, + ): Promise { + this.record({ kind: "delegateViaTransport", request }); + if (this.refuseTransportDelegation) + throw new RtcError.Http("503: the service refused"); return Promise.resolve(); } diff --git a/src/driver/jsSdk/JsSdkElementCallMatrixClientDriver.ts b/src/driver/jsSdk/JsSdkElementCallMatrixClientDriver.ts index 32b6bbc76..27a00d43d 100644 --- a/src/driver/jsSdk/JsSdkElementCallMatrixClientDriver.ts +++ b/src/driver/jsSdk/JsSdkElementCallMatrixClientDriver.ts @@ -64,8 +64,13 @@ export class JsSdkElementCallMatrixClientDriver implements ElementCallMatrixClie private capabilities: Promise | null = null; public constructor( - private readonly client: MatrixClient, - private readonly room: Room, + /** + * The client and room this driver wraps. Public only for the React tree + * that still runs on matrix-js-sdk directly (`CallView` and below); once + * that tree reads the drivers (plan slice S4) these become private. + */ + public readonly client: MatrixClient, + public readonly room: Room, options: JsSdkElementCallMatrixClientDriverOptions = {}, ) { const userId = client.getUserId(); diff --git a/src/driver/jsSdk/JsSdkRtcMatrixDriver.test.ts b/src/driver/jsSdk/JsSdkRtcMatrixDriver.test.ts index 130fbfb98..4e93f826a 100644 --- a/src/driver/jsSdk/JsSdkRtcMatrixDriver.test.ts +++ b/src/driver/jsSdk/JsSdkRtcMatrixDriver.test.ts @@ -250,19 +250,45 @@ describe("JsSdkRtcMatrixDriver", () => { ).rejects.toSatisfy((e) => RtcError.Unsupported.instanceOf(e)); }); - it("delegates the delayed leave through the authorisation service's token endpoint", async () => { - const { driver } = fullClient(); + it("offers both delegation primitives: the homeserver endpoint and the token endpoint", async () => { + const { client, driver } = fullClient(); + client.http = { authedRequest: vi.fn(async () => Promise.resolve({})) }; + await driver.delegateDelayedLeaveViaHomeserver({ + sfuUrl: "wss://sfu.example.org", + livekitServiceUrl: LK, + roomId: ROOM_ID, + slotId: "m.call#ROOM", + memberJson, + delayId: "delay-1", + delayTimeoutMs: 3_600_000n, + }); + expect(client.http.authedRequest).toHaveBeenCalledWith( + "POST", + "/rtc/livekit/delegate_delayed_leave", + undefined, + { + url: "wss://sfu.example.org", + room_id: ROOM_ID, + slot_id: "m.call#ROOM", + member: JSON.parse(memberJson), + delay_id: "delay-1", + delay_timeout: 3_600_000, + }, + { prefix: "/_matrix/client/unstable/io.element.msc4195" }, + ); + fetchMock.mockImplementation(async () => Promise.resolve(jsonResponse({ jwt: "discarded" })), ); - await driver.delegateLivekitDelayedLeave( - ROOM_ID, - "m.call#ROOM", + await driver.delegateDelayedLeaveViaTransport({ + livekitServiceUrl: LK, + roomId: ROOM_ID, + slotId: "m.call#ROOM", memberJson, - "delay-1", - LK, - 3_600_000n, - ); + delayId: "delay-1", + delayTimeoutMs: 3_600_000n, + legacySfuGet: false, + }); const [endpoint, init] = fetchMock.mock.calls[0] as unknown as [ string, RequestInit, @@ -273,17 +299,6 @@ describe("JsSdkRtcMatrixDriver", () => { delay_timeout: 3_600_000, delay_cs_api_url: "https://hs.example.org", }); - // receive-only: nothing to delegate to - await expect( - driver.delegateLivekitDelayedLeave( - ROOM_ID, - "m.call#ROOM", - memberJson, - "delay-1", - undefined, - 1n, - ), - ).rejects.toSatisfy((e) => RtcError.Unsupported.instanceOf(e)); }); it("feeds sticky events and state updates into the crate's sinks with their origin", async () => { @@ -418,6 +433,21 @@ describe("JsSdkRtcMatrixDriver", () => { expect(crossSigned).toBeUndefined(); }); + it("cannot delegate through the homeserver, so the crate falls back to the service", async () => { + const { driver } = widgetClient(); + await expect( + driver.delegateDelayedLeaveViaHomeserver({ + sfuUrl: "wss://sfu.example.org", + livekitServiceUrl: LK, + roomId: ROOM_ID, + slotId: "m.call#ROOM", + memberJson, + delayId: "delay-1", + delayTimeoutMs: 3_600_000n, + }), + ).rejects.toSatisfy((e) => RtcError.Unsupported.instanceOf(e)); + }); + it("treats member events in an encrypted room as encrypted by the claimed device", async () => { const { room, driver } = widgetClient(); const roomSink = sink(); diff --git a/src/driver/jsSdk/JsSdkRtcMatrixDriver.ts b/src/driver/jsSdk/JsSdkRtcMatrixDriver.ts index c0c4da1e9..703bac8ff 100644 --- a/src/driver/jsSdk/JsSdkRtcMatrixDriver.ts +++ b/src/driver/jsSdk/JsSdkRtcMatrixDriver.ts @@ -27,6 +27,7 @@ import { type MatrixClient, type MatrixEvent, MatrixError, + Method, type ReceivedToDeviceMessage, type Room, RoomEvent, @@ -52,6 +53,8 @@ import { type FfiSendEventResponse, type FfiToDeviceDelivery, type FfiToDeviceRecipient, + type FfiHomeserverDelegationRequest, + type FfiTransportDelegationRequest, type RoomEventSinkLike, type StateUpdateSinkLike, type ToDeviceSinkLike, @@ -200,38 +203,59 @@ export class JsSdkRtcMatrixDriver implements RtcMatrixDriver { } /** - * MSC4195, the way Element Call has always done it: the MatrixRTC - * authorisation service takes over the delayed leave when asked for a token - * with `delay_id`, `delay_timeout` and the homeserver it should restart it - * at. The token in the answer is discarded. (Interim: plan item C5 moves - * the choice of route into the crate and leaves only primitives here.) + * MSC4195 through the homeserver's CS API (a homeserver proxying + * `rtc/livekit/*` to the authorisation service, MSC4512). One + * authenticated request with the body lk-jwt-service 0.7 accepts; the + * crate decides when to make it and what to try when it fails. Widget: the + * widget client has no access token, so this is `Unsupported` there. */ - public async delegateLivekitDelayedLeave( - roomId: string, - slotId: string, - memberJson: string, - delayId: string, - livekitServiceUrl: string | undefined, - delayMs: bigint, + public async delegateDelayedLeaveViaHomeserver( + request: FfiHomeserverDelegationRequest, ): Promise { - if (livekitServiceUrl === undefined) + if (this.widget) throw new RtcError.Unsupported( - "A receive-only member has no transport to delegate to", + "A widget client cannot make authenticated homeserver requests", ); await guard(async () => { - const member = JSON.parse(memberJson) as MemberClaims; - const delegation = { - delay_id: delayId, - delay_timeout: Number(delayMs), - delay_cs_api_url: this.client.baseUrl, - }; + await this.client.http.authedRequest( + Method.Post, + "/rtc/livekit/delegate_delayed_leave", + undefined, + { + // The SFU our token named; the service checks it is its own. + url: request.sfuUrl, + room_id: request.roomId, + slot_id: request.slotId, + member: JSON.parse(request.memberJson) as MemberClaims, + delay_id: request.delayId, + // Optional once the homeserver can be asked for the delay by id. + delay_timeout: Number(request.delayTimeoutMs), + }, + { prefix: "/_matrix/client/unstable/io.element.msc4195" }, + ); + }); + } + + /** + * MSC4195 through the authorisation service: the token request Element Call + * has always made, with `delay_id`, `delay_timeout` and this client's + * homeserver URL added. The token in the answer is discarded. + */ + public async delegateDelayedLeaveViaTransport( + request: FfiTransportDelegationRequest, + ): Promise { + await guard(async () => { await this.requestToken( - livekitServiceUrl, - roomId, - slotId, - member, - false, - delegation, + request.livekitServiceUrl, + request.roomId, + request.slotId, + JSON.parse(request.memberJson) as MemberClaims, + request.legacySfuGet, + { + delay_id: request.delayId, + delay_timeout: Number(request.delayTimeoutMs), + delay_cs_api_url: this.client.baseUrl, + }, ); }); } diff --git a/src/driver/jsSdk/jsSdkTestFakes.ts b/src/driver/jsSdk/jsSdkTestFakes.ts index 4c61a2c0d..fa7d2f59e 100644 --- a/src/driver/jsSdk/jsSdkTestFakes.ts +++ b/src/driver/jsSdk/jsSdkTestFakes.ts @@ -47,6 +47,7 @@ export interface FakeClient extends EventEmitter { redactEvent: Fn; getSyncState: Fn; getUser: (userId: string) => User | null; + http: { authedRequest: Fn }; } export interface FakeRoom extends EventEmitter { diff --git a/src/e2ee/participationKeyProvider.test.ts b/src/e2ee/participationKeyProvider.test.ts new file mode 100644 index 000000000..65ebefe23 --- /dev/null +++ b/src/e2ee/participationKeyProvider.test.ts @@ -0,0 +1,75 @@ +/* +Copyright 2026 Element Creations Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE in the repository root for full details. +*/ + +import { describe, expect, it } from "vitest"; +import { KeyProviderEvent } from "livekit-client"; + +import { testScope } from "../utils/test"; +import { + FakeParticipation, + fakeMediaKey, + fakeMembership, +} from "../utils/test-participation"; +import { waitFor } from "../driver/MockRtcMatrixDriver"; +import { ParticipationKeyProvider } from "./participationKeyProvider"; + +interface SetKey { + participantIdentity: string | undefined; + keyIndex: number | undefined; +} + +function attached(): { + participation: FakeParticipation; + setKeys: SetKey[]; +} { + const participation = new FakeParticipation(); + const provider = new ParticipationKeyProvider(); + const setKeys: SetKey[] = []; + provider.on(KeyProviderEvent.SetKey, ({ participantIdentity, keyIndex }) => + setKeys.push({ participantIdentity, keyIndex }), + ); + provider.attach(testScope(), participation); + return { participation, setKeys }; +} + +describe("ParticipationKeyProvider", () => { + it("hands our own key to LiveKit under our transport identity", async () => { + const { participation, setKeys } = attached(); + participation.ownMemberId$.next("m-me"); + participation.ownTransportIdentity$.next("lk-me"); + participation.keyMap$.next([fakeMediaKey({ memberId: "m-me", index: 0 })]); + await waitFor("own key set", () => setKeys.length === 1); + expect(setKeys).toEqual([{ participantIdentity: "lk-me", keyIndex: 0 }]); + }); + + it("waits for a peer's transport identity and sets each key once", async () => { + const { participation, setKeys } = attached(); + // The key arrives before the roster knows the member's identity. + participation.keyMap$.next([ + fakeMediaKey({ memberId: "m-peer", index: 2 }), + ]); + await new Promise((resolve) => setTimeout(resolve, 20)); + expect(setKeys).toEqual([]); + + participation.setMemberships([ + fakeMembership({ + member: { memberId: "m-peer" }, + transportIdentity: "lk-peer", + }), + ]); + await waitFor("peer key set", () => setKeys.length === 1); + expect(setKeys).toEqual([{ participantIdentity: "lk-peer", keyIndex: 2 }]); + + // The map is re-emitted (a rotation elsewhere): no second delivery. + participation.keyMap$.next([ + fakeMediaKey({ memberId: "m-peer", index: 2 }), + fakeMediaKey({ memberId: "m-peer", index: 3 }), + ]); + await waitFor("next index set", () => setKeys.length === 2); + expect(setKeys[1]).toEqual({ participantIdentity: "lk-peer", keyIndex: 3 }); + }); +}); diff --git a/src/e2ee/participationKeyProvider.ts b/src/e2ee/participationKeyProvider.ts new file mode 100644 index 000000000..e326132f7 --- /dev/null +++ b/src/e2ee/participationKeyProvider.ts @@ -0,0 +1,92 @@ +/* +Copyright 2026 Element Creations Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE in the repository root for full details. +*/ + +import { BaseKeyProvider } from "livekit-client"; +import { combineLatest } from "rxjs"; +import { logger as rootLogger, type Logger } from "matrix-js-sdk/lib/logger"; + +import { type Behavior } from "../state/Behavior"; +import { type Epoch, type ObservableScope } from "../state/ObservableScope"; +import { type FfiMediaKey, type FfiMembership } from "../matrix-rtc-sdk"; + +/** What this provider needs from a {@link CallParticipation}. */ +export interface ParticipationKeys { + /** Every media key in use, ours and theirs, one per (member, index). */ + keyMap$: Behavior; + memberships$: Behavior>; + ownMemberId$: Behavior; + ownTransportIdentity$: Behavior; +} + +/** + * Feeds the crate's media keys to livekit-client's E2EE workers. + * + * The crate exchanges keys per member id; LiveKit encrypts per participant + * identity. A key is handed over as soon as both are known — a key that + * arrives before its member's transport identity waits on the roster rather + * than being dropped — and once per (member, index, identity), so a + * re-emitted map does not churn the key ring. + */ +export class ParticipationKeyProvider extends BaseKeyProvider { + private readonly logger: Logger; + private readonly applied = new Set(); + + public constructor() { + super({ ratchetWindowSize: 10, keyringSize: 256 }); + this.logger = rootLogger.getChild("[ParticipationKeyProvider]"); + } + + /** Follow the participation's keys for as long as `scope` lives. */ + public attach( + scope: ObservableScope, + participation: ParticipationKeys, + ): void { + combineLatest([ + participation.keyMap$, + participation.memberships$, + participation.ownMemberId$, + participation.ownTransportIdentity$, + ]) + .pipe(scope.bind()) + .subscribe(([keys, memberships, ownMemberId, ownIdentity]) => { + for (const key of keys) { + const identity = + key.memberId === ownMemberId + ? ownIdentity + : memberships.value.find( + (m) => m.member.memberId === key.memberId, + )?.transportIdentity; + if (!identity) continue; + const tag = `${key.memberId}|${key.index}|${identity}`; + if (this.applied.has(tag)) continue; + this.applied.add(tag); + void this.setKey(key, identity); + } + }); + } + + private async setKey(key: FfiMediaKey, identity: string): Promise { + try { + const material = await crypto.subtle.importKey( + "raw", + key.key, + "HKDF", + false, + ["deriveBits", "deriveKey"], + ); + this.onSetEncryptionKey(material, identity, key.index); + this.logger.debug( + `Set key for participant ${identity} (member ${key.memberId}) index ${key.index}`, + ); + } catch (e) { + this.logger.error( + `Failed to import the key of member ${key.memberId} index ${key.index}`, + e, + ); + } + } +} diff --git a/src/matrix-rtc-sdk/generated/VERSION b/src/matrix-rtc-sdk/generated/VERSION index 692c326aa..8966fc8d9 100644 --- a/src/matrix-rtc-sdk/generated/VERSION +++ b/src/matrix-rtc-sdk/generated/VERSION @@ -1,2 +1,2 @@ -matrix-rtc (MatrixSdkArchitectureDraft) a095ba7-dirty -built 2026-09-15T16:54:50Z by scripts/sync-matrix-rtc-sdk.sh +matrix-rtc (MatrixSdkArchitectureDraft) 088a598-dirty +built 2026-09-15T18:22:09Z by scripts/sync-matrix-rtc-sdk.sh diff --git a/src/matrix-rtc-sdk/generated/matrix_rtc-ffi.ts b/src/matrix-rtc-sdk/generated/matrix_rtc-ffi.ts index f71af07bf..67a59c954 100644 --- a/src/matrix-rtc-sdk/generated/matrix_rtc-ffi.ts +++ b/src/matrix-rtc-sdk/generated/matrix_rtc-ffi.ts @@ -51,17 +51,18 @@ export type UniffiForeignFutureResultVoid = { export type UniffiForeignFutureCompletevoid = (callbackData: bigint, result: UniffiForeignFutureResultVoid) => void; type UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod4 = (uniffiHandle: bigint, roomId: Uint8Array, delayId: Uint8Array, uniffiFutureCallback: UniffiForeignFutureCompletevoid, uniffiCallbackData: bigint) => UniffiForeignFutureDroppedCallbackStruct; type UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod5 = (uniffiHandle: bigint, roomId: Uint8Array, delayId: Uint8Array, uniffiFutureCallback: UniffiForeignFutureCompletevoid, uniffiCallbackData: bigint) => UniffiForeignFutureDroppedCallbackStruct; -type UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod6 = (uniffiHandle: bigint, roomId: Uint8Array, slotId: Uint8Array, memberJson: Uint8Array, delayId: Uint8Array, livekitServiceUrl: Uint8Array, delayMs: bigint, uniffiFutureCallback: UniffiForeignFutureCompletevoid, uniffiCallbackData: bigint) => UniffiForeignFutureDroppedCallbackStruct; -type UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod7 = (uniffiHandle: bigint, recipients: Uint8Array, eventType: Uint8Array, contentJson: Uint8Array, uniffiFutureCallback: UniffiForeignFutureCompleterustBuffer, uniffiCallbackData: bigint) => UniffiForeignFutureDroppedCallbackStruct; -type UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod8 = (uniffiHandle: bigint, uniffiFutureCallback: UniffiForeignFutureCompleterustBuffer, uniffiCallbackData: bigint) => UniffiForeignFutureDroppedCallbackStruct; -type UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod9 = (uniffiHandle: bigint, request: Uint8Array, uniffiFutureCallback: UniffiForeignFutureCompleterustBuffer, uniffiCallbackData: bigint) => UniffiForeignFutureDroppedCallbackStruct; -type UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod10 = (uniffiHandle: bigint, eventType: Uint8Array, stateKey: Uint8Array, limit: number, uniffiFutureCallback: UniffiForeignFutureCompleterustBuffer, uniffiCallbackData: bigint) => UniffiForeignFutureDroppedCallbackStruct; -type UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod11 = (uniffiHandle: bigint, eventType: Uint8Array, stateKey: Uint8Array, uniffiFutureCallback: UniffiForeignFutureCompleterustBuffer, uniffiCallbackData: bigint) => UniffiForeignFutureDroppedCallbackStruct; -type UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod12 = (uniffiHandle: bigint, sink: bigint) => UniffiResult; +type UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod6 = (uniffiHandle: bigint, request: Uint8Array, uniffiFutureCallback: UniffiForeignFutureCompletevoid, uniffiCallbackData: bigint) => UniffiForeignFutureDroppedCallbackStruct; +type UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod7 = (uniffiHandle: bigint, request: Uint8Array, uniffiFutureCallback: UniffiForeignFutureCompletevoid, uniffiCallbackData: bigint) => UniffiForeignFutureDroppedCallbackStruct; +type UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod8 = (uniffiHandle: bigint, recipients: Uint8Array, eventType: Uint8Array, contentJson: Uint8Array, uniffiFutureCallback: UniffiForeignFutureCompleterustBuffer, uniffiCallbackData: bigint) => UniffiForeignFutureDroppedCallbackStruct; +type UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod9 = (uniffiHandle: bigint, uniffiFutureCallback: UniffiForeignFutureCompleterustBuffer, uniffiCallbackData: bigint) => UniffiForeignFutureDroppedCallbackStruct; +type UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod10 = (uniffiHandle: bigint, request: Uint8Array, uniffiFutureCallback: UniffiForeignFutureCompleterustBuffer, uniffiCallbackData: bigint) => UniffiForeignFutureDroppedCallbackStruct; +type UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod11 = (uniffiHandle: bigint, eventType: Uint8Array, stateKey: Uint8Array, limit: number, uniffiFutureCallback: UniffiForeignFutureCompleterustBuffer, uniffiCallbackData: bigint) => UniffiForeignFutureDroppedCallbackStruct; +type UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod12 = (uniffiHandle: bigint, eventType: Uint8Array, stateKey: Uint8Array, uniffiFutureCallback: UniffiForeignFutureCompleterustBuffer, uniffiCallbackData: bigint) => UniffiForeignFutureDroppedCallbackStruct; type UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod13 = (uniffiHandle: bigint, sink: bigint) => UniffiResult; type UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod14 = (uniffiHandle: bigint, sink: bigint) => UniffiResult; -type UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod15 = (uniffiHandle: bigint) => number; -type UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod16 = (uniffiHandle: bigint, sink: bigint) => UniffiResult; +type UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod15 = (uniffiHandle: bigint, sink: bigint) => UniffiResult; +type UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod16 = (uniffiHandle: bigint) => number; +type UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod17 = (uniffiHandle: bigint, sink: bigint) => UniffiResult; type UniffiCallbackInterfaceCloneMatrixRtcMatrixDriverCallback = (handle: bigint) => UniffiResult; type UniffiCallbackInterfaceFreeMatrixRtcMatrixDriverCallback = (handle: bigint) => void; export type UniffiVTableCallbackInterfaceMatrixRtcMatrixDriverCallback = { @@ -73,17 +74,18 @@ export type UniffiVTableCallbackInterfaceMatrixRtcMatrixDriverCallback = { send_delayed_state_event: UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod3; restart_delayed_event: UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod4; cancel_delayed_event: UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod5; - delegate_livekit_delayed_leave: UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod6; - send_to_device: UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod7; - get_rtc_transports: UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod8; - get_livekit_token: UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod9; - read_events: UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod10; - read_state: UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod11; - subscribe_room_events: UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod12; - subscribe_to_device_events: UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod13; - subscribe_state_updates: UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod14; - is_homeserver_connected: UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod15; - subscribe_connectivity: UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod16; + delegate_delayed_leave_via_homeserver: UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod6; + delegate_delayed_leave_via_transport: UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod7; + send_to_device: UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod8; + get_rtc_transports: UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod9; + get_livekit_token: UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod10; + read_events: UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod11; + read_state: UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod12; + subscribe_room_events: UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod13; + subscribe_to_device_events: UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod14; + subscribe_state_updates: UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod15; + is_homeserver_connected: UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod16; + subscribe_connectivity: UniffiCallbackInterfaceMatrixRtcMatrixDriverCallbackMethod17; }; type UniffiCallbackInterfaceMatrixRtcMembershipsListenerMethod0 = (uniffiHandle: bigint, memberships: Uint8Array) => UniffiResult; type UniffiCallbackInterfaceCloneMatrixRtcMembershipsListener = (handle: bigint) => UniffiResult; @@ -93,6 +95,14 @@ export type UniffiVTableCallbackInterfaceMatrixRtcMembershipsListener = { uniffi_clone: UniffiCallbackInterfaceCloneMatrixRtcMembershipsListener; on_memberships_change: UniffiCallbackInterfaceMatrixRtcMembershipsListenerMethod0; }; +type UniffiCallbackInterfaceMatrixRtcSessionListenerMethod0 = (uniffiHandle: bigint, session: Uint8Array) => UniffiResult; +type UniffiCallbackInterfaceCloneMatrixRtcSessionListener = (handle: bigint) => UniffiResult; +type UniffiCallbackInterfaceFreeMatrixRtcSessionListener = (handle: bigint) => void; +export type UniffiVTableCallbackInterfaceMatrixRtcSessionListener = { + uniffi_free: UniffiCallbackInterfaceFreeMatrixRtcSessionListener; + uniffi_clone: UniffiCallbackInterfaceCloneMatrixRtcSessionListener; + on_session_change: UniffiCallbackInterfaceMatrixRtcSessionListenerMethod0; +}; type UniffiCallbackInterfaceMatrixRtcStatusListenerMethod0 = (uniffiHandle: bigint, status: Uint8Array) => UniffiResult; type UniffiCallbackInterfaceCloneMatrixRtcStatusListener = (handle: bigint) => UniffiResult; type UniffiCallbackInterfaceFreeMatrixRtcStatusListener = (handle: bigint) => void; diff --git a/src/matrix-rtc-sdk/generated/matrix_rtc.ts b/src/matrix-rtc-sdk/generated/matrix_rtc.ts index 7098b51e2..9f2ef3691 100644 --- a/src/matrix-rtc-sdk/generated/matrix_rtc.ts +++ b/src/matrix-rtc-sdk/generated/matrix_rtc.ts @@ -4,7 +4,7 @@ /* eslint-disable */ // @ts-nocheck import * as wasmBundle from "./wasm-bindgen/index.js"; -import { type UniffiRustFutureContinuationCallback, type UniffiForeignFutureDroppedCallback, type UniffiForeignFutureDroppedCallbackStruct, type UniffiVTableCallbackInterfaceMatrixRtcConnectionsListener, type UniffiVTableCallbackInterfaceMatrixRtcKeyMapListener, type UniffiVTableCallbackInterfaceMatrixRtcKeyRejectedListener, type UniffiForeignFutureResultRustBuffer, type UniffiForeignFutureCompleterustBuffer, type UniffiForeignFutureResultVoid, type UniffiForeignFutureCompletevoid, type UniffiVTableCallbackInterfaceMatrixRtcMatrixDriverCallback, type UniffiVTableCallbackInterfaceMatrixRtcMembershipsListener, type UniffiVTableCallbackInterfaceMatrixRtcStatusListener, +import { type UniffiRustFutureContinuationCallback, type UniffiForeignFutureDroppedCallback, type UniffiForeignFutureDroppedCallbackStruct, type UniffiVTableCallbackInterfaceMatrixRtcConnectionsListener, type UniffiVTableCallbackInterfaceMatrixRtcKeyMapListener, type UniffiVTableCallbackInterfaceMatrixRtcKeyRejectedListener, type UniffiForeignFutureResultRustBuffer, type UniffiForeignFutureCompleterustBuffer, type UniffiForeignFutureResultVoid, type UniffiForeignFutureCompletevoid, type UniffiVTableCallbackInterfaceMatrixRtcMatrixDriverCallback, type UniffiVTableCallbackInterfaceMatrixRtcMembershipsListener, type UniffiVTableCallbackInterfaceMatrixRtcSessionListener, type UniffiVTableCallbackInterfaceMatrixRtcStatusListener, } from "./matrix_rtc-ffi"; import { type FfiConverter, type UniffiByteArray, type UniffiGcObject, type UniffiHandle, type UniffiObjectFactory, type UniffiReferenceHolder, type UniffiRustCallStatus, AbstractFfiConverterByteArray, Cursor, FfiConverterArray, FfiConverterArrayBuffer, FfiConverterBool, FfiConverterObject, FfiConverterObjectWithCallbacks, FfiConverterOptional, FfiConverterUInt32, FfiConverterUInt64, FfiConverterUInt8, RustBuffer, UniffiAbstractObject, UniffiEnum, UniffiError, UniffiInternalError, UniffiResult, UniffiRustCaller, destructorGuardSymbol, pointerLiteralSymbol, uniffiCreateFfiConverterString, uniffiCreateRecord, uniffiRustCallAsync, uniffiTraitInterfaceCall, uniffiTraitInterfaceCallAsyncWithError, uniffiTypeNameSymbol, variantOrdinalSymbol, } from "@ubjs/core"; @@ -554,6 +554,86 @@ const FfiConverterTypeFfiExcludedCandidate = (() => { return new FFIConverter(); })(); +/** + * See `driver::TransportDelegationRequest`: the token request with the + * MSC4195 through the homeserver: `POST + * /_matrix/client/unstable/io.element.msc4195/rtc/livekit/delegate_delayed_leave` + * with the body `{ url, room_id, slot_id, member, delay_id, delay_timeout }` + * — `url` is `sfu_url`, `member` is `member_json` parsed, `delay_timeout` + * is `delay_timeout_ms`. + */ +export type FfiHomeserverDelegationRequest = { + /** + * The SFU websocket URL our token named: the service checks it is its own. + */ + sfuUrl: string, + /** + * The authorisation service of the transport we publish on. + */ + livekitServiceUrl: string, + roomId: string, + slotId: string, + /** + * MSC4195 member claims `{ id, claimed_user_id, claimed_device_id }`. + */ + memberJson: string, + delayId: string, + delayTimeoutMs: bigint +} + +/** + * Generated factory for {@link FfiHomeserverDelegationRequest} record objects. + */ +export const FfiHomeserverDelegationRequest = (() => { + const defaults = () => ({ + }); + const create = (() => { + return uniffiCreateRecord>(defaults); + })(); + return Object.freeze({ + create, + new: create, + defaults: () => Object.freeze(defaults()) as Partial, + }); +})(); + +const FfiConverterTypeFfiHomeserverDelegationRequest = (() => { + type TypeName = FfiHomeserverDelegationRequest; + class FFIConverter extends AbstractFfiConverterByteArray { + readFromCursor(c: Cursor): TypeName { + return { + sfuUrl: FfiConverterString.readFromCursor(c), + livekitServiceUrl: FfiConverterString.readFromCursor(c), + roomId: FfiConverterString.readFromCursor(c), + slotId: FfiConverterString.readFromCursor(c), + memberJson: FfiConverterString.readFromCursor(c), + delayId: FfiConverterString.readFromCursor(c), + delayTimeoutMs: FfiConverterUInt64.readFromCursor(c) + }; + } + writeIntoCursor(value: TypeName, c: Cursor): void { + FfiConverterString.writeIntoCursor(value.sfuUrl, c); + FfiConverterString.writeIntoCursor(value.livekitServiceUrl, c); + FfiConverterString.writeIntoCursor(value.roomId, c); + FfiConverterString.writeIntoCursor(value.slotId, c); + FfiConverterString.writeIntoCursor(value.memberJson, c); + FfiConverterString.writeIntoCursor(value.delayId, c); + FfiConverterUInt64.writeIntoCursor(value.delayTimeoutMs, c); + } + allocationSize(value: TypeName): number { + return FfiConverterString.allocationSize(value.sfuUrl) + + FfiConverterString.allocationSize(value.livekitServiceUrl) + + FfiConverterString.allocationSize(value.roomId) + + FfiConverterString.allocationSize(value.slotId) + + FfiConverterString.allocationSize(value.memberJson) + + FfiConverterString.allocationSize(value.delayId) + + FfiConverterUInt64.allocationSize(value.delayTimeoutMs); + + } + }; + return new FFIConverter(); +})(); + export type FfiJoinParams = { applicationType: string, /** @@ -566,7 +646,17 @@ export type FfiJoinParams = { * Lifetime when the homeserver refuses delayed events (default 5 min). */ degradedLifetimeMs?: bigint, - delegateDelayedLeave: boolean + /** + * Hand the delayed leave to the SFU (MSC4195): the crate tries the + * homeserver, then the authorisation service, then keeps restarting the + * leave itself. + */ + delegateDelayedLeave: boolean, + /** + * The delay of the delegated leave (MSC4195 asks for ≥ 1 h); the short + * `keep_alive_timeout_ms` leave stays armed until delegation is confirmed. + */ + delegatedDelayMs: bigint } /** @@ -595,7 +685,8 @@ const FfiConverterTypeFfiJoinParams = (() => { stickyDurationMs: FfiConverterUInt64.readFromCursor(c), keepAliveTimeoutMs: FfiConverterUInt64.readFromCursor(c), degradedLifetimeMs: FfiConverterOptionalUInt64.readFromCursor(c), - delegateDelayedLeave: FfiConverterBool.readFromCursor(c) + delegateDelayedLeave: FfiConverterBool.readFromCursor(c), + delegatedDelayMs: FfiConverterUInt64.readFromCursor(c) }; } writeIntoCursor(value: TypeName, c: Cursor): void { @@ -605,6 +696,7 @@ const FfiConverterTypeFfiJoinParams = (() => { FfiConverterUInt64.writeIntoCursor(value.keepAliveTimeoutMs, c); FfiConverterOptionalUInt64.writeIntoCursor(value.degradedLifetimeMs, c); FfiConverterBool.writeIntoCursor(value.delegateDelayedLeave, c); + FfiConverterUInt64.writeIntoCursor(value.delegatedDelayMs, c); } allocationSize(value: TypeName): number { return FfiConverterString.allocationSize(value.applicationType) + @@ -612,7 +704,8 @@ const FfiConverterTypeFfiJoinParams = (() => { FfiConverterUInt64.allocationSize(value.stickyDurationMs) + FfiConverterUInt64.allocationSize(value.keepAliveTimeoutMs) + FfiConverterOptionalUInt64.allocationSize(value.degradedLifetimeMs) + - FfiConverterBool.allocationSize(value.delegateDelayedLeave); + FfiConverterBool.allocationSize(value.delegateDelayedLeave) + + FfiConverterUInt64.allocationSize(value.delegatedDelayMs); } }; @@ -915,7 +1008,13 @@ export type FfiMediaKeyState = { /** * Why their most recent key was discarded, while we still lack one. */ - rejection?: FfiKeyRejection + rejection?: FfiKeyRejection, + /** + * MSC4153: whether the device that sent the key we hold from them is + * cross-signed by its owner; `None` while we hold none or the host + * could not tell. Reported whether or not the check is enforced. + */ + senderCrossSigned?: boolean } /** @@ -941,18 +1040,21 @@ const FfiConverterTypeFfiMediaKeyState = (() => { return { holdsOurKey: FfiConverterBool.readFromCursor(c), haveTheirKey: FfiConverterBool.readFromCursor(c), - rejection: FfiConverterOptionalTypeFfiKeyRejection.readFromCursor(c) + rejection: FfiConverterOptionalTypeFfiKeyRejection.readFromCursor(c), + senderCrossSigned: FfiConverterOptionalBoolean.readFromCursor(c) }; } writeIntoCursor(value: TypeName, c: Cursor): void { FfiConverterBool.writeIntoCursor(value.holdsOurKey, c); FfiConverterBool.writeIntoCursor(value.haveTheirKey, c); FfiConverterOptionalTypeFfiKeyRejection.writeIntoCursor(value.rejection, c); + FfiConverterOptionalBoolean.writeIntoCursor(value.senderCrossSigned, c); } allocationSize(value: TypeName): number { return FfiConverterBool.allocationSize(value.holdsOurKey) + FfiConverterBool.allocationSize(value.haveTheirKey) + - FfiConverterOptionalTypeFfiKeyRejection.allocationSize(value.rejection); + FfiConverterOptionalTypeFfiKeyRejection.allocationSize(value.rejection) + + FfiConverterOptionalBoolean.allocationSize(value.senderCrossSigned); } }; @@ -1136,7 +1238,6 @@ const FfiConverterTypeFfiMembershipPublication = (() => { */ export enum FfiElementCallCompat { Off, - StickyEvents, StateEvents } @@ -1146,16 +1247,14 @@ const FfiConverterTypeFfiElementCallCompat = (() => { readFromCursor(c: Cursor): TypeName { switch (c.readI32()) { case 1: return FfiElementCallCompat.Off; - case 2: return FfiElementCallCompat.StickyEvents; - case 3: return FfiElementCallCompat.StateEvents; + case 2: return FfiElementCallCompat.StateEvents; default: throw new UniffiInternalError.UnexpectedEnumCase(); } } writeIntoCursor(value: TypeName, c: Cursor): void { switch (value) { case FfiElementCallCompat.Off: return c.writeI32(1); - case FfiElementCallCompat.StickyEvents: return c.writeI32(2); - case FfiElementCallCompat.StateEvents: return c.writeI32(3); + case FfiElementCallCompat.StateEvents: return c.writeI32(2); } } allocationSize(value: TypeName): number { @@ -1518,6 +1617,76 @@ const FfiConverterTypeFfiToDeviceDelivery = (() => { return new FFIConverter(); })(); +/** + * MSC4195 delay fields, sent to `{livekit_service_url}/get_token` (or + * `/sfu/get` with `legacy_sfu_get`). + */ +export type FfiTransportDelegationRequest = { + livekitServiceUrl: string, + roomId: string, + slotId: string, + /** + * MSC4195 member claims `{ id, claimed_user_id, claimed_device_id }`. + */ + memberJson: string, + delayId: string, + delayTimeoutMs: bigint, + legacySfuGet: boolean +} + +/** + * Generated factory for {@link FfiTransportDelegationRequest} record objects. + */ +export const FfiTransportDelegationRequest = (() => { + const defaults = () => ({ + }); + const create = (() => { + return uniffiCreateRecord>(defaults); + })(); + return Object.freeze({ + create, + new: create, + defaults: () => Object.freeze(defaults()) as Partial, + }); +})(); + +const FfiConverterTypeFfiTransportDelegationRequest = (() => { + type TypeName = FfiTransportDelegationRequest; + class FFIConverter extends AbstractFfiConverterByteArray { + readFromCursor(c: Cursor): TypeName { + return { + livekitServiceUrl: FfiConverterString.readFromCursor(c), + roomId: FfiConverterString.readFromCursor(c), + slotId: FfiConverterString.readFromCursor(c), + memberJson: FfiConverterString.readFromCursor(c), + delayId: FfiConverterString.readFromCursor(c), + delayTimeoutMs: FfiConverterUInt64.readFromCursor(c), + legacySfuGet: FfiConverterBool.readFromCursor(c) + }; + } + writeIntoCursor(value: TypeName, c: Cursor): void { + FfiConverterString.writeIntoCursor(value.livekitServiceUrl, c); + FfiConverterString.writeIntoCursor(value.roomId, c); + FfiConverterString.writeIntoCursor(value.slotId, c); + FfiConverterString.writeIntoCursor(value.memberJson, c); + FfiConverterString.writeIntoCursor(value.delayId, c); + FfiConverterUInt64.writeIntoCursor(value.delayTimeoutMs, c); + FfiConverterBool.writeIntoCursor(value.legacySfuGet, c); + } + allocationSize(value: TypeName): number { + return FfiConverterString.allocationSize(value.livekitServiceUrl) + + FfiConverterString.allocationSize(value.roomId) + + FfiConverterString.allocationSize(value.slotId) + + FfiConverterString.allocationSize(value.memberJson) + + FfiConverterString.allocationSize(value.delayId) + + FfiConverterUInt64.allocationSize(value.delayTimeoutMs) + + FfiConverterBool.allocationSize(value.legacySfuGet); + + } + }; + return new FFIConverter(); +})(); + /** * Which pump stopped, for [`FfiDisconnectCause::ManagerStopped`]. */ @@ -1591,6 +1760,43 @@ const FfiConverterTypeFfiDelayedLeaveOutcome = (() => { return new FFIConverter(); })(); +/** + * How the delayed leave was handed to the SFU (MSC4195). + */ +export enum FfiDelegationRoute { + /** + * The homeserver's CS API endpoint. + */ + Homeserver, + /** + * The authorisation service's token endpoint with the delay fields. + */ + AuthorisationService +} + +const FfiConverterTypeFfiDelegationRoute = (() => { + type TypeName = FfiDelegationRoute; + class FFIConverter extends AbstractFfiConverterByteArray { + readFromCursor(c: Cursor): TypeName { + switch (c.readI32()) { + case 1: return FfiDelegationRoute.Homeserver; + case 2: return FfiDelegationRoute.AuthorisationService; + default: throw new UniffiInternalError.UnexpectedEnumCase(); + } + } + writeIntoCursor(value: TypeName, c: Cursor): void { + switch (value) { + case FfiDelegationRoute.Homeserver: return c.writeI32(1); + case FfiDelegationRoute.AuthorisationService: return c.writeI32(2); + } + } + allocationSize(value: TypeName): number { + return 4; + } + } + return new FFIConverter(); +})(); + // Enum: FfiJoinError export enum FfiJoinError_Tags { @@ -3319,7 +3525,7 @@ inner: {delayMs: bigint; lastRestartTs: bigint; firesAtTs: bigint }): Armed_ { type Delegated__interface = { tag: FfiKeepAlive_Tags.Delegated; inner: -Readonly<{delegatedAtTs: bigint; earliestFireTs: bigint}> +Readonly<{delegatedAtTs: bigint; earliestFireTs: bigint; via: FfiDelegationRoute}> }; /** * Handed to the SFU (MSC4195): we no longer restart it, so a frozen @@ -3333,15 +3539,15 @@ Readonly<{delegatedAtTs: bigint; earliestFireTs: bigint}> readonly [uniffiTypeNameSymbol] = "FfiKeepAlive"; readonly tag = FfiKeepAlive_Tags.Delegated; readonly inner: -Readonly<{delegatedAtTs: bigint; earliestFireTs: bigint}>; +Readonly<{delegatedAtTs: bigint; earliestFireTs: bigint; via: FfiDelegationRoute}>; constructor( -inner: {delegatedAtTs: bigint; earliestFireTs: bigint }) { +inner: {delegatedAtTs: bigint; earliestFireTs: bigint; via: FfiDelegationRoute }) { super("FfiKeepAlive", "Delegated"); this.inner = Object.freeze(inner); } static new( -inner: {delegatedAtTs: bigint; earliestFireTs: bigint }): Delegated_ { +inner: {delegatedAtTs: bigint; earliestFireTs: bigint; via: FfiDelegationRoute }): Delegated_ { return new Delegated_(inner); } @@ -3485,7 +3691,7 @@ const FfiConverterTypeFfiKeepAlive = (() => { readFromCursor(c: Cursor): TypeName { switch (c.readI32()) { case 1: return new FfiKeepAlive.Armed({delayMs: FfiConverterUInt64.readFromCursor(c), lastRestartTs: FfiConverterUInt64.readFromCursor(c), firesAtTs: FfiConverterUInt64.readFromCursor(c) }); - case 2: return new FfiKeepAlive.Delegated({delegatedAtTs: FfiConverterUInt64.readFromCursor(c), earliestFireTs: FfiConverterUInt64.readFromCursor(c) }); + case 2: return new FfiKeepAlive.Delegated({delegatedAtTs: FfiConverterUInt64.readFromCursor(c), earliestFireTs: FfiConverterUInt64.readFromCursor(c), via: FfiConverterTypeFfiDelegationRoute.readFromCursor(c) }); case 3: return new FfiKeepAlive.RestartFailing({sinceTs: FfiConverterUInt64.readFromCursor(c), firesAtTs: FfiConverterUInt64.readFromCursor(c), lastError: FfiConverterString.readFromCursor(c) }); case 4: return new FfiKeepAlive.Expired({sinceTs: FfiConverterUInt64.readFromCursor(c) }); case 5: return new FfiKeepAlive.Unavailable({permanent: FfiConverterBool.readFromCursor(c), nextProbeTs: FfiConverterOptionalUInt64.readFromCursor(c) }); @@ -3507,6 +3713,7 @@ const FfiConverterTypeFfiKeepAlive = (() => { const inner = value.inner; FfiConverterUInt64.writeIntoCursor(inner.delegatedAtTs, c); FfiConverterUInt64.writeIntoCursor(inner.earliestFireTs, c); + FfiConverterTypeFfiDelegationRoute.writeIntoCursor(inner.via, c); return; } case FfiKeepAlive_Tags.RestartFailing: { @@ -3550,6 +3757,7 @@ const FfiConverterTypeFfiKeepAlive = (() => { let size = 4; size += FfiConverterUInt64.allocationSize(inner.delegatedAtTs); size += FfiConverterUInt64.allocationSize(inner.earliestFireTs); + size += FfiConverterTypeFfiDelegationRoute.allocationSize(inner.via); return size; } case FfiKeepAlive_Tags.RestartFailing: { @@ -5928,6 +6136,171 @@ const uniffiCallbackInterfaceMembershipsListener: { vtable: any; register: () => }, }; +export interface SessionListener { + +/** + * The room's view of the session changed (seed done, slot opened or + * closed, roster moved): what `session()` answers now. + */ + onSessionChange(session: FfiSessionSnapshot): void; +} + + +export class SessionListenerImpl extends UniffiAbstractObject implements SessionListener { + + readonly [uniffiTypeNameSymbol] = "SessionListenerImpl"; + readonly [destructorGuardSymbol]: UniffiGcObject; + readonly [pointerLiteralSymbol]: UniffiHandle; + // No primary constructor declared for this class. +private constructor(pointer: UniffiHandle) { + super(); + this[pointerLiteralSymbol] = pointer; + this[destructorGuardSymbol] = uniffiTypeSessionListenerImplObjectFactory.bless(pointer); +} + + + + +/** + * The room's view of the session changed (seed done, slot opened or + * closed, roster moved): what `session()` answers now. + */ + onSessionChange(session: FfiSessionSnapshot): void {uniffiCaller.rustCall( + /*caller:*/ (callStatus) => { nativeModule().ubrn_uniffi_matrix_rtc_fn_method_sessionlistener_on_session_change( + uniffiTypeSessionListenerImplObjectFactory.clonePointer(this), + FfiConverterTypeFfiSessionSnapshot.lower(session, nativeModule().rustbuffer_alloc), + callStatus); + }, + /*liftString:*/ FfiConverterString.lift.bind(FfiConverterString), + ); + } + + + uniffiDestroy(): void { + const ptr = (this as any)[destructorGuardSymbol]; + if (ptr !== undefined) { + const pointer = uniffiTypeSessionListenerImplObjectFactory.pointer(this); + uniffiTypeSessionListenerImplObjectFactory.freePointer(pointer); + uniffiTypeSessionListenerImplObjectFactory.unbless(ptr); + delete (this as any)[destructorGuardSymbol]; + } + } + + static instanceOf(obj_: any): obj_ is SessionListenerImpl { + return uniffiTypeSessionListenerImplObjectFactory.isConcreteType(obj_); + } + + +} + +const uniffiTypeSessionListenerImplObjectFactory: UniffiObjectFactory = (() => { + + /// + const registry = typeof FinalizationRegistry !== 'undefined' ? new FinalizationRegistry((heldValue: UniffiHandle) => { + uniffiTypeSessionListenerImplObjectFactory.freePointer(heldValue); + }) : null; + + return { + create(pointer: UniffiHandle): SessionListener { + const instance = Object.create(SessionListenerImpl.prototype); + instance[pointerLiteralSymbol] = pointer; + instance[destructorGuardSymbol] = this.bless(pointer); + instance[uniffiTypeNameSymbol] = "SessionListenerImpl"; + return instance; + }, + + + bless(p: UniffiHandle): UniffiGcObject { + const ptr = { + p, // make sure this object doesn't get optimized away. + markDestroyed: () => undefined, + }; + if (registry) { + registry.register(ptr, p, ptr); + } + return ptr; + }, + + unbless(ptr_: UniffiGcObject) { + if (registry) { + registry.unregister(ptr_); + } + }, + + pointer(obj_: SessionListener): UniffiHandle { + if ((obj_ as any)[destructorGuardSymbol] === undefined) { + throw new UniffiInternalError.UnexpectedNullPointer(); + } + return (obj_ as any)[pointerLiteralSymbol]; + }, + + clonePointer(obj_: SessionListener): UniffiHandle { + const pointer = this.pointer(obj_); + return uniffiCaller.rustCall( + /*caller:*/ (callStatus) => nativeModule().ubrn_uniffi_matrix_rtc_fn_clone_sessionlistener(pointer, callStatus), + /*liftString:*/ FfiConverterString.lift + ); + }, + + freePointer(pointer: UniffiHandle): void { + uniffiCaller.rustCall( + /*caller:*/ (callStatus) => nativeModule().ubrn_uniffi_matrix_rtc_fn_free_sessionlistener(pointer, callStatus), + /*liftString:*/ FfiConverterString.lift + ); + }, + + isConcreteType(obj_: any): obj_ is SessionListener { + return obj_[destructorGuardSymbol] && obj_[uniffiTypeNameSymbol] === "SessionListenerImpl"; + }, +}})(); +const FfiConverterTypeSessionListener = new FfiConverterObjectWithCallbacks(uniffiTypeSessionListenerImplObjectFactory); + +// Add a vtable for the callbacks that go in SessionListener. + +// Put the implementation in a struct so we don't pollute the top-level namespace +const uniffiCallbackInterfaceSessionListener: { vtable: any; register: () => void; } = { + // Create the VTable using a series of closures. + // ts automatically converts these into C callback functions. + vtable: { + on_session_change: ( + uniffiHandle: bigint, + session: Uint8Array,) => { + const uniffiMakeCall = + () + : void => { + const jsCallback = FfiConverterTypeSessionListener.lift(uniffiHandle); + return jsCallback.onSessionChange( + FfiConverterTypeFfiSessionSnapshot.lift(session) + ) + }; + const uniffiResult = UniffiResult.ready(); + const uniffiHandleSuccess = (obj: any) => {}; + const uniffiHandleError = (code: number, errBuf: UniffiByteArray) => { + UniffiResult.writeError(uniffiResult, code, errBuf); + }; + uniffiTraitInterfaceCall( + /*makeCall:*/ uniffiMakeCall, + /*handleSuccess:*/ uniffiHandleSuccess, + /*handleError:*/ uniffiHandleError, + /*lowerString:*/ FfiConverterString.lower.bind(FfiConverterString), + /*alloc:*/ nativeModule().rustbuffer_alloc, + ) + return uniffiResult; + }, + uniffi_free: (uniffiHandle: UniffiHandle): void => { + // this will throw a stale handle error if the handle isn't found. + FfiConverterTypeSessionListener.drop(uniffiHandle); + }, + uniffi_clone: (uniffiHandle: UniffiHandle): UniffiHandle => { + return FfiConverterTypeSessionListener.clone(uniffiHandle); + } + }, + register: () => {nativeModule().ubrn_uniffi_matrix_rtc_fn_init_callback_vtable_sessionlistener( + uniffiCallbackInterfaceSessionListener.vtable + ); + }, +}; + export interface StatusListener { onStatusChange(status: FfiStatus): void; @@ -6150,6 +6523,7 @@ export interface FfiParticipationManagerLike { setKeyMapListener(listener: KeyMapListener): void; setKeyRejectedListener(listener: KeyRejectedListener): void; setMembershipsListener(listener: MembershipsListener): void; + setSessionListener(listener: SessionListener): void; setStatusListener(listener: StatusListener): void; status(): FfiStatus; /** @@ -6513,6 +6887,16 @@ export class FfiParticipationManager extends UniffiAbstractObject implements Ffi ); } + setSessionListener(listener: SessionListener): void {uniffiCaller.rustCall( + /*caller:*/ (callStatus) => { nativeModule().ubrn_uniffi_matrix_rtc_fn_method_ffiparticipationmanager_set_session_listener( + uniffiTypeFfiParticipationManagerObjectFactory.clonePointer(this), + FfiConverterTypeSessionListener.lower(listener, nativeModule().rustbuffer_alloc), + callStatus); + }, + /*liftString:*/ FfiConverterString.lift.bind(FfiConverterString), + ); + } + setStatusListener(listener: StatusListener): void {uniffiCaller.rustCall( /*caller:*/ (callStatus) => { nativeModule().ubrn_uniffi_matrix_rtc_fn_method_ffiparticipationmanager_set_status_listener( uniffiTypeFfiParticipationManagerObjectFactory.clonePointer(this), @@ -7082,8 +7466,21 @@ export interface MatrixDriverCallback { * the transport we publish on (`None` for a receive-only member) and * `delay_ms` the armed delay — what an adapter that delegates through * the authorisation service's token endpoint needs. + * MSC4195 via the homeserver: one authenticated + * `POST /_matrix/client/unstable/io.element.msc4195/rtc/livekit/delegate_delayed_leave` + * with `{ url, room_id, slot_id, member, delay_id, delay_timeout }` (see + * `FfiHomeserverDelegationRequest`). A client that cannot make + * authenticated homeserver calls (a widget) throws `Unsupported`; the + * crate then tries the authorisation service. */ - delegateLivekitDelayedLeave(roomId: string, slotId: string, memberJson: string, delayId: string, livekitServiceUrl: string | undefined, delayMs: bigint, asyncOpts_?: { signal: AbortSignal }) /*throws*/: Promise; + delegateDelayedLeaveViaHomeserver(request: FfiHomeserverDelegationRequest, asyncOpts_?: { signal: AbortSignal }) /*throws*/: Promise; +/** + * MSC4195 via the authorisation service: the `get_token` (or, with + * `legacy_sfu_get`, `sfu/get`) request the adapter already makes, with + * `delay_id`, `delay_timeout` (= `delay_timeout_ms`) and the adapter's + * own CS API URL (`delay_cs_api_url`) added. Discard the token. + */ + delegateDelayedLeaveViaTransport(request: FfiTransportDelegationRequest, asyncOpts_?: { signal: AbortSignal }) /*throws*/: Promise; sendToDevice(recipients: Array, eventType: string, contentJson: string, asyncOpts_?: { signal: AbortSignal }) /*throws*/: Promise>; /** * `GET /_matrix/client/v1/rtc/transports`, with well-known fallback. @@ -7340,13 +7737,44 @@ private constructor(pointer: UniffiHandle) { * the transport we publish on (`None` for a receive-only member) and * `delay_ms` the armed delay — what an adapter that delegates through * the authorisation service's token endpoint needs. + * MSC4195 via the homeserver: one authenticated + * `POST /_matrix/client/unstable/io.element.msc4195/rtc/livekit/delegate_delayed_leave` + * with `{ url, room_id, slot_id, member, delay_id, delay_timeout }` (see + * `FfiHomeserverDelegationRequest`). A client that cannot make + * authenticated homeserver calls (a widget) throws `Unsupported`; the + * crate then tries the authorisation service. */ - async delegateLivekitDelayedLeave(roomId: string, slotId: string, memberJson: string, delayId: string, livekitServiceUrl: string | undefined, delayMs: bigint, asyncOpts_?: { signal: AbortSignal }): Promise /*throws*/ { + async delegateDelayedLeaveViaHomeserver(request: FfiHomeserverDelegationRequest, asyncOpts_?: { signal: AbortSignal }): Promise /*throws*/ { return await uniffiRustCallAsync( /*rustCaller:*/ uniffiCaller, /*rustFutureFunc:*/ () => { - return nativeModule().ubrn_uniffi_matrix_rtc_fn_method_matrixdrivercallback_delegate_livekit_delayed_leave( - uniffiTypeMatrixDriverCallbackImplObjectFactory.clonePointer(this),FfiConverterString.lower(roomId, nativeModule().rustbuffer_alloc),FfiConverterString.lower(slotId, nativeModule().rustbuffer_alloc),FfiConverterString.lower(memberJson, nativeModule().rustbuffer_alloc),FfiConverterString.lower(delayId, nativeModule().rustbuffer_alloc),FfiConverterOptionalString.lower(livekitServiceUrl, nativeModule().rustbuffer_alloc),FfiConverterUInt64.lower(delayMs, nativeModule().rustbuffer_alloc) + return nativeModule().ubrn_uniffi_matrix_rtc_fn_method_matrixdrivercallback_delegate_delayed_leave_via_homeserver( + uniffiTypeMatrixDriverCallbackImplObjectFactory.clonePointer(this),FfiConverterTypeFfiHomeserverDelegationRequest.lower(request, nativeModule().rustbuffer_alloc) + ); + }, + /*pollFunc:*/ nativeModule().ubrn_ffi_matrix_rtc_rust_future_poll_void, + /*cancelFunc:*/ nativeModule().ubrn_ffi_matrix_rtc_rust_future_cancel_void, + /*completeFunc:*/ nativeModule().ubrn_ffi_matrix_rtc_rust_future_complete_void, + /*freeFunc:*/ nativeModule().ubrn_ffi_matrix_rtc_rust_future_free_void, + /*liftFunc:*/ (_v) => {}, + /*liftString:*/ FfiConverterString.lift.bind(FfiConverterString), + /*asyncOpts:*/ asyncOpts_, + /*errorHandler:*/ FfiConverterTypeRtcError.lift.bind(FfiConverterTypeRtcError) + ); + } + +/** + * MSC4195 via the authorisation service: the `get_token` (or, with + * `legacy_sfu_get`, `sfu/get`) request the adapter already makes, with + * `delay_id`, `delay_timeout` (= `delay_timeout_ms`) and the adapter's + * own CS API URL (`delay_cs_api_url`) added. Discard the token. + */ + async delegateDelayedLeaveViaTransport(request: FfiTransportDelegationRequest, asyncOpts_?: { signal: AbortSignal }): Promise /*throws*/ { + return await uniffiRustCallAsync( + /*rustCaller:*/ uniffiCaller, + /*rustFutureFunc:*/ () => { + return nativeModule().ubrn_uniffi_matrix_rtc_fn_method_matrixdrivercallback_delegate_delayed_leave_via_transport( + uniffiTypeMatrixDriverCallbackImplObjectFactory.clonePointer(this),FfiConverterTypeFfiTransportDelegationRequest.lower(request, nativeModule().rustbuffer_alloc) ); }, /*pollFunc:*/ nativeModule().ubrn_ffi_matrix_rtc_rust_future_poll_void, @@ -7992,27 +8420,60 @@ const uniffiCallbackInterfaceMatrixDriverCallback: { vtable: any; register: () = ); return uniffiForeignFuture; }, - delegate_livekit_delayed_leave: ( + delegate_delayed_leave_via_homeserver: ( uniffiHandle: bigint, - roomId: Uint8Array, - slotId: Uint8Array, - memberJson: Uint8Array, - delayId: Uint8Array, - livekitServiceUrl: Uint8Array, - delayMs: bigint, + request: Uint8Array, uniffiFutureCallback: UniffiForeignFutureCompletevoid, uniffiCallbackData: bigint) => { const uniffiMakeCall = async (signal: AbortSignal) : Promise => { const jsCallback = FfiConverterTypeMatrixDriverCallback.lift(uniffiHandle); - return await jsCallback.delegateLivekitDelayedLeave( - FfiConverterString.lift(roomId), - FfiConverterString.lift(slotId), - FfiConverterString.lift(memberJson), - FfiConverterString.lift(delayId), - FfiConverterOptionalString.lift(livekitServiceUrl), - FfiConverterUInt64.lift(delayMs), { signal } + return await jsCallback.delegateDelayedLeaveViaHomeserver( + FfiConverterTypeFfiHomeserverDelegationRequest.lift(request), { signal } + ) + }; + const uniffiHandleSuccess = (returnValue: void) => { + uniffiFutureCallback.call( + uniffiFutureCallback, + uniffiCallbackData, + /* UniffiForeignFutureResultVoid */{ + call_status: uniffiCaller.createCallStatus() + } + ); + }; + const uniffiHandleError = (code: number, errorBuf: UniffiByteArray) => { + uniffiFutureCallback.call( + uniffiFutureCallback, + uniffiCallbackData, + /* UniffiForeignFutureResultVoid */{ + // TODO create callstatus with error. + call_status: uniffiCaller.createErrorStatus(code, errorBuf), + } + ); + }; + const uniffiForeignFuture = uniffiTraitInterfaceCallAsyncWithError( + /*makeCall:*/ uniffiMakeCall, + /*handleSuccess:*/ uniffiHandleSuccess, + /*handleError:*/ uniffiHandleError, + /*isErrorType:*/ RtcError.instanceOf, + /*lowerError:*/ FfiConverterTypeRtcError.lower.bind(FfiConverterTypeRtcError), + /*lowerString:*/ FfiConverterString.lower.bind(FfiConverterString), + /*alloc:*/ nativeModule().rustbuffer_alloc, + ); + return uniffiForeignFuture; + }, + delegate_delayed_leave_via_transport: ( + uniffiHandle: bigint, + request: Uint8Array, + uniffiFutureCallback: UniffiForeignFutureCompletevoid, + uniffiCallbackData: bigint) => { + const uniffiMakeCall = + async (signal: AbortSignal) + : Promise => { + const jsCallback = FfiConverterTypeMatrixDriverCallback.lift(uniffiHandle); + return await jsCallback.delegateDelayedLeaveViaTransport( + FfiConverterTypeFfiTransportDelegationRequest.lift(request), { signal } ) }; const uniffiHandleSuccess = (returnValue: void) => { @@ -8435,12 +8896,12 @@ const FfiConverterSequenceTypeFfiMember = new FfiConverterArray(FfiConverterType // FfiConverter for FfiKeyRejection | undefined const FfiConverterOptionalTypeFfiKeyRejection = new FfiConverterOptional(FfiConverterTypeFfiKeyRejection); -// FfiConverter for FfiMediaKeyState | undefined -const FfiConverterOptionalTypeFfiMediaKeyState = new FfiConverterOptional(FfiConverterTypeFfiMediaKeyState); - // FfiConverter for boolean | undefined const FfiConverterOptionalBoolean = new FfiConverterOptional(FfiConverterBool); +// FfiConverter for FfiMediaKeyState | undefined +const FfiConverterOptionalTypeFfiMediaKeyState = new FfiConverterOptional(FfiConverterTypeFfiMediaKeyState); + // FfiConverter for Array const FfiConverterSequenceTypeFfiSessionRead = new FfiConverterArray(FfiConverterTypeFfiSessionRead); @@ -8568,6 +9029,9 @@ function uniffiEnsureInitialized() { if (nativeModule().ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_set_memberships_listener() !== 46727) { throw new UniffiInternalError.ApiChecksumMismatch("uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_set_memberships_listener"); } + if (nativeModule().ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_set_session_listener() !== 784) { + throw new UniffiInternalError.ApiChecksumMismatch("uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_set_session_listener"); + } if (nativeModule().ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_set_status_listener() !== 8439) { throw new UniffiInternalError.ApiChecksumMismatch("uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_set_status_listener"); } @@ -8601,37 +9065,40 @@ function uniffiEnsureInitialized() { if (nativeModule().ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_cancel_delayed_event() !== 48021) { throw new UniffiInternalError.ApiChecksumMismatch("uniffi_matrix_rtc_checksum_method_matrixdrivercallback_cancel_delayed_event"); } - if (nativeModule().ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_delegate_livekit_delayed_leave() !== 31950) { - throw new UniffiInternalError.ApiChecksumMismatch("uniffi_matrix_rtc_checksum_method_matrixdrivercallback_delegate_livekit_delayed_leave"); + if (nativeModule().ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_delegate_delayed_leave_via_homeserver() !== 43539) { + throw new UniffiInternalError.ApiChecksumMismatch("uniffi_matrix_rtc_checksum_method_matrixdrivercallback_delegate_delayed_leave_via_homeserver"); } - if (nativeModule().ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_send_to_device() !== 29274) { + if (nativeModule().ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_delegate_delayed_leave_via_transport() !== 6420) { + throw new UniffiInternalError.ApiChecksumMismatch("uniffi_matrix_rtc_checksum_method_matrixdrivercallback_delegate_delayed_leave_via_transport"); + } + if (nativeModule().ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_send_to_device() !== 43316) { throw new UniffiInternalError.ApiChecksumMismatch("uniffi_matrix_rtc_checksum_method_matrixdrivercallback_send_to_device"); } - if (nativeModule().ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_get_rtc_transports() !== 55674) { + if (nativeModule().ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_get_rtc_transports() !== 33640) { throw new UniffiInternalError.ApiChecksumMismatch("uniffi_matrix_rtc_checksum_method_matrixdrivercallback_get_rtc_transports"); } - if (nativeModule().ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_get_livekit_token() !== 36238) { + if (nativeModule().ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_get_livekit_token() !== 25518) { throw new UniffiInternalError.ApiChecksumMismatch("uniffi_matrix_rtc_checksum_method_matrixdrivercallback_get_livekit_token"); } - if (nativeModule().ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_read_events() !== 18104) { + if (nativeModule().ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_read_events() !== 28203) { throw new UniffiInternalError.ApiChecksumMismatch("uniffi_matrix_rtc_checksum_method_matrixdrivercallback_read_events"); } - if (nativeModule().ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_read_state() !== 58428) { + if (nativeModule().ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_read_state() !== 63481) { throw new UniffiInternalError.ApiChecksumMismatch("uniffi_matrix_rtc_checksum_method_matrixdrivercallback_read_state"); } - if (nativeModule().ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_subscribe_room_events() !== 31129) { + if (nativeModule().ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_subscribe_room_events() !== 8803) { throw new UniffiInternalError.ApiChecksumMismatch("uniffi_matrix_rtc_checksum_method_matrixdrivercallback_subscribe_room_events"); } - if (nativeModule().ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_subscribe_to_device_events() !== 55587) { + if (nativeModule().ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_subscribe_to_device_events() !== 45060) { throw new UniffiInternalError.ApiChecksumMismatch("uniffi_matrix_rtc_checksum_method_matrixdrivercallback_subscribe_to_device_events"); } - if (nativeModule().ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_subscribe_state_updates() !== 53493) { + if (nativeModule().ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_subscribe_state_updates() !== 58784) { throw new UniffiInternalError.ApiChecksumMismatch("uniffi_matrix_rtc_checksum_method_matrixdrivercallback_subscribe_state_updates"); } - if (nativeModule().ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_is_homeserver_connected() !== 28631) { + if (nativeModule().ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_is_homeserver_connected() !== 56819) { throw new UniffiInternalError.ApiChecksumMismatch("uniffi_matrix_rtc_checksum_method_matrixdrivercallback_is_homeserver_connected"); } - if (nativeModule().ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_subscribe_connectivity() !== 46098) { + if (nativeModule().ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_subscribe_connectivity() !== 55109) { throw new UniffiInternalError.ApiChecksumMismatch("uniffi_matrix_rtc_checksum_method_matrixdrivercallback_subscribe_connectivity"); } if (nativeModule().ubrn_uniffi_matrix_rtc_checksum_method_membershipslistener_on_memberships_change() !== 29319) { @@ -8640,6 +9107,9 @@ function uniffiEnsureInitialized() { if (nativeModule().ubrn_uniffi_matrix_rtc_checksum_method_roomeventsink_emit() !== 34604) { throw new UniffiInternalError.ApiChecksumMismatch("uniffi_matrix_rtc_checksum_method_roomeventsink_emit"); } + if (nativeModule().ubrn_uniffi_matrix_rtc_checksum_method_sessionlistener_on_session_change() !== 30825) { + throw new UniffiInternalError.ApiChecksumMismatch("uniffi_matrix_rtc_checksum_method_sessionlistener_on_session_change"); + } if (nativeModule().ubrn_uniffi_matrix_rtc_checksum_method_stateupdatesink_emit() !== 7988) { throw new UniffiInternalError.ApiChecksumMismatch("uniffi_matrix_rtc_checksum_method_stateupdatesink_emit"); } @@ -8654,6 +9124,7 @@ function uniffiEnsureInitialized() { uniffiCallbackInterfaceKeyMapListener.register(); uniffiCallbackInterfaceKeyRejectedListener.register(); uniffiCallbackInterfaceMembershipsListener.register(); + uniffiCallbackInterfaceSessionListener.register(); uniffiCallbackInterfaceStatusListener.register(); uniffiCallbackInterfaceMatrixDriverCallback.register(); } @@ -8669,12 +9140,14 @@ export default Object.freeze({ FfiConverterTypeFfiConnectionProblemKind, FfiConverterTypeFfiConnectionWithMembers, FfiConverterTypeFfiDelayedLeaveOutcome, + FfiConverterTypeFfiDelegationRoute, FfiConverterTypeFfiDeviceAttribution, FfiConverterTypeFfiDisconnectCause, FfiConverterTypeFfiElementCallCompat, FfiConverterTypeFfiEncryptionStatus, FfiConverterTypeFfiEventOrigin, FfiConverterTypeFfiExcludedCandidate, + FfiConverterTypeFfiHomeserverDelegationRequest, FfiConverterTypeFfiImpairment, FfiConverterTypeFfiJoinError, FfiConverterTypeFfiJoinExclusionReason, @@ -8702,6 +9175,7 @@ export default Object.freeze({ FfiConverterTypeFfiStatus, FfiConverterTypeFfiToDeviceDelivery, FfiConverterTypeFfiToDeviceRecipient, + FfiConverterTypeFfiTransportDelegationRequest, FfiConverterTypeFfiTransportIntent, FfiConverterTypeKeyMapListener, FfiConverterTypeKeyRejectedListener, @@ -8709,6 +9183,7 @@ export default Object.freeze({ FfiConverterTypeMembershipsListener, FfiConverterTypeRoomEventSink, FfiConverterTypeRtcError, + FfiConverterTypeSessionListener, FfiConverterTypeStateUpdateSink, FfiConverterTypeStatusListener, FfiConverterTypeToDeviceSink, diff --git a/src/matrix-rtc-sdk/generated/wasm-bindgen/index.js b/src/matrix-rtc-sdk/generated/wasm-bindgen/index.js index 3692c76d9..b221ba0b5 100644 --- a/src/matrix-rtc-sdk/generated/wasm-bindgen/index.js +++ b/src/matrix-rtc-sdk/generated/wasm-bindgen/index.js @@ -146,6 +146,19 @@ export function ubrn_uniffi_matrix_rtc_fn_method_ffiparticipationmanager_own_mem return v1; } +/** + * @param {bigint} ptr + * @param {RustCallStatus} f_status_ + * @returns {Uint8Array} + */ +export function ubrn_uniffi_matrix_rtc_fn_method_ffiparticipationmanager_status(ptr, f_status_) { + _assertClass(f_status_, RustCallStatus); + const ret = wasm.ubrn_uniffi_matrix_rtc_fn_method_ffiparticipationmanager_status(ptr, f_status_.__wbg_ptr); + var v1 = getArrayU8FromWasm0(ret[0], ret[1]).slice(); + wasm.__wbindgen_free(ret[0], ret[1] * 1, 1); + return v1; +} + /** * @param {bigint} ptr * @param {Uint8Array} intent @@ -227,21 +240,6 @@ export function ubrn_uniffi_matrix_rtc_fn_init_callback_vtable_keyrejectedlisten wasm.ubrn_uniffi_matrix_rtc_fn_init_callback_vtable_keyrejectedlistener(vtable); } -/** - * @param {bigint} ptr - * @param {Uint8Array} member_id - * @param {Uint8Array} reason - * @param {RustCallStatus} f_status_ - */ -export function ubrn_uniffi_matrix_rtc_fn_method_keyrejectedlistener_on_key_rejected(ptr, member_id, reason, f_status_) { - const ptr0 = passArray8ToWasm0(member_id, wasm.__wbindgen_malloc); - const len0 = WASM_VECTOR_LEN; - const ptr1 = passArray8ToWasm0(reason, wasm.__wbindgen_malloc); - const len1 = WASM_VECTOR_LEN; - _assertClass(f_status_, RustCallStatus); - wasm.ubrn_uniffi_matrix_rtc_fn_method_keyrejectedlistener_on_key_rejected(ptr, ptr0, len0, ptr1, len1, f_status_.__wbg_ptr); -} - /** * @param {bigint} ptr * @param {RustCallStatus} f_status_ @@ -321,6 +319,16 @@ export function ubrn_uniffi_matrix_rtc_fn_method_ffiparticipationmanager_set_mem wasm.ubrn_uniffi_matrix_rtc_fn_method_ffiparticipationmanager_set_memberships_listener(ptr, listener, f_status_.__wbg_ptr); } +/** + * @param {bigint} ptr + * @param {bigint} listener + * @param {RustCallStatus} f_status_ + */ +export function ubrn_uniffi_matrix_rtc_fn_method_ffiparticipationmanager_set_session_listener(ptr, listener, f_status_) { + _assertClass(f_status_, RustCallStatus); + wasm.ubrn_uniffi_matrix_rtc_fn_method_ffiparticipationmanager_set_session_listener(ptr, listener, f_status_.__wbg_ptr); +} + /** * @param {bigint} ptr * @param {bigint} listener @@ -333,15 +341,17 @@ export function ubrn_uniffi_matrix_rtc_fn_method_ffiparticipationmanager_set_sta /** * @param {bigint} ptr + * @param {Uint8Array} member_id + * @param {Uint8Array} reason * @param {RustCallStatus} f_status_ - * @returns {Uint8Array} */ -export function ubrn_uniffi_matrix_rtc_fn_method_ffiparticipationmanager_status(ptr, f_status_) { +export function ubrn_uniffi_matrix_rtc_fn_method_keyrejectedlistener_on_key_rejected(ptr, member_id, reason, f_status_) { + const ptr0 = passArray8ToWasm0(member_id, wasm.__wbindgen_malloc); + const len0 = WASM_VECTOR_LEN; + const ptr1 = passArray8ToWasm0(reason, wasm.__wbindgen_malloc); + const len1 = WASM_VECTOR_LEN; _assertClass(f_status_, RustCallStatus); - const ret = wasm.ubrn_uniffi_matrix_rtc_fn_method_ffiparticipationmanager_status(ptr, f_status_.__wbg_ptr); - var v1 = getArrayU8FromWasm0(ret[0], ret[1]).slice(); - wasm.__wbindgen_free(ret[0], ret[1] * 1, 1); - return v1; + wasm.ubrn_uniffi_matrix_rtc_fn_method_keyrejectedlistener_on_key_rejected(ptr, ptr0, len0, ptr1, len1, f_status_.__wbg_ptr); } /** @@ -365,10 +375,30 @@ export function ubrn_uniffi_matrix_rtc_fn_free_matrixdrivercallback(handle, f_st } /** - * @param {any} vtable + * @param {bigint} ptr + * @param {Uint8Array} recipients + * @param {Uint8Array} event_type + * @param {Uint8Array} content_json + * @returns {bigint} */ -export function ubrn_uniffi_matrix_rtc_fn_init_callback_vtable_matrixdrivercallback(vtable) { - wasm.ubrn_uniffi_matrix_rtc_fn_init_callback_vtable_matrixdrivercallback(vtable); +export function ubrn_uniffi_matrix_rtc_fn_method_matrixdrivercallback_send_to_device(ptr, recipients, event_type, content_json) { + const ptr0 = passArray8ToWasm0(recipients, wasm.__wbindgen_malloc); + const len0 = WASM_VECTOR_LEN; + const ptr1 = passArray8ToWasm0(event_type, wasm.__wbindgen_malloc); + const len1 = WASM_VECTOR_LEN; + const ptr2 = passArray8ToWasm0(content_json, wasm.__wbindgen_malloc); + const len2 = WASM_VECTOR_LEN; + const ret = wasm.ubrn_uniffi_matrix_rtc_fn_method_matrixdrivercallback_send_to_device(ptr, ptr0, len0, ptr1, len1, ptr2, len2); + return BigInt.asUintN(64, ret); +} + +/** + * @param {bigint} ptr + * @returns {bigint} + */ +export function ubrn_uniffi_matrix_rtc_fn_method_matrixdrivercallback_get_rtc_transports(ptr) { + const ret = wasm.ubrn_uniffi_matrix_rtc_fn_method_matrixdrivercallback_get_rtc_transports(ptr); + return BigInt.asUintN(64, ret); } /** @@ -445,24 +475,10 @@ export function ubrn_uniffi_matrix_rtc_fn_method_matrixdrivercallback_subscribe_ } /** - * @param {bigint} ptr - * @param {RustCallStatus} f_status_ - * @returns {number} + * @param {any} vtable */ -export function ubrn_uniffi_matrix_rtc_fn_method_matrixdrivercallback_is_homeserver_connected(ptr, f_status_) { - _assertClass(f_status_, RustCallStatus); - const ret = wasm.ubrn_uniffi_matrix_rtc_fn_method_matrixdrivercallback_is_homeserver_connected(ptr, f_status_.__wbg_ptr); - return ret; -} - -/** - * @param {bigint} ptr - * @param {bigint} sink - * @param {RustCallStatus} f_status_ - */ -export function ubrn_uniffi_matrix_rtc_fn_method_matrixdrivercallback_subscribe_connectivity(ptr, sink, f_status_) { - _assertClass(f_status_, RustCallStatus); - wasm.ubrn_uniffi_matrix_rtc_fn_method_matrixdrivercallback_subscribe_connectivity(ptr, sink, f_status_.__wbg_ptr); +export function ubrn_uniffi_matrix_rtc_fn_init_callback_vtable_matrixdrivercallback(vtable) { + wasm.ubrn_uniffi_matrix_rtc_fn_init_callback_vtable_matrixdrivercallback(vtable); } /** @@ -581,54 +597,47 @@ export function ubrn_uniffi_matrix_rtc_fn_method_matrixdrivercallback_cancel_del /** * @param {bigint} ptr - * @param {Uint8Array} room_id - * @param {Uint8Array} slot_id - * @param {Uint8Array} member_json - * @param {Uint8Array} delay_id - * @param {Uint8Array} livekit_service_url - * @param {bigint} delay_ms + * @param {Uint8Array} request * @returns {bigint} */ -export function ubrn_uniffi_matrix_rtc_fn_method_matrixdrivercallback_delegate_livekit_delayed_leave(ptr, room_id, slot_id, member_json, delay_id, livekit_service_url, delay_ms) { - const ptr0 = passArray8ToWasm0(room_id, wasm.__wbindgen_malloc); +export function ubrn_uniffi_matrix_rtc_fn_method_matrixdrivercallback_delegate_delayed_leave_via_homeserver(ptr, request) { + const ptr0 = passArray8ToWasm0(request, wasm.__wbindgen_malloc); const len0 = WASM_VECTOR_LEN; - const ptr1 = passArray8ToWasm0(slot_id, wasm.__wbindgen_malloc); - const len1 = WASM_VECTOR_LEN; - const ptr2 = passArray8ToWasm0(member_json, wasm.__wbindgen_malloc); - const len2 = WASM_VECTOR_LEN; - const ptr3 = passArray8ToWasm0(delay_id, wasm.__wbindgen_malloc); - const len3 = WASM_VECTOR_LEN; - const ptr4 = passArray8ToWasm0(livekit_service_url, wasm.__wbindgen_malloc); - const len4 = WASM_VECTOR_LEN; - const ret = wasm.ubrn_uniffi_matrix_rtc_fn_method_matrixdrivercallback_delegate_livekit_delayed_leave(ptr, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, ptr4, len4, delay_ms); + const ret = wasm.ubrn_uniffi_matrix_rtc_fn_method_matrixdrivercallback_delegate_delayed_leave_via_homeserver(ptr, ptr0, len0); return BigInt.asUintN(64, ret); } /** * @param {bigint} ptr - * @param {Uint8Array} recipients - * @param {Uint8Array} event_type - * @param {Uint8Array} content_json + * @param {Uint8Array} request * @returns {bigint} */ -export function ubrn_uniffi_matrix_rtc_fn_method_matrixdrivercallback_send_to_device(ptr, recipients, event_type, content_json) { - const ptr0 = passArray8ToWasm0(recipients, wasm.__wbindgen_malloc); +export function ubrn_uniffi_matrix_rtc_fn_method_matrixdrivercallback_delegate_delayed_leave_via_transport(ptr, request) { + const ptr0 = passArray8ToWasm0(request, wasm.__wbindgen_malloc); const len0 = WASM_VECTOR_LEN; - const ptr1 = passArray8ToWasm0(event_type, wasm.__wbindgen_malloc); - const len1 = WASM_VECTOR_LEN; - const ptr2 = passArray8ToWasm0(content_json, wasm.__wbindgen_malloc); - const len2 = WASM_VECTOR_LEN; - const ret = wasm.ubrn_uniffi_matrix_rtc_fn_method_matrixdrivercallback_send_to_device(ptr, ptr0, len0, ptr1, len1, ptr2, len2); + const ret = wasm.ubrn_uniffi_matrix_rtc_fn_method_matrixdrivercallback_delegate_delayed_leave_via_transport(ptr, ptr0, len0); return BigInt.asUintN(64, ret); } /** * @param {bigint} ptr - * @returns {bigint} + * @param {RustCallStatus} f_status_ + * @returns {number} */ -export function ubrn_uniffi_matrix_rtc_fn_method_matrixdrivercallback_get_rtc_transports(ptr) { - const ret = wasm.ubrn_uniffi_matrix_rtc_fn_method_matrixdrivercallback_get_rtc_transports(ptr); - return BigInt.asUintN(64, ret); +export function ubrn_uniffi_matrix_rtc_fn_method_matrixdrivercallback_is_homeserver_connected(ptr, f_status_) { + _assertClass(f_status_, RustCallStatus); + const ret = wasm.ubrn_uniffi_matrix_rtc_fn_method_matrixdrivercallback_is_homeserver_connected(ptr, f_status_.__wbg_ptr); + return ret; +} + +/** + * @param {bigint} ptr + * @param {bigint} sink + * @param {RustCallStatus} f_status_ + */ +export function ubrn_uniffi_matrix_rtc_fn_method_matrixdrivercallback_subscribe_connectivity(ptr, sink, f_status_) { + _assertClass(f_status_, RustCallStatus); + wasm.ubrn_uniffi_matrix_rtc_fn_method_matrixdrivercallback_subscribe_connectivity(ptr, sink, f_status_.__wbg_ptr); } /** @@ -651,183 +660,16 @@ export function ubrn_uniffi_matrix_rtc_fn_free_membershipslistener(handle, f_sta wasm.ubrn_uniffi_matrix_rtc_fn_free_membershipslistener(handle, f_status_.__wbg_ptr); } -/** - * @param {any} vtable - */ -export function ubrn_uniffi_matrix_rtc_fn_init_callback_vtable_membershipslistener(vtable) { - wasm.ubrn_uniffi_matrix_rtc_fn_init_callback_vtable_membershipslistener(vtable); -} - /** * @param {bigint} ptr - * @param {Uint8Array} memberships + * @param {Uint8Array} session * @param {RustCallStatus} f_status_ */ -export function ubrn_uniffi_matrix_rtc_fn_method_membershipslistener_on_memberships_change(ptr, memberships, f_status_) { - const ptr0 = passArray8ToWasm0(memberships, wasm.__wbindgen_malloc); +export function ubrn_uniffi_matrix_rtc_fn_method_sessionlistener_on_session_change(ptr, session, f_status_) { + const ptr0 = passArray8ToWasm0(session, wasm.__wbindgen_malloc); const len0 = WASM_VECTOR_LEN; _assertClass(f_status_, RustCallStatus); - wasm.ubrn_uniffi_matrix_rtc_fn_method_membershipslistener_on_memberships_change(ptr, ptr0, len0, f_status_.__wbg_ptr); -} - -/** - * @param {any} vtable - */ -export function ubrn_uniffi_matrix_rtc_fn_init_callback_vtable_statuslistener(vtable) { - wasm.ubrn_uniffi_matrix_rtc_fn_init_callback_vtable_statuslistener(vtable); -} - -/** - * @param {bigint} ptr - * @param {Uint8Array} status - * @param {RustCallStatus} f_status_ - */ -export function ubrn_uniffi_matrix_rtc_fn_method_statuslistener_on_status_change(ptr, status, f_status_) { - const ptr0 = passArray8ToWasm0(status, wasm.__wbindgen_malloc); - const len0 = WASM_VECTOR_LEN; - _assertClass(f_status_, RustCallStatus); - wasm.ubrn_uniffi_matrix_rtc_fn_method_statuslistener_on_status_change(ptr, ptr0, len0, f_status_.__wbg_ptr); -} - -/** - * @param {bigint} handle - * @param {RustCallStatus} f_status_ - * @returns {bigint} - */ -export function ubrn_uniffi_matrix_rtc_fn_clone_todevicesink(handle, f_status_) { - _assertClass(f_status_, RustCallStatus); - const ret = wasm.ubrn_uniffi_matrix_rtc_fn_clone_todevicesink(handle, f_status_.__wbg_ptr); - return BigInt.asUintN(64, ret); -} - -/** - * @param {bigint} handle - * @param {RustCallStatus} f_status_ - */ -export function ubrn_uniffi_matrix_rtc_fn_free_todevicesink(handle, f_status_) { - _assertClass(f_status_, RustCallStatus); - wasm.ubrn_uniffi_matrix_rtc_fn_free_todevicesink(handle, f_status_.__wbg_ptr); -} - -/** - * @param {bigint} ptr - * @param {Uint8Array} event_type - * @param {Uint8Array} sender - * @param {Uint8Array} content_json - * @param {Uint8Array} origin - * @param {Uint8Array} sender_cross_signed - * @param {RustCallStatus} f_status_ - * @returns {number} - */ -export function ubrn_uniffi_matrix_rtc_fn_method_todevicesink_emit(ptr, event_type, sender, content_json, origin, sender_cross_signed, f_status_) { - const ptr0 = passArray8ToWasm0(event_type, wasm.__wbindgen_malloc); - const len0 = WASM_VECTOR_LEN; - const ptr1 = passArray8ToWasm0(sender, wasm.__wbindgen_malloc); - const len1 = WASM_VECTOR_LEN; - const ptr2 = passArray8ToWasm0(content_json, wasm.__wbindgen_malloc); - const len2 = WASM_VECTOR_LEN; - const ptr3 = passArray8ToWasm0(origin, wasm.__wbindgen_malloc); - const len3 = WASM_VECTOR_LEN; - const ptr4 = passArray8ToWasm0(sender_cross_signed, wasm.__wbindgen_malloc); - const len4 = WASM_VECTOR_LEN; - _assertClass(f_status_, RustCallStatus); - const ret = wasm.ubrn_uniffi_matrix_rtc_fn_method_todevicesink_emit(ptr, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, ptr4, len4, f_status_.__wbg_ptr); - return ret; -} - -/** - * @param {Uint8Array} events_json - * @param {Uint8Array} compat - * @param {RustCallStatus} f_status_ - * @returns {Uint8Array} - */ -export function ubrn_uniffi_matrix_rtc_fn_func_compute_sessions_from_events(events_json, compat, f_status_) { - const ptr0 = passArray8ToWasm0(events_json, wasm.__wbindgen_malloc); - const len0 = WASM_VECTOR_LEN; - const ptr1 = passArray8ToWasm0(compat, wasm.__wbindgen_malloc); - const len1 = WASM_VECTOR_LEN; - _assertClass(f_status_, RustCallStatus); - const ret = wasm.ubrn_uniffi_matrix_rtc_fn_func_compute_sessions_from_events(ptr0, len0, ptr1, len1, f_status_.__wbg_ptr); - var v3 = getArrayU8FromWasm0(ret[0], ret[1]).slice(); - wasm.__wbindgen_free(ret[0], ret[1] * 1, 1); - return v3; -} - -/** - * @param {Uint8Array} impairment - * @param {RustCallStatus} f_status_ - * @returns {Uint8Array} - */ -export function ubrn_uniffi_matrix_rtc_fn_func_impairment_severity(impairment, f_status_) { - const ptr0 = passArray8ToWasm0(impairment, wasm.__wbindgen_malloc); - const len0 = WASM_VECTOR_LEN; - _assertClass(f_status_, RustCallStatus); - const ret = wasm.ubrn_uniffi_matrix_rtc_fn_func_impairment_severity(ptr0, len0, f_status_.__wbg_ptr); - var v2 = getArrayU8FromWasm0(ret[0], ret[1]).slice(); - wasm.__wbindgen_free(ret[0], ret[1] * 1, 1); - return v2; -} - -/** - * @param {bigint} handle - * @param {any} callback - * @param {bigint} callback_data - */ -export function ubrn_ffi_matrix_rtc_rust_future_poll_u8(handle, callback, callback_data) { - wasm.ubrn_ffi_matrix_rtc_rust_future_poll_u8(handle, callback, callback_data); -} - -/** - * @param {bigint} handle - */ -export function ubrn_ffi_matrix_rtc_rust_future_cancel_u8(handle) { - wasm.ubrn_ffi_matrix_rtc_rust_future_cancel_u8(handle); -} - -/** - * @param {bigint} handle - * @param {RustCallStatus} f_status_ - */ -export function ubrn_uniffi_matrix_rtc_fn_free_connectionslistener(handle, f_status_) { - _assertClass(f_status_, RustCallStatus); - wasm.ubrn_uniffi_matrix_rtc_fn_free_connectionslistener(handle, f_status_.__wbg_ptr); -} - -/** - * @param {bigint} handle - * @param {RustCallStatus} f_status_ - * @returns {bigint} - */ -export function ubrn_uniffi_matrix_rtc_fn_clone_roomeventsink(handle, f_status_) { - _assertClass(f_status_, RustCallStatus); - const ret = wasm.ubrn_uniffi_matrix_rtc_fn_clone_roomeventsink(handle, f_status_.__wbg_ptr); - return BigInt.asUintN(64, ret); -} - -/** - * @param {bigint} handle - * @param {RustCallStatus} f_status_ - */ -export function ubrn_uniffi_matrix_rtc_fn_free_roomeventsink(handle, f_status_) { - _assertClass(f_status_, RustCallStatus); - wasm.ubrn_uniffi_matrix_rtc_fn_free_roomeventsink(handle, f_status_.__wbg_ptr); -} - -/** - * @param {bigint} ptr - * @param {Uint8Array} event_json - * @param {Uint8Array} origin - * @param {RustCallStatus} f_status_ - * @returns {number} - */ -export function ubrn_uniffi_matrix_rtc_fn_method_roomeventsink_emit(ptr, event_json, origin, f_status_) { - const ptr0 = passArray8ToWasm0(event_json, wasm.__wbindgen_malloc); - const len0 = WASM_VECTOR_LEN; - const ptr1 = passArray8ToWasm0(origin, wasm.__wbindgen_malloc); - const len1 = WASM_VECTOR_LEN; - _assertClass(f_status_, RustCallStatus); - const ret = wasm.ubrn_uniffi_matrix_rtc_fn_method_roomeventsink_emit(ptr, ptr0, len0, ptr1, len1, f_status_.__wbg_ptr); - return ret; + wasm.ubrn_uniffi_matrix_rtc_fn_method_sessionlistener_on_session_change(ptr, ptr0, len0, f_status_.__wbg_ptr); } /** @@ -885,130 +727,178 @@ export function ubrn_uniffi_matrix_rtc_fn_free_statuslistener(handle, f_status_) } /** - * @param {bigint} handle + * @param {any} vtable */ -export function ubrn_ffi_matrix_rtc_rust_future_free_u8(handle) { - wasm.ubrn_ffi_matrix_rtc_rust_future_free_u8(handle); +export function ubrn_uniffi_matrix_rtc_fn_init_callback_vtable_statuslistener(vtable) { + wasm.ubrn_uniffi_matrix_rtc_fn_init_callback_vtable_statuslistener(vtable); +} + +/** + * @param {bigint} ptr + * @param {Uint8Array} status + * @param {RustCallStatus} f_status_ + */ +export function ubrn_uniffi_matrix_rtc_fn_method_statuslistener_on_status_change(ptr, status, f_status_) { + const ptr0 = passArray8ToWasm0(status, wasm.__wbindgen_malloc); + const len0 = WASM_VECTOR_LEN; + _assertClass(f_status_, RustCallStatus); + wasm.ubrn_uniffi_matrix_rtc_fn_method_statuslistener_on_status_change(ptr, ptr0, len0, f_status_.__wbg_ptr); } /** * @param {bigint} handle * @param {RustCallStatus} f_status_ + * @returns {bigint} + */ +export function ubrn_uniffi_matrix_rtc_fn_clone_todevicesink(handle, f_status_) { + _assertClass(f_status_, RustCallStatus); + const ret = wasm.ubrn_uniffi_matrix_rtc_fn_clone_todevicesink(handle, f_status_.__wbg_ptr); + return BigInt.asUintN(64, ret); +} + +/** + * @param {bigint} handle + * @param {RustCallStatus} f_status_ + */ +export function ubrn_uniffi_matrix_rtc_fn_free_connectionslistener(handle, f_status_) { + _assertClass(f_status_, RustCallStatus); + wasm.ubrn_uniffi_matrix_rtc_fn_free_connectionslistener(handle, f_status_.__wbg_ptr); +} + +/** + * @param {any} vtable + */ +export function ubrn_uniffi_matrix_rtc_fn_init_callback_vtable_membershipslistener(vtable) { + wasm.ubrn_uniffi_matrix_rtc_fn_init_callback_vtable_membershipslistener(vtable); +} + +/** + * @param {bigint} ptr + * @param {Uint8Array} memberships + * @param {RustCallStatus} f_status_ + */ +export function ubrn_uniffi_matrix_rtc_fn_method_membershipslistener_on_memberships_change(ptr, memberships, f_status_) { + const ptr0 = passArray8ToWasm0(memberships, wasm.__wbindgen_malloc); + const len0 = WASM_VECTOR_LEN; + _assertClass(f_status_, RustCallStatus); + wasm.ubrn_uniffi_matrix_rtc_fn_method_membershipslistener_on_memberships_change(ptr, ptr0, len0, f_status_.__wbg_ptr); +} + +/** + * @param {bigint} handle + * @param {RustCallStatus} f_status_ + * @returns {bigint} + */ +export function ubrn_uniffi_matrix_rtc_fn_clone_roomeventsink(handle, f_status_) { + _assertClass(f_status_, RustCallStatus); + const ret = wasm.ubrn_uniffi_matrix_rtc_fn_clone_roomeventsink(handle, f_status_.__wbg_ptr); + return BigInt.asUintN(64, ret); +} + +/** + * @param {bigint} handle + * @param {RustCallStatus} f_status_ + */ +export function ubrn_uniffi_matrix_rtc_fn_free_roomeventsink(handle, f_status_) { + _assertClass(f_status_, RustCallStatus); + wasm.ubrn_uniffi_matrix_rtc_fn_free_roomeventsink(handle, f_status_.__wbg_ptr); +} + +/** + * @param {bigint} ptr + * @param {Uint8Array} event_json + * @param {Uint8Array} origin + * @param {RustCallStatus} f_status_ * @returns {number} */ -export function ubrn_ffi_matrix_rtc_rust_future_complete_u8(handle, f_status_) { +export function ubrn_uniffi_matrix_rtc_fn_method_roomeventsink_emit(ptr, event_json, origin, f_status_) { + const ptr0 = passArray8ToWasm0(event_json, wasm.__wbindgen_malloc); + const len0 = WASM_VECTOR_LEN; + const ptr1 = passArray8ToWasm0(origin, wasm.__wbindgen_malloc); + const len1 = WASM_VECTOR_LEN; _assertClass(f_status_, RustCallStatus); - const ret = wasm.ubrn_ffi_matrix_rtc_rust_future_complete_u8(handle, f_status_.__wbg_ptr); + const ret = wasm.ubrn_uniffi_matrix_rtc_fn_method_roomeventsink_emit(ptr, ptr0, len0, ptr1, len1, f_status_.__wbg_ptr); return ret; } /** * @param {bigint} handle - * @param {any} callback - * @param {bigint} callback_data + * @param {RustCallStatus} f_status_ + * @returns {bigint} */ -export function ubrn_ffi_matrix_rtc_rust_future_poll_i8(handle, callback, callback_data) { - wasm.ubrn_ffi_matrix_rtc_rust_future_poll_i8(handle, callback, callback_data); -} - -/** - * @param {bigint} handle - */ -export function ubrn_ffi_matrix_rtc_rust_future_free_i16(handle) { - wasm.ubrn_ffi_matrix_rtc_rust_future_free_i16(handle); +export function ubrn_uniffi_matrix_rtc_fn_clone_sessionlistener(handle, f_status_) { + _assertClass(f_status_, RustCallStatus); + const ret = wasm.ubrn_uniffi_matrix_rtc_fn_clone_sessionlistener(handle, f_status_.__wbg_ptr); + return BigInt.asUintN(64, ret); } /** * @param {bigint} handle * @param {RustCallStatus} f_status_ + */ +export function ubrn_uniffi_matrix_rtc_fn_free_sessionlistener(handle, f_status_) { + _assertClass(f_status_, RustCallStatus); + wasm.ubrn_uniffi_matrix_rtc_fn_free_sessionlistener(handle, f_status_.__wbg_ptr); +} + +/** + * @param {any} vtable + */ +export function ubrn_uniffi_matrix_rtc_fn_init_callback_vtable_sessionlistener(vtable) { + wasm.ubrn_uniffi_matrix_rtc_fn_init_callback_vtable_sessionlistener(vtable); +} + +/** + * @param {bigint} handle + * @param {RustCallStatus} f_status_ + */ +export function ubrn_uniffi_matrix_rtc_fn_free_todevicesink(handle, f_status_) { + _assertClass(f_status_, RustCallStatus); + wasm.ubrn_uniffi_matrix_rtc_fn_free_todevicesink(handle, f_status_.__wbg_ptr); +} + +/** + * @param {bigint} ptr + * @param {Uint8Array} event_type + * @param {Uint8Array} sender + * @param {Uint8Array} content_json + * @param {Uint8Array} origin + * @param {Uint8Array} sender_cross_signed + * @param {RustCallStatus} f_status_ * @returns {number} */ -export function ubrn_ffi_matrix_rtc_rust_future_complete_i16(handle, f_status_) { +export function ubrn_uniffi_matrix_rtc_fn_method_todevicesink_emit(ptr, event_type, sender, content_json, origin, sender_cross_signed, f_status_) { + const ptr0 = passArray8ToWasm0(event_type, wasm.__wbindgen_malloc); + const len0 = WASM_VECTOR_LEN; + const ptr1 = passArray8ToWasm0(sender, wasm.__wbindgen_malloc); + const len1 = WASM_VECTOR_LEN; + const ptr2 = passArray8ToWasm0(content_json, wasm.__wbindgen_malloc); + const len2 = WASM_VECTOR_LEN; + const ptr3 = passArray8ToWasm0(origin, wasm.__wbindgen_malloc); + const len3 = WASM_VECTOR_LEN; + const ptr4 = passArray8ToWasm0(sender_cross_signed, wasm.__wbindgen_malloc); + const len4 = WASM_VECTOR_LEN; _assertClass(f_status_, RustCallStatus); - const ret = wasm.ubrn_ffi_matrix_rtc_rust_future_complete_i16(handle, f_status_.__wbg_ptr); + const ret = wasm.ubrn_uniffi_matrix_rtc_fn_method_todevicesink_emit(ptr, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, ptr4, len4, f_status_.__wbg_ptr); return ret; } /** - * @param {bigint} handle - * @param {any} callback - * @param {bigint} callback_data - */ -export function ubrn_ffi_matrix_rtc_rust_future_poll_u32(handle, callback, callback_data) { - wasm.ubrn_ffi_matrix_rtc_rust_future_poll_u32(handle, callback, callback_data); -} - -/** - * @param {bigint} handle - */ -export function ubrn_ffi_matrix_rtc_rust_future_cancel_u32(handle) { - wasm.ubrn_ffi_matrix_rtc_rust_future_cancel_u32(handle); -} - -/** - * @param {bigint} handle - */ -export function ubrn_ffi_matrix_rtc_rust_future_free_u32(handle) { - wasm.ubrn_ffi_matrix_rtc_rust_future_free_u32(handle); -} - -/** - * @param {bigint} handle + * @param {Uint8Array} events_json + * @param {Uint8Array} compat * @param {RustCallStatus} f_status_ - * @returns {number} + * @returns {Uint8Array} */ -export function ubrn_ffi_matrix_rtc_rust_future_complete_u32(handle, f_status_) { +export function ubrn_uniffi_matrix_rtc_fn_func_compute_sessions_from_events(events_json, compat, f_status_) { + const ptr0 = passArray8ToWasm0(events_json, wasm.__wbindgen_malloc); + const len0 = WASM_VECTOR_LEN; + const ptr1 = passArray8ToWasm0(compat, wasm.__wbindgen_malloc); + const len1 = WASM_VECTOR_LEN; _assertClass(f_status_, RustCallStatus); - const ret = wasm.ubrn_ffi_matrix_rtc_rust_future_complete_u32(handle, f_status_.__wbg_ptr); - return ret >>> 0; -} - -/** - * @param {bigint} handle - * @param {any} callback - * @param {bigint} callback_data - */ -export function ubrn_ffi_matrix_rtc_rust_future_poll_i32(handle, callback, callback_data) { - wasm.ubrn_ffi_matrix_rtc_rust_future_poll_i32(handle, callback, callback_data); -} - -/** - * @param {bigint} handle - */ -export function ubrn_ffi_matrix_rtc_rust_future_cancel_i32(handle) { - wasm.ubrn_ffi_matrix_rtc_rust_future_cancel_i32(handle); -} - -/** - * @param {bigint} handle - */ -export function ubrn_ffi_matrix_rtc_rust_future_free_i32(handle) { - wasm.ubrn_ffi_matrix_rtc_rust_future_free_i32(handle); -} - -/** - * @param {bigint} handle - */ -export function ubrn_ffi_matrix_rtc_rust_future_cancel_i8(handle) { - wasm.ubrn_ffi_matrix_rtc_rust_future_cancel_i8(handle); -} - -/** - * @param {bigint} handle - */ -export function ubrn_ffi_matrix_rtc_rust_future_free_i8(handle) { - wasm.ubrn_ffi_matrix_rtc_rust_future_free_i8(handle); -} - -/** - * @param {bigint} handle - * @param {RustCallStatus} f_status_ - * @returns {number} - */ -export function ubrn_ffi_matrix_rtc_rust_future_complete_i8(handle, f_status_) { - _assertClass(f_status_, RustCallStatus); - const ret = wasm.ubrn_ffi_matrix_rtc_rust_future_complete_i8(handle, f_status_.__wbg_ptr); - return ret; + const ret = wasm.ubrn_uniffi_matrix_rtc_fn_func_compute_sessions_from_events(ptr0, len0, ptr1, len1, f_status_.__wbg_ptr); + var v3 = getArrayU8FromWasm0(ret[0], ret[1]).slice(); + wasm.__wbindgen_free(ret[0], ret[1] * 1, 1); + return v3; } /** @@ -1061,14 +951,21 @@ export function ubrn_ffi_matrix_rtc_rust_future_cancel_i16(handle) { wasm.ubrn_ffi_matrix_rtc_rust_future_cancel_i16(handle); } +/** + * @param {bigint} handle + */ +export function ubrn_ffi_matrix_rtc_rust_future_free_i16(handle) { + wasm.ubrn_ffi_matrix_rtc_rust_future_free_i16(handle); +} + /** * @param {bigint} handle * @param {RustCallStatus} f_status_ * @returns {number} */ -export function ubrn_ffi_matrix_rtc_rust_future_complete_i32(handle, f_status_) { +export function ubrn_ffi_matrix_rtc_rust_future_complete_i16(handle, f_status_) { _assertClass(f_status_, RustCallStatus); - const ret = wasm.ubrn_ffi_matrix_rtc_rust_future_complete_i32(handle, f_status_.__wbg_ptr); + const ret = wasm.ubrn_ffi_matrix_rtc_rust_future_complete_i16(handle, f_status_.__wbg_ptr); return ret; } @@ -1077,15 +974,46 @@ export function ubrn_ffi_matrix_rtc_rust_future_complete_i32(handle, f_status_) * @param {any} callback * @param {bigint} callback_data */ -export function ubrn_ffi_matrix_rtc_rust_future_poll_u64(handle, callback, callback_data) { - wasm.ubrn_ffi_matrix_rtc_rust_future_poll_u64(handle, callback, callback_data); +export function ubrn_ffi_matrix_rtc_rust_future_poll_u32(handle, callback, callback_data) { + wasm.ubrn_ffi_matrix_rtc_rust_future_poll_u32(handle, callback, callback_data); +} + +/** + * @param {Uint8Array} impairment + * @param {RustCallStatus} f_status_ + * @returns {Uint8Array} + */ +export function ubrn_uniffi_matrix_rtc_fn_func_impairment_severity(impairment, f_status_) { + const ptr0 = passArray8ToWasm0(impairment, wasm.__wbindgen_malloc); + const len0 = WASM_VECTOR_LEN; + _assertClass(f_status_, RustCallStatus); + const ret = wasm.ubrn_uniffi_matrix_rtc_fn_func_impairment_severity(ptr0, len0, f_status_.__wbg_ptr); + var v2 = getArrayU8FromWasm0(ret[0], ret[1]).slice(); + wasm.__wbindgen_free(ret[0], ret[1] * 1, 1); + return v2; +} + +/** + * @param {bigint} handle + * @param {any} callback + * @param {bigint} callback_data + */ +export function ubrn_ffi_matrix_rtc_rust_future_poll_u8(handle, callback, callback_data) { + wasm.ubrn_ffi_matrix_rtc_rust_future_poll_u8(handle, callback, callback_data); } /** * @param {bigint} handle */ -export function ubrn_ffi_matrix_rtc_rust_future_cancel_u64(handle) { - wasm.ubrn_ffi_matrix_rtc_rust_future_cancel_u64(handle); +export function ubrn_ffi_matrix_rtc_rust_future_cancel_u8(handle) { + wasm.ubrn_ffi_matrix_rtc_rust_future_cancel_u8(handle); +} + +/** + * @param {bigint} handle + */ +export function ubrn_ffi_matrix_rtc_rust_future_free_u8(handle) { + wasm.ubrn_ffi_matrix_rtc_rust_future_free_u8(handle); } /** @@ -1093,9 +1021,9 @@ export function ubrn_ffi_matrix_rtc_rust_future_cancel_u64(handle) { * @param {RustCallStatus} f_status_ * @returns {number} */ -export function ubrn_ffi_matrix_rtc_rust_future_complete_f32(handle, f_status_) { +export function ubrn_ffi_matrix_rtc_rust_future_complete_u8(handle, f_status_) { _assertClass(f_status_, RustCallStatus); - const ret = wasm.ubrn_ffi_matrix_rtc_rust_future_complete_f32(handle, f_status_.__wbg_ptr); + const ret = wasm.ubrn_ffi_matrix_rtc_rust_future_complete_u8(handle, f_status_.__wbg_ptr); return ret; } @@ -1104,22 +1032,22 @@ export function ubrn_ffi_matrix_rtc_rust_future_complete_f32(handle, f_status_) * @param {any} callback * @param {bigint} callback_data */ -export function ubrn_ffi_matrix_rtc_rust_future_poll_f64(handle, callback, callback_data) { - wasm.ubrn_ffi_matrix_rtc_rust_future_poll_f64(handle, callback, callback_data); +export function ubrn_ffi_matrix_rtc_rust_future_poll_i8(handle, callback, callback_data) { + wasm.ubrn_ffi_matrix_rtc_rust_future_poll_i8(handle, callback, callback_data); } /** * @param {bigint} handle */ -export function ubrn_ffi_matrix_rtc_rust_future_cancel_f64(handle) { - wasm.ubrn_ffi_matrix_rtc_rust_future_cancel_f64(handle); +export function ubrn_ffi_matrix_rtc_rust_future_cancel_i8(handle) { + wasm.ubrn_ffi_matrix_rtc_rust_future_cancel_i8(handle); } /** * @param {bigint} handle */ -export function ubrn_ffi_matrix_rtc_rust_future_free_f64(handle) { - wasm.ubrn_ffi_matrix_rtc_rust_future_free_f64(handle); +export function ubrn_ffi_matrix_rtc_rust_future_free_i8(handle) { + wasm.ubrn_ffi_matrix_rtc_rust_future_free_i8(handle); } /** @@ -1127,60 +1055,35 @@ export function ubrn_ffi_matrix_rtc_rust_future_free_f64(handle) { * @param {RustCallStatus} f_status_ * @returns {number} */ -export function ubrn_ffi_matrix_rtc_rust_future_complete_f64(handle, f_status_) { +export function ubrn_ffi_matrix_rtc_rust_future_complete_i8(handle, f_status_) { _assertClass(f_status_, RustCallStatus); - const ret = wasm.ubrn_ffi_matrix_rtc_rust_future_complete_f64(handle, f_status_.__wbg_ptr); + const ret = wasm.ubrn_ffi_matrix_rtc_rust_future_complete_i8(handle, f_status_.__wbg_ptr); return ret; } /** * @param {bigint} handle - * @param {any} callback - * @param {bigint} callback_data */ -export function ubrn_ffi_matrix_rtc_rust_future_poll_rust_buffer(handle, callback, callback_data) { - wasm.ubrn_ffi_matrix_rtc_rust_future_poll_rust_buffer(handle, callback, callback_data); +export function ubrn_ffi_matrix_rtc_rust_future_cancel_u32(handle) { + wasm.ubrn_ffi_matrix_rtc_rust_future_cancel_u32(handle); } /** * @param {bigint} handle */ -export function ubrn_ffi_matrix_rtc_rust_future_cancel_rust_buffer(handle) { - wasm.ubrn_ffi_matrix_rtc_rust_future_cancel_rust_buffer(handle); -} - -/** - * @param {bigint} handle - */ -export function ubrn_ffi_matrix_rtc_rust_future_free_rust_buffer(handle) { - wasm.ubrn_ffi_matrix_rtc_rust_future_free_rust_buffer(handle); -} - -/** - * @param {bigint} handle - */ -export function ubrn_ffi_matrix_rtc_rust_future_free_u64(handle) { - wasm.ubrn_ffi_matrix_rtc_rust_future_free_u64(handle); +export function ubrn_ffi_matrix_rtc_rust_future_free_u32(handle) { + wasm.ubrn_ffi_matrix_rtc_rust_future_free_u32(handle); } /** * @param {bigint} handle * @param {RustCallStatus} f_status_ - * @returns {bigint} + * @returns {number} */ -export function ubrn_ffi_matrix_rtc_rust_future_complete_u64(handle, f_status_) { +export function ubrn_ffi_matrix_rtc_rust_future_complete_u32(handle, f_status_) { _assertClass(f_status_, RustCallStatus); - const ret = wasm.ubrn_ffi_matrix_rtc_rust_future_complete_u64(handle, f_status_.__wbg_ptr); - return BigInt.asUintN(64, ret); -} - -/** - * @param {bigint} handle - * @param {any} callback - * @param {bigint} callback_data - */ -export function ubrn_ffi_matrix_rtc_rust_future_poll_i64(handle, callback, callback_data) { - wasm.ubrn_ffi_matrix_rtc_rust_future_poll_i64(handle, callback, callback_data); + const ret = wasm.ubrn_ffi_matrix_rtc_rust_future_complete_u32(handle, f_status_.__wbg_ptr); + return ret >>> 0; } /** @@ -1234,14 +1137,12 @@ export function ubrn_ffi_matrix_rtc_rust_future_free_f32(handle) { /** * @param {bigint} handle * @param {RustCallStatus} f_status_ - * @returns {Uint8Array} + * @returns {number} */ -export function ubrn_ffi_matrix_rtc_rust_future_complete_rust_buffer(handle, f_status_) { +export function ubrn_ffi_matrix_rtc_rust_future_complete_f32(handle, f_status_) { _assertClass(f_status_, RustCallStatus); - const ret = wasm.ubrn_ffi_matrix_rtc_rust_future_complete_rust_buffer(handle, f_status_.__wbg_ptr); - var v1 = getArrayU8FromWasm0(ret[0], ret[1]).slice(); - wasm.__wbindgen_free(ret[0], ret[1] * 1, 1); - return v1; + const ret = wasm.ubrn_ffi_matrix_rtc_rust_future_complete_f32(handle, f_status_.__wbg_ptr); + return ret; } /** @@ -1249,120 +1150,121 @@ export function ubrn_ffi_matrix_rtc_rust_future_complete_rust_buffer(handle, f_s * @param {any} callback * @param {bigint} callback_data */ -export function ubrn_ffi_matrix_rtc_rust_future_poll_void(handle, callback, callback_data) { - wasm.ubrn_ffi_matrix_rtc_rust_future_poll_void(handle, callback, callback_data); +export function ubrn_ffi_matrix_rtc_rust_future_poll_f64(handle, callback, callback_data) { + wasm.ubrn_ffi_matrix_rtc_rust_future_poll_f64(handle, callback, callback_data); +} + +/** + * @param {bigint} handle + * @param {any} callback + * @param {bigint} callback_data + */ +export function ubrn_ffi_matrix_rtc_rust_future_poll_i32(handle, callback, callback_data) { + wasm.ubrn_ffi_matrix_rtc_rust_future_poll_i32(handle, callback, callback_data); } /** * @param {bigint} handle */ -export function ubrn_ffi_matrix_rtc_rust_future_cancel_void(handle) { - wasm.ubrn_ffi_matrix_rtc_rust_future_cancel_void(handle); +export function ubrn_ffi_matrix_rtc_rust_future_cancel_i32(handle) { + wasm.ubrn_ffi_matrix_rtc_rust_future_cancel_i32(handle); } /** * @param {bigint} handle */ -export function ubrn_ffi_matrix_rtc_rust_future_free_void(handle) { - wasm.ubrn_ffi_matrix_rtc_rust_future_free_void(handle); -} - -/** - * @returns {number} - */ -export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_debug_snapshot() { - const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_debug_snapshot(); - return ret; -} - -/** - * @returns {number} - */ -export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_is_homeserver_connected() { - const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_is_homeserver_connected(); - return ret; -} - -/** - * @returns {number} - */ -export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_join() { - const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_join(); - return ret; -} - -/** - * @returns {number} - */ -export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_key_map() { - const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_key_map(); - return ret; -} - -/** - * @returns {number} - */ -export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_leave() { - const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_leave(); - return ret; -} - -/** - * @returns {number} - */ -export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_memberships() { - const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_memberships(); - return ret; -} - -/** - * @returns {number} - */ -export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_open_slot() { - const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_open_slot(); - return ret; -} - -/** - * @returns {number} - */ -export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_own_member_id() { - const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_own_member_id(); - return ret; -} - -/** - * @returns {number} - */ -export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_own_membership() { - const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_own_membership(); - return ret; -} - -/** - * @param {any} vtable - */ -export function ubrn_uniffi_matrix_rtc_fn_init_callback_vtable_connectionslistener(vtable) { - wasm.ubrn_uniffi_matrix_rtc_fn_init_callback_vtable_connectionslistener(vtable); +export function ubrn_ffi_matrix_rtc_rust_future_free_i32(handle) { + wasm.ubrn_ffi_matrix_rtc_rust_future_free_i32(handle); } /** * @param {bigint} handle * @param {RustCallStatus} f_status_ + * @returns {number} */ -export function ubrn_ffi_matrix_rtc_rust_future_complete_void(handle, f_status_) { +export function ubrn_ffi_matrix_rtc_rust_future_complete_i32(handle, f_status_) { _assertClass(f_status_, RustCallStatus); - wasm.ubrn_ffi_matrix_rtc_rust_future_complete_void(handle, f_status_.__wbg_ptr); + const ret = wasm.ubrn_ffi_matrix_rtc_rust_future_complete_i32(handle, f_status_.__wbg_ptr); + return ret; } /** + * @param {bigint} handle + * @param {any} callback + * @param {bigint} callback_data + */ +export function ubrn_ffi_matrix_rtc_rust_future_poll_u64(handle, callback, callback_data) { + wasm.ubrn_ffi_matrix_rtc_rust_future_poll_u64(handle, callback, callback_data); +} + +/** + * @param {bigint} handle + */ +export function ubrn_ffi_matrix_rtc_rust_future_cancel_u64(handle) { + wasm.ubrn_ffi_matrix_rtc_rust_future_cancel_u64(handle); +} + +/** + * @param {bigint} handle + */ +export function ubrn_ffi_matrix_rtc_rust_future_free_u64(handle) { + wasm.ubrn_ffi_matrix_rtc_rust_future_free_u64(handle); +} + +/** + * @param {bigint} handle + * @param {RustCallStatus} f_status_ + * @returns {bigint} + */ +export function ubrn_ffi_matrix_rtc_rust_future_complete_u64(handle, f_status_) { + _assertClass(f_status_, RustCallStatus); + const ret = wasm.ubrn_ffi_matrix_rtc_rust_future_complete_u64(handle, f_status_.__wbg_ptr); + return BigInt.asUintN(64, ret); +} + +/** + * @param {bigint} handle + * @param {any} callback + * @param {bigint} callback_data + */ +export function ubrn_ffi_matrix_rtc_rust_future_poll_i64(handle, callback, callback_data) { + wasm.ubrn_ffi_matrix_rtc_rust_future_poll_i64(handle, callback, callback_data); +} + +/** + * @param {bigint} handle + */ +export function ubrn_ffi_matrix_rtc_rust_future_cancel_f64(handle) { + wasm.ubrn_ffi_matrix_rtc_rust_future_cancel_f64(handle); +} + +/** + * @param {bigint} handle + */ +export function ubrn_ffi_matrix_rtc_rust_future_free_f64(handle) { + wasm.ubrn_ffi_matrix_rtc_rust_future_free_f64(handle); +} + +/** + * @param {bigint} handle + * @param {RustCallStatus} f_status_ * @returns {number} */ -export function ubrn_uniffi_matrix_rtc_checksum_func_compute_sessions_from_events() { - const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_func_compute_sessions_from_events(); +export function ubrn_ffi_matrix_rtc_rust_future_complete_f64(handle, f_status_) { + _assertClass(f_status_, RustCallStatus); + const ret = wasm.ubrn_ffi_matrix_rtc_rust_future_complete_f64(handle, f_status_.__wbg_ptr); return ret; } +/** + * @param {bigint} handle + * @param {any} callback + * @param {bigint} callback_data + */ +export function ubrn_ffi_matrix_rtc_rust_future_poll_rust_buffer(handle, callback, callback_data) { + wasm.ubrn_ffi_matrix_rtc_rust_future_poll_rust_buffer(handle, callback, callback_data); +} + /** * @returns {number} */ @@ -1414,120 +1316,130 @@ export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_c /** * @returns {number} */ -export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_own_transport_identity() { - const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_own_transport_identity(); +export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_debug_snapshot() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_debug_snapshot(); return ret; } /** * @returns {number} */ -export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_session() { - const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_session(); +export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_is_homeserver_connected() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_is_homeserver_connected(); return ret; } /** * @returns {number} */ -export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_set_connections_listener() { - const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_set_connections_listener(); +export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_join() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_join(); + return ret; +} + +/** + * @param {any} vtable + */ +export function ubrn_uniffi_matrix_rtc_fn_init_callback_vtable_connectionslistener(vtable) { + wasm.ubrn_uniffi_matrix_rtc_fn_init_callback_vtable_connectionslistener(vtable); +} + +/** + * @param {bigint} handle + */ +export function ubrn_ffi_matrix_rtc_rust_future_cancel_rust_buffer(handle) { + wasm.ubrn_ffi_matrix_rtc_rust_future_cancel_rust_buffer(handle); +} + +/** + * @param {bigint} handle + */ +export function ubrn_ffi_matrix_rtc_rust_future_free_rust_buffer(handle) { + wasm.ubrn_ffi_matrix_rtc_rust_future_free_rust_buffer(handle); +} + +/** + * @param {bigint} handle + * @param {RustCallStatus} f_status_ + * @returns {Uint8Array} + */ +export function ubrn_ffi_matrix_rtc_rust_future_complete_rust_buffer(handle, f_status_) { + _assertClass(f_status_, RustCallStatus); + const ret = wasm.ubrn_ffi_matrix_rtc_rust_future_complete_rust_buffer(handle, f_status_.__wbg_ptr); + var v1 = getArrayU8FromWasm0(ret[0], ret[1]).slice(); + wasm.__wbindgen_free(ret[0], ret[1] * 1, 1); + return v1; +} + +/** + * @param {bigint} handle + * @param {any} callback + * @param {bigint} callback_data + */ +export function ubrn_ffi_matrix_rtc_rust_future_poll_void(handle, callback, callback_data) { + wasm.ubrn_ffi_matrix_rtc_rust_future_poll_void(handle, callback, callback_data); +} + +/** + * @param {bigint} handle + */ +export function ubrn_ffi_matrix_rtc_rust_future_cancel_void(handle) { + wasm.ubrn_ffi_matrix_rtc_rust_future_cancel_void(handle); +} + +/** + * @param {bigint} handle + */ +export function ubrn_ffi_matrix_rtc_rust_future_free_void(handle) { + wasm.ubrn_ffi_matrix_rtc_rust_future_free_void(handle); +} + +/** + * @param {bigint} handle + * @param {RustCallStatus} f_status_ + */ +export function ubrn_ffi_matrix_rtc_rust_future_complete_void(handle, f_status_) { + _assertClass(f_status_, RustCallStatus); + wasm.ubrn_ffi_matrix_rtc_rust_future_complete_void(handle, f_status_.__wbg_ptr); +} + +/** + * @returns {number} + */ +export function ubrn_uniffi_matrix_rtc_checksum_func_compute_sessions_from_events() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_func_compute_sessions_from_events(); return ret; } /** * @returns {number} */ -export function ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_send_state_event() { - const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_send_state_event(); +export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_key_map() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_key_map(); return ret; } /** * @returns {number} */ -export function ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_send_delayed_event() { - const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_send_delayed_event(); +export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_leave() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_leave(); return ret; } /** * @returns {number} */ -export function ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_send_delayed_state_event() { - const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_send_delayed_state_event(); +export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_memberships() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_memberships(); return ret; } /** * @returns {number} */ -export function ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_restart_delayed_event() { - const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_restart_delayed_event(); - return ret; -} - -/** - * @returns {number} - */ -export function ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_cancel_delayed_event() { - const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_cancel_delayed_event(); - return ret; -} - -/** - * @returns {number} - */ -export function ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_delegate_livekit_delayed_leave() { - const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_delegate_livekit_delayed_leave(); - return ret; -} - -/** - * @returns {number} - */ -export function ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_send_to_device() { - const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_send_to_device(); - return ret; -} - -/** - * @returns {number} - */ -export function ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_get_rtc_transports() { - const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_get_rtc_transports(); - return ret; -} - -/** - * @returns {number} - */ -export function ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_get_livekit_token() { - const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_get_livekit_token(); - return ret; -} - -/** - * @returns {number} - */ -export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_set_key_map_listener() { - const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_set_key_map_listener(); - return ret; -} - -/** - * @returns {number} - */ -export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_set_key_rejected_listener() { - const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_set_key_rejected_listener(); - return ret; -} - -/** - * @returns {number} - */ -export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_set_memberships_listener() { - const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_set_memberships_listener(); +export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_set_session_listener() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_set_session_listener(); return ret; } @@ -1582,56 +1494,112 @@ export function ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_send /** * @returns {number} */ -export function ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_read_events() { - const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_read_events(); +export function ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_send_state_event() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_send_state_event(); return ret; } /** * @returns {number} */ -export function ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_read_state() { - const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_read_state(); +export function ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_send_delayed_event() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_send_delayed_event(); return ret; } /** * @returns {number} */ -export function ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_subscribe_room_events() { - const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_subscribe_room_events(); +export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_open_slot() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_open_slot(); return ret; } /** * @returns {number} */ -export function ubrn_uniffi_matrix_rtc_checksum_constructor_ffimatrixdriver_new() { - const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_constructor_ffimatrixdriver_new(); +export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_own_member_id() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_own_member_id(); return ret; } /** * @returns {number} */ -export function ubrn_uniffi_matrix_rtc_checksum_constructor_ffiparticipationmanager_new() { - const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_constructor_ffiparticipationmanager_new(); +export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_own_membership() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_own_membership(); return ret; } /** * @returns {number} */ -export function ubrn_ffi_matrix_rtc_uniffi_contract_version() { - const ret = wasm.ubrn_ffi_matrix_rtc_uniffi_contract_version(); - return ret >>> 0; +export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_own_transport_identity() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_own_transport_identity(); + return ret; } /** * @returns {number} */ -export function ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_subscribe_to_device_events() { - const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_subscribe_to_device_events(); +export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_session() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_session(); + return ret; +} + +/** + * @returns {number} + */ +export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_set_connections_listener() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_set_connections_listener(); + return ret; +} + +/** + * @returns {number} + */ +export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_set_key_map_listener() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_set_key_map_listener(); + return ret; +} + +/** + * @returns {number} + */ +export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_set_key_rejected_listener() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_set_key_rejected_listener(); + return ret; +} + +/** + * @returns {number} + */ +export function ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_set_memberships_listener() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_ffiparticipationmanager_set_memberships_listener(); + return ret; +} + +/** + * @returns {number} + */ +export function ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_send_delayed_state_event() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_send_delayed_state_event(); + return ret; +} + +/** + * @returns {number} + */ +export function ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_restart_delayed_event() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_restart_delayed_event(); + return ret; +} + +/** + * @returns {number} + */ +export function ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_cancel_delayed_event() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_cancel_delayed_event(); return ret; } @@ -1675,6 +1643,14 @@ export function ubrn_uniffi_matrix_rtc_checksum_method_roomeventsink_emit() { return ret; } +/** + * @returns {number} + */ +export function ubrn_uniffi_matrix_rtc_checksum_method_sessionlistener_on_session_change() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_sessionlistener_on_session_change(); + return ret; +} + /** * @returns {number} */ @@ -1691,6 +1667,78 @@ export function ubrn_uniffi_matrix_rtc_checksum_method_statuslistener_on_status_ return ret; } +/** + * @returns {number} + */ +export function ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_delegate_delayed_leave_via_homeserver() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_delegate_delayed_leave_via_homeserver(); + return ret; +} + +/** + * @returns {number} + */ +export function ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_delegate_delayed_leave_via_transport() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_delegate_delayed_leave_via_transport(); + return ret; +} + +/** + * @returns {number} + */ +export function ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_send_to_device() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_send_to_device(); + return ret; +} + +/** + * @returns {number} + */ +export function ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_get_rtc_transports() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_get_rtc_transports(); + return ret; +} + +/** + * @returns {number} + */ +export function ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_get_livekit_token() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_get_livekit_token(); + return ret; +} + +/** + * @returns {number} + */ +export function ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_read_events() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_read_events(); + return ret; +} + +/** + * @returns {number} + */ +export function ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_read_state() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_read_state(); + return ret; +} + +/** + * @returns {number} + */ +export function ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_subscribe_room_events() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_subscribe_room_events(); + return ret; +} + +/** + * @returns {number} + */ +export function ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_subscribe_to_device_events() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_method_matrixdrivercallback_subscribe_to_device_events(); + return ret; +} + /** * @returns {number} */ @@ -1699,6 +1747,30 @@ export function ubrn_uniffi_matrix_rtc_checksum_method_todevicesink_emit() { return ret; } +/** + * @returns {number} + */ +export function ubrn_uniffi_matrix_rtc_checksum_constructor_ffimatrixdriver_new() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_constructor_ffimatrixdriver_new(); + return ret; +} + +/** + * @returns {number} + */ +export function ubrn_uniffi_matrix_rtc_checksum_constructor_ffiparticipationmanager_new() { + const ret = wasm.ubrn_uniffi_matrix_rtc_checksum_constructor_ffiparticipationmanager_new(); + return ret; +} + +/** + * @returns {number} + */ +export function ubrn_ffi_matrix_rtc_uniffi_contract_version() { + const ret = wasm.ubrn_ffi_matrix_rtc_uniffi_contract_version(); + return ret >>> 0; +} + /** * @param {bigint} ptr * @param {Uint8Array} connections @@ -1927,7 +1999,7 @@ function __wbg_adapter_24(arg0, arg1) { } function __wbg_adapter_27(arg0, arg1, arg2) { - wasm.closure531_externref_shim(arg0, arg1, arg2); + wasm.closure562_externref_shim(arg0, arg1, arg2); } const ForeignFutureCompleteF32Finalization = (typeof FinalizationRegistry === 'undefined') @@ -2390,22 +2462,14 @@ function __wbg_get_imports() { imports.wbg.__wbg_call_02529374d31ad97c = function(arg0, arg1, arg2) { arg0.call(arg1, BigInt.asUintN(64, arg2)); }; - imports.wbg.__wbg_call_0433755a93443d6e = function(arg0, arg1, arg2, arg3) { - const ret = arg0.call(arg1, BigInt.asUintN(64, arg2), BigInt.asUintN(64, arg3)); - return ret; - }; - imports.wbg.__wbg_call_05dc34bdb8662702 = function(arg0, arg1, arg2, arg3) { - const ret = arg0.call(arg1, BigInt.asUintN(64, arg2), BigInt.asUintN(64, arg3)); - return ret; - }; - imports.wbg.__wbg_call_0ba4077697ab1405 = function(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) { + imports.wbg.__wbg_call_03c16dfcbc9e20c2 = function(arg0, arg1, arg2, arg3, arg4, arg5, arg6) { var v0 = getArrayU8FromWasm0(arg3, arg4).slice(); wasm.__wbindgen_free(arg3, arg4 * 1, 1); - var v1 = getArrayU8FromWasm0(arg5, arg6).slice(); - wasm.__wbindgen_free(arg5, arg6 * 1, 1); - var v2 = getArrayU8FromWasm0(arg7, arg8).slice(); - wasm.__wbindgen_free(arg7, arg8 * 1, 1); - const ret = arg0.call(arg1, BigInt.asUintN(64, arg2), v0, v1, v2, ForeignFutureCompleteRustBuffer.__wrap(arg9), BigInt.asUintN(64, arg10)); + const ret = arg0.call(arg1, BigInt.asUintN(64, arg2), v0, ForeignFutureCompleteRustBuffer.__wrap(arg5), BigInt.asUintN(64, arg6)); + return ret; + }; + imports.wbg.__wbg_call_0433755a93443d6e = function(arg0, arg1, arg2, arg3) { + const ret = arg0.call(arg1, BigInt.asUintN(64, arg2), BigInt.asUintN(64, arg3)); return ret; }; imports.wbg.__wbg_call_21960420ca81bc05 = function(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12) { @@ -2437,12 +2501,6 @@ function __wbg_get_imports() { imports.wbg.__wbg_call_45ca295cb4469524 = function(arg0, arg1, arg2, arg3) { arg0.call(arg1, BigInt.asUintN(64, arg2), arg3); }; - imports.wbg.__wbg_call_45f35e4128d6c004 = function(arg0, arg1, arg2, arg3, arg4, arg5, arg6) { - var v0 = getArrayU8FromWasm0(arg3, arg4).slice(); - wasm.__wbindgen_free(arg3, arg4 * 1, 1); - const ret = arg0.call(arg1, BigInt.asUintN(64, arg2), v0, ForeignFutureCompleteRustBuffer.__wrap(arg5), BigInt.asUintN(64, arg6)); - return ret; - }; imports.wbg.__wbg_call_4614c0a573de577f = function(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13) { var v0 = getArrayU8FromWasm0(arg3, arg4).slice(); wasm.__wbindgen_free(arg3, arg4 * 1, 1); @@ -2455,16 +2513,14 @@ function __wbg_get_imports() { const ret = arg0.call(arg1, BigInt.asUintN(64, arg2), v0, v1, v2, v3, BigInt.asUintN(64, arg11), ForeignFutureCompleteRustBuffer.__wrap(arg12), BigInt.asUintN(64, arg13)); return ret; }; - imports.wbg.__wbg_call_496b92421c092b65 = function(arg0, arg1, arg2) { - const ret = arg0.call(arg1, BigInt.asUintN(64, arg2)); - return ret; - }; - imports.wbg.__wbg_call_571d4611879307e7 = function(arg0, arg1, arg2, arg3) { - const ret = arg0.call(arg1, BigInt.asUintN(64, arg2), BigInt.asUintN(64, arg3)); - return ret; - }; - imports.wbg.__wbg_call_65221d24e12159bf = function(arg0, arg1, arg2, arg3, arg4) { - const ret = arg0.call(arg1, BigInt.asUintN(64, arg2), ForeignFutureCompleteRustBuffer.__wrap(arg3), BigInt.asUintN(64, arg4)); + imports.wbg.__wbg_call_5718592162c98368 = function(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) { + var v0 = getArrayU8FromWasm0(arg3, arg4).slice(); + wasm.__wbindgen_free(arg3, arg4 * 1, 1); + var v1 = getArrayU8FromWasm0(arg5, arg6).slice(); + wasm.__wbindgen_free(arg5, arg6 * 1, 1); + var v2 = getArrayU8FromWasm0(arg7, arg8).slice(); + wasm.__wbindgen_free(arg7, arg8 * 1, 1); + const ret = arg0.call(arg1, BigInt.asUintN(64, arg2), v0, v1, v2, ForeignFutureCompleteRustBuffer.__wrap(arg9), BigInt.asUintN(64, arg10)); return ret; }; imports.wbg.__wbg_call_65360e4d1b0f41fa = function(arg0, arg1, arg2) { @@ -2474,6 +2530,10 @@ function __wbg_get_imports() { const ret = arg0.call(arg1); return ret; }, arguments) }; + imports.wbg.__wbg_call_6791e83bb1bb6601 = function(arg0, arg1, arg2) { + const ret = arg0.call(arg1, BigInt.asUintN(64, arg2)); + return ret; + }; imports.wbg.__wbg_call_67bcb4b184601516 = function(arg0, arg1, arg2) { arg0.call(arg1, BigInt.asUintN(64, arg2)); }; @@ -2487,18 +2547,26 @@ function __wbg_get_imports() { const ret = arg0.call(arg1, arg2); return ret; }, arguments) }; - imports.wbg.__wbg_call_85dc743acd81f8e1 = function(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15) { + imports.wbg.__wbg_call_87edfa0175375a83 = function(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) { var v0 = getArrayU8FromWasm0(arg3, arg4).slice(); wasm.__wbindgen_free(arg3, arg4 * 1, 1); var v1 = getArrayU8FromWasm0(arg5, arg6).slice(); wasm.__wbindgen_free(arg5, arg6 * 1, 1); - var v2 = getArrayU8FromWasm0(arg7, arg8).slice(); - wasm.__wbindgen_free(arg7, arg8 * 1, 1); - var v3 = getArrayU8FromWasm0(arg9, arg10).slice(); - wasm.__wbindgen_free(arg9, arg10 * 1, 1); - var v4 = getArrayU8FromWasm0(arg11, arg12).slice(); - wasm.__wbindgen_free(arg11, arg12 * 1, 1); - const ret = arg0.call(arg1, BigInt.asUintN(64, arg2), v0, v1, v2, v3, v4, BigInt.asUintN(64, arg13), ForeignFutureCompleteVoid.__wrap(arg14), BigInt.asUintN(64, arg15)); + const ret = arg0.call(arg1, BigInt.asUintN(64, arg2), v0, v1, ForeignFutureCompleteRustBuffer.__wrap(arg7), BigInt.asUintN(64, arg8)); + return ret; + }; + imports.wbg.__wbg_call_9108746ed497928f = function(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) { + var v0 = getArrayU8FromWasm0(arg3, arg4).slice(); + wasm.__wbindgen_free(arg3, arg4 * 1, 1); + var v1 = getArrayU8FromWasm0(arg5, arg6).slice(); + wasm.__wbindgen_free(arg5, arg6 * 1, 1); + const ret = arg0.call(arg1, BigInt.asUintN(64, arg2), v0, v1, arg7 >>> 0, ForeignFutureCompleteRustBuffer.__wrap(arg8), BigInt.asUintN(64, arg9)); + return ret; + }; + imports.wbg.__wbg_call_98882f14cac8324a = function(arg0, arg1, arg2, arg3, arg4, arg5, arg6) { + var v0 = getArrayU8FromWasm0(arg3, arg4).slice(); + wasm.__wbindgen_free(arg3, arg4 * 1, 1); + const ret = arg0.call(arg1, BigInt.asUintN(64, arg2), v0, ForeignFutureCompleteVoid.__wrap(arg5), BigInt.asUintN(64, arg6)); return ret; }; imports.wbg.__wbg_call_9a894f10d06a53c9 = function(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) { @@ -2534,18 +2602,29 @@ function __wbg_get_imports() { const ret = arg0.call(arg1, BigInt.asUintN(64, arg2), v0); return ret; }; + imports.wbg.__wbg_call_ac8db65a5eb7c738 = function(arg0, arg1, arg2, arg3, arg4) { + const ret = arg0.call(arg1, BigInt.asUintN(64, arg2), ForeignFutureCompleteRustBuffer.__wrap(arg3), BigInt.asUintN(64, arg4)); + return ret; + }; imports.wbg.__wbg_call_b66d526ecf55c81d = function(arg0, arg1, arg2) { const ret = arg0.call(arg1, BigInt.asUintN(64, arg2)); return ret; }; - imports.wbg.__wbg_call_bd883beab9425b7c = function(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) { + imports.wbg.__wbg_call_b9d1054c432bc102 = function(arg0, arg1, arg2, arg3, arg4, arg5, arg6) { var v0 = getArrayU8FromWasm0(arg3, arg4).slice(); wasm.__wbindgen_free(arg3, arg4 * 1, 1); - var v1 = getArrayU8FromWasm0(arg5, arg6).slice(); - wasm.__wbindgen_free(arg5, arg6 * 1, 1); - const ret = arg0.call(arg1, BigInt.asUintN(64, arg2), v0, v1, arg7 >>> 0, ForeignFutureCompleteRustBuffer.__wrap(arg8), BigInt.asUintN(64, arg9)); + const ret = arg0.call(arg1, BigInt.asUintN(64, arg2), v0, ForeignFutureCompleteVoid.__wrap(arg5), BigInt.asUintN(64, arg6)); return ret; }; + imports.wbg.__wbg_call_bd656bf95b67af57 = function(arg0, arg1, arg2, arg3, arg4) { + var v0 = getArrayU8FromWasm0(arg3, arg4).slice(); + wasm.__wbindgen_free(arg3, arg4 * 1, 1); + const ret = arg0.call(arg1, BigInt.asUintN(64, arg2), v0); + return ret; + }; + imports.wbg.__wbg_call_c7fa2ece3851d664 = function(arg0, arg1, arg2) { + arg0.call(arg1, BigInt.asUintN(64, arg2)); + }; imports.wbg.__wbg_call_c9c4e766b640b52d = function(arg0, arg1, arg2, arg3) { const ret = arg0.call(arg1, BigInt.asUintN(64, arg2), BigInt.asUintN(64, arg3)); return ret; @@ -2572,20 +2651,20 @@ function __wbg_get_imports() { const ret = arg0.call(arg1, BigInt.asUintN(64, arg2), v0, v1, v2, BigInt.asUintN(64, arg9), ForeignFutureCompleteRustBuffer.__wrap(arg10), BigInt.asUintN(64, arg11)); return ret; }; - imports.wbg.__wbg_call_dd8fc90cc1eed1a0 = function(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) { - var v0 = getArrayU8FromWasm0(arg3, arg4).slice(); - wasm.__wbindgen_free(arg3, arg4 * 1, 1); - var v1 = getArrayU8FromWasm0(arg5, arg6).slice(); - wasm.__wbindgen_free(arg5, arg6 * 1, 1); - const ret = arg0.call(arg1, BigInt.asUintN(64, arg2), v0, v1, ForeignFutureCompleteRustBuffer.__wrap(arg7), BigInt.asUintN(64, arg8)); - return ret; - }; imports.wbg.__wbg_call_df53672c5883e9e7 = function(arg0, arg1, arg2, arg3, arg4) { var v0 = getArrayU8FromWasm0(arg3, arg4).slice(); wasm.__wbindgen_free(arg3, arg4 * 1, 1); const ret = arg0.call(arg1, BigInt.asUintN(64, arg2), v0); return ret; }; + imports.wbg.__wbg_call_e1d35efce0e1a1e6 = function(arg0, arg1, arg2) { + const ret = arg0.call(arg1, BigInt.asUintN(64, arg2)); + return ret; + }; + imports.wbg.__wbg_call_e561c9090f51461d = function(arg0, arg1, arg2, arg3) { + const ret = arg0.call(arg1, BigInt.asUintN(64, arg2), BigInt.asUintN(64, arg3)); + return ret; + }; imports.wbg.__wbg_call_f95ee156aae25631 = function(arg0, arg1, arg2) { const ret = arg0.call(arg1, BigInt.asUintN(64, arg2)); return ret; @@ -2601,6 +2680,10 @@ function __wbg_get_imports() { const ret = arg0.call(arg1, BigInt.asUintN(64, arg2)); return ret; }; + imports.wbg.__wbg_call_ffd94e4913c24a7a = function(arg0, arg1, arg2, arg3) { + const ret = arg0.call(arg1, BigInt.asUintN(64, arg2), BigInt.asUintN(64, arg3)); + return ret; + }; imports.wbg.__wbg_callstatus_ab813cdd9fb59b5c = function(arg0) { const ret = arg0.call_status; _assertClass(ret, RustCallStatus); @@ -2627,8 +2710,12 @@ function __wbg_get_imports() { const ret = arg0.crypto; return ret; }; - imports.wbg.__wbg_delegatelivekitdelayedleave_991fce363b53064f = function(arg0) { - const ret = arg0.delegate_livekit_delayed_leave; + imports.wbg.__wbg_delegatedelayedleaveviahomeserver_d871a6b6bc347229 = function(arg0) { + const ret = arg0.delegate_delayed_leave_via_homeserver; + return ret; + }; + imports.wbg.__wbg_delegatedelayedleaveviatransport_aa4b046ef4e220a1 = function(arg0) { + const ret = arg0.delegate_delayed_leave_via_transport; return ret; }; imports.wbg.__wbg_errorbuf_59fafcd45c02f900 = function(arg0, arg1) { @@ -2652,11 +2739,11 @@ function __wbg_get_imports() { imports.wbg.__wbg_getRandomValues_b3f15fcbfabb0f8b = function() { return handleError(function (arg0, arg1) { arg0.getRandomValues(arg1); }, arguments) }; - imports.wbg.__wbg_getlivekittoken_269ca0b4c594770a = function(arg0) { + imports.wbg.__wbg_getlivekittoken_5f81591c0acaddc6 = function(arg0) { const ret = arg0.get_livekit_token; return ret; }; - imports.wbg.__wbg_getrtctransports_8be200fadbe143dc = function(arg0) { + imports.wbg.__wbg_getrtctransports_3911836191336767 = function(arg0) { const ret = arg0.get_rtc_transports; return ret; }; @@ -2664,7 +2751,7 @@ function __wbg_get_imports() { const ret = arg0.handle; return ret; }; - imports.wbg.__wbg_ishomeserverconnected_dc5057f7242a591e = function(arg0) { + imports.wbg.__wbg_ishomeserverconnected_751e70b3c02b3223 = function(arg0) { const ret = arg0.is_homeserver_connected; return ret; }; @@ -2712,6 +2799,10 @@ function __wbg_get_imports() { const ret = arg0.on_memberships_change; return ret; }; + imports.wbg.__wbg_onsessionchange_799b89dbe5987804 = function(arg0) { + const ret = arg0.on_session_change; + return ret; + }; imports.wbg.__wbg_onstatuschange_926e83644f91f32d = function(arg0) { const ret = arg0.on_status_change; return ret; @@ -2734,11 +2825,11 @@ function __wbg_get_imports() { imports.wbg.__wbg_randomFillSync_f8c153b79f285817 = function() { return handleError(function (arg0, arg1) { arg0.randomFillSync(arg1); }, arguments) }; - imports.wbg.__wbg_readevents_98385cdfe47bdeee = function(arg0) { + imports.wbg.__wbg_readevents_73801c97c6d3e238 = function(arg0) { const ret = arg0.read_events; return ret; }; - imports.wbg.__wbg_readstate_a52da7153b66ed2b = function(arg0) { + imports.wbg.__wbg_readstate_98bb4b03f7217a30 = function(arg0) { const ret = arg0.read_state; return ret; }; @@ -2817,7 +2908,7 @@ function __wbg_get_imports() { const ret = arg0.send_sticky_event; return ret; }; - imports.wbg.__wbg_sendtodevice_a3e33fb31230ba64 = function(arg0) { + imports.wbg.__wbg_sendtodevice_7aac4e0ebd535903 = function(arg0) { const ret = arg0.send_to_device; return ret; }; @@ -2848,19 +2939,19 @@ function __wbg_get_imports() { const ret = arg0.subarray(arg1 >>> 0, arg2 >>> 0); return ret; }; - imports.wbg.__wbg_subscribeconnectivity_a75e094330a03e3e = function(arg0) { + imports.wbg.__wbg_subscribeconnectivity_8fdd26bf00625517 = function(arg0) { const ret = arg0.subscribe_connectivity; return ret; }; - imports.wbg.__wbg_subscriberoomevents_2e4d5ca6372fe4cd = function(arg0) { + imports.wbg.__wbg_subscriberoomevents_d547d19b370bf4a1 = function(arg0) { const ret = arg0.subscribe_room_events; return ret; }; - imports.wbg.__wbg_subscribestateupdates_06939632cde2db00 = function(arg0) { + imports.wbg.__wbg_subscribestateupdates_376ee2dec3ce8226 = function(arg0) { const ret = arg0.subscribe_state_updates; return ret; }; - imports.wbg.__wbg_subscribetodeviceevents_afcc4eb08f3d890c = function(arg0) { + imports.wbg.__wbg_subscribetodeviceevents_a2b80a0df19c8813 = function(arg0) { const ret = arg0.subscribe_to_device_events; return ret; }; @@ -2876,6 +2967,10 @@ function __wbg_get_imports() { const ret = arg0.uniffi_clone; return ret; }; + imports.wbg.__wbg_unifficlone_6b800bc71dff8203 = function(arg0) { + const ret = arg0.uniffi_clone; + return ret; + }; imports.wbg.__wbg_unifficlone_95a28cf009142cf6 = function(arg0) { const ret = arg0.uniffi_clone; return ret; @@ -2908,6 +3003,10 @@ function __wbg_get_imports() { const ret = arg0.uniffi_free; return ret; }; + imports.wbg.__wbg_uniffifree_8bebc19643df1faf = function(arg0) { + const ret = arg0.uniffi_free; + return ret; + }; imports.wbg.__wbg_uniffifree_af6c094a1e08186f = function(arg0) { const ret = arg0.uniffi_free; return ret; @@ -2929,12 +3028,12 @@ function __wbg_get_imports() { const ret = false; return ret; }; - imports.wbg.__wbindgen_closure_wrapper2151 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 520, __wbg_adapter_24); + imports.wbg.__wbindgen_closure_wrapper2259 = function(arg0, arg1, arg2) { + const ret = makeMutClosure(arg0, arg1, 551, __wbg_adapter_24); return ret; }; - imports.wbg.__wbindgen_closure_wrapper2175 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 532, __wbg_adapter_27); + imports.wbg.__wbindgen_closure_wrapper2283 = function(arg0, arg1, arg2) { + const ret = makeMutClosure(arg0, arg1, 563, __wbg_adapter_27); return ret; }; imports.wbg.__wbindgen_init_externref_table = function() { diff --git a/src/matrix-rtc-sdk/generated/wasm-bindgen/index_bg.wasm b/src/matrix-rtc-sdk/generated/wasm-bindgen/index_bg.wasm index 26f57cbad674a856f1439b2882b63625eba4bc7e..972914482f2ce5993883dcd13220ceedd86cfcb4 100644 GIT binary patch delta 420332 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
lxzrp45skIVijWWy=^oI6P|l;H@jaFS}m$VSOx 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 PqB}Wc?24~uWsd&?bKX#* delta 396325 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'MM<}(4ir*-37#Wvg-!p30 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 diff --git a/src/matrix-rtc-sdk/index.test.ts b/src/matrix-rtc-sdk/index.test.ts index d22bd7215..5f75385a7 100644 --- a/src/matrix-rtc-sdk/index.test.ts +++ b/src/matrix-rtc-sdk/index.test.ts @@ -53,7 +53,7 @@ describe("matrix-rtc-sdk", () => { }); const [session] = computeSessionsFromEvents( [join], - FfiElementCallCompat.StickyEvents, + FfiElementCallCompat.Off, ); expect(session.memberCount).toBe(1); expect(session.members[0].eventId).toBe("$1"); @@ -69,7 +69,7 @@ describe("matrix-rtc-sdk", () => { "MYDEV", driver, { - compat: FfiElementCallCompat.StickyEvents, + compat: FfiElementCallCompat.Off, manageMediaKeys: false, requireCrossSignedSender: false, useKeyDelayMs: 1000n, @@ -102,7 +102,10 @@ class InertDriver implements MatrixDriverCallback { public async cancelDelayedEvent(): Promise { return Promise.resolve(); } - public async delegateLivekitDelayedLeave(): Promise { + public async delegateDelayedLeaveViaHomeserver(): Promise { + return Promise.resolve(); + } + public async delegateDelayedLeaveViaTransport(): Promise { return Promise.resolve(); } public async sendToDevice( diff --git a/src/matrix-rtc-sdk/index.ts b/src/matrix-rtc-sdk/index.ts index 6db8b385d..62278771c 100644 --- a/src/matrix-rtc-sdk/index.ts +++ b/src/matrix-rtc-sdk/index.ts @@ -25,7 +25,10 @@ export { FfiElementCallCompat, FfiEventOrigin, FfiStatus, + FfiDelegationRoute, + FfiDeviceAttribution, FfiDisconnectCause, + FfiImpairment, FfiJoinError, FfiKeepAlive, FfiMembershipState, @@ -36,6 +39,7 @@ export { export type { FfiConnectionData, FfiConnectionWithMembers, + FfiHomeserverDelegationRequest, FfiJoinParams, FfiLivekitToken, FfiLivekitTokenRequest, @@ -48,6 +52,7 @@ export type { FfiSessionSnapshot, FfiToDeviceDelivery, FfiToDeviceRecipient, + FfiTransportDelegationRequest, ConnectivitySinkLike, MatrixDriverCallback, RoomEventSinkLike, diff --git a/src/room/InCallView.tsx b/src/room/InCallView.tsx index 5f706cabd..8a88e2514 100644 --- a/src/room/InCallView.tsx +++ b/src/room/InCallView.tsx @@ -44,7 +44,7 @@ import { InviteButton } from "../button/InviteButton"; import { type CallViewModel, callViewModelOptionsFromParams, - createCallViewModel$, + createJsClientCallViewModel$, } from "../state/CallViewModel/CallViewModel.ts"; import { Grid, type TileProps } from "../grid/Grid"; import { SpotlightTile } from "../tile/SpotlightTile"; @@ -132,7 +132,7 @@ export const ActiveCall: FC = (props) => { const { autoLeaveWhenOthersLeft, waitForCallPickup, sendNotificationType } = urlParams; - const vm = createCallViewModel$( + const vm = createJsClientCallViewModel$( scope, props.rtcSession, props.matrixRoom, diff --git a/src/state/CallViewModel/CallNotificationLifecycle.test.ts b/src/state/CallViewModel/CallNotificationLifecycle.test.ts index e5281cf65..8e81425c4 100644 --- a/src/state/CallViewModel/CallNotificationLifecycle.test.ts +++ b/src/state/CallViewModel/CallNotificationLifecycle.test.ts @@ -6,12 +6,6 @@ Please see LICENSE in the repository root for full details. */ import { test } from "vitest"; -import { - EventType, - type IRoomTimelineData, - MatrixEvent, - type Room, -} from "matrix-js-sdk"; import { type RTCCallIntent } from "matrix-js-sdk/lib/matrixrtc"; import { map, mergeMap, NEVER, type Observable, startWith } from "rxjs"; @@ -182,22 +176,10 @@ test("ring attempt can be declined", () => { a: mockRingEvent("$notif1", 30), }), receivedDecline$: hot("--d", { - d: [ - new MatrixEvent({ - type: EventType.RTCDecline, - sender: alice.userId, - content: { - "m.relates_to": { - rel_type: "m.reference", - event_id: "$notif1", - }, - }, - }), - {} as Room, - undefined, - false, - {} as IRoomTimelineData, - ], + d: { + sender: alice.userId, + relatesTo: { relType: "m.reference", eventId: "$notif1" }, + }, }), }); @@ -217,22 +199,10 @@ test("ring attempt times out if recipient declines too late", () => { a: mockRingEvent("$notif1", 30), }), receivedDecline$: hot("100ms d", { - d: [ - new MatrixEvent({ - type: EventType.RTCDecline, - sender: alice.userId, - content: { - "m.relates_to": { - rel_type: "m.reference", - event_id: "$notif1", - }, - }, - }), - {} as Room, - undefined, - false, - {} as IRoomTimelineData, - ], + d: { + sender: alice.userId, + relatesTo: { relType: "m.reference", eventId: "$notif1" }, + }, }), }); @@ -252,22 +222,13 @@ test("decline event relating to wrong event is ignored (times out)", () => { a: mockRingEvent("$notif1", 30), }), receivedDecline$: hot("--d", { - d: [ - new MatrixEvent({ - type: EventType.RTCDecline, - sender: alice.userId, - content: { - "m.relates_to": { - rel_type: "m.reference", - event_id: "$other", // <---- WRONG - }, - }, - }), - {} as Room, - undefined, - false, - {} as IRoomTimelineData, - ], + d: { + sender: alice.userId, + relatesTo: { + relType: "m.reference", + eventId: "$other", // <---- WRONG + }, + }, }), }); @@ -287,22 +248,13 @@ test("decline event from wrong sender is ignored (times out)", () => { a: mockRingEvent("$notif1", 30), }), receivedDecline$: hot("--d", { - d: [ - new MatrixEvent({ - type: EventType.RTCDecline, - sender: local.userId, // <---- WRONG - content: { - "m.relates_to": { - rel_type: "m.reference", - event_id: "$notif1", - }, - }, - }), - {} as Room, - undefined, - false, - {} as IRoomTimelineData, - ], + d: { + sender: local.userId, // <---- WRONG + relatesTo: { + relType: "m.reference", + eventId: "$notif1", + }, + }, }), }); diff --git a/src/state/CallViewModel/CallNotificationLifecycle.ts b/src/state/CallViewModel/CallNotificationLifecycle.ts index 59930fd64..a6de3483e 100644 --- a/src/state/CallViewModel/CallNotificationLifecycle.ts +++ b/src/state/CallViewModel/CallNotificationLifecycle.ts @@ -37,7 +37,6 @@ import { logger as rootLogger } from "matrix-js-sdk/lib/logger"; import { type Behavior } from "../Behavior"; import { type Epoch, type ObservableScope } from "../ObservableScope"; -import { type RoomMemberMap } from "./remoteMembers/MatrixMemberMetadata"; export type AutoLeaveReason = "allOthersLeft" | "timeout" | "decline"; @@ -69,24 +68,42 @@ export function createSentCallNotification$( return sentCallNotification$; } +/** A received `org.matrix.msc4310.rtc.decline`, as far as ringing cares. */ +export interface DeclineEvent { + sender: string; + /** The `m.relates_to` of the event, when it has one. */ + relatesTo: { relType?: string; eventId?: string } | undefined; +} + export function createReceivedDecline$( matrixRoom: MatrixRoom, -): Observable> { +): Observable { return ( fromEvent(matrixRoom, RoomEvent.Timeline) as Observable< Parameters > - ).pipe(filter(([event]) => event.getType() === EventType.RTCDecline)); + ).pipe( + filter(([event]) => event.getType() === EventType.RTCDecline), + map(([event]) => { + const relation = event.getRelation(); + return { + sender: event.getSender() ?? "", + relatesTo: relation + ? { relType: relation.rel_type, eventId: relation.event_id } + : undefined, + }; + }), + ); } export interface Props { scope: ObservableScope; - memberships$: Behavior>; - matrixRoomMembers$: Behavior; + /** The call's members; only who they are matters here. */ + memberships$: Behavior[]>>; + /** The room's members; only who they are matters here. */ + matrixRoomMembers$: Behavior>; sentCallNotification$: Observable; - receivedDecline$: Observable< - Parameters - >; + receivedDecline$: Observable; options: { waitForCallPickup?: boolean; autoLeaveWhenOthersLeft?: boolean }; localUser: { deviceId: string; userId: string }; } @@ -147,10 +164,10 @@ export function createCallNotificationLifecycle$({ // Call is declined when we receive a decline event const decline$ = receivedDecline$.pipe( filter( - ([event]) => - event.getRelation()?.rel_type === "m.reference" && - event.getRelation()?.event_id === notificationEvent.event_id && - event.getSender() === recipient, + (event) => + event.relatesTo?.relType === "m.reference" && + event.relatesTo.eventId === notificationEvent.event_id && + event.sender === recipient, ), map(() => "decline" as const), ); diff --git a/src/state/CallViewModel/CallViewModel.participation.test.ts b/src/state/CallViewModel/CallViewModel.participation.test.ts new file mode 100644 index 000000000..32a8d78f3 --- /dev/null +++ b/src/state/CallViewModel/CallViewModel.participation.test.ts @@ -0,0 +1,224 @@ +/* +Copyright 2026 Element Creations Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE in the repository root for full details. +*/ + +/** + * `createCallViewModel$` over a real `CallParticipation` (the crate, through + * the mock drivers) and mocked LiveKit connections: the Matrix side end to + * end, from the user's join to the roster and back out. + * + * Real wasm, real timers — nothing here may use `vi.useFakeTimers`. + */ + +import { beforeAll, describe, expect, it } from "vitest"; +import { BehaviorSubject } from "rxjs"; +import { type Room as LivekitRoom } from "livekit-client"; + +import { MatrixRTCMode } from "../../config/ConfigOptions"; +import { E2eeType } from "../../e2ee/e2eeType"; +import { MockElementCallMatrixClientDriver } from "../../driver/MockElementCallMatrixClientDriver"; +import { + MOCK_LK_SERVICE_URL, + MockRtcMatrixDriver, + slotEvent, + waitFor, +} from "../../driver/MockRtcMatrixDriver"; +import { FfiStatus } from "../../matrix-rtc-sdk"; +import { type RaisedHandInfo, type ReactionInfo } from "../../reactions"; +import { MatrixRTCTransportMissingError } from "../../utils/errors"; +import { + MockConnection, + mockConfig, + mockLivekitRoom, + mockLocalParticipant, + mockMediaDevices, + mockMuteStates, + testScope, +} from "../../utils/test"; +import { initMatrixRtcSdkForTests } from "../../utils/test-matrix-rtc"; +import { constant } from "../Behavior"; +import { CallParticipation } from "../rtc/CallParticipation"; +import { joinParamsFromConfig, participationConfig } from "../rtc/joinParams"; +import { type CallViewModel, createCallViewModel$ } from "./CallViewModel"; + +mockConfig({}); + +const session = { + delayed_leave: { delay_ms: 15_000 }, + delegated_delayed_leave: { delay_ms: 3_600_000 }, + network_error_retry_ms: 1000, + wait_for_key_rotation_ms: 50, +}; + +const peer = { + userId: "@peer:example.org", + deviceId: "PEERDEV", + memberId: "m-peer", +}; + +function createEnvironment(driver: MockRtcMatrixDriver): { + vm: CallViewModel; + participation: CallParticipation; + clientDriver: MockElementCallMatrixClientDriver; +} { + const scope = testScope(); + const clientDriver = new MockElementCallMatrixClientDriver({ + userId: driver.userId, + deviceId: driver.deviceId, + roomId: driver.roomId, + members: [ + { + userId: driver.userId, + displayName: "Me", + avatarUrl: null, + membership: "join", + }, + { + userId: peer.userId, + displayName: "Peer", + avatarUrl: null, + membership: "join", + }, + ], + }); + const participation = new CallParticipation( + scope, + driver, + driver.roomId, + driver.userId, + driver.deviceId, + { + config: participationConfig({ + mode: MatrixRTCMode.Matrix_2_0, + manageMediaKeys: false, + session, + }), + }, + ); + const livekitRoomFactory = (): LivekitRoom => + mockLivekitRoom({ + localParticipant: mockLocalParticipant({ identity: "" }), + remoteParticipants: new Map(), + disconnect: async () => Promise.resolve(), + setE2EEEnabled: async () => Promise.resolve(), + }); + const vm = createCallViewModel$( + scope, + participation, + clientDriver, + mockMediaDevices({}), + mockMuteStates(), + { + encryptionSystem: { kind: E2eeType.NONE }, + autoLeaveWhenOthersLeft: false, + livekitRoomFactory, + connectionFactory: { + createConnection(scope, transport, ownMembershipIdentity, logger, sfu) { + return new MockConnection( + { + scope, + transport, + ownMembershipIdentity, + existingSFUConfig: sfu, + client: null, + roomId: driver.roomId, + livekitRoomFactory, + }, + logger, + ); + }, + }, + windowSize$: constant({ width: 1000, height: 800 }), + joinParams: joinParamsFromConfig({ + session, + delegateDelayedLeave: false, + }), + }, + new BehaviorSubject>({}), + new BehaviorSubject>({}), + constant({ processor: undefined, supported: false }), + ); + return { vm, participation, clientDriver }; +} + +describe("createCallViewModel$ over a CallParticipation", () => { + beforeAll(async () => { + await initMatrixRtcSdkForTests(); + }); + + it("joins through the crate, lists the members and leaves again", async () => { + // Somebody already started the call: the slot is open. + const driver = new MockRtcMatrixDriver({ + roomState: [slotEvent({ status: "open" })], + }); + const { vm, participation } = createEnvironment(driver); + expect(vm.participantCount$.value).toBe(0); + expect(vm.connected$.value).toBe(false); + + vm.join(); + await waitFor("the crate to be connected", () => + FfiStatus.Connected.instanceOf(participation.status$.value), + ); + // The crate discovered the transport and minted our token; the view + // model holds a connection to it. + await waitFor( + "our connection", + () => vm.allConnections$.value.getConnections().length === 1, + ); + expect( + vm.allConnections$.value.getConnections()[0].transport + .livekit_service_url, + ).toBe(MOCK_LK_SERVICE_URL); + // Our own membership echoed back: we are a member with our device. + await waitFor( + "our own tile", + () => vm.localMatrixLivekitMember$.value !== null, + ); + expect(vm.localMatrixLivekitMember$.value?.membership$.value).toMatchObject( + { userId: driver.userId, deviceId: driver.deviceId }, + ); + expect(vm.participantCount$.value).toBe(1); + expect(vm.fatalError$.value).toBeNull(); + + driver.peerJoins(peer); + await waitFor( + "the peer's tile", + () => vm.remoteMatrixLivekitMembers$.value.length === 1, + ); + const [remote] = vm.remoteMatrixLivekitMembers$.value; + expect(remote.membership$.value).toMatchObject({ + userId: peer.userId, + memberId: peer.memberId, + }); + // Both publish on the same service: one connection carries both. + expect(remote.connection$.value?.transport.livekit_service_url).toBe( + MOCK_LK_SERVICE_URL, + ); + expect(vm.participantCount$.value).toBe(2); + + vm.leave(); + await waitFor("the crate to be disconnected", () => + FfiStatus.Disconnected.instanceOf(participation.status$.value), + ); + await waitFor( + "our tile to go", + () => vm.localMatrixLivekitMember$.value === null, + ); + expect(vm.fatalError$.value).toBeNull(); + }); + + it("shows the crate's join failure as the fatal error", async () => { + // The homeserver advertises no transport and there is no fallback. + const driver = new MockRtcMatrixDriver({ + roomState: [slotEvent({ status: "open" })], + transports: [], + }); + const { vm } = createEnvironment(driver); + vm.join(); + await waitFor("the fatal error", () => vm.fatalError$.value !== null); + expect(vm.fatalError$.value).toBeInstanceOf(MatrixRTCTransportMissingError); + }); +}); diff --git a/src/state/CallViewModel/CallViewModel.ts b/src/state/CallViewModel/CallViewModel.ts index 957a56fad..8d5f262b7 100644 --- a/src/state/CallViewModel/CallViewModel.ts +++ b/src/state/CallViewModel/CallViewModel.ts @@ -109,6 +109,7 @@ import { createHomeserverConnected$ } from "./localMember/HomeserverConnected.ts import { createLocalMembership$, enterRTCSession, + type LocalMembership, TransportState, } from "./localMember/LocalMember.ts"; import { @@ -138,10 +139,13 @@ import { createCallNotificationLifecycle$, createReceivedDecline$, createSentCallNotification$, + type RingAttempt, } from "./CallNotificationLifecycle.ts"; import { createMatrixMemberMetadata$, createRoomMembers$, + type MatrixMemberMetadata, + type RoomMemberMap, } from "./remoteMembers/MatrixMemberMetadata.ts"; import { Publisher } from "./localMember/Publisher.ts"; import { type Connection } from "./remoteMembers/Connection.ts"; @@ -163,6 +167,25 @@ import { type RingingMediaViewModel, } from "../media/RingingMediaViewModel.ts"; import { type GridTileViewModel } from "../TileViewModel.ts"; +import { mapEpoch } from "../ObservableScope.ts"; +import { type CallParticipation } from "../rtc/CallParticipation.ts"; +import { joinParamsFromConfig } from "../rtc/joinParams.ts"; +import { type FfiJoinParams } from "../../matrix-rtc-sdk"; +import { type ElementCallMatrixClientDriver } from "../../driver/ElementCallMatrixClientDriver.ts"; +import { observeDriver } from "../../driver/observe.ts"; +import { ParticipationKeyProvider } from "../../e2ee/participationKeyProvider.ts"; +import { customLivekitUrl } from "../../settings/settings.ts"; +import { createParticipationConnectionManager$ } from "./remoteMembers/ParticipationConnections.ts"; +import { + callMemberOf, + createParticipationRemoteMembers$, +} from "./remoteMembers/ParticipationMembers.ts"; +import { createParticipationRoomMembers$ } from "./remoteMembers/ParticipationMemberMetadata.ts"; +import { createParticipationLocalMembership$ } from "./localMember/ParticipationLocalMember.ts"; +import { + createParticipationReceivedDecline$, + createParticipationSentCallNotification$, +} from "./ParticipationCallNotification.ts"; //TODO // Larger rename @@ -222,6 +245,12 @@ export interface CallViewModelOptions { matrixRTCMode?: MatrixRTCMode; /** Optional behavior overriding for the screensharing, for testing */ toggleScreensharing?: () => void; + /** + * How to join the MatrixRTC session. Only {@link createCallViewModel$} + * reads it; defaults to {@link joinParamsFromConfig} over the deployment's + * `matrix_rtc_session` configuration and {@link callIntent}. + */ + joinParams?: FfiJoinParams; } /** @@ -491,7 +520,7 @@ export interface CallViewModel { // Throughout this class and related code we must distinguish between MatrixRTC // state and LiveKit state. We use the common terminology of room "members", RTC // "memberships", and LiveKit "participants". -export function createCallViewModel$( +export function createJsClientCallViewModel$( scope: ObservableScope, // A call is permanently tied to a single Matrix room matrixRTCSession: MatrixRTCSession, @@ -515,8 +544,6 @@ export function createCallViewModel$( const { hostBridge = nullHostBridge, controlledAudioDevices = false, - header = HeaderStyle.Standard, - showControls = true, hideScreensharing = false, sendNotificationType, callIntent, @@ -741,9 +768,86 @@ export function createCallViewModel$( options, localUser: { userId, deviceId }, }); + const keyRotationSuppressed$ = createKeyRotationSuppressed$( + scope, + matrixRTCSession, + ); + + return assembleCallViewModel( + scope, + { + localMembership, + matrixLivekitMembers$, + remoteMatrixLivekitMembers$, + localMatrixLivekitMember$, + matrixMemberMetadataStore, + matrixRoomMembers$, + ringAttempts$, + autoLeave$, + connectionManagerData$: connectionManager.connectionManagerData$, + keyRotationSuppressed$, + }, + options, + mediaDevices, + handsRaisedSubject$, + reactionsSubject$, + ); +} + +/** + * The Matrix-side inputs the call view model is assembled from: what a + * MatrixRTC implementation has to provide so that the rest — tiles, layout, + * sounds, header and footer — is the same whichever one it is. + * + * {@link createJsClientCallViewModel$} builds it from matrix-js-sdk's + * `MatrixRTCSession`; {@link createCallViewModel$} from a + * {@link CallParticipation} over the drivers. + */ +export interface CallViewModelCore { + localMembership: LocalMembership; + matrixLivekitMembers$: Behavior< + (LocalMatrixLivekitMember | RemoteMatrixLivekitMember)[] + >; + remoteMatrixLivekitMembers$: Behavior>; + localMatrixLivekitMember$: Behavior; + matrixMemberMetadataStore: MatrixMemberMetadata; + /** The room's members, for the ringing name and the name-tag threshold. */ + matrixRoomMembers$: Behavior; + ringAttempts$: Observable; + autoLeave$: Observable; + connectionManagerData$: Behavior>; + keyRotationSuppressed$: Behavior; +} + +/** The half of the view model that does not care where the call comes from. */ +function assembleCallViewModel( + scope: ObservableScope, + { + localMembership, + matrixLivekitMembers$, + remoteMatrixLivekitMembers$, + localMatrixLivekitMember$, + matrixMemberMetadataStore, + matrixRoomMembers$, + ringAttempts$, + autoLeave$, + connectionManagerData$, + keyRotationSuppressed$, + }: CallViewModelCore, + options: CallViewModelOptions, + mediaDevices: MediaDevices, + handsRaisedSubject$: Observable>, + reactionsSubject$: Observable>, +): CallViewModel { + const logger = rootLogger.getChild("[CallViewModel]"); + const { + hostBridge = nullHostBridge, + header = HeaderStyle.Standard, + showControls = true, + } = options; const allConnections$ = scope.behavior( - connectionManager.connectionManagerData$.pipe(map((d) => d.value)), + connectionManagerData$.pipe(map((d) => d.value)), ); const livekitRoomItems$ = scope.behavior( remoteMatrixLivekitMembers$.pipe( @@ -838,7 +942,9 @@ export function createCallViewModel$( createWrappedUserMedia(scope, { id: `${mediaId}:${dup}`, userId, - rtcBackendIdentity: rtcId, + // Shown for debugging only; a member whose identity is not yet + // known has none to show. + rtcBackendIdentity: rtcId ?? "", participant, encryptionSystem: options.encryptionSystem, livekitRoom$: scope.behavior( @@ -946,11 +1052,6 @@ export function createCallViewModel$( matrixLivekitMembers$.pipe(map((ms) => ms.length)), ); - const keyRotationSuppressed$ = createKeyRotationSuppressed$( - scope, - matrixRTCSession, - ); - const leaveSoundEffect$ = userMedia$.pipe( pairwise(), filter( @@ -1923,6 +2024,242 @@ export function createCallViewModel$( }; } +/** + * The call view model over the host's drivers: a {@link CallParticipation} + * (the crate: memberships, connections and their tokens, media keys, our own + * membership) and an {@link ElementCallMatrixClientDriver} (the room's + * members and metadata, the timeline for notifications). + * + * The counterpart of {@link createJsClientCallViewModel$}, which reads the + * same things from matrix-js-sdk; both assemble the same view model. + */ +export function createCallViewModel$( + scope: ObservableScope, + participation: CallParticipation, + clientDriver: ElementCallMatrixClientDriver, + mediaDevices: MediaDevices, + muteStates: MuteStates, + options: CallViewModelOptions, + handsRaisedSubject$: Observable>, + reactionsSubject$: Observable>, + trackProcessorState$: Behavior, +): CallViewModel { + const logger = rootLogger.getChild("[CallViewModel]"); + const { userId, deviceId, roomId } = clientDriver; + const { + hostBridge = nullHostBridge, + controlledAudioDevices = false, + hideScreensharing = false, + callIntent, + } = options; + + const livekitKeyProvider = getParticipationKeyProvider( + options.encryptionSystem, + scope, + participation, + logger, + ); + + // ------------------------------------------------------------------------ + // connections and remote members + + const connectionFactory = + options.connectionFactory ?? + new ECConnectionFactory( + // The crate mints every token; no connection fetches its own. + null, + roomId, + mediaDevices, + trackProcessorState$, + livekitKeyProvider, + controlledAudioDevices, + options.livekitRoomFactory, + ); + + const connectionManager = createParticipationConnectionManager$({ + scope, + participation, + connectionFactory, + ownIdentity: { userId, deviceId }, + logger, + }); + + const remoteMatrixLivekitMembers$ = createParticipationRemoteMembers$({ + scope, + participation, + connectionManager, + }); + + // ------------------------------------------------------------------------ + // localMembership + + const roomInfo$ = observeDriver( + scope, + () => clientDriver.getRoomInfo(), + (listener) => clientDriver.subscribeRoomInfo(listener), + ); + // Whether the homeserver takes sticky events decides how a failed first + // send reads; assume it does until the driver says otherwise. + let stickyEventsSupported = true; + clientDriver.getCapabilities().then( + (capabilities) => { + stickyEventsSupported = capabilities.stickyEvents; + }, + (e) => logger.warn("Could not read the driver's capabilities", e), + ); + + const localMembership = createParticipationLocalMembership$({ + scope, + participation, + connectionManager, + createPublisherFactory: (connection: Connection) => + new Publisher( + connection, + mediaDevices, + muteStates, + trackProcessorState$, + logger.getChild( + "[Publisher " + connection.transport.livekit_service_url + "]", + ), + controlledAudioDevices, + ), + muteStates, + hideScreensharing, + hostBridge, + joinParams: + options.joinParams ?? + joinParamsFromConfig({ + session: Config.get().matrix_rtc_session, + callIntent, + }), + slotPolicy$: scope.behavior( + roomInfo$.pipe( + map((info) => ({ + encrypted: info.encrypted, + canOpen: info.canOpenSlot, + })), + ), + ), + customLivekitUrl$: customLivekitUrl.value$, + disconnectContext: () => ({ + domain: userId.slice(userId.indexOf(":") + 1), + stickyEventsSupported, + }), + roomId, + logger: logger.getChild(`[${Date.now()}]`), + }); + + const localMatrixLivekitMember$: Behavior = + scope.behavior( + participation.ownMembership$.pipe( + map((membership) => + membership === null ? null : callMemberOf(membership), + ), + filterBehavior((member) => member !== null), + map((membership$) => { + if (membership$ === null) return null; + return { + membership$, + participant: { + type: "local" as const, + value$: localMembership.participant$, + }, + connection$: localMembership.connection$, + userId, + }; + }), + ), + ); + + const matrixLivekitMembers$ = scope.behavior( + combineLatest( + [localMatrixLivekitMember$, remoteMatrixLivekitMembers$], + (local, remote) => [...(local === null ? [] : [local]), ...remote.value], + ), + ); + + // ------------------------------------------------------------------------ + // matrixMemberMetadataStore + + const matrixRoomMembers$ = createParticipationRoomMembers$( + scope, + clientDriver, + ); + const callMemberUserIds$ = scope.behavior( + participation.memberships$.pipe( + mapEpoch((memberships) => + memberships.map((m) => ({ userId: m.member.userId })), + ), + ), + ); + const matrixMemberMetadataStore = createMatrixMemberMetadata$( + scope, + scope.behavior(callMemberUserIds$.pipe(map((ms) => ms.value))), + matrixRoomMembers$, + ); + + // ------------------------------------------------------------------------ + // callLifecycle + + const { ringAttempts$, autoLeave$ } = createCallNotificationLifecycle$({ + scope, + memberships$: callMemberUserIds$, + matrixRoomMembers$, + sentCallNotification$: createParticipationSentCallNotification$({ + scope, + participation, + timeline: clientDriver, + options, + logger, + }), + receivedDecline$: createParticipationReceivedDecline$(clientDriver), + options, + localUser: { userId, deviceId }, + }); + + return assembleCallViewModel( + scope, + { + localMembership, + matrixLivekitMembers$, + remoteMatrixLivekitMembers$, + localMatrixLivekitMember$, + matrixMemberMetadataStore, + matrixRoomMembers$, + ringAttempts$, + autoLeave$, + connectionManagerData$: connectionManager.connectionManagerData$, + // The crate has no participant limit for key rotation. + keyRotationSuppressed$: constant(false), + }, + options, + mediaDevices, + handsRaisedSubject$, + reactionsSubject$, + ); +} + +function getParticipationKeyProvider( + e2eeSystem: EncryptionSystem, + scope: ObservableScope, + participation: CallParticipation, + logger: Logger, +): BaseKeyProvider | undefined { + if (e2eeSystem.kind === E2eeType.NONE) return undefined; + + if (e2eeSystem.kind === E2eeType.PER_PARTICIPANT) { + const keyProvider = new ParticipationKeyProvider(); + keyProvider.attach(scope, participation); + return keyProvider; + } else if (e2eeSystem.kind === E2eeType.SHARED_KEY && e2eeSystem.secret) { + const keyProvider = new ExternalE2EEKeyProvider(); + keyProvider + .setKey(e2eeSystem.secret) + .catch((e) => logger.error("Failed to set shared key for E2EE", e)); + return keyProvider; + } +} + function getE2eeKeyProvider( e2eeSystem: EncryptionSystem, rtcSession: MatrixRTCSession, diff --git a/src/state/CallViewModel/CallViewModelTestUtils.ts b/src/state/CallViewModel/CallViewModelTestUtils.ts index 5a3fa3378..ddd0929d3 100644 --- a/src/state/CallViewModel/CallViewModelTestUtils.ts +++ b/src/state/CallViewModel/CallViewModelTestUtils.ts @@ -26,7 +26,7 @@ import { E2eeType } from "../../e2ee/e2eeType"; import { type RaisedHandInfo, type ReactionInfo } from "../../reactions"; import { type CallViewModel, - createCallViewModel$, + createJsClientCallViewModel$, type CallViewModelOptions, } from "./CallViewModel"; import { @@ -197,7 +197,7 @@ export function withCallViewModel(mode: MatrixRTCMode) { setE2EEEnabled: async () => Promise.resolve(), }); - const vm = createCallViewModel$( + const vm = createJsClientCallViewModel$( testScope(), rtcSession.asMockedSession(), room, diff --git a/src/state/CallViewModel/ParticipationCallNotification.test.ts b/src/state/CallViewModel/ParticipationCallNotification.test.ts new file mode 100644 index 000000000..99cbddab2 --- /dev/null +++ b/src/state/CallViewModel/ParticipationCallNotification.test.ts @@ -0,0 +1,142 @@ +/* +Copyright 2026 Element Creations Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE in the repository root for full details. +*/ + +import { describe, expect, it } from "vitest"; +import { logger } from "matrix-js-sdk/lib/logger"; + +import { testScope } from "../../utils/test"; +import { + FakeParticipation, + fakeMembership, +} from "../../utils/test-participation"; +import { MockElementCallMatrixClientDriver } from "../../driver/MockElementCallMatrixClientDriver"; +import { waitFor } from "../../driver/MockRtcMatrixDriver"; +import { type DeclineEvent } from "./CallNotificationLifecycle"; +import { + createParticipationReceivedDecline$, + createParticipationSentCallNotification$, + RTC_DECLINE_EVENT_TYPE, + RTC_NOTIFICATION_EVENT_TYPE, +} from "./ParticipationCallNotification"; + +const own = fakeMembership({ + member: { memberId: "m-me", userId: "@me:x", eventId: "$my-join" }, +}); +const peer = fakeMembership({ member: { memberId: "m-peer" } }); + +describe("createParticipationSentCallNotification$", () => { + it("rings once our membership echoes back, if we were first, and again after a rejoin", async () => { + const participation = new FakeParticipation(); + const timeline = new MockElementCallMatrixClientDriver(); + const sent$ = createParticipationSentCallNotification$({ + scope: testScope(), + participation, + timeline, + options: { sendNotificationType: "ring", callIntent: "video" }, + logger, + }); + expect(sent$.value).toBeNull(); + + // Our echo arrives; the roster has only us. + participation.setMemberships([own]); + participation.ownMembership$.next(own); + await waitFor("notification sent", () => sent$.value !== null); + const [call] = timeline.calls("sendRoomEvent"); + expect(call.eventType).toBe(RTC_NOTIFICATION_EVENT_TYPE); + expect(call.content).toMatchObject({ + notification_type: "ring", + "m.call.intent": "video", + "m.relates_to": { event_id: "$my-join", rel_type: "m.reference" }, + lifetime: 90_000, + "m.mentions": { user_ids: [], room: true }, + }); + expect(sent$.value).toMatchObject({ + event_id: call.eventId, + notification_type: "ring", + }); + + // A refresh of our membership is not a join. + participation.ownMembership$.next({ ...own }); + expect(timeline.calls("sendRoomEvent")).toHaveLength(1); + + // We leave and come back alone: the room rings again. + participation.ownMembership$.next(null); + participation.setMemberships([]); + expect(sent$.value).toBeNull(); + participation.setMemberships([own]); + participation.ownMembership$.next(own); + await waitFor( + "second notification", + () => timeline.calls("sendRoomEvent").length === 2, + ); + }); + + it("does not ring when somebody was in the session before us", async () => { + const participation = new FakeParticipation(); + const timeline = new MockElementCallMatrixClientDriver(); + const sent$ = createParticipationSentCallNotification$({ + scope: testScope(), + participation, + timeline, + options: { sendNotificationType: "ring" }, + logger, + }); + participation.setMemberships([peer, own]); + participation.ownMembership$.next(own); + await new Promise((resolve) => setTimeout(resolve, 20)); + expect(timeline.calls("sendRoomEvent")).toEqual([]); + expect(sent$.value).toBeNull(); + }); + + it("does nothing without a notification type", async () => { + const participation = new FakeParticipation(); + const timeline = new MockElementCallMatrixClientDriver(); + createParticipationSentCallNotification$({ + scope: testScope(), + participation, + timeline, + options: {}, + logger, + }); + participation.setMemberships([own]); + participation.ownMembership$.next(own); + await new Promise((resolve) => setTimeout(resolve, 20)); + expect(timeline.calls("sendRoomEvent")).toEqual([]); + }); +}); + +describe("createParticipationReceivedDecline$", () => { + it("reports declines with who sent them and what they relate to", () => { + const timeline = new MockElementCallMatrixClientDriver(); + const declines: DeclineEvent[] = []; + createParticipationReceivedDecline$(timeline).subscribe((d) => + declines.push(d), + ); + timeline.emitTimelineEvent({ + eventId: "$other", + type: "m.room.message", + sender: "@peer:x", + content: {}, + originServerTs: 1, + }); + timeline.emitTimelineEvent({ + eventId: "$decline", + type: RTC_DECLINE_EVENT_TYPE, + sender: "@peer:x", + content: { + "m.relates_to": { rel_type: "m.reference", event_id: "$notif" }, + }, + originServerTs: 2, + }); + expect(declines).toEqual([ + { + sender: "@peer:x", + relatesTo: { relType: "m.reference", eventId: "$notif" }, + }, + ]); + }); +}); diff --git a/src/state/CallViewModel/ParticipationCallNotification.ts b/src/state/CallViewModel/ParticipationCallNotification.ts new file mode 100644 index 000000000..1c101e2b7 --- /dev/null +++ b/src/state/CallViewModel/ParticipationCallNotification.ts @@ -0,0 +1,147 @@ +/* +Copyright 2026 Element Creations Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE in the repository root for full details. +*/ + +import { + type RTCCallIntent, + type RTCNotificationType, +} from "matrix-js-sdk/lib/matrixrtc"; +import { + BehaviorSubject, + Observable, + pairwise, + startWith, + withLatestFrom, +} from "rxjs"; +import { type Logger } from "matrix-js-sdk/lib/logger"; + +import { type Behavior } from "../Behavior"; +import { type Epoch, type ObservableScope } from "../ObservableScope"; +import { type FfiMembership } from "../../matrix-rtc-sdk"; +import { type TimelineDriver } from "../../driver/ElementCallMatrixClientDriver"; +import { + type CallNotificationWrapper, + type DeclineEvent, +} from "./CallNotificationLifecycle"; + +/** MSC4075, the unstable spelling every client sends and listens for. */ +export const RTC_NOTIFICATION_EVENT_TYPE = + "org.matrix.msc4075.rtc.notification"; +/** MSC4310. */ +export const RTC_DECLINE_EVENT_TYPE = "org.matrix.msc4310.rtc.decline"; +/** How long a ring is offered for, as matrix-js-sdk has it. */ +export const NOTIFICATION_LIFETIME_MS = 90_000; + +/** What sending the notification needs from a {@link CallParticipation}. */ +export interface ParticipationNotificationSource { + ownMembership$: Behavior; + memberships$: Behavior>; +} + +interface Props { + scope: ObservableScope; + participation: ParticipationNotificationSource; + timeline: TimelineDriver; + options: { + /** Whether and what kind of notification to send when joining the call. */ + sendNotificationType?: RTCNotificationType; + /** The kind of call being placed. */ + callIntent?: RTCCallIntent; + }; + logger: Logger; +} + +/** + * Sends the call notification (`m.rtc.notification`) when we start a call: + * once our own membership has echoed back from the homeserver, and only if + * nobody else was in the session before us — whoever is first rings the + * room. Emits what was sent, so ringing can wait for the pickup, decline or + * timeout that relates to it. Resets when we leave, so a later join can + * ring again. + */ +export function createParticipationSentCallNotification$({ + scope, + participation, + timeline, + options: { sendNotificationType, callIntent }, + logger: parentLogger, +}: Props): Behavior { + const logger = parentLogger.getChild("[CallNotification]"); + const sent$ = new BehaviorSubject(null); + if (sendNotificationType === undefined) return scope.behavior(sent$); + + participation.ownMembership$ + .pipe( + startWith(null), + pairwise(), + withLatestFrom(participation.memberships$), + scope.bind(), + ) + .subscribe(([[previous, own], memberships]) => { + if (own === null) { + // Left (or not in yet): the next join decides afresh. + if (previous !== null) sent$.next(null); + return; + } + if (previous !== null) return; // Already in; a refresh, not a join. + const others = memberships.value.filter( + (m) => m.member.memberId !== own.member.memberId, + ); + if (others.length > 0) { + logger.debug( + `Not sending a call notification: ${others.length} member(s) were in the session before us`, + ); + return; + } + const eventId = own.member.eventId; + if (eventId === undefined) { + logger.warn( + "Own membership has no event id; cannot send the call notification", + ); + return; + } + const content: Record = { + "m.mentions": { user_ids: [], room: true }, + notification_type: sendNotificationType, + "m.relates_to": { event_id: eventId, rel_type: "m.reference" }, + sender_ts: Date.now(), + lifetime: NOTIFICATION_LIFETIME_MS, + }; + if (callIntent !== undefined) content["m.call.intent"] = callIntent; + timeline.sendRoomEvent(RTC_NOTIFICATION_EVENT_TYPE, content).then( + ({ eventId: notificationEventId }) => { + logger.info(`Sent call notification ${notificationEventId}`); + sent$.next({ + event_id: notificationEventId, + ...(content as Omit), + }); + }, + (e) => logger.error("Failed to send the call notification", e), + ); + }); + + return scope.behavior(sent$); +} + +/** Declines (`m.rtc.decline`) arriving in the room, for the ringing outcome. */ +export function createParticipationReceivedDecline$( + timeline: TimelineDriver, +): Observable { + return new Observable((subscriber) => + timeline.subscribeTimeline((event) => { + if (event.type !== RTC_DECLINE_EVENT_TYPE) return; + const relation = event.content["m.relates_to"] as + | { rel_type?: string; event_id?: string } + | undefined; + subscriber.next({ + sender: event.sender, + relatesTo: relation + ? { relType: relation.rel_type, eventId: relation.event_id } + : undefined, + }); + }), + ); +} diff --git a/src/state/CallViewModel/localMember/LocalMedia.ts b/src/state/CallViewModel/localMember/LocalMedia.ts new file mode 100644 index 000000000..f88e51659 --- /dev/null +++ b/src/state/CallViewModel/localMember/LocalMedia.ts @@ -0,0 +1,565 @@ +/* +Copyright 2026 Element Creations Ltd. +Copyright 2025 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 LocalParticipant, + MediaDeviceFailure, + type Participant, + ParticipantEvent, + RoomEvent, + type ScreenShareCaptureOptions, + type TrackPublishOptions, +} from "livekit-client"; +import { observeParticipantEvents } from "@livekit/components-core"; +import { + BehaviorSubject, + combineLatest, + distinctUntilChanged, + from, + fromEvent, + map, + type Observable, + of, + pairwise, + startWith, + switchMap, + tap, +} from "rxjs"; +import { type Logger } from "matrix-js-sdk/lib/logger"; +import { deepCompare } from "matrix-js-sdk/lib/utils"; + +import { type Behavior } from "../../Behavior.ts"; +import { type ObservableScope } from "../../ObservableScope.ts"; +import { type Publisher } from "./Publisher.ts"; +import { + type ElementCallError, + FailToStartLivekitConnection, + UnknownCallError, +} from "../../../utils/errors.ts"; +import { type HostBridge } from "../../../HostBridge.ts"; +import { + advancedScreenShare, + screenShareResolution, + screenShareFramerate, + screenShareBitrate, + screenShareCodec, + parseResolution, +} from "../../../settings/settings.ts"; +import { Config } from "../../../config/Config.ts"; +import { + ConnectionState, + type Connection, + type FailedToStartError, +} from "../remoteMembers/Connection.ts"; + +export enum PublishState { + WaitingForUser = "publish_waiting_for_user", + // XXX: This state is removed for now since we do not have full control over + // track publication anymore with the publisher abstraction, might come back in the future? + // /** Implies lk connection is connected */ + // Starting = "publish_start_publishing", + /** Implies lk connection is connected */ + Publishing = "publish_publishing", +} + +// TODO not sure how to map that correctly with the +// new publisher that does not manage tracks itself anymore +export enum TrackState { + /** The track is waiting for user input to create tracks (waiting to call `startTracks()`) */ + WaitingForUser = "tracks_waiting_for_user", + // XXX: This state is removed for now since we do not have full control over + // track creation anymore with the publisher abstraction, might come back in the future? + // /** Implies lk connection is connected */ + // Creating = "tracks_creating", + /** Implies lk connection is connected */ + Ready = "tracks_ready", +} + +export type LocalMemberMediaState = + | { + tracks: TrackState; + connection: ConnectionState | FailedToStartError; + } + | PublishState + | ElementCallError; + +export interface LocalMediaProps { + scope: ObservableScope; + /** The connection we publish our media on, once there is one. */ + localConnection$: Behavior; + /** + * Whether the transport we publish on is known. Until it is, there is no + * media state to speak of (`mediaState$` is null). + */ + transportReady$: Behavior; + /** + * Whether the Matrix side of the call is connected. Upstream media is paused + * while it is not, so that "reconnecting" never means "still transmitting". + */ + matrixConnected$: Observable; + createPublisherFactory: (connection: Connection) => Publisher; + /** Whether to hide the screen-sharing button. */ + hideScreensharing: boolean; + /** The application hosting Element Call, to be kept informed of join/leave. */ + hostBridge: HostBridge; + logger: Logger; +} + +export interface LocalMedia { + /** + * This request to start audio and video tracks. + * Can be called early to pre-emptively get media permissions and start devices. + */ + startTracks: () => void; + /** + * This sets a inner state (shouldPublish) to true and instructs the Matrix + * side and livekit to keep the user connected. + */ + requestJoinAndPublish: () => void; + requestDisconnect: () => void; + /** What the user last asked for: to be in the call, or out of it. */ + joinAndPublishRequested$: Behavior; + participant$: Behavior; + /** The state of the connection we publish on; null without one. */ + localConnectionState$: Observable; + /** Null until the transport is known. */ + mediaState$: Behavior; + /** A non-fatal failure to publish; we can still consume media. */ + publishError$: Behavior; + sharingScreen$: Behavior; + /** + * Callback to toggle screen sharing. If null, screen sharing is not possible. + */ + toggleScreenSharing: (() => void) | null; + /** + * The last error from toggling screen sharing, until dismissed. + */ + screenShareError$: Behavior; + dismissScreenShareError: () => void; +} + +/** + * The LiveKit half of our own membership, shared by every Matrix side there + * is: creating a publisher on the local connection, starting tracks and + * publishing them when asked, screen sharing, pausing upstream media while + * Matrix is away, and telling the host when the user joins or hangs up. + */ +export function createLocalMedia$({ + scope, + localConnection$, + transportReady$, + matrixConnected$, + createPublisherFactory, + hideScreensharing, + hostBridge, + logger, +}: LocalMediaProps): LocalMedia { + // Tracks error that happen when creating the local tracks. + const mediaErrors$ = localConnection$.pipe( + switchMap((connection) => { + if (!connection) { + return of(null); + } else { + return fromEvent( + connection.livekitRoom, + RoomEvent.MediaDevicesError, + (error: Error) => { + return MediaDeviceFailure.getFailure(error) ?? null; + }, + ); + } + }), + ); + + mediaErrors$.pipe(scope.bind()).subscribe((error) => { + if (error) { + // This is a MediaDevice error, can be PermissionDenied, NotFound, DeviceInUse, Other. + // Will also occurs if you cancel screen sharing browser prompt. + // This is not necessarily fatal, since the user might be able to join without media. + // XXX We might want to give some user feedback here to let them know their media is not working. + logger.error(`Failed to create local tracks:`, error); + } + }); + + // This should be used in a combineLatest with publisher$ to connect. + // to make it possible to call startTracks before the preferredTransport$ has resolved. + const trackStartRequested = Promise.withResolvers(); + + // This should be used in a combineLatest with publisher$ to connect. + // to make it possible to call startTracks before the preferredTransport$ has resolved. + const joinAndPublishRequested$ = new BehaviorSubject(false); + + /** + * The publisher is stored in here an abstracts creating and publishing tracks. + */ + const publisher$ = new BehaviorSubject(null); + + const startTracks = (): void => { + trackStartRequested.resolve(); + // This used to return the tracks, but now they are only accessible via the publisher. + }; + + const requestJoinAndPublish = (): void => { + trackStartRequested.resolve(); + joinAndPublishRequested$.next(true); + }; + + const requestDisconnect = (): void => { + joinAndPublishRequested$.next(false); + }; + + // Take care of the publisher$ + // create a new one as soon as a local Connection is available + // + // Recreate a new one once the local connection changes + // - stop publishing + // - destruct all current streams + // - overwrite current publisher + scope.reconcile(localConnection$, async (connection) => { + logger.info( + "reconcile based on new localConnection:", + connection?.transport.livekit_service_url, + ); + if (connection !== null) { + const publisher = createPublisherFactory(connection); + publisher$.next(publisher); + + // Clean-up callback + return Promise.resolve(async (): Promise => { + await publisher.destroy(); + }); + } + }); + + // Use reconcile here to not run concurrent createAndSetupTracks calls + // `tracks$` will update once they are ready. + scope.reconcile( + scope.behavior( + combineLatest([ + publisher$ /*, tracks$*/, + from(trackStartRequested.promise), + ]), + null, + ), + async (valueIfReady) => { + if (!valueIfReady) return; + const [publisher] = valueIfReady; + if (publisher) { + await publisher.createAndSetupTracks().catch((e) => logger.error(e)); + } + }, + ); + + // These are non fatal since we can join a room and concume media even though publishing failed. + const publishError$ = new BehaviorSubject(null); + const setPublishError = (e: ElementCallError): void => { + if (publishError$.value !== null) { + logger.error("Multiple Media Errors:", e); + } else { + publishError$.next(e); + } + }; + + // Based on `connectRequested$` we start publishing tracks. (once they are there!) + scope.reconcile( + scope.behavior(combineLatest([publisher$, joinAndPublishRequested$])), + async ([publisher, shouldJoinAndPublish]) => { + // Get the current publishing state to avoid redundant calls. + const isPublishing = publisher?.shouldPublish === true; + if (shouldJoinAndPublish && !isPublishing) { + try { + await publisher?.startPublishing(); + } catch (error) { + const message = + error instanceof Error ? error.message : String(error); + setPublishError(new FailToStartLivekitConnection(message)); + } + } else if (isPublishing) { + try { + await publisher?.stopPublishing(); + } catch (error) { + setPublishError(new UnknownCallError(error as Error)); + } + } + }, + ); + + const localConnectionState$ = localConnection$.pipe( + switchMap((connection) => (connection ? connection.state$ : of(null))), + ); + + const mediaState$: Behavior = scope.behavior( + combineLatest([ + localConnectionState$, + transportReady$, + joinAndPublishRequested$, + from(trackStartRequested.promise).pipe( + map(() => true), + startWith(false), + ), + ]).pipe( + map( + ([ + localConnectionState, + transportReady, + shouldPublish, + shouldStartTracks, + ]) => { + if (!transportReady) return null; + const trackState: TrackState = shouldStartTracks + ? TrackState.Ready + : TrackState.WaitingForUser; + + if ( + localConnectionState !== ConnectionState.LivekitConnected || + trackState !== TrackState.Ready + ) + return { + connection: localConnectionState, + tracks: trackState, + }; + if (!shouldPublish) return PublishState.WaitingForUser; + // if (!publishing) return PublishState.Starting; + return PublishState.Publishing; + }, + ), + distinctUntilChanged(deepCompare), + ), + ); + + // inform the host about the connect and disconnect intent from the user. + scope + .behavior(joinAndPublishRequested$.pipe(pairwise(), scope.bind()), [ + undefined, + joinAndPublishRequested$.value, + ]) + .subscribe(([prev, current]) => { + // JOIN prev=false (was left) => current-true (now joiend) + if (!prev && current) { + hostBridge.notifyJoined().catch((e) => { + logger.error("Failed to notify the host that we joined", e); + }); + } + // LEAVE prev=false (was joined) => current-true (now left) + if (prev && !current) { + hostBridge.notifyHungUp().catch((e) => { + logger.error("Failed to notify the host that we hung up", e); + }); + } + }); + + const participant$ = scope.behavior( + localConnection$.pipe( + map((c) => c?.livekitRoom?.localParticipant ?? null), + tap((p) => { + logger.debug("participant$ updated:", p?.identity); + }), + ), + ); + + // Pause upstream of all local media tracks when we're disconnected from + // MatrixRTC, because it can be an unpleasant surprise for the app to say + // 'reconnecting' and yet still be transmitting your media to others. + // We use matrixConnected$ rather than reconnecting$ because we want to + // pause tracks during the initial joining sequence too until we're sure + // that our own media is displayed on screen. + // TODO refactor this based no livekitState$ + combineLatest([participant$, matrixConnected$]) + .pipe(scope.bind()) + .subscribe(([participant, connected]) => { + if (!participant) return; + const publications = participant.trackPublications.values(); + if (connected) { + for (const p of publications) { + if (p.track?.isUpstreamPaused === true) { + const kind = p.track.kind; + logger.info( + `Resuming ${kind} track (MatrixRTC connection present)`, + ); + p.track + .resumeUpstream() + .catch((e) => + logger.error( + `Failed to resume ${kind} track after MatrixRTC reconnection`, + e, + ), + ); + } + } + } else { + for (const p of publications) { + if (p.track?.isUpstreamPaused === false) { + const kind = p.track.kind; + logger.info( + `Pausing ${kind} track (uncertain MatrixRTC connection)`, + ); + p.track + .pauseUpstream() + .catch((e) => + logger.error( + `Failed to pause ${kind} track after entering uncertain MatrixRTC connection`, + e, + ), + ); + } + } + } + }); + + /** + * Whether the user is currently sharing their screen. + */ + const sharingScreen$ = scope.behavior( + participant$.pipe( + switchMap((p) => (p !== null ? observeSharingScreen$(p) : of(false))), + ), + ); + + const screenShareError$ = new BehaviorSubject(null); + let toggleScreenSharing: (() => void) | null = null; + if ( + "getDisplayMedia" in (navigator.mediaDevices ?? {}) && + !hideScreensharing + ) { + toggleScreenSharing = (): void => { + const screenshareSettings: ScreenShareCaptureOptions = { + // Screen share audio shouldn't have any filtering. + // "echoCancellation" is purposely excluded, as setting it to + // false causes the screen share audio track to include + // an echo of the incoming participant's voice + audio: { + autoGainControl: false, + noiseSuppression: false, + voiceIsolation: false, + }, + selfBrowserSurface: "include", + surfaceSwitching: "include", + systemAudio: "include", + }; + + let publishOptions: TrackPublishOptions | undefined; + + if (advancedScreenShare.getValue()) { + // User has advanced screen share settings enabled + const { width, height } = parseResolution( + screenShareResolution.getValue(), + ); + const fps = screenShareFramerate.getValue(); + const bps = screenShareBitrate.getValue(); + const codec = screenShareCodec.getValue(); + + screenshareSettings.resolution = { + width, + height, + frameRate: fps, + }; + + publishOptions = { + screenShareEncoding: { + maxBitrate: bps, + maxFramerate: fps, + }, + videoCodec: codec, + }; + } else { + // Fall back to config.json settings if available + const screenConf = Config.get().media_quality?.screen_share; + if (screenConf?.max_resolution) { + screenshareSettings.resolution = { + width: Math.round((screenConf.max_resolution * 16) / 9), + height: screenConf.max_resolution, + frameRate: screenConf.max_framerate ?? 30, + }; + } + } + + const targetScreenshareState = !sharingScreen$.value; + logger.info( + `toggleScreenSharing called. Switching ${ + targetScreenshareState ? "On" : "Off" + }`, + ); + // If a connection is ready, toggle screen sharing. + // We deliberately do nothing in the case of a null connection because + // it looks nice for the call control buttons to all become available + // at once upon joining the call, rather than introducing a disabled + // state. The user can just click again. + // We also allow screen sharing to be toggled even if the connection + // is still initializing or publishing tracks, because there's no + // technical reason to disallow this. LiveKit will publish if it can. + const participant = participant$.value; + if (!participant) return; + watchScreenShareToggle( + participant.setScreenShareEnabled( + targetScreenshareState, + screenshareSettings, + publishOptions, + ), + targetScreenshareState, + logger, + (e) => screenShareError$.next(e), + ); + }; + } + + return { + startTracks, + requestJoinAndPublish, + requestDisconnect, + joinAndPublishRequested$, + participant$, + localConnectionState$, + mediaState$, + publishError$, + sharingScreen$, + toggleScreenSharing, + screenShareError$, + dismissScreenShareError: () => screenShareError$.next(null), + }; +} + +/** + * Logs the outcome of a screen share toggle and reports failures. + * + * getDisplayMedia may legitimately take a long time (the user is choosing + * what to share) or never settle at all, so nothing is inferred from silence: + * the request and its completion are logged with the elapsed time so that a + * hang is visible in the logs, and only an explicit rejection is reported. + * + * The user cancelling the picker rejects with a NotAllowedError; that is + * logged but not reported. + */ +export function watchScreenShareToggle( + toggle: Promise, + enable: boolean, + logger: Logger, + onError: (e: Error) => void, +): void { + const what = `Screen share ${enable ? "start" : "stop"}`; + const started = Date.now(); + const elapsed = (): string => `${Date.now() - started} ms`; + logger.info(`${what} requested`); + toggle.then( + () => logger.info(`${what} completed in ${elapsed()}`), + (e: unknown) => { + logger.error(`${what} failed after ${elapsed()}:`, e); + if (e instanceof DOMException && e.name === "NotAllowedError") return; + onError(e instanceof Error ? e : new Error(String(e))); + }, + ); +} + +export function observeSharingScreen$(p: Participant): Observable { + return observeParticipantEvents( + p, + ParticipantEvent.TrackPublished, + ParticipantEvent.TrackUnpublished, + ParticipantEvent.LocalTrackPublished, + ParticipantEvent.LocalTrackUnpublished, + ).pipe(map((p) => p.isScreenShareEnabled)); +} diff --git a/src/state/CallViewModel/localMember/LocalMember.ts b/src/state/CallViewModel/localMember/LocalMember.ts index 7303946a0..b52788609 100644 --- a/src/state/CallViewModel/localMember/LocalMember.ts +++ b/src/state/CallViewModel/localMember/LocalMember.ts @@ -5,16 +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 Participant, - ParticipantEvent, - type LocalParticipant, - type ScreenShareCaptureOptions, - type TrackPublishOptions, - RoomEvent, - MediaDeviceFailure, -} from "livekit-client"; -import { observeParticipantEvents } from "@livekit/components-core"; +import { type LocalParticipant } from "livekit-client"; import { type MatrixClient } from "matrix-js-sdk"; import { Status as RTCSessionStatus, @@ -30,7 +21,6 @@ import { combineLatest, distinctUntilChanged, from, - fromEvent, map, type Observable, of, @@ -40,31 +30,22 @@ import { tap, } from "rxjs"; import { type Logger } from "matrix-js-sdk/lib/logger"; -import { deepCompare } from "matrix-js-sdk/lib/utils"; import { type CallMembershipIdentityParts } from "matrix-js-sdk/lib/matrixrtc/EncryptionManager"; import { type Behavior } from "../../Behavior.ts"; import { type IConnectionManager } from "../remoteMembers/ConnectionManager.ts"; import { type ObservableScope } from "../../ObservableScope.ts"; import { type Publisher } from "./Publisher.ts"; +import { createLocalMedia$, type LocalMemberMediaState } from "./LocalMedia.ts"; import { type MuteStates } from "../../MuteStates.ts"; import { ElementCallError, - FailToStartLivekitConnection, MembershipManagerError, UnknownCallError, } from "../../../utils/errors.ts"; import { type HostBridge } from "../../../HostBridge.ts"; import { PosthogAnalytics } from "../../../analytics/PosthogAnalytics.ts"; -import { - advancedScreenShare, - screenShareResolution, - screenShareFramerate, - screenShareBitrate, - screenShareCodec, - parseResolution, -} from "../../../settings/settings.ts"; import { MatrixRTCMode, type ResolvedDelayedLeaveTimings, @@ -73,7 +54,6 @@ import { Config } from "../../../config/Config.ts"; import { ConnectionState, type Connection, - type FailedToStartError, } from "../remoteMembers/Connection.ts"; import { type HomeserverConnected } from "./HomeserverConnected.ts"; import { type LocalTransport } from "./LocalTransport.ts"; @@ -86,42 +66,31 @@ export enum TransportState { Waiting = "transport_waiting", } -export enum PublishState { - WaitingForUser = "publish_waiting_for_user", - // XXX: This state is removed for now since we do not have full control over - // track publication anymore with the publisher abstraction, might come back in the future? - // /** Implies lk connection is connected */ - // Starting = "publish_start_publishing", - /** Implies lk connection is connected */ - Publishing = "publish_publishing", +export { + PublishState, + TrackState, + type LocalMemberMediaState, + watchScreenShareToggle, + observeSharingScreen$, +} from "./LocalMedia.ts"; + +/** + * The crate's view of our membership, for `LocalMemberState.matrix` when the + * call runs over a `CallParticipation` (matrix-js-sdk reports its own + * `RTCSessionStatus` there). + */ +export enum MatrixConnectionStatus { + Disconnected = "matrix_disconnected", + Connecting = "matrix_connecting", + Connected = "matrix_connected", } -// TODO not sure how to map that correctly with the -// new publisher that does not manage tracks itself anymore -export enum TrackState { - /** The track is waiting for user input to create tracks (waiting to call `startTracks()`) */ - WaitingForUser = "tracks_waiting_for_user", - // XXX: This state is removed for now since we do not have full control over - // track creation anymore with the publisher abstraction, might come back in the future? - // /** Implies lk connection is connected */ - // Creating = "tracks_creating", - /** Implies lk connection is connected */ - Ready = "tracks_ready", -} - -export type LocalMemberMediaState = - | { - tracks: TrackState; - connection: ConnectionState | FailedToStartError; - } - | PublishState - | ElementCallError; export type LocalMemberState = | ElementCallError | TransportState.Waiting | { media: LocalMemberMediaState; - matrix: ElementCallError | RTCSessionStatus; + matrix: ElementCallError | RTCSessionStatus | MatrixConnectionStatus; }; /* @@ -191,6 +160,9 @@ interface Props { * - connectionState: the current connection state. Including matrix server and livekit server connection. * - sharingScreen$: Whether we are sharing our screen. `undefined` if we cannot share the screen. */ +/** Our own membership as the view model sees it, whichever Matrix side made it. */ +export type LocalMembership = ReturnType; + export const createLocalMembership$ = ({ scope, connectionManager, @@ -357,139 +329,36 @@ export const createLocalMembership$ = ({ ), ); - // Tracks error that happen when creating the local tracks. - const mediaErrors$ = localConnection$.pipe( - switchMap((connection) => { - if (!connection) { - return of(null); - } else { - return fromEvent( - connection.livekitRoom, - RoomEvent.MediaDevicesError, - (error: Error) => { - return MediaDeviceFailure.getFailure(error) ?? null; - }, - ); - } - }), - ); - - mediaErrors$.pipe(scope.bind()).subscribe((error) => { - if (error) { - // This is a MediaDevice error, can be PermissionDenied, NotFound, DeviceInUse, Other. - // Will also occurs if you cancel screen sharing browser prompt. - // This is not necessarily fatal, since the user might be able to join without media. - // XXX We might want to give some user feedback here to let them know their media is not working. - logger.error(`Failed to create local tracks:`, error); - } - }); - // MATRIX RELATED - - // This should be used in a combineLatest with publisher$ to connect. - // to make it possible to call startTracks before the preferredTransport$ has resolved. - const trackStartRequested = Promise.withResolvers(); - - // This should be used in a combineLatest with publisher$ to connect. - // to make it possible to call startTracks before the preferredTransport$ has resolved. - const joinAndPublishRequested$ = new BehaviorSubject(false); - - /** - * The publisher is stored in here an abstracts creating and publishing tracks. - */ - const publisher$ = new BehaviorSubject(null); - - const startTracks = (): void => { - trackStartRequested.resolve(); - // This used to return the tracks, but now they are only accessible via the publisher. - }; - - const requestJoinAndPublish = (): void => { - trackStartRequested.resolve(); - joinAndPublishRequested$.next(true); - }; - - const requestDisconnect = (): void => { - joinAndPublishRequested$.next(false); - }; - - // Take care of the publisher$ - // create a new one as soon as a local Connection is available - // - // Recreate a new one once the local connection changes - // - stop publishing - // - destruct all current streams - // - overwrite current publisher - scope.reconcile(localConnection$, async (connection) => { - logger.info( - "reconcile based on new localConnection:", - connection?.transport.livekit_service_url, - ); - if (connection !== null) { - const publisher = createPublisherFactory(connection); - publisher$.next(publisher); - - // Clean-up callback - return Promise.resolve(async (): Promise => { - await publisher.destroy(); - }); - } - }); - - // Use reconcile here to not run concurrent createAndSetupTracks calls - // `tracks$` will update once they are ready. - scope.reconcile( - scope.behavior( - combineLatest([ - publisher$ /*, tracks$*/, - from(trackStartRequested.promise), - ]), - null, + const { + startTracks, + requestJoinAndPublish, + requestDisconnect, + joinAndPublishRequested$, + participant$, + localConnectionState$, + mediaState$, + publishError$, + sharingScreen$, + toggleScreenSharing, + screenShareError$, + dismissScreenShareError, + } = createLocalMedia$({ + scope, + localConnection$, + transportReady$: scope.behavior( + activeTransport$.pipe(map((transport) => transport !== null)), ), - async (valueIfReady) => { - if (!valueIfReady) return; - const [publisher] = valueIfReady; - if (publisher) { - await publisher.createAndSetupTracks().catch((e) => logger.error(e)); - } - }, - ); - - // Based on `connectRequested$` we start publishing tracks. (once they are there!) - scope.reconcile( - scope.behavior(combineLatest([publisher$, joinAndPublishRequested$])), - async ([publisher, shouldJoinAndPublish]) => { - // Get the current publishing state to avoid redundant calls. - const isPublishing = publisher?.shouldPublish === true; - if (shouldJoinAndPublish && !isPublishing) { - try { - await publisher?.startPublishing(); - } catch (error) { - const message = - error instanceof Error ? error.message : String(error); - setPublishError(new FailToStartLivekitConnection(message)); - } - } else if (isPublishing) { - try { - await publisher?.stopPublishing(); - } catch (error) { - setPublishError(new UnknownCallError(error as Error)); - } - } - }, - ); + matrixConnected$: homeserverConnected.combined$.pipe( + map(([connected]) => connected), + ), + createPublisherFactory, + hideScreensharing, + hostBridge, + logger, + }); // STATE COMPUTATION - // These are non fatal since we can join a room and concume media even though publishing failed. - const publishError$ = new BehaviorSubject(null); - const setPublishError = (e: ElementCallError): void => { - if (publishError$.value !== null) { - logger.error("Multiple Media Errors:", e); - } else { - publishError$.next(e); - } - }; - const fatalTransportError$ = new BehaviorSubject( null, ); @@ -502,48 +371,6 @@ export const createLocalMembership$ = ({ } }; - const localConnectionState$ = localConnection$.pipe( - switchMap((connection) => (connection ? connection.state$ : of(null))), - ); - - const mediaState$: Behavior = scope.behavior( - combineLatest([ - localConnectionState$, - activeTransport$, - joinAndPublishRequested$, - from(trackStartRequested.promise).pipe( - map(() => true), - startWith(false), - ), - ]).pipe( - map( - ([ - localConnectionState, - localTransport, - shouldPublish, - shouldStartTracks, - ]) => { - if (!localTransport) return null; - const trackState: TrackState = shouldStartTracks - ? TrackState.Ready - : TrackState.WaitingForUser; - - if ( - localConnectionState !== ConnectionState.LivekitConnected || - trackState !== TrackState.Ready - ) - return { - connection: localConnectionState, - tracks: trackState, - }; - if (!shouldPublish) return PublishState.WaitingForUser; - // if (!publishing) return PublishState.Starting; - return PublishState.Publishing; - }, - ), - distinctUntilChanged(deepCompare), - ), - ); const fatalMatrixError$ = new BehaviorSubject(null); const setMatrixError = (e: ElementCallError): void => { if (fatalMatrixError$.value !== null) { @@ -650,27 +477,6 @@ export const createLocalMembership$ = ({ } }); - // inform the host about the connect and disconnect intent from the user. - scope - .behavior(joinAndPublishRequested$.pipe(pairwise(), scope.bind()), [ - undefined, - joinAndPublishRequested$.value, - ]) - .subscribe(([prev, current]) => { - // JOIN prev=false (was left) => current-true (now joiend) - if (!prev && current) { - hostBridge.notifyJoined().catch((e) => { - logger.error("Failed to notify the host that we joined", e); - }); - } - // LEAVE prev=false (was joined) => current-true (now left) - if (prev && !current) { - hostBridge.notifyHungUp().catch((e) => { - logger.error("Failed to notify the host that we hung up", e); - }); - } - }); - muteStates.video.enabled$.pipe(scope.bind()).subscribe((videoEnabled) => { void matrixRTCSession .updateCallIntent(videoEnabled ? "video" : "audio") @@ -718,15 +524,6 @@ export const createLocalMembership$ = ({ }, ); - const participant$ = scope.behavior( - localConnection$.pipe( - map((c) => c?.livekitRoom?.localParticipant ?? null), - tap((p) => { - logger.debug("participant$ updated:", p?.identity); - }), - ), - ); - // Delegate delayed leaves to the SFU scope.reconcile( scope.behavior(combineLatest([joinParams$, delayId$])), @@ -755,151 +552,6 @@ export const createLocalMembership$ = ({ }, ); - // Pause upstream of all local media tracks when we're disconnected from - // MatrixRTC, because it can be an unpleasant surprise for the app to say - // 'reconnecting' and yet still be transmitting your media to others. - // We use matrixConnected$ rather than reconnecting$ because we want to - // pause tracks during the initial joining sequence too until we're sure - // that our own media is displayed on screen. - // TODO refactor this based no livekitState$ - combineLatest([participant$, homeserverConnected.combined$]) - .pipe(scope.bind()) - .subscribe(([participant, [connected]]) => { - if (!participant) return; - const publications = participant.trackPublications.values(); - if (connected) { - for (const p of publications) { - if (p.track?.isUpstreamPaused === true) { - const kind = p.track.kind; - logger.info( - `Resuming ${kind} track (MatrixRTC connection present)`, - ); - p.track - .resumeUpstream() - .catch((e) => - logger.error( - `Failed to resume ${kind} track after MatrixRTC reconnection`, - e, - ), - ); - } - } - } else { - for (const p of publications) { - if (p.track?.isUpstreamPaused === false) { - const kind = p.track.kind; - logger.info( - `Pausing ${kind} track (uncertain MatrixRTC connection)`, - ); - p.track - .pauseUpstream() - .catch((e) => - logger.error( - `Failed to pause ${kind} track after entering uncertain MatrixRTC connection`, - e, - ), - ); - } - } - } - }); - - /** - * Whether the user is currently sharing their screen. - */ - const sharingScreen$ = scope.behavior( - participant$.pipe( - switchMap((p) => (p !== null ? observeSharingScreen$(p) : of(false))), - ), - ); - - const screenShareError$ = new BehaviorSubject(null); - let toggleScreenSharing: (() => void) | null = null; - if ( - "getDisplayMedia" in (navigator.mediaDevices ?? {}) && - !hideScreensharing - ) { - toggleScreenSharing = (): void => { - const screenshareSettings: ScreenShareCaptureOptions = { - // Screen share audio shouldn't have any filtering. - // "echoCancellation" is purposely excluded, as setting it to - // false causes the screen share audio track to include - // an echo of the incoming participant's voice - audio: { - autoGainControl: false, - noiseSuppression: false, - voiceIsolation: false, - }, - selfBrowserSurface: "include", - surfaceSwitching: "include", - systemAudio: "include", - }; - - let publishOptions: TrackPublishOptions | undefined; - - if (advancedScreenShare.getValue()) { - // User has advanced screen share settings enabled - const { width, height } = parseResolution( - screenShareResolution.getValue(), - ); - const fps = screenShareFramerate.getValue(); - const bps = screenShareBitrate.getValue(); - const codec = screenShareCodec.getValue(); - - screenshareSettings.resolution = { - width, - height, - frameRate: fps, - }; - - publishOptions = { - screenShareEncoding: { - maxBitrate: bps, - maxFramerate: fps, - }, - videoCodec: codec, - }; - } else { - // Fall back to config.json settings if available - const screenConf = Config.get().media_quality?.screen_share; - if (screenConf?.max_resolution) { - screenshareSettings.resolution = { - width: Math.round((screenConf.max_resolution * 16) / 9), - height: screenConf.max_resolution, - frameRate: screenConf.max_framerate ?? 30, - }; - } - } - - const targetScreenshareState = !sharingScreen$.value; - logger.info( - `toggleScreenSharing called. Switching ${ - targetScreenshareState ? "On" : "Off" - }`, - ); - // If a connection is ready, toggle screen sharing. - // We deliberately do nothing in the case of a null connection because - // it looks nice for the call control buttons to all become available - // at once upon joining the call, rather than introducing a disabled - // state. The user can just click again. - // We also allow screen sharing to be toggled even if the connection - // is still initializing or publishing tracks, because there's no - // technical reason to disallow this. LiveKit will publish if it can. - const participant = participant$.value; - if (!participant) return; - watchScreenShareToggle( - participant.setScreenShareEnabled( - targetScreenshareState, - screenshareSettings, - publishOptions, - ), - targetScreenshareState, - logger, - (e) => screenShareError$.next(e), - ); - }; - } - return { startTracks, requestJoinAndPublish, @@ -916,53 +568,12 @@ export const createLocalMembership$ = ({ sharingScreen$, toggleScreenSharing, screenShareError$, - dismissScreenShareError: () => screenShareError$.next(null), + dismissScreenShareError, connection$: localConnection$, internalLoggerRef: logger, }; }; -/** - * Logs the outcome of a screen share toggle and reports failures. - * - * getDisplayMedia may legitimately take a long time (the user is choosing - * what to share) or never settle at all, so nothing is inferred from silence: - * the request and its completion are logged with the elapsed time so that a - * hang is visible in the logs, and only an explicit rejection is reported. - * - * The user cancelling the picker rejects with a NotAllowedError; that is - * logged but not reported. - */ -export function watchScreenShareToggle( - toggle: Promise, - enable: boolean, - logger: Logger, - onError: (e: Error) => void, -): void { - const what = `Screen share ${enable ? "start" : "stop"}`; - const started = Date.now(); - const elapsed = (): string => `${Date.now() - started} ms`; - logger.info(`${what} requested`); - toggle.then( - () => logger.info(`${what} completed in ${elapsed()}`), - (e: unknown) => { - logger.error(`${what} failed after ${elapsed()}:`, e); - if (e instanceof DOMException && e.name === "NotAllowedError") return; - onError(e instanceof Error ? e : new Error(String(e))); - }, - ); -} - -export function observeSharingScreen$(p: Participant): Observable { - return observeParticipantEvents( - p, - ParticipantEvent.TrackPublished, - ParticipantEvent.TrackUnpublished, - ParticipantEvent.LocalTrackPublished, - ParticipantEvent.LocalTrackUnpublished, - ).pipe(map((p) => p.isScreenShareEnabled)); -} - interface EnterRTCSessionOptions { encryptMedia: boolean; matrixRTCMode: MatrixRTCMode; diff --git a/src/state/CallViewModel/localMember/ParticipationLocalMember.ts b/src/state/CallViewModel/localMember/ParticipationLocalMember.ts new file mode 100644 index 000000000..6dff07570 --- /dev/null +++ b/src/state/CallViewModel/localMember/ParticipationLocalMember.ts @@ -0,0 +1,431 @@ +/* +Copyright 2026 Element Creations Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE in the repository root for full details. +*/ + +import { + BehaviorSubject, + combineLatest, + distinctUntilChanged, + map, + type Observable, + pairwise, + tap, +} from "rxjs"; +import { type Logger } from "matrix-js-sdk/lib/logger"; + +import { type Behavior } from "../../Behavior.ts"; +import { type ObservableScope } from "../../ObservableScope.ts"; +import { type MuteStates } from "../../MuteStates.ts"; +import { type HostBridge } from "../../../HostBridge.ts"; +import { + ElementCallError, + MembershipManagerError, +} from "../../../utils/errors.ts"; +import { PosthogAnalytics } from "../../../analytics/PosthogAnalytics.ts"; +import { + FfiImpairment, + FfiKeepAlive, + FfiStatus, + type FfiConnectionWithMembers, + type FfiJoinParams, + type FfiStatus as FfiStatusType, + type FfiTransportIntent, +} from "../../../matrix-rtc-sdk"; +import { type SlotPolicy } from "../../rtc/CallParticipation.ts"; +import { type DisconnectContext, errorForStatus } from "../../rtc/errors.ts"; +import { publishOnLivekit } from "../../rtc/transportIntent.ts"; +import { type IConnectionManager } from "../remoteMembers/ConnectionManager.ts"; +import { + ConnectionState, + type Connection, +} from "../remoteMembers/Connection.ts"; +import { type Publisher } from "./Publisher.ts"; +import { createLocalMedia$ } from "./LocalMedia.ts"; +import { + type LocalMembership, + type LocalMemberState, + MatrixConnectionStatus, + TransportState, +} from "./LocalMember.ts"; +import { type HomeserverDisconnectReason } from "./HomeserverConnected.ts"; + +/** What our own membership needs from a {@link CallParticipation}. */ +export interface ParticipationLocalMemberSource { + status$: Behavior; + connections$: Behavior; + ownMemberId$: Behavior; + join( + intent: FfiTransportIntent, + params: FfiJoinParams, + slot: SlotPolicy, + ): Promise; + leave(): Promise; + updateApplication(intent: string | undefined): Promise; +} + +interface Props { + scope: ObservableScope; + participation: ParticipationLocalMemberSource; + connectionManager: IConnectionManager; + createPublisherFactory: (connection: Connection) => Publisher; + muteStates: MuteStates; + /** Whether to hide the screen-sharing button. */ + hideScreensharing: boolean; + /** The application hosting Element Call, to be kept informed of join/leave. */ + hostBridge: HostBridge; + /** How to join, from the configuration. */ + joinParams: FfiJoinParams; + /** Whether the room's slot may be opened by us, and how. */ + slotPolicy$: Behavior; + /** + * A developer's own LiveKit service URL to publish on instead of whatever + * the homeserver advertises; null or empty for none. + */ + customLivekitUrl$: Observable; + /** For turning a failed participation into the error the UI shows. */ + disconnectContext: () => DisconnectContext; + /** The room, as the call identifier in analytics events. */ + roomId: string; + logger: Logger; +} + +/** + * The Matrix side of the call as the crate sees it, reduced to what the local + * member state needs: connected or not, and if not, why. + */ +interface MatrixConnection { + connected: boolean; + reason: HomeserverDisconnectReason | null; + status: MatrixConnectionStatus; +} + +function describeStatus(status: FfiStatusType): MatrixConnection { + if (FfiStatus.Disconnected.instanceOf(status)) + return { + connected: false, + reason: "membership", + status: MatrixConnectionStatus.Disconnected, + }; + if (!FfiStatus.Connected.instanceOf(status)) + return { + connected: false, + reason: "membership", + status: MatrixConnectionStatus.Connecting, + }; + const { impairments, keepAlive } = status.inner; + if ( + impairments.some((i) => FfiImpairment.HomeserverUnreachable.instanceOf(i)) + ) + return { + connected: false, + reason: "sync", + status: MatrixConnectionStatus.Connected, + }; + // A keep-alive that cannot be restarted may already have fired: the + // homeserver may think we left. + if ( + FfiKeepAlive.RestartFailing.instanceOf(keepAlive) || + FfiKeepAlive.Expired.instanceOf(keepAlive) + ) + return { + connected: false, + reason: "probablyLeft", + status: MatrixConnectionStatus.Connected, + }; + return { + connected: true, + reason: null, + status: MatrixConnectionStatus.Connected, + }; +} + +/** + * Our own membership over a {@link CallParticipation}: the crate publishes + * and keeps alive the membership, discovers the transport and mints its + * token; this joins and leaves when the user asks, publishes our media on + * the connection the crate gave us, and projects the crate's status onto the + * connected / reconnecting / error states the call UI shows. + */ +export const createParticipationLocalMembership$ = ({ + scope, + participation, + connectionManager, + createPublisherFactory, + muteStates, + hideScreensharing, + hostBridge, + joinParams, + slotPolicy$, + customLivekitUrl$, + disconnectContext, + roomId, + logger: parentLogger, +}: Props): LocalMembership => { + const logger = parentLogger.getChild("[ParticipationLocalMembership]"); + logger.debug(`Creating local membership..`); + + // The connection we publish on: the one the crate lists our own member on. + const ownServiceUrl$ = scope.behavior( + combineLatest([ + participation.connections$, + participation.ownMemberId$, + ]).pipe( + map( + ([connections, ownMemberId]) => + connections.find((c) => + c.members.some((m) => m.memberId === ownMemberId), + )?.connection.serviceUrl ?? null, + ), + distinctUntilChanged(), + ), + ); + + const localConnection$ = scope.behavior( + combineLatest([ + connectionManager.connectionManagerData$, + ownServiceUrl$, + ]).pipe( + map(([{ value: connectionData }, serviceUrl]) => + serviceUrl === null + ? null + : connectionData.getConnectionForTransport({ + type: "livekit", + livekit_service_url: serviceUrl, + }), + ), + tap((connection) => { + logger.info( + `Local connection updated: ${connection?.transport?.livekit_service_url}`, + ); + }), + ), + ); + + const matrixConnection$ = scope.behavior( + participation.status$.pipe( + map(describeStatus), + distinctUntilChanged( + (a, b) => + a.connected === b.connected && + a.reason === b.reason && + a.status === b.status, + ), + ), + ); + + const { + startTracks, + requestJoinAndPublish, + requestDisconnect, + joinAndPublishRequested$, + participant$, + localConnectionState$, + mediaState$, + publishError$, + sharingScreen$, + toggleScreenSharing, + screenShareError$, + dismissScreenShareError, + } = createLocalMedia$({ + scope, + localConnection$, + transportReady$: scope.behavior( + ownServiceUrl$.pipe(map((url) => url !== null)), + ), + matrixConnected$: matrixConnection$.pipe(map((c) => c.connected)), + createPublisherFactory, + hideScreensharing, + hostBridge, + logger, + }); + + // MATRIX RELATED + + const fatalMatrixError$ = new BehaviorSubject(null); + const setMatrixError = (e: ElementCallError): void => { + if (fatalMatrixError$.value !== null) { + logger.error("Multiple Matrix Errors:", e); + } else { + fatalMatrixError$.next(e); + } + }; + + // Join and leave as the user asks. The crate does the rest: it opens the + // slot when we may, discovers the transport, publishes and keeps the + // membership alive, and delegates the delayed leave. + scope.reconcile( + scope.behavior( + combineLatest([joinAndPublishRequested$, customLivekitUrl$]), + ), + async ([shouldConnect, customLivekitUrl]) => { + // if shouldConnect=false we will do the disconnect as the cleanup from the previous reconcile iteration. + if (!shouldConnect) return; + PosthogAnalytics.instance.eventCallEnded.cacheStartCall(new Date()); + PosthogAnalytics.instance.eventCallStarted.track(roomId); + try { + await participation.join( + publishOnLivekit(customLivekitUrl || undefined), + joinParams, + slotPolicy$.value, + ); + } catch (error) { + logger.error("Error joining the session", error); + setMatrixError( + error instanceof ElementCallError + ? error + : (errorForStatus( + participation.status$.value, + disconnectContext(), + ) ?? + new MembershipManagerError( + error instanceof Error ? error : new Error(String(error)), + )), + ); + } + + return Promise.resolve(async (): Promise => { + try { + await participation.leave(); + } catch (e) { + logger.error("Error leaving the session", e); + } + }); + }, + ); + + // The crate can end the participation on its own (the slot closed, the + // manager stopped): while the user still wants to be in the call, that is + // an error to show. + combineLatest([participation.status$, joinAndPublishRequested$]) + .pipe(scope.bind()) + .subscribe(([status, shouldConnect]) => { + if (!shouldConnect) return; + const error = errorForStatus(status, disconnectContext()); + if (error !== null && fatalMatrixError$.value === null) { + logger.warn("The participation ended on its own", error); + setMatrixError(error); + } + }); + + const localMemberState$ = scope.behavior( + combineLatest([ + mediaState$, + matrixConnection$, + fatalMatrixError$, + publishError$, + ]).pipe( + map(([mediaState, matrixConnection, fatalMatrixError, publishError]) => { + // `mediaState` will be 'null' until the transport/connection appears. + if (mediaState) + return { + matrix: fatalMatrixError ?? matrixConnection.status, + media: publishError ?? mediaState, + }; + // A join that failed before any transport was known is still fatal. + if (fatalMatrixError) return fatalMatrixError; + return TransportState.Waiting; + }), + ), + ); + + /** + * The disconnect reason for the combined Matrix + LiveKit connection, or null + * when fully connected. Homeserver reasons take priority over livekit. + */ + const connectionDisconnectReason$ = scope.behavior( + combineLatest([ + matrixConnection$, + localConnectionState$.pipe( + map((state) => state === ConnectionState.LivekitConnected), + ), + ]).pipe( + map(([matrix, livekitConnected]) => { + if (!matrix.connected) return matrix.reason!; + if (!livekitConnected) return "livekit" as const; + return null; + }), + tap((v) => logger.debug("livekit+matrix: Connected state changed", v)), + ), + ); + + /** + * Whether we are "fully" connected to the call. Accounts for both the + * connection to the MatrixRTC session and the LiveKit publish connection. + */ + const matrixAndLivekitConnected$ = scope.behavior( + connectionDisconnectReason$.pipe(map((reason) => reason === null)), + ); + + /** + * Whether we should tell the user that we're reconnecting to the call. + */ + const reconnecting$ = scope.behavior( + matrixAndLivekitConnected$.pipe( + pairwise(), + map(([prev, current]) => prev === true && current === false), + ), + false, + ); + + let reconnectStart: { + time: number; + reason: NonNullable<(typeof connectionDisconnectReason$)["value"]>; + } | null = null; + connectionDisconnectReason$ + .pipe(distinctUntilChanged(), pairwise(), scope.bind()) + .subscribe(([prev, reason]) => { + if (reason !== null) { + // Only begin tracking when transitioning FROM connected (null → non-null). + if (prev === null) { + reconnectStart ??= { time: Date.now(), reason }; + } + } else if (reconnectStart !== null) { + PosthogAnalytics.instance.eventCallReconnecting.track( + roomId, + reconnectStart.reason, + (Date.now() - reconnectStart.time) / 1000, + ); + PosthogAnalytics.instance.eventCallEnded.cacheReconnecting( + reconnectStart.reason, + ); + reconnectStart = null; + } + }); + + // The call intent follows the camera (C11). Before the join the crate + // refuses, which is expected. + muteStates.video.enabled$.pipe(scope.bind()).subscribe((videoEnabled) => { + participation + .updateApplication(videoEnabled ? "video" : "audio") + .catch((e) => { + logger.debug( + "Could not update the call intent (expected before the join)", + e, + ); + }); + }); + + return { + startTracks, + requestJoinAndPublish, + requestDisconnect, + localMemberState$, + participant$, + reconnecting$, + connected$: matrixAndLivekitConnected$, + disconnected$: scope.behavior( + matrixConnection$.pipe( + map((c) => c.status === MatrixConnectionStatus.Disconnected), + ), + ), + sharingScreen$, + toggleScreenSharing, + screenShareError$, + dismissScreenShareError, + connection$: localConnection$, + internalLoggerRef: logger, + }; +}; diff --git a/src/state/CallViewModel/remoteMembers/Connection.ts b/src/state/CallViewModel/remoteMembers/Connection.ts index 7889f9004..dbcdf8b9c 100644 --- a/src/state/CallViewModel/remoteMembers/Connection.ts +++ b/src/state/CallViewModel/remoteMembers/Connection.ts @@ -53,8 +53,12 @@ export interface ConnectionOpts { ownMembershipIdentity: CallMembershipIdentityParts; /** The media transport to connect to. */ transport: LivekitTransportConfig; - /** The Matrix client to use for OpenID and SFU config requests. */ - client: OpenIDClientParts; + /** + * The Matrix client to use for OpenID and SFU config requests. `null` when + * every connection comes with its token already (the crate mints them), in + * which case a connection without `existingSFUConfig` cannot start. + */ + client: OpenIDClientParts | null; /** The room ID this connection is associated with. */ roomId: string; /** The observable scope to use for this connection. */ @@ -137,7 +141,7 @@ export class Connection { protected stopped = false; // TODO: can we just keep the ConnectionOpts object instead of spreading? - private readonly client: OpenIDClientParts; + private readonly client: OpenIDClientParts | null; private readonly roomId: string; private readonly logger: Logger; private readonly ownMembershipIdentity: CallMembershipIdentityParts; @@ -398,6 +402,10 @@ export class Connection { protected async getSFUConfigForRemoteConnection(): Promise { // This will only be called for sfu's where we do not publish ourselves. // For the local connection we will use the existingJwtTokenData + if (this.client === null) + throw new FailedToStartError( + "No token for this connection and no client to fetch one with", + ); return await getSFUConfigWithOpenID( this.client, this.ownMembershipIdentity, diff --git a/src/state/CallViewModel/remoteMembers/ConnectionFactory.ts b/src/state/CallViewModel/remoteMembers/ConnectionFactory.ts index 30ff37f3e..89c8331c1 100644 --- a/src/state/CallViewModel/remoteMembers/ConnectionFactory.ts +++ b/src/state/CallViewModel/remoteMembers/ConnectionFactory.ts @@ -57,7 +57,7 @@ export class ECConnectionFactory implements ConnectionFactory { /** * Creates a ConnectionFactory for LiveKit connections. * - * @param client - The OpenID client parts for authentication, needed to get openID and JWT tokens. + * @param client - The OpenID client parts for authentication, needed to get openID and JWT tokens. `null` when every connection is created with its token (the crate mints them). * @param roomId - The current room ID. * @param devices - Used for video/audio out/in capture options. * @param processorState$ - Effects like background blur (only for publishing connection?) @@ -66,7 +66,7 @@ export class ECConnectionFactory implements ConnectionFactory { * @param livekitRoomFactory - Optional factory function (for testing) to create LivekitRoom instances. If not provided, a default factory is used. */ public constructor( - private client: OpenIDClientParts, + private client: OpenIDClientParts | null, private readonly roomId: string, private devices: MediaDevices, private processorState$: Behavior, diff --git a/src/state/CallViewModel/remoteMembers/MatrixLivekitMembers.ts b/src/state/CallViewModel/remoteMembers/MatrixLivekitMembers.ts index 76f4670ec..673f914f1 100644 --- a/src/state/CallViewModel/remoteMembers/MatrixLivekitMembers.ts +++ b/src/state/CallViewModel/remoteMembers/MatrixLivekitMembers.ts @@ -31,8 +31,26 @@ export type TaggedParticipant = | LocalTaggedParticipant | RemoteTaggedParticipant; +/** + * What a tile needs to know about a call member, whichever MatrixRTC + * implementation produced it: matrix-js-sdk's `CallMembership` has this shape, + * and the crate's `FfiMembership` is projected onto it. + */ +export interface CallMember { + userId: string; + /** + * The member's device. The crate does not always know it (an unencrypted + * room, a pre-sticky event); the projection then falls back to the member + * id, which keeps the `${userId}:${deviceId}` media ids unique. + */ + deviceId: string; + memberId: string; + /** The LiveKit participant identity, once known. */ + rtcBackendIdentity: string | undefined; +} + export interface MatrixLivekitMember { - membership$: Behavior; + membership$: Behavior; connection$: Behavior; // participantId: string; We do not want a participantId here since it will be generated by the jwt // TODO decide if we can also drop the userId. Its in the matrix membership anyways. diff --git a/src/state/CallViewModel/remoteMembers/MatrixMemberMetadata.ts b/src/state/CallViewModel/remoteMembers/MatrixMemberMetadata.ts index 6a448128c..a7be6fe59 100644 --- a/src/state/CallViewModel/remoteMembers/MatrixMemberMetadata.ts +++ b/src/state/CallViewModel/remoteMembers/MatrixMemberMetadata.ts @@ -109,6 +109,11 @@ export const memberDisplaynames$ = ( ); }; +/** Per-member display names and avatars, disambiguated over the call. */ +export type MatrixMemberMetadata = ReturnType< + typeof createMatrixMemberMetadata$ +>; + export const createMatrixMemberMetadata$ = ( scope: ObservableScope, memberships$: Behavior[]>, diff --git a/src/state/CallViewModel/remoteMembers/ParticipationConnections.test.ts b/src/state/CallViewModel/remoteMembers/ParticipationConnections.test.ts new file mode 100644 index 000000000..2e64438be --- /dev/null +++ b/src/state/CallViewModel/remoteMembers/ParticipationConnections.test.ts @@ -0,0 +1,123 @@ +/* +Copyright 2026 Element Creations Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE in the repository root for full details. +*/ + +import { describe, expect, it } from "vitest"; +import { logger } from "matrix-js-sdk/lib/logger"; + +import { + MockConnection, + mockLivekitRoom, + mockLocalParticipant, + testScope, +} from "../../../utils/test"; +import { + FakeParticipation, + fakeConnection, +} from "../../../utils/test-participation"; +import { type ConnectionFactory } from "./ConnectionFactory"; +import { createParticipationConnectionManager$ } from "./ParticipationConnections"; + +interface Created { + serviceUrl: string; + jwt: string | undefined; + url: string | undefined; +} + +function recordingFactory(): { + factory: ConnectionFactory; + created: Created[]; +} { + const created: Created[] = []; + const factory: ConnectionFactory = { + createConnection(scope, transport, ownMembershipIdentity, logger, sfu) { + created.push({ + serviceUrl: transport.livekit_service_url, + jwt: sfu?.jwt, + url: sfu?.url, + }); + return new MockConnection( + { + scope, + transport, + ownMembershipIdentity, + existingSFUConfig: sfu, + client: null, + roomId: "!room:example.org", + livekitRoomFactory: () => + mockLivekitRoom({ + localParticipant: mockLocalParticipant({ identity: "" }), + remoteParticipants: new Map(), + }), + }, + logger, + ); + }, + }; + return { factory, created }; +} + +describe("createParticipationConnectionManager$", () => { + it("opens one connection per service with the crate's token and keeps it across a refresh", () => { + const scope = testScope(); + const participation = new FakeParticipation(); + const { factory, created } = recordingFactory(); + const manager = createParticipationConnectionManager$({ + scope, + participation, + connectionFactory: factory, + ownIdentity: { userId: "@me:example.org", deviceId: "MYDEV" }, + logger, + }); + expect(manager.connectionManagerData$.value.value.getConnections()).toEqual( + [], + ); + + participation.connections$.next([ + fakeConnection({ serviceUrl: "https://a", jwtToken: "t1" }), + ]); + expect(created).toEqual([ + { serviceUrl: "https://a", jwt: "t1", url: "wss://a" }, + ]); + const data = manager.connectionManagerData$.value.value; + expect(data.getConnections()).toHaveLength(1); + expect( + data.getConnectionForTransport({ + type: "livekit", + livekit_service_url: "https://a", + })?.transport.livekit_service_url, + ).toBe("https://a"); + + // The crate refreshed the token: the same connection stays up. + participation.connections$.next([ + fakeConnection({ serviceUrl: "https://a", jwtToken: "t2" }), + ]); + expect(created).toHaveLength(1); + + // A second service appears; the first is untouched. + participation.connections$.next([ + fakeConnection({ serviceUrl: "https://a", jwtToken: "t2" }), + fakeConnection({ serviceUrl: "https://b", jwtToken: "t3" }), + ]); + expect(created.map((c) => c.serviceUrl)).toEqual([ + "https://a", + "https://b", + ]); + expect( + manager.connectionManagerData$.value.value.getConnections(), + ).toHaveLength(2); + + // Everybody left the first service: its connection goes away. + participation.connections$.next([ + fakeConnection({ serviceUrl: "https://b", jwtToken: "t3" }), + ]); + expect( + manager.connectionManagerData$.value.value + .getConnections() + .map((c) => c.transport.livekit_service_url), + ).toEqual(["https://b"]); + }); +}); diff --git a/src/state/CallViewModel/remoteMembers/ParticipationConnections.ts b/src/state/CallViewModel/remoteMembers/ParticipationConnections.ts new file mode 100644 index 000000000..1a3ef8a16 --- /dev/null +++ b/src/state/CallViewModel/remoteMembers/ParticipationConnections.ts @@ -0,0 +1,124 @@ +/* +Copyright 2026 Element Creations Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE in the repository root for full details. +*/ + +import { combineLatest, map, of, skip, switchMap } from "rxjs"; +import { type Logger } from "matrix-js-sdk/lib/logger"; + +import { type Behavior } from "../../Behavior"; +import { Epoch, type ObservableScope, trackEpoch } from "../../ObservableScope"; +import { generateItemsWithEpoch } from "../../../utils/observable"; +import { type FfiConnectionWithMembers } from "../../../matrix-rtc-sdk"; +import { type ConnectionFactory } from "./ConnectionFactory"; +import { + ConnectionManagerData, + type IConnectionManager, +} from "./ConnectionManager"; + +/** What this module needs from a {@link CallParticipation}. */ +export interface ParticipationConnectionsSource { + /** The LiveKit rooms to hold, with a token for each, keyed by service URL. */ + connections$: Behavior; +} + +interface Props { + scope: ObservableScope; + participation: ParticipationConnectionsSource; + connectionFactory: ConnectionFactory; + /** Who we publish as. Connections only log it; the tokens come minted. */ + ownIdentity: { userId: string; deviceId: string }; + logger: Logger; +} + +/** + * One LiveKit connection per transport the crate says the session uses — ours + * and everybody else's — each started with the token the crate minted for + * it. The crate discovers the transports, mints and refreshes the tokens; + * this only turns its list into live `Connection`s, keyed by service URL so a + * refreshed token does not tear a connection down. + */ +export function createParticipationConnectionManager$({ + scope, + participation, + connectionFactory, + ownIdentity, + logger: parentLogger, +}: Props): IConnectionManager { + const logger = parentLogger.getChild("[ParticipationConnections]"); + + const connections$ = scope.behavior( + participation.connections$.pipe( + trackEpoch(), + generateItemsWithEpoch( + "ParticipationConnections connections$", + function* (connections) { + for (const { connection } of connections) { + yield { + keys: [connection.serviceUrl] as const, + data: { wsUrl: connection.wsUrl, jwt: connection.jwtToken }, + }; + } + }, + (scope, token$, serviceUrl) => { + const { wsUrl, jwt } = token$.value; + const connection = connectionFactory.createConnection( + scope, + { type: "livekit", livekit_service_url: serviceUrl }, + { ...ownIdentity, memberId: "" }, + logger, + // The crate minted this; nobody asks the authorisation service + // again. The alias and identity are in the token itself. + { url: wsUrl, jwt, livekitAlias: "", livekitIdentity: "" }, + ); + // A token the crate refreshed while we are connected is used on + // the next full (re)connect; livekit-client keeps the session on + // the token it connected with. + // TODO: hand the new token to livekit-client when it can take one. + token$.pipe(skip(1), scope.bind()).subscribe(() => { + logger.info( + `New token for ${serviceUrl}; it is used on the next connect`, + ); + }); + // Start the connection immediately; its state$ tracks progress. + void connection.start(); + return connection; + }, + ), + ), + new Epoch([], -1), + ); + + const connectionManagerData$ = scope.behavior( + connections$.pipe( + switchMap((connections) => { + const epoch = connections.epoch; + if (connections.value.length === 0) + return of(new Epoch(new ConnectionManagerData(), epoch)); + return combineLatest( + connections.value.map((connection) => + connection.remoteParticipants$.pipe( + map((participants) => ({ connection, participants })), + ), + ), + ).pipe( + map( + (lists) => + new Epoch( + lists.reduce((data, { connection, participants }) => { + data.add(connection, participants); + return data; + }, new ConnectionManagerData(logger)), + epoch, + ), + ), + ); + }), + ), + new Epoch(new ConnectionManagerData(), -1), + ); + + return { connectionManagerData$ }; +} diff --git a/src/state/CallViewModel/remoteMembers/ParticipationMemberMetadata.ts b/src/state/CallViewModel/remoteMembers/ParticipationMemberMetadata.ts new file mode 100644 index 000000000..18aa4419a --- /dev/null +++ b/src/state/CallViewModel/remoteMembers/ParticipationMemberMetadata.ts @@ -0,0 +1,47 @@ +/* +Copyright 2026 Element Creations Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE in the repository root for full details. +*/ + +import { map } from "rxjs"; + +import { type Behavior } from "../../Behavior"; +import { type ObservableScope } from "../../ObservableScope"; +import { observeDriver } from "../../../driver/observe"; +import { + type RoomDriver, + type RoomMemberProfile, +} from "../../../driver/ElementCallMatrixClientDriver"; +import { type RoomMemberMap } from "./MatrixMemberMetadata"; + +/** The room's roster as the display-name and ringing code reads it. */ +export function roomMemberMapOf(profiles: RoomMemberProfile[]): RoomMemberMap { + return profiles.reduce((acc, profile) => { + acc.set(profile.userId, { + userId: profile.userId, + rawDisplayName: profile.displayName ?? profile.userId, + getMxcAvatarUrl: () => profile.avatarUrl ?? undefined, + }); + return acc; + }, new Map() as RoomMemberMap); +} + +/** + * The room's joined and invited members, from the client driver. Call + * members' names come from the crate; this is for the people who are in the + * room but not (yet) in the call, and for disambiguating names. + */ +export function createParticipationRoomMembers$( + scope: ObservableScope, + room: RoomDriver, +): Behavior { + return scope.behavior( + observeDriver( + scope, + () => room.getRoomMembers(), + (listener) => room.subscribeRoomMembers(listener), + ).pipe(map(roomMemberMapOf)), + ); +} diff --git a/src/state/CallViewModel/remoteMembers/ParticipationMembers.test.ts b/src/state/CallViewModel/remoteMembers/ParticipationMembers.test.ts new file mode 100644 index 000000000..110c5f81f --- /dev/null +++ b/src/state/CallViewModel/remoteMembers/ParticipationMembers.test.ts @@ -0,0 +1,121 @@ +/* +Copyright 2026 Element Creations Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE in the repository root for full details. +*/ + +import { describe, expect, it } from "vitest"; +import { logger } from "matrix-js-sdk/lib/logger"; + +import { + MockConnection, + mockLivekitRoom, + mockLocalParticipant, + mockRemoteParticipant, + testScope, +} from "../../../utils/test"; +import { + FakeParticipation, + fakeMembership, +} from "../../../utils/test-participation"; +import { constant } from "../../Behavior"; +import { Epoch } from "../../ObservableScope"; +import { ConnectionManagerData } from "./ConnectionManager"; +import { + callMemberOf, + createParticipationRemoteMembers$, +} from "./ParticipationMembers"; + +const LK = "https://lk.example.org"; + +describe("callMemberOf", () => { + it("projects the crate's membership onto what a tile needs", () => { + expect( + callMemberOf( + fakeMembership({ + member: { memberId: "m-1", userId: "@a:x", deviceId: "DEV" }, + transportIdentity: "lk-1", + }), + ), + ).toEqual({ + userId: "@a:x", + deviceId: "DEV", + memberId: "m-1", + rtcBackendIdentity: "lk-1", + }); + // No device known: the member id keeps the media id unique. + expect( + callMemberOf( + fakeMembership({ member: { memberId: "m-2", deviceId: undefined } }), + ).deviceId, + ).toBe("m-2"); + }); +}); + +describe("createParticipationRemoteMembers$", () => { + it("lists everyone but us, with their connection and participant", () => { + const scope = testScope(); + const participation = new FakeParticipation(); + participation.ownMemberId$.next("m-me"); + + const connection = new MockConnection( + { + scope, + transport: { type: "livekit", livekit_service_url: LK }, + ownMembershipIdentity: { + userId: "@me:x", + deviceId: "MYDEV", + memberId: "m-me", + }, + client: null, + roomId: "!room:x", + livekitRoomFactory: () => + mockLivekitRoom({ + localParticipant: mockLocalParticipant({ identity: "lk-me" }), + remoteParticipants: new Map(), + }), + }, + logger, + ); + const peerParticipant = mockRemoteParticipant({ identity: "lk-peer" }); + const data = new ConnectionManagerData(); + data.add(connection, [peerParticipant]); + + const members$ = createParticipationRemoteMembers$({ + scope, + participation, + connectionManager: { + connectionManagerData$: constant(new Epoch(data, 1)), + }, + }); + expect(members$.value.value).toEqual([]); + + participation.setMemberships([ + fakeMembership({ member: { memberId: "m-me", userId: "@me:x" } }), + fakeMembership({ + member: { memberId: "m-peer", userId: "@peer:x" }, + connections: [LK], + transportIdentity: "lk-peer", + }), + // Not on LiveKit yet (no token minted for them): no participant. + fakeMembership({ + member: { memberId: "m-late", userId: "@late:x" }, + connections: ["https://elsewhere.example.org"], + transportIdentity: "lk-late", + }), + ]); + + const members = members$.value.value; + expect(members.map((m) => m.membership$.value.memberId)).toEqual([ + "m-peer", + "m-late", + ]); + const [peer, late] = members; + expect(peer.userId).toBe("@peer:x"); + expect(peer.connection$.value).toBe(connection); + expect(peer.participant.value$.value).toBe(peerParticipant); + expect(late.connection$.value).toBeNull(); + expect(late.participant.value$.value).toBeNull(); + }); +}); diff --git a/src/state/CallViewModel/remoteMembers/ParticipationMembers.ts b/src/state/CallViewModel/remoteMembers/ParticipationMembers.ts new file mode 100644 index 000000000..a4cb30dba --- /dev/null +++ b/src/state/CallViewModel/remoteMembers/ParticipationMembers.ts @@ -0,0 +1,132 @@ +/* +Copyright 2026 Element Creations Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE in the repository root for full details. +*/ + +import { combineLatest, map } from "rxjs"; +import { logger } from "matrix-js-sdk/lib/logger"; + +import { type Behavior } from "../../Behavior"; +import { Epoch, type ObservableScope } from "../../ObservableScope"; +import { generateItemsWithEpoch } from "../../../utils/observable"; +import { type FfiMembership } from "../../../matrix-rtc-sdk"; +import { type IConnectionManager } from "./ConnectionManager"; +import { + type CallMember, + type RemoteMatrixLivekitMember, +} from "./MatrixLivekitMembers"; + +/** What this module needs from a {@link CallParticipation}. */ +export interface ParticipationRoster { + memberships$: Behavior>; + ownMemberId$: Behavior; +} + +/** The crate's membership as a tile sees it. */ +export function callMemberOf(membership: FfiMembership): CallMember { + const { member } = membership; + return { + userId: member.userId, + deviceId: member.deviceId ?? member.memberId, + memberId: member.memberId, + rtcBackendIdentity: membership.transportIdentity, + }; +} + +interface Props { + scope: ObservableScope; + participation: ParticipationRoster; + connectionManager: IConnectionManager; +} + +/** + * The remote members of the call with their LiveKit side: the connection to + * the transport they publish on and, once they are on it, their participant + * — matched by the transport identity the crate derived for them. + */ +export function createParticipationRemoteMembers$({ + scope, + participation, + connectionManager, +}: Props): Behavior> { + return scope.behavior( + combineLatest([ + participation.memberships$, + participation.ownMemberId$, + connectionManager.connectionManagerData$, + ]).pipe( + map( + ([memberships, ownMemberId, data]) => + new Epoch( + [memberships.value, ownMemberId, data.value] as const, + memberships.epoch, + ), + ), + generateItemsWithEpoch( + "ParticipationRemoteMembers", + function* ([memberships, ownMemberId, managerData]) { + for (const membership of memberships) { + const { member, transportIdentity } = membership; + if (member.memberId === ownMemberId) continue; + + // The crate lists the services a member publishes on; today a + // member publishes on at most one. + const serviceUrl = membership.connections[0]; + const transport = + serviceUrl === undefined + ? null + : { type: "livekit" as const, livekit_service_url: serviceUrl }; + const participants = transport + ? managerData.getParticipantsForTransport(transport) + : []; + const matches = participants.filter( + (p) => p.identity === transportIdentity, + ); + const participant = matches[0] ?? null; + const connection = transport + ? managerData.getConnectionForTransport(transport) + : null; + if (matches.length > 1) + logger.warn( + `[ParticipationRemoteMembers] ${transportIdentity}: ${matches.length} LiveKit participants match (sids ${matches.map((p) => p.sid).join(", ")}), using ${participant?.sid}`, + ); + + yield { + // The member id is the key; the rest is there for the logs. + keys: [ + member.memberId, + member.userId, + member.deviceId ?? "", + transportIdentity ?? "", + ], + data: { + membership: callMemberOf(membership), + participant, + connection, + }, + }; + } + }, + (scope, data$, _memberId, userId, _deviceId, rtcBackendIdentity) => { + const { participant$, ...rest } = scope.splitBehavior(data$); + // Log whether the member could be matched to a LiveKit participant, + // since a tile shows "waiting for media" for as long as it cannot. + participant$.pipe(scope.bind()).subscribe((p) => { + const url = data$.value.connection?.transport.livekit_service_url; + logger.info( + `[ParticipationRemoteMembers] ${rtcBackendIdentity}: LiveKit participant ${p ? `matched (${p.sid})` : "missing"} on ${url ?? "no connection"}`, + ); + }); + return { + userId, + participant: { type: "remote" as const, value$: participant$ }, + ...rest, + }; + }, + ), + ), + new Epoch([], -1), + ); +} diff --git a/src/state/rtc/CallParticipation.backend.test.ts b/src/state/rtc/CallParticipation.backend.test.ts new file mode 100644 index 000000000..2e0bb2c56 --- /dev/null +++ b/src/state/rtc/CallParticipation.backend.test.ts @@ -0,0 +1,517 @@ +/* +Copyright 2026 Element Creations Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE in the repository root for full details. +*/ + +/** + * Full integration against the dev backend (`pnpm backend`: Synapse develop, + * lk-jwt-service and LiveKit behind nginx with the dev TLS certificate) + * through the js-sdk drivers: two real users in one encrypted room, two + * participations, and every wire feature the crate relies on — transport + * discovery, the slot state event, sticky member events, delayed events and + * their delegation, the token exchange, Olm-encrypted media keys and + * homeserver connectivity. + * + * Opt-in, because it needs the backend and takes a minute: + * + * MATRIX_RTC_BACKEND=1 NODE_TLS_REJECT_UNAUTHORIZED=0 \ + * pnpm vitest run --project unit src/state/rtc/CallParticipation.backend.test.ts + * + * `HOMESERVER_URL` overrides the homeserver (default: the dev backend). + */ + +// The global `process` is vite-plugin-node-polyfills' browser shim, whose +// `env` is empty; the real one comes from the module. +import { env } from "node:process"; +import { beforeAll, describe, expect, it } from "vitest"; +import { + ClientEvent, + createClient, + type MatrixClient, + Method, + Preset, + type Room, + SyncState, +} from "matrix-js-sdk"; +import { logger } from "matrix-js-sdk/lib/logger"; + +import { MatrixRTCMode } from "../../config/ConfigOptions"; +import { JsSdkElementCallMatrixClientDriver } from "../../driver/jsSdk/JsSdkElementCallMatrixClientDriver"; +import { JsSdkRtcMatrixDriver } from "../../driver/jsSdk/JsSdkRtcMatrixDriver"; +import { waitFor } from "../../driver/MockRtcMatrixDriver"; +import { + FfiDelegationRoute, + FfiImpairment, + FfiKeepAlive, + FfiStatus, +} from "../../matrix-rtc-sdk"; +import { initMatrixRtcSdkForTests } from "../../utils/test-matrix-rtc"; +import { testScope } from "../../utils/test"; +import { CallParticipation } from "./CallParticipation"; +import { joinParamsFromConfig, participationConfig } from "./joinParams"; +import { ELEMENT_CALL_SLOT_EVENT_TYPE, ELEMENT_CALL_SLOT_ID } from "./slot"; +import { publishOnLivekit } from "./transportIntent"; + +const enabled = env.MATRIX_RTC_BACKEND === "1"; +const HOMESERVER_URL = ( + env.HOMESERVER_URL ?? "https://synapse.m.localhost" +).replace(/\/$/, ""); +/** The transport `backend/dev_homeserver.yaml` advertises. */ +const DEV_LIVEKIT_SERVICE_URL = "https://matrix-rtc.m.localhost/livekit/jwt"; +const DELAYED_EVENTS_PREFIX = "/_matrix/client/unstable/org.matrix.msc4140"; + +const session = { + delayed_leave: { delay_ms: 18_000 }, + delegated_delayed_leave: { delay_ms: 3_600_000 }, + network_error_retry_ms: 1000, + wait_for_key_rotation_ms: 50, +}; + +interface TestUser { + name: string; + client: MatrixClient; + room: Room; + userId: string; + deviceId: string; + rtcDriver: JsSdkRtcMatrixDriver; + clientDriver: JsSdkElementCallMatrixClientDriver; + stop: () => void; +} + +interface DelayedEvent { + delay_id: string; + room_id: string; + type: string; + state_key?: string; + delay: number; + running_since: number; + content: Record; +} + +const log = (who: string, line: string): void => + // Progress of an opt-in integration run, meant to be read. + // eslint-disable-next-line no-console + console.log(`[backend ${who}] ${line}`); + +/** + * Register a throwaway user, boot rust crypto, sync, and be in the room. + * `legacyMembers` gives every member the power to send the MSC3401 member + * *state* event, as Element Call's own rooms do (`state_default: 0`); a + * plain room keeps the default 50, which also keeps Bob from opening a slot. + */ +async function createUser( + name: string, + roomId?: string, + { encrypted = true, legacyMembers = false } = {}, +): Promise { + const localpart = `ec-${name.toLowerCase()}-${Date.now().toString(16)}${Math.floor( + Math.random() * 0xffff, + ).toString(16)}`; + const register = async (): Promise => + fetch(`${HOMESERVER_URL}/_matrix/client/v3/register`, { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify({ + username: localpart, + password: `test-${localpart}`, + auth: { type: "m.login.dummy" }, + }), + }); + let response = await register(); + // Synapse rate-limits registrations; the second case of this file runs + // straight into that. + while (response.status === 429) { + const { retry_after_ms: retryAfterMs = 1000 } = (await response.json()) as { + retry_after_ms?: number; + }; + await new Promise((resolve) => setTimeout(resolve, retryAfterMs + 100)); + response = await register(); + } + if (!response.ok) + throw new Error( + `registration failed: ${response.status} ${await response.text()}`, + ); + const { + user_id: userId, + device_id: deviceId, + access_token: accessToken, + } = (await response.json()) as { + user_id: string; + device_id: string; + access_token: string; + }; + const client = createClient({ + baseUrl: HOMESERVER_URL, + accessToken, + userId, + deviceId, + logger: logger.getChild(`[${name}]`), + }); + // In memory on purpose: every run is a fresh device. + await client.initRustCrypto({ useIndexedDB: false }); + await client.setDisplayName(name); + void client.startClient(); + await new Promise((resolve, reject) => { + client.once(ClientEvent.Sync, (state) => + state === SyncState.Prepared + ? resolve() + : reject(new Error(`sync failed: ${state}`)), + ); + }); + + if (roomId === undefined) { + const created = await client.createRoom({ + preset: Preset.PublicChat, + name: `Element Call backend check ${new Date().toISOString()}`, + power_level_content_override: legacyMembers + ? { events: { "org.matrix.msc3401.call.member": 0 } } + : undefined, + initial_state: encrypted + ? [ + { + type: "m.room.encryption", + state_key: "", + content: { algorithm: "m.megolm.v1.aes-sha2" }, + }, + ] + : [], + }); + roomId = created.room_id; + } else { + await client.joinRoom(roomId); + } + await waitFor( + `${name}'s room to appear in sync`, + () => client.getRoom(roomId) !== null, + 10_000, + ); + const room = client.getRoom(roomId)!; + log(name, `ready as ${userId} (${deviceId}) in ${roomId}`); + + const rtcDriver = new JsSdkRtcMatrixDriver(client, room); + const clientDriver = new JsSdkElementCallMatrixClientDriver(client, room); + return { + name, + client, + room, + userId, + deviceId, + rtcDriver, + clientDriver, + stop: () => { + rtcDriver.detach(); + client.stopClient(); + }, + }; +} + +function participate( + user: TestUser, + mode: MatrixRTCMode, + manageMediaKeys: boolean, +): CallParticipation { + return new CallParticipation( + testScope(), + user.rtcDriver, + user.room.roomId, + user.userId, + user.deviceId, + { + config: participationConfig({ mode, manageMediaKeys, session }), + logger: logger.getChild(`[${user.name}]`), + }, + ); +} + +async function listDelayedEvents( + client: MatrixClient, +): Promise { + const response = await client.http.authedRequest<{ + delayed_events: DelayedEvent[]; + }>(Method.Get, "/delayed_events", undefined, undefined, { + prefix: DELAYED_EVENTS_PREFIX, + }); + return response.delayed_events; +} + +async function fetchRawEvent( + client: MatrixClient, + roomId: string, + eventId: string, +): Promise> { + return (await client.fetchRoomEvent(roomId, eventId)) as unknown as Record< + string, + unknown + >; +} + +function connected( + participation: CallParticipation, +): InstanceType["inner"] { + const status = participation.status$.value; + if (!FfiStatus.Connected.instanceOf(status)) + throw new Error(`Expected Connected, got ${status.tag}`); + return status.inner; +} + +describe.skipIf(!enabled)("CallParticipation against the dev backend", () => { + beforeAll(async () => { + // The two clients' crypto debug output would drown everything else. + (logger as unknown as { setLevel(level: string): void }).setLevel("warn"); + await initMatrixRtcSdkForTests(); + }); + + it.each([ + { + mode: MatrixRTCMode.Matrix_2_0, + memberEventType: "org.matrix.msc4143.rtc.member", + sticky: true, + }, + { + mode: MatrixRTCMode.Compatibility, + memberEventType: "org.matrix.msc3401.call.member", + sticky: false, + }, + ])( + "two users call each other in $mode mode", + async ({ mode, memberEventType, sticky }) => { + const alice = await createUser("Alice", undefined, { + legacyMembers: !sticky, + }); + const bob = await createUser("Bob", alice.room.roomId); + const roomId = alice.room.roomId; + const a = participate(alice, mode, true); + const b = participate(bob, mode, true); + const joinParams = joinParamsFromConfig({ + session, + delegateDelayedLeave: true, + }); + const dump = (): void => { + log("alice", `snapshot: ${a.debugSnapshot()}`); + log("bob", `snapshot: ${b.debugSnapshot()}`); + }; + try { + // --- connectivity, before anything else ------------------------------ + expect(alice.rtcDriver.isHomeserverConnected()).toBe(true); + + // --- the slot ---------------------------------------------------------- + // A fresh room has no slot. Alice created it, so she may open one; Bob + // (power level 0, state_default 50) may not. + await waitFor("the seed", () => a.session$.value.seeded, 15_000); + expect(a.session$.value.slotOpen).not.toBe(true); + expect( + alice.room.currentState.getStateEvents(ELEMENT_CALL_SLOT_EVENT_TYPE), + ).toEqual([]); + const aliceRoom = alice.clientDriver.getRoomInfo(); + const bobRoom = bob.clientDriver.getRoomInfo(); + expect(aliceRoom.encrypted).toBe(true); + expect(aliceRoom.canOpenSlot).toBe(true); + expect(bobRoom.canOpenSlot).toBe(false); + + // --- Alice joins: opens the slot, discovers the transport, publishes -- + await a.join(publishOnLivekit(), joinParams, { + encrypted: aliceRoom.encrypted, + canOpen: aliceRoom.canOpenSlot, + }); + const aliceStatus = connected(a); + log("alice", `joined: keepAlive=${aliceStatus.keepAlive.tag}`); + + const slot = alice.room.currentState.getStateEvents( + ELEMENT_CALL_SLOT_EVENT_TYPE, + ELEMENT_CALL_SLOT_ID, + ); + if (sticky) { + expect(slot?.getContent()).toMatchObject({ + status: "open", + application: { type: "m.call" }, + encryption: { type: "m.per_member" }, + }); + await waitFor( + "bob to see the slot", + () => b.session$.value.slotOpen === true, + 15_000, + ); + } else { + // The pre-slot generation: nothing opened, nothing to wait for. + expect(slot).toBeNull(); + } + + // The transport came from the homeserver's /rtc/transports. + const [connection] = a.connections$.value; + expect(connection.connection.serviceUrl).toBe(DEV_LIVEKIT_SERVICE_URL); + expect(connection.connection.jwtToken.split(".")).toHaveLength(3); + expect(connection.connection.wsUrl).toMatch(/^wss:\/\//); + + // --- the member event on the wire ------------------------------------- + await waitFor( + "alice to see her own membership", + () => a.ownMembership$.value !== null, + 15_000, + ); + const ownEventId = a.ownMembership$.value!.member.eventId; + expect(ownEventId).toBeDefined(); + const raw = await fetchRawEvent(alice.client, roomId, ownEventId!); + log("alice", `own member event: ${JSON.stringify(raw)}`); + if (sticky) { + // A sticky event is a timeline event: in an encrypted room matrix-js-sdk + // Megolm-encrypts it like any other (its own MatrixRTC code decrypts + // them on the way in, as our driver does). The sticky marker is in + // the clear. + expect(raw.type).toBe("m.room.encrypted"); + expect(raw.state_key).toBeUndefined(); + expect(raw).toHaveProperty("msc4354_sticky"); + const decrypted = [...alice.room._unstable_getStickyEvents()].find( + (e) => e.getId() === ownEventId, + ); + expect(decrypted?.getType()).toBe(memberEventType); + } else { + expect(raw.type).toBe(memberEventType); + expect(raw.state_key).toBe( + `_${alice.userId}_${alice.deviceId}_m.call`, + ); + } + + // --- delayed events and their delegation ------------------------------- + const delayed = await listDelayedEvents(alice.client); + log("alice", `delayed events: ${JSON.stringify(delayed)}`); + expect(delayed).toHaveLength(1); + expect(delayed[0].room_id).toBe(roomId); + expect(delayed[0].type).toBe(memberEventType); + const keepAlive = aliceStatus.keepAlive; + if (sticky) { + // The dev Synapse proxies `rtc/livekit/*` to lk-jwt-service + // (MSC4512), so the homeserver route takes the long leave over. + expect(FfiKeepAlive.Delegated.instanceOf(keepAlive)).toBe(true); + expect( + (keepAlive as InstanceType).inner + .via, + ).toBe(FfiDelegationRoute.Homeserver); + expect(delayed[0].delay).toBe( + session.delegated_delayed_leave.delay_ms, + ); + } else { + // MSC4195 is not spoken for the pre-slot generation: our own leave. + expect(FfiKeepAlive.Armed.instanceOf(keepAlive)).toBe(true); + expect(delayed[0].delay).toBe(session.delayed_leave.delay_ms); + } + + // --- Bob joins: roster, profiles, one connection with two members ----- + await b.join(publishOnLivekit(), joinParams, { + encrypted: bobRoom.encrypted, + canOpen: bobRoom.canOpenSlot, + }); + connected(b); + await waitFor( + "alice to see bob", + () => + a.memberships$.value.value.some( + (m) => m.member.userId === bob.userId, + ), + 20_000, + ); + await waitFor( + "bob to see alice", + () => + b.memberships$.value.value.some( + (m) => m.member.userId === alice.userId, + ), + 20_000, + ); + const bobSeenByAlice = a.memberships$.value.value.find( + (m) => m.member.userId === bob.userId, + )!; + expect(bobSeenByAlice.member.displayName).toBe("Bob"); + expect(bobSeenByAlice.member.deviceId).toBe(bob.deviceId); + expect(bobSeenByAlice.connections).toEqual([DEV_LIVEKIT_SERVICE_URL]); + await waitFor( + "two members on alice's connection", + () => a.connections$.value[0]?.members.length === 2, + 20_000, + ); + + // --- media keys, Olm-encrypted to-device both ways --------------------- + await waitFor( + "bob to hold alice's key", + () => + b.keyMap$.value.some((k) => k.memberId === a.ownMemberId$.value), + 30_000, + ); + await waitFor( + "alice to hold bob's key", + () => + a.keyMap$.value.some((k) => k.memberId === b.ownMemberId$.value), + 30_000, + ); + await waitFor( + "alice to know bob holds her key", + () => + a.memberships$.value.value.find( + (m) => m.member.userId === bob.userId, + )?.mediaKey?.holdsOurKey === true, + 30_000, + ); + const bobKeyState = a.memberships$.value.value.find( + (m) => m.member.userId === bob.userId, + )!.mediaKey!; + log("alice", `bob's key state: ${JSON.stringify(bobKeyState)}`); + expect(bobKeyState.haveTheirKey).toBe(true); + expect(bobKeyState.rejection).toBeUndefined(); + // MSC4153 verdict travels with the key (C10): nobody here is + // cross-signed, so the answer is "no", not "unknown". + expect(bobKeyState.senderCrossSigned).toBe(false); + + // --- Alice leaves: delayed events cancelled, Bob sees her go ----------- + await a.leave("m.user_hangup"); + expect(FfiStatus.Disconnected.instanceOf(a.status$.value)).toBe(true); + expect(await listDelayedEvents(alice.client)).toEqual([]); + await waitFor( + "bob to see alice gone", + () => + !b.memberships$.value.value.some( + (m) => m.member.userId === alice.userId, + ), + 20_000, + ); + + // --- losing the homeserver is a critical impairment (C12) ------------- + // Bob's network goes away: every request fails and the long-poll in + // flight is cut, so matrix-js-sdk's sync loop leaves `Syncing`. + const { opts } = bob.client.http; + opts.fetchFn = async () => { + return Promise.reject(new TypeError("network down")); + }; + bob.client.http.abort(); + const unreachable = (): boolean => + connected(b).impairments.some((i) => + FfiImpairment.HomeserverUnreachable.instanceOf(i), + ); + await waitFor( + "bob's participation to notice the homeserver is gone", + unreachable, + 15_000, + ); + // ...and comes back: the sync loop recovers and the impairment clears. + delete opts.fetchFn; + await waitFor( + "bob's participation to see the homeserver again", + () => !unreachable(), + 30_000, + ); + await b.leave(); + expect(FfiStatus.Disconnected.instanceOf(b.status$.value)).toBe(true); + } catch (e) { + dump(); + throw e; + } finally { + // Leave before the clients stop: a leave needs the homeserver. + await a.leave(); + await b.leave(); + alice.stop(); + bob.stop(); + } + }, + 180_000, + ); +}); diff --git a/src/state/rtc/CallParticipation.test.ts b/src/state/rtc/CallParticipation.test.ts index e768f39f0..5a46d44fe 100644 --- a/src/state/rtc/CallParticipation.test.ts +++ b/src/state/rtc/CallParticipation.test.ts @@ -18,6 +18,7 @@ import { import { FfiDisconnectCause, FfiElementCallCompat, + FfiEventOrigin, FfiStatus, type FfiMediaKey, } from "../../matrix-rtc-sdk"; @@ -86,6 +87,65 @@ describe("CallParticipation", () => { await initMatrixRtcSdkForTests(); }); + it("in compatibility mode joins with a legacy state event and no slot", async () => { + // a room that never had a slot, as every pre-slot room is + const driver = new MockRtcMatrixDriver(); + const callParticipation = new CallParticipation( + testScope(), + driver, + driver.roomId, + driver.userId, + driver.deviceId, + { + config: participationConfig({ + mode: MatrixRTCMode.Compatibility, + manageMediaKeys: false, + session, + }), + }, + ); + // no power to open a slot, and none is needed + await callParticipation.join(receiveOnly(), joinParams, { + encrypted: false, + canOpen: false, + }); + expect( + FfiStatus.Connected.instanceOf(callParticipation.status$.value), + ).toBe(true); + const stateEvents = driver.calls("stateEvent"); + expect(stateEvents.map((c) => c.eventType)).toEqual([ + "org.matrix.msc3401.call.member", + ]); + expect(stateEvents[0].stateKey).toBe( + `_${driver.userId}_${driver.deviceId}_m.call`, + ); + // our own legacy membership echoes back into the roster + await waitFor( + "own membership", + () => callParticipation.ownMembership$.value !== null, + ); + expect(callParticipation.ownMemberId$.value).toBe( + `${driver.userId}:${driver.deviceId}`, + ); + }); + + it("session$ follows the seed and the slot without a join", async () => { + const driver = new MockRtcMatrixDriver(); + const callParticipation = create(driver); + expect(callParticipation.session$.value.seeded).toBe(false); + await waitFor("the seed", () => callParticipation.session$.value.seeded); + expect(callParticipation.session$.value.slotOpen).not.toBe(true); + // somebody else starts the call + driver.emitRoomEvent( + slotEvent({ status: "open" }), + new FfiEventOrigin.Cleartext(), + ); + await waitFor( + "the slot to open", + () => callParticipation.session$.value.slotOpen === true, + ); + }); + it("starts disconnected and follows a remote member in and out", async () => { // somebody already started the call: the slot is open const driver = new MockRtcMatrixDriver({ @@ -355,7 +415,7 @@ describe("CallParticipation", () => { FfiElementCallCompat.StateEvents, ); expect(compatForMode(MatrixRTCMode.Matrix_2_0)).toBe( - FfiElementCallCompat.StickyEvents, + FfiElementCallCompat.Off, ); expect(joinParams).toEqual({ applicationType: "m.call", @@ -365,6 +425,7 @@ describe("CallParticipation", () => { keepAliveTimeoutMs: 15_000n, degradedLifetimeMs: undefined, delegateDelayedLeave: false, + delegatedDelayMs: 3_600_000n, }); expect( joinParamsFromConfig({ diff --git a/src/state/rtc/CallParticipation.ts b/src/state/rtc/CallParticipation.ts index fd9638618..e284ce7f4 100644 --- a/src/state/rtc/CallParticipation.ts +++ b/src/state/rtc/CallParticipation.ts @@ -32,6 +32,8 @@ import { type FfiSessionSnapshot, type FfiToDeviceDelivery, type FfiToDeviceRecipient, + type FfiHomeserverDelegationRequest, + type FfiTransportDelegationRequest, type FfiTransportIntent, type ConnectivitySinkLike, type RoomEventSinkLike, @@ -41,7 +43,12 @@ import { import { type Behavior } from "../Behavior"; import { Epoch, type ObservableScope, trackEpoch } from "../ObservableScope"; import { NoOpenSlotError } from "../../utils/errors"; -import { ELEMENT_CALL_APPLICATION, ELEMENT_CALL_SLOT_ID } from "./slot"; +import { + ELEMENT_CALL_APPLICATION, + ELEMENT_CALL_SLOT_ID, + LEGACY_SLOT_ID, + slotIdForCompat, +} from "./slot"; import { LIVEKIT_TRANSPORT_TYPE } from "./transportIntent"; /** @@ -61,7 +68,10 @@ export interface SlotPolicy { const SLOT_WAIT_MS = 15_000; export interface CallParticipationOptions { - /** One manager per `(room, slot)`; Element Call has one slot per room. */ + /** + * One manager per `(room, slot)`; Element Call has one slot per room. + * Defaults to the slot for the config's dialect ({@link slotIdForCompat}). + */ slotId?: string; config: FfiParticipationConfig; /** @@ -90,6 +100,7 @@ export class CallParticipation { private readonly matrixDriver: FfiMatrixDriver; private readonly manager: FfiParticipationManager; private ended = false; + private readonly slotId: string; private readonly membershipsSubject$: BehaviorSubject; private readonly connectionsSubject$: BehaviorSubject< @@ -145,9 +156,10 @@ export class CallParticipation { this.logger, ); this.matrixDriver = new FfiMatrixDriver(rtcDriver); + this.slotId = options.slotId ?? slotIdForCompat(options.config.compat); this.manager = new FfiParticipationManager( roomId, - options.slotId ?? ELEMENT_CALL_SLOT_ID, + this.slotId, userId, deviceId, this.matrixDriver, @@ -176,6 +188,13 @@ export class CallParticipation { this.refreshOwnIdentity(); }, }); + // The room's view of the session moves without any membership or status + // of ours changing: the seed completing, somebody opening the slot. + this.manager.setSessionListener({ + onSessionChange: (session) => { + if (!this.ended) this.sessionSubject$.next(session); + }, + }); this.manager.setConnectionsListener({ onConnectionsChange: (connections) => { if (!this.ended) this.connectionsSubject$.next(connections); @@ -248,6 +267,8 @@ export class CallParticipation { } private async ensureOpenSlot(slot: SlotPolicy): Promise { + // The pre-slot generation has no slot to open or check. + if (this.slotId === LEGACY_SLOT_ID) return; // The crate's own `join` waits for the seed too, but the slot check has // to come first: a slot read that has not finished looks like no slot. await this.waitUntil( @@ -291,6 +312,17 @@ export class CallParticipation { } } + /** + * Change the call intent (`m.call.intent`) of our membership while + * joined; the crate re-publishes it (C11). Rejects with the crate's + * `NotJoined` error otherwise, which a caller that merely mirrors the + * camera state can ignore. + */ + public async updateApplication(intent: string | undefined): Promise { + if (this.ended) throw new Error("The participation has ended"); + await this.manager.updateApplication(intent); + } + /** The crate's diagnostics dump, for rageshakes. Not a UI contract. */ public debugSnapshot(): string { return this.ended ? "{}" : this.manager.debugSnapshot(); @@ -434,22 +466,15 @@ class TransportFallbackDriver implements RtcMatrixDriver { ): Promise { return this.inner.cancelDelayedEvent(roomId, delayId); } - public async delegateLivekitDelayedLeave( - roomId: string, - slotId: string, - memberJson: string, - delayId: string, - livekitServiceUrl: string | undefined, - delayMs: bigint, + public async delegateDelayedLeaveViaHomeserver( + request: FfiHomeserverDelegationRequest, ): Promise { - return this.inner.delegateLivekitDelayedLeave( - roomId, - slotId, - memberJson, - delayId, - livekitServiceUrl, - delayMs, - ); + return this.inner.delegateDelayedLeaveViaHomeserver(request); + } + public async delegateDelayedLeaveViaTransport( + request: FfiTransportDelegationRequest, + ): Promise { + return this.inner.delegateDelayedLeaveViaTransport(request); } public async sendToDevice( recipients: FfiToDeviceRecipient[], diff --git a/src/state/rtc/joinParams.ts b/src/state/rtc/joinParams.ts index 0ea3271bc..b59f08ea9 100644 --- a/src/state/rtc/joinParams.ts +++ b/src/state/rtc/joinParams.ts @@ -22,17 +22,18 @@ const MAX_STICKY_DURATION_MS = 60 * 60 * 1000; const DEFAULT_MEMBERSHIP_EXPIRY_MS = 4 * 60 * 60 * 1000; /** - * Which pre-2026 Element Call dialect the crate speaks for a given mode. - * `compatibility` is MSC3401 state events; `matrix_2_0` is the sticky - * dialect deployed Element Call clients read today. Spec MSC4143 (`Off`) - * waits until Element Call opens slots. + * Which dialect the crate speaks for a given mode. `compatibility` is + * MSC3401 state events for the clients that predate sticky events; + * `matrix_2_0` is spec MSC4143 — sticky member events, slots (which Element + * Call opens) and the spec key message, the same wire format Element X's + * matrix-rtc crates speak. */ export function compatForMode(mode: MatrixRTCMode): FfiElementCallCompat { switch (mode) { case MatrixRTCMode.Compatibility: return FfiElementCallCompat.StateEvents; case MatrixRTCMode.Matrix_2_0: - return FfiElementCallCompat.StickyEvents; + return FfiElementCallCompat.Off; } } @@ -73,20 +74,24 @@ export interface JoinParamsInputs { session: ResolvedConfigOptions["matrix_rtc_session"]; /** `m.call.intent`: what kind of call the user is starting. */ callIntent?: string; - /** Hand the delayed leave to the SFU (MSC4195) — only where the probe said it can. */ - delegateDelayedLeave: boolean; + /** + * Hand the delayed leave to the SFU (MSC4195). The crate tries the + * homeserver, then the authorisation service, then keeps restarting the + * leave itself, so there is no reason not to ask. Tests turn it off. + */ + delegateDelayedLeave?: boolean; } /** * The crate's join parameters from Element Call's `matrix_rtc_session` * config. Keys the crate has no knob for (`restart_ms`, `restart_timeout_ms`, * `network_error_retry_ms`, `key_rotation_participant_limit`, - * `delegated_delayed_leave.*`) have no effect any more. + * `delegated_delayed_leave.restart_ms`) have no effect any more. */ export function joinParamsFromConfig({ session, callIntent, - delegateDelayedLeave, + delegateDelayedLeave = true, }: JoinParamsInputs): FfiJoinParams { return { applicationType: ELEMENT_CALL_APPLICATION, @@ -100,5 +105,6 @@ export function joinParamsFromConfig({ keepAliveTimeoutMs: BigInt(session.delayed_leave.delay_ms), degradedLifetimeMs: undefined, delegateDelayedLeave, + delegatedDelayMs: BigInt(session.delegated_delayed_leave.delay_ms), }; } diff --git a/src/state/rtc/slot.ts b/src/state/rtc/slot.ts index 137737c1a..aed525380 100644 --- a/src/state/rtc/slot.ts +++ b/src/state/rtc/slot.ts @@ -5,6 +5,8 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial Please see LICENSE in the repository root for full details. */ +import { FfiElementCallCompat } from "../../matrix-rtc-sdk"; + /** * The MatrixRTC slot Element Call lives in, `{application}#{id}` per * MSC4143. One per room: the application is a call and the id is the room's. @@ -17,3 +19,17 @@ export const ELEMENT_CALL_APPLICATION = "m.call"; * it, which is what `RoomInfo.canOpenSlot` answers. */ export const ELEMENT_CALL_SLOT_EVENT_TYPE = "org.matrix.msc4143.rtc.slot"; +/** + * The crate's slot id for the pre-slot generation (MSC3401 state events, + * `MatrixRTCMode.Compatibility`): that generation has no `m.rtc.slot`, so the + * session is projected from the legacy state events alone and nobody opens + * or checks a slot. The crate requires this id under `StateEvents` compat. + */ +export const LEGACY_SLOT_ID = ""; + +/** The slot a participation lives in for a given wire dialect. */ +export function slotIdForCompat(compat: FfiElementCallCompat): string { + return compat === FfiElementCallCompat.StateEvents + ? LEGACY_SLOT_ID + : ELEMENT_CALL_SLOT_ID; +} diff --git a/src/utils/test-participation.ts b/src/utils/test-participation.ts new file mode 100644 index 000000000..c954d7f7b --- /dev/null +++ b/src/utils/test-participation.ts @@ -0,0 +1,110 @@ +/* +Copyright 2026 Element Creations Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE in the repository root for full details. +*/ + +import { BehaviorSubject } from "rxjs"; + +import { + FfiDeviceAttribution, + FfiMembershipState, + type FfiConnectionWithMembers, + type FfiMediaKey, + type FfiMember, + type FfiMembership, +} from "../matrix-rtc-sdk"; +import { Epoch } from "../state/ObservableScope"; + +/** + * Hand-made values of the crate's records, for the modules that consume a + * `CallParticipation`'s behaviors without needing the crate itself. + */ + +export function fakeMember(overrides: Partial = {}): FfiMember { + const memberId = overrides.memberId ?? "m-peer"; + return { + memberId, + userId: "@peer:example.org", + deviceId: "PEERDEV", + deviceAttribution: FfiDeviceAttribution.Verified, + eventId: `$${memberId}`, + publishedTransports: [], + canSubscribe: ["livekit"], + ...overrides, + }; +} + +export function fakeMembership( + overrides: Partial> & { + member?: Partial; + } = {}, +): FfiMembership { + const { member, ...rest } = overrides; + return { + member: fakeMember(member), + state: FfiMembershipState.Joined, + connections: [], + ...rest, + }; +} + +export function fakeConnection( + overrides: Partial & { + members?: FfiMember[]; + } = {}, +): FfiConnectionWithMembers { + const { members = [], ...connection } = overrides; + const serviceUrl = connection.serviceUrl ?? "https://lk.example.org"; + return { + connection: { + serviceUrl, + wsUrl: serviceUrl.replace("https", "wss"), + jwtToken: "jwt", + ...connection, + }, + members, + }; +} + +export function fakeMediaKey( + overrides: Partial = {}, +): FfiMediaKey { + return { + memberId: "m-peer", + key: new Uint8Array(32).fill(7).buffer, + index: 0, + creationTsMs: 0n, + ...overrides, + }; +} + +/** + * The behaviors of a `CallParticipation`, as subjects a test drives by hand. + * Modules take structural slices of the participation, so this stands in for + * it wherever the crate is not what is under test. + */ +export class FakeParticipation { + public readonly memberships$ = new BehaviorSubject( + new Epoch([], 0), + ); + public readonly connections$ = new BehaviorSubject< + FfiConnectionWithMembers[] + >([]); + public readonly keyMap$ = new BehaviorSubject([]); + public readonly ownMemberId$ = new BehaviorSubject(null); + public readonly ownTransportIdentity$ = new BehaviorSubject( + null, + ); + public readonly ownMembership$ = new BehaviorSubject( + null, + ); + + /** Replace the roster, advancing the epoch as the real thing does. */ + public setMemberships(memberships: FfiMembership[]): void { + this.memberships$.next( + new Epoch(memberships, this.memberships$.value.epoch + 1), + ); + } +} diff --git a/src/utils/test-viewmodel.ts b/src/utils/test-viewmodel.ts index 9903b99f8..8a61dc220 100644 --- a/src/utils/test-viewmodel.ts +++ b/src/utils/test-viewmodel.ts @@ -21,7 +21,7 @@ import { ConnectionState, type Room as LivekitRoom } from "livekit-client"; import { E2eeType } from "../e2ee/e2eeType"; import { type CallViewModel, - createCallViewModel$, + createJsClientCallViewModel$, type CallViewModelOptions, } from "../state/CallViewModel/CallViewModel"; import { @@ -159,7 +159,7 @@ export function getBasicCallViewModelEnvironment( const scope = testScope(); const muteStates = mockMuteStates(); const mediaDevices = mediaDevicesOverride ?? mockMediaDevices({}); - const vm = createCallViewModel$( + const vm = createJsClientCallViewModel$( scope, rtcSession.asMockedSession(), matrixRoom, diff --git a/vitest.config.ts b/vitest.config.ts index 905ebd81d..0a5b6511c 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -58,6 +58,7 @@ export default defineConfig((configEnv) => "src/utils/test-viewmodel.ts", "src/utils/test-fixtures.ts", "src/utils/test-matrix-rtc.ts", + "src/utils/test-participation.ts", "src/matrix-rtc-sdk/generated/**", "playwright/**", ],