mirror of
https://github.com/vector-im/element-call.git
synced 2026-11-07 00:52:28 +00:00
allow to participate in full_mesh without publishing
This commit is contained in:
+3
-1
@@ -78,8 +78,10 @@
|
||||
"device_id": "Device ID: {{id}}",
|
||||
"duplicate_tiles_label": "Number of additional tile copies per participant",
|
||||
"environment_variables": "Environment variables",
|
||||
"full_mesh_capabilities": "Take part in full mesh (MSC4575)",
|
||||
"full_mesh_capabilities_description": "Receive members publishing on full mesh. As a widget, this asks the host for the signalling permissions.",
|
||||
"full_mesh_peer_connections": "Full mesh peer connections",
|
||||
"full_mesh_publishing": "Publish on full mesh (MSC4575) instead of LiveKit",
|
||||
"full_mesh_publishing": "Publish on full mesh instead of LiveKit",
|
||||
"full_mesh_transport": "Full mesh: {{device}}",
|
||||
"hostname": "Hostname: {{hostname}}",
|
||||
"livekit_server_info": "LiveKit Server Info",
|
||||
|
||||
@@ -55,14 +55,28 @@ async function recordWidgetToDevice(
|
||||
);
|
||||
}
|
||||
|
||||
const cases: { name: string; fullMesh: [boolean, boolean] }[] = [
|
||||
const cases: {
|
||||
name: string;
|
||||
/** Who publishes on full mesh; both have the capabilities unless said. */
|
||||
fullMesh: [boolean, boolean];
|
||||
capabilities?: [boolean, boolean];
|
||||
}[] = [
|
||||
// Both publish on full mesh: the media flows without any SFU
|
||||
{ name: "both on full mesh", fullMesh: [true, true] },
|
||||
// One on each: Florian receives Valere over LiveKit without publishing there
|
||||
// One on each: Florian receives Valere over LiveKit without publishing
|
||||
// there, and Valere receives Florian over full mesh without publishing there
|
||||
{ name: "full mesh and LiveKit mixed", fullMesh: [true, false] },
|
||||
// Without the capabilities a widget can't be subscribed to full mesh
|
||||
{
|
||||
name: "LiveKit side without the full mesh capabilities",
|
||||
fullMesh: [true, false],
|
||||
capabilities: [true, false],
|
||||
},
|
||||
];
|
||||
|
||||
cases.forEach(({ name, fullMesh: [florianMesh, valereMesh] }) => {
|
||||
cases.forEach(({ name, fullMesh, capabilities = [true, true] }) => {
|
||||
const [florianMesh, valereMesh] = fullMesh;
|
||||
const [florianCaps, valereCaps] = capabilities;
|
||||
widgetTest(`Full mesh call: ${name}`, async ({ addUser, browserName }) => {
|
||||
test.skip(
|
||||
browserName === "firefox",
|
||||
@@ -71,7 +85,7 @@ cases.forEach(({ name, fullMesh: [florianMesh, valereMesh] }) => {
|
||||
test.slow();
|
||||
|
||||
// Distinct per case: the cases run in parallel and register at once
|
||||
const suffix = `${Number(florianMesh)}${Number(valereMesh)}`;
|
||||
const suffix = `${Number(florianMesh)}${Number(valereMesh)}${Number(florianCaps)}${Number(valereCaps)}`;
|
||||
const [florian, valere] = await Promise.all([
|
||||
addUser(`florian${suffix}`, HOST1),
|
||||
addUser(`valere${suffix}`, HOST1),
|
||||
@@ -95,24 +109,22 @@ cases.forEach(({ name, fullMesh: [florianMesh, valereMesh] }) => {
|
||||
await TestHelpers.openWidgetSetEmbeddedElementCallRtcModeCloseWidget(
|
||||
florian.page,
|
||||
"2_0",
|
||||
{ fullMesh: florianMesh },
|
||||
{ capabilities: florianCaps, publish: florianMesh },
|
||||
);
|
||||
await TestHelpers.openWidgetSetEmbeddedElementCallRtcModeCloseWidget(
|
||||
valere.page,
|
||||
"2_0",
|
||||
{ fullMesh: valereMesh },
|
||||
{ capabilities: valereCaps, publish: valereMesh },
|
||||
);
|
||||
|
||||
await TestHelpers.startCallInCurrentRoom(florian.page, false);
|
||||
await TestHelpers.joinCallFromLobby(florian.page);
|
||||
await TestHelpers.joinCallInCurrentRoom(valere.page);
|
||||
|
||||
// A widget only asks for the full mesh signalling with full mesh turned
|
||||
// on, so a LiveKit publisher in Element Web can't receive full mesh yet:
|
||||
// the other's media arrives if it is on LiveKit or we have full mesh
|
||||
// The other's media arrives if it is on LiveKit, or we can signal full mesh
|
||||
const receives = {
|
||||
florian: !valereMesh || florianMesh,
|
||||
valere: !florianMesh || valereMesh,
|
||||
florian: !valereMesh || florianCaps,
|
||||
valere: !florianMesh || valereCaps,
|
||||
};
|
||||
// In parallel: assertions on a page also run its permission handler
|
||||
await Promise.all(
|
||||
|
||||
@@ -24,6 +24,14 @@ export const HOST2 = "https://app.othersite.m.localhost/#/welcome";
|
||||
|
||||
export type RtcMode = "compat" | "2_0";
|
||||
|
||||
/** Full mesh (MSC4575) in the widget's developer settings. */
|
||||
export interface FullMeshOptions {
|
||||
/** Ask the host for the signalling capabilities, to receive full mesh. */
|
||||
capabilities?: boolean;
|
||||
/** Publish on full mesh instead of LiveKit; needs the capabilities. */
|
||||
publish?: boolean;
|
||||
}
|
||||
|
||||
export class TestHelpers {
|
||||
public static async startCallInCurrentRoom(
|
||||
page: Page,
|
||||
@@ -306,7 +314,7 @@ export class TestHelpers {
|
||||
public static async openWidgetSetEmbeddedElementCallRtcModeCloseWidget(
|
||||
page: Page,
|
||||
mode: RtcMode,
|
||||
{ fullMesh = false }: { fullMesh?: boolean } = {},
|
||||
fullMesh: FullMeshOptions = {},
|
||||
): Promise<void> {
|
||||
await page.getByRole("button", { name: "Video call" }).click({
|
||||
timeout: 5000,
|
||||
@@ -315,7 +323,7 @@ export class TestHelpers {
|
||||
timeout: 10000,
|
||||
});
|
||||
|
||||
await TestHelpers.setEmbeddedElementCallRtcMode(page, mode, { fullMesh });
|
||||
await TestHelpers.setEmbeddedElementCallRtcMode(page, mode, fullMesh);
|
||||
await page.getByRole("button", { name: "Close lobby" }).click();
|
||||
}
|
||||
|
||||
@@ -328,7 +336,7 @@ export class TestHelpers {
|
||||
public static async setEmbeddedElementCallRtcMode(
|
||||
page: Page,
|
||||
mode: RtcMode,
|
||||
{ fullMesh = false }: { fullMesh?: boolean } = {},
|
||||
{ capabilities = false, publish = false }: FullMeshOptions = {},
|
||||
): Promise<void> {
|
||||
const iframe = page.locator('iframe[title="Element Call"]').contentFrame();
|
||||
|
||||
@@ -346,10 +354,14 @@ export class TestHelpers {
|
||||
// compat
|
||||
await iframe.getByText("Compatibility: state events").click();
|
||||
}
|
||||
// Publish on the full mesh transport (MSC4575) instead of LiveKit
|
||||
// Full mesh (MSC4575): the capabilities first, as publishing needs them
|
||||
await iframe
|
||||
.getByText("Publish on full mesh", { exact: false })
|
||||
.setChecked(fullMesh);
|
||||
.getByText("Take part in full mesh", { exact: false })
|
||||
.setChecked(capabilities);
|
||||
if (capabilities)
|
||||
await iframe
|
||||
.getByText("Publish on full mesh", { exact: false })
|
||||
.setChecked(publish);
|
||||
await iframe.getByTestId("modal_close").click();
|
||||
}
|
||||
|
||||
|
||||
@@ -86,6 +86,7 @@ import {
|
||||
cameraFramerate,
|
||||
cameraResolution,
|
||||
customTransport,
|
||||
fullMeshCapabilities,
|
||||
fullMeshPublishing,
|
||||
echoCancellationSetting,
|
||||
matrixRTCMode as matrixRTCModeSetting,
|
||||
@@ -839,9 +840,10 @@ export function rtcParticipationOptions(
|
||||
delegatedDelayedLeave: session.delegated_delayed_leave,
|
||||
},
|
||||
mediaQuality: config.media_quality,
|
||||
transport: fullMeshPublishing.value$.value
|
||||
? { type: FULL_MESH_TRANSPORT_TYPE }
|
||||
: (customTransport.value$.value ?? undefined),
|
||||
transport:
|
||||
fullMeshCapabilities.value$.value && fullMeshPublishing.value$.value
|
||||
? { type: FULL_MESH_TRANSPORT_TYPE }
|
||||
: (customTransport.value$.value ?? undefined),
|
||||
fallbackTransport: config.livekit && {
|
||||
type: "livekit",
|
||||
livekit_service_url: config.livekit.livekit_service_url,
|
||||
|
||||
@@ -9,6 +9,11 @@ Please see LICENSE in the repository root for full details.
|
||||
font-size: var(--font-size-micro);
|
||||
}
|
||||
|
||||
/* An option that depends on the one above it */
|
||||
.subOption {
|
||||
padding-inline-start: var(--cpd-space-8x);
|
||||
}
|
||||
|
||||
.livekit_room_box {
|
||||
border: 3px solid var(--cpd-color-bg-subtle-secondary);
|
||||
border-radius: var(--cpd-space-8x);
|
||||
|
||||
@@ -45,6 +45,7 @@ import {
|
||||
alwaysShowIphoneEarpiece as alwaysShowIphoneEarpieceSetting,
|
||||
matrixRTCMode as matrixRTCModeSetting,
|
||||
customTransport as customTransportSetting,
|
||||
fullMeshCapabilities as fullMeshCapabilitiesSetting,
|
||||
fullMeshPublishing as fullMeshPublishingSetting,
|
||||
advancedScreenShare as advancedScreenShareSetting,
|
||||
screenShareResolution as screenShareResolutionSetting,
|
||||
@@ -177,6 +178,9 @@ export const DeveloperSettingsTab: FC<Props> = ({
|
||||
const [customTransportUpdateError, setCustomTransportUpdateError] = useState<
|
||||
string | null
|
||||
>(null);
|
||||
const [fullMeshCapabilities, setFullMeshCapabilities] = useSetting(
|
||||
fullMeshCapabilitiesSetting,
|
||||
);
|
||||
const [fullMeshPublishing, setFullMeshPublishing] = useSetting(
|
||||
fullMeshPublishingSetting,
|
||||
);
|
||||
@@ -423,10 +427,25 @@ export const DeveloperSettingsTab: FC<Props> = ({
|
||||
/>
|
||||
</FieldRow>
|
||||
<FieldRow>
|
||||
<InputField
|
||||
id="fullMeshCapabilities"
|
||||
type="checkbox"
|
||||
checked={fullMeshCapabilities}
|
||||
label={t("developer_mode.full_mesh_capabilities")}
|
||||
description={t("developer_mode.full_mesh_capabilities_description")}
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>): void => {
|
||||
setFullMeshCapabilities(event.target.checked);
|
||||
// Publishing needs the capabilities
|
||||
if (!event.target.checked) setFullMeshPublishing(false);
|
||||
}}
|
||||
/>
|
||||
</FieldRow>
|
||||
<FieldRow className={styles.subOption}>
|
||||
<InputField
|
||||
id="fullMeshPublishing"
|
||||
type="checkbox"
|
||||
checked={fullMeshPublishing}
|
||||
checked={fullMeshPublishing && fullMeshCapabilities}
|
||||
disabled={!fullMeshCapabilities}
|
||||
label={t("developer_mode.full_mesh_publishing")}
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>): void =>
|
||||
setFullMeshPublishing(event.target.checked)
|
||||
|
||||
@@ -51,6 +51,50 @@ exports[`DeveloperSettingsTab > renders and matches snapshot 1`] = `
|
||||
>
|
||||
<input
|
||||
aria-describedby="_r_2_"
|
||||
id="fullMeshCapabilities"
|
||||
type="checkbox"
|
||||
/>
|
||||
<label
|
||||
for="fullMeshCapabilities"
|
||||
>
|
||||
<div
|
||||
class="_checkbox_1bd8c0"
|
||||
>
|
||||
<svg
|
||||
fill="none"
|
||||
height="24"
|
||||
stroke="#000"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="m20 6-11 11-5-5"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
Take part in full mesh (MSC4575)
|
||||
</label>
|
||||
<p
|
||||
class="_description_1bd8c0"
|
||||
id="_r_2_"
|
||||
>
|
||||
Receive members publishing on full mesh. As a widget, this asks the host for the signalling permissions.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_fieldRow_1bd8c0 _subOption_2ddec4"
|
||||
>
|
||||
<div
|
||||
class="_field_1bd8c0 _checkboxField_1bd8c0 _disabled_1bd8c0"
|
||||
>
|
||||
<input
|
||||
aria-describedby="_r_3_"
|
||||
disabled=""
|
||||
id="fullMeshPublishing"
|
||||
type="checkbox"
|
||||
/>
|
||||
@@ -76,7 +120,7 @@ exports[`DeveloperSettingsTab > renders and matches snapshot 1`] = `
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
Publish on full mesh (MSC4575) instead of LiveKit
|
||||
Publish on full mesh instead of LiveKit
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -87,7 +131,7 @@ exports[`DeveloperSettingsTab > renders and matches snapshot 1`] = `
|
||||
class="_field_1bd8c0 _checkboxField_1bd8c0"
|
||||
>
|
||||
<input
|
||||
aria-describedby="_r_3_"
|
||||
aria-describedby="_r_4_"
|
||||
id="debugTileLayout"
|
||||
type="checkbox"
|
||||
/>
|
||||
@@ -124,7 +168,7 @@ exports[`DeveloperSettingsTab > renders and matches snapshot 1`] = `
|
||||
class="_field_1bd8c0 _checkboxField_1bd8c0"
|
||||
>
|
||||
<input
|
||||
aria-describedby="_r_4_"
|
||||
aria-describedby="_r_5_"
|
||||
id="showConnectionStats"
|
||||
type="checkbox"
|
||||
/>
|
||||
@@ -161,7 +205,7 @@ exports[`DeveloperSettingsTab > renders and matches snapshot 1`] = `
|
||||
class="_field_1bd8c0 _checkboxField_1bd8c0"
|
||||
>
|
||||
<input
|
||||
aria-describedby="_r_5_"
|
||||
aria-describedby="_r_6_"
|
||||
id="muteAllAudio"
|
||||
type="checkbox"
|
||||
/>
|
||||
@@ -199,7 +243,7 @@ exports[`DeveloperSettingsTab > renders and matches snapshot 1`] = `
|
||||
class="_field_1bd8c0 _checkboxField_1bd8c0"
|
||||
>
|
||||
<input
|
||||
aria-describedby="_r_6_"
|
||||
aria-describedby="_r_7_"
|
||||
id="alwaysShowIphoneEarpiece"
|
||||
type="checkbox"
|
||||
/>
|
||||
@@ -236,7 +280,7 @@ exports[`DeveloperSettingsTab > renders and matches snapshot 1`] = `
|
||||
class="_field_1bd8c0 _checkboxField_1bd8c0"
|
||||
>
|
||||
<input
|
||||
aria-describedby="_r_7_"
|
||||
aria-describedby="_r_8_"
|
||||
id="enableLivekitExtendedLogs"
|
||||
type="checkbox"
|
||||
/>
|
||||
@@ -274,7 +318,7 @@ exports[`DeveloperSettingsTab > renders and matches snapshot 1`] = `
|
||||
>
|
||||
<label
|
||||
class="_label_1o4d9_60"
|
||||
for="radix-_r_8_"
|
||||
for="radix-_r_9_"
|
||||
>
|
||||
Custom transport JSON
|
||||
</label>
|
||||
@@ -282,9 +326,9 @@ exports[`DeveloperSettingsTab > renders and matches snapshot 1`] = `
|
||||
class="_controls_17lij_8"
|
||||
>
|
||||
<input
|
||||
aria-describedby="radix-_r_9_"
|
||||
aria-describedby="radix-_r_a_"
|
||||
class="_control_d83jn_10"
|
||||
id="radix-_r_8_"
|
||||
id="radix-_r_9_"
|
||||
name="input"
|
||||
title=""
|
||||
value=""
|
||||
@@ -292,7 +336,7 @@ exports[`DeveloperSettingsTab > renders and matches snapshot 1`] = `
|
||||
</div>
|
||||
<span
|
||||
class="_message_1o4d9_86 _help-message_1o4d9_92"
|
||||
id="radix-_r_9_"
|
||||
id="radix-_r_a_"
|
||||
>
|
||||
Currently, no overwrite is set. Url from config is used.
|
||||
</span>
|
||||
@@ -322,10 +366,10 @@ exports[`DeveloperSettingsTab > renders and matches snapshot 1`] = `
|
||||
class="_container_1ug7n_10"
|
||||
>
|
||||
<input
|
||||
aria-describedby="radix-_r_b_ radix-_r_d_"
|
||||
aria-describedby="radix-_r_c_ radix-_r_e_"
|
||||
checked=""
|
||||
class="_input_1ug7n_18"
|
||||
id="radix-_r_a_"
|
||||
id="radix-_r_b_"
|
||||
name="_r_0_"
|
||||
title=""
|
||||
type="radio"
|
||||
@@ -341,13 +385,13 @@ exports[`DeveloperSettingsTab > renders and matches snapshot 1`] = `
|
||||
>
|
||||
<label
|
||||
class="_label_1o4d9_60"
|
||||
for="radix-_r_a_"
|
||||
for="radix-_r_b_"
|
||||
>
|
||||
Compatibility: state events & multi SFU
|
||||
</label>
|
||||
<span
|
||||
class="_message_1o4d9_86 _help-message_1o4d9_92"
|
||||
id="radix-_r_b_"
|
||||
id="radix-_r_c_"
|
||||
>
|
||||
Compatible with homeservers that do not support sticky events (but all other EC clients are v0.17.0 or later)
|
||||
</span>
|
||||
@@ -363,9 +407,9 @@ exports[`DeveloperSettingsTab > renders and matches snapshot 1`] = `
|
||||
class="_container_1ug7n_10"
|
||||
>
|
||||
<input
|
||||
aria-describedby="radix-_r_b_ radix-_r_d_"
|
||||
aria-describedby="radix-_r_c_ radix-_r_e_"
|
||||
class="_input_1ug7n_18"
|
||||
id="radix-_r_c_"
|
||||
id="radix-_r_d_"
|
||||
name="_r_0_"
|
||||
title=""
|
||||
type="radio"
|
||||
@@ -381,13 +425,13 @@ exports[`DeveloperSettingsTab > renders and matches snapshot 1`] = `
|
||||
>
|
||||
<label
|
||||
class="_label_1o4d9_60"
|
||||
for="radix-_r_c_"
|
||||
for="radix-_r_d_"
|
||||
>
|
||||
Matrix 2.0: sticky events & multi SFU
|
||||
</label>
|
||||
<span
|
||||
class="_message_1o4d9_86 _help-message_1o4d9_92"
|
||||
id="radix-_r_d_"
|
||||
id="radix-_r_e_"
|
||||
>
|
||||
Compatible only with homservers supporting sticky events and all EC clients v0.17.0 or later
|
||||
</span>
|
||||
@@ -452,7 +496,7 @@ exports[`DeveloperSettingsTab > renders and matches snapshot 1`] = `
|
||||
class="_field_1bd8c0 _checkboxField_1bd8c0"
|
||||
>
|
||||
<input
|
||||
aria-describedby="_r_j_"
|
||||
aria-describedby="_r_k_"
|
||||
id="cameraToggle"
|
||||
type="checkbox"
|
||||
/>
|
||||
@@ -482,7 +526,7 @@ exports[`DeveloperSettingsTab > renders and matches snapshot 1`] = `
|
||||
</label>
|
||||
<p
|
||||
class="_description_1bd8c0"
|
||||
id="_r_j_"
|
||||
id="_r_k_"
|
||||
>
|
||||
Configure resolution, framerate, bitrate, and codec for camera video. Changes apply on next call join.
|
||||
</p>
|
||||
@@ -504,7 +548,7 @@ exports[`DeveloperSettingsTab > renders and matches snapshot 1`] = `
|
||||
class="_field_1bd8c0 _checkboxField_1bd8c0"
|
||||
>
|
||||
<input
|
||||
aria-describedby="_r_k_"
|
||||
aria-describedby="_r_l_"
|
||||
id="screenShareToggle"
|
||||
type="checkbox"
|
||||
/>
|
||||
@@ -534,7 +578,7 @@ exports[`DeveloperSettingsTab > renders and matches snapshot 1`] = `
|
||||
</label>
|
||||
<p
|
||||
class="_description_1bd8c0"
|
||||
id="_r_k_"
|
||||
id="_r_l_"
|
||||
>
|
||||
Configure resolution, framerate, bitrate, and codec for screen sharing
|
||||
</p>
|
||||
@@ -559,7 +603,7 @@ exports[`DeveloperSettingsTab > renders and matches snapshot 1`] = `
|
||||
class="_field_1bd8c0 _checkboxField_1bd8c0"
|
||||
>
|
||||
<input
|
||||
aria-describedby="_r_l_"
|
||||
aria-describedby="_r_m_"
|
||||
checked=""
|
||||
id="echoCancellation"
|
||||
type="checkbox"
|
||||
@@ -597,7 +641,7 @@ exports[`DeveloperSettingsTab > renders and matches snapshot 1`] = `
|
||||
class="_field_1bd8c0 _checkboxField_1bd8c0"
|
||||
>
|
||||
<input
|
||||
aria-describedby="_r_m_"
|
||||
aria-describedby="_r_n_"
|
||||
checked=""
|
||||
id="noiseSuppression"
|
||||
type="checkbox"
|
||||
@@ -635,7 +679,7 @@ exports[`DeveloperSettingsTab > renders and matches snapshot 1`] = `
|
||||
class="_field_1bd8c0 _checkboxField_1bd8c0"
|
||||
>
|
||||
<input
|
||||
aria-describedby="_r_n_"
|
||||
aria-describedby="_r_o_"
|
||||
checked=""
|
||||
id="autoGainControl"
|
||||
type="checkbox"
|
||||
|
||||
@@ -168,8 +168,19 @@ export const customTransport = new Setting<UnstableLivekitTransport | null>(
|
||||
);
|
||||
|
||||
/**
|
||||
* Publish on the full mesh transport (MSC4575) instead of LiveKit. Members on
|
||||
* either transport are received whatever this says.
|
||||
* Take part in the full mesh transport (MSC4575): as a widget, ask the host
|
||||
* for the signalling capabilities, so that members publishing on full mesh
|
||||
* are received. Element Web doesn't auto-approve them for Element Call yet
|
||||
* and asks the user whenever the widget opens, hence a setting.
|
||||
*/
|
||||
export const fullMeshCapabilities = new Setting<boolean>(
|
||||
"full-mesh-capabilities",
|
||||
false,
|
||||
);
|
||||
|
||||
/**
|
||||
* Publish on the full mesh transport instead of LiveKit. Only with
|
||||
* `fullMeshCapabilities`: a widget without them couldn't be subscribed to.
|
||||
*/
|
||||
export const fullMeshPublishing = new Setting<boolean>(
|
||||
"full-mesh-publishing",
|
||||
|
||||
+4
-2
@@ -22,7 +22,7 @@ import { LazyEventEmitter } from "./LazyEventEmitter";
|
||||
import { getUrlParams } from "./UrlParams";
|
||||
import { Config } from "./config/Config";
|
||||
import {
|
||||
fullMeshPublishing,
|
||||
fullMeshCapabilities,
|
||||
seedSettingsFromConfig,
|
||||
} from "./settings/settings";
|
||||
import { ElementCallReactionEventType } from "./reactions";
|
||||
@@ -169,7 +169,9 @@ export const initializeWidget = (
|
||||
// Full mesh signalling (MSC4575), only where it is turned on: Element
|
||||
// Web doesn't auto-approve these for Element Call yet, and would ask
|
||||
// the user on every call
|
||||
...(fullMeshPublishing.getValue() ? fullMeshSignallingEventTypes : []),
|
||||
...(fullMeshCapabilities.getValue()
|
||||
? fullMeshSignallingEventTypes
|
||||
: []),
|
||||
];
|
||||
|
||||
const client = createRoomWidgetClient(
|
||||
|
||||
Reference in New Issue
Block a user