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/* interactive buffer queue test program */
18
19#ifdef ANDROID
20#define USE_ANDROID_SIMPLE_BUFFER_QUEUE     // change to #undef for compatibility testing
21#endif
22
23#include <assert.h>
24#include <math.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <unistd.h>
28#include "SLES/OpenSLES.h"
29#ifdef USE_ANDROID_SIMPLE_BUFFER_QUEUE
30#include "SLES/OpenSLES_Android.h"
31#endif
32
33#ifdef USE_ANDROID_SIMPLE_BUFFER_QUEUE
34#define DATALOCATOR_BUFFERQUEUE SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE
35#define IID_BUFFERQUEUE SL_IID_ANDROIDSIMPLEBUFFERQUEUE
36#define BufferQueueItf SLAndroidSimpleBufferQueueItf
37#define BufferQueueState SLAndroidSimpleBufferQueueState
38#define INDEX index
39#else
40#define DATALOCATOR_BUFFERQUEUE SL_DATALOCATOR_BUFFERQUEUE
41#define IID_BUFFERQUEUE SL_IID_BUFFERQUEUE
42#define BufferQueueItf SLBufferQueueItf
43#define BufferQueueState SLBufferQueueState
44#define INDEX playIndex
45#endif
46
47#define checkResult(r) do { if ((r) != SL_RESULT_SUCCESS) fprintf(stderr, "error %d at %s:%d\n", \
48    (int) r, __FILE__, __LINE__); } while (0)
49
50typedef struct {
51    short left;
52    short right;
53} frame_t;
54
55#define SINE_FRAMES (44100*5)
56frame_t sine[SINE_FRAMES];
57
58#define SQUARE_FRAMES (44100*5)
59frame_t square[SQUARE_FRAMES];
60
61#define SAWTOOTH_FRAMES (44100*5)
62frame_t sawtooth[SAWTOOTH_FRAMES];
63
64#define HALF_FRAMES (44100*5)
65frame_t half[HALF_FRAMES];
66
67BufferQueueItf expectedCaller = NULL;
68void *expectedContext = NULL;
69
70static void callback(BufferQueueItf caller, void *context)
71{
72    putchar('.');
73    if (caller != expectedCaller)
74        printf("caller %p expected %p\r\n", caller, expectedCaller);
75    if (context != expectedContext)
76        printf("context %p expected %p\r\n", context, expectedContext);
77    fflush(stdout);
78}
79
80int main(int argc, char **argv)
81{
82    SLresult result;
83
84    // create engine
85    SLObjectItf engineObject;
86    result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
87    checkResult(result);
88    result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
89    checkResult(result);
90    SLEngineItf engineEngine;
91    result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
92    checkResult(result);
93
94    // create output mix
95    SLObjectItf outputmixObject;
96    result = (*engineEngine)->CreateOutputMix(engineEngine, &outputmixObject, 0, NULL, NULL);
97    checkResult(result);
98    result = (*outputmixObject)->Realize(outputmixObject, SL_BOOLEAN_FALSE);
99    checkResult(result);
100
101    // create audio player
102    SLDataSource audiosrc;
103    SLDataSink audiosnk;
104    SLDataFormat_PCM pcm;
105    SLDataLocator_OutputMix locator_outputmix;
106    SLDataLocator_BufferQueue locator_bufferqueue;
107    locator_bufferqueue.locatorType = DATALOCATOR_BUFFERQUEUE;
108    locator_bufferqueue.numBuffers = 255;
109    locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
110    locator_outputmix.outputMix = outputmixObject;
111    pcm.formatType = SL_DATAFORMAT_PCM;
112    pcm.numChannels = 2;
113    pcm.samplesPerSec = SL_SAMPLINGRATE_44_1;
114    pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
115    pcm.containerSize = 16;
116    pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
117    pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
118    audiosrc.pLocator = &locator_bufferqueue;
119    audiosrc.pFormat = &pcm;
120    audiosnk.pLocator = &locator_outputmix;
121    audiosnk.pFormat = NULL;
122    SLObjectItf playerObject;
123    SLInterfaceID ids[2] = {IID_BUFFERQUEUE, SL_IID_MUTESOLO};
124    SLboolean flags[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
125    result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audiosrc, &audiosnk,
126            2, ids, flags);
127    checkResult(result);
128    result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE);
129    checkResult(result);
130    SLPlayItf playerPlay;
131    result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay);
132    checkResult(result);
133    BufferQueueItf playerBufferqueue;
134    result = (*playerObject)->GetInterface(playerObject, IID_BUFFERQUEUE, &playerBufferqueue);
135    checkResult(result);
136    SLMuteSoloItf playerMuteSolo;
137    result = (*playerObject)->GetInterface(playerObject, SL_IID_MUTESOLO, &playerMuteSolo);
138    checkResult(result);
139    SLuint8 numChannels = 123;
140    result = (*playerMuteSolo)->GetNumChannels(playerMuteSolo, &numChannels);
141    assert(2 == numChannels);
142    SLuint32 state;
143    state = SL_PLAYSTATE_PLAYING;
144    result = (*playerPlay)->SetPlayState(playerPlay, state);
145    checkResult(result);
146
147    unsigned i;
148    float pi2 = 3.14*2;
149    float hz = 441;
150    float sr = 44100;
151    for (i = 0; i < SINE_FRAMES; ++i) {
152        sine[i].left = sin((float) (i  / (sr / hz)) * pi2 ) * 32000.0;
153        sine[i].right = sine[i].left;
154    }
155    for (i = 0; i < SQUARE_FRAMES; ++i) {
156        square[i].left = (i % (unsigned) (sr / hz)) < 50 ? 32767 : -32768;
157        square[i].right = square[i].left;
158    }
159    for (i = 0; i < SAWTOOTH_FRAMES; ++i) {
160        sawtooth[i].left = ((((int) (i % (unsigned) (sr / hz))) - 50) / 100.0) * 60000.0 - 30000.0;
161        sawtooth[i].right = sawtooth[i].left;
162    }
163    for (i = 0; i < HALF_FRAMES; ++i) {
164        half[i].left = sine[i].left;
165        half[i].right = sawtooth[i].right / 2;
166    }
167
168    set_conio_terminal_mode();
169    int in_count = 0;
170    unsigned count = 0;
171    for (;;) {
172        usleep(10000);
173        if (kbhit()) {
174            frame_t *buffer;
175            unsigned size;
176            BufferQueueState bufqstate;
177            int ch = getch();
178            switch (ch) {
179            case '0' ... '9':
180                if (in_count) {
181                    count = count * 10 + (ch - '0');
182                } else {
183                    count = ch - '0';
184                    in_count = 1;
185                }
186                continue;
187            case 'i':
188                buffer = sine;
189                size = sizeof(sine);
190                goto enqueue;
191            case 'q':
192                buffer = square;
193                size = sizeof(square);
194                goto enqueue;
195            case 'h':
196                buffer = half;
197                size = sizeof(half);
198                goto enqueue;
199            case 'r':
200                if (in_count) {
201                    expectedCaller = playerBufferqueue;
202                    expectedContext = (void *) count;
203                } else {
204                    expectedCaller = NULL;
205                    expectedContext = (void *) NULL;
206                }
207                result = (*playerBufferqueue)->RegisterCallback(playerBufferqueue, in_count ?
208                    callback : NULL, expectedContext);
209                checkResult(result);
210                break;
211            case 'a':
212                buffer = sawtooth;
213                size = sizeof(sawtooth);
214enqueue:
215                for (i = 0; i < (in_count ? count : 1); ++i) {
216                    result = (*playerBufferqueue)->Enqueue(playerBufferqueue, buffer, size);
217                    checkResult(result);
218                }
219                break;
220            case 'c':
221                result = (*playerBufferqueue)->Clear(playerBufferqueue);
222                checkResult(result);
223                putchar('\r');
224                result = (*playerBufferqueue)->GetState(playerBufferqueue, &bufqstate);
225                checkResult(result);
226                if (bufqstate.count != 0)
227                    printf("\rcount=%u\r\n", (unsigned) bufqstate.count);
228#if 0
229                putchar('\r');
230                putchar('\n');
231#endif
232                fflush(stdout);
233                break;
234            case 'g':
235                result = (*playerBufferqueue)->GetState(playerBufferqueue, &bufqstate);
236                checkResult(result);
237                printf("\rplayIndex=%u\r\n", (unsigned) bufqstate.INDEX);
238                printf("count=%u\r\n", (unsigned) bufqstate.count);
239                break;
240            case 'p':
241                state = SL_PLAYSTATE_PAUSED;
242                goto setplaystate;
243            case 's':
244                state = SL_PLAYSTATE_STOPPED;
245                goto setplaystate;
246            case 'P':
247                state = SL_PLAYSTATE_PLAYING;
248setplaystate:
249                result = (*playerPlay)->SetPlayState(playerPlay, state);
250                checkResult(result);
251                SLuint32 newstate;
252                result = (*playerPlay)->GetPlayState(playerPlay, &newstate);
253                checkResult(result);
254                if (newstate != state)
255                    printf("\rSetPlayState(%u) -> GetPlayState(%u)\r\n", (unsigned) state,
256                        (unsigned) newstate);
257#if 0
258                putchar('\r');
259                putchar('\n');
260                fflush(stdout);
261#endif
262                checkResult(result);
263                break;
264            case 'x':
265                goto out;
266            default:
267                putchar('?');
268                fflush(stdout);
269                break;
270            }
271            in_count = 0;
272        }
273    }
274
275out:
276    (*playerObject)->Destroy(playerObject);
277    (*outputmixObject)->Destroy(outputmixObject);
278    (*engineObject)->Destroy(engineObject);
279    return EXIT_SUCCESS;
280}
281