Android音频框架笔记 - 下篇

提醒一下,纯个人笔记,你完全可能看晕

六、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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容

  • 提醒一下,纯个人笔记,你完全可能看晕 一、音频数字化基础知识 见书,列出知识点如下: 声音声波,声音频率、响度, ...
    YY17阅读 31,203评论 6 48
  • 一.声音参数基本概念: 声音是连续模拟量,计算机将它离散化之后用数字表示,就有了以下几个名词术语。 样本长度(sa...
    cs1001阅读 2,699评论 0 2
  • 一.声音参数基本概念: 声音是连续模拟量,计算机将它离散化之后用数字表示,就有了以下几个名词术语。 样本长度(sa...
    cs1001阅读 5,371评论 0 3
  • Android HAL概述 Android HAL(Hardware Abstract Layer)硬件抽象层,从...
    诺远阅读 29,775评论 2 27
  • Android FFmpeg音频播放 本文介绍了使用opensl es和FFmpeg在Android平台上实现音频...
    JasonXiao阅读 4,408评论 9 26