转载自http://bbs.9ria.com/forum.php?mod=viewthread&tid=213240&highlight=AUDIOFLINGER

 

1.PlaybackThread的循环主体当一个PlaybackThread进入主循环后(threadLoop),音频事务就正式开启了。仔细观察的话,我们会发现这个循环中会不断地调用以“threadLoop_”开头的若干接口,比如threadLoop_mix、threadLoop_sleepTime、threadLoop_standby等等。以这样的前缀开头,是因为这些函数都是在threadLoop这个主体里被调用的,可以说代表了这个PlaybackThread所需要完成的各个操作步骤。从上一小节可以了解到,当程序执行到PlaybackThread:nFirstRef时会去真正启动一个线程承载运行threadLoop,接下来我们具体看下这个循环体的处理流程。

  1. bool AudioFlinger::PlaybackThread::threadLoop()
  2. { …         
  3.     while (!exitPending())/*Step1.*/
  4.     {   …     
  5.         processConfigEvents();/*Step 2. */
  6.         { /*把这段代码框起来的目的是限制自动锁变量_l的生命期,
  7.            从而灵活地实现了自动锁的控制范围*/
  8.           Mutex::Autolock  _l(mLock);
  9.                                  …
  10.           /*Step 3. Standby判断*/
  11.           if(CC_UNLIKELY((!mActiveTracks.size() && systemTime() > standbyTime)|| mSuspended> 0)) {                        
  12.                 if (!mStandby){
  13.                    threadLoop_standby();//调用设备的
  14.                     mStandby =true;
  15.                    mBytesWritten = 0;
  16.                 }
  17.                                                  …
  18.            }
  19.                                   /*Step 4.*/
  20.             mMixerStatus =prepareTracks_l(&tracksToRemove);
  21.                                    …
  22.         }
  23.                                 /*Step5.*/
  24.         if(CC_LIKELY(mMixerStatus == MIXER_TRACKS_READY)) {
  25.             threadLoop_mix();
  26.         } else {
  27.            threadLoop_sleepTime();
  28.         }
  29.                    …
  30.         /*Step 6.*/
  31.         if (sleepTime == 0) {
  32.            threadLoop_write(); //不需要休眠,有数据要写
  33.                                    …
  34.             mStandby = false;
  35.         } else {
  36.             usleep(sleepTime);//进入休眠,时间长短是sleepTime
  37.         }
  38.                     /*Step 7.*/
  39.         threadLoop_removeTracks(tracksToRemove);//移除相关Track
  40.        tracksToRemove.clear();…
  41.     }//while (!exitPending())结束
  42.                 …
  43.     releaseWakeLock();
  44.     return false;
  45. }
复制代码
Step1@ PlaybackThread::threadLoop, 循环的条件是!exitPending()为true。这个函数属于Thread类,它主要通过判断内部变量mExitPending的值来得出是否要结束线程。变量mExitPending在Thread初始化时为fasle,如果后面有人通过requestExit()、requestExitAndWait等等来请求退出,这个值就会改变,从而使得Playback Thread结束循环。Step2@ PlaybackThread::threadLoop, 处理config事件。当有配置改变的事件发生时,可以通过sendConfigEvent来通知PlaybackThread。这个函数将把事件添加到mConfigEvents全局变量中,以供processConfigEvents进行处理。配置事件包括如下几种:
      
  1. enum io_config_event {
  2.         OUTPUT_OPENED,//Output打开
  3.         OUTPUT_CLOSED,//Output关闭
  4.         OUTPUT_CONFIG_CHANGED,//Output配置改变
  5.         INPUT_OPENED, //Input打开
  6.         INPUT_CLOSED, //Input关闭
  7.         INPUT_CONFIG_CHANGED,//Input配置改变
  8.         STREAM_CONFIG_CHANGED,//Stream配置改变
  9.         NUM_CONFIG_EVENTS
  10.     };
复制代码
Step3@ PlaybackThread::threadLoop,判断当前是否符合Standby的条件,如果是的话就调用threadLoop_st andby。这个函数最终还是通过HAL层的接口来实现,如下:mOutput->stream->common.standby(&mOutput->stream->common);Step4@ PlaybackThread::threadLoop, 进行数据准备,prepareTracks_l这个函数非常长,我们先用伪代码的形式整理一下它所做的工作,如下所示:

  1. AudioFlinger::PlaybackThread::mixer_stateAudioFlinger::MixerThread::prepareTracks_l(…)
  2. {
  3.                 /*Step 1. 当前活跃的Track数量*/
  4.     size_t  count = mActiveTracks.size();

  5.     /*Step 2. 循环处理每个Track,这是函数的核心*/
  6.                 for (size_t i=0; i
  7.         Track* track =mActiveTracks[i];//伪代码没有考虑强指针

  8.         /*Step 3. FastTrack下的处理*/
  9.         if(track is FastTrack)
  10.         {
  11.                                                 //dosomething;
  12.         }
  13.         /*Step 4. 准备数据,分为以下几个小部来完成*/
  14.                                 audio_track_cblk_t*cblk = track->cblk(); //Step 4.1 数据块准备

  15.         /*Step 4.2 要回放音频前,至少需要准备多少帧数据?*/
  16.         uint32_t  minFrames = 1;//初始化
  17.           //具体计算minFrames…
  18.    
  19.         /*Step 4.3 如果数据已经准备完毕*/
  20.           //调整音量
  21.           //其它参数设置
  22.     }//for循环结束
  23.    
  24.      /*Step 5. 后续判断*/
  25.        //返回结果,指明当前状态是否已经ready
  26. }
复制代码
现在我们针对上面的步骤来做“填空”。Step1@ MixerThread::prepareTracks_l, mActiveTracks的数据类型是SortedVector,用于记录当前活跃的Track。它会随着新的AudioTrack的加入而扩大,也会在必要的情况下(AudioTrack工作结束、或者出错等等)remove相应的Track。Step2&3@MixerThread::prepareTracks_l, 循环的条件就是要逐个处理该PlaybackThread中包含的Track。假如当前是一个FastTrack,我们还要做一些其它准备,这里就暂时不去涉及具体细节了。

Step4@ MixerThread::prepareTracks_l, 这一步是准备工作中最重要的,那就是缓冲数据。在学习代码细节前,我们先来了解数据传输时容易出现的underrun情况。什么是BufferUnderrun呢?当两个设备或进程间形成“生产者-消费者”关系时,如果生产的速度不及消费者消耗的速度,就会出现Underrun。以音频回放为例,此时用户听到的声音就可能是断断续续的,或者是重复播放当前buffer中的数据(取决于具体的实现)。如何避免这种异常的发生?这也是Step4所要解决的问题,以下分为几个小步骤来看AudioFlinger是如何做到的。

Step4.1,取得数据块audio_track_cblk_t*cblk = track->cblk()关于audio_track_cblk_t的更多描述,可以参见后面数据流小节。Step4.2 计算正确回放音频所需的最少帧数,初始值为1。

                              
  1.   uint32_tminFrames = 1;
  2.                                 if((track->sharedBuffer() == 0) && !track->isStopped() &&!track->isPausing() &&
  3.                (mMixerStatusIgnoringFastTracks == MIXER_TRACKS_READY)) {
  4.             if(t->sampleRate() == (int)mSampleRate) {
  5.                 minFrames = mNormalFrameCount;
  6.             } else {
  7.                 minFrames =(mNormalFrameCount * t->sampleRate()) / mSampleRate + 1 + 1;               
  8.                 minFrames +=mAudioMixer->getUnreleasedFrames(track->name());               
  9.                ALOG_ASSERT(minFrames <= cblk->frameCount);
  10.             }
  11.          }
复制代码
当track->sharedBuffer()为0时,说明AudioTrack不是STATIC模式的,否则数据就是一次性传送的,可以参见AudioTrack小节的描述。全局变量mSampleRate 是通过mOutput->stream->common.get_sample_rate获得的,它是由HAL提供的,代表的是设备的Sampling rate。

如果两者一致的话,就采用mNormalFrameCount,这个值在readOutputParameters函数中进行初始化。如果两者不一致的话,就要预留多余的量做rounding(+1)和interpolation(+1)。另外,还需要考虑未释放的空间大小,也就是getUnreleasedFrames得到的。得出的minFrames必需小于数据块的总大小,因而最后有个ASSERT。通常情况下frameCount分配的是一个buffer的两倍,可以参见AudioTrack小节的例子。  Step4.3 数据是否准备就绪了?

上一步我们计算出了数据的最小帧值,即minFrames,接下来就该判断目前的情况是否符合这一指标了,代码如下所示:
                  
  1. ((track->framesReady() >=minFrames) && track->isReady() &&!track->isPaused()&& !track->isTerminated())
  2.         {//数据准备就绪,并处于ready状态
  3.             mixedTracks++; //需要mix的Track数量增加1
  4.             …
  5.             /*计算音量值*/
  6.             uint32_t vl, vr,va; //三个变量分别表示左、右声道、Aux level音量
  7.             if(track->isMuted() || track->isPausing()||mStreamTypes[track->streamType()].mute) {
  8.                 vl = vr = va =0; //当静音时,变量直接赋0
  9.                 if (track->isPausing()) {
  10.                    track->setPaused();
  11.                 }
  12.             } else {               
  13.                 /*这里获得的是针对每个stream类型设置的音量值,也就是后面“音量调节”小节里最
  14.                   后执行到的地方,在这里就起到作用了*/
  15.                                                   float typeVolume =mStreamTypes[track->streamType()].volume;               
  16.                 float v =masterVolume * typeVolume; //主音量和类型音量的乘积
  17.                 uint32_t  vlr = cblk->getVolumeLR(); //这里得到的vlr必须经过验证是否在合理范围内
  18.                 vl = vlr &0xFFFF; //vlr的高低位分别表示vr和vl
  19.                 vr = vlr>> 16;
  20.                 if (vl >MAX_GAIN_INT) { //对vl进行合理值判断
  21.                    ALOGV("Track left volume out of range: %04X", vl);
  22.                     vl =MAX_GAIN_INT;
  23.                 }
  24.                 if (vr >MAX_GAIN_INT) {//对vr进行合理值判断
  25.                    ALOGV("Track right volume out of range: %04X", vr);
  26.                     vr =MAX_GAIN_INT;
  27.                 }
  28.                 // now applythe master volume and stream type volume
  29.                 vl =(uint32_t)(v * vl) << 12;
  30.                 vr =(uint32_t)(v * vr) << 12;
  31.                 uint16_tsendLevel = cblk->getSendLevel_U4_12();
  32.                 // send levelcomes from shared memory and so may be corrupt
  33.                 if (sendLevel> MAX_GAIN_INT) {
  34.                     ALOGV("Track send level out of range:%04X", sendLevel);
  35.                     sendLevel= MAX_GAIN_INT;
  36.                 }
  37.                 va =(uint32_t)(v * sendLevel);
  38.             } …           
  39.            mAudioMixer->setParameter(name, param, AudioMixer::VOLUME0, (void*)vl);
  40.            mAudioMixer->setParameter(name, param, AudioMixer::VOLUME1, (void*)vr);
  41.            mAudioMixer->setParameter(name, param, AudioMixer::AUXLEVEL, (void*)va);
  42.             …           
  43.         } else {//
复制代码
数据未准备就绪,对于音量的设置还有很多细节,大家有兴趣的可以深入研究下。在得到vl、vr和va的值后,还需要把它们应用到AudioMixer中去,不过在prepareTracks_l中还只是调用mAudioMixer->setParameter设置了这些参数,真正的实现是在threadLoop_mix中,我们后面会讲到这个函数。

Step5@ MixerThread::prepareTracks_l, 通过对每个Track执行上述的处理后,最后要返回一个结果,这通常取决于:

①是否有activetrack

②active track的数据是否已经准备就绪

返回的最终值将影响到threadLoop的下一步操作。完成了prepareTracks_l的分析,我们再回到前面的thread Loop。Step5@ PlaybackThread::threadLoop, 如果上一步的数据准备工作已经完成(即返回值是MIXER_T RAC KS_READY),就开始进行真正的混音操作,即threadLoop_mix,否则会休眠一定的时间——如此循环往复直到退出循环体。

  1. void AudioFlinger::MixerThread::threadLoop_mix()
  2. {
  3.     int64_t pts;
  4.                 …
  5.    mAudioMixer->process(pts);
  6.     …
  7. }
复制代码
这样就进入AudioMixer的处理了,我们放在下一小节做统一分析。假如数据还没有准备就绪,那么AudioFlin ger将调用threadLoop_sleepTime来计算需要休眠多长时间(变量sleepTime),并在threadLoop主循环的末尾(在remove track之前)执行usleep进入休眠。Step6@ PlaybackThread::threadLoop, 将数据写到HAL中,从而逐步写入到硬件设备中。

  1. void AudioFlinger::PlaybackThread::threadLoop_write()
  2. {
  3.     mLastWriteTime =systemTime();
  4.     mInWrite = true;
  5.     int bytesWritten;
  6.     if (mNormalSink != 0) {
  7.                    …
  8.         ssize_t framesWritten= mNormalSink->write(mMixBuffer, count);
  9.         …
  10.     } else {
  11.         bytesWritten =(int)mOutput->stream->write(mOutput->stream, mMixBuffer,mixBufferSize);
  12.     }
  13.     if (bytesWritten > 0)mBytesWritten += mixBufferSize;
  14.     mNumWrites++;
  15.     mInWrite = false;
  16. }
复制代码
分为两种情况:

如果是采用了NBAIO(Non-blocking AudioI/O),即mNormalSink不为空,则通过它写入HA否则使用普通的AudioStreamOut(即mOutput变量)将数据输出Step7@ PlaybackThread::threadLoop, 移除tracksToRemove中指示的Tracks。是否移除一个Track是在prepareTracks_l中判断中,可以概括为以下几种情况:对于Fast Trac,如果它的状态(mState)是STOPPING_2、PAUSED、TERMINATED、STOPPED、FLUSHED,或者状态是ACTIVE但underun的次数超过限额(mRetryCount),则会被加入tracksToRemove列表中

当前的Track数据未准备就绪的情况下,且是STATICTRACK或者已经停止/暂停,也会被加入tracksToRemove列表中在tracksToRemove列表中的Track,与其相关的output将收到stop请求(由AudioSystem::stopOutput发起)关于AudioFlinger中与AudioTrack、AudioPolicyService有交互的部分,我们还将在后续小节进行阐述。

更多相关文章

  1. Android笔记汇总
  2. Android(安卓)Html.fromhtml
  3. Android源码分析:VoIP
  4. 解决Android文档打开慢的问题
  5. ContactsProvider2
  6. 利用SonarQube检测Android(安卓)studio 代码
  7. 用React Native做一个填字游戏(3)——背景音乐
  8. Android十八章:Realm-in-android
  9. AndroidAnnotations的使用

随机推荐

  1. Android计时器TimerTask,Timer,Handler
  2. Android通信之 Bluetooth
  3. Android——Handler和AsyncTask的使用
  4. Android Fragments 详细使用详细介绍
  5. Android安全模型之Android安全机制(进程通
  6. Android 的启动流程
  7. 应用phprpc协议实现Android客户端的一些
  8. Windows环境下Android Studio v1.0安装教
  9. Android(安卓)中 startService()启动serv
  10. Android布局常用控件