* #39101: updated pjsip stack, many android build enhancements.

The main issue here is due to the build system of the stack compared to a pure Android
NDK project. Generating arm and x86 ABI at the same time does not seem to be possible.
diff --git a/jni/pjproject-android/pjsip-apps/build/Makefile b/jni/pjproject-android/pjsip-apps/build/Makefile
index 71fb151..c776de1 100644
--- a/jni/pjproject-android/pjsip-apps/build/Makefile
+++ b/jni/pjproject-android/pjsip-apps/build/Makefile
@@ -62,10 +62,18 @@
 # Main entry
 #
 #
+#  x   x  x  x  x  x  x   x  x  x  x  x  x   x  x  x  x  x  x   x  x  x  x  x
+#
+#                FIX THIS
+#
+#  x   x  x  x  x  x  x   x  x  x  x  x  x   x  x  x  x  x  x   x  x  x  x  x
 TARGETS := $(BINDIR)/$(PJSUA_EXE) $(BINDIR)/$(PJSYSTEST_EXE) samples
 
 all: $(TARGETS)
 
+swig:
+	$(MAKE) -C ../src/swig
+	
 doc:
 
 dep: depend
diff --git a/jni/pjproject-android/pjsip-apps/build/Samples.mak b/jni/pjproject-android/pjsip-apps/build/Samples.mak
index 57daa8b..65d25b9 100644
--- a/jni/pjproject-android/pjsip-apps/build/Samples.mak
+++ b/jni/pjproject-android/pjsip-apps/build/Samples.mak
@@ -29,6 +29,7 @@
 	   mix \
 	   pjsip-perf \
 	   pcaputil \
+	   pjsua2_demo \
 	   playfile \
 	   playsine \
 	   recfile \
@@ -53,7 +54,7 @@
 all: $(EXES)
 
 $(EXES):
-	$(MAKE) --no-print-directory -f $(RULES_MAK) SAMPLE_SRCDIR=$(SRCDIR) SAMPLE_OBJS=$@.o SAMPLE_CFLAGS="$(_CFLAGS)" SAMPLE_LDFLAGS="$(_LDFLAGS)" SAMPLE_EXE=$@ APP=SAMPLE app=sample $(subst /,$(HOST_PSEP),$(BINDIR)/$@)
+	$(MAKE) --no-print-directory -f $(RULES_MAK) SAMPLE_SRCDIR=$(SRCDIR) SAMPLE_OBJS=$@.o SAMPLE_CFLAGS="$(_CFLAGS)" SAMPLE_CXXFLAGS="$(_CXXFLAGS)" SAMPLE_LDFLAGS="$(_LDFLAGS) -lstdc++" SAMPLE_EXE=$@ APP=SAMPLE app=sample $(subst /,$(HOST_PSEP),$(BINDIR)/$@)
 
 depend:
 
diff --git a/jni/pjproject-android/pjsip-apps/build/sample_debug.vcproj b/jni/pjproject-android/pjsip-apps/build/sample_debug.vcproj
index 1f7331f..1f821e4 100644
--- a/jni/pjproject-android/pjsip-apps/build/sample_debug.vcproj
+++ b/jni/pjproject-android/pjsip-apps/build/sample_debug.vcproj
@@ -311,6 +311,140 @@
 			/>

 		</Configuration>

 		<Configuration

+			Name="Debug|Windows Mobile 6 Standard SDK (ARMV4I)"

+			ConfigurationType="1"

+			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-common-defaults.vsprops"

+			UseOfMFC="0"

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			CharacterSet="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				ExecutionBucket="7"

+				AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"

+				PrecompiledHeaderFile=""

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib oleaut32.lib uuid.lib ole32.lib user32.lib"

+				OutputFile="..\bin\sample-debug-$(TargetCPU)-wm6std-vc$(VSVer)-$(ConfigurationName).exe"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCCodeSignTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+			<DeploymentTool

+				ForceDirty="-1"

+				RemoteDirectory=""

+				RegisterOutput="0"

+				AdditionalFiles=""

+			/>

+			<DebuggerTool

+			/>

+		</Configuration>

+		<Configuration

+			Name="Debug|Windows Mobile 6 Professional SDK (ARMV4I)"

+			ConfigurationType="1"

+			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-common-defaults.vsprops"

+			UseOfMFC="0"

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			CharacterSet="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				ExecutionBucket="7"

+				AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"

+				PrecompiledHeaderFile=""

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib oleaut32.lib uuid.lib ole32.lib user32.lib"

+				OutputFile="..\bin\sample-debug-$(TargetCPU)-wm6pro-vc$(VSVer)-$(ConfigurationName).exe"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCCodeSignTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+			<DeploymentTool

+				ForceDirty="-1"

+				RemoteDirectory=""

+				RegisterOutput="0"

+				AdditionalFiles=""

+			/>

+			<DebuggerTool

+			/>

+		</Configuration>

+		<Configuration

 			Name="Release|Win32"

 			ConfigurationType="1"

 			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-release-defaults.vsprops"

@@ -585,6 +719,140 @@
 			/>

 		</Configuration>

 		<Configuration

+			Name="Release|Windows Mobile 6 Standard SDK (ARMV4I)"

+			ConfigurationType="1"

+			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-release-defaults.vsprops"

+			UseOfMFC="0"

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			CharacterSet="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				ExecutionBucket="7"

+				AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"

+				PrecompiledHeaderFile=""

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib oleaut32.lib uuid.lib ole32.lib user32.lib"

+				OutputFile="..\bin\sample-debug-$(TargetCPU)-wm6std-vc$(VSVer)-$(ConfigurationName).exe"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCCodeSignTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+			<DeploymentTool

+				ForceDirty="-1"

+				RemoteDirectory=""

+				RegisterOutput="0"

+				AdditionalFiles=""

+			/>

+			<DebuggerTool

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Windows Mobile 6 Professional SDK (ARMV4I)"

+			ConfigurationType="1"

+			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-release-defaults.vsprops"

+			UseOfMFC="0"

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			CharacterSet="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				ExecutionBucket="7"

+				AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"

+				PrecompiledHeaderFile=""

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib oleaut32.lib uuid.lib ole32.lib user32.lib"

+				OutputFile="..\bin\sample-debug-$(TargetCPU)-wm6pro-vc$(VSVer)-$(ConfigurationName).exe"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCCodeSignTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+			<DeploymentTool

+				ForceDirty="-1"

+				RemoteDirectory=""

+				RegisterOutput="0"

+				AdditionalFiles=""

+			/>

+			<DebuggerTool

+			/>

+		</Configuration>

+		<Configuration

 			Name="Debug-Static|Win32"

 			ConfigurationType="1"

 			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-common-defaults.vsprops"

@@ -860,6 +1128,140 @@
 			/>

 		</Configuration>

 		<Configuration

+			Name="Debug-Static|Windows Mobile 6 Standard SDK (ARMV4I)"

+			ConfigurationType="1"

+			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-common-defaults.vsprops"

+			UseOfMFC="0"

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			CharacterSet="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				ExecutionBucket="7"

+				AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"

+				PrecompiledHeaderFile=""

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib oleaut32.lib uuid.lib ole32.lib user32.lib"

+				OutputFile="..\bin\sample-debug-$(TargetCPU)-wm6std-vc$(VSVer)-$(ConfigurationName).exe"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCCodeSignTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+			<DeploymentTool

+				ForceDirty="-1"

+				RemoteDirectory=""

+				RegisterOutput="0"

+				AdditionalFiles=""

+			/>

+			<DebuggerTool

+			/>

+		</Configuration>

+		<Configuration

+			Name="Debug-Static|Windows Mobile 6 Professional SDK (ARMV4I)"

+			ConfigurationType="1"

+			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-common-defaults.vsprops"

+			UseOfMFC="0"

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			CharacterSet="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				ExecutionBucket="7"

+				AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"

+				PrecompiledHeaderFile=""

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib oleaut32.lib uuid.lib ole32.lib user32.lib"

+				OutputFile="..\bin\sample-debug-$(TargetCPU)-wm6pro-vc$(VSVer)-$(ConfigurationName).exe"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCCodeSignTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+			<DeploymentTool

+				ForceDirty="-1"

+				RemoteDirectory=""

+				RegisterOutput="0"

+				AdditionalFiles=""

+			/>

+			<DebuggerTool

+			/>

+		</Configuration>

+		<Configuration

 			Name="Release-Dynamic|Win32"

 			ConfigurationType="1"

 			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-release-defaults.vsprops"

@@ -1134,6 +1536,140 @@
 			/>

 		</Configuration>

 		<Configuration

+			Name="Release-Dynamic|Windows Mobile 6 Standard SDK (ARMV4I)"

+			ConfigurationType="1"

+			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-release-defaults.vsprops"

+			UseOfMFC="0"

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			CharacterSet="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				ExecutionBucket="7"

+				AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"

+				PrecompiledHeaderFile=""

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib oleaut32.lib uuid.lib ole32.lib user32.lib"

+				OutputFile="..\bin\sample-debug-$(TargetCPU)-wm6std-vc$(VSVer)-$(ConfigurationName).exe"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCCodeSignTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+			<DeploymentTool

+				ForceDirty="-1"

+				RemoteDirectory=""

+				RegisterOutput="0"

+				AdditionalFiles=""

+			/>

+			<DebuggerTool

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release-Dynamic|Windows Mobile 6 Professional SDK (ARMV4I)"

+			ConfigurationType="1"

+			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-release-defaults.vsprops"

+			UseOfMFC="0"

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			CharacterSet="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				ExecutionBucket="7"

+				AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"

+				PrecompiledHeaderFile=""

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib oleaut32.lib uuid.lib ole32.lib user32.lib"

+				OutputFile="..\bin\sample-debug-$(TargetCPU)-wm6pro-vc$(VSVer)-$(ConfigurationName).exe"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCCodeSignTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+			<DeploymentTool

+				ForceDirty="-1"

+				RemoteDirectory=""

+				RegisterOutput="0"

+				AdditionalFiles=""

+			/>

+			<DebuggerTool

+			/>

+		</Configuration>

+		<Configuration

 			Name="Debug-Dynamic|Win32"

 			ConfigurationType="1"

 			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-common-defaults.vsprops"

@@ -1409,6 +1945,140 @@
 			/>

 		</Configuration>

 		<Configuration

+			Name="Debug-Dynamic|Windows Mobile 6 Standard SDK (ARMV4I)"

+			ConfigurationType="1"

+			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-common-defaults.vsprops"

+			UseOfMFC="0"

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			CharacterSet="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				ExecutionBucket="7"

+				AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"

+				PrecompiledHeaderFile=""

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib oleaut32.lib uuid.lib ole32.lib user32.lib"

+				OutputFile="..\bin\sample-debug-$(TargetCPU)-wm6std-vc$(VSVer)-$(ConfigurationName).exe"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCCodeSignTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+			<DeploymentTool

+				ForceDirty="-1"

+				RemoteDirectory=""

+				RegisterOutput="0"

+				AdditionalFiles=""

+			/>

+			<DebuggerTool

+			/>

+		</Configuration>

+		<Configuration

+			Name="Debug-Dynamic|Windows Mobile 6 Professional SDK (ARMV4I)"

+			ConfigurationType="1"

+			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-common-defaults.vsprops"

+			UseOfMFC="0"

+			ATLMinimizesCRunTimeLibraryUsage="false"

+			CharacterSet="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				ExecutionBucket="7"

+				AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"

+				PrecompiledHeaderFile=""

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib oleaut32.lib uuid.lib ole32.lib user32.lib"

+				OutputFile="..\bin\sample-debug-$(TargetCPU)-wm6pro-vc$(VSVer)-$(ConfigurationName).exe"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCCodeSignTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+			<DeploymentTool

+				ForceDirty="-1"

+				RemoteDirectory=""

+				RegisterOutput="0"

+				AdditionalFiles=""

+			/>

+			<DebuggerTool

+			/>

+		</Configuration>

+		<Configuration

 			Name="Release-Static|Win32"

 			ConfigurationType="1"

 			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-release-defaults.vsprops"

@@ -1683,9 +2353,9 @@
 			/>

 		</Configuration>

 		<Configuration

-			Name="Debug|Windows Mobile 6 Standard SDK (ARMV4I)"

+			Name="Release-Static|Windows Mobile 6 Standard SDK (ARMV4I)"

 			ConfigurationType="1"

-			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-common-defaults.vsprops"

+			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-release-defaults.vsprops"

 			UseOfMFC="0"

 			ATLMinimizesCRunTimeLibraryUsage="false"

 			CharacterSet="1"

@@ -1750,9 +2420,9 @@
 			/>

 		</Configuration>

 		<Configuration

-			Name="Debug|Windows Mobile 6 Professional SDK (ARMV4I)"

+			Name="Release-Static|Windows Mobile 6 Professional SDK (ARMV4I)"

 			ConfigurationType="1"

-			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-common-defaults.vsprops"

+			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-release-defaults.vsprops"

 			UseOfMFC="0"

 			ATLMinimizesCRunTimeLibraryUsage="false"

 			CharacterSet="1"

@@ -1951,140 +2621,6 @@
 			/>

 		</Configuration>

 		<Configuration

-			Name="Release|Windows Mobile 6 Standard SDK (ARMV4I)"

-			ConfigurationType="1"

-			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-release-defaults.vsprops"

-			UseOfMFC="0"

-			ATLMinimizesCRunTimeLibraryUsage="false"

-			CharacterSet="1"

-			>

-			<Tool

-				Name="VCPreBuildEventTool"

-			/>

-			<Tool

-				Name="VCCustomBuildTool"

-			/>

-			<Tool

-				Name="VCXMLDataGeneratorTool"

-			/>

-			<Tool

-				Name="VCWebServiceProxyGeneratorTool"

-			/>

-			<Tool

-				Name="VCMIDLTool"

-			/>

-			<Tool

-				Name="VCCLCompilerTool"

-				ExecutionBucket="7"

-				AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"

-				PrecompiledHeaderFile=""

-			/>

-			<Tool

-				Name="VCManagedResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCPreLinkEventTool"

-			/>

-			<Tool

-				Name="VCLinkerTool"

-				AdditionalDependencies="iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib oleaut32.lib uuid.lib ole32.lib user32.lib"

-				OutputFile="..\bin\sample-debug-$(TargetCPU)-wm6std-vc$(VSVer)-$(ConfigurationName).exe"

-			/>

-			<Tool

-				Name="VCALinkTool"

-			/>

-			<Tool

-				Name="VCXDCMakeTool"

-			/>

-			<Tool

-				Name="VCBscMakeTool"

-			/>

-			<Tool

-				Name="VCCodeSignTool"

-			/>

-			<Tool

-				Name="VCPostBuildEventTool"

-			/>

-			<DeploymentTool

-				ForceDirty="-1"

-				RemoteDirectory=""

-				RegisterOutput="0"

-				AdditionalFiles=""

-			/>

-			<DebuggerTool

-			/>

-		</Configuration>

-		<Configuration

-			Name="Release|Windows Mobile 6 Professional SDK (ARMV4I)"

-			ConfigurationType="1"

-			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-release-defaults.vsprops"

-			UseOfMFC="0"

-			ATLMinimizesCRunTimeLibraryUsage="false"

-			CharacterSet="1"

-			>

-			<Tool

-				Name="VCPreBuildEventTool"

-			/>

-			<Tool

-				Name="VCCustomBuildTool"

-			/>

-			<Tool

-				Name="VCXMLDataGeneratorTool"

-			/>

-			<Tool

-				Name="VCWebServiceProxyGeneratorTool"

-			/>

-			<Tool

-				Name="VCMIDLTool"

-			/>

-			<Tool

-				Name="VCCLCompilerTool"

-				ExecutionBucket="7"

-				AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"

-				PrecompiledHeaderFile=""

-			/>

-			<Tool

-				Name="VCManagedResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCPreLinkEventTool"

-			/>

-			<Tool

-				Name="VCLinkerTool"

-				AdditionalDependencies="iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib oleaut32.lib uuid.lib ole32.lib user32.lib"

-				OutputFile="..\bin\sample-debug-$(TargetCPU)-wm6pro-vc$(VSVer)-$(ConfigurationName).exe"

-			/>

-			<Tool

-				Name="VCALinkTool"

-			/>

-			<Tool

-				Name="VCXDCMakeTool"

-			/>

-			<Tool

-				Name="VCBscMakeTool"

-			/>

-			<Tool

-				Name="VCCodeSignTool"

-			/>

-			<Tool

-				Name="VCPostBuildEventTool"

-			/>

-			<DeploymentTool

-				ForceDirty="-1"

-				RemoteDirectory=""

-				RegisterOutput="0"

-				AdditionalFiles=""

-			/>

-			<DebuggerTool

-			/>

-		</Configuration>

-		<Configuration

 			Name="Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)"

 			ConfigurationType="1"

 			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm5-release-defaults.vsprops"

@@ -2219,140 +2755,6 @@
 			/>

 		</Configuration>

 		<Configuration

-			Name="Debug-Static|Windows Mobile 6 Standard SDK (ARMV4I)"

-			ConfigurationType="1"

-			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-common-defaults.vsprops"

-			UseOfMFC="0"

-			ATLMinimizesCRunTimeLibraryUsage="false"

-			CharacterSet="1"

-			>

-			<Tool

-				Name="VCPreBuildEventTool"

-			/>

-			<Tool

-				Name="VCCustomBuildTool"

-			/>

-			<Tool

-				Name="VCXMLDataGeneratorTool"

-			/>

-			<Tool

-				Name="VCWebServiceProxyGeneratorTool"

-			/>

-			<Tool

-				Name="VCMIDLTool"

-			/>

-			<Tool

-				Name="VCCLCompilerTool"

-				ExecutionBucket="7"

-				AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"

-				PrecompiledHeaderFile=""

-			/>

-			<Tool

-				Name="VCManagedResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCPreLinkEventTool"

-			/>

-			<Tool

-				Name="VCLinkerTool"

-				AdditionalDependencies="iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib oleaut32.lib uuid.lib ole32.lib user32.lib"

-				OutputFile="..\bin\sample-debug-$(TargetCPU)-wm6std-vc$(VSVer)-$(ConfigurationName).exe"

-			/>

-			<Tool

-				Name="VCALinkTool"

-			/>

-			<Tool

-				Name="VCXDCMakeTool"

-			/>

-			<Tool

-				Name="VCBscMakeTool"

-			/>

-			<Tool

-				Name="VCCodeSignTool"

-			/>

-			<Tool

-				Name="VCPostBuildEventTool"

-			/>

-			<DeploymentTool

-				ForceDirty="-1"

-				RemoteDirectory=""

-				RegisterOutput="0"

-				AdditionalFiles=""

-			/>

-			<DebuggerTool

-			/>

-		</Configuration>

-		<Configuration

-			Name="Debug-Static|Windows Mobile 6 Professional SDK (ARMV4I)"

-			ConfigurationType="1"

-			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-common-defaults.vsprops"

-			UseOfMFC="0"

-			ATLMinimizesCRunTimeLibraryUsage="false"

-			CharacterSet="1"

-			>

-			<Tool

-				Name="VCPreBuildEventTool"

-			/>

-			<Tool

-				Name="VCCustomBuildTool"

-			/>

-			<Tool

-				Name="VCXMLDataGeneratorTool"

-			/>

-			<Tool

-				Name="VCWebServiceProxyGeneratorTool"

-			/>

-			<Tool

-				Name="VCMIDLTool"

-			/>

-			<Tool

-				Name="VCCLCompilerTool"

-				ExecutionBucket="7"

-				AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"

-				PrecompiledHeaderFile=""

-			/>

-			<Tool

-				Name="VCManagedResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCPreLinkEventTool"

-			/>

-			<Tool

-				Name="VCLinkerTool"

-				AdditionalDependencies="iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib oleaut32.lib uuid.lib ole32.lib user32.lib"

-				OutputFile="..\bin\sample-debug-$(TargetCPU)-wm6pro-vc$(VSVer)-$(ConfigurationName).exe"

-			/>

-			<Tool

-				Name="VCALinkTool"

-			/>

-			<Tool

-				Name="VCXDCMakeTool"

-			/>

-			<Tool

-				Name="VCBscMakeTool"

-			/>

-			<Tool

-				Name="VCCodeSignTool"

-			/>

-			<Tool

-				Name="VCPostBuildEventTool"

-			/>

-			<DeploymentTool

-				ForceDirty="-1"

-				RemoteDirectory=""

-				RegisterOutput="0"

-				AdditionalFiles=""

-			/>

-			<DebuggerTool

-			/>

-		</Configuration>

-		<Configuration

 			Name="Debug-Static|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)"

 			ConfigurationType="1"

 			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm5-common-defaults.vsprops"

@@ -2487,140 +2889,6 @@
 			/>

 		</Configuration>

 		<Configuration

-			Name="Release-Dynamic|Windows Mobile 6 Standard SDK (ARMV4I)"

-			ConfigurationType="1"

-			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-release-defaults.vsprops"

-			UseOfMFC="0"

-			ATLMinimizesCRunTimeLibraryUsage="false"

-			CharacterSet="1"

-			>

-			<Tool

-				Name="VCPreBuildEventTool"

-			/>

-			<Tool

-				Name="VCCustomBuildTool"

-			/>

-			<Tool

-				Name="VCXMLDataGeneratorTool"

-			/>

-			<Tool

-				Name="VCWebServiceProxyGeneratorTool"

-			/>

-			<Tool

-				Name="VCMIDLTool"

-			/>

-			<Tool

-				Name="VCCLCompilerTool"

-				ExecutionBucket="7"

-				AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"

-				PrecompiledHeaderFile=""

-			/>

-			<Tool

-				Name="VCManagedResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCPreLinkEventTool"

-			/>

-			<Tool

-				Name="VCLinkerTool"

-				AdditionalDependencies="iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib oleaut32.lib uuid.lib ole32.lib user32.lib"

-				OutputFile="..\bin\sample-debug-$(TargetCPU)-wm6std-vc$(VSVer)-$(ConfigurationName).exe"

-			/>

-			<Tool

-				Name="VCALinkTool"

-			/>

-			<Tool

-				Name="VCXDCMakeTool"

-			/>

-			<Tool

-				Name="VCBscMakeTool"

-			/>

-			<Tool

-				Name="VCCodeSignTool"

-			/>

-			<Tool

-				Name="VCPostBuildEventTool"

-			/>

-			<DeploymentTool

-				ForceDirty="-1"

-				RemoteDirectory=""

-				RegisterOutput="0"

-				AdditionalFiles=""

-			/>

-			<DebuggerTool

-			/>

-		</Configuration>

-		<Configuration

-			Name="Release-Dynamic|Windows Mobile 6 Professional SDK (ARMV4I)"

-			ConfigurationType="1"

-			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-release-defaults.vsprops"

-			UseOfMFC="0"

-			ATLMinimizesCRunTimeLibraryUsage="false"

-			CharacterSet="1"

-			>

-			<Tool

-				Name="VCPreBuildEventTool"

-			/>

-			<Tool

-				Name="VCCustomBuildTool"

-			/>

-			<Tool

-				Name="VCXMLDataGeneratorTool"

-			/>

-			<Tool

-				Name="VCWebServiceProxyGeneratorTool"

-			/>

-			<Tool

-				Name="VCMIDLTool"

-			/>

-			<Tool

-				Name="VCCLCompilerTool"

-				ExecutionBucket="7"

-				AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"

-				PrecompiledHeaderFile=""

-			/>

-			<Tool

-				Name="VCManagedResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCPreLinkEventTool"

-			/>

-			<Tool

-				Name="VCLinkerTool"

-				AdditionalDependencies="iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib oleaut32.lib uuid.lib ole32.lib user32.lib"

-				OutputFile="..\bin\sample-debug-$(TargetCPU)-wm6pro-vc$(VSVer)-$(ConfigurationName).exe"

-			/>

-			<Tool

-				Name="VCALinkTool"

-			/>

-			<Tool

-				Name="VCXDCMakeTool"

-			/>

-			<Tool

-				Name="VCBscMakeTool"

-			/>

-			<Tool

-				Name="VCCodeSignTool"

-			/>

-			<Tool

-				Name="VCPostBuildEventTool"

-			/>

-			<DeploymentTool

-				ForceDirty="-1"

-				RemoteDirectory=""

-				RegisterOutput="0"

-				AdditionalFiles=""

-			/>

-			<DebuggerTool

-			/>

-		</Configuration>

-		<Configuration

 			Name="Release-Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)"

 			ConfigurationType="1"

 			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm5-release-defaults.vsprops"

@@ -2755,140 +3023,6 @@
 			/>

 		</Configuration>

 		<Configuration

-			Name="Debug-Dynamic|Windows Mobile 6 Standard SDK (ARMV4I)"

-			ConfigurationType="1"

-			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-common-defaults.vsprops"

-			UseOfMFC="0"

-			ATLMinimizesCRunTimeLibraryUsage="false"

-			CharacterSet="1"

-			>

-			<Tool

-				Name="VCPreBuildEventTool"

-			/>

-			<Tool

-				Name="VCCustomBuildTool"

-			/>

-			<Tool

-				Name="VCXMLDataGeneratorTool"

-			/>

-			<Tool

-				Name="VCWebServiceProxyGeneratorTool"

-			/>

-			<Tool

-				Name="VCMIDLTool"

-			/>

-			<Tool

-				Name="VCCLCompilerTool"

-				ExecutionBucket="7"

-				AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"

-				PrecompiledHeaderFile=""

-			/>

-			<Tool

-				Name="VCManagedResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCPreLinkEventTool"

-			/>

-			<Tool

-				Name="VCLinkerTool"

-				AdditionalDependencies="iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib oleaut32.lib uuid.lib ole32.lib user32.lib"

-				OutputFile="..\bin\sample-debug-$(TargetCPU)-wm6std-vc$(VSVer)-$(ConfigurationName).exe"

-			/>

-			<Tool

-				Name="VCALinkTool"

-			/>

-			<Tool

-				Name="VCXDCMakeTool"

-			/>

-			<Tool

-				Name="VCBscMakeTool"

-			/>

-			<Tool

-				Name="VCCodeSignTool"

-			/>

-			<Tool

-				Name="VCPostBuildEventTool"

-			/>

-			<DeploymentTool

-				ForceDirty="-1"

-				RemoteDirectory=""

-				RegisterOutput="0"

-				AdditionalFiles=""

-			/>

-			<DebuggerTool

-			/>

-		</Configuration>

-		<Configuration

-			Name="Debug-Dynamic|Windows Mobile 6 Professional SDK (ARMV4I)"

-			ConfigurationType="1"

-			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-common-defaults.vsprops"

-			UseOfMFC="0"

-			ATLMinimizesCRunTimeLibraryUsage="false"

-			CharacterSet="1"

-			>

-			<Tool

-				Name="VCPreBuildEventTool"

-			/>

-			<Tool

-				Name="VCCustomBuildTool"

-			/>

-			<Tool

-				Name="VCXMLDataGeneratorTool"

-			/>

-			<Tool

-				Name="VCWebServiceProxyGeneratorTool"

-			/>

-			<Tool

-				Name="VCMIDLTool"

-			/>

-			<Tool

-				Name="VCCLCompilerTool"

-				ExecutionBucket="7"

-				AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"

-				PrecompiledHeaderFile=""

-			/>

-			<Tool

-				Name="VCManagedResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCPreLinkEventTool"

-			/>

-			<Tool

-				Name="VCLinkerTool"

-				AdditionalDependencies="iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib oleaut32.lib uuid.lib ole32.lib user32.lib"

-				OutputFile="..\bin\sample-debug-$(TargetCPU)-wm6pro-vc$(VSVer)-$(ConfigurationName).exe"

-			/>

-			<Tool

-				Name="VCALinkTool"

-			/>

-			<Tool

-				Name="VCXDCMakeTool"

-			/>

-			<Tool

-				Name="VCBscMakeTool"

-			/>

-			<Tool

-				Name="VCCodeSignTool"

-			/>

-			<Tool

-				Name="VCPostBuildEventTool"

-			/>

-			<DeploymentTool

-				ForceDirty="-1"

-				RemoteDirectory=""

-				RegisterOutput="0"

-				AdditionalFiles=""

-			/>

-			<DebuggerTool

-			/>

-		</Configuration>

-		<Configuration

 			Name="Debug-Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)"

 			ConfigurationType="1"

 			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm5-common-defaults.vsprops"

@@ -3023,140 +3157,6 @@
 			/>

 		</Configuration>

 		<Configuration

-			Name="Release-Static|Windows Mobile 6 Standard SDK (ARMV4I)"

-			ConfigurationType="1"

-			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-release-defaults.vsprops"

-			UseOfMFC="0"

-			ATLMinimizesCRunTimeLibraryUsage="false"

-			CharacterSet="1"

-			>

-			<Tool

-				Name="VCPreBuildEventTool"

-			/>

-			<Tool

-				Name="VCCustomBuildTool"

-			/>

-			<Tool

-				Name="VCXMLDataGeneratorTool"

-			/>

-			<Tool

-				Name="VCWebServiceProxyGeneratorTool"

-			/>

-			<Tool

-				Name="VCMIDLTool"

-			/>

-			<Tool

-				Name="VCCLCompilerTool"

-				ExecutionBucket="7"

-				AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"

-				PrecompiledHeaderFile=""

-			/>

-			<Tool

-				Name="VCManagedResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCPreLinkEventTool"

-			/>

-			<Tool

-				Name="VCLinkerTool"

-				AdditionalDependencies="iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib oleaut32.lib uuid.lib ole32.lib user32.lib"

-				OutputFile="..\bin\sample-debug-$(TargetCPU)-wm6std-vc$(VSVer)-$(ConfigurationName).exe"

-			/>

-			<Tool

-				Name="VCALinkTool"

-			/>

-			<Tool

-				Name="VCXDCMakeTool"

-			/>

-			<Tool

-				Name="VCBscMakeTool"

-			/>

-			<Tool

-				Name="VCCodeSignTool"

-			/>

-			<Tool

-				Name="VCPostBuildEventTool"

-			/>

-			<DeploymentTool

-				ForceDirty="-1"

-				RemoteDirectory=""

-				RegisterOutput="0"

-				AdditionalFiles=""

-			/>

-			<DebuggerTool

-			/>

-		</Configuration>

-		<Configuration

-			Name="Release-Static|Windows Mobile 6 Professional SDK (ARMV4I)"

-			ConfigurationType="1"

-			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-release-defaults.vsprops"

-			UseOfMFC="0"

-			ATLMinimizesCRunTimeLibraryUsage="false"

-			CharacterSet="1"

-			>

-			<Tool

-				Name="VCPreBuildEventTool"

-			/>

-			<Tool

-				Name="VCCustomBuildTool"

-			/>

-			<Tool

-				Name="VCXMLDataGeneratorTool"

-			/>

-			<Tool

-				Name="VCWebServiceProxyGeneratorTool"

-			/>

-			<Tool

-				Name="VCMIDLTool"

-			/>

-			<Tool

-				Name="VCCLCompilerTool"

-				ExecutionBucket="7"

-				AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"

-				PrecompiledHeaderFile=""

-			/>

-			<Tool

-				Name="VCManagedResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCPreLinkEventTool"

-			/>

-			<Tool

-				Name="VCLinkerTool"

-				AdditionalDependencies="iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib oleaut32.lib uuid.lib ole32.lib user32.lib"

-				OutputFile="..\bin\sample-debug-$(TargetCPU)-wm6pro-vc$(VSVer)-$(ConfigurationName).exe"

-			/>

-			<Tool

-				Name="VCALinkTool"

-			/>

-			<Tool

-				Name="VCXDCMakeTool"

-			/>

-			<Tool

-				Name="VCBscMakeTool"

-			/>

-			<Tool

-				Name="VCCodeSignTool"

-			/>

-			<Tool

-				Name="VCPostBuildEventTool"

-			/>

-			<DeploymentTool

-				ForceDirty="-1"

-				RemoteDirectory=""

-				RegisterOutput="0"

-				AdditionalFiles=""

-			/>

-			<DebuggerTool

-			/>

-		</Configuration>

-		<Configuration

 			Name="Release-Static|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)"

 			ConfigurationType="1"

 			InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm5-release-defaults.vsprops"

@@ -3299,7 +3299,7 @@
 			Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"

 			>

 			<File

-				RelativePath="..\src\samples\debug.c"

+				RelativePath="..\src\samples\debug.cpp"

 				>

 				<FileConfiguration

 					Name="Debug|Win32"

@@ -3338,6 +3338,24 @@
 					/>

 				</FileConfiguration>

 				<FileConfiguration

+					Name="Debug|Windows Mobile 6 Standard SDK (ARMV4I)"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						AdditionalIncludeDirectories=""

+						PreprocessorDefinitions=""

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Debug|Windows Mobile 6 Professional SDK (ARMV4I)"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						AdditionalIncludeDirectories=""

+						PreprocessorDefinitions=""

+					/>

+				</FileConfiguration>

+				<FileConfiguration

 					Name="Release|Win32"

 					>

 					<Tool

@@ -3374,6 +3392,24 @@
 					/>

 				</FileConfiguration>

 				<FileConfiguration

+					Name="Release|Windows Mobile 6 Standard SDK (ARMV4I)"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						AdditionalIncludeDirectories=""

+						PreprocessorDefinitions=""

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Release|Windows Mobile 6 Professional SDK (ARMV4I)"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						AdditionalIncludeDirectories=""

+						PreprocessorDefinitions=""

+					/>

+				</FileConfiguration>

+				<FileConfiguration

 					Name="Debug-Static|Win32"

 					>

 					<Tool

@@ -3410,6 +3446,24 @@
 					/>

 				</FileConfiguration>

 				<FileConfiguration

+					Name="Debug-Static|Windows Mobile 6 Standard SDK (ARMV4I)"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						AdditionalIncludeDirectories=""

+						PreprocessorDefinitions=""

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Debug-Static|Windows Mobile 6 Professional SDK (ARMV4I)"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						AdditionalIncludeDirectories=""

+						PreprocessorDefinitions=""

+					/>

+				</FileConfiguration>

+				<FileConfiguration

 					Name="Release-Dynamic|Win32"

 					>

 					<Tool

@@ -3446,6 +3500,24 @@
 					/>

 				</FileConfiguration>

 				<FileConfiguration

+					Name="Release-Dynamic|Windows Mobile 6 Standard SDK (ARMV4I)"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						AdditionalIncludeDirectories=""

+						PreprocessorDefinitions=""

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Release-Dynamic|Windows Mobile 6 Professional SDK (ARMV4I)"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						AdditionalIncludeDirectories=""

+						PreprocessorDefinitions=""

+					/>

+				</FileConfiguration>

+				<FileConfiguration

 					Name="Debug-Dynamic|Win32"

 					>

 					<Tool

@@ -3482,6 +3554,24 @@
 					/>

 				</FileConfiguration>

 				<FileConfiguration

+					Name="Debug-Dynamic|Windows Mobile 6 Standard SDK (ARMV4I)"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						AdditionalIncludeDirectories=""

+						PreprocessorDefinitions=""

+					/>

+				</FileConfiguration>

+				<FileConfiguration

+					Name="Debug-Dynamic|Windows Mobile 6 Professional SDK (ARMV4I)"

+					>

+					<Tool

+						Name="VCCLCompilerTool"

+						AdditionalIncludeDirectories=""

+						PreprocessorDefinitions=""

+					/>

+				</FileConfiguration>

+				<FileConfiguration

 					Name="Release-Static|Win32"

 					>

 					<Tool

@@ -3518,7 +3608,7 @@
 					/>

 				</FileConfiguration>

 				<FileConfiguration

-					Name="Debug|Windows Mobile 6 Standard SDK (ARMV4I)"

+					Name="Release-Static|Windows Mobile 6 Standard SDK (ARMV4I)"

 					>

 					<Tool

 						Name="VCCLCompilerTool"

@@ -3527,7 +3617,7 @@
 					/>

 				</FileConfiguration>

 				<FileConfiguration

-					Name="Debug|Windows Mobile 6 Professional SDK (ARMV4I)"

+					Name="Release-Static|Windows Mobile 6 Professional SDK (ARMV4I)"

 					>

 					<Tool

 						Name="VCCLCompilerTool"

@@ -3554,24 +3644,6 @@
 					/>

 				</FileConfiguration>

 				<FileConfiguration

-					Name="Release|Windows Mobile 6 Standard SDK (ARMV4I)"

-					>

-					<Tool

-						Name="VCCLCompilerTool"

-						AdditionalIncludeDirectories=""

-						PreprocessorDefinitions=""

-					/>

-				</FileConfiguration>

-				<FileConfiguration

-					Name="Release|Windows Mobile 6 Professional SDK (ARMV4I)"

-					>

-					<Tool

-						Name="VCCLCompilerTool"

-						AdditionalIncludeDirectories=""

-						PreprocessorDefinitions=""

-					/>

-				</FileConfiguration>

-				<FileConfiguration

 					Name="Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)"

 					>

 					<Tool

@@ -3590,24 +3662,6 @@
 					/>

 				</FileConfiguration>

 				<FileConfiguration

-					Name="Debug-Static|Windows Mobile 6 Standard SDK (ARMV4I)"

-					>

-					<Tool

-						Name="VCCLCompilerTool"

-						AdditionalIncludeDirectories=""

-						PreprocessorDefinitions=""

-					/>

-				</FileConfiguration>

-				<FileConfiguration

-					Name="Debug-Static|Windows Mobile 6 Professional SDK (ARMV4I)"

-					>

-					<Tool

-						Name="VCCLCompilerTool"

-						AdditionalIncludeDirectories=""

-						PreprocessorDefinitions=""

-					/>

-				</FileConfiguration>

-				<FileConfiguration

 					Name="Debug-Static|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)"

 					>

 					<Tool

@@ -3626,24 +3680,6 @@
 					/>

 				</FileConfiguration>

 				<FileConfiguration

-					Name="Release-Dynamic|Windows Mobile 6 Standard SDK (ARMV4I)"

-					>

-					<Tool

-						Name="VCCLCompilerTool"

-						AdditionalIncludeDirectories=""

-						PreprocessorDefinitions=""

-					/>

-				</FileConfiguration>

-				<FileConfiguration

-					Name="Release-Dynamic|Windows Mobile 6 Professional SDK (ARMV4I)"

-					>

-					<Tool

-						Name="VCCLCompilerTool"

-						AdditionalIncludeDirectories=""

-						PreprocessorDefinitions=""

-					/>

-				</FileConfiguration>

-				<FileConfiguration

 					Name="Release-Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)"

 					>

 					<Tool

@@ -3662,24 +3698,6 @@
 					/>

 				</FileConfiguration>

 				<FileConfiguration

-					Name="Debug-Dynamic|Windows Mobile 6 Standard SDK (ARMV4I)"

-					>

-					<Tool

-						Name="VCCLCompilerTool"

-						AdditionalIncludeDirectories=""

-						PreprocessorDefinitions=""

-					/>

-				</FileConfiguration>

-				<FileConfiguration

-					Name="Debug-Dynamic|Windows Mobile 6 Professional SDK (ARMV4I)"

-					>

-					<Tool

-						Name="VCCLCompilerTool"

-						AdditionalIncludeDirectories=""

-						PreprocessorDefinitions=""

-					/>

-				</FileConfiguration>

-				<FileConfiguration

 					Name="Debug-Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)"

 					>

 					<Tool

@@ -3698,24 +3716,6 @@
 					/>

 				</FileConfiguration>

 				<FileConfiguration

-					Name="Release-Static|Windows Mobile 6 Standard SDK (ARMV4I)"

-					>

-					<Tool

-						Name="VCCLCompilerTool"

-						AdditionalIncludeDirectories=""

-						PreprocessorDefinitions=""

-					/>

-				</FileConfiguration>

-				<FileConfiguration

-					Name="Release-Static|Windows Mobile 6 Professional SDK (ARMV4I)"

-					>

-					<Tool

-						Name="VCCLCompilerTool"

-						AdditionalIncludeDirectories=""

-						PreprocessorDefinitions=""

-					/>

-				</FileConfiguration>

-				<FileConfiguration

 					Name="Release-Static|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)"

 					>

 					<Tool

diff --git a/jni/pjproject-android/pjsip-apps/src/pjsua/main.c b/jni/pjproject-android/pjsip-apps/src/pjsua/main.c
index 424b08a..5c785f9 100644
--- a/jni/pjproject-android/pjsip-apps/src/pjsua/main.c
+++ b/jni/pjproject-android/pjsip-apps/src/pjsua/main.c
@@ -1,4 +1,4 @@
-/* $Id: main.c 4522 2013-05-23 03:48:31Z riza $ */
+/* $Id: main.c 4704 2014-01-16 05:30:46Z ming $ */
 /* 
  * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
  * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -121,4 +121,5 @@
 	    pj_thread_join(sig_thread);
 	}
     }
+    return 0;
 }
diff --git a/jni/pjproject-android/pjsip-apps/src/pjsua/pjsua_app_cli.c b/jni/pjproject-android/pjsip-apps/src/pjsua/pjsua_app_cli.c
index 6dad7d2..7228ad7 100644
--- a/jni/pjproject-android/pjsip-apps/src/pjsua/pjsua_app_cli.c
+++ b/jni/pjproject-android/pjsip-apps/src/pjsua/pjsua_app_cli.c
@@ -1,4 +1,4 @@
-/* $Id: pjsua_app_cli.c 4634 2013-10-23 09:29:35Z riza $ */
+/* $Id: pjsua_app_cli.c 4709 2014-01-22 08:02:56Z bennylp $ */
 /* 
  * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
  * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -85,6 +85,7 @@
 #define CMD_MEDIA_CONF_DISCONNECT   ((CMD_MEDIA*10)+3)
 #define CMD_MEDIA_ADJUST_VOL	    ((CMD_MEDIA*10)+4)
 #define CMD_MEDIA_CODEC_PRIO	    ((CMD_MEDIA*10)+5)
+#define CMD_MEDIA_SPEAKER_TOGGLE    ((CMD_MEDIA*10)+6)
 
 /* status & config level 2 command */
 #define CMD_CONFIG_DUMP_STAT	    ((CMD_CONFIG*10)+1)
@@ -1342,6 +1343,31 @@
     case CMD_MEDIA_CODEC_PRIO:
 	status = cmd_set_codec_prio(cval);	
 	break;
+    case CMD_MEDIA_SPEAKER_TOGGLE:
+	{
+	    static int route = PJMEDIA_AUD_DEV_ROUTE_DEFAULT;
+	    status = pjsua_snd_get_setting(PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE,
+					   &route);
+	    if (status != PJ_SUCCESS) {
+		PJ_PERROR(2, (THIS_FILE, status,
+			      "Warning: unable to retrieve route setting"));
+	    }
+
+	    if (route == PJMEDIA_AUD_DEV_ROUTE_LOUDSPEAKER)
+		route = PJMEDIA_AUD_DEV_ROUTE_DEFAULT;
+	    else
+		route = PJMEDIA_AUD_DEV_ROUTE_LOUDSPEAKER;
+
+	    PJ_LOG(4,(THIS_FILE, "Setting output route to %s %s",
+		      (route==PJMEDIA_AUD_DEV_ROUTE_DEFAULT?
+				      "default" : "loudspeaker"),
+		      (status? "anyway" : "")));
+
+	    status = pjsua_snd_set_setting(PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE,
+					   &route, PJ_TRUE);
+	    PJ_PERROR(4,(THIS_FILE, status, "Result"));
+	}
+	break;
     }    
 
     return status;
@@ -2830,6 +2856,7 @@
 	"    <ARG name='mic_level' type='int' desc='Mic Level'/>"
 	"    <ARG name='speaker_port' type='int' desc='Speaker Level'/>"
 	"  </CMD>"
+	"  <CMD name='speakertog' id='4006' desc='Toggle audio output route' />"
 	"  <CMD name='codec_prio' id='4005' sc='Cp' "
 	"   desc='Arrange codec priorities'>"
 	"    <ARG name='codec_id' type='choice' id='9904' desc='Codec Id'/>"
diff --git a/jni/pjproject-android/pjsip-apps/src/pjsua/pjsua_app_legacy.c b/jni/pjproject-android/pjsip-apps/src/pjsua/pjsua_app_legacy.c
index 54a9dc7..a77e1bf 100644
--- a/jni/pjproject-android/pjsip-apps/src/pjsua/pjsua_app_legacy.c
+++ b/jni/pjproject-android/pjsip-apps/src/pjsua/pjsua_app_legacy.c
@@ -1,4 +1,4 @@
-/* $Id: pjsua_app_legacy.c 4580 2013-08-06 08:02:24Z bennylp $ */
+/* $Id: pjsua_app_legacy.c 4710 2014-01-22 10:51:49Z bennylp $ */
 /* 
  * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
  * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -1137,7 +1137,7 @@
 	    pjsua_call_info call_info;
 
 	    if (ids[i] == call)
-		return;
+		continue;
 
 	    pjsua_call_get_info(ids[i], &call_info);
 	    printf("%d  %.*s [%.*s]\n",
diff --git a/jni/pjproject-android/pjsip-apps/src/pygui/account.py b/jni/pjproject-android/pjsip-apps/src/pygui/account.py
new file mode 100644
index 0000000..1bc91b4
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/pygui/account.py
@@ -0,0 +1,239 @@
+# $Id: account.py 4704 2014-01-16 05:30:46Z ming $
+#
+# pjsua Python GUI Demo
+#
+# Copyright (C)2013 Teluu Inc. (http://www.teluu.com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+#
+import sys
+if sys.version_info[0] >= 3: # Python 3
+	import tkinter as tk
+	from tkinter import ttk
+	from tkinter import messagebox as msgbox
+else:
+	import Tkinter as tk
+	import tkMessageBox as msgbox
+	import ttk
+
+import random
+import pjsua2 as pj
+import _pjsua2
+import accountsetting
+import application
+import call
+import chat as ch
+
+# Account class
+class Account(pj.Account):
+	"""
+	High level Python Account object, derived from pjsua2's Account object.
+	"""
+	def __init__(self, app):
+		pj.Account.__init__(self)
+		self.app = app
+		self.randId = random.randint(1, 9999)
+		self.cfg =  pj.AccountConfig()
+		self.cfgChanged = False
+		self.buddyList = []
+		self.chatList = []
+		self.deleting = False
+
+	def findChat(self, uri_str):
+		uri = ch.ParseSipUri(uri_str)
+		if not uri: return None
+			
+		for chat in self.chatList:
+			if chat.isUriParticipant(uri) and chat.isPrivate():
+				return chat
+		return None
+	
+	def newChat(self, uri_str):
+		uri = ch.ParseSipUri(uri_str)
+		if not uri: return None
+			
+		chat = ch.Chat(self.app, self, uri)
+		self.chatList.append(chat)
+		self.app.updateWindowMenu()
+		return chat
+	
+	def statusText(self):
+		status = '?'
+		if self.isValid():
+			ai = self.getInfo()
+			if ai.regLastErr:
+				status = self.app.ep.utilStrError(ai.regLastErr)
+			elif ai.regIsActive:
+				if ai.onlineStatus:
+					if len(ai.onlineStatusText):
+						status = ai.onlineStatusText
+					else:
+						status = "Online"
+				else:
+					status = "Registered"
+			else:
+				if ai.regIsConfigured:
+					if ai.regStatus/100 == 2:
+						status = "Unregistered"
+					else:
+						status = ai.regStatusText
+				else:
+					status = "Doesn't register"
+		else:
+			status = '- not created -'
+		return status
+        	
+	def onRegState(self, prm):
+		self.app.updateAccount(self)
+
+        def onIncomingCall(self, prm):
+		c = call.Call(self, call_id=prm.callId)
+                call_prm = pj.CallOpParam()
+		call_prm.statusCode = 180
+		c.answer(call_prm)
+		ci = c.getInfo()
+		msg = "Incoming call for account '%s'" % self.cfg.idUri
+		if msgbox.askquestion(msg, "Accept call from '%s'?" % (ci.remoteUri), default=msgbox.YES) == u'yes':
+			call_prm.statusCode = 200
+			c.answer(call_prm)
+			
+			# find/create chat instance
+			chat = self.findChat(ci.remoteUri)
+			if not chat: chat = self.newChat(ci.remoteUri)
+			
+			chat.showWindow()
+			chat.registerCall(ci.remoteUri, c)
+			chat.updateCallState(c, ci)
+		else:
+			c.hangup(call_prm)
+			
+	def onInstantMessage(self, prm):
+		chat = self.findChat(prm.fromUri)
+		if not chat: chat = self.newChat(prm.fromUri)
+		
+		chat.showWindow()
+		chat.addMessage(prm.fromUri, prm.msgBody)
+		
+	def onInstantMessageStatus(self, prm):
+		if prm.code/100 == 2: return
+		
+		chat = self.findChat(prm.toUri)
+		if not chat:
+			print "=== IM status to '%s' cannot find chat" % prm.toUri
+			return
+		
+		chat.addMessage(None, "Failed sending message to '%s': %s" % (prm.toUri, prm.reason))
+		
+	def onTypingIndication(self, prm):
+		chat = self.findChat(prm.fromUri)
+		if not chat:
+			print "=== Incoming typing indication from '%s' cannot find chat" % prm.fromUri
+			return
+		
+		chat.setTypingIndication(prm.fromUri, prm.isTyping)
+
+		
+# Account frame, to list accounts
+class AccountListFrame(ttk.Frame):
+	"""
+	This implements a Frame which contains account list and buttons to operate
+	on them (Add, Modify, Delete, etc.). 
+	"""
+	def __init__(self, parent, app, acc_list = []):
+		ttk.Frame.__init__(self, parent, name='acclist')
+		self.app = app
+		self.accList = acc_list
+		self.accDeletedList = []
+		self.pack(expand='yes', fill='both')
+		self._createWidgets()
+		for acc in self.accList:
+			self._showAcc(acc)
+		
+	def _createWidgets(self):
+		self.tv = ttk.Treeview(self, columns=('ID', 'Registrar', 'Default'), selectmode='browse')
+		self.tv.heading('#0', text='Priority')
+		self.tv.heading(0, text='ID')
+		self.tv.heading(1, text='Registrar')
+		self.tv.heading(2, text='Default?')
+		self.tv.column('#0', width=60)
+		self.tv.column(0, width=300)
+		self.tv.column(1, width=200)
+		self.tv.column(2, width=60)
+		self.tv.grid(column=0, row=0, rowspan=4, padx=5, pady=5)
+		
+		ttk.Button(self, text='Add..', command=self._onBtnAdd).grid(column=1, row=0, padx=5)
+		ttk.Button(self, text='Settings..', command=self._onBtnSettings).grid(column=1, row=1)
+		ttk.Button(self, text='Set Default', command=self._onBtnSetDefault).grid(column=1, row=2)
+		ttk.Button(self, text='Delete..', command=self._onBtnDelete).grid(column=1, row=3)
+
+	def _showAcc(self, acc):
+		is_default = 'Yes' if acc.isValid() and acc.isDefault() else ''
+		values = (acc.cfg.idUri, acc.cfg.regConfig.registrarUri, is_default)
+		self.tv.insert('', 0, str(acc.randId), open=True, text=str(acc.cfg.priority), values=values)
+	
+	def updateAccount(self, acc):
+		is_default = 'Yes' if acc.isValid() and acc.isDefault() else ''
+		values = (acc.cfg.idUri, acc.cfg.regConfig.registrarUri, is_default)
+		self.tv.item(str(acc.randId), text=str(acc.cfg.priority), values=values)
+	
+	def _getSelectedAcc(self):
+		items = self.tv.selection()
+		if not items:
+			return None
+		iid = int(items[0])
+		return [acc for acc in self.accList if acc.randId==iid][0]
+	
+	def _onBtnAdd(self):
+		cfg = pj.AccountConfig()
+		dlg = accountsetting.Dialog(self.master, cfg)
+		if dlg.doModal():
+			acc = Account(self.app)
+			acc.cfg = cfg
+			self._showAcc(acc)
+			self.accList.append(acc)
+			self.cfgChanged = True
+	
+	def _onBtnSettings(self):
+		acc = self._getSelectedAcc()
+		if not acc:
+			return
+		dlg = accountsetting.Dialog(self.master, acc.cfg)
+		if dlg.doModal():
+			self.updateAccount(acc)
+			self.cfgChanged = True
+
+	def _onBtnDelete(self):
+		acc = self._getSelectedAcc()
+		if not acc:
+			return
+		msg = "Do you really want to delete account '%s'" % acc.cfg.idUri
+		if msgbox.askquestion('Delete account?', msg, default=msgbox.NO) != u'yes':
+			return
+		self.accList.remove(acc)
+		self.accDeletedList.append(acc)
+		self.tv.delete( (str(acc.randId),) )
+
+	def _onBtnSetDefault(self):
+		acc = self._getSelectedAcc()
+		if not acc:
+			return
+		if acc.isValid():
+			acc.setDefault()
+		for acc in self.accList:
+			self.updateAccount(acc)
+		
+		
+if __name__ == '__main__':
+	application.main()
diff --git a/jni/pjproject-android/pjsip-apps/src/pygui/accountsetting.py b/jni/pjproject-android/pjsip-apps/src/pygui/accountsetting.py
new file mode 100644
index 0000000..92cf2c4
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/pygui/accountsetting.py
@@ -0,0 +1,369 @@
+# $Id: accountsetting.py 4704 2014-01-16 05:30:46Z ming $
+#
+# pjsua Python GUI Demo
+#
+# Copyright (C)2013 Teluu Inc. (http://www.teluu.com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+#
+import sys
+if sys.version_info[0] >= 3: # Python 3
+	import tkinter as tk
+	from tkinter import ttk
+	from tkinter import messagebox as msgbox
+else:
+	import Tkinter as tk
+	import tkMessageBox as msgbox
+	import ttk
+
+import pjsua2 as pj
+import endpoint
+import application
+
+class Dialog(tk.Toplevel):
+	"""
+	This implements account settings dialog to manipulate account settings.
+	"""
+	def __init__(self, parent, cfg):
+		tk.Toplevel.__init__(self, parent)
+		self.transient(parent)
+		self.parent = parent
+		self.geometry("+100+100")
+		self.title('Account settings')
+		
+		self.frm = ttk.Frame(self)
+		self.frm.pack(expand='yes', fill='both')
+		
+		self.isOk = False
+		self.cfg = cfg
+		
+		self.createWidgets()
+	
+	def doModal(self):
+		if self.parent:
+			self.parent.wait_window(self)
+		else:
+			self.wait_window(self)
+		return self.isOk
+		
+	def createWidgets(self):
+		# The notebook
+		self.frm.rowconfigure(0, weight=1)
+		self.frm.rowconfigure(1, weight=0)
+		self.frm.columnconfigure(0, weight=1)
+		self.frm.columnconfigure(1, weight=1)
+		self.wTab = ttk.Notebook(self.frm)
+		self.wTab.grid(column=0, row=0, columnspan=2, padx=10, pady=10, ipadx=20, ipady=20, sticky=tk.N+tk.S+tk.W+tk.E)
+		
+		# Main buttons
+		btnOk = ttk.Button(self.frm, text='Ok', command=self.onOk)
+		btnOk.grid(column=0, row=1, sticky=tk.E, padx=20, pady=10)
+		btnCancel = ttk.Button(self.frm, text='Cancel', command=self.onCancel)
+		btnCancel.grid(column=1, row=1, sticky=tk.W, padx=20, pady=10)
+		
+		# Tabs
+		self.createBasicTab()
+		self.createSipTab()
+		self.createMediaTab()
+		self.createMediaNatTab()
+		
+	def createBasicTab(self):
+		# Prepare the variables to set/receive values from GUI
+		self.cfgPriority = tk.IntVar(value=self.cfg.priority)
+		self.cfgAccId = tk.StringVar(value=self.cfg.idUri)
+		self.cfgRegistrar = tk.StringVar(value=self.cfg.regConfig.registrarUri)
+		self.cfgRegisterOnAdd = tk.IntVar(value=self.cfg.regConfig.registerOnAdd)
+		self.cfgUsername = tk.StringVar()
+		self.cfgPassword = tk.StringVar()
+		if len(self.cfg.sipConfig.authCreds):
+			self.cfgUsername.set( self.cfg.sipConfig.authCreds[0].username )
+			self.cfgPassword.set( self.cfg.sipConfig.authCreds[0].data )
+		self.cfgProxy = tk.StringVar()
+		if len(self.cfg.sipConfig.proxies):
+			self.cfgProxy.set( self.cfg.sipConfig.proxies[0] )
+		
+		# Build the tab page
+		frm = ttk.Frame(self.frm)
+		frm.columnconfigure(0, weight=1)
+		frm.columnconfigure(1, weight=2)
+		row = 0
+		ttk.Label(frm, text='Priority:').grid(row=row, column=0, sticky=tk.E, pady=2)
+		tk.Spinbox(frm, from_=0, to=9, textvariable=self.cfgPriority, width=2).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Label(frm, text='ID (URI):').grid(row=row, column=0, sticky=tk.E, pady=2)
+		ttk.Entry(frm, textvariable=self.cfgAccId, width=32).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Label(frm, text='Registrar URI:').grid(row=row, column=0, sticky=tk.E, pady=2)
+		ttk.Entry(frm, textvariable=self.cfgRegistrar, width=32).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Checkbutton(frm, text='Register on add', variable=self.cfgRegisterOnAdd).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+		row += 1
+		ttk.Label(frm, text='Optional proxy URI:').grid(row=row, column=0, sticky=tk.E, pady=2)
+		ttk.Entry(frm, textvariable=self.cfgProxy, width=32).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Label(frm, text='Auth username:').grid(row=row, column=0, sticky=tk.E, pady=2)
+		ttk.Entry(frm, textvariable=self.cfgUsername, width=16).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Label(frm, text='Password:').grid(row=row, column=0, sticky=tk.E, pady=2)
+		ttk.Entry(frm, textvariable=self.cfgPassword, show='*', width=16).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+
+		self.wTab.add(frm, text='Basic Settings')
+		
+
+	def createSipTab(self):
+		# Prepare the variables to set/receive values from GUI
+		self.cfgPrackUse 	= tk.IntVar(value=self.cfg.callConfig.prackUse)
+		self.cfgTimerUse 	= tk.IntVar(value=self.cfg.callConfig.timerUse)
+		self.cfgTimerExpires 	= tk.IntVar(value=self.cfg.callConfig.timerSessExpiresSec)
+		self.cfgPublish 	= tk.BooleanVar(value=self.cfg.presConfig.publishEnabled)
+		self.cfgMwiEnabled 	= tk.BooleanVar(value=self.cfg.mwiConfig.enabled)
+		self.cfgEnableContactRewrite = tk.BooleanVar(value=self.cfg.natConfig.contactRewriteUse != 0) 
+		self.cfgEnableViaRewrite = tk.BooleanVar(value=self.cfg.natConfig.viaRewriteUse != 0) 
+		self.cfgEnableSdpRewrite = tk.BooleanVar(value=self.cfg.natConfig.sdpNatRewriteUse != 0)
+		self.cfgEnableSipOutbound = tk.BooleanVar(value=self.cfg.natConfig.sipOutboundUse != 0)
+		self.cfgKaInterval 	= tk.IntVar(value=self.cfg.natConfig.udpKaIntervalSec)
+		
+		# Build the tab page
+		frm = ttk.Frame(self.frm)
+		frm.columnconfigure(0, weight=1)
+		frm.columnconfigure(1, weight=2)
+		row = 0
+		ttk.Label(frm, text='100rel/PRACK:').grid(row=row, column=0, sticky=tk.E, pady=2)
+		ttk.Radiobutton(frm, text='Only offer PRACK', value=pj.PJSUA_100REL_NOT_USED, variable=self.cfgPrackUse).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Radiobutton(frm, text='Offer and use if remote supports', value=pj.PJSUA_100REL_OPTIONAL, variable=self.cfgPrackUse).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Radiobutton(frm, text='Required', value=pj.PJSUA_100REL_MANDATORY, variable=self.cfgPrackUse).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Label(frm, text='Session Timer:').grid(row=row, column=0, sticky=tk.E, pady=2)
+		ttk.Radiobutton(frm, text='Not offered', value=pj.PJSUA_SIP_TIMER_INACTIVE, variable=self.cfgTimerUse).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Radiobutton(frm, text='Optional', value=pj.PJSUA_SIP_TIMER_OPTIONAL, variable=self.cfgTimerUse).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Radiobutton(frm, text='Required', value=pj.PJSUA_SIP_TIMER_REQUIRED, variable=self.cfgTimerUse).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Radiobutton(frm, text="Always use", value=pj.PJSUA_SIP_TIMER_ALWAYS, variable=self.cfgTimerUse).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Label(frm, text='Session Timer Expiration:').grid(row=row, column=0, sticky=tk.E, pady=2)
+		tk.Spinbox(frm, from_=90, to=7200, textvariable=self.cfgTimerExpires, width=5).grid(row=row, column=1, sticky=tk.W, padx=6)
+		ttk.Label(frm, text='(seconds)').grid(row=row, column=1, sticky=tk.E)
+		row += 1
+		ttk.Label(frm, text='Presence:').grid(row=row, column=0, sticky=tk.E, pady=2)
+		ttk.Checkbutton(frm, text='Enable PUBLISH', variable=self.cfgPublish).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+		row += 1
+		ttk.Label(frm, text='Message Waiting Indication:').grid(row=row, column=0, sticky=tk.E, pady=2)
+		ttk.Checkbutton(frm, text='Enable MWI', variable=self.cfgMwiEnabled).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+		row += 1
+		ttk.Label(frm, text='NAT Traversal:').grid(row=row, column=0, sticky=tk.E, pady=2)
+		ttk.Checkbutton(frm, text='Enable Contact Rewrite', variable=self.cfgEnableContactRewrite).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+		row += 1
+		ttk.Checkbutton(frm, text='Enable Via Rewrite', variable=self.cfgEnableViaRewrite).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+		row += 1
+		ttk.Checkbutton(frm, text='Enable SDP IP Address Rewrite', variable=self.cfgEnableSdpRewrite).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+		row += 1
+		ttk.Checkbutton(frm, text='Enable SIP Outbound Extension', variable=self.cfgEnableSipOutbound).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+		row += 1
+		ttk.Label(frm, text='UDP Keep-Alive Interval:').grid(row=row, column=0, sticky=tk.E, pady=2)
+		tk.Spinbox(frm, from_=0, to=3600, textvariable=self.cfgKaInterval, width=5).grid(row=row, column=1, sticky=tk.W, padx=6)
+		ttk.Label(frm, text='(seconds) Zero to disable.').grid(row=row, column=1, sticky=tk.E)
+
+
+		self.wTab.add(frm, text='SIP Features')
+
+	def createMediaTab(self):
+		# Prepare the variables to set/receive values from GUI
+		self.cfgMedPort = tk.IntVar(value=self.cfg.mediaConfig.transportConfig.port)
+		self.cfgMedPortRange = tk.IntVar(value=self.cfg.mediaConfig.transportConfig.portRange)
+		self.cfgMedLockCodec = tk.BooleanVar(value=self.cfg.mediaConfig.lockCodecEnabled)
+		self.cfgMedSrtp = tk.IntVar(value=self.cfg.mediaConfig.srtpUse)
+		self.cfgMedSrtpSecure = tk.IntVar(value=self.cfg.mediaConfig.srtpSecureSignaling)
+		self.cfgMedIpv6 = tk.BooleanVar(value=self.cfg.mediaConfig.ipv6Use==pj.PJSUA_IPV6_ENABLED)
+		
+		# Build the tab page
+		frm = ttk.Frame(self.frm)
+		frm.columnconfigure(0, weight=1)
+		frm.columnconfigure(1, weight=21)
+		row = 0
+		ttk.Label(frm, text='Secure RTP (SRTP):').grid(row=row, column=0, sticky=tk.E, pady=2)
+		ttk.Radiobutton(frm, text='Disable', value=pj.PJMEDIA_SRTP_DISABLED, variable=self.cfgMedSrtp).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Radiobutton(frm, text='Mandatory', value=pj.PJMEDIA_SRTP_MANDATORY, variable=self.cfgMedSrtp).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Radiobutton(frm, text='Optional (non-standard)', value=pj.PJMEDIA_SRTP_OPTIONAL, variable=self.cfgMedSrtp).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Label(frm, text='SRTP signaling:').grid(row=row, column=0, sticky=tk.E, pady=2)
+		ttk.Radiobutton(frm, text='Does not require secure signaling', value=0, variable=self.cfgMedSrtpSecure).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Radiobutton(frm, text='Require secure next hop (TLS)', value=1, variable=self.cfgMedSrtpSecure).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Radiobutton(frm, text='Require secure end-to-end (SIPS)', value=2, variable=self.cfgMedSrtpSecure).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Label(frm, text='RTP transport start port:').grid(row=row, column=0, sticky=tk.E, pady=2)
+		tk.Spinbox(frm, from_=0, to=65535, textvariable=self.cfgMedPort, width=5).grid(row=row, column=1, sticky=tk.W, padx=6)
+		ttk.Label(frm, text='(0: any)').grid(row=row, column=1, sticky=tk.E, pady=2)
+		row += 1
+		ttk.Label(frm, text='Port range:').grid(row=row, column=0, sticky=tk.E, pady=2)
+		tk.Spinbox(frm, from_=0, to=65535, textvariable=self.cfgMedPortRange, width=5).grid(row=row, column=1, sticky=tk.W, padx=6)
+		ttk.Label(frm, text='(0: not limited)').grid(row=row, column=1, sticky=tk.E, pady=2)
+		row += 1
+		ttk.Label(frm, text='Lock codec:').grid(row=row, column=0, sticky=tk.E, pady=2)
+		ttk.Checkbutton(frm, text='Enable', variable=self.cfgMedLockCodec).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+		row += 1
+		ttk.Label(frm, text='Use IPv6:').grid(row=row, column=0, sticky=tk.E, pady=2)
+		ttk.Checkbutton(frm, text='Yes', variable=self.cfgMedIpv6).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+
+		self.wTab.add(frm, text='Media settings')
+
+	def createMediaNatTab(self):
+		# Prepare the variables to set/receive values from GUI
+		self.cfgSipUseStun = tk.IntVar(value = self.cfg.natConfig.sipStunUse)
+		self.cfgMediaUseStun = tk.IntVar(value = self.cfg.natConfig.mediaStunUse)
+		self.cfgIceEnabled = tk.BooleanVar(value = self.cfg.natConfig.iceEnabled)
+		self.cfgIceAggressive = tk.BooleanVar(value = self.cfg.natConfig.iceAggressiveNomination)
+		self.cfgAlwaysUpdate = tk.BooleanVar(value = True if self.cfg.natConfig.iceAlwaysUpdate else False)
+		self.cfgIceNoHostCands = tk.BooleanVar(value = True if self.cfg.natConfig.iceMaxHostCands == 0 else False)
+		self.cfgTurnEnabled = tk.BooleanVar(value = self.cfg.natConfig.turnEnabled)
+		self.cfgTurnServer = tk.StringVar(value = self.cfg.natConfig.turnServer)
+		self.cfgTurnConnType = tk.IntVar(value = self.cfg.natConfig.turnConnType)
+		self.cfgTurnUser = tk.StringVar(value = self.cfg.natConfig.turnUserName)
+		self.cfgTurnPasswd = tk.StringVar(value = self.cfg.natConfig.turnPassword)
+		
+		# Build the tab page
+		frm = ttk.Frame(self.frm)
+		frm.columnconfigure(0, weight=1)
+		frm.columnconfigure(1, weight=2)
+		row = 0
+		ttk.Label(frm, text='SIP STUN Usage:').grid(row=row, column=0, sticky=tk.E, pady=2)
+		ttk.Radiobutton(frm, text='Default', value=pj.PJSUA_STUN_USE_DEFAULT, variable=self.cfgSipUseStun).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Radiobutton(frm, text='Disable', value=pj.PJSUA_STUN_USE_DISABLED, variable=self.cfgSipUseStun).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Label(frm, text='Media STUN Usage:').grid(row=row, column=0, sticky=tk.E, pady=2)
+		ttk.Radiobutton(frm, text='Default', value=pj.PJSUA_STUN_USE_DEFAULT, variable=self.cfgMediaUseStun).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Radiobutton(frm, text='Disable', value=pj.PJSUA_STUN_USE_DISABLED, variable=self.cfgMediaUseStun).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Label(frm, text='ICE:').grid(row=row, column=0, sticky=tk.E, pady=2)
+		ttk.Checkbutton(frm, text='Enable', variable=self.cfgIceEnabled).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+		row += 1
+		ttk.Checkbutton(frm, text='Use aggresive nomination', variable=self.cfgIceAggressive).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+		row += 1
+		ttk.Checkbutton(frm, text='Always re-INVITE after negotiation', variable=self.cfgAlwaysUpdate).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+		row += 1
+		ttk.Checkbutton(frm, text='Disable host candidates', variable=self.cfgIceNoHostCands).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+		row += 1
+		ttk.Label(frm, text='TURN:').grid(row=row, column=0, sticky=tk.E, pady=2)
+		ttk.Checkbutton(frm, text='Enable', variable=self.cfgTurnEnabled).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+		row += 1
+		ttk.Label(frm, text='TURN server:').grid(row=row, column=0, sticky=tk.E, pady=2)
+		ttk.Entry(frm, textvariable=self.cfgTurnServer, width=20).grid(row=row, column=1, sticky=tk.W, padx=6)
+		ttk.Label(frm, text='host[:port]').grid(row=row, column=1, sticky=tk.E, pady=6)
+		row += 1
+		ttk.Label(frm, text='TURN connection:').grid(row=row, column=0, sticky=tk.E, pady=2)
+		ttk.Radiobutton(frm, text='UDP', value=pj.PJ_TURN_TP_UDP, variable=self.cfgTurnConnType).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Radiobutton(frm, text='TCP', value=pj.PJ_TURN_TP_TCP, variable=self.cfgTurnConnType).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Label(frm, text='TURN username:').grid(row=row, column=0, sticky=tk.E, pady=2)
+		ttk.Entry(frm, textvariable=self.cfgTurnUser, width=16).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Label(frm, text='TURN password:').grid(row=row, column=0, sticky=tk.E, pady=2)
+		ttk.Entry(frm, textvariable=self.cfgTurnPasswd, show='*', width=16).grid(row=row, column=1, sticky=tk.W, padx=6)
+
+		self.wTab.add(frm, text='NAT settings')
+		
+	def onOk(self):
+		# Check basic settings
+		errors = "";
+		if not self.cfgAccId.get():
+			errors += "Account ID is required\n"
+		if self.cfgAccId.get():
+			if not endpoint.validateSipUri(self.cfgAccId.get()):
+				errors += "Invalid SIP ID URI: '%s'\n" % (self.cfgAccId.get())
+		if self.cfgRegistrar.get():
+			if not endpoint.validateSipUri(self.cfgRegistrar.get()):
+				errors += "Invalid SIP registrar URI: '%s'\n" % (self.cfgRegistrar.get())
+		if self.cfgProxy.get():
+			if not endpoint.validateSipUri(self.cfgProxy.get()):
+				errors += "Invalid SIP proxy URI: '%s'\n" % (self.cfgProxy.get())
+		if self.cfgTurnEnabled.get():
+			if not self.cfgTurnServer.get():
+				errors += "TURN server is required\n"
+		if errors:
+			msgbox.showerror("Error detected:", errors)
+			return
+		
+		# Basic settings
+		self.cfg.priority = self.cfgPriority.get()
+		self.cfg.idUri = self.cfgAccId.get()
+		self.cfg.regConfig.registrarUri = self.cfgRegistrar.get()
+		self.cfg.regConfig.registerOnAdd = self.cfgRegisterOnAdd.get()
+		while len(self.cfg.sipConfig.authCreds):
+			self.cfg.sipConfig.authCreds.pop()
+		if self.cfgUsername.get():
+			cred = pj.AuthCredInfo()
+			cred.scheme = "digest"
+			cred.realm = "*"
+			cred.username = self.cfgUsername.get()
+			cred.data = self.cfgPassword.get()
+			self.cfg.sipConfig.authCreds.append(cred)
+		while len(self.cfg.sipConfig.proxies):
+			self.cfg.sipConfig.proxies.pop()
+		if self.cfgProxy.get():
+			self.cfg.sipConfig.proxies.append(self.cfgProxy.get())
+
+		# SIP features
+		self.cfg.callConfig.prackUse		= self.cfgPrackUse.get() 
+		self.cfg.callConfig.timerUse		= self.cfgTimerUse.get()
+		self.cfg.callConfig.timerSessExpiresSec	= self.cfgTimerExpires.get() 
+		self.cfg.presConfig.publishEnabled	= self.cfgPublish.get() 
+		self.cfg.mwiConfig.enabled		= self.cfgMwiEnabled.get() 
+		self.cfg.natConfig.contactRewriteUse	= 1 if self.cfgEnableContactRewrite.get() else 0
+		self.cfg.natConfig.viaRewriteUse 	= 1 if self.cfgEnableViaRewrite.get() else 0
+		self.cfg.natConfig.sdpNatRewriteUse	= 1 if self.cfgEnableSdpRewrite.get() else 0
+		self.cfg.natConfig.sipOutboundUse	= 1 if self.cfgEnableSipOutbound.get() else 0
+		self.cfg.natConfig.udpKaIntervalSec	= self.cfgKaInterval.get()
+
+		# Media
+		self.cfg.mediaConfig.transportConfig.port	= self.cfgMedPort.get()
+		self.cfg.mediaConfig.transportConfig.portRange	= self.cfgMedPortRange.get()
+		self.cfg.mediaConfig.lockCodecEnabled		= self.cfgMedLockCodec.get()
+		self.cfg.mediaConfig.srtpUse			= self.cfgMedSrtp.get()
+		self.cfg.mediaConfig.srtpSecureSignaling	= self.cfgMedSrtpSecure.get()
+		self.cfg.mediaConfig.ipv6Use			= pj.PJSUA_IPV6_ENABLED if self.cfgMedIpv6.get() else pj.PJSUA_IPV6_DISABLED
+		
+		# NAT
+		self.cfg.natConfig.sipStunUse		= self.cfgSipUseStun.get()
+		self.cfg.natConfig.mediaStunUse		= self.cfgMediaUseStun.get()
+		self.cfg.natConfig.iceEnabled		= self.cfgIceEnabled.get()
+		self.cfg.natConfig.iceAggressiveNomination = self.cfgIceAggressive .get()
+		self.cfg.natConfig.iceAlwaysUpdate	= self.cfgAlwaysUpdate.get()
+		self.cfg.natConfig.iceMaxHostCands	= 0 if self.cfgIceNoHostCands.get() else -1 
+		self.cfg.natConfig.turnEnabled		= self.cfgTurnEnabled.get()
+		self.cfg.natConfig.turnServer		= self.cfgTurnServer.get()
+		self.cfg.natConfig.turnConnType		= self.cfgTurnConnType.get()
+		self.cfg.natConfig.turnUserName		= self.cfgTurnUser.get()
+		self.cfg.natConfig.turnPasswordType	= 0
+		self.cfg.natConfig.turnPassword		= self.cfgTurnPasswd.get()
+		
+		self.isOk = True
+		self.destroy()
+		
+	def onCancel(self):
+		self.destroy()
+
+
+if __name__ == '__main__':
+	application.main()
diff --git a/jni/pjproject-android/pjsip-apps/src/pygui/application.py b/jni/pjproject-android/pjsip-apps/src/pygui/application.py
new file mode 100644
index 0000000..8be50ed
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/pygui/application.py
@@ -0,0 +1,510 @@
+# $Id: application.py 4704 2014-01-16 05:30:46Z ming $
+#
+# pjsua Python GUI Demo
+#
+# Copyright (C)2013 Teluu Inc. (http://www.teluu.com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+#
+import sys
+if sys.version_info[0] >= 3: # Python 3
+	import tkinter as tk
+	from tkinter import ttk
+	from tkinter import messagebox as msgbox
+else:
+	import Tkinter as tk
+	import tkMessageBox as msgbox
+	import ttk
+
+import pjsua2 as pj
+import log
+import accountsetting
+import account
+import buddy
+import endpoint
+import settings
+
+import os
+import traceback
+
+	
+class Application(ttk.Frame):
+	"""
+	The Application main frame.
+	"""
+	def __init__(self):
+		ttk.Frame.__init__(self, name='application', width=300, height=500)
+		self.pack(expand='yes', fill='both')
+		self.master.title('pjsua2 Demo')
+		self.master.geometry('500x500+100+100')
+		
+		# Logger
+		self.logger = log.Logger()
+		
+		# Accounts
+		self.accList = []
+		
+		# GUI variables
+		self.showLogWindow = tk.IntVar(value=0)
+		self.quitting = False 
+		
+		# Construct GUI
+		self._createWidgets()
+		
+		# Log window
+		self.logWindow = log.LogWindow(self)
+		self._onMenuShowHideLogWindow()
+		
+		# Instantiate endpoint
+		self.ep = endpoint.Endpoint()
+		self.ep.libCreate()
+		
+		# Default config
+		self.appConfig = settings.AppConfig()
+		self.appConfig.epConfig.uaConfig.threadCnt = 0;
+		self.appConfig.epConfig.uaConfig.mainThreadOnly = True
+		self.appConfig.epConfig.logConfig.writer = self.logger
+		self.appConfig.epConfig.logConfig.filename = "pygui.log"
+		self.appConfig.epConfig.logConfig.fileFlags = pj.PJ_O_APPEND
+		self.appConfig.epConfig.logConfig.level = 5
+		self.appConfig.epConfig.logConfig.consoleLevel = 5
+		
+	def saveConfig(self, filename='pygui.js'):
+		# Save disabled accounts since they are not listed in self.accList
+		disabled_accs = [ac for ac in self.appConfig.accounts if not ac.enabled]
+		self.appConfig.accounts = []
+		
+		# Get account configs from active accounts
+		for acc in self.accList:
+			acfg = settings.AccConfig()
+			acfg.enabled = True
+			acfg.config = acc.cfg
+			for bud in acc.buddyList:
+				acfg.buddyConfigs.append(bud.cfg)
+			self.appConfig.accounts.append(acfg)
+		
+		# Put back disabled accounts
+		self.appConfig.accounts.extend(disabled_accs)
+		# Save
+		self.appConfig.saveFile(filename)
+	
+	def start(self, cfg_file='pygui.js'):
+		# Load config
+		if cfg_file and os.path.exists(cfg_file):
+			self.appConfig.loadFile(cfg_file)
+
+		self.appConfig.epConfig.uaConfig.threadCnt = 0;
+		self.appConfig.epConfig.uaConfig.mainThreadOnly = True
+		self.appConfig.epConfig.logConfig.writer = self.logger
+		self.appConfig.epConfig.logConfig.level = 5
+		self.appConfig.epConfig.logConfig.consoleLevel = 5
+				
+		# Initialize library
+		self.appConfig.epConfig.uaConfig.userAgent = "pygui-" + self.ep.libVersion().full;
+		self.ep.libInit(self.appConfig.epConfig)
+		self.master.title('pjsua2 Demo version ' + self.ep.libVersion().full)
+		
+		# Create transports
+		if self.appConfig.udp.enabled:
+			self.ep.transportCreate(self.appConfig.udp.type, self.appConfig.udp.config)
+		if self.appConfig.tcp.enabled:
+			self.ep.transportCreate(self.appConfig.tcp.type, self.appConfig.tcp.config)
+		if self.appConfig.tls.enabled:
+			self.ep.transportCreate(self.appConfig.tls.type, self.appConfig.tls.config)
+			
+		# Add accounts
+		for cfg in self.appConfig.accounts:
+			if cfg.enabled:
+				self._createAcc(cfg.config)
+				acc = self.accList[-1]
+				for buddy_cfg in cfg.buddyConfigs:
+					self._createBuddy(acc, buddy_cfg)
+				
+		# Start library
+		self.ep.libStart()
+		
+		# Start polling
+		self._onTimer()
+
+	def updateAccount(self, acc):
+		if acc.deleting:
+			return	# ignore
+		iid = str(acc.randId)
+		text = acc.cfg.idUri
+		status = acc.statusText()
+		
+		values = (status,)
+		if self.tv.exists(iid):
+			self.tv.item(iid, text=text, values=values)
+		else:
+			self.tv.insert('', 'end',  iid, open=True, text=text, values=values)
+		
+	def updateBuddy(self, bud):
+		iid = 'buddy' + str(bud.randId)
+		text = bud.cfg.uri
+		status = bud.statusText()
+		
+		values = (status,)
+		if self.tv.exists(iid):
+			self.tv.item(iid, text=text, values=values)
+		else:
+			self.tv.insert(str(bud.account.randId), 'end',  iid, open=True, text=text, values=values)
+		
+	def _createAcc(self, acc_cfg):
+		acc = account.Account(self)
+		acc.cfg = acc_cfg
+		self.accList.append(acc)
+		self.updateAccount(acc)
+		acc.create(acc.cfg)
+		acc.cfgChanged = False
+		self.updateAccount(acc)
+				
+	def _createBuddy(self, acc, buddy_cfg):
+		bud = buddy.Buddy(self)
+		bud.cfg = buddy_cfg
+		bud.account = acc
+		bud.create(acc, bud.cfg)
+		self.updateBuddy(bud)
+		acc.buddyList.append(bud)
+
+	def _createWidgets(self):
+		self._createAppMenu()
+		
+		# Main pane, a Treeview
+		self.tv = ttk.Treeview(self, columns=('Status'), show='tree')
+		self.tv.pack(side='top', fill='both', expand='yes', padx=5, pady=5)
+
+		self._createContextMenu()
+		
+		# Handle close event
+		self.master.protocol("WM_DELETE_WINDOW", self._onClose)
+	
+	def _createAppMenu(self):
+		# Main menu bar
+		top = self.winfo_toplevel()
+		self.menubar = tk.Menu()
+		top.configure(menu=self.menubar)
+		
+		# File menu
+		file_menu = tk.Menu(self.menubar, tearoff=False)
+		self.menubar.add_cascade(label="File", menu=file_menu)
+		file_menu.add_command(label="Add account..", command=self._onMenuAddAccount)
+		file_menu.add_checkbutton(label="Show/hide log window", command=self._onMenuShowHideLogWindow, variable=self.showLogWindow)
+		file_menu.add_separator()
+		file_menu.add_command(label="Settings...", command=self._onMenuSettings)
+		file_menu.add_command(label="Save Settings", command=self._onMenuSaveSettings)
+		file_menu.add_separator()
+		file_menu.add_command(label="Quit", command=self._onMenuQuit)
+
+		# Window menu
+		self.window_menu = tk.Menu(self.menubar, tearoff=False)
+		self.menubar.add_cascade(label="Window", menu=self.window_menu)
+		
+		# Help menu
+		help_menu = tk.Menu(self.menubar, tearoff=False)
+		self.menubar.add_cascade(label="Help", menu=help_menu)
+		help_menu.add_command(label="About", underline=2, command=self._onMenuAbout)
+	
+	def _showChatWindow(self, chat_inst):
+		chat_inst.showWindow()
+		
+	def updateWindowMenu(self):
+		# Chat windows
+		self.window_menu.delete(0, tk.END)
+		for acc in self.accList:
+			for c in acc.chatList:
+				cmd = lambda arg=c: self._showChatWindow(arg)
+				self.window_menu.add_command(label=c.title, command=cmd)
+		
+	def _createContextMenu(self):
+		top = self.winfo_toplevel()
+
+		# Create Account context menu
+		self.accMenu = tk.Menu(top, tearoff=False)
+		# Labels, must match with _onAccContextMenu()
+		labels = ['Unregister', 'Reregister', 'Add buddy...', '-',
+			  'Online', 'Invisible', 'Away', 'Busy', '-',
+			  'Settings...', '-',
+			  'Delete...']
+		for label in labels:
+			if label=='-':
+				self.accMenu.add_separator()
+			else:
+				cmd = lambda arg=label: self._onAccContextMenu(arg)
+				self.accMenu.add_command(label=label, command=cmd)
+		
+		# Create Buddy context menu
+		# Labels, must match with _onBuddyContextMenu()
+		self.buddyMenu = tk.Menu(top, tearoff=False)
+		labels = ['Audio call', 'Send instant message', '-',
+			  'Subscribe', 'Unsubscribe', '-',
+			  'Settings...', '-',
+			  'Delete...']
+		
+		for label in labels:
+			if label=='-':
+				self.buddyMenu.add_separator()
+			else:
+				cmd = lambda arg=label: self._onBuddyContextMenu(arg)
+				self.buddyMenu.add_command(label=label, command=cmd)
+		
+		if (top.tk.call('tk', 'windowingsystem')=='aqua'):
+			self.tv.bind('<2>', self._onTvRightClick)
+			self.tv.bind('<Control-1>', self._onTvRightClick)
+		else:
+			self.tv.bind('<3>', self._onTvRightClick)
+		self.tv.bind('<Double-Button-1>', self._onTvDoubleClick)
+
+	def _getSelectedAccount(self):
+		items = self.tv.selection()
+		if not items:
+			return None
+		try:
+			iid = int(items[0])
+		except:
+			return None
+		accs = [acc for acc in self.accList if acc.randId==iid]
+		if not accs:
+			return None
+		return accs[0]
+	
+	def _getSelectedBuddy(self):
+		items = self.tv.selection()
+		if not items:
+			return None
+		try:
+			iid = int(items[0][5:])
+			iid_parent = int(self.tv.parent(items[0]))
+		except:
+			return None
+			
+		accs = [acc for acc in self.accList if acc.randId==iid_parent]
+		if not accs:
+			return None
+			
+		buds = [b for b in accs[0].buddyList if b.randId==iid]
+		if not buds:
+			return None
+			
+		return buds[0]
+	
+	def _onTvRightClick(self, event):
+		iid = self.tv.identify_row(event.y)
+		#iid = self.tv.identify('item', event.x, event.y)
+		if iid:
+			self.tv.selection_set( (iid,) )
+			acc = self._getSelectedAccount()
+			if acc:
+				self.accMenu.post(event.x_root, event.y_root)
+			else:
+				# A buddy is selected
+				self.buddyMenu.post(event.x_root, event.y_root)
+	
+	def _onTvDoubleClick(self, event):
+		iid = self.tv.identify_row(event.y)
+		if iid:
+			self.tv.selection_set( (iid,) )
+			acc = self._getSelectedAccount()
+			if acc:
+				self.cfgChanged = False
+				dlg = accountsetting.Dialog(self.master, acc.cfg)
+				if dlg.doModal():
+					self.updateAccount(acc)
+					acc.modify(acc.cfg)
+			else:
+				bud = self._getSelectedBuddy()
+				acc = bud.account
+				chat = acc.findChat(bud.cfg.uri)
+				if not chat:
+					chat = acc.newChat(bud.cfg.uri)
+				chat.showWindow()
+	
+	def _onAccContextMenu(self, label):
+		acc = self._getSelectedAccount()
+		if not acc:
+			return
+		
+		if label=='Unregister':
+			acc.setRegistration(False)
+		elif label=='Reregister':
+			acc.setRegistration(True)
+		elif label=='Online':
+			ps = pj.PresenceStatus()
+			ps.status = pj.PJSUA_BUDDY_STATUS_ONLINE
+			acc.setOnlineStatus(ps)
+		elif label=='Invisible':
+			ps = pj.PresenceStatus()
+			ps.status = pj.PJSUA_BUDDY_STATUS_OFFLINE
+			acc.setOnlineStatus(ps)
+		elif label=='Away':
+			ps = pj.PresenceStatus()
+			ps.status = pj.PJSUA_BUDDY_STATUS_ONLINE
+			ps.activity = pj.PJRPID_ACTIVITY_AWAY
+			ps.note = "Away"
+			acc.setOnlineStatus(ps)
+		elif label=='Busy':
+			ps = pj.PresenceStatus()
+			ps.status = pj.PJSUA_BUDDY_STATUS_ONLINE
+			ps.activity = pj.PJRPID_ACTIVITY_BUSY
+			ps.note = "Busy"
+			acc.setOnlineStatus(ps)
+		elif label=='Settings...':
+			self.cfgChanged = False
+			dlg = accountsetting.Dialog(self.master, acc.cfg)
+			if dlg.doModal():
+				self.updateAccount(acc)
+				acc.modify(acc.cfg)
+		elif label=='Delete...':
+			msg = "Do you really want to delete account '%s'?" % acc.cfg.idUri
+			if msgbox.askquestion('Delete account?', msg, default=msgbox.NO) != u'yes':
+				return
+			iid = str(acc.randId)
+			self.accList.remove(acc)
+			acc.setRegistration(False)
+			acc.deleting = True
+			del acc
+			self.tv.delete( (iid,) )
+		elif label=='Add buddy...':
+			cfg = pj.BuddyConfig()
+			dlg = buddy.SettingDialog(self.master, cfg)
+			if dlg.doModal():
+				self._createBuddy(acc, cfg)
+		else:
+			assert not ("Unknown menu " + label)
+	
+	def _onBuddyContextMenu(self, label):
+		bud = self._getSelectedBuddy()
+		if not bud:
+			return
+		acc = bud.account
+			
+		if label=='Audio call':
+			chat = acc.findChat(bud.cfg.uri)
+			if not chat: chat = acc.newChat(bud.cfg.uri)
+			chat.showWindow()
+			chat.startCall()
+		elif label=='Send instant message':
+			chat = acc.findChat(bud.cfg.uri)
+			if not chat: chat = acc.newChat(bud.cfg.uri)
+			chat.showWindow(True)
+		elif label=='Subscribe':
+			bud.subscribePresence(True)
+		elif label=='Unsubscribe':
+			bud.subscribePresence(False)
+		elif label=='Settings...':
+			subs = bud.cfg.subscribe
+			uri  = bud.cfg.uri
+			dlg = buddy.SettingDialog(self.master, bud.cfg)
+			if dlg.doModal():
+				self.updateBuddy(bud)
+				# URI updated?
+				if uri != bud.cfg.uri:
+					cfg = bud.cfg
+					# del old
+					iid = 'buddy' + str(bud.randId)
+					acc.buddyList.remove(bud)
+					del bud
+					self.tv.delete( (iid,) )
+					# add new
+					self._createBuddy(acc, cfg)
+				# presence subscribe setting updated
+				elif subs != bud.cfg.subscribe:
+					bud.subscribePresence(bud.cfg.subscribe)
+		elif label=='Delete...':
+			msg = "Do you really want to delete buddy '%s'?" % bud.cfg.uri
+			if msgbox.askquestion('Delete buddy?', msg, default=msgbox.NO) != u'yes':
+				return
+			iid = 'buddy' + str(bud.randId)
+			acc.buddyList.remove(bud)
+			del bud
+			self.tv.delete( (iid,) )
+		else:
+			assert not ("Unknown menu " + label)
+			
+	def _onTimer(self):
+		if not self.quitting:
+			self.ep.libHandleEvents(10)
+			if not self.quitting:
+				self.master.after(50, self._onTimer)
+			
+	def _onClose(self):
+		self.saveConfig()
+		self.quitting = True
+		self.ep.libDestroy()
+		self.ep = None
+		self.update()
+		self.quit()
+		
+	def _onMenuAddAccount(self):
+		cfg = pj.AccountConfig()
+		dlg = accountsetting.Dialog(self.master, cfg)
+		if dlg.doModal():
+			self._createAcc(cfg)
+			
+	def _onMenuShowHideLogWindow(self):
+		if self.showLogWindow.get():
+			self.logWindow.deiconify()
+		else:
+			self.logWindow.withdraw()
+	
+	def _onMenuSettings(self):
+		dlg = settings.Dialog(self, self.appConfig)
+		if dlg.doModal():
+			msgbox.showinfo(self.master.title(), 'You need to restart for new settings to take effect')
+	
+	def _onMenuSaveSettings(self):
+		self.saveConfig()
+		
+	def _onMenuQuit(self):
+		self._onClose()
+
+	def _onMenuAbout(self):
+		msgbox.showinfo(self.master.title(), 'About')
+		
+
+class ExceptionCatcher:
+	"""Custom Tk exception catcher, mainly to display more information 
+	   from pj.Error exception
+	""" 
+	def __init__(self, func, subst, widget):
+		self.func = func 
+		self.subst = subst
+		self.widget = widget
+	def __call__(self, *args):
+		try:
+			if self.subst:
+				args = apply(self.subst, args)
+			return apply(self.func, args)
+		except pj.Error, error:
+			print 'Exception:'
+			print '  ', error.info()
+			print 'Traceback:'
+			print traceback.print_stack()
+			log.writeLog2(1, 'Exception: ' + error.info() + '\n')
+		except Exception, error:
+			print 'Exception:'
+			print '  ', str(error)
+			print 'Traceback:'
+			print traceback.print_stack()
+			log.writeLog2(1, 'Exception: ' + str(error) + '\n')
+
+def main():
+	#tk.CallWrapper = ExceptionCatcher
+	app = Application()
+	app.start()
+	app.mainloop()
+		
+if __name__ == '__main__':
+	main()
diff --git a/jni/pjproject-android/pjsip-apps/src/pygui/buddy.py b/jni/pjproject-android/pjsip-apps/src/pygui/buddy.py
new file mode 100644
index 0000000..6cf7477
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/pygui/buddy.py
@@ -0,0 +1,152 @@
+# $Id: buddy.py 4704 2014-01-16 05:30:46Z ming $
+#
+# pjsua Python GUI Demo
+#
+# Copyright (C)2013 Teluu Inc. (http://www.teluu.com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+#
+import sys
+if sys.version_info[0] >= 3: # Python 3
+	import tkinter as tk
+	from tkinter import ttk
+	from tkinter import messagebox as msgbox
+else:
+	import Tkinter as tk
+	import tkMessageBox as msgbox
+	import ttk
+
+import random
+import pjsua2 as pj
+import endpoint
+import application
+
+# Buddy class
+class Buddy(pj.Buddy):
+	"""
+	High level Python Buddy object, derived from pjsua2's Buddy object.
+	"""
+	def __init__(self, app):
+		pj.Buddy.__init__(self)
+		self.app = app
+		self.randId = random.randint(1, 9999)
+		self.cfg = None
+		self.account = None
+
+	def statusText(self):
+		bi = self.getInfo()
+		status = ''
+		if bi.subState == pj.PJSIP_EVSUB_STATE_ACTIVE:
+			if bi.presStatus.status == pj.PJSUA_BUDDY_STATUS_ONLINE:
+				status = bi.presStatus.statusText
+				if not status:
+					status = 'Online'
+			elif bi.presStatus.status == pj.PJSUA_BUDDY_STATUS_OFFLINE:
+				status = 'Offline'
+			else:
+				status = 'Unknown'
+		return status
+	
+	def onBuddyState(self):
+		self.app.updateBuddy(self)
+
+class SettingDialog(tk.Toplevel):
+	"""
+	This implements buddy settings dialog to manipulate buddy settings.
+	"""
+	def __init__(self, parent, cfg):
+		tk.Toplevel.__init__(self, parent)
+		self.transient(parent)
+		self.parent = parent
+		self.geometry("+100+100")
+		self.title('Buddy settings')
+		
+		self.frm = ttk.Frame(self)
+		self.frm.pack(expand='yes', fill='both')
+		
+		self.isOk = False
+		self.cfg = cfg
+		
+		self.createWidgets()
+	
+	def doModal(self):
+		if self.parent:
+			self.parent.wait_window(self)
+		else:
+			self.wait_window(self)
+		return self.isOk
+		
+	def createWidgets(self):
+		# The notebook
+		self.frm.rowconfigure(0, weight=1)
+		self.frm.rowconfigure(1, weight=0)
+		self.frm.columnconfigure(0, weight=1)
+		self.frm.columnconfigure(1, weight=1)
+		self.wTab = ttk.Notebook(self.frm)
+		self.wTab.grid(column=0, row=0, columnspan=2, padx=5, pady=5, sticky=tk.N+tk.S+tk.W+tk.E)
+		
+		# Main buttons
+		btnOk = ttk.Button(self.frm, text='Ok', command=self.onOk)
+		btnOk.grid(column=0, row=1, sticky=tk.E, padx=20, pady=10)
+		btnCancel = ttk.Button(self.frm, text='Cancel', command=self.onCancel)
+		btnCancel.grid(column=1, row=1, sticky=tk.W, padx=20, pady=10)
+		
+		# Tabs
+		self.createBasicTab()
+		
+	def createBasicTab(self):
+		# Prepare the variables to set/receive values from GUI
+		self.cfgUri = tk.StringVar()
+		self.cfgUri.set( self.cfg.uri )
+		self.cfgSubscribe = tk.IntVar()
+		self.cfgSubscribe.set(self.cfg.subscribe)
+		
+		# Build the tab page
+		frm = ttk.Frame(self.frm)
+		frm.columnconfigure(0, weight=1)
+		frm.columnconfigure(1, weight=2)
+		row = 0
+		ttk.Label(frm, text='URI:').grid(row=row, column=0, sticky=tk.E, pady=2)
+		ttk.Entry(frm, textvariable=self.cfgUri, width=40).grid(row=row, column=1, sticky=tk.W+tk.E, padx=6)
+		row += 1
+		ttk.Checkbutton(frm, text='Subscribe presence', variable=self.cfgSubscribe).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+
+		self.wTab.add(frm, text='Basic Settings')
+		
+	
+	def onOk(self):
+		# Check basic settings
+		errors = "";
+		if self.cfgUri.get():
+			if not endpoint.validateSipUri(self.cfgUri.get()):
+				errors += "Invalid Buddy URI: '%s'\n" % (self.cfgUri.get())
+				
+		if errors:
+			msgbox.showerror("Error detected:", errors)
+			return
+		
+		# Basic settings
+		self.cfg.uri = self.cfgUri.get()
+		self.cfg.subscribe = self.cfgSubscribe.get()
+		
+		self.isOk = True
+		self.destroy()
+		
+	def onCancel(self):
+		self.destroy()
+
+
+if __name__ == '__main__':
+	application.main()
diff --git a/jni/pjproject-android/pjsip-apps/src/pygui/call.py b/jni/pjproject-android/pjsip-apps/src/pygui/call.py
new file mode 100644
index 0000000..b467fed
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/pygui/call.py
@@ -0,0 +1,104 @@
+# $Id: call.py 4704 2014-01-16 05:30:46Z ming $
+#
+# pjsua Python GUI Demo
+#
+# Copyright (C)2013 Teluu Inc. (http://www.teluu.com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+#
+import sys
+if sys.version_info[0] >= 3: # Python 3
+	import tkinter as tk
+	from tkinter import ttk
+	from tkinter import messagebox as msgbox
+else:
+	import Tkinter as tk
+	import tkMessageBox as msgbox
+	import ttk
+
+import random
+import pjsua2 as pj
+import application
+import endpoint as ep
+
+# Call class
+class Call(pj.Call):
+	"""
+	High level Python Call object, derived from pjsua2's Call object.
+	"""
+	def __init__(self, acc, peer_uri='', chat=None, call_id = pj.PJSUA_INVALID_ID):
+		pj.Call.__init__(self, acc, call_id)
+                self.acc = acc
+		self.peerUri = peer_uri
+		self.chat = chat
+		self.connected = False
+		self.onhold = False
+
+	def onCallState(self, prm):
+		ci = self.getInfo()
+		self.connected = ci.state == pj.PJSIP_INV_STATE_CONFIRMED			
+		if self.chat:
+			self.chat.updateCallState(self, ci)
+			
+	def onCallMediaState(self, prm):
+		ci = self.getInfo()
+		for mi in ci.media:
+			if mi.type == pj.PJMEDIA_TYPE_AUDIO and \
+			  (mi.status == pj.PJSUA_CALL_MEDIA_ACTIVE or \
+			   mi.status == pj.PJSUA_CALL_MEDIA_REMOTE_HOLD):
+				m = self.getMedia(mi.index)
+				am = pj.AudioMedia.typecastFromMedia(m)
+				# connect ports
+				ep.Endpoint.instance.audDevManager().getCaptureDevMedia().startTransmit(am)
+				am.startTransmit(ep.Endpoint.instance.audDevManager().getPlaybackDevMedia())
+
+				if mi.status == pj.PJSUA_CALL_MEDIA_REMOTE_HOLD and not self.onhold:
+					self.chat.addMessage(None, "'%s' sets call onhold" % (self.peerUri))
+					self.onhold = True
+				elif mi.status == pj.PJSUA_CALL_MEDIA_ACTIVE and self.onhold:
+					self.chat.addMessage(None, "'%s' sets call active" % (self.peerUri))
+					self.onhold = False
+			
+	def onInstantMessage(self, prm):
+		# chat instance should have been initalized
+		if not self.chat: return
+			
+		self.chat.addMessage(self.peerUri, prm.msgBody)
+		self.chat.showWindow()
+			
+	def onInstantMessageStatus(self, prm):
+		if prm.code/100 == 2: return
+		# chat instance should have been initalized
+		if not self.chat: return
+		
+		self.chat.addMessage(None, "Failed sending message to '%s' (%d): %s" % (self.peerUri, prm.code, prm.reason))
+		
+	def onTypingIndication(self, prm):
+		# chat instance should have been initalized
+		if not self.chat: return
+		
+		self.chat.setTypingIndication(self.peerUri, prm.isTyping)
+	
+	def onDtmfDigit(self, prm):
+		#msgbox.showinfo("pygui", 'Got DTMF:' + prm.digit)
+		pass
+		
+	def onCallMediaTransportState(self, prm):
+		#msgbox.showinfo("pygui", "Media transport state")
+		pass
+		
+		
+if __name__ == '__main__':
+	application.main()
diff --git a/jni/pjproject-android/pjsip-apps/src/pygui/chat.py b/jni/pjproject-android/pjsip-apps/src/pygui/chat.py
new file mode 100644
index 0000000..9d2d2e2
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/pygui/chat.py
@@ -0,0 +1,489 @@
+# $Id: chat.py 4704 2014-01-16 05:30:46Z ming $
+#
+# pjsua Python GUI Demo
+#
+# Copyright (C)2013 Teluu Inc. (http://www.teluu.com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+#
+import sys
+if sys.version_info[0] >= 3: # Python 3
+	import tkinter as tk
+	from tkinter import ttk
+else:
+	import Tkinter as tk
+	import ttk
+
+import buddy
+import call
+import chatgui as gui
+import endpoint as ep
+import pjsua2 as pj
+import re
+
+SipUriRegex = re.compile('(sip|sips):([^:;>\@]*)@?([^:;>]*):?([^:;>]*)')
+ConfIdx = 1
+
+# Simple SIP uri parser, input URI must have been validated
+def ParseSipUri(sip_uri_str):
+	m = SipUriRegex.search(sip_uri_str)
+	if not m:
+		assert(0)
+		return None
+	
+	scheme = m.group(1)
+	user = m.group(2)
+	host = m.group(3)
+	port = m.group(4)
+	if host == '':
+		host = user
+		user = ''
+		
+	return SipUri(scheme.lower(), user, host.lower(), port)
+	
+class SipUri:
+	def __init__(self, scheme, user, host, port):
+		self.scheme = scheme
+		self.user = user
+		self.host = host
+		self.port = port
+		
+	def __cmp__(self, sip_uri):
+		if self.scheme == sip_uri.scheme and self.user == sip_uri.user and self.host == sip_uri.host:
+			# don't check port, at least for now
+			return 0
+		return -1
+	
+	def __str__(self):
+		s = self.scheme + ':'
+		if self.user: s += self.user + '@'
+		s += self.host
+		if self.port: s+= ':' + self.port
+		return s
+	
+class Chat(gui.ChatObserver):
+	def __init__(self, app, acc, uri, call_inst=None):
+		self._app = app
+		self._acc = acc
+		self.title = ''
+		
+		global ConfIdx
+		self.confIdx = ConfIdx
+		ConfIdx += 1
+		
+		# each participant call/buddy instances are stored in call list
+		# and buddy list with same index as in particpant list
+		self._participantList = []	# list of SipUri
+		self._callList = []		# list of Call
+		self._buddyList = []		# list of Buddy
+		
+		self._gui = gui.ChatFrame(self)
+		self.addParticipant(uri, call_inst)
+	
+	def _updateGui(self):
+		if self.isPrivate():
+			self.title = str(self._participantList[0])
+		else:
+			self.title = 'Conference #%d (%d participants)' % (self.confIdx, len(self._participantList))
+		self._gui.title(self.title)
+		self._app.updateWindowMenu()
+		
+	def _getCallFromUriStr(self, uri_str, op = ''):
+		uri = ParseSipUri(uri_str)
+		if uri not in self._participantList:
+			print "=== %s cannot find participant with URI '%s'" % (op, uri_str)
+			return None
+		idx = self._participantList.index(uri)
+		if idx < len(self._callList):
+			return self._callList[idx]
+		return None
+	
+	def _getActiveMediaIdx(self, thecall):
+		ci = thecall.getInfo()
+		for mi in ci.media:
+			if mi.type == pj.PJMEDIA_TYPE_AUDIO and \
+			  (mi.status != pj.PJSUA_CALL_MEDIA_NONE and \
+			   mi.status != pj.PJSUA_CALL_MEDIA_ERROR):
+				return mi.index
+		return -1
+		
+	def _getAudioMediaFromUriStr(self, uri_str):
+		c = self._getCallFromUriStr(uri_str)
+		if not c: return None
+
+		idx = self._getActiveMediaIdx(c)
+		if idx < 0: return None
+
+		m = c.getMedia(idx)
+		am = pj.AudioMedia.typecastFromMedia(m)
+		return am
+		
+	def _sendTypingIndication(self, is_typing, sender_uri_str=''):
+		sender_uri = ParseSipUri(sender_uri_str) if sender_uri_str else None
+		type_ind_param = pj.SendTypingIndicationParam()
+		type_ind_param.isTyping = is_typing
+		for idx, p in enumerate(self._participantList):
+			# don't echo back to the original sender
+			if sender_uri and p == sender_uri:
+				continue
+				
+			# send via call, if any, or buddy
+			sender = None
+			if self._callList[idx] and self._callList[idx].connected:
+				sender = self._callList[idx]
+			else:
+				sender = self._buddyList[idx]
+			assert(sender)
+				
+			try:
+				sender.sendTypingIndication(type_ind_param)
+			except:
+				pass
+
+	def _sendInstantMessage(self, msg, sender_uri_str=''):
+		sender_uri = ParseSipUri(sender_uri_str) if sender_uri_str else None
+		send_im_param = pj.SendInstantMessageParam()
+		send_im_param.content = str(msg)
+		for idx, p in enumerate(self._participantList):
+			# don't echo back to the original sender
+			if sender_uri and p == sender_uri:
+				continue
+				
+			# send via call, if any, or buddy
+			sender = None
+			if self._callList[idx] and self._callList[idx].connected:
+				sender = self._callList[idx]
+			else:
+				sender = self._buddyList[idx]
+			assert(sender)
+			
+			try:
+				sender.sendInstantMessage(send_im_param)
+			except:
+				# error will be handled via Account::onInstantMessageStatus()
+				pass
+
+	def isPrivate(self):
+		return len(self._participantList) <= 1
+		
+	def isUriParticipant(self, uri):
+		return uri in self._participantList
+		
+	def registerCall(self, uri_str, call_inst):
+		uri = ParseSipUri(uri_str)
+		try:
+			idx = self._participantList.index(uri)
+			bud = self._buddyList[idx]
+			self._callList[idx] = call_inst
+			call_inst.chat = self
+			call_inst.peerUri = bud.cfg.uri
+		except:
+			assert(0) # idx must be found!
+		
+	def showWindow(self, show_text_chat = False):
+		self._gui.bringToFront()
+		if show_text_chat:
+			self._gui.textShowHide(True)
+		
+	def addParticipant(self, uri, call_inst=None):
+		# avoid duplication
+		if self.isUriParticipant(uri): return
+		
+		uri_str = str(uri)
+		
+		# find buddy, create one if not found (e.g: for IM/typing ind),
+		# it is a temporary one and not really registered to acc
+		bud = None
+		try:
+			bud = self._acc.findBuddy(uri_str)
+		except:
+			bud = buddy.Buddy(None)
+			bud_cfg = pj.BuddyConfig()
+			bud_cfg.uri = uri_str
+			bud_cfg.subscribe = False
+			bud.create(self._acc, bud_cfg)
+			bud.cfg = bud_cfg
+			bud.account = self._acc
+			
+		# update URI from buddy URI
+		uri = ParseSipUri(bud.cfg.uri)
+		
+		# add it
+		self._participantList.append(uri)
+		self._callList.append(call_inst)
+		self._buddyList.append(bud)
+		self._gui.addParticipant(str(uri))
+		self._updateGui()
+	
+	def kickParticipant(self, uri):
+		if (not uri) or (uri not in self._participantList):
+			assert(0)
+			return
+		
+		idx = self._participantList.index(uri)
+		del self._participantList[idx]
+		del self._callList[idx]
+		del self._buddyList[idx]
+		self._gui.delParticipant(str(uri))
+		
+		if self._participantList:
+			self._updateGui()
+		else:
+			self.onCloseWindow()
+			
+	def addMessage(self, from_uri_str, msg):
+		if from_uri_str:
+			# print message on GUI
+			msg = from_uri_str + ': ' + msg
+			self._gui.textAddMessage(msg)
+			# now relay to all participants
+			self._sendInstantMessage(msg, from_uri_str)
+		else:
+			self._gui.textAddMessage(msg, False)
+			
+	def setTypingIndication(self, from_uri_str, is_typing):
+		# notify GUI
+		self._gui.textSetTypingIndication(from_uri_str, is_typing)
+		# now relay to all participants
+		self._sendTypingIndication(is_typing, from_uri_str)
+		
+	def startCall(self):
+		self._gui.enableAudio()
+		call_param = pj.CallOpParam()
+		call_param.opt.audioCount = 1
+		call_param.opt.videoCount = 0
+		fails = []
+		for idx, p in enumerate(self._participantList):
+			# just skip if call is instantiated
+			if self._callList[idx]:
+				continue
+			
+			uri_str = str(p)
+			c = call.Call(self._acc, uri_str, self)
+			self._callList[idx] = c
+			self._gui.audioUpdateState(uri_str, gui.AudioState.INITIALIZING)
+			
+			try:
+				c.makeCall(uri_str, call_param)
+			except:
+				self._callList[idx] = None
+				self._gui.audioUpdateState(uri_str, gui.AudioState.FAILED)
+				fails.append(p)
+				
+		for p in fails:
+			# kick participants with call failure, but spare the last (avoid zombie chat)
+			if not self.isPrivate():
+				self.kickParticipant(p)
+			
+	def stopCall(self):
+		for idx, p in enumerate(self._participantList):
+			self._gui.audioUpdateState(str(p), gui.AudioState.DISCONNECTED)
+			c = self._callList[idx]
+			if c:
+				c.hangup(pj.CallOpParam())
+
+	def updateCallState(self, thecall, info = None):
+		# info is optional here, just to avoid calling getInfo() twice (in the caller and here)
+		if not info: info = thecall.getInfo()
+		
+		if info.state < pj.PJSIP_INV_STATE_CONFIRMED:
+			self._gui.audioUpdateState(thecall.peerUri, gui.AudioState.INITIALIZING)
+		elif info.state == pj.PJSIP_INV_STATE_CONFIRMED:
+			self._gui.audioUpdateState(thecall.peerUri, gui.AudioState.CONNECTED)
+			med_idx = self._getActiveMediaIdx(thecall)
+			si = thecall.getStreamInfo(med_idx)
+			stats_str = "Audio codec: %s/%s\n..." % (si.codecName, si.codecClockRate)
+			self._gui.audioSetStatsText(thecall.peerUri, stats_str)
+		elif info.state == pj.PJSIP_INV_STATE_DISCONNECTED:
+			if info.lastStatusCode/100 != 2:
+				self._gui.audioUpdateState(thecall.peerUri, gui.AudioState.FAILED)
+			else:
+				self._gui.audioUpdateState(thecall.peerUri, gui.AudioState.DISCONNECTED)
+			
+			# reset entry in the callList
+			try:
+				idx = self._callList.index(thecall)
+				if idx >= 0: self._callList[idx] = None
+			except:
+				pass
+			
+			self.addMessage(None, "Call to '%s' disconnected: %s" % (thecall.peerUri, info.lastReason))
+			
+			# kick the disconnected participant, but the last (avoid zombie chat)
+			if not self.isPrivate():
+				self.kickParticipant(ParseSipUri(thecall.peerUri))
+
+			
+	# ** callbacks from GUI (ChatObserver implementation) **
+	
+	# Text
+	def onSendMessage(self, msg):
+		self._sendInstantMessage(msg)
+
+	def onStartTyping(self):
+		self._sendTypingIndication(True)
+		
+	def onStopTyping(self):
+		self._sendTypingIndication(False)
+		
+	# Audio
+	def onHangup(self, peer_uri_str):
+		c = self._getCallFromUriStr(peer_uri_str, "onHangup()")
+		if not c: return
+		call_param = pj.CallOpParam()
+		c.hangup(call_param)
+
+	def onHold(self, peer_uri_str):
+		c = self._getCallFromUriStr(peer_uri_str, "onHold()")
+		if not c: return
+		call_param = pj.CallOpParam()
+		c.setHold(call_param)
+
+	def onUnhold(self, peer_uri_str):
+		c = self._getCallFromUriStr(peer_uri_str, "onUnhold()")
+		if not c: return
+		
+		call_param = pj.CallOpParam()
+		call_param.opt.audioCount = 1
+		call_param.opt.videoCount = 0
+		call_param.opt.flag |= pj.PJSUA_CALL_UNHOLD
+		c.reinvite(call_param)
+		
+	def onRxMute(self, peer_uri_str, mute):
+		am = self._getAudioMediaFromUriStr(peer_uri_str)
+		if not am: return
+		if mute:
+			am.stopTransmit(ep.Endpoint.instance.audDevManager().getPlaybackDevMedia())
+			self.addMessage(None, "Muted audio from '%s'" % (peer_uri_str))
+		else:
+			am.startTransmit(ep.Endpoint.instance.audDevManager().getPlaybackDevMedia())
+			self.addMessage(None, "Unmuted audio from '%s'" % (peer_uri_str))
+		
+	def onRxVol(self, peer_uri_str, vol_pct):
+		am = self._getAudioMediaFromUriStr(peer_uri_str)
+		if not am: return
+		# pjsua volume range = 0:mute, 1:no adjustment, 2:100% louder
+		am.adjustRxLevel(vol_pct/50.0)
+		self.addMessage(None, "Adjusted volume level audio from '%s'" % (peer_uri_str))
+			
+	def onTxMute(self, peer_uri_str, mute):
+		am = self._getAudioMediaFromUriStr(peer_uri_str)
+		if not am: return
+		if mute:
+			ep.Endpoint.instance.audDevManager().getCaptureDevMedia().stopTransmit(am)
+			self.addMessage(None, "Muted audio to '%s'" % (peer_uri_str))
+		else:
+			ep.Endpoint.instance.audDevManager().getCaptureDevMedia().startTransmit(am)
+			self.addMessage(None, "Unmuted audio to '%s'" % (peer_uri_str))
+
+	# Chat room
+	def onAddParticipant(self):
+		buds = []
+		dlg = AddParticipantDlg(None, self._app, buds)
+		if dlg.doModal():
+			for bud in buds:
+				uri = ParseSipUri(bud.cfg.uri)
+				self.addParticipant(uri)
+			if not self.isPrivate():
+				self.startCall()
+				
+	def onStartAudio(self):
+		self.startCall()
+
+	def onStopAudio(self):
+		self.stopCall()
+		
+	def onCloseWindow(self):
+		self.stopCall()
+		# will remove entry from list eventually destroy this chat?
+		if self in self._acc.chatList: self._acc.chatList.remove(self)
+		self._app.updateWindowMenu()
+		# destroy GUI
+		self._gui.destroy()
+
+
+class AddParticipantDlg(tk.Toplevel):
+	"""
+	List of buddies
+	"""
+	def __init__(self, parent, app, bud_list):
+		tk.Toplevel.__init__(self, parent)
+		self.title('Add participants..')
+		self.transient(parent)
+		self.parent = parent
+		self._app = app
+		self.buddyList = bud_list
+		
+		self.isOk = False
+		
+		self.createWidgets()
+	
+	def doModal(self):
+		if self.parent:
+			self.parent.wait_window(self)
+		else:
+			self.wait_window(self)
+		return self.isOk
+		
+	def createWidgets(self):
+		# buddy list
+		list_frame = ttk.Frame(self)
+		list_frame.pack(side=tk.TOP, fill=tk.BOTH, expand=1, padx=20, pady=20)
+		#scrl = ttk.Scrollbar(self, orient=tk.VERTICAL, command=list_frame.yview)
+		#list_frame.config(yscrollcommand=scrl.set)
+		#scrl.pack(side=tk.RIGHT, fill=tk.Y)
+		
+		# draw buddy list
+		self.buddies = []
+		for acc in self._app.accList:
+			self.buddies.append((0, acc.cfg.idUri))
+			for bud in acc.buddyList:
+				self.buddies.append((1, bud))
+		
+		self.bud_var = []
+		for idx,(flag,bud) in enumerate(self.buddies):
+			self.bud_var.append(tk.IntVar())
+			if flag==0:
+				s = ttk.Separator(list_frame, orient=tk.HORIZONTAL)
+				s.pack(fill=tk.X)
+				l = tk.Label(list_frame, anchor=tk.W, text="Account '%s':" % (bud))
+				l.pack(fill=tk.X)
+			else:
+				c = tk.Checkbutton(list_frame, anchor=tk.W, text=bud.cfg.uri, variable=self.bud_var[idx])
+				c.pack(fill=tk.X)
+		s = ttk.Separator(list_frame, orient=tk.HORIZONTAL)
+		s.pack(fill=tk.X)
+
+		# Ok/cancel buttons
+		tail_frame = ttk.Frame(self)
+		tail_frame.pack(side=tk.BOTTOM, fill=tk.BOTH, expand=1)
+		
+		btnOk = ttk.Button(tail_frame, text='Ok', default=tk.ACTIVE, command=self.onOk)
+		btnOk.pack(side=tk.LEFT, padx=20, pady=10)
+		btnCancel = ttk.Button(tail_frame, text='Cancel', command=self.onCancel)
+		btnCancel.pack(side=tk.RIGHT, padx=20, pady=10)
+		
+	def onOk(self):
+		self.buddyList[:] = []
+		for idx,(flag,bud) in enumerate(self.buddies):
+			if not flag: continue
+			if self.bud_var[idx].get() and not (bud in self.buddyList):
+				self.buddyList.append(bud)
+			
+		self.isOk = True
+		self.destroy()
+		
+	def onCancel(self):
+		self.destroy()
diff --git a/jni/pjproject-android/pjsip-apps/src/pygui/chatgui.py b/jni/pjproject-android/pjsip-apps/src/pygui/chatgui.py
new file mode 100644
index 0000000..c39e682
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/pygui/chatgui.py
@@ -0,0 +1,420 @@
+# $Id: chatgui.py 4704 2014-01-16 05:30:46Z ming $
+#
+# pjsua Python GUI Demo
+#
+# Copyright (C)2013 Teluu Inc. (http://www.teluu.com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+#
+import sys
+if sys.version_info[0] >= 3: # Python 3
+	import tkinter as tk
+	from tkinter import ttk
+	from tkinter import messagebox as msgbox
+else:
+	import Tkinter as tk
+	import ttk
+	import tkMessageBox as msgbox
+
+
+class TextObserver:
+	def onSendMessage(self, msg):
+		pass
+	def onStartTyping(self):
+		pass
+	def onStopTyping(self):
+		pass
+		
+class TextFrame(ttk.Frame):
+	def __init__(self, master, observer):
+		ttk.Frame.__init__(self, master)
+		self._observer = observer
+		self._isTyping = False
+		self._createWidgets()
+
+	def _onSendMessage(self, event):
+		send_text = self._typingBox.get("1.0", tk.END).strip()
+		if send_text == '':
+			return
+		
+		self.addMessage('me: ' + send_text)
+		self._typingBox.delete("0.0", tk.END)
+		self._onTyping(None)
+		
+		# notify app for sending message
+		self._observer.onSendMessage(send_text)
+		
+	def _onTyping(self, event):
+		# notify app for typing indication
+		is_typing = self._typingBox.get("1.0", tk.END).strip() != ''
+		if is_typing != self._isTyping:
+			self._isTyping = is_typing
+			if is_typing:
+				self._observer.onStartTyping()
+			else:
+				self._observer.onStopTyping()
+		
+	def _createWidgets(self):
+		self.rowconfigure(0, weight=1)
+		self.rowconfigure(1, weight=0)
+		self.rowconfigure(2, weight=0)
+		self.columnconfigure(0, weight=1)
+		self.columnconfigure(1, weight=0)
+		
+		self._text = tk.Text(self, width=50, height=30, font=("Arial", "10"))
+		self._text.grid(row=0, column=0, sticky='nswe')
+		self._text.config(state=tk.DISABLED)
+		self._text.tag_config("info", foreground="darkgray", font=("Arial", "9", "italic"))
+		
+		scrl = ttk.Scrollbar(self, orient=tk.VERTICAL, command=self._text.yview)
+		self._text.config(yscrollcommand=scrl.set)
+		scrl.grid(row=0, column=1, sticky='nsw')
+		
+		self._typingBox = tk.Text(self, width=50, height=1, font=("Arial", "10"))
+		self._typingBox.grid(row=1, columnspan=2, sticky='we', pady=0)
+		
+		self._statusBar = tk.Label(self, anchor='w', font=("Arial", "8", "italic"))
+		self._statusBar.grid(row=2, columnspan=2, sticky='we')
+		
+		self._typingBox.bind('<Return>', self._onSendMessage)
+		self._typingBox.bind("<Key>", self._onTyping)
+		self._typingBox.focus_set()
+		
+	def addMessage(self, msg, is_chat = True):
+		self._text.config(state=tk.NORMAL)
+		if is_chat:
+			self._text.insert(tk.END, msg+'\r\n')
+		else:
+			self._text.insert(tk.END, msg+'\r\n', 'info')
+		self._text.config(state=tk.DISABLED)
+		self._text.yview(tk.END)
+
+	def setTypingIndication(self, who, is_typing):
+		if is_typing:
+			self._statusBar['text'] = "'%s' is typing.." % (who)
+		else:
+			self._statusBar['text'] = ''
+
+class AudioState:
+	NULL, INITIALIZING, CONNECTED, DISCONNECTED, FAILED = range(5)
+			
+class AudioObserver:
+	def onHangup(self, peer_uri):
+		pass
+	def onHold(self, peer_uri):
+		pass
+	def onUnhold(self, peer_uri):
+		pass
+	def onRxMute(self, peer_uri, is_muted):
+		pass
+	def onRxVol(self, peer_uri, vol_pct):
+		pass
+	def onTxMute(self, peer_uri, is_muted):
+		pass
+			
+
+class AudioFrame(ttk.Labelframe):
+	def __init__(self, master, peer_uri, observer):
+		ttk.Labelframe.__init__(self, master, text=peer_uri)
+		self.peerUri = peer_uri
+		self._observer = observer
+		self._initFrame = None
+		self._callFrame = None
+		self._rxMute = False
+		self._txMute = False
+		self._state = AudioState.NULL
+		
+		self._createInitWidgets()
+		self._createWidgets()
+		
+	def updateState(self, state):
+		if self._state == state:
+			return
+
+		if state == AudioState.INITIALIZING:
+			self._callFrame.pack_forget()
+			self._initFrame.pack(fill=tk.BOTH)
+			self._btnCancel.pack(side=tk.TOP)
+			self._lblInitState['text'] = 'Intializing..'
+
+		elif state == AudioState.CONNECTED:
+			self._initFrame.pack_forget()
+			self._callFrame.pack(fill=tk.BOTH)			
+		else:
+			self._callFrame.pack_forget()
+			self._initFrame.pack(fill=tk.BOTH)
+			if state == AudioState.FAILED:
+				self._lblInitState['text'] = 'Failed'
+			else:
+				self._lblInitState['text'] = 'Normal cleared'
+				self._btnCancel.pack_forget()
+			
+			self._btnHold['text'] = 'Hold'
+			self._btnHold.config(state=tk.NORMAL)
+			self._rxMute = False
+			self._txMute = False
+			self.btnRxMute['text'] = 'Mute'
+			self.btnTxMute['text'] = 'Mute'
+			self.rxVol.set(5.0)
+		
+		# save last state
+		self._state = state
+		
+	def setStatsText(self, stats_str):
+		self.stat.config(state=tk.NORMAL)
+		self.stat.delete("0.0", tk.END)
+		self.stat.insert(tk.END, stats_str)
+		self.stat.config(state=tk.DISABLED)
+		
+	def _onHold(self):
+		self._btnHold.config(state=tk.DISABLED)
+		# notify app
+		if self._btnHold['text'] == 'Hold':
+			self._observer.onHold(self.peerUri)
+			self._btnHold['text'] = 'Unhold'
+		else:
+			self._observer.onUnhold(self.peerUri)
+			self._btnHold['text'] = 'Hold'
+		self._btnHold.config(state=tk.NORMAL)
+
+	def _onHangup(self):
+		# notify app
+		self._observer.onHangup(self.peerUri)
+
+	def _onRxMute(self):
+		# notify app
+		self._rxMute = not self._rxMute
+		self._observer.onRxMute(self.peerUri, self._rxMute)
+		self.btnRxMute['text'] = 'Unmute' if self._rxMute else 'Mute'
+		
+	def _onRxVol(self, event):
+		# notify app
+		vol = self.rxVol.get()
+		self._observer.onRxVol(self.peerUri, vol*10.0)
+
+	def _onTxMute(self):
+		# notify app
+		self._txMute = not self._txMute
+		self._observer.onTxMute(self.peerUri, self._txMute)
+		self.btnTxMute['text'] = 'Unmute' if self._txMute else 'Mute'
+
+	def _createInitWidgets(self):
+		self._initFrame = ttk.Frame(self)
+		#self._initFrame.pack(fill=tk.BOTH)
+
+	
+		self._lblInitState = tk.Label(self._initFrame, font=("Arial", "12"), text='')
+		self._lblInitState.pack(side=tk.TOP, fill=tk.X, expand=1)
+		
+		# Operation: cancel/kick
+		self._btnCancel = ttk.Button(self._initFrame, text = 'Cancel', command=self._onHangup)
+		self._btnCancel.pack(side=tk.TOP)
+				
+	def _createWidgets(self):
+		self._callFrame = ttk.Frame(self)
+		#self._callFrame.pack(fill=tk.BOTH)
+		
+		# toolbar
+		toolbar = ttk.Frame(self._callFrame)
+		toolbar.pack(side=tk.TOP, fill=tk.X)
+		self._btnHold = ttk.Button(toolbar, text='Hold', command=self._onHold)
+		self._btnHold.pack(side=tk.LEFT, fill=tk.Y)
+		#self._btnXfer = ttk.Button(toolbar, text='Transfer..')
+		#self._btnXfer.pack(side=tk.LEFT, fill=tk.Y)
+		self._btnHangUp = ttk.Button(toolbar, text='Hangup', command=self._onHangup)
+		self._btnHangUp.pack(side=tk.LEFT, fill=tk.Y)
+
+		# volume tool
+		vol_frm = ttk.Frame(self._callFrame)
+		vol_frm.pack(side=tk.TOP, fill=tk.X)
+		
+		self.rxVolFrm = ttk.Labelframe(vol_frm, text='RX volume')
+		self.rxVolFrm.pack(side=tk.LEFT, fill=tk.Y)
+		
+		self.btnRxMute = ttk.Button(self.rxVolFrm, width=8, text='Mute', command=self._onRxMute)
+		self.btnRxMute.pack(side=tk.LEFT)
+		self.rxVol = tk.Scale(self.rxVolFrm, orient=tk.HORIZONTAL, from_=0.0, to=10.0, showvalue=1) #, tickinterval=10.0, showvalue=1)
+		self.rxVol.set(5.0)
+		self.rxVol.bind("<ButtonRelease-1>", self._onRxVol)
+		self.rxVol.pack(side=tk.LEFT)
+		
+		self.txVolFrm = ttk.Labelframe(vol_frm, text='TX volume')
+		self.txVolFrm.pack(side=tk.RIGHT, fill=tk.Y)
+		
+		self.btnTxMute = ttk.Button(self.txVolFrm, width=8, text='Mute', command=self._onTxMute)
+		self.btnTxMute.pack(side=tk.LEFT)
+		
+		# stat
+		self.stat = tk.Text(self._callFrame, width=10, height=2, bg='lightgray', relief=tk.FLAT, font=("Arial", "9"))
+		self.stat.insert(tk.END, 'stat here')
+		self.stat.pack(side=tk.BOTTOM, fill=tk.BOTH, expand=1)
+
+
+class ChatObserver(TextObserver, AudioObserver):
+	def onAddParticipant(self):
+		pass
+	def onStartAudio(self):
+		pass
+	def onStopAudio(self):
+		pass
+	def onCloseWindow(self):
+		pass
+		
+class ChatFrame(tk.Toplevel):
+	"""
+	Room
+	"""
+	def __init__(self, observer):
+		tk.Toplevel.__init__(self)
+		self.protocol("WM_DELETE_WINDOW", self._onClose)
+		self._observer = observer
+
+		self._text = None
+		self._text_shown = True
+		
+		self._audioEnabled = False
+		self._audioFrames = []
+		self._createWidgets()
+	
+	def _createWidgets(self):
+		# toolbar
+		self.toolbar = ttk.Frame(self)
+		self.toolbar.pack(side=tk.TOP, fill=tk.BOTH)
+		
+		btnText = ttk.Button(self.toolbar, text='Show/hide text', command=self._onShowHideText)
+		btnText.pack(side=tk.LEFT, fill=tk.Y)
+		btnAudio = ttk.Button(self.toolbar, text='Start/stop audio', command=self._onStartStopAudio)
+		btnAudio.pack(side=tk.LEFT, fill=tk.Y)
+		
+		ttk.Separator(self.toolbar, orient=tk.VERTICAL).pack(side=tk.LEFT, fill=tk.Y, padx = 4)
+
+		btnAdd = ttk.Button(self.toolbar, text='Add participant..', command=self._onAddParticipant)
+		btnAdd.pack(side=tk.LEFT, fill=tk.Y)
+
+		# media frame
+		self.media = ttk.Frame(self)
+		self.media.pack(side=tk.BOTTOM, fill=tk.BOTH, expand=1)
+		
+		# create Text Chat frame
+		self.media_left = ttk.Frame(self.media)
+		self._text = TextFrame(self.media_left, self._observer)
+		self._text.pack(fill=tk.BOTH, expand=1)
+		self.media_left.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
+		
+		# create other media frame
+		self.media_right = ttk.Frame(self.media)
+		
+	def _arrangeMediaFrames(self):
+		if len(self._audioFrames) == 0:
+			self.media_right.pack_forget()
+			return
+		
+		self.media_right.pack(side=tk.RIGHT, fill=tk.BOTH, expand=1)
+		MAX_ROWS = 3
+		row_num = 0
+		col_num = 1
+		for frm in self._audioFrames:
+			frm.grid(row=row_num, column=col_num, sticky='nsew', padx=5, pady=5)
+			row_num += 1
+			if row_num >= MAX_ROWS:
+				row_num  = 0
+				col_num += 1
+	
+	def _onShowHideText(self):
+		self.textShowHide(not self._text_shown)
+		
+	def _onAddParticipant(self):
+		self._observer.onAddParticipant()
+	
+	def _onStartStopAudio(self):
+		self._audioEnabled = not self._audioEnabled
+		if self._audioEnabled:
+			self._observer.onStartAudio()
+		else:
+			self._observer.onStopAudio()
+		self.enableAudio(self._audioEnabled)
+		
+	def _onClose(self):
+		self._observer.onCloseWindow()
+			
+	# APIs
+	
+	def bringToFront(self):
+		self.deiconify()
+		self.lift()
+		self._text._typingBox.focus_set()
+		
+	def textAddMessage(self, msg, is_chat = True):
+		self._text.addMessage(msg, is_chat)
+		
+	def textSetTypingIndication(self, who, is_typing = True):
+		self._text.setTypingIndication(who, is_typing)
+		
+	def addParticipant(self, participant_uri):
+		aud_frm = AudioFrame(self.media_right, participant_uri, self._observer)
+		self._audioFrames.append(aud_frm)
+	
+	def delParticipant(self, participant_uri):
+		for aud_frm in self._audioFrames:
+			if participant_uri == aud_frm.peerUri:
+				self._audioFrames.remove(aud_frm)
+				# need to delete aud_frm manually?
+				aud_frm.destroy()
+				return
+
+	def textShowHide(self, show = True):
+		if show:
+			self.media_left.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
+			self._text._typingBox.focus_set()
+		else:
+			self.media_left.pack_forget()
+		self._text_shown = show
+	
+	def enableAudio(self, is_enabled = True):
+		if is_enabled:
+			self._arrangeMediaFrames()
+		else:
+			self.media_right.pack_forget()
+		self._audioEnabled = is_enabled
+			
+	def audioUpdateState(self, participant_uri, state):
+		for aud_frm in self._audioFrames:
+			if participant_uri == aud_frm.peerUri:
+				aud_frm.updateState(state)
+				break
+		if state >= AudioState.DISCONNECTED and len(self._audioFrames) == 1:
+			self.enableAudio(False)
+		else:
+			self.enableAudio(True)
+			
+	def audioSetStatsText(self, participant_uri, stats_str):
+		for aud_frm in self._audioFrames:
+			if participant_uri == aud_frm.peerUri:
+				aud_frm.setStatsText(stats_str)
+				break
+				
+if __name__ == '__main__':
+	root = tk.Tk()
+	root.title("Chat")
+	root.columnconfigure(0, weight=1)
+	root.rowconfigure(0, weight=1)
+	
+	obs = ChatObserver()
+	dlg = ChatFrame(obs)
+	#dlg = TextFrame(root)
+	#dlg = AudioFrame(root)
+
+	#dlg.pack(fill=tk.BOTH, expand=1)
+	root.mainloop()
diff --git a/jni/pjproject-android/pjsip-apps/src/pygui/endpoint.py b/jni/pjproject-android/pjsip-apps/src/pygui/endpoint.py
new file mode 100644
index 0000000..25367f2
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/pygui/endpoint.py
@@ -0,0 +1,53 @@
+# $Id: endpoint.py 4704 2014-01-16 05:30:46Z ming $
+#
+# pjsua Python GUI Demo
+#
+# Copyright (C)2013 Teluu Inc. (http://www.teluu.com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+#
+import sys
+if sys.version_info[0] >= 3: # Python 3
+	import tkinter as tk
+	from tkinter import ttk
+	from tkinter import messagebox as msgbox
+else:
+	import Tkinter as tk
+	import tkMessageBox as msgbox
+	import ttk
+
+import pjsua2 as pj
+import application
+
+
+class Endpoint(pj.Endpoint):
+	"""
+	This is high level Python object inherited from pj.Endpoint
+	"""
+	instance = None
+	def __init__(self):
+		pj.Endpoint.__init__(self)
+		Endpoint.instance = self
+	
+	
+def validateUri(uri):
+	return Endpoint.instance.utilVerifyUri(uri) == pj.PJ_SUCCESS
+
+def validateSipUri(uri):
+	return Endpoint.instance.utilVerifySipUri(uri) == pj.PJ_SUCCESS
+
+
+if __name__ == '__main__':
+	application.main()
diff --git a/jni/pjproject-android/pjsip-apps/src/pygui/log.py b/jni/pjproject-android/pjsip-apps/src/pygui/log.py
new file mode 100644
index 0000000..0011a3e
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/pygui/log.py
@@ -0,0 +1,127 @@
+# $Id: log.py 4704 2014-01-16 05:30:46Z ming $
+#
+# pjsua Python GUI Demo
+#
+# Copyright (C)2013 Teluu Inc. (http://www.teluu.com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+#
+import sys
+if sys.version_info[0] >= 3: # Python 3
+	import tkinter as tk
+	from tkinter import ttk
+	from tkinter import messagebox as msgbox
+else:
+	import Tkinter as tk
+	import tkMessageBox as msgbox
+	import ttk
+
+import pjsua2 as pj
+import application
+
+
+class LogWindow(tk.Toplevel):
+	"""
+	Log window
+	"""
+	instance = None
+	def __init__(self, app):
+		tk.Toplevel.__init__(self, name='logwnd', width=640, height=480)
+		LogWindow.instance = self
+		self.app = app
+		self.state('withdrawn')
+		self.title('Log')
+		self._createWidgets()
+		self.protocol("WM_DELETE_WINDOW", self._onHide)
+
+	def addLog(self, entry):
+		"""entry fields:
+		    int		level;
+		    string	msg;
+		    long	threadId;
+		    string	threadName;
+		"""
+		self.addLog2(entry.level, entry.msg)
+		
+	def addLog2(self, level, msg):
+		if level==5:
+			tags = ('trace',)
+		elif level==3:
+			tags = ('info',)
+		elif level==2:
+			tags = ('warning',)
+		elif level<=1:
+			tags = ('error',)
+		else:
+			tags = None
+		self.text.insert(tk.END, msg, tags)
+		self.text.see(tk.END)
+		
+	def _createWidgets(self):
+		self.rowconfigure(0, weight=1)
+		self.rowconfigure(1, weight=0)
+		self.columnconfigure(0, weight=1)
+		self.columnconfigure(1, weight=0)
+		
+		self.text = tk.Text(self, font=('Courier New', '8'), wrap=tk.NONE, undo=False, padx=4, pady=5)
+		self.text.grid(row=0, column=0, sticky='nswe', padx=5, pady=5)
+		
+		scrl = ttk.Scrollbar(self, orient=tk.VERTICAL, command=self.text.yview)
+		self.text.config(yscrollcommand=scrl.set)
+		scrl.grid(row=0, column=1, sticky='nsw', padx=5, pady=5)
+
+		scrl = ttk.Scrollbar(self, orient=tk.HORIZONTAL, command=self.text.xview)
+		self.text.config(xscrollcommand=scrl.set)
+		scrl.grid(row=1, column=0, sticky='we', padx=5, pady=5)
+		
+		self.text.bind("<Key>", self._onKey)
+		
+		self.text.tag_configure('normal', font=('Courier New', '8'), foreground='black')
+		self.text.tag_configure('trace', font=('Courier New', '8'), foreground='#777777')
+		self.text.tag_configure('info', font=('Courier New', '8', 'bold'), foreground='black')
+		self.text.tag_configure('warning', font=('Courier New', '8', 'bold'), foreground='cyan')
+		self.text.tag_configure('error', font=('Courier New', '8', 'bold'), foreground='red')
+	
+	def _onKey(self, event):
+		# Ignore key event to make text widget read-only
+		return "break"
+	
+	def _onHide(self):
+		# Hide when close ('x') button is clicked
+		self.withdraw()
+		self.app.showLogWindow.set(0)
+		
+	
+def writeLog2(level, msg):
+	if LogWindow.instance:
+		LogWindow.instance.addLog2(level, msg)	
+
+def writeLog(entry):
+	if LogWindow.instance:
+		LogWindow.instance.addLog(entry)
+
+class Logger(pj.LogWriter):
+	"""
+	Logger to receive log messages from pjsua2
+	"""
+	def __init__(self):
+		pj.LogWriter.__init__(self)
+		
+	def write(self, entry):
+		print entry.msg,
+		writeLog(entry)
+
+if __name__ == '__main__':
+	application.main()
diff --git a/jni/pjproject-android/pjsip-apps/src/pygui/settings.py b/jni/pjproject-android/pjsip-apps/src/pygui/settings.py
new file mode 100644
index 0000000..595bc12
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/pygui/settings.py
@@ -0,0 +1,362 @@
+# $Id: settings.py 4704 2014-01-16 05:30:46Z ming $
+#
+# pjsua Python GUI Demo
+#
+# Copyright (C)2013 Teluu Inc. (http://www.teluu.com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+#
+import sys
+if sys.version_info[0] >= 3: # Python 3
+	import tkinter as tk
+	from tkinter import ttk
+	from tkinter import messagebox as msgbox
+else:
+	import Tkinter as tk
+	import tkMessageBox as msgbox
+	import ttk
+
+import pjsua2 as pj
+#import application
+
+# Transport setting
+class SipTransportConfig:
+	def __init__(self, type, enabled):
+		#pj.PersistentObject.__init__(self)
+		self.type = type
+		self.enabled = enabled
+		self.config = pj.TransportConfig()
+	def readObject(self, node):
+		child_node = node.readContainer("SipTransport")
+		self.type = child_node.readInt("type")
+		self.enabled = child_node.readBool("enabled")
+		self.config.readObject(child_node)
+	def writeObject(self, node):
+		child_node = node.writeNewContainer("SipTransport")
+		child_node.writeInt("type", self.type)
+		child_node.writeBool("enabled", self.enabled)
+		self.config.writeObject(child_node)
+
+# Account setting with buddy list
+class AccConfig:
+	def __init__(self):
+		self.enabled = True
+		self.config = pj.AccountConfig()
+		self.buddyConfigs = []
+	def readObject(self, node):
+		acc_node = node.readContainer("Account")
+		self.enabled = acc_node.readBool("enabled")
+		self.config.readObject(acc_node)
+		buddy_node = acc_node.readArray("buddies")
+		while buddy_node.hasUnread():
+			buddy_cfg = pj.BuddyConfig()
+			buddy_cfg.readObject(buddy_node)
+			self.buddyConfigs.append(buddy_cfg)
+	def writeObject(self, node):
+		acc_node = node.writeNewContainer("Account")
+		acc_node.writeBool("enabled", self.enabled)
+		self.config.writeObject(acc_node)
+		buddy_node = acc_node.writeNewArray("buddies")
+		for buddy in self.buddyConfigs:
+			buddy_node.writeObject(buddy)
+
+	
+# Master settings
+class AppConfig:
+	def __init__(self):
+		self.epConfig = pj.EpConfig()	# pj.EpConfig()
+		self.udp = SipTransportConfig(pj.PJSIP_TRANSPORT_UDP, True)
+		self.tcp = SipTransportConfig(pj.PJSIP_TRANSPORT_TCP, True)
+		self.tls = SipTransportConfig(pj.PJSIP_TRANSPORT_TLS, False)
+		self.accounts = []		# Array of AccConfig
+		
+	def loadFile(self, file):
+		json = pj.JsonDocument()
+		json.loadFile(file)
+		root = json.getRootContainer()
+		self.epConfig = pj.EpConfig()
+		self.epConfig.readObject(root)
+		
+		tp_node = root.readArray("transports")
+		self.udp.readObject(tp_node)
+		self.tcp.readObject(tp_node)
+		if tp_node.hasUnread():
+			self.tls.readObject(tp_node)
+			
+		acc_node = root.readArray("accounts")
+		while acc_node.hasUnread():
+			acfg = AccConfig()
+			acfg.readObject(acc_node)
+			self.accounts.append(acfg)
+			
+	def saveFile(self,file):
+		json = pj.JsonDocument()
+		
+		# Write endpoint config
+		json.writeObject(self.epConfig)
+		
+		# Write transport config
+		tp_node = json.writeNewArray("transports")
+		self.udp.writeObject(tp_node)
+		self.tcp.writeObject(tp_node)
+		self.tls.writeObject(tp_node)
+		
+		# Write account configs
+		node = json.writeNewArray("accounts")
+		for acc in self.accounts:
+			acc.writeObject(node)
+				
+		json.saveFile(file)
+		
+
+# Settings dialog
+class Dialog(tk.Toplevel):
+	"""
+	This implements account settings dialog to manipulate account settings.
+	"""
+	def __init__(self, parent, cfg):
+		tk.Toplevel.__init__(self, parent)
+		self.transient(parent)
+		self.parent = parent
+		self.title('Settings')
+		
+		self.frm = ttk.Frame(self)
+		self.frm.pack(expand='yes', fill='both')
+		
+		self.isOk = False
+		self.cfg = cfg
+		
+		self.createWidgets()
+	
+	def doModal(self):
+		if self.parent:
+			self.parent.wait_window(self)
+		else:
+			self.wait_window(self)
+		return self.isOk
+		
+	def createWidgets(self):
+		# The notebook
+		self.frm.rowconfigure(0, weight=1)
+		self.frm.rowconfigure(1, weight=0)
+		self.frm.columnconfigure(0, weight=1)
+		self.frm.columnconfigure(1, weight=1)
+		self.wTab = ttk.Notebook(self.frm)
+		self.wTab.grid(column=0, row=0, columnspan=2, padx=10, pady=10, ipadx=20, ipady=20, sticky=tk.N+tk.S+tk.W+tk.E)
+		
+		# Main buttons
+		btnOk = ttk.Button(self.frm, text='Ok', command=self.onOk)
+		btnOk.grid(column=0, row=1, sticky=tk.E, padx=20, pady=10)
+		btnCancel = ttk.Button(self.frm, text='Cancel', command=self.onCancel)
+		btnCancel.grid(column=1, row=1, sticky=tk.W, padx=20, pady=10)
+		
+		# Tabs
+		self.createBasicTab()
+		self.createNetworkTab()
+		self.createMediaTab()
+
+	def createBasicTab(self):
+		# Prepare the variables to set/receive values from GUI
+		self.cfgLogFile = tk.StringVar(value=self.cfg.epConfig.logConfig.filename)
+		self.cfgLogAppend = tk.BooleanVar(value=True if (self.cfg.epConfig.logConfig.fileFlags & pj.PJ_O_APPEND) else False)
+		
+		# Build the tab page
+		frm = ttk.Frame(self.frm)
+		frm.columnconfigure(0, weight=1)
+		frm.columnconfigure(1, weight=2)
+		row = 0
+		ttk.Label(frm, text='User Agent:').grid(row=row, column=0, sticky=tk.E, pady=2, padx=8)
+		ttk.Label(frm, text=self.cfg.epConfig.uaConfig.userAgent).grid(row=row, column=1, sticky=tk.W, pady=2, padx=6)
+		row += 1
+		ttk.Label(frm, text='Max calls:').grid(row=row, column=0, sticky=tk.E, pady=2, padx=8)
+		ttk.Label(frm, text=str(self.cfg.epConfig.uaConfig.maxCalls)).grid(row=row, column=1, sticky=tk.W, pady=2, padx=6)
+		row += 1
+		ttk.Label(frm, text='Log file:').grid(row=row, column=0, sticky=tk.E, pady=2, padx=8)
+		ttk.Entry(frm, textvariable=self.cfgLogFile, width=32).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Checkbutton(frm, text='Append log file', variable=self.cfgLogAppend).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+
+		self.wTab.add(frm, text='Basic')
+		
+	def createNetworkTab(self):
+		self.cfgNameserver = tk.StringVar()
+		if len(self.cfg.epConfig.uaConfig.nameserver):
+			self.cfgNameserver.set(self.cfg.epConfig.uaConfig.nameserver[0])
+		self.cfgStunServer = tk.StringVar()
+		if len(self.cfg.epConfig.uaConfig.stunServer):
+			self.cfgStunServer.set(self.cfg.epConfig.uaConfig.stunServer[0])
+		self.cfgStunIgnoreError = tk.BooleanVar(value=self.cfg.epConfig.uaConfig.stunIgnoreFailure)
+		
+		self.cfgUdpEnabled = tk.BooleanVar(value=self.cfg.udp.enabled)
+		self.cfgUdpPort = tk.IntVar(value=self.cfg.udp.config.port)
+		self.cfgTcpEnabled = tk.BooleanVar(value=self.cfg.tcp.enabled)
+		self.cfgTcpPort = tk.IntVar(value=self.cfg.tcp.config.port)
+		self.cfgTlsEnabled = tk.BooleanVar(value=self.cfg.tls.enabled)
+		self.cfgTlsPort = tk.IntVar(value=self.cfg.tls.config.port)
+		
+		self.cfgTlsCaFile = tk.StringVar(value=self.cfg.tls.config.tlsConfig.CaListFile)
+		self.cfgTlsCertFile = tk.StringVar(value=self.cfg.tls.config.tlsConfig.certFile)
+		self.cfgTlsVerifyClient = tk.BooleanVar(value=self.cfg.tls.config.tlsConfig.verifyClient)
+		self.cfgTlsVerifyServer = tk.BooleanVar(value=self.cfg.tls.config.tlsConfig.verifyServer)
+		
+		# Build the tab page
+		frm = ttk.Frame(self.frm)
+		frm.columnconfigure(0, weight=1)
+		frm.columnconfigure(1, weight=2)
+		row = 0
+		#ttk.Label(frm, text='UDP transport:').grid(row=row, column=0, sticky=tk.E, pady=2, padx=8)
+		ttk.Checkbutton(frm, text='Enable UDP transport', variable=self.cfgUdpEnabled).grid(row=row, column=0, sticky=tk.W, padx=6, pady=2)
+		row += 1
+		ttk.Label(frm, text='UDP port:').grid(row=row, column=0, sticky=tk.E, pady=2, padx=8)
+		tk.Spinbox(frm, from_=0, to=65535, textvariable=self.cfgUdpPort, width=5).grid(row=row, column=1, sticky=tk.W, padx=6)
+		ttk.Label(frm, text='(0 for any)').grid(row=row, column=1, sticky=tk.E, pady=6, padx=6)
+		row += 1
+		#ttk.Label(frm, text='TCP transport:').grid(row=row, column=0, sticky=tk.E, pady=2, padx=8)
+		ttk.Checkbutton(frm, text='Enable TCP transport', variable=self.cfgTcpEnabled).grid(row=row, column=0, sticky=tk.W, padx=6, pady=2)
+		row += 1
+		ttk.Label(frm, text='TCP port:').grid(row=row, column=0, sticky=tk.E, pady=2, padx=8)
+		tk.Spinbox(frm, from_=0, to=65535, textvariable=self.cfgTcpPort, width=5).grid(row=row, column=1, sticky=tk.W, padx=6)
+		ttk.Label(frm, text='(0 for any)').grid(row=row, column=1, sticky=tk.E, pady=6, padx=6)
+		row += 1
+		#ttk.Label(frm, text='TLS transport:').grid(row=row, column=0, sticky=tk.E, pady=2, padx=8)
+		ttk.Checkbutton(frm, text='Enable TLS transport', variable=self.cfgTlsEnabled).grid(row=row, column=0, sticky=tk.W, padx=6, pady=2)
+		row += 1
+		ttk.Label(frm, text='TLS port:').grid(row=row, column=0, sticky=tk.E, pady=2, padx=8)
+		tk.Spinbox(frm, from_=0, to=65535, textvariable=self.cfgTlsPort, width=5).grid(row=row, column=1, sticky=tk.W, padx=6)
+		ttk.Label(frm, text='(0 for any)').grid(row=row, column=1, sticky=tk.E, pady=6, padx=6)
+		row += 1
+		ttk.Label(frm, text='TLS CA file:').grid(row=row, column=0, sticky=tk.E, pady=2, padx=8)
+		ttk.Entry(frm, textvariable=self.cfgTlsCaFile, width=32).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Label(frm, text='TLS cert file:').grid(row=row, column=0, sticky=tk.E, pady=2, padx=8)
+		ttk.Entry(frm, textvariable=self.cfgTlsCertFile, width=32).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Checkbutton(frm, text='TLS verify server', variable=self.cfgTlsVerifyServer).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+		row += 1
+		ttk.Checkbutton(frm, text='TLS verify client', variable=self.cfgTlsVerifyClient).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+		row += 1
+		ttk.Label(frm, text='DNS and STUN:').grid(row=row, column=0, sticky=tk.W, pady=2, padx=8)
+		row += 1
+		ttk.Label(frm, text='Nameserver:').grid(row=row, column=0, sticky=tk.E, pady=2, padx=8)
+		ttk.Entry(frm, textvariable=self.cfgNameserver, width=32).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Label(frm, text='STUN Server:').grid(row=row, column=0, sticky=tk.E, pady=2, padx=8)
+		ttk.Entry(frm, textvariable=self.cfgStunServer, width=32).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Checkbutton(frm, text='Ignore STUN failure at startup', variable=self.cfgStunIgnoreError).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+		
+		self.wTab.add(frm, text='Network')
+
+	def createMediaTab(self):
+		self.cfgClockrate = tk.IntVar(value=self.cfg.epConfig.medConfig.clockRate)
+		self.cfgSndClockrate = tk.IntVar(value=self.cfg.epConfig.medConfig.sndClockRate)
+		self.cfgAudioPtime = tk.IntVar(value=self.cfg.epConfig.medConfig.audioFramePtime)
+		self.cfgMediaQuality = tk.IntVar(value=self.cfg.epConfig.medConfig.quality)
+		self.cfgCodecPtime = tk.IntVar(value=self.cfg.epConfig.medConfig.ptime)
+		self.cfgVad = tk.BooleanVar(value=not self.cfg.epConfig.medConfig.noVad)
+		self.cfgEcTailLen = tk.IntVar(value=self.cfg.epConfig.medConfig.ecTailLen)
+		
+		# Build the tab page
+		frm = ttk.Frame(self.frm)
+		frm.columnconfigure(0, weight=1)
+		frm.columnconfigure(1, weight=2)
+		row = 0
+		ttk.Label(frm, text='Max media ports:').grid(row=row, column=0, sticky=tk.E, pady=2, padx=8)
+		ttk.Label(frm, text=str(self.cfg.epConfig.medConfig.maxMediaPorts)).grid(row=row, column=1, sticky=tk.W, pady=2, padx=6)
+		row += 1
+		ttk.Label(frm, text='Core clock rate:').grid(row=row, column=0, sticky=tk.E, pady=2, padx=8)
+		tk.Spinbox(frm, from_=8000, to=48000, increment=8000, textvariable=self.cfgClockrate, width=5).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Label(frm, text='Snd device clock rate:').grid(row=row, column=0, sticky=tk.E, pady=2, padx=8)
+		tk.Spinbox(frm, from_=0, to=48000, increment=8000, textvariable=self.cfgSndClockrate, width=5).grid(row=row, column=1, sticky=tk.W, padx=6)
+		ttk.Label(frm, text='(0: follow core)').grid(row=row, column=1, sticky=tk.E, pady=6, padx=6)
+		row += 1
+		ttk.Label(frm, text='Core ptime:').grid(row=row, column=0, sticky=tk.E, pady=2, padx=8)
+		tk.Spinbox(frm, from_=10, to=400, increment=10, textvariable=self.cfgAudioPtime, width=3).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Label(frm, text='RTP ptime:').grid(row=row, column=0, sticky=tk.E, pady=2, padx=8)
+		tk.Spinbox(frm, from_=20, to=400, increment=10, textvariable=self.cfgCodecPtime, width=3).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Label(frm, text='Media quality (1-10):').grid(row=row, column=0, sticky=tk.E, pady=2, padx=8)
+		tk.Spinbox(frm, from_=1, to=10, textvariable=self.cfgMediaQuality, width=5).grid(row=row, column=1, sticky=tk.W, padx=6)
+		row += 1
+		ttk.Label(frm, text='VAD:').grid(row=row, column=0, sticky=tk.E, pady=2, padx=8)
+		ttk.Checkbutton(frm, text='Enable', variable=self.cfgVad).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+		row += 1
+		ttk.Label(frm, text='Echo canceller tail length:').grid(row=row, column=0, sticky=tk.E, pady=2, padx=8)
+		tk.Spinbox(frm, from_=0, to=400, increment=10, textvariable=self.cfgEcTailLen, width=3).grid(row=row, column=1, sticky=tk.W, padx=6)
+		ttk.Label(frm, text='(ms, 0 to disable)').grid(row=row, column=1, sticky=tk.E, pady=6, padx=6)
+		
+		self.wTab.add(frm, text='Media')
+
+	def onOk(self):
+		# Check basic settings
+		errors = "";
+		if errors:
+			msgbox.showerror("Error detected:", errors)
+			return
+		
+		# Basic settings
+		self.cfg.epConfig.logConfig.filename = self.cfgLogFile.get()
+		flags = pj.PJ_O_APPEND if self.cfgLogAppend.get() else 0
+		self.cfg.epConfig.logConfig.fileFlags = self.cfg.epConfig.logConfig.fileFlags | flags 
+		
+		# Network settings
+		self.cfg.epConfig.uaConfig.nameserver.clear()
+		if len(self.cfgNameserver.get()): 
+			self.cfg.epConfig.uaConfig.nameserver.append(self.cfgNameserver.get())
+		self.cfg.epConfig.uaConfig.stunServer.clear()
+		if len(self.cfgStunServer.get()):
+			self.cfg.epConfig.uaConfig.stunServer.append(self.cfgStunServer.get())
+			
+		self.cfg.epConfig.uaConfig.stunIgnoreFailure = self.cfgStunIgnoreError.get()
+		
+		self.cfg.udp.enabled 	= self.cfgUdpEnabled.get()
+		self.cfg.udp.config.port = self.cfgUdpPort.get()
+		self.cfg.tcp.enabled 	= self.cfgTcpEnabled.get()
+		self.cfg.tcp.config.port = self.cfgTcpPort.get()
+		self.cfg.tls.enabled 	= self.cfgTlsEnabled.get()
+		self.cfg.tls.config.port = self.cfgTlsPort.get()
+		
+		self.cfg.tls.config.tlsConfig.CaListFile = self.cfgTlsCaFile.get()
+		self.cfg.tls.config.tlsConfig.certFile   = self.cfgTlsCertFile.get()
+		self.cfg.tls.config.tlsConfig.verifyClient = self.cfgTlsVerifyClient.get()
+		self.cfg.tls.config.tlsConfig.verifyServer = self.cfgTlsVerifyServer.get()
+
+		# Media
+		self.cfg.epConfig.medConfig.clockRate	= self.cfgClockrate.get()
+		self.cfg.epConfig.medConfig.sndClockRate = self.cfgSndClockrate.get()
+		self.cfg.epConfig.medConfig.audioFramePtime = self.cfgAudioPtime.get()
+		self.cfg.epConfig.medConfig.quality	= self.cfgMediaQuality.get()
+		self.cfg.epConfig.medConfig.ptime	= self.cfgCodecPtime.get()
+		self.cfg.epConfig.medConfig.noVad	= not self.cfgVad.get()
+		self.cfg.epConfig.medConfig.ecTailLen	= self.cfgEcTailLen.get()
+		
+		self.isOk = True
+		self.destroy()
+		
+	def onCancel(self):
+		self.destroy()
+
+
+if __name__ == '__main__':
+	#application.main()
+	acfg = AppConfig()
+	acfg.loadFile('pygui.js')
+
+	dlg = Dialog(None, acfg)
+	if dlg.doModal():
+		acfg.saveFile('pygui.js')
+		
\ No newline at end of file
diff --git a/jni/pjproject-android/pjsip-apps/src/samples/debug.c b/jni/pjproject-android/pjsip-apps/src/samples/debug.cpp
similarity index 94%
rename from jni/pjproject-android/pjsip-apps/src/samples/debug.c
rename to jni/pjproject-android/pjsip-apps/src/samples/debug.cpp
index 1d38f9a..9928c7e 100644
--- a/jni/pjproject-android/pjsip-apps/src/samples/debug.c
+++ b/jni/pjproject-android/pjsip-apps/src/samples/debug.cpp
@@ -1,4 +1,4 @@
-/* $Id: debug.c 3553 2011-05-05 06:14:19Z nanang $ */
+/* $Id: debug.cpp 4704 2014-01-16 05:30:46Z ming $ */
 /* 
  * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
  * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
diff --git a/jni/pjproject-android/pjsip-apps/src/samples/pjsua2_demo.cpp b/jni/pjproject-android/pjsip-apps/src/samples/pjsua2_demo.cpp
new file mode 100644
index 0000000..26bb8ad
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/samples/pjsua2_demo.cpp
@@ -0,0 +1,323 @@
+/* $Id: pjsua2_demo.cpp 4708 2014-01-21 10:59:25Z nanang $ */
+/*
+ * Copyright (C) 2008-2013 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <pjsua2.hpp>
+#include <iostream>
+#include <memory>
+#include <pj/file_access.h>
+
+using namespace pj;
+
+class MyAccount;
+
+class MyCall : public Call
+{
+private:
+    MyAccount *myAcc;
+
+public:
+    MyCall(Account &acc, int call_id = PJSUA_INVALID_ID)
+    : Call(acc, call_id)
+    {
+        myAcc = (MyAccount *)&acc;
+    }
+    
+    virtual void onCallState(OnCallStateParam &prm);
+};
+
+class MyAccount : public Account
+{
+public:
+    std::vector<Call *> calls;
+    
+public:
+    MyAccount()
+    {}
+
+    ~MyAccount()
+    {
+        std::cout << "*** Account is being deleted: No of calls="
+                  << calls.size() << std::endl;
+    }
+    
+    void removeCall(Call *call)
+    {
+        for (std::vector<Call *>::iterator it = calls.begin();
+             it != calls.end(); ++it)
+        {
+            if (*it == call) {
+                calls.erase(it);
+                break;
+            }
+        }
+    }
+
+    virtual void onRegState(OnRegStateParam &prm)
+    {
+	AccountInfo ai = getInfo();
+	std::cout << (ai.regIsActive? "*** Register: code=" : "*** Unregister: code=")
+		  << prm.code << std::endl;
+    }
+    
+    virtual void onIncomingCall(OnIncomingCallParam &iprm)
+    {
+        Call *call = new MyCall(*this, iprm.callId);
+        CallInfo ci = call->getInfo();
+        CallOpParam prm;
+        
+        std::cout << "*** Incoming Call: " <<  ci.remoteUri << " ["
+                  << ci.stateText << "]" << std::endl;
+        
+        calls.push_back(call);
+        prm.statusCode = (pjsip_status_code)200;
+        call->answer(prm);
+    }
+};
+
+void MyCall::onCallState(OnCallStateParam &prm)
+{
+    PJ_UNUSED_ARG(prm);
+
+    CallInfo ci = getInfo();
+    std::cout << "*** Call: " <<  ci.remoteUri << " [" << ci.stateText
+              << "]" << std::endl;
+    
+    if (ci.state == PJSIP_INV_STATE_DISCONNECTED) {
+        myAcc->removeCall(this);
+        /* Delete the call */
+        delete this;
+    }
+}
+
+static void mainProg1() throw(Error)
+{
+    Endpoint ep;
+
+    // Create library
+    ep.libCreate();
+
+    // Init library
+    EpConfig ep_cfg;
+    ep_cfg.logConfig.level = 4;
+    ep.libInit( ep_cfg );
+
+    // Transport
+    TransportConfig tcfg;
+    tcfg.port = 5060;
+    ep.transportCreate(PJSIP_TRANSPORT_UDP, tcfg);
+
+    // Start library
+    ep.libStart();
+    std::cout << "*** PJSUA2 STARTED ***" << std::endl;
+
+    // Add account
+    AccountConfig acc_cfg;
+    acc_cfg.idUri = "sip:test1@pjsip.org";
+    acc_cfg.regConfig.registrarUri = "sip:pjsip.org";
+    acc_cfg.sipConfig.authCreds.push_back( AuthCredInfo("digest", "*",
+                                                        "test1", 0, "test1") );
+    std::auto_ptr<MyAccount> acc(new MyAccount);
+    acc->create(acc_cfg);
+    
+    pj_thread_sleep(2000);
+    
+    // Make outgoing call
+    Call *call = new MyCall(*acc);
+    acc->calls.push_back(call);
+    CallOpParam prm(true);
+    prm.opt.audioCount = 1;
+    prm.opt.videoCount = 0;
+    call->makeCall("sip:test1@pjsip.org", prm);
+    
+    // Hangup all calls
+    pj_thread_sleep(8000);
+    ep.hangupAllCalls();
+    pj_thread_sleep(4000);
+    
+    // Destroy library
+    std::cout << "*** PJSUA2 SHUTTING DOWN ***" << std::endl;
+}
+
+void mainProg2() throw(Error)
+{
+    Endpoint ep;
+
+    // Create library
+    ep.libCreate();
+
+    string json_str;
+
+    {
+	EpConfig epCfg;
+	JsonDocument jDoc;
+
+	epCfg.uaConfig.maxCalls = 61;
+	epCfg.uaConfig.userAgent = "Just JSON Test";
+	epCfg.uaConfig.stunServer.push_back("stun1.pjsip.org");
+	epCfg.uaConfig.stunServer.push_back("stun2.pjsip.org");
+	epCfg.logConfig.filename = "THE.LOG";
+
+	jDoc.writeObject(epCfg);
+	json_str = jDoc.saveString();
+	std::cout << json_str << std::endl << std::endl;
+    }
+
+    {
+	EpConfig epCfg;
+	JsonDocument rDoc;
+	string output;
+
+	rDoc.loadString(json_str);
+	rDoc.readObject(epCfg);
+
+	JsonDocument wDoc;
+
+	wDoc.writeObject(epCfg);
+	json_str = wDoc.saveString();
+	std::cout << json_str << std::endl << std::endl;
+
+	wDoc.saveFile("jsontest.js");
+    }
+
+    {
+	EpConfig epCfg;
+	JsonDocument rDoc;
+
+	rDoc.loadFile("jsontest.js");
+	rDoc.readObject(epCfg);
+	pj_file_delete("jsontest.js");
+    }
+
+    ep.libDestroy();
+}
+
+
+void mainProg3() throw(Error)
+{
+    Endpoint ep;
+
+    // Create library
+    ep.libCreate();
+
+    // Init library
+    EpConfig ep_cfg;
+    ep.libInit( ep_cfg );
+
+    // Start library
+    ep.libStart();
+    std::cout << "*** PJSUA2 STARTED ***" << std::endl;
+
+    // Create player and recorder
+    {
+	AudioMediaPlayer amp;
+	amp.createPlayer("../../tests/pjsua/wavs/input.16.wav");
+
+	AudioMediaRecorder amr;
+	amr.createRecorder("recorder_test_output.wav");
+
+	amp.startTransmit(ep.audDevManager().getPlaybackDevMedia());
+	amp.startTransmit(amr);
+
+	pj_thread_sleep(5000);
+    }
+
+    ep.libDestroy();
+}
+
+
+void mainProg() throw(Error)
+{
+    Endpoint ep;
+
+    // Create library
+    ep.libCreate();
+
+    string json_str;
+
+    {
+	JsonDocument jdoc;
+	AccountConfig accCfg;
+
+	accCfg.idUri = "\"Just Test\" <sip:test@pjsip.org>";
+	accCfg.regConfig.registrarUri = "sip:pjsip.org";
+	SipHeader h;
+	h.hName = "X-Header";
+	h.hValue = "User header";
+	accCfg.regConfig.headers.push_back(h);
+
+	accCfg.sipConfig.proxies.push_back("<sip:sip.pjsip.org;transport=tcp>");
+	accCfg.sipConfig.proxies.push_back("<sip:sip.pjsip.org;transport=tls>");
+
+	accCfg.mediaConfig.transportConfig.tlsConfig.ciphers.push_back(1);
+	accCfg.mediaConfig.transportConfig.tlsConfig.ciphers.push_back(2);
+	accCfg.mediaConfig.transportConfig.tlsConfig.ciphers.push_back(3);
+
+	AuthCredInfo aci;
+	aci.scheme = "digest";
+	aci.username = "test";
+	aci.data = "passwd";
+	aci.realm = "*";
+	accCfg.sipConfig.authCreds.push_back(aci);
+
+	jdoc.writeObject(accCfg);
+	json_str = jdoc.saveString();
+	std::cout << "Original:" << std::endl;
+	std::cout << json_str << std::endl << std::endl;
+    }
+
+    {
+	JsonDocument rdoc;
+
+	rdoc.loadString(json_str);
+	AccountConfig accCfg;
+	rdoc.readObject(accCfg);
+
+	JsonDocument wdoc;
+	wdoc.writeObject(accCfg);
+	json_str = wdoc.saveString();
+
+	std::cout << "Parsed:" << std::endl;
+	std::cout << json_str << std::endl << std::endl;
+    }
+
+    ep.libDestroy();
+}
+
+int main()
+{
+    int ret = 0;
+
+    /* Test endpoint instantiation and destruction without libCreate(),
+     * libInit() etc.
+     */
+    {
+	Endpoint ep;
+    }
+
+    try {
+	mainProg3();
+	std::cout << "Success" << std::endl;
+    } catch (Error & err) {
+	std::cout << "Exception: " << err.info() << std::endl;
+	ret = 1;
+    }
+
+    return ret;
+}
+
+
diff --git a/jni/pjproject-android/pjsip-apps/src/swig/Makefile b/jni/pjproject-android/pjsip-apps/src/swig/Makefile
new file mode 100644
index 0000000..815e0e1
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/Makefile
@@ -0,0 +1,32 @@
+include ../../../build.mak
+
+ifneq ($(findstring android,$(TARGET_NAME)),)
+  # no python for android
+  DIRS = java
+else
+  DIRS = python java
+endif
+
+export SWIG_FLAGS=-I../../../../pjlib/include \
+		   -I../../../../pjlib-util/include \
+		   -I../../../../pjmedia/include \
+		   -I../../../../pjsip/include \
+		   -I../../../../pjnath/include -c++ 
+export SRC_DIR=../../../../pjsip/include
+export SRCS=$(SRC_DIR)/pjsua2/endpoint.hpp $(SRC_DIR)/pjsua2/types.hpp
+
+.PHONY: all clean dep depend distclean print realclean install uninstall
+
+all: symbols.i
+
+all clean dep depend distclean print realclean install uninstall:
+	for dir in $(DIRS); do \
+		if $(MAKE) $(MAKE_FLAGS) -C $$dir $@; then \
+		    true; \
+		else \
+		    exit 1; \
+		fi; \
+	done
+
+symbols.i: symbols.lst
+	python importsym.py
diff --git a/jni/pjproject-android/pjsip-apps/src/swig/importsym.py b/jni/pjproject-android/pjsip-apps/src/swig/importsym.py
new file mode 100644
index 0000000..94377d8
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/importsym.py
@@ -0,0 +1,193 @@
+# $Id: importsym.py 4704 2014-01-16 05:30:46Z ming $
+#
+# importsym.py: Import C symbol decls (structs, enums, etc) and write them
+#               to another file 
+#
+# Copyright (C)2013 Teluu Inc. (http://www.teluu.com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+#
+import pycparser
+from pycparser import c_generator
+import sys
+import os
+
+def which(program):
+	import os
+	def is_exe(fpath):
+		return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
+	
+	if sys.platform == 'win32' and not program.endswith(".exe"):
+		program += ".exe"
+
+	fpath, fname = os.path.split(program)
+	if fpath:
+		if is_exe(program):
+			return program
+	else:
+		for path in os.environ["PATH"].split(os.pathsep):
+			path = path.strip('"')
+			exe_file = os.path.join(path, program)
+			if is_exe(exe_file):
+				return exe_file
+	return None
+
+#
+PJ_ROOT_PATH = "../../../"
+   
+# CPP is needed by pycparser.
+CPP_PATH = which("cpp")
+if not CPP_PATH:
+	print 'Error: need to have cpp in PATH'
+	sys.exit(1)
+
+# Hardcoded!
+if sys.platform == 'win32':
+	PYCPARSER_DIR="C:/devs/tools/pycparser"
+elif sys.platform == "linux2":
+	PYCPARSER_DIR="/home/bennylp/Desktop/opt/src/pycparser-master"
+else:
+	PYCPARSER_DIR="/Library/Python/2.7/site-packages/pycparser"
+
+if not os.path.exists(PYCPARSER_DIR + '/utils/fake_libc_include'):
+	print "Error: couldn't find pycparser utils in '%s'" % PYPARSER_DIR 
+	sys.exit(1)
+
+# Heading, to be placed before the source files
+C_HEADING_SECTION = """
+#define PJ_AUTOCONF		1
+#define jmp_buf			int
+#define __attribute__(x)
+"""
+
+# CPP (C preprocessor) settings
+CPP_CFLAGS   = [
+	'-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"
+	]
+
+
+class SymbolVisitor(pycparser.c_ast.NodeVisitor):
+	def __init__(self, names):
+		self.nodeDict = {}
+		for name in names:
+			self.nodeDict[name] = None
+		
+	def _add(self, node):
+		if self.nodeDict.has_key(node.name):
+			self.nodeDict[node.name] = node
+		
+	def visit_Struct(self, node):
+		self._add(node)
+		
+	def visit_Enum(self, node):
+		self._add(node)
+
+	def visit_Typename(self, node):
+		self._add(node)
+		
+	def visit_Typedef(self, node):
+		self._add(node)
+
+		
+TEMP_FILE="tmpsrc.h"
+		
+class SymbolImporter:
+	"""
+	Import C selected declarations from C source file and move it
+	to another file.
+	
+	Parameters:
+	 - listfile	Path of file containing list of C source file
+	                and identifier names to be imported. The format
+	                of the listfile is:
+	                
+	                filename        name1  name2  name3
+	                
+	                for example:
+	                
+	                pj/sock_qos.h	pj_qos_type  pj_qos_flag
+	                pj/types.h	pj_status_t  PJ_SUCCESS
+	"""
+	def __init__(self):
+		pass
+	
+	def process(self, listfile, outfile):
+		
+		# Read listfile
+		f = open(listfile)
+		lines = f.readlines()
+		f.close()
+		
+		# Process each line in list file, while generating the
+		# temporary C file to be processed by pycparser
+		f = open(TEMP_FILE, "w")
+		f.write(C_HEADING_SECTION)
+		names = []
+		fcnt = 0
+		for line in lines:
+			spec = line.split()
+			if len(spec) < 2:
+				continue
+			fcnt += 1
+			f.write("#include <%s>\n" % spec[0])
+			names.extend(spec[1:])
+		f.close()
+		print 'Parsing %d symbols from %d files..' % (len(names), fcnt)
+		
+		# Parse the temporary C file
+		ast = pycparser.parse_file(TEMP_FILE, use_cpp=True, cpp_path=CPP_PATH, cpp_args=CPP_CFLAGS)
+		os.remove(TEMP_FILE)
+		
+		# Filter the declarations that we wanted
+		print 'Filtering..'
+		visitor = SymbolVisitor(names)
+		visitor.visit(ast)
+	
+		# Print symbol declarations to outfile
+		print 'Writing declarations..'
+		f = open(outfile, 'w')
+		f.write("// This file is autogenerated by importsym script, do not modify!\n\n")
+		gen = pycparser.c_generator.CGenerator()
+		for name in names:
+			node = visitor.nodeDict[name]
+			if not node:
+				print "  ** Warning: declaration for '%s' is not found **" % k
+			else:
+				print "  writing '%s'.." % name
+				output = gen.visit(node) + ";\n\n"
+				f.write(output)
+		f.close()
+		print "Done."
+
+
+if __name__ == "__main__":
+	print "Importing symbols: 'symbols.lst' --> 'symbols.i'"
+	si = SymbolImporter()
+	si.process("symbols.lst", "symbols.i")
+	try:
+		os.remove("lextab.py")
+	except OSError:
+		pass
+	try:
+		os.remove("yacctab.py")
+	except OSError:
+		pass
+	
+	
\ No newline at end of file
diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/Makefile b/jni/pjproject-android/pjsip-apps/src/swig/java/Makefile
new file mode 100644
index 0000000..1946891
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/Makefile
@@ -0,0 +1,124 @@
+include ../../../../build.mak
+
+ifneq ($(findstring android,$(TARGET_NAME)),)
+ OS=android
+else
+ ifneq ($(findstring darwin,$(TARGET_NAME)),)
+  OS=darwin
+ endif
+endif
+
+OUT_DIR=output
+ifeq ($(OS),Windows_NT)
+  LIBPJSUA2_SO=$(OUT_DIR)/pjsua2.dll
+else
+  ifeq ($(OS),darwin)
+    LIBPJSUA2_SO=$(OUT_DIR)/libpjsua2.jnilib
+  else
+    ifeq ($(OS),android)
+      LIBPJSUA2_SO=android/libs/armeabi/libpjsua2.so
+    else
+      LIBPJSUA2_SO=$(OUT_DIR)/libpjsua2.so
+    endif
+  endif
+endif
+
+# 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))
+else
+  ifeq (exists, $(shell test -d $(JAVA_HOME)/bin && echo exists ))
+    JAVA_BIN := $(JAVA_HOME)/bin
+  else
+    JAVA_BIN := $(JAVA_HOME)
+  endif
+endif
+
+# OS specific
+ifeq ($(OS),Windows_NT)
+  MY_JNI_LDFLAGS	= -L$(MY_JDK)/lib -Wl,--kill-at
+else
+  MY_JNI_CFLAGS	 	= -fPIC
+  MY_JNI_LDFLAGS	= -L$(MY_JDK)/lib
+  ifeq ($(OS),darwin)
+    MY_JNI_LDFLAGS 	:= $(MY_JNI_LDFLAGS) -Wl,-soname,pjsua2.so
+  endif
+  ifeq ($(OS),android)
+    MY_JNI_CFLAGS	:= $(MY_JNI_CFLAGS) -D__ANDROID__
+  endif
+endif
+
+# Env settings, e.g: path to SWIG, JDK, java(.exe), javac(.exe)
+MY_SWIG		 = swig
+MY_JDK		 = $(JAVA_HOME)
+ifneq ($(findstring bin,$(JAVA_BIN)),)
+  MY_JAVA	 = $(MY_JDK)/bin/java
+  MY_JAVAC	 = $(MY_JDK)/bin/javac
+else
+  MY_JAVA	 = $(MY_JDK)/java
+  MY_JAVAC	 = $(MY_JDK)/javac
+endif
+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) -lpjsua2-$(TARGET_NAME) $(PJ_LDLIBS) $(MY_JNI_LDFLAGS)
+MY_PACKAGE_NAME	 = org.pjsip.pjsua2
+ifeq ($(OS),android)
+  MY_PACKAGE_PATH  = android/src/$(subst .,/,$(MY_PACKAGE_NAME))
+else
+  MY_PACKAGE_PATH  = $(OUT_DIR)/$(subst .,/,$(MY_PACKAGE_NAME))
+endif
+
+MY_APP_JAVA = android/src/$(subst .,/,$(MY_PACKAGE_NAME))/app/MyApp.java
+
+.PHONY: all java install uninstall
+
+all: $(LIBPJSUA2_SO) java
+
+$(LIBPJSUA2_SO): $(OUT_DIR)/pjsua2_wrap.o
+	$(PJ_CXX) -shared -o $(LIBPJSUA2_SO) $(OUT_DIR)/pjsua2_wrap.o $(MY_CFLAGS) $(MY_LDFLAGS)
+
+$(OUT_DIR)/pjsua2_wrap.o: $(OUT_DIR)/pjsua2_wrap.cpp Makefile
+	$(PJ_CXX) -c $(OUT_DIR)/pjsua2_wrap.cpp -o $(OUT_DIR)/pjsua2_wrap.o $(MY_CFLAGS) $(MY_LDFLAGS)
+
+$(OUT_DIR)/pjsua2_wrap.cpp: ../pjsua2.i ../symbols.i $(SRCS)
+	mkdir -p $(MY_PACKAGE_PATH)
+	swig $(SWIG_FLAGS) -java  -package $(MY_PACKAGE_NAME) -outdir $(MY_PACKAGE_PATH) -o $(OUT_DIR)/pjsua2_wrap.cpp ../pjsua2.i
+
+clean distclean realclean:
+	rm -rf $(LIBPJSUA2_SO) $(OUT_DIR)/* $(MY_PACKAGE_PATH)/*.java $(MY_PACKAGE_PATH)/*.class
+
+java: $(MY_PACKAGE_PATH)/Error.class $(MY_PACKAGE_PATH)/test.class $(MY_PACKAGE_PATH)/sample.class
+
+$(MY_PACKAGE_PATH)/Error.class: $(MY_PACKAGE_PATH)/Error.java
+	$(MY_JAVAC) -d $(OUT_DIR) $(MY_PACKAGE_PATH)/*.java $(MY_APP_JAVA)
+
+$(MY_PACKAGE_PATH)/test.class: test.java
+	$(MY_JAVAC) -d $(OUT_DIR) -classpath "$(OUT_DIR)" test.java
+	
+$(MY_PACKAGE_PATH)/sample.class: sample.java
+	$(MY_JAVAC) -d $(OUT_DIR) -classpath "$(OUT_DIR)" sample.java
+
+test:
+	@# Need to specify classpath and library path, alternatively, they can be set via
+	@# CLASSPATH and java.library.path env settings
+	$(MY_JAVA) -cp "$(OUT_DIR)" -Djava.library.path="$(OUT_DIR)" test
+	
+sample:
+	@# Need to specify classpath and library path, alternatively, they can be set via
+	@# CLASSPATH and java.library.path env settings
+	$(MY_JAVA) -cp "$(OUT_DIR)" -Djava.library.path="$(OUT_DIR)" org.pjsip.pjsua2.app.sample	
+
+install:
+uninstall:
+
diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/android/.settings/org.eclipse.jdt.core.prefs b/jni/pjproject-android/pjsip-apps/src/swig/java/android/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..48ab4c6
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/android/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,4 @@
+eclipse.preferences.version=1

+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6

+org.eclipse.jdt.core.compiler.compliance=1.6

+org.eclipse.jdt.core.compiler.source=1.6

diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/android/AndroidManifest.xml b/jni/pjproject-android/pjsip-apps/src/swig/java/android/AndroidManifest.xml
new file mode 100644
index 0000000..5a9b0ae
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/android/AndroidManifest.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="org.pjsip.pjsua2.app"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk
+        android:minSdkVersion="11"
+        android:targetSdkVersion="15" />
+
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.RECORD_AUDIO" />
+    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
+    <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
+    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <uses-permission android:name="android.permission.VIBRATE" />
+    <uses-permission android:name="android.permission.READ_LOGS" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+    <application
+        android:allowBackup="true"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" >
+        <activity
+            android:name="org.pjsip.pjsua2.app.MainActivity"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name="org.pjsip.pjsua2.app.CallActivity"
+            android:label="@string/title_activity_call" >
+        </activity>
+    </application>
+
+</manifest>
diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/android/ic_launcher-web.png b/jni/pjproject-android/pjsip-apps/src/swig/java/android/ic_launcher-web.png
new file mode 100644
index 0000000..a18cbb4
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/android/ic_launcher-web.png
Binary files differ
diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/android/jni/Android.mk b/jni/pjproject-android/pjsip-apps/src/swig/java/android/jni/Android.mk
new file mode 100644
index 0000000..94912ba
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/android/jni/Android.mk
@@ -0,0 +1,12 @@
+include ../../../../../build.mak
+
+LOCAL_PATH	:= $(PJDIR)/pjsip-apps/src/swig/java/android
+include $(CLEAR_VARS)
+
+LOCAL_MODULE    := libpjsua2
+LOCAL_CFLAGS    := $(APP_CFLAGS) -frtti -fexceptions
+LOCAL_LDFLAGS   := $(APP_LDFLAGS)
+LOCAL_LDLIBS    := $(APP_LDLIBS)
+LOCAL_SRC_FILES := ../output/pjsua2_wrap.cpp
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/android/jni/Application.mk b/jni/pjproject-android/pjsip-apps/src/swig/java/android/jni/Application.mk
new file mode 100644
index 0000000..87124dd
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/android/jni/Application.mk
@@ -0,0 +1 @@
+APP_STL := gnustl_static
diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/android/proguard-project.txt b/jni/pjproject-android/pjsip-apps/src/swig/java/android/proguard-project.txt
new file mode 100644
index 0000000..f2fe155
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/android/proguard-project.txt
@@ -0,0 +1,20 @@
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/android/project.properties b/jni/pjproject-android/pjsip-apps/src/swig/java/android/project.properties
new file mode 100644
index 0000000..0840b4a
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/android/project.properties
@@ -0,0 +1,14 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
+
+# Project target.
+target=android-15
diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/drawable-hdpi/ic_launcher.png b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..288b665
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/drawable-mdpi/ic_launcher.png b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..6ae570b
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/drawable-xhdpi/ic_launcher.png b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..d4fb7cd
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/drawable-xxhdpi/ic_launcher.png b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..85a6081
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/drawable/bkg.xml b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/drawable/bkg.xml
new file mode 100644
index 0000000..f505233
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/drawable/bkg.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" ?>

+<selector xmlns:android="http://schemas.android.com/apk/res/android">

+    <item android:state_pressed="true" android:drawable="@color/pressed_color" />

+    <item android:drawable="@color/default_color" />

+</selector>
\ No newline at end of file
diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/layout/activity_call.xml b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/layout/activity_call.xml
new file mode 100644
index 0000000..3745eb3
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/layout/activity_call.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>

+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

+    android:layout_width="match_parent"

+    android:layout_height="match_parent"

+    android:gravity="center"

+    android:paddingBottom="@dimen/activity_vertical_margin"

+    android:paddingLeft="@dimen/activity_horizontal_margin"

+    android:paddingRight="@dimen/activity_horizontal_margin"

+    android:paddingTop="@dimen/activity_vertical_margin"

+    android:orientation="vertical" >

+

+    <TextView

+        android:id="@+id/textViewPeer"

+        android:layout_width="match_parent"

+        android:layout_height="wrap_content"

+        android:gravity="center_horizontal"

+        android:text="Peer URI"

+        android:textAppearance="?android:attr/textAppearanceLarge" />

+

+    <TextView

+        android:id="@+id/textViewCallState"

+        android:layout_width="match_parent"

+        android:layout_height="wrap_content"

+        android:gravity="center"

+        android:text="Call state" />

+

+    <Button

+        android:id="@+id/buttonAccept"

+        android:layout_width="match_parent"

+        android:layout_height="wrap_content"

+        android:onClick="acceptCall"

+        android:text="Accept" />

+

+    <Button

+        android:id="@+id/buttonHangup"

+        android:layout_width="match_parent"

+        android:layout_height="wrap_content"

+        android:onClick="hangupCall"

+        android:text="Reject" />

+

+</LinearLayout>
\ No newline at end of file
diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/layout/activity_main.xml b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/layout/activity_main.xml
new file mode 100644
index 0000000..c63c021
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/layout/activity_main.xml
@@ -0,0 +1,65 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

+    xmlns:tools="http://schemas.android.com/tools"

+    android:layout_width="match_parent"

+    android:layout_height="match_parent"

+    android:orientation="vertical"

+    android:paddingBottom="@dimen/activity_vertical_margin"

+    android:paddingLeft="@dimen/activity_horizontal_margin"

+    android:paddingRight="@dimen/activity_horizontal_margin"

+    android:paddingTop="@dimen/activity_vertical_margin"

+    tools:context=".MainActivity" >

+

+    <ListView

+        android:id="@+id/listViewBuddy"

+        android:layout_width="match_parent"

+        android:layout_height="match_parent"

+        android:layout_weight="1"

+    	android:listSelector="@drawable/bkg" >

+    </ListView>

+

+    <LinearLayout

+        android:layout_width="match_parent"

+        android:layout_height="wrap_content"

+        android:orientation="horizontal" >

+

+        <ImageButton

+            android:id="@+id/buttonCall"

+            android:layout_width="wrap_content"

+            android:layout_height="wrap_content"

+            android:layout_weight="1"

+            android:onClick="makeCall"

+            android:src="@android:drawable/ic_menu_call" />

+

+        <TextView

+            android:layout_width="wrap_content"

+            android:layout_height="match_parent"

+            android:layout_weight="1"

+			android:text="   "/>

+

+        <ImageButton

+            android:id="@+id/buttonAddBuddy"

+            android:layout_width="wrap_content"

+            android:layout_height="wrap_content"

+            android:layout_weight="1"

+            android:onClick="addBuddy"

+            android:src="@android:drawable/ic_menu_add" />

+        

+        <ImageButton

+            android:id="@+id/buttonEditBuddy"

+            android:layout_width="wrap_content"

+            android:layout_height="wrap_content"

+            android:layout_weight="1"

+            android:onClick="editBuddy"

+            android:src="@android:drawable/ic_menu_edit" />

+        

+        <ImageButton

+            android:id="@+id/buttonDelBuddy"

+            android:layout_width="wrap_content"

+            android:layout_height="wrap_content"

+            android:layout_weight="1"

+            android:onClick="delBuddy"

+            android:src="@android:drawable/ic_menu_delete" />

+

+        </LinearLayout>

+

+</LinearLayout>
\ No newline at end of file
diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/layout/dlg_account_config.xml b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/layout/dlg_account_config.xml
new file mode 100644
index 0000000..71111f1
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/layout/dlg_account_config.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>

+<TableLayout

+    xmlns:android="http://schemas.android.com/apk/res/android"

+    android:padding = "20dp"

+    android:layout_width="match_parent"

+    android:layout_height="match_parent">

+

+    <TextView

+        android:id="@+id/textViewInfo"

+        android:textAppearance="?android:attr/textAppearanceSmall"

+    	android:paddingBottom="20dp"

+        android:textColor="#b0b0b0" >

+    </TextView>

+    

+	<TableRow>

+        <TextView android:text="ID">

+        </TextView>  

+

+	    <EditText

+	        android:id="@+id/editTextId"

+	        android:layout_width="match_parent"

+	        android:layout_height="wrap_content"

+	        android:layout_weight="1"

+	        android:inputType="textUri" >

+

+	        <requestFocus />

+	    </EditText>

+    </TableRow>

+	<TableRow>

+        <TextView android:text="Registrar">

+        </TextView>  

+	    <EditText

+	        android:id="@+id/editTextRegistrar"

+	        android:layout_width="match_parent"

+	        android:layout_height="wrap_content"

+	        android:layout_weight="1"

+	        android:inputType="textUri" >

+	    </EditText>

+    </TableRow>

+	<TableRow>

+        <TextView android:text="Proxy">

+        </TextView>  

+	    <EditText

+	        android:id="@+id/editTextProxy"

+	        android:layout_width="match_parent"

+	        android:layout_height="wrap_content"

+	        android:layout_weight="1"

+	        android:inputType="textUri" >

+	    </EditText>

+    </TableRow>

+	<TableRow>

+        <TextView android:text="Username">

+        </TextView>  

+

+	    <EditText

+	        android:id="@+id/editTextUsername"

+	        android:layout_width="match_parent"

+	        android:layout_height="wrap_content"

+	        android:layout_weight="1"

+	        android:inputType="text" >

+

+	    </EditText>

+    </TableRow>

+	<TableRow>

+        <TextView android:text="Password">

+        </TextView>  

+

+	    <EditText

+	        android:id="@+id/editTextPassword"

+	        android:layout_width="match_parent"

+	        android:layout_height="wrap_content"

+	        android:layout_weight="1"

+	        android:inputType="textPassword" >

+

+	    </EditText>

+    </TableRow>

+</TableLayout>

diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/layout/dlg_add_buddy.xml b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/layout/dlg_add_buddy.xml
new file mode 100644
index 0000000..f13e700
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/layout/dlg_add_buddy.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>

+<TableLayout

+    xmlns:android="http://schemas.android.com/apk/res/android"

+    android:padding = "20dp"

+    android:layout_width="match_parent"

+    android:layout_height="match_parent">

+	<TableRow>

+        <TextView android:text="Buddy URI">

+        </TextView>  

+

+	    <EditText

+	        android:id="@+id/editTextUri"

+	        android:layout_weight="1"

+	        android:inputType="textUri" >

+	        <requestFocus />

+	    </EditText>

+    </TableRow>

+	<TableRow>

+        <CheckBox

+            android:id="@+id/checkBoxSubscribe"

+            android:layout_column="1"

+            android:text="Subscribe presence" />

+    </TableRow>

+</TableLayout>

diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/menu/call.xml b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/menu/call.xml
new file mode 100644
index 0000000..d122a4b
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/menu/call.xml
@@ -0,0 +1,9 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >

+

+    <item

+        android:id="@+id/action_settings"

+        android:orderInCategory="100"

+        android:showAsAction="never"

+        android:title="@string/action_settings"/>

+

+</menu>

diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/menu/main.xml b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/menu/main.xml
new file mode 100644
index 0000000..be94829
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/menu/main.xml
@@ -0,0 +1,14 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >

+

+    <item

+        android:id="@+id/action_acc_config"

+        android:icon="@android:drawable/ic_menu_manage"

+        android:showAsAction="ifRoom"

+        android:title="Account Config"/>

+    <item

+        android:id="@+id/action_quit"

+        android:icon="@android:drawable/ic_menu_close_clear_cancel"

+        android:showAsAction="ifRoom"

+        android:title="Quit"/>

+    

+</menu>

diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/values-sw600dp/dimens.xml b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..c876987
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/values-sw600dp/dimens.xml
@@ -0,0 +1,8 @@
+<resources>

+

+    <!--

+         Customize dimensions originally defined in res/values/dimens.xml (such as
+         screen margins) for sw600dp devices (e.g. 7" tablets) here.

+    -->

+

+</resources>

diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/values-sw720dp-land/dimens.xml b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/values-sw720dp-land/dimens.xml
new file mode 100644
index 0000000..0df3067
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/values-sw720dp-land/dimens.xml
@@ -0,0 +1,9 @@
+<resources>

+

+    <!--

+         Customize dimensions originally defined in res/values/dimens.xml (such as
+         screen margins) for sw720dp devices (e.g. 10" tablets) in landscape here.

+    -->

+    <dimen name="activity_horizontal_margin">128dp</dimen>

+

+</resources>

diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/values-v11/styles.xml b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/values-v11/styles.xml
new file mode 100644
index 0000000..e3ef53d
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/values-v11/styles.xml
@@ -0,0 +1,11 @@
+<resources>

+

+    <!--

+        Base application theme for API 11+. This theme completely replaces
+        AppBaseTheme from res/values/styles.xml on API 11+ devices.

+    -->

+    <style name="AppBaseTheme" parent="android:Theme.Holo.Light">

+        <!-- API 11 theme customizations can go here. -->

+    </style>

+

+</resources>

diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/values-v14/styles.xml b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/values-v14/styles.xml
new file mode 100644
index 0000000..94dd245
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/values-v14/styles.xml
@@ -0,0 +1,12 @@
+<resources>

+

+    <!--

+        Base application theme for API 14+. This theme completely replaces
+        AppBaseTheme from BOTH res/values/styles.xml and
+        res/values-v11/styles.xml on API 14+ devices.

+    -->

+    <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">

+        <!-- API 14 theme customizations can go here. -->

+    </style>

+

+</resources>

diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/values/colors.xml b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/values/colors.xml
new file mode 100644
index 0000000..9ce61cf
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/values/colors.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>

+<resources>

+    <color name="pressed_color">#B8F2F5</color>

+    <color name="default_color">#E8FEFF</color>

+</resources>
\ No newline at end of file
diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/values/dimens.xml b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/values/dimens.xml
new file mode 100644
index 0000000..2e0e2ae
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/values/dimens.xml
@@ -0,0 +1,7 @@
+<resources>

+

+    <!-- Default screen margins, per the Android Design guidelines. -->

+    <dimen name="activity_horizontal_margin">16dp</dimen>

+    <dimen name="activity_vertical_margin">16dp</dimen>

+

+</resources>

diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/values/strings.xml b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/values/strings.xml
new file mode 100644
index 0000000..2ee52b6
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/values/strings.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>

+<resources>

+

+    <string name="app_name">Pjsua2</string>

+    <string name="action_settings">Settings</string>

+    <string name="title_activity_call">Call</string>

+    <string name="hello_world">Hello world!</string>

+

+</resources>

diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/values/styles.xml b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/values/styles.xml
new file mode 100644
index 0000000..4ea9326
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/android/res/values/styles.xml
@@ -0,0 +1,20 @@
+<resources>

+

+    <!--

+        Base application theme, dependent on API level. This theme is replaced
+        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.

+    -->

+    <style name="AppBaseTheme" parent="android:Theme.Light">

+        <!--

+            Theme customizations available in newer API levels can go in
+            res/values-vXX/styles.xml, while customizations related to
+            backward-compatibility can go here.

+        -->

+    </style>

+

+    <!-- Application theme. -->

+    <style name="AppTheme" parent="AppBaseTheme">

+        <!-- All customizations that are NOT specific to a particular API-level can go here. -->

+    </style>

+

+</resources>

diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/CallActivity.java b/jni/pjproject-android/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/CallActivity.java
new file mode 100644
index 0000000..ea2d89e
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/CallActivity.java
@@ -0,0 +1,146 @@
+/* $Id: CallActivity.java 4704 2014-01-16 05:30:46Z ming $ */
+/*
+ * Copyright (C) 2013 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package org.pjsip.pjsua2.app;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+import android.app.Activity;
+
+import org.pjsip.pjsua2.*;
+
+public class CallActivity extends Activity implements Handler.Callback {
+	
+	public static Handler handler_;
+
+	private final Handler handler = new Handler(this);
+	private static CallInfo lastCallInfo;
+
+	@Override
+	protected void onCreate(Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+		setContentView(R.layout.activity_call);
+		
+		handler_ = handler;
+		if (MainActivity.currentCall != null) {
+			try {
+				lastCallInfo = MainActivity.currentCall.getInfo();
+				updateCallState(lastCallInfo);
+			} catch (Exception e) {
+				System.out.println(e);
+			}
+		} else {
+			updateCallState(lastCallInfo);
+		}
+	}
+
+    @Override
+    protected void onDestroy() {
+    	super.onDestroy();
+    	handler_ = null;
+    }
+	
+	public void acceptCall(View view) {
+		CallOpParam prm = new CallOpParam();
+		prm.setStatusCode(pjsip_status_code.PJSIP_SC_OK);
+		try {
+			MainActivity.currentCall.answer(prm);
+		} catch (Exception e) {
+			System.out.println(e);
+		}
+		
+		view.setVisibility(View.GONE);
+	}
+
+	public void hangupCall(View view) {
+		handler_ = null;
+		finish();
+		
+		if (MainActivity.currentCall != null) {
+			CallOpParam prm = new CallOpParam();
+			prm.setStatusCode(pjsip_status_code.PJSIP_SC_DECLINE);
+			try {
+				MainActivity.currentCall.hangup(prm);
+			} catch (Exception e) {
+				System.out.println(e);
+			}
+
+			MainActivity.currentCall = null;
+		}
+	}
+	
+	@Override
+	public boolean handleMessage(Message m) {
+		
+		if (m.what == MainActivity.MSG_TYPE.CALL_STATE) {
+			
+			lastCallInfo = (CallInfo) m.obj;
+			updateCallState(lastCallInfo);
+			
+		} else {
+			
+			/* Message not handled */
+			return false;
+			
+		}
+			
+		return true;
+	}
+	
+	private void updateCallState(CallInfo ci) {
+		TextView tvPeer  = (TextView) findViewById(R.id.textViewPeer);
+		TextView tvState = (TextView) findViewById(R.id.textViewCallState);
+		Button buttonHangup = (Button) findViewById(R.id.buttonHangup);
+		Button buttonAccept = (Button) findViewById(R.id.buttonAccept);
+		String call_state = "";
+		
+		if (ci.getRole() == pjsip_role_e.PJSIP_ROLE_UAC) {
+			buttonAccept.setVisibility(View.GONE);
+		}
+				
+		if (ci.getState().swigValue() < pjsip_inv_state.PJSIP_INV_STATE_CONFIRMED.swigValue())
+		{
+			if (ci.getRole() == pjsip_role_e.PJSIP_ROLE_UAS) {
+				call_state = "Incoming call..";
+				/* Default button texts are already 'Accept' & 'Reject' */
+			} else {
+				buttonHangup.setText("Cancel");
+				call_state = ci.getStateText();
+			}
+		}
+		else if (ci.getState().swigValue() >= pjsip_inv_state.PJSIP_INV_STATE_CONFIRMED.swigValue())
+		{
+			buttonAccept.setVisibility(View.GONE);
+			call_state = ci.getStateText();
+			if (ci.getState() == pjsip_inv_state.PJSIP_INV_STATE_CONFIRMED) {
+				buttonHangup.setText("Hangup");
+			} else if (ci.getState() == pjsip_inv_state.PJSIP_INV_STATE_DISCONNECTED) {
+				buttonHangup.setText("OK");
+				call_state = "Call disconnected: " + ci.getLastReason();
+				MainActivity.currentCall = null;
+			}
+		}
+		
+		tvPeer.setText(ci.getRemoteUri());
+		tvState.setText(call_state);
+	}
+}
diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MainActivity.java b/jni/pjproject-android/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MainActivity.java
new file mode 100644
index 0000000..01806d9
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MainActivity.java
@@ -0,0 +1,497 @@
+/* $Id: MainActivity.java 4704 2014-01-16 05:30:46Z ming $ */
+/*
+ * Copyright (C) 2013 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package org.pjsip.pjsua2.app;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.CheckBox;
+import android.widget.EditText;
+import android.widget.ListView;
+import android.widget.SimpleAdapter;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.pjsip.pjsua2.*;
+
+public class MainActivity extends Activity implements Handler.Callback, MyAppObserver {
+	public static MyApp app = null;
+	public static MyCall currentCall = null;
+	public static MyAccount account = null;
+	public static AccountConfig accCfg = null;
+	
+	private ListView buddyListView;
+	private SimpleAdapter buddyListAdapter;
+	private int buddyListSelectedIdx = -1;
+    ArrayList<Map<String, String>> buddyList;
+    private String lastRegStatus = "";
+
+	private final Handler handler = new Handler(this);
+	public class MSG_TYPE {
+		public final static int INCOMING_CALL = 1;
+		public final static int CALL_STATE = 2;
+		public final static int REG_STATE = 3;
+		public final static int BUDDY_STATE = 4;
+	}
+
+	private HashMap<String, String> putData(String uri, String status) {
+		HashMap<String, String> item = new HashMap<String, String>();
+		item.put("uri", uri);
+		item.put("status", status);
+		return item;
+	}
+	
+	private void showCallActivity() {
+        Intent intent = new Intent(this, CallActivity.class);
+        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+        startActivity(intent);
+	}
+
+	@Override
+	protected void onCreate(Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+		setContentView(R.layout.activity_main);
+		
+		if (app == null) {
+			app = new MyApp();
+			/* Wait for GDB to init */
+			if ((getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+				try {
+					Thread.sleep(5000);
+				} catch (InterruptedException e) {}
+			}
+			
+		    app.init(this, getFilesDir().getAbsolutePath());
+		}
+		
+	    if (app.accList.size() == 0) {
+	    	accCfg = new AccountConfig();
+	    	accCfg.setIdUri("sip:localhost");
+	    	account = app.addAcc(accCfg);
+	    } else {
+	    	account = app.accList.get(0);
+	    	accCfg = account.cfg;
+	    }
+	    
+		buddyList = new ArrayList<Map<String, String>>();
+		for (int i = 0; i < account.buddyList.size(); i++) {
+			buddyList.add(putData(account.buddyList.get(i).cfg.getUri(),
+								  account.buddyList.get(i).getStatusText()));
+		}
+
+		String[] from = { "uri", "status" };
+	    int[] to = { android.R.id.text1, android.R.id.text2 };
+	    buddyListAdapter = new SimpleAdapter(this, buddyList, android.R.layout.simple_list_item_2, from, to);
+	    
+		buddyListView = (ListView) findViewById(R.id.listViewBuddy);;
+	    buddyListView.setAdapter(buddyListAdapter);
+	    buddyListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+	    	@Override
+	    	public void onItemClick(AdapterView<?> parent, final View view,
+	    			int position, long id) 
+	    	{
+	    		view.setSelected(true);
+	    		buddyListSelectedIdx = position;
+	    	}
+	    });
+	    
+	}
+
+	@Override
+	public boolean onCreateOptionsMenu(Menu menu) {
+		// Inflate the menu; this adds items to the action bar if it is present.
+		getMenuInflater().inflate(R.menu.main, menu);
+		return true;
+	}
+
+	@Override
+	public boolean onOptionsItemSelected(MenuItem item) {
+		switch (item.getItemId()) {
+		case R.id.action_acc_config:
+			dlgAccountSetting();
+			break;
+
+		case R.id.action_quit:
+			Message m = Message.obtain(handler, 0);
+			m.sendToTarget();
+			break;
+			
+		default:
+			break;
+		}
+
+		return true;
+	} 	
+
+	@Override
+	public boolean handleMessage(Message m) {
+		
+		if (m.what == 0) {
+			
+			app.deinit();
+			finish();
+			Runtime.getRuntime().gc();
+			android.os.Process.killProcess(android.os.Process.myPid());
+			
+		} else if (m.what == MSG_TYPE.CALL_STATE) {
+			
+			CallInfo ci = (CallInfo) m.obj;
+			
+			/* Forward the message to CallActivity */
+			if (CallActivity.handler_ != null) {
+				Message m2 = Message.obtain(CallActivity.handler_, MSG_TYPE.CALL_STATE, ci);
+				m2.sendToTarget();
+			}
+			
+			if (ci.getState() == pjsip_inv_state.PJSIP_INV_STATE_DISCONNECTED)
+				currentCall = null;
+			
+		} else if (m.what == MSG_TYPE.BUDDY_STATE) {
+			
+			MyBuddy buddy = (MyBuddy) m.obj;
+			int idx = account.buddyList.indexOf(buddy);
+			if (idx >= 0) {
+				buddyList.get(idx).put("status", buddy.getStatusText());
+				buddyListAdapter.notifyDataSetChanged();
+				// TODO: selection color/mark is gone after this,
+				//       dont know how to return it back.
+				//buddyListView.setSelection(buddyListSelectedIdx);
+				//buddyListView.performItemClick(buddyListView, buddyListSelectedIdx,
+				//							   buddyListView.getItemIdAtPosition(buddyListSelectedIdx));
+				
+				/* Return back Call activity */
+				notifyCallState(currentCall);
+			}
+			
+		} else if (m.what == MSG_TYPE.REG_STATE) {
+			
+			String msg_str = (String) m.obj;
+			lastRegStatus = msg_str;
+			
+		} else if (m.what == MSG_TYPE.INCOMING_CALL) {
+			
+			/* Incoming call */
+			final MyCall call = (MyCall) m.obj;
+			CallOpParam prm = new CallOpParam();
+			
+			/* Only one call at anytime */
+			if (currentCall != null) {
+				prm.setStatusCode(pjsip_status_code.PJSIP_SC_BUSY_HERE);
+				try {
+					call.hangup(prm);
+				} catch (Exception e) {}
+				return true;
+			}
+
+			/* Answer with ringing */
+			prm.setStatusCode(pjsip_status_code.PJSIP_SC_RINGING);
+			try {
+				call.answer(prm);
+			} catch (Exception e) {}
+			
+			currentCall = call;
+			showCallActivity();
+
+		} else {
+			
+			/* Message not handled */
+			return false;
+			
+		}
+			
+		return true;
+	}
+	
+
+	private void dlgAccountSetting() {
+		
+		LayoutInflater li = LayoutInflater.from(this);
+		View view = li.inflate(R.layout.dlg_account_config, null);
+		
+		if (!lastRegStatus.isEmpty()) {
+			TextView tvInfo = (TextView)view.findViewById(R.id.textViewInfo);
+			tvInfo.setText("Last status: " + lastRegStatus);
+		}
+
+		AlertDialog.Builder adb = new AlertDialog.Builder(this);
+		adb.setView(view);
+		adb.setTitle("Account Settings");
+
+		final EditText etId    = (EditText)view.findViewById(R.id.editTextId);
+		final EditText etReg   = (EditText)view.findViewById(R.id.editTextRegistrar);
+		final EditText etProxy = (EditText)view.findViewById(R.id.editTextProxy);
+		final EditText etUser  = (EditText)view.findViewById(R.id.editTextUsername);
+		final EditText etPass  = (EditText)view.findViewById(R.id.editTextPassword);
+		
+		etId.   setText(accCfg.getIdUri());
+		etReg.  setText(accCfg.getRegConfig().getRegistrarUri());
+		StringVector proxies = accCfg.getSipConfig().getProxies();
+		if (proxies.size() > 0)
+			etProxy.setText(proxies.get(0));
+		else
+			etProxy.setText("");
+		AuthCredInfoVector creds = accCfg.getSipConfig().getAuthCreds();
+		if (creds.size() > 0) {
+			etUser. setText(creds.get(0).getUsername());
+			etPass. setText(creds.get(0).getData());
+		} else {
+			etUser. setText("");
+			etPass. setText("");
+		}
+		
+		adb.setCancelable(false);
+		adb.setPositiveButton("OK",
+			  new DialogInterface.OnClickListener() {
+			    public void onClick(DialogInterface dialog,int id) {
+			    	String acc_id 	 = etId.getText().toString();
+			    	String registrar = etReg.getText().toString();
+			    	String proxy 	 = etProxy.getText().toString();
+			    	String username  = etUser.getText().toString();
+			    	String password  = etPass.getText().toString();
+			    	
+			    	accCfg.setIdUri(acc_id);
+			    	accCfg.getRegConfig().setRegistrarUri(registrar);
+					AuthCredInfoVector creds = accCfg.getSipConfig().getAuthCreds();
+					creds.clear();
+					if (!username.isEmpty()) {
+						creds.add(new AuthCredInfo("Digest", "*", username, 0, password));
+					}
+					StringVector proxies = accCfg.getSipConfig().getProxies();
+					proxies.clear();
+					if (!proxy.isEmpty()) {
+						proxies.add(proxy);
+					}
+					
+					/* Finally */
+					lastRegStatus = "";
+					try {
+						account.modify(accCfg);
+					} catch (Exception e) {}
+			    }
+			  });
+		adb.setNegativeButton("Cancel",
+			  new DialogInterface.OnClickListener() {
+			    public void onClick(DialogInterface dialog,int id) {
+				dialog.cancel();
+			    }
+			  });
+
+		AlertDialog ad = adb.create();
+		ad.show();
+	}
+	
+	
+	public void makeCall(View view) {
+		if (buddyListSelectedIdx == -1)
+			return;
+		
+		/* Only one call at anytime */
+		if (currentCall != null) {
+			return;
+		}
+		
+		HashMap<String, String> item = (HashMap<String, String>) buddyListView.getItemAtPosition(buddyListSelectedIdx);
+		String buddy_uri = item.get("uri");
+		
+		MyCall call = new MyCall(account, -1);
+		CallOpParam prm = new CallOpParam();
+		CallSetting opt = prm.getOpt();
+		opt.setAudioCount(1);
+		opt.setVideoCount(0);
+
+		try {
+			call.makeCall(buddy_uri, prm);
+		} catch (Exception e) {
+			currentCall = null;
+			return;
+		}
+		
+		currentCall = call;
+		showCallActivity();
+	}
+
+	private void dlgAddEditBuddy(BuddyConfig initial) {
+		final BuddyConfig cfg = new BuddyConfig();
+		final BuddyConfig old_cfg = initial;
+		final boolean is_add = initial == null;
+		
+		LayoutInflater li = LayoutInflater.from(this);
+		View view = li.inflate(R.layout.dlg_add_buddy, null);
+
+		AlertDialog.Builder adb = new AlertDialog.Builder(this);
+		adb.setView(view);
+
+		final EditText etUri    = (EditText)view.findViewById(R.id.editTextUri);
+		final CheckBox cbSubs  = (CheckBox)view.findViewById(R.id.checkBoxSubscribe);
+
+		if (is_add) {
+			adb.setTitle("Add Buddy");
+		} else {
+			adb.setTitle("Edit Buddy");
+			etUri. setText(initial.getUri());
+			cbSubs.setChecked(initial.getSubscribe());
+		}
+
+		adb.setCancelable(false);
+		adb.setPositiveButton("OK",
+			  new DialogInterface.OnClickListener() {
+			    public void onClick(DialogInterface dialog,int id) {
+			    	cfg.setUri(etUri.getText().toString());
+			    	cfg.setSubscribe(cbSubs.isChecked());
+			    	
+			    	if (is_add) {
+			    		account.addBuddy(cfg);
+						buddyList.add(putData(cfg.getUri(), ""));
+						buddyListAdapter.notifyDataSetChanged();
+						buddyListSelectedIdx = -1;
+			    	} else {
+			    		if (!old_cfg.getUri().equals(cfg.getUri())) {
+			    			account.delBuddy(buddyListSelectedIdx);
+			    			account.addBuddy(cfg);
+							buddyList.remove(buddyListSelectedIdx);
+							buddyList.add(putData(cfg.getUri(), ""));
+			    			buddyListAdapter.notifyDataSetChanged();
+			    			buddyListSelectedIdx = -1;
+			    		} else if (old_cfg.getSubscribe() != cfg.getSubscribe()) {
+			    			MyBuddy bud = account.buddyList.get(buddyListSelectedIdx);
+							try {
+				    			bud.subscribePresence(cfg.getSubscribe());
+							} catch (Exception e) {}
+			    		}
+			    	}
+			    }
+			  });
+		adb.setNegativeButton("Cancel",
+			  new DialogInterface.OnClickListener() {
+			    public void onClick(DialogInterface dialog,int id) {
+				dialog.cancel();
+			    }
+			  });
+
+		AlertDialog ad = adb.create();
+		ad.show();
+	}
+	
+	public void addBuddy(View view) {
+		dlgAddEditBuddy(null);
+	}
+
+	public void editBuddy(View view) {
+		if (buddyListSelectedIdx == -1)
+			return;
+		
+		BuddyConfig old_cfg = account.buddyList.get(buddyListSelectedIdx).cfg;
+		dlgAddEditBuddy(old_cfg);
+	}
+	
+	public void delBuddy(View view) {
+		if (buddyListSelectedIdx == -1)
+			return;
+		
+		final HashMap<String, String> item = (HashMap<String, String>) buddyListView.getItemAtPosition(buddyListSelectedIdx);
+		String buddy_uri = item.get("uri");
+		
+		DialogInterface.OnClickListener ocl = new DialogInterface.OnClickListener() {
+		    @Override
+		    public void onClick(DialogInterface dialog, int which) {
+		        switch (which) {
+		        case DialogInterface.BUTTON_POSITIVE:
+		        	account.delBuddy(buddyListSelectedIdx);
+		    		buddyList.remove(item);
+		    		buddyListAdapter.notifyDataSetChanged();
+		    		buddyListSelectedIdx = -1;
+		            break;
+		        case DialogInterface.BUTTON_NEGATIVE:
+		            break;
+		        }
+		    }
+		};
+
+		AlertDialog.Builder adb = new AlertDialog.Builder(this);
+		adb.setTitle(buddy_uri);
+		adb.setMessage("\nDelete this buddy?\n");
+		adb.setPositiveButton("Yes", ocl);
+		adb.setNegativeButton("No", ocl);
+		adb.show();
+	}
+	
+	
+	/*
+	 * === MyAppObserver ===
+	 * 
+	 * As we cannot do UI from worker thread, the callbacks mostly just send
+	 * a message to UI/main thread.
+	 */
+	
+	public void notifyIncomingCall(MyCall call) {
+		Message m = Message.obtain(handler, MSG_TYPE.INCOMING_CALL, call);
+		m.sendToTarget();
+	}
+
+	public void notifyRegState(pjsip_status_code code, String reason, int expiration) {
+		String msg_str = "";
+		if (expiration == 0)
+			msg_str += "Unregistration";
+		else
+			msg_str += "Registration";
+		
+		if (code.swigValue()/100 == 2)
+			msg_str += " successful";
+		else
+			msg_str += " failed: " + reason;
+		
+		Message m = Message.obtain(handler, MSG_TYPE.REG_STATE, msg_str);
+		m.sendToTarget();
+	}
+	
+	public void notifyCallState(MyCall call) {
+		if (currentCall == null || call.getId() != currentCall.getId())
+			return;
+		
+		CallInfo ci;
+		try {
+			ci = call.getInfo();
+		} catch (Exception e) {
+			ci = null;
+		}
+		Message m = Message.obtain(handler, MSG_TYPE.CALL_STATE, ci);
+		m.sendToTarget();
+	}
+	
+	public void notifyBuddyState(MyBuddy buddy) {
+		Message m = Message.obtain(handler, MSG_TYPE.BUDDY_STATE, buddy);
+		m.sendToTarget();
+	}
+
+	/* === end of MyAppObserver ==== */
+
+}
diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MyApp.java b/jni/pjproject-android/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MyApp.java
new file mode 100644
index 0000000..cfaafe1
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MyApp.java
@@ -0,0 +1,449 @@
+/* $Id: MyApp.java 4704 2014-01-16 05:30:46Z ming $ */
+/*
+ * Copyright (C) 2013 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package org.pjsip.pjsua2.app;
+
+import java.io.File;
+import java.util.ArrayList;
+import org.pjsip.pjsua2.*;
+
+
+/* Interface to separate UI & engine a bit better */
+interface MyAppObserver {
+	abstract void notifyRegState(pjsip_status_code code, String reason, int expiration);
+	abstract void notifyIncomingCall(MyCall call);
+	abstract void notifyCallState(MyCall call);
+	abstract void notifyBuddyState(MyBuddy buddy);
+}
+
+
+class MyLogWriter extends LogWriter {
+	@Override
+	public void write(LogEntry entry) {
+		System.out.println(entry.getMsg());
+	}
+}
+
+
+class MyCall extends Call {
+	MyCall(MyAccount acc, int call_id) {
+		super(acc, call_id);
+	}
+
+	@Override
+	public void onCallState(OnCallStateParam prm) {
+		MyApp.observer.notifyCallState(this);
+	}
+	
+	@Override
+	public void onCallMediaState(OnCallMediaStateParam prm) {
+		CallInfo ci;
+		try {
+			ci = getInfo();
+		} catch (Exception e) {
+			return;
+		}
+		
+		CallMediaInfoVector cmiv = ci.getMedia();
+		
+		for (int i = 0; i < cmiv.size(); i++) {
+			CallMediaInfo cmi = cmiv.get(i);
+			if (cmi.getType() == pjmedia_type.PJMEDIA_TYPE_AUDIO &&
+			    (cmi.getStatus() == pjsua_call_media_status.PJSUA_CALL_MEDIA_ACTIVE ||
+			     cmi.getStatus() == pjsua_call_media_status.PJSUA_CALL_MEDIA_REMOTE_HOLD))
+			{
+				// unfortunately, on Java too, the returned Media cannot be downcasted to AudioMedia 
+				Media m = getMedia(i);
+				AudioMedia am = AudioMedia.typecastFromMedia(m);
+				
+				// connect ports
+				try {
+					MyApp.ep.audDevManager().getCaptureDevMedia().startTransmit(am);
+					am.startTransmit(MyApp.ep.audDevManager().getPlaybackDevMedia());
+				} catch (Exception e) {
+					continue;
+				}
+			}
+		}
+	}
+}
+
+
+class MyAccount extends Account {
+	public ArrayList<MyBuddy> buddyList = new ArrayList<MyBuddy>();
+	public AccountConfig cfg;
+	
+	MyAccount(AccountConfig config) {
+		super();
+		cfg = config;
+	}
+	
+	public MyBuddy addBuddy(BuddyConfig bud_cfg)
+	{
+		/* Create Buddy */
+		MyBuddy bud = new MyBuddy(bud_cfg);
+		try {
+			bud.create(this, bud_cfg);
+		} catch (Exception e) {
+			bud = null;
+		}
+		
+		if (bud != null) {
+			buddyList.add(bud);
+			if (bud_cfg.getSubscribe())
+				try {
+					bud.subscribePresence(true);
+				} catch (Exception e) {}
+		}
+		
+		return bud;
+	}
+	
+	public void delBuddy(MyBuddy buddy) {
+		buddyList.remove(buddy);
+	}
+	
+	public void delBuddy(int index) {
+		buddyList.remove(index);
+	}
+	
+	@Override
+	public void onRegState(OnRegStateParam prm) {
+		MyApp.observer.notifyRegState(prm.getCode(), prm.getReason(), prm.getExpiration());
+	}
+
+	@Override
+	public void onIncomingCall(OnIncomingCallParam prm) {
+		System.out.println("======== Incoming call ======== ");
+		MyCall call = new MyCall(this, prm.getCallId());
+		MyApp.observer.notifyIncomingCall(call);
+	}
+	
+	@Override
+	public void onInstantMessage(OnInstantMessageParam prm) {
+		System.out.println("======== Incoming pager ======== ");
+		System.out.println("From 		: " + prm.getFromUri());
+		System.out.println("To			: " + prm.getToUri());
+		System.out.println("Contact		: " + prm.getContactUri());
+		System.out.println("Mimetype	: " + prm.getContentType());
+		System.out.println("Body		: " + prm.getMsgBody());
+	}
+}
+
+
+class MyBuddy extends Buddy {
+	public BuddyConfig cfg;
+	
+	MyBuddy(BuddyConfig config) {
+		super();
+		cfg = config;
+	}
+	
+	String getStatusText() {
+		BuddyInfo bi;
+		
+		try {
+			bi = getInfo();
+		} catch (Exception e) {
+			return "?";
+		}
+		
+		String status = "";
+		if (bi.getSubState() == pjsip_evsub_state.PJSIP_EVSUB_STATE_ACTIVE) {
+			if (bi.getPresStatus().getStatus() == pjsua_buddy_status.PJSUA_BUDDY_STATUS_ONLINE) {
+				status = bi.getPresStatus().getStatusText();
+				if (status == null || status.isEmpty()) {
+					status = "Online";
+				}
+			} else if (bi.getPresStatus().getStatus() == pjsua_buddy_status.PJSUA_BUDDY_STATUS_OFFLINE) {
+				status = "Offline";
+			} else {
+				status = "Unknown";
+			}
+		}
+		return status;
+	}
+
+	@Override
+	public void onBuddyState() {
+		MyApp.observer.notifyBuddyState(this);
+	}
+	
+}
+
+
+class MyAccountConfig {
+	public AccountConfig accCfg = new AccountConfig();
+	public ArrayList<BuddyConfig> buddyCfgs = new ArrayList<BuddyConfig>();
+	
+	public void readObject(ContainerNode node) {
+		try {
+			ContainerNode acc_node = node.readContainer("Account");
+			accCfg.readObject(acc_node);
+			ContainerNode buddies_node = acc_node.readArray("buddies");
+			buddyCfgs.clear();
+			while (buddies_node.hasUnread()) {
+				BuddyConfig bud_cfg = new BuddyConfig(); 
+				bud_cfg.readObject(buddies_node);
+				buddyCfgs.add(bud_cfg);
+			}
+		} catch (Exception e) {}
+	}
+	
+	public void writeObject(ContainerNode node) {
+		try {
+			ContainerNode acc_node = node.writeNewContainer("Account");
+			accCfg.writeObject(acc_node);
+			ContainerNode buddies_node = acc_node.writeNewArray("buddies");
+			for (int j = 0; j < buddyCfgs.size(); j++) {
+				buddyCfgs.get(j).writeObject(buddies_node);
+			}
+		} catch (Exception e) {}
+	}
+}
+
+
+class MyApp {
+	static {
+		System.loadLibrary("pjsua2");
+		System.out.println("Library loaded");
+	}
+	
+	public static Endpoint ep = new Endpoint();
+	public static MyAppObserver observer;
+	public ArrayList<MyAccount> accList = new ArrayList<MyAccount>();
+
+	private ArrayList<MyAccountConfig> accCfgs = new ArrayList<MyAccountConfig>();
+	private EpConfig epConfig = new EpConfig();
+	private TransportConfig sipTpConfig = new TransportConfig();
+	private String appDir;
+	
+	/* Maintain reference to log writer to avoid premature cleanup by GC */
+	private MyLogWriter logWriter;
+
+	private final String configName = "pjsua2.json";
+	private final int SIP_PORT  = 6000;
+	private final int LOG_LEVEL = 4;
+	
+	public void init(MyAppObserver obs, String app_dir) {
+		init(obs, app_dir, false);
+	}
+	
+	public void init(MyAppObserver obs, String app_dir, boolean own_worker_thread) {
+		observer = obs;
+		appDir = app_dir;
+		
+		/* Create endpoint */
+		try {
+			ep.libCreate();
+		} catch (Exception e) {
+			return;
+		}
+			
+		
+		/* Load config */
+		String configPath = appDir + "/" + configName;
+		File f = new File(configPath);
+		if (f.exists()) {
+			loadConfig(configPath);
+		} else {
+			/* Set 'default' values */
+			sipTpConfig.setPort(SIP_PORT);
+		}
+		
+		/* Override log level setting */
+		epConfig.getLogConfig().setLevel(LOG_LEVEL);
+		epConfig.getLogConfig().setConsoleLevel(LOG_LEVEL);
+		
+		/* Set log config. */
+		LogConfig log_cfg = epConfig.getLogConfig();
+		logWriter = new MyLogWriter();
+		log_cfg.setWriter(logWriter);
+		log_cfg.setDecor(log_cfg.getDecor() & 
+						 ~(pj_log_decoration.PJ_LOG_HAS_CR.swigValue() | 
+						   pj_log_decoration.PJ_LOG_HAS_NEWLINE.swigValue()));
+		
+		/* Set ua config. */
+		UaConfig ua_cfg = epConfig.getUaConfig();
+		ua_cfg.setUserAgent("Pjsua2And" + ep.libVersion().getFull());
+		if (own_worker_thread) {
+			ua_cfg.setThreadCnt(0);
+			ua_cfg.setMainThreadOnly(true);
+		}
+		
+		/* Init endpoint */
+		try {
+			ep.libInit(epConfig);
+		} catch (Exception e) {
+			return;
+		}
+		
+		/* Create transports. */
+		try {
+			ep.transportCreate(pjsip_transport_type_e.PJSIP_TRANSPORT_UDP, sipTpConfig);
+		} catch (Exception e) {
+			System.out.println(e);
+		}
+
+		try {
+			ep.transportCreate(pjsip_transport_type_e.PJSIP_TRANSPORT_TCP, sipTpConfig);
+		} catch (Exception e) {
+			System.out.println(e);
+		}
+		
+		/* Create accounts. */
+		for (int i = 0; i < accCfgs.size(); i++) {
+			MyAccountConfig my_cfg = accCfgs.get(i);
+			MyAccount acc = addAcc(my_cfg.accCfg);
+			if (acc == null)
+				continue;
+			
+			/* Add Buddies */
+			for (int j = 0; j < my_cfg.buddyCfgs.size(); j++) {
+				BuddyConfig bud_cfg = my_cfg.buddyCfgs.get(j);
+				acc.addBuddy(bud_cfg);
+			}
+		}
+
+		/* Start. */
+		try {
+			ep.libStart();
+		} catch (Exception e) {
+			return;
+		}
+	}
+	
+	public MyAccount addAcc(AccountConfig cfg) {
+		MyAccount acc = new MyAccount(cfg);
+		try {
+			acc.create(cfg);
+		} catch (Exception e) {
+			acc = null;
+			return null;
+		}
+		
+		accList.add(acc);
+		return acc;
+	}
+	
+	public void delAcc(MyAccount acc) {
+		accList.remove(acc);
+	}
+	
+	private void loadConfig(String filename) {
+		JsonDocument json = new JsonDocument();
+		
+		try {
+			/* Load file */
+			json.loadFile(filename);
+			ContainerNode root = json.getRootContainer();
+			
+			/* Read endpoint config */
+			epConfig.readObject(root);
+			
+			/* Read transport config */
+			ContainerNode tp_node = root.readContainer("SipTransport");
+			sipTpConfig.readObject(tp_node);
+			
+			/* Read account configs */
+			accCfgs.clear();
+			ContainerNode accs_node = root.readArray("accounts");
+			while (accs_node.hasUnread()) {
+				MyAccountConfig acc_cfg = new MyAccountConfig();
+				acc_cfg.readObject(accs_node);
+				accCfgs.add(acc_cfg);
+			}
+		} catch (Exception e) {
+			System.out.println(e);
+		}
+		
+		/* Force delete json now, as I found that Java somehow destroys it
+		 * after lib has been destroyed and from non-registered thread.
+		 */
+		json.delete();
+	}
+
+	private void buildAccConfigs() {
+		/* Sync accCfgs from accList */
+		accCfgs.clear();
+		for (int i = 0; i < accList.size(); i++) {
+			MyAccount acc = accList.get(i);
+			MyAccountConfig my_acc_cfg = new MyAccountConfig();
+			my_acc_cfg.accCfg = acc.cfg;
+			
+			my_acc_cfg.buddyCfgs.clear();
+			for (int j = 0; j < acc.buddyList.size(); j++) {
+				MyBuddy bud = acc.buddyList.get(j);
+				my_acc_cfg.buddyCfgs.add(bud.cfg);
+			}
+			
+			accCfgs.add(my_acc_cfg);
+		}
+	}
+	
+	private void saveConfig(String filename) {
+		JsonDocument json = new JsonDocument();
+		
+		try {
+			/* Write endpoint config */
+			json.writeObject(epConfig);
+			
+			/* Write transport config */
+			ContainerNode tp_node = json.writeNewContainer("SipTransport");
+			sipTpConfig.writeObject(tp_node);
+			
+			/* Write account configs */
+			buildAccConfigs();
+			ContainerNode accs_node = json.writeNewArray("accounts");
+			for (int i = 0; i < accCfgs.size(); i++) {
+				accCfgs.get(i).writeObject(accs_node);
+			}
+			
+			/* Save file */
+			json.saveFile(filename);
+		} catch (Exception e) {}
+
+		/* Force delete json now, as I found that Java somehow destroys it
+		 * after lib has been destroyed and from non-registered thread.
+		 */
+		json.delete();
+	}
+	
+	public void deinit() {
+		String configPath = appDir + "/" + configName;
+		saveConfig(configPath);
+		
+		/* Try force GC to avoid late destroy of PJ objects as they should be
+		 * deleted before lib is destroyed.
+		 */
+		Runtime.getRuntime().gc();
+		
+		/* Shutdown pjsua. Note that Endpoint destructor will also invoke
+		 * libDestroy(), so this will be a test of double libDestroy().
+		 */
+		try {
+			ep.libDestroy();
+		} catch (Exception e) {}
+		
+		/* Force delete Endpoint here, to avoid deletion from a non-
+		 * registered thread (by GC?). 
+		 */
+		ep.delete();
+		ep = null;
+	} 
+}
diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/sample.java b/jni/pjproject-android/pjsip-apps/src/swig/java/sample.java
new file mode 100644
index 0000000..ffcc887
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/sample.java
@@ -0,0 +1,140 @@
+/* $Id: sample.java 4704 2014-01-16 05:30:46Z ming $ */
+/* 
+ * Copyright (C) 2013 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+ 
+package org.pjsip.pjsua2.app;
+
+import java.io.IOException;
+import org.pjsip.pjsua2.*;
+import org.pjsip.pjsua2.app.*;
+
+class MyObserver implements MyAppObserver {
+	private static MyCall currentCall = null;
+	
+	@Override
+	public void notifyRegState(pjsip_status_code code, String reason, int expiration) {}
+	
+	@Override
+	public void notifyIncomingCall(MyCall call) {
+		/* Auto answer. */
+		CallOpParam call_param = new CallOpParam();
+		call_param.setStatusCode(pjsip_status_code.PJSIP_SC_OK);
+		try {
+			currentCall = call;
+			currentCall.answer(call_param);
+		} catch (Exception e) {
+			System.out.println(e);
+			return;
+		}			
+	}
+	
+	@Override
+	public void notifyCallState(MyCall call) {
+		if (currentCall == null || call.getId() != currentCall.getId())
+			return;
+		
+		CallInfo ci;
+		try {
+			ci = call.getInfo();
+		} catch (Exception e) {
+			ci = null;
+		}
+		if (ci.getState() == pjsip_inv_state.PJSIP_INV_STATE_DISCONNECTED)
+			currentCall = null;		
+	}
+	
+	@Override
+	public void notifyBuddyState(MyBuddy buddy) {}	
+}
+
+class MyShutdownHook extends Thread {
+	Thread thread;
+	MyShutdownHook(Thread thr) {
+		thread = thr;
+	}
+	public void run() {
+		thread.interrupt();
+		try {
+			thread.join();
+		} catch (Exception e) {
+			;
+		}
+	}
+}	
+
+public class sample {
+	private static MyApp app = new MyApp();
+	private static MyAppObserver observer = new MyObserver();
+	private static MyAccount account = null;
+	private static AccountConfig accCfg = null;			
+	
+	private static void runWorker() {
+		try {					
+			app.init(observer, ".", true);
+		} catch (Exception e) {
+			System.out.println(e);
+			app.deinit();
+			System.exit(-1);
+		} 
+
+		if (app.accList.size() == 0) {
+			accCfg = new AccountConfig();
+			accCfg.setIdUri("sip:localhost");
+			account = app.addAcc(accCfg);
+
+			accCfg.setIdUri("sip:301@pjsip.org");
+			AccountSipConfig sipCfg = accCfg.getSipConfig();		
+			AuthCredInfoVector ciVec = sipCfg.getAuthCreds();
+			ciVec.add(new AuthCredInfo("Digest", 
+					"*",
+					"301",
+					0,
+					"pw301"));
+
+			StringVector proxy = sipCfg.getProxies();
+			proxy.add("sip:pjsip.org;transport=tcp");							
+
+			AccountRegConfig regCfg = accCfg.getRegConfig();
+			regCfg.setRegistrarUri("sip:pjsip.org");
+			account = app.addAcc(accCfg);
+		} else {
+			account = app.accList.get(0);
+			accCfg = account.cfg;
+		}				
+
+		try {
+			account.modify(accCfg);
+		} catch (Exception e) {}				
+
+		while (!Thread.currentThread().isInterrupted()) {
+			MyApp.ep.libHandleEvents(10);
+			try {						
+				Thread.currentThread().sleep(50);
+			} catch (InterruptedException ie) {						
+				break;
+			}					
+		}
+		app.deinit();
+	}	
+		
+	public static void main(String argv[]) {
+		Runtime.getRuntime().addShutdownHook(new MyShutdownHook(Thread.currentThread()));
+
+		runWorker();
+    }
+}
diff --git a/jni/pjproject-android/pjsip-apps/src/swig/java/test.java b/jni/pjproject-android/pjsip-apps/src/swig/java/test.java
new file mode 100644
index 0000000..f616460
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/java/test.java
@@ -0,0 +1,17 @@
+import org.pjsip.pjsua2.*;
+
+public class test {
+  static {
+    System.loadLibrary("pjsua2");
+    System.out.println("Library loaded");
+  }
+
+  public static void main(String argv[]) {
+
+	AuthCredInfo cred = new AuthCredInfo();
+
+	cred.setRealm("Hello world");
+    
+	System.out.println(cred.getRealm());
+  }
+}
diff --git a/jni/pjproject-android/pjsip-apps/src/swig/pjsua2.i b/jni/pjproject-android/pjsip-apps/src/swig/pjsua2.i
new file mode 100644
index 0000000..2cc41d4
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/pjsua2.i
@@ -0,0 +1,111 @@
+%module(directors="1") pjsua2
+
+//
+// Suppress few warnings
+//
+#pragma SWIG nowarn=312		// 312: nested struct (in types.h, sip_auth.h)
+
+//
+// Header section
+//
+%{
+#include "pjsua2.hpp"
+using namespace std;
+using namespace pj;
+%}
+
+#ifdef SWIGPYTHON
+  %feature("director:except") {
+    if( $error != NULL ) {
+      PyObject *ptype, *pvalue, *ptraceback;
+      PyErr_Fetch( &ptype, &pvalue, &ptraceback );
+      PyErr_Restore( ptype, pvalue, ptraceback );
+      PyErr_Print();
+      //Py_Exit(1);
+    }
+  }
+#endif
+
+// Allow C++ exceptions to be handled in Java
+#ifdef SWIGJAVA
+  %typemap(throws, throws="java.lang.Exception") pj::Error {
+  jclass excep = jenv->FindClass("java/lang/Exception");
+  if (excep)
+    jenv->ThrowNew(excep, $1.info(true).c_str());
+  return $null;
+}
+
+  // Force the Error Java class to extend java.lang.Exception
+  %typemap(javabase) pj::Error "java.lang.Exception";
+
+  // Override getMessage()
+  %typemap(javacode) pj::Error %{
+  public String getMessage() {
+    return getTitle();
+  }
+%}
+#endif
+
+
+// Constants from PJSIP libraries
+%include "symbols.i"
+
+
+//
+// Classes that can be extended in the target language
+//
+%feature("director") LogWriter;
+%feature("director") Endpoint; 
+%feature("director") Account;
+%feature("director") Call;
+%feature("director") Buddy;
+%feature("director") FindBuddyMatch;
+
+//
+// STL stuff.
+//
+%include "std_string.i"
+%include "std_vector.i"
+
+%template(StringVector)			std::vector<std::string>;
+%template(IntVector) 			std::vector<int>;
+
+//
+// Ignore stuffs in pjsua2
+//
+%ignore fromPj;
+%ignore toPj;
+
+//
+// Now include the API itself.
+//
+%include "pjsua2/types.hpp"
+
+%ignore pj::ContainerNode::op;
+%ignore pj::ContainerNode::data;
+%ignore container_node_op;
+%ignore container_node_internal_data;
+%include "pjsua2/persistent.hpp"
+
+%include "pjsua2/siptypes.hpp"
+
+%template(SipHeaderVector)		std::vector<pj::SipHeader>;
+%template(AuthCredInfoVector)		std::vector<pj::AuthCredInfo>;
+%template(SipMultipartPartVector)	std::vector<pj::SipMultipartPart>;
+%template(BuddyVector)			std::vector<pj::Buddy*>;
+%template(AudioMediaVector)		std::vector<pj::AudioMedia*>;
+%template(MediaFormatVector)		std::vector<pj::MediaFormat*>;
+%template(AudioDevInfoVector)		std::vector<pj::AudioDevInfo*>;
+%template(CodecInfoVector)		std::vector<pj::CodecInfo*>;
+
+%include "pjsua2/media.hpp"
+%include "pjsua2/endpoint.hpp"
+%include "pjsua2/presence.hpp"
+%include "pjsua2/account.hpp"
+%include "pjsua2/call.hpp"
+
+%template(CallMediaInfoVector)          std::vector<pj::CallMediaInfo>;
+
+%ignore pj::JsonDocument::allocElement;
+%ignore pj::JsonDocument::getPool;
+%include "pjsua2/json.hpp"
diff --git a/jni/pjproject-android/pjsip-apps/src/swig/python/Makefile b/jni/pjproject-android/pjsip-apps/src/swig/python/Makefile
new file mode 100644
index 0000000..80af9bf
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/python/Makefile
@@ -0,0 +1,29 @@
+PYTHON_SO=_pjsua2.so
+
+#PYTHON_SETUP_FLAGS = --inplace 
+ifeq ($(OS),Windows_NT)
+  PYTHON_SETUP_FLAGS += --compiler=mingw32
+endif
+
+SWIG_FLAGS += -w312
+
+.PHONY: all install uninstall
+
+all: $(PYTHON_SO)
+
+$(PYTHON_SO): pjsua2_wrap.cpp setup.py
+	python setup.py build $(PYTHON_SETUP_FLAGS)
+
+pjsua2_wrap.cpp: ../pjsua2.i ../symbols.i Makefile $(SRCS)
+	swig $(SWIG_FLAGS) -python  -o pjsua2_wrap.cpp ../pjsua2.i
+
+clean distclean realclean:
+	rm -rf $(PYTHON_SO) pjsua2_wrap.cpp pjsua2_wrap.h pjsua2.py build *.pyc
+
+install:
+	python setup.py install --user
+
+uninstall:
+	rm -f $(HOME)/.local/lib/python2.7/site-packages/pjsua2*
+	rm -f $(HOME)/.local/lib/python2.7/site-packages/_pjsua2*
+
diff --git a/jni/pjproject-android/pjsip-apps/src/swig/python/helper.mak b/jni/pjproject-android/pjsip-apps/src/swig/python/helper.mak
new file mode 100644
index 0000000..41baf2b
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/python/helper.mak
@@ -0,0 +1,20 @@
+include ../../../../build.mak
+
+lib_dir:
+	@for token in `echo $(APP_LDFLAGS)`; do \
+		echo $$token | grep L | sed 's/-L//'; \
+	done
+
+inc_dir:
+	@for token in `echo $(APP_CFLAGS)`; do \
+		echo $$token | grep I | sed 's/-I//'; \
+	done
+
+libs:
+	@for token in `echo $(APP_LDLIBS)`; do \
+		echo $$token | grep \\-l | sed 's/-l//'; \
+	done
+
+target_name:
+	@echo $(TARGET_NAME)
+	
diff --git a/jni/pjproject-android/pjsip-apps/src/swig/python/setup.py b/jni/pjproject-android/pjsip-apps/src/swig/python/setup.py
new file mode 100644
index 0000000..a4cca08
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/python/setup.py
@@ -0,0 +1,118 @@
+# $Id: setup.py 4704 2014-01-16 05:30:46Z ming $
+#
+# pjsua2 Setup script.
+#
+# Copyright (C)2012 Teluu Inc. (http://www.teluu.com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+#
+from distutils.core import setup, Extension
+import os
+import sys
+import platform
+
+# find pjsip version
+pj_version=""
+pj_version_major=""
+pj_version_minor=""
+pj_version_rev=""
+pj_version_suffix=""
+f = open('../../../../version.mak', 'r')
+for line in f:
+    if line.find("export PJ_VERSION_MAJOR") != -1:
+    	tokens=line.split("=")
+	if len(tokens)>1:
+		pj_version_major= tokens[1].strip()
+    elif line.find("export PJ_VERSION_MINOR") != -1:
+    	tokens=line.split("=")
+	if len(tokens)>1:
+		pj_version_minor= line.split("=")[1].strip()
+    elif line.find("export PJ_VERSION_REV") != -1:
+    	tokens=line.split("=")
+	if len(tokens)>1:
+		pj_version_rev= line.split("=")[1].strip()
+    elif line.find("export PJ_VERSION_SUFFIX") != -1:
+    	tokens=line.split("=")
+	if len(tokens)>1:
+		pj_version_suffix= line.split("=")[1].strip()
+
+f.close()
+if not pj_version_major:
+    print 'Unable to get PJ_VERSION_MAJOR'
+    sys.exit(1)
+
+pj_version = pj_version_major + "." + pj_version_minor
+if pj_version_rev:
+	pj_version += "." + pj_version_rev
+if pj_version_suffix:
+	pj_version += "-" + pj_version_suffix
+
+#print 'PJ_VERSION = "'+ pj_version + '"'
+
+# Get targetname
+f = os.popen("make --no-print-directory -f helper.mak target_name")
+pj_target_name = f.read().rstrip("\r\n")
+f.close()
+
+# Fill in pj_inc_dirs
+pj_inc_dirs = []
+f = os.popen("make --no-print-directory -f helper.mak inc_dir")
+for line in f:
+    pj_inc_dirs.append(line.rstrip("\r\n"))
+f.close()
+
+# Fill in pj_lib_dirs
+pj_lib_dirs = []
+f = os.popen("make --no-print-directory -f helper.mak lib_dir")
+for line in f:
+    pj_lib_dirs.append(line.rstrip("\r\n"))
+f.close()
+
+# Fill in pj_libs
+pj_libs = ['pjsua2-' + pj_target_name]
+f = os.popen("make --no-print-directory -f helper.mak libs")
+for line in f:
+    pj_libs.append(line.rstrip("\r\n"))
+f.close()
+
+# Fill in extra link args
+extra_link_args = ['-static-libstdc++']
+if platform.system() == 'Darwin':
+    # Mac OS X depedencies
+    extra_link_args += ["-framework", "CoreFoundation", 
+                        "-framework", "AudioToolbox",
+			"-framework", "QTKit"]
+    # OS X Lion support
+    if platform.mac_ver()[0].startswith("10.7"):
+        extra_link_args += ["-framework", "AudioUnit"]
+
+
+setup(name="pjsua2", 
+      version=pj_version,
+      description='SIP User Agent Library based on PJSIP',
+      url='http://www.pjsip.org',
+      ext_modules = [Extension("_pjsua2", 
+                               ["pjsua2_wrap.cpp"], 
+                               define_macros=[('PJ_AUTOCONF', '1'),],
+                               include_dirs=pj_inc_dirs, 
+                               library_dirs=pj_lib_dirs, 
+                               libraries=pj_libs,
+                               extra_link_args=extra_link_args
+                              )
+                    ],
+      py_modules=["pjsua2"]
+     )
+
+
diff --git a/jni/pjproject-android/pjsip-apps/src/swig/python/test.py b/jni/pjproject-android/pjsip-apps/src/swig/python/test.py
new file mode 100644
index 0000000..dc805c7
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/python/test.py
@@ -0,0 +1,112 @@
+import pjsua2 as pj
+import sys
+
+#
+# Basic data structure test, to make sure basic struct
+# and array operations work
+#
+def ua_data_test():
+	#
+	# AuthCredInfo
+	#
+	print "UA data types test.."
+	the_realm = "pjsip.org"
+	ci = pj.AuthCredInfo()
+	ci.realm = the_realm
+	ci.dataType = 20
+	
+	ci2 = ci
+	assert ci.dataType == 20
+	assert ci2.realm == the_realm
+	
+	#
+	# UaConfig
+	# See here how we manipulate std::vector
+	#
+	uc = pj.UaConfig()
+	uc.maxCalls = 10
+	uc.userAgent = "Python"
+	uc.nameserver = pj.StringVector(["10.0.0.1", "10.0.0.2"])
+	uc.nameserver.append("NS1")
+	
+	uc2 = uc
+	assert uc2.maxCalls == 10
+	assert uc2.userAgent == "Python"
+	assert len(uc2.nameserver) == 3
+	assert uc2.nameserver[0] == "10.0.0.1"
+	assert uc2.nameserver[1] == "10.0.0.2"
+	assert uc2.nameserver[2] == "NS1"
+
+	print "  Dumping nameservers: ",
+	for s in uc2.nameserver:
+		print s,
+	print ""
+
+#
+# Exception test
+#
+def ua_run_test_exception():
+	print "Exception test.."
+	ep = pj.Endpoint()
+	ep.libCreate()
+	got_exception = False
+	try:
+		ep.natDetectType()
+	except pj.Error, e:
+		got_exception = True
+		print "  Got exception: status=%u, reason=%s,\n  title=%s,\n  srcFile=%s, srcLine=%d" % \
+			(e.status, e.reason, e.title, e.srcFile, e.srcLine)
+		assert e.status == 370050
+		assert e.reason.find("PJNATH_ESTUNINSERVER") >= 0
+		assert e.title == "pjsua_detect_nat_type()"
+	assert got_exception
+
+#
+# Custom log writer
+#
+class MyLogWriter(pj.LogWriter):
+	def write(self, entry):
+		print "This is Python:", entry.msg
+		
+#
+# Testing log writer callback
+#
+def ua_run_log_test():
+	print "Logging test.."
+	ep_cfg = pj.EpConfig()
+	
+	lw = MyLogWriter()
+	ep_cfg.logConfig.writer = lw
+	ep_cfg.logConfig.decor = ep_cfg.logConfig.decor & ~(pj.PJ_LOG_HAS_CR | pj.PJ_LOG_HAS_NEWLINE) 
+	
+	ep = pj.Endpoint()
+	ep.libCreate()
+	ep.libInit(ep_cfg)
+	ep.libDestroy()
+	
+#
+# Simple create, init, start, and destroy sequence
+#
+def ua_run_ua_test():
+	print "UA test run.."
+	ep_cfg = pj.EpConfig()
+	
+	ep = pj.Endpoint()
+	ep.libCreate()
+	ep.libInit(ep_cfg)
+	ep.libStart()
+	
+	print "************* Endpoint started ok, now shutting down... *************"
+	ep.libDestroy()
+
+#
+# main()
+#
+if __name__ == "__main__":
+	ua_data_test()
+	ua_run_test_exception()
+	ua_run_log_test()
+	ua_run_ua_test()
+	sys.exit(0)
+
+	
\ No newline at end of file
diff --git a/jni/pjproject-android/pjsip-apps/src/swig/symbols.i b/jni/pjproject-android/pjsip-apps/src/swig/symbols.i
new file mode 100644
index 0000000..e101e77
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/symbols.i
@@ -0,0 +1,130 @@
+// This file is autogenerated by importsym script, do not modify!
+
+typedef int pj_status_t;
+
+enum pj_constants_ {PJ_SUCCESS = 0, PJ_TRUE = 1, PJ_FALSE = 0};
+
+typedef unsigned char pj_uint8_t;
+
+typedef int pj_int32_t;
+
+typedef unsigned int pj_uint32_t;
+
+typedef unsigned short pj_uint16_t;
+
+enum pj_file_access {PJ_O_RDONLY = 0x1101, PJ_O_WRONLY = 0x1102, PJ_O_RDWR = 0x1103, PJ_O_APPEND = 0x1108};
+
+enum pj_log_decoration {PJ_LOG_HAS_DAY_NAME = 1, PJ_LOG_HAS_YEAR = 2, PJ_LOG_HAS_MONTH = 4, PJ_LOG_HAS_DAY_OF_MON = 8, PJ_LOG_HAS_TIME = 16, PJ_LOG_HAS_MICRO_SEC = 32, PJ_LOG_HAS_SENDER = 64, PJ_LOG_HAS_NEWLINE = 128, PJ_LOG_HAS_CR = 256, PJ_LOG_HAS_SPACE = 512, PJ_LOG_HAS_COLOR = 1024, PJ_LOG_HAS_LEVEL_TEXT = 2048, PJ_LOG_HAS_THREAD_ID = 4096, PJ_LOG_HAS_THREAD_SWC = 8192, PJ_LOG_HAS_INDENT = 16384};
+
+typedef enum pj_qos_type {PJ_QOS_TYPE_BEST_EFFORT, PJ_QOS_TYPE_BACKGROUND, PJ_QOS_TYPE_VIDEO, PJ_QOS_TYPE_VOICE, PJ_QOS_TYPE_CONTROL} pj_qos_type;
+
+typedef enum pj_qos_flag {PJ_QOS_PARAM_HAS_DSCP = 1, PJ_QOS_PARAM_HAS_SO_PRIO = 2, PJ_QOS_PARAM_HAS_WMM = 4} pj_qos_flag;
+
+typedef enum pj_qos_wmm_prio {PJ_QOS_WMM_PRIO_BULK_EFFORT, PJ_QOS_WMM_PRIO_BULK, PJ_QOS_WMM_PRIO_VIDEO, PJ_QOS_WMM_PRIO_VOICE} pj_qos_wmm_prio;
+
+typedef struct pj_qos_params
+{
+  pj_uint8_t flags;
+  pj_uint8_t dscp_val;
+  pj_uint8_t so_prio;
+  pj_qos_wmm_prio wmm_prio;
+} pj_qos_params;
+
+typedef enum pj_ssl_cipher {PJ_TLS_NULL_WITH_NULL_NULL = 0x00000000, PJ_TLS_RSA_WITH_NULL_MD5 = 0x00000001, PJ_TLS_RSA_WITH_NULL_SHA = 0x00000002, PJ_TLS_RSA_WITH_NULL_SHA256 = 0x0000003B, PJ_TLS_RSA_WITH_RC4_128_MD5 = 0x00000004, PJ_TLS_RSA_WITH_RC4_128_SHA = 0x00000005, PJ_TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x0000000A, PJ_TLS_RSA_WITH_AES_128_CBC_SHA = 0x0000002F, PJ_TLS_RSA_WITH_AES_256_CBC_SHA = 0x00000035, PJ_TLS_RSA_WITH_AES_128_CBC_SHA256 = 0x0000003C, PJ_TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x0000003D, PJ_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = 0x0000000D, PJ_TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = 0x00000010, PJ_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 0x00000013, PJ_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 0x00000016, PJ_TLS_DH_DSS_WITH_AES_128_CBC_SHA = 0x00000030, PJ_TLS_DH_RSA_WITH_AES_128_CBC_SHA = 0x00000031, PJ_TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 0x00000032, PJ_TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x00000033, PJ_TLS_DH_DSS_WITH_AES_256_CBC_SHA = 0x00000036, PJ_TLS_DH_RSA_WITH_AES_256_CBC_SHA = 0x00000037, PJ_TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 0x00000038, PJ_TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x00000039, PJ_TLS_DH_DSS_WITH_AES_128_CBC_SHA256 = 0x0000003E, PJ_TLS_DH_RSA_WITH_AES_128_CBC_SHA256 = 0x0000003F, PJ_TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 = 0x00000040, PJ_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0x00000067, PJ_TLS_DH_DSS_WITH_AES_256_CBC_SHA256 = 0x00000068, PJ_TLS_DH_RSA_WITH_AES_256_CBC_SHA256 = 0x00000069, PJ_TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 = 0x0000006A, PJ_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x0000006B, PJ_TLS_DH_anon_WITH_RC4_128_MD5 = 0x00000018, PJ_TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = 0x0000001B, PJ_TLS_DH_anon_WITH_AES_128_CBC_SHA = 0x00000034, PJ_TLS_DH_anon_WITH_AES_256_CBC_SHA = 0x0000003A, PJ_TLS_DH_anon_WITH_AES_128_CBC_SHA256 = 0x0000006C, PJ_TLS_DH_anon_WITH_AES_256_CBC_SHA256 = 0x0000006D, PJ_TLS_RSA_EXPORT_WITH_RC4_40_MD5 = 0x00000003, PJ_TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = 0x00000006, PJ_TLS_RSA_WITH_IDEA_CBC_SHA = 0x00000007, PJ_TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x00000008, PJ_TLS_RSA_WITH_DES_CBC_SHA = 0x00000009, PJ_TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x0000000B, PJ_TLS_DH_DSS_WITH_DES_CBC_SHA = 0x0000000C, PJ_TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x0000000E, PJ_TLS_DH_RSA_WITH_DES_CBC_SHA = 0x0000000F, PJ_TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x00000011, PJ_TLS_DHE_DSS_WITH_DES_CBC_SHA = 0x00000012, PJ_TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x00000014, PJ_TLS_DHE_RSA_WITH_DES_CBC_SHA = 0x00000015, PJ_TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 = 0x00000017, PJ_TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA = 0x00000019, PJ_TLS_DH_anon_WITH_DES_CBC_SHA = 0x0000001A, PJ_SSL_FORTEZZA_KEA_WITH_NULL_SHA = 0x0000001C, PJ_SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA = 0x0000001D, PJ_SSL_FORTEZZA_KEA_WITH_RC4_128_SHA = 0x0000001E, PJ_SSL_CK_RC4_128_WITH_MD5 = 0x00010080, PJ_SSL_CK_RC4_128_EXPORT40_WITH_MD5 = 0x00020080, PJ_SSL_CK_RC2_128_CBC_WITH_MD5 = 0x00030080, PJ_SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5 = 0x00040080, PJ_SSL_CK_IDEA_128_CBC_WITH_MD5 = 0x00050080, PJ_SSL_CK_DES_64_CBC_WITH_MD5 = 0x00060040, PJ_SSL_CK_DES_192_EDE3_CBC_WITH_MD5 = 0x000700C0} pj_ssl_cipher;
+
+typedef enum pj_stun_nat_type {PJ_STUN_NAT_TYPE_UNKNOWN, PJ_STUN_NAT_TYPE_ERR_UNKNOWN, PJ_STUN_NAT_TYPE_OPEN, PJ_STUN_NAT_TYPE_BLOCKED, PJ_STUN_NAT_TYPE_SYMMETRIC_UDP, PJ_STUN_NAT_TYPE_FULL_CONE, PJ_STUN_NAT_TYPE_SYMMETRIC, PJ_STUN_NAT_TYPE_RESTRICTED, PJ_STUN_NAT_TYPE_PORT_RESTRICTED} pj_stun_nat_type;
+
+typedef enum pj_turn_tp_type {PJ_TURN_TP_UDP = 17, PJ_TURN_TP_TCP = 6, PJ_TURN_TP_TLS = 255} pj_turn_tp_type;
+
+typedef enum pjmedia_event_type {PJMEDIA_EVENT_NONE, PJMEDIA_EVENT_FMT_CHANGED = ((('H' << 24) | ('C' << 16)) | ('M' << 8)) | 'F', PJMEDIA_EVENT_WND_CLOSING = ((('L' << 24) | ('C' << 16)) | ('N' << 8)) | 'W', PJMEDIA_EVENT_WND_CLOSED = ((('O' << 24) | ('C' << 16)) | ('N' << 8)) | 'W', PJMEDIA_EVENT_WND_RESIZED = ((('Z' << 24) | ('R' << 16)) | ('N' << 8)) | 'W', PJMEDIA_EVENT_MOUSE_BTN_DOWN = ((('N' << 24) | ('D' << 16)) | ('S' << 8)) | 'M', PJMEDIA_EVENT_KEYFRAME_FOUND = ((('F' << 24) | ('R' << 16)) | ('F' << 8)) | 'I', PJMEDIA_EVENT_KEYFRAME_MISSING = ((('M' << 24) | ('R' << 16)) | ('F' << 8)) | 'I', PJMEDIA_EVENT_ORIENT_CHANGED = ((('T' << 24) | ('N' << 16)) | ('R' << 8)) | 'O'} pjmedia_event_type;
+
+typedef enum pjmedia_srtp_use {PJMEDIA_SRTP_DISABLED, PJMEDIA_SRTP_OPTIONAL, PJMEDIA_SRTP_MANDATORY} pjmedia_srtp_use;
+
+typedef enum pjmedia_vid_stream_rc_method {PJMEDIA_VID_STREAM_RC_NONE = 0, PJMEDIA_VID_STREAM_RC_SIMPLE_BLOCKING = 1} pjmedia_vid_stream_rc_method;
+
+typedef pj_int32_t pjmedia_vid_dev_index;
+
+enum pjmedia_vid_dev_std_index {PJMEDIA_VID_DEFAULT_CAPTURE_DEV = -1, PJMEDIA_VID_DEFAULT_RENDER_DEV = -2, PJMEDIA_VID_INVALID_DEV = -3};
+
+typedef enum pjmedia_aud_dev_route {PJMEDIA_AUD_DEV_ROUTE_DEFAULT = 0, PJMEDIA_AUD_DEV_ROUTE_LOUDSPEAKER = 1, PJMEDIA_AUD_DEV_ROUTE_EARPIECE = 2, PJMEDIA_AUD_DEV_ROUTE_BLUETOOTH = 4} pjmedia_aud_dev_route;
+
+typedef enum pjmedia_aud_dev_cap {PJMEDIA_AUD_DEV_CAP_EXT_FORMAT = 1, PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY = 2, PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY = 4, PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING = 8, PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING = 16, PJMEDIA_AUD_DEV_CAP_INPUT_SIGNAL_METER = 32, PJMEDIA_AUD_DEV_CAP_OUTPUT_SIGNAL_METER = 64, PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE = 128, PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE = 256, PJMEDIA_AUD_DEV_CAP_EC = 512, PJMEDIA_AUD_DEV_CAP_EC_TAIL = 1024, PJMEDIA_AUD_DEV_CAP_VAD = 2048, PJMEDIA_AUD_DEV_CAP_CNG = 4096, PJMEDIA_AUD_DEV_CAP_PLC = 8192, PJMEDIA_AUD_DEV_CAP_MAX = 16384} pjmedia_aud_dev_cap;
+
+enum pjmedia_file_writer_option {PJMEDIA_FILE_WRITE_PCM = 0, PJMEDIA_FILE_WRITE_ALAW = 1, PJMEDIA_FILE_WRITE_ULAW = 2};
+
+enum pjmedia_file_player_option {PJMEDIA_FILE_NO_LOOP = 1};
+
+typedef enum pjmedia_type {PJMEDIA_TYPE_NONE, PJMEDIA_TYPE_AUDIO, PJMEDIA_TYPE_VIDEO, PJMEDIA_TYPE_APPLICATION, PJMEDIA_TYPE_UNKNOWN} pjmedia_type;
+
+typedef enum pjmedia_dir {PJMEDIA_DIR_NONE = 0, PJMEDIA_DIR_ENCODING = 1, PJMEDIA_DIR_CAPTURE = PJMEDIA_DIR_ENCODING, PJMEDIA_DIR_DECODING = 2, PJMEDIA_DIR_PLAYBACK = PJMEDIA_DIR_DECODING, PJMEDIA_DIR_RENDER = PJMEDIA_DIR_DECODING, PJMEDIA_DIR_ENCODING_DECODING = 3, PJMEDIA_DIR_CAPTURE_PLAYBACK = PJMEDIA_DIR_ENCODING_DECODING, PJMEDIA_DIR_CAPTURE_RENDER = PJMEDIA_DIR_ENCODING_DECODING} pjmedia_dir;
+
+typedef enum pjmedia_tp_proto {PJMEDIA_TP_PROTO_NONE = 0, PJMEDIA_TP_PROTO_RTP_AVP, PJMEDIA_TP_PROTO_RTP_SAVP, PJMEDIA_TP_PROTO_UNKNOWN} pjmedia_tp_proto;
+
+typedef enum pjmedia_format_id {PJMEDIA_FORMAT_L16 = 0, PJMEDIA_FORMAT_PCM = PJMEDIA_FORMAT_L16, PJMEDIA_FORMAT_PCMA = ((('W' << 24) | ('A' << 16)) | ('L' << 8)) | 'A', PJMEDIA_FORMAT_ALAW = PJMEDIA_FORMAT_PCMA, PJMEDIA_FORMAT_PCMU = ((('W' << 24) | ('A' << 16)) | ('L' << 8)) | 'u', PJMEDIA_FORMAT_ULAW = PJMEDIA_FORMAT_PCMU, PJMEDIA_FORMAT_AMR = ((('R' << 24) | ('M' << 16)) | ('A' << 8)) | ' ', PJMEDIA_FORMAT_G729 = ((('9' << 24) | ('2' << 16)) | ('7' << 8)) | 'G', PJMEDIA_FORMAT_ILBC = ((('C' << 24) | ('B' << 16)) | ('L' << 8)) | 'I', PJMEDIA_FORMAT_RGB24 = ((('3' << 24) | ('B' << 16)) | ('G' << 8)) | 'R', PJMEDIA_FORMAT_RGBA = ((('A' << 24) | ('B' << 16)) | ('G' << 8)) | 'R', PJMEDIA_FORMAT_BGRA = ((('A' << 24) | ('R' << 16)) | ('G' << 8)) | 'B', PJMEDIA_FORMAT_RGB32 = PJMEDIA_FORMAT_RGBA, PJMEDIA_FORMAT_DIB = (((' ' << 24) | ('B' << 16)) | ('I' << 8)) | 'D', PJMEDIA_FORMAT_GBRP = ((('P' << 24) | ('R' << 16)) | ('B' << 8)) | 'G', PJMEDIA_FORMAT_AYUV = ((('V' << 24) | ('U' << 16)) | ('Y' << 8)) | 'A', PJMEDIA_FORMAT_YUY2 = ((('2' << 24) | ('Y' << 16)) | ('U' << 8)) | 'Y', PJMEDIA_FORMAT_UYVY = ((('Y' << 24) | ('V' << 16)) | ('Y' << 8)) | 'U', PJMEDIA_FORMAT_YVYU = ((('U' << 24) | ('Y' << 16)) | ('V' << 8)) | 'Y', PJMEDIA_FORMAT_I420 = ((('0' << 24) | ('2' << 16)) | ('4' << 8)) | 'I', PJMEDIA_FORMAT_IYUV = PJMEDIA_FORMAT_I420, PJMEDIA_FORMAT_YV12 = ((('2' << 24) | ('1' << 16)) | ('V' << 8)) | 'Y', PJMEDIA_FORMAT_I422 = ((('2' << 24) | ('2' << 16)) | ('4' << 8)) | 'I', PJMEDIA_FORMAT_I420JPEG = ((('0' << 24) | ('2' << 16)) | ('4' << 8)) | 'J', PJMEDIA_FORMAT_I422JPEG = ((('2' << 24) | ('2' << 16)) | ('4' << 8)) | 'J', PJMEDIA_FORMAT_H261 = ((('1' << 24) | ('6' << 16)) | ('2' << 8)) | 'H', PJMEDIA_FORMAT_H263 = ((('3' << 24) | ('6' << 16)) | ('2' << 8)) | 'H', PJMEDIA_FORMAT_H263P = ((('3' << 24) | ('6' << 16)) | ('2' << 8)) | 'P', PJMEDIA_FORMAT_H264 = ((('4' << 24) | ('6' << 16)) | ('2' << 8)) | 'H', PJMEDIA_FORMAT_MJPEG = ((('G' << 24) | ('P' << 16)) | ('J' << 8)) | 'M', PJMEDIA_FORMAT_MPEG1VIDEO = ((('V' << 24) | ('1' << 16)) | ('P' << 8)) | 'M', PJMEDIA_FORMAT_MPEG2VIDEO = ((('V' << 24) | ('2' << 16)) | ('P' << 8)) | 'M', PJMEDIA_FORMAT_MPEG4 = ((('4' << 24) | ('G' << 16)) | ('P' << 8)) | 'M'} pjmedia_format_id;
+
+typedef enum pjsip_cred_data_type {PJSIP_CRED_DATA_PLAIN_PASSWD = 0, PJSIP_CRED_DATA_DIGEST = 1, PJSIP_CRED_DATA_EXT_AKA = 16} pjsip_cred_data_type;
+
+typedef enum pjsip_dialog_cap_status {PJSIP_DIALOG_CAP_UNSUPPORTED = 0, PJSIP_DIALOG_CAP_SUPPORTED = 1, PJSIP_DIALOG_CAP_UNKNOWN = 2} pjsip_dialog_cap_status;
+
+typedef enum pjsip_event_id_e {PJSIP_EVENT_UNKNOWN, PJSIP_EVENT_TIMER, PJSIP_EVENT_TX_MSG, PJSIP_EVENT_RX_MSG, PJSIP_EVENT_TRANSPORT_ERROR, PJSIP_EVENT_TSX_STATE, PJSIP_EVENT_USER} pjsip_event_id_e;
+
+typedef enum pjsip_status_code {PJSIP_SC_TRYING = 100, PJSIP_SC_RINGING = 180, PJSIP_SC_CALL_BEING_FORWARDED = 181, PJSIP_SC_QUEUED = 182, PJSIP_SC_PROGRESS = 183, PJSIP_SC_OK = 200, PJSIP_SC_ACCEPTED = 202, PJSIP_SC_MULTIPLE_CHOICES = 300, PJSIP_SC_MOVED_PERMANENTLY = 301, PJSIP_SC_MOVED_TEMPORARILY = 302, PJSIP_SC_USE_PROXY = 305, PJSIP_SC_ALTERNATIVE_SERVICE = 380, PJSIP_SC_BAD_REQUEST = 400, PJSIP_SC_UNAUTHORIZED = 401, PJSIP_SC_PAYMENT_REQUIRED = 402, PJSIP_SC_FORBIDDEN = 403, PJSIP_SC_NOT_FOUND = 404, PJSIP_SC_METHOD_NOT_ALLOWED = 405, PJSIP_SC_NOT_ACCEPTABLE = 406, PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED = 407, PJSIP_SC_REQUEST_TIMEOUT = 408, PJSIP_SC_GONE = 410, PJSIP_SC_REQUEST_ENTITY_TOO_LARGE = 413, PJSIP_SC_REQUEST_URI_TOO_LONG = 414, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE = 415, PJSIP_SC_UNSUPPORTED_URI_SCHEME = 416, PJSIP_SC_BAD_EXTENSION = 420, PJSIP_SC_EXTENSION_REQUIRED = 421, PJSIP_SC_SESSION_TIMER_TOO_SMALL = 422, PJSIP_SC_INTERVAL_TOO_BRIEF = 423, PJSIP_SC_TEMPORARILY_UNAVAILABLE = 480, PJSIP_SC_CALL_TSX_DOES_NOT_EXIST = 481, PJSIP_SC_LOOP_DETECTED = 482, PJSIP_SC_TOO_MANY_HOPS = 483, PJSIP_SC_ADDRESS_INCOMPLETE = 484, PJSIP_AC_AMBIGUOUS = 485, PJSIP_SC_BUSY_HERE = 486, PJSIP_SC_REQUEST_TERMINATED = 487, PJSIP_SC_NOT_ACCEPTABLE_HERE = 488, PJSIP_SC_BAD_EVENT = 489, PJSIP_SC_REQUEST_UPDATED = 490, PJSIP_SC_REQUEST_PENDING = 491, PJSIP_SC_UNDECIPHERABLE = 493, PJSIP_SC_INTERNAL_SERVER_ERROR = 500, PJSIP_SC_NOT_IMPLEMENTED = 501, PJSIP_SC_BAD_GATEWAY = 502, PJSIP_SC_SERVICE_UNAVAILABLE = 503, PJSIP_SC_SERVER_TIMEOUT = 504, PJSIP_SC_VERSION_NOT_SUPPORTED = 505, PJSIP_SC_MESSAGE_TOO_LARGE = 513, PJSIP_SC_PRECONDITION_FAILURE = 580, PJSIP_SC_BUSY_EVERYWHERE = 600, PJSIP_SC_DECLINE = 603, PJSIP_SC_DOES_NOT_EXIST_ANYWHERE = 604, PJSIP_SC_NOT_ACCEPTABLE_ANYWHERE = 606, PJSIP_SC_TSX_TIMEOUT = PJSIP_SC_REQUEST_TIMEOUT, PJSIP_SC_TSX_TRANSPORT_ERROR = PJSIP_SC_SERVICE_UNAVAILABLE, PJSIP_SC__force_32bit = 0x7FFFFFFF} pjsip_status_code;
+
+typedef enum pjsip_hdr_e {PJSIP_H_ACCEPT, PJSIP_H_ACCEPT_ENCODING_UNIMP, PJSIP_H_ACCEPT_LANGUAGE_UNIMP, PJSIP_H_ALERT_INFO_UNIMP, PJSIP_H_ALLOW, PJSIP_H_AUTHENTICATION_INFO_UNIMP, PJSIP_H_AUTHORIZATION, PJSIP_H_CALL_ID, PJSIP_H_CALL_INFO_UNIMP, PJSIP_H_CONTACT, PJSIP_H_CONTENT_DISPOSITION_UNIMP, PJSIP_H_CONTENT_ENCODING_UNIMP, PJSIP_H_CONTENT_LANGUAGE_UNIMP, PJSIP_H_CONTENT_LENGTH, PJSIP_H_CONTENT_TYPE, PJSIP_H_CSEQ, PJSIP_H_DATE_UNIMP, PJSIP_H_ERROR_INFO_UNIMP, PJSIP_H_EXPIRES, PJSIP_H_FROM, PJSIP_H_IN_REPLY_TO_UNIMP, PJSIP_H_MAX_FORWARDS, PJSIP_H_MIME_VERSION_UNIMP, PJSIP_H_MIN_EXPIRES, PJSIP_H_ORGANIZATION_UNIMP, PJSIP_H_PRIORITY_UNIMP, PJSIP_H_PROXY_AUTHENTICATE, PJSIP_H_PROXY_AUTHORIZATION, PJSIP_H_PROXY_REQUIRE_UNIMP, PJSIP_H_RECORD_ROUTE, PJSIP_H_REPLY_TO_UNIMP, PJSIP_H_REQUIRE, PJSIP_H_RETRY_AFTER, PJSIP_H_ROUTE, PJSIP_H_SERVER_UNIMP, PJSIP_H_SUBJECT_UNIMP, PJSIP_H_SUPPORTED, PJSIP_H_TIMESTAMP_UNIMP, PJSIP_H_TO, PJSIP_H_UNSUPPORTED, PJSIP_H_USER_AGENT_UNIMP, PJSIP_H_VIA, PJSIP_H_WARNING_UNIMP, PJSIP_H_WWW_AUTHENTICATE, PJSIP_H_OTHER} pjsip_hdr_e;
+
+typedef enum pjsip_transport_type_e {PJSIP_TRANSPORT_UNSPECIFIED, PJSIP_TRANSPORT_UDP, PJSIP_TRANSPORT_TCP, PJSIP_TRANSPORT_TLS, PJSIP_TRANSPORT_SCTP, PJSIP_TRANSPORT_LOOP, PJSIP_TRANSPORT_LOOP_DGRAM, PJSIP_TRANSPORT_START_OTHER, PJSIP_TRANSPORT_IPV6 = 128, PJSIP_TRANSPORT_UDP6 = PJSIP_TRANSPORT_UDP + PJSIP_TRANSPORT_IPV6, PJSIP_TRANSPORT_TCP6 = PJSIP_TRANSPORT_TCP + PJSIP_TRANSPORT_IPV6, PJSIP_TRANSPORT_TLS6 = PJSIP_TRANSPORT_TLS + PJSIP_TRANSPORT_IPV6} pjsip_transport_type_e;
+
+enum pjsip_transport_flags_e {PJSIP_TRANSPORT_RELIABLE = 1, PJSIP_TRANSPORT_SECURE = 2, PJSIP_TRANSPORT_DATAGRAM = 4};
+
+typedef enum pjsip_transport_state {PJSIP_TP_STATE_CONNECTED, PJSIP_TP_STATE_DISCONNECTED} pjsip_transport_state;
+
+typedef enum pjsip_ssl_method {PJSIP_SSL_UNSPECIFIED_METHOD = 0, PJSIP_TLSV1_METHOD = 31, PJSIP_SSLV2_METHOD = 20, PJSIP_SSLV3_METHOD = 30, PJSIP_SSLV23_METHOD = 23} pjsip_ssl_method;
+
+typedef enum pjsip_tsx_state_e {PJSIP_TSX_STATE_NULL, PJSIP_TSX_STATE_CALLING, PJSIP_TSX_STATE_TRYING, PJSIP_TSX_STATE_PROCEEDING, PJSIP_TSX_STATE_COMPLETED, PJSIP_TSX_STATE_CONFIRMED, PJSIP_TSX_STATE_TERMINATED, PJSIP_TSX_STATE_DESTROYED, PJSIP_TSX_STATE_MAX} pjsip_tsx_state_e;
+
+typedef enum pjsip_role_e {PJSIP_ROLE_UAC, PJSIP_ROLE_UAS, PJSIP_UAC_ROLE = PJSIP_ROLE_UAC, PJSIP_UAS_ROLE = PJSIP_ROLE_UAS} pjsip_role_e;
+
+typedef enum pjsip_redirect_op {PJSIP_REDIRECT_REJECT, PJSIP_REDIRECT_ACCEPT, PJSIP_REDIRECT_ACCEPT_REPLACE, PJSIP_REDIRECT_PENDING, PJSIP_REDIRECT_STOP} pjsip_redirect_op;
+
+typedef enum pjrpid_activity {PJRPID_ACTIVITY_UNKNOWN, PJRPID_ACTIVITY_AWAY, PJRPID_ACTIVITY_BUSY} pjrpid_activity;
+
+typedef enum pjsip_evsub_state {PJSIP_EVSUB_STATE_NULL, PJSIP_EVSUB_STATE_SENT, PJSIP_EVSUB_STATE_ACCEPTED, PJSIP_EVSUB_STATE_PENDING, PJSIP_EVSUB_STATE_ACTIVE, PJSIP_EVSUB_STATE_TERMINATED, PJSIP_EVSUB_STATE_UNKNOWN} pjsip_evsub_state;
+
+typedef enum pjsip_inv_state {PJSIP_INV_STATE_NULL, PJSIP_INV_STATE_CALLING, PJSIP_INV_STATE_INCOMING, PJSIP_INV_STATE_EARLY, PJSIP_INV_STATE_CONNECTING, PJSIP_INV_STATE_CONFIRMED, PJSIP_INV_STATE_DISCONNECTED} pjsip_inv_state;
+
+enum pjsua_invalid_id_const_ {PJSUA_INVALID_ID = -1};
+
+typedef enum pjsua_state {PJSUA_STATE_NULL, PJSUA_STATE_CREATED, PJSUA_STATE_INIT, PJSUA_STATE_STARTING, PJSUA_STATE_RUNNING, PJSUA_STATE_CLOSING} pjsua_state;
+
+typedef enum pjsua_stun_use {PJSUA_STUN_USE_DEFAULT, PJSUA_STUN_USE_DISABLED} pjsua_stun_use;
+
+typedef enum pjsua_call_hold_type {PJSUA_CALL_HOLD_TYPE_RFC3264, PJSUA_CALL_HOLD_TYPE_RFC2543} pjsua_call_hold_type;
+
+typedef int pjsua_acc_id;
+
+typedef enum pjsua_destroy_flag {PJSUA_DESTROY_NO_RX_MSG = 1, PJSUA_DESTROY_NO_TX_MSG = 2, PJSUA_DESTROY_NO_NETWORK = PJSUA_DESTROY_NO_RX_MSG | PJSUA_DESTROY_NO_TX_MSG} pjsua_destroy_flag;
+
+typedef enum pjsua_100rel_use {PJSUA_100REL_NOT_USED, PJSUA_100REL_MANDATORY, PJSUA_100REL_OPTIONAL} pjsua_100rel_use;
+
+typedef enum pjsua_sip_timer_use {PJSUA_SIP_TIMER_INACTIVE, PJSUA_SIP_TIMER_OPTIONAL, PJSUA_SIP_TIMER_REQUIRED, PJSUA_SIP_TIMER_ALWAYS} pjsua_sip_timer_use;
+
+typedef enum pjsua_ipv6_use {PJSUA_IPV6_DISABLED, PJSUA_IPV6_ENABLED} pjsua_ipv6_use;
+
+typedef enum pjsua_buddy_status {PJSUA_BUDDY_STATUS_UNKNOWN, PJSUA_BUDDY_STATUS_ONLINE, PJSUA_BUDDY_STATUS_OFFLINE} pjsua_buddy_status;
+
+typedef enum pjsua_call_media_status {PJSUA_CALL_MEDIA_NONE, PJSUA_CALL_MEDIA_ACTIVE, PJSUA_CALL_MEDIA_LOCAL_HOLD, PJSUA_CALL_MEDIA_REMOTE_HOLD, PJSUA_CALL_MEDIA_ERROR} pjsua_call_media_status;
+
+typedef int pjsua_vid_win_id;
+
+typedef int pjsua_call_id;
+
+typedef enum pjsua_med_tp_st {PJSUA_MED_TP_NULL, PJSUA_MED_TP_CREATING, PJSUA_MED_TP_IDLE, PJSUA_MED_TP_INIT, PJSUA_MED_TP_RUNNING, PJSUA_MED_TP_DISABLED} pjsua_med_tp_st;
+
+typedef enum pjsua_call_vid_strm_op {PJSUA_CALL_VID_STRM_NO_OP, PJSUA_CALL_VID_STRM_ADD, PJSUA_CALL_VID_STRM_REMOVE, PJSUA_CALL_VID_STRM_CHANGE_DIR, PJSUA_CALL_VID_STRM_CHANGE_CAP_DEV, PJSUA_CALL_VID_STRM_START_TRANSMIT, PJSUA_CALL_VID_STRM_STOP_TRANSMIT, PJSUA_CALL_VID_STRM_SEND_KEYFRAME} pjsua_call_vid_strm_op;
+
+typedef enum pjsua_vid_req_keyframe_method {PJSUA_VID_REQ_KEYFRAME_SIP_INFO = 1, PJSUA_VID_REQ_KEYFRAME_RTCP_PLI = 2} pjsua_vid_req_keyframe_method;
+
+typedef enum pjsua_call_flag {PJSUA_CALL_UNHOLD = 1, PJSUA_CALL_UPDATE_CONTACT = 2, PJSUA_CALL_INCLUDE_DISABLED_MEDIA = 4} pjsua_call_flag;
+
+typedef enum pjsua_create_media_transport_flag {PJSUA_MED_TP_CLOSE_MEMBER = 1} pjsua_create_media_transport_flag;
+
diff --git a/jni/pjproject-android/pjsip-apps/src/swig/symbols.lst b/jni/pjproject-android/pjsip-apps/src/swig/symbols.lst
new file mode 100644
index 0000000..685c371
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/swig/symbols.lst
@@ -0,0 +1,34 @@
+pj/types.h			pj_status_t pj_constants_ pj_uint8_t pj_int32_t pj_uint32_t pj_uint16_t
+pj/file_io.h			pj_file_access
+pj/log.h			pj_log_decoration
+pj/sock_qos.h			pj_qos_type pj_qos_flag pj_qos_wmm_prio pj_qos_params
+pj/ssl_sock.h			pj_ssl_cipher
+
+pjnath/nat_detect.h          	pj_stun_nat_type
+pjnath/turn_session.h          	pj_turn_tp_type
+
+pjmedia/event.h                 pjmedia_event_type
+pjmedia/transport_srtp.h	pjmedia_srtp_use
+pjmedia/vid_stream.h		pjmedia_vid_stream_rc_method
+pjmedia-videodev/videodev.h	pjmedia_vid_dev_index pjmedia_vid_dev_std_index
+pjmedia-audiodev/audiodev.h 	pjmedia_aud_dev_route pjmedia_aud_dev_cap
+pjmedia/wav_port.h              pjmedia_file_writer_option pjmedia_file_player_option
+pjmedia/types.h                 pjmedia_type pjmedia_dir pjmedia_tp_proto
+pjmedia/format.h		pjmedia_format_id
+
+pjsip/sip_auth.h		pjsip_cred_data_type
+pjsip/sip_dialog.h              pjsip_dialog_cap_status
+pjsip/sip_event.h               pjsip_event_id_e
+pjsip/sip_msg.h			pjsip_status_code pjsip_hdr_e
+pjsip/sip_transport.h		pjsip_transport_type_e pjsip_transport_flags_e pjsip_transport_state
+pjsip/sip_transport_tls.h	pjsip_ssl_method
+pjsip/sip_transaction.h         pjsip_tsx_state_e
+pjsip/sip_types.h               pjsip_role_e
+pjsip/sip_util.h                pjsip_redirect_op
+
+pjsip-simple/rpid.h          	pjrpid_activity
+pjsip-simple/evsub.h		pjsip_evsub_state
+
+pjsip-ua/sip_inv.h              pjsip_inv_state
+
+pjsua-lib/pjsua.h		pjsua_invalid_id_const_ pjsua_state pjsua_stun_use pjsua_call_hold_type pjsua_acc_id pjsua_destroy_flag pjsua_100rel_use pjsua_sip_timer_use pjsua_ipv6_use pjsua_buddy_status pjsua_call_media_status pjsua_vid_win_id pjsua_call_id pjsua_med_tp_st pjsua_call_vid_strm_op pjsua_vid_req_keyframe_method pjsua_call_flag pjsua_create_media_transport_flag