• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     LOGV("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         LOGW("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             LOGW("EVENT_CONTROL_STATUS_CHANGED info == NULL");
123             goto effectCallback_Exit;
124         }
125         param = *(bool *)info;
126         arg1 = (int)param;
127         LOGV("EVENT_CONTROL_STATUS_CHANGED");
128         break;
129     case AudioEffect::EVENT_ENABLE_STATUS_CHANGED:
130         if (info == 0) {
131             LOGW("EVENT_ENABLE_STATUS_CHANGED info == NULL");
132             goto effectCallback_Exit;
133         }
134         param = *(bool *)info;
135         arg1 = (int)param;
136         LOGV("EVENT_ENABLE_STATUS_CHANGED");
137         break;
138     case AudioEffect::EVENT_PARAMETER_CHANGED:
139         if (info == 0) {
140             LOGW("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             LOGE("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         LOGV("EVENT_PARAMETER_CHANGED");
160        break;
161     case AudioEffect::EVENT_ERROR:
162         LOGW("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     LOGV("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         LOGE("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         LOGE("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", "I");
218     if (fields.fidNativeAudioEffect == NULL) {
219         LOGE("Can't find AudioEffect.%s", "mNativeAudioEffect");
220         return;
221     }
222     //      fidJniData;
223     fields.fidJniData = env->GetFieldID(
224             fields.clazzEffect,
225             "mJniData", "I");
226     if (fields.fidJniData == NULL) {
227         LOGE("Can't find AudioEffect.%s", "mJniData");
228         return;
229     }
230 
231     clazz = env->FindClass("android/media/audiofx/AudioEffect$Descriptor");
232     if (clazz == NULL) {
233         LOGE("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         LOGE("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     LOGV("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         LOGE("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     LOGV("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         LOGE("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         LOGE("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         LOGE("AudioEffect initCheck failed %d", lStatus);
329         goto setup_failure;
330     }
331 
332     nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL);
333     if (nId == NULL) {
334         LOGE("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 {
364         jdescConnect = env->NewStringUTF("Insert");
365     }
366 
367     jdescName = env->NewStringUTF(desc.name);
368     jdescImplementor = env->NewStringUTF(desc.implementor);
369 
370     jdesc = env->NewObject(fields.clazzDesc,
371                            fields.midDescCstor,
372                            jdescType,
373                            jdescUuid,
374                            jdescConnect,
375                            jdescName,
376                            jdescImplementor);
377     env->DeleteLocalRef(jdescType);
378     env->DeleteLocalRef(jdescUuid);
379     env->DeleteLocalRef(jdescConnect);
380     env->DeleteLocalRef(jdescName);
381     env->DeleteLocalRef(jdescImplementor);
382     if (jdesc == NULL) {
383         LOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)");
384         goto setup_failure;
385     }
386 
387     env->SetObjectArrayElement(javadesc, 0, jdesc);
388 
389     env->SetIntField(thiz, fields.fidNativeAudioEffect, (int)lpAudioEffect);
390 
391     env->SetIntField(thiz, fields.fidJniData, (int)lpJniStorage);
392 
393     return AUDIOEFFECT_SUCCESS;
394 
395     // failures:
396 setup_failure:
397 
398     if (nId != NULL) {
399         env->ReleasePrimitiveArrayCritical(jId, nId, 0);
400     }
401 
402     if (lpAudioEffect) {
403         delete lpAudioEffect;
404     }
405     env->SetIntField(thiz, fields.fidNativeAudioEffect, 0);
406 
407     if (lpJniStorage) {
408         delete lpJniStorage;
409     }
410     env->SetIntField(thiz, fields.fidJniData, 0);
411 
412     if (uuidStr != NULL) {
413         env->ReleaseStringUTFChars(uuid, uuidStr);
414     }
415 
416     if (typeStr != NULL) {
417         env->ReleaseStringUTFChars(type, typeStr);
418     }
419 
420     return lStatus;
421 }
422 
423 
424 // ----------------------------------------------------------------------------
android_media_AudioEffect_native_finalize(JNIEnv * env,jobject thiz)425 static void android_media_AudioEffect_native_finalize(JNIEnv *env,  jobject thiz) {
426     LOGV("android_media_AudioEffect_native_finalize jobject: %x\n", (int)thiz);
427 
428     // delete the AudioEffect object
429     AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
430         thiz, fields.fidNativeAudioEffect);
431     if (lpAudioEffect) {
432         LOGV("deleting AudioEffect: %x\n", (int)lpAudioEffect);
433         delete lpAudioEffect;
434     }
435 
436     // delete the JNI data
437     AudioEffectJniStorage* lpJniStorage = (AudioEffectJniStorage *)env->GetIntField(
438         thiz, fields.fidJniData);
439     if (lpJniStorage) {
440         LOGV("deleting pJniStorage: %x\n", (int)lpJniStorage);
441         delete lpJniStorage;
442     }
443 }
444 
445 // ----------------------------------------------------------------------------
android_media_AudioEffect_native_release(JNIEnv * env,jobject thiz)446 static void android_media_AudioEffect_native_release(JNIEnv *env,  jobject thiz) {
447 
448     // do everything a call to finalize would
449     android_media_AudioEffect_native_finalize(env, thiz);
450     // + reset the native resources in the Java object so any attempt to access
451     // them after a call to release fails.
452     env->SetIntField(thiz, fields.fidNativeAudioEffect, 0);
453     env->SetIntField(thiz, fields.fidJniData, 0);
454 }
455 
456 static jint
android_media_AudioEffect_native_setEnabled(JNIEnv * env,jobject thiz,jboolean enabled)457 android_media_AudioEffect_native_setEnabled(JNIEnv *env, jobject thiz, jboolean enabled)
458 {
459     // retrieve the AudioEffect object
460     AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
461         thiz, fields.fidNativeAudioEffect);
462 
463     if (lpAudioEffect == NULL) {
464         jniThrowException(env, "java/lang/IllegalStateException",
465             "Unable to retrieve AudioEffect pointer for enable()");
466         return AUDIOEFFECT_ERROR_NO_INIT;
467     }
468 
469     return translateError(lpAudioEffect->setEnabled(enabled));
470 }
471 
472 static jboolean
android_media_AudioEffect_native_getEnabled(JNIEnv * env,jobject thiz)473 android_media_AudioEffect_native_getEnabled(JNIEnv *env, jobject thiz)
474 {
475     // retrieve the AudioEffect object
476     AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
477         thiz, fields.fidNativeAudioEffect);
478 
479     if (lpAudioEffect == NULL) {
480         jniThrowException(env, "java/lang/IllegalStateException",
481             "Unable to retrieve AudioEffect pointer for getEnabled()");
482         return false;
483     }
484 
485     return (jboolean)lpAudioEffect->getEnabled();
486 }
487 
488 
489 static jboolean
android_media_AudioEffect_native_hasControl(JNIEnv * env,jobject thiz)490 android_media_AudioEffect_native_hasControl(JNIEnv *env, jobject thiz)
491 {
492     // retrieve the AudioEffect object
493     AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
494         thiz, fields.fidNativeAudioEffect);
495 
496     if (lpAudioEffect == NULL) {
497         jniThrowException(env, "java/lang/IllegalStateException",
498             "Unable to retrieve AudioEffect pointer for hasControl()");
499         return false;
500     }
501 
502     if (lpAudioEffect->initCheck() == NO_ERROR) {
503         return true;
504     } else {
505         return false;
506     }
507 }
508 
android_media_AudioEffect_native_setParameter(JNIEnv * env,jobject thiz,int psize,jbyteArray pJavaParam,int vsize,jbyteArray pJavaValue)509 static jint android_media_AudioEffect_native_setParameter(JNIEnv *env,
510         jobject thiz, int psize, jbyteArray pJavaParam, int vsize,
511         jbyteArray pJavaValue) {
512     // retrieve the AudioEffect object
513     jbyte* lpValue = NULL;
514     jbyte* lpParam = NULL;
515     jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
516     effect_param_t *p;
517     int voffset;
518 
519     AudioEffect* lpAudioEffect = (AudioEffect *) env->GetIntField(thiz,
520             fields.fidNativeAudioEffect);
521 
522     if (lpAudioEffect == NULL) {
523         jniThrowException(env, "java/lang/IllegalStateException",
524                 "Unable to retrieve AudioEffect pointer for setParameter()");
525         return AUDIOEFFECT_ERROR_NO_INIT;
526     }
527 
528     if (psize == 0 || vsize == 0 || pJavaParam == NULL || pJavaValue == NULL) {
529         return AUDIOEFFECT_ERROR_BAD_VALUE;
530     }
531 
532     // get the pointer for the param from the java array
533     lpParam = (jbyte *) env->GetPrimitiveArrayCritical(pJavaParam, NULL);
534     if (lpParam == NULL) {
535         LOGE("setParameter: Error retrieving param pointer");
536         goto setParameter_Exit;
537     }
538 
539     // get the pointer for the value from the java array
540     lpValue = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValue, NULL);
541     if (lpValue == NULL) {
542         LOGE("setParameter: Error retrieving value pointer");
543         goto setParameter_Exit;
544     }
545 
546     voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int);
547     p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset + vsize);
548     memcpy(p->data, lpParam, psize);
549     p->psize = psize;
550     memcpy(p->data + voffset, lpValue, vsize);
551     p->vsize = vsize;
552 
553     lStatus = lpAudioEffect->setParameter(p);
554     if (lStatus == NO_ERROR) {
555         lStatus = p->status;
556     }
557 
558     free(p);
559 
560 setParameter_Exit:
561 
562     if (lpParam != NULL) {
563         env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0);
564     }
565     if (lpValue != NULL) {
566         env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
567     }
568     return translateError(lStatus);
569 }
570 
571 static jint
android_media_AudioEffect_native_getParameter(JNIEnv * env,jobject thiz,int psize,jbyteArray pJavaParam,jintArray pJavaValueSize,jbyteArray pJavaValue)572 android_media_AudioEffect_native_getParameter(JNIEnv *env,
573         jobject thiz, int psize, jbyteArray pJavaParam,
574         jintArray pJavaValueSize, jbyteArray pJavaValue) {
575     // retrieve the AudioEffect object
576     jbyte* lpParam = NULL;
577     jbyte* lpValue = NULL;
578     jbyte* lpValueSize = NULL;
579     jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
580     effect_param_t *p;
581     int voffset;
582 
583     AudioEffect* lpAudioEffect = (AudioEffect *) env->GetIntField(thiz,
584             fields.fidNativeAudioEffect);
585 
586     if (lpAudioEffect == NULL) {
587         jniThrowException(env, "java/lang/IllegalStateException",
588                 "Unable to retrieve AudioEffect pointer for getParameter()");
589         return AUDIOEFFECT_ERROR_NO_INIT;
590     }
591 
592     if (psize == 0 || pJavaValueSize == NULL || pJavaParam == NULL || pJavaValue == NULL) {
593         return AUDIOEFFECT_ERROR_BAD_VALUE;
594     }
595 
596     // get the pointer for the param from the java array
597     lpParam = (jbyte *) env->GetPrimitiveArrayCritical(pJavaParam, NULL);
598     if (lpParam == NULL) {
599         LOGE("getParameter: Error retrieving param pointer");
600         goto getParameter_Exit;
601     }
602 
603     // get the pointer for the value from the java array
604     lpValue = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValue, NULL);
605     if (lpValue == NULL) {
606         LOGE("getParameter: Error retrieving value pointer");
607         goto getParameter_Exit;
608     }
609 
610     // get the pointer for the value size from the java array
611     lpValueSize = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValueSize, NULL);
612     if (lpValueSize == NULL) {
613         LOGE("getParameter: Error retrieving value size pointer");
614         goto getParameter_Exit;
615     }
616 
617     voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int);
618     p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset
619             + lpValueSize[0]);
620     memcpy(p->data, lpParam, psize);
621     p->psize = psize;
622     p->vsize = lpValueSize[0];
623 
624     lStatus = lpAudioEffect->getParameter(p);
625     if (lStatus == NO_ERROR) {
626         lStatus = p->status;
627         if (lStatus == NO_ERROR) {
628             memcpy(lpValue, p->data + voffset, p->vsize);
629             lpValueSize[0] = p->vsize;
630         }
631     }
632 
633     free(p);
634 
635 getParameter_Exit:
636 
637     if (lpParam != NULL) {
638         env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0);
639     }
640     if (lpValue != NULL) {
641         env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
642     }
643     if (lpValueSize != NULL) {
644         env->ReleasePrimitiveArrayCritical(pJavaValueSize, lpValueSize, 0);
645     }
646 
647     return translateError(lStatus);
648 }
649 
android_media_AudioEffect_native_command(JNIEnv * env,jobject thiz,jint cmdCode,jint cmdSize,jbyteArray jCmdData,jintArray jReplySize,jbyteArray jReplyData)650 static jint android_media_AudioEffect_native_command(JNIEnv *env, jobject thiz,
651         jint cmdCode, jint cmdSize, jbyteArray jCmdData, jintArray jReplySize,
652         jbyteArray jReplyData) {
653     jbyte* pCmdData = NULL;
654     jbyte* pReplyData = NULL;
655     jint* pReplySize = NULL;
656     jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
657 
658     // retrieve the AudioEffect object
659     AudioEffect* lpAudioEffect = (AudioEffect *) env->GetIntField(thiz,
660             fields.fidNativeAudioEffect);
661 
662     if (lpAudioEffect == NULL) {
663         jniThrowException(env, "java/lang/IllegalStateException",
664                 "Unable to retrieve AudioEffect pointer for setParameter()");
665         return AUDIOEFFECT_ERROR_NO_INIT;
666     }
667 
668     if ((cmdSize != 0 && jCmdData == NULL) || (jReplySize != NULL && jReplyData == NULL)) {
669         return AUDIOEFFECT_ERROR_BAD_VALUE;
670     }
671 
672     // get the pointer for the command from the java array
673     if (cmdSize != 0) {
674         pCmdData = (jbyte *) env->GetPrimitiveArrayCritical(jCmdData, NULL);
675         if (pCmdData == NULL) {
676             LOGE("setParameter: Error retrieving command pointer");
677             goto command_Exit;
678         }
679     }
680 
681     // get the pointer for the reply size from the java array
682     if (jReplySize != NULL) {
683         pReplySize = (jint *) env->GetPrimitiveArrayCritical(jReplySize, NULL);
684         if (pReplySize == NULL) {
685             LOGE("setParameter: Error retrieving reply pointer");
686             goto command_Exit;
687         }
688     }
689 
690     // get the pointer for the reply from the java array
691     if (pReplySize != NULL && pReplySize[0] != 0 && jReplyData != NULL) {
692         pReplyData = (jbyte *) env->GetPrimitiveArrayCritical(jReplyData, NULL);
693         if (pReplyData == NULL) {
694             LOGE("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 *)pReplySize,
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     if (pReplySize != NULL) {
714         env->ReleasePrimitiveArrayCritical(jReplySize, pReplySize, 0);
715     }
716 
717     return lStatus;
718 }
719 
720 static jobjectArray
android_media_AudioEffect_native_queryEffects(JNIEnv * env,jclass clazz)721 android_media_AudioEffect_native_queryEffects(JNIEnv *env, jclass clazz)
722 {
723     effect_descriptor_t desc;
724     char str[EFFECT_STRING_LEN_MAX];
725     uint32_t numEffects;
726     uint32_t i = 0;
727     jstring jdescType;
728     jstring jdescUuid;
729     jstring jdescConnect;
730     jstring jdescName;
731     jstring jdescImplementor;
732     jobject jdesc;
733 
734     AudioEffect::queryNumberEffects(&numEffects);
735     jobjectArray ret = env->NewObjectArray(numEffects, fields.clazzDesc, NULL);
736     if (ret == NULL) {
737         return ret;
738     }
739 
740     LOGV("queryEffects() numEffects: %d", numEffects);
741 
742     for (i = 0; i < numEffects; i++) {
743         if (AudioEffect::queryEffect(i, &desc) != NO_ERROR) {
744             goto queryEffects_failure;
745         }
746 
747         AudioEffect::guidToString(&desc.type, str, EFFECT_STRING_LEN_MAX);
748         jdescType = env->NewStringUTF(str);
749 
750         AudioEffect::guidToString(&desc.uuid, str, EFFECT_STRING_LEN_MAX);
751         jdescUuid = env->NewStringUTF(str);
752 
753         if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
754             jdescConnect = env->NewStringUTF("Auxiliary");
755         } else {
756             jdescConnect = env->NewStringUTF("Insert");
757         }
758 
759         jdescName = env->NewStringUTF(desc.name);
760         jdescImplementor = env->NewStringUTF(desc.implementor);
761 
762         jdesc = env->NewObject(fields.clazzDesc,
763                                fields.midDescCstor,
764                                jdescType,
765                                jdescUuid,
766                                jdescConnect,
767                                jdescName,
768                                jdescImplementor);
769         env->DeleteLocalRef(jdescType);
770         env->DeleteLocalRef(jdescUuid);
771         env->DeleteLocalRef(jdescConnect);
772         env->DeleteLocalRef(jdescName);
773         env->DeleteLocalRef(jdescImplementor);
774         if (jdesc == NULL) {
775             LOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)");
776             goto queryEffects_failure;
777         }
778 
779         env->SetObjectArrayElement(ret, i, jdesc);
780    }
781 
782     return ret;
783 
784 queryEffects_failure:
785 
786     if (ret != NULL) {
787         env->DeleteLocalRef(ret);
788     }
789     return NULL;
790 
791 }
792 
793 // ----------------------------------------------------------------------------
794 
795 // Dalvik VM type signatures
796 static JNINativeMethod gMethods[] = {
797     {"native_init",          "()V",      (void *)android_media_AudioEffect_native_init},
798     {"native_setup",         "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;II[I[Ljava/lang/Object;)I",
799                                          (void *)android_media_AudioEffect_native_setup},
800     {"native_finalize",      "()V",      (void *)android_media_AudioEffect_native_finalize},
801     {"native_release",       "()V",      (void *)android_media_AudioEffect_native_release},
802     {"native_setEnabled",    "(Z)I",      (void *)android_media_AudioEffect_native_setEnabled},
803     {"native_getEnabled",    "()Z",      (void *)android_media_AudioEffect_native_getEnabled},
804     {"native_hasControl",    "()Z",      (void *)android_media_AudioEffect_native_hasControl},
805     {"native_setParameter",  "(I[BI[B)I",  (void *)android_media_AudioEffect_native_setParameter},
806     {"native_getParameter",  "(I[B[I[B)I",  (void *)android_media_AudioEffect_native_getParameter},
807     {"native_command",       "(II[B[I[B)I", (void *)android_media_AudioEffect_native_command},
808     {"native_query_effects", "()[Ljava/lang/Object;", (void *)android_media_AudioEffect_native_queryEffects},
809 };
810 
811 
812 // ----------------------------------------------------------------------------
813 
814 extern int register_android_media_visualizer(JNIEnv *env);
815 
register_android_media_AudioEffect(JNIEnv * env)816 int register_android_media_AudioEffect(JNIEnv *env)
817 {
818     return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
819 }
820 
JNI_OnLoad(JavaVM * vm,void * reserved)821 jint JNI_OnLoad(JavaVM* vm, void* reserved)
822 {
823 
824     JNIEnv* env = NULL;
825     jint result = -1;
826 
827     if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
828         LOGE("ERROR: GetEnv failed\n");
829         goto bail;
830     }
831     assert(env != NULL);
832 
833     if (register_android_media_AudioEffect(env) < 0) {
834         LOGE("ERROR: AudioEffect native registration failed\n");
835         goto bail;
836     }
837 
838     if (register_android_media_visualizer(env) < 0) {
839         LOGE("ERROR: Visualizer native registration failed\n");
840         goto bail;
841     }
842 
843     /* success -- return valid version number */
844     result = JNI_VERSION_1_4;
845 
846 bail:
847     return result;
848 }
849 
850