在什么情况下,<audio>静音元素也会影响其 srcObject 的连接节点?



我知道标题可能有点令人困惑,所以让我给出一些背景。

我正在写一个扩展做一些音频操作与谷歌见面,并且,在研究它的行为后,我发现了一个奇怪的问题,我似乎不能把我的头围绕。

Google Meet似乎使用三个<audio>元素来播放音频,每个元素都有自己的MediaStreams。经过一些测试,似乎:

  • 静音<audio>元素停止谷歌会议的音频可视化,谁在说话。
  • 交换两个音频元素的.srcObject属性,然后对它们调用.play()不影响Google Meet的音频可视化。

这些似乎指向Google Meet将源MediaStream连接到其音频处理图中以创建可视化,而不是捕获<audio>元素,因为我可以在不影响可视化的情况下交换MediaStream。

然而,考虑到过去的信息,我注意到的另一件事似乎没有意义:

  • <audio>元素的.srcObject添加一个新的MediaStreamAudioSourceNode并将其连接到AnalyserNode显示,即使我静音<audio>元素,我仍然可以分析通过MediaStream播放的音频

下面是一些示例代码和通过浏览器控制台完成的输出:

ac = new AudioContext();
an = ac.createAnalyser()
sn = ac.createMediaStreamSource(document.querySelectorAll("audio")[0].srcObject)
sn.connect(an)
function analyse(aNode) {
const ret = new Float32Array(aNode.frequencyBinCount);
aNode.getFloatTimeDomainData(ret);
return ret;
}
analyse(an)
// > Float32Array(1024) [ 0.342987060546875, 0.36688232421875, 0.37115478515625, 0.362457275390625, 0.35150146484375, 0.3402099609375, 0.321075439453125, 0.308746337890625, 0.29779052734375, 0.272552490234375, … ]
document.querySelectorAll("audio")[0].muted = true
analyse(an)
// > Float32Array(1024) [ -0.203582763671875, -0.258026123046875, -0.31134033203125, -0.34375, -0.372802734375, -0.396484375, -0.3919677734375, -0.36328125, -0.31689453125, -0.247650146484375, … ]
// Here, I mute the microphone on *my end* through Google Meet.
analyse(an)
// > Float32Array(1024) [ -0.000030517578125, 0, 0, -0.000030517578125, -0.000091552734375, -0.000091552734375, -0.000091552734375, -0.00006103515625, 0, 0.000030517578125, … ]
// The values here are much closer to zero.

可以看到,当音频元素被静音时,AnalyserNode仍然可以拾取音频,但是Meet的可视化中断了。这就是我不明白的地方。这怎么可能呢?

<audio>元素被静音时,连接的AnalyserNode如何不中断,但其他东西是,不使用.captureStream()?

另一个奇怪的事情是,它只发生在Chrome. 在Firefox上,即使音频元素是静音的,Meet的可视化效果也很好。我认为这可能与已知的Chrome问题有关,其中MediaStreams需要播放<audio>元素来输出任何音频图形(https://stackoverflow.com/a/55644983),但我看不出这会如何影响静音<audio>元素。

这有点令人困惑,但AudioElement.captureStream()的行为实际上不同于使用MediaElementAudioSourceNode

new MediaStreamAudioSourceNode(audioContext, audioElement.captureStream());
// is not equal to
new MediaElementAudioSourceNode(audioContext, audioElement);

调用AudioElement.captureStream()获得的流不受音频元素上任何音量变化的影响。调用AudioElement.captureStream()也不会改变音频元素本身的音量。

然而,使用MediaElementAudioSourceNode会将音频元素的音频重新路由到AudioContext。音频将受到对音频元素所做的任何音量更改的影响。这意味着对音频元素进行静音将导致对传入AudioContext的音频进行静音。

在此之上,使用MediaElementAudioSourceNode将使audio元素本身静音。

我假设Google Meet为每个音频元素使用MediaElementAudioSourceNode来处理音频。

最新更新