在移动Safari中预加载HTML5音频

7
我遇到了一个问题,无法预加载HTML5音频内容并使用缓存中的内容,而不是每次尝试重新下载音频。

http://cs.sandbox.millennialmedia.com/~tkirchner/rich/K/kungFuPanda2_tj/

体验应该是这样的:当有人点击横幅时,它会弹出一个带有加载栏的广告。加载栏正在加载动画所需的所有图像。同时,音频也通过DOM中已经存在的音频标签进行加载(这很好)。在所有图像加载完成后,加载栏消失,用户可以继续操作。屏幕底部有4个按钮,用户可以单击其中一个播放音频文件,并且图像以翻书式动画同步播放。
音频标签:
<audio id="mmviperTrack" src='tigress.mp3'></audio>
<audio id="mmmantisTrack" src='viper.mp3'></audio>
<audio id="mmtigressTrack" src='kungfu3.mp3'></audio>
<audio id="mmcraneTrack" src='crane.wav'></audio>

播放按钮事件监听器:

button.addEventListener('click',function(){
    if ( f.playing ) return false;
    f.playing = true;
    button.audio.play();
},false);

button.audio.addEventListener('playing', function(){
    animate();
}, false);

问题是,在JavaScript中,每次我点击play(),它都会重新加载音频文件,然后播放它。我似乎无法让它在开始时仅加载一次音频并从存储在内存中的内容进行操作,而不是每次单击按钮时尝试重新加载音频。

我尝试过尝试preload和autobuffer属性,但是似乎移动Safari忽略了这些属性,因为无论我将它们设置为什么,行为始终相同。我尝试过尝试源标签和不同的文件格式......没有任何想法?


1
HTTP缓存头,也许?一个must-revalidate或过期时间在过去? - Boldewyn
我能否仅在我的音频和图像资源中使用JavaScript设置它?此广告将在其他人的网站上运行。 - TJ Kirchner
1
IBM有一篇很棒的文章,解释了iOs对音频处理的限制,链接在这里:http://www.ibm.com/developerworks/library/wa-ioshtml5/。基本上我理解的是,iOs一次只能有一个音频通道。当你改变音频时,它会从内存中丢失其他音频,因此切换会导致重新加载。你的解决方案是只使用一个音轨,以避免这种限制。 - mummybot
很酷!谢谢你分享。这很有道理。 - TJ Kirchner
1个回答

4
好的,所以这个解决方案有点像是一个hack、作弊、变通,无论你想怎么称呼它。我注意到,如果我点击刚刚播放过的音频文件上的播放按钮,它不会重新加载。可能是因为在它播放完之后我暂停了音频,但我不能100%确定。无论如何,我将所有4个音频文件合并成一个大的音频文件(耶Audacity~!)。然后,每次我点击其中一个播放按钮时,我都会将音频对象的currentTime属性设置为该轨道的起始点,然后播放该轨道直到达到其结束点,然后再次暂停它。任务完成!只在开始时加载一次,每次播放都不需要再次加载。
对于我不得不合并所有不同的音频轨道的想法并不疯狂,但是它有效。
哦,还有。为了让音频轨道加载并触发“canplaythrough”事件,我将此函数附加到用户单击事件:
var track;
function addHTMLAudio() {
    track = document.createElement('audio');
    track.id = 'mm_audio'
    track.autoplay = false;
    track.preload = false;
    track.addEventListener('canplaythrough',function(){
        track.removeEventListener('canplaythrough');
        audioLoaded = true;
    },false);       
    document.getElementById('body').appendChild(track);
    track.src = f.trackURL;
    track.play();
    setTimeout(function(){ track.pause();  },1);
}

playButton.addEventListener('click',function(e){
    if ( playStatus > 0 ) return;
    playStatus = 1;

    var myId = e.target.parentNode.id;
    var myClip = findClip( myId );

    myClip.state = 'active';        
    track.currentTime = myClip.tIndex.start;

    track.play();
    runAnimation(myClip);       
},false);

这还能用吗?或者最后一个已知的 iOS 版本是什么? - polarblau
我在iOS 4.2上实现了这个解决方案。我相信它也适用于4.3。 - TJ Kirchner
如果您能看一下这个问题并发表评论,我将非常感激:https://dev59.com/b1zUa4cB1Zd3GeqP3n2q — 谢谢! - polarblau
我很乐意。抱歉回复慢了,我没有收到这条评论的通知。 - TJ Kirchner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接