Merge "Add SystemApi for querying audio routing"

This commit is contained in:
TreeHugger Robot
2020-01-11 03:10:52 +00:00
committed by Android (Google) Code Review
8 changed files with 143 additions and 4 deletions

View File

@@ -23663,6 +23663,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

View File

@@ -4063,6 +4063,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();
@@ -4090,6 +4094,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);

View File

@@ -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[] = {

View File

@@ -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);
}
}

View File

@@ -4331,6 +4331,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)

View File

@@ -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. */

View File

@@ -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.
}

View File

@@ -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,