当流挂起时,远程流上的 WebRTC MediaRecorder 会中断

WebRTC MediaRecorder on remote stream cuts when the stream hangs

问题:

在 WebRTC 单播视频会议期间,我可以成功地将视频从移动设备的网络摄像头传输到 laptop/desktop。我想在 laptop/desktop 端录制远程流。 (设置是移动设备流式传输到 laptop/desktop)。

不过,视频流时不时挂掉是常有的事。这不是问题,因为 "viewer" 一方会赶上来的。但是,远程流的录制会在第一次挂起时停止。

最小和删除的实现(本地录制):

我可以成功录制来自navigator.mediaDevices.getUserMedia()的本地流如下:

const recordedChunks = [];

navigator.mediaDevices.getUserMedia({
    video: true,
    audio: false
}).then(stream => {
    const localVideoElement = document.getElementById('local-video');
    localVideoElement.srcObject = stream;
    return stream;
}).then(stream => {
    const mediaRecorder = new MediaRecorder(stream);
    mediaRecorder.ondataavailable = (event) => {
        if(event.data && event.data.size > 0) {
            recordedChunks.push(event.data);
        }
    };
    mediaRecorder.start({ mimeType: 'video/webm;codecs=vp9' }, 10);
});

我可以很容易地下载这个,如下所示:

const blob = new Blob(recordedChunks, { type: 'video/webm' });

const url = URL.createObjectURL(blob);
const a = document.createElement('a');
document.body.appendChild(a);
a.style = 'display: none';
a.href = url;
a.download = 'test.webm';
a.click();
window.URL.revokeObjectURL(url);

最小化和删除的实现(远程录制):

我使用的设置需要录制远程流,而不是本地流,因为 IOS Safari 不支持 MediaRecorder API。我包括上面的内容以表明录音在本地工作。远程流录制的实现没有什么不同,只是我手动向视频添加了一个 0 Hz 的音轨,因为 Chrome 似乎有一个没有音轨就无法录制的错误。

const mediaStream = new MediaStream();
const audioContext = new AudioContext();

const destinationNode = audioContext.createMediaStreamDestination();

const oscillatorNode = audioContext.createOscillator();
oscillatorNode.frequency.setValueAtTime(0, audioContext.currentTime);
oscillatorNode.connect(destinationNode);

const audioTrack = destinationNode.stream.getAudioTracks()[0];
const videoTrack = remoteStream.getVideoTracks()[0]; // Defined somewhere else.

mediaStream.addTrack(videoTrack);
mediaStream.addTrack(audioTrack);

然后我执行与上面的本地流示例完全相同的操作来记录 mediaStream 变量。

如前所述,在远程流挂起的第一点(可能是由于网络延迟),远程录制停止,因此在下载时,.webm 文件的持续时间转换为 .mp4,通过 ffmpeg,仅与第一次挂起发生的位置一样长。

缓解尝试:

我尝试过的一种缓解此问题的尝试是,我没有记录在来自 WebRTC 的 ontrack 事件的回调中获得的远程流,而是使用来自远程视频元素的视频流, 通过 remoteVideoElement.captureStream()。这无法解决问题。

如有任何帮助,我们将不胜感激。谢谢。

希望有人能够 post 为您解决实际问题。与此同时,一个讨厌的、低效的、完全不推荐的解决方法:

  1. 将传入的 MediaStream 路由到视频元素。
  2. 使用 requestAnimationFrame() 将绘图框架安排​​到 canvas。 (请注意,这会消除原始视频中的任何同步锁定感,这不是您想要做的事情。不幸的是,据我所知,我们无法知道何时出现传入帧。)
  3. 使用 CanvasCaptureMediaStream 作为视频源。
  4. 将来自 CanvasCaptureMediaStream 的视频轨道与来自原始 MediaStream 的音频轨道重新组合到新的 MediaStream 中。
  5. 将这个新的 MediaStream 用于 MediaRecorder。

在过去的项目中,我需要以编程方式操作音频和视频。有效!

一个重要的警告是 Chrome 中存在一个错误,即使捕获流附加到 canvas,如果选项卡未更新,canvas 也不会更新't active/visible。当然,如果选项卡未处于活动状态,requestAnimationFrame 最多会受到严重限制,因此您需要另一个帧时钟源。 (我用的是音频处理器,哈!)