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