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