Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MediaRecorder API recorder won't call onstop when recording multiple tracks

I've got a very weird issue with the MediaRecorder API which I haven't been able to fix the last two days.

This simplified sample works perfectly fine, when I click the Chrome UI "Stop Sharing" button, everything stops appropriately:

desktopStream = await navigator.mediaDevices.getDisplayMedia({
    video: true,
    audio: true,
});

let rec = new MediaRecorder(desktopStream, {
    mimeType: "video/webm; codecs=vp8,opus",
});

rec.onstop = async () => {
  desktopStream.getTracks().forEach((s) => s.stop());
  desktopStream = null;

  //blobs.push(MediaRecorder.requestData());
  blob = new Blob(blobs, {
    type: "video/webm",
  });
};

However this doesn't, it keeps recording (or some MediaTracks keep running, not entirely sure):

desktopStream = await navigator.mediaDevices.getDisplayMedia({
    video: true,
    audio: true,
});

voiceStream = await navigator.mediaDevices.getUserMedia({
    video: false,
    audio: true,
  });

// this is the culprit, when commented everything works as expected
desktopStream.addTrack(voiceStream.getAudioTracks()[0]);

let rec = new MediaRecorder(desktopStream, {
    mimeType: "video/webm; codecs=vp8,opus",
});

rec.onstop = async () => {
  //explicitly stop tracks
  desktopStream.getTracks().forEach((s) => s.stop();
  voiceStream.getTracks().forEach((s) => s.stop());

  desktopStream = null;
  voiceStream = null;

  //blobs.push(MediaRecorder.requestData());
  blob = new Blob(blobs, {
    type: "video/webm",
  });
};

The second code block results in chrome still showing this red recording icon. I've read many times that you need to stop the tracks manually in a forEach loop, which I do, but it never gets to that, the recorder.onstop function doesn't seem to get called.

Here's the complete fiddle: https://jsfiddle.net/agcty/xhb0c4o3/19/

Steps to reproduce:

  1. Click "Start Recording"
  2. Select Screen
  3. Do anything for some seconds
  4. Click the Chrome "Stop Sharing" button, not the button in the fiddle
  5. The red recording icon will still show and you can't download the recording when clicking "Download"
  6. Click "Stop Recording" (the button in the fiddle), now the recording is properly stopped
  7. Now comment the line "desktopStream.addTrack(voiceStream.getAudioTracks()[0]);"
  8. Everything works

enter image description here

like image 570
Alex Gogl Avatar asked Sep 02 '25 04:09

Alex Gogl


1 Answers

Ok, after very very extensive debugging I found out that when you click the "Stop Sharing" button, the recorder isn't actually stopped. That was just a wrong assumption I made due to the wording.

According to the documentation (https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder/onstop) the recorder stops, when all MediaStreams that are being recorded stop, or when the recorder is stopped manually.

"Stop Sharing" only stops the screenStream MediaTracks. There is no onstop event happening whatsoever. The first example worked, because this was the only stream that was being captured, so stopping it meant that onstop was automatically called.

Visually this looks like:

enter image description here

The workaround is somewhat hidden but it works beautifully:

Just add an event listener to when the screenStream tracks are stopped, then manually stop the voiceStream tracks, resulting in the recorder not capturing anything anymore which in turn means it stops entirely. Yaaayy.

screenStream.getTracks().forEach((track) =>
      track.addEventListener("ended", () => {
        voiceStream.getAudioTracks().forEach((audio) => audio.stop());
        if (recorder) recorder.stop();
        recorder = null;
      })
    ); 
like image 171
Alex Gogl Avatar answered Sep 05 '25 02:09

Alex Gogl