diff --git a/.gitignore b/.gitignore index f180c06fd5a40a346201cc5d373544a297bd935a..17b4b682cb70c43d59d34f3437b971ab4550913e 100644 --- a/.gitignore +++ b/.gitignore @@ -75,3 +75,7 @@ ID # IDE stuffs nbproject + +# JNI generated files +*_wrap.cpp +*_loader.c diff --git a/daemon/src/Android.mk b/daemon/src/Android.mk index 21991c8dc18dca045ea849a305b17ed2133b822f..51476033dc89bafc0368e65d30ee7ea9c8fd3227 100644 --- a/daemon/src/Android.mk +++ b/daemon/src/Android.mk @@ -21,6 +21,7 @@ MY_DBUS=libdbus-c++-0.9.0-android MY_SPEEX=speex MY_OPENSSL=openssl MY_LIBYAML=libyaml +MY_JNI_WRAP=callmanager_wrap.cpp include $(CLEAR_VARS) @@ -67,6 +68,7 @@ LOCAL_SRC_FILES := \ config/yamlnode.cpp \ dbus/callmanager.cpp \ dbus/configurationmanager.cpp \ + dbus/$(MY_JNI_WRAP) \ dbus/instance.cpp \ dbus/dbusmanager.cpp \ history/historyitem.cpp \ diff --git a/daemon/src/JavaJNI2CJNI_Load.py b/daemon/src/JavaJNI2CJNI_Load.py new file mode 100755 index 0000000000000000000000000000000000000000..fa10db4ad654d56c9f867d887d1ec7e3272fd582 --- /dev/null +++ b/daemon/src/JavaJNI2CJNI_Load.py @@ -0,0 +1,85 @@ +#!/usr/bin/python +import getopt, sys +import re +from string import Template + +def type_to_signature(itype): + if len(itype) > 2: + if itype[-2:] == '[]': + return "[%s" % type_to_signature(itype[:-2]) + if itype == "int": + return "I" + if itype == "long": + return "J" + if itype == "void": + return "V" + if itype == "boolean": + return "Z" + if itype == "byte": + return "B" + if itype == "char": + return "C" + if itype == "short": + return "S" + if itype == "float": + return "F" + if itype == "double": + return "D" + if itype == "String": + return "Ljava/lang/String;" + if itype == "Object": + return "Ljava/lang/Object;" + return "Lcom/savoirfairelinux/sflphone/client/%s;" % itype + +def parse_java_file(input_stream, package, module): + outputs = [] + package_prefix = "Java_%s_%sJNI" % (package.replace(".", "_"), module) + for line in input_stream: + definition = re.match(r'.*public final static native ([^\( ]*) ([^\)]*)\(([^)]*)\).*',line) + if definition is not None: + retour = definition.group(1) + name = definition.group(2) + args = definition.group(3) + args_sigs = [] + args_frags = args.split(',') + for args_frag in args_frags: + argf = re.match(r'(\b)?([^ ]+) .*', args_frag.strip()) + if argf is not None: + args_sigs.append(type_to_signature(argf.group(2))) + sig = "(%s)%s" % (''.join(args_sigs), type_to_signature(retour)) + outputs.append("{\"%s\", \"%s\", (void*)& %s_%s}" % (name, sig, package_prefix, name.replace('_', '_1'))) + return outputs + +def render_to_template(defs, template_string): + template = Template(template_string) + return template.substitute(defs= ",\r\n".join(defs) ) + + +if __name__ == "__main__": + try: + opts, args = getopt.getopt(sys.argv[1:], "i:o:t:m:p:", ["input=", "output=", "template=", "module=", "package="]) + except getopt.GetoptError, err: + # print help information and exit: + print str(err) # will print something like "option -a not recognized" + sys.exit(2) + input_stream = None + output_file = None + template_string = None + package = "" + module = "" + for o, a in opts: + if o in ("-i", "--input"): + input_stream = open(a) + if o in ("-o", "--output"): + output_file = open(a, "w") + if o in ("-t", "--template"): + template_string = open(a).read() + if o in ("-m", "--module"): + module = a + if o in ("-p", "--package"): + package = a + + defs = parse_java_file(input_stream, package, module) + output_file.write(render_to_template(defs, template_string)) + output_file.close() + input_stream.close() diff --git a/daemon/src/dbus/callmanager.i b/daemon/src/dbus/callmanager.i new file mode 100644 index 0000000000000000000000000000000000000000..cc9f049eb17e44977f1ca2eedb13c58cd9b23f1d --- /dev/null +++ b/daemon/src/dbus/callmanager.i @@ -0,0 +1,83 @@ + +/* File : callmanager.i */ +%module sflphoneservice + +%include "typemaps.i" +%include "std_string.i" /* std::string typemaps */ +%include "enums.swg" +%include "arrays_java.i"; +%include "carrays.i"; + +/* void* shall be handled as byte arrays */ +%typemap(jni) void * "void *" +%typemap(jtype) void * "byte[]" +%typemap(jstype) void * "byte[]" +%typemap(javain) void * "$javainput" +%typemap(in) void * %{ + $1 = $input; +%} +%typemap(javadirectorin) void * "$jniinput" +%typemap(out) void * %{ + $result = $1; +%} +%typemap(javaout) void * { + return $jnicall; +} + +/* not parsed by SWIG but needed by generated C files */ +%{ +#include <managerimpl.h> +#include <dbus/callmanager.h> + +namespace Manager { +extern ManagerImpl& instance(); +} +%} + +/* parsed by SWIG to generate all the glue */ +/* %include "../managerimpl.h" */ +/* %include <dbus/callmanager.h> */ + +/* %nodefaultctor ManagerImpl; +%nodefaultdtor ManagerImpl; */ + +class ManagerImpl { +public: + void init(const std::string &config_file); + void setPath(const std::string &path); + bool outgoingCall(const std::string&, const std::string&, const std::string&, const std::string& = ""); + void refuseCall(const std::string& id); + bool answerCall(const std::string& id); + void hangupCall(const std::string& id); +}; + +//%rename(Manager_instance) Manager::instance; + +namespace Manager { + +ManagerImpl& Manager::instance() +{ + // Meyers singleton + static ManagerImpl instance_; + return instance_; +} + +} + +//class CallManager { +//public: +// /* Manager::instance().outgoingCall */ +// void placeCall(const std::string& accountID, +// const std::string& callID, +// const std::string& to); +// /* Manager::instance().refuseCall */ +// void refuse(const std::string& callID); +// /* Manager::instance().answerCall */ +// void accept(const std::string& callID); +// /* Manager::instance().hangupCall */ +// void hangUp(const std::string& callID); +//}; + +#ifndef SWIG +/* some bad declarations */ +#endif diff --git a/daemon/src/managerimpl.cpp b/daemon/src/managerimpl.cpp index 2b64814f63ce79ddd4bb414bffaef1380a40ba0d..9f5c88f903065014bd50bf547c6dfa8549bee8dd 100644 --- a/daemon/src/managerimpl.cpp +++ b/daemon/src/managerimpl.cpp @@ -91,7 +91,9 @@ #include <sstream> #include <sys/types.h> // mkdir(2) #include <sys/stat.h> // mkdir(2) +#include <jni.h> +extern JavaVM *gJavaVM; static jobject gManagerObject, gDataObject; ManagerImpl::ManagerImpl() : @@ -314,6 +316,7 @@ void ManagerImpl::init(const std::string &config_file) //history_.load(preferences.getHistoryLimit()); registerAccounts(); + INFO("init ended"); } void ManagerImpl::setPath(const std::string &path) { diff --git a/daemon/src/sflphoneservice.c.template b/daemon/src/sflphoneservice.c.template new file mode 100644 index 0000000000000000000000000000000000000000..8755bcf21b3f1f9092f405e04aea220c72d7e8f7 --- /dev/null +++ b/daemon/src/sflphoneservice.c.template @@ -0,0 +1,104 @@ +#include "logger.h" + +JavaVM *gJavaVM; +const char *ksflphoneservicePath = "com/savoirfairelinux/sflphone/client/sflphoneserviceJNI"; +//const char *kManagerPath = "com/savoirfairelinux/sflphone/client/ManagerImpl"; +//static jobject gManagerObject, gDataObject; + +//void initClassHelper(JNIEnv *env, const char *path, jobject *objptr) { +// jclass cls; +// +// INFO("initClassHelper"); +// +// cls= env->FindClass(path); +// if(!cls) { +// ERROR("initClassHelper: failed to get %s class reference", path); +// return; +// } +// jmethodID constr = env->GetMethodID(cls, "<init>", "()V"); +// INFO("initClassHelper: %s method found", path); +// +// if(!constr) { +// ERROR("initClassHelper: failed to get %s constructor", path); +// return; +// } +// jobject obj = env->NewObject(cls, constr); +// INFO("initClassHelper: %s constructor found", path); +// +// if(!obj) { +// ERROR("initClassHelper: failed to create a %s object", path); +// return; +// } +// /* protect cached object instances from Android GC */ +// (*objptr) = env->NewGlobalRef(obj); +// INFO("initClassHelper: object found %x", objptr); +//} + +void deinitClassHelper(JNIEnv *env, jobject obj) { + INFO("deinitClassHelper"); + + /* delete cached object instances */ + env->DeleteGlobalRef(obj); + INFO("deinitClassHelper: object %x deleted", obj); +} + +JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { + JNIEnv *env; + jclass clazz; + jint r; + + INFO("JNI_OnLoad"); + + //Assume it is c++ + r = vm->GetEnv ((void **) &env, JNI_VERSION_1_6); + if (r != JNI_OK) { + ERROR("JNI_OnLoad: failed to get the environment using GetEnv()"); + return -1; + } + INFO("JNI_Onload: GetEnv %p", env); + + clazz = env->FindClass (ksflphoneservicePath); + if (!clazz) { + ERROR("JNI_Onload: whoops, %s class not found!", ksflphoneservicePath); + } + gJavaVM = vm; + INFO("JNI_Onload: JavaVM %p", gJavaVM); + + /* put instances of class object we need into cache */ + //initClassHelper(env, kManagerPath, &gManagerObject); + + JNINativeMethod methods[] = { + + $defs + + }; + + r = env->RegisterNatives (clazz, methods, (int) (sizeof(methods) / sizeof(methods[0]))); + return JNI_VERSION_1_6; +} + +void JNI_OnUnLoad(JavaVM* vm, void* reserved) { + JNIEnv* env; + jclass clazz; + + INFO("JNI_OnUnLoad"); + + /* get env */ + if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { + ERROR("JNI_OnUnLoad: failed to get the environment using GetEnv()"); + return; + } + INFO("JNI_OnUnLoad: GetEnv %p", env); + + /* Get jclass with env->FindClass */ + clazz = env->FindClass(ksflphoneservicePath); + if (!clazz) { + ERROR("JNI_OnUnLoad: whoops, %s class not found!", ksflphoneservicePath); + } + + /* remove instances of class object we need into cache */ + //deinitClassHelper(env, gManagerObject); + + env->UnregisterNatives(clazz); + INFO("JNI_OnUnLoad: Native functions unregistered"); +}