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