Android音频系统
1 分析思路
Thread如何创建?
AudioPolicyService是策略的制定者,AudioFlinger是策略的执行者,
所以: AudioPolicyService根据配置文件使唤AudioFlinger来创建ThreadThread对应output, output对应哪些设备节点?
AudioTrack和Track的创建过程: AudioTrack对应哪一个Thread, 对应哪一个output?
AudioTrack如何传输数据给Thread?
AudioTrack如何播放、暂停、关闭?
2 以例子说明几个重要概念
stream type, strategy, device, output, profile, module : policy
out flag : 比如对于某个专业APP, 它只从HDMI播放声音, 这时就可以指定out flag为AUDIO_OUTPUT_FLAG_DIRECT,这会导致最终的声音无需混音即直接输出到对应的device
Android系统里使用hardware module来访问硬件, 比如声卡
声卡上有喇叭、耳机等等,称为device
为了便于管理, 把一个设备上具有相同参数的一组device称为output,
一个module能支持哪些output,一个output能支持哪些device,使用配置文件/system/etc/audio_policy.conf
来描述
app要播放声音, 要指定声音类型: stream type有那么多的类型, 来来来, 先看它属于哪一类(策略): strategy
根据strategy确定要用什么设备播放: device, 喇叭、耳机还是蓝牙?
根据device确定output, 进而知道对应的playbackthread,
把声音数据传给这个thread
一个stream如何最终选择到一个device,这些stream如何互相影响(一个高优先级的声音会使得其他声音静音),等等等, 统称为policy (政策)
输出、输入设备:
https://blog.csdn.net/zzqhost/article/details/7711935
3 所涉及文件形象讲解
系统服务APP:
frameworks/av/media/mediaserver/main_mediaserver.cpp
AudioFlinger :
AudioFlinger.cpp
(frameworks/av/services/audioflinger/AudioFlinger.cpp
)
Threads.cpp (frameworks/av/services/audioflinger/Threads.cpp
)
Tracks.cpp (frameworks/av/services/audioflinger/Tracks.cpp
)
audio_hw_hal.cpp (hardware/libhardware_legacy/audio/Audio_hw_hal.cpp
)
AudioHardware.cpp (device/friendly-arm/common/libaudio/AudioHardware.cpp
)
AudioPolicyService:
AudioPolicyService.cpp (frameworks/av/services/audiopolicy/AudioPolicyService.cpp
)
AudioPolicyClientImpl.cpp (frameworks/av/services/audiopolicy/AudioPolicyClientImpl.cpp
)
AudioPolicyInterfaceImpl.cpp(frameworks/av/services/audiopolicy/AudioPolicyInterfaceImpl.cpp
)
AudioPolicyManager.cpp (device/friendly-arm/common/libaudio/AudioPolicyManager.cpp
)
AudioPolicyManager.h (device/friendly-arm/common/libaudio/AudioPolicyManager.h
)
AudioPolicyManagerBase.cpp (hardware/libhardware_legacy/audio/AudioPolicyManagerBase.cpp
)
堪误: 上面3个文件被以下文件替代
AudioPolicyManager.cpp (frameworks/av/services/audiopolicy/AudioPolicyManager.cpp
)
应用程序APP所用文件:
AudioTrack.java (frameworks/base/media/java/android/media/AudioTrack.java
)
android_media_AudioTrack.cpp (frameworks/base/core/jni/android_media_AudioTrack.cpp
)
AudioTrack.cpp (frameworks/av/media/libmedia/AudioTrack.cpp
)
AudioSystem.cpp (frameworks/av/media/libmedia/AudioSystem.cpp
)
4 AudioPolicyService启动过程分析
比如一部典型的手机,它既有听筒、耳机接口,还有蓝牙设备。假设默认情况下播放音乐是通过听筒喇叭输出的,那么当用户插入耳机时,这个策略就会改变——从耳机输出,而不再是听筒;又比如在机器插着耳机时,播放音乐不应该从喇叭输出,但是当有来电铃声时,就需要同时从喇叭和耳机输出音频。这些“音频策略”的制定,主导者就是AudioPolicyService
在AudioFlinger小节,我们反复强调它只是策略的执行者,而AudioPolicyService则是策略的制定者。这种分离方式有效地降低了整个系统的藕合性,而且为各个模块独立扩展功能提供了保障。
- 加载解析
/vendor/etc/audio_policy.conf
或/system/etc/audio_policy.conf
- 对于配置文件里的每一个module项, new HwModule(name), 放入mHwModules数组;
- 对于module里的每一个output, new IOProfile,放入module的mOutputProfiles
- 对于module里的每一个input, new IOProfile, 放入module的mInputProfiles
- 根据module的name加载厂家提供的so文件(通过AudioFlinger来加载)
- 打开对应的output(通过AudioFlinger来open output)
为了让大家对AudioPolicyService有个感性的认识,我们以下图来形象地表示它与AudioTrack及AudioFlinger间的关系:
5 AudioFlinger启动过程分析
- 注册AudioFlinger服务
- 被AudioPolicyService调用以打开厂家提供的so文件
- 加载哪个so文件? 文件名是什么? 文件名从何而来?
名字从/system/etc/audio_policy.conf得到 : primary
所以so文件就是 :audio.primary.XXX.so
, eg.audio.primary.tiny4412.so
- 该so文件由什么源文件组成? 查看
Android.mk
- 加载哪个so文件? 文件名是什么? 文件名从何而来?
audio.primary.$(TARGET_DEVICE) : device/friendly-arm/common/libaudio/AudioHardware.cpp
libhardware_legacy
libhardware_legacy : hardware/libhardware_legacy/audio/audio_hw_hal.cpp
- 对硬件的封装:
AudioFlinger : AudioHwDevice (放入mAudioHwDevs数组中)
audio_hw_hal.cpp : audio_hw_device
厂家 : AudioHardware (派生自: AudioHardwareInterface)
AudioHwDevice是对audio_hw_device的封装,audio_hw_device中函数的实现要通过AudioHardware类对象
6 AudioTrack创建过程概述
- 体验测试程序:
frameworks/base/media/tests/audiotests/shared_mem_test.cpp
frameworks/base/media/tests/mediaframeworktest/src/com/android/mediaframeworktest/functional/audio/MediaAudioTrackTest.java
播放声音时都要创建AudioTrack对象,java的AudioTrack对象创建时会导致c++的AudioTrack对象被创建;
所以分析的核心是c++的AudioTrack类,创建AudioTrack时涉及一个重要函数: set()函数
猜测创建过程的主要工作
- 使用AudioTrack的属性, 根据AudioPolicy找到对应的output、playbackThread
- 在playbackThread中创建对应的track
- APP的AudioTrack 和 playbackThread的mTracks中的track之间建立共享内存
源码时序图
7 AudioTrack创建过程_Track和共享内存
回顾:
- APP创建AudioTrack AudioFlinger中PlaybackThread创建对应的Track
b. APP给AudioTrack提供音频数据有2种方式: 一次性提供(MODE_STATIC)、边播放边提供(MODE_STREAM)
问:
- 音频数据存在buffer中, 这个buffer由谁提供? APP 还是 PlaybackThread ?
- APP提供数据, PlaybackThread消耗数据, 如何同步?
8 音频数据的传递
- APP创建AudioTrack, playbackThread创建对应的Track
它们之间通过共享内存传递音频数据 - APP有2种使用共享内存的方式:
- MODE_STATIC:
APP创建共享内存, APP一次性填充数据 - MODE_STREAM:
APP使用obtainBuffer获得空白内存, 填充数据后使用releaseBuffer释放内存
- MODE_STATIC:
- playbackThread使用obtainBuffer获得含有数据的内存, 使用数据后使用releaseBuffer释放内存
- AudioTrack中含有mProxy, 它被用来管理共享内存, 里面含有obtainBuffer, releaseBuffer函数。Track中含有mServerProxy, 它被用来管理共享内存, 里面含有obtainBuffer, releaseBuffer函数。对于不同的MODE, 这些Proxy指向不同的对象
- 对于MODE_STREAM, APP和playbackThread使用环型缓冲区的方式传递数据
9 PlaybackThread处理流程
prepareTracks_l :
确定enabled track, disabled track
对于enabled track, 设置mState.tracks[x]中的参数threadLoop_mix : 处理数据(比如重采样)、混音
确定hook:
逐个分析mState.tracks[x]的数据, 根据它的格式确定tracks[x].hook
再确定总的mState.hook调用hook:
调用总的mState.hook即可, 它会再去调用每一个mState.tracks[x].hook混音后的数据会放在mState.outputTemp临时BUFFER中
然后转换格式后存入 thread.mMixerBuffermemcpy_by_audio_format :
把数据从thread.mMixerBuffer或thread.mEffectBuffer复制到thread.mSinkBufferthreadLoop_write:
把thread.mSinkBuffer写到声卡上threadLoop_exit
Android音频系统的更多相关文章
- Android音频系统之音频框架
1.1 音频框架 转载请注明,From LXS, http://blog.csdn.net/uiop78uiop78/article/details/8796492 Android的音频系统在很长一段 ...
- Android音频系统之AudioFlinger(一)
1.1 AudioFlinger 在上面的框架图中,我们可以看到AudioFlinger(下面简称AF)是整个音频系统的核心与难点.作为Android系统中的音频中枢,它同时也是一个系统服务,启到承上 ...
- Android音频系统之AudioPolicyService
地址:http://blog.csdn.net/edmond999/article/details/18599327 1.1 AudioPolicy Service 在AudioFlinger小节,我 ...
- 转:ANDROID音频系统散记之四:4.0音频系统HAL初探
昨天(2011-11-15)发布了Android4.0的源码,今天download下来,开始挺进4.0时代.简单看了一下,发现音频系统方面与2.3的有较多地方不同,下面逐一描述. 一.代码模块位置 1 ...
- Android音频系统之AudioFlinger(二)
1.1.1 音频设备的管理 虽然AudioFlinger实体已经成功创建并初始化,但到目前为止它还是一块静态的内存空间,没有涉及到具体的工作. 从职能分布上来讲,AudioPolicyService是 ...
- Android音频系统之AudioFlinger(四)
http://blog.csdn.net/xuesen_lin/article/details/8805096 1.1.1 AudioMixer 每一个MixerThread都有一个唯一对应的Audi ...
- Android音频系统之AudioFlinger(三)
http://blog.csdn.net/xuesen_lin/article/details/8805091 1.1.1 PlaybackThread的循环主体 当一个PlaybackThread进 ...
- Android 音频系统得框架
http://www.mamicode.com/info-detail-1790053.html http://blog.csdn.net/lushengchu_luis/article/detail ...
- Android的系统架构
转自Android的系统架构 从上图中可以看出,Android系统架构为四层结构,从上层到下层分别是应用程序层.应用程序框架层.系统运行库层以及Linux内核层,分别介绍如下: 1)应用程序层 ...
随机推荐
- sudo的使用和配置
1 sudo是什么 Sudo是Unix/Linux平台上的一个非常有用的工具,它允许系统管理员分配给普通用户一些合理的“权利”,让他们执行一些只有超级用户或其他特许用户才能完成的任务,比如:运行一些像 ...
- 1.Magicodes.NET框架之路——起航
1.Magicodes.NET框架之路--起航 前言 从事开发也好几年了,并且最近一直在做架构搭建的工作.这些时间,最大的感悟就是: 只有自己理解了的才是自己的. 对架构这块,若欲立之,必先破之. 故 ...
- HTML语法介绍
一 基本标签(块级标签和内联标签) <hn>: n的取值范围是1~6; 从大到小. 用来表示标题. <p>: 段落标签. 包裹的内容被换行.并且也上下内容之间有一行空白. &l ...
- shiro源码篇 - shiro的filter,你值得拥有
前言 开心一刻 已经报废了一年多的电脑,今天特么突然开机了,吓老子一跳,只见电脑管家缓缓地出来了,本次开机一共用时一年零六个月,打败了全国0%的电脑,电脑管家已经对您的电脑失去信心,然后它把自己卸载了 ...
- Mysql加锁过程详解(1)-基本知识
Mysql加锁过程详解(1)-基本知识 Mysql加锁过程详解(2)-关于mysql 幻读理解 Mysql加锁过程详解(3)-关于mysql 幻读理解 Mysql加锁过程详解(4)-select fo ...
- Pandas数据去重和对重复数据分类、求和,得到未重复和重复(求和后)的数据
人的理想志向往往和他的能力成正比. —— 约翰逊 其实整个需求呢,就是题目.2018-08-16 需求的结构图: 涉及的包有:pandas.numpy 1.导入包: import pandas as ...
- ES6 使用数据类型Set求交集、并集、差集
前言 ES6新增了数据类型Set,它是一种类似数组的数据结构.但它和数组的不同之处在于它的成员都是唯一的,也就是说可以用来去除数组重复成员. Set本身是一个构造函数用来生成Set数据结构. cons ...
- [转]php模拟post提交请求,调用接口
本文转自:https://www.cnblogs.com/jiqing9006/p/3949190.html /** * 模拟post进行url请求 * @param string $url * @p ...
- Tomcat日志设定
1 Tomcat 日志概述 Tomcat 日志信息分 为 两 类 : 一.是运行中的日志,它主要 记录 运行的一些信息,尤其是一些异常 错误 日志信息 .二.是 访问 日志信息,它 记录 的 访 ...
- Docker镜像目录无法删除
docker pull下来的镜像目录默认放在:C:\ProgramData\docker\windowsfilter.由于拉下来的镜像已经几乎占满了C盘的空间,准备删除所有的镜像,却发现删除不掉. 搜 ...