From 14e3485272a2ca28764d916e266e17311943c245 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Thu, 9 Apr 2020 08:19:26 -0700 Subject: [PATCH] AudioService: better mic muting API behavior with errors If an error is reported when changing the microphone mute state, log it but still fire ACTION_MICROPHONE_MUTE_CHANGED intent. Make AudioManager.isMicrophoneMute() return the "real" mute state, not the intended mute state, by returning the cache of the state returned by AudioSystem whenever a change is attempted. Bug: 153103117 Test: atest AudioServiceTest Change-Id: I102f6b379eace7b396860b6f24024720fb465382 --- .../android/server/audio/AudioService.java | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index f55249e1d6f55..c7fac44077029 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -574,6 +574,8 @@ public class AudioService extends IAudioService.Stub private boolean mMicMuteFromSwitch; private boolean mMicMuteFromApi; private boolean mMicMuteFromRestrictions; + // caches the value returned by AudioSystem.isMicrophoneMuted() + private boolean mMicMuteFromSystemCached; @GuardedBy("mSettingsLock") private int mAssistantUid; @@ -934,6 +936,7 @@ public class AudioService extends IAudioService.Stub onIndicateSystemReady(); + mMicMuteFromSystemCached = AudioSystem.isMicrophoneMuted(); setMicMuteFromSwitchInput(); } @@ -1127,6 +1130,7 @@ public class AudioService extends IAudioService.Stub sendMsg(mAudioHandler, MSG_DISPATCH_AUDIO_SERVER_STATE, SENDMSG_QUEUE, 1, 0, null, 0); + setMicrophoneMuteNoCallerCheck(getCurrentUserId()); // will also update the mic mute cache setMicMuteFromSwitchInput(); } @@ -3223,12 +3227,20 @@ public class AudioService extends IAudioService.Stub } } + /** + * Returns the microphone mute state as seen from the native audio system + * @return true if microphone is reported as muted by primary HAL + */ public boolean isMicrophoneMuted() { + return mMicMuteFromSystemCached; + } + + private boolean isMicrophoneSupposedToBeMuted() { return mMicMuteFromSwitch || mMicMuteFromRestrictions || mMicMuteFromApi; } private void setMicrophoneMuteNoCallerCheck(int userId) { - final boolean muted = isMicrophoneMuted(); + final boolean muted = isMicrophoneSupposedToBeMuted(); if (DEBUG_VOL) { Log.d(TAG, String.format("Mic mute %b, user=%d", muted, userId)); } @@ -3236,7 +3248,7 @@ public class AudioService extends IAudioService.Stub if (getCurrentUserId() == userId || userId == android.os.Process.SYSTEM_UID) { final boolean currentMute = AudioSystem.isMicrophoneMuted(); final long identity = Binder.clearCallingIdentity(); - AudioSystem.muteMicrophone(muted); + final int ret = AudioSystem.muteMicrophone(muted); new MediaMetrics.Item(mAnalyticsId + "setMicrophoneMuteNoCallerCheck") .setUid(userId) @@ -3244,7 +3256,19 @@ public class AudioService extends IAudioService.Stub .putInt("currentMute", currentMute ? 1 : 0) .putLong("identity", identity) .record(); + + // update cache with the real state independently from what was set + mMicMuteFromSystemCached = AudioSystem.isMicrophoneMuted(); + if (ret != AudioSystem.AUDIO_STATUS_OK) { + Log.e(TAG, "Error changing mic mute state to " + muted + " current:" + + mMicMuteFromSystemCached); + } try { + // send the intent even if there was a failure to change the actual mute state: + // the AudioManager.setMicrophoneMute API doesn't have a return value to + // indicate if the call failed to successfully change the mute state, and receiving + // the intent may be the only time an application can resynchronize its mic mute + // state with the actual system mic mute state if (muted != currentMute) { sendMsg(mAudioHandler, MSG_BROADCAST_MICROPHONE_MUTE, SENDMSG_NOOP, 0, 0, null, 0); @@ -7154,6 +7178,10 @@ public class AudioService extends IAudioService.Stub pw.print(" mHdmiTvClient="); pw.println(mHdmiTvClient); pw.print(" mHdmiSystemAudioSupported="); pw.println(mHdmiSystemAudioSupported); pw.print(" mIsCallScreeningModeSupported="); pw.println(mIsCallScreeningModeSupported); + pw.print(" mic mute FromSwitch=" + mMicMuteFromSwitch + + " FromRestrictions=" + mMicMuteFromRestrictions + + " FromApi=" + mMicMuteFromApi + + " from system=" + mMicMuteFromSystemCached); dumpAudioPolicies(pw); mDynPolicyLogger.dump(pw);