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     SLint32                 numOutputs = 0;
    133     SLuint32                deviceID = 0;
    134     SLresult                res;
    135 
    136     /* Create the engine */
    137     SLEngineOption EngineOption[] = {
    138             {(SLuint32) SL_ENGINEOPTION_THREADSAFE,
    139                     (SLuint32) SL_BOOLEAN_TRUE}};
    140 
    141     res = slCreateEngine( &slEngine, 1, EngineOption, 0, NULL, NULL);
    142     CheckErr(res);
    143     /* Realizing the SL Engine in synchronous mode. */
    144     res = (*slEngine)->Realize(slEngine, SL_BOOLEAN_FALSE);
    145     CheckErr(res);
    146     /* Get the SL Engine Interface which is implicit */
    147     res = (*slEngine)->GetInterface(slEngine, SL_IID_ENGINE, (void*)&engineItf);
    148     CheckErr(res);
    149 
    150     /* Create Output Mix object to be used by player */
    151     res = (*engineItf)->CreateOutputMix(engineItf, &outputMix, 0,
    152             iidArray, required); CheckErr(res);
    153     /* Realizing the Output Mix object in synchronous mode. */
    154     res = (*outputMix)->Realize(outputMix, SL_BOOLEAN_FALSE);
    155     CheckErr(res);
    156 
    157     /* Setup the data source structure for the URI */
    158     // the syntax below is more future-proof than the individual field initialization
    159     //  with regards to OpenSL ES 1.1 but adds scary compilation warnings
    160     //uri = { SL_DATALOCATOR_URI /*locatorType*/, (SLchar*) path /*URI*/ };
    161     //mime = { /*formatType*/ SL_DATAFORMAT_MIME, /*mimeType*/ (SLchar*)NULL,
    162     //         /*containerType*/ SL_CONTAINERTYPE_UNSPECIFIED };
    163     uri.locatorType = SL_DATALOCATOR_URI;
    164     uri.URI         =  (SLchar*) path;
    165     mime.formatType    = SL_DATAFORMAT_MIME;
    166     mime.mimeType      = (SLchar*)NULL;
    167     mime.containerType = SL_CONTAINERTYPE_UNSPECIFIED;
    168 
    169     audioSource.pFormat      = (void *)&mime;
    170     audioSource.pLocator     = (void *)&uri;
    171 
    172     /* Setup the data sink structure */
    173     locator_outputmix.locatorType   = SL_DATALOCATOR_OUTPUTMIX;
    174     locator_outputmix.outputMix    = outputMix;
    175     audioSink.pLocator           = (void *)&locator_outputmix;
    176     audioSink.pFormat            = NULL;
    177 
    178     /* Initialize arrays required[] and iidArray[] */
    179     for (int i=0 ; i < MAX_NUMBER_INTERFACES ; i++) {
    180         required[i] = SL_BOOLEAN_FALSE;
    181         iidArray[i] = SL_IID_NULL;
    182     }
    183     /* Set arrays required[] and iidArray[] for VOLUME and PREFETCHSTATUS interface */
    184     required[0] = SL_BOOLEAN_TRUE;
    185     iidArray[0] = SL_IID_VOLUME;
    186     required[1] = SL_BOOLEAN_TRUE;
    187     iidArray[1] = SL_IID_PREFETCHSTATUS;
    188 
    189     fprintf(stdout, "TestSetup(%s) completed\n", path);
    190 }
    191 
    192 
    193 //-----------------------------------------------------------------
    194 void TestTeardown() {
    195     /* Destroy Output Mix object */
    196     (*outputMix)->Destroy(outputMix);
    197 
    198     /* Shutdown OpenSL ES */
    199     (*slEngine)->Destroy(slEngine);
    200 }
    201 
    202 
    203 //-----------------------------------------------------------------
    204 /**
    205  * Create a player and, if the creation is successful,
    206  * configure it, and start playing.
    207  */
    208 void CreatePlayer(int playerId) {
    209     SLresult res;
    210     playerNum[playerId] = playerId;
    211 
    212     /* Create the audio player */
    213     res = (*engineItf)->CreateAudioPlayer(engineItf, &audioPlayer[playerId],
    214             &audioSource, &audioSink, MAX_NUMBER_INTERFACES, iidArray, required);
    215     if (SL_RESULT_SUCCESS != res) {
    216             // do not abort the test, just flag the player as not a candidate for destruction
    217             fprintf(stdout, "CreateAudioPlayer for player %d failed\n", playerId);
    218             validplayer[playerId] = false;
    219             return;
    220         }
    221     validplayer[playerId] = true;
    222 
    223     /* Realizing the player in synchronous mode. */
    224     res = (*audioPlayer[playerId])->Realize(audioPlayer[playerId], SL_BOOLEAN_FALSE);
    225     if (SL_RESULT_SUCCESS != res) {
    226         // do not abort the test, just stop the player initialization here
    227         fprintf(stdout, "Realize for player %d failed\n", playerId);
    228         // this player is still a candidate for destruction
    229         return;
    230     }
    231     // after this point, any failure is a test failure
    232 
    233     /* Get interfaces */
    234     res = (*audioPlayer[playerId])->GetInterface(audioPlayer[playerId], SL_IID_PLAY,
    235             (void*)&playItfs[playerId]);
    236     CheckErrPlyr(res, playerId);
    237 
    238     res = (*audioPlayer[playerId])->GetInterface(audioPlayer[playerId], SL_IID_VOLUME,
    239             (void*)&volItfs[playerId]);
    240     CheckErrPlyr(res, playerId);
    241 
    242     res = (*audioPlayer[playerId])->GetInterface(audioPlayer[playerId], SL_IID_PREFETCHSTATUS,
    243             (void*)&prefetchItfs[playerId]);
    244     CheckErrPlyr(res, playerId);
    245     res = (*prefetchItfs[playerId])->RegisterCallback(prefetchItfs[playerId], PrefetchEventCallback,
    246             &playerNum[playerId]);
    247     CheckErrPlyr(res, playerId);
    248     res = (*prefetchItfs[playerId])->SetCallbackEventsMask(prefetchItfs[playerId],
    249             SL_PREFETCHEVENT_FILLLEVELCHANGE | SL_PREFETCHEVENT_STATUSCHANGE);
    250     CheckErrPlyr(res, playerId);
    251 
    252     /* Set the player volume */
    253     res = (*volItfs[playerId])->SetVolumeLevel( volItfs[playerId], -300);
    254     CheckErrPlyr(res, playerId);
    255 
    256     /* Set up the player callback to get events during the decoding */
    257     res = (*playItfs[playerId])->SetMarkerPosition(playItfs[playerId], 2000);
    258     CheckErrPlyr(res, playerId);
    259     res = (*playItfs[playerId])->SetPositionUpdatePeriod(playItfs[playerId], 500);
    260     CheckErrPlyr(res, playerId);
    261     res = (*playItfs[playerId])->SetCallbackEventsMask(playItfs[playerId],
    262             SL_PLAYEVENT_HEADATMARKER | SL_PLAYEVENT_HEADATNEWPOS | SL_PLAYEVENT_HEADATEND);
    263     CheckErrPlyr(res, playerId);
    264     res = (*playItfs[playerId])->RegisterCallback(playItfs[playerId], PlayEventCallback,
    265             &playerNum[playerId]);
    266     CheckErrPlyr(res, playerId);
    267 
    268     /* Configure fill level updates every 5 percent */
    269     (*prefetchItfs[playerId])->SetFillUpdatePeriod(prefetchItfs[playerId], 50);
    270 
    271     /* Play the URI */
    272     /*     first cause the player to prefetch the data */
    273     fprintf(stdout, "Setting player %d  to PAUSED\n", playerId);
    274     res = (*playItfs[playerId])->SetPlayState( playItfs[playerId], SL_PLAYSTATE_PAUSED );
    275     CheckErrPlyr(res, playerId);
    276     /*     wait until there's data to play */
    277     SLuint32 prefetchStatus = SL_PREFETCHSTATUS_UNDERFLOW;
    278     SLuint32 timeOutIndex = 10; // 1s, should be enough for a local file
    279     while ((prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) && (timeOutIndex > 0)) {
    280         usleep(100 * 1000);
    281         res = (*prefetchItfs[playerId])->GetPrefetchStatus(prefetchItfs[playerId], &prefetchStatus);
    282         CheckErrPlyr(res, playerId);
    283         timeOutIndex--;
    284     }
    285 
    286     if (timeOutIndex == 0) {
    287         fprintf(stderr, "Prefetch timed out for player %d\n", playerId);
    288         return;
    289     }
    290     res = (*playItfs[playerId])->SetPlayState( playItfs[playerId], SL_PLAYSTATE_PLAYING );
    291     CheckErrPlyr(res, playerId);
    292 
    293     /* Display duration */
    294     SLmillisecond durationInMsec = SL_TIME_UNKNOWN;
    295     res = (*playItfs[playerId])->GetDuration(playItfs[playerId], &durationInMsec);
    296     CheckErrPlyr(res, playerId);
    297     if (durationInMsec == SL_TIME_UNKNOWN) {
    298         fprintf(stdout, "Content duration is unknown for player %d\n", playerId);
    299     } else {
    300         fprintf(stdout, "Content duration is %u ms for player %d\n", durationInMsec, playerId);
    301     }
    302 }
    303 
    304 //-----------------------------------------------------------------
    305 void DestroyPlayer(int playerId) {
    306     fprintf(stdout, "About to destroy player %d\n", playerId);
    307     /* Destroy the player */
    308     (*audioPlayer[playerId])->Destroy(audioPlayer[playerId]);
    309 }
    310 
    311 
    312 //-----------------------------------------------------------------
    313 int main(int argc, char* const argv[])
    314 {
    315     fprintf(stdout, "OpenSL ES test %s: creates and destroys as many ", argv[0]);
    316     fprintf(stdout, "AudioPlayer objects as possible (max=%d)\n\n", MAX_NUMBER_PLAYERS);
    317 
    318     if (argc == 1) {
    319         fprintf(stdout, "Usage: %s path \n\t%s url\n", argv[0], argv[0]);
    320         fprintf(stdout, "Example: \"%s /sdcard/my.mp3\"  or \"%s file:///sdcard/my.mp3\"\n",
    321                 argv[0], argv[0]);
    322         exit(EXIT_FAILURE);
    323     }
    324 
    325     TestSetup(argv[1]);
    326 
    327     for (int i=0 ; i<MAX_NUMBER_PLAYERS ; i++) {
    328         CreatePlayer(i);
    329     }
    330     fprintf(stdout, "After creating %d AudioPlayers\n", MAX_NUMBER_PLAYERS);
    331 
    332     /* Wait for an arbitrary amount of time. if playing a long file, the players will still
    333        be playing while the destructions start. */
    334     usleep(10*1000*1000); // 10s
    335 
    336     for (int i=0 ; i<MAX_NUMBER_PLAYERS ; i++) {
    337         if (validplayer[i]) {
    338             DestroyPlayer(i);
    339         }
    340     }
    341     fprintf(stdout, "After destroying valid players among %d AudioPlayers\n", MAX_NUMBER_PLAYERS);
    342 
    343     TestTeardown();
    344 
    345     return EXIT_SUCCESS;
    346 }
    347