decibri 3.3.0

Cross-platform audio capture, output, and processing
Documentation

decibri

Cross-platform audio capture, output, and processing for Node.js and browsers.


Installation

npm install decibri

One package for Node.js and browsers. Node.js gets a native addon (Rust via napi-rs). Browsers get a JavaScript AudioWorklet implementation. Platform-specific binaries are installed automatically.

Requires Node.js >= 18. TypeScript definitions are bundled.


Using from Rust

Most users want the npm package above. If you're building a Rust application directly against the decibri crate on crates.io:

cargo add decibri

The vad feature (enabled by default) uses ONNX Runtime via the ort crate. From 3.1.0 onwards, ort is configured with load-dynamic by default, meaning ONNX Runtime is loaded from a shared library at runtime. Choose one of:

  • Zero-config builds. Opt into the download-binaries mode:

    decibri = { version = "3.1", features = ["ort-download-binaries"], default-features = false }
    

    Add back any other features you need (capture, output, vad, denoise, gain). ORT is downloaded during cargo build and embedded in your binary (the 3.0.x behaviour).

  • Production deployments with bundled ORT. Take default features, then either set ORT_DYLIB_PATH=/path/to/libonnxruntime.{so,dylib,dll} before first use, or call ort::init_from(path).commit() at startup. ONNX Runtime is initialized once per process. If your app creates multiple SileroVad instances with different paths, the first one wins and later paths are silently ignored. Pick one path and reuse it.

If you only need capture, output, or DSP (no Silero VAD), you won't pull in ort at all:

decibri = { version = "3.1", features = ["capture", "output"], default-features = false }

See the ort crate linking docs for runtime-loading details.


Quick Start

Capture audio

const Decibri = require('decibri');

const mic = new Decibri({ sampleRate: 16000, channels: 1 });
mic.on('data', (chunk) => { /* Buffer of Int16 PCM samples */ });
setTimeout(() => mic.stop(), 5000);

Play audio

const { DecibriOutput } = require('decibri');

const speaker = new DecibriOutput({ sampleRate: 16000, channels: 1 });
speaker.write(pcmBuffer);
speaker.end();

Browser capture

import { Decibri } from 'decibri'; // browser entry via conditional export

const mic = new Decibri({ sampleRate: 16000 });
mic.on('data', (chunk) => { /* Int16Array of PCM samples */ });
await mic.start(); // requires user gesture in Safari

Pipe capture to playback (echo)

const mic = new Decibri({ sampleRate: 16000, channels: 1 });
const speaker = new DecibriOutput({ sampleRate: 16000, channels: 1 });
mic.pipe(speaker);

API: Decibri (Capture)

new Decibri(options?)

Creates a Readable stream that captures from the microphone.

Option Type Default Description
sampleRate number 16000 Samples per second (1000–384000)
channels number 1 Input channels (1–32)
framesPerBuffer number 1600 Frames per chunk (64–65536). At 16kHz mono, 1600 = 100ms = 3200 bytes
device number | string system default Device index or case-insensitive name substring
format 'int16' | 'float32' 'int16' Sample encoding
vad boolean false Enable voice activity detection
vadMode 'energy' | 'silero' 'energy' VAD engine: RMS threshold or Silero ML model
vadThreshold number 0.01 / 0.5 Speech threshold. Default depends on vadMode
vadHoldoff number 300 Silence holdoff in ms

Standard ReadableOptions (e.g. highWaterMark) are also accepted.

Methods

Method Description
mic.stop() Stop capture and end stream. Safe to call multiple times
Decibri.devices() List available input devices
Decibri.version() Version info: { decibri: '3.0.0', portaudio: 'cpal 0.17' }

Properties

Property Type Description
mic.isOpen boolean true while capturing

Events

Event Payload Description
'data' Buffer Audio chunk (Int16 LE or Float32 LE)
'backpressure' - Internal buffer full, consumer too slow
'speech' - VAD: audio crosses threshold
'silence' - VAD: audio below threshold for vadHoldoff ms
'end' - Stream ended
'error' Error An error occurred

API: DecibriOutput (Playback)

new DecibriOutput(options?)

Creates a Writable stream for speaker playback.

Option Type Default Description
sampleRate number 16000 Playback sample rate (1000–384000)
channels number 1 Output channels (1–32)
format 'int16' | 'float32' 'int16' Sample encoding of incoming data
device number | string system default Output device index or name substring

Standard WritableOptions (e.g. highWaterMark) are also accepted.

Method / Property Description
speaker.write(chunk) Write PCM data for playback
speaker.end() Signal end. Drains remaining audio, then emits 'finish'
speaker.stop() Immediate stop. Discards remaining audio
speaker.isPlaying true while audio is being output
DecibriOutput.devices() List available output devices
DecibriOutput.version() Same as Decibri.version()

API: Browser

The browser API uses getUserMedia and AudioWorklet. It differs from the Node.js API because browser audio is fundamentally async.

new Decibri(options?)

Same options as Node.js, plus:

Option Type Default Description
device string system default Device ID from Decibri.devices() (not index)
echoCancellation boolean true Browser echo cancellation
noiseSuppression boolean true Browser noise suppression
workletUrl string inline blob Custom worklet URL for strict CSP

Key differences from Node.js

Aspect Node.js Browser
Start Automatic on first read await mic.start()
Base class Readable stream Custom Emitter
Data type Buffer Int16Array / Float32Array
devices() Sync, returns array Async, returns Promise
Sample rate Direct via cpal Resampled from native rate

Voice Activity Detection

Energy mode (default)

Lightweight RMS energy threshold. No model required.

const mic = new Decibri({ vad: true, vadThreshold: 0.01 });
mic.on('speech', () => console.log('speaking'));
mic.on('silence', () => console.log('silent'));

Silero mode

ML-based detection using the Silero VAD v5 ONNX model. More accurate than energy mode, especially in noisy environments.

const mic = new Decibri({ vad: true, vadMode: 'silero', vadThreshold: 0.5 });
mic.on('speech', () => console.log('speaking'));
mic.on('silence', () => console.log('silent'));

The Silero model (~2MB) ships inside the npm package. No downloads or API keys required.


Device Selection

// System default
const mic = new Decibri();

// By name (case-insensitive substring match)
const mic = new Decibri({ device: 'USB' });

// By index
const devices = Decibri.devices();
const mic = new Decibri({ device: devices[1].index });
Decibri.devices();
// [
//   { index: 0, name: 'Microphone', maxInputChannels: 2, defaultSampleRate: 48000, isDefault: true },
//   { index: 1, name: 'USB Headset', maxInputChannels: 1, defaultSampleRate: 44100, isDefault: false }
// ]

Examples

Runnable examples are in examples/.

# Capture to WAV file (no dependencies)
node examples/wav-capture.js

# Stream to WebSocket (requires: npm install ws)
node examples/websocket-server.js   # terminal 1
node examples/websocket-stream.js   # terminal 2

Integration guides for OpenAI, Deepgram, AssemblyAI, and other providers are at decibri.com/docs.


Platform Support

Platform Architecture Audio Backend
Windows x64 WASAPI
macOS arm64 CoreAudio
Linux x64 ALSA
Linux arm64 ALSA
Browser - Web Audio API (AudioWorklet)

How It Works

decibri is a Rust library using cpal for cross-platform audio I/O. The Rust core compiles to a Node.js native addon via napi-rs and ships pre-built binaries for each platform. Browser support uses a JavaScript AudioWorklet implementation with the same event-driven API.

Audio flows from the OS audio device through cpal's callback, into a crossbeam channel, through frame-exact buffering (guarantees consistent chunk sizes), and into Node.js via a threadsafe function. The JavaScript layer wraps this in a standard Readable stream.


License

Apache-2.0 © decibri