Decibri includes browser support via conditional exports. When imported in a browser bundle (webpack, vite, etc.), it uses getUserMedia and AudioWorklet to capture raw PCM audio chunks in real-time. Same API as the Node.js version, same npm package.
| Environment | Backend | Entry point |
|---|---|---|
| Node.js | Rust native addon (cpal) | Resolved via conditional export |
| Browser | Web Audio API | Resolved via conditional export |
Capture microphone audio and log the chunk size:
import { Decibri } from 'decibri';
const mic = new Decibri({ sampleRate: 16000 });
mic.on('data', (chunk) => {
console.log(`Received ${chunk.length} samples`);
});
await mic.start();
start() must be called from a user gesture (click/tap) in Safari. Each chunk contains 100 ms of audio by default (1,600 frames at 16 kHz).
Microphone access requires HTTPS (or localhost). The browser will show a permission prompt when start() is called.
start() rejects with Error('Microphone permission denied')'error' event also fires with the same errorDecibri.devices() may be empty before permission is grantedmic.stop();
stop() releases all resources: MediaStream tracks are stopped, AudioContext is closed, all nodes are disconnected, references are nulled. Safe for React/Vue component unmount cycles. Safe to call multiple times or before start().
To restart after stopping:
await mic.start(); // creates a fresh audio pipeline
// Start first to trigger permission, then enumerate with labels
await mic.start();
const devices = await Decibri.devices();
console.log(devices);
// [{ deviceId: 'abc123', label: 'Built-in Microphone', groupId: 'g1' }, ...]
// Use a specific device
const usbMic = new Decibri({ device: devices[1].deviceId });
await usbMic.start();
// Int16 PCM (default) - ready for most STT engines
const mic = new Decibri({ format: 'int16' });
mic.on('data', (chunk) => {
// chunk is an Int16Array
});
// Float32 - native browser format, no conversion
const mic2 = new Decibri({ format: 'float32' });
mic2.on('data', (chunk) => {
// chunk is a Float32Array
});
Enable the built-in VAD to receive 'speech' and 'silence' events based on RMS energy thresholding:
const mic = new Decibri({
sampleRate: 16000,
vad: true,
vadThreshold: 0.01,
vadHoldoff: 300,
});
mic.on('speech', () => console.log('Speaking...'));
mic.on('silence', () => console.log('Silence'));
await mic.start();
const ws = new WebSocket('wss://your-server.com/audio');
const mic = new Decibri({ sampleRate: 16000, format: 'int16' });
mic.on('data', (chunk) => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(chunk.buffer);
}
});
document.getElementById('start').onclick = () => mic.start();
document.getElementById('stop').onclick = () => mic.stop();
Requires HTTPS (or localhost) for microphone access.
| Browser | Minimum Version |
|---|---|
| Chrome | 66+ |
| Firefox | 76+ |
| Safari | 14.1+ (requires user gesture) |
| Edge | 79+ |
| iOS Safari | 14.5+ |
| Android Chrome | 66+ |
By default, decibri loads its AudioWorklet processor via an inline Blob URL. If your Content Security Policy blocks blob: URLs:
const mic = new Decibri({
workletUrl: '/static/decibri-worklet.js',
});
Copy the worklet file from node_modules/decibri/dist/worklet.js to your static assets directory and pass the URL.
new Decibri(options?)Creates a new capture instance. Does not start capture. Call start() to begin.
import { Decibri } from 'decibri';
const mic = new Decibri(options?);
| Option | Type | Default | Description |
|---|---|---|---|
sampleRate |
number |
16000 |
Target sample rate in Hz (1,000 to 384,000) |
channels |
number |
1 |
Number of channels (browsers reliably support 1) |
framesPerBuffer |
number |
1600 |
Frames per chunk. 1,600 at 16 kHz = 100 ms chunks (64 to 65,536) |
device |
string |
system default | deviceId string from Decibri.devices() |
format |
'int16' | 'float32' |
'int16' |
Sample encoding format |
vad |
boolean |
false |
Enable voice activity detection |
vadThreshold |
number |
0.01 |
RMS energy threshold for speech detection (0 to 1) |
vadHoldoff |
number |
300 |
Milliseconds of sub-threshold audio before 'silence' is emitted |
echoCancellation |
boolean |
true |
Browser echo cancellation. Set false for music/tuner apps |
noiseSuppression |
boolean |
true |
Browser noise suppression. Set false for raw signal |
workletUrl |
string |
(inline Blob URL) | URL for AudioWorklet processor file. Override if CSP blocks blob: URLs |
mic.start()Returns Promise<void>. Requests microphone permission and begins capture. Must be called from a user gesture in Safari. No-op if already started. Rejects with a clear error on permission denial.
mic.stop()Stops capture and releases all resources (tracks, context, nodes). Safe to call anytime, including before start() or multiple times. Emits 'end' then 'close'.
mic.isOpenboolean (read-only). Returns true while actively capturing audio.
Decibri.devices()Returns Promise<DeviceInfo[]>. Lists available audio input devices. Labels may be empty before microphone permission is granted.
const devices = await Decibri.devices();
console.log(devices);
// [
// { deviceId: 'abc123', label: 'Built-in Microphone', groupId: 'g1' },
// ...
// ]
Decibri.version()Returns version information for decibri.
Decibri.version();
// { decibri: '3.0.0' }
| Event | Payload | Description |
|---|---|---|
'data' |
Int16Array or Float32Array |
Audio chunk. Format depends on format option. Emitted ~10 times/sec at default settings. |
'error' |
Error |
Permission denied, worklet load failure, AudioContext creation failure. |
'end' |
(none) | Emitted after stop(). |
'close' |
(none) | Emitted after stop(), after 'end'. |
'speech' |
(none) | VAD: RMS energy crossed threshold. Requires vad: true. |
'silence' |
(none) | VAD: sub-threshold audio for vadHoldoff ms. Requires vad: true. |
// DeviceInfo
{
deviceId: string,
label: string,
groupId: string,
}
// VersionInfo
{
decibri: string,
}
| Feature | Node.js decibri |
decibri (browser) |
Notes |
|---|---|---|---|
| Class name | Decibri |
Decibri |
Identical |
| Constructor | Sync, capture starts on read | Sync, requires await start() |
Browser needs async permission |
'data' payload |
Buffer |
Int16Array / Float32Array |
Different types, same PCM data |
devices() |
Sync | Async (returns Promise) | Browser API is async |
device option |
Number index or name substring | String deviceId only |
Browser uses opaque device IDs |
version() |
{ decibri, portaudio } (portaudio key kept for compat) |
{ decibri } |
Different runtime info |
echoCancellation |
N/A | boolean (default true) |
Browser-only option |
noiseSuppression |
N/A | boolean (default true) |
Browser-only option |
'backpressure' event |
Available | Not available | No browser equivalent |
pipe() / streams |
Full Readable stream | Not available | Browser has no Node streams |
sampleRate |
Any (cpal resamples) | Any (AudioWorklet resamples) | Same behavior |
format |
'int16' or 'float32' |
'int16' or 'float32' |
Identical |
VAD (speech/silence) |
RMS-based | RMS-based (same algorithm) | Identical |