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