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