diff options
| -rw-r--r-- | api/current.txt | 1 | ||||
| -rwxr-xr-x | api/system-current.txt | 5 | ||||
| -rw-r--r-- | core/jni/android_media_AudioSystem.cpp | 43 | ||||
| -rw-r--r-- | media/java/android/media/AudioDeviceInfo.java | 32 | ||||
| -rw-r--r-- | media/java/android/media/AudioManager.java | 20 | ||||
| -rw-r--r-- | media/java/android/media/AudioSystem.java | 36 | ||||
| -rw-r--r-- | media/java/android/media/IAudioService.aidl | 2 | ||||
| -rw-r--r-- | services/core/java/com/android/server/audio/AudioService.java | 8 |
8 files changed, 143 insertions, 4 deletions
diff --git a/api/current.txt b/api/current.txt index cba0a3cdf4b0..2f909ebb5e1d 100644 --- a/api/current.txt +++ b/api/current.txt @@ -23640,6 +23640,7 @@ package android.media { field public static final int TYPE_BUILTIN_EARPIECE = 1; // 0x1 field public static final int TYPE_BUILTIN_MIC = 15; // 0xf field public static final int TYPE_BUILTIN_SPEAKER = 2; // 0x2 + field public static final int TYPE_BUILTIN_SPEAKER_SAFE = 24; // 0x18 field public static final int TYPE_BUS = 21; // 0x15 field public static final int TYPE_DOCK = 13; // 0xd field public static final int TYPE_FM = 14; // 0xe diff --git a/api/system-current.txt b/api/system-current.txt index e056419a0ab8..8f20a9a4c187 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -3997,6 +3997,10 @@ package android.media { field public static final int ROLE_OUTPUT = 2; // 0x2 } + public final class AudioDeviceInfo { + field public static final int TYPE_REMOTE_SUBMIX = 25; // 0x19 + } + public final class AudioFocusInfo implements android.os.Parcelable { method public int describeContents(); method @NonNull public android.media.AudioAttributes getAttributes(); @@ -4024,6 +4028,7 @@ package android.media { method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int dispatchAudioFocusChange(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioProductStrategy> getAudioProductStrategies(); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioVolumeGroup> getAudioVolumeGroups(); + method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAddress> getDevicesForAttributes(@NonNull android.media.AudioAttributes); method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMinVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.AudioDeviceAddress getPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy); diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index 79cf0191057d..53327bc9d99c 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -2312,6 +2312,48 @@ android_media_AudioSystem_getPreferredDeviceForStrategy(JNIEnv *env, jobject thi return jStatus; } +static jint +android_media_AudioSystem_getDevicesForAttributes(JNIEnv *env, jobject thiz, + jobject jaa, jobjectArray jDeviceArray) +{ + const jsize maxResultSize = env->GetArrayLength(jDeviceArray); + // the JNI is always expected to provide us with an array capable of holding enough + // devices i.e. the most we ever route a track to. This is preferred over receiving an ArrayList + // with reverse JNI to make the array grow as need as this would be less efficient, and some + // components call this method often + if (jDeviceArray == nullptr || maxResultSize == 0) { + ALOGE("%s invalid array to store AudioDeviceAddress", __FUNCTION__); + return (jint)AUDIO_JAVA_BAD_VALUE; + } + + JNIAudioAttributeHelper::UniqueAaPtr paa = JNIAudioAttributeHelper::makeUnique(); + jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jaa, paa.get()); + if (jStatus != (jint) AUDIO_JAVA_SUCCESS) { + return jStatus; + } + + AudioDeviceTypeAddrVector devices; + jStatus = check_AudioSystem_Command( + AudioSystem::getDevicesForAttributes(*(paa.get()), &devices)); + if (jStatus != NO_ERROR) { + return jStatus; + } + + if (devices.size() > maxResultSize) { + return AUDIO_JAVA_INVALID_OPERATION; + } + size_t index = 0; + jobject jAudioDeviceAddress = NULL; + for (const auto& device : devices) { + jStatus = createAudioDeviceAddressFromNative(env, &jAudioDeviceAddress, &device); + if (jStatus != AUDIO_JAVA_SUCCESS) { + return jStatus; + } + env->SetObjectArrayElement(jDeviceArray, index++, jAudioDeviceAddress); + } + return jStatus; +} + // ---------------------------------------------------------------------------- static const JNINativeMethod gMethods[] = { @@ -2395,6 +2437,7 @@ static const JNINativeMethod gMethods[] = { {"setPreferredDeviceForStrategy", "(IILjava/lang/String;)I", (void *)android_media_AudioSystem_setPreferredDeviceForStrategy}, {"removePreferredDeviceForStrategy", "(I)I", (void *)android_media_AudioSystem_removePreferredDeviceForStrategy}, {"getPreferredDeviceForStrategy", "(I[Landroid/media/AudioDeviceAddress;)I", (void *)android_media_AudioSystem_getPreferredDeviceForStrategy}, + {"getDevicesForAttributes", "(Landroid/media/AudioAttributes;[Landroid/media/AudioDeviceAddress;)I", (void *)android_media_AudioSystem_getDevicesForAttributes} }; static const JNINativeMethod gEventHandlerMethods[] = { diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java index 8293b5f36c04..cb132f5b1101 100644 --- a/media/java/android/media/AudioDeviceInfo.java +++ b/media/java/android/media/AudioDeviceInfo.java @@ -18,6 +18,7 @@ package android.media; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.SystemApi; import android.util.SparseIntArray; import java.lang.annotation.Retention; @@ -127,6 +128,23 @@ public final class AudioDeviceInfo { * A device type describing a Hearing Aid. */ public static final int TYPE_HEARING_AID = 23; + /** + * A device type describing the speaker system (i.e. a mono speaker or stereo speakers) built + * in a device, that is specifically tuned for outputting sounds like notifications and alarms + * (i.e. sounds the user couldn't necessarily anticipate). + * <p>Note that this physical audio device may be the same as {@link #TYPE_BUILTIN_SPEAKER} + * but is driven differently to safely accommodate the different use case.</p> + */ + public static final int TYPE_BUILTIN_SPEAKER_SAFE = 24; + /** + * @hide + * A device type for rerouting audio within the Android framework between mixes and + * system applications. Typically created when using + * {@link android.media.audiopolicy.AudioPolicy} for mixes created with the + * {@link android.media.audiopolicy.AudioMix#ROUTE_FLAG_RENDER} flag. + */ + @SystemApi + public static final int TYPE_REMOTE_SUBMIX = 25; /** @hide */ @IntDef(flag = false, prefix = "TYPE", value = { @@ -228,6 +246,8 @@ public final class AudioDeviceInfo { case TYPE_IP: case TYPE_BUS: case TYPE_HEARING_AID: + case TYPE_BUILTIN_SPEAKER_SAFE: + case TYPE_REMOTE_SUBMIX: return true; default: return false; @@ -253,6 +273,7 @@ public final class AudioDeviceInfo { case TYPE_LINE_DIGITAL: case TYPE_IP: case TYPE_BUS: + case TYPE_REMOTE_SUBMIX: return true; default: return false; @@ -449,6 +470,9 @@ public final class AudioDeviceInfo { INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_IP, TYPE_IP); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BUS, TYPE_BUS); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_HEARING_AID, TYPE_HEARING_AID); + INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_SPEAKER_SAFE, + TYPE_BUILTIN_SPEAKER_SAFE); + INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX, TYPE_REMOTE_SUBMIX); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BUILTIN_MIC, TYPE_BUILTIN_MIC); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET, TYPE_BLUETOOTH_SCO); @@ -468,10 +492,7 @@ public final class AudioDeviceInfo { INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, TYPE_BLUETOOTH_A2DP); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_IP, TYPE_IP); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BUS, TYPE_BUS); - - // not covered here, legacy - //AudioSystem.DEVICE_OUT_REMOTE_SUBMIX - //AudioSystem.DEVICE_IN_REMOTE_SUBMIX + INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_REMOTE_SUBMIX, TYPE_REMOTE_SUBMIX); // privileges mapping to output device EXT_TO_INT_DEVICE_MAPPING = new SparseIntArray(); @@ -498,6 +519,9 @@ public final class AudioDeviceInfo { EXT_TO_INT_DEVICE_MAPPING.put(TYPE_IP, AudioSystem.DEVICE_OUT_IP); EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BUS, AudioSystem.DEVICE_OUT_BUS); EXT_TO_INT_DEVICE_MAPPING.put(TYPE_HEARING_AID, AudioSystem.DEVICE_OUT_HEARING_AID); + EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BUILTIN_SPEAKER_SAFE, + AudioSystem.DEVICE_OUT_SPEAKER_SAFE); + EXT_TO_INT_DEVICE_MAPPING.put(TYPE_REMOTE_SUBMIX, AudioSystem.DEVICE_OUT_REMOTE_SUBMIX); } } diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 34ed5b3caea9..6f53c45f3c77 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -4329,6 +4329,26 @@ public class AudioManager { } } + /** + * @hide + * Get the audio devices that would be used for the routing of the given audio attributes. + * @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 audio devices + * otherwise (typically one device, except for duplicated paths). + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + public @NonNull List<AudioDeviceAddress> getDevicesForAttributes( + @NonNull AudioAttributes attributes) { + Objects.requireNonNull(attributes); + final IAudioService service = getService(); + try { + return service.getDevicesForAttributes(attributes); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Indicate wired accessory connection state change. * @param device type of device connected/disconnected (AudioManager.DEVICE_OUT_xxx) diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index e584addb35fc..fe57e71cca8c 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -33,6 +33,7 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.HashSet; import java.util.Map; +import java.util.Objects; import java.util.Set; /* IF YOU CHANGE ANY OF THE CONSTANTS IN THIS FILE, DO NOT FORGET @@ -1077,6 +1078,41 @@ public class AudioSystem @UnsupportedAppUsage public static native int getDevicesForStream(int stream); + /** + * Do not use directly, see {@link AudioManager#getDevicesForAttributes(AudioAttributes)} + * Get the audio devices that would be used for the routing of the given audio attributes. + * @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 audio devices + * otherwise (typically one device, except for duplicated paths). + */ + public static @NonNull ArrayList<AudioDeviceAddress> getDevicesForAttributes( + @NonNull AudioAttributes attributes) { + Objects.requireNonNull(attributes); + final AudioDeviceAddress[] devices = new AudioDeviceAddress[MAX_DEVICE_ROUTING]; + final int res = getDevicesForAttributes(attributes, devices); + final ArrayList<AudioDeviceAddress> routeDevices = new ArrayList<>(); + if (res != SUCCESS) { + Log.e(TAG, "error " + res + " in getDevicesForAttributes for " + attributes); + return routeDevices; + } + + for (AudioDeviceAddress device : devices) { + if (device != null) { + routeDevices.add(device); + } + } + return routeDevices; + } + + /** + * Maximum number of audio devices a track is ever routed to, determines the size of the + * array passed to {@link #getDevicesForAttributes(AudioAttributes, AudioDeviceAddress[])} + */ + private static final int MAX_DEVICE_ROUTING = 4; + + private static native int getDevicesForAttributes(@NonNull AudioAttributes aa, + @NonNull AudioDeviceAddress[] devices); + /** @hide returns true if master mono is enabled. */ public static native boolean getMasterMono(); /** @hide enables or disables the master mono mode. */ diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index ad7335e5b683..8e8385d382fb 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -272,6 +272,8 @@ interface IAudioService { AudioDeviceAddress getPreferredDeviceForStrategy(in int strategy); + List<AudioDeviceAddress> getDevicesForAttributes(in AudioAttributes attributes); + // WARNING: read warning at top of file, new methods that need to be used by native // code via IAudioManager.h need to be added to the top section. } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 114aac91fbfa..25ecee6b1674 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -1700,6 +1700,14 @@ public class AudioService extends IAudioService.Stub } } + /** @see AudioManager#getDevicesForAttributes(AudioAttributes) */ + public @NonNull ArrayList<AudioDeviceAddress> getDevicesForAttributes( + @NonNull AudioAttributes attributes) { + Objects.requireNonNull(attributes); + enforceModifyAudioRoutingPermission(); + return AudioSystem.getDevicesForAttributes(attributes); + } + /** @see AudioManager#adjustVolume(int, int) */ public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags, |