iOS: DigiRig Data-VOX operation + FT-891 (audio-only, no CAT) - #751
Merged
Conversation
iOS can't do USB-serial CAT, so the FT-891 runs audio-only via a DigiRig with the radio's Data-VOX keying on TX audio. Makes that path actually work: - Adaptive audio routing (the functional fix): the session forced output to the built-in speaker (.defaultToSpeaker), so TX audio never reached the DigiRig and Data-VOX never keyed. New pure AudioSessionPolicy drops .defaultToSpeaker when a USB audio device is present (output follows to the DigiRig, feeding the radio) and keeps it when none is (bare device RX stays audible). AudioCaptureService applies it at start and re-applies on route change (attach/detach flips it), loop-guarded, clearing a stuck speaker override only when USB is active. - Honest PTT UI: only VOX is offered (CAT/RTS/DTR need a wired CAT link iOS won't allow over USB); enum cases kept for a future Wi-Fi/rigctld bridge; a persisted non-VOX value coerces to VOX. Footer explains why. - FT-891 added to the rig picker. - Data-VOX setup hint in Radio & Audio settings. 597 FT8AFKit tests + 7 new app tests (FT8AFTests target) pass; app builds. xcodegen regenerated (new AudioSessionPolicy + app test target/scheme). On-device verification pending: with a DigiRig + FT-891 attached, confirm TX audio leaves via USB (not speaker), Data-VOX keys, and TX is decodable. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## dev #751 +/- ##
============================================
+ Coverage 41.69% 41.77% +0.08%
Complexity 284 284
============================================
Files 278 280 +2
Lines 32960 33006 +46
Branches 3940 3940
============================================
+ Hits 13742 13788 +46
Misses 18868 18868
Partials 350 350
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
🟡 Changes recommended
Cold-start USB detection precedes session activation, while legacy non-VOX settings are masked rather than normalized.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Enables iOS DigiRig Data-VOX operation by adapting audio routing and adding FT-891 support.
Changes:
- Routes TX audio to connected USB interfaces.
- Restricts iOS PTT selection to VOX and adds setup guidance.
- Adds FT-891 and app-level tests.
File summaries
| File | Description |
|---|---|
AudioSessionPolicyTests.swift |
Tests USB routing policy. |
AudioSessionPolicy.swift |
Defines platform-neutral session options. |
project.yml |
Adds the app test target and scheme. |
RigModelTests.swift |
Tests FT-891 persistence. |
PttModeTests.swift |
Tests selectable PTT modes. |
AudioCaptureSessionOptionsTests.swift |
Tests AVFoundation option mapping. |
TransmissionSettings.swift |
Restricts the PTT picker to VOX. |
RadioAudioSettings.swift |
Adds DigiRig setup guidance. |
AudioCaptureService.swift |
Applies routing policy on startup and route changes. |
AppState.swift |
Adds FT-891 and selectable PTT metadata. |
FT8AF.xscheme |
Registers app tests with the scheme. |
project.pbxproj |
Adds generated test-target configuration. |
Review details
- Files reviewed: 12/12 changed files
- Comments generated: 4
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
- Bootstrap the session into .playAndRecord (neutral options) and activate it BEFORE evaluating USB presence: under the default playback category availableInputs/currentRoute list no inputs, so an already-attached DigiRig read as absent and .defaultToSpeaker was pinned. Observers are now registered before activation so its route change is never missed. - Move the USB-presence predicate into AudioSessionPolicy over AudioPortKind lists (host-tested, one test per detection path) and add bootstrapOptions with tests. - Migrate a persisted CAT/RTS/DTR pttMode to VOX in SettingsPersistence.load via PttMode.coercedForIOS, not just in the picker binding; regression tests cover the helper and the load path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
AudioRouteController is @mainactor, so sharing kind(of:) with the nonisolated AudioCaptureService.usbAudioPresent failed to compile. The mapper is pure; mark it nonisolated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
iOS/iPadOS can't access USB-serial CAT, so the FT-891 runs audio-only through a DigiRig with the radio's Data-VOX keying on the transmit audio. This makes that path actually work and adds the FT-891.
.playAndRecordwith.defaultToSpeaker, which pins output to the built-in speaker — so TX audio never reached the DigiRig's USB output and Data-VOX never keyed. New pureAudioSessionPolicy.playAndRecordOptions(usbAudioConnected:)drops.defaultToSpeakerwhen a USB audio device is present (output follows to the DigiRig, feeding the radio) and keeps it when none is (bare iPhone/iPad RX stays audible — no regression).AudioCaptureServiceapplies it atstart()and re-applies on route change so a DigiRig attach/detach flips the behavior; loop-guarded (ignores category/override reasons, only re-sets when options differ), and clears a stuckbuiltInSpeakeroverride only while USB is active.Tests
597 FT8AFKit tests pass (2 new
AudioSessionPolicyTests) + 7 new app tests in a newFT8AFTeststarget (RigModelTestsFT-891 present/round-trip,PttModeTestsselectable ==[.vox],AudioCaptureSessionOptionsTestsneutral→AVAudioSession.CategoryOptions). App builds.xcodegenregenerated for the new file + test target/scheme.On-device verification pending
USB output routing is device behavior — with a DigiRig + FT-891 attached, confirm TX audio leaves via USB (not the speaker), the FT-891's Data-VOX keys on the FT8 tones, and the transmission is decodable/spotted; and that attach/detach flips output between speaker and USB.
🤖 Generated with Claude Code