Merge "Added update device info playback configuration"

This commit is contained in:
Oscar Azucena
2020-12-17 05:08:46 +00:00
committed by Android (Google) Code Review
10 changed files with 243 additions and 45 deletions

View File

@@ -19907,6 +19907,7 @@ package android.media {
public final class AudioPlaybackConfiguration implements android.os.Parcelable {
method public int describeContents();
method public android.media.AudioAttributes getAudioAttributes();
method @Nullable public android.media.AudioDeviceInfo getAudioDevice();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.media.AudioPlaybackConfiguration> CREATOR;
}

View File

@@ -21,6 +21,7 @@ import static android.media.AudioAttributes.ALLOW_CAPTURE_BY_NONE;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.os.Binder;
import android.os.IBinder;
@@ -47,6 +48,8 @@ public final class AudioPlaybackConfiguration implements Parcelable {
public static final int PLAYER_PIID_INVALID = -1;
/** @hide */
public static final int PLAYER_UPID_INVALID = -1;
/** @hide */
public static final int PLAYER_DEVICEID_INVALID = 0;
// information about the implementation
/**
@@ -158,6 +161,11 @@ public final class AudioPlaybackConfiguration implements Parcelable {
*/
@SystemApi
public static final int PLAYER_STATE_STOPPED = 4;
/**
* @hide
* 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 */
@IntDef({
@@ -166,7 +174,8 @@ public final class AudioPlaybackConfiguration implements Parcelable {
PLAYER_STATE_IDLE,
PLAYER_STATE_STARTED,
PLAYER_STATE_PAUSED,
PLAYER_STATE_STOPPED
PLAYER_STATE_STOPPED,
PLAYER_UPDATE_DEVICE_ID
})
@Retention(RetentionPolicy.SOURCE)
public @interface PlayerState {}
@@ -184,6 +193,8 @@ public final class AudioPlaybackConfiguration implements Parcelable {
private int mPlayerState;
private AudioAttributes mPlayerAttr; // never null
private int mDeviceId;
/**
* Never use without initializing parameters afterwards
*/
@@ -201,6 +212,7 @@ public final class AudioPlaybackConfiguration implements Parcelable {
mPlayerType = pic.mPlayerType;
mClientUid = uid;
mClientPid = pid;
mDeviceId = PLAYER_DEVICEID_INVALID;
mPlayerState = PLAYER_STATE_IDLE;
mPlayerAttr = pic.mAttributes;
if ((sPlayerDeathMonitor != null) && (pic.mIPlayer != null)) {
@@ -241,6 +253,7 @@ public final class AudioPlaybackConfiguration implements Parcelable {
in.mPlayerAttr.getAllowedCapturePolicy() == ALLOW_CAPTURE_BY_ALL
? ALLOW_CAPTURE_BY_ALL : ALLOW_CAPTURE_BY_NONE)
.build();
anonymCopy.mDeviceId = in.mDeviceId;
// anonymized data
anonymCopy.mPlayerType = PLAYER_TYPE_UNKNOWN;
anonymCopy.mClientUid = PLAYER_UPID_INVALID;
@@ -277,6 +290,25 @@ public final class AudioPlaybackConfiguration implements Parcelable {
return mClientPid;
}
/**
* Returns information about the {@link AudioDeviceInfo} used for this playback.
* @return the audio playback device or null if the device is not available at the time of query
*/
public @Nullable AudioDeviceInfo getAudioDevice() {
if (mDeviceId == PLAYER_DEVICEID_INVALID) {
return null;
}
// TODO(175802592): change this to AudioManager.getDeviceForPortId() when available
AudioDeviceInfo[] devices =
AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_OUTPUTS);
for (int i = 0; i < devices.length; i++) {
if (devices[i].getId() == mDeviceId) {
return devices[i];
}
}
return null;
}
/**
* @hide
* Return the type of player linked to this configuration.
@@ -359,13 +391,29 @@ public final class AudioPlaybackConfiguration implements Parcelable {
* @hide
* Handle a player state change
* @param event
* @param deviceId active device id or {@Code PLAYER_DEVICEID_INVALID}
* <br>Note device id is valid for {@code PLAYER_UPDATE_DEVICE_ID} or
* <br>{@code PLAYER_STATE_STARTED} events, as the device id will be reset to none when
* <br>pausing or stopping playback. It will be set to active device when playback starts or
* <br>it will be changed when PLAYER_UPDATE_DEVICE_ID is sent. The latter can happen if the
* <br>device changes in the middle of playback.
* @return true if the state changed, false otherwise
*/
public boolean handleStateEvent(int event) {
final boolean changed;
public boolean handleStateEvent(int event, int deviceId) {
boolean changed = false;
synchronized (this) {
changed = (mPlayerState != event);
mPlayerState = event;
// Do not update if it is only device id update
if (event != PLAYER_UPDATE_DEVICE_ID) {
changed = (mPlayerState != event);
mPlayerState = event;
}
if (event == PLAYER_STATE_STARTED || event == PLAYER_UPDATE_DEVICE_ID) {
changed = changed || (mDeviceId != deviceId);
mDeviceId = deviceId;
}
if (changed && (event == PLAYER_STATE_RELEASED) && (mIPlayerShell != null)) {
mIPlayerShell.release();
mIPlayerShell = null;
@@ -436,7 +484,7 @@ public final class AudioPlaybackConfiguration implements Parcelable {
@Override
public int hashCode() {
return Objects.hash(mPlayerIId, mPlayerType, mClientUid, mClientPid);
return Objects.hash(mPlayerIId, mDeviceId, mPlayerType, mClientUid, mClientPid);
}
@Override
@@ -447,6 +495,7 @@ public final class AudioPlaybackConfiguration implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mPlayerIId);
dest.writeInt(mDeviceId);
dest.writeInt(mPlayerType);
dest.writeInt(mClientUid);
dest.writeInt(mClientPid);
@@ -461,6 +510,7 @@ public final class AudioPlaybackConfiguration implements Parcelable {
private AudioPlaybackConfiguration(Parcel in) {
mPlayerIId = in.readInt();
mDeviceId = in.readInt();
mPlayerType = in.readInt();
mClientUid = in.readInt();
mClientPid = in.readInt();
@@ -478,6 +528,7 @@ public final class AudioPlaybackConfiguration implements Parcelable {
AudioPlaybackConfiguration that = (AudioPlaybackConfiguration) o;
return ((mPlayerIId == that.mPlayerIId)
&& (mDeviceId == that.mDeviceId)
&& (mPlayerType == that.mPlayerType)
&& (mClientUid == that.mClientUid)
&& (mClientPid == that.mClientPid));
@@ -486,6 +537,7 @@ public final class AudioPlaybackConfiguration implements Parcelable {
@Override
public String toString() {
return "AudioPlaybackConfiguration piid:" + mPlayerIId
+ " deviceId:" + mDeviceId
+ " type:" + toLogFriendlyPlayerType(mPlayerType)
+ " u/pid:" + mClientUid + "/" + mClientPid
+ " state:" + toLogFriendlyPlayerState(mPlayerState)
@@ -571,6 +623,7 @@ 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";
default:
return "unknown player state - FIXME";
}

View File

@@ -1824,6 +1824,7 @@ public class AudioTrack extends PlayerBase
@Override
protected void finalize() {
tryToDisableNativeRoutingCallback();
baseRelease();
native_finalize();
}
@@ -2717,9 +2718,15 @@ public class AudioTrack extends PlayerBase
}
private void startImpl() {
synchronized (mRoutingChangeListeners) {
if (!mEnableSelfRoutingMonitor) {
testEnableNativeRoutingCallbacksLocked();
mEnableSelfRoutingMonitor = true;
}
}
synchronized(mPlayStateLock) {
baseStart();
native_start();
baseStart(native_getRoutedDeviceId());
if (mPlayState == PLAYSTATE_PAUSED_STOPPING) {
mPlayState = PLAYSTATE_STOPPING;
} else {
@@ -2757,6 +2764,7 @@ public class AudioTrack extends PlayerBase
mPlayStateLock.notify();
}
}
tryToDisableNativeRoutingCallback();
}
/**
@@ -3496,12 +3504,21 @@ public class AudioTrack extends PlayerBase
return null;
}
private void tryToDisableNativeRoutingCallback() {
synchronized (mRoutingChangeListeners) {
if (mEnableSelfRoutingMonitor) {
mEnableSelfRoutingMonitor = false;
testDisableNativeRoutingCallbacksLocked();
}
}
}
/*
* Call BEFORE adding a routing callback handler.
*/
@GuardedBy("mRoutingChangeListeners")
private void testEnableNativeRoutingCallbacksLocked() {
if (mRoutingChangeListeners.size() == 0) {
if (mRoutingChangeListeners.size() == 0 && !mEnableSelfRoutingMonitor) {
native_enableDeviceCallback();
}
}
@@ -3511,7 +3528,7 @@ public class AudioTrack extends PlayerBase
*/
@GuardedBy("mRoutingChangeListeners")
private void testDisableNativeRoutingCallbacksLocked() {
if (mRoutingChangeListeners.size() == 0) {
if (mRoutingChangeListeners.size() == 0 && !mEnableSelfRoutingMonitor) {
native_disableDeviceCallback();
}
}
@@ -3528,6 +3545,9 @@ public class AudioTrack extends PlayerBase
private ArrayMap<AudioRouting.OnRoutingChangedListener,
NativeRoutingEventHandlerDelegate> mRoutingChangeListeners = new ArrayMap<>();
@GuardedBy("mRoutingChangeListeners")
private boolean mEnableSelfRoutingMonitor;
/**
* Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of routing
* changes on this AudioTrack.
@@ -3627,6 +3647,7 @@ public class AudioTrack extends PlayerBase
*/
private void broadcastRoutingChange() {
AudioManager.resetAudioPortGeneration();
baseUpdateDeviceId(getRoutedDevice());
synchronized (mRoutingChangeListeners) {
for (NativeRoutingEventHandlerDelegate delegate : mRoutingChangeListeners.values()) {
delegate.notifyClient();

View File

@@ -22,6 +22,8 @@ import android.annotation.SystemApi;
import com.android.internal.util.Preconditions;
import java.util.ArrayList;
/**
* The HwAudioSource represents the audio playback directly from a source audio device.
* It currently supports {@link HwAudioSource#start()} and {@link HwAudioSource#stop()} only
@@ -130,10 +132,32 @@ public class HwAudioSource extends PlayerBase {
*/
public void start() {
Preconditions.checkState(!isPlaying(), "HwAudioSource is currently playing");
baseStart();
mNativeHandle = AudioSystem.startAudioSource(
mAudioDeviceInfo.getPort().activeConfig(),
mAudioAttributes);
// FIXME: b/174876389 clean up device id reporting
baseStart(getDeviceId());
}
private int getDeviceId() {
ArrayList<AudioPatch> patches = new ArrayList<AudioPatch>();
if (AudioManager.listAudioPatches(patches) != AudioManager.SUCCESS) {
return 0;
}
for (int i = 0; i < patches.size(); i++) {
AudioPatch patch = patches.get(i);
AudioPortConfig[] sources = patch.sources();
AudioPortConfig[] sinks = patch.sinks();
if ((sources != null) && (sources.length > 0)) {
for (int c = 0; c < sources.length; c++) {
if (sources[c].port().id() == mAudioDeviceInfo.getId()) {
return sinks[c].port().id();
}
}
}
}
return 0;
}
/**

View File

@@ -62,7 +62,7 @@ interface IAudioService {
oneway void playerAttributes(in int piid, in AudioAttributes attr);
oneway void playerEvent(in int piid, in int event);
oneway void playerEvent(in int piid, in int event, in int deviceId);
oneway void releasePlayer(in int piid);

View File

@@ -1352,7 +1352,6 @@ public class MediaPlayer extends PlayerBase
}
private void startImpl() {
baseStart();
stayAwake(true);
_start();
}
@@ -1378,7 +1377,6 @@ public class MediaPlayer extends PlayerBase
public void stop() throws IllegalStateException {
stayAwake(false);
_stop();
baseStop();
}
private native void _stop() throws IllegalStateException;
@@ -1392,7 +1390,6 @@ public class MediaPlayer extends PlayerBase
public void pause() throws IllegalStateException {
stayAwake(false);
_pause();
basePause();
}
private native void _pause() throws IllegalStateException;
@@ -1497,13 +1494,60 @@ public class MediaPlayer extends PlayerBase
return null;
}
/**
* Sends device list change notification to all listeners.
*/
private void broadcastRoutingChange() {
AudioManager.resetAudioPortGeneration();
synchronized (mRoutingChangeListeners) {
// Prevent the case where an event is triggered by registering a routing change
// listener via the media player.
if (mEnableSelfRoutingMonitor) {
baseUpdateDeviceId(getRoutedDevice());
}
for (NativeRoutingEventHandlerDelegate delegate
: mRoutingChangeListeners.values()) {
delegate.notifyClient();
}
}
}
/*
* Call BEFORE adding a routing callback handler or AFTER removing a routing callback handler.
* Call BEFORE adding a routing callback handler.
*/
@GuardedBy("mRoutingChangeListeners")
private void enableNativeRoutingCallbacksLocked(boolean enabled) {
if (mRoutingChangeListeners.size() == 0) {
native_enableDeviceCallback(enabled);
private void testEnableNativeRoutingCallbacksLocked() {
if (mRoutingChangeListeners.size() == 0 && !mEnableSelfRoutingMonitor) {
native_enableDeviceCallback(true);
}
}
private void tryToEnableNativeRoutingCallback() {
synchronized (mRoutingChangeListeners) {
if (!mEnableSelfRoutingMonitor) {
testEnableNativeRoutingCallbacksLocked();
mEnableSelfRoutingMonitor = true;
}
}
}
private void tryToDisableNativeRoutingCallback() {
synchronized (mRoutingChangeListeners) {
if (mEnableSelfRoutingMonitor) {
mEnableSelfRoutingMonitor = false;
testDisableNativeRoutingCallbacksLocked();
}
}
}
/*
* Call AFTER removing a routing callback handler.
*/
@GuardedBy("mRoutingChangeListeners")
private void testDisableNativeRoutingCallbacksLocked() {
if (mRoutingChangeListeners.size() == 0 && !mEnableSelfRoutingMonitor) {
native_enableDeviceCallback(false);
}
}
@@ -1516,6 +1560,9 @@ public class MediaPlayer extends PlayerBase
private ArrayMap<AudioRouting.OnRoutingChangedListener,
NativeRoutingEventHandlerDelegate> mRoutingChangeListeners = new ArrayMap<>();
@GuardedBy("mRoutingChangeListeners")
private boolean mEnableSelfRoutingMonitor;
/**
* Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of routing
* changes on this MediaPlayer.
@@ -1529,7 +1576,7 @@ public class MediaPlayer extends PlayerBase
Handler handler) {
synchronized (mRoutingChangeListeners) {
if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
enableNativeRoutingCallbacksLocked(true);
testEnableNativeRoutingCallbacksLocked();
mRoutingChangeListeners.put(
listener, new NativeRoutingEventHandlerDelegate(this, listener,
handler != null ? handler : mEventHandler));
@@ -1548,8 +1595,8 @@ public class MediaPlayer extends PlayerBase
synchronized (mRoutingChangeListeners) {
if (mRoutingChangeListeners.containsKey(listener)) {
mRoutingChangeListeners.remove(listener);
enableNativeRoutingCallbacksLocked(false);
}
testDisableNativeRoutingCallbacksLocked();
}
}
@@ -3301,6 +3348,7 @@ public class MediaPlayer extends PlayerBase
@Override
protected void finalize() {
tryToDisableNativeRoutingCallback();
baseRelease();
native_finalize();
}
@@ -3415,6 +3463,8 @@ public class MediaPlayer extends PlayerBase
case MEDIA_STOPPED:
{
tryToDisableNativeRoutingCallback();
baseStop();
TimeProvider timeProvider = mTimeProvider;
if (timeProvider != null) {
timeProvider.onStopped();
@@ -3423,8 +3473,16 @@ public class MediaPlayer extends PlayerBase
break;
case MEDIA_STARTED:
{
baseStart(native_getRoutedDeviceId());
tryToEnableNativeRoutingCallback();
}
// fall through
case MEDIA_PAUSED:
{
if (msg.what == MEDIA_PAUSED) {
basePause();
}
TimeProvider timeProvider = mTimeProvider;
if (timeProvider != null) {
timeProvider.onPaused(msg.what == MEDIA_PAUSED);
@@ -3590,14 +3648,8 @@ public class MediaPlayer extends PlayerBase
break;
case MEDIA_AUDIO_ROUTING_CHANGED:
AudioManager.resetAudioPortGeneration();
synchronized (mRoutingChangeListeners) {
for (NativeRoutingEventHandlerDelegate delegate
: mRoutingChangeListeners.values()) {
delegate.notifyClient();
}
}
return;
broadcastRoutingChange();
return;
case MEDIA_TIME_DISCONTINUITY:
final OnMediaTimeDiscontinuityListener mediaTimeListener;
@@ -3803,6 +3855,7 @@ public class MediaPlayer extends PlayerBase
@Override
public void onCompletion(MediaPlayer mp) {
baseStop();
tryToDisableNativeRoutingCallback();
}
};

View File

@@ -90,6 +90,8 @@ public abstract class PlayerBase {
private float mPanMultiplierR = 1.0f;
@GuardedBy("mLock")
private float mVolMultiplier = 1.0f;
@GuardedBy("mLock")
private int mDeviceId;
/**
* Constructor. Must be given audio attributes, as they are required for AppOps.
@@ -152,14 +154,35 @@ public abstract class PlayerBase {
}
}
private void updateState(int state) {
void baseUpdateDeviceId(@Nullable AudioDeviceInfo deviceInfo) {
int deviceId = 0;
if (deviceInfo != null) {
deviceId = deviceInfo.getId();
}
int piid;
synchronized (mLock) {
piid = mPlayerIId;
mDeviceId = deviceId;
}
try {
getService().playerEvent(piid,
AudioPlaybackConfiguration.PLAYER_UPDATE_DEVICE_ID, deviceId);
} catch (RemoteException e) {
Log.e(TAG, "Error talking to audio service, "
+ deviceId
+ " device id will not be tracked for piid=" + piid, e);
}
}
private void updateState(int state, int deviceId) {
final int piid;
synchronized (mLock) {
mState = state;
piid = mPlayerIId;
mDeviceId = deviceId;
}
try {
getService().playerEvent(piid, state);
getService().playerEvent(piid, state, deviceId);
} catch (RemoteException e) {
Log.e(TAG, "Error talking to audio service, "
+ AudioPlaybackConfiguration.toLogFriendlyPlayerState(state)
@@ -167,9 +190,11 @@ public abstract class PlayerBase {
}
}
void baseStart() {
if (DEBUG) { Log.v(TAG, "baseStart() piid=" + mPlayerIId); }
updateState(AudioPlaybackConfiguration.PLAYER_STATE_STARTED);
void baseStart(int deviceId) {
if (DEBUG) {
Log.v(TAG, "baseStart() piid=" + mPlayerIId + " deviceId=" + deviceId);
}
updateState(AudioPlaybackConfiguration.PLAYER_STATE_STARTED, deviceId);
synchronized (mLock) {
if (isRestricted_sync()) {
playerSetVolume(true/*muting*/,0, 0);
@@ -191,12 +216,12 @@ public abstract class PlayerBase {
void basePause() {
if (DEBUG) { Log.v(TAG, "basePause() piid=" + mPlayerIId); }
updateState(AudioPlaybackConfiguration.PLAYER_STATE_PAUSED);
updateState(AudioPlaybackConfiguration.PLAYER_STATE_PAUSED, 0);
}
void baseStop() {
if (DEBUG) { Log.v(TAG, "baseStop() piid=" + mPlayerIId); }
updateState(AudioPlaybackConfiguration.PLAYER_STATE_STOPPED);
updateState(AudioPlaybackConfiguration.PLAYER_STATE_STOPPED, 0);
}
void baseSetPan(float pan) {

View File

@@ -303,7 +303,8 @@ public class SoundPool extends PlayerBase {
*/
public final int play(int soundID, float leftVolume, float rightVolume,
int priority, int loop, float rate) {
baseStart();
// FIXME: b/174876164 implement device id for soundpool
baseStart(0);
return _play(soundID, leftVolume, rightVolume, priority, loop, rate);
}

View File

@@ -8777,8 +8777,14 @@ public class AudioService extends IAudioService.Stub
mPlaybackMonitor.playerAttributes(piid, attr, Binder.getCallingUid());
}
public void playerEvent(int piid, int event) {
mPlaybackMonitor.playerEvent(piid, event, Binder.getCallingUid());
/**
* Update player event
* @param piid Player id to update
* @param event The new player event
* @param deviceId The new player device id
*/
public void playerEvent(int piid, int event, int deviceId) {
mPlaybackMonitor.playerEvent(piid, event, deviceId, Binder.getCallingUid());
}
public void playerHasOpPlayAudio(int piid, boolean hasOpPlayAudio) {

View File

@@ -233,15 +233,25 @@ public final class PlaybackActivityMonitor
}
}
public void playerEvent(int piid, int event, int binderUid) {
if (DEBUG) { Log.v(TAG, String.format("playerEvent(piid=%d, event=%d)", piid, event)); }
/**
* Update player event
* @param piid Player id to update
* @param event The new player event
* @param deviceId The new player device id
* @param binderUid Calling binder uid
*/
public void playerEvent(int piid, int event, int deviceId, int binderUid) {
if (DEBUG) {
Log.v(TAG, String.format("playerEvent(piid=%d, deviceId=%d, event=%d)",
piid, deviceId, event));
}
final boolean change;
synchronized(mPlayerLock) {
final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid));
if (apc == null) {
return;
}
sEventLogger.log(new PlayerEvent(piid, event));
sEventLogger.log(new PlayerEvent(piid, event, deviceId));
if (event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
for (Integer uidInteger: mBannedUids) {
if (checkBanPlayer(apc, uidInteger.intValue())) {
@@ -259,7 +269,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);
change = apc.handleStateEvent(event, deviceId);
} else {
Log.e(TAG, "Error handling event " + event);
change = false;
@@ -289,7 +299,8 @@ public final class PlaybackActivityMonitor
mPlayers.remove(new Integer(piid));
mDuckingManager.removeReleased(apc);
checkVolumeForPrivilegedAlarm(apc, AudioPlaybackConfiguration.PLAYER_STATE_RELEASED);
change = apc.handleStateEvent(AudioPlaybackConfiguration.PLAYER_STATE_RELEASED);
change = apc.handleStateEvent(AudioPlaybackConfiguration.PLAYER_STATE_RELEASED,
AudioPlaybackConfiguration.PLAYER_DEVICEID_INVALID);
}
}
if (change) {
@@ -868,16 +879,19 @@ public final class PlaybackActivityMonitor
// only keeping the player interface ID as it uniquely identifies the player in the event
final int mPlayerIId;
final int mState;
final int mDeviceId;
PlayerEvent(int piid, int state) {
PlayerEvent(int piid, int state, int deviceId) {
mPlayerIId = piid;
mState = state;
mDeviceId = deviceId;
}
@Override
public String eventToString() {
return new StringBuilder("player piid:").append(mPlayerIId).append(" state:")
.append(AudioPlaybackConfiguration.toLogFriendlyPlayerState(mState)).toString();
.append(AudioPlaybackConfiguration.toLogFriendlyPlayerState(mState))
.append(" DeviceId:").append(mDeviceId).toString();
}
}