diff --git a/core/api/current.txt b/core/api/current.txt index 7d3d57d095966..4fddf5ffddc6b 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -20955,6 +20955,7 @@ package android.media { method @NonNull public java.util.List getActivePlaybackConfigurations(); method @NonNull public java.util.List getActiveRecordingConfigurations(); method public int getAllowedCapturePolicy(); + method @NonNull public java.util.List getAudioDevicesForAttributes(@NonNull android.media.AudioAttributes); method public int getAudioHwSyncForSession(int); method @NonNull public java.util.List getAvailableCommunicationDevices(); method @Nullable public android.media.AudioDeviceInfo getCommunicationDevice(); diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 21fc6eccc67b1..aec90b2beee0c 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -79,6 +79,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -5665,6 +5666,43 @@ public class AudioManager { } } + /** + * Get the audio devices that would be used for the routing of the given audio attributes. + * These are the devices anticipated to play sound from an {@link AudioTrack} created with + * the specified {@link AudioAttributes}. + * The audio routing can change if audio devices are physically connected or disconnected or + * concurrently through {@link AudioRouting} or {@link MediaRouter}. + * @param attributes the {@link AudioAttributes} for which the routing is being queried + * @return an empty list if there was an issue with the request, a list of + * {@link AudioDeviceInfo} otherwise (typically one device, except for duplicated paths). + */ + public @NonNull List getAudioDevicesForAttributes( + @NonNull AudioAttributes attributes) { + final List devicesForAttributes; + try { + Objects.requireNonNull(attributes); + final IAudioService service = getService(); + devicesForAttributes = service.getDevicesForAttributesUnprotected(attributes); + } catch (Exception e) { + Log.i(TAG, "No audio devices available for specified attributes."); + return Collections.emptyList(); + } + + // Map from AudioDeviceAttributes to AudioDeviceInfo + AudioDeviceInfo[] outputDeviceInfos = getDevicesStatic(GET_DEVICES_OUTPUTS); + List deviceInfosForAttributes = new ArrayList<>(); + for (AudioDeviceAttributes deviceForAttributes : devicesForAttributes) { + for (AudioDeviceInfo deviceInfo : outputDeviceInfos) { + if (deviceForAttributes.getType() == deviceInfo.getType() + && TextUtils.equals(deviceForAttributes.getAddress(), + deviceInfo.getAddress())) { + deviceInfosForAttributes.add(deviceInfo); + } + } + } + return Collections.unmodifiableList(deviceInfosForAttributes); + } + /** * @hide * Volume behavior for an audio device that has no particular volume behavior set. Invalid as diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 7f6fb90297b32..96199a9887043 100755 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -308,6 +308,8 @@ interface IAudioService { List getDevicesForAttributes(in AudioAttributes attributes); + List getDevicesForAttributesUnprotected(in AudioAttributes attributes); + int setAllowedCapturePolicy(in int capturePolicy); int getAllowedCapturePolicy(); diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 69765d2fca2be..0e474f29665ee 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -2611,6 +2611,16 @@ public class AudioService extends IAudioService.Stub return getDevicesForAttributesInt(attributes); } + /** @see AudioManager#getAudioDevicesForAttributes(AudioAttributes) + * This method is similar with AudioService#getDevicesForAttributes, + * only it doesn't enforce permissions because it is used by an unprivileged public API + * instead of the system API. + */ + public @NonNull ArrayList getDevicesForAttributesUnprotected( + @NonNull AudioAttributes attributes) { + return getDevicesForAttributesInt(attributes); + } + /** * @see AudioManager#isMusicActive() * @param remotely true if query is for remote playback (cast), false for local playback.