slesTestPlayStream.cpp revision fa62f9f2c20b446178c05e3e92407fe5dfdbf8a1
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 18#include <stdlib.h> 19#include <stdio.h> 20//#include <string.h> 21#include <unistd.h> 22//#include <sys/time.h> 23 24#include "SLES/OpenSLES.h" 25#include "SLES/OpenSLES_Android.h" 26 27 28#define MAX_NUMBER_INTERFACES 2 29 30#define PREFETCHEVENT_ERROR_CANDIDATE \ 31 (SL_PREFETCHEVENT_STATUSCHANGE | SL_PREFETCHEVENT_FILLLEVELCHANGE) 32 33FILE *file; 34 35//----------------------------------------------------------------- 36//* Exits the application if an error is encountered */ 37#define CheckErr(x) ExitOnErrorFunc(x,__LINE__) 38 39void ExitOnErrorFunc( SLresult result , int line) 40{ 41 if (SL_RESULT_SUCCESS != result) { 42 fprintf(stderr, "%lu error code encountered at line %d, exiting\n", result, line); 43 exit(EXIT_FAILURE); 44 } 45} 46 47bool prefetchError = false; 48 49 50//----------------------------------------------------------------- 51/* AndroidBufferQueueItf callback for an audio player */ 52SLresult AndroidBufferQueueCallback( 53 SLAndroidBufferQueueItf caller, 54 void *pContext, 55 SLuint32 bufferId, 56 SLAint64 bufferLength, 57 void *pBufferDataLocation) 58 59{ 60 fprintf(stdout, "AndroidBufferQueueCallback called\n"); 61 62 size_t nbRead = fread(pBufferDataLocation, 1, bufferLength, file); 63 64 SLAbufferQueueEvent event = SL_ANDROIDBUFFERQUEUE_EVENT_NONE; 65 if (nbRead <= 0) { 66 event = SL_ANDROIDBUFFERQUEUE_EVENT_EOS; 67 } else { 68 event = SL_ANDROIDBUFFERQUEUE_EVENT_NONE; // no event to report 69 } 70 71 // enqueue the data right-away because in this example we're reading from a file, so we 72 // can afford to do that. When streaming from the network, we would write from our cache 73 // to this queue. 74 // last param is NULL because we've already written the data in the buffer queue 75 (*caller)->Enqueue(caller, bufferId, nbRead, event, NULL); 76 77 return SL_RESULT_SUCCESS; 78} 79 80 81//----------------------------------------------------------------- 82 83/* Play some music from a URI */ 84void TestPlayStream( SLObjectItf sl, const char* path) 85{ 86 SLEngineItf EngineItf; 87 88 SLint32 numOutputs = 0; 89 SLuint32 deviceID = 0; 90 91 SLresult res; 92 93 SLDataSource audioSource; 94 SLDataLocator_AndroidBufferQueue streamLocator; 95 SLDataFormat_MIME mime; 96 97 SLDataSink audioSink; 98 SLDataLocator_OutputMix locator_outputmix; 99 100 SLObjectItf player; 101 SLPlayItf playItf; 102 SLVolumeItf volItf; 103 SLAndroidBufferQueueItf abqItf; 104 105 SLObjectItf OutputMix; 106 107 SLboolean required[MAX_NUMBER_INTERFACES]; 108 SLInterfaceID iidArray[MAX_NUMBER_INTERFACES]; 109 110 file = fopen(path, "rb"); 111 112 /* Get the SL Engine Interface which is implicit */ 113 res = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf); 114 CheckErr(res); 115 116 /* Initialize arrays required[] and iidArray[] */ 117 for (int i=0 ; i < MAX_NUMBER_INTERFACES ; i++) { 118 required[i] = SL_BOOLEAN_FALSE; 119 iidArray[i] = SL_IID_NULL; 120 } 121 122 // Set arrays required[] and iidArray[] for VOLUME and PREFETCHSTATUS interface 123 required[0] = SL_BOOLEAN_TRUE; 124 iidArray[0] = SL_IID_VOLUME; 125 required[1] = SL_BOOLEAN_TRUE; 126 iidArray[1] = SL_IID_ANDROIDBUFFERQUEUE; 127 // Create Output Mix object to be used by player 128 res = (*EngineItf)->CreateOutputMix(EngineItf, &OutputMix, 0, 129 iidArray, required); CheckErr(res); 130 131 // Realizing the Output Mix object in synchronous mode. 132 res = (*OutputMix)->Realize(OutputMix, SL_BOOLEAN_FALSE); 133 CheckErr(res); 134 135 /* Setup the data source structure for the URI */ 136 streamLocator.locatorType = SL_DATALOCATOR_ANDROIDBUFFERQUEUE; 137 streamLocator.numBuffers = 0; // ignored at the moment 138 streamLocator.queueSize = 0; // ignored at the moment 139 mime.formatType = SL_DATAFORMAT_MIME; 140 mime.mimeType = (SLchar*)NULL; 141 mime.containerType = SL_CONTAINERTYPE_UNSPECIFIED; 142 143 audioSource.pFormat = (void *)&mime; 144 audioSource.pLocator = (void *)&streamLocator; 145 146 /* Setup the data sink structure */ 147 locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; 148 locator_outputmix.outputMix = OutputMix; 149 audioSink.pLocator = (void *)&locator_outputmix; 150 audioSink.pFormat = NULL; 151 152 /* Create the audio player */ 153 res = (*EngineItf)->CreateAudioPlayer(EngineItf, &player, &audioSource, &audioSink, 154 MAX_NUMBER_INTERFACES, iidArray, required); CheckErr(res); 155 156 /* Realizing the player in synchronous mode. */ 157 res = (*player)->Realize(player, SL_BOOLEAN_FALSE); CheckErr(res); 158 fprintf(stdout, "URI example: after Realize\n"); 159 160 /* Get interfaces */ 161 res = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf); CheckErr(res); 162 163 res = (*player)->GetInterface(player, SL_IID_VOLUME, (void*)&volItf); CheckErr(res); 164 165 res = (*player)->GetInterface(player, SL_IID_ANDROIDBUFFERQUEUE, (void*)&abqItf); 166 CheckErr(res); 167 res = (*abqItf)->RegisterCallback(abqItf, AndroidBufferQueueCallback, 168 &abqItf); CheckErr(res); 169 170 /* Display duration */ 171 SLmillisecond durationInMsec = SL_TIME_UNKNOWN; 172 res = (*playItf)->GetDuration(playItf, &durationInMsec); 173 CheckErr(res); 174 if (durationInMsec == SL_TIME_UNKNOWN) { 175 fprintf(stdout, "Content duration is unknown (before starting to prefetch)\n"); 176 } else { 177 fprintf(stdout, "Content duration is %lu ms (before starting to prefetch)\n", 178 durationInMsec); 179 } 180 181 /* Set the player volume */ 182 res = (*volItf)->SetVolumeLevel( volItf, 0);//-300); 183 CheckErr(res); 184 185 /* Play the URI */ 186 /* first cause the player to prefetch the data */ 187 fprintf(stdout, "Before set to PAUSED\n"); 188 res = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PAUSED ); 189 fprintf(stdout, "After set to PAUSED\n"); 190 CheckErr(res); 191 192 /* wait until there's data to play */ 193 //SLpermille fillLevel = 0; 194 /* SLuint32 prefetchStatus = SL_PREFETCHSTATUS_UNDERFLOW; 195 SLuint32 timeOutIndex = 2; 196 while ((prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) && (timeOutIndex > 0) && 197 !prefetchError) { 198 usleep(1 * 1000 * 1000); // 1s 199 //(*prefetchItf)->GetPrefetchStatus(prefetchItf, &prefetchStatus); 200 timeOutIndex--; 201 } 202 203 if (timeOutIndex == 0 || prefetchError) { 204 fprintf(stderr, "We\'re done waiting, failed to prefetch data in time, exiting\n"); 205 goto destroyRes; 206 }*/ 207 208 /* Display duration again, */ 209 res = (*playItf)->GetDuration(playItf, &durationInMsec); 210 CheckErr(res); 211 if (durationInMsec == SL_TIME_UNKNOWN) { 212 fprintf(stdout, "Content duration is unknown (after prefetch completed)\n"); 213 } else { 214 fprintf(stdout, "Content duration is %lu ms (after prefetch completed)\n", durationInMsec); 215 } 216 217 fprintf(stdout, "URI example: starting to play\n"); 218 res = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PLAYING ); 219 CheckErr(res); 220 221 /* Wait as long as the duration of the content before stopping */ 222 //usleep(durationInMsec * 1000); 223 usleep(30 /*s*/ * 1000 * 1000); 224 225 226 /* Make sure player is stopped */ 227 fprintf(stdout, "URI example: stopping playback\n"); 228 res = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED); 229 CheckErr(res); 230 231destroyRes: 232 233 /* Destroy the player */ 234 (*player)->Destroy(player); 235 236 /* Destroy Output Mix object */ 237 (*OutputMix)->Destroy(OutputMix); 238 239 fclose(file); 240} 241 242//----------------------------------------------------------------- 243int main(int argc, char* const argv[]) 244{ 245 SLresult res; 246 SLObjectItf sl; 247 248 fprintf(stdout, "OpenSL ES test %s: exercises SLPlayItf, SLVolumeItf, SLAndroidBufferQueue \n", 249 argv[0]); 250 fprintf(stdout, "and AudioPlayer with SL_DATALOCATOR_ANDROIDBUFFERQUEUE source / OutputMix sink\n"); 251 fprintf(stdout, "Plays a sound and stops after its reported duration\n\n"); 252 253 if (argc == 1) { 254 fprintf(stdout, "Usage: %s path \n\t%s url\n", argv[0], argv[0]); 255 fprintf(stdout, "Example: \"%s /sdcard/my.mp3\" or \"%s file:///sdcard/my.mp3\"\n", 256 argv[0], argv[0]); 257 exit(EXIT_FAILURE); 258 } 259 260 SLEngineOption EngineOption[] = { 261 {(SLuint32) SL_ENGINEOPTION_THREADSAFE, 262 (SLuint32) SL_BOOLEAN_TRUE}}; 263 264 res = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL); 265 CheckErr(res); 266 /* Realizing the SL Engine in synchronous mode. */ 267 res = (*sl)->Realize(sl, SL_BOOLEAN_FALSE); 268 CheckErr(res); 269 270 TestPlayStream(sl, argv[1]); 271 272 /* Shutdown OpenSL ES */ 273 (*sl)->Destroy(sl); 274 275 return EXIT_SUCCESS; 276} 277