diff options
3 files changed, 139 insertions, 2 deletions
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java index a1c56538e9bd..b4feef3da291 100644 --- a/services/core/java/com/android/server/audio/MediaFocusControl.java +++ b/services/core/java/com/android/server/audio/MediaFocusControl.java @@ -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); @@ -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 //========================================================================================== @@ -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"); } /** @@ -401,6 +420,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. * @param attr attributes of the sound about to start playing @@ -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) { @@ -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; @@ -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 @@ -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(); + } } diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java index 4930c5374513..3f8bbe5ecdc5 100644 --- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java +++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java @@ -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); + } } } @@ -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) { @@ -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); } @@ -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 diff --git a/services/core/java/com/android/server/audio/PlayerFocusEnforcer.java b/services/core/java/com/android/server/audio/PlayerFocusEnforcer.java index acb4f0d8f3a9..0733eca97d4e 100644 --- a/services/core/java/com/android/server/audio/PlayerFocusEnforcer.java +++ b/services/core/java/com/android/server/audio/PlayerFocusEnforcer.java @@ -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 |