注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

东东的博客

江南烟雨,同大家一起分享

 
 
 

日志

 
 

Android Audio System 之二:AudioFlinger  

2011-06-21 15:26:16|  分类: android相关 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

引言

    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类的内部结构和关系:
 

Android Audio System 之二: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。
 

Android Audio System 之二:AudioFlinger - 东东 - 东东的博客

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

Android Audio System 之二:AudioFlinger - 东东 - 东东的博客

 


                                                                           图三  本机播放时的Thread和Track

Android Audio System 之二:AudioFlinger - 东东 - 东东的博客

 

                                                                        图四   蓝牙播放时的Thread和Track


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

  评论这张
 
阅读(1687)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017