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

int main(int argc, char **argv){    .....    init_parse_config_file("/init.rc");    .....}

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

service media /system/bin/mediaserver


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


int main(int argc, char** argv){  .....    AudioFlinger::instantiate();  //实例化AudioFlinger    .....    AudioPolicyService::instantiate(); //实例化AudioPolicyService        .....}


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

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


template<typename SERVICE>class BinderService{public:    static status_t publish() {        sp<IServiceManager> sm(defaultServiceManager());        return sm->addService(String16(SERVICE::getServiceName()), new SERVICE());    ......    static void instantiate() { publish(); }    .....    }  }

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


class AudioFlinger :    public BinderService<AudioFlinger>,    public BnAudioFlinger{    friend class BinderService<AudioFlinger>;public:    static char const* getServiceName() { return "media.audio_flinger"; }    .....}

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


AudioFlinger::AudioFlinger()    : BnAudioFlinger(),        mPrimaryHardwareDev(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1),        mBtNrecIsOff(false){}

此构造函数做了一些无关紧要的事情,不管它。既然AudioFlinger服务是第一次启动,则将调到函数AudioFlinger::onFirstRef(至于为什么,我还没有搞明白,可以通过log信息确信确实是这么回事)。


void AudioFlinger::onFirstRef()
{
......

for (size_t i = 0; i < ARRAY_SIZE(audio_interfaces); i++) {
const hw_module_t *mod;
audio_hw_device_t *dev;

rc = load_audio_interface(audio_interfaces[i], &mod,&dev);

.....

mAudioHwDevs.push(dev); // 把通过load_audio_interface()函数获得的设备存入元素为audio_hw_device_t

// 类型的模板变量mAudioHwDevs中


.....

}

看到load_audio_interface()函数的名字,知晓,应当是加载音频接口的。


static int load_audio_interface(const char *if_name, const hw_module_t **mod,                                audio_hw_device_t **dev){           ......    rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, mod);    if (rc)        goto out;            rc = audio_hw_device_open(*mod, dev);    .....}


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


struct audio_hw_device {    struct hw_device_t common;    /**      * used by audio flinger to enumerate what devices are supported by     * each audio_hw_device implementation.     *     * Return value is a bitmask of 1 or more values of audio_devices_t     */    uint32_t (*get_supported_devices)(const struct audio_hw_device *dev);    /**      * check to see if the audio hardware interface has been initialized.     * returns 0 on success, -ENODEV on failure.     */    int (*init_check)(const struct audio_hw_device *dev);   ......    /* set/get global audio parameters */    int (*set_parameters)(struct audio_hw_device *dev, const char *kv_pairs);   .....    /** This method creates and opens the audio hardware output stream */    int (*open_output_stream)(struct audio_hw_device *dev, uint32_t devices,                              int *format, uint32_t *channels,                              uint32_t *sample_rate,                              struct audio_stream_out **out);   ......    /** This method creates and opens the audio hardware input stream */    int (*open_input_stream)(struct audio_hw_device *dev, uint32_t devices,                             int *format, uint32_t *channels,                             uint32_t *sample_rate,                             audio_in_acoustics_t acoustics,                             struct audio_stream_in **stream_in);   .....}


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

$ grep -rn AUDIO_HARDWARE_MODULE_ID hardware/hardware/libhardware_legacy/audio/audio_hw_hal.cpp:602:id: AUDIO_HARDWARE_MODULE_ID,hardware/libhardware/modules/audio/audio_hw.c:435:   .id = AUDIO_HARDWARE_MODULE_ID,hardware/libhardware/include/hardware/audio.h:37:                                            #define AUDIO_HARDWARE_MODULE_ID "audio"

从搜索结果发现,AUDIO_HARDWARE_MODULE_ID的音频模块有两处定义,具体用的是哪一个那?
先分析下这两个模块最终编译进哪些模块。
通过查阅Android.mk晓得,audio_hw.c先被编译进audio_policy.stub模块,而后被编译进libhardware模块;
同样的,audio_hw_hal.cpp先被编译进libaudiopolicy_legacy模块,而后被编译进libhardware_legacy模块;
而libhardware和libhardware_legacy模块都在audioFlinger中用到。
通过log信息,确认使用的是libaudiopolicy_legacy模块,即具体调到hardware/libhardware_legacy/audio/audio_hw_hal.cpp文件中所定义的模块了。

在获取到HAL层音频模块后,接下来执行audio_hw_device_open()函数,打开设备。此函数也在audio.h头文件中定义,函数体如下:

/** convenience API for opening and closing a supported device */static inline int audio_hw_device_open(const struct hw_module_t* module,                                       struct audio_hw_device** device){    return module->methods->open(module, AUDIO_HARDWARE_INTERFACE,                                 (struct hw_device_t**)device);}


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


typedef struct hw_module_methods_t {    /** Open a specific device */    int (*open)(const struct hw_module_t* module, const char* id,             struct hw_device_t** device);} hw_module_methods_t;


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

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


static struct hw_module_methods_t legacy_audio_module_methods = {         open: legacy_adev_open};


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


static int legacy_adev_open(const hw_module_t* module, const char* name,                            hw_device_t** device){    struct legacy_audio_device *ladev;    int ret;    if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)  // 看来对应宏AUDIO_HARDWARE_INTERFACE,除了用来判断希望打开的是否音频硬件接口外,并没有做什么更多的事情        return -EINVAL;    .....    ladev->device.get_supported_devices = adev_get_supported_devices;    ladev->device.init_check = adev_init_check;    .....    ladev->device.open_output_stream = adev_open_output_stream;    ladev->device.close_output_stream = adev_close_output_stream;    ladev->device.open_input_stream = adev_open_input_stream;    ladev->device.close_input_stream = adev_close_input_stream;    .....    ladev->hwif = createAudioHardware();    .....    *device = &ladev->device.common;  // 将当前设备信息层层返回给回调函数,最后返回到 // load_audio_interface()函数,并保存在 // mAudioHwDevs模板变量中,供AudioFlinger类使用。     return 0; }


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


struct legacy_audio_device {    struct audio_hw_device device;            struct AudioHardwareInterface *hwif;}; 


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


namespace android_audio_legacy {    .....extern "C" AudioHardwareInterface* createAudioHardware(void);}; // namespace android


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


$ grep -rn createAudioHardware hardware/ --exclude-dir=.svnhardware/alsa_sound/AudioHardwareALSA.cpp:45:              android_audio_legacy::AudioHardwareInterface *createAudioHardware(void) {hardware/msm7k/libaudio-qsd8k/AudioHardware.cpp:2021:                     extern "C" AudioHardwareInterface* createAudioHardware(void) {hardware/msm7k/libaudio-qdsp5v2/AudioHardware.cpp:337:                     extern "C" AudioHardwareInterface* createAudioHardware(void) {hardware/msm7k/libaudio/AudioHardware.cpp:1132:                     extern "C" AudioHardwareInterface* createAudioHardware(void) {

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


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


return new AudioHardwareALSA();

AudioHardwareALSA类的构造函数如下:


AudioHardwareALSA::AudioHardwareALSA() :    mALSADevice(0),    mAcousticDevice(0){     ......    int err = hw_get_module(ALSA_HARDWARE_MODULE_ID,            (hw_module_t const**)&module);    if (err == 0) {        hw_device_t* device;        err = module->methods->open(module, ALSA_HARDWARE_NAME, &device);        if (err == 0) {            mALSADevice = (alsa_device_t *)device;            mALSADevice->init(mALSADevice, mDeviceList);    .....    err = hw_get_module(ACOUSTICS_HARDWARE_MODULE_ID,            (hw_module_t const**)&module);                                                                                             if (err == 0) {        hw_device_t* device;        err = module->methods->open(module, ACOUSTICS_HARDWARE_NAME, &device);     .....}


宏ALSA_HARDWARE_MODULE_ID是在头文件hardware/alsa_sound/AudioHardwareALSA.h中定义的。
模块所对应的结构体类型为hw_module_t,在头文件hardware/libhardware/include/hardware/hardware.h中定义。
在构造函数中,首先调用函数hw_get_module()获取ID为ALSA_HARDWARE_MODULE_ID的ALSA硬件模块,看来即将进入庞大而又功能强大的ALSA音频子系统了!

经过搜索,很快确定ID为ALSA_HARDWARE_MODULE_ID的ALSA硬件抽象层的具体实现在文件hardware/alsa_sound/alsa_default.cpp中。


$ grep -rn ALSA_HARDWARE_MODULE_ID hardware/ --exclude-dir=.svnhardware/alsa_sound/AudioHardwareALSA.h:39:#define ALSA_HARDWARE_MODULE_ID "alsa"hardware/alsa_sound/alsa_default.cpp:59:                                            id              : ALSA_HARDWARE_MODULE_ID,hardware/alsa_sound/AudioHardwareALSA.cpp:150:                                       int err = hw_get_module(ALSA_HARDWARE_MODULE_ID,


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


extern "C" const hw_module_t HAL_MODULE_INFO_SYM = {     tag             : HARDWARE_MODULE_TAG,    version_major   : 1,    version_minor   : 0,    id              : ALSA_HARDWARE_MODULE_ID,    name            : "ALSA module",    author          : "Wind River",    methods         : &s_module_methods,    dso             : 0,    reserved        : { 0, },};

s_module_methods函数的实现如下:


static hw_module_methods_t s_module_methods = {     open            : s_device_open};

s_device_open函数的实现如下:


static int s_device_open(const hw_module_t* module, const char* name,  //有些困惑, // 此open函数实现中并没有对调用者传递下来的name(ALSA_HARDWARE_NAME)作如何处理。        hw_device_t** device) //device存储返回的模块信息{    alsa_device_t *dev;    dev = (alsa_device_t *) malloc(sizeof(*dev));    if (!dev) return -ENOMEM;    memset(dev, 0, sizeof(*dev));    /* initialize the procs */    dev->common.tag = HARDWARE_DEVICE_TAG;    dev->common.version = 0;    dev->common.module = (hw_module_t *) module;    dev->common.close = s_device_close;    dev->init = s_init;    dev->open = s_open;    dev->close = s_close;    dev->route = s_route;    *device = &dev->common; // 把此模块信息返回给调用者    return 0;}


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

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


struct alsa_device_t {    hw_device_t common;        status_t (*init)(alsa_device_t *, ALSAHandleList &);    status_t (*open)(alsa_handle_t *, uint32_t, int);    status_t (*close)(alsa_handle_t *);    status_t (*route)(alsa_handle_t *, uint32_t, int);};  

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


static status_t s_init(alsa_device_t *module, ALSAHandleList &list){    list.clear();    snd_pcm_uframes_t bufferSize = _defaultsOut.bufferSize;    for (size_t i = 1; (bufferSize & ~i) != 0; i <<= 1)        bufferSize &= ~i;         _defaultsOut.module = module;      _defaultsOut.bufferSize = bufferSize;    list.push_back(_defaultsOut);     bufferSize = _defaultsIn.bufferSize;    .....    list.push_back(_defaultsIn);    .....}

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


static alsa_handle_t _defaultsOut = {    module      : 0,    devices     : android_audio_legacy::AudioSystem::DEVICE_OUT_ALL,  // 支持的所有 // 输出音频设备    curDev      : 0,    curMode     : 0,    handle      : 0,  // PCM节点     format      : SND_PCM_FORMAT_S16_LE, // AudioSystem::PCM_16_BIT     channels    : 2,      sampleRate  : DEFAULT_SAMPLE_RATE,      latency     : 200000, // Desired Delay in usec    bufferSize  : DEFAULT_SAMPLE_RATE / 5, // Desired Number of samples    modPrivate  : 0,};static alsa_handle_t _defaultsIn = {    module      : 0,    devices     : android_audio_legacy::AudioSystem::DEVICE_IN_ALL, // 支持的所有 // 输入音频设备    curDev      : 0,    curMode     : 0,    handle      : 0, // PCM节点    format      : SND_PCM_FORMAT_S16_LE, // AudioSystem::PCM_16_BIT    channels    : 2, // 声道数: 1表示单声道,2表示立体声。如果与实际使用的USB AUDIO设备参数 // 的不一致,将导致USB AUDIO设备不能使用。    sampleRate  : DEFAULT_SAMPLE_RATE, // 采样率,如果与实际使用的USB AUDIO设备参数 // 的不一致,将导致声音失真 latency : 250000, // Desired Delay in usec    bufferSize  : 2048, // Desired Number of samples    modPrivate  : 0,};

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


struct alsa_handle_t {    alsa_device_t *     module;    uint32_t            devices;    uint32_t            curDev;    int                 curMode;    snd_pcm_t *         handle;  // PCM节点     snd_pcm_format_t    format; uint32_t channels; uint32_t sampleRate;    unsigned int        latency;         // Delay in usec    unsigned int        bufferSize;      // Size of sample buffer    void *              modPrivate;};

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

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


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

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


class AudioPolicyService :    public BinderService<AudioPolicyService>, // 继承了BinderService类, // 并把自己(AudioPolicyService)传递给 // BinderService。     public BnAudioPolicyService,//    public AudioPolicyClientInterface,    public IBinder::DeathRecipient{    friend class BinderService<AudioPolicyService>;public:    // for BinderService    static const char *getServiceName() { return "media.audio_policy"; }    .....}

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


AudioPolicyService::instantiate();


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


AudioPolicyService::AudioPolicyService()    : BnAudioPolicyService() , mpAudioPolicyDev(NULL) , mpAudioPolicy(NULL){    char value[PROPERTY_VALUE_MAX];    const struct hw_module_t *module;    int forced_val;    int rc;    Mutex::Autolock _l(mLock);    // start tone playback thread    mTonePlaybackThread = new AudioCommandThread(String8(""));    // start audio commands thread    mAudioCommandThread = new AudioCommandThread(String8("ApmCommandThread"));    /* instantiate the audio policy manager */    rc = hw_get_module(AUDIO_POLICY_HARDWARE_MODULE_ID, &module);    if (rc)        return;    rc = audio_policy_dev_open(module, &mpAudioPolicyDev);    LOGE_IF(rc, "couldn't open audio policy device (%s)", strerror(-rc));    if (rc)        return;    rc = mpAudioPolicyDev->create_audio_policy(mpAudioPolicyDev, &aps_ops, this,                                              &mpAudioPolicy);    LOGE_IF(rc, "couldn't create audio policy (%s)", strerror(-rc));    if (rc)        return;    rc = mpAudioPolicy->init_check(mpAudioPolicy);    .....}

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


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


class AudioCommandThread : public Thread {


是AudioPolicyService类的私有子类。

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



bool AudioPolicyService::AudioCommandThread::threadLoop(){    nsecs_t waitTime = INT64_MAX;    mLock.lock();    while (!exitPending())    {        while(!mAudioCommands.isEmpty()) {           .....                            switch (command->mCommand) {                .....                case SET_PARAMETERS: {                     ParametersData *data = (ParametersData *)command->mParam;                     LOGV("AudioCommandThread() processing set parameters string %s, io %d",                             data->mKeyValuePairs.string(), data->mIO);                     command->mStatus = AudioSystem::setParameters(data->mIO, data->mKeyValuePairs);                     if (command->mWaitStatus) {                         command->mCond.signal();                         mWaitWorkCV.wait(mLock);                     }                     delete data;                     }break;    .....}

这里只列出了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子模块的具体实现。


$ grep -rn AUDIO_POLICY_HARDWARE_MODULE_ID hardware/ --exclude-dir=.svnhardware/libhardware_legacy/audio/audio_policy_hal.cpp:414:                                                id: AUDIO_POLICY_HARDWARE_MODULE_ID,hardware/libhardware/modules/audio/audio_policy.c:318:                                   .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中定义的。


struct audio_policy_device {      struct hw_device_t common;    int (*create_audio_policy)(const struct audio_policy_device *device,                               struct audio_policy_service_ops *aps_ops,                               void *service,                                                struct audio_policy **ap);      .....}


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


/** convenience API for opening and closing a supported device */ static inline int audio_policy_dev_open(const hw_module_t* module, struct audio_policy_device** device) { return module->methods->open(module, AUDIO_POLICY_INTERFACE, (hw_device_t**)device); }

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


static int legacy_ap_dev_open(const hw_module_t* module, const char* name, hw_device_t** device) // 参数device保存返回的模块信息 { struct legacy_ap_device *dev; if (strcmp(name, AUDIO_POLICY_INTERFACE) != 0)// 参数name(AUDIO_POLICY_INTERFACE) // 就这点用处  return -EINVAL; dev = (struct legacy_ap_device *)calloc(1, sizeof(*dev)); if (!dev) return -ENOMEM; dev->device.common.tag = HARDWARE_DEVICE_TAG; dev->device.common.version = 0; dev->device.common.module = const_cast<hw_module_t*>(module); dev->device.common.close = legacy_ap_dev_close; dev->device.create_audio_policy = create_legacy_ap; dev->device.destroy_audio_policy = destroy_legacy_ap; *device = &dev->device.common; // 将当前模块具体信息赋值给device,并回馈给调用者 return 0; }

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


namespace { struct audio_policy_service_ops aps_ops = { open_output : aps_open_output, open_duplicate_output : aps_open_dup_output, close_output : aps_close_output, suspend_output : aps_suspend_output, restore_output : aps_restore_output, open_input : aps_open_input, close_input : aps_close_input, set_stream_volume : aps_set_stream_volume, set_stream_output : aps_set_stream_output, set_parameters : aps_set_parameters, get_parameters : aps_get_parameters, start_tone : aps_start_tone, stop_tone : aps_stop_tone, set_voice_volume : aps_set_voice_volume, move_effects : aps_move_effects, }; }; // namespace <unnamed>

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中定义,将要用到的接口如下:


struct audio_policy { /* * configuration functions */ /* indicate a change in device connection status */ int (*set_device_connection_state)(struct audio_policy *pol, audio_devices_t device, audio_policy_dev_state_t state, const char *device_address); ..... /* check proper initialization */ int (*init_check)(const struct audio_policy *pol); ..... }

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


static int create_legacy_ap(const struct audio_policy_device *device, struct audio_policy_service_ops *aps_ops, void *service, struct audio_policy **ap) { struct legacy_audio_policy *lap; int ret; if (!service || !aps_ops) return -EINVAL; lap = (struct legacy_audio_policy *)calloc(1, sizeof(*lap)); if (!lap) return -ENOMEM; lap->policy.set_device_connection_state = ap_set_device_connection_state; ...... lap->policy.init_check = ap_init_check; lap->policy.get_output = ap_get_output; lap->policy.start_output = ap_start_output; lap->policy.stop_output = ap_stop_output; lap->policy.release_output = ap_release_output; lap->policy.get_input = ap_get_input; lap->policy.start_input = ap_start_input; lap->policy.stop_input = ap_stop_input; lap->policy.release_input = ap_release_input; .....  lap->service = service; // APS lap->aps_ops = aps_ops; // 在APS中实现 lap->service_client = new AudioPolicyCompatClient(aps_ops, service); if (!lap->service_client) { ret = -ENOMEM; goto err_new_compat_client; }  lap->apm = createAudioPolicyManager(lap->service_client); ...... *ap = &lap->policy; // 将当前音频策略的配置的地址赋值给*ap,并返回给mpAudioPolicy ...... }


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

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


namespace android_audio_legacy { class AudioPolicyCompatClient : public AudioPolicyClientInterface { // 父类是AudioPolicyClientInterface,与下文中提到的 // AudioPolicyManagerBase:: // AudioPolicyManagerBase(AudioPolicyClientInterface *clientInterface)类型一致 public: AudioPolicyCompatClient(struct audio_policy_service_ops *serviceOps, void *service) : mServiceOps(serviceOps) , mService(service) {} // serviceOps = aps_ops, // service = this(APS) ...... private: struct audio_policy_service_ops* mServiceOps; void* mService; ...... }


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


$ grep -rn createAudioPolicyManager hardware/ --exclude-dir=.svn hardware/alsa_sound/AudioPolicyManagerALSA.cpp:31: extern "C" android_audio_legacy::AudioPolicyInterface* createAudioPolicyManager( android_audio_legacy::AudioPolicyClientInterface *clientInterface) hardware/libhardware_legacy/audio/AudioPolicyManagerDefault.cpp:24: extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface) hardware/msm7k/libaudio-qsd8k/AudioPolicyManager.cpp:39: extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface) hardware/msm7k/libaudio-qdsp5v2/AudioPolicyManager.cpp:39: extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface) hardware/msm7k/libaudio/AudioPolicyManager.cpp:35: extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)


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


AudioPolicyManagerALSA::AudioPolicyManagerALSA( android_audio_legacy::AudioPolicyClientInterface *clientInterface) : AudioPolicyManagerBase(clientInterface) // clientInterface正是 // AudioPolicyCompatClient类对象,而AudioPolicyCompatClient类具体实现了 // AudioPolicyClientInterface类的需函数接口 { } AudioPolicyManagerBase::AudioPolicyManagerBase( AudioPolicyClientInterface *clientInterface) : #ifdef AUDIO_POLICY_TEST Thread(false), #endif //AUDIO_POLICY_TEST mPhoneState(AudioSystem::MODE_NORMAL), mRingerMode(0), mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f), mTotalEffectsCpuLoad(0), mTotalEffectsMemory(0), mA2dpSuspended(false) { mpClientInterface = clientInterface; // mpClientInterface:将用它回调到APS for (int i = 0; i < AudioSystem::NUM_FORCE_USE; i++) { mForceUse[i] = AudioSystem::FORCE_NONE; } initializeVolumeCurves(); // devices available by default are speaker, ear piece and microphone mAvailableOutputDevices = AudioSystem::DEVICE_OUT_EARPIECE | AudioSystem::DEVICE_OUT_SPEAKER; // 可用的输出音频设备 mAvailableInputDevices = AudioSystem::DEVICE_IN_BUILTIN_MIC; // 可用的输入音频设备 ...... mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice, &outputDesc->mSamplingRate, &outputDesc->mFormat, &outputDesc->mChannels, &outputDesc->mLatency, outputDesc->mFlags); ...... setOutputDevice(mHardwareOutput, (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER, true); ...... } 


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


audio_io_handle_t AudioPolicyCompatClient::openOutput(uint32_t *pDevices, uint32_t *pSamplingRate, uint32_t *pFormat, uint32_t *pChannels, uint32_t *pLatencyMs, AudioSystem::output_flags flags) { return mServiceOps->open_output(mService, pDevices, pSamplingRate, pFormat, pChannels, pLatencyMs, (audio_policy_output_flags_t)flags); }



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


static audio_io_handle_t aps_open_output(void *service,                                             uint32_t *pDevices,                                             uint32_t *pSamplingRate,                                             uint32_t *pFormat,                                             uint32_t *pChannels,                                             uint32_t *pLatencyMs,                                             audio_policy_output_flags_t flags){    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();    if (af == NULL) {        LOGW("%s: could not get AudioFlinger", __func__);        return 0;    }    return af->openOutput(pDevices, pSamplingRate, pFormat, pChannels,                          pLatencyMs, flags);}



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


int AudioFlinger::openOutput(uint32_t *pDevices,                                uint32_t *pSamplingRate,                                uint32_t *pFormat,                                uint32_t *pChannels,                                uint32_t *pLatencyMs,                                uint32_t flags){     ......    audio_hw_device_t *outHwDev;     ......    outHwDev = findSuitableHwDev_l(*pDevices);    if (outHwDev == NULL)        return 0;    status = outHwDev->open_output_stream(outHwDev, *pDevices, (int *)&format,                                          &channels, &samplingRate, &outStream);     ......    return 0; }


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


typedef struct audio_hw_device audio_hw_device_t;

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


audio_hw_device_t* AudioFlinger::findSuitableHwDev_l(uint32_t devices){       /* first matching HW device is returned */    for (size_t i = 0; i < mAudioHwDevs.size(); i++) {  // 前文分析过,mAudioHwDevs变量保存了HAL层可用音频设备        audio_hw_device_t *dev = mAudioHwDevs[i];        if ((dev->get_supported_devices(dev) & devices) == devices)             return dev;    }           return NULL;}



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


static uint32_t adev_get_supported_devices(const struct audio_hw_device *dev){    /* XXX: The old AudioHardwareInterface interface is not smart enough to     * tell us this, so we'll lie and basically tell AF that we support the     * below input/output devices and cross our fingers. To do things properly,     * audio hardware interfaces that need advanced features (like this) should     * convert to the new HAL interface and not use this wrapper. */    return (/* OUT */            AUDIO_DEVICE_OUT_EARPIECE |            AUDIO_DEVICE_OUT_SPEAKER |            AUDIO_DEVICE_OUT_WIRED_HEADSET |            AUDIO_DEVICE_OUT_WIRED_HEADPHONE |            AUDIO_DEVICE_OUT_AUX_DIGITAL |            AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET |            AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET |            AUDIO_DEVICE_OUT_ALL_SCO |            AUDIO_DEVICE_OUT_DEFAULT |            /* IN */            AUDIO_DEVICE_IN_COMMUNICATION |            AUDIO_DEVICE_IN_AMBIENT |            AUDIO_DEVICE_IN_BUILTIN_MIC |            AUDIO_DEVICE_IN_WIRED_HEADSET |            AUDIO_DEVICE_IN_AUX_DIGITAL |            AUDIO_DEVICE_IN_BACK_MIC |            AUDIO_DEVICE_IN_ALL_SCO |            AUDIO_DEVICE_IN_DEFAULT);}


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


static int adev_open_output_stream(struct audio_hw_device *dev,                                   uint32_t devices,                                   int *format,                                   uint32_t *channels,                                   uint32_t *sample_rate,                                   struct audio_stream_out **stream_out){    struct legacy_audio_device *ladev = to_ladev(dev);    status_t status;    struct legacy_stream_out *out;    int ret;    out = (struct legacy_stream_out *)calloc(1, sizeof(*out));    if (!out)        return -ENOMEM;    out->legacy_out = ladev->hwif->openOutputStream(devices, format, channels,                                                    sample_rate, &status);    ......}

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


android_audio_legacy::AudioStreamOut *AudioHardwareALSA::openOutputStream(uint32_t devices,                                    int *format,                                    uint32_t *channels,                                    uint32_t *sampleRate,                                    status_t *status){    ......    // Find the appropriate alsa device    for(ALSAHandleList::iterator it = mDeviceList.begin(); // mDeviceList是用来存储 // 输出/输入音频通道信息的 // 句柄的,总共两个句柄, // 分别对应输出和输入音频通道         it != mDeviceList.end(); ++it)        if (it->devices & devices) {            err = mALSADevice->open(&(*it), devices, mode()); // 当调用open()函数时, // 就已经知道要打开的是 // 输入音频通道还是输出 // 音频通道            if (err) break;            out = new AudioStreamOutALSA(this, &(*it)); // 此类对象的创建本可不必理会, // 但它的父类ALSAStreamOps类的对象也会随之创建;而ALSAStreamOps // 类将在后面用到(mParent = this(AudioHardwareALSA))            err = out->set(format, channels, sampleRate);            break;        }    ......}


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


static status_t s_open(alsa_handle_t *handle, uint32_t devices, int mode){    // Close off previously opened device.    // It would be nice to determine if the underlying device actually    // changes, but we might be recovering from an error or manipulating    // mixer settings (see asound.conf).    //    s_close(handle); // 先关闭先前打开的音频通道     LOGD("open called for devices %08x in mode %d...", devices, mode);    const char *stream = streamName(handle);      const char *devName = deviceName(handle, devices, mode);    int err;    for (;;) {        // The PCM stream is opened in blocking mode, per ALSA defaults.  The        // AudioFlinger seems to assume blocking mode too, so asynchronous mode        // should not be used.        err = snd_pcm_open(&handle->handle, devName, direction(handle),                                        // handle->handle:保存从ALSA-LIB中获得的PCM节点                SND_PCM_ASYNC);        if (err == 0) break;        // See if there is a less specific name we can try.        // Note: We are changing the contents of a const char * here.        char *tail = strrchr(devName, '_');        if (!tail) break;        *tail = 0;    }    if (err < 0) {        // None of the Android defined audio devices exist. Open a generic one.        devName = "default";        err = snd_pcm_open(&handle->handle, devName, direction(handle), 0);    }    if (err < 0) {        LOGE("Failed to Initialize any ALSA %s device: %s",                stream, strerror(err));        return NO_INIT;    }    err = setHardwareParams(handle);    if (err == NO_ERROR) err = setSoftwareParams(handle);    LOGI("Initialized ALSA %s device %s", stream, devName);    handle->curDev = devices;    handle->curMode = mode;    return err;}


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


const char *streamName(alsa_handle_t *handle){       return snd_pcm_stream_name(direction(handle));}  


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


snd_pcm_stream_t direction(alsa_handle_t *handle){    return (handle->devices & android_audio_legacy::AudioSystem::DEVICE_OUT_ALL) ? SND_PCM_STREAM_PLAYBACK            : SND_PCM_STREAM_CAPTURE;}


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


const char *snd_pcm_stream_name(snd_pcm_stream_t stream){        if (stream > SND_PCM_STREAM_LAST)                 return NULL;        return snd_pcm_stream_names[stream];}



static const char *const snd_pcm_stream_names[] = {        STREAM(PLAYBACK),        STREAM(CAPTURE),};

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


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



const char *deviceName(alsa_handle_t *handle, uint32_t device, int mode){    static char devString[ALSA_NAME_MAX];    int hasDevExt = 0;    strcpy(devString, devicePrefix[direction(handle)]);    for (int dev = 0; device && dev < deviceSuffixLen; dev++)        if (device & deviceSuffix[dev].device) {            ALSA_STRCAT (devString, deviceSuffix[dev].suffix);            device &= ~deviceSuffix[dev].device;            hasDevExt = 1;        }    if (hasDevExt) switch (mode) {                case android_audio_legacy::AudioSystem::MODE_NORMAL:        ALSA_STRCAT (devString, "_normal")        ;        break;                case android_audio_legacy::AudioSystem::MODE_RINGTONE:        ALSA_STRCAT (devString, "_ringtone")        ;        break;                case android_audio_legacy::AudioSystem::MODE_IN_CALL:        ALSA_STRCAT (devString, "_incall")        ;        break;    };    return devString;}

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


static const char *devicePrefix[SND_PCM_STREAM_LAST + 1] = {        /* SND_PCM_STREAM_PLAYBACK : */"AndroidPlayback",        /* SND_PCM_STREAM_CAPTURE  : */"AndroidCapture",};


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


/* The following table(s) need to match in order of the route bits */     static const device_suffix_t deviceSuffix[] = {        {android_audio_legacy::AudioSystem::DEVICE_OUT_EARPIECE,       "_Earpiece"},        {android_audio_legacy::AudioSystem::DEVICE_OUT_SPEAKER,        "_Speaker"},        {android_audio_legacy::AudioSystem::DEVICE_OUT_BLUETOOTH_SCO,  "_Bluetooth"},        {android_audio_legacy::AudioSystem::DEVICE_OUT_WIRED_HEADSET,  "_Headset"},        {android_audio_legacy::AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP, "_Bluetooth-A2DP"},}; 


struct device_suffix_t的定义如下:


struct device_suffix_t {    const android_audio_legacy::AudioSystem::audio_devices device;    const char *suffix;};


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


1.frameworks/base/media/java/android/media/AudioSystem.java2.frameworks/base/media/java/android/media/AudioManager.java3.hardware/libhardware_legacy/include/hardware_legacy/AudioSystemLegacy.h4.system/core/include/system/audio.h

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

  public static final int DEVICE_OUT_EARPIECE = 0x1; // 0x1 << 0 public static final int DEVICE_OUT_SPEAKER = 0x2; // 0x1 << 1 public static final int DEVICE_OUT_WIRED_HEADSET = 0x4; // 0x1 << 2 public static final int DEVICE_OUT_WIRED_HEADPHONE = 0x8; // 0x1 << 3 public static final int DEVICE_OUT_BLUETOOTH_SCO = 0x10; // 0x1 << 4 public static final int DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20; // 0x1 << 5 public static final int DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40; // 0x1 << 6 public static final int DEVICE_OUT_BLUETOOTH_A2DP = 0x80; // 0x1 << 7 public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100; // 0x100 << 0 public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200; // 0x100 << 1 public static final int DEVICE_OUT_AUX_DIGITAL = 0x400; // 0x100 << 2 public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800; // 0x100 << 3 public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000; // 0x1000 << 0 public static final int DEVICE_OUT_DEFAULT = 0x8000; // 0x1000 << 3 // input devices public static final int DEVICE_IN_COMMUNICATION = 0x10000; // 0x10000 << 0 public static final int DEVICE_IN_AMBIENT = 0x20000; // 0x10000 << 1 public static final int DEVICE_IN_BUILTIN_MIC1 = 0x40000; // 0x10000 << 2 public static final int DEVICE_IN_BUILTIN_MIC2 = 0x80000; // 0x10000 << 3 public static final int DEVICE_IN_MIC_ARRAY = 0x100000; // 0x100000 << 0 public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x200000; // 0x100000 << 1 public static final int DEVICE_IN_WIRED_HEADSET = 0x400000; // 0x100000 << 2 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中声道数和采样率进行赋值。将在后面做详细分析。

status_t setHardwareParams(alsa_handle_t *handle){    ...... unsigned int requestedRate = handle->sampleRate; ...... err = snd_pcm_hw_params_set_channels(handle->handle, hardwareParams,            handle->channels);    ...... err = snd_pcm_hw_params_set_rate_near(handle->handle, hardwareParams, &requestedRate, 0);    ......}

(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)代码。


static int android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz,                                   jint device, jint state, jstring device_address){    const char *c_address = env->GetStringUTFChars(device_address, NULL);    int status = check_AudioSystem_Command(       AudioSystem::setDeviceConnectionState(static_cast <audio_devices_t>(device),       static_cast <audio_policy_dev_state_t>(state),       c_address));    env->ReleaseStringUTFChars(device_address, c_address);    return status;}

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


status_t AudioSystem::setDeviceConnectionState(audio_devices_t device,                                               audio_policy_dev_state_t state,                                               const char *device_address){    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();    const char *address = "";     if (aps == 0) return PERMISSION_DENIED;    if (device_address != NULL) {        address = device_address;    }       return aps->setDeviceConnectionState(device, state, address);}


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


status_t AudioPolicyService::setDeviceConnectionState(audio_devices_t device,                                                  audio_policy_dev_state_t state,                                                  const char *device_address){    ......    return mpAudioPolicy->set_device_connection_state(mpAudioPolicy, device,                                                      state, device_address);}


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


static int ap_set_device_connection_state(struct audio_policy *pol,                                          audio_devices_t device,                                                  audio_policy_dev_state_t state,                                          const char *device_address)    {    struct legacy_audio_policy *lap = to_lap(pol);    return lap->apm->setDeviceConnectionState(                    (AudioSystem::audio_devices)device,                    (AudioSystem::device_connection_state)state,                    device_address);               }


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


status_t AudioPolicyManagerBase::setDeviceConnectionState(AudioSystem::audio_devices device, AudioSystem::device_connection_state state, const char *device_address) { ...... // handle output devices if (AudioSystem::isOutputDevice(device)) { // 如果是输出设备  ...... switch (state) { // handle output device connection case AudioSystem::DEVICE_STATE_AVAILABLE: if (mAvailableOutputDevices & device) { LOGW("setDeviceConnectionState() device already connected: %x", device); return INVALID_OPERATION; } LOGV("setDeviceConnectionState() connecting device %x", device); // register new device as available mAvailableOutputDevices |= device; // 把当前设备加入到可用设备变量中 ..... // handle output device disconnection case AudioSystem::DEVICE_STATE_UNAVAILABLE: { if (!(mAvailableOutputDevices & device)) { LOGW("setDeviceConnectionState() device not connected: %x", device); return INVALID_OPERATION; } LOGV("setDeviceConnectionState() disconnecting device %x", device); // remove device from available output devices mAvailableOutputDevices &= ~device; // 把当前设备从可用设备变量中去除 ...... } // request routing change if necessary uint32_t newDevice = getNewDevice(mHardwareOutput, false); ...... updateDeviceForStrategy(); setOutputDevice(mHardwareOutput, newDevice); // 如果输出音频设备是USB AUDIO(USB 放音),那么应该知道输入音频设备为SUB MIC if (device == AudioSystem::DEVICE_OUT_WIRED_HEADSET) { device = AudioSystem::DEVICE_IN_WIRED_HEADSET; } else if (device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO || device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET || device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT) { device = AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET; } else { return NO_ERROR; } } // handle input devices if (AudioSystem::isInputDevice(device)) { // 如果是输入设备 switch (state) { // handle input device connection case AudioSystem::DEVICE_STATE_AVAILABLE: { if (mAvailableInputDevices & device) { LOGW("setDeviceConnectionState() device already connected: %d", device); return INVALID_OPERATION; } mAvailableInputDevices |= device; } break; // handle input device disconnection case AudioSystem::DEVICE_STATE_UNAVAILABLE: { if (!(mAvailableInputDevices & device)) { LOGW("setDeviceConnectionState() device not connected: %d", device); return INVALID_OPERATION; } mAvailableInputDevices &= ~device; } break; default: LOGE("setDeviceConnectionState() invalid state: %x", state); return BAD_VALUE; } audio_io_handle_t activeInput = getActiveInput(); if (activeInput != 0) { AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput); uint32_t newDevice = getDeviceForInputSource(inputDesc->mInputSource); if (newDevice != inputDesc->mDevice) { LOGV("setDeviceConnectionState() changing device from %x to %x for input %d", inputDesc->mDevice, newDevice, activeInput); inputDesc->mDevice = newDevice; AudioParameter param = AudioParameter(); param.addInt(String8(AudioParameter::keyRouting), (int)newDevice); mpClientInterface->setParameters(activeInput, param.toString()); } } return NO_ERROR; } LOGW("setDeviceConnectionState() invalid device: %x", device); return BAD_VALUE; }


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


uint32_t AudioPolicyManagerBase::getNewDevice(audio_io_handle_t output, bool fromCache){    uint32_t device = 0;    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);    // check the following by order of priority to request a routing change if necessary:    // 1: the strategy enforced audible is active on the output:    //      use device for strategy enforced audible    // 2: we are in call or the strategy phone is active on the output:    //      use device for strategy phone    // 3: the strategy sonification is active on the output:    //      use device for strategy sonification    // 4: the strategy media is active on the output:    //      use device for strategy media    // 5: the strategy DTMF is active on the output:    //      use device for strategy DTMF    if (outputDesc->isUsedByStrategy(STRATEGY_ENFORCED_AUDIBLE)) { // 判断是否使用了这五种音频策略之一的 // STRATEGY_ENFORCED_AUDIBLE        device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache);  // 若使用了STRATEGY_ENFORCED_AUDIBLE, // 并获得相关设备,需要增加对USB AUDIO设备的支持    } else if (isInCall() ||                    outputDesc->isUsedByStrategy(STRATEGY_PHONE)) {        device = getDeviceForStrategy(STRATEGY_PHONE, fromCache);    } else if (outputDesc->isUsedByStrategy(STRATEGY_SONIFICATION)) {        device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache);    } else if (outputDesc->isUsedByStrategy(STRATEGY_MEDIA)) {        device = getDeviceForStrategy(STRATEGY_MEDIA, fromCache);    } else if (outputDesc->isUsedByStrategy(STRATEGY_DTMF)) {        device = getDeviceForStrategy(STRATEGY_DTMF, fromCache);    }       ......    return device;}......uint32_t AudioPolicyManagerBase::getDeviceForStrategy(routing_strategy strategy, bool fromCache){    uint32_t device = 0;    if (fromCache) {        LOGV("getDeviceForStrategy() from cache strategy %d, device %x", strategy, mDeviceForStrategy[strategy]);        return mDeviceForStrategy[strategy];    }    switch (strategy) {    case STRATEGY_DTMF:         if (!isInCall()) {            // when off call, DTMF strategy follows the same rules as MEDIA strategy            device = getDeviceForStrategy(STRATEGY_MEDIA, false);            break;        }        // when in call, DTMF and PHONE strategies follow the same rules        // FALL THROUGH    case STRATEGY_PHONE:   // 由于我BOX不支持通话功能,所以可以不在此策略下添加对USB AUDIO设备的支持         // for phone strategy, we first consider the forced use and then the available devices by order        // of priority    ......    break;    case STRATEGY_SONIFICATION: // 由于我BOX不支持通话功能,所以可以不在此策略下添加对USB AUDIO设备的支持        // If incall, just select the STRATEGY_PHONE device: The rest of the behavior is handled by        // handleIncallSonification().     ......    case STRATEGY_ENFORCED_AUDIBLE:        // strategy STRATEGY_ENFORCED_AUDIBLE uses same routing policy as STRATEGY_SONIFICATION        // except when in call where it doesn't default to STRATEGY_PHONE behavior    ......    case STRATEGY_MEDIA: { // 多媒体播放策略,需要添加对USB AUDIO设备的支持        uint32_t device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE;        if (device2 == 0) {            device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;        }    .......        // 添加对USB AUDIO设备支持的代码 if (device2 == 0) { device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_USB_AUDIO; }        // end        .......}


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


void AudioPolicyManagerBase::updateDeviceForStrategy(){    for (int i = 0; i < NUM_STRATEGIES; i++) {        mDeviceForStrategy[i] = getDeviceForStrategy((routing_strategy)i, false);    }  }


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

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


void AudioPolicyManagerBase::setOutputDevice(audio_io_handle_t output, uint32_t device, bool force, int delayMs){               LOGV("setOutputDevice() output %d device %x delayMs %d", output, device, delayMs);    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);                        ......    // do the routing    AudioParameter param = AudioParameter();    param.addInt(String8(AudioParameter::keyRouting), (int)device);  // 第一个参数,暗示将重新选择路由, // 第二个参数就是要打开的音频设备的标识符     mpClientInterface->setParameters(mHardwareOutput, param.toString(), delayMs);  // 将从HAL层调回到frameworks层    ......}


调用函数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()函数。


void AudioPolicyCompatClient::setParameters(audio_io_handle_t ioHandle,                                            const String8& keyValuePairs,                                            int delayMs){    mServiceOps->set_parameters(mService, ioHandle, keyValuePairs.string(),   // 在创建APS类对象时,调用create_audio_policy()第三个参数this(即APS)一路传递下来,并在创建 // AudioPolicyCompatClient类对象时对mService进行了初始化                           delayMs);}

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


static void aps_set_parameters(void *service, audio_io_handle_t io_handle,                                   const char *kv_pairs, int delay_ms){    AudioPolicyService *audioPolicyService = (AudioPolicyService *)service;    audioPolicyService->setParameters(io_handle, kv_pairs, delay_ms);}


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


void AudioPolicyService::setParameters(audio_io_handle_t ioHandle,                                       const char *keyValuePairs,                                            int delayMs)                   {    mAudioCommandThread->parametersCommand((int)ioHandle, keyValuePairs,                                           delayMs);                      }



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


status_t AudioPolicyService::AudioCommandThread::parametersCommand(int ioHandle,                                                                   const char *keyValuePairs,                                                                   int delayMs){    status_t status = NO_ERROR;                                               AudioCommand *command = new AudioCommand();    command->mCommand = SET_PARAMETERS;     ParametersData *data = new ParametersData();    data->mIO = ioHandle;                   data->mKeyValuePairs = String8(keyValuePairs); // keyValuePairs保存了从AudioPolicyManagerBase类传递的音频参数param  command->mParam = data;                 if (delayMs == 0) {        command->mWaitStatus = true;    } else {                                               command->mWaitStatus = false;    }    Mutex::Autolock _l(mLock);    insertCommand_l(command, delayMs); // 调用函数insertCommand_l()把命令插入到此线程处理函数threadLoop()中    ......}


// insertCommand_l() must be called with mLock heldvoid AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *command, int delayMs){    ......    // acquire wake lock to make sure delayed commands are processed    if (mName != "" && mAudioCommands.isEmpty()) {        acquire_wake_lock(PARTIAL_WAKE_LOCK, mName.string());    }    // check same pending commands with later time stamps and eliminate them    for (i = mAudioCommands.size()-1; i >= 0; i--) {        AudioCommand *command2 = mAudioCommands[i];    ......        switch (command->mCommand) {        case SET_PARAMETERS: {            ParametersData *data = (ParametersData *)command->mParam;            ParametersData *data2 = (ParametersData *)command2->mParam;            if (data->mIO != data2->mIO) break;            LOGV("Comparing parameter command %s to new command %s",                    data2->mKeyValuePairs.string(), data->mKeyValuePairs.string());            AudioParameter param = AudioParameter(data->mKeyValuePairs);            AudioParameter param2 = AudioParameter(data2->mKeyValuePairs);            for (size_t j = 0; j < param.size(); j++) {               String8 key;               String8 value;               param.getAt(j, key, value);               for (size_t k = 0; k < param2.size(); k++) {                  String8 key2;                  String8 value2;                  param2.getAt(k, key2, value2);                  if (key2 == key) {                      param2.remove(key2);                      LOGV("Filtering out parameter %s", key2.string());                      break;                  }               }            }            // if all keys have been filtered out, remove the command.            // otherwise, update the key value pairs            if (param2.size() == 0) {                removedCommands.add(command2);            } else {                data2->mKeyValuePairs = param2.toString();            }        } break;    ......}

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


bool AudioPolicyService::AudioCommandThread::threadLoop(){    nsecs_t waitTime = INT64_MAX;    mLock.lock();    while (!exitPending())    {        while(!mAudioCommands.isEmpty()) {            nsecs_t curTime = systemTime();            // commands are sorted by increasing time stamp: execute them from index 0 and up            if (mAudioCommands[0]->mTime <= curTime) {                AudioCommand *command = mAudioCommands[0];                 mAudioCommands.removeAt(0);                mLastCommand = *command;                switch (command->mCommand) {    ......                case SET_PARAMETERS: {                     ParametersData *data = (ParametersData *)command->mParam;                     LOGV("AudioCommandThread() processing set parameters string %s, io %d",                             data->mKeyValuePairs.string(), data->mIO);                     command->mStatus = AudioSystem::setParameters(data->mIO, data->mKeyValuePairs);                     if (command->mWaitStatus) {                         command->mCond.signal();                         mWaitWorkCV.wait(mLock);                     }                     delete data;                     }break;    ......}


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


status_t AudioSystem::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs) {    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();    if (af == 0) return PERMISSION_DENIED;    return af->setParameters(ioHandle, keyValuePairs);}


又调到AudioFlinger了!


status_t AudioFlinger::setParameters(int ioHandle, const String8& keyValuePairs)  {    ......   // check calling permissions    if (!settingsAllowed()) {        return PERMISSION_DENIED;    }    // ioHandle == 0 means the parameters are global to the audio hardware interface    if (ioHandle == 0) {  // ioHandle就是在函数AudioPolicyManagerBase::setOutputDevice()内调用 // mpClientInterface->setParameters()函数时, // 传递的第一个参数mHardwareOutput,其值有其中可能;经查看log信息确认,当前值是0。 // 将改变全局输入/输出音频设备         AutoMutex lock(mHardwareLock);        mHardwareStatus = AUDIO_SET_PARAMETER;        status_t final_result = NO_ERROR;        for (size_t i = 0; i < mAudioHwDevs.size(); i++) {  // 将对所有的音频设备的参数都重新设置            audio_hw_device_t *dev = mAudioHwDevs[i];            result = dev->set_parameters(dev, keyValuePairs.string());            final_result = result ?: final_result;        }    ......}


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


static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs){    struct legacy_audio_device *ladev = to_ladev(dev);    return ladev->hwif->setParameters(String8(kvpairs));}

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


class ALSAStreamOps{public:    ALSAStreamOps(AudioHardwareALSA *parent, alsa_handle_t *handle);    virtual            ~ALSAStreamOps();    status_t            set(int *format, uint32_t *channels, uint32_t *rate);    status_t            setParameters(const String8& keyValuePairs);    ......}


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



status_t ALSAStreamOps::setParameters(const String8& keyValuePairs) { AudioParameter param = AudioParameter(keyValuePairs); String8 key = String8(AudioParameter::keyRouting); status_t status = NO_ERROR; int device; LOGV("setParameters() %s", keyValuePairs.string()); if (param.getInt(key, device) == NO_ERROR) { AutoMutex lock(mLock); mParent->mALSADevice->route(mHandle, (uint32_t)device, mParent->mode()); param.remove(key); } if (param.size()) { status = BAD_VALUE; } return status; }

看到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类型的值


struct alsa_device_t { hw_device_t common; status_t (*init)(alsa_device_t *, ALSAHandleList &); status_t (*open)(alsa_handle_t *, uint32_t, int); status_t (*close)(alsa_handle_t *); status_t (*route)(alsa_handle_t *, uint32_t, int); };


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


static status_t s_route(alsa_handle_t *handle, uint32_t devices, int mode) { LOGD("route called for devices %08x in mode %d...", devices, mode); //@eric:20110316 //When RingCall come,AudioHardWareALSA Set RINGMODE and will call this func. //FIXME:I think Our Audio Device only has one handle, so we can not reopen it if (handle->handle && handle->curDev == devices /*&& handle->curMode == mode*/) return NO_ERROR; return s_open(handle, devices, mode); }


进而调到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()。


/** * \brief Updates #snd_config by rereading the global configuration files (if needed). * \return A non-negative value if successful, otherwise a negative error code. * \retval 0 No action is needed. * \retval 1 The configuration tree has been rebuilt. * * The global configuration files are specified in the environment variable * \c ALSA_CONFIG_PATH. If this is not set, the default value is * "/usr/share/alsa/alsa.conf". * * \warning If the configuration tree is reread, all string pointers and * configuration node handles previously obtained from this tree become invalid. */ int snd_config_update(void) { int err; #ifdef HAVE_LIBPTHREAD pthread_mutex_lock(&snd_config_update_mutex); #endif err = snd_config_update_r(&snd_config, &snd_config_global_update, NULL); #ifdef HAVE_LIBPTHREAD pthread_mutex_unlock(&snd_config_update_mutex); #endif return err; }


又调到snd_config_update_r()函数了。



/** * \brief Updates a configuration tree by rereading the configuration files (if needed). * \param _top Address of the handle to the top level node. * \param _update Address of a pointer to private update information. * \param cfgs A list of configuration file names, delimited with ':'. * If \p cfgs is set to \c NULL, the default global configuration * file is used ("/usr/share/alsa/alsa.conf"). * \return A non-negative value if successful, otherwise a negative error code. * \retval 0 No action is needed. * \retval 1 The configuration tree has been rebuilt. * * The global configuration files are specified in the environment variable * \c ALSA_CONFIG_PATH. * * \warning If the configuration tree is reread, all string pointers and * configuration node handles previously obtained from this tree become invalid. */ int snd_config_update_r(snd_config_t **_top, snd_config_update_t **_update, const char *cfgs) // cfgs = NULL { ...... configs = cfgs; if (!configs) { configs = getenv(ALSA_CONFIG_PATH_VAR); // ??? if (!configs || !*configs) { configs = ALSA_CONFIG_PATH_DEFAULT; // 宏ALSA_CONFIG_PATH_DEFAULT // 便是/usr/share/alsa/alsa.conf ....... }

这里提到要读取配置文件/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节点真是对具体的音频设备的硬件参数的配置。可以配置的硬件参数如下:


pcm.name { type hw # Kernel PCM card INT/STR # Card name (string) or number (integer) [device INT] # Device number (default 0) [subdevice INT] # Subdevice number (default -1: first available) [sync_ptr_ioctl BOOL] # Use SYNC_PTR ioctl rather than the direct mmap access for control structures [nonblock BOOL] # Force non-blocking open mode [format STR] # Restrict only to the given format [channels INT] # Restrict only to the given channels [rate INT] # Restrict only to the given rate }

仅举一例

pcm.AndroidCapture_Usb-audio_normal { // 此PCM节点为录音设备的PCM节点  type hooks slave.pcm "hw:1,0" // 1:表示声卡1(声卡0就是系统内嵌的声卡),0表示声卡1上的设备编号为0的设备 }

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


/* The following table(s) need to match in order of the route bits */ static const device_suffix_t deviceSuffix[] = { {android_audio_legacy::AudioSystem::DEVICE_OUT_EARPIECE, "_Earpiece"}, {android_audio_legacy::AudioSystem::DEVICE_OUT_SPEAKER, "_Speaker"}, {android_audio_legacy::AudioSystem::DEVICE_OUT_BLUETOOTH_SCO, "_Bluetooth"}, {android_audio_legacy::AudioSystem::DEVICE_OUT_WIRED_HEADSET, "_Headset"}, {android_audio_legacy::AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP, "_Bluetooth-A2DP"},  {android_audio_legacy::AudioSystem::DEVICE_OUT_USB_AUDIO, "_Usb-audio"}, {android_audio_legacy::AudioSystem::DEVICE_IN_USB_AUDIO, "_Usb-audio"}, };

在此配置文件中,不要指定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中读取(只需读取录音部分的)。


$ cat /proc/asound/card1/stream0 SAGE Technology SAGE AirMouse at usb-0000:00:1d.3-2, full speed : USB Audio Playback: Status: Stop Interface 2 Altset 1 Format: S16_LE Channels: 1 Endpoint: 6 OUT (NONE) Rates: 16000 Capture: Status: Stop Interface 1 Altset 1 Format: S16_LE Channels: 1 // 这个声道数与默认值2不一致  Endpoint: 5 IN (NONE) Rates: 16000 // 这个采样率与默认值48000不一致 


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


sound/usb/card.c drivers/hid/hid-input.c


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


external/alsa-lib/src/pcm/pcm_rate.c

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


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


 for (;;) { // The PCM stream is opened in blocking mode, per ALSA defaults. The // AudioFlinger seems to assume blocking mode too, so asynchronous mode // should not be used. err = snd_pcm_open(&handle->handle, devName, direction(handle), ....... } if (err < 0) { //要在此处把输入音频通道的声道数和采样率改回默认值  // None of the Android defined audio devices exist. Open a generic one. devName = "default"; err = snd_pcm_open(&handle->handle, devName, direction(handle), 0); }


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




更多相关文章

  1. Android中关于Handler looper参数设置问题
  2. android:orientation参数说明
  3. Android 依赖注入函数库Roboguice(一)
  4. Android音频可视化开发案例说明
  5. Android中关于外部存储的一些重要函数
  6. Android 2.2中的APK安装参数installLocation
  7. android音频系统音量控制探讨
  8. Android NDK开发——操作JNI函数以及复杂对象的传递
  9. [置顶] android音频通信(三)——双向通信(A2B协议)之手机接收

随机推荐

  1. C中fork()和exec()之间的区别是什么?fork(
  2. 在C++中对象如何作为参数传递和返回?(代码
  3. 【C语言】递归和非递归分别实现strlen
  4. C++中动态内存分配与命名空间介绍
  5. C++中如何避免内存泄漏?
  6. 【C++趣味程序】之开心消消乐
  7. C中scanf()和gets()之间的区别(代码示例)
  8. C中如何声明指向函数的指针?
  9. C++实现在二维数组中的查找
  10. C#中的Console.Read()方法详解