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