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