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 68 AudioEffectJniStorage() { 69 } 70 71 ~AudioEffectJniStorage() { 72 } 73 74 }; 75 76 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 // ---------------------------------------------------------------------------- 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 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 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 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 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 // ---------------------------------------------------------------------------- 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 // ---------------------------------------------------------------------------- 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 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 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 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 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 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 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 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 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 782 int register_android_media_AudioEffect(JNIEnv *env) 783 { 784 return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)); 785 } 786 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