Skip to content

feat(audio): 0-150% volume boost + audio output-device picker#67

Merged
DRHATL95 merged 4 commits into
devfrom
feat/audio-boost-output
Jul 6, 2026
Merged

feat(audio): 0-150% volume boost + audio output-device picker#67
DRHATL95 merged 4 commits into
devfrom
feat/audio-boost-output

Conversation

@DRHATL95

@DRHATL95 DRHATL95 commented Jul 6, 2026

Copy link
Copy Markdown
Owner

Audio-first 1.1 backlog #4b. Browser/Windows path (native unchanged).

What

  • Volume boost 0-150% — the slider now exceeds 100% via a Web Audio GainNode. A pure pctToGain helper (unit-tested) maps percent→gain; streamAudio (a graph singleton) is the browser volume authority, with a video.volume fallback so the 0-100% slider is never inert even if the graph can't build. Native path unchanged (its sink already clamps to [0, 2.0], so boost is free there too).
  • Audio output device — a feature-detected picker in Settings → Stream routes the stream's audio to a chosen device via AudioContext.setSinkId (native selectAudioOutput picker, enumerate fallback). The row self-hides where setSinkId is unsupported; boost still works. Isolated in its own commit.

How it was built

Spec → plan → subagent-driven development: fresh implementer per task + two-stage review each, then a whole-branch review (all on the capable tier for the Web Audio task). Plan was hardened up-front by a 13-agent adversarial review (caught the degradation-fallback gap before any code). Whole-branch review found 2 Important items — both fixed (explicit context resume() on focus-swap; audio-only smoke coverage). 9 Minors triaged defer.

Gates: check 0/0 · vitest 381 · build ✓. 4 commits.

Owner smoke (WebView2)

  1. Slider to 150% audibly louder; 100% = old unity.
  2. Mute/unmute; level persists across reconnect + restart.
  3. Immersive toggle mid-stream doesn't drop/spike audio.
  4. Output picker lists real device names; switching moves audio live; persists across restart.
  5. On a WebView2 without setSinkId, the row is absent + boost still works.
  6. Audio-only mode: boost audible + output-switch works (the audio-first path).

🤖 Generated with Claude Code

DRHATL95 and others added 4 commits July 5, 2026 20:09
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Route the browser <video> audio through AudioContext→MediaElementSource→Gain so
the slider can exceed 100%. GainNode is the sole browser volume authority; the
context resumes on the play/unmute gesture. Native path unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Route stream audio to a chosen output via AudioContext.setSinkId; pick with the
native selectAudioOutput() picker (enumerate fallback). Row self-hides where
setSinkId is unsupported. Isolated + revertable without the boost.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Immersive toggle swaps the <video> element; attach() re-taps the new
element but the context wasn't explicitly resumed on the new graph. Resume
after re-attach so audio never waits on autoplay luck.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@DRHATL95 DRHATL95 merged commit 2fadadb into dev Jul 6, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant