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