Merge "Change Java APIs to use multiple routed devices" into main
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;