Add sticky event support (#3513)

* add sticky event support
 - use new js-sdk
 - use custom synapse
 - don't filter rooms by existing call state events

Signed-off-by: Timo K <toger5@hotmail.de>

* enable sticky events in the joinSessionConfig

Signed-off-by: Timo K <toger5@hotmail.de>

* Remove unused useNewMembershipmanager setting

* Add prefer sticky setting]

* Fixup call detection logic to allow sticky events

* lint

* update docker image

* More tidy

* update checksum

* bump js-sdk fix sticky events type

Signed-off-by: Timo K <toger5@hotmail.de>

* fix demo

Signed-off-by: Timo K <toger5@hotmail.de>

* always use multi sfu if we are using sticky events.

Signed-off-by: Timo K <toger5@hotmail.de>

* review

Signed-off-by: Timo K <toger5@hotmail.de>

* lint

Signed-off-by: Timo K <toger5@hotmail.de>

* Always consider multi-SFU mode enabled when using sticky events

CallViewModel would pass the wrong transport to enterRtcSession when the user enabled sticky events but didn't manually enable multi-SFU mode as well. This likely would've added some confusion to our attempts to test these modes.

* Fix test type errors

* add todo comment

Signed-off-by: Timo K <toger5@hotmail.de>

---------

Signed-off-by: Timo K <toger5@hotmail.de>
Co-authored-by: Half-Shot <will@half-shot.uk>
Co-authored-by: Robin <robin@robin.town>
This commit is contained in:
Timo
2025-10-22 12:53:22 +02:00
committed by GitHub
parent 4936cdfbf6
commit 5526cd74cb
12 changed files with 166 additions and 96 deletions

View File

@@ -5,8 +5,20 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE in the repository root for full details.
*/
import { type ChangeEvent, type FC, useCallback, useMemo } from "react";
import {
type ChangeEvent,
type FC,
useCallback,
useEffect,
useMemo,
useState,
} from "react";
import { useTranslation } from "react-i18next";
import {
UNSTABLE_MSC4354_STICKY_EVENTS,
type MatrixClient,
} from "matrix-js-sdk";
import { logger } from "matrix-js-sdk/lib/logger";
import { FieldRow, InputField } from "../input/Input";
import {
@@ -14,16 +26,16 @@ import {
duplicateTiles as duplicateTilesSetting,
debugTileLayout as debugTileLayoutSetting,
showConnectionStats as showConnectionStatsSetting,
useNewMembershipManager as useNewMembershipManagerSetting,
useExperimentalToDeviceTransport as useExperimentalToDeviceTransportSetting,
multiSfu as multiSfuSetting,
muteAllAudio as muteAllAudioSetting,
alwaysShowIphoneEarpiece as alwaysShowIphoneEarpieceSetting,
preferStickyEvents as preferStickyEventsSetting,
} from "./settings";
import type { MatrixClient } from "matrix-js-sdk";
import type { Room as LivekitRoom } from "livekit-client";
import styles from "./DeveloperSettingsTab.module.css";
import { useUrlParams } from "../UrlParams";
interface Props {
client: MatrixClient;
livekitRooms?: { room: LivekitRoom; url: string; isLocal?: boolean }[];
@@ -36,12 +48,24 @@ export const DeveloperSettingsTab: FC<Props> = ({ client, livekitRooms }) => {
debugTileLayoutSetting,
);
const [showConnectionStats, setShowConnectionStats] = useSetting(
showConnectionStatsSetting,
const [stickyEventsSupported, setStickyEventsSupported] = useState(false);
useEffect(() => {
client
.doesServerSupportUnstableFeature(UNSTABLE_MSC4354_STICKY_EVENTS)
.then((result) => {
setStickyEventsSupported(result);
})
.catch((ex) => {
logger.warn("Failed to check if sticky events are supported", ex);
});
}, [client]);
const [preferStickyEvents, setPreferStickyEvents] = useSetting(
preferStickyEventsSetting,
);
const [useNewMembershipManager, setNewMembershipManager] = useSetting(
useNewMembershipManagerSetting,
const [showConnectionStats, setShowConnectionStats] = useSetting(
showConnectionStatsSetting,
);
const [alwaysShowIphoneEarpiece, setAlwaysShowIphoneEarpiece] = useSetting(
@@ -126,6 +150,22 @@ 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"
@@ -140,20 +180,6 @@ export const DeveloperSettingsTab: FC<Props> = ({ client, livekitRooms }) => {
)}
/>
</FieldRow>
<FieldRow>
<InputField
id="useNewMembershipManager"
type="checkbox"
label={t("developer_mode.use_new_membership_manager")}
checked={!!useNewMembershipManager}
onChange={useCallback(
(event: ChangeEvent<HTMLInputElement>): void => {
setNewMembershipManager(event.target.checked);
},
[setNewMembershipManager],
)}
/>
</FieldRow>
<FieldRow>
<InputField
id="useToDeviceKeyTransport"
@@ -173,7 +199,9 @@ export const DeveloperSettingsTab: FC<Props> = ({ client, livekitRooms }) => {
id="multiSfu"
type="checkbox"
label={t("developer_mode.multi_sfu")}
checked={multiSfu}
// If using sticky events we implicitly prefer use multi-sfu
checked={multiSfu || preferStickyEvents}
disabled={preferStickyEvents}
onChange={useCallback(
(event: ChangeEvent<HTMLInputElement>): void => {
setMultiSfu(event.target.checked);

View File

@@ -83,6 +83,11 @@ 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,
@@ -115,11 +120,6 @@ export const soundEffectVolume = new Setting<number>(
0.5,
);
export const useNewMembershipManager = new Setting<boolean>(
"new-membership-manager",
true,
);
export const useExperimentalToDeviceTransport = new Setting<boolean>(
"experimental-to-device-transport",
true,