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