slesTestSawtoothBufferQueue.cpp revision 527b7d2e606abdbde0e29fe75f7e9a67285629d2
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/*
18 * Copyright (c) 2009 The Khronos Group Inc.
19 *
20 * Permission is hereby granted, free of charge, to any person obtaining a copy of this
21 * software and /or associated documentation files (the "Materials "), to deal in the
22 * Materials without restriction, including without limitation the rights to use, copy,
23 * modify, merge, publish, distribute, sublicense, and/or sell copies of the Materials,
24 * and to permit persons to whom the Materials are furnished to do so, subject to
25 * the following conditions:
26 *
27 * The above copyright notice and this permission notice shall be included
28 * in all copies or substantial portions of the Materials.
29 *
30 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
31 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
32 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
33 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
34 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
35 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
36 * CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS IN THE
37 * MATERIALS.
38 */
39
40#define LOG_NDEBUG 0
41#define LOG_TAG "Sawtooth"
42
43#ifdef ANDROID
44#include <utils/Log.h>
45#else
46#define LOGV printf
47#endif
48
49#include <getopt.h>
50#include <stdlib.h>
51#include <stdio.h>
52#include <string.h>
53#include <unistd.h>
54#include <sys/time.h>
55
56
57#include "SLES/OpenSLES.h"
58
59/*using namespace android;*/
60
61#define SLEEP(x) /* Client system sleep function to sleep x milliseconds
62would replace SLEEP macro */
63
64#define MAX_NUMBER_INTERFACES 3
65#define MAX_NUMBER_OUTPUT_DEVICES 6
66
67/* Local storage for Audio data in 16 bit words */
68#define AUDIO_DATA_STORAGE_SIZE 4096 * 100
69/* Audio data buffer size in 16 bit words. 8 data segments are used in
70this simple example */
71#define AUDIO_DATA_BUFFER_SIZE 4096/8
72
73/* Checks for error. If any errors exit the application! */
74void CheckErr( SLresult res )
75{
76    if ( res != SL_RESULT_SUCCESS )
77        {
78            fprintf(stdout, "%lu SL failure, exiting\n", res);
79            exit(1);
80        }
81    else {
82        //fprintf(stdout, "%d SL success, proceeding...\n", res);
83    }
84}
85
86/* Structure for passing information to callback function */
87typedef struct CallbackCntxt_ {
88    SLPlayItf  playItf;
89    SLint16*   pDataBase;    // Base adress of local audio data storage
90    SLint16*   pData;        // Current adress of local audio data storage
91    SLuint32   size;
92} CallbackCntxt;
93
94/* Local storage for Audio data */
95SLint16 pcmData[AUDIO_DATA_STORAGE_SIZE];
96
97/* Callback for Buffer Queue events */
98void BufferQueueCallback(
99        SLBufferQueueItf queueItf,
100        void *pContext)
101{
102    //fprintf(stdout, "BufferQueueCallback called\n");
103    SLresult res;
104    //fprintf(stdout, " pContext=%p\n", pContext);
105    CallbackCntxt *pCntxt = (CallbackCntxt*)pContext;
106
107    if(pCntxt->pData < (pCntxt->pDataBase + pCntxt->size))
108        {
109            //fprintf(stdout, "callback: before enqueue\n");
110            res = (*queueItf)->Enqueue(queueItf, (void*) pCntxt->pData,
111                    2 * AUDIO_DATA_BUFFER_SIZE); /* Size given in bytes. */
112            CheckErr(res);
113            /* Increase data pointer by buffer size */
114            pCntxt->pData += AUDIO_DATA_BUFFER_SIZE;
115        }
116    //fprintf(stdout, "end of BufferQueueCallback()\n");
117}
118
119/* Play some audio from a buffer queue  */
120void TestPlaySawtoothBufferQueue( SLObjectItf sl )
121{
122    SLEngineItf                EngineItf;
123
124    SLint32                    numOutputs = 0;
125    SLuint32                   deviceID = 0;
126
127    SLresult                   res;
128
129    SLDataSource               audioSource;
130    SLDataLocator_BufferQueue  bufferQueue;
131    SLDataFormat_PCM           pcm;
132
133    SLDataSink                 audioSink;
134    SLDataLocator_OutputMix    locator_outputmix;
135
136    SLObjectItf                player;
137    SLPlayItf                  playItf;
138    SLBufferQueueItf           bufferQueueItf;
139    SLBufferQueueState         state;
140
141    SLObjectItf                OutputMix;
142    SLVolumeItf                volumeItf;
143
144    int                        i;
145
146    SLboolean required[MAX_NUMBER_INTERFACES];
147    SLInterfaceID iidArray[MAX_NUMBER_INTERFACES];
148
149    /* Callback context for the buffer queue callback function */
150    CallbackCntxt cntxt;
151
152    /* Get the SL Engine Interface which is implicit */
153    res = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf);
154    CheckErr(res);
155
156    /* Initialize arrays required[] and iidArray[] */
157    for (i=0;i<MAX_NUMBER_INTERFACES;i++)
158        {
159            required[i] = SL_BOOLEAN_FALSE;
160            iidArray[i] = SL_IID_NULL;
161        }
162
163    // Set arrays required[] and iidArray[] for VOLUME interface
164    required[0] = SL_BOOLEAN_TRUE;
165    iidArray[0] = SL_IID_VOLUME;
166    // Create Output Mix object to be used by player
167    res = (*EngineItf)->CreateOutputMix(EngineItf, &OutputMix, 1,
168            iidArray, required); CheckErr(res);
169
170    // Realizing the Output Mix object in synchronous mode.
171    res = (*OutputMix)->Realize(OutputMix, SL_BOOLEAN_FALSE);
172    CheckErr(res);
173
174    res = (*OutputMix)->GetInterface(OutputMix, SL_IID_VOLUME,
175            (void*)&volumeItf); CheckErr(res);
176
177    /* Setup the data source structure for the buffer queue */
178    bufferQueue.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
179    bufferQueue.numBuffers = 4;  /* Four buffers in our buffer queue */
180
181    /* Setup the format of the content in the buffer queue */
182    pcm.formatType = SL_DATAFORMAT_PCM;
183    pcm.numChannels = 1;//2;
184    pcm.samplesPerSec = SL_SAMPLINGRATE_44_1;
185    pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
186    pcm.containerSize = 16;
187    pcm.channelMask = SL_SPEAKER_FRONT_LEFT;// | SL_SPEAKER_FRONT_RIGHT;
188    pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
189
190    audioSource.pFormat      = (void *)&pcm;
191    audioSource.pLocator     = (void *)&bufferQueue;
192
193    /* Setup the data sink structure */
194    locator_outputmix.locatorType   = SL_DATALOCATOR_OUTPUTMIX;
195    locator_outputmix.outputMix    = OutputMix;
196    audioSink.pLocator           = (void *)&locator_outputmix;
197    audioSink.pFormat            = NULL;
198
199    /* Initialize the audio data to play */
200    unsigned int j;
201    for (j = 0; j < sizeof(pcmData)/sizeof(pcmData[0]); ++j) {
202        pcmData[j] = j*(100 + j / 200);// % 1000;
203    }
204
205    /* Initialize the context for Buffer queue callbacks */
206    cntxt.pDataBase = /*(void*)&*/pcmData;
207    cntxt.pData = cntxt.pDataBase;
208    cntxt.size = sizeof(pcmData) / 2;
209
210    /* Set arrays required[] and iidArray[] for SEEK interface
211          (PlayItf is implicit) */
212    required[0] = SL_BOOLEAN_TRUE;
213    iidArray[0] = SL_IID_BUFFERQUEUE;
214
215    /* Create the music player */
216    res = (*EngineItf)->CreateAudioPlayer(EngineItf, &player,
217            &audioSource, &audioSink, 1, iidArray, required); CheckErr(res);
218    fprintf(stdout, "bufferQueue example: after CreateAudioPlayer\n");
219
220    /* Realizing the player in synchronous mode. */
221    res = (*player)->Realize(player, SL_BOOLEAN_FALSE); CheckErr(res);
222    fprintf(stdout, "bufferQueue example: after Realize\n");
223
224    /* Get seek and play interfaces */
225    res = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf);
226    CheckErr(res);
227    fprintf(stdout, "bufferQueue example: after GetInterface(PLAY)\n");
228
229    res = (*player)->GetInterface(player, SL_IID_BUFFERQUEUE,
230            (void*)&bufferQueueItf); CheckErr(res);
231
232    /* Setup to receive buffer queue event callbacks */
233    res = (*bufferQueueItf)->RegisterCallback(bufferQueueItf,
234            BufferQueueCallback, &cntxt); CheckErr(res);
235
236    /* Before we start set volume to -3dB (-300mB) */
237    res = (*volumeItf)->SetVolumeLevel(volumeItf, -300); CheckErr(res);
238
239    /* Enqueue a few buffers to get the ball rolling */
240    res = (*bufferQueueItf)->Enqueue(bufferQueueItf, cntxt.pData,
241            2 * AUDIO_DATA_BUFFER_SIZE); /* Size given in bytes. */
242    CheckErr(res);
243    cntxt.pData += AUDIO_DATA_BUFFER_SIZE;
244
245    res = (*bufferQueueItf)->Enqueue(bufferQueueItf, cntxt.pData,
246            2 * AUDIO_DATA_BUFFER_SIZE); /* Size given in bytes. */
247    CheckErr(res);
248    cntxt.pData += AUDIO_DATA_BUFFER_SIZE;
249
250    res = (*bufferQueueItf)->Enqueue(bufferQueueItf, cntxt.pData,
251            2 * AUDIO_DATA_BUFFER_SIZE); /* Size given in bytes. */
252    CheckErr(res);
253    cntxt.pData += AUDIO_DATA_BUFFER_SIZE;
254
255    /* Play the PCM samples using a buffer queue */
256    fprintf(stdout, "bufferQueue example: starting to play\n");
257    res = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PLAYING );
258    CheckErr(res);
259
260    /* Wait until the PCM data is done playing, the buffer queue callback
261           will continue to queue buffers until the entire PCM data has been
262           played. This is indicated by waiting for the count member of the
263           SLBufferQueueState to go to zero.
264     */
265    res = (*bufferQueueItf)->GetState(bufferQueueItf, &state);
266    CheckErr(res);
267
268    // while (state.playIndex < 100) {
269    while (state.count) {
270        usleep(10000);
271        (*bufferQueueItf)->GetState(bufferQueueItf, &state);
272    }
273
274    /* Make sure player is stopped */
275    res = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
276    CheckErr(res);
277    /* Destroy the player */
278    (*player)->Destroy(player);
279
280    /* Destroy Output Mix object */
281    (*OutputMix)->Destroy(OutputMix);
282}
283
284
285
286int main(int argc, char* const argv[])
287{
288    LOGV("Starting sawtoothPlayer\n");
289
290    SLresult    res;
291    SLObjectItf sl;
292
293    SLEngineOption EngineOption[] = {
294            {(SLuint32) SL_ENGINEOPTION_THREADSAFE,
295            (SLuint32) SL_BOOLEAN_TRUE}};
296
297    res = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL);
298    CheckErr(res);
299    /* Realizing the SL Engine in synchronous mode. */
300    res = (*sl)->Realize(sl, SL_BOOLEAN_FALSE); CheckErr(res);
301
302    /* Run the test */
303    TestPlaySawtoothBufferQueue(sl);
304
305    /* Shutdown OpenSL ES */
306    (*sl)->Destroy(sl);
307    exit(0);
308
309
310    return 0;
311}
312