打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Android音频框架笔记
YY17
0.5912017.04.01 18:01:36字数 1,275阅读 4,873
提醒一下,纯个人笔记,你完全可能看晕
六、HAL层
6-1、Audio HAL层,其实包括了audio.xxx.so 和 audiopolicy.so等。从前述的总框架图,也有写,代码库路径也有写。
具体运行时so对象图,对于audio.xxx.so部分,参考“Android系统Audio框架介绍”最后一张图。如下:
Paste_Image.png
6-2、对audio.primary.so库,对于Audio HAL框架的实现分析
Audio HAL层架构定义: hardware\libhardware\include\hardware\audio.h
厂商实现:以Anroid4.1.1版为例,audio.primary.grouper.so库为例, 代码位置device\asus\grouper\audio\audio_hw.c
//Audio HAL层架构中audio_module 的定义,继承hw_module_t,其实没有任何扩展
struct audio_module { struct hw_module_t common;};
// 厂商audio_module 的实现,关键是open函数赋值,其作用是打开该设备,返回audio_hw_device 结构体对象,但在这份实现中,返回是audio_device对象,即audio_hw_device子类
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, .name = "Grouper audio HW HAL", .author = "The Android Open Source Project", .methods = &hal_module_methods, },};static struct hw_module_methods_t hal_module_methods = { .open = adev_open, //open函数主要是填充audio_hw_device 结构体对象,返回之};
//Audio HAL层架构中audio_hw_device的定义,audio_hw_device 继承自hw_device_t。
//可以看到跟上层调用者的接口很一致,其实,它的作用就是为上层提供统一、稳定的接口,从而让底层的频繁变化,可以不影响上层的架构。
struct audio_hw_device { struct hw_device_t common; uint32_t (*get_supported_devices)(const struct audio_hw_device *dev); int (*init_check)(const struct audio_hw_device *dev); int (*set_voice_volume)(struct audio_hw_device *dev, float volume); int (*set_master_volume)(struct audio_hw_device *dev, float volume); int (*get_master_volume)(struct audio_hw_device *dev, float *volume); int (*set_mode)(struct audio_hw_device *dev, audio_mode_t mode); int (*set_mic_mute)(struct audio_hw_device *dev, bool state); int (*get_mic_mute)(const struct audio_hw_device *dev, bool *state); int (*set_parameters)(struct audio_hw_device *dev, const char *kv_pairs); char * (*get_parameters)(const struct audio_hw_device *dev, const char *keys); size_t (*get_input_buffer_size)(const struct audio_hw_device *dev, const struct audio_config *config); int (*open_output_stream)(struct audio_hw_device *dev, audio_io_handle_t handle, audio_devices_t devices, audio_output_flags_t flags, struct audio_config *config, struct audio_stream_out **stream_out); void (*close_output_stream)(struct audio_hw_device *dev, struct audio_stream_out* stream_out); int (*open_input_stream)(struct audio_hw_device *dev, audio_io_handle_t handle, audio_devices_t devices, struct audio_config *config, struct audio_stream_in **stream_in); void (*close_input_stream)(struct audio_hw_device *dev, struct audio_stream_in *stream_in); int (*dump)(const struct audio_hw_device *dev, int fd);};typedef struct audio_hw_device audio_hw_device_t;
//厂商中audio_hw_device 的实现,audio_device 继承自audio_hw_device。关键在于stream_out / stream_in 两个类
struct audio_device { struct audio_hw_device hw_device; pthread_mutex_t lock; /* see note below on mutex acquisition order */ unsigned int devices; bool standby; bool mic_mute; struct audio_route *ar; int orientation; bool screen_off; struct stream_out *active_out; struct stream_in *active_in;};
// 以下作简明阐述
//Audio HAL层架构中,audio_stream_out / audio_stream_in 代表输出/输入流
//这里是实现类,关键是struct pcm *pcm; 它已经就是alsa库里定义的结构体了。它的初始化也正是调用alsa库的open_pcm()函数而来。
// out->pcm = pcm_open(PCM_CARD, device, PCM_OUT | PCM_NORESTART, out->pcm_config);
//所以,意思就是,从这里开始,往下就是调用alsalib库了。
struct stream_out { struct audio_stream_out stream; struct pcm *pcm; ...};struct stream_in { struct audio_stream_in stream; struct pcm *pcm; ...};audio设备打开流程
audio_policy.conf加载、解析之后的流程,见前面
audio_policy.conf加载、解析之后的流程如下:
厂商的Audio HAL模块加载流程:
AudioFlinger::loadHwModule(const char *name)
-> load_audio_interface()
-> hw_get_module_by_class()
//参考HAL框架加载知识,这里加载到相应.so的xxx_hw_module_t 结构体
-> audio_hw_device_open() --> xxx_hw_module_t.open() ,在参数里返回audio_hw_device_t结构体
至此,已经加载了HAL模块.so库,并打开相应设备,返回我们要的audio_hw_device_t结构体
多少个.so,见audio_policy.conf加载上半部,
audio_hw_device_t: 音频设备的抽象类。多少个audio_hw_device_t结构体? 有多少个so,就有多少个。 一一对应关系。
audio_stream_out : 音频设备的输入输出通道的抽象类。这个才是对应pcmc0d0p之类的具体通道,right?
至于这些结构体的定义与功能,见HAL相关小节。
输出通道打开流程:
输出通道打开流程(上)
如AudioRecord.cpp开始:
AudioRecord.cpp
->set()
-> AudioSystem.getInput()
-> 各种辗转
->AudioFlinger->openInput()
如AudioTrack.cpp开始:
AudioTrack.set()
-> AudioSystem::getOutput
-> 各种辗转
->AudioFlinger->openOutput()
输出通道打开流程(下)
无论上层的打开流程如何辗转反侧,最终都调用到具体执行者AudioFlinger。由此开始分析如下:
AudioFlinger如何打开输出通道呢? 具体是如何调用到alsalib库,甚至驱动的呢? 接着走。
AudioFlinger->openOutput()
-> findSuitableHwDev_l ()
//寻找输出设备,返回audio_hw_device_t
-> audio_hw_device_t-> open_output_stream(..., struct audio_stream_out **stream_out))
//HAL层,Audio架构标准接口
-> new audio_stream_out
//HAL层,厂商实现类,如device\asus\grouper\audio\audio_hw.c
-> audio_stream_out.pcm = pcm_open()
// pcm_open() 已经是调用到tinyalsa库了,也就操作到了/dev/snd/pcmcxdxx设备节点了。
//所以看到调用层级AudioFlinger -> Audio HAL -> tinyalsa -> ALSA driver -> 硬件。此即所谓软件层级。
参考
“ANDROID音频系统散记之四:4.0音频系统HAL初探”
七、 TinyAlsa库
直接看其Android.mk你就明白了:
libtinyalsa.so:
给Audio HAL层代码调用的库,即几个audio.xxx.so会调用到libtinyalsa.so里的函数。
从框架全图也可以看到。
其它:tinyalsa工具程序,可用于测试、调试
流程图
初始化, 见书
八、调试
tinyalas调试
命令: tinyplay / tinycap /tinypcminfo (用法直接看usage)
命令源码位置:/external/tinyalsa
声卡驱动信息:cat /proc/asound/cards
tinyalsa声卡设备:ls /dev/snd
九、接入第三方视频解码库
mark而已,属于视频部分。
十、参考
ALSA官方文档
http://www.alsa-project.org/~tiwai/writing-an-alsa-driver/index.html
《深入理解Android内核设计思想》-2014
[深入理解Android卷一全文-第七章] 深入理解Audio系统
http://blog.csdn.net/innost/article/details/47208109
有不少这个模块的文章,不过是2012年左右,ALSA架构时代,其中值得参考的两篇已存
http://blog.csdn.net/njuitjf/article/category/837094/1
一些没看,暂时的资料:
http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=27570663&id=4432842
14人点赞
Android开发
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
android4.3之系统SetSpeakerphoneOn实现的Audio Output Path切换
ANDROID音频系统散记之四:4.0音频系统HAL初探
安卓音频架构 · Hand Book of Speech Enhancement and Recognition
Android HAL 层原理分析
Qualcomm Audio HAL 音频通路设置
Android平台读写i2c设备开发笔记一
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服