赞
踩
AndroidHAL层的代码为framework层抽象出了一系列接口,隐藏了硬件驱动细节;本文来了解AudioHal层的相关代码,相关源文件在目录frameworks\av\media\libaudiohal中;在AndroidAudio子系统中,直接操作AudioHal的是AudioFlinger,在AudioFlinger中保存了所有可用的音频设备
虽然各个音频硬件大不相同,但是涉及到操作大体上可以归为两类:设备操作和流操作。对于这两种操作,我们设计两个接口来抽象它们:DeviceHalInterface和StreamHalInterface,对于流类型来说还分输入/输出:StreamOutHalInterface和StreamInHalInterface。
早期的Android一般是把操作音频驱动的代码封装成一个库,然后AudioFlinger在初始化的时候会加载这些库,然后封装成一个对象,取得操作音频驱动的接口;后来Android准备要执行treble计划,这样就彻底隔离厂商自定义的代码和Android Framework的代码,双方的通信基于binder,相对于AIDL,google提供了另一个接口HIDL。针对这两种方式,在AudioHal层也分别提供了对应的实现,具体是以Local和Hidl结尾来表示。我们来看下这些类的关系:
具体音频硬件对象是在AudioFlinger中实现,我们一步一步来看:
AudioFlinger::AudioFlinger()
...
{
...
mDevicesFactoryHal = DevicesFactoryHalInterface::create();----从名字可以看出这是"设备工厂"
...
}
sp<DevicesFactoryHalInterface> DevicesFactoryHalInterface::create() {
return createPreferredImpl<DevicesFactoryHalInterface>(
"android.hardware.audio", "IDevicesFactory");--------创建最合适的"工厂类"的实例
}
我们来看看接口的设计:
class DevicesFactoryHalInterface : public RefBase
{
...
virtual status_t openDevice(const char *name, sp<DeviceHalInterface> *device) = 0;---接口的真正功能,打开设备
...
static sp<DevicesFactoryHalInterface> create();------------创建接口的具体实现
...
};
DevicesFactoryHalInterface有两种类继承于它,如下图:
从上面可以得知,这是版本迭代引入的两种实现方式,我们看看local是怎么实现openDevice的
static status_t load_audio_interface(const char *if_name, audio_hw_device_t **dev) { ... rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod); ... rc = audio_hw_device_open(mod, dev); ... } status_t DevicesFactoryHalLocal::openDevice(const char *name, sp<DeviceHalInterface> *device) { audio_hw_device_t *dev; status_t rc = load_audio_interface(name, &dev);----加载库提取audio_hw_device_t,这个结构体我们在第三节介绍 if (rc == OK) { *device = new DeviceHalLocal(dev);-------------创建具体音频硬件设备 } return rc; }
从这里我们看到了重要的类DeviceHalLocal,这个类是framework层对具体硬件设备的抽象。接下来看AudioFlinger调用openDevice的地方:
audio_module_handle_t AudioFlinger::loadHwModule_l(const char *name)
{
for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
//遍历是否已加载
}
sp<DeviceHalInterface> dev;
int rc = mDevicesFactoryHal->openDevice(name, &dev);
...
audio_module_handle_t handle = (audio_module_handle_t) nextUniqueId(AUDIO_UNIQUE_ID_USE_MODULE);
mAudioHwDevs.add(handle, new AudioHwDevice(handle, name, dev, flags));
...
}
loadHwModule_l根据名字去打开相应的设备,并分配一个唯一id,然后创建一个重要的类AudioHwDevice
AudioFlinger中管理audio设备的类
class AudioHwDevice { ... AudioHwDevice(audio_module_handle_t handle, const char *moduleName, sp<DeviceHalInterface> hwDevice, Flags flags) : mHandle(handle) , mModuleName(strdup(moduleName)) , mHwDevice(hwDevice) , mFlags(flags) { } ... audio_module_handle_t handle() const { return mHandle; } const char *moduleName() const { return mModuleName; } sp<DeviceHalInterface> hwDevice() const { return mHwDevice; } ... status_t openOutputStream( AudioStreamOut **ppStreamOut, audio_io_handle_t handle, audio_devices_t deviceType, audio_output_flags_t flags, struct audio_config *config, const char *address); ... const audio_module_handle_t mHandle; const char * const mModuleName; sp<DeviceHalInterface> mHwDevice; const Flags mFlags; };
status_t AudioHwDevice::openOutputStream( AudioStreamOut **ppStreamOut, audio_io_handle_t handle, audio_devices_t deviceType, audio_output_flags_t flags, struct audio_config *config, const char *address) { ... AudioStreamOut *outputStream = new AudioStreamOut(this, flags);----------建立流对象 ... status_t status = outputStream->open(handle, deviceType, config, address);------看2.3小节AudioStreamOut的实现 ... *ppStreamOut = outputStream; return status; }
说完了音频设备,下面介绍流的管理,openOutputStream就是要打开相应的流
AudioFlinger中管理流用AudioStreamOut来封装
class AudioStreamOut { ... AudioHwDevice * const audioHwDev; sp<StreamOutHalInterface> stream;-------hal层对流对象的接口封装 const audio_output_flags_t flags; sp<DeviceHalInterface> hwDev() const; AudioStreamOut(AudioHwDevice *dev, audio_output_flags_t flags); virtual status_t open( audio_io_handle_t handle, audio_devices_t deviceType, struct audio_config *config, const char *address); ... };
接上上面的调用流程继续
sp<DeviceHalInterface> AudioStreamOut::hwDev() const { return audioHwDev->hwDevice(); } status_t AudioStreamOut::open( audio_io_handle_t handle, audio_devices_t deviceType, struct audio_config *config, const char *address) { ... int status = hwDev()->openOutputStream( handle, deviceType, customFlags, config, address, &outStream);-------------最后调用devicehallocal的openOutputStream ... if (status == NO_ERROR) { stream = outStream; ... } }
status_t DeviceHalLocal::openOutputStream( audio_io_handle_t handle, audio_devices_t deviceType, audio_output_flags_t flags, struct audio_config *config, const char *address, sp<StreamOutHalInterface> *outStream) { audio_stream_out_t *halStream;------------------------这个结构体在第三节介绍 ... int openResut = mDev->open_output_stream(-------------mDev就是audio_hw_device_t,在第三节介绍 mDev, handle, deviceType, flags, config, &halStream, address); if (openResut == OK) { *outStream = new StreamOutHalLocal(halStream, this);-----创建local实现的流对象 } ... }
从上面两节我们知道两个重要的结构体需要在C层实现,C层是比hal更底层的audio功能实现,这一层基本是vendor需要实现的;这一层会基于tinyalsa库来实现audio的功能。我们继续对上面两个结构体做个介绍。
对于和硬件相关的实现都是在hardware目录下,这两个结构体的定义也在此目录下
hardware/libhardware/include/hardware/audio.h
typedef struct audio_hw_device audio_hw_device_t;
struct audio_hw_device {
struct hw_device_t common;--------------第一个字段必须是此结构体,为了强转需要
...
int (*open_output_stream)(struct audio_hw_device *dev,
audio_io_handle_t handle,
audio_devices_t devices,
audio_output_flags_t flags,
struct audio_config *config,
struct audio_stream_out **stream_out,
const char *address);--------c层open_output_stream的实现
...
};
audio_hw_device中有丰富的函数功能实现,我们只截取了一部分,为了了解open_output_stream流程。
audio_hw_device是一个通用的实现,一般来说vendor开发会基于此在外层继续包装,添加自己的一些字段,我们以google提供的例子分析,看下hardware\libhardware\modules\audio\audio_hw.c文件。
struct stub_audio_device {
struct audio_hw_device device;-----必须在开头
};
这里给了一个很简单的封装,但是一般会增加vendor特有的字段,不过audio_hw_device一定要在开头,为了HAL层强转需要。
现在来看下HAL是怎么得到此结构体audio_hw_device的,通过load_audio_interface中我们知道dlopen动态库加载来实现的,那么就一定要在代码中加入相应的识别symbol,还是在audio_hw.c中
static struct hw_module_methods_t hal_module_methods = {
.open = adev_open,
};
struct audio_module HAL_MODULE_INFO_SYM = {
.common = {
.tag = HARDWARE_MODULE_TAG,
.module_api_version = AUDIO_MODULE_API_VERSION_0_1,
.hal_api_version = HARDWARE_HAL_API_VERSION,
.id = AUDIO_HARDWARE_MODULE_ID,
.name = "Default audio HW HAL",
.author = "The Android Open Source Project",
.methods = &hal_module_methods,
},
};
具体细节不分析了,最终会调用adev_open来得到audio_hw_device
static int adev_open(const hw_module_t* module, const char* name,
hw_device_t** device)
{
...
struct stub_audio_device *adev;
...
adev = calloc(1, sizeof(struct stub_audio_device));
...
adev->device.open_output_stream = adev_open_output_stream;
...
*device = &adev->device.common;
...
}
可以看到实际新建的是stub_audio_device这个结构体,但是因为audio_hw_device在头部,进行强转就可以了。
stream也是类似的
typedef struct audio_stream_out audio_stream_out_t;
struct stub_stream_out {
struct audio_stream_out stream;
int64_t last_write_time_us;
uint32_t sample_rate;
audio_channel_mask_t channel_mask;
audio_format_t format;
size_t frame_count;
};
然后是adev_open_output_stream
static int adev_open_output_stream(struct audio_hw_device *dev, audio_io_handle_t handle, audio_devices_t devices, audio_output_flags_t flags, struct audio_config *config, struct audio_stream_out **stream_out, const char *address __unused) { ALOGV("adev_open_output_stream..."); *stream_out = NULL; struct stub_stream_out *out = (struct stub_stream_out *)calloc(1, sizeof(struct stub_stream_out)); ... *stream_out = &out->stream; return 0; }
在AudioHal中,还有另外一种模块就是音效处理,比如高音,低音,杜比音效等等,我们在目录中看到的Effect相关的文件都是其代码实现,他的具体过程和device是一样的,都是通过加载hal层的库,加载库中的一般方法,然后再对其进行抽象,供用户使用,所以这里就不赘述了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。