• 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     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", "I");
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", "I");
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->SetIntField(thiz, fields.fidNativeAudioEffect, (int)lpAudioEffect);
392 
393     env->SetIntField(thiz, fields.fidJniData, (int)lpJniStorage);
394 
395     return 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->SetIntField(thiz, fields.fidNativeAudioEffect, 0);
408 
409     if (lpJniStorage) {
410         delete lpJniStorage;
411     }
412     env->SetIntField(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 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: %x\n", (int)thiz);
429 
430     // delete the AudioEffect object
431     AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
432         thiz, fields.fidNativeAudioEffect);
433     if (lpAudioEffect) {
434         ALOGV("deleting AudioEffect: %x\n", (int)lpAudioEffect);
435         delete lpAudioEffect;
436     }
437 
438     // delete the JNI data
439     AudioEffectJniStorage* lpJniStorage = (AudioEffectJniStorage *)env->GetIntField(
440         thiz, fields.fidJniData);
441     if (lpJniStorage) {
442         ALOGV("deleting pJniStorage: %x\n", (int)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->SetIntField(thiz, fields.fidNativeAudioEffect, 0);
455     env->SetIntField(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->GetIntField(
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 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->GetIntField(
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 false;
485     }
486 
487     return (jboolean)lpAudioEffect->getEnabled();
488 }
489 
490 
491 static jboolean
android_media_AudioEffect_native_hasControl(JNIEnv * env,jobject thiz)492 android_media_AudioEffect_native_hasControl(JNIEnv *env, jobject thiz)
493 {
494     // retrieve the AudioEffect object
495     AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
496         thiz, fields.fidNativeAudioEffect);
497 
498     if (lpAudioEffect == NULL) {
499         jniThrowException(env, "java/lang/IllegalStateException",
500             "Unable to retrieve AudioEffect pointer for hasControl()");
501         return false;
502     }
503 
504     if (lpAudioEffect->initCheck() == NO_ERROR) {
505         return true;
506     } else {
507         return false;
508     }
509 }
510 
android_media_AudioEffect_native_setParameter(JNIEnv * env,jobject thiz,int psize,jbyteArray pJavaParam,int vsize,jbyteArray pJavaValue)511 static jint android_media_AudioEffect_native_setParameter(JNIEnv *env,
512         jobject thiz, int psize, jbyteArray pJavaParam, int vsize,
513         jbyteArray pJavaValue) {
514     // retrieve the AudioEffect object
515     jbyte* lpValue = NULL;
516     jbyte* lpParam = NULL;
517     jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
518     effect_param_t *p;
519     int voffset;
520 
521     AudioEffect* lpAudioEffect = (AudioEffect *) env->GetIntField(thiz,
522             fields.fidNativeAudioEffect);
523 
524     if (lpAudioEffect == NULL) {
525         jniThrowException(env, "java/lang/IllegalStateException",
526                 "Unable to retrieve AudioEffect pointer for setParameter()");
527         return AUDIOEFFECT_ERROR_NO_INIT;
528     }
529 
530     if (psize == 0 || vsize == 0 || pJavaParam == NULL || pJavaValue == NULL) {
531         return AUDIOEFFECT_ERROR_BAD_VALUE;
532     }
533 
534     // get the pointer for the param from the java array
535     lpParam = (jbyte *) env->GetPrimitiveArrayCritical(pJavaParam, NULL);
536     if (lpParam == NULL) {
537         ALOGE("setParameter: Error retrieving param pointer");
538         goto setParameter_Exit;
539     }
540 
541     // get the pointer for the value from the java array
542     lpValue = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValue, NULL);
543     if (lpValue == NULL) {
544         ALOGE("setParameter: Error retrieving value pointer");
545         goto setParameter_Exit;
546     }
547 
548     voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int);
549     p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset + vsize);
550     memcpy(p->data, lpParam, psize);
551     p->psize = psize;
552     memcpy(p->data + voffset, lpValue, vsize);
553     p->vsize = vsize;
554 
555     lStatus = lpAudioEffect->setParameter(p);
556     if (lStatus == NO_ERROR) {
557         lStatus = p->status;
558     }
559 
560     free(p);
561 
562 setParameter_Exit:
563 
564     if (lpParam != NULL) {
565         env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0);
566     }
567     if (lpValue != NULL) {
568         env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
569     }
570     return translateError(lStatus);
571 }
572 
573 static jint
android_media_AudioEffect_native_getParameter(JNIEnv * env,jobject thiz,jint psize,jbyteArray pJavaParam,jint vsize,jbyteArray pJavaValue)574 android_media_AudioEffect_native_getParameter(JNIEnv *env,
575         jobject thiz, jint psize, jbyteArray pJavaParam,
576         jint vsize, jbyteArray pJavaValue) {
577     // retrieve the AudioEffect object
578     jbyte* lpParam = NULL;
579     jbyte* lpValue = NULL;
580     jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
581     effect_param_t *p;
582     int voffset;
583 
584     AudioEffect* lpAudioEffect = (AudioEffect *) env->GetIntField(thiz,
585             fields.fidNativeAudioEffect);
586 
587     if (lpAudioEffect == NULL) {
588         jniThrowException(env, "java/lang/IllegalStateException",
589                 "Unable to retrieve AudioEffect pointer for getParameter()");
590         return AUDIOEFFECT_ERROR_NO_INIT;
591     }
592 
593     if (psize == 0 || vsize == 0 || pJavaParam == NULL || pJavaValue == NULL) {
594         return AUDIOEFFECT_ERROR_BAD_VALUE;
595     }
596 
597     // get the pointer for the param from the java array
598     lpParam = (jbyte *) env->GetPrimitiveArrayCritical(pJavaParam, NULL);
599     if (lpParam == NULL) {
600         ALOGE("getParameter: Error retrieving param pointer");
601         goto getParameter_Exit;
602     }
603 
604     // get the pointer for the value from the java array
605     lpValue = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValue, NULL);
606     if (lpValue == NULL) {
607         ALOGE("getParameter: Error retrieving value pointer");
608         goto getParameter_Exit;
609     }
610 
611     voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int);
612     p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset + vsize);
613     memcpy(p->data, lpParam, psize);
614     p->psize = psize;
615     p->vsize = vsize;
616 
617     lStatus = lpAudioEffect->getParameter(p);
618     if (lStatus == NO_ERROR) {
619         lStatus = p->status;
620         if (lStatus == NO_ERROR) {
621             memcpy(lpValue, p->data + voffset, p->vsize);
622             vsize = p->vsize;
623         }
624     }
625 
626     free(p);
627 
628 getParameter_Exit:
629 
630     if (lpParam != NULL) {
631         env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0);
632     }
633     if (lpValue != NULL) {
634         env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
635     }
636 
637     if (lStatus == NO_ERROR) {
638         return vsize;
639     }
640     return translateError(lStatus);
641 }
642 
android_media_AudioEffect_native_command(JNIEnv * env,jobject thiz,jint cmdCode,jint cmdSize,jbyteArray jCmdData,jint replySize,jbyteArray jReplyData)643 static jint android_media_AudioEffect_native_command(JNIEnv *env, jobject thiz,
644         jint cmdCode, jint cmdSize, jbyteArray jCmdData, jint replySize,
645         jbyteArray jReplyData) {
646     jbyte* pCmdData = NULL;
647     jbyte* pReplyData = NULL;
648     jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
649 
650     // retrieve the AudioEffect object
651     AudioEffect* lpAudioEffect = (AudioEffect *) env->GetIntField(thiz,
652             fields.fidNativeAudioEffect);
653 
654     if (lpAudioEffect == NULL) {
655         jniThrowException(env, "java/lang/IllegalStateException",
656                 "Unable to retrieve AudioEffect pointer for setParameter()");
657         return AUDIOEFFECT_ERROR_NO_INIT;
658     }
659 
660     if ((cmdSize != 0 && jCmdData == NULL) || (replySize != 0 && jReplyData == NULL)) {
661         return AUDIOEFFECT_ERROR_BAD_VALUE;
662     }
663 
664     // get the pointer for the command from the java array
665     if (cmdSize != 0) {
666         pCmdData = (jbyte *) env->GetPrimitiveArrayCritical(jCmdData, NULL);
667         if (pCmdData == NULL) {
668             ALOGE("setParameter: Error retrieving command pointer");
669             goto command_Exit;
670         }
671     }
672 
673     // get the pointer for the reply from the java array
674     if (replySize != 0 && jReplyData != NULL) {
675         pReplyData = (jbyte *) env->GetPrimitiveArrayCritical(jReplyData, NULL);
676         if (pReplyData == NULL) {
677             ALOGE("setParameter: Error retrieving reply pointer");
678             goto command_Exit;
679         }
680     }
681 
682     lStatus = translateError(lpAudioEffect->command((uint32_t)cmdCode,
683                                                     (uint32_t)cmdSize,
684                                                     pCmdData,
685                                                     (uint32_t *)&replySize,
686                                                     pReplyData));
687 
688 command_Exit:
689 
690     if (pCmdData != NULL) {
691         env->ReleasePrimitiveArrayCritical(jCmdData, pCmdData, 0);
692     }
693     if (pReplyData != NULL) {
694         env->ReleasePrimitiveArrayCritical(jReplyData, pReplyData, 0);
695     }
696 
697     if (lStatus == NO_ERROR) {
698         return replySize;
699     }
700     return lStatus;
701 }
702 
703 static jobjectArray
android_media_AudioEffect_native_queryEffects(JNIEnv * env,jclass clazz)704 android_media_AudioEffect_native_queryEffects(JNIEnv *env, jclass clazz)
705 {
706     effect_descriptor_t desc;
707     char str[EFFECT_STRING_LEN_MAX];
708     uint32_t numEffects = 0;
709     uint32_t i = 0;
710     jstring jdescType;
711     jstring jdescUuid;
712     jstring jdescConnect;
713     jstring jdescName;
714     jstring jdescImplementor;
715     jobject jdesc;
716 
717     if (AudioEffect::queryNumberEffects(&numEffects) != NO_ERROR) {
718         return NULL;
719     }
720 
721     jobjectArray ret = env->NewObjectArray(numEffects, fields.clazzDesc, NULL);
722     if (ret == NULL) {
723         return ret;
724     }
725 
726     ALOGV("queryEffects() numEffects: %d", numEffects);
727 
728     for (i = 0; i < numEffects; i++) {
729         if (AudioEffect::queryEffect(i, &desc) != NO_ERROR) {
730             goto queryEffects_failure;
731         }
732 
733         if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
734             jdescConnect = env->NewStringUTF("Auxiliary");
735         } else if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_INSERT) {
736             jdescConnect = env->NewStringUTF("Insert");
737         } else if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC) {
738             jdescConnect = env->NewStringUTF("Pre Processing");
739         } else {
740             continue;
741         }
742 
743         AudioEffect::guidToString(&desc.type, str, EFFECT_STRING_LEN_MAX);
744         jdescType = env->NewStringUTF(str);
745 
746         AudioEffect::guidToString(&desc.uuid, str, EFFECT_STRING_LEN_MAX);
747         jdescUuid = env->NewStringUTF(str);
748 
749         jdescName = env->NewStringUTF(desc.name);
750         jdescImplementor = env->NewStringUTF(desc.implementor);
751 
752         jdesc = env->NewObject(fields.clazzDesc,
753                                fields.midDescCstor,
754                                jdescType,
755                                jdescUuid,
756                                jdescConnect,
757                                jdescName,
758                                jdescImplementor);
759         env->DeleteLocalRef(jdescType);
760         env->DeleteLocalRef(jdescUuid);
761         env->DeleteLocalRef(jdescConnect);
762         env->DeleteLocalRef(jdescName);
763         env->DeleteLocalRef(jdescImplementor);
764         if (jdesc == NULL) {
765             ALOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)");
766             goto queryEffects_failure;
767         }
768 
769         env->SetObjectArrayElement(ret, i, jdesc);
770    }
771 
772     return ret;
773 
774 queryEffects_failure:
775 
776     if (ret != NULL) {
777         env->DeleteLocalRef(ret);
778     }
779     return NULL;
780 
781 }
782 
783 
784 
785 static jobjectArray
android_media_AudioEffect_native_queryPreProcessings(JNIEnv * env,jclass clazz,jint audioSession)786 android_media_AudioEffect_native_queryPreProcessings(JNIEnv *env, jclass clazz, jint audioSession)
787 {
788     // kDefaultNumEffects is a "reasonable" value ensuring that only one query will be enough on
789     // most devices to get all active audio pre processing on a given session.
790     static const uint32_t kDefaultNumEffects = 5;
791 
792     effect_descriptor_t *descriptors = new effect_descriptor_t[kDefaultNumEffects];
793     uint32_t numEffects = kDefaultNumEffects;
794 
795     status_t status = AudioEffect::queryDefaultPreProcessing(audioSession,
796                                            descriptors,
797                                            &numEffects);
798     if ((status != NO_ERROR && status != NO_MEMORY) ||
799             numEffects == 0) {
800         delete[] descriptors;
801         return NULL;
802     }
803     if (status == NO_MEMORY) {
804         delete [] descriptors;
805         descriptors = new effect_descriptor_t[numEffects];
806         status = AudioEffect::queryDefaultPreProcessing(audioSession,
807                                                descriptors,
808                                                &numEffects);
809     }
810     if (status != NO_ERROR || numEffects == 0) {
811         delete[] descriptors;
812         return NULL;
813     }
814     ALOGV("queryDefaultPreProcessing() got %d effects", numEffects);
815 
816     jobjectArray ret = env->NewObjectArray(numEffects, fields.clazzDesc, NULL);
817     if (ret == NULL) {
818         delete[] descriptors;
819         return ret;
820     }
821 
822     char str[EFFECT_STRING_LEN_MAX];
823     jstring jdescType;
824     jstring jdescUuid;
825     jstring jdescConnect;
826     jstring jdescName;
827     jstring jdescImplementor;
828     jobject jdesc;
829 
830     for (uint32_t i = 0; i < numEffects; i++) {
831 
832         AudioEffect::guidToString(&descriptors[i].type, str, EFFECT_STRING_LEN_MAX);
833         jdescType = env->NewStringUTF(str);
834         AudioEffect::guidToString(&descriptors[i].uuid, str, EFFECT_STRING_LEN_MAX);
835         jdescUuid = env->NewStringUTF(str);
836         jdescConnect = env->NewStringUTF("Pre Processing");
837         jdescName = env->NewStringUTF(descriptors[i].name);
838         jdescImplementor = env->NewStringUTF(descriptors[i].implementor);
839 
840         jdesc = env->NewObject(fields.clazzDesc,
841                                fields.midDescCstor,
842                                jdescType,
843                                jdescUuid,
844                                jdescConnect,
845                                jdescName,
846                                jdescImplementor);
847         env->DeleteLocalRef(jdescType);
848         env->DeleteLocalRef(jdescUuid);
849         env->DeleteLocalRef(jdescConnect);
850         env->DeleteLocalRef(jdescName);
851         env->DeleteLocalRef(jdescImplementor);
852         if (jdesc == NULL) {
853             ALOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)");
854             env->DeleteLocalRef(ret);
855             return NULL;;
856         }
857 
858         env->SetObjectArrayElement(ret, i, jdesc);
859    }
860 
861    return ret;
862 }
863 
864 // ----------------------------------------------------------------------------
865 
866 // Dalvik VM type signatures
867 static JNINativeMethod gMethods[] = {
868     {"native_init",          "()V",      (void *)android_media_AudioEffect_native_init},
869     {"native_setup",         "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;II[I[Ljava/lang/Object;)I",
870                                          (void *)android_media_AudioEffect_native_setup},
871     {"native_finalize",      "()V",      (void *)android_media_AudioEffect_native_finalize},
872     {"native_release",       "()V",      (void *)android_media_AudioEffect_native_release},
873     {"native_setEnabled",    "(Z)I",      (void *)android_media_AudioEffect_native_setEnabled},
874     {"native_getEnabled",    "()Z",      (void *)android_media_AudioEffect_native_getEnabled},
875     {"native_hasControl",    "()Z",      (void *)android_media_AudioEffect_native_hasControl},
876     {"native_setParameter",  "(I[BI[B)I",  (void *)android_media_AudioEffect_native_setParameter},
877     {"native_getParameter",  "(I[BI[B)I",  (void *)android_media_AudioEffect_native_getParameter},
878     {"native_command",       "(II[BI[B)I", (void *)android_media_AudioEffect_native_command},
879     {"native_query_effects", "()[Ljava/lang/Object;", (void *)android_media_AudioEffect_native_queryEffects},
880     {"native_query_pre_processing", "(I)[Ljava/lang/Object;",
881             (void *)android_media_AudioEffect_native_queryPreProcessings},
882 };
883 
884 
885 // ----------------------------------------------------------------------------
886 
887 extern int register_android_media_visualizer(JNIEnv *env);
888 
register_android_media_AudioEffect(JNIEnv * env)889 int register_android_media_AudioEffect(JNIEnv *env)
890 {
891     return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
892 }
893 
JNI_OnLoad(JavaVM * vm,void * reserved)894 jint JNI_OnLoad(JavaVM* vm, void* reserved)
895 {
896 
897     JNIEnv* env = NULL;
898     jint result = -1;
899 
900     if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
901         ALOGE("ERROR: GetEnv failed\n");
902         goto bail;
903     }
904     assert(env != NULL);
905 
906     if (register_android_media_AudioEffect(env) < 0) {
907         ALOGE("ERROR: AudioEffect native registration failed\n");
908         goto bail;
909     }
910 
911     if (register_android_media_visualizer(env) < 0) {
912         ALOGE("ERROR: Visualizer native registration failed\n");
913         goto bail;
914     }
915 
916     /* success -- return valid version number */
917     result = JNI_VERSION_1_4;
918 
919 bail:
920     return result;
921 }
922 
923