diff options
| author | 2020-03-13 14:30:13 -0700 | |
|---|---|---|
| committer | 2020-03-16 13:46:56 -0700 | |
| commit | a50302568731d867467f34681d60a80fe76e52f2 (patch) | |
| tree | abffa16c5f0befc5bc207480976d3bee411d36ad | |
| parent | 3bdd15fbb45911fafbbdd1000311c2320e99cdc3 (diff) | |
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
| -rwxr-xr-x | api/system-current.txt | 1 | ||||
| -rw-r--r-- | media/java/android/media/audiofx/AudioEffect.java | 43 | ||||
| -rw-r--r-- | media/jni/audioeffect/android_media_AudioEffect.cpp | 16 |
3 files changed, 51 insertions, 9 deletions
diff --git a/api/system-current.txt b/api/system-current.txt index 843fef9eca0b..aa2261583620 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -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); } } diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java index 2587350b6830..42635216e98f 100644 --- a/media/java/android/media/audiofx/AudioEffect.java +++ b/media/java/android/media/audiofx/AudioEffect.java @@ -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,8 +525,33 @@ public class AudioEffect { } mId = id[0]; mDescriptor = desc[0]; - synchronized (mStateLock) { - mState = STATE_INITIALIZED; + 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; } } @@ -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(); diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp index 007dd10aba1f..dbe7b4b619c9 100644 --- a/media/jni/audioeffect/android_media_AudioEffect.cpp +++ b/media/jni/audioeffect/android_media_AudioEffect.cpp @@ -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); - setAudioEffect(env, thiz, lpAudioEffect); + // 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}, |