slesTestFeedback.cpp revision fdef5de17abc6c30b293861ca276259a7dd93837
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
37static SLuint32 rxBufCount = 2;     // -r#
38static SLuint32 txBufCount = 2;     // -t#
39static SLuint32 bufSizeInFrames = 240;  // -f#
40static SLuint32 channels = 1;       // -c#
41static SLuint32 sampleRate = 48000; // -s#
42static SLuint32 exitAfterSeconds = 60; // -e#
43static SLuint32 freeBufCount = 0;   // calculated
44static SLuint32 bufSizeInBytes = 0; // calculated
45
46// Storage area for the buffer queues
47static char **rxBuffers;
48static char **txBuffers;
49static char **freeBuffers;
50
51// Buffer indices
52static SLuint32 rxFront;    // oldest recording
53static SLuint32 rxRear;     // next to be recorded
54static SLuint32 txFront;    // oldest playing
55static SLuint32 txRear;     // next to be played
56static SLuint32 freeFront;  // oldest free
57static SLuint32 freeRear;   // next to be freed
58
59static SLAndroidSimpleBufferQueueItf recorderBufferQueue;
60static SLBufferQueueItf playerBufferQueue;
61
62static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
63
64static android::MonoPipeReader *pipeReader;
65static android::MonoPipe *pipeWriter;
66
67// Called after audio recorder fills a buffer with data
68static 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
148static 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
226int 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
507cleanup:
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