Android O Audio libaudiohal module analysis

For the Android O Audio module, there is an additional libaudiohal folder:

Android.mk                DeviceHalLocal.h             DevicesFactoryHalLocal.h  EffectHalHidl.h             EffectsFactoryHalLocal.h  StreamHalLocal.cpp
ConversionHelperHidl.cpp  DevicesFactoryHalHidl.cpp    EffectBufferHalHidl.cpp   EffectHalLocal.cpp          HalDeathHandlerHidl.cpp   StreamHalLocal.h
ConversionHelperHidl.h    DevicesFactoryHalHidl.h      EffectBufferHalHidl.h     EffectHalLocal.h            include                   StreamPowerLog.h
DeviceHalHidl.cpp         DevicesFactoryHalHybrid.cpp  EffectBufferHalLocal.cpp  EffectsFactoryHalHidl.cpp   OWNERS
DeviceHalHidl.h           DevicesFactoryHalHybrid.h    EffectBufferHalLocal.h    EffectsFactoryHalHidl.h     StreamHalHidl.cpp
DeviceHalLocal.cpp        DevicesFactoryHalLocal.cpp   EffectHalHidl.cpp         EffectsFactoryHalLocal.cpp  StreamHalHidl.h

Obviously, it is for hidl.

Let's study how to use it.

When playing Audio, you need to openOutput first. We start with the traditional call process of AudioFlinger::openOutput_l.


sp<AudioFlinger::ThreadBase> AudioFlinger::openOutput_l(audio_module_handle_t module,
                                                            audio_io_handle_t *output,
                                                            audio_config_t *config,
                                                            audio_devices_t devices,
                                                            const String8& address,
                                                            audio_output_flags_t flags)
{
    
    
    AudioHwDevice *outHwDev = findSuitableHwDev_l(module, devices);
    ...
}

findSuitableHwDev_l finds a suitable device. This traditional function. What new changes will there be?


AudioHwDevice* AudioFlinger::findSuitableHwDev_l(
        audio_module_handle_t module,
        audio_devices_t devices)
{
    
    
    ...
        AudioHwDevice *audioHwDevice = mAudioHwDevs.valueAt(i);
        //奏是这里
        sp<DeviceHalInterface> dev = audioHwDevice->hwDevice();
    ...
        if (dev->getSupportedDevices(&supportedDevices) == OK &&
                    (supportedDevices & devices) == devices) {
    
    
             return audioHwDevice;
        }
}

What we want to focus on is here


sp<DeviceHalInterface> dev = audioHwDevice->hwDevice();
//Android 7.1.2中这行代码是这样的
audio_hw_device_t *dev = audioHwDevice->hwDevice();

dev from

/hardware/libhardware/include/hardware/audio.h

A structure defined in , a function pointer, becomes a DeviceHalInterface pointer.

This class comes from:


//AudioFlinger.cpp的顶部
#include <media/audiohal/DeviceHalInterface.h>

Yes, I am looking for you! (Sorry, I am listening to <He`sa Porate> at this time , so I am a little excited)

Go back to the libaudiohal folder.

#grep -nir DeviceHalInterface
DeviceHalHidl.h:32:class DeviceHalHidl : public DeviceHalInterface, public ConversionHelperHidl
DeviceHalLocal.h:25:class DeviceHalLocal : public DeviceHalInterface

DeviceHalInterface actually has two sons, oh no, they are two subclasses.

Let's take a look at the getSupportedDevices method separately


status_t DeviceHalHidl::getSupportedDevices(uint32_t*) {                                                                                                       
    // Obsolete.
    return INVALID_OPERATION;
}

status_t DeviceHalLocal::getSupportedDevices(uint32_t *devices) {
    
    
    if (mDev->get_supported_devices == NULL) return INVALID_OPERATION;
    *devices = mDev->get_supported_devices(mDev);
    return OK;
}

It feels like the latter should be called in AudioFlinger.

take a closer look to make sure

/frameworks/av/services/audioflinger/AudioHwDevice.h


sp<DeviceHalInterface>      mHwDevice;
...
sp<DeviceHalInterface> hwDevice() const { return mHwDevice; }
...

mHwDevice is initialized here


//AudioHwDevice.h
AudioHwDevice(audio_module_handle_t handle,
                  const char *moduleName,
                  sp<DeviceHalInterface> hwDevice,
                  Flags flags)
        : mHandle(handle)
        , mModuleName(strdup(moduleName))
        , mHwDevice(hwDevice)
        , mFlags(flags) { }

initialized in the initializer list of the constructor, then

grep -nir "new AudioHwDevice"
AudioFlinger.cpp:1788:    mAudioHwDevs.add(handle, new AudioHwDevice(handle, name, dev, flags));

Right now


audio_module_handle_t AudioFlinger::loadHwModule_l(const char *name)
{
    
    
    ...
        sp<DeviceHalInterface> dev;
        int rc = mDevicesFactoryHal->openDevice(name, &dev);
    ...
        mAudioHwDevs.add(handle, new AudioHwDevice(handle, name, dev, flags));
    ...
}

And look at the initialization of mDevicesFactoryHal


AudioFlinger::AudioFlinger()
{
    
    
    ...
        mDevicesFactoryHal = DevicesFactoryHalInterface::create();
    ...
}

In DevicesFactoryHalHybrid.cpp, the implementation of the create method (I don’t understand why it’s here):

// static
sp<DevicesFactoryHalInterface> DevicesFactoryHalInterface::create() {
   
   
    return new DevicesFactoryHalHybrid();
}

Curiously checked the meaning of Hybrid, it turned out to mean "mixed blood, hybrid power".

DevicesFactoryHalInterface::create() is actually a new DevicesFactoryHalHybrid:


DevicesFactoryHalHybrid::DevicesFactoryHalHybrid()
        : mLocalFactory(new DevicesFactoryHalLocal()),
          mHidlFactory(
#ifdef USE_LEGACY_LOCAL_AUDIO_HAL
                  nullptr
#else
                  new DevicesFactoryHalHidl()
#endif
                       ) {
    
    
}

Now we can change to:

DevicesFactoryHalInterface::create()其实是new了一个DevicesFactoryHalHybrid.该对象是一个拥有一个DevicesFactoryHalLocal对象和DevicesFactoryHalHidl对象的混血.

也就是说mDevicesFactoryHal是一个DevicesFactoryHalHybrid对象.前边调用的openDevice方法即:


status_t DevicesFactoryHalHybrid::openDevice(const char *name, sp<DeviceHalInterface> *device) {
    
    
    if (mHidlFactory != 0 && strcmp(AUDIO_HARDWARE_MODULE_ID_A2DP, name) != 0) {
    
    
        return mHidlFactory->openDevice(name, device);
    }
    return mLocalFactory->openDevice(name, device);
}

好的,到了这里,就

花开两朵,各表一支了

HIDL方式

如果mHidlFactory存在,而且要打开的设备不是AUDIO_HARDWARE_MODULE_ID_A2DP(strcmp返回0表示相等).

蓝牙A2DP不会走HIDL?(这个问题估计得另开话题了)

代码走mHidlFactory->openDevice(name, device);即:


status_t DevicesFactoryHalHidl::openDevice(const char *name, sp<DeviceHalInterface> *device) {
    
    
    Return<void> ret = mDevicesFactory->openDevice(
            hidlDevice,
            [&](Result r, const sp<IDevice>& result) { 
                retval = r;    
                if (retval == Result::OK) {     
                    *device = new DeviceHalHidl(result);
                }
            });
}

mDevicesFactory赋值


DevicesFactoryHalHidl::DevicesFactoryHalHidl() {
    
    
    mDevicesFactory = IDevicesFactory::getService();
    ...
}

IDevicesFactory是一个由IDevicesFactory.hal生成的类(这块不清楚的可以看我之前的博客,分析过很多类似的)

HIDL端(跨进程了),有对应的实现方法:

且看看Android的默认实现示例(直接看openDevice好了):

hardware/interfaces/audio/2.0/default/DevicesFactory.cpp


// Methods from ::android::hardware::audio::V2_0::IDevicesFactory follow.
Return<void> DevicesFactory::openDevice(IDevicesFactory::Device device, openDevice_cb _hidl_cb)  {
    
    
    audio_hw_device_t *halDevice;
    Result retval(Result::INVALID_ARGUMENTS);
    sp<IDevice> result;
    const char* moduleName = deviceToString(device);
    if (moduleName != nullptr) {
    
    
        //画重点
        int halStatus = loadAudioInterface(moduleName, &halDevice);
        if (halStatus == OK) {
    
    
            if (device == IDevicesFactory::Device::PRIMARY) {
    
    
                result = new PrimaryDevice(halDevice);
            } else {
    
    
                result = new ::android::hardware::audio::V2_0::implementation::
                    Device(halDevice);
            }
            retval = Result::OK;
        } else if (halStatus == -EINVAL) {
    
    
            retval = Result::NOT_INITIALIZED;
        }
    }
    _hidl_cb(retval, result);
    return Void();
}

重点loadAudioInterface


// static
int DevicesFactory::loadAudioInterface(const char *if_name, audio_hw_device_t **dev)
{
    
    
    ...
    hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod);
    ...
    audio_hw_device_open(mod, dev);
    ...
}

先不往下分析.回去分析DevicesFactoryHalHybrid::openDevice调用的另一个分支:

传统方式

如果mHidlFactory不存在,或者要打开的设备是AUDIO_HARDWARE_MODULE_ID_A2DP(strcmp(AUDIO_HARDWARE_MODULE_ID_A2DP, name) = 0)

代码走mLocalFactory->openDevice(name, device);

status_t DevicesFactoryHalLocal::openDevice(const char *name, sp<DeviceHalInterface> *device) {
    
    
    audio_hw_device_t *dev;
    status_t rc = load_audio_interface(name, &dev);
    if (rc == OK) {
    
    
        //重点在这里
        *device = new DeviceHalLocal(dev);
    }
    return rc;
}

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);
     ...        
}

到这里,终于找到了调用getSupportedDevices的dev的真实类型.就是DeviceHalLocal喽!

如果这是一道证明题的,这里可以写一个证毕了!

接下来,我们继续分析


status_t DeviceHalLocal::getSupportedDevices(uint32_t *devices) {
    
    
    if (mDev->get_supported_devices == NULL) return INVALID_OPERATION;
    *devices = mDev->get_supported_devices(mDev);
    return OK;
}

mDev:


DeviceHalLocal::DeviceHalLocal(audio_hw_device_t *dev)
        : mDev(dev) {
    
    
}

即前面一点点提到的audio_hw_device_open(mod, dev)带回来的dev.

以下就是传统方式和HIDL方式都会去调用的audio.h中的接口了.

./hardware/libhardware/include/hardware/audio.h


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,
                                 TO_HW_DEVICE_T_OPEN(device));
}

到这里,我们就知道调用的是谁啦.这块有疑问的,可以找找之前很多人分析过的hal层和framework层的调用流程.

没错,它调用的就是audio_hw.c中的adev_open函数.再往下呢,就到了bsp层了.就不继续分析了!

剩下的没涉及到的文件,StreamHalXXX这几个文件,我在另一篇博客中做过分析:

http://blog.csdn.net/bberdong/article/details/78346729

EffectsXXX的音效相关的,感兴趣的读者可以自己研究下,估计大同小异啦!

这篇文章到这里就结束了!谢谢大家观赏!

Guess you like

Origin blog.csdn.net/bberdong/article/details/79472208
Recommended