multiplay.c revision c2303eb5497c488db786dcb2b8514db229452536
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 28typedef struct { 29 SLObjectItf mPlayerObject; 30 SLPlayItf mPlayerPlay; 31 SLSeekItf mPlayerSeek; 32 SLVolumeItf mPlayerVolume; 33 SLmillisecond mPlayerDuration; 34} Player; 35 36// Strings corresponding to result codes; FIXME should move to a common test library 37 38static const char *result_strings[] = { 39 "SUCCESS", 40 "PRECONDITIONS_VIOLATED", 41 "PARAMETER_INVALID", 42 "MEMORY_FAILURE", 43 "RESOURCE_ERROR", 44 "RESOURCE_LOST", 45 "IO_ERROR", 46 "BUFFER_INSUFFICIENT", 47 "CONTENT_CORRUPTED", 48 "CONTENT_UNSUPPORTED", 49 "CONTENT_NOT_FOUND", 50 "PERMISSION_DENIED", 51 "FEATURE_UNSUPPORTED", 52 "INTERNAL_ERROR", 53 "UNKNOWN_ERROR", 54 "OPERATION_ABORTED", 55 "CONTROL_LOST" 56}; 57 58// Convert result to string; FIXME should move to common test library 59 60static const char *result_to_string(SLresult result) 61{ 62 static char buffer[32]; 63 if ( /* result >= 0 && */ result < sizeof(result_strings) / sizeof(result_strings[0])) 64 return result_strings[result]; 65 sprintf(buffer, "%d", (int) result); 66 return buffer; 67} 68 69// Compare result against expected and exit suddenly if wrong 70 71void check2(SLresult result, int line) 72{ 73 if (SL_RESULT_SUCCESS != result) { 74 fprintf(stderr, "error %s at line %d\n", result_to_string(result), line); 75 exit(EXIT_FAILURE); 76 } 77} 78 79// Same as above but automatically adds the source code line number 80 81#define check(result) check2(result, __LINE__) 82 83// Main program 84 85int main(int argc, char **argv) 86{ 87 int i; 88 const char *arg; 89 int numPlayers = 0; 90 SLmillibel mixVolumeLevel = 0; 91 for (i = 1; i < argc; ++i) { 92 arg = argv[i]; 93 if (arg[0] != '-') 94 break; 95 if (!strncmp(arg, "-n", 2)) 96 numPlayers = atoi(&arg[2]); 97 else if (!strncmp(arg, "-v", 2)) 98 mixVolumeLevel = atoi(&arg[2]); 99 else 100 fprintf(stderr, "unknown option: %s\n", arg); 101 } 102 int numPathnames = argc - i; 103 if (numPathnames <= 0) { 104 fprintf(stderr, "usage: %s file.wav ...\n", argv[0]); 105 return EXIT_FAILURE; 106 } 107 if (numPlayers <= 0) 108 numPlayers = numPathnames; 109 Player *players = (Player *) malloc(sizeof(Player) * numPlayers); 110 assert(NULL != players); 111 char **pathnames = &argv[i]; 112 SLresult result; 113 114 // engine 115 const SLInterfaceID engine_ids[] = {SL_IID_ENGINE}; 116 const SLboolean engine_req[] = {SL_BOOLEAN_TRUE}; 117 SLObjectItf engineObject; 118 result = slCreateEngine(&engineObject, 0, NULL, 1, engine_ids, engine_req); 119 check(result); 120 result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); 121 check(result); 122 SLEngineItf engineEngine; 123 result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine); 124 check(result); 125 126 // mixer 127 const SLInterfaceID mix_ids[] = {SL_IID_VOLUME}; 128 const SLboolean mix_req[] = {SL_BOOLEAN_TRUE}; 129 SLObjectItf mixObject; 130 result = (*engineEngine)->CreateOutputMix(engineEngine, &mixObject, 0, mix_ids, mix_req); 131 check(result); 132 result = (*mixObject)->Realize(mixObject, SL_BOOLEAN_FALSE); 133 check(result); 134#if 0 135 SLVolumeItf mixVolume; 136 result = (*mixObject)->GetInterface(mixObject, SL_IID_VOLUME, &mixVolume); 137 check(result); 138 SLmillibel mixVolumeLevelDefault; 139 result = (*mixVolume)->GetVolumeLevel(mixVolume, &mixVolumeLevelDefault); 140 check(result); 141 printf("default mix volume level = %d\n", mixVolumeLevelDefault); 142#endif 143 144 printf("numPathnames=%d\n", numPathnames); 145 printf("numPlayers=%d\n", numPlayers); 146 Player *p; 147 148 // create all the players 149 for (i = 0; i < numPlayers; ++i) { 150 const SLInterfaceID player_ids[] = {SL_IID_PLAY, SL_IID_VOLUME, SL_IID_SEEK}; 151 const SLboolean player_req[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; 152 p = &players[i]; 153 SLDataLocator_URI locURI = {SL_DATALOCATOR_URI, (SLchar *) pathnames[i % numPathnames]}; 154 SLDataFormat_MIME dfMIME = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED}; 155 SLDataSource audioSrc = {&locURI, &dfMIME}; 156 SLDataLocator_OutputMix locOutputMix = {SL_DATALOCATOR_OUTPUTMIX, mixObject}; 157 SLDataSink audioSnk = {&locOutputMix, NULL}; 158 result = (*engineEngine)->CreateAudioPlayer(engineEngine, &p->mPlayerObject, &audioSrc, 159 &audioSnk, 3, player_ids, player_req); 160 check(result); 161 result = (*p->mPlayerObject)->Realize(p->mPlayerObject, SL_BOOLEAN_FALSE); 162 check(result); 163 result = (*p->mPlayerObject)->GetInterface(p->mPlayerObject, SL_IID_PLAY, &p->mPlayerPlay); 164 check(result); 165 result = (*p->mPlayerObject)->GetInterface(p->mPlayerObject, SL_IID_VOLUME, 166 &p->mPlayerVolume); 167 check(result); 168 result = (*p->mPlayerObject)->GetInterface(p->mPlayerObject, SL_IID_SEEK, &p->mPlayerSeek); 169 check(result); 170 result = (*p->mPlayerPlay)->GetDuration(p->mPlayerPlay, &p->mPlayerDuration); 171 check(result); 172 printf("player %d duration %d\n", (int) i, (int) p->mPlayerDuration); 173 } 174 175 // now loop randomly doing things to the players 176 for (;;) { 177 SLmillisecond delay = 100 + (rand() & 1023); 178 printf("sleep %u\n", (unsigned) delay); 179 usleep(delay * 1000); 180 i = (rand() & 0x7FFFFFFF) % numPlayers; 181 printf("player %d ", i); 182 p = &players[i]; 183 SLuint32 state; 184 result = (*p->mPlayerPlay)->GetPlayState(p->mPlayerPlay, &state); 185 check(result); 186 printf("state = "); 187 switch (state) { 188 case SL_PLAYSTATE_STOPPED: 189 printf("STOPPED"); 190 break; 191 case SL_PLAYSTATE_PAUSED: 192 printf("PAUSED"); 193 break; 194 case SL_PLAYSTATE_PLAYING: 195 printf("PLAYING"); 196 break; 197 default: 198 printf("%u", (unsigned) state); 199 break; 200 } 201 printf("\n"); 202 if (state == SL_PLAYSTATE_STOPPED || state == SL_PLAYSTATE_PAUSED) { 203 SLmillibel volumeLevel = -((rand() & 0x7FFFFFFF) % ((SL_MILLIBEL_MIN + 1) / 10)); 204 printf("volume %d\n", volumeLevel); 205 result = (*p->mPlayerVolume)->SetVolumeLevel(p->mPlayerVolume, volumeLevel); 206 check(result); 207 result = (*p->mPlayerVolume)->EnableStereoPosition(p->mPlayerVolume, SL_BOOLEAN_TRUE); 208 check(result); 209 SLpermille stereoPosition = ((rand() & 0x7FFFFFFF) % 2001) - 1000; 210 printf("position %d\n", stereoPosition); 211 result = (*p->mPlayerVolume)->SetStereoPosition(p->mPlayerVolume, stereoPosition); 212 check(result); 213 if (state != SL_PLAYSTATE_STOPPED) { 214 result = (*p->mPlayerSeek)->SetPosition(p->mPlayerSeek, 0, SL_SEEKMODE_FAST); 215 check(result); 216 } 217 result = (*p->mPlayerPlay)->SetPlayState(p->mPlayerPlay, SL_PLAYSTATE_PLAYING); 218 check(result); 219 } 220 } 221 222 // FIXME It would be interesting to end the test on some condition (timer, key pressed) so it 223 // also exercises the destruction of the players, output mix and engine after this test has run. 224 225 // return EXIT_SUCCESS; 226} 227