blob: 375d68b858240944af873847d8748d8f4b521c52 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18
19#define LOG_TAG "AudioRecord-JNI"
20
Kévin PETIT95ece352014-02-13 11:02:27 +000021#include <inttypes.h>
Glenn Kastenc81d31c2012-03-13 14:46:23 -070022#include <jni.h>
Steven Moreland2279b252017-07-19 09:50:45 -070023#include <nativehelper/JNIHelp.h>
Andreas Gampeed6b9df2014-11-20 22:02:20 -080024#include "core_jni_helpers.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025
Glenn Kastenc81d31c2012-03-13 14:46:23 -070026#include <utils/Log.h>
27#include <media/AudioRecord.h>
jiabin23675f62018-01-17 18:05:25 -080028#include <media/MicrophoneInfo.h>
29#include <vector>
Dima Zavin24fc2fb2011-04-19 22:30:36 -070030
Steven Moreland2279b252017-07-19 09:50:45 -070031#include <nativehelper/ScopedUtfChars.h>
Svet Ganovfa5ecdc2015-04-28 12:03:28 -070032
Glenn Kastenfe834d32014-01-08 14:49:08 -080033#include "android_media_AudioFormat.h"
Eric Laurentbc11a692014-05-16 12:19:25 -070034#include "android_media_AudioErrors.h"
Eric Laurent4bcdba82015-05-01 11:37:49 -070035#include "android_media_DeviceCallback.h"
Ray Essick510225b2018-01-24 14:27:16 -080036#include "android_media_MediaMetricsJNI.h"
jiabin23675f62018-01-17 18:05:25 -080037#include "android_media_MicrophoneInfo.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038
39// ----------------------------------------------------------------------------
40
41using namespace android;
42
43// ----------------------------------------------------------------------------
44static const char* const kClassPathName = "android/media/AudioRecord";
Jean-Michel Trivi701d6ff2014-07-16 07:51:22 -070045static const char* const kAudioAttributesClassPathName = "android/media/AudioAttributes";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046
jiabin23675f62018-01-17 18:05:25 -080047static jclass gArrayListClass;
48static struct {
49 jmethodID add;
50} gArrayListMethods;
51
Jean-Michel Trivi701d6ff2014-07-16 07:51:22 -070052struct audio_record_fields_t {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053 // these fields provide access from C++ to the...
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054 jmethodID postNativeEventInJava; //... event post callback method
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055 jfieldID nativeRecorderInJavaObj; // provides access to the C++ AudioRecord object
56 jfieldID nativeCallbackCookie; // provides access to the AudioRecord callback data
Eric Laurent4bcdba82015-05-01 11:37:49 -070057 jfieldID nativeDeviceCallback; // provides access to the JNIDeviceCallback instance
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058};
Jean-Michel Trivi701d6ff2014-07-16 07:51:22 -070059struct audio_attributes_fields_t {
60 jfieldID fieldRecSource; // AudioAttributes.mSource
Eric Laurentbdad1af2014-09-19 17:43:29 -070061 jfieldID fieldFlags; // AudioAttributes.mFlags
Jean-Michel Trivi701d6ff2014-07-16 07:51:22 -070062 jfieldID fieldFormattedTags;// AudioAttributes.mFormattedTags
63};
64static audio_attributes_fields_t javaAudioAttrFields;
65static audio_record_fields_t javaAudioRecordFields;
Andy Hung0ad99c02016-01-15 17:53:47 -080066static struct {
67 jfieldID fieldFramePosition; // AudioTimestamp.framePosition
68 jfieldID fieldNanoTime; // AudioTimestamp.nanoTime
69} javaAudioTimestampFields;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070
71struct audiorecord_callback_cookie {
72 jclass audioRecord_class;
73 jobject audioRecord_ref;
Eric Laurent532bc1c2012-04-20 12:45:03 -070074 bool busy;
75 Condition cond;
76};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077
Eric Laurent532bc1c2012-04-20 12:45:03 -070078static Mutex sLock;
79static SortedVector <audiorecord_callback_cookie *> sAudioRecordCallBackCookies;
Dave Sparkse6335c92010-03-13 17:08:22 -080080
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081// ----------------------------------------------------------------------------
82
Chih-Hung Hsieh0ca16ef2016-05-19 15:14:54 -070083#define AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT (-16)
84#define AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK (-17)
85#define AUDIORECORD_ERROR_SETUP_INVALIDFORMAT (-18)
86#define AUDIORECORD_ERROR_SETUP_INVALIDSOURCE (-19)
87#define AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED (-20)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089// ----------------------------------------------------------------------------
90static void recorderCallback(int event, void* user, void *info) {
Eric Laurent532bc1c2012-04-20 12:45:03 -070091
92 audiorecord_callback_cookie *callbackInfo = (audiorecord_callback_cookie *)user;
93 {
94 Mutex::Autolock l(sLock);
95 if (sAudioRecordCallBackCookies.indexOf(callbackInfo) < 0) {
96 return;
97 }
98 callbackInfo->busy = true;
99 }
Glenn Kasten18db49a2012-03-12 16:29:55 -0700100
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700101 switch (event) {
102 case AudioRecord::EVENT_MARKER: {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103 JNIEnv *env = AndroidRuntime::getJNIEnv();
Glenn Kastena667ff32013-07-22 07:36:34 -0700104 if (user != NULL && env != NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105 env->CallStaticVoidMethod(
Glenn Kasten18db49a2012-03-12 16:29:55 -0700106 callbackInfo->audioRecord_class,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 javaAudioRecordFields.postNativeEventInJava,
108 callbackInfo->audioRecord_ref, event, 0,0, NULL);
109 if (env->ExceptionCheck()) {
110 env->ExceptionDescribe();
111 env->ExceptionClear();
112 }
113 }
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700114 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700116 case AudioRecord::EVENT_NEW_POS: {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117 JNIEnv *env = AndroidRuntime::getJNIEnv();
Glenn Kastena667ff32013-07-22 07:36:34 -0700118 if (user != NULL && env != NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119 env->CallStaticVoidMethod(
Glenn Kasten18db49a2012-03-12 16:29:55 -0700120 callbackInfo->audioRecord_class,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121 javaAudioRecordFields.postNativeEventInJava,
122 callbackInfo->audioRecord_ref, event, 0,0, NULL);
123 if (env->ExceptionCheck()) {
124 env->ExceptionDescribe();
125 env->ExceptionClear();
126 }
127 }
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700128 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129 }
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700130
Eric Laurent532bc1c2012-04-20 12:45:03 -0700131 {
132 Mutex::Autolock l(sLock);
133 callbackInfo->busy = false;
134 callbackInfo->cond.broadcast();
135 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136}
137
Eric Laurent4bcdba82015-05-01 11:37:49 -0700138static sp<JNIDeviceCallback> getJniDeviceCallback(JNIEnv* env, jobject thiz)
139{
140 Mutex::Autolock l(sLock);
141 JNIDeviceCallback* const cb =
142 (JNIDeviceCallback*)env->GetLongField(thiz,
143 javaAudioRecordFields.nativeDeviceCallback);
144 return sp<JNIDeviceCallback>(cb);
145}
146
147static sp<JNIDeviceCallback> setJniDeviceCallback(JNIEnv* env,
148 jobject thiz,
149 const sp<JNIDeviceCallback>& cb)
150{
151 Mutex::Autolock l(sLock);
152 sp<JNIDeviceCallback> old =
153 (JNIDeviceCallback*)env->GetLongField(thiz,
154 javaAudioRecordFields.nativeDeviceCallback);
155 if (cb.get()) {
156 cb->incStrong((void*)setJniDeviceCallback);
157 }
158 if (old != 0) {
159 old->decStrong((void*)setJniDeviceCallback);
160 }
161 env->SetLongField(thiz, javaAudioRecordFields.nativeDeviceCallback, (jlong)cb.get());
162 return old;
163}
164
Eric Laurent532bc1c2012-04-20 12:45:03 -0700165// ----------------------------------------------------------------------------
166static sp<AudioRecord> getAudioRecord(JNIEnv* env, jobject thiz)
167{
168 Mutex::Autolock l(sLock);
169 AudioRecord* const ar =
Ashok Bhat075e9a12014-01-06 13:45:09 +0000170 (AudioRecord*)env->GetLongField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700171 return sp<AudioRecord>(ar);
172}
173
174static sp<AudioRecord> setAudioRecord(JNIEnv* env, jobject thiz, const sp<AudioRecord>& ar)
175{
176 Mutex::Autolock l(sLock);
177 sp<AudioRecord> old =
Ashok Bhat075e9a12014-01-06 13:45:09 +0000178 (AudioRecord*)env->GetLongField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700179 if (ar.get()) {
Mathias Agopianb1d90c82013-03-06 17:45:42 -0800180 ar->incStrong((void*)setAudioRecord);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700181 }
182 if (old != 0) {
Mathias Agopianb1d90c82013-03-06 17:45:42 -0800183 old->decStrong((void*)setAudioRecord);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700184 }
Ashok Bhat075e9a12014-01-06 13:45:09 +0000185 env->SetLongField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj, (jlong)ar.get());
Eric Laurent532bc1c2012-04-20 12:45:03 -0700186 return old;
187}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188
189// ----------------------------------------------------------------------------
Ashok Bhat075e9a12014-01-06 13:45:09 +0000190static jint
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
Glenn Kasten1cbf9b32016-02-02 12:04:09 -0800192 jobject jaa, jintArray jSampleRate, jint channelMask, jint channelIndexMask,
Paul McLean9b09e532016-01-26 14:43:35 -0700193 jint audioFormat, jint buffSizeInBytes, jintArray jSession, jstring opPackageName,
194 jlong nativeRecordInJavaObj)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195{
Steve Block71f2cf12011-10-20 11:56:00 +0100196 //ALOGV(">> Entering android_media_AudioRecord_setup");
Paul McLean9b09e532016-01-26 14:43:35 -0700197 //ALOGV("sampleRate=%d, audioFormat=%d, channel mask=%x, buffSizeInBytes=%d "
198 // "nativeRecordInJavaObj=0x%llX",
199 // sampleRateInHertz, audioFormat, channelMask, buffSizeInBytes, nativeRecordInJavaObj);
200 audio_channel_mask_t localChanMask = inChannelMaskToNative(channelMask);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700201
Eric Laurent44ff4cd2011-06-18 10:34:05 -0700202 if (jSession == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000203 ALOGE("Error creating AudioRecord: invalid session ID pointer");
Eric Laurentbc11a692014-05-16 12:19:25 -0700204 return (jint) AUDIO_JAVA_ERROR;
Eric Laurent44ff4cd2011-06-18 10:34:05 -0700205 }
206
207 jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
208 if (nSession == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000209 ALOGE("Error creating AudioRecord: Error retrieving session id pointer");
Eric Laurentbc11a692014-05-16 12:19:25 -0700210 return (jint) AUDIO_JAVA_ERROR;
Eric Laurent44ff4cd2011-06-18 10:34:05 -0700211 }
Glenn Kasten33b84042016-03-08 12:02:55 -0800212 audio_session_t sessionId = (audio_session_t) nSession[0];
Eric Laurent44ff4cd2011-06-18 10:34:05 -0700213 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
214 nSession = NULL;
215
Jean-Michel Trivi701d6ff2014-07-16 07:51:22 -0700216 audio_attributes_t *paa = NULL;
Paul McLean9b09e532016-01-26 14:43:35 -0700217 sp<AudioRecord> lpRecorder = 0;
218 audiorecord_callback_cookie *lpCallbackData = NULL;
Jean-Michel Trivi701d6ff2014-07-16 07:51:22 -0700219
Paul McLean9b09e532016-01-26 14:43:35 -0700220 jclass clazz = env->GetObjectClass(thiz);
221 if (clazz == NULL) {
222 ALOGE("Can't find %s when setting up callback.", kClassPathName);
223 return (jint) AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
Eric Laurentbdad1af2014-09-19 17:43:29 -0700224 }
Glenn Kasten18db49a2012-03-12 16:29:55 -0700225
Paul McLean9b09e532016-01-26 14:43:35 -0700226 // if we pass in an existing *Native* AudioRecord, we don't need to create/initialize one.
227 if (nativeRecordInJavaObj == 0) {
228 if (jaa == 0) {
229 ALOGE("Error creating AudioRecord: invalid audio attributes");
230 return (jint) AUDIO_JAVA_ERROR;
231 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800232
Paul McLean9b09e532016-01-26 14:43:35 -0700233 if (jSampleRate == 0) {
234 ALOGE("Error creating AudioRecord: invalid sample rates");
235 return (jint) AUDIO_JAVA_ERROR;
236 }
237 jint elements[1];
238 env->GetIntArrayRegion(jSampleRate, 0, 1, elements);
239 int sampleRateInHertz = elements[0];
240
241 // channel index mask takes priority over channel position masks.
242 if (channelIndexMask) {
243 // Java channel index masks need the representation bits set.
244 localChanMask = audio_channel_mask_from_representation_and_bits(
245 AUDIO_CHANNEL_REPRESENTATION_INDEX,
246 channelIndexMask);
247 }
248 // Java channel position masks map directly to the native definition
249
250 if (!audio_is_input_channel(localChanMask)) {
251 ALOGE("Error creating AudioRecord: channel mask %#x is not valid.", localChanMask);
252 return (jint) AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK;
253 }
254 uint32_t channelCount = audio_channel_count_from_in_mask(localChanMask);
255
256 // compare the format against the Java constants
257 audio_format_t format = audioFormatToNative(audioFormat);
258 if (format == AUDIO_FORMAT_INVALID) {
259 ALOGE("Error creating AudioRecord: unsupported audio format %d.", audioFormat);
260 return (jint) AUDIORECORD_ERROR_SETUP_INVALIDFORMAT;
261 }
262
263 size_t bytesPerSample = audio_bytes_per_sample(format);
264
265 if (buffSizeInBytes == 0) {
266 ALOGE("Error creating AudioRecord: frameCount is 0.");
267 return (jint) AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT;
268 }
269 size_t frameSize = channelCount * bytesPerSample;
270 size_t frameCount = buffSizeInBytes / frameSize;
271
272 ScopedUtfChars opPackageNameStr(env, opPackageName);
273
274 // create an uninitialized AudioRecord object
275 lpRecorder = new AudioRecord(String16(opPackageNameStr.c_str()));
276
277 // read the AudioAttributes values
278 paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
279 const jstring jtags =
280 (jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags);
281 const char* tags = env->GetStringUTFChars(jtags, NULL);
282 // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it
283 strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
284 env->ReleaseStringUTFChars(jtags, tags);
285 paa->source = (audio_source_t) env->GetIntField(jaa, javaAudioAttrFields.fieldRecSource);
286 paa->flags = (audio_flags_mask_t)env->GetIntField(jaa, javaAudioAttrFields.fieldFlags);
287 ALOGV("AudioRecord_setup for source=%d tags=%s flags=%08x", paa->source, paa->tags, paa->flags);
288
289 audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE;
290 if (paa->flags & AUDIO_FLAG_HW_HOTWORD) {
291 flags = AUDIO_INPUT_FLAG_HW_HOTWORD;
292 }
293 // create the callback information:
294 // this data will be passed with every AudioRecord callback
295 lpCallbackData = new audiorecord_callback_cookie;
296 lpCallbackData->audioRecord_class = (jclass)env->NewGlobalRef(clazz);
297 // we use a weak reference so the AudioRecord object can be garbage collected.
298 lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
299 lpCallbackData->busy = false;
300
301 const status_t status = lpRecorder->set(paa->source,
302 sampleRateInHertz,
303 format, // word length, PCM
304 localChanMask,
305 frameCount,
306 recorderCallback,// callback_t
307 lpCallbackData,// void* user
308 0, // notificationFrames,
309 true, // threadCanCallJava
310 sessionId,
311 AudioRecord::TRANSFER_DEFAULT,
312 flags,
313 -1, -1, // default uid, pid
314 paa);
315
316 if (status != NO_ERROR) {
317 ALOGE("Error creating AudioRecord instance: initialization check failed with status %d.",
318 status);
319 goto native_init_failure;
320 }
321 } else { // end if nativeRecordInJavaObj == 0)
322 lpRecorder = (AudioRecord*)nativeRecordInJavaObj;
323 // TODO: We need to find out which members of the Java AudioRecord might need to be
324 // initialized from the Native AudioRecord
325 // these are directly returned from getters:
326 // mSampleRate
327 // mRecordSource
328 // mAudioFormat
329 // mChannelMask
330 // mChannelCount
331 // mState (?)
332 // mRecordingState (?)
333 // mPreferredDevice
334
335 // create the callback information:
336 // this data will be passed with every AudioRecord callback
337 lpCallbackData = new audiorecord_callback_cookie;
338 lpCallbackData->audioRecord_class = (jclass)env->NewGlobalRef(clazz);
339 // we use a weak reference so the AudioRecord object can be garbage collected.
340 lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
341 lpCallbackData->busy = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800342 }
343
Eric Laurent44ff4cd2011-06-18 10:34:05 -0700344 nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
345 if (nSession == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000346 ALOGE("Error creating AudioRecord: Error retrieving session id pointer");
Eric Laurent44ff4cd2011-06-18 10:34:05 -0700347 goto native_init_failure;
348 }
Glenn Kastenb3db2132012-01-19 08:59:58 -0800349 // read the audio session ID back from AudioRecord in case a new session was created during set()
Eric Laurent44ff4cd2011-06-18 10:34:05 -0700350 nSession[0] = lpRecorder->getSessionId();
351 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
352 nSession = NULL;
353
Glenn Kasten1cbf9b32016-02-02 12:04:09 -0800354 {
355 const jint elements[1] = { (jint) lpRecorder->getSampleRate() };
356 env->SetIntArrayRegion(jSampleRate, 0, 1, elements);
357 }
358
Eric Laurent532bc1c2012-04-20 12:45:03 -0700359 { // scope for the lock
360 Mutex::Autolock l(sLock);
361 sAudioRecordCallBackCookies.add(lpCallbackData);
362 }
Glenn Kasten18db49a2012-03-12 16:29:55 -0700363 // save our newly created C++ AudioRecord in the "nativeRecorderInJavaObj" field
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800364 // of the Java object
Eric Laurent532bc1c2012-04-20 12:45:03 -0700365 setAudioRecord(env, thiz, lpRecorder);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700366
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367 // save our newly created callback information in the "nativeCallbackCookie" field
368 // of the Java object (in mNativeCallbackCookie) so we can free the memory in finalize()
Ashok Bhat075e9a12014-01-06 13:45:09 +0000369 env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, (jlong)lpCallbackData);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700370
Eric Laurentbc11a692014-05-16 12:19:25 -0700371 return (jint) AUDIO_JAVA_SUCCESS;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700372
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800373 // failure:
374native_init_failure:
Jean-Michel Trivi4bac5a32009-07-17 12:05:31 -0700375 env->DeleteGlobalRef(lpCallbackData->audioRecord_class);
376 env->DeleteGlobalRef(lpCallbackData->audioRecord_ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800377 delete lpCallbackData;
Ashok Bhat075e9a12014-01-06 13:45:09 +0000378 env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700379
Glenn Kasten14d226a2015-05-18 13:53:39 -0700380 // lpRecorder goes out of scope, so reference count drops to zero
Ashok Bhat075e9a12014-01-06 13:45:09 +0000381 return (jint) AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800382}
383
384
385
386// ----------------------------------------------------------------------------
Ashok Bhat075e9a12014-01-06 13:45:09 +0000387static jint
Eric Laurent505e5c82012-03-29 15:19:36 -0700388android_media_AudioRecord_start(JNIEnv *env, jobject thiz, jint event, jint triggerSession)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800389{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700390 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391 if (lpRecorder == NULL ) {
392 jniThrowException(env, "java/lang/IllegalStateException", NULL);
Eric Laurentbc11a692014-05-16 12:19:25 -0700393 return (jint) AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800394 }
Glenn Kasten18db49a2012-03-12 16:29:55 -0700395
Eric Laurentbc11a692014-05-16 12:19:25 -0700396 return nativeToJavaStatus(
Glenn Kasten33b84042016-03-08 12:02:55 -0800397 lpRecorder->start((AudioSystem::sync_event_t)event, (audio_session_t) triggerSession));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398}
399
400
401// ----------------------------------------------------------------------------
402static void
403android_media_AudioRecord_stop(JNIEnv *env, jobject thiz)
404{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700405 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800406 if (lpRecorder == NULL ) {
407 jniThrowException(env, "java/lang/IllegalStateException", NULL);
408 return;
409 }
410
411 lpRecorder->stop();
Steve Block71f2cf12011-10-20 11:56:00 +0100412 //ALOGV("Called lpRecorder->stop()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413}
414
415
416// ----------------------------------------------------------------------------
Dave Sparkse6335c92010-03-13 17:08:22 -0800417
Eric Laurent532bc1c2012-04-20 12:45:03 -0700418#define CALLBACK_COND_WAIT_TIMEOUT_MS 1000
419static void android_media_AudioRecord_release(JNIEnv *env, jobject thiz) {
420 sp<AudioRecord> lpRecorder = setAudioRecord(env, thiz, 0);
421 if (lpRecorder == NULL) {
422 return;
423 }
Glenn Kasten2fbf25b2014-03-28 15:41:58 -0700424 ALOGV("About to delete lpRecorder: %p", lpRecorder.get());
Eric Laurent532bc1c2012-04-20 12:45:03 -0700425 lpRecorder->stop();
426
Ashok Bhat075e9a12014-01-06 13:45:09 +0000427 audiorecord_callback_cookie *lpCookie = (audiorecord_callback_cookie *)env->GetLongField(
Dave Sparkse6335c92010-03-13 17:08:22 -0800428 thiz, javaAudioRecordFields.nativeCallbackCookie);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800429
Dave Sparkse6335c92010-03-13 17:08:22 -0800430 // reset the native resources in the Java object so any attempt to access
431 // them after a call to release fails.
Ashok Bhat075e9a12014-01-06 13:45:09 +0000432 env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0);
Dave Sparkse6335c92010-03-13 17:08:22 -0800433
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800434 // delete the callback information
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435 if (lpCookie) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700436 Mutex::Autolock l(sLock);
Glenn Kasten2fbf25b2014-03-28 15:41:58 -0700437 ALOGV("deleting lpCookie: %p", lpCookie);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700438 while (lpCookie->busy) {
439 if (lpCookie->cond.waitRelative(sLock,
440 milliseconds(CALLBACK_COND_WAIT_TIMEOUT_MS)) !=
441 NO_ERROR) {
442 break;
443 }
444 }
445 sAudioRecordCallBackCookies.remove(lpCookie);
Jean-Michel Trivi4bac5a32009-07-17 12:05:31 -0700446 env->DeleteGlobalRef(lpCookie->audioRecord_class);
447 env->DeleteGlobalRef(lpCookie->audioRecord_ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800448 delete lpCookie;
449 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800450}
451
452
453// ----------------------------------------------------------------------------
Dave Sparkse6335c92010-03-13 17:08:22 -0800454static void android_media_AudioRecord_finalize(JNIEnv *env, jobject thiz) {
455 android_media_AudioRecord_release(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800456}
457
Andy Hung0e9e2f32015-04-13 23:47:18 -0700458// overloaded JNI array helper functions
459static inline
460jbyte *envGetArrayElements(JNIEnv *env, jbyteArray array, jboolean *isCopy) {
461 return env->GetByteArrayElements(array, isCopy);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800462}
463
Andy Hung0e9e2f32015-04-13 23:47:18 -0700464static inline
465void envReleaseArrayElements(JNIEnv *env, jbyteArray array, jbyte *elems, jint mode) {
466 env->ReleaseByteArrayElements(array, elems, mode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800467}
468
Andy Hung0e9e2f32015-04-13 23:47:18 -0700469static inline
470jshort *envGetArrayElements(JNIEnv *env, jshortArray array, jboolean *isCopy) {
471 return env->GetShortArrayElements(array, isCopy);
472}
473
474static inline
475void envReleaseArrayElements(JNIEnv *env, jshortArray array, jshort *elems, jint mode) {
476 env->ReleaseShortArrayElements(array, elems, mode);
477}
478
479static inline
480jfloat *envGetArrayElements(JNIEnv *env, jfloatArray array, jboolean *isCopy) {
481 return env->GetFloatArrayElements(array, isCopy);
482}
483
484static inline
485void envReleaseArrayElements(JNIEnv *env, jfloatArray array, jfloat *elems, jint mode) {
486 env->ReleaseFloatArrayElements(array, elems, mode);
487}
488
489static inline
490jint interpretReadSizeError(ssize_t readSize) {
Eric Laurent219de732016-05-23 12:41:50 -0700491 if (readSize == WOULD_BLOCK) {
Andy Hung0e9e2f32015-04-13 23:47:18 -0700492 return (jint)0;
Eric Laurent219de732016-05-23 12:41:50 -0700493 } else if (readSize == NO_INIT) {
494 return AUDIO_JAVA_DEAD_OBJECT;
495 } else {
496 ALOGE("Error %zd during AudioRecord native read", readSize);
497 return nativeToJavaStatus(readSize);
Andy Hung0e9e2f32015-04-13 23:47:18 -0700498 }
499}
500
501template <typename T>
502static jint android_media_AudioRecord_readInArray(JNIEnv *env, jobject thiz,
503 T javaAudioData,
504 jint offsetInSamples, jint sizeInSamples,
505 jboolean isReadBlocking) {
Andy Hung58b0f3f2015-03-27 17:59:45 -0700506 // get the audio recorder from which we'll read new audio samples
507 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
508 if (lpRecorder == NULL) {
509 ALOGE("Unable to retrieve AudioRecord object");
510 return (jint)AUDIO_JAVA_INVALID_OPERATION;
511 }
512
513 if (javaAudioData == NULL) {
Andy Hung0e9e2f32015-04-13 23:47:18 -0700514 ALOGE("Invalid Java array to store recorded audio");
515 return (jint)AUDIO_JAVA_BAD_VALUE;
516 }
Andy Hung58b0f3f2015-03-27 17:59:45 -0700517
Andy Hung58b0f3f2015-03-27 17:59:45 -0700518 // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
519 // a way that it becomes much more efficient. When doing so, we will have to prevent the
520 // AudioSystem callback to be called while in critical section (in case of media server
521 // process crash for instance)
Andy Hung0e9e2f32015-04-13 23:47:18 -0700522
523 // get the pointer to where we'll record the audio
524 auto *recordBuff = envGetArrayElements(env, javaAudioData, NULL);
Andy Hung58b0f3f2015-03-27 17:59:45 -0700525 if (recordBuff == NULL) {
526 ALOGE("Error retrieving destination for recorded audio data");
527 return (jint)AUDIO_JAVA_BAD_VALUE;
528 }
529
530 // read the new audio data from the native AudioRecord object
Andy Hung0e9e2f32015-04-13 23:47:18 -0700531 const size_t sizeInBytes = sizeInSamples * sizeof(*recordBuff);
532 ssize_t readSize = lpRecorder->read(
533 recordBuff + offsetInSamples, sizeInBytes, isReadBlocking == JNI_TRUE /* blocking */);
Andy Hung58b0f3f2015-03-27 17:59:45 -0700534
Andy Hung0e9e2f32015-04-13 23:47:18 -0700535 envReleaseArrayElements(env, javaAudioData, recordBuff, 0);
Andy Hung58b0f3f2015-03-27 17:59:45 -0700536
537 if (readSize < 0) {
Andy Hung0e9e2f32015-04-13 23:47:18 -0700538 return interpretReadSizeError(readSize);
Andy Hung58b0f3f2015-03-27 17:59:45 -0700539 }
Andy Hung0e9e2f32015-04-13 23:47:18 -0700540 return (jint)(readSize / sizeof(*recordBuff));
Andy Hung58b0f3f2015-03-27 17:59:45 -0700541}
542
543// ----------------------------------------------------------------------------
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800544static jint android_media_AudioRecord_readInDirectBuffer(JNIEnv *env, jobject thiz,
Andy Hung0e9e2f32015-04-13 23:47:18 -0700545 jobject jBuffer, jint sizeInBytes,
546 jboolean isReadBlocking) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800547 // get the audio recorder from which we'll read new audio samples
Eric Laurent532bc1c2012-04-20 12:45:03 -0700548 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700549 if (lpRecorder==NULL)
Andy Hung0e9e2f32015-04-13 23:47:18 -0700550 return (jint)AUDIO_JAVA_INVALID_OPERATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551
552 // direct buffer and direct access supported?
553 long capacity = env->GetDirectBufferCapacity(jBuffer);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700554 if (capacity == -1) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800555 // buffer direct access is not supported
Steve Block3762c312012-01-06 19:20:56 +0000556 ALOGE("Buffer direct access is not supported, can't record");
Andy Hung0e9e2f32015-04-13 23:47:18 -0700557 return (jint)AUDIO_JAVA_BAD_VALUE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800558 }
Steve Block71f2cf12011-10-20 11:56:00 +0100559 //ALOGV("capacity = %ld", capacity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560 jbyte* nativeFromJavaBuf = (jbyte*) env->GetDirectBufferAddress(jBuffer);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700561 if (nativeFromJavaBuf==NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000562 ALOGE("Buffer direct access is not supported, can't record");
Andy Hung0e9e2f32015-04-13 23:47:18 -0700563 return (jint)AUDIO_JAVA_BAD_VALUE;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700564 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800565
566 // read new data from the recorder
Eric Laurent357263d2013-09-09 10:31:59 -0700567 ssize_t readSize = lpRecorder->read(nativeFromJavaBuf,
Andy Hung0e9e2f32015-04-13 23:47:18 -0700568 capacity < sizeInBytes ? capacity : sizeInBytes,
569 isReadBlocking == JNI_TRUE /* blocking */);
Eric Laurent357263d2013-09-09 10:31:59 -0700570 if (readSize < 0) {
Andy Hung0e9e2f32015-04-13 23:47:18 -0700571 return interpretReadSizeError(readSize);
Eric Laurent357263d2013-09-09 10:31:59 -0700572 }
573 return (jint)readSize;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800574}
575
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800576// ----------------------------------------------------------------------------
Andy Hunge90a0a82015-05-19 15:44:31 -0700577static jint android_media_AudioRecord_get_buffer_size_in_frames(JNIEnv *env, jobject thiz) {
Andy Hung864ae672015-04-14 11:06:48 -0700578 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
579 if (lpRecorder == NULL) {
580 jniThrowException(env, "java/lang/IllegalStateException",
Andy Hunge90a0a82015-05-19 15:44:31 -0700581 "Unable to retrieve AudioRecord pointer for frameCount()");
Andy Hung864ae672015-04-14 11:06:48 -0700582 return (jint)AUDIO_JAVA_ERROR;
583 }
584 return lpRecorder->frameCount();
585}
586
587// ----------------------------------------------------------------------------
Glenn Kasten18db49a2012-03-12 16:29:55 -0700588static jint android_media_AudioRecord_set_marker_pos(JNIEnv *env, jobject thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800589 jint markerPos) {
Glenn Kasten18db49a2012-03-12 16:29:55 -0700590
Eric Laurent532bc1c2012-04-20 12:45:03 -0700591 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
592 if (lpRecorder == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800593 jniThrowException(env, "java/lang/IllegalStateException",
594 "Unable to retrieve AudioRecord pointer for setMarkerPosition()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700595 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596 }
Eric Laurentbc11a692014-05-16 12:19:25 -0700597 return nativeToJavaStatus( lpRecorder->setMarkerPosition(markerPos) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598}
599
600
601// ----------------------------------------------------------------------------
602static jint android_media_AudioRecord_get_marker_pos(JNIEnv *env, jobject thiz) {
Glenn Kasten18db49a2012-03-12 16:29:55 -0700603
Eric Laurent532bc1c2012-04-20 12:45:03 -0700604 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800605 uint32_t markerPos = 0;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700606
Eric Laurent532bc1c2012-04-20 12:45:03 -0700607 if (lpRecorder == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800608 jniThrowException(env, "java/lang/IllegalStateException",
609 "Unable to retrieve AudioRecord pointer for getMarkerPosition()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700610 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800611 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700612 lpRecorder->getMarkerPosition(&markerPos);
613 return (jint)markerPos;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800614}
615
616
617// ----------------------------------------------------------------------------
618static jint android_media_AudioRecord_set_pos_update_period(JNIEnv *env, jobject thiz,
619 jint period) {
Glenn Kasten18db49a2012-03-12 16:29:55 -0700620
Eric Laurent532bc1c2012-04-20 12:45:03 -0700621 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700622
Eric Laurent532bc1c2012-04-20 12:45:03 -0700623 if (lpRecorder == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800624 jniThrowException(env, "java/lang/IllegalStateException",
625 "Unable to retrieve AudioRecord pointer for setPositionUpdatePeriod()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700626 return (jint)AUDIO_JAVA_ERROR;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700627 }
Eric Laurentbc11a692014-05-16 12:19:25 -0700628 return nativeToJavaStatus( lpRecorder->setPositionUpdatePeriod(period) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800629}
630
631
632// ----------------------------------------------------------------------------
633static jint android_media_AudioRecord_get_pos_update_period(JNIEnv *env, jobject thiz) {
Glenn Kasten18db49a2012-03-12 16:29:55 -0700634
Eric Laurent532bc1c2012-04-20 12:45:03 -0700635 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800636 uint32_t period = 0;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700637
Eric Laurent532bc1c2012-04-20 12:45:03 -0700638 if (lpRecorder == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800639 jniThrowException(env, "java/lang/IllegalStateException",
640 "Unable to retrieve AudioRecord pointer for getPositionUpdatePeriod()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700641 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800642 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700643 lpRecorder->getPositionUpdatePeriod(&period);
644 return (jint)period;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800645}
646
647
648// ----------------------------------------------------------------------------
649// returns the minimum required size for the successful creation of an AudioRecord instance.
650// returns 0 if the parameter combination is not supported.
651// return -1 if there was an error querying the buffer size.
652static jint android_media_AudioRecord_get_min_buff_size(JNIEnv *env, jobject thiz,
Glenn Kasten5b8fd442013-11-14 09:44:14 -0800653 jint sampleRateInHertz, jint channelCount, jint audioFormat) {
Chia-chi Yehc3308072010-08-19 17:14:36 +0800654
Eric Laurent532bc1c2012-04-20 12:45:03 -0700655 ALOGV(">> android_media_AudioRecord_get_min_buff_size(%d, %d, %d)",
Glenn Kasten5b8fd442013-11-14 09:44:14 -0800656 sampleRateInHertz, channelCount, audioFormat);
Chia-chi Yehc3308072010-08-19 17:14:36 +0800657
Glenn Kastenfd1e3df2012-11-13 15:21:06 -0800658 size_t frameCount = 0;
Glenn Kastena5a42382013-12-19 12:34:56 -0800659 audio_format_t format = audioFormatToNative(audioFormat);
Chia-chi Yehc3308072010-08-19 17:14:36 +0800660 status_t result = AudioRecord::getMinFrameCount(&frameCount,
661 sampleRateInHertz,
Glenn Kastena5a42382013-12-19 12:34:56 -0800662 format,
Glenn Kasten5b8fd442013-11-14 09:44:14 -0800663 audio_channel_in_mask_from_count(channelCount));
Chia-chi Yehc3308072010-08-19 17:14:36 +0800664
665 if (result == BAD_VALUE) {
666 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 }
Chia-chi Yehc3308072010-08-19 17:14:36 +0800668 if (result != NO_ERROR) {
669 return -1;
670 }
Glenn Kasten5b8fd442013-11-14 09:44:14 -0800671 return frameCount * channelCount * audio_bytes_per_sample(format);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800672}
673
Paul McLean2d6de4c2015-04-17 13:13:28 -0600674static jboolean android_media_AudioRecord_setInputDevice(
675 JNIEnv *env, jobject thiz, jint device_id) {
676
Paul McLean6bd27e12015-04-24 14:01:29 -0600677 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
Eric Laurent4bcdba82015-05-01 11:37:49 -0700678 if (lpRecorder == 0) {
Paul McLeancef696e2015-05-21 08:51:18 -0700679 return false;
Eric Laurent4bcdba82015-05-01 11:37:49 -0700680 }
Paul McLean6bd27e12015-04-24 14:01:29 -0600681 return lpRecorder->setInputDevice(device_id) == NO_ERROR;
Paul McLean2d6de4c2015-04-17 13:13:28 -0600682}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800683
Eric Laurent4bcdba82015-05-01 11:37:49 -0700684static jint android_media_AudioRecord_getRoutedDeviceId(
685 JNIEnv *env, jobject thiz) {
686
687 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
688 if (lpRecorder == 0) {
689 return 0;
690 }
691 return (jint)lpRecorder->getRoutedDeviceId();
692}
693
694static void android_media_AudioRecord_enableDeviceCallback(
695 JNIEnv *env, jobject thiz) {
696
697 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
698 if (lpRecorder == 0) {
699 return;
700 }
701 sp<JNIDeviceCallback> cb = getJniDeviceCallback(env, thiz);
702 if (cb != 0) {
703 return;
704 }
705 audiorecord_callback_cookie *cookie =
706 (audiorecord_callback_cookie *)env->GetLongField(thiz,
707 javaAudioRecordFields.nativeCallbackCookie);
708 if (cookie == NULL) {
709 return;
710 }
711
712 cb = new JNIDeviceCallback(env, thiz, cookie->audioRecord_ref,
713 javaAudioRecordFields.postNativeEventInJava);
714 status_t status = lpRecorder->addAudioDeviceCallback(cb);
715 if (status == NO_ERROR) {
716 setJniDeviceCallback(env, thiz, cb);
717 }
718}
719
720static void android_media_AudioRecord_disableDeviceCallback(
721 JNIEnv *env, jobject thiz) {
722
723 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
724 if (lpRecorder == 0) {
725 return;
726 }
727 sp<JNIDeviceCallback> cb = setJniDeviceCallback(env, thiz, 0);
728 if (cb != 0) {
729 lpRecorder->removeAudioDeviceCallback(cb);
730 }
731}
732
Andy Hung0ad99c02016-01-15 17:53:47 -0800733// ----------------------------------------------------------------------------
734static jint android_media_AudioRecord_get_timestamp(JNIEnv *env, jobject thiz,
735 jobject timestamp, jint timebase) {
736 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
Eric Laurent4bcdba82015-05-01 11:37:49 -0700737
Andy Hung0ad99c02016-01-15 17:53:47 -0800738 if (lpRecorder == NULL) {
739 jniThrowException(env, "java/lang/IllegalStateException",
740 "Unable to retrieve AudioRecord pointer for getTimestamp()");
741 return (jint)AUDIO_JAVA_ERROR;
742 }
743
Andy Hung0ad99c02016-01-15 17:53:47 -0800744 ExtendedTimestamp ts;
Andy Hungf4d81bd2016-01-28 17:47:56 -0800745 jint status = nativeToJavaStatus(lpRecorder->getTimestamp(&ts));
Andy Hung0ad99c02016-01-15 17:53:47 -0800746
747 if (status == AUDIO_JAVA_SUCCESS) {
748 // set the data
749 int64_t position, time;
750
751 status = nativeToJavaStatus(ts.getBestTimestamp(&position, &time, timebase));
752 if (status == AUDIO_JAVA_SUCCESS) {
753 env->SetLongField(
754 timestamp, javaAudioTimestampFields.fieldFramePosition, position);
755 env->SetLongField(
756 timestamp, javaAudioTimestampFields.fieldNanoTime, time);
757 }
758 }
759 return status;
Andy Hung0ad99c02016-01-15 17:53:47 -0800760}
Eric Laurent4bcdba82015-05-01 11:37:49 -0700761
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800762// ----------------------------------------------------------------------------
Ray Essick510225b2018-01-24 14:27:16 -0800763static jobject
764android_media_AudioRecord_native_getMetrics(JNIEnv *env, jobject thiz)
765{
766 ALOGV("android_media_AudioRecord_native_getMetrics");
767
768 sp<AudioRecord> lpRecord = getAudioRecord(env, thiz);
769
770 if (lpRecord == NULL) {
771 ALOGE("Unable to retrieve AudioRecord pointer for getMetrics()");
772 jniThrowException(env, "java/lang/IllegalStateException", NULL);
773 return (jobject) NULL;
774 }
775
776 // get what we have for the metrics from the record session
777 MediaAnalyticsItem *item = NULL;
778
779 status_t err = lpRecord->getMetrics(item);
780 if (err != OK) {
781 ALOGE("getMetrics failed");
782 jniThrowException(env, "java/lang/IllegalStateException", NULL);
783 return (jobject) NULL;
784 }
785
786 jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL /* mybundle */);
787
788 // housekeeping
789 delete item;
790 item = NULL;
791
792 return mybundle;
793}
794
795// ----------------------------------------------------------------------------
jiabin23675f62018-01-17 18:05:25 -0800796static jint android_media_AudioRecord_get_active_microphones(JNIEnv *env,
797 jobject thiz, jobject jActiveMicrophones) {
798 if (jActiveMicrophones == NULL) {
799 ALOGE("jActiveMicrophones is null");
800 return (jint)AUDIO_JAVA_BAD_VALUE;
801 }
802 if (!env->IsInstanceOf(jActiveMicrophones, gArrayListClass)) {
803 ALOGE("getActiveMicrophones not an arraylist");
804 return (jint)AUDIO_JAVA_BAD_VALUE;
805 }
806
807 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
808 if (lpRecorder == NULL) {
809 jniThrowException(env, "java/lang/IllegalStateException",
810 "Unable to retrieve AudioRecord pointer for getActiveMicrophones()");
811 return (jint)AUDIO_JAVA_ERROR;
812 }
813
814 jint jStatus = AUDIO_JAVA_SUCCESS;
815 std::vector<media::MicrophoneInfo> activeMicrophones;
816 status_t status = lpRecorder->getActiveMicrophones(&activeMicrophones);
817 if (status != NO_ERROR) {
818 ALOGE_IF(status != NO_ERROR, "AudioRecord::getActiveMicrophones error %d", status);
819 jStatus = nativeToJavaStatus(status);
820 return jStatus;
821 }
822
823 for (size_t i = 0; i < activeMicrophones.size(); i++) {
824 jobject jMicrophoneInfo;
825 jStatus = convertMicrophoneInfoFromNative(env, &jMicrophoneInfo, &activeMicrophones[i]);
826 if (jStatus != AUDIO_JAVA_SUCCESS) {
827 return jStatus;
828 }
829 env->CallBooleanMethod(jActiveMicrophones, gArrayListMethods.add, jMicrophoneInfo);
830 env->DeleteLocalRef(jMicrophoneInfo);
831 }
832 return jStatus;
833}
834
835// ----------------------------------------------------------------------------
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800836// ----------------------------------------------------------------------------
Daniel Micay76f6a862015-09-19 17:31:01 -0400837static const JNINativeMethod gMethods[] = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800838 // name, signature, funcPtr
Eric Laurent505e5c82012-03-29 15:19:36 -0700839 {"native_start", "(II)I", (void *)android_media_AudioRecord_start},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800840 {"native_stop", "()V", (void *)android_media_AudioRecord_stop},
Paul McLean9b09e532016-01-26 14:43:35 -0700841 {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;[IIIII[ILjava/lang/String;J)I",
842 (void *)android_media_AudioRecord_setup},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800843 {"native_finalize", "()V", (void *)android_media_AudioRecord_finalize},
844 {"native_release", "()V", (void *)android_media_AudioRecord_release},
Glenn Kasten18db49a2012-03-12 16:29:55 -0700845 {"native_read_in_byte_array",
Andy Hung0e9e2f32015-04-13 23:47:18 -0700846 "([BIIZ)I",
847 (void *)android_media_AudioRecord_readInArray<jbyteArray>},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800848 {"native_read_in_short_array",
Andy Hung0e9e2f32015-04-13 23:47:18 -0700849 "([SIIZ)I",
850 (void *)android_media_AudioRecord_readInArray<jshortArray>},
Andy Hung58b0f3f2015-03-27 17:59:45 -0700851 {"native_read_in_float_array",
Andy Hung0e9e2f32015-04-13 23:47:18 -0700852 "([FIIZ)I",
853 (void *)android_media_AudioRecord_readInArray<jfloatArray>},
854 {"native_read_in_direct_buffer","(Ljava/lang/Object;IZ)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855 (void *)android_media_AudioRecord_readInDirectBuffer},
Andy Hunge90a0a82015-05-19 15:44:31 -0700856 {"native_get_buffer_size_in_frames",
857 "()I", (void *)android_media_AudioRecord_get_buffer_size_in_frames},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800858 {"native_set_marker_pos","(I)I", (void *)android_media_AudioRecord_set_marker_pos},
859 {"native_get_marker_pos","()I", (void *)android_media_AudioRecord_get_marker_pos},
860 {"native_set_pos_update_period",
861 "(I)I", (void *)android_media_AudioRecord_set_pos_update_period},
862 {"native_get_pos_update_period",
863 "()I", (void *)android_media_AudioRecord_get_pos_update_period},
864 {"native_get_min_buff_size",
865 "(III)I", (void *)android_media_AudioRecord_get_min_buff_size},
Ray Essick510225b2018-01-24 14:27:16 -0800866 {"native_getMetrics", "()Landroid/os/PersistableBundle;",
867 (void *)android_media_AudioRecord_native_getMetrics},
Paul McLean2d6de4c2015-04-17 13:13:28 -0600868 {"native_setInputDevice", "(I)Z", (void *)android_media_AudioRecord_setInputDevice},
Eric Laurent4bcdba82015-05-01 11:37:49 -0700869 {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioRecord_getRoutedDeviceId},
870 {"native_enableDeviceCallback", "()V", (void *)android_media_AudioRecord_enableDeviceCallback},
871 {"native_disableDeviceCallback", "()V",
872 (void *)android_media_AudioRecord_disableDeviceCallback},
Andy Hung0ad99c02016-01-15 17:53:47 -0800873 {"native_get_timestamp", "(Landroid/media/AudioTimestamp;I)I",
874 (void *)android_media_AudioRecord_get_timestamp},
jiabin23675f62018-01-17 18:05:25 -0800875 {"native_get_active_microphones", "(Ljava/util/ArrayList;)I",
876 (void *)android_media_AudioRecord_get_active_microphones},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800877};
878
879// field names found in android/media/AudioRecord.java
880#define JAVA_POSTEVENT_CALLBACK_NAME "postEventFromNative"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800881#define JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME "mNativeRecorderInJavaObj"
882#define JAVA_NATIVECALLBACKINFO_FIELD_NAME "mNativeCallbackCookie"
Eric Laurent4bcdba82015-05-01 11:37:49 -0700883#define JAVA_NATIVEDEVICECALLBACK_FIELD_NAME "mNativeDeviceCallback"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800884
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800885// ----------------------------------------------------------------------------
886int register_android_media_AudioRecord(JNIEnv *env)
887{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800888 javaAudioRecordFields.postNativeEventInJava = NULL;
889 javaAudioRecordFields.nativeRecorderInJavaObj = NULL;
890 javaAudioRecordFields.nativeCallbackCookie = NULL;
Eric Laurent4bcdba82015-05-01 11:37:49 -0700891 javaAudioRecordFields.nativeDeviceCallback = NULL;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700892
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800893
894 // Get the AudioRecord class
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800895 jclass audioRecordClass = FindClassOrDie(env, kClassPathName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800896 // Get the postEvent method
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800897 javaAudioRecordFields.postNativeEventInJava = GetStaticMethodIDOrDie(env,
898 audioRecordClass, JAVA_POSTEVENT_CALLBACK_NAME,
899 "(Ljava/lang/Object;IIILjava/lang/Object;)V");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800900
901 // Get the variables
902 // mNativeRecorderInJavaObj
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800903 javaAudioRecordFields.nativeRecorderInJavaObj = GetFieldIDOrDie(env,
904 audioRecordClass, JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME, "J");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800905 // mNativeCallbackCookie
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800906 javaAudioRecordFields.nativeCallbackCookie = GetFieldIDOrDie(env,
907 audioRecordClass, JAVA_NATIVECALLBACKINFO_FIELD_NAME, "J");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800908
Eric Laurent4bcdba82015-05-01 11:37:49 -0700909 javaAudioRecordFields.nativeDeviceCallback = GetFieldIDOrDie(env,
910 audioRecordClass, JAVA_NATIVEDEVICECALLBACK_FIELD_NAME, "J");
911
Jean-Michel Trivi701d6ff2014-07-16 07:51:22 -0700912 // Get the AudioAttributes class and fields
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800913 jclass audioAttrClass = FindClassOrDie(env, kAudioAttributesClassPathName);
914 javaAudioAttrFields.fieldRecSource = GetFieldIDOrDie(env, audioAttrClass, "mSource", "I");
915 javaAudioAttrFields.fieldFlags = GetFieldIDOrDie(env, audioAttrClass, "mFlags", "I");
916 javaAudioAttrFields.fieldFormattedTags = GetFieldIDOrDie(env,
917 audioAttrClass, "mFormattedTags", "Ljava/lang/String;");
Jean-Michel Trivi701d6ff2014-07-16 07:51:22 -0700918
Andy Hung0ad99c02016-01-15 17:53:47 -0800919 // Get the RecordTimestamp class and fields
920 jclass audioTimestampClass = FindClassOrDie(env, "android/media/AudioTimestamp");
921 javaAudioTimestampFields.fieldFramePosition =
922 GetFieldIDOrDie(env, audioTimestampClass, "framePosition", "J");
923 javaAudioTimestampFields.fieldNanoTime =
924 GetFieldIDOrDie(env, audioTimestampClass, "nanoTime", "J");
925
jiabin23675f62018-01-17 18:05:25 -0800926 jclass arrayListClass = FindClassOrDie(env, "java/util/ArrayList");
927 gArrayListClass = MakeGlobalRefOrDie(env, arrayListClass);
928 gArrayListMethods.add = GetMethodIDOrDie(env, arrayListClass, "add", "(Ljava/lang/Object;)Z");
929
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800930 return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800931}
932
933// ----------------------------------------------------------------------------