From 9d5ca297e3bcdba49940c8d0bc14cb73784c8626 Mon Sep 17 00:00:00 2001 From: Valere Date: Wed, 5 Aug 2026 16:12:41 +0200 Subject: [PATCH 1/5] Remove well-known discovery --- docs/self_hosting.md | 22 +++- .../RtcTransportAutoDiscovery.test.ts | 109 +++--------------- .../localMember/RtcTransportAutoDiscovery.ts | 62 +--------- 3 files changed, 38 insertions(+), 155 deletions(-) diff --git a/docs/self_hosting.md b/docs/self_hosting.md index e8ea2f6d8..fc65ba953 100644 --- a/docs/self_hosting.md +++ b/docs/self_hosting.md @@ -191,10 +191,24 @@ backend mxrtc_auth_backend > [!IMPORTANT] > As defined in > [MSC4143](https://github.com/matrix-org/matrix-spec-proposals/pull/4143), -> the MatrixRTC backend(s) must be announced to the client via your **Matrix site's -> `.well-known/matrix/client`** file (e.g. -> `example.com/.well-known/matrix/client` matching the site deployment example -> from above). The configuration is a list of Foci configs: +> the MatrixRTC backend(s) must be announced to the client via `/_matrix/client/unstable/org.matrix.msc4143/rtc/transports`. + +Enable the unstable feature flag `msc4143_enabled`, and update the synapse config file: + +```yaml + +matrix_rtc: + - transports: + - type: livekit + livekit_service_url: https://matrix-rtc.example.com/livekit/jwt +``` + + + +**⚠️ Well-known discovery will soon be deprecated, but needed if MSC4143 is not supported on your Homeserver** + +your **Matrix site's .well-known/matrix/client`** file (e.g. `example.com/.well-known/matrix/client` matching the site deployment example +from above). The configuration is a list of Foci configs: ```json "org.matrix.msc4143.rtc_foci": [ diff --git a/src/state/CallViewModel/localMember/RtcTransportAutoDiscovery.test.ts b/src/state/CallViewModel/localMember/RtcTransportAutoDiscovery.test.ts index 9314b9932..0245c757f 100644 --- a/src/state/CallViewModel/localMember/RtcTransportAutoDiscovery.test.ts +++ b/src/state/CallViewModel/localMember/RtcTransportAutoDiscovery.test.ts @@ -13,7 +13,7 @@ import { type MockedObject, vi, } from "vitest"; -import { type IClientWellKnown, MatrixError } from "matrix-js-sdk"; +import { MatrixError } from "matrix-js-sdk"; import { logger as rootLogger } from "matrix-js-sdk/lib/logger"; import { type LivekitTransportConfig, @@ -33,9 +33,9 @@ const backendTransport: LivekitTransportConfig = { livekit_service_url: "https://backend.example.org", }; -const wellKnownTransport: LivekitTransportConfig = { +const configTransport: LivekitTransportConfig = { type: "livekit", - livekit_service_url: "https://well-known.example.org", + livekit_service_url: "https://config.example.org", }; function makeClient(): MockedObject { @@ -59,12 +59,6 @@ function makeResolvedConfig(livekitServiceUrl?: string): ResolvedConfigOptions { } as ResolvedConfigOptions; } -function makeWellKnown(rtcFoci?: Transport[]): IClientWellKnown { - return { - "org.matrix.msc4143.rtc_foci": rtcFoci, - } as unknown as IClientWellKnown; -} - describe("RtcTransportAutoDiscovery", () => { beforeEach(() => { vi.clearAllMocks(); @@ -75,33 +69,30 @@ describe("RtcTransportAutoDiscovery", () => { { transports: [{ type: "not_livekit" }, backendTransport] }, ]; it.each(VALID_TEST_CASES)( - "prefers backend transport over well-known and app config $transports", + "prefers backend transport other app config $transports", async ({ transports }) => { // it("prefers backend transport over well-known and app config", async () => { const client = makeClient(); client._unstable_getRTCTransports.mockResolvedValue(transports); - const wellKnownFetcher = vi - .fn<(domain: string) => Promise>() - .mockResolvedValue(makeWellKnown([wellKnownTransport])); - const discovery = new RtcTransportAutoDiscovery({ client, - resolvedConfig: makeResolvedConfig("https://config.example.org"), - wellKnownFetcher, + resolvedConfig: makeResolvedConfig(configTransport.livekit_service_url), logger: rootLogger, }); - await expect( - discovery.discoverPreferredTransport(), - ).resolves.toStrictEqual(backendTransport); + + const discoveredTransport = await discovery.discoverPreferredTransport(); + + expect(discoveredTransport).toStrictEqual(backendTransport); + expect(discoveredTransport).not.toStrictEqual(configTransport); expect(client._unstable_getRTCTransports).toHaveBeenCalledTimes(1); - expect(wellKnownFetcher).not.toHaveBeenCalled(); + }, ); - it("Retries limit_exceeded backend transport over well-known", async () => { + it("Retries limit_exceeded backend transport", async () => { const client = makeClient(); client._unstable_getRTCTransports .mockRejectedValueOnce( @@ -116,14 +107,10 @@ describe("RtcTransportAutoDiscovery", () => { ) .mockResolvedValue([backendTransport]); - const wellKnownFetcher = vi - .fn<(domain: string) => Promise>() - .mockResolvedValue(makeWellKnown([wellKnownTransport])); const discovery = new RtcTransportAutoDiscovery({ client, resolvedConfig: makeResolvedConfig("https://config.example.org"), - wellKnownFetcher, logger: rootLogger, }); @@ -132,7 +119,6 @@ describe("RtcTransportAutoDiscovery", () => { ); expect(client._unstable_getRTCTransports).toHaveBeenCalledTimes(2); - expect(wellKnownFetcher).not.toHaveBeenCalled(); }); const INVALID_TEST_CASES: Array<{ transports: Transport[] }> = [ @@ -140,91 +126,32 @@ describe("RtcTransportAutoDiscovery", () => { { transports: [{ type: "not_livekit" }] }, ]; it.each(INVALID_TEST_CASES)( - "falls back to well-known when backend has no (valid) livekit transports $transports", + "falls back to config when backend has no (valid) livekit transports $transports", async ({ transports }) => { const client = makeClient(); client._unstable_getRTCTransports.mockResolvedValue(transports); - const wellKnownFetcher = vi - .fn<(domain: string) => Promise>() - .mockResolvedValue(makeWellKnown([wellKnownTransport])); - const discovery = new RtcTransportAutoDiscovery({ client, - resolvedConfig: makeResolvedConfig("https://config.example.org"), - wellKnownFetcher, + resolvedConfig: makeResolvedConfig(configTransport.livekit_service_url), logger: rootLogger, }); - await expect( - discovery.discoverPreferredTransport(), - ).resolves.toStrictEqual(wellKnownTransport); + const discoveredTransport = await discovery.discoverPreferredTransport(); + expect(discoveredTransport).not.toStrictEqual(backendTransport); + expect(discoveredTransport).toStrictEqual(configTransport); - expect(wellKnownFetcher).toHaveBeenCalledWith("example.org"); }, ); - it("skips backend discovery in widget mode and uses well-known", async () => { - const client = makeClient(); - // widget mode is detected by the absence of an access token - client.getAccessToken.mockReturnValue(null); - - const wellKnownFetcher = vi - .fn<(domain: string) => Promise>() - .mockResolvedValue(makeWellKnown([wellKnownTransport])); - - const discovery = new RtcTransportAutoDiscovery({ - client, - resolvedConfig: makeResolvedConfig("https://config.example.org"), - wellKnownFetcher, - logger: rootLogger, - }); - - await expect(discovery.discoverPreferredTransport()).resolves.toStrictEqual( - wellKnownTransport, - ); - - expect(client._unstable_getRTCTransports).not.toHaveBeenCalled(); - expect(wellKnownFetcher).toHaveBeenCalledWith("example.org"); - }); - - it("falls back to app config when backend fails and well-known has no rtc_foci", async () => { - const client = makeClient(); - client._unstable_getRTCTransports.mockRejectedValue( - new MatrixError({ errcode: "M_UNKNOWN" }, 404), - ); - - const wellKnownFetcher = vi - .fn<(domain: string) => Promise>() - .mockResolvedValue({} as IClientWellKnown); - - const discovery = new RtcTransportAutoDiscovery({ - client, - resolvedConfig: makeResolvedConfig("https://config.example.org"), - wellKnownFetcher, - logger: rootLogger, - }); - - await expect(discovery.discoverPreferredTransport()).resolves.toStrictEqual( - { - type: "livekit", - livekit_service_url: "https://config.example.org", - }, - ); - }); - - it("returns null when backend, well-known and config are all unavailable", async () => { + it("returns null when backend and config are all unavailable", async () => { const client = makeClient(); client._unstable_getRTCTransports.mockResolvedValue([]); - const wellKnownFetcher = vi - .fn<(domain: string) => Promise>() - .mockResolvedValue({} as IClientWellKnown); const discovery = new RtcTransportAutoDiscovery({ client, resolvedConfig: makeResolvedConfig(undefined), - wellKnownFetcher, logger: rootLogger, }); diff --git a/src/state/CallViewModel/localMember/RtcTransportAutoDiscovery.ts b/src/state/CallViewModel/localMember/RtcTransportAutoDiscovery.ts index b32b7b613..11adbac20 100644 --- a/src/state/CallViewModel/localMember/RtcTransportAutoDiscovery.ts +++ b/src/state/CallViewModel/localMember/RtcTransportAutoDiscovery.ts @@ -8,7 +8,7 @@ import { isLivekitTransportConfig, type LivekitTransportConfig, } from "matrix-js-sdk/lib/matrixrtc"; -import { type IClientWellKnown, type MatrixClient } from "matrix-js-sdk"; +import { type MatrixClient } from "matrix-js-sdk"; import { type Logger } from "matrix-js-sdk/lib/logger"; import type { ResolvedConfigOptions } from "../../../config/ConfigOptions.ts"; @@ -22,27 +22,21 @@ type TransportDiscoveryClient = Pick< export interface RtcTransportAutoDiscoveryProps { client: TransportDiscoveryClient; resolvedConfig: ResolvedConfigOptions; - wellKnownFetcher: (domain: string) => Promise; logger: Logger; } export class RtcTransportAutoDiscovery { private readonly client: TransportDiscoveryClient; private readonly resolvedConfig: ResolvedConfigOptions; - private readonly wellKnownFetcher: ( - domain: string, - ) => Promise; private readonly logger: Logger; public constructor({ client, resolvedConfig, - wellKnownFetcher, logger, }: RtcTransportAutoDiscoveryProps) { this.client = client; this.resolvedConfig = resolvedConfig; - this.wellKnownFetcher = wellKnownFetcher; this.logger = logger.getChild("[RtcTransportAutoDiscovery]"); } @@ -56,21 +50,7 @@ export class RtcTransportAutoDiscovery { return backendTransport; } - this.logger.info("No backend transport found, falling back to well-known"); - // 2) .well-known transports - const wellKnownTransport = await this.tryWellKnownTransports(); - if (wellKnownTransport) { - this.logger.info( - `Found .well-known transport: ${wellKnownTransport.livekit_service_url}`, - ); - return wellKnownTransport; - } - - this.logger.info( - "No .well-known transport found, falling back to app config", - ); - - // 3) app config URL + // 2) app config URL const configTransport = this.tryConfigTransport(); if (configTransport) { this.logger.info( @@ -110,44 +90,6 @@ export class RtcTransportAutoDiscovery { return null; } - /** - * Fetches the first rtc_foci from the .well-known/matrix/client. - * This will not throw errors, but instead just log them and return null if the expected config is not found or malformed. - * @private - */ - private async tryWellKnownTransports(): Promise { - // Legacy MSC4143 (to be removed) WELL_KNOWN: Prioritize the .well-known/matrix/client, if available. - const client = this.client; - const domain = client.getDomain(); - if (domain) { - // we use AutoDiscovery instead of relying on the MatrixClient having already - // been fully configured and started - - const wellKnownFoci = await this.wellKnownFetcher(domain); - - const fociConfig = wellKnownFoci["org.matrix.msc4143.rtc_foci"]; - if (fociConfig) { - if (!Array.isArray(fociConfig)) { - this.logger.warn( - `org.matrix.msc4143.rtc_foci is not an array in .well-known`, - ); - } else { - return fociConfig[0]; - } - } else { - this.logger.info( - `No .well-known "org.matrix.msc4143.rtc_foci" found for ${domain}`, - wellKnownFoci, - ); - } - } else { - // Should never happen, but just in case - this.logger.warn(`No domain configured for client`); - } - - return null; - } - private tryConfigTransport(): LivekitTransportConfig | null { const url = this.resolvedConfig.livekit?.livekit_service_url; if (url) { From 7d6a0da6a9b4a010b6d6f199df7e7a2b39bd4309 Mon Sep 17 00:00:00 2001 From: Robin Date: Mon, 10 Aug 2026 14:33:14 +0200 Subject: [PATCH 2/5] Remove outdated tests --- .../localMember/LocalTransport.test.ts | 45 ------------------- .../localMember/LocalTransport.ts | 2 - 2 files changed, 47 deletions(-) diff --git a/src/state/CallViewModel/localMember/LocalTransport.test.ts b/src/state/CallViewModel/localMember/LocalTransport.test.ts index ac45af2a1..31b0389ab 100644 --- a/src/state/CallViewModel/localMember/LocalTransport.test.ts +++ b/src/state/CallViewModel/localMember/LocalTransport.test.ts @@ -433,51 +433,6 @@ describe("LocalTransport", () => { ).rejects.toThrow(expect.any(FailToGetOpenIdToken)); }); - it("supports getting transport via well-known", async () => { - localTransportOpts.client.getDomain.mockReturnValue("example.org"); - fetchMock.getOnce("https://example.org/.well-known/matrix/client", { - "org.matrix.msc4143.rtc_foci": [ - { type: "livekit", livekit_service_url: "https://lk.example.org" }, - ], - }); - const { advertised$, active$ } = - createLocalTransport$(localTransportOpts); - openIdResolver.resolve?.(openIdResponse); - expect(advertised$.value).toBe(null); - expect(active$.value).toBe(null); - await flushPromises(); - const expectedTransport = { - livekit_service_url: "https://lk.example.org", - type: "livekit", - }; - expect(advertised$.value).toStrictEqual(expectedTransport); - expect(active$.value).toStrictEqual({ - transport: expectedTransport, - sfuConfig: { - jwt: "e30=.eyJzdWIiOiJAbWU6ZXhhbXBsZS5vcmc6QUJDREVGIiwidmlkZW8iOnsicm9vbSI6IiFleGFtcGxlX3Jvb21faWQifX0=.e30=", - livekitAlias: "Akph4alDMhen", - livekitIdentity: "@lk_user:ABCDEF", - url: "https://lk.example.org", - }, - }); - expect(fetchMock.done()).toEqual(true); - }); - - it("fails fast if the openId request fails for the well-known config", async () => { - localTransportOpts.client.getDomain.mockReturnValue("example.org"); - fetchMock.getOnce("https://example.org/.well-known/matrix/client", { - "org.matrix.msc4143.rtc_foci": [ - { type: "livekit", livekit_service_url: "https://lk.example.org" }, - ], - }); - openIdResolver.reject( - new FailToGetOpenIdToken(new Error("Test driven error")), - ); - await expect(async () => - lastValueFrom(createLocalTransport$(localTransportOpts).active$), - ).rejects.toThrow(expect.any(FailToGetOpenIdToken)); - }); - it("throws if no options are available", async () => { const { advertised$, active$ } = createLocalTransport$({ scope: testScope(), diff --git a/src/state/CallViewModel/localMember/LocalTransport.ts b/src/state/CallViewModel/localMember/LocalTransport.ts index e255ca946..62db5a8e1 100644 --- a/src/state/CallViewModel/localMember/LocalTransport.ts +++ b/src/state/CallViewModel/localMember/LocalTransport.ts @@ -26,7 +26,6 @@ import { tap, } from "rxjs"; import { logger as rootLogger, type Logger } from "matrix-js-sdk/lib/logger"; -import { AutoDiscovery } from "matrix-js-sdk/lib/autodiscovery"; import { type CallMembershipIdentityParts } from "matrix-js-sdk/lib/matrixrtc/EncryptionManager"; import { type Behavior } from "../../Behavior.ts"; @@ -150,7 +149,6 @@ export const createLocalTransport$ = ({ const transportDiscovery = new RtcTransportAutoDiscovery({ client: client, resolvedConfig: Config.get(), - wellKnownFetcher: AutoDiscovery.getRawClientConfig.bind(AutoDiscovery), logger: logger, }); From 426ea30fe1d5f627c5b337c8dfb8f103b052ea73 Mon Sep 17 00:00:00 2001 From: Robin Date: Mon, 10 Aug 2026 15:10:49 +0200 Subject: [PATCH 3/5] Remove all references to .well-known transport advertisement --- README.md | 40 +++++----- backend/dev_homeserver-othersite.yaml | 1 - backend/dev_homeserver.yaml | 1 - backend/dev_nginx.conf | 28 +------ backend/playwright_homeserver-othersite.yaml | 1 - backend/playwright_homeserver.yaml | 1 - docs/self_hosting.md | 65 ++++------------- locales/en/app.json | 2 +- src/config/ConfigOptions.ts | 5 +- .../DeveloperSettingsTab.test.tsx.snap | 2 +- .../localMember/LocalMember.test.ts | 73 +------------------ .../CallViewModel/localMember/LocalMember.ts | 1 - .../localMember/LocalTransport.test.ts | 43 +++++------ .../localMember/LocalTransport.ts | 6 +- .../RtcTransportAutoDiscovery.test.ts | 1 - .../localMember/RtcTransportAutoDiscovery.ts | 2 +- src/utils/errors.ts | 4 +- src/widget.ts | 2 +- 18 files changed, 68 insertions(+), 210 deletions(-) diff --git a/README.md b/README.md index 546e491a1..ecbabcf2c 100644 --- a/README.md +++ b/README.md @@ -115,30 +115,33 @@ For more details on the packages, see the For operating and deploying Element Call on your own server, refer to the [**Self-Hosting Guide**](./docs/self_hosting.md). -## 🧭 MatrixRTC Backend Discovery and Selection +## MatrixRTC Transports -For proper Element Call operation each site deployment needs a MatrixRTC backend -setup as outlined in the [Self-Hosting Guide](./docs/self_hosting.md). A typical -federated site deployment for three different sites A, B and C is depicted below. +For proper operation of Element Call, each deployment needs to set up a +MatrixRTC transport in the form of a LiveKit server as outlined in the +[Self-Hosting Guide](./docs/self_hosting.md). A typical federated site +deployment for three different sites A, B and C is depicted below.

Element Call federated setup

-### Backend Discovery +### Transport Discovery -The MatrixRTC backend (according to -[MSC4143](https://github.com/matrix-org/matrix-spec-proposals/pull/4143)) is -announced by the Matrix site's `.well-known/matrix/client` file and discovered -via the `org.matrix.msc4143.rtc_foci` key, e.g.: +Element Call discovers the available MatrixRTC transports (as defined by +[MSC4519](https://github.com/matrix-org/matrix-spec-proposals/pull/4519)) by +hitting the `GET /_matrix/client/unstable/org.matrix.msc4143/rtc/transports` +endpoint of the Client-Server API. An example response: ```json -"org.matrix.msc4143.rtc_foci": [ +{ + "rtc_transports": [ { - "type": "livekit", - "livekit_service_url": "https://matrix-rtc.example.com/livekit/jwt" - }, -] + "type": "livekit", + "livekit_service_url": "https://matrix-rtc.example.com/livekit/jwt" + } + ] +} ``` where the format for MatrixRTC using LiveKit backend is defined in @@ -149,7 +152,7 @@ via `livekit_service_url`. ### Backend Selection -- Each call participant proposes their discovered MatrixRTC backend from +- Each call participant proposes their discovered MatrixRTC transport from `org.matrix.msc4143.rtc_foci` in their `org.matrix.msc3401.call.member` state event. - For the **LiveKit** MatrixRTC backend ([MSC4195](https://github.com/hughns/matrix-spec-proposals/blob/hughns/matrixrtc-livekit/proposals/4195-matrixrtc-livekit.md)), @@ -244,10 +247,9 @@ pnpm backend > [!NOTE] > To ensure your local development frontend functions properly, you’ll need to -> add certificate exceptions in your browser for `https://localhost:3000`, -> `https://matrix-rtc.m.localhost/livekit/jwt/healthz` and -> `https://synapse.m.localhost/.well-known/matrix/client`. This can be either -> done by adding the minimum localhost CA +> add certificate exceptions in your browser for `https://localhost:3000` and +> `https://matrix-rtc.m.localhost/livekit/jwt/healthz`. This can be done either +> by adding the minimum localhost CA > ([./backend/dev_tls_local-ca.crt](./backend/dev_tls_local-ca.crt)) to your web > browser's trusted certificates or by simply copying and pasting each URL into > your browser’s address bar and follow the prompts to add the exception. diff --git a/backend/dev_homeserver-othersite.yaml b/backend/dev_homeserver-othersite.yaml index 7eb8f294a..8b7bc2272 100644 --- a/backend/dev_homeserver-othersite.yaml +++ b/backend/dev_homeserver-othersite.yaml @@ -54,7 +54,6 @@ enable_registration_without_verification: true registration_shared_secret: "test_shared_secret_for_local_dev_only" report_stats: false -serve_server_wellknown: true # Ratelimiting settings for client actions (registration, login, messaging). # diff --git a/backend/dev_homeserver.yaml b/backend/dev_homeserver.yaml index 0aea2ece2..2204c3cdb 100644 --- a/backend/dev_homeserver.yaml +++ b/backend/dev_homeserver.yaml @@ -54,7 +54,6 @@ enable_registration_without_verification: true registration_shared_secret: "test_shared_secret_for_local_dev_only" report_stats: false -serve_server_wellknown: true # Ratelimiting settings for client actions (registration, login, messaging). # diff --git a/backend/dev_nginx.conf b/backend/dev_nginx.conf index 6ec0d7010..c227370df 100644 --- a/backend/dev_nginx.conf +++ b/backend/dev_nginx.conf @@ -1,4 +1,4 @@ -# Synapse reverse proxy including .well-known/matrix/client +# Synapse reverse proxy # domain synapse.m.localhost server { listen 80; @@ -11,18 +11,6 @@ server { ssl_certificate /root/ssl/cert.pem; ssl_certificate_key /root/ssl/key.pem; - # well-known config adding rtc_foci backend - # Note well-known is currently not effective due to: - # https://spec.matrix.org/v1.12/client-server-api/#well-known-uri the spec - # says it must be at https://$server_name/... (implied port 443) Hence, we - # currently rely for local development environment on deprecated config.json - # setting for livekit_service_url - location /.well-known/matrix/client { - add_header Access-Control-Allow-Origin *; - return 200 '{"m.homeserver": {"base_url": "https://synapse.m.localhost"}, "org.matrix.msc4143.rtc_foci": [{"type": "livekit", "livekit_service_url": "https://matrix-rtc.m.localhost/livekit/jwt"}]}'; - default_type application/json; - } - # Reverse proxy for Matrix Synapse Homeserver # This is also required for development environment. # Reason: the lk-jwt-service uses the federation API for the openid token @@ -44,7 +32,7 @@ server { } -# Synapse reverse proxy including .well-known/matrix/client +# Synapse reverse proxy # domain synapse.othersite.m.localhost server { listen 80; @@ -57,18 +45,6 @@ server { ssl_certificate /root/ssl/cert.pem; ssl_certificate_key /root/ssl/key.pem; - # well-known config adding rtc_foci backend - # Note well-known is currently not effective due to: - # https://spec.matrix.org/v1.12/client-server-api/#well-known-uri the spec - # says it must be at https://$server_name/... (implied port 443) Hence, we - # currently rely for local development environment on deprecated config.json - # setting for livekit_service_url - location /.well-known/matrix/client { - add_header Access-Control-Allow-Origin *; - return 200 '{"m.homeserver": {"base_url": "https://synapse.othersite.m.localhost"}, "org.matrix.msc4143.rtc_foci": [{"type": "livekit", "livekit_service_url": "https://matrix-rtc.othersite.m.localhost/livekit/jwt"}]}'; - default_type application/json; - } - # Reverse proxy for Matrix Synapse Homeserver # This is also required for development environment. # Reason: the lk-jwt-service uses the federation API for the openid token diff --git a/backend/playwright_homeserver-othersite.yaml b/backend/playwright_homeserver-othersite.yaml index 86c77b35f..83fdbc2e5 100644 --- a/backend/playwright_homeserver-othersite.yaml +++ b/backend/playwright_homeserver-othersite.yaml @@ -54,7 +54,6 @@ enable_registration_without_verification: true registration_shared_secret: "test_shared_secret_for_local_dev_only" report_stats: false -serve_server_wellknown: true # Ratelimiting settings for client actions (registration, login, messaging). # diff --git a/backend/playwright_homeserver.yaml b/backend/playwright_homeserver.yaml index 8f4375241..c5db1f02d 100644 --- a/backend/playwright_homeserver.yaml +++ b/backend/playwright_homeserver.yaml @@ -54,7 +54,6 @@ enable_registration_without_verification: true registration_shared_secret: "test_shared_secret_for_local_dev_only" report_stats: false -serve_server_wellknown: true # Ratelimiting settings for client actions (registration, login, messaging). # diff --git a/docs/self_hosting.md b/docs/self_hosting.md index 01113fcec..0bdfe6284 100644 --- a/docs/self_hosting.md +++ b/docs/self_hosting.md @@ -68,10 +68,10 @@ As a prerequisite for the make sure that your Synapse server has either a `federation` or `openid` [listener configured](https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html#listeners). -### MatrixRTC Backend +### LiveKit backend -In order to **guarantee smooth operation** of Element Call, a MatrixRTC backend is -required for each site deployment. +In order to **guarantee smooth operation** of Element Call, a dedicated LiveKit +backend is required for each site deployment. ![MSC4195 compatible setup](MSC4195_setup.drawio.png) @@ -165,7 +165,7 @@ Using Haproxy, you can achieve this by: use_backend mxrtc_auth_backend if is_mxrtc_auth matrixrtc_domain # Backend -## MatrixRTC backend +## LiveKit backend backend sfu_backend server livekit 127.0.0.1:7880 http-request set-path %[path,regsub(^/livekit/sfu/,/)] @@ -187,57 +187,22 @@ backend mxrtc_auth_backend ``` -#### MatrixRTC backend announcement +#### MatrixRTC transport announcement -> [!IMPORTANT] -> As defined in -> [MSC4143](https://github.com/matrix-org/matrix-spec-proposals/pull/4143), -> the MatrixRTC backend(s) must be announced to the client via `/_matrix/client/unstable/org.matrix.msc4143/rtc/transports`. - -Enable the unstable feature flag `msc4143_enabled`, and update the synapse config file: +Enable the unstable feature flag `msc4143_enabled`, and update the +[`matrix_rtc` section](https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html#matrix_rtc) +of your Synapse config file: ```yaml - matrix_rtc: - - transports: - - type: livekit - livekit_service_url: https://matrix-rtc.example.com/livekit/jwt + transports: + - type: livekit + livekit_service_url: https://matrix-rtc.example.com/livekit/jwt ``` - - -**⚠️ Well-known discovery will soon be deprecated, but needed if MSC4143 is not supported on your Homeserver** - -your **Matrix site's .well-known/matrix/client`** file (e.g. `example.com/.well-known/matrix/client` matching the site deployment example -from above). The configuration is a list of Foci configs: - -```json -"org.matrix.msc4143.rtc_foci": [ - { - "type": "livekit", - "livekit_service_url": "https://matrix-rtc.example.com/livekit/jwt" - }, - { - "type": "livekit", - "livekit_service_url": "https://matrix-rtc-2.example.com/livekit/jwt" - } -] -``` - -Make sure this file is served with the correct MIME type (`application/json`). -Additionally, ensure the appropriate CORS headers are set to allow web clients -to access it across origins. For more details, refer to the -[Matrix Client-Server API: 2. Web Browser Clients](https://spec.matrix.org/latest/client-server-api/#web-browser-clients). - -``` -Access-Control-Allow-Origin: * -Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS -Access-Control-Allow-Headers: X-Requested-With, Content-Type, Authorization -``` - -> [!NOTE] -> Most `org.matrix.msc4143.rtc_foci` configurations will only have one entry in -> the array. +The transport you specify will be made available to clients over the +`/_matrix/client/unstable/org.matrix.msc4143/rtc/transports` endpoint as defined +in [MSC4143](https://github.com/matrix-org/matrix-spec-proposals/pull/4143). ## Building Element Call @@ -292,7 +257,7 @@ runtime. Documentation and default values for `public/config.json` can be found in [ConfigOptions.ts](../src/config/ConfigOptions.ts). > [!CAUTION] -> Please note configuring MatrixRTC backend via `config.json` of +> Please note configuring LiveKit backend via `config.json` of > Element Call is only available for developing and debug purposes. Relying on > it might break Element Call going forward! diff --git a/locales/en/app.json b/locales/en/app.json index 3ff956a6a..87fdebe1a 100644 --- a/locales/en/app.json +++ b/locales/en/app.json @@ -61,7 +61,7 @@ "crypto_version": "Crypto version: {{version}}", "custom_livekit_url": { "current_url": "Currently set to: ", - "from_config": "Currently, no overwrite is set. Url from well-known or config is used.", + "from_config": "Currently, no overwrite is set. Url from config is used.", "label": "Custom Livekit-url", "reset": "Reset overwrite", "save": "Save", diff --git a/src/config/ConfigOptions.ts b/src/config/ConfigOptions.ts index ff0aadc37..e283e28fb 100644 --- a/src/config/ConfigOptions.ts +++ b/src/config/ConfigOptions.ts @@ -74,10 +74,7 @@ export interface ConfigOptions { livekit?: { // The link to the service that returns a livekit url and token to use it. // This is a fallback link in case the homeserver in use does not advertise - // a livekit service url in the client well-known. - // The well known needs to be formatted like so: - // {"type":"livekit", "livekit_service_url":"https://livekit.example.com"} - // and stored under the key: "org.matrix.msc4143.rtc_foci" + // a livekit service url over the transports endpoint. livekit_service_url: string; }; diff --git a/src/settings/__snapshots__/DeveloperSettingsTab.test.tsx.snap b/src/settings/__snapshots__/DeveloperSettingsTab.test.tsx.snap index 73ae04ca5..1e9811bac 100644 --- a/src/settings/__snapshots__/DeveloperSettingsTab.test.tsx.snap +++ b/src/settings/__snapshots__/DeveloperSettingsTab.test.tsx.snap @@ -251,7 +251,7 @@ exports[`DeveloperSettingsTab > renders and matches snapshot 1`] = ` class="_message_1o4d9_86 _help-message_1o4d9_92" id="radix-_r_8_" > - Currently, no overwrite is set. Url from well-known or config is used. + Currently, no overwrite is set. Url from config is used. diff --git a/src/state/CallViewModel/localMember/LocalMember.test.ts b/src/state/CallViewModel/localMember/LocalMember.test.ts index 8bca91824..16ffe1493 100644 --- a/src/state/CallViewModel/localMember/LocalMember.test.ts +++ b/src/state/CallViewModel/localMember/LocalMember.test.ts @@ -20,7 +20,6 @@ import { afterAll, beforeEach, } from "vitest"; -import { AutoDiscovery } from "matrix-js-sdk/lib/autodiscovery"; import { BehaviorSubject, map, of } from "rxjs"; import { logger } from "matrix-js-sdk/lib/logger"; import { type LocalParticipant, type LocalTrack } from "livekit-client"; @@ -78,34 +77,10 @@ describe("LocalMembership", () => { livekit_alias: "my-oldest-member-service-alias", }; - const focusConfigFromWellKnown = { - type: "livekit", - livekit_service_url: "http://my-well-known-service-url.com", - }; - const focusConfigFromWellKnown2 = { - type: "livekit", - livekit_service_url: "http://my-well-known-service-url2.com", - }; - const clientWellKnown = { - "org.matrix.msc4143.rtc_foci": [ - focusConfigFromWellKnown, - focusConfigFromWellKnown2, - ], - }; - mockConfig({ livekit: { livekit_service_url: "http://my-default-service-url.com" }, }); - vi.spyOn(AutoDiscovery, "getRawClientConfig").mockImplementation( - async (domain) => { - if (domain === "example.org") { - return Promise.resolve(clientWellKnown); - } - return Promise.resolve({}); - }, - ); - const mockedSession = vi.mocked({ room: { roomId: "roomId", @@ -132,7 +107,7 @@ describe("LocalMembership", () => { ownMemberMock, { livekit_alias: "roomId", - livekit_service_url: "http://my-well-known-service-url.com", + livekit_service_url: "http://my-livekit-service-url.com", type: "livekit", }, { @@ -150,7 +125,7 @@ describe("LocalMembership", () => { [ { livekit_alias: "roomId", - livekit_service_url: "http://my-well-known-service-url.com", + livekit_service_url: "http://my-livekit-service-url.com", type: "livekit", }, ], @@ -161,50 +136,6 @@ describe("LocalMembership", () => { }), ); }); - - it("It should not fail with configuration error if homeserver config has livekit url but not fallback", () => { - mockConfig({}); - vi.spyOn(AutoDiscovery, "getRawClientConfig").mockResolvedValue({ - "org.matrix.msc4143.rtc_foci": [ - { - type: "livekit", - livekit_service_url: "http://my-well-known-service-url.com", - }, - ], - }); - - const mockedSession = vi.mocked({ - room: { - roomId: "roomId", - client: { - getDomain: vi.fn().mockReturnValue("example.org"), - getOpenIdToken: vi.fn().mockResolvedValue({ - access_token: "ACCCESS_TOKEN", - token_type: "Bearer", - matrix_server_name: "localhost", - expires_in: 10000, - }), - }, - }, - memberships: [], - getFocusInUse: vi.fn(), - joinRTCSession: vi.fn(), - }) as unknown as MatrixRTCSession; - - enterRTCSession( - mockedSession, - ownMemberMock, - { - livekit_alias: "roomId", - livekit_service_url: "http://my-well-known-service-url.com", - type: "livekit", - }, - { - encryptMedia: true, - matrixRTCMode: MATRIX_RTC_MODE, - }, - ); - }); }); const defaultCreateLocalMemberValues = { diff --git a/src/state/CallViewModel/localMember/LocalMember.ts b/src/state/CallViewModel/localMember/LocalMember.ts index e41901b1f..1088301f3 100644 --- a/src/state/CallViewModel/localMember/LocalMember.ts +++ b/src/state/CallViewModel/localMember/LocalMember.ts @@ -108,7 +108,6 @@ export type LocalMemberState = }; /* - * - get well known * - get oldest membership * - get transport to use * - get openId + jwt token diff --git a/src/state/CallViewModel/localMember/LocalTransport.test.ts b/src/state/CallViewModel/localMember/LocalTransport.test.ts index 31b0389ab..89cb831da 100644 --- a/src/state/CallViewModel/localMember/LocalTransport.test.ts +++ b/src/state/CallViewModel/localMember/LocalTransport.test.ts @@ -63,8 +63,7 @@ describe("LocalTransport", () => { client: { // eslint-disable-next-line @typescript-eslint/naming-convention _unstable_getRTCTransports: async () => Promise.resolve([]), - getAccessToken: vi.fn().mockReturnValue("access_token"), - getDomain: () => "", + getDomain: () => "example.org", baseUrl: "example.org", // These won't be called in this error path but satisfy the type getOpenIdToken: vi.fn(), @@ -77,9 +76,11 @@ describe("LocalTransport", () => { await flushPromises(); expect(() => advertised$.value).toThrow( - new MatrixRTCTransportMissingError(""), + new MatrixRTCTransportMissingError("example.org"), + ); + expect(() => active$.value).toThrow( + new MatrixRTCTransportMissingError("example.org"), ); - expect(() => active$.value).toThrow(new MatrixRTCTransportMissingError("")); }); it("throws FailToGetOpenIdToken when OpenID fetch fails", async () => { @@ -103,10 +104,8 @@ describe("LocalTransport", () => { useOldestMember: false, memberships$: constant(new Epoch([])), client: { - baseUrl: "https://lk.example.org", - // Use empty domain to skip .well-known and use config directly - getDomain: () => "", - getAccessToken: vi.fn().mockReturnValue("access_token"), + baseUrl: "https://example.org", + getDomain: () => "example.org", // eslint-disable-next-line @typescript-eslint/naming-convention _unstable_getRTCTransports: async () => Promise.resolve([]), getOpenIdToken: vi.fn(), @@ -150,11 +149,10 @@ describe("LocalTransport", () => { client: { // eslint-disable-next-line @typescript-eslint/naming-convention _unstable_getRTCTransports: async () => Promise.resolve([]), - getDomain: () => "", + getDomain: () => "example.org", getOpenIdToken: vi.fn(), getDeviceId: vi.fn(), - baseUrl: "https://lk.example.org", - getAccessToken: vi.fn().mockReturnValue("access_token"), + baseUrl: "https://example.org", }, ownMembershipIdentity: ownMemberMock, forceJwtEndpoint: JwtEndpointVersion.Legacy, @@ -221,13 +219,12 @@ describe("LocalTransport", () => { useOldestMember: true, memberships$: scope.behavior(memberships$.pipe(trackEpoch())), client: { - getDomain: () => "", + getDomain: () => "example.org", // eslint-disable-next-line @typescript-eslint/naming-convention _unstable_getRTCTransports: async () => Promise.resolve([]), - getAccessToken: vi.fn().mockReturnValue("access_token"), getOpenIdToken: vi.fn(), getDeviceId: vi.fn(), - baseUrl: "https://lk.example.org", + baseUrl: "https://example.org", }, ownMembershipIdentity: ownMemberMock, forceJwtEndpoint: JwtEndpointVersion.Legacy, @@ -278,14 +275,13 @@ describe("LocalTransport", () => { useOldestMember: true, memberships$: scope.behavior(memberships$.pipe(trackEpoch())), client: { - getDomain: () => "", + getDomain: () => "example.org", // eslint-disable-next-line @typescript-eslint/naming-convention _unstable_getRTCTransports: async () => Promise.resolve([aliceTransport]), - getAccessToken: vi.fn().mockReturnValue("access_token"), getOpenIdToken: vi.fn(), getDeviceId: vi.fn(), - baseUrl: "https://lk.example.org", + baseUrl: "https://example.org", }, ownMembershipIdentity: ownMemberMock, forceJwtEndpoint: JwtEndpointVersion.Legacy, @@ -330,10 +326,9 @@ describe("LocalTransport", () => { memberships$: constant(new Epoch([])), client: { baseUrl: "https://example.org", - getDomain: vi.fn().mockReturnValue(""), + getDomain: vi.fn().mockReturnValue("example.org"), // eslint-disable-next-line @typescript-eslint/naming-convention _unstable_getRTCTransports: vi.fn().mockResolvedValue([]), - getAccessToken: vi.fn().mockReturnValue("access_token"), getOpenIdToken: vi.fn(), getDeviceId: vi.fn(), }, @@ -443,11 +438,10 @@ describe("LocalTransport", () => { delayId$: constant(null), memberships$: constant(new Epoch([])), client: { - getDomain: () => "", + getDomain: () => "example.org", baseUrl: "https://example.org", // eslint-disable-next-line @typescript-eslint/naming-convention _unstable_getRTCTransports: async () => Promise.resolve([]), - getAccessToken: vi.fn().mockReturnValue("access_token"), // These won't be called in this error path but satisfy the type getOpenIdToken: vi.fn(), getDeviceId: vi.fn(), @@ -456,10 +450,10 @@ describe("LocalTransport", () => { await flushPromises(); expect(() => advertised$.value).toThrow( - new MatrixRTCTransportMissingError(""), + new MatrixRTCTransportMissingError("example.org"), ); expect(() => active$.value).toThrow( - new MatrixRTCTransportMissingError(""), + new MatrixRTCTransportMissingError("example.org"), ); }); }); @@ -484,11 +478,10 @@ describe("LocalTransport", () => { delayId$: delayId$, memberships$: constant(new Epoch([])), client: { - getDomain: () => "", + getDomain: () => "example.org", baseUrl: "https://example.org", // eslint-disable-next-line @typescript-eslint/naming-convention _unstable_getRTCTransports: async () => Promise.resolve([]), - getAccessToken: vi.fn().mockReturnValue("access_token"), // These won't be called in this error path but satisfy the type getOpenIdToken: vi.fn(), getDeviceId: vi.fn(), diff --git a/src/state/CallViewModel/localMember/LocalTransport.ts b/src/state/CallViewModel/localMember/LocalTransport.ts index 62db5a8e1..1a6dddc1f 100644 --- a/src/state/CallViewModel/localMember/LocalTransport.ts +++ b/src/state/CallViewModel/localMember/LocalTransport.ts @@ -56,7 +56,7 @@ interface Props { memberships$: Behavior>; client: Pick< MatrixClient, - "getDomain" | "baseUrl" | "_unstable_getRTCTransports" | "getAccessToken" + "getDomain" | "baseUrl" | "_unstable_getRTCTransports" > & OpenIDClientParts; // Used by the jwt service to create the livekit room and compute the livekit alias. @@ -307,7 +307,7 @@ async function doOpenIdAndJWTFromUrl( roomId: string, client: Pick< MatrixClient, - "getDomain" | "baseUrl" | "_unstable_getRTCTransports" | "getAccessToken" + "getDomain" | "baseUrl" | "_unstable_getRTCTransports" > & OpenIDClientParts, delayId?: string, @@ -337,7 +337,7 @@ function observeLocalTransportForOldestMembership( preferredTransport$: Observable, client: Pick< MatrixClient, - "getDomain" | "baseUrl" | "_unstable_getRTCTransports" | "getAccessToken" + "getDomain" | "baseUrl" | "_unstable_getRTCTransports" > & OpenIDClientParts, ownMembershipIdentity: CallMembershipIdentityParts, diff --git a/src/state/CallViewModel/localMember/RtcTransportAutoDiscovery.test.ts b/src/state/CallViewModel/localMember/RtcTransportAutoDiscovery.test.ts index c16219abf..748a16f37 100644 --- a/src/state/CallViewModel/localMember/RtcTransportAutoDiscovery.test.ts +++ b/src/state/CallViewModel/localMember/RtcTransportAutoDiscovery.test.ts @@ -71,7 +71,6 @@ describe("RtcTransportAutoDiscovery", () => { it.each(VALID_TEST_CASES)( "prefers backend transport other app config $transports", async ({ transports }) => { - // it("prefers backend transport over well-known and app config", async () => { const client = makeClient(); client._unstable_getRTCTransports.mockResolvedValue(transports); diff --git a/src/state/CallViewModel/localMember/RtcTransportAutoDiscovery.ts b/src/state/CallViewModel/localMember/RtcTransportAutoDiscovery.ts index d42e4daa4..1f295649f 100644 --- a/src/state/CallViewModel/localMember/RtcTransportAutoDiscovery.ts +++ b/src/state/CallViewModel/localMember/RtcTransportAutoDiscovery.ts @@ -16,7 +16,7 @@ import { doNetworkOperationWithRetry } from "../../../utils/matrix.ts"; type TransportDiscoveryClient = Pick< MatrixClient, - "getDomain" | "_unstable_getRTCTransports" | "getAccessToken" + "getDomain" | "_unstable_getRTCTransports" >; export interface RtcTransportAutoDiscoveryProps { diff --git a/src/utils/errors.ts b/src/utils/errors.ts index 7112702d1..0ac569278 100644 --- a/src/utils/errors.ts +++ b/src/utils/errors.ts @@ -12,7 +12,7 @@ import { i18nKey } from "./i18n"; export enum ErrorCode { /** - * Configuration problem due to no MatrixRTC backend/SFU is exposed via .well-known and no fallback configured. + * Configuration problem due to no MatrixRTC transport provided by homeserver and no fallback configured. */ MISSING_MATRIX_RTC_TRANSPORT = "MISSING_MATRIX_RTC_TRANSPORT", CONNECTION_LOST_ERROR = "CONNECTION_LOST_ERROR", @@ -67,7 +67,7 @@ export class ElementCallError extends Error { } /** - * Configuration problem due to no MatrixRTC backend/SFU is exposed via .well-known and no fallback configured. + * Configuration problem due to no MatrixRTC transport provided by homeserver and no fallback configured. */ export class MatrixRTCTransportMissingError extends ElementCallError { public domain: string; diff --git a/src/widget.ts b/src/widget.ts index 462fc6e05..d4127a835 100644 --- a/src/widget.ts +++ b/src/widget.ts @@ -195,7 +195,7 @@ export const initializeWidget = ( // Wait for the config file to be ready (we load very early on so it might not // be otherwise) await Config.init(); - await client.startClient({ clientWellKnownPollPeriod: 60 * 10 }); + await client.startClient(); return client; }; From 7ca8059b0fd81f86f4db076d0ca95a3de38ade02 Mon Sep 17 00:00:00 2001 From: Robin Date: Mon, 10 Aug 2026 17:10:31 +0200 Subject: [PATCH 4/5] Remove unused access token mocks --- src/state/CallViewModel/CallViewModelTestUtils.ts | 3 --- .../localMember/RtcTransportAutoDiscovery.test.ts | 1 - 2 files changed, 4 deletions(-) diff --git a/src/state/CallViewModel/CallViewModelTestUtils.ts b/src/state/CallViewModel/CallViewModelTestUtils.ts index 1d3d0fef3..2e1525c06 100644 --- a/src/state/CallViewModel/CallViewModelTestUtils.ts +++ b/src/state/CallViewModel/CallViewModelTestUtils.ts @@ -138,9 +138,6 @@ export function withCallViewModel(mode: MatrixRTCMode) { public getSyncState(): SyncState { return syncState; } - public getAccessToken(): string | null { - return "a-token"; - } })() as Partial as MatrixClient, getMembers: () => roomMembers, getMembersWithMembership: () => roomMembers, diff --git a/src/state/CallViewModel/localMember/RtcTransportAutoDiscovery.test.ts b/src/state/CallViewModel/localMember/RtcTransportAutoDiscovery.test.ts index 748a16f37..f81223deb 100644 --- a/src/state/CallViewModel/localMember/RtcTransportAutoDiscovery.test.ts +++ b/src/state/CallViewModel/localMember/RtcTransportAutoDiscovery.test.ts @@ -43,7 +43,6 @@ function makeClient(): MockedObject { getDomain: vi.fn().mockReturnValue("example.org"), baseUrl: "https://matrix.example.org", _unstable_getRTCTransports: vi.fn().mockResolvedValue([]), - getAccessToken: vi.fn().mockReturnValue("access_token"), getOpenIdToken: vi.fn(), getDeviceId: vi.fn(), } as unknown as MockedObject; From 78e4881c37713d7f007fa301546dc8c4d1d1c68a Mon Sep 17 00:00:00 2001 From: Robin Date: Tue, 11 Aug 2026 18:03:28 +0200 Subject: [PATCH 5/5] Enable MatrixRTC transports endpoint in dev and testing configs --- backend/dev_homeserver-othersite.yaml | 7 +++++++ backend/dev_homeserver.yaml | 7 +++++++ backend/playwright_homeserver-othersite.yaml | 7 +++++++ backend/playwright_homeserver.yaml | 7 +++++++ 4 files changed, 28 insertions(+) diff --git a/backend/dev_homeserver-othersite.yaml b/backend/dev_homeserver-othersite.yaml index 8b7bc2272..3f4c18413 100644 --- a/backend/dev_homeserver-othersite.yaml +++ b/backend/dev_homeserver-othersite.yaml @@ -40,6 +40,8 @@ experimental_features: msc4222_enabled: true # sticky events for MatrixRTC user state msc4354_enabled: true + # MatrixRTC + msc4143_enabled: true # The maximum allowed duration by which sent events can be delayed, as # per MSC4140. Must be a positive value if set. Defaults to no @@ -66,3 +68,8 @@ rc_message: # Currently the heart-beat is every 5 seconds which translates into a rate of 0.2s per_second: 0.5 burst_count: 30 + +matrix_rtc: + transports: + - type: livekit + livekit_service_url: https://matrix-rtc.othersite.m.localhost/livekit/jwt diff --git a/backend/dev_homeserver.yaml b/backend/dev_homeserver.yaml index 2204c3cdb..e38e91e5f 100644 --- a/backend/dev_homeserver.yaml +++ b/backend/dev_homeserver.yaml @@ -40,6 +40,8 @@ experimental_features: msc4222_enabled: true # sticky events for MatrixRTC user state msc4354_enabled: true + # MatrixRTC + msc4143_enabled: true # The maximum allowed duration by which sent events can be delayed, as # per MSC4140. Must be a positive value if set. Defaults to no @@ -66,3 +68,8 @@ rc_message: # Currently the heart-beat is every 5 seconds which translates into a rate of 0.2s per_second: 0.5 burst_count: 30 + +matrix_rtc: + transports: + - type: livekit + livekit_service_url: https://matrix-rtc.m.localhost/livekit/jwt diff --git a/backend/playwright_homeserver-othersite.yaml b/backend/playwright_homeserver-othersite.yaml index 83fdbc2e5..5bce4c1d5 100644 --- a/backend/playwright_homeserver-othersite.yaml +++ b/backend/playwright_homeserver-othersite.yaml @@ -40,6 +40,8 @@ experimental_features: msc4222_enabled: true # sticky events for MatrixRTC user state msc4354_enabled: true + # MatrixRTC + msc4143_enabled: true # The maximum allowed duration by which sent events can be delayed, as # per MSC4140. Must be a positive value if set. Defaults to no @@ -83,3 +85,8 @@ rc_login: rc_registration: per_second: 10000 burst_count: 10000 + +matrix_rtc: + transports: + - type: livekit + livekit_service_url: https://matrix-rtc.othersite.m.localhost/livekit/jwt diff --git a/backend/playwright_homeserver.yaml b/backend/playwright_homeserver.yaml index c5db1f02d..d0439e42c 100644 --- a/backend/playwright_homeserver.yaml +++ b/backend/playwright_homeserver.yaml @@ -40,6 +40,8 @@ experimental_features: msc4222_enabled: true # sticky events for MatrixRTC user state msc4354_enabled: true + # MatrixRTC + msc4143_enabled: true # The maximum allowed duration by which sent events can be delayed, as # per MSC4140. Must be a positive value if set. Defaults to no @@ -83,3 +85,8 @@ rc_login: rc_registration: per_second: 10000 burst_count: 10000 + +matrix_rtc: + transports: + - type: livekit + livekit_service_url: https://matrix-rtc.m.localhost/livekit/jwt