From 8ae848e45609b348e2fdcfb896010c4e3d61c8b9 Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Sat, 3 Oct 2026 10:30:05 +0200 Subject: fix(client): the local player is silent while casting It keeps playing to pace the relay, so it doubled the television's sound. The viewer's mute setting comes back when the cast ends. Co-Authored-By: Claude Opus 5.5 --- .../meshbay-hub/src/meshbay_hub/static/video-player.js | 18 ++++++++++++++++++ packages/meshbay-hub/tests/test_cast_discovery.py | 15 +++++++++++++++ 2 files changed, 33 insertions(+) (limited to 'packages/meshbay-hub') diff --git a/packages/meshbay-hub/src/meshbay_hub/static/video-player.js b/packages/meshbay-hub/src/meshbay_hub/static/video-player.js index 4fa652b..243e0c2 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/video-player.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/video-player.js @@ -1471,6 +1471,24 @@ function VideoPlayer({ entry, transportRef, gekRef, onClose, onDownload }) { // The scan lives as long as the picker is open: closing it, or picking a // receiver, stops the updates. Receivers are listed as they answer, and the // spinner sits below them so one landing never moves the row being aimed at. + // While casting, the film plays on the receiver; the local element keeps + // playing — its playhead is what paces the stream the relay forwards — but + // silently. It went on with its sound, so a phone in the room doubled the + // television's audio, screen off included. What the viewer had set comes + // back when the cast ends. + const mutedBeforeCastRef = useRef(null); + useEffect(() => { + const v = videoRef.current; + if (!v) return; + if (castActive) { + if (mutedBeforeCastRef.current === null) mutedBeforeCastRef.current = v.muted; + v.muted = true; + } else if (mutedBeforeCastRef.current !== null) { + v.muted = mutedBeforeCastRef.current; + mutedBeforeCastRef.current = null; + } + }, [castActive]); + useEffect(() => { if (!castPickerOpen) return undefined; setCastDevices([]); diff --git a/packages/meshbay-hub/tests/test_cast_discovery.py b/packages/meshbay-hub/tests/test_cast_discovery.py index 9e9ce85..77b0ef6 100644 --- a/packages/meshbay-hub/tests/test_cast_discovery.py +++ b/packages/meshbay-hub/tests/test_cast_discovery.py @@ -106,3 +106,18 @@ def test_a_new_scan_is_not_cut_short_by_the_one_it_replaced(run): assert run["restartedStillScanning"] is True assert run["restartClearedOldDevices"] is True assert run["restartedEnds"] is True + + +def test_the_local_player_is_silent_while_casting(): + """The local element keeps playing while casting — its playhead paces the + stream the relay forwards — so it must not keep its sound: a phone in the + room doubled the television's audio, screen off included. Whatever the + viewer had set comes back when the cast ends.""" + from spa_source import STATIC + player = (STATIC / "video-player.js").read_text(encoding="utf-8") + effect = player.split("const mutedBeforeCastRef = useRef(null);", 1)[1] + effect = effect.split("}, [castActive]);", 1)[0] + assert "v.muted = true;" in effect + assert "mutedBeforeCastRef.current = v.muted;" in effect + assert "v.muted = mutedBeforeCastRef.current;" in effect + assert "pause()" not in effect, "pausing would stop the stream the receiver is playing" -- cgit v1.2.3