Home | History | Annotate | Download | only in listening
      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 <pthread.h>
     19 #include <stdlib.h>
     20 #include <stdio.h>
     21 #include <string.h>
     22 #include <unistd.h>
     23 #include <sys/time.h>
     24 
     25 #include <SLES/OpenSLES.h>
     26 
     27 
     28 #define MAX_NUMBER_INTERFACES 3
     29 
     30 #define TEST_MUTE 0
     31 #define TEST_SOLO 1
     32 
     33 typedef struct {
     34     int testMode;
     35     SLPlayItf playItf;
     36     SLMuteSoloItf muteSoloItf;
     37 } Context;
     38 
     39 //-----------------------------------------------------------------
     40 /* Exits the application if an error is encountered */
     41 #define ExitOnError(x) ExitOnErrorFunc(x,__LINE__)
     42 
     43 void ExitOnErrorFunc( SLresult result , int line)
     44 {
     45     if (SL_RESULT_SUCCESS != result) {
     46         fprintf(stdout, "%u error code encountered at line %d, exiting\n", result, line);
     47         exit(EXIT_FAILURE);
     48     }
     49 }
     50 
     51 // These are extensions to OpenSL ES 1.0.1 values
     52 
     53 #define SL_PREFETCHSTATUS_UNKNOWN 0
     54 #define SL_PREFETCHSTATUS_ERROR   ((SLuint32) -1)
     55 
     56 // Mutex and condition shared with main program to protect prefetch_status
     57 
     58 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
     59 static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
     60 SLuint32 prefetch_status = SL_PREFETCHSTATUS_UNKNOWN;
     61 
     62 /* used to detect errors likely to have occured when the OpenSL ES framework fails to open
     63  * a resource, for instance because a file URI is invalid, or an HTTP server doesn't respond.
     64  */
     65 #define PREFETCHEVENT_ERROR_CANDIDATE \
     66         (SL_PREFETCHEVENT_STATUSCHANGE | SL_PREFETCHEVENT_FILLLEVELCHANGE)
     67 
     68 // Prefetch status callback
     69 
     70 void prefetch_callback(SLPrefetchStatusItf caller, void *context __unused, SLuint32 event)
     71 {
     72     SLresult result;
     73     assert(context == NULL);
     74     SLpermille level;
     75     result = (*caller)->GetFillLevel(caller, &level);
     76     assert(SL_RESULT_SUCCESS == result);
     77     SLuint32 status;
     78     result = (*caller)->GetPrefetchStatus(caller, &status);
     79     assert(SL_RESULT_SUCCESS == result);
     80     SLuint32 new_prefetch_status;
     81     if ((event & PREFETCHEVENT_ERROR_CANDIDATE) == PREFETCHEVENT_ERROR_CANDIDATE
     82             && level == 0 && status == SL_PREFETCHSTATUS_UNDERFLOW) {
     83         new_prefetch_status = SL_PREFETCHSTATUS_ERROR;
     84     } else if (event == SL_PREFETCHEVENT_STATUSCHANGE &&
     85             status == SL_PREFETCHSTATUS_SUFFICIENTDATA) {
     86         new_prefetch_status = status;
     87     } else {
     88         return;
     89     }
     90     int ok;
     91     ok = pthread_mutex_lock(&mutex);
     92     assert(ok == 0);
     93     prefetch_status = new_prefetch_status;
     94     ok = pthread_cond_signal(&cond);
     95     assert(ok == 0);
     96     ok = pthread_mutex_unlock(&mutex);
     97     assert(ok == 0);
     98 }
     99 
    100 //-----------------------------------------------------------------
    101 /* PlayItf callback for an audio player, will be called for every SL_PLAYEVENT_HEADATNEWPOS event */
    102 void PlayEventCallback( SLPlayItf caller __unused,  void *pContext, SLuint32 event __unused)
    103 {
    104     Context *context = (Context *) pContext;
    105     SLPlayItf playItf = context->playItf;
    106     SLMuteSoloItf muteSolo = context->muteSoloItf;
    107     SLuint8 numChannels = 0;
    108     SLresult res = (*muteSolo)->GetNumChannels(muteSolo, &numChannels); ExitOnError(res);
    109     //fprintf(stdout, "Content has %d channel(s)\n", numChannels);
    110     SLmillisecond position;
    111     res = (*playItf)->GetPosition(playItf, &position); ExitOnError(res);
    112     printf("position=%u\n", (unsigned) position);
    113 
    114     switch (context->testMode) {
    115         case TEST_MUTE: {
    116             //---------------------------------------------------
    117             if (numChannels > 1) { // SLMuteSoloItf only works if more than one channel
    118                 SLboolean leftMuted = SL_BOOLEAN_TRUE;
    119                 res = (*muteSolo)->GetChannelMute(muteSolo, 0, &leftMuted); ExitOnError(res);
    120                 // swap channel mute
    121                 res = (*muteSolo)->SetChannelMute(muteSolo, 0,
    122                        leftMuted == SL_BOOLEAN_TRUE ? SL_BOOLEAN_FALSE : SL_BOOLEAN_TRUE);
    123                 ExitOnError(res);
    124                 res = (*muteSolo)->SetChannelMute(muteSolo, 1,
    125                        leftMuted == SL_BOOLEAN_TRUE ? SL_BOOLEAN_TRUE : SL_BOOLEAN_FALSE);
    126                 ExitOnError(res);
    127                 if (leftMuted == SL_BOOLEAN_TRUE) { // we've swapped the channel mute above
    128                     fprintf(stdout, "channel 0: playing, channel 1: muted\n");
    129                 } else {
    130                     fprintf(stdout, "channel 0: muted, channel 1: playing\n");
    131                 }
    132             }
    133             } break;
    134 
    135         case TEST_SOLO: {
    136             //---------------------------------------------------
    137             if (numChannels > 1) { // SLMuteSoloItf only works if more than one channel
    138                 SLboolean leftSoloed = SL_BOOLEAN_TRUE;
    139                 res = (*muteSolo)->GetChannelSolo(muteSolo, 0, &leftSoloed); ExitOnError(res);
    140                 // swap channel solo
    141                 res = (*muteSolo)->SetChannelSolo(muteSolo, 0,
    142                         leftSoloed == SL_BOOLEAN_TRUE ? SL_BOOLEAN_FALSE : SL_BOOLEAN_TRUE);
    143                 ExitOnError(res);
    144                 res = (*muteSolo)->SetChannelSolo(muteSolo, 1,
    145                         leftSoloed == SL_BOOLEAN_TRUE ? SL_BOOLEAN_TRUE : SL_BOOLEAN_FALSE);
    146                 ExitOnError(res);
    147                 if (leftSoloed == SL_BOOLEAN_TRUE) { // we've swapped the channel solo above
    148                     fprintf(stdout, "channel 0: normal, channel 1: soloed\n");
    149                 } else {
    150                     fprintf(stdout, "channel 0: soloed, channel 1: normal\n");
    151                 }
    152             }
    153             } break;
    154 
    155         default:
    156             break;
    157     }
    158 }
    159 
    160 //-----------------------------------------------------------------
    161 
    162 /* Play an audio URIs, mute and solo channels  */
    163 void TestPlayUri( SLObjectItf sl, const char* path)
    164 {
    165     SLresult  result;
    166     SLEngineItf EngineItf;
    167 
    168     /* Objects this application uses: one player and an output mix */
    169     SLObjectItf  player, outputMix;
    170 
    171     /* Source of audio data to play */
    172     SLDataSource      audioSource;
    173     SLDataLocator_URI uri;
    174     SLDataFormat_MIME mime;
    175 
    176     /* Data sinks for the audio player */
    177     SLDataSink               audioSink;
    178     SLDataLocator_OutputMix  locator_outputmix;
    179 
    180     /* Play, Volume and PrefetchStatus interfaces for the audio player */
    181     SLPlayItf           playItf;
    182     SLMuteSoloItf       muteSoloItf;
    183     SLPrefetchStatusItf prefetchItf;
    184 
    185     SLboolean required[MAX_NUMBER_INTERFACES];
    186     SLInterfaceID iidArray[MAX_NUMBER_INTERFACES];
    187 
    188     /* Get the SL Engine Interface which is implicit */
    189     result = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf);
    190     ExitOnError(result);
    191 
    192     /* Initialize arrays required[] and iidArray[] */
    193     for (int i=0 ; i < MAX_NUMBER_INTERFACES ; i++) {
    194         required[i] = SL_BOOLEAN_FALSE;
    195         iidArray[i] = SL_IID_NULL;
    196     }
    197 
    198     /* ------------------------------------------------------ */
    199     /* Configuration of the output mix  */
    200 
    201     /* Create Output Mix object to be used by the player */
    202      result = (*EngineItf)->CreateOutputMix(EngineItf, &outputMix, 0, iidArray, required);
    203      ExitOnError(result);
    204 
    205     /* Realize the Output Mix object in synchronous mode */
    206     result = (*outputMix)->Realize(outputMix, SL_BOOLEAN_FALSE);
    207     ExitOnError(result);
    208 
    209     /* Setup the data sink structure */
    210     locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
    211     locator_outputmix.outputMix   = outputMix;
    212     audioSink.pLocator            = (void*)&locator_outputmix;
    213     audioSink.pFormat             = NULL;
    214 
    215     /* ------------------------------------------------------ */
    216     /* Configuration of the player  */
    217 
    218     /* Set arrays required[] and iidArray[] for SLMuteSoloItf and SLPrefetchStatusItf interfaces */
    219     /*  (SLPlayItf is implicit) */
    220     required[0] = SL_BOOLEAN_TRUE;
    221     iidArray[0] = SL_IID_MUTESOLO;
    222     required[1] = SL_BOOLEAN_TRUE;
    223     iidArray[1] = SL_IID_PREFETCHSTATUS;
    224 
    225     /* Setup the data source structure for the URI */
    226     uri.locatorType = SL_DATALOCATOR_URI;
    227     uri.URI         =  (SLchar*) path;
    228     mime.formatType = SL_DATAFORMAT_MIME;
    229     /*     this is how ignored mime information is specified, according to OpenSL ES spec
    230      *     in 9.1.6 SLDataFormat_MIME and 8.23 SLMetadataTraversalItf GetChildInfo */
    231     mime.mimeType      = (SLchar*)NULL;
    232     mime.containerType = SL_CONTAINERTYPE_UNSPECIFIED;
    233 
    234     audioSource.pFormat  = (void*)&mime;
    235     audioSource.pLocator = (void*)&uri;
    236 
    237     /* Create the audio player */
    238     result = (*EngineItf)->CreateAudioPlayer(EngineItf, &player, &audioSource, &audioSink, 2,
    239             iidArray, required);
    240     ExitOnError(result);
    241 
    242     /* Realize the player in synchronous mode. */
    243     result = (*player)->Realize(player, SL_BOOLEAN_FALSE); ExitOnError(result);
    244     fprintf(stdout, "URI example: after Realize\n");
    245 
    246     /* Get the SLPlayItf, SLPrefetchStatusItf and SLMuteSoloItf interfaces for the player */
    247     result = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf);
    248     ExitOnError(result);
    249 
    250     // get the prefetch status interface
    251     result = (*player)->GetInterface(player, SL_IID_PREFETCHSTATUS, (void*)&prefetchItf);
    252     ExitOnError(result);
    253 
    254     // enable prefetch status callbacks
    255     result = (*prefetchItf)->RegisterCallback(prefetchItf, prefetch_callback, NULL);
    256     assert(SL_RESULT_SUCCESS == result);
    257     result = (*prefetchItf)->SetCallbackEventsMask(prefetchItf,
    258             SL_PREFETCHEVENT_STATUSCHANGE | SL_PREFETCHEVENT_FILLLEVELCHANGE);
    259     assert(SL_RESULT_SUCCESS == result);
    260 
    261     // get the mute solo interface
    262     result = (*player)->GetInterface(player, SL_IID_MUTESOLO, (void*)&muteSoloItf);
    263     ExitOnError(result);
    264 
    265     // Attempt to get the duration before it is necessarily known.
    266     // This should always return successfully.
    267     // The reported duration may be either
    268     // a particular duration or SL_TIME_UNKNOWN, depending on the platform.
    269     SLmillisecond duration;
    270     result = (*playItf)->GetDuration(playItf, &duration);
    271     ExitOnError(result);
    272     printf("GetDuration after Realize but before pre-fetch: result=%u, duration=%u\n",
    273         result, duration);
    274 
    275     // Attempt to get the channel count before it is necessarily known.
    276     // This should either return successfully with a specific value (e.g. 1 or 2),
    277     // or return zero, depending on whether the channel count is known yet.
    278     SLuint8 numChannels = 123;
    279     result = (*muteSoloItf)->GetNumChannels(muteSoloItf, &numChannels);
    280     printf("GetNumChannels after Realize but before pre-fetch: result=%u, numChannels=%u\n",
    281         result, numChannels);
    282     if (result != SL_RESULT_PRECONDITIONS_VIOLATED) {
    283         ExitOnError(result);
    284     } else {
    285         printf("Warning: returning SL_RESULT_PRECONDITIONS_VIOLATED for unknown channel count is "
    286                 "obsolete; now it should return SL_RESULT_SUCCESS and zero count if unknown\n");
    287     }
    288 
    289     /* Initialize a context for use by the play event callback */
    290     Context             context;
    291     context.playItf = playItf;
    292     context.muteSoloItf = muteSoloItf;
    293     context.testMode = TEST_MUTE;
    294 
    295     /*  Setup to receive playback events on position updates */
    296     result = (*playItf)->RegisterCallback(playItf, PlayEventCallback, (void *) &context);
    297     ExitOnError(result);
    298     result = (*playItf)->SetCallbackEventsMask(playItf, SL_PLAYEVENT_HEADATNEWPOS);
    299     ExitOnError(result);
    300     result = (*playItf)->SetPositionUpdatePeriod(playItf, 1000);
    301     ExitOnError(result);
    302 
    303     fprintf(stdout, "Player configured\n");
    304 
    305     /* ------------------------------------------------------ */
    306     /* Playback and test */
    307 
    308     /* Start the data prefetching by setting the player to the paused state */
    309     result = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PAUSED );
    310     ExitOnError(result);
    311 
    312     // wait for prefetch status callback to indicate either sufficient data or error
    313     pthread_mutex_lock(&mutex);
    314     while (prefetch_status == SL_PREFETCHSTATUS_UNKNOWN) {
    315         pthread_cond_wait(&cond, &mutex);
    316     }
    317     pthread_mutex_unlock(&mutex);
    318     if (prefetch_status == SL_PREFETCHSTATUS_ERROR) {
    319         fprintf(stderr, "Error during prefetch, exiting\n");
    320         goto destroyKillKill;
    321     }
    322 
    323     /* Query the duration */
    324     result = (*playItf)->GetDuration(playItf, &duration);
    325     printf("GetDuration after Realize and after pre-fetch: result=%u, duration=%u\n",
    326         result, duration);
    327     ExitOnError(result);
    328 
    329     /* Query the number of channels */
    330     numChannels = 123;
    331     result = (*muteSoloItf)->GetNumChannels(muteSoloItf, &numChannels);
    332     printf("GetNumChannels after Realize and after pre-fetch: result=%u, numChannels=%u\n",
    333         result, numChannels);
    334     ExitOnError(result);
    335     fprintf(stdout, "Content has %d channel(s)\n", numChannels);
    336 
    337     if (numChannels == 1) {
    338         fprintf(stdout, "SLMuteSolotItf only works one content with more than one channel. Bye\n");
    339         goto destroyKillKill;
    340     } else {
    341         /* Mute left channel */
    342         result = (*muteSoloItf)->SetChannelMute(muteSoloItf, 0, SL_BOOLEAN_TRUE);
    343         ExitOnError(result);
    344         result = (*muteSoloItf)->SetChannelMute(muteSoloItf, 1, SL_BOOLEAN_FALSE);
    345         ExitOnError(result);
    346     }
    347 
    348     /* Run the test for 10s */
    349     /* see PlayEventCallback() for more of the test of the SLMuteSoloItf interface */
    350     fprintf(stdout, "\nTesting mute functionality:\n");
    351     context.testMode = TEST_MUTE;
    352     result = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PLAYING ); ExitOnError(result);
    353     usleep( 5 * 1000 * 1000);
    354     result = (*muteSoloItf)->SetChannelMute(muteSoloItf, 0, SL_BOOLEAN_FALSE); ExitOnError(result);
    355     result = (*muteSoloItf)->SetChannelMute(muteSoloItf, 1, SL_BOOLEAN_FALSE); ExitOnError(result);
    356     fprintf(stdout, "\nTesting solo functionality:\n");
    357     context.testMode = TEST_SOLO;
    358     usleep( 5 * 1000 * 1000);
    359 
    360     /* Make sure player is stopped */
    361     fprintf(stdout, "Stopping playback\n");
    362     result = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
    363     ExitOnError(result);
    364 
    365 destroyKillKill:
    366 
    367     /* Destroy the players */
    368     (*player)->Destroy(player);
    369 
    370     /* Destroy Output Mix object */
    371     (*outputMix)->Destroy(outputMix);
    372 }
    373 
    374 //-----------------------------------------------------------------
    375 int main(int argc, char* const argv[])
    376 {
    377     SLresult    result;
    378     SLObjectItf sl;
    379 
    380     fprintf(stdout, "OpenSL ES test %s: exercises SLPlayItf, SLVolumeItf, SLMuteSoloItf\n",
    381             argv[0]);
    382     fprintf(stdout, "and AudioPlayer with SLDataLocator_URI source / OutputMix sink\n");
    383     fprintf(stdout, "Plays a sound and alternates the muting of the channels (for 5s).\n");
    384     fprintf(stdout, " and then alternates the solo\'ing of the channels (for 5s).\n");
    385     fprintf(stdout, "Stops after 10s\n");
    386 
    387     if (argc == 1) {
    388         fprintf(stdout, "Usage: \t%s url\n", argv[0]);
    389         fprintf(stdout, "Example: \"%s /sdcard/my.mp3\"\n", argv[0]);
    390         exit(EXIT_FAILURE);
    391     }
    392 
    393     SLEngineOption EngineOption[] = {
    394             {(SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE}
    395     };
    396 
    397     result = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL);
    398     ExitOnError(result);
    399 
    400     /* Realizing the SL Engine in synchronous mode. */
    401     result = (*sl)->Realize(sl, SL_BOOLEAN_FALSE);
    402     ExitOnError(result);
    403 
    404     if (argc > 1) {
    405         TestPlayUri(sl, argv[1]);
    406     }
    407 
    408     /* Shutdown OpenSL ES */
    409     (*sl)->Destroy(sl);
    410 
    411     return EXIT_SUCCESS;
    412 }
    413