Android音頻系統之AudioFlinger(四)

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是如何處理音頻數據的,我們將在後續音頻流小節做統一分析。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章