iOS Safari 按一下顺序播放声音

iOS Safari play sounds in sequence after one touch

我正在为 iOS 在 safari 上播放音频进行一些研发。我知道以编程方式播放音频存在局限性,因为它必须从用户启动的事件中完成。我想知道的是我们是否可以启动一个播放列表。我希望能够通过一个数组并在我从初始按钮开始后一个一个地播放声音。我的代码看起来像这样:

<button id="play-btn">Play sounds</button><br/>
    <input class="text-input" type="text" placeholder="text for a sound here" value="hello world"><br/>
    <input class="text-input" type="text" placeholder="text for a sound here" value="typing a sound"><br/>
    <input class="text-input" type="text" placeholder="text for a sound here" value="my name is kobby"><br/>
    <input class="text-input" type="text" placeholder="text for a sound here" value="whatup allisha"><br/>

我的 js 是这样的:

(函数(){

function createAudioFile(text){
    console.log('audio file create', this);
    var audioSrc = "http://vaas.acapela-group.com/Services/Streamer?req_voice=sharon22k&req_text="
        + text.split(' ').join('+') + "&cl_login=EVAL_VAAS&cl_app=EVAL_7285884&cl_pwd=h1j1endv";

    var audioFile = new Audio();
    audioFile.src = audioSrc;

    if(audioFile.canPlayType('audio/mp3')) console.log('can play mp3');
    if(audioFile.canPlayType('audio/ogg')) console.log('can play ogg');

    console.log(audioFile);

    return audioFile;
}

var btn = document.querySelector('#play-btn');
var inputs = Array.prototype.slice.call(document.querySelectorAll('.text-input'));

btn.addEventListener('click', function(){

    //keep this context obj through all new callbacks or function calls
    var ctx = this;
    console.log('initial click', this);

    var values = inputs.map(function(el, i){
        return el.value;
    });

    console.log(values);
    var currentAudioIndex = 0;
    function playAudio(){
        console.log('playing audio', this);
        var audioFile = createAudioFile.call(ctx,values[currentAudioIndex]);

        var events = ['loadstart', 'stalled', 'suspend', 'waiting', 'progress', 'error', 'abort'];
        for( var i = 0, len = events.length; i<len; i++ ){
            audioFile.addEventListener(events[i], function(evt){{
                console.log(events[i] + ' just fired');
            }}.bind(ctx));
        }

        audioFile.addEventListener('ended', function(){
            console.log('audio end',this);
            currentAudioIndex ++;
            audioFile = null;//for ram purposes
            if(currentAudioIndex < values.length) playAudio.call(ctx);

        }.bind(ctx), false);

        audioFile.load();
        audioFile.play();

    }

    playAudio.call(ctx);


}, false);

})();

这适用于 chrome,它播放我正在使用的 Vaas 帐户中的所有 4 种声音。但是它只在 iPad.

上播放第一个声音

有没有办法在执行递归函数的同时保留调用栈?我正在通过与开始相同的上下文,但这似乎还不够?对此的任何帮助都很棒!

谢谢 科比

此处最好的解决方案是使用 Web Audio API 而不是 Audio 对象。 Web Audio API 广泛可用,甚至可以在 iOS 6 中使用。这将允许您拥有一个常量 AudioContext,您可以在其上叠加声音,如果您愿意,甚至可以同时播放多个。

一个 "gotcha" 是 iOS Safari 实现了较旧的网络音频 API,因此它使用 AudioBufferSource.prototype.noteOn(ms)noteOff(ms) 而不是 start()stop(); polyfill 很简单。

如果您想继续使用您的 Audio 方法,请注意您将在这期间保持一秒钟的沉默。另外,我建议在同一个对象上重新分配 src 属性,而不是创建新的属性,以避免这样的问题。