[logging] Add default audio summary logging (devices/sinks/resampler)#2973
Conversation
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
There was a problem hiding this comment.
Thanks @jensenpat — this is a thoughtful piece of work. The "no extra probing at startup" safety boundary (shallow buildAudioStartupSnapshot vs the probe-heavy buildAudioDevicesSnapshot) is well-drawn and explicitly motivated. Dedupe-by-canonical-text keeps no-op restarts quiet without losing real route changes. Categorising every open path (RX/TX/CW/Quindar/Aetherial + a single failure summary on each path) hits exactly the support-bundle gap described.
A few small observations:
1. Out-of-scope behaviour change in the Windows RX path. src/core/AudioEngine.cpp line ~968 now calls m_rxBufferSampleRate.store(fmt.sampleRate()) on the Windows #ifdef Q_OS_WIN branch before startSidetoneStream(). Previously this store happened only on the non-Windows path after the #endif, so the Windows branch was leaving m_rxBufferSampleRate at its prior value. This looks like a latent bug being silently fixed alongside the summary work. Probably correct, but worth either splitting into its own commit or calling out in the PR description so it isn't lost — it's a behaviour change that has nothing to do with logging.
2. aether.audio.summary cannot be disabled from the LogManager UI. LogManager::applyFilterRules() unconditionally appends aether.audio.summary.info=true before the per-category loop, and the loop only emits .debug=true rules. So toggling the category off in the UI still leaves info-level summaries flowing. This is consistent with how warnings on aether.audio are always-on, so it may be intentional ("can't break support bundles by turning it off") — but worth confirming, since a user reading the LogManager dialog would reasonably expect the toggle to silence the category.
3. buildAudioStartupSnapshot duplicates ~80 lines of buildAudioDevicesSnapshot. The PR's justification (avoid format probes at startup) is correct and explicit, but the duplication is large enough that a small private helper for the "shallow fields" (counts, saved/selected/default IDs, rx_route, tx_route, volumes) — with the two callers differing only in deviceToJson vs basicDeviceToJson — would reduce drift risk if either side changes in future. Not a blocker.
4. Minor: audioErrorName() correctly guards QAudio::UnderrunError with QT_VERSION < 6.11.0. Nice catch.
No bugs found beyond #1 above; AppSettings is used correctly, RAII in AudioSummaryLogger (Meyer's-singleton mutex + hash) is fine, and the namespace resolution into AetherSDR::AudioSummaryLogger from within AudioEngine.cpp's namespace AetherSDR { ... } block works as intended.
🤖 aethersdr-agent · cost: $14.8697 · model: claude-opus-4-7
|
Thanks for catching the first point. That line was intentional, but I agree it should be called out because it can look like hidden Windows audio-flow work. On Windows, That value is diagnostic state only. It is used by So the change corrects Windows diagnostic/reporting accuracy for the negotiated RX sink rate. It should not affect audio flow. I will call this out in the PR description so it does not surprise reviewers. |
Main extracted findPortAudioOutputDevice / defaultPortAudioOutputDevice into namespace-anonymous helpers (PR aethersdr#2899/aethersdr#2901 era), which moves the JACK-default-output selection out of start() into a helper. Weave the PR's new state-tracking calls (m_deviceDescription, m_fallbackOccurred, m_fallbackReason) into main's post-extraction start(), and detect the JACK-host-API selection by inspecting devInfo->hostApi after the helper returns so we can still mark it as a fallback for the summary. # Conflicts: # src/core/CwSidetonePortAudioSink.cpp
|
Merged — thanks @jensenpat! The 'no extra probing at startup' boundary between Resolved a stale-base conflict in Shipping in the next release. 73, |
…aethersdr#2973) ## Summary Implements aethersdr#2971 by adding a dedicated default-on `aether.audio.summary` logging path for support-bundle-friendly audio routing and negotiation summaries. This adds compact, deduped summary blocks for: - startup audio environment: selected/default input and output devices, saved-device presence, PC Audio state, and TX mic route intent - RX sink startup: actual output device, sample rate, channel count, sample format, resampling state, and fallback/substitution history - TX source startup: actual input device, negotiated rate/channels, mono/stereo state, sample format, resampling-to-24 kHz state, and fallback history - CW sidetone startup: backend, actual/backend-selected device, rate, backend substitution, and fallback history - auxiliary local sinks when instantiated: Quindar local sink and Aetherial monitor playback sink - final open failures: attempted rates/channels/formats, backend, device, failure reason, and fallback history ## Why The normal support log already caught many warning paths, but it did not reliably capture successful runtime sink/source negotiation. That left recurring audio/CW reports without the details needed to distinguish wrong endpoint, sample-rate mismatch, resampler path, backend fallback, and complete open failure cases. ## Important Safety Detail The startup summary uses a new shallow `DeviceDiagnostics::buildAudioStartupSnapshot(...)` helper. It intentionally does not call support-bundle-grade capability probes such as `preferredFormat()` or `isFormatSupported()` across devices at app startup. Full device capability probing remains in `buildAudioDevicesSnapshot(...)` for explicit diagnostics/support flows. Failure summaries only report negotiation work the audio path already attempted; they do not add extra probing. ## Historical Cases Covered The summary path is designed around recurring issue/PR classes including: - macOS Bluetooth/HFP route substitution and 24 kHz vs 48 kHz behavior (aethersdr#1486, aethersdr#2634) - CommonRadioAudio / Float32 vs Int16 format issues (aethersdr#1070, aethersdr#1090) - CW sidetone endpoint/backend routing (aethersdr#2072, aethersdr#2075, aethersdr#2899, aethersdr#2901) - CW sidetone missing/distorted reports (aethersdr#2629, aethersdr#2694) - no-audio-with-active-meters / output negotiation support gaps (aethersdr#1855) ## Implementation Notes - Adds `AudioSummaryLogger` with canonical one-block formatters and dedupe by event key. - Adds `aether.audio.summary` as a default-on info category without enabling the full `aether.audio` info/debug stream. - Keeps detailed existing `aether.audio` diagnostics intact. - Documents the summary logging policy in `docs/audio-pipeline.md`. ## Validation - `cmake --build build -j22` - `./build/device_diagnostics_test` - `./build/cw_sidetone_test` - `git diff --check` - Built and deployed a macOS test bundle; the primary test-machine replacement path is currently blocked by a Desktop delete ACL, so a separate quarantine-cleared test bundle was prepared. 👨🏼💻 Generated with OpenAI Codex (GPT-5.5 Pro 4/23) and tested by @jensenpat --------- Co-authored-by: Codex <noreply@openai.com> Co-authored-by: Jeremy Fielder <kk7gwy@aethersdr.com>
Summary
Implements #2971 by adding a dedicated default-on
aether.audio.summarylogging path for support-bundle-friendly audio routing and negotiation summaries.This adds compact, deduped summary blocks for:
Why
The normal support log already caught many warning paths, but it did not reliably capture successful runtime sink/source negotiation. That left recurring audio/CW reports without the details needed to distinguish wrong endpoint, sample-rate mismatch, resampler path, backend fallback, and complete open failure cases.
Important Safety Detail
The startup summary uses a new shallow
DeviceDiagnostics::buildAudioStartupSnapshot(...)helper. It intentionally does not call support-bundle-grade capability probes such aspreferredFormat()orisFormatSupported()across devices at app startup. Full device capability probing remains inbuildAudioDevicesSnapshot(...)for explicit diagnostics/support flows.Failure summaries only report negotiation work the audio path already attempted; they do not add extra probing.
Historical Cases Covered
The summary path is designed around recurring issue/PR classes including:
Implementation Notes
AudioSummaryLoggerwith canonical one-block formatters and dedupe by event key.aether.audio.summaryas a default-on info category without enabling the fullaether.audioinfo/debug stream.aether.audiodiagnostics intact.docs/audio-pipeline.md.Validation
cmake --build build -j22./build/device_diagnostics_test./build/cw_sidetone_testgit diff --check👨🏼💻 Generated with OpenAI Codex (GPT-5.5 Pro 4/23) and tested by @jensenpat