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