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