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