Index: pjproject/branches/projects/jni/pjsip-apps/src/jni/Makefile
===================================================================
--- pjproject/branches/projects/jni/pjsip-apps/src/jni/Makefile	(revision 4548)
+++ pjproject/branches/projects/jni/pjsip-apps/src/jni/Makefile	(revision 4549)
@@ -13,11 +13,7 @@
 MY_JNI_LDFLAGS	 = -L$(MY_JDK)/lib -Wl,--kill-at
 
-# Choose C or C++ SWIG wrapper target, just for dev purpose.
-# Note that C target doesn't support callback, and C++ target doesn't support nested class/struct.
-SWIG_CPP_TARGET = 0
-
 # Build settings
 MY_CFLAGS	 = $(PJ_CFLAGS) $(MY_JNI_CFLAGS)
-MY_LDFLAGS	 = $(PJ_LDFLAGS) $(PJ_LDLIBS) $(MY_JNI_LDFLAGS)
+MY_LDFLAGS	 = $(PJ_LDFLAGS) $(PJ_LDLIBS) $(MY_JNI_LDFLAGS) -static-libstdc++
 
 # Output/intermediate path settings
@@ -25,20 +21,9 @@
 MY_OUT_DIR	 = output
 MY_SWIG_IF	 = $(MY_OUT_DIR)/pjsua.i
-MY_SWIG_FLAG	 = -Wall
+MY_SWIG_FLAG	 = -c++ -I$(MY_OUT_DIR) # -Wall
 MY_SWIG_WRAPPER	 = $(MY_OUT_DIR)/pjsua_wrap
-MY_CALLBACKS	 = callbacks
 MY_PACKAGE_SRC	 = $(MY_OUT_DIR)/src/$(subst .,/,$(MY_PACKAGE))
 MY_PACKAGE_BIN	 = $(MY_OUT_DIR)/bin
 MY_JNI_LIB       = $(MY_PACKAGE_BIN)/pjsua.dll
-
-# Adjust setting for C/C++
-ifeq ($(SWIG_CPP_TARGET),1)
-MY_CC		 = $(PJ_CXX)
-MY_LDFLAGS	+= -static-libstdc++
-MY_SWIG_FLAG    += -c++ -debug-tmsearch -debug-tmused
-else
-MY_CC		 = $(PJ_CC)
-MY_SWIG_FLAG    += -debug-tmsearch -debug-tmused
-endif
 
 all: $(MY_JNI_LIB) java
@@ -47,32 +32,23 @@
 	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_IF).tmp: swig_gen.py
-	@mkdir -p $(MY_OUT_DIR)
-	python swig_gen.py > $(MY_SWIG_IF).tmp
-
-$(MY_SWIG_WRAPPER).c: $(MY_SWIG_IF) $(MY_CALLBACKS).h $(MY_CALLBACKS).cpp $(MY_CALLBACKS).i
-	# Cleanup java outdir first, to remove any old/deprecated java files
+$(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.txt
-	$(MY_SWIG) -c++ $(MY_SWIG_FLAG) -o $(MY_SWIG_WRAPPER)2.c -package $(MY_PACKAGE) \
-		-outdir $(MY_PACKAGE_SRC) -java $(MY_CALLBACKS).i > $(MY_SWIG_WRAPPER)2-tm.txt
+		-outdir $(MY_PACKAGE_SRC) -java $(MY_SWIG_IF) > $(MY_SWIG_WRAPPER)-tm.log
 
-$(MY_SWIG_WRAPPER).o: $(MY_SWIG_WRAPPER).c
-	$(MY_CC) -c $(MY_CFLAGS) $(MY_SWIG_WRAPPER).c -o $(MY_SWIG_WRAPPER).o
-	$(PJ_CXX) -c $(MY_CFLAGS) $(MY_SWIG_WRAPPER)2.c -o $(MY_SWIG_WRAPPER)2.o
-	
-$(MY_OUT_DIR)/$(MY_CALLBACKS).o: $(MY_CALLBACKS).cpp $(MY_CALLBACKS).h
-	$(PJ_CXX) -c $(MY_CFLAGS) $(MY_CALLBACKS).cpp -o $(MY_OUT_DIR)/$(MY_CALLBACKS).o
-
-$(MY_JNI_LIB): $(MY_SWIG_WRAPPER).o $(MY_OUT_DIR)/$(MY_CALLBACKS).o
+$(MY_JNI_LIB): $(MY_SWIG_WRAPPER).c
 	@mkdir -p $(MY_PACKAGE_BIN)
-	$(PJ_CXX) -shared -o $(MY_JNI_LIB) $(MY_SWIG_WRAPPER).o $(MY_OUT_DIR)/$(MY_CALLBACKS).o \
-		$(MY_SWIG_WRAPPER)2.o $(MY_LDFLAGS) -static-libstdc++
+	$(PJ_CXX) -shared -o $(MY_JNI_LIB) $(MY_SWIG_WRAPPER).c $(MY_OUT_DIR)/callbacks.c \
+		$(MY_CFLAGS) $(MY_LDFLAGS)
 
 java: hello.java
@@ -82,5 +58,5 @@
 
 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
+	@# 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: pjproject/branches/projects/jni/pjsip-apps/src/jni/callbacks.c.template
===================================================================
--- pjproject/branches/projects/jni/pjsip-apps/src/jni/callbacks.c.template	(revision 4549)
+++ pjproject/branches/projects/jni/pjsip-apps/src/jni/callbacks.c.template	(revision 4549)
@@ -0,0 +1,17 @@
+/* $Id$ */
+
+#include "callbacks.h"
+
+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/callbacks.cpp
===================================================================
--- pjproject/branches/projects/jni/pjsip-apps/src/jni/callbacks.cpp	(revision 4548)
+++ 	(revision )
@@ -1,20 +1,0 @@
-#include "callbacks.h"
-
-static PjsuaCallback* cb = NULL;
-
-void setPjsuaCallback(PjsuaCallback* callback) {
-	cb = callback;
-}
-
-static void on_call_media_state_wrapper(pjsua_call_id call_id) {
-	cb->on_call_media_state(call_id);
-}
-
-static pjsua_callback my_cb_proxy = {
-	NULL,
-	NULL,
-	NULL,
-	&on_call_media_state_wrapper
-};
-
-pjsua_callback* PJSUA_CALLBACK_PROXY = &my_cb_proxy;
Index: pjproject/branches/projects/jni/pjsip-apps/src/jni/callbacks.h
===================================================================
--- pjproject/branches/projects/jni/pjsip-apps/src/jni/callbacks.h	(revision 4548)
+++ 	(revision )
@@ -1,11 +1,0 @@
-#include <pjsua-lib/pjsua.h>
-
-class PjsuaCallback {
-public:
-    virtual void on_call_media_state (pjsua_call_id call_id) {}
-    virtual ~PjsuaCallback() {}
-};
-
-extern "C" {
-void setPjsuaCallback(PjsuaCallback* callback);
-}
Index: pjproject/branches/projects/jni/pjsip-apps/src/jni/callbacks.h.template
===================================================================
--- pjproject/branches/projects/jni/pjsip-apps/src/jni/callbacks.h.template	(revision 4549)
+++ pjproject/branches/projects/jni/pjsip-apps/src/jni/callbacks.h.template	(revision 4549)
@@ -0,0 +1,15 @@
+/* $Id$ */
+
+#include <pjsua-lib/pjsua.h>
+
+#ifndef SWIG /* SWIG should ignore these */
+class PjsuaCallback;
+extern void setPjsuaCallback(PjsuaCallback* callback);
+extern pjsua_callback* PJSUA_CALLBACK_PROXY;
+#endif
+
+class PjsuaCallback {
+public:
+  $PJSUA_CALLBACK_CLASS$
+  virtual ~PjsuaCallback() {}
+};
Index: pjproject/branches/projects/jni/pjsip-apps/src/jni/callbacks.i
===================================================================
--- pjproject/branches/projects/jni/pjsip-apps/src/jni/callbacks.i	(revision 4548)
+++ pjproject/branches/projects/jni/pjsip-apps/src/jni/callbacks.i	(revision 4549)
@@ -1,14 +1,16 @@
-%module (directors="1") pjsua_cb
-
-#pragma SWIG nowarn=312		/* nested struct/class/union */
+/* $Id$ */
 
 %header %{
-    #include <pjsua-lib/pjsua.h>
     #include "callbacks.h"
 %}
 
-# Get pjsua definitions
-%import "output/pjsua.i"
+%feature("director") PjsuaCallback;
+%ignore pjsua_config::cb;
+%extend pjsua_config {
+    void setCb(PjsuaCallback *pjsuaCb) {
+	$self->cb = *PJSUA_CALLBACK_PROXY;
+	setPjsuaCallback(pjsuaCb);
+    }
+}
 
-%feature("director") PjsuaCallback;
-%include "callbacks.h"
+%include <callbacks.h>
Index: pjproject/branches/projects/jni/pjsip-apps/src/jni/header.i
===================================================================
--- pjproject/branches/projects/jni/pjsip-apps/src/jni/header.i	(revision 4548)
+++ pjproject/branches/projects/jni/pjsip-apps/src/jni/header.i	(revision 4549)
@@ -1,66 +1,52 @@
-%module pjsua
+/* $Id$ */
 
-%include "typemaps.i"
+%module (directors="1") pjsua
+
 %include "enums.swg"
-%include "arrays_java.i"
+%include "../my_typemaps.i"
 
 %header %{
     #include <pjsua-lib/pjsua.h>
-    extern pjsua_callback* PJSUA_CALLBACK_PROXY;
 %}
 
-/* 'void *' shall be handled as byte arrays */
-%typemap(jni)		 void * "void *"
-%typemap(jtype) 	 void * "byte[]"
-%typemap(jstype) 	 void * "byte[]"
-%typemap(javain) 	 void * "$javainput"
-%typemap(javadirectorin) void * "$jniinput"
-%typemap(in) 		 void * { $1 = $input; }
-%typemap(out) 		 void * { $result = $1; }
-%typemap(javaout)	 void * { return $jnicall; }
+/* Strip "pjsua_" prefix from pjsua functions, for better compatibility with 
+ * pjsip-jni & csipsimple.
+ */
+%rename("%(strip:[pjsua_])s", %$isfunction) "";
 
-/* Apply output args */
-%apply unsigned	*INOUT  { unsigned *count };
-%apply unsigned *OUTPUT { unsigned *tx_level };
-%apply unsigned *OUTPUT { unsigned *rx_level };
-%apply unsigned *OUTPUT { unsigned *p_tail_ms };
-%apply int 	*OUTPUT { pjsua_acc_id *p_acc_id };
-%apply int 	*OUTPUT { pjsua_call_id *p_call_id };
-%apply int	*OUTPUT { pjsua_transport_id *p_id };
-%apply int	*OUTPUT { pjsua_recorder_id *p_id };
-%apply int 	*OUTPUT { pjsua_player_id *p_id };
-%apply int 	*OUTPUT { pjsua_buddy_id *p_buddy_id };
-%apply int 	*OUTPUT { pjsua_conf_port_id *p_id };
-%apply int 	*OUTPUT { int *capture_dev };
-%apply int 	*OUTPUT { int *playback_dev };
-%apply int 	*OUTPUT { pj_stun_nat_type * };
-%apply int[ANY] 	{ pjmedia_format_id dec_fmt_id[8] };
+/* Map 'void *' simply as long, app can use this "long" as index of its real user data */
+%apply long { void * };
 
-/* Array of pj_str_t */
+/* 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[ANY] { void *[ANY] };
+
+/* 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 int[ANY] 	{ pjmedia_format_id dec_fmt_id[ANY] };
+
+/* Handle array of pj_str_t */
 JAVA_ARRAYSOFCLASSES(pj_str_t)
-#ifndef __cplusplus
-    /* On C target, pj_str_t::cArrayWrap/Unwrap Java code are missing, this somehow 'fixes' it. */
-    JAVA_ARRAYSOFCLASSES(struct pj_str_t)
-#endif
 
-/* Array of pj_ssl_cipher in pjsip_tls_setting. Warning: this breaks JAVA_ARRAYS_TYPEMAPS(int)! */
-%typemap(out) int[] %{$result = SWIG_JavaArrayOutInt(jenv, (int*)$1, arg1->ciphers_num); %}
-%apply int[] { pj_ssl_cipher* };
-%ignore pjsip_tls_setting::ciphers;
-%ignore pjsip_tls_setting::ciphers_num;
-%extend pjsip_tls_setting {
-    void setCiphers(pj_ssl_cipher *ciphers, int num) {
-        int i;
-	$self->ciphers = (pj_ssl_cipher*)calloc(num, sizeof(pj_ssl_cipher));
-	for (i=0; i<num; ++i) $self->ciphers[i] = ciphers[i];
-	$self->ciphers_num = num;
-    }
-    pj_ssl_cipher* getCiphers() {
-	return $self->ciphers;
-    }
-};
+/* 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)
 
-/* C++ SWIG target doesn't support nested class (C version does though).
+/* 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.
@@ -72,41 +58,5 @@
 #endif
 
-/* Typemaps for marshalling pjmedia_port ** */
-%typemap(jni) pjmedia_port **p_port "jobject"
-%typemap(jtype) pjmedia_port **p_port "pjmedia_port"
-%typemap(jstype) pjmedia_port **p_port "pjmedia_port"
-
-/* Typemaps for pjmedia_port ** as a parameter output type */
-%typemap(in) pjmedia_port **p_port (pjmedia_port *ppMediaPort = 0) %{ $1 = &ppMediaPort; %}
-%typemap(argout) pjmedia_port **p_port {
-  // Give Java proxy the C pointer (of newly created object)
-  jclass clazz = JCALL1(FindClass, jenv, "org/pjsip/pjsua/pjmedia_port");
-  jfieldID fid = JCALL3(GetFieldID, jenv, clazz, "swigCPtr", "J");
-  jlong cPtr = 0;
-  *(pjmedia_port **)&cPtr = *$1;
-  JCALL3(SetLongField, jenv, $input, fid, cPtr);
-}
-%typemap(javain) pjmedia_port **p_port "$javainput"
-
-
-/* Strip "pjsua_" prefix from pjsua functions, for better compatibility with 
- * pjsip-jni & csipsimple.
- */
-%rename("%(strip:[pjsua_])s", %$isfunction) "";
-
-/* Automatically init pjsua_config::cb to cb proxy via pjsua_config_default() */
-/* 1. Hide 'cb' from 'pjsua_config' */
-%ignore pjsua_config::cb;
-/* 2. Ignore original pjsua_config_default() */
-%ignore pjsua_config_default;
-/* 3. Optional, put back "pjsua_" prefix, if stripping is not preferred */
-//%rename(pjsua_config_default) config_default;
-/* 4. Put custom implementation */
-%inline %{
-    void config_default(pjsua_config *cfg) {
-        pjsua_config_default(cfg);
-	cfg->cb = *PJSUA_CALLBACK_PROXY;
-    }
-%}
+%include "../callbacks.i"
 
 /* Global constants */
Index: pjproject/branches/projects/jni/pjsip-apps/src/jni/hello.java
===================================================================
--- pjproject/branches/projects/jni/pjsip-apps/src/jni/hello.java	(revision 4548)
+++ pjproject/branches/projects/jni/pjsip-apps/src/jni/hello.java	(revision 4549)
@@ -1,2 +1,4 @@
+/* $Id$ */
+
 import java.io.BufferedReader;
 import java.io.InputStreamReader;
@@ -12,5 +14,4 @@
 import org.pjsip.pjsua.pj_str_t;
 import org.pjsip.pjsua.PjsuaCallback;
-import org.pjsip.pjsua.pjsua_cb;
 
 class MyPjsuaCallback extends PjsuaCallback {
@@ -68,6 +69,6 @@
 			pjsua_config cfg = new pjsua_config();
 			pjsua.config_default(cfg);
-			/* Setup callback for callback proxy */
-			pjsua_cb.setPjsuaCallback(new MyPjsuaCallback());
+			/* Setup callback */
+			cfg.setCb(new MyPjsuaCallback());
 			status = pjsua.init(cfg, null, null);
 			if (status != pjsua.PJ_SUCCESS) {
@@ -106,5 +107,5 @@
 		{
 			pj_str_t call_target = pj_str("sip:localhost");
-			status = pjsua.call_make_call(acc_id[0], call_target, null, null, null, call_id);
+			status = pjsua.call_make_call(acc_id[0], call_target, null, 0, null, call_id);
 			if (status != pjsua.PJ_SUCCESS) {
 				pj_error_exit("Error making call", status);
Index: pjproject/branches/projects/jni/pjsip-apps/src/jni/my_typemaps.i
===================================================================
--- pjproject/branches/projects/jni/pjsip-apps/src/jni/my_typemaps.i	(revision 4549)
+++ pjproject/branches/projects/jni/pjsip-apps/src/jni/my_typemaps.i	(revision 4549)
@@ -0,0 +1,146 @@
+# $Id$
+
+%include "arrays_java.i"
+%include "typemaps.i"
+
+/* Add director typemaps for "int *INOUT" */
+%typemap(javadirectorin) int *INOUT "$jniinput"
+%typemap(directorin, descriptor="[I") int *INOUT %{
+  $input = jenv->NewIntArray(1);
+  jenv->SetIntArrayRegion($input, 0, 1, (jint*)$1);
+%}
+%typemap(directorout) int *INOUT %{
+  jint* tmp$result = jenv->GetIntArrayElements($input, 0);
+  *$result = tmp$result[0];
+  jenv->ReleaseIntArrayElements($input, tmp$result, JNI_ABORT);
+%}
+%typemap(directorargout) int *INOUT %{
+  jint* tmp$1 = jenv->GetIntArrayElements($input, 0);
+  *$1 = ($*1_ltype) tmp$1[0];
+  jenv->ReleaseIntArrayElements($input, tmp$1, JNI_ABORT);
+%}
+
+/* Add director typemaps for "unsigned *INOUT" */
+%typemap(javadirectorin) unsigned *INOUT "$jniinput"
+%typemap(directorin, descriptor="[I") unsigned *INOUT %{
+  $input = jenv->NewLongArray(1);
+  jenv->SetLongArrayRegion($input, 0, 1, (jlong*)$1);
+%}
+%typemap(directorout) unsigned *INOUT %{
+  jlong* tmp$result = jenv->GetLongArrayElements($input, 0);
+  *$result = tmp$result[0];
+  jenv->ReleaseLongArrayElements($input, tmp$result, JNI_ABORT);
+%}
+%typemap(directorargout) unsigned *INOUT %{
+  jlong* tmp$1 = jenv->GetLongArrayElements($input, 0);
+  *$1 = ($*1_ltype) tmp$1[0];
+  jenv->ReleaseLongArrayElements($input, tmp$1, JNI_ABORT);
+%}
+
+/* 
+ * 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.
+ * Sample usage, given enum array member in this struct:
+ * --
+ *   struct pjsip_tls_setting {
+ *     ..
+ *     unsigned ciphers_num;
+ *     pj_ssl_cipher *ciphers;
+ *     ..
+ *   };
+ * --
+ * apply:
+ *   MY_JAVA_MEMBER_ARRAY_OF_ENUM(pjsip_tls_setting, pj_ssl_cipher, ciphers, ciphers_num)
+ */
+%define MY_JAVA_MEMBER_ARRAY_OF_ENUM(CLASS_NAME, TYPE, NAME, COUNT_NAME)
+
+%apply ARRAYSOFENUMS[] { TYPE* };
+%typemap(out) TYPE* %{ $result = SWIG_JavaArrayOutInt(jenv, (int*)$1, arg1->COUNT_NAME); %}
+%ignore CLASS_NAME::NAME;
+%ignore CLASS_NAME::COUNT_NAME;
+%extend CLASS_NAME {
+    %rename ("%(lowercamelcase)s") set_##NAME;
+    %rename ("%(lowercamelcase)s") get_##NAME;
+    void set_##NAME(TYPE *NAME, int num) {
+        int i;
+	if ($self->NAME) free($self->NAME);
+	$self->NAME = (TYPE*)calloc(num, sizeof(TYPE));
+	for (i=0; i<num; ++i) $self->NAME[i] = NAME[i];
+	$self->COUNT_NAME = num;
+    }
+    TYPE* get_##NAME() {
+	return $self->NAME;
+    }
+    ~CLASS_NAME() {
+	if ($self->NAME) free($self->NAME);
+    }
+};
+
+%enddef
+
+
+/* 
+ * Handle getter of a struct member with type of 'array of pointer to struct/class'.
+ * Currently this is applicable for read-only member.
+ */
+%define MY_JAVA_MEMBER_ARRAY_OF_POINTER(CLASS_NAME, TYPE, NAME, COUNT_NAME)
+
+%ignore CLASS_NAME::COUNT_NAME;
+%immutable CLASS_NAME::NAME;
+%typemap(jni) TYPE *[ANY] "jlongArray"
+%typemap(jtype) TYPE *[ANY] "long[]"
+%typemap(jstype) TYPE *[ANY] "TYPE[]"
+%typemap(javain) TYPE *[ANY] "TYPE.cArrayUnwrap($javainput)"
+%typemap(javaout) TYPE *[ANY] {return TYPE.cArrayWrap($jnicall, $owner);}
+
+// somehow "$result" is not preprocessed in "typemap(ret)", use 'jresult' directly then
+%typemap(ret) TYPE *[ANY] {
+  jlong *arr;
+  int i;
+  jresult = JCALL1(NewLongArray, jenv, arg1->COUNT_NAME);
+  if (!jresult) {
+    return $null;
+  }
+  arr = JCALL2(GetLongArrayElements, jenv, jresult, 0);
+  if (!arr) {
+    return $null;
+  }
+  for (i=0; i<arg1->COUNT_NAME; i++) {
+    arr[i] = 0;
+    *($1_ltype)&arr[i] = $1[i];
+  }
+  JCALL3(ReleaseLongArrayElements, jenv, jresult, arr, 0);
+}
+
+%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/swig_gen.py
===================================================================
--- pjproject/branches/projects/jni/pjsip-apps/src/jni/swig_gen.py	(revision 4548)
+++ pjproject/branches/projects/jni/pjsip-apps/src/jni/swig_gen.py	(revision 4549)
@@ -3,6 +3,6 @@
 #!/usr/bin/python
 
-# import re
-import sys #, os, traceback
+import re
+import sys, os #, traceback
 from collections import OrderedDict
 from pycparser import parse_file, c_ast, c_generator
@@ -57,8 +57,12 @@
 	'pjmedia_transport',
 	'pjsua_media_transport',
-	'pjsua_callback'
+	'pjsua_callback',
+	'pjmedia_stream'
 ]
 
 FORCE_EXPORT = [
+	'pjsip_event',
+	'pjsip_transaction',
+	'pjmedia_sdp_session',
 	#'pj_str' # plain export result doesn't work!
 ]
@@ -101,5 +105,5 @@
 	if not self.deps_frozen:
 	    for name in n.names: self._add_dep(name)
-        return ' '.join(n.names)
+	return super(MyGen, self).visit_IdentifierType(n)
 
     def _check_video(self, name):
@@ -129,5 +133,5 @@
 	    return
 	    
-	if name in FORCE_STRUCT_AS_OPAQUE:
+	if name in FORCE_STRUCT_AS_OPAQUE and (not name == 'pjsua_callback'):
 	    self.deps.append(name)
 	    return
@@ -171,4 +175,58 @@
 	return code
 	
+    def _gen_pjsua_callback(self):
+	# init
+	cbclass  = ''
+	cbproxy = ''
+	cbdef = []
+
+        n = self.nodes['pjsua_callback'][0]
+	raw_lines = self._print_node(n).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])
+		
+	# trail	
+	
+        return [cbclass, cbproxy, ',\n'.join(cbdef)+'\n']
+    
     # Generate code from the specified node.
     def _print_node(self, node):
@@ -189,4 +247,29 @@
 	    s += self._process_opaque_struct(name, ss)
 	return s
+	
+    def write_pjsua_callback(self, outdir):
+        cb = self._gen_pjsua_callback()
+	
+	fout = open(outdir+'/callbacks.h', 'w+')
+        fin  = open('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.c', 'w+')
+        fin  = open('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()
 
 # MAIN		
@@ -205,4 +288,9 @@
 #   print d
 
+sys.argv.pop(0)
+outdir = sys.argv.pop() if len(sys.argv) else 'output'
+mygen.write_pjsua_callback(outdir)
+
 s = mygen.go()
 print s
+
Index: pjproject/branches/projects/jni/pjsip/include/pjsip-ua/sip_regc.h
===================================================================
--- pjproject/branches/projects/jni/pjsip/include/pjsip-ua/sip_regc.h	(revision 4548)
+++ pjproject/branches/projects/jni/pjsip/include/pjsip-ua/sip_regc.h	(revision 4549)
@@ -61,5 +61,5 @@
  *  has finished.
  */
-struct pjsip_regc_cbparam
+typedef struct pjsip_regc_cbparam
 {
     pjsip_regc		*regc;	    /**< Client registration structure.	    */
@@ -78,9 +78,9 @@
     int			 contact_cnt;/**<Number of contacts in response.    */
     pjsip_contact_hdr	*contact[PJSIP_REGC_MAX_CONTACT]; /**< Contacts.    */
-};
+} pjsip_regc_cbparam;
 
 
 /** Type declaration for callback to receive registration result. */
-typedef void pjsip_regc_cb(struct pjsip_regc_cbparam *param);
+typedef void pjsip_regc_cb(pjsip_regc_cbparam *param);
 
 /**
Index: pjproject/branches/projects/jni/pjsip/include/pjsua-lib/pjsua.h
===================================================================
--- pjproject/branches/projects/jni/pjsip/include/pjsua-lib/pjsua.h	(revision 4548)
+++ pjproject/branches/projects/jni/pjsip/include/pjsua-lib/pjsua.h	(revision 4549)
@@ -473,6 +473,6 @@
 typedef struct pjsua_reg_info
 {
-    struct pjsip_regc_cbparam	*cbparam;   /**< Parameters returned by
-						 registration callback.	*/
+    pjsip_regc_cbparam	*cbparam;	/**< Parameters returned by
+					     registration callback.	*/
 } pjsua_reg_info;
 
