转载请注明出处:http://blog.csdn.net/adits/article/details/8242146
开发环境简介
1. 主机系统: Unbuntu10.10
2. android系统版本: 4.0.3(Linux kernel 3.0.8)
综述
android的音频系统非常庞大复杂:涉及到java应用程序,java框架层,JNI,本地服务(AudioFlinger和AudioPolicyService),硬件抽象层HAL,ALSA-LIB和ALSA-DRIVER。
本文将先分析音频系统的启动与模块加载流程,并具体分析一个JAVA API的调用流程;最后在此基础上自然地为android系统添加USB AUDIO设备的放音和录音功能。
全文可分为如下几大部分:
1. 本地服务的启动流程分析。
1.1 AudioFlinger启动流程及其所涉及的HAL层模块启动流程分析。
1.2 AudioPolicyService启动流程及其所涉及的HAL层模块启动流程分析。
2. JAVA API setDeviceConnectionState()调用流程详解,同时为android系统添加USB AUDIO设备的放音和录音功能。
3. ALSA-LIB浅述以及asound.conf配置文件的书写。
4. 重新获取USB AUDIO设备的硬件参数。
详述
1. 本地服务的启动流程分析。
AudioFlinger和AudioPolicyService两大音频服务都是在android系统启动时就启动的。
当linux kenerl启动完成后,会启动android的init进程(system/core/init/init.c)。
"font-size:24px;">intmain(intargc,char**argv)
{
.....
init_parse_config_file("/color:#ff0000;">init.rc");
.....
}
init.rc文件中保存了许多系统启动时需要启动的服务。其中就有多媒体服务mediaserver的启动:
service media /system/bin/mediaserver
此服务在文件frameworks/base/media/mediaserver/main_mediaserver.cpp中定义,而音频子系统的两大本地服务AudioFlinger和AudioPolicyService就是在此启动的。
""style="font-size:24px;">intmain(intargc,char** argv)
{
.....
"color:#ff0000;">AudioFlinger::instantiate(); "color:#3333ff;">//实例化AudioFlinger
.....
"color:#ff0000;">AudioPolicyService::instantiate(); "color:#3333ff;">//实例化AudioPolicyService
.....
}
1.1 AudioFlinger启动流程及其所涉及的HAL层模块启动流程分析。
根据上文分析,将调用AudioFlinger::instantiate()函数实例化AudioFlinger。但是AudioFlinger.cpp中并没有找到此函数,那必然在其父类中。AudioFlinger类有很多父类,一时难以确定instantiate()到底在哪个父类中定义的。直接搜索吧!
grep -rn "instantiate" frameworks/base/
很快找到instantiate()函数的定义处在./frameworks/base/include/binder/BinderService.h头文件中
""style="font-size:24px;">template
classBinderService
{
public:
staticstatus_t publish() {
spsm(defaultServiceManager());
returnsm->addService(String16("color:#ff0000;">SERVICE::getServiceName()), "color:#ff0000;">newSERVICE());
......
staticvoidinstantiate() { publish(); }
.....
}
}
这里用到了模板,需要确定SERVICE是什么东东。
AudioFlinger类是在AudioFlinger.h中定义的,而恰好包含了头文件BinderService.h。
""style="font-size:24px;">classAudioFlinger :
public"color:#ff0000;">BinderService,
publicBnAudioFlinger
{
friendclassBinderService;
public:
staticcharconst* getServiceName() {return"media.audio_flinger"; }
.....
}
原来AudioFlinger类继承了BinderService类,同时把自己(AudioFlinger)传递给SERVICE。而addService函数第一个参数调用了AudioFlinger类的静态成员函数getServiceName()获取AudioFlinger的服务名称;其第二个参数便是创建了一个AudioFlinger的实例。至此,明白了实例化函数instantiate()就是要向服务管理器注册的服务是AudioFlinger。
既然此时实例化了AudioFlinger,那么看看AudioFlinger类的构造函数具体做了哪些初始化工作。
""style="font-size:24px;">AudioFlinger::AudioFlinger()
: BnAudioFlinger(),
mPrimaryHardwareDev(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1),
mBtNrecIsOff(false)
{
}
此构造函数做了一些无关紧要的事情,不管它。既然AudioFlinger服务是第一次启动,则将调到函数AudioFlinger::onFirstRef(至于为什么,我还没有搞明白,可以通过log信息确信确实是这么回事)。
void AudioFlinger::onFirstRef()
{
......
for (size_t i = 0; i < ARRAY_SIZE(audio_interfaces); i++) {
const hw_module_t *mod;
audio_hw_device_t *dev;
rc = load_audio_interface(audio_interfaces[i], &mod,&dev);
.....
mAudioHwDevs.push(dev); // 把通过load_audio_interface()函数获得的设备存入元素为audio_hw_device_t
// 类型的模板变量mAudioHwDevs中
.....
}
看到load_audio_interface()函数的名字,知晓,应当是加载音频接口的。
"font-size:24px;">staticintload_audio_interface(constchar*if_name,consthw_module_t **mod,
audio_hw_device_t **dev)
{
......
rc = "color:#ff0000;">hw_get_module_by_class("color:#ff0000;">AUDIO_HARDWARE_MODULE_ID, if_name, mod);
if(rc)
gotoout;
rc = "color:#ff0000;">audio_hw_device_open(*mod, "color:#ff0000;">dev);
.....
}
首先通过函数hw_get_module_by_class获取ID号为AUDIO_HARDWARE_MODULE_ID的音频模块,此ID在头文件hardware/libhardware/include/hardware/audio.h中定义。此头文件中定义了一个十分重要的结构体struct audio_hw_device,其中包含了许多函数接口(函数指针):
"font-size:24px;">structaudio_hw_device {
structhw_device_t common;
/**
* used by audio flinger to enumerate what devices are supported by
* each audio_hw_device implementation.
*
* Return value is a bitmask of 1 or more values of audio_devices_t
*/
uint32_t (*"color:#ff0000;">get_supported_devices)(conststructaudio_hw_device *dev);
/**
* check to see if the audio hardware interface has been initialized.
* returns 0 on success, -ENODEV on failure.
*/
int(*"color:#ff0000;">init_check)(conststructaudio_hw_device *dev);
......
/* set/get global audio parameters */
int(*"color:#ff0000;">set_parameters)(structaudio_hw_device *dev,constchar*kv_pairs);
.....
/** This method creates and opens the audio hardware output stream */
int(*"color:#ff0000;">open_output_stream)(structaudio_hw_device *dev, uint32_t devices,
int*format, uint32_t *channels,
uint32_t *sample_rate,
structaudio_stream_out **out);
......
/** This method creates and opens the audio hardware input stream */
int(*open_input_stream)(structaudio_hw_device *dev, uint32_t devices,
int*format, uint32_t *channels,
uint32_t *sample_rate,
audio_in_acoustics_t acoustics,
structaudio_stream_in **stream_in);
.....
}
ID为AUDIO_HARDWARE_MODULE_ID的音频模块到底在哪儿定义的那?既然是HAL层模块,必定在hardware目录下定义的
$ grep -rn AUDIO_HARDWARE_MODULE_ID hardware/
hardware/libhardware_legacy/audio/audio_hw_hal.cpp:602:id: AUDIO_HARDWARE_MODULE_ID,
hardware/libhardware/modules/audio/audio_hw.c:435: .id = AUDIO_HARDWARE_MODULE_ID,
hardware/libhardware/include/hardware/audio.h:37:
#define AUDIO_HARDWARE_MODULE_ID "audio"
从搜索结果发现,AUDIO_HARDWARE_MODULE_ID的音频模块有两处定义,具体用的是哪一个那?
先分析下这两个模块最终编译进哪些模块。
通过查阅Android.mk晓得,audio_hw.c先被编译进audio_policy.stub模块,而后被编译进libhardware模块;
同样的,audio_hw_hal.cpp先被编译进libaudiopolicy_legacy模块,而后被编译进libhardware_legacy模块;
而libhardware和libhardware_legacy模块都在audioFlinger中用到。
通过log信息,确认使用的是libaudiopolicy_legacy模块,即具体调到hardware/libhardware_legacy/audio/audio_hw_hal.cpp文件中所定义的模块了。
在获取到HAL层音频模块后,接下来执行audio_hw_device_open()函数,打开设备。此函数也在audio.h头文件中定义,函数体如下:
"font-size:24px;">/** convenience API for opening and closing a supported device */
staticinlineintaudio_hw_device_open(conststructhw_module_t* module,
structaudio_hw_device** device)
{
returnmodule->methods->open(module, AUDIO_HARDWARE_INTERFACE,
(structhw_device_t**)device);
}
struct hw_module_t是在hardware/libhardware/include/hardware/hardware.h头文件中定义的,其中嵌套了struct hw_module_methods_t。此结构体很简单,只有一个函数指针open
"font-size:24px;">typedefstructhw_module_methods_t {
/** Open a specific device */
int(*open)(conststructhw_module_t* module,constchar* id,
structhw_device_t** device);
} hw_module_methods_t;
在确定具体模块后,很容易确定open函数指针的具体实现
"font-size:24px;">structlegacy_audio_module HAL_MODULE_INFO_SYM = {
module: {
common: {
tag: HARDWARE_MODULE_TAG,
version_major: 1,
version_minor: 0,
id: AUDIO_HARDWARE_MODULE_ID,
name: "LEGACY Audio HW HAL",
author: "The Android Open Source Project",
methods: &"color:#ff0000;">legacy_audio_module_methods,
dso : NULL,
reserved : {0},
},
},
};
"font-size:24px;">staticstructhw_module_methods_t legacy_audio_module_methods = {
open: "color:#ff0000;">legacy_adev_open
};
open()的实现就是legacy_adev_open()函数了!
"font-size:24px;">staticintlegacy_adev_open(consthw_module_t* module,constchar* name,
hw_device_t** device)
{
structlegacy_audio_device *ladev;
intret;
if(strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)// 看来对应宏AUDIO_HARDWARE_INTERFACE,除了用来判断希望打开的是否音频硬件接口外,并没有做什么更多的事情
return-EINVAL;
.....
ladev->device.get_supported_devices = adev_get_supported_devices;
ladev->device.init_check = "color:#ff0000;">adev_init_check;
.....
ladev->device.open_output_stream = "color:#ff0000;">adev_open_output_stream;
ladev->device.close_output_stream = adev_close_output_stream;
ladev->device.open_input_stream = adev_open_input_stream;
ladev->device.close_input_stream = adev_close_input_stream;
.....
ladev->hwif = "color:#ff0000;">createAudioHardware();
.....
"color:#ff0000;">*device = &ladev->device.common; "color:#3333ff;">// 将当前设备信息层层返回给回调函数,最后返回到
// load_audio_interface()函数,并保存在
// mAudioHwDevs模板变量中,供AudioFlinger类使用。
return0;
}
这里主要做了一些初始化工作,即给函数指针提供具体实现函数;但createAudioHardware()应该做了更多的事情。
先从函数createAudioHardware()的返回值入手。struct legacy_audio_device的定义如下:
"font-size:24px;">structlegacy_audio_device {
structaudio_hw_device device;
structAudioHardwareInterface *hwif;
};
原来createAudioHardware()的返回值是一个硬件设备接口AudioHardwareInterface。
类AudioHardwareInterface正好在audio_hw_hal.cpp文件中所包含的头文件hardware_legacy/AudioHardwareInterface.h中定义的虚类(结构体能调到类,还是头一遭见到,虽然结构体和类长得很象)。那么我很想知道createAudioHardware()具体做了哪些事情。
首先需要确定函数createAudioHardware()的定义在哪儿?有几处定义?调用的具体是哪一个?
AudioHardwareInterface.h头文件中对createAudioHardware函数的声明,没有包含在任何类中,而仅仅包含在名字空间android_audio_legacy中,这和audio_hw_hal.cpp同在一个名字空间中。
"font-size:24px;">namespaceandroid_audio_legacy {
.....
extern"C"AudioHardwareInterface* createAudioHardware(void);
}; // namespace android
经搜索,发现createAudioHardware()函数有四处定义。
"font-size:24px;">$ grep -rn createAudioHardware hardware/ --exclude-dir=.svn
hardware/alsa_sound/AudioHardwareALSA.cpp:45:
android_audio_legacy::AudioHardwareInterface *createAudioHardware(void) {
hardware/msm7k/libaudio-qsd8k/AudioHardware.cpp:2021:
extern"C"AudioHardwareInterface* createAudioHardware(void) {
hardware/msm7k/libaudio-qdsp5v2/AudioHardware.cpp:337:
extern"C"AudioHardwareInterface* createAudioHardware(void) {
hardware/msm7k/libaudio/AudioHardware.cpp:1132:
extern"C"AudioHardwareInterface* createAudioHardware(void) {
只有AudioHardwareALSA.cpp文件中包含了头文件hardware_legacy/AudioHardwareInterface.h,并且返回值是android_audio_legacy名字空间的AudioHardwareInterface类对象。则createAudioHardware函数的具体实现很可能是它了,通过log信息证明了这一点。
进入AudioHardwareALSA.cpp,不难看出,此函数,最后会通过执行代码如下代码创建AudioHardwareALSA类对象。
"font-size:24px;">returnnewAudioHardwareALSA();
AudioHardwareALSA类的构造函数如下:
""style="font-size:24px;">AudioHardwareALSA::AudioHardwareALSA() :
mALSADevice(0),
mAcousticDevice(0)
{
......
interr = "color:#ff0000;">hw_get_module("color:#ff0000;">ALSA_HARDWARE_MODULE_ID,
(hw_module_t const**)"color:#ff0000;">&module);
if(err == 0) {
hw_device_t* device;
err = "color:#ff0000;">module->methods->open(module, "color:#ff0000;">ALSA_HARDWARE_NAME, &device);
if(err == 0) {
mALSADevice = (alsa_device_t *)device;
"color:#ff0000;">mALSADevice->init("color:#ff0000;">mALSADevice, "color:#ff0000;">mDeviceList);
.....
err = hw_get_module(ACOUSTICS_HARDWARE_MODULE_ID,
(hw_module_t const**)&module);
if(err == 0) {
hw_device_t* device;
err = module->methods->open(module, ACOUSTICS_HARDWARE_NAME, &device);
.....
}
宏ALSA_HARDWARE_MODULE_ID是在头文件hardware/alsa_sound/AudioHardwareALSA.h中定义的。
模块所对应的结构体类型为hw_module_t,在头文件hardware/libhardware/include/hardware/hardware.h中定义。
在构造函数中,首先调用函数hw_get_module()获取ID为ALSA_HARDWARE_MODULE_ID的ALSA硬件模块,看来即将进入庞大而又功能强大的ALSA音频子系统了!
经过搜索,很快确定ID为ALSA_HARDWARE_MODULE_ID的ALSA硬件抽象层的具体实现在文件hardware/alsa_sound/alsa_default.cpp中。
""style="font-size:24px;">$ grep -rn ALSA_HARDWARE_MODULE_ID hardware/ --exclude-dir=.svn
hardware/alsa_sound/AudioHardwareALSA.h:39:#define ALSA_HARDWARE_MODULE_ID "alsa"
hardware/alsa_sound/alsa_default.cpp:59:
id : ALSA_HARDWARE_MODULE_ID,
hardware/alsa_sound/AudioHardwareALSA.cpp:150:
interr = hw_get_module(ALSA_HARDWARE_MODULE_ID,
则很快找到此模块的具体内容如下:
""style="font-size:24px;">extern"C"consthw_module_t HAL_MODULE_INFO_SYM = {
tag : HARDWARE_MODULE_TAG,
version_major : 1,
version_minor : 0,
id : ALSA_HARDWARE_MODULE_ID,
name : "ALSA module",
author : "Wind River",
methods : &"color:#ff0000;">s_module_methods,
dso : 0,
reserved : { 0, },
};
s_module_methods函数的实现如下:
""style="font-size:24px;">statichw_module_methods_t s_module_methods = {
open : s_device_open
};
s_device_open函数的实现如下:
""style="font-size:24px;">staticints_device_open(consthw_module_t* module,constchar* name, "color:#3333ff;">//有些困惑,
// 此open函数实现中并没有对调用者传递下来的name(ALSA_HARDWARE_NAME)作如何处理。
hw_device_t** device) "color:#3333ff;">"background-color: rgb(255, 255, 255);">//device存储返回的模块信息
{
alsa_device_t *dev;
dev = (alsa_device_t *) malloc(sizeof(*dev));
if(!dev)return-ENOMEM;
memset(dev, 0, sizeof(*dev));
/* initialize the procs */
dev->common.tag = HARDWARE_DEVICE_TAG;
dev->common.version = 0;
dev->common.module = (hw_module_t *) module;
dev->common.close = s_device_close;
dev->init = "color:#ff0000;">s_init;
dev->open = "color:#ff0000;">s_open;
dev->close = s_close;
dev->route = "color:#ff0000;">s_route;
"color:#ff0000;">*device = &dev->common; "color:#3333ff;">// 把此模块信息返回给调用者
return0;
}
经过上述分析,知道了module->methods->open函数具体调用流程了。
然后对ALSA硬件抽象层模块做了初始化的工作。
这里用到一个结构体变量mALSADevice,它在头文件hardware/alsa_sound/AudioHardwareALSA.h中定义的struct alsa_device_t变量。
""style="font-size:24px;">structalsa_device_t {
hw_device_t common;
status_t (*init)(alsa_device_t *, ALSAHandleList &);
status_t (*open)(alsa_handle_t *, uint32_t, int);
status_t (*close)(alsa_handle_t *);
status_t (*route)(alsa_handle_t *, uint32_t, int);
};
此结构体仅仅提供了一些函数调用接口,在这里都有了具体的实现。则mALSADevice->init()将调到s_init()函数中。
""style="font-size:24px;">staticstatus_t s_init(alsa_device_t *module, "color:#ff0000;">ALSAHandleList &list)
{
list.clear();
snd_pcm_uframes_t bufferSize = "color:#ff0000;">_defaultsOut.bufferSize;
for(size_ti = 1; (bufferSize & ~i) != 0; i <<= 1)
bufferSize &= ~i;
_defaultsOut.module = module;
_defaultsOut.bufferSize = bufferSize;
"color:#ff0000;">list.push_back(_defaultsOut);
bufferSize = "color:#ff000