本文主要介绍AudioFlinger,AudioFlinger向下访问AudioHardware,实现输出音频数据,控制音频参数。同
时,AudioFlinger向上通过IAudioFinger接口提供服务。所以,AudioFlinger在Android的音频系统框架中起着承上
启下的作用,地位相当重要。AudioFlinger的相关代码主要在:frameworks/base/libs/audioflinger,也有部分
相关的代码在frameworks/base/media/libmedia里。
AudioFlinger的类结构
下面的图示描述了AudioFlinger类的内部结构和关系:
图一 AudioFlinger的类结构
不知道各位是否和我一样,第一次看到AudioFlinger类的定义的时候都很郁闷--这个类实在是庞大和臃肿,可是当你理清他的关系以后,你会觉得相当合理。下面我们一一展开讨论。
这是AudioFlinger向外提供服务的接口,例如openOutput,openInput,createTrack,openRecord等等,
应用程序或者其他service通过ServiceManager可以获得该接口。该接口通过继承BnAudioFlinger得到。
在AudioFlinger中,Android为每一个放音/录音设备均创建一个处理线程,负责音频数据的I/O和合成,ThreadBase是这些线程的基类,所有的播放和录音线程都派生自ThreadBase
应用程序每创建一个音轨(AudioTrack/AudioRecord),在AudioFlinger中都会创建一个对应的Track实例,TrackBase就是这些Track的基类,他的派生类有:
-
- PlaybackTread::Track // 用于普通播放,对应于应用层的AudioTrack
- PlaybackThread::OutputTrack // 用于多重设备输出,当蓝牙播放开启时使用
- RecordThread::RecordTrack // 用于录音,对应于应用层的AudioRecord
-
播放
默认的播放线程是MixerThread,它由AudioPolicyManager创建,在AudioPolicyManager的构造函数中,有以下代码:
-
mHardwareOutput=mpClientInterface->openOutput(&outputDesc->mDevice,
-
&outputDesc->mSamplingRate,
-
&outputDesc->mFormat,
-
&outputDesc->mChannels,
-
&outputDesc->mLatency,
-
outputDesc->mFlags);
最终会进入AudioFlinger的openOut函数:
-
......
-
thread=new
MixerThread(
this
,output,++mNextThreadId);
-
......
-
mPlaybackThreads.add(mNextThreadId,thread);
-
......
-
return
mNextThreadId;
可以看到,创建好的线程会把该线程和它的Id保存在AudioFlinger的成员变量mPlaybackThreads
中,mPlaybackThreads是一个Vector,AudioFlinger创建的线程都会保存在里面,最后,openOutput返回该线程的
Id,该Id也就是所谓的audio_io_handle_t,AudioFlinger的调用者这能看到这个audio_io_handle_t,当需
要访问时传入该audio_io_handle_t,AudioFlinger会通过mPlaybackThreads,得到该线程的指针。
要播放声音,应用程序首先要通过IAudioFlinger接口,调用createTrack(),关于createTrack的流程,可以参看我的另一篇文章:
http://blog.csdn.net/DroidPhone/archive/2010/10/14/5941344.aspx
createTrack会调用PlaybackThread类的createTrack_l函数:
-
track=thread->createTrack_l(client,streamType,sampleRate,format,
-
channelCount,frameCount,sharedBuffer,&lStatus);
再跟入createTrack_l函数中,可以看到创建了PlaybackThread::Track类,然后加入播放线程的track列表mTracks中。
-
track=thread->createTrack_l(client,streamType,sampleRate,format,
-
channelCount,frameCount,sharedBuffer,&lStatus);
-
......
-
mTracks.add(track);
在createTrack的最后,创建了TrackHandle类并返回,TrackHandle继承了IAudioTrack接口,以后,createTrack的调用者可以通过IAudioTrack接口与AudioFlinger中对应的Track实例交互。
-
trackHandle=
new
TrackHandle(track);
-
......
-
return
trackHandle;
最后,在系统运行时,AudioFlinger中的线程和Track的结构大致如下图所示:它会拥有多个工作线程,每个线程拥有多个Track。
图二 AudioFlinger的线程结构
播放线程实际上是MixerThread的一个实例,MixerThread的threadLoop()中,会把该线程中的各个Track进行混
合,必要时还要进行ReSample(重采样)的动作,转换为统一的采样率(44.1K),然后通过音频系统的AudioHardware层输出音频数
据。
录音的流程和放音差不多,只不过数据流动的方向相反,录音线程变成RecordThread,Track变成了RecordTrack,openRecord返回RecordHandle,详细的暂且不表。
AudioFlinger中有一个特殊的线程类:DuplicatingThread,从图一可以知道,它是MixerThread的子类。当系统中有两
个设备要同时输出时,DuplicatingThread将被创建,通过IAudioFlinger的openDuplicateOutput方法创建
DuplicatingThread。
-
int
AudioFlinger::openDuplicateOutput(
int
output1,
int
output2)
-
{
-
Mutex::Autolock_l(mLock);
-
MixerThread*thread1=checkMixerThread_l(output1);
-
MixerThread*thread2=checkMixerThread_l(output2);
-
......
-
DuplicatingThread*thread=new
DuplicatingThread(
this
,thread1,++mNextThreadId);
-
thread->addOutputTrack(thread2);
-
mPlaybackThreads.add(mNextThreadId,thread);
-
return
mNextThreadId;
-
}
创建DuplicatingThread时,传入2个需要同时输出的目标线程Id,openDuplicateOutput先从
mPlaybackThreads中根据Id取得相应输出线程的实例,然后为每个线程创建一个虚拟的AudioTrack----
OutputTrack,然后把这个虚拟的AudioTrack加入到目标线程的mTracks列表中,DuplicatingThread在它的
threadLoop()中,把Mixer好的数据同时写入两个虚拟的OutputTrack中,因为这两个OutputTrack已经加入到目标线程的
mTracks列表,所以,两个目标线程会同时输出DuplicatingThread的声音。
实际上,创建DuplicatingThread的工作是有AudioPolicyService中的AudioPolicyManager里发起的。主要是当蓝牙耳机和本机输出都开启时,AudioPolicyManager会做出以下动作:
- 首先打开(或创建)蓝牙输出线程A2dpOutput
- 以HardwareOutput和A2dpOutput作为参数,调用openDuplicateOutput,创建DuplicatingThread
- 把属于STRATEGY_MEDIA类型的Track移到A2dpOutput中
- 把属于STRATEGY_DTMF类型的Track移到A2dpOutput中
- 把属于STRATEGY_SONIFICATION类型的Track移到DuplicateOutput中
结果是,音乐和DTMF只会在蓝牙耳机中输出,而按键音和铃声等提示音会同时在本机和蓝牙耳机中输出。
分享到:
相关推荐
Android 12 AudioFlinger 分析(RK3588)
AudioPolicy&AudioFlinger初始化总体框架初始化步骤简介初始化步骤详细流程分析1、loadConfig()2、initialize()2.1、初始音频路由引擎2.2、加载so 并且打开设备节点2.3、打开输出流 总体框架 AudioFlinger和Audio...
AudioFlinger.svg UML顺序图
android audioflinger.pdf
android音频子系统之AudioFlinger深入分析
不错的介绍AudioFlinger Jelly Bean的资料
NULL博文链接:https://innost.iteye.com/blog/875435
上一篇介绍了AudioFlinger的初始化,接下来对音频路由进行介绍。注意,本文主要介绍动态路由,即汽车音频路由的常规方式。针对Android原生路由策略不做深入分析。 什么是音频路由?如何实现音频路由?如何定制音频...
最全策略加载,一片文档让你熟悉整个安卓audio framework
本文档介绍音频上层框架相关的基础知识。 IAudioFlinger.cpp是AudioFlinger.cpp给上层提供的接口,降低了耦合性,同样对于AudioPolicyService也是如此。即使AudioFlinger.cpp里面的内容发生变化,只要与...
基于ALSA的Andorid音频系统拥有一个标准和健全的架构,自上而下由Audio应用程序、Audio Java框架层、Audio本地框架层、AudioFlinger、Audio硬件抽象层、alsa-lib和底层Audio驱动几个部分组成。本文分析音频系统架构...
Audio 系统在 Android 中负责音频方面的数据流传输和控制功能,也负责音频设备的管理。这个部分作为 Android 的 Audio 系统的输入/输出层次,一般负责播放 PCM 声音输出和从外部获取 PCM 声音,以及管理声音设备和设置...
android体系结构 媒体层结构 Android-MediaPlayer上层应用程序使用JAVA语言编写,实现逻辑处理;JAVA程序通过调用底层媒体库来实现具体的音视频文件和网络视频播放...通过调用AudioFlinger的接口来实现音频数据的回放;
而 MediaRecorder 是基于 AudioRecorder 的 API(最终还是会创建AudioRecord用来与AudioFlinger进行交互) ,它可以直接将采集到的音频数据转化为执行的编码格式,并保存。 直播技术采用的就是 AudioRecorder 采集音频...
这个文档是我整理别人博客的,写的非常的不错,通俗易懂,相对来说还是比较全面,讲了linux下的声卡,Android音频 , AudioPolicyService, AudioFlinger, AudioTrack这些都有详细的讲解,然后我也做了书签,方便...
AudioRecord(录音)以及(AudioSystem)主要音频参数设定。通过 Android Binder 机 AudioFlinger 层相同步,之后调用到 AudioHardware ,其中提供的接口主要 AudioStreamOut以及AudioStreamin。最终将进入Linux内核...
AudioPolicyService和AudioFLinger、AudioPolicyManager、AudioPolicyClient之间的调用关系
介绍了android的音频框架和操作流程。
使用Android端AudioTrack以及OpenSL ES结合ffmpeg播放mp3文件
事实上,两种本质上是没啥区别的,MediaPlayer在播放音频时,在framework层还是会创建AudioTrack,把解码后的PCM数流传递给AudioTrack,最后由AudioFlinger进行混音,传递音频给硬件播放出来。利用Aud