WebAudio panner 无法与 WebRTC 音频流一起正常工作

WebAudio panner not working properly with WebRTC audio stream

我有一个问题,我的音频声像器没有正确地用给定的值声像。

目前,如果我将 positionX.value 设置为 1000,音频会像在中间播放一样播放,根本不会平移到右声道。

现在,如果我将 positionX.value 设置为 0.5 或 0.9 或 1,音频将在右声道播放,(尽管不是完全正确,因为我仍然可以听到左边的声音,比平常多) .

我不明白为什么它只能在 -1 到 1 之间工作,任何高于该数字的音频都会回到中心。 知道为什么吗?而且我确信它应该适用于更高的数字,因为我之前在不同的情况下测试过它并且没有说它不应该出现在文档中。

peerConnection.onaddstream = (event) => {
    var panner = this.aContext.createPanner();
    panner.panningModel = 'HRTF';
    panner.distanceModel = 'inverse';
    panner.refDistance = 1;
    panner.maxDistance = 10000;
    panner.rolloffFactor = 1;
    panner.coneInnerAngle = 360;
    panner.coneOuterAngle = 0;
    panner.coneOuterGain = 0;
    
    // here is how Im setting the position, using -1 to 1 works, nothing greater tho
    panner.positionX.value = 10000;

    var source = this.aContext.createMediaStreamSource(event.stream);

    source.connect(panner);
    panner.connect(this.aContext.destination);

    const recvAudio = new Audio();
    recvAudio.srcObject = source.mediaStream;
    recvAudio.autoplay = true;
}

您需要设置监听器的位置!它的位置决定了源节点的平移。

默认情况下,listners 的位置是 (0,0,0),这就是为什么当您将源节点设置为低值时可以将其放置在这里的原因。

您可以设置侦听器的位置:

var const listener = this.aContext.listener;
listener.setPosition(x,y,z);

您的 recvAudio 音频元素直接传播原始 MediaStream,没有 PannerNode 影响它。

    var source = this.aContext.createMediaStreamSource(event.stream);
///...
    recvAudio.srcObject = source.mediaStream;

在此代码段中,source.mediaStreamevent.stream 完全相同。

document.querySelector("button").onclick = (evt) => {
  const context = new AudioContext();
  // let's create an audio MediaStream from the AudioContext
  // in StackSnippets we can't use gUM...
  const event_stream = context.createMediaStreamDestination().stream;
  
  const source = context.createMediaStreamSource( event_stream );
  console.log( "Same Object:", source.mediaStream === event_stream );
  
  context.close();
}
<button>test</button>

因此,当您超出参考距离 [-1 ~ 1] 时,您的 AudioContext 的输出声音将低于此 Audio 元素的输出声音,并且您会有 PannerNode 不再工作的印象,因为 Audio 元素的输出覆盖了它。

要解决这个问题,最好的办法可能是根本不在这里使用音频元素,你真的不需要它,因为你可以让 AudioContext 自己输出声音。

但是,如果您确实需要使用音频元素,则不要将 AudioPanner 节点连接到上下文的目标,而是将其连接到 MediaStreamDestinationNode 并将后者作为音频元素的 srcObject 传递:

//...
    panner.positionX.value = 10000;

    const source = this.aContext.createMediaStreamSource(event.stream);
    const destination = this.aContext.createMediaStreamDestination();
    source.connect(panner);
    panner.connect(destination);

    const recvAudio = new Audio();
    recvAudio.srcObject = destination.stream;
    recvAudio.autoplay = true;
//...

https://jsfiddle.net/do9xq681/