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 39void 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 52SLboolean errorInPrefetchCallback = SL_BOOLEAN_FALSE; 53 54void 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 */ 72void 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//----------------------------------------------------------------- 326int 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