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