Home | History | Annotate | Download | only in examples
      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 
     19 First run the program from shell:
     20   # slesTest_decodeToBuffQueue /sdcard/myFile.mp3 4
     21 
     22 These use adb on host to retrieve the decoded file:
     23   % adb pull /sdcard/myFile.mp3.raw myFile.raw
     24 
     25 How 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 */
     61 int8_t pcmData[NB_BUFFERS_IN_QUEUE * BUFFER_SIZE_IN_BYTES];
     62 
     63 /* destination for decoded data */
     64 static FILE* gFp;
     65 
     66 /* to display the number of decode iterations */
     67 static int counter=0;
     68 
     69 /* metadata key index for the PCM format information we want to retrieve */
     70 static int channelCountKeyIndex = -1;
     71 static 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 */
     78 static SLMetadataInfo *pcmMetaData = NULL;
     79 /* we only want to query / display the PCM format once */
     80 static bool formatQueried = false;
     81 
     82 /* to signal to the test app the end of the stream to decode has been reached */
     83 bool eos = false;
     84 android::Mutex eosLock;
     85 android::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 
     97 void 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 */
    106 bool prefetchError = false;
    107 
    108 //-----------------------------------------------------------------
    109 /* Structure for passing information to callback function */
    110 typedef 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 //-----------------------------------------------------------------
    119 void 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 */
    127 void 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 */
    146 void 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 */
    172 void 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  */
    262 void 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 //-----------------------------------------------------------------
    535 int 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