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 <unistd.h>
20
21 #include <SLES/OpenSLES.h>
22
23
24 #define MAX_NUMBER_INTERFACES 3
25
26
27 //-----------------------------------------------------------------
28 /* Exits the application if an error is encountered */
ExitOnError(SLresult result)29 void ExitOnError( SLresult result )
30 {
31 if (SL_RESULT_SUCCESS != result) {
32 fprintf(stdout, "%u error code encountered, exiting\n", result);
33 exit(EXIT_FAILURE);
34 }
35 }
36
37 //-----------------------------------------------------------------
38 /* PlayItf callback for an audio player */
PlayEventCallback(SLPlayItf caller,void * pContext,SLuint32 event)39 void PlayEventCallback( SLPlayItf caller, void *pContext, SLuint32 event)
40 {
41 fprintf(stdout, "PlayEventCallback event = ");
42 if (event & SL_PLAYEVENT_HEADATEND) {
43 fprintf(stdout, "SL_PLAYEVENT_HEADATEND ");
44 }
45 if (event & SL_PLAYEVENT_HEADATMARKER) {
46 fprintf(stdout, "SL_PLAYEVENT_HEADATMARKER ");
47 }
48 if (event & SL_PLAYEVENT_HEADATNEWPOS) {
49 fprintf(stdout, "SL_PLAYEVENT_HEADATNEWPOS ");
50 }
51 if (event & SL_PLAYEVENT_HEADMOVING) {
52 fprintf(stdout, "SL_PLAYEVENT_HEADMOVING ");
53 }
54 if (event & SL_PLAYEVENT_HEADSTALLED) {
55 fprintf(stdout, "SL_PLAYEVENT_HEADSTALLED");
56 }
57 fprintf(stdout, "\n");
58 }
59
60 //-----------------------------------------------------------------
61
62 /* Play two audio URIs, pan them left and right */
TestPlayUri(SLObjectItf sl,const char * path,const char * path2)63 void TestPlayUri( SLObjectItf sl, const char* path, const char* path2)
64 {
65 SLresult result;
66 SLEngineItf EngineItf;
67
68 /* Objects this application uses: two players and an ouput mix */
69 SLObjectItf player, player2, outputMix;
70
71 /* Source of audio data to play, we'll reuse the same source for two different players */
72 SLDataSource audioSource;
73 SLDataLocator_URI uri;
74 SLDataFormat_MIME mime;
75
76 /* Data sinks for the two audio players */
77 SLDataSink audioSink;
78 SLDataLocator_OutputMix locator_outputmix;
79
80 /* Play, Volume and PrefetchStatus interfaces for the audio players */
81 SLPlayItf playItf, playItf2;
82 SLVolumeItf volItf, volItf2;
83 SLPrefetchStatusItf prefetchItf, prefetchItf2;
84
85 SLboolean required[MAX_NUMBER_INTERFACES];
86 SLInterfaceID iidArray[MAX_NUMBER_INTERFACES];
87
88 /* Get the SL Engine Interface which is implicit */
89 result = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf);
90 ExitOnError(result);
91
92 /* Initialize arrays required[] and iidArray[] */
93 for (int i=0 ; i < MAX_NUMBER_INTERFACES ; i++) {
94 required[i] = SL_BOOLEAN_FALSE;
95 iidArray[i] = SL_IID_NULL;
96 }
97 /* Set arrays required[] and iidArray[] for SLVolumeItf and SLPrefetchStatusItf interfaces */
98 /* (SLPlayItf is implicit) */
99 required[0] = SL_BOOLEAN_TRUE;
100 iidArray[0] = SL_IID_VOLUME;
101 required[1] = SL_BOOLEAN_TRUE;
102 iidArray[1] = SL_IID_PREFETCHSTATUS;
103
104 /* ------------------------------------------------------ */
105 /* Configuration of the output mix */
106
107 /* Create Output Mix object to be used each player */
108 result = (*EngineItf)->CreateOutputMix(EngineItf, &outputMix, 0, iidArray, required);
109 ExitOnError(result);
110
111 /* Realize the Output Mix object in synchronous mode */
112 result = (*outputMix)->Realize(outputMix, SL_BOOLEAN_FALSE);
113 ExitOnError(result);
114
115 /* Setup the data sink structure */
116 locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
117 locator_outputmix.outputMix = outputMix;
118 audioSink.pLocator = (void *)&locator_outputmix;
119 audioSink.pFormat = NULL;
120
121 /* ------------------------------------------------------ */
122 /* Configuration of the players */
123
124 /* Setup the data source structure for the first URI */
125 uri.locatorType = SL_DATALOCATOR_URI;
126 uri.URI = (SLchar*) path;
127 mime.formatType = SL_DATAFORMAT_MIME;
128 /* this is how ignored mime information is specified, according to OpenSL ES spec
129 * in 9.1.6 SLDataFormat_MIME and 8.23 SLMetadataTraversalItf GetChildInfo */
130 mime.mimeType = (SLchar*)NULL;
131 mime.containerType = SL_CONTAINERTYPE_UNSPECIFIED;
132
133 audioSource.pFormat = (void *)&mime;
134 audioSource.pLocator = (void *)&uri;
135
136 /* Create the first audio player */
137 result = (*EngineItf)->CreateAudioPlayer(EngineItf, &player, &audioSource, &audioSink, 2,
138 iidArray, required);
139 ExitOnError(result);
140
141 /* Create the second audio player with a different path for its data source */
142 uri.URI = (SLchar*) path2;
143 audioSource.pLocator = (void *)&uri;
144 result = (*EngineItf)->CreateAudioPlayer(EngineItf, &player2, &audioSource, &audioSink, 2,
145 iidArray, required);
146 ExitOnError(result);
147
148 /* Realize the players in synchronous mode. */
149 result = (*player)->Realize(player, SL_BOOLEAN_FALSE); ExitOnError(result);
150 result = (*player)->Realize(player2, SL_BOOLEAN_FALSE); ExitOnError(result);
151 //fprintf(stdout, "URI example: after Realize\n");
152
153 /* Get the SLPlayItf, SLVolumeItf and SLPrefetchStatusItf interfaces for each player */
154 result = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf);
155 ExitOnError(result);
156 result = (*player)->GetInterface(player2, SL_IID_PLAY, (void*)&playItf2);
157 ExitOnError(result);
158
159 result = (*player)->GetInterface(player, SL_IID_VOLUME, (void*)&volItf);
160 ExitOnError(result);
161 result = (*player2)->GetInterface(player2, SL_IID_VOLUME, (void*)&volItf2);
162 ExitOnError(result);
163
164 result = (*player)->GetInterface(player, SL_IID_PREFETCHSTATUS, (void*)&prefetchItf);
165 ExitOnError(result);
166 result = (*player2)->GetInterface(player2, SL_IID_PREFETCHSTATUS, (void*)&prefetchItf2);
167 ExitOnError(result);
168
169 /* Setup to receive playback events */
170 result = (*playItf)->RegisterCallback(playItf, PlayEventCallback, &playItf);
171 ExitOnError(result);
172 result = (*playItf)->SetCallbackEventsMask(playItf,
173 SL_PLAYEVENT_HEADATEND| SL_PLAYEVENT_HEADATMARKER | SL_PLAYEVENT_HEADATNEWPOS
174 | SL_PLAYEVENT_HEADMOVING | SL_PLAYEVENT_HEADSTALLED);
175 ExitOnError(result);
176
177 /* Set the player volume */
178 result = (*volItf)->SetVolumeLevel( volItf, -300);
179 ExitOnError(result);
180 /* Pan the first player to the left */
181 result = (*volItf)->EnableStereoPosition( volItf, SL_BOOLEAN_TRUE); ExitOnError(result);
182 result = (*volItf)->SetStereoPosition( volItf, -1000); ExitOnError(result);
183 /* Pan the second player to the right */
184 result = (*volItf2)->EnableStereoPosition( volItf2, SL_BOOLEAN_TRUE); ExitOnError(result);
185 result = (*volItf2)->SetStereoPosition( volItf2, 1000); ExitOnError(result);
186
187 /* ------------------------------------------------------ */
188 /* Playback */
189
190 /* Start the data prefetching by setting the players to the paused state */
191 result = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PAUSED );
192 ExitOnError(result);
193 result = (*playItf2)->SetPlayState( playItf2, SL_PLAYSTATE_PAUSED );
194 ExitOnError(result);
195
196 /* wait until there's data to play */
197 SLuint32 prefetchStatus = SL_PREFETCHSTATUS_UNDERFLOW;
198 while (prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) {
199 usleep(100 * 1000);
200 (*prefetchItf)->GetPrefetchStatus(prefetchItf, &prefetchStatus);
201 }
202 prefetchStatus = SL_PREFETCHSTATUS_UNDERFLOW;
203 while (prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) {
204 usleep(100 * 1000);
205 (*prefetchItf2)->GetPrefetchStatus(prefetchItf2, &prefetchStatus);
206 }
207
208 result = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PLAYING );
209 ExitOnError(result);
210
211 /* Wait 2s before starting the second player */
212 usleep(2000 * 1000);
213 fprintf(stdout, "URI example: starting to play %s\n", path2);
214 result = (*playItf2)->SetPlayState( playItf2, SL_PLAYSTATE_PLAYING );
215 ExitOnError(result);
216
217 /* Display duration */
218 SLmillisecond durationInMsec = SL_TIME_UNKNOWN;
219 result = (*playItf)->GetDuration(playItf, &durationInMsec);
220 ExitOnError(result);
221 if (durationInMsec == SL_TIME_UNKNOWN) {
222 fprintf(stdout, "Content duration of first URI is unknown\n");
223 } else {
224 fprintf(stdout, "Content duration of first URI is %u ms\n", durationInMsec);
225 }
226
227 /* Wait as long as the duration of the first URI + 2s before stopping */
228 if (durationInMsec == SL_TIME_UNKNOWN) {
229 durationInMsec = 5000; /* arbitrary time when duration is unknown */
230 }
231 usleep((durationInMsec + 2000) * 1000);
232
233 /* Make sure player is stopped */
234 fprintf(stdout, "URI example: stopping playback\n");
235 result = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
236 ExitOnError(result);
237 result = (*playItf2)->SetPlayState(playItf2, SL_PLAYSTATE_STOPPED);
238 ExitOnError(result);
239
240 /* Destroy the players */
241 (*player)->Destroy(player);
242 (*player2)->Destroy(player2);
243
244 /* Destroy Output Mix object */
245 (*outputMix)->Destroy(outputMix);
246 }
247
248 //-----------------------------------------------------------------
main(int argc,char * const argv[])249 int main(int argc, char* const argv[])
250 {
251 SLresult result;
252 SLObjectItf sl;
253
254 fprintf(stdout, "OpenSL ES test %s: exercises SLPlayItf, SLVolumeItf (incl. stereo position) ",
255 argv[0]);
256 fprintf(stdout, "and AudioPlayer with SLDataLocator_URI source / OutputMix sink\n");
257 fprintf(stdout, "Plays two sounds (or twice the same) and pans them left and right.");
258 fprintf(stdout, "Stops after the end of the first + 2s\n");
259
260 if (argc == 1) {
261 fprintf(stdout, "Usage: \n\t%s url1 url2 \n\t%s url\n", argv[0], argv[0]);
262 fprintf(stdout, "Example: \"%s /sdcard/my.mp3 http://blabla/my.wav\" ", argv[0]);
263 fprintf(stdout, "or \"%s file:///sdcard/my.mp3\"\n", argv[0]);
264 exit(EXIT_FAILURE);
265 }
266
267 SLEngineOption EngineOption[] = {
268 {(SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE}
269 };
270
271 result = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL);
272 ExitOnError(result);
273
274 /* Realizing the SL Engine in synchronous mode. */
275 result = (*sl)->Realize(sl, SL_BOOLEAN_FALSE);
276 ExitOnError(result);
277
278 if (argc == 2) {
279 TestPlayUri(sl, argv[1], argv[1]);
280 } else if (argc == 3) {
281 TestPlayUri(sl, argv[1], argv[2]);
282 }
283
284 /* Shutdown OpenSL ES */
285 (*sl)->Destroy(sl);
286
287 return EXIT_SUCCESS;
288 }
289