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 63 AudioEffectJniStorage() { 64 } 65 66 ~AudioEffectJniStorage() { 67 } 68 69 }; 70 71 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 // ---------------------------------------------------------------------------- 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 ALOGV("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 ALOGW("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 ALOGW("EVENT_CONTROL_STATUS_CHANGED info == NULL"); 123 goto effectCallback_Exit; 124 } 125 param = *(bool *)info; 126 arg1 = (int)param; 127 ALOGV("EVENT_CONTROL_STATUS_CHANGED"); 128 break; 129 case AudioEffect::EVENT_ENABLE_STATUS_CHANGED: 130 if (info == 0) { 131 ALOGW("EVENT_ENABLE_STATUS_CHANGED info == NULL"); 132 goto effectCallback_Exit; 133 } 134 param = *(bool *)info; 135 arg1 = (int)param; 136 ALOGV("EVENT_ENABLE_STATUS_CHANGED"); 137 break; 138 case AudioEffect::EVENT_PARAMETER_CHANGED: 139 if (info == 0) { 140 ALOGW("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 ALOGE("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 ALOGV("EVENT_PARAMETER_CHANGED"); 160 break; 161 case AudioEffect::EVENT_ERROR: 162 ALOGW("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 187 android_media_AudioEffect_native_init(JNIEnv *env) 188 { 189 190 ALOGV("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 ALOGE("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 ALOGE("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", "J"); 218 if (fields.fidNativeAudioEffect == NULL) { 219 ALOGE("Can't find AudioEffect.%s", "mNativeAudioEffect"); 220 return; 221 } 222 // fidJniData; 223 fields.fidJniData = env->GetFieldID( 224 fields.clazzEffect, 225 "mJniData", "J"); 226 if (fields.fidJniData == NULL) { 227 ALOGE("Can't find AudioEffect.%s", "mJniData"); 228 return; 229 } 230 231 clazz = env->FindClass("android/media/audiofx/AudioEffect$Descriptor"); 232 if (clazz == NULL) { 233 ALOGE("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 ALOGE("Can't find android/media/audiofx/AudioEffect$Descriptor class constructor"); 245 return; 246 } 247 } 248 249 250 static jint 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 ALOGV("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 ALOGE("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 ALOGV("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 ALOGE("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 ALOGE("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 ALOGE("AudioEffect initCheck failed %d", lStatus); 329 goto setup_failure; 330 } 331 332 nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL); 333 if (nId == NULL) { 334 ALOGE("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 if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC) { 364 jdescConnect = env->NewStringUTF("Pre Processing"); 365 } else { 366 jdescConnect = env->NewStringUTF("Insert"); 367 } 368 369 jdescName = env->NewStringUTF(desc.name); 370 jdescImplementor = env->NewStringUTF(desc.implementor); 371 372 jdesc = env->NewObject(fields.clazzDesc, 373 fields.midDescCstor, 374 jdescType, 375 jdescUuid, 376 jdescConnect, 377 jdescName, 378 jdescImplementor); 379 env->DeleteLocalRef(jdescType); 380 env->DeleteLocalRef(jdescUuid); 381 env->DeleteLocalRef(jdescConnect); 382 env->DeleteLocalRef(jdescName); 383 env->DeleteLocalRef(jdescImplementor); 384 if (jdesc == NULL) { 385 ALOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)"); 386 goto setup_failure; 387 } 388 389 env->SetObjectArrayElement(javadesc, 0, jdesc); 390 391 env->SetLongField(thiz, fields.fidNativeAudioEffect, (jlong)lpAudioEffect); 392 393 env->SetLongField(thiz, fields.fidJniData, (jlong)lpJniStorage); 394 395 return (jint) AUDIOEFFECT_SUCCESS; 396 397 // failures: 398 setup_failure: 399 400 if (nId != NULL) { 401 env->ReleasePrimitiveArrayCritical(jId, nId, 0); 402 } 403 404 if (lpAudioEffect) { 405 delete lpAudioEffect; 406 } 407 env->SetLongField(thiz, fields.fidNativeAudioEffect, 0); 408 409 if (lpJniStorage) { 410 delete lpJniStorage; 411 } 412 env->SetLongField(thiz, fields.fidJniData, 0); 413 414 if (uuidStr != NULL) { 415 env->ReleaseStringUTFChars(uuid, uuidStr); 416 } 417 418 if (typeStr != NULL) { 419 env->ReleaseStringUTFChars(type, typeStr); 420 } 421 422 return (jint)lStatus; 423 } 424 425 426 // ---------------------------------------------------------------------------- 427 static void android_media_AudioEffect_native_finalize(JNIEnv *env, jobject thiz) { 428 ALOGV("android_media_AudioEffect_native_finalize jobject: %p\n", thiz); 429 430 // delete the AudioEffect object 431 AudioEffect* lpAudioEffect = (AudioEffect *)env->GetLongField( 432 thiz, fields.fidNativeAudioEffect); 433 if (lpAudioEffect) { 434 ALOGV("deleting AudioEffect: %p\n", lpAudioEffect); 435 delete lpAudioEffect; 436 } 437 438 // delete the JNI data 439 AudioEffectJniStorage* lpJniStorage = (AudioEffectJniStorage *)env->GetLongField( 440 thiz, fields.fidJniData); 441 if (lpJniStorage) { 442 ALOGV("deleting pJniStorage: %p\n", lpJniStorage); 443 delete lpJniStorage; 444 } 445 } 446 447 // ---------------------------------------------------------------------------- 448 static void android_media_AudioEffect_native_release(JNIEnv *env, jobject thiz) { 449 450 // do everything a call to finalize would 451 android_media_AudioEffect_native_finalize(env, thiz); 452 // + reset the native resources in the Java object so any attempt to access 453 // them after a call to release fails. 454 env->SetLongField(thiz, fields.fidNativeAudioEffect, 0); 455 env->SetLongField(thiz, fields.fidJniData, 0); 456 } 457 458 static jint 459 android_media_AudioEffect_native_setEnabled(JNIEnv *env, jobject thiz, jboolean enabled) 460 { 461 // retrieve the AudioEffect object 462 AudioEffect* lpAudioEffect = (AudioEffect *)env->GetLongField( 463 thiz, fields.fidNativeAudioEffect); 464 465 if (lpAudioEffect == NULL) { 466 jniThrowException(env, "java/lang/IllegalStateException", 467 "Unable to retrieve AudioEffect pointer for enable()"); 468 return AUDIOEFFECT_ERROR_NO_INIT; 469 } 470 471 return (jint) translateError(lpAudioEffect->setEnabled(enabled)); 472 } 473 474 static jboolean 475 android_media_AudioEffect_native_getEnabled(JNIEnv *env, jobject thiz) 476 { 477 // retrieve the AudioEffect object 478 AudioEffect* lpAudioEffect = (AudioEffect *)env->GetLongField( 479 thiz, fields.fidNativeAudioEffect); 480 481 if (lpAudioEffect == NULL) { 482 jniThrowException(env, "java/lang/IllegalStateException", 483 "Unable to retrieve AudioEffect pointer for getEnabled()"); 484 return JNI_FALSE; 485 } 486 487 if (lpAudioEffect->getEnabled()) { 488 return JNI_TRUE; 489 } else { 490 return JNI_FALSE; 491 } 492 } 493 494 495 static jboolean 496 android_media_AudioEffect_native_hasControl(JNIEnv *env, jobject thiz) 497 { 498 // retrieve the AudioEffect object 499 AudioEffect* lpAudioEffect = (AudioEffect *)env->GetLongField( 500 thiz, fields.fidNativeAudioEffect); 501 502 if (lpAudioEffect == NULL) { 503 jniThrowException(env, "java/lang/IllegalStateException", 504 "Unable to retrieve AudioEffect pointer for hasControl()"); 505 return JNI_FALSE; 506 } 507 508 if (lpAudioEffect->initCheck() == NO_ERROR) { 509 return JNI_TRUE; 510 } else { 511 return JNI_FALSE; 512 } 513 } 514 515 static jint android_media_AudioEffect_native_setParameter(JNIEnv *env, 516 jobject thiz, jint psize, jbyteArray pJavaParam, jint vsize, 517 jbyteArray pJavaValue) { 518 // retrieve the AudioEffect object 519 jbyte* lpValue = NULL; 520 jbyte* lpParam = NULL; 521 jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE; 522 effect_param_t *p; 523 int voffset; 524 525 AudioEffect* lpAudioEffect = (AudioEffect *) env->GetLongField(thiz, 526 fields.fidNativeAudioEffect); 527 528 if (lpAudioEffect == NULL) { 529 jniThrowException(env, "java/lang/IllegalStateException", 530 "Unable to retrieve AudioEffect pointer for setParameter()"); 531 return AUDIOEFFECT_ERROR_NO_INIT; 532 } 533 534 if (psize == 0 || vsize == 0 || pJavaParam == NULL || pJavaValue == NULL) { 535 return AUDIOEFFECT_ERROR_BAD_VALUE; 536 } 537 538 // get the pointer for the param from the java array 539 lpParam = (jbyte *) env->GetPrimitiveArrayCritical(pJavaParam, NULL); 540 if (lpParam == NULL) { 541 ALOGE("setParameter: Error retrieving param pointer"); 542 goto setParameter_Exit; 543 } 544 545 // get the pointer for the value from the java array 546 lpValue = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValue, NULL); 547 if (lpValue == NULL) { 548 ALOGE("setParameter: Error retrieving value pointer"); 549 goto setParameter_Exit; 550 } 551 552 voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int); 553 p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset + vsize); 554 memcpy(p->data, lpParam, psize); 555 p->psize = psize; 556 memcpy(p->data + voffset, lpValue, vsize); 557 p->vsize = vsize; 558 559 lStatus = lpAudioEffect->setParameter(p); 560 if (lStatus == NO_ERROR) { 561 lStatus = p->status; 562 } 563 564 free(p); 565 566 setParameter_Exit: 567 568 if (lpParam != NULL) { 569 env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0); 570 } 571 if (lpValue != NULL) { 572 env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0); 573 } 574 return (jint) translateError(lStatus); 575 } 576 577 static jint 578 android_media_AudioEffect_native_getParameter(JNIEnv *env, 579 jobject thiz, jint psize, jbyteArray pJavaParam, 580 jint vsize, jbyteArray pJavaValue) { 581 // retrieve the AudioEffect object 582 jbyte* lpParam = NULL; 583 jbyte* lpValue = NULL; 584 jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE; 585 effect_param_t *p; 586 int voffset; 587 588 AudioEffect* lpAudioEffect = (AudioEffect *) env->GetLongField(thiz, 589 fields.fidNativeAudioEffect); 590 591 if (lpAudioEffect == NULL) { 592 jniThrowException(env, "java/lang/IllegalStateException", 593 "Unable to retrieve AudioEffect pointer for getParameter()"); 594 return AUDIOEFFECT_ERROR_NO_INIT; 595 } 596 597 if (psize == 0 || vsize == 0 || pJavaParam == NULL || pJavaValue == NULL) { 598 return AUDIOEFFECT_ERROR_BAD_VALUE; 599 } 600 601 // get the pointer for the param from the java array 602 lpParam = (jbyte *) env->GetPrimitiveArrayCritical(pJavaParam, NULL); 603 if (lpParam == NULL) { 604 ALOGE("getParameter: Error retrieving param pointer"); 605 goto getParameter_Exit; 606 } 607 608 // get the pointer for the value from the java array 609 lpValue = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValue, NULL); 610 if (lpValue == NULL) { 611 ALOGE("getParameter: Error retrieving value pointer"); 612 goto getParameter_Exit; 613 } 614 615 voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int); 616 p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset + vsize); 617 memcpy(p->data, lpParam, psize); 618 p->psize = psize; 619 p->vsize = vsize; 620 621 lStatus = lpAudioEffect->getParameter(p); 622 if (lStatus == NO_ERROR) { 623 lStatus = p->status; 624 if (lStatus == NO_ERROR) { 625 memcpy(lpValue, p->data + voffset, p->vsize); 626 vsize = p->vsize; 627 } 628 } 629 630 free(p); 631 632 getParameter_Exit: 633 634 if (lpParam != NULL) { 635 env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0); 636 } 637 if (lpValue != NULL) { 638 env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0); 639 } 640 641 if (lStatus == NO_ERROR) { 642 return vsize; 643 } 644 return (jint) translateError(lStatus); 645 } 646 647 static jint android_media_AudioEffect_native_command(JNIEnv *env, jobject thiz, 648 jint cmdCode, jint cmdSize, jbyteArray jCmdData, jint replySize, 649 jbyteArray jReplyData) { 650 jbyte* pCmdData = NULL; 651 jbyte* pReplyData = NULL; 652 jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE; 653 654 // retrieve the AudioEffect object 655 AudioEffect* lpAudioEffect = (AudioEffect *) env->GetLongField(thiz, 656 fields.fidNativeAudioEffect); 657 658 if (lpAudioEffect == NULL) { 659 jniThrowException(env, "java/lang/IllegalStateException", 660 "Unable to retrieve AudioEffect pointer for setParameter()"); 661 return AUDIOEFFECT_ERROR_NO_INIT; 662 } 663 664 if ((cmdSize != 0 && jCmdData == NULL) || (replySize != 0 && jReplyData == NULL)) { 665 return AUDIOEFFECT_ERROR_BAD_VALUE; 666 } 667 668 // get the pointer for the command from the java array 669 if (cmdSize != 0) { 670 pCmdData = (jbyte *) env->GetPrimitiveArrayCritical(jCmdData, NULL); 671 if (pCmdData == NULL) { 672 ALOGE("setParameter: Error retrieving command pointer"); 673 goto command_Exit; 674 } 675 } 676 677 // get the pointer for the reply from the java array 678 if (replySize != 0 && jReplyData != NULL) { 679 pReplyData = (jbyte *) env->GetPrimitiveArrayCritical(jReplyData, NULL); 680 if (pReplyData == NULL) { 681 ALOGE("setParameter: Error retrieving reply pointer"); 682 goto command_Exit; 683 } 684 } 685 686 lStatus = translateError(lpAudioEffect->command((uint32_t)cmdCode, 687 (uint32_t)cmdSize, 688 pCmdData, 689 (uint32_t *)&replySize, 690 pReplyData)); 691 692 command_Exit: 693 694 if (pCmdData != NULL) { 695 env->ReleasePrimitiveArrayCritical(jCmdData, pCmdData, 0); 696 } 697 if (pReplyData != NULL) { 698 env->ReleasePrimitiveArrayCritical(jReplyData, pReplyData, 0); 699 } 700 701 if (lStatus == NO_ERROR) { 702 return replySize; 703 } 704 return lStatus; 705 } 706 707 static jobjectArray 708 android_media_AudioEffect_native_queryEffects(JNIEnv *env, jclass clazz __unused) 709 { 710 effect_descriptor_t desc; 711 char str[EFFECT_STRING_LEN_MAX]; 712 uint32_t totalEffectsCount = 0; 713 uint32_t returnedEffectsCount = 0; 714 uint32_t i = 0; 715 jstring jdescType; 716 jstring jdescUuid; 717 jstring jdescConnect; 718 jstring jdescName; 719 jstring jdescImplementor; 720 jobject jdesc; 721 jobjectArray ret; 722 723 if (AudioEffect::queryNumberEffects(&totalEffectsCount) != NO_ERROR) { 724 return NULL; 725 } 726 727 jobjectArray temp = env->NewObjectArray(totalEffectsCount, fields.clazzDesc, NULL); 728 if (temp == NULL) { 729 return temp; 730 } 731 732 ALOGV("queryEffects() totalEffectsCount: %d", totalEffectsCount); 733 734 for (i = 0; i < totalEffectsCount; i++) { 735 if (AudioEffect::queryEffect(i, &desc) != NO_ERROR) { 736 goto queryEffects_failure; 737 } 738 739 if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { 740 jdescConnect = env->NewStringUTF("Auxiliary"); 741 } else if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_INSERT) { 742 jdescConnect = env->NewStringUTF("Insert"); 743 } else if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC) { 744 jdescConnect = env->NewStringUTF("Pre Processing"); 745 } else { 746 continue; 747 } 748 749 AudioEffect::guidToString(&desc.type, str, EFFECT_STRING_LEN_MAX); 750 jdescType = env->NewStringUTF(str); 751 752 AudioEffect::guidToString(&desc.uuid, str, EFFECT_STRING_LEN_MAX); 753 jdescUuid = env->NewStringUTF(str); 754 755 jdescName = env->NewStringUTF(desc.name); 756 jdescImplementor = env->NewStringUTF(desc.implementor); 757 758 jdesc = env->NewObject(fields.clazzDesc, 759 fields.midDescCstor, 760 jdescType, 761 jdescUuid, 762 jdescConnect, 763 jdescName, 764 jdescImplementor); 765 env->DeleteLocalRef(jdescType); 766 env->DeleteLocalRef(jdescUuid); 767 env->DeleteLocalRef(jdescConnect); 768 env->DeleteLocalRef(jdescName); 769 env->DeleteLocalRef(jdescImplementor); 770 if (jdesc == NULL) { 771 ALOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)"); 772 goto queryEffects_failure; 773 } 774 775 env->SetObjectArrayElement(temp, returnedEffectsCount++, jdesc); 776 } 777 778 if (returnedEffectsCount == 0) { 779 goto queryEffects_failure; 780 } 781 ret = env->NewObjectArray(returnedEffectsCount, fields.clazzDesc, NULL); 782 if (ret == NULL) { 783 goto queryEffects_failure; 784 } 785 for (i = 0; i < returnedEffectsCount; i++) { 786 env->SetObjectArrayElement(ret, i, env->GetObjectArrayElement(temp, i)); 787 } 788 env->DeleteLocalRef(temp); 789 return ret; 790 791 queryEffects_failure: 792 793 if (temp != NULL) { 794 env->DeleteLocalRef(temp); 795 } 796 return NULL; 797 798 } 799 800 801 802 static jobjectArray 803 android_media_AudioEffect_native_queryPreProcessings(JNIEnv *env, jclass clazz __unused, 804 jint audioSession) 805 { 806 // kDefaultNumEffects is a "reasonable" value ensuring that only one query will be enough on 807 // most devices to get all active audio pre processing on a given session. 808 static const uint32_t kDefaultNumEffects = 5; 809 810 effect_descriptor_t *descriptors = new effect_descriptor_t[kDefaultNumEffects]; 811 uint32_t numEffects = kDefaultNumEffects; 812 813 status_t status = AudioEffect::queryDefaultPreProcessing(audioSession, 814 descriptors, 815 &numEffects); 816 if ((status != NO_ERROR && status != NO_MEMORY) || 817 numEffects == 0) { 818 delete[] descriptors; 819 return NULL; 820 } 821 if (status == NO_MEMORY) { 822 delete [] descriptors; 823 descriptors = new effect_descriptor_t[numEffects]; 824 status = AudioEffect::queryDefaultPreProcessing(audioSession, 825 descriptors, 826 &numEffects); 827 } 828 if (status != NO_ERROR || numEffects == 0) { 829 delete[] descriptors; 830 return NULL; 831 } 832 ALOGV("queryDefaultPreProcessing() got %d effects", numEffects); 833 834 jobjectArray ret = env->NewObjectArray(numEffects, fields.clazzDesc, NULL); 835 if (ret == NULL) { 836 delete[] descriptors; 837 return ret; 838 } 839 840 char str[EFFECT_STRING_LEN_MAX]; 841 jstring jdescType; 842 jstring jdescUuid; 843 jstring jdescConnect; 844 jstring jdescName; 845 jstring jdescImplementor; 846 jobject jdesc; 847 848 for (uint32_t i = 0; i < numEffects; i++) { 849 850 AudioEffect::guidToString(&descriptors[i].type, str, EFFECT_STRING_LEN_MAX); 851 jdescType = env->NewStringUTF(str); 852 AudioEffect::guidToString(&descriptors[i].uuid, str, EFFECT_STRING_LEN_MAX); 853 jdescUuid = env->NewStringUTF(str); 854 jdescConnect = env->NewStringUTF("Pre Processing"); 855 jdescName = env->NewStringUTF(descriptors[i].name); 856 jdescImplementor = env->NewStringUTF(descriptors[i].implementor); 857 858 jdesc = env->NewObject(fields.clazzDesc, 859 fields.midDescCstor, 860 jdescType, 861 jdescUuid, 862 jdescConnect, 863 jdescName, 864 jdescImplementor); 865 env->DeleteLocalRef(jdescType); 866 env->DeleteLocalRef(jdescUuid); 867 env->DeleteLocalRef(jdescConnect); 868 env->DeleteLocalRef(jdescName); 869 env->DeleteLocalRef(jdescImplementor); 870 if (jdesc == NULL) { 871 ALOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)"); 872 env->DeleteLocalRef(ret); 873 return NULL;; 874 } 875 876 env->SetObjectArrayElement(ret, i, jdesc); 877 } 878 879 return ret; 880 } 881 882 // ---------------------------------------------------------------------------- 883 884 // Dalvik VM type signatures 885 static JNINativeMethod gMethods[] = { 886 {"native_init", "()V", (void *)android_media_AudioEffect_native_init}, 887 {"native_setup", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;II[I[Ljava/lang/Object;)I", 888 (void *)android_media_AudioEffect_native_setup}, 889 {"native_finalize", "()V", (void *)android_media_AudioEffect_native_finalize}, 890 {"native_release", "()V", (void *)android_media_AudioEffect_native_release}, 891 {"native_setEnabled", "(Z)I", (void *)android_media_AudioEffect_native_setEnabled}, 892 {"native_getEnabled", "()Z", (void *)android_media_AudioEffect_native_getEnabled}, 893 {"native_hasControl", "()Z", (void *)android_media_AudioEffect_native_hasControl}, 894 {"native_setParameter", "(I[BI[B)I", (void *)android_media_AudioEffect_native_setParameter}, 895 {"native_getParameter", "(I[BI[B)I", (void *)android_media_AudioEffect_native_getParameter}, 896 {"native_command", "(II[BI[B)I", (void *)android_media_AudioEffect_native_command}, 897 {"native_query_effects", "()[Ljava/lang/Object;", (void *)android_media_AudioEffect_native_queryEffects}, 898 {"native_query_pre_processing", "(I)[Ljava/lang/Object;", 899 (void *)android_media_AudioEffect_native_queryPreProcessings}, 900 }; 901 902 903 // ---------------------------------------------------------------------------- 904 905 extern int register_android_media_visualizer(JNIEnv *env); 906 907 int register_android_media_AudioEffect(JNIEnv *env) 908 { 909 return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)); 910 } 911 912 jint JNI_OnLoad(JavaVM* vm, void* reserved __unused) 913 { 914 915 JNIEnv* env = NULL; 916 jint result = -1; 917 918 if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { 919 ALOGE("ERROR: GetEnv failed\n"); 920 goto bail; 921 } 922 assert(env != NULL); 923 924 if (register_android_media_AudioEffect(env) < 0) { 925 ALOGE("ERROR: AudioEffect native registration failed\n"); 926 goto bail; 927 } 928 929 if (register_android_media_visualizer(env) < 0) { 930 ALOGE("ERROR: Visualizer native registration failed\n"); 931 goto bail; 932 } 933 934 /* success -- return valid version number */ 935 result = JNI_VERSION_1_4; 936 937 bail: 938 return result; 939 } 940 941