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