Android 4.4音量键控制音量流程
1、在AudioManager.java中的handleKeyDown函数中接收音量键的按键消息
public void handleKeyDown(KeyEvent event, int stream) {
int keyCode = event.getKeyCode();
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
/*
* Adjust the volume in on key down since it is more
* responsive to the user.
*/
int flags = FLAG_SHOW_UI | FLAG_VIBRATE;
if (mUseMasterVolume) {
adjustMasterVolume(
keyCode == KeyEvent.KEYCODE_VOLUME_UP
? ADJUST_RAISE
: ADJUST_LOWER,
flags);
} else {
adjustSuggestedStreamVolume(
keyCode == KeyEvent.KEYCODE_VOLUME_UP
? ADJUST_RAISE
: ADJUST_LOWER,
stream,
flags);
}
break;
case KeyEvent.KEYCODE_VOLUME_MUTE:
if (event.getRepeatCount() == 0) {
if (mUseMasterVolume) {
setMasterMute(!isMasterMute());
} else {
// TODO: Actually handle MUTE.
}
}
break;
}
}
2、根据音量键调节走else分支,进入adjustSuggestedStreamVolume函数中
public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
IAudioService service = getService();
Log.d(TAG, "adjustSuggestedStreamVolume: Direction = " + direction
+ ", streamType = " + suggestedStreamType);
try {
if (mUseMasterVolume) {
service.adjustMasterVolume(direction, flags, mContext.getOpPackageName());
} else {
service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags,
mContext.getOpPackageName());
}
} catch (RemoteException e) {
Log.e(TAG, "Dead object in adjustSuggestedStreamVolume", e);
}
}
3、进入AudioService.java中的adjustSuggestedStreamVolume函数中
public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
String callingPackage) {
if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType+" direction ="+direction+" flags="+flags);
int streamType;
Log.d(TAG, "adjustSuggestedStreamVolume() mVolumeControlStream="+mVolumeControlStream);
if (mVolumeControlStream != -1) {
streamType = mVolumeControlStream;
Log.d(TAG, "adjustSuggestedStreamVolume() getMode()="+getMode());
Log.d(TAG, "adjustSuggestedStreamVolume() AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) ="+AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0));
Log.d(TAG, "adjustSuggestedStreamVolume() AudioSystem.isStreamActive(AudioSystem.STREAM_VOICE_CALL, 0) ="+AudioSystem.isStreamActive(AudioSystem.STREAM_VOICE_CALL, 0));
} else {
streamType = getActiveStreamType(suggestedStreamType);
}
Log.d(TAG, "adjustSuggestedStreamVolume() streamType2="+streamType);
// Play sounds on STREAM_RING only and if lock screen is not on.
if ((streamType != STREAM_REMOTE_MUSIC) &&
(flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
((mStreamVolumeAlias[streamType] != AudioSystem.STREAM_RING)
|| (mKeyguardManager != null && mKeyguardManager.isKeyguardLocked()))) {
flags &= ~AudioManager.FLAG_PLAY_SOUND;
}
if (streamType == STREAM_REMOTE_MUSIC) {
// don't play sounds for remote
flags &= ~(AudioManager.FLAG_PLAY_SOUND|AudioManager.FLAG_FIXED_VOLUME);
//if (DEBUG_VOL) Log.i(TAG, "Need to adjust remote volume: calling adjustRemoteVolume()");
mMediaFocusControl.adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, flags);
} else {
adjustStreamVolume(streamType, direction, flags, callingPackage);
}
}
4、进入adjustStreamVolume函数中
/** @see AudioManager#adjustStreamVolume(int, int, int) */
public void adjustStreamVolume(int streamType, int direction, int flags,
String callingPackage) {
if (mUseFixedVolume) {
return;
}
if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction);
ensureValidDirection(direction);
ensureValidStreamType(streamType);
Log.v(TAG,"adjustStreamVolume streamType1 : "+streamType);
// use stream type alias here so that streams with same alias have the same behavior,
// including with regard to silent mode control (e.g the use of STREAM_RING below and in
// checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
int streamTypeAlias = mStreamVolumeAlias[streamType];
VolumeStreamState streamState = mStreamStates[streamTypeAlias];
final int device = getDeviceForStream(streamTypeAlias);
Log.v(TAG,"adjustStreamVolume streamTypeAlias : "+streamTypeAlias+" device:"+device);
int aliasIndex = streamState.getIndex(device);
boolean adjustVolume = true;
int step;
// skip a2dp absolute volume control request when the device
// is not an a2dp device
if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
(flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
return;
}
if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
callingPackage) != AppOpsManager.MODE_ALLOWED) {
return;
}
// reset any pending volume command
synchronized (mSafeMediaVolumeState) {
mPendingVolumeCommand = null;
}
flags &= ~AudioManager.FLAG_FIXED_VOLUME;
if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
((device & mFixedVolumeDevices) != 0)) {
flags |= AudioManager.FLAG_FIXED_VOLUME;
// Always toggle between max safe volume and 0 for fixed volume devices where safe
// volume is enforced, and max and 0 for the others.
// This is simulated by stepping by the full allowed volume range
if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
(device & mSafeMediaVolumeDevices) != 0) {
step = mSafeMediaVolumeIndex;
} else {
step = streamState.getMaxIndex();
}
if (aliasIndex != 0) {
aliasIndex = step;
}
} else {
// convert one UI step (+/-1) into a number of internal units on the stream alias
step = rescaleIndex(10, streamType, streamTypeAlias);
}
// If either the client forces allowing ringer modes for this adjustment,
// or the stream type is one that is affected by ringer modes
if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
(streamTypeAlias == getMasterStreamType())) {
int ringerMode = getRingerMode();
// do not vibrate if already in vibrate mode
if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
flags &= ~AudioManager.FLAG_VIBRATE;
}
// Check if the ringer mode changes with this volume adjustment. If
// it does, it will handle adjusting the volume, so we won't below
adjustVolume = checkForRingerModeChange(aliasIndex, direction, step);
}
int oldIndex = mStreamStates[streamType].getIndex(device);
if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
// Check if volume update should be send to AVRCP
if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
(device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
(flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
synchronized (mA2dpAvrcpLock) {
if (mA2dp != null && mAvrcpAbsVolSupported) {
mA2dp.adjustAvrcpAbsoluteVolume(direction);
}
}
}
if ((direction == AudioManager.ADJUST_RAISE) &&
!checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex);
mVolumePanel.postDisplaySafeVolumeWarning(flags);
} else if (streamState.adjustIndex(direction * step, device)) {
// Post message to set system volume (it in turn will post a message
// to persist). Do not change volume if stream is muted.
sendMsg(mAudioHandler,
MSG_SET_DEVICE_VOLUME,
SENDMSG_QUEUE,
device,
0,
streamState,
0);
}
}
int index = mStreamStates[streamType].getIndex(device);
sendVolumeUpdate(streamType, oldIndex, index, flags);
}
在sendMsg发送Message进入handler中处理,调用setDeviceVolume函数
private void setDeviceVolume(VolumeStreamState streamState, int device) {
// Apply volume
streamState.applyDeviceVolume(device);
// Apply change to all streams using this one as alias
int numStreamTypes = AudioSystem.getNumStreamTypes();
for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
if (streamType != streamState.mStreamType &&
mStreamVolumeAlias[streamType] == streamState.mStreamType) {
// Make sure volume is also maxed out on A2DP device for aliased stream
// that may have a different device selected
int streamDevice = getDeviceForStream(streamType);
if ((device != streamDevice) && mAvrcpAbsVolSupported &&
((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
mStreamStates[streamType].applyDeviceVolume(device);
}
mStreamStates[streamType].applyDeviceVolume(streamDevice);
}
}
// Post a persist volume msg
sendMsg(mAudioHandler,
MSG_PERSIST_VOLUME,
SENDMSG_QUEUE,
device,
0,
streamState,
PERSIST_DELAY);
}
调用applyDeviceVolume函数
public void applyDeviceVolume(int device) {
int index;
if (isMuted()) {
index = 0;
} else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
mAvrcpAbsVolSupported) {
index = (mIndexMax + 5)/10;
} else {
index = (getIndex(device) + 5)/10;
}
Log.d(TAG,"applyDeviceVolume index:"+index + " mStreamType:" + mStreamType + ",device:" + device);
AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
}
5、调用AudioSystem.java中的setStreamVolumeIndex函数
public static native int setStreamVolumeIndex(int stream, int index, int device);
6、调用AudioSystem.cpp函数中的setStreamVolumeIndex
status_t AudioSystem::setStreamVolumeIndex(audio_stream_type_t stream,
int index,
audio_devices_t device)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return PERMISSION_DENIED;
return aps->setStreamVolumeIndex(stream, index, device);
}
7、调用AudioPolicyService.cpp中的setStreamVolumeIndex
status_t AudioPolicyService::setStreamVolumeIndex(audio_stream_type_t stream,
int index,
audio_devices_t device)
{
ALOGD("AudioPolicyService::setStreamVolumeIndex");
if (mpAudioPolicy == NULL) {
return NO_INIT;
}
if (!settingsAllowed()) {
return PERMISSION_DENIED;
}
if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
return BAD_VALUE;
}
Mutex::Autolock _l(mLock);
if (mpAudioPolicy->set_stream_volume_index_for_device) {
ALOGD("mpAudioPolicy->set_stream_volume_index_for_device");
return mpAudioPolicy->set_stream_volume_index_for_device(mpAudioPolicy,
stream,
index,
device);
} else {
ALOGD("mpAudioPolicy->set_stream_volume_index");
return mpAudioPolicy->set_stream_volume_index(mpAudioPolicy, stream, index);
}
}
8、调用AudioMTKPolicyManager.cpp中的setStreamVolumeIndex函数
status_t AudioMTKPolicyManager::setStreamVolumeIndex(AudioSystem::stream_type stream,
int index,
audio_devices_t device)
{
ALOGD("AudioMTKPolicyManager setStreamVolumeIndex stream = %d index = %d device = 0x%x",stream,index,device);
if ((index < mStreams[stream].mIndexMin) || (index > mStreams[stream].mIndexMax)) {
return BAD_VALUE;
}
if (!audio_is_output_device(device)) {
return BAD_VALUE;
}
// Force max volume if stream cannot be muted
if (!mStreams[stream].mCanBeMuted) index = mStreams[stream].mIndexMax;
ALOGV("setStreamVolumeIndex() stream %d, device %04x, index %d",
stream, device, index);
// if device is AUDIO_DEVICE_OUT_DEFAULT set default value and
// clear all device specific values
if (device == AUDIO_DEVICE_OUT_DEFAULT) {
mStreams[stream].mIndexCur.clear();
}
mStreams[stream].mIndexCur.add(device, index);
#ifdef MTK_AUDIO
#ifdef MTK_AUDIO_GAIN_TABLE
mAudioUCM->setStreamVolIndex(stream,index,device);
#endif
#endif
// compute and apply stream volume on all outputs according to connected device
status_t status = NO_ERROR;
for (size_t i = 0; i < mOutputs.size(); i++) {
audio_devices_t curDevice =
getDeviceForVolume(mOutputs.valueAt(i)->device());
if ((device == AUDIO_DEVICE_OUT_DEFAULT) || (device == curDevice)) {
#ifdef MTK_AUDIO
status_t volStatus;
// alps00053099 adjust matv volume when record sound stoping, matv sound will out through speaker.
// delay -1 to put this volume command at the end of command queue in audiopolicy service
if(stream ==AudioSystem::MATV &&(mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET ||mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE))
{
volStatus =checkAndSetVolume(stream, index, mOutputs.keyAt(i), curDevice,-1);
}
else
{
volStatus =checkAndSetVolume(stream, index, mOutputs.keyAt(i), curDevice);
}
#else
status_t volStatus = checkAndSetVolume(stream, index, mOutputs.keyAt(i), curDevice);
#endif
if (volStatus != NO_ERROR) {
status = volStatus;
}
}
}
return status;
}
9、真正设置是在checkAndSetVolume函数中执行
status_t AudioMTKPolicyManager::checkAndSetVolume(int stream,
int index,
audio_io_handle_t output,
audio_devices_t device,
int delayMs,
bool force)
{
ALOGD(" checkAndSetVolume stream = %d index = %d output = %d device = 0x%x delayMs = %d force = %d"
,stream,index,output,device,delayMs,force);
// do not change actual stream volume if the stream is muted
if (mOutputs.valueFor(output)->mMuteCount[stream] != 0) {
ALOGVV("checkAndSetVolume() stream %d muted count %d",
stream, mOutputs.valueFor(output)->mMuteCount[stream]);
return NO_ERROR;
}
// do not change in call volume if bluetooth is connected and vice versa
if ((stream == AudioSystem::VOICE_CALL && mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) ||
(stream == AudioSystem::BLUETOOTH_SCO && mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO)) {
ALOGD("checkAndSetVolume() cannot set stream %d volume with force use = %d for comm",
stream, mForceUse[AudioSystem::FOR_COMMUNICATION]);
return INVALID_OPERATION;
}
float volume = computeVolume(stream, index, output, device);
ALOGD("checkAndSetVolume volume = %f stream=%d device=%d",volume,stream,device);
#ifdef MTK_AUDIO
#ifdef MTK_AUDIO_GAIN_TABLE
updateAnalogVolume(output,device,delayMs);
#endif
#endif
#ifdef MTK_AUDIO
//for VT notify tone when incoming call. it's volume will be adusted in hardware.
if((stream == AudioSystem::VOICE_CALL ||stream == AudioSystem::BLUETOOTH_SCO) && mOutputs.valueFor(output)->mRefCount[stream]!=0 && mPhoneState==AudioSystem::MODE_IN_CALL)
{
volume =1.0;
}
// ALPS00554824 KH: If notifiaction is exist, FM should be mute
if ((stream == AudioSystem::FM) &&
(mOutputs.valueFor(output)->mRefCount[AudioSystem::NOTIFICATION]
|| mOutputs.valueFor(output)->mRefCount[AudioSystem::RING]
|| mOutputs.valueFor(output)->mRefCount[AudioSystem::ALARM]))
{
volume =0.0;
}
// ALPS001125976 Mute music at ringtone from BT to primary
//if ( (stream == AudioSystem::MUSIC) && (mPhoneState ==AudioSystem::MODE_RINGTONE) && (mStreams[AudioSystem::RING].getVolumeIndex(device)!=mStreams[AudioSystem::RING].mIndexMin) ) {
// volume =0.0;
//}
#endif
//ALOGD("checkAndSetVolume newvolume %f, oldvolume %f,output %d",volume,mOutputs.valueFor(output)->mCurVolume[stream],output);
// We actually change the volume if:
// - the float value returned by computeVolume() changed
// - the force flag is set
if (volume != mOutputs.valueFor(output)->mCurVolume[stream] ||
force
#ifdef MTK_AUDIO
||(stream==AudioSystem::FM && output==mPrimaryOutput && (device == AUDIO_DEVICE_OUT_WIRED_HEADSET ||device == AUDIO_DEVICE_OUT_WIRED_HEADPHONE) )//WFD output can't affect HwGain,however affect mFmVolume . But PrimaryOutput will use mFmVolume setting
#endif
) {
#ifdef MTK_AUDIO
int bSetStreamVolume=1;
//Overall, Don't set volume to affect direct mode volume setting if the later routing is still direct mode . HoChi . This is very tricky that WFD support FM,others(BT/...) don't.
#ifdef MATV_AUDIO_SUPPORT
if( matv_use_analog_input == true){
if((stream==AudioSystem::MATV)&&(output!=mPrimaryOutput||device==AUDIO_DEVICE_NONE)&&device!=AUDIO_DEVICE_OUT_REMOTE_SUBMIX){
bSetStreamVolume=0; //MATV with line-in path is only ouput from primaryoutput
}
}
#endif
//Add device==AUDIO_DEVICE_NONE for ALPS
if((stream==AudioSystem::FM)&&(output!=mPrimaryOutput||device==AUDIO_DEVICE_NONE)&&device!=AUDIO_DEVICE_OUT_REMOTE_SUBMIX){
bSetStreamVolume=0; //FM with line-in path is only ouput from primaryoutput
}
if(bSetStreamVolume==1)
{
#endif
mOutputs.valueFor(output)->mCurVolume[stream] = volume;
ALOGD("checkAndSetVolume() for output %d stream %d, volume %f, delay %d", output, stream, volume, delayMs);
// Force VOICE_CALL to track BLUETOOTH_SCO stream volume when bluetooth audio is
// enabled
if (stream == AudioSystem::BLUETOOTH_SCO) {
mpClientInterface->setStreamVolume(AudioSystem::VOICE_CALL, volume, output, delayMs);
}
mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs);
#ifdef MTK_AUDIO
}
else
{
ALOGD("skip setStreamVolume for output %d stream %d, volume %f, delay %d",output, stream, volume, delayMs);
}
#endif
}
ALOGD("checkAndSetVolume() for output %d stream %d, volume %f, delay %d, loc 2", output, stream, volume, delayMs);
if (stream == AudioSystem::VOICE_CALL ||
stream == AudioSystem::BLUETOOTH_SCO) {
float voiceVolume;
// Force voice volume to max for bluetooth SCO as volume is managed by the headset
if (stream == AudioSystem::VOICE_CALL) {
#ifdef MTK_AUDIO
#ifndef MTK_AUDIO_GAIN_TABLE
voiceVolume = computeCustomVoiceVolume(stream, index, output, device);
#endif
#else
voiceVolume = (float)index/(float)mStreams[stream].mIndexMax;
#endif
} else {
voiceVolume = 1.0;
}
ALOGD("checkAndSetVolume() voiceVolume %f mLastVoiceVolume %f mPrimaryOutput %d output %d",voiceVolume, mLastVoiceVolume,mPrimaryOutput,output);
if (voiceVolume != mLastVoiceVolume && output == mPrimaryOutput) {
mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
#ifdef MTK_AUDIO
#ifdef EVDO_DT_SUPPORT
ALOGD("SetVoiceVolumeIndex=%d %f,%f,%d", index, voiceVolume, mLastVoiceVolume, output == mPrimaryOutput);
//set Volume Index ( for external modem)
AudioParameter param = AudioParameter();
param.addInt(String8("SetVoiceVolumeIndex"), index);
mpClientInterface->setParameters (0 , param.toString(), 0);
#endif
#endif
mLastVoiceVolume = voiceVolume;
}
}
return NO_ERROR;
}
if (voiceVolume != mLastVoiceVolume && output == mPrimaryOutput) {
mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
#ifdef MTK_AUDIO
#ifdef EVDO_DT_SUPPORT
ALOGD("SetVoiceVolumeIndex=%d %f,%f,%d", index, voiceVolume, mLastVoiceVolume, output == mPrimaryOutput);
//set Volume Index ( for external modem)
AudioParameter param = AudioParameter();
param.addInt(String8("SetVoiceVolumeIndex"), index);
mpClientInterface->setParameters (0 , param.toString(), 0);
#endif
#endif
mLastVoiceVolume = voiceVolume;
}
函数中经过判断本次音量与上次音量的比较 以及输出设备的比较正确的话,设置到底层
其中之前音量的设置会经过多次的计算,与音频参数等的计算
一花一世界,一叶一菩提;一方一净土,一水一浮生;一草一天堂,一沙一极乐;一笑一尘缘,一觉一清净