Android Framework的音频子系统中,每一个音频流对应着一个AudioTrack类的一个实例,每个AudioTrack会在创建时注册到AudioFlinger中,由AudioFlinger把所有的AudioTrack进行混合(Mixer),然后输送到AudioHardware中进行播放,目前Android的Froyo版本设定了同时最多可以创建32个音频流,也就是说,Mixer最多会同时处理32个AudioTrack的数据流。
如何使用AudioTrack
AudioTrack的主要代码位于 frameworks\base\media\libmedia\audiotrack.cpp中。现在先通过一个例子来了解一下如何使用AudioTrack,ToneGenerator是android中产生电话拨号音和其他音调波形的一个实现,我们就以它为例子:
ToneGenerator的初始化函数:
- bool ToneGenerator::initAudioTrack() {
-
- mpAudioTrack = new AudioTrack();
- mpAudioTrack->set(mStreamType,
- 0,
- AudioSystem::PCM_16_BIT,
- AudioSystem::CHANNEL_OUT_MONO,
- 0,
- 0,
- audioCallback,
- this,
- 0,
- 0,
- mThreadCanCallJava);
- if (mpAudioTrack->initCheck() != NO_ERROR) {
- LOGE("AudioTrack->initCheck failed");
- goto initAudioTrack_exit;
- }
- mpAudioTrack->setVolume(mVolume, mVolume);
- mState = TONE_INIT;
- ......
- }
可见,创建步骤很简单,先new一个AudioTrack的实例,然后调用set成员函数完成参数的设置并注册到AudioFlinger中,然后可以调用其他诸如设置音量等函数进一步设置音频参数。其中,一个重要的参数是audioCallback,audioCallback是一个回调函数,负责响应AudioTrack的通知,例如填充数据、循环播放、播放位置触发等等。回调函数的写法通常像这样:
- void ToneGenerator::audioCallback(int event, void* user, void *info) {
- if (event != AudioTrack::EVENT_MORE_DATA) return;
- AudioTrack::Buffer *buffer = static_cast(info);
- ToneGenerator *lpToneGen = static_cast(user);
- short *lpOut = buffer->i16;
- unsigned int lNumSmp = buffer->size/sizeof(short);
- const ToneDescriptor *lpToneDesc = lpToneGen->mpToneDesc;
- if (buffer->size == 0) return;
-
-
- memset(lpOut, 0, buffer->size);
- ......
-
- }
该函数首先判断事件的类型是否是EVENT_MORE_DATA,如果是,则后续的代码会填充相应的音频数据后返回,当然你可以处理其他事件,以下是可用的事件类型:
- enum event_type {
- EVENT_MORE_DATA = 0,
- EVENT_UNDERRUN = 1,
- EVENT_LOOP_END = 2,
- EVENT_MARKER = 3,
- EVENT_NEW_POS = 4,
- EVENT_BUFFER_END = 5
- };
开始播放:
停止播放:
只要简单地调用成员函数start()和stop()即可。
AudioTrack和AudioFlinger的通信机制
通常,AudioTrack和AudioFlinger并不在同一个进程中,它们通过android中的binder机制建立联系。
AudioFlinger是android中的一个service,在android启动时就已经被加载。下面这张图展示了他们两个的关系:
图一 AudioTrack和AudioFlinger的关系
我们可以这样理解这张图的含义:
- audio_track_cblk_t实现了一个环形FIFO;
- AudioTrack是FIFO的数据生产者;
- AudioFlinger是FIFO的数据消费者。
建立联系的过程
下面的序列图展示了AudioTrack和AudioFlinger建立联系的过程:
图二 AudioTrack和AudioFlinger建立联系
解释一下过程:
- Framework或者Java层通过JNI,new AudioTrack();
- 根据StreamType等参数,通过一系列的调用getOutput();
- 如有必要,AudioFlinger根据StreamType打开不同硬件设备;
- AudioFlinger为该输出设备创建混音线程: MixerThread(),并把该线程的id作为getOutput()的返回值返回给AudioTrack;
- AudioTrack通过binder机制调用AudioFlinger的createTrack();
- AudioFlinger注册该AudioTrack到MixerThread中;
- AudioFlinger创建一个用于控制的TrackHandle,并以IAudioTrack这一接口作为createTrack()的返回值;
- AudioTrack通过IAudioTrack接口,得到在AudioFlinger中创建的FIFO(audio_track_cblk_t);
- AudioTrack创建自己的监控线程:AudioTrackThread;
自此,AudioTrack建立了和AudioFlinger的全部联系工作,接下来,AudioTrack可以:
- 通过IAudioTrack接口控制该音轨的状态,例如start,stop,pause等等;
- 通过对FIFO的写入,实现连续的音频播放;
- 监控线程监控事件的发生,并通过audioCallback回调函数与用户程序进行交互;
阅读(2850) | 评论(0) | 转发(1) |