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