整个项目是复杂的,所以这里是管道的简单描述:
- 一个或多个声源是
AudioContext
图的输入。输入来自MediaStream
对象,所以我使用context.createMediaStreamSource()
创建源节点。 - 输出也是
MediaStream
,所以我使用context.createMediaStreamDestination()
作为目标节点。 - 输出音轨被复制到包含视频轨道的
MediaStream
。此流用于记录。 - 录音以webm形式完成,内容以块的形式保存。
- 块被附加到一个
SourceBuffer
对象连接到一个MediaSource
对象播放成视频标签。
我遇到的问题是,仅在Chrome中,通过媒体源播放有噼啪作响和弹出。此外,对于较长的录音(1-2分钟),音轨可以提前几秒钟结束。如果我不通过Web audio API图管道音频,则不会发生。也就是说,如果我给MediaRecorder
提供一个带有本地视频和音频轨道的常规流,播放是完美的。
还应该注意的是,即使使用Web Audio API输入,如果将webm内容放入blob中,然后放入URL并从中播放,则播放时也不会出现噼啪声或弹出声。如果从浏览器中提取webm内容并在视频播放器中播放,也不会出现任何噼啪声或弹出声。
一些代码。
音频上下文创建如下:
let audioContext: AudioContext | null = null;
if (window.AudioContext) {
audioContext = new AudioContext({ sampleRate: 48000, latencyHint: 'interactive' });
} else if ((window as any).webkitAudioContext) {
audioContext = new (window as any).webkitAudioContext() as AudioContext;
}
构建图的代码有些复杂,因为我们必须做一些特殊的逻辑。但它本质上归结为:
// output stream
const stream = new MediaStream();
// videoInput contains a video source via getUserMedia()
for (const track of videoInput.videoTracks) {
stream.addTrack(track);
}
// send all audio inputs to this node
const collectionNode = audioContext.createMediaStreamDestination();
// here we set up just one source, but the real code may create more than one of these
const source = audioContext.createMediaStreamSource(input.stream);
source.connect(collectionNode);
// extract tracks and put them in the output stream
for (const track of collectionNode.stream.getAudioTracks()) {
stream.addTrack(track);
}
此时,stream
是提供给记录器的MediaStream
对象。
MSE代码在处理错误情况和缓冲方面也同样复杂。作为初始化的一部分,我设置了duration
属性,并且编解码器与录制中使用的编解码器完全相同。在系统中有一个早期检查,以确保记录器使用的编解码器也与媒体源兼容,在两者上使用isTypeSupported()
方法。
我发现了一些关于这个的Chromium bug,但都是几年前的。当Web Audio API不用于录音时,播放很好,这一事实对我来说意味着问题不一定与MSE有关。
我在这件事上有点卡住了。我很乐意提供更多信息。完整的代码太大了,不能放在这里,但我可以根据需要提供其他片段。
我有一个值得尝试的快速建议。我注意到如果我在audiocontext中设置采样率。例如:
audioContext = new AudioContext({ sampleRate: 48000, latencyHint: 'interactive' });
或者如果您在媒体记录器中设置audioBitsPerSecond,则可能导致糟糕的声音记录。尝试让这些未设置,让我知道,如果你得到同样的问题!