applications/osmo4_android/jni/wrapper.cpp (865 lines of code) (raw):
/*
* GPAC - Multimedia Framework C SDK
*
* Authors: Jean Le Feuvre
* Copyright (c) Telecom ParisTech 2009-
* All rights reserved
*
* Created by NGO Van Luyen, Ivica ARSOV / ARTEMIS / Telecom SudParis /Institut TELECOM on Oct, 2010
*
* This file is part of GPAC / Wrapper
*
* GPAC is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* GPAC is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <jni.h>
#include <gpac/terminal.h>
#include <gpac/thread.h>
#include <gpac/options.h>
#include <gpac/modules/service.h>
#include <gpac/internal/terminal_dev.h>
#include <gpac/internal/compositor_dev.h>
#include "wrapper.h"
#include "wrapper_jni.c"
#include <math.h>
#include <android/log.h>
#define TAG "GPAC_WRAPPER"
#define LOGV(X, Y) __android_log_print(ANDROID_LOG_VERBOSE, TAG, X, Y)
#define LOGD(X, Y) __android_log_print(ANDROID_LOG_DEBUG, TAG, X, Y)
#define LOGE(X, Y) __android_log_print(ANDROID_LOG_ERROR, TAG, X, Y)
#define LOGW(X, Y) __android_log_print(ANDROID_LOG_WARN, TAG, X, Y)
#define LOGI(X, Y) __android_log_print(ANDROID_LOG_INFO, TAG, X, Y)
#include <pthread.h>
static JavaVM* javaVM = NULL;
static pthread_key_t jni_thread_env_key = 0;
//these two are used by modumles - define them when using static module build
#ifdef GPAC_STATIC_MODULES
#ifdef __cplusplus
extern "C" {
#endif
JavaVM* GetJavaVM()
{
return javaVM;
}
JNIEnv* GetEnv()
{
JNIEnv* env = 0;
if (javaVM) javaVM->GetEnv((void**)(&env), JNI_VERSION_1_2);
return env;
}
#ifdef __cplusplus
}
#endif
#endif
/**
* This method is called when a pthread is destroyed, so we can delete the JNI env
*/
static void jni_destroy_env_func(void * env) {
LOGI("Destroying a thread with attached data, env=%p.\n", env);
JavaEnvTh * jniEnv = (JavaEnvTh *) env;
if (jniEnv) {
/*jniEnv->env->DeleteLocalRef(&jniEnv->cbk_displayMessage);
jniEnv->env->DeleteLocalRef(&jniEnv->cbk_onProgress);
jniEnv->env->DeleteLocalRef(&jniEnv->cbk_showKeyboard);
jniEnv->env->DeleteLocalRef(&jniEnv->cbk_setCaption);
jniEnv->env->DeleteLocalRef(&jniEnv->cbk_onLog);*/
memset(jniEnv, 0, sizeof(JavaEnvTh));
gf_free(jniEnv);
}
pthread_setspecific(jni_thread_env_key, NULL);
if (javaVM)
javaVM->DetachCurrentThread();
}
static int jniRegisterNativeMethods(JNIEnv* env, const char* className,
const JNINativeMethod* gMethods, int numMethods)
{
int res;
jclass clazz;
clazz = env->FindClass(className);
if (clazz == NULL) {
LOGE("Native registration unable to find class '%s'\n", className);
return -1;
}
LOGI("Registering %d methods...\n", numMethods );
res = env->RegisterNatives(clazz, gMethods, numMethods);
if (res < 0) {
LOGE("RegisterNatives failed for '%s'\n", className);
return res;
}
return 0;
}
static JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{ "createInstance",
"(Lcom/gpac/Osmo4/GpacCallback;IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)J",
(void*)&Java_com_gpac_Osmo4_GPACInstance_createInstance
},
{ "gpacdisconnect",
"()V",
(void*)Java_com_gpac_Osmo4_GPACInstance_gpacdisconnect
},
{ "gpacrender",
"()V",
(void*)Java_com_gpac_Osmo4_GPACInstance_gpacrender
},
{ "gpacresize",
"(II)V",
(void*)Java_com_gpac_Osmo4_GPACInstance_gpacresize
},
{ "gpacfree",
"()V",
(void*)Java_com_gpac_Osmo4_GPACInstance_gpacfree
},
{ "gpaceventkeypress",
"(IIIII)V",
(void*)Java_com_gpac_Osmo4_GPACInstance_gpaceventkeypress
},
{ "gpaceventmousedown",
"(FF)V",
(void*)Java_com_gpac_Osmo4_GPACInstance_gpaceventmousedown
},
{ "gpaceventmouseup",
"(FF)V",
(void*)Java_com_gpac_Osmo4_GPACInstance_gpaceventmouseup
},
{ "gpaceventmousemove",
"(FF)V",
(void*)Java_com_gpac_Osmo4_GPACInstance_gpaceventmousemove
},
{ "setGpacPreference",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
(void*)Java_com_gpac_Osmo4_GPACInstance_setGpacPreference
},
{ "setGpacLogs",
"(Ljava/lang/String;)V",
(void*)Java_com_gpac_Osmo4_GPACInstance_setGpacLogs
},
NULL
};
jint JNI_OnUnLoad(JavaVM* vm, void* reserved) {
LOGI("Deleting library, vm=%p...\n", vm);
if (pthread_key_delete(jni_thread_env_key)) {
LOGW("Failed to delete key jni_thread_env_key jni_thread_env_key=%p\n", jni_thread_env_key);
}
javaVM = NULL;
jni_thread_env_key = (int) NULL;
}
#define NUM_JNI_VERSIONS 4
//---------------------------------------------------------------------------------------------------
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
int res;
int jniV;
int allowedVersions[NUM_JNI_VERSIONS];
const char * className = "com/gpac/Osmo4/GPACInstance";
allowedVersions[0] = JNI_VERSION_1_6;
allowedVersions[1] = JNI_VERSION_1_4;
allowedVersions[2] = JNI_VERSION_1_2;
allowedVersions[3] = JNI_VERSION_1_1;
JNIEnv * env;
if (!vm)
return -1;
for (int i = 0 ; i < NUM_JNI_VERSIONS; i++) {
jniV = allowedVersions[i];
if (vm->GetEnv((void**)(&env), jniV) == JNI_OK) {
LOGI("Selected JNI VERSION[%d]\n", i);
break;
} else {
if (i == NUM_JNI_VERSIONS - 1) {
LOGW("Failed to find any supported JNI VERSION of the %d proposed.", NUM_JNI_VERSIONS);
return -1;
}
}
}
javaVM = vm;
LOGI("Registering %s natives\n", className);
res = jniRegisterNativeMethods(env, className, sMethods, (sizeof(sMethods) - 1)/sizeof(JNINativeMethod));
if (res < 0) {
LOGE("Failed to register native methods, result was = %d, try to continue anyway...\n", res);
/*return -1;*/
}
LOGI("Registering natives DONE, now registering pthread_keys with destructor=%p\n", &jni_destroy_env_func);
int ret = pthread_key_create(&jni_thread_env_key, &jni_destroy_env_func);
if (ret) {
LOGE("Failed to register jni_thread_env_key jni_thread_env_key=%p\n", jni_thread_env_key);
}
return jniV;
}
//---------------------------------------------------------------------------------------------------
//CNativeWrapper
//-------------------------------
CNativeWrapper::CNativeWrapper() {
do_log = 1;
m_term = NULL;
m_mx = NULL;
mainJavaEnv = NULL;
#ifndef GPAC_GUI_ONLY
memset(&m_user, 0, sizeof(GF_User));
memset(&m_rti, 0, sizeof(GF_SystemRTInfo));
#endif
}
//-------------------------------
CNativeWrapper::~CNativeWrapper() {
debug_log("~CNativeWrapper()");
JavaEnvTh * env = getEnv();
if (env && env->cbk_obj)
env->env->DeleteGlobalRef(env->cbk_obj);
Shutdown();
debug_log("~CNativeWrapper() : DONE\n");
}
//-------------------------------
void CNativeWrapper::debug_log(const char* msg) {
LOGV("%s", msg);
}
//-------------------------------
void CNativeWrapper::Shutdown()
{
debug_log("shutdown");
if (m_term)
gf_term_disconnect(m_term);
if (m_mx)
gf_mx_del(m_mx);
m_mx = NULL;
#ifndef GPAC_GUI_ONLY
if (m_term) {
GF_Terminal *t = m_term;
m_term = NULL;
gf_term_del(t);
}
if (m_user.config) {
gf_cfg_del(m_user.config);
m_user.config = NULL;
}
if (m_user.modules) {
gf_modules_del(m_user.modules);
m_user.modules = NULL;
}
#endif
m_term = NULL;
gf_sys_close();
debug_log("shutdown end");
}
void CNativeWrapper::setJavaEnv(JavaEnvTh * envToSet, JNIEnv *env, jobject callback) {
assert( envToSet );
jclass localRef = env->GetObjectClass(callback);
envToSet->env = env;
envToSet->javaThreadId = gf_th_id();
envToSet->cbk_obj = callback;
envToSet->cbk_displayMessage =
env->GetMethodID(localRef, "displayMessage", "(Ljava/lang/String;Ljava/lang/String;I)V");
envToSet->cbk_onProgress =
env->GetMethodID(localRef, "onProgress", "(Ljava/lang/String;II)V");
envToSet->cbk_onLog =
env->GetMethodID(localRef, "onLog", "(IILjava/lang/String;)V");
envToSet->cbk_setCaption =
env->GetMethodID(localRef, "setCaption", "(Ljava/lang/String;)V");
envToSet->cbk_showKeyboard =
env->GetMethodID(localRef, "showKeyboard", "(Z)V");
env->DeleteLocalRef(localRef);
}
static u32 beforeThreadExits(void * param) {
/* Ivica - I think there is no need for this because the detach is done in jni_destroy_env_func()
/*LOGI("Before Thread exist, detach the JavaVM from Thread for thread %p...\n", gf_th_current());
if (javaVM)
javaVM->DetachCurrentThread();
*/
}
JavaEnvTh * CNativeWrapper::getEnv() {
JNIEnv *env;
JavaEnvTh * javaEnv;
if (!javaVM) {
debug_log("************* No JVM Found ************");
return NULL;
}
javaEnv = (JavaEnvTh*) pthread_getspecific( jni_thread_env_key );
if (javaEnv)
return javaEnv;
javaEnv = (JavaEnvTh *) gf_malloc(sizeof(JavaEnvTh));
if (!javaEnv)
return NULL;
memset(javaEnv, 0, sizeof(JavaEnvTh));
javaVM->AttachCurrentThread(&env, NULL);
if (!env) {
LOGE("Attaching to thread did failed for thread id=%d", gf_th_id());
gf_free(javaEnv);
return NULL;
}
LOGI("Rebuilding methods for thread %d", gf_th_id());
setJavaEnv(javaEnv, env, mainJavaEnv->cbk_obj);
if (pthread_setspecific(jni_thread_env_key, javaEnv)) {
LOGE("Failed to set specific thread data to jni_thread_env_key for thread=%d. No ENV available !", gf_th_id());
gf_free(javaEnv);
return NULL;
}
GF_Thread * t;
LOGI("Getting current Thread %d...", gf_th_id());
t = gf_th_current();
LOGI("Getting current Thread DONE = %p, now registering before exit...", t);
if (GF_OK != gf_register_before_exit_function(gf_th_current(), &beforeThreadExits)) {
LOGE("Failed to register exit function for thread %p, no javaEnv for current thread.", gf_th_current());
//javaVM->DetachCurrentThread();
gf_free(javaEnv);
javaEnv = NULL;
}
LOGI("Registering DONE for %d", gf_th_id());
return javaEnv;
}
//-------------------------------
int CNativeWrapper::MessageBox(const char* msg, const char* title, GF_Err status) {
LOGV("MessageBox start %s", msg);
JavaEnvTh * env = getEnv();
if (!env || !env->cbk_displayMessage)
return 0;
env->env->PushLocalFrame(2);
jstring tit = env->env->NewStringUTF(title?title:"null");
jstring mes = env->env->NewStringUTF(msg?msg:"null");
env->env->CallVoidMethod(env->cbk_obj, env->cbk_displayMessage, mes, tit, status);
env->env->PopLocalFrame(NULL);
LOGV("MessageBox done %s", msg);
return 1;
}
//-------------------------------
void CNativeWrapper::DisplayRTI() {
#ifndef GPAC_GUI_ONLY
// display some system informations ?
#endif
}
//-------------------------------
int CNativeWrapper::Quit(int code) {
Shutdown();
// send shutdown request to java
return code;
}
#include <stdio.h>
void CNativeWrapper::on_fm_request(void *cbk, u32 type, u32 param, int *value) {
CNativeWrapper * self = (CNativeWrapper *) cbk;
JavaEnvTh *envth = self->getEnv();
envth->env->PushLocalFrame(1);
switch(type) {
case 0: // Get PI
case 1: // Get RT
case 2: // Get PS
jint jvalue;
jvalue = envth->env->CallIntMethod(envth->cbk_obj, envth->cbk_onFmRequest, type, param);
*value = (int)jvalue;
break;
case 3: // Set Freq
case 4: // Set Volume
envth->env->CallVoidMethod(envth->cbk_obj, envth->cbk_onFmRequest, type, param);
break;
}
envth->env->PopLocalFrame(NULL);
}
//-------------------------------
void CNativeWrapper::on_gpac_log(void *cbk, u32 ll, u32 lm, const char *fmt, va_list list) {
char szMsg[4096];
const char * tag;
char unknTag[32];
int level = (ll == GF_LOG_ERROR) ? ANDROID_LOG_ERROR : ANDROID_LOG_DEBUG;
vsnprintf(szMsg, 4096, fmt, list);
CNativeWrapper * self = (CNativeWrapper *) cbk;
if (!self)
goto displayInAndroidlogs;
{
JavaEnvTh *env = self->getEnv();
jstring msg;
if (!env || !env->cbk_onLog)
goto displayInAndroidlogs;
env->env->PushLocalFrame(1);
msg = env->env->NewStringUTF(szMsg);
env->env->CallVoidMethod(env->cbk_obj, env->cbk_onLog, level, lm, msg);
env->env->PopLocalFrame(NULL);
return;
}
displayInAndroidlogs:
{
/* When no callback is properly set, we use direct logging */
switch( lm) {
case GF_LOG_CORE:
tag="GF_LOG_CORE";
break;
case GF_LOG_CODING:
tag="GF_LOG_CODING";
break;
case GF_LOG_CONTAINER:
tag="GF_LOG_CONTAINER";
break;
case GF_LOG_NETWORK:
tag="GF_LOG_NETWORK";
break;
case GF_LOG_RTP:
tag="GF_LOG_RTP";
break;
case GF_LOG_AUTHOR:
tag="GF_LOG_AUTHOR";
break;
case GF_LOG_SYNC:
tag="GF_LOG_SYNC";
break;
case GF_LOG_CODEC:
tag="GF_LOG_CODEC";
break;
case GF_LOG_PARSER:
tag="GF_LOG_PARSER";
break;
case GF_LOG_MEDIA:
tag="GF_LOG_MEDIA";
break;
case GF_LOG_SCENE:
tag="GF_LOG_SCENE";
break;
case GF_LOG_SCRIPT:
tag="GF_LOG_SCRIPT";
break;
case GF_LOG_INTERACT:
tag="GF_LOG_INTERACT";
break;
case GF_LOG_COMPOSE:
tag="GF_LOG_COMPOSE";
break;
case GF_LOG_CACHE:
tag="GF_LOG_CACHE";
break;
case GF_LOG_MMIO:
tag="GF_LOG_MMIO";
break;
case GF_LOG_RTI:
tag="GF_LOG_RTI";
break;
case GF_LOG_SMIL:
tag="GF_LOG_SMIL";
break;
case GF_LOG_MEMORY:
tag="GF_LOG_MEMORY";
break;
case GF_LOG_AUDIO:
tag="GF_LOG_AUDIO";
break;
case GF_LOG_MODULE:
tag="GF_LOG_MODULE";
break;
case GF_LOG_MUTEX:
tag="GF_LOG_MUTEX";
break;
default:
snprintf(unknTag, 32, "GPAC_UNKNOWN[%d]", lm);
tag = unknTag;
}
__android_log_print(level, tag, "%s\n", szMsg);
}
}
//-------------------------------
Bool CNativeWrapper::GPAC_EventProc(void *cbk, GF_Event *evt) {
if (cbk)
{
CNativeWrapper* ptr = (CNativeWrapper*)cbk;
char msg[4096];
msg[0] = 0;
LOGD("GPAC_EventProc() Message=%d", evt->type);
switch (evt->type) {
case GF_EVENT_CLICK:
case GF_EVENT_MOUSEUP:
case GF_EVENT_MOUSEDOWN:
case GF_EVENT_MOUSEOVER:
case GF_EVENT_MOUSEOUT:
case GF_EVENT_MOUSEMOVE:
case GF_EVENT_MOUSEWHEEL:
case GF_EVENT_KEYUP:
case GF_EVENT_KEYDOWN:
case GF_EVENT_LONGKEYPRESS:
case GF_EVENT_TEXTINPUT:
/* We ignore all these events */
break;
case GF_EVENT_MEDIA_SETUP_BEGIN:
case GF_EVENT_MEDIA_SETUP_DONE:
case GF_EVENT_MEDIA_LOAD_START:
case GF_EVENT_MEDIA_PLAYING:
case GF_EVENT_MEDIA_WAITING:
case GF_EVENT_MEDIA_PROGRESS:
case GF_EVENT_MEDIA_LOAD_DONE:
case GF_EVENT_ABORT:
case GF_EVENT_ERROR:
LOGD("GPAC_EventProc() Media Event detected = [index=%d]", evt->type - GF_EVENT_MEDIA_SETUP_BEGIN);
break;
case GF_EVENT_MESSAGE:
{
ptr->debug_log("GPAC_EventProc start");
if ( evt->message.message )
{
strcat(msg, evt->message.message);
strcat(msg, ": ");
}
strcat(msg, gf_error_to_string(evt->message.error));
ptr->debug_log(msg);
//ptr->MessageBox(msg, evt->message.service ? evt->message.service : "GF_EVENT_MESSAGE", evt->message.error);
ptr->debug_log("GPAC_EventProc end");
};
break;
case GF_EVENT_CONNECT:
if (evt->connect.is_connected)
ptr->MessageBox("Connected", "Connected to scene", GF_OK);
else
ptr->MessageBox("Disconnected", "Disconnected from scene.", GF_OK);
break;
case GF_EVENT_PROGRESS:
{
const char * szTitle;;
if (evt->progress.progress_type==0)
szTitle = "Buffering";
else if (evt->progress.progress_type==1)
szTitle = "Downloading...";
else if (evt->progress.progress_type==2)
szTitle = "Import ";
else
szTitle = "Unknown Progress Event";
ptr->Osmo4_progress_cbk(ptr, szTitle, evt->progress.done, evt->progress.total);
gf_set_progress(szTitle, evt->progress.done, evt->progress.total);
}
break;
case GF_EVENT_TEXT_EDITING_START:
case GF_EVENT_TEXT_EDITING_END:
{
JavaEnvTh * env = ptr->getEnv();
if (!env || !env->cbk_showKeyboard)
return GF_FALSE;
LOGI("Needs to display/hide the Virtual Keyboard (%d)", evt->type);
env->env->CallVoidMethod(env->cbk_obj, env->cbk_showKeyboard, GF_EVENT_TEXT_EDITING_START == evt->type);
LOGV("Done showing virtual keyboard (%d)", evt->type);
}
break;
case GF_EVENT_EOS:
LOGI("EOS Reached (%d)", evt->type);
break;
case GF_EVENT_DISCONNECT:
/* FIXME : not sure about this behaviour */
if (ptr)
ptr->disconnect();
break;
case GF_EVENT_NAVIGATE:
ptr->navigate( evt);
break;
default:
LOGI("Unknown Message %d", evt->type);
}
}
return GF_FALSE;
}
void CNativeWrapper::navigate( GF_Event* evt)
{
if (gf_term_is_supported_url(m_term, evt->navigate.to_url, GF_TRUE, GF_TRUE))
{
gf_term_navigate_to(m_term, evt->navigate.to_url);
}
}
void CNativeWrapper::progress_cbk(const char *title, u64 done, u64 total) {
JavaEnvTh *env = getEnv();
if (!env || !env->cbk_onProgress)
return;
//debug_log("Osmo4_progress_cbk start");
env->env->PushLocalFrame(1);
jstring js = env->env->NewStringUTF(title);
env->env->CallVoidMethod(env->cbk_obj, env->cbk_onProgress, js, done, total);
env->env->PopLocalFrame(NULL);
//debug_log("Osmo4_progress_cbk end");
}
//-------------------------------
void CNativeWrapper::Osmo4_progress_cbk(const void *usr, const char *title, u64 done, u64 total) {
if (!usr)
return;
CNativeWrapper * self = (CNativeWrapper *) usr;
self->progress_cbk(title, done, total);
}
//-------------------------------
void CNativeWrapper::SetupLogs() {
const char *opt;
debug_log("SetupLogs()");
gf_mx_p(m_mx);
gf_log_set_tools_levels( gf_cfg_get_key(m_user.config, "General", "Logs") );
gf_log_set_callback(this, on_gpac_log);
gf_mx_v(m_mx);
GF_LOG(GF_LOG_INFO, GF_LOG_CORE, ("Osmo4 logs initialized\n"));
/* Test for JNI invocations, should work properly
int k;
for (k = 0 ; k < 512; k++){
GF_LOG(GF_LOG_INFO, GF_LOG_CORE, ("Message %d\n", k));
}*/
}
//-------------------------------
// dir should end with /
int CNativeWrapper::init(JNIEnv * env, void * bitmap, jobject * callback, int width, int height, const char * cfg_dir, const char * modules_dir, const char * cache_dir, const char * font_dir, const char * gui_dir, const char * urlToLoad) {
LOGI("Initializing GPAC with URL=%s...", urlToLoad);
strcpy(m_cfg_dir, cfg_dir);
strcpy(m_modules_dir, modules_dir);
strcpy(m_cache_dir, cache_dir);
strcpy(m_font_dir, font_dir);
char m_cfg_filename[GF_MAX_PATH];
strcpy(m_cfg_filename, m_cfg_dir);
strcat(m_cfg_filename, "GPAC.cfg");
int m_Width = width;
int m_Height = height;
int first_launch = 0;
const char *opt;
m_window = env;
m_session = bitmap;
if (!mainJavaEnv)
mainJavaEnv = (JavaEnvTh *) gf_malloc(sizeof(JavaEnvTh));
memset(mainJavaEnv, 0, sizeof(JavaEnvTh));
setJavaEnv(mainJavaEnv, env, env->NewGlobalRef(*callback));
if (pthread_setspecific( jni_thread_env_key, mainJavaEnv)) {
LOGE("Failed to set specific thread data to jni_thread_env_key=%p for main thread !", jni_thread_env_key);
}
m_mx = gf_mx_new("Osmo4");
//load config file
LOGI("Loading User Config %s...", "GPAC.cfg");
m_user.config = gf_cfg_force_new(cfg_dir, "GPAC.cfg");
gf_set_progress_callback(this, Osmo4_progress_cbk);
opt = gf_cfg_get_key(m_user.config, "General", "ModulesDirectory");
if (!opt) {
FILE * fstart;
char msg[256];
LOGI("First launch, initializing new Config %s...", "GPAC.cfg");
/*hardcode module directory*/
gf_cfg_set_key(m_user.config, "Downloader", "CleanCache", "yes");
/*startup file*/
snprintf(msg, 256, "%sgui.bt", gui_dir);
fstart = gf_fopen(msg, "r");
if (fstart) {
gf_fclose(fstart);
gf_cfg_set_key(m_user.config, "General", "StartupFile", msg);
} else {
gf_cfg_set_key(m_user.config, "General", "#StartupFile", msg);
}
gf_cfg_set_key(m_user.config, "GUI", "UnhideControlPlayer", "1");
/*setup UDP traffic autodetect*/
gf_cfg_set_key(m_user.config, "Network", "AutoReconfigUDP", "yes");
gf_cfg_set_key(m_user.config, "Network", "UDPTimeout", "10000");
gf_cfg_set_key(m_user.config, "Network", "BufferLength", "3000");
gf_cfg_set_key(m_user.config, "Compositor", "TextureTextMode", "Default");
//gf_cfg_set_key(m_user.config, "Compositor", "FrameRate", "30");
gf_cfg_set_key(m_user.config, "Audio", "ForceConfig", "no");
gf_cfg_set_key(m_user.config, "Audio", "NumBuffers", "1");
gf_cfg_set_key(m_user.config, "FontEngine", "FontReader", "ft_font");
//Storage directory
if (!gf_cfg_get_key(m_user.config, "General", "StorageDirectory")) {
snprintf(msg, 256, "%sStorage", cfg_dir);
if (!gf_dir_exists(msg)) gf_mkdir(msg);
gf_cfg_set_key(m_user.config, "General", "StorageDirectory", msg);
}
}
/* All of this has to be done for every instance */
gf_cfg_set_key(m_user.config, "General", "ModulesDirectory", modules_dir ? modules_dir : GPAC_MODULES_DIR);
gf_cfg_set_key(m_user.config, "General", "CacheDirectory", cache_dir ? cache_dir : GPAC_CACHE_DIR);
gf_cfg_set_key(m_user.config, "General", "LastWorkingDir", cfg_dir);
gf_cfg_set_key(m_user.config, "General", "DeviceType", "Android");
gf_cfg_set_key(m_user.config, "FontEngine", "FontDirectory", GPAC_FONT_DIR);
gf_cfg_set_key(m_user.config, "Video", "DriverName", "Android Video Output");
gf_cfg_set_key(m_user.config, "Audio", "DriverName", "Android Audio Output");
opt = gf_cfg_get_key(m_user.config, "General", "ModulesDirectory");
LOGI("loading modules in directory %s...", opt);
m_user.modules = gf_modules_new(opt, m_user.config);
if (!m_user.modules || !gf_modules_get_count(m_user.modules)) {
LOGE("No modules found in directory %s !", opt);
if (m_user.modules)
gf_modules_del(m_user.modules);
gf_cfg_del(m_user.config);
m_user.config = NULL;
return Quit(KErrGeneral);
}
/*we don't thread the visual compositor to be able to minimize the app and still have audio running*/
m_user.init_flags = GF_TERM_NO_COMPOSITOR_THREAD;
m_user.opaque = this;
m_user.os_window_handler = m_window;
m_user.os_display = m_session;
m_user.EventProc = GPAC_EventProc;
if (!javaVM) {
LOGE("NO JAVA VM FOUND, m_user=%p !!!!\n", &m_user);
return Quit(KErrGeneral);
}
LOGD("Loading GPAC terminal, m_user=%p...", &m_user);
gf_sys_init(GF_FALSE);
gf_fm_request_set_callback(this, on_fm_request);
SetupLogs();
m_term = gf_term_new(&m_user);
if (!m_term) {
LOGE("Cannot load GPAC Terminal with m_user=%p", m_user);
MessageBox("Cannot load GPAC terminal", "Fatal Error", GF_SERVICE_ERROR);
gf_modules_del(m_user.modules);
m_user.modules = NULL;
gf_cfg_del(m_user.config);
m_user.config = NULL;
return Quit(KErrGeneral);
}
/*force fullscreen*/
gf_term_set_option(m_term, GF_OPT_FULLSCREEN, 1);
//setAudioEnvironment(javaVM);
LOGD("Setting term size m_user=%p...", &m_user);
gf_term_set_size(m_term, m_Width, m_Height);
opt = gf_cfg_get_key(m_user.config, "General", "StartupFile");
LOGD("File loaded at startup=%s.", opt);
if (!urlToLoad)
urlToLoad = opt;
if (urlToLoad) {
LOGI("Connecting to %s...", urlToLoad);
gf_term_connect(m_term, urlToLoad);
}
debug_log("init end");
LOGD("Saving config file %s...\n", m_cfg_filename);
gf_cfg_save(m_user.config);
LOGI("Initialization complete, config file saved as %s.\n", m_cfg_filename);
return 0;
}
//-------------------------------
int CNativeWrapper::connect(const char *url)
{
const char *str;
char the_url[256];
if (m_term)
{
debug_log("Starting to connect ...");
str = gf_cfg_get_key(m_user.config, "General", "StartupFile");
if (str)
{
gf_cfg_set_key(m_user.config, "Temp", "GUIStartupFile", url);
gf_term_connect(m_term, str);
}
if( url )
{
gf_term_connect_from_time(m_term, url, 0, GF_FALSE);
}
}
debug_log("connected ...");
}
void CNativeWrapper::setGpacPreference( const char * category, const char * name, const char * value)
{
if (m_user.config) {
gf_cfg_set_key(m_user.config, category, name, value);
gf_cfg_save(m_user.config);
}
}
//-----------------------------------------------------
void CNativeWrapper::disconnect() {
if (m_term) {
debug_log("disconnecting");
gf_term_disconnect(m_term);
debug_log("disconnected ...");
}
}
//-----------------------------------------------------
void CNativeWrapper::step(void * env, void * bitmap) {
m_window = env;
m_session = bitmap;
//debug_log("Step ...");
if (!m_term) {
debug_log("step(): No m_term found.");
return;
} else if (!m_term->compositor)
debug_log("step(): No compositor found.");
else if (!m_term->compositor->video_out)
debug_log("step(): No video_out found");
else if (!m_term->compositor->video_out->Setup)
debug_log("step(): No video_out->Setup found");
else {
m_term->compositor->frame_draw_type = GF_SC_DRAW_FRAME;
gf_term_process_step(m_term);
}
}
//-----------------------------------------------------
void CNativeWrapper::setAudioEnvironment(JavaVM* javaVM) {
if (!m_term) {
debug_log("setAudioEnvironment(): no m_term found.");
return;
}
debug_log("setAudioEnvironment start");
m_term->compositor->audio_renderer->audio_out->Setup(m_term->compositor->audio_renderer->audio_out, javaVM, 0, 0);
debug_log("setAudioEnvironment end");
}
//-----------------------------------------------------
void CNativeWrapper::resize(int w, int h) {
if (!m_term)
return;
debug_log("resize start");
gf_term_set_size(m_term, w, h);
debug_log("resize end");
}
//-----------------------------------------------------
void CNativeWrapper::onMouseDown(float x, float y) {
if (!m_term)
return;
debug_log("onMouseDown start");
//char msg[100];
//sprintf(msg, "onMousedown x=%f, y=%f", x, y );
//debug_log(msg);
GF_Event evt;
evt.type = GF_EVENT_MOUSEDOWN;
evt.mouse.button = GF_MOUSE_LEFT;
evt.mouse.x = x;
evt.mouse.y = y;
int ret = gf_term_user_event(m_term, &evt);
debug_log("onMouseDown end");
}
//-----------------------------------------------------
void CNativeWrapper::onMouseUp(float x, float y) {
if (!m_term)
return;
debug_log("onMouseUp start");
//char msg[100];
//sprintf(msg, "onMouseUp x=%f, y=%f", x, y );
//debug_log(msg);
GF_Event evt;
evt.type = GF_EVENT_MOUSEUP;
evt.mouse.button = GF_MOUSE_LEFT;
evt.mouse.x = x;
evt.mouse.y = y;
int ret = gf_term_user_event(m_term, &evt);
debug_log("onMouseUp end");
}
//-----------------------------------------------------
void CNativeWrapper::onMouseMove(float x, float y) {
if (!m_term)
return;
GF_Event evt;
evt.type = GF_EVENT_MOUSEMOVE;
evt.mouse.button = GF_MOUSE_LEFT;
evt.mouse.x = x;
evt.mouse.y = y;
int ret = gf_term_user_event(m_term, &evt);
}
//-----------------------------------------------------
void CNativeWrapper::onKeyPress(int keycode, int rawkeycode, int up, int flag, int unicode) {
if (!m_term)
return;
debug_log("onKeyPress start");
GF_Event evt;
memset(&evt, 0, sizeof(GF_Event));
if (up == 0) evt.type = GF_EVENT_KEYUP;
else evt.type = GF_EVENT_KEYDOWN;
evt.key.flags = 0;
evt.key.hw_code = rawkeycode;
translate_key(keycode, &evt.key);
//evt.key.key_code = GF_KEY_A;
int ret = gf_term_user_event(m_term, &evt);
if (evt.type == GF_EVENT_KEYUP && unicode) {
memset(&evt, 0, sizeof(GF_Event));
evt.type = GF_EVENT_TEXTINPUT;
evt.character.unicode_char = unicode;
ret = gf_term_user_event(m_term, &evt);
}
}
//-----------------------------------------------------
void CNativeWrapper::translate_key(ANDROID_KEYCODE keycode, GF_EventKey *evt) {
evt->flags = 0;
switch (keycode) {
case ANDROID_KEYCODE_BACK:
evt->key_code = GF_KEY_BACKSPACE;
evt->hw_code = 8;
break;
case ANDROID_KEYCODE_TAB:
evt->key_code = GF_KEY_TAB;
evt->hw_code = 9;
break;
case ANDROID_KEYCODE_CLEAR:
evt->key_code = GF_KEY_CLEAR;
break;
case ANDROID_KEYCODE_ENTER:
evt->key_code = GF_KEY_ENTER;
evt->hw_code = 13;
break;
case ANDROID_KEYCODE_SHIFT_LEFT:
evt->key_code = GF_KEY_SHIFT;
break;
case ANDROID_KEYCODE_SHIFT_RIGHT:
evt->key_code = GF_KEY_SHIFT;
break;
case ANDROID_KEYCODE_ALT_LEFT:
evt->key_code = GF_KEY_ALT;
break;
case ANDROID_KEYCODE_ALT_RIGHT:
evt->key_code = GF_KEY_ALT;
break;
case ANDROID_KEYCODE_SPACE:
evt->key_code = GF_KEY_SPACE;
evt->hw_code = 32;
break;
case ANDROID_KEYCODE_HOME:
evt->key_code = GF_KEY_HOME;
break;
case ANDROID_KEYCODE_DPAD_LEFT:
evt->key_code = GF_KEY_LEFT;
break;
case ANDROID_KEYCODE_DPAD_UP:
evt->key_code = GF_KEY_UP;
break;
case ANDROID_KEYCODE_DPAD_RIGHT:
evt->key_code = GF_KEY_RIGHT;
break;
case ANDROID_KEYCODE_DPAD_DOWN:
evt->key_code = GF_KEY_DOWN;
break;
case ANDROID_KEYCODE_DEL:
evt->key_code = GF_KEY_BACKSPACE;
evt->hw_code = 8;
break;
case ANDROID_KEYCODE_0:
evt->key_code = GF_KEY_0;
evt->flags = GF_KEY_EXT_NUMPAD;
break;
case ANDROID_KEYCODE_1:
evt->key_code = GF_KEY_1;
evt->flags = GF_KEY_EXT_NUMPAD;
break;
case ANDROID_KEYCODE_2:
evt->key_code = GF_KEY_2;
evt->flags = GF_KEY_EXT_NUMPAD;
break;
case ANDROID_KEYCODE_3:
evt->key_code = GF_KEY_3;
evt->flags = GF_KEY_EXT_NUMPAD;
break;
case ANDROID_KEYCODE_4:
evt->key_code = GF_KEY_4;
evt->flags = GF_KEY_EXT_NUMPAD;
break;
case ANDROID_KEYCODE_5:
evt->key_code = GF_KEY_5;
evt->flags = GF_KEY_EXT_NUMPAD;
break;
case ANDROID_KEYCODE_6:
evt->key_code = GF_KEY_6;
evt->flags = GF_KEY_EXT_NUMPAD;
break;
case ANDROID_KEYCODE_7:
evt->key_code = GF_KEY_7;
evt->flags = GF_KEY_EXT_NUMPAD;
break;
case ANDROID_KEYCODE_8:
evt->key_code = GF_KEY_8;
evt->flags = GF_KEY_EXT_NUMPAD;
break;
case ANDROID_KEYCODE_9:
evt->key_code = GF_KEY_9;
evt->flags = GF_KEY_EXT_NUMPAD;
break;
/*thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) */
/* VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) */
default:
if ((keycode>=ANDROID_KEYCODE_A) && (keycode<=ANDROID_KEYCODE_Z)) {
evt->key_code = GF_KEY_A + keycode - ANDROID_KEYCODE_A;
} else {
evt->key_code = GF_KEY_UNIDENTIFIED;
}
break;
}
}
//-----------------------------------------------------
void CNativeWrapper::setGpacLogs(const char *tools_at_level)
{
gf_log_set_tools_levels(tools_at_level);
}
//---------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------