slesTestSendToPresetReverb.cpp revision 7c7511aa96e54d94df836357fbbf76c681f20a26
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 <stdlib.h> 18#include <stdio.h> 19#include <string.h> 20#include <unistd.h> 21#include <sys/time.h> 22#include <fcntl.h> 23 24#include "SLES/OpenSLES.h" 25#ifdef ANDROID 26#include "SLES/OpenSLES_Android.h" 27#endif 28 29 30#define MAX_NUMBER_INTERFACES 3 31 32#define TIME_S_BETWEEN_SETTING_CHANGE 5 33 34//----------------------------------------------------------------- 35/* Exits the application if an error is encountered */ 36#define ExitOnError(x) ExitOnErrorFunc(x,__LINE__) 37 38void ExitOnErrorFunc( SLresult result , int line) 39{ 40 if (SL_RESULT_SUCCESS != result) { 41 fprintf(stderr, "%u error code encountered at line %d, exiting\n", result, line); 42 exit(EXIT_FAILURE); 43 } 44} 45 46 47//----------------------------------------------------------------- 48 49/* Play an audio path and feed a global reverb */ 50void TestSendToPresetReverb( SLObjectItf sl, const char* path, int preset, SLmillibel directLevel, 51 SLmillibel sendLevel, bool alwaysOn) 52{ 53 SLresult result; 54 SLEngineItf EngineItf; 55 56 /* Objects this application uses: one player and an ouput mix */ 57 SLObjectItf player, outputMix; 58 59 /* Source of audio data to play */ 60 SLDataSource audioSource; 61#ifdef ANDROID 62 SLDataLocator_AndroidFD locatorFd; 63#else 64 SLDataLocator_URI locatorUri; 65#endif 66 SLDataFormat_MIME mime; 67 68 /* Data sinks for the audio player */ 69 SLDataSink audioSink; 70 SLDataLocator_OutputMix locator_outputmix; 71 72 /* Interfaces for the audio player */ 73 SLPlayItf playItf; 74 SLPrefetchStatusItf prefetchItf; 75 SLEffectSendItf effectSendItf; 76 77 /* Interface for the output mix */ 78 SLPresetReverbItf reverbItf; 79 80 SLboolean required[MAX_NUMBER_INTERFACES]; 81 SLInterfaceID iidArray[MAX_NUMBER_INTERFACES]; 82 83 /* Get the SL Engine Interface which is implicit */ 84 result = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf); 85 ExitOnError(result); 86 87 /* Initialize arrays required[] and iidArray[] */ 88 for (int i=0 ; i < MAX_NUMBER_INTERFACES ; i++) { 89 required[i] = SL_BOOLEAN_FALSE; 90 iidArray[i] = SL_IID_NULL; 91 } 92 93 /* ------------------------------------------------------ */ 94 /* Configuration of the output mix */ 95 96 /* Set arrays required[] and iidArray[] for required interfaces */ 97 required[0] = SL_BOOLEAN_TRUE; 98 iidArray[0] = SL_IID_PRESETREVERB; 99 100 /* Create Output Mix object to be used by the player */ 101 result = (*EngineItf)->CreateOutputMix(EngineItf, &outputMix, 1, iidArray, required); 102 ExitOnError(result); 103 104 /* Realize the Output Mix object in synchronous mode */ 105 result = (*outputMix)->Realize(outputMix, SL_BOOLEAN_FALSE); 106 ExitOnError(result); 107 108 /* Get the SLPresetReverbItf for the output mix */ 109 result = (*outputMix)->GetInterface(outputMix, SL_IID_PRESETREVERB, (void*)&reverbItf); 110 ExitOnError(result); 111 112 /* Setup the data sink structure */ 113 locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; 114 locator_outputmix.outputMix = outputMix; 115 audioSink.pLocator = (void*)&locator_outputmix; 116 audioSink.pFormat = NULL; 117 118 /* Select the reverb preset */ 119 fprintf(stdout, "\nUsing preset "); 120 switch(preset) { 121 case SL_REVERBPRESET_NONE: 122 fprintf(stdout, "SL_REVERBPRESET_NONE, don't expect to hear reverb\n"); 123 break; 124 case SL_REVERBPRESET_SMALLROOM: fprintf(stdout, "SL_REVERBPRESET_SMALLROOM\n"); break; 125 case SL_REVERBPRESET_MEDIUMROOM: fprintf(stdout, "SL_REVERBPRESET_MEDIUMROOM\n"); break; 126 case SL_REVERBPRESET_LARGEROOM: fprintf(stdout, "SL_REVERBPRESET_LARGEROOM\n"); break; 127 case SL_REVERBPRESET_MEDIUMHALL: fprintf(stdout, "SL_REVERBPRESET_MEDIUMHALL\n"); break; 128 case SL_REVERBPRESET_LARGEHALL: fprintf(stdout, "SL_REVERBPRESET_LARGEHALL\n"); break; 129 case SL_REVERBPRESET_PLATE: fprintf(stdout, "SL_REVERBPRESET_PLATE\n"); break; 130 default: 131 fprintf(stdout, "unknown, use at your own risk\n"); break; 132 } 133 result = (*reverbItf)->SetPreset(reverbItf, preset); 134 ExitOnError(result); 135 136 /* ------------------------------------------------------ */ 137 /* Configuration of the player */ 138 139 /* Set arrays required[] and iidArray[] for required interfaces */ 140 /* (SLPlayItf is implicit) */ 141 required[0] = SL_BOOLEAN_TRUE; 142 iidArray[0] = SL_IID_PREFETCHSTATUS; 143 required[1] = SL_BOOLEAN_TRUE; 144 iidArray[1] = SL_IID_EFFECTSEND; 145 146#ifdef ANDROID 147 /* Setup the data source structure for the URI */ 148 locatorFd.locatorType = SL_DATALOCATOR_ANDROIDFD; 149 int fd = open(path, O_RDONLY); 150 if (fd == -1) { 151 ExitOnError(SL_RESULT_RESOURCE_ERROR); 152 } 153 locatorFd.fd = (SLint32) fd; 154 locatorFd.length = SL_DATALOCATOR_ANDROIDFD_USE_FILE_SIZE; 155 locatorFd.offset = 0; 156#else 157 locatorUri.locatorType = SL_DATALOCATOR_URI; 158 locatorUri.URI = (SLchar *) path; 159#endif 160 161 mime.formatType = SL_DATAFORMAT_MIME; 162 /* this is how ignored mime information is specified, according to OpenSL ES spec 163 * in 9.1.6 SLDataFormat_MIME and 8.23 SLMetadataTraversalItf GetChildInfo */ 164 mime.mimeType = (SLchar*)NULL; 165 mime.containerType = SL_CONTAINERTYPE_UNSPECIFIED; 166 167 audioSource.pFormat = (void*)&mime; 168#ifdef ANDROID 169 audioSource.pLocator = (void*)&locatorFd; 170#else 171 audioSource.pLocator = (void*)&locatorUri; 172#endif 173 174 /* Create the audio player */ 175 result = (*EngineItf)->CreateAudioPlayer(EngineItf, &player, &audioSource, &audioSink, 2, 176 iidArray, required); 177 ExitOnError(result); 178 179 /* Realize the player in synchronous mode. */ 180 result = (*player)->Realize(player, SL_BOOLEAN_FALSE); ExitOnError(result); 181 fprintf(stdout, "URI example: after Realize\n"); 182 183 /* Get the SLPlayItf, SLPrefetchStatusItf and SLEffectSendItf interfaces for the player*/ 184 result = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf); 185 ExitOnError(result); 186 187 result = (*player)->GetInterface(player, SL_IID_PREFETCHSTATUS, (void*)&prefetchItf); 188 ExitOnError(result); 189 190 result = (*player)->GetInterface(player, SL_IID_EFFECTSEND, (void*)&effectSendItf); 191 ExitOnError(result); 192 193 fprintf(stdout, "Player configured\n"); 194 195 /* ------------------------------------------------------ */ 196 /* Playback and test */ 197 198 /* Start the data prefetching by setting the player to the paused state */ 199 result = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PAUSED ); 200 ExitOnError(result); 201 202 /* Wait until there's data to play */ 203 SLuint32 prefetchStatus = SL_PREFETCHSTATUS_UNDERFLOW; 204 while (prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) { 205 usleep(100 * 1000); 206 (*prefetchItf)->GetPrefetchStatus(prefetchItf, &prefetchStatus); 207 ExitOnError(result); 208 } 209 210 /* Get duration */ 211 SLmillisecond durationInMsec = SL_TIME_UNKNOWN; 212 result = (*playItf)->GetDuration(playItf, &durationInMsec); 213 ExitOnError(result); 214 if (durationInMsec == SL_TIME_UNKNOWN) { 215 durationInMsec = 10000; 216 } 217 218 /* Feed the output mix' reverb from the audio player using the given send level */ 219 result = (*effectSendItf)->EnableEffectSend(effectSendItf, reverbItf, SL_BOOLEAN_TRUE, 220 sendLevel); 221 ExitOnError(result); 222 223 result = (*effectSendItf)->SetDirectLevel(effectSendItf, directLevel); 224 ExitOnError(result); 225 fprintf(stdout, "Set direct level to %dmB\n", directLevel); 226 227 result = (*effectSendItf)->SetSendLevel(effectSendItf, reverbItf, sendLevel); 228 ExitOnError(result); 229 fprintf(stdout, "Set send level to %dmB\n", sendLevel); 230 231 /* Start playback */ 232 result = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PLAYING ); 233 ExitOnError(result); 234 235 /* Disable preset reverb every TIME_S_BETWEEN_SETTING_CHANGE seconds unless always on */ 236 SLboolean previousEnabled = SL_BOOLEAN_FALSE; 237 for(unsigned int j=0 ; j<(durationInMsec/(1000*TIME_S_BETWEEN_SETTING_CHANGE)) ; j++) { 238 SLboolean enabled; 239 enabled = alwaysOn || !previousEnabled; 240 if (enabled != previousEnabled) { 241 result = (*reverbItf)->SetPreset(reverbItf, enabled ? preset : SL_REVERBPRESET_NONE); 242 fprintf(stdout, "SetPreset(%d)=%d", enabled ? preset : SL_REVERBPRESET_NONE, result); 243 //ExitOnError(result); 244 previousEnabled = enabled; 245 if (enabled) { 246 fprintf(stdout, "Reverb on\n"); 247 } else { 248 fprintf(stdout, "Reverb off\n"); 249 } 250 } 251 usleep(TIME_S_BETWEEN_SETTING_CHANGE * 1000 * 1000); 252 } 253 254 /* Make sure player is stopped */ 255 fprintf(stdout, "Stopping playback\n"); 256 result = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED); 257 ExitOnError(result); 258 259 /* Destroy the player */ 260 (*player)->Destroy(player); 261 262 /* Destroy Output Mix object */ 263 (*outputMix)->Destroy(outputMix); 264 265#ifdef ANDROID 266 close(fd); 267#endif 268} 269 270//----------------------------------------------------------------- 271int main(int argc, char* const argv[]) 272{ 273 const char *programName = argv[0]; 274 SLresult result; 275 SLObjectItf sl; 276 277 fprintf(stdout, "OpenSL ES test %s: exercises SLEffectSendItf ", programName); 278 fprintf(stdout, "on AudioPlayer and SLPresetReverbItf on OutputMix.\n"); 279 fprintf(stdout, "Plays the sound file designated by the given path, "); 280 fprintf(stdout, "and sends a specified amount of energy to a global reverb\n"); 281 fprintf(stdout, "(sendLevel in mB), with a given direct level (in mB).\n"); 282 fprintf(stdout, "Every %d seconds, the reverb turned on and off,\n", 283 TIME_S_BETWEEN_SETTING_CHANGE); 284 fprintf(stdout, "unless the --always-on option is specified before the path.\n"); 285 286 bool alwaysOn = false; 287 if (argc >= 2 && !strcmp(argv[1], "--always-on")) { 288 alwaysOn = true; 289 --argc; 290 ++argv; 291 } 292 293 if (argc < 5) { 294 fprintf(stdout, "Usage: \t%s [--always-on] path preset directLevel sendLevel\n", 295 programName); 296 fprintf(stdout, "Example: \"%s /sdcard/my.mp3 6 -2000 0\" \n", programName); 297 exit(EXIT_FAILURE); 298 } 299 300 SLEngineOption EngineOption[] = { 301 {(SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE} 302 }; 303 304 result = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL); 305 ExitOnError(result); 306 307 /* Realizing the SL Engine in synchronous mode. */ 308 result = (*sl)->Realize(sl, SL_BOOLEAN_FALSE); 309 ExitOnError(result); 310 311 // intentionally not checking that levels are of correct value 312 TestSendToPresetReverb(sl, argv[1], atoi(argv[2]), (SLmillibel)atoi(argv[3]), 313 (SLmillibel)atoi(argv[4]), alwaysOn); 314 315 /* Shutdown OpenSL ES */ 316 (*sl)->Destroy(sl); 317 318 return EXIT_SUCCESS; 319} 320