[docs] Document AetherSDR audio pipeline#2571
Conversation
There was a problem hiding this comment.
Thanks for this — really thorough docs, and a useful contributor reference for the audio code. Spot-checked the concrete claims against the source and they hold up:
Resampler::processStereoToStereo()does average L/R and duplicate (src/core/Resampler.cpp:127).- PCC codes
0x03E3/0x0123/0x8005matchsrc/core/PanadapterStream.h:126-128. - Default TX chain
Gate → EQ → DeEss → Comp → Tube → Enh (PUDU) → ReverbmatchesdefaultChain()insrc/core/AudioEngine.cpp:1771. - Final limiter ceiling default
-1.0 dBFSmatchessrc/core/ClientFinalLimiter.h:86. - Opus 24 kHz / 10 ms / 240 frames matches
src/core/OpusCodec.h:48-51. m_rxBufferCapMsdefault 200, clamped 50..1000, matchessrc/core/AudioEngine.h:114,599.- RADE TX
24→16 kHz mono → encode → 8→24 kHz stereoand RX24→8 kHz mono → decode → 16→24 kHz stereomatchsrc/core/RADEEngine.cpp:59-62,142,191,212,276. - The note that
applyClientRxDspFloat32()is currently a dispatcher stub matches the TODO bodies insrc/core/AudioEngine.cpp:1688-1701; the live RX strip is indeed inlined inwriteAudio().
A few small notes (suggestions, not blockers):
- The PR body and
audio-pipeline.mdExecutive Summary explicitly call out three current edge cases (one-sided stereo(L+R)/2loss inprocessStereoToStereo(), left-channel-only PC mic meter, DAX radio-native one-sided loss). These are real and worth tracking — consider opening a follow-up issue so they don't get lost in the docs. tx-audio-signal-path.mdrenames "PooDoo™ Audio" to "AetherialAudio" — please double-check that's the canonical user-facing name in current GUI strings; if the menu/tab still reads "PooDoo" anywhere, the doc rename will read inconsistently.- Minor: "RADE TX/RX branch points" wording in the architecture-pipelines.md ASCII diagram is slightly cramped — readable, but a future pass could split the RADE/DAX boxes onto separate sub-flows for clarity. Not worth churning this PR.
Docs-only, no risk to runtime behavior, and the path/stage table at the bottom is going to save a lot of code-spelunking on future audio changes. Nice work.
ten9876
left a comment
There was a problem hiding this comment.
Claude here, reviewing on Jeremy's behalf.
Verdict
Strong merge. This is a genuinely useful piece of reference documentation that the project has been missing — comprehensive enough that future contributors won't have to grep four files to understand where audio averages, where it duplicates, and where it stays stereo. The path/stage table and the downmix/format-change table are the most valuable artifacts.
Disclosure: AI-generated via OpenAI Codex GPT-5.5 Pro, reviewed and tested by @jensenpat. I spot-checked four of the load-bearing technical claims against the actual code:
| Claim | Verification |
|---|---|
Resampler::processStereoToStereo() averages L/R then duplicates |
✓ Resampler.cpp:127 does (stereoIn[2*i] + stereoIn[2*i+1]) * 0.5; lines 138-139 duplicate single output to both channels |
AudioEngine::resampleStereo() uses separate L/R resamplers to preserve pan |
✓ AudioEngine.cpp:903-906 instantiates two Resamplers; 919-920 processes L and R independently; existing source comment at line 900 explicitly warns about the trap |
DAX radio-native TX averages (L+R)/2 for stereo→Int16 mono conversion |
✓ AudioEngine.cpp:4152 does exactly this |
| PC mic voice meter reads left channel only | ✓ AudioEngine.cpp:3656 uses i += 2 stride over interleaved Int16 stereo |
All four match the doc verbatim. The three "current known behavior" bullets at the top (one-sided stereo 6.02 dB loss, left-channel-only PC mic meter, DAX radio-native L+R averaging) are real bugs documented honestly rather than papered over — exactly the disclosure pattern reference docs should set.
What this adds that didn't exist
- Comprehensive path/stage table — file/function, input format, output format, sample rate, channel handling, side effects, in one place
- Downmix/duplication/resampling/format-change table — every stereo↔mono transition in the audio code annotated with which helper does the work
- Meter tap table — pre/post stage, channel policy, units for every local and radio-side meter
- Mermaid diagrams for each path — RX speaker, PC mic voice TX, RADE TX/RX, DAX TX routing — that any contributor can read without opening a debugger
The diffs to architecture-pipelines.md and tx-audio-signal-path.md correctly link out to the new doc and trim down stale summaries. The PooDoo™ → AetherialAudio rename in tx-audio-signal-path.md matches the current code (the AetherialAudioStrip class, the v0.9.6 unification, and the v26.5.1 CHANGELOG framing). Good consistency pass.
Follow-up worth filing as separate issues
The doc surfaces three current bugs as "known behavior." Each deserves its own GitHub issue so they get tracked rather than living only in the doc:
- Stereo mic 6.02 dB loss in
Resampler::processStereoToStereo()— one-sided stereo input loses 6.02 dB when averaged with a silent channel. Affects PC mic capture path at non-24kHz rates. - PC mic voice meter left-channel-only read —
AudioEngine.cpp:3656i += 2stride. A right-only mic device shows silent or incorrect levels. - DAX radio-native TX 6.02 dB loss —
AudioEngine.cpp:4152averages stereo to mono with the same one-sided-stereo penalty.
These are independent fixes; the doc doesn't need to wait on them.
Minor
- The doc is 618 lines of new content. The auxiliary tables are the most valuable bit — recommend they stay current as the audio code evolves. Worth a CI hook eventually that flags PRs touching
src/core/AudioEngine.cpporsrc/core/Resampler.cppfor a "did you updatedocs/audio-pipeline.md?" reviewer prompt. Not in this PR's scope, just a thought. - The TCI / VirtualAudioBridge / PipeWireAudioBridge sections look accurate by class-name spot-check, but I didn't trace every code path inside them. If something there is subtly wrong, the table format makes it easy to fix in a follow-up.
CI
buildSUCCESScheck-pathsSUCCESScheck-windowsSKIPPED (correct — docs-only)- No
analyze (cpp)since no source files changed - CodeQL skipped (correct per the doc-only PR optimization landed in #2397)
Recommendation
Merge. Then file follow-up issues for the three documented bugs so they're in the tracker as actionable work, not just doc footnotes.
Thanks @jensenpat — the diagnostic discipline applied to documentation (tracing every L/R collapse, every resample boundary, every meter tap) is the same care you bring to fix PRs. The contributor notes at the end ("Treat Resampler::processStereoToStereo() as a mono-collapse helper") are the kind of "future-self warning" that prevents repeat mistakes.
73, Jeremy KK7GWY & Claude (AI dev partner)
ten9876
left a comment
There was a problem hiding this comment.
Approved — docs accurately reflect code, three documented bugs are real and now tracked separately.
Resolves add/add conflict in docs/audio-pipeline.md introduced when aethersdr#2571 squash-merged to main while this PR was open. Both branches added the file independently; this PR's version contains the post-fix description ("canonical mono voice signal using Auto Left/Right/Average") which supersedes aethersdr#2571's pre-fix description that was correct at the time it was written. Conflict resolved by taking the PR branch's content. Verified: - 0 conflict markers remain - post-fix "canonical mono voice signal" passage preserved (2 occurrences) - pre-fix "averages L/R and then duplicates the result" language removed
Summary
This PR adds a new
docs/audio-pipeline.mdsource-of-truth for AetherSDR audio routing and updates the existing architecture/TX docs to point at it instead of carrying stale summaries.The new document traces:
PanadapterStreamdecode through RX NR, client RX DSP, resampling, gain/trim, metering, scopes, buffering, and speaker writesremote_audio_tx24 kHz stereo Int16 framing, 10 ms packet cadence, PCC0x8005, and pacing queue behavior0x03E3/0x0123packet formatsIt also explicitly documents current edge cases:
Resampler::processStereoToStereo()averages L/R with a silent channel.(L+R)/2, so one-sided stereo DAX/TCI input can lose 6.02 dB there too.Docs Updated
docs/audio-pipeline.mddocs/architecture-pipelines.mdto make the TX/DAX/RADE routing summary match the current code and link to the new audio pipeline docdocs/tx-audio-signal-path.mdto clarify that the AetherialAudio voice strip applies to PC mic voice TX, while DAX/TCI and RADE bypass that voice chainValidation
git diff --checkNo app build was run because this is a documentation-only change.
👨🏼💻 Generated with OpenAI Codex (GPT-5.5 Pro 4/23) and tested by @jensenpat