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 "visualizers-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 <utils/threads.h> 27 #include "media/Visualizer.h" 28 29 using namespace android; 30 31 #define VISUALIZER_SUCCESS 0 32 #define VISUALIZER_ERROR -1 33 #define VISUALIZER_ERROR_ALREADY_EXISTS -2 34 #define VISUALIZER_ERROR_NO_INIT -3 35 #define VISUALIZER_ERROR_BAD_VALUE -4 36 #define VISUALIZER_ERROR_INVALID_OPERATION -5 37 #define VISUALIZER_ERROR_NO_MEMORY -6 38 #define VISUALIZER_ERROR_DEAD_OBJECT -7 39 40 #define NATIVE_EVENT_PCM_CAPTURE 0 41 #define NATIVE_EVENT_FFT_CAPTURE 1 42 #define NATIVE_EVENT_SERVER_DIED 2 43 44 // ---------------------------------------------------------------------------- 45 static const char* const kClassPathName = "android/media/audiofx/Visualizer"; 46 static const char* const kClassPeakRmsPathName = 47 "android/media/audiofx/Visualizer$MeasurementPeakRms"; 48 49 struct fields_t { 50 // these fields provide access from C++ to the... 51 jclass clazzEffect; // Visualizer class 52 jmethodID midPostNativeEvent; // event post callback method 53 jfieldID fidNativeVisualizer; // stores in Java the native Visualizer object 54 jfieldID fidJniData; // stores in Java additional resources used by the native Visualizer 55 jfieldID fidPeak; // to access Visualizer.MeasurementPeakRms.mPeak 56 jfieldID fidRms; // to access Visualizer.MeasurementPeakRms.mRms 57 }; 58 static fields_t fields; 59 60 struct visualizer_callback_cookie { 61 jclass visualizer_class; // Visualizer class 62 jobject visualizer_ref; // Visualizer object instance 63 64 // Lazily allocated arrays used to hold callback data provided to java 65 // applications. These arrays are allocated during the first callback and 66 // reallocated when the size of the callback data changes. Allocating on 67 // demand and saving the arrays means that applications cannot safely hold a 68 // reference to the provided data (they need to make a copy if they want to 69 // hold onto outside of the callback scope), but it avoids GC thrash caused 70 // by constantly allocating and releasing arrays to hold callback data. 71 Mutex callback_data_lock; 72 jbyteArray waveform_data; 73 jbyteArray fft_data; 74 75 visualizer_callback_cookie() { 76 waveform_data = NULL; 77 fft_data = NULL; 78 } 79 80 ~visualizer_callback_cookie() { 81 cleanupBuffers(); 82 } 83 84 void cleanupBuffers() { 85 AutoMutex lock(&callback_data_lock); 86 if (waveform_data || fft_data) { 87 JNIEnv *env = AndroidRuntime::getJNIEnv(); 88 89 if (waveform_data) { 90 env->DeleteGlobalRef(waveform_data); 91 waveform_data = NULL; 92 } 93 94 if (fft_data) { 95 env->DeleteGlobalRef(fft_data); 96 fft_data = NULL; 97 } 98 } 99 } 100 }; 101 102 // ---------------------------------------------------------------------------- 103 class visualizerJniStorage { 104 public: 105 visualizer_callback_cookie mCallbackData; 106 107 visualizerJniStorage() { 108 } 109 110 ~visualizerJniStorage() { 111 } 112 }; 113 114 115 static jint translateError(int code) { 116 switch(code) { 117 case NO_ERROR: 118 return VISUALIZER_SUCCESS; 119 case ALREADY_EXISTS: 120 return VISUALIZER_ERROR_ALREADY_EXISTS; 121 case NO_INIT: 122 return VISUALIZER_ERROR_NO_INIT; 123 case BAD_VALUE: 124 return VISUALIZER_ERROR_BAD_VALUE; 125 case INVALID_OPERATION: 126 return VISUALIZER_ERROR_INVALID_OPERATION; 127 case NO_MEMORY: 128 return VISUALIZER_ERROR_NO_MEMORY; 129 case DEAD_OBJECT: 130 return VISUALIZER_ERROR_DEAD_OBJECT; 131 default: 132 return VISUALIZER_ERROR; 133 } 134 } 135 136 137 // ---------------------------------------------------------------------------- 138 static void ensureArraySize(JNIEnv *env, jbyteArray *array, uint32_t size) { 139 if (NULL != *array) { 140 uint32_t len = env->GetArrayLength(*array); 141 if (len == size) 142 return; 143 144 env->DeleteGlobalRef(*array); 145 *array = NULL; 146 } 147 148 jbyteArray localRef = env->NewByteArray(size); 149 if (NULL != localRef) { 150 // Promote to global ref. 151 *array = (jbyteArray)env->NewGlobalRef(localRef); 152 153 // Release our (now pointless) local ref. 154 env->DeleteLocalRef(localRef); 155 } 156 } 157 158 static void captureCallback(void* user, 159 uint32_t waveformSize, 160 uint8_t *waveform, 161 uint32_t fftSize, 162 uint8_t *fft, 163 uint32_t samplingrate) { 164 165 int arg1 = 0; 166 int arg2 = 0; 167 size_t size; 168 169 visualizer_callback_cookie *callbackInfo = (visualizer_callback_cookie *)user; 170 JNIEnv *env = AndroidRuntime::getJNIEnv(); 171 172 if (!user || !env) { 173 ALOGW("captureCallback error user %p, env %p", user, env); 174 return; 175 } 176 177 ALOGV("captureCallback: callbackInfo %p, visualizer_ref %p visualizer_class %p", 178 callbackInfo, 179 callbackInfo->visualizer_ref, 180 callbackInfo->visualizer_class); 181 182 AutoMutex lock(&callbackInfo->callback_data_lock); 183 184 if (waveformSize != 0 && waveform != NULL) { 185 jbyteArray jArray; 186 187 ensureArraySize(env, &callbackInfo->waveform_data, waveformSize); 188 jArray = callbackInfo->waveform_data; 189 190 if (jArray != NULL) { 191 jbyte *nArray = env->GetByteArrayElements(jArray, NULL); 192 memcpy(nArray, waveform, waveformSize); 193 env->ReleaseByteArrayElements(jArray, nArray, 0); 194 env->CallStaticVoidMethod( 195 callbackInfo->visualizer_class, 196 fields.midPostNativeEvent, 197 callbackInfo->visualizer_ref, 198 NATIVE_EVENT_PCM_CAPTURE, 199 samplingrate, 200 0, 201 jArray); 202 } 203 } 204 205 if (fftSize != 0 && fft != NULL) { 206 jbyteArray jArray; 207 208 ensureArraySize(env, &callbackInfo->fft_data, fftSize); 209 jArray = callbackInfo->fft_data; 210 211 if (jArray != NULL) { 212 jbyte *nArray = env->GetByteArrayElements(jArray, NULL); 213 memcpy(nArray, fft, fftSize); 214 env->ReleaseByteArrayElements(jArray, nArray, 0); 215 env->CallStaticVoidMethod( 216 callbackInfo->visualizer_class, 217 fields.midPostNativeEvent, 218 callbackInfo->visualizer_ref, 219 NATIVE_EVENT_FFT_CAPTURE, 220 samplingrate, 221 0, 222 jArray); 223 } 224 } 225 226 if (env->ExceptionCheck()) { 227 env->ExceptionDescribe(); 228 env->ExceptionClear(); 229 } 230 } 231 232 static Visualizer *getVisualizer(JNIEnv* env, jobject thiz) 233 { 234 Visualizer *v = (Visualizer *)env->GetIntField( 235 thiz, fields.fidNativeVisualizer); 236 if (v == NULL) { 237 jniThrowException(env, "java/lang/IllegalStateException", 238 "Unable to retrieve Visualizer pointer"); 239 } 240 return v; 241 } 242 243 // ---------------------------------------------------------------------------- 244 // This function gets some field IDs, which in turn causes class initialization. 245 // It is called from a static block in Visualizer, which won't run until the 246 // first time an instance of this class is used. 247 static void 248 android_media_visualizer_native_init(JNIEnv *env) 249 { 250 251 ALOGV("android_media_visualizer_native_init"); 252 253 fields.clazzEffect = NULL; 254 255 // Get the Visualizer class 256 jclass clazz = env->FindClass(kClassPathName); 257 if (clazz == NULL) { 258 ALOGE("Can't find %s", kClassPathName); 259 return; 260 } 261 262 fields.clazzEffect = (jclass)env->NewGlobalRef(clazz); 263 264 // Get the Visualizer.MeasurementPeakRms class 265 clazz = env->FindClass(kClassPeakRmsPathName); 266 if (clazz == NULL) { 267 ALOGE("Can't find %s", kClassPeakRmsPathName); 268 return; 269 } 270 jclass clazzMeasurementPeakRms = (jclass)env->NewGlobalRef(clazz); 271 272 // Get the postEvent method 273 fields.midPostNativeEvent = env->GetStaticMethodID( 274 fields.clazzEffect, 275 "postEventFromNative", "(Ljava/lang/Object;IIILjava/lang/Object;)V"); 276 if (fields.midPostNativeEvent == NULL) { 277 ALOGE("Can't find Visualizer.%s", "postEventFromNative"); 278 return; 279 } 280 281 // Get the variables fields 282 // nativeTrackInJavaObj 283 fields.fidNativeVisualizer = env->GetFieldID( 284 fields.clazzEffect, 285 "mNativeVisualizer", "I"); 286 if (fields.fidNativeVisualizer == NULL) { 287 ALOGE("Can't find Visualizer.%s", "mNativeVisualizer"); 288 return; 289 } 290 // fidJniData; 291 fields.fidJniData = env->GetFieldID( 292 fields.clazzEffect, 293 "mJniData", "I"); 294 if (fields.fidJniData == NULL) { 295 ALOGE("Can't find Visualizer.%s", "mJniData"); 296 return; 297 } 298 // fidPeak 299 fields.fidPeak = env->GetFieldID( 300 clazzMeasurementPeakRms, 301 "mPeak", "I"); 302 if (fields.fidPeak == NULL) { 303 ALOGE("Can't find Visualizer.MeasurementPeakRms.%s", "mPeak"); 304 return; 305 } 306 // fidRms 307 fields.fidRms = env->GetFieldID( 308 clazzMeasurementPeakRms, 309 "mRms", "I"); 310 if (fields.fidRms == NULL) { 311 ALOGE("Can't find Visualizer.MeasurementPeakRms.%s", "mPeak"); 312 return; 313 } 314 315 env->DeleteGlobalRef(clazzMeasurementPeakRms); 316 } 317 318 static void android_media_visualizer_effect_callback(int32_t event, 319 void *user, 320 void *info) { 321 if ((event == AudioEffect::EVENT_ERROR) && 322 (*((status_t*)info) == DEAD_OBJECT)) { 323 visualizerJniStorage* lpJniStorage = (visualizerJniStorage*)user; 324 visualizer_callback_cookie* callbackInfo = &lpJniStorage->mCallbackData; 325 JNIEnv *env = AndroidRuntime::getJNIEnv(); 326 327 env->CallStaticVoidMethod( 328 callbackInfo->visualizer_class, 329 fields.midPostNativeEvent, 330 callbackInfo->visualizer_ref, 331 NATIVE_EVENT_SERVER_DIED, 332 0, 0, 0); 333 } 334 } 335 336 static jint 337 android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this, 338 jint sessionId, jintArray jId) 339 { 340 ALOGV("android_media_visualizer_native_setup"); 341 visualizerJniStorage* lpJniStorage = NULL; 342 int lStatus = VISUALIZER_ERROR_NO_MEMORY; 343 Visualizer* lpVisualizer = NULL; 344 jint* nId = NULL; 345 346 lpJniStorage = new visualizerJniStorage(); 347 if (lpJniStorage == NULL) { 348 ALOGE("setup: Error creating JNI Storage"); 349 goto setup_failure; 350 } 351 352 lpJniStorage->mCallbackData.visualizer_class = (jclass)env->NewGlobalRef(fields.clazzEffect); 353 // we use a weak reference so the Visualizer object can be garbage collected. 354 lpJniStorage->mCallbackData.visualizer_ref = env->NewGlobalRef(weak_this); 355 356 ALOGV("setup: lpJniStorage: %p visualizer_ref %p visualizer_class %p, &mCallbackData %p", 357 lpJniStorage, 358 lpJniStorage->mCallbackData.visualizer_ref, 359 lpJniStorage->mCallbackData.visualizer_class, 360 &lpJniStorage->mCallbackData); 361 362 if (jId == NULL) { 363 ALOGE("setup: NULL java array for id pointer"); 364 lStatus = VISUALIZER_ERROR_BAD_VALUE; 365 goto setup_failure; 366 } 367 368 // create the native Visualizer object 369 lpVisualizer = new Visualizer(0, 370 android_media_visualizer_effect_callback, 371 lpJniStorage, 372 sessionId); 373 if (lpVisualizer == NULL) { 374 ALOGE("Error creating Visualizer"); 375 goto setup_failure; 376 } 377 378 lStatus = translateError(lpVisualizer->initCheck()); 379 if (lStatus != VISUALIZER_SUCCESS && lStatus != VISUALIZER_ERROR_ALREADY_EXISTS) { 380 ALOGE("Visualizer initCheck failed %d", lStatus); 381 goto setup_failure; 382 } 383 384 nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL); 385 if (nId == NULL) { 386 ALOGE("setup: Error retrieving id pointer"); 387 lStatus = VISUALIZER_ERROR_BAD_VALUE; 388 goto setup_failure; 389 } 390 nId[0] = lpVisualizer->id(); 391 env->ReleasePrimitiveArrayCritical(jId, nId, 0); 392 nId = NULL; 393 394 env->SetIntField(thiz, fields.fidNativeVisualizer, (int)lpVisualizer); 395 396 env->SetIntField(thiz, fields.fidJniData, (int)lpJniStorage); 397 398 return VISUALIZER_SUCCESS; 399 400 // failures: 401 setup_failure: 402 403 if (nId != NULL) { 404 env->ReleasePrimitiveArrayCritical(jId, nId, 0); 405 } 406 407 if (lpVisualizer) { 408 delete lpVisualizer; 409 } 410 env->SetIntField(thiz, fields.fidNativeVisualizer, 0); 411 412 if (lpJniStorage) { 413 delete lpJniStorage; 414 } 415 env->SetIntField(thiz, fields.fidJniData, 0); 416 417 return lStatus; 418 } 419 420 // ---------------------------------------------------------------------------- 421 static void android_media_visualizer_native_finalize(JNIEnv *env, jobject thiz) { 422 ALOGV("android_media_visualizer_native_finalize jobject: %x\n", (int)thiz); 423 424 // delete the Visualizer object 425 Visualizer* lpVisualizer = (Visualizer *)env->GetIntField( 426 thiz, fields.fidNativeVisualizer); 427 if (lpVisualizer) { 428 ALOGV("deleting Visualizer: %x\n", (int)lpVisualizer); 429 delete lpVisualizer; 430 } 431 432 // delete the JNI data 433 visualizerJniStorage* lpJniStorage = (visualizerJniStorage *)env->GetIntField( 434 thiz, fields.fidJniData); 435 if (lpJniStorage) { 436 ALOGV("deleting pJniStorage: %x\n", (int)lpJniStorage); 437 delete lpJniStorage; 438 } 439 } 440 441 // ---------------------------------------------------------------------------- 442 static void android_media_visualizer_native_release(JNIEnv *env, jobject thiz) { 443 444 // do everything a call to finalize would 445 android_media_visualizer_native_finalize(env, thiz); 446 // + reset the native resources in the Java object so any attempt to access 447 // them after a call to release fails. 448 env->SetIntField(thiz, fields.fidNativeVisualizer, 0); 449 env->SetIntField(thiz, fields.fidJniData, 0); 450 } 451 452 static jint 453 android_media_visualizer_native_setEnabled(JNIEnv *env, jobject thiz, jboolean enabled) 454 { 455 Visualizer* lpVisualizer = getVisualizer(env, thiz); 456 if (lpVisualizer == NULL) { 457 return VISUALIZER_ERROR_NO_INIT; 458 } 459 460 jint retVal = translateError(lpVisualizer->setEnabled(enabled)); 461 462 if (!enabled) { 463 visualizerJniStorage* lpJniStorage = (visualizerJniStorage *)env->GetIntField( 464 thiz, fields.fidJniData); 465 466 if (NULL != lpJniStorage) 467 lpJniStorage->mCallbackData.cleanupBuffers(); 468 } 469 470 return retVal; 471 } 472 473 static jboolean 474 android_media_visualizer_native_getEnabled(JNIEnv *env, jobject thiz) 475 { 476 Visualizer* lpVisualizer = getVisualizer(env, thiz); 477 if (lpVisualizer == NULL) { 478 return false; 479 } 480 481 return (jboolean)lpVisualizer->getEnabled(); 482 } 483 484 static jintArray 485 android_media_visualizer_native_getCaptureSizeRange(JNIEnv *env, jobject thiz) 486 { 487 jintArray jRange = env->NewIntArray(2); 488 jint *nRange = env->GetIntArrayElements(jRange, NULL); 489 nRange[0] = Visualizer::getMinCaptureSize(); 490 nRange[1] = Visualizer::getMaxCaptureSize(); 491 ALOGV("getCaptureSizeRange() min %d max %d", nRange[0], nRange[1]); 492 env->ReleaseIntArrayElements(jRange, nRange, 0); 493 return jRange; 494 } 495 496 static jint 497 android_media_visualizer_native_getMaxCaptureRate(JNIEnv *env, jobject thiz) 498 { 499 return Visualizer::getMaxCaptureRate(); 500 } 501 502 static jint 503 android_media_visualizer_native_setCaptureSize(JNIEnv *env, jobject thiz, jint size) 504 { 505 Visualizer* lpVisualizer = getVisualizer(env, thiz); 506 if (lpVisualizer == NULL) { 507 return VISUALIZER_ERROR_NO_INIT; 508 } 509 510 return translateError(lpVisualizer->setCaptureSize(size)); 511 } 512 513 static jint 514 android_media_visualizer_native_getCaptureSize(JNIEnv *env, jobject thiz) 515 { 516 Visualizer* lpVisualizer = getVisualizer(env, thiz); 517 if (lpVisualizer == NULL) { 518 return -1; 519 } 520 return lpVisualizer->getCaptureSize(); 521 } 522 523 static jint 524 android_media_visualizer_native_setScalingMode(JNIEnv *env, jobject thiz, jint mode) 525 { 526 Visualizer* lpVisualizer = getVisualizer(env, thiz); 527 if (lpVisualizer == NULL) { 528 return VISUALIZER_ERROR_NO_INIT; 529 } 530 531 return translateError(lpVisualizer->setScalingMode(mode)); 532 } 533 534 static jint 535 android_media_visualizer_native_getScalingMode(JNIEnv *env, jobject thiz) 536 { 537 Visualizer* lpVisualizer = getVisualizer(env, thiz); 538 if (lpVisualizer == NULL) { 539 return -1; 540 } 541 return lpVisualizer->getScalingMode(); 542 } 543 544 static jint 545 android_media_visualizer_native_setMeasurementMode(JNIEnv *env, jobject thiz, jint mode) 546 { 547 Visualizer* lpVisualizer = getVisualizer(env, thiz); 548 if (lpVisualizer == NULL) { 549 return VISUALIZER_ERROR_NO_INIT; 550 } 551 return translateError(lpVisualizer->setMeasurementMode(mode)); 552 } 553 554 static jint 555 android_media_visualizer_native_getMeasurementMode(JNIEnv *env, jobject thiz) 556 { 557 Visualizer* lpVisualizer = getVisualizer(env, thiz); 558 if (lpVisualizer == NULL) { 559 return MEASUREMENT_MODE_NONE; 560 } 561 return lpVisualizer->getMeasurementMode(); 562 } 563 564 static jint 565 android_media_visualizer_native_getSamplingRate(JNIEnv *env, jobject thiz) 566 { 567 Visualizer* lpVisualizer = getVisualizer(env, thiz); 568 if (lpVisualizer == NULL) { 569 return -1; 570 } 571 return lpVisualizer->getSamplingRate(); 572 } 573 574 static jint 575 android_media_visualizer_native_getWaveForm(JNIEnv *env, jobject thiz, jbyteArray jWaveform) 576 { 577 Visualizer* lpVisualizer = getVisualizer(env, thiz); 578 if (lpVisualizer == NULL) { 579 return VISUALIZER_ERROR_NO_INIT; 580 } 581 582 jbyte* nWaveform = (jbyte *) env->GetPrimitiveArrayCritical(jWaveform, NULL); 583 if (nWaveform == NULL) { 584 return VISUALIZER_ERROR_NO_MEMORY; 585 } 586 jint status = translateError(lpVisualizer->getWaveForm((uint8_t *)nWaveform)); 587 588 env->ReleasePrimitiveArrayCritical(jWaveform, nWaveform, 0); 589 return status; 590 } 591 592 static jint 593 android_media_visualizer_native_getFft(JNIEnv *env, jobject thiz, jbyteArray jFft) 594 { 595 Visualizer* lpVisualizer = getVisualizer(env, thiz); 596 if (lpVisualizer == NULL) { 597 return VISUALIZER_ERROR_NO_INIT; 598 } 599 600 jbyte* nFft = (jbyte *) env->GetPrimitiveArrayCritical(jFft, NULL); 601 if (nFft == NULL) { 602 return VISUALIZER_ERROR_NO_MEMORY; 603 } 604 jint status = translateError(lpVisualizer->getFft((uint8_t *)nFft)); 605 606 env->ReleasePrimitiveArrayCritical(jFft, nFft, 0); 607 608 return status; 609 } 610 611 static jint 612 android_media_visualizer_native_getPeakRms(JNIEnv *env, jobject thiz, jobject jPeakRmsObj) 613 { 614 Visualizer* lpVisualizer = getVisualizer(env, thiz); 615 if (lpVisualizer == NULL) { 616 return VISUALIZER_ERROR_NO_INIT; 617 } 618 int32_t measurements[2]; 619 jint status = translateError( 620 lpVisualizer->getIntMeasurements(MEASUREMENT_MODE_PEAK_RMS, 621 2, measurements)); 622 if (status == VISUALIZER_SUCCESS) { 623 // measurement worked, write the values to the java object 624 env->SetIntField(jPeakRmsObj, fields.fidPeak, measurements[MEASUREMENT_IDX_PEAK]); 625 env->SetIntField(jPeakRmsObj, fields.fidRms, measurements[MEASUREMENT_IDX_RMS]); 626 } 627 return status; 628 } 629 630 static jint 631 android_media_setPeriodicCapture(JNIEnv *env, jobject thiz, jint rate, jboolean jWaveform, jboolean jFft) 632 { 633 Visualizer* lpVisualizer = getVisualizer(env, thiz); 634 if (lpVisualizer == NULL) { 635 return VISUALIZER_ERROR_NO_INIT; 636 } 637 visualizerJniStorage* lpJniStorage = (visualizerJniStorage *)env->GetIntField(thiz, 638 fields.fidJniData); 639 if (lpJniStorage == NULL) { 640 return VISUALIZER_ERROR_NO_INIT; 641 } 642 643 ALOGV("setPeriodicCapture: rate %d, jWaveform %d jFft %d", 644 rate, 645 jWaveform, 646 jFft); 647 648 uint32_t flags = Visualizer::CAPTURE_CALL_JAVA; 649 if (jWaveform) flags |= Visualizer::CAPTURE_WAVEFORM; 650 if (jFft) flags |= Visualizer::CAPTURE_FFT; 651 Visualizer::capture_cbk_t cbk = captureCallback; 652 if (!jWaveform && !jFft) cbk = NULL; 653 654 return translateError(lpVisualizer->setCaptureCallBack(cbk, 655 &lpJniStorage->mCallbackData, 656 flags, 657 rate)); 658 } 659 660 // ---------------------------------------------------------------------------- 661 662 // Dalvik VM type signatures 663 static JNINativeMethod gMethods[] = { 664 {"native_init", "()V", (void *)android_media_visualizer_native_init}, 665 {"native_setup", "(Ljava/lang/Object;I[I)I", 666 (void *)android_media_visualizer_native_setup}, 667 {"native_finalize", "()V", (void *)android_media_visualizer_native_finalize}, 668 {"native_release", "()V", (void *)android_media_visualizer_native_release}, 669 {"native_setEnabled", "(Z)I", (void *)android_media_visualizer_native_setEnabled}, 670 {"native_getEnabled", "()Z", (void *)android_media_visualizer_native_getEnabled}, 671 {"getCaptureSizeRange", "()[I", (void *)android_media_visualizer_native_getCaptureSizeRange}, 672 {"getMaxCaptureRate", "()I", (void *)android_media_visualizer_native_getMaxCaptureRate}, 673 {"native_setCaptureSize", "(I)I", (void *)android_media_visualizer_native_setCaptureSize}, 674 {"native_getCaptureSize", "()I", (void *)android_media_visualizer_native_getCaptureSize}, 675 {"native_setScalingMode", "(I)I", (void *)android_media_visualizer_native_setScalingMode}, 676 {"native_getScalingMode", "()I", (void *)android_media_visualizer_native_getScalingMode}, 677 {"native_setMeasurementMode","(I)I", (void *)android_media_visualizer_native_setMeasurementMode}, 678 {"native_getMeasurementMode","()I", (void *)android_media_visualizer_native_getMeasurementMode}, 679 {"native_getSamplingRate", "()I", (void *)android_media_visualizer_native_getSamplingRate}, 680 {"native_getWaveForm", "([B)I", (void *)android_media_visualizer_native_getWaveForm}, 681 {"native_getFft", "([B)I", (void *)android_media_visualizer_native_getFft}, 682 {"native_getPeakRms", "(Landroid/media/audiofx/Visualizer$MeasurementPeakRms;)I", 683 (void *)android_media_visualizer_native_getPeakRms}, 684 {"native_setPeriodicCapture","(IZZ)I",(void *)android_media_setPeriodicCapture}, 685 }; 686 687 // ---------------------------------------------------------------------------- 688 689 int register_android_media_visualizer(JNIEnv *env) 690 { 691 return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)); 692 } 693 694