• 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 <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 <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                 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     { //limit scope so that lpVisualizer is deleted before JNI storage data.
439         sp<Visualizer> lpVisualizer = setVisualizer(env, thiz, 0);
440         if (lpVisualizer == 0) {
441             return;
442         }
443     }
444     // delete the JNI data
445     VisualizerJniStorage* lpJniStorage =
446         (VisualizerJniStorage *)env->GetLongField(thiz, fields.fidJniData);
447 
448     // reset the native resources in the Java object so any attempt to access
449     // them after a call to release fails.
450     env->SetLongField(thiz, fields.fidJniData, 0);
451 
452     if (lpJniStorage) {
453         ALOGV("deleting pJniStorage: %p\n", lpJniStorage);
454         env->DeleteGlobalRef(lpJniStorage->mCallbackData.visualizer_class);
455         env->DeleteGlobalRef(lpJniStorage->mCallbackData.visualizer_ref);
456         delete lpJniStorage;
457     }
458 }
459 
android_media_visualizer_native_finalize(JNIEnv * env,jobject thiz)460 static void android_media_visualizer_native_finalize(JNIEnv *env,  jobject thiz) {
461     ALOGV("android_media_visualizer_native_finalize jobject: %p\n", thiz);
462     android_media_visualizer_native_release(env, thiz);
463 }
464 
465 // ----------------------------------------------------------------------------
466 static jint
android_media_visualizer_native_setEnabled(JNIEnv * env,jobject thiz,jboolean enabled)467 android_media_visualizer_native_setEnabled(JNIEnv *env, jobject thiz, jboolean enabled)
468 {
469     sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
470     if (lpVisualizer == 0) {
471         return VISUALIZER_ERROR_NO_INIT;
472     }
473 
474     jint retVal = translateError(lpVisualizer->setEnabled(enabled));
475 
476     if (!enabled) {
477         VisualizerJniStorage* lpJniStorage = (VisualizerJniStorage *)env->GetLongField(
478             thiz, fields.fidJniData);
479 
480         if (NULL != lpJniStorage)
481             lpJniStorage->mCallbackData.cleanupBuffers();
482     }
483 
484     return retVal;
485 }
486 
487 static jboolean
android_media_visualizer_native_getEnabled(JNIEnv * env,jobject thiz)488 android_media_visualizer_native_getEnabled(JNIEnv *env, jobject thiz)
489 {
490     sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
491     if (lpVisualizer == 0) {
492         return JNI_FALSE;
493     }
494 
495     if (lpVisualizer->getEnabled()) {
496         return JNI_TRUE;
497     } else {
498         return JNI_FALSE;
499     }
500 }
501 
502 static jintArray
android_media_visualizer_native_getCaptureSizeRange(JNIEnv * env,jobject)503 android_media_visualizer_native_getCaptureSizeRange(JNIEnv *env, jobject /* thiz */)
504 {
505     jintArray jRange = env->NewIntArray(2);
506     jint *nRange = env->GetIntArrayElements(jRange, NULL);
507     nRange[0] = Visualizer::getMinCaptureSize();
508     nRange[1] = Visualizer::getMaxCaptureSize();
509     ALOGV("getCaptureSizeRange() min %d max %d", nRange[0], nRange[1]);
510     env->ReleaseIntArrayElements(jRange, nRange, 0);
511     return jRange;
512 }
513 
514 static jint
android_media_visualizer_native_getMaxCaptureRate(JNIEnv *,jobject)515 android_media_visualizer_native_getMaxCaptureRate(JNIEnv* /* env */, jobject /* thiz */)
516 {
517     return (jint) Visualizer::getMaxCaptureRate();
518 }
519 
520 static jint
android_media_visualizer_native_setCaptureSize(JNIEnv * env,jobject thiz,jint size)521 android_media_visualizer_native_setCaptureSize(JNIEnv *env, jobject thiz, jint size)
522 {
523     sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
524     if (lpVisualizer == 0) {
525         return VISUALIZER_ERROR_NO_INIT;
526     }
527 
528     return translateError(lpVisualizer->setCaptureSize(size));
529 }
530 
531 static jint
android_media_visualizer_native_getCaptureSize(JNIEnv * env,jobject thiz)532 android_media_visualizer_native_getCaptureSize(JNIEnv *env, jobject thiz)
533 {
534     sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
535     if (lpVisualizer == 0) {
536         return -1;
537     }
538     return (jint) lpVisualizer->getCaptureSize();
539 }
540 
541 static jint
android_media_visualizer_native_setScalingMode(JNIEnv * env,jobject thiz,jint mode)542 android_media_visualizer_native_setScalingMode(JNIEnv *env, jobject thiz, jint mode)
543 {
544     sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
545     if (lpVisualizer == 0) {
546         return VISUALIZER_ERROR_NO_INIT;
547     }
548 
549     return translateError(lpVisualizer->setScalingMode(mode));
550 }
551 
552 static jint
android_media_visualizer_native_getScalingMode(JNIEnv * env,jobject thiz)553 android_media_visualizer_native_getScalingMode(JNIEnv *env, jobject thiz)
554 {
555     sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
556     if (lpVisualizer == 0) {
557         return -1;
558     }
559     return (jint)lpVisualizer->getScalingMode();
560 }
561 
562 static jint
android_media_visualizer_native_setMeasurementMode(JNIEnv * env,jobject thiz,jint mode)563 android_media_visualizer_native_setMeasurementMode(JNIEnv *env, jobject thiz, jint mode)
564 {
565     sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
566     if (lpVisualizer == 0) {
567         return VISUALIZER_ERROR_NO_INIT;
568     }
569     return translateError(lpVisualizer->setMeasurementMode(mode));
570 }
571 
572 static jint
android_media_visualizer_native_getMeasurementMode(JNIEnv * env,jobject thiz)573 android_media_visualizer_native_getMeasurementMode(JNIEnv *env, jobject thiz)
574 {
575     sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
576     if (lpVisualizer == 0) {
577         return MEASUREMENT_MODE_NONE;
578     }
579     return lpVisualizer->getMeasurementMode();
580 }
581 
582 static jint
android_media_visualizer_native_getSamplingRate(JNIEnv * env,jobject thiz)583 android_media_visualizer_native_getSamplingRate(JNIEnv *env, jobject thiz)
584 {
585     sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
586     if (lpVisualizer == 0) {
587         return -1;
588     }
589     return (jint) lpVisualizer->getSamplingRate();
590 }
591 
592 static jint
android_media_visualizer_native_getWaveForm(JNIEnv * env,jobject thiz,jbyteArray jWaveform)593 android_media_visualizer_native_getWaveForm(JNIEnv *env, jobject thiz, jbyteArray jWaveform)
594 {
595     sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
596     if (lpVisualizer == 0) {
597         return VISUALIZER_ERROR_NO_INIT;
598     }
599 
600     jbyte* nWaveform = (jbyte *) env->GetPrimitiveArrayCritical(jWaveform, NULL);
601     if (nWaveform == NULL) {
602         return VISUALIZER_ERROR_NO_MEMORY;
603     }
604     jint status = translateError(lpVisualizer->getWaveForm((uint8_t *)nWaveform));
605 
606     env->ReleasePrimitiveArrayCritical(jWaveform, nWaveform, 0);
607     return status;
608 }
609 
610 static jint
android_media_visualizer_native_getFft(JNIEnv * env,jobject thiz,jbyteArray jFft)611 android_media_visualizer_native_getFft(JNIEnv *env, jobject thiz, jbyteArray jFft)
612 {
613     sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
614     if (lpVisualizer == 0) {
615         return VISUALIZER_ERROR_NO_INIT;
616     }
617 
618     jbyte* nFft = (jbyte *) env->GetPrimitiveArrayCritical(jFft, NULL);
619     if (nFft == NULL) {
620         return VISUALIZER_ERROR_NO_MEMORY;
621     }
622     jint status = translateError(lpVisualizer->getFft((uint8_t *)nFft));
623 
624     env->ReleasePrimitiveArrayCritical(jFft, nFft, 0);
625 
626     return status;
627 }
628 
629 static jint
android_media_visualizer_native_getPeakRms(JNIEnv * env,jobject thiz,jobject jPeakRmsObj)630 android_media_visualizer_native_getPeakRms(JNIEnv *env, jobject thiz, jobject jPeakRmsObj)
631 {
632     sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
633     if (lpVisualizer == 0) {
634         return VISUALIZER_ERROR_NO_INIT;
635     }
636     int32_t measurements[2];
637     jint status = translateError(
638                 lpVisualizer->getIntMeasurements(MEASUREMENT_MODE_PEAK_RMS,
639                         2, measurements));
640     if (status == VISUALIZER_SUCCESS) {
641         // measurement worked, write the values to the java object
642         env->SetIntField(jPeakRmsObj, fields.fidPeak, measurements[MEASUREMENT_IDX_PEAK]);
643         env->SetIntField(jPeakRmsObj, fields.fidRms, measurements[MEASUREMENT_IDX_RMS]);
644     }
645     return status;
646 }
647 
648 static jint
android_media_setPeriodicCapture(JNIEnv * env,jobject thiz,jint rate,jboolean jWaveform,jboolean jFft)649 android_media_setPeriodicCapture(JNIEnv *env, jobject thiz, jint rate, jboolean jWaveform, jboolean jFft)
650 {
651     sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
652     if (lpVisualizer == 0) {
653         return VISUALIZER_ERROR_NO_INIT;
654     }
655     VisualizerJniStorage* lpJniStorage = (VisualizerJniStorage *)env->GetLongField(thiz,
656             fields.fidJniData);
657     if (lpJniStorage == NULL) {
658         return VISUALIZER_ERROR_NO_INIT;
659     }
660 
661     ALOGV("setPeriodicCapture: rate %d, jWaveform %d jFft %d",
662             rate,
663             jWaveform,
664             jFft);
665 
666     uint32_t flags = Visualizer::CAPTURE_CALL_JAVA;
667     if (jWaveform) flags |= Visualizer::CAPTURE_WAVEFORM;
668     if (jFft) flags |= Visualizer::CAPTURE_FFT;
669     Visualizer::capture_cbk_t cbk = captureCallback;
670     if (!jWaveform && !jFft) cbk = NULL;
671 
672     return translateError(lpVisualizer->setCaptureCallBack(cbk,
673                                                 &lpJniStorage->mCallbackData,
674                                                 flags,
675                                                 rate));
676 }
677 
678 // ----------------------------------------------------------------------------
679 
680 // Dalvik VM type signatures
681 static const JNINativeMethod gMethods[] = {
682     {"native_init",            "()V",     (void *)android_media_visualizer_native_init},
683     {"native_setup",           "(Ljava/lang/Object;I[ILjava/lang/String;)I",
684                                           (void *)android_media_visualizer_native_setup},
685     {"native_finalize",          "()V",   (void *)android_media_visualizer_native_finalize},
686     {"native_release",           "()V",   (void *)android_media_visualizer_native_release},
687     {"native_setEnabled",        "(Z)I",  (void *)android_media_visualizer_native_setEnabled},
688     {"native_getEnabled",        "()Z",   (void *)android_media_visualizer_native_getEnabled},
689     {"getCaptureSizeRange",      "()[I",  (void *)android_media_visualizer_native_getCaptureSizeRange},
690     {"getMaxCaptureRate",        "()I",   (void *)android_media_visualizer_native_getMaxCaptureRate},
691     {"native_setCaptureSize",    "(I)I",  (void *)android_media_visualizer_native_setCaptureSize},
692     {"native_getCaptureSize",    "()I",   (void *)android_media_visualizer_native_getCaptureSize},
693     {"native_setScalingMode",    "(I)I",  (void *)android_media_visualizer_native_setScalingMode},
694     {"native_getScalingMode",    "()I",   (void *)android_media_visualizer_native_getScalingMode},
695     {"native_setMeasurementMode","(I)I",  (void *)android_media_visualizer_native_setMeasurementMode},
696     {"native_getMeasurementMode","()I",   (void *)android_media_visualizer_native_getMeasurementMode},
697     {"native_getSamplingRate",   "()I",   (void *)android_media_visualizer_native_getSamplingRate},
698     {"native_getWaveForm",       "([B)I", (void *)android_media_visualizer_native_getWaveForm},
699     {"native_getFft",            "([B)I", (void *)android_media_visualizer_native_getFft},
700     {"native_getPeakRms",      "(Landroid/media/audiofx/Visualizer$MeasurementPeakRms;)I",
701                                           (void *)android_media_visualizer_native_getPeakRms},
702     {"native_setPeriodicCapture","(IZZ)I",(void *)android_media_setPeriodicCapture},
703 };
704 
705 // ----------------------------------------------------------------------------
706 
register_android_media_visualizer(JNIEnv * env)707 int register_android_media_visualizer(JNIEnv *env)
708 {
709     return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
710 }
711 
712