android_media_AudioRecord.cpp revision bc11a696f6856624de532a6830d5db9dbbe2384c
1/* 2 * Copyright (C) 2008 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//#define LOG_NDEBUG 0 18 19#define LOG_TAG "AudioRecord-JNI" 20 21#include <inttypes.h> 22#include <jni.h> 23#include <JNIHelp.h> 24#include <android_runtime/AndroidRuntime.h> 25 26#include <utils/Log.h> 27#include <media/AudioRecord.h> 28 29#include "android_media_AudioFormat.h" 30#include "android_media_AudioErrors.h" 31 32// ---------------------------------------------------------------------------- 33 34using namespace android; 35 36// ---------------------------------------------------------------------------- 37static const char* const kClassPathName = "android/media/AudioRecord"; 38 39struct fields_t { 40 // these fields provide access from C++ to the... 41 jmethodID postNativeEventInJava; //... event post callback method 42 jfieldID nativeRecorderInJavaObj; // provides access to the C++ AudioRecord object 43 jfieldID nativeCallbackCookie; // provides access to the AudioRecord callback data 44}; 45static fields_t javaAudioRecordFields; 46 47struct audiorecord_callback_cookie { 48 jclass audioRecord_class; 49 jobject audioRecord_ref; 50 bool busy; 51 Condition cond; 52}; 53 54static Mutex sLock; 55static SortedVector <audiorecord_callback_cookie *> sAudioRecordCallBackCookies; 56 57// ---------------------------------------------------------------------------- 58 59#define AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT -16 60#define AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK -17 61#define AUDIORECORD_ERROR_SETUP_INVALIDFORMAT -18 62#define AUDIORECORD_ERROR_SETUP_INVALIDSOURCE -19 63#define AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED -20 64 65// ---------------------------------------------------------------------------- 66static void recorderCallback(int event, void* user, void *info) { 67 68 audiorecord_callback_cookie *callbackInfo = (audiorecord_callback_cookie *)user; 69 { 70 Mutex::Autolock l(sLock); 71 if (sAudioRecordCallBackCookies.indexOf(callbackInfo) < 0) { 72 return; 73 } 74 callbackInfo->busy = true; 75 } 76 77 switch (event) { 78 case AudioRecord::EVENT_MARKER: { 79 JNIEnv *env = AndroidRuntime::getJNIEnv(); 80 if (user != NULL && env != NULL) { 81 env->CallStaticVoidMethod( 82 callbackInfo->audioRecord_class, 83 javaAudioRecordFields.postNativeEventInJava, 84 callbackInfo->audioRecord_ref, event, 0,0, NULL); 85 if (env->ExceptionCheck()) { 86 env->ExceptionDescribe(); 87 env->ExceptionClear(); 88 } 89 } 90 } break; 91 92 case AudioRecord::EVENT_NEW_POS: { 93 JNIEnv *env = AndroidRuntime::getJNIEnv(); 94 if (user != NULL && env != NULL) { 95 env->CallStaticVoidMethod( 96 callbackInfo->audioRecord_class, 97 javaAudioRecordFields.postNativeEventInJava, 98 callbackInfo->audioRecord_ref, event, 0,0, NULL); 99 if (env->ExceptionCheck()) { 100 env->ExceptionDescribe(); 101 env->ExceptionClear(); 102 } 103 } 104 } break; 105 } 106 107 { 108 Mutex::Autolock l(sLock); 109 callbackInfo->busy = false; 110 callbackInfo->cond.broadcast(); 111 } 112} 113 114// ---------------------------------------------------------------------------- 115static sp<AudioRecord> getAudioRecord(JNIEnv* env, jobject thiz) 116{ 117 Mutex::Autolock l(sLock); 118 AudioRecord* const ar = 119 (AudioRecord*)env->GetLongField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj); 120 return sp<AudioRecord>(ar); 121} 122 123static sp<AudioRecord> setAudioRecord(JNIEnv* env, jobject thiz, const sp<AudioRecord>& ar) 124{ 125 Mutex::Autolock l(sLock); 126 sp<AudioRecord> old = 127 (AudioRecord*)env->GetLongField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj); 128 if (ar.get()) { 129 ar->incStrong((void*)setAudioRecord); 130 } 131 if (old != 0) { 132 old->decStrong((void*)setAudioRecord); 133 } 134 env->SetLongField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj, (jlong)ar.get()); 135 return old; 136} 137 138// ---------------------------------------------------------------------------- 139static jint 140android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this, 141 jint source, jint sampleRateInHertz, jint channelMask, 142 // Java channel masks map directly to the native definition 143 jint audioFormat, jint buffSizeInBytes, jintArray jSession) 144{ 145 //ALOGV(">> Entering android_media_AudioRecord_setup"); 146 //ALOGV("sampleRate=%d, audioFormat=%d, channel mask=%x, buffSizeInBytes=%d", 147 // sampleRateInHertz, audioFormat, channelMask, buffSizeInBytes); 148 149 if (!audio_is_input_channel(channelMask)) { 150 ALOGE("Error creating AudioRecord: channel mask %#x is not valid.", channelMask); 151 return (jint) AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK; 152 } 153 uint32_t channelCount = popcount(channelMask); 154 155 // compare the format against the Java constants 156 audio_format_t format = audioFormatToNative(audioFormat); 157 if (format == AUDIO_FORMAT_INVALID) { 158 ALOGE("Error creating AudioRecord: unsupported audio format %d.", audioFormat); 159 return (jint) AUDIORECORD_ERROR_SETUP_INVALIDFORMAT; 160 } 161 162 size_t bytesPerSample = audio_bytes_per_sample(format); 163 164 if (buffSizeInBytes == 0) { 165 ALOGE("Error creating AudioRecord: frameCount is 0."); 166 return (jint) AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT; 167 } 168 size_t frameSize = channelCount * bytesPerSample; 169 size_t frameCount = buffSizeInBytes / frameSize; 170 171 if ((uint32_t(source) >= AUDIO_SOURCE_CNT) && (uint32_t(source) != AUDIO_SOURCE_HOTWORD)) { 172 ALOGE("Error creating AudioRecord: unknown source %d.", source); 173 return (jint) AUDIORECORD_ERROR_SETUP_INVALIDSOURCE; 174 } 175 176 jclass clazz = env->GetObjectClass(thiz); 177 if (clazz == NULL) { 178 ALOGE("Can't find %s when setting up callback.", kClassPathName); 179 return (jint) AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED; 180 } 181 182 if (jSession == NULL) { 183 ALOGE("Error creating AudioRecord: invalid session ID pointer"); 184 return (jint) AUDIO_JAVA_ERROR; 185 } 186 187 jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL); 188 if (nSession == NULL) { 189 ALOGE("Error creating AudioRecord: Error retrieving session id pointer"); 190 return (jint) AUDIO_JAVA_ERROR; 191 } 192 int sessionId = nSession[0]; 193 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0); 194 nSession = NULL; 195 196 // create an uninitialized AudioRecord object 197 sp<AudioRecord> lpRecorder = new AudioRecord(); 198 199 // create the callback information: 200 // this data will be passed with every AudioRecord callback 201 audiorecord_callback_cookie *lpCallbackData = new audiorecord_callback_cookie; 202 lpCallbackData->audioRecord_class = (jclass)env->NewGlobalRef(clazz); 203 // we use a weak reference so the AudioRecord object can be garbage collected. 204 lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this); 205 lpCallbackData->busy = false; 206 207 const status_t status = lpRecorder->set((audio_source_t) source, 208 sampleRateInHertz, 209 format, // word length, PCM 210 channelMask, 211 frameCount, 212 recorderCallback,// callback_t 213 lpCallbackData,// void* user 214 0, // notificationFrames, 215 true, // threadCanCallJava 216 sessionId); 217 218 if (status != NO_ERROR) { 219 ALOGE("Error creating AudioRecord instance: initialization check failed with status %d.", 220 status); 221 goto native_init_failure; 222 } 223 224 nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL); 225 if (nSession == NULL) { 226 ALOGE("Error creating AudioRecord: Error retrieving session id pointer"); 227 goto native_init_failure; 228 } 229 // read the audio session ID back from AudioRecord in case a new session was created during set() 230 nSession[0] = lpRecorder->getSessionId(); 231 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0); 232 nSession = NULL; 233 234 { // scope for the lock 235 Mutex::Autolock l(sLock); 236 sAudioRecordCallBackCookies.add(lpCallbackData); 237 } 238 // save our newly created C++ AudioRecord in the "nativeRecorderInJavaObj" field 239 // of the Java object 240 setAudioRecord(env, thiz, lpRecorder); 241 242 // save our newly created callback information in the "nativeCallbackCookie" field 243 // of the Java object (in mNativeCallbackCookie) so we can free the memory in finalize() 244 env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, (jlong)lpCallbackData); 245 246 return (jint) AUDIO_JAVA_SUCCESS; 247 248 // failure: 249native_init_failure: 250 env->DeleteGlobalRef(lpCallbackData->audioRecord_class); 251 env->DeleteGlobalRef(lpCallbackData->audioRecord_ref); 252 delete lpCallbackData; 253 env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0); 254 255 return (jint) AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED; 256} 257 258 259 260// ---------------------------------------------------------------------------- 261static jint 262android_media_AudioRecord_start(JNIEnv *env, jobject thiz, jint event, jint triggerSession) 263{ 264 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz); 265 if (lpRecorder == NULL ) { 266 jniThrowException(env, "java/lang/IllegalStateException", NULL); 267 return (jint) AUDIO_JAVA_ERROR; 268 } 269 270 return nativeToJavaStatus( 271 lpRecorder->start((AudioSystem::sync_event_t)event, triggerSession)); 272} 273 274 275// ---------------------------------------------------------------------------- 276static void 277android_media_AudioRecord_stop(JNIEnv *env, jobject thiz) 278{ 279 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz); 280 if (lpRecorder == NULL ) { 281 jniThrowException(env, "java/lang/IllegalStateException", NULL); 282 return; 283 } 284 285 lpRecorder->stop(); 286 //ALOGV("Called lpRecorder->stop()"); 287} 288 289 290// ---------------------------------------------------------------------------- 291 292#define CALLBACK_COND_WAIT_TIMEOUT_MS 1000 293static void android_media_AudioRecord_release(JNIEnv *env, jobject thiz) { 294 sp<AudioRecord> lpRecorder = setAudioRecord(env, thiz, 0); 295 if (lpRecorder == NULL) { 296 return; 297 } 298 ALOGV("About to delete lpRecorder: %p", lpRecorder.get()); 299 lpRecorder->stop(); 300 301 audiorecord_callback_cookie *lpCookie = (audiorecord_callback_cookie *)env->GetLongField( 302 thiz, javaAudioRecordFields.nativeCallbackCookie); 303 304 // reset the native resources in the Java object so any attempt to access 305 // them after a call to release fails. 306 env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0); 307 308 // delete the callback information 309 if (lpCookie) { 310 Mutex::Autolock l(sLock); 311 ALOGV("deleting lpCookie: %p", lpCookie); 312 while (lpCookie->busy) { 313 if (lpCookie->cond.waitRelative(sLock, 314 milliseconds(CALLBACK_COND_WAIT_TIMEOUT_MS)) != 315 NO_ERROR) { 316 break; 317 } 318 } 319 sAudioRecordCallBackCookies.remove(lpCookie); 320 env->DeleteGlobalRef(lpCookie->audioRecord_class); 321 env->DeleteGlobalRef(lpCookie->audioRecord_ref); 322 delete lpCookie; 323 } 324} 325 326 327// ---------------------------------------------------------------------------- 328static void android_media_AudioRecord_finalize(JNIEnv *env, jobject thiz) { 329 android_media_AudioRecord_release(env, thiz); 330} 331 332 333// ---------------------------------------------------------------------------- 334static jint android_media_AudioRecord_readInByteArray(JNIEnv *env, jobject thiz, 335 jbyteArray javaAudioData, 336 jint offsetInBytes, jint sizeInBytes) { 337 jbyte* recordBuff = NULL; 338 // get the audio recorder from which we'll read new audio samples 339 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz); 340 if (lpRecorder == NULL) { 341 ALOGE("Unable to retrieve AudioRecord object, can't record"); 342 return 0; 343 } 344 345 if (!javaAudioData) { 346 ALOGE("Invalid Java array to store recorded audio, can't record"); 347 return 0; 348 } 349 350 // get the pointer to where we'll record the audio 351 // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such 352 // a way that it becomes much more efficient. When doing so, we will have to prevent the 353 // AudioSystem callback to be called while in critical section (in case of media server 354 // process crash for instance) 355 recordBuff = (jbyte *)env->GetByteArrayElements(javaAudioData, NULL); 356 357 if (recordBuff == NULL) { 358 ALOGE("Error retrieving destination for recorded audio data, can't record"); 359 return 0; 360 } 361 362 // read the new audio data from the native AudioRecord object 363 ssize_t recorderBuffSize = lpRecorder->frameCount()*lpRecorder->frameSize(); 364 ssize_t readSize = lpRecorder->read(recordBuff + offsetInBytes, 365 sizeInBytes > (jint)recorderBuffSize ? 366 (jint)recorderBuffSize : sizeInBytes ); 367 env->ReleaseByteArrayElements(javaAudioData, recordBuff, 0); 368 369 if (readSize < 0) { 370 readSize = (jint)AUDIO_JAVA_INVALID_OPERATION; 371 } 372 return (jint) readSize; 373} 374 375// ---------------------------------------------------------------------------- 376static jint android_media_AudioRecord_readInShortArray(JNIEnv *env, jobject thiz, 377 jshortArray javaAudioData, 378 jint offsetInShorts, jint sizeInShorts) { 379 380 jshort* recordBuff = NULL; 381 // get the audio recorder from which we'll read new audio samples 382 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz); 383 if (lpRecorder == NULL) { 384 ALOGE("Unable to retrieve AudioRecord object, can't record"); 385 return 0; 386 } 387 388 if (!javaAudioData) { 389 ALOGE("Invalid Java array to store recorded audio, can't record"); 390 return 0; 391 } 392 393 // get the pointer to where we'll record the audio 394 // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such 395 // a way that it becomes much more efficient. When doing so, we will have to prevent the 396 // AudioSystem callback to be called while in critical section (in case of media server 397 // process crash for instance) 398 recordBuff = (jshort *)env->GetShortArrayElements(javaAudioData, NULL); 399 400 if (recordBuff == NULL) { 401 ALOGE("Error retrieving destination for recorded audio data, can't record"); 402 return 0; 403 } 404 405 // read the new audio data from the native AudioRecord object 406 const size_t recorderBuffSize = lpRecorder->frameCount()*lpRecorder->frameSize(); 407 const size_t sizeInBytes = sizeInShorts * sizeof(short); 408 ssize_t readSize = lpRecorder->read(recordBuff + offsetInShorts * sizeof(short), 409 sizeInBytes > recorderBuffSize ? 410 recorderBuffSize : sizeInBytes); 411 412 env->ReleaseShortArrayElements(javaAudioData, recordBuff, 0); 413 414 if (readSize < 0) { 415 readSize = (jint)AUDIO_JAVA_INVALID_OPERATION; 416 } else { 417 readSize /= sizeof(short); 418 } 419 return (jint) readSize; 420} 421 422// ---------------------------------------------------------------------------- 423static jint android_media_AudioRecord_readInDirectBuffer(JNIEnv *env, jobject thiz, 424 jobject jBuffer, jint sizeInBytes) { 425 // get the audio recorder from which we'll read new audio samples 426 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz); 427 if (lpRecorder==NULL) 428 return 0; 429 430 // direct buffer and direct access supported? 431 long capacity = env->GetDirectBufferCapacity(jBuffer); 432 if (capacity == -1) { 433 // buffer direct access is not supported 434 ALOGE("Buffer direct access is not supported, can't record"); 435 return 0; 436 } 437 //ALOGV("capacity = %ld", capacity); 438 jbyte* nativeFromJavaBuf = (jbyte*) env->GetDirectBufferAddress(jBuffer); 439 if (nativeFromJavaBuf==NULL) { 440 ALOGE("Buffer direct access is not supported, can't record"); 441 return 0; 442 } 443 444 // read new data from the recorder 445 ssize_t readSize = lpRecorder->read(nativeFromJavaBuf, 446 capacity < sizeInBytes ? capacity : sizeInBytes); 447 if (readSize < 0) { 448 readSize = (jint)AUDIO_JAVA_INVALID_OPERATION; 449 } 450 return (jint)readSize; 451} 452 453 454// ---------------------------------------------------------------------------- 455static jint android_media_AudioRecord_set_marker_pos(JNIEnv *env, jobject thiz, 456 jint markerPos) { 457 458 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz); 459 if (lpRecorder == NULL) { 460 jniThrowException(env, "java/lang/IllegalStateException", 461 "Unable to retrieve AudioRecord pointer for setMarkerPosition()"); 462 return (jint)AUDIO_JAVA_ERROR; 463 } 464 return nativeToJavaStatus( lpRecorder->setMarkerPosition(markerPos) ); 465} 466 467 468// ---------------------------------------------------------------------------- 469static jint android_media_AudioRecord_get_marker_pos(JNIEnv *env, jobject thiz) { 470 471 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz); 472 uint32_t markerPos = 0; 473 474 if (lpRecorder == NULL) { 475 jniThrowException(env, "java/lang/IllegalStateException", 476 "Unable to retrieve AudioRecord pointer for getMarkerPosition()"); 477 return (jint)AUDIO_JAVA_ERROR; 478 } 479 lpRecorder->getMarkerPosition(&markerPos); 480 return (jint)markerPos; 481} 482 483 484// ---------------------------------------------------------------------------- 485static jint android_media_AudioRecord_set_pos_update_period(JNIEnv *env, jobject thiz, 486 jint period) { 487 488 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz); 489 490 if (lpRecorder == NULL) { 491 jniThrowException(env, "java/lang/IllegalStateException", 492 "Unable to retrieve AudioRecord pointer for setPositionUpdatePeriod()"); 493 return (jint)AUDIO_JAVA_ERROR; 494 } 495 return nativeToJavaStatus( lpRecorder->setPositionUpdatePeriod(period) ); 496} 497 498 499// ---------------------------------------------------------------------------- 500static jint android_media_AudioRecord_get_pos_update_period(JNIEnv *env, jobject thiz) { 501 502 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz); 503 uint32_t period = 0; 504 505 if (lpRecorder == NULL) { 506 jniThrowException(env, "java/lang/IllegalStateException", 507 "Unable to retrieve AudioRecord pointer for getPositionUpdatePeriod()"); 508 return (jint)AUDIO_JAVA_ERROR; 509 } 510 lpRecorder->getPositionUpdatePeriod(&period); 511 return (jint)period; 512} 513 514 515// ---------------------------------------------------------------------------- 516// returns the minimum required size for the successful creation of an AudioRecord instance. 517// returns 0 if the parameter combination is not supported. 518// return -1 if there was an error querying the buffer size. 519static jint android_media_AudioRecord_get_min_buff_size(JNIEnv *env, jobject thiz, 520 jint sampleRateInHertz, jint channelCount, jint audioFormat) { 521 522 ALOGV(">> android_media_AudioRecord_get_min_buff_size(%d, %d, %d)", 523 sampleRateInHertz, channelCount, audioFormat); 524 525 size_t frameCount = 0; 526 audio_format_t format = audioFormatToNative(audioFormat); 527 status_t result = AudioRecord::getMinFrameCount(&frameCount, 528 sampleRateInHertz, 529 format, 530 audio_channel_in_mask_from_count(channelCount)); 531 532 if (result == BAD_VALUE) { 533 return 0; 534 } 535 if (result != NO_ERROR) { 536 return -1; 537 } 538 return frameCount * channelCount * audio_bytes_per_sample(format); 539} 540 541 542// ---------------------------------------------------------------------------- 543// ---------------------------------------------------------------------------- 544static JNINativeMethod gMethods[] = { 545 // name, signature, funcPtr 546 {"native_start", "(II)I", (void *)android_media_AudioRecord_start}, 547 {"native_stop", "()V", (void *)android_media_AudioRecord_stop}, 548 {"native_setup", "(Ljava/lang/Object;IIIII[I)I", 549 (void *)android_media_AudioRecord_setup}, 550 {"native_finalize", "()V", (void *)android_media_AudioRecord_finalize}, 551 {"native_release", "()V", (void *)android_media_AudioRecord_release}, 552 {"native_read_in_byte_array", 553 "([BII)I", (void *)android_media_AudioRecord_readInByteArray}, 554 {"native_read_in_short_array", 555 "([SII)I", (void *)android_media_AudioRecord_readInShortArray}, 556 {"native_read_in_direct_buffer","(Ljava/lang/Object;I)I", 557 (void *)android_media_AudioRecord_readInDirectBuffer}, 558 {"native_set_marker_pos","(I)I", (void *)android_media_AudioRecord_set_marker_pos}, 559 {"native_get_marker_pos","()I", (void *)android_media_AudioRecord_get_marker_pos}, 560 {"native_set_pos_update_period", 561 "(I)I", (void *)android_media_AudioRecord_set_pos_update_period}, 562 {"native_get_pos_update_period", 563 "()I", (void *)android_media_AudioRecord_get_pos_update_period}, 564 {"native_get_min_buff_size", 565 "(III)I", (void *)android_media_AudioRecord_get_min_buff_size}, 566}; 567 568// field names found in android/media/AudioRecord.java 569#define JAVA_POSTEVENT_CALLBACK_NAME "postEventFromNative" 570#define JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME "mNativeRecorderInJavaObj" 571#define JAVA_NATIVECALLBACKINFO_FIELD_NAME "mNativeCallbackCookie" 572 573// ---------------------------------------------------------------------------- 574int register_android_media_AudioRecord(JNIEnv *env) 575{ 576 javaAudioRecordFields.postNativeEventInJava = NULL; 577 javaAudioRecordFields.nativeRecorderInJavaObj = NULL; 578 javaAudioRecordFields.nativeCallbackCookie = NULL; 579 580 581 // Get the AudioRecord class 582 jclass audioRecordClass = env->FindClass(kClassPathName); 583 if (audioRecordClass == NULL) { 584 ALOGE("Can't find %s", kClassPathName); 585 return -1; 586 } 587 // Get the postEvent method 588 javaAudioRecordFields.postNativeEventInJava = env->GetStaticMethodID( 589 audioRecordClass, 590 JAVA_POSTEVENT_CALLBACK_NAME, "(Ljava/lang/Object;IIILjava/lang/Object;)V"); 591 if (javaAudioRecordFields.postNativeEventInJava == NULL) { 592 ALOGE("Can't find AudioRecord.%s", JAVA_POSTEVENT_CALLBACK_NAME); 593 return -1; 594 } 595 596 // Get the variables 597 // mNativeRecorderInJavaObj 598 javaAudioRecordFields.nativeRecorderInJavaObj = 599 env->GetFieldID(audioRecordClass, 600 JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME, "J"); 601 if (javaAudioRecordFields.nativeRecorderInJavaObj == NULL) { 602 ALOGE("Can't find AudioRecord.%s", JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME); 603 return -1; 604 } 605 // mNativeCallbackCookie 606 javaAudioRecordFields.nativeCallbackCookie = env->GetFieldID( 607 audioRecordClass, 608 JAVA_NATIVECALLBACKINFO_FIELD_NAME, "J"); 609 if (javaAudioRecordFields.nativeCallbackCookie == NULL) { 610 ALOGE("Can't find AudioRecord.%s", JAVA_NATIVECALLBACKINFO_FIELD_NAME); 611 return -1; 612 } 613 614 return AndroidRuntime::registerNativeMethods(env, 615 kClassPathName, gMethods, NELEM(gMethods)); 616} 617 618// ---------------------------------------------------------------------------- 619