Bring your own audio
Detector is independent of microphones. It only sees PCM samples, so the audio may come from anywhere.
Required format
Section titled “Required format”Every call to process_audio must contain:
| Property | Required value |
|---|---|
| Sample rate | 16,000 Hz |
| Channels | 1 (mono) |
| Sample type | signed 16-bit PCM (i16) |
| Block size | 160 samples |
| Time represented | 10 ms |
The constants SAMPLE_RATE and AUDIO_BLOCK_SAMPLES avoid magic numbers.
use micro_wakeword::{AUDIO_BLOCK_SAMPLES, Detector};
# fn next_block() -> [i16; AUDIO_BLOCK_SAMPLES] { [0; AUDIO_BLOCK_SAMPLES] }fn main() -> micro_wakeword::Result<()> { let mut detector = Detector::from_config("wake-word.json")?;
loop { let block: [i16; AUDIO_BLOCK_SAMPLES] = next_block(); if let Some(hit) = detector.process_audio(&block)? { println!("Detected {}", hit.wake_word); } }}Where app audio comes from
Section titled “Where app audio comes from”Examples include:
- a WebRTC or voice-call SDK delivering decoded frames;
- a Discord/voice bot receiving Opus packets, then decoding them;
- a browser sending audio over WebSocket;
- an FFmpeg/GStreamer decoding pipeline;
- a game engine’s audio capture callback;
- an embedded or network microphone;
- another Rust capture crate;
- a WAV or raw PCM file.
For compressed data, decode it first. For stereo or another sample rate, downmix and resample before calling the detector.
WebSocket bytes → decode Opus → downmix → resample to 16 kHz → chunks of 160 i16 → DetectorBackpressure and boundaries
Section titled “Backpressure and boundaries”Preserve chronological order and do not fabricate continuity after dropped data. If blocks are lost, a call ends, or you switch speakers, call detector.reset() before continuing.
The detector has no cooldown. Low-level callers should use media timestamps or their own state machine if repeated detections need suppression.