• 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,jint deviceType,jstring deviceAddress,jintArray jId,jobjectArray javadesc,jstring opPackageName,jboolean probe)270 android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
271         jstring type, jstring uuid, jint priority, jint sessionId,
272         jint deviceType, jstring deviceAddress,
273         jintArray jId, jobjectArray javadesc, jstring opPackageName, jboolean probe)
274 {
275     ALOGV("android_media_AudioEffect_native_setup");
276     AudioEffectJniStorage* lpJniStorage = NULL;
277     int lStatus = AUDIOEFFECT_ERROR_NO_MEMORY;
278     sp<AudioEffect> lpAudioEffect;
279     jint* nId = NULL;
280     const char *typeStr = NULL;
281     const char *uuidStr = NULL;
282     effect_descriptor_t desc;
283     jobject jdesc;
284     AudioDeviceTypeAddr device;
285 
286     ScopedUtfChars opPackageNameStr(env, opPackageName);
287 
288     setAudioEffect(env, thiz, 0);
289 
290     if (type != NULL) {
291         typeStr = env->GetStringUTFChars(type, NULL);
292         if (typeStr == NULL) {  // Out of memory
293             jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
294             goto setup_failure;
295         }
296     }
297 
298     if (uuid != NULL) {
299         uuidStr = env->GetStringUTFChars(uuid, NULL);
300         if (uuidStr == NULL) {  // Out of memory
301             jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
302             goto setup_failure;
303         }
304     }
305 
306     if (typeStr == NULL && uuidStr == NULL) {
307         lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
308         goto setup_failure;
309     }
310 
311     lpJniStorage = new AudioEffectJniStorage();
312     if (lpJniStorage == NULL) {
313         ALOGE("setup: Error creating JNI Storage");
314         goto setup_failure;
315     }
316 
317     lpJniStorage->mCallbackData.audioEffect_class = (jclass)env->NewGlobalRef(fields.clazzEffect);
318     // we use a weak reference so the AudioEffect object can be garbage collected.
319     lpJniStorage->mCallbackData.audioEffect_ref = env->NewGlobalRef(weak_this);
320 
321     ALOGV("setup: lpJniStorage: %p audioEffect_ref %p audioEffect_class %p, &mCallbackData %p",
322             lpJniStorage,
323             lpJniStorage->mCallbackData.audioEffect_ref,
324             lpJniStorage->mCallbackData.audioEffect_class,
325             &lpJniStorage->mCallbackData);
326 
327     if (jId == NULL) {
328         ALOGE("setup: NULL java array for id pointer");
329         lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
330         goto setup_failure;
331     }
332 
333     if (deviceType != AUDIO_DEVICE_NONE) {
334         device.mType = deviceType;
335         ScopedUtfChars address(env, deviceAddress);
336         device.mAddress = address.c_str();
337     }
338 
339     // create the native AudioEffect object
340     lpAudioEffect = new AudioEffect(String16(opPackageNameStr.c_str()));
341     if (lpAudioEffect == 0) {
342         ALOGE("Error creating AudioEffect");
343         goto setup_failure;
344     }
345 
346     lpAudioEffect->set(typeStr,
347                        uuidStr,
348                        priority,
349                        effectCallback,
350                        &lpJniStorage->mCallbackData,
351                        (audio_session_t) sessionId,
352                        AUDIO_IO_HANDLE_NONE,
353                        device,
354                        probe);
355     lStatus = AudioEffectJni::translateNativeErrorToJava(lpAudioEffect->initCheck());
356     if (lStatus != AUDIOEFFECT_SUCCESS && lStatus != AUDIOEFFECT_ERROR_ALREADY_EXISTS) {
357         ALOGE("AudioEffect initCheck failed %d", lStatus);
358         goto setup_failure;
359     }
360 
361     nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL);
362     if (nId == NULL) {
363         ALOGE("setup: Error retrieving id pointer");
364         lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
365         goto setup_failure;
366     }
367     nId[0] = lpAudioEffect->id();
368     env->ReleasePrimitiveArrayCritical(jId, nId, 0);
369     nId = NULL;
370 
371     if (typeStr) {
372         env->ReleaseStringUTFChars(type, typeStr);
373         typeStr = NULL;
374     }
375 
376     if (uuidStr) {
377         env->ReleaseStringUTFChars(uuid, uuidStr);
378         uuidStr = NULL;
379     }
380 
381     // get the effect descriptor
382     desc = lpAudioEffect->descriptor();
383 
384     if (convertAudioEffectDescriptorFromNative(env, &jdesc, &desc) != AUDIO_JAVA_SUCCESS) {
385         goto setup_failure;
386     }
387 
388     env->SetObjectArrayElement(javadesc, 0, jdesc);
389     env->DeleteLocalRef(jdesc);
390 
391     // In probe mode, release the native object and clear our strong reference
392     // to force all method calls from JAVA to be rejected.
393     if (probe) {
394         setAudioEffect(env, thiz, 0);
395     } else {
396         setAudioEffect(env, thiz, lpAudioEffect);
397     }
398 
399     env->SetLongField(thiz, fields.fidJniData, (jlong)lpJniStorage);
400 
401     return (jint) AUDIOEFFECT_SUCCESS;
402 
403     // failures:
404 setup_failure:
405 
406     if (nId != NULL) {
407         env->ReleasePrimitiveArrayCritical(jId, nId, 0);
408     }
409 
410     if (lpJniStorage) {
411         env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioEffect_class);
412         env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioEffect_ref);
413         delete lpJniStorage;
414     }
415     env->SetLongField(thiz, fields.fidJniData, 0);
416 
417     if (uuidStr != NULL) {
418         env->ReleaseStringUTFChars(uuid, uuidStr);
419     }
420 
421     if (typeStr != NULL) {
422         env->ReleaseStringUTFChars(type, typeStr);
423     }
424 
425     return (jint)lStatus;
426 }
427 
428 
429 // ----------------------------------------------------------------------------
android_media_AudioEffect_native_release(JNIEnv * env,jobject thiz)430 static void android_media_AudioEffect_native_release(JNIEnv *env,  jobject thiz) {
431     sp<AudioEffect> lpAudioEffect = setAudioEffect(env, thiz, 0);
432     if (lpAudioEffect == 0) {
433         return;
434     }
435 
436     // delete the JNI data
437     AudioEffectJniStorage* lpJniStorage =
438         (AudioEffectJniStorage *)env->GetLongField(thiz, fields.fidJniData);
439 
440     // reset the native resources in the Java object so any attempt to access
441     // them after a call to release fails.
442     env->SetLongField(thiz, fields.fidJniData, 0);
443 
444     if (lpJniStorage) {
445         ALOGV("deleting pJniStorage: %p\n", lpJniStorage);
446         env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioEffect_class);
447         env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioEffect_ref);
448         delete lpJniStorage;
449     }
450 }
451 
452 // ----------------------------------------------------------------------------
android_media_AudioEffect_native_finalize(JNIEnv * env,jobject thiz)453 static void android_media_AudioEffect_native_finalize(JNIEnv *env,  jobject thiz) {
454     ALOGV("android_media_AudioEffect_native_finalize jobject: %p\n", thiz);
455     android_media_AudioEffect_native_release(env, thiz);
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     sp<AudioEffect> lpAudioEffect = getAudioEffect(env, thiz);
462     if (lpAudioEffect == 0) {
463         jniThrowException(env, "java/lang/IllegalStateException",
464             "Unable to retrieve AudioEffect pointer for enable()");
465         return AUDIOEFFECT_ERROR_NO_INIT;
466     }
467 
468     return AudioEffectJni::translateNativeErrorToJava(lpAudioEffect->setEnabled(enabled));
469 }
470 
471 static jboolean
android_media_AudioEffect_native_getEnabled(JNIEnv * env,jobject thiz)472 android_media_AudioEffect_native_getEnabled(JNIEnv *env, jobject thiz)
473 {
474   sp<AudioEffect> lpAudioEffect = getAudioEffect(env, thiz);
475   if (lpAudioEffect == 0) {
476         jniThrowException(env, "java/lang/IllegalStateException",
477             "Unable to retrieve AudioEffect pointer for getEnabled()");
478         return JNI_FALSE;
479     }
480 
481     if (lpAudioEffect->getEnabled()) {
482         return JNI_TRUE;
483     } else {
484         return JNI_FALSE;
485     }
486 }
487 
488 
489 static jboolean
android_media_AudioEffect_native_hasControl(JNIEnv * env,jobject thiz)490 android_media_AudioEffect_native_hasControl(JNIEnv *env, jobject thiz)
491 {
492   sp<AudioEffect> lpAudioEffect = getAudioEffect(env, thiz);
493   if (lpAudioEffect == 0) {
494         jniThrowException(env, "java/lang/IllegalStateException",
495             "Unable to retrieve AudioEffect pointer for hasControl()");
496         return JNI_FALSE;
497     }
498 
499     if (lpAudioEffect->initCheck() == NO_ERROR) {
500         return JNI_TRUE;
501     } else {
502         return JNI_FALSE;
503     }
504 }
505 
android_media_AudioEffect_native_setParameter(JNIEnv * env,jobject thiz,jint psize,jbyteArray pJavaParam,jint vsize,jbyteArray pJavaValue)506 static jint android_media_AudioEffect_native_setParameter(JNIEnv *env,
507         jobject thiz, jint psize, jbyteArray pJavaParam, jint vsize,
508         jbyteArray pJavaValue) {
509     // retrieve the AudioEffect object
510     jbyte* lpValue = NULL;
511     jbyte* lpParam = NULL;
512     jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
513     effect_param_t *p;
514     int voffset;
515 
516     sp<AudioEffect> lpAudioEffect = getAudioEffect(env, thiz);
517     if (lpAudioEffect == 0) {
518         jniThrowException(env, "java/lang/IllegalStateException",
519                 "Unable to retrieve AudioEffect pointer for setParameter()");
520         return AUDIOEFFECT_ERROR_NO_INIT;
521     }
522 
523     if (psize == 0 || vsize == 0 || pJavaParam == NULL || pJavaValue == NULL) {
524         return AUDIOEFFECT_ERROR_BAD_VALUE;
525     }
526 
527     // get the pointer for the param from the java array
528     lpParam = (jbyte *) env->GetPrimitiveArrayCritical(pJavaParam, NULL);
529     if (lpParam == NULL) {
530         ALOGE("setParameter: Error retrieving param pointer");
531         goto setParameter_Exit;
532     }
533 
534     // get the pointer for the value from the java array
535     lpValue = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValue, NULL);
536     if (lpValue == NULL) {
537         ALOGE("setParameter: Error retrieving value pointer");
538         goto setParameter_Exit;
539     }
540 
541     voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int);
542     p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset + vsize);
543     memcpy(p->data, lpParam, psize);
544     p->psize = psize;
545     memcpy(p->data + voffset, lpValue, vsize);
546     p->vsize = vsize;
547 
548     lStatus = lpAudioEffect->setParameter(p);
549     if (lStatus == NO_ERROR) {
550         lStatus = p->status;
551     }
552 
553     free(p);
554 
555 setParameter_Exit:
556 
557     if (lpParam != NULL) {
558         env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0);
559     }
560     if (lpValue != NULL) {
561         env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
562     }
563     return AudioEffectJni::translateNativeErrorToJava(lStatus);
564 }
565 
566 static jint
android_media_AudioEffect_native_getParameter(JNIEnv * env,jobject thiz,jint psize,jbyteArray pJavaParam,jint vsize,jbyteArray pJavaValue)567 android_media_AudioEffect_native_getParameter(JNIEnv *env,
568         jobject thiz, jint psize, jbyteArray pJavaParam,
569         jint vsize, jbyteArray pJavaValue) {
570     // retrieve the AudioEffect object
571     jbyte* lpParam = NULL;
572     jbyte* lpValue = NULL;
573     jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
574     effect_param_t *p;
575     int voffset;
576 
577     sp<AudioEffect> lpAudioEffect = getAudioEffect(env, thiz);
578     if (lpAudioEffect == 0) {
579         jniThrowException(env, "java/lang/IllegalStateException",
580                 "Unable to retrieve AudioEffect pointer for getParameter()");
581         return AUDIOEFFECT_ERROR_NO_INIT;
582     }
583 
584     if (psize == 0 || vsize == 0 || pJavaParam == NULL || pJavaValue == NULL) {
585         return AUDIOEFFECT_ERROR_BAD_VALUE;
586     }
587 
588     // get the pointer for the param from the java array
589     lpParam = (jbyte *) env->GetPrimitiveArrayCritical(pJavaParam, NULL);
590     if (lpParam == NULL) {
591         ALOGE("getParameter: Error retrieving param pointer");
592         goto getParameter_Exit;
593     }
594 
595     // get the pointer for the value from the java array
596     lpValue = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValue, NULL);
597     if (lpValue == NULL) {
598         ALOGE("getParameter: Error retrieving value pointer");
599         goto getParameter_Exit;
600     }
601 
602     voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int);
603     p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset + vsize);
604     memcpy(p->data, lpParam, psize);
605     p->psize = psize;
606     p->vsize = vsize;
607 
608     lStatus = lpAudioEffect->getParameter(p);
609     if (lStatus == NO_ERROR) {
610         lStatus = p->status;
611         if (lStatus == NO_ERROR) {
612             memcpy(lpValue, p->data + voffset, p->vsize);
613             vsize = p->vsize;
614         }
615     }
616 
617     free(p);
618 
619 getParameter_Exit:
620 
621     if (lpParam != NULL) {
622         env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0);
623     }
624     if (lpValue != NULL) {
625         env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
626     }
627 
628     if (lStatus == NO_ERROR) {
629         return vsize;
630     }
631     return AudioEffectJni::translateNativeErrorToJava(lStatus);
632 }
633 
android_media_AudioEffect_native_command(JNIEnv * env,jobject thiz,jint cmdCode,jint cmdSize,jbyteArray jCmdData,jint replySize,jbyteArray jReplyData)634 static jint android_media_AudioEffect_native_command(JNIEnv *env, jobject thiz,
635         jint cmdCode, jint cmdSize, jbyteArray jCmdData, jint replySize,
636         jbyteArray jReplyData) {
637     jbyte* pCmdData = NULL;
638     jbyte* pReplyData = NULL;
639     jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
640 
641     sp<AudioEffect> lpAudioEffect = getAudioEffect(env, thiz);
642     if (lpAudioEffect == 0) {
643         jniThrowException(env, "java/lang/IllegalStateException",
644                 "Unable to retrieve AudioEffect pointer for setParameter()");
645         return AUDIOEFFECT_ERROR_NO_INIT;
646     }
647 
648     if ((cmdSize != 0 && jCmdData == NULL) || (replySize != 0 && jReplyData == NULL)) {
649         return AUDIOEFFECT_ERROR_BAD_VALUE;
650     }
651 
652     // get the pointer for the command from the java array
653     if (cmdSize != 0) {
654         pCmdData = (jbyte *) env->GetPrimitiveArrayCritical(jCmdData, NULL);
655         if (pCmdData == NULL) {
656             ALOGE("setParameter: Error retrieving command pointer");
657             goto command_Exit;
658         }
659     }
660 
661     // get the pointer for the reply from the java array
662     if (replySize != 0 && jReplyData != NULL) {
663         pReplyData = (jbyte *) env->GetPrimitiveArrayCritical(jReplyData, NULL);
664         if (pReplyData == NULL) {
665             ALOGE("setParameter: Error retrieving reply pointer");
666             goto command_Exit;
667         }
668     }
669 
670     lStatus = AudioEffectJni::translateNativeErrorToJava(
671             lpAudioEffect->command((uint32_t)cmdCode,
672                                    (uint32_t)cmdSize,
673                                    pCmdData,
674                                    (uint32_t *)&replySize,
675                                    pReplyData));
676 
677 command_Exit:
678 
679     if (pCmdData != NULL) {
680         env->ReleasePrimitiveArrayCritical(jCmdData, pCmdData, 0);
681     }
682     if (pReplyData != NULL) {
683         env->ReleasePrimitiveArrayCritical(jReplyData, pReplyData, 0);
684     }
685 
686     if (lStatus == NO_ERROR) {
687         return replySize;
688     }
689     return lStatus;
690 }
691 
692 static jobjectArray
android_media_AudioEffect_native_queryEffects(JNIEnv * env,jclass clazz __unused)693 android_media_AudioEffect_native_queryEffects(JNIEnv *env, jclass clazz __unused)
694 {
695     effect_descriptor_t desc;
696     uint32_t totalEffectsCount = 0;
697     uint32_t returnedEffectsCount = 0;
698     uint32_t i = 0;
699     jobjectArray ret;
700 
701     if (AudioEffect::queryNumberEffects(&totalEffectsCount) != NO_ERROR) {
702         return NULL;
703     }
704 
705     jobjectArray temp = env->NewObjectArray(totalEffectsCount, audioEffectDescriptorClass(), NULL);
706     if (temp == NULL) {
707         return temp;
708     }
709 
710     ALOGV("queryEffects() totalEffectsCount: %d", totalEffectsCount);
711 
712     for (i = 0; i < totalEffectsCount; i++) {
713         if (AudioEffect::queryEffect(i, &desc) != NO_ERROR) {
714             goto queryEffects_failure;
715         }
716 
717         jobject jdesc;
718         if (convertAudioEffectDescriptorFromNative(env, &jdesc, &desc) != AUDIO_JAVA_SUCCESS) {
719             continue;
720         }
721         env->SetObjectArrayElement(temp, returnedEffectsCount++, jdesc);
722         env->DeleteLocalRef(jdesc);
723     }
724 
725     if (returnedEffectsCount == 0) {
726         goto queryEffects_failure;
727     }
728     ret = env->NewObjectArray(returnedEffectsCount, audioEffectDescriptorClass(), NULL);
729     if (ret == NULL) {
730         goto queryEffects_failure;
731     }
732     for (i = 0; i < returnedEffectsCount; i++) {
733         env->SetObjectArrayElement(ret, i, env->GetObjectArrayElement(temp, i));
734     }
735     env->DeleteLocalRef(temp);
736     return ret;
737 
738 queryEffects_failure:
739 
740     if (temp != NULL) {
741         env->DeleteLocalRef(temp);
742     }
743     return NULL;
744 
745 }
746 
747 
748 
749 static jobjectArray
android_media_AudioEffect_native_queryPreProcessings(JNIEnv * env,jclass clazz __unused,jint audioSession)750 android_media_AudioEffect_native_queryPreProcessings(JNIEnv *env, jclass clazz __unused,
751                                                      jint audioSession)
752 {
753     auto descriptors = std::make_unique<effect_descriptor_t[]>(AudioEffect::kMaxPreProcessing);
754     uint32_t numEffects = AudioEffect::kMaxPreProcessing;
755 
756     status_t status = AudioEffect::queryDefaultPreProcessing((audio_session_t) audioSession,
757                                            descriptors.get(),
758                                            &numEffects);
759     if (status != NO_ERROR || numEffects == 0) {
760         return NULL;
761     }
762     ALOGV("queryDefaultPreProcessing() got %d effects", numEffects);
763 
764     std::vector<effect_descriptor_t> descVector(descriptors.get(), descriptors.get() + numEffects);
765 
766     jobjectArray ret;
767     convertAudioEffectDescriptorVectorFromNative(env, &ret, descVector);
768     return ret;
769 }
770 
771 // ----------------------------------------------------------------------------
772 
773 // Dalvik VM type signatures
774 static const JNINativeMethod gMethods[] = {
775     {"native_init",          "()V",      (void *)android_media_AudioEffect_native_init},
776     {"native_setup",         "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;IIILjava/lang/String;[I[Ljava/lang/Object;Ljava/lang/String;Z)I",
777                                          (void *)android_media_AudioEffect_native_setup},
778     {"native_finalize",      "()V",      (void *)android_media_AudioEffect_native_finalize},
779     {"native_release",       "()V",      (void *)android_media_AudioEffect_native_release},
780     {"native_setEnabled",    "(Z)I",      (void *)android_media_AudioEffect_native_setEnabled},
781     {"native_getEnabled",    "()Z",      (void *)android_media_AudioEffect_native_getEnabled},
782     {"native_hasControl",    "()Z",      (void *)android_media_AudioEffect_native_hasControl},
783     {"native_setParameter",  "(I[BI[B)I",  (void *)android_media_AudioEffect_native_setParameter},
784     {"native_getParameter",  "(I[BI[B)I",  (void *)android_media_AudioEffect_native_getParameter},
785     {"native_command",       "(II[BI[B)I", (void *)android_media_AudioEffect_native_command},
786     {"native_query_effects", "()[Ljava/lang/Object;", (void *)android_media_AudioEffect_native_queryEffects},
787     {"native_query_pre_processing", "(I)[Ljava/lang/Object;",
788             (void *)android_media_AudioEffect_native_queryPreProcessings},
789 };
790 
791 
792 // ----------------------------------------------------------------------------
793 
794 extern int register_android_media_SourceDefaultEffect(JNIEnv *env);
795 extern int register_android_media_StreamDefaultEffect(JNIEnv *env);
796 extern int register_android_media_visualizer(JNIEnv *env);
797 
register_android_media_AudioEffect(JNIEnv * env)798 int register_android_media_AudioEffect(JNIEnv *env)
799 {
800     return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
801 }
802 
JNI_OnLoad(JavaVM * vm,void * reserved __unused)803 jint JNI_OnLoad(JavaVM* vm, void* reserved __unused)
804 {
805 
806     JNIEnv* env = NULL;
807     jint result = -1;
808 
809     if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
810         ALOGE("ERROR: GetEnv failed\n");
811         goto bail;
812     }
813     assert(env != NULL);
814 
815     if (register_android_media_AudioEffect(env) < 0) {
816         ALOGE("ERROR: AudioEffect native registration failed\n");
817         goto bail;
818     }
819 
820     if (register_android_media_SourceDefaultEffect(env) < 0) {
821         ALOGE("ERROR: SourceDefaultEffect native registration failed\n");
822         goto bail;
823     }
824 
825     if (register_android_media_StreamDefaultEffect(env) < 0) {
826         ALOGE("ERROR: StreamDefaultEffect native registration failed\n");
827         goto bail;
828     }
829 
830     if (register_android_media_visualizer(env) < 0) {
831         ALOGE("ERROR: Visualizer native registration failed\n");
832         goto bail;
833     }
834 
835     /* success -- return valid version number */
836     result = JNI_VERSION_1_4;
837 
838 bail:
839     return result;
840 }
841