audioContext.suspend() 没有按预期停止音乐

audioContext.suspend() not stopping music as expected

我正在尝试让一些生成音乐理想地暂停,但我愿意停止使用 Wen Audio Javascript API。我遇到的问题是 audioContext.suspend() 似乎什么也没做。所有文档和示例都表明以下内容可行,但我无法解决问题。但是,我是 javascript 的新手,所以怀疑我在做一些愚蠢的事情。

所有控制台日志都证明该函数在第二次单击时触发。我也试过停止,但也没有用。我正在使用 Chrome 来测试我的作品,已经在 Safari 上试过了,但它甚至无法播放曲目。

// for cross browser
const AudioContext = window.AudioContext || window.webkitAudioContext;
const audioContext = new AudioContext();

function startLoop(audioBuffer, pan=0, rate=1) {
    let sourceNode = audioContext.createBufferSource();
    let pannerNode = audioContext.createStereoPanner();

    sourceNode.buffer = audioBuffer;
    sourceNode.loop = true;
    sourceNode.loopStart = 11.35;
    sourceNode.loopEnd = 12.1;
    sourceNode.playbackRate.value = rate;
    sourceNode.connect(audioContext.destination);

    pannerNode.pan.value = pan;

    sourceNode.connect(pannerNode);
    pannerNode.connect(audioContext.destination);

    sourceNode.start(0, 0);
}

function playAudio() {
console.log("playAudio")
fetch('Ambition.mp3')
  .then(response => response.arrayBuffer())
  .then(arrayBuffer => audioContext.decodeAudioData(arrayBuffer))
  .then(audioBuffer => {
    startLoop(audioBuffer,-1);
    startLoop(audioBuffer,1,1.002);
  })
  .catch(e => console.error(e));
}

var playing = "False"

function playOrStop() {
console.log("Playing is set to " + playing)
if (playing === "False") 
    {
    console.log("Play");
    playAudio();
    playing="True";
     }
else {
console.log("Suspend");

// 这是不起作用的函数

audioContext.suspend().then(function() {
      playing="Suspend";
      console.log("Suspend happened")
        })
     }
}

var b1=document.getElementById("playButton1");
b1.onclick = playOrStop;

第二次单击按钮 - 'Suspend happened' 显示在日志中,但音频没有暂停。 第一次点击按预期工作。

我执行了您的代码(使用不同的 MP3),它在 Firefox 和 Chrome 中按预期工作。我按下按钮,等待声音开始。几秒钟后我再次按下按钮,声音停止了。

但我觉得你运行在Chrome中进入了微妙的bug/feature。当在 Chrome 中实施自动播放政策时,它旨在尽可能向后兼容。这就是为什么在 AudioScheduledSourceNode 上调用 start() 也可以恢复挂起的上下文。

如果您按下按钮两次并且第一个承诺尚未解决,那么您的代码会在调用 sourceNode.start() 之前调用 audioContext.suspend()。即使对 suspend() 的调用有效,在 AudioScheduledSourceNode 上对 start() 的任何后续调用都会将上下文的状态设置回 运行.

Firefox 对此的处理方式不同,大家一致认为 Firefox 在这种情况下是正确的。规范已更改以反映 (https://github.com/WebAudio/web-audio-api/pull/1823) and it will most likely get fixed in a future version of Chrome. But it can of course never hurt to file a bug. https://new.crbug.com

如果您想阻止 sourceNode 恢复 AudioContext,您可以在调用 start().

之前检查上下文的 state
if (audioContext.state === 'running') {
    sourceNode.start(0, 0);
}

您的示例在 Safari 中不起作用,因为它不支持 StereoPannerNode。我建议使用 standardized-audio-context (https://github.com/chrisguttandin/standardized-audio-context) 以获得更好的跨浏览器兼容性,因为我是该库的作者。 :-) 它还附带了一个在 Safari 中工作的 StereoPannerNode 实现。