Compare commits

...

12 Commits

Author SHA1 Message Date
fkwp
00ae106e8a prettier 2026-05-04 20:51:16 +02:00
fkwp
c393aa414e Merge branch 'livekit' into fkwp/feature_add_delegation_info_to_legacy_jwt_request 2026-05-04 20:29:38 +02:00
fkwp
23039fbf80 add proper interface
Co-authored-by: Copilot <copilot@github.com>
2026-04-30 20:36:42 +02:00
fkwp
a380171d05 move startWith to corresponding switchMap branch
Co-authored-by: Copilot <copilot@github.com>
2026-04-30 20:36:29 +02:00
fkwp
af66f4b8b5 remove error pages as /50x.html does not exists 2026-04-30 20:34:53 +02:00
fkwp
af90621282 calculate the number of retries based on the /sync grace period and network_error_retry_ms 2026-04-29 10:45:42 +02:00
fkwp
507f4d677d fix test 2026-04-27 15:19:12 +02:00
fkwp
a78bfad879 more tuning and enabling multi-SFU 2026-04-24 17:39:04 +02:00
fkwp
4bbf3e501e further tuning 2026-04-24 16:54:20 +02:00
fkwp
f300d9d1f5 hacky way of tuning parameters 2026-04-24 16:51:57 +02:00
fkwp
1e822cb21c Merge branch 'fkwp/feature_relax_homeserver_offline' into fkwp/feature_add_delegation_info_to_legacy_jwt_request 2026-04-23 17:29:51 +02:00
fkwp
9ec009460d Add support for delayed delegation for legacy JWT requests 2026-04-23 17:28:48 +02:00
6 changed files with 66 additions and 20 deletions

View File

@@ -34,6 +34,7 @@ server {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
}
location ~ ^(/_matrix|/_synapse/admin) {
proxy_pass "http://homeserver:8008";
proxy_http_version 1.1;
@@ -42,8 +43,6 @@ server {
proxy_set_header Host $host;
}
error_page 500 502 503 504 /50x.html;
}
# Synapse reverse proxy including .well-known/matrix/client
@@ -91,8 +90,6 @@ server {
proxy_set_header Host $host;
}
error_page 500 502 503 504 /50x.html;
}
# MatrixRTC reverse proxy
@@ -144,8 +141,6 @@ server {
proxy_pass http://livekit-sfu:7880/;
}
error_page 500 502 503 504 /50x.html;
}
# MatrixRTC reverse proxy
@@ -192,8 +187,6 @@ server {
proxy_pass http://livekit-sfu-1:17880/;
}
error_page 500 502 503 504 /50x.html;
}
# Convenience reverse proxy for the call.m.localhost domain to element call
@@ -243,7 +236,6 @@ server {
proxy_pass http://host.docker.internal:8080;
}
error_page 500 502 503 504 /50x.html;
}
@@ -276,8 +268,6 @@ server {
}
error_page 500 502 503 504 /50x.html;
}
# Convenience reverse proxy app.othersite.m.localhost for element web
@@ -309,6 +299,4 @@ server {
}
error_page 500 502 503 504 /50x.html;
}

View File

@@ -6,11 +6,12 @@
}
},
"ssla": "https://static.element.io/legal/element-software-and-services-license-agreement-uk-1.pdf",
"sync_disconnect_grace_period_ms": 60000,
"matrix_rtc_session": {
"wait_for_key_rotation_ms": 3000,
"membership_event_expiry_ms": 180000000,
"delayed_leave_event_delay_ms": 18000,
"delayed_leave_event_restart_ms": 4000,
"delayed_leave_event_delay_ms": 120000,
"delayed_leave_event_restart_ms": 15000,
"network_error_retry_ms": 100
},
"posthog": {

View File

@@ -131,7 +131,7 @@ describe("getSFUConfigWithOpenID", () => {
expect(calls[1][0]).toStrictEqual("https://sfu.example.org/sfu/get");
expect(calls[1][1]).toStrictEqual({
body: '{"room":"!example_room_id","device_id":"DEVICE"}',
body: '{"room":"!example_room_id","device_id":"DEVICE","delay_id":"mock_delay_id","delay_timeout":1000,"delay_cs_api_url":"https://matrix.homeserverserver.org"}',
headers: {
"Content-Type": "application/json",
},

View File

@@ -155,6 +155,8 @@ export async function getSFUConfigWithOpenID(
serviceUrl,
roomId,
openIdToken,
opts?.delayEndpointBaseUrl,
opts?.delayId,
);
logger?.info(`Got JWT from call's active focus URL.`);
return extractFullConfigFromToken(sfuConfig);
@@ -187,20 +189,59 @@ async function getLiveKitJWT(
livekitServiceURL: string,
matrixRoomId: string,
openIDToken: IOpenIDToken,
delayEndpointBaseUrl?: string,
delayId?: string,
): Promise<{ url: string; jwt: string }> {
const res = await doNetworkOperationWithRetry(async () => {
interface IDelayParams {
delay_id?: string;
delay_timeout?: number;
delay_cs_api_url?: string;
}
let bodyDalayParts: IDelayParams = {};
// Also check for empty string
if (delayId && delayEndpointBaseUrl) {
const delayTimeoutMs =
Config.get().matrix_rtc_session?.delayed_leave_event_delay_ms ?? 1000;
bodyDalayParts = {
delay_id: delayId,
delay_timeout: delayTimeoutMs,
delay_cs_api_url: delayEndpointBaseUrl,
};
}
const makeRequest = async (delayParts: IDelayParams): Promise<Response> => {
return await fetch(livekitServiceURL + "/sfu/get", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
// This is the actual livekit room alias. For the legacy jwt endpoint simply the room id was used.
// The legacy jwt endpoint uses only the matrix room id to calculate the livekit room alias.
// In turn, the livekit room alias is provided as part of the JWT payload.
room: matrixRoomId,
openid_token: openIDToken,
device_id: deviceId,
...delayParts,
}),
});
};
const res = await doNetworkOperationWithRetry(async () => {
let response = await makeRequest(bodyDalayParts);
// If 400 with M_BAD_JSON and we sent delay parts, retry without them (old service compatibility)
if (response.status === 400 && Object.keys(bodyDalayParts).length > 0) {
try {
const errorBody = await response.json();
if (errorBody.errcode === "M_BAD_JSON") {
response = await makeRequest({});
}
} catch {
// If we can't parse the error, treat as real error
}
}
return response;
});
if (!res.ok) {

View File

@@ -409,8 +409,9 @@ export function createCallViewModel$(
options.encryptionSystem,
matrixRTCSession,
);
const matrixRTCMode$ =
options.matrixRTCMode$ ?? constant(MatrixRTCMode.Legacy);
// const matrixRTCMode$ =
// options.matrixRTCMode$ ?? constant(MatrixRTCMode.Legacy);
const matrixRTCMode$ = constant(MatrixRTCMode.Compatibility);
// Each hbar seperates a block of input variables required for the CallViewModel to function.
// The outputs of this block is written under the hbar.

View File

@@ -778,6 +778,20 @@ export function enterRTCSession(
};
}
// Calculates `maximumNetworkErrorRetryCount`. The connection is failed if EITHER:
// - The /sync loop is unresponsive for > `gracePeriod` ms.
// - A delayed leave event is emitted (configured with a `leaveDelay` ms period).
// Note: Use leaveDelay >> gracePeriod for delegated leave events.
const gracePeriod = Config.get().sync_disconnect_grace_period_ms ?? 10000;
const leaveDelay =
matrixRtcSessionConfig?.delayed_leave_event_delay_ms ?? 10000;
const retryInterval = matrixRtcSessionConfig?.network_error_retry_ms ?? 1000;
// Math.min is used to account for the respective worst case: /sync not available or leave event emitted.
const maxWaitTime = Math.min(gracePeriod, leaveDelay);
const maximumNetworkErrorRetryCount =
Math.ceil(maxWaitTime / retryInterval) + 1;
// Multi-sfu does not need a preferred foci list. just the focus that is actually used.
// TODO where/how do we track errors originating from the ongoing rtcSession?
@@ -803,6 +817,7 @@ export function enterRTCSession(
membershipEventExpiryMs:
matrixRtcSessionConfig?.membership_event_expiry_ms,
unstableSendStickyEvents: matrixRTCMode === MatrixRTCMode.Matrix_2_0,
maximumNetworkErrorRetryCount: maximumNetworkErrorRetryCount,
},
);
}