Start · Sprachen · JavaScript · Referenz · SourceBuffer: updateend

SourceBuffer: updateend

Ereignis

Wird ausgelöst, sobald eine <code>appendBuffer()</code>- oder <code>remove()</code>-Operation eines <code>SourceBuffer</code> beendet ist, egal ob erfolgreich, abgebrochen oder fehlerhaft.

seit JavaScript Baseline: alle modernen Browser (Media Source Exte Kategorie: webapi

Signatur

sourceBuffer.addEventListener("updateend", handler)

Beschreibung

Das Ereignis updateend gehört zur Schnittstelle SourceBuffer aus den Media Source Extensions (MSE). Es wird ausgelöst, wenn eine asynchrone Pufferoperation, also appendBuffer() oder remove(), fertig ist. Zu diesem Zeitpunkt steht sourceBuffer.updating wieder auf false. Erst jetzt dürfen Sie die nächste Operation am selben Puffer starten.

Die Reihenfolge der Ereignisse ist festgelegt: Zuerst kommt updatestart. Danach folgt genau eines der Ereignisse update (Erfolg), error (Fehler) oder abort (Abbruch durch abort()). Ganz am Ende kommt immer updateend. Deshalb eignet sich updateend gut als zentrale Stelle für die Warteschlangen-Logik: nächstes Segment anhängen, alte Bereiche entfernen oder mediaSource.endOfStream() aufrufen.

Registrieren können Sie den Handler mit addEventListener("updateend", handler) oder über die Eigenschaft sourceBuffer.onupdateend. Das Ereignis ist ein einfaches Event ohne zusätzliche Eigenschaften. Es blubbert nicht (bubbles) und lässt sich nicht abbrechen.

Parameter

Name Typ Default Beschreibung
$type Pflicht string Der Ereignisname "updateend".
$handler Pflicht (event: Event) => void Callback, das nach Abschluss der Pufferoperation aufgerufen wird. event.target ist der betroffene SourceBuffer.
$options boolean | AddEventListenerOptions false Optionen wie { once: true }, praktisch für einmalige Aktionen nach einem bestimmten Append.

Rückgabewert

Typ
void
Beschreibung
addEventListener gibt nichts zurück. Der Handler erhält ein Event-Objekt.

Beispiele

Segmente nacheinander anhängen (Warteschlange)

const video = document.querySelector('video');
const mime = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
const segmente = ['init.mp4', 'seg1.m4s', 'seg2.m4s', 'seg3.m4s'];

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

mediaSource.addEventListener('sourceopen', async () => {
  const sb = mediaSource.addSourceBuffer(mime);
  const puffer = await Promise.all(
    segmente.map(async (url) => (await fetch(url)).arrayBuffer())
  );

  const naechstes = () => {
    if (puffer.length > 0) {
      sb.appendBuffer(puffer.shift());
    } else if (mediaSource.readyState === 'open') {
      mediaSource.endOfStream();
      console.log('Alle Segmente angehängt');
    }
  };

  sb.addEventListener('updateend', naechstes);
  naechstes(); // erstes Segment starten
});
Alle Segmente angehängt

Erfolg und Fehler unterscheiden

const beobachte = (sb) => {
  let fehler = false;
  sb.addEventListener('updatestart', () => { fehler = false; });
  sb.addEventListener('error', () => { fehler = true; });
  sb.addEventListener('updateend', () => {
    console.log(fehler ? 'Operation fehlgeschlagen' : 'Operation erfolgreich',
      '| gepuffert bis:', sb.buffered.length ? sb.buffered.end(sb.buffered.length - 1) : 0);
  });
};
Operation erfolgreich | gepuffert bis: 12.48

Promise-Hilfsfunktion mit onupdateend bzw. once

// Wartet, bis der SourceBuffer frei ist
const warteAufUpdate = (sb) => new Promise((resolve) => {
  if (!sb.updating) return resolve();
  sb.addEventListener('updateend', () => resolve(), { once: true });
});

const altesEntfernen = async (sb, video) => {
  await warteAufUpdate(sb);
  const bis = video.currentTime - 30;
  if (bis > 0) {
    sb.remove(0, bis);
    await warteAufUpdate(sb);
    console.log('Puffer bereinigt bis', bis.toFixed(1));
  }
};

// Alternative per Property (ersetzt vorherigen Handler!)
// sb.onupdateend = () => console.log('fertig');
// sb.onupdateend = null; // Handler wieder entfernen
Puffer bereinigt bis 42.3

// Wichtig · Fallstricke

  • updateend heißt nicht „erfolgreich“: Das Ereignis kommt auch nach error und abort. Für den Erfolgsfall hören Sie auf update.
  • InvalidStateError: Rufen Sie appendBuffer() oder remove() auf, solange updating === true ist, wird ein InvalidStateError geworfen. Warten Sie deshalb immer auf updateend.
  • QuotaExceededError: Ist der Puffer voll, wirft appendBuffer() synchron einen Fehler, und updateend wird nicht ausgelöst. Entfernen Sie alte Bereiche mit remove() und versuchen Sie es danach erneut.
  • endOfStream() darf nur aufgerufen werden, wenn kein SourceBuffer mehr updating ist. Der richtige Zeitpunkt dafür ist also ein updateend-Handler.
  • Eine Zuweisung an onupdateend überschreibt einen vorher gesetzten Handler. Mehrere Listener registrieren Sie mit addEventListener.
  • Kompatibilität: MSE wird von Chrome, Edge, Firefox und Safari (Desktop) unterstützt. Auf dem iPhone steht es erst ab iOS 17.1 als ManagedMediaSource zur Verfügung. Prüfen Sie Codecs vorab mit MediaSource.isTypeSupported().