native-media-jni.c revision 73d888bb7b15745c6456dc0fab97c39854827d2a
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>
232f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi//FIXME shouldn't be needed here, but needed for declaration of XA_IID_ANDROIDBUFFERQUEUE
242f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi#include "SLES/OpenSLES.h"
252f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi#include "SLES/OpenSLES_Android.h"
269a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten#include "OMXAL/OpenMAXAL.h"
272f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi#include "OMXAL/OpenMAXAL_Android.h"
2873d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi#include <android/native_window_jni.h>
299a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
309a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// engine interfaces
319a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenstatic XAObjectItf engineObject = NULL;
329a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenstatic XAEngineItf engineEngine;
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;
419a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
4273d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi// cached surface where the video display happens
4373d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivistatic ANativeWindow* theNativeWindow;
449a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
452f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi// handle of the file to play
462f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel TriviFILE *file;
472f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
482f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi// AndroidBufferQueueItf callback for an audio player
492f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel TriviXAresult AndroidBufferQueueCallback(
502f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        XAAndroidBufferQueueItf caller,
512f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        void *pContext,
522f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        XAuint32 bufferId,
532f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        XAuint32 bufferLength,
542f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        void *pBufferDataLocation)
552f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
562f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi{
572f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    size_t nbRead = fread(pBufferDataLocation, 1, bufferLength, file);
582f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
592f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    XAAbufferQueueEvent event = XA_ANDROIDBUFFERQUEUE_EVENT_NONE;
602f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    if (nbRead <= 0) {
612f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        event = XA_ANDROIDBUFFERQUEUE_EVENT_EOS;
622f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    } else {
632f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        event = XA_ANDROIDBUFFERQUEUE_EVENT_NONE; // no event to report
642f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    }
652f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
662f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    // enqueue the data right-away because in this example we're reading from a file, so we
672f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    // can afford to do that. When streaming from the network, we would write from our cache
682f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    // to this queue.
692f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    // last param is NULL because we've already written the data in the buffer queue
702f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    (*caller)->Enqueue(caller, bufferId, nbRead, event, NULL);
712f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
722f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    return XA_RESULT_SUCCESS;
732f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi}
742f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
752f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
769a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// create the engine and output mix objects
779a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenvoid Java_com_example_nativemedia_NativeMedia_createEngine(JNIEnv* env, jclass clazz)
789a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten{
792f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    XAresult res;
809a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
819a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // create engine
822f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = xaCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
832f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
849a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
859a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // realize the engine
862f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = (*engineObject)->Realize(engineObject, XA_BOOLEAN_FALSE);
872f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
889a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
899a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // get the engine interface, which is needed in order to create other objects
902f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = (*engineObject)->GetInterface(engineObject, XA_IID_ENGINE, &engineEngine);
912f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
929a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
939a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // create output mix
942f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL);
952f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
969a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
979a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // realize the output mix
982f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = (*outputMixObject)->Realize(outputMixObject, XA_BOOLEAN_FALSE);
992f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
1009a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1019a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten}
1029a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1039a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1049a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// create streaming media player
1059a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenjboolean Java_com_example_nativemedia_NativeMedia_createStreamingMediaPlayer(JNIEnv* env,
1069a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten        jclass clazz, jstring filename)
1079a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten{
1082f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    XAresult res;
1099a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1109a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // convert Java string to UTF-8
1119a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    const char *utf8 = (*env)->GetStringUTFChars(env, filename, NULL);
1129a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    assert(NULL != utf8);
1139a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1142f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    // open the file to play
1152f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    file = fopen(utf8, "rb");
1162f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    if (file == NULL) {
1172f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        LOGE("Failed to open %s", utf8);
1182f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        return JNI_FALSE;
1192f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    }
1202f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
1212f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    // configure data source
1227f0e925e1a56ab80e60f2381105297184109dbc3Jean-Michel Trivi    XADataLocator_AndroidBufferQueue loc_abq = {XA_DATALOCATOR_ANDROIDBUFFERQUEUE,
1237f0e925e1a56ab80e60f2381105297184109dbc3Jean-Michel Trivi            0, 0 /* number of buffers and size of queue are ignored for now, subject to change */};
1249a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    XADataFormat_MIME format_mime = {XA_DATAFORMAT_MIME, NULL, XA_CONTAINERTYPE_UNSPECIFIED};
1252f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    XADataSource dataSrc = {&loc_abq, &format_mime};
1269a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1279a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // configure audio sink
1289a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    XADataLocator_OutputMix loc_outmix = {XA_DATALOCATOR_OUTPUTMIX, outputMixObject};
1299a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    XADataSink audioSnk = {&loc_outmix, NULL};
1309a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1319a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // configure image video sink
13273d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi    XADataLocator_NativeDisplay loc_nd = {
13373d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi            XA_DATALOCATOR_NATIVEDISPLAY /* locatorType */,
13473d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi            // currently the video sink only works on ANativeWindow created from a Surface
13573d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi            (void*)theNativeWindow       /* hWindow */,
13673d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi            // ignored here
13773d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi            0                            /* hDisplay */};
1389a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    XADataSink imageVideoSink = {&loc_nd, NULL};
1399a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1402f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    // declare interfaces to use
1412f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    XAboolean     required[2] = {XA_BOOLEAN_TRUE, XA_BOOLEAN_TRUE};
1422f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    XAInterfaceID iidArray[2] = {XA_IID_PLAY,     XA_IID_ANDROIDBUFFERQUEUE};
1432f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
1449a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // create media player
1452f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = (*engineEngine)->CreateMediaPlayer(engineEngine, &playerObj, &dataSrc,
1462f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi            NULL, &audioSnk, &imageVideoSink, NULL, NULL,
14773d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi            2        /*XAuint32 numInterfaces*/,
1482f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi            iidArray /*const XAInterfaceID *pInterfaceIds*/,
1492f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi            required /*const XAboolean *pInterfaceRequired*/);
1502f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
1519a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1529a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // release the Java string and UTF-8
1539a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    (*env)->ReleaseStringUTFChars(env, filename, utf8);
1549a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1559a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // realize the player
1562f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = (*playerObj)->Realize(playerObj, XA_BOOLEAN_FALSE);
1572f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
1589a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1599a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // get the play interface
1602f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = (*playerObj)->GetInterface(playerObj, XA_IID_PLAY, &playerPlayItf);
1612f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
1622f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
1632f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    // get the Android buffer queue interface
1642f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = (*playerObj)->GetInterface(playerObj, XA_IID_ANDROIDBUFFERQUEUE, &playerBQItf);
1652f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
1662f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
1672f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    // register the callback from which OpenMAX AL can retrieve the data to play
1682f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = (*playerBQItf)->RegisterCallback(playerBQItf, AndroidBufferQueueCallback, &playerBQItf);
1692f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
1702f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    // prepare the player
1712f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = (*playerPlayItf)->SetPlayState(playerPlayItf, XA_PLAYSTATE_PAUSED);
1722f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
1732f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi
1742f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    res = (*playerPlayItf)->SetPlayState(playerPlayItf, XA_PLAYSTATE_PLAYING);
1752f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        assert(XA_RESULT_SUCCESS == res);
1769a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1779a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    return JNI_TRUE;
1789a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten}
1799a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1809a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1819a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// set the playing state for the streaming media player
1829a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenvoid Java_com_example_nativemedia_NativeMedia_setPlayingStreamingMediaPlayer(JNIEnv* env,
1839a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten        jclass clazz, jboolean isPlaying)
1849a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten{
1852f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    XAresult res;
1869a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1879a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // make sure the streaming media player was created
1882f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    if (NULL != playerPlayItf) {
1899a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1909a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten        // set the player's state
1912f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        res = (*playerPlayItf)->SetPlayState(playerPlayItf, isPlaying ?
1929a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten            XA_PLAYSTATE_PLAYING : XA_PLAYSTATE_PAUSED);
1932f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        assert(XA_RESULT_SUCCESS == res);
1949a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1959a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    }
1969a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1979a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten}
1989a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
1999a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
2009a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// shut down the native media system
2019a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenvoid Java_com_example_nativemedia_NativeMedia_shutdown(JNIEnv* env, jclass clazz)
2029a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten{
2039a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // destroy streaming media player object, and invalidate all associated interfaces
2042f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    if (playerObj != NULL) {
2052f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        (*playerObj)->Destroy(playerObj);
2062f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        playerObj = NULL;
2072f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        playerPlayItf = NULL;
2082f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        playerBQItf = NULL;
2099a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    }
2109a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
2119a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // destroy output mix object, and invalidate all associated interfaces
2129a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    if (outputMixObject != NULL) {
2139a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten        (*outputMixObject)->Destroy(outputMixObject);
2149a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten        outputMixObject = NULL;
2159a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    }
2169a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
2179a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    // destroy engine object, and invalidate all associated interfaces
2189a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    if (engineObject != NULL) {
2199a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten        (*engineObject)->Destroy(engineObject);
2209a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten        engineObject = NULL;
2219a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten        engineEngine = NULL;
2229a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten    }
2239a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
2242f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    // close the file
2252f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    if (file != NULL) {
2262f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi        fclose(file);
2272f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi    }
22873d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi
22973d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi    // make sure we don't leak native windows
23073d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi    ANativeWindow_release(theNativeWindow);
2319a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten}
2329a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
2339a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten
2349a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// set the surface
2359a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenvoid Java_com_example_nativemedia_NativeMedia_setSurface(JNIEnv *env, jclass clazz, jobject surface)
2369a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten{
23773d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi    // obtain a native window from a Java surface
23873d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi    theNativeWindow = ANativeWindow_fromSurface(env, surface);
2399a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten}
240