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