fix(ios): stereo mic + A2DP output, add vc_audio_restart ABI
Diagnosed by comparing against TeamTalk5 (Client/iTeamTalk), which achieves stereo mic + A2DP output. Five fixes: 1. configureStereoCapture now calls setPreferredInput + setInputDataSource (mirroring TeamTalk5's SoundDevicesModel). Previously omitted based on incorrect diagnosis that setPreferredInput collapsed A2DP — the real culprit was setPreferredInputNumberOfChannels(2), which neither project uses. 2. New C ABI: vc_audio_restart (full stop + re-init, unlike suspend/resume which only stop/start). Swift wrapper added. The withAudioSuspend wrapper that used it was removed after on-device testing showed it killed all audio (including VoiceOver) when switching presets — the core's set_capture_channels handles engine restart internally. 3. Bluetooth options: Voice Chat preset now includes BOTH .allowBluetoothHFP AND .allowBluetoothA2DP (matching TeamTalk5's UtilSound.swift:228). Previously HFP-only blocked A2DP headphones. 4. Capture channels now reset when switching stereo→mono via selectCaptureChannels/applyPreset. AudioSessionManager tracks activeMicStreamId (set by SessionState on join/leave voice). 5. Docs synced: voice.md, tech-stack.md, architecture.md, PROGRESS.md. Removed stale setPreferredInputNumberOfChannels(2) references. Verified: ctest --preset dev 21/21 green, iOS client builds. Stereo mic + A2DP output still needs on-device debugging — the core recipe is correct but iOS 26 route behavior requires hands-on testing with a debugger.
This commit is contained in:
@@ -344,6 +344,19 @@ public final class VoiceCatClient {
|
||||
VoiceCatResult(vc_audio_resume(handle))
|
||||
}
|
||||
|
||||
/// Full audio engine restart — uninitialize and re-initialize the capture and playback
|
||||
/// devices so they pick up a new AVAudioSession route. Call this AFTER reconfiguring
|
||||
/// AVAudioSession (setCategory, setPreferredInput, setPreferredPolarPattern, etc.) so the
|
||||
/// core's devices reopen against the new route. Unlike `audioSuspend()`/`audioResume()`
|
||||
/// (which only stop/start the existing devices, leaving them bound to the route that was
|
||||
/// active when they were opened), this fully re-initializes them. Mirrors TeamTalk5's
|
||||
/// closeSoundDevices()/initSoundInputDevice()/initSoundOutputDevice() pattern. Safe to
|
||||
/// call when the engine is not running (it will just start it).
|
||||
@discardableResult
|
||||
public func audioRestart() -> VoiceCatResult {
|
||||
VoiceCatResult(vc_audio_restart(handle))
|
||||
}
|
||||
|
||||
// MARK: - Receive-side, per remote stream (LOCAL — no protocol traffic; docs/voice.md §10)
|
||||
|
||||
@discardableResult
|
||||
|
||||
Reference in New Issue
Block a user