• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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