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,jint deviceType,jstring deviceAddress,jintArray jId,jobjectArray javadesc,jstring opPackageName,jboolean probe)270 android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
271 jstring type, jstring uuid, jint priority, jint sessionId,
272 jint deviceType, jstring deviceAddress,
273 jintArray jId, jobjectArray javadesc, jstring opPackageName, jboolean probe)
274 {
275 ALOGV("android_media_AudioEffect_native_setup");
276 AudioEffectJniStorage* lpJniStorage = NULL;
277 int lStatus = AUDIOEFFECT_ERROR_NO_MEMORY;
278 sp<AudioEffect> lpAudioEffect;
279 jint* nId = NULL;
280 const char *typeStr = NULL;
281 const char *uuidStr = NULL;
282 effect_descriptor_t desc;
283 jobject jdesc;
284 AudioDeviceTypeAddr device;
285
286 ScopedUtfChars opPackageNameStr(env, opPackageName);
287
288 setAudioEffect(env, thiz, 0);
289
290 if (type != NULL) {
291 typeStr = env->GetStringUTFChars(type, NULL);
292 if (typeStr == NULL) { // Out of memory
293 jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
294 goto setup_failure;
295 }
296 }
297
298 if (uuid != NULL) {
299 uuidStr = env->GetStringUTFChars(uuid, NULL);
300 if (uuidStr == NULL) { // Out of memory
301 jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
302 goto setup_failure;
303 }
304 }
305
306 if (typeStr == NULL && uuidStr == NULL) {
307 lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
308 goto setup_failure;
309 }
310
311 lpJniStorage = new AudioEffectJniStorage();
312 if (lpJniStorage == NULL) {
313 ALOGE("setup: Error creating JNI Storage");
314 goto setup_failure;
315 }
316
317 lpJniStorage->mCallbackData.audioEffect_class = (jclass)env->NewGlobalRef(fields.clazzEffect);
318 // we use a weak reference so the AudioEffect object can be garbage collected.
319 lpJniStorage->mCallbackData.audioEffect_ref = env->NewGlobalRef(weak_this);
320
321 ALOGV("setup: lpJniStorage: %p audioEffect_ref %p audioEffect_class %p, &mCallbackData %p",
322 lpJniStorage,
323 lpJniStorage->mCallbackData.audioEffect_ref,
324 lpJniStorage->mCallbackData.audioEffect_class,
325 &lpJniStorage->mCallbackData);
326
327 if (jId == NULL) {
328 ALOGE("setup: NULL java array for id pointer");
329 lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
330 goto setup_failure;
331 }
332
333 if (deviceType != AUDIO_DEVICE_NONE) {
334 device.mType = deviceType;
335 ScopedUtfChars address(env, deviceAddress);
336 device.mAddress = address.c_str();
337 }
338
339 // create the native AudioEffect object
340 lpAudioEffect = new AudioEffect(typeStr,
341 String16(opPackageNameStr.c_str()),
342 uuidStr,
343 priority,
344 effectCallback,
345 &lpJniStorage->mCallbackData,
346 (audio_session_t) sessionId,
347 AUDIO_IO_HANDLE_NONE,
348 device,
349 probe);
350 if (lpAudioEffect == 0) {
351 ALOGE("Error creating AudioEffect");
352 goto setup_failure;
353 }
354
355
356 lStatus = AudioEffectJni::translateNativeErrorToJava(lpAudioEffect->initCheck());
357 if (lStatus != AUDIOEFFECT_SUCCESS && lStatus != AUDIOEFFECT_ERROR_ALREADY_EXISTS) {
358 ALOGE("AudioEffect initCheck failed %d", lStatus);
359 goto setup_failure;
360 }
361
362 nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL);
363 if (nId == NULL) {
364 ALOGE("setup: Error retrieving id pointer");
365 lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
366 goto setup_failure;
367 }
368 nId[0] = lpAudioEffect->id();
369 env->ReleasePrimitiveArrayCritical(jId, nId, 0);
370 nId = NULL;
371
372 if (typeStr) {
373 env->ReleaseStringUTFChars(type, typeStr);
374 typeStr = NULL;
375 }
376
377 if (uuidStr) {
378 env->ReleaseStringUTFChars(uuid, uuidStr);
379 uuidStr = NULL;
380 }
381
382 // get the effect descriptor
383 desc = lpAudioEffect->descriptor();
384
385 if (convertAudioEffectDescriptorFromNative(env, &jdesc, &desc) != AUDIO_JAVA_SUCCESS) {
386 goto setup_failure;
387 }
388
389 env->SetObjectArrayElement(javadesc, 0, jdesc);
390 env->DeleteLocalRef(jdesc);
391
392 // In probe mode, release the native object and clear our strong reference
393 // to force all method calls from JAVA to be rejected.
394 if (probe) {
395 setAudioEffect(env, thiz, 0);
396 } else {
397 setAudioEffect(env, thiz, lpAudioEffect);
398 }
399
400 env->SetLongField(thiz, fields.fidJniData, (jlong)lpJniStorage);
401
402 return (jint) AUDIOEFFECT_SUCCESS;
403
404 // failures:
405 setup_failure:
406
407 if (nId != NULL) {
408 env->ReleasePrimitiveArrayCritical(jId, nId, 0);
409 }
410
411 if (lpJniStorage) {
412 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioEffect_class);
413 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioEffect_ref);
414 delete lpJniStorage;
415 }
416 env->SetLongField(thiz, fields.fidJniData, 0);
417
418 if (uuidStr != NULL) {
419 env->ReleaseStringUTFChars(uuid, uuidStr);
420 }
421
422 if (typeStr != NULL) {
423 env->ReleaseStringUTFChars(type, typeStr);
424 }
425
426 return (jint)lStatus;
427 }
428
429
430 // ----------------------------------------------------------------------------
android_media_AudioEffect_native_release(JNIEnv * env,jobject thiz)431 static void android_media_AudioEffect_native_release(JNIEnv *env, jobject thiz) {
432 sp<AudioEffect> lpAudioEffect = setAudioEffect(env, thiz, 0);
433 if (lpAudioEffect == 0) {
434 return;
435 }
436
437 // delete the JNI data
438 AudioEffectJniStorage* lpJniStorage =
439 (AudioEffectJniStorage *)env->GetLongField(thiz, fields.fidJniData);
440
441 // reset the native resources in the Java object so any attempt to access
442 // them after a call to release fails.
443 env->SetLongField(thiz, fields.fidJniData, 0);
444
445 if (lpJniStorage) {
446 ALOGV("deleting pJniStorage: %p\n", lpJniStorage);
447 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioEffect_class);
448 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioEffect_ref);
449 delete lpJniStorage;
450 }
451 }
452
453 // ----------------------------------------------------------------------------
android_media_AudioEffect_native_finalize(JNIEnv * env,jobject thiz)454 static void android_media_AudioEffect_native_finalize(JNIEnv *env, jobject thiz) {
455 ALOGV("android_media_AudioEffect_native_finalize jobject: %p\n", thiz);
456 android_media_AudioEffect_native_release(env, thiz);
457 }
458
459 static jint
android_media_AudioEffect_native_setEnabled(JNIEnv * env,jobject thiz,jboolean enabled)460 android_media_AudioEffect_native_setEnabled(JNIEnv *env, jobject thiz, jboolean enabled)
461 {
462 sp<AudioEffect> lpAudioEffect = getAudioEffect(env, thiz);
463 if (lpAudioEffect == 0) {
464 jniThrowException(env, "java/lang/IllegalStateException",
465 "Unable to retrieve AudioEffect pointer for enable()");
466 return AUDIOEFFECT_ERROR_NO_INIT;
467 }
468
469 return AudioEffectJni::translateNativeErrorToJava(lpAudioEffect->setEnabled(enabled));
470 }
471
472 static jboolean
android_media_AudioEffect_native_getEnabled(JNIEnv * env,jobject thiz)473 android_media_AudioEffect_native_getEnabled(JNIEnv *env, jobject thiz)
474 {
475 sp<AudioEffect> lpAudioEffect = getAudioEffect(env, thiz);
476 if (lpAudioEffect == 0) {
477 jniThrowException(env, "java/lang/IllegalStateException",
478 "Unable to retrieve AudioEffect pointer for getEnabled()");
479 return JNI_FALSE;
480 }
481
482 if (lpAudioEffect->getEnabled()) {
483 return JNI_TRUE;
484 } else {
485 return JNI_FALSE;
486 }
487 }
488
489
490 static jboolean
android_media_AudioEffect_native_hasControl(JNIEnv * env,jobject thiz)491 android_media_AudioEffect_native_hasControl(JNIEnv *env, jobject thiz)
492 {
493 sp<AudioEffect> lpAudioEffect = getAudioEffect(env, thiz);
494 if (lpAudioEffect == 0) {
495 jniThrowException(env, "java/lang/IllegalStateException",
496 "Unable to retrieve AudioEffect pointer for hasControl()");
497 return JNI_FALSE;
498 }
499
500 if (lpAudioEffect->initCheck() == NO_ERROR) {
501 return JNI_TRUE;
502 } else {
503 return JNI_FALSE;
504 }
505 }
506
android_media_AudioEffect_native_setParameter(JNIEnv * env,jobject thiz,jint psize,jbyteArray pJavaParam,jint vsize,jbyteArray pJavaValue)507 static jint android_media_AudioEffect_native_setParameter(JNIEnv *env,
508 jobject thiz, jint psize, jbyteArray pJavaParam, jint vsize,
509 jbyteArray pJavaValue) {
510 // retrieve the AudioEffect object
511 jbyte* lpValue = NULL;
512 jbyte* lpParam = NULL;
513 jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
514 effect_param_t *p;
515 int voffset;
516
517 sp<AudioEffect> lpAudioEffect = getAudioEffect(env, thiz);
518 if (lpAudioEffect == 0) {
519 jniThrowException(env, "java/lang/IllegalStateException",
520 "Unable to retrieve AudioEffect pointer for setParameter()");
521 return AUDIOEFFECT_ERROR_NO_INIT;
522 }
523
524 if (psize == 0 || vsize == 0 || pJavaParam == NULL || pJavaValue == NULL) {
525 return AUDIOEFFECT_ERROR_BAD_VALUE;
526 }
527
528 // get the pointer for the param from the java array
529 lpParam = (jbyte *) env->GetPrimitiveArrayCritical(pJavaParam, NULL);
530 if (lpParam == NULL) {
531 ALOGE("setParameter: Error retrieving param pointer");
532 goto setParameter_Exit;
533 }
534
535 // get the pointer for the value from the java array
536 lpValue = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValue, NULL);
537 if (lpValue == NULL) {
538 ALOGE("setParameter: Error retrieving value pointer");
539 goto setParameter_Exit;
540 }
541
542 voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int);
543 p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset + vsize);
544 memcpy(p->data, lpParam, psize);
545 p->psize = psize;
546 memcpy(p->data + voffset, lpValue, vsize);
547 p->vsize = vsize;
548
549 lStatus = lpAudioEffect->setParameter(p);
550 if (lStatus == NO_ERROR) {
551 lStatus = p->status;
552 }
553
554 free(p);
555
556 setParameter_Exit:
557
558 if (lpParam != NULL) {
559 env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0);
560 }
561 if (lpValue != NULL) {
562 env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
563 }
564 return AudioEffectJni::translateNativeErrorToJava(lStatus);
565 }
566
567 static jint
android_media_AudioEffect_native_getParameter(JNIEnv * env,jobject thiz,jint psize,jbyteArray pJavaParam,jint vsize,jbyteArray pJavaValue)568 android_media_AudioEffect_native_getParameter(JNIEnv *env,
569 jobject thiz, jint psize, jbyteArray pJavaParam,
570 jint vsize, jbyteArray pJavaValue) {
571 // retrieve the AudioEffect object
572 jbyte* lpParam = NULL;
573 jbyte* lpValue = NULL;
574 jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
575 effect_param_t *p;
576 int voffset;
577
578 sp<AudioEffect> lpAudioEffect = getAudioEffect(env, thiz);
579 if (lpAudioEffect == 0) {
580 jniThrowException(env, "java/lang/IllegalStateException",
581 "Unable to retrieve AudioEffect pointer for getParameter()");
582 return AUDIOEFFECT_ERROR_NO_INIT;
583 }
584
585 if (psize == 0 || vsize == 0 || pJavaParam == NULL || pJavaValue == NULL) {
586 return AUDIOEFFECT_ERROR_BAD_VALUE;
587 }
588
589 // get the pointer for the param from the java array
590 lpParam = (jbyte *) env->GetPrimitiveArrayCritical(pJavaParam, NULL);
591 if (lpParam == NULL) {
592 ALOGE("getParameter: Error retrieving param pointer");
593 goto getParameter_Exit;
594 }
595
596 // get the pointer for the value from the java array
597 lpValue = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValue, NULL);
598 if (lpValue == NULL) {
599 ALOGE("getParameter: Error retrieving value pointer");
600 goto getParameter_Exit;
601 }
602
603 voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int);
604 p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset + vsize);
605 memcpy(p->data, lpParam, psize);
606 p->psize = psize;
607 p->vsize = vsize;
608
609 lStatus = lpAudioEffect->getParameter(p);
610 if (lStatus == NO_ERROR) {
611 lStatus = p->status;
612 if (lStatus == NO_ERROR) {
613 memcpy(lpValue, p->data + voffset, p->vsize);
614 vsize = p->vsize;
615 }
616 }
617
618 free(p);
619
620 getParameter_Exit:
621
622 if (lpParam != NULL) {
623 env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0);
624 }
625 if (lpValue != NULL) {
626 env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
627 }
628
629 if (lStatus == NO_ERROR) {
630 return vsize;
631 }
632 return AudioEffectJni::translateNativeErrorToJava(lStatus);
633 }
634
android_media_AudioEffect_native_command(JNIEnv * env,jobject thiz,jint cmdCode,jint cmdSize,jbyteArray jCmdData,jint replySize,jbyteArray jReplyData)635 static jint android_media_AudioEffect_native_command(JNIEnv *env, jobject thiz,
636 jint cmdCode, jint cmdSize, jbyteArray jCmdData, jint replySize,
637 jbyteArray jReplyData) {
638 jbyte* pCmdData = NULL;
639 jbyte* pReplyData = NULL;
640 jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
641
642 sp<AudioEffect> lpAudioEffect = getAudioEffect(env, thiz);
643 if (lpAudioEffect == 0) {
644 jniThrowException(env, "java/lang/IllegalStateException",
645 "Unable to retrieve AudioEffect pointer for setParameter()");
646 return AUDIOEFFECT_ERROR_NO_INIT;
647 }
648
649 if ((cmdSize != 0 && jCmdData == NULL) || (replySize != 0 && jReplyData == NULL)) {
650 return AUDIOEFFECT_ERROR_BAD_VALUE;
651 }
652
653 // get the pointer for the command from the java array
654 if (cmdSize != 0) {
655 pCmdData = (jbyte *) env->GetPrimitiveArrayCritical(jCmdData, NULL);
656 if (pCmdData == NULL) {
657 ALOGE("setParameter: Error retrieving command pointer");
658 goto command_Exit;
659 }
660 }
661
662 // get the pointer for the reply from the java array
663 if (replySize != 0 && jReplyData != NULL) {
664 pReplyData = (jbyte *) env->GetPrimitiveArrayCritical(jReplyData, NULL);
665 if (pReplyData == NULL) {
666 ALOGE("setParameter: Error retrieving reply pointer");
667 goto command_Exit;
668 }
669 }
670
671 lStatus = AudioEffectJni::translateNativeErrorToJava(
672 lpAudioEffect->command((uint32_t)cmdCode,
673 (uint32_t)cmdSize,
674 pCmdData,
675 (uint32_t *)&replySize,
676 pReplyData));
677
678 command_Exit:
679
680 if (pCmdData != NULL) {
681 env->ReleasePrimitiveArrayCritical(jCmdData, pCmdData, 0);
682 }
683 if (pReplyData != NULL) {
684 env->ReleasePrimitiveArrayCritical(jReplyData, pReplyData, 0);
685 }
686
687 if (lStatus == NO_ERROR) {
688 return replySize;
689 }
690 return lStatus;
691 }
692
693 static jobjectArray
android_media_AudioEffect_native_queryEffects(JNIEnv * env,jclass clazz __unused)694 android_media_AudioEffect_native_queryEffects(JNIEnv *env, jclass clazz __unused)
695 {
696 effect_descriptor_t desc;
697 uint32_t totalEffectsCount = 0;
698 uint32_t returnedEffectsCount = 0;
699 uint32_t i = 0;
700 jobjectArray ret;
701
702 if (AudioEffect::queryNumberEffects(&totalEffectsCount) != NO_ERROR) {
703 return NULL;
704 }
705
706 jobjectArray temp = env->NewObjectArray(totalEffectsCount, audioEffectDescriptorClass(), NULL);
707 if (temp == NULL) {
708 return temp;
709 }
710
711 ALOGV("queryEffects() totalEffectsCount: %d", totalEffectsCount);
712
713 for (i = 0; i < totalEffectsCount; i++) {
714 if (AudioEffect::queryEffect(i, &desc) != NO_ERROR) {
715 goto queryEffects_failure;
716 }
717
718 jobject jdesc;
719 if (convertAudioEffectDescriptorFromNative(env, &jdesc, &desc) != AUDIO_JAVA_SUCCESS) {
720 continue;
721 }
722 env->SetObjectArrayElement(temp, returnedEffectsCount++, jdesc);
723 env->DeleteLocalRef(jdesc);
724 }
725
726 if (returnedEffectsCount == 0) {
727 goto queryEffects_failure;
728 }
729 ret = env->NewObjectArray(returnedEffectsCount, audioEffectDescriptorClass(), NULL);
730 if (ret == NULL) {
731 goto queryEffects_failure;
732 }
733 for (i = 0; i < returnedEffectsCount; i++) {
734 env->SetObjectArrayElement(ret, i, env->GetObjectArrayElement(temp, i));
735 }
736 env->DeleteLocalRef(temp);
737 return ret;
738
739 queryEffects_failure:
740
741 if (temp != NULL) {
742 env->DeleteLocalRef(temp);
743 }
744 return NULL;
745
746 }
747
748
749
750 static jobjectArray
android_media_AudioEffect_native_queryPreProcessings(JNIEnv * env,jclass clazz __unused,jint audioSession)751 android_media_AudioEffect_native_queryPreProcessings(JNIEnv *env, jclass clazz __unused,
752 jint audioSession)
753 {
754 auto descriptors = std::make_unique<effect_descriptor_t[]>(AudioEffect::kMaxPreProcessing);
755 uint32_t numEffects = AudioEffect::kMaxPreProcessing;
756
757 status_t status = AudioEffect::queryDefaultPreProcessing((audio_session_t) audioSession,
758 descriptors.get(),
759 &numEffects);
760 if (status != NO_ERROR || numEffects == 0) {
761 return NULL;
762 }
763 ALOGV("queryDefaultPreProcessing() got %d effects", numEffects);
764
765 std::vector<effect_descriptor_t> descVector(descriptors.get(), descriptors.get() + numEffects);
766
767 jobjectArray ret;
768 convertAudioEffectDescriptorVectorFromNative(env, &ret, descVector);
769 return ret;
770 }
771
772 // ----------------------------------------------------------------------------
773
774 // Dalvik VM type signatures
775 static const JNINativeMethod gMethods[] = {
776 {"native_init", "()V", (void *)android_media_AudioEffect_native_init},
777 {"native_setup", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;IIILjava/lang/String;[I[Ljava/lang/Object;Ljava/lang/String;Z)I",
778 (void *)android_media_AudioEffect_native_setup},
779 {"native_finalize", "()V", (void *)android_media_AudioEffect_native_finalize},
780 {"native_release", "()V", (void *)android_media_AudioEffect_native_release},
781 {"native_setEnabled", "(Z)I", (void *)android_media_AudioEffect_native_setEnabled},
782 {"native_getEnabled", "()Z", (void *)android_media_AudioEffect_native_getEnabled},
783 {"native_hasControl", "()Z", (void *)android_media_AudioEffect_native_hasControl},
784 {"native_setParameter", "(I[BI[B)I", (void *)android_media_AudioEffect_native_setParameter},
785 {"native_getParameter", "(I[BI[B)I", (void *)android_media_AudioEffect_native_getParameter},
786 {"native_command", "(II[BI[B)I", (void *)android_media_AudioEffect_native_command},
787 {"native_query_effects", "()[Ljava/lang/Object;", (void *)android_media_AudioEffect_native_queryEffects},
788 {"native_query_pre_processing", "(I)[Ljava/lang/Object;",
789 (void *)android_media_AudioEffect_native_queryPreProcessings},
790 };
791
792
793 // ----------------------------------------------------------------------------
794
795 extern int register_android_media_SourceDefaultEffect(JNIEnv *env);
796 extern int register_android_media_StreamDefaultEffect(JNIEnv *env);
797 extern int register_android_media_visualizer(JNIEnv *env);
798
register_android_media_AudioEffect(JNIEnv * env)799 int register_android_media_AudioEffect(JNIEnv *env)
800 {
801 return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
802 }
803
JNI_OnLoad(JavaVM * vm,void * reserved __unused)804 jint JNI_OnLoad(JavaVM* vm, void* reserved __unused)
805 {
806
807 JNIEnv* env = NULL;
808 jint result = -1;
809
810 if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
811 ALOGE("ERROR: GetEnv failed\n");
812 goto bail;
813 }
814 assert(env != NULL);
815
816 if (register_android_media_AudioEffect(env) < 0) {
817 ALOGE("ERROR: AudioEffect native registration failed\n");
818 goto bail;
819 }
820
821 if (register_android_media_SourceDefaultEffect(env) < 0) {
822 ALOGE("ERROR: SourceDefaultEffect native registration failed\n");
823 goto bail;
824 }
825
826 if (register_android_media_StreamDefaultEffect(env) < 0) {
827 ALOGE("ERROR: StreamDefaultEffect native registration failed\n");
828 goto bail;
829 }
830
831 if (register_android_media_visualizer(env) < 0) {
832 ALOGE("ERROR: Visualizer native registration failed\n");
833 goto bail;
834 }
835
836 /* success -- return valid version number */
837 result = JNI_VERSION_1_4;
838
839 bail:
840 return result;
841 }
842