slesTestDecodeAac.cpp revision 0f92f48017588949daf7d24a339423e149bb2555
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/* AAC ADTS Decode Test
18
19First run the program from shell:
20  # slesTestDecodeAac /sdcard/myFile.adts
21
22Expected output:
23  OpenSL ES test slesTestDecodeAac: decodes a file containing AAC ADTS data
24  Player created
25  Player realized
26  Enqueueing initial empty buffers to receive decoded PCM data 0 1
27  Enqueueing initial full buffers of encoded ADTS data 0 1
28  Starting to decode
29  Frame counters: encoded=4579 decoded=4579
30
31These use adb on host to retrieve the decoded file:
32  % adb pull /sdcard/myFile.adts.raw myFile.raw
33
34How to examine the output with Audacity:
35 Project / Import raw data
36 Select myFile.raw file, then click Open button
37 Choose these options:
38  Signed 16-bit PCM
39  Little-endian
40  1 Channel (Mono) / 2 Channels (Stereo) based on the PCM information obtained when decoding
41  Sample rate based on the PCM information obtained when decoding
42 Click Import button
43
44*/
45
46#define QUERY_METADATA
47
48#include <stdlib.h>
49#include <stdio.h>
50#include <string.h>
51#include <unistd.h>
52#include <sys/time.h>
53#include <fcntl.h>
54#include <pthread.h>
55#include <sys/mman.h>
56#include <sys/stat.h>
57#include <unistd.h>
58
59#include <SLES/OpenSLES.h>
60#include <SLES/OpenSLES_Android.h>
61
62/* Explicitly requesting SL_IID_ANDROIDBUFFERQUEUE and SL_IID_ANDROIDSIMPLEBUFFERQUEUE
63 * on the AudioPlayer object for decoding, and
64 * SL_IID_METADATAEXTRACTION for retrieving the format of the decoded audio.
65 */
66#define NUM_EXPLICIT_INTERFACES_FOR_PLAYER 3
67
68/* Number of decoded samples produced by one AAC frame; defined by the standard */
69#define SAMPLES_PER_AAC_FRAME 1024
70/* Size of the encoded AAC ADTS buffer queue */
71#define NB_BUFFERS_IN_ADTS_QUEUE 2 // 2 to 4 is typical
72
73/* Size of the decoded PCM buffer queue */
74#define NB_BUFFERS_IN_PCM_QUEUE 2  // 2 to 4 is typical
75/* Size of each PCM buffer in the queue */
76#define BUFFER_SIZE_IN_BYTES   (2*sizeof(short)*SAMPLES_PER_AAC_FRAME)
77
78/* Local storage for decoded PCM audio data */
79int8_t pcmData[NB_BUFFERS_IN_PCM_QUEUE * BUFFER_SIZE_IN_BYTES];
80
81/* destination for decoded data */
82static FILE* outputFp;
83
84#ifdef QUERY_METADATA
85/* metadata key index for the PCM format information we want to retrieve */
86static int channelCountKeyIndex = -1;
87static int sampleRateKeyIndex = -1;
88static int bitsPerSampleKeyIndex = -1;
89static int containerSizeKeyIndex = -1;
90static int channelMaskKeyIndex = -1;
91static int endiannessKeyIndex = -1;
92/* size of the struct to retrieve the PCM format metadata values: the values we're interested in
93 * are SLuint32, but it is saved in the data field of a SLMetadataInfo, hence the larger size.
94 * Note that this size is queried and displayed at l.XXX for demonstration/test purposes.
95 *  */
96#define PCM_METADATA_VALUE_SIZE 32
97/* used to query metadata values */
98static SLMetadataInfo *pcmMetaData = NULL;
99/* we only want to query / display the PCM format once */
100static bool formatQueried = false;
101#endif
102
103/* to signal to the test app that the end of the encoded ADTS stream has been reached */
104bool eos = false;
105bool endOfEncodedStream = false;
106
107void *ptr;
108unsigned char *frame;
109size_t filelen;
110size_t encodedFrames = 0;
111size_t encodedSamples = 0;
112size_t decodedFrames = 0;
113size_t decodedSamples = 0;
114
115/* protects shared variables */
116pthread_mutex_t eosLock = PTHREAD_MUTEX_INITIALIZER;
117pthread_cond_t eosCondition = PTHREAD_COND_INITIALIZER;
118
119//-----------------------------------------------------------------
120/* Exits the application if an error is encountered */
121#define ExitOnError(x) ExitOnErrorFunc(x,__LINE__)
122
123void ExitOnErrorFunc( SLresult result , int line)
124{
125    if (SL_RESULT_SUCCESS != result) {
126        fprintf(stderr, "Error code %u encountered at line %d, exiting\n", result, line);
127        exit(EXIT_FAILURE);
128    }
129}
130
131//-----------------------------------------------------------------
132/* Structure for passing information to callback function */
133typedef struct CallbackCntxt_ {
134#ifdef QUERY_METADATA
135    SLMetadataExtractionItf metaItf;
136#endif
137    SLPlayItf playItf;
138    SLint8*   pDataBase;    // Base address of local audio data storage
139    SLint8*   pData;        // Current address of local audio data storage
140} CallbackCntxt;
141
142//-----------------------------------------------------------------
143/* Callback for AndroidBufferQueueItf through which we supply ADTS buffers */
144SLresult AndroidBufferQueueCallback(
145        SLAndroidBufferQueueItf caller,
146        void *pCallbackContext,        /* input */
147        void *pBufferContext,          /* input */
148        void *pBufferData,             /* input */
149        SLuint32 dataSize,             /* input */
150        SLuint32 dataUsed,             /* input */
151        const SLAndroidBufferItem *pItems,/* input */
152        SLuint32 itemsLength           /* input */)
153{
154    // mutex on all global variables
155    pthread_mutex_lock(&eosLock);
156    SLresult res;
157
158    if (endOfEncodedStream) {
159        // we continue to receive acknowledgement after each buffer was processed
160    } else if (filelen == 0) {
161        // signal EOS to the decoder rather than just starving it
162        SLAndroidBufferItem msgEos;
163        msgEos.itemKey = SL_ANDROID_ITEMKEY_EOS;
164        msgEos.itemSize = 0;
165        // EOS message has no parameters, so the total size of the message is the size of the key
166        //   plus the size of itemSize, both SLuint32
167        res = (*caller)->Enqueue(caller, NULL /*pBufferContext*/,
168                NULL /*pData*/, 0 /*dataLength*/,
169                &msgEos /*pMsg*/,
170                sizeof(SLuint32)*2 /*msgLength*/);
171        ExitOnError(res);
172        endOfEncodedStream = true;
173    // verify that we are at start of an ADTS frame
174    } else if (!(filelen < 7 || frame[0] != 0xFF || (frame[1] & 0xF0) != 0xF0)) {
175        unsigned framelen = ((frame[3] & 3) << 11) | (frame[4] << 3) | (frame[5] >> 5);
176        if (framelen <= filelen) {
177            // push more data to the queue
178            res = (*caller)->Enqueue(caller, NULL /*pBufferContext*/,
179                    frame, framelen, NULL, 0);
180            ExitOnError(res);
181            frame += framelen;
182            filelen -= framelen;
183            ++encodedFrames;
184            encodedSamples += SAMPLES_PER_AAC_FRAME;
185        } else {
186            fprintf(stderr,
187                    "partial ADTS frame at EOF discarded; offset=%u, framelen=%u, filelen=%u\n",
188                    frame - (unsigned char *) ptr, framelen, filelen);
189            frame += filelen;
190            filelen = 0;
191        }
192    } else {
193        fprintf(stderr, "corrupt ADTS frame encountered; offset=%u, filelen=%u\n",
194                frame - (unsigned char *) ptr, filelen);
195        frame += filelen;
196        filelen = 0;
197    }
198    pthread_mutex_unlock(&eosLock);
199
200    return SL_RESULT_SUCCESS;
201}
202
203//-----------------------------------------------------------------
204/* Callback for decoding buffer queue events */
205void DecPlayCallback(
206        SLAndroidSimpleBufferQueueItf queueItf,
207        void *pContext)
208{
209    // mutex on all global variables
210    pthread_mutex_lock(&eosLock);
211
212    CallbackCntxt *pCntxt = (CallbackCntxt*)pContext;
213
214    /* Save the decoded data to output file */
215    if (fwrite(pCntxt->pData, 1, BUFFER_SIZE_IN_BYTES, outputFp) < BUFFER_SIZE_IN_BYTES) {
216        fprintf(stderr, "Error writing to output file");
217    }
218
219    /* Re-enqueue the now empty buffer */
220    SLresult res;
221    res = (*queueItf)->Enqueue(queueItf, pCntxt->pData, BUFFER_SIZE_IN_BYTES);
222    ExitOnError(res);
223
224    /* Increase data pointer by buffer size, with circular wraparound */
225    pCntxt->pData += BUFFER_SIZE_IN_BYTES;
226    if (pCntxt->pData >= pCntxt->pDataBase + (NB_BUFFERS_IN_PCM_QUEUE * BUFFER_SIZE_IN_BYTES)) {
227        pCntxt->pData = pCntxt->pDataBase;
228    }
229
230    // Note: adding a sleep here or any sync point is a way to slow down the decoding, or
231    //  synchronize it with some other event, as the OpenSL ES framework will block until the
232    //  buffer queue callback return to proceed with the decoding.
233
234#ifdef QUERY_METADATA
235    /* Example: query of the decoded PCM format */
236    if (!formatQueried) {
237        /* memory to receive the PCM format metadata */
238        union {
239            SLMetadataInfo pcmMetaData;
240            char withData[PCM_METADATA_VALUE_SIZE];
241        } u;
242        res = (*pCntxt->metaItf)->GetValue(pCntxt->metaItf, sampleRateKeyIndex,
243                PCM_METADATA_VALUE_SIZE, &u.pcmMetaData);  ExitOnError(res);
244        // Note: here we could verify the following:
245        //         u.pcmMetaData->encoding == SL_CHARACTERENCODING_BINARY
246        //         u.pcmMetaData->size == sizeof(SLuint32)
247        //      but the call was successful for the PCM format keys, so those conditions are implied
248        printf("sample rate = %d\n", *((SLuint32*)u.pcmMetaData.data));
249        res = (*pCntxt->metaItf)->GetValue(pCntxt->metaItf, channelCountKeyIndex,
250                PCM_METADATA_VALUE_SIZE, &u.pcmMetaData);  ExitOnError(res);
251        printf("channel count = %d\n", *((SLuint32*)u.pcmMetaData.data));
252        res = (*pCntxt->metaItf)->GetValue(pCntxt->metaItf, bitsPerSampleKeyIndex,
253                PCM_METADATA_VALUE_SIZE, &u.pcmMetaData);  ExitOnError(res);
254        printf("bits per sample = %d bits\n", *((SLuint32*)u.pcmMetaData.data));
255        res = (*pCntxt->metaItf)->GetValue(pCntxt->metaItf, containerSizeKeyIndex,
256                PCM_METADATA_VALUE_SIZE, &u.pcmMetaData);  ExitOnError(res);
257        printf("container size = %d bits\n", *((SLuint32*)u.pcmMetaData.data));
258        res = (*pCntxt->metaItf)->GetValue(pCntxt->metaItf, channelMaskKeyIndex,
259                PCM_METADATA_VALUE_SIZE, &u.pcmMetaData);  ExitOnError(res);
260        printf("channel mask = 0x%X (0x3=front left | front right, 0x4=front center)\n",
261                *((SLuint32*)u.pcmMetaData.data));
262        res = (*pCntxt->metaItf)->GetValue(pCntxt->metaItf, endiannessKeyIndex,
263                PCM_METADATA_VALUE_SIZE, &u.pcmMetaData);  ExitOnError(res);
264        printf("endianness = %d (1=big, 2=little)\n", *((SLuint32*)u.pcmMetaData.data));
265        formatQueried = true;
266    }
267#endif
268
269    ++decodedFrames;
270    decodedSamples += SAMPLES_PER_AAC_FRAME;
271
272    /* Periodically ask for position and duration */
273    if ((decodedFrames % 1000 == 0) || endOfEncodedStream) {
274        SLmillisecond position;
275        res = (*pCntxt->playItf)->GetPosition(pCntxt->playItf, &position);
276        ExitOnError(res);
277        SLmillisecond duration;
278        res = (*pCntxt->playItf)->GetDuration(pCntxt->playItf, &duration);
279        ExitOnError(res);
280        if (duration == SL_TIME_UNKNOWN) {
281            printf("After %u decoded frames: position is %u ms, duration is unknown as expected\n",
282                    decodedFrames, position);
283        } else {
284            printf("After %u decoded frames: position is %u ms, duration is surprisingly %u ms\n",
285                    decodedFrames, position, duration);
286        }
287    }
288
289    if (endOfEncodedStream && decodedSamples >= encodedSamples) {
290        eos = true;
291        pthread_cond_signal(&eosCondition);
292    }
293    pthread_mutex_unlock(&eosLock);
294}
295
296//-----------------------------------------------------------------
297
298/* Decode an audio path by opening a file descriptor on that path  */
299void TestDecToBuffQueue( SLObjectItf sl, const char *path, int fd)
300{
301    // check what kind of object it is
302    int ok;
303    struct stat statbuf;
304    ok = fstat(fd, &statbuf);
305    if (ok < 0) {
306        perror(path);
307        return;
308    }
309
310    // verify that's it is a file
311    if (!S_ISREG(statbuf.st_mode)) {
312        fprintf(stderr, "%s: not an ordinary file\n", path);
313        return;
314    }
315
316    // map file contents into memory to make it easier to access the ADTS frames directly
317    ptr = mmap(NULL, statbuf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, (off_t) 0);
318    if (ptr == MAP_FAILED) {
319        perror(path);
320        return;
321    }
322    frame = (unsigned char *) ptr;
323    filelen = statbuf.st_size;
324
325    // create PCM .raw file
326    size_t len = strlen((const char *) path);
327    char* outputPath = (char*) malloc(len + 4 + 1); // save room to concatenate ".raw"
328    if (NULL == outputPath) {
329        ExitOnError(SL_RESULT_RESOURCE_ERROR);
330    }
331    memcpy(outputPath, path, len + 1);
332    strcat(outputPath, ".raw");
333    outputFp = fopen(outputPath, "w");
334    if (NULL == outputFp) {
335        ExitOnError(SL_RESULT_RESOURCE_ERROR);
336    }
337
338    SLresult res;
339    SLEngineItf EngineItf;
340
341    /* Objects this application uses: one audio player */
342    SLObjectItf  player;
343
344    /* Interfaces for the audio player */
345    SLPlayItf                     playItf;
346#ifdef QUERY_METADATA
347    /*   to retrieve the decoded PCM format */
348    SLMetadataExtractionItf       mdExtrItf;
349#endif
350    /*   to retrieve the PCM samples */
351    SLAndroidSimpleBufferQueueItf decBuffQueueItf;
352    /*   to queue the AAC data to decode */
353    SLAndroidBufferQueueItf       aacBuffQueueItf;
354
355    SLboolean required[NUM_EXPLICIT_INTERFACES_FOR_PLAYER];
356    SLInterfaceID iidArray[NUM_EXPLICIT_INTERFACES_FOR_PLAYER];
357
358    /* Get the SL Engine Interface which is implicit */
359    res = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf);
360    ExitOnError(res);
361
362    /* Initialize arrays required[] and iidArray[] */
363    unsigned int i;
364    for (i=0 ; i < NUM_EXPLICIT_INTERFACES_FOR_PLAYER ; i++) {
365        required[i] = SL_BOOLEAN_FALSE;
366        iidArray[i] = SL_IID_NULL;
367    }
368
369    /* ------------------------------------------------------ */
370    /* Configuration of the player  */
371
372    /* Request the AndroidSimpleBufferQueue interface */
373    required[0] = SL_BOOLEAN_TRUE;
374    iidArray[0] = SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
375    /* Request the AndroidBufferQueue interface */
376    required[1] = SL_BOOLEAN_TRUE;
377    iidArray[1] = SL_IID_ANDROIDBUFFERQUEUE;
378#ifdef QUERY_METADATA
379    /* Request the MetadataExtraction interface */
380    required[2] = SL_BOOLEAN_TRUE;
381    iidArray[2] = SL_IID_METADATAEXTRACTION;
382#endif
383
384    /* Setup the data source for queueing AAC buffers of ADTS data */
385    SLDataLocator_AndroidBufferQueue loc_srcAbq = {
386            SL_DATALOCATOR_ANDROIDBUFFERQUEUE /*locatorType*/,
387            NB_BUFFERS_IN_ADTS_QUEUE          /*numBuffers*/};
388    SLDataFormat_MIME format_srcMime = {
389            SL_DATAFORMAT_MIME         /*formatType*/,
390            (SLchar *)"audio/aac-adts" /*mimeType*/,
391            SL_CONTAINERTYPE_RAW       /*containerType*/};
392    SLDataSource decSource = {&loc_srcAbq /*pLocator*/, &format_srcMime /*pFormat*/};
393
394    /* Setup the data sink, a buffer queue for buffers of PCM data */
395    SLDataLocator_AndroidSimpleBufferQueue loc_destBq = {
396            SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE/*locatorType*/,
397            NB_BUFFERS_IN_PCM_QUEUE                /*numBuffers*/ };
398
399    /*    declare we're decoding to PCM, the parameters after that need to be valid,
400          but are ignored, the decoded format will match the source */
401    SLDataFormat_PCM format_destPcm = { /*formatType*/ SL_DATAFORMAT_PCM, /*numChannels*/ 1,
402            /*samplesPerSec*/ SL_SAMPLINGRATE_8, /*pcm.bitsPerSample*/ SL_PCMSAMPLEFORMAT_FIXED_16,
403            /*/containerSize*/ 16, /*channelMask*/ SL_SPEAKER_FRONT_LEFT,
404            /*endianness*/ SL_BYTEORDER_LITTLEENDIAN };
405    SLDataSink decDest = {&loc_destBq /*pLocator*/, &format_destPcm /*pFormat*/};
406
407    /* Create the audio player */
408    res = (*EngineItf)->CreateAudioPlayer(EngineItf, &player, &decSource, &decDest,
409#ifdef QUERY_METADATA
410            NUM_EXPLICIT_INTERFACES_FOR_PLAYER,
411#else
412            NUM_EXPLICIT_INTERFACES_FOR_PLAYER - 1,
413#endif
414            iidArray, required);
415    ExitOnError(res);
416    printf("Player created\n");
417
418    /* Realize the player in synchronous mode. */
419    res = (*player)->Realize(player, SL_BOOLEAN_FALSE);
420    ExitOnError(res);
421    printf("Player realized\n");
422
423    /* Get the play interface which is implicit */
424    res = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf);
425    ExitOnError(res);
426
427    /* Get the position before prefetch; should be zero */
428    SLmillisecond position;
429    res = (*playItf)->GetPosition(playItf, &position);
430    ExitOnError(res);
431    if (position == 0) {
432        printf("The position before prefetch is zero as expected\n");
433    } else if (position == SL_TIME_UNKNOWN) {
434        printf("That's surprising the position before prefetch is unknown");
435    } else {
436        printf("That's surprising the position before prefetch is %u ms\n", position);
437    }
438
439    /* Get the duration before prefetch; should be unknown */
440    SLmillisecond duration;
441    res = (*playItf)->GetDuration(playItf, &duration);
442    ExitOnError(res);
443    if (duration == SL_TIME_UNKNOWN) {
444        printf("The duration before prefetch is unknown as expected\n");
445    } else {
446        printf("That's surprising the duration before prefetch is %u ms\n", duration);
447    }
448
449    /* Get the buffer queue interface which was explicitly requested */
450    res = (*player)->GetInterface(player, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, (void*)&decBuffQueueItf);
451    ExitOnError(res);
452
453    /* Get the Android buffer queue interface which was explicitly requested */
454    res = (*player)->GetInterface(player, SL_IID_ANDROIDBUFFERQUEUE, (void*)&aacBuffQueueItf);
455    ExitOnError(res);
456
457#ifdef QUERY_METADATA
458    /* Get the metadata extraction interface which was explicitly requested */
459    res = (*player)->GetInterface(player, SL_IID_METADATAEXTRACTION, (void*)&mdExtrItf);
460    ExitOnError(res);
461#endif
462
463    /* ------------------------------------------------------ */
464    /* Initialize the callback and its context for the buffer queue of the decoded PCM */
465    CallbackCntxt sinkCntxt;
466    sinkCntxt.playItf = playItf;
467#ifdef QUERY_METADATA
468    sinkCntxt.metaItf = mdExtrItf;
469#endif
470    sinkCntxt.pDataBase = (int8_t*)&pcmData;
471    sinkCntxt.pData = sinkCntxt.pDataBase;
472    res = (*decBuffQueueItf)->RegisterCallback(decBuffQueueItf, DecPlayCallback, &sinkCntxt);
473    ExitOnError(res);
474
475    /* Enqueue buffers to map the region of memory allocated to store the decoded data */
476    printf("Enqueueing initial empty buffers to receive decoded PCM data");
477    for(i = 0 ; i < NB_BUFFERS_IN_PCM_QUEUE ; i++) {
478        printf(" %d", i);
479        res = (*decBuffQueueItf)->Enqueue(decBuffQueueItf, sinkCntxt.pData, BUFFER_SIZE_IN_BYTES);
480        ExitOnError(res);
481        sinkCntxt.pData += BUFFER_SIZE_IN_BYTES;
482        if (sinkCntxt.pData >= sinkCntxt.pDataBase +
483                (NB_BUFFERS_IN_PCM_QUEUE * BUFFER_SIZE_IN_BYTES)) {
484            sinkCntxt.pData = sinkCntxt.pDataBase;
485        }
486    }
487    printf("\n");
488
489    /* Initialize the callback for the Android buffer queue of the encoded data */
490    res = (*aacBuffQueueItf)->RegisterCallback(aacBuffQueueItf, AndroidBufferQueueCallback, NULL);
491    ExitOnError(res);
492
493    /* Enqueue the content of our encoded data before starting to play,
494       we don't want to starve the player initially */
495    printf("Enqueueing initial full buffers of encoded ADTS data");
496    for (i=0 ; i < NB_BUFFERS_IN_ADTS_QUEUE ; i++) {
497        if (filelen < 7 || frame[0] != 0xFF || (frame[1] & 0xF0) != 0xF0)
498            break;
499        unsigned framelen = ((frame[3] & 3) << 11) | (frame[4] << 3) | (frame[5] >> 5);
500        printf(" %d", i);
501        res = (*aacBuffQueueItf)->Enqueue(aacBuffQueueItf, NULL /*pBufferContext*/,
502                frame, framelen, NULL, 0);
503        ExitOnError(res);
504        frame += framelen;
505        filelen -= framelen;
506        ++encodedFrames;
507        encodedSamples += SAMPLES_PER_AAC_FRAME;
508    }
509    printf("\n");
510
511#ifdef QUERY_METADATA
512    /* ------------------------------------------------------ */
513    /* Display the metadata obtained from the decoder */
514    //   This is for test / demonstration purposes only where we discover the key and value sizes
515    //   of a PCM decoder. An application that would want to directly get access to those values
516    //   can make assumptions about the size of the keys and their matching values (all SLuint32)
517    SLuint32 itemCount;
518    res = (*mdExtrItf)->GetItemCount(mdExtrItf, &itemCount);
519    ExitOnError(res);
520    printf("itemCount=%u\n", itemCount);
521    SLuint32 keySize, valueSize;
522    SLMetadataInfo *keyInfo, *value;
523    for(i=0 ; i<itemCount ; i++) {
524        keyInfo = NULL; keySize = 0;
525        value = NULL;   valueSize = 0;
526        res = (*mdExtrItf)->GetKeySize(mdExtrItf, i, &keySize);
527        ExitOnError(res);
528        res = (*mdExtrItf)->GetValueSize(mdExtrItf, i, &valueSize);
529        ExitOnError(res);
530        keyInfo = (SLMetadataInfo*) malloc(keySize);
531        if (NULL != keyInfo) {
532            res = (*mdExtrItf)->GetKey(mdExtrItf, i, keySize, keyInfo);
533            ExitOnError(res);
534            printf("key[%d] size=%d, name=%s \tvalue size=%d encoding=0x%X langCountry=%s\n",
535                    i, keyInfo->size, keyInfo->data, valueSize, keyInfo->encoding,
536                    keyInfo->langCountry);
537            /* find out the key index of the metadata we're interested in */
538            if (!strcmp((char*)keyInfo->data, ANDROID_KEY_PCMFORMAT_NUMCHANNELS)) {
539                channelCountKeyIndex = i;
540            } else if (!strcmp((char*)keyInfo->data, ANDROID_KEY_PCMFORMAT_SAMPLERATE)) {
541                sampleRateKeyIndex = i;
542            } else if (!strcmp((char*)keyInfo->data, ANDROID_KEY_PCMFORMAT_BITSPERSAMPLE)) {
543                bitsPerSampleKeyIndex = i;
544            } else if (!strcmp((char*)keyInfo->data, ANDROID_KEY_PCMFORMAT_CONTAINERSIZE)) {
545                containerSizeKeyIndex = i;
546            } else if (!strcmp((char*)keyInfo->data, ANDROID_KEY_PCMFORMAT_CHANNELMASK)) {
547                channelMaskKeyIndex = i;
548            } else if (!strcmp((char*)keyInfo->data, ANDROID_KEY_PCMFORMAT_ENDIANNESS)) {
549                endiannessKeyIndex = i;
550            } else {
551                printf("Unknown key %s ignored\n", (char *)keyInfo->data);
552            }
553            free(keyInfo);
554        }
555    }
556    if (channelCountKeyIndex != -1) {
557        printf("Key %s is at index %d\n",
558                ANDROID_KEY_PCMFORMAT_NUMCHANNELS, channelCountKeyIndex);
559    } else {
560        fprintf(stderr, "Unable to find key %s\n", ANDROID_KEY_PCMFORMAT_NUMCHANNELS);
561    }
562    if (sampleRateKeyIndex != -1) {
563        printf("Key %s is at index %d\n",
564                ANDROID_KEY_PCMFORMAT_SAMPLERATE, sampleRateKeyIndex);
565    } else {
566        fprintf(stderr, "Unable to find key %s\n", ANDROID_KEY_PCMFORMAT_SAMPLERATE);
567    }
568    if (bitsPerSampleKeyIndex != -1) {
569        printf("Key %s is at index %d\n",
570                ANDROID_KEY_PCMFORMAT_BITSPERSAMPLE, bitsPerSampleKeyIndex);
571    } else {
572        fprintf(stderr, "Unable to find key %s\n", ANDROID_KEY_PCMFORMAT_BITSPERSAMPLE);
573    }
574    if (containerSizeKeyIndex != -1) {
575        printf("Key %s is at index %d\n",
576                ANDROID_KEY_PCMFORMAT_CONTAINERSIZE, containerSizeKeyIndex);
577    } else {
578        fprintf(stderr, "Unable to find key %s\n", ANDROID_KEY_PCMFORMAT_CONTAINERSIZE);
579    }
580    if (channelMaskKeyIndex != -1) {
581        printf("Key %s is at index %d\n",
582                ANDROID_KEY_PCMFORMAT_CHANNELMASK, channelMaskKeyIndex);
583    } else {
584        fprintf(stderr, "Unable to find key %s\n", ANDROID_KEY_PCMFORMAT_CHANNELMASK);
585    }
586    if (endiannessKeyIndex != -1) {
587        printf("Key %s is at index %d\n",
588                ANDROID_KEY_PCMFORMAT_ENDIANNESS, endiannessKeyIndex);
589    } else {
590        fprintf(stderr, "Unable to find key %s\n", ANDROID_KEY_PCMFORMAT_ENDIANNESS);
591    }
592#endif
593
594    /* ------------------------------------------------------ */
595    /* Start decoding */
596    printf("Starting to decode\n");
597    res = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING);
598    ExitOnError(res);
599
600    /* Decode until the end of the stream is reached */
601    pthread_mutex_lock(&eosLock);
602    while (!eos) {
603        pthread_cond_wait(&eosCondition, &eosLock);
604    }
605    pthread_mutex_unlock(&eosLock);
606
607    /* This just means done enqueueing; there may still more data in decode queue! */
608    usleep(100 * 1000);
609
610    pthread_mutex_lock(&eosLock);
611    printf("Frame counters: encoded=%u decoded=%u\n", encodedFrames, decodedFrames);
612    printf("Sample counters: encoded=%u decoded=%u\n", encodedSamples, decodedSamples);
613    pthread_mutex_unlock(&eosLock);
614
615    /* Get the final position and duration */
616    res = (*playItf)->GetPosition(playItf, &position);
617    ExitOnError(res);
618    res = (*playItf)->GetDuration(playItf, &duration);
619    ExitOnError(res);
620    if (duration == SL_TIME_UNKNOWN) {
621        printf("The final position is %u ms, duration is unknown\n", position);
622    } else {
623        printf("The final position is %u ms, duration is %u ms\n", position, duration);
624    }
625
626    /* ------------------------------------------------------ */
627    /* End of decoding */
628
629destroyRes:
630    /* Destroy the AudioPlayer object */
631    (*player)->Destroy(player);
632
633    fclose(outputFp);
634
635    // unmap the ADTS AAC file from memory
636    ok = munmap(ptr, statbuf.st_size);
637    if (0 != ok) {
638        perror(path);
639    }
640}
641
642//-----------------------------------------------------------------
643int main(int argc, char* const argv[])
644{
645    SLresult    res;
646    SLObjectItf sl;
647
648    printf("OpenSL ES test %s: decodes a file containing AAC ADTS data\n", argv[0]);
649
650    if (argc != 2) {
651        printf("Usage: \t%s source_file\n", argv[0]);
652        printf("Example: \"%s /sdcard/myFile.adts\n", argv[0]);
653        exit(EXIT_FAILURE);
654    }
655
656    // open pathname of encoded ADTS AAC file to get a file descriptor
657    int fd;
658    fd = open(argv[1], O_RDONLY);
659    if (fd < 0) {
660        perror(argv[1]);
661        return EXIT_FAILURE;
662    }
663
664    SLEngineOption EngineOption[] = {
665            {(SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE}
666    };
667
668    res = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL);
669    ExitOnError(res);
670
671    /* Realizing the SL Engine in synchronous mode. */
672    res = (*sl)->Realize(sl, SL_BOOLEAN_FALSE);
673    ExitOnError(res);
674
675    TestDecToBuffQueue(sl, argv[1], fd);
676
677    /* Shutdown OpenSL ES */
678    (*sl)->Destroy(sl);
679
680    // close the file
681    (void) close(fd);
682
683    return EXIT_SUCCESS;
684}
685