diff --git a/apps/desktop/element.io/nightly/config.json b/apps/desktop/element.io/nightly/config.json index 3cb23b0b5e..9c0cecfaa5 100644 --- a/apps/desktop/element.io/nightly/config.json +++ b/apps/desktop/element.io/nightly/config.json @@ -51,15 +51,11 @@ "features": { "threadsActivityCentre": true, "feature_spotlight": true, - "feature_group_calls": true, "feature_video_rooms": true, "feature_element_call_video_rooms": true }, "setting_defaults": { "RustCrypto.staged_rollout_percent": 100 }, - "element_call": { - "url": "https://call.element.dev" - }, "map_style_url": "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx" } diff --git a/apps/desktop/element.io/release/config.json b/apps/desktop/element.io/release/config.json index 9bc948b2b6..b8aed8743d 100644 --- a/apps/desktop/element.io/release/config.json +++ b/apps/desktop/element.io/release/config.json @@ -50,10 +50,6 @@ }, "features": { "feature_video_rooms": true, - "feature_group_calls": true, "feature_element_call_video_rooms": true - }, - "element_call": { - "url": "https://call.element.io" } } diff --git a/apps/web/config.sample.json b/apps/web/config.sample.json index 54656418bd..e10b825acf 100644 --- a/apps/web/config.sample.json +++ b/apps/web/config.sample.json @@ -42,8 +42,9 @@ "preferred_domain": "meet.element.io" }, "element_call": { - "url": "https://call.element.io", - "brand": "Element Call" + "brand": "Element Call", + "disable": false, + "use_exclusively": false }, "map_style_url": "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx" } diff --git a/apps/web/element.io/app/config.json b/apps/web/element.io/app/config.json index 032712a5d8..c1e6158007 100644 --- a/apps/web/element.io/app/config.json +++ b/apps/web/element.io/app/config.json @@ -47,10 +47,6 @@ }, "features": { "feature_video_rooms": true, - "feature_group_calls": true, "feature_element_call_video_rooms": true - }, - "element_call": { - "url": "https://call.element.io" } } diff --git a/apps/web/element.io/develop/config.json b/apps/web/element.io/develop/config.json index 2db410355c..2539a1e8f1 100644 --- a/apps/web/element.io/develop/config.json +++ b/apps/web/element.io/develop/config.json @@ -48,15 +48,11 @@ "features": { "threadsActivityCentre": true, "feature_video_rooms": true, - "feature_group_calls": true, "feature_element_call_video_rooms": true }, "setting_defaults": { "RustCrypto.staged_rollout_percent": 100, "Registration.mobileRegistrationHelper": true }, - "element_call": { - "url": "https://call.element.dev" - }, "map_style_url": "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx" } diff --git a/apps/web/playwright/e2e/settings/room-settings/room-video-tab.spec.ts b/apps/web/playwright/e2e/settings/room-settings/room-video-tab.spec.ts index feff22a04e..48f8addc62 100644 --- a/apps/web/playwright/e2e/settings/room-settings/room-video-tab.spec.ts +++ b/apps/web/playwright/e2e/settings/room-settings/room-video-tab.spec.ts @@ -8,8 +8,6 @@ import { type Locator } from "@playwright/test"; import { test, expect } from "../../../element-web-test"; -import { SettingLevel } from "../../../../src/settings/SettingLevel"; - test.describe("Voice & Video room settings tab", () => { const roomName = "Test room"; @@ -22,7 +20,6 @@ test.describe("Voice & Video room settings tab", () => { test.beforeEach(async ({ user, app, page }) => { // Execute client actions before setting, as the setting will force a reload. await app.client.createRoom({ name: roomName }); - await app.settings.setValue("feature_group_calls", null, SettingLevel.DEVICE, true); await app.viewRoomByName(roomName); settings = await app.settings.openRoomSettings("Voice & Video"); }); diff --git a/apps/web/playwright/e2e/voip/element-call.spec.ts b/apps/web/playwright/e2e/voip/element-call.spec.ts index c90ae306f3..9394cc47fa 100644 --- a/apps/web/playwright/e2e/voip/element-call.spec.ts +++ b/apps/web/playwright/e2e/voip/element-call.spec.ts @@ -102,14 +102,6 @@ test.use({ test.describe("Element Call", () => { test.use({ - config: { - element_call: { - use_exclusively: false, - }, - features: { - feature_group_calls: true, - }, - }, displayName: "Alice", botCreateOpts: { autoAcceptInvites: true, diff --git a/apps/web/playwright/snapshots/settings/general-room-settings-tab.spec.ts/General-room-settings-tab-should-be-rendered-properly-1-linux.png b/apps/web/playwright/snapshots/settings/general-room-settings-tab.spec.ts/General-room-settings-tab-should-be-rendered-properly-1-linux.png index 64be83b5e2..9335e8cdb1 100644 Binary files a/apps/web/playwright/snapshots/settings/general-room-settings-tab.spec.ts/General-room-settings-tab-should-be-rendered-properly-1-linux.png and b/apps/web/playwright/snapshots/settings/general-room-settings-tab.spec.ts/General-room-settings-tab-should-be-rendered-properly-1-linux.png differ diff --git a/apps/web/playwright/snapshots/settings/room-settings/room-security-tab.spec.ts/room-security-settings-linux.png b/apps/web/playwright/snapshots/settings/room-settings/room-security-tab.spec.ts/room-security-settings-linux.png index f850033eac..bcfe1113ee 100644 Binary files a/apps/web/playwright/snapshots/settings/room-settings/room-security-tab.spec.ts/room-security-settings-linux.png and b/apps/web/playwright/snapshots/settings/room-settings/room-security-tab.spec.ts/room-security-settings-linux.png differ diff --git a/apps/web/playwright/snapshots/settings/room-settings/room-security-tab.spec.ts/room-security-settings-world-readable-linux.png b/apps/web/playwright/snapshots/settings/room-settings/room-security-tab.spec.ts/room-security-settings-world-readable-linux.png index 2b758ad0a2..29354e204b 100644 Binary files a/apps/web/playwright/snapshots/settings/room-settings/room-security-tab.spec.ts/room-security-settings-world-readable-linux.png and b/apps/web/playwright/snapshots/settings/room-settings/room-security-tab.spec.ts/room-security-settings-world-readable-linux.png differ diff --git a/apps/web/src/SdkConfig.ts b/apps/web/src/SdkConfig.ts index 76e4d47b39..affa80c5be 100644 --- a/apps/web/src/SdkConfig.ts +++ b/apps/web/src/SdkConfig.ts @@ -35,7 +35,6 @@ export const DEFAULTS = { preferred_domain: "meet.element.io", }, element_call: { - use_exclusively: false, brand: "Element Call", }, diff --git a/apps/web/src/components/views/dialogs/RoomSettingsDialog.tsx b/apps/web/src/components/views/dialogs/RoomSettingsDialog.tsx index a70f562833..add6e82783 100644 --- a/apps/web/src/components/views/dialogs/RoomSettingsDialog.tsx +++ b/apps/web/src/components/views/dialogs/RoomSettingsDialog.tsx @@ -45,6 +45,7 @@ import { PeopleRoomSettingsTab } from "../settings/tabs/room/PeopleRoomSettingsT import { SDKContext } from "../../../contexts/SDKContext"; import { type SDKContextClass } from "../../../contexts/SDKContextClass"; import { RoomSettingsTab } from "./RoomSettingsDialog-tab.ts"; +import SdkConfig from "../../../SdkConfig"; interface IProps { roomId: string; @@ -147,7 +148,7 @@ class RoomSettingsDialog extends React.Component { ), ); } - if (SettingsStore.getValue("feature_group_calls")) { + if (!SdkConfig.get("element_call").disable) { tabs.push( new Tab( RoomSettingsTab.Voip, diff --git a/apps/web/src/components/views/settings/tabs/room/RolesRoomSettingsTab.tsx b/apps/web/src/components/views/settings/tabs/room/RolesRoomSettingsTab.tsx index c9078d86e3..4f59829516 100644 --- a/apps/web/src/components/views/settings/tabs/room/RolesRoomSettingsTab.tsx +++ b/apps/web/src/components/views/settings/tabs/room/RolesRoomSettingsTab.tsx @@ -18,7 +18,6 @@ import Modal from "../../../../../Modal"; import ErrorDialog from "../../../dialogs/ErrorDialog"; import PowerSelector from "../../../elements/PowerSelector"; import SettingsFieldset from "../../SettingsFieldset"; -import SettingsStore from "../../../../../settings/SettingsStore"; import SdkConfig, { DEFAULTS } from "../../../../../SdkConfig"; import { AddPrivilegedUsers } from "../../AddPrivilegedUsers"; import SettingsTab from "../SettingsTab"; @@ -270,17 +269,14 @@ export default class RolesRoomSettingsTab extends React.Component = { "users_default": { desc: _t("room_settings|permissions|users_default"), diff --git a/apps/web/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx b/apps/web/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx index db08c2947e..e7cc42397c 100644 --- a/apps/web/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx +++ b/apps/web/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx @@ -11,7 +11,7 @@ import React, { type ChangeEventHandler, type JSX, type ReactNode } from "react" import { logger } from "matrix-js-sdk/src/logger"; import { FALLBACK_ICE_SERVER } from "matrix-js-sdk/src/webrtc/call"; import { type EmptyObject } from "matrix-js-sdk/src/matrix"; -import { Form, SettingsToggleInput } from "@vector-im/compound-web"; +import { Alert, Form, SettingsToggleInput } from "@vector-im/compound-web"; import { _t } from "../../../../../languageHandler"; import MediaDeviceHandler, { type IMediaDevices, MediaDeviceKindEnum } from "../../../../../MediaDeviceHandler"; @@ -19,11 +19,13 @@ import Field from "../../../elements/Field"; import AccessibleButton from "../../../elements/AccessibleButton"; import { SettingLevel } from "../../../../../settings/SettingLevel"; import SettingsFlag from "../../../elements/SettingsFlag"; +import SettingsStore from "../../../../../settings/SettingsStore"; import { requestMediaPermissions } from "../../../../../utils/media/requestMediaPermissions"; import SettingsTab from "../SettingsTab"; import { SettingsSection } from "../../shared/SettingsSection"; import { SettingsSubsection } from "../../shared/SettingsSubsection"; import MatrixClientContext from "../../../../../contexts/MatrixClientContext"; +import SdkConfig from "../../../../../SdkConfig"; interface IState { mediaDevices: IMediaDevices | null; @@ -33,6 +35,7 @@ interface IState { audioAutoGainControl: boolean; audioEchoCancellation: boolean; audioNoiseSuppression: boolean; + enableLegacyCallsVoip: boolean; } /** @@ -65,16 +68,29 @@ export default class VoiceUserSettingsTab extends React.Component { + this.legacyCallsEnabledWatcherRef = SettingsStore.watchSetting( + "enableLegacyCallsVoip", + null, + (...[, , , , value]) => this.setState({ enableLegacyCallsVoip: value as boolean }), + ); + const canSeeDeviceLabels = await MediaDeviceHandler.hasAnyLabeledDevices(); if (canSeeDeviceLabels) { await this.refreshMediaDevices(); } } + public componentWillUnmount(): void { + SettingsStore.unwatchSetting(this.legacyCallsEnabledWatcherRef); + } + private refreshMediaDevices = async (stream?: MediaStream): Promise => { this.setState({ mediaDevices: (await MediaDeviceHandler.getDevices()) ?? null, @@ -143,34 +159,46 @@ export default class VoiceUserSettingsTab extends React.Component = async (event) => { const enable = event.target.checked; await MediaDeviceHandler.setAudioAutoGainControl(enable); - this.setState({ audioAutoGainControl: MediaDeviceHandler.getAudioAutoGainControl() }); + this.setState({ + audioAutoGainControl: MediaDeviceHandler.getAudioAutoGainControl(), + }); }; private onNoiseSuppressionChanged: ChangeEventHandler = async (event) => { const enable = event.target.checked; await MediaDeviceHandler.setAudioNoiseSuppression(enable); - this.setState({ audioNoiseSuppression: MediaDeviceHandler.getAudioNoiseSuppression() }); + this.setState({ + audioNoiseSuppression: MediaDeviceHandler.getAudioNoiseSuppression(), + }); }; private onEchoCancellationChanged: ChangeEventHandler = async (event) => { const enable = event.target.checked; await MediaDeviceHandler.setAudioEchoCancellation(enable); - this.setState({ audioEchoCancellation: MediaDeviceHandler.getAudioEchoCancellation() }); + this.setState({ + audioEchoCancellation: MediaDeviceHandler.getAudioEchoCancellation(), + }); }; - public render(): ReactNode { + public render(): JSX.Element { let requestButton: ReactNode | undefined; let speakerDropdown: ReactNode | undefined; let microphoneDropdown: ReactNode | undefined; + let webcamDropdown: ReactNode | undefined; if (!this.state.mediaDevices) { requestButton = ( -
-

{_t("settings|voip|missing_permissions_prompt")}

- - {_t("settings|voip|request_permissions")} - -
+ + {_t("settings|voip|request_permissions")} + + } + > + {_t("settings|voip|missing_permissions_prompt", { brand: SdkConfig.get("brand") })} + ); } else if (this.state.mediaDevices) { speakerDropdown = this.renderDropdown( @@ -185,6 +213,44 @@ export default class VoiceUserSettingsTab extends React.Component + + {speakerDropdown} + + + + {webcamDropdown} + + + + + + + + ); + return ( - + + {_t("settings|voip|voice_input_description")} {requestButton} - - {speakerDropdown} - {microphoneDropdown} - - - - {webcamDropdown} - - + {microphoneDropdown} - - - + {allowLegacyCalls && ( + + {elementCallEnabled && ( + // allow configuring Legacy calls if EC is also avalibale (otherwise we always show the legacySettingsComponent) + + )} + {(!elementCallEnabled || showLegacySettings) && legacySettingsComponent} + + )} + {(allowLegacyCalls || elementCallEnabled) && ( + - - - - - - + + )} ); diff --git a/apps/web/src/createRoom.ts b/apps/web/src/createRoom.ts index 193e9dd2cc..fc31c7db54 100644 --- a/apps/web/src/createRoom.ts +++ b/apps/web/src/createRoom.ts @@ -45,10 +45,10 @@ import { privateShouldBeEncrypted } from "./utils/rooms"; import { shouldForceDisableEncryption } from "./utils/crypto/shouldForceDisableEncryption"; import { waitForMember } from "./utils/membership"; import { doesRoomVersionSupport, PreferredRoomVersions } from "./utils/PreferredRoomVersions"; -import SettingsStore from "./settings/SettingsStore"; import { MEGOLM_ENCRYPTION_ALGORITHM } from "./utils/crypto"; import { ElementCallMemberEventType } from "./call-types"; import { htmlSerializeFromMdIfNeeded } from "./editor/serialize"; +import SdkConfig from "./SdkConfig"; // we define a number of interfaces which take their names from the js-sdk /* eslint-disable camelcase */ @@ -86,15 +86,26 @@ export interface IOpts { joinRule?: JoinRule; } -const DEFAULT_EVENT_POWER_LEVELS = { - [EventType.RoomName]: 50, +/** + * The power levels set by synapse as of 30.06.2026. + * If power_level_content_override is used, these values should be used + * as a starting point to ensure the expected room power levels. + * + * NOTE: power_level_content_override does do a merge but NOT a deep merge. + * e.g. "ban": 50, will still be set by the server when `power_level_content_override = {events: {"custom": 0}}` + * BUT `events` will lose all the other default props listed below. + * So we have to do: `power_level_content_override = {events: {...POWER_LEVEL_EVENTS_DEFAULT, "custom": 0}}` + * This is very unfortunate if defaults change in synapse we have to keep the sdk in sync... (todo) + */ +export const DEFAULT_EVENTS_POWER_LEVEL = { [EventType.RoomAvatar]: 50, - [EventType.RoomPowerLevels]: 100, - [EventType.RoomHistoryVisibility]: 100, [EventType.RoomCanonicalAlias]: 50, - [EventType.RoomTombstone]: 100, - [EventType.RoomServerAcl]: 100, [EventType.RoomEncryption]: 100, + [EventType.RoomHistoryVisibility]: 100, + [EventType.RoomName]: 50, + [EventType.RoomPowerLevels]: 100, + [EventType.RoomServerAcl]: 100, + [EventType.RoomTombstone]: 100, }; /** @@ -173,7 +184,7 @@ export default async function createRoom(client: MatrixClient, opts: IOpts): Pro if (opts.roomType === RoomType.ElementVideo || opts.roomType === RoomType.UnstableCall) { createOpts.power_level_content_override = { events: { - ...DEFAULT_EVENT_POWER_LEVELS, + ...DEFAULT_EVENTS_POWER_LEVEL, // Allow all users to send call membership updates [opts.roomType === RoomType.ElementVideo ? JitsiCall.MEMBER_EVENT_TYPE @@ -186,10 +197,10 @@ export default async function createRoom(client: MatrixClient, opts: IOpts): Pro }, }; } - } else if (SettingsStore.getValue("feature_group_calls")) { + } else if (!SdkConfig.get("element_call").disable) { createOpts.power_level_content_override = { events: { - ...DEFAULT_EVENT_POWER_LEVELS, + ...DEFAULT_EVENTS_POWER_LEVEL, // It should always (including non video rooms) be possible to join a group call. [ElementCallMemberEventType.name]: 0, }, diff --git a/apps/web/src/hooks/room/useRoomCall.tsx b/apps/web/src/hooks/room/useRoomCall.tsx index 9981bbdbde..4f8ae7890c 100644 --- a/apps/web/src/hooks/room/useRoomCall.tsx +++ b/apps/web/src/hooks/room/useRoomCall.tsx @@ -12,8 +12,7 @@ import { type ReactNode, useCallback, useEffect, useMemo, useState } from "react import { logger as rootLogger } from "matrix-js-sdk/src/logger"; import type React from "react"; -import { useFeatureEnabled, useSettingValue } from "../useSettings"; -import SdkConfig from "../../SdkConfig"; +import { useSettingValue } from "../useSettings"; import { useEventEmitter, useEventEmitterState } from "../useEventEmitter"; import { LegacyCallHandlerEvent } from "../../LegacyCallHandler"; import { useWidgets } from "../../utils/WidgetUtils"; @@ -38,6 +37,7 @@ import { type InteractionName } from "../../PosthogTrackers"; import { ElementCallMemberEventType } from "../../call-types"; import { LocalRoom, LocalRoomState } from "../../models/LocalRoom"; import { useScopedRoomContext } from "../../contexts/ScopedRoomContext"; +import SdkConfig from "../../SdkConfig"; import { SDKContextClass } from "../../contexts/SDKContextClass"; const logger = rootLogger.getChild("useRoomCall"); @@ -109,12 +109,13 @@ export const useRoomCall = ( } => { const roomViewStore = useScopedRoomContext("roomViewStore").roomViewStore; // settings - const groupCallsEnabled = useFeatureEnabled("feature_group_calls"); const widgetsFeatureEnabled = useSettingValue(UIFeature.Widgets); const voipFeatureEnabled = useSettingValue(UIFeature.Voip); - const useElementCallExclusively = useMemo(() => { + const enableLegacyCallsVoip = useSettingValue("enableLegacyCallsVoip"); + const sdkConfigEcOnly = useMemo(() => { return SdkConfig.get("element_call").use_exclusively; }, []); + const useElementCallExclusively = !enableLegacyCallsVoip || sdkConfigEcOnly; const serverIsConfiguredForElementCall = useEventEmitterState( CallStore.instance, @@ -175,13 +176,13 @@ export const useRoomCall = ( // If there are multiple options, the user will be prompted to choose. const callOptions = useMemo((): PlatformCallType[] => { const options: PlatformCallType[] = []; - if (groupCallsEnabled) { - if (hasGroupCall || mayCreateElementCalls) { - options.push(PlatformCallType.ElementCall); - } + if (!SdkConfig.get("element_call").disable) { if (useElementCallExclusively && !hasJitsiWidget) { return [PlatformCallType.ElementCall]; } + if (hasGroupCall || mayCreateElementCalls) { + options.push(PlatformCallType.ElementCall); + } } if (memberCount <= 2) { options.push(PlatformCallType.LegacyCall); @@ -197,7 +198,6 @@ export const useRoomCall = ( memberCount, mayEditWidgets, hasJitsiWidget, - groupCallsEnabled, hasGroupCall, mayCreateElementCalls, useElementCallExclusively, diff --git a/apps/web/src/i18n/strings/en_EN.json b/apps/web/src/i18n/strings/en_EN.json index da7ef74f66..ed42ed52d3 100644 --- a/apps/web/src/i18n/strings/en_EN.json +++ b/apps/web/src/i18n/strings/en_EN.json @@ -495,6 +495,7 @@ "integration_manager": "Integration manager", "joined": "Joined", "labs": "Labs", + "legacy_voice_and_video_settings": "Matrix 1:1 Calls (Legacy)", "legal": "Legal", "light": "Light", "loading": "Loading…", @@ -1535,7 +1536,6 @@ "required_msc_support": "Requires MSC4429 (Profile Updates for Legacy Sync)" }, "feature_wysiwyg_composer_description": "Use rich text instead of Markdown in the message composer.", - "group_calls": "New group call experience", "group_developer": "Developer", "group_encryption": "Encryption", "group_experimental": "Experimental", @@ -2995,21 +2995,25 @@ "audio_output": "Audio Output", "audio_output_empty": "No Audio Outputs detected", "auto_gain_control": "Automatic gain control", - "connection_section": "Connection", "dialog_title": "Settings: Voice & Video", "echo_cancellation": "Echo cancellation", "echo_cancellation_description": "Removes echo from your microphone input during calls. This setting also applies to Element Call.", "enable_fallback_ice_server": "Allow fallback call assist server (%(server)s)", "enable_fallback_ice_server_description": "Only applies if your homeserver does not offer one. Your IP address would be shared during a call.", + "enable_legacy_calls": "Enable Legacy voice/video calls", + "enable_legacy_calls_description": "Applies to Jitsi and 1:1 WebRTC calls", "mirror_local_feed": "Mirror local video feed", - "missing_permissions_prompt": "Missing media permissions, click the button below to request.", + "missing_permissions_prompt": "To participate in calls, give %(brand)s permission to access your audio and video device.", "noise_suppression": "Noise suppression", "noise_suppression_description": "Reduces background noise in your microphone input during calls. This setting also applies to Element Call.", - "request_permissions": "Request media permissions", + "permissions": "Allow microphone and camera access", + "request_permissions": "Request", "title": "Voice & Video", "video_input_empty": "No Webcams detected", "video_section": "Video settings", "voice_agc": "Automatically adjust the microphone volume", + "voice_input_description": "The audio input configured here is used for voice messages and calls (Legacy/1:1).", + "voice_input_section": "Audio Input", "voice_processing": "Voice processing", "voice_section": "Voice settings" }, diff --git a/apps/web/src/settings/Settings.tsx b/apps/web/src/settings/Settings.tsx index 2d19252671..4b137ae901 100644 --- a/apps/web/src/settings/Settings.tsx +++ b/apps/web/src/settings/Settings.tsx @@ -219,7 +219,6 @@ export interface Settings { "feature_sliding_sync": IBaseSetting; "feature_simplified_sliding_sync": IFeature; "feature_element_call_video_rooms": IFeature; - "feature_group_calls": IFeature; "feature_disable_call_per_sender_encryption": IFeature; "feature_location_share_live": IFeature; "feature_dynamic_room_predecessors": IFeature; @@ -282,6 +281,7 @@ export interface Settings { "useSystemFont": IBaseSetting; "systemFont": IBaseSetting; "webRtcAllowPeerToPeer": IBaseSetting; + "enableLegacyCallsVoip": IBaseSetting; "webrtc_audiooutput": IBaseSetting; "webrtc_audioinput": IBaseSetting; "webrtc_videoinput": IBaseSetting; @@ -587,15 +587,6 @@ export const SETTINGS: Settings = { controller: new ReloadOnChangeController(), default: false, }, - "feature_group_calls": { - isFeature: true, - labsGroup: LabGroup.VoiceAndVideo, - supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG_PRIORITISED, - supportedLevelsAreOrdered: true, - displayName: _td("labs|group_calls"), - controller: new ReloadOnChangeController(), - default: false, - }, "feature_disable_call_per_sender_encryption": { isFeature: true, labsGroup: LabGroup.VoiceAndVideo, @@ -980,6 +971,12 @@ export const SETTINGS: Settings = { displayName: _td("settings|appearance|custom_font_name"), controller: new SystemFontController(), }, + "enableLegacyCallsVoip": { + supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, + displayName: _td("settings|voip|enable_legacy_calls"), + description: _td("settings|voip|enable_legacy_calls_description"), + default: true, + }, "webRtcAllowPeerToPeer": { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, displayName: _td("settings|voip|allow_p2p"), diff --git a/apps/web/src/utils/device/clientInformation.test.ts b/apps/web/src/utils/device/clientInformation.test.ts index e79ce79fad..2f029f8e6b 100644 --- a/apps/web/src/utils/device/clientInformation.test.ts +++ b/apps/web/src/utils/device/clientInformation.test.ts @@ -31,7 +31,7 @@ describe("recordClientInformation()", () => { const sdkConfig: DeepReadonly = { ...DEFAULTS, brand: "Test Brand", - element_call: { use_exclusively: false, brand: "Element Call" }, + element_call: { brand: "Element Call" }, }; const platform = { diff --git a/apps/web/test/test-utils/call.ts b/apps/web/test/test-utils/call.ts index bbfe7eaee8..9dee9e10fd 100644 --- a/apps/web/test/test-utils/call.ts +++ b/apps/web/test/test-utils/call.ts @@ -135,7 +135,7 @@ export function useMockedCalls() { * Enables the feature flags required for call tests. */ export function enableCalls(): { enabledSettings: Set } { - const enabledSettings = new Set(["feature_group_calls", "feature_video_rooms", "feature_element_call_video_rooms"]); + const enabledSettings = new Set(["feature_video_rooms", "feature_element_call_video_rooms"]); jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName): any => { if (settingName.startsWith("feature_")) return enabledSettings.has(settingName); if (settingName === "activeCallRoomIds") return []; diff --git a/apps/web/test/unit-tests/components/structures/LoggedInView-test.tsx b/apps/web/test/unit-tests/components/structures/LoggedInView-test.tsx index c55572e197..90d5c0b163 100644 --- a/apps/web/test/unit-tests/components/structures/LoggedInView-test.tsx +++ b/apps/web/test/unit-tests/components/structures/LoggedInView-test.tsx @@ -68,7 +68,6 @@ describe("", () => { hideToSRUsers: false, config: { brand: "Test", - element_call: {}, }, currentRoomId: "", currentUserId: "@bob:server", diff --git a/apps/web/test/unit-tests/components/structures/MatrixChat-test.tsx b/apps/web/test/unit-tests/components/structures/MatrixChat-test.tsx index a4f6e4f68c..a4833e6bd4 100644 --- a/apps/web/test/unit-tests/components/structures/MatrixChat-test.tsx +++ b/apps/web/test/unit-tests/components/structures/MatrixChat-test.tsx @@ -242,7 +242,6 @@ describe("", () => { brand: "Test", help_url: "help_url", help_encryption_url: "help_encryption_url", - element_call: {}, feedback: { existing_issues_url: "https://feedback.org/existing", new_issue_url: "https://feedback.org/new", diff --git a/apps/web/test/unit-tests/components/views/dialogs/RoomSettingsDialog-test.tsx b/apps/web/test/unit-tests/components/views/dialogs/RoomSettingsDialog-test.tsx index 5240bfbe5b..d9f8dd65dd 100644 --- a/apps/web/test/unit-tests/components/views/dialogs/RoomSettingsDialog-test.tsx +++ b/apps/web/test/unit-tests/components/views/dialogs/RoomSettingsDialog-test.tsx @@ -146,10 +146,7 @@ describe("", () => { }); }); - it("renders voip settings tab when enabled", () => { - jest.spyOn(SettingsStore, "getValue").mockImplementation( - (settingName) => settingName === "feature_group_calls", - ); + it("always renders voip settings tab when enabled", () => { getComponent(); expect(screen.getByTestId("settings-tab-ROOM_VOIP_TAB")).toBeInTheDocument(); }); diff --git a/apps/web/test/unit-tests/components/views/dialogs/__snapshots__/RoomSettingsDialog-test.tsx.snap b/apps/web/test/unit-tests/components/views/dialogs/__snapshots__/RoomSettingsDialog-test.tsx.snap index 8b489acd4f..fa3f7b0657 100644 --- a/apps/web/test/unit-tests/components/views/dialogs/__snapshots__/RoomSettingsDialog-test.tsx.snap +++ b/apps/web/test/unit-tests/components/views/dialogs/__snapshots__/RoomSettingsDialog-test.tsx.snap @@ -32,6 +32,35 @@ NodeList [ General , + ,
  • { describe("group call enabled", () => { beforeEach(async () => { - SdkConfig.put({ - features: { - feature_group_calls: true, - }, - }); + SdkConfig.put({}); // Enable Element Call client._unstable_getRTCTransports = jest .fn() @@ -478,12 +474,10 @@ describe("RoomHeader", () => { const user = userEvent.setup(); mockRoomMembers(room, 3); SdkConfig.add({ + element_call: { disable: true }, // This test is about Jitsi widget re-pinning, not Element Call setting_defaults: { [UIFeature.Widgets]: true, }, - features: { - feature_group_calls: false, - }, }); // allow calls jest.spyOn(room.currentState, "mayClientSendStateEvent").mockReturnValue(true); diff --git a/apps/web/test/unit-tests/components/views/rooms/RoomHeader/__snapshots__/RoomHeader-test.tsx.snap b/apps/web/test/unit-tests/components/views/rooms/RoomHeader/__snapshots__/RoomHeader-test.tsx.snap index 754b6cd7c5..328ce5ed63 100644 --- a/apps/web/test/unit-tests/components/views/rooms/RoomHeader/__snapshots__/RoomHeader-test.tsx.snap +++ b/apps/web/test/unit-tests/components/views/rooms/RoomHeader/__snapshots__/RoomHeader-test.tsx.snap @@ -44,39 +44,17 @@ exports[`RoomHeader dm does not show the face pile for DMs 1`] = ` - +