@audio/ speaker
Status calibrated
npm2.5.1licenseMIT
Output audio data to speaker in browser/node
Overview
- Install
- Updated
- Family
- 1 packages under it
- Tags
- read & write, platform
Output audio data to speaker in node or browser.
Usage
import speaker from '@audio/speaker'
let write = speaker({
sampleRate: 44100,
channels: 2,
bitDepth: 16,
// bufferSize: 50, // ring buffer ms (default 50)
// backend: 'miniaudio', // force backend
})
write(pcmBuffer, (err) => {
// ready for next chunk
})
write(null) // end playback
Devices
import speaker, { devices } from '@audio/speaker'
await devices()
// [{ id: 'BuiltInSpeakerDevice', name: 'MacBook Pro Speakers', default: true }, …]
let write = speaker({ device: 'headphones' }) // by id, by name, or by part of its name when only one holds it
Ids are the platform's own: CoreAudio's UID, WASAPI's endpoint id, the ALSA or PulseAudio name. A device that isn't there is an error (code: 'ENODEVICE'), never another device. In the browser, devices() reads enumerateDevices() and device becomes the context's sink (setSinkId).
Async iterable
Consume an async iterable source directly:
import speaker from '@audio/speaker'
await speaker.from(audioSource, { sampleRate: 44100, channels: 2 })
Stream
import SpeakerWritable from '@audio/speaker/stream'
source.pipe(SpeakerWritable({ sampleRate: 44100, channels: 2 }))
Backends
Tried in order; first successful one wins.
| Backend | How | Latency | Install |
|---|---|---|---|
miniaudio |
N-API addon wrapping miniaudio.h | Low | Prebuilt via @audio/speaker-* packages |
process |
Pipes PCM to ffplay/sox/aplay | High | System tool must be installed |
null |
Silent, maintains timing contract | — | Built-in (CI/headless fallback) |
webaudio |
AudioWorklet, chunks played back to back (browser only) | Low | Built-in |
On PulseAudio's null sink (headless Linux, CI), any stream, pacat's too, starts up to 2 s late: the idle sink renders 2 s of silence ahead and doesn't take it back for a new stream, as a hardware sink does. Suspend it as soon as it idles: pactl unload-module module-suspend-on-idle && pactl load-module module-suspend-on-idle timeout=0.
API
write = speaker(opts?)
Returns a sink function. Options:
sampleRate— default44100channels— default2bitDepth—8,16(default),24,32bufferSize— ring buffer in ms, default50(browser: audio queued ahead of the write callback, default100)device— an output by id or name (devices()), default the system'sbackend— force a specific backendcontext— browser: the AudioContext to play into; by default the page shares one per sample rate and device (write.context)
write(buffer, cb?)
Write PCM data. Accepts Buffer, Uint8Array, or AudioBuffer. Callback fires when ready for next chunk.
write(null)
End playback. Flushes remaining audio then closes device.
write.flush(cb?)
Wait for buffered audio to finish playing.
write.close()
Immediately close the audio device.
write.backend
Name of the active backend ('miniaudio', 'process', 'null', 'webaudio').
Building
npm run build # compile native addon locally
npm test # run tests
Publishing
# JS-only change (no native code changed):
npm version patch && git push && git push --tags
npm publish
# Native code changed — rebuild platform packages:
npm version patch && git push && git push --tags
gh run watch # wait for CI
rm -rf artifacts
gh run download --dir artifacts \
-n speaker-darwin-arm64 -n speaker-darwin-x64 \
-n speaker-linux-x64 -n speaker-linux-arm64 -n speaker-win32-x64
# (fallback) If darwin-x64 CI is unavailable, cross-compile locally
npx node-gyp@latest rebuild --arch=x64
mkdir -p artifacts/speaker-darwin-x64
cp build/Release/speaker.node artifacts/speaker-darwin-x64/
for pkg in packages/speaker-*/; do
cp artifacts/$(basename $pkg)/speaker.node $pkg/
(cd $pkg && npm publish)
done
npm publish
License
MIT