Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 56b97b74 authored by Jean-Michel Trivi's avatar Jean-Michel Trivi
Browse files

Add SystemApi for querying audio routing

  Add a new @SystemApi for querying audio playback routing for
a given AudioAttributes.
  Note that unlike the (@UnsupportedUsage) getDevicesForStream API,
this method takes into account any current dynamic policy (unless
it is based on uid).

Bug: 144440677
Test: atest AudioServiceHostTest
Change-Id: I0431e792a209865ffa771a521c2f0792c07ce5d4
parent 8413638d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+5 −0
Original line number Diff line number Diff line
@@ -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);
+43 −0
Original line number Diff line number Diff line
@@ -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[] = {
+28 −4
Original line number Diff line number Diff line
@@ -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);
    }
}
+20 −0
Original line number Diff line number Diff line
@@ -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)
Loading