Signatur
Beschreibung
MediaSource.readyState gibt an, in welchem Zustand sich eine MediaSource gerade befindet. Die Media Source Extensions (MSE) nutzt man, um Mediendaten wie HLS-/DASH-Segmente oder selbst erzeugte Streams per JavaScript an ein <video>- oder <audio>-Element zu übergeben. Viele Operationen sind nur in einem bestimmten Zustand erlaubt, deshalb prüft man readyState vorher.
"closed": Die Quelle ist an kein Medienelement angehängt. Das gilt direkt nachnew MediaSource()und nach dem Lösen vom Element."open": Die Quelle ist angehängt und kann Daten annehmen. Nur in diesem Zustand funktionierenaddSourceBuffer(), das Setzen vondurationundendOfStream()."ended": Die Quelle ist angehängt, aberendOfStream()wurde aufgerufen. Hängt man danach neue Daten an oder ruftappendBuffer()auf, springt der Zustand wieder auf"open".
Jeder Zustandswechsel löst ein Ereignis aus: sourceopen, sourceended oder sourceclose. Statt readyState regelmäßig abzufragen, reagiert man am besten auf diese Ereignisse. Ein typisches Beispiel ist, Puffer erst im sourceopen-Handler anzulegen.
Rückgabewert
MediaSource.Beispiele
Zustand vor und nach dem Anhängen an ein Video
const video = document.querySelector('video');
const mediaSource = new MediaSource();
console.log(mediaSource.readyState); // noch nicht angehängt
video.src = URL.createObjectURL(mediaSource);
mediaSource.addEventListener('sourceopen', () => {
console.log(mediaSource.readyState);
}, { once: true });
Segmente laden und den Stream sauber beenden
const video = document.querySelector('video');
const mime = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
const mediaSource = new MediaSource();
video.src = URL.createObjectURL(mediaSource);
const appendSegment = (sb, data) => new Promise((resolve, reject) => {
sb.addEventListener('updateend', resolve, { once: true });
sb.addEventListener('error', reject, { once: true });
sb.appendBuffer(data);
});
mediaSource.addEventListener('sourceopen', async () => {
URL.revokeObjectURL(video.src);
const sb = mediaSource.addSourceBuffer(mime);
for (const url of ['/media/init.mp4', '/media/seg1.m4s', '/media/seg2.m4s']) {
const data = await (await fetch(url)).arrayBuffer();
// Wurde die Quelle inzwischen geschlossen (z. B. neue src)? Dann abbrechen.
if (mediaSource.readyState !== 'open') return;
await appendSegment(sb, data);
}
if (mediaSource.readyState === 'open' && !sb.updating) {
mediaSource.endOfStream();
}
console.log(mediaSource.readyState);
}, { once: true });
Hilfsfunktion: sicheres endOfStream()
const safeEndOfStream = (ms, error) => {
const busy = [...ms.sourceBuffers].some((sb) => sb.updating);
if (ms.readyState !== 'open' || busy) {
console.warn(`endOfStream übersprungen (readyState: ${ms.readyState})`);
return false;
}
error ? ms.endOfStream(error) : ms.endOfStream();
return true;
};
const ms = new MediaSource();
safeEndOfStream(ms);
// Wichtig · Fallstricke
- InvalidStateError: Wird
addSourceBuffer(),endOfStream()oder derduration-Setter aufgerufen, währendreadyStatenicht"open"ist, wirft der Browser eineDOMException. BeiendOfStream()unddurationpassiert das auch, solange einSourceBuffernochupdating === truehat. - Direkt nach dem Setzen von
video.srcist der Zustand noch"closed". Die Quelle öffnet sich asynchron, deshalb aufsourceopenwarten. - Bei
"ended"setzt ein erneutesappendBuffer()den Zustand automatisch zurück auf"open". Das ist praktisch für Live-Streams, kann aber unerwartet sein. - Die Eigenschaft ist schreibgeschützt. Eine Zuweisung wird ignoriert (im Strict Mode gibt es einen
TypeError). - Kompatibilität: MSE wird von allen Desktop-Browsern unterstützt. iPhone-Safari bietet erst ab iOS 17.1
ManagedMediaSourcean, das ebenfallsreadyStatehat. Vorab mit'MediaSource' in windowbzw.MediaSource.isTypeSupported()prüfen. In Dedicated Workern stehtMediaSourcein Chrome ab Version 108 zur Verfügung.