Android(安卓)P按键静音流程
今天跟了一下Android系统按键静音的流程,Android实现了在系统层面静音。输出给底层的音量为0。
按键使用注入按键方式实现,静音按键值:
public static final int KEYCODE_VOLUME_MUTE = 164;
注入方式:
KeyEvent k = new KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_VOLUME_MUTE);InputManager.getInstance().injectInputEvent(key, 0);
或者:
simulateKey(KeyEvent.KEYCODE_VOLUME_MUTE);public static void simulateKey(final int KeyCode) { new Thread() { @Override public void run() { try { Instrumentation inst = new Instrumentation(); inst.sendKeyDownUpSync(KeyCode); } catch (Exception e) { Log.e("hello", e.toString()); } } }.start();}
调用流程:
DecorView.java --> PhoneWindow.java --> MediaSessionService.java
窗口监听Key消息的过程省略过,在Input输入系统中已经分析过。
\frameworks\base\services\core\java\com\android\server\media\MediaSessionService.java
dispatchVolumeKeyEvent()
dispatchVolumeKeyEventLocked()
\frameworks\base\services\core\java\com\android\server\audio\AudioService.java
adjustSuggestedStreamVolume()
private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags, String callingPackage, String caller, int uid) { //省略一部分代码 //...// mute为true final boolean isMute = isMuteAdjust(direction); ensureValidStreamType(streamType); final int resolvedStream = mStreamVolumeAlias[streamType]; // Play sounds on STREAM_RING only. if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 && resolvedStream != AudioSystem.STREAM_RING) { flags &= ~AudioManager.FLAG_PLAY_SOUND; } // For notifications/ring, show the ui before making any adjustments // Don't suppress mute/unmute requests if (mVolumeController.suppressAdjustment(resolvedStream, flags, isMute)) { direction = 0; flags &= ~AudioManager.FLAG_PLAY_SOUND; flags &= ~AudioManager.FLAG_VIBRATE; if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment"); } adjustStreamVolume(streamType, direction, flags, callingPackage, caller, uid);}protected void adjustStreamVolume(int streamType, int direction, int flags, String callingPackage, String caller, int uid) { //省略一部分代码 //... //省略一部分代码 //...if (isMuteAdjust) { boolean state; if (direction == AudioManager.ADJUST_TOGGLE_MUTE) { state = !streamState.mIsMuted; } else { state = direction == AudioManager.ADJUST_MUTE; } if (streamTypeAlias == AudioSystem.STREAM_MUSIC) { setSystemAudioMute(state); } for (int stream = 0; stream < mStreamStates.length; stream++) { if (streamTypeAlias == mStreamVolumeAlias[stream]) { if (!(readCameraSoundForced() && (mStreamStates[stream].getStreamType() == AudioSystem.STREAM_SYSTEM_ENFORCED))) { mStreamStates[stream].mute(state); } } } } //省略一部分代码 //... //省略一部分代码 //...}
通过调用 mStreamStates[stream].mute(state);来做stream mute.
public void mute(boolean state) { boolean changed = false; synchronized (VolumeStreamState.class) { if (state != mIsMuted) { changed = true; mIsMuted = state; // Set the new mute volume. This propagates the values to // the audio system, otherwise the volume won't be changed // at the lower level. sendMsg(mAudioHandler, MSG_SET_ALL_VOLUMES, SENDMSG_QUEUE, 0, 0, this, 0); } } if (changed) { // Stream mute changed, fire the intent. Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION); intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType); intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state); sendBroadcastToAll(intent); } }
通过发送MSG_SET_ALL_VOLUMES消息,告知Audio System处理音量,降到最低。
@Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_SET_DEVICE_VOLUME: setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1); break; case MSG_SET_ALL_VOLUMES: setAllVolumes((VolumeStreamState) msg.obj); break; } private void setAllVolumes(VolumeStreamState streamState) { // Apply volume streamState.applyAllVolumes(); // 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) { mStreamStates[streamType].applyAllVolumes(); } } } public void applyAllVolumes() { synchronized (VolumeStreamState.class) { // apply device specific volumes first int index; for (int i = 0; i < mIndexMap.size(); i++) { final int device = mIndexMap.keyAt(i); if (device != AudioSystem.DEVICE_OUT_DEFAULT) { if (mIsMuted) { index = 0; } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported) { index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10); } else if ((device & mFullVolumeDevices) != 0) { index = (mIndexMax + 5)/10; } else if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) { index = (mIndexMax + 5)/10; } else { //index = (mIndexMap.valueAt(i) + 5)/10; index = (mIndexMax+5)/10;//fixed system volume(zhuqiang2019.1.2) } AudioSystem.setStreamVolumeIndex(mStreamType, index, device); } } // apply default volume last: by convention , default device volume will be used // by audio policy manager if no explicit volume is present for a given device type if (mIsMuted) { index = 0; } else { index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10; } if(mUseFixedVolume) { index = (mIndexMax+5)/10;//fixed system volume(zhuqiang2019.1.2) } AudioSystem.setStreamVolumeIndex( mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT); } }
关键代码:AudioSystem.setStreamVolumeIndex( mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
\frameworks\av\media\libaudioclient\AudioSystem.cpp
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);}
frameworks\av\services\audiopolicy\managerdefault\AudioPolicyManager.cpp
status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream, int index, audio_devices_t device){ // VOICE_CALL stream has minVolumeIndex > 0 but can be muted directly by an // app that has MODIFY_PHONE_STATE permission. if (((index < mVolumeCurves->getVolumeIndexMin(stream)) && !(stream == AUDIO_STREAM_VOICE_CALL && index == 0)) || (index > mVolumeCurves->getVolumeIndexMax(stream))) { return BAD_VALUE; } if (!audio_is_output_device(device)) { return BAD_VALUE; } // Force max volume if stream cannot be muted if (!mVolumeCurves->canBeMuted(stream)) index = mVolumeCurves->getVolumeIndexMax(stream); ALOGV("setStreamVolumeIndex() stream %d, device %08x, index %d", stream, device, index); // update other private stream volumes which follow this one for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT; curStream++) { if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) { continue; } mVolumeCurves->addCurrentVolumeIndex((audio_stream_type_t)curStream, device, index); } // update volume on all outputs and streams matching the following: // - The requested stream (or a stream matching for volume control) is active on the output // - The device (or devices) selected by the strategy corresponding to this stream includes // the requested device // - For non default requested device, currently selected device on the output is either the // requested device or one of the devices selected by the strategy // - For default requested device (AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME), apply volume only if // no specific device volume value exists for currently selected device. status_t status = NO_ERROR; for (size_t i = 0; i < mOutputs.size(); i++) { sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i); audio_devices_t curDevice = Volume::getDeviceForVolume(desc->device()); for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT; curStream++) { if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) { continue; } if (!(desc->isStreamActive((audio_stream_type_t)curStream) || (isInCall() && (curStream == AUDIO_STREAM_VOICE_CALL)))) { continue; } routing_strategy curStrategy = getStrategy((audio_stream_type_t)curStream); audio_devices_t curStreamDevice = Volume::getDeviceForVolume(getDeviceForStrategy( curStrategy, false /*fromCache*/)); if ((device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) && ((curStreamDevice & device) == 0)) { continue; } bool applyVolume; if (device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) { curStreamDevice |= device; applyVolume = (curDevice & curStreamDevice) != 0; } else { applyVolume = !mVolumeCurves->hasVolumeIndexForDevice( stream, curStreamDevice); } if (applyVolume) { //FIXME: workaround for truncated touch sounds // delayed volume change for system stream to be removed when the problem is // handled by system UI status_t volStatus = checkAndSetVolume((audio_stream_type_t)curStream, index, desc, curDevice, (stream == AUDIO_STREAM_SYSTEM) ? TOUCH_SOUND_FIXED_DELAY_MS : 0); if (volStatus != NO_ERROR) { status = volStatus; } } } } return status;}status_t AudioPolicyManager::checkAndSetVolume(audio_stream_type_t stream, int index, const sp<AudioOutputDescriptor>& outputDesc, audio_devices_t device, int delayMs, bool force){ // do not change actual stream volume if the stream is muted if (outputDesc->mMuteCount[stream] != 0) { ALOGVV("checkAndSetVolume() stream %d muted count %d", stream, outputDesc->mMuteCount[stream]); return NO_ERROR; } audio_policy_forced_cfg_t forceUseForComm = mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION); // do not change in call volume if bluetooth is connected and vice versa if ((stream == AUDIO_STREAM_VOICE_CALL && forceUseForComm == AUDIO_POLICY_FORCE_BT_SCO) || (stream == AUDIO_STREAM_BLUETOOTH_SCO && forceUseForComm != AUDIO_POLICY_FORCE_BT_SCO)) { ALOGV("checkAndSetVolume() cannot set stream %d volume with force use = %d for comm", stream, forceUseForComm); return INVALID_OPERATION; } if (device == AUDIO_DEVICE_NONE) { device = outputDesc->device(); } float volumeDb = computeVolume(stream, index, device); if (outputDesc->isFixedVolume(device) || // Force VoIP volume to max for bluetooth SCO ((stream == AUDIO_STREAM_VOICE_CALL || stream == AUDIO_STREAM_BLUETOOTH_SCO) && (device & AUDIO_DEVICE_OUT_ALL_SCO) != 0)) { volumeDb = 0.0f; } outputDesc->setVolume(volumeDb, stream, device, delayMs, force); if (stream == AUDIO_STREAM_VOICE_CALL || stream == AUDIO_STREAM_BLUETOOTH_SCO) { float voiceVolume; // Force voice volume to max for bluetooth SCO as volume is managed by the headset if (stream == AUDIO_STREAM_VOICE_CALL) { voiceVolume = (float)index/(float)mVolumeCurves->getVolumeIndexMax(stream); } else { voiceVolume = 1.0; } if (voiceVolume != mLastVoiceVolume) { mpClientInterface->setVoiceVolume(voiceVolume, delayMs); mLastVoiceVolume = voiceVolume; } } return NO_ERROR;}
打印:
2020-06-13 16:17:18.136 2523-4902/? V/APM::AudioOutputDescriptor: setVolume() for stream 3, volume -758.000000, delay 0
2020-06-13 16:17:26.360 2523-2684/? V/APM::AudioOutputDescriptor: setVolume() for stream 3, volume 0.000000, delay 0
2020-06-13 16:17:28.369 2523-2684/? V/APM::AudioOutputDescriptor: setVolume() for stream 3, volume -758.000000, delay 0
Mute时,volume 为-758.000000
更多相关文章
- TextView过长显示省略号, TextView文字中间加横线
- android 透明效果
- Android(安卓)Edittext设置负数以及小数
- 几款好用的Android(安卓)Studio插件
- TextView添加ClickableSpan和LinkMovementMethod之间的关系
- android中的提示信息显示方法(toast应用)
- Android实现widget定时更新
- Android(安卓)中使用OpenGL ES进行2D开发(GLSurfaceView)
- Android应用实例之----基于Service与ContentProvider的音乐播放