zoukankan      html  css  js  c++  java
  • 记开发过的一款无线音箱解决方案

    从2017年开始国外智能音箱的热潮席卷到国内,各大小厂商都推出了智能音箱,主要有阿里的天猫精灵京东的叮咚和小米的小爱同学等。我也在去年双11入手了一款智能音箱(天猫精灵),体验下来总体感觉还是不错的,我相信这股热潮在今年(2018)会愈演愈热。有报道说美国的青年有了智能音箱后对手机的依赖度有所下降,即有些事情可以通过智能音箱解决了,这种现象在国内也会出现。智能音箱是在无线音箱的基础上加上人工智能(AI)发展起来的。几年前无线音箱也火过,推出了好多产品,有基于bluetooth的,也有基于WiFi的。基于bluetooth的是主流,基于WiFi的不多,但是现在智能音箱都是基于WiFi的。那时我还在芯片公司,我们team的语音解决方案已经做得很成熟,老板就让我们用自己公司的芯片做主芯片,开发一个基于WiFi的无线音箱解决方案。

    无线音箱先由手机去配置连到某个无线路由器上,手机也连到这个无线路由器上, 这样手机上的音乐播放器就可以把音乐在无线音箱上播放了。既可以把手机本机上的歌曲推送到音箱上播放,也可以把云端的歌曲推送到音箱上播放。支持的协议有DLNA和Airplay,主流的音乐播放器(QQ音乐/酷狗音乐/网易云音乐等)均支持,也支持苹果的音乐播放器(Airplay)。支持的音乐格式很多,有MP3/AAC/OGG/APE/WMA/ALAC/FLAC等,支持音乐双声道立体声播放,但是在一个音箱上效果不明显。如果有两个这样的音箱,又用上公司开发的相应的音乐播放APP,可以把左声道的数据推送到一个音箱上,右声道的数据推送到另一个音箱上,产生较强的立体声效果。

    无线音箱的软件实现是在openWrt上开发的,这样无线相关的软件全都好了,我们只要开发音频相关的软件。音频相关的绝大多数是基于开源的开发,协议的DLNA用的是sharepoint,AirPlay用的是gmediarender,音乐格式解析及解码等用的是FFMPEG,音频的播放用的是ALSA。Sharepoint和gmediarender基本上是拿来用,在接口上改了一点点,调用我们做好的API实现与我们自己软件的通信。FFMPEG主要是增加decoder,同时还要对decoder优化使其能流畅的运行。我们自己的软件就是搭一个框架(实现一个process)把这些开源实现给串起来,形成一个无线音箱音乐播放方案。解决方案的软件框图如下:

                                           

    我们实现的process叫mediaplay, 它与协议(DLNA/AirPlay)之间通过share memory通信,从而实现音乐的播放暂停停止等。Mediaplay会调用FFMPEG提供的API去解析音乐格式,并一帧一帧的解码得到PCM数据放进ring buffer中,然后用mutex block住mediaplay。Mediaplay向ALSA注册了回调函数,每隔一帧时长就会被调用一次,取走ring buffer中一帧PCM数据,并解锁mutex使mediaplay继续循环运行去解码下一帧。在一首歌开始解码时一般会缓存若干帧在ring buffer中然后才使能播放,这样做虽然增加了一两百毫秒的delay,但是保证了播放时的连续流畅性,不会出现噪声。再说音乐播放是非实时业务,一两百毫秒的delay对用户是不敏感的。

    我们team共4人。一人负责ALSA(包括driver和ALSA-Lib的调用),一人负责软件框架(即实现mediaplay process及里面的控制逻辑),一人负责DLNA/AirPlay协议的移植以及与mediaplay的通信,我负责FFMPEG、decoder优化以及把优化好的decoder lib集成到FFMPEG中,同时还负责后处理(主要是EQ)。用开源的好处是网上资料很多。我开始前先在网上搜怎么编译FFMPEG生成动态库,以及怎么使能一些decoder不使能一些decoder等。这些搞定后就调研我们需要的decoder(MP3/AAC/APE/OGG/WMA/FLAC/ALAC)FFMPEG是否都支持,哪些是定点实现的,哪些是浮点实现的(我们是在ARM上做软件方案,且CPU只有500兆,一定要用定点实现,浮点实现CPU load扛不住)。调研下来这些decoder FFMPEG都支持,但是AAC/OGG/WMA是浮点实现的。做了个小应用程序(代码中调用FFMPEG的API)在芯片上去播放这些格式的音乐,明显播放速度变慢了,这就需要去找这些decoder的定点实现来替换浮点实现。又到网上搜这些decoder定点实现中哪个应用最广泛(在网上快速搜到自己想要的东西也是一种能力,我就在那时候这方面的能力得到了提高,并且养成了要找开源首先去GitHub的习惯。给GitHub打广告了,哈哈)。

    对于AAC,搜下来定点方案中较好的是3GPP中AAC的参考实现。由于是3GPP的reference code,质量肯定没问题,就决定用它了。刚开始未优化时在我们芯片上跑下来load是2000多MCPS,后来一步步优化到不到200MCPS,可以在芯片上高枕无忧的运行了,也就没再继续优化,还要去忙其他的decoder呢。至于怎么优化的可以看我前面写过的一片文章(音频的编解码及其优化方法和经验),这里就不具体描述了,通常优化都是有套路的。优化好后就要把静态库集成到FFMPEG中,并且加相应的适配代码,使其能正常运行。那时(2013年)网上关于这方面的描述不多,我也是一边搜索一边尝试,最终把AAC的定点实现库成功集成到FFMPEG中了。这里也简单说一下怎么加decoder的库到FFMPEG 中,给有需要的做个参考。主要有以下几个步骤:

    1)把decoder调好,得到库文件和头文件

    2)修改FFMPEG的configure

    3)在allcodecs.c中加上REGISTER_DECODER(),注册这个decoder

    4)在libavcodec目录中加上这个decoder的适配文件(*.c),同时修改libavcodec下的makefile,使这个适配文件能编进去

    5)修改./configure 使这个decoder使能,同时告诉相应的库路径和头文件路径

    OGG格式的解码用的是Vorbis,其官网(www.xiph.org)上就有定点实现。本来load就不高,把他简单优化一下就可以用了,然后做成静态库集成到FFMPEG中。从找定点实现到集成到FFMPEG中用了不到一星期时间,可以说是非常顺利。WMA就没有这么顺利了,废了一番波折,主要是因为微软不提供定点实现。在网上花了一些时间搜索,某个国外论坛里有人说RockBox里有WMA的定点实现。把RockBox download下来在Ubuntu下生成一个带界面的应用程序,播放一个WMA格式的音乐,可以正常播放。接下来就是把WMA的定点实现从RockBox中剥离出来,它与其他代码耦合的比较深,剥离花了些时间,最终还是成功剥离了,又花了点时间简单优化下并做成库集成进FFMPEG中。这样三个decoder的优化及集成就搞定了。

    Decoder搞定后就开始做后处理,主要做均衡化(EQ),它是通过改变不同频段上的gain值从而产生不同的音效,有摇滚、经典、古典、爵士舞曲等10种模式。从信号处理的角度看,EQ就是一个两阶IIR滤波器。用户在手机APP上指定想要的模式后模式ID就会发到音箱上,软件就会根据ID得到相应的参数做EQ后处理。依旧在网上找定点实现,找到后先做一个应用程序验证效果。验证好后就开始把它用到我们的产品中并和其他模块联调。调试好后看到我们的无线音箱也支持音效特别有成就感。

    经过我们几个月的努力,无线音箱解决方案完成了,也陆续得到客户的认可,采用我们的方案。对我个人而言,从语音扩展到了音乐,音频的知识面更广了。

  • 相关阅读:
    string.Join()用法
    从List分组后重新组织数据
    Java学习笔记05--字符串
    Java学习笔记03--判断与循环语句
    Java学习笔记04--数组
    Java学习笔记02--运算符、表达式
    Java学习笔记01--数据类型
    Spring面试问答
    115个Java面试题和答案——终极列表(下)
    115个Java面试题和答案——终极列表(上)
  • 原文地址:https://www.cnblogs.com/talkaudiodev/p/8428434.html
Copyright © 2011-2022 走看看