引言

AudioFlinger是Android音频系统的两大服务之一,另一个服务是AudioPolicyService,这两大服务都在系统启动时有MediaSever加载,加载的代码位于:frameworks\base\media\mediaserver\main_mediaserver.cpp。AudioPolicyService的相关内容请参考另一编文章:《Android Audio System 之三: AudioPolicyService 和 AudioPolicyManager 》

http://blog.csdn.net/DroidPhone/archive/2010/10/18/5949280.aspx

本文主要介绍AudioFlinger,AudioFlinger向下访问AudioHardware,实现输出音频数据,控制音频参数。同时,AudioFlinger向上通过IAudioFinger接口提供服务。所以,AudioFlinger在Android的音频系统框架中起着承上启下的作用,地位相当重要。AudioFlinger的相关代码主要在:frameworks\base\libs\audioflinger,也有部分相关的代码在frameworks\base\media\libmedia里。

AudioFlinger的类结构

下面的图示描述了AudioFlinger类的内部结构和关系:


图一 AudioFlinger的类结构

不知道各位是否和我一样,第一次看到AudioFlinger类的定义的时候都很郁闷--这个类实在是庞大和臃肿,可是当你理清他的关系以后,你会觉得相当合理。下面我们一一展开讨论。
?
IAudioFlinger接口

这是AudioFlinger向外提供服务的接口,例如openOutput,openInput,createTrack,openRecord等等,应用程序或者其他service通过ServiceManager可以获得该接口。该接口通过继承BnAudioFlinger得到。
?
ThreadBase

在AudioFlinger中,Android为每一个放音/录音设备均创建一个处理线程,负责音频数据的I/O和合成,ThreadBase是这些线程的基类,所有的播放和录音线程都派生自ThreadBase
?
TrackBase

应用程序每创建一个音轨(AudioTrack/AudioRecord),在AudioFlinger中都会创建一个对应的Track实例,TrackBase就是这些Track的基类,他的派生类有:
? ?PlaybackTread::Track // 用于普通播放,对应于应用层的AudioTrack
?PlaybackThread::OutputTrack // 用于多重设备输出,当蓝牙播放开启时使用
?RecordThread::RecordTrack // 用于录音,对应于应用层的AudioRecord

?
播放

默认的播放线程是MixerThread,它由AudioPolicyManager创建,在AudioPolicyManager的构造函数中,有以下代码:

view plaincopy to clipboardprint?
01.mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice,
02. &outputDesc->mSamplingRate,
03. &outputDesc->mFormat,
04. &outputDesc->mChannels,
05. &outputDesc->mLatency,
06. outputDesc->mFlags);

最终会进入AudioFlinger的openOut函数:

view plaincopy to clipboardprint?
01.......
02.thread = new MixerThread(this, output, ++mNextThreadId);
03.......
04.mPlaybackThreads.add(mNextThreadId, thread);
05.......
06.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函数:

view plaincopy to clipboardprint?
01.track = thread->createTrack_l(client, streamType, sampleRate, format,
02. channelCount, frameCount, sharedBuffer, &lStatus);

再跟入createTrack_l函数中,可以看到创建了PlaybackThread::Track类,然后加入播放线程的track列表mTracks中。

view plaincopy to clipboardprint?
01.track = thread->createTrack_l(client, streamType, sampleRate, format,
02. channelCount, frameCount, sharedBuffer, &lStatus);
03.......
04.mTracks.add(track);

在createTrack的最后,创建了TrackHandle类并返回,TrackHandle继承了IAudioTrack接口,以后,createTrack的调用者可以通过IAudioTrack接口与AudioFlinger中对应的Track实例交互。

view plaincopy to clipboardprint?
01.trackHandle = new TrackHandle(track);
02.......
03.return trackHandle;

最后,在系统运行时,AudioFlinger中的线程和Track的结构大致如下图所示:它会拥有多个工作线程,每个线程拥有多个Track。


图二 AudioFlinger的线程结构

播放线程实际上是MixerThread的一个实例,MixerThread的threadLoop()中,会把该线程中的各个Track进行混合,必要时还要进行ReSample(重采样)的动作,转换为统一的采样率(44.1K),然后通过音频系统的AudioHardware层输出音频数据。
?
录音


录音的流程和放音差不多,只不过数据流动的方向相反,录音线程变成RecordThread,Track变成了RecordTrack,openRecord返回RecordHandle,详细的暂且不表。
?
DuplicatingThread

AudioFlinger中有一个特殊的线程类:DuplicatingThread,从图一可以知道,它是MixerThread的子类。当系统中有两个设备要同时输出时,DuplicatingThread将被创建,通过IAudioFlinger的openDuplicateOutput方法创建DuplicatingThread。

view plaincopy to clipboardprint?
01.int AudioFlinger::openDuplicateOutput(int output1, int output2)
02.{
03. Mutex::Autolock _l(mLock);
04. MixerThread *thread1 = checkMixerThread_l(output1);
05. MixerThread *thread2 = checkMixerThread_l(output2);
06. ......
07. DuplicatingThread *thread = new DuplicatingThread(this, thread1, ++mNextThreadId);
08. thread->addOutputTrack(thread2);
09. mPlaybackThreads.add(mNextThreadId, thread);
10. return mNextThreadId;
11.}

创建 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只会在蓝牙耳机中输出,而按键音和铃声等提示音会同时在本机和蓝牙耳机中输出。


图三 本机播放时的Thread和Track

图四 蓝牙播放时的Thread和Track


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/DroidPhone/archive/2010/10/19/5951999.aspx

更多相关文章

  1. Android摄像头--通过Intent启动
  2. 【Android】EventBus源码解析(3.1.1)
  3. Android中对Handle机制的理解
  4. Android(安卓)录音
  5. Android(2017-2018)BAT面试题整理(Java篇,含答案)
  6. Android的线程使用来更新UI----Thread、Handler、Looper、TimerT
  7. 开始使用Android(安卓)Sutdio(三)创建一个Hello World程序
  8. Android(安卓)ServiceManager注册自定义service
  9. android message机制

随机推荐

  1. 【30篇突击 android】源码统计四
  2. SlidingMenu和ActionBarSherlock结合做出
  3. android 布局式跑马灯,非TextView
  4. Android如何获得系统版本
  5. Android(安卓)TabHost使用、动态加载内容
  6. Android异步加载图像小结 (含线程池,缓存方
  7. Android开发之消息处理机制(一)——Handler
  8. Android,一个思路实现APP版本更新
  9. android style
  10. Android(安卓)Activity界面切换添加动画