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