Android Audio音频系统之深入浅出
一、Audio音频架构简介
二、Android Audio系统框架
三、Audio架构以及各层的代码分布图
四、音频框架在Android系统中的进一步细化
五、创建声卡和注册声卡
六、Android Audio系统的结构
七、Audio音频原理介绍
八、Audio音频策略制定与策略执行的调用流程
九、Android AudioPolicyService服务启动过程
十、Android系统中所有的音频接口设备保存到AudioFlinger的成员变量mAudioHwDevs中
十一、audio_policy.conf同时定义了多个audio接口
十二、通过AudioFlinger的loadHwModule加载各audio接口对应的库文件实现调用PlaybackThread播放线程或RecordThread录音线程
十三、AudioFlinger的openInput()方法调用流程分析
十四、AudioFlinger的openOutput()方法的调用流程分析
十五、Audio系统为了能正常播放音频数据,需要创建抽象的音频输出接口对象,打开音频输出过程
十六、打开音频输入的流程
十七、打开音频输出后,在AudioFlinger与AudioPolicyService中的表现形式
十八、打开音频输入后,在AudioFlinger与AudioPolicyService中的表现形式
十九、AudioPolicyService加载完系统定义的所有音频接口,并生成相应的数据对象
二十、AudioPolicyService与AudioTrack和AudioFlinger的关系
二十一、AudioPolicyService注册名为服务的流程
二十二、AudioTrack构造过程
二十三、AudioTrack和AudioFlinger的关系
二十四、audio_policy与AudioPolicyService、AudioPolicyCompatClient之间的关系
一、Audio音频架构简介
APP
整个音频体系的最上层
Framework
MediaPlayer和MediaRecorder、AudioTrack和AudioRecorder,Android系统为控制音频系统提供了AudioManager、AudioService及AudioSystem类,这些都是framework为便利上层应用开发所设计的
Libraries
系统服务AudioFlinger和AudioPolicyService(比如:ServiceManager、LocationManagerService、ActivityManagerService等等),音频体系中另一个重要的系统服务是MediaPlayerService
HAL
硬件抽象层是AudioFlinger直接访问的对象,这说明了两个问题,一方面AudioFlinger并不直接调用底层的驱动程序;另一方面,AudioFlinger上层(包括和它同一层的MediaPlayerService)的模块只需要与它进行交互就可以实现音频相关的功能了。因而我们可以认为AudioFlinger是Android音频系统中真正的“隔离板”,无论下面如何变化,上层的实现都可以保持兼容。音频方面的硬件抽象层主要分为两部分,即AudioFlinger和AudioPolicyService。实际上后者并不是一个真实的设备,只是采用虚拟设备的方式来让厂商可以方便地定制出自己的策略,抽象层的任务是将AudioFlinger/AudioPolicyService真正地与硬件设备关联起来
以前Android系统中的Audio系统依赖于ALSA-lib,但后期就变为了tinyalsa,这样的转变不应该对上层造成破坏。因而Audio HAL提供了统一的接口来定义它与AudioFlinger/AudioPolicyService之间的通信方式,这就是audio_hw_device、audio_stream_in及audio_stream_out等等存在的目的,这些Struct数据类型内部大多只是函数指针的定义,是一些“壳”。当AudioFlinger/AudioPolicyService初始化时,它们会去寻找系统中最匹配的实现(这些实现驻留在以audio.primary.*,audio.a2dp.*为名的各种库中)来填充这些“壳”
理解Android音频系统的时候分为两条线索
以库为线索,比如:AudioPolicyService和AudioFlinger都是在libaudioflinger库中,而AudioTrack、AudioRecorder等一系列实现则在libmedia库中
以进程为线索,库并不代表一个进程,进程则依赖于库来运行。虽然有的类是在同一个库中实现的,但并不代表它们会在同一个进程中被调用。比如AudioFlinger和AudioPolicyService都驻留于名为mediaserver的系统进程中,而AudioTrack/AudioRecorder和MediaPlayer/MediaRecorder一样实际上只是应用进程的一部分,它们通过binder服务来与其它系统进程通信
二、Android Audio系统框架
三、Audio架构以及各层的代码分布图
四、音频框架在Android系统中的进一步细化
五、创建声卡和注册声卡
六、Android Audio系统的结构
七、Audio音频原理介绍
AudioFlinger、AudioPolicyService和AudioTrack/AudioRecorder抛开MediaPlayer、MediaRecorder这些与应用开发直接关联的部分,整个音频系统的核心就是由这三者构建而成的。其中前两个都是System Service,驻留在mediaserver进程中,不断地处理AudioTrack/AudioRecorder的请求。音频的回放和录制从大的流程上看都是相似的,所以我们侧重于对AudioTrack的分析
把所有媒体相关的native层服务(包括AudioFlinger,MediaPlayerService,CameraService和AudioPolicyService)启动起来,编译生成的mediaserver将被烧录到设备的/system/bin/mediaserver路径,然后由系统启动时的init进程启动
Audio系统的结构
libmedia.so提供Audio接口,这些Audio接口既向上层开放,也向本地代码开放
libaudiofilnger.so提供Audio接口实现
Audio硬件抽象层提供到硬件的接口,供AudioFlinger调用
Audio使用JNI和JAVA对上层提供接口
media库中的Audio框架部分
Android 的Audio的核心框架在media库中提供,其中对上面主要实现AudioSystem、AudioTrack和AudioRecorder三个类。提供了IAudioFlinger类接口,在这个类中,可以获得IAudioTrack和IAudioRecorder两个接口,分别用于声音的播放和录制。AudioTrack和AudioRecorder分别通过调用IAudioTrack和IAudioRecorder来实现
Audio系统的头文件
路径为:frameworks/base/include/media/
AudioSystem.h
IAudioFlinger.h
AudioTrack.h
IAudioTrack.h
AudioRecorder.h
IAudioRecorder.h
Ixxx的接口通过AudioFlinger来实现,其他接口通过JNI向上层提供接口
Audio系统的头文件在frameworks/base/include/media/目录中,主要的头文件如下
AudioSystem.h:media库的Audio部分对上层的总管接口
IAudioFlinger.h:需要下层实现的总管接口
AudioTrack.h:放音部分对上接口
IAudioTrack.h:放音部分需要下层实现的接口
AudioRecorder.h:录音部分对上接口
IAudioRecorder.h:录音部分需要下层实现的接口
IAudioFlinger.h、IAudioTrack.h和IAudioRecorder.h这三个接口通过下层的继承来实现(即:AudioFlinger)
AudioFlinger.h,AudioTrack.h和AudioRecorder.h是对上层提供的接口,它们既供本地程序调用(例如:声音的播放器、录制器等),也可以通过JNI向Java层提供接口
AudioTrack和AudioRecorder都具有start,stop和pause等接口。前者具有write接口,用于声音的播放,后者具有read接口,用于声音的录制
AudioSystem用于Audio系统的控制工作,主要包含一些set和get接口,是一个对上层的类
AudioFlinger是Audio系统的核心,来自AudioTrack的数据,最终在这里得到处理并被写入Audio HAL层
MediaPlayer在framework层还是会创建AudioTrack,把解码后的PCM数流传递给AudioTrack,AudioTrack再传递给AudioFlinger进行混音,然后才传递给硬件播放,所以是MediaPlayer包含了AudioTrack。使用AudioTrack播放音乐
MediaPlayer提供了更完整的封装和状态控制,相比MediaPlayer,AudioTrack更为精练、高效,实际上MediaPlayerService的内部实现就是使用了AudioTrack把所有媒体相关的native层服务(包括AudioFlinger,MediaPlayerService,CameraService和AudioPolicyService)启动起来,编译生成的mediaserver将被烧录到设备的/system/bin/mediaserver路径,然后由系统启动时的init进程启动
两种Audio Hardware HAL接口定义
legacy:hardware/libhardware_legacy/include/hardware_legacy/AudioHardwareInterface.h
非legacy:hardware/libhardware/include/hardware/audio.h
前者是2.3及之前的音频设备接口定义,后者是4.0的接口定义,为了兼容以前的设计,4.0实现一个中间层:hardware/libhardware_legacy/audio/audio_hw_hal.cpp,结构与其他的audio_hw.c大同小异,差别在于open方法事实上legacy也要封装成非legacy中的audio.h,确切的说需要一个联系legacy interface和not legacy interface的中间层,这里的audio_hw_hal.cpp就充当这样的一个角色了
hardware/libhardware/modules/audio/
createAudioHardware()函数
external/tinyalsa/
mixer.c 类alsa-lib的control,作用音频部件开关、音量调节等
pcm.c 类alsa-lib的pcm,作用音频pcm数据回放录制
上面的hardware/libhardware_legacy/audio/、hardware/libhardware/modules/audio/、device/samsung/tuna/audio/是同层的。之一是legacy audio,用于兼容2.2时代的alsa_sound;之二是stub audio接口;之三是Samsung Tuna的音频抽象层实现。调用层次:AudioFlinger -> audio_hw -> tinyalsa
Audio硬件抽象层的实现在各个系统中可能是不同的,需要使用代码去继承相应的类并实现它们,作为Android系统本地框架层和驱动程序接口AudioFlinger继承了libmedia.so(Audio本地框架类)里面的接口,上层调用的只是libmedia.so部分的接口,但实际上调用的内容是libaudioflinger.so,使用JNI和Java对上层提供接口,JNI部分通过调用libmedia.so库提供的接口来实现
Audio硬件抽象层提供到硬件的接口,供AudioFlinger调用,Audio的硬件抽象层实际上是各个平台开发过程中需要主要关注和独立完成的部分,因为Android中的Audio系统不涉及编解码环节,只负责上层系统和底层Audio硬件的交互,所以通常以PCM作为输入/输出格式
IAudioFlinger类接口通过该类可以获得IAudioTrack和IAudioRecorder两个接口,分别用于声音的播放和录制,AudioTrack和AudioRecorder分别通过调用IAudioTrack和IAudioRecorder来实现
硬件抽象层主要实现了AudioStreamInALSA和AudioStreamOutALSA两个类,这两个类又会调用该文件下的 ALSAStreamOps类的方法。AudioStreamInALSA是录音部分调用的路径。在AudioStreamInALSA的构造函数中会对alsa进行一些初始化参数设置,
AudioStreamInALSA的read方法是最主要的方法,audioflinger层的read调用就是对 AudioStreamInALSA的read的调用。由于
录音部分出现单声道和双声道数据传输的问题,修改read方法如下,即可实现了录音功能正常, 避免了在编码的时候修改数据时其他编码仍不能工作的弊端
八、Audio音频策略制定与策略执行的调用流程
AudioPolicyService是策略的制定者,AudioFlinger则是策略的执行者
AudioTrack是AudioFlinger的客户端,AudioFlinger是Android系统中Audio管理的中枢
在Android中AudioPolicyService最终都会调用到AudioFlinger中去,因为AudioFlinger实际创建并管理了硬件设备
AudioFlinger类是代表整个AudioFlinger服务的类,其余所有的工作类都是通过内部类的方式在其中定义的
九、Android AudioPolicyService服务启动过程
AudioPolicyService完成的工作
加载audio_policy.default.so库得到audio_policy_module模块
通过audio_policy_module模块打开audio_policy_device设备
通过audio_policy_device设备创建audio_policy
hw_get_module函数加载硬件抽象层模块的过程
audio_policy实现在audio_policy_hal.cpp中,audio_policy_service_ops实现在AudioPolicyService.cpp中。create_audio_policy()函数就是创建并初始化一个legacy_audio_policy对象,AudioPolicyCompatClient是对audio_policy_service_ops的封装类,对外提供audio_policy_service_ops数据结构中定义的接口
Android AudioPolicyService服务启动过程
引用AudioPolicyCompatClient对象,这样音频管理器AudioPolicyManager就可以使用audio_policy_service_ops中的接口
优先加载/vendor/etc/audio_policy.conf配置文件,如果该配置文件不存在,则加载/system/etc/audio_policy.conf配置文件,如果该文件还是不存在,则通过函数defaultAudioPolicyConfig()来设置默认音频接口
设置各种音频流对应的音量调节点
通过名称打开对应的音频接口硬件抽象库
打开mAttachedOutputDevices对应的输出
将输出IOProfile封装为AudioOutputDescriptor对象
设置当前音频接口的默认输出设备
打开输出,在AudioFlinger中创建PlaybackThread线程,并返回该线程的id
设置可以使用的输出设备为mAttachedOutputDevices
将输出描述符对象AudioOutputDescriptor及创建的PlaybackThread线程id以键值对形式保存
设置默认输出设备
AudioPolicyManagerBase对象构造过程中主要完成以下几个步骤
loadAudioPolicyConfig(AUDIO_POLICY_CONFIG_FILE)加载audio_policy.conf配置文件
initializeVolumeCurves()初始化各种音频流对应的音量调节点
加载audio policy硬件抽象库:mpClientInterface->loadHwModule(mHwModules[i]->mName)
打开attached_output_devices输出mpClientInterface->openOutput();
保存输出设备描述符对象addOutput(output, outputDesc);
十、Android系统中所有的音频接口设备保存到AudioFlinger的成员变量mAudioHwDevs中
audio_policy.conf文件
从audio_policy.conf文件中可以发现,系统包含了primary、a2dp、usb等音频接口,对应着系统中的audio.<primary/a2dp/usb>.<device>.so。每个音频接口中又包含了若干个outputs & inputs,并且每个output or input又包含了若干个devices,且还有采样频率,声道数等信息。这些devices信息、采样频率信息 & 声道信息等都会保存在各自module的IOProfile中。按上文中audio_policy.conf配置文件所描述,系统最后会生成6个modules(eg.primary,a2dp,hdmi,r_submix,hs_usb & usb)以及7个outputs
十一、audio_policy.conf同时定义了多个audio接口
不同的Android产品在音频的设计上通常是存在差异的,而这些差异可以通过Audio的配置文件audio_policy.conf来获得。在Android系统中音频配置文件存放路径有两处,存放地址可以从AudioPolicyManagerBase.cpp文件中获取
在AudioPolicyManager.cpp文件中可以知道系统会首先加载vendor/etc目录下的configure文件,再加载system/etc目录下的configure文件。若这两者加载都发生错误的话,系统会加载default配置文件,并命名为primary module
通过loadGlobalConfig(root)函数来读取这些全局配置信息,通过loadHwModules()函数来加载系统配置的所有audio接口(加载音频接口),由于audio_policy.conf可以定义多个音频接口,因此该函数循环调用loadHwModule()来解析每个音频接口参数信息。Android定义HwModule类来描述每一个audio接口参数,定义IOProfile类来描述输入输出模式配置
/system/etc/audio_policy.conf
/vendor/etc/audio_policy.conf
加载audio_module模块
AudioPolicyManager通过读取audio_policy.conf配置文件,可以知道系统当前支持哪些音频接口以及attached的输入输出设备、默认输出设备。接下来就需要加载这些音频接口的硬件抽象库
AudioPolicyClientInterface提供了加载音频接口硬件抽象库的接口函数,AudioPolicyCompatClient通过代理audio_policy_service_ops实现AudioPolicyClientInterface接口
AudioPolicyCompatClient将音频模块加载工作交给audio_policy_service_ops,AudioPolicyService又将其转交给AudioFlinger
当AudioPolicyManagerBase构造时,它会根据用户提供的audio_policy.conf来分析系统中有哪些audio接口(primary,a2dp以及usb),然后通过AudioFlinger::loadHwModule加载各audio接口对应的库文件,并依次打开其中的output(openOutput)和input(openInput)
打开音频输出时创建一个audio_stream_out通道,并创建AudioStreamOut对象以及新建PlaybackThread播放线程
打开音频输入时创建一个audio_stream_in通道,并创建AudioStreamIn对象以及创建RecordThread录音线程
audio_policy.conf文件定义了两种音频配置信息
当前系统支持的音频输入输出设备及默认输入输出设备,这些信息是通过global_configuration配置项来设置,在global_configuration中定义了三种音频设备信息
attached_output_devices:已连接的输出设备
default_output_device:默认输出设备
attached_input_devices:已连接的输入设备
系统支持的音频接口信息
audio_policy.conf定义了系统支持的所有音频接口参数信息,比如primary、a2dp、usb等
每种音频接口包含输入输出,每种输入输出又包含多种输入输出配置,每种输入输出配置又支持多种音频设备。AudioPolicyManagerBase首先加载/vendor/etc/audio_policy.conf,如果该文件不存在,则加载/system/etc/audio_policy.conf
audio_policy.conf同时定义了多个audio 接口,每一个audio接口包含若干output和input,而每个output和input又同时支持多种输入输出模式,每种输入输出模式又支持若干种设备
十二、通过AudioFlinger的loadHwModule加载各audio接口对应的库文件实现调用PlaybackThread播放线程或RecordThread录音线程
十三、AudioFlinger的openInput()方法调用流程分析
十四、AudioFlinger的openOutput()方法的调用流程分析
十五、Audio系统为了能正常播放音频数据,需要创建抽象的音频输出接口对象,打开音频输出过程
十六、打开音频输入的流程
十七、打开音频输出后,在AudioFlinger与AudioPolicyService中的表现形式
十八、打开音频输入后,在AudioFlinger与AudioPolicyService中的表现形式
十九、AudioPolicyService加载完系统定义的所有音频接口,并生成相应的数据对象
二十、AudioPolicyService与AudioTrack和AudioFlinger的关系
二十一、AudioPolicyService注册名为服务的流程
二十二、AudioTrack构造过程
二十三、AudioTrack和AudioFlinger的关系
二十四、audio_policy与AudioPolicyService、AudioPolicyCompatClient之间的关系
欢迎关注公众号