android_media_Visualizer.cpp revision 76f6a86de25e1bf74717e047e55fd44b089673f3
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    visualizer_callback_cookie *callbackInfo = (visualizer_callback_cookie *)user;
166    JNIEnv *env = AndroidRuntime::getJNIEnv();
167
168    if (!user || !env) {
169        ALOGW("captureCallback error user %p, env %p", user, env);
170        return;
171    }
172
173    ALOGV("captureCallback: callbackInfo %p, visualizer_ref %p visualizer_class %p",
174            callbackInfo,
175            callbackInfo->visualizer_ref,
176            callbackInfo->visualizer_class);
177
178    AutoMutex lock(&callbackInfo->callback_data_lock);
179
180    if (waveformSize != 0 && waveform != NULL) {
181        jbyteArray jArray;
182
183        ensureArraySize(env, &callbackInfo->waveform_data, waveformSize);
184        jArray = callbackInfo->waveform_data;
185
186        if (jArray != NULL) {
187            jbyte *nArray = env->GetByteArrayElements(jArray, NULL);
188            memcpy(nArray, waveform, waveformSize);
189            env->ReleaseByteArrayElements(jArray, nArray, 0);
190            env->CallStaticVoidMethod(
191                callbackInfo->visualizer_class,
192                fields.midPostNativeEvent,
193                callbackInfo->visualizer_ref,
194                NATIVE_EVENT_PCM_CAPTURE,
195                samplingrate,
196                0,
197                jArray);
198        }
199    }
200
201    if (fftSize != 0 && fft != NULL) {
202        jbyteArray jArray;
203
204        ensureArraySize(env, &callbackInfo->fft_data, fftSize);
205        jArray = callbackInfo->fft_data;
206
207        if (jArray != NULL) {
208            jbyte *nArray = env->GetByteArrayElements(jArray, NULL);
209            memcpy(nArray, fft, fftSize);
210            env->ReleaseByteArrayElements(jArray, nArray, 0);
211            env->CallStaticVoidMethod(
212                callbackInfo->visualizer_class,
213                fields.midPostNativeEvent,
214                callbackInfo->visualizer_ref,
215                NATIVE_EVENT_FFT_CAPTURE,
216                samplingrate,
217                0,
218                jArray);
219        }
220    }
221
222    if (env->ExceptionCheck()) {
223        env->ExceptionDescribe();
224        env->ExceptionClear();
225    }
226}
227
228static Visualizer *getVisualizer(JNIEnv* env, jobject thiz)
229{
230    Visualizer *v = (Visualizer *)env->GetLongField(
231        thiz, fields.fidNativeVisualizer);
232    if (v == NULL) {
233        jniThrowException(env, "java/lang/IllegalStateException",
234            "Unable to retrieve Visualizer pointer");
235    }
236    return v;
237}
238
239// ----------------------------------------------------------------------------
240// This function gets some field IDs, which in turn causes class initialization.
241// It is called from a static block in Visualizer, which won't run until the
242// first time an instance of this class is used.
243static void
244android_media_visualizer_native_init(JNIEnv *env)
245{
246
247    ALOGV("android_media_visualizer_native_init");
248
249    fields.clazzEffect = NULL;
250
251    // Get the Visualizer class
252    jclass clazz = env->FindClass(kClassPathName);
253    if (clazz == NULL) {
254        ALOGE("Can't find %s", kClassPathName);
255        return;
256    }
257
258    fields.clazzEffect = (jclass)env->NewGlobalRef(clazz);
259
260    // Get the Visualizer.MeasurementPeakRms class
261    clazz = env->FindClass(kClassPeakRmsPathName);
262    if (clazz == NULL) {
263        ALOGE("Can't find %s", kClassPeakRmsPathName);
264        return;
265    }
266    jclass clazzMeasurementPeakRms = (jclass)env->NewGlobalRef(clazz);
267
268    // Get the postEvent method
269    fields.midPostNativeEvent = env->GetStaticMethodID(
270            fields.clazzEffect,
271            "postEventFromNative", "(Ljava/lang/Object;IIILjava/lang/Object;)V");
272    if (fields.midPostNativeEvent == NULL) {
273        ALOGE("Can't find Visualizer.%s", "postEventFromNative");
274        return;
275    }
276
277    // Get the variables fields
278    //      nativeTrackInJavaObj
279    fields.fidNativeVisualizer = env->GetFieldID(
280            fields.clazzEffect,
281            "mNativeVisualizer", "J");
282    if (fields.fidNativeVisualizer == NULL) {
283        ALOGE("Can't find Visualizer.%s", "mNativeVisualizer");
284        return;
285    }
286    //      fidJniData;
287    fields.fidJniData = env->GetFieldID(
288            fields.clazzEffect,
289            "mJniData", "J");
290    if (fields.fidJniData == NULL) {
291        ALOGE("Can't find Visualizer.%s", "mJniData");
292        return;
293    }
294    //      fidPeak
295    fields.fidPeak = env->GetFieldID(
296            clazzMeasurementPeakRms,
297            "mPeak", "I");
298    if (fields.fidPeak == NULL) {
299        ALOGE("Can't find Visualizer.MeasurementPeakRms.%s", "mPeak");
300        return;
301    }
302    //      fidRms
303    fields.fidRms = env->GetFieldID(
304            clazzMeasurementPeakRms,
305            "mRms", "I");
306    if (fields.fidRms == NULL) {
307        ALOGE("Can't find Visualizer.MeasurementPeakRms.%s", "mPeak");
308        return;
309    }
310
311    env->DeleteGlobalRef(clazzMeasurementPeakRms);
312}
313
314static void android_media_visualizer_effect_callback(int32_t event,
315                                                     void *user,
316                                                     void *info) {
317    if ((event == AudioEffect::EVENT_ERROR) &&
318        (*((status_t*)info) == DEAD_OBJECT)) {
319        visualizerJniStorage* lpJniStorage = (visualizerJniStorage*)user;
320        visualizer_callback_cookie* callbackInfo = &lpJniStorage->mCallbackData;
321        JNIEnv *env = AndroidRuntime::getJNIEnv();
322
323        env->CallStaticVoidMethod(
324            callbackInfo->visualizer_class,
325            fields.midPostNativeEvent,
326            callbackInfo->visualizer_ref,
327            NATIVE_EVENT_SERVER_DIED,
328            0, 0, NULL);
329    }
330}
331
332static jint
333android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
334        jint sessionId, jintArray jId)
335{
336    ALOGV("android_media_visualizer_native_setup");
337    visualizerJniStorage* lpJniStorage = NULL;
338    int lStatus = VISUALIZER_ERROR_NO_MEMORY;
339    Visualizer* lpVisualizer = NULL;
340    jint* nId = NULL;
341
342    lpJniStorage = new visualizerJniStorage();
343    if (lpJniStorage == NULL) {
344        ALOGE("setup: Error creating JNI Storage");
345        goto setup_failure;
346    }
347
348    lpJniStorage->mCallbackData.visualizer_class = (jclass)env->NewGlobalRef(fields.clazzEffect);
349    // we use a weak reference so the Visualizer object can be garbage collected.
350    lpJniStorage->mCallbackData.visualizer_ref = env->NewGlobalRef(weak_this);
351
352    ALOGV("setup: lpJniStorage: %p visualizer_ref %p visualizer_class %p, &mCallbackData %p",
353            lpJniStorage,
354            lpJniStorage->mCallbackData.visualizer_ref,
355            lpJniStorage->mCallbackData.visualizer_class,
356            &lpJniStorage->mCallbackData);
357
358    if (jId == NULL) {
359        ALOGE("setup: NULL java array for id pointer");
360        lStatus = VISUALIZER_ERROR_BAD_VALUE;
361        goto setup_failure;
362    }
363
364    // create the native Visualizer object
365    lpVisualizer = new Visualizer(0,
366                                  android_media_visualizer_effect_callback,
367                                  lpJniStorage,
368                                  sessionId);
369    if (lpVisualizer == NULL) {
370        ALOGE("Error creating Visualizer");
371        goto setup_failure;
372    }
373
374    lStatus = translateError(lpVisualizer->initCheck());
375    if (lStatus != VISUALIZER_SUCCESS && lStatus != VISUALIZER_ERROR_ALREADY_EXISTS) {
376        ALOGE("Visualizer initCheck failed %d", lStatus);
377        goto setup_failure;
378    }
379
380    nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL);
381    if (nId == NULL) {
382        ALOGE("setup: Error retrieving id pointer");
383        lStatus = VISUALIZER_ERROR_BAD_VALUE;
384        goto setup_failure;
385    }
386    nId[0] = lpVisualizer->id();
387    env->ReleasePrimitiveArrayCritical(jId, nId, 0);
388    nId = NULL;
389
390    env->SetLongField(thiz, fields.fidNativeVisualizer, (jlong)lpVisualizer);
391
392    env->SetLongField(thiz, fields.fidJniData, (jlong)lpJniStorage);
393
394    return VISUALIZER_SUCCESS;
395
396    // failures:
397setup_failure:
398
399    if (nId != NULL) {
400        env->ReleasePrimitiveArrayCritical(jId, nId, 0);
401    }
402
403    if (lpVisualizer) {
404        delete lpVisualizer;
405    }
406    env->SetLongField(thiz, fields.fidNativeVisualizer, 0);
407
408    if (lpJniStorage) {
409        delete lpJniStorage;
410    }
411    env->SetLongField(thiz, fields.fidJniData, 0);
412
413    return (jint) lStatus;
414}
415
416// ----------------------------------------------------------------------------
417static void android_media_visualizer_native_finalize(JNIEnv *env,  jobject thiz) {
418    ALOGV("android_media_visualizer_native_finalize jobject: %p\n", thiz);
419
420    // delete the Visualizer object
421    Visualizer* lpVisualizer = (Visualizer *)env->GetLongField(
422        thiz, fields.fidNativeVisualizer);
423    if (lpVisualizer) {
424        ALOGV("deleting Visualizer: %p\n", lpVisualizer);
425        delete lpVisualizer;
426    }
427
428    // delete the JNI data
429    visualizerJniStorage* lpJniStorage = (visualizerJniStorage *)env->GetLongField(
430        thiz, fields.fidJniData);
431    if (lpJniStorage) {
432        ALOGV("deleting pJniStorage: %p\n", lpJniStorage);
433        delete lpJniStorage;
434    }
435}
436
437// ----------------------------------------------------------------------------
438static void android_media_visualizer_native_release(JNIEnv *env,  jobject thiz) {
439
440    // do everything a call to finalize would
441    android_media_visualizer_native_finalize(env, thiz);
442    // + reset the native resources in the Java object so any attempt to access
443    // them after a call to release fails.
444    env->SetLongField(thiz, fields.fidNativeVisualizer, 0);
445    env->SetLongField(thiz, fields.fidJniData, 0);
446}
447
448static jint
449android_media_visualizer_native_setEnabled(JNIEnv *env, jobject thiz, jboolean enabled)
450{
451    Visualizer* lpVisualizer = getVisualizer(env, thiz);
452    if (lpVisualizer == NULL) {
453        return VISUALIZER_ERROR_NO_INIT;
454    }
455
456    jint retVal = translateError(lpVisualizer->setEnabled(enabled));
457
458    if (!enabled) {
459        visualizerJniStorage* lpJniStorage = (visualizerJniStorage *)env->GetLongField(
460            thiz, fields.fidJniData);
461
462        if (NULL != lpJniStorage)
463            lpJniStorage->mCallbackData.cleanupBuffers();
464    }
465
466    return retVal;
467}
468
469static jboolean
470android_media_visualizer_native_getEnabled(JNIEnv *env, jobject thiz)
471{
472    Visualizer* lpVisualizer = getVisualizer(env, thiz);
473    if (lpVisualizer == NULL) {
474        return JNI_FALSE;
475    }
476
477    if (lpVisualizer->getEnabled()) {
478        return JNI_TRUE;
479    } else {
480        return JNI_FALSE;
481    }
482}
483
484static jintArray
485android_media_visualizer_native_getCaptureSizeRange(JNIEnv *env, jobject /* thiz */)
486{
487    jintArray jRange = env->NewIntArray(2);
488    jint *nRange = env->GetIntArrayElements(jRange, NULL);
489    nRange[0] = Visualizer::getMinCaptureSize();
490    nRange[1] = Visualizer::getMaxCaptureSize();
491    ALOGV("getCaptureSizeRange() min %d max %d", nRange[0], nRange[1]);
492    env->ReleaseIntArrayElements(jRange, nRange, 0);
493    return jRange;
494}
495
496static jint
497android_media_visualizer_native_getMaxCaptureRate(JNIEnv* /* env */, jobject /* thiz */)
498{
499    return (jint) Visualizer::getMaxCaptureRate();
500}
501
502static jint
503android_media_visualizer_native_setCaptureSize(JNIEnv *env, jobject thiz, jint size)
504{
505    Visualizer* lpVisualizer = getVisualizer(env, thiz);
506    if (lpVisualizer == NULL) {
507        return VISUALIZER_ERROR_NO_INIT;
508    }
509
510    return translateError(lpVisualizer->setCaptureSize(size));
511}
512
513static jint
514android_media_visualizer_native_getCaptureSize(JNIEnv *env, jobject thiz)
515{
516    Visualizer* lpVisualizer = getVisualizer(env, thiz);
517    if (lpVisualizer == NULL) {
518        return -1;
519    }
520    return (jint) lpVisualizer->getCaptureSize();
521}
522
523static jint
524android_media_visualizer_native_setScalingMode(JNIEnv *env, jobject thiz, jint mode)
525{
526    Visualizer* lpVisualizer = getVisualizer(env, thiz);
527    if (lpVisualizer == NULL) {
528        return VISUALIZER_ERROR_NO_INIT;
529    }
530
531    return translateError(lpVisualizer->setScalingMode(mode));
532}
533
534static jint
535android_media_visualizer_native_getScalingMode(JNIEnv *env, jobject thiz)
536{
537    Visualizer* lpVisualizer = getVisualizer(env, thiz);
538    if (lpVisualizer == NULL) {
539        return -1;
540    }
541    return (jint)lpVisualizer->getScalingMode();
542}
543
544static jint
545android_media_visualizer_native_setMeasurementMode(JNIEnv *env, jobject thiz, jint mode)
546{
547    Visualizer* lpVisualizer = getVisualizer(env, thiz);
548    if (lpVisualizer == NULL) {
549        return VISUALIZER_ERROR_NO_INIT;
550    }
551    return translateError(lpVisualizer->setMeasurementMode(mode));
552}
553
554static jint
555android_media_visualizer_native_getMeasurementMode(JNIEnv *env, jobject thiz)
556{
557    Visualizer* lpVisualizer = getVisualizer(env, thiz);
558    if (lpVisualizer == NULL) {
559        return MEASUREMENT_MODE_NONE;
560    }
561    return lpVisualizer->getMeasurementMode();
562}
563
564static jint
565android_media_visualizer_native_getSamplingRate(JNIEnv *env, jobject thiz)
566{
567    Visualizer* lpVisualizer = getVisualizer(env, thiz);
568    if (lpVisualizer == NULL) {
569        return -1;
570    }
571    return (jint) lpVisualizer->getSamplingRate();
572}
573
574static jint
575android_media_visualizer_native_getWaveForm(JNIEnv *env, jobject thiz, jbyteArray jWaveform)
576{
577    Visualizer* lpVisualizer = getVisualizer(env, thiz);
578    if (lpVisualizer == NULL) {
579        return VISUALIZER_ERROR_NO_INIT;
580    }
581
582    jbyte* nWaveform = (jbyte *) env->GetPrimitiveArrayCritical(jWaveform, NULL);
583    if (nWaveform == NULL) {
584        return VISUALIZER_ERROR_NO_MEMORY;
585    }
586    jint status = translateError(lpVisualizer->getWaveForm((uint8_t *)nWaveform));
587
588    env->ReleasePrimitiveArrayCritical(jWaveform, nWaveform, 0);
589    return status;
590}
591
592static jint
593android_media_visualizer_native_getFft(JNIEnv *env, jobject thiz, jbyteArray jFft)
594{
595    Visualizer* lpVisualizer = getVisualizer(env, thiz);
596    if (lpVisualizer == NULL) {
597        return VISUALIZER_ERROR_NO_INIT;
598    }
599
600    jbyte* nFft = (jbyte *) env->GetPrimitiveArrayCritical(jFft, NULL);
601    if (nFft == NULL) {
602        return VISUALIZER_ERROR_NO_MEMORY;
603    }
604    jint status = translateError(lpVisualizer->getFft((uint8_t *)nFft));
605
606    env->ReleasePrimitiveArrayCritical(jFft, nFft, 0);
607
608    return status;
609}
610
611static jint
612android_media_visualizer_native_getPeakRms(JNIEnv *env, jobject thiz, jobject jPeakRmsObj)
613{
614    Visualizer* lpVisualizer = getVisualizer(env, thiz);
615    if (lpVisualizer == NULL) {
616        return VISUALIZER_ERROR_NO_INIT;
617    }
618    int32_t measurements[2];
619    jint status = translateError(
620                lpVisualizer->getIntMeasurements(MEASUREMENT_MODE_PEAK_RMS,
621                        2, measurements));
622    if (status == VISUALIZER_SUCCESS) {
623        // measurement worked, write the values to the java object
624        env->SetIntField(jPeakRmsObj, fields.fidPeak, measurements[MEASUREMENT_IDX_PEAK]);
625        env->SetIntField(jPeakRmsObj, fields.fidRms, measurements[MEASUREMENT_IDX_RMS]);
626    }
627    return status;
628}
629
630static jint
631android_media_setPeriodicCapture(JNIEnv *env, jobject thiz, jint rate, jboolean jWaveform, jboolean jFft)
632{
633    Visualizer* lpVisualizer = getVisualizer(env, thiz);
634    if (lpVisualizer == NULL) {
635        return VISUALIZER_ERROR_NO_INIT;
636    }
637    visualizerJniStorage* lpJniStorage = (visualizerJniStorage *)env->GetLongField(thiz,
638            fields.fidJniData);
639    if (lpJniStorage == NULL) {
640        return VISUALIZER_ERROR_NO_INIT;
641    }
642
643    ALOGV("setPeriodicCapture: rate %d, jWaveform %d jFft %d",
644            rate,
645            jWaveform,
646            jFft);
647
648    uint32_t flags = Visualizer::CAPTURE_CALL_JAVA;
649    if (jWaveform) flags |= Visualizer::CAPTURE_WAVEFORM;
650    if (jFft) flags |= Visualizer::CAPTURE_FFT;
651    Visualizer::capture_cbk_t cbk = captureCallback;
652    if (!jWaveform && !jFft) cbk = NULL;
653
654    return translateError(lpVisualizer->setCaptureCallBack(cbk,
655                                                &lpJniStorage->mCallbackData,
656                                                flags,
657                                                rate));
658}
659
660// ----------------------------------------------------------------------------
661
662// Dalvik VM type signatures
663static const JNINativeMethod gMethods[] = {
664    {"native_init",            "()V",     (void *)android_media_visualizer_native_init},
665    {"native_setup",           "(Ljava/lang/Object;I[I)I",
666                                          (void *)android_media_visualizer_native_setup},
667    {"native_finalize",          "()V",   (void *)android_media_visualizer_native_finalize},
668    {"native_release",           "()V",   (void *)android_media_visualizer_native_release},
669    {"native_setEnabled",        "(Z)I",  (void *)android_media_visualizer_native_setEnabled},
670    {"native_getEnabled",        "()Z",   (void *)android_media_visualizer_native_getEnabled},
671    {"getCaptureSizeRange",      "()[I",  (void *)android_media_visualizer_native_getCaptureSizeRange},
672    {"getMaxCaptureRate",        "()I",   (void *)android_media_visualizer_native_getMaxCaptureRate},
673    {"native_setCaptureSize",    "(I)I",  (void *)android_media_visualizer_native_setCaptureSize},
674    {"native_getCaptureSize",    "()I",   (void *)android_media_visualizer_native_getCaptureSize},
675    {"native_setScalingMode",    "(I)I",  (void *)android_media_visualizer_native_setScalingMode},
676    {"native_getScalingMode",    "()I",   (void *)android_media_visualizer_native_getScalingMode},
677    {"native_setMeasurementMode","(I)I",  (void *)android_media_visualizer_native_setMeasurementMode},
678    {"native_getMeasurementMode","()I",   (void *)android_media_visualizer_native_getMeasurementMode},
679    {"native_getSamplingRate",   "()I",   (void *)android_media_visualizer_native_getSamplingRate},
680    {"native_getWaveForm",       "([B)I", (void *)android_media_visualizer_native_getWaveForm},
681    {"native_getFft",            "([B)I", (void *)android_media_visualizer_native_getFft},
682    {"native_getPeakRms",      "(Landroid/media/audiofx/Visualizer$MeasurementPeakRms;)I",
683                                          (void *)android_media_visualizer_native_getPeakRms},
684    {"native_setPeriodicCapture","(IZZ)I",(void *)android_media_setPeriodicCapture},
685};
686
687// ----------------------------------------------------------------------------
688
689int register_android_media_visualizer(JNIEnv *env)
690{
691    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
692}
693
694