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