blob: 6904fda1bef878f0b374d2ac9f193a122e084b15 [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>
23#include <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>
Dima Zavin24fc2fb2011-04-19 22:30:36 -070028
Svet Ganovfa5ecdc2015-04-28 12:03:28 -070029#include <ScopedUtfChars.h>
30
Glenn Kastenfe834d32014-01-08 14:49:08 -080031#include "android_media_AudioFormat.h"
Eric Laurentbc11a692014-05-16 12:19:25 -070032#include "android_media_AudioErrors.h"
Eric Laurent4bcdba82015-05-01 11:37:49 -070033#include "android_media_DeviceCallback.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034
35// ----------------------------------------------------------------------------
36
37using namespace android;
38
39// ----------------------------------------------------------------------------
40static const char* const kClassPathName = "android/media/AudioRecord";
Jean-Michel Trivi701d6ff2014-07-16 07:51:22 -070041static const char* const kAudioAttributesClassPathName = "android/media/AudioAttributes";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042
Jean-Michel Trivi701d6ff2014-07-16 07:51:22 -070043struct audio_record_fields_t {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044 // these fields provide access from C++ to the...
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045 jmethodID postNativeEventInJava; //... event post callback method
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046 jfieldID nativeRecorderInJavaObj; // provides access to the C++ AudioRecord object
47 jfieldID nativeCallbackCookie; // provides access to the AudioRecord callback data
Eric Laurent4bcdba82015-05-01 11:37:49 -070048 jfieldID nativeDeviceCallback; // provides access to the JNIDeviceCallback instance
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049};
Jean-Michel Trivi701d6ff2014-07-16 07:51:22 -070050struct audio_attributes_fields_t {
51 jfieldID fieldRecSource; // AudioAttributes.mSource
Eric Laurentbdad1af2014-09-19 17:43:29 -070052 jfieldID fieldFlags; // AudioAttributes.mFlags
Jean-Michel Trivi701d6ff2014-07-16 07:51:22 -070053 jfieldID fieldFormattedTags;// AudioAttributes.mFormattedTags
54};
55static audio_attributes_fields_t javaAudioAttrFields;
56static audio_record_fields_t javaAudioRecordFields;
Andy Hung0ad99c02016-01-15 17:53:47 -080057static struct {
58 jfieldID fieldFramePosition; // AudioTimestamp.framePosition
59 jfieldID fieldNanoTime; // AudioTimestamp.nanoTime
60} javaAudioTimestampFields;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061
62struct audiorecord_callback_cookie {
63 jclass audioRecord_class;
64 jobject audioRecord_ref;
Eric Laurent532bc1c2012-04-20 12:45:03 -070065 bool busy;
66 Condition cond;
67};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068
Eric Laurent532bc1c2012-04-20 12:45:03 -070069static Mutex sLock;
70static SortedVector <audiorecord_callback_cookie *> sAudioRecordCallBackCookies;
Dave Sparkse6335c92010-03-13 17:08:22 -080071
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072// ----------------------------------------------------------------------------
73
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074#define AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT -16
Eric Laurenta553c252009-07-17 12:17:14 -070075#define AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK -17
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076#define AUDIORECORD_ERROR_SETUP_INVALIDFORMAT -18
Eric Laurent4bc035a2009-05-22 09:18:15 -070077#define AUDIORECORD_ERROR_SETUP_INVALIDSOURCE -19
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078#define AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED -20
79
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080// ----------------------------------------------------------------------------
81static void recorderCallback(int event, void* user, void *info) {
Eric Laurent532bc1c2012-04-20 12:45:03 -070082
83 audiorecord_callback_cookie *callbackInfo = (audiorecord_callback_cookie *)user;
84 {
85 Mutex::Autolock l(sLock);
86 if (sAudioRecordCallBackCookies.indexOf(callbackInfo) < 0) {
87 return;
88 }
89 callbackInfo->busy = true;
90 }
Glenn Kasten18db49a2012-03-12 16:29:55 -070091
Glenn Kasten5b1576c2013-07-18 16:58:19 -070092 switch (event) {
93 case AudioRecord::EVENT_MARKER: {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094 JNIEnv *env = AndroidRuntime::getJNIEnv();
Glenn Kastena667ff32013-07-22 07:36:34 -070095 if (user != NULL && env != NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096 env->CallStaticVoidMethod(
Glenn Kasten18db49a2012-03-12 16:29:55 -070097 callbackInfo->audioRecord_class,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098 javaAudioRecordFields.postNativeEventInJava,
99 callbackInfo->audioRecord_ref, event, 0,0, NULL);
100 if (env->ExceptionCheck()) {
101 env->ExceptionDescribe();
102 env->ExceptionClear();
103 }
104 }
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700105 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700107 case AudioRecord::EVENT_NEW_POS: {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108 JNIEnv *env = AndroidRuntime::getJNIEnv();
Glenn Kastena667ff32013-07-22 07:36:34 -0700109 if (user != NULL && env != NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110 env->CallStaticVoidMethod(
Glenn Kasten18db49a2012-03-12 16:29:55 -0700111 callbackInfo->audioRecord_class,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112 javaAudioRecordFields.postNativeEventInJava,
113 callbackInfo->audioRecord_ref, event, 0,0, NULL);
114 if (env->ExceptionCheck()) {
115 env->ExceptionDescribe();
116 env->ExceptionClear();
117 }
118 }
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700119 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800120 }
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700121
Eric Laurent532bc1c2012-04-20 12:45:03 -0700122 {
123 Mutex::Autolock l(sLock);
124 callbackInfo->busy = false;
125 callbackInfo->cond.broadcast();
126 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127}
128
Eric Laurent4bcdba82015-05-01 11:37:49 -0700129static sp<JNIDeviceCallback> getJniDeviceCallback(JNIEnv* env, jobject thiz)
130{
131 Mutex::Autolock l(sLock);
132 JNIDeviceCallback* const cb =
133 (JNIDeviceCallback*)env->GetLongField(thiz,
134 javaAudioRecordFields.nativeDeviceCallback);
135 return sp<JNIDeviceCallback>(cb);
136}
137
138static sp<JNIDeviceCallback> setJniDeviceCallback(JNIEnv* env,
139 jobject thiz,
140 const sp<JNIDeviceCallback>& cb)
141{
142 Mutex::Autolock l(sLock);
143 sp<JNIDeviceCallback> old =
144 (JNIDeviceCallback*)env->GetLongField(thiz,
145 javaAudioRecordFields.nativeDeviceCallback);
146 if (cb.get()) {
147 cb->incStrong((void*)setJniDeviceCallback);
148 }
149 if (old != 0) {
150 old->decStrong((void*)setJniDeviceCallback);
151 }
152 env->SetLongField(thiz, javaAudioRecordFields.nativeDeviceCallback, (jlong)cb.get());
153 return old;
154}
155
Eric Laurent532bc1c2012-04-20 12:45:03 -0700156// ----------------------------------------------------------------------------
157static sp<AudioRecord> getAudioRecord(JNIEnv* env, jobject thiz)
158{
159 Mutex::Autolock l(sLock);
160 AudioRecord* const ar =
Ashok Bhat075e9a12014-01-06 13:45:09 +0000161 (AudioRecord*)env->GetLongField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700162 return sp<AudioRecord>(ar);
163}
164
165static sp<AudioRecord> setAudioRecord(JNIEnv* env, jobject thiz, const sp<AudioRecord>& ar)
166{
167 Mutex::Autolock l(sLock);
168 sp<AudioRecord> old =
Ashok Bhat075e9a12014-01-06 13:45:09 +0000169 (AudioRecord*)env->GetLongField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700170 if (ar.get()) {
Mathias Agopianb1d90c82013-03-06 17:45:42 -0800171 ar->incStrong((void*)setAudioRecord);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700172 }
173 if (old != 0) {
Mathias Agopianb1d90c82013-03-06 17:45:42 -0800174 old->decStrong((void*)setAudioRecord);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700175 }
Ashok Bhat075e9a12014-01-06 13:45:09 +0000176 env->SetLongField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj, (jlong)ar.get());
Eric Laurent532bc1c2012-04-20 12:45:03 -0700177 return old;
178}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179
180// ----------------------------------------------------------------------------
Ashok Bhat075e9a12014-01-06 13:45:09 +0000181static jint
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
Glenn Kasten1cbf9b32016-02-02 12:04:09 -0800183 jobject jaa, jintArray jSampleRate, jint channelMask, jint channelIndexMask,
Svet Ganovfa5ecdc2015-04-28 12:03:28 -0700184 jint audioFormat, jint buffSizeInBytes, jintArray jSession, jstring opPackageName)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185{
Glenn Kasten1cbf9b32016-02-02 12:04:09 -0800186 jint elements[1];
187 env->GetIntArrayRegion(jSampleRate, 0, 1, elements);
188 int sampleRateInHertz = elements[0];
189
Steve Block71f2cf12011-10-20 11:56:00 +0100190 //ALOGV(">> Entering android_media_AudioRecord_setup");
Glenn Kasten33c437d2013-07-18 17:04:21 -0700191 //ALOGV("sampleRate=%d, audioFormat=%d, channel mask=%x, buffSizeInBytes=%d",
192 // sampleRateInHertz, audioFormat, channelMask, buffSizeInBytes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800193
Jean-Michel Trivi701d6ff2014-07-16 07:51:22 -0700194 if (jaa == 0) {
195 ALOGE("Error creating AudioRecord: invalid audio attributes");
196 return (jint) AUDIO_JAVA_ERROR;
197 }
198
Andy Hung98d4ca62015-04-19 22:33:15 -0700199 // channel index mask takes priority over channel position masks.
200 if (channelIndexMask) {
201 // Java channel index masks need the representation bits set.
202 channelMask = audio_channel_mask_from_representation_and_bits(
203 AUDIO_CHANNEL_REPRESENTATION_INDEX,
204 channelIndexMask);
205 }
206 // Java channel position masks map directly to the native definition
207
Glenn Kasten33c437d2013-07-18 17:04:21 -0700208 if (!audio_is_input_channel(channelMask)) {
209 ALOGE("Error creating AudioRecord: channel mask %#x is not valid.", channelMask);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000210 return (jint) AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211 }
Eric Laurentdbf55662014-07-01 18:56:30 -0700212 uint32_t channelCount = audio_channel_count_from_in_mask(channelMask);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213
214 // compare the format against the Java constants
Glenn Kastena5a42382013-12-19 12:34:56 -0800215 audio_format_t format = audioFormatToNative(audioFormat);
216 if (format == AUDIO_FORMAT_INVALID) {
Glenn Kastena9838af2013-11-22 13:34:35 -0800217 ALOGE("Error creating AudioRecord: unsupported audio format %d.", audioFormat);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000218 return (jint) AUDIORECORD_ERROR_SETUP_INVALIDFORMAT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800219 }
220
Glenn Kastena5a42382013-12-19 12:34:56 -0800221 size_t bytesPerSample = audio_bytes_per_sample(format);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222
223 if (buffSizeInBytes == 0) {
Steve Block3762c312012-01-06 19:20:56 +0000224 ALOGE("Error creating AudioRecord: frameCount is 0.");
Ashok Bhat075e9a12014-01-06 13:45:09 +0000225 return (jint) AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226 }
Glenn Kasten5b8fd442013-11-14 09:44:14 -0800227 size_t frameSize = channelCount * bytesPerSample;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228 size_t frameCount = buffSizeInBytes / frameSize;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700229
Eric Laurent532bc1c2012-04-20 12:45:03 -0700230 jclass clazz = env->GetObjectClass(thiz);
231 if (clazz == NULL) {
232 ALOGE("Can't find %s when setting up callback.", kClassPathName);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000233 return (jint) AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
Eric Laurent532bc1c2012-04-20 12:45:03 -0700234 }
235
Eric Laurent44ff4cd2011-06-18 10:34:05 -0700236 if (jSession == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000237 ALOGE("Error creating AudioRecord: invalid session ID pointer");
Eric Laurentbc11a692014-05-16 12:19:25 -0700238 return (jint) AUDIO_JAVA_ERROR;
Eric Laurent44ff4cd2011-06-18 10:34:05 -0700239 }
240
241 jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
242 if (nSession == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000243 ALOGE("Error creating AudioRecord: Error retrieving session id pointer");
Eric Laurentbc11a692014-05-16 12:19:25 -0700244 return (jint) AUDIO_JAVA_ERROR;
Eric Laurent44ff4cd2011-06-18 10:34:05 -0700245 }
246 int sessionId = nSession[0];
247 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
248 nSession = NULL;
249
Svet Ganovfa5ecdc2015-04-28 12:03:28 -0700250 ScopedUtfChars opPackageNameStr(env, opPackageName);
251
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252 // create an uninitialized AudioRecord object
Svet Ganovfa5ecdc2015-04-28 12:03:28 -0700253 sp<AudioRecord> lpRecorder = new AudioRecord(String16(opPackageNameStr.c_str()));
Glenn Kasten18db49a2012-03-12 16:29:55 -0700254
Jean-Michel Trivi701d6ff2014-07-16 07:51:22 -0700255 audio_attributes_t *paa = NULL;
256 // read the AudioAttributes values
257 paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
258 const jstring jtags =
259 (jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags);
260 const char* tags = env->GetStringUTFChars(jtags, NULL);
261 // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it
262 strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
263 env->ReleaseStringUTFChars(jtags, tags);
264 paa->source = (audio_source_t) env->GetIntField(jaa, javaAudioAttrFields.fieldRecSource);
Eric Laurentbdad1af2014-09-19 17:43:29 -0700265 paa->flags = (audio_flags_mask_t)env->GetIntField(jaa, javaAudioAttrFields.fieldFlags);
266 ALOGV("AudioRecord_setup for source=%d tags=%s flags=%08x", paa->source, paa->tags, paa->flags);
Jean-Michel Trivi701d6ff2014-07-16 07:51:22 -0700267
Eric Laurentbdad1af2014-09-19 17:43:29 -0700268 audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE;
269 if (paa->flags & AUDIO_FLAG_HW_HOTWORD) {
270 flags = AUDIO_INPUT_FLAG_HW_HOTWORD;
271 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272 // create the callback information:
273 // this data will be passed with every AudioRecord callback
Eric Laurent532bc1c2012-04-20 12:45:03 -0700274 audiorecord_callback_cookie *lpCallbackData = new audiorecord_callback_cookie;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 lpCallbackData->audioRecord_class = (jclass)env->NewGlobalRef(clazz);
276 // we use a weak reference so the AudioRecord object can be garbage collected.
277 lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700278 lpCallbackData->busy = false;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700279
Jean-Michel Trivi701d6ff2014-07-16 07:51:22 -0700280 const status_t status = lpRecorder->set(paa->source,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281 sampleRateInHertz,
282 format, // word length, PCM
Glenn Kasten33c437d2013-07-18 17:04:21 -0700283 channelMask,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284 frameCount,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800285 recorderCallback,// callback_t
286 lpCallbackData,// void* user
287 0, // notificationFrames,
Glenn Kasten86fad472012-06-21 16:21:36 -0700288 true, // threadCanCallJava
Eric Laurentbdad1af2014-09-19 17:43:29 -0700289 sessionId,
290 AudioRecord::TRANSFER_DEFAULT,
Eric Laurent4c3fc59b2014-11-26 09:46:44 -0800291 flags,
Jean-Michel Trivi60e1dc22015-05-01 18:48:29 -0700292 -1, -1, // default uid, pid
Eric Laurent4c3fc59b2014-11-26 09:46:44 -0800293 paa);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294
Glenn Kastena9838af2013-11-22 13:34:35 -0800295 if (status != NO_ERROR) {
296 ALOGE("Error creating AudioRecord instance: initialization check failed with status %d.",
297 status);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800298 goto native_init_failure;
299 }
300
Eric Laurent44ff4cd2011-06-18 10:34:05 -0700301 nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
302 if (nSession == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000303 ALOGE("Error creating AudioRecord: Error retrieving session id pointer");
Eric Laurent44ff4cd2011-06-18 10:34:05 -0700304 goto native_init_failure;
305 }
Glenn Kastenb3db2132012-01-19 08:59:58 -0800306 // read the audio session ID back from AudioRecord in case a new session was created during set()
Eric Laurent44ff4cd2011-06-18 10:34:05 -0700307 nSession[0] = lpRecorder->getSessionId();
308 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
309 nSession = NULL;
310
Glenn Kasten1cbf9b32016-02-02 12:04:09 -0800311 {
312 const jint elements[1] = { (jint) lpRecorder->getSampleRate() };
313 env->SetIntArrayRegion(jSampleRate, 0, 1, elements);
314 }
315
Eric Laurent532bc1c2012-04-20 12:45:03 -0700316 { // scope for the lock
317 Mutex::Autolock l(sLock);
318 sAudioRecordCallBackCookies.add(lpCallbackData);
319 }
Glenn Kasten18db49a2012-03-12 16:29:55 -0700320 // save our newly created C++ AudioRecord in the "nativeRecorderInJavaObj" field
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800321 // of the Java object
Eric Laurent532bc1c2012-04-20 12:45:03 -0700322 setAudioRecord(env, thiz, lpRecorder);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700323
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800324 // save our newly created callback information in the "nativeCallbackCookie" field
325 // of the Java object (in mNativeCallbackCookie) so we can free the memory in finalize()
Ashok Bhat075e9a12014-01-06 13:45:09 +0000326 env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, (jlong)lpCallbackData);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700327
Eric Laurentbc11a692014-05-16 12:19:25 -0700328 return (jint) AUDIO_JAVA_SUCCESS;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700329
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330 // failure:
331native_init_failure:
Jean-Michel Trivi4bac5a32009-07-17 12:05:31 -0700332 env->DeleteGlobalRef(lpCallbackData->audioRecord_class);
333 env->DeleteGlobalRef(lpCallbackData->audioRecord_ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800334 delete lpCallbackData;
Ashok Bhat075e9a12014-01-06 13:45:09 +0000335 env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700336
Glenn Kasten14d226a2015-05-18 13:53:39 -0700337 // lpRecorder goes out of scope, so reference count drops to zero
Ashok Bhat075e9a12014-01-06 13:45:09 +0000338 return (jint) AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339}
340
341
342
343// ----------------------------------------------------------------------------
Ashok Bhat075e9a12014-01-06 13:45:09 +0000344static jint
Eric Laurent505e5c82012-03-29 15:19:36 -0700345android_media_AudioRecord_start(JNIEnv *env, jobject thiz, jint event, jint triggerSession)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700347 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 if (lpRecorder == NULL ) {
349 jniThrowException(env, "java/lang/IllegalStateException", NULL);
Eric Laurentbc11a692014-05-16 12:19:25 -0700350 return (jint) AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800351 }
Glenn Kasten18db49a2012-03-12 16:29:55 -0700352
Eric Laurentbc11a692014-05-16 12:19:25 -0700353 return nativeToJavaStatus(
Eric Laurent505e5c82012-03-29 15:19:36 -0700354 lpRecorder->start((AudioSystem::sync_event_t)event, triggerSession));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355}
356
357
358// ----------------------------------------------------------------------------
359static void
360android_media_AudioRecord_stop(JNIEnv *env, jobject thiz)
361{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700362 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363 if (lpRecorder == NULL ) {
364 jniThrowException(env, "java/lang/IllegalStateException", NULL);
365 return;
366 }
367
368 lpRecorder->stop();
Steve Block71f2cf12011-10-20 11:56:00 +0100369 //ALOGV("Called lpRecorder->stop()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370}
371
372
373// ----------------------------------------------------------------------------
Dave Sparkse6335c92010-03-13 17:08:22 -0800374
Eric Laurent532bc1c2012-04-20 12:45:03 -0700375#define CALLBACK_COND_WAIT_TIMEOUT_MS 1000
376static void android_media_AudioRecord_release(JNIEnv *env, jobject thiz) {
377 sp<AudioRecord> lpRecorder = setAudioRecord(env, thiz, 0);
378 if (lpRecorder == NULL) {
379 return;
380 }
Glenn Kasten2fbf25b2014-03-28 15:41:58 -0700381 ALOGV("About to delete lpRecorder: %p", lpRecorder.get());
Eric Laurent532bc1c2012-04-20 12:45:03 -0700382 lpRecorder->stop();
383
Ashok Bhat075e9a12014-01-06 13:45:09 +0000384 audiorecord_callback_cookie *lpCookie = (audiorecord_callback_cookie *)env->GetLongField(
Dave Sparkse6335c92010-03-13 17:08:22 -0800385 thiz, javaAudioRecordFields.nativeCallbackCookie);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386
Dave Sparkse6335c92010-03-13 17:08:22 -0800387 // reset the native resources in the Java object so any attempt to access
388 // them after a call to release fails.
Ashok Bhat075e9a12014-01-06 13:45:09 +0000389 env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0);
Dave Sparkse6335c92010-03-13 17:08:22 -0800390
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391 // delete the callback information
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800392 if (lpCookie) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700393 Mutex::Autolock l(sLock);
Glenn Kasten2fbf25b2014-03-28 15:41:58 -0700394 ALOGV("deleting lpCookie: %p", lpCookie);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700395 while (lpCookie->busy) {
396 if (lpCookie->cond.waitRelative(sLock,
397 milliseconds(CALLBACK_COND_WAIT_TIMEOUT_MS)) !=
398 NO_ERROR) {
399 break;
400 }
401 }
402 sAudioRecordCallBackCookies.remove(lpCookie);
Jean-Michel Trivi4bac5a32009-07-17 12:05:31 -0700403 env->DeleteGlobalRef(lpCookie->audioRecord_class);
404 env->DeleteGlobalRef(lpCookie->audioRecord_ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800405 delete lpCookie;
406 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800407}
408
409
410// ----------------------------------------------------------------------------
Dave Sparkse6335c92010-03-13 17:08:22 -0800411static void android_media_AudioRecord_finalize(JNIEnv *env, jobject thiz) {
412 android_media_AudioRecord_release(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413}
414
Andy Hung0e9e2f32015-04-13 23:47:18 -0700415// overloaded JNI array helper functions
416static inline
417jbyte *envGetArrayElements(JNIEnv *env, jbyteArray array, jboolean *isCopy) {
418 return env->GetByteArrayElements(array, isCopy);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800419}
420
Andy Hung0e9e2f32015-04-13 23:47:18 -0700421static inline
422void envReleaseArrayElements(JNIEnv *env, jbyteArray array, jbyte *elems, jint mode) {
423 env->ReleaseByteArrayElements(array, elems, mode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424}
425
Andy Hung0e9e2f32015-04-13 23:47:18 -0700426static inline
427jshort *envGetArrayElements(JNIEnv *env, jshortArray array, jboolean *isCopy) {
428 return env->GetShortArrayElements(array, isCopy);
429}
430
431static inline
432void envReleaseArrayElements(JNIEnv *env, jshortArray array, jshort *elems, jint mode) {
433 env->ReleaseShortArrayElements(array, elems, mode);
434}
435
436static inline
437jfloat *envGetArrayElements(JNIEnv *env, jfloatArray array, jboolean *isCopy) {
438 return env->GetFloatArrayElements(array, isCopy);
439}
440
441static inline
442void envReleaseArrayElements(JNIEnv *env, jfloatArray array, jfloat *elems, jint mode) {
443 env->ReleaseFloatArrayElements(array, elems, mode);
444}
445
446static inline
447jint interpretReadSizeError(ssize_t readSize) {
448 ALOGE_IF(readSize != WOULD_BLOCK, "Error %zd during AudioRecord native read", readSize);
449 switch (readSize) {
450 case WOULD_BLOCK:
451 return (jint)0;
452 case BAD_VALUE:
453 return (jint)AUDIO_JAVA_BAD_VALUE;
454 default:
455 // may be possible for other errors such as
456 // NO_INIT to happen if restoreRecord_l fails.
457 case INVALID_OPERATION:
458 return (jint)AUDIO_JAVA_INVALID_OPERATION;
459 }
460}
461
462template <typename T>
463static jint android_media_AudioRecord_readInArray(JNIEnv *env, jobject thiz,
464 T javaAudioData,
465 jint offsetInSamples, jint sizeInSamples,
466 jboolean isReadBlocking) {
Andy Hung58b0f3f2015-03-27 17:59:45 -0700467 // get the audio recorder from which we'll read new audio samples
468 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
469 if (lpRecorder == NULL) {
470 ALOGE("Unable to retrieve AudioRecord object");
471 return (jint)AUDIO_JAVA_INVALID_OPERATION;
472 }
473
474 if (javaAudioData == NULL) {
Andy Hung0e9e2f32015-04-13 23:47:18 -0700475 ALOGE("Invalid Java array to store recorded audio");
476 return (jint)AUDIO_JAVA_BAD_VALUE;
477 }
Andy Hung58b0f3f2015-03-27 17:59:45 -0700478
Andy Hung58b0f3f2015-03-27 17:59:45 -0700479 // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
480 // a way that it becomes much more efficient. When doing so, we will have to prevent the
481 // AudioSystem callback to be called while in critical section (in case of media server
482 // process crash for instance)
Andy Hung0e9e2f32015-04-13 23:47:18 -0700483
484 // get the pointer to where we'll record the audio
485 auto *recordBuff = envGetArrayElements(env, javaAudioData, NULL);
Andy Hung58b0f3f2015-03-27 17:59:45 -0700486 if (recordBuff == NULL) {
487 ALOGE("Error retrieving destination for recorded audio data");
488 return (jint)AUDIO_JAVA_BAD_VALUE;
489 }
490
491 // read the new audio data from the native AudioRecord object
Andy Hung0e9e2f32015-04-13 23:47:18 -0700492 const size_t sizeInBytes = sizeInSamples * sizeof(*recordBuff);
493 ssize_t readSize = lpRecorder->read(
494 recordBuff + offsetInSamples, sizeInBytes, isReadBlocking == JNI_TRUE /* blocking */);
Andy Hung58b0f3f2015-03-27 17:59:45 -0700495
Andy Hung0e9e2f32015-04-13 23:47:18 -0700496 envReleaseArrayElements(env, javaAudioData, recordBuff, 0);
Andy Hung58b0f3f2015-03-27 17:59:45 -0700497
498 if (readSize < 0) {
Andy Hung0e9e2f32015-04-13 23:47:18 -0700499 return interpretReadSizeError(readSize);
Andy Hung58b0f3f2015-03-27 17:59:45 -0700500 }
Andy Hung0e9e2f32015-04-13 23:47:18 -0700501 return (jint)(readSize / sizeof(*recordBuff));
Andy Hung58b0f3f2015-03-27 17:59:45 -0700502}
503
504// ----------------------------------------------------------------------------
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505static jint android_media_AudioRecord_readInDirectBuffer(JNIEnv *env, jobject thiz,
Andy Hung0e9e2f32015-04-13 23:47:18 -0700506 jobject jBuffer, jint sizeInBytes,
507 jboolean isReadBlocking) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508 // get the audio recorder from which we'll read new audio samples
Eric Laurent532bc1c2012-04-20 12:45:03 -0700509 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700510 if (lpRecorder==NULL)
Andy Hung0e9e2f32015-04-13 23:47:18 -0700511 return (jint)AUDIO_JAVA_INVALID_OPERATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800512
513 // direct buffer and direct access supported?
514 long capacity = env->GetDirectBufferCapacity(jBuffer);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700515 if (capacity == -1) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 // buffer direct access is not supported
Steve Block3762c312012-01-06 19:20:56 +0000517 ALOGE("Buffer direct access is not supported, can't record");
Andy Hung0e9e2f32015-04-13 23:47:18 -0700518 return (jint)AUDIO_JAVA_BAD_VALUE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800519 }
Steve Block71f2cf12011-10-20 11:56:00 +0100520 //ALOGV("capacity = %ld", capacity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800521 jbyte* nativeFromJavaBuf = (jbyte*) env->GetDirectBufferAddress(jBuffer);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700522 if (nativeFromJavaBuf==NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000523 ALOGE("Buffer direct access is not supported, can't record");
Andy Hung0e9e2f32015-04-13 23:47:18 -0700524 return (jint)AUDIO_JAVA_BAD_VALUE;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700525 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800526
527 // read new data from the recorder
Eric Laurent357263d2013-09-09 10:31:59 -0700528 ssize_t readSize = lpRecorder->read(nativeFromJavaBuf,
Andy Hung0e9e2f32015-04-13 23:47:18 -0700529 capacity < sizeInBytes ? capacity : sizeInBytes,
530 isReadBlocking == JNI_TRUE /* blocking */);
Eric Laurent357263d2013-09-09 10:31:59 -0700531 if (readSize < 0) {
Andy Hung0e9e2f32015-04-13 23:47:18 -0700532 return interpretReadSizeError(readSize);
Eric Laurent357263d2013-09-09 10:31:59 -0700533 }
534 return (jint)readSize;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800535}
536
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537// ----------------------------------------------------------------------------
Andy Hunge90a0a82015-05-19 15:44:31 -0700538static jint android_media_AudioRecord_get_buffer_size_in_frames(JNIEnv *env, jobject thiz) {
Andy Hung864ae672015-04-14 11:06:48 -0700539 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
540 if (lpRecorder == NULL) {
541 jniThrowException(env, "java/lang/IllegalStateException",
Andy Hunge90a0a82015-05-19 15:44:31 -0700542 "Unable to retrieve AudioRecord pointer for frameCount()");
Andy Hung864ae672015-04-14 11:06:48 -0700543 return (jint)AUDIO_JAVA_ERROR;
544 }
545 return lpRecorder->frameCount();
546}
547
548// ----------------------------------------------------------------------------
Glenn Kasten18db49a2012-03-12 16:29:55 -0700549static jint android_media_AudioRecord_set_marker_pos(JNIEnv *env, jobject thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800550 jint markerPos) {
Glenn Kasten18db49a2012-03-12 16:29:55 -0700551
Eric Laurent532bc1c2012-04-20 12:45:03 -0700552 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
553 if (lpRecorder == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800554 jniThrowException(env, "java/lang/IllegalStateException",
555 "Unable to retrieve AudioRecord pointer for setMarkerPosition()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700556 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 }
Eric Laurentbc11a692014-05-16 12:19:25 -0700558 return nativeToJavaStatus( lpRecorder->setMarkerPosition(markerPos) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800559}
560
561
562// ----------------------------------------------------------------------------
563static jint android_media_AudioRecord_get_marker_pos(JNIEnv *env, jobject thiz) {
Glenn Kasten18db49a2012-03-12 16:29:55 -0700564
Eric Laurent532bc1c2012-04-20 12:45:03 -0700565 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800566 uint32_t markerPos = 0;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700567
Eric Laurent532bc1c2012-04-20 12:45:03 -0700568 if (lpRecorder == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800569 jniThrowException(env, "java/lang/IllegalStateException",
570 "Unable to retrieve AudioRecord pointer for getMarkerPosition()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700571 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800572 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700573 lpRecorder->getMarkerPosition(&markerPos);
574 return (jint)markerPos;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800575}
576
577
578// ----------------------------------------------------------------------------
579static jint android_media_AudioRecord_set_pos_update_period(JNIEnv *env, jobject thiz,
580 jint period) {
Glenn Kasten18db49a2012-03-12 16:29:55 -0700581
Eric Laurent532bc1c2012-04-20 12:45:03 -0700582 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700583
Eric Laurent532bc1c2012-04-20 12:45:03 -0700584 if (lpRecorder == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800585 jniThrowException(env, "java/lang/IllegalStateException",
586 "Unable to retrieve AudioRecord pointer for setPositionUpdatePeriod()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700587 return (jint)AUDIO_JAVA_ERROR;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700588 }
Eric Laurentbc11a692014-05-16 12:19:25 -0700589 return nativeToJavaStatus( lpRecorder->setPositionUpdatePeriod(period) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800590}
591
592
593// ----------------------------------------------------------------------------
594static jint android_media_AudioRecord_get_pos_update_period(JNIEnv *env, jobject thiz) {
Glenn Kasten18db49a2012-03-12 16:29:55 -0700595
Eric Laurent532bc1c2012-04-20 12:45:03 -0700596 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800597 uint32_t period = 0;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700598
Eric Laurent532bc1c2012-04-20 12:45:03 -0700599 if (lpRecorder == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800600 jniThrowException(env, "java/lang/IllegalStateException",
601 "Unable to retrieve AudioRecord pointer for getPositionUpdatePeriod()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700602 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800603 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700604 lpRecorder->getPositionUpdatePeriod(&period);
605 return (jint)period;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800606}
607
608
609// ----------------------------------------------------------------------------
610// returns the minimum required size for the successful creation of an AudioRecord instance.
611// returns 0 if the parameter combination is not supported.
612// return -1 if there was an error querying the buffer size.
613static jint android_media_AudioRecord_get_min_buff_size(JNIEnv *env, jobject thiz,
Glenn Kasten5b8fd442013-11-14 09:44:14 -0800614 jint sampleRateInHertz, jint channelCount, jint audioFormat) {
Chia-chi Yehc3308072010-08-19 17:14:36 +0800615
Eric Laurent532bc1c2012-04-20 12:45:03 -0700616 ALOGV(">> android_media_AudioRecord_get_min_buff_size(%d, %d, %d)",
Glenn Kasten5b8fd442013-11-14 09:44:14 -0800617 sampleRateInHertz, channelCount, audioFormat);
Chia-chi Yehc3308072010-08-19 17:14:36 +0800618
Glenn Kastenfd1e3df2012-11-13 15:21:06 -0800619 size_t frameCount = 0;
Glenn Kastena5a42382013-12-19 12:34:56 -0800620 audio_format_t format = audioFormatToNative(audioFormat);
Chia-chi Yehc3308072010-08-19 17:14:36 +0800621 status_t result = AudioRecord::getMinFrameCount(&frameCount,
622 sampleRateInHertz,
Glenn Kastena5a42382013-12-19 12:34:56 -0800623 format,
Glenn Kasten5b8fd442013-11-14 09:44:14 -0800624 audio_channel_in_mask_from_count(channelCount));
Chia-chi Yehc3308072010-08-19 17:14:36 +0800625
626 if (result == BAD_VALUE) {
627 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800628 }
Chia-chi Yehc3308072010-08-19 17:14:36 +0800629 if (result != NO_ERROR) {
630 return -1;
631 }
Glenn Kasten5b8fd442013-11-14 09:44:14 -0800632 return frameCount * channelCount * audio_bytes_per_sample(format);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633}
634
Paul McLean2d6de4c2015-04-17 13:13:28 -0600635static jboolean android_media_AudioRecord_setInputDevice(
636 JNIEnv *env, jobject thiz, jint device_id) {
637
Paul McLean6bd27e12015-04-24 14:01:29 -0600638 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
Eric Laurent4bcdba82015-05-01 11:37:49 -0700639 if (lpRecorder == 0) {
Paul McLeancef696e2015-05-21 08:51:18 -0700640 return false;
Eric Laurent4bcdba82015-05-01 11:37:49 -0700641 }
Paul McLean6bd27e12015-04-24 14:01:29 -0600642 return lpRecorder->setInputDevice(device_id) == NO_ERROR;
Paul McLean2d6de4c2015-04-17 13:13:28 -0600643}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800644
Eric Laurent4bcdba82015-05-01 11:37:49 -0700645static jint android_media_AudioRecord_getRoutedDeviceId(
646 JNIEnv *env, jobject thiz) {
647
648 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
649 if (lpRecorder == 0) {
650 return 0;
651 }
652 return (jint)lpRecorder->getRoutedDeviceId();
653}
654
655static void android_media_AudioRecord_enableDeviceCallback(
656 JNIEnv *env, jobject thiz) {
657
658 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
659 if (lpRecorder == 0) {
660 return;
661 }
662 sp<JNIDeviceCallback> cb = getJniDeviceCallback(env, thiz);
663 if (cb != 0) {
664 return;
665 }
666 audiorecord_callback_cookie *cookie =
667 (audiorecord_callback_cookie *)env->GetLongField(thiz,
668 javaAudioRecordFields.nativeCallbackCookie);
669 if (cookie == NULL) {
670 return;
671 }
672
673 cb = new JNIDeviceCallback(env, thiz, cookie->audioRecord_ref,
674 javaAudioRecordFields.postNativeEventInJava);
675 status_t status = lpRecorder->addAudioDeviceCallback(cb);
676 if (status == NO_ERROR) {
677 setJniDeviceCallback(env, thiz, cb);
678 }
679}
680
681static void android_media_AudioRecord_disableDeviceCallback(
682 JNIEnv *env, jobject thiz) {
683
684 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
685 if (lpRecorder == 0) {
686 return;
687 }
688 sp<JNIDeviceCallback> cb = setJniDeviceCallback(env, thiz, 0);
689 if (cb != 0) {
690 lpRecorder->removeAudioDeviceCallback(cb);
691 }
692}
693
Andy Hung0ad99c02016-01-15 17:53:47 -0800694// ----------------------------------------------------------------------------
695static jint android_media_AudioRecord_get_timestamp(JNIEnv *env, jobject thiz,
696 jobject timestamp, jint timebase) {
697 sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
Eric Laurent4bcdba82015-05-01 11:37:49 -0700698
Andy Hung0ad99c02016-01-15 17:53:47 -0800699 if (lpRecorder == NULL) {
700 jniThrowException(env, "java/lang/IllegalStateException",
701 "Unable to retrieve AudioRecord pointer for getTimestamp()");
702 return (jint)AUDIO_JAVA_ERROR;
703 }
704
Andy Hung0ad99c02016-01-15 17:53:47 -0800705 ExtendedTimestamp ts;
Andy Hungf4d81bd2016-01-28 17:47:56 -0800706 jint status = nativeToJavaStatus(lpRecorder->getTimestamp(&ts));
Andy Hung0ad99c02016-01-15 17:53:47 -0800707
708 if (status == AUDIO_JAVA_SUCCESS) {
709 // set the data
710 int64_t position, time;
711
712 status = nativeToJavaStatus(ts.getBestTimestamp(&position, &time, timebase));
713 if (status == AUDIO_JAVA_SUCCESS) {
714 env->SetLongField(
715 timestamp, javaAudioTimestampFields.fieldFramePosition, position);
716 env->SetLongField(
717 timestamp, javaAudioTimestampFields.fieldNanoTime, time);
718 }
719 }
720 return status;
Andy Hung0ad99c02016-01-15 17:53:47 -0800721}
Eric Laurent4bcdba82015-05-01 11:37:49 -0700722
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800723// ----------------------------------------------------------------------------
724// ----------------------------------------------------------------------------
Daniel Micay76f6a862015-09-19 17:31:01 -0400725static const JNINativeMethod gMethods[] = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800726 // name, signature, funcPtr
Eric Laurent505e5c82012-03-29 15:19:36 -0700727 {"native_start", "(II)I", (void *)android_media_AudioRecord_start},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800728 {"native_stop", "()V", (void *)android_media_AudioRecord_stop},
Glenn Kasten1cbf9b32016-02-02 12:04:09 -0800729 {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;[IIIII[ILjava/lang/String;)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800730 (void *)android_media_AudioRecord_setup},
731 {"native_finalize", "()V", (void *)android_media_AudioRecord_finalize},
732 {"native_release", "()V", (void *)android_media_AudioRecord_release},
Glenn Kasten18db49a2012-03-12 16:29:55 -0700733 {"native_read_in_byte_array",
Andy Hung0e9e2f32015-04-13 23:47:18 -0700734 "([BIIZ)I",
735 (void *)android_media_AudioRecord_readInArray<jbyteArray>},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800736 {"native_read_in_short_array",
Andy Hung0e9e2f32015-04-13 23:47:18 -0700737 "([SIIZ)I",
738 (void *)android_media_AudioRecord_readInArray<jshortArray>},
Andy Hung58b0f3f2015-03-27 17:59:45 -0700739 {"native_read_in_float_array",
Andy Hung0e9e2f32015-04-13 23:47:18 -0700740 "([FIIZ)I",
741 (void *)android_media_AudioRecord_readInArray<jfloatArray>},
742 {"native_read_in_direct_buffer","(Ljava/lang/Object;IZ)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800743 (void *)android_media_AudioRecord_readInDirectBuffer},
Andy Hunge90a0a82015-05-19 15:44:31 -0700744 {"native_get_buffer_size_in_frames",
745 "()I", (void *)android_media_AudioRecord_get_buffer_size_in_frames},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800746 {"native_set_marker_pos","(I)I", (void *)android_media_AudioRecord_set_marker_pos},
747 {"native_get_marker_pos","()I", (void *)android_media_AudioRecord_get_marker_pos},
748 {"native_set_pos_update_period",
749 "(I)I", (void *)android_media_AudioRecord_set_pos_update_period},
750 {"native_get_pos_update_period",
751 "()I", (void *)android_media_AudioRecord_get_pos_update_period},
752 {"native_get_min_buff_size",
753 "(III)I", (void *)android_media_AudioRecord_get_min_buff_size},
Paul McLean2d6de4c2015-04-17 13:13:28 -0600754 {"native_setInputDevice", "(I)Z", (void *)android_media_AudioRecord_setInputDevice},
Eric Laurent4bcdba82015-05-01 11:37:49 -0700755 {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioRecord_getRoutedDeviceId},
756 {"native_enableDeviceCallback", "()V", (void *)android_media_AudioRecord_enableDeviceCallback},
757 {"native_disableDeviceCallback", "()V",
758 (void *)android_media_AudioRecord_disableDeviceCallback},
Andy Hung0ad99c02016-01-15 17:53:47 -0800759 {"native_get_timestamp", "(Landroid/media/AudioTimestamp;I)I",
760 (void *)android_media_AudioRecord_get_timestamp},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800761};
762
763// field names found in android/media/AudioRecord.java
764#define JAVA_POSTEVENT_CALLBACK_NAME "postEventFromNative"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800765#define JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME "mNativeRecorderInJavaObj"
766#define JAVA_NATIVECALLBACKINFO_FIELD_NAME "mNativeCallbackCookie"
Eric Laurent4bcdba82015-05-01 11:37:49 -0700767#define JAVA_NATIVEDEVICECALLBACK_FIELD_NAME "mNativeDeviceCallback"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800768
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800769// ----------------------------------------------------------------------------
770int register_android_media_AudioRecord(JNIEnv *env)
771{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800772 javaAudioRecordFields.postNativeEventInJava = NULL;
773 javaAudioRecordFields.nativeRecorderInJavaObj = NULL;
774 javaAudioRecordFields.nativeCallbackCookie = NULL;
Eric Laurent4bcdba82015-05-01 11:37:49 -0700775 javaAudioRecordFields.nativeDeviceCallback = NULL;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700776
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800777
778 // Get the AudioRecord class
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800779 jclass audioRecordClass = FindClassOrDie(env, kClassPathName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800780 // Get the postEvent method
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800781 javaAudioRecordFields.postNativeEventInJava = GetStaticMethodIDOrDie(env,
782 audioRecordClass, JAVA_POSTEVENT_CALLBACK_NAME,
783 "(Ljava/lang/Object;IIILjava/lang/Object;)V");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800784
785 // Get the variables
786 // mNativeRecorderInJavaObj
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800787 javaAudioRecordFields.nativeRecorderInJavaObj = GetFieldIDOrDie(env,
788 audioRecordClass, JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME, "J");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800789 // mNativeCallbackCookie
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800790 javaAudioRecordFields.nativeCallbackCookie = GetFieldIDOrDie(env,
791 audioRecordClass, JAVA_NATIVECALLBACKINFO_FIELD_NAME, "J");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800792
Eric Laurent4bcdba82015-05-01 11:37:49 -0700793 javaAudioRecordFields.nativeDeviceCallback = GetFieldIDOrDie(env,
794 audioRecordClass, JAVA_NATIVEDEVICECALLBACK_FIELD_NAME, "J");
795
Jean-Michel Trivi701d6ff2014-07-16 07:51:22 -0700796 // Get the AudioAttributes class and fields
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800797 jclass audioAttrClass = FindClassOrDie(env, kAudioAttributesClassPathName);
798 javaAudioAttrFields.fieldRecSource = GetFieldIDOrDie(env, audioAttrClass, "mSource", "I");
799 javaAudioAttrFields.fieldFlags = GetFieldIDOrDie(env, audioAttrClass, "mFlags", "I");
800 javaAudioAttrFields.fieldFormattedTags = GetFieldIDOrDie(env,
801 audioAttrClass, "mFormattedTags", "Ljava/lang/String;");
Jean-Michel Trivi701d6ff2014-07-16 07:51:22 -0700802
Andy Hung0ad99c02016-01-15 17:53:47 -0800803 // Get the RecordTimestamp class and fields
804 jclass audioTimestampClass = FindClassOrDie(env, "android/media/AudioTimestamp");
805 javaAudioTimestampFields.fieldFramePosition =
806 GetFieldIDOrDie(env, audioTimestampClass, "framePosition", "J");
807 javaAudioTimestampFields.fieldNanoTime =
808 GetFieldIDOrDie(env, audioTimestampClass, "nanoTime", "J");
809
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800810 return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800811}
812
813// ----------------------------------------------------------------------------