fix(call): serve RTC transports to Element Call over MSC4515 — calls work again
CI / Build & Quality Checks (push) Successful in 2m6s
CI / Docker image build & smoke test (push) Skipped
CI / Secret scan (gitleaks) (push) Successful in 9s
CI / Trigger Desktop Build (push) Successful in 10s
CI / Playwright smoke (e2e) (push) Successful in 1m42s
CI / Build & Quality Checks (push) Successful in 2m6s
CI / Docker image build & smoke test (push) Skipped
CI / Secret scan (gitleaks) (push) Successful in 9s
CI / Trigger Desktop Build (push) Successful in 10s
CI / Playwright smoke (e2e) (push) Successful in 1m42s
Since the upstream v0.25.0 merge, Element Call in widget mode no longer reads .well-known for its LiveKit transport; it asks the HOST via the widget API (org.matrix.msc4515.get_rtc_transports, capability org.matrix.msc4515.rtc_transports). cinny never granted the capability nor implemented WidgetDriver.getRtcTransports(), so discovery returned nothing and every join failed with "Call is not supported" (MISSING_MATRIX_RTC_TRANSPORT) — the [LocalMembership] Multiple Transport Errors line in the browser console. - matrix-widget-api 1.17.0 -> 1.18.0 (adds MSC4515; also changes the sendDelayedEvent driver signature, adapted — parent delay ids were removed from the draft). - Grant MSC4515RtcTransports in getCallCapabilities. - CallWidgetDriver.getRtcTransports(): homeserver /rtc/transports (MSC4143) first, then the .well-known org.matrix.msc4143.rtc_foci list (what matrix.lotusguild.org advertises today). Unit-tested. Server side needs no change: the well-known already carries the livekit focus and the JWT service answers. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
This commit is contained in:
@@ -8,6 +8,8 @@ import {
|
||||
type IWidgetApiErrorResponseDataDetails,
|
||||
type ISearchUserDirectoryResult,
|
||||
type IGetMediaConfigResult,
|
||||
type IRtcTransportsResult,
|
||||
type IRtcTransport,
|
||||
OpenIDRequestState,
|
||||
SimpleObservable,
|
||||
IOpenIDUpdate,
|
||||
@@ -79,29 +81,18 @@ export class CallWidgetDriver extends WidgetDriver {
|
||||
return { roomId, eventId: r.event_id };
|
||||
}
|
||||
|
||||
// matrix-widget-api >= 1.18 dropped the `parentDelayId` argument (MSC4140
|
||||
// parent delays were removed from the spec draft); the signature is now
|
||||
// (delay, eventType, content, stateKey?, roomId?).
|
||||
public async sendDelayedEvent(
|
||||
delay: number | null,
|
||||
parentDelayId: string | null,
|
||||
delay: number,
|
||||
eventType: string,
|
||||
content: IContent,
|
||||
content: unknown,
|
||||
stateKey: string | null = null,
|
||||
targetRoomId: string | null = null,
|
||||
): Promise<ISendDelayedEventDetails> {
|
||||
const roomId = targetRoomId || this.inRoomId;
|
||||
|
||||
let delayOpts;
|
||||
if (delay !== null) {
|
||||
delayOpts = {
|
||||
delay,
|
||||
...(parentDelayId !== null && { parent_delay_id: parentDelayId }),
|
||||
};
|
||||
} else if (parentDelayId !== null) {
|
||||
delayOpts = {
|
||||
parent_delay_id: parentDelayId,
|
||||
};
|
||||
} else {
|
||||
throw new Error('Must provide at least one of delay or parentDelayId');
|
||||
}
|
||||
const delayOpts = { delay };
|
||||
|
||||
let r: SendDelayedEventResponse | null;
|
||||
if (stateKey !== null) {
|
||||
@@ -295,6 +286,36 @@ export class CallWidgetDriver extends WidgetDriver {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* MSC4515: the embedded Element Call asks us for the RTC transports because
|
||||
* a widget can't make authenticated homeserver calls itself. Prefer the
|
||||
* homeserver's MSC4143 `/rtc/transports` endpoint; fall back to the
|
||||
* `org.matrix.msc4143.rtc_foci` list in the client .well-known (what
|
||||
* Synapse deployments without MSC4143 advertise today, incl. ours).
|
||||
* Returning an empty list makes EC report "Call is not supported".
|
||||
*/
|
||||
public async getRtcTransports(): Promise<IRtcTransportsResult> {
|
||||
try {
|
||||
const fromServer = await this.mx._unstable_getRTCTransports();
|
||||
if (Array.isArray(fromServer) && fromServer.length > 0) {
|
||||
return { rtc_transports: fromServer as unknown as IRtcTransport[] };
|
||||
}
|
||||
} catch {
|
||||
// 404 / M_UNRECOGNIZED on homeservers without MSC4143 — fall through.
|
||||
}
|
||||
const wellKnown = this.mx.getClientWellKnown() as
|
||||
| { 'org.matrix.msc4143.rtc_foci'?: unknown }
|
||||
| undefined;
|
||||
const foci = wellKnown?.['org.matrix.msc4143.rtc_foci'];
|
||||
const transports = Array.isArray(foci)
|
||||
? (foci.filter(
|
||||
(f): f is IRtcTransport =>
|
||||
!!f && typeof f === 'object' && typeof (f as { type?: unknown }).type === 'string',
|
||||
) as IRtcTransport[])
|
||||
: [];
|
||||
return { rtc_transports: transports };
|
||||
}
|
||||
|
||||
public async getMediaConfig(): Promise<IGetMediaConfigResult> {
|
||||
return this.mx.getMediaConfig();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user