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