web-audio-apiwebcodecs

Encoding an AudioBuffer with web codecs


I'm trying to process audio files using the Web Audio API and then to encode the result using the Web Codecs API, here is what a simplified version of my code looks like:

/**
 * Encode an audio file using web codecs
 */
async function encodeAudio(url: string) {
  const audioBuffer = await fetchAudioBuffer(url); // see function below
  const signal = bufferToF32Planar(audioBuffer); // see function below

  const encoder = new AudioEncoder({
    output: console.log,
    error: console.error,
  });

  encoder.configure({
    codec: 'opus',
    sampleRate: 44100,
    numberOfChannels: 2,
    bitrate: 128_000, // 128 kbps
  });

  const data = new AudioData({
    format: 'f32-planar',
    sampleRate: audioBuffer.sampleRate,
    numberOfChannels: audioBuffer.numberOfChannels,
    numberOfFrames: audioBuffer.length,
    timestamp: 0,
    data: signal,
  });

  encoder.encode(data);
}

/**
 * Convert an audio buffer into a planar float 32 array
 * @param input processed audio buffer
 * @returns Typed array
 */
function bufferToF32Planar(input: AudioBuffer): Float32Array {
  const result = new Float32Array(input.length * input.numberOfChannels);

  let offset = 0;
  for (let i = 0; i < input.numberOfChannels; i++) {
    const data = input.getChannelData(i);
    result.set(data, offset);
    offset = data.length;
  }

  return result;
}

/**
 * Fetch the audio file and convert it into
 * an audio buffer using an audio context
 */
async function fetchAudioBuffer(
  input: RequestInfo | URL,
  init?: RequestInit | undefined,
): Promise<AudioBuffer> {
  const context = new AudioContext();
  const res = await fetch(input, init);
  const buffer = await res.arrayBuffer();

  return await context.decodeAudioData(buffer);
}

await encodeAudio('/audio.mp3');

However when I run this code, I'm getting the error DOMException: Input audio buffer is incompatible with codec parameters. What did I do wrong?


Solution

  • I guess your source file has a different sample rate than 44.1 kHz. But you could use the Web Audio API to resample your source file when it gets decoded.

    const context = new AudioContext({ sampleRate: 44100 });
    

    Calling decodeAudioData() on that context will then always produce an AudioBuffer at 44.1 kHz.