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 #ifdef ANDROID
     26 #include <SLES/OpenSLES_Android.h>
     27 #endif
     28 
     29 
     30 #define MAX_NUMBER_INTERFACES 3
     31 
     32 #define TIME_S_BETWEEN_EQ_ON_OFF 3
     33 
     34 //-----------------------------------------------------------------
     35 /* Exits the application if an error is encountered */
     36 #define ExitOnError(x) ExitOnErrorFunc(x,__LINE__)
     37 
     38 void ExitOnErrorFunc( SLresult result , int line)
     39 {
     40     if (SL_RESULT_SUCCESS != result) {
     41         fprintf(stderr, "%u error code encountered at line %d, exiting\n", result, line);
     42         exit(EXIT_FAILURE);
     43     }
     44 }
     45 
     46 
     47 //-----------------------------------------------------------------
     48 
     49 /* Play an audio path by opening a file descriptor on that path  */
     50 void TestEQPathFromFD( SLObjectItf sl, const char* path
     51 #ifdef ANDROID
     52     , SLAint64 offset, SLAint64 size
     53 #endif
     54     , bool alwaysOn
     55     )
     56 {
     57     SLresult  result;
     58     SLEngineItf EngineItf;
     59 
     60     /* Objects this application uses: one player and an ouput mix */
     61     SLObjectItf  player, outputMix;
     62 
     63     /* Source of audio data to play */
     64     SLDataSource            audioSource;
     65 #ifdef ANDROID
     66     SLDataLocator_AndroidFD locatorFd;
     67 #else
     68     SLDataLocator_URI       locatorUri;
     69 #endif
     70     SLDataFormat_MIME       mime;
     71 
     72     /* Data sinks for the audio player */
     73     SLDataSink               audioSink;
     74     SLDataLocator_OutputMix  locator_outputmix;
     75 
     76     /* Play and PrefetchStatus interfaces for the audio player */
     77     SLPlayItf              playItf;
     78     SLPrefetchStatusItf    prefetchItf;
     79     SLEqualizerItf         eqItf;
     80 
     81     SLboolean required[MAX_NUMBER_INTERFACES];
     82     SLInterfaceID iidArray[MAX_NUMBER_INTERFACES];
     83 
     84     /* Get the SL Engine Interface which is implicit */
     85     result = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf);
     86     ExitOnError(result);
     87 
     88     /* Initialize arrays required[] and iidArray[] */
     89     for (int i=0 ; i < MAX_NUMBER_INTERFACES ; i++) {
     90         required[i] = SL_BOOLEAN_FALSE;
     91         iidArray[i] = SL_IID_NULL;
     92     }
     93 
     94     /* ------------------------------------------------------ */
     95     /* Configuration of the output mix  */
     96 
     97     /* Create Output Mix object to be used by the player */
     98      result = (*EngineItf)->CreateOutputMix(EngineItf, &outputMix, 1, iidArray, required);
     99      ExitOnError(result);
    100 
    101     /* Realize the Output Mix object in synchronous mode */
    102     result = (*outputMix)->Realize(outputMix, SL_BOOLEAN_FALSE);
    103     ExitOnError(result);
    104 
    105     /* Setup the data sink structure */
    106     locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
    107     locator_outputmix.outputMix   = outputMix;
    108     audioSink.pLocator            = (void*)&locator_outputmix;
    109     audioSink.pFormat             = NULL;
    110 
    111     /* ------------------------------------------------------ */
    112     /* Configuration of the player  */
    113 
    114     /* Set arrays required[] and iidArray[] for SLPrefetchStatusItf interfaces */
    115     /*  (SLPlayItf is implicit) */
    116     required[0] = SL_BOOLEAN_TRUE;
    117     iidArray[0] = SL_IID_PREFETCHSTATUS;
    118     required[1] = SL_BOOLEAN_TRUE;
    119     iidArray[1] = SL_IID_EQUALIZER;
    120 
    121     /* Setup the data source structure for the URI */
    122 #ifdef ANDROID
    123     locatorFd.locatorType = SL_DATALOCATOR_ANDROIDFD;
    124     int fd = open(path, O_RDONLY);
    125     if (fd == -1) {
    126         ExitOnError(SL_RESULT_RESOURCE_ERROR);
    127     }
    128     locatorFd.fd = (SLint32) fd;
    129     locatorFd.length = size;
    130     locatorFd.offset = offset;
    131 #else
    132     locatorUri.locatorType = SL_DATALOCATOR_URI;
    133     locatorUri.URI = (SLchar *) path;
    134 #endif
    135 
    136     mime.formatType = SL_DATAFORMAT_MIME;
    137     /*     this is how ignored mime information is specified, according to OpenSL ES spec
    138      *     in 9.1.6 SLDataFormat_MIME and 8.23 SLMetadataTraversalItf GetChildInfo */
    139     mime.mimeType      = (SLchar*)NULL;
    140     mime.containerType = SL_CONTAINERTYPE_UNSPECIFIED;
    141 
    142     audioSource.pFormat  = (void*)&mime;
    143 #ifdef ANDROID
    144     audioSource.pLocator = (void*)&locatorFd;
    145 #else
    146     audioSource.pLocator = (void*)&locatorUri;
    147 #endif
    148 
    149     /* Create the audio player */
    150     result = (*EngineItf)->CreateAudioPlayer(EngineItf, &player, &audioSource, &audioSink, 2,
    151             iidArray, required);
    152     ExitOnError(result);
    153 
    154     /* Realize the player in synchronous mode. */
    155     result = (*player)->Realize(player, SL_BOOLEAN_FALSE); ExitOnError(result);
    156     fprintf(stdout, "URI example: after Realize\n");
    157 
    158     /* Get the SLPlayItf, SLPrefetchStatusItf and SLAndroidStreamTypeItf interfaces for the player*/
    159     result = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf);
    160     ExitOnError(result);
    161 
    162     result = (*player)->GetInterface(player, SL_IID_PREFETCHSTATUS, (void*)&prefetchItf);
    163     ExitOnError(result);
    164 
    165     result = (*player)->GetInterface(player, SL_IID_EQUALIZER, (void*)&eqItf);
    166     ExitOnError(result);
    167 
    168     fprintf(stdout, "Player configured\n");
    169 
    170     /* ------------------------------------------------------ */
    171     /* Playback and test */
    172 
    173     /* Start the data prefetching by setting the player to the paused state */
    174     result = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PAUSED );
    175     ExitOnError(result);
    176 
    177     /* Wait until there's data to play */
    178     SLuint32 prefetchStatus = SL_PREFETCHSTATUS_UNDERFLOW;
    179     while (prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) {
    180         usleep(100 * 1000);
    181         (*prefetchItf)->GetPrefetchStatus(prefetchItf, &prefetchStatus);
    182         ExitOnError(result);
    183     }
    184 
    185     /* Get duration */
    186     SLmillisecond durationInMsec = SL_TIME_UNKNOWN;
    187     result = (*playItf)->GetDuration(playItf, &durationInMsec);
    188     ExitOnError(result);
    189     if (durationInMsec == SL_TIME_UNKNOWN) {
    190         durationInMsec = 5000;
    191     }
    192 
    193     /* Start playback */
    194     fprintf(stdout, "Starting to play\n");
    195     result = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING );
    196     ExitOnError(result);
    197 
    198     /* Configure EQ */
    199     SLuint16 nbPresets, preset, nbBands = 0;
    200     result = (*eqItf)->GetNumberOfBands(eqItf, &nbBands);
    201     ExitOnError(result);
    202     result = (*eqItf)->GetNumberOfPresets(eqItf, &nbPresets);
    203     ExitOnError(result);
    204     /*    Start from a preset  */
    205     preset = nbPresets > 2 ?  2 : 0;
    206     result = (*eqItf)->UsePreset(eqItf, preset);
    207 
    208     preset = 1977;
    209     result = (*eqItf)->GetCurrentPreset(eqItf, &preset);
    210     ExitOnError(result);
    211     if (SL_EQUALIZER_UNDEFINED == preset) {
    212         fprintf(stderr, "Using SL_EQUALIZER_UNDEFINED preset, unexpected here!\n");
    213     } else {
    214         fprintf(stdout, "Using preset %d\n", preset);
    215     }
    216 
    217     /*    Tweak it so it's obvious it gets turned on/off later */
    218     SLmillibel minLevel, maxLevel = 0;
    219     result = (*eqItf)->GetBandLevelRange(eqItf, &minLevel, &maxLevel);
    220     ExitOnError(result);
    221     fprintf(stdout, "Band level range = %dmB to %dmB\n", minLevel, maxLevel);
    222 
    223     SLuint16 b = 0;
    224     for(b = 0 ; b < nbBands/2 ; b++) {
    225         result = (*eqItf)->SetBandLevel(eqItf, b, minLevel);
    226         ExitOnError(result);
    227     }
    228     for(b = nbBands/2 ; b < nbBands ; b++) {
    229         result = (*eqItf)->SetBandLevel(eqItf, b, maxLevel);
    230         ExitOnError(result);
    231     }
    232 
    233     SLmillibel level = 0;
    234     for(b = 0 ; b < nbBands ; b++) {
    235         result = (*eqItf)->GetBandLevel(eqItf, b, &level);
    236         ExitOnError(result);
    237         fprintf(stdout, "Band %d level = %dmB\n", b, level);
    238     }
    239 
    240     /* Switch EQ on/off every TIME_S_BETWEEN_EQ_ON_OFF seconds unless always on */
    241     SLboolean previousEnabled = SL_BOOLEAN_FALSE;
    242     for(unsigned int j=0 ; j<(durationInMsec/(1000*TIME_S_BETWEEN_EQ_ON_OFF)) ; j++) {
    243         SLboolean enabled;
    244         result = (*eqItf)->IsEnabled(eqItf, &enabled);
    245         ExitOnError(result);
    246         enabled = alwaysOn || !enabled;
    247         if (enabled != previousEnabled) {
    248             result = (*eqItf)->SetEnabled(eqItf, enabled);
    249             ExitOnError(result);
    250             previousEnabled = enabled;
    251             if (SL_BOOLEAN_TRUE == enabled) {
    252                 fprintf(stdout, "EQ on\n");
    253             } else {
    254                 fprintf(stdout, "EQ off\n");
    255             }
    256         }
    257         usleep(TIME_S_BETWEEN_EQ_ON_OFF * 1000 * 1000);
    258     }
    259 
    260     /* Make sure player is stopped */
    261     fprintf(stdout, "Stopping playback\n");
    262     result = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
    263     ExitOnError(result);
    264 
    265     /* Destroy the player */
    266     (*player)->Destroy(player);
    267 
    268     /* Destroy Output Mix object */
    269     (*outputMix)->Destroy(outputMix);
    270 
    271 #ifdef ANDROID
    272     close(fd);
    273 #endif
    274 }
    275 
    276 //-----------------------------------------------------------------
    277 int main(int argc, char* const argv[])
    278 {
    279     const char *programName = argv[0];
    280     SLresult    result;
    281     SLObjectItf sl;
    282 
    283     fprintf(stdout, "OpenSL ES test %s: exercises SLEqualizerItf ", programName);
    284     fprintf(stdout, "and AudioPlayer with SLDataLocator_AndroidFD source / OutputMix sink\n");
    285     fprintf(stdout, "Plays the sound file designated by the given path, ");
    286     fprintf(stdout, "starting at the specified offset, and using the specified length.\n");
    287     fprintf(stdout, "Omit the length of the file for it to be computed by the system.\n");
    288     fprintf(stdout, "Every %d seconds, the EQ will be turned on and off,\n",
    289             TIME_S_BETWEEN_EQ_ON_OFF);
    290     fprintf(stdout, "unless the --always-on option is specified before the path.\n");
    291 
    292     bool alwaysOn = false;
    293     if (argc >= 2 && !strcmp(argv[1], "--always-on")) {
    294         alwaysOn = true;
    295         --argc;
    296         ++argv;
    297     }
    298 
    299 #ifdef ANDROID
    300     if (argc < 3)
    301 #else
    302     if (argc < 1)
    303 #endif
    304     {
    305         fprintf(stdout, "Usage: \t%s [--always-on] path offsetInBytes [sizeInBytes]\n",
    306                 programName);
    307         fprintf(stdout, "Example: \"%s /sdcard/my.mp3 0 344460\" \n", programName);
    308         exit(EXIT_FAILURE);
    309     }
    310 
    311     SLEngineOption EngineOption[] = {
    312             {(SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE}
    313     };
    314 
    315     result = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL);
    316     ExitOnError(result);
    317 
    318     /* Realizing the SL Engine in synchronous mode. */
    319     result = (*sl)->Realize(sl, SL_BOOLEAN_FALSE);
    320     ExitOnError(result);
    321 
    322 #ifdef ANDROID
    323     if (argc == 3) {
    324         fprintf(stdout, "\nno file size given, using SL_DATALOCATOR_ANDROIDFD_USE_FILE_SIZE\n\n");
    325         TestEQPathFromFD(sl, argv[1], (SLAint64)atoi(argv[2]),
    326                 SL_DATALOCATOR_ANDROIDFD_USE_FILE_SIZE, alwaysOn);
    327     } else {
    328         TestEQPathFromFD(sl, argv[1], (SLAint64)atoi(argv[2]), (SLAint64)atoi(argv[3]), alwaysOn);
    329     }
    330 #else
    331     TestEQPathFromFD(sl, argv[1]);
    332 #endif
    333 
    334     /* Shutdown OpenSL ES */
    335     (*sl)->Destroy(sl);
    336 
    337     return EXIT_SUCCESS;
    338 }
    339