Skip to main content

AudioEncoder

The AudioEncoder class encodes raw AudioData objects into compressed EncodedAudioChunk objects. It supports common audio codecs like AAC, MP3, Opus, FLAC, and Vorbis through FFmpeg.

Quick Example

import { AudioEncoder, AudioData } from 'node-webcodecs';

// Create an AAC encoder
const encoder = new AudioEncoder({
  output: (chunk, metadata) => {
    console.log(`Encoded ${chunk.byteLength} bytes at ${chunk.timestamp}μs`);

    // First chunk includes decoder config
    if (metadata?.decoderConfig) {
      console.log('Decoder config:', metadata.decoderConfig);
    }
  },
  error: (err) => console.error('Encoding error:', err)
});

// Configure for AAC-LC at 128kbps
encoder.configure({
  codec: 'mp4a.40.2',      // AAC-LC
  sampleRate: 48000,
  numberOfChannels: 2,
  bitrate: 128_000
});

// Create audio data from raw samples
const audioData = new AudioData({
  format: 'f32-planar',
  sampleRate: 48000,
  numberOfFrames: 1024,
  numberOfChannels: 2,
  timestamp: 0,
  data: audioSamples
});

// Encode and close the source data
encoder.encode(audioData);
audioData.close();  // Important: prevent memory leaks

// Wait for encoding to complete
await encoder.flush();
encoder.close();
Always call audioData.close() after passing it to encode(). Failing to close AudioData objects will cause memory leaks as the underlying buffers are not automatically released.

Supported Audio Codecs

CodecWebCodecs StringTypical Bitrate
AAC-LCmp4a.40.2128-256 kbps
MP3mp3128-320 kbps
Opusopus64-256 kbps
FLACflacLossless
Vorbisvorbis128-320 kbps

Constructor

Creates a new AudioEncoder with output and error callbacks.
new AudioEncoder(init: AudioEncoderInit)
init
AudioEncoderInit
required
Initialization callbacks for the encoder.
Throws: TypeError if callbacks are not functions.
const encoder = new AudioEncoder({
  output: (chunk, metadata) => {
    // Handle encoded chunk
    const data = new Uint8Array(chunk.byteLength);
    chunk.copyTo(data);

    // Check for decoder config (usually on first chunk)
    if (metadata?.decoderConfig) {
      console.log('Codec:', metadata.decoderConfig.codec);
      console.log('Sample rate:', metadata.decoderConfig.sampleRate);
      console.log('Channels:', metadata.decoderConfig.numberOfChannels);
    }
  },
  error: (err) => {
    console.error('Encoding failed:', err.message);
  }
});

Properties

state
CodecState
required
Current encoder state. One of:
  • 'unconfigured' - Not configured yet, or reset() was called
  • 'configured' - Ready to encode audio data
  • 'closed' - Encoder has been closed and cannot be used
encodeQueueSize
number
required
Number of pending encode operations. Useful for backpressure management when encoding large amounts of audio data.

Static Methods

isConfigSupported()

Check if an audio encoder configuration is supported on this platform.
static isConfigSupported(config: AudioEncoderConfig): Promise<AudioEncoderSupport>
config
AudioEncoderConfig
required
Configuration to test for support.
Returns: Promise<AudioEncoderSupport> - Resolves with support status and normalized config.
const aacSupport = await AudioEncoder.isConfigSupported({
  codec: 'mp4a.40.2',
  sampleRate: 48000,
  numberOfChannels: 2,
  bitrate: 128_000
});

if (aacSupport.supported) {
  console.log('AAC encoding is supported');
  encoder.configure(aacSupport.config);
} else {
  console.log('AAC encoding is NOT supported');
}
// Try preferred codecs in order
const codecs = ['mp4a.40.2', 'opus', 'mp3'];

for (const codec of codecs) {
  const support = await AudioEncoder.isConfigSupported({
    codec,
    sampleRate: 48000,
    numberOfChannels: 2,
    bitrate: 128_000
  });

  if (support.supported) {
    console.log(`Using codec: ${codec}`);
    encoder.configure(support.config);
    break;
  }
}

Instance Methods

configure()

Configure the encoder with codec parameters. Must be called before encoding.
configure(config: AudioEncoderConfig): void
config
AudioEncoderConfig
required
Encoder configuration specifying codec and audio parameters.
Throws:
  • InvalidStateError if encoder is closed
  • NotSupportedError if codec is not supported
encoder.configure({
  codec: 'mp4a.40.2',
  sampleRate: 48000,
  numberOfChannels: 2,
  bitrate: 256_000,
  bitrateMode: 'variable'
});
encoder.configure({
  codec: 'opus',
  sampleRate: 48000,
  numberOfChannels: 2,
  bitrate: 96_000  // Opus is very efficient
});

encode()

Queue an AudioData object for encoding.
encode(data: AudioData): void
data
AudioData
required
The raw audio data to encode. Must have a valid format and timestamp.
Throws:
  • InvalidStateError if encoder is not configured
  • TypeError if data is invalid
Always call audioData.close() after encoding to prevent memory leaks. The encoder makes an internal copy of the data, so closing the source is safe.
// Encode multiple audio frames
for (let i = 0; i < audioFrames.length; i++) {
  const audioData = new AudioData({
    format: 'f32-planar',
    sampleRate: 48000,
    numberOfFrames: 1024,
    numberOfChannels: 2,
    timestamp: i * 21333,  // ~21ms per AAC frame
    data: audioFrames[i]
  });

  encoder.encode(audioData);
  audioData.close();  // Always close after encode
}
for (const samples of audioSamples) {
  const audioData = new AudioData({
    format: 'f32-planar',
    sampleRate: 48000,
    numberOfFrames: 1024,
    numberOfChannels: 2,
    timestamp,
    data: samples
  });

  encoder.encode(audioData);
  audioData.close();

  // Wait if queue gets too large
  if (encoder.encodeQueueSize > 10) {
    await new Promise(resolve => {
      encoder.addEventListener('dequeue', resolve, { once: true });
    });
  }
}

addEventListener()

Add an event listener for encoder events.
addEventListener(type: string, listener: () => void, options?: { once?: boolean }): void
type
string
required
Event type. Currently supports 'dequeue' which fires when the encode queue size decreases.
listener
() => void
required
Callback function to invoke when the event fires.
options
object
Event listener options.
// Monitor queue size
encoder.addEventListener('dequeue', () => {
  console.log('Queue size:', encoder.encodeQueueSize);
});

// One-time listener for flow control
await new Promise(resolve => {
  encoder.addEventListener('dequeue', resolve, { once: true });
});

removeEventListener()

Remove a previously added event listener.
removeEventListener(type: string, listener: () => void): void
type
string
required
Event type (e.g., 'dequeue').
listener
() => void
required
The callback function to remove. Must be the same function reference that was added.
const onDequeue = () => {
  console.log('Dequeue event fired');
};

encoder.addEventListener('dequeue', onDequeue);

// Later, remove the listener
encoder.removeEventListener('dequeue', onDequeue);

flush()

Wait for all pending encode operations to complete.
flush(): Promise<void>
Returns: Promise<void> - Resolves when all queued audio data has been encoded. Throws:
  • InvalidStateError if encoder is not configured
  • Rejects if encoding fails
// Encode all audio data
for (const frame of audioFrames) {
  encoder.encode(frame);
  frame.close();
}

// Wait for all encoding to complete
await encoder.flush();
console.log('All audio encoded!');

// Now safe to close
encoder.close();

reset()

Reset the encoder to the unconfigured state.
reset(): void
Aborts all pending encode operations and resets to the 'unconfigured' state. You must call configure() again before encoding more audio. Throws: InvalidStateError if encoder is closed
encoder.configure({
  codec: 'mp4a.40.2',
  sampleRate: 48000,
  numberOfChannels: 2
});

encoder.encode(audioData);

// Abort and reconfigure with different settings
encoder.reset();

encoder.configure({
  codec: 'opus',
  sampleRate: 48000,
  numberOfChannels: 2
});

close()

Close the encoder and release all resources.
close(): void
The encoder cannot be used after calling close(). Any pending encode operations are aborted and the state transitions to 'closed'.
// Encode all audio
for (const frame of audioFrames) {
  encoder.encode(frame);
  frame.close();
}

// Wait for encoding to complete
await encoder.flush();

// Release resources
encoder.close();

// encoder.encode() will now throw InvalidStateError

Type Definitions

AudioEncoderConfig

Configuration options for the audio encoder.
interface AudioEncoderConfig {
  codec: string;                     // Required: codec identifier
  sampleRate: number;                // Required: sample rate in Hz
  numberOfChannels: number;          // Required: channel count
  bitrate?: number;                  // Optional: target bitrate (bps)
  bitrateMode?: AudioBitrateMode;    // Optional: 'constant' | 'variable'
}

AudioEncoderInit

Initialization callbacks for creating an AudioEncoder.
interface AudioEncoderInit {
  output: (chunk: EncodedAudioChunk, metadata?: AudioEncoderOutputMetadata) => void;
  error: (error: DOMException) => void;
}

AudioEncoderOutputMetadata

Metadata provided with encoded audio chunks.
interface AudioEncoderOutputMetadata {
  decoderConfig?: {
    codec: string;              // Codec string for decoder
    sampleRate: number;         // Sample rate in Hz
    numberOfChannels: number;   // Channel count
    description?: ArrayBuffer;  // Codec-specific data (e.g., AudioSpecificConfig)
  };
}

AudioEncoderSupport

Result from isConfigSupported() indicating codec support.
interface AudioEncoderSupport {
  supported: boolean;           // Whether the config is supported
  config: AudioEncoderConfig;   // The tested (possibly normalized) config
}

AudioBitrateMode

Bitrate control mode for audio encoding.
type AudioBitrateMode = 'constant' | 'variable';
ValueDescription
'constant'Constant bitrate (CBR) - consistent file size, may waste bits on silence
'variable'Variable bitrate (VBR) - better quality/size ratio, recommended for most uses

See Also