diff options
author | Eric Laurent <elaurent@google.com> | 2010-06-14 09:02:13 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2010-06-14 09:02:13 -0700 |
commit | 01f7ac64488027492b2909b99d70491e7a391015 (patch) | |
tree | 109dc569fe04f88f7ae8525708095cf3f332c37b /media/jni | |
parent | 724c52244423feced2677fbd1f905e0b8b0639f2 (diff) | |
parent | 948235c06ed0d49190b2f49d9299b473c4dd61a9 (diff) | |
download | frameworks_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.mk | 3 | ||||
-rw-r--r-- | media/jni/audioeffect/Android.mk | 16 | ||||
-rw-r--r-- | media/jni/audioeffect/android_media_AudioEffect.cpp | 861 |
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; +} + |