Home | History | Annotate | Download | only in examples
      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 #include <stdlib.h>
     18 #include <stdio.h>
     19 #include <string.h>
     20 #include <unistd.h>
     21 #include <sys/time.h>
     22 #include <fcntl.h>
     23 
     24 #include <SLES/OpenSLES.h>
     25 #include <SLES/OpenSLES_Android.h>
     26 
     27 
     28 #define MAX_NUMBER_INTERFACES 3
     29 
     30 #define TEST_MUTE 0
     31 #define TEST_SOLO 1
     32 
     33 #define PREFETCHEVENT_ERROR_CANDIDATE \
     34             (SL_PREFETCHEVENT_STATUSCHANGE | SL_PREFETCHEVENT_FILLLEVELCHANGE)
     35 
     36 //-----------------------------------------------------------------
     37 /* Exits the application if an error is encountered */
     38 #define ExitOnError(x) ExitOnErrorFunc(x,__LINE__)
     39 
     40 void ExitOnErrorFunc( SLresult result , int line)
     41 {
     42     if (SL_RESULT_SUCCESS != result) {
     43         fprintf(stdout, "%u error code encountered at line %d, exiting\n", result, line);
     44         exit(EXIT_FAILURE);
     45     }
     46 }
     47 
     48 //-----------------------------------------------------------------
     49 bool prefetchError = false;
     50 
     51 /* Callback for "prefetch" events, here used to detect audio resource opening errors */
     52 void PrefetchEventCallback( SLPrefetchStatusItf caller,  void *pContext __unused, SLuint32 event)
     53 {
     54     SLpermille level = 0;
     55     SLresult result;
     56     result = (*caller)->GetFillLevel(caller, &level);
     57     ExitOnError(result);
     58     SLuint32 status;
     59     result = (*caller)->GetPrefetchStatus(caller, &status);
     60     ExitOnError(result);
     61     if ((PREFETCHEVENT_ERROR_CANDIDATE == (event & PREFETCHEVENT_ERROR_CANDIDATE))
     62             && (level == 0) && (status == SL_PREFETCHSTATUS_UNDERFLOW)) {
     63         fprintf(stdout, "PrefetchEventCallback: Error while prefetching data, exiting\n");
     64         prefetchError = true;
     65     }
     66 }
     67 
     68 //-----------------------------------------------------------------
     69 
     70 /* Play an audio path by opening a file descriptor on that path  */
     71 void TestPlayPathFromFD( SLObjectItf sl, const char* path, SLAint64 offset, SLAint64 size)
     72 {
     73     SLresult  result;
     74     SLEngineItf EngineItf;
     75 
     76     /* Objects this application uses: one player and an ouput mix */
     77     SLObjectItf  player, outputMix;
     78 
     79     /* Source of audio data to play */
     80     SLDataSource            audioSource;
     81     SLDataLocator_AndroidFD locatorFd;
     82     SLDataFormat_MIME       mime;
     83 
     84     /* Data sinks for the audio player */
     85     SLDataSink               audioSink;
     86     SLDataLocator_OutputMix  locator_outputmix;
     87 
     88     /* Play and PrefetchStatus interfaces for the audio player */
     89     SLPlayItf              playItf;
     90     SLPrefetchStatusItf    prefetchItf;
     91 
     92     SLboolean required[MAX_NUMBER_INTERFACES];
     93     SLInterfaceID iidArray[MAX_NUMBER_INTERFACES];
     94 
     95     /* Get the SL Engine Interface which is implicit */
     96     result = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf);
     97     ExitOnError(result);
     98 
     99     /* Initialize arrays required[] and iidArray[] */
    100     for (int i=0 ; i < MAX_NUMBER_INTERFACES ; i++) {
    101         required[i] = SL_BOOLEAN_FALSE;
    102         iidArray[i] = SL_IID_NULL;
    103     }
    104 
    105     /* ------------------------------------------------------ */
    106     /* Configuration of the output mix  */
    107 
    108     /* Create Output Mix object to be used by the player */
    109      result = (*EngineItf)->CreateOutputMix(EngineItf, &outputMix, 0, iidArray, required);
    110      ExitOnError(result);
    111 
    112     /* Realize the Output Mix object in synchronous mode */
    113     result = (*outputMix)->Realize(outputMix, SL_BOOLEAN_FALSE);
    114     ExitOnError(result);
    115 
    116     /* Setup the data sink structure */
    117     locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
    118     locator_outputmix.outputMix   = outputMix;
    119     audioSink.pLocator            = (void*)&locator_outputmix;
    120     audioSink.pFormat             = NULL;
    121 
    122     /* ------------------------------------------------------ */
    123     /* Configuration of the player  */
    124 
    125     /* Set arrays required[] and iidArray[] for SLPrefetchStatusItf interfaces */
    126     /*  (SLPlayItf is implicit) */
    127     required[0] = SL_BOOLEAN_TRUE;
    128     iidArray[0] = SL_IID_PREFETCHSTATUS;
    129 
    130     /* Setup the data source structure for the URI */
    131     locatorFd.locatorType = SL_DATALOCATOR_ANDROIDFD;
    132     int fd = open(path, O_RDONLY);
    133     if (fd == -1) {
    134         perror(path);
    135         exit(EXIT_FAILURE);
    136     }
    137     locatorFd.fd = (SLint32) fd;
    138     locatorFd.length = size;
    139     locatorFd.offset = offset;
    140 
    141     mime.formatType = SL_DATAFORMAT_MIME;
    142     /*     this is how ignored mime information is specified, according to OpenSL ES spec
    143      *     in 9.1.6 SLDataFormat_MIME and 8.23 SLMetadataTraversalItf GetChildInfo */
    144     mime.mimeType      = (SLchar*)NULL;
    145     mime.containerType = SL_CONTAINERTYPE_UNSPECIFIED;
    146 
    147     audioSource.pFormat  = (void*)&mime;
    148     audioSource.pLocator = (void*)&locatorFd;
    149 
    150     /* Create the audio player */
    151     result = (*EngineItf)->CreateAudioPlayer(EngineItf, &player, &audioSource, &audioSink, 1,
    152             iidArray, required);
    153     ExitOnError(result);
    154 
    155     /* Realize the player in synchronous mode. */
    156     result = (*player)->Realize(player, SL_BOOLEAN_FALSE); ExitOnError(result);
    157     fprintf(stdout, "URI example: after Realize\n");
    158 
    159     /* Get the SLPlayItf, SLPrefetchStatusItf and SLAndroidStreamTypeItf interfaces for the player*/
    160     result = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf);
    161     ExitOnError(result);
    162 
    163     result = (*player)->GetInterface(player, SL_IID_PREFETCHSTATUS, (void*)&prefetchItf);
    164     ExitOnError(result);
    165 
    166     /* Set up prefetching callback.*/
    167     result = (*prefetchItf)->RegisterCallback(prefetchItf, PrefetchEventCallback, &prefetchItf);
    168     ExitOnError(result);
    169     result = (*prefetchItf)->SetCallbackEventsMask(prefetchItf, PREFETCHEVENT_ERROR_CANDIDATE);
    170     ExitOnError(result);
    171 
    172     fprintf(stdout, "Player configured\n");
    173 
    174     /* ------------------------------------------------------ */
    175     /* Playback and test */
    176 
    177     /* Start the data prefetching by setting the player to the paused state */
    178     result = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PAUSED );
    179     ExitOnError(result);
    180 
    181     /* Wait until there's data to play */
    182     SLuint32 prefetchStatus = SL_PREFETCHSTATUS_UNDERFLOW;
    183     while (prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) {
    184         usleep(100 * 1000);
    185         result = (*prefetchItf)->GetPrefetchStatus(prefetchItf, &prefetchStatus);
    186         ExitOnError(result);
    187         if (prefetchError) {
    188             fprintf(stderr, "Failure to prefetch data, exiting\n");
    189             ExitOnError(SL_RESULT_CONTENT_NOT_FOUND);
    190         }
    191     }
    192 
    193     /* Get duration */
    194     SLmillisecond durationInMsec = SL_TIME_UNKNOWN;
    195     result = (*playItf)->GetDuration(playItf, &durationInMsec);
    196     ExitOnError(result);
    197     if (durationInMsec == SL_TIME_UNKNOWN) {
    198         durationInMsec = 5000;
    199     }
    200 
    201     /* Start playback */
    202     result = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PLAYING );
    203     ExitOnError(result);
    204 
    205     usleep(durationInMsec * 1000);
    206 
    207     /* Make sure player is stopped */
    208     fprintf(stdout, "Stopping playback\n");
    209     result = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
    210     ExitOnError(result);
    211 
    212     /* Destroy the player */
    213     (*player)->Destroy(player);
    214 
    215     /* Destroy Output Mix object */
    216     (*outputMix)->Destroy(outputMix);
    217 
    218     close(fd);
    219 }
    220 
    221 //-----------------------------------------------------------------
    222 int main(int argc, char* const argv[])
    223 {
    224     SLresult    result;
    225     SLObjectItf sl;
    226 
    227     fprintf(stdout, "OpenSL ES test %s: exercises SLPlayItf ", argv[0]);
    228     fprintf(stdout, "and AudioPlayer with SLDataLocator_AndroidFD source / OutputMix sink\n");
    229     fprintf(stdout, "Plays the sound file designated by the given path, ");
    230     fprintf(stdout, "starting at the specified offset, and using the specified length.\n");
    231     fprintf(stdout, "Omit the length of the file for it to be computed by the system.\n");
    232 
    233     if (argc < 3) {
    234         fprintf(stdout, "Usage: \t%s path offsetInBytes [sizeInBytes]\n", argv[0]);
    235         fprintf(stdout, "Example: \"%s /sdcard/my.mp3 0 344460\" \n", argv[0]);
    236         exit(EXIT_FAILURE);
    237     }
    238 
    239     SLEngineOption EngineOption[] = {
    240             {(SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE}
    241     };
    242 
    243     result = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL);
    244     ExitOnError(result);
    245 
    246     /* Realizing the SL Engine in synchronous mode. */
    247     result = (*sl)->Realize(sl, SL_BOOLEAN_FALSE);
    248     ExitOnError(result);
    249 
    250     if (argc == 3) {
    251         fprintf(stdout, "no file size given, using SL_DATALOCATOR_ANDROIDFD_USE_FILE_SIZE\n");
    252         TestPlayPathFromFD(sl, argv[1], (SLAint64)atoi(argv[2]),
    253                 SL_DATALOCATOR_ANDROIDFD_USE_FILE_SIZE);
    254     } else {
    255         TestPlayPathFromFD(sl, argv[1], (SLAint64)atoi(argv[2]), (SLAint64)atoi(argv[3]));
    256     }
    257 
    258     /* Shutdown OpenSL ES */
    259     (*sl)->Destroy(sl);
    260 
    261     return EXIT_SUCCESS;
    262 }
    263