1 分析思路

  1. Thread如何创建?

    AudioPolicyService是策略的制定者,AudioFlinger是策略的执行者,

    所以: AudioPolicyService根据配置文件使唤AudioFlinger来创建Thread

  2. Thread对应output, output对应哪些设备节点?

  3. AudioTrack和Track的创建过程: AudioTrack对应哪一个Thread, 对应哪一个output?

  4. AudioTrack如何传输数据给Thread?

  5. AudioTrack如何播放、暂停、关闭?

2 以例子说明几个重要概念

stream type, strategy, device, output, profile, module : policy

out flag : 比如对于某个专业APP, 它只从HDMI播放声音, 这时就可以指定out flag为AUDIO_OUTPUT_FLAG_DIRECT,这会导致最终的声音无需混音即直接输出到对应的device

Android系统里使用hardware module来访问硬件, 比如声卡

声卡上有喇叭、耳机等等,称为device

为了便于管理, 把一个设备上具有相同参数的一组device称为output,

一个module能支持哪些output,一个output能支持哪些device,使用配置文件/system/etc/audio_policy.conf来描述

app要播放声音, 要指定声音类型: stream type有那么多的类型, 来来来, 先看它属于哪一类(策略): strategy

根据strategy确定要用什么设备播放: device, 喇叭、耳机还是蓝牙?

根据device确定output, 进而知道对应的playbackthread,

把声音数据传给这个thread

一个stream如何最终选择到一个device,这些stream如何互相影响(一个高优先级的声音会使得其他声音静音),等等等, 统称为policy (政策)

输出、输入设备:

https://blog.csdn.net/zzqhost/article/details/7711935

3 所涉及文件形象讲解

系统服务APP:

frameworks/av/media/mediaserver/main_mediaserver.cpp

AudioFlinger :

AudioFlinger.cpp

(frameworks/av/services/audioflinger/AudioFlinger.cpp)

Threads.cpp (frameworks/av/services/audioflinger/Threads.cpp)

Tracks.cpp (frameworks/av/services/audioflinger/Tracks.cpp)

audio_hw_hal.cpp (hardware/libhardware_legacy/audio/Audio_hw_hal.cpp)

AudioHardware.cpp (device/friendly-arm/common/libaudio/AudioHardware.cpp)

AudioPolicyService:

AudioPolicyService.cpp (frameworks/av/services/audiopolicy/AudioPolicyService.cpp)

AudioPolicyClientImpl.cpp (frameworks/av/services/audiopolicy/AudioPolicyClientImpl.cpp)

AudioPolicyInterfaceImpl.cpp(frameworks/av/services/audiopolicy/AudioPolicyInterfaceImpl.cpp)

AudioPolicyManager.cpp (device/friendly-arm/common/libaudio/AudioPolicyManager.cpp)

AudioPolicyManager.h (device/friendly-arm/common/libaudio/AudioPolicyManager.h)

AudioPolicyManagerBase.cpp (hardware/libhardware_legacy/audio/AudioPolicyManagerBase.cpp)

堪误: 上面3个文件被以下文件替代

AudioPolicyManager.cpp (frameworks/av/services/audiopolicy/AudioPolicyManager.cpp)

应用程序APP所用文件:

AudioTrack.java (frameworks/base/media/java/android/media/AudioTrack.java)

android_media_AudioTrack.cpp (frameworks/base/core/jni/android_media_AudioTrack.cpp)

AudioTrack.cpp (frameworks/av/media/libmedia/AudioTrack.cpp)

AudioSystem.cpp (frameworks/av/media/libmedia/AudioSystem.cpp)

4 AudioPolicyService启动过程分析

比如一部典型的手机,它既有听筒、耳机接口,还有蓝牙设备。假设默认情况下播放音乐是通过听筒喇叭输出的,那么当用户插入耳机时,这个策略就会改变——从耳机输出,而不再是听筒;又比如在机器插着耳机时,播放音乐不应该从喇叭输出,但是当有来电铃声时,就需要同时从喇叭和耳机输出音频。这些“音频策略”的制定,主导者就是AudioPolicyService

在AudioFlinger小节,我们反复强调它只是策略的执行者,而AudioPolicyService则是策略的制定者。这种分离方式有效地降低了整个系统的藕合性,而且为各个模块独立扩展功能提供了保障。

  1. 加载解析/vendor/etc/audio_policy.conf/system/etc/audio_policy.conf

    • 对于配置文件里的每一个module项, new HwModule(name), 放入mHwModules数组;
    • 对于module里的每一个output, new IOProfile,放入module的mOutputProfiles
    • 对于module里的每一个input, new IOProfile, 放入module的mInputProfiles
  2. 根据module的name加载厂家提供的so文件(通过AudioFlinger来加载)
  3. 打开对应的output(通过AudioFlinger来open output)

为了让大家对AudioPolicyService有个感性的认识,我们以下图来形象地表示它与AudioTrack及AudioFlinger间的关系:

5 AudioFlinger启动过程分析

  1. 注册AudioFlinger服务
  2. 被AudioPolicyService调用以打开厂家提供的so文件
    1. 加载哪个so文件? 文件名是什么? 文件名从何而来?

      名字从/system/etc/audio_policy.conf得到 : primary

      所以so文件就是 : audio.primary.XXX.so, eg. audio.primary.tiny4412.so
    2. 该so文件由什么源文件组成? 查看Android.mk
audio.primary.$(TARGET_DEVICE) : device/friendly-arm/common/libaudio/AudioHardware.cpp
libhardware_legacy
libhardware_legacy : hardware/libhardware_legacy/audio/audio_hw_hal.cpp
  1. 对硬件的封装:
AudioFlinger       : AudioHwDevice (放入mAudioHwDevs数组中)
audio_hw_hal.cpp : audio_hw_device
厂家               : AudioHardware (派生自: AudioHardwareInterface)

AudioHwDevice是对audio_hw_device的封装,audio_hw_device中函数的实现要通过AudioHardware类对象

6 AudioTrack创建过程概述

  1. 体验测试程序: frameworks/base/media/tests/audiotests/shared_mem_test.cpp

frameworks/base/media/tests/mediaframeworktest/src/com/android/mediaframeworktest/functional/audio/MediaAudioTrackTest.java

播放声音时都要创建AudioTrack对象,java的AudioTrack对象创建时会导致c++的AudioTrack对象被创建;

所以分析的核心是c++的AudioTrack类,创建AudioTrack时涉及一个重要函数: set()函数

  1. 猜测创建过程的主要工作

    1. 使用AudioTrack的属性, 根据AudioPolicy找到对应的output、playbackThread
    2. 在playbackThread中创建对应的track
    3. APP的AudioTrack 和 playbackThread的mTracks中的track之间建立共享内存
  2. 源码时序图

7 AudioTrack创建过程_Track和共享内存

回顾:

  1. APP创建AudioTrack AudioFlinger中PlaybackThread创建对应的Track

b. APP给AudioTrack提供音频数据有2种方式: 一次性提供(MODE_STATIC)、边播放边提供(MODE_STREAM)

问:

  1. 音频数据存在buffer中, 这个buffer由谁提供? APP 还是 PlaybackThread ?
  2. APP提供数据, PlaybackThread消耗数据, 如何同步?

8 音频数据的传递

  1. APP创建AudioTrack, playbackThread创建对应的Track

    它们之间通过共享内存传递音频数据
  2. APP有2种使用共享内存的方式:
    1. MODE_STATIC:

      APP创建共享内存, APP一次性填充数据
    2. MODE_STREAM:

      APP使用obtainBuffer获得空白内存, 填充数据后使用releaseBuffer释放内存
  3. playbackThread使用obtainBuffer获得含有数据的内存, 使用数据后使用releaseBuffer释放内存
  4. AudioTrack中含有mProxy, 它被用来管理共享内存, 里面含有obtainBuffer, releaseBuffer函数。Track中含有mServerProxy, 它被用来管理共享内存, 里面含有obtainBuffer, releaseBuffer函数。对于不同的MODE, 这些Proxy指向不同的对象
  5. 对于MODE_STREAM, APP和playbackThread使用环型缓冲区的方式传递数据

9 PlaybackThread处理流程

  1. prepareTracks_l :

    确定enabled track, disabled track

    对于enabled track, 设置mState.tracks[x]中的参数

  2. threadLoop_mix : 处理数据(比如重采样)、混音

    确定hook:

    逐个分析mState.tracks[x]的数据, 根据它的格式确定tracks[x].hook

    再确定总的mState.hook

    调用hook:

    调用总的mState.hook即可, 它会再去调用每一个mState.tracks[x].hook

    混音后的数据会放在mState.outputTemp临时BUFFER中

    然后转换格式后存入 thread.mMixerBuffer

  3. memcpy_by_audio_format :

    把数据从thread.mMixerBuffer或thread.mEffectBuffer复制到thread.mSinkBuffer

  4. threadLoop_write:

    把thread.mSinkBuffer写到声卡上

  5. threadLoop_exit

Android音频系统的更多相关文章

  1. Android音频系统之音频框架

    1.1 音频框架 转载请注明,From LXS, http://blog.csdn.net/uiop78uiop78/article/details/8796492 Android的音频系统在很长一段 ...

  2. Android音频系统之AudioFlinger(一)

    1.1 AudioFlinger 在上面的框架图中,我们可以看到AudioFlinger(下面简称AF)是整个音频系统的核心与难点.作为Android系统中的音频中枢,它同时也是一个系统服务,启到承上 ...

  3. Android音频系统之AudioPolicyService

    地址:http://blog.csdn.net/edmond999/article/details/18599327 1.1 AudioPolicy Service 在AudioFlinger小节,我 ...

  4. 转:ANDROID音频系统散记之四:4.0音频系统HAL初探

    昨天(2011-11-15)发布了Android4.0的源码,今天download下来,开始挺进4.0时代.简单看了一下,发现音频系统方面与2.3的有较多地方不同,下面逐一描述. 一.代码模块位置 1 ...

  5. Android音频系统之AudioFlinger(二)

    1.1.1 音频设备的管理 虽然AudioFlinger实体已经成功创建并初始化,但到目前为止它还是一块静态的内存空间,没有涉及到具体的工作. 从职能分布上来讲,AudioPolicyService是 ...

  6. Android音频系统之AudioFlinger(四)

    http://blog.csdn.net/xuesen_lin/article/details/8805096 1.1.1 AudioMixer 每一个MixerThread都有一个唯一对应的Audi ...

  7. Android音频系统之AudioFlinger(三)

    http://blog.csdn.net/xuesen_lin/article/details/8805091 1.1.1 PlaybackThread的循环主体 当一个PlaybackThread进 ...

  8. Android 音频系统得框架

    http://www.mamicode.com/info-detail-1790053.html http://blog.csdn.net/lushengchu_luis/article/detail ...

  9. Android的系统架构

    转自Android的系统架构 从上图中可以看出,Android系统架构为四层结构,从上层到下层分别是应用程序层.应用程序框架层.系统运行库层以及Linux内核层,分别介绍如下:     1)应用程序层 ...

随机推荐

  1. 深入学习主成分分析(PCA)算法原理(Python实现)

    一:引入问题 首先看一个表格,下表是某些学生的语文,数学,物理,化学成绩统计: 首先,假设这些科目成绩不相关,也就是说某一科目考多少分与其他科目没有关系,那么如何判断三个学生的优秀程度呢?首先我们一眼 ...

  2. Qt 编程中 namespace Ui { class Widget; } 解析

    class Widget 里面有个声明 Ui::Widget *ui,这个 ui 是使用 namespace Ui 里的 Widget 类声明的,该类只是简单的继承了 ui_widget.h 里的 U ...

  3. JavaScript基础知识梳理,你能回答几道题?

    在学习JavaScript的时候,总是这里学一点,那里学一点,很的很零星,很杂,没有很系统的去学习,感觉好像JavaScript的知识点都了解了,但是真正要说起来,又不知道从何说起! 最深刻的体会就是 ...

  4. 在CentOS中部署.Net Core2.1网站

    作为一个刚接触linux的新手,在安装环境的时候,折腾了不少时间,写下一篇总结帖,帮助下新人吧~ 做完后再回来看步骤,也很简单,也就以下几步: 1.安装.Net Core环境 2.安装nginx实现端 ...

  5. .NET 单元测试的利剑——模拟框架Moq(简述篇)

    .NET 单元测试的利剑--模拟框架Moq 前言 这篇文章是翻译文,因为通过自己参与的项目,越发觉得单元测试的重要性,特别是当跟业务数据打交道的时候的,Moq就如雪中送炭,所以想学习这个框架,就从这篇 ...

  6. 【Linux】nginx常用命令

    相关内容链接 Centos之安装Nginx及注意事项 [nginx]详细配置说明 nginx常用命令 [重新加载配置]sudo nginx -s reload [打开nginx配置]sudo vim ...

  7. Java岗 面试考点精讲(基础篇02期)

    1. 两个对象的hashCode相同,则equals也一定为true,对吗? 不对,答案见下面的代码: @Override public int hashCode() { return 1; } 两个 ...

  8. redux 入门

    背景: 在react中使用redux 重点:不要滥用redux,如果你的页面非常简单,没有 那么多的互动,那么就不要使用redux,反而会增加项目的复杂性. 如果你有以下情况,则可以考虑使用redux ...

  9. WORLD 合并多个WORLD中的文本

    1,把多个文档放入一个文件夹中. 2,新建一个WORLD文档. 3,点击插入----对象----文件中的文字----选中文件中的多个WORLD文档----打开.

  10. 微信wx.request

    官方 wx.request 代码,Post 没成功过,使用Get 方式成功了. wx.request({ url: 'test.php', //仅为示例,并非真实的接口地址 data: { x: '' ...