Loading services/core/java/com/android/server/audio/MediaFocusControl.java +69 −1 Original line number Diff line number Diff line Loading @@ -49,11 +49,18 @@ public class MediaFocusControl implements PlayerFocusEnforcer { * that they lost focus. */ static final boolean ENFORCE_DUCKING = false; /** * set to true so the framework enforces muting media/game itself when the device is ringing * or in a call. */ static final boolean ENFORCE_MUTING_FOR_RING_OR_CALL = true; private final Context mContext; private final AppOpsManager mAppOps; private PlayerFocusEnforcer mFocusEnforcer; // never null private boolean mRingOrCallActive = false; protected MediaFocusControl(Context cntxt, PlayerFocusEnforcer pfe) { mContext = cntxt; mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE); Loading @@ -78,6 +85,16 @@ public class MediaFocusControl implements PlayerFocusEnforcer { mFocusEnforcer.unduckPlayers(winner); } @Override public void mutePlayersForCall(int[] usagesToMute) { mFocusEnforcer.mutePlayersForCall(usagesToMute); } @Override public void unmutePlayersForCall() { mFocusEnforcer.unmutePlayersForCall(); } //========================================================================================== // AudioFocus //========================================================================================== Loading Loading @@ -139,7 +156,9 @@ public class MediaFocusControl implements PlayerFocusEnforcer { stackIterator.next().dump(pw); } } pw.println("\n Notify on duck: " + mNotifyFocusOwnerOnDuck +"\n"); pw.println("\n"); pw.println(" Notify on duck: " + mNotifyFocusOwnerOnDuck + "\n"); pw.println(" In ring or call: " + mRingOrCallActive + "\n"); } /** Loading Loading @@ -400,6 +419,18 @@ public class MediaFocusControl implements PlayerFocusEnforcer { } } /** * Delay after entering ringing or call mode after which the framework will mute streams * that are still playing. */ private static final int RING_CALL_MUTING_ENFORCEMENT_DELAY_MS = 100; /** * Usages to mute when the device rings or is in a call */ private final static int[] USAGES_TO_MUTE_IN_RING_OR_CALL = { AudioAttributes.USAGE_MEDIA, AudioAttributes.USAGE_GAME }; /** * Return the volume ramp time expected before playback with the given AudioAttributes would * start after gaining audio focus. Loading Loading @@ -452,6 +483,10 @@ public class MediaFocusControl implements PlayerFocusEnforcer { } synchronized(mAudioFocusLock) { boolean enteringRingOrCall = !mRingOrCallActive & (AudioSystem.IN_VOICE_COMM_FOCUS_ID.compareTo(clientId) == 0); if (enteringRingOrCall) { mRingOrCallActive = true; } boolean focusGrantDelayed = false; if (!canReassignAudioFocus()) { if ((flags & AudioManager.AUDIOFOCUS_FLAG_DELAY_OK) == 0) { Loading Loading @@ -523,6 +558,9 @@ public class MediaFocusControl implements PlayerFocusEnforcer { notifyExtPolicyFocusGrant_syncAf(nfr.toAudioFocusInfo(), AudioManager.AUDIOFOCUS_REQUEST_GRANTED); if (ENFORCE_MUTING_FOR_RING_OR_CALL & enteringRingOrCall) { runAudioCheckerForRingOrCallAsync(true/*enteringRingOrCall*/); } }//synchronized(mAudioFocusLock) return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; Loading @@ -539,7 +577,15 @@ public class MediaFocusControl implements PlayerFocusEnforcer { try { // this will take care of notifying the new focus owner if needed synchronized(mAudioFocusLock) { boolean exitingRingOrCall = mRingOrCallActive & (AudioSystem.IN_VOICE_COMM_FOCUS_ID.compareTo(clientId) == 0); if (exitingRingOrCall) { mRingOrCallActive = false; } removeFocusStackEntry(clientId, true /*signal*/, true /*notifyFocusFollowers*/); if (ENFORCE_MUTING_FOR_RING_OR_CALL & exitingRingOrCall) { runAudioCheckerForRingOrCallAsync(false/*enteringRingOrCall*/); } } } catch (java.util.ConcurrentModificationException cme) { // Catching this exception here is temporary. It is here just to prevent Loading @@ -559,4 +605,26 @@ public class MediaFocusControl implements PlayerFocusEnforcer { } } private void runAudioCheckerForRingOrCallAsync(final boolean enteringRingOrCall) { new Thread() { public void run() { if (enteringRingOrCall) { try { Thread.sleep(RING_CALL_MUTING_ENFORCEMENT_DELAY_MS); } catch (InterruptedException e) { e.printStackTrace(); } } synchronized (mAudioFocusLock) { // since the new thread starting running the state could have changed, so // we need to check again mRingOrCallActive, not enteringRingOrCall if (mRingOrCallActive) { mFocusEnforcer.mutePlayersForCall(USAGES_TO_MUTE_IN_RING_OR_CALL); } else { mFocusEnforcer.unmutePlayersForCall(); } } } }.start(); } } services/core/java/com/android/server/audio/PlaybackActivityMonitor.java +66 −1 Original line number Diff line number Diff line Loading @@ -147,6 +147,11 @@ public final class PlaybackActivityMonitor for (int piid : mDuckedPlayers) { pw.println(" " + piid); } // players muted due to the device ringing or being in a call pw.println("\n muted player piids:"); for (int piid : mMutedPlayers) { pw.println(" " + piid); } } } Loading Loading @@ -231,6 +236,7 @@ public final class PlaybackActivityMonitor //================================================================= // PlayerFocusEnforcer implementation private final ArrayList<Integer> mDuckedPlayers = new ArrayList<Integer>(); private final ArrayList<Integer> mMutedPlayers = new ArrayList<Integer>(); @Override public boolean duckPlayers(FocusRequester winner, FocusRequester loser) { Loading Loading @@ -290,9 +296,9 @@ public final class PlaybackActivityMonitor && winner.hasSameUid(apc.getClientUid())) { try { if (DEBUG) { Log.v(TAG, "unducking player" + piid); } mDuckedPlayers.remove(new Integer(piid)); //FIXME just a test before we have VolumeShape apc.getPlayerProxy().setPan(0.0f); mDuckedPlayers.remove(new Integer(piid)); } catch (Exception e) { Log.e(TAG, "Error unducking player " + piid, e); } Loading @@ -303,6 +309,65 @@ public final class PlaybackActivityMonitor } } @Override public void mutePlayersForCall(int[] usagesToMute) { if (DEBUG) { String log = new String("mutePlayersForCall: usages="); for (int usage : usagesToMute) { log += " " + usage; } Log.v(TAG, log); } synchronized (mPlayerLock) { final Set<Integer> piidSet = mPlayers.keySet(); final Iterator<Integer> piidIterator = piidSet.iterator(); // find which players to mute while (piidIterator.hasNext()) { final Integer piid = piidIterator.next(); final AudioPlaybackConfiguration apc = mPlayers.get(piid); final int playerUsage = apc.getAudioAttributes().getUsage(); boolean mute = false; for (int usageToMute : usagesToMute) { if (playerUsage == usageToMute) { mute = true; break; } } if (mute) { try { if (DEBUG) { Log.v(TAG, "muting player" + piid); } apc.getPlayerProxy().setVolume(0.0f); mMutedPlayers.add(piid); } catch (Exception e) { Log.e(TAG, "Error muting player " + piid, e); } } } } } @Override public void unmutePlayersForCall() { if (DEBUG) { Log.v(TAG, "unmutePlayersForCall()"); } synchronized (mPlayerLock) { if (mMutedPlayers.isEmpty()) { return; } for (int piid : mMutedPlayers) { final AudioPlaybackConfiguration apc = mPlayers.get(piid); if (apc != null) { try { if (DEBUG) { Log.v(TAG, "unmuting player" + piid); } apc.getPlayerProxy().setVolume(1.0f); mMutedPlayers.remove(new Integer(piid)); } catch (Exception e) { Log.e(TAG, "Error unmuting player " + piid, e); } } } } } //================================================================= // Track playback activity listeners Loading services/core/java/com/android/server/audio/PlayerFocusEnforcer.java +4 −0 Original line number Diff line number Diff line Loading @@ -28,4 +28,8 @@ public interface PlayerFocusEnforcer { public boolean duckPlayers(FocusRequester winner, FocusRequester loser); public void unduckPlayers(FocusRequester winner); public void mutePlayersForCall(int[] usagesToMute); public void unmutePlayersForCall(); } No newline at end of file Loading
services/core/java/com/android/server/audio/MediaFocusControl.java +69 −1 Original line number Diff line number Diff line Loading @@ -49,11 +49,18 @@ public class MediaFocusControl implements PlayerFocusEnforcer { * that they lost focus. */ static final boolean ENFORCE_DUCKING = false; /** * set to true so the framework enforces muting media/game itself when the device is ringing * or in a call. */ static final boolean ENFORCE_MUTING_FOR_RING_OR_CALL = true; private final Context mContext; private final AppOpsManager mAppOps; private PlayerFocusEnforcer mFocusEnforcer; // never null private boolean mRingOrCallActive = false; protected MediaFocusControl(Context cntxt, PlayerFocusEnforcer pfe) { mContext = cntxt; mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE); Loading @@ -78,6 +85,16 @@ public class MediaFocusControl implements PlayerFocusEnforcer { mFocusEnforcer.unduckPlayers(winner); } @Override public void mutePlayersForCall(int[] usagesToMute) { mFocusEnforcer.mutePlayersForCall(usagesToMute); } @Override public void unmutePlayersForCall() { mFocusEnforcer.unmutePlayersForCall(); } //========================================================================================== // AudioFocus //========================================================================================== Loading Loading @@ -139,7 +156,9 @@ public class MediaFocusControl implements PlayerFocusEnforcer { stackIterator.next().dump(pw); } } pw.println("\n Notify on duck: " + mNotifyFocusOwnerOnDuck +"\n"); pw.println("\n"); pw.println(" Notify on duck: " + mNotifyFocusOwnerOnDuck + "\n"); pw.println(" In ring or call: " + mRingOrCallActive + "\n"); } /** Loading Loading @@ -400,6 +419,18 @@ public class MediaFocusControl implements PlayerFocusEnforcer { } } /** * Delay after entering ringing or call mode after which the framework will mute streams * that are still playing. */ private static final int RING_CALL_MUTING_ENFORCEMENT_DELAY_MS = 100; /** * Usages to mute when the device rings or is in a call */ private final static int[] USAGES_TO_MUTE_IN_RING_OR_CALL = { AudioAttributes.USAGE_MEDIA, AudioAttributes.USAGE_GAME }; /** * Return the volume ramp time expected before playback with the given AudioAttributes would * start after gaining audio focus. Loading Loading @@ -452,6 +483,10 @@ public class MediaFocusControl implements PlayerFocusEnforcer { } synchronized(mAudioFocusLock) { boolean enteringRingOrCall = !mRingOrCallActive & (AudioSystem.IN_VOICE_COMM_FOCUS_ID.compareTo(clientId) == 0); if (enteringRingOrCall) { mRingOrCallActive = true; } boolean focusGrantDelayed = false; if (!canReassignAudioFocus()) { if ((flags & AudioManager.AUDIOFOCUS_FLAG_DELAY_OK) == 0) { Loading Loading @@ -523,6 +558,9 @@ public class MediaFocusControl implements PlayerFocusEnforcer { notifyExtPolicyFocusGrant_syncAf(nfr.toAudioFocusInfo(), AudioManager.AUDIOFOCUS_REQUEST_GRANTED); if (ENFORCE_MUTING_FOR_RING_OR_CALL & enteringRingOrCall) { runAudioCheckerForRingOrCallAsync(true/*enteringRingOrCall*/); } }//synchronized(mAudioFocusLock) return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; Loading @@ -539,7 +577,15 @@ public class MediaFocusControl implements PlayerFocusEnforcer { try { // this will take care of notifying the new focus owner if needed synchronized(mAudioFocusLock) { boolean exitingRingOrCall = mRingOrCallActive & (AudioSystem.IN_VOICE_COMM_FOCUS_ID.compareTo(clientId) == 0); if (exitingRingOrCall) { mRingOrCallActive = false; } removeFocusStackEntry(clientId, true /*signal*/, true /*notifyFocusFollowers*/); if (ENFORCE_MUTING_FOR_RING_OR_CALL & exitingRingOrCall) { runAudioCheckerForRingOrCallAsync(false/*enteringRingOrCall*/); } } } catch (java.util.ConcurrentModificationException cme) { // Catching this exception here is temporary. It is here just to prevent Loading @@ -559,4 +605,26 @@ public class MediaFocusControl implements PlayerFocusEnforcer { } } private void runAudioCheckerForRingOrCallAsync(final boolean enteringRingOrCall) { new Thread() { public void run() { if (enteringRingOrCall) { try { Thread.sleep(RING_CALL_MUTING_ENFORCEMENT_DELAY_MS); } catch (InterruptedException e) { e.printStackTrace(); } } synchronized (mAudioFocusLock) { // since the new thread starting running the state could have changed, so // we need to check again mRingOrCallActive, not enteringRingOrCall if (mRingOrCallActive) { mFocusEnforcer.mutePlayersForCall(USAGES_TO_MUTE_IN_RING_OR_CALL); } else { mFocusEnforcer.unmutePlayersForCall(); } } } }.start(); } }
services/core/java/com/android/server/audio/PlaybackActivityMonitor.java +66 −1 Original line number Diff line number Diff line Loading @@ -147,6 +147,11 @@ public final class PlaybackActivityMonitor for (int piid : mDuckedPlayers) { pw.println(" " + piid); } // players muted due to the device ringing or being in a call pw.println("\n muted player piids:"); for (int piid : mMutedPlayers) { pw.println(" " + piid); } } } Loading Loading @@ -231,6 +236,7 @@ public final class PlaybackActivityMonitor //================================================================= // PlayerFocusEnforcer implementation private final ArrayList<Integer> mDuckedPlayers = new ArrayList<Integer>(); private final ArrayList<Integer> mMutedPlayers = new ArrayList<Integer>(); @Override public boolean duckPlayers(FocusRequester winner, FocusRequester loser) { Loading Loading @@ -290,9 +296,9 @@ public final class PlaybackActivityMonitor && winner.hasSameUid(apc.getClientUid())) { try { if (DEBUG) { Log.v(TAG, "unducking player" + piid); } mDuckedPlayers.remove(new Integer(piid)); //FIXME just a test before we have VolumeShape apc.getPlayerProxy().setPan(0.0f); mDuckedPlayers.remove(new Integer(piid)); } catch (Exception e) { Log.e(TAG, "Error unducking player " + piid, e); } Loading @@ -303,6 +309,65 @@ public final class PlaybackActivityMonitor } } @Override public void mutePlayersForCall(int[] usagesToMute) { if (DEBUG) { String log = new String("mutePlayersForCall: usages="); for (int usage : usagesToMute) { log += " " + usage; } Log.v(TAG, log); } synchronized (mPlayerLock) { final Set<Integer> piidSet = mPlayers.keySet(); final Iterator<Integer> piidIterator = piidSet.iterator(); // find which players to mute while (piidIterator.hasNext()) { final Integer piid = piidIterator.next(); final AudioPlaybackConfiguration apc = mPlayers.get(piid); final int playerUsage = apc.getAudioAttributes().getUsage(); boolean mute = false; for (int usageToMute : usagesToMute) { if (playerUsage == usageToMute) { mute = true; break; } } if (mute) { try { if (DEBUG) { Log.v(TAG, "muting player" + piid); } apc.getPlayerProxy().setVolume(0.0f); mMutedPlayers.add(piid); } catch (Exception e) { Log.e(TAG, "Error muting player " + piid, e); } } } } } @Override public void unmutePlayersForCall() { if (DEBUG) { Log.v(TAG, "unmutePlayersForCall()"); } synchronized (mPlayerLock) { if (mMutedPlayers.isEmpty()) { return; } for (int piid : mMutedPlayers) { final AudioPlaybackConfiguration apc = mPlayers.get(piid); if (apc != null) { try { if (DEBUG) { Log.v(TAG, "unmuting player" + piid); } apc.getPlayerProxy().setVolume(1.0f); mMutedPlayers.remove(new Integer(piid)); } catch (Exception e) { Log.e(TAG, "Error unmuting player " + piid, e); } } } } } //================================================================= // Track playback activity listeners Loading
services/core/java/com/android/server/audio/PlayerFocusEnforcer.java +4 −0 Original line number Diff line number Diff line Loading @@ -28,4 +28,8 @@ public interface PlayerFocusEnforcer { public boolean duckPlayers(FocusRequester winner, FocusRequester loser); public void unduckPlayers(FocusRequester winner); public void mutePlayersForCall(int[] usagesToMute); public void unmutePlayersForCall(); } No newline at end of file