那些年,我们一起被坑的H5音频

时间:2023-12-30 22:01:26

原文地址:http://weibo.com/p/23041874d6cedd0102vkbr

不要被这么文艺的标题吓到,这里不会跟你讲述中学时期泡妞史,也不会有其它什么现实不该有而小说噼里啪啦不能没有的坑爹情节,请注意,这是一篇技术类文章,主要讲的是:音频在移动端的兼容问题,至于为什么标题要起的这么文艺,这只是为了迎合下这条微博而已:

那些年,我们一起被坑的H5音频

神马?你还没关注我新浪微博 - 桑尼真?果断走起吧,我不会晒自拍刷屏不会买面膜,有的只是吐槽跟技术类的分享,欢迎关注…

好了,前面按惯例废话了不少,下面我们来说下,音频在移动端的那些坑,坑的具体表现与填坑方式…

我私自把 音频分两种,背景音乐与音效音乐;

一、背景音乐

背景音乐,就是贯穿整个页面的音乐,一般挑选节奏与曲风页面表达主题搭配,比如旅行类的页面,我可能会挑选《TravelingLight》这样的轻快节奏的,清新乡村一点,让用户听了,感觉就真的要放下包袱去旅行的感觉;而游戏类体验类的页面,可能会挑选《TheTime HasCome》这样快节奏,rap&rock系的,感觉就是在游戏里面打击的那种节奏感;而对于那种少女系萌萌哒的页面,可能会挑选《Downby the sallygarden》这种轻淡旋律,符合思春少女的心境的风格…不过背景音乐类型一般以轻音乐类型为主,作为衬托主题辅助作用,节奏太重不宜长听…

选曲风格大概就如上面所述,在页面播放背景音乐的话,一般就是进入页面,背景音乐自动响起,音量由小到大渐入,到收尾的时候,音量由大到小渐出,然后再循环这样的过程,那把上面的过程用HTML5代码转化的话,就是这样代码流程的:

首先new audio,创建一个audio音频对象,赋值音频src地址,设置loop循环,检测它的readystatey音频当前就绪状态,等于4 HAVE_ENOUGH_DATA的时候,表示可用数据足以开始播放,或者监听canplaythrough事件/canplay事件,canplaythrough表示歌曲已经载入完全完成,而canplay表示缓冲至目前可播放状态,前者是完全加载好了才播,后者是加载到当前网络状态能播就播,不一定完全加载,边播边载,可能会快一点,不过如果播一部分后网速变慢,或者断网,音乐可能就会卡顿…当加载完成后,就play播放音频,大概就是这样的流程,具体代码:

function musicPlay(){
       var audio =document_createElement_x_x("audio");
       audio.src ="media/thunder.mp3";
       audio.loop =true;
      audio.load();
      audio.addEventListener("canplaythrough", function(){
         audio.play();
      },false);
}
   
musicPlay();

测试地址: Demo
二维码:

那些年,我们一起被坑的H5音频

上面代码看起来正常,网上找的代码也是这样的,在电脑上面播也是ok的,然后当你欢心喜地在手机上面播的时候,TNND,坑爹啊…有砸手机的冲动…就上面的流程,会发现在IOS手机上面压根就没声音好吗!玩笑不能这样开的好吗!这是想闹哪样(PS:安卓4.1以上都是可以的)…用无线网卡+fiddler抓包调试,手机配代理后,居然可以正常播放,相当奇葩…

IOS手机请扫下面二维码:

那些年,我们一起被坑的H5音频

是否听到了阵阵打雷声?与之前的代码比较,其实将 audio添加到html页面节点而已,然后IOS就能正常识别了,这个安卓相对而言要好些…

对于背景音乐播放的,我上面提到,可以做一个“音量由小到大渐入,到收尾的时候,音量由大到小渐出”这样的效果,这样不会让用户一进页面,就马上最大音量轰炸,有多少人开会或者在图书馆被这样的突入起来的背景音乐吓到,麻烦举下手,诚实点我们还可以做朋友的…

音量的话,audio也有相应的控制属性volume,设置范围为0-1,0的时候为静音,也有一个专有静音属性muted与之对应,1的时候是音频原有音量,然后我在PC上,就写了这样一个定时器:

audio.volume=0.01;
timer_volume_up=setInterval(function(){
         if(audio.volume<0.15){
            audio.volume+=0.01;
          }
          else{
            audio.volume=0.15;
            clearInterval(timer_volume_up);
          }
},1000);

刚播放的时候,声音音量为0.01,然后1s加0.01,直到0.15的时候,就停止,清除计数器,做一个声音渐入的效果,调节时长15s;

timer_count=setTimeout(function(){
            timer_volume_down=setInterval(function(){
               if(audio.volume>0.01){
                  audio.volume-=0.01;
                }
                else{
                  audio.volume=0.01;
                  clearInterval(timer_volume_down);
                }
              
            },1000);
},parseInt(audio.duration*1000-15000));

音频的时长可以用duration是音频长度,单位为秒,获取audio.duration乘以1000,化作毫秒,减去15000,就是音频离结束前15秒,检测音频音量是不是大于0.01,如果是,就1s减0.01,直到0.01为止,15秒,刚好音频结束,做为淡出

演示地址:Demo
二维码:

那些年,我们一起被坑的H5音频

PC上面听起来是不是很正,首次打开的时候,因为音量很低,所以不会给用户突入起来的感觉,如果用户所在场合不适合有声音,可以有足够的时间将手机设置为静音,然后继续浏览页面;而且音乐循环起来没那么硬,感觉就被无缝连接一样,很舒适的就循环起来了,有木有…

然后用IOS扫二维码,瞬间崩溃,又来坑爹了…
在IOS手机上面就算直接设置了volume 0.01,他还是最大音量 1,这里的话,是苹果的设定,具体可以见《Safari HTML5 Audio and Video Guide》一文:

On iOS devices, the audio level is always under the user's physicalcontrol. The volume property is not settable in JavaScript. Readingthe volume property always returns 1.

意思就是说,屌丝程序猿你吖别瞎操心,老子这里只能最大声…
对于安卓,没有什么详细的资料说不支持,不过我拿安卓4.4测试,好像也是无效…
如果想在手机上实现跟PC一样的效果,目前别太指望代码,老老实实调整音频源文件吧…

那对于背景音乐,单放一首,会不会太单调啦?那就来个多音频顺序播放呗,可以这样,监听单曲的onended事件,然后当音频ended播放完毕后,就play播放下一首,我们来看下实例:

演示地址: Demo
二维码:

那些年,我们一起被坑的H5音频

PC上正常,会听到两声雷声的音频,然后就哔哔哔的车笛声,循环播放;
在IOS上,也可以正常播放,但是安卓4.4它获取不到onended事件,不支持,所以雷声过后,就没有哔哔哔…
这里可以用setInterval计算好每个音频的时间,手动循环播放,不过这样时间点会由于loading时加载延迟,对的不准,可能播一半就又重新播了…

对于背景音乐自动播放问题,就IOS而言,在微信里面,页面加载后调用play是可以正常播放音乐的,但是在同个手机safari上,它是不能自动播放的,因为IOS系统为了防止网页浪费用户流量,需要用户在该页面进行操作(比如划屏,点击)后,,才能播放音频,视频同理,所以在safari打开后,一切都是那么安静…这里解决方法,可以做一个音频按钮,引导用户选择需不需要背景音乐,然后就有了用户操作,人性化的伪装,啊哈哈…

背景音乐的问题,目前我碰到的基本都罗列出来了,那么我们进入下一个话题:音效音乐

二、音效音乐

音效音乐,就是在页面中,点击按钮的啪嗒声,物品掉落的嘎达声,成龙头发特技的duangduang声,这些用于辅助页面,让动态交互效果更加真实,贴近实际的音频;一般为点击触发型,播放次数为一次,再次点击,再触发,与用户动作配合,比如你在玩一个捡金币的游戏,点一个金币,就叮 的一声,那点两个金币,就 叮叮 两声,那点一万个金币,就……你以为我会打一万个 叮 充字数么,我像是那种靠打叮叮叮叮叮叮叮叮叮叮叮叮叮叮叮叮叮叮叮叮叮叮叮叮叮叮叮叮 的人么…我很正直的好吧…

至于音效音频,它也是一个音频,跟背景音频一样的用audio,所以,跟上面背景音频同样的问题我就不累赘了,我们来看一个致命的问题:

演示地址:Demo
二维码:

那些年,我们一起被坑的H5音频

背景音乐是个很欢快的音频,页面加载后自动播放,页面中间两个按钮,点击beep按钮,播放一个车笛声的音频,点击thunder按钮,播放一个雷声的音频,在IOS上,是可以正常播放的;
在安卓…当点击beep按钮时,背景音乐被强制中止,车笛声音频播放正常,车笛声播放完毕后,背景音乐不会继续播放;
当点击thunder按钮,播放途中点击beep按钮,雷声同样被中断;
由此可见,安卓下,同时只能播放一个audio音频,不支持多个audio音频同时播放,所以,安卓下要背景音乐还是音效,就要权衡取舍了…

当页面存在多个页面,页面之间切换后,音频当前时间没有重置,导致来回切换,音频与动作没有匹配,具体效果如:

演示地址:Demo
二维码:

那些年,我们一起被坑的H5音频

页面左右切换,背景音乐会切换与之对应,切换的时候,会出现沙沙沙的翻页声,但是再来回切换,会发现音频没有重置,会继续上次播放的位置继续播放,这里其实只需要在页面切换的时候,把音频pause暂停,然后currentTime当前时间帧,设置为0,就可以让音频下次播放的时候,从头播放…具体效果按下Reset CurrentTime 按钮后,就可以体验了…

那现在只是添加了1个音效,如果添加多10个音效呢?会出现什么问题?没错啦,http请求数量增加,跟图片一样,请求时间也会相应的增加,如果你觉得10个音频没什么,那如果50个呢…iP6直接就停在loading页面,进不去…好吧,说到loading,当页面文件增加,体积到达到一定程度,loading页面就肯定要加的,下面提供个loading的代码:

演示地址:Demo
二维码:

那些年,我们一起被坑的H5音频

页面加载10张图片,4个音频,资源加载完毕后,页面上‘loading...’字样,被替换为“PageStart”,表示页面加载完成…

喂喂喂,怎么突然转移话题,刚说到http请求数量增加,怎么就变成加载资源判断了?
那说回减少http请求这个上面,图片的话,我们知道,可以通过csssprite,也就是图片合并,来适当减少图片请求,那音频能不能也做个合并呢?当然是可以的,就网上下载个音频编辑器,把它们合成一段再下载咯…啊哈哈…其实真的有这个代码可以使用JSFIDDLE,通过将小音频合并,然后记录关键点,需要哪段音频,就获取对应的关键点,以及音频长度,赋值对应的currentTime播放时间,然后播放,由于加载问题,可能会有0.几秒的误差,所以音频在合并的时候,需要留适当的空白,以免音频错位,读到下一个音频去,就好像sprite图与图之间,也需要有相应的间隙一样…不过一旦合并,后面修改起来,就比较麻烦了,因为只要中间一个音频加长,后面的音频都必须做相应挪动(剪短可以不用,哈哈),可维护性偏低,建议在最后项目发布时使用(如果有时间的话,哈哈)…

音频参考的话,可以看下这文章,感觉不错:《Making HTML5 audio actually work onmobile》;

以上就是我近一个礼拜做音频项目所遇到的坑坑洼洼,罗列一下,需要的同学们可以看下作为参考,避免以后在同样的坑上浪费时间,期待各系统各浏览器的兼容完善,有音频的页面总体会上了一个档次的说(虽然页面加载速度被拖后腿了,哈哈)…然后,不管你PC上面的demo多牛逼,音频音效切合的多么好,都要老老实实用真机过一遍,IOS7/8(为什么没有IOS6??因为IOS6压根就不支持audio标签,哈哈,详见这里)、安卓4.1-4.4,真机没问题,才是真的没问题…最后感谢 黄坤,基神,岱霖提供的相关资料(下次做完项目记得写总结啊混蛋们,遇到坑也写啊混蛋们,不要让队友走自己走过的坑啊混蛋们)…