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    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
272int 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