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