native-media-jni.c revision 5b21a0626e173d407aa3835e5cffcaa9b582016d
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>
219a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten#define LOG_TAG "NativeMedia"
229a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten#include <utils/Log.h>
23c09fe859aabccb8b18e6c857d087686b37d48c1fJean-Michel Trivi
249a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten#include "OMXAL/OpenMAXAL.h"
252f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi#include "OMXAL/OpenMAXAL_Android.h"
26c09fe859aabccb8b18e6c857d087686b37d48c1fJean-Michel Trivi
2773d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi#include <android/native_window_jni.h>
289a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
2913a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten// define as 1 if ANativeWindow * is not supported as a video sink
3013a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten#define NO_NATIVE_WINDOW 1
3113a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten
329a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// engine interfaces
339a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenstatic XAObjectItf engineObject = NULL;
349a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenstatic XAEngineItf engineEngine;
359a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
369a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// output mix interfaces
379a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenstatic XAObjectItf outputMixObject = NULL;
389a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
399a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// streaming media player interfaces
402f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivistatic XAObjectItf             playerObj = NULL;
412f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivistatic XAPlayItf               playerPlayItf = NULL;
422f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivistatic XAAndroidBufferQueueItf playerBQItf = NULL;
43f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi// number of required interfaces for the MediaPlayer creation
44f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi#define NB_MAXAL_INTERFACES 2 // XAAndroidBufferQueueItf and XAPlayItf
459a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
4673d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi// cached surface where the video display happens
4713a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten#if NO_NATIVE_WINDOW
4813a07de046bce3663b905a892dbaf770a54d982dGlenn Kastenstatic jobject theSurfaceOrSurfaceTexture;
4913a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten#else
5073d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivistatic ANativeWindow* theNativeWindow;
5113a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten#endif
529a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
53f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi// number of buffers in our buffer queue
54f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi#define NB_BUFFERS 16
55f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi// we're streaming MPEG-2 transport stream data, operate on transport stream block size
56f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi#define MPEG2_TS_BLOCK_SIZE 188
57f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi// determines how much memory we're dedicating to memory caching
58f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi#define BUFFER_SIZE 20*MPEG2_TS_BLOCK_SIZE // 20 is an arbitrary number chosen here
59f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi
60f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi// where we cache in memory the data to play
61f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivichar dataCache[BUFFER_SIZE * NB_BUFFERS];
622f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi// handle of the file to play
632f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel TriviFILE *file;
645b21a0626e173d407aa3835e5cffcaa9b582016dJean-Michel Trivi// has the app reached the end of the file
655b21a0626e173d407aa3835e5cffcaa9b582016dJean-Michel Trivichar reachedEof = 0;
662f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
672f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi// AndroidBufferQueueItf callback for an audio player
682f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel TriviXAresult AndroidBufferQueueCallback(
692f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        XAAndroidBufferQueueItf caller,
70f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi        void *pContext,                /* input */
71f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi        const void *pBufferData,       /* input */
72f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi        XAuint32 dataSize,             /* input */
73f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi        XAuint32 dataUsed,             /* input */
74f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi        const XAAndroidBufferItem *pItems,/* input */
75f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi        XAuint32 itemsLength           /* input */)
762f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi{
77f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi    // assert(BUFFER_SIZE <= dataSize);
78f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi    size_t nbRead = fread((void*)pBufferData, 1, BUFFER_SIZE, file);
79f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi    if (nbRead > 0) {
80f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi        (*caller)->Enqueue(caller,
81f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi                pBufferData /*pData*/,
82f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi                nbRead /*dataLength*/,
83f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi                NULL /*pMsg*/,
84f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi                0 /*msgLength*/);
855b21a0626e173d407aa3835e5cffcaa9b582016dJean-Michel Trivi    } else if (!reachedEof) {
86f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi        // signal EOS
87f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi        XAAndroidBufferItem msgEos;
88f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi        msgEos.itemKey = XA_ANDROID_ITEMKEY_EOS;
89f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi        msgEos.itemSize = 0;
90f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi        // EOS message has no parameters, so the total size of the message is the size of the key
91f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi        //   plus the size if itemSize, both XAuint32
92f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi        (*caller)->Enqueue(caller, NULL /*pData*/, 0 /*dataLength*/,
93f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi                        &msgEos /*pMsg*/,
94f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi                        sizeof(XAuint32)*2 /*msgLength*/);
955b21a0626e173d407aa3835e5cffcaa9b582016dJean-Michel Trivi        reachedEof = 1;
962f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    }
972f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
982f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    return XA_RESULT_SUCCESS;
992f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi}
1002f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
1012f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
1029a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// create the engine and output mix objects
1039a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenvoid Java_com_example_nativemedia_NativeMedia_createEngine(JNIEnv* env, jclass clazz)
1049a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten{
1052f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    XAresult res;
1069a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1079a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // create engine
1082f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = xaCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
1092f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
1109a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1119a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // realize the engine
1122f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = (*engineObject)->Realize(engineObject, XA_BOOLEAN_FALSE);
1132f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
1149a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1159a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // get the engine interface, which is needed in order to create other objects
1162f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = (*engineObject)->GetInterface(engineObject, XA_IID_ENGINE, &engineEngine);
1172f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
1189a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1199a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // create output mix
1202f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL);
1212f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
1229a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1239a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // realize the output mix
1242f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = (*outputMixObject)->Realize(outputMixObject, XA_BOOLEAN_FALSE);
1252f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
1269a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1279a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten}
1289a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1299a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1309a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// create streaming media player
1319a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenjboolean Java_com_example_nativemedia_NativeMedia_createStreamingMediaPlayer(JNIEnv* env,
1329a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten        jclass clazz, jstring filename)
1339a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten{
1342f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    XAresult res;
1359a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1369a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // convert Java string to UTF-8
1379a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    const char *utf8 = (*env)->GetStringUTFChars(env, filename, NULL);
1389a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    assert(NULL != utf8);
1399a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1402f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    // open the file to play
1412f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    file = fopen(utf8, "rb");
1422f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    if (file == NULL) {
1432f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        LOGE("Failed to open %s", utf8);
1442f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        return JNI_FALSE;
1452f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    }
1462f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
1472f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    // configure data source
148f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi    XADataLocator_AndroidBufferQueue loc_abq = { XA_DATALOCATOR_ANDROIDBUFFERQUEUE, NB_BUFFERS };
149f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi    XADataFormat_MIME format_mime = {
150f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi            XA_DATAFORMAT_MIME, (XAchar *)"video/mp2ts", XA_CONTAINERTYPE_MPEG_TS };
1512f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    XADataSource dataSrc = {&loc_abq, &format_mime};
1529a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1539a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // configure audio sink
154f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi    XADataLocator_OutputMix loc_outmix = { XA_DATALOCATOR_OUTPUTMIX, outputMixObject };
155f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi    XADataSink audioSnk = { &loc_outmix, NULL };
1569a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1579a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // configure image video sink
15873d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi    XADataLocator_NativeDisplay loc_nd = {
15913a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten            XA_DATALOCATOR_NATIVEDISPLAY,        // locatorType
16013a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten#if NO_NATIVE_WINDOW
16113a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten            (void *) theSurfaceOrSurfaceTexture, // jobject
16213a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten            (void *) env                         // JNIEnv *env
16313a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten#else
16413a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten            // later the video sink can be an ANativeWindow created from a Surface or SurfaceTexture
16513a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten            (void*)theNativeWindow,              // hWindow
16613a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten            // must be NULL
16713a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten            NULL                                 // hDisplay
16813a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten#endif
16913a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten    };
1709a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    XADataSink imageVideoSink = {&loc_nd, NULL};
1719a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1722f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    // declare interfaces to use
173f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi    XAboolean     required[NB_MAXAL_INTERFACES] = {XA_BOOLEAN_TRUE, XA_BOOLEAN_TRUE};
174f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi    XAInterfaceID iidArray[NB_MAXAL_INTERFACES] = {XA_IID_PLAY,     XA_IID_ANDROIDBUFFERQUEUE};
1752f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
1769a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // create media player
1772f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = (*engineEngine)->CreateMediaPlayer(engineEngine, &playerObj, &dataSrc,
1782f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi            NULL, &audioSnk, &imageVideoSink, NULL, NULL,
179f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi            NB_MAXAL_INTERFACES /*XAuint32 numInterfaces*/,
1802f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi            iidArray /*const XAInterfaceID *pInterfaceIds*/,
1812f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi            required /*const XAboolean *pInterfaceRequired*/);
1822f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
1839a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1849a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // release the Java string and UTF-8
1859a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    (*env)->ReleaseStringUTFChars(env, filename, utf8);
1869a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1879a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // realize the player
1882f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = (*playerObj)->Realize(playerObj, XA_BOOLEAN_FALSE);
1892f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
1909a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1919a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // get the play interface
1922f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = (*playerObj)->GetInterface(playerObj, XA_IID_PLAY, &playerPlayItf);
1932f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
1942f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
1952f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    // get the Android buffer queue interface
1962f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = (*playerObj)->GetInterface(playerObj, XA_IID_ANDROIDBUFFERQUEUE, &playerBQItf);
1972f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
1982f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
1992f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    // register the callback from which OpenMAX AL can retrieve the data to play
200f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi    res = (*playerBQItf)->RegisterCallback(playerBQItf, AndroidBufferQueueCallback, NULL);
201f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi
202f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi    /* Fill our cache */
203f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi    if (fread(dataCache, 1, BUFFER_SIZE * NB_BUFFERS, file) <= 0) {
204f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi        LOGE("Error filling cache, exiting\n");
205f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi        return JNI_FALSE;
206f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi    }
207f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi    /* Enqueue the content of our cache before starting to play,
208f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi       we don't want to starve the player */
209f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi    int i;
210f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi    for (i=0 ; i < NB_BUFFERS ; i++) {
211f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi        res = (*playerBQItf)->Enqueue(playerBQItf, dataCache + i*BUFFER_SIZE, BUFFER_SIZE, NULL, 0);
212f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi        assert(XA_RESULT_SUCCESS == res);
213f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi    }
214f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi
2152f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
2162f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    // prepare the player
2172f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = (*playerPlayItf)->SetPlayState(playerPlayItf, XA_PLAYSTATE_PAUSED);
2182f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
2192f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
2202f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = (*playerPlayItf)->SetPlayState(playerPlayItf, XA_PLAYSTATE_PLAYING);
2212f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        assert(XA_RESULT_SUCCESS == res);
2229a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
2239a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    return JNI_TRUE;
2249a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten}
2259a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
2269a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
2279a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// set the playing state for the streaming media player
2289a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenvoid Java_com_example_nativemedia_NativeMedia_setPlayingStreamingMediaPlayer(JNIEnv* env,
2299a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten        jclass clazz, jboolean isPlaying)
2309a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten{
2312f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    XAresult res;
2329a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
2339a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // make sure the streaming media player was created
2342f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    if (NULL != playerPlayItf) {
2359a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
2369a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten        // set the player's state
2372f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        res = (*playerPlayItf)->SetPlayState(playerPlayItf, isPlaying ?
2389a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten            XA_PLAYSTATE_PLAYING : XA_PLAYSTATE_PAUSED);
2392f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        assert(XA_RESULT_SUCCESS == res);
2409a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
2419a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    }
2429a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
2439a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten}
2449a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
2459a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
2469a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// shut down the native media system
2479a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenvoid Java_com_example_nativemedia_NativeMedia_shutdown(JNIEnv* env, jclass clazz)
2489a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten{
2499a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // destroy streaming media player object, and invalidate all associated interfaces
2502f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    if (playerObj != NULL) {
2512f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        (*playerObj)->Destroy(playerObj);
2522f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        playerObj = NULL;
2532f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        playerPlayItf = NULL;
2542f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        playerBQItf = NULL;
2559a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    }
2569a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
2579a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // destroy output mix object, and invalidate all associated interfaces
2589a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    if (outputMixObject != NULL) {
2599a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten        (*outputMixObject)->Destroy(outputMixObject);
2609a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten        outputMixObject = NULL;
2619a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    }
2629a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
2639a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // destroy engine object, and invalidate all associated interfaces
2649a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    if (engineObject != NULL) {
2659a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten        (*engineObject)->Destroy(engineObject);
2669a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten        engineObject = NULL;
2679a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten        engineEngine = NULL;
2689a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    }
2699a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
2702f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    // close the file
2712f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    if (file != NULL) {
2722f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        fclose(file);
2732f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    }
27473d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi
27513a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten#if !NO_NATIVE_WINDOW
27673d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi    // make sure we don't leak native windows
27713a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten    if (theNativeWindow != NULL) {
27813a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten        ANativeWindow_release(theNativeWindow);
27913a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten    }
28013a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten#endif
2819a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten}
2829a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
2839a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
2849a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// set the surface
2859a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenvoid Java_com_example_nativemedia_NativeMedia_setSurface(JNIEnv *env, jclass clazz, jobject surface)
2869a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten{
28713a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten#if NO_NATIVE_WINDOW
28813a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten    theSurfaceOrSurfaceTexture = surface;
28913a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten#else
29073d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi    // obtain a native window from a Java surface
29173d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi    theNativeWindow = ANativeWindow_fromSurface(env, surface);
29213a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten#endif
29313a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten}
29413a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten
29513a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten
29613a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten// set the surface texture
29713a07de046bce3663b905a892dbaf770a54d982dGlenn Kastenvoid Java_com_example_nativemedia_NativeMedia_setSurfaceTexture(JNIEnv *env, jclass clazz,
29813a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten        jobject surfaceTexture)
29913a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten{
30013a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten#if NO_NATIVE_WINDOW
30113a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten    theSurfaceOrSurfaceTexture = surfaceTexture;
30213a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten#else
30313a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten    // obtain a native window from a Java surface texture
30413a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten    theNativeWindow = ANativeWindow_fromSurfaceTexture(env, surfaceTexture);
30513a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten#endif
3069a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten}
307