1 /*
2 * Copyright (C) 2010 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 // Test program to record from default audio input and playback to default audio output.
18 // It will generate feedback (Larsen effect) if played through on-device speakers,
19 // or acts as a delay if played through headset.
20
21 #include <SLES/OpenSLES.h>
22 #include <SLES/OpenSLES_Android.h>
23 #include <assert.h>
24 #include <pthread.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29
30 #include <media/nbaio/MonoPipe.h>
31 #include <media/nbaio/MonoPipeReader.h>
32
33 #define ASSERT_EQ(x, y) do { if ((x) == (y)) ; else { fprintf(stderr, "0x%x != 0x%x\n", \
34 (unsigned) (x), (unsigned) (y)); assert((x) == (y)); } } while (0)
35
36 // default values
37 static SLuint32 rxBufCount = 2; // -r#
38 static SLuint32 txBufCount = 2; // -t#
39 static SLuint32 bufSizeInFrames = 240; // -f#
40 static SLuint32 channels = 1; // -c#
41 static SLuint32 sampleRate = 48000; // -s#
42 static SLuint32 exitAfterSeconds = 60; // -e#
43 static SLuint32 freeBufCount = 0; // calculated
44 static SLuint32 bufSizeInBytes = 0; // calculated
45
46 // Storage area for the buffer queues
47 static char **rxBuffers;
48 static char **txBuffers;
49 static char **freeBuffers;
50
51 // Buffer indices
52 static SLuint32 rxFront; // oldest recording
53 static SLuint32 rxRear; // next to be recorded
54 static SLuint32 txFront; // oldest playing
55 static SLuint32 txRear; // next to be played
56 static SLuint32 freeFront; // oldest free
57 static SLuint32 freeRear; // next to be freed
58
59 static SLAndroidSimpleBufferQueueItf recorderBufferQueue;
60 static SLBufferQueueItf playerBufferQueue;
61
62 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
63
64 static android::MonoPipeReader *pipeReader;
65 static android::MonoPipe *pipeWriter;
66
67 // Called after audio recorder fills a buffer with data
recorderCallback(SLAndroidSimpleBufferQueueItf caller,void * context)68 static void recorderCallback(SLAndroidSimpleBufferQueueItf caller, void *context)
69 {
70 SLresult result;
71
72 pthread_mutex_lock(&mutex);
73
74 // We should only be called when a recording buffer is done
75 assert(rxFront <= rxBufCount);
76 assert(rxRear <= rxBufCount);
77 assert(rxFront != rxRear);
78 char *buffer = rxBuffers[rxFront];
79
80 // Remove buffer from record queue
81 if (++rxFront > rxBufCount) {
82 rxFront = 0;
83 }
84
85 #if 1
86 ssize_t actual = pipeWriter->write(buffer, (size_t) bufSizeInFrames);
87 if (actual != (ssize_t) bufSizeInFrames) {
88 write(1, "?", 1);
89 }
90
91 // Enqueue this same buffer for the recorder to fill again.
92 result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, buffer, bufSizeInBytes);
93 ASSERT_EQ(SL_RESULT_SUCCESS, result);
94
95 // Update our model of the record queue
96 SLuint32 rxRearNext = rxRear+1;
97 if (rxRearNext > rxBufCount) {
98 rxRearNext = 0;
99 }
100 assert(rxRearNext != rxFront);
101 rxBuffers[rxRear] = buffer;
102 rxRear = rxRearNext;
103
104 #else
105 // Enqueue the just-filled buffer for the player
106 result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, bufSizeInBytes);
107 if (SL_RESULT_SUCCESS == result) {
108
109 // There was room in the play queue, update our model of it
110 assert(txFront <= txBufCount);
111 assert(txRear <= txBufCount);
112 SLuint32 txRearNext = txRear+1;
113 if (txRearNext > txBufCount) {
114 txRearNext = 0;
115 }
116 assert(txRearNext != txFront);
117 txBuffers[txRear] = buffer;
118 txRear = txRearNext;
119
120 } else {
121
122 // Here if record has a filled buffer to play, but play queue is full.
123 assert(SL_RESULT_BUFFER_INSUFFICIENT == result);
124 write(1, "?", 1);
125
126 // We could either try again later, or discard. For now we discard and re-use buffer.
127 // Enqueue this same buffer for the recorder to fill again.
128 result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, buffer, bufSizeInBytes);
129 ASSERT_EQ(SL_RESULT_SUCCESS, result);
130
131 // Update our model of the record queue
132 SLuint32 rxRearNext = rxRear+1;
133 if (rxRearNext > rxBufCount) {
134 rxRearNext = 0;
135 }
136 assert(rxRearNext != rxFront);
137 rxBuffers[rxRear] = buffer;
138 rxRear = rxRearNext;
139
140 }
141 #endif
142
143 pthread_mutex_unlock(&mutex);
144 }
145
146
147 // Called after audio player empties a buffer of data
playerCallback(SLBufferQueueItf caller,void * context)148 static void playerCallback(SLBufferQueueItf caller, void *context)
149 {
150 SLresult result;
151
152 pthread_mutex_lock(&mutex);
153
154 // Get the buffer that just finished playing
155 assert(txFront <= txBufCount);
156 assert(txRear <= txBufCount);
157 assert(txFront != txRear);
158 char *buffer = txBuffers[txFront];
159 if (++txFront > txBufCount) {
160 txFront = 0;
161 }
162
163 #if 1
164 ssize_t actual = pipeReader->read(buffer, bufSizeInFrames, (int64_t) -1);
165 if (actual != (ssize_t) bufSizeInFrames) {
166 write(1, "/", 1);
167 // on underrun from pipe, substitute silence
168 memset(buffer, 0, bufSizeInFrames * channels * sizeof(short));
169 }
170
171 // Enqueue the filled buffer for playing
172 result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, bufSizeInBytes);
173 ASSERT_EQ(SL_RESULT_SUCCESS, result);
174
175 // Update our model of the player queue
176 assert(txFront <= txBufCount);
177 assert(txRear <= txBufCount);
178 SLuint32 txRearNext = txRear+1;
179 if (txRearNext > txBufCount) {
180 txRearNext = 0;
181 }
182 assert(txRearNext != txFront);
183 txBuffers[txRear] = buffer;
184 txRear = txRearNext;
185
186 #else
187 // First try to enqueue the free buffer for recording
188 result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, buffer, bufSizeInBytes);
189 if (SL_RESULT_SUCCESS == result) {
190
191 // There was room in the record queue, update our model of it
192 assert(rxFront <= rxBufCount);
193 assert(rxRear <= rxBufCount);
194 SLuint32 rxRearNext = rxRear+1;
195 if (rxRearNext > rxBufCount) {
196 rxRearNext = 0;
197 }
198 assert(rxRearNext != rxFront);
199 rxBuffers[rxRear] = buffer;
200 rxRear = rxRearNext;
201
202 } else {
203
204 // Here if record queue is full
205 assert(SL_RESULT_BUFFER_INSUFFICIENT == result);
206
207 // Instead enqueue the free buffer on the free queue
208 assert(freeFront <= freeBufCount);
209 assert(freeRear <= freeBufCount);
210 SLuint32 freeRearNext = freeRear+1;
211 if (freeRearNext > freeBufCount) {
212 freeRearNext = 0;
213 }
214 // There must always be room in the free queue
215 assert(freeRearNext != freeFront);
216 freeBuffers[freeRear] = buffer;
217 freeRear = freeRearNext;
218
219 }
220 #endif
221
222 pthread_mutex_unlock(&mutex);
223 }
224
225 // Main program
main(int argc,char ** argv)226 int main(int argc, char **argv)
227 {
228 // process command-line options
229 int i;
230 for (i = 1; i < argc; ++i) {
231 char *arg = argv[i];
232 if (arg[0] != '-') {
233 break;
234 }
235 // -r# number of slots in receive buffer queue
236 if (!strncmp(arg, "-r", 2)) {
237 rxBufCount = atoi(&arg[2]);
238 if (rxBufCount < 1 || rxBufCount > 16) {
239 fprintf(stderr, "%s: unusual receive buffer queue size (%u buffers)\n", argv[0],
240 (unsigned) rxBufCount);
241 }
242 // -t# number of slots in transmit buffer queue
243 } else if (!strncmp(arg, "-t", 2)) {
244 txBufCount = atoi(&arg[2]);
245 if (txBufCount < 1 || txBufCount > 16) {
246 fprintf(stderr, "%s: unusual transmit buffer queue size (%u buffers)\n", argv[0],
247 (unsigned) txBufCount);
248 }
249 // -f# size of each buffer in frames
250 } else if (!strncmp(arg, "-f", 2)) {
251 bufSizeInFrames = atoi(&arg[2]);
252 if (bufSizeInFrames == 0) {
253 fprintf(stderr, "%s: unusual buffer size (%u frames)\n", argv[0],
254 (unsigned) bufSizeInFrames);
255 }
256 // -c1 mono or -c2 stereo
257 } else if (!strncmp(arg, "-c", 2)) {
258 channels = atoi(&arg[2]);
259 if (channels < 1 || channels > 2) {
260 fprintf(stderr, "%s: unusual channel count ignored (%u)\n", argv[0],
261 (unsigned) channels);
262 channels = 2;
263 }
264 // -s# sample rate in Hz
265 } else if (!strncmp(arg, "-s", 2)) {
266 sampleRate = atoi(&arg[2]);
267 switch (sampleRate) {
268 case 8000:
269 case 11025:
270 case 12000:
271 case 16000:
272 case 22050:
273 case 24000:
274 case 32000:
275 case 44100:
276 case 48000:
277 break;
278 default:
279 fprintf(stderr, "%s: unusual sample rate (%u Hz)\n", argv[0],
280 (unsigned) sampleRate);
281 break;
282 }
283 // -e# exit after this many seconds
284 } else if (!strncmp(arg, "-e", 2)) {
285 exitAfterSeconds = atoi(&arg[2]);
286 } else
287 fprintf(stderr, "%s: unknown option %s\n", argv[0], arg);
288 }
289 // no other arguments allowed
290 if (i < argc) {
291 fprintf(stderr, "usage: %s -r# -t# -f# -s# -c#\n", argv[0]);
292 fprintf(stderr, " -r# receive buffer queue count for microphone input, default 1\n");
293 fprintf(stderr, " -t# transmit buffer queue count for speaker output, default 2\n");
294 fprintf(stderr, " -f# number of frames per buffer, default 512\n");
295 fprintf(stderr, " -s# sample rate in Hz, default 44100\n");
296 fprintf(stderr, " -c1 mono\n");
297 fprintf(stderr, " -c2 stereo, default\n");
298 }
299 // compute total free buffers as -r plus -t
300 freeBufCount = rxBufCount + txBufCount;
301 // compute buffer size
302 bufSizeInBytes = channels * bufSizeInFrames * sizeof(short);
303
304 // Initialize free buffers
305 freeBuffers = (char **) calloc(freeBufCount+1, sizeof(char *));
306 unsigned j;
307 for (j = 0; j < freeBufCount; ++j) {
308 freeBuffers[j] = (char *) malloc(bufSizeInBytes);
309 }
310 freeFront = 0;
311 freeRear = freeBufCount;
312 freeBuffers[j] = NULL;
313
314 // Initialize record queue
315 rxBuffers = (char **) calloc(rxBufCount+1, sizeof(char *));
316 rxFront = 0;
317 rxRear = 0;
318
319 // Initialize play queue
320 txBuffers = (char **) calloc(txBufCount+1, sizeof(char *));
321 txFront = 0;
322 txRear = 0;
323
324 const android::NBAIO_Format nbaio_format = android::Format_from_SR_C(sampleRate, channels,
325 AUDIO_FORMAT_PCM_16_BIT);
326 pipeWriter = new android::MonoPipe(1024, nbaio_format, false /*writeCanBlock*/);
327 android::NBAIO_Format offer = nbaio_format;
328 size_t numCounterOffers = 0;
329 ssize_t neg = pipeWriter->negotiate(&offer, 1, NULL, numCounterOffers);
330 assert(0 == neg);
331 pipeReader = new android::MonoPipeReader(pipeWriter);
332 numCounterOffers = 0;
333 neg = pipeReader->negotiate(&offer, 1, NULL, numCounterOffers);
334 assert(0 == neg);
335
336 SLresult result;
337
338 // create engine
339 SLObjectItf engineObject;
340 result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
341 ASSERT_EQ(SL_RESULT_SUCCESS, result);
342 result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
343 ASSERT_EQ(SL_RESULT_SUCCESS, result);
344 SLEngineItf engineEngine;
345 result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
346 ASSERT_EQ(SL_RESULT_SUCCESS, result);
347
348 // create output mix
349 SLObjectItf outputmixObject;
350 result = (*engineEngine)->CreateOutputMix(engineEngine, &outputmixObject, 0, NULL, NULL);
351 ASSERT_EQ(SL_RESULT_SUCCESS, result);
352 result = (*outputmixObject)->Realize(outputmixObject, SL_BOOLEAN_FALSE);
353 ASSERT_EQ(SL_RESULT_SUCCESS, result);
354
355 // create an audio player with buffer queue source and output mix sink
356 SLDataSource audiosrc;
357 SLDataSink audiosnk;
358 SLDataFormat_PCM pcm;
359 SLDataLocator_OutputMix locator_outputmix;
360 SLDataLocator_BufferQueue locator_bufferqueue_tx;
361 locator_bufferqueue_tx.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
362 locator_bufferqueue_tx.numBuffers = txBufCount;
363 locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
364 locator_outputmix.outputMix = outputmixObject;
365 pcm.formatType = SL_DATAFORMAT_PCM;
366 pcm.numChannels = channels;
367 pcm.samplesPerSec = sampleRate * 1000;
368 pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
369 pcm.containerSize = 16;
370 pcm.channelMask = channels == 1 ? SL_SPEAKER_FRONT_CENTER :
371 (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT);
372 pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
373 audiosrc.pLocator = &locator_bufferqueue_tx;
374 audiosrc.pFormat = &pcm;
375 audiosnk.pLocator = &locator_outputmix;
376 audiosnk.pFormat = NULL;
377 SLObjectItf playerObject = NULL;
378 SLObjectItf recorderObject = NULL;
379 SLInterfaceID ids_tx[1] = {SL_IID_BUFFERQUEUE};
380 SLboolean flags_tx[1] = {SL_BOOLEAN_TRUE};
381 result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audiosrc, &audiosnk,
382 1, ids_tx, flags_tx);
383 if (SL_RESULT_CONTENT_UNSUPPORTED == result) {
384 fprintf(stderr, "Could not create audio player (result %x), check sample rate\n", result);
385 goto cleanup;
386 }
387 ASSERT_EQ(SL_RESULT_SUCCESS, result);
388 result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE);
389 ASSERT_EQ(SL_RESULT_SUCCESS, result);
390 SLPlayItf playerPlay;
391 result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay);
392 ASSERT_EQ(SL_RESULT_SUCCESS, result);
393 result = (*playerObject)->GetInterface(playerObject, SL_IID_BUFFERQUEUE, &playerBufferQueue);
394 ASSERT_EQ(SL_RESULT_SUCCESS, result);
395 result = (*playerBufferQueue)->RegisterCallback(playerBufferQueue, playerCallback, NULL);
396 ASSERT_EQ(SL_RESULT_SUCCESS, result);
397
398 // Enqueue some zero buffers for the player
399 for (j = 0; j < txBufCount; ++j) {
400
401 // allocate a free buffer
402 assert(freeFront != freeRear);
403 char *buffer = freeBuffers[freeFront];
404 if (++freeFront > freeBufCount) {
405 freeFront = 0;
406 }
407
408 // put on play queue
409 SLuint32 txRearNext = txRear + 1;
410 if (txRearNext > txBufCount) {
411 txRearNext = 0;
412 }
413 assert(txRearNext != txFront);
414 txBuffers[txRear] = buffer;
415 txRear = txRearNext;
416 result = (*playerBufferQueue)->Enqueue(playerBufferQueue,
417 buffer, bufSizeInBytes);
418 ASSERT_EQ(SL_RESULT_SUCCESS, result);
419 }
420
421 result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING);
422 ASSERT_EQ(SL_RESULT_SUCCESS, result);
423
424 // Create an audio recorder with microphone device source and buffer queue sink.
425 // The buffer queue as sink is an Android-specific extension.
426
427 SLDataLocator_IODevice locator_iodevice;
428 SLDataLocator_AndroidSimpleBufferQueue locator_bufferqueue_rx;
429 locator_iodevice.locatorType = SL_DATALOCATOR_IODEVICE;
430 locator_iodevice.deviceType = SL_IODEVICE_AUDIOINPUT;
431 locator_iodevice.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT;
432 locator_iodevice.device = NULL;
433 audiosrc.pLocator = &locator_iodevice;
434 audiosrc.pFormat = NULL;
435 locator_bufferqueue_rx.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
436 locator_bufferqueue_rx.numBuffers = rxBufCount;
437 audiosnk.pLocator = &locator_bufferqueue_rx;
438 audiosnk.pFormat = &pcm;
439 {
440 SLInterfaceID ids_rx[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
441 SLboolean flags_rx[1] = {SL_BOOLEAN_TRUE};
442 result = (*engineEngine)->CreateAudioRecorder(engineEngine, &recorderObject, &audiosrc,
443 &audiosnk, 1, ids_rx, flags_rx);
444 if (SL_RESULT_SUCCESS != result) {
445 fprintf(stderr, "Could not create audio recorder (result %x), "
446 "check sample rate and channel count\n", result);
447 goto cleanup;
448 }
449 }
450 ASSERT_EQ(SL_RESULT_SUCCESS, result);
451 result = (*recorderObject)->Realize(recorderObject, SL_BOOLEAN_FALSE);
452 ASSERT_EQ(SL_RESULT_SUCCESS, result);
453 SLRecordItf recorderRecord;
454 result = (*recorderObject)->GetInterface(recorderObject, SL_IID_RECORD, &recorderRecord);
455 ASSERT_EQ(SL_RESULT_SUCCESS, result);
456 result = (*recorderObject)->GetInterface(recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
457 &recorderBufferQueue);
458 ASSERT_EQ(SL_RESULT_SUCCESS, result);
459 result = (*recorderBufferQueue)->RegisterCallback(recorderBufferQueue, recorderCallback, NULL);
460 ASSERT_EQ(SL_RESULT_SUCCESS, result);
461
462 // Enqueue some empty buffers for the recorder
463 for (j = 0; j < rxBufCount; ++j) {
464
465 // allocate a free buffer
466 assert(freeFront != freeRear);
467 char *buffer = freeBuffers[freeFront];
468 if (++freeFront > freeBufCount) {
469 freeFront = 0;
470 }
471
472 // put on record queue
473 SLuint32 rxRearNext = rxRear + 1;
474 if (rxRearNext > rxBufCount) {
475 rxRearNext = 0;
476 }
477 assert(rxRearNext != rxFront);
478 rxBuffers[rxRear] = buffer;
479 rxRear = rxRearNext;
480 result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue,
481 buffer, bufSizeInBytes);
482 ASSERT_EQ(SL_RESULT_SUCCESS, result);
483 }
484
485 // Kick off the recorder
486 result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_RECORDING);
487 ASSERT_EQ(SL_RESULT_SUCCESS, result);
488
489 #if 0
490 // give recorder a head start so that the pipe is initially filled
491 sleep(1);
492 #endif
493
494 // Wait patiently
495 do {
496 usleep(1000000);
497 write(1, ".", 1);
498 SLBufferQueueState playerBQState;
499 result = (*playerBufferQueue)->GetState(playerBufferQueue, &playerBQState);
500 ASSERT_EQ(SL_RESULT_SUCCESS, result);
501 SLAndroidSimpleBufferQueueState recorderBQState;
502 result = (*recorderBufferQueue)->GetState(recorderBufferQueue, &recorderBQState);
503 ASSERT_EQ(SL_RESULT_SUCCESS, result);
504 } while (--exitAfterSeconds);
505
506 // Tear down the objects and exit
507 cleanup:
508 if (NULL != playerObject) {
509 (*playerObject)->Destroy(playerObject);
510 }
511 if (NULL != recorderObject) {
512 (*recorderObject)->Destroy(recorderObject);
513 }
514 (*outputmixObject)->Destroy(outputmixObject);
515 (*engineObject)->Destroy(engineObject);
516
517 return EXIT_SUCCESS;
518 }
519