一、代码模块位置


1、AudioFlinger


[plain] view plain copy
  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/ 非legacy:hardware/libhardware/include/hardware/audio.h

2、audio_hw


[plain] view plain copy
  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也要封装成非legacy中的audio.h,确切的说需要一个联系legacy interface和not legacy interface的中间层,这里的audio_hw_hal.cpp就充当这样的一个角色了。因此,我们其实也可以把2.3之前的alsa_sound这一套东西也搬过来。
[plain] view plain copy
  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跑起来。
[plain] view plain copy
  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


[plain] view plain copy
  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


[cpp] view plain copy
  1. //加载audiohardwarehal
  2. staticintload_audio_interface(constchar*if_name,consthw_module_t**mod,
  3. audio_hw_device_t**dev)
  4. {
  5. intrc;
  6. //根据classid和if_name找到指定的动态库并加载,这里加载的是音频动态库,如libaudio.primary.tuna.so
  7. rc=hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID,if_name,mod);
  8. if(rc)
  9. gotoout;
  10. //加载好的动态库模块必有个open方法,调用open方法打开音频设备模块
  11. rc=audio_hw_device_open(*mod,dev);
  12. LOGE_IF(rc,"couldn'topenaudiohwdevicein%s.%s(%s)",
  13. AUDIO_HARDWARE_MODULE_ID,if_name,strerror(-rc));
  14. if(rc)
  15. gotoout;
  16. return0;
  17. out:
  18. *mod=NULL;
  19. *dev=NULL;
  20. returnrc;
  21. }
  22. //音频设备接口,hw_get_module_by_class需要根据这些字符串找到相关的音频模块库
  23. staticconstchar*audio_interfaces[]={
  24. "primary",//主音频设备,一般为本机codec
  25. "a2dp",//a2dp设备,蓝牙高保真音频
  26. "usb",//usb-audio设备,这个东东我2.3就考虑要实现了,现在终于支持了
  27. };
  28. #defineARRAY_SIZE(x)(sizeof((x))/sizeof(((x)[0])))
  29. //----------------------------------------------------------------------------
  30. AudioFlinger::AudioFlinger()
  31. :BnAudioFlinger(),
  32. mPrimaryHardwareDev(0),mMasterVolume(1.0f),mMasterMute(false),mNextUniqueId(1),
  33. mBtNrecIsOff(false)
  34. {
  35. }
  36. voidAudioFlinger::onFirstRef()
  37. {
  38. intrc=0;
  39. Mutex::Autolock_l(mLock);
  40. /*TODO:moveallthisworkintoanInit()function*/
  41. mHardwareStatus=AUDIO_HW_IDLE;
  42. //打开audio_interfaces数组定义的所有音频设备
  43. for(size_ti=0;i<ARRAY_SIZE(audio_interfaces);i++){
  44. consthw_module_t*mod;
  45. audio_hw_device_t*dev;
  46. rc=load_audio_interface(audio_interfaces[i],&mod,&dev);
  47. if(rc)
  48. continue;
  49. LOGI("Loaded%saudiointerfacefrom%s(%s)",audio_interfaces[i],
  50. mod->name,mod->id);
  51. mAudioHwDevs.push(dev);//mAudioHwDevs是一个Vector,存储已打开的audiohwdevices
  52. if(!mPrimaryHardwareDev){
  53. mPrimaryHardwareDev=dev;
  54. LOGI("Using'%s'(%s.%s)astheprimaryaudiointerface",
  55. mod->name,mod->id,audio_interfaces[i]);
  56. }
  57. }
  58. mHardwareStatus=AUDIO_HW_INIT;
  59. if(!mPrimaryHardwareDev||mAudioHwDevs.size()==0){
  60. LOGE("Primaryaudiointerfacenotfound");
  61. return;
  62. }
  63. //对audiohwdevices进行一些初始化,如mode、mastervolume的设置
  64. for(size_ti=0;i<mAudioHwDevs.size();i++){
  65. audio_hw_device_t*dev=mAudioHwDevs[i];
  66. mHardwareStatus=AUDIO_HW_INIT;
  67. rc=dev->init_check(dev);
  68. if(rc==0){
  69. AutoMutexlock(mHardwareLock);
  70. mMode=AUDIO_MODE_NORMAL;
  71. mHardwareStatus=AUDIO_HW_SET_MODE;
  72. dev->set_mode(dev,mMode);
  73. mHardwareStatus=AUDIO_HW_SET_MASTER_VOLUME;
  74. dev->set_master_volume(dev,1.0f);
  75. mHardwareStatus=AUDIO_HW_IDLE;
  76. }
  77. }
  78. }

以上对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文件),这个应该是用于加载所有硬件设备相关的库文件,并不只是音频设备。
[cpp] view plain copy
  1. inthw_get_module_by_class(constchar*class_id,constchar*inst,
  2. conststructhw_module_t**module)
  3. {
  4. intstatus;
  5. inti;
  6. conststructhw_module_t*hmi=NULL;
  7. charprop[PATH_MAX];
  8. charpath[PATH_MAX];
  9. charname[PATH_MAX];
  10. if(inst)
  11. snprintf(name,PATH_MAX,"%s.%s",class_id,inst);
  12. else
  13. strlcpy(name,class_id,PATH_MAX);
  14. //这里我们以音频库为例,AudioFlinger调用到这个函数时,
  15. //class_id=AUDIO_HARDWARE_MODULE_ID="audio",inst="primary"(或"a2dp"或"usb")
  16. //那么此时name="audio.primary"
  17. /*
  18. *Herewerelyonthefactthatcallingdlopenmultipletimeson
  19. *thesame.sowillsimplyincrementarefcount(andnotload
  20. *anewcopyofthelibrary).
  21. *Wealsoassumethatdlopen()isthread-safe.
  22. */
  23. /*Loopthroughtheconfigurationvariantslookingforamodule*/
  24. for(i=0;i<HAL_VARIANT_KEYS_COUNT+1;i++){
  25. if(i<HAL_VARIANT_KEYS_COUNT){
  26. //通过property_get找到厂家标记如"ro.product.board=tuna",这时prop="tuna"
  27. if(property_get(variant_keys[i],prop,NULL)==0){
  28. continue;
  29. }
  30. snprintf(path,sizeof(path),"%s/%s.%s.so",
  31. HAL_LIBRARY_PATH2,name,prop);//#defineHAL_LIBRARY_PATH2"/vendor/lib/hw"
  32. if(access(path,R_OK)==0)break;
  33. snprintf(path,sizeof(path),"%s/%s.%s.so",
  34. HAL_LIBRARY_PATH1,name,prop);//#defineHAL_LIBRARY_PATH1"/system/lib/hw"
  35. if(access(path,R_OK)==0)break;
  36. }else{
  37. snprintf(path,sizeof(path),"%s/%s.default.so",//如没有指定的库文件,则加载default.so,即stub-device
  38. HAL_LIBRARY_PATH1,name);
  39. if(access(path,R_OK)==0)break;
  40. }
  41. }
  42. //到这里,完成一个模块库的完整路径名称,如path="/system/lib/hw/audio.primary.tuna.so"
  43. //如何生成audio.primary.tuna.so?请看相关的Android.mk文件,其中有定义LOCAL_MODULE:=audio.primary.tuna
  44. status=-ENOENT;
  45. if(i<HAL_VARIANT_KEYS_COUNT+1){
  46. /*loadthemodule,ifthisfails,we'redoomed,andweshouldnottry
  47. *toloadadifferentvariant.*/
  48. status=load(class_id,path,module);//加载模块库
  49. }
  50. returnstatus;
  51. }

load()函数不详细分析了,它通过dlopen加载库文件,然后dlsym找到hal_module_info的首地址。我们先看看hal_module_info的定义: [cpp] view plain copy
  1. /**
  2. *EveryhardwaremodulemusthaveadatastructurenamedHAL_MODULE_INFO_SYM
  3. *andthefieldsofthisdatastructuremustbeginwithhw_module_t
  4. *followedbymodulespecificinformation.
  5. */
  6. typedefstructhw_module_t{
  7. /**tagmustbeinitializedtoHARDWARE_MODULE_TAG*/
  8. uint32_ttag;
  9. /**majorversionnumberforthemodule*/
  10. uint16_tversion_major;
  11. /**minorversionnumberofthemodule*/
  12. uint16_tversion_minor;
  13. /**Identifierofmodule*/
  14. constchar*id;
  15. /**Nameofthismodule*/
  16. constchar*name;
  17. /**Author/owner/implementorofthemodule*/
  18. constchar*author;
  19. /**Modulesmethods*/
  20. structhw_module_methods_t*methods;
  21. /**module'sdso*/
  22. void*dso;
  23. /**paddingto128bytes,reservedforfutureuse*/
  24. uint32_treserved[32-7];
  25. }hw_module_t;
  26. typedefstructhw_module_methods_t{
  27. /**Openaspecificdevice*/
  28. int(*open)(conststructhw_module_t*module,constchar*id,
  29. structhw_device_t**device);
  30. }hw_module_methods_t;
这个结构体很重要,注释很详细。dlsym拿到这个结构体的首地址后,就可以调用Modules methods进行设备模块的初始化了。设备模块中,都应该按照这个格式初始化好这个结构体,否则dlsym找不到它,也就无法调用Modules methods进行初始化了。
例如,在audio_hw.c中,它是这样定义的: [cpp] view plain copy
  1. staticstructhw_module_methods_thal_module_methods={
  2. .open=adev_open,
  3. };
  4. structaudio_moduleHAL_MODULE_INFO_SYM={
  5. .common={
  6. .tag=HARDWARE_MODULE_TAG,
  7. .version_major=1,
  8. .version_minor=0,
  9. .id=AUDIO_HARDWARE_MODULE_ID,
  10. .name="TunaaudioHWHAL",
  11. .author="TheAndroidOpenSourceProject",
  12. .methods=&hal_module_methods,
  13. },
  14. };

3、audio_hw


好了,经过一番周折,又dlopen又dlsym的,终于进入我们的audio_hw。这部分没什么好说的,按照hardware/libhardware/include/hardware/audio.h定义的接口实现就行了。这些接口全扔到一个结构体里面的,这样做的好处是:不必用大量的dlsym来获取各个接口函数的地址,只需找到这个结构体即可,从易用性和可扩充性来说,都是首选方式。

接口定义如下:
[cpp] view plain copy
  1. structaudio_hw_device{
  2. structhw_device_tcommon;
  3. /**
  4. *usedbyaudioflingertoenumeratewhatdevicesaresupportedby
  5. *eachaudio_hw_deviceimplementation.
  6. *
  7. *Returnvalueisabitmaskof1ormorevaluesofaudio_devices_t
  8. */
  9. uint32_t(*get_supported_devices)(conststructaudio_hw_device*dev);
  10. /**
  11. *checktoseeiftheaudiohardwareinterfacehasbeeninitialized.
  12. *returns0onsuccess,-ENODEVonfailure.
  13. */
  14. int(*init_check)(conststructaudio_hw_device*dev);
  15. /**settheaudiovolumeofavoicecall.Rangeisbetween0.0and1.0*/
  16. int(*set_voice_volume)(structaudio_hw_device*dev,floatvolume);
  17. /**
  18. *settheaudiovolumeforallaudioactivitiesotherthanvoicecall.
  19. *Rangebetween0.0and1.0.Ifanyvalueotherthan0isreturned,
  20. *thesoftwaremixerwillemulatethiscapability.
  21. */
  22. int(*set_master_volume)(structaudio_hw_device*dev,floatvolume);
  23. /**
  24. *setModeiscalledwhentheaudiomodechanges.AUDIO_MODE_NORMALmode
  25. *isforstandardaudioplayback,AUDIO_MODE_RINGTONEwhenaringtoneis
  26. *playing,andAUDIO_MODE_IN_CALLwhenacallisinprogress.
  27. */
  28. int(*set_mode)(structaudio_hw_device*dev,intmode);
  29. /*micmute*/
  30. int(*set_mic_mute)(structaudio_hw_device*dev,boolstate);
  31. int(*get_mic_mute)(conststructaudio_hw_device*dev,bool*state);
  32. /*set/getglobalaudioparameters*/
  33. int(*set_parameters)(structaudio_hw_device*dev,constchar*kv_pairs);
  34. /*
  35. *Returnsapointertoaheapallocatedstring.Thecallerisresponsible
  36. *forfreeingthememoryforit.
  37. */
  38. char*(*get_parameters)(conststructaudio_hw_device*dev,
  39. constchar*keys);
  40. /*Returnsaudioinputbuffersizeaccordingtoparameterspassedor
  41. *0ifoneoftheparametersisnotsupported
  42. */
  43. size_t(*get_input_buffer_size)(conststructaudio_hw_device*dev,
  44. uint32_tsample_rate,intformat,
  45. intchannel_count);
  46. /**Thismethodcreatesandopenstheaudiohardwareoutputstream*/
  47. int(*open_output_stream)(structaudio_hw_device*dev,uint32_tdevices,
  48. int*format,uint32_t*channels,
  49. uint32_t*sample_rate,
  50. structaudio_stream_out**out);
  51. void(*close_output_stream)(structaudio_hw_device*dev,
  52. structaudio_stream_out*out);
  53. /**Thismethodcreatesandopenstheaudiohardwareinputstream*/
  54. int(*open_input_stream)(structaudio_hw_device*dev,uint32_tdevices,
  55. int*format,uint32_t*channels,
  56. uint32_t*sample_rate,
  57. audio_in_acoustics_tacoustics,
  58. structaudio_stream_in**stream_in);
  59. void(*close_input_stream)(structaudio_hw_device*dev,
  60. structaudio_stream_in*in);
  61. /**Thismethoddumpsthestateoftheaudiohardware*/
  62. int(*dump)(conststructaudio_hw_device*dev,intfd);
  63. };
  64. typedefstructaudio_hw_deviceaudio_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/ 非legacy:hardware/libhardware/include/hardware/audio.h
前者是2.3及之前的音频设备接口定义,后者是4.0的接口定义。
为了兼容以前的设计,4.0实现一个中间层:hardware/libhardware_legacy/audio/audio_hw_hal.cpp,结构与其他的audio_hw.c大同小异,差别在于open方法:
[cpp] view plain copy
  1. staticintlegacy_adev_open(consthw_module_t*module,constchar*name,
  2. hw_device_t**device)
  3. {
  4. ......
  5. ladev->hwif=createAudioHardware();
  6. if(!ladev->hwif){
  7. ret=-EIO;
  8. gotoerr_create_audio_hw;
  9. }
  10. ......
  11. }
看到那个熟悉的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…

更多相关文章

  1. Android组合控件自定义标题栏
  2. Android自定义Dialog的Match_parent无效问题解决
  3. RatingBar自定义设置
  4. android自定义通知栏并通过广播实现监听
  5. android 自定义软键盘
  6. Android中自定义ProgressDialog实现加载滚动条(加载中…)效果
  7. android studio 3.0配置自定义打包名称
  8. Android 发送自定义广播
  9. Android使用xml自定义图片实例详解

随机推荐

  1. 【Android】数据存储之SQLite
  2. Android关于LinearLayout和RelativeLayou
  3. Android的介绍
  4. 百度招聘Android客服端(1)
  5. 在Android(安卓)studio中建立Java工程
  6. android与tomcat服务器交互实例
  7. android Service Activity三种交互方式(付
  8. 【进阶篇】Android学习笔记——TextInput
  9. Android官方命令深入分析之AVD Manager
  10. android:layout_marginEnd隐藏的坑