Skip to content

Add "Direct USB TX" toggle to bypass the mixer on transmit - #722

Open
patrickrb wants to merge 1 commit into
devfrom
feat/direct-usb-tx-toggle
Open

Add "Direct USB TX" toggle to bypass the mixer on transmit#722
patrickrb wants to merge 1 commit into
devfrom
feat/direct-usb-tx-toggle

Conversation

@patrickrb

Copy link
Copy Markdown
Owner

What

Adds a Direct USB TX on/off toggle in Settings → Radio & Audio → Audio (right under Audio Output).

  • On — TX audio goes straight to the USB radio over the direct libusb path, bypassing Android's shared mixer. Notification and other-app sounds can no longer be mixed into the transmission and go out on air.
  • Off — normal AudioTrack output (system-default sink).

Why

The direct-libusb TX path already existed in FT8TransmitSignal (chosen when audioOutputDeviceId == -1 && usbAudioOutputVendorId != 0), but the only way to select it was to find the … (USB direct) row in the Audio Output device picker — sitting right next to the AudioManager USB Audio entry for the same card, hard to tell apart. The direct path is the robust fix for the mixer-bleed class of problem (other apps' sounds transmitted on air) that the advisory audio-focus work in #597 can only partially mitigate, since notification sounds ignore audio focus.

This exposes it as a clear, reversible toggle instead of touching the (working, timing-sensitive) TX pipeline.

How

  • The toggle is a second view of the same audio-output selection: it reads and writes the exact three persisted config keys (audioOutputDevice, usbAudioOutputVid, usbAudioOutputPid) the device picker uses, so the two controls stay in sync and the setting round-trips across restarts.
  • Enabling with no USB sound card attached refuses and toasts why; enabling requests USB permission just like the picker path.
  • Decision logic extracted to DirectUsbTx.kt (isDirectUsbTxEnabled / directUsbTxSelection / systemDefaultTxSelection) — pure functions, unit-tested. The enable predicate deliberately mirrors the engine's TX-path branch condition so the two can't drift.

Testing

  • New DirectUsbTxTest covers the on/off predicate (including the deviceId-is-−1-but-no-VID edge) and the round-trip of each selection back through the predicate. Passes.
  • ./gradlew assembleDebug clean.
  • Not yet exercised on-device (no phone attached this session). Scope is TX-path only; RX capture is a separate setting.

🤖 Generated with Claude Code

The direct-libusb TX path (FT8TransmitSignal, selected when
audioOutputDeviceId == -1 && usbAudioOutputVendorId != 0) sends the FT8
waveform straight to the USB radio, bypassing Android's shared mixer — so
notification and other-app sounds can't be mixed into the transmission and
go out on air (the mixer-bleed class of problem behind #597). It was only
reachable by picking the "… (USB direct)" row in the Audio Output device
picker, indistinguishable at a glance from the AudioManager "USB Audio"
entry for the same card.

Add a dedicated on/off toggle in Settings → Radio & Audio → Audio that
drives the same three persisted config keys the device picker writes, so
the two controls stay in sync and it round-trips across restarts. Enabling
with no USB sound card present refuses and explains why; enabling requests
USB permission like the picker does. Off falls back to the system-default
AudioTrack sink.

Decision logic is extracted to DirectUsbTx.kt (isDirectUsbTxEnabled /
directUsbTxSelection / systemDefaultTxSelection) with DirectUsbTxTest
covering both directions and the round-trip; the predicate deliberately
mirrors the engine's TX-path branch so they can't drift.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Aug 2, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 12.96296% with 47 lines in your changes missing coverage. Please review.
✅ Project coverage is 35.94%. Comparing base (d01be83) to head (edc8a1e).

Files with missing lines Patch % Lines
...dio/ks3ckc/ft8af/ui/settings/RadioAudioSettings.kt 0.00% 47 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff              @@
##                dev     #722      +/-   ##
============================================
- Coverage     35.98%   35.94%   -0.05%     
  Complexity      289      289              
============================================
  Files           247      248       +1     
  Lines         30276    30330      +54     
  Branches       3989     3994       +5     
============================================
+ Hits          10895    10902       +7     
- Misses        19032    19079      +47     
  Partials        349      349              
Flag Coverage Δ
android 17.55% <12.96%> (-0.02%) ⬇️
native 9.93% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...tlin/radio/ks3ckc/ft8af/ui/settings/DirectUsbTx.kt 100.00% <100.00%> (ø)
...dio/ks3ckc/ft8af/ui/settings/RadioAudioSettings.kt 0.15% <0.00%> (-0.02%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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