• 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 #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