Change Java APIs to use multiple routed devices
After you open an audio stream, you can call getRoutedDevice() to
get which output device is actually used.
However, if you play an ALARM with a headset attached, audio comes
out of both the speaker and the headset. This is not properly reflected
with our current APIs.
This CL makes changes to pass multiple devices to our APIs.
Bug: 367816690
Test: Alarm with and without USB headset
Flag: android.media.audio.routed_device_ids
Change-Id: I245e47449d64fee2dccbc750f42bfb4ac8d615c8
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index f9d00ed..5a18392 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -584,14 +584,23 @@
return lpRecorder->setInputDevice(device_id) == NO_ERROR;
}
-static jint android_media_AudioRecord_getRoutedDeviceId(
- JNIEnv *env, jobject thiz) {
-
+static jintArray android_media_AudioRecord_getRoutedDeviceIds(JNIEnv *env, jobject thiz) {
sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
- if (lpRecorder == 0) {
- return 0;
+ if (lpRecorder == NULL) {
+ return NULL;
}
- return (jint)lpRecorder->getRoutedDeviceId();
+ DeviceIdVector deviceIds = lpRecorder->getRoutedDeviceIds();
+ jintArray result;
+ result = env->NewIntArray(deviceIds.size());
+ if (result == NULL) {
+ return NULL;
+ }
+ jint *values = env->GetIntArrayElements(result, 0);
+ for (unsigned int i = 0; i < deviceIds.size(); i++) {
+ values[i++] = static_cast<jint>(deviceIds[i]);
+ }
+ env->ReleaseIntArrayElements(result, values, 0);
+ return result;
}
// Enable and Disable Callback methods are synchronized on the Java side
@@ -821,8 +830,7 @@
// name, signature, funcPtr
{"native_start", "(II)I", (void *)android_media_AudioRecord_start},
{"native_stop", "()V", (void *)android_media_AudioRecord_stop},
- {"native_setup",
- "(Ljava/lang/Object;Ljava/lang/Object;[IIIII[ILandroid/os/Parcel;JII)I",
+ {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;[IIIII[ILandroid/os/Parcel;JII)I",
(void *)android_media_AudioRecord_setup},
{"native_finalize", "()V", (void *)android_media_AudioRecord_finalize},
{"native_release", "()V", (void *)android_media_AudioRecord_release},
@@ -846,7 +854,7 @@
{"native_getMetrics", "()Landroid/os/PersistableBundle;",
(void *)android_media_AudioRecord_native_getMetrics},
{"native_setInputDevice", "(I)Z", (void *)android_media_AudioRecord_setInputDevice},
- {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioRecord_getRoutedDeviceId},
+ {"native_getRoutedDeviceIds", "()[I", (void *)android_media_AudioRecord_getRoutedDeviceIds},
{"native_enableDeviceCallback", "()V",
(void *)android_media_AudioRecord_enableDeviceCallback},
{"native_disableDeviceCallback", "()V",
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 1557f9e..5d4d1ce 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -1190,15 +1190,23 @@
}
return lpTrack->setOutputDevice(device_id) == NO_ERROR;
}
-
-static jint android_media_AudioTrack_getRoutedDeviceId(
- JNIEnv *env, jobject thiz) {
-
+static jintArray android_media_AudioTrack_getRoutedDeviceIds(JNIEnv *env, jobject thiz) {
sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
if (lpTrack == NULL) {
- return 0;
+ return NULL;
}
- return (jint)lpTrack->getRoutedDeviceId();
+ DeviceIdVector deviceIds = lpTrack->getRoutedDeviceIds();
+ jintArray result;
+ result = env->NewIntArray(deviceIds.size());
+ if (result == NULL) {
+ return NULL;
+ }
+ jint *values = env->GetIntArrayElements(result, 0);
+ for (unsigned int i = 0; i < deviceIds.size(); i++) {
+ values[i++] = static_cast<jint>(deviceIds[i]);
+ }
+ env->ReleaseIntArrayElements(result, values, 0);
+ return result;
}
static void android_media_AudioTrack_enableDeviceCallback(
@@ -1503,7 +1511,7 @@
(void *)android_media_AudioTrack_setAuxEffectSendLevel},
{"native_attachAuxEffect", "(I)I", (void *)android_media_AudioTrack_attachAuxEffect},
{"native_setOutputDevice", "(I)Z", (void *)android_media_AudioTrack_setOutputDevice},
- {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioTrack_getRoutedDeviceId},
+ {"native_getRoutedDeviceIds", "()[I", (void *)android_media_AudioTrack_getRoutedDeviceIds},
{"native_enableDeviceCallback", "()V",
(void *)android_media_AudioTrack_enableDeviceCallback},
{"native_disableDeviceCallback", "()V",
diff --git a/core/jni/android_media_DeviceCallback.cpp b/core/jni/android_media_DeviceCallback.cpp
index a1a0351..ccdf633 100644
--- a/core/jni/android_media_DeviceCallback.cpp
+++ b/core/jni/android_media_DeviceCallback.cpp
@@ -61,21 +61,20 @@
}
void JNIDeviceCallback::onAudioDeviceUpdate(audio_io_handle_t audioIo,
- audio_port_handle_t deviceId)
-{
+ const DeviceIdVector& deviceIds) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
if (env == NULL) {
return;
}
- ALOGV("%s audioIo %d deviceId %d", __FUNCTION__, audioIo, deviceId);
- env->CallStaticVoidMethod(mClass,
- mPostEventFromNative,
- mObject,
- AUDIO_NATIVE_EVENT_ROUTING_CHANGE, deviceId, 0, NULL);
+ ALOGV("%s audioIo %d deviceIds %s", __FUNCTION__, audioIo, toString(deviceIds).c_str());
+ // Java should query the new device ids once it gets the event.
+ // TODO(b/378505346): Pass the deviceIds to Java to avoid race conditions.
+ env->CallStaticVoidMethod(mClass, mPostEventFromNative, mObject,
+ AUDIO_NATIVE_EVENT_ROUTING_CHANGE, 0 /*arg1*/, 0 /*arg2*/,
+ NULL /*obj*/);
if (env->ExceptionCheck()) {
ALOGW("An exception occurred while notifying an event.");
env->ExceptionClear();
}
}
-
diff --git a/core/jni/android_media_DeviceCallback.h b/core/jni/android_media_DeviceCallback.h
index 7ae788e..0c9ccc8 100644
--- a/core/jni/android_media_DeviceCallback.h
+++ b/core/jni/android_media_DeviceCallback.h
@@ -31,8 +31,7 @@
JNIDeviceCallback(JNIEnv* env, jobject thiz, jobject weak_thiz, jmethodID postEventFromNative);
~JNIDeviceCallback();
- virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
- audio_port_handle_t deviceId);
+ virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo, const DeviceIdVector& deviceIds);
private:
void sendEvent(int event);
diff --git a/media/java/android/media/AudioPlaybackConfiguration.java b/media/java/android/media/AudioPlaybackConfiguration.java
index da50f2c..c085b89 100644
--- a/media/java/android/media/AudioPlaybackConfiguration.java
+++ b/media/java/android/media/AudioPlaybackConfiguration.java
@@ -41,6 +41,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@@ -59,6 +60,8 @@
public static final int PLAYER_UPID_INVALID = -1;
/** @hide */
public static final int PLAYER_DEVICEID_INVALID = 0;
+ /** @hide */
+ public static final int[] PLAYER_DEVICEIDS_INVALID = new int[0];
// information about the implementation
/**
@@ -335,7 +338,7 @@
private final Object mUpdateablePropLock = new Object();
@GuardedBy("mUpdateablePropLock")
- private int mDeviceId;
+ private @NonNull int[] mDeviceIds = AudioPlaybackConfiguration.PLAYER_DEVICEIDS_INVALID;
@GuardedBy("mUpdateablePropLock")
private int mSessionId;
@GuardedBy("mUpdateablePropLock")
@@ -364,7 +367,7 @@
mClientUid = uid;
mClientPid = pid;
mMutedState = 0;
- mDeviceId = PLAYER_DEVICEID_INVALID;
+ mDeviceIds = AudioPlaybackConfiguration.PLAYER_DEVICEIDS_INVALID;
mPlayerState = PLAYER_STATE_IDLE;
mPlayerAttr = pic.mAttributes;
if ((sPlayerDeathMonitor != null) && (pic.mIPlayer != null)) {
@@ -388,10 +391,11 @@
}
// sets the fields that are updateable and require synchronization
- private void setUpdateableFields(int deviceId, int sessionId, int mutedState, FormatInfo format)
+ private void setUpdateableFields(int[] deviceIds, int sessionId, int mutedState,
+ FormatInfo format)
{
synchronized (mUpdateablePropLock) {
- mDeviceId = deviceId;
+ mDeviceIds = deviceIds;
mSessionId = sessionId;
mMutedState = mutedState;
mFormatInfo = format;
@@ -427,7 +431,7 @@
anonymCopy.mClientPid = PLAYER_UPID_INVALID;
anonymCopy.mIPlayerShell = null;
anonymCopy.setUpdateableFields(
- /*deviceId*/ PLAYER_DEVICEID_INVALID,
+ /*deviceIds*/ new int[0],
/*sessionId*/ AudioSystem.AUDIO_SESSION_ALLOCATE,
/*mutedState*/ 0,
FormatInfo.DEFAULT);
@@ -471,14 +475,14 @@
@Deprecated
@FlaggedApi(FLAG_ROUTED_DEVICE_IDS)
public @Nullable AudioDeviceInfo getAudioDeviceInfo() {
- final int deviceId;
+ final int[] deviceIds;
synchronized (mUpdateablePropLock) {
- deviceId = mDeviceId;
+ deviceIds = mDeviceIds;
}
- if (deviceId == PLAYER_DEVICEID_INVALID) {
+ if (deviceIds.length == 0) {
return null;
}
- return AudioManager.getDeviceForPortId(deviceId, AudioManager.GET_DEVICES_OUTPUTS);
+ return AudioManager.getDeviceForPortId(deviceIds[0], AudioManager.GET_DEVICES_OUTPUTS);
}
/**
@@ -491,9 +495,17 @@
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
public @NonNull List<AudioDeviceInfo> getAudioDeviceInfos() {
List<AudioDeviceInfo> audioDeviceInfos = new ArrayList<AudioDeviceInfo>();
- AudioDeviceInfo audioDeviceInfo = getAudioDeviceInfo();
- if (audioDeviceInfo != null) {
- audioDeviceInfos.add(audioDeviceInfo);
+ final int[] deviceIds;
+ synchronized (mUpdateablePropLock) {
+ deviceIds = mDeviceIds;
+ }
+
+ for (int i = 0; i < deviceIds.length; i++) {
+ AudioDeviceInfo audioDeviceInfo = AudioManager.getDeviceForPortId(deviceIds[i],
+ AudioManager.GET_DEVICES_OUTPUTS);
+ if (audioDeviceInfo != null) {
+ audioDeviceInfos.add(audioDeviceInfo);
+ }
}
return audioDeviceInfos;
}
@@ -701,15 +713,15 @@
* @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
+ * @param deviceIds an array of device ids. This can be empty.
+ * <br>Note device ids are non-empty for {@code PLAYER_UPDATE_DEVICE_ID} or
+ * <br>{@code PLAYER_STATE_STARTED} events, as the device ids will be emptied when pausing
+ * <br>or stopping playback. It will be set to active devices 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.
+ * <br>devices change in the middle of playback.
* @return true if the state changed, false otherwise
*/
- public boolean handleStateEvent(int event, int deviceId) {
+ public boolean handleStateEvent(int event, int[] deviceIds) {
boolean changed = false;
synchronized (mUpdateablePropLock) {
@@ -720,8 +732,8 @@
}
if (event == PLAYER_STATE_STARTED || event == PLAYER_UPDATE_DEVICE_ID) {
- changed = changed || (mDeviceId != deviceId);
- mDeviceId = deviceId;
+ changed = changed || !Arrays.equals(mDeviceIds, deviceIds);
+ mDeviceIds = deviceIds;
}
if (changed && (event == PLAYER_STATE_RELEASED) && (mIPlayerShell != null)) {
@@ -801,8 +813,8 @@
@Override
public int hashCode() {
synchronized (mUpdateablePropLock) {
- return Objects.hash(mPlayerIId, mDeviceId, mMutedState, mPlayerType, mClientUid,
- mClientPid, mSessionId);
+ return Objects.hash(mPlayerIId, Arrays.toString(mDeviceIds), mMutedState, mPlayerType,
+ mClientUid, mClientPid, mSessionId);
}
}
@@ -815,7 +827,7 @@
public void writeToParcel(Parcel dest, int flags) {
synchronized (mUpdateablePropLock) {
dest.writeInt(mPlayerIId);
- dest.writeInt(mDeviceId);
+ dest.writeIntArray(mDeviceIds);
dest.writeInt(mMutedState);
dest.writeInt(mPlayerType);
dest.writeInt(mClientUid);
@@ -834,7 +846,10 @@
private AudioPlaybackConfiguration(Parcel in) {
mPlayerIId = in.readInt();
- mDeviceId = in.readInt();
+ mDeviceIds = new int[in.readInt()];
+ for (int i = 0; i < mDeviceIds.length; i++) {
+ mDeviceIds[i] = in.readInt();
+ }
mMutedState = in.readInt();
mPlayerType = in.readInt();
mClientUid = in.readInt();
@@ -855,7 +870,7 @@
AudioPlaybackConfiguration that = (AudioPlaybackConfiguration) o;
return ((mPlayerIId == that.mPlayerIId)
- && (mDeviceId == that.mDeviceId)
+ && Arrays.equals(mDeviceIds, that.mDeviceIds)
&& (mMutedState == that.mMutedState)
&& (mPlayerType == that.mPlayerType)
&& (mClientUid == that.mClientUid)
@@ -868,7 +883,7 @@
StringBuilder apcToString = new StringBuilder();
synchronized (mUpdateablePropLock) {
apcToString.append("AudioPlaybackConfiguration piid:").append(mPlayerIId).append(
- " deviceId:").append(mDeviceId).append(" type:").append(
+ " deviceIds:").append(Arrays.toString(mDeviceIds)).append(" type:").append(
toLogFriendlyPlayerType(mPlayerType)).append(" u/pid:").append(
mClientUid).append(
"/").append(mClientPid).append(" state:").append(
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 9394941..cacd59f 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -1908,17 +1908,37 @@
}
/**
+ * Internal API of getRoutedDevices(). We should not call flag APIs internally.
+ */
+ private @NonNull List<AudioDeviceInfo> getRoutedDevicesInternal() {
+ List<AudioDeviceInfo> audioDeviceInfos = new ArrayList<AudioDeviceInfo>();
+ final int[] deviceIds = native_getRoutedDeviceIds();
+ if (deviceIds == null || deviceIds.length == 0) {
+ return audioDeviceInfos;
+ }
+
+ for (int i = 0; i < deviceIds.length; i++) {
+ AudioDeviceInfo audioDeviceInfo = AudioManager.getDeviceForPortId(deviceIds[i],
+ AudioManager.GET_DEVICES_INPUTS);
+ if (audioDeviceInfo != null) {
+ audioDeviceInfos.add(audioDeviceInfo);
+ }
+ }
+ return audioDeviceInfos;
+ }
+
+ /**
* Returns an {@link AudioDeviceInfo} identifying the current routing of this AudioRecord.
* Note: The query is only valid if the AudioRecord is currently recording. If it is not,
* <code>getRoutedDevice()</code> will return null.
*/
@Override
public AudioDeviceInfo getRoutedDevice() {
- int deviceId = native_getRoutedDeviceId();
- if (deviceId == 0) {
+ final List<AudioDeviceInfo> audioDeviceInfos = getRoutedDevicesInternal();
+ if (audioDeviceInfos.isEmpty()) {
return null;
}
- return AudioManager.getDeviceForPortId(deviceId, AudioManager.GET_DEVICES_INPUTS);
+ return audioDeviceInfos.get(0);
}
/**
@@ -1930,12 +1950,7 @@
@Override
@FlaggedApi(FLAG_ROUTED_DEVICE_IDS)
public @NonNull List<AudioDeviceInfo> getRoutedDevices() {
- List<AudioDeviceInfo> audioDeviceInfos = new ArrayList<AudioDeviceInfo>();
- AudioDeviceInfo audioDeviceInfo = getRoutedDevice();
- if (audioDeviceInfo != null) {
- audioDeviceInfos.add(audioDeviceInfo);
- }
- return audioDeviceInfos;
+ return getRoutedDevicesInternal();
}
/**
@@ -2513,7 +2528,7 @@
int sampleRateInHz, int channelCount, int audioFormat);
private native final boolean native_setInputDevice(int deviceId);
- private native final int native_getRoutedDeviceId();
+ private native int[] native_getRoutedDeviceIds();
private native final void native_enableDeviceCallback();
private native final void native_disableDeviceCallback();
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 93a1831..a5d9adb 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -3023,7 +3023,7 @@
}
}
synchronized(mPlayStateLock) {
- baseStart(0); // unknown device at this point
+ baseStart(new int[0]); // unknown device at this point
native_start();
// FIXME see b/179218630
//baseStart(native_getRoutedDeviceId());
@@ -3784,6 +3784,26 @@
}
/**
+ * Internal API of getRoutedDevices(). We should not call flag APIs internally.
+ */
+ private @NonNull List<AudioDeviceInfo> getRoutedDevicesInternal() {
+ List<AudioDeviceInfo> audioDeviceInfos = new ArrayList<AudioDeviceInfo>();
+ final int[] deviceIds = native_getRoutedDeviceIds();
+ if (deviceIds == null || deviceIds.length == 0) {
+ return audioDeviceInfos;
+ }
+
+ for (int i = 0; i < deviceIds.length; i++) {
+ AudioDeviceInfo audioDeviceInfo = AudioManager.getDeviceForPortId(deviceIds[i],
+ AudioManager.GET_DEVICES_OUTPUTS);
+ if (audioDeviceInfo != null) {
+ audioDeviceInfos.add(audioDeviceInfo);
+ }
+ }
+ return audioDeviceInfos;
+ }
+
+ /**
* Returns an {@link AudioDeviceInfo} identifying the current routing of this AudioTrack.
* Note: The query is only valid if the AudioTrack is currently playing. If it is not,
* <code>getRoutedDevice()</code> will return null.
@@ -3792,11 +3812,11 @@
*/
@Override
public AudioDeviceInfo getRoutedDevice() {
- int deviceId = native_getRoutedDeviceId();
- if (deviceId == 0) {
+ final List<AudioDeviceInfo> audioDeviceInfos = getRoutedDevicesInternal();
+ if (audioDeviceInfos.isEmpty()) {
return null;
}
- return AudioManager.getDeviceForPortId(deviceId, AudioManager.GET_DEVICES_OUTPUTS);
+ return audioDeviceInfos.get(0);
}
/**
@@ -3808,12 +3828,7 @@
@Override
@FlaggedApi(FLAG_ROUTED_DEVICE_IDS)
public @NonNull List<AudioDeviceInfo> getRoutedDevices() {
- List<AudioDeviceInfo> audioDeviceInfos = new ArrayList<AudioDeviceInfo>();
- AudioDeviceInfo audioDeviceInfo = getRoutedDevice();
- if (audioDeviceInfo != null) {
- audioDeviceInfos.add(audioDeviceInfo);
- }
- return audioDeviceInfos;
+ return getRoutedDevicesInternal();
}
private void tryToDisableNativeRoutingCallback() {
@@ -3973,7 +3988,7 @@
*/
private void broadcastRoutingChange() {
AudioManager.resetAudioPortGeneration();
- baseUpdateDeviceId(getRoutedDevice());
+ baseUpdateDeviceIds(getRoutedDevicesInternal());
synchronized (mRoutingChangeListeners) {
for (NativeRoutingEventHandlerDelegate delegate : mRoutingChangeListeners.values()) {
delegate.notifyClient();
@@ -4530,7 +4545,7 @@
private native final int native_setAuxEffectSendLevel(float level);
private native final boolean native_setOutputDevice(int deviceId);
- private native final int native_getRoutedDeviceId();
+ private native int[] native_getRoutedDeviceIds();
private native final void native_enableDeviceCallback();
private native final void native_disableDeviceCallback();
diff --git a/media/java/android/media/HwAudioSource.java b/media/java/android/media/HwAudioSource.java
index 167ab65..68a3aa7 100644
--- a/media/java/android/media/HwAudioSource.java
+++ b/media/java/android/media/HwAudioSource.java
@@ -145,7 +145,14 @@
mAudioAttributes);
if (isPlaying()) {
// FIXME: b/174876389 clean up device id reporting
- baseStart(getDeviceId());
+ // Set as deviceIds empty and create an array with element if device id is valid.
+ int[] deviceIds = AudioPlaybackConfiguration.PLAYER_DEVICEIDS_INVALID;
+ int deviceId = getDeviceId();
+ if (deviceId != 0) {
+ deviceIds = new int[1];
+ deviceIds[0] = deviceId;
+ }
+ baseStart(deviceIds);
}
}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 9fd3f5b..08b0dd3 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -87,7 +87,7 @@
oneway void playerAttributes(in int piid, in AudioAttributes attr);
- oneway void playerEvent(in int piid, in int event, in int eventId);
+ oneway void playerEvent(in int piid, in int event, in int[] eventId);
oneway void releasePlayer(in int piid);
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 158bc7f..f1c2a7a 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1415,7 +1415,7 @@
}
private void startImpl() {
- baseStart(0); // unknown device at this point
+ baseStart(new int[0]); // unknown device at this point
stayAwake(true);
tryToEnableNativeRoutingCallback();
_start();
@@ -1541,6 +1541,26 @@
}
/**
+ * Internal API of getRoutedDevices(). We should not call flag APIs internally.
+ */
+ private @NonNull List<AudioDeviceInfo> getRoutedDevicesInternal() {
+ List<AudioDeviceInfo> audioDeviceInfos = new ArrayList<AudioDeviceInfo>();
+ final int[] deviceIds = native_getRoutedDeviceIds();
+ if (deviceIds == null || deviceIds.length == 0) {
+ return audioDeviceInfos;
+ }
+
+ for (int i = 0; i < deviceIds.length; i++) {
+ AudioDeviceInfo audioDeviceInfo = AudioManager.getDeviceForPortId(deviceIds[i],
+ AudioManager.GET_DEVICES_OUTPUTS);
+ if (audioDeviceInfo != null) {
+ audioDeviceInfos.add(audioDeviceInfo);
+ }
+ }
+ return audioDeviceInfos;
+ }
+
+ /**
* Returns an {@link AudioDeviceInfo} identifying the current routing of this MediaPlayer
* Note: The query is only valid if the MediaPlayer is currently playing.
* If the player is not playing, the returned device can be null or correspond to previously
@@ -1550,11 +1570,11 @@
*/
@Override
public AudioDeviceInfo getRoutedDevice() {
- int deviceId = native_getRoutedDeviceId();
- if (deviceId == 0) {
+ final List<AudioDeviceInfo> audioDeviceInfos = getRoutedDevicesInternal();
+ if (audioDeviceInfos.isEmpty()) {
return null;
}
- return AudioManager.getDeviceForPortId(deviceId, AudioManager.GET_DEVICES_OUTPUTS);
+ return audioDeviceInfos.get(0);
}
/**
@@ -1567,12 +1587,7 @@
@Override
@FlaggedApi(FLAG_ROUTED_DEVICE_IDS)
public @NonNull List<AudioDeviceInfo> getRoutedDevices() {
- List<AudioDeviceInfo> audioDeviceInfos = new ArrayList<AudioDeviceInfo>();
- AudioDeviceInfo audioDeviceInfo = getRoutedDevice();
- if (audioDeviceInfo != null) {
- audioDeviceInfos.add(audioDeviceInfo);
- }
- return audioDeviceInfos;
+ return getRoutedDevicesInternal();
}
/**
@@ -1584,7 +1599,7 @@
// Prevent the case where an event is triggered by registering a routing change
// listener via the media player.
if (mEnableSelfRoutingMonitor) {
- baseUpdateDeviceId(getRoutedDevice());
+ baseUpdateDeviceIds(getRoutedDevicesInternal());
}
for (NativeRoutingEventHandlerDelegate delegate
: mRoutingChangeListeners.values()) {
@@ -1694,7 +1709,7 @@
}
private native final boolean native_setOutputDevice(int deviceId);
- private native final int native_getRoutedDeviceId();
+ private native int[] native_getRoutedDeviceIds();
private native final void native_enableDeviceCallback(boolean enabled);
/**
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index f75bcf3..7af78b8 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -1684,6 +1684,26 @@
}
/**
+ * Internal API of getRoutedDevices(). We should not call flag APIs internally.
+ */
+ private @NonNull List<AudioDeviceInfo> getRoutedDevicesInternal() {
+ List<AudioDeviceInfo> audioDeviceInfos = new ArrayList<AudioDeviceInfo>();
+ final int[] deviceIds = native_getRoutedDeviceIds();
+ if (deviceIds == null || deviceIds.length == 0) {
+ return audioDeviceInfos;
+ }
+
+ for (int i = 0; i < deviceIds.length; i++) {
+ AudioDeviceInfo audioDeviceInfo = AudioManager.getDeviceForPortId(deviceIds[i],
+ AudioManager.GET_DEVICES_INPUTS);
+ if (audioDeviceInfo != null) {
+ audioDeviceInfos.add(audioDeviceInfo);
+ }
+ }
+ return audioDeviceInfos;
+ }
+
+ /**
* Returns an {@link AudioDeviceInfo} identifying the current routing of this MediaRecorder
* Note: The query is only valid if the MediaRecorder is currently recording.
* If the recorder is not recording, the returned device can be null or correspond to previously
@@ -1691,11 +1711,11 @@
*/
@Override
public AudioDeviceInfo getRoutedDevice() {
- int deviceId = native_getRoutedDeviceId();
- if (deviceId == 0) {
+ final List<AudioDeviceInfo> audioDeviceInfos = getRoutedDevicesInternal();
+ if (audioDeviceInfos.isEmpty()) {
return null;
}
- return AudioManager.getDeviceForPortId(deviceId, AudioManager.GET_DEVICES_INPUTS);
+ return audioDeviceInfos.get(0);
}
/**
@@ -1708,12 +1728,7 @@
@Override
@FlaggedApi(FLAG_ROUTED_DEVICE_IDS)
public @NonNull List<AudioDeviceInfo> getRoutedDevices() {
- List<AudioDeviceInfo> audioDeviceInfos = new ArrayList<AudioDeviceInfo>();
- AudioDeviceInfo audioDeviceInfo = getRoutedDevice();
- if (audioDeviceInfo != null) {
- audioDeviceInfos.add(audioDeviceInfo);
- }
- return audioDeviceInfos;
+ return getRoutedDevicesInternal();
}
/*
@@ -1773,7 +1788,7 @@
}
private native final boolean native_setInputDevice(int deviceId);
- private native final int native_getRoutedDeviceId();
+ private native int[] native_getRoutedDeviceIds();
private native final void native_enableDeviceCallback(boolean enabled);
//--------------------------------------------------------------------------
diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java
index 3f44b09..dbf8338ac 100644
--- a/media/java/android/media/PlayerBase.java
+++ b/media/java/android/media/PlayerBase.java
@@ -39,6 +39,8 @@
import com.android.internal.app.IAppOpsService;
import java.lang.ref.WeakReference;
+import java.util.Arrays;
+import java.util.List;
import java.util.Objects;
/**
@@ -91,7 +93,7 @@
@GuardedBy("mLock")
private float mVolMultiplier = 1.0f;
@GuardedBy("mLock")
- private int mDeviceId;
+ private @NonNull int[] mDeviceIds = AudioPlaybackConfiguration.PLAYER_DEVICEIDS_INVALID;
/**
* Constructor. Must be given audio attributes, as they are required for AppOps.
@@ -158,35 +160,36 @@
}
}
- void baseUpdateDeviceId(@Nullable AudioDeviceInfo deviceInfo) {
- int deviceId = 0;
- if (deviceInfo != null) {
- deviceId = deviceInfo.getId();
+ void baseUpdateDeviceIds(@NonNull List<AudioDeviceInfo> deviceInfos) {
+ int[] deviceIds = new int[deviceInfos.size()];
+ for (int i = 0; i < deviceInfos.size(); i++) {
+ deviceIds[i] = deviceInfos.get(i).getId();
}
+
int piid;
synchronized (mLock) {
piid = mPlayerIId;
- mDeviceId = deviceId;
+ mDeviceIds = deviceIds;
}
try {
getService().playerEvent(piid,
- AudioPlaybackConfiguration.PLAYER_UPDATE_DEVICE_ID, deviceId);
+ AudioPlaybackConfiguration.PLAYER_UPDATE_DEVICE_ID, deviceIds);
} catch (RemoteException e) {
Log.e(TAG, "Error talking to audio service, "
- + deviceId
+ + Arrays.toString(deviceIds)
+ " device id will not be tracked for piid=" + piid, e);
}
}
- private void updateState(int state, int deviceId) {
+ private void updateState(int state, @NonNull int[] deviceIds) {
final int piid;
synchronized (mLock) {
mState = state;
piid = mPlayerIId;
- mDeviceId = deviceId;
+ mDeviceIds = deviceIds;
}
try {
- getService().playerEvent(piid, state, deviceId);
+ getService().playerEvent(piid, state, deviceIds);
} catch (RemoteException e) {
Log.e(TAG, "Error talking to audio service, "
+ AudioPlaybackConfiguration.toLogFriendlyPlayerState(state)
@@ -194,11 +197,12 @@
}
}
- void baseStart(int deviceId) {
+ void baseStart(@NonNull int[] deviceIds) {
if (DEBUG) {
- Log.v(TAG, "baseStart() piid=" + mPlayerIId + " deviceId=" + deviceId);
+ Log.v(TAG, "baseStart() piid=" + mPlayerIId + " deviceId="
+ + Arrays.toString(deviceIds));
}
- updateState(AudioPlaybackConfiguration.PLAYER_STATE_STARTED, deviceId);
+ updateState(AudioPlaybackConfiguration.PLAYER_STATE_STARTED, deviceIds);
}
void baseSetStartDelayMs(int delayMs) {
@@ -215,12 +219,12 @@
void basePause() {
if (DEBUG) { Log.v(TAG, "basePause() piid=" + mPlayerIId); }
- updateState(AudioPlaybackConfiguration.PLAYER_STATE_PAUSED, 0);
+ updateState(AudioPlaybackConfiguration.PLAYER_STATE_PAUSED, new int[0]);
}
void baseStop() {
if (DEBUG) { Log.v(TAG, "baseStop() piid=" + mPlayerIId); }
- updateState(AudioPlaybackConfiguration.PLAYER_STATE_STOPPED, 0);
+ updateState(AudioPlaybackConfiguration.PLAYER_STATE_STOPPED, new int[0]);
}
void baseSetPan(float pan) {
diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java
index 7b9ff23..f22cc9c 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -317,7 +317,7 @@
// FIXME: b/174876164 implement device id for soundpool
try {
Trace.traceBegin(Trace.TRACE_TAG_AUDIO, "SoundPool.play");
- baseStart(0);
+ baseStart(new int[0]);
return _play(soundID, leftVolume, rightVolume, priority, loop, rate, getPlayerIId());
} finally {
Trace.traceEnd(Trace.TRACE_TAG_AUDIO);
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index d05ee55..a942300 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -1362,13 +1362,26 @@
return mp->setOutputDevice(device_id) == NO_ERROR;
}
-static jint android_media_MediaPlayer_getRoutedDeviceId(JNIEnv *env, jobject thiz)
+static jintArray android_media_MediaPlayer_getRoutedDeviceIds(JNIEnv *env, jobject thiz)
{
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
if (mp == NULL) {
- return AUDIO_PORT_HANDLE_NONE;
+ return NULL;
}
- return mp->getRoutedDeviceId();
+ DeviceIdVector deviceIds;
+ // TODO: b/379161379 - Should we throw an exception if the result is not ok?
+ mp->getRoutedDeviceIds(deviceIds);
+ jintArray result;
+ result = env->NewIntArray(deviceIds.size());
+ if (result == NULL) {
+ return NULL;
+ }
+ jint* values = env->GetIntArrayElements(result, 0);
+ for (unsigned int i = 0; i < deviceIds.size(); i++) {
+ values[i++] = static_cast<jint>(deviceIds[i]);
+ }
+ env->ReleaseIntArrayElements(result, values, 0);
+ return result;
}
static void android_media_MediaPlayer_enableDeviceCallback(
@@ -1452,7 +1465,8 @@
// AudioRouting
{"native_setOutputDevice", "(I)Z", (void *)android_media_MediaPlayer_setOutputDevice},
- {"native_getRoutedDeviceId", "()I", (void *)android_media_MediaPlayer_getRoutedDeviceId},
+ {"native_getRoutedDeviceIds", "()[I",
+ (void *)android_media_MediaPlayer_getRoutedDeviceIds},
{"native_enableDeviceCallback", "(Z)V", (void *)android_media_MediaPlayer_enableDeviceCallback},
};
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 9a6d5d7..643fc8a 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -722,21 +722,31 @@
return true;
}
-static jint
-android_media_MediaRecorder_getRoutedDeviceId(JNIEnv *env, jobject thiz)
+static jintArray
+android_media_MediaRecorder_getRoutedDeviceIds(JNIEnv *env, jobject thiz)
{
- ALOGV("android_media_MediaRecorder_getRoutedDeviceId");
+ ALOGV("android_media_MediaRecorder_getRoutedDeviceIds");
sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
if (mr == NULL) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
- return AUDIO_PORT_HANDLE_NONE;
+ return NULL;
}
- audio_port_handle_t deviceId;
- process_media_recorder_call(env, mr->getRoutedDeviceId(&deviceId),
- "java/lang/RuntimeException", "getRoutedDeviceId failed.");
- return (jint) deviceId;
+ DeviceIdVector deviceIds;
+ process_media_recorder_call(env, mr->getRoutedDeviceIds(deviceIds),
+ "java/lang/RuntimeException", "getRoutedDeviceIds failed.");
+ jintArray result;
+ result = env->NewIntArray(deviceIds.size());
+ if (result == NULL) {
+ return NULL;
+ }
+ jint* values = env->GetIntArrayElements(result, 0);
+ for (unsigned int i = 0; i < deviceIds.size(); i++) {
+ values[i++] = static_cast<jint>(deviceIds[i]);
+ }
+ env->ReleaseIntArrayElements(result, values, 0);
+ return result;
}
static void
@@ -880,7 +890,8 @@
{"native_getMetrics", "()Landroid/os/PersistableBundle;", (void *)android_media_MediaRecorder_native_getMetrics},
{"native_setInputDevice", "(I)Z", (void *)android_media_MediaRecorder_setInputDevice},
- {"native_getRoutedDeviceId", "()I", (void *)android_media_MediaRecorder_getRoutedDeviceId},
+ {"native_getRoutedDeviceIds", "()[I",
+ (void *)android_media_MediaRecorder_getRoutedDeviceIds},
{"native_enableDeviceCallback", "(Z)V", (void *)android_media_MediaRecorder_enableDeviceCallback},
{"native_getActiveMicrophones", "(Ljava/util/ArrayList;)I", (void *)android_media_MediaRecord_getActiveMicrophones},
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 5f71660..6e6bf80 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -14166,10 +14166,10 @@
* Update player event
* @param piid Player id to update
* @param event The new player event
- * @param eventValue The value associated with this event
+ * @param eventValues The values associated with this event
*/
- public void playerEvent(int piid, int event, int eventValue) {
- mPlaybackMonitor.playerEvent(piid, event, eventValue, Binder.getCallingUid());
+ public void playerEvent(int piid, int event, int[] eventValues) {
+ mPlaybackMonitor.playerEvent(piid, event, eventValues, Binder.getCallingUid());
}
/**
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index e92b518..a62ac82 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -365,10 +365,11 @@
* @param eventValue The value associated with this event
* @param binderUid Calling binder uid
*/
- public void playerEvent(int piid, int event, int eventValue, int binderUid) {
+ public void playerEvent(int piid, int event, int[] eventValues, int binderUid) {
if (DEBUG) {
- Log.v(TAG, TextUtils.formatSimple("playerEvent(piid=%d, event=%s, eventValue=%d)",
- piid, AudioPlaybackConfiguration.playerStateToString(event), eventValue));
+ Log.v(TAG, TextUtils.formatSimple("playerEvent(piid=%d, event=%s, eventValues=%d)",
+ piid, AudioPlaybackConfiguration.playerStateToString(event),
+ Arrays.toString(eventValues)));
}
boolean change;
synchronized(mPlayerLock) {
@@ -382,13 +383,13 @@
// do not log nor dispatch events for "ignored" players other than the release
return;
}
- sEventLogger.enqueue(new PlayerEvent(piid, event, eventValue));
+ sEventLogger.enqueue(new PlayerEvent(piid, event, eventValues));
if (event == AudioPlaybackConfiguration.PLAYER_UPDATE_PORT_ID) {
if (portToPiidSimplification()) {
- mPiidToPortId.put(piid, eventValue);
+ mPiidToPortId.put(piid, eventValues[0]);
} else {
- mPortIdToPiid.put(eventValue, piid);
+ mPortIdToPiid.put(eventValues[0], piid);
}
return;
} else if (event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
@@ -409,7 +410,7 @@
if (checkConfigurationCaller(piid, apc, binderUid)) {
//TODO add generation counter to only update to the latest state
checkVolumeForPrivilegedAlarm(apc, event);
- change = apc.handleStateEvent(event, eventValue);
+ change = apc.handleStateEvent(event, eventValues);
} else {
Log.e(TAG, "Error handling event " + event);
change = false;
@@ -517,7 +518,7 @@
mMutedPlayersAwaitingConnection.remove(Integer.valueOf(piid));
checkVolumeForPrivilegedAlarm(apc, AudioPlaybackConfiguration.PLAYER_STATE_RELEASED);
change = apc.handleStateEvent(AudioPlaybackConfiguration.PLAYER_STATE_RELEASED,
- AudioPlaybackConfiguration.PLAYER_DEVICEID_INVALID);
+ AudioPlaybackConfiguration.PLAYER_DEVICEIDS_INVALID);
if (portToPiidSimplification()) {
mPiidToPortId.delete(piid);
@@ -1336,12 +1337,12 @@
// only keeping the player interface ID as it uniquely identifies the player in the event
final int mPlayerIId;
final int mEvent;
- final int mEventValue;
+ final int[] mEventValues;
- PlayerEvent(int piid, int event, int eventValue) {
+ PlayerEvent(int piid, int event, int[] eventValues) {
mPlayerIId = piid;
mEvent = event;
- mEventValue = eventValue;
+ mEventValues = eventValues;
}
@Override
@@ -1353,36 +1354,38 @@
switch (mEvent) {
case AudioPlaybackConfiguration.PLAYER_UPDATE_PORT_ID:
return AudioPlaybackConfiguration.toLogFriendlyPlayerState(mEvent) + " portId:"
- + mEventValue + " mapped to player piid:" + mPlayerIId;
+ + Arrays.toString(mEventValues) + " mapped to player piid:"
+ + mPlayerIId;
case AudioPlaybackConfiguration.PLAYER_UPDATE_DEVICE_ID:
- if (mEventValue != 0) {
- builder.append(" deviceId:").append(mEventValue);
+ if ((mEventValues.length > 0) && (mEventValues[0] != 0)) {
+ builder.append(" deviceIds:").append(Arrays.toString(mEventValues));
}
return builder.toString();
case AudioPlaybackConfiguration.PLAYER_UPDATE_MUTED:
builder.append(" source:");
- if (mEventValue <= 0) {
+ int eventValue = mEventValues[0];
+ if (eventValue <= 0) {
builder.append("none ");
} else {
- if ((mEventValue & MUTED_BY_MASTER) != 0) {
+ if ((eventValue & MUTED_BY_MASTER) != 0) {
builder.append("masterMute ");
}
- if ((mEventValue & MUTED_BY_STREAM_VOLUME) != 0) {
+ if ((eventValue & MUTED_BY_STREAM_VOLUME) != 0) {
builder.append("streamVolume ");
}
- if ((mEventValue & MUTED_BY_STREAM_MUTED) != 0) {
+ if ((eventValue & MUTED_BY_STREAM_MUTED) != 0) {
builder.append("streamMute ");
}
- if ((mEventValue & MUTED_BY_APP_OPS) != 0) {
+ if ((eventValue & MUTED_BY_APP_OPS) != 0) {
builder.append("appOps ");
}
- if ((mEventValue & MUTED_BY_CLIENT_VOLUME) != 0) {
+ if ((eventValue & MUTED_BY_CLIENT_VOLUME) != 0) {
builder.append("clientVolume ");
}
- if ((mEventValue & MUTED_BY_VOLUME_SHAPER) != 0) {
+ if ((eventValue & MUTED_BY_VOLUME_SHAPER) != 0) {
builder.append("volumeShaper ");
}
- if ((mEventValue & MUTED_BY_PORT_VOLUME) != 0) {
+ if ((eventValue & MUTED_BY_PORT_VOLUME) != 0) {
builder.append("portVolume ");
}
}
@@ -1732,8 +1735,11 @@
synchronized (mPlayerLock) {
int piid = msg.arg1;
+
+ int[] eventValues = new int[1];
+ eventValues[0] = eventValue;
sEventLogger.enqueue(
- new PlayerEvent(piid, PLAYER_UPDATE_MUTED, eventValue));
+ new PlayerEvent(piid, PLAYER_UPDATE_MUTED, eventValues));
final AudioPlaybackConfiguration apc = mPlayers.get(piid);
if (apc == null || !apc.handleMutedEvent(eventValue)) {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/FlashNotificationsControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/FlashNotificationsControllerTest.java
index 0988eea..a55346c 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/FlashNotificationsControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/FlashNotificationsControllerTest.java
@@ -430,7 +430,7 @@
AudioPlaybackConfiguration config = new AudioPlaybackConfiguration(
mock(PlayerBase.PlayerIdCard.class), 0, 0, 0);
config.handleStateEvent(AudioPlaybackConfiguration.PLAYER_STATE_STARTED,
- AudioPlaybackConfiguration.PLAYER_DEVICEID_INVALID);
+ AudioPlaybackConfiguration.PLAYER_DEVICEIDS_INVALID);
AudioAttributes.Builder builder = new AudioAttributes.Builder();
builder.setUsage(AudioAttributes.USAGE_ALARM);
diff --git a/services/tests/servicestests/src/com/android/server/audio/LoudnessCodecHelperTest.java b/services/tests/servicestests/src/com/android/server/audio/LoudnessCodecHelperTest.java
index 84c0ab3..0d44021 100644
--- a/services/tests/servicestests/src/com/android/server/audio/LoudnessCodecHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/LoudnessCodecHelperTest.java
@@ -314,12 +314,13 @@
AudioDeviceInfo[] devicesStatic = AudioManager.getDevicesStatic(GET_DEVICES_OUTPUTS);
assumeTrue(devIdx < devicesStatic.length);
Log.d(TAG, "Out devices number " + devicesStatic.length + ". Picking index " + devIdx);
- int deviceId = devicesStatic[devIdx].getId();
+ int[] deviceIds = new int[1];
+ deviceIds[0] = devicesStatic[devIdx].getId();
PlayerBase.PlayerIdCard idCard = Mockito.mock(PlayerBase.PlayerIdCard.class);
AudioPlaybackConfiguration apc =
new AudioPlaybackConfiguration(idCard, piid, /*uid=*/1, /*pid=*/myPid());
- apc.handleStateEvent(PLAYER_UPDATE_DEVICE_ID, deviceId);
+ apc.handleStateEvent(PLAYER_UPDATE_DEVICE_ID, deviceIds);
apc.handleSessionIdEvent(sessionId);
apc.handleAudioAttributesEvent(new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
index 51c2ad1..687a1ab 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
@@ -200,7 +200,9 @@
AudioPlaybackConfiguration audioPlaybackConfiguration =
new AudioPlaybackConfiguration(
playerIdCard, /* piid= */ 1000, appUid, /* pid= */ 1000);
- audioPlaybackConfiguration.handleStateEvent(PLAYER_STATE_STARTED, /* deviceId= */1);
+ int[] deviceIds = new int[1];
+ deviceIds[0] = 1;
+ audioPlaybackConfiguration.handleStateEvent(PLAYER_STATE_STARTED, deviceIds);
configs.add(audioPlaybackConfiguration);
}
return configs;