blob: 0645543d4a74af05fe93a52d1055c47226af6d30 [file] [log] [blame]
Eric Laurentdf9b81c2010-07-02 08:12:41 -07001/*
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>
John Grossman449725f2012-01-10 12:17:03 -080026#include <utils/threads.h>
Eric Laurentdf9b81c2010-07-02 08:12:41 -070027#include "media/Visualizer.h"
28
Svet Ganovfa5ecdc2015-04-28 12:03:28 -070029#include <ScopedUtfChars.h>
30
Eric Laurentdf9b81c2010-07-02 08:12:41 -070031using namespace android;
32
33#define VISUALIZER_SUCCESS 0
Chih-Hung Hsieh0ca16ef2016-05-19 15:14:54 -070034#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)
Eric Laurentdf9b81c2010-07-02 08:12:41 -070041
42#define NATIVE_EVENT_PCM_CAPTURE 0
43#define NATIVE_EVENT_FFT_CAPTURE 1
John Grossman3540a012012-01-11 12:23:42 -080044#define NATIVE_EVENT_SERVER_DIED 2
Eric Laurentdf9b81c2010-07-02 08:12:41 -070045
46// ----------------------------------------------------------------------------
Eric Laurent1a5149e2010-09-21 18:18:20 -070047static const char* const kClassPathName = "android/media/audiofx/Visualizer";
Jean-Michel Trivibadca262013-09-20 10:48:55 -070048static const char* const kClassPeakRmsPathName =
49 "android/media/audiofx/Visualizer$MeasurementPeakRms";
Eric Laurentdf9b81c2010-07-02 08:12:41 -070050
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
Jean-Michel Trivibadca262013-09-20 10:48:55 -070057 jfieldID fidPeak; // to access Visualizer.MeasurementPeakRms.mPeak
58 jfieldID fidRms; // to access Visualizer.MeasurementPeakRms.mRms
Eric Laurentdf9b81c2010-07-02 08:12:41 -070059};
60static fields_t fields;
61
62struct visualizer_callback_cookie {
63 jclass visualizer_class; // Visualizer class
64 jobject visualizer_ref; // Visualizer object instance
John Grossman449725f2012-01-10 12:17:03 -080065
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 }
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700102 };
103
104// ----------------------------------------------------------------------------
Eric Laurent76f81332015-06-04 16:20:47 -0700105class VisualizerJniStorage {
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700106 public:
107 visualizer_callback_cookie mCallbackData;
108
Eric Laurent76f81332015-06-04 16:20:47 -0700109 VisualizerJniStorage() {
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700110 }
111
Eric Laurent76f81332015-06-04 16:20:47 -0700112 ~VisualizerJniStorage() {
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700113 }
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700114};
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
Eric Laurent76f81332015-06-04 16:20:47 -0700138static Mutex sLock;
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700139
140// ----------------------------------------------------------------------------
John Grossman449725f2012-01-10 12:17:03 -0800141static 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
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700161static 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
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700168 visualizer_callback_cookie *callbackInfo = (visualizer_callback_cookie *)user;
169 JNIEnv *env = AndroidRuntime::getJNIEnv();
Mike J. Chen67a12182013-04-26 12:34:52 -0700170
171 if (!user || !env) {
172 ALOGW("captureCallback error user %p, env %p", user, env);
173 return;
174 }
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700175
Steve Block71f2cf12011-10-20 11:56:00 +0100176 ALOGV("captureCallback: callbackInfo %p, visualizer_ref %p visualizer_class %p",
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700177 callbackInfo,
178 callbackInfo->visualizer_ref,
179 callbackInfo->visualizer_class);
180
Mike J. Chen67a12182013-04-26 12:34:52 -0700181 AutoMutex lock(&callbackInfo->callback_data_lock);
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700182
183 if (waveformSize != 0 && waveform != NULL) {
John Grossman449725f2012-01-10 12:17:03 -0800184 jbyteArray jArray;
185
186 ensureArraySize(env, &callbackInfo->waveform_data, waveformSize);
187 jArray = callbackInfo->waveform_data;
188
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700189 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) {
John Grossman449725f2012-01-10 12:17:03 -0800205 jbyteArray jArray;
206
207 ensureArraySize(env, &callbackInfo->fft_data, fftSize);
208 jArray = callbackInfo->fft_data;
209
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700210 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);
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700222 }
223 }
224
225 if (env->ExceptionCheck()) {
226 env->ExceptionDescribe();
227 env->ExceptionClear();
228 }
229}
230
Eric Laurent76f81332015-06-04 16:20:47 -0700231// ----------------------------------------------------------------------------
232
233static sp<Visualizer> getVisualizer(JNIEnv* env, jobject thiz)
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700234{
Eric Laurent76f81332015-06-04 16:20:47 -0700235 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);
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700249 }
Eric Laurent76f81332015-06-04 16:20:47 -0700250 if (old != 0) {
251 old->decStrong((void*)setVisualizer);
252 }
253 env->SetLongField(thiz, fields.fidNativeVisualizer, (jlong)v.get());
254 return old;
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700255}
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
Steve Block71f2cf12011-10-20 11:56:00 +0100265 ALOGV("android_media_visualizer_native_init");
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700266
267 fields.clazzEffect = NULL;
268
269 // Get the Visualizer class
270 jclass clazz = env->FindClass(kClassPathName);
271 if (clazz == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000272 ALOGE("Can't find %s", kClassPathName);
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700273 return;
274 }
275
276 fields.clazzEffect = (jclass)env->NewGlobalRef(clazz);
277
Jean-Michel Trivibadca262013-09-20 10:48:55 -0700278 // 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
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700286 // 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) {
Steve Block3762c312012-01-06 19:20:56 +0000291 ALOGE("Can't find Visualizer.%s", "postEventFromNative");
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700292 return;
293 }
294
295 // Get the variables fields
296 // nativeTrackInJavaObj
297 fields.fidNativeVisualizer = env->GetFieldID(
298 fields.clazzEffect,
Ashok Bhatea7861c2013-12-17 12:42:00 +0000299 "mNativeVisualizer", "J");
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700300 if (fields.fidNativeVisualizer == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000301 ALOGE("Can't find Visualizer.%s", "mNativeVisualizer");
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700302 return;
303 }
304 // fidJniData;
305 fields.fidJniData = env->GetFieldID(
306 fields.clazzEffect,
Ashok Bhatea7861c2013-12-17 12:42:00 +0000307 "mJniData", "J");
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700308 if (fields.fidJniData == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000309 ALOGE("Can't find Visualizer.%s", "mJniData");
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700310 return;
311 }
Jean-Michel Trivibadca262013-09-20 10:48:55 -0700312 // 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 }
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700328
Jean-Michel Trivibadca262013-09-20 10:48:55 -0700329 env->DeleteGlobalRef(clazzMeasurementPeakRms);
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700330}
331
John Grossman3540a012012-01-11 12:23:42 -0800332static 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)) {
Eric Laurent76f81332015-06-04 16:20:47 -0700337 VisualizerJniStorage* lpJniStorage = (VisualizerJniStorage*)user;
John Grossman3540a012012-01-11 12:23:42 -0800338 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,
Haitao Feng8bd6a202014-12-31 13:48:08 +0800346 0, 0, NULL);
John Grossman3540a012012-01-11 12:23:42 -0800347 }
348}
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700349
350static jint
351android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
Svet Ganovfa5ecdc2015-04-28 12:03:28 -0700352 jint sessionId, jintArray jId, jstring opPackageName)
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700353{
Steve Block71f2cf12011-10-20 11:56:00 +0100354 ALOGV("android_media_visualizer_native_setup");
Eric Laurent76f81332015-06-04 16:20:47 -0700355 VisualizerJniStorage* lpJniStorage = NULL;
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700356 int lStatus = VISUALIZER_ERROR_NO_MEMORY;
Eric Laurent76f81332015-06-04 16:20:47 -0700357 sp<Visualizer> lpVisualizer;
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700358 jint* nId = NULL;
359
Svet Ganovfa5ecdc2015-04-28 12:03:28 -0700360 ScopedUtfChars opPackageNameStr(env, opPackageName);
361
Eric Laurent76f81332015-06-04 16:20:47 -0700362 setVisualizer(env, thiz, 0);
363
364 lpJniStorage = new VisualizerJniStorage();
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700365 if (lpJniStorage == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000366 ALOGE("setup: Error creating JNI Storage");
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700367 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
Steve Block71f2cf12011-10-20 11:56:00 +0100374 ALOGV("setup: lpJniStorage: %p visualizer_ref %p visualizer_class %p, &mCallbackData %p",
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700375 lpJniStorage,
376 lpJniStorage->mCallbackData.visualizer_ref,
377 lpJniStorage->mCallbackData.visualizer_class,
378 &lpJniStorage->mCallbackData);
379
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700380 if (jId == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000381 ALOGE("setup: NULL java array for id pointer");
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700382 lStatus = VISUALIZER_ERROR_BAD_VALUE;
383 goto setup_failure;
384 }
385
386 // create the native Visualizer object
Svet Ganovfa5ecdc2015-04-28 12:03:28 -0700387 lpVisualizer = new Visualizer(String16(opPackageNameStr.c_str()),
388 0,
John Grossman3540a012012-01-11 12:23:42 -0800389 android_media_visualizer_effect_callback,
390 lpJniStorage,
Glenn Kasten33b84042016-03-08 12:02:55 -0800391 (audio_session_t) sessionId);
Eric Laurent76f81332015-06-04 16:20:47 -0700392 if (lpVisualizer == 0) {
Steve Block3762c312012-01-06 19:20:56 +0000393 ALOGE("Error creating Visualizer");
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700394 goto setup_failure;
395 }
396
397 lStatus = translateError(lpVisualizer->initCheck());
398 if (lStatus != VISUALIZER_SUCCESS && lStatus != VISUALIZER_ERROR_ALREADY_EXISTS) {
Steve Block3762c312012-01-06 19:20:56 +0000399 ALOGE("Visualizer initCheck failed %d", lStatus);
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700400 goto setup_failure;
401 }
402
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700403 nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL);
404 if (nId == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000405 ALOGE("setup: Error retrieving id pointer");
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700406 lStatus = VISUALIZER_ERROR_BAD_VALUE;
407 goto setup_failure;
408 }
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700409 nId[0] = lpVisualizer->id();
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700410 env->ReleasePrimitiveArrayCritical(jId, nId, 0);
411 nId = NULL;
412
Eric Laurent76f81332015-06-04 16:20:47 -0700413 setVisualizer(env, thiz, lpVisualizer);
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700414
Ashok Bhatea7861c2013-12-17 12:42:00 +0000415 env->SetLongField(thiz, fields.fidJniData, (jlong)lpJniStorage);
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700416
417 return VISUALIZER_SUCCESS;
418
419 // failures:
420setup_failure:
421
422 if (nId != NULL) {
423 env->ReleasePrimitiveArrayCritical(jId, nId, 0);
424 }
425
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700426 if (lpJniStorage) {
Eric Laurent76f81332015-06-04 16:20:47 -0700427 env->DeleteGlobalRef(lpJniStorage->mCallbackData.visualizer_class);
428 env->DeleteGlobalRef(lpJniStorage->mCallbackData.visualizer_ref);
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700429 delete lpJniStorage;
430 }
Ashok Bhatea7861c2013-12-17 12:42:00 +0000431 env->SetLongField(thiz, fields.fidJniData, 0);
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700432
Ashok Bhatea7861c2013-12-17 12:42:00 +0000433 return (jint) lStatus;
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700434}
435
436// ----------------------------------------------------------------------------
Eric Laurent76f81332015-06-04 16:20:47 -0700437static void android_media_visualizer_native_release(JNIEnv *env, jobject thiz) {
rago8dc9afa2016-09-14 17:33:45 -0700438 { //limit scope so that lpVisualizer is deleted before JNI storage data.
ganxiaolin7b9f5be2016-06-06 11:09:05 +0800439 sp<Visualizer> lpVisualizer = setVisualizer(env, thiz, 0);
440 if (lpVisualizer == 0) {
441 return;
442 }
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700443 }
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700444 // delete the JNI data
Eric Laurent76f81332015-06-04 16:20:47 -0700445 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
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700452 if (lpJniStorage) {
Ashok Bhatea7861c2013-12-17 12:42:00 +0000453 ALOGV("deleting pJniStorage: %p\n", lpJniStorage);
Eric Laurent07799982015-06-19 09:13:02 -0700454 env->DeleteGlobalRef(lpJniStorage->mCallbackData.visualizer_class);
455 env->DeleteGlobalRef(lpJniStorage->mCallbackData.visualizer_ref);
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700456 delete lpJniStorage;
457 }
458}
459
Eric Laurent76f81332015-06-04 16:20:47 -0700460static 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);
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700463}
464
Eric Laurent76f81332015-06-04 16:20:47 -0700465// ----------------------------------------------------------------------------
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700466static jint
467android_media_visualizer_native_setEnabled(JNIEnv *env, jobject thiz, jboolean enabled)
468{
Eric Laurent76f81332015-06-04 16:20:47 -0700469 sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
470 if (lpVisualizer == 0) {
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700471 return VISUALIZER_ERROR_NO_INIT;
472 }
473
John Grossman449725f2012-01-10 12:17:03 -0800474 jint retVal = translateError(lpVisualizer->setEnabled(enabled));
475
476 if (!enabled) {
Eric Laurent76f81332015-06-04 16:20:47 -0700477 VisualizerJniStorage* lpJniStorage = (VisualizerJniStorage *)env->GetLongField(
John Grossman449725f2012-01-10 12:17:03 -0800478 thiz, fields.fidJniData);
479
480 if (NULL != lpJniStorage)
481 lpJniStorage->mCallbackData.cleanupBuffers();
482 }
483
484 return retVal;
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700485}
486
487static jboolean
488android_media_visualizer_native_getEnabled(JNIEnv *env, jobject thiz)
489{
Eric Laurent76f81332015-06-04 16:20:47 -0700490 sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
491 if (lpVisualizer == 0) {
Ashok Bhatea7861c2013-12-17 12:42:00 +0000492 return JNI_FALSE;
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700493 }
494
Ashok Bhatea7861c2013-12-17 12:42:00 +0000495 if (lpVisualizer->getEnabled()) {
496 return JNI_TRUE;
497 } else {
498 return JNI_FALSE;
499 }
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700500}
501
502static jintArray
Andreas Gampe5a15d0d2014-11-10 18:19:40 -0800503android_media_visualizer_native_getCaptureSizeRange(JNIEnv *env, jobject /* thiz */)
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700504{
505 jintArray jRange = env->NewIntArray(2);
506 jint *nRange = env->GetIntArrayElements(jRange, NULL);
507 nRange[0] = Visualizer::getMinCaptureSize();
508 nRange[1] = Visualizer::getMaxCaptureSize();
Steve Block71f2cf12011-10-20 11:56:00 +0100509 ALOGV("getCaptureSizeRange() min %d max %d", nRange[0], nRange[1]);
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700510 env->ReleaseIntArrayElements(jRange, nRange, 0);
511 return jRange;
512}
513
514static jint
Andreas Gampe5a15d0d2014-11-10 18:19:40 -0800515android_media_visualizer_native_getMaxCaptureRate(JNIEnv* /* env */, jobject /* thiz */)
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700516{
Ashok Bhatea7861c2013-12-17 12:42:00 +0000517 return (jint) Visualizer::getMaxCaptureRate();
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700518}
519
520static jint
521android_media_visualizer_native_setCaptureSize(JNIEnv *env, jobject thiz, jint size)
522{
Eric Laurent76f81332015-06-04 16:20:47 -0700523 sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
524 if (lpVisualizer == 0) {
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700525 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{
Eric Laurent76f81332015-06-04 16:20:47 -0700534 sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
535 if (lpVisualizer == 0) {
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700536 return -1;
537 }
Ashok Bhatea7861c2013-12-17 12:42:00 +0000538 return (jint) lpVisualizer->getCaptureSize();
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700539}
540
541static jint
Jean-Michel Trivie1123e72012-04-15 17:22:01 -0700542android_media_visualizer_native_setScalingMode(JNIEnv *env, jobject thiz, jint mode)
543{
Eric Laurent76f81332015-06-04 16:20:47 -0700544 sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
545 if (lpVisualizer == 0) {
Jean-Michel Trivie1123e72012-04-15 17:22:01 -0700546 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{
Eric Laurent76f81332015-06-04 16:20:47 -0700555 sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
556 if (lpVisualizer == 0) {
Jean-Michel Trivie1123e72012-04-15 17:22:01 -0700557 return -1;
558 }
Ashok Bhatea7861c2013-12-17 12:42:00 +0000559 return (jint)lpVisualizer->getScalingMode();
Jean-Michel Trivie1123e72012-04-15 17:22:01 -0700560}
561
562static jint
Jean-Michel Trivibadca262013-09-20 10:48:55 -0700563android_media_visualizer_native_setMeasurementMode(JNIEnv *env, jobject thiz, jint mode)
564{
Eric Laurent76f81332015-06-04 16:20:47 -0700565 sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
566 if (lpVisualizer == 0) {
Jean-Michel Trivibadca262013-09-20 10:48:55 -0700567 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{
Eric Laurent76f81332015-06-04 16:20:47 -0700575 sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
576 if (lpVisualizer == 0) {
Jean-Michel Trivibadca262013-09-20 10:48:55 -0700577 return MEASUREMENT_MODE_NONE;
578 }
579 return lpVisualizer->getMeasurementMode();
580}
581
582static jint
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700583android_media_visualizer_native_getSamplingRate(JNIEnv *env, jobject thiz)
584{
Eric Laurent76f81332015-06-04 16:20:47 -0700585 sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
586 if (lpVisualizer == 0) {
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700587 return -1;
588 }
Ashok Bhatea7861c2013-12-17 12:42:00 +0000589 return (jint) lpVisualizer->getSamplingRate();
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700590}
591
592static jint
593android_media_visualizer_native_getWaveForm(JNIEnv *env, jobject thiz, jbyteArray jWaveform)
594{
Eric Laurent76f81332015-06-04 16:20:47 -0700595 sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
596 if (lpVisualizer == 0) {
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700597 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);
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700607 return status;
608}
609
610static jint
611android_media_visualizer_native_getFft(JNIEnv *env, jobject thiz, jbyteArray jFft)
612{
Eric Laurent76f81332015-06-04 16:20:47 -0700613 sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
614 if (lpVisualizer == 0) {
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700615 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
Jean-Michel Trivibadca262013-09-20 10:48:55 -0700630android_media_visualizer_native_getPeakRms(JNIEnv *env, jobject thiz, jobject jPeakRmsObj)
631{
Eric Laurent76f81332015-06-04 16:20:47 -0700632 sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
633 if (lpVisualizer == 0) {
Jean-Michel Trivibadca262013-09-20 10:48:55 -0700634 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
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700649android_media_setPeriodicCapture(JNIEnv *env, jobject thiz, jint rate, jboolean jWaveform, jboolean jFft)
650{
Eric Laurent76f81332015-06-04 16:20:47 -0700651 sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
652 if (lpVisualizer == 0) {
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700653 return VISUALIZER_ERROR_NO_INIT;
654 }
Eric Laurent76f81332015-06-04 16:20:47 -0700655 VisualizerJniStorage* lpJniStorage = (VisualizerJniStorage *)env->GetLongField(thiz,
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700656 fields.fidJniData);
657 if (lpJniStorage == NULL) {
658 return VISUALIZER_ERROR_NO_INIT;
659 }
660
Steve Block71f2cf12011-10-20 11:56:00 +0100661 ALOGV("setPeriodicCapture: rate %d, jWaveform %d jFft %d",
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700662 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
Daniel Micay76f6a862015-09-19 17:31:01 -0400681static const JNINativeMethod gMethods[] = {
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700682 {"native_init", "()V", (void *)android_media_visualizer_native_init},
Svet Ganovfa5ecdc2015-04-28 12:03:28 -0700683 {"native_setup", "(Ljava/lang/Object;I[ILjava/lang/String;)I",
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700684 (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},
Jean-Michel Trivie1123e72012-04-15 17:22:01 -0700693 {"native_setScalingMode", "(I)I", (void *)android_media_visualizer_native_setScalingMode},
694 {"native_getScalingMode", "()I", (void *)android_media_visualizer_native_getScalingMode},
Jean-Michel Trivibadca262013-09-20 10:48:55 -0700695 {"native_setMeasurementMode","(I)I", (void *)android_media_visualizer_native_setMeasurementMode},
696 {"native_getMeasurementMode","()I", (void *)android_media_visualizer_native_getMeasurementMode},
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700697 {"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},
Jean-Michel Trivibadca262013-09-20 10:48:55 -0700700 {"native_getPeakRms", "(Landroid/media/audiofx/Visualizer$MeasurementPeakRms;)I",
701 (void *)android_media_visualizer_native_getPeakRms},
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700702 {"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