android_media_AudioRecord.cpp revision 34bb419e5946ab28112e9e27a4d1b3928d31e0e2
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/AudioRecord.h" 32#include "media/mediarecorder.h" 33 34#include <cutils/bitops.h> 35 36#include <system/audio.h> 37 38// ---------------------------------------------------------------------------- 39 40using namespace android; 41 42// ---------------------------------------------------------------------------- 43static const char* const kClassPathName = "android/media/AudioRecord"; 44 45struct fields_t { 46 // these fields provide access from C++ to the... 47 jmethodID postNativeEventInJava; //... event post callback method 48 int PCM16; //... format constants 49 int PCM8; //... format constants 50 jfieldID nativeRecorderInJavaObj; // provides access to the C++ AudioRecord object 51 jfieldID nativeCallbackCookie; // provides access to the AudioRecord callback data 52}; 53static fields_t javaAudioRecordFields; 54 55struct audiorecord_callback_cookie { 56 jclass audioRecord_class; 57 jobject audioRecord_ref; 58 }; 59 60Mutex sLock; 61 62// ---------------------------------------------------------------------------- 63 64#define AUDIORECORD_SUCCESS 0 65#define AUDIORECORD_ERROR -1 66#define AUDIORECORD_ERROR_BAD_VALUE -2 67#define AUDIORECORD_ERROR_INVALID_OPERATION -3 68#define AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT -16 69#define AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK -17 70#define AUDIORECORD_ERROR_SETUP_INVALIDFORMAT -18 71#define AUDIORECORD_ERROR_SETUP_INVALIDSOURCE -19 72#define AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED -20 73 74jint android_media_translateRecorderErrorCode(int code) { 75 switch(code) { 76 case NO_ERROR: 77 return AUDIORECORD_SUCCESS; 78 case BAD_VALUE: 79 return AUDIORECORD_ERROR_BAD_VALUE; 80 case INVALID_OPERATION: 81 return AUDIORECORD_ERROR_INVALID_OPERATION; 82 default: 83 return AUDIORECORD_ERROR; 84 } 85} 86 87 88// ---------------------------------------------------------------------------- 89static void recorderCallback(int event, void* user, void *info) { 90 if (event == AudioRecord::EVENT_MORE_DATA) { 91 // set size to 0 to signal we're not using the callback to read more data 92 AudioRecord::Buffer* pBuff = (AudioRecord::Buffer*)info; 93 pBuff->size = 0; 94 95 } else if (event == AudioRecord::EVENT_MARKER) { 96 audiorecord_callback_cookie *callbackInfo = (audiorecord_callback_cookie *)user; 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 109 } else if (event == AudioRecord::EVENT_NEW_POS) { 110 audiorecord_callback_cookie *callbackInfo = (audiorecord_callback_cookie *)user; 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 } 123} 124 125 126// ---------------------------------------------------------------------------- 127static int 128android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this, 129 jint source, jint sampleRateInHertz, jint channels, 130 jint audioFormat, jint buffSizeInBytes) 131{ 132 //LOGV(">> Entering android_media_AudioRecord_setup"); 133 //LOGV("sampleRate=%d, audioFormat=%d, channels=%x, buffSizeInBytes=%d", 134 // sampleRateInHertz, audioFormat, channels, buffSizeInBytes); 135 136 if (!audio_is_input_channel(channels)) { 137 LOGE("Error creating AudioRecord: channel count is not 1 or 2."); 138 return AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK; 139 } 140 uint32_t nbChannels = popcount(channels); 141 142 // compare the format against the Java constants 143 if ((audioFormat != javaAudioRecordFields.PCM16) 144 && (audioFormat != javaAudioRecordFields.PCM8)) { 145 LOGE("Error creating AudioRecord: unsupported audio format."); 146 return AUDIORECORD_ERROR_SETUP_INVALIDFORMAT; 147 } 148 149 int bytesPerSample = audioFormat==javaAudioRecordFields.PCM16 ? 2 : 1; 150 int format = audioFormat==javaAudioRecordFields.PCM16 ? 151 AUDIO_FORMAT_PCM_16_BIT : AUDIO_FORMAT_PCM_8_BIT; 152 153 if (buffSizeInBytes == 0) { 154 LOGE("Error creating AudioRecord: frameCount is 0."); 155 return AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT; 156 } 157 int frameSize = nbChannels * bytesPerSample; 158 size_t frameCount = buffSizeInBytes / frameSize; 159 160 if (source >= AUDIO_SOURCE_CNT) { 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(source, 188 sampleRateInHertz, 189 format, // word length, PCM 190 channels, 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 int 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 AUDIORECORD_ERROR; 239 } 240 241 return android_media_translateRecorderErrorCode(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_release(JNIEnv *env, jobject thiz) { 263 264 // serialize access. Ugly, but functional. 265 Mutex::Autolock lock(&sLock); 266 AudioRecord *lpRecorder = 267 (AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj); 268 audiorecord_callback_cookie *lpCookie = (audiorecord_callback_cookie *)env->GetIntField( 269 thiz, javaAudioRecordFields.nativeCallbackCookie); 270 271 // reset the native resources in the Java object so any attempt to access 272 // them after a call to release fails. 273 env->SetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj, 0); 274 env->SetIntField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0); 275 276 // delete the AudioRecord object 277 if (lpRecorder) { 278 LOGV("About to delete lpRecorder: %x\n", (int)lpRecorder); 279 lpRecorder->stop(); 280 delete lpRecorder; 281 } 282 283 // delete the callback information 284 if (lpCookie) { 285 LOGV("deleting lpCookie: %x\n", (int)lpCookie); 286 env->DeleteGlobalRef(lpCookie->audioRecord_class); 287 env->DeleteGlobalRef(lpCookie->audioRecord_ref); 288 delete lpCookie; 289 } 290} 291 292 293// ---------------------------------------------------------------------------- 294static void android_media_AudioRecord_finalize(JNIEnv *env, jobject thiz) { 295 android_media_AudioRecord_release(env, thiz); 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 // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such 321 // a way that it becomes much more efficient. When doing so, we will have to prevent the 322 // AudioSystem callback to be called while in critical section (in case of media server 323 // process crash for instance) 324 recordBuff = (jbyte *)env->GetByteArrayElements(javaAudioData, NULL); 325 326 if (recordBuff == NULL) { 327 LOGE("Error retrieving destination for recorded audio data, can't record"); 328 return 0; 329 } 330 331 // read the new audio data from the native AudioRecord object 332 ssize_t recorderBuffSize = lpRecorder->frameCount()*lpRecorder->frameSize(); 333 ssize_t readSize = lpRecorder->read(recordBuff + offsetInBytes, 334 sizeInBytes > (jint)recorderBuffSize ? 335 (jint)recorderBuffSize : sizeInBytes ); 336 env->ReleaseByteArrayElements(javaAudioData, recordBuff, 0); 337 338 return (jint) readSize; 339} 340 341// ---------------------------------------------------------------------------- 342static jint android_media_AudioRecord_readInShortArray(JNIEnv *env, jobject thiz, 343 jshortArray javaAudioData, 344 jint offsetInShorts, jint sizeInShorts) { 345 346 return (android_media_AudioRecord_readInByteArray(env, thiz, 347 (jbyteArray) javaAudioData, 348 offsetInShorts*2, sizeInShorts*2) 349 / 2); 350} 351 352// ---------------------------------------------------------------------------- 353static jint android_media_AudioRecord_readInDirectBuffer(JNIEnv *env, jobject thiz, 354 jobject jBuffer, jint sizeInBytes) { 355 AudioRecord *lpRecorder = NULL; 356 //LOGV("Entering android_media_AudioRecord_readInBuffer"); 357 358 // get the audio recorder from which we'll read new audio samples 359 lpRecorder = 360 (AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj); 361 if(lpRecorder==NULL) 362 return 0; 363 364 // direct buffer and direct access supported? 365 long capacity = env->GetDirectBufferCapacity(jBuffer); 366 if(capacity == -1) { 367 // buffer direct access is not supported 368 LOGE("Buffer direct access is not supported, can't record"); 369 return 0; 370 } 371 //LOGV("capacity = %ld", capacity); 372 jbyte* nativeFromJavaBuf = (jbyte*) env->GetDirectBufferAddress(jBuffer); 373 if(nativeFromJavaBuf==NULL) { 374 LOGE("Buffer direct access is not supported, can't record"); 375 return 0; 376 } 377 378 // read new data from the recorder 379 return (jint) lpRecorder->read(nativeFromJavaBuf, 380 capacity < sizeInBytes ? capacity : sizeInBytes); 381} 382 383 384// ---------------------------------------------------------------------------- 385static jint android_media_AudioRecord_set_marker_pos(JNIEnv *env, jobject thiz, 386 jint markerPos) { 387 388 AudioRecord *lpRecorder = (AudioRecord *)env->GetIntField( 389 thiz, javaAudioRecordFields.nativeRecorderInJavaObj); 390 391 if (lpRecorder) { 392 return 393 android_media_translateRecorderErrorCode( lpRecorder->setMarkerPosition(markerPos) ); 394 } else { 395 jniThrowException(env, "java/lang/IllegalStateException", 396 "Unable to retrieve AudioRecord pointer for setMarkerPosition()"); 397 return AUDIORECORD_ERROR; 398 } 399} 400 401 402// ---------------------------------------------------------------------------- 403static jint android_media_AudioRecord_get_marker_pos(JNIEnv *env, jobject thiz) { 404 405 AudioRecord *lpRecorder = (AudioRecord *)env->GetIntField( 406 thiz, javaAudioRecordFields.nativeRecorderInJavaObj); 407 uint32_t markerPos = 0; 408 409 if (lpRecorder) { 410 lpRecorder->getMarkerPosition(&markerPos); 411 return (jint)markerPos; 412 } else { 413 jniThrowException(env, "java/lang/IllegalStateException", 414 "Unable to retrieve AudioRecord pointer for getMarkerPosition()"); 415 return AUDIORECORD_ERROR; 416 } 417} 418 419 420// ---------------------------------------------------------------------------- 421static jint android_media_AudioRecord_set_pos_update_period(JNIEnv *env, jobject thiz, 422 jint period) { 423 424 AudioRecord *lpRecorder = (AudioRecord *)env->GetIntField( 425 thiz, javaAudioRecordFields.nativeRecorderInJavaObj); 426 427 if (lpRecorder) { 428 return 429 android_media_translateRecorderErrorCode( lpRecorder->setPositionUpdatePeriod(period) ); 430 } else { 431 jniThrowException(env, "java/lang/IllegalStateException", 432 "Unable to retrieve AudioRecord pointer for setPositionUpdatePeriod()"); 433 return AUDIORECORD_ERROR; 434 } 435} 436 437 438// ---------------------------------------------------------------------------- 439static jint android_media_AudioRecord_get_pos_update_period(JNIEnv *env, jobject thiz) { 440 441 AudioRecord *lpRecorder = (AudioRecord *)env->GetIntField( 442 thiz, javaAudioRecordFields.nativeRecorderInJavaObj); 443 uint32_t period = 0; 444 445 if (lpRecorder) { 446 lpRecorder->getPositionUpdatePeriod(&period); 447 return (jint)period; 448 } else { 449 jniThrowException(env, "java/lang/IllegalStateException", 450 "Unable to retrieve AudioRecord pointer for getPositionUpdatePeriod()"); 451 return AUDIORECORD_ERROR; 452 } 453} 454 455 456// ---------------------------------------------------------------------------- 457// returns the minimum required size for the successful creation of an AudioRecord instance. 458// returns 0 if the parameter combination is not supported. 459// return -1 if there was an error querying the buffer size. 460static jint android_media_AudioRecord_get_min_buff_size(JNIEnv *env, jobject thiz, 461 jint sampleRateInHertz, jint nbChannels, jint audioFormat) { 462 463 LOGV(">> android_media_AudioRecord_get_min_buff_size(%d, %d, %d)", sampleRateInHertz, nbChannels, audioFormat); 464 465 int frameCount = 0; 466 status_t result = AudioRecord::getMinFrameCount(&frameCount, 467 sampleRateInHertz, 468 (audioFormat == javaAudioRecordFields.PCM16 ? 469 AUDIO_FORMAT_PCM_16_BIT : AUDIO_FORMAT_PCM_8_BIT), 470 nbChannels); 471 472 if (result == BAD_VALUE) { 473 return 0; 474 } 475 if (result != NO_ERROR) { 476 return -1; 477 } 478 return frameCount * nbChannels * (audioFormat == javaAudioRecordFields.PCM16 ? 2 : 1); 479} 480 481 482// ---------------------------------------------------------------------------- 483// ---------------------------------------------------------------------------- 484static JNINativeMethod gMethods[] = { 485 // name, signature, funcPtr 486 {"native_start", "()I", (void *)android_media_AudioRecord_start}, 487 {"native_stop", "()V", (void *)android_media_AudioRecord_stop}, 488 {"native_setup", "(Ljava/lang/Object;IIIII)I", 489 (void *)android_media_AudioRecord_setup}, 490 {"native_finalize", "()V", (void *)android_media_AudioRecord_finalize}, 491 {"native_release", "()V", (void *)android_media_AudioRecord_release}, 492 {"native_read_in_byte_array", 493 "([BII)I", (void *)android_media_AudioRecord_readInByteArray}, 494 {"native_read_in_short_array", 495 "([SII)I", (void *)android_media_AudioRecord_readInShortArray}, 496 {"native_read_in_direct_buffer","(Ljava/lang/Object;I)I", 497 (void *)android_media_AudioRecord_readInDirectBuffer}, 498 {"native_set_marker_pos","(I)I", (void *)android_media_AudioRecord_set_marker_pos}, 499 {"native_get_marker_pos","()I", (void *)android_media_AudioRecord_get_marker_pos}, 500 {"native_set_pos_update_period", 501 "(I)I", (void *)android_media_AudioRecord_set_pos_update_period}, 502 {"native_get_pos_update_period", 503 "()I", (void *)android_media_AudioRecord_get_pos_update_period}, 504 {"native_get_min_buff_size", 505 "(III)I", (void *)android_media_AudioRecord_get_min_buff_size}, 506}; 507 508// field names found in android/media/AudioRecord.java 509#define JAVA_POSTEVENT_CALLBACK_NAME "postEventFromNative" 510#define JAVA_CONST_PCM16_NAME "ENCODING_PCM_16BIT" 511#define JAVA_CONST_PCM8_NAME "ENCODING_PCM_8BIT" 512#define JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME "mNativeRecorderInJavaObj" 513#define JAVA_NATIVECALLBACKINFO_FIELD_NAME "mNativeCallbackCookie" 514 515#define JAVA_AUDIOFORMAT_CLASS_NAME "android/media/AudioFormat" 516 517// ---------------------------------------------------------------------------- 518 519extern bool android_media_getIntConstantFromClass(JNIEnv* pEnv, 520 jclass theClass, const char* className, const char* constName, int* constVal); 521 522// ---------------------------------------------------------------------------- 523int register_android_media_AudioRecord(JNIEnv *env) 524{ 525 javaAudioRecordFields.postNativeEventInJava = NULL; 526 javaAudioRecordFields.nativeRecorderInJavaObj = NULL; 527 javaAudioRecordFields.nativeCallbackCookie = NULL; 528 529 530 // Get the AudioRecord class 531 jclass audioRecordClass = env->FindClass(kClassPathName); 532 if (audioRecordClass == NULL) { 533 LOGE("Can't find %s", kClassPathName); 534 return -1; 535 } 536 // Get the postEvent method 537 javaAudioRecordFields.postNativeEventInJava = env->GetStaticMethodID( 538 audioRecordClass, 539 JAVA_POSTEVENT_CALLBACK_NAME, "(Ljava/lang/Object;IIILjava/lang/Object;)V"); 540 if (javaAudioRecordFields.postNativeEventInJava == NULL) { 541 LOGE("Can't find AudioRecord.%s", JAVA_POSTEVENT_CALLBACK_NAME); 542 return -1; 543 } 544 545 // Get the variables 546 // mNativeRecorderInJavaObj 547 javaAudioRecordFields.nativeRecorderInJavaObj = 548 env->GetFieldID(audioRecordClass, 549 JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME, "I"); 550 if (javaAudioRecordFields.nativeRecorderInJavaObj == NULL) { 551 LOGE("Can't find AudioRecord.%s", JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME); 552 return -1; 553 } 554 // mNativeCallbackCookie 555 javaAudioRecordFields.nativeCallbackCookie = env->GetFieldID( 556 audioRecordClass, 557 JAVA_NATIVECALLBACKINFO_FIELD_NAME, "I"); 558 if (javaAudioRecordFields.nativeCallbackCookie == NULL) { 559 LOGE("Can't find AudioRecord.%s", JAVA_NATIVECALLBACKINFO_FIELD_NAME); 560 return -1; 561 } 562 563 // Get the format constants from the AudioFormat class 564 jclass audioFormatClass = NULL; 565 audioFormatClass = env->FindClass(JAVA_AUDIOFORMAT_CLASS_NAME); 566 if (audioFormatClass == NULL) { 567 LOGE("Can't find %s", JAVA_AUDIOFORMAT_CLASS_NAME); 568 return -1; 569 } 570 if ( !android_media_getIntConstantFromClass(env, audioFormatClass, 571 JAVA_AUDIOFORMAT_CLASS_NAME, 572 JAVA_CONST_PCM16_NAME, &(javaAudioRecordFields.PCM16)) 573 || !android_media_getIntConstantFromClass(env, audioFormatClass, 574 JAVA_AUDIOFORMAT_CLASS_NAME, 575 JAVA_CONST_PCM8_NAME, &(javaAudioRecordFields.PCM8)) ) { 576 // error log performed in getIntConstantFromClass() 577 return -1; 578 } 579 580 return AndroidRuntime::registerNativeMethods(env, 581 kClassPathName, gMethods, NELEM(gMethods)); 582} 583 584// ---------------------------------------------------------------------------- 585