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     ALOGV("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         ALOGW("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             ALOGW("EVENT_CONTROL_STATUS_CHANGED info == NULL");
    123             goto effectCallback_Exit;
    124         }
    125         param = *(bool *)info;
    126         arg1 = (int)param;
    127         ALOGV("EVENT_CONTROL_STATUS_CHANGED");
    128         break;
    129     case AudioEffect::EVENT_ENABLE_STATUS_CHANGED:
    130         if (info == 0) {
    131             ALOGW("EVENT_ENABLE_STATUS_CHANGED info == NULL");
    132             goto effectCallback_Exit;
    133         }
    134         param = *(bool *)info;
    135         arg1 = (int)param;
    136         ALOGV("EVENT_ENABLE_STATUS_CHANGED");
    137         break;
    138     case AudioEffect::EVENT_PARAMETER_CHANGED:
    139         if (info == 0) {
    140             ALOGW("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             ALOGE("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         ALOGV("EVENT_PARAMETER_CHANGED");
    160        break;
    161     case AudioEffect::EVENT_ERROR:
    162         ALOGW("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     ALOGV("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         ALOGE("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         ALOGE("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         ALOGE("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         ALOGE("Can't find AudioEffect.%s", "mJniData");
    228         return;
    229     }
    230 
    231     clazz = env->FindClass("android/media/audiofx/AudioEffect$Descriptor");
    232     if (clazz == NULL) {
    233         ALOGE("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         ALOGE("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     ALOGV("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         ALOGE("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     ALOGV("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         ALOGE("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         ALOGE("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         ALOGE("AudioEffect initCheck failed %d", lStatus);
    329         goto setup_failure;
    330     }
    331 
    332     nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL);
    333     if (nId == NULL) {
    334         ALOGE("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 if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC) {
    364         jdescConnect = env->NewStringUTF("Pre Processing");
    365     } else {
    366         jdescConnect = env->NewStringUTF("Insert");
    367     }
    368 
    369     jdescName = env->NewStringUTF(desc.name);
    370     jdescImplementor = env->NewStringUTF(desc.implementor);
    371 
    372     jdesc = env->NewObject(fields.clazzDesc,
    373                            fields.midDescCstor,
    374                            jdescType,
    375                            jdescUuid,
    376                            jdescConnect,
    377                            jdescName,
    378                            jdescImplementor);
    379     env->DeleteLocalRef(jdescType);
    380     env->DeleteLocalRef(jdescUuid);
    381     env->DeleteLocalRef(jdescConnect);
    382     env->DeleteLocalRef(jdescName);
    383     env->DeleteLocalRef(jdescImplementor);
    384     if (jdesc == NULL) {
    385         ALOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)");
    386         goto setup_failure;
    387     }
    388 
    389     env->SetObjectArrayElement(javadesc, 0, jdesc);
    390 
    391     env->SetIntField(thiz, fields.fidNativeAudioEffect, (int)lpAudioEffect);
    392 
    393     env->SetIntField(thiz, fields.fidJniData, (int)lpJniStorage);
    394 
    395     return AUDIOEFFECT_SUCCESS;
    396 
    397     // failures:
    398 setup_failure:
    399 
    400     if (nId != NULL) {
    401         env->ReleasePrimitiveArrayCritical(jId, nId, 0);
    402     }
    403 
    404     if (lpAudioEffect) {
    405         delete lpAudioEffect;
    406     }
    407     env->SetIntField(thiz, fields.fidNativeAudioEffect, 0);
    408 
    409     if (lpJniStorage) {
    410         delete lpJniStorage;
    411     }
    412     env->SetIntField(thiz, fields.fidJniData, 0);
    413 
    414     if (uuidStr != NULL) {
    415         env->ReleaseStringUTFChars(uuid, uuidStr);
    416     }
    417 
    418     if (typeStr != NULL) {
    419         env->ReleaseStringUTFChars(type, typeStr);
    420     }
    421 
    422     return lStatus;
    423 }
    424 
    425 
    426 // ----------------------------------------------------------------------------
    427 static void android_media_AudioEffect_native_finalize(JNIEnv *env,  jobject thiz) {
    428     ALOGV("android_media_AudioEffect_native_finalize jobject: %x\n", (int)thiz);
    429 
    430     // delete the AudioEffect object
    431     AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
    432         thiz, fields.fidNativeAudioEffect);
    433     if (lpAudioEffect) {
    434         ALOGV("deleting AudioEffect: %x\n", (int)lpAudioEffect);
    435         delete lpAudioEffect;
    436     }
    437 
    438     // delete the JNI data
    439     AudioEffectJniStorage* lpJniStorage = (AudioEffectJniStorage *)env->GetIntField(
    440         thiz, fields.fidJniData);
    441     if (lpJniStorage) {
    442         ALOGV("deleting pJniStorage: %x\n", (int)lpJniStorage);
    443         delete lpJniStorage;
    444     }
    445 }
    446 
    447 // ----------------------------------------------------------------------------
    448 static void android_media_AudioEffect_native_release(JNIEnv *env,  jobject thiz) {
    449 
    450     // do everything a call to finalize would
    451     android_media_AudioEffect_native_finalize(env, thiz);
    452     // + reset the native resources in the Java object so any attempt to access
    453     // them after a call to release fails.
    454     env->SetIntField(thiz, fields.fidNativeAudioEffect, 0);
    455     env->SetIntField(thiz, fields.fidJniData, 0);
    456 }
    457 
    458 static jint
    459 android_media_AudioEffect_native_setEnabled(JNIEnv *env, jobject thiz, jboolean enabled)
    460 {
    461     // retrieve the AudioEffect object
    462     AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
    463         thiz, fields.fidNativeAudioEffect);
    464 
    465     if (lpAudioEffect == NULL) {
    466         jniThrowException(env, "java/lang/IllegalStateException",
    467             "Unable to retrieve AudioEffect pointer for enable()");
    468         return AUDIOEFFECT_ERROR_NO_INIT;
    469     }
    470 
    471     return translateError(lpAudioEffect->setEnabled(enabled));
    472 }
    473 
    474 static jboolean
    475 android_media_AudioEffect_native_getEnabled(JNIEnv *env, jobject thiz)
    476 {
    477     // retrieve the AudioEffect object
    478     AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
    479         thiz, fields.fidNativeAudioEffect);
    480 
    481     if (lpAudioEffect == NULL) {
    482         jniThrowException(env, "java/lang/IllegalStateException",
    483             "Unable to retrieve AudioEffect pointer for getEnabled()");
    484         return false;
    485     }
    486 
    487     return (jboolean)lpAudioEffect->getEnabled();
    488 }
    489 
    490 
    491 static jboolean
    492 android_media_AudioEffect_native_hasControl(JNIEnv *env, jobject thiz)
    493 {
    494     // retrieve the AudioEffect object
    495     AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
    496         thiz, fields.fidNativeAudioEffect);
    497 
    498     if (lpAudioEffect == NULL) {
    499         jniThrowException(env, "java/lang/IllegalStateException",
    500             "Unable to retrieve AudioEffect pointer for hasControl()");
    501         return false;
    502     }
    503 
    504     if (lpAudioEffect->initCheck() == NO_ERROR) {
    505         return true;
    506     } else {
    507         return false;
    508     }
    509 }
    510 
    511 static jint android_media_AudioEffect_native_setParameter(JNIEnv *env,
    512         jobject thiz, int psize, jbyteArray pJavaParam, int vsize,
    513         jbyteArray pJavaValue) {
    514     // retrieve the AudioEffect object
    515     jbyte* lpValue = NULL;
    516     jbyte* lpParam = NULL;
    517     jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
    518     effect_param_t *p;
    519     int voffset;
    520 
    521     AudioEffect* lpAudioEffect = (AudioEffect *) env->GetIntField(thiz,
    522             fields.fidNativeAudioEffect);
    523 
    524     if (lpAudioEffect == NULL) {
    525         jniThrowException(env, "java/lang/IllegalStateException",
    526                 "Unable to retrieve AudioEffect pointer for setParameter()");
    527         return AUDIOEFFECT_ERROR_NO_INIT;
    528     }
    529 
    530     if (psize == 0 || vsize == 0 || pJavaParam == NULL || pJavaValue == NULL) {
    531         return AUDIOEFFECT_ERROR_BAD_VALUE;
    532     }
    533 
    534     // get the pointer for the param from the java array
    535     lpParam = (jbyte *) env->GetPrimitiveArrayCritical(pJavaParam, NULL);
    536     if (lpParam == NULL) {
    537         ALOGE("setParameter: Error retrieving param pointer");
    538         goto setParameter_Exit;
    539     }
    540 
    541     // get the pointer for the value from the java array
    542     lpValue = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValue, NULL);
    543     if (lpValue == NULL) {
    544         ALOGE("setParameter: Error retrieving value pointer");
    545         goto setParameter_Exit;
    546     }
    547 
    548     voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int);
    549     p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset + vsize);
    550     memcpy(p->data, lpParam, psize);
    551     p->psize = psize;
    552     memcpy(p->data + voffset, lpValue, vsize);
    553     p->vsize = vsize;
    554 
    555     lStatus = lpAudioEffect->setParameter(p);
    556     if (lStatus == NO_ERROR) {
    557         lStatus = p->status;
    558     }
    559 
    560     free(p);
    561 
    562 setParameter_Exit:
    563 
    564     if (lpParam != NULL) {
    565         env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0);
    566     }
    567     if (lpValue != NULL) {
    568         env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
    569     }
    570     return translateError(lStatus);
    571 }
    572 
    573 static jint
    574 android_media_AudioEffect_native_getParameter(JNIEnv *env,
    575         jobject thiz, jint psize, jbyteArray pJavaParam,
    576         jint vsize, jbyteArray pJavaValue) {
    577     // retrieve the AudioEffect object
    578     jbyte* lpParam = NULL;
    579     jbyte* lpValue = NULL;
    580     jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
    581     effect_param_t *p;
    582     int voffset;
    583 
    584     AudioEffect* lpAudioEffect = (AudioEffect *) env->GetIntField(thiz,
    585             fields.fidNativeAudioEffect);
    586 
    587     if (lpAudioEffect == NULL) {
    588         jniThrowException(env, "java/lang/IllegalStateException",
    589                 "Unable to retrieve AudioEffect pointer for getParameter()");
    590         return AUDIOEFFECT_ERROR_NO_INIT;
    591     }
    592 
    593     if (psize == 0 || vsize == 0 || pJavaParam == NULL || pJavaValue == NULL) {
    594         return AUDIOEFFECT_ERROR_BAD_VALUE;
    595     }
    596 
    597     // get the pointer for the param from the java array
    598     lpParam = (jbyte *) env->GetPrimitiveArrayCritical(pJavaParam, NULL);
    599     if (lpParam == NULL) {
    600         ALOGE("getParameter: Error retrieving param pointer");
    601         goto getParameter_Exit;
    602     }
    603 
    604     // get the pointer for the value from the java array
    605     lpValue = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValue, NULL);
    606     if (lpValue == NULL) {
    607         ALOGE("getParameter: Error retrieving value pointer");
    608         goto getParameter_Exit;
    609     }
    610 
    611     voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int);
    612     p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset + vsize);
    613     memcpy(p->data, lpParam, psize);
    614     p->psize = psize;
    615     p->vsize = vsize;
    616 
    617     lStatus = lpAudioEffect->getParameter(p);
    618     if (lStatus == NO_ERROR) {
    619         lStatus = p->status;
    620         if (lStatus == NO_ERROR) {
    621             memcpy(lpValue, p->data + voffset, p->vsize);
    622             vsize = p->vsize;
    623         }
    624     }
    625 
    626     free(p);
    627 
    628 getParameter_Exit:
    629 
    630     if (lpParam != NULL) {
    631         env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0);
    632     }
    633     if (lpValue != NULL) {
    634         env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
    635     }
    636 
    637     if (lStatus == NO_ERROR) {
    638         return vsize;
    639     }
    640     return translateError(lStatus);
    641 }
    642 
    643 static jint android_media_AudioEffect_native_command(JNIEnv *env, jobject thiz,
    644         jint cmdCode, jint cmdSize, jbyteArray jCmdData, jint replySize,
    645         jbyteArray jReplyData) {
    646     jbyte* pCmdData = NULL;
    647     jbyte* pReplyData = NULL;
    648     jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
    649 
    650     // retrieve the AudioEffect object
    651     AudioEffect* lpAudioEffect = (AudioEffect *) env->GetIntField(thiz,
    652             fields.fidNativeAudioEffect);
    653 
    654     if (lpAudioEffect == NULL) {
    655         jniThrowException(env, "java/lang/IllegalStateException",
    656                 "Unable to retrieve AudioEffect pointer for setParameter()");
    657         return AUDIOEFFECT_ERROR_NO_INIT;
    658     }
    659 
    660     if ((cmdSize != 0 && jCmdData == NULL) || (replySize != 0 && jReplyData == NULL)) {
    661         return AUDIOEFFECT_ERROR_BAD_VALUE;
    662     }
    663 
    664     // get the pointer for the command from the java array
    665     if (cmdSize != 0) {
    666         pCmdData = (jbyte *) env->GetPrimitiveArrayCritical(jCmdData, NULL);
    667         if (pCmdData == NULL) {
    668             ALOGE("setParameter: Error retrieving command pointer");
    669             goto command_Exit;
    670         }
    671     }
    672 
    673     // get the pointer for the reply from the java array
    674     if (replySize != 0 && jReplyData != NULL) {
    675         pReplyData = (jbyte *) env->GetPrimitiveArrayCritical(jReplyData, NULL);
    676         if (pReplyData == NULL) {
    677             ALOGE("setParameter: Error retrieving reply pointer");
    678             goto command_Exit;
    679         }
    680     }
    681 
    682     lStatus = translateError(lpAudioEffect->command((uint32_t)cmdCode,
    683                                                     (uint32_t)cmdSize,
    684                                                     pCmdData,
    685                                                     (uint32_t *)&replySize,
    686                                                     pReplyData));
    687 
    688 command_Exit:
    689 
    690     if (pCmdData != NULL) {
    691         env->ReleasePrimitiveArrayCritical(jCmdData, pCmdData, 0);
    692     }
    693     if (pReplyData != NULL) {
    694         env->ReleasePrimitiveArrayCritical(jReplyData, pReplyData, 0);
    695     }
    696 
    697     if (lStatus == NO_ERROR) {
    698         return replySize;
    699     }
    700     return lStatus;
    701 }
    702 
    703 static jobjectArray
    704 android_media_AudioEffect_native_queryEffects(JNIEnv *env, jclass clazz)
    705 {
    706     effect_descriptor_t desc;
    707     char str[EFFECT_STRING_LEN_MAX];
    708     uint32_t numEffects;
    709     uint32_t i = 0;
    710     jstring jdescType;
    711     jstring jdescUuid;
    712     jstring jdescConnect;
    713     jstring jdescName;
    714     jstring jdescImplementor;
    715     jobject jdesc;
    716 
    717     AudioEffect::queryNumberEffects(&numEffects);
    718     jobjectArray ret = env->NewObjectArray(numEffects, fields.clazzDesc, NULL);
    719     if (ret == NULL) {
    720         return ret;
    721     }
    722 
    723     ALOGV("queryEffects() numEffects: %d", numEffects);
    724 
    725     for (i = 0; i < numEffects; i++) {
    726         if (AudioEffect::queryEffect(i, &desc) != NO_ERROR) {
    727             goto queryEffects_failure;
    728         }
    729 
    730         if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
    731             jdescConnect = env->NewStringUTF("Auxiliary");
    732         } else if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_INSERT) {
    733             jdescConnect = env->NewStringUTF("Insert");
    734         } else if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC) {
    735             jdescConnect = env->NewStringUTF("Pre Processing");
    736         } else {
    737             continue;
    738         }
    739 
    740         AudioEffect::guidToString(&desc.type, str, EFFECT_STRING_LEN_MAX);
    741         jdescType = env->NewStringUTF(str);
    742 
    743         AudioEffect::guidToString(&desc.uuid, str, EFFECT_STRING_LEN_MAX);
    744         jdescUuid = env->NewStringUTF(str);
    745 
    746         jdescName = env->NewStringUTF(desc.name);
    747         jdescImplementor = env->NewStringUTF(desc.implementor);
    748 
    749         jdesc = env->NewObject(fields.clazzDesc,
    750                                fields.midDescCstor,
    751                                jdescType,
    752                                jdescUuid,
    753                                jdescConnect,
    754                                jdescName,
    755                                jdescImplementor);
    756         env->DeleteLocalRef(jdescType);
    757         env->DeleteLocalRef(jdescUuid);
    758         env->DeleteLocalRef(jdescConnect);
    759         env->DeleteLocalRef(jdescName);
    760         env->DeleteLocalRef(jdescImplementor);
    761         if (jdesc == NULL) {
    762             ALOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)");
    763             goto queryEffects_failure;
    764         }
    765 
    766         env->SetObjectArrayElement(ret, i, jdesc);
    767    }
    768 
    769     return ret;
    770 
    771 queryEffects_failure:
    772 
    773     if (ret != NULL) {
    774         env->DeleteLocalRef(ret);
    775     }
    776     return NULL;
    777 
    778 }
    779 
    780 
    781 
    782 static jobjectArray
    783 android_media_AudioEffect_native_queryPreProcessings(JNIEnv *env, jclass clazz, jint audioSession)
    784 {
    785     // kDefaultNumEffects is a "reasonable" value ensuring that only one query will be enough on
    786     // most devices to get all active audio pre processing on a given session.
    787     static const uint32_t kDefaultNumEffects = 5;
    788 
    789     effect_descriptor_t *descriptors = new effect_descriptor_t[kDefaultNumEffects];
    790     uint32_t numEffects = kDefaultNumEffects;
    791 
    792     status_t status = AudioEffect::queryDefaultPreProcessing(audioSession,
    793                                            descriptors,
    794                                            &numEffects);
    795     if ((status != NO_ERROR && status != NO_MEMORY) ||
    796             numEffects == 0) {
    797         delete[] descriptors;
    798         return NULL;
    799     }
    800     if (status == NO_MEMORY) {
    801         delete [] descriptors;
    802         descriptors = new effect_descriptor_t[numEffects];
    803         status = AudioEffect::queryDefaultPreProcessing(audioSession,
    804                                                descriptors,
    805                                                &numEffects);
    806     }
    807     if (status != NO_ERROR || numEffects == 0) {
    808         delete[] descriptors;
    809         return NULL;
    810     }
    811     ALOGV("queryDefaultPreProcessing() got %d effects", numEffects);
    812 
    813     jobjectArray ret = env->NewObjectArray(numEffects, fields.clazzDesc, NULL);
    814     if (ret == NULL) {
    815         delete[] descriptors;
    816         return ret;
    817     }
    818 
    819     char str[EFFECT_STRING_LEN_MAX];
    820     jstring jdescType;
    821     jstring jdescUuid;
    822     jstring jdescConnect;
    823     jstring jdescName;
    824     jstring jdescImplementor;
    825     jobject jdesc;
    826 
    827     for (uint32_t i = 0; i < numEffects; i++) {
    828 
    829         AudioEffect::guidToString(&descriptors[i].type, str, EFFECT_STRING_LEN_MAX);
    830         jdescType = env->NewStringUTF(str);
    831         AudioEffect::guidToString(&descriptors[i].uuid, str, EFFECT_STRING_LEN_MAX);
    832         jdescUuid = env->NewStringUTF(str);
    833         jdescConnect = env->NewStringUTF("Pre Processing");
    834         jdescName = env->NewStringUTF(descriptors[i].name);
    835         jdescImplementor = env->NewStringUTF(descriptors[i].implementor);
    836 
    837         jdesc = env->NewObject(fields.clazzDesc,
    838                                fields.midDescCstor,
    839                                jdescType,
    840                                jdescUuid,
    841                                jdescConnect,
    842                                jdescName,
    843                                jdescImplementor);
    844         env->DeleteLocalRef(jdescType);
    845         env->DeleteLocalRef(jdescUuid);
    846         env->DeleteLocalRef(jdescConnect);
    847         env->DeleteLocalRef(jdescName);
    848         env->DeleteLocalRef(jdescImplementor);
    849         if (jdesc == NULL) {
    850             ALOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)");
    851             env->DeleteLocalRef(ret);
    852             return NULL;;
    853         }
    854 
    855         env->SetObjectArrayElement(ret, i, jdesc);
    856    }
    857 
    858    return ret;
    859 }
    860 
    861 // ----------------------------------------------------------------------------
    862 
    863 // Dalvik VM type signatures
    864 static JNINativeMethod gMethods[] = {
    865     {"native_init",          "()V",      (void *)android_media_AudioEffect_native_init},
    866     {"native_setup",         "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;II[I[Ljava/lang/Object;)I",
    867                                          (void *)android_media_AudioEffect_native_setup},
    868     {"native_finalize",      "()V",      (void *)android_media_AudioEffect_native_finalize},
    869     {"native_release",       "()V",      (void *)android_media_AudioEffect_native_release},
    870     {"native_setEnabled",    "(Z)I",      (void *)android_media_AudioEffect_native_setEnabled},
    871     {"native_getEnabled",    "()Z",      (void *)android_media_AudioEffect_native_getEnabled},
    872     {"native_hasControl",    "()Z",      (void *)android_media_AudioEffect_native_hasControl},
    873     {"native_setParameter",  "(I[BI[B)I",  (void *)android_media_AudioEffect_native_setParameter},
    874     {"native_getParameter",  "(I[BI[B)I",  (void *)android_media_AudioEffect_native_getParameter},
    875     {"native_command",       "(II[BI[B)I", (void *)android_media_AudioEffect_native_command},
    876     {"native_query_effects", "()[Ljava/lang/Object;", (void *)android_media_AudioEffect_native_queryEffects},
    877     {"native_query_pre_processing", "(I)[Ljava/lang/Object;",
    878             (void *)android_media_AudioEffect_native_queryPreProcessings},
    879 };
    880 
    881 
    882 // ----------------------------------------------------------------------------
    883 
    884 extern int register_android_media_visualizer(JNIEnv *env);
    885 
    886 int register_android_media_AudioEffect(JNIEnv *env)
    887 {
    888     return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
    889 }
    890 
    891 jint JNI_OnLoad(JavaVM* vm, void* reserved)
    892 {
    893 
    894     JNIEnv* env = NULL;
    895     jint result = -1;
    896 
    897     if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
    898         ALOGE("ERROR: GetEnv failed\n");
    899         goto bail;
    900     }
    901     assert(env != NULL);
    902 
    903     if (register_android_media_AudioEffect(env) < 0) {
    904         ALOGE("ERROR: AudioEffect native registration failed\n");
    905         goto bail;
    906     }
    907 
    908     if (register_android_media_visualizer(env) < 0) {
    909         ALOGE("ERROR: Visualizer native registration failed\n");
    910         goto bail;
    911     }
    912 
    913     /* success -- return valid version number */
    914     result = JNI_VERSION_1_4;
    915 
    916 bail:
    917     return result;
    918 }
    919 
    920