在上小节中,分析了android音频系统中,HAL代码的框架,该小节我们根据源代码查看一下流程,加深一下理解。在分析源代码之前,我们先俩看看HAL在整个音频系统中,他处于什么位置,下面是一个框图,相关知识点,在前面的小节中,都已经讲解过:
现在我们来回顾一下,假设有一个android手机,他上面有喇叭,我们在听音乐的时候,声音会中喇叭中播放出来,当插上耳机的时候,声音就从耳机中播放出来,那么这整个过程会涉及什么东西? 1.优先从耳机播放,其由AudioPolicyService决定 2.如果有多个APP要播放声音,AudioFlinger负责混合多个APP的声音,当然除此之外还有其他的许多功能。 3.最终要操作硬件,有多种声卡,可以动态的拔插(USB声卡,蓝牙声卡),对于每一种声卡由一个模块(so文件)来操控他,即HAL 4.为简化声卡的操作,有一个tinyalsa库。只需要pcm_open,pcm_wirte,pcm_read就能进行播放录音。 5.pcm_open,pcm_wirte,pcm_read通过标准的open,wirte,read访问驱动,进而控制驱动访问硬件。
现在我们来看看HAL的代码是怎么被调用的,其又是怎么调用tinyalsa的。下面是流程图: 我们先来看下HAL的操作流程: 1.从/system/etc/audio_policy.conf配置文件中确定so文件的名字。 2.加载so文件 3.HAL文件中的open函数构造并且返回一个audio_hw_device_t 结构体,其中包含了adev_open_output_stream,adev_open_input_stream。 然后AudioFlinger使用audio_hw_device_t 构造成AudioHwDevice对象,每个声卡对应一个audio_hw_device_t 与AudioHwDevice。放入数组mAudioHwDeviceS中。 4.调用hal文件中audio_hw_device_t 结构体中的adev_open_output_stream会构建一个audio_stream_out结构体,返回给AudioFlinger,AudioFlinger使用根据他创建一个MixerThread线程。
根据图示,最终会调用到adev_open_output_stream。
5.write写入给声卡,
以上步骤的对应函数都已经和流程图连接,之前讲解过的函数,就不再次进行讲解了,我们知道每个module中都有一个,如audio_hw_hal.cpp 中:
static int legacy_adev_open(const hw_module_t* module, const char* name,hw_device_t** device){
*device = &ladev->device.common;
}
static struct hw_module_methods_t legacy_audio_module_methods = {
open: legacy_adev_open
};
struct legacy_audio_module HAL_MODULE_INFO_SYM = {
module: {
common: {
tag: HARDWARE_MODULE_TAG,
module_api_version: AUDIO_MODULE_API_VERSION_0_1,
hal_api_version: HARDWARE_HAL_API_VERSION,
id: AUDIO_HARDWARE_MODULE_ID,
name: "LEGACY Audio HW HAL",
author: "The Android Open Source Project",
methods: &legacy_audio_module_methods,
dso : NULL,
reserved : {0},
},
},
};
这个module中有一个方法methods legacy_audio_module_methods,methods 中包含了open函数,那么他是在什么时候被调用呢?从流程图可以知道load_audio_interface,打开AudioFlinger.cpp:
static int load_audio_interface(const char *if_name, audio_hw_device_t **dev)
/*获得一个audio_hw_device_t **dev结构体指针*/
rc = audio_hw_device_open(mod, dev);
audio_hw_device_t 最终在AudioFlinger中被构建成一个AudioHwDevice对象,
现在我们看看最终调用到的adev_open_output_stream函数:
static int adev_open_output_stream(struct audio_hw_device *dev,audio_io_handle_t handle,audio_devices_t devices,audio_output_flags_t flags,struct audio_config *config,struct audio_stream_out **stream_out, const char *address __unused)
out->stream.write = out_write;
*stream_out = &out->stream;
可以知道其返回一个audio_stream_out结构体。其中的out_write函数又对应谁呢?其对应AudioHardware.cpp(厂家提供)中的write函数。当然,引起该函数的调用流程如下: 也就是说MixerThread线程被创建之后,一直在等待数据,当接受到数据之后最终引起AudioHardware.cpp(厂家提供)中的write函数被调用。
下面是该小节的要点总结:
HAL之调用流程源码分析
a. 确定HAL文件的名字:
AudioPolicyManager的构造函数读取配置文件/system/etc/audio_policy.conf
确定名字
b. 加载HAL对应的so文件
c. 打开HAL文件中的open函数
在HAL中会构造audio_hw_device结构体,
该结构体中有各类函数, 特别是 open_output_stream / open_input_stream
AudioFlinger根据audio_hw_device结构体构造一个AudioHwDev对象并放入mAudioHwDevs
d. open output stream:
调用hal结构体audio_hw_device的open_output_stream,
它会构造出一个audio_stream_out结构体, 里面有write函数
AudioFlinger根据audio_stream_out结构体构造一个MixerThread
e. 播放声音(这时才真正打开声卡驱动):
thread->threadLoopg_write => stream.write ==> pcm_open, pcm_write