android_media_Visualizer.cpp revision badca26cb218852d32862dada36ee52fce865ad2
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->GetIntField(
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", "I");
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", "I");
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, 0);
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->SetIntField(thiz, fields.fidNativeVisualizer, (int)lpVisualizer);
395
396    env->SetIntField(thiz, fields.fidJniData, (int)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->SetIntField(thiz, fields.fidNativeVisualizer, 0);
411
412    if (lpJniStorage) {
413        delete lpJniStorage;
414    }
415    env->SetIntField(thiz, fields.fidJniData, 0);
416
417    return lStatus;
418}
419
420// ----------------------------------------------------------------------------
421static void android_media_visualizer_native_finalize(JNIEnv *env,  jobject thiz) {
422    ALOGV("android_media_visualizer_native_finalize jobject: %x\n", (int)thiz);
423
424    // delete the Visualizer object
425    Visualizer* lpVisualizer = (Visualizer *)env->GetIntField(
426        thiz, fields.fidNativeVisualizer);
427    if (lpVisualizer) {
428        ALOGV("deleting Visualizer: %x\n", (int)lpVisualizer);
429        delete lpVisualizer;
430    }
431
432    // delete the JNI data
433    visualizerJniStorage* lpJniStorage = (visualizerJniStorage *)env->GetIntField(
434        thiz, fields.fidJniData);
435    if (lpJniStorage) {
436        ALOGV("deleting pJniStorage: %x\n", (int)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->SetIntField(thiz, fields.fidNativeVisualizer, 0);
449    env->SetIntField(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->GetIntField(
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 false;
479    }
480
481    return (jboolean)lpVisualizer->getEnabled();
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 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 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 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 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->GetIntField(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 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