1 /*
2 * Copyright (C) 2015 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 #define LOG_TAG "audio-record-native"
19
20 #include "Blob.h"
21 #include "Gate.h"
22 #include "sl-utils.h"
23
24 #include <deque>
25 #include <utils/Errors.h>
26
27 // Select whether to use STL shared pointer or to use Android strong pointer.
28 // We really don't promote any sharing of this object for its lifetime, but nevertheless could
29 // change the shared pointer value on the fly if desired.
30 #define USE_SHARED_POINTER
31
32 #ifdef USE_SHARED_POINTER
33 #include <memory>
34 template <typename T> using shared_pointer = std::shared_ptr<T>;
35 #else
36 #include <utils/RefBase.h>
37 template <typename T> using shared_pointer = android::sp<T>;
38 #endif
39
40 using namespace android;
41
42 // Must be kept in sync with Java android.media.cts.AudioRecordNative.ReadFlags
43 enum {
44 READ_FLAG_BLOCKING = (1 << 0),
45 };
46
47 // buffer queue buffers on the OpenSL ES side.
48 // The choice can be >= 1. There is also internal buffering by AudioRecord.
49
50 static const size_t BUFFER_SIZE_MSEC = 20;
51
52 // TODO: Add a single buffer blocking read mode which does not require additional memory.
53 // TODO: Add internal buffer memory (e.g. use circular buffer, right now mallocs on heap).
54
55 class AudioRecordNative
56 #ifndef USE_SHARED_POINTER
57 : public RefBase // android strong pointers require RefBase
58 #endif
59 {
60 public:
AudioRecordNative()61 AudioRecordNative() :
62 mEngineObj(NULL),
63 mEngine(NULL),
64 mRecordObj(NULL),
65 mRecord(NULL),
66 mBufferQueue(NULL),
67 mRecordState(SL_RECORDSTATE_STOPPED),
68 mBufferSize(0),
69 mNumBuffers(0)
70 { }
71
~AudioRecordNative()72 ~AudioRecordNative() {
73 close();
74 }
75
76 typedef std::lock_guard<std::recursive_mutex> auto_lock;
77
open(uint32_t numChannels,uint32_t sampleRate,bool useFloat,uint32_t numBuffers)78 status_t open(uint32_t numChannels, uint32_t sampleRate, bool useFloat, uint32_t numBuffers) {
79 close();
80 auto_lock l(mLock);
81 mEngineObj = OpenSLEngine();
82 if (mEngineObj == NULL) {
83 ALOGW("cannot create OpenSL ES engine");
84 return INVALID_OPERATION;
85 }
86
87 SLresult res;
88 for (;;) {
89 /* Get the SL Engine Interface which is implicit */
90 res = (*mEngineObj)->GetInterface(mEngineObj, SL_IID_ENGINE, (void *)&mEngine);
91 if (res != SL_RESULT_SUCCESS) break;
92
93 SLDataLocator_IODevice locator_mic;
94 /* Setup the data source structure */
95 locator_mic.locatorType = SL_DATALOCATOR_IODEVICE;
96 locator_mic.deviceType = SL_IODEVICE_AUDIOINPUT;
97 locator_mic.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT;
98 locator_mic.device= NULL;
99 SLDataSource audioSource;
100 audioSource.pLocator = (void *)&locator_mic;
101 audioSource.pFormat = NULL;
102
103 // FIXME: Android requires SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE
104 // because the recorder makes the distinction from SL_DATALOCATOR_BUFFERQUEUE
105 // which the player does not.
106 SLDataLocator_AndroidSimpleBufferQueue loc_bq = {
107 SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, numBuffers
108 };
109 #if 0
110 SLDataFormat_PCM pcm = {
111 SL_DATAFORMAT_PCM, 1, SL_SAMPLINGRATE_16,
112 SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,
113 SL_SPEAKER_FRONT_LEFT, SL_BYTEORDER_LITTLEENDIAN
114 };
115 #else
116 SLAndroidDataFormat_PCM_EX pcm;
117 pcm.formatType = useFloat ? SL_ANDROID_DATAFORMAT_PCM_EX : SL_DATAFORMAT_PCM;
118 pcm.numChannels = numChannels;
119 pcm.sampleRate = sampleRate * 1000;
120 pcm.bitsPerSample = useFloat ?
121 SL_PCMSAMPLEFORMAT_FIXED_32 : SL_PCMSAMPLEFORMAT_FIXED_16;
122 pcm.containerSize = pcm.bitsPerSample;
123 pcm.channelMask = channelCountToMask(numChannels);
124 pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
125 // additional
126 pcm.representation = useFloat ? SL_ANDROID_PCM_REPRESENTATION_FLOAT
127 : SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT;
128 #endif
129 SLDataSink audioSink;
130 audioSink = { &loc_bq, &pcm };
131
132 SLboolean required[2];
133 SLInterfaceID iidArray[2];
134 /* Request the AndroidSimpleBufferQueue and AndroidConfiguration interfaces */
135 required[0] = SL_BOOLEAN_TRUE;
136 iidArray[0] = SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
137 required[1] = SL_BOOLEAN_TRUE;
138 iidArray[1] = SL_IID_ANDROIDCONFIGURATION;
139
140 ALOGV("creating recorder");
141 /* Create audio recorder */
142 res = (*mEngine)->CreateAudioRecorder(mEngine, &mRecordObj,
143 &audioSource, &audioSink, 2, iidArray, required);
144 if (res != SL_RESULT_SUCCESS) break;
145
146 ALOGV("realizing recorder");
147 /* Realizing the recorder in synchronous mode. */
148 res = (*mRecordObj)->Realize(mRecordObj, SL_BOOLEAN_FALSE /* async */);
149 if (res != SL_RESULT_SUCCESS) break;
150
151 ALOGV("geting record interface");
152 /* Get the RECORD interface - it is an implicit interface */
153 res = (*mRecordObj)->GetInterface(mRecordObj, SL_IID_RECORD, (void *)&mRecord);
154 if (res != SL_RESULT_SUCCESS) break;
155
156 ALOGV("geting buffer queue interface");
157 /* Get the buffer queue interface which was explicitly requested */
158 res = (*mRecordObj)->GetInterface(mRecordObj, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
159 (void *)&mBufferQueue);
160 if (res != SL_RESULT_SUCCESS) break;
161
162 ALOGV("registering buffer queue interface");
163 /* Setup to receive buffer queue event callbacks */
164 res = (*mBufferQueue)->RegisterCallback(mBufferQueue, BufferQueueCallback, this);
165 if (res != SL_RESULT_SUCCESS) break;
166
167 mBufferSize = (BUFFER_SIZE_MSEC * sampleRate / 1000)
168 * numChannels * (useFloat ? sizeof(float) : sizeof(int16_t));
169 mNumBuffers = numBuffers;
170 // success
171 break;
172 }
173 if (res != SL_RESULT_SUCCESS) {
174 close(); // should be safe to close even with lock held
175 ALOGW("open error %s", android::getSLErrStr(res));
176 return INVALID_OPERATION;
177 }
178 return OK;
179 }
180
close()181 void close() {
182 SLObjectItf engineObj;
183 SLObjectItf recordObj;
184 {
185 auto_lock l(mLock);
186 (void)stop();
187 // once stopped, we can unregister the callback
188 if (mBufferQueue != NULL) {
189 (void)(*mBufferQueue)->RegisterCallback(
190 mBufferQueue, NULL /* callback */, NULL /* *pContext */);
191 }
192 (void)flush();
193 engineObj = mEngineObj;
194 recordObj = mRecordObj;
195 // clear out interfaces and objects
196 mRecord = NULL;
197 mBufferQueue = NULL;
198 mEngine = NULL;
199 mRecordObj = NULL;
200 mEngineObj = NULL;
201 mRecordState = SL_RECORDSTATE_STOPPED;
202 mBufferSize = 0;
203 mNumBuffers = 0;
204 }
205 // destroy without lock
206 if (recordObj != NULL) {
207 (*recordObj)->Destroy(recordObj);
208 }
209 if (engineObj) {
210 CloseSLEngine(engineObj);
211 }
212 }
213
setRecordState(SLuint32 recordState)214 status_t setRecordState(SLuint32 recordState) {
215 auto_lock l(mLock);
216 if (mRecord == NULL) {
217 return INVALID_OPERATION;
218 }
219 if (recordState == SL_RECORDSTATE_RECORDING) {
220 queueBuffers();
221 }
222 SLresult res = (*mRecord)->SetRecordState(mRecord, recordState);
223 if (res != SL_RESULT_SUCCESS) {
224 ALOGW("setRecordState %d error %s", recordState, android::getSLErrStr(res));
225 return INVALID_OPERATION;
226 }
227 mRecordState = recordState;
228 return OK;
229 }
230
getRecordState()231 SLuint32 getRecordState() {
232 auto_lock l(mLock);
233 if (mRecord == NULL) {
234 return SL_RECORDSTATE_STOPPED;
235 }
236 SLuint32 recordState;
237 SLresult res = (*mRecord)->GetRecordState(mRecord, &recordState);
238 if (res != SL_RESULT_SUCCESS) {
239 ALOGW("getRecordState error %s", android::getSLErrStr(res));
240 return SL_RECORDSTATE_STOPPED;
241 }
242 return recordState;
243 }
244
getPositionInMsec(int64_t * position)245 status_t getPositionInMsec(int64_t *position) {
246 auto_lock l(mLock);
247 if (mRecord == NULL) {
248 return INVALID_OPERATION;
249 }
250 if (position == NULL) {
251 return BAD_VALUE;
252 }
253 SLuint32 pos;
254 SLresult res = (*mRecord)->GetPosition(mRecord, &pos);
255 if (res != SL_RESULT_SUCCESS) {
256 ALOGW("getPosition error %s", android::getSLErrStr(res));
257 return INVALID_OPERATION;
258 }
259 // only lower 32 bits valid
260 *position = pos;
261 return OK;
262 }
263
start()264 status_t start() {
265 return setRecordState(SL_RECORDSTATE_RECORDING);
266 }
267
pause()268 status_t pause() {
269 return setRecordState(SL_RECORDSTATE_PAUSED);
270 }
271
stop()272 status_t stop() {
273 return setRecordState(SL_RECORDSTATE_STOPPED);
274 }
275
flush()276 status_t flush() {
277 auto_lock l(mLock);
278 status_t result = OK;
279 if (mBufferQueue != NULL) {
280 SLresult res = (*mBufferQueue)->Clear(mBufferQueue);
281 if (res != SL_RESULT_SUCCESS) {
282 return INVALID_OPERATION;
283 }
284 }
285 mReadyQueue.clear();
286 // possible race if the engine is in the callback
287 // safety is only achieved if the recorder is paused or stopped.
288 mDeliveredQueue.clear();
289 mReadBlob = NULL;
290 mReadReady.terminate();
291 return result;
292 }
293
read(void * buffer,size_t size,bool blocking=false)294 ssize_t read(void *buffer, size_t size, bool blocking = false) {
295 std::lock_guard<std::mutex> rl(mReadLock);
296 // not needed if we assume that a single thread is doing the reading
297 // or we always operate in non-blocking mode.
298
299 ALOGV("reading:%p %zu", buffer, size);
300 size_t copied;
301 std::shared_ptr<Blob> blob;
302 {
303 auto_lock l(mLock);
304 if (mEngine == NULL) {
305 return INVALID_OPERATION;
306 }
307 size_t osize = size;
308 while (!mReadyQueue.empty() && size > 0) {
309 auto b = mReadyQueue.front();
310 size_t tocopy = min(size, b->mSize - b->mOffset);
311 // ALOGD("buffer:%p size:%zu b->mSize:%zu b->mOffset:%zu tocopy:%zu ",
312 // buffer, size, b->mSize, b->mOffset, tocopy);
313 memcpy(buffer, (char *)b->mData + b->mOffset, tocopy);
314 buffer = (char *)buffer + tocopy;
315 size -= tocopy;
316 b->mOffset += tocopy;
317 if (b->mOffset == b->mSize) {
318 mReadyQueue.pop_front();
319 }
320 }
321 copied = osize - size;
322 if (!blocking || size == 0 || mReadBlob.get() != NULL) {
323 return copied;
324 }
325 blob = std::make_shared<Blob>(buffer, size);
326 mReadBlob = blob;
327 mReadReady.closeGate(); // the callback will open gate when read is completed.
328 }
329 if (mReadReady.wait()) {
330 // success then the blob is ours with valid data otherwise a flush has occurred
331 // and we return a short count.
332 copied += blob->mOffset;
333 }
334 return copied;
335 }
336
logBufferState()337 void logBufferState() {
338 auto_lock l(mLock);
339 SLBufferQueueState state;
340 SLresult res = (*mBufferQueue)->GetState(mBufferQueue, &state);
341 CheckErr(res);
342 ALOGD("logBufferState state.count:%d state.playIndex:%d", state.count, state.playIndex);
343 }
344
getBuffersPending()345 size_t getBuffersPending() {
346 auto_lock l(mLock);
347 return mReadyQueue.size();
348 }
349
350 private:
queueBuffers()351 status_t queueBuffers() {
352 if (mBufferQueue == NULL) {
353 return INVALID_OPERATION;
354 }
355 if (mReadyQueue.size() + mDeliveredQueue.size() < mNumBuffers) {
356 // add new empty buffer
357 auto b = std::make_shared<Blob>(mBufferSize);
358 mDeliveredQueue.emplace_back(b);
359 (*mBufferQueue)->Enqueue(mBufferQueue, b->mData, b->mSize);
360 }
361 return OK;
362 }
363
bufferQueueCallback(SLBufferQueueItf queueItf)364 void bufferQueueCallback(SLBufferQueueItf queueItf) {
365 auto_lock l(mLock);
366 if (queueItf != mBufferQueue) {
367 ALOGW("invalid buffer queue interface, ignoring");
368 return;
369 }
370 // logBufferState();
371
372 // remove from delivered queue
373 if (mDeliveredQueue.size()) {
374 auto b = mDeliveredQueue.front();
375 mDeliveredQueue.pop_front();
376 if (mReadBlob.get() != NULL) {
377 size_t tocopy = min(mReadBlob->mSize - mReadBlob->mOffset, b->mSize - b->mOffset);
378 memcpy((char *)mReadBlob->mData + mReadBlob->mOffset,
379 (char *)b->mData + b->mOffset, tocopy);
380 b->mOffset += tocopy;
381 mReadBlob->mOffset += tocopy;
382 if (mReadBlob->mOffset == mReadBlob->mSize) {
383 mReadBlob = NULL; // we're done, clear our reference.
384 mReadReady.openGate(); // allow read to continue.
385 }
386 if (b->mOffset == b->mSize) {
387 b = NULL;
388 }
389 }
390 if (b.get() != NULL) {
391 if (mReadyQueue.size() + mDeliveredQueue.size() < mNumBuffers) {
392 mReadyQueue.emplace_back(b); // save onto ready queue for future reads
393 } else {
394 ALOGW("dropping data");
395 }
396 }
397 } else {
398 ALOGW("no delivered data!");
399 }
400 queueBuffers();
401 }
402
BufferQueueCallback(SLBufferQueueItf queueItf,void * pContext)403 static void BufferQueueCallback(SLBufferQueueItf queueItf, void *pContext) {
404 SLresult res;
405 // naked native record
406 AudioRecordNative *record = (AudioRecordNative *)pContext;
407 record->bufferQueueCallback(queueItf);
408 }
409
410 SLObjectItf mEngineObj;
411 SLEngineItf mEngine;
412 SLObjectItf mRecordObj;
413 SLRecordItf mRecord;
414 SLBufferQueueItf mBufferQueue;
415 SLuint32 mRecordState;
416 size_t mBufferSize;
417 size_t mNumBuffers;
418 std::recursive_mutex mLock; // monitor lock - locks public API methods and callback.
419 // recursive since it may call itself through API.
420 std::mutex mReadLock; // read lock - for blocking mode, prevents multiple
421 // reader threads from overlapping reads. this is
422 // generally unnecessary as reads occur from
423 // one thread only. acquire this before mLock.
424 std::shared_ptr<Blob> mReadBlob;
425 Gate mReadReady;
426 std::deque<std::shared_ptr<Blob>> mReadyQueue; // ready for read.
427 std::deque<std::shared_ptr<Blob>> mDeliveredQueue; // delivered to BufferQueue
428 };
429
430 /* Java static methods.
431 *
432 * These are not directly exposed to the user, so we can assume a valid "jrecord" handle
433 * to be passed in.
434 */
435
Java_android_media_cts_AudioRecordNative_nativeTest(JNIEnv *,jclass,jint numChannels,jint sampleRate,jboolean useFloat,jint msecPerBuffer,jint numBuffers)436 extern "C" jint Java_android_media_cts_AudioRecordNative_nativeTest(
437 JNIEnv * /* env */, jclass /* clazz */,
438 jint numChannels, jint sampleRate, jboolean useFloat,
439 jint msecPerBuffer, jint numBuffers)
440 {
441 AudioRecordNative record;
442 const size_t frameSize = numChannels * (useFloat ? sizeof(float) : sizeof(int16_t));
443 const size_t framesPerBuffer = msecPerBuffer * sampleRate / 1000;
444
445 status_t res;
446 void *buffer = calloc(framesPerBuffer * numBuffers, frameSize);
447 for (;;) {
448 res = record.open(numChannels, sampleRate, useFloat, numBuffers);
449 if (res != OK) break;
450
451 record.logBufferState();
452 res = record.start();
453 if (res != OK) break;
454
455 size_t size = framesPerBuffer * numBuffers * frameSize;
456 for (size_t offset = 0; size - offset > 0; ) {
457 ssize_t amount = record.read((char *)buffer + offset, size -offset);
458 // ALOGD("read amount: %zd", amount);
459 if (amount < 0) break;
460 offset += amount;
461 usleep(5 * 1000 /* usec */);
462 }
463
464 res = record.stop();
465 break;
466 }
467 record.close();
468 free(buffer);
469 return res;
470 }
471
Java_android_media_cts_AudioRecordNative_nativeCreateRecord(JNIEnv *,jclass)472 extern "C" jlong Java_android_media_cts_AudioRecordNative_nativeCreateRecord(
473 JNIEnv * /* env */, jclass /* clazz */)
474 {
475 return (jlong)(new shared_pointer<AudioRecordNative>(new AudioRecordNative()));
476 }
477
Java_android_media_cts_AudioRecordNative_nativeDestroyRecord(JNIEnv *,jclass,jlong jrecord)478 extern "C" void Java_android_media_cts_AudioRecordNative_nativeDestroyRecord(
479 JNIEnv * /* env */, jclass /* clazz */, jlong jrecord)
480 {
481 delete (shared_pointer<AudioRecordNative> *)jrecord;
482 }
483
Java_android_media_cts_AudioRecordNative_nativeOpen(JNIEnv *,jclass,jlong jrecord,jint numChannels,jint sampleRate,jboolean useFloat,jint numBuffers)484 extern "C" jint Java_android_media_cts_AudioRecordNative_nativeOpen(
485 JNIEnv * /* env */, jclass /* clazz */, jlong jrecord,
486 jint numChannels, jint sampleRate, jboolean useFloat, jint numBuffers)
487 {
488 auto record = *(shared_pointer<AudioRecordNative> *)jrecord;
489 if (record.get() == NULL) {
490 return (jint)INVALID_OPERATION;
491 }
492 return (jint)record->open(numChannels, sampleRate, useFloat == JNI_TRUE,
493 numBuffers);
494 }
495
Java_android_media_cts_AudioRecordNative_nativeClose(JNIEnv *,jclass,jlong jrecord)496 extern "C" void Java_android_media_cts_AudioRecordNative_nativeClose(
497 JNIEnv * /* env */, jclass /* clazz */, jlong jrecord)
498 {
499 auto record = *(shared_pointer<AudioRecordNative> *)jrecord;
500 if (record.get() != NULL) {
501 record->close();
502 }
503 }
504
Java_android_media_cts_AudioRecordNative_nativeStart(JNIEnv *,jclass,jlong jrecord)505 extern "C" jint Java_android_media_cts_AudioRecordNative_nativeStart(
506 JNIEnv * /* env */, jclass /* clazz */, jlong jrecord)
507 {
508 auto record = *(shared_pointer<AudioRecordNative> *)jrecord;
509 if (record.get() == NULL) {
510 return (jint)INVALID_OPERATION;
511 }
512 return (jint)record->start();
513 }
514
Java_android_media_cts_AudioRecordNative_nativeStop(JNIEnv *,jclass,jlong jrecord)515 extern "C" jint Java_android_media_cts_AudioRecordNative_nativeStop(
516 JNIEnv * /* env */, jclass /* clazz */, jlong jrecord)
517 {
518 auto record = *(shared_pointer<AudioRecordNative> *)jrecord;
519 if (record.get() == NULL) {
520 return (jint)INVALID_OPERATION;
521 }
522 return (jint)record->stop();
523 }
524
Java_android_media_cts_AudioRecordNative_nativePause(JNIEnv *,jclass,jlong jrecord)525 extern "C" jint Java_android_media_cts_AudioRecordNative_nativePause(
526 JNIEnv * /* env */, jclass /* clazz */, jlong jrecord)
527 {
528 auto record = *(shared_pointer<AudioRecordNative> *)jrecord;
529 if (record.get() == NULL) {
530 return (jint)INVALID_OPERATION;
531 }
532 return (jint)record->pause();
533 }
534
Java_android_media_cts_AudioRecordNative_nativeFlush(JNIEnv *,jclass,jlong jrecord)535 extern "C" jint Java_android_media_cts_AudioRecordNative_nativeFlush(
536 JNIEnv * /* env */, jclass /* clazz */, jlong jrecord)
537 {
538 auto record = *(shared_pointer<AudioRecordNative> *)jrecord;
539 if (record.get() == NULL) {
540 return (jint)INVALID_OPERATION;
541 }
542 return (jint)record->flush();
543 }
544
Java_android_media_cts_AudioRecordNative_nativeGetPositionInMsec(JNIEnv * env,jclass,jlong jrecord,jlongArray jPosition)545 extern "C" jint Java_android_media_cts_AudioRecordNative_nativeGetPositionInMsec(
546 JNIEnv *env, jclass /* clazz */, jlong jrecord, jlongArray jPosition)
547 {
548 auto record = *(shared_pointer<AudioRecordNative> *)jrecord;
549 if (record.get() == NULL) {
550 return (jint)INVALID_OPERATION;
551 }
552 int64_t pos;
553 status_t res = record->getPositionInMsec(&pos);
554 if (res != OK) {
555 return res;
556 }
557 jlong *nPostition = (jlong *) env->GetPrimitiveArrayCritical(jPosition, NULL /* isCopy */);
558 if (nPostition == NULL) {
559 ALOGE("Unable to get array for nativeGetPositionInMsec()");
560 return BAD_VALUE;
561 }
562 nPostition[0] = (jlong)pos;
563 env->ReleasePrimitiveArrayCritical(jPosition, nPostition, 0 /* mode */);
564 return OK;
565 }
566
567
Java_android_media_cts_AudioRecordNative_nativeGetBuffersPending(JNIEnv *,jclass,jlong jrecord)568 extern "C" jint Java_android_media_cts_AudioRecordNative_nativeGetBuffersPending(
569 JNIEnv * /* env */, jclass /* clazz */, jlong jrecord)
570 {
571 auto record = *(shared_pointer<AudioRecordNative> *)jrecord;
572 if (record.get() == NULL) {
573 return (jint)0;
574 }
575 return (jint)record->getBuffersPending();
576 }
577
578 template <typename T>
readFromRecord(jlong jrecord,T * data,jint offsetInSamples,jint sizeInSamples,jint readFlags)579 static inline jint readFromRecord(jlong jrecord, T *data,
580 jint offsetInSamples, jint sizeInSamples, jint readFlags)
581 {
582 auto record = *(shared_pointer<AudioRecordNative> *)jrecord;
583 if (record.get() == NULL) {
584 return (jint)INVALID_OPERATION;
585 }
586
587 const bool isBlocking = readFlags & READ_FLAG_BLOCKING;
588 const size_t sizeInBytes = sizeInSamples * sizeof(T);
589 ssize_t ret = record->read(data + offsetInSamples, sizeInBytes, isBlocking == JNI_TRUE);
590 return (jint)(ret > 0 ? ret / sizeof(T) : ret);
591 }
592
593 template <typename T>
readArray(JNIEnv * env,jclass,jlong jrecord,T javaAudioData,jint offsetInSamples,jint sizeInSamples,jint readFlags)594 static inline jint readArray(JNIEnv *env, jclass /* clazz */, jlong jrecord,
595 T javaAudioData, jint offsetInSamples, jint sizeInSamples, jint readFlags)
596 {
597 if (javaAudioData == NULL) {
598 return (jint)BAD_VALUE;
599 }
600
601 auto cAudioData = envGetArrayElements(env, javaAudioData, NULL /* isCopy */);
602 if (cAudioData == NULL) {
603 ALOGE("Error retrieving destination of audio data to record");
604 return (jint)BAD_VALUE;
605 }
606
607 jint ret = readFromRecord(jrecord, cAudioData, offsetInSamples, sizeInSamples, readFlags);
608 envReleaseArrayElements(env, javaAudioData, cAudioData, 0 /* mode */);
609 return ret;
610 }
611
Java_android_media_cts_AudioRecordNative_nativeReadByteArray(JNIEnv * env,jclass clazz,jlong jrecord,jbyteArray byteArray,jint offsetInSamples,jint sizeInSamples,jint readFlags)612 extern "C" jint Java_android_media_cts_AudioRecordNative_nativeReadByteArray(
613 JNIEnv *env, jclass clazz, jlong jrecord,
614 jbyteArray byteArray, jint offsetInSamples, jint sizeInSamples, jint readFlags)
615 {
616 return readArray(env, clazz, jrecord, byteArray, offsetInSamples, sizeInSamples, readFlags);
617 }
618
Java_android_media_cts_AudioRecordNative_nativeReadShortArray(JNIEnv * env,jclass clazz,jlong jrecord,jshortArray shortArray,jint offsetInSamples,jint sizeInSamples,jint readFlags)619 extern "C" jint Java_android_media_cts_AudioRecordNative_nativeReadShortArray(
620 JNIEnv *env, jclass clazz, jlong jrecord,
621 jshortArray shortArray, jint offsetInSamples, jint sizeInSamples, jint readFlags)
622 {
623 return readArray(env, clazz, jrecord, shortArray, offsetInSamples, sizeInSamples, readFlags);
624 }
625
Java_android_media_cts_AudioRecordNative_nativeReadFloatArray(JNIEnv * env,jclass clazz,jlong jrecord,jfloatArray floatArray,jint offsetInSamples,jint sizeInSamples,jint readFlags)626 extern "C" jint Java_android_media_cts_AudioRecordNative_nativeReadFloatArray(
627 JNIEnv *env, jclass clazz, jlong jrecord,
628 jfloatArray floatArray, jint offsetInSamples, jint sizeInSamples, jint readFlags)
629 {
630 return readArray(env, clazz, jrecord, floatArray, offsetInSamples, sizeInSamples, readFlags);
631 }
632