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