xref: /aosp_15_r20/frameworks/wilhelm/tests/sandbox/xaplay.c (revision bebae9c0e76121f8312ccb50385c080b3a0b023c)
1*bebae9c0SAndroid Build Coastguard Worker /*
2*bebae9c0SAndroid Build Coastguard Worker  * Copyright (C) 2011 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 // OpenMAX AL MediaPlayer command-line player
18*bebae9c0SAndroid Build Coastguard Worker 
19*bebae9c0SAndroid Build Coastguard Worker #include <assert.h>
20*bebae9c0SAndroid Build Coastguard Worker #include <pthread.h>
21*bebae9c0SAndroid Build Coastguard Worker #include <stdio.h>
22*bebae9c0SAndroid Build Coastguard Worker #include <stdlib.h>
23*bebae9c0SAndroid Build Coastguard Worker #include <string.h>
24*bebae9c0SAndroid Build Coastguard Worker #include <fcntl.h>
25*bebae9c0SAndroid Build Coastguard Worker #include <sys/mman.h>
26*bebae9c0SAndroid Build Coastguard Worker #include <sys/stat.h>
27*bebae9c0SAndroid Build Coastguard Worker #include <unistd.h>
28*bebae9c0SAndroid Build Coastguard Worker #include <OMXAL/OpenMAXAL.h>
29*bebae9c0SAndroid Build Coastguard Worker #include <OMXAL/OpenMAXAL_Android.h>
30*bebae9c0SAndroid Build Coastguard Worker #include "nativewindow.h"
31*bebae9c0SAndroid Build Coastguard Worker 
32*bebae9c0SAndroid Build Coastguard Worker #define MPEG2TS_PACKET_SIZE 188  // MPEG-2 transport stream packet size in bytes
33*bebae9c0SAndroid Build Coastguard Worker #define PACKETS_PER_BUFFER 20    // Number of MPEG-2 transport stream packets per buffer
34*bebae9c0SAndroid Build Coastguard Worker 
35*bebae9c0SAndroid Build Coastguard Worker #define NB_BUFFERS 2    // Number of buffers in Android buffer queue
36*bebae9c0SAndroid Build Coastguard Worker 
37*bebae9c0SAndroid Build Coastguard Worker // MPEG-2 transport stream packet
38*bebae9c0SAndroid Build Coastguard Worker typedef struct {
39*bebae9c0SAndroid Build Coastguard Worker     char data[MPEG2TS_PACKET_SIZE];
40*bebae9c0SAndroid Build Coastguard Worker } MPEG2TS_Packet;
41*bebae9c0SAndroid Build Coastguard Worker 
42*bebae9c0SAndroid Build Coastguard Worker // Globals shared between main thread and buffer queue callback
43*bebae9c0SAndroid Build Coastguard Worker MPEG2TS_Packet *packets;
44*bebae9c0SAndroid Build Coastguard Worker size_t totalPackets;    // total number of packets in input file
45*bebae9c0SAndroid Build Coastguard Worker size_t numPackets;      // number of packets to play, defaults to totalPackets - firstPacket
46*bebae9c0SAndroid Build Coastguard Worker size_t curPacket;       // current packet index
47*bebae9c0SAndroid Build Coastguard Worker size_t discPacket;      // discontinuity packet index, defaults to no discontinuity requested
48*bebae9c0SAndroid Build Coastguard Worker size_t afterDiscPacket; // packet index to switch to after the discontinuity
49*bebae9c0SAndroid Build Coastguard Worker size_t firstPacket;     // first packet index to be played, defaults to zero
50*bebae9c0SAndroid Build Coastguard Worker size_t lastPacket;      // last packet index to be played
51*bebae9c0SAndroid Build Coastguard Worker size_t formatPacket;    // format change packet index, defaults to no format change requested
52*bebae9c0SAndroid Build Coastguard Worker XAmillisecond seekPos = XA_TIME_UNKNOWN;    // seek to this position initially
53*bebae9c0SAndroid Build Coastguard Worker int pauseMs = -1;       // pause after this many ms into playback
54*bebae9c0SAndroid Build Coastguard Worker XAboolean forceCallbackFailure = XA_BOOLEAN_FALSE;  // force callback failures occasionally
55*bebae9c0SAndroid Build Coastguard Worker XAboolean sentEOS = XA_BOOLEAN_FALSE;   // whether we have enqueued EOS yet
56*bebae9c0SAndroid Build Coastguard Worker 
57*bebae9c0SAndroid Build Coastguard Worker // These are extensions to OpenMAX AL 1.0.1 values
58*bebae9c0SAndroid Build Coastguard Worker 
59*bebae9c0SAndroid Build Coastguard Worker #define PREFETCHSTATUS_UNKNOWN ((XAuint32) 0)
60*bebae9c0SAndroid Build Coastguard Worker #define PREFETCHSTATUS_ERROR   ((XAuint32) (-1))
61*bebae9c0SAndroid Build Coastguard Worker 
62*bebae9c0SAndroid Build Coastguard Worker // Mutex and condition shared with main program to protect prefetch_status
63*bebae9c0SAndroid Build Coastguard Worker 
64*bebae9c0SAndroid Build Coastguard Worker static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
65*bebae9c0SAndroid Build Coastguard Worker static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
66*bebae9c0SAndroid Build Coastguard Worker XAuint32 prefetch_status = PREFETCHSTATUS_UNKNOWN;
67*bebae9c0SAndroid Build Coastguard Worker 
68*bebae9c0SAndroid Build Coastguard Worker /* used to detect errors likely to have occured when the OpenMAX AL framework fails to open
69*bebae9c0SAndroid Build Coastguard Worker  * a resource, for instance because a file URI is invalid, or an HTTP server doesn't respond.
70*bebae9c0SAndroid Build Coastguard Worker  */
71*bebae9c0SAndroid Build Coastguard Worker #define PREFETCHEVENT_ERROR_CANDIDATE \
72*bebae9c0SAndroid Build Coastguard Worker         (XA_PREFETCHEVENT_STATUSCHANGE | XA_PREFETCHEVENT_FILLLEVELCHANGE)
73*bebae9c0SAndroid Build Coastguard Worker 
74*bebae9c0SAndroid Build Coastguard Worker // stream event change callback
streamEventChangeCallback(XAStreamInformationItf caller __unused,XAuint32 eventId,XAuint32 streamIndex,void * pEventData,void * pContext)75*bebae9c0SAndroid Build Coastguard Worker void streamEventChangeCallback(XAStreamInformationItf caller __unused, XAuint32 eventId,
76*bebae9c0SAndroid Build Coastguard Worker         XAuint32 streamIndex, void *pEventData, void *pContext)
77*bebae9c0SAndroid Build Coastguard Worker {
78*bebae9c0SAndroid Build Coastguard Worker     // context parameter is specified as NULL and is unused here
79*bebae9c0SAndroid Build Coastguard Worker     assert(NULL == pContext);
80*bebae9c0SAndroid Build Coastguard Worker     switch (eventId) {
81*bebae9c0SAndroid Build Coastguard Worker     case XA_STREAMCBEVENT_PROPERTYCHANGE:
82*bebae9c0SAndroid Build Coastguard Worker         printf("XA_STREAMCBEVENT_PROPERTYCHANGE on stream index %u, pEventData %p\n", streamIndex,
83*bebae9c0SAndroid Build Coastguard Worker                 pEventData);
84*bebae9c0SAndroid Build Coastguard Worker         break;
85*bebae9c0SAndroid Build Coastguard Worker     default:
86*bebae9c0SAndroid Build Coastguard Worker         printf("Unknown stream event ID %u\n", eventId);
87*bebae9c0SAndroid Build Coastguard Worker         break;
88*bebae9c0SAndroid Build Coastguard Worker     }
89*bebae9c0SAndroid Build Coastguard Worker }
90*bebae9c0SAndroid Build Coastguard Worker 
91*bebae9c0SAndroid Build Coastguard Worker // prefetch status callback
prefetchStatusCallback(XAPrefetchStatusItf caller,void * pContext,XAuint32 event)92*bebae9c0SAndroid Build Coastguard Worker void prefetchStatusCallback(XAPrefetchStatusItf caller,  void *pContext, XAuint32 event)
93*bebae9c0SAndroid Build Coastguard Worker {
94*bebae9c0SAndroid Build Coastguard Worker     // pContext is unused here, so we pass NULL
95*bebae9c0SAndroid Build Coastguard Worker     assert(pContext == NULL);
96*bebae9c0SAndroid Build Coastguard Worker     XApermille level = 0;
97*bebae9c0SAndroid Build Coastguard Worker     XAresult result;
98*bebae9c0SAndroid Build Coastguard Worker     result = (*caller)->GetFillLevel(caller, &level);
99*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_SUCCESS == result);
100*bebae9c0SAndroid Build Coastguard Worker     XAuint32 status;
101*bebae9c0SAndroid Build Coastguard Worker     result = (*caller)->GetPrefetchStatus(caller, &status);
102*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_SUCCESS == result);
103*bebae9c0SAndroid Build Coastguard Worker     if (event & XA_PREFETCHEVENT_FILLLEVELCHANGE) {
104*bebae9c0SAndroid Build Coastguard Worker         printf("PrefetchEventCallback: Buffer fill level is = %d\n", level);
105*bebae9c0SAndroid Build Coastguard Worker     }
106*bebae9c0SAndroid Build Coastguard Worker     if (event & XA_PREFETCHEVENT_STATUSCHANGE) {
107*bebae9c0SAndroid Build Coastguard Worker         printf("PrefetchEventCallback: Prefetch Status is = %u\n", status);
108*bebae9c0SAndroid Build Coastguard Worker     }
109*bebae9c0SAndroid Build Coastguard Worker     XAuint32 new_prefetch_status;
110*bebae9c0SAndroid Build Coastguard Worker     if ((PREFETCHEVENT_ERROR_CANDIDATE == (event & PREFETCHEVENT_ERROR_CANDIDATE))
111*bebae9c0SAndroid Build Coastguard Worker             && (level == 0) && (status == XA_PREFETCHSTATUS_UNDERFLOW)) {
112*bebae9c0SAndroid Build Coastguard Worker         printf("PrefetchEventCallback: Error while prefetching data, exiting\n");
113*bebae9c0SAndroid Build Coastguard Worker         new_prefetch_status = PREFETCHSTATUS_ERROR;
114*bebae9c0SAndroid Build Coastguard Worker     } else if (event == XA_PREFETCHEVENT_STATUSCHANGE) {
115*bebae9c0SAndroid Build Coastguard Worker         new_prefetch_status = status;
116*bebae9c0SAndroid Build Coastguard Worker     } else {
117*bebae9c0SAndroid Build Coastguard Worker         return;
118*bebae9c0SAndroid Build Coastguard Worker     }
119*bebae9c0SAndroid Build Coastguard Worker     int ok;
120*bebae9c0SAndroid Build Coastguard Worker     ok = pthread_mutex_lock(&mutex);
121*bebae9c0SAndroid Build Coastguard Worker     assert(ok == 0);
122*bebae9c0SAndroid Build Coastguard Worker     prefetch_status = new_prefetch_status;
123*bebae9c0SAndroid Build Coastguard Worker     ok = pthread_cond_signal(&cond);
124*bebae9c0SAndroid Build Coastguard Worker     assert(ok == 0);
125*bebae9c0SAndroid Build Coastguard Worker     ok = pthread_mutex_unlock(&mutex);
126*bebae9c0SAndroid Build Coastguard Worker     assert(ok == 0);
127*bebae9c0SAndroid Build Coastguard Worker }
128*bebae9c0SAndroid Build Coastguard Worker 
129*bebae9c0SAndroid Build Coastguard Worker // playback event callback
playEventCallback(XAPlayItf caller,void * pContext,XAuint32 event)130*bebae9c0SAndroid Build Coastguard Worker void playEventCallback(XAPlayItf caller, void *pContext, XAuint32 event)
131*bebae9c0SAndroid Build Coastguard Worker {
132*bebae9c0SAndroid Build Coastguard Worker     // pContext is unused here, so we pass NULL
133*bebae9c0SAndroid Build Coastguard Worker     assert(NULL == pContext);
134*bebae9c0SAndroid Build Coastguard Worker 
135*bebae9c0SAndroid Build Coastguard Worker     XAresult result;
136*bebae9c0SAndroid Build Coastguard Worker     XAmillisecond position;
137*bebae9c0SAndroid Build Coastguard Worker     result = (*caller)->GetPosition(caller, &position);
138*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_SUCCESS == result);
139*bebae9c0SAndroid Build Coastguard Worker 
140*bebae9c0SAndroid Build Coastguard Worker     if (XA_PLAYEVENT_HEADATEND & event) {
141*bebae9c0SAndroid Build Coastguard Worker         printf("XA_PLAYEVENT_HEADATEND current position=%u ms\n", position);
142*bebae9c0SAndroid Build Coastguard Worker     }
143*bebae9c0SAndroid Build Coastguard Worker 
144*bebae9c0SAndroid Build Coastguard Worker     if (XA_PLAYEVENT_HEADATNEWPOS & event) {
145*bebae9c0SAndroid Build Coastguard Worker         printf("XA_PLAYEVENT_HEADATNEWPOS current position=%u ms\n", position);
146*bebae9c0SAndroid Build Coastguard Worker     }
147*bebae9c0SAndroid Build Coastguard Worker 
148*bebae9c0SAndroid Build Coastguard Worker     if (XA_PLAYEVENT_HEADATMARKER & event) {
149*bebae9c0SAndroid Build Coastguard Worker         printf("XA_PLAYEVENT_HEADATMARKER current position=%u ms\n", position);
150*bebae9c0SAndroid Build Coastguard Worker     }
151*bebae9c0SAndroid Build Coastguard Worker }
152*bebae9c0SAndroid Build Coastguard Worker 
153*bebae9c0SAndroid Build Coastguard Worker // Android buffer queue callback
bufferQueueCallback(XAAndroidBufferQueueItf caller,void * pCallbackContext,void * pBufferContext __unused,void * pBufferData __unused,XAuint32 dataSize __unused,XAuint32 dataUsed __unused,const XAAndroidBufferItem * pItems __unused,XAuint32 itemsLength __unused)154*bebae9c0SAndroid Build Coastguard Worker XAresult bufferQueueCallback(
155*bebae9c0SAndroid Build Coastguard Worker         XAAndroidBufferQueueItf caller,
156*bebae9c0SAndroid Build Coastguard Worker         void *pCallbackContext,
157*bebae9c0SAndroid Build Coastguard Worker         void *pBufferContext __unused,
158*bebae9c0SAndroid Build Coastguard Worker         void *pBufferData __unused,
159*bebae9c0SAndroid Build Coastguard Worker         XAuint32 dataSize __unused,
160*bebae9c0SAndroid Build Coastguard Worker         XAuint32 dataUsed __unused,
161*bebae9c0SAndroid Build Coastguard Worker         const XAAndroidBufferItem *pItems __unused,
162*bebae9c0SAndroid Build Coastguard Worker         XAuint32 itemsLength __unused)
163*bebae9c0SAndroid Build Coastguard Worker {
164*bebae9c0SAndroid Build Coastguard Worker     XAPlayItf playerPlay = (XAPlayItf) pCallbackContext;
165*bebae9c0SAndroid Build Coastguard Worker     // enqueue the .ts data directly from mapped memory, so ignore the empty buffer pBufferData
166*bebae9c0SAndroid Build Coastguard Worker     if (curPacket <= lastPacket) {
167*bebae9c0SAndroid Build Coastguard Worker         static const XAAndroidBufferItem discontinuity = {XA_ANDROID_ITEMKEY_DISCONTINUITY, 0, {}};
168*bebae9c0SAndroid Build Coastguard Worker         static const XAAndroidBufferItem eos = {XA_ANDROID_ITEMKEY_EOS, 0, {}};
169*bebae9c0SAndroid Build Coastguard Worker         static const XAAndroidBufferItem formatChange = {XA_ANDROID_ITEMKEY_FORMAT_CHANGE, 0, {}};
170*bebae9c0SAndroid Build Coastguard Worker         const XAAndroidBufferItem *items;
171*bebae9c0SAndroid Build Coastguard Worker         XAuint32 itemSize;
172*bebae9c0SAndroid Build Coastguard Worker         // compute number of packets to be enqueued in this buffer
173*bebae9c0SAndroid Build Coastguard Worker         XAuint32 packetsThisBuffer = lastPacket - curPacket;
174*bebae9c0SAndroid Build Coastguard Worker         if (packetsThisBuffer > PACKETS_PER_BUFFER) {
175*bebae9c0SAndroid Build Coastguard Worker             packetsThisBuffer = PACKETS_PER_BUFFER;
176*bebae9c0SAndroid Build Coastguard Worker         }
177*bebae9c0SAndroid Build Coastguard Worker         // last packet? this should only happen once
178*bebae9c0SAndroid Build Coastguard Worker         if (curPacket == lastPacket) {
179*bebae9c0SAndroid Build Coastguard Worker             if (sentEOS) {
180*bebae9c0SAndroid Build Coastguard Worker                 printf("buffer completion callback after EOS\n");
181*bebae9c0SAndroid Build Coastguard Worker                 return XA_RESULT_SUCCESS;
182*bebae9c0SAndroid Build Coastguard Worker             }
183*bebae9c0SAndroid Build Coastguard Worker             printf("sending EOS\n");
184*bebae9c0SAndroid Build Coastguard Worker             items = &eos;
185*bebae9c0SAndroid Build Coastguard Worker             itemSize = sizeof(eos);
186*bebae9c0SAndroid Build Coastguard Worker             sentEOS = XA_BOOLEAN_TRUE;
187*bebae9c0SAndroid Build Coastguard Worker         // discontinuity requested?
188*bebae9c0SAndroid Build Coastguard Worker         } else if (curPacket == discPacket) {
189*bebae9c0SAndroid Build Coastguard Worker             printf("sending discontinuity at packet %zu, then resuming at packet %zu\n", discPacket,
190*bebae9c0SAndroid Build Coastguard Worker                     afterDiscPacket);
191*bebae9c0SAndroid Build Coastguard Worker             items = &discontinuity;
192*bebae9c0SAndroid Build Coastguard Worker             itemSize = sizeof(discontinuity);
193*bebae9c0SAndroid Build Coastguard Worker             curPacket = afterDiscPacket;
194*bebae9c0SAndroid Build Coastguard Worker         // format change requested?
195*bebae9c0SAndroid Build Coastguard Worker         } else if (curPacket == formatPacket) {
196*bebae9c0SAndroid Build Coastguard Worker             printf("sending format change");
197*bebae9c0SAndroid Build Coastguard Worker             items = &formatChange;
198*bebae9c0SAndroid Build Coastguard Worker             itemSize = sizeof(formatChange);
199*bebae9c0SAndroid Build Coastguard Worker         // pure data with no items
200*bebae9c0SAndroid Build Coastguard Worker         } else {
201*bebae9c0SAndroid Build Coastguard Worker             items = NULL;
202*bebae9c0SAndroid Build Coastguard Worker             itemSize = 0;
203*bebae9c0SAndroid Build Coastguard Worker         }
204*bebae9c0SAndroid Build Coastguard Worker         XAresult result;
205*bebae9c0SAndroid Build Coastguard Worker         // enqueue the optional data and optional items; there is always at least one or the other
206*bebae9c0SAndroid Build Coastguard Worker         assert(packetsThisBuffer > 0 || itemSize > 0);
207*bebae9c0SAndroid Build Coastguard Worker         result = (*caller)->Enqueue(caller, NULL, &packets[curPacket],
208*bebae9c0SAndroid Build Coastguard Worker                 sizeof(MPEG2TS_Packet) * packetsThisBuffer, items, itemSize);
209*bebae9c0SAndroid Build Coastguard Worker         assert(XA_RESULT_SUCCESS == result);
210*bebae9c0SAndroid Build Coastguard Worker         curPacket += packetsThisBuffer;
211*bebae9c0SAndroid Build Coastguard Worker         // display position periodically
212*bebae9c0SAndroid Build Coastguard Worker         if (curPacket % 1000 == 0) {
213*bebae9c0SAndroid Build Coastguard Worker             XAmillisecond position;
214*bebae9c0SAndroid Build Coastguard Worker             result = (*playerPlay)->GetPosition(playerPlay, &position);
215*bebae9c0SAndroid Build Coastguard Worker             assert(XA_RESULT_SUCCESS == result);
216*bebae9c0SAndroid Build Coastguard Worker             printf("Position after enqueueing packet %zu: %u ms\n", curPacket, position);
217*bebae9c0SAndroid Build Coastguard Worker         }
218*bebae9c0SAndroid Build Coastguard Worker     }
219*bebae9c0SAndroid Build Coastguard Worker     if (forceCallbackFailure && (curPacket % 1230 == 0)) {
220*bebae9c0SAndroid Build Coastguard Worker         return (XAresult) curPacket;
221*bebae9c0SAndroid Build Coastguard Worker     } else {
222*bebae9c0SAndroid Build Coastguard Worker         return XA_RESULT_SUCCESS;
223*bebae9c0SAndroid Build Coastguard Worker     }
224*bebae9c0SAndroid Build Coastguard Worker }
225*bebae9c0SAndroid Build Coastguard Worker 
226*bebae9c0SAndroid Build Coastguard Worker // convert a domain type to string
domainToString(XAuint32 domain)227*bebae9c0SAndroid Build Coastguard Worker static const char *domainToString(XAuint32 domain)
228*bebae9c0SAndroid Build Coastguard Worker {
229*bebae9c0SAndroid Build Coastguard Worker     switch (domain) {
230*bebae9c0SAndroid Build Coastguard Worker     case 0: // FIXME There's a private declaration '#define XA_DOMAINTYPE_CONTAINER 0' in src/data.h
231*bebae9c0SAndroid Build Coastguard Worker             // but we don't have access to it. Plan to file a bug with Khronos about this symbol.
232*bebae9c0SAndroid Build Coastguard Worker         return "media container";
233*bebae9c0SAndroid Build Coastguard Worker #define _(x) case x: return #x;
234*bebae9c0SAndroid Build Coastguard Worker     _(XA_DOMAINTYPE_AUDIO)
235*bebae9c0SAndroid Build Coastguard Worker     _(XA_DOMAINTYPE_VIDEO)
236*bebae9c0SAndroid Build Coastguard Worker     _(XA_DOMAINTYPE_IMAGE)
237*bebae9c0SAndroid Build Coastguard Worker     _(XA_DOMAINTYPE_TIMEDTEXT)
238*bebae9c0SAndroid Build Coastguard Worker     _(XA_DOMAINTYPE_MIDI)
239*bebae9c0SAndroid Build Coastguard Worker     _(XA_DOMAINTYPE_VENDOR)
240*bebae9c0SAndroid Build Coastguard Worker     _(XA_DOMAINTYPE_UNKNOWN)
241*bebae9c0SAndroid Build Coastguard Worker #undef _
242*bebae9c0SAndroid Build Coastguard Worker     default:
243*bebae9c0SAndroid Build Coastguard Worker         return "unknown";
244*bebae9c0SAndroid Build Coastguard Worker     }
245*bebae9c0SAndroid Build Coastguard Worker }
246*bebae9c0SAndroid Build Coastguard Worker 
247*bebae9c0SAndroid Build Coastguard Worker // main program
main(int argc,char ** argv)248*bebae9c0SAndroid Build Coastguard Worker int main(int argc, char **argv)
249*bebae9c0SAndroid Build Coastguard Worker {
250*bebae9c0SAndroid Build Coastguard Worker     const char *prog = argv[0];
251*bebae9c0SAndroid Build Coastguard Worker     int i;
252*bebae9c0SAndroid Build Coastguard Worker 
253*bebae9c0SAndroid Build Coastguard Worker     XAboolean abq = XA_BOOLEAN_FALSE;   // use AndroidBufferQueue, default is URI
254*bebae9c0SAndroid Build Coastguard Worker     XAboolean looping = XA_BOOLEAN_FALSE;
255*bebae9c0SAndroid Build Coastguard Worker     for (i = 1; i < argc; ++i) {
256*bebae9c0SAndroid Build Coastguard Worker         const char *arg = argv[i];
257*bebae9c0SAndroid Build Coastguard Worker         if (arg[0] != '-')
258*bebae9c0SAndroid Build Coastguard Worker             break;
259*bebae9c0SAndroid Build Coastguard Worker         switch (arg[1]) {
260*bebae9c0SAndroid Build Coastguard Worker         case 'a':
261*bebae9c0SAndroid Build Coastguard Worker             abq = XA_BOOLEAN_TRUE;
262*bebae9c0SAndroid Build Coastguard Worker             break;
263*bebae9c0SAndroid Build Coastguard Worker         case 'c':
264*bebae9c0SAndroid Build Coastguard Worker             forceCallbackFailure = XA_BOOLEAN_TRUE;
265*bebae9c0SAndroid Build Coastguard Worker             break;
266*bebae9c0SAndroid Build Coastguard Worker         case 'd':
267*bebae9c0SAndroid Build Coastguard Worker             discPacket = atoi(&arg[2]);
268*bebae9c0SAndroid Build Coastguard Worker             break;
269*bebae9c0SAndroid Build Coastguard Worker         case 'D':
270*bebae9c0SAndroid Build Coastguard Worker             afterDiscPacket = atoi(&arg[2]);
271*bebae9c0SAndroid Build Coastguard Worker             break;
272*bebae9c0SAndroid Build Coastguard Worker         case 'f':
273*bebae9c0SAndroid Build Coastguard Worker             firstPacket = atoi(&arg[2]);
274*bebae9c0SAndroid Build Coastguard Worker             break;
275*bebae9c0SAndroid Build Coastguard Worker         case 'F':
276*bebae9c0SAndroid Build Coastguard Worker             formatPacket = atoi(&arg[2]);
277*bebae9c0SAndroid Build Coastguard Worker             break;
278*bebae9c0SAndroid Build Coastguard Worker         case 'l':
279*bebae9c0SAndroid Build Coastguard Worker             looping = XA_BOOLEAN_TRUE;
280*bebae9c0SAndroid Build Coastguard Worker             break;
281*bebae9c0SAndroid Build Coastguard Worker         case 'n':
282*bebae9c0SAndroid Build Coastguard Worker             numPackets = atoi(&arg[2]);
283*bebae9c0SAndroid Build Coastguard Worker             break;
284*bebae9c0SAndroid Build Coastguard Worker         case 'p':
285*bebae9c0SAndroid Build Coastguard Worker             pauseMs = atoi(&arg[2]);
286*bebae9c0SAndroid Build Coastguard Worker             break;
287*bebae9c0SAndroid Build Coastguard Worker         case 's':
288*bebae9c0SAndroid Build Coastguard Worker             seekPos = atoi(&arg[2]);
289*bebae9c0SAndroid Build Coastguard Worker             break;
290*bebae9c0SAndroid Build Coastguard Worker         default:
291*bebae9c0SAndroid Build Coastguard Worker             fprintf(stderr, "%s: unknown option %s\n", prog, arg);
292*bebae9c0SAndroid Build Coastguard Worker             break;
293*bebae9c0SAndroid Build Coastguard Worker         }
294*bebae9c0SAndroid Build Coastguard Worker     }
295*bebae9c0SAndroid Build Coastguard Worker 
296*bebae9c0SAndroid Build Coastguard Worker     // check that exactly one URI was specified
297*bebae9c0SAndroid Build Coastguard Worker     if (argc - i != 1) {
298*bebae9c0SAndroid Build Coastguard Worker         fprintf(stderr, "usage: %s [-a] [-c] [-d#] [-D#] [-f#] [-F#] [-l] [-n#] [-p#] [-s#] uri\n",
299*bebae9c0SAndroid Build Coastguard Worker                 prog);
300*bebae9c0SAndroid Build Coastguard Worker         fprintf(stderr, "    -a  Use Android buffer queue to supply data, default is URI\n");
301*bebae9c0SAndroid Build Coastguard Worker         fprintf(stderr, "    -c  Force callback to return an error randomly, for debugging only\n");
302*bebae9c0SAndroid Build Coastguard Worker         fprintf(stderr, "    -d# Packet index to insert a discontinuity, default is none\n");
303*bebae9c0SAndroid Build Coastguard Worker         fprintf(stderr, "    -D# Packet index to switch to after the discontinuity\n");
304*bebae9c0SAndroid Build Coastguard Worker         fprintf(stderr, "    -f# First packet index, defaults to 0\n");
305*bebae9c0SAndroid Build Coastguard Worker         fprintf(stderr, "    -F# Packet index to insert a format change, default is none\n");
306*bebae9c0SAndroid Build Coastguard Worker         fprintf(stderr, "    -l  Enable looping, for URI only\n");
307*bebae9c0SAndroid Build Coastguard Worker         fprintf(stderr, "    -n# Number of packets to enqueue\n");
308*bebae9c0SAndroid Build Coastguard Worker         fprintf(stderr, "    -p# Pause playback for 5 seconds after this many milliseconds\n");
309*bebae9c0SAndroid Build Coastguard Worker         fprintf(stderr, "    -s# Seek position in milliseconds, for URI only\n");
310*bebae9c0SAndroid Build Coastguard Worker         return EXIT_FAILURE;
311*bebae9c0SAndroid Build Coastguard Worker     }
312*bebae9c0SAndroid Build Coastguard Worker     const char *uri = argv[i];
313*bebae9c0SAndroid Build Coastguard Worker 
314*bebae9c0SAndroid Build Coastguard Worker     // for AndroidBufferQueue, interpret URI as a filename and open
315*bebae9c0SAndroid Build Coastguard Worker     int fd = -1;
316*bebae9c0SAndroid Build Coastguard Worker     if (abq) {
317*bebae9c0SAndroid Build Coastguard Worker         fd = open(uri, O_RDONLY);
318*bebae9c0SAndroid Build Coastguard Worker         if (fd < 0) {
319*bebae9c0SAndroid Build Coastguard Worker             perror(uri);
320*bebae9c0SAndroid Build Coastguard Worker             goto close;
321*bebae9c0SAndroid Build Coastguard Worker         }
322*bebae9c0SAndroid Build Coastguard Worker         int ok;
323*bebae9c0SAndroid Build Coastguard Worker         struct stat statbuf;
324*bebae9c0SAndroid Build Coastguard Worker         ok = fstat(fd, &statbuf);
325*bebae9c0SAndroid Build Coastguard Worker         if (ok < 0) {
326*bebae9c0SAndroid Build Coastguard Worker             perror(uri);
327*bebae9c0SAndroid Build Coastguard Worker             goto close;
328*bebae9c0SAndroid Build Coastguard Worker         }
329*bebae9c0SAndroid Build Coastguard Worker         if (!S_ISREG(statbuf.st_mode)) {
330*bebae9c0SAndroid Build Coastguard Worker             fprintf(stderr, "%s: not an ordinary file\n", uri);
331*bebae9c0SAndroid Build Coastguard Worker             goto close;
332*bebae9c0SAndroid Build Coastguard Worker         }
333*bebae9c0SAndroid Build Coastguard Worker         void *ptr;
334*bebae9c0SAndroid Build Coastguard Worker         ptr = mmap(NULL, statbuf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, (off_t) 0);
335*bebae9c0SAndroid Build Coastguard Worker         if (ptr == MAP_FAILED) {
336*bebae9c0SAndroid Build Coastguard Worker             perror(uri);
337*bebae9c0SAndroid Build Coastguard Worker             goto close;
338*bebae9c0SAndroid Build Coastguard Worker         }
339*bebae9c0SAndroid Build Coastguard Worker         size_t filelen = statbuf.st_size;
340*bebae9c0SAndroid Build Coastguard Worker         if ((filelen % MPEG2TS_PACKET_SIZE) != 0) {
341*bebae9c0SAndroid Build Coastguard Worker             fprintf(stderr, "%s: warning file length %zu is not a multiple of %d\n", uri, filelen,
342*bebae9c0SAndroid Build Coastguard Worker                     MPEG2TS_PACKET_SIZE);
343*bebae9c0SAndroid Build Coastguard Worker         }
344*bebae9c0SAndroid Build Coastguard Worker         packets = (MPEG2TS_Packet *) ptr;
345*bebae9c0SAndroid Build Coastguard Worker         totalPackets = filelen / MPEG2TS_PACKET_SIZE;
346*bebae9c0SAndroid Build Coastguard Worker         printf("%s has %zu total packets\n", uri, totalPackets);
347*bebae9c0SAndroid Build Coastguard Worker         if (firstPacket >= totalPackets) {
348*bebae9c0SAndroid Build Coastguard Worker             fprintf(stderr, "-f%zu ignored\n", firstPacket);
349*bebae9c0SAndroid Build Coastguard Worker             firstPacket = 0;
350*bebae9c0SAndroid Build Coastguard Worker         }
351*bebae9c0SAndroid Build Coastguard Worker         if (numPackets == 0) {
352*bebae9c0SAndroid Build Coastguard Worker             numPackets = totalPackets - firstPacket;
353*bebae9c0SAndroid Build Coastguard Worker         } else if (firstPacket + numPackets > totalPackets) {
354*bebae9c0SAndroid Build Coastguard Worker             fprintf(stderr, "-n%zu ignored\n", numPackets);
355*bebae9c0SAndroid Build Coastguard Worker             numPackets = totalPackets - firstPacket;
356*bebae9c0SAndroid Build Coastguard Worker         }
357*bebae9c0SAndroid Build Coastguard Worker         lastPacket = firstPacket + numPackets;
358*bebae9c0SAndroid Build Coastguard Worker         if (discPacket != 0 && (discPacket < firstPacket || discPacket >= lastPacket)) {
359*bebae9c0SAndroid Build Coastguard Worker             fprintf(stderr, "-d%zu ignored\n", discPacket);
360*bebae9c0SAndroid Build Coastguard Worker             discPacket = 0;
361*bebae9c0SAndroid Build Coastguard Worker         }
362*bebae9c0SAndroid Build Coastguard Worker         if (afterDiscPacket < firstPacket || afterDiscPacket >= lastPacket) {
363*bebae9c0SAndroid Build Coastguard Worker             fprintf(stderr, "-D%zu ignored\n", afterDiscPacket);
364*bebae9c0SAndroid Build Coastguard Worker             afterDiscPacket = 0;
365*bebae9c0SAndroid Build Coastguard Worker         }
366*bebae9c0SAndroid Build Coastguard Worker         if (formatPacket != 0 && (formatPacket < firstPacket || formatPacket >= lastPacket)) {
367*bebae9c0SAndroid Build Coastguard Worker             fprintf(stderr, "-F%zu ignored\n", formatPacket);
368*bebae9c0SAndroid Build Coastguard Worker             formatPacket = 0;
369*bebae9c0SAndroid Build Coastguard Worker         }
370*bebae9c0SAndroid Build Coastguard Worker     }
371*bebae9c0SAndroid Build Coastguard Worker 
372*bebae9c0SAndroid Build Coastguard Worker     ANativeWindow *nativeWindow;
373*bebae9c0SAndroid Build Coastguard Worker 
374*bebae9c0SAndroid Build Coastguard Worker     XAresult result;
375*bebae9c0SAndroid Build Coastguard Worker     XAObjectItf engineObject;
376*bebae9c0SAndroid Build Coastguard Worker 
377*bebae9c0SAndroid Build Coastguard Worker     // create engine
378*bebae9c0SAndroid Build Coastguard Worker     result = xaCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
379*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_SUCCESS == result);
380*bebae9c0SAndroid Build Coastguard Worker     result = (*engineObject)->Realize(engineObject, XA_BOOLEAN_FALSE);
381*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_SUCCESS == result);
382*bebae9c0SAndroid Build Coastguard Worker     XAEngineItf engineEngine;
383*bebae9c0SAndroid Build Coastguard Worker     result = (*engineObject)->GetInterface(engineObject, XA_IID_ENGINE, &engineEngine);
384*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_SUCCESS == result);
385*bebae9c0SAndroid Build Coastguard Worker 
386*bebae9c0SAndroid Build Coastguard Worker     // create output mix
387*bebae9c0SAndroid Build Coastguard Worker     XAObjectItf outputMixObject;
388*bebae9c0SAndroid Build Coastguard Worker     result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL);
389*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_SUCCESS == result);
390*bebae9c0SAndroid Build Coastguard Worker     result = (*outputMixObject)->Realize(outputMixObject, XA_BOOLEAN_FALSE);
391*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_SUCCESS == result);
392*bebae9c0SAndroid Build Coastguard Worker 
393*bebae9c0SAndroid Build Coastguard Worker     // configure media source
394*bebae9c0SAndroid Build Coastguard Worker     XADataLocator_URI locUri;
395*bebae9c0SAndroid Build Coastguard Worker     locUri.locatorType = XA_DATALOCATOR_URI;
396*bebae9c0SAndroid Build Coastguard Worker     locUri.URI = (XAchar *) uri;
397*bebae9c0SAndroid Build Coastguard Worker     XADataFormat_MIME fmtMime;
398*bebae9c0SAndroid Build Coastguard Worker     fmtMime.formatType = XA_DATAFORMAT_MIME;
399*bebae9c0SAndroid Build Coastguard Worker     if (abq) {
400*bebae9c0SAndroid Build Coastguard Worker         fmtMime.mimeType = (XAchar *) XA_ANDROID_MIME_MP2TS;
401*bebae9c0SAndroid Build Coastguard Worker         fmtMime.containerType = XA_CONTAINERTYPE_MPEG_TS;
402*bebae9c0SAndroid Build Coastguard Worker     } else {
403*bebae9c0SAndroid Build Coastguard Worker         fmtMime.mimeType = NULL;
404*bebae9c0SAndroid Build Coastguard Worker         fmtMime.containerType = XA_CONTAINERTYPE_UNSPECIFIED;
405*bebae9c0SAndroid Build Coastguard Worker     }
406*bebae9c0SAndroid Build Coastguard Worker     XADataLocator_AndroidBufferQueue locABQ;
407*bebae9c0SAndroid Build Coastguard Worker     locABQ.locatorType = XA_DATALOCATOR_ANDROIDBUFFERQUEUE;
408*bebae9c0SAndroid Build Coastguard Worker     locABQ.numBuffers = NB_BUFFERS;
409*bebae9c0SAndroid Build Coastguard Worker     XADataSource dataSrc;
410*bebae9c0SAndroid Build Coastguard Worker     if (abq) {
411*bebae9c0SAndroid Build Coastguard Worker         dataSrc.pLocator = &locABQ;
412*bebae9c0SAndroid Build Coastguard Worker     } else {
413*bebae9c0SAndroid Build Coastguard Worker         dataSrc.pLocator = &locUri;
414*bebae9c0SAndroid Build Coastguard Worker     }
415*bebae9c0SAndroid Build Coastguard Worker     dataSrc.pFormat = &fmtMime;
416*bebae9c0SAndroid Build Coastguard Worker 
417*bebae9c0SAndroid Build Coastguard Worker     // configure audio sink
418*bebae9c0SAndroid Build Coastguard Worker     XADataLocator_OutputMix locOM;
419*bebae9c0SAndroid Build Coastguard Worker     locOM.locatorType = XA_DATALOCATOR_OUTPUTMIX;
420*bebae9c0SAndroid Build Coastguard Worker     locOM.outputMix = outputMixObject;
421*bebae9c0SAndroid Build Coastguard Worker     XADataSink audioSnk;
422*bebae9c0SAndroid Build Coastguard Worker     audioSnk.pLocator = &locOM;
423*bebae9c0SAndroid Build Coastguard Worker     audioSnk.pFormat = NULL;
424*bebae9c0SAndroid Build Coastguard Worker 
425*bebae9c0SAndroid Build Coastguard Worker     // configure video sink
426*bebae9c0SAndroid Build Coastguard Worker     nativeWindow = getNativeWindow();
427*bebae9c0SAndroid Build Coastguard Worker     XADataLocator_NativeDisplay locND;
428*bebae9c0SAndroid Build Coastguard Worker     locND.locatorType = XA_DATALOCATOR_NATIVEDISPLAY;
429*bebae9c0SAndroid Build Coastguard Worker     locND.hWindow = nativeWindow;
430*bebae9c0SAndroid Build Coastguard Worker     locND.hDisplay = NULL;
431*bebae9c0SAndroid Build Coastguard Worker     XADataSink imageVideoSink;
432*bebae9c0SAndroid Build Coastguard Worker     imageVideoSink.pLocator = &locND;
433*bebae9c0SAndroid Build Coastguard Worker     imageVideoSink.pFormat = NULL;
434*bebae9c0SAndroid Build Coastguard Worker 
435*bebae9c0SAndroid Build Coastguard Worker     // create media player
436*bebae9c0SAndroid Build Coastguard Worker     XAObjectItf playerObject;
437*bebae9c0SAndroid Build Coastguard Worker     XAInterfaceID ids[4] = {XA_IID_STREAMINFORMATION, XA_IID_PREFETCHSTATUS, XA_IID_SEEK,
438*bebae9c0SAndroid Build Coastguard Worker             XA_IID_ANDROIDBUFFERQUEUESOURCE};
439*bebae9c0SAndroid Build Coastguard Worker     XAboolean req[4] = {XA_BOOLEAN_TRUE, XA_BOOLEAN_TRUE, XA_BOOLEAN_FALSE, XA_BOOLEAN_TRUE};
440*bebae9c0SAndroid Build Coastguard Worker     result = (*engineEngine)->CreateMediaPlayer(engineEngine, &playerObject, &dataSrc, NULL,
441*bebae9c0SAndroid Build Coastguard Worker             &audioSnk, nativeWindow != NULL ? &imageVideoSink : NULL, NULL, NULL, abq ? 4 : 3, ids,
442*bebae9c0SAndroid Build Coastguard Worker             req);
443*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_SUCCESS == result);
444*bebae9c0SAndroid Build Coastguard Worker 
445*bebae9c0SAndroid Build Coastguard Worker     // realize the player
446*bebae9c0SAndroid Build Coastguard Worker     result = (*playerObject)->Realize(playerObject, XA_BOOLEAN_FALSE);
447*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_SUCCESS == result);
448*bebae9c0SAndroid Build Coastguard Worker 
449*bebae9c0SAndroid Build Coastguard Worker     // get the play interface
450*bebae9c0SAndroid Build Coastguard Worker     XAPlayItf playerPlay;
451*bebae9c0SAndroid Build Coastguard Worker     result = (*playerObject)->GetInterface(playerObject, XA_IID_PLAY, &playerPlay);
452*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_SUCCESS == result);
453*bebae9c0SAndroid Build Coastguard Worker 
454*bebae9c0SAndroid Build Coastguard Worker     if (abq) {
455*bebae9c0SAndroid Build Coastguard Worker 
456*bebae9c0SAndroid Build Coastguard Worker         // get the Android buffer queue interface
457*bebae9c0SAndroid Build Coastguard Worker         XAAndroidBufferQueueItf playerAndroidBufferQueue;
458*bebae9c0SAndroid Build Coastguard Worker         result = (*playerObject)->GetInterface(playerObject, XA_IID_ANDROIDBUFFERQUEUESOURCE,
459*bebae9c0SAndroid Build Coastguard Worker                 &playerAndroidBufferQueue);
460*bebae9c0SAndroid Build Coastguard Worker         assert(XA_RESULT_SUCCESS == result);
461*bebae9c0SAndroid Build Coastguard Worker 
462*bebae9c0SAndroid Build Coastguard Worker         // register the buffer queue callback
463*bebae9c0SAndroid Build Coastguard Worker         result = (*playerAndroidBufferQueue)->RegisterCallback(playerAndroidBufferQueue,
464*bebae9c0SAndroid Build Coastguard Worker                 bufferQueueCallback, (void *) playerPlay);
465*bebae9c0SAndroid Build Coastguard Worker         assert(XA_RESULT_SUCCESS == result);
466*bebae9c0SAndroid Build Coastguard Worker         result = (*playerAndroidBufferQueue)->SetCallbackEventsMask(playerAndroidBufferQueue,
467*bebae9c0SAndroid Build Coastguard Worker                 XA_ANDROIDBUFFERQUEUEEVENT_PROCESSED);
468*bebae9c0SAndroid Build Coastguard Worker         assert(XA_RESULT_SUCCESS == result);
469*bebae9c0SAndroid Build Coastguard Worker 
470*bebae9c0SAndroid Build Coastguard Worker         // set the player's state to paused, to start prefetching
471*bebae9c0SAndroid Build Coastguard Worker         printf("start early prefetch\n");
472*bebae9c0SAndroid Build Coastguard Worker         result = (*playerPlay)->SetPlayState(playerPlay, XA_PLAYSTATE_PAUSED);
473*bebae9c0SAndroid Build Coastguard Worker         assert(XA_RESULT_SUCCESS == result);
474*bebae9c0SAndroid Build Coastguard Worker 
475*bebae9c0SAndroid Build Coastguard Worker         // enqueue the initial buffers until buffer queue is full
476*bebae9c0SAndroid Build Coastguard Worker         XAuint32 packetsThisBuffer;
477*bebae9c0SAndroid Build Coastguard Worker         for (curPacket = firstPacket; curPacket < lastPacket; curPacket += packetsThisBuffer) {
478*bebae9c0SAndroid Build Coastguard Worker             // handle the unlikely case of a very short .ts
479*bebae9c0SAndroid Build Coastguard Worker             packetsThisBuffer = lastPacket - curPacket;
480*bebae9c0SAndroid Build Coastguard Worker             if (packetsThisBuffer > PACKETS_PER_BUFFER) {
481*bebae9c0SAndroid Build Coastguard Worker                 packetsThisBuffer = PACKETS_PER_BUFFER;
482*bebae9c0SAndroid Build Coastguard Worker             }
483*bebae9c0SAndroid Build Coastguard Worker             result = (*playerAndroidBufferQueue)->Enqueue(playerAndroidBufferQueue, NULL,
484*bebae9c0SAndroid Build Coastguard Worker                     &packets[curPacket], MPEG2TS_PACKET_SIZE * packetsThisBuffer, NULL, 0);
485*bebae9c0SAndroid Build Coastguard Worker             if (XA_RESULT_BUFFER_INSUFFICIENT == result) {
486*bebae9c0SAndroid Build Coastguard Worker                 printf("Enqueued initial %zu packets in %zu buffers\n", curPacket - firstPacket,
487*bebae9c0SAndroid Build Coastguard Worker                         (curPacket - firstPacket + PACKETS_PER_BUFFER - 1) / PACKETS_PER_BUFFER);
488*bebae9c0SAndroid Build Coastguard Worker                 break;
489*bebae9c0SAndroid Build Coastguard Worker             }
490*bebae9c0SAndroid Build Coastguard Worker             assert(XA_RESULT_SUCCESS == result);
491*bebae9c0SAndroid Build Coastguard Worker         }
492*bebae9c0SAndroid Build Coastguard Worker 
493*bebae9c0SAndroid Build Coastguard Worker     }
494*bebae9c0SAndroid Build Coastguard Worker 
495*bebae9c0SAndroid Build Coastguard Worker     // get the stream information interface
496*bebae9c0SAndroid Build Coastguard Worker     XAStreamInformationItf playerStreamInformation;
497*bebae9c0SAndroid Build Coastguard Worker     result = (*playerObject)->GetInterface(playerObject, XA_IID_STREAMINFORMATION,
498*bebae9c0SAndroid Build Coastguard Worker             &playerStreamInformation);
499*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_SUCCESS == result);
500*bebae9c0SAndroid Build Coastguard Worker 
501*bebae9c0SAndroid Build Coastguard Worker     // register the stream event change callback
502*bebae9c0SAndroid Build Coastguard Worker     result = (*playerStreamInformation)->RegisterStreamChangeCallback(playerStreamInformation,
503*bebae9c0SAndroid Build Coastguard Worker             streamEventChangeCallback, NULL);
504*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_SUCCESS == result);
505*bebae9c0SAndroid Build Coastguard Worker 
506*bebae9c0SAndroid Build Coastguard Worker     // get the prefetch status interface
507*bebae9c0SAndroid Build Coastguard Worker     XAPrefetchStatusItf playerPrefetchStatus;
508*bebae9c0SAndroid Build Coastguard Worker     result = (*playerObject)->GetInterface(playerObject, XA_IID_PREFETCHSTATUS,
509*bebae9c0SAndroid Build Coastguard Worker             &playerPrefetchStatus);
510*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_SUCCESS == result);
511*bebae9c0SAndroid Build Coastguard Worker 
512*bebae9c0SAndroid Build Coastguard Worker     // register prefetch status callback
513*bebae9c0SAndroid Build Coastguard Worker     result = (*playerPrefetchStatus)->RegisterCallback(playerPrefetchStatus, prefetchStatusCallback,
514*bebae9c0SAndroid Build Coastguard Worker             NULL);
515*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_SUCCESS == result);
516*bebae9c0SAndroid Build Coastguard Worker     result = (*playerPrefetchStatus)->SetCallbackEventsMask(playerPrefetchStatus,
517*bebae9c0SAndroid Build Coastguard Worker             XA_PREFETCHEVENT_FILLLEVELCHANGE | XA_PREFETCHEVENT_STATUSCHANGE);
518*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_SUCCESS == result);
519*bebae9c0SAndroid Build Coastguard Worker 
520*bebae9c0SAndroid Build Coastguard Worker     // get the seek interface for seeking and/or looping
521*bebae9c0SAndroid Build Coastguard Worker     if (looping || seekPos != XA_TIME_UNKNOWN) {
522*bebae9c0SAndroid Build Coastguard Worker         XASeekItf playerSeek;
523*bebae9c0SAndroid Build Coastguard Worker         result = (*playerObject)->GetInterface(playerObject, XA_IID_SEEK, &playerSeek);
524*bebae9c0SAndroid Build Coastguard Worker         assert(XA_RESULT_SUCCESS == result);
525*bebae9c0SAndroid Build Coastguard Worker         if (seekPos != XA_TIME_UNKNOWN) {
526*bebae9c0SAndroid Build Coastguard Worker             result = (*playerSeek)->SetPosition(playerSeek, seekPos, XA_SEEKMODE_ACCURATE);
527*bebae9c0SAndroid Build Coastguard Worker             if (XA_RESULT_FEATURE_UNSUPPORTED == result) {
528*bebae9c0SAndroid Build Coastguard Worker                 fprintf(stderr, "-s%u (seek to initial position) is unsupported\n", seekPos);
529*bebae9c0SAndroid Build Coastguard Worker             } else {
530*bebae9c0SAndroid Build Coastguard Worker                 assert(XA_RESULT_SUCCESS == result);
531*bebae9c0SAndroid Build Coastguard Worker             }
532*bebae9c0SAndroid Build Coastguard Worker         }
533*bebae9c0SAndroid Build Coastguard Worker         if (looping) {
534*bebae9c0SAndroid Build Coastguard Worker             result = (*playerSeek)->SetLoop(playerSeek, XA_BOOLEAN_TRUE, (XAmillisecond) 0,
535*bebae9c0SAndroid Build Coastguard Worker                     XA_TIME_UNKNOWN);
536*bebae9c0SAndroid Build Coastguard Worker             if (XA_RESULT_FEATURE_UNSUPPORTED) {
537*bebae9c0SAndroid Build Coastguard Worker                 fprintf(stderr, "-l (looping) is unsupported\n");
538*bebae9c0SAndroid Build Coastguard Worker             } else {
539*bebae9c0SAndroid Build Coastguard Worker                 assert(XA_RESULT_SUCCESS == result);
540*bebae9c0SAndroid Build Coastguard Worker             }
541*bebae9c0SAndroid Build Coastguard Worker         }
542*bebae9c0SAndroid Build Coastguard Worker     }
543*bebae9c0SAndroid Build Coastguard Worker 
544*bebae9c0SAndroid Build Coastguard Worker     // register play event callback
545*bebae9c0SAndroid Build Coastguard Worker     result = (*playerPlay)->RegisterCallback(playerPlay, playEventCallback, NULL);
546*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_SUCCESS == result);
547*bebae9c0SAndroid Build Coastguard Worker     result = (*playerPlay)->SetCallbackEventsMask(playerPlay,
548*bebae9c0SAndroid Build Coastguard Worker             XA_PLAYEVENT_HEADATEND | XA_PLAYEVENT_HEADATMARKER | XA_PLAYEVENT_HEADATNEWPOS);
549*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_SUCCESS == result);
550*bebae9c0SAndroid Build Coastguard Worker 
551*bebae9c0SAndroid Build Coastguard Worker     // set a marker
552*bebae9c0SAndroid Build Coastguard Worker     result = (*playerPlay)->SetMarkerPosition(playerPlay, 5000);
553*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_SUCCESS == result);
554*bebae9c0SAndroid Build Coastguard Worker 
555*bebae9c0SAndroid Build Coastguard Worker     // set position update period
556*bebae9c0SAndroid Build Coastguard Worker     result = (*playerPlay)->SetPositionUpdatePeriod(playerPlay, 2000);
557*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_SUCCESS == result);
558*bebae9c0SAndroid Build Coastguard Worker 
559*bebae9c0SAndroid Build Coastguard Worker     // get the position before prefetch
560*bebae9c0SAndroid Build Coastguard Worker     XAmillisecond position;
561*bebae9c0SAndroid Build Coastguard Worker     result = (*playerPlay)->GetPosition(playerPlay, &position);
562*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_SUCCESS == result);
563*bebae9c0SAndroid Build Coastguard Worker     printf("Position before prefetch: %u ms\n", position);
564*bebae9c0SAndroid Build Coastguard Worker 
565*bebae9c0SAndroid Build Coastguard Worker     // get the duration before prefetch
566*bebae9c0SAndroid Build Coastguard Worker     XAmillisecond duration;
567*bebae9c0SAndroid Build Coastguard Worker     result = (*playerPlay)->GetDuration(playerPlay, &duration);
568*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_SUCCESS == result);
569*bebae9c0SAndroid Build Coastguard Worker     if (XA_TIME_UNKNOWN == duration)
570*bebae9c0SAndroid Build Coastguard Worker         printf("Duration before prefetch: unknown as expected\n");
571*bebae9c0SAndroid Build Coastguard Worker     else
572*bebae9c0SAndroid Build Coastguard Worker         printf("Duration before prefetch: %.1f (surprise!)\n", duration / 1000.0f);
573*bebae9c0SAndroid Build Coastguard Worker 
574*bebae9c0SAndroid Build Coastguard Worker     // set the player's state to paused, to start prefetching
575*bebae9c0SAndroid Build Coastguard Worker     printf("start prefetch\n");
576*bebae9c0SAndroid Build Coastguard Worker     result = (*playerPlay)->SetPlayState(playerPlay, XA_PLAYSTATE_PAUSED);
577*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_SUCCESS == result);
578*bebae9c0SAndroid Build Coastguard Worker 
579*bebae9c0SAndroid Build Coastguard Worker     // wait for prefetch status callback to indicate either sufficient data or error
580*bebae9c0SAndroid Build Coastguard Worker     pthread_mutex_lock(&mutex);
581*bebae9c0SAndroid Build Coastguard Worker     while (prefetch_status == PREFETCHSTATUS_UNKNOWN) {
582*bebae9c0SAndroid Build Coastguard Worker         pthread_cond_wait(&cond, &mutex);
583*bebae9c0SAndroid Build Coastguard Worker     }
584*bebae9c0SAndroid Build Coastguard Worker     pthread_mutex_unlock(&mutex);
585*bebae9c0SAndroid Build Coastguard Worker     if (prefetch_status == PREFETCHSTATUS_ERROR) {
586*bebae9c0SAndroid Build Coastguard Worker         fprintf(stderr, "Error during prefetch, exiting\n");
587*bebae9c0SAndroid Build Coastguard Worker         goto destroyRes;
588*bebae9c0SAndroid Build Coastguard Worker     }
589*bebae9c0SAndroid Build Coastguard Worker 
590*bebae9c0SAndroid Build Coastguard Worker     // get the position after prefetch
591*bebae9c0SAndroid Build Coastguard Worker     result = (*playerPlay)->GetPosition(playerPlay, &position);
592*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_SUCCESS == result);
593*bebae9c0SAndroid Build Coastguard Worker     printf("Position after prefetch: %u ms\n", position);
594*bebae9c0SAndroid Build Coastguard Worker 
595*bebae9c0SAndroid Build Coastguard Worker     // get duration again, now it should be known for the file source or unknown for TS
596*bebae9c0SAndroid Build Coastguard Worker     result = (*playerPlay)->GetDuration(playerPlay, &duration);
597*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_SUCCESS == result);
598*bebae9c0SAndroid Build Coastguard Worker     if (duration == XA_TIME_UNKNOWN) {
599*bebae9c0SAndroid Build Coastguard Worker         printf("Duration after prefetch: unknown (expected for TS, unexpected for file)\n");
600*bebae9c0SAndroid Build Coastguard Worker     } else {
601*bebae9c0SAndroid Build Coastguard Worker         printf("Duration after prefetch: %u ms (expected for file, unexpected for TS)\n", duration);
602*bebae9c0SAndroid Build Coastguard Worker     }
603*bebae9c0SAndroid Build Coastguard Worker 
604*bebae9c0SAndroid Build Coastguard Worker     // query for media container information
605*bebae9c0SAndroid Build Coastguard Worker     result = (*playerStreamInformation)->QueryMediaContainerInformation(playerStreamInformation,
606*bebae9c0SAndroid Build Coastguard Worker             NULL);
607*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_PARAMETER_INVALID == result);
608*bebae9c0SAndroid Build Coastguard Worker     XAMediaContainerInformation mediaContainerInformation;
609*bebae9c0SAndroid Build Coastguard Worker     // this verifies it is filling in all the fields
610*bebae9c0SAndroid Build Coastguard Worker     memset(&mediaContainerInformation, 0x55, sizeof(XAMediaContainerInformation));
611*bebae9c0SAndroid Build Coastguard Worker     result = (*playerStreamInformation)->QueryMediaContainerInformation(playerStreamInformation,
612*bebae9c0SAndroid Build Coastguard Worker             &mediaContainerInformation);
613*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_SUCCESS == result);
614*bebae9c0SAndroid Build Coastguard Worker     printf("Media container information:\n");
615*bebae9c0SAndroid Build Coastguard Worker     printf("  containerType = %u\n", mediaContainerInformation.containerType);
616*bebae9c0SAndroid Build Coastguard Worker     printf("  mediaDuration = %u\n", mediaContainerInformation.mediaDuration);
617*bebae9c0SAndroid Build Coastguard Worker     printf("  numStreams = %u\n", mediaContainerInformation.numStreams);
618*bebae9c0SAndroid Build Coastguard Worker 
619*bebae9c0SAndroid Build Coastguard Worker     // Now query for each the streams.  Note that stream indices go up to and including
620*bebae9c0SAndroid Build Coastguard Worker     // mediaContainerInformation.numStreams, because stream 0 is the container itself,
621*bebae9c0SAndroid Build Coastguard Worker     // while stream 1 to mediaContainerInformation.numStreams are the contained streams.
622*bebae9c0SAndroid Build Coastguard Worker     XAuint32 streamIndex;
623*bebae9c0SAndroid Build Coastguard Worker     for (streamIndex = 0; streamIndex <= mediaContainerInformation.numStreams; ++streamIndex) {
624*bebae9c0SAndroid Build Coastguard Worker         XAuint32 domain;
625*bebae9c0SAndroid Build Coastguard Worker         XAuint16 nameSize;
626*bebae9c0SAndroid Build Coastguard Worker         XAchar name[64];
627*bebae9c0SAndroid Build Coastguard Worker         printf("stream[%u]:\n", streamIndex);
628*bebae9c0SAndroid Build Coastguard Worker         if (streamIndex == 0) {
629*bebae9c0SAndroid Build Coastguard Worker             result = (*playerStreamInformation)->QueryStreamType(playerStreamInformation,
630*bebae9c0SAndroid Build Coastguard Worker                     streamIndex, &domain);
631*bebae9c0SAndroid Build Coastguard Worker             assert(XA_RESULT_PARAMETER_INVALID == result);
632*bebae9c0SAndroid Build Coastguard Worker             result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
633*bebae9c0SAndroid Build Coastguard Worker                     streamIndex, &mediaContainerInformation);
634*bebae9c0SAndroid Build Coastguard Worker             //assert(XA_RESULT_PARAMETER_INVALID == result);
635*bebae9c0SAndroid Build Coastguard Worker             nameSize = sizeof(name);
636*bebae9c0SAndroid Build Coastguard Worker             result = (*playerStreamInformation)->QueryStreamName(playerStreamInformation,
637*bebae9c0SAndroid Build Coastguard Worker streamIndex, &nameSize, name);
638*bebae9c0SAndroid Build Coastguard Worker             //assert(XA_RESULT_PARAMETER_INVALID == result);
639*bebae9c0SAndroid Build Coastguard Worker             continue;
640*bebae9c0SAndroid Build Coastguard Worker         }
641*bebae9c0SAndroid Build Coastguard Worker         result = (*playerStreamInformation)->QueryStreamType(playerStreamInformation, streamIndex,
642*bebae9c0SAndroid Build Coastguard Worker                 NULL);
643*bebae9c0SAndroid Build Coastguard Worker         assert(XA_RESULT_PARAMETER_INVALID == result);
644*bebae9c0SAndroid Build Coastguard Worker         domain = 12345;
645*bebae9c0SAndroid Build Coastguard Worker         result = (*playerStreamInformation)->QueryStreamType(playerStreamInformation, streamIndex,
646*bebae9c0SAndroid Build Coastguard Worker                 &domain);
647*bebae9c0SAndroid Build Coastguard Worker         assert(XA_RESULT_SUCCESS == result);
648*bebae9c0SAndroid Build Coastguard Worker         printf(" QueryStreamType: domain = 0x%X (%s)\n", domain, domainToString(domain));
649*bebae9c0SAndroid Build Coastguard Worker         nameSize = sizeof(name);
650*bebae9c0SAndroid Build Coastguard Worker         result = (*playerStreamInformation)->QueryStreamName(playerStreamInformation, streamIndex,
651*bebae9c0SAndroid Build Coastguard Worker                 &nameSize, name);
652*bebae9c0SAndroid Build Coastguard Worker #if 0
653*bebae9c0SAndroid Build Coastguard Worker         assert(XA_RESULT_SUCCESS == result);
654*bebae9c0SAndroid Build Coastguard Worker         assert(sizeof(name) >= nameSize);
655*bebae9c0SAndroid Build Coastguard Worker         if (sizeof(name) != nameSize) {
656*bebae9c0SAndroid Build Coastguard Worker             assert('\0' == name[nameSize]);
657*bebae9c0SAndroid Build Coastguard Worker         }
658*bebae9c0SAndroid Build Coastguard Worker         printf(" QueryStreamName: nameSize=%u, name=\"%.*s\"\n", nameSize, nameSize, name);
659*bebae9c0SAndroid Build Coastguard Worker         result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
660*bebae9c0SAndroid Build Coastguard Worker                 streamIndex, NULL);
661*bebae9c0SAndroid Build Coastguard Worker         assert(XA_RESULT_PARAMETER_INVALID == result);
662*bebae9c0SAndroid Build Coastguard Worker #endif
663*bebae9c0SAndroid Build Coastguard Worker 
664*bebae9c0SAndroid Build Coastguard Worker         printf(" QueryStreamInformation:\n");
665*bebae9c0SAndroid Build Coastguard Worker         switch (domain) {
666*bebae9c0SAndroid Build Coastguard Worker #if 0
667*bebae9c0SAndroid Build Coastguard Worker         case 0: // FIXME container
668*bebae9c0SAndroid Build Coastguard Worker             result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
669*bebae9c0SAndroid Build Coastguard Worker streamIndex, &mediaContainerInformation);
670*bebae9c0SAndroid Build Coastguard Worker             assert(XA_RESULT_SUCCESS == result);
671*bebae9c0SAndroid Build Coastguard Worker             printf("  containerType = %u (1=unspecified)\n",
672*bebae9c0SAndroid Build Coastguard Worker                     mediaContainerInformation.containerType);
673*bebae9c0SAndroid Build Coastguard Worker             printf("  mediaDuration = %u\n", mediaContainerInformation.mediaDuration);
674*bebae9c0SAndroid Build Coastguard Worker             printf("  numStreams = %u\n", mediaContainerInformation.numStreams);
675*bebae9c0SAndroid Build Coastguard Worker             break;
676*bebae9c0SAndroid Build Coastguard Worker #endif
677*bebae9c0SAndroid Build Coastguard Worker         case XA_DOMAINTYPE_AUDIO: {
678*bebae9c0SAndroid Build Coastguard Worker             XAAudioStreamInformation audioStreamInformation;
679*bebae9c0SAndroid Build Coastguard Worker             memset(&audioStreamInformation, 0x55, sizeof(XAAudioStreamInformation));
680*bebae9c0SAndroid Build Coastguard Worker             result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
681*bebae9c0SAndroid Build Coastguard Worker                     streamIndex, &audioStreamInformation);
682*bebae9c0SAndroid Build Coastguard Worker             assert(XA_RESULT_PARAMETER_INVALID == result);
683*bebae9c0SAndroid Build Coastguard Worker             printf("  codecId = %u\n", audioStreamInformation.codecId);
684*bebae9c0SAndroid Build Coastguard Worker             printf("  channels = %u\n", audioStreamInformation.channels);
685*bebae9c0SAndroid Build Coastguard Worker             printf("  sampleRate = %u\n", audioStreamInformation.sampleRate);
686*bebae9c0SAndroid Build Coastguard Worker             printf("  bitRate = %u\n", audioStreamInformation.bitRate);
687*bebae9c0SAndroid Build Coastguard Worker             printf("  langCountry = \"%s\"\n", audioStreamInformation.langCountry);
688*bebae9c0SAndroid Build Coastguard Worker             printf("  duration = %u\n", audioStreamInformation.duration);
689*bebae9c0SAndroid Build Coastguard Worker             } break;
690*bebae9c0SAndroid Build Coastguard Worker         case XA_DOMAINTYPE_VIDEO: {
691*bebae9c0SAndroid Build Coastguard Worker             XAVideoStreamInformation videoStreamInformation;
692*bebae9c0SAndroid Build Coastguard Worker             result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
693*bebae9c0SAndroid Build Coastguard Worker                     streamIndex, &videoStreamInformation);
694*bebae9c0SAndroid Build Coastguard Worker             assert(XA_RESULT_SUCCESS == result);
695*bebae9c0SAndroid Build Coastguard Worker             printf("  codecId = %u\n", videoStreamInformation.codecId);
696*bebae9c0SAndroid Build Coastguard Worker             printf("  width = %u\n", videoStreamInformation.width);
697*bebae9c0SAndroid Build Coastguard Worker             printf("  height = %u\n", videoStreamInformation.height);
698*bebae9c0SAndroid Build Coastguard Worker             printf("  frameRate = %u\n", videoStreamInformation.frameRate);
699*bebae9c0SAndroid Build Coastguard Worker             printf("  bitRate = %u\n", videoStreamInformation.bitRate);
700*bebae9c0SAndroid Build Coastguard Worker             printf("  duration = %u\n", videoStreamInformation.duration);
701*bebae9c0SAndroid Build Coastguard Worker             } break;
702*bebae9c0SAndroid Build Coastguard Worker         case XA_DOMAINTYPE_IMAGE: {
703*bebae9c0SAndroid Build Coastguard Worker             XAImageStreamInformation imageStreamInformation;
704*bebae9c0SAndroid Build Coastguard Worker             result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
705*bebae9c0SAndroid Build Coastguard Worker                     streamIndex, &imageStreamInformation);
706*bebae9c0SAndroid Build Coastguard Worker             assert(XA_RESULT_SUCCESS == result);
707*bebae9c0SAndroid Build Coastguard Worker             printf("  codecId = %u\n", imageStreamInformation.codecId);
708*bebae9c0SAndroid Build Coastguard Worker             printf("  width = %u\n", imageStreamInformation.width);
709*bebae9c0SAndroid Build Coastguard Worker             printf("  height = %u\n", imageStreamInformation.height);
710*bebae9c0SAndroid Build Coastguard Worker             printf("  presentationDuration = %u\n", imageStreamInformation.presentationDuration);
711*bebae9c0SAndroid Build Coastguard Worker             } break;
712*bebae9c0SAndroid Build Coastguard Worker         case XA_DOMAINTYPE_TIMEDTEXT: {
713*bebae9c0SAndroid Build Coastguard Worker             XATimedTextStreamInformation timedTextStreamInformation;
714*bebae9c0SAndroid Build Coastguard Worker             result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
715*bebae9c0SAndroid Build Coastguard Worker                     streamIndex, &timedTextStreamInformation);
716*bebae9c0SAndroid Build Coastguard Worker             assert(XA_RESULT_SUCCESS == result);
717*bebae9c0SAndroid Build Coastguard Worker             printf("  layer = %u\n", timedTextStreamInformation.layer);
718*bebae9c0SAndroid Build Coastguard Worker             printf("  width = %u\n", timedTextStreamInformation.width);
719*bebae9c0SAndroid Build Coastguard Worker             printf("  height = %u\n", timedTextStreamInformation.height);
720*bebae9c0SAndroid Build Coastguard Worker             printf("  tx = %u\n", timedTextStreamInformation.tx);
721*bebae9c0SAndroid Build Coastguard Worker             printf("  ty = %u\n", timedTextStreamInformation.ty);
722*bebae9c0SAndroid Build Coastguard Worker             printf("  bitrate = %u\n", timedTextStreamInformation.bitrate);
723*bebae9c0SAndroid Build Coastguard Worker             printf("  langCountry = \"%s\"\n", timedTextStreamInformation.langCountry);
724*bebae9c0SAndroid Build Coastguard Worker             printf("  duration = %u\n", timedTextStreamInformation.duration);
725*bebae9c0SAndroid Build Coastguard Worker             } break;
726*bebae9c0SAndroid Build Coastguard Worker         case XA_DOMAINTYPE_MIDI: {
727*bebae9c0SAndroid Build Coastguard Worker             XAMIDIStreamInformation midiStreamInformation;
728*bebae9c0SAndroid Build Coastguard Worker             result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
729*bebae9c0SAndroid Build Coastguard Worker                     streamIndex, &midiStreamInformation);
730*bebae9c0SAndroid Build Coastguard Worker             assert(XA_RESULT_SUCCESS == result);
731*bebae9c0SAndroid Build Coastguard Worker             printf("  channels = %u\n", midiStreamInformation.channels);
732*bebae9c0SAndroid Build Coastguard Worker             printf("  tracks = %u\n", midiStreamInformation.tracks);
733*bebae9c0SAndroid Build Coastguard Worker             printf("  bankType = %u\n", midiStreamInformation.bankType);
734*bebae9c0SAndroid Build Coastguard Worker             printf("  langCountry = \"%s\"\n", midiStreamInformation.langCountry);
735*bebae9c0SAndroid Build Coastguard Worker             printf("  duration = %u\n", midiStreamInformation.duration);
736*bebae9c0SAndroid Build Coastguard Worker             } break;
737*bebae9c0SAndroid Build Coastguard Worker         case XA_DOMAINTYPE_VENDOR: {
738*bebae9c0SAndroid Build Coastguard Worker             XAVendorStreamInformation vendorStreamInformation;
739*bebae9c0SAndroid Build Coastguard Worker             result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
740*bebae9c0SAndroid Build Coastguard Worker                     streamIndex, &vendorStreamInformation);
741*bebae9c0SAndroid Build Coastguard Worker             assert(XA_RESULT_SUCCESS == result);
742*bebae9c0SAndroid Build Coastguard Worker             printf("  VendorStreamInfo = %p\n", vendorStreamInformation.VendorStreamInfo);
743*bebae9c0SAndroid Build Coastguard Worker             } break;
744*bebae9c0SAndroid Build Coastguard Worker         case XA_DOMAINTYPE_UNKNOWN: {
745*bebae9c0SAndroid Build Coastguard Worker             // "It is not possible to query Information for streams identified as
746*bebae9c0SAndroid Build Coastguard Worker             // XA_DOMAINTYPE_UNKNOWN, any attempt to do so shall return a result of
747*bebae9c0SAndroid Build Coastguard Worker             // XA_RESULT_CONTENT_UNSUPPORTED."
748*bebae9c0SAndroid Build Coastguard Worker             char big[256];
749*bebae9c0SAndroid Build Coastguard Worker             result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
750*bebae9c0SAndroid Build Coastguard Worker                     streamIndex, &big);
751*bebae9c0SAndroid Build Coastguard Worker             assert(XA_RESULT_CONTENT_UNSUPPORTED == result);
752*bebae9c0SAndroid Build Coastguard Worker             } break;
753*bebae9c0SAndroid Build Coastguard Worker         default:
754*bebae9c0SAndroid Build Coastguard Worker             break;
755*bebae9c0SAndroid Build Coastguard Worker         }
756*bebae9c0SAndroid Build Coastguard Worker 
757*bebae9c0SAndroid Build Coastguard Worker     }
758*bebae9c0SAndroid Build Coastguard Worker     // Try one more stream index beyond the valid range
759*bebae9c0SAndroid Build Coastguard Worker     XAuint32 domain;
760*bebae9c0SAndroid Build Coastguard Worker     result = (*playerStreamInformation)->QueryStreamType(playerStreamInformation, streamIndex,
761*bebae9c0SAndroid Build Coastguard Worker             &domain);
762*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_PARAMETER_INVALID == result);
763*bebae9c0SAndroid Build Coastguard Worker     XATimedTextStreamInformation big;
764*bebae9c0SAndroid Build Coastguard Worker     result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
765*bebae9c0SAndroid Build Coastguard Worker             streamIndex, &big);
766*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_PARAMETER_INVALID == result);
767*bebae9c0SAndroid Build Coastguard Worker 
768*bebae9c0SAndroid Build Coastguard Worker     printf("QueryActiveStreams:\n");
769*bebae9c0SAndroid Build Coastguard Worker     result = (*playerStreamInformation)->QueryActiveStreams(playerStreamInformation, NULL, NULL);
770*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_PARAMETER_INVALID == result);
771*bebae9c0SAndroid Build Coastguard Worker     XAuint32 numStreams1 = 0x12345678;
772*bebae9c0SAndroid Build Coastguard Worker     result = (*playerStreamInformation)->QueryActiveStreams(playerStreamInformation, &numStreams1,
773*bebae9c0SAndroid Build Coastguard Worker             NULL);
774*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_SUCCESS == result);
775*bebae9c0SAndroid Build Coastguard Worker     printf("  numStreams = %u\n", numStreams1);
776*bebae9c0SAndroid Build Coastguard Worker     XAboolean *activeStreams = calloc(numStreams1 + 1, sizeof(XAboolean));
777*bebae9c0SAndroid Build Coastguard Worker     assert(NULL != activeStreams);
778*bebae9c0SAndroid Build Coastguard Worker     printf("  active stream(s) =");
779*bebae9c0SAndroid Build Coastguard Worker     XAuint32 numStreams2 = numStreams1;
780*bebae9c0SAndroid Build Coastguard Worker     result = (*playerStreamInformation)->QueryActiveStreams(playerStreamInformation, &numStreams2,
781*bebae9c0SAndroid Build Coastguard Worker             activeStreams);
782*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_SUCCESS == result);
783*bebae9c0SAndroid Build Coastguard Worker     assert(numStreams2 == numStreams1);
784*bebae9c0SAndroid Build Coastguard Worker     for (streamIndex = 0; streamIndex <= numStreams1; ++streamIndex) {
785*bebae9c0SAndroid Build Coastguard Worker         if (activeStreams[streamIndex])
786*bebae9c0SAndroid Build Coastguard Worker             printf(" %u", streamIndex);
787*bebae9c0SAndroid Build Coastguard Worker     }
788*bebae9c0SAndroid Build Coastguard Worker     printf("\n");
789*bebae9c0SAndroid Build Coastguard Worker 
790*bebae9c0SAndroid Build Coastguard Worker     // SetActiveStream is untested
791*bebae9c0SAndroid Build Coastguard Worker 
792*bebae9c0SAndroid Build Coastguard Worker     // start playing
793*bebae9c0SAndroid Build Coastguard Worker     printf("starting to play\n");
794*bebae9c0SAndroid Build Coastguard Worker     result = (*playerPlay)->SetPlayState(playerPlay, XA_PLAYSTATE_PLAYING);
795*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_SUCCESS == result);
796*bebae9c0SAndroid Build Coastguard Worker 
797*bebae9c0SAndroid Build Coastguard Worker     // continue playing until end of media
798*bebae9c0SAndroid Build Coastguard Worker     for (;;) {
799*bebae9c0SAndroid Build Coastguard Worker         XAuint32 status;
800*bebae9c0SAndroid Build Coastguard Worker         result = (*playerPlay)->GetPlayState(playerPlay, &status);
801*bebae9c0SAndroid Build Coastguard Worker         assert(XA_RESULT_SUCCESS == result);
802*bebae9c0SAndroid Build Coastguard Worker         if (status == XA_PLAYSTATE_PAUSED)
803*bebae9c0SAndroid Build Coastguard Worker             break;
804*bebae9c0SAndroid Build Coastguard Worker         assert(status == XA_PLAYSTATE_PLAYING);
805*bebae9c0SAndroid Build Coastguard Worker         usleep(100000);
806*bebae9c0SAndroid Build Coastguard Worker         if (pauseMs >= 0) {
807*bebae9c0SAndroid Build Coastguard Worker             result = (*playerPlay)->GetPosition(playerPlay, &position);
808*bebae9c0SAndroid Build Coastguard Worker             assert(XA_RESULT_SUCCESS == result);
809*bebae9c0SAndroid Build Coastguard Worker             if ((int) position >= pauseMs) {
810*bebae9c0SAndroid Build Coastguard Worker                 printf("Pausing for 5 seconds at position %u\n", position);
811*bebae9c0SAndroid Build Coastguard Worker                 result = (*playerPlay)->SetPlayState(playerPlay, XA_PLAYSTATE_PAUSED);
812*bebae9c0SAndroid Build Coastguard Worker                 assert(XA_RESULT_SUCCESS == result);
813*bebae9c0SAndroid Build Coastguard Worker                 sleep(5);
814*bebae9c0SAndroid Build Coastguard Worker                 // FIXME clear ABQ queue here
815*bebae9c0SAndroid Build Coastguard Worker                 result = (*playerPlay)->SetPlayState(playerPlay, XA_PLAYSTATE_PLAYING);
816*bebae9c0SAndroid Build Coastguard Worker                 assert(XA_RESULT_SUCCESS == result);
817*bebae9c0SAndroid Build Coastguard Worker                 pauseMs = -1;
818*bebae9c0SAndroid Build Coastguard Worker             }
819*bebae9c0SAndroid Build Coastguard Worker         }
820*bebae9c0SAndroid Build Coastguard Worker     }
821*bebae9c0SAndroid Build Coastguard Worker 
822*bebae9c0SAndroid Build Coastguard Worker     // wait a bit more in case of additional callbacks
823*bebae9c0SAndroid Build Coastguard Worker     printf("end of media\n");
824*bebae9c0SAndroid Build Coastguard Worker     sleep(3);
825*bebae9c0SAndroid Build Coastguard Worker 
826*bebae9c0SAndroid Build Coastguard Worker     // get final position
827*bebae9c0SAndroid Build Coastguard Worker     result = (*playerPlay)->GetPosition(playerPlay, &position);
828*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_SUCCESS == result);
829*bebae9c0SAndroid Build Coastguard Worker     printf("Position at end: %u ms\n", position);
830*bebae9c0SAndroid Build Coastguard Worker 
831*bebae9c0SAndroid Build Coastguard Worker     // get duration again, now it should be known
832*bebae9c0SAndroid Build Coastguard Worker     result = (*playerPlay)->GetDuration(playerPlay, &duration);
833*bebae9c0SAndroid Build Coastguard Worker     assert(XA_RESULT_SUCCESS == result);
834*bebae9c0SAndroid Build Coastguard Worker     if (duration == XA_TIME_UNKNOWN) {
835*bebae9c0SAndroid Build Coastguard Worker         printf("Duration at end: unknown\n");
836*bebae9c0SAndroid Build Coastguard Worker     } else {
837*bebae9c0SAndroid Build Coastguard Worker         printf("Duration at end: %u ms\n", duration);
838*bebae9c0SAndroid Build Coastguard Worker     }
839*bebae9c0SAndroid Build Coastguard Worker 
840*bebae9c0SAndroid Build Coastguard Worker destroyRes:
841*bebae9c0SAndroid Build Coastguard Worker 
842*bebae9c0SAndroid Build Coastguard Worker     // destroy the player
843*bebae9c0SAndroid Build Coastguard Worker     (*playerObject)->Destroy(playerObject);
844*bebae9c0SAndroid Build Coastguard Worker 
845*bebae9c0SAndroid Build Coastguard Worker     // destroy the output mix
846*bebae9c0SAndroid Build Coastguard Worker     (*outputMixObject)->Destroy(outputMixObject);
847*bebae9c0SAndroid Build Coastguard Worker 
848*bebae9c0SAndroid Build Coastguard Worker     // destroy the engine
849*bebae9c0SAndroid Build Coastguard Worker     (*engineObject)->Destroy(engineObject);
850*bebae9c0SAndroid Build Coastguard Worker 
851*bebae9c0SAndroid Build Coastguard Worker #if 0
852*bebae9c0SAndroid Build Coastguard Worker     if (nativeWindow != NULL) {
853*bebae9c0SAndroid Build Coastguard Worker         ANativeWindow_release(nativeWindow);
854*bebae9c0SAndroid Build Coastguard Worker     }
855*bebae9c0SAndroid Build Coastguard Worker #endif
856*bebae9c0SAndroid Build Coastguard Worker 
857*bebae9c0SAndroid Build Coastguard Worker close:
858*bebae9c0SAndroid Build Coastguard Worker     if (fd >= 0) {
859*bebae9c0SAndroid Build Coastguard Worker         (void) close(fd);
860*bebae9c0SAndroid Build Coastguard Worker     }
861*bebae9c0SAndroid Build Coastguard Worker 
862*bebae9c0SAndroid Build Coastguard Worker     disposeNativeWindow();
863*bebae9c0SAndroid Build Coastguard Worker 
864*bebae9c0SAndroid Build Coastguard Worker     return EXIT_SUCCESS;
865*bebae9c0SAndroid Build Coastguard Worker }
866