Skip to content

fix(audio): name CW sidetone JACK client "AetherSDR CW Sidetone"#3517

Open
Ozy311 wants to merge 2 commits into
aethersdr:mainfrom
Ozy311:fix/cw-sidetone-jack-name
Open

fix(audio): name CW sidetone JACK client "AetherSDR CW Sidetone"#3517
Ozy311 wants to merge 2 commits into
aethersdr:mainfrom
Ozy311:fix/cw-sidetone-jack-name

Conversation

@Ozy311

@Ozy311 Ozy311 commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Summary

The CW sidetone uses the PortAudio backend, which on Linux runs over PipeWire's JACK API and registers a JACK client under PortAudio's hardcoded default name PortAudio. The sidetone sink opens alongside RX and stays open for the whole RX session, so qpwgraph / JACK patchbays / WSJT-X / FLDIGI show a persistent node literally named PortAudio with no indication it belongs to AetherSDR — the most opaque label of any AetherSDR audio node.

Fix

Call PaJack_SetClientName("AetherSDR CW Sidetone") immediately before Pa_Initialize(). The pa_jack contract requires the call precede Pa_Initialize and references (does not copy) the string, so it uses a static-lifetime const char[]. Guarded with #if defined(Q_OS_LINUX) && __has_include(<pa_jack.h>) so macOS CoreAudio / Windows WASAPI builds (no pa_jack.h, no JACK node) compile unaffected. CW sidetone is AetherSDR's only PortAudio user, so naming the process-global JACK client is unambiguous.

Why

Scope

  • 13 lines added in one file (src/core/CwSidetonePortAudioSink.cpp).
  • Linux/PipeWire-only effect (guarded); no protocol, persistence, or UX change.

Test plan

  • Local incremental ninja -C build clean on Linux (Nobara 43, Qt 6.10.3, gcc 15.2.1).
  • Live A/B on a FLEX-6700 (RX-only), pw-dump ground truth:
    • Baseline (upstream/main 753eb689): sidetone node client.name / node.name / node.description all read PortAudio.
    • This branch: all three read AetherSDR CW Sidetone.
  • macOS CoreAudio / Windows WASAPI: compiles unaffected (guard excludes the call; no JACK node on those backends) — maintainer/secondary.

Related: #3438, #3440


73, Ozy K6OZY
AI compute partnership: cloaked.agency — drafted with Don, our VP of Engineering agent, on Linux dev stack (nobara-dell).

The CW sidetone defaults to the PortAudio backend, which on Linux runs over
PipeWire's JACK API and registers a JACK client under PortAudio's hardcoded
default name "PortAudio". The sidetone sink opens alongside RX and stays open
for the whole RX session, so qpwgraph/JACK/WSJT-X show a persistent node
literally named "PortAudio" with no indication it belongs to AetherSDR -- the
most opaque label of any AetherSDR audio node.

Call PaJack_SetClientName("AetherSDR CW Sidetone") immediately before
Pa_Initialize(). The pa_jack contract requires the call precede Pa_Initialize
and references (does not copy) the string, so it uses a static-lifetime
const char[]. Guarded with `#if defined(Q_OS_LINUX) && __has_include(<pa_jack.h>)`
so macOS CoreAudio / Windows WASAPI builds (no pa_jack.h, no JACK node) compile
unaffected. CW sidetone is AetherSDR's only PortAudio user, so naming the
process-global JACK client is unambiguous.

Verified A/B on Linux/PipeWire (Nobara 43, Qt 6.10.3): the sidetone node's
node.name / node.description / client.name change from "PortAudio" to
"AetherSDR CW Sidetone" in pw-dump while RX is running.

Co-authored-by: Don @ cloaked.agency <don@cloaked.agency> & K6OZY
@Ozy311 Ozy311 marked this pull request as ready for review June 11, 2026 03:10
@Ozy311 Ozy311 requested a review from a team as a code owner June 11, 2026 03:10

@aethersdr-agent aethersdr-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the diff — this looks good. Small, well-scoped, and correctly implemented:

  • Placement is right. The PaJack_SetClientName() call sits inside the if (!m_paInitialized) block immediately before Pa_Initialize(), which satisfies the pa_jack contract, and it re-runs correctly if the sink is ever re-initialized after Pa_Terminate() in the destructor.
  • Lifetime is right. static const char[] satisfies pa_jack's reference-not-copy semantics; the comment documents why, which future readers will appreciate.
  • The "only PortAudio user" claim is accurate. I verified CwSidetonePortAudioSink.{h,cpp} is the only code touching portaudio.h/Pa_Initialize in the tree, so naming the process-global JACK client here is unambiguous as stated.
  • Guard works. Q_OS_LINUX is defined by the time the preprocessor reaches the check (the header pulls in QtCore via QString/CwSidetoneSinkBackend.h), and macOS/Windows builds are unaffected.

One non-blocking note: the __has_include(<pa_jack.h>) guard tests header presence, not whether libportaudio was actually built with JACK support. A hand-built portaudio with JACK disabled but headers installed would fail at link time on PaJack_SetClientName. All mainstream distro packages build with JACK enabled (and CI uses pkg-config portaudio), so this is a theoretical edge case — just worth knowing if a user ever reports a link error against a custom portaudio. Not asking for a change; a CMake symbol check would be heavier than this 13-line fix deserves.

Ignoring the PaJack_SetClientName return value is fine — the pa_jack implementation just stores the pointer and always returns paNoError.

Nice test plan with the pw-dump A/B ground truth, and good continuity with #3438/#3440. Thanks for the contribution, K6OZY! 73


🤖 aethersdr-agent · cost: $7.4429 · model: claude-fable-5

@aethersdr-agent aethersdr-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the diff against the surrounding code — this looks good. Verified the details that matter for this kind of change:

  • Guard evaluates correctly. The new #if defined(Q_OS_LINUX) && __has_include(<pa_jack.h>) sits after #include "CwSidetonePortAudioSink.h", which pulls in <QString>, so Q_OS_LINUX is already defined at that point. No silent no-op on Linux.
  • Call ordering and lifetime are right. PaJack_SetClientName is called inside the !m_paInitialized block immediately before Pa_Initialize(), and re-runs correctly on any Pa_Terminate/re-init cycle. The function-local static const char[] satisfies pa_jack's reference-not-copy contract.
  • "Only PortAudio user" claim holds. Pa_Initialize appears only in this file; AudioEngine references HAVE_PORTAUDIO for backend selection but never initializes PortAudio itself. Naming the process-global JACK client here is unambiguous as stated.
  • Build safety. PortAudio comes from pkg-config (system package), and pa_jack.h is only installed when portaudio was built with JACK support, so the __has_include guard doubles as a link-safety check in practice. macOS/Windows are excluded cleanly.

One optional nit, not blocking: PaJack_SetClientName returns a PaError that's silently discarded. A failure just leaves the default name (and the 21-char name is well under JACK's 64-char limit), so this is harmless — but a qCWarning(lcAudio) on non-paNoError would match the error-logging style of the rest of this file if you want it.

Nice, tightly-scoped fix with a solid pw-dump A/B test plan — thanks for continuing the patchbay-identifiability work from #3438, @Ozy311!


🤖 aethersdr-agent · cost: $4.8654 · model: claude-fable-5

Address the aethersdr-agent review note on aethersdr#3517: PaJack_SetClientName returns a PaError that was silently discarded. Capture it and qCWarning(lcAudio) on non-paNoError, mirroring the Pa_Initialize error path in the same file. Non-fatal — a naming failure only leaves the default JACK/PipeWire node label — so we log and continue rather than abort. No behavior change on any current path (pa_jack returns paNoError today); this codes to the published PaError contract and keeps the file’s error-logging uniform.

Co-authored-by: Don @ cloaked.agency <don@cloaked.agency> & K6OZY
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant