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