Signatur
Beschreibung
Das Ereignis update gehört zu den Media Source Extensions (MSE). Ein SourceBuffer löst es aus, sobald eine asynchrone Operation (appendBuffer() oder remove()) erfolgreich beendet ist. Zu diesem Zeitpunkt ist sourceBuffer.updating bereits wieder false, sodass man die nächste Operation starten darf.
Die Reihenfolge der Ereignisse ist festgelegt: updatestart → update → updateend. Schlägt eine Operation fehl, wird statt update das Ereignis error ausgelöst, bei einem Abbruch über abort() das Ereignis abort. updateend kommt in allen Fällen danach.
Einen Handler registriert man mit addEventListener("update", handler) oder über die Eigenschaft onupdate. Das übergebene Objekt ist ein einfaches Event ohne zusätzliche Eigenschaften. Es blubbert nicht (bubbles) und lässt sich nicht abbrechen.
In der Praxis steuert man damit oft eine Warteschlange von Mediensegmenten: Man hängt immer nur ein Segment an und reicht das nächste erst weiter, wenn das vorherige verarbeitet wurde. Wer auch Fehlerfälle zuverlässig behandeln will, nimmt dafür meist updateend, weil update nur bei Erfolg feuert.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | Der Ereignisname, hier "update". |
|
| $handler Pflicht | (event: Event) => void | Callback, der nach erfolgreichem Abschluss von appendBuffer() bzw. remove() aufgerufen wird. event.target ist der betroffene SourceBuffer. |
|
| $options | boolean | AddEventListenerOptions | false | Optionen wie once, signal (zum Entfernen über AbortController) oder capture. |
Rückgabewert
addEventListener() gibt nichts zurück. Der Handler bekommt ein Event-Objekt.Beispiele
Segmente nacheinander mit addEventListener anhängen
const video = document.querySelector('video');
const mimeType = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
const segmentUrls = ['/media/init.mp4', '/media/seg1.m4s', '/media/seg2.m4s'];
if (!MediaSource.isTypeSupported(mimeType)) {
throw new Error('Codec wird nicht unterstützt');
}
const mediaSource = new MediaSource();
video.src = URL.createObjectURL(mediaSource);
mediaSource.addEventListener('sourceopen', async () => {
const sourceBuffer = mediaSource.addSourceBuffer(mimeType);
const segments = await Promise.all(
segmentUrls.map(async (url) => (await fetch(url)).arrayBuffer())
);
let index = 0;
const appendNext = () => {
if (index < segments.length) {
sourceBuffer.appendBuffer(segments[index++]);
} else if (mediaSource.readyState === 'open') {
mediaSource.endOfStream();
}
};
sourceBuffer.addEventListener('update', () => {
console.log(`Segment ${index} angehängt, updating = ${sourceBuffer.updating}`);
appendNext();
});
appendNext();
}, { once: true });
on-Property onupdate und Handler wieder entfernen
const logBuffered = (event) => {
const sb = event.target;
const ranges = [];
for (let i = 0; i < sb.buffered.length; i++) {
ranges.push(`${sb.buffered.start(i).toFixed(1)}–${sb.buffered.end(i).toFixed(1)} s`);
}
console.log('Gepuffert:', ranges.join(', '));
};
// Variante 1: on-Property
sourceBuffer.onupdate = logBuffered;
// ... später deaktivieren
sourceBuffer.onupdate = null;
// Variante 2: addEventListener / removeEventListener
sourceBuffer.addEventListener('update', logBuffered);
sourceBuffer.removeEventListener('update', logBuffered);
remove() als Promise mit update/error verpacken
const removeRange = (sourceBuffer, start, end) =>
new Promise((resolve, reject) => {
const controller = new AbortController();
const { signal } = controller;
sourceBuffer.addEventListener('update', () => {
controller.abort();
resolve();
}, { signal });
sourceBuffer.addEventListener('error', () => {
controller.abort();
reject(new Error('remove() fehlgeschlagen'));
}, { signal });
sourceBuffer.remove(start, end);
});
// Alten Puffer vor der aktuellen Position freigeben
const trimBuffer = async (video, sourceBuffer) => {
const cutoff = video.currentTime - 30;
if (cutoff > 0 && !sourceBuffer.updating) {
await removeRange(sourceBuffer, 0, cutoff);
console.log(`Puffer bis ${cutoff.toFixed(1)} s entfernt`);
}
};
// Wichtig · Fallstricke
- Nur bei Erfolg:
updatekommt nicht, wenn die Operation fehlschlägt (error) oder abgebrochen wird (abort). Wer „fertig, egal wie“ erkennen will, nimmtupdateend. Sonst kann eine Warteschlange hängen bleiben. - InvalidStateError: Wird
appendBuffer()oderremove()aufgerufen, solangeupdating === trueist, gibt es eine Ausnahme. Deshalb immer erst aufupdate/updateendwarten. - QuotaExceededError: Ist der Puffer voll, wirft
appendBuffer()sofort eine Ausnahme und es kommt kein Ereignis. Dann zuerst alte Bereiche mitremove()freigeben. - endOfStream(): Darf nur aufgerufen werden, wenn kein
SourceBuffermehrupdatingist, am besten also imupdate-/updateend-Handler. - Kompatibilität: MSE wird in Chrome, Edge, Firefox und Safari (Desktop) unterstützt. Auf dem iPhone gibt es MSE erst ab iOS 17.1, und zwar über
ManagedMediaSource. Vorher vorhandene Unterstützung mitMediaSource.isTypeSupported()bzw.'MediaSource' in windowprüfen. In Dedicated Workers ist MSE nur teilweise verfügbar (Chrome 108+).