summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt1
-rwxr-xr-xapi/system-current.txt5
-rw-r--r--core/jni/android_media_AudioSystem.cpp43
-rw-r--r--media/java/android/media/AudioDeviceInfo.java32
-rw-r--r--media/java/android/media/AudioManager.java20
-rw-r--r--media/java/android/media/AudioSystem.java36
-rw-r--r--media/java/android/media/IAudioService.aidl2
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java8
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,