当前位置: 首页 > article >正文

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[i];
        // 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 [0.0, 1.0] float format//左声道,右声道,aux level音量
            // read original volumes with volume control
            float typeVolume = mStreamTypes[track->streamType()].volume;//获取每个stream类型的音频音量
            float v = masterVolume * typeVolume;//主音量和类型音量相乘

            if (track->isPausing() || mStreamTypes[track->streamType()].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 [0.0, 1.0] 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());
                }
            }
        }
    }
}

http://www.kler.cn/a/577881.html

相关文章:

  • react脚手架(creat-react-app)
  • 大数定律详解
  • 回归预测 | Matlab实现GWO-BP-Adaboost基于灰狼算法优化BP神经网络结合Adaboost思想的回归预测
  • 使用Dify+DeepSeek搭建私有知识库
  • STM32入门之I2C总线应用详解(附LM75A温度传感器实战) | 零基础入门STM32第四十九步
  • #UVM# 关于 config_db 机制中的“路径”和“层次”概念剖析
  • 点云数据处理--splat转3dtiles
  • 架构师面试(十一):消息收发
  • ajax之生成一个ajax的demo示例
  • 网络安全 api 网络安全 ast技术
  • 【五.LangChain技术与应用】【9.LangChain ChatPromptTemplate(上):高级对话模板设计】
  • MuBlE:为机器人操作任务规划提供了逼真的视觉观察和精确的物理建模
  • 力扣hot100——多维动态规划
  • MySQL5.7.44-winx64版本Windows Server下载安装教程图解
  • three.js 在 webGL 添加纹理
  • Django系列教程(5)——Django模型详解
  • [FE] React 初窥门径(五):React 组件的加载过程(commit 阶段)
  • 【爬虫软件】抖音评论区采集工具
  • [含文档+PPT+源码等]精品基于Python实现的django电动车租赁系统
  • FPGA 实验报告:四位全加器与三八译码器仿真实现