slesTestSawtoothBufferQueue.cpp revision 086a6f51a7b12880ed114962136972f89ed70da2
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#include <stdlib.h>
41#include <stdio.h>
42#include <string.h>
43#include <unistd.h>
44#include <sys/time.h>
45
46
47#include <SLES/OpenSLES.h>
48
49
50#define MAX_NUMBER_INTERFACES 3
51
52/* Local storage for Audio data in 16 bit words */
53#define AUDIO_DATA_STORAGE_SIZE 4096 * 100
54/* Audio data buffer size in 16 bit words. 8 data segments are used in
55this simple example */
56#define AUDIO_DATA_BUFFER_SIZE 4096/8
57
58/* Checks for error. If any errors exit the application! */
59void CheckErr( SLresult res )
60{
61    if ( res != SL_RESULT_SUCCESS )
62        {
63            fprintf(stdout, "%u SL failure, exiting\n", res);
64            exit(EXIT_FAILURE);
65        }
66    else {
67        //fprintf(stdout, "%d SL success, proceeding...\n", res);
68    }
69}
70
71/* Structure for passing information to callback function */
72typedef struct CallbackCntxt_ {
73    SLPlayItf  playItf;
74    SLint16*   pDataBase;    // Base adress of local audio data storage
75    SLint16*   pData;        // Current adress of local audio data storage
76    SLuint32   size;
77} CallbackCntxt;
78
79/* Local storage for Audio data */
80SLint16 pcmData[AUDIO_DATA_STORAGE_SIZE];
81
82/* Callback for Buffer Queue events */
83void BufferQueueCallback(
84        SLBufferQueueItf queueItf,
85        void *pContext)
86{
87    //fprintf(stdout, "BufferQueueCallback called\n");
88    SLresult res;
89    //fprintf(stdout, " pContext=%p\n", pContext);
90    CallbackCntxt *pCntxt = (CallbackCntxt*)pContext;
91
92    if(pCntxt->pData < (pCntxt->pDataBase + pCntxt->size))
93        {
94            //fprintf(stdout, "callback: before enqueue\n");
95            res = (*queueItf)->Enqueue(queueItf, (void*) pCntxt->pData,
96                    2 * AUDIO_DATA_BUFFER_SIZE); /* Size given in bytes. */
97            CheckErr(res);
98            /* Increase data pointer by buffer size */
99            pCntxt->pData += AUDIO_DATA_BUFFER_SIZE;
100        }
101    //fprintf(stdout, "end of BufferQueueCallback()\n");
102}
103
104/* Play some audio from a buffer queue  */
105void TestPlaySawtoothBufferQueue( SLObjectItf sl )
106{
107    SLEngineItf                EngineItf;
108
109    SLint32                    numOutputs = 0;
110    SLuint32                   deviceID = 0;
111
112    SLresult                   res;
113
114    SLDataSource               audioSource;
115    SLDataLocator_BufferQueue  bufferQueue;
116    SLDataFormat_PCM           pcm;
117
118    SLDataSink                 audioSink;
119    SLDataLocator_OutputMix    locator_outputmix;
120
121    SLObjectItf                player;
122    SLPlayItf                  playItf;
123    SLBufferQueueItf           bufferQueueItf;
124    SLBufferQueueState         state;
125
126    SLObjectItf                OutputMix;
127    SLVolumeItf                volumeItf;
128
129    int                        i;
130
131    SLboolean required[MAX_NUMBER_INTERFACES];
132    SLInterfaceID iidArray[MAX_NUMBER_INTERFACES];
133
134    /* Callback context for the buffer queue callback function */
135    CallbackCntxt cntxt;
136
137    /* Get the SL Engine Interface which is implicit */
138    res = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf);
139    CheckErr(res);
140
141    /* Initialize arrays required[] and iidArray[] */
142    for (i=0;i<MAX_NUMBER_INTERFACES;i++)
143        {
144            required[i] = SL_BOOLEAN_FALSE;
145            iidArray[i] = SL_IID_NULL;
146        }
147
148    // Set arrays required[] and iidArray[] for VOLUME interface
149    required[0] = SL_BOOLEAN_TRUE;
150    iidArray[0] = SL_IID_VOLUME;
151    // Create Output Mix object to be used by player
152    res = (*EngineItf)->CreateOutputMix(EngineItf, &OutputMix, 0,
153            iidArray, required); CheckErr(res);
154
155    // Realizing the Output Mix object in synchronous mode.
156    res = (*OutputMix)->Realize(OutputMix, SL_BOOLEAN_FALSE);
157    CheckErr(res);
158
159#if 0
160    res = (*OutputMix)->GetInterface(OutputMix, SL_IID_VOLUME,
161            (void*)&volumeItf); CheckErr(res);
162#endif
163
164    /* Setup the data source structure for the buffer queue */
165    bufferQueue.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
166    bufferQueue.numBuffers = 4;  /* Four buffers in our buffer queue */
167
168    /* Setup the format of the content in the buffer queue */
169    pcm.formatType = SL_DATAFORMAT_PCM;
170    pcm.numChannels = 1;//2;
171    pcm.samplesPerSec = SL_SAMPLINGRATE_44_1;
172    pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
173    pcm.containerSize = 16;
174    pcm.channelMask = SL_SPEAKER_FRONT_LEFT;// | SL_SPEAKER_FRONT_RIGHT;
175    pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
176
177    audioSource.pFormat      = (void *)&pcm;
178    audioSource.pLocator     = (void *)&bufferQueue;
179
180    /* Setup the data sink structure */
181    locator_outputmix.locatorType   = SL_DATALOCATOR_OUTPUTMIX;
182    locator_outputmix.outputMix    = OutputMix;
183    audioSink.pLocator           = (void *)&locator_outputmix;
184    audioSink.pFormat            = NULL;
185
186    /* Initialize the audio data to play */
187    unsigned int j;
188    for (j = 0; j < sizeof(pcmData)/sizeof(pcmData[0]); ++j) {
189        pcmData[j] = j*(100 + j / 200);// % 1000;
190    }
191
192    /* Initialize the context for Buffer queue callbacks */
193    cntxt.pDataBase = /*(void*)&*/pcmData;
194    cntxt.pData = cntxt.pDataBase;
195    cntxt.size = sizeof(pcmData) / 2;
196
197    /* Set arrays required[] and iidArray[] for SEEK interface
198          (PlayItf is implicit) */
199    required[0] = SL_BOOLEAN_TRUE;
200    iidArray[0] = SL_IID_BUFFERQUEUE;
201
202    /* Create the music player */
203    res = (*EngineItf)->CreateAudioPlayer(EngineItf, &player,
204            &audioSource, &audioSink, 1, iidArray, required); CheckErr(res);
205    fprintf(stdout, "bufferQueue example: after CreateAudioPlayer\n");
206
207    /* Realizing the player in synchronous mode. */
208    res = (*player)->Realize(player, SL_BOOLEAN_FALSE); CheckErr(res);
209    fprintf(stdout, "bufferQueue example: after Realize\n");
210
211    /* Get seek and play interfaces */
212    res = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf);
213    CheckErr(res);
214    fprintf(stdout, "bufferQueue example: after GetInterface(PLAY)\n");
215
216    res = (*player)->GetInterface(player, SL_IID_BUFFERQUEUE,
217            (void*)&bufferQueueItf); CheckErr(res);
218
219    /* Setup to receive buffer queue event callbacks */
220    res = (*bufferQueueItf)->RegisterCallback(bufferQueueItf,
221            BufferQueueCallback, &cntxt); CheckErr(res);
222
223#if 0
224    /* Before we start set volume to -3dB (-300mB) */
225    res = (*volumeItf)->SetVolumeLevel(volumeItf, -300); CheckErr(res);
226#endif
227
228    /* Enqueue a few buffers to get the ball rolling */
229    res = (*bufferQueueItf)->Enqueue(bufferQueueItf, cntxt.pData,
230            2 * AUDIO_DATA_BUFFER_SIZE); /* Size given in bytes. */
231    CheckErr(res);
232    cntxt.pData += AUDIO_DATA_BUFFER_SIZE;
233
234    res = (*bufferQueueItf)->Enqueue(bufferQueueItf, cntxt.pData,
235            2 * AUDIO_DATA_BUFFER_SIZE); /* Size given in bytes. */
236    CheckErr(res);
237    cntxt.pData += AUDIO_DATA_BUFFER_SIZE;
238
239    res = (*bufferQueueItf)->Enqueue(bufferQueueItf, cntxt.pData,
240            2 * AUDIO_DATA_BUFFER_SIZE); /* Size given in bytes. */
241    CheckErr(res);
242    cntxt.pData += AUDIO_DATA_BUFFER_SIZE;
243
244    /* Play the PCM samples using a buffer queue */
245    fprintf(stdout, "bufferQueue example: starting to play\n");
246    res = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PLAYING );
247    CheckErr(res);
248
249    /* Wait until the PCM data is done playing, the buffer queue callback
250           will continue to queue buffers until the entire PCM data has been
251           played. This is indicated by waiting for the count member of the
252           SLBufferQueueState to go to zero.
253     */
254    res = (*bufferQueueItf)->GetState(bufferQueueItf, &state);
255    CheckErr(res);
256
257    // while (state.playIndex < 100) {
258    while (state.count) {
259        usleep(10000);
260        (*bufferQueueItf)->GetState(bufferQueueItf, &state);
261    }
262
263    /* Make sure player is stopped */
264    res = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
265    CheckErr(res);
266    /* Destroy the player */
267    (*player)->Destroy(player);
268
269    /* Destroy Output Mix object */
270    (*OutputMix)->Destroy(OutputMix);
271}
272
273
274
275int main(int argc __unused, char* const argv[] __unused)
276{
277    SLresult    res;
278    SLObjectItf sl;
279
280    SLEngineOption EngineOption[] = {
281            {(SLuint32) SL_ENGINEOPTION_THREADSAFE,
282            (SLuint32) SL_BOOLEAN_TRUE}};
283
284    res = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL);
285    CheckErr(res);
286    /* Realizing the SL Engine in synchronous mode. */
287    res = (*sl)->Realize(sl, SL_BOOLEAN_FALSE); CheckErr(res);
288
289    /* Run the test */
290    TestPlaySawtoothBufferQueue(sl);
291
292    /* Shutdown OpenSL ES */
293    (*sl)->Destroy(sl);
294
295    return EXIT_SUCCESS;
296}
297