为什么setSinkId不能与BiquadFilters一起工作?



我正在尝试使音乐播放器具有实时改变输出设备(耳机或扬声器)的能力。我有工作功能,以改变目标设备与setSinkId。我也有工作Biquad滤波器(低通,高通…)和音频处理器,以产生增益水平条(下图)。滤波器滑块和增益条

部分代码(很多)。

设置输出设备:

if (audiooutput_ch1active == 0) {
if (typeof audiooutput_headphonesid !== "undefined") {
audiooutput_ch1active = 1;
await audio_ch1.setSinkId(audiooutput_headphonesid);
return;
}
} else if (audiooutput_ch1active == 1) {
if (typeof audiooutput_speakersid !== "undefined") {
audiooutput_ch1active = 0;
await audio_ch1.setSinkId(audiooutput_speakersid);
return;
}
}  

定义过滤器:

var filter_ch1_lowpass = audioCtx_ch1.createBiquadFilter();  
filter_ch1_lowpass.type = "lowpass";  
filter_ch1_lowpass.frequency.value = 12000;  
var filter_ch1_highpass = audioCtx_ch1.createBiquadFilter();  
filter_ch1_highpass.type = "highpass";  
filter_ch1_highpass.frequency.value = 0;  
var filter_ch1_lowshelf = audioCtx_ch1.createBiquadFilter();  
filter_ch1_lowshelf.type = "lowshelf";  
filter_ch1_lowshelf.frequency.value = 100;  
filter_ch1_lowshelf.gain.value = 0;

连接过滤器和处理器:

audio_ch1.src = path;
source_ch1 = audioCtx_ch1.createMediaElementSource(audio_ch1);
source_ch1.connect(filter_ch1_lowpass);
filter_ch1_lowpass.connect(filter_ch1_highpass);
filter_ch1_highpass.connect(filter_ch1_lowshelf);
filter_ch1_lowshelf.connect(processor_ch1);
filter_ch1_lowshelf.connect(audioCtx_ch1.destination);
processor_ch1.connect(filter_ch1_lowshelf);

当我将过滤器连接到我的音频上下文时,我不能使用setSinkId - Error: Uncaught (in promise) DOMException:该操作无法执行并被中止

当我跳过连接过滤器的代码时,setSinkId可以正常工作。

setSinkId不支持音频上下文过滤器吗?

我是JavaScript音频新手。

在您将<audio>的输出路由到音频上下文之后,您正在设置<audio>元素的接收器。<audio>已经失去了对其输出的控制,现在是音频上下文控制了它,因此你不能再设置<audio>元素的接收器了。

你可以在不使用过滤器的时候调用这个方法,这是Web Audio API中一个很大的Chrome bug的一部分,我相信他们正在积极地工作:基本上,他们只在音频图形连接到目的地时才真正创建连接。

你可以通过从你的<audio>创建一个MediaStream来避免这个错误,通过调用它的captureStream()方法,然后从MediaStream对象连接一个MediaStreamAudioSourceNode到你的音频图形。然而,你仍然只设置输入<audio>的接收器,而不是你在音频上下文中修改的接收器。

相反,你可能想要的是直接设置音频上下文的接收器。
有一个积极的建议,在AudioContext接口上添加一个setSinkId()方法,最新的Chrome Canary确实暴露了它。然而,它仍然是一个建议,AFAICT只有金丝雀揭露它。所以在不久的将来你只需要输入

audioCtx_ch1.setSinkId(audiooutput_speakersid).catch(handlePossibleError);

但是现在,你需要做一些体操,首先创建一个MediaStreamAudioDestinationNode,你将连接你的音频图形,将它的MediaStream设置为另一个<audio>元素的srcObject,你将在其上称为setSinkId()

udio_ch1.src = path;
// might be better to use createMediaStreamSource(audio_ch1.captureStream()) anyway here
source_ch1 = audioCtx_ch1.createMediaElementSource(audio_ch1);
source_ch1.connect(filter_ch1_lowpass);
filter_ch1_lowpass.connect(filter_ch1_highpass);
filter_ch1_highpass.connect(filter_ch1_lowshelf);
filter_ch1_lowshelf.connect(processor_ch1);
processor_ch1.connect(filter_ch1_lowshelf);
const outputNode = audioCtx_ch1.createMediaStreamDestination();
filter_ch1_lowshelf.connect(outputNode);
const outputElem = new Audio();
outputElem.srcObject = outputNode.stream;
outputElem.setSinkId(audiooutput_speakersid);
outputElem.play();

相关内容

  • 没有找到相关文章

最新更新