• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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 <unistd.h>
20 //#include <sys/time.h>
21 
22 #include <SLES/OpenSLES.h>
23 
24 
25 #define MAX_NUMBER_INTERFACES 2
26 #define MAX_NUMBER_PLAYERS 40
27 
28 #define PREFETCHEVENT_ERROR_CANDIDATE \
29         (SL_PREFETCHEVENT_STATUSCHANGE | SL_PREFETCHEVENT_FILLLEVELCHANGE)
30 
31 /* the OpenSL ES engine from which we create all other resources */
32 SLObjectItf  slEngine;
33 SLEngineItf  engineItf;
34 SLObjectItf  outputMix;
35 
36 SLboolean     required[MAX_NUMBER_INTERFACES];
37 SLInterfaceID iidArray[MAX_NUMBER_INTERFACES];
38 
39 SLObjectItf  audioPlayer[MAX_NUMBER_PLAYERS];
40 bool         validplayer[MAX_NUMBER_PLAYERS];
41 int          playerNum[MAX_NUMBER_PLAYERS];
42 SLPlayItf    playItfs[MAX_NUMBER_PLAYERS];
43 SLVolumeItf  volItfs[MAX_NUMBER_PLAYERS];
44 SLPrefetchStatusItf prefetchItfs[MAX_NUMBER_PLAYERS];
45 
46 SLDataSource      audioSource;
47 SLDataLocator_URI uri;
48 SLDataFormat_MIME mime;
49 
50 SLDataSink              audioSink;
51 SLDataLocator_OutputMix locator_outputmix;
52 
53 
54 //-----------------------------------------------------------------
55 //* Exits the application if an error is encountered */
56 #define CheckErr(x) ExitOnErrorFunc(x, -1, __LINE__)
57 #define CheckErrPlyr(x, id) ExitOnErrorFunc(x, id, __LINE__)
58 
ExitOnErrorFunc(SLresult result,int playerId,int line)59 void ExitOnErrorFunc( SLresult result, int playerId, int line)
60 {
61     if (SL_RESULT_SUCCESS != result) {
62         if (playerId == -1) {
63             fprintf(stderr, "Error %u code encountered at line %d, exiting\n", result, line);
64         } else {
65             fprintf(stderr, "Error %u code encountered at line %d for player %d, exiting\n",
66                     result, line, playerId);
67         }
68         exit(EXIT_FAILURE);
69     }
70 }
71 
72 //-----------------------------------------------------------------
73 /* PrefetchStatusItf callback for an audio player */
PrefetchEventCallback(SLPrefetchStatusItf caller,void * pContext,SLuint32 event)74 void PrefetchEventCallback( SLPrefetchStatusItf caller,  void *pContext, SLuint32 event)
75 {
76     SLresult res;
77     SLpermille level = 0;
78     int* pPlayerId = (int*)pContext;
79     res = (*caller)->GetFillLevel(caller, &level); CheckErrPlyr(res, *pPlayerId);
80     SLuint32 status;
81     //fprintf(stdout, "PrefetchEventCallback: received event %u\n", event);
82     res = (*caller)->GetPrefetchStatus(caller, &status); CheckErrPlyr(res, *pPlayerId);
83     if ((PREFETCHEVENT_ERROR_CANDIDATE == (event & PREFETCHEVENT_ERROR_CANDIDATE))
84             && (level == 0) && (status == SL_PREFETCHSTATUS_UNDERFLOW)) {
85         fprintf(stdout, "PrefetchEventCallback: Error while prefetching data for player %d, "
86                 "exiting\n", *pPlayerId);
87         exit(EXIT_FAILURE);
88     }
89     if (event & SL_PREFETCHEVENT_FILLLEVELCHANGE) {
90         fprintf(stdout, "PrefetchEventCallback: Buffer fill level is = %d for player %d\n",
91                 level, *pPlayerId);
92     }
93     if (event & SL_PREFETCHEVENT_STATUSCHANGE) {
94         fprintf(stdout, "PrefetchEventCallback: Prefetch Status is = %u for player %d\n",
95                 status, *pPlayerId);
96     }
97 }
98 
99 
100 //-----------------------------------------------------------------
101 /* PlayItf callback for playback events */
PlayEventCallback(SLPlayItf caller,void * pContext,SLuint32 event)102 void PlayEventCallback(
103         SLPlayItf caller,
104         void *pContext,
105         SLuint32 event)
106 {
107     SLresult res;
108     int* pPlayerId = (int*)pContext;
109     if (SL_PLAYEVENT_HEADATEND & event) {
110         fprintf(stdout, "SL_PLAYEVENT_HEADATEND reached for player %d\n", *pPlayerId);
111         //SignalEos();
112     }
113 
114     if (SL_PLAYEVENT_HEADATNEWPOS & event) {
115         SLmillisecond pMsec = 0;
116         res = (*caller)->GetPosition(caller, &pMsec); CheckErrPlyr(res, *pPlayerId);
117         fprintf(stdout, "SL_PLAYEVENT_HEADATNEWPOS current position=%ums for player %d\n",
118                 pMsec, *pPlayerId);
119     }
120 
121     if (SL_PLAYEVENT_HEADATMARKER & event) {
122         SLmillisecond pMsec = 0;
123         res = (*caller)->GetPosition(caller, &pMsec); CheckErrPlyr(res, *pPlayerId);
124         fprintf(stdout, "SL_PLAYEVENT_HEADATMARKER current position=%ums for player %d\n",
125                 pMsec, *pPlayerId);
126     }
127 }
128 
129 
130 //-----------------------------------------------------------------
TestSetup(const char * path)131 void TestSetup(const char* path) {
132     SLint32                 numOutputs = 0;
133     SLuint32                deviceID = 0;
134     SLresult                res;
135 
136     /* Create the engine */
137     SLEngineOption EngineOption[] = {
138             {(SLuint32) SL_ENGINEOPTION_THREADSAFE,
139                     (SLuint32) SL_BOOLEAN_TRUE}};
140 
141     res = slCreateEngine( &slEngine, 1, EngineOption, 0, NULL, NULL);
142     CheckErr(res);
143     /* Realizing the SL Engine in synchronous mode. */
144     res = (*slEngine)->Realize(slEngine, SL_BOOLEAN_FALSE);
145     CheckErr(res);
146     /* Get the SL Engine Interface which is implicit */
147     res = (*slEngine)->GetInterface(slEngine, SL_IID_ENGINE, (void*)&engineItf);
148     CheckErr(res);
149 
150     /* Create Output Mix object to be used by player */
151     res = (*engineItf)->CreateOutputMix(engineItf, &outputMix, 0,
152             iidArray, required); CheckErr(res);
153     /* Realizing the Output Mix object in synchronous mode. */
154     res = (*outputMix)->Realize(outputMix, SL_BOOLEAN_FALSE);
155     CheckErr(res);
156 
157     /* Setup the data source structure for the URI */
158     // the syntax below is more future-proof than the individual field initialization
159     //  with regards to OpenSL ES 1.1 but adds scary compilation warnings
160     //uri = { SL_DATALOCATOR_URI /*locatorType*/, (SLchar*) path /*URI*/ };
161     //mime = { /*formatType*/ SL_DATAFORMAT_MIME, /*mimeType*/ (SLchar*)NULL,
162     //         /*containerType*/ SL_CONTAINERTYPE_UNSPECIFIED };
163     uri.locatorType = SL_DATALOCATOR_URI;
164     uri.URI         =  (SLchar*) path;
165     mime.formatType    = SL_DATAFORMAT_MIME;
166     mime.mimeType      = (SLchar*)NULL;
167     mime.containerType = SL_CONTAINERTYPE_UNSPECIFIED;
168 
169     audioSource.pFormat      = (void *)&mime;
170     audioSource.pLocator     = (void *)&uri;
171 
172     /* Setup the data sink structure */
173     locator_outputmix.locatorType   = SL_DATALOCATOR_OUTPUTMIX;
174     locator_outputmix.outputMix    = outputMix;
175     audioSink.pLocator           = (void *)&locator_outputmix;
176     audioSink.pFormat            = NULL;
177 
178     /* Initialize arrays required[] and iidArray[] */
179     for (int i=0 ; i < MAX_NUMBER_INTERFACES ; i++) {
180         required[i] = SL_BOOLEAN_FALSE;
181         iidArray[i] = SL_IID_NULL;
182     }
183     /* Set arrays required[] and iidArray[] for VOLUME and PREFETCHSTATUS interface */
184     required[0] = SL_BOOLEAN_TRUE;
185     iidArray[0] = SL_IID_VOLUME;
186     required[1] = SL_BOOLEAN_TRUE;
187     iidArray[1] = SL_IID_PREFETCHSTATUS;
188 
189     fprintf(stdout, "TestSetup(%s) completed\n", path);
190 }
191 
192 
193 //-----------------------------------------------------------------
TestTeardown()194 void TestTeardown() {
195     /* Destroy Output Mix object */
196     (*outputMix)->Destroy(outputMix);
197 
198     /* Shutdown OpenSL ES */
199     (*slEngine)->Destroy(slEngine);
200 }
201 
202 
203 //-----------------------------------------------------------------
204 /**
205  * Create a player and, if the creation is successful,
206  * configure it, and start playing.
207  */
CreatePlayer(int playerId)208 void CreatePlayer(int playerId) {
209     SLresult res;
210     playerNum[playerId] = playerId;
211 
212     /* Create the audio player */
213     res = (*engineItf)->CreateAudioPlayer(engineItf, &audioPlayer[playerId],
214             &audioSource, &audioSink, MAX_NUMBER_INTERFACES, iidArray, required);
215     if (SL_RESULT_SUCCESS != res) {
216             // do not abort the test, just flag the player as not a candidate for destruction
217             fprintf(stdout, "CreateAudioPlayer for player %d failed\n", playerId);
218             validplayer[playerId] = false;
219             return;
220         }
221     validplayer[playerId] = true;
222 
223     /* Realizing the player in synchronous mode. */
224     res = (*audioPlayer[playerId])->Realize(audioPlayer[playerId], SL_BOOLEAN_FALSE);
225     if (SL_RESULT_SUCCESS != res) {
226         // do not abort the test, just stop the player initialization here
227         fprintf(stdout, "Realize for player %d failed\n", playerId);
228         // this player is still a candidate for destruction
229         return;
230     }
231     // after this point, any failure is a test failure
232 
233     /* Get interfaces */
234     res = (*audioPlayer[playerId])->GetInterface(audioPlayer[playerId], SL_IID_PLAY,
235             (void*)&playItfs[playerId]);
236     CheckErrPlyr(res, playerId);
237 
238     res = (*audioPlayer[playerId])->GetInterface(audioPlayer[playerId], SL_IID_VOLUME,
239             (void*)&volItfs[playerId]);
240     CheckErrPlyr(res, playerId);
241 
242     res = (*audioPlayer[playerId])->GetInterface(audioPlayer[playerId], SL_IID_PREFETCHSTATUS,
243             (void*)&prefetchItfs[playerId]);
244     CheckErrPlyr(res, playerId);
245     res = (*prefetchItfs[playerId])->RegisterCallback(prefetchItfs[playerId], PrefetchEventCallback,
246             &playerNum[playerId]);
247     CheckErrPlyr(res, playerId);
248     res = (*prefetchItfs[playerId])->SetCallbackEventsMask(prefetchItfs[playerId],
249             SL_PREFETCHEVENT_FILLLEVELCHANGE | SL_PREFETCHEVENT_STATUSCHANGE);
250     CheckErrPlyr(res, playerId);
251 
252     /* Set the player volume */
253     res = (*volItfs[playerId])->SetVolumeLevel( volItfs[playerId], -300);
254     CheckErrPlyr(res, playerId);
255 
256     /* Set up the player callback to get events during the decoding */
257     res = (*playItfs[playerId])->SetMarkerPosition(playItfs[playerId], 2000);
258     CheckErrPlyr(res, playerId);
259     res = (*playItfs[playerId])->SetPositionUpdatePeriod(playItfs[playerId], 500);
260     CheckErrPlyr(res, playerId);
261     res = (*playItfs[playerId])->SetCallbackEventsMask(playItfs[playerId],
262             SL_PLAYEVENT_HEADATMARKER | SL_PLAYEVENT_HEADATNEWPOS | SL_PLAYEVENT_HEADATEND);
263     CheckErrPlyr(res, playerId);
264     res = (*playItfs[playerId])->RegisterCallback(playItfs[playerId], PlayEventCallback,
265             &playerNum[playerId]);
266     CheckErrPlyr(res, playerId);
267 
268     /* Configure fill level updates every 5 percent */
269     (*prefetchItfs[playerId])->SetFillUpdatePeriod(prefetchItfs[playerId], 50);
270 
271     /* Play the URI */
272     /*     first cause the player to prefetch the data */
273     fprintf(stdout, "Setting player %d  to PAUSED\n", playerId);
274     res = (*playItfs[playerId])->SetPlayState( playItfs[playerId], SL_PLAYSTATE_PAUSED );
275     CheckErrPlyr(res, playerId);
276     /*     wait until there's data to play */
277     SLuint32 prefetchStatus = SL_PREFETCHSTATUS_UNDERFLOW;
278     SLuint32 timeOutIndex = 10; // 1s, should be enough for a local file
279     while ((prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) && (timeOutIndex > 0)) {
280         usleep(100 * 1000);
281         res = (*prefetchItfs[playerId])->GetPrefetchStatus(prefetchItfs[playerId], &prefetchStatus);
282         CheckErrPlyr(res, playerId);
283         timeOutIndex--;
284     }
285 
286     if (timeOutIndex == 0) {
287         fprintf(stderr, "Prefetch timed out for player %d\n", playerId);
288         return;
289     }
290     res = (*playItfs[playerId])->SetPlayState( playItfs[playerId], SL_PLAYSTATE_PLAYING );
291     CheckErrPlyr(res, playerId);
292 
293     /* Display duration */
294     SLmillisecond durationInMsec = SL_TIME_UNKNOWN;
295     res = (*playItfs[playerId])->GetDuration(playItfs[playerId], &durationInMsec);
296     CheckErrPlyr(res, playerId);
297     if (durationInMsec == SL_TIME_UNKNOWN) {
298         fprintf(stdout, "Content duration is unknown for player %d\n", playerId);
299     } else {
300         fprintf(stdout, "Content duration is %u ms for player %d\n", durationInMsec, playerId);
301     }
302 }
303 
304 //-----------------------------------------------------------------
DestroyPlayer(int playerId)305 void DestroyPlayer(int playerId) {
306     fprintf(stdout, "About to destroy player %d\n", playerId);
307     /* Destroy the player */
308     (*audioPlayer[playerId])->Destroy(audioPlayer[playerId]);
309 }
310 
311 
312 //-----------------------------------------------------------------
main(int argc,char * const argv[])313 int main(int argc, char* const argv[])
314 {
315     fprintf(stdout, "OpenSL ES test %s: creates and destroys as many ", argv[0]);
316     fprintf(stdout, "AudioPlayer objects as possible (max=%d)\n\n", MAX_NUMBER_PLAYERS);
317 
318     if (argc == 1) {
319         fprintf(stdout, "Usage: %s path \n\t%s url\n", argv[0], argv[0]);
320         fprintf(stdout, "Example: \"%s /sdcard/my.mp3\"  or \"%s file:///sdcard/my.mp3\"\n",
321                 argv[0], argv[0]);
322         exit(EXIT_FAILURE);
323     }
324 
325     TestSetup(argv[1]);
326 
327     for (int i=0 ; i<MAX_NUMBER_PLAYERS ; i++) {
328         CreatePlayer(i);
329     }
330     fprintf(stdout, "After creating %d AudioPlayers\n", MAX_NUMBER_PLAYERS);
331 
332     /* Wait for an arbitrary amount of time. if playing a long file, the players will still
333        be playing while the destructions start. */
334     usleep(10*1000*1000); // 10s
335 
336     for (int i=0 ; i<MAX_NUMBER_PLAYERS ; i++) {
337         if (validplayer[i]) {
338             DestroyPlayer(i);
339         }
340     }
341     fprintf(stdout, "After destroying valid players among %d AudioPlayers\n", MAX_NUMBER_PLAYERS);
342 
343     TestTeardown();
344 
345     return EXIT_SUCCESS;
346 }
347