首页 > 解决方案 > 使用 Web Audio API webkitAudioContext() 在 Safari 中没有声音

问题描述

我正在尝试使用Web Audio API在我的应用程序中播放声音React

它目前正在除 Safari 之外的所有浏览器中播放声音v12.1

我知道 Safari 对自动播放有限制,并且需要用户交互才能播放声音,所以我有一个调用该_play()函数的播放按钮:

_play = (url, index) => {
    this._getData(url);
    this.source.start(index)
}

它正在调用如下_getData()所示的函数:

_getData(url) {
    this.source = this.audioContext.createBufferSource();
    var request = new XMLHttpRequest();

    request.open('GET', url, true);

    request.responseType = 'arraybuffer';


    request.onload = () => {
        var audioData = request.response;
        console.log(this.audioContext)
        this.audioContext.decodeAudioData(audioData, buffer => {
        this.source.buffer = buffer;
        this.source.connect(this.audioContext.destination);
    },

        function(e){ console.log("Error with decoding audio data" + e.err); });

    }

    request.send();
}

this.audioContext使用以下组件在组件中创建constructor

this.audioContext = new (window.AudioContext || window.webkitAudioContext)();

在按下播放之前,里面会输出这个console.log(this.audioContext)request.onload

控制台日志

...按下播放后:

控制台日志2

但没有声音播放(在 Safari 中)。

我究竟做错了什么?

标签: safariweb-audio-apiaudiocontextwebkitaudiocontext

解决方案


我认为您遇到的问题是,一旦您调用 start(),Safari 就不允许您再修改缓冲区。

例如,当您按下播放按钮时,以下页面会在 Safari 中播放一秒钟的噪音。

<!DOCTYPE html>
<html>
    <body>
        <button id="play-button">play</button>
        <script>

document
    .getElementById('play-button')
    .addEventListener('click', () => {
        const audioContext = new AudioContext();
        const audioBufferSourceNode = audioContext.createBufferSource();
        const sampleRate = audioContext.sampleRate;
        const audioBuffer = audioContext.createBuffer(1, sampleRate, sampleRate);
        const channelData = audioBuffer.getChannelData(0);

        for (let i = 0; i < sampleRate; i += 1) {
            channelData[i] = (Math.random() * 2) - 1;
        }

        audioBufferSourceNode.buffer = audioBuffer;

        audioBufferSourceNode.connect(audioContext.destination);
        audioBufferSourceNode.start(audioContext.currentTime);
    });

        </script>
    </body>
</html>

但是稍微修改一下就不行了。在分配缓冲区之前启动 audioBufferSourceNode 时,将不再有输出。

audioBufferSourceNode.connect(audioContext.destination); 
audioBufferSourceNode.start(audioContext.currentTime);

audioBufferSourceNode.buffer = audioBuffer;

我想您可以通过在启动源代码之前等待 HTTP 响应和音频解码来使您的代码正常工作。确保在执行this.source.buffer = buffer之前执行this.source.start(index)

我希望这有帮助。


推荐阅读