Skip to content

Track CW sidetone routing to selected PC audio output #2901

Description

@jensenpat

Summary

Multiple reports describe CW sidetone being absent, distorted, delayed, or otherwise unreliable. During the investigation for PR #2899, we found one concrete local-audio routing failure mode: the dedicated CW sidetone sink can be out of sync with the PC audio output selected in AetherSDR.

Tracking PR:

Findings from the PR #2899 investigation

  • Local CW sidetone is generated by CwSidetoneGenerator and played through a dedicated sidetone backend, separate from the normal RX QAudioSink.
  • The app settings output selector and the new-device dialog both route through AudioEngine::setOutputDevice().
  • setOutputDevice() persists the selected output and restarts the RX stream when RX audio is running.
  • Restarting RX audio also stops and restarts the local CW sidetone sink via stopRxStream() / startRxStream().
  • The Qt sidetone backend (CwSidetoneQAudioSink) accepted and used the selected QAudioDevice.
  • The PortAudio sidetone backend accepted a QAudioDevice in its interface but ignored it internally, opening PortAudio's default output instead.
  • Therefore, when the operator selected a non-default PC output in AetherSDR, RX audio could move to that selected output while CW sidetone stayed on the OS/PortAudio default output.
  • That mismatch can present to the user as “lost sidetone,” especially with headphones, virtual cables, USB audio devices, or after the OS changes the default route.
  • A related default-following gap also existed: when AetherSDR was configured to follow the system default output, the audio-device monitor restarted local audio paths on device add/remove, but not on a pure OS default-output change where the device list stayed the same.

What PR #2899 changes

  • Maps the selected Qt output device name to a PortAudio output device before opening the low-latency sidetone stream.
  • Treats missing or ambiguous PortAudio mappings as a PortAudio backend failure, causing fallback to the Qt QAudioSink sidetone backend on the selected device.
  • Passes the current Qt output device object into sidetone startup so default-following and explicit-output selection go through the same routing logic.
  • Tracks Qt default input/output IDs in MainWindow.
  • Restarts default-following local audio paths when Qt reports that the OS default input/output changed, even if no device was removed.
  • Updates docs/audio-pipeline.md with the default-device restart behavior and sidetone backend routing/fallback behavior.

Expected user-facing behavior after PR #2899

  • Changing the PC output device from AetherSDR settings restarts CW sidetone on the selected output device.
  • Accepting a new output device from the new-device dialog restarts CW sidetone on the selected output device.
  • If AetherSDR is following the system default output, changing the OS default output restarts the local output path so RX audio and CW sidetone bind to the new default.
  • If PortAudio cannot map the selected Qt output reliably, AetherSDR should use the Qt sidetone sink instead of silently playing sidetone through the wrong PortAudio/default endpoint.

Validation performed for PR #2899

  • cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo
  • cmake --build build --parallel 22
  • cmake --build build --target AetherSDR --parallel 22
  • ./build/cw_sidetone_test
  • git diff --check

Follow-up verification needed

  • Confirm on Windows with explicit non-default output device selected.
  • Confirm on macOS with explicit non-default output device selected.
  • Confirm with USB audio/headset devices where the OS default differs from AetherSDR's selected output.
  • Confirm with virtual audio devices/cables.
  • Confirm the OS-default-following path by changing the OS default output while AetherSDR is connected and PC audio/CW sidetone are active.
  • Capture logs showing either:
    • CwSidetonePortAudioSink: matched selected Qt output ...
    • or fallback to QAudioSink when the selected output cannot be mapped.

Known related CW issues

These are not all the same root cause. This list is meant to keep the CW/sidetone context connected while #2899 is verified.

Open sidetone / keying / timing reports

Open CW decoder / CW feature requests

Open CW-adjacent UI / slice / spectrum reports

Closed or previously-addressed sidetone/keying/CWX history

Acceptance criteria for closing this tracking issue

  • [bug] Route CW sidetone to selected audio output #2899 is merged or superseded by an equivalent fix.
  • Field verification confirms sidetone follows the selected AetherSDR PC output after settings changes.
  • Field verification confirms sidetone follows the selected output after accepting the new-device dialog.
  • Field verification confirms sidetone follows OS default changes when AetherSDR is configured to use the system default output.
  • Any remaining CW sidetone reports after [bug] Route CW sidetone to selected audio output #2899 are triaged into separate root causes instead of being folded into the output-routing failure mode.

Metadata

Metadata

Assignees

No one assigned

    Labels

    CWCW keying, decode, and operationaudioAudio engine and streamingbugSomething isn't workingmaintainer-reviewRequires maintainer review before any action is takenpriority: highHigh priority

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions