Start · Sprachen · JavaScript · Referenz · SourceBuffer.appendBufferAsync()

SourceBuffer.appendBufferAsync()

Methode

Hängt Mediensegmentdaten aus einem <code>ArrayBuffer</code>, <code>TypedArray</code> oder <code>DataView</code> asynchron an einen <code>SourceBuffer</code> an und gibt ein <code>Promise</code> zurück.

seit JavaScript Nicht standardisiert – nur Firefox 62+ hinter dem Kategorie: webapi

Signatur

SourceBuffer.prototype.appendBufferAsync(source)

Beschreibung

appendBufferAsync() ist die Promise-basierte Variante von SourceBuffer.appendBuffer(). Die Methode startet das Anhängen von Mediendaten (Initialisierungs- oder Mediensegmente) an den Puffer. Das zurückgegebene Promise wird erfüllt, sobald die Daten verarbeitet sind. Das entspricht dem Zeitpunkt, an dem bei appendBuffer() das Ereignis updateend ausgelöst wird.

Der Vorteil gegenüber der klassischen Methode: Statt Ereignis-Listener für update, updateend und error zu registrieren, kann man Segmente mit async/await einfach nacheinander anhängen. So bleibt der Code für adaptives Streaming (z. B. DASH oder HLS über die Media Source Extensions) übersichtlich.

Wichtig: Die Methode steht in keiner Spezifikation. Sie war nur ein Experiment in Firefox und ist dort standardmäßig ausgeschaltet. In Produktivcode sollte man immer vorher prüfen, ob sie vorhanden ist, und sonst auf appendBuffer() mit einem eigenen Promise-Wrapper ausweichen (siehe Beispiele).

Parameter

Name Typ Default Beschreibung
$source Pflicht ArrayBuffer | TypedArray | DataView Die Mediendaten, die angehängt werden, z. B. ein fMP4- oder WebM-Segment, das per fetch() geladen wurde.

Rückgabewert

Typ
Promise<undefined>
Beschreibung
Ein Promise, das ohne Wert erfüllt wird, sobald das Anhängen fertig ist. Es wird abgelehnt, wenn das Anhängen fehlschlägt oder abgebrochen wird (z. B. QuotaExceededError bei vollem Puffer oder InvalidStateError, wenn der SourceBuffer aus der MediaSource entfernt wurde).

Beispiele

Plattformübergreifender Wrapper mit Fallback

// Nutzt appendBufferAsync(), wenn vorhanden, sonst appendBuffer() + Ereignisse
const appendAsync = (sourceBuffer, data) => {
  if (typeof sourceBuffer.appendBufferAsync === 'function') {
    return sourceBuffer.appendBufferAsync(data);
  }
  return new Promise((resolve, reject) => {
    const onEnd = () => { cleanup(); resolve(); };
    const onError = () => { cleanup(); reject(new Error('Anhängen fehlgeschlagen')); };
    const cleanup = () => {
      sourceBuffer.removeEventListener('updateend', onEnd);
      sourceBuffer.removeEventListener('error', onError);
    };
    sourceBuffer.addEventListener('updateend', onEnd);
    sourceBuffer.addEventListener('error', onError);
    sourceBuffer.appendBuffer(data);
  });
};

Segmente nacheinander in ein Video streamen

const video = document.querySelector('video');
const mime = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
const segments = ['init.mp4', 'seg-1.m4s', 'seg-2.m4s', 'seg-3.m4s'];

const mediaSource = new MediaSource();
video.src = URL.createObjectURL(mediaSource);

mediaSource.addEventListener('sourceopen', async () => {
  const sb = mediaSource.addSourceBuffer(mime);
  for (const url of segments) {
    const data = await (await fetch(url)).arrayBuffer();
    await sb.appendBufferAsync(data); // wartet auf das Ende des Anhängens
    console.log(`Angehängt: ${url}`);
  }
  mediaSource.endOfStream();
}, { once: true });
Angehängt: init.mp4 Angehängt: seg-1.m4s Angehängt: seg-2.m4s Angehängt: seg-3.m4s

Vollen Puffer (QuotaExceededError) abfangen

const appendWithEviction = async (sb, video, data) => {
  try {
    await sb.appendBufferAsync(data);
  } catch (err) {
    if (err.name === 'QuotaExceededError') {
      // Alte, bereits abgespielte Daten entfernen und erneut versuchen
      const end = Math.max(0, video.currentTime - 10);
      await sb.removeAsync(0, end);
      await sb.appendBufferAsync(data);
    } else {
      throw err;
    }
  }
};

// Wichtig · Fallstricke

  • Nicht standardisiert und experimentell: Die Methode gibt es nur in Firefox (ab Version 62) hinter dem Flag media.mediasource.experimental.enabled. Chrome, Edge und Safari unterstützen sie nicht. Vor der Nutzung immer mit typeof sb.appendBufferAsync === 'function' prüfen.
  • Wie bei appendBuffer() darf nicht angehängt werden, während sourceBuffer.updating den Wert true hat. Sonst gibt es einen InvalidStateError. Deshalb jedes Anhängen mit await abwarten, bevor das nächste startet.
  • Ist die MediaSource im Zustand ended, wird sie durch das Anhängen wieder auf open gesetzt. Ist sie closed oder wurde der Puffer entfernt, schlägt das Promise fehl.
  • Browser begrenzen den Puffer (oft rund 100–150 MB für Video). Bei langen Streams abgespielte Bereiche mit remove() freigeben, sonst droht ein QuotaExceededError.
  • Die Media Source Extensions sind in Worker-Kontexten nur eingeschränkt verfügbar. Auf iPhones gibt es statt MediaSource nur ManagedMediaSource (ab iOS 17.1).