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