移动端音频直播

前言:

直播现在很火,公司有个在线教育的项目里面也用到了直播,做在线课程,业务需求所以我们只需要开发音频直播,之前的一篇文章介绍了夸pc平台推流端的实现。

但是在移动端网页播放会有个问题,rtmp协议在网页上播放需要flash支持,但是现在的手机很少有装flash的,ios设备更是没有。所以不能采用rtmp协议来播放直播。

我们公司推流的服务用了阿里云的,对于ios移动设备,苹果官方也提倡了一种hls的协议来做直播,html5支持。阿里云也提供了相关的转码服务了。一切都很正常。
但是了解hls协议后,就明白了hls会产生“切片时长*切片个数”的延时时长。

阿里云直播使用hls协议产生的延时时长

前文说到延时时长是: 切片时长*切片个数,关于在阿里云使用hls协议直播的测试结果来看,阿里云hls的最大切片时长是6秒,通常会产生一个5点零几秒的切片。
而切片数通常是4,换句话说在这样的情况下使用hls协议直播就会产生 4 * 5.0x 大于20秒的延时。当然播放器也能优化,就是直接播后面的切片 这样最低最低的延时就可以控制到2-3个切片内了,但是依旧会有延时。

业务冲突

我们的业务需求,音频要跟课件内容直播同步,课件内容是websocket走的,内容少传输量小,所以基本是实时。这样就很不好控制同步。所以就想办法降低音频直播的延时。

利用http+flv做直播

阿里云也提供了相关转码的服务,默认情况下其实也许要flash来播的,但是网上有个开源的项目flv.js 可以利用html5相关的api实现flv直播无需flash插件的播放。
但是移动设备的浏览器少了一个相关的api导致播放不了。对flv格式思来想去于是有了个想法,把flv中audio tag取出来,再把audio tag的data body取出来里面其实就是上一篇文章里

我对音频数据进行的mp3编码的数据。然后再用mp3解码得到pcm数据,然后用html5的Audio API来播放。

http+flv

简单的说明一下http+flv格式:

header_tag(9个字节)+tag_end(4字节)+media_tag+tag_end(4字节)+media_tag+tag_end(4字节).........

media_tag有好些类型我们通常用到其中两种audio video,当然我的业务需求只用一种,相关属性是用media_tag的前11个字节解析出来的,这11个字节第一个就是表示类型,8是audio 9是video, 紧接着的三个字节是标识media_tag除去11个字节的header剩下的body data的长度的,这样就可以知道media_tag的长度了。紧跟着3个字节是时间相对时间戳,毫秒单位。
紧跟的字节是时间戳的拓展,三个字节不够用了就拓展成4个字节。 mp3 audio tag中body_data的解析,对于mp3frame的解析,第一个字节表示mp3的声道数以及采样率的类型的,所以body_data去除第一个字节剩下的就是一系列的mp3frame了。

相关依赖

1. javascript 进行mp3解码

这个主要是依赖github上的mp3.js这个开源工程,不过里面有些许不兼容,因为它主要针对完整的mp3文件解码的,但是直播这个环境下,我们传输的是mp3的fame而且每个flv的audio tag里的每一mp3 frame还不一定完整的(会在后面的audio tag里)所以解码会有问题,不过好在了解这些bug,自然就多尝试一下改改,于是就可以用来解码了。改进了以后重新整合一下,只用其中工程需要的。这样mp3解码的问题就解决了

2. 流文件的处理

这个主要是用了fetch API,可以对http+flv的流进行处理,每次获取一定量的字节数组,于是解析出audio tag里的mp3 frame然后交给解码器处理。

3. 播放

mp3解码后得到的数据是左右声道的数据数组,AudioContext可以通过createBuffer()创建AudioBuffer的一个实例并设置声道数据数组,AudioContext通过createBufferSource()
创建AudioBufferSourceNode的实例用于AudioBuffer的播放。

后记

Audio API也有用于相关mp3解码的,性能会比mp3.js解码好些,就是得控制好frame的完整性,不然就会出现断音的情况。但是是原生的api所以有些异常不能检查出来。网络流操作以及audio tag的解析可以在一个worker里做,当然解码也可以。IOS设备开始播放时需要有touch行为来触发,可以先播一段重复的空audio等到有音频了再播具体的了,这样就不会出现音频播不了的情况,以为用回调来触发音频的播放在ios里是不行的。

最后说一下延时,基本在5秒内,有的时候可以是1-2秒的延时


阅读量: