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