native-media-jni.c revision c6853892c94800e72c0bd676d5d2136d48cea76e
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>
2137dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi#define LOG_NDEBUG 0
2297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten#define LOG_TAG "NativeMedia"
2397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten#include <utils/Log.h>
24f183d0fd23f1c0f45ceaf280d404f1b0709a699aJean-Michel Trivi
25c6853892c94800e72c0bd676d5d2136d48cea76eGlenn Kasten#include <OMXAL/OpenMAXAL.h>
26c6853892c94800e72c0bd676d5d2136d48cea76eGlenn Kasten#include <OMXAL/OpenMAXAL_Android.h>
27f183d0fd23f1c0f45ceaf280d404f1b0709a699aJean-Michel Trivi
28295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivi#include <android/native_window_jni.h>
2997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
3097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// engine interfaces
3197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenstatic XAObjectItf engineObject = NULL;
3297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenstatic XAEngineItf engineEngine;
3397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
3497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// output mix interfaces
3597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenstatic XAObjectItf outputMixObject = NULL;
3697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
3797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// streaming media player interfaces
38eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivistatic XAObjectItf             playerObj = NULL;
39eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivistatic XAPlayItf               playerPlayItf = NULL;
40eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivistatic XAAndroidBufferQueueItf playerBQItf = NULL;
4137dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivistatic XAStreamInformationItf  playerStreamInfoItf = NULL;
4237dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivistatic XAVolumeItf             playerVolItf;
43d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi// number of required interfaces for the MediaPlayer creation
4437dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi#define NB_MAXAL_INTERFACES 3 // XAAndroidBufferQueueItf, XAStreamInformationItf and XAPlayItf
4597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
4639310fca2e30101fa6e5168da443581cc60c20bfGlenn Kasten// video sink for the player
47295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivistatic ANativeWindow* theNativeWindow;
4897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
49d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi// number of buffers in our buffer queue
50d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi#define NB_BUFFERS 16
51d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi// we're streaming MPEG-2 transport stream data, operate on transport stream block size
52d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi#define MPEG2_TS_BLOCK_SIZE 188
53d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi// determines how much memory we're dedicating to memory caching
54d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi#define BUFFER_SIZE 20*MPEG2_TS_BLOCK_SIZE // 20 is an arbitrary number chosen here
55d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi
56d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi// where we cache in memory the data to play
57d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivichar dataCache[BUFFER_SIZE * NB_BUFFERS];
58eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi// handle of the file to play
59eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel TriviFILE *file;
6070c49ae2867094072a4365423417ea452bf82231Jean-Michel Trivi// has the app reached the end of the file
6170c49ae2867094072a4365423417ea452bf82231Jean-Michel Trivichar reachedEof = 0;
62eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi
63eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi// AndroidBufferQueueItf callback for an audio player
64eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel TriviXAresult AndroidBufferQueueCallback(
65eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        XAAndroidBufferQueueItf caller,
6637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        void *pCallbackContext,        /* input */
6737dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        void *pBufferContext,          /* input */
6837dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        void *pBufferData,             /* input */
69d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        XAuint32 dataSize,             /* input */
70d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        XAuint32 dataUsed,             /* input */
71d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        const XAAndroidBufferItem *pItems,/* input */
72d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        XAuint32 itemsLength           /* input */)
73eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi{
74d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    // assert(BUFFER_SIZE <= dataSize);
7537dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    if (pBufferData == NULL) {
7637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        // this is the case when our buffer with the EOS message has been consumed
7737dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        return XA_RESULT_SUCCESS;
7837dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    }
7937dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi
8037dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi#if 0
8137dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    // sample code to use the XAVolumeItf
8237dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    XAAndroidBufferQueueState state;
8337dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    (*caller)->GetState(caller, &state);
8437dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    switch (state.index) {
8537dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    case 300:
8637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        (*playerVolItf)->SetVolumeLevel(playerVolItf, -600); // -6dB
8737dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        LOGV("setting volume to -6dB");
8837dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        break;
8937dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    case 400:
9037dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        (*playerVolItf)->SetVolumeLevel(playerVolItf, -1200); // -12dB
9137dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        LOGV("setting volume to -12dB");
9237dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        break;
9337dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    case 500:
9437dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        (*playerVolItf)->SetVolumeLevel(playerVolItf, 0); // full volume
9537dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        LOGV("setting volume to 0dB (full volume)");
9637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        break;
9737dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    case 600:
9837dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        (*playerVolItf)->SetMute(playerVolItf, XA_BOOLEAN_TRUE); // mute
9937dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        LOGV("muting player");
10037dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        break;
10137dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    case 700:
10237dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        (*playerVolItf)->SetMute(playerVolItf, XA_BOOLEAN_FALSE); // unmute
10337dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        LOGV("unmuting player");
10437dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        break;
10537dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    case 800:
10637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        (*playerVolItf)->SetStereoPosition(playerVolItf, -1000);
10737dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        (*playerVolItf)->EnableStereoPosition(playerVolItf, XA_BOOLEAN_TRUE);
10837dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        LOGV("pan sound to the left (hard-left)");
10937dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        break;
11037dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    case 900:
11137dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        (*playerVolItf)->EnableStereoPosition(playerVolItf, XA_BOOLEAN_FALSE);
11237dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        LOGV("disabling stereo position");
11337dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        break;
11437dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    default:
11537dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        break;
11637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    }
11737dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi#endif
11837dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi
119d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    size_t nbRead = fread((void*)pBufferData, 1, BUFFER_SIZE, file);
12037dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    if ((nbRead > 0) && (NULL != pBufferData)) {
12137dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        (*caller)->Enqueue(caller, NULL /*pBufferContext*/,
122d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi                pBufferData /*pData*/,
123d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi                nbRead /*dataLength*/,
124d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi                NULL /*pMsg*/,
125d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi                0 /*msgLength*/);
12670c49ae2867094072a4365423417ea452bf82231Jean-Michel Trivi    } else if (!reachedEof) {
127d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        // signal EOS
128d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        XAAndroidBufferItem msgEos;
129d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        msgEos.itemKey = XA_ANDROID_ITEMKEY_EOS;
130d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        msgEos.itemSize = 0;
131d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        // EOS message has no parameters, so the total size of the message is the size of the key
132d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        //   plus the size if itemSize, both XAuint32
13337dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        (*caller)->Enqueue(caller, NULL /*pBufferContext*/,
13437dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi                NULL /*pData*/, 0 /*dataLength*/,
13537dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi                &msgEos /*pMsg*/,
13637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi                sizeof(XAuint32)*2 /*msgLength*/);
13770c49ae2867094072a4365423417ea452bf82231Jean-Michel Trivi        reachedEof = 1;
138eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    }
139eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi
140eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    return XA_RESULT_SUCCESS;
141eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi}
142eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi
143eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi
14437dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivivoid StreamChangeCallback (XAStreamInformationItf caller,
14537dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        XAuint32 eventId,
14637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        XAuint32 streamIndex,
14737dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        void * pEventData,
14837dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        void * pContext )
14937dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi{
15037dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    if (XA_STREAMCBEVENT_PROPERTYCHANGE == eventId) {
15158432eb9cea995c69b4f905e68b38c1b8216edebGlenn Kasten        LOGD("StreamChangeCallback called for stream %u", streamIndex);
15237dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi
15337dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        XAuint32 domain;
15437dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        if (XA_RESULT_SUCCESS == (*caller)->QueryStreamType(caller, streamIndex, &domain)) {
15537dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi            if (XA_DOMAINTYPE_VIDEO == domain) {
15637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi                XAVideoStreamInformation videoInfo;
15737dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi                if (XA_RESULT_SUCCESS == (*caller)->QueryStreamInformation(caller, streamIndex,
15837dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi                        &videoInfo)) {
15958432eb9cea995c69b4f905e68b38c1b8216edebGlenn Kasten                    LOGI("Found video size %u x %u", videoInfo.width, videoInfo.height);
16037dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi                }
16137dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi            }
16237dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        }
16337dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    }
16437dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi}
16537dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi
16637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi
16797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// create the engine and output mix objects
16897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenvoid Java_com_example_nativemedia_NativeMedia_createEngine(JNIEnv* env, jclass clazz)
16997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten{
170eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    XAresult res;
17197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
17297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // create engine
173eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = xaCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
174eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
17597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
17697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // realize the engine
177eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = (*engineObject)->Realize(engineObject, XA_BOOLEAN_FALSE);
178eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
17997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
18097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // get the engine interface, which is needed in order to create other objects
181eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = (*engineObject)->GetInterface(engineObject, XA_IID_ENGINE, &engineEngine);
182eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
18397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
18497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // create output mix
185eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL);
186eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
18797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
18897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // realize the output mix
189eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = (*outputMixObject)->Realize(outputMixObject, XA_BOOLEAN_FALSE);
190eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
19197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
19297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten}
19397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
19497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
19597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// create streaming media player
19697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenjboolean Java_com_example_nativemedia_NativeMedia_createStreamingMediaPlayer(JNIEnv* env,
19797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten        jclass clazz, jstring filename)
19897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten{
199eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    XAresult res;
20097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
20197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // convert Java string to UTF-8
20297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    const char *utf8 = (*env)->GetStringUTFChars(env, filename, NULL);
20397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    assert(NULL != utf8);
20497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
205eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    // open the file to play
206eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    file = fopen(utf8, "rb");
207eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    if (file == NULL) {
208eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        LOGE("Failed to open %s", utf8);
209eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        return JNI_FALSE;
210eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    }
211eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi
212eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    // configure data source
213d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    XADataLocator_AndroidBufferQueue loc_abq = { XA_DATALOCATOR_ANDROIDBUFFERQUEUE, NB_BUFFERS };
214d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    XADataFormat_MIME format_mime = {
215d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi            XA_DATAFORMAT_MIME, (XAchar *)"video/mp2ts", XA_CONTAINERTYPE_MPEG_TS };
216eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    XADataSource dataSrc = {&loc_abq, &format_mime};
21797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
21897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // configure audio sink
219d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    XADataLocator_OutputMix loc_outmix = { XA_DATALOCATOR_OUTPUTMIX, outputMixObject };
220d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    XADataSink audioSnk = { &loc_outmix, NULL };
22197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
22297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // configure image video sink
223295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivi    XADataLocator_NativeDisplay loc_nd = {
224ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten            XA_DATALOCATOR_NATIVEDISPLAY,        // locatorType
22539310fca2e30101fa6e5168da443581cc60c20bfGlenn Kasten            // the video sink must be an ANativeWindow created from a Surface or SurfaceTexture
226ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten            (void*)theNativeWindow,              // hWindow
227ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten            // must be NULL
228ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten            NULL                                 // hDisplay
229ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten    };
23097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    XADataSink imageVideoSink = {&loc_nd, NULL};
23197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
232eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    // declare interfaces to use
23337dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    XAboolean     required[NB_MAXAL_INTERFACES]
23437dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi                           = {XA_BOOLEAN_TRUE, XA_BOOLEAN_TRUE,           XA_BOOLEAN_TRUE};
23537dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    XAInterfaceID iidArray[NB_MAXAL_INTERFACES]
23637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi                           = {XA_IID_PLAY,     XA_IID_ANDROIDBUFFERQUEUE, XA_IID_STREAMINFORMATION};
23737dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi
238eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi
23997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // create media player
240eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = (*engineEngine)->CreateMediaPlayer(engineEngine, &playerObj, &dataSrc,
241eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi            NULL, &audioSnk, &imageVideoSink, NULL, NULL,
242d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi            NB_MAXAL_INTERFACES /*XAuint32 numInterfaces*/,
243eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi            iidArray /*const XAInterfaceID *pInterfaceIds*/,
244eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi            required /*const XAboolean *pInterfaceRequired*/);
245eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
24697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
24797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // release the Java string and UTF-8
24897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    (*env)->ReleaseStringUTFChars(env, filename, utf8);
24997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
25097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // realize the player
251eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = (*playerObj)->Realize(playerObj, XA_BOOLEAN_FALSE);
252eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
25397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
25497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // get the play interface
255eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = (*playerObj)->GetInterface(playerObj, XA_IID_PLAY, &playerPlayItf);
256eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
257eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi
25837dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    // get the stream information interface (for video size)
25937dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    res = (*playerObj)->GetInterface(playerObj, XA_IID_STREAMINFORMATION, &playerStreamInfoItf);
26037dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
26137dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi
26237dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    // get the volume interface
26337dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    res = (*playerObj)->GetInterface(playerObj, XA_IID_VOLUME, &playerVolItf);
26437dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
26537dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi
266eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    // get the Android buffer queue interface
267eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = (*playerObj)->GetInterface(playerObj, XA_IID_ANDROIDBUFFERQUEUE, &playerBQItf);
268eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
269eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi
270eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    // register the callback from which OpenMAX AL can retrieve the data to play
271d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    res = (*playerBQItf)->RegisterCallback(playerBQItf, AndroidBufferQueueCallback, NULL);
27237dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
27337dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi
27437dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    // we want to be notified of the video size once it's found, so we register a callback for that
27537dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    res = (*playerStreamInfoItf)->RegisterStreamChangeCallback(playerStreamInfoItf,
27637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi            StreamChangeCallback, NULL);
277d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi
278d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    /* Fill our cache */
279d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    if (fread(dataCache, 1, BUFFER_SIZE * NB_BUFFERS, file) <= 0) {
280d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        LOGE("Error filling cache, exiting\n");
281d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        return JNI_FALSE;
282d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    }
283d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    /* Enqueue the content of our cache before starting to play,
284d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi       we don't want to starve the player */
285d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    int i;
286d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    for (i=0 ; i < NB_BUFFERS ; i++) {
28737dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi        res = (*playerBQItf)->Enqueue(playerBQItf, NULL /*pBufferContext*/,
28837dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi                dataCache + i*BUFFER_SIZE, BUFFER_SIZE, NULL, 0);
289d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        assert(XA_RESULT_SUCCESS == res);
290d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    }
291d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi
292eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    // prepare the player
293eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = (*playerPlayItf)->SetPlayState(playerPlayItf, XA_PLAYSTATE_PAUSED);
294eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
295eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi
29637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    // set the volume
29737dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    res = (*playerVolItf)->SetVolumeLevel(playerVolItf, 0);//-300);
29837dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    assert(XA_RESULT_SUCCESS == res);
29937dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi
30037dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi    // start the playback
301eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    res = (*playerPlayItf)->SetPlayState(playerPlayItf, XA_PLAYSTATE_PLAYING);
302eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        assert(XA_RESULT_SUCCESS == res);
30397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
30497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    return JNI_TRUE;
30597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten}
30697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
30797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
30897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// set the playing state for the streaming media player
30997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenvoid Java_com_example_nativemedia_NativeMedia_setPlayingStreamingMediaPlayer(JNIEnv* env,
31097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten        jclass clazz, jboolean isPlaying)
31197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten{
312eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    XAresult res;
31397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
31497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // make sure the streaming media player was created
315eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    if (NULL != playerPlayItf) {
31697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
31797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten        // set the player's state
318eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        res = (*playerPlayItf)->SetPlayState(playerPlayItf, isPlaying ?
31997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten            XA_PLAYSTATE_PLAYING : XA_PLAYSTATE_PAUSED);
320eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        assert(XA_RESULT_SUCCESS == res);
32197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
32297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    }
32397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
32497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten}
32597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
32697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
32797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// shut down the native media system
32897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenvoid Java_com_example_nativemedia_NativeMedia_shutdown(JNIEnv* env, jclass clazz)
32997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten{
33097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // destroy streaming media player object, and invalidate all associated interfaces
331eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    if (playerObj != NULL) {
332eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        (*playerObj)->Destroy(playerObj);
333eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        playerObj = NULL;
334eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        playerPlayItf = NULL;
335eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        playerBQItf = NULL;
33697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    }
33797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
33897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // destroy output mix object, and invalidate all associated interfaces
33997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    if (outputMixObject != NULL) {
34097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten        (*outputMixObject)->Destroy(outputMixObject);
34197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten        outputMixObject = NULL;
34297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    }
34397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
34497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    // destroy engine object, and invalidate all associated interfaces
34597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    if (engineObject != NULL) {
34697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten        (*engineObject)->Destroy(engineObject);
34797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten        engineObject = NULL;
34897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten        engineEngine = NULL;
34997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten    }
35097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
351eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    // close the file
352eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    if (file != NULL) {
353eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi        fclose(file);
354b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        file = NULL;
355eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi    }
356295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivi
357295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivi    // make sure we don't leak native windows
358ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten    if (theNativeWindow != NULL) {
359ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten        ANativeWindow_release(theNativeWindow);
360b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        theNativeWindow = NULL;
361ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten    }
36297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten}
36397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
36497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten
36597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// set the surface
36697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenvoid Java_com_example_nativemedia_NativeMedia_setSurface(JNIEnv *env, jclass clazz, jobject surface)
36797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten{
368295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivi    // obtain a native window from a Java surface
369295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivi    theNativeWindow = ANativeWindow_fromSurface(env, surface);
370ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten}
371ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten
372ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten
373ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten// set the surface texture
374ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kastenvoid Java_com_example_nativemedia_NativeMedia_setSurfaceTexture(JNIEnv *env, jclass clazz,
375ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten        jobject surfaceTexture)
376ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten{
377ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten    // obtain a native window from a Java surface texture
378ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten    theNativeWindow = ANativeWindow_fromSurfaceTexture(env, surfaceTexture);
37997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten}
380