当流挂起时,远程流上的 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 为您解决实际问题。与此同时,一个讨厌的、低效的、完全不推荐的解决方法:
- 将传入的 MediaStream 路由到视频元素。
- 使用
requestAnimationFrame()
将绘图框架安排到 canvas。 (请注意,这会消除原始视频中的任何同步锁定感,这不是您想要做的事情。不幸的是,据我所知,我们无法知道何时出现传入帧。)
- 使用 CanvasCaptureMediaStream 作为视频源。
- 将来自 CanvasCaptureMediaStream 的视频轨道与来自原始 MediaStream 的音频轨道重新组合到新的 MediaStream 中。
- 将这个新的 MediaStream 用于 MediaRecorder。
在过去的项目中,我需要以编程方式操作音频和视频。有效!
一个重要的警告是 Chrome 中存在一个错误,即使捕获流附加到 canvas,如果选项卡未更新,canvas 也不会更新't active/visible。当然,如果选项卡未处于活动状态,requestAnimationFrame 最多会受到严重限制,因此您需要另一个帧时钟源。 (我用的是音频处理器,哈!)
问题:
在 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 为您解决实际问题。与此同时,一个讨厌的、低效的、完全不推荐的解决方法:
- 将传入的 MediaStream 路由到视频元素。
- 使用
requestAnimationFrame()
将绘图框架安排到 canvas。 (请注意,这会消除原始视频中的任何同步锁定感,这不是您想要做的事情。不幸的是,据我所知,我们无法知道何时出现传入帧。) - 使用 CanvasCaptureMediaStream 作为视频源。
- 将来自 CanvasCaptureMediaStream 的视频轨道与来自原始 MediaStream 的音频轨道重新组合到新的 MediaStream 中。
- 将这个新的 MediaStream 用于 MediaRecorder。
在过去的项目中,我需要以编程方式操作音频和视频。有效!
一个重要的警告是 Chrome 中存在一个错误,即使捕获流附加到 canvas,如果选项卡未更新,canvas 也不会更新't active/visible。当然,如果选项卡未处于活动状态,requestAnimationFrame 最多会受到严重限制,因此您需要另一个帧时钟源。 (我用的是音频处理器,哈!)