blob: be37aa8317e76b4907305d44548fab5172f8a36e [file] [log] [blame]
Eric Laurent948235c2010-06-09 00:17:29 -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 "AudioEffects-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 "media/AudioEffect.h"
27
28using namespace android;
29
30#define AUDIOEFFECT_SUCCESS 0
31#define AUDIOEFFECT_ERROR -1
32#define AUDIOEFFECT_ERROR_ALREADY_EXISTS -2
33#define AUDIOEFFECT_ERROR_NO_INIT -3
34#define AUDIOEFFECT_ERROR_BAD_VALUE -4
35#define AUDIOEFFECT_ERROR_INVALID_OPERATION -5
36#define AUDIOEFFECT_ERROR_NO_MEMORY -6
37#define AUDIOEFFECT_ERROR_DEAD_OBJECT -7
38
39// ----------------------------------------------------------------------------
Eric Laurent1a5149e2010-09-21 18:18:20 -070040static const char* const kClassPathName = "android/media/audiofx/AudioEffect";
Eric Laurent948235c2010-06-09 00:17:29 -070041
42struct fields_t {
43 // these fields provide access from C++ to the...
44 jclass clazzEffect; // AudioEffect class
45 jmethodID midPostNativeEvent; // event post callback method
46 jfieldID fidNativeAudioEffect; // stores in Java the native AudioEffect object
47 jfieldID fidJniData; // stores in Java additional resources used by the native AudioEffect
48 jclass clazzDesc; // AudioEffect.Descriptor class
49 jmethodID midDescCstor; // AudioEffect.Descriptor class constructor
50};
51static fields_t fields;
52
53struct effect_callback_cookie {
54 jclass audioEffect_class; // AudioEffect class
55 jobject audioEffect_ref; // AudioEffect object instance
56 };
57
58// ----------------------------------------------------------------------------
59class AudioEffectJniStorage {
60 public:
61 effect_callback_cookie mCallbackData;
62
63 AudioEffectJniStorage() {
64 }
65
66 ~AudioEffectJniStorage() {
67 }
68
69};
70
71
72static jint translateError(int code) {
73 switch(code) {
74 case NO_ERROR:
75 return AUDIOEFFECT_SUCCESS;
76 case ALREADY_EXISTS:
77 return AUDIOEFFECT_ERROR_ALREADY_EXISTS;
78 case NO_INIT:
79 return AUDIOEFFECT_ERROR_NO_INIT;
80 case BAD_VALUE:
81 return AUDIOEFFECT_ERROR_BAD_VALUE;
82 case INVALID_OPERATION:
83 return AUDIOEFFECT_ERROR_INVALID_OPERATION;
84 case NO_MEMORY:
85 return AUDIOEFFECT_ERROR_NO_MEMORY;
86 case DEAD_OBJECT:
87 return AUDIOEFFECT_ERROR_DEAD_OBJECT;
88 default:
89 return AUDIOEFFECT_ERROR;
90 }
91}
92
93
94// ----------------------------------------------------------------------------
95static void effectCallback(int event, void* user, void *info) {
96
97 effect_param_t *p;
98 int arg1 = 0;
99 int arg2 = 0;
100 jobject obj = NULL;
101 jbyteArray array = NULL;
102 jbyte *bytes;
103 bool param;
104 size_t size;
105
106 effect_callback_cookie *callbackInfo = (effect_callback_cookie *)user;
107 JNIEnv *env = AndroidRuntime::getJNIEnv();
108
Steve Block71f2cf12011-10-20 11:56:00 +0100109 ALOGV("effectCallback: callbackInfo %p, audioEffect_ref %p audioEffect_class %p",
Eric Laurent948235c2010-06-09 00:17:29 -0700110 callbackInfo,
111 callbackInfo->audioEffect_ref,
112 callbackInfo->audioEffect_class);
113
114 if (!user || !env) {
Steve Block8564c8d2012-01-05 23:22:43 +0000115 ALOGW("effectCallback error user %p, env %p", user, env);
Eric Laurent948235c2010-06-09 00:17:29 -0700116 return;
117 }
118
119 switch (event) {
120 case AudioEffect::EVENT_CONTROL_STATUS_CHANGED:
121 if (info == 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000122 ALOGW("EVENT_CONTROL_STATUS_CHANGED info == NULL");
Eric Laurent948235c2010-06-09 00:17:29 -0700123 goto effectCallback_Exit;
124 }
125 param = *(bool *)info;
126 arg1 = (int)param;
Steve Block71f2cf12011-10-20 11:56:00 +0100127 ALOGV("EVENT_CONTROL_STATUS_CHANGED");
Eric Laurent948235c2010-06-09 00:17:29 -0700128 break;
129 case AudioEffect::EVENT_ENABLE_STATUS_CHANGED:
130 if (info == 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000131 ALOGW("EVENT_ENABLE_STATUS_CHANGED info == NULL");
Eric Laurent948235c2010-06-09 00:17:29 -0700132 goto effectCallback_Exit;
133 }
134 param = *(bool *)info;
135 arg1 = (int)param;
Steve Block71f2cf12011-10-20 11:56:00 +0100136 ALOGV("EVENT_ENABLE_STATUS_CHANGED");
Eric Laurent948235c2010-06-09 00:17:29 -0700137 break;
138 case AudioEffect::EVENT_PARAMETER_CHANGED:
139 if (info == 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000140 ALOGW("EVENT_PARAMETER_CHANGED info == NULL");
Eric Laurent948235c2010-06-09 00:17:29 -0700141 goto effectCallback_Exit;
142 }
143 p = (effect_param_t *)info;
144 if (p->psize == 0 || p->vsize == 0) {
145 goto effectCallback_Exit;
146 }
147 // arg1 contains offset of parameter value from start of byte array
148 arg1 = sizeof(effect_param_t) + ((p->psize - 1) / sizeof(int) + 1) * sizeof(int);
149 size = arg1 + p->vsize;
150 array = env->NewByteArray(size);
151 if (array == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000152 ALOGE("effectCallback: Couldn't allocate byte array for parameter data");
Eric Laurent948235c2010-06-09 00:17:29 -0700153 goto effectCallback_Exit;
154 }
155 bytes = env->GetByteArrayElements(array, NULL);
156 memcpy(bytes, p, size);
157 env->ReleaseByteArrayElements(array, bytes, 0);
158 obj = array;
Steve Block71f2cf12011-10-20 11:56:00 +0100159 ALOGV("EVENT_PARAMETER_CHANGED");
Eric Laurent948235c2010-06-09 00:17:29 -0700160 break;
161 case AudioEffect::EVENT_ERROR:
Steve Block8564c8d2012-01-05 23:22:43 +0000162 ALOGW("EVENT_ERROR");
Eric Laurent948235c2010-06-09 00:17:29 -0700163 break;
164 }
165
166 env->CallStaticVoidMethod(
167 callbackInfo->audioEffect_class,
168 fields.midPostNativeEvent,
169 callbackInfo->audioEffect_ref, event, arg1, arg2, obj);
170
171effectCallback_Exit:
172 if (array) {
173 env->DeleteLocalRef(array);
174 }
175
176 if (env->ExceptionCheck()) {
177 env->ExceptionDescribe();
178 env->ExceptionClear();
179 }
180}
181
182// ----------------------------------------------------------------------------
183// This function gets some field IDs, which in turn causes class initialization.
184// It is called from a static block in AudioEffect, which won't run until the
185// first time an instance of this class is used.
186static void
187android_media_AudioEffect_native_init(JNIEnv *env)
188{
189
Steve Block71f2cf12011-10-20 11:56:00 +0100190 ALOGV("android_media_AudioEffect_native_init");
Eric Laurent948235c2010-06-09 00:17:29 -0700191
192 fields.clazzEffect = NULL;
193 fields.clazzDesc = NULL;
194
195 // Get the AudioEffect class
196 jclass clazz = env->FindClass(kClassPathName);
197 if (clazz == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000198 ALOGE("Can't find %s", kClassPathName);
Eric Laurent948235c2010-06-09 00:17:29 -0700199 return;
200 }
201
202 fields.clazzEffect = (jclass)env->NewGlobalRef(clazz);
203
204 // Get the postEvent method
205 fields.midPostNativeEvent = env->GetStaticMethodID(
206 fields.clazzEffect,
207 "postEventFromNative", "(Ljava/lang/Object;IIILjava/lang/Object;)V");
208 if (fields.midPostNativeEvent == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000209 ALOGE("Can't find AudioEffect.%s", "postEventFromNative");
Eric Laurent948235c2010-06-09 00:17:29 -0700210 return;
211 }
212
213 // Get the variables fields
214 // nativeTrackInJavaObj
215 fields.fidNativeAudioEffect = env->GetFieldID(
216 fields.clazzEffect,
Ashok Bhatea7861c2013-12-17 12:42:00 +0000217 "mNativeAudioEffect", "J");
Eric Laurent948235c2010-06-09 00:17:29 -0700218 if (fields.fidNativeAudioEffect == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000219 ALOGE("Can't find AudioEffect.%s", "mNativeAudioEffect");
Eric Laurent948235c2010-06-09 00:17:29 -0700220 return;
221 }
222 // fidJniData;
223 fields.fidJniData = env->GetFieldID(
224 fields.clazzEffect,
Ashok Bhatea7861c2013-12-17 12:42:00 +0000225 "mJniData", "J");
Eric Laurent948235c2010-06-09 00:17:29 -0700226 if (fields.fidJniData == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000227 ALOGE("Can't find AudioEffect.%s", "mJniData");
Eric Laurent948235c2010-06-09 00:17:29 -0700228 return;
229 }
230
Eric Laurent1a5149e2010-09-21 18:18:20 -0700231 clazz = env->FindClass("android/media/audiofx/AudioEffect$Descriptor");
Eric Laurent948235c2010-06-09 00:17:29 -0700232 if (clazz == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000233 ALOGE("Can't find android/media/audiofx/AudioEffect$Descriptor class");
Eric Laurent948235c2010-06-09 00:17:29 -0700234 return;
235 }
236 fields.clazzDesc = (jclass)env->NewGlobalRef(clazz);
237
238 fields.midDescCstor
239 = env->GetMethodID(
240 fields.clazzDesc,
241 "<init>",
242 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
243 if (fields.midDescCstor == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000244 ALOGE("Can't find android/media/audiofx/AudioEffect$Descriptor class constructor");
Eric Laurent948235c2010-06-09 00:17:29 -0700245 return;
246 }
247}
248
249
250static jint
251android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
252 jstring type, jstring uuid, jint priority, jint sessionId, jintArray jId, jobjectArray javadesc)
253{
Steve Block71f2cf12011-10-20 11:56:00 +0100254 ALOGV("android_media_AudioEffect_native_setup");
Eric Laurent948235c2010-06-09 00:17:29 -0700255 AudioEffectJniStorage* lpJniStorage = NULL;
256 int lStatus = AUDIOEFFECT_ERROR_NO_MEMORY;
257 AudioEffect* lpAudioEffect = NULL;
258 jint* nId = NULL;
259 const char *typeStr = NULL;
260 const char *uuidStr = NULL;
261 effect_descriptor_t desc;
262 jobject jdesc;
263 char str[EFFECT_STRING_LEN_MAX];
264 jstring jdescType;
265 jstring jdescUuid;
266 jstring jdescConnect;
267 jstring jdescName;
268 jstring jdescImplementor;
269
270 if (type != NULL) {
271 typeStr = env->GetStringUTFChars(type, NULL);
272 if (typeStr == NULL) { // Out of memory
273 jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
274 goto setup_failure;
275 }
276 }
277
278 if (uuid != NULL) {
279 uuidStr = env->GetStringUTFChars(uuid, NULL);
280 if (uuidStr == NULL) { // Out of memory
281 jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
282 goto setup_failure;
283 }
284 }
285
286 if (typeStr == NULL && uuidStr == NULL) {
287 lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
288 goto setup_failure;
289 }
290
291 lpJniStorage = new AudioEffectJniStorage();
292 if (lpJniStorage == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000293 ALOGE("setup: Error creating JNI Storage");
Eric Laurent948235c2010-06-09 00:17:29 -0700294 goto setup_failure;
295 }
296
297 lpJniStorage->mCallbackData.audioEffect_class = (jclass)env->NewGlobalRef(fields.clazzEffect);
298 // we use a weak reference so the AudioEffect object can be garbage collected.
299 lpJniStorage->mCallbackData.audioEffect_ref = env->NewGlobalRef(weak_this);
300
Steve Block71f2cf12011-10-20 11:56:00 +0100301 ALOGV("setup: lpJniStorage: %p audioEffect_ref %p audioEffect_class %p, &mCallbackData %p",
Eric Laurent948235c2010-06-09 00:17:29 -0700302 lpJniStorage,
303 lpJniStorage->mCallbackData.audioEffect_ref,
304 lpJniStorage->mCallbackData.audioEffect_class,
305 &lpJniStorage->mCallbackData);
306
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700307 if (jId == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000308 ALOGE("setup: NULL java array for id pointer");
Eric Laurent948235c2010-06-09 00:17:29 -0700309 lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
310 goto setup_failure;
311 }
312
313 // create the native AudioEffect object
314 lpAudioEffect = new AudioEffect(typeStr,
315 uuidStr,
316 priority,
317 effectCallback,
318 &lpJniStorage->mCallbackData,
Jean-Michel Trivi4cb15cf2010-07-09 12:11:49 -0700319 sessionId,
320 0);
Eric Laurent948235c2010-06-09 00:17:29 -0700321 if (lpAudioEffect == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000322 ALOGE("Error creating AudioEffect");
Eric Laurent948235c2010-06-09 00:17:29 -0700323 goto setup_failure;
324 }
325
326 lStatus = translateError(lpAudioEffect->initCheck());
327 if (lStatus != AUDIOEFFECT_SUCCESS && lStatus != AUDIOEFFECT_ERROR_ALREADY_EXISTS) {
Steve Block3762c312012-01-06 19:20:56 +0000328 ALOGE("AudioEffect initCheck failed %d", lStatus);
Eric Laurent948235c2010-06-09 00:17:29 -0700329 goto setup_failure;
330 }
331
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700332 nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL);
333 if (nId == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000334 ALOGE("setup: Error retrieving id pointer");
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700335 lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
336 goto setup_failure;
337 }
Eric Laurent948235c2010-06-09 00:17:29 -0700338 nId[0] = lpAudioEffect->id();
Eric Laurent948235c2010-06-09 00:17:29 -0700339 env->ReleasePrimitiveArrayCritical(jId, nId, 0);
340 nId = NULL;
341
342 if (typeStr) {
343 env->ReleaseStringUTFChars(type, typeStr);
344 typeStr = NULL;
345 }
346
347 if (uuidStr) {
348 env->ReleaseStringUTFChars(uuid, uuidStr);
349 uuidStr = NULL;
350 }
351
352 // get the effect descriptor
353 desc = lpAudioEffect->descriptor();
354
355 AudioEffect::guidToString(&desc.type, str, EFFECT_STRING_LEN_MAX);
356 jdescType = env->NewStringUTF(str);
357
358 AudioEffect::guidToString(&desc.uuid, str, EFFECT_STRING_LEN_MAX);
359 jdescUuid = env->NewStringUTF(str);
360
361 if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
362 jdescConnect = env->NewStringUTF("Auxiliary");
Eric Laurent09f17352011-08-11 17:06:10 -0700363 } else if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC) {
364 jdescConnect = env->NewStringUTF("Pre Processing");
Eric Laurent948235c2010-06-09 00:17:29 -0700365 } else {
366 jdescConnect = env->NewStringUTF("Insert");
367 }
368
369 jdescName = env->NewStringUTF(desc.name);
370 jdescImplementor = env->NewStringUTF(desc.implementor);
371
372 jdesc = env->NewObject(fields.clazzDesc,
373 fields.midDescCstor,
374 jdescType,
375 jdescUuid,
376 jdescConnect,
377 jdescName,
378 jdescImplementor);
379 env->DeleteLocalRef(jdescType);
380 env->DeleteLocalRef(jdescUuid);
381 env->DeleteLocalRef(jdescConnect);
382 env->DeleteLocalRef(jdescName);
383 env->DeleteLocalRef(jdescImplementor);
384 if (jdesc == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000385 ALOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)");
Eric Laurent948235c2010-06-09 00:17:29 -0700386 goto setup_failure;
387 }
388
389 env->SetObjectArrayElement(javadesc, 0, jdesc);
390
Ashok Bhatea7861c2013-12-17 12:42:00 +0000391 env->SetLongField(thiz, fields.fidNativeAudioEffect, (jlong)lpAudioEffect);
Eric Laurent948235c2010-06-09 00:17:29 -0700392
Ashok Bhatea7861c2013-12-17 12:42:00 +0000393 env->SetLongField(thiz, fields.fidJniData, (jlong)lpJniStorage);
Eric Laurent948235c2010-06-09 00:17:29 -0700394
Ashok Bhatea7861c2013-12-17 12:42:00 +0000395 return (jint) AUDIOEFFECT_SUCCESS;
Eric Laurent948235c2010-06-09 00:17:29 -0700396
397 // failures:
398setup_failure:
399
400 if (nId != NULL) {
401 env->ReleasePrimitiveArrayCritical(jId, nId, 0);
402 }
403
404 if (lpAudioEffect) {
405 delete lpAudioEffect;
406 }
Ashok Bhatea7861c2013-12-17 12:42:00 +0000407 env->SetLongField(thiz, fields.fidNativeAudioEffect, 0);
Eric Laurent948235c2010-06-09 00:17:29 -0700408
409 if (lpJniStorage) {
410 delete lpJniStorage;
411 }
Ashok Bhatea7861c2013-12-17 12:42:00 +0000412 env->SetLongField(thiz, fields.fidJniData, 0);
Eric Laurent948235c2010-06-09 00:17:29 -0700413
414 if (uuidStr != NULL) {
415 env->ReleaseStringUTFChars(uuid, uuidStr);
416 }
417
418 if (typeStr != NULL) {
419 env->ReleaseStringUTFChars(type, typeStr);
420 }
421
Ashok Bhatea7861c2013-12-17 12:42:00 +0000422 return (jint)lStatus;
Eric Laurent948235c2010-06-09 00:17:29 -0700423}
424
425
426// ----------------------------------------------------------------------------
427static void android_media_AudioEffect_native_finalize(JNIEnv *env, jobject thiz) {
Ashok Bhatea7861c2013-12-17 12:42:00 +0000428 ALOGV("android_media_AudioEffect_native_finalize jobject: %p\n", thiz);
Eric Laurent948235c2010-06-09 00:17:29 -0700429
430 // delete the AudioEffect object
Ashok Bhatea7861c2013-12-17 12:42:00 +0000431 AudioEffect* lpAudioEffect = (AudioEffect *)env->GetLongField(
Eric Laurent948235c2010-06-09 00:17:29 -0700432 thiz, fields.fidNativeAudioEffect);
433 if (lpAudioEffect) {
Ashok Bhatea7861c2013-12-17 12:42:00 +0000434 ALOGV("deleting AudioEffect: %p\n", lpAudioEffect);
Eric Laurent948235c2010-06-09 00:17:29 -0700435 delete lpAudioEffect;
436 }
437
438 // delete the JNI data
Ashok Bhatea7861c2013-12-17 12:42:00 +0000439 AudioEffectJniStorage* lpJniStorage = (AudioEffectJniStorage *)env->GetLongField(
Eric Laurent948235c2010-06-09 00:17:29 -0700440 thiz, fields.fidJniData);
441 if (lpJniStorage) {
Ashok Bhatea7861c2013-12-17 12:42:00 +0000442 ALOGV("deleting pJniStorage: %p\n", lpJniStorage);
Eric Laurent948235c2010-06-09 00:17:29 -0700443 delete lpJniStorage;
444 }
445}
446
447// ----------------------------------------------------------------------------
448static void android_media_AudioEffect_native_release(JNIEnv *env, jobject thiz) {
449
450 // do everything a call to finalize would
451 android_media_AudioEffect_native_finalize(env, thiz);
452 // + reset the native resources in the Java object so any attempt to access
453 // them after a call to release fails.
Ashok Bhatea7861c2013-12-17 12:42:00 +0000454 env->SetLongField(thiz, fields.fidNativeAudioEffect, 0);
455 env->SetLongField(thiz, fields.fidJniData, 0);
Eric Laurent948235c2010-06-09 00:17:29 -0700456}
457
Eric Laurent948235c2010-06-09 00:17:29 -0700458static jint
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700459android_media_AudioEffect_native_setEnabled(JNIEnv *env, jobject thiz, jboolean enabled)
Eric Laurent948235c2010-06-09 00:17:29 -0700460{
461 // retrieve the AudioEffect object
Ashok Bhatea7861c2013-12-17 12:42:00 +0000462 AudioEffect* lpAudioEffect = (AudioEffect *)env->GetLongField(
Eric Laurent948235c2010-06-09 00:17:29 -0700463 thiz, fields.fidNativeAudioEffect);
464
465 if (lpAudioEffect == NULL) {
466 jniThrowException(env, "java/lang/IllegalStateException",
467 "Unable to retrieve AudioEffect pointer for enable()");
468 return AUDIOEFFECT_ERROR_NO_INIT;
469 }
470
Ashok Bhatea7861c2013-12-17 12:42:00 +0000471 return (jint) translateError(lpAudioEffect->setEnabled(enabled));
Eric Laurent948235c2010-06-09 00:17:29 -0700472}
473
Eric Laurent948235c2010-06-09 00:17:29 -0700474static jboolean
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700475android_media_AudioEffect_native_getEnabled(JNIEnv *env, jobject thiz)
Eric Laurent948235c2010-06-09 00:17:29 -0700476{
477 // retrieve the AudioEffect object
Ashok Bhatea7861c2013-12-17 12:42:00 +0000478 AudioEffect* lpAudioEffect = (AudioEffect *)env->GetLongField(
Eric Laurent948235c2010-06-09 00:17:29 -0700479 thiz, fields.fidNativeAudioEffect);
480
481 if (lpAudioEffect == NULL) {
482 jniThrowException(env, "java/lang/IllegalStateException",
483 "Unable to retrieve AudioEffect pointer for getEnabled()");
Ashok Bhatea7861c2013-12-17 12:42:00 +0000484 return JNI_FALSE;
Eric Laurent948235c2010-06-09 00:17:29 -0700485 }
486
Ashok Bhatea7861c2013-12-17 12:42:00 +0000487 if (lpAudioEffect->getEnabled()) {
488 return JNI_TRUE;
489 } else {
490 return JNI_FALSE;
491 }
Eric Laurent948235c2010-06-09 00:17:29 -0700492}
493
494
495static jboolean
496android_media_AudioEffect_native_hasControl(JNIEnv *env, jobject thiz)
497{
498 // retrieve the AudioEffect object
Ashok Bhatea7861c2013-12-17 12:42:00 +0000499 AudioEffect* lpAudioEffect = (AudioEffect *)env->GetLongField(
Eric Laurent948235c2010-06-09 00:17:29 -0700500 thiz, fields.fidNativeAudioEffect);
501
502 if (lpAudioEffect == NULL) {
503 jniThrowException(env, "java/lang/IllegalStateException",
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700504 "Unable to retrieve AudioEffect pointer for hasControl()");
Ashok Bhatea7861c2013-12-17 12:42:00 +0000505 return JNI_FALSE;
Eric Laurent948235c2010-06-09 00:17:29 -0700506 }
507
508 if (lpAudioEffect->initCheck() == NO_ERROR) {
Ashok Bhatea7861c2013-12-17 12:42:00 +0000509 return JNI_TRUE;
Eric Laurent948235c2010-06-09 00:17:29 -0700510 } else {
Ashok Bhatea7861c2013-12-17 12:42:00 +0000511 return JNI_FALSE;
Eric Laurent948235c2010-06-09 00:17:29 -0700512 }
513}
514
515static jint android_media_AudioEffect_native_setParameter(JNIEnv *env,
Ashok Bhatea7861c2013-12-17 12:42:00 +0000516 jobject thiz, jint psize, jbyteArray pJavaParam, jint vsize,
Eric Laurent948235c2010-06-09 00:17:29 -0700517 jbyteArray pJavaValue) {
518 // retrieve the AudioEffect object
519 jbyte* lpValue = NULL;
520 jbyte* lpParam = NULL;
521 jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
522 effect_param_t *p;
523 int voffset;
524
Ashok Bhatea7861c2013-12-17 12:42:00 +0000525 AudioEffect* lpAudioEffect = (AudioEffect *) env->GetLongField(thiz,
Eric Laurent948235c2010-06-09 00:17:29 -0700526 fields.fidNativeAudioEffect);
527
528 if (lpAudioEffect == NULL) {
529 jniThrowException(env, "java/lang/IllegalStateException",
530 "Unable to retrieve AudioEffect pointer for setParameter()");
531 return AUDIOEFFECT_ERROR_NO_INIT;
532 }
533
534 if (psize == 0 || vsize == 0 || pJavaParam == NULL || pJavaValue == NULL) {
535 return AUDIOEFFECT_ERROR_BAD_VALUE;
536 }
537
538 // get the pointer for the param from the java array
539 lpParam = (jbyte *) env->GetPrimitiveArrayCritical(pJavaParam, NULL);
540 if (lpParam == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000541 ALOGE("setParameter: Error retrieving param pointer");
Eric Laurent948235c2010-06-09 00:17:29 -0700542 goto setParameter_Exit;
543 }
544
545 // get the pointer for the value from the java array
546 lpValue = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValue, NULL);
547 if (lpValue == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000548 ALOGE("setParameter: Error retrieving value pointer");
Eric Laurent948235c2010-06-09 00:17:29 -0700549 goto setParameter_Exit;
550 }
551
552 voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int);
553 p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset + vsize);
554 memcpy(p->data, lpParam, psize);
555 p->psize = psize;
Eric Laurentca57d1c2010-07-23 00:19:11 -0700556 memcpy(p->data + voffset, lpValue, vsize);
Eric Laurent948235c2010-06-09 00:17:29 -0700557 p->vsize = vsize;
558
559 lStatus = lpAudioEffect->setParameter(p);
560 if (lStatus == NO_ERROR) {
561 lStatus = p->status;
562 }
563
564 free(p);
565
566setParameter_Exit:
567
568 if (lpParam != NULL) {
569 env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0);
570 }
571 if (lpValue != NULL) {
572 env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
573 }
Ashok Bhatea7861c2013-12-17 12:42:00 +0000574 return (jint) translateError(lStatus);
Eric Laurent948235c2010-06-09 00:17:29 -0700575}
576
577static jint
578android_media_AudioEffect_native_getParameter(JNIEnv *env,
Eric Laurent602b3282011-03-18 08:33:14 -0700579 jobject thiz, jint psize, jbyteArray pJavaParam,
580 jint vsize, jbyteArray pJavaValue) {
Eric Laurent948235c2010-06-09 00:17:29 -0700581 // retrieve the AudioEffect object
582 jbyte* lpParam = NULL;
583 jbyte* lpValue = NULL;
Eric Laurent948235c2010-06-09 00:17:29 -0700584 jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
585 effect_param_t *p;
586 int voffset;
587
Ashok Bhatea7861c2013-12-17 12:42:00 +0000588 AudioEffect* lpAudioEffect = (AudioEffect *) env->GetLongField(thiz,
Eric Laurent948235c2010-06-09 00:17:29 -0700589 fields.fidNativeAudioEffect);
590
591 if (lpAudioEffect == NULL) {
592 jniThrowException(env, "java/lang/IllegalStateException",
593 "Unable to retrieve AudioEffect pointer for getParameter()");
594 return AUDIOEFFECT_ERROR_NO_INIT;
595 }
596
Eric Laurent602b3282011-03-18 08:33:14 -0700597 if (psize == 0 || vsize == 0 || pJavaParam == NULL || pJavaValue == NULL) {
Eric Laurent948235c2010-06-09 00:17:29 -0700598 return AUDIOEFFECT_ERROR_BAD_VALUE;
599 }
600
601 // get the pointer for the param from the java array
602 lpParam = (jbyte *) env->GetPrimitiveArrayCritical(pJavaParam, NULL);
603 if (lpParam == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000604 ALOGE("getParameter: Error retrieving param pointer");
Eric Laurent948235c2010-06-09 00:17:29 -0700605 goto getParameter_Exit;
606 }
607
608 // get the pointer for the value from the java array
609 lpValue = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValue, NULL);
610 if (lpValue == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000611 ALOGE("getParameter: Error retrieving value pointer");
Eric Laurent948235c2010-06-09 00:17:29 -0700612 goto getParameter_Exit;
613 }
614
Eric Laurent948235c2010-06-09 00:17:29 -0700615 voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int);
Eric Laurent602b3282011-03-18 08:33:14 -0700616 p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset + vsize);
Eric Laurent948235c2010-06-09 00:17:29 -0700617 memcpy(p->data, lpParam, psize);
618 p->psize = psize;
Eric Laurent602b3282011-03-18 08:33:14 -0700619 p->vsize = vsize;
Eric Laurent948235c2010-06-09 00:17:29 -0700620
621 lStatus = lpAudioEffect->getParameter(p);
622 if (lStatus == NO_ERROR) {
623 lStatus = p->status;
624 if (lStatus == NO_ERROR) {
625 memcpy(lpValue, p->data + voffset, p->vsize);
Eric Laurent602b3282011-03-18 08:33:14 -0700626 vsize = p->vsize;
Eric Laurent948235c2010-06-09 00:17:29 -0700627 }
628 }
629
630 free(p);
631
632getParameter_Exit:
633
634 if (lpParam != NULL) {
635 env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0);
636 }
637 if (lpValue != NULL) {
638 env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
639 }
Eric Laurent948235c2010-06-09 00:17:29 -0700640
Eric Laurent602b3282011-03-18 08:33:14 -0700641 if (lStatus == NO_ERROR) {
642 return vsize;
643 }
Ashok Bhatea7861c2013-12-17 12:42:00 +0000644 return (jint) translateError(lStatus);
Eric Laurent948235c2010-06-09 00:17:29 -0700645}
646
647static jint android_media_AudioEffect_native_command(JNIEnv *env, jobject thiz,
Eric Laurent602b3282011-03-18 08:33:14 -0700648 jint cmdCode, jint cmdSize, jbyteArray jCmdData, jint replySize,
Eric Laurent948235c2010-06-09 00:17:29 -0700649 jbyteArray jReplyData) {
650 jbyte* pCmdData = NULL;
651 jbyte* pReplyData = NULL;
Eric Laurent948235c2010-06-09 00:17:29 -0700652 jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
653
654 // retrieve the AudioEffect object
Ashok Bhatea7861c2013-12-17 12:42:00 +0000655 AudioEffect* lpAudioEffect = (AudioEffect *) env->GetLongField(thiz,
Eric Laurent948235c2010-06-09 00:17:29 -0700656 fields.fidNativeAudioEffect);
657
658 if (lpAudioEffect == NULL) {
659 jniThrowException(env, "java/lang/IllegalStateException",
660 "Unable to retrieve AudioEffect pointer for setParameter()");
661 return AUDIOEFFECT_ERROR_NO_INIT;
662 }
663
Eric Laurent602b3282011-03-18 08:33:14 -0700664 if ((cmdSize != 0 && jCmdData == NULL) || (replySize != 0 && jReplyData == NULL)) {
Eric Laurent948235c2010-06-09 00:17:29 -0700665 return AUDIOEFFECT_ERROR_BAD_VALUE;
666 }
667
668 // get the pointer for the command from the java array
669 if (cmdSize != 0) {
670 pCmdData = (jbyte *) env->GetPrimitiveArrayCritical(jCmdData, NULL);
671 if (pCmdData == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000672 ALOGE("setParameter: Error retrieving command pointer");
Eric Laurent948235c2010-06-09 00:17:29 -0700673 goto command_Exit;
674 }
675 }
676
Eric Laurent948235c2010-06-09 00:17:29 -0700677 // get the pointer for the reply from the java array
Eric Laurent602b3282011-03-18 08:33:14 -0700678 if (replySize != 0 && jReplyData != NULL) {
Eric Laurent948235c2010-06-09 00:17:29 -0700679 pReplyData = (jbyte *) env->GetPrimitiveArrayCritical(jReplyData, NULL);
680 if (pReplyData == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000681 ALOGE("setParameter: Error retrieving reply pointer");
Eric Laurent948235c2010-06-09 00:17:29 -0700682 goto command_Exit;
683 }
684 }
685
Eric Laurenta4c72ac2010-07-28 05:40:18 -0700686 lStatus = translateError(lpAudioEffect->command((uint32_t)cmdCode,
687 (uint32_t)cmdSize,
688 pCmdData,
Eric Laurent602b3282011-03-18 08:33:14 -0700689 (uint32_t *)&replySize,
Eric Laurenta4c72ac2010-07-28 05:40:18 -0700690 pReplyData));
Eric Laurent948235c2010-06-09 00:17:29 -0700691
692command_Exit:
693
694 if (pCmdData != NULL) {
695 env->ReleasePrimitiveArrayCritical(jCmdData, pCmdData, 0);
696 }
697 if (pReplyData != NULL) {
698 env->ReleasePrimitiveArrayCritical(jReplyData, pReplyData, 0);
699 }
Eric Laurent948235c2010-06-09 00:17:29 -0700700
Eric Laurent602b3282011-03-18 08:33:14 -0700701 if (lStatus == NO_ERROR) {
702 return replySize;
703 }
Eric Laurent948235c2010-06-09 00:17:29 -0700704 return lStatus;
705}
706
707static jobjectArray
708android_media_AudioEffect_native_queryEffects(JNIEnv *env, jclass clazz)
709{
710 effect_descriptor_t desc;
711 char str[EFFECT_STRING_LEN_MAX];
Peter Karlsson4526f0d2012-11-16 16:14:15 +0100712 uint32_t numEffects = 0;
Eric Laurent948235c2010-06-09 00:17:29 -0700713 uint32_t i = 0;
714 jstring jdescType;
715 jstring jdescUuid;
716 jstring jdescConnect;
717 jstring jdescName;
718 jstring jdescImplementor;
719 jobject jdesc;
720
Peter Karlsson4526f0d2012-11-16 16:14:15 +0100721 if (AudioEffect::queryNumberEffects(&numEffects) != NO_ERROR) {
722 return NULL;
723 }
724
Eric Laurent948235c2010-06-09 00:17:29 -0700725 jobjectArray ret = env->NewObjectArray(numEffects, fields.clazzDesc, NULL);
726 if (ret == NULL) {
727 return ret;
728 }
729
Steve Block71f2cf12011-10-20 11:56:00 +0100730 ALOGV("queryEffects() numEffects: %d", numEffects);
Eric Laurent948235c2010-06-09 00:17:29 -0700731
732 for (i = 0; i < numEffects; i++) {
Eric Laurent53334cd2010-06-23 17:38:20 -0700733 if (AudioEffect::queryEffect(i, &desc) != NO_ERROR) {
Eric Laurent948235c2010-06-09 00:17:29 -0700734 goto queryEffects_failure;
735 }
736
Eric Laurent0f7f4ec2011-07-24 13:36:09 -0700737 if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
738 jdescConnect = env->NewStringUTF("Auxiliary");
739 } else if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_INSERT) {
740 jdescConnect = env->NewStringUTF("Insert");
741 } else if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC) {
742 jdescConnect = env->NewStringUTF("Pre Processing");
743 } else {
744 continue;
745 }
746
Eric Laurent948235c2010-06-09 00:17:29 -0700747 AudioEffect::guidToString(&desc.type, str, EFFECT_STRING_LEN_MAX);
748 jdescType = env->NewStringUTF(str);
749
750 AudioEffect::guidToString(&desc.uuid, str, EFFECT_STRING_LEN_MAX);
751 jdescUuid = env->NewStringUTF(str);
752
Eric Laurent948235c2010-06-09 00:17:29 -0700753 jdescName = env->NewStringUTF(desc.name);
754 jdescImplementor = env->NewStringUTF(desc.implementor);
755
756 jdesc = env->NewObject(fields.clazzDesc,
757 fields.midDescCstor,
758 jdescType,
759 jdescUuid,
760 jdescConnect,
761 jdescName,
762 jdescImplementor);
763 env->DeleteLocalRef(jdescType);
764 env->DeleteLocalRef(jdescUuid);
765 env->DeleteLocalRef(jdescConnect);
766 env->DeleteLocalRef(jdescName);
767 env->DeleteLocalRef(jdescImplementor);
768 if (jdesc == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000769 ALOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)");
Eric Laurent948235c2010-06-09 00:17:29 -0700770 goto queryEffects_failure;
771 }
772
773 env->SetObjectArrayElement(ret, i, jdesc);
774 }
775
776 return ret;
777
778queryEffects_failure:
779
780 if (ret != NULL) {
781 env->DeleteLocalRef(ret);
782 }
783 return NULL;
784
785}
786
Eric Laurent0f7f4ec2011-07-24 13:36:09 -0700787
788
789static jobjectArray
790android_media_AudioEffect_native_queryPreProcessings(JNIEnv *env, jclass clazz, jint audioSession)
791{
792 // kDefaultNumEffects is a "reasonable" value ensuring that only one query will be enough on
793 // most devices to get all active audio pre processing on a given session.
794 static const uint32_t kDefaultNumEffects = 5;
795
796 effect_descriptor_t *descriptors = new effect_descriptor_t[kDefaultNumEffects];
797 uint32_t numEffects = kDefaultNumEffects;
798
799 status_t status = AudioEffect::queryDefaultPreProcessing(audioSession,
800 descriptors,
801 &numEffects);
802 if ((status != NO_ERROR && status != NO_MEMORY) ||
803 numEffects == 0) {
804 delete[] descriptors;
805 return NULL;
806 }
807 if (status == NO_MEMORY) {
808 delete [] descriptors;
809 descriptors = new effect_descriptor_t[numEffects];
810 status = AudioEffect::queryDefaultPreProcessing(audioSession,
811 descriptors,
812 &numEffects);
813 }
814 if (status != NO_ERROR || numEffects == 0) {
815 delete[] descriptors;
816 return NULL;
817 }
Steve Block71f2cf12011-10-20 11:56:00 +0100818 ALOGV("queryDefaultPreProcessing() got %d effects", numEffects);
Eric Laurent0f7f4ec2011-07-24 13:36:09 -0700819
820 jobjectArray ret = env->NewObjectArray(numEffects, fields.clazzDesc, NULL);
821 if (ret == NULL) {
822 delete[] descriptors;
823 return ret;
824 }
825
826 char str[EFFECT_STRING_LEN_MAX];
827 jstring jdescType;
828 jstring jdescUuid;
829 jstring jdescConnect;
830 jstring jdescName;
831 jstring jdescImplementor;
832 jobject jdesc;
833
834 for (uint32_t i = 0; i < numEffects; i++) {
835
836 AudioEffect::guidToString(&descriptors[i].type, str, EFFECT_STRING_LEN_MAX);
837 jdescType = env->NewStringUTF(str);
838 AudioEffect::guidToString(&descriptors[i].uuid, str, EFFECT_STRING_LEN_MAX);
839 jdescUuid = env->NewStringUTF(str);
840 jdescConnect = env->NewStringUTF("Pre Processing");
841 jdescName = env->NewStringUTF(descriptors[i].name);
842 jdescImplementor = env->NewStringUTF(descriptors[i].implementor);
843
844 jdesc = env->NewObject(fields.clazzDesc,
845 fields.midDescCstor,
846 jdescType,
847 jdescUuid,
848 jdescConnect,
849 jdescName,
850 jdescImplementor);
851 env->DeleteLocalRef(jdescType);
852 env->DeleteLocalRef(jdescUuid);
853 env->DeleteLocalRef(jdescConnect);
854 env->DeleteLocalRef(jdescName);
855 env->DeleteLocalRef(jdescImplementor);
856 if (jdesc == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000857 ALOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)");
Eric Laurent0f7f4ec2011-07-24 13:36:09 -0700858 env->DeleteLocalRef(ret);
859 return NULL;;
860 }
861
862 env->SetObjectArrayElement(ret, i, jdesc);
863 }
864
865 return ret;
866}
867
Eric Laurent948235c2010-06-09 00:17:29 -0700868// ----------------------------------------------------------------------------
869
870// Dalvik VM type signatures
871static JNINativeMethod gMethods[] = {
872 {"native_init", "()V", (void *)android_media_AudioEffect_native_init},
873 {"native_setup", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;II[I[Ljava/lang/Object;)I",
874 (void *)android_media_AudioEffect_native_setup},
875 {"native_finalize", "()V", (void *)android_media_AudioEffect_native_finalize},
876 {"native_release", "()V", (void *)android_media_AudioEffect_native_release},
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700877 {"native_setEnabled", "(Z)I", (void *)android_media_AudioEffect_native_setEnabled},
878 {"native_getEnabled", "()Z", (void *)android_media_AudioEffect_native_getEnabled},
Eric Laurent948235c2010-06-09 00:17:29 -0700879 {"native_hasControl", "()Z", (void *)android_media_AudioEffect_native_hasControl},
880 {"native_setParameter", "(I[BI[B)I", (void *)android_media_AudioEffect_native_setParameter},
Eric Laurent602b3282011-03-18 08:33:14 -0700881 {"native_getParameter", "(I[BI[B)I", (void *)android_media_AudioEffect_native_getParameter},
882 {"native_command", "(II[BI[B)I", (void *)android_media_AudioEffect_native_command},
Eric Laurent948235c2010-06-09 00:17:29 -0700883 {"native_query_effects", "()[Ljava/lang/Object;", (void *)android_media_AudioEffect_native_queryEffects},
Eric Laurent0f7f4ec2011-07-24 13:36:09 -0700884 {"native_query_pre_processing", "(I)[Ljava/lang/Object;",
885 (void *)android_media_AudioEffect_native_queryPreProcessings},
Eric Laurent948235c2010-06-09 00:17:29 -0700886};
887
888
889// ----------------------------------------------------------------------------
890
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700891extern int register_android_media_visualizer(JNIEnv *env);
892
Eric Laurent948235c2010-06-09 00:17:29 -0700893int register_android_media_AudioEffect(JNIEnv *env)
894{
895 return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
896}
897
898jint JNI_OnLoad(JavaVM* vm, void* reserved)
899{
900
901 JNIEnv* env = NULL;
902 jint result = -1;
903
904 if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
Steve Block3762c312012-01-06 19:20:56 +0000905 ALOGE("ERROR: GetEnv failed\n");
Eric Laurent948235c2010-06-09 00:17:29 -0700906 goto bail;
907 }
908 assert(env != NULL);
909
910 if (register_android_media_AudioEffect(env) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000911 ALOGE("ERROR: AudioEffect native registration failed\n");
Eric Laurent948235c2010-06-09 00:17:29 -0700912 goto bail;
913 }
914
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700915 if (register_android_media_visualizer(env) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000916 ALOGE("ERROR: Visualizer native registration failed\n");
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700917 goto bail;
918 }
919
Eric Laurent948235c2010-06-09 00:17:29 -0700920 /* success -- return valid version number */
921 result = JNI_VERSION_1_4;
922
923bail:
924 return result;
925}
926