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 <inttypes.h>
22 #include <jni.h>
23 #include <nativehelper/JNIHelp.h>
24 #include "core_jni_helpers.h"
25 
26 #include <utils/Log.h>
27 #include <media/AudioRecord.h>
28 #include <media/MicrophoneInfo.h>
29 #include <vector>
30 
31 #include <nativehelper/ScopedUtfChars.h>
32 
33 #include "android_media_AudioFormat.h"
34 #include "android_media_AudioErrors.h"
35 #include "android_media_DeviceCallback.h"
36 #include "android_media_MediaMetricsJNI.h"
37 #include "android_media_MicrophoneInfo.h"
38 
39 // ----------------------------------------------------------------------------
40 
41 using namespace android;
42 
43 // ----------------------------------------------------------------------------
44 static const char* const kClassPathName = "android/media/AudioRecord";
45 static const char* const kAudioAttributesClassPathName = "android/media/AudioAttributes";
46 
47 static jclass gArrayListClass;
48 static struct {
49     jmethodID add;
50 } gArrayListMethods;
51 
52 struct audio_record_fields_t {
53     // these fields provide access from C++ to the...
54     jmethodID postNativeEventInJava; //... event post callback method
55     jfieldID  nativeRecorderInJavaObj; // provides access to the C++ AudioRecord object
56     jfieldID  nativeCallbackCookie;    // provides access to the AudioRecord callback data
57     jfieldID  nativeDeviceCallback;    // provides access to the JNIDeviceCallback instance
58 };
59 struct audio_attributes_fields_t {
60     jfieldID  fieldRecSource;    // AudioAttributes.mSource
61     jfieldID  fieldFlags;        // AudioAttributes.mFlags
62     jfieldID  fieldFormattedTags;// AudioAttributes.mFormattedTags
63 };
64 static audio_attributes_fields_t javaAudioAttrFields;
65 static audio_record_fields_t     javaAudioRecordFields;
66 static struct {
67     jfieldID  fieldFramePosition;     // AudioTimestamp.framePosition
68     jfieldID  fieldNanoTime;          // AudioTimestamp.nanoTime
69 } javaAudioTimestampFields;
70 
71 struct audiorecord_callback_cookie {
72     jclass      audioRecord_class;
73     jobject     audioRecord_ref;
74     bool        busy;
75     Condition   cond;
76 };
77 
78 static Mutex sLock;
79 static SortedVector <audiorecord_callback_cookie *> sAudioRecordCallBackCookies;
80 
81 // ----------------------------------------------------------------------------
82 
83 #define AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT      (-16)
84 #define AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK  (-17)
85 #define AUDIORECORD_ERROR_SETUP_INVALIDFORMAT       (-18)
86 #define AUDIORECORD_ERROR_SETUP_INVALIDSOURCE       (-19)
87 #define AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED    (-20)
88 
89 // ----------------------------------------------------------------------------
recorderCallback(int event,void * user,void * info)90 static void recorderCallback(int event, void* user, void *info) {
91 
92     audiorecord_callback_cookie *callbackInfo = (audiorecord_callback_cookie *)user;
93     {
94         Mutex::Autolock l(sLock);
95         if (sAudioRecordCallBackCookies.indexOf(callbackInfo) < 0) {
96             return;
97         }
98         callbackInfo->busy = true;
99     }
100 
101     switch (event) {
102     case AudioRecord::EVENT_MARKER: {
103         JNIEnv *env = AndroidRuntime::getJNIEnv();
104         if (user != NULL && env != NULL) {
105             env->CallStaticVoidMethod(
106                 callbackInfo->audioRecord_class,
107                 javaAudioRecordFields.postNativeEventInJava,
108                 callbackInfo->audioRecord_ref, event, 0,0, NULL);
109             if (env->ExceptionCheck()) {
110                 env->ExceptionDescribe();
111                 env->ExceptionClear();
112             }
113         }
114         } break;
115 
116     case AudioRecord::EVENT_NEW_POS: {
117         JNIEnv *env = AndroidRuntime::getJNIEnv();
118         if (user != NULL && env != NULL) {
119             env->CallStaticVoidMethod(
120                 callbackInfo->audioRecord_class,
121                 javaAudioRecordFields.postNativeEventInJava,
122                 callbackInfo->audioRecord_ref, event, 0,0, NULL);
123             if (env->ExceptionCheck()) {
124                 env->ExceptionDescribe();
125                 env->ExceptionClear();
126             }
127         }
128         } break;
129     }
130 
131     {
132         Mutex::Autolock l(sLock);
133         callbackInfo->busy = false;
134         callbackInfo->cond.broadcast();
135     }
136 }
137 
getJniDeviceCallback(JNIEnv * env,jobject thiz)138 static sp<JNIDeviceCallback> getJniDeviceCallback(JNIEnv* env, jobject thiz)
139 {
140     Mutex::Autolock l(sLock);
141     JNIDeviceCallback* const cb =
142             (JNIDeviceCallback*)env->GetLongField(thiz,
143                                                   javaAudioRecordFields.nativeDeviceCallback);
144     return sp<JNIDeviceCallback>(cb);
145 }
146 
setJniDeviceCallback(JNIEnv * env,jobject thiz,const sp<JNIDeviceCallback> & cb)147 static sp<JNIDeviceCallback> setJniDeviceCallback(JNIEnv* env,
148                                                   jobject thiz,
149                                                   const sp<JNIDeviceCallback>& cb)
150 {
151     Mutex::Autolock l(sLock);
152     sp<JNIDeviceCallback> old =
153             (JNIDeviceCallback*)env->GetLongField(thiz,
154                                                   javaAudioRecordFields.nativeDeviceCallback);
155     if (cb.get()) {
156         cb->incStrong((void*)setJniDeviceCallback);
157     }
158     if (old != 0) {
159         old->decStrong((void*)setJniDeviceCallback);
160     }
161     env->SetLongField(thiz, javaAudioRecordFields.nativeDeviceCallback, (jlong)cb.get());
162     return old;
163 }
164 
165 // ----------------------------------------------------------------------------
getAudioRecord(JNIEnv * env,jobject thiz)166 static sp<AudioRecord> getAudioRecord(JNIEnv* env, jobject thiz)
167 {
168     Mutex::Autolock l(sLock);
169     AudioRecord* const ar =
170             (AudioRecord*)env->GetLongField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
171     return sp<AudioRecord>(ar);
172 }
173 
setAudioRecord(JNIEnv * env,jobject thiz,const sp<AudioRecord> & ar)174 static sp<AudioRecord> setAudioRecord(JNIEnv* env, jobject thiz, const sp<AudioRecord>& ar)
175 {
176     Mutex::Autolock l(sLock);
177     sp<AudioRecord> old =
178             (AudioRecord*)env->GetLongField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
179     if (ar.get()) {
180         ar->incStrong((void*)setAudioRecord);
181     }
182     if (old != 0) {
183         old->decStrong((void*)setAudioRecord);
184     }
185     env->SetLongField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj, (jlong)ar.get());
186     return old;
187 }
188 
189 // ----------------------------------------------------------------------------
190 static jint
android_media_AudioRecord_setup(JNIEnv * env,jobject thiz,jobject weak_this,jobject jaa,jintArray jSampleRate,jint channelMask,jint channelIndexMask,jint audioFormat,jint buffSizeInBytes,jintArray jSession,jstring opPackageName,jlong nativeRecordInJavaObj)191 android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
192         jobject jaa, jintArray jSampleRate, jint channelMask, jint channelIndexMask,
193         jint audioFormat, jint buffSizeInBytes, jintArray jSession, jstring opPackageName,
194         jlong nativeRecordInJavaObj)
195 {
196     //ALOGV(">> Entering android_media_AudioRecord_setup");
197     //ALOGV("sampleRate=%d, audioFormat=%d, channel mask=%x, buffSizeInBytes=%d "
198     //     "nativeRecordInJavaObj=0x%llX",
199     //     sampleRateInHertz, audioFormat, channelMask, buffSizeInBytes, nativeRecordInJavaObj);
200     audio_channel_mask_t localChanMask = inChannelMaskToNative(channelMask);
201 
202     if (jSession == NULL) {
203         ALOGE("Error creating AudioRecord: invalid session ID pointer");
204         return (jint) AUDIO_JAVA_ERROR;
205     }
206 
207     jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
208     if (nSession == NULL) {
209         ALOGE("Error creating AudioRecord: Error retrieving session id pointer");
210         return (jint) AUDIO_JAVA_ERROR;
211     }
212     audio_session_t sessionId = (audio_session_t) nSession[0];
213     env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
214     nSession = NULL;
215 
216     audio_attributes_t *paa = NULL;
217     sp<AudioRecord> lpRecorder = 0;
218     audiorecord_callback_cookie *lpCallbackData = NULL;
219 
220     jclass clazz = env->GetObjectClass(thiz);
221     if (clazz == NULL) {
222         ALOGE("Can't find %s when setting up callback.", kClassPathName);
223         return (jint) AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
224     }
225 
226     // if we pass in an existing *Native* AudioRecord, we don't need to create/initialize one.
227     if (nativeRecordInJavaObj == 0) {
228         if (jaa == 0) {
229             ALOGE("Error creating AudioRecord: invalid audio attributes");
230             return (jint) AUDIO_JAVA_ERROR;
231         }
232 
233         if (jSampleRate == 0) {
234             ALOGE("Error creating AudioRecord: invalid sample rates");
235             return (jint) AUDIO_JAVA_ERROR;
236         }
237         jint elements[1];
238         env->GetIntArrayRegion(jSampleRate, 0, 1, elements);
239         int sampleRateInHertz = elements[0];
240 
241         // channel index mask takes priority over channel position masks.
242         if (channelIndexMask) {
243             // Java channel index masks need the representation bits set.
244             localChanMask = audio_channel_mask_from_representation_and_bits(
245                     AUDIO_CHANNEL_REPRESENTATION_INDEX,
246                     channelIndexMask);
247         }
248         // Java channel position masks map directly to the native definition
249 
250         if (!audio_is_input_channel(localChanMask)) {
251             ALOGE("Error creating AudioRecord: channel mask %#x is not valid.", localChanMask);
252             return (jint) AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK;
253         }
254         uint32_t channelCount = audio_channel_count_from_in_mask(localChanMask);
255 
256         // compare the format against the Java constants
257         audio_format_t format = audioFormatToNative(audioFormat);
258         if (format == AUDIO_FORMAT_INVALID) {
259             ALOGE("Error creating AudioRecord: unsupported audio format %d.", audioFormat);
260             return (jint) AUDIORECORD_ERROR_SETUP_INVALIDFORMAT;
261         }
262 
263         size_t bytesPerSample = audio_bytes_per_sample(format);
264 
265         if (buffSizeInBytes == 0) {
266              ALOGE("Error creating AudioRecord: frameCount is 0.");
267             return (jint) AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT;
268         }
269         size_t frameSize = channelCount * bytesPerSample;
270         size_t frameCount = buffSizeInBytes / frameSize;
271 
272         ScopedUtfChars opPackageNameStr(env, opPackageName);
273 
274         // create an uninitialized AudioRecord object
275         lpRecorder = new AudioRecord(String16(opPackageNameStr.c_str()));
276 
277         // read the AudioAttributes values
278         paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
279         const jstring jtags =
280                 (jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags);
281         const char* tags = env->GetStringUTFChars(jtags, NULL);
282         // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it
283         strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
284         env->ReleaseStringUTFChars(jtags, tags);
285         paa->source = (audio_source_t) env->GetIntField(jaa, javaAudioAttrFields.fieldRecSource);
286         paa->flags = (audio_flags_mask_t)env->GetIntField(jaa, javaAudioAttrFields.fieldFlags);
287         ALOGV("AudioRecord_setup for source=%d tags=%s flags=%08x", paa->source, paa->tags, paa->flags);
288 
289         audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE;
290         if (paa->flags & AUDIO_FLAG_HW_HOTWORD) {
291             flags = AUDIO_INPUT_FLAG_HW_HOTWORD;
292         }
293         // create the callback information:
294         // this data will be passed with every AudioRecord callback
295         lpCallbackData = new audiorecord_callback_cookie;
296         lpCallbackData->audioRecord_class = (jclass)env->NewGlobalRef(clazz);
297         // we use a weak reference so the AudioRecord object can be garbage collected.
298         lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
299         lpCallbackData->busy = false;
300 
301         const status_t status = lpRecorder->set(paa->source,
302             sampleRateInHertz,
303             format,        // word length, PCM
304             localChanMask,
305             frameCount,
306             recorderCallback,// callback_t
307             lpCallbackData,// void* user
308             0,             // notificationFrames,
309             true,          // threadCanCallJava
310             sessionId,
311             AudioRecord::TRANSFER_DEFAULT,
312             flags,
313             -1, -1,        // default uid, pid
314             paa);
315 
316         if (status != NO_ERROR) {
317             ALOGE("Error creating AudioRecord instance: initialization check failed with status %d.",
318                     status);
319             goto native_init_failure;
320         }
321     } else { // end if nativeRecordInJavaObj == 0)
322         lpRecorder = (AudioRecord*)nativeRecordInJavaObj;
323         // TODO: We need to find out which members of the Java AudioRecord might need to be
324         // initialized from the Native AudioRecord
325         // these are directly returned from getters:
326         //  mSampleRate
327         //  mRecordSource
328         //  mAudioFormat
329         //  mChannelMask
330         //  mChannelCount
331         //  mState (?)
332         //  mRecordingState (?)
333         //  mPreferredDevice
334 
335         // create the callback information:
336         // this data will be passed with every AudioRecord callback
337         lpCallbackData = new audiorecord_callback_cookie;
338         lpCallbackData->audioRecord_class = (jclass)env->NewGlobalRef(clazz);
339         // we use a weak reference so the AudioRecord object can be garbage collected.
340         lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
341         lpCallbackData->busy = false;
342     }
343 
344     nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
345     if (nSession == NULL) {
346         ALOGE("Error creating AudioRecord: Error retrieving session id pointer");
347         goto native_init_failure;
348     }
349     // read the audio session ID back from AudioRecord in case a new session was created during set()
350     nSession[0] = lpRecorder->getSessionId();
351     env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
352     nSession = NULL;
353 
354     {
355         const jint elements[1] = { (jint) lpRecorder->getSampleRate() };
356         env->SetIntArrayRegion(jSampleRate, 0, 1, elements);
357     }
358 
359     {   // scope for the lock
360         Mutex::Autolock l(sLock);
361         sAudioRecordCallBackCookies.add(lpCallbackData);
362     }
363     // save our newly created C++ AudioRecord in the "nativeRecorderInJavaObj" field
364     // of the Java object
365     setAudioRecord(env, thiz, lpRecorder);
366 
367     // save our newly created callback information in the "nativeCallbackCookie" field
368     // of the Java object (in mNativeCallbackCookie) so we can free the memory in finalize()
369     env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, (jlong)lpCallbackData);
370 
371     if (paa != NULL) {
372         // audio attributes were copied in AudioRecord creation
373         free(paa);
374         paa = NULL;
375     }
376 
377     return (jint) AUDIO_JAVA_SUCCESS;
378 
379     // failure:
380 native_init_failure:
381     if (paa != NULL) {
382         free(paa);
383     }
384     env->DeleteGlobalRef(lpCallbackData->audioRecord_class);
385     env->DeleteGlobalRef(lpCallbackData->audioRecord_ref);
386     delete lpCallbackData;
387     env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0);
388 
389     // lpRecorder goes out of scope, so reference count drops to zero
390     return (jint) AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
391 }
392 
393 
394 
395 // ----------------------------------------------------------------------------
396 static jint
android_media_AudioRecord_start(JNIEnv * env,jobject thiz,jint event,jint triggerSession)397 android_media_AudioRecord_start(JNIEnv *env, jobject thiz, jint event, jint triggerSession)
398 {
399     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
400     if (lpRecorder == NULL ) {
401         jniThrowException(env, "java/lang/IllegalStateException", NULL);
402         return (jint) AUDIO_JAVA_ERROR;
403     }
404 
405     return nativeToJavaStatus(
406             lpRecorder->start((AudioSystem::sync_event_t)event, (audio_session_t) triggerSession));
407 }
408 
409 
410 // ----------------------------------------------------------------------------
411 static void
android_media_AudioRecord_stop(JNIEnv * env,jobject thiz)412 android_media_AudioRecord_stop(JNIEnv *env, jobject thiz)
413 {
414     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
415     if (lpRecorder == NULL ) {
416         jniThrowException(env, "java/lang/IllegalStateException", NULL);
417         return;
418     }
419 
420     lpRecorder->stop();
421     //ALOGV("Called lpRecorder->stop()");
422 }
423 
424 
425 // ----------------------------------------------------------------------------
426 
427 #define CALLBACK_COND_WAIT_TIMEOUT_MS 1000
android_media_AudioRecord_release(JNIEnv * env,jobject thiz)428 static void android_media_AudioRecord_release(JNIEnv *env,  jobject thiz) {
429     sp<AudioRecord> lpRecorder = setAudioRecord(env, thiz, 0);
430     if (lpRecorder == NULL) {
431         return;
432     }
433     ALOGV("About to delete lpRecorder: %p", lpRecorder.get());
434     lpRecorder->stop();
435 
436     audiorecord_callback_cookie *lpCookie = (audiorecord_callback_cookie *)env->GetLongField(
437         thiz, javaAudioRecordFields.nativeCallbackCookie);
438 
439     // reset the native resources in the Java object so any attempt to access
440     // them after a call to release fails.
441     env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0);
442 
443     // delete the callback information
444     if (lpCookie) {
445         Mutex::Autolock l(sLock);
446         ALOGV("deleting lpCookie: %p", lpCookie);
447         while (lpCookie->busy) {
448             if (lpCookie->cond.waitRelative(sLock,
449                                             milliseconds(CALLBACK_COND_WAIT_TIMEOUT_MS)) !=
450                                                     NO_ERROR) {
451                 break;
452             }
453         }
454         sAudioRecordCallBackCookies.remove(lpCookie);
455         env->DeleteGlobalRef(lpCookie->audioRecord_class);
456         env->DeleteGlobalRef(lpCookie->audioRecord_ref);
457         delete lpCookie;
458     }
459 }
460 
461 
462 // ----------------------------------------------------------------------------
android_media_AudioRecord_finalize(JNIEnv * env,jobject thiz)463 static void android_media_AudioRecord_finalize(JNIEnv *env,  jobject thiz) {
464     android_media_AudioRecord_release(env, thiz);
465 }
466 
467 // overloaded JNI array helper functions
468 static inline
envGetArrayElements(JNIEnv * env,jbyteArray array,jboolean * isCopy)469 jbyte *envGetArrayElements(JNIEnv *env, jbyteArray array, jboolean *isCopy) {
470     return env->GetByteArrayElements(array, isCopy);
471 }
472 
473 static inline
envReleaseArrayElements(JNIEnv * env,jbyteArray array,jbyte * elems,jint mode)474 void envReleaseArrayElements(JNIEnv *env, jbyteArray array, jbyte *elems, jint mode) {
475     env->ReleaseByteArrayElements(array, elems, mode);
476 }
477 
478 static inline
envGetArrayElements(JNIEnv * env,jshortArray array,jboolean * isCopy)479 jshort *envGetArrayElements(JNIEnv *env, jshortArray array, jboolean *isCopy) {
480     return env->GetShortArrayElements(array, isCopy);
481 }
482 
483 static inline
envReleaseArrayElements(JNIEnv * env,jshortArray array,jshort * elems,jint mode)484 void envReleaseArrayElements(JNIEnv *env, jshortArray array, jshort *elems, jint mode) {
485     env->ReleaseShortArrayElements(array, elems, mode);
486 }
487 
488 static inline
envGetArrayElements(JNIEnv * env,jfloatArray array,jboolean * isCopy)489 jfloat *envGetArrayElements(JNIEnv *env, jfloatArray array, jboolean *isCopy) {
490     return env->GetFloatArrayElements(array, isCopy);
491 }
492 
493 static inline
envReleaseArrayElements(JNIEnv * env,jfloatArray array,jfloat * elems,jint mode)494 void envReleaseArrayElements(JNIEnv *env, jfloatArray array, jfloat *elems, jint mode) {
495     env->ReleaseFloatArrayElements(array, elems, mode);
496 }
497 
498 static inline
interpretReadSizeError(ssize_t readSize)499 jint interpretReadSizeError(ssize_t readSize) {
500     if (readSize == WOULD_BLOCK) {
501         return (jint)0;
502     } else if (readSize == NO_INIT) {
503         return AUDIO_JAVA_DEAD_OBJECT;
504     } else {
505         ALOGE("Error %zd during AudioRecord native read", readSize);
506         return nativeToJavaStatus(readSize);
507     }
508 }
509 
510 template <typename T>
android_media_AudioRecord_readInArray(JNIEnv * env,jobject thiz,T javaAudioData,jint offsetInSamples,jint sizeInSamples,jboolean isReadBlocking)511 static jint android_media_AudioRecord_readInArray(JNIEnv *env,  jobject thiz,
512                                                   T javaAudioData,
513                                                   jint offsetInSamples, jint sizeInSamples,
514                                                   jboolean isReadBlocking) {
515     // get the audio recorder from which we'll read new audio samples
516     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
517     if (lpRecorder == NULL) {
518         ALOGE("Unable to retrieve AudioRecord object");
519         return (jint)AUDIO_JAVA_INVALID_OPERATION;
520     }
521 
522     if (javaAudioData == NULL) {
523         ALOGE("Invalid Java array to store recorded audio");
524         return (jint)AUDIO_JAVA_BAD_VALUE;
525     }
526 
527     // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
528     // a way that it becomes much more efficient. When doing so, we will have to prevent the
529     // AudioSystem callback to be called while in critical section (in case of media server
530     // process crash for instance)
531 
532     // get the pointer to where we'll record the audio
533     auto *recordBuff = envGetArrayElements(env, javaAudioData, NULL);
534     if (recordBuff == NULL) {
535         ALOGE("Error retrieving destination for recorded audio data");
536         return (jint)AUDIO_JAVA_BAD_VALUE;
537     }
538 
539     // read the new audio data from the native AudioRecord object
540     const size_t sizeInBytes = sizeInSamples * sizeof(*recordBuff);
541     ssize_t readSize = lpRecorder->read(
542             recordBuff + offsetInSamples, sizeInBytes, isReadBlocking == JNI_TRUE /* blocking */);
543 
544     envReleaseArrayElements(env, javaAudioData, recordBuff, 0);
545 
546     if (readSize < 0) {
547         return interpretReadSizeError(readSize);
548     }
549     return (jint)(readSize / sizeof(*recordBuff));
550 }
551 
552 // ----------------------------------------------------------------------------
android_media_AudioRecord_readInDirectBuffer(JNIEnv * env,jobject thiz,jobject jBuffer,jint sizeInBytes,jboolean isReadBlocking)553 static jint android_media_AudioRecord_readInDirectBuffer(JNIEnv *env,  jobject thiz,
554                                                          jobject jBuffer, jint sizeInBytes,
555                                                          jboolean isReadBlocking) {
556     // get the audio recorder from which we'll read new audio samples
557     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
558     if (lpRecorder==NULL)
559         return (jint)AUDIO_JAVA_INVALID_OPERATION;
560 
561     // direct buffer and direct access supported?
562     long capacity = env->GetDirectBufferCapacity(jBuffer);
563     if (capacity == -1) {
564         // buffer direct access is not supported
565         ALOGE("Buffer direct access is not supported, can't record");
566         return (jint)AUDIO_JAVA_BAD_VALUE;
567     }
568     //ALOGV("capacity = %ld", capacity);
569     jbyte* nativeFromJavaBuf = (jbyte*) env->GetDirectBufferAddress(jBuffer);
570     if (nativeFromJavaBuf==NULL) {
571         ALOGE("Buffer direct access is not supported, can't record");
572         return (jint)AUDIO_JAVA_BAD_VALUE;
573     }
574 
575     // read new data from the recorder
576     ssize_t readSize = lpRecorder->read(nativeFromJavaBuf,
577                                         capacity < sizeInBytes ? capacity : sizeInBytes,
578                                         isReadBlocking == JNI_TRUE /* blocking */);
579     if (readSize < 0) {
580         return interpretReadSizeError(readSize);
581     }
582     return (jint)readSize;
583 }
584 
585 // ----------------------------------------------------------------------------
android_media_AudioRecord_get_buffer_size_in_frames(JNIEnv * env,jobject thiz)586 static jint android_media_AudioRecord_get_buffer_size_in_frames(JNIEnv *env,  jobject thiz) {
587     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
588     if (lpRecorder == NULL) {
589         jniThrowException(env, "java/lang/IllegalStateException",
590             "Unable to retrieve AudioRecord pointer for frameCount()");
591         return (jint)AUDIO_JAVA_ERROR;
592     }
593     return lpRecorder->frameCount();
594 }
595 
596 // ----------------------------------------------------------------------------
android_media_AudioRecord_set_marker_pos(JNIEnv * env,jobject thiz,jint markerPos)597 static jint android_media_AudioRecord_set_marker_pos(JNIEnv *env,  jobject thiz,
598         jint markerPos) {
599 
600     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
601     if (lpRecorder == NULL) {
602         jniThrowException(env, "java/lang/IllegalStateException",
603             "Unable to retrieve AudioRecord pointer for setMarkerPosition()");
604         return (jint)AUDIO_JAVA_ERROR;
605     }
606     return nativeToJavaStatus( lpRecorder->setMarkerPosition(markerPos) );
607 }
608 
609 
610 // ----------------------------------------------------------------------------
android_media_AudioRecord_get_marker_pos(JNIEnv * env,jobject thiz)611 static jint android_media_AudioRecord_get_marker_pos(JNIEnv *env,  jobject thiz) {
612 
613     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
614     uint32_t markerPos = 0;
615 
616     if (lpRecorder == NULL) {
617         jniThrowException(env, "java/lang/IllegalStateException",
618             "Unable to retrieve AudioRecord pointer for getMarkerPosition()");
619         return (jint)AUDIO_JAVA_ERROR;
620     }
621     lpRecorder->getMarkerPosition(&markerPos);
622     return (jint)markerPos;
623 }
624 
625 
626 // ----------------------------------------------------------------------------
android_media_AudioRecord_set_pos_update_period(JNIEnv * env,jobject thiz,jint period)627 static jint android_media_AudioRecord_set_pos_update_period(JNIEnv *env,  jobject thiz,
628         jint period) {
629 
630     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
631 
632     if (lpRecorder == NULL) {
633         jniThrowException(env, "java/lang/IllegalStateException",
634             "Unable to retrieve AudioRecord pointer for setPositionUpdatePeriod()");
635         return (jint)AUDIO_JAVA_ERROR;
636     }
637     return nativeToJavaStatus( lpRecorder->setPositionUpdatePeriod(period) );
638 }
639 
640 
641 // ----------------------------------------------------------------------------
android_media_AudioRecord_get_pos_update_period(JNIEnv * env,jobject thiz)642 static jint android_media_AudioRecord_get_pos_update_period(JNIEnv *env,  jobject thiz) {
643 
644     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
645     uint32_t period = 0;
646 
647     if (lpRecorder == NULL) {
648         jniThrowException(env, "java/lang/IllegalStateException",
649             "Unable to retrieve AudioRecord pointer for getPositionUpdatePeriod()");
650         return (jint)AUDIO_JAVA_ERROR;
651     }
652     lpRecorder->getPositionUpdatePeriod(&period);
653     return (jint)period;
654 }
655 
656 
657 // ----------------------------------------------------------------------------
658 // returns the minimum required size for the successful creation of an AudioRecord instance.
659 // returns 0 if the parameter combination is not supported.
660 // 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 channelCount,jint audioFormat)661 static jint android_media_AudioRecord_get_min_buff_size(JNIEnv *env,  jobject thiz,
662     jint sampleRateInHertz, jint channelCount, jint audioFormat) {
663 
664     ALOGV(">> android_media_AudioRecord_get_min_buff_size(%d, %d, %d)",
665           sampleRateInHertz, channelCount, audioFormat);
666 
667     size_t frameCount = 0;
668     audio_format_t format = audioFormatToNative(audioFormat);
669     status_t result = AudioRecord::getMinFrameCount(&frameCount,
670             sampleRateInHertz,
671             format,
672             audio_channel_in_mask_from_count(channelCount));
673 
674     if (result == BAD_VALUE) {
675         return 0;
676     }
677     if (result != NO_ERROR) {
678         return -1;
679     }
680     return frameCount * channelCount * audio_bytes_per_sample(format);
681 }
682 
android_media_AudioRecord_setInputDevice(JNIEnv * env,jobject thiz,jint device_id)683 static jboolean android_media_AudioRecord_setInputDevice(
684         JNIEnv *env,  jobject thiz, jint device_id) {
685 
686     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
687     if (lpRecorder == 0) {
688         return false;
689     }
690     return lpRecorder->setInputDevice(device_id) == NO_ERROR;
691 }
692 
android_media_AudioRecord_getRoutedDeviceId(JNIEnv * env,jobject thiz)693 static jint android_media_AudioRecord_getRoutedDeviceId(
694                 JNIEnv *env,  jobject thiz) {
695 
696     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
697     if (lpRecorder == 0) {
698         return 0;
699     }
700     return (jint)lpRecorder->getRoutedDeviceId();
701 }
702 
android_media_AudioRecord_enableDeviceCallback(JNIEnv * env,jobject thiz)703 static void android_media_AudioRecord_enableDeviceCallback(
704                 JNIEnv *env,  jobject thiz) {
705 
706     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
707     if (lpRecorder == 0) {
708         return;
709     }
710     sp<JNIDeviceCallback> cb = getJniDeviceCallback(env, thiz);
711     if (cb != 0) {
712         return;
713     }
714     audiorecord_callback_cookie *cookie =
715             (audiorecord_callback_cookie *)env->GetLongField(thiz,
716                                                      javaAudioRecordFields.nativeCallbackCookie);
717     if (cookie == NULL) {
718         return;
719     }
720 
721     cb = new JNIDeviceCallback(env, thiz, cookie->audioRecord_ref,
722                                javaAudioRecordFields.postNativeEventInJava);
723     status_t status = lpRecorder->addAudioDeviceCallback(cb);
724     if (status == NO_ERROR) {
725         setJniDeviceCallback(env, thiz, cb);
726     }
727 }
728 
android_media_AudioRecord_disableDeviceCallback(JNIEnv * env,jobject thiz)729 static void android_media_AudioRecord_disableDeviceCallback(
730                 JNIEnv *env,  jobject thiz) {
731 
732     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
733     if (lpRecorder == 0) {
734         return;
735     }
736     sp<JNIDeviceCallback> cb = setJniDeviceCallback(env, thiz, 0);
737     if (cb != 0) {
738         lpRecorder->removeAudioDeviceCallback(cb);
739     }
740 }
741 
742 // ----------------------------------------------------------------------------
android_media_AudioRecord_get_timestamp(JNIEnv * env,jobject thiz,jobject timestamp,jint timebase)743 static jint android_media_AudioRecord_get_timestamp(JNIEnv *env, jobject thiz,
744         jobject timestamp, jint timebase) {
745     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
746 
747     if (lpRecorder == NULL) {
748         jniThrowException(env, "java/lang/IllegalStateException",
749             "Unable to retrieve AudioRecord pointer for getTimestamp()");
750         return (jint)AUDIO_JAVA_ERROR;
751     }
752 
753     ExtendedTimestamp ts;
754     jint status = nativeToJavaStatus(lpRecorder->getTimestamp(&ts));
755 
756     if (status == AUDIO_JAVA_SUCCESS) {
757         // set the data
758         int64_t position, time;
759 
760         status = nativeToJavaStatus(ts.getBestTimestamp(&position, &time, timebase));
761         if (status == AUDIO_JAVA_SUCCESS) {
762             env->SetLongField(
763                     timestamp, javaAudioTimestampFields.fieldFramePosition, position);
764             env->SetLongField(
765                     timestamp, javaAudioTimestampFields.fieldNanoTime, time);
766         }
767     }
768     return status;
769 }
770 
771 // ----------------------------------------------------------------------------
772 static jobject
android_media_AudioRecord_native_getMetrics(JNIEnv * env,jobject thiz)773 android_media_AudioRecord_native_getMetrics(JNIEnv *env, jobject thiz)
774 {
775     ALOGV("android_media_AudioRecord_native_getMetrics");
776 
777     sp<AudioRecord> lpRecord = getAudioRecord(env, thiz);
778 
779     if (lpRecord == NULL) {
780         ALOGE("Unable to retrieve AudioRecord pointer for getMetrics()");
781         jniThrowException(env, "java/lang/IllegalStateException", NULL);
782         return (jobject) NULL;
783     }
784 
785     // get what we have for the metrics from the record session
786     MediaAnalyticsItem *item = NULL;
787 
788     status_t err = lpRecord->getMetrics(item);
789     if (err != OK) {
790         ALOGE("getMetrics failed");
791         jniThrowException(env, "java/lang/IllegalStateException", NULL);
792         return (jobject) NULL;
793     }
794 
795     jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL /* mybundle */);
796 
797     // housekeeping
798     delete item;
799     item = NULL;
800 
801     return mybundle;
802 }
803 
804 // ----------------------------------------------------------------------------
android_media_AudioRecord_get_active_microphones(JNIEnv * env,jobject thiz,jobject jActiveMicrophones)805 static jint android_media_AudioRecord_get_active_microphones(JNIEnv *env,
806         jobject thiz, jobject jActiveMicrophones) {
807     if (jActiveMicrophones == NULL) {
808         ALOGE("jActiveMicrophones is null");
809         return (jint)AUDIO_JAVA_BAD_VALUE;
810     }
811     if (!env->IsInstanceOf(jActiveMicrophones, gArrayListClass)) {
812         ALOGE("getActiveMicrophones not an arraylist");
813         return (jint)AUDIO_JAVA_BAD_VALUE;
814     }
815 
816     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
817     if (lpRecorder == NULL) {
818         jniThrowException(env, "java/lang/IllegalStateException",
819             "Unable to retrieve AudioRecord pointer for getActiveMicrophones()");
820         return (jint)AUDIO_JAVA_ERROR;
821     }
822 
823     jint jStatus = AUDIO_JAVA_SUCCESS;
824     std::vector<media::MicrophoneInfo> activeMicrophones;
825     status_t status = lpRecorder->getActiveMicrophones(&activeMicrophones);
826     if (status != NO_ERROR) {
827         ALOGE_IF(status != NO_ERROR, "AudioRecord::getActiveMicrophones error %d", status);
828         jStatus = nativeToJavaStatus(status);
829         return jStatus;
830     }
831 
832     for (size_t i = 0; i < activeMicrophones.size(); i++) {
833         jobject jMicrophoneInfo;
834         jStatus = convertMicrophoneInfoFromNative(env, &jMicrophoneInfo, &activeMicrophones[i]);
835         if (jStatus != AUDIO_JAVA_SUCCESS) {
836             return jStatus;
837         }
838         env->CallBooleanMethod(jActiveMicrophones, gArrayListMethods.add, jMicrophoneInfo);
839         env->DeleteLocalRef(jMicrophoneInfo);
840     }
841     return jStatus;
842 }
843 
844 // ----------------------------------------------------------------------------
845 // ----------------------------------------------------------------------------
846 static const JNINativeMethod gMethods[] = {
847     // name,               signature,  funcPtr
848     {"native_start",         "(II)I",    (void *)android_media_AudioRecord_start},
849     {"native_stop",          "()V",    (void *)android_media_AudioRecord_stop},
850     {"native_setup",         "(Ljava/lang/Object;Ljava/lang/Object;[IIIII[ILjava/lang/String;J)I",
851                                       (void *)android_media_AudioRecord_setup},
852     {"native_finalize",      "()V",    (void *)android_media_AudioRecord_finalize},
853     {"native_release",       "()V",    (void *)android_media_AudioRecord_release},
854     {"native_read_in_byte_array",
855                              "([BIIZ)I",
856                                      (void *)android_media_AudioRecord_readInArray<jbyteArray>},
857     {"native_read_in_short_array",
858                              "([SIIZ)I",
859                                      (void *)android_media_AudioRecord_readInArray<jshortArray>},
860     {"native_read_in_float_array",
861                              "([FIIZ)I",
862                                      (void *)android_media_AudioRecord_readInArray<jfloatArray>},
863     {"native_read_in_direct_buffer","(Ljava/lang/Object;IZ)I",
864                                        (void *)android_media_AudioRecord_readInDirectBuffer},
865     {"native_get_buffer_size_in_frames",
866                              "()I", (void *)android_media_AudioRecord_get_buffer_size_in_frames},
867     {"native_set_marker_pos","(I)I",   (void *)android_media_AudioRecord_set_marker_pos},
868     {"native_get_marker_pos","()I",    (void *)android_media_AudioRecord_get_marker_pos},
869     {"native_set_pos_update_period",
870                              "(I)I",   (void *)android_media_AudioRecord_set_pos_update_period},
871     {"native_get_pos_update_period",
872                              "()I",    (void *)android_media_AudioRecord_get_pos_update_period},
873     {"native_get_min_buff_size",
874                              "(III)I",   (void *)android_media_AudioRecord_get_min_buff_size},
875     {"native_getMetrics",    "()Landroid/os/PersistableBundle;",
876                                          (void *)android_media_AudioRecord_native_getMetrics},
877     {"native_setInputDevice", "(I)Z", (void *)android_media_AudioRecord_setInputDevice},
878     {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioRecord_getRoutedDeviceId},
879     {"native_enableDeviceCallback", "()V", (void *)android_media_AudioRecord_enableDeviceCallback},
880     {"native_disableDeviceCallback", "()V",
881                                         (void *)android_media_AudioRecord_disableDeviceCallback},
882     {"native_get_timestamp", "(Landroid/media/AudioTimestamp;I)I",
883                                        (void *)android_media_AudioRecord_get_timestamp},
884     {"native_get_active_microphones", "(Ljava/util/ArrayList;)I",
885                                         (void *)android_media_AudioRecord_get_active_microphones},
886 };
887 
888 // field names found in android/media/AudioRecord.java
889 #define JAVA_POSTEVENT_CALLBACK_NAME  "postEventFromNative"
890 #define JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME  "mNativeRecorderInJavaObj"
891 #define JAVA_NATIVECALLBACKINFO_FIELD_NAME       "mNativeCallbackCookie"
892 #define JAVA_NATIVEDEVICECALLBACK_FIELD_NAME       "mNativeDeviceCallback"
893 
894 // ----------------------------------------------------------------------------
register_android_media_AudioRecord(JNIEnv * env)895 int register_android_media_AudioRecord(JNIEnv *env)
896 {
897     javaAudioRecordFields.postNativeEventInJava = NULL;
898     javaAudioRecordFields.nativeRecorderInJavaObj = NULL;
899     javaAudioRecordFields.nativeCallbackCookie = NULL;
900     javaAudioRecordFields.nativeDeviceCallback = NULL;
901 
902 
903     // Get the AudioRecord class
904     jclass audioRecordClass = FindClassOrDie(env, kClassPathName);
905     // Get the postEvent method
906     javaAudioRecordFields.postNativeEventInJava = GetStaticMethodIDOrDie(env,
907             audioRecordClass, JAVA_POSTEVENT_CALLBACK_NAME,
908             "(Ljava/lang/Object;IIILjava/lang/Object;)V");
909 
910     // Get the variables
911     //    mNativeRecorderInJavaObj
912     javaAudioRecordFields.nativeRecorderInJavaObj = GetFieldIDOrDie(env,
913             audioRecordClass, JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME, "J");
914     //     mNativeCallbackCookie
915     javaAudioRecordFields.nativeCallbackCookie = GetFieldIDOrDie(env,
916             audioRecordClass, JAVA_NATIVECALLBACKINFO_FIELD_NAME, "J");
917 
918     javaAudioRecordFields.nativeDeviceCallback = GetFieldIDOrDie(env,
919             audioRecordClass, JAVA_NATIVEDEVICECALLBACK_FIELD_NAME, "J");
920 
921     // Get the AudioAttributes class and fields
922     jclass audioAttrClass = FindClassOrDie(env, kAudioAttributesClassPathName);
923     javaAudioAttrFields.fieldRecSource = GetFieldIDOrDie(env, audioAttrClass, "mSource", "I");
924     javaAudioAttrFields.fieldFlags = GetFieldIDOrDie(env, audioAttrClass, "mFlags", "I");
925     javaAudioAttrFields.fieldFormattedTags = GetFieldIDOrDie(env,
926             audioAttrClass, "mFormattedTags", "Ljava/lang/String;");
927 
928     // Get the RecordTimestamp class and fields
929     jclass audioTimestampClass = FindClassOrDie(env, "android/media/AudioTimestamp");
930     javaAudioTimestampFields.fieldFramePosition =
931             GetFieldIDOrDie(env, audioTimestampClass, "framePosition", "J");
932     javaAudioTimestampFields.fieldNanoTime =
933             GetFieldIDOrDie(env, audioTimestampClass, "nanoTime", "J");
934 
935     jclass arrayListClass = FindClassOrDie(env, "java/util/ArrayList");
936     gArrayListClass = MakeGlobalRefOrDie(env, arrayListClass);
937     gArrayListMethods.add = GetMethodIDOrDie(env, arrayListClass, "add", "(Ljava/lang/Object;)Z");
938 
939     return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
940 }
941 
942 // ----------------------------------------------------------------------------
943