• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
47 struct fields_t {
48     // these fields provide access from C++ to the...
49     jclass    clazzEffect;          // Visualizer class
50     jmethodID midPostNativeEvent;   // event post callback method
51     jfieldID  fidNativeVisualizer; // stores in Java the native Visualizer object
52     jfieldID  fidJniData;           // stores in Java additional resources used by the native Visualizer
53 };
54 static fields_t fields;
55 
56 struct visualizer_callback_cookie {
57     jclass      visualizer_class;  // Visualizer class
58     jobject     visualizer_ref;    // Visualizer object instance
59 
60     // Lazily allocated arrays used to hold callback data provided to java
61     // applications.  These arrays are allocated during the first callback and
62     // reallocated when the size of the callback data changes.  Allocating on
63     // demand and saving the arrays means that applications cannot safely hold a
64     // reference to the provided data (they need to make a copy if they want to
65     // hold onto outside of the callback scope), but it avoids GC thrash caused
66     // by constantly allocating and releasing arrays to hold callback data.
67     Mutex       callback_data_lock;
68     jbyteArray  waveform_data;
69     jbyteArray  fft_data;
70 
visualizer_callback_cookievisualizer_callback_cookie71     visualizer_callback_cookie() {
72         waveform_data = NULL;
73         fft_data = NULL;
74     }
75 
~visualizer_callback_cookievisualizer_callback_cookie76     ~visualizer_callback_cookie() {
77         cleanupBuffers();
78     }
79 
cleanupBuffersvisualizer_callback_cookie80     void cleanupBuffers() {
81         AutoMutex lock(&callback_data_lock);
82         if (waveform_data || fft_data) {
83             JNIEnv *env = AndroidRuntime::getJNIEnv();
84 
85             if (waveform_data) {
86                 env->DeleteGlobalRef(waveform_data);
87                 waveform_data = NULL;
88             }
89 
90             if (fft_data) {
91                 env->DeleteGlobalRef(fft_data);
92                 fft_data = NULL;
93             }
94         }
95     }
96  };
97 
98 // ----------------------------------------------------------------------------
99 class visualizerJniStorage {
100     public:
101         visualizer_callback_cookie mCallbackData;
102 
visualizerJniStorage()103     visualizerJniStorage() {
104     }
105 
~visualizerJniStorage()106     ~visualizerJniStorage() {
107     }
108 };
109 
110 
translateError(int code)111 static jint translateError(int code) {
112     switch(code) {
113     case NO_ERROR:
114         return VISUALIZER_SUCCESS;
115     case ALREADY_EXISTS:
116         return VISUALIZER_ERROR_ALREADY_EXISTS;
117     case NO_INIT:
118         return VISUALIZER_ERROR_NO_INIT;
119     case BAD_VALUE:
120         return VISUALIZER_ERROR_BAD_VALUE;
121     case INVALID_OPERATION:
122         return VISUALIZER_ERROR_INVALID_OPERATION;
123     case NO_MEMORY:
124         return VISUALIZER_ERROR_NO_MEMORY;
125     case DEAD_OBJECT:
126         return VISUALIZER_ERROR_DEAD_OBJECT;
127     default:
128         return VISUALIZER_ERROR;
129     }
130 }
131 
132 
133 // ----------------------------------------------------------------------------
ensureArraySize(JNIEnv * env,jbyteArray * array,uint32_t size)134 static void ensureArraySize(JNIEnv *env, jbyteArray *array, uint32_t size) {
135     if (NULL != *array) {
136         uint32_t len = env->GetArrayLength(*array);
137         if (len == size)
138             return;
139 
140         env->DeleteGlobalRef(*array);
141         *array = NULL;
142     }
143 
144     jbyteArray localRef = env->NewByteArray(size);
145     if (NULL != localRef) {
146         // Promote to global ref.
147         *array = (jbyteArray)env->NewGlobalRef(localRef);
148 
149         // Release our (now pointless) local ref.
150         env->DeleteLocalRef(localRef);
151     }
152 }
153 
captureCallback(void * user,uint32_t waveformSize,uint8_t * waveform,uint32_t fftSize,uint8_t * fft,uint32_t samplingrate)154 static void captureCallback(void* user,
155         uint32_t waveformSize,
156         uint8_t *waveform,
157         uint32_t fftSize,
158         uint8_t *fft,
159         uint32_t samplingrate) {
160 
161     int arg1 = 0;
162     int arg2 = 0;
163     size_t size;
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 
getVisualizer(JNIEnv * env,jobject thiz)228 static Visualizer *getVisualizer(JNIEnv* env, jobject thiz)
229 {
230     Visualizer *v = (Visualizer *)env->GetIntField(
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.
243 static void
android_media_visualizer_native_init(JNIEnv * env)244 android_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 postEvent method
261     fields.midPostNativeEvent = env->GetStaticMethodID(
262             fields.clazzEffect,
263             "postEventFromNative", "(Ljava/lang/Object;IIILjava/lang/Object;)V");
264     if (fields.midPostNativeEvent == NULL) {
265         ALOGE("Can't find Visualizer.%s", "postEventFromNative");
266         return;
267     }
268 
269     // Get the variables fields
270     //      nativeTrackInJavaObj
271     fields.fidNativeVisualizer = env->GetFieldID(
272             fields.clazzEffect,
273             "mNativeVisualizer", "I");
274     if (fields.fidNativeVisualizer == NULL) {
275         ALOGE("Can't find Visualizer.%s", "mNativeVisualizer");
276         return;
277     }
278     //      fidJniData;
279     fields.fidJniData = env->GetFieldID(
280             fields.clazzEffect,
281             "mJniData", "I");
282     if (fields.fidJniData == NULL) {
283         ALOGE("Can't find Visualizer.%s", "mJniData");
284         return;
285     }
286 
287 }
288 
android_media_visualizer_effect_callback(int32_t event,void * user,void * info)289 static void android_media_visualizer_effect_callback(int32_t event,
290                                                      void *user,
291                                                      void *info) {
292     if ((event == AudioEffect::EVENT_ERROR) &&
293         (*((status_t*)info) == DEAD_OBJECT)) {
294         visualizerJniStorage* lpJniStorage = (visualizerJniStorage*)user;
295         visualizer_callback_cookie* callbackInfo = &lpJniStorage->mCallbackData;
296         JNIEnv *env = AndroidRuntime::getJNIEnv();
297 
298         env->CallStaticVoidMethod(
299             callbackInfo->visualizer_class,
300             fields.midPostNativeEvent,
301             callbackInfo->visualizer_ref,
302             NATIVE_EVENT_SERVER_DIED,
303             0, 0, 0);
304     }
305 }
306 
307 static jint
android_media_visualizer_native_setup(JNIEnv * env,jobject thiz,jobject weak_this,jint sessionId,jintArray jId)308 android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
309         jint sessionId, jintArray jId)
310 {
311     ALOGV("android_media_visualizer_native_setup");
312     visualizerJniStorage* lpJniStorage = NULL;
313     int lStatus = VISUALIZER_ERROR_NO_MEMORY;
314     Visualizer* lpVisualizer = NULL;
315     jint* nId = NULL;
316 
317     lpJniStorage = new visualizerJniStorage();
318     if (lpJniStorage == NULL) {
319         ALOGE("setup: Error creating JNI Storage");
320         goto setup_failure;
321     }
322 
323     lpJniStorage->mCallbackData.visualizer_class = (jclass)env->NewGlobalRef(fields.clazzEffect);
324     // we use a weak reference so the Visualizer object can be garbage collected.
325     lpJniStorage->mCallbackData.visualizer_ref = env->NewGlobalRef(weak_this);
326 
327     ALOGV("setup: lpJniStorage: %p visualizer_ref %p visualizer_class %p, &mCallbackData %p",
328             lpJniStorage,
329             lpJniStorage->mCallbackData.visualizer_ref,
330             lpJniStorage->mCallbackData.visualizer_class,
331             &lpJniStorage->mCallbackData);
332 
333     if (jId == NULL) {
334         ALOGE("setup: NULL java array for id pointer");
335         lStatus = VISUALIZER_ERROR_BAD_VALUE;
336         goto setup_failure;
337     }
338 
339     // create the native Visualizer object
340     lpVisualizer = new Visualizer(0,
341                                   android_media_visualizer_effect_callback,
342                                   lpJniStorage,
343                                   sessionId);
344     if (lpVisualizer == NULL) {
345         ALOGE("Error creating Visualizer");
346         goto setup_failure;
347     }
348 
349     lStatus = translateError(lpVisualizer->initCheck());
350     if (lStatus != VISUALIZER_SUCCESS && lStatus != VISUALIZER_ERROR_ALREADY_EXISTS) {
351         ALOGE("Visualizer initCheck failed %d", lStatus);
352         goto setup_failure;
353     }
354 
355     nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL);
356     if (nId == NULL) {
357         ALOGE("setup: Error retrieving id pointer");
358         lStatus = VISUALIZER_ERROR_BAD_VALUE;
359         goto setup_failure;
360     }
361     nId[0] = lpVisualizer->id();
362     env->ReleasePrimitiveArrayCritical(jId, nId, 0);
363     nId = NULL;
364 
365     env->SetIntField(thiz, fields.fidNativeVisualizer, (int)lpVisualizer);
366 
367     env->SetIntField(thiz, fields.fidJniData, (int)lpJniStorage);
368 
369     return VISUALIZER_SUCCESS;
370 
371     // failures:
372 setup_failure:
373 
374     if (nId != NULL) {
375         env->ReleasePrimitiveArrayCritical(jId, nId, 0);
376     }
377 
378     if (lpVisualizer) {
379         delete lpVisualizer;
380     }
381     env->SetIntField(thiz, fields.fidNativeVisualizer, 0);
382 
383     if (lpJniStorage) {
384         delete lpJniStorage;
385     }
386     env->SetIntField(thiz, fields.fidJniData, 0);
387 
388     return lStatus;
389 }
390 
391 // ----------------------------------------------------------------------------
android_media_visualizer_native_finalize(JNIEnv * env,jobject thiz)392 static void android_media_visualizer_native_finalize(JNIEnv *env,  jobject thiz) {
393     ALOGV("android_media_visualizer_native_finalize jobject: %x\n", (int)thiz);
394 
395     // delete the Visualizer object
396     Visualizer* lpVisualizer = (Visualizer *)env->GetIntField(
397         thiz, fields.fidNativeVisualizer);
398     if (lpVisualizer) {
399         ALOGV("deleting Visualizer: %x\n", (int)lpVisualizer);
400         delete lpVisualizer;
401     }
402 
403     // delete the JNI data
404     visualizerJniStorage* lpJniStorage = (visualizerJniStorage *)env->GetIntField(
405         thiz, fields.fidJniData);
406     if (lpJniStorage) {
407         ALOGV("deleting pJniStorage: %x\n", (int)lpJniStorage);
408         delete lpJniStorage;
409     }
410 }
411 
412 // ----------------------------------------------------------------------------
android_media_visualizer_native_release(JNIEnv * env,jobject thiz)413 static void android_media_visualizer_native_release(JNIEnv *env,  jobject thiz) {
414 
415     // do everything a call to finalize would
416     android_media_visualizer_native_finalize(env, thiz);
417     // + reset the native resources in the Java object so any attempt to access
418     // them after a call to release fails.
419     env->SetIntField(thiz, fields.fidNativeVisualizer, 0);
420     env->SetIntField(thiz, fields.fidJniData, 0);
421 }
422 
423 static jint
android_media_visualizer_native_setEnabled(JNIEnv * env,jobject thiz,jboolean enabled)424 android_media_visualizer_native_setEnabled(JNIEnv *env, jobject thiz, jboolean enabled)
425 {
426     Visualizer* lpVisualizer = getVisualizer(env, thiz);
427     if (lpVisualizer == NULL) {
428         return VISUALIZER_ERROR_NO_INIT;
429     }
430 
431     jint retVal = translateError(lpVisualizer->setEnabled(enabled));
432 
433     if (!enabled) {
434         visualizerJniStorage* lpJniStorage = (visualizerJniStorage *)env->GetIntField(
435             thiz, fields.fidJniData);
436 
437         if (NULL != lpJniStorage)
438             lpJniStorage->mCallbackData.cleanupBuffers();
439     }
440 
441     return retVal;
442 }
443 
444 static jboolean
android_media_visualizer_native_getEnabled(JNIEnv * env,jobject thiz)445 android_media_visualizer_native_getEnabled(JNIEnv *env, jobject thiz)
446 {
447     Visualizer* lpVisualizer = getVisualizer(env, thiz);
448     if (lpVisualizer == NULL) {
449         return false;
450     }
451 
452     return (jboolean)lpVisualizer->getEnabled();
453 }
454 
455 static jintArray
android_media_visualizer_native_getCaptureSizeRange(JNIEnv * env,jobject thiz)456 android_media_visualizer_native_getCaptureSizeRange(JNIEnv *env, jobject thiz)
457 {
458     jintArray jRange = env->NewIntArray(2);
459     jint *nRange = env->GetIntArrayElements(jRange, NULL);
460     nRange[0] = Visualizer::getMinCaptureSize();
461     nRange[1] = Visualizer::getMaxCaptureSize();
462     ALOGV("getCaptureSizeRange() min %d max %d", nRange[0], nRange[1]);
463     env->ReleaseIntArrayElements(jRange, nRange, 0);
464     return jRange;
465 }
466 
467 static jint
android_media_visualizer_native_getMaxCaptureRate(JNIEnv * env,jobject thiz)468 android_media_visualizer_native_getMaxCaptureRate(JNIEnv *env, jobject thiz)
469 {
470     return Visualizer::getMaxCaptureRate();
471 }
472 
473 static jint
android_media_visualizer_native_setCaptureSize(JNIEnv * env,jobject thiz,jint size)474 android_media_visualizer_native_setCaptureSize(JNIEnv *env, jobject thiz, jint size)
475 {
476     Visualizer* lpVisualizer = getVisualizer(env, thiz);
477     if (lpVisualizer == NULL) {
478         return VISUALIZER_ERROR_NO_INIT;
479     }
480 
481     return translateError(lpVisualizer->setCaptureSize(size));
482 }
483 
484 static jint
android_media_visualizer_native_getCaptureSize(JNIEnv * env,jobject thiz)485 android_media_visualizer_native_getCaptureSize(JNIEnv *env, jobject thiz)
486 {
487     Visualizer* lpVisualizer = getVisualizer(env, thiz);
488     if (lpVisualizer == NULL) {
489         return -1;
490     }
491     return lpVisualizer->getCaptureSize();
492 }
493 
494 static jint
android_media_visualizer_native_setScalingMode(JNIEnv * env,jobject thiz,jint mode)495 android_media_visualizer_native_setScalingMode(JNIEnv *env, jobject thiz, jint mode)
496 {
497     Visualizer* lpVisualizer = getVisualizer(env, thiz);
498     if (lpVisualizer == NULL) {
499         return VISUALIZER_ERROR_NO_INIT;
500     }
501 
502     return translateError(lpVisualizer->setScalingMode(mode));
503 }
504 
505 static jint
android_media_visualizer_native_getScalingMode(JNIEnv * env,jobject thiz)506 android_media_visualizer_native_getScalingMode(JNIEnv *env, jobject thiz)
507 {
508     Visualizer* lpVisualizer = getVisualizer(env, thiz);
509     if (lpVisualizer == NULL) {
510         return -1;
511     }
512     return lpVisualizer->getScalingMode();
513 }
514 
515 static jint
android_media_visualizer_native_getSamplingRate(JNIEnv * env,jobject thiz)516 android_media_visualizer_native_getSamplingRate(JNIEnv *env, jobject thiz)
517 {
518     Visualizer* lpVisualizer = getVisualizer(env, thiz);
519     if (lpVisualizer == NULL) {
520         return -1;
521     }
522     return lpVisualizer->getSamplingRate();
523 }
524 
525 static jint
android_media_visualizer_native_getWaveForm(JNIEnv * env,jobject thiz,jbyteArray jWaveform)526 android_media_visualizer_native_getWaveForm(JNIEnv *env, jobject thiz, jbyteArray jWaveform)
527 {
528     Visualizer* lpVisualizer = getVisualizer(env, thiz);
529     if (lpVisualizer == NULL) {
530         return VISUALIZER_ERROR_NO_INIT;
531     }
532 
533     jbyte* nWaveform = (jbyte *) env->GetPrimitiveArrayCritical(jWaveform, NULL);
534     if (nWaveform == NULL) {
535         return VISUALIZER_ERROR_NO_MEMORY;
536     }
537     jint status = translateError(lpVisualizer->getWaveForm((uint8_t *)nWaveform));
538 
539     env->ReleasePrimitiveArrayCritical(jWaveform, nWaveform, 0);
540     return status;
541 }
542 
543 static jint
android_media_visualizer_native_getFft(JNIEnv * env,jobject thiz,jbyteArray jFft)544 android_media_visualizer_native_getFft(JNIEnv *env, jobject thiz, jbyteArray jFft)
545 {
546     Visualizer* lpVisualizer = getVisualizer(env, thiz);
547     if (lpVisualizer == NULL) {
548         return VISUALIZER_ERROR_NO_INIT;
549     }
550 
551     jbyte* nFft = (jbyte *) env->GetPrimitiveArrayCritical(jFft, NULL);
552     if (nFft == NULL) {
553         return VISUALIZER_ERROR_NO_MEMORY;
554     }
555     jint status = translateError(lpVisualizer->getFft((uint8_t *)nFft));
556 
557     env->ReleasePrimitiveArrayCritical(jFft, nFft, 0);
558 
559     return status;
560 }
561 
562 static jint
android_media_setPeriodicCapture(JNIEnv * env,jobject thiz,jint rate,jboolean jWaveform,jboolean jFft)563 android_media_setPeriodicCapture(JNIEnv *env, jobject thiz, jint rate, jboolean jWaveform, jboolean jFft)
564 {
565     Visualizer* lpVisualizer = getVisualizer(env, thiz);
566     if (lpVisualizer == NULL) {
567         return VISUALIZER_ERROR_NO_INIT;
568     }
569     visualizerJniStorage* lpJniStorage = (visualizerJniStorage *)env->GetIntField(thiz,
570             fields.fidJniData);
571     if (lpJniStorage == NULL) {
572         return VISUALIZER_ERROR_NO_INIT;
573     }
574 
575     ALOGV("setPeriodicCapture: rate %d, jWaveform %d jFft %d",
576             rate,
577             jWaveform,
578             jFft);
579 
580     uint32_t flags = Visualizer::CAPTURE_CALL_JAVA;
581     if (jWaveform) flags |= Visualizer::CAPTURE_WAVEFORM;
582     if (jFft) flags |= Visualizer::CAPTURE_FFT;
583     Visualizer::capture_cbk_t cbk = captureCallback;
584     if (!jWaveform && !jFft) cbk = NULL;
585 
586     return translateError(lpVisualizer->setCaptureCallBack(cbk,
587                                                 &lpJniStorage->mCallbackData,
588                                                 flags,
589                                                 rate));
590 }
591 
592 // ----------------------------------------------------------------------------
593 
594 // Dalvik VM type signatures
595 static JNINativeMethod gMethods[] = {
596     {"native_init",            "()V",     (void *)android_media_visualizer_native_init},
597     {"native_setup",           "(Ljava/lang/Object;I[I)I",
598                                           (void *)android_media_visualizer_native_setup},
599     {"native_finalize",          "()V",   (void *)android_media_visualizer_native_finalize},
600     {"native_release",           "()V",   (void *)android_media_visualizer_native_release},
601     {"native_setEnabled",        "(Z)I",  (void *)android_media_visualizer_native_setEnabled},
602     {"native_getEnabled",        "()Z",   (void *)android_media_visualizer_native_getEnabled},
603     {"getCaptureSizeRange",      "()[I",  (void *)android_media_visualizer_native_getCaptureSizeRange},
604     {"getMaxCaptureRate",        "()I",   (void *)android_media_visualizer_native_getMaxCaptureRate},
605     {"native_setCaptureSize",    "(I)I",  (void *)android_media_visualizer_native_setCaptureSize},
606     {"native_getCaptureSize",    "()I",   (void *)android_media_visualizer_native_getCaptureSize},
607     {"native_setScalingMode",    "(I)I",  (void *)android_media_visualizer_native_setScalingMode},
608     {"native_getScalingMode",    "()I",   (void *)android_media_visualizer_native_getScalingMode},
609     {"native_getSamplingRate",   "()I",   (void *)android_media_visualizer_native_getSamplingRate},
610     {"native_getWaveForm",       "([B)I", (void *)android_media_visualizer_native_getWaveForm},
611     {"native_getFft",            "([B)I", (void *)android_media_visualizer_native_getFft},
612     {"native_setPeriodicCapture","(IZZ)I",(void *)android_media_setPeriodicCapture},
613 };
614 
615 // ----------------------------------------------------------------------------
616 
register_android_media_visualizer(JNIEnv * env)617 int register_android_media_visualizer(JNIEnv *env)
618 {
619     return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
620 }
621 
622