在我的 chrome 扩展中,我使用
AudioContext
和 AudioNode
将两个流合并为一个流,其中一个位于左通道,另一个位于右通道。当左通道音量高于某个阈值时,我还想在出于录音目的而合并之前对右通道进行选通(静音)。现实世界的用例是,左流是通过当前选项卡播放的音频的直接音频录制,右流是麦克风输入。如果用户没有戴耳机,那么麦克风输入会拾取正在播放的流的(稍微时移延迟的)流血,我想将其静音。在我的用例中,录音始终是双向对话,因此实际上不需要两个人同时讲话,在这种情况下,我仍然会优先考虑左流。
下面是我合并音频流的代码。我相信 AudioWorklet 可以帮助我在录制之前实时处理流,或者可能使用 CustomNode - 但我无法使用这些音频 API 找到足够的指导性示例。
const mergeAudioStreams = (leftStream: MediaStream, rightStream: MediaStream) => {
// Create an AudioContext
const audioContext = new AudioContext();
const leftSource = audioContext.createMediaStreamSource(leftStream);
const rightSource = audioContext.createMediaStreamSource(rightStream);
const merger = audioContext.createChannelMerger(2);
merger.channelInterpretation = 'speakers'
merger.channelInterpretation = 'speakers';
leftSource.connect(merger, 0, 0); // Left channel
rightSource.connect(merger, 0, 1); // Right channel
const destination = audioContext.createMediaStreamDestination();
merger.connect(destination);
// Create a new MediaStream from the MediaStreamDestination
const combinedStream = destination.stream;
return combinedStream;
};
感谢您的指导。
听起来您的问题可以通过设置来解决
echoCancellation
当请求麦克风输入时,按 true
。
navigator.mediaDevices.getUserMedia({ audio: { echoCancellation: true } });
如果这不起作用,您还可以使用
AudioWorklet
在流之间切换。
我设置了一个演示,它使用两个振荡器作为源节点。左声道的音量通过
GainNode
进行调制以模拟您的用例。
https://stackblitz.com/edit/vitejs-vite-jypuvr
process()
内部的AudioWorklet
函数计算左声道的音量,并用它来决定是否应该通过左声道或右声道。
process([input], [output]) {
if (input.length === 2) {
let volume = 0;
for (let i = 0; i < input[0].length; i += 1) {
volume += input[0][i] ** 2;
}
volume = Math.sqrt(volume / input[0].length);
if (volume > 0.4) {
output[0].set(input[0]);
} else {
output[0].set(input[1]);
}
}
return true;
}
该演示仅查看当前渲染量子的样本并执行硬切换。您可能需要对此进行调整以使结果更令人愉快。