Cross-platform microphone audio capture for Node.js.
Pre-built binaries for Windows, macOS, and Linux. No build tools, no SoX, no system dependencies required.
| Meta |
|
| Binaries |
|
npm install @analyticsinmotion/micstreamPre-compiled binaries for all supported platforms are bundled inside the package and loaded automatically by node-gyp-build. If no binary is available for your platform, it falls back to compiling from source (requires build tools and libasound2-dev on Linux).
const MicStream = require('@analyticsinmotion/micstream');
const mic = new MicStream();
mic.on('data', (chunk) => {
// chunk is a Buffer of 16-bit signed integer PCM samples (little-endian)
// default: 16kHz, mono, 1600 frames per chunk (100ms)
});
mic.on('error', (err) => {
console.error('Microphone error:', err);
});
// Stop after 10 seconds
setTimeout(() => mic.stop(), 10000);const fs = require('fs');
const MicStream = require('@analyticsinmotion/micstream');
const mic = new MicStream({ sampleRate: 44100, channels: 2 });
const out = fs.createWriteStream('capture.raw');
mic.pipe(out);
setTimeout(() => mic.stop(), 5000);const MicStream = require('@analyticsinmotion/micstream');
const mic = new MicStream({ sampleRate: 16000, channels: 1 });
mic.on('data', (chunk) => {
speechEngine.feed(chunk); // pass raw PCM directly
});TypeScript definitions are bundled. No @types/ package needed.
import MicStream, { DeviceInfo, MicStreamOptions } from '@analyticsinmotion/micstream';
const options: MicStreamOptions = { sampleRate: 16000, channels: 1 };
const mic = new MicStream(options);
mic.on('data', (chunk: Buffer) => {
// zero-copy Int16 view over the same memory
const samples = new Int16Array(chunk.buffer, chunk.byteOffset, chunk.length / 2);
});
mic.on('backpressure', () => console.warn('Consumer too slow'));
const devices: DeviceInfo[] = MicStream.devices();Creates a Readable stream that captures from the system default microphone.
| Option | Type | Default | Description |
|---|---|---|---|
sampleRate |
number | 16000 |
Samples per second (1000–384000) |
channels |
number | 1 |
Number of input channels (1–32) |
framesPerBuffer |
number | 1600 |
Frames per audio callback (64–65536) |
device |
number | string | system default | Device index from MicStream.devices() or case-insensitive name substring |
format |
'int16' | 'float32' |
'int16' |
Sample encoding — 16-bit signed integer or 32-bit IEEE 754 float |
vad |
boolean | false |
Enable voice activity detection |
vadThreshold |
number | 0.01 |
RMS energy threshold for speech (0–1) |
vadHoldoff |
number | 300 |
Silence holdoff in ms before 'silence' is emitted |
Standard Node.js Readable stream options (e.g. highWaterMark) are also accepted.
Stops microphone capture and ends the stream. Safe to call multiple times.
Emitted when push() returns false, meaning the stream's internal buffer is full and the consumer is reading too slowly. Because a microphone cannot be paused, audio chunks will continue to arrive. Callers should drain the stream or drop data to avoid unbounded memory growth.
Emitted when the RMS energy of an audio chunk crosses vadThreshold. Requires vad: true.
Emitted when audio stays below vadThreshold for vadHoldoff ms after a speech period. Requires vad: true.
true if the microphone is currently capturing.
Returns an array of available input devices on the system.
const devices = MicStream.devices();
// [
// { index: 0, name: 'Built-in Microphone', maxInputChannels: 1, defaultSampleRate: 44100, isDefault: true },
// ...
// ]Returns version information for micstream and the bundled PortAudio.
MicStream.version();
// { micstream: '0.4.0', portaudio: 'PortAudio V19.7.0-devel...' }Runnable examples are in examples/.
No external dependencies.
node examples/wav-capture.js
# writes capture.wav (5 seconds, 16 kHz mono)The WebSocket examples require the ws package, which is not bundled with micstream. Install it before running:
npm install wsThen in two terminals:
# Terminal 1 — start receiver
node examples/websocket-server.js
# Terminal 2 — start streaming
node examples/websocket-stream.js
# streams raw PCM to ws://localhost:8080All audio is captured as 16-bit signed integer PCM, little-endian. This is the raw format expected by most speech and wake-word engines (Vosk, sherpa-onnx, whisper.cpp, openWakeWord).
Each data event emits a Buffer where every 2 bytes is one 16-bit sample:
mic.on('data', (chunk) => {
const samples = new Int16Array(chunk.buffer, chunk.byteOffset, chunk.length / 2);
// samples[0], samples[1], ...
});| Platform | Architecture | Audio Backend |
|---|---|---|
| Windows 11 | x64 | WASAPI |
| macOS (Apple Silicon) | arm64 | CoreAudio |
| Linux | x64 | ALSA |
| Linux | arm64 | ALSA |
| Platform | Requirements |
|---|---|
| macOS Intel (pre-2020) | Xcode CLI tools: xcode-select --install |
| Windows ARM64 | Visual C++ Build Tools |
| Platform | Reason |
|---|---|
| Windows 32-bit | N-API native addons require 64-bit |
Requires Node.js >= 16, node-gyp, and platform build tools.
Linux:
sudo apt-get install -y build-essential libasound2-devmacOS:
xcode-select --installWindows: Install Visual C++ Build Tools.
Then:
git clone --recurse-submodules https://github.com/analyticsinmotion/micstream.git
cd micstream
npm install
npm run buildmicstream wraps PortAudio, the standard cross-platform audio I/O library, as a Node.js native addon using N-API. PortAudio is compiled from source and statically linked, so there is no system PortAudio dependency.
The native addon opens the default input device, runs a PortAudio callback in an audio thread, and forwards PCM chunks to JavaScript via an N-API ThreadSafeFunction. The JavaScript layer wraps this in a standard Node.js Readable stream.
Apache-2.0 © Analytics in Motion