fix(lotus): screenshare-audio mute survives a re-share — mute via the renderer, not setVolume
"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
This commit is contained in:
co-authored by
Claude Opus 5
parent
bc0e5ed432
commit
ea579cb998
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
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$,
|
||||
);
|
||||
Reference in New Issue
Block a user