干翻全岛蛙蛙 发表于 2025-3-9 16:01:55

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

前言:

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

当进入到threadloop就分析playbackthread的音频变乱正式开启了。代码比力多,但是我们如果细致看的话会发现关键代码就几处,而且都是threadLoop_前缀的,threadLoop_standby\threadLoop_mix\threadLoop_sleepTime\threadLoop_write等,这也代表这些函数都是threadLoop内部调用的。
bool AudioFlinger::PlaybackThread::threadLoop()
{
...
    while (!exitPending())
    {
...
      { // scope for mLock
            //这个地方框起来主要就是限制自动锁_l的生命周期,
            Mutex::Autolock _l(mLock);
            //处理config事件
            processConfigEvents_l();            
            if ((!mActiveTracks.size() && systemTime() > mStandbyTimeNs) ||
                                 isSuspended()) {
                if (shouldStandby_l()) {
                  //进入standby状态节省能耗
                  threadLoop_standby();
                }
            }
            //准备音频流
            mMixerStatus = prepareTracks_l(&tracksToRemove);
      } // mLock scope ends
    ...
      if (mBytesRemaining == 0) {
            mCurrentWriteLength = 0;
            if (mMixerStatus == MIXER_TRACKS_READY) {
                //读取所有active设备数据,混音器开始混音
                threadLoop_mix();
            } else if ((mMixerStatus != MIXER_DRAIN_TRACK)
                        && (mMixerStatus != MIXER_DRAIN_ALL)) {
                //进入休眠
                threadLoop_sleepTime();
            }
      }
    ...
      if (!waitingAsyncCallback()) {
            if (mSleepTimeUs == 0) {
                if (mBytesRemaining) {
                  //把混音器处理好的数据写入到输出流设备
                  ret = threadLoop_write();
                } else if ((mMixerStatus == MIXER_DRAIN_TRACK) ||
                        (mMixerStatus == MIXER_DRAIN_ALL)) {
                  threadLoop_drain();
                }
             ...
            }
      }
...
      //移除相关的track
      threadLoop_removeTracks(tracksToRemove);
      tracksToRemove.clear();
      clearOutputTracks();
      effectChains.clear();
    }
    threadLoop_exit();
    if (!mStandby) {
      threadLoop_standby();
      mStandby = true;
    }
    releaseWakeLock();
    return false;
}
首先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: 这个函数非常复杂,我们简单概括下,挑几个重点谈一谈

// prepareTracks_l() must be called with ThreadBase::mLock held
AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTracks_l(
      Vector< sp<Track> > *tracksToRemove)
{
//获取当前活跃的track数量
    size_t count = mActiveTracks.size();
    for (size_t i=0 ; i<count ; i++) {
    //循环每个活跃的track
      const sp<Track> t = mActiveTracks;
      // this const just means the local variable doesn't change
      Track* const track = t.get();
      // process fast tracks
      if (track->isFastTrack()) {
      //如果是fasttrack改如何处理
      }
...
      {   // local variable scope to avoid goto warning
    //数据块准备操作
      audio_track_cblk_t* cblk = track->cblk();
    //获取track的音频信息
      const uint32_t sampleRate = track->mAudioTrackServerProxy->getSampleRate();
      AudioPlaybackRate playbackRate = track->mAudioTrackServerProxy->getPlaybackRate();

      desiredFrames = sourceFramesNeededWithTimestretch(
                sampleRate, mNormalFrameCount, mSampleRate, playbackRate.mSpeed);

      desiredFrames += mAudioMixer->getUnreleasedFrames(track->name());

      uint32_t minFrames = 1;
      if ((track->sharedBuffer() == 0) && !track->isStopped() && !track->isPausing() &&
                (mMixerStatusIgnoringFastTracks == MIXER_TRACKS_READY)) {
      //至少需要准备的音频帧数
            minFrames = desiredFrames;
      }
      size_t framesReady = track->framesReady();
      if ((framesReady >= minFrames) && track->isReady() &&
                !track->isPaused() && !track->isTerminated())
      {
            mixedTracks++;
            // compute volume for this track
            uint32_t vl, vr;       // in U8.24 integer format
            float vlf, vrf, vaf;   // in float format//左声道,右声道,aux level音量
            // read original volumes with volume control
            float typeVolume = mStreamTypes.volume;//获取每个stream类型的音频音量
            float v = masterVolume * typeVolume;//主音量和类型音量相乘

            if (track->isPausing() || mStreamTypes.mute) {
                vl = vr = 0;
                vlf = vrf = vaf = 0.;//设置0,代表静音操作
                if (track->isPausing()) {
                  track->setPaused();//track设置暂停
                }
            } else {
                sp<AudioTrackServerProxy> proxy = track->mAudioTrackServerProxy;
                gain_minifloat_packed_t vlr = proxy->getVolumeLR();//得到音量的增益值
                vlf = float_from_gain(gain_minifloat_unpack_left(vlr));
                vrf = float_from_gain(gain_minifloat_unpack_right(vlr));//转换为浮点值
                // track volumes come from shared memory, so can't be trusted and must be clamped
      //判断是否在合理范围内
                if (vlf > GAIN_FLOAT_UNITY) {
                  ALOGV("Track left volume out of range: %.3g", vlf);
                  vlf = GAIN_FLOAT_UNITY;
                }
                if (vrf > GAIN_FLOAT_UNITY) {
                  ALOGV("Track right volume out of range: %.3g", vrf);
                  vrf = GAIN_FLOAT_UNITY;
                }
                const float vh = track->getVolumeHandler()->getVolume(
                        track->mAudioTrackServerProxy->framesReleased()).first;
                // now apply the master volume and stream type volume and shaper volume
                vlf *= v * vh;
                vrf *= v * vh;
                // assuming master volume and stream type volume each go up to 1.0,
                // then derive vl and vr as U8.24 versions for the effect chain
                const float scaleto8_24 = MAX_GAIN_INT * MAX_GAIN_INT;
                vl = (uint32_t) (scaleto8_24 * vlf);
                vr = (uint32_t) (scaleto8_24 * vrf);
                // vl and vr are now in U8.24 format
                uint16_t sendLevel = proxy->getSendLevel_U4_12();
                // send level comes from shared memory and so may be corrupt
                if (sendLevel > MAX_GAIN_INT) {
                  ALOGV("Track send level out of range: %04X", sendLevel);
                  sendLevel = MAX_GAIN_INT;
                }
                // vaf is represented as float by rescaling sendLevel
                vaf = v * sendLevel * (1. / MAX_GAIN_INT);
            }

            track->setFinalVolume((vrf + vlf) / 2.f);

            // XXX: these things DON'T need to be done each time
            mAudioMixer->setBufferProvider(name, track);
            mAudioMixer->enable(name);

            mAudioMixer->setParameter(name, param, AudioMixer::VOLUME0, &vlf);
            mAudioMixer->setParameter(name, param, AudioMixer::VOLUME1, &vrf);
            mAudioMixer->setParameter(name, param, AudioMixer::AUXLEVEL, &vaf);
...
      } else {
         ...
      }
      }   // local variable scope to avoid goto warning
    }

    return mixerStatus;
}
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。

void AudioFlinger::MixerThread::threadLoop_mix()
{
    // 启动混音
    mAudioMixer->process();
    mCurrentWriteLength = mSinkBufferSize;
    //当应用程序欠载情况清除时,逐步增加睡眠时间。
    //仅当混频器连续两次准备就绪时才增加睡眠时间,
    //以避免交替的就绪/未就绪条件的稳定状态保持睡眠时间,从而导致音频 HAL 欠载。
    if ((mSleepTimeUs == 0) && (sleepTimeShift > 0)) {
      sleepTimeShift--;
    }
    mSleepTimeUs = 0;
    mStandbyTimeNs = systemTime() + mStandbyDelayNs;
    //TODO: delay standby when effects have a tail

}
最后就是将数据写入HAL层了,threadloop_write。
当mNormalSink存在的时候调用他的write函数写入,不存在就调用mOutput的write函数,mOutput就是 AudioStreamOut。
ssize_t AudioFlinger::PlaybackThread::threadLoop_write()
{
    ssize_t bytesWritten;
    // If an NBAIO sink is present, use it to write the normal mixer's submix
    if (mNormalSink != 0) {
      ssize_t framesWritten = mNormalSink->write((char *)mSinkBuffer + offset, count);
      ATRACE_END();
      if (framesWritten > 0) {
            bytesWritten = framesWritten * mFrameSize;
      } else {
            bytesWritten = framesWritten;
      }
    // otherwise use the HAL / AudioStreamOut directly
    } else {
      bytesWritten = mOutput->write((char *)mSinkBuffer + offset, mBytesRemaining);
    }
    return bytesWritten;
}

写入完成后调用各种整理的函数,remove,clear等。
// Finally let go of removed track(s), without the lock held
// since we can't guarantee the destructors won't acquire that
// same lock.This will also mutate and push a new fast mixer state.
threadLoop_removeTracks(tracksToRemove);
tracksToRemove.clear();

// FIXME I don't understand the need for this here;
//       it was in the original code but maybe the
//       assignment in saveOutputTracks() makes this unnecessary?
clearOutputTracks();

// Effect chains will be actually deleted here if they were removed from
// mEffectChains list during mixing or effects processing
effectChains.clear();
void AudioFlinger::PlaybackThread::threadLoop_removeTracks(
      const Vector< sp<Track> >& tracksToRemove)
{
    size_t count = tracksToRemove.size();
    if (count > 0) {
      for (size_t i = 0 ; i < count ; i++) {
            const sp<Track>& track = tracksToRemove.itemAt(i);
            if (track->isExternalTrack()) {
                AudioSystem::stopOutput(mId, track->streamType(),
                                        track->sessionId());
                if (track->isTerminated()) {
                  AudioSystem::releaseOutput(mId, track->streamType(),
                                             track->sessionId());
                }
            }
      }
    }
}

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: Android AudioFlinger(四)—— 揭开PlaybackThread面纱