Нет звука в сафари с использованием Web Audio API webkitAudioContext()

Я пытаюсь использовать 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 выводит это перед нажатием кнопки воспроизведения:

consolelog

... и это после нажатия кнопки воспроизведения:

consolelog2

Но звук не воспроизводится (в Safari).

Что я делаю не так?


person Dave    schedule 28.04.2019    source источник


Ответы (1)


Я думаю, что проблема, с которой вы столкнулись, заключается в том, что Safari больше не позволяет вам изменять буфер после вызова start().

На следующей странице, например, воспроизводится секундный шум в 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).

Надеюсь, это поможет.

person chrisguttandin    schedule 28.04.2019