slesTestDecodeToBuffQueue.cpp revision 68c8a1b6deea46eeca57848768a92e96d583aadd
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/* Audio Decode Test 18 19First run the program from shell: 20 # slesTest_decodeToBuffQueue /sdcard/myFile.mp3 4 21 22These use adb on host to retrieve the decoded file: 23 % adb pull /sdcard/myFile.mp3.raw myFile.raw 24 25How to examine the output with Audacity: 26 Project / Import raw data 27 Select myFile.raw file, then click Open button 28 Choose these options: 29 Signed 16-bit PCM 30 Little-endian 31 1 Channel (Mono) / 2 Channels (Stereo) based on the selected file 32 Sample rate same as the selected file 33 Click Import button 34 35*/ 36 37 38#include <stdlib.h> 39#include <stdio.h> 40#include <string.h> 41#include <unistd.h> 42#include <sys/time.h> 43#include <fcntl.h> 44#include <utils/threads.h> 45 46#include <SLES/OpenSLES.h> 47#include <SLES/OpenSLES_Android.h> 48 49/* Explicitly requesting SL_IID_ANDROIDSIMPLEBUFFERQUEUE and SL_IID_PREFETCHSTATUS 50 * on the AudioPlayer object for decoding, SL_IID_METADATAEXTRACTION for retrieving the 51 * format of the decoded audio */ 52#define NUM_EXPLICIT_INTERFACES_FOR_PLAYER 3 53 54/* Size of the decode buffer queue */ 55#define NB_BUFFERS_IN_QUEUE 4 56/* Size of each buffer in the queue */ 57#define BUFFER_SIZE_IN_SAMPLES 1152 // number of samples per MP3 frame 58#define BUFFER_SIZE_IN_BYTES (2*BUFFER_SIZE_IN_SAMPLES) 59 60/* Local storage for decoded audio data */ 61int8_t pcmData[NB_BUFFERS_IN_QUEUE * BUFFER_SIZE_IN_BYTES]; 62 63/* destination for decoded data */ 64static FILE* gFp; 65 66/* to display the number of decode iterations */ 67static int counter=0; 68 69/* metadata key index for the PCM format information we want to retrieve */ 70static int channelCountKeyIndex = -1; 71static int sampleRateKeyIndex = -1; 72/* size of the struct to retrieve the PCM format metadata values: the values we're interested in 73 * are SLuint32, but it is saved in the data field of a SLMetadataInfo, hence the larger size. 74 * Nate that this size is queried and displayed at l.452 for demonstration/test purposes. 75 * */ 76#define PCM_METADATA_VALUE_SIZE 32 77/* used to query metadata values */ 78static SLMetadataInfo *pcmMetaData = NULL; 79/* we only want to query / display the PCM format once */ 80static bool formatQueried = false; 81 82/* to signal to the test app the end of the stream to decode has been reached */ 83bool eos = false; 84android::Mutex eosLock; 85android::Condition eosCondition; 86 87/* used to detect errors likely to have occured when the OpenSL ES framework fails to open 88 * a resource, for instance because a file URI is invalid, or an HTTP server doesn't respond. 89 */ 90#define PREFETCHEVENT_ERROR_CANDIDATE \ 91 (SL_PREFETCHEVENT_STATUSCHANGE | SL_PREFETCHEVENT_FILLLEVELCHANGE) 92 93//----------------------------------------------------------------- 94/* Exits the application if an error is encountered */ 95#define ExitOnError(x) ExitOnErrorFunc(x,__LINE__) 96 97void ExitOnErrorFunc( SLresult result , int line) 98{ 99 if (SL_RESULT_SUCCESS != result) { 100 fprintf(stdout, "Error code %u encountered at line %d, exiting\n", result, line); 101 exit(EXIT_FAILURE); 102 } 103} 104 105/* Used to signal prefetching failures */ 106bool prefetchError = false; 107 108//----------------------------------------------------------------- 109/* Structure for passing information to callback function */ 110typedef struct CallbackCntxt_ { 111 SLPlayItf playItf; 112 SLMetadataExtractionItf metaItf; 113 SLuint32 size; 114 SLint8* pDataBase; // Base address of local audio data storage 115 SLint8* pData; // Current address of local audio data storage 116} CallbackCntxt; 117 118//----------------------------------------------------------------- 119void SignalEos() { 120 android::Mutex::Autolock autoLock(eosLock); 121 eos = true; 122 eosCondition.signal(); 123} 124 125//----------------------------------------------------------------- 126/* Callback for "prefetch" events, here used to detect audio resource opening errors */ 127void PrefetchEventCallback( SLPrefetchStatusItf caller, void *pContext, SLuint32 event) 128{ 129 SLpermille level = 0; 130 (*caller)->GetFillLevel(caller, &level); 131 SLuint32 status; 132 //fprintf(stdout, "PrefetchEventCallback: received event %u\n", event); 133 (*caller)->GetPrefetchStatus(caller, &status); 134 if ((PREFETCHEVENT_ERROR_CANDIDATE == (event & PREFETCHEVENT_ERROR_CANDIDATE)) 135 && (level == 0) && (status == SL_PREFETCHSTATUS_UNDERFLOW)) { 136 fprintf(stdout, "PrefetchEventCallback: Error while prefetching data, exiting\n"); 137 prefetchError = true; 138 SignalEos(); 139 } 140} 141 142//----------------------------------------------------------------- 143/* Callback for "playback" events, i.e. event happening during decoding */ 144void DecProgressCallback( 145 SLPlayItf caller, 146 void *pContext, 147 SLuint32 event) 148{ 149 if (SL_PLAYEVENT_HEADATEND & event) { 150 fprintf(stdout, "SL_PLAYEVENT_HEADATEND reached\n"); 151 SLmillisecond pMsec = 0; 152 SLresult res = (*caller)->GetPosition(caller, &pMsec); ExitOnError(res); 153 fprintf(stdout, "Position when SL_PLAYEVENT_HEADATEND received is %ums\n", pMsec); 154 SignalEos(); 155 } 156 157 if (SL_PLAYEVENT_HEADATNEWPOS & event) { 158 SLmillisecond pMsec = 0; 159 (*caller)->GetPosition(caller, &pMsec); 160 fprintf(stdout, "SL_PLAYEVENT_HEADATNEWPOS current position=%ums\n", pMsec); 161 } 162 163 if (SL_PLAYEVENT_HEADATMARKER & event) { 164 SLmillisecond pMsec = 0; 165 (*caller)->GetPosition(caller, &pMsec); 166 fprintf(stdout, "SL_PLAYEVENT_HEADATMARKER current position=%ums\n", pMsec); 167 } 168} 169 170//----------------------------------------------------------------- 171/* Callback for decoding buffer queue events */ 172void DecPlayCallback( 173 SLAndroidSimpleBufferQueueItf queueItf, 174 void *pContext) 175{ 176 counter++; 177 fprintf(stdout, "DecPlayCallback called (iteration %d) ", counter); 178 179 CallbackCntxt *pCntxt = (CallbackCntxt*)pContext; 180 181 /* Save the decoded data */ 182 if (fwrite(pCntxt->pDataBase, 1, BUFFER_SIZE_IN_BYTES, gFp) < BUFFER_SIZE_IN_BYTES) { 183 fprintf(stdout, "Error writing to output file, signaling EOS\n"); 184 SignalEos(); 185 return; 186 } 187 188 /* Increase data pointer by buffer size */ 189 pCntxt->pData += BUFFER_SIZE_IN_BYTES; 190 191 if (pCntxt->pData >= pCntxt->pDataBase + (NB_BUFFERS_IN_QUEUE * BUFFER_SIZE_IN_BYTES)) { 192 pCntxt->pData = pCntxt->pDataBase; 193 } 194 195 ExitOnError( (*queueItf)->Enqueue(queueItf, pCntxt->pDataBase, BUFFER_SIZE_IN_BYTES) ); 196 // Note: adding a sleep here or any sync point is a way to slow down the decoding, or 197 // synchronize it with some other event, as the OpenSL ES framework will block until the 198 // buffer queue callback return to proceed with the decoding. 199 200#if 0 201 /* Example: buffer queue state display */ 202 SLAndroidSimpleBufferQueueState decQueueState; 203 ExitOnError( (*queueItf)->GetState(queueItf, &decQueueState) ); 204 205 fprintf(stderr, "\DecBufferQueueCallback now has pCntxt->pData=%p queue: " 206 "count=%u playIndex=%u\n", 207 pCntxt->pData, decQueueState.count, decQueueState.index); 208#endif 209 210#if 0 211 /* Example: display duration in callback where we use the callback context for the SLPlayItf*/ 212 SLmillisecond durationInMsec = SL_TIME_UNKNOWN; 213 SLresult result = (*pCntxt->playItf)->GetDuration(pCntxt->playItf, &durationInMsec); 214 ExitOnError(result); 215 if (durationInMsec == SL_TIME_UNKNOWN) { 216 fprintf(stdout, "Content duration is unknown (in dec callback)\n"); 217 } else { 218 fprintf(stdout, "Content duration is %ums (in dec callback)\n", 219 durationInMsec); 220 } 221#endif 222 223#if 0 224 /* Example: display position in callback where we use the callback context for the SLPlayItf*/ 225 SLmillisecond posMsec = SL_TIME_UNKNOWN; 226 SLresult result = (*pCntxt->playItf)->GetPosition(pCntxt->playItf, &posMsec); 227 ExitOnError(result); 228 if (posMsec == SL_TIME_UNKNOWN) { 229 fprintf(stdout, "Content position is unknown (in dec callback)\n"); 230 } else { 231 fprintf(stdout, "Content position is %ums (in dec callback)\n", 232 posMsec); 233 } 234#endif 235 236 /* Example: query of the decoded PCM format */ 237 if (formatQueried) { 238 return; 239 } 240 SLresult res = (*pCntxt->metaItf)->GetValue(pCntxt->metaItf, sampleRateKeyIndex, 241 PCM_METADATA_VALUE_SIZE, pcmMetaData); ExitOnError(res); 242 // Note: here we could verify the following: 243 // pcmMetaData->encoding == SL_CHARACTERENCODING_BINARY 244 // pcmMetaData->size == sizeof(SLuint32) 245 // but the call was successful for the PCM format keys, so those conditions are implied 246 fprintf(stdout, "sample rate = %dHz, ", *((SLuint32*)pcmMetaData->data)); 247 res = (*pCntxt->metaItf)->GetValue(pCntxt->metaItf, channelCountKeyIndex, 248 PCM_METADATA_VALUE_SIZE, pcmMetaData); ExitOnError(res); 249 fprintf(stdout, " channel count = %d\n", *((SLuint32*)pcmMetaData->data)); 250 formatQueried = true; 251} 252 253//----------------------------------------------------------------- 254 255/* Decode an audio path by opening a file descriptor on that path */ 256void TestDecToBuffQueue( SLObjectItf sl, const char* path) 257{ 258 size_t len = strlen((const char *) path); 259 char* outputPath = (char*) malloc(len + 4 + 1); // save room to concatenate ".raw" 260 if (NULL == outputPath) { 261 ExitOnError(SL_RESULT_RESOURCE_ERROR); 262 } 263 memcpy(outputPath, path, len + 1); 264 strcat(outputPath, ".raw"); 265 gFp = fopen(outputPath, "w"); 266 if (NULL == gFp) { 267 ExitOnError(SL_RESULT_RESOURCE_ERROR); 268 } 269 270 SLresult result; 271 SLEngineItf EngineItf; 272 273 /* Objects this application uses: one audio player */ 274 SLObjectItf player; 275 276 /* Interfaces for the audio player */ 277 SLAndroidSimpleBufferQueueItf decBuffQueueItf; 278 SLPrefetchStatusItf prefetchItf; 279 SLPlayItf playItf; 280 SLMetadataExtractionItf mdExtrItf; 281 282 /* Source of audio data for the decoding */ 283 SLDataSource decSource; 284 SLDataLocator_URI decUri; 285 SLDataFormat_MIME decMime; 286 287 /* Data sink for decoded audio */ 288 SLDataSink decDest; 289 SLDataLocator_AndroidSimpleBufferQueue decBuffQueue; 290 SLDataFormat_PCM pcm; 291 292 SLboolean required[NUM_EXPLICIT_INTERFACES_FOR_PLAYER]; 293 SLInterfaceID iidArray[NUM_EXPLICIT_INTERFACES_FOR_PLAYER]; 294 295 /* Get the SL Engine Interface which is implicit */ 296 result = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf); 297 ExitOnError(result); 298 299 /* Initialize arrays required[] and iidArray[] */ 300 for (int i=0 ; i < NUM_EXPLICIT_INTERFACES_FOR_PLAYER ; i++) { 301 required[i] = SL_BOOLEAN_FALSE; 302 iidArray[i] = SL_IID_NULL; 303 } 304 305 /* allocate memory to receive the PCM format metadata */ 306 if (!pcmMetaData) { 307 pcmMetaData = (SLMetadataInfo*) malloc(PCM_METADATA_VALUE_SIZE); 308 } 309 310 formatQueried = false; 311 312 /* ------------------------------------------------------ */ 313 /* Configuration of the player */ 314 315 /* Request the AndroidSimpleBufferQueue interface */ 316 required[0] = SL_BOOLEAN_TRUE; 317 iidArray[0] = SL_IID_ANDROIDSIMPLEBUFFERQUEUE; 318 /* Request the PrefetchStatus interface */ 319 required[1] = SL_BOOLEAN_TRUE; 320 iidArray[1] = SL_IID_PREFETCHSTATUS; 321 /* Request the PrefetchStatus interface */ 322 required[2] = SL_BOOLEAN_TRUE; 323 iidArray[2] = SL_IID_METADATAEXTRACTION; 324 325 /* Setup the data source */ 326 decUri.locatorType = SL_DATALOCATOR_URI; 327 decUri.URI = (SLchar*)path; 328 decMime.formatType = SL_DATAFORMAT_MIME; 329 /* this is how ignored mime information is specified, according to OpenSL ES spec 330 * in 9.1.6 SLDataFormat_MIME and 8.23 SLMetadataTraversalItf GetChildInfo */ 331 decMime.mimeType = (SLchar*)NULL; 332 decMime.containerType = SL_CONTAINERTYPE_UNSPECIFIED; 333 decSource.pLocator = (void *) &decUri; 334 decSource.pFormat = (void *) &decMime; 335 336 /* Setup the data sink */ 337 decBuffQueue.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; 338 decBuffQueue.numBuffers = NB_BUFFERS_IN_QUEUE; 339 /* set up the format of the data in the buffer queue */ 340 pcm.formatType = SL_DATAFORMAT_PCM; 341 // FIXME valid value required but currently ignored 342 pcm.numChannels = 1; 343 pcm.samplesPerSec = SL_SAMPLINGRATE_8; 344 pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16; 345 pcm.containerSize = 16; 346 pcm.channelMask = SL_SPEAKER_FRONT_LEFT; 347 pcm.endianness = SL_BYTEORDER_LITTLEENDIAN; 348 349 decDest.pLocator = (void *) &decBuffQueue; 350 decDest.pFormat = (void * ) &pcm; 351 352 /* Create the audio player */ 353 result = (*EngineItf)->CreateAudioPlayer(EngineItf, &player, &decSource, &decDest, 354 NUM_EXPLICIT_INTERFACES_FOR_PLAYER, iidArray, required); 355 ExitOnError(result); 356 fprintf(stdout, "Player created\n"); 357 358 /* Realize the player in synchronous mode. */ 359 result = (*player)->Realize(player, SL_BOOLEAN_FALSE); 360 ExitOnError(result); 361 fprintf(stdout, "Player realized\n"); 362 363 /* Get the play interface which is implicit */ 364 result = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf); 365 ExitOnError(result); 366 367 /* Set up the player callback to get events during the decoding */ 368 // FIXME currently ignored 369 result = (*playItf)->SetMarkerPosition(playItf, 2000); 370 ExitOnError(result); 371 result = (*playItf)->SetPositionUpdatePeriod(playItf, 500); 372 ExitOnError(result); 373 result = (*playItf)->SetCallbackEventsMask(playItf, 374 SL_PLAYEVENT_HEADATMARKER | SL_PLAYEVENT_HEADATNEWPOS | SL_PLAYEVENT_HEADATEND); 375 ExitOnError(result); 376 result = (*playItf)->RegisterCallback(playItf, DecProgressCallback, NULL); 377 ExitOnError(result); 378 fprintf(stdout, "Play callback registered\n"); 379 380 /* Get the buffer queue interface which was explicitly requested */ 381 result = (*player)->GetInterface(player, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, 382 (void*)&decBuffQueueItf); 383 ExitOnError(result); 384 385 /* Get the prefetch status interface which was explicitly requested */ 386 result = (*player)->GetInterface(player, SL_IID_PREFETCHSTATUS, (void*)&prefetchItf); 387 ExitOnError(result); 388 389 /* Get the metadata extraction interface which was explicitly requested */ 390 result = (*player)->GetInterface(player, SL_IID_METADATAEXTRACTION, (void*)&mdExtrItf); 391 ExitOnError(result); 392 393 /* ------------------------------------------------------ */ 394 /* Initialize the callback and its context for the decoding buffer queue */ 395 CallbackCntxt cntxt; 396 cntxt.playItf = playItf; 397 cntxt.metaItf = mdExtrItf; 398 cntxt.pDataBase = (int8_t*)&pcmData; 399 cntxt.pData = cntxt.pDataBase; 400 cntxt.size = sizeof(pcmData); 401 result = (*decBuffQueueItf)->RegisterCallback(decBuffQueueItf, DecPlayCallback, &cntxt); 402 ExitOnError(result); 403 404 /* Enqueue buffers to map the region of memory allocated to store the decoded data */ 405 fprintf(stdout,"Enqueueing buffer "); 406 for(int i = 0 ; i < NB_BUFFERS_IN_QUEUE ; i++) { 407 fprintf(stdout,"%d \n", i); 408 result = (*decBuffQueueItf)->Enqueue(decBuffQueueItf, cntxt.pData, BUFFER_SIZE_IN_BYTES); 409 ExitOnError(result); 410 cntxt.pData += BUFFER_SIZE_IN_BYTES; 411 } 412 fprintf(stdout,"\n"); 413 cntxt.pData = cntxt.pDataBase; 414 415 /* ------------------------------------------------------ */ 416 /* Initialize the callback for prefetch errors, if we can't open the resource to decode */ 417 result = (*prefetchItf)->RegisterCallback(prefetchItf, PrefetchEventCallback, &prefetchItf); 418 ExitOnError(result); 419 result = (*prefetchItf)->SetCallbackEventsMask(prefetchItf, PREFETCHEVENT_ERROR_CANDIDATE); 420 ExitOnError(result); 421 422 /* ------------------------------------------------------ */ 423 /* Prefetch the data so we can get information about the format before starting to decode */ 424 /* 1/ cause the player to prefetch the data */ 425 result = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PAUSED ); 426 ExitOnError(result); 427 /* 2/ block until data has been prefetched */ 428 SLuint32 prefetchStatus = SL_PREFETCHSTATUS_UNDERFLOW; 429 SLuint32 timeOutIndex = 50; // time out prefetching after 5s 430 while ((prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) && (timeOutIndex > 0) && 431 !prefetchError) { 432 usleep(10 * 1000); 433 (*prefetchItf)->GetPrefetchStatus(prefetchItf, &prefetchStatus); 434 timeOutIndex--; 435 } 436 if (timeOutIndex == 0 || prefetchError) { 437 fprintf(stderr, "Failure to prefetch data in time, exiting\n"); 438 ExitOnError(SL_RESULT_CONTENT_NOT_FOUND); 439 } 440 441 /* ------------------------------------------------------ */ 442 /* Display duration */ 443 SLmillisecond durationInMsec = SL_TIME_UNKNOWN; 444 result = (*playItf)->GetDuration(playItf, &durationInMsec); 445 ExitOnError(result); 446 if (durationInMsec == SL_TIME_UNKNOWN) { 447 fprintf(stdout, "Content duration is unknown\n"); 448 } else { 449 fprintf(stdout, "Content duration is %ums\n", durationInMsec); 450 } 451 452 /* ------------------------------------------------------ */ 453 /* Display the metadata obtained from the decoder */ 454 // This is for test / demonstration purposes only where we discover the key and value sizes 455 // of a PCM decoder. An application that would want to directly get access to those values 456 // can make assumptions about the size of the keys and their matching values (all SLuint32) 457 SLuint32 itemCount; 458 result = (*mdExtrItf)->GetItemCount(mdExtrItf, &itemCount); 459 SLuint32 i, keySize, valueSize; 460 SLMetadataInfo *keyInfo, *value; 461 for(i=0 ; i<itemCount ; i++) { 462 keyInfo = NULL; keySize = 0; 463 value = NULL; valueSize = 0; 464 result = (*mdExtrItf)->GetKeySize(mdExtrItf, i, &keySize); 465 ExitOnError(result); 466 result = (*mdExtrItf)->GetValueSize(mdExtrItf, i, &valueSize); 467 ExitOnError(result); 468 keyInfo = (SLMetadataInfo*) malloc(keySize); 469 if (NULL != keyInfo) { 470 result = (*mdExtrItf)->GetKey(mdExtrItf, i, keySize, keyInfo); 471 ExitOnError(result); 472 fprintf(stdout, "key[%d] size=%d, name=%s \tvalue size=%d \n", 473 i, keyInfo->size, keyInfo->data, valueSize); 474 /* find out the key index of the metadata we're interested in */ 475 if (!strcmp((char*)keyInfo->data, ANDROID_KEY_PCMFORMAT_NUMCHANNELS)) { 476 channelCountKeyIndex = i; 477 } else if (!strcmp((char*)keyInfo->data, ANDROID_KEY_PCMFORMAT_SAMPLESPERSEC)) { 478 sampleRateKeyIndex = i; 479 } 480 free(keyInfo); 481 } 482 } 483 if (channelCountKeyIndex != -1) { 484 fprintf(stdout, "Key %s is at index %d\n", 485 ANDROID_KEY_PCMFORMAT_NUMCHANNELS, channelCountKeyIndex); 486 } else { 487 fprintf(stderr, "Unable to find key %s\n", ANDROID_KEY_PCMFORMAT_NUMCHANNELS); 488 } 489 if (sampleRateKeyIndex != -1) { 490 fprintf(stdout, "Key %s is at index %d\n", 491 ANDROID_KEY_PCMFORMAT_SAMPLESPERSEC, sampleRateKeyIndex); 492 } else { 493 fprintf(stderr, "Unable to find key %s\n", ANDROID_KEY_PCMFORMAT_SAMPLESPERSEC); 494 } 495 496 /* ------------------------------------------------------ */ 497 /* Start decoding */ 498 result = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING); 499 ExitOnError(result); 500 fprintf(stdout, "Starting to decode\n"); 501 502 /* Decode until the end of the stream is reached */ 503 { 504 android::Mutex::Autolock autoLock(eosLock); 505 while (!eos) { 506 eosCondition.wait(eosLock); 507 } 508 } 509 fprintf(stdout, "EOS signaled\n"); 510 511 /* ------------------------------------------------------ */ 512 /* End of decoding */ 513 514 /* Stop decoding */ 515 result = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED); 516 ExitOnError(result); 517 fprintf(stdout, "Stopped decoding\n"); 518 519 /* Destroy the AudioPlayer object */ 520 (*player)->Destroy(player); 521 522 fclose(gFp); 523 524 free(pcmMetaData); 525 pcmMetaData = NULL; 526} 527 528//----------------------------------------------------------------- 529int main(int argc, char* const argv[]) 530{ 531 SLresult result; 532 SLObjectItf sl; 533 534 fprintf(stdout, "OpenSL ES test %s: exercises SLPlayItf and SLAndroidSimpleBufferQueueItf ", 535 argv[0]); 536 fprintf(stdout, "on an AudioPlayer object to decode a URI to PCM\n"); 537 538 if (argc != 2) { 539 fprintf(stdout, "Usage: \t%s source_file\n", argv[0]); 540 fprintf(stdout, "Example: \"%s /sdcard/myFile.mp3\n", argv[0]); 541 exit(EXIT_FAILURE); 542 } 543 544 SLEngineOption EngineOption[] = { 545 {(SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE} 546 }; 547 548 result = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL); 549 ExitOnError(result); 550 551 /* Realizing the SL Engine in synchronous mode. */ 552 result = (*sl)->Realize(sl, SL_BOOLEAN_FALSE); 553 ExitOnError(result); 554 555 TestDecToBuffQueue(sl, argv[1]); 556 557 /* Shutdown OpenSL ES */ 558 (*sl)->Destroy(sl); 559 560 return EXIT_SUCCESS; 561} 562