Signatur
Beschreibung
Das Ereignis bufferedchange gehört zur Schnittstelle ManagedSourceBuffer der Managed Media Source-API, einer speicherschonenden Variante von Media Source Extensions (MSE). Es wird ausgelöst, sobald sich die Zeitbereiche in sourceBuffer.buffered ändern. Der Handler bekommt ein BufferedChangeEvent mit den Eigenschaften addedRanges und removedRanges. Beide sind vom Typ TimeRanges.
Bei klassischem MSE ändert sich der Puffer nur durch eigene Aufrufe wie appendBuffer() oder remove(). Bei ManagedMediaSource darf der Browser dagegen jederzeit selbst gepufferte Daten entfernen, etwa bei Speicherknappheit. bufferedchange ist der einzige zuverlässige Weg, davon zu erfahren. Ein Player sollte das Ereignis deshalb nutzen, um entfernte Segmente in seiner Segmentverwaltung als „nicht geladen“ zu markieren und bei Bedarf neu zu laden.
Einen Handler registrierst du mit addEventListener("bufferedchange", handler) oder über die Eigenschaft onbufferedchange. Das Ereignis lässt sich nicht abbrechen und steigt nicht auf (kein Bubbling).
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | Der Ereignisname "bufferedchange". |
|
| $handler Pflicht | (event: BufferedChangeEvent) => void | Callback-Funktion. Sie erhält ein BufferedChangeEvent mit addedRanges und removedRanges (jeweils TimeRanges). |
|
| $options | boolean | AddEventListenerOptions | false | Optionen wie once oder signal (AbortSignal, damit lässt sich der Handler später gezielt entfernen). |
Rückgabewert
addEventListener gibt nichts zurück. Der Handler bekommt ein BufferedChangeEvent.Beispiele
Hinzugefügte und entfernte Bereiche protokollieren
const video = document.querySelector('video');
// Nötig, damit ManagedMediaSource ohne AirPlay-Alternative funktioniert
video.disableRemotePlayback = true;
const MS = window.ManagedMediaSource ?? window.MediaSource;
const source = new MS();
video.src = URL.createObjectURL(source);
const rangesToString = (ranges) =>
Array.from({ length: ranges.length }, (_, i) =>
`[${ranges.start(i).toFixed(2)}–${ranges.end(i).toFixed(2)}]`
).join(' ') || '(keine)';
source.addEventListener('sourceopen', async () => {
const sb = source.addSourceBuffer('video/mp4; codecs="avc1.42E01E"');
sb.addEventListener('bufferedchange', (event) => {
console.log('Hinzugefügt:', rangesToString(event.addedRanges));
console.log('Entfernt:', rangesToString(event.removedRanges));
});
const data = await fetch('/media/init-und-segment1.mp4').then((r) => r.arrayBuffer());
sb.appendBuffer(data);
});
Vom Browser verworfene Segmente neu laden
// segments: [{ start, end, url, loaded }]
const markEvicted = (segments, removedRanges) => {
for (let i = 0; i < removedRanges.length; i++) {
const from = removedRanges.start(i);
const to = removedRanges.end(i);
for (const seg of segments) {
if (seg.start < to && seg.end > from) seg.loaded = false;
}
}
};
const watchBuffer = (sourceBuffer, segments) => {
sourceBuffer.onbufferedchange = (event) => {
if (event.removedRanges.length > 0) {
markEvicted(segments, event.removedRanges);
const missing = segments.filter((s) => !s.loaded).length;
console.log(`Vom Browser entfernt – ${missing} Segment(e) neu laden`);
}
};
};
Handler mit AbortController wieder entfernen
const controller = new AbortController();
const onBufferedChange = (event) => {
console.log('Neue Bereiche:', event.addedRanges.length);
};
sourceBuffer.addEventListener('bufferedchange', onBufferedChange, {
signal: controller.signal,
});
// Beim Zerstören des Players:
controller.abort();
// Alternativ:
// sourceBuffer.removeEventListener('bufferedchange', onBufferedChange);
// oder: sourceBuffer.onbufferedchange = null;
// Wichtig · Fallstricke
- Kompatibilität:
ManagedMediaSourceund damitbufferedchangegibt es vor allem in Safari 17+, auf dem iPhone ab iOS 17.1. Andere Browser unterstützen die API nicht oder nur experimentell. Prüfe die Unterstützung mit'ManagedMediaSource' in windowund greife sonst aufMediaSourcezurück. Beim klassischenSourceBuffergibt es dieses Ereignis nicht. - Unter iOS funktioniert
ManagedMediaSourcenur, wenn am MedienelementdisableRemotePlayback = truegesetzt ist oder eine AirPlay-taugliche Alternativquelle (z. B. HLS über<source>) angegeben ist. - Der Browser kann Daten ohne eigenen Aufruf entfernen. Verlass dich also nicht darauf, dass einmal angehängte Segmente erhalten bleiben. Werte
removedRangesimmer aus. - Das Ereignis kommt nach Ende eines
appendBuffer()- oderremove()-Vorgangs, also in der Nähe vonupdateend. Die genaue Reihenfolge solltest du aber nicht voraussetzen. Stoße neue Anhänge nur an, wennsourceBuffer.updating === falseist. TimeRangesist kein Array. Greife mitstart(i)/end(i)undlengthauf die Bereiche zu.