Home | History | Annotate | Download | only in audioeffect
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <stdio.h>
     18 
     19 //#define LOG_NDEBUG 0
     20 #define LOG_TAG "AudioEffects-JNI"
     21 
     22 #include <utils/Log.h>
     23 #include <nativehelper/jni.h>
     24 #include <nativehelper/JNIHelp.h>
     25 #include <android_runtime/AndroidRuntime.h>
     26 #include "media/AudioEffect.h"
     27 
     28 using namespace android;
     29 
     30 #define AUDIOEFFECT_SUCCESS                      0
     31 #define AUDIOEFFECT_ERROR                       -1
     32 #define AUDIOEFFECT_ERROR_ALREADY_EXISTS        -2
     33 #define AUDIOEFFECT_ERROR_NO_INIT               -3
     34 #define AUDIOEFFECT_ERROR_BAD_VALUE             -4
     35 #define AUDIOEFFECT_ERROR_INVALID_OPERATION     -5
     36 #define AUDIOEFFECT_ERROR_NO_MEMORY             -6
     37 #define AUDIOEFFECT_ERROR_DEAD_OBJECT           -7
     38 
     39 // ----------------------------------------------------------------------------
     40 static const char* const kClassPathName = "android/media/audiofx/AudioEffect";
     41 
     42 struct fields_t {
     43     // these fields provide access from C++ to the...
     44     jclass    clazzEffect;          // AudioEffect class
     45     jmethodID midPostNativeEvent;   // event post callback method
     46     jfieldID  fidNativeAudioEffect; // stores in Java the native AudioEffect object
     47     jfieldID  fidJniData;           // stores in Java additional resources used by the native AudioEffect
     48     jclass    clazzDesc;            // AudioEffect.Descriptor class
     49     jmethodID midDescCstor;         // AudioEffect.Descriptor class constructor
     50 };
     51 static fields_t fields;
     52 
     53 struct effect_callback_cookie {
     54     jclass      audioEffect_class;  // AudioEffect class
     55     jobject     audioEffect_ref;    // AudioEffect object instance
     56  };
     57 
     58 // ----------------------------------------------------------------------------
     59 class AudioEffectJniStorage {
     60     public:
     61         effect_callback_cookie mCallbackData;
     62 
     63     AudioEffectJniStorage() {
     64     }
     65 
     66     ~AudioEffectJniStorage() {
     67     }
     68 
     69 };
     70 
     71 
     72 static jint translateError(int code) {
     73     switch(code) {
     74     case NO_ERROR:
     75         return AUDIOEFFECT_SUCCESS;
     76     case ALREADY_EXISTS:
     77         return AUDIOEFFECT_ERROR_ALREADY_EXISTS;
     78     case NO_INIT:
     79         return AUDIOEFFECT_ERROR_NO_INIT;
     80     case BAD_VALUE:
     81         return AUDIOEFFECT_ERROR_BAD_VALUE;
     82     case INVALID_OPERATION:
     83         return AUDIOEFFECT_ERROR_INVALID_OPERATION;
     84     case NO_MEMORY:
     85         return AUDIOEFFECT_ERROR_NO_MEMORY;
     86     case DEAD_OBJECT:
     87         return AUDIOEFFECT_ERROR_DEAD_OBJECT;
     88     default:
     89         return AUDIOEFFECT_ERROR;
     90     }
     91 }
     92 
     93 
     94 // ----------------------------------------------------------------------------
     95 static void effectCallback(int event, void* user, void *info) {
     96 
     97     effect_param_t *p;
     98     int arg1 = 0;
     99     int arg2 = 0;
    100     jobject obj = NULL;
    101     jbyteArray array = NULL;
    102     jbyte *bytes;
    103     bool param;
    104     size_t size;
    105 
    106     effect_callback_cookie *callbackInfo = (effect_callback_cookie *)user;
    107     JNIEnv *env = AndroidRuntime::getJNIEnv();
    108 
    109     LOGV("effectCallback: callbackInfo %p, audioEffect_ref %p audioEffect_class %p",
    110             callbackInfo,
    111             callbackInfo->audioEffect_ref,
    112             callbackInfo->audioEffect_class);
    113 
    114     if (!user || !env) {
    115         LOGW("effectCallback error user %p, env %p", user, env);
    116         return;
    117     }
    118 
    119     switch (event) {
    120     case AudioEffect::EVENT_CONTROL_STATUS_CHANGED:
    121         if (info == 0) {
    122             LOGW("EVENT_CONTROL_STATUS_CHANGED info == NULL");
    123             goto effectCallback_Exit;
    124         }
    125         param = *(bool *)info;
    126         arg1 = (int)param;
    127         LOGV("EVENT_CONTROL_STATUS_CHANGED");
    128         break;
    129     case AudioEffect::EVENT_ENABLE_STATUS_CHANGED:
    130         if (info == 0) {
    131             LOGW("EVENT_ENABLE_STATUS_CHANGED info == NULL");
    132             goto effectCallback_Exit;
    133         }
    134         param = *(bool *)info;
    135         arg1 = (int)param;
    136         LOGV("EVENT_ENABLE_STATUS_CHANGED");
    137         break;
    138     case AudioEffect::EVENT_PARAMETER_CHANGED:
    139         if (info == 0) {
    140             LOGW("EVENT_PARAMETER_CHANGED info == NULL");
    141             goto effectCallback_Exit;
    142         }
    143         p = (effect_param_t *)info;
    144         if (p->psize == 0 || p->vsize == 0) {
    145             goto effectCallback_Exit;
    146         }
    147         // arg1 contains offset of parameter value from start of byte array
    148         arg1 = sizeof(effect_param_t) + ((p->psize - 1) / sizeof(int) + 1) * sizeof(int);
    149         size = arg1 + p->vsize;
    150         array = env->NewByteArray(size);
    151         if (array == NULL) {
    152             LOGE("effectCallback: Couldn't allocate byte array for parameter data");
    153             goto effectCallback_Exit;
    154         }
    155         bytes = env->GetByteArrayElements(array, NULL);
    156         memcpy(bytes, p, size);
    157         env->ReleaseByteArrayElements(array, bytes, 0);
    158         obj = array;
    159         LOGV("EVENT_PARAMETER_CHANGED");
    160        break;
    161     case AudioEffect::EVENT_ERROR:
    162         LOGW("EVENT_ERROR");
    163         break;
    164     }
    165 
    166     env->CallStaticVoidMethod(
    167         callbackInfo->audioEffect_class,
    168         fields.midPostNativeEvent,
    169         callbackInfo->audioEffect_ref, event, arg1, arg2, obj);
    170 
    171 effectCallback_Exit:
    172     if (array) {
    173         env->DeleteLocalRef(array);
    174     }
    175 
    176     if (env->ExceptionCheck()) {
    177         env->ExceptionDescribe();
    178         env->ExceptionClear();
    179     }
    180 }
    181 
    182 // ----------------------------------------------------------------------------
    183 // This function gets some field IDs, which in turn causes class initialization.
    184 // It is called from a static block in AudioEffect, which won't run until the
    185 // first time an instance of this class is used.
    186 static void
    187 android_media_AudioEffect_native_init(JNIEnv *env)
    188 {
    189 
    190     LOGV("android_media_AudioEffect_native_init");
    191 
    192     fields.clazzEffect = NULL;
    193     fields.clazzDesc = NULL;
    194 
    195     // Get the AudioEffect class
    196     jclass clazz = env->FindClass(kClassPathName);
    197     if (clazz == NULL) {
    198         LOGE("Can't find %s", kClassPathName);
    199         return;
    200     }
    201 
    202     fields.clazzEffect = (jclass)env->NewGlobalRef(clazz);
    203 
    204     // Get the postEvent method
    205     fields.midPostNativeEvent = env->GetStaticMethodID(
    206             fields.clazzEffect,
    207             "postEventFromNative", "(Ljava/lang/Object;IIILjava/lang/Object;)V");
    208     if (fields.midPostNativeEvent == NULL) {
    209         LOGE("Can't find AudioEffect.%s", "postEventFromNative");
    210         return;
    211     }
    212 
    213     // Get the variables fields
    214     //      nativeTrackInJavaObj
    215     fields.fidNativeAudioEffect = env->GetFieldID(
    216             fields.clazzEffect,
    217             "mNativeAudioEffect", "I");
    218     if (fields.fidNativeAudioEffect == NULL) {
    219         LOGE("Can't find AudioEffect.%s", "mNativeAudioEffect");
    220         return;
    221     }
    222     //      fidJniData;
    223     fields.fidJniData = env->GetFieldID(
    224             fields.clazzEffect,
    225             "mJniData", "I");
    226     if (fields.fidJniData == NULL) {
    227         LOGE("Can't find AudioEffect.%s", "mJniData");
    228         return;
    229     }
    230 
    231     clazz = env->FindClass("android/media/audiofx/AudioEffect$Descriptor");
    232     if (clazz == NULL) {
    233         LOGE("Can't find android/media/audiofx/AudioEffect$Descriptor class");
    234         return;
    235     }
    236     fields.clazzDesc = (jclass)env->NewGlobalRef(clazz);
    237 
    238     fields.midDescCstor
    239             = env->GetMethodID(
    240                     fields.clazzDesc,
    241                     "<init>",
    242                     "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
    243     if (fields.midDescCstor == NULL) {
    244         LOGE("Can't find android/media/audiofx/AudioEffect$Descriptor class constructor");
    245         return;
    246     }
    247 }
    248 
    249 
    250 static jint
    251 android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
    252         jstring type, jstring uuid, jint priority, jint sessionId, jintArray jId, jobjectArray javadesc)
    253 {
    254     LOGV("android_media_AudioEffect_native_setup");
    255     AudioEffectJniStorage* lpJniStorage = NULL;
    256     int lStatus = AUDIOEFFECT_ERROR_NO_MEMORY;
    257     AudioEffect* lpAudioEffect = NULL;
    258     jint* nId = NULL;
    259     const char *typeStr = NULL;
    260     const char *uuidStr = NULL;
    261     effect_descriptor_t desc;
    262     jobject jdesc;
    263     char str[EFFECT_STRING_LEN_MAX];
    264     jstring jdescType;
    265     jstring jdescUuid;
    266     jstring jdescConnect;
    267     jstring jdescName;
    268     jstring jdescImplementor;
    269 
    270     if (type != NULL) {
    271         typeStr = env->GetStringUTFChars(type, NULL);
    272         if (typeStr == NULL) {  // Out of memory
    273             jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
    274             goto setup_failure;
    275         }
    276     }
    277 
    278     if (uuid != NULL) {
    279         uuidStr = env->GetStringUTFChars(uuid, NULL);
    280         if (uuidStr == NULL) {  // Out of memory
    281             jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
    282             goto setup_failure;
    283         }
    284     }
    285 
    286     if (typeStr == NULL && uuidStr == NULL) {
    287         lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
    288         goto setup_failure;
    289     }
    290 
    291     lpJniStorage = new AudioEffectJniStorage();
    292     if (lpJniStorage == NULL) {
    293         LOGE("setup: Error creating JNI Storage");
    294         goto setup_failure;
    295     }
    296 
    297     lpJniStorage->mCallbackData.audioEffect_class = (jclass)env->NewGlobalRef(fields.clazzEffect);
    298     // we use a weak reference so the AudioEffect object can be garbage collected.
    299     lpJniStorage->mCallbackData.audioEffect_ref = env->NewGlobalRef(weak_this);
    300 
    301     LOGV("setup: lpJniStorage: %p audioEffect_ref %p audioEffect_class %p, &mCallbackData %p",
    302             lpJniStorage,
    303             lpJniStorage->mCallbackData.audioEffect_ref,
    304             lpJniStorage->mCallbackData.audioEffect_class,
    305             &lpJniStorage->mCallbackData);
    306 
    307     if (jId == NULL) {
    308         LOGE("setup: NULL java array for id pointer");
    309         lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
    310         goto setup_failure;
    311     }
    312 
    313     // create the native AudioEffect object
    314     lpAudioEffect = new AudioEffect(typeStr,
    315                                     uuidStr,
    316                                     priority,
    317                                     effectCallback,
    318                                     &lpJniStorage->mCallbackData,
    319                                     sessionId,
    320                                     0);
    321     if (lpAudioEffect == NULL) {
    322         LOGE("Error creating AudioEffect");
    323         goto setup_failure;
    324     }
    325 
    326     lStatus = translateError(lpAudioEffect->initCheck());
    327     if (lStatus != AUDIOEFFECT_SUCCESS && lStatus != AUDIOEFFECT_ERROR_ALREADY_EXISTS) {
    328         LOGE("AudioEffect initCheck failed %d", lStatus);
    329         goto setup_failure;
    330     }
    331 
    332     nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL);
    333     if (nId == NULL) {
    334         LOGE("setup: Error retrieving id pointer");
    335         lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
    336         goto setup_failure;
    337     }
    338     nId[0] = lpAudioEffect->id();
    339     env->ReleasePrimitiveArrayCritical(jId, nId, 0);
    340     nId = NULL;
    341 
    342     if (typeStr) {
    343         env->ReleaseStringUTFChars(type, typeStr);
    344         typeStr = NULL;
    345     }
    346 
    347     if (uuidStr) {
    348         env->ReleaseStringUTFChars(uuid, uuidStr);
    349         uuidStr = NULL;
    350     }
    351 
    352     // get the effect descriptor
    353     desc = lpAudioEffect->descriptor();
    354 
    355     AudioEffect::guidToString(&desc.type, str, EFFECT_STRING_LEN_MAX);
    356     jdescType = env->NewStringUTF(str);
    357 
    358     AudioEffect::guidToString(&desc.uuid, str, EFFECT_STRING_LEN_MAX);
    359     jdescUuid = env->NewStringUTF(str);
    360 
    361     if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
    362         jdescConnect = env->NewStringUTF("Auxiliary");
    363     } else {
    364         jdescConnect = env->NewStringUTF("Insert");
    365     }
    366 
    367     jdescName = env->NewStringUTF(desc.name);
    368     jdescImplementor = env->NewStringUTF(desc.implementor);
    369 
    370     jdesc = env->NewObject(fields.clazzDesc,
    371                            fields.midDescCstor,
    372                            jdescType,
    373                            jdescUuid,
    374                            jdescConnect,
    375                            jdescName,
    376                            jdescImplementor);
    377     env->DeleteLocalRef(jdescType);
    378     env->DeleteLocalRef(jdescUuid);
    379     env->DeleteLocalRef(jdescConnect);
    380     env->DeleteLocalRef(jdescName);
    381     env->DeleteLocalRef(jdescImplementor);
    382     if (jdesc == NULL) {
    383         LOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)");
    384         goto setup_failure;
    385     }
    386 
    387     env->SetObjectArrayElement(javadesc, 0, jdesc);
    388 
    389     env->SetIntField(thiz, fields.fidNativeAudioEffect, (int)lpAudioEffect);
    390 
    391     env->SetIntField(thiz, fields.fidJniData, (int)lpJniStorage);
    392 
    393     return AUDIOEFFECT_SUCCESS;
    394 
    395     // failures:
    396 setup_failure:
    397 
    398     if (nId != NULL) {
    399         env->ReleasePrimitiveArrayCritical(jId, nId, 0);
    400     }
    401 
    402     if (lpAudioEffect) {
    403         delete lpAudioEffect;
    404     }
    405     env->SetIntField(thiz, fields.fidNativeAudioEffect, 0);
    406 
    407     if (lpJniStorage) {
    408         delete lpJniStorage;
    409     }
    410     env->SetIntField(thiz, fields.fidJniData, 0);
    411 
    412     if (uuidStr != NULL) {
    413         env->ReleaseStringUTFChars(uuid, uuidStr);
    414     }
    415 
    416     if (typeStr != NULL) {
    417         env->ReleaseStringUTFChars(type, typeStr);
    418     }
    419 
    420     return lStatus;
    421 }
    422 
    423 
    424 // ----------------------------------------------------------------------------
    425 static void android_media_AudioEffect_native_finalize(JNIEnv *env,  jobject thiz) {
    426     LOGV("android_media_AudioEffect_native_finalize jobject: %x\n", (int)thiz);
    427 
    428     // delete the AudioEffect object
    429     AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
    430         thiz, fields.fidNativeAudioEffect);
    431     if (lpAudioEffect) {
    432         LOGV("deleting AudioEffect: %x\n", (int)lpAudioEffect);
    433         delete lpAudioEffect;
    434     }
    435 
    436     // delete the JNI data
    437     AudioEffectJniStorage* lpJniStorage = (AudioEffectJniStorage *)env->GetIntField(
    438         thiz, fields.fidJniData);
    439     if (lpJniStorage) {
    440         LOGV("deleting pJniStorage: %x\n", (int)lpJniStorage);
    441         delete lpJniStorage;
    442     }
    443 }
    444 
    445 // ----------------------------------------------------------------------------
    446 static void android_media_AudioEffect_native_release(JNIEnv *env,  jobject thiz) {
    447 
    448     // do everything a call to finalize would
    449     android_media_AudioEffect_native_finalize(env, thiz);
    450     // + reset the native resources in the Java object so any attempt to access
    451     // them after a call to release fails.
    452     env->SetIntField(thiz, fields.fidNativeAudioEffect, 0);
    453     env->SetIntField(thiz, fields.fidJniData, 0);
    454 }
    455 
    456 static jint
    457 android_media_AudioEffect_native_setEnabled(JNIEnv *env, jobject thiz, jboolean enabled)
    458 {
    459     // retrieve the AudioEffect object
    460     AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
    461         thiz, fields.fidNativeAudioEffect);
    462 
    463     if (lpAudioEffect == NULL) {
    464         jniThrowException(env, "java/lang/IllegalStateException",
    465             "Unable to retrieve AudioEffect pointer for enable()");
    466         return AUDIOEFFECT_ERROR_NO_INIT;
    467     }
    468 
    469     return translateError(lpAudioEffect->setEnabled(enabled));
    470 }
    471 
    472 static jboolean
    473 android_media_AudioEffect_native_getEnabled(JNIEnv *env, jobject thiz)
    474 {
    475     // retrieve the AudioEffect object
    476     AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
    477         thiz, fields.fidNativeAudioEffect);
    478 
    479     if (lpAudioEffect == NULL) {
    480         jniThrowException(env, "java/lang/IllegalStateException",
    481             "Unable to retrieve AudioEffect pointer for getEnabled()");
    482         return false;
    483     }
    484 
    485     return (jboolean)lpAudioEffect->getEnabled();
    486 }
    487 
    488 
    489 static jboolean
    490 android_media_AudioEffect_native_hasControl(JNIEnv *env, jobject thiz)
    491 {
    492     // retrieve the AudioEffect object
    493     AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
    494         thiz, fields.fidNativeAudioEffect);
    495 
    496     if (lpAudioEffect == NULL) {
    497         jniThrowException(env, "java/lang/IllegalStateException",
    498             "Unable to retrieve AudioEffect pointer for hasControl()");
    499         return false;
    500     }
    501 
    502     if (lpAudioEffect->initCheck() == NO_ERROR) {
    503         return true;
    504     } else {
    505         return false;
    506     }
    507 }
    508 
    509 static jint android_media_AudioEffect_native_setParameter(JNIEnv *env,
    510         jobject thiz, int psize, jbyteArray pJavaParam, int vsize,
    511         jbyteArray pJavaValue) {
    512     // retrieve the AudioEffect object
    513     jbyte* lpValue = NULL;
    514     jbyte* lpParam = NULL;
    515     jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
    516     effect_param_t *p;
    517     int voffset;
    518 
    519     AudioEffect* lpAudioEffect = (AudioEffect *) env->GetIntField(thiz,
    520             fields.fidNativeAudioEffect);
    521 
    522     if (lpAudioEffect == NULL) {
    523         jniThrowException(env, "java/lang/IllegalStateException",
    524                 "Unable to retrieve AudioEffect pointer for setParameter()");
    525         return AUDIOEFFECT_ERROR_NO_INIT;
    526     }
    527 
    528     if (psize == 0 || vsize == 0 || pJavaParam == NULL || pJavaValue == NULL) {
    529         return AUDIOEFFECT_ERROR_BAD_VALUE;
    530     }
    531 
    532     // get the pointer for the param from the java array
    533     lpParam = (jbyte *) env->GetPrimitiveArrayCritical(pJavaParam, NULL);
    534     if (lpParam == NULL) {
    535         LOGE("setParameter: Error retrieving param pointer");
    536         goto setParameter_Exit;
    537     }
    538 
    539     // get the pointer for the value from the java array
    540     lpValue = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValue, NULL);
    541     if (lpValue == NULL) {
    542         LOGE("setParameter: Error retrieving value pointer");
    543         goto setParameter_Exit;
    544     }
    545 
    546     voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int);
    547     p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset + vsize);
    548     memcpy(p->data, lpParam, psize);
    549     p->psize = psize;
    550     memcpy(p->data + voffset, lpValue, vsize);
    551     p->vsize = vsize;
    552 
    553     lStatus = lpAudioEffect->setParameter(p);
    554     if (lStatus == NO_ERROR) {
    555         lStatus = p->status;
    556     }
    557 
    558     free(p);
    559 
    560 setParameter_Exit:
    561 
    562     if (lpParam != NULL) {
    563         env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0);
    564     }
    565     if (lpValue != NULL) {
    566         env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
    567     }
    568     return translateError(lStatus);
    569 }
    570 
    571 static jint
    572 android_media_AudioEffect_native_getParameter(JNIEnv *env,
    573         jobject thiz, int psize, jbyteArray pJavaParam,
    574         jintArray pJavaValueSize, jbyteArray pJavaValue) {
    575     // retrieve the AudioEffect object
    576     jbyte* lpParam = NULL;
    577     jbyte* lpValue = NULL;
    578     jbyte* lpValueSize = NULL;
    579     jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
    580     effect_param_t *p;
    581     int voffset;
    582 
    583     AudioEffect* lpAudioEffect = (AudioEffect *) env->GetIntField(thiz,
    584             fields.fidNativeAudioEffect);
    585 
    586     if (lpAudioEffect == NULL) {
    587         jniThrowException(env, "java/lang/IllegalStateException",
    588                 "Unable to retrieve AudioEffect pointer for getParameter()");
    589         return AUDIOEFFECT_ERROR_NO_INIT;
    590     }
    591 
    592     if (psize == 0 || pJavaValueSize == NULL || pJavaParam == NULL || pJavaValue == NULL) {
    593         return AUDIOEFFECT_ERROR_BAD_VALUE;
    594     }
    595 
    596     // get the pointer for the param from the java array
    597     lpParam = (jbyte *) env->GetPrimitiveArrayCritical(pJavaParam, NULL);
    598     if (lpParam == NULL) {
    599         LOGE("getParameter: Error retrieving param pointer");
    600         goto getParameter_Exit;
    601     }
    602 
    603     // get the pointer for the value from the java array
    604     lpValue = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValue, NULL);
    605     if (lpValue == NULL) {
    606         LOGE("getParameter: Error retrieving value pointer");
    607         goto getParameter_Exit;
    608     }
    609 
    610     // get the pointer for the value size from the java array
    611     lpValueSize = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValueSize, NULL);
    612     if (lpValueSize == NULL) {
    613         LOGE("getParameter: Error retrieving value size pointer");
    614         goto getParameter_Exit;
    615     }
    616 
    617     voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int);
    618     p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset
    619             + lpValueSize[0]);
    620     memcpy(p->data, lpParam, psize);
    621     p->psize = psize;
    622     p->vsize = lpValueSize[0];
    623 
    624     lStatus = lpAudioEffect->getParameter(p);
    625     if (lStatus == NO_ERROR) {
    626         lStatus = p->status;
    627         if (lStatus == NO_ERROR) {
    628             memcpy(lpValue, p->data + voffset, p->vsize);
    629             lpValueSize[0] = p->vsize;
    630         }
    631     }
    632 
    633     free(p);
    634 
    635 getParameter_Exit:
    636 
    637     if (lpParam != NULL) {
    638         env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0);
    639     }
    640     if (lpValue != NULL) {
    641         env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
    642     }
    643     if (lpValueSize != NULL) {
    644         env->ReleasePrimitiveArrayCritical(pJavaValueSize, lpValueSize, 0);
    645     }
    646 
    647     return translateError(lStatus);
    648 }
    649 
    650 static jint android_media_AudioEffect_native_command(JNIEnv *env, jobject thiz,
    651         jint cmdCode, jint cmdSize, jbyteArray jCmdData, jintArray jReplySize,
    652         jbyteArray jReplyData) {
    653     jbyte* pCmdData = NULL;
    654     jbyte* pReplyData = NULL;
    655     jint* pReplySize = NULL;
    656     jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
    657 
    658     // retrieve the AudioEffect object
    659     AudioEffect* lpAudioEffect = (AudioEffect *) env->GetIntField(thiz,
    660             fields.fidNativeAudioEffect);
    661 
    662     if (lpAudioEffect == NULL) {
    663         jniThrowException(env, "java/lang/IllegalStateException",
    664                 "Unable to retrieve AudioEffect pointer for setParameter()");
    665         return AUDIOEFFECT_ERROR_NO_INIT;
    666     }
    667 
    668     if ((cmdSize != 0 && jCmdData == NULL) || (jReplySize != NULL && jReplyData == NULL)) {
    669         return AUDIOEFFECT_ERROR_BAD_VALUE;
    670     }
    671 
    672     // get the pointer for the command from the java array
    673     if (cmdSize != 0) {
    674         pCmdData = (jbyte *) env->GetPrimitiveArrayCritical(jCmdData, NULL);
    675         if (pCmdData == NULL) {
    676             LOGE("setParameter: Error retrieving command pointer");
    677             goto command_Exit;
    678         }
    679     }
    680 
    681     // get the pointer for the reply size from the java array
    682     if (jReplySize != NULL) {
    683         pReplySize = (jint *) env->GetPrimitiveArrayCritical(jReplySize, NULL);
    684         if (pReplySize == NULL) {
    685             LOGE("setParameter: Error retrieving reply pointer");
    686             goto command_Exit;
    687         }
    688     }
    689 
    690     // get the pointer for the reply from the java array
    691     if (pReplySize != NULL && pReplySize[0] != 0 && jReplyData != NULL) {
    692         pReplyData = (jbyte *) env->GetPrimitiveArrayCritical(jReplyData, NULL);
    693         if (pReplyData == NULL) {
    694             LOGE("setParameter: Error retrieving reply pointer");
    695             goto command_Exit;
    696         }
    697     }
    698 
    699     lStatus = translateError(lpAudioEffect->command((uint32_t)cmdCode,
    700                                                     (uint32_t)cmdSize,
    701                                                     pCmdData,
    702                                                     (uint32_t *)pReplySize,
    703                                                     pReplyData));
    704 
    705 command_Exit:
    706 
    707     if (pCmdData != NULL) {
    708         env->ReleasePrimitiveArrayCritical(jCmdData, pCmdData, 0);
    709     }
    710     if (pReplyData != NULL) {
    711         env->ReleasePrimitiveArrayCritical(jReplyData, pReplyData, 0);
    712     }
    713     if (pReplySize != NULL) {
    714         env->ReleasePrimitiveArrayCritical(jReplySize, pReplySize, 0);
    715     }
    716 
    717     return lStatus;
    718 }
    719 
    720 static jobjectArray
    721 android_media_AudioEffect_native_queryEffects(JNIEnv *env, jclass clazz)
    722 {
    723     effect_descriptor_t desc;
    724     char str[EFFECT_STRING_LEN_MAX];
    725     uint32_t numEffects;
    726     uint32_t i = 0;
    727     jstring jdescType;
    728     jstring jdescUuid;
    729     jstring jdescConnect;
    730     jstring jdescName;
    731     jstring jdescImplementor;
    732     jobject jdesc;
    733 
    734     AudioEffect::queryNumberEffects(&numEffects);
    735     jobjectArray ret = env->NewObjectArray(numEffects, fields.clazzDesc, NULL);
    736     if (ret == NULL) {
    737         return ret;
    738     }
    739 
    740     LOGV("queryEffects() numEffects: %d", numEffects);
    741 
    742     for (i = 0; i < numEffects; i++) {
    743         if (AudioEffect::queryEffect(i, &desc) != NO_ERROR) {
    744             goto queryEffects_failure;
    745         }
    746 
    747         AudioEffect::guidToString(&desc.type, str, EFFECT_STRING_LEN_MAX);
    748         jdescType = env->NewStringUTF(str);
    749 
    750         AudioEffect::guidToString(&desc.uuid, str, EFFECT_STRING_LEN_MAX);
    751         jdescUuid = env->NewStringUTF(str);
    752 
    753         if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
    754             jdescConnect = env->NewStringUTF("Auxiliary");
    755         } else {
    756             jdescConnect = env->NewStringUTF("Insert");
    757         }
    758 
    759         jdescName = env->NewStringUTF(desc.name);
    760         jdescImplementor = env->NewStringUTF(desc.implementor);
    761 
    762         jdesc = env->NewObject(fields.clazzDesc,
    763                                fields.midDescCstor,
    764                                jdescType,
    765                                jdescUuid,
    766                                jdescConnect,
    767                                jdescName,
    768                                jdescImplementor);
    769         env->DeleteLocalRef(jdescType);
    770         env->DeleteLocalRef(jdescUuid);
    771         env->DeleteLocalRef(jdescConnect);
    772         env->DeleteLocalRef(jdescName);
    773         env->DeleteLocalRef(jdescImplementor);
    774         if (jdesc == NULL) {
    775             LOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)");
    776             goto queryEffects_failure;
    777         }
    778 
    779         env->SetObjectArrayElement(ret, i, jdesc);
    780    }
    781 
    782     return ret;
    783 
    784 queryEffects_failure:
    785 
    786     if (ret != NULL) {
    787         env->DeleteLocalRef(ret);
    788     }
    789     return NULL;
    790 
    791 }
    792 
    793 // ----------------------------------------------------------------------------
    794 
    795 // Dalvik VM type signatures
    796 static JNINativeMethod gMethods[] = {
    797     {"native_init",          "()V",      (void *)android_media_AudioEffect_native_init},
    798     {"native_setup",         "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;II[I[Ljava/lang/Object;)I",
    799                                          (void *)android_media_AudioEffect_native_setup},
    800     {"native_finalize",      "()V",      (void *)android_media_AudioEffect_native_finalize},
    801     {"native_release",       "()V",      (void *)android_media_AudioEffect_native_release},
    802     {"native_setEnabled",    "(Z)I",      (void *)android_media_AudioEffect_native_setEnabled},
    803     {"native_getEnabled",    "()Z",      (void *)android_media_AudioEffect_native_getEnabled},
    804     {"native_hasControl",    "()Z",      (void *)android_media_AudioEffect_native_hasControl},
    805     {"native_setParameter",  "(I[BI[B)I",  (void *)android_media_AudioEffect_native_setParameter},
    806     {"native_getParameter",  "(I[B[I[B)I",  (void *)android_media_AudioEffect_native_getParameter},
    807     {"native_command",       "(II[B[I[B)I", (void *)android_media_AudioEffect_native_command},
    808     {"native_query_effects", "()[Ljava/lang/Object;", (void *)android_media_AudioEffect_native_queryEffects},
    809 };
    810 
    811 
    812 // ----------------------------------------------------------------------------
    813 
    814 extern int register_android_media_visualizer(JNIEnv *env);
    815 
    816 int register_android_media_AudioEffect(JNIEnv *env)
    817 {
    818     return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
    819 }
    820 
    821 jint JNI_OnLoad(JavaVM* vm, void* reserved)
    822 {
    823 
    824     JNIEnv* env = NULL;
    825     jint result = -1;
    826 
    827     if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
    828         LOGE("ERROR: GetEnv failed\n");
    829         goto bail;
    830     }
    831     assert(env != NULL);
    832 
    833     if (register_android_media_AudioEffect(env) < 0) {
    834         LOGE("ERROR: AudioEffect native registration failed\n");
    835         goto bail;
    836     }
    837 
    838     if (register_android_media_visualizer(env) < 0) {
    839         LOGE("ERROR: Visualizer native registration failed\n");
    840         goto bail;
    841     }
    842 
    843     /* success -- return valid version number */
    844     result = JNI_VERSION_1_4;
    845 
    846 bail:
    847     return result;
    848 }
    849 
    850