最近在做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值的大小
false</bool>
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 }
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;
}
播放音频流(如SYSTEM、MUSIC、ALARM、RING & TTS等)时的音量曲线,最后decibles & amplification就是我们需要求的值,其中decibles代表某一音节所对应的dB值,而amplification则是由dB值转化得到的音量放大倍数。这样整个音量调节过程到此就算完成了,具体的计算分析会放在后面继续分析。