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