android_media_AudioEffect.cpp revision 53334cdb81bab4a4dfd0a41d2ef50709015a36c8
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/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/AudioEffect$Descriptor"); 232 if (clazz == NULL) { 233 LOGE("Can't find android/media/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/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) { 308 nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL); 309 if (nId == NULL) { 310 LOGE("setup: Error retrieving id pointer"); 311 lStatus = AUDIOEFFECT_ERROR_BAD_VALUE; 312 goto setup_failure; 313 } 314 } else { 315 LOGE("setup: NULL java array for id pointer"); 316 lStatus = AUDIOEFFECT_ERROR_BAD_VALUE; 317 goto setup_failure; 318 } 319 320 // create the native AudioEffect object 321 lpAudioEffect = new AudioEffect(typeStr, 322 uuidStr, 323 priority, 324 effectCallback, 325 &lpJniStorage->mCallbackData, 326 0, 327 sessionId); 328 if (lpAudioEffect == NULL) { 329 LOGE("Error creating AudioEffect"); 330 goto setup_failure; 331 } 332 333 lStatus = translateError(lpAudioEffect->initCheck()); 334 if (lStatus != AUDIOEFFECT_SUCCESS && lStatus != AUDIOEFFECT_ERROR_ALREADY_EXISTS) { 335 LOGE("AudioEffect initCheck failed %d", lStatus); 336 goto setup_failure; 337 } 338 339 nId[0] = lpAudioEffect->id(); 340 341 env->ReleasePrimitiveArrayCritical(jId, nId, 0); 342 nId = NULL; 343 344 if (typeStr) { 345 env->ReleaseStringUTFChars(type, typeStr); 346 typeStr = NULL; 347 } 348 349 if (uuidStr) { 350 env->ReleaseStringUTFChars(uuid, uuidStr); 351 uuidStr = NULL; 352 } 353 354 // get the effect descriptor 355 desc = lpAudioEffect->descriptor(); 356 357 AudioEffect::guidToString(&desc.type, str, EFFECT_STRING_LEN_MAX); 358 jdescType = env->NewStringUTF(str); 359 360 AudioEffect::guidToString(&desc.uuid, str, EFFECT_STRING_LEN_MAX); 361 jdescUuid = env->NewStringUTF(str); 362 363 if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { 364 jdescConnect = env->NewStringUTF("Auxiliary"); 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 LOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)"); 386 goto setup_failure; 387 } 388 389 env->SetObjectArrayElement(javadesc, 0, jdesc); 390 391 env->SetIntField(thiz, fields.fidNativeAudioEffect, (int)lpAudioEffect); 392 393 env->SetIntField(thiz, fields.fidJniData, (int)lpJniStorage); 394 395 return AUDIOEFFECT_SUCCESS; 396 397 // failures: 398setup_failure: 399 400 if (nId != NULL) { 401 env->ReleasePrimitiveArrayCritical(jId, nId, 0); 402 } 403 404 if (lpAudioEffect) { 405 delete lpAudioEffect; 406 } 407 env->SetIntField(thiz, fields.fidNativeAudioEffect, 0); 408 409 if (lpJniStorage) { 410 delete lpJniStorage; 411 } 412 env->SetIntField(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 lStatus; 423} 424 425 426// ---------------------------------------------------------------------------- 427static void android_media_AudioEffect_native_finalize(JNIEnv *env, jobject thiz) { 428 LOGV("android_media_AudioEffect_native_finalize jobject: %x\n", (int)thiz); 429 430 // delete the AudioEffect object 431 AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField( 432 thiz, fields.fidNativeAudioEffect); 433 if (lpAudioEffect) { 434 LOGV("deleting AudioEffect: %x\n", (int)lpAudioEffect); 435 delete lpAudioEffect; 436 } 437 438 // delete the JNI data 439 AudioEffectJniStorage* lpJniStorage = (AudioEffectJniStorage *)env->GetIntField( 440 thiz, fields.fidJniData); 441 if (lpJniStorage) { 442 LOGV("deleting pJniStorage: %x\n", (int)lpJniStorage); 443 delete lpJniStorage; 444 } 445} 446 447// ---------------------------------------------------------------------------- 448static 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->SetIntField(thiz, fields.fidNativeAudioEffect, 0); 455 env->SetIntField(thiz, fields.fidJniData, 0); 456} 457 458 459static jint 460android_media_AudioEffect_native_enable(JNIEnv *env, jobject thiz) 461{ 462 // retrieve the AudioEffect object 463 AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField( 464 thiz, fields.fidNativeAudioEffect); 465 466 if (lpAudioEffect == NULL) { 467 jniThrowException(env, "java/lang/IllegalStateException", 468 "Unable to retrieve AudioEffect pointer for enable()"); 469 return AUDIOEFFECT_ERROR_NO_INIT; 470 } 471 472 return translateError(lpAudioEffect->enable()); 473} 474 475 476static jint 477android_media_AudioEffect_native_disable(JNIEnv *env, jobject thiz) 478{ 479 // retrieve the AudioEffect object 480 AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField( 481 thiz, fields.fidNativeAudioEffect); 482 483 if (lpAudioEffect == NULL) { 484 jniThrowException(env, "java/lang/IllegalStateException", 485 "Unable to retrieve AudioEffect pointer for disable()"); 486 return AUDIOEFFECT_ERROR_NO_INIT; 487 } 488 489 return translateError(lpAudioEffect->disable()); 490} 491 492 493static jboolean 494android_media_AudioEffect_native_getEnable(JNIEnv *env, jobject thiz) 495{ 496 // retrieve the AudioEffect object 497 AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField( 498 thiz, fields.fidNativeAudioEffect); 499 500 if (lpAudioEffect == NULL) { 501 jniThrowException(env, "java/lang/IllegalStateException", 502 "Unable to retrieve AudioEffect pointer for getEnabled()"); 503 return false; 504 } 505 506 return (jboolean)lpAudioEffect->isEnabled(); 507} 508 509 510static jboolean 511android_media_AudioEffect_native_hasControl(JNIEnv *env, jobject thiz) 512{ 513 // retrieve the AudioEffect object 514 AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField( 515 thiz, fields.fidNativeAudioEffect); 516 517 if (lpAudioEffect == NULL) { 518 jniThrowException(env, "java/lang/IllegalStateException", 519 "Unable to retrieve AudioEffect pointer for getEnabled()"); 520 return false; 521 } 522 523 if (lpAudioEffect->initCheck() == NO_ERROR) { 524 return true; 525 } else { 526 return false; 527 } 528} 529 530static jint android_media_AudioEffect_native_setParameter(JNIEnv *env, 531 jobject thiz, int psize, jbyteArray pJavaParam, int vsize, 532 jbyteArray pJavaValue) { 533 // retrieve the AudioEffect object 534 jbyte* lpValue = NULL; 535 jbyte* lpParam = NULL; 536 jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE; 537 effect_param_t *p; 538 int voffset; 539 540 AudioEffect* lpAudioEffect = (AudioEffect *) env->GetIntField(thiz, 541 fields.fidNativeAudioEffect); 542 543 if (lpAudioEffect == NULL) { 544 jniThrowException(env, "java/lang/IllegalStateException", 545 "Unable to retrieve AudioEffect pointer for setParameter()"); 546 return AUDIOEFFECT_ERROR_NO_INIT; 547 } 548 549 if (psize == 0 || vsize == 0 || pJavaParam == NULL || pJavaValue == NULL) { 550 return AUDIOEFFECT_ERROR_BAD_VALUE; 551 } 552 553 // get the pointer for the param from the java array 554 lpParam = (jbyte *) env->GetPrimitiveArrayCritical(pJavaParam, NULL); 555 if (lpParam == NULL) { 556 LOGE("setParameter: Error retrieving param pointer"); 557 goto setParameter_Exit; 558 } 559 560 // get the pointer for the value from the java array 561 lpValue = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValue, NULL); 562 if (lpValue == NULL) { 563 LOGE("setParameter: Error retrieving value pointer"); 564 goto setParameter_Exit; 565 } 566 567 voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int); 568 p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset + vsize); 569 memcpy(p->data, lpParam, psize); 570 p->psize = psize; 571 memcpy(p->data + voffset, lpValue, psize); 572 p->vsize = vsize; 573 574 lStatus = lpAudioEffect->setParameter(p); 575 if (lStatus == NO_ERROR) { 576 lStatus = p->status; 577 } 578 579 free(p); 580 581setParameter_Exit: 582 583 if (lpParam != NULL) { 584 env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0); 585 } 586 if (lpValue != NULL) { 587 env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0); 588 } 589 return translateError(lStatus); 590} 591 592static jint 593android_media_AudioEffect_native_getParameter(JNIEnv *env, 594 jobject thiz, int psize, jbyteArray pJavaParam, 595 jintArray pJavaValueSize, jbyteArray pJavaValue) { 596 // retrieve the AudioEffect object 597 jbyte* lpParam = NULL; 598 jbyte* lpValue = NULL; 599 jbyte* lpValueSize = NULL; 600 jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE; 601 effect_param_t *p; 602 int voffset; 603 604 AudioEffect* lpAudioEffect = (AudioEffect *) env->GetIntField(thiz, 605 fields.fidNativeAudioEffect); 606 607 if (lpAudioEffect == NULL) { 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 || pJavaValueSize == NULL || 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 LOGE("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 LOGE("getParameter: Error retrieving value pointer"); 628 goto getParameter_Exit; 629 } 630 631 // get the pointer for the value size from the java array 632 lpValueSize = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValueSize, NULL); 633 if (lpValueSize == NULL) { 634 LOGE("getParameter: Error retrieving value size pointer"); 635 goto getParameter_Exit; 636 } 637 638 voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int); 639 p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset 640 + lpValueSize[0]); 641 memcpy(p->data, lpParam, psize); 642 p->psize = psize; 643 p->vsize = lpValueSize[0]; 644 645 lStatus = lpAudioEffect->getParameter(p); 646 if (lStatus == NO_ERROR) { 647 lStatus = p->status; 648 if (lStatus == NO_ERROR) { 649 memcpy(lpValue, p->data + voffset, p->vsize); 650 lpValueSize[0] = p->vsize; 651 } 652 } 653 654 free(p); 655 656getParameter_Exit: 657 658 if (lpParam != NULL) { 659 env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0); 660 } 661 if (lpValue != NULL) { 662 env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0); 663 } 664 if (lpValueSize != NULL) { 665 env->ReleasePrimitiveArrayCritical(pJavaValueSize, lpValueSize, 0); 666 } 667 668 return translateError(lStatus); 669} 670 671static jint android_media_AudioEffect_native_command(JNIEnv *env, jobject thiz, 672 jint cmdCode, jint cmdSize, jbyteArray jCmdData, jintArray jReplySize, 673 jbyteArray jReplyData) { 674 jbyte* pCmdData = NULL; 675 jbyte* pReplyData = NULL; 676 jint* pReplySize = NULL; 677 jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE; 678 679 // retrieve the AudioEffect object 680 AudioEffect* lpAudioEffect = (AudioEffect *) env->GetIntField(thiz, 681 fields.fidNativeAudioEffect); 682 683 if (lpAudioEffect == NULL) { 684 jniThrowException(env, "java/lang/IllegalStateException", 685 "Unable to retrieve AudioEffect pointer for setParameter()"); 686 return AUDIOEFFECT_ERROR_NO_INIT; 687 } 688 689 if ((cmdSize != 0 && jCmdData == NULL) || (jReplySize != NULL && jReplyData == NULL)) { 690 return AUDIOEFFECT_ERROR_BAD_VALUE; 691 } 692 693 // get the pointer for the command from the java array 694 if (cmdSize != 0) { 695 pCmdData = (jbyte *) env->GetPrimitiveArrayCritical(jCmdData, NULL); 696 if (pCmdData == NULL) { 697 LOGE("setParameter: Error retrieving command pointer"); 698 goto command_Exit; 699 } 700 } 701 702 // get the pointer for the reply size from the java array 703 if (jReplySize != NULL) { 704 pReplySize = (jint *) env->GetPrimitiveArrayCritical(jReplySize, NULL); 705 if (pReplySize == NULL) { 706 LOGE("setParameter: Error retrieving reply pointer"); 707 goto command_Exit; 708 } 709 } 710 711 // get the pointer for the reply from the java array 712 if (pReplySize != NULL && pReplySize[0] != 0 && jReplyData != NULL) { 713 pReplyData = (jbyte *) env->GetPrimitiveArrayCritical(jReplyData, NULL); 714 if (pReplyData == NULL) { 715 LOGE("setParameter: Error retrieving reply pointer"); 716 goto command_Exit; 717 } 718 } 719 720 lStatus = translateError(lpAudioEffect->command(cmdCode, cmdSize, pCmdData, 721 pReplySize, pReplyData)); 722 723command_Exit: 724 725 if (pCmdData != NULL) { 726 env->ReleasePrimitiveArrayCritical(jCmdData, pCmdData, 0); 727 } 728 if (pReplyData != NULL) { 729 env->ReleasePrimitiveArrayCritical(jReplyData, pReplyData, 0); 730 } 731 if (pReplySize != NULL) { 732 env->ReleasePrimitiveArrayCritical(jReplySize, pReplySize, 0); 733 } 734 735 return lStatus; 736} 737 738static jobjectArray 739android_media_AudioEffect_native_queryEffects(JNIEnv *env, jclass clazz) 740{ 741 effect_descriptor_t desc; 742 char str[EFFECT_STRING_LEN_MAX]; 743 uint32_t numEffects; 744 uint32_t i = 0; 745 jstring jdescType; 746 jstring jdescUuid; 747 jstring jdescConnect; 748 jstring jdescName; 749 jstring jdescImplementor; 750 jobject jdesc; 751 752 AudioEffect::queryNumberEffects(&numEffects); 753 jobjectArray ret = env->NewObjectArray(numEffects, fields.clazzDesc, NULL); 754 if (ret == NULL) { 755 return ret; 756 } 757 758 LOGV("queryEffects() numEffects: %d", numEffects); 759 760 for (i = 0; i < numEffects; i++) { 761 if (AudioEffect::queryEffect(i, &desc) != NO_ERROR) { 762 goto queryEffects_failure; 763 } 764 765 AudioEffect::guidToString(&desc.type, str, EFFECT_STRING_LEN_MAX); 766 jdescType = env->NewStringUTF(str); 767 768 AudioEffect::guidToString(&desc.uuid, str, EFFECT_STRING_LEN_MAX); 769 jdescUuid = env->NewStringUTF(str); 770 771 if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { 772 jdescConnect = env->NewStringUTF("Auxiliary"); 773 } else { 774 jdescConnect = env->NewStringUTF("Insert"); 775 } 776 777 jdescName = env->NewStringUTF(desc.name); 778 jdescImplementor = env->NewStringUTF(desc.implementor); 779 780 jdesc = env->NewObject(fields.clazzDesc, 781 fields.midDescCstor, 782 jdescType, 783 jdescUuid, 784 jdescConnect, 785 jdescName, 786 jdescImplementor); 787 env->DeleteLocalRef(jdescType); 788 env->DeleteLocalRef(jdescUuid); 789 env->DeleteLocalRef(jdescConnect); 790 env->DeleteLocalRef(jdescName); 791 env->DeleteLocalRef(jdescImplementor); 792 if (jdesc == NULL) { 793 LOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)"); 794 goto queryEffects_failure; 795 } 796 797 env->SetObjectArrayElement(ret, i, jdesc); 798 } 799 800 return ret; 801 802queryEffects_failure: 803 804 if (ret != NULL) { 805 env->DeleteLocalRef(ret); 806 } 807 return NULL; 808 809} 810 811// ---------------------------------------------------------------------------- 812 813// Dalvik VM type signatures 814static JNINativeMethod gMethods[] = { 815 {"native_init", "()V", (void *)android_media_AudioEffect_native_init}, 816 {"native_setup", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;II[I[Ljava/lang/Object;)I", 817 (void *)android_media_AudioEffect_native_setup}, 818 {"native_finalize", "()V", (void *)android_media_AudioEffect_native_finalize}, 819 {"native_release", "()V", (void *)android_media_AudioEffect_native_release}, 820 {"native_enable", "()I", (void *)android_media_AudioEffect_native_enable}, 821 {"native_disable", "()I", (void *)android_media_AudioEffect_native_disable}, 822 {"native_getEnable", "()Z", (void *)android_media_AudioEffect_native_getEnable}, 823 {"native_hasControl", "()Z", (void *)android_media_AudioEffect_native_hasControl}, 824 {"native_setParameter", "(I[BI[B)I", (void *)android_media_AudioEffect_native_setParameter}, 825 {"native_getParameter", "(I[B[I[B)I", (void *)android_media_AudioEffect_native_getParameter}, 826 {"native_command", "(II[B[I[B)I", (void *)android_media_AudioEffect_native_command}, 827 {"native_query_effects", "()[Ljava/lang/Object;", (void *)android_media_AudioEffect_native_queryEffects}, 828}; 829 830 831// ---------------------------------------------------------------------------- 832 833int register_android_media_AudioEffect(JNIEnv *env) 834{ 835 return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)); 836} 837 838jint JNI_OnLoad(JavaVM* vm, void* reserved) 839{ 840 841 JNIEnv* env = NULL; 842 jint result = -1; 843 844 if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { 845 LOGE("ERROR: GetEnv failed\n"); 846 goto bail; 847 } 848 assert(env != NULL); 849 850 if (register_android_media_AudioEffect(env) < 0) { 851 LOGE("ERROR: AudioEffect native registration failed\n"); 852 goto bail; 853 } 854 855 /* success -- return valid version number */ 856 result = JNI_VERSION_1_4; 857 858bail: 859 return result; 860} 861 862