Home | History | Annotate | Download | only in sandbox
      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 // multiplay is a command-line test app that plays multiple files randomly
     18 
     19 #include <SLES/OpenSLES.h>
     20 #include <assert.h>
     21 #include <string.h>
     22 #include <stdlib.h>
     23 #include <stdio.h>
     24 #include <unistd.h>
     25 
     26 // Describes the state of one player
     27 
     28 typedef struct {
     29     SLObjectItf mPlayerObject;
     30     SLPlayItf mPlayerPlay;
     31     SLSeekItf mPlayerSeek;
     32     SLPrefetchStatusItf mPlayerPrefetchStatus;
     33     SLVolumeItf mPlayerVolume;
     34     SLmillisecond mPlayerDuration;
     35     SLboolean mPlayerErrorInCallback;
     36     SLboolean mPlayerErrorReported;
     37 } Player;
     38 
     39 // Strings corresponding to result codes; FIXME should move to a common test library
     40 
     41 static const char *result_strings[] = {
     42     "SUCCESS",
     43     "PRECONDITIONS_VIOLATED",
     44     "PARAMETER_INVALID",
     45     "MEMORY_FAILURE",
     46     "RESOURCE_ERROR",
     47     "RESOURCE_LOST",
     48     "IO_ERROR",
     49     "BUFFER_INSUFFICIENT",
     50     "CONTENT_CORRUPTED",
     51     "CONTENT_UNSUPPORTED",
     52     "CONTENT_NOT_FOUND",
     53     "PERMISSION_DENIED",
     54     "FEATURE_UNSUPPORTED",
     55     "INTERNAL_ERROR",
     56     "UNKNOWN_ERROR",
     57     "OPERATION_ABORTED",
     58     "CONTROL_LOST"
     59 };
     60 
     61 // Convert result to string; FIXME should move to common test library
     62 
     63 static const char *result_to_string(SLresult result)
     64 {
     65     static char buffer[32];
     66     if ( /* result >= 0 && */ result < sizeof(result_strings) / sizeof(result_strings[0]))
     67         return result_strings[result];
     68     sprintf(buffer, "%d", (int) result);
     69     return buffer;
     70 }
     71 
     72 // Compare result against expected and exit suddenly if wrong
     73 
     74 void check2(SLresult result, int line)
     75 {
     76     if (SL_RESULT_SUCCESS != result) {
     77         fprintf(stderr, "error %s at line %d\n", result_to_string(result), line);
     78         exit(EXIT_FAILURE);
     79     }
     80 }
     81 
     82 // Same as above but automatically adds the source code line number
     83 
     84 #define check(result) check2(result, __LINE__)
     85 
     86 // Prefetch status callback
     87 
     88 #define PREFETCHEVENT_ERROR_CANDIDATE \
     89             (SL_PREFETCHEVENT_STATUSCHANGE | SL_PREFETCHEVENT_FILLLEVELCHANGE)
     90 
     91 void prefetch_callback(SLPrefetchStatusItf caller, void *context, SLuint32 event)
     92 {
     93     SLresult result;
     94     assert(context != NULL);
     95     Player *p = (Player *) context;
     96     assert(p->mPlayerPrefetchStatus == caller);
     97     SLpermille level;
     98     result = (*caller)->GetFillLevel(caller, &level);
     99     check(result);
    100     SLuint32 status;
    101     result = (*caller)->GetPrefetchStatus(caller, &status);
    102     check(result);
    103     //fprintf(stderr, "PrefetchEventCallback: received event %u, level %u, status %u\n",
    104     //      event, level, status);
    105     if ((PREFETCHEVENT_ERROR_CANDIDATE == (event & PREFETCHEVENT_ERROR_CANDIDATE))
    106             && (level == 0) && (status == SL_PREFETCHSTATUS_UNDERFLOW)) {
    107         p->mPlayerErrorInCallback = SL_BOOLEAN_TRUE;
    108     }
    109 }
    110 
    111 // Main program
    112 
    113 int main(int argc, char **argv)
    114 {
    115     int i;
    116     const char *arg;
    117     int numPlayers = 0;
    118     int playTimeInMilliseconds = 0; // default to run forever
    119     SLmillibel mixVolumeLevel = 0;
    120     for (i = 1; i < argc; ++i) {
    121         arg = argv[i];
    122         if (arg[0] != '-')
    123             break;
    124         if (!strncmp(arg, "-n", 2))
    125             numPlayers = atoi(&arg[2]);
    126         else if (!strncmp(arg, "-v", 2))
    127             mixVolumeLevel = atoi(&arg[2]);
    128         else if (!strncmp(arg, "-t", 2))
    129             playTimeInMilliseconds = atoi(&arg[2]) * 1000;
    130         else
    131             fprintf(stderr, "unknown option: %s\n", arg);
    132     }
    133     int numPathnames = argc - i;
    134     if (numPathnames <= 0) {
    135         fprintf(stderr, "usage: %s file.wav ...\n", argv[0]);
    136         return EXIT_FAILURE;
    137     }
    138     if (numPlayers <= 0) {
    139         numPlayers = numPathnames;
    140     }
    141     Player *players = (Player *) calloc(numPlayers, sizeof(Player));
    142     assert(NULL != players);
    143     char **pathnames = &argv[i];
    144     SLresult result;
    145 
    146     // engine
    147     const SLInterfaceID engine_ids[] = {SL_IID_ENGINE};
    148     const SLboolean engine_req[] = {SL_BOOLEAN_TRUE};
    149     SLObjectItf engineObject;
    150     result = slCreateEngine(&engineObject, 0, NULL, 1, engine_ids, engine_req);
    151     check(result);
    152     result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
    153     check(result);
    154     SLEngineItf engineEngine;
    155     result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
    156     check(result);
    157 
    158     // mixer
    159     const SLInterfaceID mix_ids[] = {SL_IID_VOLUME};
    160     const SLboolean mix_req[] = {SL_BOOLEAN_TRUE};
    161     SLObjectItf mixObject;
    162     result = (*engineEngine)->CreateOutputMix(engineEngine, &mixObject, 0, mix_ids, mix_req);
    163     check(result);
    164     result = (*mixObject)->Realize(mixObject, SL_BOOLEAN_FALSE);
    165     check(result);
    166 #if 0
    167     SLVolumeItf mixVolume;
    168     result = (*mixObject)->GetInterface(mixObject, SL_IID_VOLUME, &mixVolume);
    169     check(result);
    170     SLmillibel mixVolumeLevelDefault;
    171     result = (*mixVolume)->GetVolumeLevel(mixVolume, &mixVolumeLevelDefault);
    172     check(result);
    173     printf("default mix volume level = %d\n", mixVolumeLevelDefault);
    174 #endif
    175 
    176     printf("numPathnames=%d\n", numPathnames);
    177     printf("numPlayers=%d\n", numPlayers);
    178     Player *p;
    179 
    180     // create all the players
    181     for (i = 0; i < numPlayers; ++i) {
    182         const SLInterfaceID player_ids[] =
    183                 {SL_IID_PLAY, SL_IID_VOLUME, SL_IID_SEEK, SL_IID_PREFETCHSTATUS};
    184         const SLboolean player_req[] =
    185                 {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
    186         p = &players[i];
    187         SLDataLocator_URI locURI = {SL_DATALOCATOR_URI, (SLchar *) pathnames[i % numPathnames]};
    188         SLDataFormat_MIME dfMIME = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED};
    189         SLDataSource audioSrc = {&locURI, &dfMIME};
    190         SLDataLocator_OutputMix locOutputMix = {SL_DATALOCATOR_OUTPUTMIX, mixObject};
    191         SLDataSink audioSnk = {&locOutputMix, NULL};
    192         result = (*engineEngine)->CreateAudioPlayer(engineEngine, &p->mPlayerObject, &audioSrc,
    193             &audioSnk, sizeof(player_ids)/sizeof(player_ids[0]), player_ids, player_req);
    194         check(result);
    195         result = (*p->mPlayerObject)->Realize(p->mPlayerObject, SL_BOOLEAN_FALSE);
    196         check(result);
    197         result = (*p->mPlayerObject)->GetInterface(p->mPlayerObject, SL_IID_PLAY, &p->mPlayerPlay);
    198         check(result);
    199         result = (*p->mPlayerObject)->GetInterface(p->mPlayerObject, SL_IID_VOLUME,
    200             &p->mPlayerVolume);
    201         check(result);
    202         result = (*p->mPlayerObject)->GetInterface(p->mPlayerObject, SL_IID_SEEK, &p->mPlayerSeek);
    203         check(result);
    204         result = (*p->mPlayerObject)->GetInterface(p->mPlayerObject, SL_IID_PREFETCHSTATUS,
    205                 &p->mPlayerPrefetchStatus);
    206         check(result);
    207         result = (*p->mPlayerPrefetchStatus)->RegisterCallback(p->mPlayerPrefetchStatus,
    208                 prefetch_callback, p);
    209         check(result);
    210         result = (*p->mPlayerPrefetchStatus)->SetCallbackEventsMask(p->mPlayerPrefetchStatus,
    211                 SL_PREFETCHEVENT_STATUSCHANGE | SL_PREFETCHEVENT_FILLLEVELCHANGE);
    212         check(result);
    213     }
    214 
    215     // now loop randomly doing things to the players
    216     for (;;) {
    217         SLmillisecond delay = 100 + (rand() & 1023);
    218         printf("sleep %u\n", (unsigned) delay);
    219         usleep(delay * 1000);
    220         i = (rand() & 0x7FFFFFFF) % numPlayers;
    221         p = &players[i];
    222         if (p->mPlayerErrorReported)
    223             continue;
    224         printf("player %d (%s): ", i, pathnames[i]);
    225         if (p->mPlayerErrorInCallback && !p->mPlayerErrorReported) {
    226             printf("error, ");
    227             p->mPlayerErrorReported = SL_BOOLEAN_TRUE;
    228         }
    229         result = (*p->mPlayerPlay)->GetDuration(p->mPlayerPlay, &p->mPlayerDuration);
    230         check(result);
    231         if (p->mPlayerDuration == SL_TIME_UNKNOWN) {
    232             printf("duration unknown, ");
    233         } else {
    234             printf("duration %d ms, ", (int) p->mPlayerDuration);
    235         }
    236         SLuint32 state;
    237         result = (*p->mPlayerPlay)->GetPlayState(p->mPlayerPlay, &state);
    238         check(result);
    239         printf("state = ");
    240         switch (state) {
    241         case SL_PLAYSTATE_STOPPED:
    242             printf("STOPPED");
    243             break;
    244         case SL_PLAYSTATE_PAUSED:
    245             printf("PAUSED");
    246             break;
    247         case SL_PLAYSTATE_PLAYING:
    248             printf("PLAYING");
    249             break;
    250         default:
    251             printf("%u", (unsigned) state);
    252             break;
    253         }
    254         printf("\n");
    255         if (state == SL_PLAYSTATE_STOPPED || state == SL_PLAYSTATE_PAUSED) {
    256             SLmillibel volumeLevel = -((rand() & 0x7FFFFFFF) % ((SL_MILLIBEL_MIN + 1) / 10));
    257             printf("volume %d\n", volumeLevel);
    258             result = (*p->mPlayerVolume)->SetVolumeLevel(p->mPlayerVolume, volumeLevel);
    259             check(result);
    260             result = (*p->mPlayerVolume)->EnableStereoPosition(p->mPlayerVolume, SL_BOOLEAN_TRUE);
    261             check(result);
    262             SLpermille stereoPosition = ((rand() & 0x7FFFFFFF) % 2001) - 1000;
    263             printf("position %d\n", stereoPosition);
    264             result = (*p->mPlayerVolume)->SetStereoPosition(p->mPlayerVolume, stereoPosition);
    265             check(result);
    266             if (state != SL_PLAYSTATE_STOPPED) {
    267                 result = (*p->mPlayerSeek)->SetPosition(p->mPlayerSeek, 0, SL_SEEKMODE_FAST);
    268                 check(result);
    269             }
    270             result = (*p->mPlayerPlay)->SetPlayState(p->mPlayerPlay, SL_PLAYSTATE_PLAYING);
    271             check(result);
    272         }
    273         if ((playTimeInMilliseconds > 0) && ((playTimeInMilliseconds -= delay) < 0))
    274             break;
    275     }
    276 
    277     for (i = 0; i < numPlayers; ++i) {
    278         SLObjectItf playerObject = players[i].mPlayerObject;
    279         (*playerObject)->Destroy(playerObject);
    280     }
    281     (*mixObject)->Destroy(mixObject);
    282     (*engineObject)->Destroy(engineObject);
    283 
    284     return EXIT_SUCCESS;
    285 }
    286