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