zoukankan      html  css  js  c++  java
  • 转:ANDROID音频系统散记之四:4.0音频系统HAL初探

    昨天(2011-11-15)发布了Android4.0的源码,今天download下来,开始挺进4.0时代。简单看了一下,发现音频系统方面与2.3的有较多地方不同,下面逐一描述。

    一、代码模块位置

    1、AudioFlinger

     
    1. frameworks/base/services/audioflinger/  
    2. +-- Android.mk  
    3. +-- AudioBufferProvider.h  
    4. +-- AudioFlinger.cpp  
    5. +-- AudioFlinger.h  
    6. +-- AudioMixer.cpp  
    7. +-- AudioMixer.h  
    8. +-- AudioPolicyService.cpp  
    9. +-- AudioPolicyService.h  
    10. +-- AudioResampler.cpp  
    11. +-- AudioResamplerCubic.cpp  
    12. +-- AudioResamplerCubic.h  
    13. +-- AudioResampler.h  
    14. +-- AudioResamplerSinc.cpp  
    15. +-- AudioResamplerSinc.h  
    AudioFlinger相关代码,好像这部分与2.3相差不大,至少接口是兼容的。值得注意的是:2.3位于这里的还有AudioHardwareGeneric、AudioHardwareInterface、A2dpAudioInterface等一系列接口代码,现在都移除了。实际上,这些接口变更为legacy(有另外更好的实现方式,但也兼容之前的方法),取而代之的是要实现hardware/libhardware/include/hardware/audio.h提供的接口,这是一个较大的变化。
     
    两种Audio Hardware HAL接口定义:
    1/ legacy:hardware/libhardware_legacy/include/hardware_legacy/AudioHardwareInterface.h
    2/ current:hardware/libhardware/include/hardware/audio.h

    2、audio_hw

     
    1. hardware/libhardware_legacy/audio/  
    2. +-- A2dpAudioInterface.cpp  
    3. +-- A2dpAudioInterface.h  
    4. +-- Android.mk  
    5. +-- AudioDumpInterface.cpp  
    6. +-- AudioDumpInterface.h  
    7. +-- AudioHardwareGeneric.cpp  
    8. +-- AudioHardwareGeneric.h  
    9. +-- AudioHardwareInterface.cpp  
    10. +-- AudioHardwareStub.cpp  
    11. +-- AudioHardwareStub.h  
    12. +-- audio_hw_hal.cpp  
    13. +-- AudioPolicyCompatClient.cpp  
    14. +-- AudioPolicyCompatClient.h  
    15. +-- audio_policy_hal.cpp  
    16. +-- AudioPolicyManagerBase.cpp  
    17. +-- AudioPolicyManagerDefault.cpp  
    18. +-- AudioPolicyManagerDefault.h  
    上面提及的AudioHardwareGeneric、AudioHardwareInterface、A2dpAudioInterface等都放到libhardware_legacy里。
    事实上legacy也要封装成current中的audio.h,确切的说需要一个联系legacy interface和not legacy interface的中间层,这里的audio_hw_hal.cpp就充当这样的一个角色了。因此,我们其实也可以把2.3之前的alsa_sound这一套东西也搬过来。
     
    1. hardware/libhardware/modules/audio/  
    2. +-- Android.mk  
    3. +-- audio_hw.c  
    4. +-- audio_policy.c  
    这是一个stub(类似于2.3中的AudioHardwareStub),大多数函数只是简单的返回一个值,并没有实际操作,只是保证Android能得到一个audio hardware hal实例,从而启动运行,当然声音没有输出到外设的。在底层音频驱动或audio hardware hal还没有实现好的情况下,可以使用这个stub device,先让Android跑起来。
     
    1. device/samsung/tuna/audio/  
    2. +-- Android.mk  
    3. +-- audio_hw.c  
    4. +-- ril_interface.c  
    5. +-- ril_interface.h  
    这是Samsung Tuna的音频设备抽象层,很有参考价值,计划以后就在它的基础上进行移植。它调用tinyalsa的接口,可见这个方案的底层音频驱动是alsa。
     

    3、tinyalsa

     
    1. external/tinyalsa/  
    2. +-- Android.mk  
    3. +-- include  
    4. |   +-- tinyalsa  
    5. |       +-- asoundlib.h  
    6. +-- mixer.c      ##类alsa-lib的control,作用音频部件开关、音量调节等  
    7. +-- pcm.c        ##类alsa-lib的pcm,作用音频pcm数据回放录制  
    8. +-- README  
    9. +-- tinycap.c    ##类alsa_arecord  
    10. +-- tinymix.c    ##类alsa_amixer  
    11. +-- tinyplay.c   ##类alsa_aplay  
    在2.3时代,Android还隐晦把它放在android2.3.1-gingerbread/device/samsung/crespo/libaudio,现在终于把alsa-lib一脚踢开,小三变正室了,正名tinyalsa。
    这其实是历史的必然了,alsa-lib太过复杂繁琐了,我看得也很不爽;更重要的商业上面的考虑,必须移除被GNU GPL授权证所约束的部份,alsa-lib并不是个例。

    注意:上面的hardware/libhardware_legacy/audio/、hardware/libhardware/modules/audio/、device/samsung/tuna/audio/是同层的。之一是legacy audio,用于兼容2.2时代的alsa_sound;之二是stub audio接口;之三是Samsung Tuna的音频抽象层实现。调用层次:AudioFlinger -> audio_hw -> tinyalsa。
     

    二、Audio Hardware HAL加载

     

    1、AudioFlinger

     
    1. //加载audio hardware hal  
    2. static int load_audio_interface(const char *if_name, const hw_module_t **mod,  
    3.                                 audio_hw_device_t **dev)  
    4. {  
    5.     int rc;  
    6.       
    7.     //根据classid和if_name找到指定的动态库并加载,这里加载的是音频动态库,如libaudio.primary.tuna.so  
    8.     rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, mod);  
    9.     if (rc)  
    10.         goto out;  
    11.   
    12.     //加载好的动态库模块必有个open方法,调用open方法打开音频设备模块  
    13.     rc = audio_hw_device_open(*mod, dev);  
    14.     LOGE_IF(rc, "couldn't open audio hw device in %s.%s (%s)",  
    15.             AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc));  
    16.     if (rc)  
    17.         goto out;  
    18.   
    19.     return 0;  
    20.   
    21. out:  
    22.     *mod = NULL;  
    23.     *dev = NULL;  
    24.     return rc;  
    25. }  
    26.   
    27. //音频设备接口,hw_get_module_by_class需要根据这些字符串找到相关的音频模块库  
    28. static const char *audio_interfaces[] = {  
    29.     "primary", //主音频设备,一般为本机codec  
    30.     "a2dp",    //a2dp设备,蓝牙高保真音频  
    31.     "usb",     //usb-audio设备,这个东东我2.3就考虑要实现了,现在终于支持了  
    32. };  
    33. #define ARRAY_SIZE(x) (sizeof((x))/sizeof(((x)[0])))  
    34.   
    35. // ----------------------------------------------------------------------------  
    36.   
    37. AudioFlinger::AudioFlinger()  
    38.     : BnAudioFlinger(),  
    39.         mPrimaryHardwareDev(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1),  
    40.         mBtNrecIsOff(false)  
    41. {  
    42. }  
    43.   
    44. void AudioFlinger::onFirstRef()  
    45. {  
    46.     int rc = 0;  
    47.   
    48.     Mutex::Autolock _l(mLock);  
    49.   
    50.     /* TODO: move all this work into an Init() function */  
    51.     mHardwareStatus = AUDIO_HW_IDLE;  
    52.   
    53.     //打开audio_interfaces数组定义的所有音频设备  
    54.     for (size_t i = 0; i < ARRAY_SIZE(audio_interfaces); i++) {  
    55.         const hw_module_t *mod;  
    56.         audio_hw_device_t *dev;  
    57.   
    58.         rc = load_audio_interface(audio_interfaces[i], &mod, &dev);  
    59.         if (rc)  
    60.             continue;  
    61.   
    62.         LOGI("Loaded %s audio interface from %s (%s)", audio_interfaces[i],  
    63.              mod->name, mod->id);  
    64.         mAudioHwDevs.push(dev); //mAudioHwDevs是一个Vector,存储已打开的audio hw devices  
    65.   
    66.         if (!mPrimaryHardwareDev) {  
    67.             mPrimaryHardwareDev = dev;  
    68.             LOGI("Using '%s' (%s.%s) as the primary audio interface",  
    69.                  mod->name, mod->id, audio_interfaces[i]);  
    70.         }  
    71.     }  
    72.   
    73.     mHardwareStatus = AUDIO_HW_INIT;  
    74.   
    75.     if (!mPrimaryHardwareDev || mAudioHwDevs.size() == 0) {  
    76.         LOGE("Primary audio interface not found");  
    77.         return;  
    78.     }  
    79.   
    80.     //对audio hw devices进行一些初始化,如mode、master volume的设置  
    81.     for (size_t i = 0; i < mAudioHwDevs.size(); i++) {  
    82.         audio_hw_device_t *dev = mAudioHwDevs[i];  
    83.   
    84.         mHardwareStatus = AUDIO_HW_INIT;  
    85.         rc = dev->init_check(dev);  
    86.         if (rc == 0) {  
    87.             AutoMutex lock(mHardwareLock);  
    88.   
    89.             mMode = AUDIO_MODE_NORMAL;  
    90.             mHardwareStatus = AUDIO_HW_SET_MODE;  
    91.             dev->set_mode(dev, mMode);  
    92.             mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;  
    93.             dev->set_master_volume(dev, 1.0f);  
    94.             mHardwareStatus = AUDIO_HW_IDLE;  
    95.         }  
    96.     }  
    97. }  

    以上对AudioFlinger进行的分析,主要是通过hw_get_module_by_class()找到模块接口名字if_name相匹配的模块库,加载,然后audio_hw_device_open()调用模块的open方法,完成音频设备模块的初始化。
     
    留意AudioFlinger的构造函数只有简单的私有变量的初始化操作了,把音频设备初始化放到onFirstRef(),Android终于改进了这一点,好的设计根本不应该把可能会失败的操作放到构造函数中。onFirstRef是RefBase类的一个虚函数,在构造sp的时候就会被调用。因此,在构造sp<AudioFlinger>的时候就会触发onFirstRef方法,从而完成音频设备模块初始化。
     

    2、hw_get_module_by_class

     
    我们接下来看看hw_get_module_by_class,实现在hardware/libhardware/ hardware.c中,它作用加载指定名字的模块库(.so文件),这个应该是用于加载所有硬件设备相关的库文件,并不只是音频设备。
    1. int hw_get_module_by_class(const char *class_id, const char *inst,  
    2.                            const struct hw_module_t **module)  
    3. {  
    4.     int status;  
    5.     int i;  
    6.     const struct hw_module_t *hmi = NULL;  
    7.     char prop[PATH_MAX];  
    8.     char path[PATH_MAX];  
    9.     char name[PATH_MAX];  
    10.   
    11.     if (inst)  
    12.         snprintf(name, PATH_MAX, "%s.%s", class_id, inst);  
    13.     else  
    14.         strlcpy(name, class_id, PATH_MAX);  
    15.           
    16.     //这里我们以音频库为例,AudioFlinger调用到这个函数时,  
    17.     //class_id=AUDIO_HARDWARE_MODULE_ID="audio",inst="primary"(或"a2dp"或"usb")  
    18.     //那么此时name="audio.primary"  
    19.   
    20.     /* 
    21.      * Here we rely on the fact that calling dlopen multiple times on 
    22.      * the same .so will simply increment a refcount (and not load 
    23.      * a new copy of the library). 
    24.      * We also assume that dlopen() is thread-safe. 
    25.      */  
    26.   
    27.     /* Loop through the configuration variants looking for a module */  
    28.     for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) {  
    29.         if (i < HAL_VARIANT_KEYS_COUNT) {  
    30.               //通过property_get找到厂家标记如"ro.product.board=tuna",这时prop="tuna"  
    31.             if (property_get(variant_keys[i], prop, NULL) == 0) {  
    32.                 continue;  
    33.             }  
    34.             snprintf(path, sizeof(path), "%s/%s.%s.so",  
    35.                      HAL_LIBRARY_PATH2, name, prop); //#define HAL_LIBRARY_PATH2 "/vendor/lib/hw"  
    36.             if (access(path, R_OK) == 0) break;  
    37.   
    38.             snprintf(path, sizeof(path), "%s/%s.%s.so",  
    39.                      HAL_LIBRARY_PATH1, name, prop); //#define HAL_LIBRARY_PATH1 "/system/lib/hw"  
    40.             if (access(path, R_OK) == 0) break;  
    41.         } else {  
    42.             snprintf(path, sizeof(path), "%s/%s.default.so", //如没有指定的库文件,则加载default.so,即stub-device  
    43.                      HAL_LIBRARY_PATH1, name);  
    44.             if (access(path, R_OK) == 0) break;  
    45.         }  
    46.     }  
    47.     //到这里,完成一个模块库的完整路径名称,如path="/system/lib/hw/audio.primary.tuna.so"  
    48.     //如何生成audio.primary.tuna.so?请看相关的Android.mk文件,其中有定义LOCAL_MODULE := audio.primary.tuna  
    49.   
    50.     status = -ENOENT;  
    51.     if (i < HAL_VARIANT_KEYS_COUNT+1) {  
    52.         /* load the module, if this fails, we're doomed, and we should not try 
    53.          * to load a different variant. */  
    54.         status = load(class_id, path, module); //加载模块库  
    55.     }  
    56.   
    57.     return status;  
    58. }  
     
    load()函数不详细分析了,它通过dlopen加载库文件,然后dlsym找到hal_module_info的首地址。我们先看看hal_module_info的定义:
    1. /** 
    2.  * Every hardware module must have a data structure named HAL_MODULE_INFO_SYM 
    3.  * and the fields of this data structure must begin with hw_module_t 
    4.  * followed by module specific information. 
    5.  */  
    6. typedef struct hw_module_t {  
    7.     /** tag must be initialized to HARDWARE_MODULE_TAG */  
    8.     uint32_t tag;  
    9.   
    10.     /** major version number for the module */  
    11.     uint16_t version_major;  
    12.   
    13.     /** minor version number of the module */  
    14.     uint16_t version_minor;  
    15.   
    16.     /** Identifier of module */  
    17.     const char *id;  
    18.   
    19.     /** Name of this module */  
    20.     const char *name;  
    21.   
    22.     /** Author/owner/implementor of the module */  
    23.     const char *author;  
    24.   
    25.     /** Modules methods */  
    26.     struct hw_module_methods_t* methods;  
    27.   
    28.     /** module's dso */  
    29.     void* dso;  
    30.   
    31.     /** padding to 128 bytes, reserved for future use */  
    32.     uint32_t reserved[32-7];  
    33.   
    34. } hw_module_t;  
    35.   
    36. typedef struct hw_module_methods_t {  
    37.     /** Open a specific device */  
    38.     int (*open)(const struct hw_module_t* module, const char* id,  
    39.             struct hw_device_t** device);  
    40.   
    41. } hw_module_methods_t;  
    这个结构体很重要,注释很详细。dlsym拿到这个结构体的首地址后,就可以调用Modules methods进行设备模块的初始化了。设备模块中,都应该按照这个格式初始化好这个结构体,否则dlsym找不到它,也就无法调用Modules methods进行初始化了。
     
    例如,在audio_hw.c中,它是这样定义的:
    1. static struct hw_module_methods_t hal_module_methods = {  
    2.     .open = adev_open,  
    3. };  
    4.   
    5. struct audio_module HAL_MODULE_INFO_SYM = {  
    6.     .common = {  
    7.         .tag = HARDWARE_MODULE_TAG,  
    8.         .version_major = 1,  
    9.         .version_minor = 0,  
    10.         .id = AUDIO_HARDWARE_MODULE_ID,  
    11.         .name = "Tuna audio HW HAL",  
    12.         .author = "The Android Open Source Project",  
    13.         .methods = &hal_module_methods,  
    14.     },  
    15. };  

    3、audio_hw

     
    好了,经过一番周折,又dlopen又dlsym的,终于进入我们的audio_hw。这部分没什么好说的,按照hardware/libhardware/include/hardware/audio.h定义的接口实现就行了。这些接口全扔到一个结构体里面的,这样做的好处是:不必用大量的dlsym来获取各个接口函数的地址,只需找到这个结构体即可,从易用性和可扩充性来说,都是首选方式。
     
    接口定义如下:
    1. struct audio_hw_device {  
    2.     struct hw_device_t common;  
    3.   
    4.     /** 
    5.      * used by audio flinger to enumerate what devices are supported by 
    6.      * each audio_hw_device implementation. 
    7.      * 
    8.      * Return value is a bitmask of 1 or more values of audio_devices_t 
    9.      */  
    10.     uint32_t (*get_supported_devices)(const struct audio_hw_device *dev);  
    11.   
    12.     /** 
    13.      * check to see if the audio hardware interface has been initialized. 
    14.      * returns 0 on success, -ENODEV on failure. 
    15.      */  
    16.     int (*init_check)(const struct audio_hw_device *dev);  
    17.   
    18.     /** set the audio volume of a voice call. Range is between 0.0 and 1.0 */  
    19.     int (*set_voice_volume)(struct audio_hw_device *dev, float volume);  
    20.   
    21.     /** 
    22.      * set the audio volume for all audio activities other than voice call. 
    23.      * Range between 0.0 and 1.0. If any value other than 0 is returned, 
    24.      * the software mixer will emulate this capability. 
    25.      */  
    26.     int (*set_master_volume)(struct audio_hw_device *dev, float volume);  
    27.   
    28.     /** 
    29.      * setMode is called when the audio mode changes. AUDIO_MODE_NORMAL mode 
    30.      * is for standard audio playback, AUDIO_MODE_RINGTONE when a ringtone is 
    31.      * playing, and AUDIO_MODE_IN_CALL when a call is in progress. 
    32.      */  
    33.     int (*set_mode)(struct audio_hw_device *dev, int mode);  
    34.   
    35.     /* mic mute */  
    36.     int (*set_mic_mute)(struct audio_hw_device *dev, bool state);  
    37.     int (*get_mic_mute)(const struct audio_hw_device *dev, bool *state);  
    38.   
    39.     /* set/get global audio parameters */  
    40.     int (*set_parameters)(struct audio_hw_device *dev, const char *kv_pairs);  
    41.   
    42.     /* 
    43.      * Returns a pointer to a heap allocated string. The caller is responsible 
    44.      * for freeing the memory for it. 
    45.      */  
    46.     char * (*get_parameters)(const struct audio_hw_device *dev,  
    47.                              const char *keys);  
    48.   
    49.     /* Returns audio input buffer size according to parameters passed or 
    50.      * 0 if one of the parameters is not supported 
    51.      */  
    52.     size_t (*get_input_buffer_size)(const struct audio_hw_device *dev,  
    53.                                     uint32_t sample_rate, int format,  
    54.                                     int channel_count);  
    55.   
    56.     /** This method creates and opens the audio hardware output stream */  
    57.     int (*open_output_stream)(struct audio_hw_device *dev, uint32_t devices,  
    58.                               int *format, uint32_t *channels,  
    59.                               uint32_t *sample_rate,  
    60.                               struct audio_stream_out **out);  
    61.   
    62.     void (*close_output_stream)(struct audio_hw_device *dev,  
    63.                                 struct audio_stream_out* out);  
    64.   
    65.     /** This method creates and opens the audio hardware input stream */  
    66.     int (*open_input_stream)(struct audio_hw_device *dev, uint32_t devices,  
    67.                              int *format, uint32_t *channels,  
    68.                              uint32_t *sample_rate,  
    69.                              audio_in_acoustics_t acoustics,  
    70.                              struct audio_stream_in **stream_in);  
    71.   
    72.     void (*close_input_stream)(struct audio_hw_device *dev,  
    73.                                struct audio_stream_in *in);  
    74.   
    75.     /** This method dumps the state of the audio hardware */  
    76.     int (*dump)(const struct audio_hw_device *dev, int fd);  
    77. };  
    78. typedef struct audio_hw_device audio_hw_device_t;  
     
    注:这是比较标准的C接口设计方法了,但是个人感觉还是用C++比较好,直观易读。2.3之前都是用C++实现这些接口设计的,到了4.0,不知道为何采纳用C?不会理由是做底层的不懂C++吧?!

    三、Audio Hardware HAL的legacy实现

     
    之前提到两种Audio Hardware HAL接口定义:
    1/ legacy:hardware/libhardware_legacy/include/hardware_legacy/AudioHardwareInterface.h
    2/ current:hardware/libhardware/include/hardware/audio.h
    前者是2.3及之前的音频设备接口定义,后者是4.0的接口定义。

    为了兼容以前的设计,4.0实现一个中间层:hardware/libhardware_legacy/audio/audio_hw_hal.cpp,结构与其他的audio_hw.c大同小异,差别在于open方法:
    1. static int legacy_adev_open(const hw_module_t* module, const char* name,  
    2.                             hw_device_t** device)  
    3. {  
    4.     ......  
    5.   
    6.     ladev->hwif = createAudioHardware();  
    7.     if (!ladev->hwif) {  
    8.         ret = -EIO;  
    9.         goto err_create_audio_hw;  
    10.     }  
    11.   
    12.     ......  
    13. }  
    看到那个熟悉的createAudioHardware()没有?这是以前我提到的Vendor Specific Audio接口,然后新的接口再调用ladev->hwif的函数就是了。
    因此老一套的alsa-lib、alsa-utils和alsa_sound也可以照搬过来,这里的文件被编译成静态库的,因此你需要修改alsa_sound里面的Android.mk文件,链接这个静态库。还有alsa_sound的命名空间原来是“android”,现在需要改成“android_audio_legacy”。

    四、a2dp Audio HAL的实现

     
    4.0的a2dp audio hal放到bluez里实现了,我找了好一会才找到:
    external/Bluetooth/bluez/audio/android_audio_hw.c
    大致与上面提到的audio_hw.c类似,因为都是基于audio.h定义的接口来实现的。
    如果需要编译这个库,须在BoardConfig.mk里定义:
    BOARD_HAVE_BLUETOOTH := true

    开始还提到现在支持3种audio设备了,分别是primary、a2dp和usb。目前剩下usb audio hal我没有找到,不知是否需要自己去实现?其实alsa-driver都支持大部分的usb-audio设备了,因此上层也可调用tinyalsa的接口,就像samsung tuna的audio_hw.c那样。

    五、音质改进???

     
    可使用audio echo cancel和更好的resampler(SRC)???

    --to be continued…
     
    转自:http://blog.csdn.net/azloong/article/details/6978484
  • 相关阅读:
    Leetcode 15 3Sum
    Leetcode 383 Ransom Note
    用i个点组成高度为不超过j的二叉树的数量。
    配对问题 小于10 1.3.5
    字符矩阵的旋转 镜面对称 1.2.2
    字符串统计 连续的某个字符的数量 1.1.4
    USACO twofive 没理解
    1002 All Roads Lead to Rome
    USACO 5.5.1 求矩形并的周长
    USACO 5.5.2 字符串的最小表示法
  • 原文地址:https://www.cnblogs.com/albert1017/p/3949398.html
Copyright © 2011-2022 走看看