Skip to content

Bring your own audio

Detector is independent of microphones. It only sees PCM samples, so the audio may come from anywhere.

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);
}
}
}

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 → Detector

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.