blob: f78f83c2a6d98670a91bb2223f77b80bb5035558 [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
Dave Sparkse6335c92010-03-13 17:08:22 -080058Mutex sLock;
59
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060// ----------------------------------------------------------------------------
61
62#define AUDIORECORD_SUCCESS 0
63#define AUDIORECORD_ERROR -1
64#define AUDIORECORD_ERROR_BAD_VALUE -2
65#define AUDIORECORD_ERROR_INVALID_OPERATION -3
66#define AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT -16
Eric Laurenta553c252009-07-17 12:17:14 -070067#define AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK -17
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068#define AUDIORECORD_ERROR_SETUP_INVALIDFORMAT -18
Eric Laurent4bc035a2009-05-22 09:18:15 -070069#define AUDIORECORD_ERROR_SETUP_INVALIDSOURCE -19
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070#define AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED -20
71
72jint android_media_translateRecorderErrorCode(int code) {
73 switch(code) {
74 case NO_ERROR:
75 return AUDIORECORD_SUCCESS;
76 case BAD_VALUE:
77 return AUDIORECORD_ERROR_BAD_VALUE;
78 case INVALID_OPERATION:
79 return AUDIORECORD_ERROR_INVALID_OPERATION;
80 default:
81 return AUDIORECORD_ERROR;
82 }
83}
84
85
86// ----------------------------------------------------------------------------
87static void recorderCallback(int event, void* user, void *info) {
88 if (event == AudioRecord::EVENT_MORE_DATA) {
89 // set size to 0 to signal we're not using the callback to read more data
90 AudioRecord::Buffer* pBuff = (AudioRecord::Buffer*)info;
91 pBuff->size = 0;
92
93 } else if (event == AudioRecord::EVENT_MARKER) {
94 audiorecord_callback_cookie *callbackInfo = (audiorecord_callback_cookie *)user;
95 JNIEnv *env = AndroidRuntime::getJNIEnv();
96 if (user && env) {
97 env->CallStaticVoidMethod(
98 callbackInfo->audioRecord_class,
99 javaAudioRecordFields.postNativeEventInJava,
100 callbackInfo->audioRecord_ref, event, 0,0, NULL);
101 if (env->ExceptionCheck()) {
102 env->ExceptionDescribe();
103 env->ExceptionClear();
104 }
105 }
106
107 } else if (event == AudioRecord::EVENT_NEW_POS) {
108 audiorecord_callback_cookie *callbackInfo = (audiorecord_callback_cookie *)user;
109 JNIEnv *env = AndroidRuntime::getJNIEnv();
110 if (user && env) {
111 env->CallStaticVoidMethod(
112 callbackInfo->audioRecord_class,
113 javaAudioRecordFields.postNativeEventInJava,
114 callbackInfo->audioRecord_ref, event, 0,0, NULL);
115 if (env->ExceptionCheck()) {
116 env->ExceptionDescribe();
117 env->ExceptionClear();
118 }
119 }
120 }
121}
122
123
124// ----------------------------------------------------------------------------
125static int
126android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
Eric Laurenta553c252009-07-17 12:17:14 -0700127 jint source, jint sampleRateInHertz, jint channels,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128 jint audioFormat, jint buffSizeInBytes)
129{
130 //LOGV(">> Entering android_media_AudioRecord_setup");
Eric Laurenta553c252009-07-17 12:17:14 -0700131 //LOGV("sampleRate=%d, audioFormat=%d, channels=%x, buffSizeInBytes=%d",
132 // sampleRateInHertz, audioFormat, channels, buffSizeInBytes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133
Eric Laurenta553c252009-07-17 12:17:14 -0700134 if (!AudioSystem::isInputChannel(channels)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 LOGE("Error creating AudioRecord: channel count is not 1 or 2.");
Eric Laurenta553c252009-07-17 12:17:14 -0700136 return AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 }
Eric Laurenta553c252009-07-17 12:17:14 -0700138 uint32_t nbChannels = AudioSystem::popCount(channels);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139
140 // compare the format against the Java constants
141 if ((audioFormat != javaAudioRecordFields.PCM16)
142 && (audioFormat != javaAudioRecordFields.PCM8)) {
143 LOGE("Error creating AudioRecord: unsupported audio format.");
144 return AUDIORECORD_ERROR_SETUP_INVALIDFORMAT;
145 }
146
147 int bytesPerSample = audioFormat==javaAudioRecordFields.PCM16 ? 2 : 1;
148 int format = audioFormat==javaAudioRecordFields.PCM16 ?
149 AudioSystem::PCM_16_BIT : AudioSystem::PCM_8_BIT;
150
151 if (buffSizeInBytes == 0) {
152 LOGE("Error creating AudioRecord: frameCount is 0.");
153 return AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT;
154 }
155 int frameSize = nbChannels * bytesPerSample;
156 size_t frameCount = buffSizeInBytes / frameSize;
157
Eric Laurenta553c252009-07-17 12:17:14 -0700158 if (source >= AUDIO_SOURCE_LIST_END) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159 LOGE("Error creating AudioRecord: unknown source.");
Eric Laurent4bc035a2009-05-22 09:18:15 -0700160 return AUDIORECORD_ERROR_SETUP_INVALIDSOURCE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161 }
Eric Laurent4bc035a2009-05-22 09:18:15 -0700162
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163 audiorecord_callback_cookie *lpCallbackData = NULL;
164 AudioRecord* lpRecorder = NULL;
165
166 // create an uninitialized AudioRecord object
167 lpRecorder = new AudioRecord();
168 if(lpRecorder == NULL) {
169 LOGE("Error creating AudioRecord instance.");
170 return AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
171 }
172
173 // create the callback information:
174 // this data will be passed with every AudioRecord callback
175 jclass clazz = env->GetObjectClass(thiz);
176 if (clazz == NULL) {
177 LOGE("Can't find %s when setting up callback.", kClassPathName);
178 goto native_track_failure;
179 }
180 lpCallbackData = new audiorecord_callback_cookie;
181 lpCallbackData->audioRecord_class = (jclass)env->NewGlobalRef(clazz);
182 // we use a weak reference so the AudioRecord object can be garbage collected.
183 lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
184
Eric Laurenta553c252009-07-17 12:17:14 -0700185 lpRecorder->set(source,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186 sampleRateInHertz,
187 format, // word length, PCM
Eric Laurenta553c252009-07-17 12:17:14 -0700188 channels,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189 frameCount,
190 0, // flags
191 recorderCallback,// callback_t
192 lpCallbackData,// void* user
193 0, // notificationFrames,
194 true); // threadCanCallJava)
195
196 if(lpRecorder->initCheck() != NO_ERROR) {
197 LOGE("Error creating AudioRecord instance: initialization check failed.");
198 goto native_init_failure;
199 }
200
201 // save our newly created C++ AudioRecord in the "nativeRecorderInJavaObj" field
202 // of the Java object
203 env->SetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj, (int)lpRecorder);
204
205 // save our newly created callback information in the "nativeCallbackCookie" field
206 // of the Java object (in mNativeCallbackCookie) so we can free the memory in finalize()
207 env->SetIntField(thiz, javaAudioRecordFields.nativeCallbackCookie, (int)lpCallbackData);
208
209 return AUDIORECORD_SUCCESS;
210
211 // failure:
212native_init_failure:
Jean-Michel Trivi4bac5a32009-07-17 12:05:31 -0700213 env->DeleteGlobalRef(lpCallbackData->audioRecord_class);
214 env->DeleteGlobalRef(lpCallbackData->audioRecord_ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215 delete lpCallbackData;
Jean-Michel Trivi4bac5a32009-07-17 12:05:31 -0700216
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217native_track_failure:
218 delete lpRecorder;
219
220 env->SetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj, 0);
221 env->SetIntField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0);
222
223 return AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
224}
225
226
227
228// ----------------------------------------------------------------------------
Eric Laurent9cc489a2009-12-05 05:20:01 -0800229static int
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230android_media_AudioRecord_start(JNIEnv *env, jobject thiz)
231{
232 AudioRecord *lpRecorder =
233 (AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
234 if (lpRecorder == NULL ) {
235 jniThrowException(env, "java/lang/IllegalStateException", NULL);
Eric Laurent9cc489a2009-12-05 05:20:01 -0800236 return AUDIORECORD_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 }
238
Eric Laurent9cc489a2009-12-05 05:20:01 -0800239 return android_media_translateRecorderErrorCode(lpRecorder->start());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240}
241
242
243// ----------------------------------------------------------------------------
244static void
245android_media_AudioRecord_stop(JNIEnv *env, jobject thiz)
246{
247 AudioRecord *lpRecorder =
248 (AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
249 if (lpRecorder == NULL ) {
250 jniThrowException(env, "java/lang/IllegalStateException", NULL);
251 return;
252 }
253
254 lpRecorder->stop();
255 //LOGV("Called lpRecorder->stop()");
256}
257
258
259// ----------------------------------------------------------------------------
Dave Sparkse6335c92010-03-13 17:08:22 -0800260static void android_media_AudioRecord_release(JNIEnv *env, jobject thiz) {
261
262 // serialize access. Ugly, but functional.
263 Mutex::Autolock lock(&sLock);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800264 AudioRecord *lpRecorder =
265 (AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
Dave Sparkse6335c92010-03-13 17:08:22 -0800266 audiorecord_callback_cookie *lpCookie = (audiorecord_callback_cookie *)env->GetIntField(
267 thiz, javaAudioRecordFields.nativeCallbackCookie);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800268
Dave Sparkse6335c92010-03-13 17:08:22 -0800269 // reset the native resources in the Java object so any attempt to access
270 // them after a call to release fails.
271 env->SetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj, 0);
272 env->SetIntField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0);
273
274 // delete the AudioRecord object
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 if (lpRecorder) {
276 LOGV("About to delete lpRecorder: %x\n", (int)lpRecorder);
277 lpRecorder->stop();
278 delete lpRecorder;
279 }
280
281 // delete the callback information
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800282 if (lpCookie) {
283 LOGV("deleting lpCookie: %x\n", (int)lpCookie);
Jean-Michel Trivi4bac5a32009-07-17 12:05:31 -0700284 env->DeleteGlobalRef(lpCookie->audioRecord_class);
285 env->DeleteGlobalRef(lpCookie->audioRecord_ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286 delete lpCookie;
287 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800288}
289
290
291// ----------------------------------------------------------------------------
Dave Sparkse6335c92010-03-13 17:08:22 -0800292static void android_media_AudioRecord_finalize(JNIEnv *env, jobject thiz) {
293 android_media_AudioRecord_release(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294}
295
296
297// ----------------------------------------------------------------------------
298static jint android_media_AudioRecord_readInByteArray(JNIEnv *env, jobject thiz,
299 jbyteArray javaAudioData,
300 jint offsetInBytes, jint sizeInBytes) {
301 jbyte* recordBuff = NULL;
302 AudioRecord *lpRecorder = NULL;
303
304 // get the audio recorder from which we'll read new audio samples
305 lpRecorder =
306 (AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
307 if (lpRecorder == NULL) {
308 LOGE("Unable to retrieve AudioRecord object, can't record");
309 return 0;
310 }
311
312 if (!javaAudioData) {
313 LOGE("Invalid Java array to store recorded audio, can't record");
314 return 0;
315 }
316
317 // get the pointer to where we'll record the audio
318 recordBuff = (jbyte *)env->GetPrimitiveArrayCritical(javaAudioData, NULL);
319
320 if (recordBuff == NULL) {
321 LOGE("Error retrieving destination for recorded audio data, can't record");
322 return 0;
323 }
324
325 // read the new audio data from the native AudioRecord object
326 ssize_t recorderBuffSize = lpRecorder->frameCount()*lpRecorder->frameSize();
327 ssize_t readSize = lpRecorder->read(recordBuff + offsetInBytes,
328 sizeInBytes > (jint)recorderBuffSize ?
329 (jint)recorderBuffSize : sizeInBytes );
330 env->ReleasePrimitiveArrayCritical(javaAudioData, recordBuff, 0);
331
332 return (jint) readSize;
333}
334
335// ----------------------------------------------------------------------------
336static jint android_media_AudioRecord_readInShortArray(JNIEnv *env, jobject thiz,
337 jshortArray javaAudioData,
338 jint offsetInShorts, jint sizeInShorts) {
339
340 return (android_media_AudioRecord_readInByteArray(env, thiz,
341 (jbyteArray) javaAudioData,
342 offsetInShorts*2, sizeInShorts*2)
343 / 2);
344}
345
346// ----------------------------------------------------------------------------
347static jint android_media_AudioRecord_readInDirectBuffer(JNIEnv *env, jobject thiz,
348 jobject jBuffer, jint sizeInBytes) {
349 AudioRecord *lpRecorder = NULL;
350 //LOGV("Entering android_media_AudioRecord_readInBuffer");
351
352 // get the audio recorder from which we'll read new audio samples
353 lpRecorder =
354 (AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
355 if(lpRecorder==NULL)
356 return 0;
357
358 // direct buffer and direct access supported?
359 long capacity = env->GetDirectBufferCapacity(jBuffer);
360 if(capacity == -1) {
361 // buffer direct access is not supported
362 LOGE("Buffer direct access is not supported, can't record");
363 return 0;
364 }
365 //LOGV("capacity = %ld", capacity);
366 jbyte* nativeFromJavaBuf = (jbyte*) env->GetDirectBufferAddress(jBuffer);
367 if(nativeFromJavaBuf==NULL) {
368 LOGE("Buffer direct access is not supported, can't record");
369 return 0;
370 }
371
372 // read new data from the recorder
373 return (jint) lpRecorder->read(nativeFromJavaBuf,
374 capacity < sizeInBytes ? capacity : sizeInBytes);
375}
376
377
378// ----------------------------------------------------------------------------
379static jint android_media_AudioRecord_set_marker_pos(JNIEnv *env, jobject thiz,
380 jint markerPos) {
381
382 AudioRecord *lpRecorder = (AudioRecord *)env->GetIntField(
383 thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
384
385 if (lpRecorder) {
386 return
387 android_media_translateRecorderErrorCode( lpRecorder->setMarkerPosition(markerPos) );
388 } else {
389 jniThrowException(env, "java/lang/IllegalStateException",
390 "Unable to retrieve AudioRecord pointer for setMarkerPosition()");
391 return AUDIORECORD_ERROR;
392 }
393}
394
395
396// ----------------------------------------------------------------------------
397static jint android_media_AudioRecord_get_marker_pos(JNIEnv *env, jobject thiz) {
398
399 AudioRecord *lpRecorder = (AudioRecord *)env->GetIntField(
400 thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
401 uint32_t markerPos = 0;
402
403 if (lpRecorder) {
404 lpRecorder->getMarkerPosition(&markerPos);
405 return (jint)markerPos;
406 } else {
407 jniThrowException(env, "java/lang/IllegalStateException",
408 "Unable to retrieve AudioRecord pointer for getMarkerPosition()");
409 return AUDIORECORD_ERROR;
410 }
411}
412
413
414// ----------------------------------------------------------------------------
415static jint android_media_AudioRecord_set_pos_update_period(JNIEnv *env, jobject thiz,
416 jint period) {
417
418 AudioRecord *lpRecorder = (AudioRecord *)env->GetIntField(
419 thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
420
421 if (lpRecorder) {
422 return
423 android_media_translateRecorderErrorCode( lpRecorder->setPositionUpdatePeriod(period) );
424 } else {
425 jniThrowException(env, "java/lang/IllegalStateException",
426 "Unable to retrieve AudioRecord pointer for setPositionUpdatePeriod()");
427 return AUDIORECORD_ERROR;
428 }
429}
430
431
432// ----------------------------------------------------------------------------
433static jint android_media_AudioRecord_get_pos_update_period(JNIEnv *env, jobject thiz) {
434
435 AudioRecord *lpRecorder = (AudioRecord *)env->GetIntField(
436 thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
437 uint32_t period = 0;
438
439 if (lpRecorder) {
440 lpRecorder->getPositionUpdatePeriod(&period);
441 return (jint)period;
442 } else {
443 jniThrowException(env, "java/lang/IllegalStateException",
444 "Unable to retrieve AudioRecord pointer for getPositionUpdatePeriod()");
445 return AUDIORECORD_ERROR;
446 }
447}
448
449
450// ----------------------------------------------------------------------------
451// returns the minimum required size for the successful creation of an AudioRecord instance.
452// returns 0 if the parameter combination is not supported.
453// return -1 if there was an error querying the buffer size.
454static jint android_media_AudioRecord_get_min_buff_size(JNIEnv *env, jobject thiz,
455 jint sampleRateInHertz, jint nbChannels, jint audioFormat) {
Chia-chi Yehc3308072010-08-19 17:14:36 +0800456
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457 LOGV(">> android_media_AudioRecord_get_min_buff_size(%d, %d, %d)", sampleRateInHertz, nbChannels, audioFormat);
Chia-chi Yehc3308072010-08-19 17:14:36 +0800458
459 int frameCount = 0;
460 status_t result = AudioRecord::getMinFrameCount(&frameCount,
461 sampleRateInHertz,
462 (audioFormat == javaAudioRecordFields.PCM16 ?
463 AudioSystem::PCM_16_BIT : AudioSystem::PCM_8_BIT),
464 nbChannels);
465
466 if (result == BAD_VALUE) {
467 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468 }
Chia-chi Yehc3308072010-08-19 17:14:36 +0800469 if (result != NO_ERROR) {
470 return -1;
471 }
472 return frameCount * nbChannels * (audioFormat == javaAudioRecordFields.PCM16 ? 2 : 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800473}
474
475
476// ----------------------------------------------------------------------------
477// ----------------------------------------------------------------------------
478static JNINativeMethod gMethods[] = {
479 // name, signature, funcPtr
Eric Laurent9cc489a2009-12-05 05:20:01 -0800480 {"native_start", "()I", (void *)android_media_AudioRecord_start},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800481 {"native_stop", "()V", (void *)android_media_AudioRecord_stop},
482 {"native_setup", "(Ljava/lang/Object;IIIII)I",
483 (void *)android_media_AudioRecord_setup},
484 {"native_finalize", "()V", (void *)android_media_AudioRecord_finalize},
485 {"native_release", "()V", (void *)android_media_AudioRecord_release},
486 {"native_read_in_byte_array",
487 "([BII)I", (void *)android_media_AudioRecord_readInByteArray},
488 {"native_read_in_short_array",
489 "([SII)I", (void *)android_media_AudioRecord_readInShortArray},
490 {"native_read_in_direct_buffer","(Ljava/lang/Object;I)I",
491 (void *)android_media_AudioRecord_readInDirectBuffer},
492 {"native_set_marker_pos","(I)I", (void *)android_media_AudioRecord_set_marker_pos},
493 {"native_get_marker_pos","()I", (void *)android_media_AudioRecord_get_marker_pos},
494 {"native_set_pos_update_period",
495 "(I)I", (void *)android_media_AudioRecord_set_pos_update_period},
496 {"native_get_pos_update_period",
497 "()I", (void *)android_media_AudioRecord_get_pos_update_period},
498 {"native_get_min_buff_size",
499 "(III)I", (void *)android_media_AudioRecord_get_min_buff_size},
500};
501
502// field names found in android/media/AudioRecord.java
503#define JAVA_POSTEVENT_CALLBACK_NAME "postEventFromNative"
504#define JAVA_CONST_PCM16_NAME "ENCODING_PCM_16BIT"
505#define JAVA_CONST_PCM8_NAME "ENCODING_PCM_8BIT"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800506#define JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME "mNativeRecorderInJavaObj"
507#define JAVA_NATIVECALLBACKINFO_FIELD_NAME "mNativeCallbackCookie"
508
509#define JAVA_AUDIOFORMAT_CLASS_NAME "android/media/AudioFormat"
510
511// ----------------------------------------------------------------------------
512
513extern bool android_media_getIntConstantFromClass(JNIEnv* pEnv,
514 jclass theClass, const char* className, const char* constName, int* constVal);
515
516// ----------------------------------------------------------------------------
517int register_android_media_AudioRecord(JNIEnv *env)
518{
519 javaAudioRecordFields.audioRecordClass = NULL;
520 javaAudioRecordFields.postNativeEventInJava = NULL;
521 javaAudioRecordFields.nativeRecorderInJavaObj = NULL;
522 javaAudioRecordFields.nativeCallbackCookie = NULL;
523
524
525 // Get the AudioRecord class
526 javaAudioRecordFields.audioRecordClass = env->FindClass(kClassPathName);
527 if (javaAudioRecordFields.audioRecordClass == NULL) {
528 LOGE("Can't find %s", kClassPathName);
529 return -1;
530 }
531
532 // Get the postEvent method
533 javaAudioRecordFields.postNativeEventInJava = env->GetStaticMethodID(
534 javaAudioRecordFields.audioRecordClass,
535 JAVA_POSTEVENT_CALLBACK_NAME, "(Ljava/lang/Object;IIILjava/lang/Object;)V");
536 if (javaAudioRecordFields.postNativeEventInJava == NULL) {
537 LOGE("Can't find AudioRecord.%s", JAVA_POSTEVENT_CALLBACK_NAME);
538 return -1;
539 }
540
541 // Get the variables
542 // mNativeRecorderInJavaObj
543 javaAudioRecordFields.nativeRecorderInJavaObj =
544 env->GetFieldID(javaAudioRecordFields.audioRecordClass,
545 JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME, "I");
546 if (javaAudioRecordFields.nativeRecorderInJavaObj == NULL) {
547 LOGE("Can't find AudioRecord.%s", JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME);
548 return -1;
549 }
550 // mNativeCallbackCookie
551 javaAudioRecordFields.nativeCallbackCookie = env->GetFieldID(
552 javaAudioRecordFields.audioRecordClass,
553 JAVA_NATIVECALLBACKINFO_FIELD_NAME, "I");
554 if (javaAudioRecordFields.nativeCallbackCookie == NULL) {
555 LOGE("Can't find AudioRecord.%s", JAVA_NATIVECALLBACKINFO_FIELD_NAME);
556 return -1;
557 }
558
559 // Get the format constants from the AudioFormat class
560 jclass audioFormatClass = NULL;
561 audioFormatClass = env->FindClass(JAVA_AUDIOFORMAT_CLASS_NAME);
562 if (audioFormatClass == NULL) {
563 LOGE("Can't find %s", JAVA_AUDIOFORMAT_CLASS_NAME);
564 return -1;
565 }
566 if ( !android_media_getIntConstantFromClass(env, audioFormatClass,
567 JAVA_AUDIOFORMAT_CLASS_NAME,
568 JAVA_CONST_PCM16_NAME, &(javaAudioRecordFields.PCM16))
569 || !android_media_getIntConstantFromClass(env, audioFormatClass,
570 JAVA_AUDIOFORMAT_CLASS_NAME,
571 JAVA_CONST_PCM8_NAME, &(javaAudioRecordFields.PCM8)) ) {
572 // error log performed in getIntConstantFromClass()
573 return -1;
574 }
575
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800576 return AndroidRuntime::registerNativeMethods(env,
577 kClassPathName, gMethods, NELEM(gMethods));
578}
579
580// ----------------------------------------------------------------------------