这个题目比较大,我准备分三篇文章来讲,分别从 android Audio App/framewok hal 和 driver层分别讲述。由于本人能力有限,有些地方会出现错误,大家仅供参考。android 版本以6.0作为参考
下面进入正题,首先是Audio 的 App/framework层,我们就以播放为例,先上图
我们先从Android 的运行角度来介绍一下,无非就是App(哪怕是最简单的helloworld) 通过binder 跨进程与Android 初始化就运行的service进行通讯(即service list 列表打印出的service)并通过hal层调用kerner中的driver驱动程序来实现具体的功能(如配置寄存器控制speaker发声/Audio通路等)
一个最简单的helloworld程序大家如果用eclipse在oncreate位置加断点会发现其至少有三个线程,一个ActivityThread,和两个binder线程,所以binder贯穿Android的始终,理解binder很大程度上能帮助我们更加深入的理解Android系统,后续我会单独开一个binder专题。
下面开始解释该图,首先是App层,
Uri myUri = ....; // initialize Uri here
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(getApplicationContext(), myUri);
mediaPlayer.prepare();
mediaPlayer.start();
上面6行 代码 很简单 ,就 不解释了
APP 层 通过JNI调用本地的Native 代码,注意这时还是在一个进程中,只是本地代码AudioRecord或AudioTrack 通过binder跨进程调用AudioPolicyService或AudioFlingerSerivice,之后AudioService再去调用 hal层去控制底层硬件,整个Android系统都是这么工作的,理解了这点可以更方便大家加深 理解android工作流程。
下面开始分析framework层:
1. AudioTrack/AudioRecord 具体的AudioRecord 和 AudioTrack的分析网上很多
2. AudioFlinger/AudioPolicy
接下来就是这两个service了,网上同样很多。大家只要 记住
AudioPolicyService是策略的制定者,比如什么时候打开音频接口设备、某种Stream类型的音频对应什么设备等等。而AudioFlinger则是策略的执行者,例如具体如何与音频设备通信,如何维护现有系统中的音频设备,以及多个音频流的混音如何处理等等都得由它来完成。AudioPolicyService根据用户配置来指导AudioFlinger加载设备接口,起到路由功能。
2.1.1 AudioFlinger向下访问AudioHardware,实现输出音频数据,控制音频参数。同时,AudioFlinger向上通过IAudioFinger接口提供服务。所以,AudioFlinger在Android的音频系统框架中起着承上启下的作用,地位相当重要。
当Android启动,会加载Audiohadware的.so库,在AudioPolicyManager的构造函中,
最终会进入AudioFlinger的openOut函数,创建对应的线程(mixerthread/DirectOutputThread/offloadThread)
2.1.2 Track 和 thread 之间的关系
AudioFlinger中会创建对应得线程,准确的说有如下几种 线程
enum type_t {
MIXER, // Thread class is MixerThread
DIRECT, // Thread class is DirectOutputThread
DUPLICATING, // Thread class is DuplicatingThread
RECORD, // Thread class is RecordThread
OFFLOAD // Thread class is OffloadThread
};
其中mixer线程包括,primary, deepbuffer fasttrack等
Record主要作为录音
Duplicating 主要是蓝牙方面
Direct顾名思义就是不经过混音的线程
OFFload 硬件混音不通过软件,codec 内部dsp去处理
解释了上面几种线程之后,我们来分析下Track 和 Thread之间的关系,
创建好的线程会把该线程和它的Id保存在AudioFlinger的成员变量mPlaybackThreads中,AudioFlinger创建的线程都会保存在里面,最后,openOutput返回该线程的Id,该Id也就是所谓的audio_io_handle_t,AudioFlinger的调用者这能看到这个audio_io_handle_t,当需要访问时传入该audio_io_handle_t,AudioFlinger会通过mPlaybackThreads,得到该线程的指针
上图是我从 某大神的博客 截取出来的,在其基础上添加 了一部分线程 相关的内容 ,从图中可以很容易的 看出,各个mixer线程的thread都是相互独立的,每个thread之间的Track 也是相互独立 的,这些在framework层 相互 独立 的track在对应的Thread中混音之后 传递给hal层,kernel层 中 会把这些相互独立的track进行 硬件 Mixer,从而达到了混音的效果。
2.1.3 AudioFlinger Thread中的几个Buffer
AudioFlinger是实现上层跟Hal层进行交互的重要的一层,它主要就是通过Thread进行沟通,不管是数据流还是控制流都是需要经由AudioFlinger Thread往下分发
主要是下面三个buffer:
1.mSinkBuffer,这个buffer的数据最后是要写到hal去的,但是你会发现一开始都没有对它操作,只有在写之前最后一步的时候会进行拷贝操作,将之前处理过的数据的buffer拷贝到该buffer中来。
2.mMixerBuffer 在没有效果的情况下,使用这个buffer进行前期处理
3.mEffectBuffer 如果有效果的话,该buffer会直接取代mMixerBuffer进行处理
具体的数据流数据流 audiotrack->audiomixer->audioeffect->audio hal的,这里就不上代码了,大家可以根据这个流程自己去跟下AudioFlinger的源码
2.2.1 AudioPolicy
AudioPolicyService主要完成以下任务:
. JAVA应用层通过JNI,经由IAudioPolicyService接口,访AudioPolicyService 提供的服务
.输入输出设备的连接状态
.系统的音频策略(strategy)的切换
.音量/音频参数的设置
AudioPolicyService的很大一部分管理工作都是在AudioPolicyManager中完成的。包括音量管理,音频策略(strategy)管理,输入输出设备管理
2.2.2 音频策略管理
主要理解 stream_type,device,strategy三者之间的关系:
AudioSystem::stream_type 音频流的类型,一共有10种类型
AudioSystem::audio_devices 音频输入输出设备,每一个bit代表一种设备,见前面的说明
AudioPolicyManager::routing_strategy 音频路由策略,可以有4种策略
总结一下,主要是从 Android的调用角度分析 了一下音频的调用流程,着重讲解了AudioFlinger中创建的几个线程 ,以及 线程 的通信关系,将framework层Audio个人 认为 重要的点都提了一遍,又不 详细的后续 还会 补充 。 好了,framework层的代码分析就到 这里