IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android音频框架之一 详解工作流程及HAL驱动加载与配置 -> 正文阅读

[移动开发]Android音频框架之一 详解工作流程及HAL驱动加载与配置

前言

此音频架构梳理笔记、主要是因工作上需要在 Android8.1 以上版本中,增加 snd-aloop 虚拟声卡做前期准备工作,
本篇文章提纲挈领的把音频框架主线梳理清晰,通过这篇文章能够清晰如下内容:

1>. 声卡服务框架是什么时间产生、如何引发?

2>. 声卡框架主要模块都是什么,他们基本功能如何分配? audioFlinger、audioService、audioPolicyMannager等

3>. audio_policy_configuration.xml 与 audio_policy.conf 文件,是如何配置管理Android音频系统?
xml文件解析一般规则。

4>. 厂家 audio_hw_hal 驱动是如何被加载至系统的,由谁加载的、加载到哪里去了?

5>. 安卓 AUDIO-HAL 与 Linux snd-driver 是如何关联起来的,如果管理不同声卡?

希望您阅读此文章时,带着上述 5 点内容,能够快速全面的对安卓音频系统有框架认知。由于 android 声卡涉及内容较多,
本比较中未分析 soundTrigger 相关内容。 后面将分享 android 添加虚拟声卡系列笔记内容,敬请阅读讨论。

一、 AndroidRuntime.so 引发思考

android 系统 framework 代码起点, frameworks/base/core/jni/AndroidRuntime.cpp 文件,
此文件是android系统主线程代码,代码内容涉及系统很多模块,此程序主要是注册模块的JNI接口方法。
其中涉及到模块 native、sensorHal、media、audioflinger、displayflinger、camera、serialport、bindler等模块
从各模块名称上、可看出是 android 系统核心组件内容,由此可见 AndroidRuntime 是系统框架的入口。

二、 Android 音频框架

Android音频系统有两大服务:一是AudioFlinger,二是AudioPolicyService。AudioFlinger负责向下 访问AudioHardwareInterface,
实现音频PCM数据的混音/输入/输出,实现音量调节;
AudioPolicyService负责音 频输入输出设备的连接状态,音频策略调度即音频设备(如本地CODEC、Bluetooth A2DP、Headset)的切换
策略(注意它只是负责策略,真正的切换操作是在AudioFlinger中的openOutput,毕竟 AudioFlinger负责操作底层音频硬件)。

//> 此处敲黑板了!!!
如我们所知,BluetoothA2DP与ALSA设备并不走同一套 接口,因此 Android 的设计者就把ALSA设备接口扔到A2DP接口里面管理了。
这又是如何管理呢?简单来说,就是根据上层传下来的参数 devices,判断 devices 是否是 DEVICE_OUT_BLUETOOTH_A2DP,
如果是则走A2DP接口,如果不是则走ALSA设备接口。 https://blog.csdn.net/tronteng/article/details/8212641

2.0> audioserver 本地服务

@ frameworks/av/media/mediaserver/main_mediaserver.cpp
此程序是 audio 程序入口函数,在 android 系统初始化时,初始化脚本 audioserver.rc 文件、启动 audioserver 服务;
所有媒体服务端线程都在此被启动, 线程名称: /system/bin/mediaserver 。

#define LOG_TAG "audioserver"
//#define LOG_NDEBUG 0

#include <fcntl.h>
#include <sys/prctl.h>
#include <sys/wait.h>
#include <cutils/properties.h>

#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <utils/Log.h>

// from LOCAL_C_INCLUDES
#include "AudioFlinger.h"
#include "AudioPolicyService.h"
#include "MediaLogService.h"
#include "RadioService.h"
#include "SoundTriggerHwService.h"

using namespace android;

int main(int argc __unused, char **argv)
{
    signal(SIGPIPE, SIG_IGN);

    bool doLog = (bool) property_get_bool("ro.test_harness", 0);

    pid_t childPid;
    // FIXME The advantage of making the process containing media.log service the parent process of
    // the process that contains the other audio services, is that it allows us to collect more
    // detailed information such as signal numbers, stop and continue, resource usage, etc.
    // But it is also more complex.  Consider replacing this by independent processes, and using
    // binder on death notification instead.
    if (doLog && (childPid = fork()) != 0) {
        // media.log service
        //prctl(PR_SET_NAME, (unsigned long) "media.log", 0, 0, 0);
        // unfortunately ps ignores PR_SET_NAME for the main thread, so use this ugly hack
        strcpy(argv[0], "media.log");
        sp<ProcessState> proc(ProcessState::self());
        MediaLogService::instantiate();
        ProcessState::self()->startThreadPool();
        IPCThreadState::self()->joinThreadPool();
        for (;;) {
            siginfo_t info;
            int ret = waitid(P_PID, childPid, &info, WEXITED | WSTOPPED | WCONTINUED);
            if (ret == EINTR) {
                continue;
            }
            if (ret < 0) {
                break;
            }
            char buffer[32];
            const char *code;
            switch (info.si_code) {
            case CLD_EXITED:
                code = "CLD_EXITED";
                break;
            case CLD_KILLED:
                code = "CLD_KILLED";
                break;
            case CLD_DUMPED:
                code = "CLD_DUMPED";
                break;
            case CLD_STOPPED:
                code = "CLD_STOPPED";
                break;
            case CLD_TRAPPED:
                code = "CLD_TRAPPED";
                break;
            case CLD_CONTINUED:
                code = "CLD_CONTINUED";
                break;
            default:
                snprintf(buffer, sizeof(buffer), "unknown (%d)", info.si_code);
                code = buffer;
                break;
            }
            struct rusage usage;
            getrusage(RUSAGE_CHILDREN, &usage);
            ALOG(LOG_ERROR, "media.log", "pid %d status %d code %s user %ld.%03lds sys %ld.%03lds",
                    info.si_pid, info.si_status, code,
                    usage.ru_utime.tv_sec, usage.ru_utime.tv_usec / 1000,
                    usage.ru_stime.tv_sec, usage.ru_stime.tv_usec / 1000);
            sp<IServiceManager> sm = defaultServiceManager();
            sp<IBinder> binder = sm->getService(String16("media.log"));
            if (binder != 0) {
                Vector<String16> args;
                binder->dump(-1, args);
            }
            switch (info.si_code) {
            case CLD_EXITED:
            case CLD_KILLED:
            case CLD_DUMPED: {
                ALOG(LOG_INFO, "media.log", "exiting");
                _exit(0);
                // not reached
                }
            default:
                break;
            }
        }
    } else {
        // all other services
        if (doLog) {
            prctl(PR_SET_PDEATHSIG, SIGKILL);   // if parent media.log dies before me, kill me also
            setpgid(0, 0);                      // but if I die first, don't kill my parent
        }
        sp<ProcessState> proc(ProcessState::self());
        sp<IServiceManager> sm = defaultServiceManager();
        ALOGI("ServiceManager: %p", sm.get());
        AudioFlinger::instantiate();
        AudioPolicyService::instantiate();       //> @ av/services/audiopolicy/service/AudioPolicyService.cpp
        RadioService::instantiate();
        SoundTriggerHwService::instantiate();
        ProcessState::self()->startThreadPool();
        IPCThreadState::self()->joinThreadPool();
    }
}

此线程启动服务有:AudioFlinger\AudioPolicyService\RadioService\SoundTriggerHwService 服务;
其中 RadioService 是电话服务,不是本次讨论内容略过。

2.1> AudioPolicyService 本地服务的创建

@ framework/av/services/audiopolicy/service/AudioPolicyService.cpp
此 AudioPolicyService::instantiate(); 函数执行将调用下面函数执行。

void AudioPolicyService::onFirstRef()
{
    {
        Mutex::Autolock _l(mLock);

        // start tone playback thread
        mTonePlaybackThread = new AudioCommandThread(String8("ApmTone"), this);
        // start audio commands thread
        mAudioCommandThread = new AudioCommandThread(String8("ApmAudio"), this);
        // start output activity command thread
        mOutputCommandThread = new AudioCommandThread(String8("ApmOutput"), this);

#ifdef USE_LEGACY_AUDIO_POLICY
        ALOGI("AudioPolicyService CSTOR in legacy mode");

        /* instantiate the audio policy manager */
        const struct hw_module_t *module;
        int rc = hw_get_module(AUDIO_POLICY_HARDWARE_MODULE_ID, &module);         //> 获取 AUDIO_POLICY_HARDWARE_MODULE_ID 的 module 内容
        if (rc) {
            return;
        }
        rc = audio_policy_dev_open(module, &mpAudioPolicyDev);                    //> 打开 AudioPolicyDevice 逻辑设备
        ALOGE_IF(rc, "couldn't open audio policy device (%s)", strerror(-rc));
        if (rc) {
            return;
        }

        rc = mpAudioPolicyDev->create_audio_policy(mpAudioPolicyDev, &aps_ops, this,
                                                   &mpAudioPolicy);               //> 调用 create_legacy_ap() 函数创建路由策略
        ALOGE_IF(rc, "couldn't create audio policy (%s)", strerror(-rc));
        if (rc) {
            return;
        }

        rc = mpAudioPolicy->init_check(mpAudioPolicy);
        ALOGE_IF(rc, "couldn't init_check the audio policy (%s)", strerror(-rc));
        if (rc) {
            return;
        }
        ALOGI("Loaded audio policy from %s (%s)", module->name, module->id);
#else
        ALOGI("AudioPolicyService CSTOR in new mode");                          //> 采用 XML 配置文件模式
        mAudioPolicyClient = new AudioPolicyClient(this);
        mAudioPolicyManager = createAudioPolicyManager(mAudioPolicyClient);     //> 此函数创建 AudioPolicyManager() 对象。
#endif
    }
    // load audio processing modules
    sp<AudioPolicyEffects>audioPolicyEffects = new AudioPolicyEffects();
    {
        Mutex::Autolock _l(mLock);
        mAudioPolicyEffects = audioPolicyEffects;
    }
}

2.1.1 legacy 模式、创建策略与声卡

@ hardware/libhardware/include/hardware/audio_policy.h
audio_policy 宏定义

/**
 * The id of this module
 */
#define AUDIO_POLICY_HARDWARE_MODULE_ID "audio_policy"

@ hardware/rockchip/audio/legacy_hal/audio_policy_hal.cpp

static int legacy_ap_dev_open(const hw_module_t* module, const char* name,
                                    hw_device_t** device)
{
    struct legacy_ap_device *dev;

    if (strcmp(name, AUDIO_POLICY_INTERFACE) != 0)
        return -EINVAL;

    dev = (struct legacy_ap_device *)calloc(1, sizeof(*dev));
    if (!dev)
        return -ENOMEM;

    dev->device.common.tag = HARDWARE_DEVICE_TAG;
    dev->device.common.version = 0;
    dev->device.common.module = const_cast<hw_module_t*>(module);
    dev->device.common.close = legacy_ap_dev_close;
    dev->device.create_audio_policy = create_legacy_ap;
    dev->device.destroy_audio_policy = destroy_legacy_ap;
    *device = &dev->device.common;
    return 0;
}

static struct hw_module_methods_t legacy_ap_module_methods = {
        .open = legacy_ap_dev_open
};

struct legacy_ap_module HAL_MODULE_INFO_SYM = {
    .module = {
        .common = {
            .tag = HARDWARE_MODULE_TAG,
            .version_major = 1,
            .version_minor = 0,
            .id = AUDIO_POLICY_HARDWARE_MODULE_ID,
            .name = "LEGACY Audio Policy HAL",
            .author = "The Android Open Source Project",
            .methods = &legacy_ap_module_methods,
            .dso = NULL,
            .reserved = {0},
        },
    },
};

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

/**
 * The id of this module
 */
#define AUDIO_HARDWARE_MODULE_ID "audio"
/**
 * List of known audio HAL modules. This is the base name of the audio HAL
 * library composed of the "audio." prefix, one of the base names below and
 * a suffix specific to the device.
 * e.g: audio.primary.goldfish.so or audio.a2dp.default.so
 */
#define AUDIO_HARDWARE_MODULE_ID_PRIMARY "primary"
#define AUDIO_HARDWARE_MODULE_ID_A2DP "a2dp"
#define AUDIO_HARDWARE_MODULE_ID_USB "usb"
#define AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX "r_submix"
#define AUDIO_HARDWARE_MODULE_ID_CODEC_OFFLOAD "codec_offload"

@ hardware/rockchip/audio/legacy_hal/audio_hw_hal.cpp


#define LOG_TAG "legacy_audio_hw_hal"
//#define LOG_NDEBUG 0

#include <stdint.h>

#include <hardware/hardware.h>
#include <system/audio.h>
#include <hardware/audio.h>

#include <hardware_legacy/AudioHardwareInterface.h>
#include <hardware_legacy/AudioSystemLegacy.h>
static int legacy_adev_open(const hw_module_t* module, const char* name,
                            hw_device_t** device)
{
    struct legacy_audio_device *ladev;
    int ret;

    if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
        return -EINVAL;

    ladev = (struct legacy_audio_device *)calloc(1, sizeof(*ladev));
    if (!ladev)
        return -ENOMEM;

    ladev->device.common.tag = HARDWARE_DEVICE_TAG;
    ladev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
    ladev->device.common.module = const_cast<hw_module_t*>(module);
    ladev->device.common.close = legacy_adev_close;

    ladev->device.init_check = adev_init_check;
    ladev->device.set_voice_volume = adev_set_voice_volume;
    ladev->device.set_master_volume = adev_set_master_volume;
    ladev->device.get_master_volume = adev_get_master_volume;
    ladev->device.set_mode = adev_set_mode;
    ladev->device.set_mic_mute = adev_set_mic_mute;
    ladev->device.get_mic_mute = adev_get_mic_mute;
    ladev->device.set_parameters = adev_set_parameters;
    ladev->device.get_parameters = adev_get_parameters;
    ladev->device.get_input_buffer_size = adev_get_input_buffer_size;
    ladev->device.open_output_stream = adev_open_output_stream;
    ladev->device.close_output_stream = adev_close_output_stream;
    ladev->device.open_input_stream = adev_open_input_stream;
    ladev->device.close_input_stream = adev_close_input_stream;
    ladev->device.dump = adev_dump;

    ladev->hwif = createAudioHardware();
    if (!ladev->hwif) {
        ret = -EIO;
        goto err_create_audio_hw;
    }

    *device = &ladev->device.common;

    return 0;

err_create_audio_hw:
    free(ladev);
    return ret;
}

static struct hw_module_methods_t legacy_audio_module_methods = {
        open: legacy_adev_open
};

struct legacy_audio_module HAL_MODULE_INFO_SYM = {
    module: {
        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: "LEGACY Audio HW HAL",
            author: "The Android Open Source Project",
            methods: &legacy_audio_module_methods,
            dso : NULL,
            reserved : {0},
        },
    },
};

Android7.0 以前版本采用 legacy 接口, 通过 AUDIO_POLICY_HARDWARE_MODULE_ID、AUDIO_HARDWARE_MODULE_ID 方式、
查找声卡路由策略和声卡hal层驱动。

2.1.2 采用 XML 配置文件方法

@ av/services/audiopolicy/manager/AudioPolicyFactory.cpp

#include "managerdefault/AudioPolicyManager.h"
namespace android {

extern "C" AudioPolicyInterface* createAudioPolicyManager(
        AudioPolicyClientInterface *clientInterface)
{
    return new AudioPolicyManager(clientInterface);                 //> 此函数创建 2.3> 的 AudioPolicyManager 对象。
}

}

总结:

2.2> audioflinger 本地混音管理框架

@ frameworks/av/services/audioflinger/audioFlinger.hpp 这部分内容被编译成库 libaudioflinger.so,它是Audio系统的混音器服务部分。

 // IAudioFlinger interface, in binder opcode order
    virtual sp<IAudioTrack> createTrack(
                                audio_stream_type_t streamType,
                                uint32_t sampleRate,
                                audio_format_t format,
                                audio_channel_mask_t channelMask,
                                size_t *pFrameCount,
                                audio_output_flags_t *flags,
                                const sp<IMemory>& sharedBuffer,
                                audio_io_handle_t output,
                                pid_t pid,
                                pid_t tid,
                                audio_session_t *sessionId,
                                int clientUid,
                                status_t *status /*non-NULL*/,
                                audio_port_handle_t portId);

    virtual sp<IAudioRecord> openRecord(
                                audio_io_handle_t input,
                                uint32_t sampleRate,
                                audio_format_t format,
                                audio_channel_mask_t channelMask,
                                const String16& opPackageName,
                                size_t *pFrameCount,
                                audio_input_flags_t *flags,
                                pid_t pid,
                                pid_t tid,
                                int clientUid,
                                audio_session_t *sessionId,
                                size_t *notificationFrames,
                                sp<IMemory>& cblk,
                                sp<IMemory>& buffers,
                                status_t *status /*non-NULL*/,
                                audio_port_handle_t portId);
    virtual sp<IEffect> createEffect(
                        effect_descriptor_t *pDesc,
                        const sp<IEffectClient>& effectClient,
                        int32_t priority,
                        audio_io_handle_t io,
                        audio_session_t sessionId,
                        const String16& opPackageName,
                        pid_t pid,
                        status_t *status /*non-NULL*/,
                        int *id,
                        int *enabled);

    virtual status_t openInput(audio_module_handle_t module,
                               audio_io_handle_t *input,
                               audio_config_t *config,
                               audio_devices_t *device,
                               const String8& address,
                               audio_source_t source,
                               audio_input_flags_t flags);

    virtual uint32_t getPrimaryOutputSamplingRate();
    virtual size_t getPrimaryOutputFrameCount();
    /* Create an audio patch between several source and sink ports */
    virtual status_t createAudioPatch(const struct audio_patch *patch,
                                       audio_patch_handle_t *handle);

    sp<SyncEvent> createSyncEvent(AudioSystem::sync_event_t type,
                                        audio_session_t triggerSession,
                                        audio_session_t listenerSession,
                                        sync_event_callback_t callBack,
                                        const wp<RefBase>& cookie);

2.3> audiopolicy 音频策略管理框架

@frameworks/av/services/audiopolicy/service/AudioPolicyManager.cpp

    virtual status_t setDeviceConnectionState(audio_devices_t device,
                                              audio_policy_dev_state_t state,
                                              const char *device_address,
                                              const char *device_name);

    virtual status_t handleDeviceConfigChange(audio_devices_t device,
                                              const char *device_address,
                                              const char *device_name);

    virtual status_t createAudioPatch(const struct audio_patch *patch,
                                       audio_patch_handle_t *handle);

    virtual status_t startAudioSource(const struct audio_port_config *source,
                                      const audio_attributes_t *attributes,
                                      audio_patch_handle_t *handle);

Android 7.0 弃用了 audio_policy.conf,并增加了对使用 XML 文件格式来定义音频拓扑的支持,这种文件格式更通俗易懂,
具有多种编辑和解析工具,并且足够灵活,可以描述复杂的音频拓扑。

注意:Android 7.0 仍支持使用 audio_policy.conf;默认使用这种旧版格式。要使用 XML 文件格式,需要在设备 Makefile 中
添加构建选项 USE_XML_AUDIO_POLICY_CONF := 1。

此程序获取 audio_policy_configuration.xml 生成音频设备管理对象,根据 xml 定义构建 audio policy 对象和 input、output 设备,
通过 dumpsys media.audio_policy 可以看到本机声卡设备和路由策略。

AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
    :
#ifdef AUDIO_POLICY_TEST
    Thread(false),
#endif //AUDIO_POLICY_TEST
    mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
    mA2dpSuspended(false),
    mAudioPortGeneration(1),
    mBeaconMuteRefCount(0),
    mBeaconPlayingRefCount(0),
    mBeaconMuted(false),
    mTtsOutputAvailable(false),
    mMasterMono(false)
{
    mUidCached = getuid();
    mpClientInterface = clientInterface;      //> 把入口参数 clientInterface 赋值给 mpClientInterface
    // TODO: remove when legacy conf file is removed. true on devices that use DRC on the
    // DEVICE_CATEGORY_SPEAKER path to boost soft sounds, used to adjust volume curves accordingly.
    // Note: remove also speaker_drc_enabled from global configuration of XML config file.
    bool speakerDrcEnabled = false;

#ifdef USE_XML_AUDIO_POLICY_CONF
    mVolumeCurves = new VolumeCurvesCollection();
    AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices, //> 此 mHwModules 头文件申明全局变量.
                             mDefaultOutputDevice, speakerDrcEnabled,
                             static_cast<VolumeCurvesCollection *>(mVolumeCurves));
    PolicySerializer serializer;
    if (serializer.deserialize(AUDIO_POLICY_XML_CONFIG_FILE, config) != NO_ERROR) { //> 在 deserialize() 方法中,创建 mHwModules 对象
#else                                                                               //> 和 mAvailableOutputDevices、mAvailableInputDevices 对象
    mVolumeCurves = new StreamDescriptorCollection();  //> 下面是采用 audio_policy.conf 配置方式

    AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices,  
                             mDefaultOutputDevice, speakerDrcEnabled);
    if ((ConfigParsingUtils::loadConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE, config) != NO_ERROR) &&
            (ConfigParsingUtils::loadConfig(AUDIO_POLICY_CONFIG_FILE, config) != NO_ERROR)) {
#endif
        ALOGE("could not load audio policy configuration file, setting defaults");
        config.setDefault();
    }

    mHDMIOutputDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_AUX_DIGITAL);
    mSPDIFOutputDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPDIF);

    // mAvailableOutputDevices and mAvailableInputDevices now contain all attached devices
    // open all output streams needed to access attached devices
    audio_devices_t outputDeviceTypes = mAvailableOutputDevices.types();
    audio_devices_t inputDeviceTypes = mAvailableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN;
    for (size_t i = 0; i < mHwModules.size(); i++) {
        mHwModules[i]->mHandle = mpClientInterface->loadHwModule(mHwModules[i]->getName());  //> loadHwModule 装载 HAL驱动模块
        if (mHwModules[i]->mHandle == 0) {
            ALOGW("could not open HW module %s", mHwModules[i]->getName());
            continue;
        }
        // open all output streams needed to access attached devices
        // except for direct output streams that are only opened when they are actually
        // required by an app.
        // This also validates mAvailableOutputDevices list
        for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
        {
            const sp<IOProfile> outProfile = mHwModules[i]->mOutputProfiles[j];
            ...  //> 省略代码
            sp<SwAudioOutputDescriptor> outputDesc = new SwAudioOutputDescriptor(outProfile,
                                                                                 mpClientInterface);
            const DeviceVector &supportedDevices = outProfile->getSupportedDevices();
            const DeviceVector &devicesForType = supportedDevices.getDevicesFromType(profileType);
            String8 address = devicesForType.size() > 0 ? devicesForType.itemAt(0)->mAddress
                    : String8("");

            outputDesc->mDevice = profileType;
            audio_config_t config = AUDIO_CONFIG_INITIALIZER;
            config.sample_rate = outputDesc->mSamplingRate;
            config.channel_mask = outputDesc->mChannelMask;
            config.format = outputDesc->mFormat;
            audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
            status_t status = mpClientInterface->openOutput(outProfile->getModuleHandle(),
                                                            &output,
                                                            &config,
                                                            &outputDesc->mDevice,
                                                            address,
                                                            &outputDesc->mLatency,
                                                            outputDesc->mFlags);

            if (status != NO_ERROR) {
                ALOGW("Cannot open output stream for device %08x on hw module %s",
                      outputDesc->mDevice,
                      mHwModules[i]->getName());
            } else {
                outputDesc->mSamplingRate = config.sample_rate;
                outputDesc->mChannelMask = config.channel_mask;
                outputDesc->mFormat = config.format;

                for (size_t k = 0; k  < supportedDevices.size(); k++) {
                    ssize_t index = mAvailableOutputDevices.indexOf(supportedDevices[k]);
                    // give a valid ID to an attached device once confirmed it is reachable
                    if (index >= 0 && !mAvailableOutputDevices[index]->isAttached()) {
                        mAvailableOutputDevices[index]->attach(mHwModules[i]);
                    }
                }
                if (mPrimaryOutput == 0 &&
                        outProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
                    mPrimaryOutput = outputDesc;
                }
                addOutput(output, outputDesc);
                setOutputDevice(outputDesc,
                                outputDesc->mDevice,
                                true,
                                0,
                                NULL,
                                address.string());
            }
        }

        // open input streams needed to access attached devices to validate
        // mAvailableInputDevices list
        for (size_t j = 0; j < mHwModules[i]->mInputProfiles.size(); j++)
        {
            const sp<IOProfile> inProfile = mHwModules[i]->mInputProfiles[j];

            if (!inProfile->hasSupportedDevices()) {
                ALOGW("Input profile contains no device on module %s", mHwModules[i]->getName());
                continue;
            }
            // chose first device present in profile's SupportedDevices also part of
            // inputDeviceTypes
            audio_devices_t profileType = inProfile->getSupportedDeviceForType(inputDeviceTypes);

            if ((profileType & inputDeviceTypes) == 0) {
                continue;
            }
            sp<AudioInputDescriptor> inputDesc =
                    new AudioInputDescriptor(inProfile);

            inputDesc->mDevice = profileType;

            // find the address
            DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromType(profileType);
            //   the inputs vector must be of size 1, but we don't want to crash here
            String8 address = inputDevices.size() > 0 ? inputDevices.itemAt(0)->mAddress
                    : String8("");
            ALOGV("  for input device 0x%x using address %s", profileType, address.string());
            ALOGE_IF(inputDevices.size() == 0, "Input device list is empty!");

            audio_config_t config = AUDIO_CONFIG_INITIALIZER;
            config.sample_rate = inputDesc->mSamplingRate;
            config.channel_mask = inputDesc->mChannelMask;
            config.format = inputDesc->mFormat;
            audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
            status_t status = mpClientInterface->openInput(inProfile->getModuleHandle(),
                                                           &input,
                                                           &config,
                                                           &inputDesc->mDevice,
                                                           address,
                                                           AUDIO_SOURCE_MIC,
                                                           AUDIO_INPUT_FLAG_NONE);

            if (status == NO_ERROR) {
                const DeviceVector &supportedDevices = inProfile->getSupportedDevices();
                for (size_t k = 0; k  < supportedDevices.size(); k++) {
                    ssize_t index =  mAvailableInputDevices.indexOf(supportedDevices[k]);
                    // give a valid ID to an attached device once confirmed it is reachable
                    if (index >= 0) {
                        sp<DeviceDescriptor> devDesc = mAvailableInputDevices[index];
                        if (!devDesc->isAttached()) {
                            devDesc->attach(mHwModules[i]);
                            devDesc->importAudioPort(inProfile);
                        }
                    }
                }
                mpClientInterface->closeInput(input);
            } else {
                ALOGW("Cannot open input stream for device %08x on hw module %s",
                      inputDesc->mDevice,
                      mHwModules[i]->getName());
            }
        }
    }
}

此 audio_policy_configuration.xml 包含 usb、a2dp 和 r_submix 策略配置文件 xml , 这些文件会拷贝至 system/etc/ 文件夹中。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<audioPolicyConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
    <!-- version section contains a “version” tag in the form “major.minor” e.g version=1.0-->
    <!-- Global configuration Decalaration -->
    <globalConfiguration speaker_drc_enabled="true"/>

    <modules>
        <!-- Primary Audio HAL -->
        <module name="primary" halVersion="3.0">
            <attachedDevices>
                <item>Speaker</item>
                <item>Built-In Mic</item>
                <item>Built-In Back Mic</item>
            </attachedDevices>
            <defaultOutputDevice>Speaker</defaultOutputDevice>

            <mixPorts>
                <mixPort name="primary output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                </mixPort>
                <mixPort name="deep_buffer" role="source"
                        flags="AUDIO_OUTPUT_FLAG_DEEP_BUFFER">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                </mixPort>
                <mixPort name="compressed_offload" role="source"
                         flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|AUDIO_OUTPUT_FLAG_NON_BLOCKING">
                    <profile name="" format="AUDIO_FORMAT_MP3"
                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
                             channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/>
                    <profile name="" format="AUDIO_FORMAT_AAC"
                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
                             channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/>
                    <profile name="" format="AUDIO_FORMAT_AAC_LC"
                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
                             channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/>
                </mixPort>

                <mixPort name="voice_tx" role="source">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
                </mixPort>
                <mixPort name="primary input" role="sink">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
                             channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
                </mixPort>
                <mixPort name="voice_rx" role="sink">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
                </mixPort>
            </mixPorts>

            <devicePorts>
                <!-- Output devices declaration, i.e. Sink DEVICE PORT -->
                <devicePort tagName="Earpiece" type="AUDIO_DEVICE_OUT_EARPIECE" role="sink">
                   <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                            samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
                </devicePort>
                <devicePort tagName="Speaker" role="sink" type="AUDIO_DEVICE_OUT_SPEAKER" address="">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                    <gains>
                        <gain name="gain_1" mode="AUDIO_GAIN_MODE_JOINT"
                              minValueMB="-8400"
                              maxValueMB="4000"
                              defaultValueMB="0"
                              stepValueMB="100"/>
                    </gains>
                </devicePort>
                <devicePort tagName="Wired Headset" type="AUDIO_DEVICE_OUT_WIRED_HEADSET" role="sink">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                </devicePort>
                <devicePort tagName="Wired Headphones" type="AUDIO_DEVICE_OUT_WIRED_HEADPHONE" role="sink">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                </devicePort>
                <devicePort tagName="BT SCO" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO" role="sink">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
                </devicePort>
                <devicePort tagName="BT SCO Headset" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET" role="sink">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
                </devicePort>
                <devicePort tagName="BT SCO Car Kit" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT" role="sink">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
                </devicePort>
                <devicePort tagName="Telephony Tx" type="AUDIO_DEVICE_OUT_TELEPHONY_TX" role="sink">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
                </devicePort>

                <devicePort tagName="Built-In Mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" role="source">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
                             channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
                </devicePort>
                <devicePort tagName="Built-In Back Mic" type="AUDIO_DEVICE_IN_BACK_MIC" role="source">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
                             channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
                </devicePort>
                <devicePort tagName="Wired Headset Mic" type="AUDIO_DEVICE_IN_WIRED_HEADSET" role="source">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
                             channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
                </devicePort>
                <devicePort tagName="BT SCO Headset Mic" type="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET" role="source">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
                </devicePort>
                <devicePort tagName="Telephony Rx" type="AUDIO_DEVICE_IN_TELEPHONY_RX" role="source">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
                </devicePort>
            </devicePorts>
            <!-- route declaration, i.e. list all available sources for a given sink -->
            <routes>
                <route type="mix" sink="Earpiece"
                       sources="primary output,deep_buffer,BT SCO Headset Mic"/>
                <route type="mix" sink="Speaker"
                       sources="primary output,deep_buffer,compressed_offload,BT SCO Headset Mic,Telephony Rx"/>
                <route type="mix" sink="Wired Headset"
                       sources="primary output,deep_buffer,compressed_offload,BT SCO Headset Mic,Telephony Rx"/>
                <route type="mix" sink="Wired Headphones"
                       sources="primary output,deep_buffer,compressed_offload,BT SCO Headset Mic,Telephony Rx"/>
                <route type="mix" sink="Telephony Tx"
                       sources="voice_tx"/>
                <route type="mix" sink="primary input"
                       sources="Built-In Mic,Built-In Back Mic,Wired Headset Mic,BT SCO Headset Mic"/>
                <route type="mix" sink="Telephony Tx"
                       sources="Built-In Mic,Built-In Back Mic,Wired Headset Mic,BT SCO Headset Mic"/>
                <route type="mix" sink="voice_rx"
                       sources="Telephony Rx"/>
            </routes>
        </module>

        <!-- HDMI Audio HAL -->
        <module description="HDMI Audio HAL" name="hdmi" version="2.0">
            <mixPorts>
                <mixPort name="hdmi output" role="source">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" samplingRates="48000"/>
                </mixPort>
            </mixPorts>
            <devicePorts>
                <devicePort tagName="HDMI Out" type="AUDIO_DEVICE_OUT_AUX_DIGITAL" role="sink">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                </devicePort>
            </devicePorts>
            <routes>
                <route type="mix" sink="HDMI Out"
                       sources="hdmi output"/>
            </routes>
        </module>

        <!-- A2dp Audio HAL -->        <xi:include href="a2dp_audio_policy_configuration.xml"/>

        <!-- Usb Audio HAL -->        <xi:include href="usb_audio_policy_configuration.xml"/>

        <!-- Remote Submix Audio HAL -->   <xi:include href="r_submix_audio_policy_configuration.xml"/>

    </modules>    <!-- End of Modules section -->
    <!-- Volume section -->
    <xi:include href="audio_policy_volumes.xml"/>
    <xi:include href="default_volume_tables.xml"/>
    <!-- End of Volume section -->

</audioPolicyConfiguration>

总结:
(1). 在 AudioPolicyManager(AudioPolicyClientInterface *clientInterface) 构建函数中,根据 xml 配置文件 module 生成
mHwModules[] 设备对象,多个 moduel 就生成多个 mHwModules[] 对象;

(2). 把 mHwModules[] 设备中的 输入与输出sink,添加到所有 mAvailableOutputDevices 和 mAvailableInputDevices 实例中;

(3). 把所有 mHwModules[] 设备中sink取交集,作为音频输入与输出设备接口;

(4). 每各 mHwModules[] 都由 route 属性,提取路由策略相关信息。

rk3288:/ # dumpsys media.audio_policy
AudioPolicyManager Dump: 0xb4d3e200
 Primary Output: 13
 Phone state: 0
 Force use for communications 0
 Force use for media 0
 Force use for record 0
 Force use for dock 8
 Force use for system 0
 Force use for hdmi system audio 0
 Force use for encoded surround output 0
 TTS output not available
 Master mono: off
- Available output devices:
  Device 1:
  - id:  1
  - tag name: Speaker
  - type: AUDIO_DEVICE_OUT_SPEAKER                        
  - Profiles:
      Profile 0:
          - format: AUDIO_FORMAT_PCM_16_BIT
          - sampling rates:48000
          - channel masks:0x0003
  - gains:
    Gain 1:
    - mode: 00000001
    - channel_mask: 00000000
    - min_value: 0 mB
    - max_value: 4000 mB
    - default_value: 0 mB
    - step_value: 100 mB
    - min_ramp_ms: 0 ms
    - max_ramp_ms: 0 ms
- Available input devices:
  Device 1:
  - id:  4
  - tag name: Built-In Mic
  - type: AUDIO_DEVICE_IN_BUILTIN_MIC                     
  - Profiles:
      Profile 0:
          - format: AUDIO_FORMAT_PCM_16_BIT
          - sampling rates:8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
          - channel masks:0x000c, 0x0010, 0x0030
  Device 2:
  - id:  5
  - tag name: Built-In Back Mic
  - type: AUDIO_DEVICE_IN_BACK_MIC                        
  - Profiles:
      Profile 0:
          - format: AUDIO_FORMAT_PCM_16_BIT
          - sampling rates:8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
          - channel masks:0x000c, 0x0010, 0x0030
  Device 3:
  - id:  6
  - tag name: Remote Submix In
  - type: AUDIO_DEVICE_IN_REMOTE_SUBMIX                   
  - address: 0                               
  - Profiles:
      Profile 0:
          - format: AUDIO_FORMAT_PCM_16_BIT
          - sampling rates:48000
          - channel masks:0x000c

HW Modules dump:
- HW Module 1:
  - name: primary
  - handle: 10
  - version: 2.5
  - outputs:
    output 0:
    - name: primary output
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:48000
            - channel masks:0x0003
    - flags: 0x0002
    - Supported devices:
      Device 1:
      - tag name: Earpiece
      - type: AUDIO_DEVICE_OUT_EARPIECE                       
      Device 2:
      - id:  1
      - tag name: Speaker
      - type: AUDIO_DEVICE_OUT_SPEAKER                        
      Device 3:
      - tag name: Wired Headset
      - type: AUDIO_DEVICE_OUT_WIRED_HEADSET                  
      Device 4:
      - tag name: Wired Headphones
      - type: AUDIO_DEVICE_OUT_WIRED_HEADPHONE                
    output 1:
    - name: deep_buffer
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:48000
            - channel masks:0x0003
    - flags: 0x0008
    - Supported devices:
      Device 1:
      - tag name: Earpiece
      - type: AUDIO_DEVICE_OUT_EARPIECE                       
      Device 2:
      - id:  1
      - tag name: Speaker
      - type: AUDIO_DEVICE_OUT_SPEAKER                        
      Device 3:
      - tag name: Wired Headset
      - type: AUDIO_DEVICE_OUT_WIRED_HEADSET                  
      Device 4:
      - tag name: Wired Headphones
      - type: AUDIO_DEVICE_OUT_WIRED_HEADPHONE                
    output 2:
    - name: compressed_offload
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_MP3
            - sampling rates:8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
            - channel masks:0x0001, 0x0003
        Profile 1:
            - format: AUDIO_FORMAT_AAC
            - sampling rates:8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
            - channel masks:0x0001, 0x0003
        Profile 2:
            - format: AUDIO_FORMAT_AAC_LC
            - sampling rates:8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
            - channel masks:0x0001, 0x0003
    - flags: 0x0031
    - Supported devices:
      Device 1:
      - id:  1
      - tag name: Speaker
      - type: AUDIO_DEVICE_OUT_SPEAKER                        
      Device 2:
      - tag name: Wired Headset
      - type: AUDIO_DEVICE_OUT_WIRED_HEADSET                  
      Device 3:
      - tag name: Wired Headphones
      - type: AUDIO_DEVICE_OUT_WIRED_HEADPHONE                
    output 3:
    - name: voice_tx
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:8000, 16000
            - channel masks:0x0001
    - flags: 0x0000
    - Supported devices:
      Device 1:
      - tag name: Telephony Tx
      - type: AUDIO_DEVICE_OUT_TELEPHONY_TX                   
  - inputs:
    input 0:
    - name: primary input
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
            - channel masks:0x000c, 0x0010, 0x0030
    - flags: 0x0000
    - Supported devices:
      Device 1:
      - id:  4
      - tag name: Built-In Mic
      - type: AUDIO_DEVICE_IN_BUILTIN_MIC                     
      Device 2:
      - id:  5
      - tag name: Built-In Back Mic
      - type: AUDIO_DEVICE_IN_BACK_MIC                        
      Device 3:
      - tag name: Wired Headset Mic
      - type: AUDIO_DEVICE_IN_WIRED_HEADSET                   
      Device 4:
      - tag name: BT SCO Headset Mic
      - type: AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET           
    input 1:
    - name: voice_rx
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:8000, 16000
            - channel masks:0x0010
    - flags: 0x0000
    - Supported devices:
      Device 1:
      - tag name: Telephony Rx
      - type: AUDIO_DEVICE_IN_TELEPHONY_RX                    
  - Declared devices:
    Device 1:
    - tag name: Earpiece
    - type: AUDIO_DEVICE_OUT_EARPIECE                       
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:48000
            - channel masks:0x0010
    Device 2:
    - id:  1
    - tag name: Speaker
    - type: AUDIO_DEVICE_OUT_SPEAKER                        
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:48000
            - channel masks:0x0003
    - gains:
      Gain 1:
      - mode: 00000001
      - channel_mask: 00000000
      - min_value: 0 mB
      - max_value: 4000 mB
      - default_value: 0 mB
      - step_value: 100 mB
      - min_ramp_ms: 0 ms
      - max_ramp_ms: 0 ms
    Device 3:
    - tag name: Wired Headset
    - type: AUDIO_DEVICE_OUT_WIRED_HEADSET                  
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:48000
            - channel masks:0x0003
    Device 4:
    - tag name: Wired Headphones
    - type: AUDIO_DEVICE_OUT_WIRED_HEADPHONE                
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:48000
            - channel masks:0x0003
    Device 5:
    - tag name: BT SCO
    - type: AUDIO_DEVICE_OUT_BLUETOOTH_SCO                  
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:8000, 16000
            - channel masks:0x0001
    Device 6:
    - tag name: BT SCO Headset
    - type: AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET          
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:8000, 16000
            - channel masks:0x0001
    Device 7:
    - tag name: BT SCO Car Kit
    - type: AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT           
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:8000, 16000
            - channel masks:0x0001
    Device 8:
    - tag name: Telephony Tx
    - type: AUDIO_DEVICE_OUT_TELEPHONY_TX                   
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:8000, 16000
            - channel masks:0x0001
    Device 9:
    - id:  4
    - tag name: Built-In Mic
    - type: AUDIO_DEVICE_IN_BUILTIN_MIC                     
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
            - channel masks:0x000c, 0x0010, 0x0030
    Device 10:
    - id:  5
    - tag name: Built-In Back Mic
    - type: AUDIO_DEVICE_IN_BACK_MIC                        
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
            - channel masks:0x000c, 0x0010, 0x0030
    Device 11:
    - tag name: Wired Headset Mic
    - type: AUDIO_DEVICE_IN_WIRED_HEADSET                   
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
            - channel masks:0x000c, 0x0010, 0x0030
    Device 12:
    - tag name: BT SCO Headset Mic
    - type: AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET           
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:8000, 16000
            - channel masks:0x0010
    Device 13:
    - tag name: Telephony Rx
    - type: AUDIO_DEVICE_IN_TELEPHONY_RX                    
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:8000, 16000
            - channel masks:0x0010

  Audio Routes (8):
  - Route 1:
    - Type: Mix
    - Sink: Earpiece
    - Sources: 
        primary output 
        deep_buffer 
        BT SCO Headset Mic 

  - Route 2:
    - Type: Mix
    - Sink: Speaker
    - Sources: 
        primary output 
        deep_buffer 
        compressed_offload 
        BT SCO Headset Mic 
        Telephony Rx 

  - Route 3:
    - Type: Mix
    - Sink: Wired Headset
    - Sources: 
        primary output 
        deep_buffer 
        compressed_offload 
        BT SCO Headset Mic 
        Telephony Rx 

  - Route 4:
    - Type: Mix
    - Sink: Wired Headphones
    - Sources: 
        primary output 
        deep_buffer 
        compressed_offload 
        BT SCO Headset Mic 
        Telephony Rx 

  - Route 5:
    - Type: Mix
    - Sink: Telephony Tx
    - Sources: 
        voice_tx 

  - Route 6:
    - Type: Mix
    - Sink: primary input
    - Sources: 
        Built-In Mic 
        Built-In Back Mic 
        Wired Headset Mic 
        BT SCO Headset Mic 

  - Route 7:
    - Type: Mix
    - Sink: Telephony Tx
    - Sources: 
        Built-In Mic 
        Built-In Back Mic 
        Wired Headset Mic 
        BT SCO Headset Mic 

  - Route 8:
    - Type: Mix
    - Sink: voice_rx
    - Sources: 
        Telephony Rx 

- HW Module 2:
  - name: hdmi
  - handle: 0
  - version: 2.0
  - outputs:
    output 0:
    - name: hdmi output
    - Profiles:
        Profile 0:[dynamic channels]
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:48000
    - flags: 0x0000
    - Supported devices:
      Device 1:
      - tag name: HDMI Out
      - type: AUDIO_DEVICE_OUT_AUX_DIGITAL                    
  - Declared devices:
    Device 1:
    - tag name: HDMI Out
    - type: AUDIO_DEVICE_OUT_AUX_DIGITAL                    
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:48000
            - channel masks:0x0003

  Audio Routes (1):
  - Route 1:
    - Type: Mix
    - Sink: HDMI Out
    - Sources: 
        hdmi output 

- HW Module 3:
  - name: a2dp
  - handle: 18
  - version: 2.3
  - outputs:
    output 0:
    - name: a2dp output
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:44100
            - channel masks:0x0003
    - flags: 0x0000
    - Supported devices:
      Device 1:
      - tag name: BT A2DP Out
      - type: AUDIO_DEVICE_OUT_BLUETOOTH_A2DP                 
      Device 2:
      - tag name: BT A2DP Headphones
      - type: AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES      
      Device 3:
      - tag name: BT A2DP Speaker
      - type: AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER         
  - inputs:
    input 0:
    - name: a2dp input
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:44100, 48000
            - channel masks:0x000c, 0x0010
    - flags: 0x0000
    - Supported devices:
      Device 1:
      - tag name: BT A2DP In
      - type: AUDIO_DEVICE_IN_BLUETOOTH_A2DP                  
  - Declared devices:
    Device 1:
    - tag name: BT A2DP Out
    - type: AUDIO_DEVICE_OUT_BLUETOOTH_A2DP                 
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:44100
            - channel masks:0x0003
    Device 2:
    - tag name: BT A2DP Headphones
    - type: AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES      
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:44100
            - channel masks:0x0003
    Device 3:
    - tag name: BT A2DP Speaker
    - type: AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER         
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:44100
            - channel masks:0x0003
    Device 4:
    - tag name: BT A2DP In
    - type: AUDIO_DEVICE_IN_BLUETOOTH_A2DP                  
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:44100, 48000
            - channel masks:0x000c, 0x0010

  Audio Routes (4):
  - Route 1:
    - Type: Mix
    - Sink: BT A2DP Out
    - Sources: 
        a2dp output 

  - Route 2:
    - Type: Mix
    - Sink: BT A2DP Headphones
    - Sources: 
        a2dp output 

  - Route 3:
    - Type: Mix
    - Sink: BT A2DP Speaker
    - Sources: 
        a2dp output 

  - Route 4:
    - Type: Mix
    - Sink: a2dp input
    - Sources: 
        BT A2DP In 

- HW Module 4:
  - name: usb
  - handle: 26
  - version: 2.2
  - outputs:
    output 0:
    - name: usb_accessory output
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:44100
            - channel masks:0x0003
    - flags: 0x0000
    - Supported devices:
      Device 1:
      - tag name: USB Host Out
      - type: AUDIO_DEVICE_OUT_USB_ACCESSORY                  
    output 1:
    - name: usb_device output
    - Profiles:
        Profile 0:[dynamic format][dynamic channels][dynamic rates]
    - flags: 0x0000
    - Supported devices:
      Device 1:
      - tag name: USB Device Out
      - type: AUDIO_DEVICE_OUT_USB_DEVICE                     
  - inputs:
    input 0:
    - name: usb_device input
    - Profiles:
        Profile 0:[dynamic format][dynamic channels][dynamic rates]
    - flags: 0x0000
    - Supported devices:
      Device 1:
      - tag name: USB Device In
      - type: AUDIO_DEVICE_IN_USB_DEVICE                      
  - Declared devices:
    Device 1:
    - tag name: USB Host Out
    - type: AUDIO_DEVICE_OUT_USB_ACCESSORY                  
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:44100
            - channel masks:0x0003
    Device 2:
    - tag name: USB Device Out
    - type: AUDIO_DEVICE_OUT_USB_DEVICE                     
    - Profiles:
        Profile 0:[dynamic format][dynamic channels][dynamic rates]
    Device 3:
    - tag name: USB Device In
    - type: AUDIO_DEVICE_IN_USB_DEVICE                      
    - Profiles:
        Profile 0:[dynamic format][dynamic channels][dynamic rates]

  Audio Routes (3):
  - Route 1:
    - Type: Mix
    - Sink: USB Host Out
    - Sources: 
        usb_accessory output 

  - Route 2:
    - Type: Mix
    - Sink: USB Device Out
    - Sources: 
        usb_device output 

  - Route 3:
    - Type: Mix
    - Sink: usb_device input
    - Sources: 
        USB Device In 

- HW Module 5:
  - name: r_submix
  - handle: 34
  - version: 2.1
  - outputs:
    output 0:
    - name: r_submix output
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:48000
            - channel masks:0x0003
    - flags: 0x0000
    - Supported devices:
      Device 1:
      - tag name: Remote Submix Out
      - type: AUDIO_DEVICE_OUT_REMOTE_SUBMIX                  
      - address: 0                               
  - inputs:
    input 0:
    - name: r_submix input
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:48000
            - channel masks:0x000c
    - flags: 0x0000
    - Supported devices:
      Device 1:
      - id:  6
      - tag name: Remote Submix In
      - type: AUDIO_DEVICE_IN_REMOTE_SUBMIX                   
      - address: 0                               
  - Declared devices:
    Device 1:
    - tag name: Remote Submix Out
    - type: AUDIO_DEVICE_OUT_REMOTE_SUBMIX                  
    - address: 0                               
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:48000
            - channel masks:0x0003
    Device 2:
    - id:  6
    - tag name: Remote Submix In
    - type: AUDIO_DEVICE_IN_REMOTE_SUBMIX                   
    - address: 0                               
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:48000
            - channel masks:0x000c

  Audio Routes (2):
  - Route 1:
    - Type: Mix
    - Sink: Remote Submix Out
    - Sources: 
        r_submix output 

  - Route 2:
    - Type: Mix
    - Sink: r_submix input
    - Sources: 
        Remote Submix In 


Outputs dump:
- Output 13 dump:
 Latency: 115
 Flags 00000002
 ID: 2
 Sampling rate: 48000
 Format: 00000001
 Channels: 00000003
 Devices 00000002
 Stream volume refCount muteCount
 00     -24.000     00       00
 01     -758.000     00       00
 02     -758.000     00       00
 03     -758.000     00       00
 04     -758.000     00       00
 05     -758.000     00       00
 06     -1.000     00       00
 07     -758.000     00       00
 08     -758.000     00       00
 09     0.000     00       01
 10     -758.000     00       00
 11     0.000     00       00
 12     -1.000     00       00
- Output 21 dump:
 Latency: 743
 Flags 00000008
 ID: 3
 Sampling rate: 48000
 Format: 00000001
 Channels: 00000003
 Devices 00000002
 Stream volume refCount muteCount
 00     -24.000     00       00
 01     -758.000     00       00
 02     -758.000     00       00
 03     -758.000     00       00
 04     -758.000     00       00
 05     -758.000     00       00
 06     -1.000     00       00
 07     -758.000     00       00
 08     -758.000     00       00
 09     0.000     00       01
 10     -758.000     00       00
 11     0.000     00       00
 12     -1.000     00       00

Inputs dump:

Streams dump:
 Stream  Can be muted  Index Min  Index Max  Index Cur [device : index]...
 00      true          01         05         0002 : 05, 0004 : 05, 0008 : 05, 0400 : 05, 40000000 : 04, 
 01      true          00         07         0002 : 07, 0004 : 07, 0008 : 07, 0400 : 07, 40000000 : 05, 
 02      true          00         07         0002 : 07, 0004 : 07, 0008 : 07, 0400 : 07, 40000000 : 05, 
 03      true          00         15         0002 : 15, 0004 : 15, 0008 : 15, 0400 : 15, 40000000 : 11, 
 04      true          00         07         0002 : 07, 0004 : 07, 0008 : 07, 0400 : 07, 40000000 : 06, 
 05      true          00         07         0002 : 07, 0004 : 07, 0008 : 07, 0400 : 07, 40000000 : 05, 
 06      true          00         15         0002 : 15, 0004 : 15, 0008 : 15, 0400 : 15, 40000000 : 07, 
 07      true          00         07         0002 : 07, 0004 : 07, 0008 : 07, 0400 : 07, 40000000 : 05, 
 08      true          00         15         0002 : 15, 0004 : 15, 0008 : 15, 0400 : 15, 40000000 : 11, 
 09      true          00         15         0002 : 15, 0004 : 15, 0008 : 15, 0400 : 15, 40000000 : 11, 
 10      true          00         15         0002 : 15, 0004 : 15, 0008 : 15, 0400 : 15, 40000000 : 11, 
 11      true          00         01         40000000 : 00, 
 12      true          00         01         40000000 : 00, 

Volume Curves for Use Cases (aka Stream types) dump:
 AUDIO_STREAM_VOICE_CALL (00): Curve points for device category (index, attenuation in millibel)
   DEVICE_CATEGORY_HEADSET : {(  0, -4200), ( 33, -2800), ( 66, -1400), (100,     0) }
   DEVICE_CATEGORY_SPEAKER : {(  0, -2400), ( 33, -1600), ( 66,  -800), (100,     0) }
   DEVICE_CATEGORY_EARPIECE : {(  0, -2400), ( 33, -1600), ( 66,  -800), (100,     0) }
   DEVICE_CATEGORY_EXT_MEDIA : {(  1, -5800), ( 20, -4000), ( 60, -1700), (100,     0) }

 AUDIO_STREAM_SYSTEM (01): Curve points for device category (index, attenuation in millibel)
   DEVICE_CATEGORY_HEADSET : {(  1, -3000), ( 33, -2600), ( 66, -2200), (100, -1800) }
   DEVICE_CATEGORY_SPEAKER : {(  1, -2400), ( 33, -1800), ( 66, -1200), (100,  -600) }
   DEVICE_CATEGORY_EARPIECE : {(  1, -2400), ( 33, -1800), ( 66, -1200), (100,  -600) }
   DEVICE_CATEGORY_EXT_MEDIA : {(  1, -5800), ( 20, -4000), ( 60, -2100), (100, -1000) }

 AUDIO_STREAM_RING (02): Curve points for device category (index, attenuation in millibel)
   DEVICE_CATEGORY_HEADSET : {(  1, -4950), ( 33, -3350), ( 66, -1700), (100,     0) }
   DEVICE_CATEGORY_SPEAKER : {(  1, -2970), ( 33, -2010), ( 66, -1020), (100,     0) }
   DEVICE_CATEGORY_EARPIECE : {(  1, -4950), ( 33, -3350), ( 66, -1700), (100,     0) }
   DEVICE_CATEGORY_EXT_MEDIA : {(  1, -5800), ( 20, -4000), ( 60, -2100), (100, -1000) }

 AUDIO_STREAM_MUSIC (03): Curve points for device category (index, attenuation in millibel)
   DEVICE_CATEGORY_HEADSET : {(  1, -5800), ( 20, -4000), ( 60, -1700), (100,     0) }
   DEVICE_CATEGORY_SPEAKER : {(  1, -5800), ( 20, -4000), ( 60, -1700), (100,     0) }
   DEVICE_CATEGORY_EARPIECE : {(  1, -5800), ( 20, -4000), ( 60, -1700), (100,     0) }
   DEVICE_CATEGORY_EXT_MEDIA : {(  1, -5800), ( 20, -4000), ( 60, -1700), (100,     0) }

 AUDIO_STREAM_ALARM (04): Curve points for device category (index, attenuation in millibel)
   DEVICE_CATEGORY_HEADSET : {(  1, -4950), ( 33, -3350), ( 66, -1700), (100,     0) }
   DEVICE_CATEGORY_SPEAKER : {(  1, -2970), ( 33, -2010), ( 66, -1020), (100,     0) }
   DEVICE_CATEGORY_EARPIECE : {(  1, -4950), ( 33, -3350), ( 66, -1700), (100,     0) }
   DEVICE_CATEGORY_EXT_MEDIA : {(  1, -5800), ( 20, -4000), ( 60, -2100), (100, -1000) }

 AUDIO_STREAM_NOTIFICATION (05): Curve points for device category (index, attenuation in millibel)
   DEVICE_CATEGORY_HEADSET : {(  1, -4950), ( 33, -3350), ( 66, -1700), (100,     0) }
   DEVICE_CATEGORY_SPEAKER : {(  1, -2970), ( 33, -2010), ( 66, -1020), (100,     0) }
   DEVICE_CATEGORY_EARPIECE : {(  1, -4950), ( 33, -3350), ( 66, -1700), (100,     0) }
   DEVICE_CATEGORY_EXT_MEDIA : {(  1, -5800), ( 20, -4000), ( 60, -2100), (100, -1000) }

 AUDIO_STREAM_BLUETOOTH_SCO (06): Curve points for device category (index, attenuation in millibel)
   DEVICE_CATEGORY_HEADSET : {(  0, -4200), ( 33, -2800), ( 66, -1400), (100,     0) }
   DEVICE_CATEGORY_SPEAKER : {(  0, -2400), ( 33, -1600), ( 66,  -800), (100,     0) }
   DEVICE_CATEGORY_EARPIECE : {(  0, -4200), ( 33, -2800), ( 66, -1400), (100,     0) }
   DEVICE_CATEGORY_EXT_MEDIA : {(  1, -5800), ( 20, -4000), ( 60, -1700), (100,     0) }

 AUDIO_STREAM_ENFORCED_AUDIBLE (07): Curve points for device category (index, attenuation in millibel)
   DEVICE_CATEGORY_HEADSET : {(  1, -3000), ( 33, -2600), ( 66, -2200), (100, -1800) }
   DEVICE_CATEGORY_SPEAKER : {(  1, -2400), ( 33, -1800), ( 66, -1200), (100,  -600) }
   DEVICE_CATEGORY_EARPIECE : {(  1, -2400), ( 33, -1800), ( 66, -1200), (100,  -600) }
   DEVICE_CATEGORY_EXT_MEDIA : {(  1, -5800), ( 20, -4000), ( 60, -2100), (100, -1000) }

 AUDIO_STREAM_DTMF (08): Curve points for device category (index, attenuation in millibel)
   DEVICE_CATEGORY_HEADSET : {(  1, -3000), ( 33, -2600), ( 66, -2200), (100, -1800) }
   DEVICE_CATEGORY_SPEAKER : {(  1, -2400), ( 33, -1800), ( 66, -1200), (100,  -600) }
   DEVICE_CATEGORY_EARPIECE : {(  1, -2400), ( 33, -1800), ( 66, -1200), (100,  -600) }
   DEVICE_CATEGORY_EXT_MEDIA : {(  1, -5800), ( 20, -4000), ( 60, -2100), (100, -1000) }

 AUDIO_STREAM_TTS (09): Curve points for device category (index, attenuation in millibel)
   DEVICE_CATEGORY_HEADSET : {(  0, -9600), (100, -9600) }
   DEVICE_CATEGORY_SPEAKER : {(  0,     0), (100,     0) }
   DEVICE_CATEGORY_EARPIECE : {(  0, -9600), (100, -9600) }
   DEVICE_CATEGORY_EXT_MEDIA : {(  0, -9600), (100, -9600) }

 AUDIO_STREAM_ACCESSIBILITY (10): Curve points for device category (index, attenuation in millibel)
   DEVICE_CATEGORY_HEADSET : {(  1, -5800), ( 20, -4000), ( 60, -1700), (100,     0) }
   DEVICE_CATEGORY_SPEAKER : {(  1, -5800), ( 20, -4000), ( 60, -1700), (100,     0) }
   DEVICE_CATEGORY_EARPIECE : {(  1, -5800), ( 20, -4000), ( 60, -1700), (100,     0) }
   DEVICE_CATEGORY_EXT_MEDIA : {(  1, -5800), ( 20, -4000), ( 60, -1700), (100,     0) }

 AUDIO_STREAM_REROUTING (11): Curve points for device category (index, attenuation in millibel)
   DEVICE_CATEGORY_HEADSET : {(  0,     0), (100,     0) }
   DEVICE_CATEGORY_SPEAKER : {(  0,     0), (100,     0) }
   DEVICE_CATEGORY_EARPIECE : {(  0,     0), (100,     0) }
   DEVICE_CATEGORY_EXT_MEDIA : {(  0,     0), (100,     0) }

 AUDIO_STREAM_PATCH (12): Curve points for device category (index, attenuation in millibel)
   DEVICE_CATEGORY_HEADSET : {(  0,     0), (100,     0) }
   DEVICE_CATEGORY_SPEAKER : {(  0,     0), (100,     0) }
   DEVICE_CATEGORY_EARPIECE : {(  0,     0), (100,     0) }
   DEVICE_CATEGORY_EXT_MEDIA : {(  0,     0), (100,     0) }


Total Effects CPU: 0.000000 MIPS, Total Effects memory: 0 KB, Max memory used: 0 KB
Registered effects:

Audio Patches:
  Audio patch 1:
  - handle:  1
  - audio flinger handle: 12
  - owner uid: 1041
  - 1 sources:
    - Mix ID 2 I/O handle 13
  - 1 sinks:
    - Device ID 1 AUDIO_DEVICE_OUT_SPEAKER
  Audio patch 2:
  - handle:  2
  - audio flinger handle: 20
  - owner uid: 1041
  - 1 sources:
    - Mix ID 3 I/O handle 21
  - 1 sinks:
    - Device ID 1 AUDIO_DEVICE_OUT_SPEAKER

2.3.1> 如何通过 xml 配置文件对应 hw_hal 驱动?

mpClientInterface 是入口参数传递过来,此 loadHwModule() 是虚函数,在 AudioPolicyClientImpl.cpp 中被实现;

/* implementation of the client interface from the policy manager */
audio_module_handle_t AudioPolicyService::AudioPolicyClient::loadHwModule(const char *name) //> name = primary 在配置文件中
{
    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();    //> @ framework/av/media/libmeida/AudioSystem.cpp 中
    if (af == 0) {
        ALOGW("%s: could not get AudioFlinger", __func__);
        return AUDIO_MODULE_HANDLE_NONE;
    }
    return af->loadHwModule(name);                             //> 通过 AudioFlinger 服务的 loadHwModule() 方法装载 audio.primary.rk30xx.so 库
}                                                              //> 就是 rockchip 实现的 audio_tinyalsa_hal 驱动程序库文件。

@ AudioSystem::get_audio_flinger() 函数内容如下

// establish binder interface to AudioFlinger service
const sp<IAudioFlinger> AudioSystem::get_audio_flinger()
{
    sp<IAudioFlinger> af;
    sp<AudioFlingerClient> afc;
    {
        Mutex::Autolock _l(gLock);
        if (gAudioFlinger == 0) {
            sp<IServiceManager> sm = defaultServiceManager();              //> sm 对象
            sp<IBinder> binder;
            do {
                binder = sm->getService(String16("media.audio_flinger"));  //> 系统服务
                if (binder != 0)
                    break;
                ALOGW("AudioFlinger not published, waiting...");
                usleep(500000); // 0.5 s
            } while (true);
            if (gAudioFlingerClient == NULL) {
                gAudioFlingerClient = new AudioFlingerClient();          //> AudioFlingerClient 实例
            } else {
                if (gAudioErrorCallback) {
                    gAudioErrorCallback(NO_ERROR);
                }
            }
            binder->linkToDeath(gAudioFlingerClient);                   //> 绑定 client 与 gAudioFlinger 对象关系
            gAudioFlinger = interface_cast<IAudioFlinger>(binder);
            LOG_ALWAYS_FATAL_IF(gAudioFlinger == 0);
            afc = gAudioFlingerClient;
        }
        af = gAudioFlinger;
    }
    if (afc != 0) {
        af->registerClient(afc);                                      //> 注册 AudioFlingerClient 对象
    }
    return af;
}

@ hardware/rockchip/tinyalsa_hal/Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := audio.primary.$(TARGET_BOARD_HARDWARE)  //> tinyalsa_hal 的程序编译生成结果,audio.primary.rk30.so 文件
LOCAL_PROPRIETARY_MODULE := true
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_SRC_FILES := \
    audio_setting.c \
    audio_bitstream.c \
    audio_hw.c \
    alsa_route.c \
    alsa_mixer.c \
    voice_preprocess.c \
    audio_hw_hdmi.c

LOCAL_C_INCLUDES += \
    external/tinyalsa/include \
    $(call include-path-for, audio-utils) \
    $(call include-path-for, audio-route) \
    $(call include-path-for, speex)

至此为止,我们捋顺 AudioPolicyManager 是如何装载厂商编写 HAL 驱动程序。

在 AudioPolicyManager::AudioPolicyManager() 构造函数中, 解析 xml 配置文件将生成 4 个 HwModule[] 对象,分别是:
primary、a2dp、usb 和 r_submix 模块。

总结:

  1. AudioPolicyService继承了IAudioPolicyService接口,这样AudioPolicyService就可以基于Android的Binder机制,向外部提供服务;

  2. AudioPolicyService同时也继承了AudioPolicyClientInterface类,他有一个AudioPolicyInterface类的成员指针mpPolicyManager,
    实际上就是指向了AudioPolicyManager;

  3. AudioPolicyManager类继承了AudioPolicyInterface类以便向AudioPolicyService提供服务,反过来同时还有一个AudioPolicyClientInterface指针,
    该指针在构造函数中被初始化,指向了AudioPolicyService,实际上,AudioPolicyService是通过成员指针mpPolicyManager访问AudioPolicyManager,
    而AudioPolicyManager则通过AudioPolicyClientInterface(mpClientInterface)访问AudioPolicyService;

  4. AudioPolicyService有一个内部线程类AudioCommandThread,顾名思义,所有的命令(音量控制,输入、输出的切换等)最终都会在该线程中排队执行;

  5. 音频系统为音频设备定义了一个枚举:AudioSystem::audio_devices,例如:DEVICE_OUT_SPEAKER,DEVICE_OUT_WIRED_HEADPHONE,
    DEVICE_OUT_BLUETOOTH_A2DP,DEVICE_IN_BUILTIN_MIC,DEVICE_IN_VOICE_CALL等等,每一个枚举值其实对应一个32bit整数的某一个位,
    所以这些值是可以进行位或操作的,例如我希望同时打开扬声器和耳机,可以这样配置:

   newDevice = DEVICE_OUT_SPEAKER | DEVICE_OUT_WIRED_HEADPHONE;
   setOutputDevice(mHardwareOutput, newDevice);
  1. AudioPolicyManager中有两个成员变量:mAvailableOutputDevices和mAvailableInputDevices,他们记录了当前可用的输入和输出设备,
    当系统检测到耳机或者蓝牙已连接好时,会调用AudioPolicyManager的成员函数;
status_t AudioPolicyManager::setDeviceConnectionState(AudioSystem::audio_devices device,
                                                  AudioSystem::device_connection_state state,
                                                  const char *device_address)
  1. AudioSystem::stream_type 音频流的类型,一共有10种类型;AudioSystem::audio_devices 音频输入输出设备,xml 文件中可配置;
    AudioPolicyManager::routing_strategy 音频路由策略,可以有4种策略;

参考链接
https://blog.csdn.net/u012188065/article/details/84104275
https://blog.csdn.net/qq_27136111/article/details/97246184
此篇博文属于精品,音频系统认证全面、准确。
https://blog.csdn.net/droidphone/article/details/5949280

2.4> SoundTringer

@frameworks/av/services/soundtriger/SoundTriggerHwService.cpp
此模块是音频动态管理服务,本地音频设备动态调整时将阐述 uevent 事件,程序根据音频设备变化自动改变音频路由策略。

        /* 装载声卡模块
         * Load a sound model. Once loaded, recognition of this model can be started and stopped.
         * Only one active recognition per model at a time. The SoundTrigger service will handle
         * concurrent recognition requests by different users/applications on the same model.
         * The implementation returns a unique handle used by other functions (unload_sound_model(),
         * start_recognition(), etc...
         */
        virtual int loadSoundModel(struct sound_trigger_sound_model *sound_model,
                                sound_model_callback_t callback,
                                void *cookie,
                                sound_model_handle_t *handle);

        /*
         * Unload a sound model. A sound model can be unloaded to make room for a new one to overcome
         * implementation limitations.
         */
        virtual int unloadSoundModel(sound_model_handle_t handle);

        void convertTriggerPhraseToHal(
                ISoundTriggerHw::Phrase *halTriggerPhrase,
                const struct sound_trigger_phrase *triggerPhrase);
        ISoundTriggerHw::SoundModel *convertSoundModelToHal(
                const struct sound_trigger_sound_model *soundModel);

三、audio HAL 硬件抽象层接口

3.1> Android 对 Audio HAL 的框架定义

rk3288 实现的 tinyalsa 接口实例代码如下:
@ hardware/rockchip/audio/tinyalsa_hal/aduio_hw.cpp

//#define LOG_NDEBUG 0
#define LOG_TAG "AudioHardwareTiny"

#include "alsa_audio.h"
#include "audio_hw.h"
#include "audio_hw_hdmi.h"
#include <system/audio.h>
#include "codec_config/config.h"
#include "audio_bitstream.h"
#include "audio_setting.h"

#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))

//#define ALSA_DEBUG
#ifdef ALSA_IN_DEBUG
FILE *in_debug;
#endif

/**
 * @brief get_output_device_id
 *
 * @param device
 *
 * @returns
 */
int get_output_device_id(audio_devices_t device)
{
    if (device == AUDIO_DEVICE_NONE)
        return OUT_DEVICE_NONE;

    if (popcount(device) == 2) {
        if ((device == (AUDIO_DEVICE_OUT_SPEAKER |
                        AUDIO_DEVICE_OUT_WIRED_HEADSET)) ||
                (device == (AUDIO_DEVICE_OUT_SPEAKER |
                            AUDIO_DEVICE_OUT_WIRED_HEADPHONE)))
            return OUT_DEVICE_SPEAKER_AND_HEADSET;
        else
            return OUT_DEVICE_NONE;
    }

    if (popcount(device) != 1)
        return OUT_DEVICE_NONE;

    switch (device) {
    case AUDIO_DEVICE_OUT_SPEAKER:
        return OUT_DEVICE_SPEAKER;
    case AUDIO_DEVICE_OUT_WIRED_HEADSET:
        return OUT_DEVICE_HEADSET;
    case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
        return OUT_DEVICE_HEADPHONES;
    case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
    case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
    case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
        return OUT_DEVICE_BT_SCO;
    default:
        return OUT_DEVICE_NONE;
    }
}

/**
 * @brief get_input_source_id
 *
 * @param source
 *
 * @returns
 */
int get_input_source_id(audio_source_t source)
{
    switch (source) {
    case AUDIO_SOURCE_DEFAULT:
        return IN_SOURCE_NONE;
    case AUDIO_SOURCE_MIC:
        return IN_SOURCE_MIC;
    case AUDIO_SOURCE_CAMCORDER:
        return IN_SOURCE_CAMCORDER;
    case AUDIO_SOURCE_VOICE_RECOGNITION:
        return IN_SOURCE_VOICE_RECOGNITION;
    case AUDIO_SOURCE_VOICE_COMMUNICATION:
        return IN_SOURCE_VOICE_COMMUNICATION;
    default:
        return IN_SOURCE_NONE;
    }
}
...  //> 省略部分代码

static int adev_open(const hw_module_t* module, const char* name,
                     hw_device_t** device)
{
    struct audio_device *adev;
    int ret;

    ALOGD(AUDIO_HAL_VERSION);

    if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
        return -EINVAL;

    adev = calloc(1, sizeof(struct audio_device));
    if (!adev)
        return -ENOMEM;

    adev->hw_device.common.tag = HARDWARE_DEVICE_TAG;
    adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
    adev->hw_device.common.module = (struct hw_module_t *) module;
    adev->hw_device.common.close = adev_close;

    adev->hw_device.init_check = adev_init_check;
    adev->hw_device.set_voice_volume = adev_set_voice_volume;
    adev->hw_device.set_master_volume = adev_set_master_volume;
    adev->hw_device.set_mode = adev_set_mode;
    adev->hw_device.set_mic_mute = adev_set_mic_mute;
    adev->hw_device.get_mic_mute = adev_get_mic_mute;
    adev->hw_device.set_parameters = adev_set_parameters;
    adev->hw_device.get_parameters = adev_get_parameters;
    adev->hw_device.get_input_buffer_size = adev_get_input_buffer_size;
    adev->hw_device.open_output_stream = adev_open_output_stream;
    adev->hw_device.close_output_stream = adev_close_output_stream;
    adev->hw_device.open_input_stream = adev_open_input_stream;
    adev->hw_device.close_input_stream = adev_close_input_stream;
    adev->hw_device.dump = adev_dump;

    //adev->ar = audio_route_init(MIXER_CARD, NULL);
    route_init();

    adev->input_source = AUDIO_SOURCE_DEFAULT;
    /* adev->cur_route_id initial value is 0 and such that first device
     * selection is always applied by select_devices() */

    adev->hdmi_drv_fd = -1;
#ifdef AUDIO_3A
    adev->voice_api = NULL;
#endif

    *device = &adev->hw_device.common;
    for(int i =0; i < OUTPUT_TOTAL; i++){
        adev->outputs[i] = NULL;
    }

    char value[PROPERTY_VALUE_MAX];
    if (property_get("audio_hal.period_size", value, NULL) > 0) {
        pcm_config.period_size = atoi(value);
        pcm_config_in.period_size = pcm_config.period_size;
    }
    if (property_get("audio_hal.in_period_size", value, NULL) > 0)
        pcm_config_in.period_size = atoi(value);

    read_snd_card_info();
    return 0;
}

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,                     //> 声卡驱动 ID 编号
        .name = "Manta audio HW HAL",
        .author = "The Android Open Source Project",
        .methods = &hal_module_methods,
    },
};

此代码是 rockchip 实现 tinyalsa_hal 源码,此库会在 AudioPolicyManager.cpp 源码中调用并装载至 AudioFlinger 封装对象中。

3.2> Linux tinyalsa 库部分

extern/tinyalsa/README.MD
tinyalsa: a small library to interface with ALSA in the Linux kernel

此部分通过源码 mixer.c与pcm.c 产生 libtinyalsa.so 库文件,在 tinyalsa_hal 中调用此库,来管理 linux 内核中声卡。
在此查看库接口,就能够分析处库提供功能及多声卡切换相关逻辑。

The aims are:

  • Provide a basic pcm and mixer API
  • If it’s not absolutely needed, don’t add it to the API
  • Avoid supporting complex and unnecessary operations that could be
    dealt with at a higher level

参考链接:
Android音频框架笔记 - 上篇
概述:此片记录 android 源码中 看声卡提供服务接口、JNI内容,比较优秀文章。
https://www.jianshu.com/p/9481b1482367

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-02-28 15:41:20  更:2022-02-28 15:43:08 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 15:38:10-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码