Merge "Playback activity monitoring: API for format and spatialization"

This commit is contained in:
Jean-Michel Trivi
2022-12-21 22:39:30 +00:00
committed by Android (Google) Code Review
3 changed files with 336 additions and 72 deletions

View File

@@ -6683,6 +6683,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();
@@ -6690,9 +6691,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

View File

@@ -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 <code>CHANNEL_OUT_*</code> 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<FormatInfo> CREATOR =
new Parcelable.Creator<FormatInfo>() {
public FormatInfo createFromParcel(Parcel p) {
return new FormatInfo(p);
}
public FormatInfo[] newArray(int size) {
return new FormatInfo[size];
}
};
}
//=====================================================================
// Utilities

View File

@@ -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;
}