"Mute Screenshare Audio" (io.lotus.set_deafen screenshareAudioMuted) used RemoteParticipant.setVolume(0, ScreenShareAudio). EC's own createVolumeControls writes volume 1 through the same setter the moment a new screenshare media item resolves, so when the sharer stopped and re-shared (or a late joiner shared) the audio came back at full volume while the host button still said "Unmute Screenshare Audio". Reproduced on the local calls stack with two headless clients: after a re-share the screen_share_audio element read vol=1. Now the flag is a global behavior (muteScreenshareAudio$) that LivekitRoomAudioRenderer turns into the `muted` prop of every Track.Source.ScreenShareAudio element — the exact mechanism deafen already uses (pub.setEnabled(false): the server stops sending). Verified via the RemoteTrackPublication behind each <audio>: the re-published track (new sid) mounts with enabled=false while muted and re-enables on unmute; deafen + undeafen leaves it muted; teardown resets the flag so the next call starts clean. Unit tests updated; renderer test asserts only ScreenShareAudio elements get muted by the new prop. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
28 lines
1.1 KiB
TypeScript
28 lines
1.1 KiB
TypeScript
/*
|
|
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";
|
|
|
|
/**
|
|
* 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$,
|
|
);
|