目录

前言

1. AudioFlinger 服务启动

2. AudioFlinger 服务接口

3. AudioFlinger 回放录制线程

4. AT和AF交互的流程

5. AudioTrack 构造过程


前言

AudioPolicyService 与 AudioFlinger 是 Android 音频系统的两大基本服务。前者是音频系统策略的制定者,负责音频设备切换的策略抉择、音量调节策略等;后者是音频系统策略的执行者,负责音频流设备的管理及音频流数据的处理传输,所以 AudioFlinger 也被认为是 Android 音频系统的引擎。

1. AudioFlinger 服务启动

从 Android 7.0 开始,AudioFlinger 在系统启动时由 audioserver 加载(之前版本由 mediaserver 加载),详见 frameworks/av/media/audioserver/main_audioserver.cpp:

int main(int argc, char** argv)
{sp<ProcessState> proc(ProcessState::self());sp<IServiceManager>sm = defaultServiceManager();ALOGI("ServiceManager:%p",sm.get());AudioFlinger::instantiate();AudioPolicyService::instantiate();RadioService::instantiate();SoundTriggerHwService::instantiate();ProcessState::self()->startThreadPool();IPCThreadState::self()->joinThreadPool();
}

可见 audioserver 把音频相关的服务都加载了,包括 AudioFlinger、AudioPolicyService、RadioService、SoundTriggerHwService。

AudioFlinger 服务启动后,其他进程可以通过 ServiceManager 来获取其代理对象 IAudioFlinger,通过 IAudioFlinger 可以向 AudioFlinger 发出各种服务请求,从而完成自己的音频业务。

2. AudioFlinger 服务接口

[-->AudioHardwareInterface.h::AudioHardwareInterface声明]class AudioHardwareInterface
{
public:virtual ~AudioHardwareInterface() {}//用于检查硬件是否初始化成功,返回的错误码定义在include/utils/Errors.hvirtual status_t    initCheck() =0;//设置通话音量,范围从0到1.0virtual status_t   setVoiceVolume(float volume) = 0;/*设置除通话音量外的其他所有音频流类型的音量,范围从0到1.0,如果硬件不支持的话,这个功能会由软件层的混音器完成*/virtual status_t   setMasterVolume(float volume) = 0;/*设置模式,NORMAL的状态为普通模式,RINGTONE表示来电模式(这时听到的声音是来电铃声)IN_CALL表示通话模式(这时听到的声音是手机通话过程中的语音)*/virtual status_t    setMode(intmode) = 0; // 和麦克相关virtual status_t   setMicMute(bool state) = 0;virtual status_t   getMicMute(bool* state) = 0;// 设置/获取配置参数,采用key/value的组织方式virtual status_t   setParameters(const String8& keyValuePairs) = 0;virtual String8    getParameters(const String8& keys) = 0;// 根据传入的参数得到输入缓冲的大小,返回0表示其中某个参数的值Audio HAL不支持virtualsize_t    getInputBufferSize(uint32_tsampleRate, int format, int channelCount) = 0;/*下面这几个函数非常重要 *//*openOutputStream:创建音频输出流对象(相当于打开音频输出设备)AF可以往其中write数据,指针型参数将返回该音频输出流支持的类型、声道数、采样率等*/virtual AudioStreamOut* openOutputStream(uint32_tdevices,int *format=0,uint32_t*channels=0,uint32_t*sampleRate=0,status_t*status=0) = 0;// 关闭音频输出流virtual    void       closeOutputStream(AudioStreamOut* out) = 0;// 创建音频输入流对象(相当于打开音频输入设备),AF可以read数据virtual AudioStreamIn* openInputStream(uint32_tdevices,int *format,uint32_t*channels,uint32_t *sampleRate,status_t*status,AudioSystem::audio_in_acoustics acoustics) = 0;virtual    void        closeInputStream(AudioStreamIn* in) =0;//关闭音频输入流virtual status_t dumpState(int fd, const Vector<String16>&args) = 0;//静态create函数,使用设计模式中的工厂模式,具体返回的对象由厂商根据硬件的情况决定staticAudioHardwareInterface* create();......
};

根据上面的代码,可以得出以下结论:

  • AudioHardwareInterface管理音频输出设备对象(AudioStreamOut)和音频输入设备对象(AudioStreamIn)的创建。
  • 通过AudioHardwareInterface可设置音频系统的一些参数。

AudioFlinger 对外提供的主要的服务接口如下:

Interface Description
sampleRate 获取硬件设备的采样率
format 获取硬件设备的音频格式
frameCount 获取硬件设备的周期帧数
latency 获取硬件设备的传输延迟
setMasterVolume 调节主输出设备的音量
setMasterMute 静音主输出设备
setStreamVolume 调节指定类型的音频流的音量,这种调节不影响其他类型的音频流的音量
setStreamMute 静音指定类型的音频流
setVoiceVolume 调节通话音量
setMicMute 静音麦克风输入
setMode 切换音频模式:音频模式有 4 种,分别是 Normal、Ringtone、Call、Communicatoin
setParameters 设置音频参数:往下调用 HAL 层相应接口,常用于切换音频通道
getParameters 获取音频参数:往下调用 HAL 层相应接口
openOutput 打开输出流:打开输出流设备,并创建 PlaybackThread 对象
closeOutput 关闭输出流:移除并销毁 PlaybackThread 上面挂着的所有的 Track,退出 PlaybackThread,关闭输出流设备
openInput 打开输入流:打开输入流设备,并创建 RecordThread 对象
closeInput 关闭输入流:退出 RecordThread,关闭输入流设备
createTrack 新建输出流管理对象: 找到对应的 PlaybackThread,创建输出流管理对象 Track,然后创建并返回该 Track 的代理对象 TrackHandle
createRecord 新建输入流管理对象:找到 RecordThread,创建输入流管理对象 RecordTrack,然后创建并返回该 RecordTrack 的代理对象 RecordHandle

可以归纳出 AudioFlinger 响应的服务请求主要有:

  1. 获取硬件设备的配置信息
  2. 音量调节
  3. 静音操作
  4. 音频模式切换
  5. 音频参数设置
  6. 输入输出流设备管理
  7. 音频流管理

其中,openOutput() 和 createTrack() 这两个接口涉及最多。

3. AudioFlinger 回放录制线程

AndioFlinger 作为 Android 的音频系统引擎,重任之一是负责输入输出流设备的管理及音频流数据的处理传输,这是由回放线程(PlaybackThread 及其派生的子类)和录制线程(RecordThread)进行的,我们简单看看回放线程和录制线程类关系:

  • ThreadBase:PlaybackThread 和 RecordThread 的基类;
  • RecordThread:录制线程类,由 ThreadBase 派生;
  • PlaybackThread:回放线程基类,同由 ThreadBase 派生;
  • MixerThread:混音回放线程类,由 PlaybackThread 派生,负责处理标识为 AUDIO_OUTPUT_FLAG_PRIMARY、AUDIO_OUTPUT_FLAG_FAST、AUDIO_OUTPUT_FLAG_DEEP_BUFFER 的音频流,MixerThread 可以把多个音轨的数据混音后再输出;
  • DirectOutputThread:直输回放线程类,由 PlaybackThread 派生,负责处理标识为 AUDIO_OUTPUT_FLAG_DIRECT 的音频流,这种音频流数据不需要软件混音,直接输出到音频设备即可;
  • DuplicatingThread:复制回放线程类,由 MixerThread 派生,负责复制音频流数据到其他输出设备,使用场景如主声卡设备、蓝牙耳机设备、USB 声卡设备同时输出;
  • OffloadThread:硬解回放线程类,由 DirectOutputThread 派生,负责处理标识为 AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD 的音频流,这种音频流未经软件解码的(一般是 MP3、AAC 等格式的数据),需要输出到硬件解码器,由硬件解码器解码成 PCM 数据。

从 Audio HAL 中,我们通常看到如下 4 种输出流设备,分别对应着不同的播放场景:

  • primary_out:主输出流设备,用于铃声类声音输出,对应着标识为 AUDIO_OUTPUT_FLAG_PRIMARY 的音频流和一个 MixerThread 回放线程实例;
  • low_latency:低延迟输出流设备,用于按键音、游戏背景音等对时延要求高的声音输出,对应着标识为 AUDIO_OUTPUT_FLAG_FAST 的音频流和一个 MixerThread 回放线程实例;
  • deep_buffer:音乐音轨输出流设备,用于音乐等对时延要求不高的声音输出,对应着标识为 AUDIO_OUTPUT_FLAG_DEEP_BUFFER 的音频流和一个 MixerThread 回放线程实例;
  • compress_offload:硬解输出流设备,用于需要硬件解码的数据输出,对应着标识为 AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD 的音频流和一个 OffloadThread 回放线程实例。

下图简单描述 AudioTrack、PlaybackThread、输出流设备三者的对应关系:

4. AT和AF交互的流程

  • AT调用createTrack,得到一个IAudioTrack对象。
  • AT调用IAudioTrack对象的start,表示准备写数据了。
  • AT通过write写数据,这个过程和audio_track_cblk_t有着密切关系。
  • 最后AT调用IAudioTrack的stop或delete IAudioTrack结束工作。

5. AudioTrack 构造过程

当我们构造一个 AudioTrack 实例时(以 MODE_STREAM/TRANSFER_SYNC 模式为例,这也是最常用的模式了,此时 sharedBuffer 为空),系统都发生了什么事?阐述下大致流程:

1. 如果 cbf(audioCallback 回调函数)非空,那么创建 AudioTrackThread 线程处理 audioCallback 回调函数(MODE_STREAM 模式时,cbf 为空);

2. 根据 streamType(流类型)、flags(输出标识)等参数调用 AudioSystem::getOutputForAttr();经过一系列的调用,进入 AudioPolicyManager::getOutputForDevice():

  • 如果输出标识置了 AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD 或 AUDIO_OUTPUT_FLAG_DIRECT,那么最终调用 AudioFlinger::openOutput() 打开输出标识对应的输出流设备并创建相应的 PlaybackThread,保存该 PlaybackThread 对应的 audio_io_handle_t 给 AudioTrack;
  • 如果输出标识是其他类型,那么根据策略选择一个输出流设备和 PlaybackThread,并保存该 PlaybackThread 对应的 audio_io_handle_t 给 AudioTrack;别忘了在 3.4. AudioFlinger 回放录制线程 小节中提到:系统启动时,就已经打开 primary_out、low_latency、deep_buffer 这三种输出流设备,并创建对应的 PlaybackThread 了;

3. 通过 Binder 机制调用 AudioFlinger::createTrack()(注意 step2 中 AudioTrack 已经拿到一个 audio_io_handle_t 了,此时把这个 audio_io_handle_t 传入给 createTrack()):

  • 根据传入的 audio_io_handle_t 找到它对应的 PlaybackThread;
  • PlaybackThread 新建一个音频流管理对象 Track;Track 构造时会分配一块匿名共享内存用于 AudioFlinger 与 AudioTrack 的数据交换缓冲区(FIFO)及其控制块(audio_track_cblk_t),并创建一个 AudioTrackServerProxy 对象(PlaybackThread 将使用它从 FIFO 上取得可读数据的位置);
  • 最后新建一个 Track 的通讯代理 TrackHandle,并以 IAudioTrack 作为返回值给 AudioTrack(TrackHandle、BnAudioTrack、BpAudioTrack、IAudioTrack 的关系见上一个小节);

4. 通过 IAudioTrack 接口,取得 AudioFlinger 中的 FIFO 控制块(audio_track_cblk_t),由此再计算得到 FIFO 的首地址;

5. 创建一个 AudioTrackClientProxy 对象(AudioTrack 将使用它从 FIFO 上取得可用空间的位置);

AudioTrack 由此建立了和 AudioFlinger 的全部联系工作:

  • 通过 IAudioTrack 接口可以控制该音轨的状态,例如 start、stop、pause;
  • 持续写入数据到 FIFO 上,实现音频连续播放;
  • 通过 audio_io_handle_t,可以找到它对应的 PlaybackThread,从而查询该 PlaybackThread 的相关信息,如所设置的采样率、格式等等。

构造 1 个 AudioTrack 实例时,AudioFlinger 会有 1 个 PlaybackThread 实例、1 个 Track 实例、1 个 TrackHandle 实例、1 个 AudioTrackServerProxy 实例、1 块 FIFO 与之对应。

【初学音频】Android的Audio系统之AudioFlinger相关推荐

  1. 【初学音频】Android的Audio系统之AudioTrack

    目录 前言 1. AudioTrack 2. 用例介绍 2.1 过程 2.2 数据加载模式 2.3 音频流的类型 2.4 Buffer分配和Frame的概念 3. AudioTrack (Java空间 ...

  2. Android8.0 Audio系统之AudioFlinger

    继上一篇AudioTrack的分析,本篇我们来看AudioFlinger,AF主要承担音频混合输出,是Audio系统的核心,从AudioTrack来的数据最终都会在这里处理,并被写入到Audio的HA ...

  3. Android 9 Audio系统笔记:音频路由实现——从AudioTrack到audiohal

    目录 一.动态路由的初始化 1.获取路由策略 2.向AudioPolicyManager注册路由策略 二.动态路由的路由流程,以AudioTrack创建为例 创建AudioTrack的路由选择 如何定 ...

  4. [深入理解Android卷一全文-第七章]深入理解Audio系统

    由于<深入理解Android 卷一>和<深入理解Android卷二>不再出版,而知识的传播不应该因为纸质媒介的问题而中断,所以我将在CSDN博客中全文转发这两本书的全部内容. ...

  5. 1.7 深入理解Audio系统

    第7章 深入理解Audio系统 7.1 概述 Audio系统是Android平台的重要组成部分,它主要包括三方面的内容: AudioRcorder和AudioTrack:这两个类属于Audio系统对外 ...

  6. 【Android】Audio音频输出通道切换 - 蓝牙bluetooth、外放

    参考: [Android]Audio音频输出通道切换 - 蓝牙.外放 Android Audio 音频输出通道切换 为什么 iOS 或 Android 设备连接蓝牙设备后不能通过蓝牙设备接电话? xq ...

  7. 【Android】Audio音频输出通道切换 - 蓝牙、外放

    手机音频的输出有外放(Speaker).听筒(Telephone Receiver).有线耳机(WiredHeadset).蓝牙音箱(Bluetooth A2DP)等输出设备.在平时,电话免提.插拔耳 ...

  8. MT6737 Android N 平台 Audio系统学习----录音到播放录音流程分析

    本文将从主mic录音到播放流程来进行学习mtk audio系统架构.  在AudioFlinger::RecordThread::threadLoop中会调用mInput->stream-> ...

  9. Android Audio系统之RingerMode

    田海立@CSDN 2012-04-11 本文介绍Android系统中Audio里的RingerMode.从使用的角度,只要关注第一节AudioManager中对于RingerMode的接口:后面章节讲 ...

  10. Android Media (Audio) Framework 多媒体系统框架

    http://blog.csdn.net/lskshz/article/details/17264113 原址:http://blog.csdn.net/myzhzygh/article/detail ...

最新文章

  1. android打不开链接,安卓的webView的loadUrl打不开,太长的url超链接,求解
  2. BeanUtils工具类,简化数据封装
  3. java 匿名委托_委托,匿名方法,λ 表达式
  4. 设置linux中docker中的mysql开机自动启动
  5. 银监计算机类 考试题库,银监会(计算机类)笔试资料-微观经济学试题库 .doc...
  6. 《React小书》终结笔记
  7. 2020年电工(技师)证考试及电工(技师)模拟考试软件
  8. 数学建模学习笔记(一) 层次分析法
  9. Kaggle案例泰坦尼克号问题
  10. hdu 3954 Level up(成段更新)
  11. Python之NumPy(axis=0/1/2...)的透彻理解——通过np.sum(axis=?)实例进行说明
  12. Android画布放大缩小,android画板---涂鸦,缩放,旋转,贴纸实现
  13. 火焰课堂java_通过火焰图引入Java剖析
  14. word操作:如何修改字体(正确、规范、快捷)
  15. Java中的过滤器doFilter里的chain.doFilter()函数理解
  16. EMNLP2020 | 近期必读Transformer精选论文
  17. 【物联网】windows环境 配置mqtt服务器
  18. QuickBooks profitandloss report 获取Not Specified 详情
  19. Word实用操作技巧之文字编辑(转)
  20. Odoo | Odoo中常用的常量配置方法

热门文章

  1. 别在坑年轻人了,他们好骗但不傻。
  2. astar不能用了_解锁不可切除肝癌治疗的新时代——“T+A”北美上市会纪要
  3. 苹果内购IAP服务端验证-java篇
  4. 0-1背包问题和部分背包(fractional knapsack)问题分析(动态规划,贪心算法)
  5. 酸辣土豆丝的做法你知道几个?
  6. [转载]jbx 乱码问题的解决大全
  7. 使用Memberane Moniter监控HTTP SOAP requests
  8. 16年“折腾史” | 盘点联想手机成与败
  9. Day15——Huffman编码之构建Huffman树
  10. Js Switch语句