slesTestPlayStream.cpp revision e7bfcdc183454ec959ff51342f0973cabba219b2
1/* 2 * Copyright (C) 2010 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 18#include <stdlib.h> 19#include <stdio.h> 20//#include <string.h> 21#include <unistd.h> 22//#include <sys/time.h> 23 24#include "SLES/OpenSLES.h" 25#include "SLES/OpenSLES_Android.h" 26 27 28#define MAX_NUMBER_INTERFACES 2 29 30#define PREFETCHEVENT_ERROR_CANDIDATE \ 31 (SL_PREFETCHEVENT_STATUSCHANGE | SL_PREFETCHEVENT_FILLLEVELCHANGE) 32 33#define NB_BUFFERS 16 34#define MPEG2_TS_BLOCK_SIZE 188 35#define BUFFER_SIZE 20*MPEG2_TS_BLOCK_SIZE 36 37/* Where we store the data to play */ 38char dataCache[BUFFER_SIZE * NB_BUFFERS]; 39/* From where we read the data to play */ 40FILE *file; 41/* Has the app reached the end of the file */ 42bool reachedEof = false; 43 44//----------------------------------------------------------------- 45//* Exits the application if an error is encountered */ 46#define CheckErr(x) ExitOnErrorFunc(x,__LINE__) 47 48void ExitOnErrorFunc( SLresult result , int line) 49{ 50 if (SL_RESULT_SUCCESS != result) { 51 fprintf(stderr, "%lu error code encountered at line %d, exiting\n", result, line); 52 exit(EXIT_FAILURE); 53 } 54} 55 56bool prefetchError = false; 57 58//----------------------------------------------------------------- 59/* AndroidBufferQueueItf callback for an audio player */ 60SLresult AndroidBufferQueueCallback( 61 SLAndroidBufferQueueItf caller, 62 void *pContext, /* input */ 63 const void *pBufferData, /* input */ 64 SLuint32 dataSize, /* input */ 65 SLuint32 dataUsed, /* input */ 66 const SLAndroidBufferItem *pItems,/* input */ 67 SLuint32 itemsLength /* input */) 68{ 69 // assert(BUFFER_SIZE <= dataSize); 70 71 //-------------------------------------------------------------------------------- 72 // this section is for testing only, this is NOT an example of how to use the API 73 // to play a .ts file, but rather shows more ways to exercise the API 74 //-------------------------------------------------------------------------------- 75 SLAndroidBufferQueueState state; 76 (*caller)->GetState(caller, &state); 77 fprintf(stdout, "ABQ state count=%lu, index=%lu\n", state.count, state.index); 78 79 // just to test, clear the queue to see what happens 80 if (state.index == 500) { 81 (*caller)->Clear(caller); 82 // we've cleared the queue, and have introduced a discontinuity, so signal it 83 SLAndroidBufferItem msgDiscontinuity; 84 msgDiscontinuity.itemKey = SL_ANDROID_ITEMKEY_DISCONTINUITY; 85 msgDiscontinuity.itemSize = 0; 86 // message has no parameters, so the total size of the message is the size of the key 87 // plus the size if itemSize, both SLuint32 88 (*caller)->Enqueue(caller, NULL /*pData*/, 0 /*dataLength*/, 89 &msgDiscontinuity /*pMsg*/, 90 sizeof(SLuint32)*2 /*msgLength*/); 91 92 // we've cleared the queue, it's now empty: let's rebuffer a bit so playback doesn't starve 93 size_t nbRead = fread((void*)pBufferData, 1, BUFFER_SIZE*(NB_BUFFERS/2), file); 94 if (nbRead == BUFFER_SIZE*(NB_BUFFERS/2)) { 95 for (int i=0 ; i < NB_BUFFERS/2 ; i++) { 96 SLresult res = (*caller)->Enqueue(caller, dataCache + i*BUFFER_SIZE, 97 BUFFER_SIZE, NULL, 0); 98 CheckErr(res); 99 } 100 } 101 return SL_RESULT_SUCCESS; 102 } 103 //-------------------------------------------------------------------------------- 104 // end of test only section 105 //-------------------------------------------------------------------------------- 106 else { 107 108 // pBufferData can be null if the last consumed buffer contained only a command 109 // just like we do for signalling DISCONTINUITY (above) or EOS (below) 110 if (pBufferData != NULL) { 111 size_t nbRead = fread((void*)pBufferData, 1, BUFFER_SIZE, file); 112 if (nbRead > 0) { 113 (*caller)->Enqueue(caller, 114 pBufferData /*pData*/, 115 nbRead /*dataLength*/, 116 NULL /*pMsg*/, 117 0 /*msgLength*/); 118 } else if (!reachedEof) { 119 // signal EOS 120 SLAndroidBufferItem msgEos; 121 msgEos.itemKey = SL_ANDROID_ITEMKEY_EOS; 122 msgEos.itemSize = 0; 123 // EOS message has no parameters, so the total size of the message is the size of the key 124 // plus the size if itemSize, both SLuint32 125 (*caller)->Enqueue(caller, NULL /*pData*/, 0 /*dataLength*/, 126 &msgEos /*pMsg*/, 127 sizeof(SLuint32)*2 /*msgLength*/); 128 reachedEof = true; 129 } 130 } 131 132 return SL_RESULT_SUCCESS; 133 } 134} 135 136 137//----------------------------------------------------------------- 138 139/* Play some music from a URI */ 140void TestPlayStream( SLObjectItf sl, const char* path) 141{ 142 SLEngineItf EngineItf; 143 144 SLint32 numOutputs = 0; 145 SLuint32 deviceID = 0; 146 147 SLresult res; 148 149 SLDataSource audioSource; 150 SLDataLocator_AndroidBufferQueue streamLocator; 151 SLDataFormat_MIME mime; 152 153 SLDataSink audioSink; 154 SLDataLocator_OutputMix locator_outputmix; 155 156 SLObjectItf player; 157 SLPlayItf playItf; 158 SLVolumeItf volItf; 159 SLAndroidBufferQueueItf abqItf; 160 161 SLObjectItf OutputMix; 162 163 SLboolean required[MAX_NUMBER_INTERFACES]; 164 SLInterfaceID iidArray[MAX_NUMBER_INTERFACES]; 165 166 int playTimeInSec = 60; 167 168 file = fopen(path, "rb"); 169 170 /* Get the SL Engine Interface which is implicit */ 171 res = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf); 172 CheckErr(res); 173 174 /* Initialize arrays required[] and iidArray[] */ 175 for (int i=0 ; i < MAX_NUMBER_INTERFACES ; i++) { 176 required[i] = SL_BOOLEAN_FALSE; 177 iidArray[i] = SL_IID_NULL; 178 } 179 180 // Set arrays required[] and iidArray[] for VOLUME and PREFETCHSTATUS interface 181 required[0] = SL_BOOLEAN_TRUE; 182 iidArray[0] = SL_IID_VOLUME; 183 required[1] = SL_BOOLEAN_TRUE; 184 iidArray[1] = SL_IID_ANDROIDBUFFERQUEUE; 185 // Create Output Mix object to be used by player 186 res = (*EngineItf)->CreateOutputMix(EngineItf, &OutputMix, 0, 187 iidArray, required); CheckErr(res); 188 189 // Realizing the Output Mix object in synchronous mode. 190 res = (*OutputMix)->Realize(OutputMix, SL_BOOLEAN_FALSE); 191 CheckErr(res); 192 193 /* Setup the data source structure for the URI */ 194 streamLocator.locatorType = SL_DATALOCATOR_ANDROIDBUFFERQUEUE; 195 streamLocator.numBuffers = NB_BUFFERS; 196 mime.formatType = SL_DATAFORMAT_MIME; 197 mime.mimeType = (SLchar *) "video/mp2ts";//(SLchar*)NULL; 198 mime.containerType = SL_CONTAINERTYPE_MPEG_TS; 199 200 audioSource.pFormat = (void *)&mime; 201 audioSource.pLocator = (void *)&streamLocator; 202 203 /* Setup the data sink structure */ 204 locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; 205 locator_outputmix.outputMix = OutputMix; 206 audioSink.pLocator = (void *)&locator_outputmix; 207 audioSink.pFormat = NULL; 208 209 /* Create the audio player */ 210 res = (*EngineItf)->CreateAudioPlayer(EngineItf, &player, &audioSource, &audioSink, 211 MAX_NUMBER_INTERFACES, iidArray, required); CheckErr(res); 212 213 /* Realizing the player in synchronous mode. */ 214 res = (*player)->Realize(player, SL_BOOLEAN_FALSE); CheckErr(res); 215 fprintf(stdout, "URI example: after Realize\n"); 216 217 /* Get interfaces */ 218 res = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf); CheckErr(res); 219 220 res = (*player)->GetInterface(player, SL_IID_VOLUME, (void*)&volItf); CheckErr(res); 221 222 res = (*player)->GetInterface(player, SL_IID_ANDROIDBUFFERQUEUE, (void*)&abqItf); 223 CheckErr(res); 224 225 res = (*abqItf)->RegisterCallback(abqItf, AndroidBufferQueueCallback, 226 // context is not used in the example, but can be used to track who registered 227 // the buffer queue callback 228 NULL /*pContext*/); CheckErr(res); 229 230 /* Display duration */ 231 SLmillisecond durationInMsec = SL_TIME_UNKNOWN; 232 res = (*playItf)->GetDuration(playItf, &durationInMsec); 233 CheckErr(res); 234 if (durationInMsec == SL_TIME_UNKNOWN) { 235 fprintf(stdout, "Content duration is unknown (before starting to prefetch)\n"); 236 } else { 237 fprintf(stdout, "Content duration is %lu ms (before starting to prefetch)\n", 238 durationInMsec); 239 } 240 241 /* Set the player volume */ 242 res = (*volItf)->SetVolumeLevel( volItf, 0);//-300); 243 CheckErr(res); 244 245 246 /* Play the URI */ 247 /* first cause the player to prefetch the data */ 248 fprintf(stdout, "Before set to PAUSED\n"); 249 res = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PAUSED ); 250 fprintf(stdout, "After set to PAUSED\n"); 251 CheckErr(res); 252 253 /* Fill our cache */ 254 if (fread(dataCache, 1, BUFFER_SIZE * NB_BUFFERS, file) <= 0) { 255 fprintf(stderr, "Error filling cache, exiting\n"); 256 goto destroyRes; 257 } 258 /* Enqueue the content of our cache before starting to play, 259 * we don't want to starve the player */ 260 for (int i=0 ; i < NB_BUFFERS ; i++) { 261 res = (*abqItf)->Enqueue(abqItf, dataCache + i*BUFFER_SIZE, BUFFER_SIZE, NULL, 0); 262 CheckErr(res); 263 } 264 265#if 0 // used to test ABQ starving where only one buffer is enqueued before playback 266 /* Fill our cache */ 267 if (fread(dataCache, 1, BUFFER_SIZE * 1, file) <= 0) { 268 fprintf(stderr, "Error filling cache, exiting\n"); 269 goto destroyRes; 270 } 271 /* Enqueue the content of our cache before starting to play, 272 * we don't want to starve the player */ 273 for (int i=0 ; i < 1 ; i++) { 274 res = (*abqItf)->Enqueue(abqItf, dataCache + i*BUFFER_SIZE, BUFFER_SIZE, NULL, 0); 275 CheckErr(res); 276 } 277#endif 278 /* wait until there's data to play */ 279 //SLpermille fillLevel = 0; 280 /* 281 SLuint32 prefetchStatus = SL_PREFETCHSTATUS_UNDERFLOW; 282 SLuint32 timeOutIndex = 2; 283 while ((prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) && (timeOutIndex > 0) && 284 !prefetchError) { 285 usleep(1 * 1000 * 1000); // 1s 286 //(*prefetchItf)->GetPrefetchStatus(prefetchItf, &prefetchStatus); 287 timeOutIndex--; 288 } 289 290 if (timeOutIndex == 0 || prefetchError) { 291 fprintf(stderr, "We\'re done waiting, failed to prefetch data in time, exiting\n"); 292 goto destroyRes; 293 } 294*/ 295 296 /* Display duration again, */ 297/* res = (*playItf)->GetDuration(playItf, &durationInMsec); 298 CheckErr(res); 299 if (durationInMsec == SL_TIME_UNKNOWN) { 300 fprintf(stdout, "Content duration is unknown (after prefetch completed)\n"); 301 } else { 302 fprintf(stdout, "Content duration is %lu ms (after prefetch completed)\n", durationInMsec); 303 } 304*/ 305 306 fprintf(stdout, "URI example: starting to play\n"); 307 res = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PLAYING ); 308 CheckErr(res); 309 310 /* Wait as long as the duration of the content before stopping */ 311 fprintf(stdout, "Letting playback go on for %d sec\n", playTimeInSec); 312 usleep(playTimeInSec /*s*/ * 1000 * 1000); 313 314 315 /* Make sure player is stopped */ 316 fprintf(stdout, "URI example: stopping playback\n"); 317 res = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED); 318 CheckErr(res); 319 320 fprintf(stdout, "sleeping to verify playback stopped\n"); 321 usleep(2 /*s*/ * 1000 * 1000); 322 323destroyRes: 324 325 /* Destroy the player */ 326 (*player)->Destroy(player); 327 328 /* Destroy Output Mix object */ 329 (*OutputMix)->Destroy(OutputMix); 330 331 fclose(file); 332} 333 334//----------------------------------------------------------------- 335int main(int argc, char* const argv[]) 336{ 337 SLresult res; 338 SLObjectItf sl; 339 340 fprintf(stdout, "OpenSL ES test %s: exercises SLPlayItf, SLVolumeItf, SLAndroidBufferQueue \n", 341 argv[0]); 342 fprintf(stdout, "and AudioPlayer with SL_DATALOCATOR_ANDROIDBUFFERQUEUE source / OutputMix sink\n"); 343 fprintf(stdout, "Plays a sound and stops after its reported duration\n\n"); 344 345 if (argc == 1) { 346 fprintf(stdout, "Usage: %s path \n\t%s url\n", argv[0], argv[0]); 347 fprintf(stdout, "Example: \"%s /sdcard/my.mp3\" or \"%s file:///sdcard/my.mp3\"\n", 348 argv[0], argv[0]); 349 exit(EXIT_FAILURE); 350 } 351 352 SLEngineOption EngineOption[] = { 353 {(SLuint32) SL_ENGINEOPTION_THREADSAFE, 354 (SLuint32) SL_BOOLEAN_TRUE}}; 355 356 res = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL); 357 CheckErr(res); 358 /* Realizing the SL Engine in synchronous mode. */ 359 res = (*sl)->Realize(sl, SL_BOOLEAN_FALSE); 360 CheckErr(res); 361 362 TestPlayStream(sl, argv[1]); 363 364 /* Shutdown OpenSL ES */ 365 (*sl)->Destroy(sl); 366 367 return EXIT_SUCCESS; 368} 369