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 23 #include "SLES/OpenSLES.h" 24 25 26 #define MAX_NUMBER_INTERFACES 3 27 28 #define TEST_MUTE 0 29 #define TEST_SOLO 1 30 31 typedef struct { 32 int testMode; 33 SLPlayItf playItf; 34 SLMuteSoloItf muteSoloItf; 35 } Context; 36 37 //----------------------------------------------------------------- 38 /* Exits the application if an error is encountered */ 39 #define ExitOnError(x) ExitOnErrorFunc(x,__LINE__) 40 41 void ExitOnErrorFunc( SLresult result , int line) 42 { 43 if (SL_RESULT_SUCCESS != result) { 44 fprintf(stdout, "%lu error code encountered at line %d, exiting\n", result, line); 45 exit(EXIT_FAILURE); 46 } 47 } 48 49 //----------------------------------------------------------------- 50 /* PlayItf callback for an audio player, will be called for every SL_PLAYEVENT_HEADATNEWPOS event */ 51 void PlayEventCallback( SLPlayItf caller, void *pContext, SLuint32 event) 52 { 53 Context *context = (Context *) pContext; 54 SLPlayItf playItf = context->playItf; 55 SLMuteSoloItf muteSolo = context->muteSoloItf; 56 SLuint8 numChannels = 0; 57 SLresult res = (*muteSolo)->GetNumChannels(muteSolo, &numChannels); ExitOnError(res); 58 //fprintf(stdout, "Content has %d channel(s)\n", numChannels); 59 SLmillisecond position; 60 res = (*playItf)->GetPosition(playItf, &position); ExitOnError(res); 61 printf("position=%u\n", (unsigned) position); 62 63 switch (context->testMode) { 64 case TEST_MUTE: { 65 //--------------------------------------------------- 66 if (numChannels > 1) { // SLMuteSoloItf only works if more than one channel 67 SLboolean leftMuted = SL_BOOLEAN_TRUE; 68 res = (*muteSolo)->GetChannelMute(muteSolo, 0, &leftMuted); ExitOnError(res); 69 // swap channel mute 70 res = (*muteSolo)->SetChannelMute(muteSolo, 0, 71 leftMuted == SL_BOOLEAN_TRUE ? SL_BOOLEAN_FALSE : SL_BOOLEAN_TRUE); 72 ExitOnError(res); 73 res = (*muteSolo)->SetChannelMute(muteSolo, 1, 74 leftMuted == SL_BOOLEAN_TRUE ? SL_BOOLEAN_TRUE : SL_BOOLEAN_FALSE); 75 ExitOnError(res); 76 if (leftMuted == SL_BOOLEAN_TRUE) { // we've swapped the channel mute above 77 fprintf(stdout, "channel 0: playing, channel 1: muted\n"); 78 } else { 79 fprintf(stdout, "channel 0: muted, channel 1: playing\n"); 80 } 81 } 82 } break; 83 84 case TEST_SOLO: { 85 //--------------------------------------------------- 86 if (numChannels > 1) { // SLMuteSoloItf only works if more than one channel 87 SLboolean leftSoloed = SL_BOOLEAN_TRUE; 88 res = (*muteSolo)->GetChannelSolo(muteSolo, 0, &leftSoloed); ExitOnError(res); 89 // swap channel solo 90 res = (*muteSolo)->SetChannelSolo(muteSolo, 0, 91 leftSoloed == SL_BOOLEAN_TRUE ? SL_BOOLEAN_FALSE : SL_BOOLEAN_TRUE); 92 ExitOnError(res); 93 res = (*muteSolo)->SetChannelSolo(muteSolo, 1, 94 leftSoloed == SL_BOOLEAN_TRUE ? SL_BOOLEAN_TRUE : SL_BOOLEAN_FALSE); 95 ExitOnError(res); 96 if (leftSoloed == SL_BOOLEAN_TRUE) { // we've swapped the channel solo above 97 fprintf(stdout, "channel 0: normal, channel 1: soloed\n"); 98 } else { 99 fprintf(stdout, "channel 0: soloed, channel 1: normal\n"); 100 } 101 } 102 } break; 103 104 default: 105 break; 106 } 107 } 108 109 //----------------------------------------------------------------- 110 111 /* Play an audio URIs, mute and solo channels */ 112 void TestPlayUri( SLObjectItf sl, const char* path) 113 { 114 SLresult result; 115 SLEngineItf EngineItf; 116 117 /* Objects this application uses: one player and an ouput mix */ 118 SLObjectItf player, outputMix; 119 120 /* Source of audio data to play */ 121 SLDataSource audioSource; 122 SLDataLocator_URI uri; 123 SLDataFormat_MIME mime; 124 125 /* Data sinks for the audio player */ 126 SLDataSink audioSink; 127 SLDataLocator_OutputMix locator_outputmix; 128 129 /* Play, Volume and PrefetchStatus interfaces for the audio player */ 130 SLPlayItf playItf; 131 SLMuteSoloItf muteSoloItf; 132 SLPrefetchStatusItf prefetchItf; 133 134 SLboolean required[MAX_NUMBER_INTERFACES]; 135 SLInterfaceID iidArray[MAX_NUMBER_INTERFACES]; 136 137 /* Get the SL Engine Interface which is implicit */ 138 result = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf); 139 ExitOnError(result); 140 141 /* Initialize arrays required[] and iidArray[] */ 142 for (int i=0 ; i < MAX_NUMBER_INTERFACES ; i++) { 143 required[i] = SL_BOOLEAN_FALSE; 144 iidArray[i] = SL_IID_NULL; 145 } 146 147 /* ------------------------------------------------------ */ 148 /* Configuration of the output mix */ 149 150 /* Create Output Mix object to be used by the player */ 151 result = (*EngineItf)->CreateOutputMix(EngineItf, &outputMix, 0, iidArray, required); 152 ExitOnError(result); 153 154 /* Realize the Output Mix object in synchronous mode */ 155 result = (*outputMix)->Realize(outputMix, SL_BOOLEAN_FALSE); 156 ExitOnError(result); 157 158 /* Setup the data sink structure */ 159 locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; 160 locator_outputmix.outputMix = outputMix; 161 audioSink.pLocator = (void*)&locator_outputmix; 162 audioSink.pFormat = NULL; 163 164 /* ------------------------------------------------------ */ 165 /* Configuration of the player */ 166 167 /* Set arrays required[] and iidArray[] for SLMuteSoloItf and SLPrefetchStatusItf interfaces */ 168 /* (SLPlayItf is implicit) */ 169 required[0] = SL_BOOLEAN_TRUE; 170 iidArray[0] = SL_IID_MUTESOLO; 171 required[1] = SL_BOOLEAN_TRUE; 172 iidArray[1] = SL_IID_PREFETCHSTATUS; 173 174 /* Setup the data source structure for the URI */ 175 uri.locatorType = SL_DATALOCATOR_URI; 176 uri.URI = (SLchar*) path; 177 mime.formatType = SL_DATAFORMAT_MIME; 178 /* this is how ignored mime information is specified, according to OpenSL ES spec 179 * in 9.1.6 SLDataFormat_MIME and 8.23 SLMetadataTraversalItf GetChildInfo */ 180 mime.mimeType = (SLchar*)NULL; 181 mime.containerType = SL_CONTAINERTYPE_UNSPECIFIED; 182 183 audioSource.pFormat = (void*)&mime; 184 audioSource.pLocator = (void*)&uri; 185 186 /* Create the audio player */ 187 result = (*EngineItf)->CreateAudioPlayer(EngineItf, &player, &audioSource, &audioSink, 2, 188 iidArray, required); 189 ExitOnError(result); 190 191 /* Realize the player in synchronous mode. */ 192 result = (*player)->Realize(player, SL_BOOLEAN_FALSE); ExitOnError(result); 193 fprintf(stdout, "URI example: after Realize\n"); 194 195 /* Get the SLPlayItf, SLPrefetchStatusItf and SLMuteSoloItf interfaces for the player */ 196 result = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf); 197 ExitOnError(result); 198 199 result = (*player)->GetInterface(player, SL_IID_PREFETCHSTATUS, (void*)&prefetchItf); 200 ExitOnError(result); 201 202 result = (*player)->GetInterface(player, SL_IID_MUTESOLO, (void*)&muteSoloItf); 203 ExitOnError(result); 204 205 // Attempt to get the channel count before it is necessarily known. 206 // This may fail depending on the platform. 207 SLuint8 numChannels = 123; 208 result = (*muteSoloItf)->GetNumChannels(muteSoloItf, &numChannels); 209 printf("GetNumChannels after Realize but before pre-fetch: result=%lu, numChannels=%u\n", 210 result, numChannels); 211 212 /* Initialize a context for use by the callback */ 213 Context context; 214 context.playItf = playItf; 215 context.muteSoloItf = muteSoloItf; 216 context.testMode = TEST_MUTE; 217 218 /* Setup to receive playback events on position updates */ 219 result = (*playItf)->RegisterCallback(playItf, PlayEventCallback, (void *) &context); 220 ExitOnError(result); 221 result = (*playItf)->SetCallbackEventsMask(playItf, SL_PLAYEVENT_HEADATNEWPOS); 222 ExitOnError(result); 223 result = (*playItf)->SetPositionUpdatePeriod(playItf, 1000); 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 usleep(100 * 1000); 239 (*prefetchItf)->GetPrefetchStatus(prefetchItf, &prefetchStatus); 240 } 241 242 /* Query the number of channels */ 243 numChannels = 123; 244 result = (*muteSoloItf)->GetNumChannels(muteSoloItf, &numChannels); 245 ExitOnError(result); 246 fprintf(stdout, "Content has %d channel(s)\n", numChannels); 247 248 if (numChannels == 1) { 249 fprintf(stdout, "SLMuteSolotItf only works one content with more than one channel. Bye\n"); 250 goto destroyKillKill; 251 } else { 252 /* Mute left channel */ 253 result = (*muteSoloItf)->SetChannelMute(muteSoloItf, 0, SL_BOOLEAN_TRUE); 254 ExitOnError(result); 255 result = (*muteSoloItf)->SetChannelMute(muteSoloItf, 1, SL_BOOLEAN_FALSE); 256 ExitOnError(result); 257 } 258 259 /* Run the test for 10s */ 260 /* see PlayEventCallback() for more of the test of the SLMuteSoloItf interface */ 261 fprintf(stdout, "\nTesting mute functionality:\n"); 262 context.testMode = TEST_MUTE; 263 result = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PLAYING ); ExitOnError(result); 264 usleep( 5 * 1000 * 1000); 265 result = (*muteSoloItf)->SetChannelMute(muteSoloItf, 0, SL_BOOLEAN_FALSE); ExitOnError(result); 266 result = (*muteSoloItf)->SetChannelMute(muteSoloItf, 1, SL_BOOLEAN_FALSE); ExitOnError(result); 267 fprintf(stdout, "\nTesting solo functionality:\n"); 268 context.testMode = TEST_SOLO; 269 usleep( 5 * 1000 * 1000); 270 271 /* Make sure player is stopped */ 272 fprintf(stdout, "Stopping playback\n"); 273 result = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED); 274 ExitOnError(result); 275 276 destroyKillKill: 277 278 /* Destroy the players */ 279 (*player)->Destroy(player); 280 281 /* Destroy Output Mix object */ 282 (*outputMix)->Destroy(outputMix); 283 } 284 285 //----------------------------------------------------------------- 286 int main(int argc, char* const argv[]) 287 { 288 SLresult result; 289 SLObjectItf sl; 290 291 fprintf(stdout, "OpenSL ES test %s: exercises SLPlayItf, SLVolumeItf, SLMuteSoloItf\n", 292 argv[0]); 293 fprintf(stdout, "and AudioPlayer with SLDataLocator_URI source / OutputMix sink\n"); 294 fprintf(stdout, "Plays a sound and alternates the muting of the channels (for 5s).\n"); 295 fprintf(stdout, " and then alternates the solo\'ing of the channels (for 5s).\n"); 296 fprintf(stdout, "Stops after 10s\n"); 297 298 if (argc == 1) { 299 fprintf(stdout, "Usage: \t%s url\n", argv[0]); 300 fprintf(stdout, "Example: \"%s /sdcard/my.mp3\"\n", argv[0]); 301 exit(EXIT_FAILURE); 302 } 303 304 SLEngineOption EngineOption[] = { 305 {(SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE} 306 }; 307 308 result = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL); 309 ExitOnError(result); 310 311 /* Realizing the SL Engine in synchronous mode. */ 312 result = (*sl)->Realize(sl, SL_BOOLEAN_FALSE); 313 ExitOnError(result); 314 315 if (argc > 1) { 316 TestPlayUri(sl, argv[1]); 317 } 318 319 /* Shutdown OpenSL ES */ 320 (*sl)->Destroy(sl); 321 322 return EXIT_SUCCESS; 323 } 324