Start · Sprachen · JavaScript · Referenz · AudioEncoder.encode()

AudioEncoder.encode()

Methode

Stellt ein <code>AudioData</code>-Objekt zur asynchronen Kodierung in die Warteschlange des <code>AudioEncoder</code>. Die Ergebnisse kommen über den <code>output</code>-Callback.

seit JavaScript WebCodecs – Chrome/Edge 94+, Firefox 130+, Safari Kategorie: webapi

Signatur

AudioEncoder.prototype.encode(data)

Beschreibung

encode() übergibt einen Block unkomprimierter Audio-Samples (AudioData) an einen konfigurierten AudioEncoder. Die Methode arbeitet asynchron und kehrt sofort zurück. Das Ergebnis erscheint später als EncodedAudioChunk im output-Callback, den du im Konstruktor angegeben hast. Tritt beim Kodieren ein Fehler auf, wird der error-Callback aufgerufen und der Encoder geschlossen.

Typische Einsatzfälle sind Audioaufnahmen im Browser (z. B. Mikrofon → Opus), eigene WebRTC- oder WebTransport-Pipelines und das Erzeugen von Audiospuren für Container wie WebM oder MP4. Vor dem ersten Aufruf muss der Encoder mit configure() eingerichtet sein. state muss also "configured" sein.

Jeder Aufruf erhöht encodeQueueSize. Ist ein Auftrag erledigt, sinkt der Wert wieder und das Ereignis dequeue wird ausgelöst. So kannst du Rückstau (Backpressure) steuern: Liefert deine Quelle schneller Daten, als der Encoder verarbeiten kann, solltest du keine weiteren Aufträge einreihen. Mit flush() wartest du darauf, dass alle ausstehenden Aufträge fertig sind. Das ist z. B. am Ende einer Aufnahme wichtig.

Der Encoder legt intern eine Kopie (einen Klon) des übergebenen AudioData an. Du kannst und solltest dein eigenes Objekt deshalb direkt nach encode() mit close() freigeben, damit der Speicher nicht vollläuft.

Parameter

Name Typ Default Beschreibung
$data Pflicht AudioData Die zu kodierenden Audio-Samples. Das Objekt darf nicht geschlossen sein (nicht per close() freigegeben). Abtastrate und Kanalzahl sollten zur Konfiguration aus configure() passen.

Rückgabewert

Typ
void
Beschreibung
Kein Rückgabewert (undefined). Kodierte Daten werden als EncodedAudioChunk an den output-Callback übergeben.

Beispiele

Sinuston synthetisch erzeugen und als Opus kodieren

const chunks = [];

const encoder = new AudioEncoder({
  output: (chunk, metadata) => {
    chunks.push(chunk);
    if (metadata?.decoderConfig) {
      console.log('Decoder-Config:', metadata.decoderConfig.codec);
    }
  },
  error: (e) => console.error('Encoder-Fehler:', e)
});

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

// 1 Sekunde 440-Hz-Sinus in Blöcken zu 960 Frames (20 ms)
const sampleRate = 48000;
const frames = 960;
for (let block = 0; block < 50; block++) {
  const samples = new Float32Array(frames);
  for (let i = 0; i < frames; i++) {
    const t = (block * frames + i) / sampleRate;
    samples[i] = Math.sin(2 * Math.PI * 440 * t) * 0.5;
  }
  const audioData = new AudioData({
    format: 'f32-planar',
    sampleRate,
    numberOfFrames: frames,
    numberOfChannels: 1,
    timestamp: (block * frames * 1_000_000) / sampleRate, // Mikrosekunden
    data: samples
  });
  encoder.encode(audioData);
  audioData.close(); // eigene Kopie sofort freigeben
}

await encoder.flush();
console.log(`Kodierte Chunks: ${chunks.length}`);
encoder.close();
Decoder-Config: opus Kodierte Chunks: 50

Mikrofon live kodieren (MediaStreamTrackProcessor)

// Hinweis: MediaStreamTrackProcessor gibt es derzeit nur in Chromium-Browsern
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const [track] = stream.getAudioTracks();
const { sampleRate, channelCount = 1 } = track.getSettings();

const encoder = new AudioEncoder({
  output: (chunk) => {
    // z. B. per WebSocket / WebTransport verschicken
    console.log(chunk.type, chunk.timestamp, chunk.byteLength);
  },
  error: console.error
});

encoder.configure({ codec: 'opus', sampleRate, numberOfChannels: channelCount, bitrate: 32000 });

const processor = new MediaStreamTrackProcessor({ track });
const reader = processor.readable.getReader();

while (true) {
  const { value: audioData, done } = await reader.read();
  if (done) break;
  encoder.encode(audioData);
  audioData.close();
}

await encoder.flush();
encoder.close();
key 0 118 key 20000 96 ...

Rückstau über encodeQueueSize und dequeue steuern

const MAX_QUEUE = 10;

const encoder = new AudioEncoder({
  output: (chunk) => {},
  error: console.error
});
encoder.configure({ codec: 'opus', sampleRate: 48000, numberOfChannels: 2 });

// Wartet, bis die Warteschlange wieder Platz hat
const waitForQueue = () =>
  encoder.encodeQueueSize < MAX_QUEUE
    ? Promise.resolve()
    : new Promise((resolve) =>
        encoder.addEventListener('dequeue', resolve, { once: true })
      );

const encodeSafely = async (audioData) => {
  if (encoder.state !== 'configured') {
    audioData.close();
    return;
  }
  await waitForQueue();
  encoder.encode(audioData);
  audioData.close();
};

// Wichtig · Fallstricke

  • InvalidStateError: Ist state nicht "configured" (also vor configure() oder nach close()), wirft encode() eine DOMException vom Typ InvalidStateError.
  • TypeError: Ist das übergebene AudioData schon geschlossen, wirft die Methode einen TypeError. Rufe close() daher erst nach encode() auf.
  • Speicherlecks: Nicht geschlossene AudioData-Objekte halten Puffer fest. Gib sie immer mit close() frei.
  • Zeitstempel werden in Mikrosekunden angegeben, nicht in Millisekunden. Sie sollten lückenlos steigen.
  • Fehler beim Kodieren selbst werden nicht als Ausnahme geworfen. Sie kommen asynchron im error-Callback an, und der Encoder ist danach geschlossen.
  • Prüfe vorab mit AudioEncoder.isConfigSupported(), ob der Browser den gewünschten Codec unterstützt. Welche Codecs verfügbar sind (Opus, AAC usw.), hängt vom Browser und von der Plattform ab.
  • Kompatibilität: WebCodecs gibt es nur in sicheren Kontexten (HTTPS), im Fenster und in Workern. Chromium unterstützt die API seit Version 94, Firefox seit Version 130. Safari unterstützt AudioEncoder erst in neueren Versionen. Nutze Feature-Erkennung: 'AudioEncoder' in globalThis.