转载:android audio flinger

https://blog.csdn.net/innost/article/details/6142812函数

https://blog.csdn.net/zyuanyun/article/details/60890534oop

 

AndioFlinger 做为 Android 的音频系统引擎,重任之一是负责输入输出流设备的管理及音频流数据的处理传输,这是由回放线程(PlaybackThread 及其派生的子类)和录制线程(RecordThread)进行的,咱们简单看看回放线程和录制线程类关系:.net

 

 

ThreadBase:PlaybackThread 和 RecordThread 的基类
RecordThread:录制线程类,由 ThreadBase 派生
PlaybackThread:回放线程基类,同由 ThreadBase 派生
MixerThread:混音回放线程类,由 PlaybackThread 派生,负责处理标识为 AUDIO_OUTPUT_FLAG_PRIMARY、AUDIO_OUTPUT_FLAG_FAST、AUDIO_OUTPUT_FLAG_DEEP_BUFFER 的音频流,MixerThread 能够把多个音轨的数据混音后再输出
DirectOutputThread:直输回放线程类,由 PlaybackThread 派生,负责处理标识为 AUDIO_OUTPUT_FLAG_DIRECT 的音频流,这种音频流数据不须要软件混音,直接输出到音频设备便可
DuplicatingThread:复制回放线程类,由 MixerThread 派生,负责复制音频流数据到其余输出设备,使用场景如主声卡设备、蓝牙耳机设备、USB 声卡设备同时输出
OffloadThread:硬解回放线程类,由 DirectOutputThread 派生,负责处理标识为 AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD 的音频流,这种音频流未经软件解码的(通常是 MP三、AAC 等格式的数据),须要输出到硬件解码器,由硬件解码器解码成 PCM 数据
PlaybackThread 中有个极为重要的函数 threadLoop(),当 PlaybackThread 被强引用时,threadLoop() 会真正运行起来进入循环主体,处理音频流数据相关事务

线程

1.threadLoop() 循环的条件是 exitPending() 返回 false,若是想要 PlaybackThread 结束循环,则能够调用 requestExit() 来请求退出;
2.processConfigEvents_l() :处理配置事件;当有配置改变的事件发生时,须要调用 sendConfigEvent_l() 来通知 PlaybackThread,这样 PlaybackThread 才能及时处理配置事件;常见的配置事件是切换音频通路;
检查此时此刻是否符合 standby 条件,好比当前并无 ACTIVE 状态的 Track(mActiveTracks.size() = 0),那么调用 threadLoop_standby() 关闭音频硬件设备以节省能耗;
3.prepareTracks_l(): 准备音频流和混音器,该函数很是复杂,这里不详细分析了,仅列一下流程要点:
遍历 mActiveTracks,逐个处理 mActiveTracks 上的 Track,检查该 Track 是否为 ACTIVE 状态;
若是 Track 设置是 ACTIVE 状态,则再检查该 Track 的数据是否准备就绪了;
根据音频流的音量值、格式、声道数、音轨的采样率、硬件设备的采样率,配置好混音器参数;
若是 Track 的状态是 PAUSED 或 STOPPED,则把该 Track 添加到 tracksToRemove 向量中;
4.threadLoop_mix():读取全部置了 ACTIVE 状态的音频流数据,混音器开始处理这些数据;
5.threadLoop_write(): 把混音器处理后的数据写到输出流设备;
6.threadLoop_removeTracks(): 把 tracksToRemove 上的全部 Track 从 mActiveTracks 中移除出来;这样下一次循环时就不会处理这些 Track 了。
这里说说 PlaybackThread 与输出流设备的关系:PlaybackThread 实例与输出流设备是一一对应的,比方说 OffloadThread 只会将音频数据输出到 compress_offload 设备中,MixerThread(with FastMixer) 只会将音频数据输出到 low_latency 设备中。3d

从 Audio HAL 中,咱们一般看到以下 4 种输出流设备,分别对应着不一样的播放场景:blog

primary_out:主输出流设备,用于铃声类声音输出,对应着标识为 AUDIO_OUTPUT_FLAG_PRIMARY 的音频流和一个 MixerThread 回放线程实例
low_latency:低延迟输出流设备,用于按键音、游戏背景音等对时延要求高的声音输出,对应着标识为 AUDIO_OUTPUT_FLAG_FAST 的音频流和一个 MixerThread 回放线程实例
deep_buffer:音乐音轨输出流设备,用于音乐等对时延要求不高的声音输出,对应着标识为 AUDIO_OUTPUT_FLAG_DEEP_BUFFER 的音频流和一个 MixerThread 回放线程实例
compress_offload:硬解输出流设备,用于须要硬件解码的数据输出,对应着标识为 AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD 的音频流和一个 OffloadThread 回放线程实例
其中 primary_out 设备是必须声明支持的,并且系统启动时就已经打开 primary_out 设备并建立好对应的 MixerThread 实例。其余类型的输出流设备并不是必须声明支持的,主要是看硬件上有无这个能力。游戏

可能有人产生这样的疑问:既然 primary_out 设备一直保持打开,那么能耗岂不是很大?这里阐释一个概念:输出流设备属于逻辑设备,并非硬件设备。因此即便输出流设备一直保持打开,只要硬件设备不工做,那么就不会影响能耗。那么硬件设备何时才会打开呢?答案是 PlaybackThread 将音频数据写入到输出流设备时。事件

下图简单描述 AudioTrack、PlaybackThread、输出流设备三者的对应关系:
事务

 

咱们能够这么说:输出流设备决定了它对应的 PlaybackThread 是什么类型。怎么理解呢?意思是说:只有支持了该类型的输出流设备,那么该类型的 PlaybackThread 才有可能被建立。举个例子:只有硬件上具有硬件解码器,系统才创建 compress_offload 设备,而后播放 mp3 格式的音乐文件时,才会建立 OffloadThread 把数据输出到 compress_offload 设备上;反之,若是硬件上并不具有硬件解码器,系统则不该该创建 compress_offload 设备,那么播放 mp3 格式的音乐文件时,经过 MixerThread 把数据输出到其余输出流设备上。rem

那么有无可能出现这种状况:底层并不支持 compress_offload 设备,但恰恰有个标识为 AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD 的音频流送到 AudioFlinger 了呢?这是不可能的。系统启动时,会检查并保存输入输出流设备的支持信息;播放器在播放 mp3 文件时,首先看 compress_offload 设备是否支持了,若是支持,那么不进行软件解码,直接把数据标识为 AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;若是不支持,那么先进行软件解码,而后把解码好的数据标识为 AUDIO_OUTPUT_FLAG_DEEP_BUFFER,前提是 deep_buffer 设备是支持了的;若是 deep_buffer 设备也不支持,那么把数据标识为 AUDIO_OUTPUT_FLAG_PRIMARY。

系统启动时,就已经打开 primary_out、low_latency、deep_buffer 这三种输出流设备,并建立对应的 MixerThread 了;而此时 DirectOutputThread 与 OffloadThread 不会被建立,直到标识为 AUDIO_OUTPUT_FLAG_DIRECT/AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD 的音频流须要输出时,才开始建立 DirectOutputThread/OffloadThread 和打开 direct_out/compress_offload 设备。

 openOUtput:

 

new AudioTrack:

start:

write:

pause:

相关文章
相关标签/搜索