/* Copyright 2026 Lotus Guild SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial Please see LICENSE in the repository root for full details. */ import { BehaviorSubject } from "rxjs"; import { globalScope } from "../state/ObservableScope"; import { LotusWidgetActions } from "./lotusActions"; import { lotusSendToHost } from "./lotusWidget"; /** * Whether the host has muted remote screenshare AUDIO (`io.lotus.set_deafen` * `screenshareAudioMuted`). Consumed by `LivekitRoomAudioRenderer` exactly the * way `muteAllAudio$` is: it becomes the `muted` prop of every * `Track.Source.ScreenShareAudio` element, so it survives re-renders, applies * to tracks that are published LATER (a sharer stopping and re-sharing, a late * joiner) and never fights EC's per-tile volume controls — which was the * failure mode of the old `RemoteParticipant.setVolume(0, ScreenShareAudio)` * approach: `createVolumeControls` writes its own volume (1) through the same * sink the moment a new screenshare media item appears, un-muting it. */ export const setScreenshareAudioMuted$ = new BehaviorSubject(false); export const muteScreenshareAudio$ = globalScope.behavior( setScreenshareAudioMuted$, ); /** * [cinny #277] Whether any remote participant's screenshare AUDIO is being * received, so the host shows its "Mute Screenshare Audio" control only when * there is something to mute. Each `LivekitRoomAudioRenderer` (one per SFU) * reports for its own room; the host gets `io.lotus.screenshare_audio_state * { present }` whenever the combined answer changes. */ const presentByRoom = new Map(); let lastSent: boolean | undefined; function sendIfChanged(): void { const present = [...presentByRoom.values()].some(Boolean); if (present === lastSent) return; lastSent = present; lotusSendToHost(LotusWidgetActions.ScreenshareAudioState, { present }); } export function reportScreenshareAudio( roomKey: string, present: boolean, ): void { presentByRoom.set(roomKey, present); sendIfChanged(); } /** The renderer for `roomKey` went away (call left, SFU switched). */ export function clearScreenshareAudio(roomKey: string): void { presentByRoom.delete(roomKey); sendIfChanged(); } /** Test-only: forget all reports. */ export function resetScreenshareAudioPresence(): void { presentByRoom.clear(); lastSent = undefined; }