native-media-jni.c revision c3d6dd225415ac68b1868575e793eb352c7105e2
19a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten/*
29a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten * Copyright (C) 2010 The Android Open Source Project
39a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten *
49a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten * Licensed under the Apache License, Version 2.0 (the "License");
59a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten * you may not use this file except in compliance with the License.
69a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten * You may obtain a copy of the License at
79a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten *
89a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten *      http://www.apache.org/licenses/LICENSE-2.0
99a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten *
109a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten * Unless required by applicable law or agreed to in writing, software
119a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten * distributed under the License is distributed on an "AS IS" BASIS,
129a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten * See the License for the specific language governing permissions and
149a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten * limitations under the License.
159a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten */
169a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
179a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten#include <assert.h>
189a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten#include <jni.h>
199a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten#include <pthread.h>
209a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten#include <string.h>
2134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten//#define LOG_NDEBUG 0
229a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten#define LOG_TAG "NativeMedia"
239a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten#include <utils/Log.h>
24c09fe859aabccb8b18e6c857d087686b37d48c1fJean-Michel Trivi
25a6c5e52ded343b557152156c33d33a10d29bf6f1Glenn Kasten#include <OMXAL/OpenMAXAL.h>
26a6c5e52ded343b557152156c33d33a10d29bf6f1Glenn Kasten#include <OMXAL/OpenMAXAL_Android.h>
27c09fe859aabccb8b18e6c857d087686b37d48c1fJean-Michel Trivi
2873d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi#include <android/native_window_jni.h>
299a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
309a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// engine interfaces
319a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenstatic XAObjectItf engineObject = NULL;
3234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kastenstatic XAEngineItf engineEngine = NULL;
339a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
349a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// output mix interfaces
359a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenstatic XAObjectItf outputMixObject = NULL;
369a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
379a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// streaming media player interfaces
382f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivistatic XAObjectItf             playerObj = NULL;
392f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivistatic XAPlayItf               playerPlayItf = NULL;
402f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivistatic XAAndroidBufferQueueItf playerBQItf = NULL;
41fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivistatic XAStreamInformationItf  playerStreamInfoItf = NULL;
4234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kastenstatic XAVolumeItf             playerVolItf = NULL;
4334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten
44f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi// number of required interfaces for the MediaPlayer creation
45fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi#define NB_MAXAL_INTERFACES 3 // XAAndroidBufferQueueItf, XAStreamInformationItf and XAPlayItf
469a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
4749dfad6a8f91f0cce729f6db143f26c188caf523Glenn Kasten// video sink for the player
4873d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivistatic ANativeWindow* theNativeWindow;
499a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
5034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten// number of buffers in our buffer queue, an arbitrary number
51f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi#define NB_BUFFERS 16
5234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten
53f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi// we're streaming MPEG-2 transport stream data, operate on transport stream block size
54f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi#define MPEG2_TS_BLOCK_SIZE 188
5534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten
5634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten// number of MPEG-2 transport stream blocks per buffer, an arbitrary number
5734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten#define BLOCKS_PER_BUFFER 20
5834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten
59f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi// determines how much memory we're dedicating to memory caching
6034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten#define BUFFER_SIZE (BLOCKS_PER_BUFFER*MPEG2_TS_BLOCK_SIZE)
61f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi
62f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi// where we cache in memory the data to play
6334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten// note this memory is re-used by the buffer queue callback
64f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivichar dataCache[BUFFER_SIZE * NB_BUFFERS];
6534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten
662f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi// handle of the file to play
672f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel TriviFILE *file;
6834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten
695b21a0626e173d407aa3835e5cffcaa9b582016dJean-Michel Trivi// has the app reached the end of the file
7034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kastenjboolean reachedEof = JNI_FALSE;
7134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten
7234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten// for mutual exclusion between callback thread and application thread(s)
7334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kastenpthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
7434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kastenpthread_cond_t cond = PTHREAD_COND_INITIALIZER;
7534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten
7634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten// whether a discontinuity is in progress
7734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kastenjboolean discontinuity = JNI_FALSE;
7834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten
7934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kastenstatic jboolean enqueueInitialBuffers(jboolean discontinuity);
802f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
812f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi// AndroidBufferQueueItf callback for an audio player
822f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel TriviXAresult AndroidBufferQueueCallback(
832f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        XAAndroidBufferQueueItf caller,
84fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        void *pCallbackContext,        /* input */
85fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        void *pBufferContext,          /* input */
86fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        void *pBufferData,             /* input */
87f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi        XAuint32 dataSize,             /* input */
88f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi        XAuint32 dataUsed,             /* input */
89f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi        const XAAndroidBufferItem *pItems,/* input */
90f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi        XAuint32 itemsLength           /* input */)
912f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi{
9234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    XAresult res;
9334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    int ok;
9434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten
9534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    // pCallbackContext was specified as NULL at RegisterCallback and is unused here
9634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    assert(NULL == pCallbackContext);
9734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten
9834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    // note there is never any contention on this mutex unless a discontinuity request is active
9934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    ok = pthread_mutex_lock(&mutex);
10034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    assert(0 == ok);
10134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten
10234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    // was a discontinuity requested?
10334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    if (discontinuity) {
10434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        // FIXME sorry, can't rewind after EOS
10534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        if (!reachedEof) {
10634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten            // clear the buffer queue
10734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten            res = (*playerBQItf)->Clear(playerBQItf);
10834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten            assert(XA_RESULT_SUCCESS == res);
10934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten            // rewind the data source so we are guaranteed to be at an appropriate point
11034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten            rewind(file);
11134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten            // Enqueue the initial buffers, with a discontinuity indicator on first buffer
11234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten            (void) enqueueInitialBuffers(JNI_TRUE);
11334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        }
11434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        // acknowledge the discontinuity request
11534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        discontinuity = JNI_FALSE;
11634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        ok = pthread_cond_signal(&cond);
11734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        assert(0 == ok);
11834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        goto exit;
11934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    }
12034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten
121fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi    if (pBufferData == NULL) {
122fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        // this is the case when our buffer with the EOS message has been consumed
12334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        assert(0 == dataSize);
12434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        goto exit;
125fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi    }
126fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi
12734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    // pBufferData is a pointer to a buffer that we previously Enqueued
12834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    assert(BUFFER_SIZE == dataSize);
12934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    assert(dataCache <= (char *) pBufferData && (char *) pBufferData <
13034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten            &dataCache[BUFFER_SIZE * NB_BUFFERS]);
13134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    assert(0 == (((char *) pBufferData - dataCache) % BUFFER_SIZE));
13234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten
133fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi#if 0
134fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi    // sample code to use the XAVolumeItf
135fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi    XAAndroidBufferQueueState state;
136fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi    (*caller)->GetState(caller, &state);
137fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi    switch (state.index) {
138fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi    case 300:
139fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        (*playerVolItf)->SetVolumeLevel(playerVolItf, -600); // -6dB
140fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        LOGV("setting volume to -6dB");
141fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        break;
142fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi    case 400:
143fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        (*playerVolItf)->SetVolumeLevel(playerVolItf, -1200); // -12dB
144fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        LOGV("setting volume to -12dB");
145fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        break;
146fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi    case 500:
147fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        (*playerVolItf)->SetVolumeLevel(playerVolItf, 0); // full volume
148fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        LOGV("setting volume to 0dB (full volume)");
149fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        break;
150fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi    case 600:
151fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        (*playerVolItf)->SetMute(playerVolItf, XA_BOOLEAN_TRUE); // mute
152fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        LOGV("muting player");
153fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        break;
154fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi    case 700:
155fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        (*playerVolItf)->SetMute(playerVolItf, XA_BOOLEAN_FALSE); // unmute
156fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        LOGV("unmuting player");
157fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        break;
158fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi    case 800:
159fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        (*playerVolItf)->SetStereoPosition(playerVolItf, -1000);
160fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        (*playerVolItf)->EnableStereoPosition(playerVolItf, XA_BOOLEAN_TRUE);
161fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        LOGV("pan sound to the left (hard-left)");
162fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        break;
163fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi    case 900:
164fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        (*playerVolItf)->EnableStereoPosition(playerVolItf, XA_BOOLEAN_FALSE);
165fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        LOGV("disabling stereo position");
166fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        break;
167fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi    default:
168fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        break;
169fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi    }
170fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi#endif
171fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi
17234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    // don't bother trying to read more data once we've hit EOF
17334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    if (reachedEof) {
17434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        goto exit;
17534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    }
17634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten
17734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    size_t nbRead;
17834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    // note we do call fread from multiple threads, but never concurrently
17934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    nbRead = fread(pBufferData, BUFFER_SIZE, 1, file);
18034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    if (nbRead > 0) {
18134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        assert(1 == nbRead);
18234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        res = (*caller)->Enqueue(caller, NULL /*pBufferContext*/,
183f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi                pBufferData /*pData*/,
18434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten                nbRead * BUFFER_SIZE /*dataLength*/,
185f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi                NULL /*pMsg*/,
186f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi                0 /*msgLength*/);
18734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        assert(XA_RESULT_SUCCESS == res);
18834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    } else {
189f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi        // signal EOS
19034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        XAAndroidBufferItem msgEos[1];
19134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        msgEos[0].itemKey = XA_ANDROID_ITEMKEY_EOS;
19234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        msgEos[0].itemSize = 0;
193f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi        // EOS message has no parameters, so the total size of the message is the size of the key
194f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi        //   plus the size if itemSize, both XAuint32
19534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        res = (*caller)->Enqueue(caller, NULL /*pBufferContext*/,
196fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi                NULL /*pData*/, 0 /*dataLength*/,
19734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten                msgEos /*pMsg*/,
19834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten                // FIXME == sizeof(BufferItem)? */
199fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi                sizeof(XAuint32)*2 /*msgLength*/);
20034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        assert(XA_RESULT_SUCCESS == res);
20134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        reachedEof = JNI_TRUE;
2022f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    }
2032f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
20434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kastenexit:
20534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    ok = pthread_mutex_unlock(&mutex);
20634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    assert(0 == ok);
2072f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    return XA_RESULT_SUCCESS;
2082f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi}
2092f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
2102f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
211fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivivoid StreamChangeCallback (XAStreamInformationItf caller,
212fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        XAuint32 eventId,
213fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        XAuint32 streamIndex,
214fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        void * pEventData,
215fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        void * pContext )
216fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi{
21734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    LOGV("StreamChangeCallback called for stream %u", streamIndex);
21834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    // pContext was specified as NULL at RegisterStreamChangeCallback and is unused here
21934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    assert(NULL == pContext);
22034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    switch (eventId) {
22134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    case XA_STREAMCBEVENT_PROPERTYCHANGE: {
22234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        /** From spec 1.0.1:
22334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten            "This event indicates that stream property change has occurred.
22434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten            The streamIndex parameter identifies the stream with the property change.
22534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten            The pEventData parameter for this event is not used and shall be ignored."
22634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten         */
22734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten
22834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        XAresult res;
229fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        XAuint32 domain;
23034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        res = (*caller)->QueryStreamType(caller, streamIndex, &domain);
23134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        assert(XA_RESULT_SUCCESS == res);
23234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        switch (domain) {
23334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        case XA_DOMAINTYPE_VIDEO: {
23434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten            XAVideoStreamInformation videoInfo;
23534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten            res = (*caller)->QueryStreamInformation(caller, streamIndex, &videoInfo);
23634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten            assert(XA_RESULT_SUCCESS == res);
23734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten            LOGI("Found video size %u x %u, codec ID=%u, frameRate=%u, bitRate=%u, duration=%u ms",
23834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten                        videoInfo.width, videoInfo.height, videoInfo.codecId, videoInfo.frameRate,
23934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten                        videoInfo.bitRate, videoInfo.duration);
24034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        } break;
24134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        default:
24234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten            fprintf(stderr, "Unexpected domain %u\n", domain);
24334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten            break;
244fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi        }
24534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        } break;
24634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    default:
24734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        fprintf(stderr, "Unexpected stream event ID %u\n", eventId);
24834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        break;
249fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi    }
250fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi}
251fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi
252fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi
2539a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// create the engine and output mix objects
2549a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenvoid Java_com_example_nativemedia_NativeMedia_createEngine(JNIEnv* env, jclass clazz)
2559a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten{
2562f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    XAresult res;
2579a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
2589a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // create engine
2592f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = xaCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
2602f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
2619a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
2629a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // realize the engine
2632f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = (*engineObject)->Realize(engineObject, XA_BOOLEAN_FALSE);
2642f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
2659a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
2669a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // get the engine interface, which is needed in order to create other objects
2672f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = (*engineObject)->GetInterface(engineObject, XA_IID_ENGINE, &engineEngine);
2682f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
2699a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
2709a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // create output mix
2712f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL);
2722f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
2739a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
2749a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // realize the output mix
2752f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = (*outputMixObject)->Realize(outputMixObject, XA_BOOLEAN_FALSE);
2762f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
2779a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
2789a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten}
2799a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
2809a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
28134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten// Enqueue the initial buffers, and optionally signal a discontinuity in the first buffer
28234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kastenstatic jboolean enqueueInitialBuffers(jboolean discontinuity)
28334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten{
28434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten
28534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    /* Fill our cache */
28634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    size_t nbRead;
28734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    nbRead = fread(dataCache, BUFFER_SIZE, NB_BUFFERS, file);
28834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    if (nbRead <= 0) {
28934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        // could be premature EOF or I/O error
29034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        LOGE("Error filling cache, exiting\n");
29134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        return JNI_FALSE;
29234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    }
29334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    assert(1 <= nbRead && nbRead <= NB_BUFFERS);
29434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    LOGV("Initially queueing %u buffers of %u bytes each", nbRead, BUFFER_SIZE);
29534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten
29634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    /* Enqueue the content of our cache before starting to play,
29734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten       we don't want to starve the player */
29834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    size_t i;
29934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    for (i = 0; i < nbRead; i++) {
30034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        XAresult res;
30134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        if (discontinuity) {
30234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten            // signal discontinuity
30334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten            XAAndroidBufferItem items[1];
30434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten            items[0].itemKey = XA_ANDROID_ITEMKEY_DISCONTINUITY;
30534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten            items[0].itemSize = 0;
30634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten            // DISCONTINUITY message has no parameters,
30734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten            //   so the total size of the message is the size of the key
30834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten            //   plus the size if itemSize, both XAuint32
30934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten            res = (*playerBQItf)->Enqueue(playerBQItf, NULL /*pBufferContext*/,
31034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten                    dataCache + i*BUFFER_SIZE, BUFFER_SIZE, items /*pMsg*/,
31134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten                    // FIXME == sizeof(BufferItem)? */
31234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten                    sizeof(XAuint32)*2 /*msgLength*/);
31334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten            discontinuity = JNI_FALSE;
31434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        } else {
31534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten            res = (*playerBQItf)->Enqueue(playerBQItf, NULL /*pBufferContext*/,
31634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten                    dataCache + i*BUFFER_SIZE, BUFFER_SIZE, NULL, 0);
31734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        }
31834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        assert(XA_RESULT_SUCCESS == res);
31934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    }
32034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten
32134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    return JNI_TRUE;
32234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten}
32334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten
32434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten
3259a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// create streaming media player
3269a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenjboolean Java_com_example_nativemedia_NativeMedia_createStreamingMediaPlayer(JNIEnv* env,
3279a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten        jclass clazz, jstring filename)
3289a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten{
3292f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    XAresult res;
3309a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
3319a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // convert Java string to UTF-8
3329a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    const char *utf8 = (*env)->GetStringUTFChars(env, filename, NULL);
3339a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    assert(NULL != utf8);
3349a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
3352f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    // open the file to play
3362f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    file = fopen(utf8, "rb");
3372f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    if (file == NULL) {
3382f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        LOGE("Failed to open %s", utf8);
3392f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        return JNI_FALSE;
3402f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    }
3412f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
3422f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    // configure data source
343f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi    XADataLocator_AndroidBufferQueue loc_abq = { XA_DATALOCATOR_ANDROIDBUFFERQUEUE, NB_BUFFERS };
344f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi    XADataFormat_MIME format_mime = {
345f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi            XA_DATAFORMAT_MIME, (XAchar *)"video/mp2ts", XA_CONTAINERTYPE_MPEG_TS };
3462f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    XADataSource dataSrc = {&loc_abq, &format_mime};
3479a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
3489a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // configure audio sink
349f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi    XADataLocator_OutputMix loc_outmix = { XA_DATALOCATOR_OUTPUTMIX, outputMixObject };
350f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi    XADataSink audioSnk = { &loc_outmix, NULL };
3519a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
3529a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // configure image video sink
35373d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi    XADataLocator_NativeDisplay loc_nd = {
35413a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten            XA_DATALOCATOR_NATIVEDISPLAY,        // locatorType
35549dfad6a8f91f0cce729f6db143f26c188caf523Glenn Kasten            // the video sink must be an ANativeWindow created from a Surface or SurfaceTexture
35613a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten            (void*)theNativeWindow,              // hWindow
35713a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten            // must be NULL
35813a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten            NULL                                 // hDisplay
35913a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten    };
3609a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    XADataSink imageVideoSink = {&loc_nd, NULL};
3619a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
3622f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    // declare interfaces to use
363fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi    XAboolean     required[NB_MAXAL_INTERFACES]
364fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi                           = {XA_BOOLEAN_TRUE, XA_BOOLEAN_TRUE,           XA_BOOLEAN_TRUE};
365fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi    XAInterfaceID iidArray[NB_MAXAL_INTERFACES]
366c3d6dd225415ac68b1868575e793eb352c7105e2Glenn Kasten                           = {XA_IID_PLAY,     XA_IID_ANDROIDBUFFERQUEUESOURCE,
367c3d6dd225415ac68b1868575e793eb352c7105e2Glenn Kasten                                               XA_IID_STREAMINFORMATION};
368fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi
3692f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
3709a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // create media player
3712f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = (*engineEngine)->CreateMediaPlayer(engineEngine, &playerObj, &dataSrc,
3722f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi            NULL, &audioSnk, &imageVideoSink, NULL, NULL,
373f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi            NB_MAXAL_INTERFACES /*XAuint32 numInterfaces*/,
3742f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi            iidArray /*const XAInterfaceID *pInterfaceIds*/,
3752f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi            required /*const XAboolean *pInterfaceRequired*/);
3762f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
3779a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
3789a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // release the Java string and UTF-8
3799a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    (*env)->ReleaseStringUTFChars(env, filename, utf8);
3809a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
3819a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // realize the player
3822f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = (*playerObj)->Realize(playerObj, XA_BOOLEAN_FALSE);
3832f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
3849a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
3859a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // get the play interface
3862f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = (*playerObj)->GetInterface(playerObj, XA_IID_PLAY, &playerPlayItf);
3872f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
3882f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
389fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi    // get the stream information interface (for video size)
390fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi    res = (*playerObj)->GetInterface(playerObj, XA_IID_STREAMINFORMATION, &playerStreamInfoItf);
391fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
392fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi
393fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi    // get the volume interface
394fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi    res = (*playerObj)->GetInterface(playerObj, XA_IID_VOLUME, &playerVolItf);
395fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
396fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi
3972f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    // get the Android buffer queue interface
398c3d6dd225415ac68b1868575e793eb352c7105e2Glenn Kasten    res = (*playerObj)->GetInterface(playerObj, XA_IID_ANDROIDBUFFERQUEUESOURCE, &playerBQItf);
3992f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
4002f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
40134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    // specify which events we want to be notified of
40234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    res = (*playerBQItf)->SetCallbackEventsMask(playerBQItf, XA_ANDROIDBUFFERQUEUEEVENT_PROCESSED);
40334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten
4042f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    // register the callback from which OpenMAX AL can retrieve the data to play
405f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi    res = (*playerBQItf)->RegisterCallback(playerBQItf, AndroidBufferQueueCallback, NULL);
406fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
407fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi
408fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi    // we want to be notified of the video size once it's found, so we register a callback for that
409fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi    res = (*playerStreamInfoItf)->RegisterStreamChangeCallback(playerStreamInfoItf,
410fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi            StreamChangeCallback, NULL);
411f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi
41234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    // enqueue the initial buffers
41334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    if (!enqueueInitialBuffers(JNI_FALSE)) {
414f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi        return JNI_FALSE;
415f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi    }
416f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi
4172f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    // prepare the player
4182f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = (*playerPlayItf)->SetPlayState(playerPlayItf, XA_PLAYSTATE_PAUSED);
4192f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
4202f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
421fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi    // set the volume
422fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi    res = (*playerVolItf)->SetVolumeLevel(playerVolItf, 0);//-300);
423fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
424fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi
425fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi    // start the playback
4262f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = (*playerPlayItf)->SetPlayState(playerPlayItf, XA_PLAYSTATE_PLAYING);
4272f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        assert(XA_RESULT_SUCCESS == res);
4289a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
4299a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    return JNI_TRUE;
4309a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten}
4319a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
4329a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
4339a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// set the playing state for the streaming media player
4349a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenvoid Java_com_example_nativemedia_NativeMedia_setPlayingStreamingMediaPlayer(JNIEnv* env,
4359a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten        jclass clazz, jboolean isPlaying)
4369a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten{
4372f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    XAresult res;
4389a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
4399a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // make sure the streaming media player was created
4402f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    if (NULL != playerPlayItf) {
4419a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
4429a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten        // set the player's state
4432f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        res = (*playerPlayItf)->SetPlayState(playerPlayItf, isPlaying ?
4449a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten            XA_PLAYSTATE_PLAYING : XA_PLAYSTATE_PAUSED);
4452f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        assert(XA_RESULT_SUCCESS == res);
4469a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
4479a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    }
4489a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
4499a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten}
4509a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
4519a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
4529a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// shut down the native media system
4539a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenvoid Java_com_example_nativemedia_NativeMedia_shutdown(JNIEnv* env, jclass clazz)
4549a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten{
4559a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // destroy streaming media player object, and invalidate all associated interfaces
4562f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    if (playerObj != NULL) {
4572f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        (*playerObj)->Destroy(playerObj);
4582f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        playerObj = NULL;
4592f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        playerPlayItf = NULL;
4602f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        playerBQItf = NULL;
46134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        playerStreamInfoItf = NULL;
46234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        playerVolItf = NULL;
4639a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    }
4649a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
4659a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // destroy output mix object, and invalidate all associated interfaces
4669a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    if (outputMixObject != NULL) {
4679a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten        (*outputMixObject)->Destroy(outputMixObject);
4689a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten        outputMixObject = NULL;
4699a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    }
4709a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
4719a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // destroy engine object, and invalidate all associated interfaces
4729a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    if (engineObject != NULL) {
4739a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten        (*engineObject)->Destroy(engineObject);
4749a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten        engineObject = NULL;
4759a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten        engineEngine = NULL;
4769a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    }
4779a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
4782f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    // close the file
4792f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    if (file != NULL) {
4802f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        fclose(file);
4812a1042f54c8e61a0c2a062709367093100ea6f8fGlenn Kasten        file = NULL;
4822f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    }
48373d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi
48473d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi    // make sure we don't leak native windows
48513a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten    if (theNativeWindow != NULL) {
48613a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten        ANativeWindow_release(theNativeWindow);
4872a1042f54c8e61a0c2a062709367093100ea6f8fGlenn Kasten        theNativeWindow = NULL;
48813a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten    }
4899a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten}
4909a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
4919a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
4929a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// set the surface
4939a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenvoid Java_com_example_nativemedia_NativeMedia_setSurface(JNIEnv *env, jclass clazz, jobject surface)
4949a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten{
49573d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi    // obtain a native window from a Java surface
49673d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi    theNativeWindow = ANativeWindow_fromSurface(env, surface);
49713a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten}
49813a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten
49913a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten
50013a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten// set the surface texture
50113a07de046bce3663b905a892dbaf770a54d982dGlenn Kastenvoid Java_com_example_nativemedia_NativeMedia_setSurfaceTexture(JNIEnv *env, jclass clazz,
50213a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten        jobject surfaceTexture)
50313a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten{
50413a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten    // obtain a native window from a Java surface texture
50513a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten    theNativeWindow = ANativeWindow_fromSurfaceTexture(env, surfaceTexture);
5069a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten}
50734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten
50834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten
50934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten// rewind the streaming media player
51034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kastenvoid Java_com_example_nativemedia_NativeMedia_rewindStreamingMediaPlayer(JNIEnv *env, jclass clazz)
51134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten{
51234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    XAresult res;
51334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten
51434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    // make sure the streaming media player was created
51534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    if (NULL != playerBQItf && NULL != file) {
51634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        // first wait for buffers currently in queue to be drained
51734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        int ok;
51834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        ok = pthread_mutex_lock(&mutex);
51934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        assert(0 == ok);
52034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        discontinuity = JNI_TRUE;
52134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        // wait for discontinuity request to be observed by buffer queue callback
52234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        // FIXME sorry, can't rewind after EOS
52334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        while (discontinuity && !reachedEof) {
52434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten            ok = pthread_cond_wait(&cond, &mutex);
52534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten            assert(0 == ok);
52634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        }
52734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        ok = pthread_mutex_unlock(&mutex);
52834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten        assert(0 == ok);
52934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten    }
53034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten
53134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten}
532