一篇不错的Android Audio架构代码梳理总结 2014-08-22 14:03:41

分类: LINUX

为android系统添加USB AUDIO设备的放音和录音功能

分类: Android原创2012-11-30 11:53 3422人阅读 评论(14) 收藏 举报
androidAndroidaudioAudioaudioFlingerjavaJavaJAVAjniJNI

目录(?)[+]

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

[cpp] view plaincopyprint?
  1. <span style=< span="" style="word-wrap: break-word;">"font-size:24px;">int main(int argc, char **argv)
  2. {
  3. .....
  4. init_parse_config_file("/<span style="< span="" style="word-wrap: break-word;">color:#ff0000;">init.rc");
  5. .....
  6. }

init.rc文件中保存了许多系统启动时需要启动的服务。其中就有多媒体服务mediaserver的启动:

[plain] view plaincopyprint?
  1. service media /system/bin/mediaserver

此服务在文件frameworks/base/media/mediaserver/main_mediaserver.cpp中定义,而音频子系统的两大本地服务AudioFlinger和AudioPolicyService就是在此启动的。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">int main(int argc, char** argv)
  2. {
  3.   .....
  4. <span style="color:#ff0000;">AudioFlinger::instantiate();  <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">//实例化AudioFlinger
  5. .....
  6. <span style="color:#ff0000;">AudioPolicyService::instantiate(); <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">//实例化AudioPolicyService
  7. .....
  8. }

1.1 AudioFlinger启动流程及其所涉及的HAL层模块启动流程分析。

根据上文分析,将调用AudioFlinger::instantiate()函数实例化AudioFlinger。但是AudioFlinger.cpp中并没有找到此函数,那必然在其父类中。AudioFlinger类有很多父类,一时难以确定instantiate()到底在哪个父类中定义的。直接搜索吧!
grep -rn "instantiate"  frameworks/base/ 
很快找到instantiate()函数的定义处在./frameworks/base/include/binder/BinderService.h头文件中

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">template<typename SERVICE>
  2. class BinderService
  3. {
  4. public:
  5. static status_t publish() {
  6. sp sm(defaultServiceManager());
  7. return sm->addService(String16(<span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">SERVICE::getServiceName()), <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">new SERVICE());
  8. ......
  9. static void instantiate() { publish(); }
  10. .....
  11. }
  12. }

这里用到了模板,需要确定SERVICE是什么东东。
AudioFlinger类是在AudioFlinger.h中定义的,而恰好包含了头文件BinderService.h。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">class AudioFlinger :
  2. public <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">BinderService,
  3. public BnAudioFlinger
  4. {
  5. friend class BinderService;
  6. public:
  7. static char const* getServiceName() { return "media.audio_flinger"; }
  8. .....
  9. }

原来AudioFlinger类继承了BinderService类,同时把自己(AudioFlinger)传递给SERVICE。而addService函数第一个参数调用了AudioFlinger类的静态成员函数getServiceName()获取AudioFlinger的服务名称;其第二个参数便是创建了一个AudioFlinger的实例。至此,明白了实例化函数instantiate()就是要向服务管理器注册的服务是AudioFlinger。
既然此时实例化了AudioFlinger,那么看看AudioFlinger类的构造函数具体做了哪些初始化工作。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">AudioFlinger::AudioFlinger()
  2. : BnAudioFlinger(),
  3. mPrimaryHardwareDev(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1),
  4. mBtNrecIsOff(false)
  5. {
  6. }

此构造函数做了一些无关紧要的事情,不管它。既然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()函数的名字,知晓,应当是加载音频接口的。

[cpp] view plaincopyprint?
  1. <span style=< span="" style="word-wrap: break-word;">"font-size:24px;">static int load_audio_interface(const char *if_name, const hw_module_t **mod,
  2. audio_hw_device_t **dev)
  3. {
  4. ......
  5. rc = <span style="color:#ff0000;">hw_get_module_by_class(<span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">AUDIO_HARDWARE_MODULE_ID, if_name, mod);
  6. if (rc)
  7. goto out;
  8. rc = <span style="color:#ff0000;">audio_hw_device_open(*mod, <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">dev);
  9. .....
  10. }

首先通过函数hw_get_module_by_class获取ID号为AUDIO_HARDWARE_MODULE_ID的音频模块,此ID在头文件hardware/libhardware/include/hardware/audio.h中定义。此头文件中定义了一个十分重要的结构体struct audio_hw_device,其中包含了许多函数接口(函数指针):

[cpp] view plaincopyprint?
  1. <span style=< span="" style="word-wrap: break-word;">"font-size:24px;">struct audio_hw_device {
  2. struct hw_device_t common;
  3. /**
  4. * used by audio flinger to enumerate what devices are supported by
  5. * each audio_hw_device implementation.
  6. *
  7. * Return value is a bitmask of 1 or more values of audio_devices_t
  8. */
  9. uint32_t (*<span style="color:#ff0000;">get_supported_devices)(const struct audio_hw_device *dev);
  10. /**
  11. * check to see if the audio hardware interface has been initialized.
  12. * returns 0 on success, -ENODEV on failure.
  13. */
  14. int (*<span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">init_check)(const struct audio_hw_device *dev);
  15. ......
  16. /* set/get global audio parameters */
  17. int (*<span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">set_parameters)(struct audio_hw_device *dev, const char *kv_pairs);
  18. .....
  19. /** This method creates and opens the audio hardware output stream */
  20. int (*<span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">open_output_stream)(struct audio_hw_device *dev, uint32_t devices,
  21. int *format, uint32_t *channels,
  22. uint32_t *sample_rate,
  23. struct audio_stream_out **out);
  24. ......
  25. /** This method creates and opens the audio hardware input stream */
  26. int (*open_input_stream)(struct audio_hw_device *dev, uint32_t devices,
  27. int *format, uint32_t *channels,
  28. uint32_t *sample_rate,
  29. audio_in_acoustics_t acoustics,
  30. struct audio_stream_in **stream_in);
  31. .....
  32. }

ID为AUDIO_HARDWARE_MODULE_ID的音频模块到底在哪儿定义的那?既然是HAL层模块,必定在hardware目录下定义的

[plain] view plaincopyprint?
  1. $ grep -rn AUDIO_HARDWARE_MODULE_ID hardware/
  2. hardware/libhardware_legacy/audio/audio_hw_hal.cpp:602:id: AUDIO_HARDWARE_MODULE_ID,
  3. hardware/libhardware/modules/audio/audio_hw.c:435:   .id = AUDIO_HARDWARE_MODULE_ID,
  4. hardware/libhardware/include/hardware/audio.h:37:
  5. #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头文件中定义,函数体如下:

[cpp] view plaincopyprint?
  1. <span style=< span="" style="word-wrap: break-word;">"font-size:24px;">/** convenience API for opening and closing a supported device */
  2. static inline int audio_hw_device_open(const struct hw_module_t* module,
  3. struct audio_hw_device** device)
  4. {
  5. return module->methods->open(module, AUDIO_HARDWARE_INTERFACE,
  6. (struct hw_device_t**)device);
  7. }

struct hw_module_t是在hardware/libhardware/include/hardware/hardware.h头文件中定义的,其中嵌套了struct hw_module_methods_t。此结构体很简单,只有一个函数指针open

[cpp] view plaincopyprint?
  1. <span style=< span="" style="word-wrap: break-word;">"font-size:24px;">typedef struct hw_module_methods_t {
  2. /** Open a specific device */
  3. int (*open)(const struct hw_module_t* module, const char* id,
  4. struct hw_device_t** device);
  5. } hw_module_methods_t;

在确定具体模块后,很容易确定open函数指针的具体实现

[cpp] view plaincopyprint?
  1. <span style=< span="" style="word-wrap: break-word;">"font-size:24px;">struct legacy_audio_module HAL_MODULE_INFO_SYM = {
  2. module: {
  3. common: {
  4. tag: HARDWARE_MODULE_TAG,
  5. version_major: 1,
  6. version_minor: 0,
  7. id: AUDIO_HARDWARE_MODULE_ID,
  8. name: "LEGACY Audio HW HAL",
  9. author: "The Android Open Source Project",
  10. methods: &<span style="color:#ff0000;">legacy_audio_module_methods,
  11. dso : NULL,
  12. reserved : {0},
  13. },
  14. },
  15. };
[cpp] view plaincopyprint?
  1. <span style=< span="" style="word-wrap: break-word;">"font-size:24px;">static struct hw_module_methods_t legacy_audio_module_methods = {
  2. open: <span style="color:#ff0000;">legacy_adev_open
  3. };

open()的实现就是legacy_adev_open()函数了!

[cpp] view plaincopyprint?
  1. <span style=< span="" style="word-wrap: break-word;">"font-size:24px;">static int legacy_adev_open(const hw_module_t* module, const char* name,
  2. hw_device_t** device)
  3. {
  4. struct legacy_audio_device *ladev;
  5. int ret;
  6. if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)  // 看来对应宏AUDIO_HARDWARE_INTERFACE,除了用来判断希望打开的是否音频硬件接口外,并没有做什么更多的事情
  7. return -EINVAL;
  8. .....
  9. ladev->device.get_supported_devices = adev_get_supported_devices;
  10. ladev->device.init_check = <span style="color:#ff0000;">adev_init_check;
  11. .....
  12. ladev->device.open_output_stream = <span style="color:#ff0000;">adev_open_output_stream;
  13. ladev->device.close_output_stream = adev_close_output_stream;
  14. ladev->device.open_input_stream = adev_open_input_stream;
  15. ladev->device.close_input_stream = adev_close_input_stream;
  16. .....
  17. ladev->hwif = <span style="color:#ff0000;">createAudioHardware();
  18. .....
  19. <span style="color:#ff0000;">*device = &ladev->device.common;  <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">// 将当前设备信息层层返回给回调函数,最后返回到
  20. // load_audio_interface()函数,并保存在
  21. // mAudioHwDevs模板变量中,供AudioFlinger类使用。
  22. return 0;
  23. }

这里主要做了一些初始化工作,即给函数指针提供具体实现函数;但createAudioHardware()应该做了更多的事情。
先从函数createAudioHardware()的返回值入手。struct legacy_audio_device的定义如下:

[cpp] view plaincopyprint?
  1. <span style=< span="" style="word-wrap: break-word;">"font-size:24px;">struct legacy_audio_device {
  2. struct audio_hw_device device;
  3. struct AudioHardwareInterface *hwif;
  4. };

原来createAudioHardware()的返回值是一个硬件设备接口AudioHardwareInterface。
类AudioHardwareInterface正好在audio_hw_hal.cpp文件中所包含的头文件hardware_legacy/AudioHardwareInterface.h中定义的虚类(结构体能调到类,还是头一遭见到,虽然结构体和类长得很象)。那么我很想知道createAudioHardware()具体做了哪些事情。
首先需要确定函数createAudioHardware()的定义在哪儿?有几处定义?调用的具体是哪一个?
AudioHardwareInterface.h头文件中对createAudioHardware函数的声明,没有包含在任何类中,而仅仅包含在名字空间android_audio_legacy中,这和audio_hw_hal.cpp同在一个名字空间中。

[cpp] view plaincopyprint?
  1. <span style=< span="" style="word-wrap: break-word;">"font-size:24px;">namespace android_audio_legacy {
  2. .....
  3. extern "C" AudioHardwareInterface* createAudioHardware(void);
  4. }; // namespace android

经搜索,发现createAudioHardware()函数有四处定义。

[cpp] view plaincopyprint?
  1. <span style=< span="" style="word-wrap: break-word;">"font-size:24px;">$ grep -rn createAudioHardware hardware/ --exclude-dir=.svn
  2. hardware/alsa_sound/AudioHardwareALSA.cpp:45:
  3. android_audio_legacy::AudioHardwareInterface *createAudioHardware(void) {
  4. hardware/msm7k/libaudio-qsd8k/AudioHardware.cpp:2021:
  5. extern "C" AudioHardwareInterface* createAudioHardware(void) {
  6. hardware/msm7k/libaudio-qdsp5v2/AudioHardware.cpp:337:
  7. extern "C" AudioHardwareInterface* createAudioHardware(void) {
  8. hardware/msm7k/libaudio/AudioHardware.cpp:1132:
  9. extern "C" AudioHardwareInterface* createAudioHardware(void) {

只有AudioHardwareALSA.cpp文件中包含了头文件hardware_legacy/AudioHardwareInterface.h,并且返回值是android_audio_legacy名字空间的AudioHardwareInterface类对象。则createAudioHardware函数的具体实现很可能是它了,通过log信息证明了这一点。

进入AudioHardwareALSA.cpp,不难看出,此函数,最后会通过执行代码如下代码创建AudioHardwareALSA类对象。

[cpp] view plaincopyprint?
  1. "font-size:24px;">return new AudioHardwareALSA();

AudioHardwareALSA类的构造函数如下:

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">AudioHardwareALSA::AudioHardwareALSA() :
  2. mALSADevice(0),
  3. mAcousticDevice(0)
  4. {
  5. ......
  6. int err = <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">hw_get_module(<span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">ALSA_HARDWARE_MODULE_ID,
  7. (hw_module_t const**)<span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">&module);
  8. if (err == 0) {
  9. hw_device_t* device;
  10. err = <span style="color:#ff0000;">module->methods->open(module, <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">ALSA_HARDWARE_NAME, &device);
  11. if (err == 0) {
  12. mALSADevice = (alsa_device_t *)device;
  13. <span style="color:#ff0000;">mALSADevice->init(<span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">mALSADevice, <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">mDeviceList);
  14. .....
  15. err = hw_get_module(ACOUSTICS_HARDWARE_MODULE_ID,
  16. (hw_module_t const**)&module);
  17. if (err == 0) {
  18. hw_device_t* device;
  19. err = module->methods->open(module, ACOUSTICS_HARDWARE_NAME, &device);
  20. .....
  21. }

宏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中。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">$ grep -rn ALSA_HARDWARE_MODULE_ID hardware/ --exclude-dir=.svn
  2. hardware/alsa_sound/AudioHardwareALSA.h:39:#define ALSA_HARDWARE_MODULE_ID "alsa"
  3. hardware/alsa_sound/alsa_default.cpp:59:
  4. id              : ALSA_HARDWARE_MODULE_ID,
  5. hardware/alsa_sound/AudioHardwareALSA.cpp:150:
  6. int err = hw_get_module(ALSA_HARDWARE_MODULE_ID,

则很快找到此模块的具体内容如下:

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">extern "C" const hw_module_t HAL_MODULE_INFO_SYM = {
  2. tag             : HARDWARE_MODULE_TAG,
  3. version_major   : 1,
  4. version_minor   : 0,
  5. id              : ALSA_HARDWARE_MODULE_ID,
  6. name            : "ALSA module",
  7. author          : "Wind River",
  8. methods         : &<span style="color:#ff0000;">s_module_methods,
  9. dso             : 0,
  10. reserved        : { 0, },
  11. };

s_module_methods函数的实现如下:

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">static hw_module_methods_t s_module_methods = {
  2. open            : s_device_open
  3. };

s_device_open函数的实现如下:

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">static int s_device_open(const hw_module_t* module, const char* name,  <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">//有些困惑,
  2. // 此open函数实现中并没有对调用者传递下来的name(ALSA_HARDWARE_NAME)作如何处理。
  3. hw_device_t** device) <span style="color:#3333ff;"><span style=< span="" style="word-wrap: break-word;">"background-color: rgb(255, 255, 255);">//device存储返回的模块信息
  4. {
  5. alsa_device_t *dev;
  6. dev = (alsa_device_t *) malloc(sizeof(*dev));
  7. if (!dev) return -ENOMEM;
  8. memset(dev, 0, sizeof(*dev));
  9. /* initialize the procs */
  10. dev->common.tag = HARDWARE_DEVICE_TAG;
  11. dev->common.version = 0;
  12. dev->common.module = (hw_module_t *) module;
  13. dev->common.close = s_device_close;
  14. dev->init = <span style="color:#ff0000;">s_init;
  15. dev->open = <span style="color:#ff0000;">s_open;
  16. dev->close = s_close;
  17. dev->route = <span style="color:#ff0000;">s_route;
  18. <span style="color:#ff0000;">*device = &dev->common; <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">// 把此模块信息返回给调用者
  19. return 0;
  20. }

经过上述分析,知道了module->methods->open函数具体调用流程了。

然后对ALSA硬件抽象层模块做了初始化的工作。
这里用到一个结构体变量mALSADevice,它在头文件hardware/alsa_sound/AudioHardwareALSA.h中定义的struct alsa_device_t变量。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">struct alsa_device_t {
  2. hw_device_t common;
  3. status_t (*init)(alsa_device_t *, ALSAHandleList &);
  4. status_t (*open)(alsa_handle_t *, uint32_t, int);
  5. status_t (*close)(alsa_handle_t *);
  6. status_t (*route)(alsa_handle_t *, uint32_t, int);
  7. };

此结构体仅仅提供了一些函数调用接口,在这里都有了具体的实现。则mALSADevice->init()将调到s_init()函数中。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">static status_t s_init(alsa_device_t *module, <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">ALSAHandleList &list)
  2. {
  3. list.clear();
  4. snd_pcm_uframes_t bufferSize = <span style="color:#ff0000;">_defaultsOut.bufferSize;
  5. for (size_t i = 1; (bufferSize & ~i) != 0; i <<= 1)
  6. bufferSize &= ~i;
  7. _defaultsOut.module = module;
  8. _defaultsOut.bufferSize = bufferSize;
  9. <span style="color:#ff0000;">list.push_back(_defaultsOut);
  10. bufferSize = <span style="color:#ff0000;">_defaultsIn.bufferSize;
  11. .....
  12. <span style="color:#ff0000;">list.push_back(_defaultsIn);
  13. .....
  14. }

这里会把_defaultsOut和_defaultsIn东东保存在ALSA句柄列表ALSAHandleList中。
首先需要明确_defaultsOut和_defaultsIn具体是什么东东。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">static alsa_handle_t _defaultsOut = {
  2. module      : 0,
  3. devices     : android_audio_legacy::AudioSystem::DEVICE_OUT_ALL,  <span style="color:#3333ff;">// 支持的所有
  4. // 输出音频设备
  5. curDev      : 0,
  6. curMode     : 0,
  7. handle      : 0,  <span style="color:#3333ff;">// PCM节点
  8. format      : SND_PCM_FORMAT_S16_LE, // AudioSystem::PCM_16_BIT
  9. channels    : 2,
  10. sampleRate  : DEFAULT_SAMPLE_RATE,
  11. latency     : 200000, // Desired Delay in usec
  12. bufferSize  : DEFAULT_SAMPLE_RATE / 5, // Desired Number of samples
  13. modPrivate  : 0,
  14. };
  15. static alsa_handle_t _defaultsIn = {
  16. module      : 0,
  17. devices     : android_audio_legacy::AudioSystem::DEVICE_IN_ALL, <span style="color:#3333ff;">// 支持的所有
  18. // 输入音频设备
  19. curDev      : 0,
  20. curMode     : 0,
  21. handle      : 0, <span style="color:#3333ff;">// PCM节点
  22. format      : SND_PCM_FORMAT_S16_LE, // AudioSystem::PCM_16_BIT
  23. channels    : 2, <span style="color:#3333ff;">// 声道数: 1表示单声道,2表示立体声。如果与实际使用的USB AUDIO设备参数
  24. // 的不一致,将导致USB AUDIO设备不能使用。
  25. sampleRate  : DEFAULT_SAMPLE_RATE, <span style="color:#3333ff;">// 采样率,如果与实际使用的USB AUDIO设备参数
  26. // 的不一致,将导致声音失真
  27. <span style="color:#000000;">latency     : 250000, // Desired Delay in usec
  28. bufferSize  : 2048, // Desired Number of samples
  29. modPrivate  : 0,
  30. };

那ALSAHandleList又是什么东东?
ALSAHandleList在头文件hardware/alsa_sound/AudioHardwareALSA.h中定义的List模板变量。
typedef List ALSAHandleList;
原来就是struct asla_handle_t的一个列表而已,而_defaultsOut和_defaultsIn正是这样的结构体变量。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">struct alsa_handle_t {
  2. alsa_device_t *     module;
  3. uint32_t            devices;
  4. uint32_t            curDev;
  5. int                 curMode;
  6. snd_pcm_t *         handle;  <span style="color:#3333ff;">// PCM节点
  7. snd_pcm_format_t    format;
  8. <span style="color:#ff0000;">    uint32_t            channels;
  9. uint32_t            sampleRate;
  10. unsigned int        latency;         // Delay in usec
  11. unsigned int        bufferSize;      // Size of sample buffer
  12. void *              modPrivate;
  13. };

ALSA硬件抽象层正是这样获得了输出音频通道和输入音频通道的相关初始化硬件参数,以后在使用中并不试图改变这些硬件参数(针对真能手机和平板来说,也却是不需要改变)。因此,在扩展android系统功能,为其添加对USB AUDIO设备的支持时,就不得不考虑时事改变channels和sampleRate这两个硬件参数的值。

至此,AudioFlinger服务首次启动过程分析完毕!

1.2 AudioPolicyService启动流程及其所涉及的HAL层模块启动流程分析。

AudioPolicyService服务的启动流程类似于AudioFlinger服务的启动过程,将简要分析。
先看下AudioPolicyService类的定义(AudioPolicyService.h)(提供此类的定义,主要是为下面instantiate()函数服务的):

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">class AudioPolicyService :
  2. public <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">BinderService, <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">// 继承了BinderService类,
  3. // 并把自己(AudioPolicyService)传递给
  4. // BinderService。
  5. public BnAudioPolicyService,
  6. //    public AudioPolicyClientInterface,
  7. public IBinder::DeathRecipient
  8. {
  9. friend class BinderService;
  10. public:
  11. // for BinderService
  12. static const char *<span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">getServiceName() { return "media.audio_policy"; }
  13. .....
  14. }

根据前面的分析,晓得将通过调用如下代码启动AudioPolicyService服务。

[cpp] view plaincopyprint?
  1. "http://www.w3.org/1999/xhtml" style="font-size:24px;">AudioPolicyService::instantiate();

此代码最后将调到AudioPolicyService类的构造函数

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">AudioPolicyService::AudioPolicyService()
  2. : BnAudioPolicyService() , mpAudioPolicyDev(NULL) , mpAudioPolicy(NULL)
  3. {
  4. char value[PROPERTY_VALUE_MAX];
  5. const struct hw_module_t *module;
  6. int forced_val;
  7. int rc;
  8. Mutex::Autolock _l(mLock);
  9. // start tone playback thread
  10. mTonePlaybackThread = new AudioCommandThread(String8(""));
  11. // start audio commands thread
  12. mAudioCommandThread = new <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">AudioCommandThread(String8("ApmCommandThread"));
  13. /* instantiate the audio policy manager */
  14. rc = <span style="color:#ff0000;">hw_get_module(<span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">AUDIO_POLICY_HARDWARE_MODULE_ID, &module);
  15. if (rc)
  16. return;
  17. rc = <span style="color:#ff0000;">audio_policy_dev_open(module, <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">&mpAudioPolicyDev);
  18. LOGE_IF(rc, "couldn't open audio policy device (%s)", strerror(-rc));
  19. if (rc)
  20. return;
  21. rc = <span style="color:#ff0000;">mpAudioPolicyDev->create_audio_policy(mpAudioPolicyDev, <strong style=< span="" style="word-wrap: break-word;">"background-color: rgb(192, 192, 192);"><span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">&aps_ops, this,
  22. <span style="color:#ff0000;">&mpAudioPolicy);
  23. LOGE_IF(rc, "couldn't create audio policy (%s)", strerror(-rc));
  24. if (rc)
  25. return;
  26. rc = <span style="color:#ff0000;">mpAudioPolicy->init_check(mpAudioPolicy);
  27. .....
  28. }

(1)首先开启了放音线程和音频命令线程。这些工作都是通过创建AudioCommandThread线程类对象完成。

AudioCommandThread类在头文件frameworks/base/services/audioflinger/AudioPolicyService.h中定义

[cpp] view plaincopyprint?
  1. "http://www.w3.org/1999/xhtml" style="font-size:24px;">class AudioCommandThread : public Thread {

是AudioPolicyService类的私有子类。

AudioCommandThread线程类创建了对象后,将进入死循环中,等待要处理的事件传来。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">bool AudioPolicyService::AudioCommandThread::threadLoop()
  2. {
  3. nsecs_t waitTime = INT64_MAX;
  4. mLock.lock();
  5. while (!exitPending())
  6. {
  7. while(!mAudioCommands.isEmpty()) {
  8. .....
  9. switch (command->mCommand) {
  10. .....
  11. <span style="color:#ff0000;">case SET_PARAMETERS: {
  12. ParametersData *data = (ParametersData *)command->mParam;
  13. LOGV("AudioCommandThread() processing set parameters string %s, io %d",
  14. data->mKeyValuePairs.string(), data->mIO);
  15. command->mStatus = <span style="color:#ff0000;">AudioSystem::setParameters(data->mIO, data->mKeyValuePairs);
  16. if (command->mWaitStatus) {
  17. command->mCond.signal();
  18. mWaitWorkCV.wait(mLock);
  19. }
  20. delete data;
  21. }break;
  22. .....
  23. }

这里只列出了switch语句中的一种情况的处理代码,因为后面分析setDeviceConnectionState()函数的调用流程时将用到。
当command->mCommand值为SET_PARAMETERS时,将调用libmedia库(frameworks/base/media/libmedia/AudioSystem.cpp)中的函数setParameters()做进一步处理。

(2)然后调用函数hw_get_module()获得ID号为AUDIO_POLICY_HARDWARE_MODULE_ID的硬件抽象层的音频策略模块。宏AUDIO_POLICY_HARDWARE_MODULE_ID在头文件hardware/libhardware/include/hardware/audio_policy.h中定义。

ID号为AUDIO_POLICY_HARDWARE_MODULE_ID的模块也有两处具体实现,同样通过log信息,确认调用的是libhardware_legacy模块中的AUDIO_POLICY_HARDWARE_MODULE_ID子模块的具体实现。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">$ grep -rn AUDIO_POLICY_HARDWARE_MODULE_ID hardware/ --exclude-dir=.svn
  2. hardware/libhardware_legacy/audio/audio_policy_hal.cpp:414:
  3. id: AUDIO_POLICY_HARDWARE_MODULE_ID,
  4. hardware/libhardware/modules/audio/audio_policy.c:318:
  5. .id             = AUDIO_POLICY_HARDWARE_MODULE_ID,

audio_policy_hal.cpp文件中定义的AUDIO_POLICY_HARDWARE_MODULE_ID模块如下:

struct legacy_ap_module HAL_MODULE_INFO_SYM = {
    module: {
        common: {
            tag: HARDWARE_MODULE_TAG,
            version_major: 1,
            version_minor: 0,
            id: AUDIO_POLICY_HARDWARE_MODULE_ID,
            name: "LEGACY Audio Policy HAL",
            author: "The Android Open Source Project",
            methods: &legacy_ap_module_methods,
            dso : NULL,
            reserved : {0},
        },
    },
};

(3)再然后调用audio_policy_dev_open()函数(在头文件hardware/libhardware/include/hardware/audio_policy.h中定义)。

首先分析函数参数:第一个参数就是上面获取的模块,第二个参数mpAudioPolicyDev是struct audio_policy_device 指针变量,在头文件AudioPolicyService.h中定义。而struct audio_policy_device是在头文件audio_policy.h中定义的。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">struct audio_policy_device {
  2. struct hw_device_t common;
  3. int (*create_audio_policy)(const struct audio_policy_device *device,
  4. struct audio_policy_service_ops <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;background-color: rgb(153, 153, 153);">*aps_ops,
  5. void *service,
  6. struct audio_policy **ap);
  7. .....
  8. }

最后看下audio_policy_dev_open()函数的实现

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;"><span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">/** convenience API for opening and closing a supported device */
  2. static inline int audio_policy_dev_open(const hw_module_t* module,
  3. struct audio_policy_device** device)
  4. {
  5. return module->methods->open(module, AUDIO_POLICY_INTERFACE,
  6. (hw_device_t**)device);
  7. }

由上述分析可知,open函数指针就指向legacy_ap_dev_open()函数。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style=""><span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">static int legacy_ap_dev_open(const hw_module_t* module, const char* name,
  2. hw_device_t** device) <span style="color:#3333ff;">// 参数device保存返回的模块信息
  3. {
  4. struct legacy_ap_device *dev;
  5. if (strcmp(name, AUDIO_POLICY_INTERFACE) != 0)<span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">// 参数name(AUDIO_POLICY_INTERFACE)
  6. // 就这点用处
  7. return -EINVAL;
  8. dev = (struct legacy_ap_device *)calloc(1, sizeof(*dev));
  9. if (!dev)
  10. return -ENOMEM;
  11. dev->device.common.tag = HARDWARE_DEVICE_TAG;
  12. dev->device.common.version = 0;
  13. dev->device.common.module = const_cast(module);
  14. dev->device.common.close = legacy_ap_dev_close;
  15. dev->device.create_audio_policy = <span style="color:#ff0000;">create_legacy_ap;
  16. dev->device.destroy_audio_policy = destroy_legacy_ap;
  17. <span style="color:#ff0000;">*device = &dev->device.common; <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">// 将当前模块具体信息赋值给device,并回馈给调用者
  18. return 0;
  19. }

(4)再接下来调用的mpAudioPolicyDev->create_audio_policy()函数指针具体就是create_legacy_ap()。
第二个参数&aps_ops是struct audio_policy_service_ops变量,是APS(AudioPolicyService)的操作接口,并且传递的是aps_ops的地址,则被调用者使用的将是在APS中函数接口的实现。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style=""><span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">namespace {
  2. struct audio_policy_service_ops aps_ops = {
  3. <span style="color:#ff0000;">open_output           : aps_open_output,
  4. open_duplicate_output : aps_open_dup_output,
  5. close_output          : aps_close_output,
  6. suspend_output        : aps_suspend_output,
  7. restore_output        : aps_restore_output,
  8. open_input            : aps_open_input,
  9. close_input           : aps_close_input,
  10. set_stream_volume     : aps_set_stream_volume,
  11. set_stream_output     : aps_set_stream_output,
  12. <span style="color:#ff0000;">set_parameters        : aps_set_parameters,
  13. get_parameters        : aps_get_parameters,
  14. start_tone            : aps_start_tone,
  15. stop_tone             : aps_stop_tone,
  16. set_voice_volume      : aps_set_voice_volume,
  17. move_effects          : aps_move_effects,
  18. };
  19. }; // namespace

struct audio_policy_service_ops在头文件hardware/libhardware/include/hardware/audio_policy.h中定义,是包含音频相关控制函数的接口。可见aps_ops接口将为HAL层提供服务。

第四个参数是&mpAudioPolicy。mpAudioPolicy是struct audio_policy的指针变量(AudioPolicyService.h)。而struct audio_policy也是在audio_policy.h中定义,将要用到的接口如下:

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style=""><span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">struct audio_policy {
  2. /*
  3. * configuration functions
  4. */
  5. /* indicate a change in device connection status */
  6. int (*set_device_connection_state)(struct audio_policy *pol,
  7. audio_devices_t device,
  8. audio_policy_dev_state_t state,
  9. const char *device_address);
  10. .....
  11. /* check proper initialization */
  12. int (*init_check)(const struct audio_policy *pol);
  13. .....
  14. }

接下来看看create_audio_policy()函数指针的具体实现:

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style=""><span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">static int create_legacy_ap(const struct audio_policy_device *device,
  2. struct audio_policy_service_ops *aps_ops,
  3. void *service,
  4. struct audio_policy **ap)
  5. {
  6. struct legacy_audio_policy *lap;
  7. int ret;
  8. if (!service || !aps_ops)
  9. return -EINVAL;
  10. lap = (struct legacy_audio_policy *)calloc(1, sizeof(*lap));
  11. if (!lap)
  12. return -ENOMEM;
  13. lap->policy.set_device_connection_state = <span style="color:#ff0000;">ap_set_device_connection_state;
  14. ......
  15. lap->policy.init_check = ap_init_check;
  16. lap->policy.get_output = ap_get_output;
  17. lap->policy.start_output = ap_start_output;
  18. lap->policy.stop_output = ap_stop_output;
  19. lap->policy.release_output = ap_release_output;
  20. lap->policy.get_input = ap_get_input;
  21. lap->policy.start_input = <span style="color:#ff0000;">ap_start_input;
  22. lap->policy.stop_input = ap_stop_input;
  23. lap->policy.release_input = ap_release_input;
  24. .....
  25. <span style="color:#ff0000;">
  26. lap->service = service; <span style="color:#3333ff;">// APS
  27. lap->aps_ops = aps_ops; <span style="color:#3333ff;">// 在APS中实现
  28. lap->service_client =
  29. new AudioPolicyCompatClient(aps_ops, service);
  30. if (!lap->service_client) {
  31. ret = -ENOMEM;
  32. goto err_new_compat_client;
  33. }
  34. <span style="color:#ff0000;">
  35. lap->apm = createAudioPolicyManager(lap->service_client);
  36. ......
  37. <span style="color:#ff0000;">*ap = &lap->policy; <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">// 将当前音频策略的配置的地址赋值给*ap,并返回给mpAudioPolicy
  38. ......
  39. }

此函数中创建了重要对象:AudioPolicyCompatClient类对象和createAudioPolicyManager函数创建音频策略管理器,需要分析下。

先分析AudioPolicyCompatClient类对象的创建。此类在头文件hardware/libhardware_legacy/audio/AudioPolicyCompatClient.h中定义。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style=""><span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">namespace android_audio_legacy {
  2. class AudioPolicyCompatClient : public AudioPolicyClientInterface {
  3. <span style="color:#3333ff;">// 父类是AudioPolicyClientInterface,与下文中提到的
  4. // AudioPolicyManagerBase::
  5. // AudioPolicyManagerBase(AudioPolicyClientInterface *clientInterface)类型一致
  6. public:
  7. AudioPolicyCompatClient(struct audio_policy_service_ops *serviceOps,
  8. void *service) :
  9. <span style="color:#ff0000;">mServiceOps(serviceOps) , mService(service) {} <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">// serviceOps = aps_ops,
  10. // service = this(APS)
  11. ......
  12. private:
  13. struct audio_policy_service_ops* mServiceOps;
  14. void*                            mService;
  15. ......
  16. }

此构造函数主要初始化两个私有化变量mServiceOps和mService,并把创建的对象作为函数createAudioPolicyManager的唯一参数,来创建音频策略管理器。
然而,函数createAudioPolicyManager有多个定义,搜索结果如下:

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style=""><span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">$ grep -rn createAudioPolicyManager hardware/ --exclude-dir=.svn
  2. hardware/alsa_sound/AudioPolicyManagerALSA.cpp:31:
  3. extern "C" android_audio_legacy::AudioPolicyInterface*
  4. createAudioPolicyManager(
  5. android_audio_legacy::AudioPolicyClientInterface *clientInterface)
  6. hardware/libhardware_legacy/audio/AudioPolicyManagerDefault.cpp:24:
  7. extern "C" AudioPolicyInterface*
  8. createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
  9. hardware/msm7k/libaudio-qsd8k/AudioPolicyManager.cpp:39:
  10. extern "C" AudioPolicyInterface*
  11. createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
  12. hardware/msm7k/libaudio-qdsp5v2/AudioPolicyManager.cpp:39:
  13. extern "C" AudioPolicyInterface*
  14. createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
  15. hardware/msm7k/libaudio/AudioPolicyManager.cpp:35:
  16. extern "C" AudioPolicyInterface*
  17. createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)

函数createAudioPolicyManager虽然有多个定义,但是它们最后将创建AudioPolicyManagerBase类对象,以AudioPolicyManagerALSA类为例分析

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style=""><span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">AudioPolicyManagerALSA::AudioPolicyManagerALSA(
  2. android_audio_legacy::AudioPolicyClientInterface *<span style="color:#ff0000;">clientInterface)
  3. : AudioPolicyManagerBase(<span style="color:#ff0000;">clientInterface) <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">// clientInterface正是
  4. // AudioPolicyCompatClient类对象,而AudioPolicyCompatClient类具体实现了
  5. // AudioPolicyClientInterface类的需函数接口
  6. {
  7. }
  8. AudioPolicyManagerBase::AudioPolicyManagerBase(
  9. AudioPolicyClientInterface *clientInterface)
  10. :
  11. #ifdef AUDIO_POLICY_TEST
  12. Thread(false),
  13. #endif //AUDIO_POLICY_TEST
  14. mPhoneState(AudioSystem::MODE_NORMAL), mRingerMode(0),
  15. mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
  16. mTotalEffectsCpuLoad(0), mTotalEffectsMemory(0),
  17. mA2dpSuspended(false)
  18. {
  19. <span style="color:#ff0000;">mpClientInterface = clientInterface;   <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">// mpClientInterface:将用它回调到APS
  20. for (int i = 0; i < AudioSystem::NUM_FORCE_USE; i++) {
  21. mForceUse[i] = AudioSystem::FORCE_NONE;
  22. }
  23. initializeVolumeCurves();
  24. // devices available by default are speaker, ear piece and microphone
  25. mAvailableOutputDevices = AudioSystem::DEVICE_OUT_EARPIECE |
  26. AudioSystem::DEVICE_OUT_SPEAKER;          <span style="color:#3333ff;">// 可用的输出音频设备
  27. mAvailableInputDevices = AudioSystem::DEVICE_IN_BUILTIN_MIC;  <span style="color:#3333ff;">// 可用的输入音频设备
  28. ......
  29. <span style="color:#ff0000;">mHardwareOutput = <span style=< span="" style="word-wrap: break-word;">"color:#cc0000;">mpClientInterface->openOutput(&outputDesc->mDevice,
  30. &outputDesc->mSamplingRate,
  31. &outputDesc->mFormat,
  32. &outputDesc->mChannels,
  33. &outputDesc->mLatency,
  34. outputDesc->mFlags);
  35. ......
  36. <span style="color:#ff0000;">setOutputDevice(mHardwareOutput, (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER,
  37. true);
  38. ......
  39. }

mpClientInterface->openOutput()函数先回掉到AudioPolicyCompatClient类的openOutput()函数。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style=""><span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">audio_io_handle_t AudioPolicyCompatClient::openOutput(uint32_t *pDevices,
  2. uint32_t *pSamplingRate,
  3. uint32_t *pFormat,
  4. uint32_t *pChannels,
  5. uint32_t *pLatencyMs,
  6. AudioSystem::output_flags flags)
  7. {
  8. return <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">mServiceOps->open_output(mService, pDevices, pSamplingRate, pFormat,
  9. pChannels, pLatencyMs,
  10. (audio_policy_output_flags_t)flags);
  11. }

由前面分析可知,在创建AudioPolicyCompatClient类对象时,mServiceOps被初始化为APS的struct audio_policy_service_ops变量aps_ops;则将回调到ops中的open_output()函数,具体调到aps_open_output()函数:

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">static audio_io_handle_t aps_open_output(void *service,
  2. uint32_t *pDevices,
  3. uint32_t *pSamplingRate,
  4. uint32_t *pFormat,
  5. uint32_t *pChannels,
  6. uint32_t *pLatencyMs,
  7. audio_policy_output_flags_t flags)
  8. {
  9. sp af = AudioSystem::get_audio_flinger();
  10. if (af == NULL) {
  11. LOGW("%s: could not get AudioFlinger", __func__);
  12. return 0;
  13. }
  14. return <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">af->openOutput(pDevices, pSamplingRate, pFormat, pChannels,
  15. pLatencyMs, flags);
  16. }

不难看出,将调到AudioFlinger的openOutput()函数。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">int AudioFlinger::openOutput(uint32_t *pDevices,
  2. uint32_t *pSamplingRate,
  3. uint32_t *pFormat,
  4. uint32_t *pChannels,
  5. uint32_t *pLatencyMs,
  6. uint32_t flags)
  7. {
  8. ......
  9. audio_hw_device_t *outHwDev;
  10. ......
  11. outHwDev = findSuitableHwDev_l(*pDevices);
  12. if (outHwDev == NULL)
  13. return 0;
  14. status = <span style="color:#ff0000;">outHwDev->open_output_stream(outHwDev, *pDevices, (int *)&format,
  15. &channels, &samplingRate, &outStream);
  16. ......
  17. return 0;
  18. }

struct audio_hw_device_t是在头文件hardware/libhardware/include/hardware/audio.h中定义的一个结构体。

[cpp] view plaincopyprint?
  1. "http://www.w3.org/1999/xhtml" style="font-size:24px;">typedef struct audio_hw_device audio_hw_device_t;

前面在分析AudioFlinger类的load_audio_interface函数时,已经分析过struct audio_hw_device。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">audio_hw_device_t* AudioFlinger::findSuitableHwDev_l(uint32_t devices)
  2. {
  3. /* first matching HW device is returned */
  4. for (size_t i = 0; i < mAudioHwDevs.size(); i++) {  // 前文分析过,mAudioHwDevs变量保存了HAL层可用音频设备
  5. audio_hw_device_t *dev = <span style="color:#ff0000;">mAudioHwDevs[i];
  6. if ((<span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">dev->get_supported_devices(dev) & devices) == devices)
  7. return dev;
  8. }
  9. return NULL;
  10. }

由前文分析可知,此处的get_supported_devices()函数指针将具体调到audio_hw_hal.cpp文件中的adev_get_supported_devices(),如下所示,这里列出了系统所支持的所有输出/输入音频设备。因此,我们要也要仿照此音频设备的定义名称,在这里添加USB AUDIO音频设备的名称,以及它们在别处的定义。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">static uint32_t adev_get_supported_devices(const struct audio_hw_device *dev)
  2. {
  3. /* XXX: The old AudioHardwareInterface interface is not smart enough to
  4. * tell us this, so we'll lie and basically tell AF that we support the
  5. * below input/output devices and cross our fingers. To do things properly,
  6. * audio hardware interfaces that need advanced features (like this) should
  7. * convert to the new HAL interface and not use this wrapper. */
  8. return (/* OUT */
  9. AUDIO_DEVICE_OUT_EARPIECE |
  10. AUDIO_DEVICE_OUT_SPEAKER |
  11. AUDIO_DEVICE_OUT_WIRED_HEADSET |
  12. AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
  13. AUDIO_DEVICE_OUT_AUX_DIGITAL |
  14. AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET |
  15. AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET |
  16. AUDIO_DEVICE_OUT_ALL_SCO |
  17. AUDIO_DEVICE_OUT_DEFAULT |
  18. /* IN */
  19. AUDIO_DEVICE_IN_COMMUNICATION |
  20. AUDIO_DEVICE_IN_AMBIENT |
  21. AUDIO_DEVICE_IN_BUILTIN_MIC |
  22. AUDIO_DEVICE_IN_WIRED_HEADSET |
  23. AUDIO_DEVICE_IN_AUX_DIGITAL |
  24. AUDIO_DEVICE_IN_BACK_MIC |
  25. AUDIO_DEVICE_IN_ALL_SCO |
  26. AUDIO_DEVICE_IN_DEFAULT);
  27. }

当找到合适的设备之后,将调用outHwDev->open_output_stream()函数打开相应设备的输出流;同样的道理,将具体调到audio_hw_hal.cpp文件中的adev_open_output_stream()函数。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">static int adev_open_output_stream(struct audio_hw_device *dev,
  2. uint32_t devices,
  3. int *format,
  4. uint32_t *channels,
  5. uint32_t *sample_rate,
  6. struct audio_stream_out **stream_out)
  7. {
  8. struct legacy_audio_device *ladev = to_ladev(dev);
  9. status_t status;
  10. struct legacy_stream_out *out;
  11. int ret;
  12. out = (struct legacy_stream_out *)calloc(1, sizeof(*out));
  13. if (!out)
  14. return -ENOMEM;
  15. out->legacy_out = <span style="color:#ff0000;">ladev->hwif->openOutputStream(devices, format, channels,
  16. sample_rate, &status);
  17. ......
  18. }

由前文分析可知,ladev->hwif具体指AudioHardwareALSA类;则ladev->hwif->openOutputStream()函数调到AudioHardwareALSA::openOutputStream()函数。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">android_audio_legacy::AudioStreamOut *
  2. AudioHardwareALSA::openOutputStream(uint32_t devices,
  3. int *format,
  4. uint32_t *channels,
  5. uint32_t *sampleRate,
  6. status_t *status)
  7. {
  8. ......
  9. // Find the appropriate alsa device
  10. for(ALSAHandleList::iterator it = mDeviceList.begin(); <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">// mDeviceList是用来存储
  11. // 输出/输入音频通道信息的
  12. // 句柄的,总共两个句柄,
  13. // 分别对应输出和输入音频通道
  14. it != mDeviceList.end(); ++it)
  15. if (it->devices & devices) {
  16. err = <span style="color:#ff0000;">mALSADevice->open(&(*it), devices, mode()); <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">// 当调用open()函数时,
  17. // 就已经知道要打开的是
  18. // 输入音频通道还是输出
  19. // 音频通道
  20. if (err) break;
  21. out = <span style="color:#ff0000;">new AudioStreamOutALSA(this, &(*it)); <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">// 此类对象的创建本可不必理会,
  22. // 但它的父类ALSAStreamOps类的对象也会随之创建;而ALSAStreamOps
  23. // 类将在后面用到(mParent = this(AudioHardwareALSA))
  24. err = out->set(format, channels, sampleRate);
  25. break;
  26. }
  27. ......
  28. }

由前文对AudioHardwareALSA类的启动流程分析可知,mDeviceList是用来存储输出/输入音频通道信息的句柄的。
mALSADevice表示在初始化ALSA设备时所指向的一个具体ALSA设备的操作接口。则mALSADevice->open()函数,将具体调到ALSA模块的s_open()函数。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">static status_t s_open(alsa_handle_t *handle, uint32_t devices, int mode)
  2. {
  3. // Close off previously opened device.
  4. // It would be nice to determine if the underlying device actually
  5. // changes, but we might be recovering from an error or manipulating
  6. // mixer settings (see asound.conf).
  7. //
  8. s_close(handle); <span style="color:#3333ff;">// 先关闭先前打开的音频通道
  9. LOGD("open called for devices %08x in mode %d...", devices, mode);
  10. const char *stream = <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">streamName(handle);
  11. const char *devName = <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">deviceName(handle, devices, mode);
  12. int err;
  13. for (;;) {
  14. // The PCM stream is opened in blocking mode, per ALSA defaults.  The
  15. // AudioFlinger seems to assume blocking mode too, so asynchronous mode
  16. // should not be used.
  17. err = <span style="color:#ff0000;">snd_pcm_open(<span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">&handle->handle, <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">devName, <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">direction(handle),
  18. <span style="color:#3333ff;">// handle->handle:保存从ALSA-LIB中获得的PCM节点
  19. SND_PCM_ASYNC);
  20. if (err == 0) break;
  21. // See if there is a less specific name we can try.
  22. // Note: We are changing the contents of a const char * here.
  23. char *tail = strrchr(devName, '_');
  24. if (!tail) break;
  25. *tail = 0;
  26. }
  27. if (err < 0) {
  28. // None of the Android defined audio devices exist. Open a generic one.
  29. <span style="color:#ff0000;">devName = "default";
  30. err = <span style="color:#ff0000;">snd_pcm_open(&handle->handle, devName, direction(handle), 0);
  31. }
  32. if (err < 0) {
  33. LOGE("Failed to Initialize any ALSA %s device: %s",
  34. stream, strerror(err));
  35. return NO_INIT;
  36. }
  37. err = <span style="color:#ff0000;">setHardwareParams(handle);
  38. if (err == NO_ERROR) err = setSoftwareParams(handle);
  39. LOGI("Initialized ALSA %s device %s", stream, devName);
  40. handle->curDev = devices;
  41. handle->curMode = mode;
  42. return err;
  43. }

(1) 调用函数streamName()函数获取音频流名称。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">const char *streamName(alsa_handle_t *handle)
  2. {
  3. return snd_pcm_stream_name(direction(handle));
  4. }

snd_pcm_stream_name()函数是ALSA-LIB API,在external/alsa-lib/src/pcm/pcm.c文件中定义。
要想获得音频流名称,不得不先分析direction()函数。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">snd_pcm_stream_t direction(alsa_handle_t *handle)
  2. {
  3. return (handle->devices & android_audio_legacy::AudioSystem::DEVICE_OUT_ALL) ? SND_PCM_STREAM_PLAYBACK
  4. : SND_PCM_STREAM_CAPTURE;
  5. }

原来direction()函数就是用来返回PCM流的方向(放音或者录音)。
direction()函数的返回值将作为snd_pcm_stream_name()的参数,

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">const char *snd_pcm_stream_name(snd_pcm_stream_t stream)
  2. {
  3. if (stream > SND_PCM_STREAM_LAST)
  4. return NULL;
  5. return <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">snd_pcm_stream_names[stream];
  6. }
[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">static const char *const snd_pcm_stream_names[] = {
  2. STREAM(PLAYBACK),
  3. STREAM(CAPTURE),
  4. };

好吧,音频流的名称不是放音就是录音。

(2)接下来调用deviceName()函数获取设备名称。这点很重要,将为我们在asound.conf为新添加的USB AUDIO音频设备命名提供规则。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">const char *deviceName(alsa_handle_t *handle, uint32_t device, int mode)
  2. {
  3. static char <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">devString[ALSA_NAME_MAX];
  4. int hasDevExt = 0;
  5. strcpy(devString, devicePrefix[direction(handle)]);
  6. for (int dev = 0; device && dev < deviceSuffixLen; dev++)
  7. if (device & <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">deviceSuffix[dev].device) {
  8. ALSA_STRCAT (devString, deviceSuffix[dev].suffix);
  9. device &= ~deviceSuffix[dev].device;
  10. <span style="color:#ff0000;">hasDevExt = 1;
  11. }
  12. if (hasDevExt) switch (mode) {
  13. case android_audio_legacy::AudioSystem::MODE_NORMAL:
  14. ALSA_STRCAT (devString, "_normal")
  15. ;
  16. break;
  17. case android_audio_legacy::AudioSystem::MODE_RINGTONE:
  18. ALSA_STRCAT (devString, "_ringtone")
  19. ;
  20. break;
  21. case android_audio_legacy::AudioSystem::MODE_IN_CALL:
  22. ALSA_STRCAT (devString, "_incall")
  23. ;
  24. break;
  25. };
  26. return devString;
  27. }

用字符数组devString存储设备名称。
首先把设备前缀复制给devString。因此,作为输出音频通道设备的名称,必以AndroidPlayback为前缀;作为输入音频通道设备的名称,必以AndroidCapture为前缀。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">static const char *devicePrefix[SND_PCM_STREAM_LAST + 1] = {
  2. /* SND_PCM_STREAM_PLAYBACK : */"AndroidPlayback",
  3. /* SND_PCM_STREAM_CAPTURE  : */"AndroidCapture",
  4. };

接下来从deviceSuffix数组中查找合适的后缀,追加到devString字符数组中。

[cpp] view plaincopyprint?
  1. "http://www.w3.org/1999/xhtml" style="font-size:24px;">/* The following table(s) need to match in order of the route bits
  2. */
  3. static const device_suffix_t deviceSuffix[] = {
  4. {android_audio_legacy::AudioSystem::DEVICE_OUT_EARPIECE,       "_Earpiece"},
  5. {android_audio_legacy::AudioSystem::DEVICE_OUT_SPEAKER,        "_Speaker"},
  6. {android_audio_legacy::AudioSystem::DEVICE_OUT_BLUETOOTH_SCO,  "_Bluetooth"},
  7. {android_audio_legacy::AudioSystem::DEVICE_OUT_WIRED_HEADSET,  "_Headset"},
  8. {android_audio_legacy::AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP, "_Bluetooth-A2DP"},
  9. };

struct device_suffix_t的定义如下:

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">struct device_suffix_t {
  2. const android_audio_legacy::AudioSystem::audio_devices device;
  3. const char *suffix;
  4. };

PS: 我们也要在此数组中添加USB AUDIO音频设备的相关信息。同时也要在定义了类似DEVICE_OUT_EARPIECE设备的类中定义USB AUDIO音频设备:

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;"> 1.frameworks/base/media/java/android/media/AudioSystem.java
  2. 2.frameworks/base/media/java/android/media/AudioManager.java
  3. 3.hardware/libhardware_legacy/include/hardware_legacy/AudioSystemLegacy.h
  4. 4.system/core/include/system/audio.h

题外话:android系统中对音频设备的定义如下(AudioSystem.java):

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style=""> <span style=< span="" style="word-wrap: break-word;">"font-size:24px;">   public static final int DEVICE_OUT_EARPIECE = 0x1; // 0x1 << 0
  2. public static final int DEVICE_OUT_SPEAKER = 0x2;  // 0x1 << 1
  3. public static final int DEVICE_OUT_WIRED_HEADSET = 0x4; // 0x1 << 2
  4. public static final int DEVICE_OUT_WIRED_HEADPHONE = 0x8; // 0x1 << 3
  5. public static final int DEVICE_OUT_BLUETOOTH_SCO = 0x10; // 0x1 << 4
  6. public static final int DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20; // 0x1 << 5
  7. public static final int DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40; // 0x1 << 6
  8. public static final int DEVICE_OUT_BLUETOOTH_A2DP = 0x80; // 0x1 << 7
  9. public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100;
  10. // 0x100 << 0
  11. public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200; // 0x100 << 1
  12. public static final int DEVICE_OUT_AUX_DIGITAL = 0x400; // 0x100 << 2
  13. public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800; // 0x100 << 3
  14. public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000; // 0x1000 << 0
  15. public static final int DEVICE_OUT_DEFAULT = 0x8000; // 0x1000 << 3
  16. // input devices
  17. public static final int DEVICE_IN_COMMUNICATION = 0x10000; // 0x10000 << 0
  18. public static final int DEVICE_IN_AMBIENT = 0x20000; // 0x10000 << 1
  19. public static final int DEVICE_IN_BUILTIN_MIC1 = 0x40000; // 0x10000 << 2
  20. public static final int DEVICE_IN_BUILTIN_MIC2 = 0x80000; // 0x10000 << 3
  21. public static final int DEVICE_IN_MIC_ARRAY = 0x100000; // 0x100000 << 0
  22. public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x200000;
  23. // 0x100000 << 1
  24. public static final int DEVICE_IN_WIRED_HEADSET = 0x400000; // 0x100000 << 2
  25. public static final int DEVICE_IN_AUX_DIGITAL = 0x800000; // 0x100000 << 3

当设备越来越多时,很难保证等号右边的数字中零的个数不写错。采用注释部分的定义方式较好。

当找到了设备后缀后,将对变量hasDevExt赋值为1,表示还会有扩展名称(_normal,_ringtone或者_incall)。

至此,一个设备的PCM节点名称就形成了!

(3)程序将执行到调用snd_pcm_open() ALSA-LIB API,并把刚才得到的设备名称devName作为参数之一,调到ALSA-LIB,进而调到ALSA-DRIVER,去打开所指定的音频设备。如果打开指定的音频设备失败了,将打开默认的音频设备。

(4)如果成功打开音频设备,程序继续往下执行,将调用setHardwareParams()函数设置硬件参数。这些硬件参数包括缓冲区大小,采样率,声道数和音频格式等。其实这些硬件参数都在struct alsa_handle_t中定义,在分析初始化函数s_init()函数时已有分析,在默认音频设备配置_defaultsOut和_defaultsIn中已经指定。

但是,在使用USB AUDIO输入音频设备时,默认的输入音频配置中的声道数和采样率很有可能与实际使用的USB AUDIO的不一致,导致USB AUDIO设备不可用或者音频失真。因此,需要在执行setHardwareParams()函数前,并且知道是要打开输入音频通道时(输出音频通道的硬件参数配置可用),需要检测时间使用的USB AUDIO音频设备的这两个硬件参数,重新对_defaultsIn中声道数和采样率进行赋值。将在后面做详细分析。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">status_t setHardwareParams(alsa_handle_t *handle)
  2. {
  3. ......
  4. unsigned int requestedRate = <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">handle->sampleRate;
  5. ......
  6. <span style="color:#ff0000;">    err = snd_pcm_hw_params_set_channels(handle->handle, hardwareParams,
  7. <span style="color:#ff0000;">handle->channels);
  8. ......
  9. err = <span style="color:#ff0000;">snd_pcm_hw_params_set_rate_near(handle->handle, hardwareParams,
  10. <span style="color:#ff0000;">&requestedRate, 0);
  11. ......
  12. }

(5)最后程序会执行到设置软件参数的函数setHardwareParams()中。在添加USB AUDIO音频设备时,这里没有遇到问题,不再分析。

2. JAVA API setDeviceConnectionState()调用流程详解。

把最复杂的两大本地服务分析完后,后面的任务就很轻了!
JAVA API setDeviceConnectionState()在文件frameworks/base/media/java/android/media/AudioSystem.java中定义。
    public static native int setDeviceConnectionState(int device, int state, String device_address);
第一个参数就是要打开的音频设备的标识符,将一路传递下去,直到ALSA模块(alsa_default.cpp);
第二个参数表示第一个参数所指的音频设备是否可用;
第三个参数表示设备地址,一般为空。

看到java关键字native,晓得将调到对应的JNI(frameworks/base/core/jni/android_media_AudioSystem.cpp)代码。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">static int
  2. android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz,
  3. jint device, jint state, jstring device_address)
  4. {
  5. const char *c_address = env->GetStringUTFChars(device_address, NULL);
  6. int status = check_AudioSystem_Command(
  7. <span style="color:#ff0000;">AudioSystem::setDeviceConnectionState(static_cast (device),
  8. static_cast (state),
  9. c_address));
  10. env->ReleaseStringUTFChars(device_address, c_address);
  11. return status;
  12. }

显然,又调到libmedia库(frameworks/base/media/libmedia/AudioSystem.cpp)中setDeviceConnectionState()函数。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">status_t AudioSystem::setDeviceConnectionState(audio_devices_t device,
  2. audio_policy_dev_state_t state,
  3. const char *device_address)
  4. {
  5. const sp& aps = AudioSystem::get_audio_policy_service();
  6. const char *address = "";
  7. if (aps == 0) return PERMISSION_DENIED;
  8. if (device_address != NULL) {
  9. address = device_address;
  10. }
  11. return <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">aps->setDeviceConnectionState(device, state, address);
  12. }

显然,调到APS的setDeviceConnectionState()函数。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">status_t AudioPolicyService::setDeviceConnectionState(audio_devices_t device,
  2. audio_policy_dev_state_t state,
  3. const char *device_address)
  4. {
  5. ......
  6. return <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">mpAudioPolicy->set_device_connection_state(mpAudioPolicy, device,
  7. state, device_address);
  8. }

根据前面对AudioPolicyService服务的启动流程分析可知,mpAudioPolicy指向在文件audio_policy_hal.cpp中定义的音频策略模块。则mpAudioPolicy->set_device_connection_state()函数具体调到函数ap_set_device_connection_state()函数。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">static int ap_set_device_connection_state(struct audio_policy *pol,
  2. audio_devices_t device,
  3. audio_policy_dev_state_t state,
  4. const char *device_address)
  5. {
  6. struct legacy_audio_policy *lap = to_lap(pol);
  7. return <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">lap->apm->setDeviceConnectionState(
  8. (AudioSystem::audio_devices)device,
  9. (AudioSystem::device_connection_state)state,
  10. device_address);
  11. }

同样,由前面对AudioPolicyService服务的启动流程分析可知,lap->apm指向AudioPolicyManagerBase类对象。则lap->apm->setDeviceConnectionState()函数将调到AudioPolicyManagerBase::setDeviceConnectionState()函数。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size: 24px;"><span style=< span="" style="word-wrap: break-word;">"font-size:18px;">status_t AudioPolicyManagerBase::setDeviceConnectionState(AudioSystem::audio_devices device,
  2. AudioSystem::device_connection_state state,
  3. const char *device_address)
  4. {
  5. ......
  6. // handle output devices
  7. if (AudioSystem::isOutputDevice(device)) {   <span style=< span="" style="word-wrap: break-word;">"font-size:18px;color:#3333ff;">// 如果是输出设备
  8. <span style="font-size:18px;">
  9. ......
  10. switch (state)
  11. {
  12. // handle output device connection
  13. case AudioSystem::DEVICE_STATE_AVAILABLE:
  14. if (mAvailableOutputDevices & device) {
  15. LOGW("setDeviceConnectionState() device already connected: %x", device);
  16. return INVALID_OPERATION;
  17. }
  18. LOGV("setDeviceConnectionState() connecting device %x", device);
  19. // register new device as available
  20. mAvailableOutputDevices |= device;   <span style="color:#3333ff;">// 把当前设备加入到可用设备变量中
  21. .....
  22. // handle output device disconnection
  23. case AudioSystem::DEVICE_STATE_UNAVAILABLE: {
  24. if (!(mAvailableOutputDevices & device)) {
  25. LOGW("setDeviceConnectionState() device not connected: %x", device);
  26. return INVALID_OPERATION;
  27. }
  28. LOGV("setDeviceConnectionState() disconnecting device %x", device);
  29. // remove device from available output devices
  30. mAvailableOutputDevices &= ~device; <span style="color:#3333ff;">// 把当前设备从可用设备变量中去除
  31. ......
  32. }
  33. // request routing change if necessary
  34. uint32_t newDevice = <span style="color:#ff0000;">getNewDevice(mHardwareOutput, false);
  35. ......
  36. <span style="color:#ff0000;">updateDeviceForStrategy();
  37. <span style="font-size:24px;"><strong style=< span="" style="word-wrap: break-word;">"background-color: rgb(153, 153, 153);"><span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">setOutputDevice(mHardwareOutput, newDevice);
  38. <span style="color:#3333ff;">// 如果输出音频设备是USB AUDIO(USB 放音),那么应该知道输入音频设备为SUB MIC
  39. if (device == AudioSystem::DEVICE_OUT_WIRED_HEADSET) {
  40. device = AudioSystem::DEVICE_IN_WIRED_HEADSET;
  41. } else if (device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO ||
  42. device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET ||
  43. device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT) {
  44. device = AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET;
  45. } else {
  46. return NO_ERROR;
  47. }
  48. }
  49. // handle input devices
  50. if (AudioSystem::isInputDevice(device)) { <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">// 如果是输入设备
  51. switch (state)
  52. {
  53. // handle input device connection
  54. case AudioSystem::DEVICE_STATE_AVAILABLE: {
  55. if (mAvailableInputDevices & device) {
  56. LOGW("setDeviceConnectionState() device already connected: %d", device);
  57. return INVALID_OPERATION;
  58. }
  59. mAvailableInputDevices |= device;
  60. }
  61. break;
  62. // handle input device disconnection
  63. case AudioSystem::DEVICE_STATE_UNAVAILABLE: {
  64. if (!(mAvailableInputDevices & device)) {
  65. LOGW("setDeviceConnectionState() device not connected: %d", device);
  66. return INVALID_OPERATION;
  67. }
  68. mAvailableInputDevices &= ~device;
  69. } break;
  70. default:
  71. LOGE("setDeviceConnectionState() invalid state: %x", state);
  72. return BAD_VALUE;
  73. }
  74. audio_io_handle_t activeInput = getActiveInput();
  75. if (activeInput != 0) {
  76. AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput);
  77. uint32_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
  78. if (newDevice != inputDesc->mDevice) {
  79. LOGV("setDeviceConnectionState() changing device from %x to %x for input %d",
  80. inputDesc->mDevice, newDevice, activeInput);
  81. inputDesc->mDevice = newDevice;
  82. AudioParameter param = AudioParameter();
  83. param.addInt(String8(AudioParameter::keyRouting), (int)newDevice);
  84. mpClientInterface->setParameters(activeInput, param.toString());
  85. }
  86. }
  87. return NO_ERROR;
  88. }
  89. LOGW("setDeviceConnectionState() invalid device: %x", device);
  90. return BAD_VALUE;
  91. }

(1) 当前设备是输出设备时,程序执行到getNewDevice()函数,将获得新设备,作为设置输出设备函数setOutputDevice()的第二个参数。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">uint32_t AudioPolicyManagerBase::getNewDevice(audio_io_handle_t output, bool fromCache)
  2. {
  3. uint32_t device = 0;
  4. AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
  5. // check the following by order of priority to request a routing change if necessary:
  6. // 1: the strategy enforced audible is active on the output:
  7. //      use device for strategy enforced audible
  8. // 2: we are in call or the strategy phone is active on the output:
  9. //      use device for strategy phone
  10. // 3: the strategy sonification is active on the output:
  11. //      use device for strategy sonification
  12. // 4: the strategy media is active on the output:
  13. //      use device for strategy media
  14. // 5: the strategy DTMF is active on the output:
  15. //      use device for strategy DTMF
  16. if (outputDesc-><span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">isUsedByStrategy(STRATEGY_ENFORCED_AUDIBLE)) { <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">// 判断是否使用了这五种音频策略之一的
  17. // STRATEGY_ENFORCED_AUDIBLE
  18. device = <span style="color:#ff0000;">getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache);  <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">// 若使用了STRATEGY_ENFORCED_AUDIBLE,
  19. // 并获得相关设备,需要增加对USB AUDIO设备的支持
  20. } else if (isInCall() ||
  21. outputDesc->isUsedByStrategy(STRATEGY_PHONE)) {
  22. device = getDeviceForStrategy(STRATEGY_PHONE, fromCache);
  23. } else if (outputDesc->isUsedByStrategy(STRATEGY_SONIFICATION)) {
  24. device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache);
  25. } else if (outputDesc->isUsedByStrategy(STRATEGY_MEDIA)) {
  26. device = getDeviceForStrategy(STRATEGY_MEDIA, fromCache);
  27. } else if (outputDesc->isUsedByStrategy(STRATEGY_DTMF)) {
  28. device = getDeviceForStrategy(STRATEGY_DTMF, fromCache);
  29. }
  30. ......
  31. return device;
  32. }
  33. ......
  34. uint32_t AudioPolicyManagerBase::getDeviceForStrategy(routing_strategy strategy, bool fromCache)
  35. {
  36. uint32_t device = 0;
  37. if (fromCache) {
  38. LOGV("getDeviceForStrategy() from cache strategy %d, device %x", strategy, mDeviceForStrategy[strategy]);
  39. return mDeviceForStrategy[strategy];
  40. }
  41. switch (strategy) {
  42. case STRATEGY_DTMF:
  43. if (!isInCall()) {
  44. // when off call, DTMF strategy follows the same rules as MEDIA strategy
  45. device = getDeviceForStrategy(STRATEGY_MEDIA, false);
  46. break;
  47. }
  48. // when in call, DTMF and PHONE strategies follow the same rules
  49. // FALL THROUGH
  50. case STRATEGY_PHONE:   <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">// 由于我BOX不支持通话功能,所以可以不在此策略下添加对USB AUDIO设备的支持
  51. // for phone strategy, we first consider the forced use and then the available devices by order
  52. // of priority
  53. ......
  54. break;
  55. case STRATEGY_SONIFICATION: <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">// 由于我BOX不支持通话功能,所以可以不在此策略下添加对USB AUDIO设备的支持
  56. // If incall, just select the STRATEGY_PHONE device: The rest of the behavior is handled by
  57. // handleIncallSonification().
  58. ......
  59. case STRATEGY_ENFORCED_AUDIBLE:
  60. // strategy STRATEGY_ENFORCED_AUDIBLE uses same routing policy as STRATEGY_SONIFICATION
  61. // except when in call where it doesn't default to STRATEGY_PHONE behavior
  62. ......
  63. case STRATEGY_MEDIA: { <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">// 多媒体播放策略,需要添加对USB AUDIO设备的支持
  64. uint32_t device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE;
  65. if (device2 == 0) {
  66. device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;
  67. }
  68. .......
  69. <span style="color:#3333ff;">// 添加对USB AUDIO设备支持的代码
  70. <span style="color:#33cc00;">        if (device2 == 0) {
  71. device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_USB_AUDIO;
  72. }
  73. <span style="color:#3333ff;">// end
  74. .......
  75. }

(2)获取到新设备后,程序继续向下执行到updateDeviceForStrategy()函数,根据音频策略更新了相应的设备。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">void AudioPolicyManagerBase::updateDeviceForStrategy()
  2. {
  3. for (int i = 0; i < NUM_STRATEGIES; i++) {
  4. mDeviceForStrategy[i] = <span style="color:#ff0000;">getDeviceForStrategy((routing_strategy)i, false);
  5. }
  6. }

由于此函数仍将调到刚刚分析的函数getDeviceForStrategy(),故不再深入分析。

(3)更新完设备后,程序继续向下执行到setOutputDevice()函数,用新获取到的设备名称作为第二个参数(第一个参数是在创建AudioPolicyManagerBase类对象时获得的输出音频通道),来设置输出设备。此函数很重要,它将调到ALSA模块(alsa_default.cpp)。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">void AudioPolicyManagerBase::setOutputDevice(audio_io_handle_t output, uint32_t device, bool force, int delayMs)
  2. {
  3. LOGV("setOutputDevice() output %d device %x delayMs %d", output, device, delayMs);
  4. AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
  5. ......
  6. // do the routing
  7. AudioParameter param = AudioParameter();
  8. param.addInt(String8(AudioParameter::keyRouting), (int)device);  <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">// 第一个参数,暗示将重新选择路由,
  9. // 第二个参数就是要打开的音频设备的标识符
  10. mpClientInterface->setParameters(mHardwareOutput, param.toString(), delayMs);  <span style="color:#3333ff;">// 将从HAL层调回到frameworks层
  11. ......
  12. }

调用函数setOutputDevice()时,明明只有两个参数,怎么函数原型却有4个参数了那。有点儿诡异吧!我也困惑了好大会儿。最后才发现此函数的声明(AudioPolicyManagerBase.h)中,最后两个参数(第三个和第四个参数)已经有了默认值。原来,C++中有了默认值的参数,在调用时可以不写出来!!!
        void setOutputDevice(audio_io_handle_t output, uint32_t device, bool force = false, int delayMs = 0);
此函数的重点在于调用了函数mpClientInterface->setParameters()。
第一个参数mHardwareOutput:表示输出音频通道,
第三个参数delayMs:表示等待时间,值为默认值0。

通过前文分析可知,mpClientInterface就是AudioPolicyCompatClient类的对象,则mpClientInterface->setParameters()函数将调到AudioPolicyCompatClient类的setParameters()函数。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">void AudioPolicyCompatClient::setParameters(audio_io_handle_t ioHandle,
  2. const String8& keyValuePairs,
  3. int delayMs)
  4. {
  5. <span style="color:#ff0000;">mServiceOps->set_parameters(mService, ioHandle, keyValuePairs.string(),
  6. <span style="color:#3333ff;">  // 在创建APS类对象时,调用create_audio_policy()第三个参数this(即APS)一路传递下来,并在创建
  7. // AudioPolicyCompatClient类对象时对mService进行了初始化
  8. delayMs);
  9. }

而mServiceOps在创建AudioPolicyCompatClient类对象时,指向APS的struct audio_policy_service_ops变量aps_ops。则mServiceOps->set_parameters()函数将调到APS的aps_set_parameters()函数。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">static void aps_set_parameters(void *service, audio_io_handle_t io_handle,
  2. const char *kv_pairs, int delay_ms)
  3. {
  4. AudioPolicyService *audioPolicyService = (AudioPolicyService *)service;
  5. audioPolicyService->setParameters(io_handle, kv_pairs, delay_ms);
  6. }

显然将调到APS类的setParameters()函数。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">void AudioPolicyService::setParameters(audio_io_handle_t ioHandle,
  2. const char *keyValuePairs,
  3. int delayMs)
  4. {
  5. <span style="color:#ff0000;">mAudioCommandThread->parametersCommand((int)ioHandle, keyValuePairs,
  6. delayMs);
  7. }

mAudioCommandThread就是在创建APS类对象时,启动的一个音频命令线程。函数mAudioCommandThread->parametersCommand()将根据第二个参数产生一个设置音频参数的命令,并发给此线程的处理函数threadLoop()。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">status_t AudioPolicyService::AudioCommandThread::parametersCommand(int ioHandle,
  2. const char *keyValuePairs,
  3. int delayMs)
  4. {
  5. status_t status = NO_ERROR;
  6. AudioCommand *command = new AudioCommand();
  7. <span style="color:#ff0000;">command->mCommand = SET_PARAMETERS;
  8. ParametersData *data = new ParametersData();
  9. data->mIO = ioHandle;
  10. <span style="color:#ff0000;">data->mKeyValuePairs = String8(keyValuePairs);  <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">// keyValuePairs保存了从AudioPolicyManagerBase类传递的音频参数param
  11. command->mParam = data;
  12. if (delayMs == 0) {
  13. command->mWaitStatus = true;
  14. } else {
  15. command->mWaitStatus = false;
  16. }
  17. Mutex::Autolock _l(mLock);
  18. insertCommand_l(command, delayMs); <span style="color:#3333ff;">// 调用函数insertCommand_l()把命令插入到此线程处理函数threadLoop()中
  19. ......
  20. }
[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">// insertCommand_l() must be called with mLock held
  2. void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *command, int delayMs)
  3. {
  4. ......
  5. // acquire wake lock to make sure delayed commands are processed
  6. if (mName != "" && <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">mAudioCommands.isEmpty()) {
  7. acquire_wake_lock(PARTIAL_WAKE_LOCK, mName.string());
  8. }
  9. // check same pending commands with later time stamps and eliminate them
  10. for (i = mAudioCommands.size()-1; i >= 0; i--) {
  11. <span style="color:#ff0000;">AudioCommand *command2 = mAudioCommands[i];
  12. ......
  13. switch (command->mCommand) {
  14. <span style="color:#ff0000;">case SET_PARAMETERS: {
  15. ParametersData *data = (ParametersData *)command->mParam;
  16. ParametersData *data2 = (ParametersData *)command2->mParam;
  17. if (data->mIO != data2->mIO) break;
  18. LOGV("Comparing parameter command %s to new command %s",
  19. data2->mKeyValuePairs.string(), data->mKeyValuePairs.string());
  20. AudioParameter param = AudioParameter(data->mKeyValuePairs);
  21. AudioParameter param2 = AudioParameter(data2->mKeyValuePairs);
  22. for (size_t j = 0; j < param.size(); j++) {
  23. String8 key;
  24. String8 value;
  25. param.getAt(j, key, value);
  26. for (size_t k = 0; k < param2.size(); k++) {
  27. String8 key2;
  28. String8 value2;
  29. param2.getAt(k, key2, value2);
  30. if (key2 == key) {
  31. param2.remove(key2);
  32. LOGV("Filtering out parameter %s", key2.string());
  33. break;
  34. }
  35. }
  36. }
  37. // if all keys have been filtered out, remove the command.
  38. // otherwise, update the key value pairs
  39. if (param2.size() == 0) {
  40. <span style="color:#ff0000;">removedCommands.add(command2);
  41. } else {
  42. data2->mKeyValuePairs = param2.toString();
  43. }
  44. } break;
  45. ......
  46. }

插入命令函数AudioCommandThread::insertCommand_l()和命令处理函数AudioCommandThread::threadLoop()的衔接点就是mAudioCommands列表。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">bool AudioPolicyService::AudioCommandThread::threadLoop()
  2. {
  3. nsecs_t waitTime = INT64_MAX;
  4. mLock.lock();
  5. while (!exitPending())
  6. {
  7. while(!mAudioCommands.isEmpty()) {
  8. nsecs_t curTime = systemTime();
  9. // commands are sorted by increasing time stamp: execute them from index 0 and up
  10. if (mAudioCommands[0]->mTime <= curTime) {
  11. <span style="color:#ff0000;">AudioCommand *command = mAudioCommands[0];
  12. mAudioCommands.removeAt(0);
  13. mLastCommand = *command;
  14. switch (command->mCommand) {
  15. ......
  16. case SET_PARAMETERS: {
  17. ParametersData *data = (ParametersData *)command->mParam;
  18. LOGV("AudioCommandThread() processing set parameters string %s, io %d",
  19. data->mKeyValuePairs.string(), data->mIO);
  20. command->mStatus = <span style="color:#ff0000;">AudioSystem::setParameters(data->mIO, data->mKeyValuePairs);
  21. if (command->mWaitStatus) {
  22. command->mCond.signal();
  23. mWaitWorkCV.wait(mLock);
  24. }
  25. delete data;
  26. }break;
  27. ......
  28. }

此线程处理函数并没有真正去设置参数,而是把设置参数的实际操作交给了函数AudioSystem::setParameters()。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">status_t AudioSystem::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs) {
  2. const sp& af = AudioSystem::get_audio_flinger();
  3. if (af == 0) return PERMISSION_DENIED;
  4. return <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">af->setParameters(ioHandle, keyValuePairs);
  5. }

又调到AudioFlinger了!

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">status_t AudioFlinger::setParameters(int ioHandle, const String8& keyValuePairs)
  2. {
  3. ......
  4. // check calling permissions
  5. if (!settingsAllowed()) {
  6. return PERMISSION_DENIED;
  7. }
  8. // ioHandle == 0 means the parameters are global to the audio hardware interface
  9. if (ioHandle == 0) {  <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;"><span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">// ioHandle就是在函数AudioPolicyManagerBase::setOutputDevice()内调用
  10. // mpClientInterface->setParameters()函数时,
  11. // 传递的第一个参数mHardwareOutput,其值有其中可能;经查看log信息确认,当前值是0。
  12. // 将改变全局输入/输出音频设备
  13. AutoMutex lock(mHardwareLock);
  14. mHardwareStatus = AUDIO_SET_PARAMETER;
  15. status_t final_result = NO_ERROR;
  16. for (size_t i = 0; i < mAudioHwDevs.size(); i++) {  // 将对所有的音频设备的参数都重新设置
  17. audio_hw_device_t *dev = <span style="color:#ff0000;">mAudioHwDevs[i];
  18. result = <span style="color:#ff0000;">dev->set_parameters(dev, keyValuePairs.string());
  19. final_result = result ?: final_result;
  20. }
  21. ......
  22. }

由前面对AudioFlinger服务和AudioPolicyService服务的启动流程分析可知,mAudioHwDevs具体指在文件audio_hw_hal.cpp所实现的音频模块中定义的设备。则dev->set_parameters()函数就是adev_set_parameters()函数。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
  2. {
  3. struct legacy_audio_device *ladev = to_ladev(dev);
  4. return <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">ladev->hwif->setParameters(String8(kvpairs));
  5. }

同样根据前面AudioFlinger服务分析可知,ladev->hwif具体指ALSA音频类AudioHardwareALSA的对象。则函数ladev->hwif->setParameters()就是函数AudioHardwareALSA类的setParameters()函数。此函数在头文件hardware/alsa_sound/AudioHardwareALSA.h中定义。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">class ALSAStreamOps
  2. {
  3. public:
  4. ALSAStreamOps(AudioHardwareALSA *parent, alsa_handle_t *handle);
  5. virtual            ~ALSAStreamOps();
  6. status_t            set(int *format, uint32_t *channels, uint32_t *rate);
  7. status_t            <span style="color:#ff0000;">setParameters(const String8& keyValuePairs);
  8. ......
  9. }

此setParameters()函数的实现在提供了ALSA流操作接口的文件hardware/alsa_sound/ALSAStreamOps.cpp中。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style=""><span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">status_t ALSAStreamOps::setParameters(const String8& keyValuePairs)
  2. {
  3. AudioParameter param = AudioParameter(keyValuePairs);
  4. String8 key = String8(AudioParameter::keyRouting);
  5. status_t status = NO_ERROR;
  6. int device;
  7. LOGV("setParameters() %s", keyValuePairs.string());
  8. if (param.getInt(key, device) == NO_ERROR) {
  9. AutoMutex lock(mLock);
  10. <span style="color:#ff0000;">mParent->mALSADevice->route(mHandle, (uint32_t)device, mParent->mode());
  11. param.remove(key);
  12. }
  13. if (param.size()) {
  14. status = BAD_VALUE;
  15. }
  16. return status;
  17. }

看到route()函数,有点儿面熟吧?!
mParent是在AudioHardwareALSA.h头文件中定义的AudioHardwareALSA类的指针对象,是在创建ALSAStreamOps类实例时初始化的。没有看到什么时候直接创建了ALSAStreamOps类的对象。不过,ALSAStreamOps类同时被AudioStreamOutALSA类和AudioStreamInALSA类继承了,则在创建这两个子类的同时将创建ALSAStreamOps类的对象。 ALSAStreamOps类的子类之一AudioStreamOutALSA类在AudioPolicyManagerBase类被创建时,打开输出音频通道的操作一路调到AudioHardwareALSA类的打开音频通道时被创建。因此,此时mParent将指向AudioHardwareALSA类,不为空。
AudioHardwareALSA *     mParent;
mALSADevice也在创建AudioHardwareALSA类的对象时有了struct alsa_device_t类型的值

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style=""><span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">struct alsa_device_t {
  2. hw_device_t common;
  3. status_t (*init)(alsa_device_t *, ALSAHandleList &);
  4. status_t (*open)(alsa_handle_t *, uint32_t, int);
  5. status_t (*close)(alsa_handle_t *);
  6. status_t (*route)(alsa_handle_t *, uint32_t, int);
  7. };

而这些ALSA函数接口已经指向了具体的函数实现(alsa_default.cpp)。则调到HAL层ALSA音频模块(alsa_default.cpp)中s_route()函数。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style=""><span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">static status_t s_route(alsa_handle_t *handle, uint32_t devices, int mode)
  2. {
  3. LOGD("route called for devices %08x in mode %d...", devices, mode);
  4. //@eric:20110316
  5. //When RingCall come,AudioHardWareALSA Set RINGMODE and will call this  func.
  6. //FIXME:I think Our Audio Device only has one handle, so we can not reopen it
  7. if (handle->handle && handle->curDev == devices /*&& handle->curMode == mode*/) return NO_ERROR;
  8. return s_open(handle, devices, mode);
  9. }

进而调到s_open()函数。前面已经对s_open()函数做过分析,这里不再重述。

3. ALSA-LIB浅述以及asound.conf配置文件的书写。

ALSA(Advanced Linux Sound Architecture)音频驱动是一个十分庞大,复杂和功能强大的音频系统,应用领域远远高于先前的OSS (Open Sound System)音频驱动。由于ALSA-DRIVER过于庞杂,给开发者使用ALSA-DRIVER带来许多不变,故ALSA-DRIVER的API ALSA-LIB应运而生。我们可以通过调用ALSA-LIB的API间接与ALSA-DRIVER打交道。
关于ALSA的更多更详尽的介绍请参阅其官网(http://www.alsa-project.org/main/index.php/Main_Page)。
前文在分析ALSA音频模块(alsa_default.cpp)时,已经提到会在s_open()函数中调到ALSA-LIB的API函数snd_pcm_open()函数。就是此函数来实际实现音频通道的打开的!
snd_pcm_open(&handle->handle, devName, direction(handle), SND_PCM_ASYNC);
函数snd_pcm_open()在文件external/alsa-lib/src/pcm/pcm.c中定义。

/**
 * \brief Opens a PCM
 * \param pcmp Returned PCM handle
 * \param name ASCII identifier of the PCM handle
 * \param stream Wanted stream
 * \param mode Open mode (see #SND_PCM_NONBLOCK, #SND_PCM_ASYNC)
 * \return 0 on success otherwise a negative error code
 */
int snd_pcm_open(snd_pcm_t **pcmp, const char *name, 
                 snd_pcm_stream_t stream, int mode)
{
        int err; 
        assert(pcmp && name);
        err = snd_config_update();
        if (err < 0) 
                return err; 
        return snd_pcm_open_noupdate(pcmp, snd_config, name, stream, mode, 0);
}

(1)更新配置文件函数snd_config_update()。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style=""><span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">/**
  2. * \brief Updates #snd_config by rereading the global configuration files (if needed).
  3. * \return A non-negative value if successful, otherwise a negative error code.
  4. * \retval 0 No action is needed.
  5. * \retval 1 The configuration tree has been rebuilt.
  6. *
  7. * The global configuration files are specified in the environment variable
  8. * \c ALSA_CONFIG_PATH. If this is not set, the default value is
  9. * "/usr/share/alsa/alsa.conf".
  10. *
  11. * \warning If the configuration tree is reread, all string pointers and
  12. * configuration node handles previously obtained from this tree become invalid.
  13. */
  14. int snd_config_update(void)
  15. {
  16. int err;
  17. #ifdef HAVE_LIBPTHREAD
  18. pthread_mutex_lock(&snd_config_update_mutex);
  19. #endif
  20. err = <span style="color:#ff0000;">snd_config_update_r(<span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">&snd_config, <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">&snd_config_global_update, <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">NULL);
  21. #ifdef HAVE_LIBPTHREAD
  22. pthread_mutex_unlock(&snd_config_update_mutex);
  23. #endif
  24. return err;
  25. }

又调到snd_config_update_r()函数了。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style=""><span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">/**
  2. * \brief Updates a configuration tree by rereading the configuration files (if needed).
  3. * \param _top Address of the handle to the top level node.
  4. * \param _update Address of a pointer to private update information.
  5. * \param cfgs A list of configuration file names, delimited with ':'.
  6. *             If \p cfgs is set to \c NULL, the default global configuration
  7. *             file is used ("/usr/share/alsa/alsa.conf").
  8. * \return A non-negative value if successful, otherwise a negative error code.
  9. * \retval 0 No action is needed.
  10. * \retval 1 The configuration tree has been rebuilt.
  11. *
  12. * The global configuration files are specified in the environment variable
  13. * \c ALSA_CONFIG_PATH.
  14. *
  15. * \warning If the configuration tree is reread, all string pointers and
  16. * configuration node handles previously obtained from this tree become invalid.
  17. */
  18. int snd_config_update_r(snd_config_t **_top, snd_config_update_t **_update, const char *cfgs) <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">// cfgs = NULL
  19. {
  20. ......
  21. configs = cfgs;
  22. if (!configs) {
  23. configs = getenv(ALSA_CONFIG_PATH_VAR); <span style="color:#3333ff;">// ???
  24. if (!configs || !*configs) {
  25. configs = ALSA_CONFIG_PATH_DEFAULT;  <span style="color:#3333ff;">// 宏ALSA_CONFIG_PATH_DEFAULT
  26. // 便是/usr/share/alsa/alsa.conf
  27. .......
  28. }

这里提到要读取配置文件/usr/share/alsa/alsa.conf,即是在源码中的文件external/alsa-lib/src/conf/alsa.conf。在解析alsa.conf配置文件的同时,将解析alsa.conf文件中所包含的文件/etc/asound.conf。据ALSA官方网站介绍,asound.conf是全局配置文件。
网上关于asound.conf介绍很丰富了,其官网网址如下:http://www.alsa-project.org/alsa-doc/alsa-lib/pcm_plugins.html。
在android的源码中,也有现成的例子可以参考,比如三星的一个音频配置文件device/samsung/crespo/asound.conf。

pcm节点真是对具体的音频设备的硬件参数的配置。可以配置的硬件参数如下:

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style=""><span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">pcm.name {
  2. type hw # Kernel PCM
  3. card INT/STR # Card name (string) or number (integer)
  4. [device INT] # Device number (default 0)
  5. [subdevice INT] # Subdevice number (default -1: first available)
  6. [sync_ptr_ioctl BOOL] # Use SYNC_PTR ioctl rather than the direct mmap access for control structures
  7. [nonblock BOOL] # Force non-blocking open mode
  8. [format STR] # Restrict only to the given format
  9. [channels INT] # Restrict only to the given channels
  10. [rate INT] # Restrict only to the given rate
  11. }

仅举一例

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style=""><span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">pcm.AndroidCapture_Usb-audio_normal {  <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">// 此PCM节点为录音设备的PCM节点
  2. type hooks
  3. slave.pcm "hw:1,0" <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">// 1:表示声卡1(声卡0就是系统内嵌的声卡),0表示声卡1上的设备编号为0的设备
  4. }

AndroidCapture_Usb-audio_normal:前缀"AndroidCapture"和扩展"_normal"是固定的,后缀"_Usb-audio"是要在alsa_default.cpp中设置的。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style=""><span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">/* The following table(s) need to match in order of the route bits
  2. */
  3. static const device_suffix_t deviceSuffix[] = {
  4. {android_audio_legacy::AudioSystem::DEVICE_OUT_EARPIECE,       "_Earpiece"},
  5. {android_audio_legacy::AudioSystem::DEVICE_OUT_SPEAKER,        "_Speaker"},
  6. {android_audio_legacy::AudioSystem::DEVICE_OUT_BLUETOOTH_SCO,  "_Bluetooth"},
  7. {android_audio_legacy::AudioSystem::DEVICE_OUT_WIRED_HEADSET,  "_Headset"},
  8. {android_audio_legacy::AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP, "_Bluetooth-A2DP"},
  9. <span style="color:#33cc00;">        {android_audio_legacy::AudioSystem::DEVICE_OUT_USB_AUDIO,      "_Usb-audio"},
  10. {android_audio_legacy::AudioSystem::DEVICE_IN_USB_AUDIO,       "_Usb-audio"},
  11. };

在此配置文件中,不要指定USB AUDIO音频设备的声道数和采样率。因为不同的USB AUDIO音频设备具有不同的声道数channels或采样率rate。当要打开输入音频设备进行录音时。就需要根据实际使用的USB AUDIO音频设备的声道数或采样率这两个硬件参数进行重新设置(如果不改变channels,当channels值与实际设备的不一致时,将打不开音频设备;如果不改变rate,当rate值与实际设备的不一致时,声音将失真)。而打开输出音频通道时,采用默认值是没有问题的。

4. 重新获取USB AUDIO设备的硬件参数。

前文已经提到,可在alsa_default.cpp文件中的s_open()函数在调用setHardwareParams()函数设置硬件参数之前重设声道数channels或采样率rate。

4.1 有三种方法获得实际使用的USB AUDIO设备的硬件参数信息。

第一种方法: 自己写个字符串处理函数,从文件/proc/asound/card1/stream0中读取(只需读取录音部分的)。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style=""><span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">$ cat /proc/asound/card1/stream0
  2. SAGE Technology SAGE AirMouse at usb-0000:00:1d.3-2, full speed : USB Audio
  3. Playback:
  4. Status: Stop
  5. Interface 2
  6. Altset 1
  7. Format: S16_LE
  8. Channels: 1
  9. Endpoint: 6 OUT (NONE)
  10. Rates: 16000
  11. Capture:
  12. Status: Stop
  13. Interface 1
  14. Altset 1
  15. Format: S16_LE
  16. Channels: 1  <span style="color:#3333ff;">// 这个声道数与默认值2不一致
  17. Endpoint: 5 IN (NONE)
  18. Rates: 16000 <span style="color:#3333ff;">// 这个采样率与默认值48000不一致

第二种方法:自己写代码,从内核USB驱动中读取。主要涉及到如下文件(也是我们项目所采用的方法)

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style=""><span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">sound/usb/card.c
  2. drivers/hid/hid-input.c

第三种方法:因为是直接调用系统现有接口,是比较可靠的方法:调用ALSA-LIB库的API。主要涉及到如下文件

[cpp] view plaincopyprint?
  1. "http://www.w3.org/1999/xhtml" style=""><span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">external/alsa-lib/src/pcm/pcm_rate.c

4.2 把输入音频通道的声道数和采样率改回默认值

当打开指定PCM节点的音频设备失败后,系统会去打开默认的音频通道(alsa_default.cpp)。

[cpp] view plaincopyprint?
  1. <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style=""><span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">    for (;;) {
  2. // The PCM stream is opened in blocking mode, per ALSA defaults.  The
  3. // AudioFlinger seems to assume blocking mode too, so asynchronous mode
  4. // should not be used.
  5. err = snd_pcm_open(&handle->handle, devName, direction(handle),
  6. .......
  7. }
  8. if (err < 0) {
  9. <span style="color:#3333ff;">//要在此处把输入音频通道的声道数和采样率改回默认值
  10. // None of the Android defined audio devices exist. Open a generic one.
  11. devName = "default";
  12. err = snd_pcm_open(&handle->handle, devName, direction(handle), 0);
  13. }

PS:只需调用setDeviceConnectionState()函数打开输出音频通道,不要去打开输入音频通道。因为用户使用的音频聊天工具(如Skypee)会自动打开。我们只需在打开USB AUDIO输出音频通道时,强制设置USB MIC为输入音频通道。这样就能实现用USB MIC 进行语音聊天了!
结贴~~~~~~~

一篇不错的Android Audio架构代码梳理总结相关推荐

  1. Android Audio 架构分析

    一个音频系统大概包括音频的管理.声音播放.声音录音和声音音效几个部分,这几个部分分工协作来完成音频的功能, ·音频管理:负责音量调节.音频设备选择.响铃模式选择等: ·声音播放:负责一个音频流的创建. ...

  2. Android应用开发-小巫CSDN博客客户端Jsoup篇,分享Android资深架构师的成长之路

    Elements blogList = doc.getElementsByClass("article_item"); // Log.e("elements->&q ...

  3. Android Jetpack架构组件之 Room(使用、源码篇)

    2019独角兽企业重金招聘Python工程师标准>>> 1.前言 最近简单看了下google推出的框架Jetpack,感觉此框架的内容可以对平时的开发有很大的帮助,也可以解决很多开发 ...

  4. android 使用4大组件的源码,Android Jetpack架构组件之 Paging(使用、源码篇)

    1.前言 最近简单看了下google推出的框架Jetpack,感觉此框架的内容可以对平时的开发有很大的帮助,也可以解决很多开发中的问题,对代码的逻辑和UI界面实现深层解耦,打造数据驱动型UI界面. A ...

  5. Android JetPack架构篇,一个实战项目带你学懂JetPack

    第五届世界互联网大会昨日开幕,来自76个国家的1500余位嘉宾出席大会.腾讯公司董事会主席兼首席执行官马化腾在大会开幕式演讲中表示,全球产业都在进行数字化,在此期间机遇挑战并存,产业互联网机会巨大. ...

  6. Android 音频(Audio)架构

    一.概述 Android 的音频硬件抽象层 (HAL) 可将 android.media 中特定于音频的较高级别的框架 API 连接到底层音频驱动程序和硬件.本部分介绍了有关提升性能的实现说明和提示. ...

  7. Android当中的MVP模式(七)终篇---关于对MVP模式中代码臃肿

    个人博客:CODE FRAMER BIGZ MVP系列文章配套DEMO Android 当中的 MVP 模式(一)基本概念 Android 当中的 MVP 模式(二)封装 Android 当中的 MV ...

  8. Android audio篇章(1)------Audio架构

    文章目录 前言 一.Android和Linux的区别? 二.Audio架构 1. Audio音频子系统架构图 2. Audio HAL层的功能以及理解 2.1. Audio HAL层的框架分析 2.2 ...

  9. Android Qcom Audio架构学习

    总结: Android Audio不简单呀,一个人摸索入门不容易的,研究了一段时间,感觉还不是很懂,但以下的知识对入门还是有帮助的. Audio架构中的名词 FE(Front End) 提供pcm的设 ...

最新文章

  1. 自律到极致-人生才精致:第9期
  2. NTU课程:MAS714(4):贪心
  3. Altium designer原理图导入word文档模糊——终极解决办法
  4. 《Java 进阶之路》 下--推荐书籍
  5. SQLLite (二) :sqlite3_open, sqlite3_exec, slite3_close
  6. 影场与属性访问器界面
  7. android存电话号码,如何从android中删除联系人的电话号码?
  8. windows安装wget
  9. HTK---语音识别实现应用的Kit
  10. SublimeLinter 3中使用jshint
  11. MATLAB数字水印技术实现
  12. hp 430g8 笔记本摄像头黑屏问题解决
  13. 博睿APM获《金融电子化》2021年金融业新技术应用创新突出贡献奖
  14. 励志电影排行榜2011
  15. 【scrapy爬虫】爬取华为应用市场中所有应用的评论数据
  16. 人生重开模拟器(未完工)
  17. post入门篇:请求头/响应头、cookie、URL结构/编码、数据编码、winHttpRequest、post分析技巧、伪装IP
  18. wps怎么转换成jpg格式?
  19. yolov8s网络模型结构图
  20. 数据库(单表查询与多表联查)

热门文章

  1. GitHub 开源了多款字体「GitHub 热点速览 v.22.48」
  2. Ubuntu 下使用 FDDB 测试人脸检测模型并生成 ROC 曲线,详细步骤
  3. python中文版下载官网-Python中文版
  4. 少儿编程启蒙课程1:方格纸编程 揭秘算法
  5. 10G 网络变压器 万兆以太网技术
  6. Django 框架 要点
  7. mac 黑屏后不能启动系统的解决方案
  8. HTB OnlyForYou WriteUp
  9. Ubuntu 16.04 英伟达驱动、常用软件以及虚拟环境的安装
  10. 为Adobe Reader添加书签功能