feat(audio): prefer native voice backends

This commit is contained in:
Edison Jwa
2026-05-20 14:52:33 +09:00
parent 7d6d56e330
commit c87b47f064
6 changed files with 127 additions and 119 deletions
+16 -22
View File
@@ -1,6 +1,6 @@
[package]
name = "chanora_audio"
description = "Chanora audio subsystem — cpal-based capture/playback, audiopus encode, tsclientlib AudioHandler for decode + jitter buffer + mix. DEC-011, DEC-011.1."
description = "Chanora audio subsystem — platform-native capture/playback, audiopus encode, tsclientlib AudioHandler for decode + jitter buffer + mix. DEC-011, DEC-011.1."
version.workspace = true
edition.workspace = true
rust-version.workspace = true
@@ -14,39 +14,32 @@ chanora_protocol = { path = "../chanora_protocol" }
thiserror.workspace = true
tracing.workspace = true
# Cross-platform audio I/O (DEC-011.1).
cpal = "0.17.3"
# Opus encoder. tsclientlib already pulls this; we depend explicitly so
# this crate can compile against it without going through tsclientlib.
audiopus = "0.3.0-rc.0"
# AudioHandler lives in the tsclientlib crate behind the `audio`
# feature. We import the crate just for the AudioHandler type; the
# Connection type stays inside chanora_protocol.
tsclientlib = { git = "https://github.com/ReSpeak/tsclientlib.git", rev = "04aa2491", default-features = false, features = ["audio"] }
tokio = { version = "1", features = ["sync", "rt", "macros", "time"] }
[target.'cfg(all(not(target_os = "android"), not(target_os = "ios"), not(target_os = "macos")))'.dependencies]
# Desktop audio I/O for Windows capture/playback and Linux capture.
# Linux playback uses SDL2; Apple platforms use direct VoiceProcessingIO
# AudioUnits via `coreaudio-rs` for the voice path.
cpal = "0.17.3"
[target.'cfg(not(target_os = "android"))'.dependencies]
# Desktop/iOS: native TLS maps to the platform TLS backend (Security.framework
# on Apple, SChannel on Windows, system OpenSSL on Linux/BSD).
reqwest = { version = "0.13", default-features = false, features = ["charset", "http2", "native-tls"] }
[target.'cfg(target_os = "ios")'.dependencies]
# Direct CoreAudio AudioUnit access on iOS (DEC-011.x follow-up).
# cpal's iOS backend is unsuitable for VoIP: it opens
# kAudioUnitSubType_RemoteIO with a mono-only output element and no
# control over buffer size / sample rate, AND its AudioUnit stays
# bound to the route present at construction time so user-driven
# `overrideOutputAudioPort` flips do not actually move audio to the
# new transducer. Every production iOS VoIP client (Linphone, Mumble
# iOS, Signal, Jitsi, WebRTC reference) instead drives
# `kAudioUnitSubType_VoiceProcessingIO` (a.k.a. VPIO) directly. VPIO
# is Apple's recommended voice unit; it ships hardware AEC + AGC + NS
# and honours route changes natively because it IS the canonical
# voice unit on iOS. `coreaudio-rs` (RustAudio org, same maintainers
# as `cpal`, 8.6M downloads) gives us a safe wrapper around the
# AudioUnit C API. We use it on iOS only; cpal stays on macOS where
# its CoreAudio backend works well against HAL units.
[target.'cfg(any(target_os = "ios", target_os = "macos"))'.dependencies]
# Direct CoreAudio AudioUnit access on Apple platforms (DEC-011 follow-up).
# cpal's Apple path does not expose the voice-processing controls Chanora
# needs for VoIP. Use `kAudioUnitSubType_VoiceProcessingIO` directly via
# `coreaudio-rs` so capture/playback share Apple's native AEC + AGC + NS
# voice unit on both iOS and macOS.
#
# Default features keep `audio_toolbox` + `core_audio`, both required
# for AudioUnit construction + property access.
@@ -137,8 +130,9 @@ futures-util = { version = "0.3", default-features = false, features = ["std"] }
# options. The portal recommends fresh tokens to scope its own
# object paths per call.
rand = "0.8"
# SDL2 audio for Linux. Replaces the cpal capture / playback paths
# on Linux only; cpal stays in use on Windows/macOS. Rationale: the
# SDL2 audio for Linux. Replaces the cpal playback path on Linux only;
# cpal stays in use for Linux capture and Windows capture/playback.
# Apple platforms use direct VoiceProcessingIO AudioUnits. Rationale: the
# cpal Linux backend opens raw ALSA `default`, which on most Arch
# / Fedora / Debian installs routes through `dmix` + `plug` with
# nearest-neighbour resampling and very small period sizes — the