hydra

Terminal replacement for Loopback — virtual audio devices and routing on macOS, from a ratatui TUI.
Log | Files | Refs | README | LICENSE

commit 0e5db1afa327fa25d057474b3232294f392525e5
parent 6f8b8c69d4f0a6a651b8a755b690151c91582c3b
Author: Matthew Gantenbein <ganten1998@gmail.com>
Date:   Mon,  1 Jun 2026 15:08:05 -0500

docs: diagnostics/README — layer-by-layer audio debugging method

Captures the methodology from the one-ear-in-Discord investigation: measure
each layer (tap → device output → device properties → browser capture → SDP →
Discord DSP → receiver) in order instead of guessing at the device. Notes the
key mistakes: identical-L/R test tones can't detect mono collapse (use distinct
L/R), and the listener's own playback is the easiest variable to forget.

Issue resolved (stereo works); can't attribute to a single change among the
44.1k driver default, a headphone swap, and a voice rejoin. Hydra measured
correct throughout.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Diffstat:
Adiagnostics/README.md | 46++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+), 0 deletions(-)

diff --git a/diagnostics/README.md b/diagnostics/README.md @@ -0,0 +1,46 @@ +# Hydra diagnostics + +Tools for diagnosing audio-path problems — built while chasing a "one ear in Discord" bug +that turned out to be **downstream of Hydra entirely**. The lesson they encode: when audio +"sounds wrong," measure each layer in order rather than guessing at the device. + +## The layers, and how to measure each + +1. **Tap capture** (does Hydra capture the app at all, balanced?) — route an app via the TUI + and watch the route's peak in `hydra query`. A balanced source should give equal L/R. +2. **Hydra device output** (does the virtual device emit true stereo?) — record Hydra's + *input* with ffmpeg and check per-channel frequency content: + ```sh + ffmpeg -f avfoundation -i ":0" -t 2 -y /tmp/out.wav # ":0" = Hydra (check -list_devices) + # feed a hard-panned source (300Hz L / 900Hz R) and confirm L≠R in the recording + ``` + IMPORTANT: test with a **distinct-L/R** source, not an identical-L/R tone — an identical + tone plays in both ears even if a channel is being dropped, so it can't detect mono + collapse. (This was a real mistake during the original investigation.) +3. **Device properties** (`devdiff.m`) — dump format / channel-layout / labels for every + input device, to A/B Hydra against a known-good device (e.g. Loopback): + ```sh + clang -framework CoreAudio -framework CoreFoundation devdiff.m -o /tmp/devdiff && /tmp/devdiff + ``` + This is what found Hydra was defaulting to 48000 Hz while the host ran at 44100 — the one + device-level difference from the working Loopback mic. +4. **Browser capture** (`hydra_mic_probe.js`) — paste into Vesktop DevTools console; reports + what Chromium's WebRTC capture actually sees (track settings + per-channel peaks). Confirms + whether the browser receives stereo from the device. +5. **SDP / Opus** — read StereoMic's own console logs (no pasting needed): + `[StereoMic] munged setLocalDescription` AND `munged setRemoteDescription` both firing = + Opus is advertising stereo on offer + answer. If only local fires, the answer-munge didn't + apply (a StereoMic-side issue, not Hydra). +6. **Discord audio processing** — Echo Cancellation / Noise Suppression(Krisp) / Auto Gain + are mono-only; any one enabled collapses capture to mono regardless of device. Turn all + off in Vesktop → Voice & Video. +7. **The receiver** — the easiest variable to forget. Verify the *listener's* playback is + actually stereo (headphones on a second device joined to the same channel) before + concluding the transmit path is broken. Unknown/mono speakers on the far end mimic every + send-side bug. + +## Hard-won rule + +Hydra measured correct at every layer (44.1k, clean [L,R] labels, true stereo to the +browser, both channels captured). Most "Hydra is broken" symptoms live in layers 5–7. Build +the measurement before changing the device.