Start · Sprachen · JavaScript · Referenz · ManagedSourceBuffer

ManagedSourceBuffer

Schnittstelle

Ein <code>SourceBuffer</code>, den <code>ManagedMediaSource.addSourceBuffer()</code> erzeugt und dessen Pufferinhalt der Browser selbstständig leeren darf – mit dem Ereignis <code>bufferedchange</code>.

seit JavaScript Safari 17 (macOS), Safari iOS 17.1+; nicht Baselin Kategorie: webapi

Signatur

interface ManagedSourceBuffer extends SourceBuffer

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);
});
ManagedSourceBuffer // in Safari 17+, sonst "SourceBuffer"

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);
Hinzugefügt: 0.0s – 6.0s Entfernt: 0.0s – 2.0s

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 auf MediaSource zurückfallen.
  • Ohne video.disableRemotePlayback = true oder eine alternative AirPlay-Quelle (<source> mit HLS-URL) wird die Wiedergabe mit ManagedMediaSource nicht gestartet.
  • Der Browser darf gepufferte Daten jederzeit entfernen. Lokale Kopien von buffered veralten dadurch. Maßgeblich sind bufferedchange bzw. ein erneutes Lesen von sourceBuffer.buffered.
  • Wie bei jedem SourceBuffer gilt: Solange updating den Wert true hat, darf nicht erneut appendBuffer() oder remove() aufgerufen werden, sonst wird ein InvalidStateError geworfen.
  • Segmente nur zwischen startstreaming und endstreaming nachladen. Das spart Akku und Datenvolumen, und genau darauf ist die Managed-Variante ausgelegt.