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 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 */ 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 */ 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 //----------------------------------------------------------------- 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 //----------------------------------------------------------------- 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 */ 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 //----------------------------------------------------------------- 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 //----------------------------------------------------------------- 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