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 <jni.h>
24 #include <nativehelper/JNIHelp.h>
25 #include <android_runtime/AndroidRuntime.h>
26 #include <utils/threads.h>
27 #include "Visualizer.h"
28
29 #include <nativehelper/ScopedUtfChars.h>
30
31 using namespace android;
32
33 #define VISUALIZER_SUCCESS 0
34 #define VISUALIZER_ERROR (-1)
35 #define VISUALIZER_ERROR_ALREADY_EXISTS (-2)
36 #define VISUALIZER_ERROR_NO_INIT (-3)
37 #define VISUALIZER_ERROR_BAD_VALUE (-4)
38 #define VISUALIZER_ERROR_INVALID_OPERATION (-5)
39 #define VISUALIZER_ERROR_NO_MEMORY (-6)
40 #define VISUALIZER_ERROR_DEAD_OBJECT (-7)
41
42 #define NATIVE_EVENT_PCM_CAPTURE 0
43 #define NATIVE_EVENT_FFT_CAPTURE 1
44 #define NATIVE_EVENT_SERVER_DIED 2
45
46 // ----------------------------------------------------------------------------
47 static const char* const kClassPathName = "android/media/audiofx/Visualizer";
48 static const char* const kClassPeakRmsPathName =
49 "android/media/audiofx/Visualizer$MeasurementPeakRms";
50
51 struct fields_t {
52 // these fields provide access from C++ to the...
53 jclass clazzEffect; // Visualizer class
54 jmethodID midPostNativeEvent; // event post callback method
55 jfieldID fidNativeVisualizer; // stores in Java the native Visualizer object
56 jfieldID fidJniData; // stores in Java additional resources used by the native Visualizer
57 jfieldID fidPeak; // to access Visualizer.MeasurementPeakRms.mPeak
58 jfieldID fidRms; // to access Visualizer.MeasurementPeakRms.mRms
59 };
60 static fields_t fields;
61
62 struct visualizer_callback_cookie {
63 jclass visualizer_class; // Visualizer class
64 jobject visualizer_ref; // Visualizer object instance
65
66 // Lazily allocated arrays used to hold callback data provided to java
67 // applications. These arrays are allocated during the first callback and
68 // reallocated when the size of the callback data changes. Allocating on
69 // demand and saving the arrays means that applications cannot safely hold a
70 // reference to the provided data (they need to make a copy if they want to
71 // hold onto outside of the callback scope), but it avoids GC thrash caused
72 // by constantly allocating and releasing arrays to hold callback data.
73 Mutex callback_data_lock;
74 jbyteArray waveform_data;
75 jbyteArray fft_data;
76
visualizer_callback_cookievisualizer_callback_cookie77 visualizer_callback_cookie() {
78 waveform_data = NULL;
79 fft_data = NULL;
80 }
81
~visualizer_callback_cookievisualizer_callback_cookie82 ~visualizer_callback_cookie() {
83 cleanupBuffers();
84 }
85
cleanupBuffersvisualizer_callback_cookie86 void cleanupBuffers() {
87 AutoMutex lock(&callback_data_lock);
88 if (waveform_data || fft_data) {
89 JNIEnv *env = AndroidRuntime::getJNIEnv();
90
91 if (waveform_data) {
92 env->DeleteGlobalRef(waveform_data);
93 waveform_data = NULL;
94 }
95
96 if (fft_data) {
97 env->DeleteGlobalRef(fft_data);
98 fft_data = NULL;
99 }
100 }
101 }
102 };
103
104 // ----------------------------------------------------------------------------
105 class VisualizerJniStorage {
106 public:
107 visualizer_callback_cookie mCallbackData;
108
VisualizerJniStorage()109 VisualizerJniStorage() {
110 }
111
~VisualizerJniStorage()112 ~VisualizerJniStorage() {
113 }
114 };
115
116
translateError(int code)117 static jint translateError(int code) {
118 switch(code) {
119 case NO_ERROR:
120 return VISUALIZER_SUCCESS;
121 case ALREADY_EXISTS:
122 return VISUALIZER_ERROR_ALREADY_EXISTS;
123 case NO_INIT:
124 return VISUALIZER_ERROR_NO_INIT;
125 case BAD_VALUE:
126 return VISUALIZER_ERROR_BAD_VALUE;
127 case INVALID_OPERATION:
128 return VISUALIZER_ERROR_INVALID_OPERATION;
129 case NO_MEMORY:
130 return VISUALIZER_ERROR_NO_MEMORY;
131 case DEAD_OBJECT:
132 return VISUALIZER_ERROR_DEAD_OBJECT;
133 default:
134 return VISUALIZER_ERROR;
135 }
136 }
137
138 static Mutex sLock;
139
140 // ----------------------------------------------------------------------------
ensureArraySize(JNIEnv * env,jbyteArray * array,uint32_t size)141 static void ensureArraySize(JNIEnv *env, jbyteArray *array, uint32_t size) {
142 if (NULL != *array) {
143 uint32_t len = env->GetArrayLength(*array);
144 if (len == size)
145 return;
146
147 env->DeleteGlobalRef(*array);
148 *array = NULL;
149 }
150
151 jbyteArray localRef = env->NewByteArray(size);
152 if (NULL != localRef) {
153 // Promote to global ref.
154 *array = (jbyteArray)env->NewGlobalRef(localRef);
155
156 // Release our (now pointless) local ref.
157 env->DeleteLocalRef(localRef);
158 }
159 }
160
captureCallback(void * user,uint32_t waveformSize,uint8_t * waveform,uint32_t fftSize,uint8_t * fft,uint32_t samplingrate)161 static void captureCallback(void* user,
162 uint32_t waveformSize,
163 uint8_t *waveform,
164 uint32_t fftSize,
165 uint8_t *fft,
166 uint32_t samplingrate) {
167
168 visualizer_callback_cookie *callbackInfo = (visualizer_callback_cookie *)user;
169 JNIEnv *env = AndroidRuntime::getJNIEnv();
170
171 if (!user || !env) {
172 ALOGW("captureCallback error user %p, env %p", user, env);
173 return;
174 }
175
176 ALOGV("captureCallback: callbackInfo %p, visualizer_ref %p visualizer_class %p",
177 callbackInfo,
178 callbackInfo->visualizer_ref,
179 callbackInfo->visualizer_class);
180
181 AutoMutex lock(&callbackInfo->callback_data_lock);
182
183 if (waveformSize != 0 && waveform != NULL) {
184 jbyteArray jArray;
185
186 ensureArraySize(env, &callbackInfo->waveform_data, waveformSize);
187 jArray = callbackInfo->waveform_data;
188
189 if (jArray != NULL) {
190 jbyte *nArray = env->GetByteArrayElements(jArray, NULL);
191 memcpy(nArray, waveform, waveformSize);
192 env->ReleaseByteArrayElements(jArray, nArray, 0);
193 env->CallStaticVoidMethod(
194 callbackInfo->visualizer_class,
195 fields.midPostNativeEvent,
196 callbackInfo->visualizer_ref,
197 NATIVE_EVENT_PCM_CAPTURE,
198 samplingrate,
199 jArray);
200 }
201 }
202
203 if (fftSize != 0 && fft != NULL) {
204 jbyteArray jArray;
205
206 ensureArraySize(env, &callbackInfo->fft_data, fftSize);
207 jArray = callbackInfo->fft_data;
208
209 if (jArray != NULL) {
210 jbyte *nArray = env->GetByteArrayElements(jArray, NULL);
211 memcpy(nArray, fft, fftSize);
212 env->ReleaseByteArrayElements(jArray, nArray, 0);
213 env->CallStaticVoidMethod(
214 callbackInfo->visualizer_class,
215 fields.midPostNativeEvent,
216 callbackInfo->visualizer_ref,
217 NATIVE_EVENT_FFT_CAPTURE,
218 samplingrate,
219 jArray);
220 }
221 }
222
223 if (env->ExceptionCheck()) {
224 env->ExceptionDescribe();
225 env->ExceptionClear();
226 }
227 }
228
229 // ----------------------------------------------------------------------------
230
getVisualizer(JNIEnv * env,jobject thiz)231 static sp<Visualizer> getVisualizer(JNIEnv* env, jobject thiz)
232 {
233 Mutex::Autolock l(sLock);
234 Visualizer* const v =
235 (Visualizer*)env->GetLongField(thiz, fields.fidNativeVisualizer);
236 return sp<Visualizer>(v);
237 }
238
setVisualizer(JNIEnv * env,jobject thiz,const sp<Visualizer> & v)239 static sp<Visualizer> setVisualizer(JNIEnv* env, jobject thiz,
240 const sp<Visualizer>& v)
241 {
242 Mutex::Autolock l(sLock);
243 sp<Visualizer> old =
244 (Visualizer*)env->GetLongField(thiz, fields.fidNativeVisualizer);
245 if (v.get()) {
246 v->incStrong((void*)setVisualizer);
247 }
248 if (old != 0) {
249 old->decStrong((void*)setVisualizer);
250 }
251 env->SetLongField(thiz, fields.fidNativeVisualizer, (jlong)v.get());
252 return old;
253 }
254
255 // ----------------------------------------------------------------------------
256 // This function gets some field IDs, which in turn causes class initialization.
257 // It is called from a static block in Visualizer, which won't run until the
258 // first time an instance of this class is used.
259 static void
android_media_visualizer_native_init(JNIEnv * env)260 android_media_visualizer_native_init(JNIEnv *env)
261 {
262
263 ALOGV("android_media_visualizer_native_init");
264
265 fields.clazzEffect = NULL;
266
267 // Get the Visualizer class
268 jclass clazz = env->FindClass(kClassPathName);
269 if (clazz == NULL) {
270 ALOGE("Can't find %s", kClassPathName);
271 return;
272 }
273
274 fields.clazzEffect = (jclass)env->NewGlobalRef(clazz);
275
276 // Get the Visualizer.MeasurementPeakRms class
277 clazz = env->FindClass(kClassPeakRmsPathName);
278 if (clazz == NULL) {
279 ALOGE("Can't find %s", kClassPeakRmsPathName);
280 return;
281 }
282 jclass clazzMeasurementPeakRms = (jclass)env->NewGlobalRef(clazz);
283
284 // Get the postEvent method
285 fields.midPostNativeEvent = env->GetStaticMethodID(
286 fields.clazzEffect,
287 "postEventFromNative", "(Ljava/lang/Object;II[B)V");
288 if (fields.midPostNativeEvent == NULL) {
289 ALOGE("Can't find Visualizer.%s", "postEventFromNative");
290 return;
291 }
292
293 // Get the variables fields
294 // nativeTrackInJavaObj
295 fields.fidNativeVisualizer = env->GetFieldID(
296 fields.clazzEffect,
297 "mNativeVisualizer", "J");
298 if (fields.fidNativeVisualizer == NULL) {
299 ALOGE("Can't find Visualizer.%s", "mNativeVisualizer");
300 return;
301 }
302 // fidJniData;
303 fields.fidJniData = env->GetFieldID(
304 fields.clazzEffect,
305 "mJniData", "J");
306 if (fields.fidJniData == NULL) {
307 ALOGE("Can't find Visualizer.%s", "mJniData");
308 return;
309 }
310 // fidPeak
311 fields.fidPeak = env->GetFieldID(
312 clazzMeasurementPeakRms,
313 "mPeak", "I");
314 if (fields.fidPeak == NULL) {
315 ALOGE("Can't find Visualizer.MeasurementPeakRms.%s", "mPeak");
316 return;
317 }
318 // fidRms
319 fields.fidRms = env->GetFieldID(
320 clazzMeasurementPeakRms,
321 "mRms", "I");
322 if (fields.fidRms == NULL) {
323 ALOGE("Can't find Visualizer.MeasurementPeakRms.%s", "mPeak");
324 return;
325 }
326
327 env->DeleteGlobalRef(clazzMeasurementPeakRms);
328 }
329
android_media_visualizer_effect_callback(int32_t event,void * user,void * info)330 static void android_media_visualizer_effect_callback(int32_t event,
331 void *user,
332 void *info) {
333 if ((event == AudioEffect::EVENT_ERROR) &&
334 (*((status_t*)info) == DEAD_OBJECT)) {
335 VisualizerJniStorage* lpJniStorage = (VisualizerJniStorage*)user;
336 visualizer_callback_cookie* callbackInfo = &lpJniStorage->mCallbackData;
337 JNIEnv *env = AndroidRuntime::getJNIEnv();
338
339 env->CallStaticVoidMethod(
340 callbackInfo->visualizer_class,
341 fields.midPostNativeEvent,
342 callbackInfo->visualizer_ref,
343 NATIVE_EVENT_SERVER_DIED,
344 0, NULL);
345 }
346 }
347
348 static jint
android_media_visualizer_native_setup(JNIEnv * env,jobject thiz,jobject weak_this,jint sessionId,jintArray jId,jstring opPackageName)349 android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
350 jint sessionId, jintArray jId, jstring opPackageName)
351 {
352 ALOGV("android_media_visualizer_native_setup");
353 VisualizerJniStorage* lpJniStorage = NULL;
354 int lStatus = VISUALIZER_ERROR_NO_MEMORY;
355 sp<Visualizer> lpVisualizer;
356 jint* nId = NULL;
357
358 ScopedUtfChars opPackageNameStr(env, opPackageName);
359
360 setVisualizer(env, thiz, 0);
361
362 lpJniStorage = new VisualizerJniStorage();
363 if (lpJniStorage == NULL) {
364 ALOGE("setup: Error creating JNI Storage");
365 goto setup_failure;
366 }
367
368 lpJniStorage->mCallbackData.visualizer_class = (jclass)env->NewGlobalRef(fields.clazzEffect);
369 // we use a weak reference so the Visualizer object can be garbage collected.
370 lpJniStorage->mCallbackData.visualizer_ref = env->NewGlobalRef(weak_this);
371
372 ALOGV("setup: lpJniStorage: %p visualizer_ref %p visualizer_class %p, &mCallbackData %p",
373 lpJniStorage,
374 lpJniStorage->mCallbackData.visualizer_ref,
375 lpJniStorage->mCallbackData.visualizer_class,
376 &lpJniStorage->mCallbackData);
377
378 if (jId == NULL) {
379 ALOGE("setup: NULL java array for id pointer");
380 lStatus = VISUALIZER_ERROR_BAD_VALUE;
381 goto setup_failure;
382 }
383
384 // create the native Visualizer object
385 lpVisualizer = new Visualizer(String16(opPackageNameStr.c_str()),
386 0,
387 android_media_visualizer_effect_callback,
388 lpJniStorage,
389 (audio_session_t) sessionId);
390 if (lpVisualizer == 0) {
391 ALOGE("Error creating Visualizer");
392 goto setup_failure;
393 }
394
395 lStatus = translateError(lpVisualizer->initCheck());
396 if (lStatus != VISUALIZER_SUCCESS && lStatus != VISUALIZER_ERROR_ALREADY_EXISTS) {
397 ALOGE("Visualizer initCheck failed %d", lStatus);
398 goto setup_failure;
399 }
400
401 nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL);
402 if (nId == NULL) {
403 ALOGE("setup: Error retrieving id pointer");
404 lStatus = VISUALIZER_ERROR_BAD_VALUE;
405 goto setup_failure;
406 }
407 nId[0] = lpVisualizer->id();
408 env->ReleasePrimitiveArrayCritical(jId, nId, 0);
409 nId = NULL;
410
411 setVisualizer(env, thiz, lpVisualizer);
412
413 env->SetLongField(thiz, fields.fidJniData, (jlong)lpJniStorage);
414
415 return VISUALIZER_SUCCESS;
416
417 // failures:
418 setup_failure:
419
420 if (nId != NULL) {
421 env->ReleasePrimitiveArrayCritical(jId, nId, 0);
422 }
423
424 if (lpJniStorage) {
425 env->DeleteGlobalRef(lpJniStorage->mCallbackData.visualizer_class);
426 env->DeleteGlobalRef(lpJniStorage->mCallbackData.visualizer_ref);
427 delete lpJniStorage;
428 }
429 env->SetLongField(thiz, fields.fidJniData, 0);
430
431 return (jint) lStatus;
432 }
433
434 // ----------------------------------------------------------------------------
android_media_visualizer_native_release(JNIEnv * env,jobject thiz)435 static void android_media_visualizer_native_release(JNIEnv *env, jobject thiz) {
436 { //limit scope so that lpVisualizer is deleted before JNI storage data.
437 sp<Visualizer> lpVisualizer = setVisualizer(env, thiz, 0);
438 if (lpVisualizer == 0) {
439 return;
440 }
441 lpVisualizer->release();
442 }
443 // delete the JNI data
444 VisualizerJniStorage* lpJniStorage =
445 (VisualizerJniStorage *)env->GetLongField(thiz, fields.fidJniData);
446
447 // reset the native resources in the Java object so any attempt to access
448 // them after a call to release fails.
449 env->SetLongField(thiz, fields.fidJniData, 0);
450
451 if (lpJniStorage) {
452 ALOGV("deleting pJniStorage: %p\n", lpJniStorage);
453 env->DeleteGlobalRef(lpJniStorage->mCallbackData.visualizer_class);
454 env->DeleteGlobalRef(lpJniStorage->mCallbackData.visualizer_ref);
455 delete lpJniStorage;
456 }
457 }
458
android_media_visualizer_native_finalize(JNIEnv * env,jobject thiz)459 static void android_media_visualizer_native_finalize(JNIEnv *env, jobject thiz) {
460 ALOGV("android_media_visualizer_native_finalize jobject: %p\n", thiz);
461 android_media_visualizer_native_release(env, thiz);
462 }
463
464 // ----------------------------------------------------------------------------
465 static jint
android_media_visualizer_native_setEnabled(JNIEnv * env,jobject thiz,jboolean enabled)466 android_media_visualizer_native_setEnabled(JNIEnv *env, jobject thiz, jboolean enabled)
467 {
468 sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
469 if (lpVisualizer == 0) {
470 return VISUALIZER_ERROR_NO_INIT;
471 }
472
473 jint retVal = translateError(lpVisualizer->setEnabled(enabled));
474
475 if (!enabled) {
476 VisualizerJniStorage* lpJniStorage = (VisualizerJniStorage *)env->GetLongField(
477 thiz, fields.fidJniData);
478
479 if (NULL != lpJniStorage)
480 lpJniStorage->mCallbackData.cleanupBuffers();
481 }
482
483 return retVal;
484 }
485
486 static jboolean
android_media_visualizer_native_getEnabled(JNIEnv * env,jobject thiz)487 android_media_visualizer_native_getEnabled(JNIEnv *env, jobject thiz)
488 {
489 sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
490 if (lpVisualizer == 0) {
491 return JNI_FALSE;
492 }
493
494 if (lpVisualizer->getEnabled()) {
495 return JNI_TRUE;
496 } else {
497 return JNI_FALSE;
498 }
499 }
500
501 static jintArray
android_media_visualizer_native_getCaptureSizeRange(JNIEnv * env,jobject)502 android_media_visualizer_native_getCaptureSizeRange(JNIEnv *env, jobject /* thiz */)
503 {
504 jintArray jRange = env->NewIntArray(2);
505 jint *nRange = env->GetIntArrayElements(jRange, NULL);
506 nRange[0] = Visualizer::getMinCaptureSize();
507 nRange[1] = Visualizer::getMaxCaptureSize();
508 ALOGV("getCaptureSizeRange() min %d max %d", nRange[0], nRange[1]);
509 env->ReleaseIntArrayElements(jRange, nRange, 0);
510 return jRange;
511 }
512
513 static jint
android_media_visualizer_native_getMaxCaptureRate(JNIEnv *,jobject)514 android_media_visualizer_native_getMaxCaptureRate(JNIEnv* /* env */, jobject /* thiz */)
515 {
516 return (jint) Visualizer::getMaxCaptureRate();
517 }
518
519 static jint
android_media_visualizer_native_setCaptureSize(JNIEnv * env,jobject thiz,jint size)520 android_media_visualizer_native_setCaptureSize(JNIEnv *env, jobject thiz, jint size)
521 {
522 sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
523 if (lpVisualizer == 0) {
524 return VISUALIZER_ERROR_NO_INIT;
525 }
526
527 return translateError(lpVisualizer->setCaptureSize(size));
528 }
529
530 static jint
android_media_visualizer_native_getCaptureSize(JNIEnv * env,jobject thiz)531 android_media_visualizer_native_getCaptureSize(JNIEnv *env, jobject thiz)
532 {
533 sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
534 if (lpVisualizer == 0) {
535 return -1;
536 }
537 return (jint) lpVisualizer->getCaptureSize();
538 }
539
540 static jint
android_media_visualizer_native_setScalingMode(JNIEnv * env,jobject thiz,jint mode)541 android_media_visualizer_native_setScalingMode(JNIEnv *env, jobject thiz, jint mode)
542 {
543 sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
544 if (lpVisualizer == 0) {
545 return VISUALIZER_ERROR_NO_INIT;
546 }
547
548 return translateError(lpVisualizer->setScalingMode(mode));
549 }
550
551 static jint
android_media_visualizer_native_getScalingMode(JNIEnv * env,jobject thiz)552 android_media_visualizer_native_getScalingMode(JNIEnv *env, jobject thiz)
553 {
554 sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
555 if (lpVisualizer == 0) {
556 return -1;
557 }
558 return (jint)lpVisualizer->getScalingMode();
559 }
560
561 static jint
android_media_visualizer_native_setMeasurementMode(JNIEnv * env,jobject thiz,jint mode)562 android_media_visualizer_native_setMeasurementMode(JNIEnv *env, jobject thiz, jint mode)
563 {
564 sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
565 if (lpVisualizer == 0) {
566 return VISUALIZER_ERROR_NO_INIT;
567 }
568 return translateError(lpVisualizer->setMeasurementMode(mode));
569 }
570
571 static jint
android_media_visualizer_native_getMeasurementMode(JNIEnv * env,jobject thiz)572 android_media_visualizer_native_getMeasurementMode(JNIEnv *env, jobject thiz)
573 {
574 sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
575 if (lpVisualizer == 0) {
576 return MEASUREMENT_MODE_NONE;
577 }
578 return lpVisualizer->getMeasurementMode();
579 }
580
581 static jint
android_media_visualizer_native_getSamplingRate(JNIEnv * env,jobject thiz)582 android_media_visualizer_native_getSamplingRate(JNIEnv *env, jobject thiz)
583 {
584 sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
585 if (lpVisualizer == 0) {
586 return -1;
587 }
588 return (jint) lpVisualizer->getSamplingRate();
589 }
590
591 static jint
android_media_visualizer_native_getWaveForm(JNIEnv * env,jobject thiz,jbyteArray jWaveform)592 android_media_visualizer_native_getWaveForm(JNIEnv *env, jobject thiz, jbyteArray jWaveform)
593 {
594 sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
595 if (lpVisualizer == 0) {
596 return VISUALIZER_ERROR_NO_INIT;
597 }
598
599 jbyte* nWaveform = (jbyte *) env->GetPrimitiveArrayCritical(jWaveform, NULL);
600 if (nWaveform == NULL) {
601 return VISUALIZER_ERROR_NO_MEMORY;
602 }
603 jint status = translateError(lpVisualizer->getWaveForm((uint8_t *)nWaveform));
604
605 env->ReleasePrimitiveArrayCritical(jWaveform, nWaveform, 0);
606 return status;
607 }
608
609 static jint
android_media_visualizer_native_getFft(JNIEnv * env,jobject thiz,jbyteArray jFft)610 android_media_visualizer_native_getFft(JNIEnv *env, jobject thiz, jbyteArray jFft)
611 {
612 sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
613 if (lpVisualizer == 0) {
614 return VISUALIZER_ERROR_NO_INIT;
615 }
616
617 jbyte* nFft = (jbyte *) env->GetPrimitiveArrayCritical(jFft, NULL);
618 if (nFft == NULL) {
619 return VISUALIZER_ERROR_NO_MEMORY;
620 }
621 jint status = translateError(lpVisualizer->getFft((uint8_t *)nFft));
622
623 env->ReleasePrimitiveArrayCritical(jFft, nFft, 0);
624
625 return status;
626 }
627
628 static jint
android_media_visualizer_native_getPeakRms(JNIEnv * env,jobject thiz,jobject jPeakRmsObj)629 android_media_visualizer_native_getPeakRms(JNIEnv *env, jobject thiz, jobject jPeakRmsObj)
630 {
631 sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
632 if (lpVisualizer == 0) {
633 return VISUALIZER_ERROR_NO_INIT;
634 }
635 int32_t measurements[2];
636 jint status = translateError(
637 lpVisualizer->getIntMeasurements(MEASUREMENT_MODE_PEAK_RMS,
638 2, measurements));
639 if (status == VISUALIZER_SUCCESS) {
640 // measurement worked, write the values to the java object
641 env->SetIntField(jPeakRmsObj, fields.fidPeak, measurements[MEASUREMENT_IDX_PEAK]);
642 env->SetIntField(jPeakRmsObj, fields.fidRms, measurements[MEASUREMENT_IDX_RMS]);
643 }
644 return status;
645 }
646
647 static jint
android_media_setPeriodicCapture(JNIEnv * env,jobject thiz,jint rate,jboolean jWaveform,jboolean jFft)648 android_media_setPeriodicCapture(JNIEnv *env, jobject thiz, jint rate, jboolean jWaveform, jboolean jFft)
649 {
650 sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
651 if (lpVisualizer == 0) {
652 return VISUALIZER_ERROR_NO_INIT;
653 }
654 VisualizerJniStorage* lpJniStorage = (VisualizerJniStorage *)env->GetLongField(thiz,
655 fields.fidJniData);
656 if (lpJniStorage == NULL) {
657 return VISUALIZER_ERROR_NO_INIT;
658 }
659
660 ALOGV("setPeriodicCapture: rate %d, jWaveform %d jFft %d",
661 rate,
662 jWaveform,
663 jFft);
664
665 uint32_t flags = Visualizer::CAPTURE_CALL_JAVA;
666 if (jWaveform) flags |= Visualizer::CAPTURE_WAVEFORM;
667 if (jFft) flags |= Visualizer::CAPTURE_FFT;
668 Visualizer::capture_cbk_t cbk = captureCallback;
669 if (!jWaveform && !jFft) cbk = NULL;
670
671 return translateError(lpVisualizer->setCaptureCallBack(cbk,
672 &lpJniStorage->mCallbackData,
673 flags,
674 rate));
675 }
676
677 // ----------------------------------------------------------------------------
678
679 // Dalvik VM type signatures
680 static const JNINativeMethod gMethods[] = {
681 {"native_init", "()V", (void *)android_media_visualizer_native_init},
682 {"native_setup", "(Ljava/lang/Object;I[ILjava/lang/String;)I",
683 (void *)android_media_visualizer_native_setup},
684 {"native_finalize", "()V", (void *)android_media_visualizer_native_finalize},
685 {"native_release", "()V", (void *)android_media_visualizer_native_release},
686 {"native_setEnabled", "(Z)I", (void *)android_media_visualizer_native_setEnabled},
687 {"native_getEnabled", "()Z", (void *)android_media_visualizer_native_getEnabled},
688 {"getCaptureSizeRange", "()[I", (void *)android_media_visualizer_native_getCaptureSizeRange},
689 {"getMaxCaptureRate", "()I", (void *)android_media_visualizer_native_getMaxCaptureRate},
690 {"native_setCaptureSize", "(I)I", (void *)android_media_visualizer_native_setCaptureSize},
691 {"native_getCaptureSize", "()I", (void *)android_media_visualizer_native_getCaptureSize},
692 {"native_setScalingMode", "(I)I", (void *)android_media_visualizer_native_setScalingMode},
693 {"native_getScalingMode", "()I", (void *)android_media_visualizer_native_getScalingMode},
694 {"native_setMeasurementMode","(I)I", (void *)android_media_visualizer_native_setMeasurementMode},
695 {"native_getMeasurementMode","()I", (void *)android_media_visualizer_native_getMeasurementMode},
696 {"native_getSamplingRate", "()I", (void *)android_media_visualizer_native_getSamplingRate},
697 {"native_getWaveForm", "([B)I", (void *)android_media_visualizer_native_getWaveForm},
698 {"native_getFft", "([B)I", (void *)android_media_visualizer_native_getFft},
699 {"native_getPeakRms", "(Landroid/media/audiofx/Visualizer$MeasurementPeakRms;)I",
700 (void *)android_media_visualizer_native_getPeakRms},
701 {"native_setPeriodicCapture","(IZZ)I",(void *)android_media_setPeriodicCapture},
702 };
703
704 // ----------------------------------------------------------------------------
705
register_android_media_visualizer(JNIEnv * env)706 int register_android_media_visualizer(JNIEnv *env)
707 {
708 return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
709 }
710
711