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