Android AudioFlinger(四)—— 揭开PlaybackThread面纱

打印 上一主题 下一主题

主题 1012|帖子 1012|积分 3036

前言:

继上一篇Android AudioFlinger(三)—— AndroidAudio Flinger 之设备管理我们知道PlaybackThread继承自Re’fBase, 在被第一次引用的时候就会调用onFirstRef,实现如下:
  1. void AudioFlinger::PlaybackThread::onFirstRef()
  2. {
  3.     run(mThreadName, ANDROID_PRIORITY_URGENT_AUDIO);
  4. }
复制代码
很简单就调用了一个run方法去开起了一个ThreadLoop线程:
  1. bool AudioFlinger::PlaybackThread::threadLoop()
  2. {
  3. ...
  4. }
复制代码
接下来我们进一步研究下PlaybackThread的循环主题具体做了什么?
揭开PlaybackThread面纱

当进入到threadloop就分析playbackthread的音频变乱正式开启了。代码比力多,但是我们如果细致看的话会发现关键代码就几处,而且都是threadLoop_前缀的,threadLoop_standby\threadLoop_mix\threadLoop_sleepTime\threadLoop_write等,这也代表这些函数都是threadLoop内部调用的。
  1. bool AudioFlinger::PlaybackThread::threadLoop()
  2. {
  3. ...
  4.     while (!exitPending())
  5.     {
  6.   ...
  7.         { // scope for mLock
  8.             //这个地方框起来主要就是限制自动锁_l的生命周期,
  9.             Mutex::Autolock _l(mLock);
  10.             //处理config事件
  11.             processConfigEvents_l();            
  12.             if ((!mActiveTracks.size() && systemTime() > mStandbyTimeNs) ||
  13.                                    isSuspended()) {
  14.                 if (shouldStandby_l()) {
  15.                     //进入standby状态节省能耗
  16.                     threadLoop_standby();
  17.                 }
  18.             }
  19.             //准备音频流
  20.             mMixerStatus = prepareTracks_l(&tracksToRemove);
  21.         } // mLock scope ends
  22.     ...
  23.         if (mBytesRemaining == 0) {
  24.             mCurrentWriteLength = 0;
  25.             if (mMixerStatus == MIXER_TRACKS_READY) {
  26.                 //读取所有active设备数据,混音器开始混音
  27.                 threadLoop_mix();
  28.             } else if ((mMixerStatus != MIXER_DRAIN_TRACK)
  29.                         && (mMixerStatus != MIXER_DRAIN_ALL)) {
  30.                 //进入休眠
  31.                 threadLoop_sleepTime();
  32.             }
  33.         }
  34.     ...
  35.         if (!waitingAsyncCallback()) {
  36.             if (mSleepTimeUs == 0) {
  37.                 if (mBytesRemaining) {
  38.                     //把混音器处理好的数据写入到输出流设备
  39.                     ret = threadLoop_write();
  40.                 } else if ((mMixerStatus == MIXER_DRAIN_TRACK) ||
  41.                         (mMixerStatus == MIXER_DRAIN_ALL)) {
  42.                     threadLoop_drain();
  43.                 }
  44.              ...
  45.             }
  46.         }
  47. ...
  48.         //移除相关的track
  49.         threadLoop_removeTracks(tracksToRemove);
  50.         tracksToRemove.clear();
  51.         clearOutputTracks();
  52.         effectChains.clear();
  53.     }
  54.     threadLoop_exit();
  55.     if (!mStandby) {
  56.         threadLoop_standby();
  57.         mStandby = true;
  58.     }
  59.     releaseWakeLock();
  60.     return false;
  61. }
复制代码
首先exitPending是threadloop循环的条件,这个函数是Thread的内部函数,它主要就是通过判断mExitPending来决定是否退出线程,这个值默认为false,在收到requestExit大概requestExitAndWait的时候会变为true,然后就会退出循环。
Thread PATH:/system/core/libutils/Threads.cpp
processConfigEvents_l: 处理config时间,当有设置发声变化的时候会调用sendConfigEvent_l来把变乱添加到mConfigEvents中,最终processConfigEvents_l检测到就会去处理对应的设置。
threadLoop_standby: 判断当前是否符合standby条件,符合就调用threadLoop_standby,最终的实现其实是hal层实现,会做出关闭音频流等操作。
prepareTracks_l: 这个函数非常复杂,我们简单概括下,挑几个重点谈一谈
  1. // prepareTracks_l() must be called with ThreadBase::mLock held
  2. AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTracks_l(
  3.         Vector< sp<Track> > *tracksToRemove)
  4. {
  5.   //获取当前活跃的track数量
  6.     size_t count = mActiveTracks.size();
  7.     for (size_t i=0 ; i<count ; i++) {
  8.     //循环每个活跃的track
  9.         const sp<Track> t = mActiveTracks[i];
  10.         // this const just means the local variable doesn't change
  11.         Track* const track = t.get();
  12.         // process fast tracks
  13.         if (track->isFastTrack()) {
  14.       //如果是fasttrack改如何处理
  15.         }
  16. ...
  17.         {   // local variable scope to avoid goto warning
  18.     //数据块准备操作
  19.         audio_track_cblk_t* cblk = track->cblk();
  20.     //获取track的音频信息
  21.         const uint32_t sampleRate = track->mAudioTrackServerProxy->getSampleRate();
  22.         AudioPlaybackRate playbackRate = track->mAudioTrackServerProxy->getPlaybackRate();
  23.         desiredFrames = sourceFramesNeededWithTimestretch(
  24.                 sampleRate, mNormalFrameCount, mSampleRate, playbackRate.mSpeed);
  25.         desiredFrames += mAudioMixer->getUnreleasedFrames(track->name());
  26.         uint32_t minFrames = 1;
  27.         if ((track->sharedBuffer() == 0) && !track->isStopped() && !track->isPausing() &&
  28.                 (mMixerStatusIgnoringFastTracks == MIXER_TRACKS_READY)) {
  29.       //至少需要准备的音频帧数
  30.             minFrames = desiredFrames;
  31.         }
  32.         size_t framesReady = track->framesReady();
  33.         if ((framesReady >= minFrames) && track->isReady() &&
  34.                 !track->isPaused() && !track->isTerminated())
  35.         {
  36.             mixedTracks++;
  37.             // compute volume for this track
  38.             uint32_t vl, vr;       // in U8.24 integer format
  39.             float vlf, vrf, vaf;   // in [0.0, 1.0] float format//左声道,右声道,aux level音量
  40.             // read original volumes with volume control
  41.             float typeVolume = mStreamTypes[track->streamType()].volume;//获取每个stream类型的音频音量
  42.             float v = masterVolume * typeVolume;//主音量和类型音量相乘
  43.             if (track->isPausing() || mStreamTypes[track->streamType()].mute) {
  44.                 vl = vr = 0;
  45.                 vlf = vrf = vaf = 0.;//设置0,代表静音操作
  46.                 if (track->isPausing()) {
  47.                     track->setPaused();//track设置暂停
  48.                 }
  49.             } else {
  50.                 sp<AudioTrackServerProxy> proxy = track->mAudioTrackServerProxy;
  51.                 gain_minifloat_packed_t vlr = proxy->getVolumeLR();//得到音量的增益值
  52.                 vlf = float_from_gain(gain_minifloat_unpack_left(vlr));
  53.                 vrf = float_from_gain(gain_minifloat_unpack_right(vlr));//转换为浮点值
  54.                 // track volumes come from shared memory, so can't be trusted and must be clamped
  55.         //判断是否在合理范围内
  56.                 if (vlf > GAIN_FLOAT_UNITY) {
  57.                     ALOGV("Track left volume out of range: %.3g", vlf);
  58.                     vlf = GAIN_FLOAT_UNITY;
  59.                 }
  60.                 if (vrf > GAIN_FLOAT_UNITY) {
  61.                     ALOGV("Track right volume out of range: %.3g", vrf);
  62.                     vrf = GAIN_FLOAT_UNITY;
  63.                 }
  64.                 const float vh = track->getVolumeHandler()->getVolume(
  65.                         track->mAudioTrackServerProxy->framesReleased()).first;
  66.                 // now apply the master volume and stream type volume and shaper volume
  67.                 vlf *= v * vh;
  68.                 vrf *= v * vh;
  69.                 // assuming master volume and stream type volume each go up to 1.0,
  70.                 // then derive vl and vr as U8.24 versions for the effect chain
  71.                 const float scaleto8_24 = MAX_GAIN_INT * MAX_GAIN_INT;
  72.                 vl = (uint32_t) (scaleto8_24 * vlf);
  73.                 vr = (uint32_t) (scaleto8_24 * vrf);
  74.                 // vl and vr are now in U8.24 format
  75.                 uint16_t sendLevel = proxy->getSendLevel_U4_12();
  76.                 // send level comes from shared memory and so may be corrupt
  77.                 if (sendLevel > MAX_GAIN_INT) {
  78.                     ALOGV("Track send level out of range: %04X", sendLevel);
  79.                     sendLevel = MAX_GAIN_INT;
  80.                 }
  81.                 // vaf is represented as [0.0, 1.0] float by rescaling sendLevel
  82.                 vaf = v * sendLevel * (1. / MAX_GAIN_INT);
  83.             }
  84.             track->setFinalVolume((vrf + vlf) / 2.f);
  85.             // XXX: these things DON'T need to be done each time
  86.             mAudioMixer->setBufferProvider(name, track);
  87.             mAudioMixer->enable(name);
  88.             mAudioMixer->setParameter(name, param, AudioMixer::VOLUME0, &vlf);
  89.             mAudioMixer->setParameter(name, param, AudioMixer::VOLUME1, &vrf);
  90.             mAudioMixer->setParameter(name, param, AudioMixer::AUXLEVEL, &vaf);
  91. ...
  92.         } else {
  93.            ...
  94.         }
  95.         }   // local variable scope to avoid goto warning
  96.     }
  97.     return mixerStatus;
  98. }
复制代码
mActiveTracks记录了当前处于活跃状态的track,接着就是循环遍历每一个track举行处理,获取对应的音频参数。
audio_track_cblk_t是音频数据块,后面我们会扩展讲解。
在之后minFrames代表了此次音频播放所必要的最小帧数,他的初始值为1。当track->sharedBuffer() == 0的时候,分析这个AudioTrack不是STATIC模式(数据不是一次性传送完成的)。
getUnreleasedFrames用来获取音频缓冲区中尚未被音频硬件处理的帧数。
当我们盘算出minFrames之后,就开始判断当前音频的各种指标是否符合标准。
vlf, vrf, vaf分别表示,左声道音量,右声道音量,AUX level音量,浮点数表示。
根据streamType获取对应stream范例音频的音量,然后举行判断是否在公道范围内,最终经过盘算设置到AudioMixer对象中。当预备工作完成后,就进入到了真正的混音操作中了。
threadloop_mix:主要就是调用AudioMixer的process函数举行处理,这样就进入了audiomixer。
  1. void AudioFlinger::MixerThread::threadLoop_mix()
  2. {
  3.     // 启动混音
  4.     mAudioMixer->process();
  5.     mCurrentWriteLength = mSinkBufferSize;
  6.     //当应用程序欠载情况清除时,逐步增加睡眠时间。
  7.     //仅当混频器连续两次准备就绪时才增加睡眠时间,
  8.     //以避免交替的就绪/未就绪条件的稳定状态保持睡眠时间,从而导致音频 HAL 欠载。
  9.     if ((mSleepTimeUs == 0) && (sleepTimeShift > 0)) {
  10.         sleepTimeShift--;
  11.     }
  12.     mSleepTimeUs = 0;
  13.     mStandbyTimeNs = systemTime() + mStandbyDelayNs;
  14.     //TODO: delay standby when effects have a tail
  15. }
复制代码
最后就是将数据写入HAL层了,threadloop_write。
当mNormalSink存在的时候调用他的write函数写入,不存在就调用mOutput的write函数,mOutput就是 AudioStreamOut。
  1. ssize_t AudioFlinger::PlaybackThread::threadLoop_write()
  2. {
  3.     ssize_t bytesWritten;
  4.     // If an NBAIO sink is present, use it to write the normal mixer's submix
  5.     if (mNormalSink != 0) {
  6.         ssize_t framesWritten = mNormalSink->write((char *)mSinkBuffer + offset, count);
  7.         ATRACE_END();
  8.         if (framesWritten > 0) {
  9.             bytesWritten = framesWritten * mFrameSize;
  10.         } else {
  11.             bytesWritten = framesWritten;
  12.         }
  13.     // otherwise use the HAL / AudioStreamOut directly
  14.     } else {
  15.         bytesWritten = mOutput->write((char *)mSinkBuffer + offset, mBytesRemaining);
  16.     }
  17.     return bytesWritten;
  18. }
复制代码
写入完成后调用各种整理的函数,remove,clear等。
  1. // Finally let go of removed track(s), without the lock held
  2. // since we can't guarantee the destructors won't acquire that
  3. // same lock.  This will also mutate and push a new fast mixer state.
  4. threadLoop_removeTracks(tracksToRemove);
  5. tracksToRemove.clear();
  6. // FIXME I don't understand the need for this here;
  7. //       it was in the original code but maybe the
  8. //       assignment in saveOutputTracks() makes this unnecessary?
  9. clearOutputTracks();
  10. // Effect chains will be actually deleted here if they were removed from
  11. // mEffectChains list during mixing or effects processing
  12. effectChains.clear();
复制代码
  1. void AudioFlinger::PlaybackThread::threadLoop_removeTracks(
  2.         const Vector< sp<Track> >& tracksToRemove)
  3. {
  4.     size_t count = tracksToRemove.size();
  5.     if (count > 0) {
  6.         for (size_t i = 0 ; i < count ; i++) {
  7.             const sp<Track>& track = tracksToRemove.itemAt(i);
  8.             if (track->isExternalTrack()) {
  9.                 AudioSystem::stopOutput(mId, track->streamType(),
  10.                                         track->sessionId());
  11.                 if (track->isTerminated()) {
  12.                     AudioSystem::releaseOutput(mId, track->streamType(),
  13.                                                track->sessionId());
  14.                 }
  15.             }
  16.         }
  17.     }
  18. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

干翻全岛蛙蛙

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表