【问题标题】:Web Audio API source.start() only plays the second time it is called (in safari)Web Audio API source.start() 仅在第二次调用时播放(在 safari 中)
【发布时间】:2021-08-11 19:03:51
【问题描述】:

我正在学习如何使用 Web Audio API,但我遇到了一个不知道如何解决的问题。我不确定是因为我是这方面的初学者,还是发生了一些我不明白的事情。

基本上,我正在创建一个播放短 mp3 的函数。第一次播放音频时,它应该 http GET 将 MP3 加载到音频缓冲区中。 (后续对相同音频的请求不需要重新获取 mp3)

以下代码在 Chrome 中完全正常工作。但是在 Safari 中,playAudio('filename') 在第一次被调用时不会播放音频。之后的每一次都可以正常工作。任何比我更有经验的人的专家建议将不胜感激。

<script>
var context;

function init() {
    try {
        window.AudioContext = window.AudioContext || window.webkitAudioContext;
        context = new AudioContext();
    }
    catch(e) {
        alert("Your browser doesn't support Web Audio API");
    }
}
window.addEventListener('load', init);    

function loadAudio(w) {
    var audioURL='https://biblicaltext.com/audio/' + w + '.mp3';
    var request = new XMLHttpRequest();
    request.open("GET", audioURL, true);
    request.responseType = 'arraybuffer';
    request.onload = function() {
        //console.log("update", request.readyState, request.status)
        if (request.readyState === 4) {
            if (request.status === 200) {
                //take the audio from http request and decode it in an audio buffer
                context.decodeAudioData(request.response, function(buffer) {
                    if(buffer) {
                        console.log(w, buffer);
                        playAudioBuffer(w, buffer);
                    } else {
                        console.log("audio buffer decoding failed")
                    }
                }, function(ec) {
                    console.log("http request buffer decoding failed")
                });
            } else {
                console.log("get", audioURL, "failed", request.status)
            }
        }
    }
    request.send();
}

var audioBuffer;
var currentWord;

function playAudio(w) {
    if (typeof audioBuffer === 'undefined' || audioBuffer == null || currentWord != w) {
        audioBuffer = null
        currentWord = ""
        console.log("reqest load of different word", w)
        loadAudio(w)
    } else {
        playAudioBuffer(w, audioBuffer)
    }
}

function playAudioBuffer(w, buffer) {
    audioBuffer = buffer
    currentWord = w
    var source = context.createBufferSource();
    source.buffer = audioBuffer;
    source.connect(context.destination);
    source.start();
    console.log('playing', currentWord);
}

</script>


<a href="javascript:playAudio('ἦν')">Play ἦν</a>
<br>
<a href="javascript:playAudio('ὥστε')">Play ὥστε</a>
<br>
<a href="javascript:playAudio('οὐρανός')">Play οὐρανός</a>
<br>
<a href="javascript:playAudio('υἱός')">Play υἱός</a>
<br>
<a href="javascript:playAudio('εἷς')">Play εἷς</a>
<br>

我是否遇到了某种奇怪的情况,即 Safari 阻止声音,因为点击链接与音频的加载/播放断开了几分之一秒?

【问题讨论】:

    标签: javascript safari web-audio-api


    【解决方案1】:

    事实证明,“解锁”音频的方法是在用户首次与页面交互时播放静音/隐藏声音,以确保未来的音频请求能够正常运行。

    https://paulbakaus.com/tutorials/html5/web-audio-on-ios/

    这是我使用的:

    window.addEventListener('touchstart', function() {
    
        // create empty buffer
        var buffer = myContext.createBuffer(1, 1, 22050);
        var source = myContext.createBufferSource();
        source.buffer = buffer;
    
        // connect to output (your speakers)
        source.connect(myContext.destination);
    
        // play the file
        source.noteOn(0);
    
    }, false);
    

    我意识到我可能不是第一个在 SO 上提出这个问题的人,但是搜索关键字(safari play first vs second time)在 SO 上没有出现任何问题,所以我倾向于回答并留下这个。如果社区删除我的菜鸟问题会更好,那么我很乐意这样做。

    【讨论】:

    • 默认情况下,如果在用户发起的事件期间未创建音频上下文,则音频上下文以挂起状态开始。您可以通过在touchstart 事件中调用myContext.resume() 来简化您的代码。您也可以考虑使用click 事件而不是touchstart,这样它也可以在桌面上运行。
    猜你喜欢
    • 1970-01-01
    • 2013-10-05
    • 2023-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多