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", "I");
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", "I");
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->SetIntField(thiz, fields.fidNativeAudioEffect, (int)lpAudioEffect);
392
393 env->SetIntField(thiz, fields.fidJniData, (int)lpJniStorage);
394
395 return 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->SetIntField(thiz, fields.fidNativeAudioEffect, 0);
408
409 if (lpJniStorage) {
410 delete lpJniStorage;
411 }
412 env->SetIntField(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 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: %x\n", (int)thiz);
429
430 // delete the AudioEffect object
431 AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
432 thiz, fields.fidNativeAudioEffect);
433 if (lpAudioEffect) {
434 ALOGV("deleting AudioEffect: %x\n", (int)lpAudioEffect);
435 delete lpAudioEffect;
436 }
437
438 // delete the JNI data
439 AudioEffectJniStorage* lpJniStorage = (AudioEffectJniStorage *)env->GetIntField(
440 thiz, fields.fidJniData);
441 if (lpJniStorage) {
442 ALOGV("deleting pJniStorage: %x\n", (int)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->SetIntField(thiz, fields.fidNativeAudioEffect, 0);
455 env->SetIntField(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->GetIntField(
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 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->GetIntField(
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 false;
485 }
486
487 return (jboolean)lpAudioEffect->getEnabled();
488 }
489
490
491 static jboolean
android_media_AudioEffect_native_hasControl(JNIEnv * env,jobject thiz)492 android_media_AudioEffect_native_hasControl(JNIEnv *env, jobject thiz)
493 {
494 // retrieve the AudioEffect object
495 AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
496 thiz, fields.fidNativeAudioEffect);
497
498 if (lpAudioEffect == NULL) {
499 jniThrowException(env, "java/lang/IllegalStateException",
500 "Unable to retrieve AudioEffect pointer for hasControl()");
501 return false;
502 }
503
504 if (lpAudioEffect->initCheck() == NO_ERROR) {
505 return true;
506 } else {
507 return false;
508 }
509 }
510
android_media_AudioEffect_native_setParameter(JNIEnv * env,jobject thiz,int psize,jbyteArray pJavaParam,int vsize,jbyteArray pJavaValue)511 static jint android_media_AudioEffect_native_setParameter(JNIEnv *env,
512 jobject thiz, int psize, jbyteArray pJavaParam, int vsize,
513 jbyteArray pJavaValue) {
514 // retrieve the AudioEffect object
515 jbyte* lpValue = NULL;
516 jbyte* lpParam = NULL;
517 jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
518 effect_param_t *p;
519 int voffset;
520
521 AudioEffect* lpAudioEffect = (AudioEffect *) env->GetIntField(thiz,
522 fields.fidNativeAudioEffect);
523
524 if (lpAudioEffect == NULL) {
525 jniThrowException(env, "java/lang/IllegalStateException",
526 "Unable to retrieve AudioEffect pointer for setParameter()");
527 return AUDIOEFFECT_ERROR_NO_INIT;
528 }
529
530 if (psize == 0 || vsize == 0 || pJavaParam == NULL || pJavaValue == NULL) {
531 return AUDIOEFFECT_ERROR_BAD_VALUE;
532 }
533
534 // get the pointer for the param from the java array
535 lpParam = (jbyte *) env->GetPrimitiveArrayCritical(pJavaParam, NULL);
536 if (lpParam == NULL) {
537 ALOGE("setParameter: Error retrieving param pointer");
538 goto setParameter_Exit;
539 }
540
541 // get the pointer for the value from the java array
542 lpValue = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValue, NULL);
543 if (lpValue == NULL) {
544 ALOGE("setParameter: Error retrieving value pointer");
545 goto setParameter_Exit;
546 }
547
548 voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int);
549 p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset + vsize);
550 memcpy(p->data, lpParam, psize);
551 p->psize = psize;
552 memcpy(p->data + voffset, lpValue, vsize);
553 p->vsize = vsize;
554
555 lStatus = lpAudioEffect->setParameter(p);
556 if (lStatus == NO_ERROR) {
557 lStatus = p->status;
558 }
559
560 free(p);
561
562 setParameter_Exit:
563
564 if (lpParam != NULL) {
565 env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0);
566 }
567 if (lpValue != NULL) {
568 env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
569 }
570 return translateError(lStatus);
571 }
572
573 static jint
android_media_AudioEffect_native_getParameter(JNIEnv * env,jobject thiz,jint psize,jbyteArray pJavaParam,jint vsize,jbyteArray pJavaValue)574 android_media_AudioEffect_native_getParameter(JNIEnv *env,
575 jobject thiz, jint psize, jbyteArray pJavaParam,
576 jint vsize, jbyteArray pJavaValue) {
577 // retrieve the AudioEffect object
578 jbyte* lpParam = NULL;
579 jbyte* lpValue = NULL;
580 jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
581 effect_param_t *p;
582 int voffset;
583
584 AudioEffect* lpAudioEffect = (AudioEffect *) env->GetIntField(thiz,
585 fields.fidNativeAudioEffect);
586
587 if (lpAudioEffect == NULL) {
588 jniThrowException(env, "java/lang/IllegalStateException",
589 "Unable to retrieve AudioEffect pointer for getParameter()");
590 return AUDIOEFFECT_ERROR_NO_INIT;
591 }
592
593 if (psize == 0 || vsize == 0 || pJavaParam == NULL || pJavaValue == NULL) {
594 return AUDIOEFFECT_ERROR_BAD_VALUE;
595 }
596
597 // get the pointer for the param from the java array
598 lpParam = (jbyte *) env->GetPrimitiveArrayCritical(pJavaParam, NULL);
599 if (lpParam == NULL) {
600 ALOGE("getParameter: Error retrieving param pointer");
601 goto getParameter_Exit;
602 }
603
604 // get the pointer for the value from the java array
605 lpValue = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValue, NULL);
606 if (lpValue == NULL) {
607 ALOGE("getParameter: Error retrieving value pointer");
608 goto getParameter_Exit;
609 }
610
611 voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int);
612 p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset + vsize);
613 memcpy(p->data, lpParam, psize);
614 p->psize = psize;
615 p->vsize = vsize;
616
617 lStatus = lpAudioEffect->getParameter(p);
618 if (lStatus == NO_ERROR) {
619 lStatus = p->status;
620 if (lStatus == NO_ERROR) {
621 memcpy(lpValue, p->data + voffset, p->vsize);
622 vsize = p->vsize;
623 }
624 }
625
626 free(p);
627
628 getParameter_Exit:
629
630 if (lpParam != NULL) {
631 env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0);
632 }
633 if (lpValue != NULL) {
634 env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
635 }
636
637 if (lStatus == NO_ERROR) {
638 return vsize;
639 }
640 return translateError(lStatus);
641 }
642
android_media_AudioEffect_native_command(JNIEnv * env,jobject thiz,jint cmdCode,jint cmdSize,jbyteArray jCmdData,jint replySize,jbyteArray jReplyData)643 static jint android_media_AudioEffect_native_command(JNIEnv *env, jobject thiz,
644 jint cmdCode, jint cmdSize, jbyteArray jCmdData, jint replySize,
645 jbyteArray jReplyData) {
646 jbyte* pCmdData = NULL;
647 jbyte* pReplyData = NULL;
648 jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
649
650 // retrieve the AudioEffect object
651 AudioEffect* lpAudioEffect = (AudioEffect *) env->GetIntField(thiz,
652 fields.fidNativeAudioEffect);
653
654 if (lpAudioEffect == NULL) {
655 jniThrowException(env, "java/lang/IllegalStateException",
656 "Unable to retrieve AudioEffect pointer for setParameter()");
657 return AUDIOEFFECT_ERROR_NO_INIT;
658 }
659
660 if ((cmdSize != 0 && jCmdData == NULL) || (replySize != 0 && jReplyData == NULL)) {
661 return AUDIOEFFECT_ERROR_BAD_VALUE;
662 }
663
664 // get the pointer for the command from the java array
665 if (cmdSize != 0) {
666 pCmdData = (jbyte *) env->GetPrimitiveArrayCritical(jCmdData, NULL);
667 if (pCmdData == NULL) {
668 ALOGE("setParameter: Error retrieving command pointer");
669 goto command_Exit;
670 }
671 }
672
673 // get the pointer for the reply from the java array
674 if (replySize != 0 && jReplyData != NULL) {
675 pReplyData = (jbyte *) env->GetPrimitiveArrayCritical(jReplyData, NULL);
676 if (pReplyData == NULL) {
677 ALOGE("setParameter: Error retrieving reply pointer");
678 goto command_Exit;
679 }
680 }
681
682 lStatus = translateError(lpAudioEffect->command((uint32_t)cmdCode,
683 (uint32_t)cmdSize,
684 pCmdData,
685 (uint32_t *)&replySize,
686 pReplyData));
687
688 command_Exit:
689
690 if (pCmdData != NULL) {
691 env->ReleasePrimitiveArrayCritical(jCmdData, pCmdData, 0);
692 }
693 if (pReplyData != NULL) {
694 env->ReleasePrimitiveArrayCritical(jReplyData, pReplyData, 0);
695 }
696
697 if (lStatus == NO_ERROR) {
698 return replySize;
699 }
700 return lStatus;
701 }
702
703 static jobjectArray
android_media_AudioEffect_native_queryEffects(JNIEnv * env,jclass clazz)704 android_media_AudioEffect_native_queryEffects(JNIEnv *env, jclass clazz)
705 {
706 effect_descriptor_t desc;
707 char str[EFFECT_STRING_LEN_MAX];
708 uint32_t numEffects = 0;
709 uint32_t i = 0;
710 jstring jdescType;
711 jstring jdescUuid;
712 jstring jdescConnect;
713 jstring jdescName;
714 jstring jdescImplementor;
715 jobject jdesc;
716
717 if (AudioEffect::queryNumberEffects(&numEffects) != NO_ERROR) {
718 return NULL;
719 }
720
721 jobjectArray ret = env->NewObjectArray(numEffects, fields.clazzDesc, NULL);
722 if (ret == NULL) {
723 return ret;
724 }
725
726 ALOGV("queryEffects() numEffects: %d", numEffects);
727
728 for (i = 0; i < numEffects; i++) {
729 if (AudioEffect::queryEffect(i, &desc) != NO_ERROR) {
730 goto queryEffects_failure;
731 }
732
733 if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
734 jdescConnect = env->NewStringUTF("Auxiliary");
735 } else if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_INSERT) {
736 jdescConnect = env->NewStringUTF("Insert");
737 } else if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC) {
738 jdescConnect = env->NewStringUTF("Pre Processing");
739 } else {
740 continue;
741 }
742
743 AudioEffect::guidToString(&desc.type, str, EFFECT_STRING_LEN_MAX);
744 jdescType = env->NewStringUTF(str);
745
746 AudioEffect::guidToString(&desc.uuid, str, EFFECT_STRING_LEN_MAX);
747 jdescUuid = env->NewStringUTF(str);
748
749 jdescName = env->NewStringUTF(desc.name);
750 jdescImplementor = env->NewStringUTF(desc.implementor);
751
752 jdesc = env->NewObject(fields.clazzDesc,
753 fields.midDescCstor,
754 jdescType,
755 jdescUuid,
756 jdescConnect,
757 jdescName,
758 jdescImplementor);
759 env->DeleteLocalRef(jdescType);
760 env->DeleteLocalRef(jdescUuid);
761 env->DeleteLocalRef(jdescConnect);
762 env->DeleteLocalRef(jdescName);
763 env->DeleteLocalRef(jdescImplementor);
764 if (jdesc == NULL) {
765 ALOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)");
766 goto queryEffects_failure;
767 }
768
769 env->SetObjectArrayElement(ret, i, jdesc);
770 }
771
772 return ret;
773
774 queryEffects_failure:
775
776 if (ret != NULL) {
777 env->DeleteLocalRef(ret);
778 }
779 return NULL;
780
781 }
782
783
784
785 static jobjectArray
android_media_AudioEffect_native_queryPreProcessings(JNIEnv * env,jclass clazz,jint audioSession)786 android_media_AudioEffect_native_queryPreProcessings(JNIEnv *env, jclass clazz, jint audioSession)
787 {
788 // kDefaultNumEffects is a "reasonable" value ensuring that only one query will be enough on
789 // most devices to get all active audio pre processing on a given session.
790 static const uint32_t kDefaultNumEffects = 5;
791
792 effect_descriptor_t *descriptors = new effect_descriptor_t[kDefaultNumEffects];
793 uint32_t numEffects = kDefaultNumEffects;
794
795 status_t status = AudioEffect::queryDefaultPreProcessing(audioSession,
796 descriptors,
797 &numEffects);
798 if ((status != NO_ERROR && status != NO_MEMORY) ||
799 numEffects == 0) {
800 delete[] descriptors;
801 return NULL;
802 }
803 if (status == NO_MEMORY) {
804 delete [] descriptors;
805 descriptors = new effect_descriptor_t[numEffects];
806 status = AudioEffect::queryDefaultPreProcessing(audioSession,
807 descriptors,
808 &numEffects);
809 }
810 if (status != NO_ERROR || numEffects == 0) {
811 delete[] descriptors;
812 return NULL;
813 }
814 ALOGV("queryDefaultPreProcessing() got %d effects", numEffects);
815
816 jobjectArray ret = env->NewObjectArray(numEffects, fields.clazzDesc, NULL);
817 if (ret == NULL) {
818 delete[] descriptors;
819 return ret;
820 }
821
822 char str[EFFECT_STRING_LEN_MAX];
823 jstring jdescType;
824 jstring jdescUuid;
825 jstring jdescConnect;
826 jstring jdescName;
827 jstring jdescImplementor;
828 jobject jdesc;
829
830 for (uint32_t i = 0; i < numEffects; i++) {
831
832 AudioEffect::guidToString(&descriptors[i].type, str, EFFECT_STRING_LEN_MAX);
833 jdescType = env->NewStringUTF(str);
834 AudioEffect::guidToString(&descriptors[i].uuid, str, EFFECT_STRING_LEN_MAX);
835 jdescUuid = env->NewStringUTF(str);
836 jdescConnect = env->NewStringUTF("Pre Processing");
837 jdescName = env->NewStringUTF(descriptors[i].name);
838 jdescImplementor = env->NewStringUTF(descriptors[i].implementor);
839
840 jdesc = env->NewObject(fields.clazzDesc,
841 fields.midDescCstor,
842 jdescType,
843 jdescUuid,
844 jdescConnect,
845 jdescName,
846 jdescImplementor);
847 env->DeleteLocalRef(jdescType);
848 env->DeleteLocalRef(jdescUuid);
849 env->DeleteLocalRef(jdescConnect);
850 env->DeleteLocalRef(jdescName);
851 env->DeleteLocalRef(jdescImplementor);
852 if (jdesc == NULL) {
853 ALOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)");
854 env->DeleteLocalRef(ret);
855 return NULL;;
856 }
857
858 env->SetObjectArrayElement(ret, i, jdesc);
859 }
860
861 return ret;
862 }
863
864 // ----------------------------------------------------------------------------
865
866 // Dalvik VM type signatures
867 static JNINativeMethod gMethods[] = {
868 {"native_init", "()V", (void *)android_media_AudioEffect_native_init},
869 {"native_setup", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;II[I[Ljava/lang/Object;)I",
870 (void *)android_media_AudioEffect_native_setup},
871 {"native_finalize", "()V", (void *)android_media_AudioEffect_native_finalize},
872 {"native_release", "()V", (void *)android_media_AudioEffect_native_release},
873 {"native_setEnabled", "(Z)I", (void *)android_media_AudioEffect_native_setEnabled},
874 {"native_getEnabled", "()Z", (void *)android_media_AudioEffect_native_getEnabled},
875 {"native_hasControl", "()Z", (void *)android_media_AudioEffect_native_hasControl},
876 {"native_setParameter", "(I[BI[B)I", (void *)android_media_AudioEffect_native_setParameter},
877 {"native_getParameter", "(I[BI[B)I", (void *)android_media_AudioEffect_native_getParameter},
878 {"native_command", "(II[BI[B)I", (void *)android_media_AudioEffect_native_command},
879 {"native_query_effects", "()[Ljava/lang/Object;", (void *)android_media_AudioEffect_native_queryEffects},
880 {"native_query_pre_processing", "(I)[Ljava/lang/Object;",
881 (void *)android_media_AudioEffect_native_queryPreProcessings},
882 };
883
884
885 // ----------------------------------------------------------------------------
886
887 extern int register_android_media_visualizer(JNIEnv *env);
888
register_android_media_AudioEffect(JNIEnv * env)889 int register_android_media_AudioEffect(JNIEnv *env)
890 {
891 return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
892 }
893
JNI_OnLoad(JavaVM * vm,void * reserved)894 jint JNI_OnLoad(JavaVM* vm, void* reserved)
895 {
896
897 JNIEnv* env = NULL;
898 jint result = -1;
899
900 if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
901 ALOGE("ERROR: GetEnv failed\n");
902 goto bail;
903 }
904 assert(env != NULL);
905
906 if (register_android_media_AudioEffect(env) < 0) {
907 ALOGE("ERROR: AudioEffect native registration failed\n");
908 goto bail;
909 }
910
911 if (register_android_media_visualizer(env) < 0) {
912 ALOGE("ERROR: Visualizer native registration failed\n");
913 goto bail;
914 }
915
916 /* success -- return valid version number */
917 result = JNI_VERSION_1_4;
918
919 bail:
920 return result;
921 }
922
923