fix: hardware PTT into radio drives PC mic audio (#2373, fixes #2200)#2431
Conversation
…no modulating audio (#2373, fixes #2200) Pressing the radio's hardware PTT (mic-line PTT, footswitch into ACC, RCA TXREQ) lit the carrier but no PC mic audio modulated it. The gate at RadioModel.cpp:3382 forced TransmitModel::setTransmitting(false) whenever m_txRequested was false, even when the radio reported our handle was the TX owner. moxChanged(false) propagated to AudioEngine::setTransmitting(false), so the mic capture path stayed gated. Parse the radio's interlock `source=` field (SW/MIC/ACC/RCA/TUNE per FlexLib v4.2.18 ParsePTTSource, Radio.cs:7932) and persist it across status updates that omit it. Treat MIC/ACC/RCA as legitimate non- m_txRequested TX paths alongside the existing CW key, CWX, and tune bypasses. SW source still requires m_txRequested so the optimistic local-unkey behaviour from docs/TX_SYNC_FIX_REPORT.md is preserved — a stale state=TRANSMITTING after setTransmit(false) on SW source still falls through to the force-off branch. Clear m_lastInterlockSource when interlock confirms non-TX state (RECEIVE/READY/NOT_READY) and on disconnect, so a stale hardware source can't outlive the actual key release. Waterfall and panadapter timing untouched: radioTransmittingChanged is still emitted unconditionally before the gate logic at line 3380, so spectrum freeze, S-Meter, and TX status indicator are byte- identical to pre-fix behaviour. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
There was a problem hiding this comment.
Thanks @jensenpat — this is a thoughtful, surgical fix, and the writeup made it easy to verify. LGTM.
What I checked:
- Gate logic preserves SW optimistic-off: A stale
state=TRANSMITTING source=SWafter a local unkey still takes the force-off branch (sincehardwarePtt=false,m_txRequested=false, no CW/tune), so the SSB unkey-tail behavior fromTX_SYNC_FIX_REPORT.mdis preserved. ✓ - Multi-Flex correctness: The
!m_txOwnedByUsouter check is unchanged, andhardwarePttonly relaxes the inner condition — another station's hardware PTT (differenttx_client_handle) still force-offs us. ✓ - Source persistence cleanup: Cleared on disconnect (
RadioModel.cpp:1767) and on confirmed non-TX states (READY/READY_NOT/STANDBYetc., anything notTRANSMITTING/*REQUESTED/*DELAY). The clear happens after the gate logic in the same status frame, so it doesn't disturb the current decision — only prevents stale carryover into the next one. ✓ - Disconnect ordering:
m_lastInterlockSource.clear()is grouped with the other TX flag resets atRadioModel.cpp:1764, exactly where you'd want it. ✓ radioTransmittingChangedtiming: Emit at line 3380 is byte-identical to before — the hardware PTT changes only affect the gate that follows. Waterfall freeze/unfreeze (#2368) and S-Meter mode (MainWindow.cpp:2002+) are unaffected. ✓
One minor observation, not blocking:
During hardware PTT release, the radio likely transitions through state=UNKEY_REQUESTED source=MIC before reaching READY. Pre-existing code uses state.contains("REQUESTED") for the transitioningToTx check, which matches UNKEY_REQUESTED too — so the audio gate stays open during the unkey-tail. That's actually probably what you want for hardware PTT (the operator hasn't unkeyed locally; let the radio finish its tail naturally), and it matches the m_cwKeyActive/m_cwxActive paths. Just flagging it for awareness — not a regression and not something this PR needs to address.
Nice job tracing this against FlexLib's Radio.cs:7932 ParsePTTSource and Radio.cs:7577 IsInterlockMox — that's the level of homework this kind of fix needs. Approve from my side once you've validated on real hardware (mic PTT + ACC footswitch + RCA TXREQ per the test plan).
|
Claude here — really thorough work, jensenpat. The FlexLib v4.2.18 ParsePTTSource validation is exactly the right discipline, and explicitly noting where AetherSDR diverges (m_txRequested optimistic-off) and why we still need the source distinction makes the whole reasoning chain auditable. The state-machine walk in the description (PTT_REQUESTED + source=MIC → TRANSMITTING with no source) covers the persist-across-omission case cleanly, and the conservative source-clear (only on confirmed non-TX states) preserves through transitions. Filing a follow-up issue with two cleanups surfaced during review; will tag you there. Merged. 73, Jeremy KK7GWY & Claude (AI dev partner) |
Summary
Fixes #2373 (hardware PTT into radio doesn't drive forward RF when
mic_selection=PC) and the duplicate #2200 (Jerry KE9U's external PTT on FLEX-8400M).When the user keyed the radio's hardware PTT (mic-line PTT, footswitch into ACC, RCA TXREQ), the carrier came up but no PC mic audio modulated it. The gate at
RadioModel.cpp:3382forcedTransmitModel::setTransmitting(false)wheneverm_txRequestedwas false — even when the radio reported our client handle as the TX owner.moxChanged(false)propagated toAudioEngine::setTransmitting(false), gating the mic capture path.Root cause
The bypasses (
m_cwKeyActive,m_cwxActive,isTuning()) cover the existing non-m_txRequestedTX paths, but hardware-keyed PTT had no such bypass. Effectively a latent bug: the PC-mic-with-hardware-PTT combination has likely never worked through this branch.Fix
Parse the radio's interlock
source=field (SW/MIC/ACC/RCA/TUNEper FlexLib v4.2.18ParsePTTSource), persist it across status updates that omit it, and addMIC|ACC|RCAto the bypass list:SWsource still requiresm_txRequested, so the optimistic local-unkey behaviour fromdocs/TX_SYNC_FIX_REPORT.mdis preserved — a stalestate=TRANSMITTINGaftersetTransmit(false)on SW source still falls through to the force-off branch (no SSB unkey-tail regression).m_lastInterlockSourceis cleared on:RECEIVE/READY/NOT_READY) — so a stale hardware source can't outlive the actual key release if a later status update omitssource=.Validation against FlexLib v4.2.18
Validated against
/Users/patj/aether/FlexLib_API_v4.2.18.41174reference docs:source=field exists:Radio.cs:7932-7944ParsePTTSourceparses exactly these five values. Confirmed.Radio.cs:7577isIsInterlockMox(state) && ShouldUpdateMoxOrTuneState(handle).IsInterlockMoxacceptsTransmitting | PTTRequested | UnkeyRequested. FlexLib has nom_txRequestedanalogue — it doesn't do AetherSDR's optimistic-off, so it doesn't need to distinguish SW from hardware sources for the gate.sourcedistinction: AetherSDR diverges from FlexLib intentionally (perTX_SYNC_FIX_REPORT.md) for SSB unkey responsiveness. Them_txRequestedflag is what guards optimistic-off — we can't drop it. Thesourcefield is exactly the right primitive to apply optimistic-off only to SW source while accepting interlock as authoritative for hardware sources.Timing / ordering preserved
The user explicitly asked that this not adversely impact panadapter/waterfall timing. Verified:
radioTransmittingChangedis emitted atRadioModel.cpp:3380unconditionally, before any gate logic. This is what drives waterfall freeze, S-Meter mode, and the TX status indicator atMainWindow.cpp:2006-2024. The fix touches only the gate at line 3382 and below —radioTransmittingChangedemit timing is byte-identical to pre-fix behaviour.moxChanged→AudioEngine::setTransmitting(MainWindow.cpp:1965-1986) now correctly firestruewhen hardware PTT keys the radio, so PC mic audio enables. This is the intended new behaviour.txAudioGateChangedremains a TX-OFF-only fallback atMainWindow.cpp:1991-2000(the report explicitly warns against reintroducing TX-on wait-for-interlock for SSB).Acceptance criteria coverage (from issue #2373)
TransmitModel::isTransmitting()returns true when radio reports our handle + TRANSMITTING with hardware sourceAetherialAudioStripTX indicator and Chain applet TX endpoint pulse (driven offmoxChanged)moxChanged→AudioEngine::setTransmitting(true))m_txRequested=true→ existing accept path)!m_txOwnedByUsouter check unchanged, hardwarePtt only relaxes the inner condition)m_txRequested)Files changed
src/models/RadioModel.h— addm_lastInterlockSourcemembersrc/models/RadioModel.cpp— parsesource=, addhardwarePttbypass, clear on non-TX/disconnect40 insertions, 1 deletion. No protocol changes, no new dependencies.
Test plan
mic_selection=PCproduces forward RF and lit Aetherial Audio TX indicator (primary acceptance — issues #2200, #2373)!m_txOwnedByUs), local indicators stay dim, no audio flows (Multi-Flex)🤖 Generated with Claude Code