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