Audio在移动端的实践

好久没写blog了,有三点原因,一是懒,二是懒,三是懒。

因为最近项目里面有个需求,要在移动端用web的Audio实现音频播放。本想说臣妾做不到啊~然而,还是开始挖坑了。在这里记录下各种坑死人的问题。

准备

先看兼容性(下图),可以看到在移动端上用是完全可行的(理论上):

compatibility.png

我们再分别看看audio提供的属性,方法和事件

属性

params.png

方法

way.png

事件

event.png

具体的可以戳这里

实践

其实按照上面的方法,随便怎么写怎么玩都可以,但主要有以下几个问题要解决的:

1.预加载的问题;
2.加载进度条问题;
3.多个音频文件切换问题;
4.其他的兼容性问题。

1.预加载的问题

我们先来看预加载的流程(如下),先用load去加载音频,当音频可以播放就会触发canplay事件,表示加载已经完成,可以播放,完美。

patten1.png

但是,理想和现实总是有区别的,在表现不一的手机上就有问题了。

问题一:load方法调用了没效果,根本没有加载音频,要调用play方法才开始加载。

问题二:在三星note3 和锤子T1手机上,有50%的几率预加载失败。如果预加载失败,要切换好几次播放/暂停状态才开始加载播放,或者一直没反应。

问题三:一般触发load加载音频文件后,音频文件缓冲好会触发canplay事件的。

在安卓下,触发canplay事件,会有下面问题:

  • 360浏览器audio.seekablefalse;
  • uc浏览器,魅族自带浏览器,微信audio.buffered.length居然为0;

在iOS下,有以下问题:

  • canplay事件触发后,微信的audio.seekablefalse
  • safariload了之后,canplay事件不触发,点击play后才触发 (9.1版本是正常的);

看到这里是不是觉得坑大了,想逃?不要急,接着看。

解决方法

上面问题总的来说有俩个,一个是加载进度,另外一个就是播放Bug了。这里主要说下问题二的解决方法。

调用load事件后,对加载进度进行检测,如果直到canplay触发,加载进度一直为0,就判断为预加载失败。然后在点击播放的,设置进度audio.currentTime = 1;,这样就会再次触发加载。这里还有个问题,如果是用zeptotap监听点击播放事件,可以再次加载,但一直不播放,要监听touchend这些事件才行(这个问题纠结N久)。
这样调整后,在三星note 3 和锤子T1这些有问题的手机上基本没什么问题了。

2.加载进度条问题

加载进度,浏览器提供了progress事件,但这个事件会有一些小问题,所以采用setInterval的去实行。正常来说在canplay的时候显示进度条:

onCanplay: function () {
    this.seekable = this.audio.seekable && this.audio.seekable.length > 0;

    if ( this.seekable ) {
        this.timer = setInterval(this.onProgress.bind(this), 500);
    }

    var name = this.list[this.index].name || '',
        time = this.list[this.index].time || '';

    this.trigger('canplay', time, name, this.list[this.index]);
},

onProgress: function () {
    if ( this.audio && this.audio.buffered !== null && this.audio.buffered.length ) {
        this.duration = this.audio.duration === Infinity ? null : this.audio.duration;
        this.load_percent = ((this.audio.buffered.end(this.audio.buffered.length - 1) / this.duration) * 100).toFixed(4);
        if (isNaN(this.load_percent)) {
            this.load_percent = 0;
        }

        if ( this.load_percent >= 100 ) {
            this.clearLoadProgress();
        }

        this.trigger('progress', this.load_percent);
    }
},

// 对于play触发后才开始加载
play: function () {
    if (!this.seekable) {
        this.timer = setInterval(this.onProgress.bind(this), 500);
    }
    this.audio.play();
},

上面代码的逻辑主要是检测audio的buffered,因为不同浏览器对buffered的解析不同,如果跳跃播放,有的会产生多段buffered,所以获取最新的缓存要这样:this.audio.buffered.end(this.audio.buffered.length - 1)

3.多音频切换问题

在播放列表里,有多个音频文件,点击可以切换。正常的做法是,用tap绑定点击事件,事件内部这样处理:

audio.pause();
audio.setAttribute('src', url);
audio.play();

在PC的chrome上是很正常的,完美。但是,在手机上就嗝屁了。问题为:偶发性的出现,切换音频后,直接触发音频的ended事件,然后再怎么切换播放/点击都是无效的了。
这个问题的解决方法很简单,就是在canplay触发的时候再触发play就好,不要切换了音频url马上play

_t.audioHandler.on('canplay', function (totalTime, name) {
    _t.audioHandler.play();
});

因为没有预加载的过程,每次都是点击列表的音频才播放,所以这样理论上是可行的。但是如果点击了播放,触发了加载,马上就点暂停,这时候canplay还没触发,会不会有问题?

4.其他的兼容性问题

  • 关于音频的总时间,理论来说,正常加载的情况,在canplay的时候是可以读取到的,但因为上面一堆load问题,所以音频总时间要手动设置。
  • tab去绑定播放事件好像会有奇葩的问题,用touch系列又太灵敏了,都接受不了可以用fastclick

暂时还没发生其他问题,下面就看看例子吧。例子分两个,一个是单音频预加载播放,另外一个是多音频列表播放(UI直接用项目的了)。

例子1:单音频预加载播放

audio1.gif

例子2:多音频切换播放

audio2.gif

上面俩个例子的代码在这里

最后

实践都这里就算完了。不过这里有个更好玩的东西,有兴趣可以看看,非常酷炫。

在开发的过程中,针对移动端,参考了Audio5js,整理出了个audio的库。代码在这里,有兴趣可以关注下。

参考:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,326评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,228评论 1 304
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,979评论 0 252
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,489评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,894评论 3 294
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,900评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,075评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,803评论 0 205
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,565评论 1 249
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,778评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,255评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,582评论 3 261
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,254评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,151评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,952评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,035评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,839评论 2 277

推荐阅读更多精彩内容