mirror of
https://github.com/vector-im/element-call.git
synced 2026-06-30 18:02:56 +00:00
quick experimental kiosk mode which hides local tiles.
src/UrlParams.ts — added hideLocalTiles: boolean to UrlConfiguration, parsed it via parser.getFlag(hideLocalTiles), and defaulted it to false in both the SPA fallback and the widget intent preset. src/state/CallViewModel/CallViewModel.ts — in the userMedia$ generator: - Added a module-level PUBLISH_SUFFIX = +publish constant. - Added base-device-ID and +publish-twin helpers. - Always: when a +publish membership exists for (userId, baseDeviceId), the non-suffixed sibling is dropped (it would just be an empty receive-only tile). - When hideLocalTiles is set: every membership whose (userId, baseDeviceId) matches the local user/device is dropped — covering both the local camera tile and any +publish twin from this device.
This commit is contained in:
@@ -179,6 +179,14 @@ export interface UrlConfiguration {
|
||||
* Whether to hide the screen-sharing button.
|
||||
*/
|
||||
hideScreensharing: boolean;
|
||||
/**
|
||||
* Whether to hide tiles representing the local device. This includes the
|
||||
* local camera tile and any other MatrixRTC memberships originating from
|
||||
* the same device (e.g. a `+publish` twin used to publish media). Useful
|
||||
* for kiosk-style embeddings where the embedder does not want the local
|
||||
* user to see themselves.
|
||||
*/
|
||||
hideLocalTiles: boolean;
|
||||
|
||||
/**
|
||||
* Whether the app is allowed to use fallback STUN servers for ICE in case the
|
||||
@@ -369,6 +377,7 @@ export const computeUrlParams = (search = "", hash = ""): UrlParams => {
|
||||
header: platform === "desktop" ? HeaderStyle.None : HeaderStyle.AppBar,
|
||||
showControls: true,
|
||||
hideScreensharing: false,
|
||||
hideLocalTiles: false,
|
||||
allowIceFallback: true,
|
||||
perParticipantE2EE: true,
|
||||
controlledAudioDevices: platform === "desktop" ? false : true,
|
||||
@@ -424,6 +433,7 @@ export const computeUrlParams = (search = "", hash = ""): UrlParams => {
|
||||
header: HeaderStyle.Standard,
|
||||
showControls: true,
|
||||
hideScreensharing: false,
|
||||
hideLocalTiles: false,
|
||||
allowIceFallback: false,
|
||||
perParticipantE2EE: false,
|
||||
controlledAudioDevices: false,
|
||||
@@ -470,6 +480,7 @@ export const computeUrlParams = (search = "", hash = ""): UrlParams => {
|
||||
header: parser.getEnumParam("header", HeaderStyle),
|
||||
showControls: parser.getFlag("showControls"),
|
||||
hideScreensharing: parser.getFlag("hideScreensharing"),
|
||||
hideLocalTiles: parser.getFlag("hideLocalTiles"),
|
||||
allowIceFallback: parser.getFlag("allowIceFallback"),
|
||||
perParticipantE2EE: parser.getFlag("perParticipantE2EE"),
|
||||
controlledAudioDevices: parser.getFlag("controlledAudioDevices"),
|
||||
|
||||
@@ -197,6 +197,11 @@ const smallMobileCallThreshold = 3;
|
||||
// with the interface
|
||||
const showFooterMs = 4000;
|
||||
|
||||
// Suffix used by MatrixRTC members who participate twice from the same
|
||||
// physical device — once with the bare device ID (typically receive-only)
|
||||
// and once with this suffix appended (the publishing twin).
|
||||
const PUBLISH_SUFFIX = "+publish";
|
||||
|
||||
export type GridMode = "grid" | "spotlight";
|
||||
|
||||
export type WindowMode = "normal" | "narrow" | "flat" | "pip";
|
||||
@@ -704,6 +709,18 @@ export function createCallViewModel$(
|
||||
]) {
|
||||
const computeMediaId = (m: MatrixLivekitMember): string =>
|
||||
`${m.userId}:${m.membership$.value.deviceId}`;
|
||||
// A member may participate twice from the same physical device by
|
||||
// suffixing their device ID with "+publish" — one membership for
|
||||
// receiving and one for publishing media. We treat both as the same
|
||||
// logical device for de-duplication and local-tile filtering.
|
||||
const baseDeviceId = (deviceId: string): string =>
|
||||
deviceId.endsWith(PUBLISH_SUFFIX)
|
||||
? deviceId.slice(0, -PUBLISH_SUFFIX.length)
|
||||
: deviceId;
|
||||
const isPublishTwin = (m: MatrixLivekitMember): boolean =>
|
||||
m.membership$.value.deviceId.endsWith(PUBLISH_SUFFIX);
|
||||
const computeBaseId = (m: MatrixLivekitMember): string =>
|
||||
`${m.userId}:${baseDeviceId(m.membership$.value.deviceId)}`;
|
||||
|
||||
const localUserMediaId = localMatrixLivekitMember
|
||||
? computeMediaId(localMatrixLivekitMember)
|
||||
@@ -715,10 +732,28 @@ export function createCallViewModel$(
|
||||
const remoteWithoutLocal = matrixLivekitMembers.value.filter(
|
||||
(m) => computeMediaId(m) !== localUserMediaId,
|
||||
);
|
||||
const allMatrixLivekitMembers = [
|
||||
...localAsArray,
|
||||
...remoteWithoutLocal,
|
||||
];
|
||||
const candidates = [...localAsArray, ...remoteWithoutLocal];
|
||||
|
||||
// For any (user, device) that has a +publish membership, hide its
|
||||
// non-suffixed sibling — the publishing twin is the one carrying
|
||||
// the media, so the receive-only twin's tile would just be empty.
|
||||
const publishTwinBaseIds = new Set(
|
||||
candidates.filter(isPublishTwin).map(computeBaseId),
|
||||
);
|
||||
|
||||
const { hideLocalTiles } = getUrlParams();
|
||||
const localBaseId = `${userId}:${deviceId}`;
|
||||
|
||||
const allMatrixLivekitMembers = candidates.filter((m) => {
|
||||
// Hide all tiles originating from the local device, including
|
||||
// the +publish twin.
|
||||
if (hideLocalTiles && computeBaseId(m) === localBaseId)
|
||||
return false;
|
||||
// Drop the receive-only sibling when a +publish twin is present.
|
||||
if (!isPublishTwin(m) && publishTwinBaseIds.has(computeBaseId(m)))
|
||||
return false;
|
||||
return true;
|
||||
});
|
||||
|
||||
for (const matrixLivekitMember of allMatrixLivekitMembers) {
|
||||
const { userId, participant, connection$, membership$ } =
|
||||
|
||||
Reference in New Issue
Block a user