WebRTC video/audio 流不同步(MediaStream -> MediaRecorder -> MediaSource -> 视频元素)
WebRTC video/audio streams out of sync (MediaStream -> MediaRecorder -> MediaSource -> Video Element)
我正在使用 MediaStream 并使用 canvas 和 WebAudio API 合并两个单独的轨道(视频和音频)。 MediaStream 本身似乎并没有不同步,但在将其读入 MediaRecorder 并将其缓冲到视频元素后,音频似乎总是比视频播放得早得多这里是似乎有问题的代码:
let stream = new MediaStream();
// Get the mixed sources drawn to the canvas
this.canvas.captureStream().getVideoTracks().forEach(track => {
stream.addTrack(track);
});
// Add mixed audio tracks to the stream
//
this.audioMixer.dest.stream.getAudioTracks().forEach(track => {
stream.addTrack(track);
});
// stream = stream;
let mediaRecorder = new MediaRecorder(stream, { mimeType: 'video/webm;codecs=opus,vp8' });
let mediaSource = new MediaSource();
let video = document.createElement('video');
video.src = URL.createObjectURL(mediaSource);
document.body.appendChild(video);
video.controls = true;
video.autoplay = true;
// Source open
mediaSource.onsourceopen = () => {
let sourceBuffer = mediaSource.addSourceBuffer(mediaRecorder.mimeType);
mediaRecorder.ondataavailable = (event) => {
if (event.data.size > 0) {
const reader = new FileReader();
reader.readAsArrayBuffer(event.data);
reader.onloadend = () => {
sourceBuffer.appendBuffer(reader.result);
console.log(mediaSource.sourceBuffers);
console.log(event.data);
}
}
}
mediaRecorder.start(1000);
}
AudioMixer.js
export default class AudioMixer {
constructor() {
// Initialize an audio context
this.audioContext = new AudioContext();
// Destination outputs one track of mixed audio
this.dest = this.audioContext.createMediaStreamDestination();
// Array of current streams in mixer
this.sources = [];
}
// Add an audio stream to the mixer
addStream(id, stream) {
// Get the audio tracks from the stream and add them to the mixer
let sources = stream.getAudioTracks().map(track => this.audioContext.createMediaStreamSource(new MediaStream([track])));
sources.forEach(source => {
// Add it to the current sources being mixed
this.sources.push(source);
source.connect(this.dest);
// Connect to analyser to update volume slider
let analyser = this.audioContext.createAnalyser();
source.connect(analyser);
...
});
}
// Remove all current sources from the mixer
flushAll() {
this.sources.forEach(source => {
source.disconnect(this.dest);
});
this.sources = [];
}
// Clean up the audio context for the mixer
cleanup() {
this.audioContext.close();
}
}
我认为这与数据如何被推入 MediaSource 缓冲区有关,但我不确定。我在做什么使流不同步?
对旧 post 的迟到回复,但它可能会对某人有所帮助...
我遇到了完全相同的问题:我有一个视频流,应该辅以音频流。音频流中不时播放短促的声音(AudioBuffer)。整个事情都是通过 MediaRecorder 记录的。
在 Chrome 上一切正常。但是在 Chrome for Android 上,所有声音都快速连续播放。 "play()" 的 "when" 参数在 Android 上被忽略。 (audiocontext.currentTime 随着时间的推移继续增加...... - 这不是重点)。
我的解决方案类似于 Jacob 于 2018 年 9 月 2 日在 7:41 发表的评论:
我创建并连接了一个频率为 48,000 Hz 的正弦波振荡器,它在录音期间在音频流中永久播放。显然这会导致正确的时间进度。
Chrome 中存在一个错误,它播放 44100KHz 的缓冲媒体流音频,即使它是用 48000 编码的(这会导致间隙和视频不同步)。所有其他浏览器似乎都可以正常播放。您可以选择将编解码器更改为支持 44.1KHz 编码的编解码器或从网络 link 播放文件作为源(这样 Chrome 可以正确播放)
发出多个相关 RTP 流的 RTP 端点
要求在其他端点同步必须使用相同的
所有要同步的流的 RTCP CNAME。这个
需要 short-term 通用的持久 RTCP CNAME
几个 RTP 流,并且可能跨越多个相关的 RTP
session秒。 lip-syncing 音频时出现这种用法的一个常见示例
和多媒体 session 中的视频流,其中单个参与者
必须为其音频 RTP session 及其
视频 RTP session。另一个例子可能是同步
分层音频编解码器的层,其中必须有相同的 RTCP CNAME
用于每一层。
我正在使用 MediaStream 并使用 canvas 和 WebAudio API 合并两个单独的轨道(视频和音频)。 MediaStream 本身似乎并没有不同步,但在将其读入 MediaRecorder 并将其缓冲到视频元素后,音频似乎总是比视频播放得早得多这里是似乎有问题的代码:
let stream = new MediaStream();
// Get the mixed sources drawn to the canvas
this.canvas.captureStream().getVideoTracks().forEach(track => {
stream.addTrack(track);
});
// Add mixed audio tracks to the stream
//
this.audioMixer.dest.stream.getAudioTracks().forEach(track => {
stream.addTrack(track);
});
// stream = stream;
let mediaRecorder = new MediaRecorder(stream, { mimeType: 'video/webm;codecs=opus,vp8' });
let mediaSource = new MediaSource();
let video = document.createElement('video');
video.src = URL.createObjectURL(mediaSource);
document.body.appendChild(video);
video.controls = true;
video.autoplay = true;
// Source open
mediaSource.onsourceopen = () => {
let sourceBuffer = mediaSource.addSourceBuffer(mediaRecorder.mimeType);
mediaRecorder.ondataavailable = (event) => {
if (event.data.size > 0) {
const reader = new FileReader();
reader.readAsArrayBuffer(event.data);
reader.onloadend = () => {
sourceBuffer.appendBuffer(reader.result);
console.log(mediaSource.sourceBuffers);
console.log(event.data);
}
}
}
mediaRecorder.start(1000);
}
AudioMixer.js
export default class AudioMixer {
constructor() {
// Initialize an audio context
this.audioContext = new AudioContext();
// Destination outputs one track of mixed audio
this.dest = this.audioContext.createMediaStreamDestination();
// Array of current streams in mixer
this.sources = [];
}
// Add an audio stream to the mixer
addStream(id, stream) {
// Get the audio tracks from the stream and add them to the mixer
let sources = stream.getAudioTracks().map(track => this.audioContext.createMediaStreamSource(new MediaStream([track])));
sources.forEach(source => {
// Add it to the current sources being mixed
this.sources.push(source);
source.connect(this.dest);
// Connect to analyser to update volume slider
let analyser = this.audioContext.createAnalyser();
source.connect(analyser);
...
});
}
// Remove all current sources from the mixer
flushAll() {
this.sources.forEach(source => {
source.disconnect(this.dest);
});
this.sources = [];
}
// Clean up the audio context for the mixer
cleanup() {
this.audioContext.close();
}
}
我认为这与数据如何被推入 MediaSource 缓冲区有关,但我不确定。我在做什么使流不同步?
对旧 post 的迟到回复,但它可能会对某人有所帮助...
我遇到了完全相同的问题:我有一个视频流,应该辅以音频流。音频流中不时播放短促的声音(AudioBuffer)。整个事情都是通过 MediaRecorder 记录的。 在 Chrome 上一切正常。但是在 Chrome for Android 上,所有声音都快速连续播放。 "play()" 的 "when" 参数在 Android 上被忽略。 (audiocontext.currentTime 随着时间的推移继续增加...... - 这不是重点)。
我的解决方案类似于 Jacob 于 2018 年 9 月 2 日在 7:41 发表的评论: 我创建并连接了一个频率为 48,000 Hz 的正弦波振荡器,它在录音期间在音频流中永久播放。显然这会导致正确的时间进度。
Chrome 中存在一个错误,它播放 44100KHz 的缓冲媒体流音频,即使它是用 48000 编码的(这会导致间隙和视频不同步)。所有其他浏览器似乎都可以正常播放。您可以选择将编解码器更改为支持 44.1KHz 编码的编解码器或从网络 link 播放文件作为源(这样 Chrome 可以正确播放)
发出多个相关 RTP 流的 RTP 端点 要求在其他端点同步必须使用相同的 所有要同步的流的 RTCP CNAME。这个 需要 short-term 通用的持久 RTCP CNAME 几个 RTP 流,并且可能跨越多个相关的 RTP session秒。 lip-syncing 音频时出现这种用法的一个常见示例 和多媒体 session 中的视频流,其中单个参与者 必须为其音频 RTP session 及其 视频 RTP session。另一个例子可能是同步 分层音频编解码器的层,其中必须有相同的 RTCP CNAME 用于每一层。