• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <sys/time.h>
22 
23 #include "SLES/OpenSLES.h"
24 
25 
26 #define MAX_NUMBER_INTERFACES 2
27 
28 #define REPETITIONS 4
29 
30 //-----------------------------------------------------------------
31 //* Exits the application if an error is encountered */
32 #define CheckErr(x) ExitOnErrorFunc(x,__LINE__)
33 
ExitOnErrorFunc(SLresult result,int line)34 void ExitOnErrorFunc( SLresult result , int line)
35 {
36     if (SL_RESULT_SUCCESS != result) {
37         fprintf(stderr, "%lu error code encountered at line %d, exiting\n", result, line);
38         exit(EXIT_FAILURE);
39     }
40 }
41 
42 //-----------------------------------------------------------------
43 /* PrefetchStatusItf callback for an audio player */
PrefetchEventCallback(SLPrefetchStatusItf caller,void * pContext,SLuint32 event)44 void PrefetchEventCallback( SLPrefetchStatusItf caller,  void *pContext, SLuint32 event)
45 {
46     SLpermille level = 0;
47     (*caller)->GetFillLevel(caller, &level);
48     SLuint32 status;
49     //fprintf(stdout, "\t\tPrefetchEventCallback: received event %lu\n", event);
50     (*caller)->GetPrefetchStatus(caller, &status);
51     if ((event & (SL_PREFETCHEVENT_STATUSCHANGE|SL_PREFETCHEVENT_FILLLEVELCHANGE))
52             && (level == 0) && (status == SL_PREFETCHSTATUS_UNDERFLOW)) {
53         fprintf(stdout, "\t\tPrefetchEventCallback: Error while prefetching data, exiting\n");
54         //exit(EXIT_FAILURE);
55     }
56     if (event & SL_PREFETCHEVENT_FILLLEVELCHANGE) {
57         fprintf(stdout, "\t\tPrefetchEventCallback: Buffer fill level is = %d\n", level);
58     }
59     if (event & SL_PREFETCHEVENT_STATUSCHANGE) {
60         fprintf(stdout, "\t\tPrefetchEventCallback: Prefetch Status is = %lu\n", status);
61     }
62 
63 }
64 
65 
66 //-----------------------------------------------------------------
67 
68 /* Play some music from a URI  */
TestLoopUri(SLObjectItf sl,const char * path)69 void TestLoopUri( SLObjectItf sl, const char* path)
70 {
71     SLEngineItf                EngineItf;
72 
73     SLint32                    numOutputs = 0;
74     SLuint32                   deviceID = 0;
75 
76     SLresult                   res;
77 
78     SLDataSource               audioSource;
79     SLDataLocator_URI          uri;
80     SLDataFormat_MIME          mime;
81 
82     SLDataSink                 audioSink;
83     SLDataLocator_OutputMix    locator_outputmix;
84 
85     SLObjectItf                player;
86     SLPlayItf                  playItf;
87     SLSeekItf                  seekItf;
88     SLPrefetchStatusItf        prefetchItf;
89 
90     SLObjectItf                OutputMix;
91 
92     SLboolean required[MAX_NUMBER_INTERFACES];
93     SLInterfaceID iidArray[MAX_NUMBER_INTERFACES];
94 
95     /* Get the SL Engine Interface which is implicit */
96     res = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf);
97     CheckErr(res);
98 
99     /* Initialize arrays required[] and iidArray[] */
100     for (int i=0 ; i < MAX_NUMBER_INTERFACES ; i++) {
101         required[i] = SL_BOOLEAN_FALSE;
102         iidArray[i] = SL_IID_NULL;
103     }
104 
105     required[0] = SL_BOOLEAN_TRUE;
106     iidArray[0] = SL_IID_VOLUME;
107     // Create Output Mix object to be used by player
108     res = (*EngineItf)->CreateOutputMix(EngineItf, &OutputMix, 0,
109             iidArray, required); CheckErr(res);
110 
111     // Realizing the Output Mix object in synchronous mode.
112     res = (*OutputMix)->Realize(OutputMix, SL_BOOLEAN_FALSE);
113     CheckErr(res);
114 
115     /* Setup the data source structure for the URI */
116     uri.locatorType = SL_DATALOCATOR_URI;
117     uri.URI         =  (SLchar*) path;
118     mime.formatType    = SL_DATAFORMAT_MIME;
119     mime.mimeType      = (SLchar*)NULL;
120     mime.containerType = SL_CONTAINERTYPE_UNSPECIFIED;
121 
122     audioSource.pFormat      = (void *)&mime;
123     audioSource.pLocator     = (void *)&uri;
124 
125     /* Setup the data sink structure */
126     locator_outputmix.locatorType   = SL_DATALOCATOR_OUTPUTMIX;
127     locator_outputmix.outputMix    = OutputMix;
128     audioSink.pLocator           = (void *)&locator_outputmix;
129     audioSink.pFormat            = NULL;
130 
131     /* Create the audio player */
132     required[0] = SL_BOOLEAN_TRUE;
133     iidArray[0] = SL_IID_SEEK;
134     required[1] = SL_BOOLEAN_TRUE;
135     iidArray[1] = SL_IID_PREFETCHSTATUS;
136     res = (*EngineItf)->CreateAudioPlayer(EngineItf, &player, &audioSource, &audioSink,
137             MAX_NUMBER_INTERFACES, iidArray, required); CheckErr(res);
138 
139     /* Realizing the player in synchronous mode. */
140     res = (*player)->Realize(player, SL_BOOLEAN_FALSE); CheckErr(res);
141     fprintf(stdout, "URI example: after Realize\n");
142 
143     /* Get interfaces */
144     res = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf);
145     CheckErr(res);
146 
147     res = (*player)->GetInterface(player, SL_IID_SEEK,  (void*)&seekItf);
148     CheckErr(res);
149 
150     res = (*player)->GetInterface(player, SL_IID_PREFETCHSTATUS, (void*)&prefetchItf);
151     CheckErr(res);
152     res = (*prefetchItf)->RegisterCallback(prefetchItf, PrefetchEventCallback, &prefetchItf);
153     CheckErr(res);
154     res = (*prefetchItf)->SetCallbackEventsMask(prefetchItf,
155             SL_PREFETCHEVENT_FILLLEVELCHANGE | SL_PREFETCHEVENT_STATUSCHANGE);
156     CheckErr(res);
157 
158     /* Configure fill level updates every 5 percent */
159     (*prefetchItf)->SetFillUpdatePeriod(prefetchItf, 50);
160 
161     /* Display duration */
162     SLmillisecond durationInMsec = SL_TIME_UNKNOWN;
163     res = (*playItf)->GetDuration(playItf, &durationInMsec);
164     CheckErr(res);
165     if (durationInMsec == SL_TIME_UNKNOWN) {
166         fprintf(stdout, "Content duration is unknown (before starting to prefetch)\n");
167     } else {
168         fprintf(stdout, "Content duration is %lu ms (before starting to prefetch)\n",
169                 durationInMsec);
170     }
171 
172     /* Loop on the whole of the content */
173     res = (*seekItf)->SetLoop(seekItf, SL_BOOLEAN_TRUE, 0, SL_TIME_UNKNOWN);
174     CheckErr(res);
175 
176     /* Play the URI */
177     /*     first cause the player to prefetch the data */
178     res = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PAUSED );
179     CheckErr(res);
180 
181     /*     wait until there's data to play */
182     //SLpermille fillLevel = 0;
183     SLuint32 prefetchStatus = SL_PREFETCHSTATUS_UNDERFLOW;
184     SLuint32 timeOutIndex = 100; // 10s
185     while ((prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) && (timeOutIndex > 0)) {
186         usleep(100 * 1000);
187         (*prefetchItf)->GetPrefetchStatus(prefetchItf, &prefetchStatus);
188         timeOutIndex--;
189     }
190 
191     if (timeOutIndex == 0) {
192         fprintf(stderr, "\nWe\'re done waiting, failed to prefetch data in time, exiting\n");
193         goto destroyRes;
194     }
195 
196     /* Display duration again, */
197     res = (*playItf)->GetDuration(playItf, &durationInMsec);
198     CheckErr(res);
199     if (durationInMsec == SL_TIME_UNKNOWN) {
200         fprintf(stdout, "Content duration is unknown (after prefetch completed)\n");
201     } else {
202         fprintf(stdout, "Content duration is %lu ms (after prefetch completed)\n", durationInMsec);
203     }
204 
205     fprintf(stdout, "starting to play\n");
206     res = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PLAYING );
207     CheckErr(res);
208 
209     /* Wait as long as the duration of the content, times the repetitions,
210      * before stopping the loop */
211     usleep( (REPETITIONS-1) * durationInMsec * 1100);
212     res = (*seekItf)->SetLoop(seekItf, SL_BOOLEAN_FALSE, 0, SL_TIME_UNKNOWN);
213     CheckErr(res);
214     fprintf(stdout, "As of now, stopped looping (sound shouldn't repeat from now on)\n");
215     /* wait some more to make sure it doesn't repeat */
216     usleep(durationInMsec * 1000);
217 
218     /* Stop playback */
219     fprintf(stdout, "stopping playback\n");
220     res = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
221     CheckErr(res);
222 
223 destroyRes:
224 
225     /* Destroy the player */
226     (*player)->Destroy(player);
227 
228     /* Destroy Output Mix object */
229     (*OutputMix)->Destroy(OutputMix);
230 }
231 
232 //-----------------------------------------------------------------
main(int argc,char * const argv[])233 int main(int argc, char* const argv[])
234 {
235     SLresult    res;
236     SLObjectItf sl;
237 
238     fprintf(stdout, "OpenSL ES test %s: exercises SLPlayItf, SLSeekItf ", argv[0]);
239     fprintf(stdout, "and AudioPlayer with SLDataLocator_URI source / OutputMix sink\n");
240     fprintf(stdout, "Plays a sound and loops it %d times.\n\n", REPETITIONS);
241 
242     if (argc == 1) {
243         fprintf(stdout, "Usage: \n\t%s path \n\t%s url\n", argv[0], argv[0]);
244         fprintf(stdout, "Example: \"%s /sdcard/my.mp3\"  or \"%s file:///sdcard/my.mp3\"\n",
245                 argv[0], argv[0]);
246         exit(EXIT_FAILURE);
247     }
248 
249     SLEngineOption EngineOption[] = {
250             {(SLuint32) SL_ENGINEOPTION_THREADSAFE,
251             (SLuint32) SL_BOOLEAN_TRUE}};
252 
253     res = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL);
254     CheckErr(res);
255     /* Realizing the SL Engine in synchronous mode. */
256     res = (*sl)->Realize(sl, SL_BOOLEAN_FALSE);
257     CheckErr(res);
258 
259     TestLoopUri(sl, argv[1]);
260 
261     /* Shutdown OpenSL ES */
262     (*sl)->Destroy(sl);
263 
264     return EXIT_SUCCESS;
265 }
266