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