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 <jni.h>
24 #include <nativehelper/JNIHelp.h>
25 #include <android_runtime/AndroidRuntime.h>
26 #include "media/AudioEffect.h"
27
28 #include <nativehelper/ScopedUtfChars.h>
29
30 using namespace android;
31
32 #define AUDIOEFFECT_SUCCESS 0
33 #define AUDIOEFFECT_ERROR (-1)
34 #define AUDIOEFFECT_ERROR_ALREADY_EXISTS (-2)
35 #define AUDIOEFFECT_ERROR_NO_INIT (-3)
36 #define AUDIOEFFECT_ERROR_BAD_VALUE (-4)
37 #define AUDIOEFFECT_ERROR_INVALID_OPERATION (-5)
38 #define AUDIOEFFECT_ERROR_NO_MEMORY (-6)
39 #define AUDIOEFFECT_ERROR_DEAD_OBJECT (-7)
40
41 // ----------------------------------------------------------------------------
42 static const char* const kClassPathName = "android/media/audiofx/AudioEffect";
43
44 struct fields_t {
45 // these fields provide access from C++ to the...
46 jclass clazzEffect; // AudioEffect class
47 jmethodID midPostNativeEvent; // event post callback method
48 jfieldID fidNativeAudioEffect; // stores in Java the native AudioEffect object
49 jfieldID fidJniData; // stores in Java additional resources used by the native AudioEffect
50 jclass clazzDesc; // AudioEffect.Descriptor class
51 jmethodID midDescCstor; // AudioEffect.Descriptor class constructor
52 };
53 static fields_t fields;
54
55 struct effect_callback_cookie {
56 jclass audioEffect_class; // AudioEffect class
57 jobject audioEffect_ref; // AudioEffect object instance
58 };
59
60 // ----------------------------------------------------------------------------
61 class AudioEffectJniStorage {
62 public:
63 effect_callback_cookie mCallbackData;
64
AudioEffectJniStorage()65 AudioEffectJniStorage() {
66 }
67
~AudioEffectJniStorage()68 ~AudioEffectJniStorage() {
69 }
70
71 };
72
73
translateError(int code)74 static jint translateError(int code) {
75 switch(code) {
76 case NO_ERROR:
77 return AUDIOEFFECT_SUCCESS;
78 case ALREADY_EXISTS:
79 return AUDIOEFFECT_ERROR_ALREADY_EXISTS;
80 case NO_INIT:
81 return AUDIOEFFECT_ERROR_NO_INIT;
82 case BAD_VALUE:
83 return AUDIOEFFECT_ERROR_BAD_VALUE;
84 case INVALID_OPERATION:
85 return AUDIOEFFECT_ERROR_INVALID_OPERATION;
86 case NO_MEMORY:
87 return AUDIOEFFECT_ERROR_NO_MEMORY;
88 case DEAD_OBJECT:
89 case FAILED_TRANSACTION: // Hidl crash shows as FAILED_TRANSACTION: -2147483646
90 return AUDIOEFFECT_ERROR_DEAD_OBJECT;
91 default:
92 return AUDIOEFFECT_ERROR;
93 }
94 }
95
96 static Mutex sLock;
97
98 // ----------------------------------------------------------------------------
effectCallback(int event,void * user,void * info)99 static void effectCallback(int event, void* user, void *info) {
100
101 effect_param_t *p;
102 int arg1 = 0;
103 int arg2 = 0;
104 jobject obj = NULL;
105 jbyteArray array = NULL;
106 jbyte *bytes;
107 bool param;
108 size_t size;
109
110 effect_callback_cookie *callbackInfo = (effect_callback_cookie *)user;
111 JNIEnv *env = AndroidRuntime::getJNIEnv();
112
113 ALOGV("effectCallback: callbackInfo %p, audioEffect_ref %p audioEffect_class %p",
114 callbackInfo,
115 callbackInfo->audioEffect_ref,
116 callbackInfo->audioEffect_class);
117
118 if (!user || !env) {
119 ALOGW("effectCallback error user %p, env %p", user, env);
120 return;
121 }
122
123 switch (event) {
124 case AudioEffect::EVENT_CONTROL_STATUS_CHANGED:
125 if (info == 0) {
126 ALOGW("EVENT_CONTROL_STATUS_CHANGED info == NULL");
127 goto effectCallback_Exit;
128 }
129 param = *(bool *)info;
130 arg1 = (int)param;
131 ALOGV("EVENT_CONTROL_STATUS_CHANGED");
132 break;
133 case AudioEffect::EVENT_ENABLE_STATUS_CHANGED:
134 if (info == 0) {
135 ALOGW("EVENT_ENABLE_STATUS_CHANGED info == NULL");
136 goto effectCallback_Exit;
137 }
138 param = *(bool *)info;
139 arg1 = (int)param;
140 ALOGV("EVENT_ENABLE_STATUS_CHANGED");
141 break;
142 case AudioEffect::EVENT_PARAMETER_CHANGED:
143 if (info == 0) {
144 ALOGW("EVENT_PARAMETER_CHANGED info == NULL");
145 goto effectCallback_Exit;
146 }
147 p = (effect_param_t *)info;
148 if (p->psize == 0 || p->vsize == 0) {
149 goto effectCallback_Exit;
150 }
151 // arg1 contains offset of parameter value from start of byte array
152 arg1 = sizeof(effect_param_t) + ((p->psize - 1) / sizeof(int) + 1) * sizeof(int);
153 size = arg1 + p->vsize;
154 array = env->NewByteArray(size);
155 if (array == NULL) {
156 ALOGE("effectCallback: Couldn't allocate byte array for parameter data");
157 goto effectCallback_Exit;
158 }
159 bytes = env->GetByteArrayElements(array, NULL);
160 memcpy(bytes, p, size);
161 env->ReleaseByteArrayElements(array, bytes, 0);
162 obj = array;
163 ALOGV("EVENT_PARAMETER_CHANGED");
164 break;
165 case AudioEffect::EVENT_ERROR:
166 ALOGW("EVENT_ERROR");
167 break;
168 }
169
170 env->CallStaticVoidMethod(
171 callbackInfo->audioEffect_class,
172 fields.midPostNativeEvent,
173 callbackInfo->audioEffect_ref, event, arg1, arg2, obj);
174
175 effectCallback_Exit:
176 if (array) {
177 env->DeleteLocalRef(array);
178 }
179
180 if (env->ExceptionCheck()) {
181 env->ExceptionDescribe();
182 env->ExceptionClear();
183 }
184 }
185
186 // ----------------------------------------------------------------------------
187
getAudioEffect(JNIEnv * env,jobject thiz)188 static sp<AudioEffect> getAudioEffect(JNIEnv* env, jobject thiz)
189 {
190 Mutex::Autolock l(sLock);
191 AudioEffect* const ae =
192 (AudioEffect*)env->GetLongField(thiz, fields.fidNativeAudioEffect);
193 return sp<AudioEffect>(ae);
194 }
195
setAudioEffect(JNIEnv * env,jobject thiz,const sp<AudioEffect> & ae)196 static sp<AudioEffect> setAudioEffect(JNIEnv* env, jobject thiz,
197 const sp<AudioEffect>& ae)
198 {
199 Mutex::Autolock l(sLock);
200 sp<AudioEffect> old =
201 (AudioEffect*)env->GetLongField(thiz, fields.fidNativeAudioEffect);
202 if (ae.get()) {
203 ae->incStrong((void*)setAudioEffect);
204 }
205 if (old != 0) {
206 old->decStrong((void*)setAudioEffect);
207 }
208 env->SetLongField(thiz, fields.fidNativeAudioEffect, (jlong)ae.get());
209 return old;
210 }
211
212 // ----------------------------------------------------------------------------
213 // This function gets some field IDs, which in turn causes class initialization.
214 // It is called from a static block in AudioEffect, which won't run until the
215 // first time an instance of this class is used.
216 static void
android_media_AudioEffect_native_init(JNIEnv * env)217 android_media_AudioEffect_native_init(JNIEnv *env)
218 {
219
220 ALOGV("android_media_AudioEffect_native_init");
221
222 fields.clazzEffect = NULL;
223 fields.clazzDesc = NULL;
224
225 // Get the AudioEffect class
226 jclass clazz = env->FindClass(kClassPathName);
227 if (clazz == NULL) {
228 ALOGE("Can't find %s", kClassPathName);
229 return;
230 }
231
232 fields.clazzEffect = (jclass)env->NewGlobalRef(clazz);
233
234 // Get the postEvent method
235 fields.midPostNativeEvent = env->GetStaticMethodID(
236 fields.clazzEffect,
237 "postEventFromNative", "(Ljava/lang/Object;IIILjava/lang/Object;)V");
238 if (fields.midPostNativeEvent == NULL) {
239 ALOGE("Can't find AudioEffect.%s", "postEventFromNative");
240 return;
241 }
242
243 // Get the variables fields
244 // nativeTrackInJavaObj
245 fields.fidNativeAudioEffect = env->GetFieldID(
246 fields.clazzEffect,
247 "mNativeAudioEffect", "J");
248 if (fields.fidNativeAudioEffect == NULL) {
249 ALOGE("Can't find AudioEffect.%s", "mNativeAudioEffect");
250 return;
251 }
252 // fidJniData;
253 fields.fidJniData = env->GetFieldID(
254 fields.clazzEffect,
255 "mJniData", "J");
256 if (fields.fidJniData == NULL) {
257 ALOGE("Can't find AudioEffect.%s", "mJniData");
258 return;
259 }
260
261 clazz = env->FindClass("android/media/audiofx/AudioEffect$Descriptor");
262 if (clazz == NULL) {
263 ALOGE("Can't find android/media/audiofx/AudioEffect$Descriptor class");
264 return;
265 }
266 fields.clazzDesc = (jclass)env->NewGlobalRef(clazz);
267
268 fields.midDescCstor
269 = env->GetMethodID(
270 fields.clazzDesc,
271 "<init>",
272 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
273 if (fields.midDescCstor == NULL) {
274 ALOGE("Can't find android/media/audiofx/AudioEffect$Descriptor class constructor");
275 return;
276 }
277 }
278
279
280 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,jstring opPackageName)281 android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
282 jstring type, jstring uuid, jint priority, jint sessionId, jintArray jId,
283 jobjectArray javadesc, jstring opPackageName)
284 {
285 ALOGV("android_media_AudioEffect_native_setup");
286 AudioEffectJniStorage* lpJniStorage = NULL;
287 int lStatus = AUDIOEFFECT_ERROR_NO_MEMORY;
288 sp<AudioEffect> lpAudioEffect;
289 jint* nId = NULL;
290 const char *typeStr = NULL;
291 const char *uuidStr = NULL;
292 effect_descriptor_t desc;
293 jobject jdesc;
294 char str[EFFECT_STRING_LEN_MAX];
295 jstring jdescType;
296 jstring jdescUuid;
297 jstring jdescConnect;
298 jstring jdescName;
299 jstring jdescImplementor;
300
301 ScopedUtfChars opPackageNameStr(env, opPackageName);
302
303 setAudioEffect(env, thiz, 0);
304
305 if (type != NULL) {
306 typeStr = env->GetStringUTFChars(type, NULL);
307 if (typeStr == NULL) { // Out of memory
308 jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
309 goto setup_failure;
310 }
311 }
312
313 if (uuid != NULL) {
314 uuidStr = env->GetStringUTFChars(uuid, NULL);
315 if (uuidStr == NULL) { // Out of memory
316 jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
317 goto setup_failure;
318 }
319 }
320
321 if (typeStr == NULL && uuidStr == NULL) {
322 lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
323 goto setup_failure;
324 }
325
326 lpJniStorage = new AudioEffectJniStorage();
327 if (lpJniStorage == NULL) {
328 ALOGE("setup: Error creating JNI Storage");
329 goto setup_failure;
330 }
331
332 lpJniStorage->mCallbackData.audioEffect_class = (jclass)env->NewGlobalRef(fields.clazzEffect);
333 // we use a weak reference so the AudioEffect object can be garbage collected.
334 lpJniStorage->mCallbackData.audioEffect_ref = env->NewGlobalRef(weak_this);
335
336 ALOGV("setup: lpJniStorage: %p audioEffect_ref %p audioEffect_class %p, &mCallbackData %p",
337 lpJniStorage,
338 lpJniStorage->mCallbackData.audioEffect_ref,
339 lpJniStorage->mCallbackData.audioEffect_class,
340 &lpJniStorage->mCallbackData);
341
342 if (jId == NULL) {
343 ALOGE("setup: NULL java array for id pointer");
344 lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
345 goto setup_failure;
346 }
347
348 // create the native AudioEffect object
349 lpAudioEffect = new AudioEffect(typeStr,
350 String16(opPackageNameStr.c_str()),
351 uuidStr,
352 priority,
353 effectCallback,
354 &lpJniStorage->mCallbackData,
355 (audio_session_t) sessionId,
356 AUDIO_IO_HANDLE_NONE);
357 if (lpAudioEffect == 0) {
358 ALOGE("Error creating AudioEffect");
359 goto setup_failure;
360 }
361
362 lStatus = translateError(lpAudioEffect->initCheck());
363 if (lStatus != AUDIOEFFECT_SUCCESS && lStatus != AUDIOEFFECT_ERROR_ALREADY_EXISTS) {
364 ALOGE("AudioEffect initCheck failed %d", lStatus);
365 goto setup_failure;
366 }
367
368 nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL);
369 if (nId == NULL) {
370 ALOGE("setup: Error retrieving id pointer");
371 lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
372 goto setup_failure;
373 }
374 nId[0] = lpAudioEffect->id();
375 env->ReleasePrimitiveArrayCritical(jId, nId, 0);
376 nId = NULL;
377
378 if (typeStr) {
379 env->ReleaseStringUTFChars(type, typeStr);
380 typeStr = NULL;
381 }
382
383 if (uuidStr) {
384 env->ReleaseStringUTFChars(uuid, uuidStr);
385 uuidStr = NULL;
386 }
387
388 // get the effect descriptor
389 desc = lpAudioEffect->descriptor();
390
391 AudioEffect::guidToString(&desc.type, str, EFFECT_STRING_LEN_MAX);
392 jdescType = env->NewStringUTF(str);
393
394 AudioEffect::guidToString(&desc.uuid, str, EFFECT_STRING_LEN_MAX);
395 jdescUuid = env->NewStringUTF(str);
396
397 if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
398 jdescConnect = env->NewStringUTF("Auxiliary");
399 } else if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC) {
400 jdescConnect = env->NewStringUTF("Pre Processing");
401 } else {
402 jdescConnect = env->NewStringUTF("Insert");
403 }
404
405 jdescName = env->NewStringUTF(desc.name);
406 jdescImplementor = env->NewStringUTF(desc.implementor);
407
408 jdesc = env->NewObject(fields.clazzDesc,
409 fields.midDescCstor,
410 jdescType,
411 jdescUuid,
412 jdescConnect,
413 jdescName,
414 jdescImplementor);
415 env->DeleteLocalRef(jdescType);
416 env->DeleteLocalRef(jdescUuid);
417 env->DeleteLocalRef(jdescConnect);
418 env->DeleteLocalRef(jdescName);
419 env->DeleteLocalRef(jdescImplementor);
420 if (jdesc == NULL) {
421 ALOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)");
422 goto setup_failure;
423 }
424
425 env->SetObjectArrayElement(javadesc, 0, jdesc);
426
427 setAudioEffect(env, thiz, lpAudioEffect);
428
429 env->SetLongField(thiz, fields.fidJniData, (jlong)lpJniStorage);
430
431 return (jint) AUDIOEFFECT_SUCCESS;
432
433 // failures:
434 setup_failure:
435
436 if (nId != NULL) {
437 env->ReleasePrimitiveArrayCritical(jId, nId, 0);
438 }
439
440 if (lpJniStorage) {
441 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioEffect_class);
442 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioEffect_ref);
443 delete lpJniStorage;
444 }
445 env->SetLongField(thiz, fields.fidJniData, 0);
446
447 if (uuidStr != NULL) {
448 env->ReleaseStringUTFChars(uuid, uuidStr);
449 }
450
451 if (typeStr != NULL) {
452 env->ReleaseStringUTFChars(type, typeStr);
453 }
454
455 return (jint)lStatus;
456 }
457
458
459 // ----------------------------------------------------------------------------
android_media_AudioEffect_native_release(JNIEnv * env,jobject thiz)460 static void android_media_AudioEffect_native_release(JNIEnv *env, jobject thiz) {
461 sp<AudioEffect> lpAudioEffect = setAudioEffect(env, thiz, 0);
462 if (lpAudioEffect == 0) {
463 return;
464 }
465
466 // delete the JNI data
467 AudioEffectJniStorage* lpJniStorage =
468 (AudioEffectJniStorage *)env->GetLongField(thiz, fields.fidJniData);
469
470 // reset the native resources in the Java object so any attempt to access
471 // them after a call to release fails.
472 env->SetLongField(thiz, fields.fidJniData, 0);
473
474 if (lpJniStorage) {
475 ALOGV("deleting pJniStorage: %p\n", lpJniStorage);
476 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioEffect_class);
477 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioEffect_ref);
478 delete lpJniStorage;
479 }
480 }
481
482 // ----------------------------------------------------------------------------
android_media_AudioEffect_native_finalize(JNIEnv * env,jobject thiz)483 static void android_media_AudioEffect_native_finalize(JNIEnv *env, jobject thiz) {
484 ALOGV("android_media_AudioEffect_native_finalize jobject: %p\n", thiz);
485 android_media_AudioEffect_native_release(env, thiz);
486 }
487
488 static jint
android_media_AudioEffect_native_setEnabled(JNIEnv * env,jobject thiz,jboolean enabled)489 android_media_AudioEffect_native_setEnabled(JNIEnv *env, jobject thiz, jboolean enabled)
490 {
491 sp<AudioEffect> lpAudioEffect = getAudioEffect(env, thiz);
492 if (lpAudioEffect == 0) {
493 jniThrowException(env, "java/lang/IllegalStateException",
494 "Unable to retrieve AudioEffect pointer for enable()");
495 return AUDIOEFFECT_ERROR_NO_INIT;
496 }
497
498 return (jint) translateError(lpAudioEffect->setEnabled(enabled));
499 }
500
501 static jboolean
android_media_AudioEffect_native_getEnabled(JNIEnv * env,jobject thiz)502 android_media_AudioEffect_native_getEnabled(JNIEnv *env, jobject thiz)
503 {
504 sp<AudioEffect> lpAudioEffect = getAudioEffect(env, thiz);
505 if (lpAudioEffect == 0) {
506 jniThrowException(env, "java/lang/IllegalStateException",
507 "Unable to retrieve AudioEffect pointer for getEnabled()");
508 return JNI_FALSE;
509 }
510
511 if (lpAudioEffect->getEnabled()) {
512 return JNI_TRUE;
513 } else {
514 return JNI_FALSE;
515 }
516 }
517
518
519 static jboolean
android_media_AudioEffect_native_hasControl(JNIEnv * env,jobject thiz)520 android_media_AudioEffect_native_hasControl(JNIEnv *env, jobject thiz)
521 {
522 sp<AudioEffect> lpAudioEffect = getAudioEffect(env, thiz);
523 if (lpAudioEffect == 0) {
524 jniThrowException(env, "java/lang/IllegalStateException",
525 "Unable to retrieve AudioEffect pointer for hasControl()");
526 return JNI_FALSE;
527 }
528
529 if (lpAudioEffect->initCheck() == NO_ERROR) {
530 return JNI_TRUE;
531 } else {
532 return JNI_FALSE;
533 }
534 }
535
android_media_AudioEffect_native_setParameter(JNIEnv * env,jobject thiz,jint psize,jbyteArray pJavaParam,jint vsize,jbyteArray pJavaValue)536 static jint android_media_AudioEffect_native_setParameter(JNIEnv *env,
537 jobject thiz, jint psize, jbyteArray pJavaParam, jint vsize,
538 jbyteArray pJavaValue) {
539 // retrieve the AudioEffect object
540 jbyte* lpValue = NULL;
541 jbyte* lpParam = NULL;
542 jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
543 effect_param_t *p;
544 int voffset;
545
546 sp<AudioEffect> lpAudioEffect = getAudioEffect(env, thiz);
547 if (lpAudioEffect == 0) {
548 jniThrowException(env, "java/lang/IllegalStateException",
549 "Unable to retrieve AudioEffect pointer for setParameter()");
550 return AUDIOEFFECT_ERROR_NO_INIT;
551 }
552
553 if (psize == 0 || vsize == 0 || pJavaParam == NULL || pJavaValue == NULL) {
554 return AUDIOEFFECT_ERROR_BAD_VALUE;
555 }
556
557 // get the pointer for the param from the java array
558 lpParam = (jbyte *) env->GetPrimitiveArrayCritical(pJavaParam, NULL);
559 if (lpParam == NULL) {
560 ALOGE("setParameter: Error retrieving param pointer");
561 goto setParameter_Exit;
562 }
563
564 // get the pointer for the value from the java array
565 lpValue = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValue, NULL);
566 if (lpValue == NULL) {
567 ALOGE("setParameter: Error retrieving value pointer");
568 goto setParameter_Exit;
569 }
570
571 voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int);
572 p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset + vsize);
573 memcpy(p->data, lpParam, psize);
574 p->psize = psize;
575 memcpy(p->data + voffset, lpValue, vsize);
576 p->vsize = vsize;
577
578 lStatus = lpAudioEffect->setParameter(p);
579 if (lStatus == NO_ERROR) {
580 lStatus = p->status;
581 }
582
583 free(p);
584
585 setParameter_Exit:
586
587 if (lpParam != NULL) {
588 env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0);
589 }
590 if (lpValue != NULL) {
591 env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
592 }
593 return (jint) translateError(lStatus);
594 }
595
596 static jint
android_media_AudioEffect_native_getParameter(JNIEnv * env,jobject thiz,jint psize,jbyteArray pJavaParam,jint vsize,jbyteArray pJavaValue)597 android_media_AudioEffect_native_getParameter(JNIEnv *env,
598 jobject thiz, jint psize, jbyteArray pJavaParam,
599 jint vsize, jbyteArray pJavaValue) {
600 // retrieve the AudioEffect object
601 jbyte* lpParam = NULL;
602 jbyte* lpValue = NULL;
603 jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
604 effect_param_t *p;
605 int voffset;
606
607 sp<AudioEffect> lpAudioEffect = getAudioEffect(env, thiz);
608 if (lpAudioEffect == 0) {
609 jniThrowException(env, "java/lang/IllegalStateException",
610 "Unable to retrieve AudioEffect pointer for getParameter()");
611 return AUDIOEFFECT_ERROR_NO_INIT;
612 }
613
614 if (psize == 0 || vsize == 0 || pJavaParam == NULL || pJavaValue == NULL) {
615 return AUDIOEFFECT_ERROR_BAD_VALUE;
616 }
617
618 // get the pointer for the param from the java array
619 lpParam = (jbyte *) env->GetPrimitiveArrayCritical(pJavaParam, NULL);
620 if (lpParam == NULL) {
621 ALOGE("getParameter: Error retrieving param pointer");
622 goto getParameter_Exit;
623 }
624
625 // get the pointer for the value from the java array
626 lpValue = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValue, NULL);
627 if (lpValue == NULL) {
628 ALOGE("getParameter: Error retrieving value pointer");
629 goto getParameter_Exit;
630 }
631
632 voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int);
633 p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset + vsize);
634 memcpy(p->data, lpParam, psize);
635 p->psize = psize;
636 p->vsize = vsize;
637
638 lStatus = lpAudioEffect->getParameter(p);
639 if (lStatus == NO_ERROR) {
640 lStatus = p->status;
641 if (lStatus == NO_ERROR) {
642 memcpy(lpValue, p->data + voffset, p->vsize);
643 vsize = p->vsize;
644 }
645 }
646
647 free(p);
648
649 getParameter_Exit:
650
651 if (lpParam != NULL) {
652 env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0);
653 }
654 if (lpValue != NULL) {
655 env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
656 }
657
658 if (lStatus == NO_ERROR) {
659 return vsize;
660 }
661 return (jint) translateError(lStatus);
662 }
663
android_media_AudioEffect_native_command(JNIEnv * env,jobject thiz,jint cmdCode,jint cmdSize,jbyteArray jCmdData,jint replySize,jbyteArray jReplyData)664 static jint android_media_AudioEffect_native_command(JNIEnv *env, jobject thiz,
665 jint cmdCode, jint cmdSize, jbyteArray jCmdData, jint replySize,
666 jbyteArray jReplyData) {
667 jbyte* pCmdData = NULL;
668 jbyte* pReplyData = NULL;
669 jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
670
671 sp<AudioEffect> lpAudioEffect = getAudioEffect(env, thiz);
672 if (lpAudioEffect == 0) {
673 jniThrowException(env, "java/lang/IllegalStateException",
674 "Unable to retrieve AudioEffect pointer for setParameter()");
675 return AUDIOEFFECT_ERROR_NO_INIT;
676 }
677
678 if ((cmdSize != 0 && jCmdData == NULL) || (replySize != 0 && jReplyData == NULL)) {
679 return AUDIOEFFECT_ERROR_BAD_VALUE;
680 }
681
682 // get the pointer for the command from the java array
683 if (cmdSize != 0) {
684 pCmdData = (jbyte *) env->GetPrimitiveArrayCritical(jCmdData, NULL);
685 if (pCmdData == NULL) {
686 ALOGE("setParameter: Error retrieving command pointer");
687 goto command_Exit;
688 }
689 }
690
691 // get the pointer for the reply from the java array
692 if (replySize != 0 && jReplyData != NULL) {
693 pReplyData = (jbyte *) env->GetPrimitiveArrayCritical(jReplyData, NULL);
694 if (pReplyData == NULL) {
695 ALOGE("setParameter: Error retrieving reply pointer");
696 goto command_Exit;
697 }
698 }
699
700 lStatus = translateError(lpAudioEffect->command((uint32_t)cmdCode,
701 (uint32_t)cmdSize,
702 pCmdData,
703 (uint32_t *)&replySize,
704 pReplyData));
705
706 command_Exit:
707
708 if (pCmdData != NULL) {
709 env->ReleasePrimitiveArrayCritical(jCmdData, pCmdData, 0);
710 }
711 if (pReplyData != NULL) {
712 env->ReleasePrimitiveArrayCritical(jReplyData, pReplyData, 0);
713 }
714
715 if (lStatus == NO_ERROR) {
716 return replySize;
717 }
718 return lStatus;
719 }
720
721 static jobjectArray
android_media_AudioEffect_native_queryEffects(JNIEnv * env,jclass clazz __unused)722 android_media_AudioEffect_native_queryEffects(JNIEnv *env, jclass clazz __unused)
723 {
724 effect_descriptor_t desc;
725 char str[EFFECT_STRING_LEN_MAX];
726 uint32_t totalEffectsCount = 0;
727 uint32_t returnedEffectsCount = 0;
728 uint32_t i = 0;
729 jstring jdescType;
730 jstring jdescUuid;
731 jstring jdescConnect;
732 jstring jdescName;
733 jstring jdescImplementor;
734 jobject jdesc;
735 jobjectArray ret;
736
737 if (AudioEffect::queryNumberEffects(&totalEffectsCount) != NO_ERROR) {
738 return NULL;
739 }
740
741 jobjectArray temp = env->NewObjectArray(totalEffectsCount, fields.clazzDesc, NULL);
742 if (temp == NULL) {
743 return temp;
744 }
745
746 ALOGV("queryEffects() totalEffectsCount: %d", totalEffectsCount);
747
748 for (i = 0; i < totalEffectsCount; i++) {
749 if (AudioEffect::queryEffect(i, &desc) != NO_ERROR) {
750 goto queryEffects_failure;
751 }
752
753 if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
754 jdescConnect = env->NewStringUTF("Auxiliary");
755 } else if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_INSERT) {
756 jdescConnect = env->NewStringUTF("Insert");
757 } else if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC) {
758 jdescConnect = env->NewStringUTF("Pre Processing");
759 } else {
760 continue;
761 }
762
763 AudioEffect::guidToString(&desc.type, str, EFFECT_STRING_LEN_MAX);
764 jdescType = env->NewStringUTF(str);
765
766 AudioEffect::guidToString(&desc.uuid, str, EFFECT_STRING_LEN_MAX);
767 jdescUuid = env->NewStringUTF(str);
768
769 jdescName = env->NewStringUTF(desc.name);
770 jdescImplementor = env->NewStringUTF(desc.implementor);
771
772 jdesc = env->NewObject(fields.clazzDesc,
773 fields.midDescCstor,
774 jdescType,
775 jdescUuid,
776 jdescConnect,
777 jdescName,
778 jdescImplementor);
779 env->DeleteLocalRef(jdescType);
780 env->DeleteLocalRef(jdescUuid);
781 env->DeleteLocalRef(jdescConnect);
782 env->DeleteLocalRef(jdescName);
783 env->DeleteLocalRef(jdescImplementor);
784 if (jdesc == NULL) {
785 ALOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)");
786 goto queryEffects_failure;
787 }
788
789 env->SetObjectArrayElement(temp, returnedEffectsCount++, jdesc);
790 }
791
792 if (returnedEffectsCount == 0) {
793 goto queryEffects_failure;
794 }
795 ret = env->NewObjectArray(returnedEffectsCount, fields.clazzDesc, NULL);
796 if (ret == NULL) {
797 goto queryEffects_failure;
798 }
799 for (i = 0; i < returnedEffectsCount; i++) {
800 env->SetObjectArrayElement(ret, i, env->GetObjectArrayElement(temp, i));
801 }
802 env->DeleteLocalRef(temp);
803 return ret;
804
805 queryEffects_failure:
806
807 if (temp != NULL) {
808 env->DeleteLocalRef(temp);
809 }
810 return NULL;
811
812 }
813
814
815
816 static jobjectArray
android_media_AudioEffect_native_queryPreProcessings(JNIEnv * env,jclass clazz __unused,jint audioSession)817 android_media_AudioEffect_native_queryPreProcessings(JNIEnv *env, jclass clazz __unused,
818 jint audioSession)
819 {
820 effect_descriptor_t *descriptors = new effect_descriptor_t[AudioEffect::kMaxPreProcessing];
821 uint32_t numEffects = AudioEffect::kMaxPreProcessing;
822
823 status_t status = AudioEffect::queryDefaultPreProcessing((audio_session_t) audioSession,
824 descriptors,
825 &numEffects);
826 if (status != NO_ERROR || numEffects == 0) {
827 delete[] descriptors;
828 return NULL;
829 }
830 ALOGV("queryDefaultPreProcessing() got %d effects", numEffects);
831
832 jobjectArray ret = env->NewObjectArray(numEffects, fields.clazzDesc, NULL);
833 if (ret == NULL) {
834 delete[] descriptors;
835 return ret;
836 }
837
838 char str[EFFECT_STRING_LEN_MAX];
839 jstring jdescType;
840 jstring jdescUuid;
841 jstring jdescConnect;
842 jstring jdescName;
843 jstring jdescImplementor;
844 jobject jdesc;
845
846 for (uint32_t i = 0; i < numEffects; i++) {
847
848 AudioEffect::guidToString(&descriptors[i].type, str, EFFECT_STRING_LEN_MAX);
849 jdescType = env->NewStringUTF(str);
850 AudioEffect::guidToString(&descriptors[i].uuid, str, EFFECT_STRING_LEN_MAX);
851 jdescUuid = env->NewStringUTF(str);
852 jdescConnect = env->NewStringUTF("Pre Processing");
853 jdescName = env->NewStringUTF(descriptors[i].name);
854 jdescImplementor = env->NewStringUTF(descriptors[i].implementor);
855
856 jdesc = env->NewObject(fields.clazzDesc,
857 fields.midDescCstor,
858 jdescType,
859 jdescUuid,
860 jdescConnect,
861 jdescName,
862 jdescImplementor);
863 env->DeleteLocalRef(jdescType);
864 env->DeleteLocalRef(jdescUuid);
865 env->DeleteLocalRef(jdescConnect);
866 env->DeleteLocalRef(jdescName);
867 env->DeleteLocalRef(jdescImplementor);
868 if (jdesc == NULL) {
869 ALOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)");
870 env->DeleteLocalRef(ret);
871 return NULL;;
872 }
873
874 env->SetObjectArrayElement(ret, i, jdesc);
875 }
876
877 return ret;
878 }
879
880 // ----------------------------------------------------------------------------
881
882 // Dalvik VM type signatures
883 static const JNINativeMethod gMethods[] = {
884 {"native_init", "()V", (void *)android_media_AudioEffect_native_init},
885 {"native_setup", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;II[I[Ljava/lang/Object;Ljava/lang/String;)I",
886 (void *)android_media_AudioEffect_native_setup},
887 {"native_finalize", "()V", (void *)android_media_AudioEffect_native_finalize},
888 {"native_release", "()V", (void *)android_media_AudioEffect_native_release},
889 {"native_setEnabled", "(Z)I", (void *)android_media_AudioEffect_native_setEnabled},
890 {"native_getEnabled", "()Z", (void *)android_media_AudioEffect_native_getEnabled},
891 {"native_hasControl", "()Z", (void *)android_media_AudioEffect_native_hasControl},
892 {"native_setParameter", "(I[BI[B)I", (void *)android_media_AudioEffect_native_setParameter},
893 {"native_getParameter", "(I[BI[B)I", (void *)android_media_AudioEffect_native_getParameter},
894 {"native_command", "(II[BI[B)I", (void *)android_media_AudioEffect_native_command},
895 {"native_query_effects", "()[Ljava/lang/Object;", (void *)android_media_AudioEffect_native_queryEffects},
896 {"native_query_pre_processing", "(I)[Ljava/lang/Object;",
897 (void *)android_media_AudioEffect_native_queryPreProcessings},
898 };
899
900
901 // ----------------------------------------------------------------------------
902
903 extern int register_android_media_visualizer(JNIEnv *env);
904
register_android_media_AudioEffect(JNIEnv * env)905 int register_android_media_AudioEffect(JNIEnv *env)
906 {
907 return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
908 }
909
JNI_OnLoad(JavaVM * vm,void * reserved __unused)910 jint JNI_OnLoad(JavaVM* vm, void* reserved __unused)
911 {
912
913 JNIEnv* env = NULL;
914 jint result = -1;
915
916 if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
917 ALOGE("ERROR: GetEnv failed\n");
918 goto bail;
919 }
920 assert(env != NULL);
921
922 if (register_android_media_AudioEffect(env) < 0) {
923 ALOGE("ERROR: AudioEffect native registration failed\n");
924 goto bail;
925 }
926
927 if (register_android_media_visualizer(env) < 0) {
928 ALOGE("ERROR: Visualizer native registration failed\n");
929 goto bail;
930 }
931
932 /* success -- return valid version number */
933 result = JNI_VERSION_1_4;
934
935 bail:
936 return result;
937 }
938
939