Signatur
Beschreibung
Das Ereignis sourceclose gehört zur Media Source Extensions API (MSE). Es tritt auf, sobald ein MediaSource-Objekt in den Zustand "closed" wechselt. Das passiert, wenn die Quelle von ihrem HTMLMediaElement getrennt wird, etwa weil video.src neu gesetzt oder entfernt wird, weil video.load() aufgerufen wird oder weil das Element eine andere Quelle lädt.
Wofür braucht man das? Vor allem zum Aufräumen: Timer für das Nachladen von Segmenten stoppen, laufende fetch-Anfragen per AbortController abbrechen, Objekt-URLs mit URL.revokeObjectURL() freigeben und interne Player-Zustände zurücksetzen. Ist die Quelle geschlossen, sind alle SourceBuffer aus mediaSource.sourceBuffers entfernt. Ein weiteres appendBuffer() wirft dann einen Fehler.
Registriert wird der Handler entweder mit addEventListener("sourceclose", handler) oder über die Eigenschaft onsourceclose. Das Ereignis ist ein einfaches Event ohne zusätzliche Eigenschaften. Es blubbert nicht (bubbles) und lässt sich nicht abbrechen. Den typischen Lebenszyklus bilden sourceopen → (sourceended) → sourceclose.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | Der Ereignisname "sourceclose". |
|
| $handler Pflicht | (event: Event) => void | Callback, der ein einfaches Event erhält. event.target ist das betroffene MediaSource-Objekt. |
|
| $options | boolean | AddEventListenerOptions | false | Optionen wie { once: true } oder { signal } zum späteren automatischen Entfernen. |
Rückgabewert
addEventListener gibt nichts zurück. Auch der Rückgabewert des Handlers wird ignoriert.Beispiele
Aufräumen beim Schließen der Quelle
const video = document.querySelector('video');
const mediaSource = new MediaSource();
const url = URL.createObjectURL(mediaSource);
video.src = url;
const controller = new AbortController();
mediaSource.addEventListener('sourceopen', async () => {
const sb = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.42E01E, mp4a.40.2"');
const res = await fetch('/media/init.mp4', { signal: controller.signal });
sb.appendBuffer(await res.arrayBuffer());
}, { once: true });
mediaSource.addEventListener('sourceclose', () => {
console.log('readyState:', mediaSource.readyState);
controller.abort(); // laufende Downloads stoppen
URL.revokeObjectURL(url); // Speicher freigeben
});
// Später: Quelle wechseln, dadurch wird sourceclose ausgelöst
setTimeout(() => {
video.removeAttribute('src');
video.load();
}, 5000);
Handler über onsourceclose setzen und wieder entfernen
const mediaSource = new MediaSource();
const video = document.createElement('video');
video.src = URL.createObjectURL(mediaSource);
mediaSource.onsourceclose = (event) => {
console.log('Geschlossen:', event.type, event.target.sourceBuffers.length);
};
// Handler wieder entfernen
// mediaSource.onsourceclose = null;
mediaSource.addEventListener('sourceopen', () => {
video.src = ''; // trennt die MediaSource, danach folgt sourceclose
}, { once: true });
removeEventListener in einer Player-Klasse
class MsePlayer {
#ms = new MediaSource();
#timer = null;
constructor(video) {
this.video = video;
this.onClose = this.onClose.bind(this);
this.#ms.addEventListener('sourceclose', this.onClose);
video.src = URL.createObjectURL(this.#ms);
this.#timer = setInterval(() => console.log('Puffer prüfen ...'), 1000);
}
onClose() {
clearInterval(this.#timer);
this.#ms.removeEventListener('sourceclose', this.onClose);
console.log('Player aufgeräumt');
}
destroy() {
this.video.removeAttribute('src');
this.video.load();
}
}
const player = new MsePlayer(document.querySelector('video'));
setTimeout(() => player.destroy(), 3000);
// Wichtig · Fallstricke
- Nicht mit
sourceendedverwechseln:endOfStream()setzt den Zustand auf"ended"und löstsourceendedaus, aber nichtsourceclose. Geschlossen wird die Quelle erst beim Trennen vom Medienelement. - Nach
sourceclosesind alleSourceBufferentfernt. Aufrufe wieappendBuffer()oderendOfStream()werfen dann einenInvalidStateError. Asynchrone Lade-Schleifen sollten deshalb vor jedem AnhängenmediaSource.readyStateprüfen. - Das Ereignis wird asynchron ausgelöst. Direkt nach
video.src = ''istreadyStateeventuell noch nicht"closed". - Eine geschlossene
MediaSourcelässt sich über eine neue Objekt-URL erneut anhängen. Meist ist ein neues Objekt aber sauberer. - Kompatibilität: MSE wird von allen Desktop-Browsern unterstützt. Auf dem iPhone steht MSE erst ab iOS 17.1 als
ManagedMediaSourcezur Verfügung. Vorher prüfen, zum Beispiel mit'MediaSource' in window. In Dedicated Workern istMediaSourcenur in manchen Browsern verfügbar (Chrome 108+).