fix(audio): suppress mic capture while TCI client feeds TX audio#2982
Conversation
When a slice's mic_selection=PC and a TCI client is sending binary TX audio, two packet producers compete for the same UDP path to the radio: - onTxAudioReady (local mic capture via QAudioSource -> txPacketReady) - feedDaxTxAudio (TCI binary audio -> txPacketReady) If the host's default audio input is a real mic producing samples, the mic-derived packets (~5 ms cadence) drown out the TCI tone (~50 ms). End-to-end symptom: a TCI client's calibration sweep keys the radio, tx_sensors flows back, but ALC stays pinned at the mic's noise floor regardless of tx_gain and fwd ~ 0 W. Most visible on macOS where the CoreAudio default input is a real mic (webcam etc.). Linux only escapes by accident on hosts with no usable default input. Fix: feedDaxTxAudio stamps a QElapsedTimer on every frame; in onTxAudioReady, if that timer is fresh (<200 ms, comfortably wider than the 50 ms TCI cadence), early-return so the mic samples are dropped while TCI audio is flowing. No platform branch -- correct on every host. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Merged — thanks @nigelfenton! The bug-report writeup itself is the kind of competing-producer diagnosis that's worth keeping as project lore: the side-by-side TCC-permission-denied (clean The Cool to hear about tci-monitor too — TX-drive calibration is a recurring gap. If you ever want to drop a line in our docs about it as a companion tool, happy to merge a docs PR pointing users at it. Shipping in the next release. 73, |
… + @G6PWY-Chris (#3067) Two attribution errors in the v26.5.3 release CHANGELOG: 1. @M7HNF-Ian (Ian, separate GitHub account) → @nigelfenton (Nigel Fenton, G0JKN) — Nigel authored all 5 of the commits I bucketed under that line: TCI Network dialog tab (#2879), tx_gain + ALC (#2950), use-after-free fix (#2946), vfo emit on band-change (#2828), mic-capture suppress during TCI feed (#2982). 2. @chrisb1964 → @G6PWY-Chris (Chris G6PWY) — single commit author in the cycle was the latter; chrisb1964 is unrelated. Reported by Nigel directly. All other handles verified against gh api repos/.../commits/<sha>. GitHub release notes already updated; this lands the same fix in the in-repo CHANGELOG. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…hersdr#2982) ## Problem When a slice's `mic_selection=PC` AND a TCI client (TCI Monitor, WSJT-X, JTDX) is sending binary TX audio, two packet producers compete for the same UDP path to the radio: - `AudioEngine::onTxAudioReady` — local mic capture via `QAudioSource` → emits `txPacketReady` - `AudioEngine::feedDaxTxAudio` — TCI binary audio → emits `txPacketReady` If the host's default audio input is a real microphone producing samples (the common case on macOS where CoreAudio defaults to a webcam mic), the mic-derived packets (~5 ms cadence) drown out the TCI tone (~50 ms cadence). ## End-to-end symptom A TCI client's calibration sweep keys the radio, `tx_sensors` flows back — **but ALC stays pinned at the host mic's noise floor regardless of `tx_gain`, and forward power stays at ~0 W.** Caught while building a TX-drive calibration panel against AetherSDR on macOS: - **Mic permission denied** (terminal-launched AE, no TCC grant): no audio at all reached the modulator → clean `-150 dBFS` across the whole sweep. - **Mic permission granted** (normal launch): ALC pinned at `~-38 dBFS` — exactly the level of room ambient picked up by the webcam mic. Coughing produced fwd-power spikes that confirmed mic-derived packets were reaching the modulator while TCI packets were being lost in the stream. Linux escapes this only by accident — on hosts with no usable default audio input, `QAudioSource` produces silence so there's no competition. ## Fix `feedDaxTxAudio` stamps a `QElapsedTimer` on every frame. In `onTxAudioReady`, if that timer is fresh (< 200 ms, comfortably wider than the 50 ms TCI cadence), early-return so the mic samples are dropped while TCI audio is flowing. No platform branch — correct on every host. When the TCI client stops sending audio (timer goes stale), the mic-capture path resumes normally. ## Verified - **macOS** (Mac mini Apple Silicon, Qt 6.11): mic suppression eliminates the false TCI baseline; calibration sweep then produces a clean monotonic ALC-vs-`tx_gain` curve into a Flex 6300. - **Linux** (Ubuntu 24.04, Qt 6.4.2): no behavior change (no real mic samples to suppress on the test rig). - **Windows** (Qt 6.10.3): builds clean; equivalent behavior expected (same code path, no platform branches). ## Notes Draft for now — opened so it doesn't disappear into a personal fork branch. Happy to ready-for-review once reviewers want a look. The TX-drive calibration tool that surfaced this is a separate standalone (TCI Monitor — github.com/nigelfenton/tci-monitor) and is **not** being proposed for inclusion in AetherSDR. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… + @G6PWY-Chris (aethersdr#3067) Two attribution errors in the v26.5.3 release CHANGELOG: 1. @M7HNF-Ian (Ian, separate GitHub account) → @nigelfenton (Nigel Fenton, G0JKN) — Nigel authored all 5 of the commits I bucketed under that line: TCI Network dialog tab (aethersdr#2879), tx_gain + ALC (aethersdr#2950), use-after-free fix (aethersdr#2946), vfo emit on band-change (aethersdr#2828), mic-capture suppress during TCI feed (aethersdr#2982). 2. @chrisb1964 → @G6PWY-Chris (Chris G6PWY) — single commit author in the cycle was the latter; chrisb1964 is unrelated. Reported by Nigel directly. All other handles verified against gh api repos/.../commits/<sha>. GitHub release notes already updated; this lands the same fix in the in-repo CHANGELOG. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Problem
When a slice's
mic_selection=PCAND a TCI client (TCI Monitor, WSJT-X, JTDX) is sending binary TX audio, two packet producers compete for the same UDP path to the radio:AudioEngine::onTxAudioReady— local mic capture viaQAudioSource→ emitstxPacketReadyAudioEngine::feedDaxTxAudio— TCI binary audio → emitstxPacketReadyIf the host's default audio input is a real microphone producing samples (the common case on macOS where CoreAudio defaults to a webcam mic), the mic-derived packets (~5 ms cadence) drown out the TCI tone (~50 ms cadence).
End-to-end symptom
A TCI client's calibration sweep keys the radio,
tx_sensorsflows back — but ALC stays pinned at the host mic's noise floor regardless oftx_gain, and forward power stays at ~0 W.Caught while building a TX-drive calibration panel against AetherSDR on macOS:
-150 dBFSacross the whole sweep.~-38 dBFS— exactly the level of room ambient picked up by the webcam mic. Coughing produced fwd-power spikes that confirmed mic-derived packets were reaching the modulator while TCI packets were being lost in the stream.Linux escapes this only by accident — on hosts with no usable default audio input,
QAudioSourceproduces silence so there's no competition.Fix
feedDaxTxAudiostamps aQElapsedTimeron every frame. InonTxAudioReady, if that timer is fresh (< 200 ms, comfortably wider than the 50 ms TCI cadence), early-return so the mic samples are dropped while TCI audio is flowing. No platform branch — correct on every host.When the TCI client stops sending audio (timer goes stale), the mic-capture path resumes normally.
Verified
tx_gaincurve into a Flex 6300.Notes
Draft for now — opened so it doesn't disappear into a personal fork branch. Happy to ready-for-review once reviewers want a look. The TX-drive calibration tool that surfaced this is a separate standalone (TCI Monitor — github.com/nigelfenton/tci-monitor) and is not being proposed for inclusion in AetherSDR.