1*bebae9c0SAndroid Build Coastguard Worker /*
2*bebae9c0SAndroid Build Coastguard Worker * Copyright (C) 2010 The Android Open Source Project
3*bebae9c0SAndroid Build Coastguard Worker *
4*bebae9c0SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*bebae9c0SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*bebae9c0SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*bebae9c0SAndroid Build Coastguard Worker *
8*bebae9c0SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*bebae9c0SAndroid Build Coastguard Worker *
10*bebae9c0SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*bebae9c0SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*bebae9c0SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*bebae9c0SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*bebae9c0SAndroid Build Coastguard Worker * limitations under the License.
15*bebae9c0SAndroid Build Coastguard Worker */
16*bebae9c0SAndroid Build Coastguard Worker
17*bebae9c0SAndroid Build Coastguard Worker
18*bebae9c0SAndroid Build Coastguard Worker #include <stdlib.h>
19*bebae9c0SAndroid Build Coastguard Worker #include <stdio.h>
20*bebae9c0SAndroid Build Coastguard Worker //#include <string.h>
21*bebae9c0SAndroid Build Coastguard Worker #include <unistd.h>
22*bebae9c0SAndroid Build Coastguard Worker //#include <sys/time.h>
23*bebae9c0SAndroid Build Coastguard Worker
24*bebae9c0SAndroid Build Coastguard Worker #include <SLES/OpenSLES.h>
25*bebae9c0SAndroid Build Coastguard Worker #include <SLES/OpenSLES_Android.h>
26*bebae9c0SAndroid Build Coastguard Worker
27*bebae9c0SAndroid Build Coastguard Worker //#define TEST_DISPLAY_FIRST_BUFFER_ITEM
28*bebae9c0SAndroid Build Coastguard Worker //#define TEST_CLEAR
29*bebae9c0SAndroid Build Coastguard Worker //#define TEST_PTS
30*bebae9c0SAndroid Build Coastguard Worker
31*bebae9c0SAndroid Build Coastguard Worker #define MAX_NUMBER_INTERFACES 2
32*bebae9c0SAndroid Build Coastguard Worker
33*bebae9c0SAndroid Build Coastguard Worker #define PREFETCHEVENT_ERROR_CANDIDATE \
34*bebae9c0SAndroid Build Coastguard Worker (SL_PREFETCHEVENT_STATUSCHANGE | SL_PREFETCHEVENT_FILLLEVELCHANGE)
35*bebae9c0SAndroid Build Coastguard Worker
36*bebae9c0SAndroid Build Coastguard Worker #define NB_BUFFERS 16
37*bebae9c0SAndroid Build Coastguard Worker #define MPEG2_TS_BLOCK_SIZE 188
38*bebae9c0SAndroid Build Coastguard Worker #define BUFFER_SIZE (20*MPEG2_TS_BLOCK_SIZE)
39*bebae9c0SAndroid Build Coastguard Worker #define DISCONTINUITY_MAGIC 1977
40*bebae9c0SAndroid Build Coastguard Worker
41*bebae9c0SAndroid Build Coastguard Worker /* Where we store the data to play */
42*bebae9c0SAndroid Build Coastguard Worker char dataCache[BUFFER_SIZE * NB_BUFFERS];
43*bebae9c0SAndroid Build Coastguard Worker /* From where we read the data to play */
44*bebae9c0SAndroid Build Coastguard Worker FILE *file;
45*bebae9c0SAndroid Build Coastguard Worker /* Has the app reached the end of the file */
46*bebae9c0SAndroid Build Coastguard Worker bool reachedEof = false;
47*bebae9c0SAndroid Build Coastguard Worker /* Special discontinuity buffer context */
48*bebae9c0SAndroid Build Coastguard Worker int myDiscBufferContext = DISCONTINUITY_MAGIC;
49*bebae9c0SAndroid Build Coastguard Worker
50*bebae9c0SAndroid Build Coastguard Worker /* structure to store my discontinuity with PTS command */
51*bebae9c0SAndroid Build Coastguard Worker typedef struct {
52*bebae9c0SAndroid Build Coastguard Worker SLuint32 discKey; // identifies the item
53*bebae9c0SAndroid Build Coastguard Worker SLuint32 discSize;
54*bebae9c0SAndroid Build Coastguard Worker SLAuint64 discPts;
55*bebae9c0SAndroid Build Coastguard Worker } DiscPts;
56*bebae9c0SAndroid Build Coastguard Worker
57*bebae9c0SAndroid Build Coastguard Worker //-----------------------------------------------------------------
58*bebae9c0SAndroid Build Coastguard Worker /* Exits the application if an error is encountered */
59*bebae9c0SAndroid Build Coastguard Worker #define CheckErr(x) ExitOnErrorFunc(x,__LINE__)
60*bebae9c0SAndroid Build Coastguard Worker
ExitOnErrorFunc(SLresult result,int line)61*bebae9c0SAndroid Build Coastguard Worker void ExitOnErrorFunc( SLresult result , int line)
62*bebae9c0SAndroid Build Coastguard Worker {
63*bebae9c0SAndroid Build Coastguard Worker if (SL_RESULT_SUCCESS != result) {
64*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, "%u error code encountered at line %d, exiting\n", result, line);
65*bebae9c0SAndroid Build Coastguard Worker exit(EXIT_FAILURE);
66*bebae9c0SAndroid Build Coastguard Worker }
67*bebae9c0SAndroid Build Coastguard Worker }
68*bebae9c0SAndroid Build Coastguard Worker
69*bebae9c0SAndroid Build Coastguard Worker bool prefetchError = false;
70*bebae9c0SAndroid Build Coastguard Worker
71*bebae9c0SAndroid Build Coastguard Worker //-----------------------------------------------------------------
72*bebae9c0SAndroid Build Coastguard Worker /* AndroidBufferQueueItf callback for an audio player */
AndroidBufferQueueCallback(SLAndroidBufferQueueItf caller,void * pCallbackContext __unused,void * pBufferContext,void * pBufferData __unused,SLuint32 dataSize __unused,SLuint32 dataUsed __unused,const SLAndroidBufferItem * pItems __unused,SLuint32 itemsLength __unused)73*bebae9c0SAndroid Build Coastguard Worker SLresult AndroidBufferQueueCallback(
74*bebae9c0SAndroid Build Coastguard Worker SLAndroidBufferQueueItf caller,
75*bebae9c0SAndroid Build Coastguard Worker void *pCallbackContext __unused, /* input */
76*bebae9c0SAndroid Build Coastguard Worker void *pBufferContext, /* input */
77*bebae9c0SAndroid Build Coastguard Worker void *pBufferData __unused, /* input */
78*bebae9c0SAndroid Build Coastguard Worker SLuint32 dataSize __unused, /* input */
79*bebae9c0SAndroid Build Coastguard Worker SLuint32 dataUsed __unused, /* input */
80*bebae9c0SAndroid Build Coastguard Worker const SLAndroidBufferItem *pItems __unused, /* input */
81*bebae9c0SAndroid Build Coastguard Worker SLuint32 itemsLength __unused /* input */)
82*bebae9c0SAndroid Build Coastguard Worker {
83*bebae9c0SAndroid Build Coastguard Worker // assert(BUFFER_SIZE <= dataSize);
84*bebae9c0SAndroid Build Coastguard Worker
85*bebae9c0SAndroid Build Coastguard Worker //--------------------------------------------------------------------------------
86*bebae9c0SAndroid Build Coastguard Worker // this section is for testing only, this is NOT an example of how to use the API
87*bebae9c0SAndroid Build Coastguard Worker // to play a .ts file, but rather shows more ways to exercise the API
88*bebae9c0SAndroid Build Coastguard Worker //--------------------------------------------------------------------------------
89*bebae9c0SAndroid Build Coastguard Worker SLAndroidBufferQueueState state;
90*bebae9c0SAndroid Build Coastguard Worker (*caller)->GetState(caller, &state);
91*bebae9c0SAndroid Build Coastguard Worker //fprintf(stdout, "ABQ state count=%lu, index=%lu\n", state.count, state.index);
92*bebae9c0SAndroid Build Coastguard Worker
93*bebae9c0SAndroid Build Coastguard Worker // just to test, clear the queue to see what happens
94*bebae9c0SAndroid Build Coastguard Worker if (state.index == 500) {
95*bebae9c0SAndroid Build Coastguard Worker #ifdef TEST_CLEAR
96*bebae9c0SAndroid Build Coastguard Worker (*caller)->Clear(caller);
97*bebae9c0SAndroid Build Coastguard Worker // we've cleared the queue, and have introduced a discontinuity, so signal it
98*bebae9c0SAndroid Build Coastguard Worker SLAndroidBufferItem msgDiscontinuity;
99*bebae9c0SAndroid Build Coastguard Worker msgDiscontinuity.itemKey = SL_ANDROID_ITEMKEY_DISCONTINUITY;
100*bebae9c0SAndroid Build Coastguard Worker msgDiscontinuity.itemSize = 0;
101*bebae9c0SAndroid Build Coastguard Worker // message has no parameters, so the total size of the message is the size of the key
102*bebae9c0SAndroid Build Coastguard Worker // plus the size if itemSize, both SLuint32
103*bebae9c0SAndroid Build Coastguard Worker (*caller)->Enqueue(caller, (void*)&myDiscBufferContext /*pBufferContext*/,
104*bebae9c0SAndroid Build Coastguard Worker NULL /*pData*/, 0 /*dataLength*/,
105*bebae9c0SAndroid Build Coastguard Worker &msgDiscontinuity /*pMsg*/,
106*bebae9c0SAndroid Build Coastguard Worker sizeof(SLuint32)*2 /*msgLength*/);
107*bebae9c0SAndroid Build Coastguard Worker // we've cleared the queue, it's now empty: let's rebuffer a bit so playback doesn't starve
108*bebae9c0SAndroid Build Coastguard Worker size_t nbRead = fread((void*)dataCache, 1, BUFFER_SIZE*(NB_BUFFERS/2), file);
109*bebae9c0SAndroid Build Coastguard Worker if (nbRead == BUFFER_SIZE*(NB_BUFFERS/2)) {
110*bebae9c0SAndroid Build Coastguard Worker for (int i=0 ; i < NB_BUFFERS/2 ; i++) {
111*bebae9c0SAndroid Build Coastguard Worker SLresult res = (*caller)->Enqueue(caller, NULL /*pBufferContext*/,
112*bebae9c0SAndroid Build Coastguard Worker dataCache + i*BUFFER_SIZE,
113*bebae9c0SAndroid Build Coastguard Worker BUFFER_SIZE, NULL, 0);
114*bebae9c0SAndroid Build Coastguard Worker CheckErr(res);
115*bebae9c0SAndroid Build Coastguard Worker }
116*bebae9c0SAndroid Build Coastguard Worker }
117*bebae9c0SAndroid Build Coastguard Worker #endif
118*bebae9c0SAndroid Build Coastguard Worker #ifdef TEST_PTS
119*bebae9c0SAndroid Build Coastguard Worker DiscPts msgDiscontinuity = { SL_ANDROID_ITEMKEY_DISCONTINUITY,
120*bebae9c0SAndroid Build Coastguard Worker sizeof(SLAuint64), 15*90*1000 /*15s in 90kHz clock */ };
121*bebae9c0SAndroid Build Coastguard Worker // enqueue discontinuity message with our PTS
122*bebae9c0SAndroid Build Coastguard Worker (*caller)->Enqueue(caller, (void*)&myDiscBufferContext /*pBufferContext*/,
123*bebae9c0SAndroid Build Coastguard Worker NULL /*pData*/, 0 /*dataLength*/,
124*bebae9c0SAndroid Build Coastguard Worker (SLAndroidBufferItem*)&msgDiscontinuity,
125*bebae9c0SAndroid Build Coastguard Worker sizeof(DiscPts) );
126*bebae9c0SAndroid Build Coastguard Worker fprintf(stdout, "rendering will resume at 15s mark");
127*bebae9c0SAndroid Build Coastguard Worker
128*bebae9c0SAndroid Build Coastguard Worker #endif
129*bebae9c0SAndroid Build Coastguard Worker return SL_RESULT_SUCCESS;
130*bebae9c0SAndroid Build Coastguard Worker }
131*bebae9c0SAndroid Build Coastguard Worker //--------------------------------------------------------------------------------
132*bebae9c0SAndroid Build Coastguard Worker // end of test only section
133*bebae9c0SAndroid Build Coastguard Worker //--------------------------------------------------------------------------------
134*bebae9c0SAndroid Build Coastguard Worker else {
135*bebae9c0SAndroid Build Coastguard Worker
136*bebae9c0SAndroid Build Coastguard Worker #ifdef TEST_DISPLAY_FIRST_BUFFER_ITEM
137*bebae9c0SAndroid Build Coastguard Worker // display item data (only parsing first item)
138*bebae9c0SAndroid Build Coastguard Worker if (itemsLength !=0) {
139*bebae9c0SAndroid Build Coastguard Worker fprintf(stdout, "item key=0x%lx size=%lu data=0x%lx\n",
140*bebae9c0SAndroid Build Coastguard Worker pItems->itemKey, pItems->itemSize, *((SLuint32*)&pItems->itemData));
141*bebae9c0SAndroid Build Coastguard Worker }
142*bebae9c0SAndroid Build Coastguard Worker #endif
143*bebae9c0SAndroid Build Coastguard Worker
144*bebae9c0SAndroid Build Coastguard Worker // pBufferData can be null if the last consumed buffer contained only a command
145*bebae9c0SAndroid Build Coastguard Worker // just like we do for signalling DISCONTINUITY (above) or EOS (below)
146*bebae9c0SAndroid Build Coastguard Worker if ((pBufferContext != NULL) && (*((int*)pBufferContext) == DISCONTINUITY_MAGIC)) {
147*bebae9c0SAndroid Build Coastguard Worker fprintf(stdout, "Successfully detected my discontinuity buffer having been consumed\n");
148*bebae9c0SAndroid Build Coastguard Worker }
149*bebae9c0SAndroid Build Coastguard Worker if (pBufferData != NULL) {
150*bebae9c0SAndroid Build Coastguard Worker size_t nbRead = fread((void*)pBufferData, 1, BUFFER_SIZE, file);
151*bebae9c0SAndroid Build Coastguard Worker if (nbRead > 0) {
152*bebae9c0SAndroid Build Coastguard Worker (*caller)->Enqueue(caller, NULL /*pBufferContext*/,
153*bebae9c0SAndroid Build Coastguard Worker pBufferData /*pData*/,
154*bebae9c0SAndroid Build Coastguard Worker nbRead /*dataLength*/,
155*bebae9c0SAndroid Build Coastguard Worker NULL /*pMsg*/,
156*bebae9c0SAndroid Build Coastguard Worker 0 /*msgLength*/);
157*bebae9c0SAndroid Build Coastguard Worker } else if (!reachedEof) {
158*bebae9c0SAndroid Build Coastguard Worker // signal EOS
159*bebae9c0SAndroid Build Coastguard Worker SLAndroidBufferItem msgEos;
160*bebae9c0SAndroid Build Coastguard Worker msgEos.itemKey = SL_ANDROID_ITEMKEY_EOS;
161*bebae9c0SAndroid Build Coastguard Worker msgEos.itemSize = 0;
162*bebae9c0SAndroid Build Coastguard Worker // EOS message has no parameters, so the total size of the message is the size of
163*bebae9c0SAndroid Build Coastguard Worker // the key plus the size if itemSize, both SLuint32
164*bebae9c0SAndroid Build Coastguard Worker (*caller)->Enqueue(caller, NULL /*pBufferContext*/,
165*bebae9c0SAndroid Build Coastguard Worker NULL /*pData*/, 0 /*dataLength*/,
166*bebae9c0SAndroid Build Coastguard Worker &msgEos /*pMsg*/,
167*bebae9c0SAndroid Build Coastguard Worker sizeof(SLuint32)*2 /*msgLength*/);
168*bebae9c0SAndroid Build Coastguard Worker reachedEof = true;
169*bebae9c0SAndroid Build Coastguard Worker }
170*bebae9c0SAndroid Build Coastguard Worker }
171*bebae9c0SAndroid Build Coastguard Worker
172*bebae9c0SAndroid Build Coastguard Worker return SL_RESULT_SUCCESS;
173*bebae9c0SAndroid Build Coastguard Worker }
174*bebae9c0SAndroid Build Coastguard Worker }
175*bebae9c0SAndroid Build Coastguard Worker
176*bebae9c0SAndroid Build Coastguard Worker
177*bebae9c0SAndroid Build Coastguard Worker //-----------------------------------------------------------------
178*bebae9c0SAndroid Build Coastguard Worker
179*bebae9c0SAndroid Build Coastguard Worker /* Play some music from a URI */
TestPlayStream(SLObjectItf sl,const char * path)180*bebae9c0SAndroid Build Coastguard Worker void TestPlayStream( SLObjectItf sl, const char* path)
181*bebae9c0SAndroid Build Coastguard Worker {
182*bebae9c0SAndroid Build Coastguard Worker SLEngineItf EngineItf;
183*bebae9c0SAndroid Build Coastguard Worker
184*bebae9c0SAndroid Build Coastguard Worker SLresult res;
185*bebae9c0SAndroid Build Coastguard Worker
186*bebae9c0SAndroid Build Coastguard Worker SLDataSource audioSource;
187*bebae9c0SAndroid Build Coastguard Worker SLDataLocator_AndroidBufferQueue streamLocator;
188*bebae9c0SAndroid Build Coastguard Worker SLDataFormat_MIME mime;
189*bebae9c0SAndroid Build Coastguard Worker
190*bebae9c0SAndroid Build Coastguard Worker SLDataSink audioSink;
191*bebae9c0SAndroid Build Coastguard Worker SLDataLocator_OutputMix locator_outputmix;
192*bebae9c0SAndroid Build Coastguard Worker
193*bebae9c0SAndroid Build Coastguard Worker SLObjectItf player;
194*bebae9c0SAndroid Build Coastguard Worker SLPlayItf playItf;
195*bebae9c0SAndroid Build Coastguard Worker SLVolumeItf volItf;
196*bebae9c0SAndroid Build Coastguard Worker SLAndroidBufferQueueItf abqItf;
197*bebae9c0SAndroid Build Coastguard Worker
198*bebae9c0SAndroid Build Coastguard Worker SLObjectItf OutputMix;
199*bebae9c0SAndroid Build Coastguard Worker
200*bebae9c0SAndroid Build Coastguard Worker SLboolean required[MAX_NUMBER_INTERFACES];
201*bebae9c0SAndroid Build Coastguard Worker SLInterfaceID iidArray[MAX_NUMBER_INTERFACES];
202*bebae9c0SAndroid Build Coastguard Worker
203*bebae9c0SAndroid Build Coastguard Worker int playTimeInSec = 60;
204*bebae9c0SAndroid Build Coastguard Worker
205*bebae9c0SAndroid Build Coastguard Worker file = fopen(path, "rb");
206*bebae9c0SAndroid Build Coastguard Worker
207*bebae9c0SAndroid Build Coastguard Worker /* Get the SL Engine Interface which is implicit */
208*bebae9c0SAndroid Build Coastguard Worker res = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf);
209*bebae9c0SAndroid Build Coastguard Worker CheckErr(res);
210*bebae9c0SAndroid Build Coastguard Worker
211*bebae9c0SAndroid Build Coastguard Worker /* Initialize arrays required[] and iidArray[] */
212*bebae9c0SAndroid Build Coastguard Worker for (int i=0 ; i < MAX_NUMBER_INTERFACES ; i++) {
213*bebae9c0SAndroid Build Coastguard Worker required[i] = SL_BOOLEAN_FALSE;
214*bebae9c0SAndroid Build Coastguard Worker iidArray[i] = SL_IID_NULL;
215*bebae9c0SAndroid Build Coastguard Worker }
216*bebae9c0SAndroid Build Coastguard Worker
217*bebae9c0SAndroid Build Coastguard Worker // Set arrays required[] and iidArray[] for VOLUME and PREFETCHSTATUS interface
218*bebae9c0SAndroid Build Coastguard Worker required[0] = SL_BOOLEAN_TRUE;
219*bebae9c0SAndroid Build Coastguard Worker iidArray[0] = SL_IID_VOLUME;
220*bebae9c0SAndroid Build Coastguard Worker required[1] = SL_BOOLEAN_TRUE;
221*bebae9c0SAndroid Build Coastguard Worker iidArray[1] = SL_IID_ANDROIDBUFFERQUEUESOURCE;
222*bebae9c0SAndroid Build Coastguard Worker // Create Output Mix object to be used by player
223*bebae9c0SAndroid Build Coastguard Worker res = (*EngineItf)->CreateOutputMix(EngineItf, &OutputMix, 0,
224*bebae9c0SAndroid Build Coastguard Worker iidArray, required); CheckErr(res);
225*bebae9c0SAndroid Build Coastguard Worker
226*bebae9c0SAndroid Build Coastguard Worker // Realizing the Output Mix object in synchronous mode.
227*bebae9c0SAndroid Build Coastguard Worker res = (*OutputMix)->Realize(OutputMix, SL_BOOLEAN_FALSE);
228*bebae9c0SAndroid Build Coastguard Worker CheckErr(res);
229*bebae9c0SAndroid Build Coastguard Worker
230*bebae9c0SAndroid Build Coastguard Worker /* Setup the data source structure for the URI */
231*bebae9c0SAndroid Build Coastguard Worker streamLocator.locatorType = SL_DATALOCATOR_ANDROIDBUFFERQUEUE;
232*bebae9c0SAndroid Build Coastguard Worker streamLocator.numBuffers = NB_BUFFERS;
233*bebae9c0SAndroid Build Coastguard Worker mime.formatType = SL_DATAFORMAT_MIME;
234*bebae9c0SAndroid Build Coastguard Worker mime.mimeType = (SLchar *) "video/mp2ts";//(SLchar*)NULL;
235*bebae9c0SAndroid Build Coastguard Worker mime.containerType = SL_CONTAINERTYPE_MPEG_TS;
236*bebae9c0SAndroid Build Coastguard Worker
237*bebae9c0SAndroid Build Coastguard Worker audioSource.pFormat = (void *)&mime;
238*bebae9c0SAndroid Build Coastguard Worker audioSource.pLocator = (void *)&streamLocator;
239*bebae9c0SAndroid Build Coastguard Worker
240*bebae9c0SAndroid Build Coastguard Worker /* Setup the data sink structure */
241*bebae9c0SAndroid Build Coastguard Worker locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
242*bebae9c0SAndroid Build Coastguard Worker locator_outputmix.outputMix = OutputMix;
243*bebae9c0SAndroid Build Coastguard Worker audioSink.pLocator = (void *)&locator_outputmix;
244*bebae9c0SAndroid Build Coastguard Worker audioSink.pFormat = NULL;
245*bebae9c0SAndroid Build Coastguard Worker
246*bebae9c0SAndroid Build Coastguard Worker /* Create the audio player */
247*bebae9c0SAndroid Build Coastguard Worker res = (*EngineItf)->CreateAudioPlayer(EngineItf, &player, &audioSource, &audioSink,
248*bebae9c0SAndroid Build Coastguard Worker MAX_NUMBER_INTERFACES, iidArray, required); CheckErr(res);
249*bebae9c0SAndroid Build Coastguard Worker
250*bebae9c0SAndroid Build Coastguard Worker /* Realizing the player in synchronous mode. */
251*bebae9c0SAndroid Build Coastguard Worker res = (*player)->Realize(player, SL_BOOLEAN_FALSE); CheckErr(res);
252*bebae9c0SAndroid Build Coastguard Worker fprintf(stdout, "URI example: after Realize\n");
253*bebae9c0SAndroid Build Coastguard Worker
254*bebae9c0SAndroid Build Coastguard Worker /* Get interfaces */
255*bebae9c0SAndroid Build Coastguard Worker res = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf); CheckErr(res);
256*bebae9c0SAndroid Build Coastguard Worker
257*bebae9c0SAndroid Build Coastguard Worker res = (*player)->GetInterface(player, SL_IID_VOLUME, (void*)&volItf); CheckErr(res);
258*bebae9c0SAndroid Build Coastguard Worker
259*bebae9c0SAndroid Build Coastguard Worker res = (*player)->GetInterface(player, SL_IID_ANDROIDBUFFERQUEUESOURCE, (void*)&abqItf);
260*bebae9c0SAndroid Build Coastguard Worker CheckErr(res);
261*bebae9c0SAndroid Build Coastguard Worker
262*bebae9c0SAndroid Build Coastguard Worker res = (*abqItf)->RegisterCallback(abqItf, AndroidBufferQueueCallback,
263*bebae9c0SAndroid Build Coastguard Worker // context is not used in the example, but can be used to track who registered
264*bebae9c0SAndroid Build Coastguard Worker // the buffer queue callback
265*bebae9c0SAndroid Build Coastguard Worker NULL /*pContext*/); CheckErr(res);
266*bebae9c0SAndroid Build Coastguard Worker
267*bebae9c0SAndroid Build Coastguard Worker res = (*abqItf)->SetCallbackEventsMask(abqItf, SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED);
268*bebae9c0SAndroid Build Coastguard Worker CheckErr(res);
269*bebae9c0SAndroid Build Coastguard Worker
270*bebae9c0SAndroid Build Coastguard Worker /* Display duration */
271*bebae9c0SAndroid Build Coastguard Worker SLmillisecond durationInMsec = SL_TIME_UNKNOWN;
272*bebae9c0SAndroid Build Coastguard Worker res = (*playItf)->GetDuration(playItf, &durationInMsec);
273*bebae9c0SAndroid Build Coastguard Worker CheckErr(res);
274*bebae9c0SAndroid Build Coastguard Worker if (durationInMsec == SL_TIME_UNKNOWN) {
275*bebae9c0SAndroid Build Coastguard Worker fprintf(stdout, "Content duration is unknown (before starting to prefetch)\n");
276*bebae9c0SAndroid Build Coastguard Worker } else {
277*bebae9c0SAndroid Build Coastguard Worker fprintf(stdout, "Content duration is %u ms (before starting to prefetch)\n",
278*bebae9c0SAndroid Build Coastguard Worker durationInMsec);
279*bebae9c0SAndroid Build Coastguard Worker }
280*bebae9c0SAndroid Build Coastguard Worker
281*bebae9c0SAndroid Build Coastguard Worker /* Set the player volume */
282*bebae9c0SAndroid Build Coastguard Worker res = (*volItf)->SetVolumeLevel( volItf, 0);//-300);
283*bebae9c0SAndroid Build Coastguard Worker CheckErr(res);
284*bebae9c0SAndroid Build Coastguard Worker
285*bebae9c0SAndroid Build Coastguard Worker
286*bebae9c0SAndroid Build Coastguard Worker /* Play the URI */
287*bebae9c0SAndroid Build Coastguard Worker /* first cause the player to prefetch the data */
288*bebae9c0SAndroid Build Coastguard Worker fprintf(stdout, "Before set to PAUSED\n");
289*bebae9c0SAndroid Build Coastguard Worker res = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PAUSED );
290*bebae9c0SAndroid Build Coastguard Worker fprintf(stdout, "After set to PAUSED\n");
291*bebae9c0SAndroid Build Coastguard Worker CheckErr(res);
292*bebae9c0SAndroid Build Coastguard Worker
293*bebae9c0SAndroid Build Coastguard Worker /* Fill our cache */
294*bebae9c0SAndroid Build Coastguard Worker if (fread(dataCache, 1, BUFFER_SIZE * NB_BUFFERS, file) <= 0) {
295*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, "Error filling cache, exiting\n");
296*bebae9c0SAndroid Build Coastguard Worker goto destroyRes;
297*bebae9c0SAndroid Build Coastguard Worker }
298*bebae9c0SAndroid Build Coastguard Worker /* Enqueue the content of our cache before starting to play,
299*bebae9c0SAndroid Build Coastguard Worker * we don't want to starve the player */
300*bebae9c0SAndroid Build Coastguard Worker for (int i=0 ; i < NB_BUFFERS ; i++) {
301*bebae9c0SAndroid Build Coastguard Worker res = (*abqItf)->Enqueue(abqItf, NULL /*pBufferContext*/,
302*bebae9c0SAndroid Build Coastguard Worker dataCache + i*BUFFER_SIZE, BUFFER_SIZE, NULL, 0);
303*bebae9c0SAndroid Build Coastguard Worker CheckErr(res);
304*bebae9c0SAndroid Build Coastguard Worker }
305*bebae9c0SAndroid Build Coastguard Worker
306*bebae9c0SAndroid Build Coastguard Worker #if 0 // used to test ABQ starving where only one buffer is enqueued before playback
307*bebae9c0SAndroid Build Coastguard Worker /* Fill our cache */
308*bebae9c0SAndroid Build Coastguard Worker if (fread(dataCache, 1, BUFFER_SIZE * 1, file) <= 0) {
309*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, "Error filling cache, exiting\n");
310*bebae9c0SAndroid Build Coastguard Worker goto destroyRes;
311*bebae9c0SAndroid Build Coastguard Worker }
312*bebae9c0SAndroid Build Coastguard Worker /* Enqueue the content of our cache before starting to play,
313*bebae9c0SAndroid Build Coastguard Worker * we don't want to starve the player */
314*bebae9c0SAndroid Build Coastguard Worker for (int i=0 ; i < 1 ; i++) {
315*bebae9c0SAndroid Build Coastguard Worker res = (*abqItf)->Enqueue(abqItf, dataCache + i*BUFFER_SIZE, BUFFER_SIZE, NULL, 0);
316*bebae9c0SAndroid Build Coastguard Worker CheckErr(res);
317*bebae9c0SAndroid Build Coastguard Worker }
318*bebae9c0SAndroid Build Coastguard Worker #endif
319*bebae9c0SAndroid Build Coastguard Worker /* wait until there's data to play */
320*bebae9c0SAndroid Build Coastguard Worker //SLpermille fillLevel = 0;
321*bebae9c0SAndroid Build Coastguard Worker /*
322*bebae9c0SAndroid Build Coastguard Worker SLuint32 prefetchStatus = SL_PREFETCHSTATUS_UNDERFLOW;
323*bebae9c0SAndroid Build Coastguard Worker SLuint32 timeOutIndex = 2;
324*bebae9c0SAndroid Build Coastguard Worker while ((prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) && (timeOutIndex > 0) &&
325*bebae9c0SAndroid Build Coastguard Worker !prefetchError) {
326*bebae9c0SAndroid Build Coastguard Worker usleep(1 * 1000 * 1000); // 1s
327*bebae9c0SAndroid Build Coastguard Worker //(*prefetchItf)->GetPrefetchStatus(prefetchItf, &prefetchStatus);
328*bebae9c0SAndroid Build Coastguard Worker timeOutIndex--;
329*bebae9c0SAndroid Build Coastguard Worker }
330*bebae9c0SAndroid Build Coastguard Worker
331*bebae9c0SAndroid Build Coastguard Worker if (timeOutIndex == 0 || prefetchError) {
332*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, "We\'re done waiting, failed to prefetch data in time, exiting\n");
333*bebae9c0SAndroid Build Coastguard Worker goto destroyRes;
334*bebae9c0SAndroid Build Coastguard Worker }
335*bebae9c0SAndroid Build Coastguard Worker */
336*bebae9c0SAndroid Build Coastguard Worker
337*bebae9c0SAndroid Build Coastguard Worker /* Display duration again, */
338*bebae9c0SAndroid Build Coastguard Worker /* res = (*playItf)->GetDuration(playItf, &durationInMsec);
339*bebae9c0SAndroid Build Coastguard Worker CheckErr(res);
340*bebae9c0SAndroid Build Coastguard Worker if (durationInMsec == SL_TIME_UNKNOWN) {
341*bebae9c0SAndroid Build Coastguard Worker fprintf(stdout, "Content duration is unknown (after prefetch completed)\n");
342*bebae9c0SAndroid Build Coastguard Worker } else {
343*bebae9c0SAndroid Build Coastguard Worker fprintf(stdout, "Content duration is %lu ms (after prefetch completed)\n", durationInMsec);
344*bebae9c0SAndroid Build Coastguard Worker }
345*bebae9c0SAndroid Build Coastguard Worker */
346*bebae9c0SAndroid Build Coastguard Worker
347*bebae9c0SAndroid Build Coastguard Worker fprintf(stdout, "URI example: starting to play\n");
348*bebae9c0SAndroid Build Coastguard Worker res = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PLAYING );
349*bebae9c0SAndroid Build Coastguard Worker CheckErr(res);
350*bebae9c0SAndroid Build Coastguard Worker
351*bebae9c0SAndroid Build Coastguard Worker /* Wait as long as the duration of the content before stopping */
352*bebae9c0SAndroid Build Coastguard Worker fprintf(stdout, "Letting playback go on for %d sec\n", playTimeInSec);
353*bebae9c0SAndroid Build Coastguard Worker usleep(playTimeInSec /*s*/ * 1000 * 1000);
354*bebae9c0SAndroid Build Coastguard Worker
355*bebae9c0SAndroid Build Coastguard Worker
356*bebae9c0SAndroid Build Coastguard Worker /* Make sure player is stopped */
357*bebae9c0SAndroid Build Coastguard Worker fprintf(stdout, "URI example: stopping playback\n");
358*bebae9c0SAndroid Build Coastguard Worker res = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
359*bebae9c0SAndroid Build Coastguard Worker CheckErr(res);
360*bebae9c0SAndroid Build Coastguard Worker
361*bebae9c0SAndroid Build Coastguard Worker fprintf(stdout, "sleeping to verify playback stopped\n");
362*bebae9c0SAndroid Build Coastguard Worker usleep(2 /*s*/ * 1000 * 1000);
363*bebae9c0SAndroid Build Coastguard Worker
364*bebae9c0SAndroid Build Coastguard Worker destroyRes:
365*bebae9c0SAndroid Build Coastguard Worker
366*bebae9c0SAndroid Build Coastguard Worker /* Destroy the player */
367*bebae9c0SAndroid Build Coastguard Worker (*player)->Destroy(player);
368*bebae9c0SAndroid Build Coastguard Worker
369*bebae9c0SAndroid Build Coastguard Worker /* Destroy Output Mix object */
370*bebae9c0SAndroid Build Coastguard Worker (*OutputMix)->Destroy(OutputMix);
371*bebae9c0SAndroid Build Coastguard Worker
372*bebae9c0SAndroid Build Coastguard Worker fclose(file);
373*bebae9c0SAndroid Build Coastguard Worker }
374*bebae9c0SAndroid Build Coastguard Worker
375*bebae9c0SAndroid Build Coastguard Worker //-----------------------------------------------------------------
main(int argc,char * const argv[])376*bebae9c0SAndroid Build Coastguard Worker int main(int argc, char* const argv[])
377*bebae9c0SAndroid Build Coastguard Worker {
378*bebae9c0SAndroid Build Coastguard Worker SLresult res;
379*bebae9c0SAndroid Build Coastguard Worker SLObjectItf sl;
380*bebae9c0SAndroid Build Coastguard Worker
381*bebae9c0SAndroid Build Coastguard Worker fprintf(stdout, "OpenSL ES test %s: exercises SLPlayItf, SLVolumeItf, SLAndroidBufferQueue \n",
382*bebae9c0SAndroid Build Coastguard Worker argv[0]);
383*bebae9c0SAndroid Build Coastguard Worker fprintf(stdout, "and AudioPlayer with SL_DATALOCATOR_ANDROIDBUFFERQUEUE source / OutputMix "
384*bebae9c0SAndroid Build Coastguard Worker "sink\n");
385*bebae9c0SAndroid Build Coastguard Worker fprintf(stdout, "Plays a sound and stops after its reported duration\n\n");
386*bebae9c0SAndroid Build Coastguard Worker
387*bebae9c0SAndroid Build Coastguard Worker if (argc != 2) {
388*bebae9c0SAndroid Build Coastguard Worker fprintf(stdout, "Usage: %s path.ts\n", argv[0]);
389*bebae9c0SAndroid Build Coastguard Worker exit(EXIT_FAILURE);
390*bebae9c0SAndroid Build Coastguard Worker }
391*bebae9c0SAndroid Build Coastguard Worker
392*bebae9c0SAndroid Build Coastguard Worker SLEngineOption EngineOption[] = {
393*bebae9c0SAndroid Build Coastguard Worker {(SLuint32) SL_ENGINEOPTION_THREADSAFE,
394*bebae9c0SAndroid Build Coastguard Worker (SLuint32) SL_BOOLEAN_TRUE}};
395*bebae9c0SAndroid Build Coastguard Worker
396*bebae9c0SAndroid Build Coastguard Worker res = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL);
397*bebae9c0SAndroid Build Coastguard Worker CheckErr(res);
398*bebae9c0SAndroid Build Coastguard Worker /* Realizing the SL Engine in synchronous mode. */
399*bebae9c0SAndroid Build Coastguard Worker res = (*sl)->Realize(sl, SL_BOOLEAN_FALSE);
400*bebae9c0SAndroid Build Coastguard Worker CheckErr(res);
401*bebae9c0SAndroid Build Coastguard Worker
402*bebae9c0SAndroid Build Coastguard Worker TestPlayStream(sl, argv[1]);
403*bebae9c0SAndroid Build Coastguard Worker
404*bebae9c0SAndroid Build Coastguard Worker /* Shutdown OpenSL ES */
405*bebae9c0SAndroid Build Coastguard Worker (*sl)->Destroy(sl);
406*bebae9c0SAndroid Build Coastguard Worker
407*bebae9c0SAndroid Build Coastguard Worker return EXIT_SUCCESS;
408*bebae9c0SAndroid Build Coastguard Worker }
409