Start · Sprachen · JavaScript · Referenz · MediaRecorder: stop

MediaRecorder: stop

Ereignis

Wird ausgelöst, wenn eine <code>MediaRecorder</code>-Aufnahme endet – durch <code>stop()</code> oder weil der aufgenommene <code>MediaStream</code> endet.

seit JavaScript Baseline: alle modernen Browser (Safari ab 14.1) Kategorie: webapi

Signatur

mediaRecorder.addEventListener("stop", handler)

Beschreibung

Das stop-Ereignis signalisiert, dass eine Aufnahme mit MediaRecorder endgültig beendet ist. Es tritt ein, wenn MediaRecorder.prototype.stop() aufgerufen wird, wenn alle Spuren des aufgenommenen MediaStream enden (z. B. weil der Nutzer die Bildschirmfreigabe beendet oder die Kamera getrennt wird) oder wenn bei der Aufnahme ein Fehler auftritt.

Wichtig ist die Reihenfolge: Beim Stoppen feuert der Recorder zuerst ein letztes dataavailable-Ereignis mit den restlichen gepufferten Daten und erst danach stop. Deshalb ist der stop-Handler die richtige Stelle, um die gesammelten Blob-Stücke zu einer Datei zusammenzufügen, eine Vorschau anzuzeigen, einen Upload zu starten oder die Oberfläche zurückzusetzen.

Registrieren lässt sich der Handler per addEventListener("stop", handler) oder über die Eigenschaft onstop. Das übergebene Objekt ist ein einfaches Event ohne zusätzliche Eigenschaften; es ist nicht abbrechbar und steigt nicht auf (kein Bubbling). Zum Zeitpunkt des Ereignisses hat recorder.state bereits den Wert "inactive".

Parameter

Name Typ Default Beschreibung
$type Pflicht string Der Ereignistyp, hier immer "stop".
$handler Pflicht (event: Event) => void Rückruffunktion, die beim Ende der Aufnahme aufgerufen wird. Erhält ein einfaches Event-Objekt; event.target ist der MediaRecorder.
$options boolean | AddEventListenerOptions false Optionen wie { once: true } oder { signal } zum späteren Entfernen über einen AbortController.

Rückgabewert

Typ
void
Beschreibung
addEventListener gibt nichts zurück. Der Rückgabewert des Handlers wird ignoriert.

Beispiele

Mikrofon aufnehmen und bei stop als Datei bereitstellen

const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const recorder = new MediaRecorder(stream);
const chunks = [];

recorder.addEventListener("dataavailable", (e) => {
  if (e.data.size > 0) chunks.push(e.data);
});

recorder.addEventListener("stop", () => {
  // Letztes dataavailable ist bereits eingetroffen
  const blob = new Blob(chunks, { type: recorder.mimeType });
  const audio = document.querySelector("audio");
  audio.src = URL.createObjectURL(blob);
  console.log("Aufnahme fertig:", blob.size, "Bytes, Status:", recorder.state);
  // Mikrofon freigeben
  stream.getTracks().forEach((t) => t.stop());
});

recorder.start();
setTimeout(() => recorder.stop(), 5000); // nach 5 Sekunden stoppen
Aufnahme fertig: 81234 Bytes, Status: inactive

onstop-Eigenschaft: Bildschirmaufnahme, die vom Nutzer beendet wird

const stream = await navigator.mediaDevices.getDisplayMedia({ video: true });
const recorder = new MediaRecorder(stream, { mimeType: "video/webm" });
const chunks = [];

recorder.ondataavailable = (e) => chunks.push(e.data);

// Feuert auch, wenn der Nutzer im Browser "Freigabe beenden" klickt
recorder.onstop = () => {
  const blob = new Blob(chunks, { type: "video/webm" });
  const link = document.createElement("a");
  link.href = URL.createObjectURL(blob);
  link.download = "bildschirm.webm";
  link.click();
  console.log("Download gestartet");
};

recorder.start(1000); // alle 1000 ms ein Datenstück
Download gestartet

Aufnahme als Promise kapseln und Listener wieder entfernen

const recordFor = (stream, ms) => new Promise((resolve, reject) => {
  const recorder = new MediaRecorder(stream);
  const chunks = [];
  const onData = (e) => chunks.push(e.data);
  const onStop = () => {
    recorder.removeEventListener("dataavailable", onData);
    recorder.removeEventListener("stop", onStop);
    resolve(new Blob(chunks, { type: recorder.mimeType }));
  };
  recorder.addEventListener("dataavailable", onData);
  recorder.addEventListener("stop", onStop);
  recorder.addEventListener("error", (e) => reject(e.error ?? e), { once: true });
  recorder.start();
  setTimeout(() => recorder.state !== "inactive" && recorder.stop(), ms);
});

const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const blob = await recordFor(stream, 3000);
console.log(blob.type, blob.size);
audio/webm;codecs=opus 48213

// Wichtig · Fallstricke

  • Reihenfolge beachten: Den Blob nicht direkt nach recorder.stop() bauen – der Aufruf ist asynchron, das letzte dataavailable kommt erst später. Immer im stop-Handler zusammensetzen.
  • stop() auf einem Recorder im Zustand "inactive" wirft je nach Browser einen InvalidStateError bzw. tut nichts; vorher recorder.state prüfen.
  • Das Ereignis feuert auch, wenn der Stream von außen endet (Gerät getrennt, Bildschirmfreigabe beendet) – Aufräumlogik also nicht nur an den eigenen Stopp-Button koppeln.
  • Bei einem Fehler feuert zuerst error, danach ebenfalls stop. Im stop-Handler ggf. prüfen, ob die Aufnahme vollständig ist.
  • Speicher freigeben: mit URL.createObjectURL() erzeugte URLs später per URL.revokeObjectURL() wieder freigeben und Stream-Spuren mit track.stop() beenden, sonst bleibt die Kamera- bzw. Mikrofonanzeige aktiv.
  • Kompatibilität: In allen modernen Browsern verfügbar, in Safari erst ab 14.1. Unterstützte Formate unterscheiden sich (Safari: meist video/mp4, Chrome/Firefox: webm) – mit MediaRecorder.isTypeSupported() prüfen. getUserMedia funktioniert nur in sicheren Kontexten (HTTPS).