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 SLresult res; 133 134 /* Create the engine */ 135 SLEngineOption EngineOption[] = { 136 {(SLuint32) SL_ENGINEOPTION_THREADSAFE, 137 (SLuint32) SL_BOOLEAN_TRUE}}; 138 139 res = slCreateEngine( &slEngine, 1, EngineOption, 0, NULL, NULL); 140 CheckErr(res); 141 /* Realizing the SL Engine in synchronous mode. */ 142 res = (*slEngine)->Realize(slEngine, SL_BOOLEAN_FALSE); 143 CheckErr(res); 144 /* Get the SL Engine Interface which is implicit */ 145 res = (*slEngine)->GetInterface(slEngine, SL_IID_ENGINE, (void*)&engineItf); 146 CheckErr(res); 147 148 /* Create Output Mix object to be used by player */ 149 res = (*engineItf)->CreateOutputMix(engineItf, &outputMix, 0, 150 iidArray, required); CheckErr(res); 151 /* Realizing the Output Mix object in synchronous mode. */ 152 res = (*outputMix)->Realize(outputMix, SL_BOOLEAN_FALSE); 153 CheckErr(res); 154 155 /* Setup the data source structure for the URI */ 156 // the syntax below is more future-proof than the individual field initialization 157 // with regards to OpenSL ES 1.1 but adds scary compilation warnings 158 //uri = { SL_DATALOCATOR_URI /*locatorType*/, (SLchar*) path /*URI*/ }; 159 //mime = { /*formatType*/ SL_DATAFORMAT_MIME, /*mimeType*/ (SLchar*)NULL, 160 // /*containerType*/ SL_CONTAINERTYPE_UNSPECIFIED }; 161 uri.locatorType = SL_DATALOCATOR_URI; 162 uri.URI = (SLchar*) path; 163 mime.formatType = SL_DATAFORMAT_MIME; 164 mime.mimeType = (SLchar*)NULL; 165 mime.containerType = SL_CONTAINERTYPE_UNSPECIFIED; 166 167 audioSource.pFormat = (void *)&mime; 168 audioSource.pLocator = (void *)&uri; 169 170 /* Setup the data sink structure */ 171 locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; 172 locator_outputmix.outputMix = outputMix; 173 audioSink.pLocator = (void *)&locator_outputmix; 174 audioSink.pFormat = NULL; 175 176 /* Initialize arrays required[] and iidArray[] */ 177 for (int i=0 ; i < MAX_NUMBER_INTERFACES ; i++) { 178 required[i] = SL_BOOLEAN_FALSE; 179 iidArray[i] = SL_IID_NULL; 180 } 181 /* Set arrays required[] and iidArray[] for VOLUME and PREFETCHSTATUS interface */ 182 required[0] = SL_BOOLEAN_TRUE; 183 iidArray[0] = SL_IID_VOLUME; 184 required[1] = SL_BOOLEAN_TRUE; 185 iidArray[1] = SL_IID_PREFETCHSTATUS; 186 187 fprintf(stdout, "TestSetup(%s) completed\n", path); 188 } 189 190 191 //----------------------------------------------------------------- 192 void TestTeardown() { 193 /* Destroy Output Mix object */ 194 (*outputMix)->Destroy(outputMix); 195 196 /* Shutdown OpenSL ES */ 197 (*slEngine)->Destroy(slEngine); 198 } 199 200 201 //----------------------------------------------------------------- 202 /** 203 * Create a player and, if the creation is successful, 204 * configure it, and start playing. 205 */ 206 void CreatePlayer(int playerId) { 207 SLresult res; 208 playerNum[playerId] = playerId; 209 210 /* Create the audio player */ 211 res = (*engineItf)->CreateAudioPlayer(engineItf, &audioPlayer[playerId], 212 &audioSource, &audioSink, MAX_NUMBER_INTERFACES, iidArray, required); 213 if (SL_RESULT_SUCCESS != res) { 214 // do not abort the test, just flag the player as not a candidate for destruction 215 fprintf(stdout, "CreateAudioPlayer for player %d failed\n", playerId); 216 validplayer[playerId] = false; 217 return; 218 } 219 validplayer[playerId] = true; 220 221 /* Realizing the player in synchronous mode. */ 222 res = (*audioPlayer[playerId])->Realize(audioPlayer[playerId], SL_BOOLEAN_FALSE); 223 if (SL_RESULT_SUCCESS != res) { 224 // do not abort the test, just stop the player initialization here 225 fprintf(stdout, "Realize for player %d failed\n", playerId); 226 // this player is still a candidate for destruction 227 return; 228 } 229 // after this point, any failure is a test failure 230 231 /* Get interfaces */ 232 res = (*audioPlayer[playerId])->GetInterface(audioPlayer[playerId], SL_IID_PLAY, 233 (void*)&playItfs[playerId]); 234 CheckErrPlyr(res, playerId); 235 236 res = (*audioPlayer[playerId])->GetInterface(audioPlayer[playerId], SL_IID_VOLUME, 237 (void*)&volItfs[playerId]); 238 CheckErrPlyr(res, playerId); 239 240 res = (*audioPlayer[playerId])->GetInterface(audioPlayer[playerId], SL_IID_PREFETCHSTATUS, 241 (void*)&prefetchItfs[playerId]); 242 CheckErrPlyr(res, playerId); 243 res = (*prefetchItfs[playerId])->RegisterCallback(prefetchItfs[playerId], PrefetchEventCallback, 244 &playerNum[playerId]); 245 CheckErrPlyr(res, playerId); 246 res = (*prefetchItfs[playerId])->SetCallbackEventsMask(prefetchItfs[playerId], 247 SL_PREFETCHEVENT_FILLLEVELCHANGE | SL_PREFETCHEVENT_STATUSCHANGE); 248 CheckErrPlyr(res, playerId); 249 250 /* Set the player volume */ 251 res = (*volItfs[playerId])->SetVolumeLevel( volItfs[playerId], -300); 252 CheckErrPlyr(res, playerId); 253 254 /* Set up the player callback to get events during the decoding */ 255 res = (*playItfs[playerId])->SetMarkerPosition(playItfs[playerId], 2000); 256 CheckErrPlyr(res, playerId); 257 res = (*playItfs[playerId])->SetPositionUpdatePeriod(playItfs[playerId], 500); 258 CheckErrPlyr(res, playerId); 259 res = (*playItfs[playerId])->SetCallbackEventsMask(playItfs[playerId], 260 SL_PLAYEVENT_HEADATMARKER | SL_PLAYEVENT_HEADATNEWPOS | SL_PLAYEVENT_HEADATEND); 261 CheckErrPlyr(res, playerId); 262 res = (*playItfs[playerId])->RegisterCallback(playItfs[playerId], PlayEventCallback, 263 &playerNum[playerId]); 264 CheckErrPlyr(res, playerId); 265 266 /* Configure fill level updates every 5 percent */ 267 (*prefetchItfs[playerId])->SetFillUpdatePeriod(prefetchItfs[playerId], 50); 268 269 /* Play the URI */ 270 /* first cause the player to prefetch the data */ 271 fprintf(stdout, "Setting player %d to PAUSED\n", playerId); 272 res = (*playItfs[playerId])->SetPlayState( playItfs[playerId], SL_PLAYSTATE_PAUSED ); 273 CheckErrPlyr(res, playerId); 274 /* wait until there's data to play */ 275 SLuint32 prefetchStatus = SL_PREFETCHSTATUS_UNDERFLOW; 276 SLuint32 timeOutIndex = 10; // 1s, should be enough for a local file 277 while ((prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) && (timeOutIndex > 0)) { 278 usleep(100 * 1000); 279 res = (*prefetchItfs[playerId])->GetPrefetchStatus(prefetchItfs[playerId], &prefetchStatus); 280 CheckErrPlyr(res, playerId); 281 timeOutIndex--; 282 } 283 284 if (timeOutIndex == 0) { 285 fprintf(stderr, "Prefetch timed out for player %d\n", playerId); 286 return; 287 } 288 res = (*playItfs[playerId])->SetPlayState( playItfs[playerId], SL_PLAYSTATE_PLAYING ); 289 CheckErrPlyr(res, playerId); 290 291 /* Display duration */ 292 SLmillisecond durationInMsec = SL_TIME_UNKNOWN; 293 res = (*playItfs[playerId])->GetDuration(playItfs[playerId], &durationInMsec); 294 CheckErrPlyr(res, playerId); 295 if (durationInMsec == SL_TIME_UNKNOWN) { 296 fprintf(stdout, "Content duration is unknown for player %d\n", playerId); 297 } else { 298 fprintf(stdout, "Content duration is %u ms for player %d\n", durationInMsec, playerId); 299 } 300 } 301 302 //----------------------------------------------------------------- 303 void DestroyPlayer(int playerId) { 304 fprintf(stdout, "About to destroy player %d\n", playerId); 305 /* Destroy the player */ 306 (*audioPlayer[playerId])->Destroy(audioPlayer[playerId]); 307 } 308 309 310 //----------------------------------------------------------------- 311 int main(int argc, char* const argv[]) 312 { 313 fprintf(stdout, "OpenSL ES test %s: creates and destroys as many ", argv[0]); 314 fprintf(stdout, "AudioPlayer objects as possible (max=%d)\n\n", MAX_NUMBER_PLAYERS); 315 316 if (argc == 1) { 317 fprintf(stdout, "Usage: %s path \n\t%s url\n", argv[0], argv[0]); 318 fprintf(stdout, "Example: \"%s /sdcard/my.mp3\" or \"%s file:///sdcard/my.mp3\"\n", 319 argv[0], argv[0]); 320 exit(EXIT_FAILURE); 321 } 322 323 TestSetup(argv[1]); 324 325 for (int i=0 ; i<MAX_NUMBER_PLAYERS ; i++) { 326 CreatePlayer(i); 327 } 328 fprintf(stdout, "After creating %d AudioPlayers\n", MAX_NUMBER_PLAYERS); 329 330 /* Wait for an arbitrary amount of time. if playing a long file, the players will still 331 be playing while the destructions start. */ 332 usleep(10*1000*1000); // 10s 333 334 for (int i=0 ; i<MAX_NUMBER_PLAYERS ; i++) { 335 if (validplayer[i]) { 336 DestroyPlayer(i); 337 } 338 } 339 fprintf(stdout, "After destroying valid players among %d AudioPlayers\n", MAX_NUMBER_PLAYERS); 340 341 TestTeardown(); 342 343 return EXIT_SUCCESS; 344 } 345