Skip to content

Recording & Playback

Jan Janak edited this page Jan 28, 2021 · 9 revisions

Audio Recording

import * as fs from 'fs';
import * as wav from 'wav';
import { PulseAudio, PA_SAMPLE_FORMAT, sampleSize } from '@janakj/pulseaudio.js';

const pa = new PulseAudio();
await pa.connect();

Recording audio with pulseaudio.js is straightforward. Create a new record stream with the method createRecordStream, pipe the stream to a wav write, and pipe the wav writer to a file. When you are done recording, unpipe the streams and destroy the record stream.

// Configure the sample format: 44.1 kHz, stereo, 16 bits per sample
const rate = 44100, channels = 2, format = PA_SAMPLE_FORMAT.S16LE;

// Create a new record stream with the given sample format connected
// to the default source (sound card)
const stream = await pa.createRecordStream({
    sampleSpec : { rate, format, channels }
});

// Create a new wav file writer with the above sample format
const writer = new wav.Writer({
    sampleRate : rate,
    channels,
    bitDepth : sampleSize[format] * 8
});    

// Write the recorded audio to file audio.wav
const file = fs.createWriteStream('audio.wav');

// Pipe the record stream to the write and the writer to the
// filesystem stream
stream.pipe(writer);
writer.pipe(file);

// Keep recording for 10 seconds. Once the time is up, unpipe
// the streams and destroy the record the stream
setTimeout(() => {
    stream.unpipe();
    writer.unpipe();
    stream.destroy();
}, 10000);

It is also possible the specify the maximum length of the recording in bytes by passing a maximumLength property to createRecordStream. In that case, the record stream will end automatically upon recording the given number of bytes, without the need to set a timer.

Audio Playback

The basic playback routine might look as follows. We first create a read stream for a wav file and pipe the stream to a wav reader object. Once the 'format' event has been emitted, we know the sample format of the wav file. We create a new playback stream using createPlaybackStream and pipe the wav reader stream into it. Once the end of the wav file has been reached, the playback stream will be automatically destroyed.

// Create a read stream for the wav file
const file = fs.createReadStream('audio.wav');
const reader = new wav.Reader();

// wait for the wav reader to emit the 'format' event
reader.once('format', async ({ bitDepth, channels, sampleRate: rate }) => {
    // Create a new playback stream using the given parameters
    const output = await pa.createPlaybackStream({
        sampleSpec: {
            format : bitDepth === 16 ? PA_SAMPLE_FORMAT.S16LE : PA_SAMPLE_FORMAT.U8,
            rate,
            channels
        }
    });

    // Pipe the rest of the file into the playback stream
    reader.pipe(output);
});

// Pipe the file stream into the wav reader to get playback started
file.pipe(reader);