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