native-media-jni.c revision 70c49ae2867094072a4365423417ea452bf82231
197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten/*
297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten * Copyright (C) 2010 The Android Open Source Project
397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten *
497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten * Licensed under the Apache License, Version 2.0 (the "License");
597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten * you may not use this file except in compliance with the License.
697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten * You may obtain a copy of the License at
797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten *
897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten *      http://www.apache.org/licenses/LICENSE-2.0
997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten *
1097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten * Unless required by applicable law or agreed to in writing, software
1197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten * distributed under the License is distributed on an "AS IS" BASIS,
1297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten * See the License for the specific language governing permissions and
1497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten * limitations under the License.
1597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten */
1697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
1797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten#include <assert.h>
1897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten#include <jni.h>
1997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten#include <pthread.h>
2097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten#include <string.h>
2197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten#define LOG_TAG "NativeMedia"
2297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten#include <utils/Log.h>
23f183d0fd23f1c0f45ceaf280d404f1b0709a699aJean-Michel Trivi
2497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten#include "OMXAL/OpenMAXAL.h"
25eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi#include "OMXAL/OpenMAXAL_Android.h"
26f183d0fd23f1c0f45ceaf280d404f1b0709a699aJean-Michel Trivi
27295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivi#include <android/native_window_jni.h>
2897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
29ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten// define as 1 if ANativeWindow * is not supported as a video sink
30ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten#define NO_NATIVE_WINDOW 1
31ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten
3297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// engine interfaces
3397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenstatic XAObjectItf engineObject = NULL;
3497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenstatic XAEngineItf engineEngine;
3597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
3697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// output mix interfaces
3797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenstatic XAObjectItf outputMixObject = NULL;
3897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
3997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// streaming media player interfaces
40eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivistatic XAObjectItf             playerObj = NULL;
41eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivistatic XAPlayItf               playerPlayItf = NULL;
42eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivistatic XAAndroidBufferQueueItf playerBQItf = NULL;
43d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi// number of required interfaces for the MediaPlayer creation
44d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi#define NB_MAXAL_INTERFACES 2 // XAAndroidBufferQueueItf and XAPlayItf
4597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
46295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivi// cached surface where the video display happens
47ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten#if NO_NATIVE_WINDOW
48ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kastenstatic jobject theSurfaceOrSurfaceTexture;
49ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten#else
50295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivistatic ANativeWindow* theNativeWindow;
51ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten#endif
5297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
53d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi// number of buffers in our buffer queue
54d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi#define NB_BUFFERS 16
55d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi// we're streaming MPEG-2 transport stream data, operate on transport stream block size
56d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi#define MPEG2_TS_BLOCK_SIZE 188
57d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi// determines how much memory we're dedicating to memory caching
58d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi#define BUFFER_SIZE 20*MPEG2_TS_BLOCK_SIZE // 20 is an arbitrary number chosen here
59d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi
60d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi// where we cache in memory the data to play
61d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivichar dataCache[BUFFER_SIZE * NB_BUFFERS];
62eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi// handle of the file to play
63eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel TriviFILE *file;
6470c49ae2867094072a4365423417ea452bf82231Jean-Michel Trivi// has the app reached the end of the file
6570c49ae2867094072a4365423417ea452bf82231Jean-Michel Trivichar reachedEof = 0;
66eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi
67eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi// AndroidBufferQueueItf callback for an audio player
68eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel TriviXAresult AndroidBufferQueueCallback(
69eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        XAAndroidBufferQueueItf caller,
70d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        void *pContext,                /* input */
71d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        const void *pBufferData,       /* input */
72d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        XAuint32 dataSize,             /* input */
73d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        XAuint32 dataUsed,             /* input */
74d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        const XAAndroidBufferItem *pItems,/* input */
75d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        XAuint32 itemsLength           /* input */)
76eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi{
77d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    // assert(BUFFER_SIZE <= dataSize);
78d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    size_t nbRead = fread((void*)pBufferData, 1, BUFFER_SIZE, file);
79d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    if (nbRead > 0) {
80d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        (*caller)->Enqueue(caller,
81d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi                pBufferData /*pData*/,
82d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi                nbRead /*dataLength*/,
83d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi                NULL /*pMsg*/,
84d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi                0 /*msgLength*/);
8570c49ae2867094072a4365423417ea452bf82231Jean-Michel Trivi    } else if (!reachedEof) {
86d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        // signal EOS
87d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        XAAndroidBufferItem msgEos;
88d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        msgEos.itemKey = XA_ANDROID_ITEMKEY_EOS;
89d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        msgEos.itemSize = 0;
90d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        // EOS message has no parameters, so the total size of the message is the size of the key
91d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        //   plus the size if itemSize, both XAuint32
92d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        (*caller)->Enqueue(caller, NULL /*pData*/, 0 /*dataLength*/,
93d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi                        &msgEos /*pMsg*/,
94d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi                        sizeof(XAuint32)*2 /*msgLength*/);
9570c49ae2867094072a4365423417ea452bf82231Jean-Michel Trivi        reachedEof = 1;
96eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    }
97eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi
98eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    return XA_RESULT_SUCCESS;
99eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi}
100eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi
101eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi
10297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// create the engine and output mix objects
10397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenvoid Java_com_example_nativemedia_NativeMedia_createEngine(JNIEnv* env, jclass clazz)
10497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten{
105eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    XAresult res;
10697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
10797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // create engine
108eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = xaCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
109eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
11097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
11197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // realize the engine
112eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = (*engineObject)->Realize(engineObject, XA_BOOLEAN_FALSE);
113eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
11497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
11597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // get the engine interface, which is needed in order to create other objects
116eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = (*engineObject)->GetInterface(engineObject, XA_IID_ENGINE, &engineEngine);
117eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
11897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
11997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // create output mix
120eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL);
121eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
12297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
12397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // realize the output mix
124eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = (*outputMixObject)->Realize(outputMixObject, XA_BOOLEAN_FALSE);
125eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
12697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
12797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten}
12897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
12997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
13097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// create streaming media player
13197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenjboolean Java_com_example_nativemedia_NativeMedia_createStreamingMediaPlayer(JNIEnv* env,
13297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten        jclass clazz, jstring filename)
13397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten{
134eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    XAresult res;
13597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
13697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // convert Java string to UTF-8
13797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    const char *utf8 = (*env)->GetStringUTFChars(env, filename, NULL);
13897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    assert(NULL != utf8);
13997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
140eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    // open the file to play
141eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    file = fopen(utf8, "rb");
142eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    if (file == NULL) {
143eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        LOGE("Failed to open %s", utf8);
144eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        return JNI_FALSE;
145eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    }
146eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi
147eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    // configure data source
148d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    XADataLocator_AndroidBufferQueue loc_abq = { XA_DATALOCATOR_ANDROIDBUFFERQUEUE, NB_BUFFERS };
149d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    XADataFormat_MIME format_mime = {
150d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi            XA_DATAFORMAT_MIME, (XAchar *)"video/mp2ts", XA_CONTAINERTYPE_MPEG_TS };
151eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    XADataSource dataSrc = {&loc_abq, &format_mime};
15297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
15397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // configure audio sink
154d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    XADataLocator_OutputMix loc_outmix = { XA_DATALOCATOR_OUTPUTMIX, outputMixObject };
155d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    XADataSink audioSnk = { &loc_outmix, NULL };
15697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
15797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // configure image video sink
158295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivi    XADataLocator_NativeDisplay loc_nd = {
159ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten            XA_DATALOCATOR_NATIVEDISPLAY,        // locatorType
160ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten#if NO_NATIVE_WINDOW
161ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten            (void *) theSurfaceOrSurfaceTexture, // jobject
162ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten            (void *) env                         // JNIEnv *env
163ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten#else
164ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten            // later the video sink can be an ANativeWindow created from a Surface or SurfaceTexture
165ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten            (void*)theNativeWindow,              // hWindow
166ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten            // must be NULL
167ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten            NULL                                 // hDisplay
168ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten#endif
169ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten    };
17097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    XADataSink imageVideoSink = {&loc_nd, NULL};
17197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
172eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    // declare interfaces to use
173d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    XAboolean     required[NB_MAXAL_INTERFACES] = {XA_BOOLEAN_TRUE, XA_BOOLEAN_TRUE};
174d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    XAInterfaceID iidArray[NB_MAXAL_INTERFACES] = {XA_IID_PLAY,     XA_IID_ANDROIDBUFFERQUEUE};
175eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi
17697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // create media player
177eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = (*engineEngine)->CreateMediaPlayer(engineEngine, &playerObj, &dataSrc,
178eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi            NULL, &audioSnk, &imageVideoSink, NULL, NULL,
179d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi            NB_MAXAL_INTERFACES /*XAuint32 numInterfaces*/,
180eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi            iidArray /*const XAInterfaceID *pInterfaceIds*/,
181eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi            required /*const XAboolean *pInterfaceRequired*/);
182eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
18397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
18497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // release the Java string and UTF-8
18597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    (*env)->ReleaseStringUTFChars(env, filename, utf8);
18697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
18797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // realize the player
188eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = (*playerObj)->Realize(playerObj, XA_BOOLEAN_FALSE);
189eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
19097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
19197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // get the play interface
192eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = (*playerObj)->GetInterface(playerObj, XA_IID_PLAY, &playerPlayItf);
193eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
194eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi
195eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    // get the Android buffer queue interface
196eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = (*playerObj)->GetInterface(playerObj, XA_IID_ANDROIDBUFFERQUEUE, &playerBQItf);
197eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
198eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi
199eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    // register the callback from which OpenMAX AL can retrieve the data to play
200d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    res = (*playerBQItf)->RegisterCallback(playerBQItf, AndroidBufferQueueCallback, NULL);
201d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi
202d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    /* Fill our cache */
203d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    if (fread(dataCache, 1, BUFFER_SIZE * NB_BUFFERS, file) <= 0) {
204d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        LOGE("Error filling cache, exiting\n");
205d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        return JNI_FALSE;
206d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    }
207d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    /* Enqueue the content of our cache before starting to play,
208d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi       we don't want to starve the player */
209d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    int i;
210d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    for (i=0 ; i < NB_BUFFERS ; i++) {
211d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        res = (*playerBQItf)->Enqueue(playerBQItf, dataCache + i*BUFFER_SIZE, BUFFER_SIZE, NULL, 0);
212d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        assert(XA_RESULT_SUCCESS == res);
213d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    }
214d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi
215eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi
216eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    // prepare the player
217eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = (*playerPlayItf)->SetPlayState(playerPlayItf, XA_PLAYSTATE_PAUSED);
218eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
219eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi
220eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = (*playerPlayItf)->SetPlayState(playerPlayItf, XA_PLAYSTATE_PLAYING);
221eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        assert(XA_RESULT_SUCCESS == res);
22297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
22397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    return JNI_TRUE;
22497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten}
22597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
22697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
22797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// set the playing state for the streaming media player
22897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenvoid Java_com_example_nativemedia_NativeMedia_setPlayingStreamingMediaPlayer(JNIEnv* env,
22997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten        jclass clazz, jboolean isPlaying)
23097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten{
231eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    XAresult res;
23297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
23397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // make sure the streaming media player was created
234eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    if (NULL != playerPlayItf) {
23597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
23697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten        // set the player's state
237eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        res = (*playerPlayItf)->SetPlayState(playerPlayItf, isPlaying ?
23897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten            XA_PLAYSTATE_PLAYING : XA_PLAYSTATE_PAUSED);
239eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        assert(XA_RESULT_SUCCESS == res);
24097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
24197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    }
24297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
24397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten}
24497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
24597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
24697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// shut down the native media system
24797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenvoid Java_com_example_nativemedia_NativeMedia_shutdown(JNIEnv* env, jclass clazz)
24897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten{
24997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // destroy streaming media player object, and invalidate all associated interfaces
250eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    if (playerObj != NULL) {
251eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        (*playerObj)->Destroy(playerObj);
252eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        playerObj = NULL;
253eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        playerPlayItf = NULL;
254eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        playerBQItf = NULL;
25597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    }
25697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
25797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // destroy output mix object, and invalidate all associated interfaces
25897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    if (outputMixObject != NULL) {
25997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten        (*outputMixObject)->Destroy(outputMixObject);
26097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten        outputMixObject = NULL;
26197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    }
26297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
26397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // destroy engine object, and invalidate all associated interfaces
26497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    if (engineObject != NULL) {
26597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten        (*engineObject)->Destroy(engineObject);
26697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten        engineObject = NULL;
26797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten        engineEngine = NULL;
26897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    }
26997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
270eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    // close the file
271eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    if (file != NULL) {
272eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        fclose(file);
273eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    }
274295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivi
275ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten#if !NO_NATIVE_WINDOW
276295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivi    // make sure we don't leak native windows
277ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten    if (theNativeWindow != NULL) {
278ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten        ANativeWindow_release(theNativeWindow);
279ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten    }
280ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten#endif
28197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten}
28297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
28397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
28497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// set the surface
28597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenvoid Java_com_example_nativemedia_NativeMedia_setSurface(JNIEnv *env, jclass clazz, jobject surface)
28697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten{
287ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten#if NO_NATIVE_WINDOW
288ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten    theSurfaceOrSurfaceTexture = surface;
289ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten#else
290295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivi    // obtain a native window from a Java surface
291295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivi    theNativeWindow = ANativeWindow_fromSurface(env, surface);
292ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten#endif
293ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten}
294ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten
295ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten
296ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten// set the surface texture
297ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kastenvoid Java_com_example_nativemedia_NativeMedia_setSurfaceTexture(JNIEnv *env, jclass clazz,
298ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten        jobject surfaceTexture)
299ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten{
300ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten#if NO_NATIVE_WINDOW
301ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten    theSurfaceOrSurfaceTexture = surfaceTexture;
302ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten#else
303ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten    // obtain a native window from a Java surface texture
304ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten    theNativeWindow = ANativeWindow_fromSurfaceTexture(env, surfaceTexture);
305ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten#endif
30697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten}
307