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