Signatur
Beschreibung
ManagedSourceBuffer gehört zur Managed Media Source-Erweiterung der Media Source Extensions (MSE). Das Objekt erbt alle Eigenschaften und Methoden von SourceBuffer (appendBuffer(), remove(), buffered, updating, mode, timestampOffset usw.). Einen eigenen Konstruktor gibt es nicht: Man bekommt eine Instanz nur über ManagedMediaSource.prototype.addSourceBuffer(mimeType).
Der wichtigste Unterschied zum klassischen SourceBuffer: Der Browser verwaltet den Puffer selbst. Wird der Speicher knapp oder ist das Gerät im Energiesparmodus, darf er bereits gepufferte Daten jederzeit entfernen, auch außerhalb eines appendBuffer()- oder remove()-Aufrufs. Damit die Anwendung davon erfährt, feuert ManagedSourceBuffer das Ereignis bufferedchange. Es ist ein BufferedChangeEvent mit den Eigenschaften addedRanges und removedRanges (jeweils TimeRanges).
Sinnvoll ist das vor allem für adaptives Streaming (HLS/DASH-Player) auf Mobilgeräten, besonders auf dem iPhone, wo das klassische MediaSource nicht verfügbar ist. Der Player sollte den Pufferstand nicht selbst mitführen, sondern auf bufferedchange reagieren und entfernte Bereiche bei Bedarf neu laden. Zusätzlich sollte er die Ereignisse startstreaming/endstreaming der zugehörigen ManagedMediaSource beachten.
Beispiele
ManagedSourceBuffer erzeugen (mit Rückfall auf MediaSource)
const video = document.querySelector('video');
const MS = window.ManagedMediaSource ?? window.MediaSource;
const mediaSource = new MS();
// Für ManagedMediaSource Pflicht: Remote Playback abschalten oder AirPlay-Quelle angeben
video.disableRemotePlayback = true;
video.src = URL.createObjectURL(mediaSource);
mediaSource.addEventListener('sourceopen', async () => {
const mime = 'video/mp4; codecs="avc1.64001f, mp4a.40.2"';
const sb = mediaSource.addSourceBuffer(mime);
console.log(sb.constructor.name);
const data = await (await fetch('/media/init.mp4')).arrayBuffer();
sb.appendBuffer(data);
});
Auf vom Browser entfernte Pufferbereiche reagieren (addEventListener)
const handleBufferedChange = (event) => {
const { addedRanges, removedRanges } = event;
for (let i = 0; i < removedRanges.length; i++) {
console.log(`Entfernt: ${removedRanges.start(i).toFixed(1)}s – ${removedRanges.end(i).toFixed(1)}s`);
}
for (let i = 0; i < addedRanges.length; i++) {
console.log(`Hinzugefügt: ${addedRanges.start(i).toFixed(1)}s – ${addedRanges.end(i).toFixed(1)}s`);
}
};
sourceBuffer.addEventListener('bufferedchange', handleBufferedChange);
// Beim Abbau des Players wieder entfernen
// sourceBuffer.removeEventListener('bufferedchange', handleBufferedChange);
on-Property und Streaming-Steuerung kombinieren
let streamingAllowed = false;
mediaSource.onstartstreaming = () => { streamingAllowed = true; loadNextSegment(); };
mediaSource.onendstreaming = () => { streamingAllowed = false; };
sourceBuffer.onbufferedchange = (event) => {
// Wenn der Bereich rund um die aktuelle Position entfernt wurde, neu laden
const t = video.currentTime;
const r = event.removedRanges;
for (let i = 0; i < r.length; i++) {
if (t >= r.start(i) && t < r.end(i) + 10 && streamingAllowed) {
loadNextSegment();
break;
}
}
};
async function loadNextSegment() {
if (!streamingAllowed || sourceBuffer.updating) return;
const res = await fetch('/media/segment-1.m4s');
sourceBuffer.appendBuffer(await res.arrayBuffer());
}
// Wichtig · Fallstricke
- Browser-Kompatibilität: Bisher nur in Safari 17+ (macOS) und iOS/iPadOS 17.1+ verfügbar. Chrome und Firefox unterstützen die Schnittstelle derzeit nicht. Deshalb immer per Feature-Erkennung (
'ManagedMediaSource' in window) prüfen und aufMediaSourcezurückfallen. - Ohne
video.disableRemotePlayback = trueoder eine alternative AirPlay-Quelle (<source>mit HLS-URL) wird die Wiedergabe mitManagedMediaSourcenicht gestartet. - Der Browser darf gepufferte Daten jederzeit entfernen. Lokale Kopien von
bufferedveralten dadurch. Maßgeblich sindbufferedchangebzw. ein erneutes Lesen vonsourceBuffer.buffered. - Wie bei jedem
SourceBuffergilt: Solangeupdatingden Werttruehat, darf nicht erneutappendBuffer()oderremove()aufgerufen werden, sonst wird einInvalidStateErrorgeworfen. - Segmente nur zwischen
startstreamingundendstreamingnachladen. Das spart Akku und Datenvolumen, und genau darauf ist die Managed-Variante ausgelegt.