我使用的是三星的SMDKC110平台,Android代码为4.0版本。其中理解错误的请指正,谢谢!!
android系统的音频系统在不同层大概都是由三块组成,AudioSystem, AudioTrack, AudioRecorder。它们分别负责音频系统的综合管理功能、音频数据的输出和输入。
代码文件结构:代码头文件放在frameworks/base/include/media/目录中,主要有:
AudioSystem.h: media库的Audio部分对上层的总接口;
IAudioFlinger.h: 需要下层实现的总接口;
AudioTrack.h: 播放声音部分的对上接口;
IAudioTrack.h: 播放声音部分需要下层实现的接口;
AudioRecorder.h: 录制声音部分的对上接口;
IAudioRecorder.h: 录制声音部分需要下层实现的接口;
下表是Android各个层次的对应关系:
|
Audio管理环节 |
Audio输出 |
Audio输入 |
Java层 |
android.media.AudioSystem |
android.media.AudioTrack |
android.media.AudioRecorder |
本地框架层 |
AudioSystem |
AudioTrack |
AudioRecorder |
AudioFlinger |
IAudioFlinger |
IAudioTrack |
IAudioRecorder |
硬件抽象层 |
AudioHardwareInterface |
AudioStreamOut |
AudioStreamIn |
每一个音频应用对应一个AudioTrack实体或者AudioRecord实体,这个实体是由AudioFlinger分配的,应用程序操作音频播放或者录音,实际上也就是操作分配的audioTrack 或者audioRecord对象,通过audioFlinger过操作HAL层的音频模块,HAL层其实就相当于用户空间的设备驱动,这个模块一般是由生产厂家完成的。大概流程图可见下面:
AudioTrack向AudioFlinger申请creatTrack(),然后有双方共同操作这个Track实例,前者通过它执行控制(start/stop)和写入数据操作(write),后者负责所有Track实体的管理 :
AudioRecord请求audioFlinger进行openRecord(),生成一个RecordTrack实例,其它的跟上面的AudioTrack过程一样;
AudioFlinger中所涉及的类的继承关系:
1, AudioFlinger 继承 BnAudioFlinger,目的是为了提供binder接口供audioSystem分配AudioTrack对象;
2,DuplicatingThread 继承 MixerThread 继承 PlaybackThread 继承 ThreadBase 继承 Thread;
PlaybackThread的子类Track 继承 TrackBase;
ThreadBase 的子类TrackBase 继承 AudioBufferProvider;
3,DirectOutputThread 继承 PlaybackThread;
4,TrackHandle 继承 android::BnAudioTrack;
5,RecordThread 继承 ThreadBase和AudioBufferProvider;
RecordThread的子类RecordTrack 继承 TrackBase;
6,RecordHandle 继承 android::BnAudioRecord
在AudioFlinger中,有一个DuplicationThread,这个线程的功能可能有些人不太能理解,它其实是为了多音频设备同时输出时而存在的,当有多个设备需要同时输出音频时,AudioFlinger会用openDuplicateOutput()来创建一个thread,当Mixer将数据混合好后,同时写入两个虚拟的outputTrack中,就实现了多设备的输出;
MixerThread是完成音频数据混合的线程,它的处理过程如下:
MixerThread::threadLoop()---> processConfigEvents()+prepareTracks_l()(修改所有的mActiveTracks状态,并将没有准备好的Tracks Remove出去)+mAudioMixer->process()+mOutput->stream->write()这样就将数据写到硬件HAL中;
下面看一下播放器应用程序创建音频对象的流程,这里从JNI开始,不考虑JAVA层:
android_media_MediaPlayer.cpp(JNI):android_media_MediaPlayer_native_setup()---->new MediaPlayer()(在这里会申请一个AudioSessionId)----->IMediaPlayer(这个对象的创建是在 MediaPlayer::setDataSource()--->IMediaPlayerService::create(), 同时会在MediaPlayerService端创建一个本地对象)----通过binder在服务端创建client对象-----new Client()---->MediaPlayerBase mPlayer(stagefrightplayer--->awesomePlayer--->OMX)------>AudioOutput mAudioOutput(在setDataSource()时创建);
MediaPlayerService::AudioOutput::open()---->new AudioTrack()----->AudioTrack::set()---->createTrack_l()---->sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger()(获取audioFlinger的binder对象)------->sp<IAudioTrack> track = audioFlinger->createTrack()(对过audioFlinger 创建AudioTrack对象并返回binder对象)这样就播放器应用就与audioFlinger建立了对应联系;
从代码模块音频部分可分为五大块:AudioSystem, AudioPoliceService, AudioFlinger, AudioTrack, AudioRecord,其中最为难理解的就是AudioPoliceService,它涉及到整个音频系统的使用策略,较为复杂。下面是这五大块之间的联系关系:
audio_io_handle_t output将AF,AS, APS关联起来,AF在createTrack时会用到output,利用output找到对应类型的playbackThread,而output是由AT的set时通过AS::getOutput()得到的,AS通过stream类型映射的output,若不存在这种映射,会通过APS::getOutput()获取output,同时AS会建立一种stream和output的映射,以后再使用的时候就不用再麻烦APS了,其实APS中的output也是从AF中获取的,这个output在AF创建MixerThread的时候产生的,感觉绕了一个大圈啊!!!!!
AudioTrack::set()---->AS::getOutput()---->APS::getOutput()---->mpAudioPolicy::get_output()(HAL, audio_policy)----->ap_get_output()(目前代码中处理为空,猜测应该用aps_ops->open_output)如果猜测正确的话, aps_open_output()---->AF::openOutput---->findSuitableHwDev+open_output_stream+AudioStreamOut+MixerThread;
音频数据更新流程:
1,启动线程:AudioTrack::start()----->AudioTrackThread::run()---->createThreadEtc()--->Thread::_threadLoop()---->self->threadLoop()----> AudioTrack::AudioTrackThread::threadLoop()---->AudioTrack::processAudioBuffer()
2, MediaPlayerService::AudioOutput::CallbackWrapper()作为回调函数,在MediaPlayerService::AudioOutput::open()--->ew AudioTrack()时,作为参数送到AudioTrack中mCbf,在上面的处理线程AudioTrack::processAudioBuffer()中会用到这个回调函数;
3,AudioTrack在向AudioFlinger申请IAudioTrack对象时,会同时申请一块内存sp<IMemory> cblk = track->getCblk();将内存地址给audio_track_cblk_t mCblk对象,其实播放器解码后的数据都是填充到这个内存块中,然后AudioFlinger从这块内存中取出数据操作。