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