feat(ios): audio overhaul, Join/Leave Voice, channel-id sync fix, stereo mic capture
Three iOS client problems fixed plus a new core stereo-mic capture ABI: 1. Channel-id sync bug (mic button permanently dimmed): SessionState never synced currentChannelId from the self user's channelId on connect, so the mic button (gated on currentChannelId == 0) stayed dimmed. Added syncSelfChannel() (mirrors macOS MainWindowController.swift:461,491,522); called from init/.channelList/.userJoined/.userLeft/.userUpdated/.joinResult. Added applyServerMuteState() + serverMuted/serverDeafened to VoiceState. 2. Join/Leave Voice button: replaced icon-only mic toggle with explicit text button (parity with macOS). Mute/deafen disable when not in voice. 3. IOSAudioRouter.swift (new): full AVAudioSession routing layer — input port selection, built-in mic orientation/polar patterns, Bluetooth HFP/A2DP/Off modes, Standard/Raw mic processing, stereo capture, AirPlay, UserDefaults persistence. AudioSessionManager delegates to it. 4. Core stereo-mic capture (append-only ABI): vc_set_capture_channels() lets the core open the mic device in stereo (2-ch interleaved). LocalStream gains capture_channels; ensure_audio_running reads it; audio_engine.cpp capture_accum_ + on_capture updated to channel-aware accumulation. Test test_stereo_mic_capture (headless, L!=R stereo round-trip). Swift wrapper VoiceCatClient.setCaptureChannels. 5. Settings UI rework: AVAudioSession-derived input/output tree replaces miniaudio device picker. 6. iOS deployment target raised to 18.0 (Package.swift + project.pbxproj). swift-tools-version 6.0 with swiftLanguageModes .v5. Docs: tech-stack.md, architecture.md, voice.md, roadmap.md, building.md updated; stale 'vc_audio_suspend/resume deferred' claims corrected. Verified: ctest --preset dev 21/21 green; swift test 6/6 green; xcodebuild -target VoiceCatiOS -sdk iphonesimulator BUILD SUCCEEDED.
This commit is contained in:
52
PROGRESS.md
52
PROGRESS.md
@@ -172,8 +172,56 @@ up instantly. Newest status at the top.
|
||||
controls the *mic* path which still uses miniaudio's device.
|
||||
|
||||
|
||||
- **Planned (not started):** **iOS audio overhaul + Join/Leave Voice + channel-id sync fix**
|
||||
(2026-06-19, plan written on Windows; implement on Mac). Three problems found while reviewing
|
||||
- **Done:** **iOS audio overhaul + Join/Leave Voice + channel-id sync fix** (2026-06-19).
|
||||
Three problems found while reviewing the iOS client, all fixed:
|
||||
1. **Mic button permanently dimmed (BUG — fixed).** `VoiceControlsView.swift:26` gated the
|
||||
mic button on `session.currentChannelId == 0`, but `SessionState` never synced
|
||||
`currentChannelId` from the self user's `channelId` on connect. The server auto-places
|
||||
every newly-authed user into the Lobby (channel 1, `server/src/session_registry.cpp:111`),
|
||||
but the iOS client ignored it. **Fix:** added `syncSelfChannel()` (mirrors macOS
|
||||
`MainWindowController.swift:461,491,522`); called from `init`, `.channelList`,
|
||||
`.userJoined`/`.userLeft`/`.userUpdated`, `.joinResult`. Added
|
||||
`applyServerMuteState(muted:deafened:)` (mirrors macOS lines 693-700); called from
|
||||
`.userUpdated`. Added `serverMuted`/`serverDeafened` to `VoiceState`.
|
||||
2. **No Join/Leave Voice button (fixed — parity with macOS).** Replaced the icon-only mic
|
||||
toggle with an explicit "Join Voice"/"Leave Voice" text button (mirrors macOS
|
||||
`micToggleButton`). Mute/deafen buttons now disable when not in voice. PTT path kept.
|
||||
3. **Limited audio input/output options (fixed — full `IOSAudioRouter.swift`).** New
|
||||
`IOSAudioRouter` singleton drives all iOS audio routing via `AVAudioSession` before the
|
||||
core (miniaudio) opens its device: input port selection (`availableInputs`), built-in mic
|
||||
orientation (`setPreferredDataSource`: front/back/top/bottom), polar patterns
|
||||
(`setPreferredPolarPattern`: omni/cardioid/subcardioid/bidirectional), Bluetooth mode
|
||||
(`.allowBluetooth` HFP voice / `.allowBluetoothA2DP` stereo output / neither), mic
|
||||
processing mode (`.voiceChat` Standard with AEC/AGC/HPF / `.measurement` Raw with all
|
||||
processing off + speaker echo warning), stereo capture
|
||||
(`setPreferredInputNumberOfChannels(2)` → `vc_set_capture_channels`), AirPlay via
|
||||
`AVRoutePickerView`. All choices persisted in `UserDefaults`; re-applied on route changes.
|
||||
`AudioSessionManager` refactored to delegate routing to `IOSAudioRouter`.
|
||||
4. **Core stereo-mic capture (new C ABI: `vc_set_capture_channels`).** Append-only ABI
|
||||
addition: `vc_result vc_set_capture_channels(vc_client*, uint32_t stream_id, uint32_t
|
||||
channels)` (1=mono, 2=stereo). `LocalStream` gained a `capture_channels` field;
|
||||
`ensure_audio_running()` reads it into `AudioParams.capture_channels` before the device
|
||||
opens. `audio_engine.cpp` `capture_accum_` sized to `frame_samples_ * capture_channels`;
|
||||
`on_capture` updated to the same channel-aware accumulation pattern as `on_loopback`.
|
||||
Skeleton stub added. Test `test_stereo_mic_capture` (headless, feeds L≠R stereo through
|
||||
the mic accumulator path, asserts L≠R end-to-end). `ctest --preset dev` — **21/21 green**.
|
||||
Swift wrapper: `VoiceCatClient.setCaptureChannels(streamId:channels:)`.
|
||||
5. **Settings UI rework.** `SettingsView` replaced the miniaudio-based device picker with
|
||||
the AVAudioSession-derived tree: Audio Input (port picker → built-in mic
|
||||
orientation/polar pattern sub-pickers + mic mode Standard/Raw + channels Mono/Stereo),
|
||||
Audio Output (bluetooth mode + current route read-only + AirPlay), Voice (input mode,
|
||||
VAD threshold).
|
||||
6. **Deployment target raised to iOS 18.0.** `Package.swift` + `project.pbxproj` (4
|
||||
occurrences). Unlocks newest AVAudioSession APIs.
|
||||
7. **Docs updated:** `docs/tech-stack.md` §2 (iOS audio routing via IOSAudioRouter, stereo
|
||||
mic, deployment 18.0, fixed stale "deferred" claim about `vc_audio_suspend`/`resume`),
|
||||
`docs/architecture.md` §4 (Swift binding notes — IOSAudioRouter, fixed stale "deferred"
|
||||
claim), `docs/voice.md` (new iOS mic capture subsection), `docs/roadmap.md` (iOS pending
|
||||
list updated), `docs/building.md` §9 (deployment target 18.0), `PROGRESS.md` (this entry).
|
||||
- **Verified:** `cmake --build --preset dev` + `ctest --preset dev` — **21/21 green**
|
||||
(including new `test_stereo_mic_capture`: `total_diff=8433549, seen_channels=2`).
|
||||
- **Original plan (kept for reference):**
|
||||
Three problems found while reviewing
|
||||
the iOS client:
|
||||
1. **Mic button permanently dimmed (BUG — root cause).** `VoiceControlsView.swift:26` gates the
|
||||
mic button on `session.currentChannelId == 0`, but `SessionState` never syncs
|
||||
|
||||
Reference in New Issue
Block a user