summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/audio/MediaFocusControl.java70
-rw-r--r--services/core/java/com/android/server/audio/PlaybackActivityMonitor.java67
-rw-r--r--services/core/java/com/android/server/audio/PlayerFocusEnforcer.java4
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