1、Android 音频系统1. 系统架构Android 的音频系统拥有一个比较标准和健全的架构,从上层应用,java framework 服务 AudioMananger,本地服务 AudioFlinger,抽象层 AlsaHAL,本地库,再调用external 的 tinyalsa 外部支持库,最后到底层驱动的 codec。Java 服务 AudioManager 作为服务端,本地服务 AudioFlinger 作为客户端,两者通过Binder 机制交互。AudioFlinger 对硬件功能的具体实现交给硬件抽象层 AlsaHAL 完成。抽象层可以调用本地标准接口,或者直接调用 Tinyals
2、a 库去操作底层驱动。详细调用过程如下图:简单说来,轨迹如下:Java 端发起调用,MediaPlayer 会转至 MediaPlayerService,然后会调用相应的解码工具解码后创建 AudioTrack,所有待输出的 AudioTrack 在 AudioFlinger:AudioMixer 里合成,然后通过 AudioHAL(AudioHardwareInterface 的实际实现者) 传至实际的硬件来实现播放。2. AudioFlinger AudioFlinger 是 android 中的一个 service,在 android 启动时就已经被加载。AudioFlinger 向下访
3、问 AudioHardware,实现输出音频数据,控制音频参数。同时,AudioFlinger 向上通过 IAudioFinger 接口提供服务。所以,AudioFlinger 在 Android 的音频系统框架中起着承上启下的作用,地位相当重要。AudioFlinger 的类结构下面的图示描述了 AudioFlinger 类的内部结构和关系: IAudioFlinger 接口这是 AudioFlinger 向外提供服务的接口,例如openOutput,openInput,createTrack,openRecord 等等,应用程序或者其他 service 通过 ServiceManager
4、可以获得该接口。该接口通过继承 BnAudioFlinger 得到。 ThreadBase在 AudioFlinger 中,Android 为每一个放音/ 录音设备均创建一个处理线程,负责音频数据的 I/O 和合成,ThreadBase 是这些线程的基类,所有的播放和录音线程都派生自 ThreadBase TrackBase应用程序每创建一个音轨(AudioTrack/AudioRecord) ,在 AudioFlinger 中都会创建一个对应的 Track 实例,TrackBase 就是这些 Track 的基类,他的派生类有:PlaybackTread:Track / 用于普通播放,对应于应
5、用层的 AudioTrack PlaybackThread:OutputTrack / 用于多重设备输出,当蓝牙播放开启时使用 RecordThread:RecordTrack / 用于录音,对应于应用层的 AudioRecord 播放默认的播放线程是 MixerThread,它由 AudioPolicyManager 创建,最终会进入AudioFlinger 的 openOut 函数。3. AudioTrack 和 AudioFlinger 的通信机制通常,AudioTrack 和 AudioFlinger 并不在同一个进程中,它们通过 android 中的 binder机制建立联系。Aud
6、ioTrack 主要是用来播放声音的,AudioTrack 贯穿了 JAVA 层,JNI 层和 Native 层。下面这张图展示了他们两个的关系:我们可以这样理解这张图的含义:audio_track_cblk_t 实现了一个环形 FIFO; AudioTrack 是 FIFO 的数据生产者; AudioFlinger 是 FIFO 的数据消费者。 1) 建立联系的过程下面的序列图展示了 AudioTrack 和 AudioFlinger 建立联系的过程:2) FIFO 的管理audio_track_cblk_taudio_track_cblk_t 这个结构是 FIFO 实现的关键,该结构是在
7、createTrack 的时候,由AudioFlinger 申请相应的内存,然后通过 IMemory 接口返回 AudioTrack 的,这样AudioTrack 和 AudioFlinger 管理着同一个 audio_track_cblk_t,通过它实现了环形FIFO, AudioTrack 向 FIFO 中写入音频数据,AudioFlinger 从 FIFO 中读取音频数据,经 Mixer 后送给 AudioHardware 进行播放。 audio_track_cblk_t 的主要数据成员:user - AudioTrack 当前的写位置的偏移userBase - AudioTrack 写
8、偏移的基准位置,结合 user 的值方可确定真实的FIFO 地址指针server - AudioFlinger 当前的读位置的偏移serverBase - AudioFlinger 读偏移的基准位置,结合 server 的值方可确定真实的FIFO 地址指针frameCount - FIFO 的大小,以音频数据的帧为单位,16bit 的音频每帧的大小是 2 字节buffers - 指向 FIFO 的起始地址out - 音频流的方向,对于 AudioTrack,out=1,对于AudioRecord,out=0 audio_track_cblk_t 的主要成员函数:framesAvailable_
9、l()和 framesAvailable()用于获取 FIFO 中可写的空闲空间的大小,只是加锁和不加锁的区别。framesReady()用于获取 FIFO 中可读取的空间大小。3) IMemory 接口在 createTrack 的过程中,AudioFlinger 会根据传入的 frameCount 参数,申请一块内存,AudioTrack 可以通过 IAudioTrack 接口的 getCblk()函数获得指向该内存块的 Imemory接口,然后 AudioTrack 通过该 IMemory 接口的 pointer()函数获得指向该内存块的指针,这块内存的开始部分就是 audio_trac
10、k_cblk_t 结构,紧接着是大小为 frameSize的 FIFO 内存。4. AudioPolicyServiceAudioPolicyService 是 Android 音频系统的两大服务之一,另一个服务是 AudioFlinger,这两大服务都在系统启动时有 MediaSever 加载。AudioPolicyService 主要完成以下任务: JAVA 应用层通过 JNI,经由 IAudioPolicyService 接口,访问 AudioPolicyService 提供的服务 输入输出设备的连接状态 系统的音频策略(strategy)的切换 音量/音频参数的设置AudioPolic
11、yService 的构成下面这张图描述了 AudioPolicyService 的静态结构:进一步说明:1) AudioPolicyService 继承了 IAudioPolicyService 接口,这样 AudioPolicyService 就可以基于 Android 的 Binder 机制,向外部提供服务;2) AudioPolicyService 同时也继承了 AudioPolicyClientInterface 类,他有一个AudioPolicyInterface 类的成员指针 mpPolicyManager,实际上就是指向了AudioPolicyManager;3) AudioPo
12、licyManager 类继承了 AudioPolicyInterface 类以便向 AudioPolicyService 提供服务,反过来同时还有一个 AudioPolicyClientInterface 指针,该指针在构造函数中被初始化,指向了 AudioPolicyService,实际上,AudioPolicyService 是通过成员指针 mpPolicyManager 访问 AudioPolicyManager,而 AudioPolicyManager 则通过 AudioPolicyClientInterface(mpClientInterface)访问 AudioPolicySer
13、vice;4) AudioPolicyService 有一个内部线程类 AudioCommandThread,顾名思义,所有的命令(音量控制,输入、输出的切换等)最终都会在该线程中排队执行; 输入输出设备管理音频系统为音频设备定义了一个枚举:AudioSystem:audio_devices ,例如:DEVICE_OUT_SPEAKER,DEVICE_OUT_WIRED_HEADPHONE,DEVICE_OUT_BLUETOOTH_A2DP,DEVICE_IN_BUILTIN_MIC,DEVICE_IN_VOICE_CALL 等等,每一个枚举值其实对应一个 32bit 整数的某一个位,所以这些
14、值是可以进行位或操作的, 音量管理AudioPolicyManager 提供了一下几个与音量相关的函数:initStreamVolume(AudioSystem:stream_type stream, int indexMin, int indexMax) setStreamVolumeIndex(AudioSystem:stream_type stream, int index) getStreamVolumeIndex(AudioSystem:stream_type stream) AudioService.java 中定义了每一种音频流的最大音量级别:/* hide Maximum vo
15、lume index values for audio streams */ private int MAX_STREAM_VOLUME = new int 5, / STREAM_VOICE_CALL 7, / STREAM_SYSTEM 7, / STREAM_RING 15, / STREAM_MUSIC 7, / STREAM_ALARM 7, / STREAM_NOTIFICATION 15, / STREAM_BLUETOOTH_SCO 7, / STREAM_SYSTEM_ENFORCED 15, / STREAM_DTMF 15 / STREAM_TTS ; 由此可见,电话铃声
16、可以有 7 个级别的音量,而音乐则可以有 15 个音量级别,java 的代码通过 jni,最后调用 AudioPolicyManager 的 initStreamVolume(),把这个数组的内容传入 AudioPolicyManager 中,这样 AudioPolicyManager 也就记住了每一个音频流的音量级别。应用程序可以调用 setStreamVolumeIndex 设置各个音频流的音量级别,setStreamVolumeIndex 会把这个整数的音量级别转化为适合人耳的对数级别,然后通过 AudioPolicyService 的 AudioCommandThread,最终会将设置
17、应用到 AudioFlinger 的相应的 Track 中。 音频策略管理我想首先要搞清楚 stream_type,device ,strategy 三者之间的关系:AudioSystem:stream_type 音频流的类型,一共有 10 种类型。AudioSystem:audio_devices 音频输入输出设备,每一个 bit 代表一种设备,见前面的说明。AudioPolicyManager:routing_strategy 音频路由策略,可以有 4 种策略。getStrategy(stream_type)根据 stream type,返回对应的 routing strategy 值,getDeviceForStrategy()则是根据 routing strategy,返回可用的 device。Android 把 10 种stream type 归纳为 4 种路由策略,然后根据路由策略决定具体的输出设备。