Index: project/branches/projects/jni/pjsip-apps/src/jni/Makefile
===================================================================
--- /pjproject/branches/projects/jni/pjsip-apps/src/jni/Makefile	(revision 4567)
+++ 	(revision )
@@ -1,84 +1,0 @@
-# $Id$
-
-# Get PJ build settings
-include ../../../build.mak
-include $(PJDIR)/build/common.mak
-
-# Get JDK location
-ifeq ("$(JAVA_HOME)","")
-  # Get javac location to determine JDK location
-  JAVAC_PATH = $(shell which javac)
-  ifeq ("$(JAVAC_PATH)","")
-    $(error Cannot determine JDK location using 'which' command. Please define JAVA_HOME envvar)
-  endif
-
-  JAVAC_PATH := $(realpath $(JAVAC_PATH))
-  JAVA_BIN := $(dir $(JAVAC_PATH))
-  JAVA_HOME := $(patsubst %/bin/,%,$(JAVA_BIN))
-endif
-
-# OS specific
-ifeq ($(OS),Windows_NT)
-MY_JNI_LDFLAGS	 = -L$(MY_JDK)/lib -Wl,--kill-at
-MY_JNI_LIB       = $(MY_PACKAGE_BIN)/pjsua.dll
-else
-MY_JNI_LDFLAGS	 = -L$(MY_JDK)/lib -Wl,-soname,pjsua.so
-MY_JNI_LIB       = $(MY_PACKAGE_BIN)/libpjsua.so
-MY_JNI_CFLAGS	 := -fPIC
-endif
-
-# Env settings, e.g: path to SWIG, JDK, java(.exe), javac(.exe)
-MY_SWIG		 = swig
-MY_JDK		 = $(JAVA_HOME)
-MY_JAVA		 = $(MY_JDK)/bin/java
-MY_JAVAC	 = $(MY_JDK)/bin/javac
-MY_JNI_CFLAGS	 := $(MY_JNI_CFLAGS) -I$(MY_JDK)/include -I$(MY_JDK)/include/win32 \
-		   -I$(MY_JDK)/include/linux -I.
-
-# Build settings
-MY_CFLAGS	 = $(PJ_CFLAGS) $(MY_JNI_CFLAGS)
-MY_LDFLAGS	 = $(PJ_LDFLAGS) $(PJ_LDLIBS) $(MY_JNI_LDFLAGS) -static-libstdc++
-
-# Output/intermediate path settings
-MY_PACKAGE	 = org.pjsip.pjsua
-MY_OUT_DIR	 = output
-MY_SWIG_IF	 = $(MY_OUT_DIR)/pjsua.i
-MY_SWIG_FLAG	 = -c++ -I$(MY_OUT_DIR) # -debug-tmsearch -debug-tmused # -Wall
-MY_SWIG_WRAPPER	 = $(MY_OUT_DIR)/pjsua_wrap
-MY_PACKAGE_SRC	 = $(MY_OUT_DIR)/src/$(subst .,/,$(MY_PACKAGE))
-MY_PACKAGE_BIN	 = $(MY_OUT_DIR)/bin
-
-all: $(MY_JNI_LIB) java
-
-clean:
-	rm -rf $(MY_OUT_DIR)
-
-$(MY_SWIG_IF).tmp: swig_gen.py
-	@mkdir -p $(MY_OUT_DIR)
-	python swig_gen.py > $(MY_SWIG_IF).tmp
-
-$(MY_SWIG_IF): header.i $(MY_SWIG_IF).tmp
-	cat header.i > $(MY_SWIG_IF)
-	cat $(MY_SWIG_IF).tmp >> $(MY_SWIG_IF)
-
-$(MY_SWIG_WRAPPER).c: $(MY_SWIG_IF) callbacks.i my_typemaps.i
-	@# Cleanup java outdir first, to remove any old/deprecated java files
-	rm -rf $(MY_PACKAGE_SRC)
-	@mkdir -p $(MY_PACKAGE_SRC)
-	$(MY_SWIG) $(MY_SWIG_FLAG) -o $(MY_SWIG_WRAPPER).c -package $(MY_PACKAGE) \
-		-outdir $(MY_PACKAGE_SRC) -java $(MY_SWIG_IF) > $(MY_SWIG_WRAPPER)-tm.log
-
-$(MY_JNI_LIB): $(MY_SWIG_WRAPPER).c
-	@mkdir -p $(MY_PACKAGE_BIN)
-	$(PJ_CXX) -shared -o $(MY_JNI_LIB) $(MY_SWIG_WRAPPER).c $(MY_OUT_DIR)/callbacks.c \
-		$(MY_CFLAGS) $(MY_LDFLAGS)
-
-java: hello.java
-	@mkdir -p $(MY_PACKAGE_BIN)
-	$(MY_JAVAC) -d $(MY_PACKAGE_BIN) $(MY_PACKAGE_SRC)/*.java
-	$(MY_JAVAC) -d $(MY_PACKAGE_BIN) -classpath "$(MY_PACKAGE_BIN)" hello.java
-
-test: $(MY_PACKAGE_BIN)/hello.class
-	@# Need to specify classpath and library path, alternatively, they can be set via
-	@# CLASSPATH and java.library.path env settings
-	$(MY_JAVA) -cp $(MY_PACKAGE_BIN) -Djava.library.path="$(MY_PACKAGE_BIN)" hello
Index: project/branches/projects/jni/pjsip-apps/src/jni/callbacks.c.template
===================================================================
--- /pjproject/branches/projects/jni/pjsip-apps/src/jni/callbacks.c.template	(revision 4567)
+++ 	(revision )
@@ -1,53 +1,0 @@
-/* $Id$ */
-
-#include "callbacks.h"
-
-/*
- * Wrapper of pjsua_logging_config callback
- */
-static PjsuaLoggingConfigCallback *pjsua_logging_config_cb = NULL;
-
-void pjsua_logging_config_callback_proxy(int level, const char *data, int len)
-{
-  PJ_UNUSED_ARG(len);
-  pjsua_logging_config_cb->on_log(level, data);
-}
-
-void setPjsuaLoggingConfigCallback(PjsuaLoggingConfigCallback *callback)
-{
-  pjsua_logging_config_cb = callback;
-}
-
-
-/*
- * Wrapper of pj_timer_heap_callback
- */
-void pj_timer_heap_callback_proxy(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
-{
-  PjTimerHeapCallback *cb = (PjTimerHeapCallback*)entry->user_data;
-  pj_assert(cb);
-  cb->on_timer(timer_heap, entry);
-}
-
-void setPjTimerHeapCallback(pj_timer_entry *entry, PjTimerHeapCallback *callback)
-{
-  entry->user_data = callback;
-}
-
-
-/*
- * Wrapper of pjsua_callback
- */
-static PjsuaCallback* cb = NULL;
-
-void setPjsuaCallback(PjsuaCallback* callback) {
-  cb = callback;
-}
-
-$PJSUA_CALLBACK_PROXY$
-
-static pjsua_callback my_cb_proxy = {
-  $PJSUA_CALLBACK_DEF$
-};
-
-pjsua_callback* pjsua_callback_proxy = &my_cb_proxy;
Index: project/branches/projects/jni/pjsip-apps/src/jni/callbacks.h.template
===================================================================
--- /pjproject/branches/projects/jni/pjsip-apps/src/jni/callbacks.h.template	(revision 4567)
+++ 	(revision )
@@ -1,47 +1,0 @@
-/* $Id$ */
-
-#include <pjsua-lib/pjsua.h>
-
-/*
- * Wrapper of pjsua_logging_config callback
- */
-class PjsuaLoggingConfigCallback {
-public:
-  virtual void on_log(int level, const char *data) {}
-  virtual ~PjsuaLoggingConfigCallback() {}
-};
-
-#ifndef SWIG /* SWIG should ignore these */
-extern void pjsua_logging_config_callback_proxy(int level, const char *data, int len);
-extern void setPjsuaLoggingConfigCallback(PjsuaLoggingConfigCallback *callback);
-#endif
-
-
-/*
- * Wrapper of pj_timer_heap_callback
- */
-class PjTimerHeapCallback {
-public:
-  virtual void on_timer(pj_timer_heap_t *timer_heap, pj_timer_entry *entry) {}
-  virtual ~PjTimerHeapCallback() {}
-};
-
-#ifndef SWIG /* SWIG should ignore these */
-extern void pj_timer_heap_callback_proxy(pj_timer_heap_t *timer_heap, pj_timer_entry *entry);
-extern void setPjTimerHeapCallback(pj_timer_entry *entry, PjTimerHeapCallback *callback);
-#endif
-
-
-/*
- * Wrapper of pjsua_callback
- */
-class PjsuaCallback {
-public:
-  $PJSUA_CALLBACK_CLASS$
-  virtual ~PjsuaCallback() {}
-};
-
-#ifndef SWIG /* SWIG should ignore these */
-extern void setPjsuaCallback(PjsuaCallback* callback);
-extern pjsua_callback* pjsua_callback_proxy;
-#endif
Index: project/branches/projects/jni/pjsip-apps/src/jni/callbacks.i
===================================================================
--- /pjproject/branches/projects/jni/pjsip-apps/src/jni/callbacks.i	(revision 4567)
+++ 	(revision )
@@ -1,58 +1,0 @@
-/* $Id$ */
-
-%header %{
-    #include "callbacks.h"
-%}
-
-/*
- * Wrap pjsua_logging_config callback
- */
-%feature("director") PjsuaLoggingConfigCallback;
-%ignore pjsua_logging_config::cb;
-%extend pjsua_logging_config {
-    void setCb(PjsuaLoggingConfigCallback* callback) {
-	setPjsuaLoggingConfigCallback(callback);
-	$self->cb = callback? &pjsua_logging_config_callback_proxy : NULL;
-    }
-}
-
-
-/*
- * Wrap pj_timer_heap_callback in pj_timer_entry
- */
-%feature("director") PjTimerHeapCallback;
-%ignore pj_timer_entry::cb;
-/* Suppress user_data, app can put user data in PjTimerHeapCallback inherited class */
-%ignore pj_timer_entry::user_data;
-%extend pj_timer_entry {
-    void setCb(PjTimerHeapCallback* callback) {
-	setPjTimerHeapCallback($self, callback);
-	$self->cb = callback? &pj_timer_heap_callback_proxy : NULL;
-    }
-}
-
-
-/*
- * Wrap pjsua_callback
- */
-%feature("director") PjsuaCallback;
-%ignore pjsua_callback;
-%ignore pjsua_config::cb;
-%extend pjsua_config {
-    void setCb(PjsuaCallback *callback) {
-	setPjsuaCallback(callback);
-	if (callback)
-	    $self->cb = *pjsua_callback_proxy;
-	else
-	    pj_bzero(&$self->cb, sizeof($self->cb));
-    }
-}
-
-
-%include <callbacks.h>
-
-/* Ignore these callbacks */
-%ignore pjsip_msg_body::print_body;
-%ignore pjsip_msg_body::clone_data;
-%ignore pjsip_tx_data::cb;
-%ignore pjsip_transaction::state_handler;
Index: project/branches/projects/jni/pjsip-apps/src/jni/header.i
===================================================================
--- /pjproject/branches/projects/jni/pjsip-apps/src/jni/header.i	(revision 4567)
+++ 	(revision )
@@ -1,94 +1,0 @@
-/* $Id$ */
-
-/* TODO:
- * - fix memory leaks in pj_str_t - java String typemaps
- * - typemap for pj_str_t as output param for callback/director,
- *   e.g: "st_text" param in pjsua_callback::on_call_replace_request()
- * - workaround for nested struct/union, i.e: moving out inner classes to global scope
- */
-
-%module (directors="1") pjsua
-
-%include "enums.swg"
-%include "../my_typemaps.i"
-
-%header %{
-    #include <pjsua-lib/pjsua.h>
-%}
-
-/* Strip "pjsua_" prefix from pjsua functions, for better compatibility with 
- * pjsip-jni & csipsimple.
- */
-%rename("%(strip:[pjsua_])s", %$isfunction) "";
-
-/* Suppress pjsua_schedule_timer2(), app can still use pjsua_schedule_timer() */
-%ignore pjsua_schedule_timer2;
-
-/* Suppress aux function pjsua_resolve_stun_servers(), usually app won't need this
- * as app can just simply configure STUN server to use STUN.
- */
-%ignore pjsua_resolve_stun_servers;
-
-/* Map 'void *' simply as long, app can use this "long" as index of its real user data */
-%apply long long { void * };
-
-/* Handle void *[ANY], e.g: pjsip_tx_data::mod_data, pjsip_transaction::mod_data */
-//%ignore pjsip_tx_data::mod_data;
-//%ignore pjsip_transaction::mod_data;
-%apply long long[ANY]   { void *[ANY] };
-
-/* Map pj_bool_t */
-%apply bool { pj_bool_t };
-
-/* Map pjsua_call_dump() output buffer */
-%apply (char *STRING, size_t LENGTH) { (char *buffer, unsigned maxlen) };
-
-/* Map "int*" & "unsigned*" as input & output */
-%apply unsigned	*INOUT  { unsigned * };
-%apply int      *INOUT  { int * };
-
-/* Map the following args as input & output */
-%apply int      *INOUT	{ pj_stun_nat_type * };
-%apply int      *INOUT	{ pjsip_status_code * };
-%apply pj_str_t *INOUT  { pj_str_t *p_contact };
-
-/* Apply array of integer on array of enum */
-%apply int[ANY]         { pjmedia_format_id dec_fmt_id[ANY] };
-
-/* Handle members typed array of pj_str_t */
-MY_JAVA_MEMBER_ARRAY_OF_STR(pjsua_config, nameserver, nameserver_count)
-MY_JAVA_MEMBER_ARRAY_OF_STR(pjsua_config, outbound_proxy, outbound_proxy_cnt)
-MY_JAVA_MEMBER_ARRAY_OF_STR(pjsua_config, stun_srv, stun_srv_cnt)
-MY_JAVA_MEMBER_ARRAY_OF_STR(pjsua_acc_config, proxy, proxy_cnt)
-MY_JAVA_MEMBER_ARRAY_OF_STR(pjsua_config, stun_srv, stun_srv_cnt)
-MY_JAVA_MEMBER_ARRAY_OF_STR(pjsua_config, stun_srv, stun_srv_cnt)
-MY_JAVA_MEMBER_ARRAY_OF_STR(pjsip_generic_array_hdr, values, count)
-
-/* Handle pointer-to-pointer-to-object as input & output */
-MY_JAVA_CLASS_INOUT(pjmedia_port, p_port)
-MY_JAVA_CLASS_INOUT(pjsip_tx_data, p_tdata)
-
-/* Handle array of pj_ssl_cipher in pjsip_tls_setting. */
-MY_JAVA_MEMBER_ARRAY_OF_ENUM(pjsip_tls_setting, pj_ssl_cipher, ciphers, ciphers_num)
-
-/* Handle array of pointer in struct/class member */
-MY_JAVA_MEMBER_ARRAY_OF_POINTER(pjsip_regc_cbparam, pjsip_contact_hdr, contact, contact_cnt)
-MY_JAVA_MEMBER_ARRAY_OF_POINTER(pjmedia_sdp_session, pjmedia_sdp_media, media, media_count)
-MY_JAVA_MEMBER_ARRAY_OF_POINTER(pjmedia_sdp_media, pjmedia_sdp_bandw, bandw, bandw_count)
-MY_JAVA_MEMBER_ARRAY_OF_POINTER(pjmedia_sdp_media, pjmedia_sdp_attr, attr, attr_count)
-
-/* C++ SWIG target doesn't support nested class (C version does though!).
- * This is minimal workaround, ignore nested class as if it is not there.
- * TODO: proper workaround will be moving out inner classes to global scope.
- */
-#ifdef __cplusplus
-    %nestedworkaround pjmedia_codec_fmtp::param;
-    %nestedworkaround pjsip_cred_info::ext;
-    %nestedworkaround pjsip_event::body;
-#endif
-
-%include "../callbacks.i"
-
-/* Global constants */
-#define PJ_SUCCESS  0
-
Index: project/branches/projects/jni/pjsip-apps/src/jni/hello.java
===================================================================
--- /pjproject/branches/projects/jni/pjsip-apps/src/jni/hello.java	(revision 4567)
+++ 	(revision )
@@ -1,218 +1,0 @@
-/* $Id$ */
-
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-import java.io.IOException;
-
-import org.pjsip.pjsua.*;
-
-class app_config {
-	public static int cur_call_id = -1;
-}
-
-class MyPjsuaCallback extends PjsuaCallback {
-	@Override
-	public void on_call_media_state(int call_id)
-	{
-		System.out.println("======== Call media started (call id: " + call_id + ")");
-		pjsua_call_info info = new pjsua_call_info();
-		pjsua.call_get_info(call_id, info);
-		if (info.getMedia_status() == pjsua_call_media_status.PJSUA_CALL_MEDIA_ACTIVE) {
-			pjsua.conf_connect(info.getConf_slot(), 0);
-			pjsua.conf_connect(0, info.getConf_slot());
-		}
-	}
-	
-	/* Testing pj_str_t-String map with director */
-	@Override
-	public void on_pager(int call_id, String from, String to, String contact, String mime_type, String body)
-	{
-		System.out.println("======== Incoming pager (call id: " + call_id + ")");
-		System.out.println("From     : " + from);
-		System.out.println("To       : " + to);
-		System.out.println("Contact  : " + contact);
-		System.out.println("Mimetype : " + mime_type);
-		System.out.println("Body     : " + body);
-	}
-	@Override
-	public void on_incoming_call(int acc_id, int call_id, pjsip_rx_data rdata) {
-		/* Auto answer */
-		pjsua.call_answer(call_id, 200, null, null);
-		app_config.cur_call_id = call_id;
-	}
-}
-
-class MyLogger extends PjsuaLoggingConfigCallback {
-	@Override
-	public void on_log(int level, String data)
-	{
-		System.out.print("LOG: " + data);
-	}
-}
-
-class MyTimerCallback extends PjTimerHeapCallback {
-	private int _user_data;
-	
-	/* Use this class itself to store app user data */
-	MyTimerCallback(int user_data) { _user_data = user_data; }
-	
-	@Override
-	public void on_timer(pj_timer_heap_t timer_heap, pj_timer_entry entry)
-	{
-		System.out.println("======== Timer fired (user data = " + _user_data + ")");
-	}
-}
-
-
-public class hello {
-	static {
-		System.loadLibrary("pjsua");
-	}
-
-	protected static void pj_error_exit(String message, int status) {
-		pjsua.perror("hello", message, status);
-		pjsua.destroy();
-		System.exit(status);
-	}
-
-	public static void main(String[] args) {
-		int[] tp_id = new int[1];
-		int[] acc_id = new int[1];
-		int[] call_id = new int[1];
-		int status;
-
-		/* Say hello first */
-		System.out.println("Hello, World");
-
-		/* Create pjsua */
-		{
-			status = pjsua.create();
-			if (status != pjsua.PJ_SUCCESS) {
-				System.out.println("Error creating pjsua: " + status);
-				System.exit(status);
-			}
-		}
-		
-		/* Init pjsua */
-		{
-			pjsua_config cfg = new pjsua_config();
-			pjsua.config_default(cfg);
-			cfg.setCb(new MyPjsuaCallback());
-
-			pjsua_logging_config log_cfg = new pjsua_logging_config();
-			pjsua.logging_config_default(log_cfg);
-			log_cfg.setLevel(4);
-			log_cfg.setCb(new MyLogger());
-
-			status = pjsua.init(cfg, log_cfg, null);
-			if (status != pjsua.PJ_SUCCESS) {
-				pj_error_exit("Error inintializing pjsua", status);
-			}
-		}
-		
-		/* Add SIP UDP transport */
-		{
-			pjsua_transport_config cfg = new pjsua_transport_config();
-			pjsua.transport_config_default(cfg);
-			cfg.setPort(6000);
-			status = pjsua.transport_create(pjsip_transport_type_e.PJSIP_TRANSPORT_UDP, cfg, tp_id);
-			if (status != pjsua.PJ_SUCCESS) {
-				pj_error_exit("Error creating transport", status);
-			}
-		}
-		
-		/* Add local account */
-		{
-			status = pjsua.acc_add_local(tp_id[0], true, acc_id);
-			if (status != pjsua.PJ_SUCCESS) {
-				pj_error_exit("Error creating local UDP account", status);
-			}
-		}
-		
-		/* Start pjsua */
-		{
-			status = pjsua.start();
-			if (status != pjsua.PJ_SUCCESS) {
-				pj_error_exit("Error starting pjsua", status);
-			}
-		}
-		
-		/* Make call to the URL. */
-		if (false) {
-			status = pjsua.call_make_call(acc_id[0], "sip:localhost:6000", null, 0, null, call_id);
-			if (status != pjsua.PJ_SUCCESS) {
-				pj_error_exit("Error making call", status);
-			}
-			app_config.cur_call_id = call_id[0];
-		}
-		
-		/* Test timer */
-		{
-			pj_timer_entry timer = new pj_timer_entry();
-			timer.setCb(new MyTimerCallback(1234567890));
-
-			pj_time_val tv = new pj_time_val();
-			tv.setSec(0);
-			tv.setMsec(1000);
-
-			pjsua.schedule_timer(timer, tv);
-		}
-		
-		/* Wait until user press "q" to quit. */
-		for (;;) {
-			String userInput;
-			BufferedReader inBuffReader = new BufferedReader(new InputStreamReader(System.in));
-
-			System.out.println("Press 'h' to hangup all calls, 'q' to quit");
-
-			try {
-				userInput = inBuffReader.readLine();
-			} catch (IOException e) {
-				System.out.println("Error in readLine(): " + e);
-				break;
-			}
-			
-			if (userInput.equals("q")) {
-				break;
-			} else if (userInput.equals("h")) {
-				pjsua.call_hangup_all();
-				app_config.cur_call_id = -1;
-			} else if (userInput.equals("c")) {
-				/* Test string as output param, it is wrapped as string array */
-				String[] contact = new String[1];
-				pj_pool_t my_pool = pjsua.pool_create("hello", 256, 256);
-				
-				pjsua.acc_create_uac_contact(my_pool, contact, 0, "sip:localhost");
-				System.out.println("Test create contact: " + contact[0]);
-				
-				pjsua.pj_pool_release(my_pool);
-			} else if (userInput.equals("d")) {
-				pjsua.dump(false);
-			} else if (userInput.equals("dd")) {
-				pjsua.dump(true);
-			} else if (userInput.equals("dq")) {
-				if (app_config.cur_call_id == -1) {
-					System.out.println("No active call");
-					continue;
-				}
-				
-				byte[] buf = new byte[1024*2];
-				pjsua.call_dump(app_config.cur_call_id, true, buf, "");
-
-				/* Build string from byte array, find null terminator first */
-				int len = 0;
-				while (len < buf.length && buf[len] != 0) ++len;
-				String call_dump = new String(buf, 0, len);
-
-				System.out.println("Statistics of call " + app_config.cur_call_id);
-				System.out.println(call_dump);
-			}
-		}
-
-		/* Finally, destroy pjsua */
-		{
-			pjsua.destroy();
-		}
-		
-	}
-}
Index: /pjproject/branches/projects/jni/pjsip-apps/src/jni/jni/Android.mk
===================================================================
--- /pjproject/branches/projects/jni/pjsip-apps/src/jni/jni/Android.mk	(revision 4568)
+++ /pjproject/branches/projects/jni/pjsip-apps/src/jni/jni/Android.mk	(revision 4568)
@@ -0,0 +1,103 @@
+# $Id: Makefile 4563 2013-07-15 05:34:14Z bennylp $
+
+# Get PJ build settings
+include ../../../build.mak
+include $(PJDIR)/build/common.mak
+
+# Get JDK location
+ifeq ("$(JAVA_HOME)","")
+  # Get javac location to determine JDK location
+  JAVAC_PATH = $(shell which javac)
+  ifeq ("$(JAVAC_PATH)","")
+    $(error Cannot determine JDK location using 'which' command. Please define JAVA_HOME envvar)
+  endif
+
+  JAVAC_PATH := $(realpath $(JAVAC_PATH))
+  JAVA_BIN := $(dir $(JAVAC_PATH))
+  JAVA_HOME := $(patsubst %/bin/,%,$(JAVA_BIN))
+endif
+
+# OS specific
+ifeq ($(OS),Windows_NT)
+MY_JNI_LDFLAGS	 = -L$(MY_JDK)/lib -Wl,--kill-at
+MY_JNI_LIB       = $(MY_PACKAGE_BIN)/pjsua.dll
+else
+MY_JNI_LDFLAGS	 = -L$(MY_JDK)/lib -Wl,-soname,pjsua.so
+MY_JNI_LIB       = $(MY_PACKAGE_BIN)/libpjsua.so
+MY_JNI_CFLAGS	 := -fPIC
+endif
+
+# Env settings, e.g: path to SWIG, JDK, java(.exe), javac(.exe)
+MY_SWIG		 = swig
+MY_JDK		 = $(JAVA_HOME)
+MY_JAVA		 = $(MY_JDK)/bin/java
+MY_JAVAC	 = $(MY_JDK)/bin/javac
+MY_JNI_CFLAGS	 := $(MY_JNI_CFLAGS) -I$(MY_JDK)/include -I$(MY_JDK)/include/win32 \
+		   -I$(MY_JDK)/include/linux -I.
+
+# Build settings
+MY_CFLAGS	 = $(PJ_CFLAGS) $(MY_JNI_CFLAGS)
+MY_LDFLAGS	 = $(PJ_LDFLAGS) $(PJ_LDLIBS) $(MY_JNI_LDFLAGS) -static-libstdc++
+
+# Output/intermediate path settings
+MY_PACKAGE	 = org.pjsip.pjsua
+MY_OUT_DIR	 = jni/output
+MY_SWIG_IF	 = $(MY_OUT_DIR)/pjsua.i
+MY_SWIG_FLAG	 = -c++ -I$(MY_OUT_DIR) # -debug-tmsearch -debug-tmused # -Wall
+MY_SWIG_WRAPPER	 = $(MY_OUT_DIR)/pjsua_wrap
+MY_PACKAGE_SRC	 = src/$(subst .,/,$(MY_PACKAGE))
+MY_PACKAGE_BIN	 = $(MY_OUT_DIR)/bin
+
+TEST_PACKAGE	 = org.pjsip.hello
+TEST_SRC	 = src/$(subst .,/,$(TEST_PACKAGE))
+
+# Android build settings
+LOCAL_PATH	:= $(call my-dir)/pjsip-apps/src/jni
+LOCAL_MODULE    := libpjsua
+LOCAL_MODULE_FILENAME := libpjsua
+LOCAL_CFLAGS    := -Werror $(APP_CFLAGS) -frtti
+LOCAL_LDFLAGS   := $(APP_LDFLAGS)
+LOCAL_LDLIBS    := $(APP_LDLIBS)
+LOCAL_SRC_FILES := $(MY_SWIG_WRAPPER).cpp $(MY_OUT_DIR)/callbacks.cpp
+
+MY_JNI_WRAP	:= $(MY_SWIG_WRAPPER).cpp
+
+jni: $(MY_JNI_LIB) java
+
+clean:
+	rm -rf $(MY_OUT_DIR)
+	rm -rf $(MY_PACKAGE_SRC)
+
+$(MY_SWIG_IF).tmp: jni/swig_gen.py
+	@mkdir -p $(MY_OUT_DIR)
+	python jni/swig_gen.py > $(MY_SWIG_IF).tmp
+
+$(MY_SWIG_IF): jni/header.i $(MY_SWIG_IF).tmp
+	cat jni/header.i > $(MY_SWIG_IF)
+	cat $(MY_SWIG_IF).tmp >> $(MY_SWIG_IF)
+
+$(MY_SWIG_WRAPPER).cpp: $(MY_SWIG_IF) jni/callbacks.i jni/my_typemaps.i
+	@# Cleanup java outdir first, to remove any old/deprecated java files
+	rm -rf $(MY_PACKAGE_SRC)
+	@mkdir -p $(MY_PACKAGE_SRC)
+	$(MY_SWIG) $(MY_SWIG_FLAG) -o $(MY_SWIG_WRAPPER).cpp -package $(MY_PACKAGE) \
+		-outdir $(MY_PACKAGE_SRC) -java $(MY_SWIG_IF) > $(MY_SWIG_WRAPPER)-tm.log
+
+$(MY_JNI_LIB): $(MY_SWIG_WRAPPER).cpp
+	@mkdir -p $(MY_PACKAGE_BIN)
+	$(PJ_CXX) -shared -o $(MY_JNI_LIB) $(MY_SWIG_WRAPPER).cpp $(MY_OUT_DIR)/callbacks.cpp \
+		$(MY_CFLAGS) $(MY_LDFLAGS)
+
+java: $(TEST_SRC)/hello.java
+	@mkdir -p $(MY_PACKAGE_BIN)
+	$(MY_JAVAC) -d $(MY_PACKAGE_BIN) $(MY_PACKAGE_SRC)/*.java
+	$(MY_JAVAC) -d $(MY_PACKAGE_BIN) -classpath "$(MY_PACKAGE_BIN)" $(TEST_SRC)/hello.java
+
+test: $(MY_PACKAGE_BIN)/hello.class
+	@# Need to specify classpath and library path, alternatively, they can be set via
+	@# CLASSPATH and java.library.path env settings
+	$(MY_JAVA) -cp $(MY_PACKAGE_BIN) -Djava.library.path="$(MY_PACKAGE_BIN)" hello
+
+.PHONY: $(MY_JNI_WRAP)
+
+include $(BUILD_SHARED_LIBRARY)
Index: /pjproject/branches/projects/jni/pjsip-apps/src/jni/jni/callbacks.c.template
===================================================================
--- /pjproject/branches/projects/jni/pjsip-apps/src/jni/jni/callbacks.c.template	(revision 4568)
+++ /pjproject/branches/projects/jni/pjsip-apps/src/jni/jni/callbacks.c.template	(revision 4568)
@@ -0,0 +1,53 @@
+/* $Id: callbacks.c.template 4566 2013-07-17 20:20:50Z nanang $ */
+
+#include "callbacks.h"
+
+/*
+ * Wrapper of pjsua_logging_config callback
+ */
+static PjsuaLoggingConfigCallback *pjsua_logging_config_cb = NULL;
+
+void pjsua_logging_config_callback_proxy(int level, const char *data, int len)
+{
+  PJ_UNUSED_ARG(len);
+  pjsua_logging_config_cb->on_log(level, data);
+}
+
+void setPjsuaLoggingConfigCallback(PjsuaLoggingConfigCallback *callback)
+{
+  pjsua_logging_config_cb = callback;
+}
+
+
+/*
+ * Wrapper of pj_timer_heap_callback
+ */
+void pj_timer_heap_callback_proxy(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
+{
+  PjTimerHeapCallback *cb = (PjTimerHeapCallback*)entry->user_data;
+  pj_assert(cb);
+  cb->on_timer(timer_heap, entry);
+}
+
+void setPjTimerHeapCallback(pj_timer_entry *entry, PjTimerHeapCallback *callback)
+{
+  entry->user_data = callback;
+}
+
+
+/*
+ * Wrapper of pjsua_callback
+ */
+static PjsuaCallback* cb = NULL;
+
+void setPjsuaCallback(PjsuaCallback* callback) {
+  cb = callback;
+}
+
+$PJSUA_CALLBACK_PROXY$
+
+static pjsua_callback my_cb_proxy = {
+  $PJSUA_CALLBACK_DEF$
+};
+
+pjsua_callback* pjsua_callback_proxy = &my_cb_proxy;
Index: /pjproject/branches/projects/jni/pjsip-apps/src/jni/jni/callbacks.h.template
===================================================================
--- /pjproject/branches/projects/jni/pjsip-apps/src/jni/jni/callbacks.h.template	(revision 4568)
+++ /pjproject/branches/projects/jni/pjsip-apps/src/jni/jni/callbacks.h.template	(revision 4568)
@@ -0,0 +1,47 @@
+/* $Id: callbacks.h.template 4566 2013-07-17 20:20:50Z nanang $ */
+
+#include <pjsua-lib/pjsua.h>
+
+/*
+ * Wrapper of pjsua_logging_config callback
+ */
+class PjsuaLoggingConfigCallback {
+public:
+  virtual void on_log(int level, const char *data) {}
+  virtual ~PjsuaLoggingConfigCallback() {}
+};
+
+#ifndef SWIG /* SWIG should ignore these */
+extern void pjsua_logging_config_callback_proxy(int level, const char *data, int len);
+extern void setPjsuaLoggingConfigCallback(PjsuaLoggingConfigCallback *callback);
+#endif
+
+
+/*
+ * Wrapper of pj_timer_heap_callback
+ */
+class PjTimerHeapCallback {
+public:
+  virtual void on_timer(pj_timer_heap_t *timer_heap, pj_timer_entry *entry) {}
+  virtual ~PjTimerHeapCallback() {}
+};
+
+#ifndef SWIG /* SWIG should ignore these */
+extern void pj_timer_heap_callback_proxy(pj_timer_heap_t *timer_heap, pj_timer_entry *entry);
+extern void setPjTimerHeapCallback(pj_timer_entry *entry, PjTimerHeapCallback *callback);
+#endif
+
+
+/*
+ * Wrapper of pjsua_callback
+ */
+class PjsuaCallback {
+public:
+  $PJSUA_CALLBACK_CLASS$
+  virtual ~PjsuaCallback() {}
+};
+
+#ifndef SWIG /* SWIG should ignore these */
+extern void setPjsuaCallback(PjsuaCallback* callback);
+extern pjsua_callback* pjsua_callback_proxy;
+#endif
Index: /pjproject/branches/projects/jni/pjsip-apps/src/jni/jni/callbacks.i
===================================================================
--- /pjproject/branches/projects/jni/pjsip-apps/src/jni/jni/callbacks.i	(revision 4568)
+++ /pjproject/branches/projects/jni/pjsip-apps/src/jni/jni/callbacks.i	(revision 4568)
@@ -0,0 +1,58 @@
+/* $Id: callbacks.i 4566 2013-07-17 20:20:50Z nanang $ */
+
+%header %{
+    #include "callbacks.h"
+%}
+
+/*
+ * Wrap pjsua_logging_config callback
+ */
+%feature("director") PjsuaLoggingConfigCallback;
+%ignore pjsua_logging_config::cb;
+%extend pjsua_logging_config {
+    void setCb(PjsuaLoggingConfigCallback* callback) {
+	setPjsuaLoggingConfigCallback(callback);
+	$self->cb = callback? &pjsua_logging_config_callback_proxy : NULL;
+    }
+}
+
+
+/*
+ * Wrap pj_timer_heap_callback in pj_timer_entry
+ */
+%feature("director") PjTimerHeapCallback;
+%ignore pj_timer_entry::cb;
+/* Suppress user_data, app can put user data in PjTimerHeapCallback inherited class */
+%ignore pj_timer_entry::user_data;
+%extend pj_timer_entry {
+    void setCb(PjTimerHeapCallback* callback) {
+	setPjTimerHeapCallback($self, callback);
+	$self->cb = callback? &pj_timer_heap_callback_proxy : NULL;
+    }
+}
+
+
+/*
+ * Wrap pjsua_callback
+ */
+%feature("director") PjsuaCallback;
+%ignore pjsua_callback;
+%ignore pjsua_config::cb;
+%extend pjsua_config {
+    void setCb(PjsuaCallback *callback) {
+	setPjsuaCallback(callback);
+	if (callback)
+	    $self->cb = *pjsua_callback_proxy;
+	else
+	    pj_bzero(&$self->cb, sizeof($self->cb));
+    }
+}
+
+
+%include <callbacks.h>
+
+/* Ignore these callbacks */
+%ignore pjsip_msg_body::print_body;
+%ignore pjsip_msg_body::clone_data;
+%ignore pjsip_tx_data::cb;
+%ignore pjsip_transaction::state_handler;
Index: /pjproject/branches/projects/jni/pjsip-apps/src/jni/jni/header.i
===================================================================
--- /pjproject/branches/projects/jni/pjsip-apps/src/jni/jni/header.i	(revision 4568)
+++ /pjproject/branches/projects/jni/pjsip-apps/src/jni/jni/header.i	(revision 4568)
@@ -0,0 +1,94 @@
+/* $Id: header.i 4566 2013-07-17 20:20:50Z nanang $ */
+
+/* TODO:
+ * - fix memory leaks in pj_str_t - java String typemaps
+ * - typemap for pj_str_t as output param for callback/director,
+ *   e.g: "st_text" param in pjsua_callback::on_call_replace_request()
+ * - workaround for nested struct/union, i.e: moving out inner classes to global scope
+ */
+
+%module (directors="1") pjsua
+
+%include "enums.swg"
+%include "../my_typemaps.i"
+
+%header %{
+    #include <pjsua-lib/pjsua.h>
+%}
+
+/* Strip "pjsua_" prefix from pjsua functions, for better compatibility with 
+ * pjsip-jni & csipsimple.
+ */
+%rename("%(strip:[pjsua_])s", %$isfunction) "";
+
+/* Suppress pjsua_schedule_timer2(), app can still use pjsua_schedule_timer() */
+%ignore pjsua_schedule_timer2;
+
+/* Suppress aux function pjsua_resolve_stun_servers(), usually app won't need this
+ * as app can just simply configure STUN server to use STUN.
+ */
+%ignore pjsua_resolve_stun_servers;
+
+/* Map 'void *' simply as long, app can use this "long" as index of its real user data */
+%apply long long { void * };
+
+/* Handle void *[ANY], e.g: pjsip_tx_data::mod_data, pjsip_transaction::mod_data */
+//%ignore pjsip_tx_data::mod_data;
+//%ignore pjsip_transaction::mod_data;
+%apply long long[ANY]   { void *[ANY] };
+
+/* Map pj_bool_t */
+%apply bool { pj_bool_t };
+
+/* Map pjsua_call_dump() output buffer */
+%apply (char *STRING, size_t LENGTH) { (char *buffer, unsigned maxlen) };
+
+/* Map "int*" & "unsigned*" as input & output */
+%apply unsigned	*INOUT  { unsigned * };
+%apply int      *INOUT  { int * };
+
+/* Map the following args as input & output */
+%apply int      *INOUT	{ pj_stun_nat_type * };
+%apply int      *INOUT	{ pjsip_status_code * };
+%apply pj_str_t *INOUT  { pj_str_t *p_contact };
+
+/* Apply array of integer on array of enum */
+%apply int[ANY]         { pjmedia_format_id dec_fmt_id[ANY] };
+
+/* Handle members typed array of pj_str_t */
+MY_JAVA_MEMBER_ARRAY_OF_STR(pjsua_config, nameserver, nameserver_count)
+MY_JAVA_MEMBER_ARRAY_OF_STR(pjsua_config, outbound_proxy, outbound_proxy_cnt)
+MY_JAVA_MEMBER_ARRAY_OF_STR(pjsua_config, stun_srv, stun_srv_cnt)
+MY_JAVA_MEMBER_ARRAY_OF_STR(pjsua_acc_config, proxy, proxy_cnt)
+MY_JAVA_MEMBER_ARRAY_OF_STR(pjsua_config, stun_srv, stun_srv_cnt)
+MY_JAVA_MEMBER_ARRAY_OF_STR(pjsua_config, stun_srv, stun_srv_cnt)
+MY_JAVA_MEMBER_ARRAY_OF_STR(pjsip_generic_array_hdr, values, count)
+
+/* Handle pointer-to-pointer-to-object as input & output */
+MY_JAVA_CLASS_INOUT(pjmedia_port, p_port)
+MY_JAVA_CLASS_INOUT(pjsip_tx_data, p_tdata)
+
+/* Handle array of pj_ssl_cipher in pjsip_tls_setting. */
+MY_JAVA_MEMBER_ARRAY_OF_ENUM(pjsip_tls_setting, pj_ssl_cipher, ciphers, ciphers_num)
+
+/* Handle array of pointer in struct/class member */
+MY_JAVA_MEMBER_ARRAY_OF_POINTER(pjsip_regc_cbparam, pjsip_contact_hdr, contact, contact_cnt)
+MY_JAVA_MEMBER_ARRAY_OF_POINTER(pjmedia_sdp_session, pjmedia_sdp_media, media, media_count)
+MY_JAVA_MEMBER_ARRAY_OF_POINTER(pjmedia_sdp_media, pjmedia_sdp_bandw, bandw, bandw_count)
+MY_JAVA_MEMBER_ARRAY_OF_POINTER(pjmedia_sdp_media, pjmedia_sdp_attr, attr, attr_count)
+
+/* C++ SWIG target doesn't support nested class (C version does though!).
+ * This is minimal workaround, ignore nested class as if it is not there.
+ * TODO: proper workaround will be moving out inner classes to global scope.
+ */
+#ifdef __cplusplus
+    %nestedworkaround pjmedia_codec_fmtp::param;
+    %nestedworkaround pjsip_cred_info::ext;
+    %nestedworkaround pjsip_event::body;
+#endif
+
+%include "../callbacks.i"
+
+/* Global constants */
+#define PJ_SUCCESS  0
+
Index: /pjproject/branches/projects/jni/pjsip-apps/src/jni/jni/my_typemaps.i
===================================================================
--- /pjproject/branches/projects/jni/pjsip-apps/src/jni/jni/my_typemaps.i	(revision 4568)
+++ /pjproject/branches/projects/jni/pjsip-apps/src/jni/jni/my_typemaps.i	(revision 4568)
@@ -0,0 +1,312 @@
+# $Id: my_typemaps.i 4566 2013-07-17 20:20:50Z nanang $
+
+%include "arrays_java.i"
+%include "typemaps.i"
+
+/* Auto destroy JNI object, useful for director */
+%header %{
+class LocalRefGuard {
+    JNIEnv* jenv;
+    jobject jobj;
+public:
+    LocalRefGuard(JNIEnv* jenv_, jobject jobj_) : jenv(jenv_), jobj(jobj_) {}
+    ~LocalRefGuard() { if (jobj) jenv->DeleteLocalRef(jobj); }
+};
+%}
+
+/*
+ * Add director typemaps for "int *INOUT"
+ */
+%typemap(javadirectorin) int *INOUT "$jniinput"
+%typemap(directorin, descriptor="[I") int *INOUT %{
+  $input = jenv->NewIntArray(1);
+  LocalRefGuard g_$input(jenv, $input);
+  jenv->SetIntArrayRegion($input, 0, 1, (jint*)$1);
+%}
+%typemap(directorout) int *INOUT %{
+  jint tmp$result;
+  jenv->GetIntArrayRegion($input, 0, 1, &tmp$result);
+  *$result = ($*1_ltype)tmp$result;
+%}
+%typemap(directorargout) int *INOUT %{
+  jint tmp$1;
+  jenv->GetIntArrayRegion($input, 0, 1, &tmp$1);
+  *$1 = ($*1_ltype)tmp$1;
+%}
+
+/*
+ * Add director typemaps for "unsigned *INOUT"
+ */
+%typemap(javadirectorin) unsigned *INOUT "$jniinput"
+%typemap(directorin, descriptor="[I") unsigned *INOUT %{
+  $input = jenv->NewLongArray(1);
+  LocalRefGuard g_$input(jenv, $input);
+  jenv->SetLongArrayRegion($input, 0, 1, (jlong*)$1);
+%}
+%typemap(directorout) unsigned *INOUT %{
+  jlong tmp$result;
+  jenv->GetLongArrayRegion($input, 0, 1, &tmp$result);
+  *$result = ($*1_ltype)tmp$result;
+%}
+%typemap(directorargout) unsigned *INOUT %{
+  jlong tmp$1;
+  jenv->GetLongArrayRegion($input, 0, 1, &tmp$1);
+  *$1 = ($*1_ltype)tmp$1;
+%}
+
+/*
+ * Map pj_str_t to java String
+ */
+%ignore pj_str_t;
+%typemap(jni)             pj_str_t* "jstring"
+%typemap(jtype)           pj_str_t* "String"
+%typemap(jstype)          pj_str_t* "String"
+%typemap(javain)          pj_str_t* "$javainput"
+%typemap(javaout)         pj_str_t* { return $jnicall; }
+%typemap(javadirectorin)  pj_str_t* "$jniinput"
+%typemap(javadirectorout) pj_str_t* "$javacall"
+
+%typemap(in)              pj_str_t* (pj_str_t str_tmp, char* str_ptr=NULL) %{
+  $1 = &str_tmp;
+  if(!$input) pj_strset($1, NULL, 0);
+  else {
+    str_ptr = (char*)jenv->GetStringUTFChars($input, 0);
+    pj_size_t str_len = jenv->GetStringUTFLength($input);
+    if (!str_ptr || !str_len) pj_strset($1, NULL, 0);
+    else pj_strset($1, str_ptr, str_len);
+  }
+%}
+
+%typemap(freearg)         pj_str_t* %{
+  if ($input)
+    jenv->ReleaseStringUTFChars($input, str_ptr$argnum);
+%}
+
+%typemap(memberin)        pj_str_t %{
+  if ($1.ptr) free($1.ptr);
+  if ($input->ptr) {
+    $1.ptr = (char*)malloc($input->slen);				/* <-- will leak! */
+    memcpy($1.ptr, $input->ptr, $input->slen);
+    $1.slen = $input->slen;
+  }
+%}
+
+%typemap(out)             pj_str_t* %{
+  char *$1_ptr = (char*)malloc($1->slen+1);
+  memcpy($1_ptr, $1->ptr, $1->slen);
+  $1_ptr[$1->slen] = '\0';
+  $result = jenv->NewStringUTF($1_ptr);
+  free($1_ptr);
+%}
+
+%typemap(directorin,descriptor="Ljava/lang/String;") pj_str_t* %{
+  char *$input_ptr = (char*)malloc($1->slen+1);
+  memcpy($input_ptr, $1->ptr, $1->slen);
+  $input_ptr[$1->slen] = '\0';
+  $input = jenv->NewStringUTF($input_ptr);
+  LocalRefGuard g_$input(jenv, $input);
+  free($input_ptr);
+%}
+
+/*
+ * Map pj_str_t[ANY] to java String[]
+ */
+%typemap(jni)     pj_str_t[ANY] "jobjectArray"
+%typemap(jtype)	  pj_str_t[ANY] "String[]"
+%typemap(jstype)  pj_str_t[ANY] "String[]"
+%typemap(javain)  pj_str_t[ANY] "$javainput"
+%typemap(javaout) pj_str_t[ANY] { return $jnicall; }
+%typemap(in)      pj_str_t[ANY] %{
+  int $1_len = jenv->GetArrayLength($input);
+  char** $1_tmpstr = new char*[$1_len];
+  jstring* $1_tmp = new jstring[$1_len];
+  $1 = new pj_str_t[$1_len];
+  int $1_ii;
+  for ($1_ii = 0; $1_ii<$1_len; $1_ii++) {
+    $1_tmp[$1_ii] = (jstring)jenv->GetObjectArrayElement($input, $1_ii);
+    if ($1_tmp[$1_ii]) {
+      $1[$1_ii].ptr = $1_tmpstr[$1_ii] = (char*)jenv->GetStringUTFChars($1_tmp[$1_ii], 0);
+      $1[$1_ii].slen = jenv->GetStringUTFLength($1_tmp[$1_ii]);
+    } else {
+      pj_strset(&$1[$1_ii], NULL, 0);
+    }
+    jenv->DeleteLocalRef($1_tmp[$1_ii]); /* is this ok here? */
+  }
+%}
+
+%typemap(freearg) pj_str_t[ANY] %{
+  for ($1_ii=0; $1_ii<$1_len; $1_ii++)
+    if ($1_tmp[$1_ii]) jenv->ReleaseStringUTFChars($1_tmp[$1_ii], $1_tmpstr[$1_ii]);
+  delete [] $1;
+  delete [] $1_tmp;
+  delete [] $1_tmpstr;
+%}
+
+/* 
+ * Handle setter/getter of a struct member with type of 'array of pj_str_t'.
+ */
+%define MY_JAVA_MEMBER_ARRAY_OF_STR(CLASS_NAME, NAME, COUNT_NAME)
+
+%ignore CLASS_NAME::COUNT_NAME;
+
+%typemap(memberin)	pj_str_t NAME[ANY], pj_str_t NAME[] {
+  int i;
+  for (i=0; i<arg1->COUNT_NAME; ++i)
+    if ($1[i].ptr) free($1[i].ptr);
+  
+  arg1->COUNT_NAME = $input_len;
+  for (i=0; i<arg1->COUNT_NAME; ++i) {
+    if ($input->ptr) {
+      $1[i].ptr = (char*)malloc($input->slen);				/* <-- will leak! */
+      memcpy($1[i].ptr, $input->ptr, $input->slen);
+      $1[i].slen = $input->slen;
+    }
+  }
+}
+
+%typemap(out) 		pj_str_t NAME[ANY] {
+  int i;
+  jstring temp_string;
+  const jclass clazz = jenv->FindClass("java/lang/String");
+
+  $result = jenv->NewObjectArray(arg1->COUNT_NAME, clazz, NULL);
+  for (i=0; i<arg1->COUNT_NAME; i++) {
+    temp_string = jenv->NewStringUTF($1[i].ptr);
+    jenv->SetObjectArrayElement($result, i, temp_string);
+    jenv->DeleteLocalRef(temp_string);
+  }
+}
+
+%enddef
+
+/*
+ * pj_str_t *INOUT, string as input and output param, handled as single element array.
+ */
+%apply pj_str_t[ANY] { pj_str_t *INOUT };
+
+%typemap(argout) pj_str_t *INOUT {
+  char *$1_ptr = new char[$1[0].slen+1];
+  memcpy($1_ptr, $1[0].ptr, $1[0].slen);
+  $1_ptr[$1[0].slen] = '\0';
+  jstring temp_string = jenv->NewStringUTF($1_ptr);
+  jenv->SetObjectArrayElement($input, 0, temp_string);
+  delete [] $1_ptr;
+}
+
+%typemap(directorin,descriptor="[Ljava/lang/String;") pj_str_t *INOUT %{
+  jstring tmp_$input;
+  $input = jenv->NewObjectArray(1, jenv->FindClass("java/lang/String"), NULL);
+  LocalRefGuard g_$input(jenv, $input);
+  tmp_$input = jenv->NewStringUTF($1[0].ptr);
+  LocalRefGuard g_temp_$input(jenv, tmp_$input);
+  jenv->SetObjectArrayElement($input, 0, tmp_$input);
+%}
+
+%typemap(directorargout)  pj_str_t *INOUT {
+  if(!$input) pj_strset($1, NULL, 0);
+  else {
+    str_ptr = (char*)jenv->GetStringUTFChars($input, 0);
+    pj_size_t str_len = jenv->GetStringUTFLength($input);
+    if (!str_ptr || !str_len) pj_strset($1, NULL, 0);
+    else {
+      $1->ptr = (char*)malloc(str_len);					/* <-- will leak! */
+      memcpy($1->ptr, str_ptr, str_len);
+      $1->slen = str_len;
+    }
+    jenv->ReleaseStringUTFChars($input, str_ptr);
+  }
+}
+
+
+/* 
+ * Object input & output (with double pointers).
+ */
+%define MY_JAVA_CLASS_INOUT(TYPE, NAME)
+%typemap(jni) 	 TYPE **NAME "jlong"
+%typemap(jtype)  TYPE **NAME "long"
+%typemap(jstype) TYPE **NAME "TYPE"
+%typemap(in) 	 TYPE **NAME (TYPE *temp = NULL) "temp = (TYPE*)$input; $1 = &temp;"
+%typemap(argout) TYPE **NAME "$input = (jlong)*$1;"
+%typemap(directorin,descriptor="L$packagepath/TYPE;") TYPE **NAME "$input = (jlong)*$1;"
+%typemap(directorargout)  TYPE **NAME " *$1 = (TYPE*)$input; "
+%typemap(javain)	  TYPE **NAME "TYPE.getCPtr($javainput)"
+%typemap(javadirectorin)  TYPE **NAME "($jniinput == 0) ? null : new TYPE($jniinput, false)"
+%typemap(javadirectorout) TYPE **NAME "TYPE.getCPtr($javacall)"
+%enddef
+
+
+/* 
+ * Generate setter/getter of a struct member typed of 'array of enum' with variable length.
+ */
+%define MY_JAVA_MEMBER_ARRAY_OF_ENUM(CLASS_NAME, TYPE, NAME, COUNT_NAME)
+
+%ignore CLASS_NAME::COUNT_NAME;
+%apply ARRAYSOFENUMS[] { TYPE* NAME };
+
+%typemap(in)       TYPE* NAME (jint *jarr) %{
+  int size$1 = jenv->GetArrayLength($input);
+  if (!SWIG_JavaArrayInInt(jenv, &jarr, (int **)&$1, $input)) return $null;
+%}
+
+%typemap(memberin) TYPE* NAME %{
+  if ($1) free($1);
+  arg1->COUNT_NAME = size$input;
+  $1 = (TYPE*)calloc(arg1->COUNT_NAME, sizeof(TYPE));			/* <-- will leak! */
+  for (size_t i = 0; i < (size_t)arg1->COUNT_NAME; i++)
+    $1[i] = $input[i];
+%}
+
+%typemap(out)      TYPE* NAME %{
+  $result = SWIG_JavaArrayOutInt(jenv, (int*)$1, arg1->COUNT_NAME);
+%}
+
+// Hack for avoiding leak, may not work when another macro defines class destructor too
+%extend CLASS_NAME { ~CLASS_NAME() { if ($self->NAME) free($self->NAME); } };
+
+%enddef
+
+
+/* 
+ * Handle setter/getter of a struct member with type of 'array of pointer to struct/class'.
+ */
+%define MY_JAVA_MEMBER_ARRAY_OF_POINTER(CLASS_NAME, TYPE, NAME, COUNT_NAME)
+
+%ignore CLASS_NAME::COUNT_NAME;
+%typemap(jni) 	   TYPE* NAME[ANY] "jlongArray"
+%typemap(jtype)    TYPE* NAME[ANY] "long[]"
+%typemap(jstype)   TYPE* NAME[ANY] "TYPE[]"
+%typemap(javain)   TYPE* NAME[ANY] "TYPE.cArrayUnwrap($javainput)"
+%typemap(javaout)  TYPE* NAME[ANY] {return TYPE.cArrayWrap($jnicall, $owner);}
+
+%typemap(in)       TYPE* NAME[ANY] (jlong *jarr) %{
+  if (!SWIG_JavaArrayInUlong(jenv, &jarr, (unsigned long**)&$1, $input))
+    return $null;
+  arg1->COUNT_NAME = jenv->GetArrayLength($input);
+%}
+
+%typemap(freearg)  TYPE* NAME[ANY] %{ if ($1) delete [] $1; %}
+
+%typemap(memberin) TYPE* NAME[ANY] %{
+  for (size_t i = 0; i < (size_t)arg1->COUNT_NAME; i++) $1[i] = $input[i];
+%}
+
+%typemap(out)      TYPE* NAME[ANY] %{
+  $result = SWIG_JavaArrayOutUlong(jenv, (unsigned long*)$1, arg1->COUNT_NAME);
+%}
+
+%typemap(javacode) TYPE %{
+  protected static long[] cArrayUnwrap($javaclassname[] arrayWrapper) {
+    long[] cArray = new long[arrayWrapper.length];
+    for (int i=0; i<arrayWrapper.length; i++)
+      cArray[i] = $javaclassname.getCPtr(arrayWrapper[i]);
+    return cArray;
+  }
+  protected static $javaclassname[] cArrayWrap(long[] cArray, boolean cMemoryOwn) {
+    $javaclassname[] arrayWrapper = new $javaclassname[cArray.length];
+    for (int i=0; i<cArray.length; i++)
+      arrayWrapper[i] = new $javaclassname(cArray[i], cMemoryOwn);
+    return arrayWrapper;
+  }
+%}
+
+%enddef
Index: /pjproject/branches/projects/jni/pjsip-apps/src/jni/jni/swig_gen.py
===================================================================
--- /pjproject/branches/projects/jni/pjsip-apps/src/jni/jni/swig_gen.py	(revision 4568)
+++ /pjproject/branches/projects/jni/pjsip-apps/src/jni/jni/swig_gen.py	(revision 4568)
@@ -0,0 +1,304 @@
+# $Id: swig_gen.py 4566 2013-07-17 20:20:50Z nanang $
+
+#!/usr/bin/python
+
+import re
+import sys, os #, traceback
+from collections import OrderedDict
+from pycparser import parse_file, c_ast, c_generator
+
+# Settings.
+PJ_ROOT_PATH = "../../../"
+SOURCE_PATH  = PJ_ROOT_PATH + "pjsip/include/pjsua-lib/pjsua.h"
+#SOURCE_PATH  = PJ_ROOT_PATH + "pjlib-util/include/pjlib-util/scanner.h"
+#SOURCE_PATH  = PJ_ROOT_PATH + "pjlib/include/pj/types.h"
+OUTDIR = "jni/output" if len(sys.argv)<=1 else sys.argv[1]
+
+
+# CPP is needed by pycparser.
+if sys.platform == 'win32':
+	PYCPARSER_DIR="C:/devs/tools/pycparser"
+	CPP_PATH='C:/devs/bin/cpp.exe'
+else:
+    PYCPARSER_DIR="/Library/Python/2.7/site-packages/pycparser"
+    CPP_PATH='/Users/ming/teluu/android/android-ndk-r7c/toolchains/arm-linux-androideabi-4.4.3/prebuilt/darwin-x86/bin/arm-linux-androideabi-cpp'
+
+# CPP (C preprocessor) settings
+CPP_CFLAGS   = [
+	'-DPJ_AUTOCONF',
+	'-DCC_DUMMY',
+	'-U__GNUC__',
+	'-Djmp_buf=int',
+	'-I' + PYCPARSER_DIR + '/utils/fake_libc_include',
+	"-I" + PJ_ROOT_PATH + "pjlib/include",
+	"-I" + PJ_ROOT_PATH + "pjlib-util/include",
+	"-I" + PJ_ROOT_PATH + "pjnath/include",
+	"-I" + PJ_ROOT_PATH + "pjmedia/include",
+	"-I" + PJ_ROOT_PATH + "pjsip/include"
+	]
+
+# Any type/func names without this prefix will be excluded from the generated SWIG interface,
+# e.g: int, void.
+BASE_PREFIX = 'pj'
+
+# Any type/func names with this prefix will be treated as part of main module, i.e: they will
+# always be included in the generated SWIG interface, and will be used as starting point in
+# tracing dependencies (e.g: as struct pjsua_acc_config is part of main module, any types used
+# in its struct member, such as pj_str_t, pjsip_hdr, pj_bool_t, etc, will be included too).
+MODULE_PREFIX = 'pjsua_'
+#MODULE_PREFIX = 'pj'
+
+# If true, video related declarations (anything has '_vid_') will be removed, as long as not
+# used by main module (e.g: pjmedia_vid_dev_index type is used by pjsua_acc_config, so it won't
+# be removed).
+NO_VIDEO = True
+
+FORCE_STRUCT_AS_OPAQUE = [
+	'pj_pool_t',
+	'pj_stun_msg',
+	'pj_pool_factory',
+	'pjsip_hdr_vptr',
+	'pjsip_tpfactory',
+	'pjsip_transport',
+	'pjsip_tx_data_op_key',
+	'pjsip_rx_data_op_key',
+	'pjsip_module',
+	'pjsip_uri',
+	'pjsip_uri_vptr',
+	'pjmedia_port',
+	'pjmedia_transport',
+	'pjsua_media_transport'
+]
+
+FORCE_EXPORT = [
+	'pj_pool_release'
+]
+
+class MyGen(c_generator.CGenerator):
+
+	def __init__(self, ast):
+		super(MyGen, self).__init__()
+		self.ast = ast
+		self.nodes = OrderedDict()
+		self.deps = list()
+		self.deps_pending = list()
+		self.deps_frozen = False
+
+		# Generate nodes map (name -> node instances)
+		for ext in self.ast.ext:
+			name = self._get_node_name(ext)
+			if name and not name.startswith(BASE_PREFIX):
+				continue
+
+			if name in self.nodes:
+				self.nodes[name].append(ext)
+				# always put typedef later, swig issue
+				if isinstance(self.nodes[name][0], c_ast.Typedef):
+					self.nodes[name].reverse()
+			else:
+				self.nodes[name] = [ext]
+
+		# Generate dependencies, they are all APIs to be exported
+		for name in self.nodes.keys():
+			if (not name) or \
+				((name in FORCE_EXPORT or name.startswith(MODULE_PREFIX)) \
+					  and self._check_video(name)):
+				self._add_dep(name)
+		self.deps_frozen = True
+
+	# Override visit_IdentifierType() to collect "node name" and generate dependencies
+	# from this node's children
+	def visit_IdentifierType(self, n):
+		if not self.deps_frozen:
+			for name in n.names: self._add_dep(name)
+		return super(MyGen, self).visit_IdentifierType(n)
+
+	def _check_video(self, name):
+		if NO_VIDEO and name and ((name.find('_vid_') > 0) or (name.find('_video_') > 0)):
+			return False
+		return True
+
+	def _get_node_name(self, node):
+		s = getattr(node, 'name', None)
+		if s:
+			return s
+		if isinstance(node, c_ast.FuncDef):
+			return self._get_node_name(node.decl)
+		ss = getattr(node, 'names', None)
+		if ss:
+			s = ' '.join(ss)
+			return s
+		if getattr(node, 'type', None):
+			return self._get_node_name(node.type)
+		return s
+
+	# Trace node dependencies by recursively inspecting its children.
+	# The node itself and all its children will be listed in 'deps'.
+	def _add_dep(self, name):
+		if (name and not name.startswith(BASE_PREFIX)) or \
+			name in self.deps or name in self.deps_pending:
+			return
+
+		if name in FORCE_STRUCT_AS_OPAQUE:
+			self.deps.append(name)
+			return
+
+		self.deps_pending.append(name)
+		for node in self.nodes[name]:
+			self.visit(node)
+		if not self.deps_pending.pop() == name:
+			print 'Error initializing dep!'
+			sys.exit(1)
+		self.deps.append(name)
+
+	# Opaque struct is identified by empty struct member declaration.
+	def _is_struct_opaque(self, node):
+		if isinstance(node, c_ast.Typedef) and isinstance(node.type, c_ast.TypeDecl) and \
+		   isinstance(node.type.type, c_ast.Struct) and node.type.type.decls == None:
+			return True
+		elif isinstance(node, c_ast.Decl) and isinstance(node.type, c_ast.Struct) and \
+			 node.type.decls == None:
+			return True
+		return False
+
+	# Check if the specified struct name is opaque. If it is, declare as zero member and
+	# tell SWIG to omit ctor/dtor.
+	def _process_opaque_struct(self, name, code):
+		opaque = True
+		if not (name in FORCE_STRUCT_AS_OPAQUE):
+			for n in self.nodes[name]:
+				if not self._is_struct_opaque(n):
+					opaque = False
+					break
+		if opaque:
+			s = '%nodefaultctor ' + name + '; %nodefaultdtor ' + name + ';\n'
+			s += 'struct ' + name + ' {};\n'
+			return s
+
+		# Remove "typedef struct/enum ..." without member decl (optional)
+		if name:
+			code = code.replace('typedef struct '+name+' '+name+';\n', '', 1)
+			code = code.replace('typedef enum '+name+' '+name+';\n', '', 1)
+		return code
+
+	def _gen_pjsua_callback(self, code):
+		# init
+		cbclass  = ''
+		cbproxy = ''
+		cbdef = []
+
+		raw_lines = code.splitlines()
+		for idx, line in enumerate(raw_lines):
+			if idx in [0, 1, len(raw_lines)-1]: continue
+			fstrs = []
+			# pointer to function type format
+			m = re.match('\s+(.*)\(\*(.*)\)(\(.*\));', line)
+			if m:
+				fstrs = [m.group(1).strip(), m.group(2), m.group(3)]
+			else:
+				# typedef'd format
+				m = re.match('\s+(.*)\s+(.*);', line)
+				if (not m) or (not self.nodes.has_key(m.group(1))):
+					cbdef.append('  NULL')
+					continue
+				fstrs = ['', m.group(2), '']
+				n = self.nodes[m.group(1)][0]
+				raw = self._print_node(n)
+				m = re.match('typedef\s+(.*)\(\*(.*)\)(\(.*\));', raw)
+				if not m:
+					cbdef.append('  NULL')
+					continue
+				fstrs[0] = m.group(1).strip()
+				fstrs[2] = m.group(3)
+
+			cbclass += '  virtual ' + ' '.join(fstrs)
+			if fstrs[0] == 'void':
+				cbclass += ' {}\n'
+			elif fstrs[1] == 'on_create_media_transport':
+				cbclass += ' { return base_tp; }\n'
+			elif fstrs[1] == 'on_call_redirected':
+				cbclass += ' { return PJSIP_REDIRECT_STOP; }\n'
+			else:
+				cbclass += ' { return 0; }\n'
+
+			cbproxy += 'static ' + ' '.join(fstrs)
+			params = re.findall('(\w+)[,\)]', fstrs[2])
+			if fstrs[0] == 'void':
+				cbproxy += ' { cb->'+fstrs[1]+'('+','.join(params)+'); }\n'
+			else:
+				cbproxy += ' { return cb->'+fstrs[1]+'('+','.join(params)+'); }\n'
+
+			cbdef.append('  &' + fstrs[1])
+
+		return [cbclass, cbproxy, ',\n'.join(cbdef)+'\n']
+
+	def _process_pjsua_callback(self, name, code):
+		if name != 'pjsua_callback':
+			return code
+
+		cb = self._gen_pjsua_callback(code)
+
+		fout = open(OUTDIR+'/callbacks.h', 'w+')
+		fin  = open('jni/callbacks.h.template', 'r')
+		for line in fin:
+			if line.find(r'$PJSUA_CALLBACK_CLASS$') >= 0:
+				fout.write(cb[0])
+			else:
+				fout.write(line)
+		fin.close()
+		fout.close()
+
+		fout = open(OUTDIR+'/callbacks.cpp', 'w+')
+		fin  = open('jni/callbacks.c.template', 'r')
+		for line in fin:
+			if line.find(r'$PJSUA_CALLBACK_PROXY$') >= 0:
+				fout.write(cb[1])
+			elif line.find(r'$PJSUA_CALLBACK_DEF$') >= 0:
+				fout.write(cb[2])
+			else:
+				fout.write(line)
+		fin.close()
+		fout.close()
+		return ''
+
+	# Generate code from the specified node.
+	def _print_node(self, node):
+		s = ''
+		if isinstance(node, c_ast.FuncDef):
+			s = self.visit(node)
+		else:
+			s = self.visit(node)
+			if s: s += ';\n'
+		return s
+
+	def go(self):
+		s = ''
+		for name in self.deps:
+			ss = ''
+			for node in self.nodes[name]:
+				ss += self._print_node(node)
+
+			ss = self._process_opaque_struct(name, ss)
+			ss = self._process_pjsua_callback(name, ss)
+			s += ss
+		return s
+
+
+# MAIN			
+ast = parse_file(SOURCE_PATH, use_cpp=True, cpp_path=CPP_PATH, cpp_args=CPP_CFLAGS)
+#ast.show(attrnames=True, nodenames=True)
+#exit(0)
+
+mygen = MyGen(ast)
+
+#print 'Found ' + str(len(mygen.nodes)) + ' nodes:'
+#for a, b in mygen.nodes.items():
+#   print a + ':' + str(len(b))
+
+#print '\n\nFound ' + str(len(mygen.deps)) + ' dependencies:'
+#for d in mygen.deps:
+#   print d
+
+s = mygen.go()
+print s
+
Index: /pjproject/branches/projects/jni/pjsip-apps/src/jni/src/org/pjsip/hello/hello.java
===================================================================
--- /pjproject/branches/projects/jni/pjsip-apps/src/jni/src/org/pjsip/hello/hello.java	(revision 4568)
+++ /pjproject/branches/projects/jni/pjsip-apps/src/jni/src/org/pjsip/hello/hello.java	(revision 4568)
@@ -0,0 +1,218 @@
+/* $Id: hello.java 4566 2013-07-17 20:20:50Z nanang $ */
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.IOException;
+
+import org.pjsip.pjsua.*;
+
+class app_config {
+	public static int cur_call_id = -1;
+}
+
+class MyPjsuaCallback extends PjsuaCallback {
+	@Override
+	public void on_call_media_state(int call_id)
+	{
+		System.out.println("======== Call media started (call id: " + call_id + ")");
+		pjsua_call_info info = new pjsua_call_info();
+		pjsua.call_get_info(call_id, info);
+		if (info.getMedia_status() == pjsua_call_media_status.PJSUA_CALL_MEDIA_ACTIVE) {
+			pjsua.conf_connect(info.getConf_slot(), 0);
+			pjsua.conf_connect(0, info.getConf_slot());
+		}
+	}
+	
+	/* Testing pj_str_t-String map with director */
+	@Override
+	public void on_pager(int call_id, String from, String to, String contact, String mime_type, String body)
+	{
+		System.out.println("======== Incoming pager (call id: " + call_id + ")");
+		System.out.println("From     : " + from);
+		System.out.println("To       : " + to);
+		System.out.println("Contact  : " + contact);
+		System.out.println("Mimetype : " + mime_type);
+		System.out.println("Body     : " + body);
+	}
+	@Override
+	public void on_incoming_call(int acc_id, int call_id, pjsip_rx_data rdata) {
+		/* Auto answer */
+		pjsua.call_answer(call_id, 200, null, null);
+		app_config.cur_call_id = call_id;
+	}
+}
+
+class MyLogger extends PjsuaLoggingConfigCallback {
+	@Override
+	public void on_log(int level, String data)
+	{
+		System.out.print("LOG: " + data);
+	}
+}
+
+class MyTimerCallback extends PjTimerHeapCallback {
+	private int _user_data;
+	
+	/* Use this class itself to store app user data */
+	MyTimerCallback(int user_data) { _user_data = user_data; }
+	
+	@Override
+	public void on_timer(pj_timer_heap_t timer_heap, pj_timer_entry entry)
+	{
+		System.out.println("======== Timer fired (user data = " + _user_data + ")");
+	}
+}
+
+
+public class hello {
+	static {
+		System.loadLibrary("pjsua");
+	}
+
+	protected static void pj_error_exit(String message, int status) {
+		pjsua.perror("hello", message, status);
+		pjsua.destroy();
+		System.exit(status);
+	}
+
+	public static void main(String[] args) {
+		int[] tp_id = new int[1];
+		int[] acc_id = new int[1];
+		int[] call_id = new int[1];
+		int status;
+
+		/* Say hello first */
+		System.out.println("Hello, World");
+
+		/* Create pjsua */
+		{
+			status = pjsua.create();
+			if (status != pjsua.PJ_SUCCESS) {
+				System.out.println("Error creating pjsua: " + status);
+				System.exit(status);
+			}
+		}
+		
+		/* Init pjsua */
+		{
+			pjsua_config cfg = new pjsua_config();
+			pjsua.config_default(cfg);
+			cfg.setCb(new MyPjsuaCallback());
+
+			pjsua_logging_config log_cfg = new pjsua_logging_config();
+			pjsua.logging_config_default(log_cfg);
+			log_cfg.setLevel(4);
+			log_cfg.setCb(new MyLogger());
+
+			status = pjsua.init(cfg, log_cfg, null);
+			if (status != pjsua.PJ_SUCCESS) {
+				pj_error_exit("Error inintializing pjsua", status);
+			}
+		}
+		
+		/* Add SIP UDP transport */
+		{
+			pjsua_transport_config cfg = new pjsua_transport_config();
+			pjsua.transport_config_default(cfg);
+			cfg.setPort(6000);
+			status = pjsua.transport_create(pjsip_transport_type_e.PJSIP_TRANSPORT_UDP, cfg, tp_id);
+			if (status != pjsua.PJ_SUCCESS) {
+				pj_error_exit("Error creating transport", status);
+			}
+		}
+		
+		/* Add local account */
+		{
+			status = pjsua.acc_add_local(tp_id[0], true, acc_id);
+			if (status != pjsua.PJ_SUCCESS) {
+				pj_error_exit("Error creating local UDP account", status);
+			}
+		}
+		
+		/* Start pjsua */
+		{
+			status = pjsua.start();
+			if (status != pjsua.PJ_SUCCESS) {
+				pj_error_exit("Error starting pjsua", status);
+			}
+		}
+		
+		/* Make call to the URL. */
+		if (false) {
+			status = pjsua.call_make_call(acc_id[0], "sip:localhost:6000", null, 0, null, call_id);
+			if (status != pjsua.PJ_SUCCESS) {
+				pj_error_exit("Error making call", status);
+			}
+			app_config.cur_call_id = call_id[0];
+		}
+		
+		/* Test timer */
+		{
+			pj_timer_entry timer = new pj_timer_entry();
+			timer.setCb(new MyTimerCallback(1234567890));
+
+			pj_time_val tv = new pj_time_val();
+			tv.setSec(0);
+			tv.setMsec(1000);
+
+			pjsua.schedule_timer(timer, tv);
+		}
+		
+		/* Wait until user press "q" to quit. */
+		for (;;) {
+			String userInput;
+			BufferedReader inBuffReader = new BufferedReader(new InputStreamReader(System.in));
+
+			System.out.println("Press 'h' to hangup all calls, 'q' to quit");
+
+			try {
+				userInput = inBuffReader.readLine();
+			} catch (IOException e) {
+				System.out.println("Error in readLine(): " + e);
+				break;
+			}
+			
+			if (userInput.equals("q")) {
+				break;
+			} else if (userInput.equals("h")) {
+				pjsua.call_hangup_all();
+				app_config.cur_call_id = -1;
+			} else if (userInput.equals("c")) {
+				/* Test string as output param, it is wrapped as string array */
+				String[] contact = new String[1];
+				pj_pool_t my_pool = pjsua.pool_create("hello", 256, 256);
+				
+				pjsua.acc_create_uac_contact(my_pool, contact, 0, "sip:localhost");
+				System.out.println("Test create contact: " + contact[0]);
+				
+				pjsua.pj_pool_release(my_pool);
+			} else if (userInput.equals("d")) {
+				pjsua.dump(false);
+			} else if (userInput.equals("dd")) {
+				pjsua.dump(true);
+			} else if (userInput.equals("dq")) {
+				if (app_config.cur_call_id == -1) {
+					System.out.println("No active call");
+					continue;
+				}
+				
+				byte[] buf = new byte[1024*2];
+				pjsua.call_dump(app_config.cur_call_id, true, buf, "");
+
+				/* Build string from byte array, find null terminator first */
+				int len = 0;
+				while (len < buf.length && buf[len] != 0) ++len;
+				String call_dump = new String(buf, 0, len);
+
+				System.out.println("Statistics of call " + app_config.cur_call_id);
+				System.out.println(call_dump);
+			}
+		}
+
+		/* Finally, destroy pjsua */
+		{
+			pjsua.destroy();
+		}
+		
+	}
+}
