android_media_Visualizer.cpp revision 67f304e2ca0d7a93730669b143bb30ef6a3f7199
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
29using 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// ----------------------------------------------------------------------------
45static const char* const kClassPathName = "android/media/audiofx/Visualizer";
46static const char* const kClassPeakRmsPathName =
47        "android/media/audiofx/Visualizer$MeasurementPeakRms";
48
49struct 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};
58static fields_t fields;
59
60struct 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// ----------------------------------------------------------------------------
103class visualizerJniStorage {
104    public:
105        visualizer_callback_cookie mCallbackData;
106
107    visualizerJniStorage() {
108    }
109
110    ~visualizerJniStorage() {
111    }
112};
113
114
115static 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// ----------------------------------------------------------------------------
138static 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
158static 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
232static 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.
247static void
248android_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
318static 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
336static jint
337android_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:
401setup_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// ----------------------------------------------------------------------------
421static 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// ----------------------------------------------------------------------------
442static 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
452static jint
453android_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
473static jboolean
474android_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
488static jintArray
489android_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
500static jint
501android_media_visualizer_native_getMaxCaptureRate(JNIEnv *env, jobject thiz)
502{
503    return (jint) Visualizer::getMaxCaptureRate();
504}
505
506static jint
507android_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
517static jint
518android_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
527static jint
528android_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
538static jint
539android_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
548static jint
549android_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
558static jint
559android_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
568static jint
569android_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
578static jint
579android_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
596static jint
597android_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
615static jint
616android_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
634static jint
635android_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
667static 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
693int register_android_media_visualizer(JNIEnv *env)
694{
695    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
696}
697
698