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

Commit a5030256 authored by Eric Laurent's avatar Eric Laurent
Browse files

AudioEffect: add isEffectSupportedForDevice() API

Add AudioEffect.isEffectSupportedForDevice() @SystemApi
for apps to query if an audio effect can be created and
attached to a particular device without actually calling
the constructor and checking for exceptions.

Bug: 150699608
Test: CTS and GTS Tests for audio effects
Change-Id: Ia03af6114a5cafdc46d5d0cb8130fc0165ca93ac
parent 3bdd15fb
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -4403,6 +4403,7 @@ package android.media.audiofx {
  public class AudioEffect {
    ctor @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public AudioEffect(@NonNull java.util.UUID, @NonNull android.media.AudioDeviceAttributes);
    method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public static boolean isEffectSupportedForDevice(@NonNull java.util.UUID, @NonNull android.media.AudioDeviceAttributes);
  }
}
+38 −5
Original line number Diff line number Diff line
@@ -477,13 +477,21 @@ public class AudioEffect {
    @SystemApi
    @RequiresPermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS)
    public AudioEffect(@NonNull UUID uuid, @NonNull AudioDeviceAttributes device) {
        this(EFFECT_TYPE_NULL, Objects.requireNonNull(uuid), 0, -2, Objects.requireNonNull(device));
        this(EFFECT_TYPE_NULL, Objects.requireNonNull(uuid),
                0, -2, Objects.requireNonNull(device));
    }

    private AudioEffect(UUID type, UUID uuid, int priority,
            int audioSession, @Nullable AudioDeviceAttributes device)
            throws IllegalArgumentException, UnsupportedOperationException,
            RuntimeException {
        this(type, uuid, priority, audioSession, device, false);
    }

    private AudioEffect(UUID type, UUID uuid, int priority,
            int audioSession, @Nullable AudioDeviceAttributes device, boolean probe)
            throws IllegalArgumentException, UnsupportedOperationException,
            RuntimeException {
        int[] id = new int[1];
        Descriptor[] desc = new Descriptor[1];

@@ -498,7 +506,7 @@ public class AudioEffect {
        int initResult = native_setup(new WeakReference<AudioEffect>(this),
                type.toString(), uuid.toString(), priority, audioSession,
                deviceType, deviceAddress,
                id, desc, ActivityThread.currentOpPackageName());
                id, desc, ActivityThread.currentOpPackageName(), probe);
        if (initResult != SUCCESS && initResult != ALREADY_EXISTS) {
            Log.e(TAG, "Error code " + initResult
                    + " when initializing AudioEffect.");
@@ -517,10 +525,35 @@ public class AudioEffect {
        }
        mId = id[0];
        mDescriptor = desc[0];
        if (!probe) {
            synchronized (mStateLock) {
                mState = STATE_INITIALIZED;
            }
        }
    }

    /**
     * Checks if an AudioEffect identified by the supplied uuid can be attached
     * to an audio device described by the supplied AudioDeviceAttributes.
     * @param uuid unique identifier of a particular effect implementation.
     * @param device the device the effect would be attached to.
     * @return true if possible, false otherwise.
     * @hide
     */
    @SystemApi
    @RequiresPermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS)
    public static boolean isEffectSupportedForDevice(
            @NonNull UUID uuid, @NonNull AudioDeviceAttributes device) {
        try {
            AudioEffect fx = new AudioEffect(
                    EFFECT_TYPE_NULL, Objects.requireNonNull(uuid),
                    0, -2, Objects.requireNonNull(device), true);
            fx.release();
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * Releases the native AudioEffect resources. It is a good practice to
@@ -1340,7 +1373,7 @@ public class AudioEffect {
    private native final int native_setup(Object audioeffect_this, String type,
            String uuid, int priority, int audioSession,
            int deviceType, String deviceAddress, int[] id, Object[] desc,
            String opPackageName);
            String opPackageName, boolean probe);

    private native final void native_finalize();

+12 −4
Original line number Diff line number Diff line
@@ -270,7 +270,7 @@ static jint
android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
        jstring type, jstring uuid, jint priority, jint sessionId,
        jint deviceType, jstring deviceAddress,
        jintArray jId, jobjectArray javadesc, jstring opPackageName)
        jintArray jId, jobjectArray javadesc, jstring opPackageName, jboolean probe)
{
    ALOGV("android_media_AudioEffect_native_setup");
    AudioEffectJniStorage* lpJniStorage = NULL;
@@ -345,12 +345,14 @@ android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_t
                                    &lpJniStorage->mCallbackData,
                                    (audio_session_t) sessionId,
                                    AUDIO_IO_HANDLE_NONE,
                                    device);
                                    device,
                                    probe);
    if (lpAudioEffect == 0) {
        ALOGE("Error creating AudioEffect");
        goto setup_failure;
    }


    lStatus = AudioEffectJni::translateNativeErrorToJava(lpAudioEffect->initCheck());
    if (lStatus != AUDIOEFFECT_SUCCESS && lStatus != AUDIOEFFECT_ERROR_ALREADY_EXISTS) {
        ALOGE("AudioEffect initCheck failed %d", lStatus);
@@ -387,7 +389,13 @@ android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_t
    env->SetObjectArrayElement(javadesc, 0, jdesc);
    env->DeleteLocalRef(jdesc);

    // In probe mode, release the native object and clear our strong reference
    // to force all method calls from JAVA to be rejected.
    if (probe) {
        setAudioEffect(env, thiz, 0);
    } else {
        setAudioEffect(env, thiz, lpAudioEffect);
    }

    env->SetLongField(thiz, fields.fidJniData, (jlong)lpJniStorage);

@@ -766,7 +774,7 @@ android_media_AudioEffect_native_queryPreProcessings(JNIEnv *env, jclass clazz _
// Dalvik VM type signatures
static const JNINativeMethod gMethods[] = {
    {"native_init",          "()V",      (void *)android_media_AudioEffect_native_init},
    {"native_setup",         "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;IIILjava/lang/String;[I[Ljava/lang/Object;Ljava/lang/String;)I",
    {"native_setup",         "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;IIILjava/lang/String;[I[Ljava/lang/Object;Ljava/lang/String;Z)I",
                                         (void *)android_media_AudioEffect_native_setup},
    {"native_finalize",      "()V",      (void *)android_media_AudioEffect_native_finalize},
    {"native_release",       "()V",      (void *)android_media_AudioEffect_native_release},