Home | History | Annotate | Download | only in mimeUri
      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 #include <stdlib.h>
     18 #include <stdio.h>
     19 #include <unistd.h>
     20 //#include <sys/time.h>
     21 
     22 #include <SLES/OpenSLES.h>
     23 
     24 
     25 #define MAX_NUMBER_INTERFACES 2
     26 #define MAX_NUMBER_PLAYERS 40
     27 
     28 #define PREFETCHEVENT_ERROR_CANDIDATE \
     29         (SL_PREFETCHEVENT_STATUSCHANGE | SL_PREFETCHEVENT_FILLLEVELCHANGE)
     30 
     31 /* the OpenSL ES engine from which we create all other resources */
     32 SLObjectItf  slEngine;
     33 SLEngineItf  engineItf;
     34 SLObjectItf  outputMix;
     35 
     36 SLboolean     required[MAX_NUMBER_INTERFACES];
     37 SLInterfaceID iidArray[MAX_NUMBER_INTERFACES];
     38 
     39 SLObjectItf  audioPlayer[MAX_NUMBER_PLAYERS];
     40 bool         validplayer[MAX_NUMBER_PLAYERS];
     41 int          playerNum[MAX_NUMBER_PLAYERS];
     42 SLPlayItf    playItfs[MAX_NUMBER_PLAYERS];
     43 SLVolumeItf  volItfs[MAX_NUMBER_PLAYERS];
     44 SLPrefetchStatusItf prefetchItfs[MAX_NUMBER_PLAYERS];
     45 
     46 SLDataSource      audioSource;
     47 SLDataLocator_URI uri;
     48 SLDataFormat_MIME mime;
     49 
     50 SLDataSink              audioSink;
     51 SLDataLocator_OutputMix locator_outputmix;
     52 
     53 
     54 //-----------------------------------------------------------------
     55 //* Exits the application if an error is encountered */
     56 #define CheckErr(x) ExitOnErrorFunc(x, -1, __LINE__)
     57 #define CheckErrPlyr(x, id) ExitOnErrorFunc(x, id, __LINE__)
     58 
     59 void ExitOnErrorFunc( SLresult result, int playerId, int line)
     60 {
     61     if (SL_RESULT_SUCCESS != result) {
     62         if (playerId == -1) {
     63             fprintf(stderr, "Error %u code encountered at line %d, exiting\n", result, line);
     64         } else {
     65             fprintf(stderr, "Error %u code encountered at line %d for player %d, exiting\n",
     66                     result, line, playerId);
     67         }
     68         exit(EXIT_FAILURE);
     69     }
     70 }
     71 
     72 //-----------------------------------------------------------------
     73 /* PrefetchStatusItf callback for an audio player */
     74 void PrefetchEventCallback( SLPrefetchStatusItf caller,  void *pContext, SLuint32 event)
     75 {
     76     SLresult res;
     77     SLpermille level = 0;
     78     int* pPlayerId = (int*)pContext;
     79     res = (*caller)->GetFillLevel(caller, &level); CheckErrPlyr(res, *pPlayerId);
     80     SLuint32 status;
     81     //fprintf(stdout, "PrefetchEventCallback: received event %u\n", event);
     82     res = (*caller)->GetPrefetchStatus(caller, &status); CheckErrPlyr(res, *pPlayerId);
     83     if ((PREFETCHEVENT_ERROR_CANDIDATE == (event & PREFETCHEVENT_ERROR_CANDIDATE))
     84             && (level == 0) && (status == SL_PREFETCHSTATUS_UNDERFLOW)) {
     85         fprintf(stdout, "PrefetchEventCallback: Error while prefetching data for player %d, "
     86                 "exiting\n", *pPlayerId);
     87         exit(EXIT_FAILURE);
     88     }
     89     if (event & SL_PREFETCHEVENT_FILLLEVELCHANGE) {
     90         fprintf(stdout, "PrefetchEventCallback: Buffer fill level is = %d for player %d\n",
     91                 level, *pPlayerId);
     92     }
     93     if (event & SL_PREFETCHEVENT_STATUSCHANGE) {
     94         fprintf(stdout, "PrefetchEventCallback: Prefetch Status is = %u for player %d\n",
     95                 status, *pPlayerId);
     96     }
     97 }
     98 
     99 
    100 //-----------------------------------------------------------------
    101 /* PlayItf callback for playback events */
    102 void PlayEventCallback(
    103         SLPlayItf caller,
    104         void *pContext,
    105         SLuint32 event)
    106 {
    107     SLresult res;
    108     int* pPlayerId = (int*)pContext;
    109     if (SL_PLAYEVENT_HEADATEND & event) {
    110         fprintf(stdout, "SL_PLAYEVENT_HEADATEND reached for player %d\n", *pPlayerId);
    111         //SignalEos();
    112     }
    113 
    114     if (SL_PLAYEVENT_HEADATNEWPOS & event) {
    115         SLmillisecond pMsec = 0;
    116         res = (*caller)->GetPosition(caller, &pMsec); CheckErrPlyr(res, *pPlayerId);
    117         fprintf(stdout, "SL_PLAYEVENT_HEADATNEWPOS current position=%ums for player %d\n",
    118                 pMsec, *pPlayerId);
    119     }
    120 
    121     if (SL_PLAYEVENT_HEADATMARKER & event) {
    122         SLmillisecond pMsec = 0;
    123         res = (*caller)->GetPosition(caller, &pMsec); CheckErrPlyr(res, *pPlayerId);
    124         fprintf(stdout, "SL_PLAYEVENT_HEADATMARKER current position=%ums for player %d\n",
    125                 pMsec, *pPlayerId);
    126     }
    127 }
    128 
    129 
    130 //-----------------------------------------------------------------
    131 void TestSetup(const char* path) {
    132     SLresult                res;
    133 
    134     /* Create the engine */
    135     SLEngineOption EngineOption[] = {
    136             {(SLuint32) SL_ENGINEOPTION_THREADSAFE,
    137                     (SLuint32) SL_BOOLEAN_TRUE}};
    138 
    139     res = slCreateEngine( &slEngine, 1, EngineOption, 0, NULL, NULL);
    140     CheckErr(res);
    141     /* Realizing the SL Engine in synchronous mode. */
    142     res = (*slEngine)->Realize(slEngine, SL_BOOLEAN_FALSE);
    143     CheckErr(res);
    144     /* Get the SL Engine Interface which is implicit */
    145     res = (*slEngine)->GetInterface(slEngine, SL_IID_ENGINE, (void*)&engineItf);
    146     CheckErr(res);
    147 
    148     /* Create Output Mix object to be used by player */
    149     res = (*engineItf)->CreateOutputMix(engineItf, &outputMix, 0,
    150             iidArray, required); CheckErr(res);
    151     /* Realizing the Output Mix object in synchronous mode. */
    152     res = (*outputMix)->Realize(outputMix, SL_BOOLEAN_FALSE);
    153     CheckErr(res);
    154 
    155     /* Setup the data source structure for the URI */
    156     // the syntax below is more future-proof than the individual field initialization
    157     //  with regards to OpenSL ES 1.1 but adds scary compilation warnings
    158     //uri = { SL_DATALOCATOR_URI /*locatorType*/, (SLchar*) path /*URI*/ };
    159     //mime = { /*formatType*/ SL_DATAFORMAT_MIME, /*mimeType*/ (SLchar*)NULL,
    160     //         /*containerType*/ SL_CONTAINERTYPE_UNSPECIFIED };
    161     uri.locatorType = SL_DATALOCATOR_URI;
    162     uri.URI         =  (SLchar*) path;
    163     mime.formatType    = SL_DATAFORMAT_MIME;
    164     mime.mimeType      = (SLchar*)NULL;
    165     mime.containerType = SL_CONTAINERTYPE_UNSPECIFIED;
    166 
    167     audioSource.pFormat      = (void *)&mime;
    168     audioSource.pLocator     = (void *)&uri;
    169 
    170     /* Setup the data sink structure */
    171     locator_outputmix.locatorType   = SL_DATALOCATOR_OUTPUTMIX;
    172     locator_outputmix.outputMix    = outputMix;
    173     audioSink.pLocator           = (void *)&locator_outputmix;
    174     audioSink.pFormat            = NULL;
    175 
    176     /* Initialize arrays required[] and iidArray[] */
    177     for (int i=0 ; i < MAX_NUMBER_INTERFACES ; i++) {
    178         required[i] = SL_BOOLEAN_FALSE;
    179         iidArray[i] = SL_IID_NULL;
    180     }
    181     /* Set arrays required[] and iidArray[] for VOLUME and PREFETCHSTATUS interface */
    182     required[0] = SL_BOOLEAN_TRUE;
    183     iidArray[0] = SL_IID_VOLUME;
    184     required[1] = SL_BOOLEAN_TRUE;
    185     iidArray[1] = SL_IID_PREFETCHSTATUS;
    186 
    187     fprintf(stdout, "TestSetup(%s) completed\n", path);
    188 }
    189 
    190 
    191 //-----------------------------------------------------------------
    192 void TestTeardown() {
    193     /* Destroy Output Mix object */
    194     (*outputMix)->Destroy(outputMix);
    195 
    196     /* Shutdown OpenSL ES */
    197     (*slEngine)->Destroy(slEngine);
    198 }
    199 
    200 
    201 //-----------------------------------------------------------------
    202 /**
    203  * Create a player and, if the creation is successful,
    204  * configure it, and start playing.
    205  */
    206 void CreatePlayer(int playerId) {
    207     SLresult res;
    208     playerNum[playerId] = playerId;
    209 
    210     /* Create the audio player */
    211     res = (*engineItf)->CreateAudioPlayer(engineItf, &audioPlayer[playerId],
    212             &audioSource, &audioSink, MAX_NUMBER_INTERFACES, iidArray, required);
    213     if (SL_RESULT_SUCCESS != res) {
    214             // do not abort the test, just flag the player as not a candidate for destruction
    215             fprintf(stdout, "CreateAudioPlayer for player %d failed\n", playerId);
    216             validplayer[playerId] = false;
    217             return;
    218         }
    219     validplayer[playerId] = true;
    220 
    221     /* Realizing the player in synchronous mode. */
    222     res = (*audioPlayer[playerId])->Realize(audioPlayer[playerId], SL_BOOLEAN_FALSE);
    223     if (SL_RESULT_SUCCESS != res) {
    224         // do not abort the test, just stop the player initialization here
    225         fprintf(stdout, "Realize for player %d failed\n", playerId);
    226         // this player is still a candidate for destruction
    227         return;
    228     }
    229     // after this point, any failure is a test failure
    230 
    231     /* Get interfaces */
    232     res = (*audioPlayer[playerId])->GetInterface(audioPlayer[playerId], SL_IID_PLAY,
    233             (void*)&playItfs[playerId]);
    234     CheckErrPlyr(res, playerId);
    235 
    236     res = (*audioPlayer[playerId])->GetInterface(audioPlayer[playerId], SL_IID_VOLUME,
    237             (void*)&volItfs[playerId]);
    238     CheckErrPlyr(res, playerId);
    239 
    240     res = (*audioPlayer[playerId])->GetInterface(audioPlayer[playerId], SL_IID_PREFETCHSTATUS,
    241             (void*)&prefetchItfs[playerId]);
    242     CheckErrPlyr(res, playerId);
    243     res = (*prefetchItfs[playerId])->RegisterCallback(prefetchItfs[playerId], PrefetchEventCallback,
    244             &playerNum[playerId]);
    245     CheckErrPlyr(res, playerId);
    246     res = (*prefetchItfs[playerId])->SetCallbackEventsMask(prefetchItfs[playerId],
    247             SL_PREFETCHEVENT_FILLLEVELCHANGE | SL_PREFETCHEVENT_STATUSCHANGE);
    248     CheckErrPlyr(res, playerId);
    249 
    250     /* Set the player volume */
    251     res = (*volItfs[playerId])->SetVolumeLevel( volItfs[playerId], -300);
    252     CheckErrPlyr(res, playerId);
    253 
    254     /* Set up the player callback to get events during the decoding */
    255     res = (*playItfs[playerId])->SetMarkerPosition(playItfs[playerId], 2000);
    256     CheckErrPlyr(res, playerId);
    257     res = (*playItfs[playerId])->SetPositionUpdatePeriod(playItfs[playerId], 500);
    258     CheckErrPlyr(res, playerId);
    259     res = (*playItfs[playerId])->SetCallbackEventsMask(playItfs[playerId],
    260             SL_PLAYEVENT_HEADATMARKER | SL_PLAYEVENT_HEADATNEWPOS | SL_PLAYEVENT_HEADATEND);
    261     CheckErrPlyr(res, playerId);
    262     res = (*playItfs[playerId])->RegisterCallback(playItfs[playerId], PlayEventCallback,
    263             &playerNum[playerId]);
    264     CheckErrPlyr(res, playerId);
    265 
    266     /* Configure fill level updates every 5 percent */
    267     (*prefetchItfs[playerId])->SetFillUpdatePeriod(prefetchItfs[playerId], 50);
    268 
    269     /* Play the URI */
    270     /*     first cause the player to prefetch the data */
    271     fprintf(stdout, "Setting player %d  to PAUSED\n", playerId);
    272     res = (*playItfs[playerId])->SetPlayState( playItfs[playerId], SL_PLAYSTATE_PAUSED );
    273     CheckErrPlyr(res, playerId);
    274     /*     wait until there's data to play */
    275     SLuint32 prefetchStatus = SL_PREFETCHSTATUS_UNDERFLOW;
    276     SLuint32 timeOutIndex = 10; // 1s, should be enough for a local file
    277     while ((prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) && (timeOutIndex > 0)) {
    278         usleep(100 * 1000);
    279         res = (*prefetchItfs[playerId])->GetPrefetchStatus(prefetchItfs[playerId], &prefetchStatus);
    280         CheckErrPlyr(res, playerId);
    281         timeOutIndex--;
    282     }
    283 
    284     if (timeOutIndex == 0) {
    285         fprintf(stderr, "Prefetch timed out for player %d\n", playerId);
    286         return;
    287     }
    288     res = (*playItfs[playerId])->SetPlayState( playItfs[playerId], SL_PLAYSTATE_PLAYING );
    289     CheckErrPlyr(res, playerId);
    290 
    291     /* Display duration */
    292     SLmillisecond durationInMsec = SL_TIME_UNKNOWN;
    293     res = (*playItfs[playerId])->GetDuration(playItfs[playerId], &durationInMsec);
    294     CheckErrPlyr(res, playerId);
    295     if (durationInMsec == SL_TIME_UNKNOWN) {
    296         fprintf(stdout, "Content duration is unknown for player %d\n", playerId);
    297     } else {
    298         fprintf(stdout, "Content duration is %u ms for player %d\n", durationInMsec, playerId);
    299     }
    300 }
    301 
    302 //-----------------------------------------------------------------
    303 void DestroyPlayer(int playerId) {
    304     fprintf(stdout, "About to destroy player %d\n", playerId);
    305     /* Destroy the player */
    306     (*audioPlayer[playerId])->Destroy(audioPlayer[playerId]);
    307 }
    308 
    309 
    310 //-----------------------------------------------------------------
    311 int main(int argc, char* const argv[])
    312 {
    313     fprintf(stdout, "OpenSL ES test %s: creates and destroys as many ", argv[0]);
    314     fprintf(stdout, "AudioPlayer objects as possible (max=%d)\n\n", MAX_NUMBER_PLAYERS);
    315 
    316     if (argc == 1) {
    317         fprintf(stdout, "Usage: %s path \n\t%s url\n", argv[0], argv[0]);
    318         fprintf(stdout, "Example: \"%s /sdcard/my.mp3\"  or \"%s file:///sdcard/my.mp3\"\n",
    319                 argv[0], argv[0]);
    320         exit(EXIT_FAILURE);
    321     }
    322 
    323     TestSetup(argv[1]);
    324 
    325     for (int i=0 ; i<MAX_NUMBER_PLAYERS ; i++) {
    326         CreatePlayer(i);
    327     }
    328     fprintf(stdout, "After creating %d AudioPlayers\n", MAX_NUMBER_PLAYERS);
    329 
    330     /* Wait for an arbitrary amount of time. if playing a long file, the players will still
    331        be playing while the destructions start. */
    332     usleep(10*1000*1000); // 10s
    333 
    334     for (int i=0 ; i<MAX_NUMBER_PLAYERS ; i++) {
    335         if (validplayer[i]) {
    336             DestroyPlayer(i);
    337         }
    338     }
    339     fprintf(stdout, "After destroying valid players among %d AudioPlayers\n", MAX_NUMBER_PLAYERS);
    340 
    341     TestTeardown();
    342 
    343     return EXIT_SUCCESS;
    344 }
    345