summaryrefslogtreecommitdiffstats
path: root/media/jni
diff options
context:
space:
mode:
authorEric Laurent <elaurent@google.com>2010-06-14 09:02:13 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2010-06-14 09:02:13 -0700
commit01f7ac64488027492b2909b99d70491e7a391015 (patch)
tree109dc569fe04f88f7ae8525708095cf3f332c37b /media/jni
parent724c52244423feced2677fbd1f905e0b8b0639f2 (diff)
parent948235c06ed0d49190b2f49d9299b473c4dd61a9 (diff)
downloadframeworks_base-01f7ac64488027492b2909b99d70491e7a391015.zip
frameworks_base-01f7ac64488027492b2909b99d70491e7a391015.tar.gz
frameworks_base-01f7ac64488027492b2909b99d70491e7a391015.tar.bz2
Merge "Issue 2667802: [Audio Effect Framework] AudioEffect base class and JNI." into kraken
Diffstat (limited to 'media/jni')
-rw-r--r--media/jni/Android.mk3
-rw-r--r--media/jni/audioeffect/Android.mk16
-rw-r--r--media/jni/audioeffect/android_media_AudioEffect.cpp861
3 files changed, 879 insertions, 1 deletions
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index a6a25cd..698cece 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -65,4 +65,5 @@ LOCAL_MODULE:= libmedia_jni
include $(BUILD_SHARED_LIBRARY)
# build libsoundpool.so
-include $(LOCAL_PATH)/soundpool/Android.mk
+# build libaudioeffect_jni.so
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/jni/audioeffect/Android.mk b/media/jni/audioeffect/Android.mk
new file mode 100644
index 0000000..d03b63b
--- /dev/null
+++ b/media/jni/audioeffect/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ android_media_AudioEffect.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libandroid_runtime \
+ libnativehelper \
+ libmedia
+
+LOCAL_MODULE:= libaudioeffect_jni
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp
new file mode 100644
index 0000000..de01dd3
--- /dev/null
+++ b/media/jni/audioeffect/android_media_AudioEffect.cpp
@@ -0,0 +1,861 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AudioEffects-JNI"
+
+#include <utils/Log.h>
+#include <nativehelper/jni.h>
+#include <nativehelper/JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+#include "media/AudioEffect.h"
+
+using namespace android;
+
+#define AUDIOEFFECT_SUCCESS 0
+#define AUDIOEFFECT_ERROR -1
+#define AUDIOEFFECT_ERROR_ALREADY_EXISTS -2
+#define AUDIOEFFECT_ERROR_NO_INIT -3
+#define AUDIOEFFECT_ERROR_BAD_VALUE -4
+#define AUDIOEFFECT_ERROR_INVALID_OPERATION -5
+#define AUDIOEFFECT_ERROR_NO_MEMORY -6
+#define AUDIOEFFECT_ERROR_DEAD_OBJECT -7
+
+// ----------------------------------------------------------------------------
+static const char* const kClassPathName = "android/media/AudioEffect";
+
+struct fields_t {
+ // these fields provide access from C++ to the...
+ jclass clazzEffect; // AudioEffect class
+ jmethodID midPostNativeEvent; // event post callback method
+ jfieldID fidNativeAudioEffect; // stores in Java the native AudioEffect object
+ jfieldID fidJniData; // stores in Java additional resources used by the native AudioEffect
+ jclass clazzDesc; // AudioEffect.Descriptor class
+ jmethodID midDescCstor; // AudioEffect.Descriptor class constructor
+};
+static fields_t fields;
+
+struct effect_callback_cookie {
+ jclass audioEffect_class; // AudioEffect class
+ jobject audioEffect_ref; // AudioEffect object instance
+ };
+
+// ----------------------------------------------------------------------------
+class AudioEffectJniStorage {
+ public:
+ effect_callback_cookie mCallbackData;
+
+ AudioEffectJniStorage() {
+ }
+
+ ~AudioEffectJniStorage() {
+ }
+
+};
+
+
+static jint translateError(int code) {
+ switch(code) {
+ case NO_ERROR:
+ return AUDIOEFFECT_SUCCESS;
+ case ALREADY_EXISTS:
+ return AUDIOEFFECT_ERROR_ALREADY_EXISTS;
+ case NO_INIT:
+ return AUDIOEFFECT_ERROR_NO_INIT;
+ case BAD_VALUE:
+ return AUDIOEFFECT_ERROR_BAD_VALUE;
+ case INVALID_OPERATION:
+ return AUDIOEFFECT_ERROR_INVALID_OPERATION;
+ case NO_MEMORY:
+ return AUDIOEFFECT_ERROR_NO_MEMORY;
+ case DEAD_OBJECT:
+ return AUDIOEFFECT_ERROR_DEAD_OBJECT;
+ default:
+ return AUDIOEFFECT_ERROR;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+static void effectCallback(int event, void* user, void *info) {
+
+ effect_param_t *p;
+ int arg1 = 0;
+ int arg2 = 0;
+ jobject obj = NULL;
+ jbyteArray array = NULL;
+ jbyte *bytes;
+ bool param;
+ size_t size;
+
+ effect_callback_cookie *callbackInfo = (effect_callback_cookie *)user;
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+ LOGV("effectCallback: callbackInfo %p, audioEffect_ref %p audioEffect_class %p",
+ callbackInfo,
+ callbackInfo->audioEffect_ref,
+ callbackInfo->audioEffect_class);
+
+ if (!user || !env) {
+ LOGW("effectCallback error user %p, env %p", user, env);
+ return;
+ }
+
+ switch (event) {
+ case AudioEffect::EVENT_CONTROL_STATUS_CHANGED:
+ if (info == 0) {
+ LOGW("EVENT_CONTROL_STATUS_CHANGED info == NULL");
+ goto effectCallback_Exit;
+ }
+ param = *(bool *)info;
+ arg1 = (int)param;
+ LOGV("EVENT_CONTROL_STATUS_CHANGED");
+ break;
+ case AudioEffect::EVENT_ENABLE_STATUS_CHANGED:
+ if (info == 0) {
+ LOGW("EVENT_ENABLE_STATUS_CHANGED info == NULL");
+ goto effectCallback_Exit;
+ }
+ param = *(bool *)info;
+ arg1 = (int)param;
+ LOGV("EVENT_ENABLE_STATUS_CHANGED");
+ break;
+ case AudioEffect::EVENT_PARAMETER_CHANGED:
+ if (info == 0) {
+ LOGW("EVENT_PARAMETER_CHANGED info == NULL");
+ goto effectCallback_Exit;
+ }
+ p = (effect_param_t *)info;
+ if (p->psize == 0 || p->vsize == 0) {
+ goto effectCallback_Exit;
+ }
+ // arg1 contains offset of parameter value from start of byte array
+ arg1 = sizeof(effect_param_t) + ((p->psize - 1) / sizeof(int) + 1) * sizeof(int);
+ size = arg1 + p->vsize;
+ array = env->NewByteArray(size);
+ if (array == NULL) {
+ LOGE("effectCallback: Couldn't allocate byte array for parameter data");
+ goto effectCallback_Exit;
+ }
+ bytes = env->GetByteArrayElements(array, NULL);
+ memcpy(bytes, p, size);
+ env->ReleaseByteArrayElements(array, bytes, 0);
+ obj = array;
+ LOGV("EVENT_PARAMETER_CHANGED");
+ break;
+ case AudioEffect::EVENT_ERROR:
+ LOGW("EVENT_ERROR");
+ break;
+ }
+
+ env->CallStaticVoidMethod(
+ callbackInfo->audioEffect_class,
+ fields.midPostNativeEvent,
+ callbackInfo->audioEffect_ref, event, arg1, arg2, obj);
+
+effectCallback_Exit:
+ if (array) {
+ env->DeleteLocalRef(array);
+ }
+
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+}
+
+// ----------------------------------------------------------------------------
+// This function gets some field IDs, which in turn causes class initialization.
+// It is called from a static block in AudioEffect, which won't run until the
+// first time an instance of this class is used.
+static void
+android_media_AudioEffect_native_init(JNIEnv *env)
+{
+
+ LOGV("android_media_AudioEffect_native_init");
+
+ fields.clazzEffect = NULL;
+ fields.clazzDesc = NULL;
+
+ // Get the AudioEffect class
+ jclass clazz = env->FindClass(kClassPathName);
+ if (clazz == NULL) {
+ LOGE("Can't find %s", kClassPathName);
+ return;
+ }
+
+ fields.clazzEffect = (jclass)env->NewGlobalRef(clazz);
+
+ // Get the postEvent method
+ fields.midPostNativeEvent = env->GetStaticMethodID(
+ fields.clazzEffect,
+ "postEventFromNative", "(Ljava/lang/Object;IIILjava/lang/Object;)V");
+ if (fields.midPostNativeEvent == NULL) {
+ LOGE("Can't find AudioEffect.%s", "postEventFromNative");
+ return;
+ }
+
+ // Get the variables fields
+ // nativeTrackInJavaObj
+ fields.fidNativeAudioEffect = env->GetFieldID(
+ fields.clazzEffect,
+ "mNativeAudioEffect", "I");
+ if (fields.fidNativeAudioEffect == NULL) {
+ LOGE("Can't find AudioEffect.%s", "mNativeAudioEffect");
+ return;
+ }
+ // fidJniData;
+ fields.fidJniData = env->GetFieldID(
+ fields.clazzEffect,
+ "mJniData", "I");
+ if (fields.fidJniData == NULL) {
+ LOGE("Can't find AudioEffect.%s", "mJniData");
+ return;
+ }
+
+ clazz = env->FindClass("android/media/AudioEffect$Descriptor");
+ if (clazz == NULL) {
+ LOGE("Can't find android/media/AudioEffect$Descriptor class");
+ return;
+ }
+ fields.clazzDesc = (jclass)env->NewGlobalRef(clazz);
+
+ fields.midDescCstor
+ = env->GetMethodID(
+ fields.clazzDesc,
+ "<init>",
+ "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
+ if (fields.midDescCstor == NULL) {
+ LOGE("Can't find android/media/AudioEffect$Descriptor class constructor");
+ return;
+ }
+}
+
+
+static jint
+android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
+ jstring type, jstring uuid, jint priority, jint sessionId, jintArray jId, jobjectArray javadesc)
+{
+ LOGV("android_media_AudioEffect_native_setup");
+ AudioEffectJniStorage* lpJniStorage = NULL;
+ int lStatus = AUDIOEFFECT_ERROR_NO_MEMORY;
+ AudioEffect* lpAudioEffect = NULL;
+ jint* nId = NULL;
+ const char *typeStr = NULL;
+ const char *uuidStr = NULL;
+ effect_descriptor_t desc;
+ jobject jdesc;
+ char str[EFFECT_STRING_LEN_MAX];
+ jstring jdescType;
+ jstring jdescUuid;
+ jstring jdescConnect;
+ jstring jdescName;
+ jstring jdescImplementor;
+
+ if (type != NULL) {
+ typeStr = env->GetStringUTFChars(type, NULL);
+ if (typeStr == NULL) { // Out of memory
+ jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
+ goto setup_failure;
+ }
+ }
+
+ if (uuid != NULL) {
+ uuidStr = env->GetStringUTFChars(uuid, NULL);
+ if (uuidStr == NULL) { // Out of memory
+ jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
+ goto setup_failure;
+ }
+ }
+
+ if (typeStr == NULL && uuidStr == NULL) {
+ lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
+ goto setup_failure;
+ }
+
+ lpJniStorage = new AudioEffectJniStorage();
+ if (lpJniStorage == NULL) {
+ LOGE("setup: Error creating JNI Storage");
+ goto setup_failure;
+ }
+
+ lpJniStorage->mCallbackData.audioEffect_class = (jclass)env->NewGlobalRef(fields.clazzEffect);
+ // we use a weak reference so the AudioEffect object can be garbage collected.
+ lpJniStorage->mCallbackData.audioEffect_ref = env->NewGlobalRef(weak_this);
+
+ LOGV("setup: lpJniStorage: %p audioEffect_ref %p audioEffect_class %p, &mCallbackData %p",
+ lpJniStorage,
+ lpJniStorage->mCallbackData.audioEffect_ref,
+ lpJniStorage->mCallbackData.audioEffect_class,
+ &lpJniStorage->mCallbackData);
+
+ if (jId) {
+ nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL);
+ if (nId == NULL) {
+ LOGE("setup: Error retrieving id pointer");
+ lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
+ goto setup_failure;
+ }
+ } else {
+ LOGE("setup: NULL java array for id pointer");
+ lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
+ goto setup_failure;
+ }
+
+ // create the native AudioEffect object
+ lpAudioEffect = new AudioEffect(typeStr,
+ uuidStr,
+ priority,
+ effectCallback,
+ &lpJniStorage->mCallbackData,
+ 0,
+ sessionId);
+ if (lpAudioEffect == NULL) {
+ LOGE("Error creating AudioEffect");
+ goto setup_failure;
+ }
+
+ lStatus = translateError(lpAudioEffect->initCheck());
+ if (lStatus != AUDIOEFFECT_SUCCESS && lStatus != AUDIOEFFECT_ERROR_ALREADY_EXISTS) {
+ LOGE("AudioEffect initCheck failed %d", lStatus);
+ goto setup_failure;
+ }
+
+ nId[0] = lpAudioEffect->id();
+
+ env->ReleasePrimitiveArrayCritical(jId, nId, 0);
+ nId = NULL;
+
+ if (typeStr) {
+ env->ReleaseStringUTFChars(type, typeStr);
+ typeStr = NULL;
+ }
+
+ if (uuidStr) {
+ env->ReleaseStringUTFChars(uuid, uuidStr);
+ uuidStr = NULL;
+ }
+
+ // get the effect descriptor
+ desc = lpAudioEffect->descriptor();
+
+ AudioEffect::guidToString(&desc.type, str, EFFECT_STRING_LEN_MAX);
+ jdescType = env->NewStringUTF(str);
+
+ AudioEffect::guidToString(&desc.uuid, str, EFFECT_STRING_LEN_MAX);
+ jdescUuid = env->NewStringUTF(str);
+
+ if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
+ jdescConnect = env->NewStringUTF("Auxiliary");
+ } else {
+ jdescConnect = env->NewStringUTF("Insert");
+ }
+
+ jdescName = env->NewStringUTF(desc.name);
+ jdescImplementor = env->NewStringUTF(desc.implementor);
+
+ jdesc = env->NewObject(fields.clazzDesc,
+ fields.midDescCstor,
+ jdescType,
+ jdescUuid,
+ jdescConnect,
+ jdescName,
+ jdescImplementor);
+ env->DeleteLocalRef(jdescType);
+ env->DeleteLocalRef(jdescUuid);
+ env->DeleteLocalRef(jdescConnect);
+ env->DeleteLocalRef(jdescName);
+ env->DeleteLocalRef(jdescImplementor);
+ if (jdesc == NULL) {
+ LOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)");
+ goto setup_failure;
+ }
+
+ env->SetObjectArrayElement(javadesc, 0, jdesc);
+
+ env->SetIntField(thiz, fields.fidNativeAudioEffect, (int)lpAudioEffect);
+
+ env->SetIntField(thiz, fields.fidJniData, (int)lpJniStorage);
+
+ return AUDIOEFFECT_SUCCESS;
+
+ // failures:
+setup_failure:
+
+ if (nId != NULL) {
+ env->ReleasePrimitiveArrayCritical(jId, nId, 0);
+ }
+
+ if (lpAudioEffect) {
+ delete lpAudioEffect;
+ }
+ env->SetIntField(thiz, fields.fidNativeAudioEffect, 0);
+
+ if (lpJniStorage) {
+ delete lpJniStorage;
+ }
+ env->SetIntField(thiz, fields.fidJniData, 0);
+
+ if (uuidStr != NULL) {
+ env->ReleaseStringUTFChars(uuid, uuidStr);
+ }
+
+ if (typeStr != NULL) {
+ env->ReleaseStringUTFChars(type, typeStr);
+ }
+
+ return lStatus;
+}
+
+
+// ----------------------------------------------------------------------------
+static void android_media_AudioEffect_native_finalize(JNIEnv *env, jobject thiz) {
+ LOGV("android_media_AudioEffect_native_finalize jobject: %x\n", (int)thiz);
+
+ // delete the AudioEffect object
+ AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
+ thiz, fields.fidNativeAudioEffect);
+ if (lpAudioEffect) {
+ LOGV("deleting AudioEffect: %x\n", (int)lpAudioEffect);
+ delete lpAudioEffect;
+ }
+
+ // delete the JNI data
+ AudioEffectJniStorage* lpJniStorage = (AudioEffectJniStorage *)env->GetIntField(
+ thiz, fields.fidJniData);
+ if (lpJniStorage) {
+ LOGV("deleting pJniStorage: %x\n", (int)lpJniStorage);
+ delete lpJniStorage;
+ }
+}
+
+// ----------------------------------------------------------------------------
+static void android_media_AudioEffect_native_release(JNIEnv *env, jobject thiz) {
+
+ // do everything a call to finalize would
+ android_media_AudioEffect_native_finalize(env, thiz);
+ // + reset the native resources in the Java object so any attempt to access
+ // them after a call to release fails.
+ env->SetIntField(thiz, fields.fidNativeAudioEffect, 0);
+ env->SetIntField(thiz, fields.fidJniData, 0);
+}
+
+
+static jint
+android_media_AudioEffect_native_enable(JNIEnv *env, jobject thiz)
+{
+ // retrieve the AudioEffect object
+ AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
+ thiz, fields.fidNativeAudioEffect);
+
+ if (lpAudioEffect == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioEffect pointer for enable()");
+ return AUDIOEFFECT_ERROR_NO_INIT;
+ }
+
+ return translateError(lpAudioEffect->enable());
+}
+
+
+static jint
+android_media_AudioEffect_native_disable(JNIEnv *env, jobject thiz)
+{
+ // retrieve the AudioEffect object
+ AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
+ thiz, fields.fidNativeAudioEffect);
+
+ if (lpAudioEffect == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioEffect pointer for disable()");
+ return AUDIOEFFECT_ERROR_NO_INIT;
+ }
+
+ return translateError(lpAudioEffect->disable());
+}
+
+
+static jboolean
+android_media_AudioEffect_native_getEnable(JNIEnv *env, jobject thiz)
+{
+ // retrieve the AudioEffect object
+ AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
+ thiz, fields.fidNativeAudioEffect);
+
+ if (lpAudioEffect == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioEffect pointer for getEnabled()");
+ return false;
+ }
+
+ return (jboolean)lpAudioEffect->isEnabled();
+}
+
+
+static jboolean
+android_media_AudioEffect_native_hasControl(JNIEnv *env, jobject thiz)
+{
+ // retrieve the AudioEffect object
+ AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
+ thiz, fields.fidNativeAudioEffect);
+
+ if (lpAudioEffect == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioEffect pointer for getEnabled()");
+ return false;
+ }
+
+ if (lpAudioEffect->initCheck() == NO_ERROR) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static jint android_media_AudioEffect_native_setParameter(JNIEnv *env,
+ jobject thiz, int psize, jbyteArray pJavaParam, int vsize,
+ jbyteArray pJavaValue) {
+ // retrieve the AudioEffect object
+ jbyte* lpValue = NULL;
+ jbyte* lpParam = NULL;
+ jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
+ effect_param_t *p;
+ int voffset;
+
+ AudioEffect* lpAudioEffect = (AudioEffect *) env->GetIntField(thiz,
+ fields.fidNativeAudioEffect);
+
+ if (lpAudioEffect == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioEffect pointer for setParameter()");
+ return AUDIOEFFECT_ERROR_NO_INIT;
+ }
+
+ if (psize == 0 || vsize == 0 || pJavaParam == NULL || pJavaValue == NULL) {
+ return AUDIOEFFECT_ERROR_BAD_VALUE;
+ }
+
+ // get the pointer for the param from the java array
+ lpParam = (jbyte *) env->GetPrimitiveArrayCritical(pJavaParam, NULL);
+ if (lpParam == NULL) {
+ LOGE("setParameter: Error retrieving param pointer");
+ goto setParameter_Exit;
+ }
+
+ // get the pointer for the value from the java array
+ lpValue = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValue, NULL);
+ if (lpValue == NULL) {
+ LOGE("setParameter: Error retrieving value pointer");
+ goto setParameter_Exit;
+ }
+
+ voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int);
+ p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset + vsize);
+ memcpy(p->data, lpParam, psize);
+ p->psize = psize;
+ memcpy(p->data + voffset, lpValue, psize);
+ p->vsize = vsize;
+
+ lStatus = lpAudioEffect->setParameter(p);
+ if (lStatus == NO_ERROR) {
+ lStatus = p->status;
+ }
+
+ free(p);
+
+setParameter_Exit:
+
+ if (lpParam != NULL) {
+ env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0);
+ }
+ if (lpValue != NULL) {
+ env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
+ }
+ return translateError(lStatus);
+}
+
+static jint
+android_media_AudioEffect_native_getParameter(JNIEnv *env,
+ jobject thiz, int psize, jbyteArray pJavaParam,
+ jintArray pJavaValueSize, jbyteArray pJavaValue) {
+ // retrieve the AudioEffect object
+ jbyte* lpParam = NULL;
+ jbyte* lpValue = NULL;
+ jbyte* lpValueSize = NULL;
+ jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
+ effect_param_t *p;
+ int voffset;
+
+ AudioEffect* lpAudioEffect = (AudioEffect *) env->GetIntField(thiz,
+ fields.fidNativeAudioEffect);
+
+ if (lpAudioEffect == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioEffect pointer for getParameter()");
+ return AUDIOEFFECT_ERROR_NO_INIT;
+ }
+
+ if (psize == 0 || pJavaValueSize == NULL || pJavaParam == NULL || pJavaValue == NULL) {
+ return AUDIOEFFECT_ERROR_BAD_VALUE;
+ }
+
+ // get the pointer for the param from the java array
+ lpParam = (jbyte *) env->GetPrimitiveArrayCritical(pJavaParam, NULL);
+ if (lpParam == NULL) {
+ LOGE("getParameter: Error retrieving param pointer");
+ goto getParameter_Exit;
+ }
+
+ // get the pointer for the value from the java array
+ lpValue = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValue, NULL);
+ if (lpValue == NULL) {
+ LOGE("getParameter: Error retrieving value pointer");
+ goto getParameter_Exit;
+ }
+
+ // get the pointer for the value size from the java array
+ lpValueSize = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValueSize, NULL);
+ if (lpValueSize == NULL) {
+ LOGE("getParameter: Error retrieving value size pointer");
+ goto getParameter_Exit;
+ }
+
+ voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int);
+ p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset
+ + lpValueSize[0]);
+ memcpy(p->data, lpParam, psize);
+ p->psize = psize;
+ p->vsize = lpValueSize[0];
+
+ lStatus = lpAudioEffect->getParameter(p);
+ if (lStatus == NO_ERROR) {
+ lStatus = p->status;
+ if (lStatus == NO_ERROR) {
+ memcpy(lpValue, p->data + voffset, p->vsize);
+ lpValueSize[0] = p->vsize;
+ }
+ }
+
+ free(p);
+
+getParameter_Exit:
+
+ if (lpParam != NULL) {
+ env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0);
+ }
+ if (lpValue != NULL) {
+ env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
+ }
+ if (lpValueSize != NULL) {
+ env->ReleasePrimitiveArrayCritical(pJavaValueSize, lpValueSize, 0);
+ }
+
+ return translateError(lStatus);
+}
+
+static jint android_media_AudioEffect_native_command(JNIEnv *env, jobject thiz,
+ jint cmdCode, jint cmdSize, jbyteArray jCmdData, jintArray jReplySize,
+ jbyteArray jReplyData) {
+ jbyte* pCmdData = NULL;
+ jbyte* pReplyData = NULL;
+ jint* pReplySize = NULL;
+ jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
+
+ // retrieve the AudioEffect object
+ AudioEffect* lpAudioEffect = (AudioEffect *) env->GetIntField(thiz,
+ fields.fidNativeAudioEffect);
+
+ if (lpAudioEffect == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioEffect pointer for setParameter()");
+ return AUDIOEFFECT_ERROR_NO_INIT;
+ }
+
+ if ((cmdSize != 0 && jCmdData == NULL) || (jReplySize != NULL && jReplyData == NULL)) {
+ return AUDIOEFFECT_ERROR_BAD_VALUE;
+ }
+
+ // get the pointer for the command from the java array
+ if (cmdSize != 0) {
+ pCmdData = (jbyte *) env->GetPrimitiveArrayCritical(jCmdData, NULL);
+ if (pCmdData == NULL) {
+ LOGE("setParameter: Error retrieving command pointer");
+ goto command_Exit;
+ }
+ }
+
+ // get the pointer for the reply size from the java array
+ if (jReplySize != NULL) {
+ pReplySize = (jint *) env->GetPrimitiveArrayCritical(jReplySize, NULL);
+ if (pReplySize == NULL) {
+ LOGE("setParameter: Error retrieving reply pointer");
+ goto command_Exit;
+ }
+ }
+
+ // get the pointer for the reply from the java array
+ if (pReplySize != NULL && pReplySize[0] != 0 && jReplyData != NULL) {
+ pReplyData = (jbyte *) env->GetPrimitiveArrayCritical(jReplyData, NULL);
+ if (pReplyData == NULL) {
+ LOGE("setParameter: Error retrieving reply pointer");
+ goto command_Exit;
+ }
+ }
+
+ lStatus = translateError(lpAudioEffect->command(cmdCode, cmdSize, pCmdData,
+ pReplySize, pReplyData));
+
+command_Exit:
+
+ if (pCmdData != NULL) {
+ env->ReleasePrimitiveArrayCritical(jCmdData, pCmdData, 0);
+ }
+ if (pReplyData != NULL) {
+ env->ReleasePrimitiveArrayCritical(jReplyData, pReplyData, 0);
+ }
+ if (pReplySize != NULL) {
+ env->ReleasePrimitiveArrayCritical(jReplySize, pReplySize, 0);
+ }
+
+ return lStatus;
+}
+
+static jobjectArray
+android_media_AudioEffect_native_queryEffects(JNIEnv *env, jclass clazz)
+{
+ effect_descriptor_t desc;
+ char str[EFFECT_STRING_LEN_MAX];
+ uint32_t numEffects;
+ uint32_t i = 0;
+ jstring jdescType;
+ jstring jdescUuid;
+ jstring jdescConnect;
+ jstring jdescName;
+ jstring jdescImplementor;
+ jobject jdesc;
+
+ AudioEffect::queryNumberEffects(&numEffects);
+ jobjectArray ret = env->NewObjectArray(numEffects, fields.clazzDesc, NULL);
+ if (ret == NULL) {
+ return ret;
+ }
+
+ LOGV("queryEffects() numEffects: %d", numEffects);
+
+ for (i = 0; i < numEffects; i++) {
+ if (AudioEffect::queryNextEffect(&desc) != NO_ERROR) {
+ goto queryEffects_failure;
+ }
+
+ AudioEffect::guidToString(&desc.type, str, EFFECT_STRING_LEN_MAX);
+ jdescType = env->NewStringUTF(str);
+
+ AudioEffect::guidToString(&desc.uuid, str, EFFECT_STRING_LEN_MAX);
+ jdescUuid = env->NewStringUTF(str);
+
+ if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
+ jdescConnect = env->NewStringUTF("Auxiliary");
+ } else {
+ jdescConnect = env->NewStringUTF("Insert");
+ }
+
+ jdescName = env->NewStringUTF(desc.name);
+ jdescImplementor = env->NewStringUTF(desc.implementor);
+
+ jdesc = env->NewObject(fields.clazzDesc,
+ fields.midDescCstor,
+ jdescType,
+ jdescUuid,
+ jdescConnect,
+ jdescName,
+ jdescImplementor);
+ env->DeleteLocalRef(jdescType);
+ env->DeleteLocalRef(jdescUuid);
+ env->DeleteLocalRef(jdescConnect);
+ env->DeleteLocalRef(jdescName);
+ env->DeleteLocalRef(jdescImplementor);
+ if (jdesc == NULL) {
+ LOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)");
+ goto queryEffects_failure;
+ }
+
+ env->SetObjectArrayElement(ret, i, jdesc);
+ }
+
+ return ret;
+
+queryEffects_failure:
+
+ if (ret != NULL) {
+ env->DeleteLocalRef(ret);
+ }
+ return NULL;
+
+}
+
+// ----------------------------------------------------------------------------
+
+// Dalvik VM type signatures
+static JNINativeMethod gMethods[] = {
+ {"native_init", "()V", (void *)android_media_AudioEffect_native_init},
+ {"native_setup", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;II[I[Ljava/lang/Object;)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},
+ {"native_enable", "()I", (void *)android_media_AudioEffect_native_enable},
+ {"native_disable", "()I", (void *)android_media_AudioEffect_native_disable},
+ {"native_getEnable", "()Z", (void *)android_media_AudioEffect_native_getEnable},
+ {"native_hasControl", "()Z", (void *)android_media_AudioEffect_native_hasControl},
+ {"native_setParameter", "(I[BI[B)I", (void *)android_media_AudioEffect_native_setParameter},
+ {"native_getParameter", "(I[B[I[B)I", (void *)android_media_AudioEffect_native_getParameter},
+ {"native_command", "(II[B[I[B)I", (void *)android_media_AudioEffect_native_command},
+ {"native_query_effects", "()[Ljava/lang/Object;", (void *)android_media_AudioEffect_native_queryEffects},
+};
+
+
+// ----------------------------------------------------------------------------
+
+int register_android_media_AudioEffect(JNIEnv *env)
+{
+ return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+}
+
+jint JNI_OnLoad(JavaVM* vm, void* reserved)
+{
+
+ JNIEnv* env = NULL;
+ jint result = -1;
+
+ if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
+ LOGE("ERROR: GetEnv failed\n");
+ goto bail;
+ }
+ assert(env != NULL);
+
+ if (register_android_media_AudioEffect(env) < 0) {
+ LOGE("ERROR: AudioEffect native registration failed\n");
+ goto bail;
+ }
+
+ /* success -- return valid version number */
+ result = JNI_VERSION_1_4;
+
+bail:
+ return result;
+}
+