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