diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 566ac4535b0d1..f20af42cedf54 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -6649,6 +6649,7 @@ package android.media {
}
public final class AudioPlaybackConfiguration implements android.os.Parcelable {
+ method public int getChannelMask();
method public int getClientPid();
method public int getClientUid();
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMutedBy();
@@ -6656,9 +6657,11 @@ package android.media {
method public android.media.PlayerProxy getPlayerProxy();
method public int getPlayerState();
method public int getPlayerType();
+ method @IntRange(from=0) public int getSampleRate();
method @IntRange(from=0) public int getSessionId();
method public boolean isActive();
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean isMuted();
+ method public boolean isSpatialized();
field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_APP_OPS = 8; // 0x8
field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_CLIENT_VOLUME = 16; // 0x10
field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_MASTER = 1; // 0x1
diff --git a/media/java/android/media/AudioPlaybackConfiguration.java b/media/java/android/media/AudioPlaybackConfiguration.java
index 59a0f7b88937d..f64e5cc1c5f15 100644
--- a/media/java/android/media/AudioPlaybackConfiguration.java
+++ b/media/java/android/media/AudioPlaybackConfiguration.java
@@ -32,6 +32,8 @@ import android.os.Parcelable;
import android.os.RemoteException;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -178,6 +180,11 @@ public final class AudioPlaybackConfiguration implements Parcelable {
* Used to update the mute state of a player through its port id
*/
public static final int PLAYER_UPDATE_MUTED = 7;
+ /**
+ * @hide
+ * Used to update the spatialization status and format of a player through its port id
+ */
+ public static final int PLAYER_UPDATE_FORMAT = 8;
/** @hide */
@IntDef({
@@ -190,6 +197,7 @@ public final class AudioPlaybackConfiguration implements Parcelable {
PLAYER_UPDATE_DEVICE_ID,
PLAYER_UPDATE_PORT_ID,
PLAYER_UPDATE_MUTED,
+ PLAYER_UPDATE_FORMAT,
})
@Retention(RetentionPolicy.SOURCE)
public @interface PlayerState {}
@@ -206,11 +214,33 @@ public final class AudioPlaybackConfiguration implements Parcelable {
case PLAYER_UPDATE_DEVICE_ID: return "PLAYER_UPDATE_DEVICE_ID";
case PLAYER_UPDATE_PORT_ID: return "PLAYER_UPDATE_PORT_ID";
case PLAYER_UPDATE_MUTED: return "PLAYER_UPDATE_MUTED";
+ case PLAYER_UPDATE_FORMAT: return "PLAYER_UPDATE_FORMAT";
default:
return "invalid state " + state;
}
}
+ /**
+ * @hide
+ * Used to update the spatialization status of a player through its port ID. Must be kept in
+ * sync with frameworks/native/include/audiomanager/AudioManager.h
+ */
+ public static final String EXTRA_PLAYER_EVENT_SPATIALIZED =
+ "android.media.extra.PLAYER_EVENT_SPATIALIZED";
+ /**
+ * @hide
+ * Used to update the sample rate of a player through its port ID. Must be kept in sync with
+ * frameworks/native/include/audiomanager/AudioManager.h
+ */
+ public static final String EXTRA_PLAYER_EVENT_SAMPLE_RATE =
+ "android.media.extra.PLAYER_EVENT_SAMPLE_RATE";
+ /**
+ * @hide
+ * Used to update the channel mask of a player through its port ID. Must be kept in sync with
+ * frameworks/native/include/audiomanager/AudioManager.h
+ */
+ public static final String EXTRA_PLAYER_EVENT_CHANNEL_MASK =
+ "android.media.extra.PLAYER_EVENT_CHANNEL_MASK";
/**
* @hide
* Used to update the mute state of a player through its port ID. Must be kept in sync with
@@ -284,10 +314,16 @@ public final class AudioPlaybackConfiguration implements Parcelable {
private int mPlayerState;
private AudioAttributes mPlayerAttr; // never null
+ // lock for updateable properties
+ private final Object mUpdateablePropLock = new Object();
+
+ @GuardedBy("mUpdateablePropLock")
private int mDeviceId;
-
+ @GuardedBy("mUpdateablePropLock")
private int mSessionId;
-
+ @GuardedBy("mUpdateablePropLock")
+ private @NonNull FormatInfo mFormatInfo;
+ @GuardedBy("mUpdateablePropLock")
@PlayerMuteEvent private int mMutedState;
/**
@@ -320,6 +356,7 @@ public final class AudioPlaybackConfiguration implements Parcelable {
mIPlayerShell = null;
}
mSessionId = pic.mSessionId;
+ mFormatInfo = FormatInfo.DEFAULT;
}
/**
@@ -333,13 +370,23 @@ public final class AudioPlaybackConfiguration implements Parcelable {
}
}
+ // sets the fields that are updateable and require synchronization
+ private void setUpdateableFields(int deviceId, int sessionId, int mutedState, FormatInfo format)
+ {
+ synchronized (mUpdateablePropLock) {
+ mDeviceId = deviceId;
+ mSessionId = sessionId;
+ mMutedState = mutedState;
+ mFormatInfo = format;
+ }
+ }
// Note that this method is called server side, so no "privileged" information is ever sent
// to a client that is not supposed to have access to it.
/**
* @hide
* Creates a copy of the playback configuration that is stripped of any data enabling
* identification of which application it is associated with ("anonymized").
- * @param toSanitize
+ * @param in the instance to copy from
*/
public static AudioPlaybackConfiguration anonymizedCopy(AudioPlaybackConfiguration in) {
final AudioPlaybackConfiguration anonymCopy = new AudioPlaybackConfiguration(in.mPlayerIId);
@@ -357,14 +404,16 @@ public final class AudioPlaybackConfiguration implements Parcelable {
builder.setUsage(in.mPlayerAttr.getUsage());
}
anonymCopy.mPlayerAttr = builder.build();
- anonymCopy.mDeviceId = in.mDeviceId;
// anonymized data
- anonymCopy.mMutedState = 0;
anonymCopy.mPlayerType = PLAYER_TYPE_UNKNOWN;
anonymCopy.mClientUid = PLAYER_UPID_INVALID;
anonymCopy.mClientPid = PLAYER_UPID_INVALID;
anonymCopy.mIPlayerShell = null;
- anonymCopy.mSessionId = AudioSystem.AUDIO_SESSION_ALLOCATE;
+ anonymCopy.setUpdateableFields(
+ /*deviceId*/ PLAYER_DEVICEID_INVALID,
+ /*sessionId*/ AudioSystem.AUDIO_SESSION_ALLOCATE,
+ /*mutedState*/ 0,
+ FormatInfo.DEFAULT);
return anonymCopy;
}
@@ -401,10 +450,14 @@ public final class AudioPlaybackConfiguration implements Parcelable {
* @return the audio playback device or null if the device is not available at the time of query
*/
public @Nullable AudioDeviceInfo getAudioDeviceInfo() {
- if (mDeviceId == PLAYER_DEVICEID_INVALID) {
+ final int deviceId;
+ synchronized (mUpdateablePropLock) {
+ deviceId = mDeviceId;
+ }
+ if (deviceId == PLAYER_DEVICEID_INVALID) {
return null;
}
- return AudioManager.getDeviceForPortId(mDeviceId, AudioManager.GET_DEVICES_OUTPUTS);
+ return AudioManager.getDeviceForPortId(deviceId, AudioManager.GET_DEVICES_OUTPUTS);
}
/**
@@ -415,7 +468,9 @@ public final class AudioPlaybackConfiguration implements Parcelable {
*/
@SystemApi
public @IntRange(from = 0) int getSessionId() {
- return mSessionId;
+ synchronized (mUpdateablePropLock) {
+ return mSessionId;
+ }
}
/**
@@ -428,7 +483,9 @@ public final class AudioPlaybackConfiguration implements Parcelable {
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
public boolean isMuted() {
- return mMutedState != 0;
+ synchronized (mUpdateablePropLock) {
+ return mMutedState != 0;
+ }
}
/**
@@ -440,7 +497,9 @@ public final class AudioPlaybackConfiguration implements Parcelable {
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
@PlayerMuteEvent public int getMutedBy() {
- return mMutedState;
+ synchronized (mUpdateablePropLock) {
+ return mMutedState;
+ }
}
/**
@@ -498,6 +557,43 @@ public final class AudioPlaybackConfiguration implements Parcelable {
return ips == null ? null : new PlayerProxy(this);
}
+ /**
+ * @hide
+ * Return whether this player's output is spatialized
+ * @return true if spatialized, false if not or playback hasn't started
+ */
+ @SystemApi
+ public boolean isSpatialized() {
+ synchronized (mUpdateablePropLock) {
+ return mFormatInfo.mIsSpatialized;
+ }
+ }
+
+ /**
+ * @hide
+ * Return the sample rate in Hz of the content being played.
+ * @return the sample rate in Hertz, or 0 if playback hasn't started
+ */
+ @SystemApi
+ public @IntRange(from = 0) int getSampleRate() {
+ synchronized (mUpdateablePropLock) {
+ return mFormatInfo.mSampleRate;
+ }
+ }
+
+ /**
+ * @hide
+ * Return the player's channel mask
+ * @return the channel mask, or 0 if playback hasn't started. See {@link AudioFormat} and
+ * the definitions for the CHANNEL_OUT_* values used for the mask's bitfield
+ */
+ @SystemApi
+ public int getChannelMask() {
+ synchronized (mUpdateablePropLock) {
+ return (AudioFormat.convertNativeChannelMaskToOutMask(mFormatInfo.mNativeChannelMask));
+ }
+ }
+
/**
* @hide
* @return the IPlayer interface for the associated player
@@ -527,9 +623,11 @@ public final class AudioPlaybackConfiguration implements Parcelable {
* @param sessionId the audio session ID
*/
public boolean handleSessionIdEvent(int sessionId) {
- final boolean changed = sessionId != mSessionId;
- mSessionId = sessionId;
- return changed;
+ synchronized (mUpdateablePropLock) {
+ final boolean changed = sessionId != mSessionId;
+ mSessionId = sessionId;
+ return changed;
+ }
}
/**
@@ -539,9 +637,25 @@ public final class AudioPlaybackConfiguration implements Parcelable {
* @return true if the state changed, false otherwise
*/
public boolean handleMutedEvent(@PlayerMuteEvent int mutedState) {
- final boolean changed = mMutedState != mutedState;
- mMutedState = mutedState;
- return changed;
+ synchronized (mUpdateablePropLock) {
+ final boolean changed = mMutedState != mutedState;
+ mMutedState = mutedState;
+ return changed;
+ }
+ }
+
+ /**
+ * @hide
+ * Handle a change of playback format
+ * @param fi the latest format information
+ * @return true if the format changed, false otherwise
+ */
+ public boolean handleFormatEvent(@NonNull FormatInfo fi) {
+ synchronized (mUpdateablePropLock) {
+ final boolean changed = !mFormatInfo.equals(fi);
+ mFormatInfo = fi;
+ return changed;
+ }
}
/**
@@ -558,7 +672,7 @@ public final class AudioPlaybackConfiguration implements Parcelable {
*/
public boolean handleStateEvent(int event, int deviceId) {
boolean changed = false;
- synchronized (this) {
+ synchronized (mUpdateablePropLock) {
// Do not update if it is only device id update
if (event != PLAYER_UPDATE_DEVICE_ID) {
@@ -647,8 +761,10 @@ public final class AudioPlaybackConfiguration implements Parcelable {
@Override
public int hashCode() {
- return Objects.hash(mPlayerIId, mDeviceId, mMutedState, mPlayerType, mClientUid, mClientPid,
- mSessionId);
+ synchronized (mUpdateablePropLock) {
+ return Objects.hash(mPlayerIId, mDeviceId, mMutedState, mPlayerType, mClientUid,
+ mClientPid, mSessionId);
+ }
}
@Override
@@ -658,20 +774,23 @@ public final class AudioPlaybackConfiguration implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mPlayerIId);
- dest.writeInt(mDeviceId);
- dest.writeInt(mMutedState);
- dest.writeInt(mPlayerType);
- dest.writeInt(mClientUid);
- dest.writeInt(mClientPid);
- dest.writeInt(mPlayerState);
- mPlayerAttr.writeToParcel(dest, 0);
- final IPlayerShell ips;
- synchronized (this) {
- ips = mIPlayerShell;
+ synchronized (mUpdateablePropLock) {
+ dest.writeInt(mPlayerIId);
+ dest.writeInt(mDeviceId);
+ dest.writeInt(mMutedState);
+ dest.writeInt(mPlayerType);
+ dest.writeInt(mClientUid);
+ dest.writeInt(mClientPid);
+ dest.writeInt(mPlayerState);
+ mPlayerAttr.writeToParcel(dest, 0);
+ final IPlayerShell ips;
+ synchronized (this) {
+ ips = mIPlayerShell;
+ }
+ dest.writeStrongInterface(ips == null ? null : ips.getIPlayer());
+ dest.writeInt(mSessionId);
+ mFormatInfo.writeToParcel(dest, 0);
}
- dest.writeStrongInterface(ips == null ? null : ips.getIPlayer());
- dest.writeInt(mSessionId);
}
private AudioPlaybackConfiguration(Parcel in) {
@@ -686,6 +805,7 @@ public final class AudioPlaybackConfiguration implements Parcelable {
final IPlayer p = IPlayer.Stub.asInterface(in.readStrongBinder());
mIPlayerShell = (p == null) ? null : new IPlayerShell(null, p);
mSessionId = in.readInt();
+ mFormatInfo = FormatInfo.CREATOR.createFromParcel(in);
}
@Override
@@ -707,35 +827,39 @@ public final class AudioPlaybackConfiguration implements Parcelable {
@Override
public String toString() {
StringBuilder apcToString = new StringBuilder();
- apcToString.append("AudioPlaybackConfiguration piid:").append(mPlayerIId).append(
- " deviceId:").append(mDeviceId).append(" type:").append(
- toLogFriendlyPlayerType(mPlayerType)).append(" u/pid:").append(mClientUid).append(
- "/").append(mClientPid).append(" state:").append(
- toLogFriendlyPlayerState(mPlayerState)).append(" attr:").append(mPlayerAttr).append(
- " sessionId:").append(mSessionId).append(" mutedState:");
- if (mMutedState == 0) {
- apcToString.append("none ");
- } else {
- if ((mMutedState & MUTED_BY_MASTER) != 0) {
- apcToString.append("master ");
- }
- if ((mMutedState & MUTED_BY_STREAM_VOLUME) != 0) {
- apcToString.append("streamVolume ");
- }
- if ((mMutedState & MUTED_BY_STREAM_MUTED) != 0) {
- apcToString.append("streamMute ");
- }
- if ((mMutedState & MUTED_BY_APP_OPS) != 0) {
- apcToString.append("appOps ");
- }
- if ((mMutedState & MUTED_BY_CLIENT_VOLUME) != 0) {
- apcToString.append("clientVolume ");
- }
- if ((mMutedState & MUTED_BY_VOLUME_SHAPER) != 0) {
- apcToString.append("volumeShaper ");
+ synchronized (mUpdateablePropLock) {
+ apcToString.append("AudioPlaybackConfiguration piid:").append(mPlayerIId).append(
+ " deviceId:").append(mDeviceId).append(" type:").append(
+ toLogFriendlyPlayerType(mPlayerType)).append(" u/pid:").append(
+ mClientUid).append(
+ "/").append(mClientPid).append(" state:").append(
+ toLogFriendlyPlayerState(mPlayerState)).append(" attr:").append(
+ mPlayerAttr).append(
+ " sessionId:").append(mSessionId).append(" mutedState:");
+ if (mMutedState == 0) {
+ apcToString.append("none ");
+ } else {
+ if ((mMutedState & MUTED_BY_MASTER) != 0) {
+ apcToString.append("master ");
+ }
+ if ((mMutedState & MUTED_BY_STREAM_VOLUME) != 0) {
+ apcToString.append("streamVolume ");
+ }
+ if ((mMutedState & MUTED_BY_STREAM_MUTED) != 0) {
+ apcToString.append("streamMute ");
+ }
+ if ((mMutedState & MUTED_BY_APP_OPS) != 0) {
+ apcToString.append("appOps ");
+ }
+ if ((mMutedState & MUTED_BY_CLIENT_VOLUME) != 0) {
+ apcToString.append("clientVolume ");
+ }
+ if ((mMutedState & MUTED_BY_VOLUME_SHAPER) != 0) {
+ apcToString.append("volumeShaper ");
+ }
}
+ apcToString.append(" ").append(mFormatInfo);
}
-
return apcToString.toString();
}
@@ -787,6 +911,79 @@ public final class AudioPlaybackConfiguration implements Parcelable {
}
}
+ //=====================================================================
+
+ /**
+ * @hide
+ * Class to store sample rate, channel mask, and spatialization status
+ */
+ public static final class FormatInfo implements Parcelable {
+ static final FormatInfo DEFAULT = new FormatInfo(
+ /*spatialized*/ false, /*channel mask*/ 0, /*sample rate*/ 0);
+ final boolean mIsSpatialized;
+ final int mNativeChannelMask;
+ final int mSampleRate;
+
+ public FormatInfo(boolean isSpatialized, int nativeChannelMask, int sampleRate) {
+ mIsSpatialized = isSpatialized;
+ mNativeChannelMask = nativeChannelMask;
+ mSampleRate = sampleRate;
+ }
+
+ @Override
+ public String toString() {
+ return "FormatInfo{"
+ + "isSpatialized=" + mIsSpatialized
+ + ", channelMask=0x" + Integer.toHexString(mNativeChannelMask)
+ + ", sampleRate=" + mSampleRate
+ + '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof FormatInfo)) return false;
+ FormatInfo that = (FormatInfo) o;
+ return mIsSpatialized == that.mIsSpatialized
+ && mNativeChannelMask == that.mNativeChannelMask
+ && mSampleRate == that.mSampleRate;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mIsSpatialized, mNativeChannelMask, mSampleRate);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@androidx.annotation.NonNull Parcel dest, int flags) {
+ dest.writeBoolean(mIsSpatialized);
+ dest.writeInt(mNativeChannelMask);
+ dest.writeInt(mSampleRate);
+ }
+
+ private FormatInfo(Parcel in) {
+ this(
+ in.readBoolean(), // isSpatialized
+ in.readInt(), // channelMask
+ in.readInt() // sampleRate
+ );
+ }
+
+ public static final @NonNull Parcelable.Creator CREATOR =
+ new Parcelable.Creator() {
+ public FormatInfo createFromParcel(Parcel p) {
+ return new FormatInfo(p);
+ }
+ public FormatInfo[] newArray(int size) {
+ return new FormatInfo[size];
+ }
+ };
+ }
//=====================================================================
// Utilities
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index f35931ca1837c..99d62287f2a99 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -35,6 +35,7 @@ import android.media.AudioDeviceAttributes;
import android.media.AudioDeviceInfo;
import android.media.AudioManager;
import android.media.AudioPlaybackConfiguration;
+import android.media.AudioPlaybackConfiguration.FormatInfo;
import android.media.AudioPlaybackConfiguration.PlayerMuteEvent;
import android.media.AudioSystem;
import android.media.IPlaybackConfigDispatcher;
@@ -75,7 +76,7 @@ import java.util.function.Consumer;
public final class PlaybackActivityMonitor
implements AudioPlaybackConfiguration.PlayerDeathMonitor, PlayerFocusEnforcer {
- public static final String TAG = "AudioService.PlaybackActivityMonitor";
+ public static final String TAG = "AS.PlaybackActivityMon";
/*package*/ static final boolean DEBUG = false;
/*package*/ static final int VOLUME_SHAPER_SYSTEM_DUCK_ID = 1;
@@ -343,7 +344,7 @@ public final class PlaybackActivityMonitor
if (event == AudioPlaybackConfiguration.PLAYER_UPDATE_PORT_ID) {
mEventHandler.sendMessage(
- mEventHandler.obtainMessage(MSG_L_UPDATE_PORT_EVENT, eventValue, piid));
+ mEventHandler.obtainMessage(MSG_II_UPDATE_PORT_EVENT, eventValue, piid));
return;
} else if (event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
for (Integer uidInteger: mBannedUids) {
@@ -399,7 +400,7 @@ public final class PlaybackActivityMonitor
}
if (DEBUG) {
- Log.v(TAG, TextUtils.formatSimple("portEvent(portId=%d, event=%s, extras=%s)",
+ Log.v(TAG, TextUtils.formatSimple("BLA portEvent(portId=%d, event=%s, extras=%s)",
portId, AudioPlaybackConfiguration.playerStateToString(event), extras));
}
@@ -427,7 +428,12 @@ public final class PlaybackActivityMonitor
if (event == AudioPlaybackConfiguration.PLAYER_UPDATE_MUTED) {
mEventHandler.sendMessage(
- mEventHandler.obtainMessage(MSG_L_UPDATE_PLAYER_MUTED_EVENT, piid,
+ mEventHandler.obtainMessage(MSG_IIL_UPDATE_PLAYER_MUTED_EVENT, piid,
+ portId,
+ extras));
+ } else if (event == AudioPlaybackConfiguration.PLAYER_UPDATE_FORMAT) {
+ mEventHandler.sendMessage(
+ mEventHandler.obtainMessage(MSG_IIL_UPDATE_PLAYER_FORMAT, piid,
portId,
extras));
}
@@ -457,7 +463,7 @@ public final class PlaybackActivityMonitor
// remove all port ids mapped to the released player
mEventHandler.sendMessage(
- mEventHandler.obtainMessage(MSG_L_CLEAR_PORTS_FOR_PIID, piid, /*arg2=*/0));
+ mEventHandler.obtainMessage(MSG_I_CLEAR_PORTS_FOR_PIID, piid, /*arg2=*/0));
if (change && mDoNotLogPiidList.contains(piid)) {
// do not dispatch a change for a "do not log" player
@@ -1352,6 +1358,21 @@ public final class PlaybackActivityMonitor
}
}
+ private static final class PlayerFormatEvent extends EventLogger.Event {
+ private final int mPlayerIId;
+ private final AudioPlaybackConfiguration.FormatInfo mFormat;
+
+ PlayerFormatEvent(int piid, AudioPlaybackConfiguration.FormatInfo format) {
+ mPlayerIId = piid;
+ mFormat = format;
+ }
+
+ @Override
+ public String eventToString() {
+ return new String("player piid:" + mPlayerIId + " format update:" + mFormat);
+ }
+ }
+
static final EventLogger
sEventLogger = new EventLogger(100,
"playback activity as reported through PlayerBase");
@@ -1478,7 +1499,7 @@ public final class PlaybackActivityMonitor
* msg.arg1: port id
* msg.arg2: piid
*/
- private static final int MSG_L_UPDATE_PORT_EVENT = 2;
+ private static final int MSG_II_UPDATE_PORT_EVENT = 2;
/**
* event for player getting muted
@@ -1488,14 +1509,24 @@ public final class PlaybackActivityMonitor
* msg.obj: extras describing the mute reason
* type: PersistableBundle
*/
- private static final int MSG_L_UPDATE_PLAYER_MUTED_EVENT = 3;
+ private static final int MSG_IIL_UPDATE_PLAYER_MUTED_EVENT = 3;
/**
* clear all ports assigned to a given piid
* args:
* msg.arg1: the piid
*/
- private static final int MSG_L_CLEAR_PORTS_FOR_PIID = 4;
+ private static final int MSG_I_CLEAR_PORTS_FOR_PIID = 4;
+
+ /**
+ * event for player reporting playback format and spatialization status
+ * args:
+ * msg.arg1: piid
+ * msg.arg2: port id
+ * msg.obj: extras describing the sample rate, channel mask, spatialized
+ * type: PersistableBundle
+ */
+ private static final int MSG_IIL_UPDATE_PLAYER_FORMAT = 5;
private void initEventHandler() {
mEventThread = new HandlerThread(TAG);
@@ -1513,12 +1544,13 @@ public final class PlaybackActivityMonitor
}
mMuteAwaitConnectionTimeoutCb.accept((AudioDeviceAttributes) msg.obj);
break;
- case MSG_L_UPDATE_PORT_EVENT:
+
+ case MSG_II_UPDATE_PORT_EVENT:
synchronized (mPlayerLock) {
mPortIdToPiid.put(/*portId*/msg.arg1, /*piid*/msg.arg2);
}
break;
- case MSG_L_UPDATE_PLAYER_MUTED_EVENT:
+ case MSG_IIL_UPDATE_PLAYER_MUTED_EVENT:
// TODO: replace PersistableBundle with own struct
PersistableBundle extras = (PersistableBundle) msg.obj;
if (extras == null) {
@@ -1533,14 +1565,18 @@ public final class PlaybackActivityMonitor
sEventLogger.enqueue(
new PlayerEvent(piid, PLAYER_UPDATE_MUTED, eventValue));
- final AudioPlaybackConfiguration apc = mPlayers.get(piid);
+ final AudioPlaybackConfiguration apc;
+ synchronized (mPlayerLock) {
+ apc = mPlayers.get(piid);
+ }
if (apc == null || !apc.handleMutedEvent(eventValue)) {
break; // do not dispatch
}
dispatchPlaybackChange(/* iplayerReleased= */false);
}
break;
- case MSG_L_CLEAR_PORTS_FOR_PIID:
+
+ case MSG_I_CLEAR_PORTS_FOR_PIID:
int piid = msg.arg1;
if (piid == AudioPlaybackConfiguration.PLAYER_PIID_INVALID) {
Log.w(TAG, "Received clear ports with invalid piid");
@@ -1554,6 +1590,34 @@ public final class PlaybackActivityMonitor
}
}
break;
+
+ case MSG_IIL_UPDATE_PLAYER_FORMAT:
+ final PersistableBundle formatExtras = (PersistableBundle) msg.obj;
+ if (formatExtras == null) {
+ Log.w(TAG, "Received format event with no extras");
+ break;
+ }
+ final boolean spatialized = formatExtras.getBoolean(
+ AudioPlaybackConfiguration.EXTRA_PLAYER_EVENT_SPATIALIZED, false);
+ final int sampleRate = formatExtras.getInt(
+ AudioPlaybackConfiguration.EXTRA_PLAYER_EVENT_SAMPLE_RATE, 0);
+ final int nativeChannelMask = formatExtras.getInt(
+ AudioPlaybackConfiguration.EXTRA_PLAYER_EVENT_CHANNEL_MASK, 0);
+ final FormatInfo format =
+ new FormatInfo(spatialized, nativeChannelMask, sampleRate);
+
+ sEventLogger.enqueue(new PlayerFormatEvent(msg.arg1, format));
+
+ final AudioPlaybackConfiguration apc;
+ synchronized (mPlayerLock) {
+ apc = mPlayers.get(msg.arg1);
+ }
+ if (apc == null || !apc.handleFormatEvent(format)) {
+ break; // do not dispatch
+ }
+ // TODO optimize for no dispatch to non-privileged listeners
+ dispatchPlaybackChange(/* iplayerReleased= */false);
+ break;
default:
break;
}