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:
Lotus CI
2026-09-18 23:54:25 -04:00
co-authored by Claude Opus 5
parent bc0e5ed432
commit ea579cb998
6 changed files with 149 additions and 118 deletions
+12 -1
View File
@@ -38,6 +38,12 @@ export interface MatrixAudioRendererProps {
* If set to `true`, the server will stop sending audio track data to the client.
*/
muted?: boolean;
/**
* [lotus] If set to `true`, mutes only the `Track.Source.ScreenShareAudio`
* tracks (the host's "Mute Screenshare Audio" control) — same mechanism as
* `muted`, so it holds across re-renders and later-published shares.
*/
screenshareAudioMuted?: boolean;
}
/**
@@ -58,6 +64,7 @@ export function LivekitRoomAudioRenderer({
livekitRoom,
validIdentities,
muted,
screenshareAudioMuted,
}: MatrixAudioRendererProps): ReactNode {
const logger = rootLogger.getChild("[MatrixAudioRenderer]");
const tracks = useTracks(
@@ -143,7 +150,11 @@ export function LivekitRoomAudioRenderer({
<AudioTrackWithAudioNodes
key={getTrackReferenceId(trackRef)}
trackRef={trackRef}
muted={muted}
muted={
muted ||
(screenshareAudioMuted &&
trackRef.publication.source === Track.Source.ScreenShareAudio)
}
audioContext={shouldUseAudioContext ? audioContext : undefined}
audioNodes={audioNodes}
/>