android 4.0之audio

来源:互联网 发布:blued软件中的符号 编辑:程序博客网 时间:2024/05/28 17:06

我使用的是三星的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从这块内存中取出数据操作。



 

原创粉丝点击