[package] name = "chanora_audio" 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 authors.workspace = true license.workspace = true repository.workspace = true publish.workspace = true [features] default = [] bench-harness = ["dep:criterion", "dep:dhat", "dep:serde_json"] [dependencies] chanora_protocol = { path = "../chanora_protocol" } thiserror.workspace = true tracing.workspace = true sonora = "0.1" webrtc-vad = "0.4" # ndarray is required by ort's tensor construction API and by # Silero VAD ONNX inference across all platforms. ndarray = "0.17" # 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"] } rustfft = "6.2.0" criterion = { version = "0.5", optional = true } dhat = { version = "0.3", optional = true } serde_json = { version = "1", optional = true } [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 fallback metadata. # Linux voice I/O uses PipeWire first and PulseAudio as fallback; Apple platforms use direct VoiceProcessingIO # AudioUnits via `coreaudio-rs` for the voice path. cpal = "0.17.3" [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. coreaudio-rs = "0.14" # Grand Central Dispatch bindings — used to run AudioUnit initialize/start # on the main queue to avoid the VPIO RPC timeout on iOS simulator. dispatch2 = "0.3" [target.'cfg(target_os = "ios")'.dependencies] # ONNX Runtime Rust binding for Silero VAD v6 (P1 VAD_002). The official # iOS CocoaPod ships ONNX Runtime as a static framework, so iOS links it # into chanora_bridge at build time instead of loading a dylib at runtime. ort = { version = "2.0.0-rc.12", default-features = false, features = ["std", "ndarray"] } [target.'cfg(not(target_os = "ios"))'.dependencies] ort = { version = "2.0.0-rc.12", default-features = false, features = ["load-dynamic", "ndarray", "api-24"] } [target.'cfg(target_os = "android")'.dependencies] # JNI bindings to flip Android's AudioManager into MODE_IN_COMMUNICATION # when the voice-comm preset is requested. ndk_context is initialised # by the bridge crate's android_init shim. jni = { version = "0.21", default-features = false } ndk-context = "0.1" # Oboe-rs (Google Oboe wrapper) for low-latency voice capture + playback. # Primary backend for SDD-111..SDD-115. The pre-compiled static library # shipped with `oboe-sys` 0.6 covers armv7 / aarch64 / x86 / x86_64. # Default features keep the precompiled library + pregenerated bindings # so we avoid the clang-sys / libclang requirement on the build host. # # Using local fork edisonjwa/oboe-rs (v0.6.2) with: # - catch_unwind safety in callbacks # - unwrap_or_default in enum getters (no more SessionId panic) # - get_raw_session_id() for JNI hardware effect binding # - deduplicated macro impls # - PowerSavingOffloaded PerformanceMode variant oboe = { path = "../../../oboe-rs" } [target.'cfg(target_os = "windows")'.dependencies] # Real Windows global PTT (SDD-083 / SDD-084): RegisterRawInputDevices # + WM_INPUT translation backed by a hidden message-only window, and # SetWindowsHookExW(WH_KEYBOARD_LL / WH_MOUSE_LL) fallback. Both # require a per-backend OS thread that owns a message pump. windows = { version = "0.54", features = [ "Win32_Foundation", "Win32_Graphics_Gdi", "Win32_System_LibraryLoader", "Win32_System_Threading", "Win32_UI_Input", "Win32_UI_Input_KeyboardAndMouse", "Win32_UI_WindowsAndMessaging", ] } [dev-dependencies] # `test-util` enables `start_paused` / virtual-clock tests used by # the missed-key-up watchdog unit tests. tokio = { version = "1", features = ["sync", "rt", "macros", "time", "test-util"] } # Cross-platform recording Layer for the SDD-090 / DEC-027 privacy # invariant integration test (`tests/ptt_privacy.rs`). tracing-subscriber = { version = "0.3", features = ["registry"] } [[bench]] name = "realtime_capture" harness = false path = "benches/realtime_capture.rs" required-features = ["bench-harness"] [[bench]] name = "opus_codec" harness = false path = "benches/opus_codec.rs" required-features = ["bench-harness"] [[bench]] name = "resampler" harness = false path = "benches/resampler.rs" required-features = ["bench-harness"] [[example]] name = "compare_baseline" path = "examples/compare_baseline.rs" required-features = ["bench-harness"] [[example]] name = "emit_baseline" path = "examples/emit_baseline.rs" required-features = ["bench-harness"] [target.'cfg(target_os = "linux")'.dependencies] # GNOME-on-Wayland Global Push-to-Talk uses the freedesktop # `org.freedesktop.portal.GlobalShortcuts` interface over D-Bus. # `zbus` is the standard async D-Bus crate; the `tokio` runtime # selector is mandatory in zbus 5; we share the tokio runtime # the rest of the audio + core crates already depend on. The # `blocking-api` feature is retained so the audio-engine # probe path can do a synchronous portal-version read without # starting an async runtime; the live session flow uses the # async surface. zbus = { version = "5", default-features = false, features = ["tokio", "blocking-api"] } # Stream / sink utilities for consuming portal signals on the # async path. futures-util = { version = "0.3", default-features = false, features = ["std"] } # Random token bytes for the portal handle_token / session_handle_token # options. The portal recommends fresh tokens to scope its own # object paths per call. rand = "0.8" # Linux-native voice I/O. PipeWire is primary on modern desktops; # PulseAudio is retained as fallback and for older environments. pipewire = { version = "0.10", features = ["v0_3_44"] } libpulse-binding = "2.30" libpulse-simple-binding = "2.29"