175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten/*
275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten * Copyright (C) 2011 The Android Open Source Project
375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten *
475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten * Licensed under the Apache License, Version 2.0 (the "License");
575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten * you may not use this file except in compliance with the License.
675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten * You may obtain a copy of the License at
775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten *
875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten *      http://www.apache.org/licenses/LICENSE-2.0
975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten *
1075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten * Unless required by applicable law or agreed to in writing, software
1175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten * distributed under the License is distributed on an "AS IS" BASIS,
1275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten * See the License for the specific language governing permissions and
1475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten * limitations under the License.
1575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten */
1675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
1775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten// OpenMAX AL MediaPlayer command-line player
1875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
1975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#include <assert.h>
2075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#include <pthread.h>
2175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#include <stdio.h>
2275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#include <stdlib.h>
23b93695922547aecaf67b4e9c0bf1306257ffd54dElliott Hughes#include <string.h>
2475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#include <fcntl.h>
2575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#include <sys/mman.h>
2675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#include <sys/stat.h>
2775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#include <unistd.h>
2875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#include <OMXAL/OpenMAXAL.h>
2975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#include <OMXAL/OpenMAXAL_Android.h>
3075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#include "nativewindow.h"
3175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
3275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#define MPEG2TS_PACKET_SIZE 188  // MPEG-2 transport stream packet size in bytes
3375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#define PACKETS_PER_BUFFER 20    // Number of MPEG-2 transport stream packets per buffer
3475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
3575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#define NB_BUFFERS 2    // Number of buffers in Android buffer queue
3675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
3775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten// MPEG-2 transport stream packet
3875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kastentypedef struct {
3975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    char data[MPEG2TS_PACKET_SIZE];
4075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten} MPEG2TS_Packet;
4175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
4275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten// Globals shared between main thread and buffer queue callback
4375290ff394698c53f35a21612c03b8ddd21fecf9Glenn KastenMPEG2TS_Packet *packets;
44b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kastensize_t totalPackets;    // total number of packets in input file
45b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kastensize_t numPackets;      // number of packets to play, defaults to totalPackets - firstPacket
46b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kastensize_t curPacket;       // current packet index
47b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kastensize_t discPacket;      // discontinuity packet index, defaults to no discontinuity requested
48b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kastensize_t afterDiscPacket; // packet index to switch to after the discontinuity
49b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kastensize_t firstPacket;     // first packet index to be played, defaults to zero
50b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kastensize_t lastPacket;      // last packet index to be played
51b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kastensize_t formatPacket;    // format change packet index, defaults to no format change requested
52b17edb96ba759cd1197bf13cd13e279ee144da60Glenn KastenXAmillisecond seekPos = XA_TIME_UNKNOWN;    // seek to this position initially
53b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kastenint pauseMs = -1;       // pause after this many ms into playback
54b17edb96ba759cd1197bf13cd13e279ee144da60Glenn KastenXAboolean forceCallbackFailure = XA_BOOLEAN_FALSE;  // force callback failures occasionally
55b17edb96ba759cd1197bf13cd13e279ee144da60Glenn KastenXAboolean sentEOS = XA_BOOLEAN_FALSE;   // whether we have enqueued EOS yet
5675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
5775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten// These are extensions to OpenMAX AL 1.0.1 values
5875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
5975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#define PREFETCHSTATUS_UNKNOWN ((XAuint32) 0)
6075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#define PREFETCHSTATUS_ERROR   ((XAuint32) (-1))
6175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
6275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten// Mutex and condition shared with main program to protect prefetch_status
6375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
6475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kastenstatic pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
6575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kastenstatic pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
6675290ff394698c53f35a21612c03b8ddd21fecf9Glenn KastenXAuint32 prefetch_status = PREFETCHSTATUS_UNKNOWN;
6775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
6875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten/* used to detect errors likely to have occured when the OpenMAX AL framework fails to open
6975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten * a resource, for instance because a file URI is invalid, or an HTTP server doesn't respond.
7075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten */
7175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#define PREFETCHEVENT_ERROR_CANDIDATE \
7275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        (XA_PREFETCHEVENT_STATUSCHANGE | XA_PREFETCHEVENT_FILLLEVELCHANGE)
7375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
7475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten// stream event change callback
75086a6f51a7b12880ed114962136972f89ed70da2Glenn Kastenvoid streamEventChangeCallback(XAStreamInformationItf caller __unused, XAuint32 eventId,
7675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        XAuint32 streamIndex, void *pEventData, void *pContext)
7775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten{
7875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // context parameter is specified as NULL and is unused here
7975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(NULL == pContext);
8075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    switch (eventId) {
8175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    case XA_STREAMCBEVENT_PROPERTYCHANGE:
8275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        printf("XA_STREAMCBEVENT_PROPERTYCHANGE on stream index %u, pEventData %p\n", streamIndex,
8375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten                pEventData);
8475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        break;
8575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    default:
8675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        printf("Unknown stream event ID %u\n", eventId);
8775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        break;
8875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
8975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten}
9075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
9175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten// prefetch status callback
9275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kastenvoid prefetchStatusCallback(XAPrefetchStatusItf caller,  void *pContext, XAuint32 event)
9375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten{
9475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // pContext is unused here, so we pass NULL
9575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(pContext == NULL);
9675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XApermille level = 0;
9775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XAresult result;
9875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*caller)->GetFillLevel(caller, &level);
9975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
10075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XAuint32 status;
10175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*caller)->GetPrefetchStatus(caller, &status);
10275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
10375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    if (event & XA_PREFETCHEVENT_FILLLEVELCHANGE) {
10475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        printf("PrefetchEventCallback: Buffer fill level is = %d\n", level);
10575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
10675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    if (event & XA_PREFETCHEVENT_STATUSCHANGE) {
10775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        printf("PrefetchEventCallback: Prefetch Status is = %u\n", status);
10875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
10975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XAuint32 new_prefetch_status;
11075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    if ((PREFETCHEVENT_ERROR_CANDIDATE == (event & PREFETCHEVENT_ERROR_CANDIDATE))
11175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            && (level == 0) && (status == XA_PREFETCHSTATUS_UNDERFLOW)) {
11275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        printf("PrefetchEventCallback: Error while prefetching data, exiting\n");
11375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        new_prefetch_status = PREFETCHSTATUS_ERROR;
11475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    } else if (event == XA_PREFETCHEVENT_STATUSCHANGE) {
11575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        new_prefetch_status = status;
11675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    } else {
11775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        return;
11875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
11975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    int ok;
12075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    ok = pthread_mutex_lock(&mutex);
12175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(ok == 0);
12275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    prefetch_status = new_prefetch_status;
12375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    ok = pthread_cond_signal(&cond);
12475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(ok == 0);
12575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    ok = pthread_mutex_unlock(&mutex);
12675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(ok == 0);
12775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten}
12875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
12975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten// playback event callback
13075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kastenvoid playEventCallback(XAPlayItf caller, void *pContext, XAuint32 event)
13175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten{
13275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // pContext is unused here, so we pass NULL
13375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(NULL == pContext);
13475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
135b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    XAresult result;
13675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XAmillisecond position;
137b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    result = (*caller)->GetPosition(caller, &position);
138b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
13975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
14075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    if (XA_PLAYEVENT_HEADATEND & event) {
141b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        printf("XA_PLAYEVENT_HEADATEND current position=%u ms\n", position);
14275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
14375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
14475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    if (XA_PLAYEVENT_HEADATNEWPOS & event) {
145b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        printf("XA_PLAYEVENT_HEADATNEWPOS current position=%u ms\n", position);
14675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
14775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
14875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    if (XA_PLAYEVENT_HEADATMARKER & event) {
149b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        printf("XA_PLAYEVENT_HEADATMARKER current position=%u ms\n", position);
15075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
15175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten}
15275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
15375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten// Android buffer queue callback
15475290ff394698c53f35a21612c03b8ddd21fecf9Glenn KastenXAresult bufferQueueCallback(
15575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        XAAndroidBufferQueueItf caller,
15675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        void *pCallbackContext,
157086a6f51a7b12880ed114962136972f89ed70da2Glenn Kasten        void *pBufferContext __unused,
158086a6f51a7b12880ed114962136972f89ed70da2Glenn Kasten        void *pBufferData __unused,
159086a6f51a7b12880ed114962136972f89ed70da2Glenn Kasten        XAuint32 dataSize __unused,
160086a6f51a7b12880ed114962136972f89ed70da2Glenn Kasten        XAuint32 dataUsed __unused,
161086a6f51a7b12880ed114962136972f89ed70da2Glenn Kasten        const XAAndroidBufferItem *pItems __unused,
162086a6f51a7b12880ed114962136972f89ed70da2Glenn Kasten        XAuint32 itemsLength __unused)
16375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten{
164b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    XAPlayItf playerPlay = (XAPlayItf) pCallbackContext;
16575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // enqueue the .ts data directly from mapped memory, so ignore the empty buffer pBufferData
166b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    if (curPacket <= lastPacket) {
16762496886cb4620c09bc5df0de70a883319616c25Aurimas Liutikas        static const XAAndroidBufferItem discontinuity = {XA_ANDROID_ITEMKEY_DISCONTINUITY, 0, {}};
16862496886cb4620c09bc5df0de70a883319616c25Aurimas Liutikas        static const XAAndroidBufferItem eos = {XA_ANDROID_ITEMKEY_EOS, 0, {}};
16962496886cb4620c09bc5df0de70a883319616c25Aurimas Liutikas        static const XAAndroidBufferItem formatChange = {XA_ANDROID_ITEMKEY_FORMAT_CHANGE, 0, {}};
17075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        const XAAndroidBufferItem *items;
17175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        XAuint32 itemSize;
17275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        // compute number of packets to be enqueued in this buffer
173b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        XAuint32 packetsThisBuffer = lastPacket - curPacket;
17475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        if (packetsThisBuffer > PACKETS_PER_BUFFER) {
17575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            packetsThisBuffer = PACKETS_PER_BUFFER;
17675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        }
17775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        // last packet? this should only happen once
178b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        if (curPacket == lastPacket) {
179b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            if (sentEOS) {
180b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                printf("buffer completion callback after EOS\n");
181b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                return XA_RESULT_SUCCESS;
182b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            }
183b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("sending EOS\n");
18475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            items = &eos;
18575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            itemSize = sizeof(eos);
186b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            sentEOS = XA_BOOLEAN_TRUE;
18775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        // discontinuity requested?
18875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        } else if (curPacket == discPacket) {
189b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("sending discontinuity at packet %zu, then resuming at packet %zu\n", discPacket,
190b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                    afterDiscPacket);
19175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            items = &discontinuity;
19275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            itemSize = sizeof(discontinuity);
193b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            curPacket = afterDiscPacket;
194b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        // format change requested?
195b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        } else if (curPacket == formatPacket) {
196b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("sending format change");
197b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            items = &formatChange;
198b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            itemSize = sizeof(formatChange);
19975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        // pure data with no items
20075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        } else {
20175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            items = NULL;
20275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            itemSize = 0;
20375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        }
20475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        XAresult result;
20575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        // enqueue the optional data and optional items; there is always at least one or the other
20675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        assert(packetsThisBuffer > 0 || itemSize > 0);
20775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        result = (*caller)->Enqueue(caller, NULL, &packets[curPacket],
20875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten                sizeof(MPEG2TS_Packet) * packetsThisBuffer, items, itemSize);
20975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        assert(XA_RESULT_SUCCESS == result);
21075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        curPacket += packetsThisBuffer;
211b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        // display position periodically
212b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        if (curPacket % 1000 == 0) {
213b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            XAmillisecond position;
214b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            result = (*playerPlay)->GetPosition(playerPlay, &position);
215b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            assert(XA_RESULT_SUCCESS == result);
21601f8573bc2a850536b02855d483dfe130c050a2fAshok Bhat            printf("Position after enqueueing packet %zu: %u ms\n", curPacket, position);
217b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        }
218b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    }
219b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    if (forceCallbackFailure && (curPacket % 1230 == 0)) {
220b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        return (XAresult) curPacket;
221b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    } else {
222b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        return XA_RESULT_SUCCESS;
223b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    }
224b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten}
225b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten
226b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten// convert a domain type to string
227b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kastenstatic const char *domainToString(XAuint32 domain)
228b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten{
229b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    switch (domain) {
230b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    case 0: // FIXME There's a private declaration '#define XA_DOMAINTYPE_CONTAINER 0' in src/data.h
231b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            // but we don't have access to it. Plan to file a bug with Khronos about this symbol.
232b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        return "media container";
233b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten#define _(x) case x: return #x;
234b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    _(XA_DOMAINTYPE_AUDIO)
235b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    _(XA_DOMAINTYPE_VIDEO)
236b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    _(XA_DOMAINTYPE_IMAGE)
237b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    _(XA_DOMAINTYPE_TIMEDTEXT)
238b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    _(XA_DOMAINTYPE_MIDI)
239b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    _(XA_DOMAINTYPE_VENDOR)
240b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    _(XA_DOMAINTYPE_UNKNOWN)
241b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten#undef _
242b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    default:
243b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        return "unknown";
24475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
24575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten}
24675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
24775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten// main program
24875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kastenint main(int argc, char **argv)
24975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten{
25075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    const char *prog = argv[0];
25175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    int i;
25275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
25375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XAboolean abq = XA_BOOLEAN_FALSE;   // use AndroidBufferQueue, default is URI
25475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XAboolean looping = XA_BOOLEAN_FALSE;
25575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    for (i = 1; i < argc; ++i) {
25675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        const char *arg = argv[i];
25775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        if (arg[0] != '-')
25875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            break;
25975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        switch (arg[1]) {
26075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        case 'a':
26175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            abq = XA_BOOLEAN_TRUE;
26275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            break;
263b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        case 'c':
264b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            forceCallbackFailure = XA_BOOLEAN_TRUE;
265b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            break;
26675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        case 'd':
26775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            discPacket = atoi(&arg[2]);
26875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            break;
269b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        case 'D':
270b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            afterDiscPacket = atoi(&arg[2]);
271b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            break;
272b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        case 'f':
273b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            firstPacket = atoi(&arg[2]);
274b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            break;
275b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        case 'F':
276b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            formatPacket = atoi(&arg[2]);
277b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            break;
27875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        case 'l':
27975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            looping = XA_BOOLEAN_TRUE;
28075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            break;
281b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        case 'n':
282b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            numPackets = atoi(&arg[2]);
283b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            break;
284b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        case 'p':
285b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            pauseMs = atoi(&arg[2]);
286b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            break;
287b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        case 's':
288b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            seekPos = atoi(&arg[2]);
28975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            break;
29075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        default:
29175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            fprintf(stderr, "%s: unknown option %s\n", prog, arg);
29275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            break;
29375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        }
29475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
29575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
29675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // check that exactly one URI was specified
29775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    if (argc - i != 1) {
298b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        fprintf(stderr, "usage: %s [-a] [-c] [-d#] [-D#] [-f#] [-F#] [-l] [-n#] [-p#] [-s#] uri\n",
299b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                prog);
300b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        fprintf(stderr, "    -a  Use Android buffer queue to supply data, default is URI\n");
301b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        fprintf(stderr, "    -c  Force callback to return an error randomly, for debugging only\n");
302b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        fprintf(stderr, "    -d# Packet index to insert a discontinuity, default is none\n");
303b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        fprintf(stderr, "    -D# Packet index to switch to after the discontinuity\n");
304b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        fprintf(stderr, "    -f# First packet index, defaults to 0\n");
305b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        fprintf(stderr, "    -F# Packet index to insert a format change, default is none\n");
306b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        fprintf(stderr, "    -l  Enable looping, for URI only\n");
307b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        fprintf(stderr, "    -n# Number of packets to enqueue\n");
308b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        fprintf(stderr, "    -p# Pause playback for 5 seconds after this many milliseconds\n");
309b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        fprintf(stderr, "    -s# Seek position in milliseconds, for URI only\n");
31075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        return EXIT_FAILURE;
31175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
31275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    const char *uri = argv[i];
31375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
31475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // for AndroidBufferQueue, interpret URI as a filename and open
31575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    int fd = -1;
31675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    if (abq) {
31775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        fd = open(uri, O_RDONLY);
31875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        if (fd < 0) {
31975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            perror(uri);
32075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            goto close;
32175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        }
32275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        int ok;
32375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        struct stat statbuf;
32475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        ok = fstat(fd, &statbuf);
32575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        if (ok < 0) {
32675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            perror(uri);
32775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            goto close;
32875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        }
32975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        if (!S_ISREG(statbuf.st_mode)) {
33075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            fprintf(stderr, "%s: not an ordinary file\n", uri);
33175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            goto close;
33275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        }
33375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        void *ptr;
33475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        ptr = mmap(NULL, statbuf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, (off_t) 0);
33575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        if (ptr == MAP_FAILED) {
33675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            perror(uri);
33775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            goto close;
33875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        }
33975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        size_t filelen = statbuf.st_size;
34075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        if ((filelen % MPEG2TS_PACKET_SIZE) != 0) {
34175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            fprintf(stderr, "%s: warning file length %zu is not a multiple of %d\n", uri, filelen,
34275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten                    MPEG2TS_PACKET_SIZE);
34375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        }
34475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        packets = (MPEG2TS_Packet *) ptr;
345b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        totalPackets = filelen / MPEG2TS_PACKET_SIZE;
346b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        printf("%s has %zu total packets\n", uri, totalPackets);
347b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        if (firstPacket >= totalPackets) {
348b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            fprintf(stderr, "-f%zu ignored\n", firstPacket);
349b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            firstPacket = 0;
350b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        }
351b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        if (numPackets == 0) {
352b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            numPackets = totalPackets - firstPacket;
353b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        } else if (firstPacket + numPackets > totalPackets) {
354b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            fprintf(stderr, "-n%zu ignored\n", numPackets);
355b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            numPackets = totalPackets - firstPacket;
356b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        }
357b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        lastPacket = firstPacket + numPackets;
358b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        if (discPacket != 0 && (discPacket < firstPacket || discPacket >= lastPacket)) {
359b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            fprintf(stderr, "-d%zu ignored\n", discPacket);
360b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            discPacket = 0;
361b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        }
362b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        if (afterDiscPacket < firstPacket || afterDiscPacket >= lastPacket) {
363b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            fprintf(stderr, "-D%zu ignored\n", afterDiscPacket);
364b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            afterDiscPacket = 0;
365b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        }
366b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        if (formatPacket != 0 && (formatPacket < firstPacket || formatPacket >= lastPacket)) {
367b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            fprintf(stderr, "-F%zu ignored\n", formatPacket);
368b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            formatPacket = 0;
369b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        }
37075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
37175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
37275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    ANativeWindow *nativeWindow;
37375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
37475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XAresult result;
37575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XAObjectItf engineObject;
37675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
37775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // create engine
37875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = xaCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
37975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
38075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*engineObject)->Realize(engineObject, XA_BOOLEAN_FALSE);
38175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
38275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XAEngineItf engineEngine;
38375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*engineObject)->GetInterface(engineObject, XA_IID_ENGINE, &engineEngine);
38475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
38575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
38675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // create output mix
38775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XAObjectItf outputMixObject;
38875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL);
38975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
39075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*outputMixObject)->Realize(outputMixObject, XA_BOOLEAN_FALSE);
39175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
39275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
39375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // configure media source
39475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XADataLocator_URI locUri;
39575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    locUri.locatorType = XA_DATALOCATOR_URI;
39675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    locUri.URI = (XAchar *) uri;
39775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XADataFormat_MIME fmtMime;
39875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    fmtMime.formatType = XA_DATAFORMAT_MIME;
39975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    if (abq) {
400c3b82a293ed06001ba6d50f111608160c6065ef2Glenn Kasten        fmtMime.mimeType = (XAchar *) XA_ANDROID_MIME_MP2TS;
40175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        fmtMime.containerType = XA_CONTAINERTYPE_MPEG_TS;
40275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    } else {
40375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        fmtMime.mimeType = NULL;
40475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        fmtMime.containerType = XA_CONTAINERTYPE_UNSPECIFIED;
40575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
40675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XADataLocator_AndroidBufferQueue locABQ;
40775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    locABQ.locatorType = XA_DATALOCATOR_ANDROIDBUFFERQUEUE;
40875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    locABQ.numBuffers = NB_BUFFERS;
40975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XADataSource dataSrc;
41075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    if (abq) {
41175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        dataSrc.pLocator = &locABQ;
41275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    } else {
41375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        dataSrc.pLocator = &locUri;
41475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
41575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    dataSrc.pFormat = &fmtMime;
41675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
41775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // configure audio sink
41875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XADataLocator_OutputMix locOM;
41975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    locOM.locatorType = XA_DATALOCATOR_OUTPUTMIX;
42075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    locOM.outputMix = outputMixObject;
42175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XADataSink audioSnk;
42275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    audioSnk.pLocator = &locOM;
42375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    audioSnk.pFormat = NULL;
42475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
42575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // configure video sink
42675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    nativeWindow = getNativeWindow();
42775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XADataLocator_NativeDisplay locND;
42875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    locND.locatorType = XA_DATALOCATOR_NATIVEDISPLAY;
42975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    locND.hWindow = nativeWindow;
43075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    locND.hDisplay = NULL;
43175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XADataSink imageVideoSink;
43275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    imageVideoSink.pLocator = &locND;
43375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    imageVideoSink.pFormat = NULL;
43475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
43575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // create media player
43675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XAObjectItf playerObject;
43775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XAInterfaceID ids[4] = {XA_IID_STREAMINFORMATION, XA_IID_PREFETCHSTATUS, XA_IID_SEEK,
43860ca9f9ef02f6e486c3338cb811f603dd7825c05Glenn Kasten            XA_IID_ANDROIDBUFFERQUEUESOURCE};
439b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    XAboolean req[4] = {XA_BOOLEAN_TRUE, XA_BOOLEAN_TRUE, XA_BOOLEAN_FALSE, XA_BOOLEAN_TRUE};
44075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*engineEngine)->CreateMediaPlayer(engineEngine, &playerObject, &dataSrc, NULL,
44175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            &audioSnk, nativeWindow != NULL ? &imageVideoSink : NULL, NULL, NULL, abq ? 4 : 3, ids,
44275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            req);
44375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
44475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
44575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // realize the player
44675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*playerObject)->Realize(playerObject, XA_BOOLEAN_FALSE);
44775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
44875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
449b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    // get the play interface
450b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    XAPlayItf playerPlay;
451b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    result = (*playerObject)->GetInterface(playerObject, XA_IID_PLAY, &playerPlay);
452b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
453b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten
45475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    if (abq) {
45575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
45675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        // get the Android buffer queue interface
45775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        XAAndroidBufferQueueItf playerAndroidBufferQueue;
45860ca9f9ef02f6e486c3338cb811f603dd7825c05Glenn Kasten        result = (*playerObject)->GetInterface(playerObject, XA_IID_ANDROIDBUFFERQUEUESOURCE,
45975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten                &playerAndroidBufferQueue);
46075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        assert(XA_RESULT_SUCCESS == result);
46175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
46275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        // register the buffer queue callback
46375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        result = (*playerAndroidBufferQueue)->RegisterCallback(playerAndroidBufferQueue,
464b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                bufferQueueCallback, (void *) playerPlay);
46575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        assert(XA_RESULT_SUCCESS == result);
46675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        result = (*playerAndroidBufferQueue)->SetCallbackEventsMask(playerAndroidBufferQueue,
46775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten                XA_ANDROIDBUFFERQUEUEEVENT_PROCESSED);
46875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        assert(XA_RESULT_SUCCESS == result);
46975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
470b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        // set the player's state to paused, to start prefetching
471b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        printf("start early prefetch\n");
472b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        result = (*playerPlay)->SetPlayState(playerPlay, XA_PLAYSTATE_PAUSED);
473b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        assert(XA_RESULT_SUCCESS == result);
474b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten
47575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        // enqueue the initial buffers until buffer queue is full
47675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        XAuint32 packetsThisBuffer;
477b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        for (curPacket = firstPacket; curPacket < lastPacket; curPacket += packetsThisBuffer) {
47875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            // handle the unlikely case of a very short .ts
479b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            packetsThisBuffer = lastPacket - curPacket;
48075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            if (packetsThisBuffer > PACKETS_PER_BUFFER) {
48175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten                packetsThisBuffer = PACKETS_PER_BUFFER;
48275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            }
48375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            result = (*playerAndroidBufferQueue)->Enqueue(playerAndroidBufferQueue, NULL,
48475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten                    &packets[curPacket], MPEG2TS_PACKET_SIZE * packetsThisBuffer, NULL, 0);
48575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            if (XA_RESULT_BUFFER_INSUFFICIENT == result) {
48601f8573bc2a850536b02855d483dfe130c050a2fAshok Bhat                printf("Enqueued initial %zu packets in %zu buffers\n", curPacket - firstPacket,
487b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                        (curPacket - firstPacket + PACKETS_PER_BUFFER - 1) / PACKETS_PER_BUFFER);
48875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten                break;
48975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            }
49075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            assert(XA_RESULT_SUCCESS == result);
49175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        }
49275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
49375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
49475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
49575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // get the stream information interface
49675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XAStreamInformationItf playerStreamInformation;
49775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*playerObject)->GetInterface(playerObject, XA_IID_STREAMINFORMATION,
49875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            &playerStreamInformation);
49975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
50075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
50175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // register the stream event change callback
50275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*playerStreamInformation)->RegisterStreamChangeCallback(playerStreamInformation,
50375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            streamEventChangeCallback, NULL);
50475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
50575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
50675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // get the prefetch status interface
50775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XAPrefetchStatusItf playerPrefetchStatus;
50875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*playerObject)->GetInterface(playerObject, XA_IID_PREFETCHSTATUS,
50975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            &playerPrefetchStatus);
51075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
51175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
51275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // register prefetch status callback
51375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*playerPrefetchStatus)->RegisterCallback(playerPrefetchStatus, prefetchStatusCallback,
51475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            NULL);
51575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
51675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*playerPrefetchStatus)->SetCallbackEventsMask(playerPrefetchStatus,
51775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            XA_PREFETCHEVENT_FILLLEVELCHANGE | XA_PREFETCHEVENT_STATUSCHANGE);
51875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
51975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
520b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    // get the seek interface for seeking and/or looping
521b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    if (looping || seekPos != XA_TIME_UNKNOWN) {
52275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        XASeekItf playerSeek;
52375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        result = (*playerObject)->GetInterface(playerObject, XA_IID_SEEK, &playerSeek);
52475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        assert(XA_RESULT_SUCCESS == result);
525b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        if (seekPos != XA_TIME_UNKNOWN) {
526b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            result = (*playerSeek)->SetPosition(playerSeek, seekPos, XA_SEEKMODE_ACCURATE);
527b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            if (XA_RESULT_FEATURE_UNSUPPORTED == result) {
528b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                fprintf(stderr, "-s%u (seek to initial position) is unsupported\n", seekPos);
529b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            } else {
530b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                assert(XA_RESULT_SUCCESS == result);
531b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            }
532b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        }
533b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        if (looping) {
534b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            result = (*playerSeek)->SetLoop(playerSeek, XA_BOOLEAN_TRUE, (XAmillisecond) 0,
535b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                    XA_TIME_UNKNOWN);
536b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            if (XA_RESULT_FEATURE_UNSUPPORTED) {
537b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                fprintf(stderr, "-l (looping) is unsupported\n");
538b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            } else {
539b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                assert(XA_RESULT_SUCCESS == result);
540b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            }
541b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        }
54275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
54375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
54475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // register play event callback
54575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*playerPlay)->RegisterCallback(playerPlay, playEventCallback, NULL);
54675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
54775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*playerPlay)->SetCallbackEventsMask(playerPlay,
54875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            XA_PLAYEVENT_HEADATEND | XA_PLAYEVENT_HEADATMARKER | XA_PLAYEVENT_HEADATNEWPOS);
54975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
55075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
55175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // set a marker
552b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    result = (*playerPlay)->SetMarkerPosition(playerPlay, 5000);
55375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
55475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
55575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // set position update period
556b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    result = (*playerPlay)->SetPositionUpdatePeriod(playerPlay, 2000);
55775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
55875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
559b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    // get the position before prefetch
560b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    XAmillisecond position;
561b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    result = (*playerPlay)->GetPosition(playerPlay, &position);
562b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
563b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    printf("Position before prefetch: %u ms\n", position);
564b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten
565b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    // get the duration before prefetch
56675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XAmillisecond duration;
56775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*playerPlay)->GetDuration(playerPlay, &duration);
56875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
56975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    if (XA_TIME_UNKNOWN == duration)
570b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        printf("Duration before prefetch: unknown as expected\n");
57175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    else
572b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        printf("Duration before prefetch: %.1f (surprise!)\n", duration / 1000.0f);
57375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
57475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // set the player's state to paused, to start prefetching
57575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    printf("start prefetch\n");
57675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*playerPlay)->SetPlayState(playerPlay, XA_PLAYSTATE_PAUSED);
57775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
57875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
57975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // wait for prefetch status callback to indicate either sufficient data or error
58075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    pthread_mutex_lock(&mutex);
58175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    while (prefetch_status == PREFETCHSTATUS_UNKNOWN) {
58275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        pthread_cond_wait(&cond, &mutex);
58375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
58475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    pthread_mutex_unlock(&mutex);
58575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    if (prefetch_status == PREFETCHSTATUS_ERROR) {
58675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        fprintf(stderr, "Error during prefetch, exiting\n");
58775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        goto destroyRes;
58875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
58975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
590b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    // get the position after prefetch
591b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    result = (*playerPlay)->GetPosition(playerPlay, &position);
592b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
593b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    printf("Position after prefetch: %u ms\n", position);
594b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten
595b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    // get duration again, now it should be known for the file source or unknown for TS
59675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*playerPlay)->GetDuration(playerPlay, &duration);
59775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
59875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    if (duration == XA_TIME_UNKNOWN) {
599b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        printf("Duration after prefetch: unknown (expected for TS, unexpected for file)\n");
60075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    } else {
601b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        printf("Duration after prefetch: %u ms (expected for file, unexpected for TS)\n", duration);
60275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
60375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
604b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    // query for media container information
605b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    result = (*playerStreamInformation)->QueryMediaContainerInformation(playerStreamInformation,
606b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            NULL);
607b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    assert(XA_RESULT_PARAMETER_INVALID == result);
608b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    XAMediaContainerInformation mediaContainerInformation;
609b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    // this verifies it is filling in all the fields
610b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    memset(&mediaContainerInformation, 0x55, sizeof(XAMediaContainerInformation));
611b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    result = (*playerStreamInformation)->QueryMediaContainerInformation(playerStreamInformation,
612b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            &mediaContainerInformation);
613b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
614b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    printf("Media container information:\n");
615b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    printf("  containerType = %u\n", mediaContainerInformation.containerType);
616b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    printf("  mediaDuration = %u\n", mediaContainerInformation.mediaDuration);
617b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    printf("  numStreams = %u\n", mediaContainerInformation.numStreams);
618b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten
619b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    // Now query for each the streams.  Note that stream indices go up to and including
620b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    // mediaContainerInformation.numStreams, because stream 0 is the container itself,
621b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    // while stream 1 to mediaContainerInformation.numStreams are the contained streams.
622b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    XAuint32 streamIndex;
623b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    for (streamIndex = 0; streamIndex <= mediaContainerInformation.numStreams; ++streamIndex) {
624b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        XAuint32 domain;
625b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        XAuint16 nameSize;
626b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        XAchar name[64];
627b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        printf("stream[%u]:\n", streamIndex);
628b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        if (streamIndex == 0) {
629b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            result = (*playerStreamInformation)->QueryStreamType(playerStreamInformation,
630b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                    streamIndex, &domain);
631b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            assert(XA_RESULT_PARAMETER_INVALID == result);
632b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
633b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                    streamIndex, &mediaContainerInformation);
634b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            //assert(XA_RESULT_PARAMETER_INVALID == result);
635b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            nameSize = sizeof(name);
636b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            result = (*playerStreamInformation)->QueryStreamName(playerStreamInformation,
637b17edb96ba759cd1197bf13cd13e279ee144da60Glenn KastenstreamIndex, &nameSize, name);
638b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            //assert(XA_RESULT_PARAMETER_INVALID == result);
639b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            continue;
640b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        }
641b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        result = (*playerStreamInformation)->QueryStreamType(playerStreamInformation, streamIndex,
642b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                NULL);
643b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        assert(XA_RESULT_PARAMETER_INVALID == result);
644b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        domain = 12345;
645b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        result = (*playerStreamInformation)->QueryStreamType(playerStreamInformation, streamIndex,
646b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                &domain);
647b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        assert(XA_RESULT_SUCCESS == result);
648b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        printf(" QueryStreamType: domain = 0x%X (%s)\n", domain, domainToString(domain));
649b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        nameSize = sizeof(name);
650b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        result = (*playerStreamInformation)->QueryStreamName(playerStreamInformation, streamIndex,
651b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                &nameSize, name);
652b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten#if 0
653b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        assert(XA_RESULT_SUCCESS == result);
654b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        assert(sizeof(name) >= nameSize);
655b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        if (sizeof(name) != nameSize) {
656b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            assert('\0' == name[nameSize]);
657b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        }
658b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        printf(" QueryStreamName: nameSize=%u, name=\"%.*s\"\n", nameSize, nameSize, name);
659b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
660b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                streamIndex, NULL);
661b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        assert(XA_RESULT_PARAMETER_INVALID == result);
662b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten#endif
663b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten
664b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        printf(" QueryStreamInformation:\n");
665b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        switch (domain) {
666b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten#if 0
667b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        case 0: // FIXME container
668b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
669b17edb96ba759cd1197bf13cd13e279ee144da60Glenn KastenstreamIndex, &mediaContainerInformation);
670b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            assert(XA_RESULT_SUCCESS == result);
671b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  containerType = %u (1=unspecified)\n",
672b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                    mediaContainerInformation.containerType);
673b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  mediaDuration = %u\n", mediaContainerInformation.mediaDuration);
674b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  numStreams = %u\n", mediaContainerInformation.numStreams);
675b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            break;
676b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten#endif
677b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        case XA_DOMAINTYPE_AUDIO: {
678b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            XAAudioStreamInformation audioStreamInformation;
679b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            memset(&audioStreamInformation, 0x55, sizeof(XAAudioStreamInformation));
680b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
681b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                    streamIndex, &audioStreamInformation);
682b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            assert(XA_RESULT_PARAMETER_INVALID == result);
683b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  codecId = %u\n", audioStreamInformation.codecId);
684b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  channels = %u\n", audioStreamInformation.channels);
685b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  sampleRate = %u\n", audioStreamInformation.sampleRate);
686b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  bitRate = %u\n", audioStreamInformation.bitRate);
687b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  langCountry = \"%s\"\n", audioStreamInformation.langCountry);
688b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  duration = %u\n", audioStreamInformation.duration);
689b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            } break;
690b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        case XA_DOMAINTYPE_VIDEO: {
691b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            XAVideoStreamInformation videoStreamInformation;
692b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
693b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                    streamIndex, &videoStreamInformation);
694b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            assert(XA_RESULT_SUCCESS == result);
695b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  codecId = %u\n", videoStreamInformation.codecId);
696b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  width = %u\n", videoStreamInformation.width);
697b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  height = %u\n", videoStreamInformation.height);
698b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  frameRate = %u\n", videoStreamInformation.frameRate);
699b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  bitRate = %u\n", videoStreamInformation.bitRate);
700b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  duration = %u\n", videoStreamInformation.duration);
701b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            } break;
702b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        case XA_DOMAINTYPE_IMAGE: {
703b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            XAImageStreamInformation imageStreamInformation;
704b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
705b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                    streamIndex, &imageStreamInformation);
706b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            assert(XA_RESULT_SUCCESS == result);
707b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  codecId = %u\n", imageStreamInformation.codecId);
708b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  width = %u\n", imageStreamInformation.width);
709b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  height = %u\n", imageStreamInformation.height);
710b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  presentationDuration = %u\n", imageStreamInformation.presentationDuration);
711b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            } break;
712b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        case XA_DOMAINTYPE_TIMEDTEXT: {
713b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            XATimedTextStreamInformation timedTextStreamInformation;
714b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
715b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                    streamIndex, &timedTextStreamInformation);
716b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            assert(XA_RESULT_SUCCESS == result);
717b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  layer = %u\n", timedTextStreamInformation.layer);
718b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  width = %u\n", timedTextStreamInformation.width);
719b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  height = %u\n", timedTextStreamInformation.height);
720b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  tx = %u\n", timedTextStreamInformation.tx);
721b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  ty = %u\n", timedTextStreamInformation.ty);
722b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  bitrate = %u\n", timedTextStreamInformation.bitrate);
723b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  langCountry = \"%s\"\n", timedTextStreamInformation.langCountry);
724b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  duration = %u\n", timedTextStreamInformation.duration);
725b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            } break;
726b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        case XA_DOMAINTYPE_MIDI: {
727b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            XAMIDIStreamInformation midiStreamInformation;
728b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
729b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                    streamIndex, &midiStreamInformation);
730b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            assert(XA_RESULT_SUCCESS == result);
731b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  channels = %u\n", midiStreamInformation.channels);
732b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  tracks = %u\n", midiStreamInformation.tracks);
733b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  bankType = %u\n", midiStreamInformation.bankType);
734b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  langCountry = \"%s\"\n", midiStreamInformation.langCountry);
735b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  duration = %u\n", midiStreamInformation.duration);
736b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            } break;
737b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        case XA_DOMAINTYPE_VENDOR: {
738b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            XAVendorStreamInformation vendorStreamInformation;
739b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
740b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                    streamIndex, &vendorStreamInformation);
741b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            assert(XA_RESULT_SUCCESS == result);
742b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("  VendorStreamInfo = %p\n", vendorStreamInformation.VendorStreamInfo);
743b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            } break;
744b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        case XA_DOMAINTYPE_UNKNOWN: {
745b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            // "It is not possible to query Information for streams identified as
746b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            // XA_DOMAINTYPE_UNKNOWN, any attempt to do so shall return a result of
747b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            // XA_RESULT_CONTENT_UNSUPPORTED."
748b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            char big[256];
749b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
750b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                    streamIndex, &big);
751b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            assert(XA_RESULT_CONTENT_UNSUPPORTED == result);
752b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            } break;
753b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        default:
754b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            break;
755b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        }
756b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten
757b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    }
758b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    // Try one more stream index beyond the valid range
759b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    XAuint32 domain;
760b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    result = (*playerStreamInformation)->QueryStreamType(playerStreamInformation, streamIndex,
761b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            &domain);
762b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    assert(XA_RESULT_PARAMETER_INVALID == result);
763b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    XATimedTextStreamInformation big;
764b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
765b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            streamIndex, &big);
766b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    assert(XA_RESULT_PARAMETER_INVALID == result);
767b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten
768b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    printf("QueryActiveStreams:\n");
769b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    result = (*playerStreamInformation)->QueryActiveStreams(playerStreamInformation, NULL, NULL);
770b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    assert(XA_RESULT_PARAMETER_INVALID == result);
771b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    XAuint32 numStreams1 = 0x12345678;
772b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    result = (*playerStreamInformation)->QueryActiveStreams(playerStreamInformation, &numStreams1,
773b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            NULL);
774b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
775b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    printf("  numStreams = %u\n", numStreams1);
776b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    XAboolean *activeStreams = calloc(numStreams1 + 1, sizeof(XAboolean));
777b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    assert(NULL != activeStreams);
778b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    printf("  active stream(s) =");
779b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    XAuint32 numStreams2 = numStreams1;
780b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    result = (*playerStreamInformation)->QueryActiveStreams(playerStreamInformation, &numStreams2,
781b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            activeStreams);
782b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
783b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    assert(numStreams2 == numStreams1);
784b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    for (streamIndex = 0; streamIndex <= numStreams1; ++streamIndex) {
785b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        if (activeStreams[streamIndex])
786b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf(" %u", streamIndex);
787b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    }
788b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    printf("\n");
789b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten
790b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    // SetActiveStream is untested
791b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten
79275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // start playing
79375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    printf("starting to play\n");
79475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*playerPlay)->SetPlayState(playerPlay, XA_PLAYSTATE_PLAYING);
79575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
79675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
79775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // continue playing until end of media
79875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    for (;;) {
79975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        XAuint32 status;
80075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        result = (*playerPlay)->GetPlayState(playerPlay, &status);
80175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        assert(XA_RESULT_SUCCESS == result);
80275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        if (status == XA_PLAYSTATE_PAUSED)
80375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            break;
80475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        assert(status == XA_PLAYSTATE_PLAYING);
805b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        usleep(100000);
806b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        if (pauseMs >= 0) {
807b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            result = (*playerPlay)->GetPosition(playerPlay, &position);
808b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            assert(XA_RESULT_SUCCESS == result);
80914463a8e53e2a5185a395e2045fd33ad4a63050dGlenn Kasten            if ((int) position >= pauseMs) {
810b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                printf("Pausing for 5 seconds at position %u\n", position);
811b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                result = (*playerPlay)->SetPlayState(playerPlay, XA_PLAYSTATE_PAUSED);
812b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                assert(XA_RESULT_SUCCESS == result);
813b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                sleep(5);
814b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                // FIXME clear ABQ queue here
815b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                result = (*playerPlay)->SetPlayState(playerPlay, XA_PLAYSTATE_PLAYING);
816b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                assert(XA_RESULT_SUCCESS == result);
817b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                pauseMs = -1;
818b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            }
819b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        }
82075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
82175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
82275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // wait a bit more in case of additional callbacks
82375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    printf("end of media\n");
82475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    sleep(3);
82575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
826b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    // get final position
827b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    result = (*playerPlay)->GetPosition(playerPlay, &position);
828b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
829b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    printf("Position at end: %u ms\n", position);
830b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten
831b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    // get duration again, now it should be known
832b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    result = (*playerPlay)->GetDuration(playerPlay, &duration);
833b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
834b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    if (duration == XA_TIME_UNKNOWN) {
835b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        printf("Duration at end: unknown\n");
836b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    } else {
837b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        printf("Duration at end: %u ms\n", duration);
838b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    }
839b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten
84075290ff394698c53f35a21612c03b8ddd21fecf9Glenn KastendestroyRes:
84175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
84275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // destroy the player
84375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    (*playerObject)->Destroy(playerObject);
84475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
84575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // destroy the output mix
84675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    (*outputMixObject)->Destroy(outputMixObject);
84775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
84875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // destroy the engine
84975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    (*engineObject)->Destroy(engineObject);
85075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
85175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#if 0
85275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    if (nativeWindow != NULL) {
85375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        ANativeWindow_release(nativeWindow);
85475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
85575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#endif
85675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
85775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kastenclose:
85875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    if (fd >= 0) {
85975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        (void) close(fd);
86075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
86175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
862b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    disposeNativeWindow();
863b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten
86475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    return EXIT_SUCCESS;
86575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten}
866