slesTestDecodeAac.cpp revision 0c7022072205ec9790a5b2c1b626096fc4cba74d
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 <assert.h> 49#include <stdlib.h> 50#include <stdio.h> 51#include <string.h> 52#include <unistd.h> 53#include <sys/time.h> 54#include <fcntl.h> 55#include <pthread.h> 56#include <sys/mman.h> 57#include <sys/stat.h> 58#include <unistd.h> 59#include <cpustats/CentralTendencyStatistics.h> 60 61#include <SLES/OpenSLES.h> 62#include <SLES/OpenSLES_Android.h> 63 64/* Explicitly requesting SL_IID_ANDROIDBUFFERQUEUE and SL_IID_ANDROIDSIMPLEBUFFERQUEUE 65 * on the AudioPlayer object for decoding, and 66 * SL_IID_METADATAEXTRACTION for retrieving the format of the decoded audio. 67 */ 68#define NUM_EXPLICIT_INTERFACES_FOR_PLAYER 4 69 70/* Number of decoded samples produced by one AAC frame; defined by the standard */ 71#define SAMPLES_PER_AAC_FRAME 1024 72/* Size of the encoded AAC ADTS buffer queue */ 73#define NB_BUFFERS_IN_ADTS_QUEUE 2 // 2 to 4 is typical 74 75/* Size of the decoded PCM buffer queue */ 76#define NB_BUFFERS_IN_PCM_QUEUE 2 // 2 to 4 is typical 77/* Size of each PCM buffer in the queue */ 78#define BUFFER_SIZE_IN_BYTES (2*sizeof(short)*SAMPLES_PER_AAC_FRAME) 79 80/* Local storage for decoded PCM audio data */ 81int8_t pcmData[NB_BUFFERS_IN_PCM_QUEUE * BUFFER_SIZE_IN_BYTES]; 82 83/* destination for decoded data */ 84static FILE* outputFp; 85 86#ifdef QUERY_METADATA 87/* metadata key index for the PCM format information we want to retrieve */ 88static int channelCountKeyIndex = -1; 89static int sampleRateKeyIndex = -1; 90static int bitsPerSampleKeyIndex = -1; 91static int containerSizeKeyIndex = -1; 92static int channelMaskKeyIndex = -1; 93static int endiannessKeyIndex = -1; 94/* size of the struct to retrieve the PCM format metadata values: the values we're interested in 95 * are SLuint32, but it is saved in the data field of a SLMetadataInfo, hence the larger size. 96 * Note that this size is queried and displayed at l.XXX for demonstration/test purposes. 97 * */ 98#define PCM_METADATA_VALUE_SIZE 32 99/* used to query metadata values */ 100static SLMetadataInfo *pcmMetaData = NULL; 101/* we only want to query / display the PCM format once */ 102static bool formatQueried = false; 103#endif 104 105/* to signal to the test app that the end of the encoded ADTS stream has been reached */ 106bool eos = false; 107bool endOfEncodedStream = false; 108 109void *ptr; 110unsigned char *frame; 111size_t filelen; 112size_t encodedFrames = 0; 113size_t encodedSamples = 0; 114size_t decodedFrames = 0; 115size_t decodedSamples = 0; 116size_t totalEncodeCompletions = 0; // number of Enqueue completions received 117CentralTendencyStatistics frameStats; 118size_t pauseFrame = 0; // pause after this many decoded frames, zero means don't pause 119SLboolean createRaw = SL_BOOLEAN_TRUE; // whether to create a .raw file containing PCM data 120 121/* constant to identify a buffer context which is the end of the stream to decode */ 122static const int kEosBufferCntxt = 1980; // a magic value we can compare against 123 124/* protects shared variables */ 125pthread_mutex_t eosLock = PTHREAD_MUTEX_INITIALIZER; 126pthread_cond_t eosCondition = PTHREAD_COND_INITIALIZER; 127 128// These are extensions to OpenMAX AL 1.0.1 values 129 130#define PREFETCHSTATUS_UNKNOWN ((SLuint32) 0) 131#define PREFETCHSTATUS_ERROR ((SLuint32) (-1)) 132 133// Mutex and condition shared with main program to protect prefetch_status 134 135static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 136static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 137SLuint32 prefetch_status = PREFETCHSTATUS_UNKNOWN; 138 139/* used to detect errors likely to have occured when the OpenSL ES framework fails to open 140 * a resource, for instance because a file URI is invalid, or an HTTP server doesn't respond. 141 */ 142#define PREFETCHEVENT_ERROR_CANDIDATE \ 143 (SL_PREFETCHEVENT_STATUSCHANGE | SL_PREFETCHEVENT_FILLLEVELCHANGE) 144 145//----------------------------------------------------------------- 146/* Exits the application if an error is encountered */ 147#define ExitOnError(x) ExitOnErrorFunc(x,__LINE__) 148 149void ExitOnErrorFunc( SLresult result , int line) 150{ 151 if (SL_RESULT_SUCCESS != result) { 152 fprintf(stderr, "Error code %u encountered at line %d, exiting\n", result, line); 153 exit(EXIT_FAILURE); 154 } 155} 156 157//----------------------------------------------------------------- 158/* Callback for "prefetch" events, here used to detect audio resource opening errors */ 159void PrefetchEventCallback(SLPrefetchStatusItf caller, void *pContext, SLuint32 event) 160{ 161 // pContext is unused here, so we pass NULL 162 assert(pContext == NULL); 163 SLpermille level = 0; 164 SLresult result; 165 result = (*caller)->GetFillLevel(caller, &level); 166 ExitOnError(result); 167 SLuint32 status; 168 result = (*caller)->GetPrefetchStatus(caller, &status); 169 ExitOnError(result); 170 printf("prefetch level=%d status=0x%x event=%d\n", level, status, event); 171 SLuint32 new_prefetch_status; 172 if ((PREFETCHEVENT_ERROR_CANDIDATE == (event & PREFETCHEVENT_ERROR_CANDIDATE)) 173 && (level == 0) && (status == SL_PREFETCHSTATUS_UNDERFLOW)) { 174 printf("PrefetchEventCallback: Error while prefetching data, exiting\n"); 175 new_prefetch_status = PREFETCHSTATUS_ERROR; 176 } else if (event == SL_PREFETCHEVENT_STATUSCHANGE) { 177 new_prefetch_status = status; 178 } else { 179 return; 180 } 181 int ok; 182 ok = pthread_mutex_lock(&mutex); 183 assert(ok == 0); 184 prefetch_status = new_prefetch_status; 185 ok = pthread_cond_signal(&cond); 186 assert(ok == 0); 187 ok = pthread_mutex_unlock(&mutex); 188 assert(ok == 0); 189} 190 191//----------------------------------------------------------------- 192/* Structure for passing information to callback function */ 193typedef struct CallbackCntxt_ { 194#ifdef QUERY_METADATA 195 SLMetadataExtractionItf metaItf; 196#endif 197 SLPlayItf playItf; 198 SLint8* pDataBase; // Base address of local audio data storage 199 SLint8* pData; // Current address of local audio data storage 200} CallbackCntxt; 201 202// used to notify when SL_PLAYEVENT_HEADATEND event is received 203static pthread_mutex_t head_mutex = PTHREAD_MUTEX_INITIALIZER; 204static pthread_cond_t head_cond = PTHREAD_COND_INITIALIZER; 205static SLboolean head_atend = SL_BOOLEAN_FALSE; 206 207//----------------------------------------------------------------- 208/* Callback for SLPlayItf through which we receive the SL_PLAYEVENT_HEADATEND event */ 209void PlayCallback(SLPlayItf caller, void *pContext, SLuint32 event) { 210 SLmillisecond position; 211 SLresult res = (*caller)->GetPosition(caller, &position); 212 ExitOnError(res); 213 if (event & SL_PLAYEVENT_HEADATMARKER) { 214 printf("SL_PLAYEVENT_HEADATMARKER position=%u ms\n", position); 215 } 216 if (event & SL_PLAYEVENT_HEADATNEWPOS) { 217 printf("SL_PLAYEVENT_HEADATNEWPOS position=%u ms\n", position); 218 } 219 if (event & SL_PLAYEVENT_HEADATEND) { 220 printf("SL_PLAYEVENT_HEADATEND position=%u ms, all decoded data has been received\n", 221 position); 222 pthread_mutex_lock(&head_mutex); 223 head_atend = SL_BOOLEAN_TRUE; 224 pthread_cond_signal(&head_cond); 225 pthread_mutex_unlock(&head_mutex); 226 } 227} 228 229//----------------------------------------------------------------- 230/* Callback for AndroidBufferQueueItf through which we supply ADTS buffers */ 231SLresult AndroidBufferQueueCallback( 232 SLAndroidBufferQueueItf caller, 233 void *pCallbackContext, /* input */ 234 void *pBufferContext, /* input */ 235 void *pBufferData, /* input */ 236 SLuint32 dataSize, /* input */ 237 SLuint32 dataUsed, /* input */ 238 const SLAndroidBufferItem *pItems,/* input */ 239 SLuint32 itemsLength /* input */) 240{ 241 // mutex on all global variables 242 pthread_mutex_lock(&eosLock); 243 SLresult res; 244 245 // for demonstration purposes: 246 // verify what type of information was enclosed in the processed buffer 247 if (NULL != pBufferContext) { 248 if (&kEosBufferCntxt == pBufferContext) { 249 fprintf(stdout, "EOS was processed\n"); 250 } 251 } 252 253 ++totalEncodeCompletions; 254 if (endOfEncodedStream) { 255 // we continue to receive acknowledgement after each buffer was processed 256 if (pBufferContext == (void *) &kEosBufferCntxt) { 257 printf("Received EOS completion after EOS\n"); 258 } else if (pBufferContext == NULL) { 259 printf("Received ADTS completion after EOS\n"); 260 } else { 261 fprintf(stderr, "Received acknowledgement after EOS with unexpected context %p\n", 262 pBufferContext); 263 } 264 } else if (filelen == 0) { 265 // signal EOS to the decoder rather than just starving it 266 printf("Enqueue EOS: encoded frames=%zu, decoded frames=%zu\n", encodedFrames, 267 decodedFrames); 268 printf("You should now see %u ADTS completion%s followed by 1 EOS completion\n", 269 NB_BUFFERS_IN_ADTS_QUEUE - 1, NB_BUFFERS_IN_ADTS_QUEUE != 2 ? "s" : ""); 270 SLAndroidBufferItem msgEos; 271 msgEos.itemKey = SL_ANDROID_ITEMKEY_EOS; 272 msgEos.itemSize = 0; 273 // EOS message has no parameters, so the total size of the message is the size of the key 274 // plus the size of itemSize, both SLuint32 275 res = (*caller)->Enqueue(caller, (void *)&kEosBufferCntxt /*pBufferContext*/, 276 NULL /*pData*/, 0 /*dataLength*/, 277 &msgEos /*pMsg*/, 278 sizeof(SLuint32)*2 /*msgLength*/); 279 ExitOnError(res); 280 endOfEncodedStream = true; 281 // verify that we are at start of an ADTS frame 282 } else if (!(filelen < 7 || frame[0] != 0xFF || (frame[1] & 0xF0) != 0xF0)) { 283 if (pBufferContext != NULL) { 284 fprintf(stderr, "Received acknowledgement before EOS with unexpected context %p\n", 285 pBufferContext); 286 } 287 unsigned framelen = ((frame[3] & 3) << 11) | (frame[4] << 3) | (frame[5] >> 5); 288 if (framelen <= filelen) { 289 // push more data to the queue 290 res = (*caller)->Enqueue(caller, NULL /*pBufferContext*/, 291 frame, framelen, NULL, 0); 292 ExitOnError(res); 293 frame += framelen; 294 filelen -= framelen; 295 ++encodedFrames; 296 encodedSamples += SAMPLES_PER_AAC_FRAME; 297 frameStats.sample(framelen); 298 } else { 299 fprintf(stderr, 300 "partial ADTS frame at EOF discarded; offset=%zu, framelen=%u, filelen=%zu\n", 301 frame - (unsigned char *) ptr, framelen, filelen); 302 frame += filelen; 303 filelen = 0; 304 } 305 } else { 306 fprintf(stderr, "corrupt ADTS frame encountered; offset=%zu, filelen=%zu\n", 307 frame - (unsigned char *) ptr, filelen); 308 frame += filelen; 309 filelen = 0; 310 } 311 pthread_mutex_unlock(&eosLock); 312 313 return SL_RESULT_SUCCESS; 314} 315 316//----------------------------------------------------------------- 317/* Callback for decoding buffer queue events */ 318void DecPlayCallback( 319 SLAndroidSimpleBufferQueueItf queueItf, 320 void *pContext) 321{ 322 // mutex on all global variables 323 pthread_mutex_lock(&eosLock); 324 325 CallbackCntxt *pCntxt = (CallbackCntxt*)pContext; 326 327 /* Save the decoded data to output file */ 328 if (outputFp != NULL && fwrite(pCntxt->pData, 1, BUFFER_SIZE_IN_BYTES, outputFp) 329 < BUFFER_SIZE_IN_BYTES) { 330 fprintf(stderr, "Error writing to output file"); 331 } 332 333 /* Re-enqueue the now empty buffer */ 334 SLresult res; 335 res = (*queueItf)->Enqueue(queueItf, pCntxt->pData, BUFFER_SIZE_IN_BYTES); 336 ExitOnError(res); 337 338 /* Increase data pointer by buffer size, with circular wraparound */ 339 pCntxt->pData += BUFFER_SIZE_IN_BYTES; 340 if (pCntxt->pData >= pCntxt->pDataBase + (NB_BUFFERS_IN_PCM_QUEUE * BUFFER_SIZE_IN_BYTES)) { 341 pCntxt->pData = pCntxt->pDataBase; 342 } 343 344 // Note: adding a sleep here or any sync point is a way to slow down the decoding, or 345 // synchronize it with some other event, as the OpenSL ES framework will block until the 346 // buffer queue callback return to proceed with the decoding. 347 348#ifdef QUERY_METADATA 349 /* Example: query of the decoded PCM format */ 350 if (!formatQueried) { 351 /* memory to receive the PCM format metadata */ 352 union { 353 SLMetadataInfo pcmMetaData; 354 char withData[PCM_METADATA_VALUE_SIZE]; 355 } u; 356 res = (*pCntxt->metaItf)->GetValue(pCntxt->metaItf, sampleRateKeyIndex, 357 PCM_METADATA_VALUE_SIZE, &u.pcmMetaData); ExitOnError(res); 358 // Note: here we could verify the following: 359 // u.pcmMetaData->encoding == SL_CHARACTERENCODING_BINARY 360 // u.pcmMetaData->size == sizeof(SLuint32) 361 // but the call was successful for the PCM format keys, so those conditions are implied 362 printf("sample rate = %d\n", *((SLuint32*)u.pcmMetaData.data)); 363 res = (*pCntxt->metaItf)->GetValue(pCntxt->metaItf, channelCountKeyIndex, 364 PCM_METADATA_VALUE_SIZE, &u.pcmMetaData); ExitOnError(res); 365 printf("channel count = %d\n", *((SLuint32*)u.pcmMetaData.data)); 366 res = (*pCntxt->metaItf)->GetValue(pCntxt->metaItf, bitsPerSampleKeyIndex, 367 PCM_METADATA_VALUE_SIZE, &u.pcmMetaData); ExitOnError(res); 368 printf("bits per sample = %d bits\n", *((SLuint32*)u.pcmMetaData.data)); 369 res = (*pCntxt->metaItf)->GetValue(pCntxt->metaItf, containerSizeKeyIndex, 370 PCM_METADATA_VALUE_SIZE, &u.pcmMetaData); ExitOnError(res); 371 printf("container size = %d bits\n", *((SLuint32*)u.pcmMetaData.data)); 372 res = (*pCntxt->metaItf)->GetValue(pCntxt->metaItf, channelMaskKeyIndex, 373 PCM_METADATA_VALUE_SIZE, &u.pcmMetaData); ExitOnError(res); 374 printf("channel mask = 0x%X (0x3=front left | front right, 0x4=front center)\n", 375 *((SLuint32*)u.pcmMetaData.data)); 376 res = (*pCntxt->metaItf)->GetValue(pCntxt->metaItf, endiannessKeyIndex, 377 PCM_METADATA_VALUE_SIZE, &u.pcmMetaData); ExitOnError(res); 378 printf("endianness = %d (1=big, 2=little)\n", *((SLuint32*)u.pcmMetaData.data)); 379 formatQueried = true; 380 } 381#endif 382 383 ++decodedFrames; 384 decodedSamples += SAMPLES_PER_AAC_FRAME; 385 386 /* Periodically ask for position and duration */ 387 if ((decodedFrames % 1000 == 0) || endOfEncodedStream) { 388 SLmillisecond position; 389 res = (*pCntxt->playItf)->GetPosition(pCntxt->playItf, &position); 390 ExitOnError(res); 391 SLmillisecond duration; 392 res = (*pCntxt->playItf)->GetDuration(pCntxt->playItf, &duration); 393 ExitOnError(res); 394 if (duration == SL_TIME_UNKNOWN) { 395 printf("After %zu encoded %zu decoded frames: position is %u ms, duration is " 396 "unknown as expected\n", 397 encodedFrames, decodedFrames, position); 398 } else { 399 printf("After %zu encoded %zu decoded frames: position is %u ms, duration is " 400 "surprisingly %u ms\n", 401 encodedFrames, decodedFrames, position, duration); 402 } 403 } 404 405 if (endOfEncodedStream && decodedSamples >= encodedSamples) { 406 eos = true; 407 pthread_cond_signal(&eosCondition); 408 } 409 pthread_mutex_unlock(&eosLock); 410} 411 412//----------------------------------------------------------------- 413 414/* Decode an audio path by opening a file descriptor on that path */ 415void TestDecToBuffQueue( SLObjectItf sl, const char *path, int fd) 416{ 417 // check what kind of object it is 418 int ok; 419 struct stat statbuf; 420 ok = fstat(fd, &statbuf); 421 if (ok < 0) { 422 perror(path); 423 return; 424 } 425 426 // verify that's it is a file 427 if (!S_ISREG(statbuf.st_mode)) { 428 fprintf(stderr, "%s: not an ordinary file\n", path); 429 return; 430 } 431 432 // map file contents into memory to make it easier to access the ADTS frames directly 433 ptr = mmap(NULL, statbuf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, (off_t) 0); 434 if (ptr == MAP_FAILED) { 435 perror(path); 436 return; 437 } 438 frame = (unsigned char *) ptr; 439 filelen = statbuf.st_size; 440 441 // create PCM .raw file 442 if (createRaw) { 443 size_t len = strlen((const char *) path); 444 char* outputPath = (char*) malloc(len + 4 + 1); // save room to concatenate ".raw" 445 if (NULL == outputPath) { 446 ExitOnError(SL_RESULT_RESOURCE_ERROR); 447 } 448 memcpy(outputPath, path, len + 1); 449 strcat(outputPath, ".raw"); 450 outputFp = fopen(outputPath, "w"); 451 if (NULL == outputFp) { 452 // issue an error message, but continue the decoding anyway 453 perror(outputPath); 454 } 455 } else { 456 outputFp = NULL; 457 } 458 459 SLresult res; 460 SLEngineItf EngineItf; 461 462 /* Objects this application uses: one audio player */ 463 SLObjectItf player; 464 465 /* Interfaces for the audio player */ 466 SLPlayItf playItf; 467#ifdef QUERY_METADATA 468 /* to retrieve the decoded PCM format */ 469 SLMetadataExtractionItf mdExtrItf; 470#endif 471 /* to retrieve the PCM samples */ 472 SLAndroidSimpleBufferQueueItf decBuffQueueItf; 473 /* to queue the AAC data to decode */ 474 SLAndroidBufferQueueItf aacBuffQueueItf; 475 /* for prefetch status */ 476 SLPrefetchStatusItf prefetchItf; 477 478 SLboolean required[NUM_EXPLICIT_INTERFACES_FOR_PLAYER]; 479 SLInterfaceID iidArray[NUM_EXPLICIT_INTERFACES_FOR_PLAYER]; 480 481 /* Get the SL Engine Interface which is implicit */ 482 res = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf); 483 ExitOnError(res); 484 485 /* Initialize arrays required[] and iidArray[] */ 486 unsigned int i; 487 for (i=0 ; i < NUM_EXPLICIT_INTERFACES_FOR_PLAYER ; i++) { 488 required[i] = SL_BOOLEAN_FALSE; 489 iidArray[i] = SL_IID_NULL; 490 } 491 492 /* ------------------------------------------------------ */ 493 /* Configuration of the player */ 494 495 /* Request the AndroidSimpleBufferQueue interface */ 496 required[0] = SL_BOOLEAN_TRUE; 497 iidArray[0] = SL_IID_ANDROIDSIMPLEBUFFERQUEUE; 498 /* Request the AndroidBufferQueue interface */ 499 required[1] = SL_BOOLEAN_TRUE; 500 iidArray[1] = SL_IID_ANDROIDBUFFERQUEUESOURCE; 501 /* Request the PrefetchStatus interface */ 502 required[2] = SL_BOOLEAN_TRUE; 503 iidArray[2] = SL_IID_PREFETCHSTATUS; 504#ifdef QUERY_METADATA 505 /* Request the MetadataExtraction interface */ 506 required[3] = SL_BOOLEAN_TRUE; 507 iidArray[3] = SL_IID_METADATAEXTRACTION; 508#endif 509 510 /* Setup the data source for queueing AAC buffers of ADTS data */ 511 SLDataLocator_AndroidBufferQueue loc_srcAbq = { 512 SL_DATALOCATOR_ANDROIDBUFFERQUEUE /*locatorType*/, 513 NB_BUFFERS_IN_ADTS_QUEUE /*numBuffers*/}; 514 SLDataFormat_MIME format_srcMime = { 515 SL_DATAFORMAT_MIME /*formatType*/, 516 SL_ANDROID_MIME_AACADTS /*mimeType*/, 517 SL_CONTAINERTYPE_RAW /*containerType*/}; 518 SLDataSource decSource = {&loc_srcAbq /*pLocator*/, &format_srcMime /*pFormat*/}; 519 520 /* Setup the data sink, a buffer queue for buffers of PCM data */ 521 SLDataLocator_AndroidSimpleBufferQueue loc_destBq = { 522 SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE/*locatorType*/, 523 NB_BUFFERS_IN_PCM_QUEUE /*numBuffers*/ }; 524 525 /* declare we're decoding to PCM, the parameters after that need to be valid, 526 but are ignored, the decoded format will match the source */ 527 SLDataFormat_PCM format_destPcm = { /*formatType*/ SL_DATAFORMAT_PCM, /*numChannels*/ 1, 528 /*samplesPerSec*/ SL_SAMPLINGRATE_8, /*pcm.bitsPerSample*/ SL_PCMSAMPLEFORMAT_FIXED_16, 529 /*/containerSize*/ 16, /*channelMask*/ SL_SPEAKER_FRONT_LEFT, 530 /*endianness*/ SL_BYTEORDER_LITTLEENDIAN }; 531 SLDataSink decDest = {&loc_destBq /*pLocator*/, &format_destPcm /*pFormat*/}; 532 533 /* Create the audio player */ 534 res = (*EngineItf)->CreateAudioPlayer(EngineItf, &player, &decSource, &decDest, 535#ifdef QUERY_METADATA 536 NUM_EXPLICIT_INTERFACES_FOR_PLAYER, 537#else 538 NUM_EXPLICIT_INTERFACES_FOR_PLAYER - 1, 539#endif 540 iidArray, required); 541 ExitOnError(res); 542 printf("Player created\n"); 543 544 /* Realize the player in synchronous mode. */ 545 res = (*player)->Realize(player, SL_BOOLEAN_FALSE); 546 ExitOnError(res); 547 printf("Player realized\n"); 548 549 /* Get the play interface which is implicit */ 550 res = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf); 551 ExitOnError(res); 552 553 /* Enable callback when position passes through a marker (SL_PLAYEVENT_HEADATMARKER) */ 554 res = (*playItf)->SetMarkerPosition(playItf, 5000); 555 ExitOnError(res); 556 557 /* Enable callback for periodic position updates (SL_PLAYEVENT_HEADATNEWPOS) */ 558 res = (*playItf)->SetPositionUpdatePeriod(playItf, 3000); 559 ExitOnError(res); 560 561 /* Use the play interface to set up a callback for the SL_PLAYEVENT_HEAD* events */ 562 res = (*playItf)->SetCallbackEventsMask(playItf, 563 SL_PLAYEVENT_HEADATMARKER | SL_PLAYEVENT_HEADATNEWPOS | SL_PLAYEVENT_HEADATEND); 564 ExitOnError(res); 565 res = (*playItf)->RegisterCallback(playItf, PlayCallback /*callback*/, NULL /*pContext*/); 566 ExitOnError(res); 567 568 /* Get the position before prefetch; should be zero */ 569 SLmillisecond position; 570 res = (*playItf)->GetPosition(playItf, &position); 571 ExitOnError(res); 572 if (position == 0) { 573 printf("The position before prefetch is zero as expected\n"); 574 } else if (position == SL_TIME_UNKNOWN) { 575 printf("That's surprising the position before prefetch is unknown"); 576 } else { 577 printf("That's surprising the position before prefetch is %u ms\n", position); 578 } 579 580 /* Get the duration before prefetch; should be unknown */ 581 SLmillisecond duration; 582 res = (*playItf)->GetDuration(playItf, &duration); 583 ExitOnError(res); 584 if (duration == SL_TIME_UNKNOWN) { 585 printf("The duration before prefetch is unknown as expected\n"); 586 } else { 587 printf("That's surprising the duration before prefetch is %u ms\n", duration); 588 } 589 590 /* Get the buffer queue interface which was explicitly requested */ 591 res = (*player)->GetInterface(player, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, (void*)&decBuffQueueItf); 592 ExitOnError(res); 593 594 /* Get the Android buffer queue interface which was explicitly requested */ 595 res = (*player)->GetInterface(player, SL_IID_ANDROIDBUFFERQUEUESOURCE, (void*)&aacBuffQueueItf); 596 ExitOnError(res); 597 598 /* Get the prefetch status interface which was explicitly requested */ 599 res = (*player)->GetInterface(player, SL_IID_PREFETCHSTATUS, (void*)&prefetchItf); 600 ExitOnError(res); 601 602#ifdef QUERY_METADATA 603 /* Get the metadata extraction interface which was explicitly requested */ 604 res = (*player)->GetInterface(player, SL_IID_METADATAEXTRACTION, (void*)&mdExtrItf); 605 ExitOnError(res); 606#endif 607 608 /* ------------------------------------------------------ */ 609 /* Initialize the callback and its context for the buffer queue of the decoded PCM */ 610 CallbackCntxt sinkCntxt; 611 sinkCntxt.playItf = playItf; 612#ifdef QUERY_METADATA 613 sinkCntxt.metaItf = mdExtrItf; 614#endif 615 sinkCntxt.pDataBase = (int8_t*)&pcmData; 616 sinkCntxt.pData = sinkCntxt.pDataBase; 617 res = (*decBuffQueueItf)->RegisterCallback(decBuffQueueItf, DecPlayCallback, &sinkCntxt); 618 ExitOnError(res); 619 620 /* Enqueue buffers to map the region of memory allocated to store the decoded data */ 621 printf("Enqueueing initial empty buffers to receive decoded PCM data"); 622 for(i = 0 ; i < NB_BUFFERS_IN_PCM_QUEUE ; i++) { 623 printf(" %d", i); 624 res = (*decBuffQueueItf)->Enqueue(decBuffQueueItf, sinkCntxt.pData, BUFFER_SIZE_IN_BYTES); 625 ExitOnError(res); 626 sinkCntxt.pData += BUFFER_SIZE_IN_BYTES; 627 if (sinkCntxt.pData >= sinkCntxt.pDataBase + 628 (NB_BUFFERS_IN_PCM_QUEUE * BUFFER_SIZE_IN_BYTES)) { 629 sinkCntxt.pData = sinkCntxt.pDataBase; 630 } 631 } 632 printf("\n"); 633 634 /* ------------------------------------------------------ */ 635 /* Initialize the callback for prefetch errors, if we can't open the resource to decode */ 636 res = (*prefetchItf)->RegisterCallback(prefetchItf, PrefetchEventCallback, NULL); 637 ExitOnError(res); 638 res = (*prefetchItf)->SetCallbackEventsMask(prefetchItf, PREFETCHEVENT_ERROR_CANDIDATE); 639 ExitOnError(res); 640 641 /* Initialize the callback for the Android buffer queue of the encoded data */ 642 res = (*aacBuffQueueItf)->RegisterCallback(aacBuffQueueItf, AndroidBufferQueueCallback, NULL); 643 ExitOnError(res); 644 645 /* Enqueue the content of our encoded data before starting to play, 646 we don't want to starve the player initially */ 647 printf("Enqueueing initial full buffers of encoded ADTS data"); 648 for (i=0 ; i < NB_BUFFERS_IN_ADTS_QUEUE ; i++) { 649 if (filelen < 7 || frame[0] != 0xFF || (frame[1] & 0xF0) != 0xF0) { 650 printf("\ncorrupt ADTS frame encountered; offset %zu bytes\n", 651 frame - (unsigned char *) ptr); 652 // Note that prefetch will detect this error soon when it gets a premature EOF 653 break; 654 } 655 unsigned framelen = ((frame[3] & 3) << 11) | (frame[4] << 3) | (frame[5] >> 5); 656 printf(" %d (%u bytes)", i, framelen); 657 res = (*aacBuffQueueItf)->Enqueue(aacBuffQueueItf, NULL /*pBufferContext*/, 658 frame, framelen, NULL, 0); 659 ExitOnError(res); 660 frame += framelen; 661 filelen -= framelen; 662 ++encodedFrames; 663 encodedSamples += SAMPLES_PER_AAC_FRAME; 664 frameStats.sample(framelen); 665 } 666 printf("\n"); 667 668#ifdef QUERY_METADATA 669 /* ------------------------------------------------------ */ 670 /* Get and display the metadata key names for the decoder */ 671 // This is for test / demonstration purposes only where we discover the key and value sizes 672 // of a PCM decoder. An application that would want to directly get access to those values 673 // can make assumptions about the size of the keys and their matching values (all SLuint32), 674 // but it should not make assumptions about the key indices as these are subject to change. 675 // Note that we don't get the metadata values yet; that happens in the first decode callback. 676 SLuint32 itemCount; 677 res = (*mdExtrItf)->GetItemCount(mdExtrItf, &itemCount); 678 ExitOnError(res); 679 printf("itemCount=%u\n", itemCount); 680 SLuint32 keySize, valueSize; 681 SLMetadataInfo *keyInfo, *value; 682 for(i=0 ; i<itemCount ; i++) { 683 keyInfo = NULL; keySize = 0; 684 value = NULL; valueSize = 0; 685 res = (*mdExtrItf)->GetKeySize(mdExtrItf, i, &keySize); 686 ExitOnError(res); 687 res = (*mdExtrItf)->GetValueSize(mdExtrItf, i, &valueSize); 688 ExitOnError(res); 689 keyInfo = (SLMetadataInfo*) malloc(keySize); 690 if (NULL != keyInfo) { 691 res = (*mdExtrItf)->GetKey(mdExtrItf, i, keySize, keyInfo); 692 ExitOnError(res); 693 printf("key[%d] size=%d, name=%s \tvalue size=%d encoding=0x%X langCountry=%s\n", 694 i, keyInfo->size, keyInfo->data, valueSize, keyInfo->encoding, 695 keyInfo->langCountry); 696 /* find out the key index of the metadata we're interested in */ 697 if (!strcmp((char*)keyInfo->data, ANDROID_KEY_PCMFORMAT_NUMCHANNELS)) { 698 channelCountKeyIndex = i; 699 } else if (!strcmp((char*)keyInfo->data, ANDROID_KEY_PCMFORMAT_SAMPLERATE)) { 700 sampleRateKeyIndex = i; 701 } else if (!strcmp((char*)keyInfo->data, ANDROID_KEY_PCMFORMAT_BITSPERSAMPLE)) { 702 bitsPerSampleKeyIndex = i; 703 } else if (!strcmp((char*)keyInfo->data, ANDROID_KEY_PCMFORMAT_CONTAINERSIZE)) { 704 containerSizeKeyIndex = i; 705 } else if (!strcmp((char*)keyInfo->data, ANDROID_KEY_PCMFORMAT_CHANNELMASK)) { 706 channelMaskKeyIndex = i; 707 } else if (!strcmp((char*)keyInfo->data, ANDROID_KEY_PCMFORMAT_ENDIANNESS)) { 708 endiannessKeyIndex = i; 709 } else { 710 printf("Unknown key %s ignored\n", (char *)keyInfo->data); 711 } 712 free(keyInfo); 713 } 714 } 715 if (channelCountKeyIndex != -1) { 716 printf("Key %s is at index %d\n", 717 ANDROID_KEY_PCMFORMAT_NUMCHANNELS, channelCountKeyIndex); 718 } else { 719 fprintf(stderr, "Unable to find key %s\n", ANDROID_KEY_PCMFORMAT_NUMCHANNELS); 720 } 721 if (sampleRateKeyIndex != -1) { 722 printf("Key %s is at index %d\n", 723 ANDROID_KEY_PCMFORMAT_SAMPLERATE, sampleRateKeyIndex); 724 } else { 725 fprintf(stderr, "Unable to find key %s\n", ANDROID_KEY_PCMFORMAT_SAMPLERATE); 726 } 727 if (bitsPerSampleKeyIndex != -1) { 728 printf("Key %s is at index %d\n", 729 ANDROID_KEY_PCMFORMAT_BITSPERSAMPLE, bitsPerSampleKeyIndex); 730 } else { 731 fprintf(stderr, "Unable to find key %s\n", ANDROID_KEY_PCMFORMAT_BITSPERSAMPLE); 732 } 733 if (containerSizeKeyIndex != -1) { 734 printf("Key %s is at index %d\n", 735 ANDROID_KEY_PCMFORMAT_CONTAINERSIZE, containerSizeKeyIndex); 736 } else { 737 fprintf(stderr, "Unable to find key %s\n", ANDROID_KEY_PCMFORMAT_CONTAINERSIZE); 738 } 739 if (channelMaskKeyIndex != -1) { 740 printf("Key %s is at index %d\n", 741 ANDROID_KEY_PCMFORMAT_CHANNELMASK, channelMaskKeyIndex); 742 } else { 743 fprintf(stderr, "Unable to find key %s\n", ANDROID_KEY_PCMFORMAT_CHANNELMASK); 744 } 745 if (endiannessKeyIndex != -1) { 746 printf("Key %s is at index %d\n", 747 ANDROID_KEY_PCMFORMAT_ENDIANNESS, endiannessKeyIndex); 748 } else { 749 fprintf(stderr, "Unable to find key %s\n", ANDROID_KEY_PCMFORMAT_ENDIANNESS); 750 } 751#endif 752 753 // set the player's state to paused, to start prefetching 754 printf("Setting play state to PAUSED\n"); 755 res = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PAUSED); 756 ExitOnError(res); 757 758 // wait for prefetch status callback to indicate either sufficient data or error 759 printf("Awaiting prefetch complete\n"); 760 pthread_mutex_lock(&mutex); 761 while (prefetch_status == PREFETCHSTATUS_UNKNOWN) { 762 pthread_cond_wait(&cond, &mutex); 763 } 764 pthread_mutex_unlock(&mutex); 765 if (prefetch_status == PREFETCHSTATUS_ERROR) { 766 fprintf(stderr, "Error during prefetch, exiting\n"); 767 goto destroyRes; 768 } 769 printf("Prefetch is complete\n"); 770 771 /* ------------------------------------------------------ */ 772 /* Start decoding */ 773 printf("Starting to decode\n"); 774 res = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING); 775 ExitOnError(res); 776 777 /* Decode until the end of the stream is reached */ 778 printf("Awaiting notification that all encoded buffers have been enqueued\n"); 779 pthread_mutex_lock(&eosLock); 780 while (!eos) { 781 if (pauseFrame > 0) { 782 if (decodedFrames >= pauseFrame) { 783 pauseFrame = 0; 784 printf("Pausing after decoded frame %zu for 10 seconds\n", decodedFrames); 785 pthread_mutex_unlock(&eosLock); 786 res = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PAUSED); 787 ExitOnError(res); 788 sleep(10); 789 printf("Resuming\n"); 790 res = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING); 791 ExitOnError(res); 792 pthread_mutex_lock(&eosLock); 793 } else { 794 pthread_mutex_unlock(&eosLock); 795 usleep(10*1000); 796 pthread_mutex_lock(&eosLock); 797 } 798 } else { 799 pthread_cond_wait(&eosCondition, &eosLock); 800 } 801 } 802 pthread_mutex_unlock(&eosLock); 803 printf("All encoded buffers have now been enqueued, but there's still more to do\n"); 804 805 /* This just means done enqueueing; there may still more data in decode queue! */ 806 pthread_mutex_lock(&head_mutex); 807 while (!head_atend) { 808 pthread_cond_wait(&head_cond, &head_mutex); 809 } 810 pthread_mutex_unlock(&head_mutex); 811 printf("Decode is now finished\n"); 812 813 pthread_mutex_lock(&eosLock); 814 printf("Frame counters: encoded=%zu decoded=%zu\n", encodedFrames, decodedFrames); 815 printf("Sample counters: encoded=%zu decoded=%zu\n", encodedSamples, decodedSamples); 816 printf("Total encode completions received: actual=%zu, expected=%zu\n", 817 totalEncodeCompletions, encodedFrames+1/*EOS*/); 818 pthread_mutex_unlock(&eosLock); 819 820 /* Get the final position and duration */ 821 res = (*playItf)->GetPosition(playItf, &position); 822 ExitOnError(res); 823 res = (*playItf)->GetDuration(playItf, &duration); 824 ExitOnError(res); 825 if (duration == SL_TIME_UNKNOWN) { 826 printf("The final position is %u ms, duration is unknown\n", position); 827 } else { 828 printf("The final position is %u ms, duration is %u ms\n", position, duration); 829 } 830 831 printf("Frame length statistics:\n"); 832 printf(" n = %u frames\n", frameStats.n()); 833 printf(" mean = %.1f bytes\n", frameStats.mean()); 834 printf(" minimum = %.1f bytes\n", frameStats.minimum()); 835 printf(" maximum = %.1f bytes\n", frameStats.maximum()); 836 printf(" stddev = %.1f bytes\n", frameStats.stddev()); 837 838 /* ------------------------------------------------------ */ 839 /* End of decoding */ 840 841destroyRes: 842 /* Destroy the AudioPlayer object */ 843 (*player)->Destroy(player); 844 845 if (outputFp != NULL) { 846 fclose(outputFp); 847 } 848 849 // unmap the ADTS AAC file from memory 850 ok = munmap(ptr, statbuf.st_size); 851 if (0 != ok) { 852 perror(path); 853 } 854} 855 856//----------------------------------------------------------------- 857int main(int argc, char* const argv[]) 858{ 859 SLresult res; 860 SLObjectItf sl; 861 862 printf("OpenSL ES test %s: decodes a file containing AAC ADTS data\n", argv[0]); 863 864 if (argc != 2) { 865 printf("Usage: \t%s source_file\n", argv[0]); 866 printf("Example: \"%s /sdcard/myFile.adts\n", argv[0]); 867 exit(EXIT_FAILURE); 868 } 869 870 // open pathname of encoded ADTS AAC file to get a file descriptor 871 int fd; 872 fd = open(argv[1], O_RDONLY); 873 if (fd < 0) { 874 perror(argv[1]); 875 return EXIT_FAILURE; 876 } 877 878 SLEngineOption EngineOption[] = { 879 {(SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE} 880 }; 881 882 res = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL); 883 ExitOnError(res); 884 885 /* Realizing the SL Engine in synchronous mode. */ 886 res = (*sl)->Realize(sl, SL_BOOLEAN_FALSE); 887 ExitOnError(res); 888 889 TestDecToBuffQueue(sl, argv[1], fd); 890 891 /* Shutdown OpenSL ES */ 892 (*sl)->Destroy(sl); 893 894 // close the file 895 (void) close(fd); 896 897 return EXIT_SUCCESS; 898} 899