| Crates.io | sys-voice |
| lib.rs | sys-voice |
| version | 0.2.0 |
| created_at | 2026-01-04 19:33:13.040907+00 |
| updated_at | 2026-01-24 05:10:53.535834+00 |
| description | Cross-platform native voice I/O with OS-level Acoustic Echo Cancellation |
| homepage | |
| repository | https://github.com/tigy32/sys-voice |
| max_upload_size | |
| id | 2022351 |
| size | 681,355 |
Cross-platform native voice I/O with OS-level Acoustic Echo Cancellation (AEC).
Each platform has been roughly tested but this library is likely to have bugs. Contributions welcome.
| Platform | Backend | AEC Method |
|---|---|---|
| macOS | CoreAudio VoiceProcessingIO | Full hardware AEC |
| iOS | AVAudioEngine voiceChat mode | Full hardware AEC |
| Windows | WASAPI IAcousticEchoCancellationControl | Full hardware AEC |
| Linux | PulseAudio | Depends on module-echo-cancel |
| Android | Oboe VoiceCommunication | Hardware AEC |
use sys_voice::{AecConfig, CaptureHandle, Channels};
let config = AecConfig {
sample_rate: 48000,
channels: Channels::Mono,
};
let handle = CaptureHandle::new(config)?;
// Receive samples (async, blocking, or non-blocking)
while let Some(result) = handle.recv_blocking() {
match result {
Ok(samples) => { /* Process AEC-enabled audio samples */ }
Err(e) => { /* Handle audio error */ }
}
}
// Handle automatically stops capture on drop
Run the included test tool to verify AEC is working on your system:
cargo run --example aec_test
The test tool:
aec_recording.wavExpected result: The recording should contain your voice but NOT the 440Hz tone. If you hear the tone clearly in the recording, AEC may not be active on your system.
NSMicrophoneUsageDescription in Info.plistmodule-echo-cancel: pactl load-module module-echo-cancelRECORD_AUDIO permission in AndroidManifest.xmlSee docs/ios-testing.md for detailed instructions on building and testing on iOS devices and simulators.
module-echo-cancel is loaded in the system configuration.#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum Channels {
#[default]
Mono,
Stereo,
}
pub struct AecConfig {
pub sample_rate: u32, // Target sample rate (48000 recommended)
pub channels: Channels, // Mono or Stereo (stereo = duplicated mono)
}
impl CaptureHandle {
pub fn new(config: AecConfig) -> Result<Self, AecError>;
// Async receive (requires async runtime)
pub async fn recv(&self) -> Option<Result<Vec<f32>, AecError>>;
// Blocking receive
pub fn recv_blocking(&self) -> Option<Result<Vec<f32>, AecError>>;
// Non-blocking receive
pub fn try_recv(&self) -> Option<Result<Vec<f32>, AecError>>;
// Get the native sample rate
pub fn native_sample_rate(&self) -> u32;
}
// Capture stops automatically on drop
pub enum AecError {
DeviceUnavailable, // No capture device found
PermissionDenied, // Microphone access denied
AecNotSupported, // Platform doesn't support AEC
InvalidConfig(String), // Invalid configuration
BackendError(String), // Platform-specific error
}
MIT