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