Expand description
Cross-platform audio capture, playback, and voice-activity detection.
decibri records from a microphone, plays audio to a speaker, and runs Silero voice-activity detection through one API on Windows, macOS, and Linux. It is the Rust core that also powers decibri’s Python and Node.js packages.
§Orientation
There are two primary types: Microphone for input and Speaker for
output. Both follow the same shape: build a configuration, construct the
object, then call start() to open the device and obtain a stream.
- A
Microphoneyields aMicrophoneStreamyou pullAudioChunks from withnext_chunk. - A
Speakeryields aSpeakerStreamyou pushf32samples to withsend.
Voice-activity detection runs through SileroVad: construct it once, then
call process on each chunk’s samples.
List devices with input_devices / output_devices (or
Microphone::devices / Speaker::devices) and pick one with a
DeviceSelector. Every fallible operation returns DecibriError.
§Feature flags
| Flag | Default | Purpose |
|---|---|---|
capture | on | Microphone input stream support |
playback | on | Speaker output stream support |
vad | on | Silero voice-activity detection (pulls ort) |
ort-load-dynamic | on | ONNX Runtime loaded at runtime from a path |
ort-download-binaries | off | ONNX Runtime downloaded at build time |
ort-load-dynamic and ort-download-binaries are mutually exclusive;
selecting both is a compile error. Disabling vad drops the ONNX Runtime
dependency entirely.
Execution-provider features (coreml, cuda, directml, rocm) are off by
default and opt in to GPU acceleration on specific platforms. See
docs/features.md
for the full reference.
§Example: capture and detect speech
MicrophoneStream::next_chunk
returns a three-state Result: Ok(Some(chunk)) with data, Ok(None) on a
timeout while the stream is still open, and
Err(DecibriError::MicrophoneStreamClosed) once the stream ends.
use std::time::Duration;
use decibri::{Microphone, MicrophoneConfig, SileroVad, VadConfig, DecibriError};
let microphone = Microphone::new(MicrophoneConfig::default())?;
let stream = microphone.start()?;
let mut vad = SileroVad::new(VadConfig::default())?;
// 1600 interleaved samples = one 100 ms block of mono 16 kHz audio
// (frames_per_buffer * channels for the default config).
loop {
match stream.next_chunk(1600, Some(Duration::from_millis(100))) {
Ok(Some(chunk)) => {
let result = vad.process(&chunk.data)?;
if result.is_speech {
println!("speech @ p={:.2}", result.probability);
}
}
Ok(None) => continue,
Err(DecibriError::MicrophoneStreamClosed) => break,
Err(e) => return Err(e.into()),
}
}§Process-global ORT initialization
ONNX Runtime initializes exactly once per process. The first successful
SileroVad::new call wins; later constructions
with a different vad::VadConfig::ort_library_path silently reuse the
first path. See vad::VadConfig for details.
§ORT error construction has FFI side effects
Under ort-load-dynamic, constructing any ort::Error calls into the
ORT C API (ortsys![CreateStatus]), which in turn triggers ORT dylib
loading. If the dylib path is invalid (missing file, a directory, or a
wrong-arch binary), this load can hang indefinitely on some hosts
(reproduced on Windows with pyke/ort 2.0.0-rc.12 and onnxruntime 1.24.4).
For authors writing FFI bindings on top of decibri: when you need to
surface a “this ORT path is wrong” failure from a pre-load check, use
DecibriError::OrtPathInvalid
(carries path: PathBuf and reason: &'static str, never touches ORT
symbols) rather than reconstructing an ort::Error. decibri’s internal
init_ort_once follows this pattern: it performs a filesystem-level
Path::is_file() check first and returns
OrtPathInvalid on rejection,
only handing the path to ort::init_from once the check passes.
This constraint is why DecibriError splits
“ORT path failure” across two variants:
OrtLoadFailed carries an
ort::Error source (reached after ort::init_from genuinely failed,
by which point ORT is loaded and constructing errors is safe), and
OrtPathInvalid does not
(reached before any ORT symbol is touched). The
is_ort_path_error helper
groups both so consumers don’t need to match the variant distinction.
§Fork safety
Once ORT has been initialized in a process (via the first
SileroVad::new call), that process’s ORT
state survives across fork(). ORT is not designed to have its
runtime state cloned into a forked child: internal threads, memory
pools, and device handles belonging to the parent may misbehave in
the child.
Python consumers using
multiprocessing
should call multiprocessing.set_start_method('spawn', force=True)
before importing decibri. This gives each child its own fresh ORT
state rather than inheriting the parent’s.
Node.js consumers using child_process or worker_threads are
unaffected; those mechanisms do not share ORT state across workers.
§Thread safety
All public types are Send and suitable for cross-thread handoff.
microphone::MicrophoneStream and speaker::SpeakerStream are also
Sync (they hold their live platform audio stream behind an internal
mutex), so they can be shared across threads, for example via an Arc,
without external synchronization.
§Stability
The following stream surface is stable and changes signature only with a breaking version bump:
Re-exports§
pub use microphone::AudioChunk;pub use microphone::DenoiseModel;pub use microphone::HighpassFilter;pub use microphone::Microphone;pub use microphone::MicrophoneConfig;pub use microphone::MicrophoneStream;pub use file::File;pub use file::FileConfig;pub use file::Segment;pub use file::VadReport;pub use file::VadWindow;pub use speaker::Speaker;pub use speaker::SpeakerConfig;pub use speaker::SpeakerSink;pub use speaker::SpeakerStream;pub use device::input_devices;pub use device::output_devices;pub use device::DeviceSelector;pub use device::MicrophoneInfo;pub use device::SpeakerInfo;pub use vad::SileroVad;pub use vad::VadConfig;pub use vad::VadResult;pub use error::DecibriError;
Modules§
- denoise
- Single-channel speech enhancement (denoise) for the capture path.
- device
- Audio device discovery and selection.
- error
- file
- Offline audio source.
- gain
- Adaptive level control for the capture chain.
- microphone
- Microphone capture: open an input device and pull
AudioChunks from it. - sample
- speaker
- Speaker playback: open an output device and push
f32samples to it. - vad
- Voice Activity Detection using the Silero VAD v5 ONNX model.
Constants§
- CPAL_
VERSION - Resolved cpal version (major.minor) extracted at build time from the
crate’s
Cargo.toml.