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