usb audio架构 linux,一篇不错的Android Audio架构代码梳理总结

转载请注明出处: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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值