【AudioPolicy To AudioHAL笔记(二)】AudioPolicyAudioFliger To AudioHAL

/*****************************************************************************************************************/

声明: 本博客内容均由https://blog.csdn.net/weixin_47702410原创,转载or引用请注明出处,谢谢!

创作不易,如果文章对你有帮助,麻烦点赞 收藏支持~感谢

/*****************************************************************************************************************/

在上篇文章中我们分析了new AudioPolicyManager(clientInterface, audiopolicymanager_IC_manu_name)的过程,但是却没有分析到AudioPolicyManger的一个初始化过程,本章就以AudioPolicy&AudioFliger To AudioHAL为线索进行分析:

/frameworks/av/services/audiopolicy/service/AudioPolicyService.cpp
static AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
{ALOGE("%s Mylog_AP: new AudioPolicyManager !!! !", __func__);AudioPolicyManager *apm = new AudioPolicyManager(clientInterface, audiopolicymanager_IC_manu_name);ALOGE("%s Mylog_AP: new AudioPolicyManager done !", __func__);status_t status = apm->initialize();ALOGE("%s Mylog_AP: apm->initialize() !", __func__);...
}

在上面的函数中,下面的语句就会使Framework C++ Native连接到IC_manu Audio HAL

status_t status = apm->initialize();

在上面的语句中apm其实就是AudioPolicyManager的简称,这个函数最终会调到下面的函数:

/frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
status_t AudioPolicyManager::initialize() {{
...// after parsing the config, mOutputDevicesAll and mInputDevicesAll contain all known devices;// open all output streams needed to access attached devicesonNewAudioModulesAvailableInt(nullptr /*newDevices*/);// make sure default device is reachableif (mDefaultOutputDevice == 0 || !mAvailableOutputDevices.contains(mDefaultOutputDevice)) {ALOGE_IF(mDefaultOutputDevice != 0, "Default device %s is unreachable",mDefaultOutputDevice->toString().c_str());status = NO_INIT;}
...
}

其中onNewAudioModulesAvailableInt函数就会建立Framework JAVA Native To Audio HAL的关系,函数原型如下:

xref: /frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cppvoid AudioPolicyManager::onNewAudioModulesAvailableInt(DeviceVector *newDevices)
{
...hwModule->setHandle(mpClientInterface->loadHwModule(hwModule->getName()));   // 加载音频硬件模块if (hwModule->getHandle() == AUDIO_MODULE_HANDLE_NONE) {ALOGW("could not open HW module %s", hwModule->getName());continue;}
...
}

loadHwModule的定义如下:

xref: /frameworks/av/services/audioflinger/AudioFlinger.cpp
audio_module_handle_t AudioFlinger::loadHwModule(const char *name)
{if (name == NULL) {return AUDIO_MODULE_HANDLE_NONE;}if (!settingsAllowed()) {return AUDIO_MODULE_HANDLE_NONE;}Mutex::Autolock _l(mLock);AutoMutex lock(mHardwareLock);return loadHwModule_l(name);
}

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

重点关注这个openDevice函数,其会加载HAL并并将其封装在一个DeviceHalInterface对象中。

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

关注一下,这个选择加载HAL的过程,即函数load_audio_interface,它的原型如下:

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

上面的函数中hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod)
就会获取HW Module的名字:
这个AUDIO_HARDWARE_MODULE_ID的定义就是Audio,原型如下:

/hardware/libhardware/include/hardware/
H A D    audio.h    38 #define AUDIO_HARDWARE_MODULE_ID "audio"

参数"if_name"的数值在上层中传递下来,具体在函数AudioPolicyManager::onNewAudioModulesAvailableInt中传递,如下代码片段:

 hwModule->setHandle(mpClientInterface->loadHwModule(hwModule->getName()));    加载音频硬件模块

即参数"if_name"是"hwModule"的名字。

 hwModule->getName()

这个名字通常具体在配置文件(*xml,例如Audio_policy_configuration.xml)中获取,通常有primary、A2dp、Usb、Remote Submix Audio这四种名字。见下篇文章分析。

继续分析源码:

int hw_get_module_by_class(const char *class_id, const char *inst,const struct hw_module_t **module)
{int i = 0;char prop[PATH_MAX] = {0};char path[PATH_MAX] = {0};char name[PATH_MAX] = {0};char prop_name[PATH_MAX] = {0};if (inst)snprintf(name, PATH_MAX, "%s.%s", class_id, inst);       //合成audio.primary或者audio.$moudle_nameelsestrlcpy(name, class_id, PATH_MAX);/** Here we rely on the fact that calling dlopen multiple times on* the same .so will simply increment a refcount (and not load* a new copy of the library).* We also assume that dlopen() is thread-safe.*//* First try a property specific to the class and possibly instance */snprintf(prop_name, sizeof(prop_name), "ro.hardware.%s", name);if (property_get(prop_name, prop, NULL) > 0) {if (hw_module_exists(path, sizeof(path), name, prop) == 0) {goto found;}}/* Loop through the configuration variants looking for a module */for (i=0 ; i<HAL_VARIANT_KEYS_COUNT; i++) {if (property_get(variant_keys[i], prop, NULL) == 0) {continue;}if (hw_module_exists(path, sizeof(path), name, prop) == 0) {goto found;}}/* Nothing found, try the default */if (hw_module_exists(path, sizeof(path), name, "default") == 0) {goto found;}return -ENOENT;found:/* load the module, if this fails, we're doomed, and we should not try* to load a different variant. */return load(class_id, path, module);
}

可以看到源码中还会获取property来具体确定调用那个HAL中了,获取的property是ro.hardware(没有则是:ro.product.board、ro.board.platform、ro.arch),查看板子这个property是什么:

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

板子的情况:

Android_S:/vendor/lib64/hw # ls audio*
audio.bluetooth.default.so  audio.primary.IC_manu_name.so  audio.r_submix.default.so   audio.r_submix.IC_name_1.so  audio_policy.stub.so
audio.primary.default.so    audio.primary.IC_name_1.so    audio.r_submix.IC_manu_name.so  audio.usb.default.so
Android_S:/vendor/lib64/hw #
Android_S:/vendor/lib64/hw # getprop ro.hardware
IC_name_2
Android_S:/vendor/lib64/hw # getprop ro.product.board
Android_S
Android_S:/vendor/lib64/hw # getprop ro.board.platform
IC_name_1
Android_S:/vendor/lib64/hw # getprop ro.archAndroid_S:/vendor/lib64/hw #

可见最终加载的是audio.primary.IC_name_1.so这个so文件,那么这个so文件哪里来的?在下面来的:

\vendor\IC_manu_name\proprietary\hardware\audioLOCAL_ARM_MODE := arm
LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM)
LOCAL_PROPRIETARY_MODULE := true
LOCAL_MODULE_OWNER := IC_manu_name
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_MODULE_TAGS := optional

最终产物是audio.primary.IC_name_1.so
这个就是链接到IC_manu_name HAL那边了,后续可以通过这个so访问到IC_manu_name HAL。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/664836.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Python】【完整代码】解析Excel文件内容,按每列首行元素名打印出某个字符串的统计占比(超详细)

目录 1.示例&#xff1a; 1.1 实现代码1&#xff1a;列数为常量 运行结果&#xff1a; 1.2 实现代码2&#xff1a;列数为变量 运行结果&#xff1a; 1.示例&#xff1a; 开发需求&#xff1a;读取Excel文件&#xff0c;统计第3列到第5列中每列的"False"字段占…

【新书推荐】5.1节 16位汇编语言学习环境

第五章 16位汇编学习环境 16位汇编语言的学习环境是建立在8086计算机的基础上的&#xff0c;我将借助于DosBox虚拟机来实现16位汇编语言学习环境的搭建。 5.1节 16位汇编语言学习环境 本节内容&#xff1a;16位汇编学习环境的搭建。 ■汇编语言程序设计编程调试过程&#xff1…

【React】react组件传参

【React】react组件传参 一、props&#xff1a;父组件向子组件传参1、将普通的参数作为props传递2、将jsx作为props传递&#xff08;组件插槽&#xff09; 二、自定义事件&#xff1a;子父组件向父组件传参三、context进行多级组件传参四、redux全局状态管理 一、props&#xf…

MySQL篇----第四篇

系列文章目录 文章目录 系列文章目录前言一、数据库的三范式是什么二、第一范式(1st NF - 列都是不可再分)三、第二范式(2nd NF- 每个表只描述一件事情)四、第三范式(3rd NF- 不存在对非主键列的传递依赖)五、数据库是事务前言 前些天发现了一个巨牛的人工智能学习网站,通…

C++迷宫游戏详解

个人主页&#xff1a;[PingdiGuo_guo] 收录专栏&#xff1a;[C干货专栏] 大家好呀&#xff0c;我是PingdiGuo_guo&#xff0c;今天我们来学习用C实现一个迷宫游戏。 目录 1.迷宫的具体步骤 1.1.迷宫的初始化 1.2.寻路算法 1.DFS算法 2.BFS算法 1.3.移动 2.总结 C迷宫游…

Javascript入门:第三个知识点:javascript里的数据类型、运算符

数字类型 123 //整数 123.1 //浮点数 1.123e3 //科学计数法 -10 //负数 NaN //not a number Infinity //无限大 以上的类型在javascript里都是数字类型 字符串类型 在开始之前&#xff0c;我需要先说明白两个知识点&#xff1a; console.log()是啥&#xff1f; let 与 v…

【C++初阶】C++入门(2)

&#x1f525;博客主页&#xff1a; 小羊失眠啦. &#x1f3a5;系列专栏&#xff1a;《C语言》 《数据结构》 《C》 《Linux》 《Cpolar》 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 文章目录 一、函数重载1.1 函数重载的概念1.2 函数重载的种类1.3 C支持函数重载的原理 二…

服务器常遇的响应状态码

服务器常遇的响应状态码 状态码 500 表示服务器内部错误。 这种状态码意味着服务器在尝试执行请求时遇到了意外情况。在处理这种状态码时&#xff0c;我们需要联系服务器管理员或服务提供商以获取更多信息。 处理方法&#xff1a;联系服务器管理员或服务提供商以获取更多信息…

Ubuntu中rosdep update报错的解决办法

1.问题&#xff1a; Ubuntu22.04系统下面&#xff0c;rosdep update总是报错 2.方法 2.1 方法一 a.直接访问raw.githubusercontent.com不可行&#xff0c;按一下网址查询raw.githubusercontent.com的ip地址 多个地点ping[raw.githubusercontent.com]服务器-网站测速-站长工…

计算机网络——链路层(1)

计算机网络——链路层&#xff08;1&#xff09; 小程一言专栏链接: [link](http://t.csdnimg.cn/ZUTXU)前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家&#xff0c; [跳转到网站](https://www.captainbed.…

C语言第十七弹---指针(一)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 指针 1、内存和地址 1.1、内存 2、指针变量和地址 2.1、取地址操作符&#xff08;&&#xff09; 2.2、指针变量和解引用操作符&#xff08;*&#xff09;…

Tiktok东南亚商家如何通过直播活动提高直播流量和转化率?

一、什么是直播活动? 直播活动是帮助卖家在直播中有效推广商品和店铺的促销活动。 您报名参加直播活动后&#xff0c;您的直播将以活动品牌的形式突出展示。 您可以同时参与商品活动和直播活动&#xff0c;在直播中给买家提供超值优惠。 如何参加直播活动? 二、如何准备直…

[SWPUCTF 2021 新生赛]include

他让我们传入一个flag值 我们传入即可看到代码部分 传入一个php的伪类即可 得到经过Base64加密的flag&#xff0c;解密即可

Python基础知识:Python注释及print函数、input函数

在Python中&#xff0c;注释是对相应代码的解释&#xff0c;以增加代码的可读性&#xff0c;让用户能够更好地理解相应代码的含义。注释通过在相应代码后面加上“#”号来实现。比如以下代码 data.describe()#对数据集进行描述性分析 其中data.describe()为需要被执行的代码&a…

LED点阵屏(基于51单片机)

师从江科大 LED点阵屏 LED点阵屏由若干个独立的LED组成&#xff0c;LED以矩阵的形式排列&#xff0c;以灯珠亮灭来显示文字、图片、视频等。 LED点阵屏分类 按颜色&#xff1a;单色、双色、全彩 按像素&#xff1a;8*8、16*16等&#xff08;大规模的LED点阵通常由很多个…

MySQL原理(三)锁定机制(2)表锁行锁与页锁

前面提到&#xff0c;mysql锁按照操作颗粒分类&#xff0c;一般认为有表级锁、行级锁、页面锁三种。其实还有一种特殊的全局锁。 锁场景问题全局锁全库逻辑备份加了全局锁之后&#xff0c;整个数据库都是【只读状态】&#xff0c;如果数据库里有很多数据&#xff0c;备份就会花…

BUUCTF-Real-ThinkPHP]5.0.23-Rce

漏洞介绍 这个版本容易存在我们都喜欢的rce漏洞&#xff01; 网站为了提高访问效率往往会将用户访问过的页面存入缓存来减少开销。而Thinkphp 在使用缓存的时候是将数据序列化&#xff0c;然后存进一个 php 文件中&#xff0c;这使得命令执行等行为成为可能&#xff01; ThinkP…

MySQL 数据库表的增删改查(基础版)

目录 1 前言(CRUD)2 新增(Create)2.1 全列插入2.2 指定列插入2.3 关于日期和时间的插入 3 查询(Retrieve)3.1 全列查询3.2 指定列查询3.3 查询字段为表达式3.4 取别名3.5 去重3.6 排序3.7 条件查询3.8 分页查询 4 更新(Update)5 删除(Delete) 1 前言(CRUD) CRUD &#xff1a; …

Springboot 自定义参数配置化,密钥,密码,文件保存路径

application.properties 和 application.yml 都是一样的配置方法&#xff0c;只是格式不一样 定义配置文件 server.port8080 image.save.pathE:\ #自定义文件保存路径读取配置文件 Value("${image.save.path}")private String filePath;//E:\优化配置文件 如果我参…

HashMap的扩容机制

HashMap简介 HashMap在底层数据结构上采用了数组&#xff0b;链表&#xff0b;红黑树&#xff0c;通过散列映射来存储键值对数据因为在查询上使用散列码&#xff08;通过键生成一个数字作为数组下标&#xff0c;这个数字就是hash code&#xff09;所以在查询上的访问速度比较快…