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