1*bebae9c0SAndroid Build Coastguard Worker /*
2*bebae9c0SAndroid Build Coastguard Worker * Copyright (C) 2010 The Android Open Source Project
3*bebae9c0SAndroid Build Coastguard Worker *
4*bebae9c0SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*bebae9c0SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*bebae9c0SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*bebae9c0SAndroid Build Coastguard Worker *
8*bebae9c0SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*bebae9c0SAndroid Build Coastguard Worker *
10*bebae9c0SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*bebae9c0SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*bebae9c0SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*bebae9c0SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*bebae9c0SAndroid Build Coastguard Worker * limitations under the License.
15*bebae9c0SAndroid Build Coastguard Worker */
16*bebae9c0SAndroid Build Coastguard Worker
17*bebae9c0SAndroid Build Coastguard Worker #include <assert.h>
18*bebae9c0SAndroid Build Coastguard Worker #include <jni.h>
19*bebae9c0SAndroid Build Coastguard Worker #include <pthread.h>
20*bebae9c0SAndroid Build Coastguard Worker #include <string.h>
21*bebae9c0SAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
22*bebae9c0SAndroid Build Coastguard Worker #define LOG_TAG "NativeMedia"
23*bebae9c0SAndroid Build Coastguard Worker #include <utils/Log.h>
24*bebae9c0SAndroid Build Coastguard Worker
25*bebae9c0SAndroid Build Coastguard Worker #include <OMXAL/OpenMAXAL.h>
26*bebae9c0SAndroid Build Coastguard Worker #include <OMXAL/OpenMAXAL_Android.h>
27*bebae9c0SAndroid Build Coastguard Worker
28*bebae9c0SAndroid Build Coastguard Worker #include <android/native_window_jni.h>
29*bebae9c0SAndroid Build Coastguard Worker
30*bebae9c0SAndroid Build Coastguard Worker // engine interfaces
31*bebae9c0SAndroid Build Coastguard Worker static XAObjectItf engineObject = NULL;
32*bebae9c0SAndroid Build Coastguard Worker static XAEngineItf engineEngine = NULL;
33*bebae9c0SAndroid Build Coastguard Worker
34*bebae9c0SAndroid Build Coastguard Worker // output mix interfaces
35*bebae9c0SAndroid Build Coastguard Worker static XAObjectItf outputMixObject = NULL;
36*bebae9c0SAndroid Build Coastguard Worker
37*bebae9c0SAndroid Build Coastguard Worker // streaming media player interfaces
38*bebae9c0SAndroid Build Coastguard Worker static XAObjectItf playerObj = NULL;
39*bebae9c0SAndroid Build Coastguard Worker static XAPlayItf playerPlayItf = NULL;
40*bebae9c0SAndroid Build Coastguard Worker static XAAndroidBufferQueueItf playerBQItf = NULL;
41*bebae9c0SAndroid Build Coastguard Worker static XAStreamInformationItf playerStreamInfoItf = NULL;
42*bebae9c0SAndroid Build Coastguard Worker static XAVolumeItf playerVolItf = NULL;
43*bebae9c0SAndroid Build Coastguard Worker
44*bebae9c0SAndroid Build Coastguard Worker // number of required interfaces for the MediaPlayer creation
45*bebae9c0SAndroid Build Coastguard Worker #define NB_MAXAL_INTERFACES 3 // XAAndroidBufferQueueItf, XAStreamInformationItf and XAPlayItf
46*bebae9c0SAndroid Build Coastguard Worker
47*bebae9c0SAndroid Build Coastguard Worker // video sink for the player
48*bebae9c0SAndroid Build Coastguard Worker static ANativeWindow* theNativeWindow;
49*bebae9c0SAndroid Build Coastguard Worker
50*bebae9c0SAndroid Build Coastguard Worker // number of buffers in our buffer queue, an arbitrary number
51*bebae9c0SAndroid Build Coastguard Worker #define NB_BUFFERS 16
52*bebae9c0SAndroid Build Coastguard Worker
53*bebae9c0SAndroid Build Coastguard Worker // we're streaming MPEG-2 transport stream data, operate on transport stream block size
54*bebae9c0SAndroid Build Coastguard Worker #define MPEG2_TS_BLOCK_SIZE 188
55*bebae9c0SAndroid Build Coastguard Worker
56*bebae9c0SAndroid Build Coastguard Worker // number of MPEG-2 transport stream blocks per buffer, an arbitrary number
57*bebae9c0SAndroid Build Coastguard Worker #define BLOCKS_PER_BUFFER 20
58*bebae9c0SAndroid Build Coastguard Worker
59*bebae9c0SAndroid Build Coastguard Worker // determines how much memory we're dedicating to memory caching
60*bebae9c0SAndroid Build Coastguard Worker #define BUFFER_SIZE (BLOCKS_PER_BUFFER*MPEG2_TS_BLOCK_SIZE)
61*bebae9c0SAndroid Build Coastguard Worker
62*bebae9c0SAndroid Build Coastguard Worker // where we cache in memory the data to play
63*bebae9c0SAndroid Build Coastguard Worker // note this memory is re-used by the buffer queue callback
64*bebae9c0SAndroid Build Coastguard Worker char dataCache[BUFFER_SIZE * NB_BUFFERS];
65*bebae9c0SAndroid Build Coastguard Worker
66*bebae9c0SAndroid Build Coastguard Worker // handle of the file to play
67*bebae9c0SAndroid Build Coastguard Worker FILE *file;
68*bebae9c0SAndroid Build Coastguard Worker
69*bebae9c0SAndroid Build Coastguard Worker // has the app reached the end of the file
70*bebae9c0SAndroid Build Coastguard Worker jboolean reachedEof = JNI_FALSE;
71*bebae9c0SAndroid Build Coastguard Worker
72*bebae9c0SAndroid Build Coastguard Worker // constant to identify a buffer context which is the end of the stream to decode
73*bebae9c0SAndroid Build Coastguard Worker static const int kEosBufferCntxt = 1980; // a magic value we can compare against
74*bebae9c0SAndroid Build Coastguard Worker
75*bebae9c0SAndroid Build Coastguard Worker // for mutual exclusion between callback thread and application thread(s)
76*bebae9c0SAndroid Build Coastguard Worker pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
77*bebae9c0SAndroid Build Coastguard Worker pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
78*bebae9c0SAndroid Build Coastguard Worker
79*bebae9c0SAndroid Build Coastguard Worker // whether a discontinuity is in progress
80*bebae9c0SAndroid Build Coastguard Worker jboolean discontinuity = JNI_FALSE;
81*bebae9c0SAndroid Build Coastguard Worker
82*bebae9c0SAndroid Build Coastguard Worker static jboolean enqueueInitialBuffers(jboolean discontinuity);
83*bebae9c0SAndroid Build Coastguard Worker
84*bebae9c0SAndroid Build Coastguard Worker // Callback for XAPlayItf through which we receive the XA_PLAYEVENT_HEADATEND event */
PlayCallback(XAPlayItf caller,void * pContext,XAuint32 event)85*bebae9c0SAndroid Build Coastguard Worker void PlayCallback(XAPlayItf caller, void *pContext, XAuint32 event) {
86*bebae9c0SAndroid Build Coastguard Worker if (event & XA_PLAYEVENT_HEADATEND) {
87*bebae9c0SAndroid Build Coastguard Worker ALOGV("XA_PLAYEVENT_HEADATEND received, all MP2TS data has been decoded\n");
88*bebae9c0SAndroid Build Coastguard Worker }
89*bebae9c0SAndroid Build Coastguard Worker }
90*bebae9c0SAndroid Build Coastguard Worker
91*bebae9c0SAndroid Build Coastguard Worker // AndroidBufferQueueItf callback for an audio player
AndroidBufferQueueCallback(XAAndroidBufferQueueItf caller,void * pCallbackContext,void * pBufferContext,void * pBufferData,XAuint32 dataSize,XAuint32 dataUsed,const XAAndroidBufferItem * pItems,XAuint32 itemsLength)92*bebae9c0SAndroid Build Coastguard Worker XAresult AndroidBufferQueueCallback(
93*bebae9c0SAndroid Build Coastguard Worker XAAndroidBufferQueueItf caller,
94*bebae9c0SAndroid Build Coastguard Worker void *pCallbackContext, /* input */
95*bebae9c0SAndroid Build Coastguard Worker void *pBufferContext, /* input */
96*bebae9c0SAndroid Build Coastguard Worker void *pBufferData, /* input */
97*bebae9c0SAndroid Build Coastguard Worker XAuint32 dataSize, /* input */
98*bebae9c0SAndroid Build Coastguard Worker XAuint32 dataUsed, /* input */
99*bebae9c0SAndroid Build Coastguard Worker const XAAndroidBufferItem *pItems,/* input */
100*bebae9c0SAndroid Build Coastguard Worker XAuint32 itemsLength /* input */)
101*bebae9c0SAndroid Build Coastguard Worker {
102*bebae9c0SAndroid Build Coastguard Worker XAresult res;
103*bebae9c0SAndroid Build Coastguard Worker int ok;
104*bebae9c0SAndroid Build Coastguard Worker
105*bebae9c0SAndroid Build Coastguard Worker // pCallbackContext was specified as NULL at RegisterCallback and is unused here
106*bebae9c0SAndroid Build Coastguard Worker assert(NULL == pCallbackContext);
107*bebae9c0SAndroid Build Coastguard Worker
108*bebae9c0SAndroid Build Coastguard Worker // note there is never any contention on this mutex unless a discontinuity request is active
109*bebae9c0SAndroid Build Coastguard Worker ok = pthread_mutex_lock(&mutex);
110*bebae9c0SAndroid Build Coastguard Worker assert(0 == ok);
111*bebae9c0SAndroid Build Coastguard Worker
112*bebae9c0SAndroid Build Coastguard Worker // was a discontinuity requested?
113*bebae9c0SAndroid Build Coastguard Worker if (discontinuity) {
114*bebae9c0SAndroid Build Coastguard Worker // FIXME sorry, can't rewind after EOS
115*bebae9c0SAndroid Build Coastguard Worker if (!reachedEof) {
116*bebae9c0SAndroid Build Coastguard Worker // clear the buffer queue
117*bebae9c0SAndroid Build Coastguard Worker res = (*playerBQItf)->Clear(playerBQItf);
118*bebae9c0SAndroid Build Coastguard Worker assert(XA_RESULT_SUCCESS == res);
119*bebae9c0SAndroid Build Coastguard Worker // rewind the data source so we are guaranteed to be at an appropriate point
120*bebae9c0SAndroid Build Coastguard Worker rewind(file);
121*bebae9c0SAndroid Build Coastguard Worker // Enqueue the initial buffers, with a discontinuity indicator on first buffer
122*bebae9c0SAndroid Build Coastguard Worker (void) enqueueInitialBuffers(JNI_TRUE);
123*bebae9c0SAndroid Build Coastguard Worker }
124*bebae9c0SAndroid Build Coastguard Worker // acknowledge the discontinuity request
125*bebae9c0SAndroid Build Coastguard Worker discontinuity = JNI_FALSE;
126*bebae9c0SAndroid Build Coastguard Worker ok = pthread_cond_signal(&cond);
127*bebae9c0SAndroid Build Coastguard Worker assert(0 == ok);
128*bebae9c0SAndroid Build Coastguard Worker goto exit;
129*bebae9c0SAndroid Build Coastguard Worker }
130*bebae9c0SAndroid Build Coastguard Worker
131*bebae9c0SAndroid Build Coastguard Worker if ((pBufferData == NULL) && (pBufferContext != NULL)) {
132*bebae9c0SAndroid Build Coastguard Worker const int processedCommand = *(int *)pBufferContext;
133*bebae9c0SAndroid Build Coastguard Worker if (kEosBufferCntxt == processedCommand) {
134*bebae9c0SAndroid Build Coastguard Worker ALOGV("EOS was processed\n");
135*bebae9c0SAndroid Build Coastguard Worker // our buffer with the EOS message has been consumed
136*bebae9c0SAndroid Build Coastguard Worker assert(0 == dataSize);
137*bebae9c0SAndroid Build Coastguard Worker goto exit;
138*bebae9c0SAndroid Build Coastguard Worker }
139*bebae9c0SAndroid Build Coastguard Worker }
140*bebae9c0SAndroid Build Coastguard Worker
141*bebae9c0SAndroid Build Coastguard Worker // pBufferData is a pointer to a buffer that we previously Enqueued
142*bebae9c0SAndroid Build Coastguard Worker assert(BUFFER_SIZE == dataSize);
143*bebae9c0SAndroid Build Coastguard Worker assert(dataCache <= (char *) pBufferData && (char *) pBufferData <
144*bebae9c0SAndroid Build Coastguard Worker &dataCache[BUFFER_SIZE * NB_BUFFERS]);
145*bebae9c0SAndroid Build Coastguard Worker assert(0 == (((char *) pBufferData - dataCache) % BUFFER_SIZE));
146*bebae9c0SAndroid Build Coastguard Worker
147*bebae9c0SAndroid Build Coastguard Worker #if 0
148*bebae9c0SAndroid Build Coastguard Worker // sample code to use the XAVolumeItf
149*bebae9c0SAndroid Build Coastguard Worker XAAndroidBufferQueueState state;
150*bebae9c0SAndroid Build Coastguard Worker (*caller)->GetState(caller, &state);
151*bebae9c0SAndroid Build Coastguard Worker switch (state.index) {
152*bebae9c0SAndroid Build Coastguard Worker case 300:
153*bebae9c0SAndroid Build Coastguard Worker (*playerVolItf)->SetVolumeLevel(playerVolItf, -600); // -6dB
154*bebae9c0SAndroid Build Coastguard Worker ALOGV("setting volume to -6dB");
155*bebae9c0SAndroid Build Coastguard Worker break;
156*bebae9c0SAndroid Build Coastguard Worker case 400:
157*bebae9c0SAndroid Build Coastguard Worker (*playerVolItf)->SetVolumeLevel(playerVolItf, -1200); // -12dB
158*bebae9c0SAndroid Build Coastguard Worker ALOGV("setting volume to -12dB");
159*bebae9c0SAndroid Build Coastguard Worker break;
160*bebae9c0SAndroid Build Coastguard Worker case 500:
161*bebae9c0SAndroid Build Coastguard Worker (*playerVolItf)->SetVolumeLevel(playerVolItf, 0); // full volume
162*bebae9c0SAndroid Build Coastguard Worker ALOGV("setting volume to 0dB (full volume)");
163*bebae9c0SAndroid Build Coastguard Worker break;
164*bebae9c0SAndroid Build Coastguard Worker case 600:
165*bebae9c0SAndroid Build Coastguard Worker (*playerVolItf)->SetMute(playerVolItf, XA_BOOLEAN_TRUE); // mute
166*bebae9c0SAndroid Build Coastguard Worker ALOGV("muting player");
167*bebae9c0SAndroid Build Coastguard Worker break;
168*bebae9c0SAndroid Build Coastguard Worker case 700:
169*bebae9c0SAndroid Build Coastguard Worker (*playerVolItf)->SetMute(playerVolItf, XA_BOOLEAN_FALSE); // unmute
170*bebae9c0SAndroid Build Coastguard Worker ALOGV("unmuting player");
171*bebae9c0SAndroid Build Coastguard Worker break;
172*bebae9c0SAndroid Build Coastguard Worker case 800:
173*bebae9c0SAndroid Build Coastguard Worker (*playerVolItf)->SetStereoPosition(playerVolItf, -1000);
174*bebae9c0SAndroid Build Coastguard Worker (*playerVolItf)->EnableStereoPosition(playerVolItf, XA_BOOLEAN_TRUE);
175*bebae9c0SAndroid Build Coastguard Worker ALOGV("pan sound to the left (hard-left)");
176*bebae9c0SAndroid Build Coastguard Worker break;
177*bebae9c0SAndroid Build Coastguard Worker case 900:
178*bebae9c0SAndroid Build Coastguard Worker (*playerVolItf)->EnableStereoPosition(playerVolItf, XA_BOOLEAN_FALSE);
179*bebae9c0SAndroid Build Coastguard Worker ALOGV("disabling stereo position");
180*bebae9c0SAndroid Build Coastguard Worker break;
181*bebae9c0SAndroid Build Coastguard Worker default:
182*bebae9c0SAndroid Build Coastguard Worker break;
183*bebae9c0SAndroid Build Coastguard Worker }
184*bebae9c0SAndroid Build Coastguard Worker #endif
185*bebae9c0SAndroid Build Coastguard Worker
186*bebae9c0SAndroid Build Coastguard Worker // don't bother trying to read more data once we've hit EOF
187*bebae9c0SAndroid Build Coastguard Worker if (reachedEof) {
188*bebae9c0SAndroid Build Coastguard Worker goto exit;
189*bebae9c0SAndroid Build Coastguard Worker }
190*bebae9c0SAndroid Build Coastguard Worker
191*bebae9c0SAndroid Build Coastguard Worker size_t nbRead;
192*bebae9c0SAndroid Build Coastguard Worker // note we do call fread from multiple threads, but never concurrently
193*bebae9c0SAndroid Build Coastguard Worker nbRead = fread(pBufferData, BUFFER_SIZE, 1, file);
194*bebae9c0SAndroid Build Coastguard Worker if (nbRead > 0) {
195*bebae9c0SAndroid Build Coastguard Worker assert(1 == nbRead);
196*bebae9c0SAndroid Build Coastguard Worker res = (*caller)->Enqueue(caller, NULL /*pBufferContext*/,
197*bebae9c0SAndroid Build Coastguard Worker pBufferData /*pData*/,
198*bebae9c0SAndroid Build Coastguard Worker nbRead * BUFFER_SIZE /*dataLength*/,
199*bebae9c0SAndroid Build Coastguard Worker NULL /*pMsg*/,
200*bebae9c0SAndroid Build Coastguard Worker 0 /*msgLength*/);
201*bebae9c0SAndroid Build Coastguard Worker assert(XA_RESULT_SUCCESS == res);
202*bebae9c0SAndroid Build Coastguard Worker } else {
203*bebae9c0SAndroid Build Coastguard Worker // signal EOS
204*bebae9c0SAndroid Build Coastguard Worker XAAndroidBufferItem msgEos[1];
205*bebae9c0SAndroid Build Coastguard Worker msgEos[0].itemKey = XA_ANDROID_ITEMKEY_EOS;
206*bebae9c0SAndroid Build Coastguard Worker msgEos[0].itemSize = 0;
207*bebae9c0SAndroid Build Coastguard Worker // EOS message has no parameters, so the total size of the message is the size of the key
208*bebae9c0SAndroid Build Coastguard Worker // plus the size if itemSize, both XAuint32
209*bebae9c0SAndroid Build Coastguard Worker res = (*caller)->Enqueue(caller, (void *)&kEosBufferCntxt /*pBufferContext*/,
210*bebae9c0SAndroid Build Coastguard Worker NULL /*pData*/, 0 /*dataLength*/,
211*bebae9c0SAndroid Build Coastguard Worker msgEos /*pMsg*/,
212*bebae9c0SAndroid Build Coastguard Worker // FIXME == sizeof(BufferItem)? */
213*bebae9c0SAndroid Build Coastguard Worker sizeof(XAuint32)*2 /*msgLength*/);
214*bebae9c0SAndroid Build Coastguard Worker assert(XA_RESULT_SUCCESS == res);
215*bebae9c0SAndroid Build Coastguard Worker reachedEof = JNI_TRUE;
216*bebae9c0SAndroid Build Coastguard Worker }
217*bebae9c0SAndroid Build Coastguard Worker
218*bebae9c0SAndroid Build Coastguard Worker exit:
219*bebae9c0SAndroid Build Coastguard Worker ok = pthread_mutex_unlock(&mutex);
220*bebae9c0SAndroid Build Coastguard Worker assert(0 == ok);
221*bebae9c0SAndroid Build Coastguard Worker return XA_RESULT_SUCCESS;
222*bebae9c0SAndroid Build Coastguard Worker }
223*bebae9c0SAndroid Build Coastguard Worker
224*bebae9c0SAndroid Build Coastguard Worker
StreamChangeCallback(XAStreamInformationItf caller,XAuint32 eventId,XAuint32 streamIndex,void * pEventData,void * pContext)225*bebae9c0SAndroid Build Coastguard Worker void StreamChangeCallback (XAStreamInformationItf caller,
226*bebae9c0SAndroid Build Coastguard Worker XAuint32 eventId,
227*bebae9c0SAndroid Build Coastguard Worker XAuint32 streamIndex,
228*bebae9c0SAndroid Build Coastguard Worker void * pEventData,
229*bebae9c0SAndroid Build Coastguard Worker void * pContext )
230*bebae9c0SAndroid Build Coastguard Worker {
231*bebae9c0SAndroid Build Coastguard Worker ALOGV("StreamChangeCallback called for stream %u", streamIndex);
232*bebae9c0SAndroid Build Coastguard Worker // pContext was specified as NULL at RegisterStreamChangeCallback and is unused here
233*bebae9c0SAndroid Build Coastguard Worker assert(NULL == pContext);
234*bebae9c0SAndroid Build Coastguard Worker switch (eventId) {
235*bebae9c0SAndroid Build Coastguard Worker case XA_STREAMCBEVENT_PROPERTYCHANGE: {
236*bebae9c0SAndroid Build Coastguard Worker /** From spec 1.0.1:
237*bebae9c0SAndroid Build Coastguard Worker "This event indicates that stream property change has occurred.
238*bebae9c0SAndroid Build Coastguard Worker The streamIndex parameter identifies the stream with the property change.
239*bebae9c0SAndroid Build Coastguard Worker The pEventData parameter for this event is not used and shall be ignored."
240*bebae9c0SAndroid Build Coastguard Worker */
241*bebae9c0SAndroid Build Coastguard Worker
242*bebae9c0SAndroid Build Coastguard Worker XAresult res;
243*bebae9c0SAndroid Build Coastguard Worker XAuint32 domain;
244*bebae9c0SAndroid Build Coastguard Worker res = (*caller)->QueryStreamType(caller, streamIndex, &domain);
245*bebae9c0SAndroid Build Coastguard Worker assert(XA_RESULT_SUCCESS == res);
246*bebae9c0SAndroid Build Coastguard Worker switch (domain) {
247*bebae9c0SAndroid Build Coastguard Worker case XA_DOMAINTYPE_VIDEO: {
248*bebae9c0SAndroid Build Coastguard Worker XAVideoStreamInformation videoInfo;
249*bebae9c0SAndroid Build Coastguard Worker res = (*caller)->QueryStreamInformation(caller, streamIndex, &videoInfo);
250*bebae9c0SAndroid Build Coastguard Worker assert(XA_RESULT_SUCCESS == res);
251*bebae9c0SAndroid Build Coastguard Worker ALOGI("Found video size %u x %u, codec ID=%u, frameRate=%u, bitRate=%u, duration=%u ms",
252*bebae9c0SAndroid Build Coastguard Worker videoInfo.width, videoInfo.height, videoInfo.codecId, videoInfo.frameRate,
253*bebae9c0SAndroid Build Coastguard Worker videoInfo.bitRate, videoInfo.duration);
254*bebae9c0SAndroid Build Coastguard Worker } break;
255*bebae9c0SAndroid Build Coastguard Worker default:
256*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, "Unexpected domain %u\n", domain);
257*bebae9c0SAndroid Build Coastguard Worker break;
258*bebae9c0SAndroid Build Coastguard Worker }
259*bebae9c0SAndroid Build Coastguard Worker } break;
260*bebae9c0SAndroid Build Coastguard Worker default:
261*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, "Unexpected stream event ID %u\n", eventId);
262*bebae9c0SAndroid Build Coastguard Worker break;
263*bebae9c0SAndroid Build Coastguard Worker }
264*bebae9c0SAndroid Build Coastguard Worker }
265*bebae9c0SAndroid Build Coastguard Worker
266*bebae9c0SAndroid Build Coastguard Worker
267*bebae9c0SAndroid Build Coastguard Worker // create the engine and output mix objects
Java_com_example_nativemedia_NativeMedia_createEngine(JNIEnv * env,jclass clazz)268*bebae9c0SAndroid Build Coastguard Worker void Java_com_example_nativemedia_NativeMedia_createEngine(JNIEnv* env, jclass clazz)
269*bebae9c0SAndroid Build Coastguard Worker {
270*bebae9c0SAndroid Build Coastguard Worker XAresult res;
271*bebae9c0SAndroid Build Coastguard Worker
272*bebae9c0SAndroid Build Coastguard Worker // create engine
273*bebae9c0SAndroid Build Coastguard Worker res = xaCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
274*bebae9c0SAndroid Build Coastguard Worker assert(XA_RESULT_SUCCESS == res);
275*bebae9c0SAndroid Build Coastguard Worker
276*bebae9c0SAndroid Build Coastguard Worker // realize the engine
277*bebae9c0SAndroid Build Coastguard Worker res = (*engineObject)->Realize(engineObject, XA_BOOLEAN_FALSE);
278*bebae9c0SAndroid Build Coastguard Worker assert(XA_RESULT_SUCCESS == res);
279*bebae9c0SAndroid Build Coastguard Worker
280*bebae9c0SAndroid Build Coastguard Worker // get the engine interface, which is needed in order to create other objects
281*bebae9c0SAndroid Build Coastguard Worker res = (*engineObject)->GetInterface(engineObject, XA_IID_ENGINE, &engineEngine);
282*bebae9c0SAndroid Build Coastguard Worker assert(XA_RESULT_SUCCESS == res);
283*bebae9c0SAndroid Build Coastguard Worker
284*bebae9c0SAndroid Build Coastguard Worker // create output mix
285*bebae9c0SAndroid Build Coastguard Worker res = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL);
286*bebae9c0SAndroid Build Coastguard Worker assert(XA_RESULT_SUCCESS == res);
287*bebae9c0SAndroid Build Coastguard Worker
288*bebae9c0SAndroid Build Coastguard Worker // realize the output mix
289*bebae9c0SAndroid Build Coastguard Worker res = (*outputMixObject)->Realize(outputMixObject, XA_BOOLEAN_FALSE);
290*bebae9c0SAndroid Build Coastguard Worker assert(XA_RESULT_SUCCESS == res);
291*bebae9c0SAndroid Build Coastguard Worker
292*bebae9c0SAndroid Build Coastguard Worker }
293*bebae9c0SAndroid Build Coastguard Worker
294*bebae9c0SAndroid Build Coastguard Worker
295*bebae9c0SAndroid Build Coastguard Worker // Enqueue the initial buffers, and optionally signal a discontinuity in the first buffer
enqueueInitialBuffers(jboolean discontinuity)296*bebae9c0SAndroid Build Coastguard Worker static jboolean enqueueInitialBuffers(jboolean discontinuity)
297*bebae9c0SAndroid Build Coastguard Worker {
298*bebae9c0SAndroid Build Coastguard Worker
299*bebae9c0SAndroid Build Coastguard Worker /* Fill our cache */
300*bebae9c0SAndroid Build Coastguard Worker size_t nbRead;
301*bebae9c0SAndroid Build Coastguard Worker nbRead = fread(dataCache, BUFFER_SIZE, NB_BUFFERS, file);
302*bebae9c0SAndroid Build Coastguard Worker if (nbRead <= 0) {
303*bebae9c0SAndroid Build Coastguard Worker // could be premature EOF or I/O error
304*bebae9c0SAndroid Build Coastguard Worker ALOGE("Error filling cache, exiting\n");
305*bebae9c0SAndroid Build Coastguard Worker return JNI_FALSE;
306*bebae9c0SAndroid Build Coastguard Worker }
307*bebae9c0SAndroid Build Coastguard Worker assert(1 <= nbRead && nbRead <= NB_BUFFERS);
308*bebae9c0SAndroid Build Coastguard Worker ALOGV("Initially queueing %zu buffers of %u bytes each", nbRead, BUFFER_SIZE);
309*bebae9c0SAndroid Build Coastguard Worker
310*bebae9c0SAndroid Build Coastguard Worker /* Enqueue the content of our cache before starting to play,
311*bebae9c0SAndroid Build Coastguard Worker we don't want to starve the player */
312*bebae9c0SAndroid Build Coastguard Worker size_t i;
313*bebae9c0SAndroid Build Coastguard Worker for (i = 0; i < nbRead; i++) {
314*bebae9c0SAndroid Build Coastguard Worker XAresult res;
315*bebae9c0SAndroid Build Coastguard Worker if (discontinuity) {
316*bebae9c0SAndroid Build Coastguard Worker // signal discontinuity
317*bebae9c0SAndroid Build Coastguard Worker XAAndroidBufferItem items[1];
318*bebae9c0SAndroid Build Coastguard Worker items[0].itemKey = XA_ANDROID_ITEMKEY_DISCONTINUITY;
319*bebae9c0SAndroid Build Coastguard Worker items[0].itemSize = 0;
320*bebae9c0SAndroid Build Coastguard Worker // DISCONTINUITY message has no parameters,
321*bebae9c0SAndroid Build Coastguard Worker // so the total size of the message is the size of the key
322*bebae9c0SAndroid Build Coastguard Worker // plus the size if itemSize, both XAuint32
323*bebae9c0SAndroid Build Coastguard Worker res = (*playerBQItf)->Enqueue(playerBQItf, NULL /*pBufferContext*/,
324*bebae9c0SAndroid Build Coastguard Worker dataCache + i*BUFFER_SIZE, BUFFER_SIZE, items /*pMsg*/,
325*bebae9c0SAndroid Build Coastguard Worker // FIXME == sizeof(BufferItem)? */
326*bebae9c0SAndroid Build Coastguard Worker sizeof(XAuint32)*2 /*msgLength*/);
327*bebae9c0SAndroid Build Coastguard Worker discontinuity = JNI_FALSE;
328*bebae9c0SAndroid Build Coastguard Worker } else {
329*bebae9c0SAndroid Build Coastguard Worker res = (*playerBQItf)->Enqueue(playerBQItf, NULL /*pBufferContext*/,
330*bebae9c0SAndroid Build Coastguard Worker dataCache + i*BUFFER_SIZE, BUFFER_SIZE, NULL, 0);
331*bebae9c0SAndroid Build Coastguard Worker }
332*bebae9c0SAndroid Build Coastguard Worker assert(XA_RESULT_SUCCESS == res);
333*bebae9c0SAndroid Build Coastguard Worker }
334*bebae9c0SAndroid Build Coastguard Worker
335*bebae9c0SAndroid Build Coastguard Worker return JNI_TRUE;
336*bebae9c0SAndroid Build Coastguard Worker }
337*bebae9c0SAndroid Build Coastguard Worker
338*bebae9c0SAndroid Build Coastguard Worker
339*bebae9c0SAndroid Build Coastguard Worker // create streaming media player
Java_com_example_nativemedia_NativeMedia_createStreamingMediaPlayer(JNIEnv * env,jclass clazz,jstring filename)340*bebae9c0SAndroid Build Coastguard Worker jboolean Java_com_example_nativemedia_NativeMedia_createStreamingMediaPlayer(JNIEnv* env,
341*bebae9c0SAndroid Build Coastguard Worker jclass clazz, jstring filename)
342*bebae9c0SAndroid Build Coastguard Worker {
343*bebae9c0SAndroid Build Coastguard Worker XAresult res;
344*bebae9c0SAndroid Build Coastguard Worker
345*bebae9c0SAndroid Build Coastguard Worker // convert Java string to UTF-8
346*bebae9c0SAndroid Build Coastguard Worker const char *utf8 = (*env)->GetStringUTFChars(env, filename, NULL);
347*bebae9c0SAndroid Build Coastguard Worker assert(NULL != utf8);
348*bebae9c0SAndroid Build Coastguard Worker
349*bebae9c0SAndroid Build Coastguard Worker // open the file to play
350*bebae9c0SAndroid Build Coastguard Worker file = fopen(utf8, "rb");
351*bebae9c0SAndroid Build Coastguard Worker if (file == NULL) {
352*bebae9c0SAndroid Build Coastguard Worker ALOGE("Failed to open %s", utf8);
353*bebae9c0SAndroid Build Coastguard Worker return JNI_FALSE;
354*bebae9c0SAndroid Build Coastguard Worker }
355*bebae9c0SAndroid Build Coastguard Worker
356*bebae9c0SAndroid Build Coastguard Worker // configure data source
357*bebae9c0SAndroid Build Coastguard Worker XADataLocator_AndroidBufferQueue loc_abq = { XA_DATALOCATOR_ANDROIDBUFFERQUEUE, NB_BUFFERS };
358*bebae9c0SAndroid Build Coastguard Worker XADataFormat_MIME format_mime = {
359*bebae9c0SAndroid Build Coastguard Worker XA_DATAFORMAT_MIME, XA_ANDROID_MIME_MP2TS, XA_CONTAINERTYPE_MPEG_TS };
360*bebae9c0SAndroid Build Coastguard Worker XADataSource dataSrc = {&loc_abq, &format_mime};
361*bebae9c0SAndroid Build Coastguard Worker
362*bebae9c0SAndroid Build Coastguard Worker // configure audio sink
363*bebae9c0SAndroid Build Coastguard Worker XADataLocator_OutputMix loc_outmix = { XA_DATALOCATOR_OUTPUTMIX, outputMixObject };
364*bebae9c0SAndroid Build Coastguard Worker XADataSink audioSnk = { &loc_outmix, NULL };
365*bebae9c0SAndroid Build Coastguard Worker
366*bebae9c0SAndroid Build Coastguard Worker // configure image video sink
367*bebae9c0SAndroid Build Coastguard Worker XADataLocator_NativeDisplay loc_nd = {
368*bebae9c0SAndroid Build Coastguard Worker XA_DATALOCATOR_NATIVEDISPLAY, // locatorType
369*bebae9c0SAndroid Build Coastguard Worker // the video sink must be an ANativeWindow
370*bebae9c0SAndroid Build Coastguard Worker // created from a Surface or SurfaceTextureClient
371*bebae9c0SAndroid Build Coastguard Worker (void*)theNativeWindow, // hWindow
372*bebae9c0SAndroid Build Coastguard Worker // must be NULL
373*bebae9c0SAndroid Build Coastguard Worker NULL // hDisplay
374*bebae9c0SAndroid Build Coastguard Worker };
375*bebae9c0SAndroid Build Coastguard Worker XADataSink imageVideoSink = {&loc_nd, NULL};
376*bebae9c0SAndroid Build Coastguard Worker
377*bebae9c0SAndroid Build Coastguard Worker // declare interfaces to use
378*bebae9c0SAndroid Build Coastguard Worker XAboolean required[NB_MAXAL_INTERFACES]
379*bebae9c0SAndroid Build Coastguard Worker = {XA_BOOLEAN_TRUE, XA_BOOLEAN_TRUE, XA_BOOLEAN_TRUE};
380*bebae9c0SAndroid Build Coastguard Worker XAInterfaceID iidArray[NB_MAXAL_INTERFACES]
381*bebae9c0SAndroid Build Coastguard Worker = {XA_IID_PLAY, XA_IID_ANDROIDBUFFERQUEUESOURCE,
382*bebae9c0SAndroid Build Coastguard Worker XA_IID_STREAMINFORMATION};
383*bebae9c0SAndroid Build Coastguard Worker
384*bebae9c0SAndroid Build Coastguard Worker
385*bebae9c0SAndroid Build Coastguard Worker // create media player
386*bebae9c0SAndroid Build Coastguard Worker res = (*engineEngine)->CreateMediaPlayer(engineEngine, &playerObj, &dataSrc,
387*bebae9c0SAndroid Build Coastguard Worker NULL, &audioSnk, &imageVideoSink, NULL, NULL,
388*bebae9c0SAndroid Build Coastguard Worker NB_MAXAL_INTERFACES /*XAuint32 numInterfaces*/,
389*bebae9c0SAndroid Build Coastguard Worker iidArray /*const XAInterfaceID *pInterfaceIds*/,
390*bebae9c0SAndroid Build Coastguard Worker required /*const XAboolean *pInterfaceRequired*/);
391*bebae9c0SAndroid Build Coastguard Worker assert(XA_RESULT_SUCCESS == res);
392*bebae9c0SAndroid Build Coastguard Worker
393*bebae9c0SAndroid Build Coastguard Worker // release the Java string and UTF-8
394*bebae9c0SAndroid Build Coastguard Worker (*env)->ReleaseStringUTFChars(env, filename, utf8);
395*bebae9c0SAndroid Build Coastguard Worker
396*bebae9c0SAndroid Build Coastguard Worker // realize the player
397*bebae9c0SAndroid Build Coastguard Worker res = (*playerObj)->Realize(playerObj, XA_BOOLEAN_FALSE);
398*bebae9c0SAndroid Build Coastguard Worker assert(XA_RESULT_SUCCESS == res);
399*bebae9c0SAndroid Build Coastguard Worker
400*bebae9c0SAndroid Build Coastguard Worker // get the play interface
401*bebae9c0SAndroid Build Coastguard Worker res = (*playerObj)->GetInterface(playerObj, XA_IID_PLAY, &playerPlayItf);
402*bebae9c0SAndroid Build Coastguard Worker assert(XA_RESULT_SUCCESS == res);
403*bebae9c0SAndroid Build Coastguard Worker
404*bebae9c0SAndroid Build Coastguard Worker // get the stream information interface (for video size)
405*bebae9c0SAndroid Build Coastguard Worker res = (*playerObj)->GetInterface(playerObj, XA_IID_STREAMINFORMATION, &playerStreamInfoItf);
406*bebae9c0SAndroid Build Coastguard Worker assert(XA_RESULT_SUCCESS == res);
407*bebae9c0SAndroid Build Coastguard Worker
408*bebae9c0SAndroid Build Coastguard Worker // get the volume interface
409*bebae9c0SAndroid Build Coastguard Worker res = (*playerObj)->GetInterface(playerObj, XA_IID_VOLUME, &playerVolItf);
410*bebae9c0SAndroid Build Coastguard Worker assert(XA_RESULT_SUCCESS == res);
411*bebae9c0SAndroid Build Coastguard Worker
412*bebae9c0SAndroid Build Coastguard Worker // get the Android buffer queue interface
413*bebae9c0SAndroid Build Coastguard Worker res = (*playerObj)->GetInterface(playerObj, XA_IID_ANDROIDBUFFERQUEUESOURCE, &playerBQItf);
414*bebae9c0SAndroid Build Coastguard Worker assert(XA_RESULT_SUCCESS == res);
415*bebae9c0SAndroid Build Coastguard Worker
416*bebae9c0SAndroid Build Coastguard Worker // specify which events we want to be notified of
417*bebae9c0SAndroid Build Coastguard Worker res = (*playerBQItf)->SetCallbackEventsMask(playerBQItf, XA_ANDROIDBUFFERQUEUEEVENT_PROCESSED);
418*bebae9c0SAndroid Build Coastguard Worker
419*bebae9c0SAndroid Build Coastguard Worker // use the play interface to set up a callback for the XA_PLAYEVENT_HEADATEND event */
420*bebae9c0SAndroid Build Coastguard Worker res = (*playerPlayItf)->SetCallbackEventsMask(playerPlayItf, XA_PLAYEVENT_HEADATEND);
421*bebae9c0SAndroid Build Coastguard Worker assert(XA_RESULT_SUCCESS == res);
422*bebae9c0SAndroid Build Coastguard Worker res = (*playerPlayItf)->RegisterCallback(playerPlayItf,
423*bebae9c0SAndroid Build Coastguard Worker PlayCallback /*callback*/, NULL /*pContext*/);
424*bebae9c0SAndroid Build Coastguard Worker assert(XA_RESULT_SUCCESS == res);
425*bebae9c0SAndroid Build Coastguard Worker
426*bebae9c0SAndroid Build Coastguard Worker // register the callback from which OpenMAX AL can retrieve the data to play
427*bebae9c0SAndroid Build Coastguard Worker res = (*playerBQItf)->RegisterCallback(playerBQItf, AndroidBufferQueueCallback, NULL);
428*bebae9c0SAndroid Build Coastguard Worker assert(XA_RESULT_SUCCESS == res);
429*bebae9c0SAndroid Build Coastguard Worker
430*bebae9c0SAndroid Build Coastguard Worker // we want to be notified of the video size once it's found, so we register a callback for that
431*bebae9c0SAndroid Build Coastguard Worker res = (*playerStreamInfoItf)->RegisterStreamChangeCallback(playerStreamInfoItf,
432*bebae9c0SAndroid Build Coastguard Worker StreamChangeCallback, NULL);
433*bebae9c0SAndroid Build Coastguard Worker
434*bebae9c0SAndroid Build Coastguard Worker // enqueue the initial buffers
435*bebae9c0SAndroid Build Coastguard Worker if (!enqueueInitialBuffers(JNI_FALSE)) {
436*bebae9c0SAndroid Build Coastguard Worker return JNI_FALSE;
437*bebae9c0SAndroid Build Coastguard Worker }
438*bebae9c0SAndroid Build Coastguard Worker
439*bebae9c0SAndroid Build Coastguard Worker // prepare the player
440*bebae9c0SAndroid Build Coastguard Worker res = (*playerPlayItf)->SetPlayState(playerPlayItf, XA_PLAYSTATE_PAUSED);
441*bebae9c0SAndroid Build Coastguard Worker assert(XA_RESULT_SUCCESS == res);
442*bebae9c0SAndroid Build Coastguard Worker
443*bebae9c0SAndroid Build Coastguard Worker // set the volume
444*bebae9c0SAndroid Build Coastguard Worker res = (*playerVolItf)->SetVolumeLevel(playerVolItf, 0);//-300);
445*bebae9c0SAndroid Build Coastguard Worker assert(XA_RESULT_SUCCESS == res);
446*bebae9c0SAndroid Build Coastguard Worker
447*bebae9c0SAndroid Build Coastguard Worker // start the playback
448*bebae9c0SAndroid Build Coastguard Worker res = (*playerPlayItf)->SetPlayState(playerPlayItf, XA_PLAYSTATE_PLAYING);
449*bebae9c0SAndroid Build Coastguard Worker assert(XA_RESULT_SUCCESS == res);
450*bebae9c0SAndroid Build Coastguard Worker
451*bebae9c0SAndroid Build Coastguard Worker return JNI_TRUE;
452*bebae9c0SAndroid Build Coastguard Worker }
453*bebae9c0SAndroid Build Coastguard Worker
454*bebae9c0SAndroid Build Coastguard Worker
455*bebae9c0SAndroid Build Coastguard Worker // set the playing state for the streaming media player
Java_com_example_nativemedia_NativeMedia_setPlayingStreamingMediaPlayer(JNIEnv * env,jclass clazz,jboolean isPlaying)456*bebae9c0SAndroid Build Coastguard Worker void Java_com_example_nativemedia_NativeMedia_setPlayingStreamingMediaPlayer(JNIEnv* env,
457*bebae9c0SAndroid Build Coastguard Worker jclass clazz, jboolean isPlaying)
458*bebae9c0SAndroid Build Coastguard Worker {
459*bebae9c0SAndroid Build Coastguard Worker XAresult res;
460*bebae9c0SAndroid Build Coastguard Worker
461*bebae9c0SAndroid Build Coastguard Worker // make sure the streaming media player was created
462*bebae9c0SAndroid Build Coastguard Worker if (NULL != playerPlayItf) {
463*bebae9c0SAndroid Build Coastguard Worker
464*bebae9c0SAndroid Build Coastguard Worker // set the player's state
465*bebae9c0SAndroid Build Coastguard Worker res = (*playerPlayItf)->SetPlayState(playerPlayItf, isPlaying ?
466*bebae9c0SAndroid Build Coastguard Worker XA_PLAYSTATE_PLAYING : XA_PLAYSTATE_PAUSED);
467*bebae9c0SAndroid Build Coastguard Worker assert(XA_RESULT_SUCCESS == res);
468*bebae9c0SAndroid Build Coastguard Worker
469*bebae9c0SAndroid Build Coastguard Worker }
470*bebae9c0SAndroid Build Coastguard Worker
471*bebae9c0SAndroid Build Coastguard Worker }
472*bebae9c0SAndroid Build Coastguard Worker
473*bebae9c0SAndroid Build Coastguard Worker
474*bebae9c0SAndroid Build Coastguard Worker // shut down the native media system
Java_com_example_nativemedia_NativeMedia_shutdown(JNIEnv * env,jclass clazz)475*bebae9c0SAndroid Build Coastguard Worker void Java_com_example_nativemedia_NativeMedia_shutdown(JNIEnv* env, jclass clazz)
476*bebae9c0SAndroid Build Coastguard Worker {
477*bebae9c0SAndroid Build Coastguard Worker // destroy streaming media player object, and invalidate all associated interfaces
478*bebae9c0SAndroid Build Coastguard Worker if (playerObj != NULL) {
479*bebae9c0SAndroid Build Coastguard Worker (*playerObj)->Destroy(playerObj);
480*bebae9c0SAndroid Build Coastguard Worker playerObj = NULL;
481*bebae9c0SAndroid Build Coastguard Worker playerPlayItf = NULL;
482*bebae9c0SAndroid Build Coastguard Worker playerBQItf = NULL;
483*bebae9c0SAndroid Build Coastguard Worker playerStreamInfoItf = NULL;
484*bebae9c0SAndroid Build Coastguard Worker playerVolItf = NULL;
485*bebae9c0SAndroid Build Coastguard Worker }
486*bebae9c0SAndroid Build Coastguard Worker
487*bebae9c0SAndroid Build Coastguard Worker // destroy output mix object, and invalidate all associated interfaces
488*bebae9c0SAndroid Build Coastguard Worker if (outputMixObject != NULL) {
489*bebae9c0SAndroid Build Coastguard Worker (*outputMixObject)->Destroy(outputMixObject);
490*bebae9c0SAndroid Build Coastguard Worker outputMixObject = NULL;
491*bebae9c0SAndroid Build Coastguard Worker }
492*bebae9c0SAndroid Build Coastguard Worker
493*bebae9c0SAndroid Build Coastguard Worker // destroy engine object, and invalidate all associated interfaces
494*bebae9c0SAndroid Build Coastguard Worker if (engineObject != NULL) {
495*bebae9c0SAndroid Build Coastguard Worker (*engineObject)->Destroy(engineObject);
496*bebae9c0SAndroid Build Coastguard Worker engineObject = NULL;
497*bebae9c0SAndroid Build Coastguard Worker engineEngine = NULL;
498*bebae9c0SAndroid Build Coastguard Worker }
499*bebae9c0SAndroid Build Coastguard Worker
500*bebae9c0SAndroid Build Coastguard Worker // close the file
501*bebae9c0SAndroid Build Coastguard Worker if (file != NULL) {
502*bebae9c0SAndroid Build Coastguard Worker fclose(file);
503*bebae9c0SAndroid Build Coastguard Worker file = NULL;
504*bebae9c0SAndroid Build Coastguard Worker }
505*bebae9c0SAndroid Build Coastguard Worker
506*bebae9c0SAndroid Build Coastguard Worker // make sure we don't leak native windows
507*bebae9c0SAndroid Build Coastguard Worker if (theNativeWindow != NULL) {
508*bebae9c0SAndroid Build Coastguard Worker ANativeWindow_release(theNativeWindow);
509*bebae9c0SAndroid Build Coastguard Worker theNativeWindow = NULL;
510*bebae9c0SAndroid Build Coastguard Worker }
511*bebae9c0SAndroid Build Coastguard Worker }
512*bebae9c0SAndroid Build Coastguard Worker
513*bebae9c0SAndroid Build Coastguard Worker
514*bebae9c0SAndroid Build Coastguard Worker // set the surface
Java_com_example_nativemedia_NativeMedia_setSurface(JNIEnv * env,jclass clazz,jobject surface)515*bebae9c0SAndroid Build Coastguard Worker void Java_com_example_nativemedia_NativeMedia_setSurface(JNIEnv *env, jclass clazz, jobject surface)
516*bebae9c0SAndroid Build Coastguard Worker {
517*bebae9c0SAndroid Build Coastguard Worker // obtain a native window from a Java surface
518*bebae9c0SAndroid Build Coastguard Worker theNativeWindow = ANativeWindow_fromSurface(env, surface);
519*bebae9c0SAndroid Build Coastguard Worker }
520*bebae9c0SAndroid Build Coastguard Worker
521*bebae9c0SAndroid Build Coastguard Worker
522*bebae9c0SAndroid Build Coastguard Worker // rewind the streaming media player
Java_com_example_nativemedia_NativeMedia_rewindStreamingMediaPlayer(JNIEnv * env,jclass clazz)523*bebae9c0SAndroid Build Coastguard Worker void Java_com_example_nativemedia_NativeMedia_rewindStreamingMediaPlayer(JNIEnv *env, jclass clazz)
524*bebae9c0SAndroid Build Coastguard Worker {
525*bebae9c0SAndroid Build Coastguard Worker // make sure the streaming media player was created
526*bebae9c0SAndroid Build Coastguard Worker if (NULL != playerBQItf && NULL != file) {
527*bebae9c0SAndroid Build Coastguard Worker // first wait for buffers currently in queue to be drained
528*bebae9c0SAndroid Build Coastguard Worker int ok;
529*bebae9c0SAndroid Build Coastguard Worker ok = pthread_mutex_lock(&mutex);
530*bebae9c0SAndroid Build Coastguard Worker assert(0 == ok);
531*bebae9c0SAndroid Build Coastguard Worker discontinuity = JNI_TRUE;
532*bebae9c0SAndroid Build Coastguard Worker // wait for discontinuity request to be observed by buffer queue callback
533*bebae9c0SAndroid Build Coastguard Worker // FIXME sorry, can't rewind after EOS
534*bebae9c0SAndroid Build Coastguard Worker while (discontinuity && !reachedEof) {
535*bebae9c0SAndroid Build Coastguard Worker ok = pthread_cond_wait(&cond, &mutex);
536*bebae9c0SAndroid Build Coastguard Worker assert(0 == ok);
537*bebae9c0SAndroid Build Coastguard Worker }
538*bebae9c0SAndroid Build Coastguard Worker ok = pthread_mutex_unlock(&mutex);
539*bebae9c0SAndroid Build Coastguard Worker assert(0 == ok);
540*bebae9c0SAndroid Build Coastguard Worker }
541*bebae9c0SAndroid Build Coastguard Worker
542*bebae9c0SAndroid Build Coastguard Worker }
543