From 663a5ff13c727db9bd16bdd01b8128c712af0829 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Tue, 11 May 2021 18:02:47 -0700 Subject: [PATCH] Audio focus: tweaks for less intrusive fade outs - shorten duration of fade out from 2.5s to 2s - more aggressive fade out curve at start - do not fade out when: - focus winner has CONTENT_TYPE_SPEECH in focus request - focus loser has AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS Bug: 186685202 Test: atest AudioFocusTest Change-Id: Ic347cfa0b9f08ce24b9bb1354d1b334ef2f776fe --- .../android/server/audio/FadeOutManager.java | 31 +++++++++++++++++-- .../android/server/audio/FocusRequester.java | 2 +- .../server/audio/MediaFocusControl.java | 1 + .../server/audio/PlaybackActivityMonitor.java | 3 ++ 4 files changed, 33 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/audio/FadeOutManager.java b/services/core/java/com/android/server/audio/FadeOutManager.java index e08bd673948f8..bb627e5a21fbb 100644 --- a/services/core/java/com/android/server/audio/FadeOutManager.java +++ b/services/core/java/com/android/server/audio/FadeOutManager.java @@ -18,6 +18,7 @@ package com.android.server.audio; import android.annotation.NonNull; import android.media.AudioAttributes; +import android.media.AudioManager; import android.media.AudioPlaybackConfiguration; import android.media.VolumeShaper; import android.util.Log; @@ -35,15 +36,15 @@ public final class FadeOutManager { public static final String TAG = "AudioService.FadeOutManager"; - /*package*/ static final long FADE_OUT_DURATION_MS = 2500; + /*package*/ static final long FADE_OUT_DURATION_MS = 2000; private static final boolean DEBUG = PlaybackActivityMonitor.DEBUG; private static final VolumeShaper.Configuration FADEOUT_VSHAPE = new VolumeShaper.Configuration.Builder() .setId(PlaybackActivityMonitor.VOLUME_SHAPER_SYSTEM_FADEOUT_ID) - .setCurve(new float[]{0.f, 1.0f} /* times */, - new float[]{1.f, 0.0f} /* volumes */) + .setCurve(new float[]{0.f, 0.25f, 1.0f} /* times */, + new float[]{1.f, 0.65f, 0.0f} /* volumes */) .setOptionFlags(VolumeShaper.Configuration.OPTION_FLAG_CLOCK_TIME) .setDuration(FADE_OUT_DURATION_MS) .build(); @@ -70,6 +71,30 @@ public final class FadeOutManager { private static final VolumeShaper.Operation PLAY_SKIP_RAMP = new VolumeShaper.Operation.Builder(PLAY_CREATE_IF_NEEDED).setXOffset(1.0f).build(); + + // TODO explore whether a shorter fade out would be a better UX instead of not fading out at all + // (legacy behavior) + /** + * Determine whether the focus request would trigger a fade out, given the parameters of the + * requester and those of the focus loser + * @param requester the parameters for the focus request + * @return true if there can be a fade out over the requester starting to play + */ + static boolean canCauseFadeOut(@NonNull FocusRequester requester, + @NonNull FocusRequester loser) { + if (requester.getAudioAttributes().getContentType() == AudioAttributes.CONTENT_TYPE_SPEECH) + { + if (DEBUG) { Log.i(TAG, "not fading out: new focus is for speech"); } + return false; + } + if ((loser.getGrantFlags() & AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) != 0) { + if (DEBUG) { Log.i(TAG, "not fading out: loser has PAUSES_ON_DUCKABLE_LOSS"); } + return false; + } + + return true; + } + /** * Evaluates whether the player associated with this configuration can and should be faded out * @param apc the configuration of the player diff --git a/services/core/java/com/android/server/audio/FocusRequester.java b/services/core/java/com/android/server/audio/FocusRequester.java index cc60fe1200b12..ab8b795c52ca9 100644 --- a/services/core/java/com/android/server/audio/FocusRequester.java +++ b/services/core/java/com/android/server/audio/FocusRequester.java @@ -182,7 +182,7 @@ public class FocusRequester { return mGrantFlags; } - AudioAttributes getAudioAttributes() { + @NonNull AudioAttributes getAudioAttributes() { return mAttributes; } diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java index 03102155952df..e6c4abfa20861 100644 --- a/services/core/java/com/android/server/audio/MediaFocusControl.java +++ b/services/core/java/com/android/server/audio/MediaFocusControl.java @@ -888,6 +888,7 @@ public class MediaFocusControl implements PlayerFocusEnforcer { mEventLogger.log((new AudioEventLogger.StringEvent( "requestAudioFocus() from uid/pid " + uid + "/" + Binder.getCallingPid() + + " AA=" + aa.usageToString() + "/" + aa.contentTypeToString() + " clientId=" + clientId + " callingPack=" + callingPackageName + " req=" + focusChangeHint + " flags=0x" + Integer.toHexString(flags) diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java index e71219fd3d26f..af9a14ec80cd5 100644 --- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java +++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java @@ -707,6 +707,9 @@ public final class PlaybackActivityMonitor if (DEBUG) { Log.v(TAG, "no players to fade out"); } return false; } + if (!FadeOutManager.canCauseFadeOut(winner, loser)) { + return false; + } // check if this UID needs to be faded out (return false if not), and gather list of // eligible players to fade out final Iterator apcIterator = mPlayers.values().iterator();