feat(audio): renderer-bus feeder — song audio into engine output under exclusive mode (Phase 2)#828
Conversation
Song playback runs through the renderer, which WASAPI-exclusive (and ASIO) output silences. Route single-mix feedpaks (stem-less original_audio packs AND single-stem packs) onto the engine's backing transport when the output device type is exclusive-style, and migrate back to HTML5 when it isn't. Extends /api/audio-local-path to resolve /api/sloppak/.../file/... URLs via the same containment guards as serve_sloppak_file. Multi-stem packs stay on the WebAudio path (Phase 2). Includes [feedpak-route] transition-gated diagnostics logging. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e output (Phase 2) Under exclusive-style output the native backing transport (Phase 1, #824) carries loose /audio/ songs and feedpak full-mixes, but not the stems plugin's multi-stem WebAudio graph or tracks JUCE rejected. The feeder taps the renderer-side master with an AudioWorklet, re-points the owning AudioContext at a null sink so it keeps rendering without a device, and pushes ~10 ms chunks over IPC into the desktop engine's renderer bus (feedBack-desktop#90 follow-up). Inert in the Docker sphere and in shared mode. Validated by the fix12 tester spike: null-sink rendering works, clocks hold, no overflow. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
📝 WalkthroughWalkthroughAdds a renderer-side audio bus feeder in static/app.js that taps stems or core audio element output via AudioWorklet/AudioContext, redirects audio to a null sink in exclusive output modes, and pushes PCM chunks to the desktop engine bus. Includes a corresponding test suite validating engagement/disengagement behavior. ChangesRenderer Bus Feeder
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
|
Reviewed — ship-ready, one retarget. The Before merge: retarget to Minor (optional): the tap worklet |
|
Retargeted to On the worklet nit (inactive tap still posting ~375×/s while |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@static/app.js`:
- Around line 5455-5457: The reevaluate failure path in the renderer bus should
restore the sink state before forcing `_mode = 'off'`, because `_setSink(ctx,
true)` may already have disengaged the context and left `_disengage()` unable to
clean up on the next pass. Update the `catch` block in the reevaluation flow to
explicitly clean up/reset the sink or bus using the existing helpers around
`_setSink` and `_disengage` before changing `_mode`, so the context does not
remain stuck on `{type:'none'}` after a failed `reevaluate`.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 7a8e53d0-19bf-4d32-a50c-f6455019a900
📒 Files selected for processing (2)
static/app.jstests/js/renderer_bus_feeder.test.js
| } catch (e) { | ||
| console.warn('[renderer-bus] reevaluate failed (will retry):', e); | ||
| _mode = 'off'; |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file=static/app.js
wc -l "$file"
echo '--- around _disengage / mode logic ---'
rg -n "_disengage|_setSink|_mode|reevaluate failed|want === 'off'|type:'none'|type: 'none'" "$file" | head -n 80
echo '--- lines 5360-5485 ---'
sed -n '5360,5485p' "$file"Repository: got-feedBack/feedBack
Length of output: 6764
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '5368,5475p' static/app.jsRepository: got-feedBack/feedBack
Length of output: 4973
Restore the sink when reevaluate fails. If _setSink(ctx, true) already ran, clearing _mode here leaves _disengage() with nothing to do on the next pass, so the context can stay on {type:'none'} and audio remains muted until a successful re-engage. Clean up the sink/bus before setting _mode = 'off'.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@static/app.js` around lines 5455 - 5457, The reevaluate failure path in the
renderer bus should restore the sink state before forcing `_mode = 'off'`,
because `_setSink(ctx, true)` may already have disengaged the context and left
`_disengage()` unable to clean up on the next pass. Update the `catch` block in
the reevaluation flow to explicitly clean up/reset the sink or bus using the
existing helpers around `_setSink` and `_disengage` before changing `_mode`, so
the context does not remain stuck on `{type:'none'}` after a failed
`reevaluate`.
Stacked on #824 (Phase 1) — merge that first; this PR then reduces to one commit.
Under exclusive-style output the Phase 1 native transport carries loose
/audio/songs and feedpak full-mixes, but not the stems plugin's multi-stem WebAudio graph or tracks JUCE hard-rejected. This adds_installRendererBusFeedertostatic/app.js:audioGraph, or the core<audio>element as fallback) with an AudioWorklet tap.setSinkId({type:'none'})) so the graph keeps rendering while the device is exclusive-locked — analysers/visualizations stay live.feat/renderer-bus-phase2), mixed like a backing track (~10–20 ms added latency on song audio only; guitar path untouched).window._juceOutputIsExclusivepredicate; inert in the Docker sphere and in shared mode (no double audio — covered by tests).Validated by the fix12 tester spike (null-sink rendering works, clocks hold, drift → 0, zero overflow over 8 min) and shipped end-to-end in the fix13 tester build.
Companion PRs: feedBack-desktop
feat/renderer-bus-phase2(engine-side bus), feedBack-plugin-stemsfeat/publish-audio-graph(graph publication).Tests: 7 new sandbox tests (
tests/js/renderer_bus_feeder.test.js); full JS suite 955/955; #824's python suite 19/19 on the merged result.🤖 Generated with Claude Code
Summary by CodeRabbit