zoukankan      html  css  js  c++  java
  • Android音频系统之AudioFlinger(四)

    http://blog.csdn.net/xuesen_lin/article/details/8805096

    1.1.1 AudioMixer

    每一个MixerThread都有一个唯一对应的AudioMixer(在MixerThread中用mAudioMixer表示),它的作用如其名所表示的,就是为了完成音频的混音操作。

     

    图 13‑14 MixerThread示意图

    如上图,MixerThread对外开放的接口主要涉及到Parameter(比如setParameter)、Resampler(比如setResampler)、Volume(比如adjustVolumeRamp)、Buffer(比如setBufferProvider)及Track(比如getTrackName)五个部分。

    在内部的实现中,MixerThread的核心是一个mState变量(state_t类型),所有的混音工作都会在这个变量中体现出来——特别是其中的tracks数组,如下所示:

        struct state_t {

            uint32_t        enabledTracks;

            uint32_t        needsChanged;

            size_t          frameCount;

            void            (*hook)(state_t* state, int64_tpts);   // one of process__*, never NULL

            int32_t         *outputTemp;

            int32_t         *resampleTemp;

            int32_t         reserved[2];

            track_t         tracks[MAX_NUM_TRACKS];__attribute__((aligned(32)));

        };

    MAX_NUM_TRACKS=32,也就是说最多支持32路同时混音,这对于大部分情况肯定是足够了。数据类型track_t是对每个Track的描述,可想而知类似Parameter这种设置,最终影响的就是Track的属性。

        struct track_t {

            …

            union {

            int16_t     volume[MAX_NUM_CHANNELS];

            int32_t     volumeRL;

            };//音量相关的属性

            int32_t     prevVolume[MAX_NUM_CHANNELS];

            int32_t     volumeInc[MAX_NUM_CHANNELS];

            …

            uint8_t     channelCount; //只能是1或2

            uint8_t     format;         // 总是16

            uint16_t    enabled;        // 实际是布尔类型

            audio_channel_mask_t  channelMask;

           AudioBufferProvider*               bufferProvider;       

            mutableAudioBufferProvider::Buffer buffer; // 8 bytes

            hook_t      hook;

            const void* in; //buffer中的当前位置

            AudioResampler*     resampler;

            uint32_t            sampleRate;

            int32_t*           mainBuffer;

            int32_t*           auxBuffer;

                       …

            bool        setResampler(uint32_t sampleRate,uint32_t devSampleRate);

            bool        doesResample() const { return resampler!= NULL; }

            void        resetResampler() { if (resampler !=NULL) resampler->reset(); }

            void        adjustVolumeRamp(bool aux);

            size_t     getUnreleasedFrames() const { return resampler != NULL ?resampler->getUnreleasedFrames() : 0; };

        };

    AudioFlinger的threadLoop中,通过不断调用prepareTracks_l来准备数据,而每次prepare实际上都是对所有Track的一次调整。如果属性有变化,就会通过setParamter来告知AudioMixer。

    在上一个小节中,threadLoop_mix在内部就是通过AudioMixer来实现混音的,我们这里具体来看下:

    void AudioMixer::process(int64_t  pts)

    {

        mState.hook(&mState,pts);

    }

    “hook”是钩子的意思,为什么取这个名字?一个原因可能是hook指向的实体是变化的,就好像钩子一样,它可以灵活的依附于各种物体之上。从代码层面上看,hook是一个函数指针,它根据当前具体情况会分别指向以下几个函数实现:

    process__validate:根据当前具体情况,将hook导向下面的几个实现

    process__nop:初始化值

    process__OneTrack16BitsStereoNoResampling:只有一路Track,16比特立体声,不重采样

    process__genericNoResampling:两路(包含)以上Track,不重采样

    process__genericResampling:两路(包含)以上Track,重采样

    hook在以下几种情况下会重新赋值

    Ø  AudioMixer初始化时,hook指向process_nop

    Ø  当状态改变或者参数变化时(比如setParameter),调用invalidateState。此时hook指向process__validate

    Ø  AudioMixer::process是外部调用hook的入口

    我们以下面的图来描述一下,大家会看得更清楚些:

    图 13‑15 hook的使用

    其中process_validate的代码实现如下:

    void AudioMixer::process__validate(state_t* state, int64_t pts)

    {  …

        int countActiveTracks = 0;

        boolall16BitsStereoNoResample = true;

        bool resampling = false;…

        uint32_t en =state->enabledTracks;

        while (en) {

            const int i = 31 -__builtin_clz(en);

            en &= ~(1<<i);

            countActiveTracks++;//enabled 状态的Track计数

            …

        }

        state->hook = process__nop;

        if (countActiveTracks) {

            if (resampling) {

                …

                state->hook = process__genericResampling;

            } else {

                                       …

                state->hook = process__genericNoResampling;

                if(all16BitsStereoNoResample && !volumeRamp) {

                    if(countActiveTracks == 1) {

                       state->hook = process__OneTrack16BitsStereoNoResampling;

                    }

                }

            }

        }

       state->hook(state, pts);

       …

    }

    这个函数先通过while循环逐个分析处于enabled状态的Track,统计其内部各状态位(比如NEEDS_AUX__MASK、NEEDS_RESAMPLE__MASK等等)情况,得出countActiveTracks、resampling、volumeRamp及all16BitsStereoNoResample的合理值,最后根据这几个变量判断选择正确的hook实现,并调用这个hook函数执行具体工作。

    关于AudioMixer是如何处理音频数据的,我们将在后续音频流小节做统一分析。

  • 相关阅读:
    div+css清除浮动代码
    JavaScript for循环实现表格隔行变色
    JavaScript 四种显示数据方式
    table表格隔行变色
    table表格用tbody新属性获取DOM元素
    条形图
    子图--面向对象
    线的形状
    matplotlib--直线和点
    颜色和样式字符串
  • 原文地址:https://www.cnblogs.com/leaven/p/6077047.html
Copyright © 2011-2022 走看看