Skip to content

analyticsinmotion/micstream

Repository files navigation

micstream-github-logo-rectangle

micstream

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 npm version  Apache 2.0 License  Analytics in Motion
Binaries Windows x64  macOS ARM64  Linux x64  Linux ARM64

Installation

npm install @analyticsinmotion/micstream

Pre-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).


Usage

Stream PCM audio from the default microphone

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

Pipe to a file

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

Pipe to a speech engine

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

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

API

new MicStream(options?)

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.

mic.stop()

Stops microphone capture and ends the stream. Safe to call multiple times.

Event: 'backpressure'

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.

Event: 'speech'

Emitted when the RMS energy of an audio chunk crosses vadThreshold. Requires vad: true.

Event: 'silence'

Emitted when audio stays below vadThreshold for vadHoldoff ms after a speech period. Requires vad: true.

mic.isOpen

true if the microphone is currently capturing.

MicStream.devices()

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 },
//   ...
// ]

MicStream.version()

Returns version information for micstream and the bundled PortAudio.

MicStream.version();
// { micstream: '0.4.0', portaudio: 'PortAudio V19.7.0-devel...' }

Examples

Runnable examples are in examples/.

Capture to WAV file

No external dependencies.

node examples/wav-capture.js
# writes capture.wav (5 seconds, 16 kHz mono)

Stream to WebSocket

The WebSocket examples require the ws package, which is not bundled with micstream. Install it before running:

npm install ws

Then 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:8080

Audio format

All 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 Support

Pre-built binaries (zero setup)

Platform Architecture Audio Backend
Windows 11 x64 WASAPI
macOS (Apple Silicon) arm64 CoreAudio
Linux x64 ALSA
Linux arm64 ALSA

Source build fallback (requires build tools)

Platform Requirements
macOS Intel (pre-2020) Xcode CLI tools: xcode-select --install
Windows ARM64 Visual C++ Build Tools

Not supported

Platform Reason
Windows 32-bit N-API native addons require 64-bit

Building from source

Requires Node.js >= 16, node-gyp, and platform build tools.

Linux:

sudo apt-get install -y build-essential libasound2-dev

macOS:

xcode-select --install

Windows: Install Visual C++ Build Tools.

Then:

git clone --recurse-submodules https://github.com/analyticsinmotion/micstream.git
cd micstream
npm install
npm run build

How it works

micstream 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.


License

Apache-2.0 © Analytics in Motion

About

Cross-platform microphone audio capture for Node.js with pre-built binaries. No build tools required.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors