slesTestDecodeToBuffQueue.cpp revision 7f5cc1afe49395fefaad9b2bbd728a45d1bfda6a
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#include <SLES/OpenSLES_AndroidConfiguration.h> 49 50/* Explicitly requesting SL_IID_ANDROIDSIMPLEBUFFERQUEUE and SL_IID_PREFETCHSTATUS 51 * on the AudioPlayer object for decoding, SL_IID_METADATAEXTRACTION for retrieving the 52 * format of the decoded audio */ 53#define NUM_EXPLICIT_INTERFACES_FOR_PLAYER 3 54 55/* Size of the decode buffer queue */ 56#define NB_BUFFERS_IN_QUEUE 4 57/* Size of each buffer in the queue */ 58#define BUFFER_SIZE_IN_SAMPLES 1152 // number of samples per MP3 frame 59#define BUFFER_SIZE_IN_BYTES (2*BUFFER_SIZE_IN_SAMPLES) 60 61/* Local storage for decoded audio data */ 62int8_t pcmData[NB_BUFFERS_IN_QUEUE * BUFFER_SIZE_IN_BYTES]; 63 64/* destination for decoded data */ 65static FILE* gFp; 66 67/* to display the number of decode iterations */ 68static int counter=0; 69 70/* to signal to the test app the end of the stream to decode has been reached */ 71bool eos = false; 72android::Mutex eosLock; 73android::Condition eosCondition; 74 75/* used to detect errors likely to have occured when the OpenSL ES framework fails to open 76 * a resource, for instance because a file URI is invalid, or an HTTP server doesn't respond. 77 */ 78#define PREFETCHEVENT_ERROR_CANDIDATE \ 79 (SL_PREFETCHEVENT_STATUSCHANGE | SL_PREFETCHEVENT_FILLLEVELCHANGE) 80 81//----------------------------------------------------------------- 82/* Exits the application if an error is encountered */ 83#define ExitOnError(x) ExitOnErrorFunc(x,__LINE__) 84 85void ExitOnErrorFunc( SLresult result , int line) 86{ 87 if (SL_RESULT_SUCCESS != result) { 88 fprintf(stdout, "Error code %u encountered at line %d, exiting\n", result, line); 89 exit(EXIT_FAILURE); 90 } 91} 92 93/* Used to signal prefetching failures */ 94bool prefetchError = false; 95 96//----------------------------------------------------------------- 97/* Structure for passing information to callback function */ 98typedef struct CallbackCntxt_ { 99 SLPlayItf playItf; 100 SLuint32 size; 101 SLint8* pDataBase; // Base address of local audio data storage 102 SLint8* pData; // Current address of local audio data storage 103} CallbackCntxt; 104 105//----------------------------------------------------------------- 106void SignalEos() { 107 android::Mutex::Autolock autoLock(eosLock); 108 eos = true; 109 eosCondition.signal(); 110} 111 112//----------------------------------------------------------------- 113/* Callback for "prefetch" events, here used to detect audio resource opening errors */ 114void PrefetchEventCallback( SLPrefetchStatusItf caller, void *pContext, SLuint32 event) 115{ 116 SLpermille level = 0; 117 (*caller)->GetFillLevel(caller, &level); 118 SLuint32 status; 119 //fprintf(stdout, "PrefetchEventCallback: received event %u\n", event); 120 (*caller)->GetPrefetchStatus(caller, &status); 121 if ((PREFETCHEVENT_ERROR_CANDIDATE == (event & PREFETCHEVENT_ERROR_CANDIDATE)) 122 && (level == 0) && (status == SL_PREFETCHSTATUS_UNDERFLOW)) { 123 fprintf(stdout, "PrefetchEventCallback: Error while prefetching data, exiting\n"); 124 prefetchError = true; 125 SignalEos(); 126 } 127} 128 129//----------------------------------------------------------------- 130/* Callback for "playback" events, i.e. event happening during decoding */ 131void DecCallback( 132 SLPlayItf caller, 133 void *pContext, 134 SLuint32 event) 135{ 136 if (SL_PLAYEVENT_HEADATEND & event) { 137 fprintf(stdout, "SL_PLAYEVENT_HEADATEND reached\n"); 138 SignalEos(); 139 } 140 141 if (SL_PLAYEVENT_HEADATNEWPOS & event) { 142 SLmillisecond pMsec = 0; 143 (*caller)->GetPosition(caller, &pMsec); 144 fprintf(stdout, "SL_PLAYEVENT_HEADATNEWPOS current position=%ums\n", pMsec); 145 } 146 147 if (SL_PLAYEVENT_HEADATMARKER & event) { 148 SLmillisecond pMsec = 0; 149 (*caller)->GetPosition(caller, &pMsec); 150 fprintf(stdout, "SL_PLAYEVENT_HEADATMARKER current position=%ums\n", pMsec); 151 } 152} 153 154//----------------------------------------------------------------- 155/* Callback for decoding buffer queue events */ 156void DecBufferQueueCallback( 157 SLAndroidSimpleBufferQueueItf queueItf, 158 void *pContext) 159{ 160 counter++; 161 fprintf(stdout, "DecBufferQueueCallback called (iteration %d) ", counter); 162 163 CallbackCntxt *pCntxt = (CallbackCntxt*)pContext; 164 165 /* Save the decoded data */ 166 if (fwrite(pCntxt->pDataBase, 1, BUFFER_SIZE_IN_BYTES, gFp) < BUFFER_SIZE_IN_BYTES) { 167 fprintf(stdout, "Error writing to output file, signaling EOS\n"); 168 SignalEos(); 169 return; 170 } 171 172 /* Increase data pointer by buffer size */ 173 pCntxt->pData += BUFFER_SIZE_IN_BYTES; 174 175 if (pCntxt->pData >= pCntxt->pDataBase + (NB_BUFFERS_IN_QUEUE * BUFFER_SIZE_IN_BYTES)) { 176 pCntxt->pData = pCntxt->pDataBase; 177 } 178 179 ExitOnError( (*queueItf)->Enqueue(queueItf, pCntxt->pDataBase, BUFFER_SIZE_IN_BYTES) ); 180 // Note: adding a sleep here or any sync point is a way to slow down the decoding, or 181 // synchronize it with some other event, as the OpenSL ES framework will block until the 182 // buffer queue callback return to proceed with the decoding. 183 184#if 0 185 /* Example buffer queue state display */ 186 SLAndroidSimpleBufferQueueState decQueueState; 187 ExitOnError( (*queueItf)->GetState(queueItf, &decQueueState) ); 188 189 fprintf(stderr, "\DecBufferQueueCallback now has pCntxt->pData=%p queue: " 190 "count=%u playIndex=%u\n", 191 pCntxt->pData, decQueueState.count, decQueueState.index); 192#endif 193 194#if 0 195 /* Example of duration display in callback where we use the callback context for the SLPlayItf*/ 196 SLmillisecond durationInMsec = SL_TIME_UNKNOWN; 197 SLresult result = (*pCntxt->playItf)->GetDuration(pCntxt->playItf, &durationInMsec); 198 ExitOnError(result); 199 if (durationInMsec == SL_TIME_UNKNOWN) { 200 fprintf(stdout, "Content duration is unknown (in dec callback)\n"); 201 } else { 202 fprintf(stdout, "Content duration is %ums (in dec callback)\n", 203 durationInMsec); 204 } 205#endif 206} 207 208//----------------------------------------------------------------- 209 210/* Decode an audio path by opening a file descriptor on that path */ 211void TestDecToBuffQueue( SLObjectItf sl, const char* path) 212{ 213 size_t len = strlen((const char *) path); 214 char* outputPath = (char*) malloc(len + 4 + 1); // save room to concatenate ".raw" 215 if (NULL == outputPath) { 216 ExitOnError(SL_RESULT_RESOURCE_ERROR); 217 } 218 memcpy(outputPath, path, len + 1); 219 strcat(outputPath, ".raw"); 220 gFp = fopen(outputPath, "w"); 221 if (NULL == gFp) { 222 ExitOnError(SL_RESULT_RESOURCE_ERROR); 223 } 224 225 SLresult result; 226 SLEngineItf EngineItf; 227 228 /* Objects this application uses: one audio player */ 229 SLObjectItf player; 230 231 /* Interfaces for the audio player */ 232 SLAndroidSimpleBufferQueueItf decBuffQueueItf; 233 SLPrefetchStatusItf prefetchItf; 234 SLPlayItf playItf; 235 SLMetadataExtractionItf mdExtrItf; 236 237 /* Source of audio data for the decoding */ 238 SLDataSource decSource; 239 SLDataLocator_URI decUri; 240 SLDataFormat_MIME decMime; 241 242 /* Data sink for decoded audio */ 243 SLDataSink decDest; 244 SLDataLocator_AndroidSimpleBufferQueue decBuffQueue; 245 SLDataFormat_PCM pcm; 246 247 SLboolean required[NUM_EXPLICIT_INTERFACES_FOR_PLAYER]; 248 SLInterfaceID iidArray[NUM_EXPLICIT_INTERFACES_FOR_PLAYER]; 249 250 /* Get the SL Engine Interface which is implicit */ 251 result = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf); 252 ExitOnError(result); 253 254 /* Initialize arrays required[] and iidArray[] */ 255 for (int i=0 ; i < NUM_EXPLICIT_INTERFACES_FOR_PLAYER ; i++) { 256 required[i] = SL_BOOLEAN_FALSE; 257 iidArray[i] = SL_IID_NULL; 258 } 259 260 261 /* ------------------------------------------------------ */ 262 /* Configuration of the player */ 263 264 /* Request the AndroidSimpleBufferQueue interface */ 265 required[0] = SL_BOOLEAN_TRUE; 266 iidArray[0] = SL_IID_ANDROIDSIMPLEBUFFERQUEUE; 267 /* Request the PrefetchStatus interface */ 268 required[1] = SL_BOOLEAN_TRUE; 269 iidArray[1] = SL_IID_PREFETCHSTATUS; 270 /* Request the PrefetchStatus interface */ 271 required[2] = SL_BOOLEAN_TRUE; 272 iidArray[2] = SL_IID_METADATAEXTRACTION; 273 274 /* Setup the data source */ 275 decUri.locatorType = SL_DATALOCATOR_URI; 276 decUri.URI = (SLchar*)path; 277 decMime.formatType = SL_DATAFORMAT_MIME; 278 /* this is how ignored mime information is specified, according to OpenSL ES spec 279 * in 9.1.6 SLDataFormat_MIME and 8.23 SLMetadataTraversalItf GetChildInfo */ 280 decMime.mimeType = (SLchar*)NULL; 281 decMime.containerType = SL_CONTAINERTYPE_UNSPECIFIED; 282 decSource.pLocator = (void *) &decUri; 283 decSource.pFormat = (void *) &decMime; 284 285 /* Setup the data sink */ 286 decBuffQueue.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; 287 decBuffQueue.numBuffers = NB_BUFFERS_IN_QUEUE; 288 /* set up the format of the data in the buffer queue */ 289 pcm.formatType = SL_DATAFORMAT_PCM; 290 // FIXME valid value required but currently ignored 291 pcm.numChannels = 1; 292 pcm.samplesPerSec = SL_SAMPLINGRATE_8; 293 pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16; 294 pcm.containerSize = 16; 295 pcm.channelMask = SL_SPEAKER_FRONT_LEFT; 296 pcm.endianness = SL_BYTEORDER_LITTLEENDIAN; 297 298 decDest.pLocator = (void *) &decBuffQueue; 299 decDest.pFormat = (void * ) &pcm; 300 301 /* Create the audio player */ 302 result = (*EngineItf)->CreateAudioPlayer(EngineItf, &player, &decSource, &decDest, 303 NUM_EXPLICIT_INTERFACES_FOR_PLAYER, iidArray, required); 304 ExitOnError(result); 305 fprintf(stdout, "Player created\n"); 306 307 /* Realize the player in synchronous mode. */ 308 result = (*player)->Realize(player, SL_BOOLEAN_FALSE); 309 ExitOnError(result); 310 fprintf(stdout, "Player realized\n"); 311 312 /* Get the play interface which is implicit */ 313 result = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf); 314 ExitOnError(result); 315 316 /* Set up the player callback to get events during the decoding */ 317 // FIXME currently ignored 318 result = (*playItf)->SetMarkerPosition(playItf, 2000); 319 ExitOnError(result); 320 result = (*playItf)->SetPositionUpdatePeriod(playItf, 500); 321 ExitOnError(result); 322 result = (*playItf)->SetCallbackEventsMask(playItf, 323 SL_PLAYEVENT_HEADATMARKER | SL_PLAYEVENT_HEADATNEWPOS | SL_PLAYEVENT_HEADATEND); 324 ExitOnError(result); 325 result = (*playItf)->RegisterCallback(playItf, DecCallback, NULL); 326 ExitOnError(result); 327 fprintf(stdout, "Play callback registered\n"); 328 329 /* Get the buffer queue interface which was explicitly requested */ 330 result = (*player)->GetInterface(player, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, 331 (void*)&decBuffQueueItf); 332 ExitOnError(result); 333 334 /* Get the prefetch status interface which was explicitly requested */ 335 result = (*player)->GetInterface(player, SL_IID_PREFETCHSTATUS, (void*)&prefetchItf); 336 ExitOnError(result); 337 338 /* ------------------------------------------------------ */ 339 /* Initialize the callback and its context for the decoding buffer queue */ 340 CallbackCntxt cntxt; 341 cntxt.playItf = playItf; 342 cntxt.pDataBase = (int8_t*)&pcmData; 343 cntxt.pData = cntxt.pDataBase; 344 cntxt.size = sizeof(pcmData); 345 result = (*decBuffQueueItf)->RegisterCallback(decBuffQueueItf, DecBufferQueueCallback, &cntxt); 346 ExitOnError(result); 347 348 /* Enqueue buffers to map the region of memory allocated to store the decoded data */ 349 fprintf(stdout,"Enqueueing buffer "); 350 for(int i = 0 ; i < NB_BUFFERS_IN_QUEUE ; i++) { 351 fprintf(stdout,"%d \n", i); 352 result = (*decBuffQueueItf)->Enqueue(decBuffQueueItf, cntxt.pData, BUFFER_SIZE_IN_BYTES); 353 ExitOnError(result); 354 cntxt.pData += BUFFER_SIZE_IN_BYTES; 355 } 356 fprintf(stdout,"\n"); 357 cntxt.pData = cntxt.pDataBase; 358 359 /* ------------------------------------------------------ */ 360 /* Initialize the callback for prefetch errors, if we can't open the resource to decode */ 361 result = (*prefetchItf)->RegisterCallback(prefetchItf, PrefetchEventCallback, &prefetchItf); 362 ExitOnError(result); 363 result = (*prefetchItf)->SetCallbackEventsMask(prefetchItf, PREFETCHEVENT_ERROR_CANDIDATE); 364 ExitOnError(result); 365 366 /* ------------------------------------------------------ */ 367 /* Prefetch the data so we can get information about the format before starting to decode */ 368 /* 1/ cause the player to prefetch the data */ 369 result = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PAUSED ); 370 ExitOnError(result); 371 /* 2/ block until data has been prefetched */ 372 SLuint32 prefetchStatus = SL_PREFETCHSTATUS_UNDERFLOW; 373 SLuint32 timeOutIndex = 50; // time out prefetching after 5s 374 while ((prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) && (timeOutIndex > 0) && 375 !prefetchError) { 376 usleep(10 * 1000); 377 (*prefetchItf)->GetPrefetchStatus(prefetchItf, &prefetchStatus); 378 timeOutIndex--; 379 } 380 if (timeOutIndex == 0 || prefetchError) { 381 fprintf(stderr, "Failure to prefetch data in time, exiting\n"); 382 ExitOnError(SL_RESULT_CONTENT_NOT_FOUND); 383 } 384 385 /* ------------------------------------------------------ */ 386 /* Display duration */ 387 SLmillisecond durationInMsec = SL_TIME_UNKNOWN; 388 result = (*playItf)->GetDuration(playItf, &durationInMsec); 389 ExitOnError(result); 390 if (durationInMsec == SL_TIME_UNKNOWN) { 391 fprintf(stdout, "Content duration is unknown\n"); 392 } else { 393 fprintf(stdout, "Content duration is %ums\n", durationInMsec); 394 } 395 396 /* ------------------------------------------------------ */ 397 /* Display the metadata obtained from the decoder */ 398 // This is for test / demonstration purposes only where we discover the key and value sizes 399 // of a PCM decoder. An application that would want to directly get access to those values 400 // can make assumptions about the size of the keys and their matching values (all SLuint32) 401 result = (*player)->GetInterface(player, SL_IID_METADATAEXTRACTION, 402 (void*)&mdExtrItf); 403 ExitOnError(result); 404 SLuint32 itemCount; 405 result = (*mdExtrItf)->GetItemCount(mdExtrItf, &itemCount); 406 SLuint32 i, keySize, valueSize; 407 SLMetadataInfo *keyInfo, *value; 408 for(i=0 ; i<itemCount ; i++) { 409 keyInfo = NULL; keySize = 0; 410 value = NULL; valueSize = 0; 411 result = (*mdExtrItf)->GetKeySize(mdExtrItf, i, &keySize); 412 ExitOnError(result); 413 result = (*mdExtrItf)->GetValueSize(mdExtrItf, i, &valueSize); 414 ExitOnError(result); 415 keyInfo = (SLMetadataInfo*) malloc(keySize); 416 value = (SLMetadataInfo*) malloc(valueSize); 417 if ((NULL != keyInfo) && (NULL != value)) { 418 result = (*mdExtrItf)->GetKey(mdExtrItf, i, keySize, keyInfo); 419 ExitOnError(result); 420 result = (*mdExtrItf)->GetValue(mdExtrItf, i, valueSize, value); 421 ExitOnError(result); 422 if ((value->encoding == SL_CHARACTERENCODING_BINARY) 423 && (value->size == sizeof(SLuint32))) { 424 fprintf(stdout, "key[%d] size=%d, name=%s \tvalue size=%d value=%d\n", 425 i, keyInfo->size, keyInfo->data, value->size, *((SLuint32*)value->data)); 426 } 427 free(keyInfo); 428 free(value); 429 } 430 } 431 432 /* ------------------------------------------------------ */ 433 /* Start decoding */ 434 result = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING); 435 ExitOnError(result); 436 fprintf(stdout, "Starting to decode\n"); 437 438 /* Decode until the end of the stream is reached */ 439 { 440 android::Mutex::Autolock autoLock(eosLock); 441 while (!eos) { 442 eosCondition.wait(eosLock); 443 } 444 } 445 fprintf(stdout, "EOS signaled\n"); 446 447 /* ------------------------------------------------------ */ 448 /* End of decoding */ 449 450 /* Stop decoding */ 451 result = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED); 452 ExitOnError(result); 453 fprintf(stdout, "Stopped decoding\n"); 454 455 /* Destroy the AudioPlayer object */ 456 (*player)->Destroy(player); 457 458 //sleep(1); 459 460 fclose(gFp); 461} 462 463//----------------------------------------------------------------- 464int main(int argc, char* const argv[]) 465{ 466 SLresult result; 467 SLObjectItf sl; 468 469 fprintf(stdout, "OpenSL ES test %s: exercises SLPlayItf and SLAndroidSimpleBufferQueueItf ", 470 argv[0]); 471 fprintf(stdout, "on an AudioPlayer object to decode a URI to PCM\n"); 472 473 if (argc != 2) { 474 fprintf(stdout, "Usage: \t%s source_file\n", argv[0]); 475 fprintf(stdout, "Example: \"%s /sdcard/myFile.mp3\n", argv[0]); 476 exit(EXIT_FAILURE); 477 } 478 479 SLEngineOption EngineOption[] = { 480 {(SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE} 481 }; 482 483 result = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL); 484 ExitOnError(result); 485 486 /* Realizing the SL Engine in synchronous mode. */ 487 result = (*sl)->Realize(sl, SL_BOOLEAN_FALSE); 488 ExitOnError(result); 489 490 TestDecToBuffQueue(sl, argv[1]); 491 492 /* Shutdown OpenSL ES */ 493 (*sl)->Destroy(sl); 494 495 return EXIT_SUCCESS; 496} 497