代码分析 加载hal库和openoutput

https://blog.csdn.net/xuesen_lin/article/details/8805076?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-3.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-3.control

添加链接描述

AudioFlinger加载不同的 audio.primary.so或者audio.primary.default.so 、audio.a2dp.so或者audio.a2dp.default.so 、audio.usb.so或者audio.usb.default.so

指定的audiointerface,比如“primary”、“a2dp”或者“usb”。函数load_audio_interface用来加载设备所需的库文件,然后打开设备并创建一个audio_hw_device_t实例。音频接口设备所对应的库文件名称是有一定格式的,比如a2dp的模块名可能是audio.a2dp.so或者audio.a2dp.default.so
————————————————
版权声明:本文为CSDN博主「林学森」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/xuesen_lin/article/details/8805076

每种音频设备接口由一个对应的so库提供支持。那么AudioFlinger怎么会知道当前设备中支持上述的哪些接口,每种接口又支持哪些具体的音频设备呢?这是AudioPolicyService的责任之一,即根据用户配置来指导AudioFlinger加载设备接口

目前Audio系统中支持的音频设备接口(Audio Interface)分为三大类,即:

/*frameworks/av/services/audioflinger/AudioFlinger.cpp*/

static const char * const audio_interfaces[] = {
   AUDIO_HARDWARE_MODULE_ID_PRIMARY, //主音频设备,必须存在

   AUDIO_HARDWARE_MODULE_ID_A2DP, //蓝牙A2DP音频

   AUDIO_HARDWARE_MODULE_ID_USB, //USB音频,早期的版本不支持

};
————————————————
版权声明:本文为CSDN博主「林学森」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/xuesen_lin/article/details/8805076

每种音频设备接口由一个对应的so库提供支持。那么AudioFlinger怎么会知道当前设备中支持上述的哪些接口,每种接口又支持哪些具体的音频设备呢?这是AudioPolicyService的责任之一,即根据用户配置来指导AudioFlinger加载设备接口。
当AudioPolicyManagerBase(AudioPolicyService中持有的Policy管理者,后面小节有详细介绍)构造时,它会读取厂商关于音频设备的描述文件(audio_policy.conf),然后据此来打开以上三类音频接口(如果存在的话)。这一过程最终会调用loadHwModule@AudioFlinger,如下所示:
————————————————
版权声明:本文为CSDN博主「林学森」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/xuesen_lin/article/details/8805076

/*frameworks/av/services/audioflinger*/

audio_module_handle_t AudioFlinger::loadHwModule(const char *name)/*name就是前面audio_interfaces 数组成员中的字符串*/
{
    if (!settingsAllowed()) {
        return 0;
    }
    Mutex::Autolock _l(mLock);
    returnloadHwModule_l(name);
}

loadHwModule_l的函数分析
/Step 1. 是否已经添加了这个interface?/
/Step 2. 加载audio interface/
int rc = mDevicesFactoryHal->openDevice(name, &dev);
调用

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

load_audio_interface调用

DevicesFactoryHalLocal.cpp
static status_t load_audio_interface(const char *if_name, audio_hw_device_t **dev)
{
    const hw_module_t *mod;
    int rc;

    rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod);
    if (rc) {
        ALOGE("%s couldn't load audio hw module %s.%s (%s)", __func__,
                AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc));
        goto out;
    }
    rc = audio_hw_device_open(mod, dev);
    if (rc) {
        ALOGE("%s couldn't open audio hw device in %s.%s (%s)", __func__,
                AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc));
        goto out;
    }
    if ((*dev)->common.version < AUDIO_DEVICE_API_VERSION_MIN) {
        ALOGE("%s wrong audio hw device version %04x", __func__, (*dev)->common.version);
        rc = BAD_VALUE;
        audio_hw_device_close(*dev);
        goto out;
    }
    return OK;

out:
    *dev = NULL;
    return rc;
}

hw_get_module_by_class调用

int hw_get_module_by_class(const char *class_id, const char *inst,
                           const struct hw_module_t **module)
{
    int i = 0;
    char prop[PATH_MAX] = {0};
    char path[PATH_MAX] = {0};
    char name[PATH_MAX] = {0};
    char prop_name[PATH_MAX] = {0};


    if (inst)
        snprintf(name, PATH_MAX, "%s.%s", class_id, inst);
    else
        strlcpy(name, class_id, PATH_MAX);

    /*
     * Here we rely on the fact that calling dlopen multiple times on
     * the same .so will simply increment a refcount (and not load
     * a new copy of the library).
     * We also assume that dlopen() is thread-safe.
     */

    /* First try a property specific to the class and possibly instance */
    snprintf(prop_name, sizeof(prop_name), "ro.hardware.%s", name);
    if (property_get(prop_name, prop, NULL) > 0) {
        if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
            goto found;
        }
    }

    /* Loop through the configuration variants looking for a module */
    for (i=0 ; i<HAL_VARIANT_KEYS_COUNT; i++) {
        if (property_get(variant_keys[i], prop, NULL) == 0) {
            continue;
        }
        if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
            goto found;
        }
    }

    /* Nothing found, try the default */
    if (hw_module_exists(path, sizeof(path), name, "default") == 0) {
        goto found;
    }

    return -ENOENT;

found:
    /* load the module, if this fails, we're doomed, and we should not try
     * to load a different variant. */
    return load(class_id, path, module);
}


**hardware.c load调用  dlopen加载库文件**
static int load(const char *id,
        const char *path,
        const struct hw_module_t **pHmi)
{
    int status = -EINVAL;
    void *handle = NULL;
    struct hw_module_t *hmi = NULL;
#ifdef __ANDROID_VNDK__
    const bool try_system = false;
#else
    const bool try_system = true;
#endif

    /*
     * load the symbols resolving undefined symbols before
     * dlopen returns. Since RTLD_GLOBAL is not or'd in with
     * RTLD_NOW the external symbols will not be global
     */
    if (try_system &&
        strncmp(path, HAL_LIBRARY_PATH1, strlen(HAL_LIBRARY_PATH1)) == 0) {
        /* If the library is in system partition, no need to check
         * sphal namespace. Open it with dlopen.
         */
        handle = dlopen(path, RTLD_NOW);
    } else {
        handle = android_load_sphal_library(path, RTLD_NOW);
    }
    if (handle == NULL) {
        char const *err_str = dlerror();
        ALOGE("load: module=%s\n%s", path, err_str?err_str:"unknown");
        status = -EINVAL;
        goto done;
    }

Android系统支持的音频设备(输出)

Device Name

Description

AUDIO_DEVICE_OUT_EARPIECE

听筒

AUDIO_DEVICE_OUT_SPEAKER

喇叭

AUDIO_DEVICE_OUT_WIRED_HEADSET

带话筒的耳机

AUDIO_DEVICE_OUT_WIRED_HEADPHONE

耳机

AUDIO_DEVICE_OUT_BLUETOOTH_SCO

SCO 蓝牙

AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET

SCO 蓝牙耳机

AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT

SCO 车载套件

AUDIO_DEVICE_OUT_BLUETOOTH_A2DP

A2DP 蓝牙

AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES

A2DP 蓝牙耳机

AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER

A2DP 蓝牙喇叭

AUDIO_DEVICE_OUT_AUX_DIGITAL

AUX IN

AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET

模拟dock headset

AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET

数字dock headset

AUDIO_DEVICE_OUT_USB_ACCESSORY

USB配件

AUDIO_DEVICE_OUT_USB_DEVICE

USB设备

AUDIO_DEVICE_OUT_DEFAULT

默认设备

AUDIO_DEVICE_OUT_ALL

上述每种设备只占int值一个bit位,这里是指上述设备的集合

AUDIO_DEVICE_OUT_ALL_A2DP

上述设备中与A2DP蓝牙相关的设备集合

AUDIO_DEVICE_OUT_ALL_SCO

上述设备中与SCO蓝牙相关的设备集合

AUDIO_DEVICE_OUT_ALL_USB

上述设备中与USB相关的设备集合

打开音频输出通道(output)在AF中对应的接口是openOutput()

audio_io_handle_t  AudioFlinger::openOutput(audio_module_handle_tmodule, audio_devices_t *pDevices,

                                          uint32_t *pSamplingRate,audio_format_t *pFormat,

                                          audio_channel_mask_t *pChannelMask,

                                          uint32_t *pLatencyMs, audio_output_flags_t flags)

{
                /*入参中的module是由前面的loadHwModule 获得的,它是一个audiointerface的id号,可以通过此id在mAudioHwDevs中查找到对应的AudioHwDevice对象*/

    status_t status;

    PlaybackThread *thread =NULL;

…

audio_stream_out_t  *outStream = NULL;

    audio_hw_device_t*outHwDev;/*Step 1. 查找相应的audio interface

    outHwDev = findSuitableHwDev_l(module, *pDevices);     

                …

                /*Step 2. 为设备打开一个输出流*/

mHardwareStatus =AUDIO_HW_OUTPUT_OPEN;

    status = outHwDev->open_output_stream(outHwDev, id, *pDevices,(audio_output_flags_t)flags,

                                          &config, &outStream);

    mHardwareStatus =AUDIO_HW_IDLE;if (status == NO_ERROR &&outStream != NULL) {
 /*Step 3.生成AudioStreamOut*/

      AudioStreamOut *output = newAudioStreamOut(outHwDev, outStream);

                 /*Step 4.创建PlaybackThread*/

      if ((flags & AUDIO_OUTPUT_FLAG_DIRECT) ||(config.format != AUDIO_FORMAT_PCM_16_BIT) ||

           (config.channel_mask != AUDIO_CHANNEL_OUT_STEREO)) {
            thread = new DirectOutputThread(this, output, id, *pDevices);

      } else {
            thread = new MixerThread(this, output, id, *pDevices);

      }

      mPlaybackThreads.add(id,thread); //添加播放线程/*Step 5.Primary output情况下的处理*/

      if ((mPrimaryHardwareDev== NULL) &&flags & AUDIO_OUTPUT_FLAG_PRIMARY)) {
            ALOGI("Usingmodule %d has the primary audio interface", module);

           mPrimaryHardwareDev = outHwDev;

            AutoMutexlock(mHardwareLock);

            mHardwareStatus =AUDIO_HW_SET_MODE;

           outHwDev->set_mode(outHwDev, mMode);float initialVolume = 1.0;

           mMasterVolumeSupportLvl = MVS_NONE;

            mHardwareStatus = AUDIO_HW_GET_MASTER_VOLUME; //测试设备是否支持主音量获取

            if ((NULL !=outHwDev->get_master_volume) &&

                (NO_ERROR ==outHwDev->get_master_volume (outHwDev, &initialVolume))) {
               mMasterVolumeSupportLvl = MVS_FULL;

            } else {
               mMasterVolumeSupportLvl = MVS_SETONLY;

                initialVolume= 1.0;

            }

 

            mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;//测试是否支持主音量设置

            if ((NULL ==outHwDev->set_master_volume) ||

                (NO_ERROR !=outHwDev->set_master_volume (outHwDev, initialVolume))) {
               mMasterVolumeSupportLvl = MVS_NONE;

            }

            for (size_t i = 0; i <mAudioHwDevs.size(); i++) {
               audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice();

                if ((dev !=mPrimaryHardwareDev) &&

                    (NULL !=dev->set_master_volume)) {
                    dev->set_master_volume(dev,initialVolume);

                }

            }

            mHardwareStatus =AUDIO_HW_IDLE;

            mMasterVolumeSW =(MVS_NONE == mMasterVolumeSupportLvl)? initialVolume: 1.0;

            mMasterVolume   = initialVolume;

        }

        return id;

    }

    return 0;

}
————————————————
版权声明:本文为CSDN博主「林学森」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/xuesen_lin/article/details/8805076

上面这段代码中,颜色加深的部分是我们接下来分析的重点,主要还是围绕outHwDev这个变量所做的一系列操作,即:

· 查找合适的音频接口设备(findSuitableHwDev_l)

· 创建音频输出流(通过open_output_stream获得一个audio_stream_out_t)

· 利用AudioStreamOut来封装audio_stream_out_t与audio_hw_device_t

· 创建播放线程(PlaybackThread)

· 如果当前设备是主设备,则还需要进行相应的设置,包括模式、主音量等等
显然,outHwDev用于记录一个打开的音频接口设备,它的数据类型是audio_hw_device_t,是由HAL规定的一个音频接口设备所应具有的属性集合,如下所示:

struct audio_hw_device {
    struct hw_device_t common;int (*set_master_volume)(struct audio_hw_device *dev, float volume);

    int (*set_mode)(struct audio_hw_device *dev, audio_mode_t mode);

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

https://blog.csdn.net/xuesen_lin/article/details/8805076?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-3.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-3.control

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值