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