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>
2375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#include <fcntl.h>
2475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#include <sys/mman.h>
2575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#include <sys/stat.h>
2675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#include <unistd.h>
2775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#include <OMXAL/OpenMAXAL.h>
2875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#include <OMXAL/OpenMAXAL_Android.h>
2975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#include "nativewindow.h"
3075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
3175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#define MPEG2TS_PACKET_SIZE 188  // MPEG-2 transport stream packet size in bytes
3275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#define PACKETS_PER_BUFFER 20    // Number of MPEG-2 transport stream packets per buffer
3375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
3475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#define NB_BUFFERS 2    // Number of buffers in Android buffer queue
3575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
3675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten// MPEG-2 transport stream packet
3775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kastentypedef struct {
3875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    char data[MPEG2TS_PACKET_SIZE];
3975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten} MPEG2TS_Packet;
4075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
4175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten// Globals shared between main thread and buffer queue callback
4275290ff394698c53f35a21612c03b8ddd21fecf9Glenn KastenMPEG2TS_Packet *packets;
43b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kastensize_t totalPackets;    // total number of packets in input file
44b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kastensize_t numPackets;      // number of packets to play, defaults to totalPackets - firstPacket
45b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kastensize_t curPacket;       // current packet index
46b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kastensize_t discPacket;      // discontinuity packet index, defaults to no discontinuity requested
47b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kastensize_t afterDiscPacket; // packet index to switch to after the discontinuity
48b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kastensize_t firstPacket;     // first packet index to be played, defaults to zero
49b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kastensize_t lastPacket;      // last packet index to be played
50b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kastensize_t formatPacket;    // format change packet index, defaults to no format change requested
51b17edb96ba759cd1197bf13cd13e279ee144da60Glenn KastenXAmillisecond seekPos = XA_TIME_UNKNOWN;    // seek to this position initially
52b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kastenint pauseMs = -1;       // pause after this many ms into playback
53b17edb96ba759cd1197bf13cd13e279ee144da60Glenn KastenXAboolean forceCallbackFailure = XA_BOOLEAN_FALSE;  // force callback failures occasionally
54b17edb96ba759cd1197bf13cd13e279ee144da60Glenn KastenXAboolean sentEOS = XA_BOOLEAN_FALSE;   // whether we have enqueued EOS yet
5575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
5675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten// These are extensions to OpenMAX AL 1.0.1 values
5775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
5875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#define PREFETCHSTATUS_UNKNOWN ((XAuint32) 0)
5975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#define PREFETCHSTATUS_ERROR   ((XAuint32) (-1))
6075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
6175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten// Mutex and condition shared with main program to protect prefetch_status
6275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
6375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kastenstatic pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
6475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kastenstatic pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
6575290ff394698c53f35a21612c03b8ddd21fecf9Glenn KastenXAuint32 prefetch_status = PREFETCHSTATUS_UNKNOWN;
6675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
6775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten/* used to detect errors likely to have occured when the OpenMAX AL framework fails to open
6875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten * a resource, for instance because a file URI is invalid, or an HTTP server doesn't respond.
6975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten */
7075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten#define PREFETCHEVENT_ERROR_CANDIDATE \
7175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        (XA_PREFETCHEVENT_STATUSCHANGE | XA_PREFETCHEVENT_FILLLEVELCHANGE)
7275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
7375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten// stream event change callback
7475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kastenvoid streamEventChangeCallback(XAStreamInformationItf caller, XAuint32 eventId,
7575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        XAuint32 streamIndex, void *pEventData, void *pContext)
7675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten{
7775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // context parameter is specified as NULL and is unused here
7875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(NULL == pContext);
7975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    switch (eventId) {
8075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    case XA_STREAMCBEVENT_PROPERTYCHANGE:
8175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        printf("XA_STREAMCBEVENT_PROPERTYCHANGE on stream index %u, pEventData %p\n", streamIndex,
8275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten                pEventData);
8375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        break;
8475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    default:
8575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        printf("Unknown stream event ID %u\n", eventId);
8675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        break;
8775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
8875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten}
8975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
9075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten// prefetch status callback
9175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kastenvoid prefetchStatusCallback(XAPrefetchStatusItf caller,  void *pContext, XAuint32 event)
9275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten{
9375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // pContext is unused here, so we pass NULL
9475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(pContext == NULL);
9575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XApermille level = 0;
9675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XAresult result;
9775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*caller)->GetFillLevel(caller, &level);
9875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
9975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XAuint32 status;
10075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*caller)->GetPrefetchStatus(caller, &status);
10175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
10275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    if (event & XA_PREFETCHEVENT_FILLLEVELCHANGE) {
10375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        printf("PrefetchEventCallback: Buffer fill level is = %d\n", level);
10475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
10575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    if (event & XA_PREFETCHEVENT_STATUSCHANGE) {
10675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        printf("PrefetchEventCallback: Prefetch Status is = %u\n", status);
10775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
10875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XAuint32 new_prefetch_status;
10975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    if ((PREFETCHEVENT_ERROR_CANDIDATE == (event & PREFETCHEVENT_ERROR_CANDIDATE))
11075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            && (level == 0) && (status == XA_PREFETCHSTATUS_UNDERFLOW)) {
11175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        printf("PrefetchEventCallback: Error while prefetching data, exiting\n");
11275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        new_prefetch_status = PREFETCHSTATUS_ERROR;
11375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    } else if (event == XA_PREFETCHEVENT_STATUSCHANGE) {
11475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        new_prefetch_status = status;
11575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    } else {
11675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        return;
11775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
11875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    int ok;
11975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    ok = pthread_mutex_lock(&mutex);
12075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(ok == 0);
12175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    prefetch_status = new_prefetch_status;
12275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    ok = pthread_cond_signal(&cond);
12375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(ok == 0);
12475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    ok = pthread_mutex_unlock(&mutex);
12575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(ok == 0);
12675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten}
12775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
12875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten// playback event callback
12975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kastenvoid playEventCallback(XAPlayItf caller, void *pContext, XAuint32 event)
13075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten{
13175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // pContext is unused here, so we pass NULL
13275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(NULL == pContext);
13375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
134b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    XAresult result;
13575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XAmillisecond position;
136b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    result = (*caller)->GetPosition(caller, &position);
137b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
13875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
13975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    if (XA_PLAYEVENT_HEADATEND & event) {
140b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        printf("XA_PLAYEVENT_HEADATEND current position=%u ms\n", position);
14175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
14275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
14375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    if (XA_PLAYEVENT_HEADATNEWPOS & event) {
144b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        printf("XA_PLAYEVENT_HEADATNEWPOS current position=%u ms\n", position);
14575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
14675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
14775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    if (XA_PLAYEVENT_HEADATMARKER & event) {
148b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        printf("XA_PLAYEVENT_HEADATMARKER current position=%u ms\n", position);
14975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
15075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten}
15175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
15275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten// Android buffer queue callback
15375290ff394698c53f35a21612c03b8ddd21fecf9Glenn KastenXAresult bufferQueueCallback(
15475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        XAAndroidBufferQueueItf caller,
15575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        void *pCallbackContext,
15675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        void *pBufferContext,
15775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        void *pBufferData,
15875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        XAuint32 dataSize,
15975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        XAuint32 dataUsed,
16075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        const XAAndroidBufferItem *pItems,
16175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        XAuint32 itemsLength)
16275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten{
163b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    XAPlayItf playerPlay = (XAPlayItf) pCallbackContext;
16475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // enqueue the .ts data directly from mapped memory, so ignore the empty buffer pBufferData
165b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    if (curPacket <= lastPacket) {
16675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        static const XAAndroidBufferItem discontinuity = {XA_ANDROID_ITEMKEY_DISCONTINUITY, 0};
16775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        static const XAAndroidBufferItem eos = {XA_ANDROID_ITEMKEY_EOS, 0};
168b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        static const XAAndroidBufferItem formatChange = {XA_ANDROID_ITEMKEY_FORMAT_CHANGE, 0};
16975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        const XAAndroidBufferItem *items;
17075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        XAuint32 itemSize;
17175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        // compute number of packets to be enqueued in this buffer
172b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        XAuint32 packetsThisBuffer = lastPacket - curPacket;
17375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        if (packetsThisBuffer > PACKETS_PER_BUFFER) {
17475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            packetsThisBuffer = PACKETS_PER_BUFFER;
17575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        }
17675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        // last packet? this should only happen once
177b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        if (curPacket == lastPacket) {
178b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            if (sentEOS) {
179b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                printf("buffer completion callback after EOS\n");
180b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                return XA_RESULT_SUCCESS;
181b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            }
182b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("sending EOS\n");
18375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            items = &eos;
18475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            itemSize = sizeof(eos);
185b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            sentEOS = XA_BOOLEAN_TRUE;
18675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        // discontinuity requested?
18775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        } else if (curPacket == discPacket) {
188b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("sending discontinuity at packet %zu, then resuming at packet %zu\n", discPacket,
189b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                    afterDiscPacket);
19075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            items = &discontinuity;
19175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            itemSize = sizeof(discontinuity);
192b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            curPacket = afterDiscPacket;
193b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        // format change requested?
194b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        } else if (curPacket == formatPacket) {
195b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            printf("sending format change");
196b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            items = &formatChange;
197b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            itemSize = sizeof(formatChange);
19875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        // pure data with no items
19975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        } else {
20075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            items = NULL;
20175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            itemSize = 0;
20275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        }
20375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        XAresult result;
20475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        // enqueue the optional data and optional items; there is always at least one or the other
20575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        assert(packetsThisBuffer > 0 || itemSize > 0);
20675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        result = (*caller)->Enqueue(caller, NULL, &packets[curPacket],
20775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten                sizeof(MPEG2TS_Packet) * packetsThisBuffer, items, itemSize);
20875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        assert(XA_RESULT_SUCCESS == result);
20975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        curPacket += packetsThisBuffer;
210b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        // display position periodically
211b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        if (curPacket % 1000 == 0) {
212b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            XAmillisecond position;
213b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            result = (*playerPlay)->GetPosition(playerPlay, &position);
214b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            assert(XA_RESULT_SUCCESS == result);
21501f8573bc2a850536b02855d483dfe130c050a2fAshok Bhat            printf("Position after enqueueing packet %zu: %u ms\n", curPacket, position);
216b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        }
217b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    }
218b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    if (forceCallbackFailure && (curPacket % 1230 == 0)) {
219b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        return (XAresult) curPacket;
220b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    } else {
221b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        return XA_RESULT_SUCCESS;
222b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    }
223b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten}
224b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten
225b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten// convert a domain type to string
226b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kastenstatic const char *domainToString(XAuint32 domain)
227b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten{
228b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    switch (domain) {
229b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    case 0: // FIXME There's a private declaration '#define XA_DOMAINTYPE_CONTAINER 0' in src/data.h
230b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            // but we don't have access to it. Plan to file a bug with Khronos about this symbol.
231b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        return "media container";
232b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten#define _(x) case x: return #x;
233b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    _(XA_DOMAINTYPE_AUDIO)
234b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    _(XA_DOMAINTYPE_VIDEO)
235b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    _(XA_DOMAINTYPE_IMAGE)
236b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    _(XA_DOMAINTYPE_TIMEDTEXT)
237b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    _(XA_DOMAINTYPE_MIDI)
238b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    _(XA_DOMAINTYPE_VENDOR)
239b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    _(XA_DOMAINTYPE_UNKNOWN)
240b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten#undef _
241b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    default:
242b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        return "unknown";
24375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
24475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten}
24575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
24675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten// main program
24775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kastenint main(int argc, char **argv)
24875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten{
24975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    const char *prog = argv[0];
25075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    int i;
25175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
25275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XAboolean abq = XA_BOOLEAN_FALSE;   // use AndroidBufferQueue, default is URI
25375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XAboolean looping = XA_BOOLEAN_FALSE;
25475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    for (i = 1; i < argc; ++i) {
25575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        const char *arg = argv[i];
25675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        if (arg[0] != '-')
25775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            break;
25875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        switch (arg[1]) {
25975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        case 'a':
26075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            abq = XA_BOOLEAN_TRUE;
26175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            break;
262b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        case 'c':
263b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            forceCallbackFailure = XA_BOOLEAN_TRUE;
264b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            break;
26575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        case 'd':
26675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            discPacket = atoi(&arg[2]);
26775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            break;
268b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        case 'D':
269b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            afterDiscPacket = atoi(&arg[2]);
270b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            break;
271b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        case 'f':
272b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            firstPacket = atoi(&arg[2]);
273b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            break;
274b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        case 'F':
275b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            formatPacket = atoi(&arg[2]);
276b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            break;
27775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        case 'l':
27875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            looping = XA_BOOLEAN_TRUE;
27975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            break;
280b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        case 'n':
281b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            numPackets = atoi(&arg[2]);
282b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            break;
283b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        case 'p':
284b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            pauseMs = atoi(&arg[2]);
285b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            break;
286b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        case 's':
287b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            seekPos = atoi(&arg[2]);
28875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            break;
28975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        default:
29075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            fprintf(stderr, "%s: unknown option %s\n", prog, arg);
29175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            break;
29275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        }
29375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
29475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
29575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // check that exactly one URI was specified
29675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    if (argc - i != 1) {
297b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        fprintf(stderr, "usage: %s [-a] [-c] [-d#] [-D#] [-f#] [-F#] [-l] [-n#] [-p#] [-s#] uri\n",
298b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                prog);
299b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        fprintf(stderr, "    -a  Use Android buffer queue to supply data, default is URI\n");
300b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        fprintf(stderr, "    -c  Force callback to return an error randomly, for debugging only\n");
301b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        fprintf(stderr, "    -d# Packet index to insert a discontinuity, default is none\n");
302b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        fprintf(stderr, "    -D# Packet index to switch to after the discontinuity\n");
303b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        fprintf(stderr, "    -f# First packet index, defaults to 0\n");
304b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        fprintf(stderr, "    -F# Packet index to insert a format change, default is none\n");
305b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        fprintf(stderr, "    -l  Enable looping, for URI only\n");
306b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        fprintf(stderr, "    -n# Number of packets to enqueue\n");
307b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        fprintf(stderr, "    -p# Pause playback for 5 seconds after this many milliseconds\n");
308b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        fprintf(stderr, "    -s# Seek position in milliseconds, for URI only\n");
30975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        return EXIT_FAILURE;
31075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
31175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    const char *uri = argv[i];
31275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
31375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // for AndroidBufferQueue, interpret URI as a filename and open
31475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    int fd = -1;
31575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    if (abq) {
31675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        fd = open(uri, O_RDONLY);
31775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        if (fd < 0) {
31875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            perror(uri);
31975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            goto close;
32075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        }
32175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        int ok;
32275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        struct stat statbuf;
32375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        ok = fstat(fd, &statbuf);
32475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        if (ok < 0) {
32575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            perror(uri);
32675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            goto close;
32775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        }
32875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        if (!S_ISREG(statbuf.st_mode)) {
32975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            fprintf(stderr, "%s: not an ordinary file\n", uri);
33075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            goto close;
33175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        }
33275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        void *ptr;
33375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        ptr = mmap(NULL, statbuf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, (off_t) 0);
33475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        if (ptr == MAP_FAILED) {
33575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            perror(uri);
33675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            goto close;
33775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        }
33875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        size_t filelen = statbuf.st_size;
33975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        if ((filelen % MPEG2TS_PACKET_SIZE) != 0) {
34075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            fprintf(stderr, "%s: warning file length %zu is not a multiple of %d\n", uri, filelen,
34175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten                    MPEG2TS_PACKET_SIZE);
34275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        }
34375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        packets = (MPEG2TS_Packet *) ptr;
344b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        totalPackets = filelen / MPEG2TS_PACKET_SIZE;
345b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        printf("%s has %zu total packets\n", uri, totalPackets);
346b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        if (firstPacket >= totalPackets) {
347b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            fprintf(stderr, "-f%zu ignored\n", firstPacket);
348b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            firstPacket = 0;
349b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        }
350b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        if (numPackets == 0) {
351b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            numPackets = totalPackets - firstPacket;
352b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        } else if (firstPacket + numPackets > totalPackets) {
353b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            fprintf(stderr, "-n%zu ignored\n", numPackets);
354b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            numPackets = totalPackets - firstPacket;
355b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        }
356b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        lastPacket = firstPacket + numPackets;
357b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        if (discPacket != 0 && (discPacket < firstPacket || discPacket >= lastPacket)) {
358b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            fprintf(stderr, "-d%zu ignored\n", discPacket);
359b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            discPacket = 0;
360b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        }
361b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        if (afterDiscPacket < firstPacket || afterDiscPacket >= lastPacket) {
362b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            fprintf(stderr, "-D%zu ignored\n", afterDiscPacket);
363b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            afterDiscPacket = 0;
364b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        }
365b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        if (formatPacket != 0 && (formatPacket < firstPacket || formatPacket >= lastPacket)) {
366b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            fprintf(stderr, "-F%zu ignored\n", formatPacket);
367b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            formatPacket = 0;
368b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        }
36975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
37075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
37175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    ANativeWindow *nativeWindow;
37275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
37375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XAresult result;
37475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XAObjectItf engineObject;
37575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
37675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // create engine
37775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = xaCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
37875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
37975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*engineObject)->Realize(engineObject, XA_BOOLEAN_FALSE);
38075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
38175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XAEngineItf engineEngine;
38275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*engineObject)->GetInterface(engineObject, XA_IID_ENGINE, &engineEngine);
38375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
38475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
38575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // create output mix
38675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XAObjectItf outputMixObject;
38775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL);
38875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
38975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*outputMixObject)->Realize(outputMixObject, XA_BOOLEAN_FALSE);
39075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
39175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
39275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // configure media source
39375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XADataLocator_URI locUri;
39475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    locUri.locatorType = XA_DATALOCATOR_URI;
39575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    locUri.URI = (XAchar *) uri;
39675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XADataFormat_MIME fmtMime;
39775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    fmtMime.formatType = XA_DATAFORMAT_MIME;
39875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    if (abq) {
399c3b82a293ed06001ba6d50f111608160c6065ef2Glenn Kasten        fmtMime.mimeType = (XAchar *) XA_ANDROID_MIME_MP2TS;
40075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        fmtMime.containerType = XA_CONTAINERTYPE_MPEG_TS;
40175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    } else {
40275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        fmtMime.mimeType = NULL;
40375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        fmtMime.containerType = XA_CONTAINERTYPE_UNSPECIFIED;
40475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
40575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XADataLocator_AndroidBufferQueue locABQ;
40675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    locABQ.locatorType = XA_DATALOCATOR_ANDROIDBUFFERQUEUE;
40775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    locABQ.numBuffers = NB_BUFFERS;
40875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XADataSource dataSrc;
40975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    if (abq) {
41075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        dataSrc.pLocator = &locABQ;
41175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    } else {
41275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        dataSrc.pLocator = &locUri;
41375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
41475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    dataSrc.pFormat = &fmtMime;
41575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
41675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // configure audio sink
41775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XADataLocator_OutputMix locOM;
41875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    locOM.locatorType = XA_DATALOCATOR_OUTPUTMIX;
41975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    locOM.outputMix = outputMixObject;
42075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XADataSink audioSnk;
42175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    audioSnk.pLocator = &locOM;
42275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    audioSnk.pFormat = NULL;
42375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
42475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // configure video sink
42575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    nativeWindow = getNativeWindow();
42675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XADataLocator_NativeDisplay locND;
42775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    locND.locatorType = XA_DATALOCATOR_NATIVEDISPLAY;
42875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    locND.hWindow = nativeWindow;
42975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    locND.hDisplay = NULL;
43075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XADataSink imageVideoSink;
43175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    imageVideoSink.pLocator = &locND;
43275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    imageVideoSink.pFormat = NULL;
43375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
43475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // create media player
43575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XAObjectItf playerObject;
43675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XAInterfaceID ids[4] = {XA_IID_STREAMINFORMATION, XA_IID_PREFETCHSTATUS, XA_IID_SEEK,
43760ca9f9ef02f6e486c3338cb811f603dd7825c05Glenn Kasten            XA_IID_ANDROIDBUFFERQUEUESOURCE};
438b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    XAboolean req[4] = {XA_BOOLEAN_TRUE, XA_BOOLEAN_TRUE, XA_BOOLEAN_FALSE, XA_BOOLEAN_TRUE};
43975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*engineEngine)->CreateMediaPlayer(engineEngine, &playerObject, &dataSrc, NULL,
44075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            &audioSnk, nativeWindow != NULL ? &imageVideoSink : NULL, NULL, NULL, abq ? 4 : 3, ids,
44175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            req);
44275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
44375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
44475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // realize the player
44575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*playerObject)->Realize(playerObject, XA_BOOLEAN_FALSE);
44675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
44775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
448b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    // get the play interface
449b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    XAPlayItf playerPlay;
450b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    result = (*playerObject)->GetInterface(playerObject, XA_IID_PLAY, &playerPlay);
451b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
452b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten
45375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    if (abq) {
45475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
45575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        // get the Android buffer queue interface
45675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        XAAndroidBufferQueueItf playerAndroidBufferQueue;
45760ca9f9ef02f6e486c3338cb811f603dd7825c05Glenn Kasten        result = (*playerObject)->GetInterface(playerObject, XA_IID_ANDROIDBUFFERQUEUESOURCE,
45875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten                &playerAndroidBufferQueue);
45975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        assert(XA_RESULT_SUCCESS == result);
46075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
46175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        // register the buffer queue callback
46275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        result = (*playerAndroidBufferQueue)->RegisterCallback(playerAndroidBufferQueue,
463b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                bufferQueueCallback, (void *) playerPlay);
46475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        assert(XA_RESULT_SUCCESS == result);
46575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        result = (*playerAndroidBufferQueue)->SetCallbackEventsMask(playerAndroidBufferQueue,
46675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten                XA_ANDROIDBUFFERQUEUEEVENT_PROCESSED);
46775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        assert(XA_RESULT_SUCCESS == result);
46875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
469b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        // set the player's state to paused, to start prefetching
470b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        printf("start early prefetch\n");
471b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        result = (*playerPlay)->SetPlayState(playerPlay, XA_PLAYSTATE_PAUSED);
472b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        assert(XA_RESULT_SUCCESS == result);
473b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten
47475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        // enqueue the initial buffers until buffer queue is full
47575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        XAuint32 packetsThisBuffer;
476b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        for (curPacket = firstPacket; curPacket < lastPacket; curPacket += packetsThisBuffer) {
47775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            // handle the unlikely case of a very short .ts
478b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            packetsThisBuffer = lastPacket - curPacket;
47975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            if (packetsThisBuffer > PACKETS_PER_BUFFER) {
48075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten                packetsThisBuffer = PACKETS_PER_BUFFER;
48175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            }
48275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            result = (*playerAndroidBufferQueue)->Enqueue(playerAndroidBufferQueue, NULL,
48375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten                    &packets[curPacket], MPEG2TS_PACKET_SIZE * packetsThisBuffer, NULL, 0);
48475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            if (XA_RESULT_BUFFER_INSUFFICIENT == result) {
48501f8573bc2a850536b02855d483dfe130c050a2fAshok Bhat                printf("Enqueued initial %zu packets in %zu buffers\n", curPacket - firstPacket,
486b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                        (curPacket - firstPacket + PACKETS_PER_BUFFER - 1) / PACKETS_PER_BUFFER);
48775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten                break;
48875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            }
48975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            assert(XA_RESULT_SUCCESS == result);
49075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        }
49175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
49275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
49375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
49475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // get the stream information interface
49575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XAStreamInformationItf playerStreamInformation;
49675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*playerObject)->GetInterface(playerObject, XA_IID_STREAMINFORMATION,
49775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            &playerStreamInformation);
49875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
49975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
50075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // register the stream event change callback
50175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*playerStreamInformation)->RegisterStreamChangeCallback(playerStreamInformation,
50275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            streamEventChangeCallback, NULL);
50375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
50475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
50575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // get the prefetch status interface
50675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XAPrefetchStatusItf playerPrefetchStatus;
50775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*playerObject)->GetInterface(playerObject, XA_IID_PREFETCHSTATUS,
50875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            &playerPrefetchStatus);
50975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
51075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
51175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // register prefetch status callback
51275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*playerPrefetchStatus)->RegisterCallback(playerPrefetchStatus, prefetchStatusCallback,
51375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            NULL);
51475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
51575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*playerPrefetchStatus)->SetCallbackEventsMask(playerPrefetchStatus,
51675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            XA_PREFETCHEVENT_FILLLEVELCHANGE | XA_PREFETCHEVENT_STATUSCHANGE);
51775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
51875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
519b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    // get the seek interface for seeking and/or looping
520b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    if (looping || seekPos != XA_TIME_UNKNOWN) {
52175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        XASeekItf playerSeek;
52275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        result = (*playerObject)->GetInterface(playerObject, XA_IID_SEEK, &playerSeek);
52375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        assert(XA_RESULT_SUCCESS == result);
524b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        if (seekPos != XA_TIME_UNKNOWN) {
525b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            result = (*playerSeek)->SetPosition(playerSeek, seekPos, XA_SEEKMODE_ACCURATE);
526b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            if (XA_RESULT_FEATURE_UNSUPPORTED == result) {
527b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                fprintf(stderr, "-s%u (seek to initial position) is unsupported\n", seekPos);
528b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            } else {
529b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                assert(XA_RESULT_SUCCESS == result);
530b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            }
531b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        }
532b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        if (looping) {
533b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            result = (*playerSeek)->SetLoop(playerSeek, XA_BOOLEAN_TRUE, (XAmillisecond) 0,
534b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                    XA_TIME_UNKNOWN);
535b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            if (XA_RESULT_FEATURE_UNSUPPORTED) {
536b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                fprintf(stderr, "-l (looping) is unsupported\n");
537b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            } else {
538b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten                assert(XA_RESULT_SUCCESS == result);
539b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            }
540b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        }
54175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
54275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
54375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // register play event callback
54475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*playerPlay)->RegisterCallback(playerPlay, playEventCallback, NULL);
54575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
54675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*playerPlay)->SetCallbackEventsMask(playerPlay,
54775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten            XA_PLAYEVENT_HEADATEND | XA_PLAYEVENT_HEADATMARKER | XA_PLAYEVENT_HEADATNEWPOS);
54875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
54975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
55075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // set a marker
551b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    result = (*playerPlay)->SetMarkerPosition(playerPlay, 5000);
55275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
55375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
55475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // set position update period
555b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    result = (*playerPlay)->SetPositionUpdatePeriod(playerPlay, 2000);
55675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
55775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
558b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    // get the position before prefetch
559b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    XAmillisecond position;
560b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    result = (*playerPlay)->GetPosition(playerPlay, &position);
561b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
562b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    printf("Position before prefetch: %u ms\n", position);
563b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten
564b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    // get the duration before prefetch
56575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    XAmillisecond duration;
56675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*playerPlay)->GetDuration(playerPlay, &duration);
56775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
56875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    if (XA_TIME_UNKNOWN == duration)
569b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        printf("Duration before prefetch: unknown as expected\n");
57075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    else
571b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        printf("Duration before prefetch: %.1f (surprise!)\n", duration / 1000.0f);
57275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
57375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // set the player's state to paused, to start prefetching
57475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    printf("start prefetch\n");
57575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*playerPlay)->SetPlayState(playerPlay, XA_PLAYSTATE_PAUSED);
57675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
57775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
57875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    // wait for prefetch status callback to indicate either sufficient data or error
57975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    pthread_mutex_lock(&mutex);
58075290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    while (prefetch_status == PREFETCHSTATUS_UNKNOWN) {
58175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        pthread_cond_wait(&cond, &mutex);
58275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
58375290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    pthread_mutex_unlock(&mutex);
58475290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    if (prefetch_status == PREFETCHSTATUS_ERROR) {
58575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        fprintf(stderr, "Error during prefetch, exiting\n");
58675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten        goto destroyRes;
58775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
58875290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
589b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    // get the position after prefetch
590b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    result = (*playerPlay)->GetPosition(playerPlay, &position);
591b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
592b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    printf("Position after prefetch: %u ms\n", position);
593b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten
594b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    // get duration again, now it should be known for the file source or unknown for TS
59575290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    result = (*playerPlay)->GetDuration(playerPlay, &duration);
59675290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
59775290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    if (duration == XA_TIME_UNKNOWN) {
598b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        printf("Duration after prefetch: unknown (expected for TS, unexpected for file)\n");
59975290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    } else {
600b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten        printf("Duration after prefetch: %u ms (expected for file, unexpected for TS)\n", duration);
60175290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten    }
60275290ff394698c53f35a21612c03b8ddd21fecf9Glenn Kasten
603b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    // query for media container information
604b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    result = (*playerStreamInformation)->QueryMediaContainerInformation(playerStreamInformation,
605b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            NULL);
606b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    assert(XA_RESULT_PARAMETER_INVALID == result);
607b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    XAMediaContainerInformation mediaContainerInformation;
608b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    // this verifies it is filling in all the fields
609b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    memset(&mediaContainerInformation, 0x55, sizeof(XAMediaContainerInformation));
610b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    result = (*playerStreamInformation)->QueryMediaContainerInformation(playerStreamInformation,
611b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            &mediaContainerInformation);
612b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    assert(XA_RESULT_SUCCESS == result);
613b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    printf("Media container information:\n");
614b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    printf("  containerType = %u\n", mediaContainerInformation.containerType);
615b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    printf("  mediaDuration = %u\n", mediaContainerInformation.mediaDuration);
616b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    printf("  numStreams = %u\n", mediaContainerInformation.numStreams);
617b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten
618b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    // Now query for each the streams.  Note that stream indices go up to and including
619b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    // mediaContainerInformation.numStreams, because stream 0 is the container itself,
620b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    // while stream 1 to mediaContainerInformation.numStreams are the contained streams.
621b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten    XAuint32 numStreams = mediaContainerInformation.numStreams;
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);
809b17edb96ba759cd1197bf13cd13e279ee144da60Glenn Kasten            if (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