一、HAL之框架
1. tiny4412上HAL框架
audio.primary.tiny4412.so文件的Makefile:
device/friendly-arm/common/libaudio/Android.mk
LOCAL_SRC_FILES:= AudioHardware.cpp LOCAL_MODULE := audio.primary.$(TARGET_DEVICE) #TARGET_DEVICE就是tiny4412,生成audio.primary.tiny4412.so,其中primary是在 /system/etc/audio_policy.conf中指定的module的名字。 LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw LOCAL_STATIC_LIBRARIES:= libmedia_helper LOCAL_SHARED_LIBRARIES:= libutils liblog libhardware_legacy # 依赖这个库 libtinyalsa # 依赖这个库 libaudioutils LOCAL_WHOLE_STATIC_LIBRARIES := libaudiohw_legacy
libaudiohw_legacy依赖文件:
hardware/libhardware_legacy/audio/Android.mk LOCAL_SRC_FILES := AudioHardwareInterface.cpp audio_hw_hal.cpp # 4412的5.0版Android上是这个HAL,其它的可不一定了 LOCAL_MODULE := libaudiohw_legacy LOCAL_MODULE_TAGS := optional LOCAL_STATIC_LIBRARIES := libmedia_helper LOCAL_CFLAGS := -Wno-unused-parameter include $(BUILD_STATIC_LIBRARY)
所以库文件audio.primary.tiny4412.so至少涉及:
audio_hw_hal.cpp (hardware/libhardware_legacy/audio/audio_hw_hal.cpp)
audioHardwareInterface.cpp (hardware/libhardware_legacy/audio/audioHardwareInterface.cpp)
audioHardware.cpp (device/friendly-arm/common/libaudio/audioHardware.cpp) 生成audio.primary.tiny4412.so
作用:
audio_hw_hal.cpp:向上提供接口的函数
audioHardwareInterface.cpp:向厂商制定访问硬件接口的函数
audioHardware.cpp:厂商实现的访问声卡硬件的文件
2. 要先弄清楚其框架,才能看懂其代码。
从图片上可以看出,HAL这一层有audio的HAL,也有Audio_policy的HAL。对于Audio_policy的HAL我们不关系,因为它基本上已经废弃了。
HAL要向上层提供统一的接口,操作硬件也可能有一组接口或一个类,抓住这两点分析HAL框架。
3. 见audio_hw_hal.cpp,向上提供的接口就是struct audio_hw_device,它是对hw_device_t结构的封装。
audio_hw_hal.cpp位于hardware/libhardware_legacy/audio下,既然是旧的,那么有没有新的呢?在hardware/libhardware/modules/audio
下有个audio_hw.c文件,它就是新的Audio的HAL文件,但是在5.0板中没有使用它,它里面的函数全部为空。在版本的Android8.0中可以看出,
这个文件同样没有实现,所以libhardware_legacy下的还是起主打作用。但是在Android8.0中的高通的HAL使用的是新的。
4. audio_hw_hal.cpp
a.向上提供接口struct audio_hw_device
b.向下访问硬件class AudioHardware(实现在device/friendly-arm/common/libaudio/audioHardware.cpp) 由厂商提供,里面使用到了tinyalsa
库的接口。但是厂商肯定不能随意去实现硬件的访问接口,Android指定了一套接口给它。
类的继承关系:
AudioHardwareInterface //hardware/AudioHardwareInterface.cpp ↑ AudioHardwareBase //hardware/AudioHardwareBase.h 这个应该是audio HAL给厂商定义的接口 ↑ AudioHardware //device/friendly-arm/common/libaudio/audioHardware.cpp
5. 在厂商的HAL中,AudioHardware (audioHardware.cpp中)表示一个声卡,它使用audio_stream_out结构来表示输出,使用audio_stream_in来表示输入。
audio_stream_out中有write(),audio_stream_in中有read()
6. Audio HAL的调用流程总结
上层应用程序调用audio_hw_hal.cpp中的legacy_adev_open()会得到一个struct audio_hw_device结构体,这个结构体就代表上层使用硬件的接口,这个结构体中有一堆的函数,它们都依赖于厂家提供的struct AudioHardwareInterface结构(在HAL中使用,在厂商代码中实现,此例中是在audioHardware.cpp中实现的),由于HAL对上层直接提供的接口中没有read/write函数,因此,应用程序想要录音或播放声音的时候需要先打卡output或input(调用HAL的open_output_stream/open_input_stream),以使用其里面的write/read函数向声卡硬件写音频数据。
7. HAL相关的数据结构
struct legacy_audio_device { //规范了向上提供的接口 struct audio_hw_device device; //向上提供的接口依赖厂家提供的这个类来实现 struct AudioHardwareInterface *hwif; }; 下面的legacy_stream_out和legacy_stream_in也是同理 struct legacy_stream_out { struct audio_stream_out stream; AudioStreamOut *legacy_out; }; struct legacy_stream_in { struct audio_stream_in stream; AudioStreamIn *legacy_in; };
上面的也是Android源码中常用的套路。
8. http://androidxref.com/ 上有各个版本的Android源码,查看代码非常方便
9. 由于有类的继承关系,SourceInsight工程自动跳转是不准的。
10. AudioFlinger启动过程中,AudioPolicyService构造过程中会读取配置文件 /system/etc/audio_policy.conf,该配置文件中有一个module名为”primary”,根据这个名字, 会去 /system/lib/hw 中打开库文件: audio.primary.XXX.so,比如: audio.primary.tiny4412.so
11. 框架详细描述
audio HAL中:
b.1 向上提供统一接口: audio_hw_device,里面设置了各种函数
b.2 这些函数要借助声卡的代码才能实现,声卡的功能抽象为AudioHardware对象
b.3 audio_hw_device中的函数只看到各种set, get,没有看到wirte, read,怎么播放声音、录制声音?
b.4 要播放声音,
b.4.1 要先open output:在audio_hw_device中有open_output_stream函数指针
b.4.2 open_output_stream返回一个audio_stream_out结构体,它是向上提供的”播放接口”
b.4.3 audio_stream_out也需要厂家提供的代码才能实现,厂家提供的代码抽象为AudioStreamOutALSA对象
b.5 对于录制声音
b.5.1 要先open input:在audio_hw_device中有open_input_stream函数指针
b.5.2 open_input_stream返回一个audio_stream_in结构体,它是向上提供的”录制接口”
b.5.3 audio_stream_in也需要厂家提供的代码才能实现,厂家提供的代码抽象为AudioStreamInALSA对象
二、HAL之调用流程源码分析
1. HAL文件一般位于/system/lib/hardware下面,音频中操作硬件的库文件名称在(厂商提供的HAL部分)在/system/etc/policy_config中指定,如module name为primary,
就对应audio.primary.tiny4412.so。
2. 直接使用系统调用控制声卡的是tinyalsa库,位于目录/external/tinyalsa下,编译生成库文件libtinyalsa.so(只涉及两个文件mixer.c,pcm.c),编译生成工具 tinycap,tinymix,tinypcminfo,tinyplay,可用于直接控制音频通道,进行录音播音测试。
tinyalsa中使用
pcm_open()来打开声卡
pcm_write()来播放音乐
pcm_read()来录音
3. HAL调用流程源码分析
a. 确定HAL文件的名字:
AudioPolicyManager的构造函数读取配置文件/system/etc/audio_policy.conf确定名字(这个名字在tiny4412上只是HAL厂商部分编译生成库的名字,HAL入口是hardware/libhardware_legacy/audio/audio_hw_hal.cpp)
b. 加载HAL对应的so文件。
c. 打开HAL文件中的open函数,在HAL中会构造audio_hw_device结构体, 该结构体中有各类函数, 特别是 open_output_stream / open_input_stream
AudioFlinger根据audio_hw_device结构体构造一个AudioHwDev对象并放入mAudioHwDevs
d. open output stream: 调用hal结构体audio_hw_device的open_output_stream, 它会构造出一个audio_stream_out结构体, 里面有write函数
AudioFlinger根据audio_stream_out结构体构造一个MixerThread
e. 播放声音(这时才真正打开声卡驱动):
thread->threadLoopg_write => stream.write ==> pcm_open, pcm_write