Cross-platform audio recorder library for real-time speech processing in Node.js applications.
npx @tessl/cli install tessl/npm-picovoice--pvrecorder-node@1.2.0PvRecorder is a cross-platform audio recorder library designed for real-time speech audio processing in Node.js applications. It provides frame-based audio capture with configurable buffer sizes, supporting multiple platforms including Linux, macOS, Windows, and Raspberry Pi. The library offers both synchronous and asynchronous APIs for reading audio frames, automatic device enumeration and selection capabilities, and proper resource management.
npm install @picovoice/pvrecorder-nodeimport { PvRecorder } from "@picovoice/pvrecorder-node";For CommonJS:
const { PvRecorder } = require("@picovoice/pvrecorder-node");import { PvRecorder } from "@picovoice/pvrecorder-node";
// Initialize recorder with frame length (required) and optional device index
const recorder = new PvRecorder(512); // 512 samples per frame
// or with specific device: new PvRecorder(512, deviceIndex);
// Start recording
recorder.start();
// Read audio frames
while (recorder.isRecording) {
// Asynchronous read
const frame = await recorder.read();
console.log(`Received ${frame.length} audio samples`);
// Or synchronous read
// const frame = recorder.readSync();
// Process frame (Int16Array with frameLength samples)
// ... your audio processing logic
}
// Stop recording
recorder.stop();
// Clean up resources
recorder.release();PvRecorder is built around several key components:
Core audio recording functionality providing frame-based audio capture from system audio devices.
/**
* PvRecorder constructor
* @param frameLength - Length of audio frames to receive per read call
* @param deviceIndex - Audio device index (-1 for default device, defaults to -1)
* @param bufferedFramesCount - Number of frames buffered internally (defaults to 50)
*/
constructor(
frameLength: number,
deviceIndex: number = -1,
bufferedFramesCount: number = 50
);
/** Start recording audio */
start(): void;
/** Stop recording audio */
stop(): void;
/** Asynchronously read a frame of audio data */
read(): Promise<Int16Array>;
/** Synchronously read a frame of audio data */
readSync(): Int16Array;
/** Release resources acquired by PvRecorder */
release(): void;Audio device enumeration and selection capabilities for choosing specific recording devices.
/**
* Get list of available audio device names
* @throws {Error} When failed to retrieve audio devices
*/
static getAvailableDevices(): string[];
/**
* Get name of the currently selected audio device
* @throws {Error} When failed to get selected device information
*/
getSelectedDevice(): string;Configuration options and runtime monitoring capabilities for optimal recording performance.
/** Enable or disable debug logging for buffer overflows and silence detection */
setDebugLogging(isDebugLoggingEnabled: boolean): void;
/** Get length of audio frames per read call */
get frameLength(): number;
/** Get audio sample rate used by PvRecorder */
get sampleRate(): number;
/** Get version of the PvRecorder library */
get version(): string;
/** Check if PvRecorder is currently recording */
get isRecording(): boolean;PvRecorder operations can throw errors for various failure conditions. All errors are thrown as standard JavaScript Error objects with descriptive messages:
try {
const recorder = new PvRecorder(512, invalidDeviceIndex);
recorder.start();
const frame = await recorder.read();
} catch (error) {
console.error("PvRecorder operation failed:", error.message);
// Handle error appropriately for your use case
}import { PvRecorder } from "@picovoice/pvrecorder-node";
// List available audio devices
const devices = PvRecorder.getAvailableDevices();
console.log("Available devices:", devices);
// Select specific device by index
const recorder = new PvRecorder(512, 0); // Use first device
console.log("Selected device:", recorder.getSelectedDevice());import { PvRecorder } from "@picovoice/pvrecorder-node";
const recorder = new PvRecorder(512);
recorder.setDebugLogging(true); // Enable debug logging
recorder.start();
// Process audio in streaming fashion
const processAudio = async () => {
while (recorder.isRecording) {
try {
const frame = await recorder.read();
// Example: Calculate RMS (root mean square) for volume detection
const rms = Math.sqrt(
frame.reduce((sum, sample) => sum + sample * sample, 0) / frame.length
);
if (rms > 1000) { // Threshold for voice activity
console.log("Voice detected, RMS:", rms);
// Process speech audio...
}
} catch (error) {
console.error("Audio read error:", error);
break;
}
}
};
processAudio();
// Stop after 10 seconds
setTimeout(() => {
recorder.stop();
recorder.release();
}, 10000);import { PvRecorder } from "@picovoice/pvrecorder-node";
// Use larger internal buffer for high-throughput scenarios
const recorder = new PvRecorder(
1024, // Larger frame size
-1, // Default device
100 // Larger buffer (100 frames)
);
console.log(`Sample rate: ${recorder.sampleRate} Hz`);
console.log(`Frame length: ${recorder.frameLength} samples`);
console.log(`Library version: ${recorder.version}`);
recorder.start();
// Synchronous reading for low-latency scenarios
const frames = [];
for (let i = 0; i < 100; i++) {
frames.push(recorder.readSync());
}
recorder.stop();
recorder.release();
console.log(`Recorded ${frames.length} frames of audio`);import { PvRecorder } from "@picovoice/pvrecorder-node";
// Test for invalid constructor parameters as shown in test suite
try {
// Invalid device index (must be >= -1)
const recorder1 = new PvRecorder(512, -2);
} catch (error) {
console.error("Invalid device index:", error.message);
}
try {
// Invalid frame length (must be > 0)
const recorder2 = new PvRecorder(0, 0);
} catch (error) {
console.error("Invalid frame length:", error.message);
}
try {
// Invalid buffered frames count (must be > 0)
const recorder3 = new PvRecorder(512, 0, 0);
} catch (error) {
console.error("Invalid buffered frames count:", error.message);
}
// Valid usage with proper error handling
const recorder = new PvRecorder(512, 0);
// Test recorder state management
console.log("Before start:", recorder.isRecording); // false
recorder.start();
console.log("After start:", recorder.isRecording); // true
recorder.stop();
console.log("After stop:", recorder.isRecording); // false
recorder.release();