Skip to content

Stabilize DAX2 coexistence policy#2271

Merged
ten9876 merged 1 commit intoten9876:mainfrom
jensenpat:aether/troubleshoot-pr2266-1ff6716
May 2, 2026
Merged

Stabilize DAX2 coexistence policy#2271
ten9876 merged 1 commit intoten9876:mainfrom
jensenpat:aether/troubleshoot-pr2266-1ff6716

Conversation

@jensenpat
Copy link
Copy Markdown
Collaborator

Summary

This PR stabilizes coexistence with SmartSDR DAX2 by making AetherSDR explicit about when it may create or adopt DAX TX streams, and by avoiding stale/orphan DAX stream status from being treated as locally owned state.

Code Summary

  • Added DaxTxPolicy.h to centralize platform-aware DAX TX decisions. Windows builds now treat SmartSDR DAX2 as the owner of the external DAX route, while hosted DAX platforms such as macOS and PipeWire can still create local dax_tx streams when their bridge or TCI route needs one.
  • Moved DAX TX creation behind RadioModel::ensureDaxTxStream(...), with request reasons for hosted DAX bridge, TCI TX audio, external route-only, and generic audio recreation. This prevents eager stream create type=dax_tx during GUI attach and tracks pending creates to avoid duplicate requests.
  • Tightened DAX stream status ownership parsing in StreamStatus.h and RadioModel.cpp. Dead orphan DAX RX entries with client_handle=0x00000000 ip=0.0.0.0 are ignored, external DAX RX/TX streams are logged separately, and local DAX TX state only updates from the current stream id or our own client_handle.
  • Updated slice mode and DAX bridge startup handling in MainWindow.cpp so radio-side transmit set dax=1 behavior remains aligned for digital modes, while local DAX TX stream creation is gated by the new policy.
  • Added UdpRegistrationPolicy.h plus a LAN VITA UDP rebind path. PanadapterStream now binds an OS-assigned LAN UDP port with DontShareAddress, and RadioModel retries client udpport registration on Flex's port/IP collision error instead of leaving the session stuck.
  • Added focused regression coverage in radio_status_ownership_test for DAX TX policy decisions, dead DAX RX status handling, DAX TX ownership updates, and UDP registration retry detection.

Validation

  • Built successfully on macOS with cmake --build build -j10.
  • Ran ./build/radio_status_ownership_test and all tests passed.
  • Launched the built app from build/AetherSDR.app for manual troubleshooting.

👨🏼‍💻 Generated with OpenAI Codex (GPT-5.5 Pro 4/23) and tested by @jensenpat

@ten9876
Copy link
Copy Markdown
Owner

ten9876 commented May 2, 2026

Claude here — thanks Patrick! This is a textbook second-draft refactor of #2266: the new `DaxTxPolicy.h` decision table is exactly the kind of structure we want for cross-platform DAX coexistence, and the test coverage (`testStreamStatusOwnershipCompatibility`, `testDaxTxStatusOwnership`, `testDaxTxPolicy`, `testUdpRegistrationPolicy`) makes the platform branches verifiable.

Audited the SmartLink/WAN path before merging — `startWan()` already binds to `AnyIPv4:0` for the local socket and your new `shouldRetryLanUdpPortRegistration(isWan, ...)` correctly excludes WAN from the rebind logic (with explicit test coverage). Clean.

Merging now.

Filed a follow-up at #2273 to track the Linux non-PipeWire edge case — the new `setDax(isDigital)` is now unconditional on all platforms but Linux non-PipeWire builds don't get a local `dax_tx` stream, so digital TX would be silent on that niche configuration. It's documented in the policy via the `route_only_does_not_require_local_stream` note, but worth tracking in case someone hits it.

73, Jeremy KK7GWY & Claude (AI dev partner)

@ten9876 ten9876 merged commit e7be1e8 into ten9876:main May 2, 2026
5 checks passed
ten9876 added a commit that referenced this pull request May 2, 2026
Reliability sweep release.  Headline is jensenpat's DAX2 coexistence
policy refactor (#2271): platform-aware decision table, lazy dax_tx
stream creation, anti-stomp on incoming foreign DAX TX status, LAN
VITA UDP rebind on Flex's "Port/IP pair already in use" error, dead-
orphan DAX RX detection, and 24+ test assertions.

Substantial reliability fixes around disconnect teardown (#2247 —
sequenced stream remove with response wait, dropped self-disconnect,
dying-gasp byte), worker-thread shutdown (#2248 — no more killTimer
warnings), and panadapter zoom (#2246 — no spectrum flash).

Closes 12 issues via two paired triage-cleanup sweep PRs (#2270 +
#2272) covering small UI bugs, contrast, indicator routing, click-to-
tune behaviour, and visible regressions from recent feature work.

Also includes the #2273 follow-up to #2271: setDax() and DAX TX
stream creation are now both gated on platforms that can actually
feed DAX audio, so Linux non-PipeWire builds keep digital TX on the
physical mic input rather than going silent.

Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
@aethersdr-agent aethersdr-agent Bot mentioned this pull request May 2, 2026
2 tasks
ten9876 added a commit that referenced this pull request May 2, 2026
…re (#2285)

v0.9.5's DAX2 coexistence policy (#2271) regressed TCI digital TX
(WSJT-X / JTDX / MSHV) on Windows and Linux without PipeWire.  The
radio was told dax=1 but evaluateDaxTxPolicy() denied dax_tx stream
creation for TciTxAudio on those platforms, so the modulator stayed
silent during TX.

The conceptual mistake was conflating SmartSDR DAX2's ownership of
Windows DAX audio devices with the radio's dax_tx stream slot.  TCI
feeds its dax_tx packets from a WebSocket — it doesn't touch local
audio devices and doesn't conflict with SmartSDR DAX2 at all.

evaluateDaxTxPolicy() now always allows DaxTxRequestReason::TciTxAudio
regardless of platform / hosted-DAX availability.  Test assertions in
radio_status_ownership_test.cpp flipped to match (the prior
"Windows external-DAX2 TCI policy does not create dax_tx" assertion
codified the regression) plus a new Linux-non-PipeWire case.

macOS and Linux + PipeWire were unaffected — they hit the
`tciDaxTxSupported = true` branch and were already allowed.

Fixes #2276.

Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
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.

2 participants