最近在做Android Audio方面的工作,有需求是在調節Volume_Up_Key & Volume_Down_key時,Spearker or Headset每音階的衰減變爲3db左右。所以利用Source Insight分析Android源碼中音量控制的流程,如有錯誤,歡迎指正,謝謝!
以下是調節音量的流程:
Step_1.首先在調節機臺Volume_Up_Key & Volume_Down_Key操作時,系統會調用到AudioManager.java中handleKeyUp & handleKeyDown函數,以 handleKeyDown函數爲例:
1 public void handleKeyDown(KeyEvent event, int stream) { 2 int keyCode = event.getKeyCode(); 3 switch (keyCode) { 4 case KeyEvent.KEYCODE_VOLUME_UP: /*KeyEvent 在KeyEvent.java中定義*/ 5 case KeyEvent.KEYCODE_VOLUME_DOWN: 6 7 int flags = FLAG_SHOW_UI | FLAG_VIBRATE; 8 9 if (mUseMasterVolume) { 10 adjustMasterVolume( 11 keyCode == KeyEvent.KEYCODE_VOLUME_UP 12 ? ADJUST_RAISE 13 : ADJUST_LOWER, 14 flags); 15 } else { 16 adjustSuggestedStreamVolume( 17 keyCode == KeyEvent.KEYCODE_VOLUME_UP 18 ? ADJUST_RAISE 19 : ADJUST_LOWER, 20 stream, 21 flags); 22 } 23 break; 24 ... ... 25 } 26 }
其中是否進入adjustMasterVolume 函數是通過mUseMasterVolume的值判斷的,而mUseMasterVolume的值是在AudioManager的構造函數中定義,其值的大小如下:mUseMasterVolume = mContext.getResources().getBoolean(com.android.internal.R.bool.config_useMasterVolume),所以首先從系統的配置文件config.xml中查找config_useMasterVolume值的大小
<bool name="config_useMasterVolume">false</bool>
所以handleKeyDown中 switch語句中會選擇進入adjustSuggestedStreamVolume函數。
1 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) { 2 IAudioService service = getService(); 3 try { 4 if (mUseMasterVolume) { 5 service.adjustMasterVolume(direction, flags, mContext.getOpPackageName()); 6 } else { 7 service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, 8 mContext.getOpPackageName()); 9 } 10 ... ... 11 } 12 }
Step_2.在adjustSuggestedStreamVolume函數中首先會通過binder機制得到AudioService,並將音量控制過程轉入到AudioService.java中。
1 public void adjustStreamVolume(int streamType, int direction, int flags, 2 String callingPackage) { 3 ... ... 4 /*音量調大時,若要超過SafeMediaVolume時,系統會彈出對話框給予確認*/ 5 if ((direction == AudioManager.ADJUST_RAISE) && 6 !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) { 7 Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex); 8 mVolumePanel.postDisplaySafeVolumeWarning(flags); 9 } else if (streamState.adjustIndex(direction * step, device)) { 10 sendMsg(mAudioHandler, 11 MSG_SET_DEVICE_VOLUME, /*需要處理的Message值*/ 12 SENDMSG_QUEUE, 13 device, 14 0, 15 streamState, 16 0); 17 } 18 } 19 int index = mStreamStates[streamType].getIndex(device); 20 sendVolumeUpdate(streamType, oldIndex, index, flags); /*通知上層更新Volume*/ 21 }
在adjustStreamVolume 中會通過sendMsg的方式來將調節音量的事件加入到消息列隊SENDMSG_QUENE中,當輪尋到該Message時,系統會調用handleMessage函數來處理該Message,此時該處對應的Message爲MSG_SET_DEVICE_VOLUME。
1 public void handleMessage(Message msg) { 2 3 switch (msg.what) { 4 5 case MSG_SET_DEVICE_VOLUME: 6 setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1); 7 break; 8 9 case MSG_SET_ALL_VOLUMES: 10 setAllVolumes((VolumeStreamState) msg.obj); 11 break; 12 13 ... ... 14 } 15 }
可以發現當msg.what = MSG_SET_DEVICE_VOLUME時,會進到setDeviceVolume函數中,繼續往下分析:
1 private void setDeviceVolume(VolumeStreamState streamState, int device) { 2 3 // Apply volume 4 streamState.applyDeviceVolume(device); 5 6 // Apply change to all streams using this one as alias 7 ... ... 8 9 // Post a persist volume msg 10 ... ... 11 }
applyDeviceVolume就是將音量Volume設置到對應的設備Device上,繼續往下分析:
1 public void applyDeviceVolume(int device) { 2 int index; 3 if (isMuted()) { 4 index = 0; 5 } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && 6 mAvrcpAbsVolSupported) { 7 index = (mIndexMax + 5)/10; 8 } else { 9 index = (getIndex(device) + 5)/10; 10 } 11 AudioSystem.setStreamVolumeIndex(mStreamType, index, device); 12 }
此處VolumeIndex就是對應UI界面調節音量時,音量所處在的位置下標。在AudioService.java中定義了每種音頻流對應的Max-Index,在AudioManager.java中定義了每種音頻流在第一次刷機後默認的Index。
Step_3.此時得到音量的下標Index後,會調用AudioSystem.java中的setStreamVolumeIndex函數中來得到此時音量的放大倍數。通過JNI層調用到AudioSystem.cpp文件中的 setStreamVolumeIndex中。
1 status_t AudioSystem::setStreamVolumeIndex(audio_stream_type_t stream, 2 int index, 3 audio_devices_t device) 4 { 5 const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); 6 if (aps == 0) return PERMISSION_DENIED; 7 return aps->setStreamVolumeIndex(stream, index, device); 8 }
setStreamVolumeIndex函數中比較簡單,通過StrongPointer來與AudioPolicyService建立聯繫,將AudioSystem中的setStreamVolumeIndex操作移到aps中完成。下面進入到AudioPolicyService.cpp文件中的setStreamVolumeIndex繼續分析:
1 status_t AudioPolicyService::setStreamVolumeIndex(audio_stream_type_t stream, 2 int index, 3 audio_devices_t device) 4 { 5 ... ... 6 if (mpAudioPolicy->set_stream_volume_index_for_device) { 7 return mpAudioPolicy->set_stream_volume_index_for_device(mpAudioPolicy, 8 stream, 9 index, 10 device); 11 } else { 12 return mpAudioPolicy->set_stream_volume_index(mpAudioPolicy, stream, index); 13 } 14 }
Step_4.AudioPolicyService.cpp作爲bn端,其對應的bp端爲AudioPolicyManagerBase.cpp。在當前函數的if語句中判斷AudioPolicyManagerBase.cpp文件中是否存在setStreamVolumeIndexForDevice函數,條件成立則會選擇setStreamVolumeIndexForDevice作爲函數入口端;否則選擇setStreamVolumeIndex作爲函數入口。現在進入AudioPolicyManagerBase.cpp中文件中完成最後的分析:
1 status_t AudioPolicyManagerBase::setStreamVolumeIndex(AudioSystem::stream_type stream, 2 int index, 3 audio_devices_t device) 4 { 5 ... ... 6 // compute and apply stream volume on all outputs according to connected device 7 status_t status = NO_ERROR; 8 for (size_t i = 0; i < mOutputs.size(); i++) { 9 audio_devices_t curDevice = 10 getDeviceForVolume(mOutputs.valueAt(i)->device()); 11 if ((device == AUDIO_DEVICE_OUT_DEFAULT) || (device == curDevice)) { 12 status_t volStatus = checkAndSetVolume(stream, index, mOutputs.keyAt(i), curDevice); 13 if (volStatus != NO_ERROR) { 14 status = volStatus; 15 } 16 } 17 } 18 return status; 19 }
繼續調用checkAndSetVolume函數:
1 status_t AudioPolicyManagerBase::checkAndSetVolume(int stream, 2 int index, 3 audio_io_handle_t output, 4 audio_devices_t device, 5 int delayMs, 6 bool force) 7 { 8 9 // do not change actual stream volume if the stream is muted 10 ... ... 11 // do not change in call volume if bluetooth is connected and vice versa 12 ... ... 13 audio_devices_t checkedDevice = (device == AUDIO_DEVICE_NONE) ? mOutputs.valueFor(output)->device() : device; 14 float volume = computeVolume(stream, index, checkedDevice); 15 16 ... ... 17 mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs);/*將得到的volume應用到對應的output中*/ 18 }
在checkAndSetVolume中可以知道volume是通過computeVolume得到的。繼續向下分析:
float AudioPolicyManagerBase::computeVolume(int stream, int index, audio_devices_t device) { ... ... volume = volIndexToAmpl(device, streamDesc, index); ... ... return volume; }
終於到了最後volIndexToAmpl,從函數名就可以知道該函數的作用是通過volIndex得到音量放大倍數。
float AudioPolicyManagerBase::volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc, int indexInUi) { device_category deviceCategory = getDeviceCategory(device); const VolumeCurvePoint *curve = streamDesc.mVolumeCurve[deviceCategory]; // the volume index in the UI is relative to the min and max volume indices for this stream type int nbSteps = 1 + curve[VOLMAX].mIndex - curve[VOLMIN].mIndex; int volIdx = (nbSteps * (indexInUi - streamDesc.mIndexMin)) / (streamDesc.mIndexMax - streamDesc.mIndexMin); // find what part of the curve this index volume belongs to, or if it's out of bounds int segment = 0; if (volIdx < curve[VOLMIN].mIndex) { // out of bounds return 0.0f; } else if (volIdx < curve[VOLKNEE1].mIndex) { segment = 0; } else if (volIdx < curve[VOLKNEE2].mIndex) { segment = 1; } else if (volIdx <= curve[VOLMAX].mIndex) { segment = 2; } else { // out of bounds return 1.0f; } // linear interpolation in the attenuation table in dB float decibels = curve[segment].mDBAttenuation + ((float)(volIdx - curve[segment].mIndex)) * ( (curve[segment+1].mDBAttenuation - curve[segment].mDBAttenuation) / ((float)(curve[segment+1].mIndex - curve[segment].mIndex)) ); float amplification = exp( decibels * 0.115129f); // exp( dB * ln(10) / 20 ) return amplification; }
其中curve代表在用設備(如SPEAKER、HEADSET & EARPIECE)播放音頻流(如SYSTEM、MUSIC、ALARM、RING & TTS等)時的音量曲線,最後decibles & amplification就是我們需要求的值,其中decibles代表某一音節所對應的dB值,而amplification則是由dB值轉化得到的音量放大倍數。這樣整個音量調節過程到此就算完成了,具體的計算分析會放在後面繼續分析。