From ec2da91460b4a0e1fbd7eaad44f5b12cd24ffa2e Mon Sep 17 00:00:00 2001 From: Eli Mallon Date: Tue, 13 Oct 2026 09:25:37 -0700 Subject: [PATCH] Stems follow the video's play/pause; list only stems WebRTC sends Stem audio elements now pause and resume with the video. The menu lists at most two stem groups that have an Opus encode, matching the tracks the node sends, so levels apply to the right stem. The e2e checks the stem element actually plays and follows pause. --- .../src/components/mobile-player/video.tsx | 50 ++++++++++++++++--- js/core/src/lib/audio-stems.test.ts | 41 +++++++++++++++ js/core/src/lib/audio-stems.ts | 14 ++++-- js/e2e-web/flows/audio-stems.spec.ts | 19 +++++++ 4 files changed, 111 insertions(+), 13 deletions(-) diff --git a/js/components/src/components/mobile-player/video.tsx b/js/components/src/components/mobile-player/video.tsx index a5c38c9fa..d209e2b19 100644 --- a/js/components/src/components/mobile-player/video.tsx +++ b/js/components/src/components/mobile-player/video.tsx @@ -642,6 +642,14 @@ export function WebRTCPlayerInner({ const [mediaStream, stuck, audioTracks] = useWebRTC(src, selectedRendition); const levels = useAudioTrackLevels(); + const playbackVideoRef = useRef(null); + const setPlaybackVideoRef = useCallback( + (element: HTMLVideoElement | null) => { + playbackVideoRef.current = element; + assignVideoRef(videoRef, element); + }, + [videoRef], + ); const [fullMix, ...stems] = audioTracks; // The video element gets the video and the full mix; each stem the viewer @@ -717,10 +725,9 @@ export function WebRTCPlayerInner({ }, [mediaStream]); useEffect(() => { - if (!videoRef || !videoRef.current) { - return; + if (playbackVideoRef.current) { + playbackVideoRef.current.srcObject = videoStream; } - videoRef.current.srcObject = videoStream; }, [videoStream]); if (!mediaStream) { @@ -754,12 +761,17 @@ export function WebRTCPlayerInner({ } return ( <> - + {stems.map( (track, i) => track && levels[i + 1] > 0 && ( - + ), )} @@ -770,9 +782,11 @@ export function WebRTCPlayerInner({ function StemAudio({ track, level, + videoRef, }: { track: MediaStreamTrack; level: number; + videoRef: React.RefObject; }) { const ref = useRef(null); const volume = useVolume(); @@ -790,9 +804,29 @@ function StemAudio({ } }, [volume, level]); - return ( -