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