slesTestDecodeToBuffQueue.cpp revision 1fd0cd18598d76e9a0f9e6675e4d988be41644f7
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 */ 52#define NUM_EXPLICIT_INTERFACES_FOR_PLAYER 2 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/* to signal to the test app the end of the stream to decode has been reached */ 70bool eos = false; 71android::Mutex eosLock; 72android::Condition eosCondition; 73 74/* used to detect errors likely to have occured when the OpenSL ES framework fails to open 75 * a resource, for instance because a file URI is invalid, or an HTTP server doesn't respond. 76 */ 77#define PREFETCHEVENT_ERROR_CANDIDATE \ 78 (SL_PREFETCHEVENT_STATUSCHANGE | SL_PREFETCHEVENT_FILLLEVELCHANGE) 79 80//----------------------------------------------------------------- 81/* Exits the application if an error is encountered */ 82#define ExitOnError(x) ExitOnErrorFunc(x,__LINE__) 83 84void ExitOnErrorFunc( SLresult result , int line) 85{ 86 if (SL_RESULT_SUCCESS != result) { 87 fprintf(stdout, "%lu error code encountered at line %d, exiting\n", result, line); 88 exit(EXIT_FAILURE); 89 } 90} 91 92//----------------------------------------------------------------- 93/* Structure for passing information to callback function */ 94typedef struct CallbackCntxt_ { 95 SLPlayItf playItf; 96 SLuint32 size; 97 SLint8* pDataBase; // Base address of local audio data storage 98 SLint8* pData; // Current address of local audio data storage 99} CallbackCntxt; 100 101//----------------------------------------------------------------- 102void SignalEos() { 103 android::Mutex::Autolock autoLock(eosLock); 104 eos = true; 105 eosCondition.signal(); 106} 107 108//----------------------------------------------------------------- 109/* Callback for "prefetch" events, here used to detect audio resource opening errors */ 110void PrefetchEventCallback( SLPrefetchStatusItf caller, void *pContext, SLuint32 event) 111{ 112 SLpermille level = 0; 113 (*caller)->GetFillLevel(caller, &level); 114 SLuint32 status; 115 //fprintf(stdout, "PrefetchEventCallback: received event %lu\n", event); 116 (*caller)->GetPrefetchStatus(caller, &status); 117 if ((PREFETCHEVENT_ERROR_CANDIDATE == (event & PREFETCHEVENT_ERROR_CANDIDATE)) 118 && (level == 0) && (status == SL_PREFETCHSTATUS_UNDERFLOW)) { 119 fprintf(stdout, "PrefetchEventCallback: Error while prefetching data, exiting\n"); 120 SignalEos(); 121 } 122} 123 124//----------------------------------------------------------------- 125/* Callback for "playback" events, i.e. event happening during decoding */ 126void DecCallback( 127 SLPlayItf caller, 128 void *pContext, 129 SLuint32 event) 130{ 131 if (SL_PLAYEVENT_HEADATEND & event) { 132 fprintf(stdout, "SL_PLAYEVENT_HEADATEND reached\n"); 133 SignalEos(); 134 } 135 136 if (SL_PLAYEVENT_HEADATNEWPOS & event) { 137 SLmillisecond pMsec = 0; 138 (*caller)->GetPosition(caller, &pMsec); 139 fprintf(stdout, "SL_PLAYEVENT_HEADATNEWPOS current position=%lums\n", pMsec); 140 } 141 142 if (SL_PLAYEVENT_HEADATMARKER & event) { 143 SLmillisecond pMsec = 0; 144 (*caller)->GetPosition(caller, &pMsec); 145 fprintf(stdout, "SL_PLAYEVENT_HEADATMARKER current position=%lums\n", pMsec); 146 } 147} 148 149//----------------------------------------------------------------- 150/* Callback for decoding buffer queue events */ 151void DecBufferQueueCallback( 152 SLAndroidSimpleBufferQueueItf queueItf, 153 void *pContext) 154{ 155 counter++; 156 fprintf(stdout, "DecBufferQueueCallback called (iteration %d)\n", counter); 157 158 CallbackCntxt *pCntxt = (CallbackCntxt*)pContext; 159 160 /* Save the decoded data */ 161 if (fwrite(pCntxt->pDataBase, 1, BUFFER_SIZE_IN_BYTES, gFp) < BUFFER_SIZE_IN_BYTES) { 162 fprintf(stdout, "Error writing to output file, signaling EOS\n"); 163 SignalEos(); 164 return; 165 } 166 167 /* Increase data pointer by buffer size */ 168 pCntxt->pData += BUFFER_SIZE_IN_BYTES; 169 170 if (pCntxt->pData >= pCntxt->pDataBase + (NB_BUFFERS_IN_QUEUE * BUFFER_SIZE_IN_BYTES)) { 171 pCntxt->pData = pCntxt->pDataBase; 172 } 173 174 ExitOnError( (*queueItf)->Enqueue(queueItf, pCntxt->pDataBase, BUFFER_SIZE_IN_BYTES) ); 175 // Note: adding a sleep here or any sync point is a way to slow down the decoding, or 176 // synchronize it with some other event, as the OpenSL ES framework will block until the 177 // buffer queue callback return to proceed with the decoding. 178 179/* 180 SLAndroidSimpleBufferQueueState decQueueState; 181 ExitOnError( (*queueItf)->GetState(queueItf, &decQueueState) ); 182 183 fprintf(stderr, "\DecBufferQueueCallback now has pCntxt->pData=%p queue: " 184 "count=%lu playIndex=%lu\n", 185 pCntxt->pData, decQueueState.count, decQueueState.index); 186*/ 187} 188 189//----------------------------------------------------------------- 190 191/* Decode an audio path by opening a file descriptor on that path */ 192void TestDecToBuffQueue( SLObjectItf sl, const char* path) 193{ 194 size_t len = strlen((const char *) path); 195 char* outputPath = (char*) malloc(len + 4 + 1); // save room to concatenate ".raw" 196 if (NULL == outputPath) { 197 ExitOnError(SL_RESULT_RESOURCE_ERROR); 198 } 199 memcpy(outputPath, path, len + 1); 200 strcat(outputPath, ".raw"); 201 gFp = fopen(outputPath, "w"); 202 if (NULL == gFp) { 203 ExitOnError(SL_RESULT_RESOURCE_ERROR); 204 } 205 206 SLresult result; 207 SLEngineItf EngineItf; 208 209 /* Objects this application uses: one audio player */ 210 SLObjectItf player; 211 212 /* Interfaces for the audio player */ 213 SLAndroidSimpleBufferQueueItf decBuffQueueItf; 214 SLPrefetchStatusItf prefetchItf; 215 SLPlayItf playItf; 216 217 /* Source of audio data for the decoding */ 218 SLDataSource decSource; 219 SLDataLocator_URI decUri; 220 SLDataFormat_MIME decMime; 221 222 /* Data sink for decoded audio */ 223 SLDataSink decDest; 224 SLDataLocator_AndroidSimpleBufferQueue decBuffQueue; 225 SLDataFormat_PCM pcm; 226 227 SLboolean required[NUM_EXPLICIT_INTERFACES_FOR_PLAYER]; 228 SLInterfaceID iidArray[NUM_EXPLICIT_INTERFACES_FOR_PLAYER]; 229 230 /* Get the SL Engine Interface which is implicit */ 231 result = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf); 232 ExitOnError(result); 233 234 /* Initialize arrays required[] and iidArray[] */ 235 for (int i=0 ; i < NUM_EXPLICIT_INTERFACES_FOR_PLAYER ; i++) { 236 required[i] = SL_BOOLEAN_FALSE; 237 iidArray[i] = SL_IID_NULL; 238 } 239 240 241 /* ------------------------------------------------------ */ 242 /* Configuration of the player */ 243 244 /* Request the AndroidSimpleBufferQueue interface */ 245 required[0] = SL_BOOLEAN_TRUE; 246 iidArray[0] = SL_IID_ANDROIDSIMPLEBUFFERQUEUE; 247 /* Request the PrefetchStatus interface */ 248 required[1] = SL_BOOLEAN_TRUE; 249 iidArray[1] = SL_IID_PREFETCHSTATUS; 250 251 /* Setup the data source */ 252 decUri.locatorType = SL_DATALOCATOR_URI; 253 decUri.URI = (SLchar*)path; 254 decMime.formatType = SL_DATAFORMAT_MIME; 255 /* this is how ignored mime information is specified, according to OpenSL ES spec 256 * in 9.1.6 SLDataFormat_MIME and 8.23 SLMetadataTraversalItf GetChildInfo */ 257 decMime.mimeType = (SLchar*)NULL; 258 decMime.containerType = SL_CONTAINERTYPE_UNSPECIFIED; 259 decSource.pLocator = (void *) &decUri; 260 decSource.pFormat = (void *) &decMime; 261 262 /* Setup the data sink */ 263 decBuffQueue.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; 264 decBuffQueue.numBuffers = NB_BUFFERS_IN_QUEUE; 265 /* set up the format of the data in the buffer queue */ 266 pcm.formatType = SL_DATAFORMAT_PCM; 267 // FIXME valid value required but currently ignored 268 pcm.numChannels = 1; 269 pcm.samplesPerSec = SL_SAMPLINGRATE_44_1; 270 pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16; 271 pcm.containerSize = 16; 272 pcm.channelMask = SL_SPEAKER_FRONT_LEFT; 273 pcm.endianness = SL_BYTEORDER_LITTLEENDIAN; 274 275 decDest.pLocator = (void *) &decBuffQueue; 276 decDest.pFormat = (void * ) &pcm; 277 278 /* Create the audio player */ 279 result = (*EngineItf)->CreateAudioPlayer(EngineItf, &player, &decSource, &decDest, 280 NUM_EXPLICIT_INTERFACES_FOR_PLAYER, iidArray, required); 281 ExitOnError(result); 282 fprintf(stdout, "Player created\n"); 283 284 /* Realize the player in synchronous mode. */ 285 result = (*player)->Realize(player, SL_BOOLEAN_FALSE); 286 ExitOnError(result); 287 fprintf(stdout, "Player realized\n"); 288 289 /* Get the play interface which is implicit */ 290 result = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf); 291 ExitOnError(result); 292 293 /* Set up the player callback to get events during the decoding */ 294 // FIXME currently ignored 295 result = (*playItf)->SetMarkerPosition(playItf, 2000); 296 ExitOnError(result); 297 result = (*playItf)->SetPositionUpdatePeriod(playItf, 500); 298 ExitOnError(result); 299 result = (*playItf)->SetCallbackEventsMask(playItf, 300 SL_PLAYEVENT_HEADATMARKER | SL_PLAYEVENT_HEADATNEWPOS | SL_PLAYEVENT_HEADATEND); 301 ExitOnError(result); 302 result = (*playItf)->RegisterCallback(playItf, DecCallback, NULL); 303 ExitOnError(result); 304 fprintf(stdout, "Play callback registered\n"); 305 306 /* Get the buffer queue interface which was explicitly requested */ 307 result = (*player)->GetInterface(player, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, 308 (void*)&decBuffQueueItf); 309 ExitOnError(result); 310 311 /* Get the prefetch status interface which was explicitly requested */ 312 result = (*player)->GetInterface(player, SL_IID_PREFETCHSTATUS, (void*)&prefetchItf); 313 ExitOnError(result); 314 315 /* ------------------------------------------------------ */ 316 /* Initialize the callback and its context for the decoding buffer queue */ 317 CallbackCntxt cntxt; 318 cntxt.playItf = playItf; 319 cntxt.pDataBase = (int8_t*)&pcmData; 320 cntxt.pData = cntxt.pDataBase; 321 cntxt.size = sizeof(pcmData); 322 result = (*decBuffQueueItf)->RegisterCallback(decBuffQueueItf, DecBufferQueueCallback, &cntxt); 323 ExitOnError(result); 324 325 /* Enqueue buffers to map the region of memory allocated to store the decoded data */ 326 fprintf(stdout,"Enqueueing buffer "); 327 for(int i = 0 ; i < NB_BUFFERS_IN_QUEUE ; i++) { 328 fprintf(stdout,"%d \n", i); 329 result = (*decBuffQueueItf)->Enqueue(decBuffQueueItf, cntxt.pData, BUFFER_SIZE_IN_BYTES); 330 ExitOnError(result); 331 cntxt.pData += BUFFER_SIZE_IN_BYTES; 332 } 333 fprintf(stdout,"\n"); 334 cntxt.pData = cntxt.pDataBase; 335 336 /* ------------------------------------------------------ */ 337 /* Initialize the callback for prefetch errors, if we can't open the resource to decode */ 338 result = (*prefetchItf)->RegisterCallback(prefetchItf, PrefetchEventCallback, &prefetchItf); 339 ExitOnError(result); 340 result = (*prefetchItf)->SetCallbackEventsMask(prefetchItf, PREFETCHEVENT_ERROR_CANDIDATE); 341 ExitOnError(result); 342 343 /* ------------------------------------------------------ */ 344 /* Start decoding */ 345 result = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING); 346 ExitOnError(result); 347 fprintf(stdout, "Starting to decode\n"); 348 349 /* Decode until the end of the stream is reached */ 350 { 351 android::Mutex::Autolock autoLock(eosLock); 352 while (!eos) { 353 eosCondition.wait(eosLock); 354 } 355 } 356 fprintf(stdout, "EOS signaled\n"); 357 358 /* ------------------------------------------------------ */ 359 /* End of decoding */ 360 361 /* Stop decoding */ 362 result = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED); 363 ExitOnError(result); 364 fprintf(stdout, "Stopped decoding\n"); 365 366 /* Destroy the AudioPlayer object */ 367 (*player)->Destroy(player); 368 369 fclose(gFp); 370} 371 372//----------------------------------------------------------------- 373int main(int argc, char* const argv[]) 374{ 375 SLresult result; 376 SLObjectItf sl; 377 378 fprintf(stdout, "OpenSL ES test %s: exercises SLPlayItf and SLAndroidSimpleBufferQueueItf ", 379 argv[0]); 380 fprintf(stdout, "on an AudioPlayer object to decode a URI to PCM\n"); 381 382 if (argc != 2) { 383 fprintf(stdout, "Usage: \t%s source_file\n", argv[0]); 384 fprintf(stdout, "Example: \"%s /sdcard/myFile.mp3\n", argv[0]); 385 exit(EXIT_FAILURE); 386 } 387 388 SLEngineOption EngineOption[] = { 389 {(SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE} 390 }; 391 392 result = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL); 393 ExitOnError(result); 394 395 /* Realizing the SL Engine in synchronous mode. */ 396 result = (*sl)->Realize(sl, SL_BOOLEAN_FALSE); 397 ExitOnError(result); 398 399 TestDecToBuffQueue(sl, argv[1]); 400 401 /* Shutdown OpenSL ES */ 402 (*sl)->Destroy(sl); 403 404 return EXIT_SUCCESS; 405} 406