Compare commits

...

10 Commits

Author SHA1 Message Date
Half-Shot
8268e7527c Ensure we set the slot_id 2025-11-07 12:31:19 +00:00
Half-Shot
dc293e9f97 Update branch 2025-11-07 10:39:30 +00:00
Half-Shot
33469f992d Use sticky events synapse 2025-11-07 10:39:24 +00:00
Half-Shot
ba36acbc4b Always create a slot on a new room. 2025-10-30 11:22:56 +00:00
Half-Shot
1f0367f21f fix param parse 2025-10-28 09:42:48 +00:00
Half-Shot
890508ce53 cleanup 2025-10-28 09:31:05 +00:00
Half-Shot
8dde994275 fix 2025-10-28 09:28:28 +00:00
Half-Shot
36ea3e9eff Refactor to remove preferStickyEvents 2025-10-28 09:25:58 +00:00
Half-Shot
c98397a6c8 update docs 2025-10-27 11:47:53 +00:00
Half-Shot
b59275b3e1 Add ability to specify sticky events in URI. 2025-10-27 11:37:56 +00:00
10 changed files with 53 additions and 62 deletions

View File

@@ -88,7 +88,7 @@ services:
synapse:
hostname: homeserver
image: docker.io/matrixdotorg/synapse:latest
image: ghcr.io/element-hq/synapse:msc4354-5
pull_policy: always
environment:
- SYNAPSE_CONFIG_PATH=/data/cfg/homeserver.yaml
@@ -106,7 +106,7 @@ services:
synapse-1:
hostname: homeserver-1
image: docker.io/matrixdotorg/synapse:latest
image: ghcr.io/element-hq/synapse:msc4354-5
pull_policy: always
environment:
- SYNAPSE_CONFIG_PATH=/data/cfg/homeserver.yaml

View File

@@ -72,6 +72,7 @@ These parameters are relevant to both [widget](./embedded-standalone.md) and [st
| `sendNotificationType` | `ring` or `notification` | No | No | Will send a "ring" or "notification" `m.rtc.notification` event if the user is the first one in the call. |
| `autoLeaveWhenOthersLeft` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Whether the app should automatically leave the call when there is no one left in the call. |
| `waitForCallPickup` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | When sending a notification, show UI that the app is awaiting an answer, play a dial tone, and (in widget mode) auto-close the widget once the notification expires. |
| `multiSFU` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Enables experimental new multiSFU support. |
### Widget-only parameters

View File

@@ -72,12 +72,11 @@
"livekit_server_info": "LiveKit Server Info",
"livekit_sfu": "LiveKit SFU: {{url}}",
"matrix_id": "Matrix ID: {{id}}",
"multi_sfu": "Multi-SFU media transport",
"mute_all_audio": "Mute all audio (participants, reactions, join sounds)",
"prefer_sticky_events": {
"description": "Improves reliability of calls (requires homeserver support)",
"label": "Prefer sticky events"
"multi_sfu": {
"description": "Allows multiple SFUs to be present in a call (requires homeserver support)",
"label": "Multi-SFU media transport"
},
"mute_all_audio": "Mute all audio (participants, reactions, join sounds)",
"show_connection_stats": "Show connection statistics",
"url_params": "URL parameters"
},

View File

@@ -109,7 +109,7 @@
"livekit-client": "^2.13.0",
"lodash-es": "^4.17.21",
"loglevel": "^1.9.1",
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#head=toger5/sticky-events&commit=e7f5bec51b6f70501a025b79fe5021c933385b21",
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#head=hs/rtc-slots&commit=c56fe525aa4dcb8c3b8629dc303b95f4dd4988bd",
"matrix-widget-api": "^1.13.0",
"normalize.css": "^8.0.1",
"observable-hooks": "^4.2.3",

View File

@@ -141,6 +141,11 @@ export interface UrlProperties {
* can be "light", "dark", "light-high-contrast" or "dark-high-contrast".
*/
theme: string | null;
/**
* Whether or not the call should be held using the sticky event implementation,
* where possible.
*/
multiSFU: boolean;
}
/**
@@ -501,6 +506,7 @@ export const computeUrlParams = (search = "", hash = ""): UrlParams => {
sentryDsn: parser.getParam("sentryDsn"),
sentryEnvironment: parser.getParam("sentryEnvironment"),
e2eEnabled: parser.getFlagParam("enableE2EE", true),
multiSFU: parser.getFlagParam("multiSFU", false),
};
const configuration: Partial<UrlConfiguration> = {

View File

@@ -29,7 +29,6 @@ import {
multiSfu as multiSfuSetting,
muteAllAudio as muteAllAudioSetting,
alwaysShowIphoneEarpiece as alwaysShowIphoneEarpieceSetting,
preferStickyEvents as preferStickyEventsSetting,
} from "./settings";
import type { Room as LivekitRoom } from "livekit-client";
import styles from "./DeveloperSettingsTab.module.css";
@@ -59,10 +58,6 @@ export const DeveloperSettingsTab: FC<Props> = ({ client, livekitRooms }) => {
});
}, [client]);
const [preferStickyEvents, setPreferStickyEvents] = useSetting(
preferStickyEventsSetting,
);
const [showConnectionStats, setShowConnectionStats] = useSetting(
showConnectionStatsSetting,
);
@@ -146,22 +141,6 @@ export const DeveloperSettingsTab: FC<Props> = ({ client, livekitRooms }) => {
}
/>
</FieldRow>
<FieldRow>
<InputField
id="preferStickyEvents"
type="checkbox"
label={t("developer_mode.prefer_sticky_events.label")}
disabled={!stickyEventsSupported}
description={t("developer_mode.prefer_sticky_events.description")}
checked={!!preferStickyEvents}
onChange={useCallback(
(event: ChangeEvent<HTMLInputElement>): void => {
setPreferStickyEvents(event.target.checked);
},
[setPreferStickyEvents],
)}
/>
</FieldRow>
<FieldRow>
<InputField
id="showConnectionStats"
@@ -180,10 +159,10 @@ export const DeveloperSettingsTab: FC<Props> = ({ client, livekitRooms }) => {
<InputField
id="multiSfu"
type="checkbox"
label={t("developer_mode.multi_sfu")}
// If using sticky events we implicitly prefer use multi-sfu
checked={multiSfu || preferStickyEvents}
disabled={preferStickyEvents}
label={t("developer_mode.multi_sfu.label")}
description={t("developer_mode.multi_sfu.description")}
checked={multiSfu}
disabled={!stickyEventsSupported}
onChange={useCallback(
(event: ChangeEvent<HTMLInputElement>): void => {
setMultiSfu(event.target.checked);

View File

@@ -83,11 +83,6 @@ export const showConnectionStats = new Setting<boolean>(
false,
);
export const preferStickyEvents = new Setting<boolean>(
"prefer-sticky-events",
false,
);
export const audioInput = new Setting<string | undefined>(
"audio-input",
undefined,

View File

@@ -91,7 +91,6 @@ import {
duplicateTiles,
multiSfu,
playReactionsSound,
preferStickyEvents,
showReactions,
} from "../settings/settings";
import { isFirefox } from "../Platform";
@@ -282,22 +281,13 @@ export class CallViewModel {
remote: { membership: CallMembership; transport: LivekitTransport }[];
preferred: Async<LivekitTransport>;
multiSfu: boolean;
preferStickyEvents: boolean;
} | null> = this.scope.behavior(
this.joined$.pipe(
switchMap((joined) =>
joined
? combineLatest(
[
this.preferredTransport$,
this.memberships$,
multiSfu.value$,
preferStickyEvents.value$,
],
(preferred, memberships, preferMultiSfu, preferStickyEvents) => {
// Multi-SFU must be implicitly enabled when using sticky events
const multiSfu = preferStickyEvents || preferMultiSfu;
[this.preferredTransport$, this.memberships$, multiSfu.value$],
(preferred, memberships, multiSfu) => {
const oldestMembership =
this.matrixRTCSession.getOldestMembership();
const remote = memberships.flatMap((m) => {
@@ -333,7 +323,6 @@ export class CallViewModel {
remote,
preferred,
multiSfu,
preferStickyEvents,
};
},
)
@@ -368,7 +357,6 @@ export class CallViewModel {
*/
private readonly advertisedTransport$: Behavior<{
multiSfu: boolean;
preferStickyEvents: boolean;
transport: LivekitTransport;
} | null> = this.scope.behavior(
this.transports$.pipe(
@@ -377,7 +365,6 @@ export class CallViewModel {
transports.preferred.state === "ready"
? {
multiSfu: transports.multiSfu,
preferStickyEvents: transports.preferStickyEvents,
// In non-multi-SFU mode we should always advertise the preferred
// SFU to minimize the number of membership updates
transport: transports.multiSfu
@@ -388,7 +375,6 @@ export class CallViewModel {
),
distinctUntilChanged<{
multiSfu: boolean;
preferStickyEvents: boolean;
transport: LivekitTransport;
} | null>(deepCompare),
),
@@ -1834,7 +1820,8 @@ export class CallViewModel {
await enterRTCSession(this.matrixRTCSession, advertised.transport, {
encryptMedia: this.options.encryptionSystem.kind !== E2eeType.NONE,
useMultiSfu: advertised.multiSfu,
preferStickyEvents: advertised.preferStickyEvents,
// Multi-SFU enables sticky events.
preferStickyEvents: advertised.multiSfu ?? this.urlParams.multiSFU,
});
} catch (e) {
logger.error("Error entering RTC session", e);

View File

@@ -13,6 +13,7 @@ import {
MemoryStore,
Preset,
Visibility,
EventType,
} from "matrix-js-sdk";
import { type ISyncStateData, type SyncState } from "matrix-js-sdk/lib/sync";
import { logger } from "matrix-js-sdk/lib/logger";
@@ -28,6 +29,10 @@ import {
type EncryptionSystem,
saveKeyForRoom,
} from "../e2ee/sharedKeyManagement";
import {
DefaultCallApplicationSlot,
RtcSlotEventContent,
} from "matrix-js-sdk/lib/matrixrtc";
export const fallbackICEServerAllowed =
import.meta.env.VITE_FALLBACK_STUN_ALLOWED === "true";
@@ -236,6 +241,16 @@ export async function createRoom(
preset: Preset.PublicChat,
name,
room_alias_name: e2ee ? undefined : roomAliasLocalpartFromRoomName(name),
initial_state: [
// Always create a slot
{
type: EventType.RTCSlot,
content: {
slot_id: DefaultCallApplicationSlot.slot_id,
application: { ...DefaultCallApplicationSlot.application },
} satisfies RtcSlotEventContent,
},
],
power_level_content_override: {
invite: 100,
kick: 100,

View File

@@ -7545,7 +7545,7 @@ __metadata:
livekit-client: "npm:^2.13.0"
lodash-es: "npm:^4.17.21"
loglevel: "npm:^1.9.1"
matrix-js-sdk: "github:matrix-org/matrix-js-sdk#head=toger5/sticky-events&commit=e7f5bec51b6f70501a025b79fe5021c933385b21"
matrix-js-sdk: "github:matrix-org/matrix-js-sdk#head=hs/rtc-slots&commit=c56fe525aa4dcb8c3b8629dc303b95f4dd4988bd"
matrix-widget-api: "npm:^1.13.0"
normalize.css: "npm:^8.0.1"
observable-hooks: "npm:^4.2.3"
@@ -10343,9 +10343,9 @@ __metadata:
languageName: node
linkType: hard
"matrix-js-sdk@github:matrix-org/matrix-js-sdk#head=toger5/sticky-events&commit=e7f5bec51b6f70501a025b79fe5021c933385b21":
version: 38.4.0
resolution: "matrix-js-sdk@https://github.com/matrix-org/matrix-js-sdk.git#commit=e7f5bec51b6f70501a025b79fe5021c933385b21"
"matrix-js-sdk@github:matrix-org/matrix-js-sdk#head=hs/rtc-slots&commit=c56fe525aa4dcb8c3b8629dc303b95f4dd4988bd":
version: 39.0.0
resolution: "matrix-js-sdk@https://github.com/matrix-org/matrix-js-sdk.git#commit=c56fe525aa4dcb8c3b8629dc303b95f4dd4988bd"
dependencies:
"@babel/runtime": "npm:^7.12.5"
"@matrix-org/matrix-sdk-crypto-wasm": "npm:^15.3.0"
@@ -10358,10 +10358,10 @@ __metadata:
matrix-widget-api: "npm:^1.10.0"
oidc-client-ts: "npm:^3.0.1"
p-retry: "npm:7"
sdp-transform: "npm:^2.14.1"
sdp-transform: "npm:^3.0.0"
unhomoglyph: "npm:^1.0.6"
uuid: "npm:13"
checksum: 10c0/7adffdc183affd2d3ee1e8497cad6ca7904a37f98328ff7bc15aa6c1829dc9f9a92f8e1bd6260432a33626ff2a839644de938270163e73438b7294675cd954e4
checksum: 10c0/f8267c2a1fac67076400f886259d9b58b597f975865ce49aefe774d2f56a5c7caef66307f02fe24dcad35829e747bd7e563ecbb9a694d1f80b2439eebe0724fa
languageName: node
linkType: hard
@@ -12544,7 +12544,7 @@ __metadata:
languageName: node
linkType: hard
"sdp-transform@npm:^2.14.1, sdp-transform@npm:^2.15.0":
"sdp-transform@npm:^2.15.0":
version: 2.15.0
resolution: "sdp-transform@npm:2.15.0"
bin:
@@ -12553,6 +12553,15 @@ __metadata:
languageName: node
linkType: hard
"sdp-transform@npm:^3.0.0":
version: 3.0.0
resolution: "sdp-transform@npm:3.0.0"
bin:
sdp-verify: checker.js
checksum: 10c0/828a4595041ba64c86b29075aa4007ab384519b1fa29882db59ccb83b54b2b2a33b60848293f8da537fe151c52f5844fc17c8325396cac309fb19e2e81ec5bf4
languageName: node
linkType: hard
"sdp@npm:^3.2.0":
version: 3.2.0
resolution: "sdp@npm:3.2.0"