BufferInput
Server-side audio input provider that accepts pushed audio buffers.
Defined in: src/providers/input/BufferInput.ts:206
Server-side audio input provider that accepts pushed audio buffers.
Remarks
BufferInput allows server-side applications to feed audio data into the CompositeVoice pipeline without any browser dependencies. The application pushes raw audio via push(), and BufferInput wraps each buffer into an AudioChunk with a timestamp and sequence number before delivering it to the registered callback.
The audio format can be declared up-front in the constructor via AudioMetadata, letting the pipeline auto-configure STT encoding/sample-rate settings. Anything left undeclared is filled in by magic-byte detection on the pushed bytes, so a pipeline can accept an arbitrary WAV, OGG, or MP3 buffer with no format configuration at all.
Format resolution order (first defined value wins):
- Fields declared in the constructor
- Fields detected from the container header of the pushed audio
- Raw-PCM defaults — 16 kHz, mono,
linear16
Detection timing matters. The pipeline reads getMetadata() while startListening() runs, which is before the first push(). To have detected values reach the STT provider, sniff the head of the stream with detectFormat() before starting the pipeline. Detection during push() still updates getMetadata() and fires onFormatDetected(), but arrives too late to configure an STT provider that has already connected.
Data-flow diagram:
app.push(data) ──> BufferInput ──callback(chunk)──> InputQueue ──> STT
|
active=true?
yes: emit + sniff format
no: drop
Examples
import { BufferInput } from 'composite-voice';
import { createReadStream } from 'node:fs';
const input = new BufferInput({
sampleRate: 16000,
encoding: 'linear16',
channels: 1,
bitDepth: 16,
});
await input.initialize();
input.onAudio((chunk) => {
console.log(`Received ${chunk.data.byteLength} bytes, seq=${chunk.sequence}`);
});
input.start();
// Stream audio from a file
const stream = createReadStream('audio.raw', { highWaterMark: 4096 });
stream.on('data', (buf: Buffer) => input.push(buf.buffer));
// No format declared — sniff the file header, then let the pipeline configure
// the STT provider from what was found.
import { readFileSync } from 'node:fs';
const audio = readFileSync('speech.wav');
const input = new BufferInput();
input.detectFormat(audio.buffer);
// => { sampleRate: 16000, encoding: 'linear16', channels: 1, bitDepth: 16,
// mimeType: 'audio/wav' }
await voice.startListening();
input.push(audio.buffer);
See
- AudioInputProvider for the interface contract
- BufferInputOptions for the detection toggle
- detectAudioFormat for the underlying magic-byte detection
- MicrophoneInput for the browser-side counterpart
- NullOutput for the server-side output counterpart
Implements
Constructors
Constructor
new BufferInput(metadata?, options?): BufferInput;
Defined in: src/providers/input/BufferInput.ts:299
Creates a new BufferInput instance.
Parameters
| Parameter | Type | Description |
|---|---|---|
metadata | Partial<AudioMetadata> | Format description for the audio that will be pushed. Omit it entirely to rely on detection. |
options | BufferInputOptions | Provider options — see BufferInputOptions. |
Returns
BufferInput
Remarks
The metadata parameter declares the audio format that will be pushed via push(). This metadata is returned by getMetadata() and used by the pipeline to auto-configure the downstream STT provider.
Every field is optional. Undeclared fields are filled in from the container header of the pushed audio, falling back to 16 kHz mono linear16 when the stream carries no recognizable header. Declared fields are never overwritten by detection, so partial declarations work: declare the sample rate you know and let the container supply the rest.
Example
// Fully declared — no detection needed
const input = new BufferInput({
sampleRate: 16000,
encoding: 'linear16',
channels: 1,
bitDepth: 16,
});
// Undeclared — format comes from the pushed buffer's header
const sniffing = new BufferInput();
// Declared format, detection off — pushed headers are ignored
const fixed = new BufferInput(
{ sampleRate: 8000, encoding: 'mulaw', channels: 1 },
{ autoDetect: false }
);
Properties
| Property | Modifier | Type | Default value | Description | Defined in |
|---|---|---|---|---|---|
roles | readonly | readonly ProviderRole[] | undefined | Pipeline roles covered by this provider. Remarks BufferInput is a single-role provider covering only the 'input' slot. It requires a separate STT provider for the 'stt' role. | src/providers/input/BufferInput.ts:223 |
type | readonly | ProviderType | 'rest' | Communication type for this provider. Remarks BufferInput uses 'rest' because it does not maintain a persistent connection — audio is pushed imperatively by the application. | src/providers/input/BufferInput.ts:214 |
Methods
detectFormat()
detectFormat(data): AudioMetadata;
Defined in: src/providers/input/BufferInput.ts:604
Detect the audio format from a buffer without pushing it into the pipeline.
Parameters
| Parameter | Type | Description |
|---|---|---|
data | ArrayBuffer | The start of the audio stream to inspect. |
Returns
The resolved AudioMetadata, identical to what getMetadata() now returns.
Remarks
Runs the same sniffing push() performs, but emits nothing. Call it before startListening() so the detected format reaches the STT provider: the pipeline reads getMetadata() while starting, before any audio has been pushed.
Pass the head of the stream — the first few kilobytes are enough, and the whole file is fine. Detection accumulates across calls, so feeding chunks of a stream one at a time works the same as feeding a single buffer. Once the format resolves, further calls are no-ops until resetDetection().
Works even when autoDetect is disabled — an explicit call is an explicit request. Declared format fields still take precedence in the result.
Example
const audio = readFileSync('speech.ogg');
const input = new BufferInput();
const metadata = input.detectFormat(audio.buffer);
console.log(metadata.encoding, metadata.sampleRate); // 'opus' 48000
await voice.startListening(); // STT is configured from the detected format
input.push(audio.buffer);
See
onFormatDetected for the callback form
dispose()
dispose(): Promise<void>;
Defined in: src/providers/input/BufferInput.ts:326
Dispose of the provider and release all resources.
Returns
Promise<void>
Remarks
Stops accepting audio, clears the callback references, discards any detected format, and resets the sequence counter. After disposal the instance should not be reused.
Implementation of
getDetectedFormat()
getDetectedFormat(): DetectedAudioFormat | null;
Defined in: src/providers/input/BufferInput.ts:477
Get the container format detected from the pushed audio.
Returns
DetectedAudioFormat | null
The detected DetectedAudioFormat, or null when detection has not resolved yet or the stream carries no recognizable container (raw PCM, or an unknown format).
See
isFormatResolved to tell the two null cases apart
getMetadata()
getMetadata(): AudioMetadata;
Defined in: src/providers/input/BufferInput.ts:440
Get the audio format metadata for the audio being pushed.
Returns
The resolved AudioMetadata for the current stream.
Remarks
Merges three sources, in descending priority: the fields declared in the constructor, the fields detected from the pushed stream’s container header, and the raw-PCM defaults (16 kHz mono linear16). The result therefore changes once detection resolves, unless every field was declared.
Used by the pipeline to auto-configure STT encoding, sample rate, and channel settings via configureSTTFromMetadata(). That call happens during startListening() — see the class remarks on detection timing.
See
detectFormat to resolve detection early
Implementation of
AudioInputProvider.getMetadata
initialize()
initialize(): Promise<void>;
Defined in: src/providers/input/BufferInput.ts:313
Initialize the provider, making it ready to accept audio.
Returns
Promise<void>
Remarks
A no-op beyond setting the initialized flag, since BufferInput has no external resources to acquire. If already initialized, this is a no-op.
Implementation of
isActive()
isActive(): boolean;
Defined in: src/providers/input/BufferInput.ts:404
Check whether the provider is actively emitting audio.
Returns
boolean
true when started and not paused.
Implementation of
isFormatResolved()
isFormatResolved(): boolean;
Defined in: src/providers/input/BufferInput.ts:488
Check whether format detection has finished for the current stream.
Returns
boolean
true once enough bytes have been seen to settle on a format — including the raw-PCM fallback, where BufferInput.getDetectedFormat | getDetectedFormat() stays null.
isReady()
isReady(): boolean;
Defined in: src/providers/input/BufferInput.ts:343
Check whether the provider has been initialized.
Returns
boolean
true when initialize has completed and dispose has not yet been called.
Implementation of
onAudio()
onAudio(callback): void;
Defined in: src/providers/input/BufferInput.ts:419
Register a callback to receive audio chunks.
Parameters
| Parameter | Type | Description |
|---|---|---|
callback | (chunk) => void | Function invoked with each AudioChunk when audio is pushed and the provider is active. |
Returns
void
Remarks
Only one callback can be registered at a time; subsequent calls replace the previous callback. Must be called before start().
Implementation of
onFormatDetected()
onFormatDetected(callback): void;
Defined in: src/providers/input/BufferInput.ts:514
Register a callback fired when the audio format is detected.
Parameters
| Parameter | Type | Description |
|---|---|---|
callback | (metadata, format) => void | Invoked with the resolved AudioMetadata and the detected container format, which is null for raw PCM and unknown formats. |
Returns
void
Remarks
Invoked once per stream, as soon as detection resolves — from either push() or BufferInput.detectFormat | detectFormat(). Only one callback can be registered at a time; subsequent calls replace the previous one.
The callback does not fire when autoDetect is disabled and detectFormat() is never called.
Example
input.onFormatDetected((metadata, format) => {
console.log(`Detected ${format ?? 'raw pcm'} at ${metadata.sampleRate} Hz`);
});
pause()
pause(): void;
Defined in: src/providers/input/BufferInput.ts:382
Temporarily pause audio emission without stopping the provider.
Returns
void
Remarks
Audio pushed while paused is silently dropped. Resume with resume().
Implementation of
push()
push(data): void;
Defined in: src/providers/input/BufferInput.ts:552
Push raw audio data into the pipeline.
Parameters
| Parameter | Type | Description |
|---|---|---|
data | ArrayBuffer | Raw audio bytes matching the format declared in the constructor’s AudioMetadata, or any container format listed in DetectedAudioFormat when relying on detection. |
Returns
void
Remarks
Wraps the raw ArrayBuffer into an AudioChunk with a timestamp and monotonically increasing sequence number, then delivers it to the registered callback. If the provider is not active (not started, stopped, or paused), the data is silently dropped.
Unless detection is disabled, the head of the stream is also sniffed for a container signature, updating getMetadata() and firing onFormatDetected(). Sniffing copies at most MAX_SNIFF_BYTES bytes and never delays or alters the emitted chunk — headers are passed through to the STT provider intact, since that is what AudioHeaderCache re-injects on reconnect.
Example
// Push PCM audio from a Node.js Buffer
const pcmBuffer = Buffer.alloc(3200); // 100ms of 16kHz 16-bit mono
input.push(pcmBuffer.buffer);
// Push from a WebSocket message
ws.on('message', (data: ArrayBuffer) => input.push(data));
resetDetection()
resetDetection(): void;
Defined in: src/providers/input/BufferInput.ts:618
Discard the detected format so the next stream is sniffed afresh.
Returns
void
Remarks
Detection resolves once and then stops inspecting bytes, which is what you want for a single stream. Call this between streams — a new file pushed into the same provider, say — so the next one is detected on its own merits. Declared format fields are unaffected.
resume()
resume(): void;
Defined in: src/providers/input/BufferInput.ts:393
Resume audio emission after a pause.
Returns
void
See
Implementation of
start()
start(): void;
Defined in: src/providers/input/BufferInput.ts:358
Start accepting and emitting audio chunks.
Returns
void
Remarks
After calling start(), audio pushed via push() will be delivered to the callback registered with onAudio(). Must be called after initialize().
Implementation of
stop()
stop(): void;
Defined in: src/providers/input/BufferInput.ts:370
Stop accepting audio and cease emitting chunks.
Returns
void
Remarks
Audio pushed after stop() is silently dropped. The provider can be restarted with start().