native-media-jni.c revision ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8
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;
64eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi
65eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi// AndroidBufferQueueItf callback for an audio player
66eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel TriviXAresult AndroidBufferQueueCallback(
67eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        XAAndroidBufferQueueItf caller,
68d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        void *pContext,                /* input */
69d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        const void *pBufferData,       /* input */
70d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        XAuint32 dataSize,             /* input */
71d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        XAuint32 dataUsed,             /* input */
72d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        const XAAndroidBufferItem *pItems,/* input */
73d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        XAuint32 itemsLength           /* input */)
74eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi{
75d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    // assert(BUFFER_SIZE <= dataSize);
76d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    size_t nbRead = fread((void*)pBufferData, 1, BUFFER_SIZE, file);
77d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    if (nbRead > 0) {
78d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        (*caller)->Enqueue(caller,
79d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi                pBufferData /*pData*/,
80d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi                nbRead /*dataLength*/,
81d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi                NULL /*pMsg*/,
82d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi                0 /*msgLength*/);
83eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    } else {
84d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        // signal EOS
85d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        XAAndroidBufferItem msgEos;
86d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        msgEos.itemKey = XA_ANDROID_ITEMKEY_EOS;
87d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        msgEos.itemSize = 0;
88d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        // EOS message has no parameters, so the total size of the message is the size of the key
89d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        //   plus the size if itemSize, both XAuint32
90d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        (*caller)->Enqueue(caller, NULL /*pData*/, 0 /*dataLength*/,
91d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi                        &msgEos /*pMsg*/,
92d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi                        sizeof(XAuint32)*2 /*msgLength*/);
93eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    }
94eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi
95eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    return XA_RESULT_SUCCESS;
96eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi}
97eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi
98eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi
9997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// create the engine and output mix objects
10097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenvoid Java_com_example_nativemedia_NativeMedia_createEngine(JNIEnv* env, jclass clazz)
10197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten{
102eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    XAresult res;
10397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
10497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // create engine
105eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = xaCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
106eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
10797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
10897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // realize the engine
109eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = (*engineObject)->Realize(engineObject, XA_BOOLEAN_FALSE);
110eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
11197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
11297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // get the engine interface, which is needed in order to create other objects
113eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = (*engineObject)->GetInterface(engineObject, XA_IID_ENGINE, &engineEngine);
114eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
11597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
11697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // create output mix
117eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL);
118eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
11997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
12097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // realize the output mix
121eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = (*outputMixObject)->Realize(outputMixObject, XA_BOOLEAN_FALSE);
122eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
12397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
12497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten}
12597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
12697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
12797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// create streaming media player
12897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenjboolean Java_com_example_nativemedia_NativeMedia_createStreamingMediaPlayer(JNIEnv* env,
12997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten        jclass clazz, jstring filename)
13097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten{
131eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    XAresult res;
13297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
13397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // convert Java string to UTF-8
13497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    const char *utf8 = (*env)->GetStringUTFChars(env, filename, NULL);
13597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    assert(NULL != utf8);
13697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
137eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    // open the file to play
138eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    file = fopen(utf8, "rb");
139eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    if (file == NULL) {
140eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        LOGE("Failed to open %s", utf8);
141eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        return JNI_FALSE;
142eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    }
143eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi
144eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    // configure data source
145d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    XADataLocator_AndroidBufferQueue loc_abq = { XA_DATALOCATOR_ANDROIDBUFFERQUEUE, NB_BUFFERS };
146d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    XADataFormat_MIME format_mime = {
147d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi            XA_DATAFORMAT_MIME, (XAchar *)"video/mp2ts", XA_CONTAINERTYPE_MPEG_TS };
148eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    XADataSource dataSrc = {&loc_abq, &format_mime};
14997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
15097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // configure audio sink
151d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    XADataLocator_OutputMix loc_outmix = { XA_DATALOCATOR_OUTPUTMIX, outputMixObject };
152d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    XADataSink audioSnk = { &loc_outmix, NULL };
15397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
15497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // configure image video sink
155295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivi    XADataLocator_NativeDisplay loc_nd = {
156ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten            XA_DATALOCATOR_NATIVEDISPLAY,        // locatorType
157ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten#if NO_NATIVE_WINDOW
158ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten            (void *) theSurfaceOrSurfaceTexture, // jobject
159ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten            (void *) env                         // JNIEnv *env
160ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten#else
161ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten            // later the video sink can be an ANativeWindow created from a Surface or SurfaceTexture
162ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten            (void*)theNativeWindow,              // hWindow
163ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten            // must be NULL
164ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten            NULL                                 // hDisplay
165ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten#endif
166ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten    };
16797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    XADataSink imageVideoSink = {&loc_nd, NULL};
16897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
169eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    // declare interfaces to use
170d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    XAboolean     required[NB_MAXAL_INTERFACES] = {XA_BOOLEAN_TRUE, XA_BOOLEAN_TRUE};
171d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    XAInterfaceID iidArray[NB_MAXAL_INTERFACES] = {XA_IID_PLAY,     XA_IID_ANDROIDBUFFERQUEUE};
172eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi
17397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // create media player
174eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = (*engineEngine)->CreateMediaPlayer(engineEngine, &playerObj, &dataSrc,
175eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi            NULL, &audioSnk, &imageVideoSink, NULL, NULL,
176d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi            NB_MAXAL_INTERFACES /*XAuint32 numInterfaces*/,
177eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi            iidArray /*const XAInterfaceID *pInterfaceIds*/,
178eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi            required /*const XAboolean *pInterfaceRequired*/);
179eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
18097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
18197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // release the Java string and UTF-8
18297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    (*env)->ReleaseStringUTFChars(env, filename, utf8);
18397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
18497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // realize the player
185eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = (*playerObj)->Realize(playerObj, XA_BOOLEAN_FALSE);
186eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
18797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
18897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // get the play interface
189eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = (*playerObj)->GetInterface(playerObj, XA_IID_PLAY, &playerPlayItf);
190eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
191eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi
192eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    // get the Android buffer queue interface
193eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = (*playerObj)->GetInterface(playerObj, XA_IID_ANDROIDBUFFERQUEUE, &playerBQItf);
194eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
195eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi
196eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    // register the callback from which OpenMAX AL can retrieve the data to play
197d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    res = (*playerBQItf)->RegisterCallback(playerBQItf, AndroidBufferQueueCallback, NULL);
198d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi
199d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    /* Fill our cache */
200d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    if (fread(dataCache, 1, BUFFER_SIZE * NB_BUFFERS, file) <= 0) {
201d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        LOGE("Error filling cache, exiting\n");
202d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        return JNI_FALSE;
203d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    }
204d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    /* Enqueue the content of our cache before starting to play,
205d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi       we don't want to starve the player */
206d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    int i;
207d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    for (i=0 ; i < NB_BUFFERS ; i++) {
208d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        res = (*playerBQItf)->Enqueue(playerBQItf, dataCache + i*BUFFER_SIZE, BUFFER_SIZE, NULL, 0);
209d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        assert(XA_RESULT_SUCCESS == res);
210d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    }
211d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi
212eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi
213eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    // prepare the player
214eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = (*playerPlayItf)->SetPlayState(playerPlayItf, XA_PLAYSTATE_PAUSED);
215eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
216eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi
217eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = (*playerPlayItf)->SetPlayState(playerPlayItf, XA_PLAYSTATE_PLAYING);
218eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        assert(XA_RESULT_SUCCESS == res);
21997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
22097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    return JNI_TRUE;
22197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten}
22297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
22397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
22497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// set the playing state for the streaming media player
22597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenvoid Java_com_example_nativemedia_NativeMedia_setPlayingStreamingMediaPlayer(JNIEnv* env,
22697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten        jclass clazz, jboolean isPlaying)
22797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten{
228eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    XAresult res;
22997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
23097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // make sure the streaming media player was created
231eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    if (NULL != playerPlayItf) {
23297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
23397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten        // set the player's state
234eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        res = (*playerPlayItf)->SetPlayState(playerPlayItf, isPlaying ?
23597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten            XA_PLAYSTATE_PLAYING : XA_PLAYSTATE_PAUSED);
236eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        assert(XA_RESULT_SUCCESS == res);
23797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
23897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    }
23997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
24097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten}
24197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
24297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
24397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// shut down the native media system
24497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenvoid Java_com_example_nativemedia_NativeMedia_shutdown(JNIEnv* env, jclass clazz)
24597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten{
24697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // destroy streaming media player object, and invalidate all associated interfaces
247eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    if (playerObj != NULL) {
248eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        (*playerObj)->Destroy(playerObj);
249eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        playerObj = NULL;
250eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        playerPlayItf = NULL;
251eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        playerBQItf = NULL;
25297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    }
25397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
25497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // destroy output mix object, and invalidate all associated interfaces
25597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    if (outputMixObject != NULL) {
25697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten        (*outputMixObject)->Destroy(outputMixObject);
25797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten        outputMixObject = NULL;
25897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    }
25997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
26097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // destroy engine object, and invalidate all associated interfaces
26197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    if (engineObject != NULL) {
26297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten        (*engineObject)->Destroy(engineObject);
26397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten        engineObject = NULL;
26497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten        engineEngine = NULL;
26597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    }
26697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
267eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    // close the file
268eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    if (file != NULL) {
269eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        fclose(file);
270eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    }
271295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivi
272ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten#if !NO_NATIVE_WINDOW
273295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivi    // make sure we don't leak native windows
274ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten    if (theNativeWindow != NULL) {
275ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten        ANativeWindow_release(theNativeWindow);
276ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten    }
277ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten#endif
27897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten}
27997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
28097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
28197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// set the surface
28297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenvoid Java_com_example_nativemedia_NativeMedia_setSurface(JNIEnv *env, jclass clazz, jobject surface)
28397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten{
284ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten#if NO_NATIVE_WINDOW
285ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten    theSurfaceOrSurfaceTexture = surface;
286ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten#else
287295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivi    // obtain a native window from a Java surface
288295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivi    theNativeWindow = ANativeWindow_fromSurface(env, surface);
289ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten#endif
290ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten}
291ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten
292ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten
293ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten// set the surface texture
294ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kastenvoid Java_com_example_nativemedia_NativeMedia_setSurfaceTexture(JNIEnv *env, jclass clazz,
295ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten        jobject surfaceTexture)
296ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten{
297ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten#if NO_NATIVE_WINDOW
298ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten    theSurfaceOrSurfaceTexture = surfaceTexture;
299ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten#else
300ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten    // obtain a native window from a Java surface texture
301ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten    theNativeWindow = ANativeWindow_fromSurfaceTexture(env, surfaceTexture);
302ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten#endif
30397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten}
304