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 #include <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 0,
200 jArray);
201 }
202 }
203
204 if (fftSize != 0 && fft != NULL) {
205 jbyteArray jArray;
206
207 ensureArraySize(env, &callbackInfo->fft_data, fftSize);
208 jArray = callbackInfo->fft_data;
209
210 if (jArray != NULL) {
211 jbyte *nArray = env->GetByteArrayElements(jArray, NULL);
212 memcpy(nArray, fft, fftSize);
213 env->ReleaseByteArrayElements(jArray, nArray, 0);
214 env->CallStaticVoidMethod(
215 callbackInfo->visualizer_class,
216 fields.midPostNativeEvent,
217 callbackInfo->visualizer_ref,
218 NATIVE_EVENT_FFT_CAPTURE,
219 samplingrate,
220 0,
221 jArray);
222 }
223 }
224
225 if (env->ExceptionCheck()) {
226 env->ExceptionDescribe();
227 env->ExceptionClear();
228 }
229 }
230
231 // ----------------------------------------------------------------------------
232
getVisualizer(JNIEnv * env,jobject thiz)233 static sp<Visualizer> getVisualizer(JNIEnv* env, jobject thiz)
234 {
235 Mutex::Autolock l(sLock);
236 Visualizer* const v =
237 (Visualizer*)env->GetLongField(thiz, fields.fidNativeVisualizer);
238 return sp<Visualizer>(v);
239 }
240
setVisualizer(JNIEnv * env,jobject thiz,const sp<Visualizer> & v)241 static sp<Visualizer> setVisualizer(JNIEnv* env, jobject thiz,
242 const sp<Visualizer>& v)
243 {
244 Mutex::Autolock l(sLock);
245 sp<Visualizer> old =
246 (Visualizer*)env->GetLongField(thiz, fields.fidNativeVisualizer);
247 if (v.get()) {
248 v->incStrong((void*)setVisualizer);
249 }
250 if (old != 0) {
251 old->decStrong((void*)setVisualizer);
252 }
253 env->SetLongField(thiz, fields.fidNativeVisualizer, (jlong)v.get());
254 return old;
255 }
256
257 // ----------------------------------------------------------------------------
258 // This function gets some field IDs, which in turn causes class initialization.
259 // It is called from a static block in Visualizer, which won't run until the
260 // first time an instance of this class is used.
261 static void
android_media_visualizer_native_init(JNIEnv * env)262 android_media_visualizer_native_init(JNIEnv *env)
263 {
264
265 ALOGV("android_media_visualizer_native_init");
266
267 fields.clazzEffect = NULL;
268
269 // Get the Visualizer class
270 jclass clazz = env->FindClass(kClassPathName);
271 if (clazz == NULL) {
272 ALOGE("Can't find %s", kClassPathName);
273 return;
274 }
275
276 fields.clazzEffect = (jclass)env->NewGlobalRef(clazz);
277
278 // Get the Visualizer.MeasurementPeakRms class
279 clazz = env->FindClass(kClassPeakRmsPathName);
280 if (clazz == NULL) {
281 ALOGE("Can't find %s", kClassPeakRmsPathName);
282 return;
283 }
284 jclass clazzMeasurementPeakRms = (jclass)env->NewGlobalRef(clazz);
285
286 // Get the postEvent method
287 fields.midPostNativeEvent = env->GetStaticMethodID(
288 fields.clazzEffect,
289 "postEventFromNative", "(Ljava/lang/Object;IIILjava/lang/Object;)V");
290 if (fields.midPostNativeEvent == NULL) {
291 ALOGE("Can't find Visualizer.%s", "postEventFromNative");
292 return;
293 }
294
295 // Get the variables fields
296 // nativeTrackInJavaObj
297 fields.fidNativeVisualizer = env->GetFieldID(
298 fields.clazzEffect,
299 "mNativeVisualizer", "J");
300 if (fields.fidNativeVisualizer == NULL) {
301 ALOGE("Can't find Visualizer.%s", "mNativeVisualizer");
302 return;
303 }
304 // fidJniData;
305 fields.fidJniData = env->GetFieldID(
306 fields.clazzEffect,
307 "mJniData", "J");
308 if (fields.fidJniData == NULL) {
309 ALOGE("Can't find Visualizer.%s", "mJniData");
310 return;
311 }
312 // fidPeak
313 fields.fidPeak = env->GetFieldID(
314 clazzMeasurementPeakRms,
315 "mPeak", "I");
316 if (fields.fidPeak == NULL) {
317 ALOGE("Can't find Visualizer.MeasurementPeakRms.%s", "mPeak");
318 return;
319 }
320 // fidRms
321 fields.fidRms = env->GetFieldID(
322 clazzMeasurementPeakRms,
323 "mRms", "I");
324 if (fields.fidRms == NULL) {
325 ALOGE("Can't find Visualizer.MeasurementPeakRms.%s", "mPeak");
326 return;
327 }
328
329 env->DeleteGlobalRef(clazzMeasurementPeakRms);
330 }
331
android_media_visualizer_effect_callback(int32_t event,void * user,void * info)332 static void android_media_visualizer_effect_callback(int32_t event,
333 void *user,
334 void *info) {
335 if ((event == AudioEffect::EVENT_ERROR) &&
336 (*((status_t*)info) == DEAD_OBJECT)) {
337 VisualizerJniStorage* lpJniStorage = (VisualizerJniStorage*)user;
338 visualizer_callback_cookie* callbackInfo = &lpJniStorage->mCallbackData;
339 JNIEnv *env = AndroidRuntime::getJNIEnv();
340
341 env->CallStaticVoidMethod(
342 callbackInfo->visualizer_class,
343 fields.midPostNativeEvent,
344 callbackInfo->visualizer_ref,
345 NATIVE_EVENT_SERVER_DIED,
346 0, 0, NULL);
347 }
348 }
349
350 static jint
android_media_visualizer_native_setup(JNIEnv * env,jobject thiz,jobject weak_this,jint sessionId,jintArray jId,jstring opPackageName)351 android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
352 jint sessionId, jintArray jId, jstring opPackageName)
353 {
354 ALOGV("android_media_visualizer_native_setup");
355 VisualizerJniStorage* lpJniStorage = NULL;
356 int lStatus = VISUALIZER_ERROR_NO_MEMORY;
357 sp<Visualizer> lpVisualizer;
358 jint* nId = NULL;
359
360 ScopedUtfChars opPackageNameStr(env, opPackageName);
361
362 setVisualizer(env, thiz, 0);
363
364 lpJniStorage = new VisualizerJniStorage();
365 if (lpJniStorage == NULL) {
366 ALOGE("setup: Error creating JNI Storage");
367 goto setup_failure;
368 }
369
370 lpJniStorage->mCallbackData.visualizer_class = (jclass)env->NewGlobalRef(fields.clazzEffect);
371 // we use a weak reference so the Visualizer object can be garbage collected.
372 lpJniStorage->mCallbackData.visualizer_ref = env->NewGlobalRef(weak_this);
373
374 ALOGV("setup: lpJniStorage: %p visualizer_ref %p visualizer_class %p, &mCallbackData %p",
375 lpJniStorage,
376 lpJniStorage->mCallbackData.visualizer_ref,
377 lpJniStorage->mCallbackData.visualizer_class,
378 &lpJniStorage->mCallbackData);
379
380 if (jId == NULL) {
381 ALOGE("setup: NULL java array for id pointer");
382 lStatus = VISUALIZER_ERROR_BAD_VALUE;
383 goto setup_failure;
384 }
385
386 // create the native Visualizer object
387 lpVisualizer = new Visualizer(String16(opPackageNameStr.c_str()),
388 0,
389 android_media_visualizer_effect_callback,
390 lpJniStorage,
391 (audio_session_t) sessionId);
392 if (lpVisualizer == 0) {
393 ALOGE("Error creating Visualizer");
394 goto setup_failure;
395 }
396
397 lStatus = translateError(lpVisualizer->initCheck());
398 if (lStatus != VISUALIZER_SUCCESS && lStatus != VISUALIZER_ERROR_ALREADY_EXISTS) {
399 ALOGE("Visualizer initCheck failed %d", lStatus);
400 goto setup_failure;
401 }
402
403 nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL);
404 if (nId == NULL) {
405 ALOGE("setup: Error retrieving id pointer");
406 lStatus = VISUALIZER_ERROR_BAD_VALUE;
407 goto setup_failure;
408 }
409 nId[0] = lpVisualizer->id();
410 env->ReleasePrimitiveArrayCritical(jId, nId, 0);
411 nId = NULL;
412
413 setVisualizer(env, thiz, lpVisualizer);
414
415 env->SetLongField(thiz, fields.fidJniData, (jlong)lpJniStorage);
416
417 return VISUALIZER_SUCCESS;
418
419 // failures:
420 setup_failure:
421
422 if (nId != NULL) {
423 env->ReleasePrimitiveArrayCritical(jId, nId, 0);
424 }
425
426 if (lpJniStorage) {
427 env->DeleteGlobalRef(lpJniStorage->mCallbackData.visualizer_class);
428 env->DeleteGlobalRef(lpJniStorage->mCallbackData.visualizer_ref);
429 delete lpJniStorage;
430 }
431 env->SetLongField(thiz, fields.fidJniData, 0);
432
433 return (jint) lStatus;
434 }
435
436 // ----------------------------------------------------------------------------
android_media_visualizer_native_release(JNIEnv * env,jobject thiz)437 static void android_media_visualizer_native_release(JNIEnv *env, jobject thiz) {
438 sp<Visualizer> lpVisualizer = setVisualizer(env, thiz, 0);
439 if (lpVisualizer == 0) {
440 return;
441 }
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