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); } //--------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------