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 "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
28 using 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 // ----------------------------------------------------------------------------
40 static const char* const kClassPathName = "android/media/audiofx/AudioEffect";
41
42 struct 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 };
51 static fields_t fields;
52
53 struct effect_callback_cookie {
54 jclass audioEffect_class; // AudioEffect class
55 jobject audioEffect_ref; // AudioEffect object instance
56 };
57
58 // ----------------------------------------------------------------------------
59 class AudioEffectJniStorage {
60 public:
61 effect_callback_cookie mCallbackData;
62
AudioEffectJniStorage()63 AudioEffectJniStorage() {
64 }
65
~AudioEffectJniStorage()66 ~AudioEffectJniStorage() {
67 }
68
69 };
70
71
translateError(int code)72 static 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 // ----------------------------------------------------------------------------
effectCallback(int event,void * user,void * info)95 static 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
109 ALOGV("effectCallback: callbackInfo %p, audioEffect_ref %p audioEffect_class %p",
110 callbackInfo,
111 callbackInfo->audioEffect_ref,
112 callbackInfo->audioEffect_class);
113
114 if (!user || !env) {
115 ALOGW("effectCallback error user %p, env %p", user, env);
116 return;
117 }
118
119 switch (event) {
120 case AudioEffect::EVENT_CONTROL_STATUS_CHANGED:
121 if (info == 0) {
122 ALOGW("EVENT_CONTROL_STATUS_CHANGED info == NULL");
123 goto effectCallback_Exit;
124 }
125 param = *(bool *)info;
126 arg1 = (int)param;
127 ALOGV("EVENT_CONTROL_STATUS_CHANGED");
128 break;
129 case AudioEffect::EVENT_ENABLE_STATUS_CHANGED:
130 if (info == 0) {
131 ALOGW("EVENT_ENABLE_STATUS_CHANGED info == NULL");
132 goto effectCallback_Exit;
133 }
134 param = *(bool *)info;
135 arg1 = (int)param;
136 ALOGV("EVENT_ENABLE_STATUS_CHANGED");
137 break;
138 case AudioEffect::EVENT_PARAMETER_CHANGED:
139 if (info == 0) {
140 ALOGW("EVENT_PARAMETER_CHANGED info == NULL");
141 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) {
152 ALOGE("effectCallback: Couldn't allocate byte array for parameter data");
153 goto effectCallback_Exit;
154 }
155 bytes = env->GetByteArrayElements(array, NULL);
156 memcpy(bytes, p, size);
157 env->ReleaseByteArrayElements(array, bytes, 0);
158 obj = array;
159 ALOGV("EVENT_PARAMETER_CHANGED");
160 break;
161 case AudioEffect::EVENT_ERROR:
162 ALOGW("EVENT_ERROR");
163 break;
164 }
165
166 env->CallStaticVoidMethod(
167 callbackInfo->audioEffect_class,
168 fields.midPostNativeEvent,
169 callbackInfo->audioEffect_ref, event, arg1, arg2, obj);
170
171 effectCallback_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.
186 static void
android_media_AudioEffect_native_init(JNIEnv * env)187 android_media_AudioEffect_native_init(JNIEnv *env)
188 {
189
190 ALOGV("android_media_AudioEffect_native_init");
191
192 fields.clazzEffect = NULL;
193 fields.clazzDesc = NULL;
194
195 // Get the AudioEffect class
196 jclass clazz = env->FindClass(kClassPathName);
197 if (clazz == NULL) {
198 ALOGE("Can't find %s", kClassPathName);
199 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) {
209 ALOGE("Can't find AudioEffect.%s", "postEventFromNative");
210 return;
211 }
212
213 // Get the variables fields
214 // nativeTrackInJavaObj
215 fields.fidNativeAudioEffect = env->GetFieldID(
216 fields.clazzEffect,
217 "mNativeAudioEffect", "J");
218 if (fields.fidNativeAudioEffect == NULL) {
219 ALOGE("Can't find AudioEffect.%s", "mNativeAudioEffect");
220 return;
221 }
222 // fidJniData;
223 fields.fidJniData = env->GetFieldID(
224 fields.clazzEffect,
225 "mJniData", "J");
226 if (fields.fidJniData == NULL) {
227 ALOGE("Can't find AudioEffect.%s", "mJniData");
228 return;
229 }
230
231 clazz = env->FindClass("android/media/audiofx/AudioEffect$Descriptor");
232 if (clazz == NULL) {
233 ALOGE("Can't find android/media/audiofx/AudioEffect$Descriptor class");
234 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) {
244 ALOGE("Can't find android/media/audiofx/AudioEffect$Descriptor class constructor");
245 return;
246 }
247 }
248
249
250 static jint
android_media_AudioEffect_native_setup(JNIEnv * env,jobject thiz,jobject weak_this,jstring type,jstring uuid,jint priority,jint sessionId,jintArray jId,jobjectArray javadesc)251 android_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 {
254 ALOGV("android_media_AudioEffect_native_setup");
255 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) {
293 ALOGE("setup: Error creating JNI Storage");
294 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
301 ALOGV("setup: lpJniStorage: %p audioEffect_ref %p audioEffect_class %p, &mCallbackData %p",
302 lpJniStorage,
303 lpJniStorage->mCallbackData.audioEffect_ref,
304 lpJniStorage->mCallbackData.audioEffect_class,
305 &lpJniStorage->mCallbackData);
306
307 if (jId == NULL) {
308 ALOGE("setup: NULL java array for id pointer");
309 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,
319 sessionId,
320 0);
321 if (lpAudioEffect == NULL) {
322 ALOGE("Error creating AudioEffect");
323 goto setup_failure;
324 }
325
326 lStatus = translateError(lpAudioEffect->initCheck());
327 if (lStatus != AUDIOEFFECT_SUCCESS && lStatus != AUDIOEFFECT_ERROR_ALREADY_EXISTS) {
328 ALOGE("AudioEffect initCheck failed %d", lStatus);
329 goto setup_failure;
330 }
331
332 nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL);
333 if (nId == NULL) {
334 ALOGE("setup: Error retrieving id pointer");
335 lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
336 goto setup_failure;
337 }
338 nId[0] = lpAudioEffect->id();
339 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");
363 } else if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC) {
364 jdescConnect = env->NewStringUTF("Pre Processing");
365 } 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) {
385 ALOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)");
386 goto setup_failure;
387 }
388
389 env->SetObjectArrayElement(javadesc, 0, jdesc);
390
391 env->SetLongField(thiz, fields.fidNativeAudioEffect, (jlong)lpAudioEffect);
392
393 env->SetLongField(thiz, fields.fidJniData, (jlong)lpJniStorage);
394
395 return (jint) AUDIOEFFECT_SUCCESS;
396
397 // failures:
398 setup_failure:
399
400 if (nId != NULL) {
401 env->ReleasePrimitiveArrayCritical(jId, nId, 0);
402 }
403
404 if (lpAudioEffect) {
405 delete lpAudioEffect;
406 }
407 env->SetLongField(thiz, fields.fidNativeAudioEffect, 0);
408
409 if (lpJniStorage) {
410 delete lpJniStorage;
411 }
412 env->SetLongField(thiz, fields.fidJniData, 0);
413
414 if (uuidStr != NULL) {
415 env->ReleaseStringUTFChars(uuid, uuidStr);
416 }
417
418 if (typeStr != NULL) {
419 env->ReleaseStringUTFChars(type, typeStr);
420 }
421
422 return (jint)lStatus;
423 }
424
425
426 // ----------------------------------------------------------------------------
android_media_AudioEffect_native_finalize(JNIEnv * env,jobject thiz)427 static void android_media_AudioEffect_native_finalize(JNIEnv *env, jobject thiz) {
428 ALOGV("android_media_AudioEffect_native_finalize jobject: %p\n", thiz);
429
430 // delete the AudioEffect object
431 AudioEffect* lpAudioEffect = (AudioEffect *)env->GetLongField(
432 thiz, fields.fidNativeAudioEffect);
433 if (lpAudioEffect) {
434 ALOGV("deleting AudioEffect: %p\n", lpAudioEffect);
435 delete lpAudioEffect;
436 }
437
438 // delete the JNI data
439 AudioEffectJniStorage* lpJniStorage = (AudioEffectJniStorage *)env->GetLongField(
440 thiz, fields.fidJniData);
441 if (lpJniStorage) {
442 ALOGV("deleting pJniStorage: %p\n", lpJniStorage);
443 delete lpJniStorage;
444 }
445 }
446
447 // ----------------------------------------------------------------------------
android_media_AudioEffect_native_release(JNIEnv * env,jobject thiz)448 static 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.
454 env->SetLongField(thiz, fields.fidNativeAudioEffect, 0);
455 env->SetLongField(thiz, fields.fidJniData, 0);
456 }
457
458 static jint
android_media_AudioEffect_native_setEnabled(JNIEnv * env,jobject thiz,jboolean enabled)459 android_media_AudioEffect_native_setEnabled(JNIEnv *env, jobject thiz, jboolean enabled)
460 {
461 // retrieve the AudioEffect object
462 AudioEffect* lpAudioEffect = (AudioEffect *)env->GetLongField(
463 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
471 return (jint) translateError(lpAudioEffect->setEnabled(enabled));
472 }
473
474 static jboolean
android_media_AudioEffect_native_getEnabled(JNIEnv * env,jobject thiz)475 android_media_AudioEffect_native_getEnabled(JNIEnv *env, jobject thiz)
476 {
477 // retrieve the AudioEffect object
478 AudioEffect* lpAudioEffect = (AudioEffect *)env->GetLongField(
479 thiz, fields.fidNativeAudioEffect);
480
481 if (lpAudioEffect == NULL) {
482 jniThrowException(env, "java/lang/IllegalStateException",
483 "Unable to retrieve AudioEffect pointer for getEnabled()");
484 return JNI_FALSE;
485 }
486
487 if (lpAudioEffect->getEnabled()) {
488 return JNI_TRUE;
489 } else {
490 return JNI_FALSE;
491 }
492 }
493
494
495 static jboolean
android_media_AudioEffect_native_hasControl(JNIEnv * env,jobject thiz)496 android_media_AudioEffect_native_hasControl(JNIEnv *env, jobject thiz)
497 {
498 // retrieve the AudioEffect object
499 AudioEffect* lpAudioEffect = (AudioEffect *)env->GetLongField(
500 thiz, fields.fidNativeAudioEffect);
501
502 if (lpAudioEffect == NULL) {
503 jniThrowException(env, "java/lang/IllegalStateException",
504 "Unable to retrieve AudioEffect pointer for hasControl()");
505 return JNI_FALSE;
506 }
507
508 if (lpAudioEffect->initCheck() == NO_ERROR) {
509 return JNI_TRUE;
510 } else {
511 return JNI_FALSE;
512 }
513 }
514
android_media_AudioEffect_native_setParameter(JNIEnv * env,jobject thiz,jint psize,jbyteArray pJavaParam,jint vsize,jbyteArray pJavaValue)515 static jint android_media_AudioEffect_native_setParameter(JNIEnv *env,
516 jobject thiz, jint psize, jbyteArray pJavaParam, jint vsize,
517 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
525 AudioEffect* lpAudioEffect = (AudioEffect *) env->GetLongField(thiz,
526 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) {
541 ALOGE("setParameter: Error retrieving param pointer");
542 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) {
548 ALOGE("setParameter: Error retrieving value pointer");
549 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;
556 memcpy(p->data + voffset, lpValue, vsize);
557 p->vsize = vsize;
558
559 lStatus = lpAudioEffect->setParameter(p);
560 if (lStatus == NO_ERROR) {
561 lStatus = p->status;
562 }
563
564 free(p);
565
566 setParameter_Exit:
567
568 if (lpParam != NULL) {
569 env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0);
570 }
571 if (lpValue != NULL) {
572 env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
573 }
574 return (jint) translateError(lStatus);
575 }
576
577 static jint
android_media_AudioEffect_native_getParameter(JNIEnv * env,jobject thiz,jint psize,jbyteArray pJavaParam,jint vsize,jbyteArray pJavaValue)578 android_media_AudioEffect_native_getParameter(JNIEnv *env,
579 jobject thiz, jint psize, jbyteArray pJavaParam,
580 jint vsize, jbyteArray pJavaValue) {
581 // retrieve the AudioEffect object
582 jbyte* lpParam = NULL;
583 jbyte* lpValue = NULL;
584 jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
585 effect_param_t *p;
586 int voffset;
587
588 AudioEffect* lpAudioEffect = (AudioEffect *) env->GetLongField(thiz,
589 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
597 if (psize == 0 || vsize == 0 || pJavaParam == NULL || pJavaValue == NULL) {
598 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) {
604 ALOGE("getParameter: Error retrieving param pointer");
605 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) {
611 ALOGE("getParameter: Error retrieving value pointer");
612 goto getParameter_Exit;
613 }
614
615 voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int);
616 p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset + vsize);
617 memcpy(p->data, lpParam, psize);
618 p->psize = psize;
619 p->vsize = vsize;
620
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);
626 vsize = p->vsize;
627 }
628 }
629
630 free(p);
631
632 getParameter_Exit:
633
634 if (lpParam != NULL) {
635 env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0);
636 }
637 if (lpValue != NULL) {
638 env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
639 }
640
641 if (lStatus == NO_ERROR) {
642 return vsize;
643 }
644 return (jint) translateError(lStatus);
645 }
646
android_media_AudioEffect_native_command(JNIEnv * env,jobject thiz,jint cmdCode,jint cmdSize,jbyteArray jCmdData,jint replySize,jbyteArray jReplyData)647 static jint android_media_AudioEffect_native_command(JNIEnv *env, jobject thiz,
648 jint cmdCode, jint cmdSize, jbyteArray jCmdData, jint replySize,
649 jbyteArray jReplyData) {
650 jbyte* pCmdData = NULL;
651 jbyte* pReplyData = NULL;
652 jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
653
654 // retrieve the AudioEffect object
655 AudioEffect* lpAudioEffect = (AudioEffect *) env->GetLongField(thiz,
656 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
664 if ((cmdSize != 0 && jCmdData == NULL) || (replySize != 0 && jReplyData == NULL)) {
665 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) {
672 ALOGE("setParameter: Error retrieving command pointer");
673 goto command_Exit;
674 }
675 }
676
677 // get the pointer for the reply from the java array
678 if (replySize != 0 && jReplyData != NULL) {
679 pReplyData = (jbyte *) env->GetPrimitiveArrayCritical(jReplyData, NULL);
680 if (pReplyData == NULL) {
681 ALOGE("setParameter: Error retrieving reply pointer");
682 goto command_Exit;
683 }
684 }
685
686 lStatus = translateError(lpAudioEffect->command((uint32_t)cmdCode,
687 (uint32_t)cmdSize,
688 pCmdData,
689 (uint32_t *)&replySize,
690 pReplyData));
691
692 command_Exit:
693
694 if (pCmdData != NULL) {
695 env->ReleasePrimitiveArrayCritical(jCmdData, pCmdData, 0);
696 }
697 if (pReplyData != NULL) {
698 env->ReleasePrimitiveArrayCritical(jReplyData, pReplyData, 0);
699 }
700
701 if (lStatus == NO_ERROR) {
702 return replySize;
703 }
704 return lStatus;
705 }
706
707 static jobjectArray
android_media_AudioEffect_native_queryEffects(JNIEnv * env,jclass clazz __unused)708 android_media_AudioEffect_native_queryEffects(JNIEnv *env, jclass clazz __unused)
709 {
710 effect_descriptor_t desc;
711 char str[EFFECT_STRING_LEN_MAX];
712 uint32_t totalEffectsCount = 0;
713 uint32_t returnedEffectsCount = 0;
714 uint32_t i = 0;
715 jstring jdescType;
716 jstring jdescUuid;
717 jstring jdescConnect;
718 jstring jdescName;
719 jstring jdescImplementor;
720 jobject jdesc;
721 jobjectArray ret;
722
723 if (AudioEffect::queryNumberEffects(&totalEffectsCount) != NO_ERROR) {
724 return NULL;
725 }
726
727 jobjectArray temp = env->NewObjectArray(totalEffectsCount, fields.clazzDesc, NULL);
728 if (temp == NULL) {
729 return temp;
730 }
731
732 ALOGV("queryEffects() totalEffectsCount: %d", totalEffectsCount);
733
734 for (i = 0; i < totalEffectsCount; i++) {
735 if (AudioEffect::queryEffect(i, &desc) != NO_ERROR) {
736 goto queryEffects_failure;
737 }
738
739 if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
740 jdescConnect = env->NewStringUTF("Auxiliary");
741 } else if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_INSERT) {
742 jdescConnect = env->NewStringUTF("Insert");
743 } else if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC) {
744 jdescConnect = env->NewStringUTF("Pre Processing");
745 } else {
746 continue;
747 }
748
749 AudioEffect::guidToString(&desc.type, str, EFFECT_STRING_LEN_MAX);
750 jdescType = env->NewStringUTF(str);
751
752 AudioEffect::guidToString(&desc.uuid, str, EFFECT_STRING_LEN_MAX);
753 jdescUuid = env->NewStringUTF(str);
754
755 jdescName = env->NewStringUTF(desc.name);
756 jdescImplementor = env->NewStringUTF(desc.implementor);
757
758 jdesc = env->NewObject(fields.clazzDesc,
759 fields.midDescCstor,
760 jdescType,
761 jdescUuid,
762 jdescConnect,
763 jdescName,
764 jdescImplementor);
765 env->DeleteLocalRef(jdescType);
766 env->DeleteLocalRef(jdescUuid);
767 env->DeleteLocalRef(jdescConnect);
768 env->DeleteLocalRef(jdescName);
769 env->DeleteLocalRef(jdescImplementor);
770 if (jdesc == NULL) {
771 ALOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)");
772 goto queryEffects_failure;
773 }
774
775 env->SetObjectArrayElement(temp, returnedEffectsCount++, jdesc);
776 }
777
778 if (returnedEffectsCount == 0) {
779 goto queryEffects_failure;
780 }
781 ret = env->NewObjectArray(returnedEffectsCount, fields.clazzDesc, NULL);
782 if (ret == NULL) {
783 goto queryEffects_failure;
784 }
785 for (i = 0; i < returnedEffectsCount; i++) {
786 env->SetObjectArrayElement(ret, i, env->GetObjectArrayElement(temp, i));
787 }
788 env->DeleteLocalRef(temp);
789 return ret;
790
791 queryEffects_failure:
792
793 if (temp != NULL) {
794 env->DeleteLocalRef(temp);
795 }
796 return NULL;
797
798 }
799
800
801
802 static jobjectArray
android_media_AudioEffect_native_queryPreProcessings(JNIEnv * env,jclass clazz __unused,jint audioSession)803 android_media_AudioEffect_native_queryPreProcessings(JNIEnv *env, jclass clazz __unused,
804 jint audioSession)
805 {
806 effect_descriptor_t *descriptors = new effect_descriptor_t[AudioEffect::kMaxPreProcessing];
807 uint32_t numEffects = AudioEffect::kMaxPreProcessing;
808
809 status_t status = AudioEffect::queryDefaultPreProcessing(audioSession,
810 descriptors,
811 &numEffects);
812 if (status != NO_ERROR || numEffects == 0) {
813 delete[] descriptors;
814 return NULL;
815 }
816 ALOGV("queryDefaultPreProcessing() got %d effects", numEffects);
817
818 jobjectArray ret = env->NewObjectArray(numEffects, fields.clazzDesc, NULL);
819 if (ret == NULL) {
820 delete[] descriptors;
821 return ret;
822 }
823
824 char str[EFFECT_STRING_LEN_MAX];
825 jstring jdescType;
826 jstring jdescUuid;
827 jstring jdescConnect;
828 jstring jdescName;
829 jstring jdescImplementor;
830 jobject jdesc;
831
832 for (uint32_t i = 0; i < numEffects; i++) {
833
834 AudioEffect::guidToString(&descriptors[i].type, str, EFFECT_STRING_LEN_MAX);
835 jdescType = env->NewStringUTF(str);
836 AudioEffect::guidToString(&descriptors[i].uuid, str, EFFECT_STRING_LEN_MAX);
837 jdescUuid = env->NewStringUTF(str);
838 jdescConnect = env->NewStringUTF("Pre Processing");
839 jdescName = env->NewStringUTF(descriptors[i].name);
840 jdescImplementor = env->NewStringUTF(descriptors[i].implementor);
841
842 jdesc = env->NewObject(fields.clazzDesc,
843 fields.midDescCstor,
844 jdescType,
845 jdescUuid,
846 jdescConnect,
847 jdescName,
848 jdescImplementor);
849 env->DeleteLocalRef(jdescType);
850 env->DeleteLocalRef(jdescUuid);
851 env->DeleteLocalRef(jdescConnect);
852 env->DeleteLocalRef(jdescName);
853 env->DeleteLocalRef(jdescImplementor);
854 if (jdesc == NULL) {
855 ALOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)");
856 env->DeleteLocalRef(ret);
857 return NULL;;
858 }
859
860 env->SetObjectArrayElement(ret, i, jdesc);
861 }
862
863 return ret;
864 }
865
866 // ----------------------------------------------------------------------------
867
868 // Dalvik VM type signatures
869 static JNINativeMethod gMethods[] = {
870 {"native_init", "()V", (void *)android_media_AudioEffect_native_init},
871 {"native_setup", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;II[I[Ljava/lang/Object;)I",
872 (void *)android_media_AudioEffect_native_setup},
873 {"native_finalize", "()V", (void *)android_media_AudioEffect_native_finalize},
874 {"native_release", "()V", (void *)android_media_AudioEffect_native_release},
875 {"native_setEnabled", "(Z)I", (void *)android_media_AudioEffect_native_setEnabled},
876 {"native_getEnabled", "()Z", (void *)android_media_AudioEffect_native_getEnabled},
877 {"native_hasControl", "()Z", (void *)android_media_AudioEffect_native_hasControl},
878 {"native_setParameter", "(I[BI[B)I", (void *)android_media_AudioEffect_native_setParameter},
879 {"native_getParameter", "(I[BI[B)I", (void *)android_media_AudioEffect_native_getParameter},
880 {"native_command", "(II[BI[B)I", (void *)android_media_AudioEffect_native_command},
881 {"native_query_effects", "()[Ljava/lang/Object;", (void *)android_media_AudioEffect_native_queryEffects},
882 {"native_query_pre_processing", "(I)[Ljava/lang/Object;",
883 (void *)android_media_AudioEffect_native_queryPreProcessings},
884 };
885
886
887 // ----------------------------------------------------------------------------
888
889 extern int register_android_media_visualizer(JNIEnv *env);
890
register_android_media_AudioEffect(JNIEnv * env)891 int register_android_media_AudioEffect(JNIEnv *env)
892 {
893 return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
894 }
895
JNI_OnLoad(JavaVM * vm,void * reserved __unused)896 jint JNI_OnLoad(JavaVM* vm, void* reserved __unused)
897 {
898
899 JNIEnv* env = NULL;
900 jint result = -1;
901
902 if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
903 ALOGE("ERROR: GetEnv failed\n");
904 goto bail;
905 }
906 assert(env != NULL);
907
908 if (register_android_media_AudioEffect(env) < 0) {
909 ALOGE("ERROR: AudioEffect native registration failed\n");
910 goto bail;
911 }
912
913 if (register_android_media_visualizer(env) < 0) {
914 ALOGE("ERROR: Visualizer native registration failed\n");
915 goto bail;
916 }
917
918 /* success -- return valid version number */
919 result = JNI_VERSION_1_4;
920
921 bail:
922 return result;
923 }
924
925