diff --git a/media/java/android/media/AudioPlaybackConfiguration.java b/media/java/android/media/AudioPlaybackConfiguration.java index d18d7e4238e2e..457fccf0a24ed 100644 --- a/media/java/android/media/AudioPlaybackConfiguration.java +++ b/media/java/android/media/AudioPlaybackConfiguration.java @@ -167,6 +167,11 @@ public final class AudioPlaybackConfiguration implements Parcelable { * The state used to update device id, does not actually change the state of the player */ public static final int PLAYER_UPDATE_DEVICE_ID = 5; + /** + * @hide + * The state used to update port id, does not actually change the state of the player + */ + public static final int PLAYER_UPDATE_PORT_ID = 6; /** @hide */ @IntDef({ @@ -176,7 +181,8 @@ public final class AudioPlaybackConfiguration implements Parcelable { PLAYER_STATE_STARTED, PLAYER_STATE_PAUSED, PLAYER_STATE_STOPPED, - PLAYER_UPDATE_DEVICE_ID + PLAYER_UPDATE_DEVICE_ID, + PLAYER_UPDATE_PORT_ID, }) @Retention(RetentionPolicy.SOURCE) public @interface PlayerState {} @@ -191,6 +197,7 @@ public final class AudioPlaybackConfiguration implements Parcelable { case PLAYER_STATE_PAUSED: return "PLAYER_STATE_PAUSED"; case PLAYER_STATE_STOPPED: return "PLAYER_STATE_STOPPED"; case PLAYER_UPDATE_DEVICE_ID: return "PLAYER_UPDATE_DEVICE_ID"; + case PLAYER_UPDATE_PORT_ID: return "PLAYER_UPDATE_PORT_ID"; default: return "invalid state " + state; } @@ -669,7 +676,8 @@ public final class AudioPlaybackConfiguration implements Parcelable { case PLAYER_STATE_STARTED: return "started"; case PLAYER_STATE_PAUSED: return "paused"; case PLAYER_STATE_STOPPED: return "stopped"; - case PLAYER_UPDATE_DEVICE_ID: return "device"; + case PLAYER_UPDATE_DEVICE_ID: return "device updated"; + case PLAYER_UPDATE_PORT_ID: return "port updated"; default: return "unknown player state - FIXME"; } diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index f9b043f2525ca..92d81c61ee5a4 100755 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -74,7 +74,7 @@ interface IAudioService { oneway void playerAttributes(in int piid, in AudioAttributes attr); - oneway void playerEvent(in int piid, in int event, in int deviceId); + oneway void playerEvent(in int piid, in int event, in int eventId); oneway void releasePlayer(in int piid); diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 7c02531d54079..46b0dedbab20a 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -550,6 +550,10 @@ public class AudioService extends IAudioService.Stub if (mRecordMonitor != null) { mRecordMonitor.onAudioServerDied(); } + // Notify the playback monitor that the audio server has died + if (mPlaybackMonitor != null) { + mPlaybackMonitor.onAudioServerDied(); + } sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED, SENDMSG_NOOP, 0, 0, null, 0); sendMsg(mAudioHandler, MSG_DISPATCH_AUDIO_SERVER_STATE, @@ -11023,10 +11027,10 @@ public class AudioService extends IAudioService.Stub * Update player event * @param piid Player id to update * @param event The new player event - * @param deviceId The new player device id + * @param eventValue The value associated with this event */ - public void playerEvent(int piid, int event, int deviceId) { - mPlaybackMonitor.playerEvent(piid, event, deviceId, Binder.getCallingUid()); + public void playerEvent(int piid, int event, int eventValue) { + mPlaybackMonitor.playerEvent(piid, event, eventValue, Binder.getCallingUid()); } public void playerHasOpPlayAudio(int piid, boolean hasOpPlayAudio) { diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java index b3e7e31d37fc8..02036db4551ec 100644 --- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java +++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java @@ -34,7 +34,9 @@ import android.os.HandlerThread; import android.os.IBinder; import android.os.Message; import android.os.RemoteException; +import android.text.TextUtils; import android.util.Log; +import android.util.SparseIntArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.ArrayUtils; @@ -115,6 +117,9 @@ public final class PlaybackActivityMonitor private final HashMap mPlayers = new HashMap(); + @GuardedBy("mPlayerLock") + private final SparseIntArray mPortIdToPiid = new SparseIntArray(); + private final Context mContext; private int mSavedAlarmVolume = -1; private final int mMaxAlarmVolume; @@ -290,22 +295,29 @@ public final class PlaybackActivityMonitor * Update player event * @param piid Player id to update * @param event The new player event - * @param deviceId The new player device id + * @param eventValue The value associated with this event * @param binderUid Calling binder uid */ - public void playerEvent(int piid, int event, int deviceId, int binderUid) { + public void playerEvent(int piid, int event, int eventValue, int binderUid) { if (DEBUG) { - Log.v(TAG, String.format("playerEvent(piid=%d, deviceId=%d, event=%s)", - piid, deviceId, AudioPlaybackConfiguration.playerStateToString(event))); + Log.v(TAG, TextUtils.formatSimple("playerEvent(piid=%d, event=%s, eventValue=%d)", + piid, AudioPlaybackConfiguration.playerStateToString(event), eventValue)); } + final boolean change; synchronized(mPlayerLock) { final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid)); if (apc == null) { return; } - sEventLogger.log(new PlayerEvent(piid, event, deviceId)); - if (event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) { + + sEventLogger.log(new PlayerEvent(piid, event, eventValue)); + + if (event == AudioPlaybackConfiguration.PLAYER_UPDATE_PORT_ID) { + mEventHandler.sendMessage( + mEventHandler.obtainMessage(MSG_L_UPDATE_PORT_EVENT, eventValue, piid)); + return; + } else if (event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) { for (Integer uidInteger: mBannedUids) { if (checkBanPlayer(apc, uidInteger.intValue())) { // player was banned, do not update its state @@ -322,7 +334,7 @@ public final class PlaybackActivityMonitor if (checkConfigurationCaller(piid, apc, binderUid)) { //TODO add generation counter to only update to the latest state checkVolumeForPrivilegedAlarm(apc, event); - change = apc.handleStateEvent(event, deviceId); + change = apc.handleStateEvent(event, eventValue); } else { Log.e(TAG, "Error handling event " + event); change = false; @@ -357,6 +369,11 @@ public final class PlaybackActivityMonitor checkVolumeForPrivilegedAlarm(apc, AudioPlaybackConfiguration.PLAYER_STATE_RELEASED); change = apc.handleStateEvent(AudioPlaybackConfiguration.PLAYER_STATE_RELEASED, AudioPlaybackConfiguration.PLAYER_DEVICEID_INVALID); + + // remove all port ids mapped to the released player + mEventHandler.sendMessage( + mEventHandler.obtainMessage(MSG_L_CLEAR_PORTS_FOR_PIID, piid, /*arg2=*/0)); + } } if (change) { @@ -364,6 +381,18 @@ public final class PlaybackActivityMonitor } } + /*package*/ void onAudioServerDied() { + sEventLogger.log( + new AudioEventLogger.StringEvent( + "clear port id to piid map")); + synchronized (mPlayerLock) { + if (DEBUG) { + Log.v(TAG, "clear port id to piid map:\n" + mPortIdToPiid); + } + mPortIdToPiid.clear(); + } + } + /** * A map of uid to capture policy. */ @@ -499,9 +528,18 @@ public final class PlaybackActivityMonitor pw.print(" " + piid); } pw.println("\n"); + // portId to piid mappings: + pw.println("\n current portId to piid map:"); + for (int i = 0; i < mPortIdToPiid.size(); ++i) { + pw.println( + " portId: " + mPortIdToPiid.keyAt(i) + " piid: " + mPortIdToPiid.valueAt( + i)); + } + pw.println("\n"); // log sEventLogger.dump(pw); } + synchronized (mAllowedCapturePolicies) { pw.println("\n allowed capture policies:"); for (HashMap.Entry entry : mAllowedCapturePolicies.entrySet()) { @@ -1010,27 +1048,36 @@ public final class PlaybackActivityMonitor //================================================================= // For logging - private final static class PlayerEvent extends AudioEventLogger.Event { + private static final class PlayerEvent extends AudioEventLogger.Event { // only keeping the player interface ID as it uniquely identifies the player in the event final int mPlayerIId; - final int mState; - final int mDeviceId; + final int mEvent; + final int mEventValue; - PlayerEvent(int piid, int state, int deviceId) { + PlayerEvent(int piid, int event, int eventValue) { mPlayerIId = piid; - mState = state; - mDeviceId = deviceId; + mEvent = event; + mEventValue = eventValue; } @Override public String eventToString() { - return new StringBuilder("player piid:").append(mPlayerIId).append(" state:") - .append(AudioPlaybackConfiguration.toLogFriendlyPlayerState(mState)) - .append(" DeviceId:").append(mDeviceId).toString(); + if (mEvent == AudioPlaybackConfiguration.PLAYER_UPDATE_PORT_ID) { + return AudioPlaybackConfiguration.toLogFriendlyPlayerState(mEvent) + " portId:" + + mEventValue + " mapped to player piid:" + mPlayerIId; + } + + StringBuilder builder = new StringBuilder("player piid:").append(mPlayerIId).append( + " state:") + .append(AudioPlaybackConfiguration.toLogFriendlyPlayerState(mEvent)); + if (mEventValue != 0) { + builder.append(" DeviceId:").append(mEventValue); + } + return builder.toString(); } } - private final static class PlayerOpPlayAudioEvent extends AudioEventLogger.Event { + private static final class PlayerOpPlayAudioEvent extends AudioEventLogger.Event { // only keeping the player interface ID as it uniquely identifies the player in the event final int mPlayerIId; final boolean mHasOp; @@ -1050,7 +1097,7 @@ public final class PlaybackActivityMonitor } } - private final static class NewPlayerEvent extends AudioEventLogger.Event { + private static final class NewPlayerEvent extends AudioEventLogger.Event { private final int mPlayerIId; private final int mPlayerType; private final int mClientUid; @@ -1267,6 +1314,21 @@ public final class PlaybackActivityMonitor */ private static final int MSG_L_TIMEOUT_MUTE_AWAIT_CONNECTION = 1; + /** + * assign new port id to piid + * args: + * msg.arg1: port id + * msg.arg2: piid + */ + private static final int MSG_L_UPDATE_PORT_EVENT = 2; + + /** + * clear all ports assigned to a given piid + * args: + * msg.arg1: the piid + */ + private static final int MSG_L_CLEAR_PORTS_FOR_PIID = 3; + private void initEventHandler() { mEventThread = new HandlerThread(TAG); mEventThread.start(); @@ -1282,6 +1344,25 @@ public final class PlaybackActivityMonitor } mMuteAwaitConnectionTimeoutCb.accept((AudioDeviceAttributes) msg.obj); break; + case MSG_L_UPDATE_PORT_EVENT: + synchronized (mPlayerLock) { + mPortIdToPiid.put(/*portId*/msg.arg1, /*piid*/msg.arg2); + } + break; + case MSG_L_CLEAR_PORTS_FOR_PIID: + int piid = msg.arg1; + if (piid == AudioPlaybackConfiguration.PLAYER_PIID_INVALID) { + Log.w(TAG, "Received clear ports with invalid piid"); + break; + } + + synchronized (mPlayerLock) { + int portIdx; + while ((portIdx = mPortIdToPiid.indexOfValue(piid)) >= 0) { + mPortIdToPiid.removeAt(portIdx); + } + } + break; default: break; }