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