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 <assert.h>
     18 #include <stdlib.h>
     19 #include <stdio.h>
     20 #include <string.h>
     21 #include <unistd.h>
     22 #include <sys/time.h>
     23 #include <fcntl.h>
     24 
     25 #include <SLES/OpenSLES.h>
     26 #ifdef ANDROID
     27 #include <SLES/OpenSLES_Android.h>
     28 #endif
     29 
     30 
     31 #define MAX_NUMBER_INTERFACES 4
     32 
     33 #define TIME_S_BETWEEN_SETTING_CHANGE 3
     34 
     35 //-----------------------------------------------------------------
     36 /* Exits the application if an error is encountered */
     37 #define ExitOnError(x) ExitOnErrorFunc(x,__LINE__)
     38 
     39 void ExitOnErrorFunc( SLresult result , int line)
     40 {
     41     if (SL_RESULT_SUCCESS != result) {
     42         fprintf(stderr, "%u error code encountered at line %d, exiting\n", result, line);
     43         exit(EXIT_FAILURE);
     44     }
     45 }
     46 
     47 // Prefetch status callback
     48 
     49 #define PREFETCHEVENT_ERROR_CANDIDATE \
     50             (SL_PREFETCHEVENT_STATUSCHANGE | SL_PREFETCHEVENT_FILLLEVELCHANGE)
     51 
     52 SLboolean errorInPrefetchCallback = SL_BOOLEAN_FALSE;
     53 
     54 void prefetch_callback(SLPrefetchStatusItf caller, void *context, SLuint32 event)
     55 {
     56     SLresult result;
     57     assert(context == NULL);
     58     SLpermille level;
     59     result = (*caller)->GetFillLevel(caller, &level);
     60     ExitOnError(result);
     61     SLuint32 status;
     62     result = (*caller)->GetPrefetchStatus(caller, &status);
     63     ExitOnError(result);
     64     if ((PREFETCHEVENT_ERROR_CANDIDATE == (event & PREFETCHEVENT_ERROR_CANDIDATE))
     65             && (level == 0) && (status == SL_PREFETCHSTATUS_UNDERFLOW)) {
     66         errorInPrefetchCallback = SL_BOOLEAN_TRUE;
     67     }
     68 }
     69 
     70 //-----------------------------------------------------------------
     71 
     72 /* Play an audio path and feed a global reverb  */
     73 void TestSendToPresetReverb( SLObjectItf sl, const char* path, int preset, SLmillibel directLevel,
     74         SLmillibel sendLevel, bool alwaysOn, bool useFd, bool loop)
     75 {
     76     SLresult  result;
     77     SLEngineItf EngineItf;
     78 
     79     /* Objects this application uses: one player and an ouput mix */
     80     SLObjectItf  player, outputMix;
     81 
     82     /* Source of audio data to play */
     83     SLDataSource            audioSource;
     84 #ifdef ANDROID
     85     SLDataLocator_AndroidFD locatorFd;
     86 #endif
     87     SLDataLocator_URI       locatorUri;
     88     SLDataFormat_MIME       mime;
     89 
     90     /* Data sinks for the audio player */
     91     SLDataSink               audioSink;
     92     SLDataLocator_OutputMix  locator_outputmix;
     93 
     94     /* Interfaces for the audio player */
     95     SLPlayItf              playItf;
     96     SLPrefetchStatusItf    prefetchItf;
     97     SLEffectSendItf        effectSendItf;
     98     SLSeekItf              seekItf;
     99 
    100     /* Interface for the output mix */
    101     SLPresetReverbItf      reverbItf;
    102 
    103     SLboolean required[MAX_NUMBER_INTERFACES];
    104     SLInterfaceID iidArray[MAX_NUMBER_INTERFACES];
    105 
    106     /* Get the SL Engine Interface which is implicit */
    107     result = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf);
    108     ExitOnError(result);
    109 
    110     /* Initialize arrays required[] and iidArray[] */
    111     for (int i=0 ; i < MAX_NUMBER_INTERFACES ; i++) {
    112         required[i] = SL_BOOLEAN_FALSE;
    113         iidArray[i] = SL_IID_NULL;
    114     }
    115 
    116     /* ------------------------------------------------------ */
    117     /* Configuration of the output mix  */
    118 
    119     /* Set arrays required[] and iidArray[] for required interfaces */
    120     required[0] = SL_BOOLEAN_TRUE;
    121     iidArray[0] = SL_IID_PRESETREVERB;
    122 
    123     /* Create Output Mix object to be used by the player */
    124      result = (*EngineItf)->CreateOutputMix(EngineItf, &outputMix, 1, iidArray, required);
    125      ExitOnError(result);
    126 
    127     /* Realize the Output Mix object in synchronous mode */
    128     result = (*outputMix)->Realize(outputMix, SL_BOOLEAN_FALSE);
    129     ExitOnError(result);
    130 
    131     /* Get the SLPresetReverbItf for the output mix */
    132     result = (*outputMix)->GetInterface(outputMix, SL_IID_PRESETREVERB, (void*)&reverbItf);
    133     ExitOnError(result);
    134 
    135     /* Setup the data sink structure */
    136     locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
    137     locator_outputmix.outputMix   = outputMix;
    138     audioSink.pLocator            = (void*)&locator_outputmix;
    139     audioSink.pFormat             = NULL;
    140 
    141     /* Select the reverb preset */
    142     fprintf(stdout, "\nUsing preset ");
    143     switch(preset) {
    144         case SL_REVERBPRESET_NONE:
    145             fprintf(stdout, "SL_REVERBPRESET_NONE, don't expect to hear reverb\n");
    146             break;
    147         case SL_REVERBPRESET_SMALLROOM: fprintf(stdout, "SL_REVERBPRESET_SMALLROOM\n"); break;
    148         case SL_REVERBPRESET_MEDIUMROOM: fprintf(stdout, "SL_REVERBPRESET_MEDIUMROOM\n"); break;
    149         case SL_REVERBPRESET_LARGEROOM: fprintf(stdout, "SL_REVERBPRESET_LARGEROOM\n"); break;
    150         case SL_REVERBPRESET_MEDIUMHALL: fprintf(stdout, "SL_REVERBPRESET_MEDIUMHALL\n"); break;
    151         case SL_REVERBPRESET_LARGEHALL: fprintf(stdout, "SL_REVERBPRESET_LARGEHALL\n"); break;
    152         case SL_REVERBPRESET_PLATE: fprintf(stdout, "SL_REVERBPRESET_PLATE\n"); break;
    153         default:
    154             fprintf(stdout, "unknown, use at your own risk\n"); break;
    155     }
    156     result = (*reverbItf)->SetPreset(reverbItf, preset);
    157     ExitOnError(result);
    158 
    159     /* ------------------------------------------------------ */
    160     /* Configuration of the player  */
    161 
    162     /* Set arrays required[] and iidArray[] for required interfaces */
    163     /*  (SLPlayItf is implicit) */
    164     required[0] = SL_BOOLEAN_TRUE;
    165     iidArray[0] = SL_IID_PREFETCHSTATUS;
    166     required[1] = SL_BOOLEAN_TRUE;
    167     iidArray[1] = SL_IID_EFFECTSEND;
    168     required[2] = SL_BOOLEAN_TRUE;
    169     iidArray[2] = SL_IID_SEEK;
    170 
    171     locatorUri.locatorType = SL_DATALOCATOR_URI;
    172     locatorUri.URI = (SLchar *) path;
    173     audioSource.pLocator = (void*)&locatorUri;
    174     if (useFd) {
    175 #ifdef ANDROID
    176         /* Setup the data source structure for the URI */
    177         locatorFd.locatorType = SL_DATALOCATOR_ANDROIDFD;
    178         int fd = open(path, O_RDONLY);
    179         if (fd == -1) {
    180             perror(path);
    181             exit(EXIT_FAILURE);
    182         }
    183         locatorFd.fd = (SLint32) fd;
    184         locatorFd.length = SL_DATALOCATOR_ANDROIDFD_USE_FILE_SIZE;
    185         locatorFd.offset = 0;
    186         audioSource.pLocator = (void*)&locatorFd;
    187 #else
    188         fprintf(stderr, "option --fd is not supported\n");
    189 #endif
    190     }
    191 
    192     mime.formatType = SL_DATAFORMAT_MIME;
    193     /*     this is how ignored mime information is specified, according to OpenSL ES spec
    194      *     in 9.1.6 SLDataFormat_MIME and 8.23 SLMetadataTraversalItf GetChildInfo */
    195     mime.mimeType      = (SLchar*)NULL;
    196     mime.containerType = SL_CONTAINERTYPE_UNSPECIFIED;
    197 
    198     audioSource.pFormat  = (void*)&mime;
    199 
    200     /* Create the audio player */
    201     result = (*EngineItf)->CreateAudioPlayer(EngineItf, &player, &audioSource, &audioSink, 3,
    202             iidArray, required);
    203     ExitOnError(result);
    204 
    205     /* Realize the player in synchronous mode. */
    206     result = (*player)->Realize(player, SL_BOOLEAN_FALSE); ExitOnError(result);
    207     fprintf(stdout, "URI example: after Realize\n");
    208 
    209     /* Get the SLPlayItf, SLPrefetchStatusItf and SLEffectSendItf interfaces for the player*/
    210     result = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf);
    211     ExitOnError(result);
    212 
    213     result = (*player)->GetInterface(player, SL_IID_PREFETCHSTATUS, (void*)&prefetchItf);
    214     ExitOnError(result);
    215     result = (*prefetchItf)->RegisterCallback(prefetchItf, prefetch_callback, NULL);
    216     ExitOnError(result);
    217     result = (*prefetchItf)->SetCallbackEventsMask(prefetchItf,
    218             SL_PREFETCHEVENT_STATUSCHANGE | SL_PREFETCHEVENT_FILLLEVELCHANGE);
    219     ExitOnError(result);
    220 
    221     result = (*player)->GetInterface(player, SL_IID_EFFECTSEND, (void*)&effectSendItf);
    222     ExitOnError(result);
    223 
    224     result = (*player)->GetInterface(player, SL_IID_SEEK, (void*)&seekItf);
    225     ExitOnError(result);
    226 
    227     fprintf(stdout, "Player configured\n");
    228 
    229     /* ------------------------------------------------------ */
    230     /* Playback and test */
    231 
    232     /* Start the data prefetching by setting the player to the paused state */
    233     result = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PAUSED );
    234     ExitOnError(result);
    235 
    236     /* Wait until there's data to play */
    237     SLuint32 prefetchStatus = SL_PREFETCHSTATUS_UNDERFLOW;
    238     while (prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) {
    239         if (errorInPrefetchCallback) {
    240             fprintf(stderr, "Error during prefetch, exiting\n");
    241             exit(EXIT_FAILURE);
    242         }
    243         usleep(100 * 1000);
    244         (*prefetchItf)->GetPrefetchStatus(prefetchItf, &prefetchStatus);
    245         ExitOnError(result);
    246     }
    247 
    248     /* Get duration */
    249     SLmillisecond durationInMsec = SL_TIME_UNKNOWN;
    250     result = (*playItf)->GetDuration(playItf, &durationInMsec);
    251     ExitOnError(result);
    252     if (durationInMsec == SL_TIME_UNKNOWN) {
    253         printf("Duration unknown, assuming 10 seconds\n");
    254         durationInMsec = 10000;
    255     } else {
    256         printf("Duration is %.1f seconds\n", durationInMsec / 1000.0);
    257     }
    258 
    259     /* Feed the output mix' reverb from the audio player using the given send level */
    260     result = (*effectSendItf)->EnableEffectSend(effectSendItf, reverbItf, SL_BOOLEAN_TRUE,
    261             sendLevel);
    262     ExitOnError(result);
    263 
    264     result = (*effectSendItf)->SetDirectLevel(effectSendItf, directLevel);
    265     ExitOnError(result);
    266     fprintf(stdout, "Set direct level to %dmB\n", directLevel);
    267 
    268     result = (*effectSendItf)->SetSendLevel(effectSendItf, reverbItf, sendLevel);
    269     ExitOnError(result);
    270     fprintf(stdout, "Set send level to %dmB\n", sendLevel);
    271 
    272     /* Enable looping */
    273     if (loop) {
    274         result = (*seekItf)->SetLoop(seekItf, SL_BOOLEAN_TRUE, (SLmillisecond) 0, SL_TIME_UNKNOWN);
    275         ExitOnError(result);
    276     }
    277 
    278     /* Start playback */
    279     result = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PLAYING );
    280     ExitOnError(result);
    281 
    282     /* Disable preset reverb every TIME_S_BETWEEN_SETTING_CHANGE seconds unless always on */
    283     SLboolean previousEnabled = SL_BOOLEAN_FALSE;
    284     SLuint32 playState;
    285     for (;;) {
    286         result = (*playItf)->GetPlayState(playItf, &playState);
    287         ExitOnError(result);
    288         if (playState != SL_PLAYSTATE_PLAYING)
    289             break;
    290         SLboolean enabled;
    291         enabled = alwaysOn || !previousEnabled;
    292         if (enabled != previousEnabled) {
    293             result = (*reverbItf)->SetPreset(reverbItf, enabled ? preset : SL_REVERBPRESET_NONE);
    294             fprintf(stdout, "SetPreset(%d)=%d\n", enabled ? preset : SL_REVERBPRESET_NONE, result);
    295             ExitOnError(result);
    296             previousEnabled = enabled;
    297             if (enabled) {
    298                 fprintf(stdout, "Reverb on\n");
    299             } else {
    300                 fprintf(stdout, "Reverb off\n");
    301             }
    302         }
    303         usleep(TIME_S_BETWEEN_SETTING_CHANGE * 1000 * 1000);
    304     }
    305 
    306     /* Make sure player is stopped */
    307     assert(playState == SL_PLAYSTATE_STOPPED);
    308 #if 0
    309     fprintf(stdout, "Stopping playback\n");
    310     result = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
    311     ExitOnError(result);
    312 #endif
    313 
    314     /* Destroy the player */
    315     (*player)->Destroy(player);
    316 
    317     /* Destroy Output Mix object */
    318     (*outputMix)->Destroy(outputMix);
    319 
    320 #ifdef ANDROID
    321     if (useFd)
    322         close(locatorFd.fd);
    323 #endif
    324 }
    325 
    326 //-----------------------------------------------------------------
    327 int main(int argc, char* const argv[])
    328 {
    329     const char *programName = argv[0];
    330     SLresult    result;
    331     SLObjectItf sl;
    332 
    333     fprintf(stdout, "OpenSL ES test %s: exercises SLEffectSendItf ", programName);
    334     fprintf(stdout, "on AudioPlayer and SLPresetReverbItf on OutputMix.\n");
    335     fprintf(stdout, "Plays the sound file designated by the given path, ");
    336     fprintf(stdout, "and sends a specified amount of energy to a global reverb\n");
    337     fprintf(stdout, "(sendLevel in mB), with a given direct level (in mB).\n");
    338     fprintf(stdout, "Every %d seconds, the reverb is turned on and off,\n",
    339             TIME_S_BETWEEN_SETTING_CHANGE);
    340     fprintf(stdout, "unless the --always-on option is specified before the path.\n");
    341 
    342     bool alwaysOn = false;
    343     bool useFd = false;
    344     bool loop = false;
    345     int i;
    346     for (i = 1; i < argc; ++i) {
    347         const char *arg = argv[i];
    348         if (arg[0] != '-')
    349             break;
    350         if (!strcmp(arg, "--always-on")) {
    351             alwaysOn = true;
    352         } else if (!strcmp(arg, "--fd")) {
    353             useFd = true;
    354         } else if (!strcmp(arg, "--loop")) {
    355             loop = true;
    356         } else {
    357             fprintf(stderr, "unknown option %s ignored\n", arg);
    358         }
    359     }
    360 
    361     if (argc - i != 4) {
    362         fprintf(stdout, "Usage: \t%s [--always-on] [--fd] [--loop] path preset directLevel "
    363                 "sendLevel\n", programName);
    364         fprintf(stdout, "Example: \"%s /sdcard/my.mp3 6 -2000 0\" \n", programName);
    365         exit(EXIT_FAILURE);
    366     }
    367 
    368     SLEngineOption EngineOption[] = {
    369             {(SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE}
    370     };
    371 
    372     result = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL);
    373     ExitOnError(result);
    374 
    375     /* Realizing the SL Engine in synchronous mode. */
    376     result = (*sl)->Realize(sl, SL_BOOLEAN_FALSE);
    377     ExitOnError(result);
    378 
    379     // intentionally not checking that levels are of correct value
    380     TestSendToPresetReverb(sl, argv[i], atoi(argv[i+1]), (SLmillibel)atoi(argv[i+2]),
    381             (SLmillibel)atoi(argv[i+3]), alwaysOn, useFd, loop);
    382 
    383     /* Shutdown OpenSL ES */
    384     (*sl)->Destroy(sl);
    385 
    386     return EXIT_SUCCESS;
    387 }
    388