Android AudioFlinger(三)—— AndroidAudio Flinger 之设备管理-继续分析

时间:2025-03-08 07:12:52

按照职责来划分的画,audioflinger只是策略的执行者,策略的制定者其实是audiopolicyservice。比如某种stream类型对应什么设备、何时打开接口等等,都由它来决定。

目前Android音频系统中支持的音频设备接口主要有三种:

static const char * const audio_interfaces[] = {
    AUDIO_HARDWARE_MODULE_ID_PRIMARY,  //主要音频设备
    AUDIO_HARDWARE_MODULE_ID_A2DP, //蓝牙音频设备
    AUDIO_HARDWARE_MODULE_ID_USB, //USB音频设备
};

这三种音频设备对应的就是三个so库,那如何知道我需要加载哪一个库呢,下面我们就跟随代码来看一看。

AudioHwDevice* AudioFlinger::findSuitableHwDev_l(
        audio_module_handle_t module,
        audio_devices_t devices)
{
    // if module is 0, the request comes from an old policy manager and we should load
    // well known modules
    if (module == 0) {
        ALOGW("findSuitableHwDev_l() loading well know audio hw modules");
        for (size_t i = 0; i < arraysize(audio_interfaces); i++) {
            loadHwModule_l(audio_interfaces[i]);
        }
       ...

    return NULL;
}

这里可以看到将audio_interface传入了loadHwModule_l函数中,循环遍历了三种音频设备都会调用一遍。

audio_module_handle_t AudioFlinger::loadHwModule_l(const char *name)
{
    for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
        if (strncmp(mAudioHwDevs.valueAt(i)->moduleName(), name, strlen(name)) == 0) {
            ALOGW("loadHwModule() module %s already loaded", name);
            return mAudioHwDevs.keyAt(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));

    ALOGI("loadHwModule() Loaded %s audio interface, handle %d", name, handle);

    return handle;

}

这个函数我们主要看两个地方,openDevice打开了一个音频设备,而且是根据我们for循环穿下来的name打开的。之后调用的mAudioHwDevs.add将设备添加到vector容器中,很明显我们需要先看下如何打开的这设备。

// /frameworks/av/media/libaudiohal/DevicesFactoryHalInterface.cpp
sp<DevicesFactoryHalInterface> DevicesFactoryHalInterface::create() {
    if (hardware::audio::V4_0::IDevicesFactory::getService() != nullptr) {
        return new V4_0::DevicesFactoryHalHybrid();
    }
    if (hardware::audio::V2_0::IDevicesFactory::getService() != nullptr) {
        return new DevicesFactoryHalHybrid();
    }
    return nullptr;
}

这段代码表示的是mDevicesFactoryHal的创建过程,很明显,mDevicesFactoryHal就等于DevicesFactoryHalHybrid()。

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

这里会做一个判断,如果不是蓝牙也不是hearing就会调用mHidlFactory,我们就走这里看下,不是蓝牙的情况,也就是说primary和usb都会走这里获取。

///frameworks/av/media/libaudiohal/4.0/DevicesFactoryHalHidl.cpp
status_t DevicesFactoryHalHidl::openDevice(const char *name, sp<DeviceHalInterface> *device) {
    if (mDevicesFactory == 0) return NO_INIT;
    Result retval = Result::NOT_INITIALIZED;
    Return<void> ret = mDevicesFactory->openDevice(
            name,
            [&](Result r, const sp<IDevice>& result) {
                retval = r;
                if (retval == Result::OK) {
                    *device = new DeviceHalHidl(result);
                }
            });
...
    return FAILED_TRANSACTION;
}

这里也没做什么只是继续调用了mDevicesFactory->openDevice并传入了name和一个回调函数,采用了lamda表达式,可以进一步了解下这个写法。

///hardware/interfaces/audio/core/all-versions/default/include/core/all-versions/default/DevicesFactory.impl.h

Return<void> DevicesFactory::openDevice(const hidl_string& moduleName, openDevice_cb _hidl_cb) {
    if (moduleName == AUDIO_HARDWARE_MODULE_ID_PRIMARY) {
        return openDevice<PrimaryDevice>(moduleName.c_str(), _hidl_cb);
    }
    return openDevice(moduleName.c_str(), _hidl_cb);
}
Return<void> DevicesFactory::openPrimaryDevice(openPrimaryDevice_cb _hidl_cb) {
    return openDevice<PrimaryDevice>(AUDIO_HARDWARE_MODULE_ID_PRIMARY, _hidl_cb);
}
Return<void> DevicesFactory::openDevice(const char* moduleName, openDevice_cb _hidl_cb) {
    return openDevice<implementation::Device>(moduleName, _hidl_cb);
}

template <class DeviceShim, class Callback>
Return<void> DevicesFactory::openDevice(const char* moduleName, Callback _hidl_cb) {
    audio_hw_device_t* halDevice;
    Result retval(Result::INVALID_ARGUMENTS);
    sp<DeviceShim> result;
    int halStatus = loadAudioInterface(moduleName, &halDevice);
    if (halStatus == OK) {
        result = new DeviceShim(halDevice);
        retval = Result::OK;
    } else if (halStatus == -EINVAL) {
        retval = Result::NOT_INITIALIZED;
    }
    _hidl_cb(retval, result);
    return Void();
}

// static
int DevicesFactory::loadAudioInterface(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 = -EINVAL;
        audio_hw_device_close(*dev);
        goto out;
    }
    return OK;

out:
    *dev = NULL;
    return rc;
}

这块代码相对简单就没有什么一次往下追就可以看到最终调用了hw_get_module_by_class,并且传入了name,AUDIO_HARDWARE_MODULE_ID就是hal层会设置的ID,相互匹配上。

// /hardware/libhardware/hardware.c

#if defined(__LP64__)
#define HAL_LIBRARY_PATH1 "/system/lib64/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib64/hw"
#define HAL_LIBRARY_PATH3 "/odm/lib64/hw"
#else
#define HAL_LIBRARY_PATH1 "/system/lib/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib/hw"
#define HAL_LIBRARY_PATH3 "/odm/lib/hw"
#endif

static const char *variant_keys[] = {
    "ro.hardware",  /* This goes first so that it can pick up a different
                       file on the emulator. */
    "ro.product.board",
    "ro.board.platform",
    "ro.arch"
};

int hw_get_module_by_class(const char *class_id, const char *inst,
                           const struct hw_module_t **module)
{
    if (inst)
        snprintf(name, PATH_MAX, "%s.%s", class_id, inst);
    else
        strlcpy(name, class_id, PATH_MAX);
...
    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);
}

到这里就会去获取你得项目代号,通过prop获取,可以看到variant_keys里面有四个属性,一次判断,有其中之一匹配上即可,如果匹配不上就会使用默认的primary,库就在对应的vendor、system、odm下搜索。到这里我们设备so库的查找就结束了,只要我们配置好项目属性值,与so库对应即可查询使用。

回到我们一开始说的地方,loadHwModule_l函数中还做了一件是,就是将获取的设备添加到mAudioHwDevs键值对中,其中key值由(audio_module_handle_t)

nextUniqueId(AUDIO_UNIQUE_ID_USE_MODULE);获取,这样可以保证这个值全局唯一。
现在我们完成audio interface的加载,但是每一个interface里面包含的设备又有非常多个,目前Android支持的就如下代码所示。


enum {    AUDIO_DEVICE_NONE                          = 0x0,    /* reserved bits */    AUDIO_DEVICE_BIT_IN                        = 0x80000000,    AUDIO_DEVICE_BIT_DEFAULT                   = 0x40000000,    /* output devices */这些是输出声音的设备,就是我们听声音的设备    AUDIO_DEVICE_OUT_EARPIECE                  = 0x1,    // 听筒    AUDIO_DEVICE_OUT_SPEAKER                   = 0x2,    // 扬声器    AUDIO_DEVICE_OUT_WIRED_HEADSET             = 0x4,    // 线控耳机,可以通过耳机控制远端播放、暂停、音量调节等功能的耳机    AUDIO_DEVICE_OUT_WIRED_HEADPHONE           = 0x8,    // 普通耳机,只能听,不能操控播放    AUDIO_DEVICE_OUT_BLUETOOTH_SCO             = 0x10,   // 单声道蓝牙耳机,十进制16    AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET     = 0x20,   // 车载免提蓝牙设备,十进制32    AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT      = 0x40,   // 立体声蓝牙耳机,十进制64    AUDIO_DEVICE_OUT_BLUETOOTH_A2DP            = 0x80,   // 蓝牙耳机    AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100,  // 十进制256    AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER    = 0x200,  // 十进制512    AUDIO_DEVICE_OUT_AUX_DIGITAL               = 0x400,  // HDMI输出    AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET         = 0x800,  // 十进制2048    AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET         = 0x1000, // 十进制4096    AUDIO_DEVICE_OUT_USB_ACCESSORY             = 0x2000,    AUDIO_DEVICE_OUT_USB_DEVICE                = 0x4000, //USB设备    AUDIO_DEVICE_OUT_REMOTE_SUBMIX             = 0x8000,    AUDIO_DEVICE_OUT_DEFAULT                   = AUDIO_DEVICE_BIT_DEFAULT,    /* input devices */ (这里主要是接收声音的设备就是我们对着说话的设备)    AUDIO_DEVICE_IN_COMMUNICATION         = AUDIO_DEVICE_BIT_IN | 0x1,    AUDIO_DEVICE_IN_AMBIENT               = AUDIO_DEVICE_BIT_IN | 0x2,    AUDIO_DEVICE_IN_BUILTIN_MIC           = AUDIO_DEVICE_BIT_IN | 0x4,//手机自带MIC    AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET = AUDIO_DEVICE_BIT_IN | 0x8,     //蓝牙耳机    AUDIO_DEVICE_IN_WIRED_HEADSET         = AUDIO_DEVICE_BIT_IN | 0x10,//3.5MM线性耳机    AUDIO_DEVICE_IN_AUX_DIGITAL           = AUDIO_DEVICE_BIT_IN | 0x20,    AUDIO_DEVICE_IN_VOICE_CALL            = AUDIO_DEVICE_BIT_IN | 0x40,    AUDIO_DEVICE_IN_BACK_MIC              = AUDIO_DEVICE_BIT_IN | 0x80,    AUDIO_DEVICE_IN_REMOTE_SUBMIX         = AUDIO_DEVICE_BIT_IN | 0x100,    AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET     = AUDIO_DEVICE_BIT_IN | 0x200,    AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET     = AUDIO_DEVICE_BIT_IN | 0x400,    AUDIO_DEVICE_IN_USB_ACCESSORY         = AUDIO_DEVICE_BIT_IN | 0x800,    AUDIO_DEVICE_IN_USB_DEVICE            = AUDIO_DEVICE_BIT_IN | 0x1000,   //USB耳机    AUDIO_DEVICE_IN_DEFAULT               = AUDIO_DEVICE_BIT_IN | AUDIO_DEVICE_BIT_DEFAULT,};

下面我们来继续分析,audioflinger是如何打开一个output通道的。打开output通道在audioflinger内的函数是openOutput:

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);
    if (outHwDev == NULL) {
        return 0;
    }
    if (*output == AUDIO_IO_HANDLE_NONE) {
        *output = nextUniqueId(AUDIO_UNIQUE_ID_USE_OUTPUT);
    }
    mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
    AudioStreamOut *outputStream = NULL;
    status_t status = outHwDev->openOutputStream(
            &outputStream,
            *output,
            devices,
            flags,
            config,
            address.string());
    mHardwareStatus = AUDIO_HW_IDLE;
    if (status == NO_ERROR) {
        if (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
            sp<MmapPlaybackThread> thread =
                    new MmapPlaybackThread(this, *output, outHwDev, outputStream,
                                          devices, AUDIO_DEVICE_NONE, mSystemReady);
            mMmapThreads.add(*output, thread);
            return thread;
        } else {
            sp<PlaybackThread> thread;
            if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
                thread = new OffloadThread(this, outputStream, *output, devices, mSystemReady);
            } else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT)
                    || !isValidPcmSinkFormat(config->format)
                    || !isValidPcmSinkChannelMask(config->channel_mask)) {
                thread = new DirectOutputThread(this, outputStream, *output, devices, mSystemReady);
            } else {
                thread = new MixerThread(this, outputStream, *output, devices, mSystemReady);
            }
            mPlaybackThreads.add(*output, thread);
            return thread;
        }
    }

    return 0;
}

上面代码的主要做了以下操作:

  • 查找合适的音频接口设备(findSuitableHwDev_l),这里最后调用的就是我们一开始讲道理的loadHwModule_l函数。

  • 创建音频流,通过openOutputStream获得了一个AudioStreamOut。

  • 创建播放线程PlaybackThread

    outHwDev用于记录了一个打开的音频接口设备,数据类型是audioHwDevice,就是通过刚刚分析的键值对mAudioHwDevs中获取到,对应的就是HAL的audio_hw_device,里面实现了HAL的共有属性,setMasterMute、setMasterVolume、open_output_stream等。

struct audio_module {
    struct hw_module_t common;
};

struct audio_hw_device {
    struct hw_device_t common;
    
    int (*set_master_volume)(struct audio_hw_device *dev, float volume);
    int (*set_parameters)(struct audio_hw_device *dev, const char *kv_pairs);
    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);
    int (*set_master_mute)(struct audio_hw_device *dev, bool mute);

};

下面我们来分别讲一下每一步都是如何实现的