blob: d7485ae16beefd2a4973467cb24c3da9d28fd5d7 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031#include "media/AudioRecord.h"
Eric Laurenta553c252009-07-17 12:17:14 -070032#include "media/mediarecorder.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033
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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048 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
Eric Laurenta553c252009-07-17 12:17:14 -070065#define AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK -17
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066#define AUDIORECORD_ERROR_SETUP_INVALIDFORMAT -18
Eric Laurent4bc035a2009-05-22 09:18:15 -070067#define AUDIORECORD_ERROR_SETUP_INVALIDSOURCE -19
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068#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,
Eric Laurenta553c252009-07-17 12:17:14 -0700125 jint source, jint sampleRateInHertz, jint channels,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 jint audioFormat, jint buffSizeInBytes)
127{
128 //LOGV(">> Entering android_media_AudioRecord_setup");
Eric Laurenta553c252009-07-17 12:17:14 -0700129 //LOGV("sampleRate=%d, audioFormat=%d, channels=%x, buffSizeInBytes=%d",
130 // sampleRateInHertz, audioFormat, channels, buffSizeInBytes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131
Eric Laurenta553c252009-07-17 12:17:14 -0700132 if (!AudioSystem::isInputChannel(channels)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 LOGE("Error creating AudioRecord: channel count is not 1 or 2.");
Eric Laurenta553c252009-07-17 12:17:14 -0700134 return AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 }
Eric Laurenta553c252009-07-17 12:17:14 -0700136 uint32_t nbChannels = AudioSystem::popCount(channels);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137
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
Eric Laurenta553c252009-07-17 12:17:14 -0700156 if (source >= AUDIO_SOURCE_LIST_END) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157 LOGE("Error creating AudioRecord: unknown source.");
Eric Laurent4bc035a2009-05-22 09:18:15 -0700158 return AUDIORECORD_ERROR_SETUP_INVALIDSOURCE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159 }
Eric Laurent4bc035a2009-05-22 09:18:15 -0700160
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161 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
Eric Laurenta553c252009-07-17 12:17:14 -0700183 lpRecorder->set(source,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800184 sampleRateInHertz,
185 format, // word length, PCM
Eric Laurenta553c252009-07-17 12:17:14 -0700186 channels,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187 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:
210native_init_failure:
Jean-Michel Trivi4bac5a32009-07-17 12:05:31 -0700211 env->DeleteGlobalRef(lpCallbackData->audioRecord_class);
212 env->DeleteGlobalRef(lpCallbackData->audioRecord_ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213 delete lpCallbackData;
Jean-Michel Trivi4bac5a32009-07-17 12:05:31 -0700214
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215native_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// ----------------------------------------------------------------------------
Eric Laurent9cc489a2009-12-05 05:20:01 -0800227static int
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228android_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);
Eric Laurent9cc489a2009-12-05 05:20:01 -0800234 return AUDIORECORD_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800235 }
236
Eric Laurent9cc489a2009-12-05 05:20:01 -0800237 return android_media_translateRecorderErrorCode(lpRecorder->start());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800238}
239
240
241// ----------------------------------------------------------------------------
242static void
243android_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// ----------------------------------------------------------------------------
258static 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);
Jean-Michel Trivi4bac5a32009-07-17 12:05:31 -0700275 env->DeleteGlobalRef(lpCookie->audioRecord_class);
276 env->DeleteGlobalRef(lpCookie->audioRecord_ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800277 delete lpCookie;
278 }
279
280}
281
282
283// ----------------------------------------------------------------------------
284static 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// ----------------------------------------------------------------------------
296static 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// ----------------------------------------------------------------------------
334static 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// ----------------------------------------------------------------------------
345static 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// ----------------------------------------------------------------------------
377static 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// ----------------------------------------------------------------------------
395static 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// ----------------------------------------------------------------------------
413static 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// ----------------------------------------------------------------------------
431static 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.
452static 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// ----------------------------------------------------------------------------
483static JNINativeMethod gMethods[] = {
484 // name, signature, funcPtr
Eric Laurent9cc489a2009-12-05 05:20:01 -0800485 {"native_start", "()I", (void *)android_media_AudioRecord_start},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800486 {"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"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800511#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
518extern bool android_media_getIntConstantFromClass(JNIEnv* pEnv,
519 jclass theClass, const char* className, const char* constName, int* constVal);
520
521// ----------------------------------------------------------------------------
522int 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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800581 return AndroidRuntime::registerNativeMethods(env,
582 kClassPathName, gMethods, NELEM(gMethods));
583}
584
585// ----------------------------------------------------------------------------