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