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