目录

1.0 设备驱动

2.0  android hal层

3.0  选择设备的暗箱策略AudioPolicy

4.0  软件层面的混音,AudioFlinger

5.0 完整的对外接口 AudioSystem.cpp

6.0 换壳java形似的对外接口AudioSystem.java

7.0 java层的服务供应AudioService.java

8.0 应用层的一对一服务AudioManager

9.0 为了支持和兼容多音频设备的car, 提供的动态策略。

10.0 CarAudioService CarAudioManager

11.0 AudioTrack OpenslEs AAudio

Aaudiotrack:

opensl:

AAudio:

12.0 oboe 库


总览:个人对于Android 音频模块的整体理解,分析各个子模块存在的意义,领悟设计者架构思想,探讨未来可能的发展趋势。篇幅有限,码字不易,部分子模块的详细分析还为上blog
放一张自制图:

图中有一个小的拼写错误,为AlSA ,非ALSO。
全文涉及到 AudioFlinger  AudioPolicy  AudioSystem  AudioService  AudioManager
以及用于音频流数据传输的 AudioTrack  OpenSLes  AAudio。 部分子篇还为编写,先预留占坑。

1.0 设备驱动

linux 系统上一个应用要播放一个音频,原理是open一个音频播放设备的设备节点,然后往节点写入数据即可。设备节点由内核里面的驱动提供,往该设备节点写数据就是输入到了驱动中,对应音频设备的驱动,linux 提供的是名为ALSA 的框架,通常对音频来说都是pcm设备,所以里面的驱动也就是pcm设备驱动。属于字符设备,串行。(linux 设备类型:字符设备,块设备,网络设备)   由该pcm设备的驱动,处理获得的pcm数据给到硬件信号达到播放声音的目的。
        驱动要处理的问题:竞争,阻塞,可重入。
         pcm设备当然也是支持多个进程同时使用的,那么内核的pcm驱动就需要处理这个并发的情况   (内部也应该是作了混合音频的处理的,待后续补充详细)
        android 也有相应的工具,tinyalsa.  就是直接通过和linux 内核的alsa框架进行交互,可以不经过hal层。当然这个机制只是为了方便调试的,android并不打算把它给应用层使用,应用层的接口还需要经过android系统的层层包装和管理。
详细参考:
《  1.有待补充blog linux pcm设备驱动  》
《 
1. android tinyalsa 理解_王二の黄金时代的博客-CSDN博客

2.0  android hal层

既然是基于linux内核,硬件厂商完全可以实现自己的驱动,然后系统启动insmod加载进去,普通的应用程序即可通过驱动的设备节点,来open write/read iocontrol  完成对设备的操作。但是为了厂家并不乐意公开自己的驱动全部,于是安卓整了一套硬件抽象层 hal.( 关于hal,介绍的资料不少,不再赘述)
       一个普通的c++的层序,就已经可以直接调用hal层的接口,打开指定的设备,把pcm数据流写入进行播放了。
《2..1 android 直接使用hal库播放pcm demo》
但是设备众多,总不能都需要开发者自己选择具体的输出设备,于是android又为我们提供了一个自动确定具体设备的模块:AudioPolicy

3.0  选择设备的暗箱策略AudioPolicy

AudioPolicy   根据有限的固定的流类型,来确定最终的设备。之所以说它是暗箱操作,应为应用层不会参与也不清楚具体选择那个输出设备。很好地将应用开发者和设备制作者再进行了一次分离,通过这个相对不会有太多变化的流类型,让应用开发者不需要再往下关注不同android设备具体音频设备的组成。 而到底这个流类型的数据是输出给听筒,还是扬声器,还是一起都输出,这就需要设备制作者来暗箱操作了,这个就是AudioPolicyServe的用途。
详细参考:
《3. 待后续补充blog  AudioPolicy 选择设备策略的源码分析》

4.0  软件层面的混音,AudioFlinger

每一个应用都需要自己去调用hal驱动,这看起来是linux上面的开发模式,移动端的系统总是期望什么功能都有系统的一个统一管理,Android系统音频也就是这么干的,这就是AudioFlinger.   从linux的角度来看, android 系统只有一个进程在播放声音,就是AudioFlinger所在的进程。  
        关于AudioFlinger的角色,从其命名就可以直接看出来,Flinger的原本意思就是将多个汇合成一个的意思,同样命名的还有SurfaceFlinger,所以它的作用就是汇合所有的应用的音频输入,合成一个音频流再输入hal层。故而android应用想要播放生音,就需要通过跨进程的方式将自己的pcm数据传递给AudioFlinger,由AudioFlinger汇合,AudioFlinger顺便在汇合的时候可以根据需要做一个音效处理,然后输出给对应的hal层设备。
        当然,如果我们应用不想这么做,而是想直接自行通过hal层输出数据,也是可以的,只要你能访问到hal层接口,有足够的权限,那就不走AudioFlinger中间商,当然也就没办法享用到AudiFlinger提供的增值服务比如音效。
       要说明的是,输入给AudioFlinger的数据也不全是经过解码的pcm数据,有些特殊的设备它可以直接自己解码特殊格式的音频,这些音频数据就不能被AudioFlinger进行混合,AudioFlinger对这些数据就不会处理,直接交给对应的dsp设备,这算是特殊通道,这样的数据流类型被标记为offload  顾名思义就是包袱,打包的数据,一般用于dsp硬件解码的流数据
详细参考:
《4. 待补充blog AudioFlinger 混音及线程模型分析》
《4. Android native层直接使用AudioFlinger播放pcm》

5.0 完整的对外接口 AudioSystem.cpp

到此已经完全具备完整的音频能力了,如果是开发一个c++的程序,完全可以使用AudioPolicyServe 和AudioFlingerServer 的接口,从AudioPolicy获取到合适的输出设备,然后把pcm数据给到AudioFlinger让其帮忙播放。这个AudioSystem正是对内部AudioPolicyServe 和AudioFlingerServer的接口的一个外壳包装,让它门两个看起来成为一个整体,已经具备完整的音频能力,取名System也无可厚非。

6.0 换壳java形似的对外接口AudioSystem.java

为了给java使用,同样再换了个外壳,AudioSystem.java ,AudioSystem.java的作用就完全是为了通过java ->jni-> cpp了。没什么逻辑,只是个桥梁。

7.0 java层的服务供应AudioService.java

如何让应用层使用到AudioSystem.java? Android还是不想直接将AudioSystem的接口暴露给应用,毕竟还涉及到权限管理,音量的控制,焦点的控制等等,这些逻辑就都被放在了java sdk层统一处理,所以从java 层面来看,android 将音频相关的控制,都放在了 AudioService.java  可以说这是android 音频java 层的大本营, 由它来唯一和AudioSystem同底层控制交互。(也不完全是唯一和AudioSystem交互的模块,比如AudioManager在列举所有音频设备时,没有经过AudioService.java ,而是直接调用的AudioSystem.java. 但是总的设计上的思想,应该是都要经过AudioService的)
AudioService.java 源码有相关的注释:

The implementation of the audio service for volume, audio focus, device management...

详细参考《7. 待后续补充blog  AudioService 如何同AudioManager AudioSystem关联》

8.0 应用层的一对一服务AudioManager

为了更加方便应用层的使用,AudioService.java 服务为每一个应用派遣了一个一对一的接待AudioManager 。 每一个应用可以申请到一个只为自己服务的AudioManager对象。 但是AudioManager 的实际业务基本上是去跨进程调用AudioService服务, 应用获得AudioManager对象也是通过getSystemService(Context.AUDIO_SERVICE) 得到。

9.0 为了支持和兼容多音频设备的car, 提供的动态策略。

原来的android只是用于音频固件相对比较少的手机,一般只有 扬声器、听筒、有线耳机和蓝牙耳机,以及虚拟的用于无线投屏远程播放的 REMOTE_SUBMIX。 应用层只需要表明音频流的类型,由AudioPolicy来决定该流类型应该使用具体是扬声器设备还是听筒设备,这个AudioPolicy就提自定义策略的实现,由Android设备制作厂家来定制自己的策略,当然这个策略是在 底层AudioPolicy内部的。  对于音频输出设备比较多的car 而言,动不动就6个到10个的喇叭,光靠几个流类型显得不太够用,并且策略完全在底层的AudioPolicy ,修改也很不灵活,于是从 Android 9 开始,  对AudioPolicy进行了修改, 他定义了一个策略的接口 AudioMix ,可以由外部实现,然后注册进来覆盖原来的传统策略模式,这个外部策略甚至可以更加灵活,一直对外暴露到AudioSystem -> AudioService.java->AudioManager.java .  在java层这个策略的定义为AudioPolicy.java 。
        这样连应用层都可以使用AudioManager.java来定义注册自己的AudioPolicy,这就是动态音频策略。当没有app来注册动态策略的时候,系统默认就使用传统的内置在AudioPolicy的策略。当有应用向系统注册了音频策略的时候,就优先使用注册的动态外部策略。当然并不是所有的应用都能随意注册,需要SystemApi级别, 需要android.Manifest.permission.MODIFY_AUDIO_ROUTING权限。
        于是对于传统的手机,可以默认使用原来的策略,对于汽车,只需要外挂一个系统级别的app,即源码中的 packages/services/Car  然后在里面实现自己的AudioPolicy ,用AudioManager.registerAudioPolicy注入即可。
详细参考《 9. 待后续补充blog  android 动态音频策略的原理》

10.0 CarAudioService CarAudioManager

        这就是对于car 设备,外挂的系统级别app, 在应用层 java 实现了定制的音频策略,比如多音区.
       安卓中很多这种manager+service的结构,类似于AudioManager+AudioService的结构,就像我们在8.0 AudioManager中提到的那样, manager是给应用层一对一专门服务的接待对象,而manager内部实现则是经过统一的跨进程到service中去完成功能。
  详细参考:《10. 待后续补充 blog  android CarAudio》

11.0 AudioTrack OpenslEs AAudio

以上全部在讨论关于设备的选择策略,音量的控制等等,对于应用如何把pcm数据流交给系统,就需要看AudioTrack了。

Aaudiotrack:

Track原本的意思,是轨迹,轨道,这个名词在安卓系统中有多处使用。 在AudioFlinger中, 每一路音频输入,都是一个 track.    这个就是AudioFlinger 内部创建的track, 为了让外部应用层可以访问到,于是专门抽象出一个类AudioTrack.cpp (为了方便区分是java还是c++ 故意在对象后面加上后缀名), 专门负责和AudioFlinger内部的track进行流数据的拷贝交互。 AudioTrack.cpp 负责直接和AudioFlinger进行流数据的交互, 它不负责具体使用那个音频设备。  它被暴露给应用层,也就是java层的AudioTrack.java  , app 可以用AudioTrack来输出一个音频流到AudioFlinger. 然后AudioFlinger将其输送到具体的音频输出设备。
native层为了配合媒体播放,利用AudioTrack.cpp 的接口编写了一个TrackPlayer,让他符合plaer播放器的特性。 
《11. Android native层使用TrackPlayer播放pcm》

opensl:

同时为了支持opensl 这套公共api标准, 又基于TrackPlayer  实现了Wilhelm project这个工程,所以android 上使用 opensl 实际上就是通过native层的AudioTrack 来和AudioFlinger交互数据流。  至于opensles 相对于AudioTrack.java的性能提升,其实就是少了一层从java 到 native的拷贝延时,两者最后都会通过AudioTrack.cpp -> AudioFlinger -> hal

AAudio:

其实就是Android Audio的缩写,android 在java层提供了AudioTrack.java 这个api,但是在native层却没有相应的独立API, 而对 opensles 的支持只是为了适应一套通用规范的接口,并不能提供一些android 自己特性的音频接口,于是在Android O(8.0版本,API-26 ) 版本中引入的全新 Android C API , 取名AAudio (Android Audio)  其中还支持 mmap通路,内存映射的方式直接通到内核层,以减少拷贝,降低延迟。
详细参考:
        《11. Android native层使用TrackPlayer播放pcm_》
        《11. 有待补充 blog android opensl 源码原理分析》
        《11. 有待补充 blog android AAudio分析》

12.0 oboe 库

为了简化调用流程,自动选择是使用 opensl 还是AAudio (毕竟在低于8.0的设备上是没有AAudio的支持的),谷歌整合了一个c++ 库,叫做oboe, 目前是以第三方库的方式提供,应用层可以嵌入使用,相比于opensl 确实调用起来简洁多了。

官方源码 https://github.com/google/oboe

Oboe audio library | Android Developers (google.cn)

读源码不容易! 码字更是费时费力!  原创!!!发扬共享精神!

<一>Android Audio音频框架相关推荐

  1. Android Audio音频通路(七)

    android audio 生产者与消费者 简介 全面接触生产者/消费者问题是在操作系统原理中,并发性原理讨论的问题 生产者/消费者问题.最近的工作偏向音频,接着上一篇文章,用生产者,消费者模型来理解 ...

  2. Android Audio 音频输出设备切换

    扬声器输出和耳机输出是音频系统最基本的音频输出通路,实际应用中用户可根据自己需要随意切换,具体表现是通过插入耳机选择耳机输出,拔出耳机选择默认的扬声器输出. 如图5-13所示,扬声器与耳机输出切换的实 ...

  3. Android Audio 音频路由

    一.在 AudioPolicyService 中,选择音频路由时会从当前音频流的类型获取音频的路由策略: /frameworks/av/services/audiopolicy/managerdefa ...

  4. 【Android】Audio音频输出通道切换 - 蓝牙bluetooth、外放

    参考: [Android]Audio音频输出通道切换 - 蓝牙.外放 Android Audio 音频输出通道切换 为什么 iOS 或 Android 设备连接蓝牙设备后不能通过蓝牙设备接电话? xq ...

  5. Android Audio - 支持多个APK同时录音

    Android Audio - 支持多个APK同时录音 原理说明 Android4.4 修改方法 Android5.1 & 6.0 修改方法 Android8.1 修改方法 Android9. ...

  6. Android Audio - 支持多应用同时录音_Android8.1修改方法

    支持多应用同时录音_Android8.1修改方法 修改方法 与之相关 修改方法 源码路径: sdk\frameworks\av\services\audiopolicy\managerdefault\ ...

  7. Android audio音频流数据异常问题分析

    一.背景 在 Android 系统的开发过程当中,音频异常问题通常有如下几类,无声,调节不了声音,爆音,声音卡顿,声音效果异常(忽大忽小,低音缺失等)等.尤其声音效果这部分问题通常从日志上信息量较少, ...

  8. Android音频框架笔记 - 下篇

    原址 六.HAL层 6-1.Audio HAL层,其实包括了audio.xxx.so 和 audiopolicy.so等.从前述的总框架图,也有写,代码库路径也有写. 具体运行时so对象图,对于aud ...

  9. Android音频框架笔记 - 上篇

    原址 一.音频数字化基础知识 见书,列出知识点如下: 声音 声波,声音频率.响度, 音调.音色. 音响设备中的声道 得翻翻初高中的课本了. 声音数字化过程 声源 -> mic -> ADC ...

最新文章

  1. 20165235实验四 Android程序设计
  2. iOS打包framework - Swift完整项目打包Framework,嵌入OC项目使用
  3. OneNote2016安装代码高亮插件-NoteHightlight
  4. [codevs 3273] 两圆的交
  5. PADS 非常用操作 备忘
  6. python 对象转dict_如何将python dict对象转换为java等效对象?
  7. win7域内桌面黑屏
  8. 德国软件巨头SAP旗下风投基金募集10亿美元 专门投资科技初创公司
  9. Linux内核多线程(二)
  10. idm下载器怎么下载网页视频?如何用idm自动下载网站文件?
  11. visual C#(二十五)实现UWP应用的用户界面
  12. 从WinMain函数看Windows程序内部运行机制
  13. word中如何将空格变成换行
  14. Windows 10 build Error !include: could not find: ****StdUtils.nsh
  15. EasyCVR出现只有HLS协议可播放,其他协议均无法播放是什么原因?
  16. SFTP命令常用操作
  17. matlab土方计算,土方量计算的MATLAB工具箱研制
  18. 【PPP概念股龙头】PPP再迎风口 相关概念股表现格外抢眼(2)
  19. 计算机基础与office应用考试专题,一级考试计算机基础及WPS Office应用模拟题
  20. 投资理念研究分析报告

热门文章

  1. Mutual Supervision for Dense Object Detection(ICCV2021)阅读笔记
  2. 如何添加Google统计在自己的网站
  3. python数据分析 - T检验与F检验:二组数据那个更好?(一)
  4. 看到的有意思的文章(一)
  5. C语言输出各种类型数据的方式
  6. 春节期间,怎样晒朋友圈才安全?
  7. 人工智能机器人技术概述
  8. 概览:可视化前端测试
  9. 会汇编语言学c语言好学吗,只有C语言功底的我学习汇编语言可以吗?
  10. c语言和java哪个好学_学java前要学C语言吗?java和C语言哪个好学?