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