Signatur
Beschreibung
ManagedMediaSource erweitert MediaSource aus der Media Source Extensions API (MSE). Der Unterschied: Bei einer normalen MediaSource entscheidet allein die Anwendung, wann Segmente mit SourceBuffer.appendBuffer() angehängt oder mit remove() entfernt werden. Bei ManagedMediaSource darf der Browser selbst gepufferte Daten verwerfen, z. B. bei Speicherknappheit, und sagt der Anwendung über Ereignisse, wann sich das Nachladen lohnt.
Das ist vor allem für Mobilgeräte gedacht. Der Browser kann das Nachladen auf Zeiten legen, in denen das Funkmodul ohnehin aktiv ist (z. B. schnelles 5G, WLAN). Das spart Akku und Datenvolumen. Apple hat die Schnittstelle eingeführt, damit MSE-basierte Player (hls.js, dash.js, Shaka Player) auch auf dem iPhone laufen. Dort gibt es die klassische MediaSource nicht.
Zusätzlich zu den geerbten Mitgliedern gibt es:
streaming(schreibgeschützt,boolean):true, solange die Anwendung neue Daten anhängen soll.startstreaming-Ereignis: Jetzt sollen Daten geladen werden.endstreaming-Ereignis: Das Laden soll vorerst stoppen.- Die
sourceBufferssind vom TypManagedSourceBuffer. Dieser feuertbufferedchange, wenn der Browser gepufferte Bereiche entfernt hat.
Die Einrichtung läuft wie bei MSE: Instanz erzeugen, per URL.createObjectURL() (oder srcObject) an ein <video> binden, auf sourceopen warten und dann addSourceBuffer() aufrufen. Unterstützte Formate prüft man mit der statischen Methode ManagedMediaSource.isTypeSupported().
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $(Konstruktor) new ManagedMediaSource() | — | Der Konstruktor nimmt keine Parameter. Er erzeugt eine neue Instanz mit readyState "closed". |
Rückgabewert
new ManagedMediaSource() liefert eine neue Instanz. Sie wird über eine Objekt-URL oder srcObject an ein Medienelement gebunden.Beispiele
Feature-Erkennung und Einrichtung mit Rückfall auf MediaSource
const video = document.querySelector('video');
const mime = 'video/mp4; codecs="avc1.64001f, mp4a.40.2"';
// ManagedMediaSource bevorzugen, sonst klassische MediaSource
const MS = window.ManagedMediaSource ?? window.MediaSource;
if (!MS || !MS.isTypeSupported(mime)) {
throw new Error('MSE bzw. Codec wird nicht unterstützt');
}
const mediaSource = new MS();
// Pflicht bei ManagedMediaSource in Safari (sonst AirPlay-Alternative nötig)
video.disableRemotePlayback = true;
video.src = URL.createObjectURL(mediaSource);
mediaSource.addEventListener('sourceopen', () => {
URL.revokeObjectURL(video.src);
const sourceBuffer = mediaSource.addSourceBuffer(mime);
console.log('Typ:', mediaSource.constructor.name);
console.log('readyState:', mediaSource.readyState);
}, { once: true });
Laden über startstreaming/endstreaming steuern
const video = document.querySelector('video');
const mime = 'video/mp4; codecs="avc1.64001f"';
const segmentUrls = ['/seg/init.mp4', '/seg/1.m4s', '/seg/2.m4s', '/seg/3.m4s'];
let next = 0;
const ms = new ManagedMediaSource();
video.disableRemotePlayback = true;
video.src = URL.createObjectURL(ms);
const appendOnce = (sb, data) => new Promise((resolve, reject) => {
sb.addEventListener('updateend', resolve, { once: true });
sb.addEventListener('error', reject, { once: true });
sb.appendBuffer(data);
});
const loadWhileStreaming = async (sb) => {
// Nur laden, solange der Browser es erlaubt
while (ms.streaming && next < segmentUrls.length) {
const res = await fetch(segmentUrls[next++]);
await appendOnce(sb, await res.arrayBuffer());
}
if (next >= segmentUrls.length && ms.readyState === 'open') {
ms.endOfStream();
}
};
ms.addEventListener('sourceopen', () => {
const sb = ms.addSourceBuffer(mime);
ms.addEventListener('startstreaming', () => {
console.log('startstreaming – lade Segmente');
loadWhileStreaming(sb);
});
ms.addEventListener('endstreaming', () => {
console.log('endstreaming – pausiere Laden');
});
// Falls streaming bereits aktiv ist
if (ms.streaming) loadWhileStreaming(sb);
}, { once: true });
Vom Browser entfernte Pufferbereiche erkennen (bufferedchange)
const ms = new ManagedMediaSource();
const video = document.querySelector('video');
video.disableRemotePlayback = true;
video.src = URL.createObjectURL(ms);
ms.addEventListener('sourceopen', () => {
const sb = ms.addSourceBuffer('video/mp4; codecs="avc1.64001f"');
// ManagedSourceBuffer meldet Änderungen, auch wenn der Browser Daten verwirft
sb.addEventListener('bufferedchange', (event) => {
for (let i = 0; i < event.removedRanges.length; i++) {
const start = event.removedRanges.start(i).toFixed(1);
const end = event.removedRanges.end(i).toFixed(1);
console.log(`Entfernt: ${start}s – ${end}s`);
}
// Hier z. B. den eigenen Segment-Index aktualisieren,
// damit entfernte Segmente bei Bedarf neu geladen werden.
});
}, { once: true });