Summary
Add a low-noise, default-on audio troubleshooting summary to the normal log so support bundles reliably capture the actual sink/source negotiation story behind recurring audio and CW issues.
Today, many of the useful details already exist in code, but they are split across aether.audio qCDebug / qCInfo lines and therefore are not present in the default log settings. The result is that clusters of recurring reports arrive with the same missing context:
- Which output sink actually opened?
- Which input source actually opened?
- What sample rate and channel count were negotiated?
- Was resampling active?
- Which CW sidetone backend/device/rate was used?
- Did we fall back from one sink/backend to another?
- Were auxiliary local sinks (e.g. Quindar / monitor playback) instantiated, and on what format?
This issue is to add that information in a way that is immediately useful for troubleshooting without making the default log noisy.
Problem
The current default log policy enables aether.discovery, aether.connection, and aether.protocol, but does not enable aether.audio info/debug logging.
That means the default log usually captures:
- warning/error paths for audio fallback or outright failure
- but not the normal successful sink/source negotiation path
This is a poor fit for real-world support, because many of the bugs we keep seeing are not hard failures. They are:
- wrong sink/backend chosen
- telephony/Bluetooth route picked unexpectedly
- 24 kHz vs 48 kHz mismatch
- hidden resampler path differences
- CW sidetone on the wrong output
- auxiliary sink using a different output profile than RX audio
In those cases, the existing default log is often missing the exact information we need.
Proposed approach
Do not simply make all existing aether.audio qCInfo(...) lines default-on.
Instead, add a consolidated summary log block that emits only at key lifecycle moments and only when the material audio-routing state changes.
Design goals
- Default-on in the normal log
- Low noise
- High signal for support bundles
- One consolidated block instead of many scattered lines
- Covers the happy path, not only warnings/failures
- Reuses existing diagnostics logic where practical so we have one consistent description of audio state
What to log
1. Startup / environment summary
At application startup, log a one-shot summary of the selected/default audio devices and route intentions.
Example fields:
- selected output device description
- default output device description
- selected input device description
- default input device description
- whether the saved device is present
- whether PC Audio is enabled
- whether TX mic source is
PC / radio / DAX
This is the static context block.
2. RX sink summary
When the RX sink is actually started, emit a summary with:
- actual output device used
- sink format
- actual sample rate
- channel count
- sample format
- whether resampling is enabled
- whether we fell back from 48 kHz to 24 kHz, or substituted a sibling/default output
This captures the real PC-audio playback path.
3. TX source summary
When the TX mic source is actually started, emit a summary with:
- actual input device used
- negotiated sample rate
- channel count
- mono/stereo
- whether resampling to radio-native 24 kHz is enabled
- whether a fallback input format/rate was required
This captures the real TX capture path.
4. CW sidetone summary
When CW sidetone starts, emit a summary with:
- backend (
PortAudio vs QAudioSink)
- actual output device / backend-selected device
- actual sample rate
- whether fallback occurred
- any backend substitution (e.g. PortAudio failed -> Qt sink)
This is especially important because CW issue clusters frequently come down to sidetone sink choice and output routing.
5. Auxiliary local sink summary
When any auxiliary local sink actually starts, emit its own compact summary.
Examples:
- Quindar local sink
- any Aetherial/monitor playback sink that owns its own
QAudioSink
Log only for sinks that are really instantiated at runtime.
6. Re-log only on material change
If output/input device selection changes, or a sink restarts with materially different state, emit a new summary.
Otherwise do not repeat the block.
Suggested implementation shape
Dedicated summary category
Add a dedicated logging category such as:
with default severity suitable for normal logs, e.g. QtInfoMsg.
This keeps the existing aether.audio category as the detailed opt-in category while making the new summary path explicitly part of the default troubleshooting signal.
Consolidated structured message
Prefer a compact multi-line or structured one-block summary over scattered individual lines.
Example:
[INF] aether.audio.summary: Audio summary:
output selected="USB Audio CODEC" default="MacBook Pro Speakers" rxSink=started rate=48000 format=Float resample=24k->48k fallback=no
input selected="2-USB PnP Audio Device" default="MacBook Mic" txSource=started rate=48000 channels=2 resample=48k->24k fallback=no
sidetone backend=QAudioSink rate=48000 fallback=no
quindar running=no
puduMonitor running=no
Deduping / noise control
Compute a compact canonical summary string or JSON object, hash it, and only emit when it changes.
This keeps the log readable while still surfacing the important transitions.
Reuse existing snapshot logic
DeviceDiagnostics::buildAudioDevicesSnapshot(...) already knows a lot about:
- selected/default devices
- supported rates/formats
- route intentions
- device availability
The implementation should reuse or extend this logic instead of inventing a second independent description of audio state.
Non-goals
- Do not make the full detailed
aether.audio info/debug stream default-on
- Do not emit per-buffer or per-callback audio logs
- Do not create a repeated heartbeat log
- Do not duplicate support-dialog JSON snapshots verbatim on every startup if a smaller human-readable summary is sufficient
Acceptance criteria
Likely touch points
src/core/LogManager.h/.cpp
src/core/AudioEngine.cpp
src/core/CwSidetoneQAudioSink.cpp
src/core/CwSidetonePortAudioSink.cpp
src/core/QuindarLocalSink.cpp
src/core/ClientPuduMonitor.cpp
src/core/DeviceDiagnostics.h/.cpp
- possibly
src/core/SupportBundle.cpp only if any category/default handling needs adjustment
Suggested labels
enhancement
audio
CW
supportability
73
Summary
Add a low-noise, default-on audio troubleshooting summary to the normal log so support bundles reliably capture the actual sink/source negotiation story behind recurring audio and CW issues.
Today, many of the useful details already exist in code, but they are split across
aether.audioqCDebug/qCInfolines and therefore are not present in the default log settings. The result is that clusters of recurring reports arrive with the same missing context:This issue is to add that information in a way that is immediately useful for troubleshooting without making the default log noisy.
Problem
The current default log policy enables
aether.discovery,aether.connection, andaether.protocol, but does not enableaether.audioinfo/debug logging.That means the default log usually captures:
This is a poor fit for real-world support, because many of the bugs we keep seeing are not hard failures. They are:
In those cases, the existing default log is often missing the exact information we need.
Proposed approach
Do not simply make all existing
aether.audioqCInfo(...)lines default-on.Instead, add a consolidated summary log block that emits only at key lifecycle moments and only when the material audio-routing state changes.
Design goals
What to log
1. Startup / environment summary
At application startup, log a one-shot summary of the selected/default audio devices and route intentions.
Example fields:
PC/ radio / DAXThis is the static context block.
2. RX sink summary
When the RX sink is actually started, emit a summary with:
This captures the real PC-audio playback path.
3. TX source summary
When the TX mic source is actually started, emit a summary with:
This captures the real TX capture path.
4. CW sidetone summary
When CW sidetone starts, emit a summary with:
PortAudiovsQAudioSink)This is especially important because CW issue clusters frequently come down to sidetone sink choice and output routing.
5. Auxiliary local sink summary
When any auxiliary local sink actually starts, emit its own compact summary.
Examples:
QAudioSinkLog only for sinks that are really instantiated at runtime.
6. Re-log only on material change
If output/input device selection changes, or a sink restarts with materially different state, emit a new summary.
Otherwise do not repeat the block.
Suggested implementation shape
Dedicated summary category
Add a dedicated logging category such as:
aether.audio.summarywith default severity suitable for normal logs, e.g.
QtInfoMsg.This keeps the existing
aether.audiocategory as the detailed opt-in category while making the new summary path explicitly part of the default troubleshooting signal.Consolidated structured message
Prefer a compact multi-line or structured one-block summary over scattered individual lines.
Example:
Deduping / noise control
Compute a compact canonical summary string or JSON object, hash it, and only emit when it changes.
This keeps the log readable while still surfacing the important transitions.
Reuse existing snapshot logic
DeviceDiagnostics::buildAudioDevicesSnapshot(...)already knows a lot about:The implementation should reuse or extend this logic instead of inventing a second independent description of audio state.
Non-goals
aether.audioinfo/debug stream default-onAcceptance criteria
Likely touch points
src/core/LogManager.h/.cppsrc/core/AudioEngine.cppsrc/core/CwSidetoneQAudioSink.cppsrc/core/CwSidetonePortAudioSink.cppsrc/core/QuindarLocalSink.cppsrc/core/ClientPuduMonitor.cppsrc/core/DeviceDiagnostics.h/.cppsrc/core/SupportBundle.cpponly if any category/default handling needs adjustmentSuggested labels
enhancementaudioCWsupportability73