Android音量設定流程乾貨版
1. 音量級數定義
在AudioService.java中定義了最大音量MAX_STREAM_VOLUME,手機的設定property可以覆蓋它。
2. 音量初始化
initStreamVolume傳入AudioPolicyManagerBase裡的StreamDescriptor mStreams[AudioSystem::NUM_STREAM_TYPES];
3. 設定主音量
主音量怎麼起作用?
最終音量=主音量*流音量
4. 設定流音量
setStreamVolumeIndex函式,在AudioPolicy中,通過volIndexToAmpl把Index整數轉為float型的振幅比,也就是“振幅/參考振幅”。
具體做法是:通過輸入的index查表找到對應的聲壓值db,然後通過下面的公式算出amplifier,這個值就是振幅比。
函式volIndexToAmpl中有一行程式碼
float amplification = exp( decibels * 0.115129f);
就是這個公式。
通過這個值乘以音源的振幅,就得到了調節後的音量。這也是數字增益調節的原理。
拿到這個值後,存入AudioFlinger的全域性變數mStreamTypes,即:mStreamTypes[stream].volume =value。
在Thread試圖播放聲音時,在prepareTracks_l中是這麼做的(AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTracks_l(
Vector< sp<Track> > *tracksToRemove)):
// 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 if (track->isPausing() || mStreamTypes[track->streamType()].mute) { vl = vr = 0; vlf = vrf = vaf = 0.; if (track->isPausing()) { track->setPaused(); } } else { // read original volumes with volume control float typeVolume = mStreamTypes[track->streamType()].volume; float v = masterVolume * typeVolume; 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; } // now apply the master volume and stream type volume vlf *= v; vrf *= v; // 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); } // Delegate volume control to effect in track effect chain if needed if (chain != 0 && chain->setVolume_l(&vl, &vr)) { // Do not ramp volume if volume is controlled by effect param = AudioMixer::VOLUME; // Update remaining floating point volume levels vlf = (float)vl / (1 << 24); vrf = (float)vr / (1 << 24); track->mHasVolumeController = true; } else { // force no volume ramp when volume controller was just disabled or removed // from effect chain to avoid volume spike if (track->mHasVolumeController) { param = AudioMixer::VOLUME; } track->mHasVolumeController = false; } // 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); mAudioMixer->setParameter( name, AudioMixer::TRACK, AudioMixer::FORMAT, (void *)track->format()); mAudioMixer->setParameter( name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK, (void *)(uintptr_t)track->channelMask()); mAudioMixer->setParameter( name, AudioMixer::TRACK, AudioMixer::MIXER_CHANNEL_MASK, (void *)(uintptr_t)mChannelMask
在系統靜音時,只是很簡單的設定下列引數為0:
vl = vr = 0;vlf = vrf = vaf = 0.
設定AudioMixer的引數
mAudioMixer->setParameter(name, param,AudioMixer::VOLUME0, &vlf);
mAudioMixer->setParameter(name, param,AudioMixer::VOLUME1, &vrf);
所以最後還是通過AudioMixer真正去乘以VOLUME0和VOLUME1來設定音量。
如track__16BitsStereo中
int32_t vl = t->prevVolume[0];
int32_t vr = t->prevVolume[1];
const int32_t vlInc =t->volumeInc[0];
const int32_t vrInc =t->volumeInc[1];
do {
*out++ += (vl >> 16) *(int32_t) *in++;
*out++ += (vr >> 16) *(int32_t) *in++;
vl += vlInc;
vr += vrInc;
} while (--frameCount);