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 #ifdef ANDROID 25 #include <SLES/OpenSLES_Android.h> 26 #endif 27 28 29 #define MAX_NUMBER_INTERFACES 2 30 31 32 //----------------------------------------------------------------- 33 /* Exits the application if an error is encountered */ 34 #define ExitOnError(x) ExitOnErrorFunc(x,__LINE__) 35 36 void ExitOnErrorFunc( SLresult result , int line) 37 { 38 if (SL_RESULT_SUCCESS != result) { 39 fprintf(stdout, "%u error code encountered at line %d, exiting\n", result, line); 40 exit(EXIT_FAILURE); 41 } 42 } 43 44 45 //----------------------------------------------------------------- 46 47 /* Play an audio URIs on the given stream type */ 48 void TestStreamTypeConfiguration( SLObjectItf sl, const char* path, const SLint32 type) 49 { 50 SLresult result; 51 SLEngineItf EngineItf; 52 53 /* Objects this application uses: one player and an ouput mix */ 54 SLObjectItf player, outputMix; 55 56 /* Source of audio data to play */ 57 SLDataSource audioSource; 58 SLDataLocator_URI uri; 59 SLDataFormat_MIME mime; 60 61 /* Data sinks for the audio player */ 62 SLDataSink audioSink; 63 SLDataLocator_OutputMix locator_outputmix; 64 65 /* Play, Volume and AndroidStreamType interfaces for the audio player */ 66 SLPlayItf playItf; 67 SLPrefetchStatusItf prefetchItf; 68 #ifdef ANDROID 69 SLAndroidConfigurationItf configItf; 70 #endif 71 72 SLboolean required[MAX_NUMBER_INTERFACES]; 73 SLInterfaceID iidArray[MAX_NUMBER_INTERFACES]; 74 75 /* Get the SL Engine Interface which is implicit */ 76 result = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf); 77 ExitOnError(result); 78 79 /* Initialize arrays required[] and iidArray[] */ 80 for (int i=0 ; i < MAX_NUMBER_INTERFACES ; i++) { 81 required[i] = SL_BOOLEAN_FALSE; 82 iidArray[i] = SL_IID_NULL; 83 } 84 85 /* ------------------------------------------------------ */ 86 /* Configuration of the output mix */ 87 88 /* Create Output Mix object to be used by the player */ 89 result = (*EngineItf)->CreateOutputMix(EngineItf, &outputMix, 0, iidArray, required); 90 ExitOnError(result); 91 92 /* Realize the Output Mix object in synchronous mode */ 93 result = (*outputMix)->Realize(outputMix, SL_BOOLEAN_FALSE); 94 ExitOnError(result); 95 96 /* Setup the data sink structure */ 97 locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; 98 locator_outputmix.outputMix = outputMix; 99 audioSink.pLocator = (void*)&locator_outputmix; 100 audioSink.pFormat = NULL; 101 102 /* ------------------------------------------------------ */ 103 /* Configuration of the player */ 104 105 /* Set arrays required[] and iidArray[] for SLAndroidConfigurationItf interfaces */ 106 /* (SLPlayItf is implicit) */ 107 required[0] = SL_BOOLEAN_TRUE; 108 iidArray[0] = SL_IID_PREFETCHSTATUS; 109 #ifdef ANDROID 110 required[1] = SL_BOOLEAN_TRUE; 111 iidArray[1] = SL_IID_ANDROIDCONFIGURATION; 112 #endif 113 114 115 /* Setup the data source structure for the URI */ 116 uri.locatorType = SL_DATALOCATOR_URI; 117 uri.URI = (SLchar*) path; 118 mime.formatType = SL_DATAFORMAT_MIME; 119 /* this is how ignored mime information is specified, according to OpenSL ES spec 120 * in 9.1.6 SLDataFormat_MIME and 8.23 SLMetadataTraversalItf GetChildInfo */ 121 mime.mimeType = (SLchar*)NULL; 122 mime.containerType = SL_CONTAINERTYPE_UNSPECIFIED; 123 124 audioSource.pFormat = (void*)&mime; 125 audioSource.pLocator = (void*)&uri; 126 127 /* Create the audio player */ 128 result = (*EngineItf)->CreateAudioPlayer(EngineItf, &player, &audioSource, &audioSink, 129 MAX_NUMBER_INTERFACES, iidArray, required); 130 ExitOnError(result); 131 132 /* Retrieve the configuration interface before the player is realized so its resources 133 * can be configured. 134 */ 135 #ifdef ANDROID 136 result = (*player)->GetInterface(player, SL_IID_ANDROIDCONFIGURATION, (void*)&configItf); 137 ExitOnError(result); 138 139 /* Set the Android audio stream type on the player */ 140 result = (*configItf)->SetConfiguration(configItf, 141 SL_ANDROID_KEY_STREAM_TYPE, &type, sizeof(SLint32)); 142 if (SL_RESULT_PARAMETER_INVALID == result) { 143 fprintf(stderr, "invalid stream type %d\n", type); 144 } else { 145 ExitOnError(result); 146 } 147 #endif 148 149 /* Realize the player in synchronous mode. */ 150 result = (*player)->Realize(player, SL_BOOLEAN_FALSE); ExitOnError(result); 151 fprintf(stdout, "URI example: after Realize\n"); 152 153 /* Get the SLPlayItf, SLPrefetchStatusItf and SLAndroidConfigurationItf interfaces for player */ 154 result = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf); 155 ExitOnError(result); 156 157 result = (*player)->GetInterface(player, SL_IID_PREFETCHSTATUS, (void*)&prefetchItf); 158 ExitOnError(result); 159 160 fprintf(stdout, "Player configured\n"); 161 162 /* ------------------------------------------------------ */ 163 /* Playback and test */ 164 165 /* Start the data prefetching by setting the player to the paused state */ 166 result = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PAUSED ); 167 ExitOnError(result); 168 169 /* Wait until there's data to play */ 170 SLuint32 prefetchStatus = SL_PREFETCHSTATUS_UNDERFLOW; 171 while (prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) { 172 usleep(100 * 1000); 173 (*prefetchItf)->GetPrefetchStatus(prefetchItf, &prefetchStatus); 174 ExitOnError(result); 175 } 176 177 /* Get duration */ 178 SLmillisecond durationInMsec = SL_TIME_UNKNOWN; 179 result = (*playItf)->GetDuration(playItf, &durationInMsec); 180 ExitOnError(result); 181 if (durationInMsec == SL_TIME_UNKNOWN) { 182 durationInMsec = 5000; 183 } 184 185 /* Start playback */ 186 result = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PLAYING ); 187 ExitOnError(result); 188 189 usleep((durationInMsec/2) * 1000); 190 191 #ifdef ANDROID 192 /* Get the stream type during playback */ 193 SLint32 currentType = -1; 194 SLuint32 valueSize = sizeof(SLint32) * 2; // trying too big on purpose 195 result = (*configItf)->GetConfiguration(configItf, 196 SL_ANDROID_KEY_STREAM_TYPE, &valueSize, NULL); 197 ExitOnError(result); 198 if (valueSize != sizeof(SLint32)) { 199 fprintf(stderr, "ERROR: size for stream type is %u, should be %u\n", 200 valueSize, sizeof(SLint32)); 201 } 202 result = (*configItf)->GetConfiguration(configItf, 203 SL_ANDROID_KEY_STREAM_TYPE, &valueSize, ¤tType); 204 ExitOnError(result); 205 if (currentType != type) { 206 fprintf(stderr, "ERROR: stream type is %u, should be %u\n", currentType, type); 207 } 208 #endif 209 210 usleep((durationInMsec/2) * 1000); 211 212 /* Make sure player is stopped */ 213 fprintf(stdout, "Stopping playback\n"); 214 result = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED); 215 ExitOnError(result); 216 217 #ifdef ANDROID 218 /* Try again to get the stream type, just in case it changed behind our back */ 219 result = (*configItf)->GetConfiguration(configItf, 220 SL_ANDROID_KEY_STREAM_TYPE, &valueSize, ¤tType); 221 ExitOnError(result); 222 if (currentType != type) { 223 fprintf(stderr, "ERROR: stream type is %u, should be %u\n", currentType, type); 224 } 225 #endif 226 227 /* Destroy the player */ 228 (*player)->Destroy(player); 229 230 /* Destroy Output Mix object */ 231 (*outputMix)->Destroy(outputMix); 232 } 233 234 //----------------------------------------------------------------- 235 int main(int argc, char* const argv[]) 236 { 237 SLresult result; 238 SLObjectItf sl; 239 240 fprintf(stdout, "OpenSL ES test %s: exercises SLPlayItf, SLAndroidConfigurationItf\n", 241 argv[0]); 242 fprintf(stdout, "and AudioPlayer with SLDataLocator_URI source / OutputMix sink\n"); 243 fprintf(stdout, "Plays a sound on the specified android stream type\n"); 244 245 if (argc < 3) { 246 fprintf(stdout, "Usage: \t%s url stream_type\n", argv[0]); 247 fprintf(stdout, " where stream_type is one of the SL_ANDROID_STREAM_ constants.\n"); 248 fprintf(stdout, "Example: \"%s /sdcard/my.mp3 5\" \n", argv[0]); 249 fprintf(stdout, "Stream type %d is the default (media or music), %d is notifications\n", 250 SL_ANDROID_STREAM_MEDIA, SL_ANDROID_STREAM_NOTIFICATION); 251 return EXIT_FAILURE; 252 } 253 254 SLEngineOption EngineOption[] = { 255 {(SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE} 256 }; 257 258 result = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL); 259 ExitOnError(result); 260 261 /* Realizing the SL Engine in synchronous mode. */ 262 result = (*sl)->Realize(sl, SL_BOOLEAN_FALSE); 263 ExitOnError(result); 264 265 TestStreamTypeConfiguration(sl, argv[1], (SLint32)atoi(argv[2])); 266 267 /* Shutdown OpenSL ES */ 268 (*sl)->Destroy(sl); 269 270 return EXIT_SUCCESS; 271 } 272