OSDN Git Service

Audio focus: start players in ducked state when focus is already lost
authorJean-Michel Trivi <jmtrivi@google.com>
Wed, 17 May 2017 00:59:54 +0000 (17:59 -0700)
committerJean-Michel Trivi <jmtrivi@google.com>
Thu, 18 May 2017 16:50:44 +0000 (16:50 +0000)
The volume ramp for ducking is only to be heard when a player is
  playing while focus is lost. When a player is starting when
  focus is already lost (and ducking is applicable), it should
  play at the same level as that reached after a duck. This is
  implemented using the VolumeShaper.Operation time offset
  (a.k.a. XOffset), set to 1, i.e. the end of the duck.

Test: see bug
Bug: 38353147
Change-Id: Iec36fbe002b183d6d70c258d9ab26b577dc1d2ce

services/core/java/com/android/server/audio/PlaybackActivityMonitor.java

index dcd58e7..702cbbe 100644 (file)
@@ -67,6 +67,10 @@ public final class PlaybackActivityMonitor
                     .createIfNeeded()
                     .build();
 
+    // like a PLAY_CREATE_IF_NEEDED operation but with a skip to the end of the ramp
+    private static final VolumeShaper.Operation PLAY_SKIP_RAMP =
+            new VolumeShaper.Operation.Builder(PLAY_CREATE_IF_NEEDED).setXOffset(1.0f).build();
+
     private final ArrayList<PlayMonitorClient> mClients = new ArrayList<PlayMonitorClient>();
     // a public client is one that needs an anonymized version of the playback configurations, we
     // keep track of whether there is at least one to know when we need to create the list of
@@ -487,17 +491,19 @@ public final class PlaybackActivityMonitor
     private static final class DuckingManager {
         private final HashMap<Integer, DuckedApp> mDuckers = new HashMap<Integer, DuckedApp>();
 
-        void duckUid(int uid, ArrayList<AudioPlaybackConfiguration> apcsToDuck) {
+        synchronized void duckUid(int uid, ArrayList<AudioPlaybackConfiguration> apcsToDuck) {
+            if (DEBUG) {  Log.v(TAG, "DuckingManager: duckUid() uid:"+ uid); }
             if (!mDuckers.containsKey(uid)) {
                 mDuckers.put(uid, new DuckedApp(uid));
             }
             final DuckedApp da = mDuckers.get(uid);
             for (AudioPlaybackConfiguration apc : apcsToDuck) {
-                da.addDuck(apc);
+                da.addDuck(apc, false /*skipRamp*/);
             }
         }
 
-        void unduckUid(int uid, HashMap<Integer, AudioPlaybackConfiguration> players) {
+        synchronized void unduckUid(int uid, HashMap<Integer, AudioPlaybackConfiguration> players) {
+            if (DEBUG) {  Log.v(TAG, "DuckingManager: unduckUid() uid:"+ uid); }
             final DuckedApp da = mDuckers.remove(uid);
             if (da == null) {
                 return;
@@ -506,25 +512,27 @@ public final class PlaybackActivityMonitor
         }
 
         // pre-condition: apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED
-        void checkDuck(@NonNull AudioPlaybackConfiguration apc) {
+        synchronized void checkDuck(@NonNull AudioPlaybackConfiguration apc) {
+            if (DEBUG) {  Log.v(TAG, "DuckingManager: checkDuck() player piid:"
+                    + apc.getPlayerInterfaceId()+ " uid:"+ apc.getClientUid()); }
             final DuckedApp da = mDuckers.get(apc.getClientUid());
             if (da == null) {
                 return;
             }
-            // FIXME here the player needs to be put in a state that is the same as if it
-            //   had been ducked as it starts. At the moment, this works already for linked
-            //   players, as is the case in gapless playback.
-            da.addDuck(apc);
+            da.addDuck(apc, true /*skipRamp*/);
         }
 
-        void dump(PrintWriter pw) {
+        synchronized void dump(PrintWriter pw) {
             for (DuckedApp da : mDuckers.values()) {
                 da.dump(pw);
             }
         }
 
-        void removeReleased(@NonNull AudioPlaybackConfiguration apc) {
-            final DuckedApp da = mDuckers.get(apc.getClientUid());
+        synchronized void removeReleased(@NonNull AudioPlaybackConfiguration apc) {
+            final int uid = apc.getClientUid();
+            if (DEBUG) {  Log.v(TAG, "DuckingManager: removedReleased() player piid: "
+                    + apc.getPlayerInterfaceId() + " uid:" + uid); }
+            final DuckedApp da = mDuckers.get(uid);
             if (da == null) {
                 return;
             }
@@ -550,20 +558,21 @@ public final class PlaybackActivityMonitor
             // pre-conditions:
             //  * apc != null
             //  * apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED
-            void addDuck(@NonNull AudioPlaybackConfiguration apc) {
+            void addDuck(@NonNull AudioPlaybackConfiguration apc, boolean skipRamp) {
                 final int piid = new Integer(apc.getPlayerInterfaceId());
                 if (mDuckedPlayers.contains(piid)) {
-                    if (DEBUG) { Log.v(TAG, "player " + piid + " already ducked"); }
+                    if (DEBUG) { Log.v(TAG, "player piid:" + piid + " already ducked"); }
                     return;
                 }
                 try {
-                    Log.v(TAG, "ducking player " + apc.getPlayerInterfaceId() + " uid:" + mUid);
+                    Log.v(TAG, "ducking (skipRamp=" + skipRamp + ") player piid:"
+                            + apc.getPlayerInterfaceId() + " uid:" + mUid);
                     apc.getPlayerProxy().applyVolumeShaper(
                             DUCK_VSHAPE,
-                            PLAY_CREATE_IF_NEEDED);
+                            skipRamp ? PLAY_SKIP_RAMP : PLAY_CREATE_IF_NEEDED);
                     mDuckedPlayers.add(piid);
                 } catch (Exception e) {
-                    Log.e(TAG, "Error ducking player " + piid + " uid:" + mUid, e);
+                    Log.e(TAG, "Error ducking player piid:" + piid + " uid:" + mUid, e);
                 }
             }
 
@@ -577,13 +586,13 @@ public final class PlaybackActivityMonitor
                                     DUCK_ID,
                                     VolumeShaper.Operation.REVERSE);
                         } catch (Exception e) {
-                            Log.e(TAG, "Error unducking player " + piid + " uid:" + mUid, e);
+                            Log.e(TAG, "Error unducking player piid:" + piid + " uid:" + mUid, e);
                         }
                     } else {
                         // this piid was in the list of ducked players, but wasn't found
                         if (DEBUG) {
-                            Log.v(TAG, "Error unducking player " + piid + ", player not found for"
-                                    + " uid " + mUid);
+                            Log.v(TAG, "Error unducking player piid:" + piid
+                                    + ", player not found for uid " + mUid);
                         }
                     }
                 }