Android audio播放策略和设备的获取

本文探讨Android设备上音频播放策略的实现,包括音频接口配置信息的加载、播放策略的获取。开机时加载音频配置信息,根据音频类型选取播放策略和设备。详细解析了audio_policy.conf文件内容和AudioPolicyService如何工作,以及AudioFlinger如何打开音频接口和创建输出流。
摘要由CSDN通过智能技术生成

在一个设备平台上可能会支持很多种输出–包括蓝牙、功放、耳机等,音频来源也分很多种–闹钟、提示音、多媒体、电话、视频等等,对于这么多音频又如何正确的让音频从对应的设备播放出来呢?这就是音频播放策略所完成的事,本节围绕这个话题来分析一下源码。
将本节内容分为两节,一是方案商对平台音频接口的配置信息的加载和解析过程,组织成怎样的数据结构,这是音频播放策略的重要依据 , 二就是看一下如何根据播放的音频类型来选取对应的播放策略、选择合适的设备和输出接口。

1、音频接口配置信息的加载

开机过程中在拉起audio service时候,会去加载音频配置信息,然后读取内容,打开相应的输出通道,创建输出线程(playbackthread),支持的设备决定了音频播放策略。
首先,\frameworks\av\media\mediaserver\main_mediaserver.cpp会创建

AudioPolicyService::instantiate();

导致audiopolicyservice的构造函数中创建audio policy
\frameworks\av\services\audioflinger\AudioPolicyService.cpp

rc = hw_get_module(AUDIO_POLICY_HARDWARE_MODULE_ID, &module);//加载audio_policy.default.so,获取module信息(由audio_policy_hal.cpp编译而来)
rc = audio_policy_dev_open(module, &mpAudioPolicyDev); //调用加载的legacy_ap_module模块中中open函数,并获取struct audio_policy_device 结构体初始化信息
rc = mpAudioPolicyDev->create_audio_policy(mpAudioPolicyDev, &aps_ops, this,
                                               &mpAudioPolicy);//create_audio_policy所对应的函数是create_legacy_ap

这里顺便说一下hw_get_module,接口实现在hardware\libhardware\hardware.c:

int hw_get_module(const char *id, const struct hw_module_t **module)
{
   
    return hw_get_module_by_class(id, NULL, module); //通过hardware id获取 对应module信息
}

int hw_get_module_by_class(const char *class_id, const char *inst, //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);
    /*
     * 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.
     */
    /* Loop through the configuration variants looking for a module */
    for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) {
   
        if (i < HAL_VARIANT_KEYS_COUNT) {
    //在初始化的variant_keys中查找想要的hardware
            if (property_get(variant_keys[i], prop, NULL) == 0) {
   
                continue;
            }
            snprintf(path, sizeof(path), "%s/%s.%s.so", //优先在path2中查找
                     HAL_LIBRARY_PATH2, name, prop); //path2 /vendor/lib/hw
            if (access(path, R_OK) == 0) break; //
            snprintf(path, sizeof(path), "%s/%s.%s.so",
                     HAL_LIBRARY_PATH1, name, prop);//path1 /system/lib/hw
            if (access(path, R_OK) == 0) break;
        } else {
   
            snprintf(path, sizeof(path), "%s/%s.default.so",//没有在variant_keys找到库的部分名字内容就使用默认的,default
                     HAL_LIBRARY_PATH2, name);
            if (access(path, R_OK) == 0) break;
			...
        }
    }
    if (i < HAL_VARIANT_KEYS_COUNT+1) {
   
        /* load the module, if this fails, we're doomed, and we should not try
         * to load a different variant. */
        status = load(class_id, path, module); //找到对应的so时,使用load加载,获取信息
    }
    return status;
}
/**
 * Load the file defined by the variant and if successful
 * return the dlopen handle and the hmi.
 * @return 0 = success, !0 = failure.
 */
static int load(const char *id,
        const char *path,
        const struct hw_module_t **pHmi)
{
   
    int status;
    void *handle;
    struct hw_module_t *hmi;

    /*
     * 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
     */
    handle = dlopen(path, RTLD_NOW); //handle,打开动态库的句柄
  	...
    /* Get the address of the struct hal_module_info. */
    const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
    hmi = (struct hw_module_t *)dlsym(handle, sym); //获取 hardware module info的首地址,我们需要的最终结果,
    //如以下形式,以audio为例
    /*
	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},
	        },
	    },
	};
	/* 
	...
    /* Check that the id matches */
    if (strcmp(id, hmi->id) != 0) {
   
    ...
    hmi->dso = handle;
	...
    *pHmi = hmi;
    return status;
}

从上面的代码分析可知,HAL层有关硬件的初始化和信息描述,会被编译成对应的xxx.xxx.so放在系统的指定目录下,用于JNI层来获取这些信息。
继续看create_legacy_ap是HAL层文件\hardware\libhardware_legacy\audio\audio_policy_hal.cpp中定义的接口,大概内容如下:

struct legacy_audio_policy *lap;
...
lap->policy.set_device_connection_state = ap_set_device_connection_state;//初始化audio_policy结构体,音频策略
lap->policy.get_device_connection_state = ap_get_device_connection_state;
...
lap->policy.get_strategy_for_stream = ap_get_strategy_for_stream; //为不同音频stream获取策略
lap->policy.get_devices_for_stream = ap_get_devices_for_stream;//为不同音频stream获取devices
...
lap->policy.dump = ap_dump;
lap->policy.is_offload_supported = ap_is_offload_supported;
lap->service = service;
lap->aps_ops = aps_ops;
lap->service_client =
    new AudioPolicyCompatClient(aps_ops, service); //创建对象
if (!lap->service_client) {
   
    ret = -ENOMEM;
    goto err_new_compat_client;
}
lap-
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值