native-media-jni.c revision eae4df541ba1d46f65d37e959baf2127aa632c93
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <assert.h> 18#include <jni.h> 19#include <pthread.h> 20#include <string.h> 21#define LOG_TAG "NativeMedia" 22#include <utils/Log.h> 23//FIXME shouldn't be needed here, but needed for declaration of XA_IID_ANDROIDBUFFERQUEUE 24#include "SLES/OpenSLES.h" 25#include "SLES/OpenSLES_Android.h" 26#include "OMXAL/OpenMAXAL.h" 27#include "OMXAL/OpenMAXAL_Android.h" 28 29// engine interfaces 30static XAObjectItf engineObject = NULL; 31static XAEngineItf engineEngine; 32 33// output mix interfaces 34static XAObjectItf outputMixObject = NULL; 35 36// streaming media player interfaces 37static XAObjectItf playerObj = NULL; 38static XAPlayItf playerPlayItf = NULL; 39static XAAndroidBufferQueueItf playerBQItf = NULL; 40 41// cached surface 42static jobject theSurface; 43static JNIEnv *theEnv; 44 45// handle of the file to play 46FILE *file; 47 48// AndroidBufferQueueItf callback for an audio player 49XAresult AndroidBufferQueueCallback( 50 XAAndroidBufferQueueItf caller, 51 void *pContext, 52 XAuint32 bufferId, 53 XAuint32 bufferLength, 54 void *pBufferDataLocation) 55 56{ 57 size_t nbRead = fread(pBufferDataLocation, 1, bufferLength, file); 58 59 XAAbufferQueueEvent event = XA_ANDROIDBUFFERQUEUE_EVENT_NONE; 60 if (nbRead <= 0) { 61 event = XA_ANDROIDBUFFERQUEUE_EVENT_EOS; 62 } else { 63 event = XA_ANDROIDBUFFERQUEUE_EVENT_NONE; // no event to report 64 } 65 66 // enqueue the data right-away because in this example we're reading from a file, so we 67 // can afford to do that. When streaming from the network, we would write from our cache 68 // to this queue. 69 // last param is NULL because we've already written the data in the buffer queue 70 (*caller)->Enqueue(caller, bufferId, nbRead, event, NULL); 71 72 return XA_RESULT_SUCCESS; 73} 74 75 76// create the engine and output mix objects 77void Java_com_example_nativemedia_NativeMedia_createEngine(JNIEnv* env, jclass clazz) 78{ 79 XAresult res; 80 81 // create engine 82 res = xaCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); 83 assert(XA_RESULT_SUCCESS == res); 84 85 // realize the engine 86 res = (*engineObject)->Realize(engineObject, XA_BOOLEAN_FALSE); 87 assert(XA_RESULT_SUCCESS == res); 88 89 // get the engine interface, which is needed in order to create other objects 90 res = (*engineObject)->GetInterface(engineObject, XA_IID_ENGINE, &engineEngine); 91 assert(XA_RESULT_SUCCESS == res); 92 93 // create output mix 94 res = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL); 95 assert(XA_RESULT_SUCCESS == res); 96 97 // realize the output mix 98 res = (*outputMixObject)->Realize(outputMixObject, XA_BOOLEAN_FALSE); 99 assert(XA_RESULT_SUCCESS == res); 100 101} 102 103 104// create streaming media player 105jboolean Java_com_example_nativemedia_NativeMedia_createStreamingMediaPlayer(JNIEnv* env, 106 jclass clazz, jstring filename) 107{ 108 XAresult res; 109 110 // convert Java string to UTF-8 111 const char *utf8 = (*env)->GetStringUTFChars(env, filename, NULL); 112 assert(NULL != utf8); 113 114 // open the file to play 115 file = fopen(utf8, "rb"); 116 if (file == NULL) { 117 LOGE("Failed to open %s", utf8); 118 return JNI_FALSE; 119 } 120 121 // configure data source 122 XADataLocator_AndroidBufferQueue loc_abq = {XA_DATALOCATOR_ANDROIDBUFFERQUEUE, 0, 0}; 123 XADataFormat_MIME format_mime = {XA_DATAFORMAT_MIME, NULL, XA_CONTAINERTYPE_UNSPECIFIED}; 124 XADataSource dataSrc = {&loc_abq, &format_mime}; 125 126 // configure audio sink 127 XADataLocator_OutputMix loc_outmix = {XA_DATALOCATOR_OUTPUTMIX, outputMixObject}; 128 XADataSink audioSnk = {&loc_outmix, NULL}; 129 130 // configure image video sink 131 XADataLocator_NativeDisplay loc_nd = {XA_DATALOCATOR_NATIVEDISPLAY, theSurface, theEnv}; 132 XADataSink imageVideoSink = {&loc_nd, NULL}; 133 134 // declare interfaces to use 135 XAboolean required[2] = {XA_BOOLEAN_TRUE, XA_BOOLEAN_TRUE}; 136 XAInterfaceID iidArray[2] = {XA_IID_PLAY, XA_IID_ANDROIDBUFFERQUEUE}; 137 138 // create media player 139 res = (*engineEngine)->CreateMediaPlayer(engineEngine, &playerObj, &dataSrc, 140 NULL, &audioSnk, &imageVideoSink, NULL, NULL, 141 2 /*XAuint32 numInterfaces*/, 142 iidArray /*const XAInterfaceID *pInterfaceIds*/, 143 required /*const XAboolean *pInterfaceRequired*/); 144 assert(XA_RESULT_SUCCESS == res); 145 146 // release the Java string and UTF-8 147 (*env)->ReleaseStringUTFChars(env, filename, utf8); 148 149 // realize the player 150 res = (*playerObj)->Realize(playerObj, XA_BOOLEAN_FALSE); 151 assert(XA_RESULT_SUCCESS == res); 152 153 // get the play interface 154 res = (*playerObj)->GetInterface(playerObj, XA_IID_PLAY, &playerPlayItf); 155 assert(XA_RESULT_SUCCESS == res); 156 157 // get the Android buffer queue interface 158 res = (*playerObj)->GetInterface(playerObj, XA_IID_ANDROIDBUFFERQUEUE, &playerBQItf); 159 assert(XA_RESULT_SUCCESS == res); 160 161 // register the callback from which OpenMAX AL can retrieve the data to play 162 res = (*playerBQItf)->RegisterCallback(playerBQItf, AndroidBufferQueueCallback, &playerBQItf); 163 164 // prepare the player 165 res = (*playerPlayItf)->SetPlayState(playerPlayItf, XA_PLAYSTATE_PAUSED); 166 assert(XA_RESULT_SUCCESS == res); 167 168 res = (*playerPlayItf)->SetPlayState(playerPlayItf, XA_PLAYSTATE_PLAYING); 169 assert(XA_RESULT_SUCCESS == res); 170 171 return JNI_TRUE; 172} 173 174 175// set the playing state for the streaming media player 176void Java_com_example_nativemedia_NativeMedia_setPlayingStreamingMediaPlayer(JNIEnv* env, 177 jclass clazz, jboolean isPlaying) 178{ 179 XAresult res; 180 181 // make sure the streaming media player was created 182 if (NULL != playerPlayItf) { 183 184 // set the player's state 185 res = (*playerPlayItf)->SetPlayState(playerPlayItf, isPlaying ? 186 XA_PLAYSTATE_PLAYING : XA_PLAYSTATE_PAUSED); 187 assert(XA_RESULT_SUCCESS == res); 188 189 } 190 191} 192 193 194// shut down the native media system 195void Java_com_example_nativemedia_NativeMedia_shutdown(JNIEnv* env, jclass clazz) 196{ 197 198 // destroy streaming media player object, and invalidate all associated interfaces 199 if (playerObj != NULL) { 200 (*playerObj)->Destroy(playerObj); 201 playerObj = NULL; 202 playerPlayItf = NULL; 203 playerBQItf = NULL; 204 } 205 206 // destroy output mix object, and invalidate all associated interfaces 207 if (outputMixObject != NULL) { 208 (*outputMixObject)->Destroy(outputMixObject); 209 outputMixObject = NULL; 210 } 211 212 // destroy engine object, and invalidate all associated interfaces 213 if (engineObject != NULL) { 214 (*engineObject)->Destroy(engineObject); 215 engineObject = NULL; 216 engineEngine = NULL; 217 } 218 219 // close the file 220 if (file != NULL) { 221 fclose(file); 222 } 223} 224 225 226// set the surface 227void Java_com_example_nativemedia_NativeMedia_setSurface(JNIEnv *env, jclass clazz, jobject surface) 228{ 229 theEnv = env; 230 theSurface = surface; 231} 232