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(stderr, "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 __unused, SLuint32 event) 128{ 129 SLpermille level = 0; 130 SLresult result; 131 result = (*caller)->GetFillLevel(caller, &level); 132 ExitOnError(result); 133 SLuint32 status; 134 //fprintf(stdout, "PrefetchEventCallback: received event %u\n", event); 135 result = (*caller)->GetPrefetchStatus(caller, &status); 136 ExitOnError(result); 137 if ((PREFETCHEVENT_ERROR_CANDIDATE == (event & PREFETCHEVENT_ERROR_CANDIDATE)) 138 && (level == 0) && (status == SL_PREFETCHSTATUS_UNDERFLOW)) { 139 fprintf(stdout, "PrefetchEventCallback: Error while prefetching data, exiting\n"); 140 prefetchError = true; 141 SignalEos(); 142 } 143} 144 145/* Callback for "playback" events, i.e. event happening during decoding */ 146void DecProgressCallback( 147 SLPlayItf caller, 148 void *pContext __unused, 149 SLuint32 event) 150{ 151 SLresult result; 152 SLmillisecond msec; 153 result = (*caller)->GetPosition(caller, &msec); 154 ExitOnError(result); 155 156 if (SL_PLAYEVENT_HEADATEND & event) { 157 fprintf(stdout, "SL_PLAYEVENT_HEADATEND current position=%u ms\n", msec); 158 SignalEos(); 159 } 160 161 if (SL_PLAYEVENT_HEADATNEWPOS & event) { 162 fprintf(stdout, "SL_PLAYEVENT_HEADATNEWPOS current position=%u ms\n", msec); 163 } 164 165 if (SL_PLAYEVENT_HEADATMARKER & event) { 166 fprintf(stdout, "SL_PLAYEVENT_HEADATMARKER current position=%u ms\n", msec); 167 } 168} 169 170//----------------------------------------------------------------- 171/* Callback for decoding buffer queue events */ 172void DecPlayCallback( 173 SLAndroidSimpleBufferQueueItf queueItf, 174 void *pContext) 175{ 176 counter++; 177 178 CallbackCntxt *pCntxt = (CallbackCntxt*)pContext; 179 180 if (counter % 1000 == 0) { 181 SLmillisecond msec; 182 SLresult result = (*pCntxt->playItf)->GetPosition(pCntxt->playItf, &msec); 183 ExitOnError(result); 184 printf("DecPlayCallback called (iteration %d): current position=%u ms\n", counter, msec); 185 } 186 187 /* Save the decoded data */ 188 if (fwrite(pCntxt->pDataBase, 1, BUFFER_SIZE_IN_BYTES, gFp) < BUFFER_SIZE_IN_BYTES) { 189 fprintf(stdout, "Error writing to output file, signaling EOS\n"); 190 SignalEos(); 191 return; 192 } 193 194 /* Increase data pointer by buffer size */ 195 pCntxt->pData += BUFFER_SIZE_IN_BYTES; 196 197 if (pCntxt->pData >= pCntxt->pDataBase + (NB_BUFFERS_IN_QUEUE * BUFFER_SIZE_IN_BYTES)) { 198 pCntxt->pData = pCntxt->pDataBase; 199 } 200 201 ExitOnError( (*queueItf)->Enqueue(queueItf, pCntxt->pDataBase, BUFFER_SIZE_IN_BYTES) ); 202 // Note: adding a sleep here or any sync point is a way to slow down the decoding, or 203 // synchronize it with some other event, as the OpenSL ES framework will block until the 204 // buffer queue callback return to proceed with the decoding. 205 206#if 0 207 /* Example: buffer queue state display */ 208 SLAndroidSimpleBufferQueueState decQueueState; 209 ExitOnError( (*queueItf)->GetState(queueItf, &decQueueState) ); 210 211 fprintf(stderr, "\DecBufferQueueCallback now has pCntxt->pData=%p queue: " 212 "count=%u playIndex=%u\n", 213 pCntxt->pData, decQueueState.count, decQueueState.index); 214#endif 215 216#if 0 217 /* Example: display duration in callback where we use the callback context for the SLPlayItf*/ 218 SLmillisecond durationInMsec = SL_TIME_UNKNOWN; 219 SLresult result = (*pCntxt->playItf)->GetDuration(pCntxt->playItf, &durationInMsec); 220 ExitOnError(result); 221 if (durationInMsec == SL_TIME_UNKNOWN) { 222 fprintf(stdout, "Content duration is unknown (in dec callback)\n"); 223 } else { 224 fprintf(stdout, "Content duration is %ums (in dec callback)\n", 225 durationInMsec); 226 } 227#endif 228 229#if 0 230 /* Example: display position in callback where we use the callback context for the SLPlayItf*/ 231 SLmillisecond posMsec = SL_TIME_UNKNOWN; 232 SLresult result = (*pCntxt->playItf)->GetPosition(pCntxt->playItf, &posMsec); 233 ExitOnError(result); 234 if (posMsec == SL_TIME_UNKNOWN) { 235 fprintf(stdout, "Content position is unknown (in dec callback)\n"); 236 } else { 237 fprintf(stdout, "Content position is %ums (in dec callback)\n", 238 posMsec); 239 } 240#endif 241 242 /* Example: query of the decoded PCM format */ 243 if (formatQueried) { 244 return; 245 } 246 SLresult res = (*pCntxt->metaItf)->GetValue(pCntxt->metaItf, sampleRateKeyIndex, 247 PCM_METADATA_VALUE_SIZE, pcmMetaData); ExitOnError(res); 248 // Note: here we could verify the following: 249 // pcmMetaData->encoding == SL_CHARACTERENCODING_BINARY 250 // pcmMetaData->size == sizeof(SLuint32) 251 // but the call was successful for the PCM format keys, so those conditions are implied 252 fprintf(stdout, "sample rate = %dHz, ", *((SLuint32*)pcmMetaData->data)); 253 res = (*pCntxt->metaItf)->GetValue(pCntxt->metaItf, channelCountKeyIndex, 254 PCM_METADATA_VALUE_SIZE, pcmMetaData); ExitOnError(res); 255 fprintf(stdout, " channel count = %d\n", *((SLuint32*)pcmMetaData->data)); 256 formatQueried = true; 257} 258 259//----------------------------------------------------------------- 260 261/* Decode an audio path by opening a file descriptor on that path */ 262void TestDecToBuffQueue( SLObjectItf sl, const char* path) 263{ 264 size_t len = strlen((const char *) path); 265 char* outputPath = (char*) malloc(len + 4 + 1); // save room to concatenate ".raw" 266 if (NULL == outputPath) { 267 ExitOnError(SL_RESULT_RESOURCE_ERROR); 268 } 269 memcpy(outputPath, path, len + 1); 270 strcat(outputPath, ".raw"); 271 gFp = fopen(outputPath, "w"); 272 if (NULL == gFp) { 273 ExitOnError(SL_RESULT_RESOURCE_ERROR); 274 } 275 276 SLresult result; 277 SLEngineItf EngineItf; 278 279 /* Objects this application uses: one audio player */ 280 SLObjectItf player; 281 282 /* Interfaces for the audio player */ 283 SLAndroidSimpleBufferQueueItf decBuffQueueItf; 284 SLPrefetchStatusItf prefetchItf; 285 SLPlayItf playItf; 286 SLMetadataExtractionItf mdExtrItf; 287 288 /* Source of audio data for the decoding */ 289 SLDataSource decSource; 290 SLDataLocator_URI decUri; 291 SLDataFormat_MIME decMime; 292 293 /* Data sink for decoded audio */ 294 SLDataSink decDest; 295 SLDataLocator_AndroidSimpleBufferQueue decBuffQueue; 296 SLDataFormat_PCM pcm; 297 298 SLboolean required[NUM_EXPLICIT_INTERFACES_FOR_PLAYER]; 299 SLInterfaceID iidArray[NUM_EXPLICIT_INTERFACES_FOR_PLAYER]; 300 301 /* Get the SL Engine Interface which is implicit */ 302 result = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf); 303 ExitOnError(result); 304 305 /* Initialize arrays required[] and iidArray[] */ 306 for (int i=0 ; i < NUM_EXPLICIT_INTERFACES_FOR_PLAYER ; i++) { 307 required[i] = SL_BOOLEAN_FALSE; 308 iidArray[i] = SL_IID_NULL; 309 } 310 311 /* allocate memory to receive the PCM format metadata */ 312 if (!pcmMetaData) { 313 pcmMetaData = (SLMetadataInfo*) malloc(PCM_METADATA_VALUE_SIZE); 314 } 315 316 formatQueried = false; 317 318 /* ------------------------------------------------------ */ 319 /* Configuration of the player */ 320 321 /* Request the AndroidSimpleBufferQueue interface */ 322 required[0] = SL_BOOLEAN_TRUE; 323 iidArray[0] = SL_IID_ANDROIDSIMPLEBUFFERQUEUE; 324 /* Request the PrefetchStatus interface */ 325 required[1] = SL_BOOLEAN_TRUE; 326 iidArray[1] = SL_IID_PREFETCHSTATUS; 327 /* Request the PrefetchStatus interface */ 328 required[2] = SL_BOOLEAN_TRUE; 329 iidArray[2] = SL_IID_METADATAEXTRACTION; 330 331 /* Setup the data source */ 332 decUri.locatorType = SL_DATALOCATOR_URI; 333 decUri.URI = (SLchar*)path; 334 decMime.formatType = SL_DATAFORMAT_MIME; 335 /* this is how ignored mime information is specified, according to OpenSL ES spec 336 * in 9.1.6 SLDataFormat_MIME and 8.23 SLMetadataTraversalItf GetChildInfo */ 337 decMime.mimeType = (SLchar*)NULL; 338 decMime.containerType = SL_CONTAINERTYPE_UNSPECIFIED; 339 decSource.pLocator = (void *) &decUri; 340 decSource.pFormat = (void *) &decMime; 341 342 /* Setup the data sink */ 343 decBuffQueue.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; 344 decBuffQueue.numBuffers = NB_BUFFERS_IN_QUEUE; 345 /* set up the format of the data in the buffer queue */ 346 pcm.formatType = SL_DATAFORMAT_PCM; 347 // FIXME valid value required but currently ignored 348 pcm.numChannels = 1; 349 pcm.samplesPerSec = SL_SAMPLINGRATE_8; 350 pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16; 351 pcm.containerSize = 16; 352 pcm.channelMask = SL_SPEAKER_FRONT_LEFT; 353 pcm.endianness = SL_BYTEORDER_LITTLEENDIAN; 354 355 decDest.pLocator = (void *) &decBuffQueue; 356 decDest.pFormat = (void * ) &pcm; 357 358 /* Create the audio player */ 359 result = (*EngineItf)->CreateAudioPlayer(EngineItf, &player, &decSource, &decDest, 360 NUM_EXPLICIT_INTERFACES_FOR_PLAYER, iidArray, required); 361 ExitOnError(result); 362 fprintf(stdout, "Player created\n"); 363 364 /* Realize the player in synchronous mode. */ 365 result = (*player)->Realize(player, SL_BOOLEAN_FALSE); 366 ExitOnError(result); 367 fprintf(stdout, "Player realized\n"); 368 369 /* Get the play interface which is implicit */ 370 result = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf); 371 ExitOnError(result); 372 373 /* Set up the player callback to get events during the decoding */ 374 // FIXME currently ignored 375 result = (*playItf)->SetMarkerPosition(playItf, 2000); 376 ExitOnError(result); 377 result = (*playItf)->SetPositionUpdatePeriod(playItf, 500); 378 ExitOnError(result); 379 result = (*playItf)->SetCallbackEventsMask(playItf, 380 SL_PLAYEVENT_HEADATMARKER | SL_PLAYEVENT_HEADATNEWPOS | SL_PLAYEVENT_HEADATEND); 381 ExitOnError(result); 382 result = (*playItf)->RegisterCallback(playItf, DecProgressCallback, NULL); 383 ExitOnError(result); 384 fprintf(stdout, "Play callback registered\n"); 385 386 /* Get the buffer queue interface which was explicitly requested */ 387 result = (*player)->GetInterface(player, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, 388 (void*)&decBuffQueueItf); 389 ExitOnError(result); 390 391 /* Get the prefetch status interface which was explicitly requested */ 392 result = (*player)->GetInterface(player, SL_IID_PREFETCHSTATUS, (void*)&prefetchItf); 393 ExitOnError(result); 394 395 /* Get the metadata extraction interface which was explicitly requested */ 396 result = (*player)->GetInterface(player, SL_IID_METADATAEXTRACTION, (void*)&mdExtrItf); 397 ExitOnError(result); 398 399 /* ------------------------------------------------------ */ 400 /* Initialize the callback and its context for the decoding buffer queue */ 401 CallbackCntxt cntxt; 402 cntxt.playItf = playItf; 403 cntxt.metaItf = mdExtrItf; 404 cntxt.pDataBase = (int8_t*)&pcmData; 405 cntxt.pData = cntxt.pDataBase; 406 cntxt.size = sizeof(pcmData); 407 result = (*decBuffQueueItf)->RegisterCallback(decBuffQueueItf, DecPlayCallback, &cntxt); 408 ExitOnError(result); 409 410 /* Enqueue buffers to map the region of memory allocated to store the decoded data */ 411 fprintf(stdout,"Enqueueing buffer "); 412 for(int i = 0 ; i < NB_BUFFERS_IN_QUEUE ; i++) { 413 fprintf(stdout,"%d ", i); 414 result = (*decBuffQueueItf)->Enqueue(decBuffQueueItf, cntxt.pData, BUFFER_SIZE_IN_BYTES); 415 ExitOnError(result); 416 cntxt.pData += BUFFER_SIZE_IN_BYTES; 417 } 418 fprintf(stdout,"\n"); 419 cntxt.pData = cntxt.pDataBase; 420 421 /* ------------------------------------------------------ */ 422 /* Initialize the callback for prefetch errors, if we can't open the resource to decode */ 423 result = (*prefetchItf)->RegisterCallback(prefetchItf, PrefetchEventCallback, &prefetchItf); 424 ExitOnError(result); 425 result = (*prefetchItf)->SetCallbackEventsMask(prefetchItf, PREFETCHEVENT_ERROR_CANDIDATE); 426 ExitOnError(result); 427 428 /* ------------------------------------------------------ */ 429 /* Prefetch the data so we can get information about the format before starting to decode */ 430 /* 1/ cause the player to prefetch the data */ 431 result = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PAUSED ); 432 ExitOnError(result); 433 /* 2/ block until data has been prefetched */ 434 SLuint32 prefetchStatus = SL_PREFETCHSTATUS_UNDERFLOW; 435 SLuint32 timeOutIndex = 50; // time out prefetching after 5s 436 while ((prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) && (timeOutIndex > 0) && 437 !prefetchError) { 438 usleep(10 * 1000); 439 (*prefetchItf)->GetPrefetchStatus(prefetchItf, &prefetchStatus); 440 timeOutIndex--; 441 } 442 if (timeOutIndex == 0 || prefetchError) { 443 fprintf(stderr, "Failure to prefetch data in time, exiting\n"); 444 ExitOnError(SL_RESULT_CONTENT_NOT_FOUND); 445 } 446 447 /* ------------------------------------------------------ */ 448 /* Display duration */ 449 SLmillisecond durationInMsec = SL_TIME_UNKNOWN; 450 result = (*playItf)->GetDuration(playItf, &durationInMsec); 451 ExitOnError(result); 452 if (durationInMsec == SL_TIME_UNKNOWN) { 453 fprintf(stdout, "Content duration is unknown\n"); 454 } else { 455 fprintf(stdout, "Content duration is %ums\n", durationInMsec); 456 } 457 458 /* ------------------------------------------------------ */ 459 /* Display the metadata obtained from the decoder */ 460 // This is for test / demonstration purposes only where we discover the key and value sizes 461 // of a PCM decoder. An application that would want to directly get access to those values 462 // can make assumptions about the size of the keys and their matching values (all SLuint32) 463 SLuint32 itemCount; 464 result = (*mdExtrItf)->GetItemCount(mdExtrItf, &itemCount); 465 SLuint32 i, keySize, valueSize; 466 SLMetadataInfo *keyInfo, *value; 467 for(i=0 ; i<itemCount ; i++) { 468 keyInfo = NULL; keySize = 0; 469 value = NULL; valueSize = 0; 470 result = (*mdExtrItf)->GetKeySize(mdExtrItf, i, &keySize); 471 ExitOnError(result); 472 result = (*mdExtrItf)->GetValueSize(mdExtrItf, i, &valueSize); 473 ExitOnError(result); 474 keyInfo = (SLMetadataInfo*) malloc(keySize); 475 if (NULL != keyInfo) { 476 result = (*mdExtrItf)->GetKey(mdExtrItf, i, keySize, keyInfo); 477 ExitOnError(result); 478 fprintf(stdout, "key[%d] size=%d, name=%s \tvalue size=%d \n", 479 i, keyInfo->size, keyInfo->data, valueSize); 480 /* find out the key index of the metadata we're interested in */ 481 if (!strcmp((char*)keyInfo->data, ANDROID_KEY_PCMFORMAT_NUMCHANNELS)) { 482 channelCountKeyIndex = i; 483 } else if (!strcmp((char*)keyInfo->data, ANDROID_KEY_PCMFORMAT_SAMPLERATE)) { 484 sampleRateKeyIndex = i; 485 } 486 free(keyInfo); 487 } 488 } 489 if (channelCountKeyIndex != -1) { 490 fprintf(stdout, "Key %s is at index %d\n", 491 ANDROID_KEY_PCMFORMAT_NUMCHANNELS, channelCountKeyIndex); 492 } else { 493 fprintf(stderr, "Unable to find key %s\n", ANDROID_KEY_PCMFORMAT_NUMCHANNELS); 494 } 495 if (sampleRateKeyIndex != -1) { 496 fprintf(stdout, "Key %s is at index %d\n", 497 ANDROID_KEY_PCMFORMAT_SAMPLERATE, sampleRateKeyIndex); 498 } else { 499 fprintf(stderr, "Unable to find key %s\n", ANDROID_KEY_PCMFORMAT_SAMPLERATE); 500 } 501 502 /* ------------------------------------------------------ */ 503 /* Start decoding */ 504 result = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING); 505 ExitOnError(result); 506 fprintf(stdout, "Starting to decode\n"); 507 508 /* Decode until the end of the stream is reached */ 509 { 510 android::Mutex::Autolock autoLock(eosLock); 511 while (!eos) { 512 eosCondition.wait(eosLock); 513 } 514 } 515 fprintf(stdout, "EOS signaled\n"); 516 517 /* ------------------------------------------------------ */ 518 /* End of decoding */ 519 520 /* Stop decoding */ 521 result = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED); 522 ExitOnError(result); 523 fprintf(stdout, "Stopped decoding\n"); 524 525 /* Destroy the AudioPlayer object */ 526 (*player)->Destroy(player); 527 528 fclose(gFp); 529 530 free(pcmMetaData); 531 pcmMetaData = NULL; 532} 533 534//----------------------------------------------------------------- 535int main(int argc, char* const argv[]) 536{ 537 SLresult result; 538 SLObjectItf sl; 539 540 fprintf(stdout, "OpenSL ES test %s: exercises SLPlayItf and SLAndroidSimpleBufferQueueItf ", 541 argv[0]); 542 fprintf(stdout, "on an AudioPlayer object to decode a URI to PCM\n"); 543 544 if (argc != 2) { 545 fprintf(stdout, "Usage: \t%s source_file\n", argv[0]); 546 fprintf(stdout, "Example: \"%s /sdcard/myFile.mp3\n", argv[0]); 547 exit(EXIT_FAILURE); 548 } 549 550 SLEngineOption EngineOption[] = { 551 {(SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE} 552 }; 553 554 result = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL); 555 ExitOnError(result); 556 557 /* Realizing the SL Engine in synchronous mode. */ 558 result = (*sl)->Realize(sl, SL_BOOLEAN_FALSE); 559 ExitOnError(result); 560 561 TestDecToBuffQueue(sl, argv[1]); 562 563 /* Shutdown OpenSL ES */ 564 (*sl)->Destroy(sl); 565 566 return EXIT_SUCCESS; 567} 568