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