slesTestFeedback.cpp revision 01e9f5fa4698856f92bcfd88188ee4c8397b22db
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
19#undef NDEBUG
20
21#include "SLES/OpenSLES.h"
22#include "SLES/OpenSLES_Android.h"
23#include <assert.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <unistd.h>
28
29#define ASSERT_EQ(x, y) do { if ((x) == (y)) ; else { fprintf(stderr, "0x%x != 0x%x\n", \
30    (unsigned) (x), (unsigned) (y)); assert((x) == (y)); } } while (0)
31
32// default values
33static SLuint32 rxBufCount = 1;     // -r#
34static SLuint32 txBufCount = 2;     // -t#
35static SLuint32 bufSizeInFrames = 512;  // -f#
36static SLuint32 channels = 2;       // -c#
37static SLuint32 sampleRate = 44100; // -s#
38static SLuint32 appBufCount = 0;    // -n#
39static SLuint32 bufSizeInBytes = 0; // calculated
40static SLboolean verbose = SL_BOOLEAN_FALSE;
41
42// Storage area for the buffers
43static char *buffers = NULL;
44
45// Index of which buffer to enqueue next
46static SLuint32 whichRecord;
47static SLuint32 whichPlay;
48
49SLAndroidSimpleBufferQueueItf recorderBufferQueue;
50SLBufferQueueItf playerBufferQueue;
51
52// Compute maximum of two values
53static SLuint32 max(SLuint32 a, SLuint32 b)
54{
55    return a >= b ? a : b;
56}
57
58// Compute minimum of two values
59static SLuint32 min(SLuint32 a, SLuint32 b)
60{
61    return a <= b ? a : b;
62}
63
64// Called after audio recorder fills a buffer with data
65static void recorderCallback(SLAndroidSimpleBufferQueueItf caller, void *context)
66{
67    SLresult result;
68    if (verbose) {
69        putchar('*');
70        fflush(stdout);
71    }
72
73    // Enqueue the next empty buffer for the recorder to fill
74    assert(whichRecord < appBufCount);
75    void *buffer = &buffers[bufSizeInBytes * whichRecord];
76    result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, buffer, bufSizeInBytes);
77    ASSERT_EQ(SL_RESULT_SUCCESS, result);
78    if (++whichRecord >= appBufCount)
79        whichRecord = 0;
80
81    // Enqueue the just-filled buffer for the player to empty
82    assert(whichPlay < appBufCount); // sic not tx
83    buffer = &buffers[bufSizeInBytes * whichPlay];
84    result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, bufSizeInBytes);
85    // FIXME not sure yet why this is overflowing
86    if (SL_RESULT_SUCCESS == result) {
87        if (++whichPlay >= appBufCount)
88            whichPlay = 0;
89    } else {
90        ASSERT_EQ(SL_RESULT_BUFFER_INSUFFICIENT, result);
91    }
92
93}
94
95int main(int argc, char **argv)
96{
97    // process command-line options
98    int i;
99    for (i = 1; i < argc; ++i) {
100        char *arg = argv[i];
101        if (arg[0] != '-')
102            break;
103        // -r# number of receive buffers
104        if (!strncmp(arg, "-r", 2)) {
105            rxBufCount = atoi(&arg[2]);
106            if (rxBufCount < 1 || rxBufCount > 8)
107                fprintf(stderr, "%s: unusual receive buffer queue size (%u buffers)", argv[0],
108                    (unsigned) rxBufCount);
109        // -t# number of receive buffers
110        } else if (!strncmp(arg, "-t", 2)) {
111            txBufCount = atoi(&arg[2]);
112            if (txBufCount < 1 || txBufCount > 8)
113                fprintf(stderr, "%s: unusual transmit buffer queue size (%u buffers)", argv[0],
114                    (unsigned) txBufCount);
115        // -n# number of application buffers
116        } else if (!strncmp(arg, "-n", 2)) {
117            appBufCount = atoi(&arg[2]);
118        // -f# size of each buffer in frames
119        } else if (!strncmp(arg, "-f", 2)) {
120            bufSizeInFrames = atoi(&arg[2]);
121            if (bufSizeInFrames == 0) {
122                fprintf(stderr, "%s: unusual buffer size (%u frames)\n", argv[0],
123                    (unsigned) bufSizeInFrames);
124            }
125        // -c1 mono or -c2 stereo
126        } else if (!strncmp(arg, "-c", 2)) {
127            channels = atoi(&arg[2]);
128            if (channels < 1 || channels > 2) {
129                fprintf(stderr, "%s: unusual channel count ignored (%u)\n", argv[0],
130                    (unsigned) channels);
131                channels = 2;
132            }
133        // -s# sample rate in Hz
134        } else if (!strncmp(arg, "-s", 2)) {
135            sampleRate = atoi(&arg[2]);
136            switch (sampleRate) {
137            case 8000:
138            case 11025:
139            case 16000:
140            case 22050:
141            case 32000:
142            case 44100:
143                break;
144            default:
145                fprintf(stderr, "%s: unusual sample rate (%u Hz)\n", argv[0],
146                    (unsigned) sampleRate);
147                break;
148            }
149        // -v verbose
150        } else if (!strcmp(arg, "-v")) {
151            verbose = SL_BOOLEAN_TRUE;
152        } else
153            fprintf(stderr, "%s: unknown option %s\n", argv[0], arg);
154    }
155    if (i < argc) {
156        fprintf(stderr, "usage: %s -r# -t# -f# -r# -m/-s\n", argv[0]);
157        fprintf(stderr, "  -r# receive buffer queue count for microphone input, default 1\n");
158        fprintf(stderr, "  -t# transmit buffer queue count for speaker output, default 2\n");
159        fprintf(stderr, "  -f# number of frames per buffer, default 512\n");
160        fprintf(stderr, "  -s# sample rate in Hz, default 44100\n");
161        fprintf(stderr, "  -n# number of application-allocated buffers, default max(-r#,-t#)\n");
162        fprintf(stderr, "  -c1 mono\n");
163        fprintf(stderr, "  -c2 stereo, default\n");
164    }
165    if (appBufCount == 0)
166        appBufCount = max(rxBufCount, txBufCount);
167    if (appBufCount == 0)
168        appBufCount = 1;
169    if (appBufCount < max(rxBufCount, txBufCount))
170        fprintf(stderr, "%s: unusual application buffer count (%u buffers)", argv[0],
171            (unsigned) appBufCount);
172    bufSizeInBytes = channels * bufSizeInFrames * sizeof(short);
173    buffers = (char *) malloc(bufSizeInBytes * appBufCount);
174    SLresult result;
175
176    // create engine
177    SLObjectItf engineObject;
178    result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
179    ASSERT_EQ(SL_RESULT_SUCCESS, result);
180    result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
181    ASSERT_EQ(SL_RESULT_SUCCESS, result);
182    SLEngineItf engineEngine;
183    result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
184    ASSERT_EQ(SL_RESULT_SUCCESS, result);
185
186    // create output mix
187    SLObjectItf outputmixObject;
188    result = (*engineEngine)->CreateOutputMix(engineEngine, &outputmixObject, 0, NULL, NULL);
189    ASSERT_EQ(SL_RESULT_SUCCESS, result);
190    result = (*outputmixObject)->Realize(outputmixObject, SL_BOOLEAN_FALSE);
191    ASSERT_EQ(SL_RESULT_SUCCESS, result);
192
193    // create an audio player with buffer queue source and output mix sink
194    SLDataSource audiosrc;
195    SLDataSink audiosnk;
196    SLDataFormat_PCM pcm;
197    SLDataLocator_OutputMix locator_outputmix;
198    SLDataLocator_BufferQueue locator_bufferqueue_tx;
199    locator_bufferqueue_tx.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
200    locator_bufferqueue_tx.numBuffers = txBufCount;
201    locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
202    locator_outputmix.outputMix = outputmixObject;
203    pcm.formatType = SL_DATAFORMAT_PCM;
204    pcm.numChannels = channels;
205    pcm.samplesPerSec = sampleRate * 1000;
206    pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
207    pcm.containerSize = 16;
208    pcm.channelMask = channels == 1 ? SL_SPEAKER_FRONT_CENTER :
209        (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT);
210    pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
211    audiosrc.pLocator = &locator_bufferqueue_tx;
212    audiosrc.pFormat = &pcm;
213    audiosnk.pLocator = &locator_outputmix;
214    audiosnk.pFormat = NULL;
215    SLObjectItf playerObject;
216    SLInterfaceID ids_tx[1] = {SL_IID_BUFFERQUEUE};
217    SLboolean flags_tx[1] = {SL_BOOLEAN_TRUE};
218    result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audiosrc, &audiosnk,
219        1, ids_tx, flags_tx);
220    ASSERT_EQ(SL_RESULT_SUCCESS, result);
221    result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE);
222    ASSERT_EQ(SL_RESULT_SUCCESS, result);
223    SLPlayItf playerPlay;
224    result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay);
225    ASSERT_EQ(SL_RESULT_SUCCESS, result);
226    result = (*playerObject)->GetInterface(playerObject, SL_IID_BUFFERQUEUE, &playerBufferQueue);
227    ASSERT_EQ(SL_RESULT_SUCCESS, result);
228    result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING);
229    ASSERT_EQ(SL_RESULT_SUCCESS, result);
230
231    // Create an audio recorder with microphone device source and buffer queue sink.
232    // The buffer queue as sink is an Android-specific extension.
233
234    SLDataLocator_IODevice locator_iodevice;
235    SLDataLocator_AndroidSimpleBufferQueue locator_bufferqueue_rx;
236    locator_iodevice.locatorType = SL_DATALOCATOR_IODEVICE;
237    locator_iodevice.deviceType = SL_IODEVICE_AUDIOINPUT;
238    locator_iodevice.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT;
239    locator_iodevice.device = NULL;
240    audiosrc.pLocator = &locator_iodevice;
241    audiosrc.pFormat = &pcm;
242    locator_bufferqueue_rx.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
243    locator_bufferqueue_rx.numBuffers = rxBufCount;
244    audiosnk.pLocator = &locator_bufferqueue_rx;
245    audiosnk.pFormat = &pcm;
246    SLObjectItf recorderObject;
247    SLInterfaceID ids_rx[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
248    SLboolean flags_rx[1] = {SL_BOOLEAN_TRUE};
249    result = (*engineEngine)->CreateAudioRecorder(engineEngine, &recorderObject, &audiosrc,
250        &audiosnk, 1, ids_rx, flags_rx);
251    ASSERT_EQ(SL_RESULT_SUCCESS, result);
252    result = (*recorderObject)->Realize(recorderObject, SL_BOOLEAN_FALSE);
253    ASSERT_EQ(SL_RESULT_SUCCESS, result);
254    SLRecordItf recorderRecord;
255    result = (*recorderObject)->GetInterface(recorderObject, SL_IID_RECORD, &recorderRecord);
256    ASSERT_EQ(SL_RESULT_SUCCESS, result);
257    result = (*recorderObject)->GetInterface(recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
258        &recorderBufferQueue);
259    ASSERT_EQ(SL_RESULT_SUCCESS, result);
260    result = (*recorderBufferQueue)->RegisterCallback(recorderBufferQueue, recorderCallback, NULL);
261    ASSERT_EQ(SL_RESULT_SUCCESS, result);
262
263    // Enqueue some empty buffers for the recorder
264    SLuint32 temp = min(rxBufCount, appBufCount);
265    for (whichRecord = 0; whichRecord < (temp <= 1 ? 1 : temp - 1); ++whichRecord) {
266        result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue,
267            &buffers[bufSizeInBytes * whichRecord], bufSizeInBytes);
268        ASSERT_EQ(SL_RESULT_SUCCESS, result);
269    }
270    if (whichRecord >= appBufCount)
271        whichRecord = 0;
272
273    // Kick off the recorder
274    whichPlay = 0;
275    result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_RECORDING);
276    ASSERT_EQ(SL_RESULT_SUCCESS, result);
277
278    // Wait patiently
279    for (;;) {
280        usleep(1000000);
281        putchar('.');
282        SLBufferQueueState playerBQState;
283        result = (*playerBufferQueue)->GetState(playerBufferQueue, &playerBQState);
284        ASSERT_EQ(SL_RESULT_SUCCESS, result);
285        SLAndroidSimpleBufferQueueState recorderBQState;
286        result = (*recorderBufferQueue)->GetState(recorderBufferQueue, &recorderBQState);
287        ASSERT_EQ(SL_RESULT_SUCCESS, result);
288        if (verbose) {
289            printf("pC%u pI%u rC%u rI%u\n", (unsigned) playerBQState.count,
290                (unsigned) playerBQState.playIndex, (unsigned) recorderBQState.count,
291                (unsigned) recorderBQState.index);
292            fflush(stdout);
293        }
294    }
295
296    //return EXIT_SUCCESS;
297}
298