MediaRecorder API 录音机在录制多个曲目时不会调用 onstop

Ale*_*ogl 3 javascript screen-capture web-mediarecorder

我的 MediaRecorder API 遇到了一个非常奇怪的问题,过去两天我一直无法解决这个问题。

这个简化的示例工作得很好,当我单击 Chrome UI“停止共享”按钮时,一切都会适当停止:

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",
  });
};
Run Code Online (Sandbox Code Playgroud)

然而事实并非如此,它会继续录制(或者某些 MediaTrack 继续运行,不完全确定):

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",
  });
};
Run Code Online (Sandbox Code Playgroud)

第二个代码块导致 chrome 仍然显示这个红色录音图标。我已经读过很多次,您需要在 forEach 循环中手动停止曲目,我就是这样做的,但它永远不会达到这一点, recorder.onstop 函数似乎没有被调用。

这是完整的小提琴:https://jsfiddle.net/agcty/xhb0c4o3/19/

重现步骤:

  1. 点击“开始录制”
  2. 选择屏幕
  3. 做任何事情几秒钟
  4. 单击 Chrome 的“停止共享”按钮,而不是小提琴中的按钮
  5. 单击“下载”时,红色录音图标仍会显示,并且无法下载录音
  6. 单击“停止录制”(小提琴中的按钮),现在录制已正确停止
  7. 现在注释行“desktopStream.addTrack(voiceStream.getAudioTracks()[0]);”
  8. 一切正常

在此输入图像描述

Ale*_*ogl 6

好的,经过非常非常广泛的调试,我发现当您单击“停止共享”按钮时,录音机实际上并没有停止。这只是我因措辞而做出的错误假设。

根据文档(https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder/onstop),当正在录制的所有 MediaStream 停止或手动停止录制器时,录制器将停止。

“停止共享”仅停止 screenStream MediaTracks。没有任何 onstop 事件发生。第一个示例有效,因为这是唯一被捕获的流,因此停止它意味着自动调用 onstop。

从视觉上看,这看起来像:

在此输入图像描述

解决方法有点隐藏,但效果很好:

只需在 screenStream 轨道停止时添加一个事件监听器,然后手动停止 voiceStream 轨道,导致录音机不再捕获任何内容,这意味着它完全停止。是啊。

screenStream.getTracks().forEach((track) =>
      track.addEventListener("ended", () => {
        voiceStream.getAudioTracks().forEach((audio) => audio.stop());
        if (recorder) recorder.stop();
        recorder = null;
      })
    ); 
Run Code Online (Sandbox Code Playgroud)