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
31using 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// ----------------------------------------------------------------------------
47static const char* const kClassPathName = "android/media/audiofx/Visualizer";
48static const char* const kClassPeakRmsPathName =
49        "android/media/audiofx/Visualizer$MeasurementPeakRms";
50
51struct 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};
60static fields_t fields;
61
62struct 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
77    visualizer_callback_cookie() {
78        waveform_data = NULL;
79        fft_data = NULL;
80    }
81
82    ~visualizer_callback_cookie() {
83        cleanupBuffers();
84    }
85
86    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// ----------------------------------------------------------------------------
105class VisualizerJniStorage {
106    public:
107        visualizer_callback_cookie mCallbackData;
108
109    VisualizerJniStorage() {
110    }
111
112    ~VisualizerJniStorage() {
113    }
114};
115
116
117static 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
138static Mutex sLock;
139
140// ----------------------------------------------------------------------------
141static 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
161static 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
233static 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
241static 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.
261static void
262android_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
332static 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
350static jint
351android_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:
420setup_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// ----------------------------------------------------------------------------
437static 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
460static 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// ----------------------------------------------------------------------------
466static jint
467android_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
487static jboolean
488android_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
502static jintArray
503android_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
514static jint
515android_media_visualizer_native_getMaxCaptureRate(JNIEnv* /* env */, jobject /* thiz */)
516{
517    return (jint) Visualizer::getMaxCaptureRate();
518}
519
520static jint
521android_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
531static jint
532android_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
541static jint
542android_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
552static jint
553android_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
562static jint
563android_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
572static jint
573android_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
582static jint
583android_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
592static jint
593android_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
610static jint
611android_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
629static jint
630android_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
648static jint
649android_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
681static 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
707int register_android_media_visualizer(JNIEnv *env)
708{
709    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
710}
711
712