Index: pjproject/branches/projects/jni/pjsip-apps/src/jni/jni/callbacks.i
===================================================================
--- pjproject/branches/projects/jni/pjsip-apps/src/jni/jni/callbacks.i	(revision 4569)
+++ pjproject/branches/projects/jni/pjsip-apps/src/jni/jni/callbacks.i	(revision 4570)
@@ -57,2 +57,11 @@
 %ignore pjsip_tx_data::cb;
 %ignore pjsip_transaction::state_handler;
+
+/* Ignore some struct members with aux credential callbacks, at least temporarily */
+%ignore pjsip_cred_info::ext;
+%ignore pjsip_cred_info_ext;
+%ignore pjsip_cred_info_ext_aka;
+
+%ignore pj_stun_auth_cred::data::dyn_cred;
+%ignore pj_stun_auth_cred_data::dyn_cred;
+%ignore pj_stun_auth_cred_data_dyn_cred;
Index: pjproject/branches/projects/jni/pjsip-apps/src/jni/jni/header.i
===================================================================
--- pjproject/branches/projects/jni/pjsip-apps/src/jni/jni/header.i	(revision 4569)
+++ pjproject/branches/projects/jni/pjsip-apps/src/jni/jni/header.i	(revision 4570)
@@ -78,14 +78,4 @@
 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"
 
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 4569)
+++ pjproject/branches/projects/jni/pjsip-apps/src/jni/jni/my_typemaps.i	(revision 4570)
@@ -14,4 +14,10 @@
 };
 %}
+
+/*
+ * Typemap for setting member of inner struct/union.
+ */
+%typemap(memberin) NESTED_INNER "if ($input) pj_memcpy(&$1, $input, sizeof(*$input));"
+
 
 /*
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 4569)
+++ pjproject/branches/projects/jni/pjsip-apps/src/jni/jni/swig_gen.py	(revision 4570)
@@ -262,4 +262,65 @@
 		return ''
 
+
+	# Move out inner struct/union
+	def _process_nested_struct_union(self, code):
+		if not (code.startswith('struct') or \
+			code.startswith('typedef struct') or \
+			code.startswith('typedef union')):
+			return code
+			
+		# max nested level is 5
+		name = ['','','','','']
+		type = ['','','','','']
+		content = ['','','','','']
+		level = 0
+		s = ''
+		for line in code.splitlines():
+			line_s = line.lstrip()
+			if (not line_s) or (line_s == '{'): continue
+
+			last_level = level
+			level = (len(line) - len(line_s)) / 2
+
+			if level < last_level:
+				if not line_s.startswith('}'):
+					print "bad tabulation!"
+
+				# closing bracket, get var name
+				varname = ''
+				vartail = ''
+				m = re.match(r'\}\s*(\w+)(.*);', line_s)
+				if m:
+					varname = m.group(1)
+					vartail = m.group(2)
+					if level > 0:
+						name[level] = '$name' + str(level-1) + '$_' + varname
+				# print inner struct/union in outer
+				ss = type[level] + ' ' + name[level] + '\n'
+				ss += '{\n' + content[level] + '};\n'
+				if level > 0:
+					s += "%inline %{\n" + ss + '%}\n'
+					s += "%apply NESTED_INNER { " + name[level] + " " + varname + " };\n"
+				else:
+					s += ss
+				content[level] = ''
+				# print inner struct member var at global scope
+				if level > 0:
+					content[level-1] += ' '*level*2 + type[level] + ' ' + name[level] + ' ' + varname + vartail + ';\n'
+					s = s.replace('$name' + str(level) + '$', '$name' + str(level-1) + '$_' + varname)
+				else:
+					s = s.replace('$name' + str(level) + '$', name[level])
+
+			elif level >= last_level:
+				if line_s.startswith('typedef'): line_s = line_s[8:]
+				if (line_s.startswith('union') or line_s.startswith('struct')) and not line_s.endswith(';'):
+					ll = line_s.split()
+					type[level] = ll[0]
+					name[level] = ll[1] if len(ll) > 1 else ''
+				else:
+					content[level-1] += line + '\n'
+		return s
+		
+
 	# Generate code from the specified node.
 	def _print_node(self, node):
@@ -281,4 +342,5 @@
 			ss = self._process_opaque_struct(name, ss)
 			ss = self._process_pjsua_callback(name, ss)
+			ss = self._process_nested_struct_union(ss)
 			s += ss
 		return 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 4569)
+++ pjproject/branches/projects/jni/pjsip-apps/src/jni/src/org/pjsip/hello/hello.java	(revision 4570)
@@ -47,5 +47,5 @@
 	public void on_log(int level, String data)
 	{
-		System.out.print("LOG: " + data);
+		System.out.print("LOG" + level + ": " + data);
 	}
 }
@@ -74,4 +74,10 @@
 		pjsua.destroy();
 		System.exit(status);
+	}
+	
+	protected static boolean check_active_call() {
+		if (app_config.cur_call_id == -1)
+			System.out.println("No active call");
+		return (app_config.cur_call_id > -1);
 	}
 
@@ -192,8 +198,5 @@
 				pjsua.dump(true);
 			} else if (userInput.equals("dq")) {
-				if (app_config.cur_call_id == -1) {
-					System.out.println("No active call");
-					continue;
-				}
+				if (!check_active_call()) continue;
 				
 				byte[] buf = new byte[1024*2];
@@ -207,4 +210,11 @@
 				System.out.println("Statistics of call " + app_config.cur_call_id);
 				System.out.println(call_dump);
+			} else if (userInput.equals("si")) {
+				/* Test nested struct in pjsua_stream_info */
+				if (!check_active_call()) continue;
+
+				pjsua_stream_info si = new pjsua_stream_info();
+				pjsua.call_get_stream_info(app_config.cur_call_id, 0, si);
+				System.out.println("Audio codec being used: " + si.getInfo().getAud().getFmt().getEncoding_name());
 			}
 		}
