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 "visualizers-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 <utils/threads.h>
     27 #include "media/Visualizer.h"
     28 
     29 using namespace android;
     30 
     31 #define VISUALIZER_SUCCESS                      0
     32 #define VISUALIZER_ERROR                       -1
     33 #define VISUALIZER_ERROR_ALREADY_EXISTS        -2
     34 #define VISUALIZER_ERROR_NO_INIT               -3
     35 #define VISUALIZER_ERROR_BAD_VALUE             -4
     36 #define VISUALIZER_ERROR_INVALID_OPERATION     -5
     37 #define VISUALIZER_ERROR_NO_MEMORY             -6
     38 #define VISUALIZER_ERROR_DEAD_OBJECT           -7
     39 
     40 #define NATIVE_EVENT_PCM_CAPTURE                0
     41 #define NATIVE_EVENT_FFT_CAPTURE                1
     42 #define NATIVE_EVENT_SERVER_DIED                2
     43 
     44 // ----------------------------------------------------------------------------
     45 static const char* const kClassPathName = "android/media/audiofx/Visualizer";
     46 static const char* const kClassPeakRmsPathName =
     47         "android/media/audiofx/Visualizer$MeasurementPeakRms";
     48 
     49 struct fields_t {
     50     // these fields provide access from C++ to the...
     51     jclass    clazzEffect;          // Visualizer class
     52     jmethodID midPostNativeEvent;   // event post callback method
     53     jfieldID  fidNativeVisualizer; // stores in Java the native Visualizer object
     54     jfieldID  fidJniData;           // stores in Java additional resources used by the native Visualizer
     55     jfieldID  fidPeak; // to access Visualizer.MeasurementPeakRms.mPeak
     56     jfieldID  fidRms;  // to access Visualizer.MeasurementPeakRms.mRms
     57 };
     58 static fields_t fields;
     59 
     60 struct visualizer_callback_cookie {
     61     jclass      visualizer_class;  // Visualizer class
     62     jobject     visualizer_ref;    // Visualizer object instance
     63 
     64     // Lazily allocated arrays used to hold callback data provided to java
     65     // applications.  These arrays are allocated during the first callback and
     66     // reallocated when the size of the callback data changes.  Allocating on
     67     // demand and saving the arrays means that applications cannot safely hold a
     68     // reference to the provided data (they need to make a copy if they want to
     69     // hold onto outside of the callback scope), but it avoids GC thrash caused
     70     // by constantly allocating and releasing arrays to hold callback data.
     71     Mutex       callback_data_lock;
     72     jbyteArray  waveform_data;
     73     jbyteArray  fft_data;
     74 
     75     visualizer_callback_cookie() {
     76         waveform_data = NULL;
     77         fft_data = NULL;
     78     }
     79 
     80     ~visualizer_callback_cookie() {
     81         cleanupBuffers();
     82     }
     83 
     84     void cleanupBuffers() {
     85         AutoMutex lock(&callback_data_lock);
     86         if (waveform_data || fft_data) {
     87             JNIEnv *env = AndroidRuntime::getJNIEnv();
     88 
     89             if (waveform_data) {
     90                 env->DeleteGlobalRef(waveform_data);
     91                 waveform_data = NULL;
     92             }
     93 
     94             if (fft_data) {
     95                 env->DeleteGlobalRef(fft_data);
     96                 fft_data = NULL;
     97             }
     98         }
     99     }
    100  };
    101 
    102 // ----------------------------------------------------------------------------
    103 class visualizerJniStorage {
    104     public:
    105         visualizer_callback_cookie mCallbackData;
    106 
    107     visualizerJniStorage() {
    108     }
    109 
    110     ~visualizerJniStorage() {
    111     }
    112 };
    113 
    114 
    115 static jint translateError(int code) {
    116     switch(code) {
    117     case NO_ERROR:
    118         return VISUALIZER_SUCCESS;
    119     case ALREADY_EXISTS:
    120         return VISUALIZER_ERROR_ALREADY_EXISTS;
    121     case NO_INIT:
    122         return VISUALIZER_ERROR_NO_INIT;
    123     case BAD_VALUE:
    124         return VISUALIZER_ERROR_BAD_VALUE;
    125     case INVALID_OPERATION:
    126         return VISUALIZER_ERROR_INVALID_OPERATION;
    127     case NO_MEMORY:
    128         return VISUALIZER_ERROR_NO_MEMORY;
    129     case DEAD_OBJECT:
    130         return VISUALIZER_ERROR_DEAD_OBJECT;
    131     default:
    132         return VISUALIZER_ERROR;
    133     }
    134 }
    135 
    136 
    137 // ----------------------------------------------------------------------------
    138 static void ensureArraySize(JNIEnv *env, jbyteArray *array, uint32_t size) {
    139     if (NULL != *array) {
    140         uint32_t len = env->GetArrayLength(*array);
    141         if (len == size)
    142             return;
    143 
    144         env->DeleteGlobalRef(*array);
    145         *array = NULL;
    146     }
    147 
    148     jbyteArray localRef = env->NewByteArray(size);
    149     if (NULL != localRef) {
    150         // Promote to global ref.
    151         *array = (jbyteArray)env->NewGlobalRef(localRef);
    152 
    153         // Release our (now pointless) local ref.
    154         env->DeleteLocalRef(localRef);
    155     }
    156 }
    157 
    158 static void captureCallback(void* user,
    159         uint32_t waveformSize,
    160         uint8_t *waveform,
    161         uint32_t fftSize,
    162         uint8_t *fft,
    163         uint32_t samplingrate) {
    164 
    165     int arg1 = 0;
    166     int arg2 = 0;
    167     size_t size;
    168 
    169     visualizer_callback_cookie *callbackInfo = (visualizer_callback_cookie *)user;
    170     JNIEnv *env = AndroidRuntime::getJNIEnv();
    171 
    172     if (!user || !env) {
    173         ALOGW("captureCallback error user %p, env %p", user, env);
    174         return;
    175     }
    176 
    177     ALOGV("captureCallback: callbackInfo %p, visualizer_ref %p visualizer_class %p",
    178             callbackInfo,
    179             callbackInfo->visualizer_ref,
    180             callbackInfo->visualizer_class);
    181 
    182     AutoMutex lock(&callbackInfo->callback_data_lock);
    183 
    184     if (waveformSize != 0 && waveform != NULL) {
    185         jbyteArray jArray;
    186 
    187         ensureArraySize(env, &callbackInfo->waveform_data, waveformSize);
    188         jArray = callbackInfo->waveform_data;
    189 
    190         if (jArray != NULL) {
    191             jbyte *nArray = env->GetByteArrayElements(jArray, NULL);
    192             memcpy(nArray, waveform, waveformSize);
    193             env->ReleaseByteArrayElements(jArray, nArray, 0);
    194             env->CallStaticVoidMethod(
    195                 callbackInfo->visualizer_class,
    196                 fields.midPostNativeEvent,
    197                 callbackInfo->visualizer_ref,
    198                 NATIVE_EVENT_PCM_CAPTURE,
    199                 samplingrate,
    200                 0,
    201                 jArray);
    202         }
    203     }
    204 
    205     if (fftSize != 0 && fft != NULL) {
    206         jbyteArray jArray;
    207 
    208         ensureArraySize(env, &callbackInfo->fft_data, fftSize);
    209         jArray = callbackInfo->fft_data;
    210 
    211         if (jArray != NULL) {
    212             jbyte *nArray = env->GetByteArrayElements(jArray, NULL);
    213             memcpy(nArray, fft, fftSize);
    214             env->ReleaseByteArrayElements(jArray, nArray, 0);
    215             env->CallStaticVoidMethod(
    216                 callbackInfo->visualizer_class,
    217                 fields.midPostNativeEvent,
    218                 callbackInfo->visualizer_ref,
    219                 NATIVE_EVENT_FFT_CAPTURE,
    220                 samplingrate,
    221                 0,
    222                 jArray);
    223         }
    224     }
    225 
    226     if (env->ExceptionCheck()) {
    227         env->ExceptionDescribe();
    228         env->ExceptionClear();
    229     }
    230 }
    231 
    232 static Visualizer *getVisualizer(JNIEnv* env, jobject thiz)
    233 {
    234     Visualizer *v = (Visualizer *)env->GetLongField(
    235         thiz, fields.fidNativeVisualizer);
    236     if (v == NULL) {
    237         jniThrowException(env, "java/lang/IllegalStateException",
    238             "Unable to retrieve Visualizer pointer");
    239     }
    240     return v;
    241 }
    242 
    243 // ----------------------------------------------------------------------------
    244 // This function gets some field IDs, which in turn causes class initialization.
    245 // It is called from a static block in Visualizer, which won't run until the
    246 // first time an instance of this class is used.
    247 static void
    248 android_media_visualizer_native_init(JNIEnv *env)
    249 {
    250 
    251     ALOGV("android_media_visualizer_native_init");
    252 
    253     fields.clazzEffect = NULL;
    254 
    255     // Get the Visualizer class
    256     jclass clazz = env->FindClass(kClassPathName);
    257     if (clazz == NULL) {
    258         ALOGE("Can't find %s", kClassPathName);
    259         return;
    260     }
    261 
    262     fields.clazzEffect = (jclass)env->NewGlobalRef(clazz);
    263 
    264     // Get the Visualizer.MeasurementPeakRms class
    265     clazz = env->FindClass(kClassPeakRmsPathName);
    266     if (clazz == NULL) {
    267         ALOGE("Can't find %s", kClassPeakRmsPathName);
    268         return;
    269     }
    270     jclass clazzMeasurementPeakRms = (jclass)env->NewGlobalRef(clazz);
    271 
    272     // Get the postEvent method
    273     fields.midPostNativeEvent = env->GetStaticMethodID(
    274             fields.clazzEffect,
    275             "postEventFromNative", "(Ljava/lang/Object;IIILjava/lang/Object;)V");
    276     if (fields.midPostNativeEvent == NULL) {
    277         ALOGE("Can't find Visualizer.%s", "postEventFromNative");
    278         return;
    279     }
    280 
    281     // Get the variables fields
    282     //      nativeTrackInJavaObj
    283     fields.fidNativeVisualizer = env->GetFieldID(
    284             fields.clazzEffect,
    285             "mNativeVisualizer", "J");
    286     if (fields.fidNativeVisualizer == NULL) {
    287         ALOGE("Can't find Visualizer.%s", "mNativeVisualizer");
    288         return;
    289     }
    290     //      fidJniData;
    291     fields.fidJniData = env->GetFieldID(
    292             fields.clazzEffect,
    293             "mJniData", "J");
    294     if (fields.fidJniData == NULL) {
    295         ALOGE("Can't find Visualizer.%s", "mJniData");
    296         return;
    297     }
    298     //      fidPeak
    299     fields.fidPeak = env->GetFieldID(
    300             clazzMeasurementPeakRms,
    301             "mPeak", "I");
    302     if (fields.fidPeak == NULL) {
    303         ALOGE("Can't find Visualizer.MeasurementPeakRms.%s", "mPeak");
    304         return;
    305     }
    306     //      fidRms
    307     fields.fidRms = env->GetFieldID(
    308             clazzMeasurementPeakRms,
    309             "mRms", "I");
    310     if (fields.fidRms == NULL) {
    311         ALOGE("Can't find Visualizer.MeasurementPeakRms.%s", "mPeak");
    312         return;
    313     }
    314 
    315     env->DeleteGlobalRef(clazzMeasurementPeakRms);
    316 }
    317 
    318 static void android_media_visualizer_effect_callback(int32_t event,
    319                                                      void *user,
    320                                                      void *info) {
    321     if ((event == AudioEffect::EVENT_ERROR) &&
    322         (*((status_t*)info) == DEAD_OBJECT)) {
    323         visualizerJniStorage* lpJniStorage = (visualizerJniStorage*)user;
    324         visualizer_callback_cookie* callbackInfo = &lpJniStorage->mCallbackData;
    325         JNIEnv *env = AndroidRuntime::getJNIEnv();
    326 
    327         env->CallStaticVoidMethod(
    328             callbackInfo->visualizer_class,
    329             fields.midPostNativeEvent,
    330             callbackInfo->visualizer_ref,
    331             NATIVE_EVENT_SERVER_DIED,
    332             0, 0, NULL);
    333     }
    334 }
    335 
    336 static jint
    337 android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
    338         jint sessionId, jintArray jId)
    339 {
    340     ALOGV("android_media_visualizer_native_setup");
    341     visualizerJniStorage* lpJniStorage = NULL;
    342     int lStatus = VISUALIZER_ERROR_NO_MEMORY;
    343     Visualizer* lpVisualizer = NULL;
    344     jint* nId = NULL;
    345 
    346     lpJniStorage = new visualizerJniStorage();
    347     if (lpJniStorage == NULL) {
    348         ALOGE("setup: Error creating JNI Storage");
    349         goto setup_failure;
    350     }
    351 
    352     lpJniStorage->mCallbackData.visualizer_class = (jclass)env->NewGlobalRef(fields.clazzEffect);
    353     // we use a weak reference so the Visualizer object can be garbage collected.
    354     lpJniStorage->mCallbackData.visualizer_ref = env->NewGlobalRef(weak_this);
    355 
    356     ALOGV("setup: lpJniStorage: %p visualizer_ref %p visualizer_class %p, &mCallbackData %p",
    357             lpJniStorage,
    358             lpJniStorage->mCallbackData.visualizer_ref,
    359             lpJniStorage->mCallbackData.visualizer_class,
    360             &lpJniStorage->mCallbackData);
    361 
    362     if (jId == NULL) {
    363         ALOGE("setup: NULL java array for id pointer");
    364         lStatus = VISUALIZER_ERROR_BAD_VALUE;
    365         goto setup_failure;
    366     }
    367 
    368     // create the native Visualizer object
    369     lpVisualizer = new Visualizer(0,
    370                                   android_media_visualizer_effect_callback,
    371                                   lpJniStorage,
    372                                   sessionId);
    373     if (lpVisualizer == NULL) {
    374         ALOGE("Error creating Visualizer");
    375         goto setup_failure;
    376     }
    377 
    378     lStatus = translateError(lpVisualizer->initCheck());
    379     if (lStatus != VISUALIZER_SUCCESS && lStatus != VISUALIZER_ERROR_ALREADY_EXISTS) {
    380         ALOGE("Visualizer initCheck failed %d", lStatus);
    381         goto setup_failure;
    382     }
    383 
    384     nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL);
    385     if (nId == NULL) {
    386         ALOGE("setup: Error retrieving id pointer");
    387         lStatus = VISUALIZER_ERROR_BAD_VALUE;
    388         goto setup_failure;
    389     }
    390     nId[0] = lpVisualizer->id();
    391     env->ReleasePrimitiveArrayCritical(jId, nId, 0);
    392     nId = NULL;
    393 
    394     env->SetLongField(thiz, fields.fidNativeVisualizer, (jlong)lpVisualizer);
    395 
    396     env->SetLongField(thiz, fields.fidJniData, (jlong)lpJniStorage);
    397 
    398     return VISUALIZER_SUCCESS;
    399 
    400     // failures:
    401 setup_failure:
    402 
    403     if (nId != NULL) {
    404         env->ReleasePrimitiveArrayCritical(jId, nId, 0);
    405     }
    406 
    407     if (lpVisualizer) {
    408         delete lpVisualizer;
    409     }
    410     env->SetLongField(thiz, fields.fidNativeVisualizer, 0);
    411 
    412     if (lpJniStorage) {
    413         delete lpJniStorage;
    414     }
    415     env->SetLongField(thiz, fields.fidJniData, 0);
    416 
    417     return (jint) lStatus;
    418 }
    419 
    420 // ----------------------------------------------------------------------------
    421 static void android_media_visualizer_native_finalize(JNIEnv *env,  jobject thiz) {
    422     ALOGV("android_media_visualizer_native_finalize jobject: %p\n", thiz);
    423 
    424     // delete the Visualizer object
    425     Visualizer* lpVisualizer = (Visualizer *)env->GetLongField(
    426         thiz, fields.fidNativeVisualizer);
    427     if (lpVisualizer) {
    428         ALOGV("deleting Visualizer: %p\n", lpVisualizer);
    429         delete lpVisualizer;
    430     }
    431 
    432     // delete the JNI data
    433     visualizerJniStorage* lpJniStorage = (visualizerJniStorage *)env->GetLongField(
    434         thiz, fields.fidJniData);
    435     if (lpJniStorage) {
    436         ALOGV("deleting pJniStorage: %p\n", lpJniStorage);
    437         delete lpJniStorage;
    438     }
    439 }
    440 
    441 // ----------------------------------------------------------------------------
    442 static void android_media_visualizer_native_release(JNIEnv *env,  jobject thiz) {
    443 
    444     // do everything a call to finalize would
    445     android_media_visualizer_native_finalize(env, thiz);
    446     // + reset the native resources in the Java object so any attempt to access
    447     // them after a call to release fails.
    448     env->SetLongField(thiz, fields.fidNativeVisualizer, 0);
    449     env->SetLongField(thiz, fields.fidJniData, 0);
    450 }
    451 
    452 static jint
    453 android_media_visualizer_native_setEnabled(JNIEnv *env, jobject thiz, jboolean enabled)
    454 {
    455     Visualizer* lpVisualizer = getVisualizer(env, thiz);
    456     if (lpVisualizer == NULL) {
    457         return VISUALIZER_ERROR_NO_INIT;
    458     }
    459 
    460     jint retVal = translateError(lpVisualizer->setEnabled(enabled));
    461 
    462     if (!enabled) {
    463         visualizerJniStorage* lpJniStorage = (visualizerJniStorage *)env->GetLongField(
    464             thiz, fields.fidJniData);
    465 
    466         if (NULL != lpJniStorage)
    467             lpJniStorage->mCallbackData.cleanupBuffers();
    468     }
    469 
    470     return retVal;
    471 }
    472 
    473 static jboolean
    474 android_media_visualizer_native_getEnabled(JNIEnv *env, jobject thiz)
    475 {
    476     Visualizer* lpVisualizer = getVisualizer(env, thiz);
    477     if (lpVisualizer == NULL) {
    478         return JNI_FALSE;
    479     }
    480 
    481     if (lpVisualizer->getEnabled()) {
    482         return JNI_TRUE;
    483     } else {
    484         return JNI_FALSE;
    485     }
    486 }
    487 
    488 static jintArray
    489 android_media_visualizer_native_getCaptureSizeRange(JNIEnv *env, jobject thiz)
    490 {
    491     jintArray jRange = env->NewIntArray(2);
    492     jint *nRange = env->GetIntArrayElements(jRange, NULL);
    493     nRange[0] = Visualizer::getMinCaptureSize();
    494     nRange[1] = Visualizer::getMaxCaptureSize();
    495     ALOGV("getCaptureSizeRange() min %d max %d", nRange[0], nRange[1]);
    496     env->ReleaseIntArrayElements(jRange, nRange, 0);
    497     return jRange;
    498 }
    499 
    500 static jint
    501 android_media_visualizer_native_getMaxCaptureRate(JNIEnv *env, jobject thiz)
    502 {
    503     return (jint) Visualizer::getMaxCaptureRate();
    504 }
    505 
    506 static jint
    507 android_media_visualizer_native_setCaptureSize(JNIEnv *env, jobject thiz, jint size)
    508 {
    509     Visualizer* lpVisualizer = getVisualizer(env, thiz);
    510     if (lpVisualizer == NULL) {
    511         return VISUALIZER_ERROR_NO_INIT;
    512     }
    513 
    514     return translateError(lpVisualizer->setCaptureSize(size));
    515 }
    516 
    517 static jint
    518 android_media_visualizer_native_getCaptureSize(JNIEnv *env, jobject thiz)
    519 {
    520     Visualizer* lpVisualizer = getVisualizer(env, thiz);
    521     if (lpVisualizer == NULL) {
    522         return -1;
    523     }
    524     return (jint) lpVisualizer->getCaptureSize();
    525 }
    526 
    527 static jint
    528 android_media_visualizer_native_setScalingMode(JNIEnv *env, jobject thiz, jint mode)
    529 {
    530     Visualizer* lpVisualizer = getVisualizer(env, thiz);
    531     if (lpVisualizer == NULL) {
    532         return VISUALIZER_ERROR_NO_INIT;
    533     }
    534 
    535     return translateError(lpVisualizer->setScalingMode(mode));
    536 }
    537 
    538 static jint
    539 android_media_visualizer_native_getScalingMode(JNIEnv *env, jobject thiz)
    540 {
    541     Visualizer* lpVisualizer = getVisualizer(env, thiz);
    542     if (lpVisualizer == NULL) {
    543         return -1;
    544     }
    545     return (jint)lpVisualizer->getScalingMode();
    546 }
    547 
    548 static jint
    549 android_media_visualizer_native_setMeasurementMode(JNIEnv *env, jobject thiz, jint mode)
    550 {
    551     Visualizer* lpVisualizer = getVisualizer(env, thiz);
    552     if (lpVisualizer == NULL) {
    553         return VISUALIZER_ERROR_NO_INIT;
    554     }
    555     return translateError(lpVisualizer->setMeasurementMode(mode));
    556 }
    557 
    558 static jint
    559 android_media_visualizer_native_getMeasurementMode(JNIEnv *env, jobject thiz)
    560 {
    561     Visualizer* lpVisualizer = getVisualizer(env, thiz);
    562     if (lpVisualizer == NULL) {
    563         return MEASUREMENT_MODE_NONE;
    564     }
    565     return lpVisualizer->getMeasurementMode();
    566 }
    567 
    568 static jint
    569 android_media_visualizer_native_getSamplingRate(JNIEnv *env, jobject thiz)
    570 {
    571     Visualizer* lpVisualizer = getVisualizer(env, thiz);
    572     if (lpVisualizer == NULL) {
    573         return -1;
    574     }
    575     return (jint) lpVisualizer->getSamplingRate();
    576 }
    577 
    578 static jint
    579 android_media_visualizer_native_getWaveForm(JNIEnv *env, jobject thiz, jbyteArray jWaveform)
    580 {
    581     Visualizer* lpVisualizer = getVisualizer(env, thiz);
    582     if (lpVisualizer == NULL) {
    583         return VISUALIZER_ERROR_NO_INIT;
    584     }
    585 
    586     jbyte* nWaveform = (jbyte *) env->GetPrimitiveArrayCritical(jWaveform, NULL);
    587     if (nWaveform == NULL) {
    588         return VISUALIZER_ERROR_NO_MEMORY;
    589     }
    590     jint status = translateError(lpVisualizer->getWaveForm((uint8_t *)nWaveform));
    591 
    592     env->ReleasePrimitiveArrayCritical(jWaveform, nWaveform, 0);
    593     return status;
    594 }
    595 
    596 static jint
    597 android_media_visualizer_native_getFft(JNIEnv *env, jobject thiz, jbyteArray jFft)
    598 {
    599     Visualizer* lpVisualizer = getVisualizer(env, thiz);
    600     if (lpVisualizer == NULL) {
    601         return VISUALIZER_ERROR_NO_INIT;
    602     }
    603 
    604     jbyte* nFft = (jbyte *) env->GetPrimitiveArrayCritical(jFft, NULL);
    605     if (nFft == NULL) {
    606         return VISUALIZER_ERROR_NO_MEMORY;
    607     }
    608     jint status = translateError(lpVisualizer->getFft((uint8_t *)nFft));
    609 
    610     env->ReleasePrimitiveArrayCritical(jFft, nFft, 0);
    611 
    612     return status;
    613 }
    614 
    615 static jint
    616 android_media_visualizer_native_getPeakRms(JNIEnv *env, jobject thiz, jobject jPeakRmsObj)
    617 {
    618     Visualizer* lpVisualizer = getVisualizer(env, thiz);
    619     if (lpVisualizer == NULL) {
    620         return VISUALIZER_ERROR_NO_INIT;
    621     }
    622     int32_t measurements[2];
    623     jint status = translateError(
    624                 lpVisualizer->getIntMeasurements(MEASUREMENT_MODE_PEAK_RMS,
    625                         2, measurements));
    626     if (status == VISUALIZER_SUCCESS) {
    627         // measurement worked, write the values to the java object
    628         env->SetIntField(jPeakRmsObj, fields.fidPeak, measurements[MEASUREMENT_IDX_PEAK]);
    629         env->SetIntField(jPeakRmsObj, fields.fidRms, measurements[MEASUREMENT_IDX_RMS]);
    630     }
    631     return status;
    632 }
    633 
    634 static jint
    635 android_media_setPeriodicCapture(JNIEnv *env, jobject thiz, jint rate, jboolean jWaveform, jboolean jFft)
    636 {
    637     Visualizer* lpVisualizer = getVisualizer(env, thiz);
    638     if (lpVisualizer == NULL) {
    639         return VISUALIZER_ERROR_NO_INIT;
    640     }
    641     visualizerJniStorage* lpJniStorage = (visualizerJniStorage *)env->GetLongField(thiz,
    642             fields.fidJniData);
    643     if (lpJniStorage == NULL) {
    644         return VISUALIZER_ERROR_NO_INIT;
    645     }
    646 
    647     ALOGV("setPeriodicCapture: rate %d, jWaveform %d jFft %d",
    648             rate,
    649             jWaveform,
    650             jFft);
    651 
    652     uint32_t flags = Visualizer::CAPTURE_CALL_JAVA;
    653     if (jWaveform) flags |= Visualizer::CAPTURE_WAVEFORM;
    654     if (jFft) flags |= Visualizer::CAPTURE_FFT;
    655     Visualizer::capture_cbk_t cbk = captureCallback;
    656     if (!jWaveform && !jFft) cbk = NULL;
    657 
    658     return translateError(lpVisualizer->setCaptureCallBack(cbk,
    659                                                 &lpJniStorage->mCallbackData,
    660                                                 flags,
    661                                                 rate));
    662 }
    663 
    664 // ----------------------------------------------------------------------------
    665 
    666 // Dalvik VM type signatures
    667 static JNINativeMethod gMethods[] = {
    668     {"native_init",            "()V",     (void *)android_media_visualizer_native_init},
    669     {"native_setup",           "(Ljava/lang/Object;I[I)I",
    670                                           (void *)android_media_visualizer_native_setup},
    671     {"native_finalize",          "()V",   (void *)android_media_visualizer_native_finalize},
    672     {"native_release",           "()V",   (void *)android_media_visualizer_native_release},
    673     {"native_setEnabled",        "(Z)I",  (void *)android_media_visualizer_native_setEnabled},
    674     {"native_getEnabled",        "()Z",   (void *)android_media_visualizer_native_getEnabled},
    675     {"getCaptureSizeRange",      "()[I",  (void *)android_media_visualizer_native_getCaptureSizeRange},
    676     {"getMaxCaptureRate",        "()I",   (void *)android_media_visualizer_native_getMaxCaptureRate},
    677     {"native_setCaptureSize",    "(I)I",  (void *)android_media_visualizer_native_setCaptureSize},
    678     {"native_getCaptureSize",    "()I",   (void *)android_media_visualizer_native_getCaptureSize},
    679     {"native_setScalingMode",    "(I)I",  (void *)android_media_visualizer_native_setScalingMode},
    680     {"native_getScalingMode",    "()I",   (void *)android_media_visualizer_native_getScalingMode},
    681     {"native_setMeasurementMode","(I)I",  (void *)android_media_visualizer_native_setMeasurementMode},
    682     {"native_getMeasurementMode","()I",   (void *)android_media_visualizer_native_getMeasurementMode},
    683     {"native_getSamplingRate",   "()I",   (void *)android_media_visualizer_native_getSamplingRate},
    684     {"native_getWaveForm",       "([B)I", (void *)android_media_visualizer_native_getWaveForm},
    685     {"native_getFft",            "([B)I", (void *)android_media_visualizer_native_getFft},
    686     {"native_getPeakRms",      "(Landroid/media/audiofx/Visualizer$MeasurementPeakRms;)I",
    687                                           (void *)android_media_visualizer_native_getPeakRms},
    688     {"native_setPeriodicCapture","(IZZ)I",(void *)android_media_setPeriodicCapture},
    689 };
    690 
    691 // ----------------------------------------------------------------------------
    692 
    693 int register_android_media_visualizer(JNIEnv *env)
    694 {
    695     return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
    696 }
    697 
    698