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", "J");
    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", "J");
    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->SetLongField(thiz, fields.fidNativeAudioEffect, (jlong)lpAudioEffect);
    392 
    393     env->SetLongField(thiz, fields.fidJniData, (jlong)lpJniStorage);
    394 
    395     return (jint) 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->SetLongField(thiz, fields.fidNativeAudioEffect, 0);
    408 
    409     if (lpJniStorage) {
    410         delete lpJniStorage;
    411     }
    412     env->SetLongField(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 (jint)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: %p\n", thiz);
    429 
    430     // delete the AudioEffect object
    431     AudioEffect* lpAudioEffect = (AudioEffect *)env->GetLongField(
    432         thiz, fields.fidNativeAudioEffect);
    433     if (lpAudioEffect) {
    434         ALOGV("deleting AudioEffect: %p\n", lpAudioEffect);
    435         delete lpAudioEffect;
    436     }
    437 
    438     // delete the JNI data
    439     AudioEffectJniStorage* lpJniStorage = (AudioEffectJniStorage *)env->GetLongField(
    440         thiz, fields.fidJniData);
    441     if (lpJniStorage) {
    442         ALOGV("deleting pJniStorage: %p\n", 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->SetLongField(thiz, fields.fidNativeAudioEffect, 0);
    455     env->SetLongField(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->GetLongField(
    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 (jint) 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->GetLongField(
    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 JNI_FALSE;
    485     }
    486 
    487     if (lpAudioEffect->getEnabled()) {
    488         return JNI_TRUE;
    489     } else {
    490         return JNI_FALSE;
    491     }
    492 }
    493 
    494 
    495 static jboolean
    496 android_media_AudioEffect_native_hasControl(JNIEnv *env, jobject thiz)
    497 {
    498     // retrieve the AudioEffect object
    499     AudioEffect* lpAudioEffect = (AudioEffect *)env->GetLongField(
    500         thiz, fields.fidNativeAudioEffect);
    501 
    502     if (lpAudioEffect == NULL) {
    503         jniThrowException(env, "java/lang/IllegalStateException",
    504             "Unable to retrieve AudioEffect pointer for hasControl()");
    505         return JNI_FALSE;
    506     }
    507 
    508     if (lpAudioEffect->initCheck() == NO_ERROR) {
    509         return JNI_TRUE;
    510     } else {
    511         return JNI_FALSE;
    512     }
    513 }
    514 
    515 static jint android_media_AudioEffect_native_setParameter(JNIEnv *env,
    516         jobject thiz, jint psize, jbyteArray pJavaParam, jint vsize,
    517         jbyteArray pJavaValue) {
    518     // retrieve the AudioEffect object
    519     jbyte* lpValue = NULL;
    520     jbyte* lpParam = NULL;
    521     jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
    522     effect_param_t *p;
    523     int voffset;
    524 
    525     AudioEffect* lpAudioEffect = (AudioEffect *) env->GetLongField(thiz,
    526             fields.fidNativeAudioEffect);
    527 
    528     if (lpAudioEffect == NULL) {
    529         jniThrowException(env, "java/lang/IllegalStateException",
    530                 "Unable to retrieve AudioEffect pointer for setParameter()");
    531         return AUDIOEFFECT_ERROR_NO_INIT;
    532     }
    533 
    534     if (psize == 0 || vsize == 0 || pJavaParam == NULL || pJavaValue == NULL) {
    535         return AUDIOEFFECT_ERROR_BAD_VALUE;
    536     }
    537 
    538     // get the pointer for the param from the java array
    539     lpParam = (jbyte *) env->GetPrimitiveArrayCritical(pJavaParam, NULL);
    540     if (lpParam == NULL) {
    541         ALOGE("setParameter: Error retrieving param pointer");
    542         goto setParameter_Exit;
    543     }
    544 
    545     // get the pointer for the value from the java array
    546     lpValue = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValue, NULL);
    547     if (lpValue == NULL) {
    548         ALOGE("setParameter: Error retrieving value pointer");
    549         goto setParameter_Exit;
    550     }
    551 
    552     voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int);
    553     p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset + vsize);
    554     memcpy(p->data, lpParam, psize);
    555     p->psize = psize;
    556     memcpy(p->data + voffset, lpValue, vsize);
    557     p->vsize = vsize;
    558 
    559     lStatus = lpAudioEffect->setParameter(p);
    560     if (lStatus == NO_ERROR) {
    561         lStatus = p->status;
    562     }
    563 
    564     free(p);
    565 
    566 setParameter_Exit:
    567 
    568     if (lpParam != NULL) {
    569         env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0);
    570     }
    571     if (lpValue != NULL) {
    572         env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
    573     }
    574     return (jint) translateError(lStatus);
    575 }
    576 
    577 static jint
    578 android_media_AudioEffect_native_getParameter(JNIEnv *env,
    579         jobject thiz, jint psize, jbyteArray pJavaParam,
    580         jint vsize, jbyteArray pJavaValue) {
    581     // retrieve the AudioEffect object
    582     jbyte* lpParam = NULL;
    583     jbyte* lpValue = NULL;
    584     jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
    585     effect_param_t *p;
    586     int voffset;
    587 
    588     AudioEffect* lpAudioEffect = (AudioEffect *) env->GetLongField(thiz,
    589             fields.fidNativeAudioEffect);
    590 
    591     if (lpAudioEffect == NULL) {
    592         jniThrowException(env, "java/lang/IllegalStateException",
    593                 "Unable to retrieve AudioEffect pointer for getParameter()");
    594         return AUDIOEFFECT_ERROR_NO_INIT;
    595     }
    596 
    597     if (psize == 0 || vsize == 0 || pJavaParam == NULL || pJavaValue == NULL) {
    598         return AUDIOEFFECT_ERROR_BAD_VALUE;
    599     }
    600 
    601     // get the pointer for the param from the java array
    602     lpParam = (jbyte *) env->GetPrimitiveArrayCritical(pJavaParam, NULL);
    603     if (lpParam == NULL) {
    604         ALOGE("getParameter: Error retrieving param pointer");
    605         goto getParameter_Exit;
    606     }
    607 
    608     // get the pointer for the value from the java array
    609     lpValue = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValue, NULL);
    610     if (lpValue == NULL) {
    611         ALOGE("getParameter: Error retrieving value pointer");
    612         goto getParameter_Exit;
    613     }
    614 
    615     voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int);
    616     p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset + vsize);
    617     memcpy(p->data, lpParam, psize);
    618     p->psize = psize;
    619     p->vsize = vsize;
    620 
    621     lStatus = lpAudioEffect->getParameter(p);
    622     if (lStatus == NO_ERROR) {
    623         lStatus = p->status;
    624         if (lStatus == NO_ERROR) {
    625             memcpy(lpValue, p->data + voffset, p->vsize);
    626             vsize = p->vsize;
    627         }
    628     }
    629 
    630     free(p);
    631 
    632 getParameter_Exit:
    633 
    634     if (lpParam != NULL) {
    635         env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0);
    636     }
    637     if (lpValue != NULL) {
    638         env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
    639     }
    640 
    641     if (lStatus == NO_ERROR) {
    642         return vsize;
    643     }
    644     return (jint) translateError(lStatus);
    645 }
    646 
    647 static jint android_media_AudioEffect_native_command(JNIEnv *env, jobject thiz,
    648         jint cmdCode, jint cmdSize, jbyteArray jCmdData, jint replySize,
    649         jbyteArray jReplyData) {
    650     jbyte* pCmdData = NULL;
    651     jbyte* pReplyData = NULL;
    652     jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
    653 
    654     // retrieve the AudioEffect object
    655     AudioEffect* lpAudioEffect = (AudioEffect *) env->GetLongField(thiz,
    656             fields.fidNativeAudioEffect);
    657 
    658     if (lpAudioEffect == NULL) {
    659         jniThrowException(env, "java/lang/IllegalStateException",
    660                 "Unable to retrieve AudioEffect pointer for setParameter()");
    661         return AUDIOEFFECT_ERROR_NO_INIT;
    662     }
    663 
    664     if ((cmdSize != 0 && jCmdData == NULL) || (replySize != 0 && jReplyData == NULL)) {
    665         return AUDIOEFFECT_ERROR_BAD_VALUE;
    666     }
    667 
    668     // get the pointer for the command from the java array
    669     if (cmdSize != 0) {
    670         pCmdData = (jbyte *) env->GetPrimitiveArrayCritical(jCmdData, NULL);
    671         if (pCmdData == NULL) {
    672             ALOGE("setParameter: Error retrieving command pointer");
    673             goto command_Exit;
    674         }
    675     }
    676 
    677     // get the pointer for the reply from the java array
    678     if (replySize != 0 && jReplyData != NULL) {
    679         pReplyData = (jbyte *) env->GetPrimitiveArrayCritical(jReplyData, NULL);
    680         if (pReplyData == NULL) {
    681             ALOGE("setParameter: Error retrieving reply pointer");
    682             goto command_Exit;
    683         }
    684     }
    685 
    686     lStatus = translateError(lpAudioEffect->command((uint32_t)cmdCode,
    687                                                     (uint32_t)cmdSize,
    688                                                     pCmdData,
    689                                                     (uint32_t *)&replySize,
    690                                                     pReplyData));
    691 
    692 command_Exit:
    693 
    694     if (pCmdData != NULL) {
    695         env->ReleasePrimitiveArrayCritical(jCmdData, pCmdData, 0);
    696     }
    697     if (pReplyData != NULL) {
    698         env->ReleasePrimitiveArrayCritical(jReplyData, pReplyData, 0);
    699     }
    700 
    701     if (lStatus == NO_ERROR) {
    702         return replySize;
    703     }
    704     return lStatus;
    705 }
    706 
    707 static jobjectArray
    708 android_media_AudioEffect_native_queryEffects(JNIEnv *env, jclass clazz __unused)
    709 {
    710     effect_descriptor_t desc;
    711     char str[EFFECT_STRING_LEN_MAX];
    712     uint32_t totalEffectsCount = 0;
    713     uint32_t returnedEffectsCount = 0;
    714     uint32_t i = 0;
    715     jstring jdescType;
    716     jstring jdescUuid;
    717     jstring jdescConnect;
    718     jstring jdescName;
    719     jstring jdescImplementor;
    720     jobject jdesc;
    721     jobjectArray ret;
    722 
    723     if (AudioEffect::queryNumberEffects(&totalEffectsCount) != NO_ERROR) {
    724         return NULL;
    725     }
    726 
    727     jobjectArray temp = env->NewObjectArray(totalEffectsCount, fields.clazzDesc, NULL);
    728     if (temp == NULL) {
    729         return temp;
    730     }
    731 
    732     ALOGV("queryEffects() totalEffectsCount: %d", totalEffectsCount);
    733 
    734     for (i = 0; i < totalEffectsCount; i++) {
    735         if (AudioEffect::queryEffect(i, &desc) != NO_ERROR) {
    736             goto queryEffects_failure;
    737         }
    738 
    739         if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
    740             jdescConnect = env->NewStringUTF("Auxiliary");
    741         } else if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_INSERT) {
    742             jdescConnect = env->NewStringUTF("Insert");
    743         } else if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC) {
    744             jdescConnect = env->NewStringUTF("Pre Processing");
    745         } else {
    746             continue;
    747         }
    748 
    749         AudioEffect::guidToString(&desc.type, str, EFFECT_STRING_LEN_MAX);
    750         jdescType = env->NewStringUTF(str);
    751 
    752         AudioEffect::guidToString(&desc.uuid, str, EFFECT_STRING_LEN_MAX);
    753         jdescUuid = env->NewStringUTF(str);
    754 
    755         jdescName = env->NewStringUTF(desc.name);
    756         jdescImplementor = env->NewStringUTF(desc.implementor);
    757 
    758         jdesc = env->NewObject(fields.clazzDesc,
    759                                fields.midDescCstor,
    760                                jdescType,
    761                                jdescUuid,
    762                                jdescConnect,
    763                                jdescName,
    764                                jdescImplementor);
    765         env->DeleteLocalRef(jdescType);
    766         env->DeleteLocalRef(jdescUuid);
    767         env->DeleteLocalRef(jdescConnect);
    768         env->DeleteLocalRef(jdescName);
    769         env->DeleteLocalRef(jdescImplementor);
    770         if (jdesc == NULL) {
    771             ALOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)");
    772             goto queryEffects_failure;
    773         }
    774 
    775         env->SetObjectArrayElement(temp, returnedEffectsCount++, jdesc);
    776    }
    777 
    778     if (returnedEffectsCount == 0) {
    779         goto queryEffects_failure;
    780     }
    781     ret = env->NewObjectArray(returnedEffectsCount, fields.clazzDesc, NULL);
    782     if (ret == NULL) {
    783         goto queryEffects_failure;
    784     }
    785     for (i = 0; i < returnedEffectsCount; i++) {
    786         env->SetObjectArrayElement(ret, i, env->GetObjectArrayElement(temp, i));
    787     }
    788     env->DeleteLocalRef(temp);
    789     return ret;
    790 
    791 queryEffects_failure:
    792 
    793     if (temp != NULL) {
    794         env->DeleteLocalRef(temp);
    795     }
    796     return NULL;
    797 
    798 }
    799 
    800 
    801 
    802 static jobjectArray
    803 android_media_AudioEffect_native_queryPreProcessings(JNIEnv *env, jclass clazz __unused,
    804                                                      jint audioSession)
    805 {
    806     // kDefaultNumEffects is a "reasonable" value ensuring that only one query will be enough on
    807     // most devices to get all active audio pre processing on a given session.
    808     static const uint32_t kDefaultNumEffects = 5;
    809 
    810     effect_descriptor_t *descriptors = new effect_descriptor_t[kDefaultNumEffects];
    811     uint32_t numEffects = kDefaultNumEffects;
    812 
    813     status_t status = AudioEffect::queryDefaultPreProcessing(audioSession,
    814                                            descriptors,
    815                                            &numEffects);
    816     if ((status != NO_ERROR && status != NO_MEMORY) ||
    817             numEffects == 0) {
    818         delete[] descriptors;
    819         return NULL;
    820     }
    821     if (status == NO_MEMORY) {
    822         delete [] descriptors;
    823         descriptors = new effect_descriptor_t[numEffects];
    824         status = AudioEffect::queryDefaultPreProcessing(audioSession,
    825                                                descriptors,
    826                                                &numEffects);
    827     }
    828     if (status != NO_ERROR || numEffects == 0) {
    829         delete[] descriptors;
    830         return NULL;
    831     }
    832     ALOGV("queryDefaultPreProcessing() got %d effects", numEffects);
    833 
    834     jobjectArray ret = env->NewObjectArray(numEffects, fields.clazzDesc, NULL);
    835     if (ret == NULL) {
    836         delete[] descriptors;
    837         return ret;
    838     }
    839 
    840     char str[EFFECT_STRING_LEN_MAX];
    841     jstring jdescType;
    842     jstring jdescUuid;
    843     jstring jdescConnect;
    844     jstring jdescName;
    845     jstring jdescImplementor;
    846     jobject jdesc;
    847 
    848     for (uint32_t i = 0; i < numEffects; i++) {
    849 
    850         AudioEffect::guidToString(&descriptors[i].type, str, EFFECT_STRING_LEN_MAX);
    851         jdescType = env->NewStringUTF(str);
    852         AudioEffect::guidToString(&descriptors[i].uuid, str, EFFECT_STRING_LEN_MAX);
    853         jdescUuid = env->NewStringUTF(str);
    854         jdescConnect = env->NewStringUTF("Pre Processing");
    855         jdescName = env->NewStringUTF(descriptors[i].name);
    856         jdescImplementor = env->NewStringUTF(descriptors[i].implementor);
    857 
    858         jdesc = env->NewObject(fields.clazzDesc,
    859                                fields.midDescCstor,
    860                                jdescType,
    861                                jdescUuid,
    862                                jdescConnect,
    863                                jdescName,
    864                                jdescImplementor);
    865         env->DeleteLocalRef(jdescType);
    866         env->DeleteLocalRef(jdescUuid);
    867         env->DeleteLocalRef(jdescConnect);
    868         env->DeleteLocalRef(jdescName);
    869         env->DeleteLocalRef(jdescImplementor);
    870         if (jdesc == NULL) {
    871             ALOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)");
    872             env->DeleteLocalRef(ret);
    873             return NULL;;
    874         }
    875 
    876         env->SetObjectArrayElement(ret, i, jdesc);
    877    }
    878 
    879    return ret;
    880 }
    881 
    882 // ----------------------------------------------------------------------------
    883 
    884 // Dalvik VM type signatures
    885 static JNINativeMethod gMethods[] = {
    886     {"native_init",          "()V",      (void *)android_media_AudioEffect_native_init},
    887     {"native_setup",         "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;II[I[Ljava/lang/Object;)I",
    888                                          (void *)android_media_AudioEffect_native_setup},
    889     {"native_finalize",      "()V",      (void *)android_media_AudioEffect_native_finalize},
    890     {"native_release",       "()V",      (void *)android_media_AudioEffect_native_release},
    891     {"native_setEnabled",    "(Z)I",      (void *)android_media_AudioEffect_native_setEnabled},
    892     {"native_getEnabled",    "()Z",      (void *)android_media_AudioEffect_native_getEnabled},
    893     {"native_hasControl",    "()Z",      (void *)android_media_AudioEffect_native_hasControl},
    894     {"native_setParameter",  "(I[BI[B)I",  (void *)android_media_AudioEffect_native_setParameter},
    895     {"native_getParameter",  "(I[BI[B)I",  (void *)android_media_AudioEffect_native_getParameter},
    896     {"native_command",       "(II[BI[B)I", (void *)android_media_AudioEffect_native_command},
    897     {"native_query_effects", "()[Ljava/lang/Object;", (void *)android_media_AudioEffect_native_queryEffects},
    898     {"native_query_pre_processing", "(I)[Ljava/lang/Object;",
    899             (void *)android_media_AudioEffect_native_queryPreProcessings},
    900 };
    901 
    902 
    903 // ----------------------------------------------------------------------------
    904 
    905 extern int register_android_media_visualizer(JNIEnv *env);
    906 
    907 int register_android_media_AudioEffect(JNIEnv *env)
    908 {
    909     return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
    910 }
    911 
    912 jint JNI_OnLoad(JavaVM* vm, void* reserved __unused)
    913 {
    914 
    915     JNIEnv* env = NULL;
    916     jint result = -1;
    917 
    918     if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
    919         ALOGE("ERROR: GetEnv failed\n");
    920         goto bail;
    921     }
    922     assert(env != NULL);
    923 
    924     if (register_android_media_AudioEffect(env) < 0) {
    925         ALOGE("ERROR: AudioEffect native registration failed\n");
    926         goto bail;
    927     }
    928 
    929     if (register_android_media_visualizer(env) < 0) {
    930         ALOGE("ERROR: Visualizer native registration failed\n");
    931         goto bail;
    932     }
    933 
    934     /* success -- return valid version number */
    935     result = JNI_VERSION_1_4;
    936 
    937 bail:
    938     return result;
    939 }
    940 
    941