summaryrefslogtreecommitdiff
path: root/pjsip
diff options
context:
space:
mode:
authorLiong Sauw Ming <ming@teluu.com>2014-01-16 05:30:46 +0000
committerLiong Sauw Ming <ming@teluu.com>2014-01-16 05:30:46 +0000
commite56ea14ab8531ee3cec375460577d1b89bf62e26 (patch)
treedf77c3acb961514b2022ee9e030071b691145920 /pjsip
parentbd1c47e995a3a844868f1d4dcc8f77f163ae721b (diff)
Closed #1723: Merging pjsua2 branch into trunk
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@4704 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjsip')
-rw-r--r--pjsip/build/Makefile56
-rw-r--r--pjsip/build/pjsua2_lib.vcproj3220
-rw-r--r--pjsip/docs/doxygen.cfg2
-rw-r--r--pjsip/include/pjsip-simple/evsub.h9
-rw-r--r--pjsip/include/pjsua-lib/pjsua.h34
-rw-r--r--pjsip/include/pjsua2.hpp29
-rw-r--r--pjsip/include/pjsua2/account.hpp1557
-rw-r--r--pjsip/include/pjsua2/call.hpp1713
-rw-r--r--pjsip/include/pjsua2/config.hpp47
-rw-r--r--pjsip/include/pjsua2/doxygen.hpp52
-rw-r--r--pjsip/include/pjsua2/endpoint.hpp1322
-rw-r--r--pjsip/include/pjsua2/json.hpp116
-rw-r--r--pjsip/include/pjsua2/media.hpp1162
-rw-r--r--pjsip/include/pjsua2/persistent.hpp689
-rw-r--r--pjsip/include/pjsua2/presence.hpp296
-rw-r--r--pjsip/include/pjsua2/siptypes.hpp910
-rw-r--r--pjsip/include/pjsua2/types.hpp266
-rw-r--r--pjsip/src/pjsip/sip_endpoint.c2
-rw-r--r--pjsip/src/pjsua-lib/pjsua_aud.c3
-rw-r--r--pjsip/src/pjsua-lib/pjsua_core.c60
-rw-r--r--pjsip/src/pjsua2-test/main.cpp38
-rw-r--r--pjsip/src/pjsua2/account.cpp799
-rw-r--r--pjsip/src/pjsua2/call.cpp719
-rw-r--r--pjsip/src/pjsua2/endpoint.cpp1612
-rw-r--r--pjsip/src/pjsua2/json.cpp544
-rw-r--r--pjsip/src/pjsua2/media.cpp779
-rw-r--r--pjsip/src/pjsua2/persistent.cpp227
-rw-r--r--pjsip/src/pjsua2/presence.cpp190
-rw-r--r--pjsip/src/pjsua2/siptypes.cpp590
-rw-r--r--pjsip/src/pjsua2/types.cpp95
-rw-r--r--pjsip/src/pjsua2/util.hpp45
31 files changed, 17158 insertions, 25 deletions
diff --git a/pjsip/build/Makefile b/pjsip/build/Makefile
index a10fdc7d..a6e474e3 100644
--- a/pjsip/build/Makefile
+++ b/pjsip/build/Makefile
@@ -21,6 +21,7 @@ export PJSIP_LIB:=libpjsip-$(TARGET_NAME)$(LIBEXT)
export PJSIP_UA_LIB:=libpjsip-ua-$(TARGET_NAME)$(LIBEXT)
export PJSIP_SIMPLE_LIB:=libpjsip-simple-$(TARGET_NAME)$(LIBEXT)
export PJSUA_LIB_LIB:=libpjsua-$(TARGET_NAME)$(LIBEXT)
+export PJSUA2_LIB_LIB=../lib/libpjsua2-$(TARGET_NAME)$(LIBEXT)
ifeq ($(PJ_SHARED_LIBRARIES),)
else
@@ -32,6 +33,8 @@ export PJSIP_SIMPLE_SONAME := libpjsip-simple.$(SHLIB_SUFFIX)
export PJSIP_SIMPLE_SHLIB := $(PJSIP_SIMPLE_SONAME).$(PJ_VERSION_MAJOR)
export PJSUA_LIB_SONAME := libpjsua.$(SHLIB_SUFFIX)
export PJSUA_LIB_SHLIB := $(PJSUA_LIB_SONAME).$(PJ_VERSION_MAJOR)
+export PJSUA2_LIB_SONAME := ../lib/libpjsua2.$(SHLIB_SUFFIX)
+export PJSUA2_LIB_SHLIB := $(PJSUA2_LIB_SONAME).$(PJ_VERSION_MAJOR)
endif
###############################################################################
@@ -130,6 +133,31 @@ export PJSUA_LIB_LDFLAGS += $(PJSIP_UA_LDLIB) \
export CC_OUT CC AR RANLIB HOST_MV HOST_RM HOST_RMDIR HOST_MKDIR OBJEXT LD LDOUT
###############################################################################
+# Defines for building pjsua2 library
+#
+export PJSUA2_LIB_SRCDIR = ../src/pjsua2
+export PJSUA2_LIB_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \
+ account.o endpoint.o json.o persistent.o types.o \
+ siptypes.o call.o presence.o media.o
+export PJSUA2_LIB_CFLAGS += $(_CFLAGS) $(PJ_VIDEO_CFLAGS)
+export PJSUA2_LIB_CXXFLAGS = $(PJSUA2_LIB_CFLAGS)
+
+
+###############################################################################
+# Defines for building pjsua2-test application
+#
+export PJSUA2_TEST_SRCDIR = ../src/pjsua2-test
+export PJSUA2_TEST_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \
+ main.o
+export PJSUA2_TEST_CFLAGS += $(_CFLAGS) $(PJ_VIDEO_CFLAGS)
+export PJSUA2_TEST_CXXFLAGS = $(PJSUA2_LIB_CFLAGS)
+export PJSUA2_TEST_LDFLAGS += -lpjsua2-$(TARGET_NAME) -lstdc++ $(PJ_LDFLAGS) $(PJ_LDLIBS) $(LDFLAGS)
+export PJSUA2_TEST_EXE := pjsua2-test-$(TARGET_NAME)$(HOST_EXE)
+
+export CC_OUT CC AR RANLIB HOST_MV HOST_RM HOST_RMDIR HOST_MKDIR OBJEXT LD LDOUT
+
+
+###############################################################################
# Defines for building test application
#
export TEST_SRCDIR = ../src/test
@@ -166,7 +194,9 @@ TARGETS := $(PJSIP_LIB) $(PJSIP_SONAME) \
$(PJSIP_SIMPLE_LIB) $(PJSIP_SIMPLE_SONAME) \
$(PJSIP_UA_LIB) $(PJSIP_UA_SONAME) \
$(PJSUA_LIB_LIB) $(PJSUA_LIB_SONAME) \
- $(TEST_EXE)
+ $(PJSUA2_LIB_LIB) $(PJSUA2_LIB_SONAME) \
+ $(TEST_EXE) \
+ $(PJSUA2_TEST_EXE)
all: $(TARGETS)
@@ -190,7 +220,9 @@ distclean: realclean
.PHONY: $(PJSIP_UA_LIB) $(PJSIP_UA_SONAME)
.PHONY: $(PJSIP_SIMPLE_LIB) $(PJSIP_SIMPLE_SONAME)
.PHONY: $(PJSUA_LIB_LIB) $(PJSUA_LIB_SONAME)
+.PHONY: $(PJSUA2_LIB_LIB) $(PJSUA2_LIB_SONAME)
.PHONY: $(TEST_EXE)
+.PHONY: $(PJSUA2_TEST_EXE)
pjsip: $(PJSIP_LIB)
$(PJSIP_SONAME): $(PJSIP_LIB)
@@ -220,6 +252,14 @@ $(TEST_EXE): $(PJSUA_LIB_LIB) $(PJSUA_LIB_SONAME)
$(TEST_EXE):
$(MAKE) -f $(RULES_MAK) APP=TEST app=pjsip-test $(subst /,$(HOST_PSEP),$(BINDIR)/$@)
+pjsua2-test: $(PJSUA2_TEST_EXE)
+$(PJSUA2_TEST_EXE): $(PJSIP_LIB) $(PJSIP_SONAME)
+$(PJSUA2_TEST_EXE): $(PJSIP_UA_LIB) $(PJSIP_UA_SONAME)
+$(PJSUA2_TEST_EXE): $(PJSIP_SIMPLE_LIB) $(PJSIP_SIMPLE_SONAME)
+$(PJSUA2_TEST_EXE): $(PJSUA_LIB_LIB) $(PJSUA_LIB_SONAME)
+$(PJSUA2_TEST_EXE): $(PJSUA2_LIB_LIB) $(PJSUA2_LIB_SONAME)
+ $(MAKE) -f $(RULES_MAK) APP=PJSUA2_TEST app=pjsua2-test $(subst /,$(HOST_PSEP),$(BINDIR)/$@)
+
.PHONY: pjsip.ko
pjsip.ko:
echo Making $@
@@ -240,31 +280,45 @@ pjsua-lib.ko:
echo Making $@
$(MAKE) -f $(RULES_MAK) APP=PJSUA_LIB app=pjsua-lib $(subst /,$(HOST_PSEP),$(LIBDIR)/$@)
+.PHONY: pjsua2-lib.ko
+pjsua2-lib.ko:
+ echo Making $@
+ $(MAKE) -f $(RULES_MAK) APP=PJSUA2_LIB app=pjsua2-lib $(subst /,$(HOST_PSEP),$(LIBDIR)/$@)
+
clean:
$(MAKE) -f $(RULES_MAK) APP=PJSIP app=pjsip $@
$(MAKE) -f $(RULES_MAK) APP=PJSIP_UA app=pjsip-ua $@
$(MAKE) -f $(RULES_MAK) APP=PJSIP_SIMPLE app=pjsip-simple $@
$(MAKE) -f $(RULES_MAK) APP=PJSUA_LIB app=pjsua-lib $@
+ $(MAKE) -f $(RULES_MAK) APP=PJSUA2_LIB app=pjsua2-lib $@
$(MAKE) -f $(RULES_MAK) APP=TEST app=pjsip-test $@
+ $(MAKE) -f $(RULES_MAK) APP=PJSUA2_TEST app=pjsua2-test $@
depend:
$(MAKE) -f $(RULES_MAK) APP=PJSIP app=pjsip $@
$(MAKE) -f $(RULES_MAK) APP=PJSIP_UA app=pjsip-ua $@
$(MAKE) -f $(RULES_MAK) APP=PJSIP_SIMPLE app=pjsip-simple $@
$(MAKE) -f $(RULES_MAK) APP=PJSUA_LIB app=pjsua-lib $@
+ $(MAKE) -f $(RULES_MAK) APP=PJSUA2_LIB app=pjsua2-lib $@
$(MAKE) -f $(RULES_MAK) APP=TEST app=pjsip-test $@
+ $(MAKE) -f $(RULES_MAK) APP=PJSUA2_TEST app=pjsua2-test $@
echo '$(BINDIR)/$(TEST_EXE): $(PJMEDIA_LIB) $(LIBDIR)/$(PJSUA_LIB_LIB) $(LIBDIR)/$(PJSIP_SIMPLE_LIB) $(LIBDIR)/$(PJSIP_UA_LIB) $(LIBDIR)/$(PJSIP_LIB) $(PJNATH_LIB) $(PJLIB_UTIL_LIB) $(PJLIB_LIB)' >> .pjsip-test-$(TARGET_NAME).depend
+ echo '$(BINDIR)/$(PJSUA2_TEST_EXE): $(PJSUA2_LIB_LIB) $(PJMEDIA_LIB) $(LIBDIR)/$(PJSUA_LIB_LIB) $(LIBDIR)/$(PJSIP_SIMPLE_LIB) $(LIBDIR)/$(PJSIP_UA_LIB) $(LIBDIR)/$(PJSIP_LIB) $(PJNATH_LIB) $(PJLIB_UTIL_LIB) $(PJLIB_LIB)' >> .pjsua2-test-$(TARGET_NAME).depend
realclean:
$(subst @@,$(subst /,$(HOST_PSEP),.pjsip-$(TARGET_NAME).depend),$(HOST_RMR))
$(subst @@,$(subst /,$(HOST_PSEP),.pjsip-ua-$(TARGET_NAME).depend),$(HOST_RMR))
$(subst @@,$(subst /,$(HOST_PSEP),.pjsip-simple-$(TARGET_NAME).depend),$(HOST_RMR))
$(subst @@,$(subst /,$(HOST_PSEP),.pjsua-lib-$(TARGET_NAME).depend),$(HOST_RMR))
+ $(subst @@,$(subst /,$(HOST_PSEP),.pjsua2-lib-$(TARGET_NAME).depend),$(HOST_RMR))
+ $(subst @@,$(subst /,$(HOST_PSEP),.pjsua2-test-$(TARGET_NAME).depend),$(HOST_RMR))
$(MAKE) -f $(RULES_MAK) APP=PJSIP app=pjsip $@
$(MAKE) -f $(RULES_MAK) APP=PJSIP_UA app=pjsip-ua $@
$(MAKE) -f $(RULES_MAK) APP=PJSIP_SIMPLE app=pjsip-simple $@
$(MAKE) -f $(RULES_MAK) APP=TEST app=pjsip-test $@
$(MAKE) -f $(RULES_MAK) APP=PJSUA_LIB app=pjsua-lib $@
+ $(MAKE) -f $(RULES_MAK) APP=PJSUA2_LIB app=pjsua2-lib $@
+ $(MAKE) -f $(RULES_MAK) APP=PJSUA2_TEST app=pjsua2-test $@
diff --git a/pjsip/build/pjsua2_lib.vcproj b/pjsip/build/pjsua2_lib.vcproj
new file mode 100644
index 00000000..61f725ac
--- /dev/null
+++ b/pjsip/build/pjsua2_lib.vcproj
@@ -0,0 +1,3220 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="pjsua2_lib"
+ ProjectGUID="{B82CDD25-6903-430E-BD38-D8129A2015C1}"
+ RootNamespace="pjsua2_lib"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="Pocket PC 2003 (ARMV4)"
+ />
+ <Platform
+ Name="Smartphone 2003 (ARMV4)"
+ />
+ <Platform
+ Name="x64"
+ />
+ <Platform
+ Name="Windows Mobile 6 Standard SDK (ARMV4I)"
+ />
+ <Platform
+ Name="Windows Mobile 6 Professional SDK (ARMV4I)"
+ />
+ <Platform
+ Name="Windows Mobile 5.0 Pocket PC SDK (ARMV4I)"
+ />
+ <Platform
+ Name="Windows Mobile 5.0 Smartphone SDK (ARMV4I)"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-common-defaults.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|Pocket PC 2003 (ARMV4)"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-common-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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|Smartphone 2003 (ARMV4)"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-common-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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|x64"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-common-defaults.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|Windows Mobile 6 Standard SDK (ARMV4I)"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-common-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-common-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-release-defaults.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Pocket PC 2003 (ARMV4)"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-release-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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|Smartphone 2003 (ARMV4)"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-release-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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|x64"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-release-defaults.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Windows Mobile 6 Standard SDK (ARMV4I)"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-release-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-release-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-common-defaults.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug-Static|Pocket PC 2003 (ARMV4)"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-common-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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|Smartphone 2003 (ARMV4)"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-common-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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|x64"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-common-defaults.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug-Static|Windows Mobile 6 Standard SDK (ARMV4I)"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-common-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-common-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-release-defaults.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release-Dynamic|Pocket PC 2003 (ARMV4)"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-release-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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|Smartphone 2003 (ARMV4)"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-release-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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|x64"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-release-defaults.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release-Dynamic|Windows Mobile 6 Standard SDK (ARMV4I)"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-release-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-release-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-common-defaults.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug-Dynamic|Pocket PC 2003 (ARMV4)"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-common-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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|Smartphone 2003 (ARMV4)"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-common-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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|x64"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-common-defaults.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug-Dynamic|Windows Mobile 6 Standard SDK (ARMV4I)"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-common-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-common-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-release-defaults.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release-Static|Pocket PC 2003 (ARMV4)"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-release-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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|Smartphone 2003 (ARMV4)"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-release-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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|x64"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-release-defaults.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release-Static|Windows Mobile 6 Standard SDK (ARMV4I)"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-release-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm6-release-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua2-lib-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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 5.0 Pocket PC SDK (ARMV4I)"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm5-common-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua-lib-$(TargetCPU)-wm5ppc-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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 5.0 Smartphone SDK (ARMV4I)"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm5-common-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua-lib-$(TargetCPU)-wm5sp-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm5-release-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua-lib-$(TargetCPU)-wm5ppc-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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 Smartphone SDK (ARMV4I)"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm5-release-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua-lib-$(TargetCPU)-wm5sp-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm5-common-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua-lib-$(TargetCPU)-wm5ppc-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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 Smartphone SDK (ARMV4I)"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm5-common-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua-lib-$(TargetCPU)-wm5sp-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm5-release-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua-lib-$(TargetCPU)-wm5ppc-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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 Smartphone SDK (ARMV4I)"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm5-release-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua-lib-$(TargetCPU)-wm5sp-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm5-common-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua-lib-$(TargetCPU)-wm5ppc-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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 Smartphone SDK (ARMV4I)"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm5-common-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua-lib-$(TargetCPU)-wm5sp-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm5-release-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua-lib-$(TargetCPU)-wm5ppc-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <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 Smartphone SDK (ARMV4I)"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm5-release-defaults.vsprops"
+ 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="../include,../../pjmedia/include,../../pjlib-util/include,../../pjlib/include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\lib\pjsua-lib-$(TargetCPU)-wm5sp-vc$(VSVer)-$(ConfigurationName).lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCCodeSignTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ <DeploymentTool
+ ForceDirty="-1"
+ RemoteDirectory=""
+ RegisterOutput="0"
+ AdditionalFiles=""
+ />
+ <DebuggerTool
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+ >
+ <File
+ RelativePath="..\src\pjsua2\account.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\src\pjsua2\call.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\src\pjsua2\endpoint.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\src\pjsua2\json.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\src\pjsua2\media.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\src\pjsua2\persistent.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\src\pjsua2\presence.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\src\pjsua2\siptypes.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\src\pjsua2\types.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\src\pjsua2\util.hpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl"
+ >
+ <File
+ RelativePath="..\include\pjsua2\account.hpp"
+ >
+ </File>
+ <File
+ RelativePath="..\include\pjsua2\call.hpp"
+ >
+ </File>
+ <File
+ RelativePath="..\include\pjsua2\config.hpp"
+ >
+ </File>
+ <File
+ RelativePath="..\include\pjsua2\doxygen.hpp"
+ >
+ </File>
+ <File
+ RelativePath="..\include\pjsua2\endpoint.hpp"
+ >
+ </File>
+ <File
+ RelativePath="..\include\pjsua2\json.hpp"
+ >
+ </File>
+ <File
+ RelativePath="..\include\pjsua2\media.hpp"
+ >
+ </File>
+ <File
+ RelativePath="..\include\pjsua2\persistent.hpp"
+ >
+ </File>
+ <File
+ RelativePath="..\include\pjsua2\presence.hpp"
+ >
+ </File>
+ <File
+ RelativePath="..\include\pjsua2\siptypes.hpp"
+ >
+ </File>
+ <File
+ RelativePath="..\include\pjsua2\types.hpp"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/pjsip/docs/doxygen.cfg b/pjsip/docs/doxygen.cfg
index cd3f8e4c..e3e6dc9f 100644
--- a/pjsip/docs/doxygen.cfg
+++ b/pjsip/docs/doxygen.cfg
@@ -356,7 +356,7 @@ INPUT = docs include
# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp
# *.h++ *.idl *.odl
-FILE_PATTERNS = *.h
+FILE_PATTERNS = *.h *.hpp
# The RECURSIVE tag can be used to turn specify whether or not subdirectories
# should be searched for input files as well. Possible values are YES and NO.
diff --git a/pjsip/include/pjsip-simple/evsub.h b/pjsip/include/pjsip-simple/evsub.h
index b0159bff..2dc4d69c 100644
--- a/pjsip/include/pjsip-simple/evsub.h
+++ b/pjsip/include/pjsip-simple/evsub.h
@@ -58,7 +58,7 @@ typedef struct pjsip_evsub pjsip_evsub;
* will be set to PJSIP_EVSUB_STATE_UNKNOWN, and the token will be kept
* in state_str member of the susbcription structure.
*/
-enum pjsip_evsub_state
+typedef enum pjsip_evsub_state
{
PJSIP_EVSUB_STATE_NULL, /**< State is NULL. */
PJSIP_EVSUB_STATE_SENT, /**< Client has sent SUBSCRIBE request. */
@@ -70,12 +70,7 @@ enum pjsip_evsub_state
PJSIP_EVSUB_STATE_UNKNOWN, /**< Subscription state can not be determined.
Application can query the state by
calling #pjsip_evsub_get_state_name().*/
-};
-
-/**
- * @see pjsip_evsub_state
- */
-typedef enum pjsip_evsub_state pjsip_evsub_state;
+} pjsip_evsub_state;
/**
diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h
index bca343ba..7ee3d6cf 100644
--- a/pjsip/include/pjsua-lib/pjsua.h
+++ b/pjsip/include/pjsua-lib/pjsua.h
@@ -251,7 +251,10 @@ PJ_BEGIN_DECL
*/
/** Constant to identify invalid ID for all sorts of IDs. */
-#define PJSUA_INVALID_ID (-1)
+enum pjsua_invalid_id_const_
+{
+ PJSUA_INVALID_ID = -1
+};
/** Disabled features temporarily for media reorganization */
#define DISABLED_FOR_TICKET_1185 0
@@ -1880,6 +1883,26 @@ PJ_DECL(int) pjsua_handle_events(unsigned msec_timeout);
/**
+ * Register a thread to poll for events. This function should be
+ * called by an external worker thread, and it will block polling
+ * for events until the library is destroyed.
+ *
+ * @return PJ_SUCCESS if things are working correctly
+ * or an error polling cannot be done for some
+ * reason.
+ */
+PJ_DECL(pj_status_t) pjsua_register_worker_thread(const char *name);
+
+
+/**
+ * Signal all worker threads to quit. This will only wait until internal
+ * threads are done. For external threads, application must perform
+ * its own waiting for the external threads to quit from
+ * pjsua_register_worker_thread() function.
+ */
+PJ_DECL(void) pjsua_stop_worker_threads(void);
+
+/**
* Create memory pool to be used by the application. Once application
* finished using the pool, it must be released with pj_pool_release().
*
@@ -5777,6 +5800,9 @@ typedef struct pjsua_conf_port_info
/** Port name. */
pj_str_t name;
+ /** Format. */
+ pjmedia_format format;
+
/** Clock rate. */
unsigned clock_rate;
@@ -5789,6 +5815,12 @@ typedef struct pjsua_conf_port_info
/** Bits per sample */
unsigned bits_per_sample;
+ /** Tx level adjustment. */
+ float tx_level_adj;
+
+ /** Rx level adjustment. */
+ float rx_level_adj;
+
/** Number of listeners in the array. */
unsigned listener_cnt;
diff --git a/pjsip/include/pjsua2.hpp b/pjsip/include/pjsua2.hpp
new file mode 100644
index 00000000..d1a12ed6
--- /dev/null
+++ b/pjsip/include/pjsua2.hpp
@@ -0,0 +1,29 @@
+/* $Id$ */
+/*
+ * 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
+ */
+#ifndef __PJSUA2_HPP__
+#define __PJSUA2_HPP__
+
+#include <pjsua2/endpoint.hpp>
+#include <pjsua2/account.hpp>
+#include <pjsua2/call.hpp>
+#include <pjsua2/presence.hpp>
+#include <pjsua2/media.hpp>
+#include <pjsua2/json.hpp>
+
+#endif
diff --git a/pjsip/include/pjsua2/account.hpp b/pjsip/include/pjsua2/account.hpp
new file mode 100644
index 00000000..2a7199f2
--- /dev/null
+++ b/pjsip/include/pjsua2/account.hpp
@@ -0,0 +1,1557 @@
+/* $Id$ */
+/*
+ * 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
+ */
+#ifndef __PJSUA2_ACCOUNT_HPP__
+#define __PJSUA2_ACCOUNT_HPP__
+
+/**
+ * @file pjsua2/account.hpp
+ * @brief PJSUA2 Account operations
+ */
+#include <pjsua-lib/pjsua.h>
+#include <pjsua2/persistent.hpp>
+#include <pjsua2/presence.hpp>
+#include <pjsua2/siptypes.hpp>
+
+/** PJSUA2 API is inside pj namespace */
+namespace pj
+{
+
+/**
+ * @defgroup PJSUA2_ACC Account
+ * @ingroup PJSUA2_Ref
+ * @{
+ */
+
+using std::string;
+
+/**
+ * Account registration config. This will be specified in AccountConfig.
+ */
+struct AccountRegConfig : public PersistentObject
+{
+ /**
+ * This is the URL to be put in the request URI for the registration,
+ * and will look something like "sip:serviceprovider".
+ *
+ * This field should be specified if registration is desired. If the
+ * value is empty, no account registration will be performed.
+ */
+ string registrarUri;
+
+ /**
+ * Specify whether the account should register as soon as it is
+ * added to the UA. Application can set this to PJ_FALSE and control
+ * the registration manually with pjsua_acc_set_registration().
+ *
+ * Default: True
+ */
+ bool registerOnAdd;
+
+ /**
+ * The optional custom SIP headers to be put in the registration
+ * request.
+ */
+ SipHeaderVector headers;
+
+ /**
+ * Optional interval for registration, in seconds. If the value is zero,
+ * default interval will be used (PJSUA_REG_INTERVAL, 300 seconds).
+ */
+ unsigned timeoutSec;
+
+ /**
+ * Specify interval of auto registration retry upon registration failure
+ * (including caused by transport problem), in second. Set to 0 to
+ * disable auto re-registration. Note that if the registration retry
+ * occurs because of transport failure, the first retry will be done
+ * after \a firstRetryIntervalSec seconds instead. Also note that
+ * the interval will be randomized slightly by approximately +/- ten
+ * seconds to avoid all clients re-registering at the same time.
+ *
+ * See also \a firstRetryIntervalSec setting.
+ *
+ * Default: PJSUA_REG_RETRY_INTERVAL
+ */
+ unsigned retryIntervalSec;
+
+ /**
+ * This specifies the interval for the first registration retry. The
+ * registration retry is explained in \a retryIntervalSec. Note that
+ * the value here will also be randomized by +/- ten seconds.
+ *
+ * Default: 0
+ */
+ unsigned firstRetryIntervalSec;
+
+ /**
+ * Specify the number of seconds to refresh the client registration
+ * before the registration expires.
+ *
+ * Default: PJSIP_REGISTER_CLIENT_DELAY_BEFORE_REFRESH, 5 seconds
+ */
+ unsigned delayBeforeRefreshSec;
+
+ /**
+ * Specify whether calls of the configured account should be dropped
+ * after registration failure and an attempt of re-registration has
+ * also failed.
+ *
+ * Default: FALSE (disabled)
+ */
+ bool dropCallsOnFail;
+
+ /**
+ * Specify the maximum time to wait for unregistration requests to
+ * complete during library shutdown sequence.
+ *
+ * Default: PJSUA_UNREG_TIMEOUT
+ */
+ unsigned unregWaitSec;
+
+ /**
+ * Specify how the registration uses the outbound and account proxy
+ * settings. This controls if and what Route headers will appear in
+ * the REGISTER request of this account. The value is bitmask combination
+ * of PJSUA_REG_USE_OUTBOUND_PROXY and PJSUA_REG_USE_ACC_PROXY bits.
+ * If the value is set to 0, the REGISTER request will not use any proxy
+ * (i.e. it will not have any Route headers).
+ *
+ * Default: 3 (PJSUA_REG_USE_OUTBOUND_PROXY | PJSUA_REG_USE_ACC_PROXY)
+ */
+ unsigned proxyUse;
+
+public:
+ /**
+ * Read this object from a container node.
+ *
+ * @param node Container to read values from.
+ */
+ virtual void readObject(const ContainerNode &node) throw(Error);
+
+ /**
+ * Write this object to a container node.
+ *
+ * @param node Container to write values to.
+ */
+ virtual void writeObject(ContainerNode &node) const throw(Error);
+
+};
+
+/** Array of SIP credentials */
+typedef std::vector<AuthCredInfo> AuthCredInfoVector;
+
+/**
+ * Various SIP settings for the account. This will be specified in
+ * AccountConfig.
+ */
+struct AccountSipConfig : public PersistentObject
+{
+ /**
+ * Array of credentials. If registration is desired, normally there should
+ * be at least one credential specified, to successfully authenticate
+ * against the service provider. More credentials can be specified, for
+ * example when the requests are expected to be challenged by the
+ * proxies in the route set.
+ */
+ AuthCredInfoVector authCreds;
+
+ /**
+ * Array of proxy servers to visit for outgoing requests. Each of the
+ * entry is translated into one Route URI.
+ */
+ StringVector proxies;
+
+ /**
+ * Optional URI to be put as Contact for this account. It is recommended
+ * that this field is left empty, so that the value will be calculated
+ * automatically based on the transport address.
+ */
+ string contactForced;
+
+ /**
+ * Additional parameters that will be appended in the Contact header
+ * for this account. This will affect the Contact header in all SIP
+ * messages sent on behalf of this account, including but not limited to
+ * REGISTER, INVITE, and SUBCRIBE requests or responses.
+ *
+ * The parameters should be preceeded by semicolon, and all strings must
+ * be properly escaped. Example:
+ * ";my-param=X;another-param=Hi%20there"
+ */
+ string contactParams;
+
+ /**
+ * Additional URI parameters that will be appended in the Contact URI
+ * for this account. This will affect the Contact URI in all SIP
+ * messages sent on behalf of this account, including but not limited to
+ * REGISTER, INVITE, and SUBCRIBE requests or responses.
+ *
+ * The parameters should be preceeded by semicolon, and all strings must
+ * be properly escaped. Example:
+ * ";my-param=X;another-param=Hi%20there"
+ */
+ string contactUriParams;
+
+
+ /**
+ * If this flag is set, the authentication client framework will
+ * send an empty Authorization header in each initial request.
+ * Default is no.
+ */
+ bool authInitialEmpty;
+
+ /**
+ * Specify the algorithm to use when empty Authorization header
+ * is to be sent for each initial request (see above)
+ */
+ string authInitialAlgorithm;
+
+ /**
+ * Optionally bind this account to specific transport. This normally is
+ * not a good idea, as account should be able to send requests using
+ * any available transports according to the destination. But some
+ * application may want to have explicit control over the transport to
+ * use, so in that case it can set this field.
+ *
+ * Default: -1 (PJSUA_INVALID_ID)
+ *
+ * @see Account::setTransport()
+ */
+ TransportId transportId;
+
+public:
+ /**
+ * Read this object from a container node.
+ *
+ * @param node Container to read values from.
+ */
+ virtual void readObject(const ContainerNode &node) throw(Error);
+
+ /**
+ * Write this object to a container node.
+ *
+ * @param node Container to write values to.
+ */
+ virtual void writeObject(ContainerNode &node) const throw(Error);
+};
+
+/**
+ * Account's call settings. This will be specified in AccountConfig.
+ */
+struct AccountCallConfig : public PersistentObject
+{
+ /**
+ * Specify how to offer call hold to remote peer. Please see the
+ * documentation on pjsua_call_hold_type for more info.
+ *
+ * Default: PJSUA_CALL_HOLD_TYPE_DEFAULT
+ */
+ pjsua_call_hold_type holdType;
+
+ /**
+ * Specify how support for reliable provisional response (100rel/
+ * PRACK) should be used for all sessions in this account. See the
+ * documentation of pjsua_100rel_use enumeration for more info.
+ *
+ * Default: PJSUA_100REL_NOT_USED
+ */
+ pjsua_100rel_use prackUse;
+
+ /**
+ * Specify the usage of Session Timers for all sessions. See the
+ * pjsua_sip_timer_use for possible values.
+ *
+ * Default: PJSUA_SIP_TIMER_OPTIONAL
+ */
+ pjsua_sip_timer_use timerUse;
+
+ /**
+ * Specify minimum Session Timer expiration period, in seconds.
+ * Must not be lower than 90. Default is 90.
+ */
+ unsigned timerMinSESec;
+
+ /**
+ * Specify Session Timer expiration period, in seconds.
+ * Must not be lower than timerMinSE. Default is 1800.
+ */
+ unsigned timerSessExpiresSec;
+
+public:
+ /**
+ * Read this object from a container node.
+ *
+ * @param node Container to read values from.
+ */
+ virtual void readObject(const ContainerNode &node) throw(Error);
+
+ /**
+ * Write this object to a container node.
+ *
+ * @param node Container to write values to.
+ */
+ virtual void writeObject(ContainerNode &node) const throw(Error);
+};
+
+/**
+ * Account presence config. This will be specified in AccountConfig.
+ */
+struct AccountPresConfig : public PersistentObject
+{
+ /**
+ * The optional custom SIP headers to be put in the presence
+ * subscription request.
+ */
+ SipHeaderVector headers;
+
+ /**
+ * If this flag is set, the presence information of this account will
+ * be PUBLISH-ed to the server where the account belongs.
+ *
+ * Default: PJ_FALSE
+ */
+ bool publishEnabled;
+
+ /**
+ * Specify whether the client publication session should queue the
+ * PUBLISH request should there be another PUBLISH transaction still
+ * pending. If this is set to false, the client will return error
+ * on the PUBLISH request if there is another PUBLISH transaction still
+ * in progress.
+ *
+ * Default: PJSIP_PUBLISHC_QUEUE_REQUEST (TRUE)
+ */
+ bool publishQueue;
+
+ /**
+ * Maximum time to wait for unpublication transaction(s) to complete
+ * during shutdown process, before sending unregistration. The library
+ * tries to wait for the unpublication (un-PUBLISH) to complete before
+ * sending REGISTER request to unregister the account, during library
+ * shutdown process. If the value is set too short, it is possible that
+ * the unregistration is sent before unpublication completes, causing
+ * unpublication request to fail.
+ *
+ * Value is in milliseconds.
+ *
+ * Default: PJSUA_UNPUBLISH_MAX_WAIT_TIME_MSEC (2000)
+ */
+ unsigned publishShutdownWaitMsec;
+
+ /**
+ * Optional PIDF tuple ID for outgoing PUBLISH and NOTIFY. If this value
+ * is not specified, a random string will be used.
+ */
+ string pidfTupleId;
+
+public:
+ /**
+ * Read this object from a container node.
+ *
+ * @param node Container to read values from.
+ */
+ virtual void readObject(const ContainerNode &node) throw(Error);
+
+ /**
+ * Write this object to a container node.
+ *
+ * @param node Container to write values to.
+ */
+ virtual void writeObject(ContainerNode &node) const throw(Error);
+};
+
+/**
+ * Account MWI (Message Waiting Indication) settings. This will be specified
+ * in AccountConfig.
+ */
+struct AccountMwiConfig : public PersistentObject
+{
+ /**
+ * Subscribe to message waiting indication events (RFC 3842).
+ *
+ * See also UaConfig.mwiUnsolicitedEnabled setting.
+ *
+ * Default: FALSE
+ */
+ bool enabled;
+
+ /**
+ * Specify the default expiration time (in seconds) for Message
+ * Waiting Indication (RFC 3842) event subscription. This must not
+ * be zero.
+ *
+ * Default: PJSIP_MWI_DEFAULT_EXPIRES (3600)
+ */
+ unsigned expirationSec;
+
+public:
+ /**
+ * Read this object from a container node.
+ *
+ * @param node Container to read values from.
+ */
+ virtual void readObject(const ContainerNode &node) throw(Error);
+
+ /**
+ * Write this object to a container node.
+ *
+ * @param node Container to write values to.
+ */
+ virtual void writeObject(ContainerNode &node) const throw(Error);
+};
+
+/**
+ * Account's NAT (Network Address Translation) settings. This will be
+ * specified in AccountConfig.
+ */
+struct AccountNatConfig : public PersistentObject
+{
+ /**
+ * Control the use of STUN for the SIP signaling.
+ *
+ * Default: PJSUA_STUN_USE_DEFAULT
+ */
+ pjsua_stun_use sipStunUse;
+
+ /**
+ * Control the use of STUN for the media transports.
+ *
+ * Default: PJSUA_STUN_USE_DEFAULT
+ */
+ pjsua_stun_use mediaStunUse;
+
+ /**
+ * Enable ICE for the media transport.
+ *
+ * Default: False
+ */
+ bool iceEnabled;
+
+ /**
+ * Set the maximum number of ICE host candidates.
+ *
+ * Default: -1 (maximum not set)
+ */
+ int iceMaxHostCands;
+
+ /**
+ * Specify whether to use aggressive nomination.
+ *
+ * Default: True
+ */
+ bool iceAggressiveNomination;
+
+ /**
+ * For controlling agent if it uses regular nomination, specify the delay
+ * to perform nominated check (connectivity check with USE-CANDIDATE
+ * attribute) after all components have a valid pair.
+ *
+ * Default value is PJ_ICE_NOMINATED_CHECK_DELAY.
+ */
+ unsigned iceNominatedCheckDelayMsec;
+
+ /**
+ * For a controlled agent, specify how long it wants to wait (in
+ * milliseconds) for the controlling agent to complete sending
+ * connectivity check with nominated flag set to true for all components
+ * after the controlled agent has found that all connectivity checks in
+ * its checklist have been completed and there is at least one successful
+ * (but not nominated) check for every component.
+ *
+ * Default value for this option is
+ * ICE_CONTROLLED_AGENT_WAIT_NOMINATION_TIMEOUT. Specify -1 to disable
+ * this timer.
+ */
+ int iceWaitNominationTimeoutMsec;
+
+ /**
+ * Disable RTCP component.
+ *
+ * Default: False
+ */
+ bool iceNoRtcp;
+
+ /**
+ * Always send re-INVITE/UPDATE after ICE negotiation regardless of whether
+ * the default ICE transport address is changed or not. When this is set
+ * to False, re-INVITE/UPDATE will be sent only when the default ICE
+ * transport address is changed.
+ *
+ * Default: yes
+ */
+ bool iceAlwaysUpdate;
+
+ /**
+ * Enable TURN candidate in ICE.
+ */
+ bool turnEnabled;
+
+ /**
+ * Specify TURN domain name or host name, in in "DOMAIN:PORT" or
+ * "HOST:PORT" format.
+ */
+ string turnServer;
+
+ /**
+ * Specify the connection type to be used to the TURN server. Valid
+ * values are PJ_TURN_TP_UDP or PJ_TURN_TP_TCP.
+ *
+ * Default: PJ_TURN_TP_UDP
+ */
+ pj_turn_tp_type turnConnType;
+
+ /**
+ * Specify the username to authenticate with the TURN server.
+ */
+ string turnUserName;
+
+ /**
+ * Specify the type of password. Currently this must be zero to
+ * indicate plain-text password will be used in the password.
+ */
+ int turnPasswordType;
+
+ /**
+ * Specify the password to authenticate with the TURN server.
+ */
+ string turnPassword;
+
+ /**
+ * This option is used to update the transport address and the Contact
+ * header of REGISTER request. When this option is enabled, the library
+ * will keep track of the public IP address from the response of REGISTER
+ * request. Once it detects that the address has changed, it will
+ * unregister current Contact, update the Contact with transport address
+ * learned from Via header, and register a new Contact to the registrar.
+ * This will also update the public name of UDP transport if STUN is
+ * configured.
+ *
+ * See also contactRewriteMethod field.
+ *
+ * Default: TRUE
+ */
+ int contactRewriteUse;
+
+ /**
+ * Specify how Contact update will be done with the registration, if
+ * \a contactRewriteEnabled is enabled. The value is bitmask combination of
+ * \a pjsua_contact_rewrite_method. See also pjsua_contact_rewrite_method.
+ *
+ * Value PJSUA_CONTACT_REWRITE_UNREGISTER(1) is the legacy behavior.
+ *
+ * Default value: PJSUA_CONTACT_REWRITE_METHOD
+ * (PJSUA_CONTACT_REWRITE_NO_UNREG | PJSUA_CONTACT_REWRITE_ALWAYS_UPDATE)
+ */
+ int contactRewriteMethod;
+
+ /**
+ * This option is used to overwrite the "sent-by" field of the Via header
+ * for outgoing messages with the same interface address as the one in
+ * the REGISTER request, as long as the request uses the same transport
+ * instance as the previous REGISTER request.
+ *
+ * Default: TRUE
+ */
+ int viaRewriteUse;
+
+ /**
+ * This option controls whether the IP address in SDP should be replaced
+ * with the IP address found in Via header of the REGISTER response, ONLY
+ * when STUN and ICE are not used. If the value is FALSE (the original
+ * behavior), then the local IP address will be used. If TRUE, and when
+ * STUN and ICE are disabled, then the IP address found in registration
+ * response will be used.
+ *
+ * Default: PJ_FALSE (no)
+ */
+ int sdpNatRewriteUse;
+
+ /**
+ * Control the use of SIP outbound feature. SIP outbound is described in
+ * RFC 5626 to enable proxies or registrar to send inbound requests back
+ * to UA using the same connection initiated by the UA for its
+ * registration. This feature is highly useful in NAT-ed deployemtns,
+ * hence it is enabled by default.
+ *
+ * Note: currently SIP outbound can only be used with TCP and TLS
+ * transports. If UDP is used for the registration, the SIP outbound
+ * feature will be silently ignored for the account.
+ *
+ * Default: TRUE
+ */
+ int sipOutboundUse;
+
+ /**
+ * Specify SIP outbound (RFC 5626) instance ID to be used by this
+ * account. If empty, an instance ID will be generated based on
+ * the hostname of this agent. If application specifies this parameter, the
+ * value will look like "<urn:uuid:00000000-0000-1000-8000-AABBCCDDEEFF>"
+ * without the double-quotes.
+ *
+ * Default: empty
+ */
+ string sipOutboundInstanceId;
+
+ /**
+ * Specify SIP outbound (RFC 5626) registration ID. The default value
+ * is empty, which would cause the library to automatically generate
+ * a suitable value.
+ *
+ * Default: empty
+ */
+ string sipOutboundRegId;
+
+ /**
+ * Set the interval for periodic keep-alive transmission for this account.
+ * If this value is zero, keep-alive will be disabled for this account.
+ * The keep-alive transmission will be sent to the registrar's address,
+ * after successful registration.
+ *
+ * Default: 15 (seconds)
+ */
+ unsigned udpKaIntervalSec;
+
+ /**
+ * Specify the data to be transmitted as keep-alive packets.
+ *
+ * Default: CR-LF
+ */
+ string udpKaData;
+
+public:
+ /**
+ * Read this object from a container node.
+ *
+ * @param node Container to read values from.
+ */
+ virtual void readObject(const ContainerNode &node) throw(Error);
+
+ /**
+ * Write this object to a container node.
+ *
+ * @param node Container to write values to.
+ */
+ virtual void writeObject(ContainerNode &node) const throw(Error);
+};
+
+/**
+ * Account media config (applicable for both audio and video). This will be
+ * specified in AccountConfig.
+ */
+struct AccountMediaConfig : public PersistentObject
+{
+ /**
+ * Media transport (RTP) configuration.
+ */
+ TransportConfig transportConfig;
+
+ /**
+ * If remote sends SDP answer containing more than one format or codec in
+ * the media line, send re-INVITE or UPDATE with just one codec to lock
+ * which codec to use.
+ *
+ * Default: True (Yes).
+ */
+ bool lockCodecEnabled;
+
+ /**
+ * Specify whether stream keep-alive and NAT hole punching with
+ * non-codec-VAD mechanism (see PJMEDIA_STREAM_ENABLE_KA) is enabled
+ * for this account.
+ *
+ * Default: False
+ */
+ bool streamKaEnabled;
+
+ /**
+ * Specify whether secure media transport should be used for this account.
+ * Valid values are PJMEDIA_SRTP_DISABLED, PJMEDIA_SRTP_OPTIONAL, and
+ * PJMEDIA_SRTP_MANDATORY.
+ *
+ * Default: PJSUA_DEFAULT_USE_SRTP
+ */
+ pjmedia_srtp_use srtpUse;
+
+ /**
+ * Specify whether SRTP requires secure signaling to be used. This option
+ * is only used when \a use_srtp option above is non-zero.
+ *
+ * Valid values are:
+ * 0: SRTP does not require secure signaling
+ * 1: SRTP requires secure transport such as TLS
+ * 2: SRTP requires secure end-to-end transport (SIPS)
+ *
+ * Default: PJSUA_DEFAULT_SRTP_SECURE_SIGNALING
+ */
+ int srtpSecureSignaling;
+
+ /**
+ * Specify whether IPv6 should be used on media. Default is not used.
+ */
+ pjsua_ipv6_use ipv6Use;
+
+public:
+ /**
+ * Read this object from a container node.
+ *
+ * @param node Container to read values from.
+ */
+ virtual void readObject(const ContainerNode &node) throw(Error);
+
+ /**
+ * Write this object to a container node.
+ *
+ * @param node Container to write values to.
+ */
+ virtual void writeObject(ContainerNode &node) const throw(Error);
+};
+
+/**
+ * Account video config. This will be specified in AccountConfig.
+ */
+struct AccountVideoConfig : public PersistentObject
+{
+ /**
+ * Specify whether incoming video should be shown to screen by default.
+ * This applies to incoming call (INVITE), incoming re-INVITE, and
+ * incoming UPDATE requests.
+ *
+ * Regardless of this setting, application can detect incoming video
+ * by implementing \a on_call_media_state() callback and enumerating
+ * the media stream(s) with pjsua_call_get_info(). Once incoming
+ * video is recognised, application may retrieve the window associated
+ * with the incoming video and show or hide it with
+ * pjsua_vid_win_set_show().
+ *
+ * Default: False
+ */
+ bool autoShowIncoming;
+
+ /**
+ * Specify whether outgoing video should be activated by default when
+ * making outgoing calls and/or when incoming video is detected. This
+ * applies to incoming and outgoing calls, incoming re-INVITE, and
+ * incoming UPDATE. If the setting is non-zero, outgoing video
+ * transmission will be started as soon as response to these requests
+ * is sent (or received).
+ *
+ * Regardless of the value of this setting, application can start and
+ * stop outgoing video transmission with pjsua_call_set_vid_strm().
+ *
+ * Default: False
+ */
+ bool autoTransmitOutgoing;
+
+ /**
+ * Specify video window's flags. The value is a bitmask combination of
+ * pjmedia_vid_dev_wnd_flag.
+ *
+ * Default: 0
+ */
+ unsigned windowFlags;
+
+ /**
+ * Specify the default capture device to be used by this account. If
+ * vidOutAutoTransmit is enabled, this device will be used for
+ * capturing video.
+ *
+ * Default: PJMEDIA_VID_DEFAULT_CAPTURE_DEV
+ */
+ pjmedia_vid_dev_index defaultCaptureDevice;
+
+ /**
+ * Specify the default rendering device to be used by this account.
+ *
+ * Default: PJMEDIA_VID_DEFAULT_RENDER_DEV
+ */
+ pjmedia_vid_dev_index defaultRenderDevice;
+
+ /**
+ * Rate control method.
+ *
+ * Default: PJMEDIA_VID_STREAM_RC_SIMPLE_BLOCKING.
+ */
+ pjmedia_vid_stream_rc_method rateControlMethod;
+
+ /**
+ * Upstream/outgoing bandwidth. If this is set to zero, the video stream
+ * will use codec maximum bitrate setting.
+ *
+ * Default: 0 (follow codec maximum bitrate).
+ */
+ unsigned rateControlBandwidth;
+
+public:
+ /**
+ * Read this object from a container node.
+ *
+ * @param node Container to read values from.
+ */
+ virtual void readObject(const ContainerNode &node) throw(Error);
+
+ /**
+ * Write this object to a container node.
+ *
+ * @param node Container to write values to.
+ */
+ virtual void writeObject(ContainerNode &node) const throw(Error);
+};
+
+/**
+ * Account configuration.
+ */
+struct AccountConfig : public PersistentObject
+{
+ /**
+ * Account priority, which is used to control the order of matching
+ * incoming/outgoing requests. The higher the number means the higher
+ * the priority is, and the account will be matched first.
+ */
+ int priority;
+
+ /**
+ * The Address of Record or AOR, that is full SIP URL that identifies the
+ * account. The value can take name address or URL format, and will look
+ * something like "sip:account@serviceprovider".
+ *
+ * This field is mandatory.
+ */
+ string idUri;
+
+ /**
+ * Registration settings.
+ */
+ AccountRegConfig regConfig;
+
+ /**
+ * SIP settings.
+ */
+ AccountSipConfig sipConfig;
+
+ /**
+ * Call settings.
+ */
+ AccountCallConfig callConfig;
+
+ /**
+ * Presence settings.
+ */
+ AccountPresConfig presConfig;
+
+ /**
+ * MWI (Message Waiting Indication) settings.
+ */
+ AccountMwiConfig mwiConfig;
+
+ /**
+ * NAT settings.
+ */
+ AccountNatConfig natConfig;
+
+ /**
+ * Media settings (applicable for both audio and video).
+ */
+ AccountMediaConfig mediaConfig;
+
+ /**
+ * Video settings.
+ */
+ AccountVideoConfig videoConfig;
+
+public:
+ /**
+ * Default constructor will initialize with default values.
+ */
+ AccountConfig();
+
+ /**
+ * This will return a temporary pjsua_acc_config instance, which contents
+ * are only valid as long as this AccountConfig structure remains valid
+ * AND no modifications are done to it AND no further toPj() function call
+ * is made. Any call to toPj() function will invalidate the content of
+ * temporary pjsua_acc_config that was returned by the previous call.
+ */
+ void toPj(pjsua_acc_config &cfg) const;
+
+ /**
+ * Initialize from pjsip.
+ */
+ void fromPj(const pjsua_acc_config &prm, const pjsua_media_config *mcfg);
+
+ /**
+ * Read this object from a container node.
+ *
+ * @param node Container to read values from.
+ */
+ virtual void readObject(const ContainerNode &node) throw(Error);
+
+ /**
+ * Write this object to a container node.
+ *
+ * @param node Container to write values to.
+ */
+ virtual void writeObject(ContainerNode &node) const throw(Error);
+};
+
+
+/**
+ * Account information. Application can query the account information
+ * by calling Account::getInfo().
+ */
+struct AccountInfo
+{
+ /**
+ * The account ID.
+ */
+ pjsua_acc_id id;
+
+ /**
+ * Flag to indicate whether this is the default account.
+ */
+ bool isDefault;
+
+ /**
+ * Account URI
+ */
+ string uri;
+
+ /**
+ * Flag to tell whether this account has registration setting
+ * (reg_uri is not empty).
+ */
+ bool regIsConfigured;
+
+ /**
+ * Flag to tell whether this account is currently registered
+ * (has active registration session).
+ */
+ bool regIsActive;
+
+ /**
+ * An up to date expiration interval for account registration session.
+ */
+ int regExpiresSec;
+
+ /**
+ * Last registration status code. If status code is zero, the account
+ * is currently not registered. Any other value indicates the SIP
+ * status code of the registration.
+ */
+ pjsip_status_code regStatus;
+
+ /**
+ * String describing the registration status.
+ */
+ string regStatusText;
+
+ /**
+ * Last registration error code. When the status field contains a SIP
+ * status code that indicates a registration failure, last registration
+ * error code contains the error code that causes the failure. In any
+ * other case, its value is zero.
+ */
+ pj_status_t regLastErr;
+
+ /**
+ * Presence online status for this account.
+ */
+ bool onlineStatus;
+
+ /**
+ * Presence online status text.
+ */
+ string onlineStatusText;
+
+public:
+ /** Import from pjsip data */
+ void fromPj(const pjsua_acc_info &pai);
+};
+
+/**
+ * This structure contains parameters for onIncomingCall() account callback.
+ */
+struct OnIncomingCallParam
+{
+ /**
+ * The library call ID allocated for the new call.
+ */
+ int callId;
+
+ /**
+ * The incoming INVITE request.
+ */
+ SipRxData rdata;
+};
+
+/**
+ * This structure contains parameters for onRegStarted() account callback.
+ */
+struct OnRegStartedParam
+{
+ /**
+ * True for registration and False for unregistration.
+ */
+ bool renew;
+};
+
+/**
+ * This structure contains parameters for onRegState() account callback.
+ */
+struct OnRegStateParam
+{
+ /**
+ * Registration operation status.
+ */
+ pj_status_t status;
+
+ /**
+ * SIP status code received.
+ */
+ pjsip_status_code code;
+
+ /**
+ * SIP reason phrase received.
+ */
+ string reason;
+
+ /**
+ * The incoming message.
+ */
+ SipRxData rdata;
+
+ /**
+ * Next expiration interval.
+ */
+ int expiration;
+};
+
+/**
+ * This structure contains parameters for onIncomingSubscribe() callback.
+ */
+struct OnIncomingSubscribeParam
+{
+ /**
+ * Server presence subscription instance. If application delays
+ * the acceptance of the request, it will need to specify this object
+ * when calling Account::presNotify().
+ */
+ void *srvPres;
+
+ /**
+ * Sender URI.
+ */
+ string fromUri;
+
+ /**
+ * The incoming message.
+ */
+ SipRxData rdata;
+
+ /**
+ * The status code to respond to the request. The default value is 200.
+ * Application may set this to other final status code to accept or
+ * reject the request.
+ */
+ pjsip_status_code code;
+
+ /**
+ * The reason phrase to respond to the request.
+ */
+ string reason;
+
+ /**
+ * Additional data to be sent with the response, if any.
+ */
+ SipTxOption txOption;
+};
+
+/**
+ * Parameters for onInstantMessage() account callback.
+ */
+struct OnInstantMessageParam
+{
+ /**
+ * Sender From URI.
+ */
+ string fromUri;
+
+ /**
+ * To URI of the request.
+ */
+ string toUri;
+
+ /**
+ * Contact URI of the sender.
+ */
+ string contactUri;
+
+ /**
+ * MIME type of the message body.
+ */
+ string contentType;
+
+ /**
+ * The message body.
+ */
+ string msgBody;
+
+ /**
+ * The whole message.
+ */
+ SipRxData rdata;
+};
+
+/**
+ * Parameters for onInstantMessageStatus() account callback.
+ */
+struct OnInstantMessageStatusParam
+{
+ /**
+ * Token or a user data that was associated with the pager
+ * transmission.
+ */
+ Token userData;
+
+ /**
+ * Destination URI.
+ */
+ string toUri;
+
+ /**
+ * The message body.
+ */
+ string msgBody;
+
+ /**
+ * The SIP status code of the transaction.
+ */
+ pjsip_status_code code;
+
+ /**
+ * The reason phrase of the transaction.
+ */
+ string reason;
+
+ /**
+ * The incoming response that causes this callback to be called.
+ * If the transaction fails because of time out or transport error,
+ * the content will be empty.
+ */
+ SipRxData rdata;
+};
+
+/**
+ * Parameters for onTypingIndication() account callback.
+ */
+struct OnTypingIndicationParam
+{
+ /**
+ * Sender/From URI.
+ */
+ string fromUri;
+
+ /**
+ * To URI.
+ */
+ string toUri;
+
+ /**
+ * The Contact URI.
+ */
+ string contactUri;
+
+ /**
+ * Boolean to indicate if sender is typing.
+ */
+ bool isTyping;
+
+ /**
+ * The whole message buffer.
+ */
+ SipRxData rdata;
+};
+
+/**
+ * Parameters for onMwiInfo() account callback.
+ */
+struct OnMwiInfoParam
+{
+ /**
+ * MWI subscription state.
+ */
+ pjsip_evsub_state state;
+
+ /**
+ * The whole message buffer.
+ */
+ SipRxData rdata;
+};
+
+/**
+ * Parameters for presNotify() account method.
+ */
+struct PresNotifyParam
+{
+ /**
+ * Server presence subscription instance.
+ */
+ void *srvPres;
+
+ /**
+ * Server presence subscription state to set.
+ */
+ pjsip_evsub_state state;
+
+ /**
+ * Optionally specify the state string name, if state is not "active",
+ * "pending", or "terminated".
+ */
+ string stateStr;
+
+ /**
+ * If the new state is PJSIP_EVSUB_STATE_TERMINATED, optionally specify
+ * the termination reason.
+ */
+ string reason;
+
+ /**
+ * If the new state is PJSIP_EVSUB_STATE_TERMINATED, this specifies
+ * whether the NOTIFY request should contain message body containing
+ * account's presence information.
+ */
+ bool withBody;
+
+ /**
+ * Optional list of headers to be sent with the NOTIFY request.
+ */
+ SipTxOption txOption;
+};
+
+
+/**
+ * Wrapper class for Buddy matching algo.
+ *
+ * Default algo is a simple substring lookup of search-token in the
+ * Buddy URIs, with case sensitive. Application can implement its own
+ * matching algo by overriding this class and specifying its instance
+ * in Account::findBuddy().
+ */
+class FindBuddyMatch
+{
+public:
+ /**
+ * Default algo implementation.
+ */
+ virtual bool match(const string &token, const Buddy &buddy)
+ {
+ BuddyInfo bi = buddy.getInfo();
+ return bi.uri.find(token) != string::npos;
+ }
+
+ /**
+ * Destructor.
+ */
+ virtual ~FindBuddyMatch() {}
+};
+
+
+/**
+ * Account.
+ */
+class Account
+{
+public:
+ /**
+ * Constructor.
+ */
+ Account();
+
+ /**
+ * Destructor. Note that if the account is deleted, it will also delete
+ * the corresponding account in the PJSUA-LIB.
+ */
+ virtual ~Account();
+
+ /**
+ * Create the account.
+ *
+ * @param cfg The account config.
+ * @param make_default Make this the default account.
+ */
+ void create(const AccountConfig &cfg,
+ bool make_default=false) throw(Error);
+
+ /**
+ * Modify the account to use the specified account configuration.
+ * Depending on the changes, this may cause unregistration or
+ * reregistration on the account.
+ *
+ * @param cfg New account config to be applied to the
+ * account.
+ */
+ void modify(const AccountConfig &cfg) throw(Error);
+
+ /**
+ * Check if this account is still valid.
+ *
+ * @return True if it is.
+ */
+ bool isValid() const;
+
+ /**
+ * Set this as default account to be used when incoming and outgoing
+ * requests don't match any accounts.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+ void setDefault() throw(Error);
+
+ /**
+ * Check if this account is the default account. Default account will be
+ * used for incoming and outgoing requests that don't match any other
+ * accounts.
+ *
+ * @return True if this is the default account.
+ */
+ bool isDefault() const;
+
+ /**
+ * Get PJSUA-LIB account ID or index associated with this account.
+ *
+ * @return Integer greater than or equal to zero.
+ */
+ int getId() const;
+
+ /**
+ * Get the Account class for the specified account Id.
+ *
+ * @param acc_id The account ID to lookup
+ *
+ * @return The Account instance or NULL if not found.
+ */
+ static Account *lookup(int acc_id);
+
+ /**
+ * Get account info.
+ *
+ * @return Account info.
+ */
+ AccountInfo getInfo() const throw(Error);
+
+ /**
+ * Update registration or perform unregistration. Application normally
+ * only needs to call this function if it wants to manually update the
+ * registration or to unregister from the server.
+ *
+ * @param renew If False, this will start unregistration
+ * process.
+ */
+ void setRegistration(bool renew) throw(Error);
+
+ /**
+ * Set or modify account's presence online status to be advertised to
+ * remote/presence subscribers. This would trigger the sending of
+ * outgoing NOTIFY request if there are server side presence subscription
+ * for this account, and/or outgoing PUBLISH if presence publication is
+ * enabled for this account.
+ *
+ * @param pres_st Presence online status.
+ */
+ void setOnlineStatus(const PresenceStatus &pres_st) throw(Error);
+
+ /**
+ * Lock/bind this account to a specific transport/listener. Normally
+ * application shouldn't need to do this, as transports will be selected
+ * automatically by the library according to the destination.
+ *
+ * When account is locked/bound to a specific transport, all outgoing
+ * requests from this account will use the specified transport (this
+ * includes SIP registration, dialog (call and event subscription), and
+ * out-of-dialog requests such as MESSAGE).
+ *
+ * Note that transport id may be specified in AccountConfig too.
+ *
+ * @param tp_id The transport ID.
+ */
+ void setTransport(TransportId tp_id) throw(Error);
+
+ /**
+ * Send NOTIFY to inform account presence status or to terminate server
+ * side presence subscription. If application wants to reject the incoming
+ * request, it should set the param \a PresNotifyParam.state to
+ * PJSIP_EVSUB_STATE_TERMINATED.
+ *
+ * @param prm The sending NOTIFY parameter.
+ */
+ void presNotify(const PresNotifyParam &prm) throw(Error);
+
+ /**
+ * Enumerate all buddies of the account.
+ *
+ * @return The buddy list.
+ */
+ const BuddyVector& enumBuddies() const throw(Error);
+
+ /**
+ * Find a buddy in the buddy list with the specified URI.
+ *
+ * Exception: if buddy is not found, PJ_ENOTFOUND will be thrown.
+ *
+ * @param uri The buddy URI.
+ * @param buddy_match The buddy match algo.
+ *
+ * @return The pointer to buddy.
+ */
+ Buddy* findBuddy(string uri, FindBuddyMatch *buddy_match = NULL) const
+ throw(Error);
+
+ /**
+ * An internal function to add a Buddy to Account buddy list.
+ * This function must never be used by application.
+ */
+ void addBuddy(Buddy *buddy);
+
+ /**
+ * An internal function to remove a Buddy from Account buddy list.
+ * This function must never be used by application.
+ */
+ void removeBuddy(Buddy *buddy);
+
+public:
+ /*
+ * Callbacks
+ */
+ /**
+ * Notify application on incoming call.
+ *
+ * @param prm Callback parameter.
+ */
+ virtual void onIncomingCall(OnIncomingCallParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
+ /**
+ * Notify application when registration or unregistration has been
+ * initiated. Note that this only notifies the initial registration
+ * and unregistration. Once registration session is active, subsequent
+ * refresh will not cause this callback to be called.
+ *
+ * @param prm Callback parameter.
+ */
+ virtual void onRegStarted(OnRegStartedParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
+ /**
+ * Notify application when registration status has changed.
+ * Application may then query the account info to get the
+ * registration details.
+ *
+ * @param prm Callback parameter.
+ */
+ virtual void onRegState(OnRegStateParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
+ /**
+ * Notification when incoming SUBSCRIBE request is received. Application
+ * may use this callback to authorize the incoming subscribe request
+ * (e.g. ask user permission if the request should be granted).
+ *
+ * If this callback is not implemented, all incoming presence subscription
+ * requests will be accepted.
+ *
+ * If this callback is implemented, application has several choices on
+ * what to do with the incoming request:
+ * - it may reject the request immediately by specifying non-200 class
+ * final response in the IncomingSubscribeParam.code parameter.
+ * - it may immediately accept the request by specifying 200 as the
+ * IncomingSubscribeParam.code parameter. This is the default value if
+ * application doesn't set any value to the IncomingSubscribeParam.code
+ * parameter. In this case, the library will automatically send NOTIFY
+ * request upon returning from this callback.
+ * - it may delay the processing of the request, for example to request
+ * user permission whether to accept or reject the request. In this
+ * case, the application MUST set the IncomingSubscribeParam.code
+ * argument to 202, then IMMEDIATELY calls presNotify() with
+ * state PJSIP_EVSUB_STATE_PENDING and later calls presNotify()
+ * again to accept or reject the subscription request.
+ *
+ * Any IncomingSubscribeParam.code other than 200 and 202 will be treated
+ * as 200.
+ *
+ * Application MUST return from this callback immediately (e.g. it must
+ * not block in this callback while waiting for user confirmation).
+ *
+ * @param prm Callback parameter.
+ */
+ virtual void onIncomingSubscribe(OnIncomingSubscribeParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
+ /**
+ * Notify application on incoming instant message or pager (i.e. MESSAGE
+ * request) that was received outside call context.
+ *
+ * @param prm Callback parameter.
+ */
+ virtual void onInstantMessage(OnInstantMessageParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
+ /**
+ * Notify application about the delivery status of outgoing pager/instant
+ * message (i.e. MESSAGE) request.
+ *
+ * @param prm Callback parameter.
+ */
+ virtual void onInstantMessageStatus(OnInstantMessageStatusParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
+ /**
+ * Notify application about typing indication.
+ *
+ * @param prm Callback parameter.
+ */
+ virtual void onTypingIndication(OnTypingIndicationParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
+ /**
+ * Notification about MWI (Message Waiting Indication) status change.
+ * This callback can be called upon the status change of the
+ * SUBSCRIBE request (for example, 202/Accepted to SUBSCRIBE is received)
+ * or when a NOTIFY reqeust is received.
+ *
+ * @param prm Callback parameter.
+ */
+ virtual void onMwiInfo(OnMwiInfoParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
+protected:
+ friend class Endpoint;
+
+private:
+ pjsua_acc_id id;
+ string tmpReason; // for saving response's reason
+ BuddyVector buddyList;
+};
+
+/**
+ * @} // PJSUA2_ACC
+ */
+
+} // namespace pj
+
+#endif /* __PJSUA2_ACCOUNT_HPP__ */
+
diff --git a/pjsip/include/pjsua2/call.hpp b/pjsip/include/pjsua2/call.hpp
new file mode 100644
index 00000000..f16db153
--- /dev/null
+++ b/pjsip/include/pjsua2/call.hpp
@@ -0,0 +1,1713 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2012-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
+ */
+#ifndef __PJSUA2_CALL_HPP__
+#define __PJSUA2_CALL_HPP__
+
+/**
+ * @file pjsua2/call.hpp
+ * @brief PJSUA2 Call manipulation
+ */
+#include <pjsua-lib/pjsua.h>
+#include <pjsua2/media.hpp>
+
+/** PJSUA2 API is inside pj namespace */
+namespace pj
+{
+
+/**
+ * @defgroup PJSUA2_CALL Call
+ * @ingroup PJSUA2_Ref
+ */
+
+/**
+ * @defgroup PJSUA2_Call_Data_Structure Call Related Types
+ * @ingroup PJSUA2_DS
+ * @{
+ */
+
+using std::string;
+using std::vector;
+
+//////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Codec parameters, corresponds to pjmedia_codec_param or
+ * pjmedia_vid_codec_param.
+ */
+typedef void *CodecParam;
+
+/**
+ * Media stream, corresponds to pjmedia_stream
+ */
+typedef void *MediaStream;
+
+/**
+ * Media transport, corresponds to pjmedia_transport
+ */
+typedef void *MediaTransport;
+
+/**
+ * This structure describes statistics state.
+ */
+struct MathStat
+{
+ int n; /**< number of samples */
+ int max; /**< maximum value */
+ int min; /**< minimum value */
+ int last; /**< last value */
+ int mean; /**< mean */
+
+public:
+ /**
+ * Default constructor
+ */
+ MathStat();
+
+ /**
+ * Convert from pjsip
+ */
+ void fromPj(const pj_math_stat &prm);
+};
+
+/**
+ * Unidirectional RTP stream statistics.
+ */
+struct RtcpStreamStat
+{
+ TimeValue update; /**< Time of last update. */
+ unsigned updateCount;/**< Number of updates (to calculate avg) */
+ unsigned pkt; /**< Total number of packets */
+ unsigned bytes; /**< Total number of payload/bytes */
+ unsigned discard; /**< Total number of discarded packets. */
+ unsigned loss; /**< Total number of packets lost */
+ unsigned reorder; /**< Total number of out of order packets */
+ unsigned dup; /**< Total number of duplicates packets */
+
+ MathStat lossPeriodUsec; /**< Loss period statistics */
+
+ struct {
+ unsigned burst; /**< Burst/sequential packet lost detected */
+ unsigned random; /**< Random packet lost detected. */
+ } lossType; /**< Types of loss detected. */
+
+ MathStat jitterUsec; /**< Jitter statistics */
+
+public:
+ /**
+ * Convert from pjsip
+ */
+ void fromPj(const pjmedia_rtcp_stream_stat &prm);
+};
+
+/**
+ * RTCP SDES structure.
+ */
+struct RtcpSdes
+{
+ string cname; /**< RTCP SDES type CNAME. */
+ string name; /**< RTCP SDES type NAME. */
+ string email; /**< RTCP SDES type EMAIL. */
+ string phone; /**< RTCP SDES type PHONE. */
+ string loc; /**< RTCP SDES type LOC. */
+ string tool; /**< RTCP SDES type TOOL. */
+ string note; /**< RTCP SDES type NOTE. */
+
+public:
+ /**
+ * Convert from pjsip
+ */
+ void fromPj(const pjmedia_rtcp_sdes &prm);
+};
+
+/**
+ * Bidirectional RTP stream statistics.
+ */
+struct RtcpStat
+{
+ TimeValue start; /**< Time when session was created */
+
+ RtcpStreamStat txStat; /**< Encoder stream statistics. */
+ RtcpStreamStat rxStat; /**< Decoder stream statistics. */
+
+ MathStat rttUsec; /**< Round trip delay statistic. */
+
+ pj_uint32_t rtpTxLastTs; /**< Last TX RTP timestamp. */
+ pj_uint16_t rtpTxLastSeq; /**< Last TX RTP sequence. */
+
+ MathStat rxIpdvUsec; /**< Statistics of IP packet delay
+ variation in receiving
+ direction. It is only used when
+ PJMEDIA_RTCP_STAT_HAS_IPDV is
+ set to non-zero. */
+
+ MathStat rxRawJitterUsec;/**< Statistic of raw jitter in
+ receiving direction. It is only
+ used when
+ PJMEDIA_RTCP_STAT_HAS_RAW_JITTER
+ is set to non-zero. */
+
+ RtcpSdes peerSdes; /**< Peer SDES. */
+
+public:
+ /**
+ * Convert from pjsip
+ */
+ void fromPj(const pjmedia_rtcp_stat &prm);
+};
+
+/**
+ * This structure describes jitter buffer state.
+ */
+struct JbufState
+{
+ /* Setting */
+ unsigned frameSize; /**< Individual frame size, in bytes. */
+ unsigned minPrefetch; /**< Minimum allowed prefetch, in frms. */
+ unsigned maxPrefetch; /**< Maximum allowed prefetch, in frms. */
+
+ /* Status */
+ unsigned burst; /**< Current burst level, in frames */
+ unsigned prefetch; /**< Current prefetch value, in frames */
+ unsigned size; /**< Current buffer size, in frames. */
+
+ /* Statistic */
+ unsigned avgDelayMsec; /**< Average delay, in ms. */
+ unsigned minDelayMsec; /**< Minimum delay, in ms. */
+ unsigned maxDelayMsec; /**< Maximum delay, in ms. */
+ unsigned devDelayMsec; /**< Standard deviation of delay, in ms.*/
+ unsigned avgBurst; /**< Average burst, in frames. */
+ unsigned lost; /**< Number of lost frames. */
+ unsigned discard; /**< Number of discarded frames. */
+ unsigned empty; /**< Number of empty on GET events. */
+
+public:
+ /**
+ * Convert from pjsip
+ */
+ void fromPj(const pjmedia_jb_state &prm);
+};
+
+/**
+ * This structure describes SDP session description. It corresponds to the
+ * pjmedia_sdp_session structure.
+ */
+struct SdpSession
+{
+ /**
+ * The whole SDP as a string.
+ */
+ string wholeSdp;
+
+ /**
+ * Pointer to its original pjmedia_sdp_session. Only valid when the struct
+ * is converted from PJSIP's pjmedia_sdp_session.
+ */
+ void *pjSdpSession;
+
+public:
+ /**
+ * Convert from pjsip
+ */
+ void fromPj(const pjmedia_sdp_session &sdp);
+};
+
+/**
+ * This structure describes a media format changed event.
+ */
+struct MediaFmtChangedEvent
+{
+ unsigned newWidth; /**< The new width. */
+ unsigned newHeight; /**< The new height. */
+};
+
+/**
+ * This structure describes a media event. It corresponds to the
+ * pjmedia_event structure.
+ */
+struct MediaEvent
+{
+ /**
+ * The event type.
+ */
+ pjmedia_event_type type;
+
+ /**
+ * Additional data/parameters about the event. The type of data
+ * will be specific to the event type being reported.
+ */
+ union {
+ /**
+ * Media format changed event data.
+ */
+ MediaFmtChangedEvent fmtChanged;
+
+ /**
+ * Pointer to storage to user event data, if it's outside
+ * this struct
+ */
+ GenericData ptr;
+ } data;
+
+ /**
+ * Pointer to original pjmedia_event. Only valid when the struct
+ * is converted from PJSIP's pjmedia_event.
+ */
+ void *pjMediaEvent;
+
+public:
+ /**
+ * Convert from pjsip
+ */
+ void fromPj(const pjmedia_event &ev);
+};
+
+/**
+ * This structure describes media transport informations. It corresponds to the
+ * pjmedia_transport_info structure.
+ */
+struct MediaTransportInfo
+{
+ /**
+ * Remote address where RTP originated from.
+ */
+ SocketAddress srcRtpName;
+
+ /**
+ * Remote address where RTCP originated from.
+ */
+ SocketAddress srcRtcpName;
+
+public:
+ /**
+ * Convert from pjsip
+ */
+ void fromPj(const pjmedia_transport_info &info);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Call settings.
+ */
+struct CallSetting
+{
+ /**
+ * Bitmask of pjsua_call_flag constants.
+ *
+ * Default: PJSUA_CALL_INCLUDE_DISABLED_MEDIA
+ */
+ unsigned flag;
+
+ /**
+ * This flag controls what methods to request keyframe are allowed on
+ * the call. Value is bitmask of pjsua_vid_req_keyframe_method.
+ *
+ * Default: PJSUA_VID_REQ_KEYFRAME_SIP_INFO |
+ * PJSUA_VID_REQ_KEYFRAME_RTCP_PLI
+ */
+ unsigned reqKeyframeMethod;
+
+ /**
+ * Number of simultaneous active audio streams for this call. Setting
+ * this to zero will disable audio in this call.
+ *
+ * Default: 1
+ */
+ unsigned audioCount;
+
+ /**
+ * Number of simultaneous active video streams for this call. Setting
+ * this to zero will disable video in this call.
+ *
+ * Default: 1 (if video feature is enabled, otherwise it is zero)
+ */
+ unsigned videoCount;
+
+public:
+ /**
+ * Default constructor initializes with empty or default values.
+ */
+ CallSetting(pj_bool_t useDefaultValues = false);
+
+ /**
+ * Check if the settings are set with empty values.
+ *
+ * @return True if the settings are empty.
+ */
+ bool isEmpty() const;
+
+ /**
+ * Convert from pjsip
+ */
+ void fromPj(const pjsua_call_setting &prm);
+
+ /**
+ * Convert to pjsip
+ */
+ pjsua_call_setting toPj() const;
+};
+
+/**
+ * Call media information.
+ */
+struct CallMediaInfo
+{
+ /**
+ * Media index in SDP.
+ */
+ unsigned index;
+
+ /**
+ * Media type.
+ */
+ pjmedia_type type;
+
+ /**
+ * Media direction.
+ */
+ pjmedia_dir dir;
+
+ /**
+ * Call media status.
+ */
+ pjsua_call_media_status status;
+
+ /**
+ * The conference port number for the call. Only valid if the media type
+ * is audio.
+ */
+ int audioConfSlot;
+
+ /**
+ * The window id for incoming video, if any, or
+ * PJSUA_INVALID_ID. Only valid if the media type is video.
+ */
+ pjsua_vid_win_id videoIncomingWindowId;
+
+ /**
+ * The video capture device for outgoing transmission, if any,
+ * or PJMEDIA_VID_INVALID_DEV. Only valid if the media type is video.
+ */
+ pjmedia_vid_dev_index videoCapDev;
+
+public:
+ /**
+ * Default constructor
+ */
+ CallMediaInfo();
+
+ /**
+ * Convert from pjsip
+ */
+ void fromPj(const pjsua_call_media_info &prm);
+};
+
+/** Array of call media info */
+typedef std::vector<CallMediaInfo> CallMediaInfoVector;
+
+/**
+ * Call information. Application can query the call information
+ * by calling Call::getInfo().
+ */
+struct CallInfo
+{
+ /**
+ * Call identification.
+ */
+ pjsua_call_id id;
+
+ /**
+ * Initial call role (UAC == caller)
+ */
+ pjsip_role_e role;
+
+ /**
+ * The account ID where this call belongs.
+ */
+ pjsua_acc_id accId;
+
+ /**
+ * Local URI
+ */
+ string localUri;
+
+ /**
+ * Local Contact
+ */
+ string localContact;
+
+ /**
+ * Remote URI
+ */
+ string remoteUri;
+
+ /**
+ * Remote contact
+ */
+ string remoteContact;
+
+ /**
+ * Dialog Call-ID string.
+ */
+ string callIdString;
+
+ /**
+ * Call setting
+ */
+ CallSetting setting;
+
+ /**
+ * Call state
+ */
+ pjsip_inv_state state;
+
+ /**
+ * Text describing the state
+ */
+ string stateText;
+
+ /**
+ * Last status code heard, which can be used as cause code
+ */
+ pjsip_status_code lastStatusCode;
+
+ /**
+ * The reason phrase describing the last status.
+ */
+ string lastReason;
+
+ /**
+ * Array of active media information.
+ */
+ CallMediaInfoVector media;
+
+ /**
+ * Array of provisional media information. This contains the media info
+ * in the provisioning state, that is when the media session is being
+ * created/updated (SDP offer/answer is on progress).
+ */
+ CallMediaInfoVector provMedia;
+
+ /**
+ * Up-to-date call connected duration (zero when call is not
+ * established)
+ */
+ TimeValue connectDuration;
+
+ /**
+ * Total call duration, including set-up time
+ */
+ TimeValue totalDuration;
+
+ /**
+ * Flag if remote was SDP offerer
+ */
+ bool remOfferer;
+
+ /**
+ * Number of audio streams offered by remote
+ */
+ unsigned remAudioCount;
+
+ /**
+ * Number of video streams offered by remote
+ */
+ unsigned remVideoCount;
+
+public:
+ /**
+ * Convert from pjsip
+ */
+ void fromPj(const pjsua_call_info &pci);
+};
+
+/**
+ * Media stream info.
+ */
+struct StreamInfo
+{
+ /**
+ * Media type of this stream.
+ */
+ pjmedia_type type;
+
+ /**
+ * Transport protocol (RTP/AVP, etc.)
+ */
+ pjmedia_tp_proto proto;
+
+ /**
+ * Media direction.
+ */
+ pjmedia_dir dir;
+
+ /**
+ * Remote RTP address
+ */
+ SocketAddress remoteRtpAddress;
+
+ /**
+ * Optional remote RTCP address
+ */
+ SocketAddress remoteRtcpAddress;
+
+ /**
+ * Outgoing codec payload type.
+ */
+ unsigned txPt;
+
+ /**
+ * Incoming codec payload type.
+ */
+ unsigned rxPt;
+
+ /**
+ * Codec name.
+ */
+ string codecName;
+
+ /**
+ * Codec clock rate.
+ */
+ unsigned codecClockRate;
+
+ /**
+ * Optional codec param.
+ */
+ CodecParam codecParam;
+
+public:
+ /**
+ * Convert from pjsip
+ */
+ void fromPj(const pjsua_stream_info &info);
+};
+
+/**
+ * Media stream statistic.
+ */
+struct StreamStat
+{
+ /**
+ * RTCP statistic.
+ */
+ RtcpStat rtcp;
+
+ /**
+ * Jitter buffer statistic.
+ */
+ JbufState jbuf;
+
+public:
+ /**
+ * Convert from pjsip
+ */
+ void fromPj(const pjsua_stream_stat &prm);
+};
+
+/**
+ * This structure contains parameters for Call::onCallState() callback.
+ */
+struct OnCallStateParam
+{
+ /**
+ * Event which causes the call state to change.
+ */
+ SipEvent e;
+};
+
+/**
+ * This structure contains parameters for Call::onCallTsxState() callback.
+ */
+struct OnCallTsxStateParam
+{
+ /**
+ * Transaction event that caused the state change.
+ */
+ SipEvent e;
+};
+
+/**
+ * This structure contains parameters for Call::onCallMediaState() callback.
+ */
+struct OnCallMediaStateParam
+{
+};
+
+/**
+ * This structure contains parameters for Call::onCallSdpCreated() callback.
+ */
+struct OnCallSdpCreatedParam
+{
+ /**
+ * The SDP has just been created.
+ */
+ SdpSession sdp;
+
+ /**
+ * The remote SDP, will be empty if local is SDP offerer.
+ */
+ SdpSession remSdp;
+};
+
+/**
+ * This structure contains parameters for Call::onStreamCreated()
+ * callback.
+ */
+struct OnStreamCreatedParam
+{
+ /**
+ * Media stream.
+ */
+ MediaStream stream;
+
+ /**
+ * Stream index in the media session.
+ */
+ unsigned streamIdx;
+
+ /**
+ * On input, it specifies the media port of the stream. Application
+ * may modify this pointer to point to different media port to be
+ * registered to the conference bridge.
+ */
+ MediaPort pPort;
+};
+
+/**
+ * This structure contains parameters for Call::onStreamDestroyed()
+ * callback.
+ */
+struct OnStreamDestroyedParam
+{
+ /**
+ * Media stream.
+ */
+ MediaStream stream;
+
+ /**
+ * Stream index in the media session.
+ */
+ unsigned streamIdx;
+};
+
+/**
+ * This structure contains parameters for Call::onDtmfDigit()
+ * callback.
+ */
+struct OnDtmfDigitParam
+{
+ /**
+ * DTMF ASCII digit.
+ */
+ string digit;
+};
+
+/**
+ * This structure contains parameters for Call::onCallTransferRequest()
+ * callback.
+ */
+struct OnCallTransferRequestParam
+{
+ /**
+ * The destination where the call will be transfered to.
+ */
+ string dstUri;
+
+ /**
+ * Status code to be returned for the call transfer request. On input,
+ * it contains status code 200.
+ */
+ pjsip_status_code statusCode;
+
+ /**
+ * The current call setting, application can update this setting
+ * for the call being transfered.
+ */
+ CallSetting opt;
+};
+
+/**
+ * This structure contains parameters for Call::onCallTransferStatus()
+ * callback.
+ */
+struct OnCallTransferStatusParam
+{
+ /**
+ * Status progress of the transfer request.
+ */
+ pjsip_status_code statusCode;
+
+ /**
+ * Status progress reason.
+ */
+ string reason;
+
+ /**
+ * If true, no further notification will be reported. The statusCode
+ * specified in this callback is the final status.
+ */
+ bool finalNotify;
+
+ /**
+ * Initially will be set to true, application can set this to false
+ * if it no longer wants to receive further notification (for example,
+ * after it hangs up the call).
+ */
+ bool cont;
+};
+
+/**
+ * This structure contains parameters for Call::onCallReplaceRequest()
+ * callback.
+ */
+struct OnCallReplaceRequestParam
+{
+ /**
+ * The incoming INVITE request to replace the call.
+ */
+ SipRxData rdata;
+
+ /**
+ * Status code to be set by application. Application should only
+ * return a final status (200-699)
+ */
+ pjsip_status_code statusCode;
+
+ /**
+ * Optional status text to be set by application.
+ */
+ string reason;
+
+ /**
+ * The current call setting, application can update this setting for
+ * the call being replaced.
+ */
+ CallSetting opt;
+};
+
+/**
+ * This structure contains parameters for Call::onCallReplaced() callback.
+ */
+struct OnCallReplacedParam
+{
+ /**
+ * The new call id.
+ */
+ pjsua_call_id newCallId;
+};
+
+/**
+ * This structure contains parameters for Call::onCallRxOffer() callback.
+ */
+struct OnCallRxOfferParam
+{
+ /**
+ * The new offer received.
+ */
+ SdpSession offer;
+
+ /**
+ * Status code to be returned for answering the offer. On input,
+ * it contains status code 200. Currently, valid values are only
+ * 200 and 488.
+ */
+ pjsip_status_code statusCode;
+
+ /**
+ * The current call setting, application can update this setting for
+ * answering the offer.
+ */
+ CallSetting opt;
+};
+
+/**
+ * This structure contains parameters for Call::onCallRedirected() callback.
+ */
+struct OnCallRedirectedParam
+{
+ /**
+ * The current target to be tried.
+ */
+ string targetUri;
+
+ /**
+ * The event that caused this callback to be called.
+ * This could be the receipt of 3xx response, or 4xx/5xx response
+ * received for the INVITE sent to subsequent targets, or empty
+ * (e.type == PJSIP_EVENT_UNKNOWN)
+ * if this callback is called from within Call::processRedirect()
+ * context.
+ */
+ SipEvent e;
+};
+
+/**
+ * This structure contains parameters for Call::onCallMediaEvent() callback.
+ */
+struct OnCallMediaEventParam
+{
+ /**
+ * The media stream index.
+ */
+ unsigned medIdx;
+
+ /**
+ * The media event.
+ */
+ MediaEvent ev;
+};
+
+/**
+ * This structure contains parameters for Call::onCallMediaTransportState()
+ * callback.
+ */
+struct OnCallMediaTransportStateParam
+{
+ /**
+ * The media index.
+ */
+ unsigned medIdx;
+
+ /**
+ * The media transport state
+ */
+ pjsua_med_tp_st state;
+
+ /**
+ * The last error code related to the media transport state.
+ */
+ pj_status_t status;
+
+ /**
+ * Optional SIP error code.
+ */
+ int sipErrorCode;
+};
+
+/**
+ * This structure contains parameters for Call::onCreateMediaTransport()
+ * callback.
+ */
+struct OnCreateMediaTransportParam
+{
+ /**
+ * The media index in the SDP for which this media transport will be used.
+ */
+ unsigned mediaIdx;
+
+ /**
+ * The media transport which otherwise will be used by the call has this
+ * callback not been implemented. Application can change this to its own
+ * instance of media transport to be used by the call.
+ */
+ MediaTransport mediaTp;
+
+ /**
+ * Bitmask from pjsua_create_media_transport_flag.
+ */
+ unsigned flags;
+};
+
+/**
+ * @} // PJSUA2_Call_Data_Structure
+ */
+
+/**
+ * @addtogroup PJSUA2_CALL
+ * @{
+ */
+
+/**
+ * This structure contains parameters for Call::answer(), Call::hangup(),
+ * Call::reinvite(), Call::update(), Call::xfer(), Call::xferReplaces(),
+ * Call::setHold().
+ */
+struct CallOpParam
+{
+ /**
+ * The call setting.
+ */
+ CallSetting opt;
+
+ /**
+ * Status code.
+ */
+ pjsip_status_code statusCode;
+
+ /**
+ * Reason phrase.
+ */
+ string reason;
+
+ /**
+ * Options.
+ */
+ unsigned options;
+
+ /**
+ * List of headers etc to be added to outgoing response message.
+ * Note that this message data will be persistent in all next
+ * answers/responses for this INVITE request.
+ */
+ SipTxOption txOption;
+
+public:
+ /**
+ * Default constructor initializes with zero/empty values.
+ * Setting useDefaultCallSetting to true will initialize opt with default
+ * call setting values.
+ */
+ CallOpParam(bool useDefaultCallSetting = false);
+};
+
+/**
+ * This structure contains parameters for Call::sendRequest()
+ */
+struct CallSendRequestParam
+{
+ /**
+ * SIP method of the request.
+ */
+ string method;
+
+ /**
+ * Message body and/or list of headers etc to be included in
+ * outgoing request.
+ */
+ SipTxOption txOption;
+
+public:
+ /**
+ * Default constructor initializes with zero/empty values.
+ */
+ CallSendRequestParam();
+};
+
+/**
+ * This structure contains parameters for Call::vidSetStream()
+ */
+struct CallVidSetStreamParam
+{
+ /**
+ * Specify the media stream index. This can be set to -1 to denote
+ * the default video stream in the call, which is the first active
+ * video stream or any first video stream if none is active.
+ *
+ * This field is valid for all video stream operations, except
+ * PJSUA_CALL_VID_STRM_ADD.
+ *
+ * Default: -1 (first active video stream, or any first video stream
+ * if none is active)
+ */
+ int medIdx;
+
+ /**
+ * Specify the media stream direction.
+ *
+ * This field is valid for the following video stream operations:
+ * PJSUA_CALL_VID_STRM_ADD and PJSUA_CALL_VID_STRM_CHANGE_DIR.
+ *
+ * Default: PJMEDIA_DIR_ENCODING_DECODING
+ */
+ pjmedia_dir dir;
+
+ /**
+ * Specify the video capture device ID. This can be set to
+ * PJMEDIA_VID_DEFAULT_CAPTURE_DEV to specify the default capture
+ * device as configured in the account.
+ *
+ * This field is valid for the following video stream operations:
+ * PJSUA_CALL_VID_STRM_ADD and PJSUA_CALL_VID_STRM_CHANGE_CAP_DEV.
+ *
+ * Default: PJMEDIA_VID_DEFAULT_CAPTURE_DEV.
+ */
+ pjmedia_vid_dev_index capDev;
+
+public:
+ /**
+ * Default constructor
+ */
+ CallVidSetStreamParam();
+};
+
+/**
+ * Call.
+ */
+class Call
+{
+public:
+ /**
+ * Constructor.
+ */
+ Call(Account& acc, int call_id = PJSUA_INVALID_ID);
+
+ /**
+ * Destructor.
+ */
+ virtual ~Call();
+
+ /**
+ * Obtain detail information about this call.
+ *
+ * @return Call info.
+ */
+ CallInfo getInfo() const throw(Error);
+
+ /**
+ * Check if this call has active INVITE session and the INVITE
+ * session has not been disconnected.
+ *
+ * @return True if call is active.
+ */
+ bool isActive() const;
+
+ /**
+ * Get PJSUA-LIB call ID or index associated with this call.
+ *
+ * @return Integer greater than or equal to zero.
+ */
+ int getId() const;
+
+ /**
+ * Get the Call class for the specified call Id.
+ *
+ * @param call_id The call ID to lookup
+ *
+ * @return The Call instance or NULL if not found.
+ */
+ static Call *lookup(int call_id);
+
+ /**
+ * Check if call has an active media session.
+ *
+ * @return True if yes.
+ */
+ bool hasMedia() const;
+
+ /**
+ * Get media for the specified media index.
+ *
+ * @param med_idx Media index.
+ *
+ * @return The media or NULL if invalid or inactive.
+ */
+ Media *getMedia(unsigned med_idx) const;
+
+ /**
+ * Check if remote peer support the specified capability.
+ *
+ * @param htype The header type (pjsip_hdr_e) to be checked, which
+ * value may be:
+ * - PJSIP_H_ACCEPT
+ * - PJSIP_H_ALLOW
+ * - PJSIP_H_SUPPORTED
+ * @param hname If htype specifies PJSIP_H_OTHER, then the header
+ * name must be supplied in this argument. Otherwise
+ * the value must be set to empty string ("").
+ * @param token The capability token to check. For example, if \a
+ * htype is PJSIP_H_ALLOW, then \a token specifies the
+ * method names; if \a htype is PJSIP_H_SUPPORTED, then
+ * \a token specifies the extension names such as
+ * "100rel".
+ *
+ * @return PJSIP_DIALOG_CAP_SUPPORTED if the specified
+ * capability is explicitly supported, see
+ * pjsip_dialog_cap_status for more info.
+ */
+ pjsip_dialog_cap_status remoteHasCap(int htype,
+ const string &hname,
+ const string &token) const;
+
+ /**
+ * Attach application specific data to the call. Application can then
+ * inspect this data by calling getUserData().
+ *
+ * @param user_data Arbitrary data to be attached to the call.
+ */
+ void setUserData(Token user_data);
+
+ /**
+ * Get user data attached to the call, which has been previously set with
+ * setUserData().
+ *
+ * @return The user data.
+ */
+ Token getUserData() const;
+
+ /**
+ * Get the NAT type of remote's endpoint. This is a proprietary feature
+ * of PJSUA-LIB which sends its NAT type in the SDP when \a natTypeInSdp
+ * is set in UaConfig.
+ *
+ * This function can only be called after SDP has been received from remote,
+ * which means for incoming call, this function can be called as soon as
+ * call is received as long as incoming call contains SDP, and for outgoing
+ * call, this function can be called only after SDP is received (normally in
+ * 200/OK response to INVITE). As a general case, application should call
+ * this function after or in \a onCallMediaState() callback.
+ *
+ * @return The NAT type.
+ *
+ * @see Endpoint::natGetType(), natTypeInSdp
+ */
+ pj_stun_nat_type getRemNatType() throw(Error);
+
+ /**
+ * Make outgoing call to the specified URI.
+ *
+ * @param dst_uri URI to be put in the To header (normally is the same
+ * as the target URI).
+ * @param prm.opt Optional call setting.
+ * @param prm.txOption Optional headers etc to be added to outgoing INVITE
+ * request.
+ */
+ void makeCall(const string &dst_uri, const CallOpParam &prm) throw(Error);
+
+ /**
+ * Send response to incoming INVITE request with call setting param.
+ * Depending on the status code specified as parameter, this function may
+ * send provisional response, establish the call, or terminate the call.
+ * Notes about call setting:
+ * - if call setting is changed in the subsequent call to this function,
+ * only the first call setting supplied will applied. So normally
+ * application will not supply call setting before getting confirmation
+ * from the user.
+ * - if no call setting is supplied when SDP has to be sent, i.e: answer
+ * with status code 183 or 2xx, the default call setting will be used,
+ * check CallSetting for its default values.
+ *
+ * @param prm.opt Optional call setting.
+ * @param prm.statusCode Status code, (100-699).
+ * @param prm.reason Optional reason phrase. If empty, default text
+ * will be used.
+ * @param prm.txOption Optional list of headers etc to be added to outgoing
+ * response message. Note that this message data will
+ * be persistent in all next answers/responses for this
+ * INVITE request.
+ */
+ void answer(const CallOpParam &prm) throw(Error);
+
+ /**
+ * Hangup call by using method that is appropriate according to the
+ * call state. This function is different than answering the call with
+ * 3xx-6xx response (with answer()), in that this function
+ * will hangup the call regardless of the state and role of the call,
+ * while answer() only works with incoming calls on EARLY
+ * state.
+ *
+ * @param prm.statusCode
+ * Optional status code to be sent when we're rejecting
+ * incoming call. If the value is zero, "603/Decline"
+ * will be sent.
+ * @param prm.reason Optional reason phrase to be sent when we're
+ * rejecting incoming call. If empty, default text
+ * will be used.
+ * @param prm.txOption Optional list of headers etc to be added to outgoing
+ * request/response message.
+ */
+ void hangup(const CallOpParam &prm) throw(Error);
+
+ /**
+ * Put the specified call on hold. This will send re-INVITE with the
+ * appropriate SDP to inform remote that the call is being put on hold.
+ * The final status of the request itself will be reported on the
+ * \a onCallMediaState() callback, which inform the application that
+ * the media state of the call has changed.
+ *
+ * @param prm.options Bitmask of pjsua_call_flag constants. Currently,
+ * only the flag PJSUA_CALL_UPDATE_CONTACT can be used.
+ * @param prm.txOption Optional message components to be sent with
+ * the request.
+ */
+ void setHold(const CallOpParam &prm) throw(Error);
+
+ /**
+ * Send re-INVITE to release hold.
+ * The final status of the request itself will be reported on the
+ * \a onCallMediaState() callback, which inform the application that
+ * the media state of the call has changed.
+ *
+ * @param prm.opt Optional call setting, if empty, the current call
+ * setting will remain unchanged.
+ * @param prm.txOption Optional message components to be sent with
+ * the request.
+ */
+ void reinvite(const CallOpParam &prm) throw(Error);
+
+ /**
+ * Send UPDATE request.
+ *
+ * @param prm.opt Optional call setting, if empty, the current call
+ * setting will remain unchanged.
+ * @param prm.txOption Optional message components to be sent with
+ * the request.
+ */
+ void update(const CallOpParam &prm) throw(Error);
+
+ /**
+ * Initiate call transfer to the specified address. This function will send
+ * REFER request to instruct remote call party to initiate a new INVITE
+ * session to the specified destination/target.
+ *
+ * If application is interested to monitor the successfulness and
+ * the progress of the transfer request, it can implement
+ * \a onCallTransferStatus() callback which will report the progress
+ * of the call transfer request.
+ *
+ * @param dest URI of new target to be contacted. The URI may be
+ * in name address or addr-spec format.
+ * @param prm.txOption Optional message components to be sent with
+ * the request.
+ */
+ void xfer(const string &dest, const CallOpParam &prm) throw(Error);
+
+ /**
+ * Initiate attended call transfer. This function will send REFER request
+ * to instruct remote call party to initiate new INVITE session to the URL
+ * of \a destCall. The party at \a dest_call then should "replace"
+ * the call with us with the new call from the REFER recipient.
+ *
+ * @param dest_call The call to be replaced.
+ * @param prm.options Application may specify
+ * PJSUA_XFER_NO_REQUIRE_REPLACES to suppress the
+ * inclusion of "Require: replaces" in
+ * the outgoing INVITE request created by the REFER
+ * request.
+ * @param prm.txOption Optional message components to be sent with
+ * the request.
+ */
+ void xferReplaces(const Call& dest_call,
+ const CallOpParam &prm) throw(Error);
+
+ /**
+ * Accept or reject redirection response. Application MUST call this
+ * function after it signaled PJSIP_REDIRECT_PENDING in the
+ * \a onCallRedirected() callback,
+ * to notify the call whether to accept or reject the redirection
+ * to the current target. Application can use the combination of
+ * PJSIP_REDIRECT_PENDING command in \a onCallRedirected() callback and
+ * this function to ask for user permission before redirecting the call.
+ *
+ * Note that if the application chooses to reject or stop redirection (by
+ * using PJSIP_REDIRECT_REJECT or PJSIP_REDIRECT_STOP respectively), the
+ * call disconnection callback will be called before this function returns.
+ * And if the application rejects the target, the \a onCallRedirected()
+ * callback may also be called before this function returns if there is
+ * another target to try.
+ *
+ * @param cmd Redirection operation to be applied to the current
+ * target. The semantic of this argument is similar
+ * to the description in the \a onCallRedirected()
+ * callback, except that the PJSIP_REDIRECT_PENDING is
+ * not accepted here.
+ */
+ void processRedirect(pjsip_redirect_op cmd) throw(Error);
+
+ /**
+ * Send DTMF digits to remote using RFC 2833 payload formats.
+ *
+ * @param digits DTMF string digits to be sent.
+ */
+ void dialDtmf(const string &digits) throw(Error);
+
+ /**
+ * Send instant messaging inside INVITE session.
+ *
+ * @param prm.contentType
+ * MIME type.
+ * @param prm.content The message content.
+ * @param prm.txOption Optional list of headers etc to be included in
+ * outgoing request. The body descriptor in the
+ * txOption is ignored.
+ * @param prm.userData Optional user data, which will be given back when
+ * the IM callback is called.
+ */
+ void sendInstantMessage(const SendInstantMessageParam& prm) throw(Error);
+
+ /**
+ * Send IM typing indication inside INVITE session.
+ *
+ * @param prm.isTyping True to indicate to remote that local person is
+ * currently typing an IM.
+ * @param prm.txOption Optional list of headers etc to be included in
+ * outgoing request.
+ */
+ void sendTypingIndication(const SendTypingIndicationParam &prm)
+ throw(Error);
+
+ /**
+ * Send arbitrary request with the call. This is useful for example to send
+ * INFO request. Note that application should not use this function to send
+ * requests which would change the invite session's state, such as
+ * re-INVITE, UPDATE, PRACK, and BYE.
+ *
+ * @param prm.method SIP method of the request.
+ * @param prm.txOption Optional message body and/or list of headers to be
+ * included in outgoing request.
+ */
+ void sendRequest(const CallSendRequestParam &prm) throw(Error);
+
+ /**
+ * Dump call and media statistics to string.
+ *
+ * @param with_media True to include media information too.
+ * @param indent Spaces for left indentation.
+ *
+ * @return Call dump and media statistics string.
+ */
+ string dump(bool with_media, const string indent) throw(Error);
+
+ /**
+ * Get the media stream index of the default video stream in the call.
+ * Typically this will just retrieve the stream index of the first
+ * activated video stream in the call. If none is active, it will return
+ * the first inactive video stream.
+ *
+ * @return The media stream index or -1 if no video stream
+ * is present in the call.
+ */
+ int vidGetStreamIdx() const;
+
+ /**
+ * Determine if video stream for the specified call is currently running
+ * (i.e. has been created, started, and not being paused) for the specified
+ * direction.
+ *
+ * @param med_idx Media stream index, or -1 to specify default video
+ * media.
+ * @param dir The direction to be checked.
+ *
+ * @return True if stream is currently running for the
+ * specified direction.
+ */
+ bool vidStreamIsRunning(int med_idx, pjmedia_dir dir) const;
+
+ /**
+ * Add, remove, modify, and/or manipulate video media stream for the
+ * specified call. This may trigger a re-INVITE or UPDATE to be sent
+ * for the call.
+ *
+ * @param op The video stream operation to be performed,
+ * possible values are pjsua_call_vid_strm_op.
+ * @param param The parameters for the video stream operation
+ * (see CallVidSetStreamParam).
+ */
+ void vidSetStream(pjsua_call_vid_strm_op op,
+ const CallVidSetStreamParam &param) throw(Error);
+
+ /**
+ * Get media stream info for the specified media index.
+ *
+ * @param med_idx Media stream index.
+ *
+ * @return The stream info.
+ */
+ StreamInfo getStreamInfo(unsigned med_idx) const throw(Error);
+
+ /**
+ * Get media stream statistic for the specified media index.
+ *
+ * @param med_idx Media stream index.
+ *
+ * @return The stream statistic.
+ */
+ StreamStat getStreamStat(unsigned med_idx) const throw(Error);
+
+ /**
+ * Get media transport info for the specified media index.
+ *
+ * @param med_idx Media stream index.
+ *
+ * @return The transport info.
+ */
+ MediaTransportInfo getMedTransportInfo(unsigned med_idx) const throw(Error);
+
+ /**
+ * Internal function (callled by Endpoint( to process update to call
+ * medias when call media state changes.
+ */
+ void processMediaUpdate(OnCallMediaStateParam &prm);
+
+ /**
+ * Internal function (called by Endpoint) to process call state change.
+ */
+ void processStateChange(OnCallStateParam &prm);
+
+public:
+ /*
+ * Callbacks
+ */
+ /**
+ * Notify application when call state has changed.
+ * Application may then query the call info to get the
+ * detail call states by calling getInfo() function.
+ *
+ * @param prm Callback parameter.
+ */
+ virtual void onCallState(OnCallStateParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
+ /**
+ * This is a general notification callback which is called whenever
+ * a transaction within the call has changed state. Application can
+ * implement this callback for example to monitor the state of
+ * outgoing requests, or to answer unhandled incoming requests
+ * (such as INFO) with a final response.
+ *
+ * @param prm Callback parameter.
+ */
+ virtual void onCallTsxState(OnCallTsxStateParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
+ /**
+ * Notify application when media state in the call has changed.
+ * Normal application would need to implement this callback, e.g.
+ * to connect the call's media to sound device. When ICE is used,
+ * this callback will also be called to report ICE negotiation
+ * failure.
+ *
+ * @param prm Callback parameter.
+ */
+ virtual void onCallMediaState(OnCallMediaStateParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
+ /**
+ * Notify application when a call has just created a local SDP (for
+ * initial or subsequent SDP offer/answer). Application can implement
+ * this callback to modify the SDP, before it is being sent and/or
+ * negotiated with remote SDP, for example to apply per account/call
+ * basis codecs priority or to add custom/proprietary SDP attributes.
+ *
+ * @param prm Callback parameter.
+ */
+ virtual void onCallSdpCreated(OnCallSdpCreatedParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
+ /**
+ * Notify application when media session is created and before it is
+ * registered to the conference bridge. Application may return different
+ * media port if it has added media processing port to the stream. This
+ * media port then will be added to the conference bridge instead.
+ *
+ * @param prm Callback parameter.
+ */
+ virtual void onStreamCreated(OnStreamCreatedParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
+ /**
+ * Notify application when media session has been unregistered from the
+ * conference bridge and about to be destroyed.
+ *
+ * @param prm Callback parameter.
+ */
+ virtual void onStreamDestroyed(OnStreamDestroyedParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
+ /**
+ * Notify application upon incoming DTMF digits.
+ *
+ * @param prm Callback parameter.
+ */
+ virtual void onDtmfDigit(OnDtmfDigitParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
+ /**
+ * Notify application on call being transfered (i.e. REFER is received).
+ * Application can decide to accept/reject transfer request
+ * by setting the code (default is 202). When this callback
+ * is not implemented, the default behavior is to accept the
+ * transfer.
+ *
+ * @param prm Callback parameter.
+ */
+ virtual void onCallTransferRequest(OnCallTransferRequestParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
+ /**
+ * Notify application of the status of previously sent call
+ * transfer request. Application can monitor the status of the
+ * call transfer request, for example to decide whether to
+ * terminate existing call.
+ *
+ * @param prm Callback parameter.
+ */
+ virtual void onCallTransferStatus(OnCallTransferStatusParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
+ /**
+ * Notify application about incoming INVITE with Replaces header.
+ * Application may reject the request by setting non-2xx code.
+ *
+ * @param prm Callback parameter.
+ */
+ virtual void onCallReplaceRequest(OnCallReplaceRequestParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
+ /**
+ * Notify application that an existing call has been replaced with
+ * a new call. This happens when PJSUA-API receives incoming INVITE
+ * request with Replaces header.
+ *
+ * After this callback is called, normally PJSUA-API will disconnect
+ * this call and establish a new call \a newCallId.
+ *
+ * @param prm Callback parameter.
+ */
+ virtual void onCallReplaced(OnCallReplacedParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
+ /**
+ * Notify application when call has received new offer from remote
+ * (i.e. re-INVITE/UPDATE with SDP is received). Application can
+ * decide to accept/reject the offer by setting the code (default
+ * is 200). If the offer is accepted, application can update the
+ * call setting to be applied in the answer. When this callback is
+ * not implemented, the default behavior is to accept the offer using
+ * current call setting.
+ *
+ * @param prm Callback parameter.
+ */
+ virtual void onCallRxOffer(OnCallRxOfferParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
+ /**
+ * Notify application on incoming MESSAGE request.
+ *
+ * @param prm Callback parameter.
+ */
+ virtual void onInstantMessage(OnInstantMessageParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
+ /**
+ * Notify application about the delivery status of outgoing MESSAGE
+ * request.
+ *
+ * @param prm Callback parameter.
+ */
+ virtual void onInstantMessageStatus(OnInstantMessageStatusParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
+ /**
+ * Notify application about typing indication.
+ *
+ * @param prm Callback parameter.
+ */
+ virtual void onTypingIndication(OnTypingIndicationParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
+ /**
+ * This callback is called when the call is about to resend the
+ * INVITE request to the specified target, following the previously
+ * received redirection response.
+ *
+ * Application may accept the redirection to the specified target,
+ * reject this target only and make the session continue to try the next
+ * target in the list if such target exists, stop the whole
+ * redirection process altogether and cause the session to be
+ * disconnected, or defer the decision to ask for user confirmation.
+ *
+ * This callback is optional,
+ * the default behavior is to NOT follow the redirection response.
+ *
+ * @param prm Callback parameter.
+ *
+ * @return Action to be performed for the target. Set this
+ * parameter to one of the value below:
+ * - PJSIP_REDIRECT_ACCEPT: immediately accept the
+ * redirection. When set, the call will immediately
+ * resend INVITE request to the target.
+ * - PJSIP_REDIRECT_ACCEPT_REPLACE: immediately accept
+ * the redirection and replace the To header with the
+ * current target. When set, the call will immediately
+ * resend INVITE request to the target.
+ * - PJSIP_REDIRECT_REJECT: immediately reject this
+ * target. The call will continue retrying with
+ * next target if present, or disconnect the call
+ * if there is no more target to try.
+ * - PJSIP_REDIRECT_STOP: stop the whole redirection
+ * process and immediately disconnect the call. The
+ * onCallState() callback will be called with
+ * PJSIP_INV_STATE_DISCONNECTED state immediately
+ * after this callback returns.
+ * - PJSIP_REDIRECT_PENDING: set to this value if
+ * no decision can be made immediately (for example
+ * to request confirmation from user). Application
+ * then MUST call processRedirect()
+ * to either accept or reject the redirection upon
+ * getting user decision.
+ */
+ virtual pjsip_redirect_op onCallRedirected(OnCallRedirectedParam &prm)
+ {
+ PJ_UNUSED_ARG(prm);
+ return PJSIP_REDIRECT_STOP;
+ }
+
+ /**
+ * This callback is called when media transport state is changed.
+ *
+ * @param prm Callback parameter.
+ */
+ virtual void onCallMediaTransportState(OnCallMediaTransportStateParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
+ /**
+ * Notification about media events such as video notifications. This
+ * callback will most likely be called from media threads, thus
+ * application must not perform heavy processing in this callback.
+ * Especially, application must not destroy the call or media in this
+ * callback. If application needs to perform more complex tasks to
+ * handle the event, it should post the task to another thread.
+ *
+ * @param prm Callback parameter.
+ */
+ virtual void onCallMediaEvent(OnCallMediaEventParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
+ /**
+ * This callback can be used by application to implement custom media
+ * transport adapter for the call, or to replace the media transport
+ * with something completely new altogether.
+ *
+ * This callback is called when a new call is created. The library has
+ * created a media transport for the call, and it is provided as the
+ * \a mediaTp argument of this callback. The callback may change it
+ * with the instance of media transport to be used by the call.
+ *
+ * @param prm Callback parameter.
+ */
+ virtual void
+ onCreateMediaTransport(OnCreateMediaTransportParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
+private:
+ Account &acc;
+ pjsua_call_id id;
+ Token userData;
+ std::vector<Media *> medias;
+};
+
+/**
+ * @} // PJSUA2_CALL
+ */
+
+} // namespace pj
+
+#endif /* __PJSUA2_CALL_HPP__ */
+
diff --git a/pjsip/include/pjsua2/config.hpp b/pjsip/include/pjsua2/config.hpp
new file mode 100644
index 00000000..743a7deb
--- /dev/null
+++ b/pjsip/include/pjsua2/config.hpp
@@ -0,0 +1,47 @@
+/* $Id$ */
+/*
+ * 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
+ */
+#ifndef __PJSUA2_CONFIG_HPP__
+#define __PJSUA2_CONFIG_HPP__
+
+/**
+ * @file pjsua2/config.hpp
+ * @brief PJSUA2 Base Agent Operation
+ */
+#include <pjsua-lib/pjsua.h>
+
+/**
+ * @defgroup PJSUA2_CFG_Compile Compile time settings
+ * @ingroup PJSUA2_DS
+ * @{
+ */
+
+/**
+ * Specify if the Error exception info should contain operation and source
+ * file information.
+ */
+#ifndef PJSUA2_ERROR_HAS_EXTRA_INFO
+# define PJSUA2_ERROR_HAS_EXTRA_INFO 1
+#endif
+
+
+/**
+ * @} PJSUA2_CFG
+ */
+
+#endif /* __PJSUA2_CONFIG_HPP__ */
diff --git a/pjsip/include/pjsua2/doxygen.hpp b/pjsip/include/pjsua2/doxygen.hpp
new file mode 100644
index 00000000..c9952c44
--- /dev/null
+++ b/pjsip/include/pjsua2/doxygen.hpp
@@ -0,0 +1,52 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2008-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
+ */
+#ifndef __PJSUA2_DOXYGEN_HPP__
+#define __PJSUA2_DOXYGEN_HPP__
+
+/**
+ * @file pjsua2/doxygen.hpp
+ * @brief PJSUA2 Doxygen documentation
+ */
+
+/**
+@mainpage pjsua2 API
+
+This documentation contains the API Reference for pjsua2. Please
+go to <b>Modules</b> section above for navigation.
+
+For more info regarding pjsua2, including some tutorials, please
+see The PJSIP Book.
+*/
+
+
+/**
+ * @defgroup PJSUA2_Ref pjsua2 API Reference
+ */
+
+/**
+ * @defgroup PJSUA2_DS Data Structure
+ * @ingroup PJSUA2_Ref
+ */
+
+
+/**
+ * @} PJSUA2_CFG
+ */
+
+#endif /* __PJSUA2_DOXYGEN_HPP__ */
diff --git a/pjsip/include/pjsua2/endpoint.hpp b/pjsip/include/pjsua2/endpoint.hpp
new file mode 100644
index 00000000..5ccd533b
--- /dev/null
+++ b/pjsip/include/pjsua2/endpoint.hpp
@@ -0,0 +1,1322 @@
+/* $Id$ */
+/*
+ * 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
+ */
+#ifndef __PJSUA2_UA_HPP__
+#define __PJSUA2_UA_HPP__
+
+/**
+ * @file pjsua2/endpoint.hpp
+ * @brief PJSUA2 Base Agent Operation
+ */
+#include <pjsua2/persistent.hpp>
+#include <pjsua2/media.hpp>
+#include <pjsua2/siptypes.hpp>
+#include <list>
+
+/** PJSUA2 API is inside pj namespace */
+namespace pj
+{
+
+/**
+ * @defgroup PJSUA2_UA Endpoint
+ * @ingroup PJSUA2_Ref
+ * @{
+ */
+
+using std::string;
+using std::vector;
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Argument to Endpoint::onNatDetectionComplete() callback.
+ */
+struct OnNatDetectionCompleteParam
+{
+ /**
+ * Status of the detection process. If this value is not PJ_SUCCESS,
+ * the detection has failed and \a nat_type field will contain
+ * PJ_STUN_NAT_TYPE_UNKNOWN.
+ */
+ pj_status_t status;
+
+ /**
+ * The text describing the status, if the status is not PJ_SUCCESS.
+ */
+ string reason;
+
+ /**
+ * This contains the NAT type as detected by the detection procedure.
+ * This value is only valid when the \a status is PJ_SUCCESS.
+ */
+ pj_stun_nat_type natType;
+
+ /**
+ * Text describing that NAT type.
+ */
+ string natTypeName;
+
+};
+
+/**
+ * Argument to Endpoint::onNatCheckStunServersComplete() callback.
+ */
+struct OnNatCheckStunServersCompleteParam
+{
+ /**
+ * Arbitrary user data that was passed to Endpoint::natCheckStunServers()
+ * function.
+ */
+ Token userData;
+
+ /**
+ * This will contain PJ_SUCCESS if at least one usable STUN server
+ * is found, otherwise it will contain the last error code during
+ * the operation.
+ */
+ pj_status_t status;
+
+ /**
+ * The server name that yields successful result. This will only
+ * contain value if status is successful.
+ */
+ string name;
+
+ /**
+ * The server IP address and port in "IP:port" format. This will only
+ * contain value if status is successful.
+ */
+ SocketAddress addr;
+};
+
+/**
+ * Parameter of Endpoint::onTimer() callback.
+ */
+struct OnTimerParam
+{
+ /**
+ * Arbitrary user data that was passed to Endpoint::utilTimerSchedule()
+ * function.
+ */
+ Token userData;
+
+ /**
+ * The interval of this timer, in miliseconds.
+ */
+ unsigned msecDelay;
+};
+
+/**
+ * Parameter of Endpoint::onTransportState() callback.
+ */
+struct OnTransportStateParam
+{
+ /**
+ * The transport handle.
+ */
+ TransportHandle hnd;
+
+ /**
+ * Transport current state.
+ */
+ pjsip_transport_state state;
+
+ /**
+ * The last error code related to the transport state.
+ */
+ pj_status_t lastError;
+};
+
+/**
+ * Parameter of Endpoint::onSelectAccount() callback.
+ */
+struct OnSelectAccountParam
+{
+ /**
+ * The incoming request.
+ */
+ SipRxData rdata;
+
+ /**
+ * The account index to be used to handle the request.
+ * Upon entry, this will be filled by the account index
+ * chosen by the library. Application may change it to
+ * another value to use another account.
+ */
+ int accountIndex;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+/**
+ * SIP User Agent related settings.
+ */
+struct UaConfig : public PersistentObject
+{
+ /**
+ * Maximum calls to support (default: 4). The value specified here
+ * must be smaller than the compile time maximum settings
+ * PJSUA_MAX_CALLS, which by default is 32. To increase this
+ * limit, the library must be recompiled with new PJSUA_MAX_CALLS
+ * value.
+ */
+ unsigned maxCalls;
+
+ /**
+ * Number of worker threads. Normally application will want to have at
+ * least one worker thread, unless when it wants to poll the library
+ * periodically, which in this case the worker thread can be set to
+ * zero.
+ */
+ unsigned threadCnt;
+
+ /**
+ * When this flag is non-zero, all callbacks that come from thread
+ * other than main thread will be posted to the main thread and
+ * to be executed by Endpoint::libHandleEvents() function. This
+ * includes the logging callback. Note that this will only work if
+ * threadCnt is set to zero and Endpoint::libHandleEvents() is
+ * performed by main thread. By default, the main thread is set
+ * from the thread that invoke Endpoint::libCreate()
+ *
+ * Default: false
+ */
+ bool mainThreadOnly;
+
+ /**
+ * Array of nameservers to be used by the SIP resolver subsystem.
+ * The order of the name server specifies the priority (first name
+ * server will be used first, unless it is not reachable).
+ */
+ StringVector nameserver;
+
+ /**
+ * Optional user agent string (default empty). If it's empty, no
+ * User-Agent header will be sent with outgoing requests.
+ */
+ string userAgent;
+
+ /**
+ * Array of STUN servers to try. The library will try to resolve and
+ * contact each of the STUN server entry until it finds one that is
+ * usable. Each entry may be a domain name, host name, IP address, and
+ * it may contain an optional port number. For example:
+ * - "pjsip.org" (domain name)
+ * - "sip.pjsip.org" (host name)
+ * - "pjsip.org:33478" (domain name and a non-standard port number)
+ * - "10.0.0.1:3478" (IP address and port number)
+ *
+ * When nameserver is configured in the \a pjsua_config.nameserver field,
+ * if entry is not an IP address, it will be resolved with DNS SRV
+ * resolution first, and it will fallback to use DNS A resolution if this
+ * fails. Port number may be specified even if the entry is a domain name,
+ * in case the DNS SRV resolution should fallback to a non-standard port.
+ *
+ * When nameserver is not configured, entries will be resolved with
+ * pj_gethostbyname() if it's not an IP address. Port number may be
+ * specified if the server is not listening in standard STUN port.
+ */
+ StringVector stunServer;
+
+ /**
+ * This specifies if the library startup should ignore failure with the
+ * STUN servers. If this is set to PJ_FALSE, the library will refuse to
+ * start if it fails to resolve or contact any of the STUN servers.
+ *
+ * Default: TRUE
+ */
+ bool stunIgnoreFailure;
+
+ /**
+ * Support for adding and parsing NAT type in the SDP to assist
+ * troubleshooting. The valid values are:
+ * - 0: no information will be added in SDP, and parsing is disabled.
+ * - 1: only the NAT type number is added.
+ * - 2: add both NAT type number and name.
+ *
+ * Default: 1
+ */
+ int natTypeInSdp;
+
+ /**
+ * Handle unsolicited NOTIFY requests containing message waiting
+ * indication (MWI) info. Unsolicited MWI is incoming NOTIFY requests
+ * which are not requested by client with SUBSCRIBE request.
+ *
+ * If this is enabled, the library will respond 200/OK to the NOTIFY
+ * request and forward the request to Endpoint::onMwiInfo() callback.
+ *
+ * See also AccountMwiConfig.enabled.
+ *
+ * Default: PJ_TRUE
+ */
+ bool mwiUnsolicitedEnabled;
+
+public:
+ /**
+ * Default constructor to initialize with default values.
+ */
+ UaConfig();
+
+ /**
+ * Construct from pjsua_config.
+ */
+ void fromPj(const pjsua_config &ua_cfg);
+
+ /**
+ * Export to pjsua_config
+ */
+ pjsua_config toPj() const;
+
+ /**
+ * Read this object from a container.
+ *
+ * @param node Container to write values from.
+ */
+ virtual void readObject(const ContainerNode &node) throw(Error);
+
+ /**
+ * Write this object to a container.
+ *
+ * @param node Container to write values to.
+ */
+ virtual void writeObject(ContainerNode &node) const throw(Error);
+
+};
+
+
+/**
+ * Data containing log entry to be written by the LogWriter.
+ */
+struct LogEntry
+{
+ /** Log verbosity level of this message */
+ int level;
+
+ /** The log message */
+ string msg;
+
+ /** ID of current thread */
+ long threadId;
+
+ /** The name of the thread that writes this log */
+ string threadName;
+};
+
+
+/**
+ * Interface for writing log messages. Applications can inherit this class
+ * and supply it in the LogConfig structure to implement custom log
+ * writing facility.
+ */
+class LogWriter
+{
+public:
+ /** Destructor */
+ virtual ~LogWriter() {}
+
+ /** Write a log entry. */
+ virtual void write(const LogEntry &entry) = 0;
+};
+
+
+/**
+ * Logging configuration, which can be (optionally) specified when calling
+ * Lib::init().
+ */
+struct LogConfig : public PersistentObject
+{
+ /** Log incoming and outgoing SIP message? Yes! */
+ unsigned msgLogging;
+
+ /** Input verbosity level. Value 5 is reasonable. */
+ unsigned level;
+
+ /** Verbosity level for console. Value 4 is reasonable. */
+ unsigned consoleLevel;
+
+ /** Log decoration. */
+ unsigned decor;
+
+ /** Optional log filename if app wishes the library to write to log file.
+ */
+ string filename;
+
+ /**
+ * Additional flags to be given to pj_file_open() when opening
+ * the log file. By default, the flag is PJ_O_WRONLY. Application
+ * may set PJ_O_APPEND here so that logs are appended to existing
+ * file instead of overwriting it.
+ *
+ * Default is 0.
+ */
+ unsigned fileFlags;
+
+ /**
+ * Custom log writer, if required. This instance will be destroyed
+ * by the endpoint when the endpoint is destroyed.
+ */
+ LogWriter *writer;
+
+public:
+ /** Default constructor initialises with default values */
+ LogConfig();
+
+ /** Construct from pjsua_logging_config */
+ void fromPj(const pjsua_logging_config &lc);
+
+ /** Generate pjsua_logging_config. */
+ pjsua_logging_config toPj() const;
+
+ /**
+ * Read this object from a container.
+ *
+ * @param node Container to write values from.
+ */
+ virtual void readObject(const ContainerNode &node) throw(Error);
+
+ /**
+ * Write this object to a container.
+ *
+ * @param node Container to write values to.
+ */
+ virtual void writeObject(ContainerNode &node) const throw(Error);
+};
+
+
+/**
+ * This structure describes media configuration, which will be specified
+ * when calling Lib::init().
+ */
+struct MediaConfig : public PersistentObject
+{
+public:
+ /**
+ * Clock rate to be applied to the conference bridge.
+ * If value is zero, default clock rate will be used
+ * (PJSUA_DEFAULT_CLOCK_RATE, which by default is 16KHz).
+ */
+ unsigned clockRate;
+
+ /**
+ * Clock rate to be applied when opening the sound device.
+ * If value is zero, conference bridge clock rate will be used.
+ */
+ unsigned sndClockRate;
+
+ /**
+ * Channel count be applied when opening the sound device and
+ * conference bridge.
+ */
+ unsigned channelCount;
+
+ /**
+ * Specify audio frame ptime. The value here will affect the
+ * samples per frame of both the sound device and the conference
+ * bridge. Specifying lower ptime will normally reduce the
+ * latency.
+ *
+ * Default value: PJSUA_DEFAULT_AUDIO_FRAME_PTIME
+ */
+ unsigned audioFramePtime;
+
+ /**
+ * Specify maximum number of media ports to be created in the
+ * conference bridge. Since all media terminate in the bridge
+ * (calls, file player, file recorder, etc), the value must be
+ * large enough to support all of them. However, the larger
+ * the value, the more computations are performed.
+ *
+ * Default value: PJSUA_MAX_CONF_PORTS
+ */
+ unsigned maxMediaPorts;
+
+ /**
+ * Specify whether the media manager should manage its own
+ * ioqueue for the RTP/RTCP sockets. If yes, ioqueue will be created
+ * and at least one worker thread will be created too. If no,
+ * the RTP/RTCP sockets will share the same ioqueue as SIP sockets,
+ * and no worker thread is needed.
+ *
+ * Normally application would say yes here, unless it wants to
+ * run everything from a single thread.
+ */
+ bool hasIoqueue;
+
+ /**
+ * Specify the number of worker threads to handle incoming RTP
+ * packets. A value of one is recommended for most applications.
+ */
+ unsigned threadCnt;
+
+ /**
+ * Media quality, 0-10, according to this table:
+ * 5-10: resampling use large filter,
+ * 3-4: resampling use small filter,
+ * 1-2: resampling use linear.
+ * The media quality also sets speex codec quality/complexity to the
+ * number.
+ *
+ * Default: 5 (PJSUA_DEFAULT_CODEC_QUALITY).
+ */
+ unsigned quality;
+
+ /**
+ * Specify default codec ptime.
+ *
+ * Default: 0 (codec specific)
+ */
+ unsigned ptime;
+
+ /**
+ * Disable VAD?
+ *
+ * Default: 0 (no (meaning VAD is enabled))
+ */
+ bool noVad;
+
+ /**
+ * iLBC mode (20 or 30).
+ *
+ * Default: 30 (PJSUA_DEFAULT_ILBC_MODE)
+ */
+ unsigned ilbcMode;
+
+ /**
+ * Percentage of RTP packet to drop in TX direction
+ * (to simulate packet lost).
+ *
+ * Default: 0
+ */
+ unsigned txDropPct;
+
+ /**
+ * Percentage of RTP packet to drop in RX direction
+ * (to simulate packet lost).
+ *
+ * Default: 0
+ */
+ unsigned rxDropPct;
+
+ /**
+ * Echo canceller options (see pjmedia_echo_create())
+ *
+ * Default: 0.
+ */
+ unsigned ecOptions;
+
+ /**
+ * Echo canceller tail length, in miliseconds. Setting this to zero
+ * will disable echo cancellation.
+ *
+ * Default: PJSUA_DEFAULT_EC_TAIL_LEN
+ */
+ unsigned ecTailLen;
+
+ /**
+ * Audio capture buffer length, in milliseconds.
+ *
+ * Default: PJMEDIA_SND_DEFAULT_REC_LATENCY
+ */
+ unsigned sndRecLatency;
+
+ /**
+ * Audio playback buffer length, in milliseconds.
+ *
+ * Default: PJMEDIA_SND_DEFAULT_PLAY_LATENCY
+ */
+ unsigned sndPlayLatency;
+
+ /**
+ * Jitter buffer initial prefetch delay in msec. The value must be
+ * between jb_min_pre and jb_max_pre below.
+ *
+ * Default: -1 (to use default stream settings, currently 150 msec)
+ */
+ int jbInit;
+
+ /**
+ * Jitter buffer minimum prefetch delay in msec.
+ *
+ * Default: -1 (to use default stream settings, currently 60 msec)
+ */
+ int jbMinPre;
+
+ /**
+ * Jitter buffer maximum prefetch delay in msec.
+ *
+ * Default: -1 (to use default stream settings, currently 240 msec)
+ */
+ int jbMaxPre;
+
+ /**
+ * Set maximum delay that can be accomodated by the jitter buffer msec.
+ *
+ * Default: -1 (to use default stream settings, currently 360 msec)
+ */
+ int jbMax;
+
+ /**
+ * Specify idle time of sound device before it is automatically closed,
+ * in seconds. Use value -1 to disable the auto-close feature of sound
+ * device
+ *
+ * Default : 1
+ */
+ int sndAutoCloseTime;
+
+ /**
+ * Specify whether built-in/native preview should be used if available.
+ * In some systems, video input devices have built-in capability to show
+ * preview window of the device. Using this built-in preview is preferable
+ * as it consumes less CPU power. If built-in preview is not available,
+ * the library will perform software rendering of the input. If this
+ * field is set to PJ_FALSE, software preview will always be used.
+ *
+ * Default: PJ_TRUE
+ */
+ bool vidPreviewEnableNative;
+
+public:
+ /** Default constructor initialises with default values */
+ MediaConfig();
+
+ /** Construct from pjsua_media_config. */
+ void fromPj(const pjsua_media_config &mc);
+
+ /** Export */
+ pjsua_media_config toPj() const;
+
+ /**
+ * Read this object from a container.
+ *
+ * @param node Container to write values from.
+ */
+ virtual void readObject(const ContainerNode &node) throw(Error);
+
+ /**
+ * Write this object to a container.
+ *
+ * @param node Container to write values to.
+ */
+ virtual void writeObject(ContainerNode &node) const throw(Error);
+};
+
+
+/**
+ * Endpoint configuration
+ */
+struct EpConfig : public PersistentObject
+{
+ /** UA config */
+ UaConfig uaConfig;
+
+ /** Logging config */
+ LogConfig logConfig;
+
+ /** Media config */
+ MediaConfig medConfig;
+
+ /**
+ * Read this object from a container.
+ *
+ * @param node Container to write values from.
+ */
+ virtual void readObject(const ContainerNode &node) throw(Error);
+
+ /**
+ * Write this object to a container.
+ *
+ * @param node Container to write values to.
+ */
+ virtual void writeObject(ContainerNode &node) const throw(Error);
+
+};
+
+/* This represents posted job */
+struct PendingJob
+{
+ /** Perform the job */
+ virtual void execute(bool is_pending) = 0;
+
+ /** Virtual destructor */
+ virtual ~PendingJob() {}
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Endpoint represents an instance of pjsua library. There can only be
+ * one instance of pjsua library in an application, hence this class
+ * is a singleton.
+ */
+class Endpoint
+{
+public:
+ /** Retrieve the singleton instance of the endpoint */
+ static Endpoint &instance() throw(Error);
+
+ /** Default constructor */
+ Endpoint();
+
+ /** Virtual destructor */
+ virtual ~Endpoint();
+
+
+ /*************************************************************************
+ * Base library operations
+ */
+
+ /**
+ * Get library version.
+ */
+ Version libVersion() const;
+
+ /**
+ * Instantiate pjsua application. Application must call this function before
+ * calling any other functions, to make sure that the underlying libraries
+ * are properly initialized. Once this function has returned success,
+ * application must call destroy() before quitting.
+ */
+ void libCreate() throw(Error);
+
+ /**
+ * Get library state.
+ *
+ * @return library state.
+ */
+ pjsua_state libGetState() const;
+
+ /**
+ * Initialize pjsua with the specified settings. All the settings are
+ * optional, and the default values will be used when the config is not
+ * specified.
+ *
+ * Note that create() MUST be called before calling this function.
+ *
+ * @param prmEpConfig Endpoint configurations
+ */
+ void libInit( const EpConfig &prmEpConfig) throw(Error);
+
+ /**
+ * Call this function after all initialization is done, so that the
+ * library can do additional checking set up. Application may call this
+ * function any time after init().
+ */
+ void libStart() throw(Error);
+
+ /**
+ * Register a thread to poll for events. This function should be
+ * called by an external worker thread, and it will block polling
+ * for events until the library is destroyed.
+ */
+ void libRegisterWorkerThread(const string &name) throw(Error);
+
+ /**
+ * Stop all worker threads.
+ */
+ void libStopWorkerThreads();
+
+ /**
+ * Poll pjsua for events, and if necessary block the caller thread for
+ * the specified maximum interval (in miliseconds).
+ *
+ * Application doesn't normally need to call this function if it has
+ * configured worker thread (\a thread_cnt field) in pjsua_config
+ * structure, because polling then will be done by these worker threads
+ * instead.
+ *
+ * If EpConfig::UaConfig::mainThreadOnly is enabled and this function
+ * is called from the main thread (by default the main thread is thread
+ * that calls libCreate()), this function will also scan and run any
+ * pending jobs in the list.
+ *
+ * @param msec_timeout Maximum time to wait, in miliseconds.
+ *
+ * @return The number of events that have been handled during the
+ * poll. Negative value indicates error, and application
+ * can retrieve the error as (status = -return_value).
+ */
+ int libHandleEvents(unsigned msec_timeout);
+
+ /**
+ * Destroy pjsua. Application is recommended to perform graceful shutdown
+ * before calling this function (such as unregister the account from the
+ * SIP server, terminate presense subscription, and hangup active calls),
+ * however, this function will do all of these if it finds there are
+ * active sessions that need to be terminated. This function will
+ * block for few seconds to wait for replies from remote.
+ *
+ * Application.may safely call this function more than once if it doesn't
+ * keep track of it's state.
+ *
+ * @param prmFlags Combination of pjsua_destroy_flag enumeration.
+ */
+ void libDestroy(unsigned prmFlags=0) throw(Error);
+
+
+ /*************************************************************************
+ * Utilities
+ */
+
+ /**
+ * Retrieve the error string for the specified status code.
+ *
+ * @param prmErr The error code.
+ */
+ string utilStrError(pj_status_t prmErr);
+
+ /**
+ * Write a log message.
+ *
+ * @param prmLevel Log verbosity level (1-5)
+ * @param prmSender The log sender.
+ * @param prmMsg The log message.
+ */
+ void utilLogWrite(int prmLevel,
+ const string &prmSender,
+ const string &prmMsg);
+
+ /**
+ * Write a log entry.
+ *
+ * @param e The log entry.
+ */
+ void utilLogWrite(LogEntry &e);
+
+ /**
+ * This is a utility function to verify that valid SIP url is given. If the
+ * URL is a valid SIP/SIPS scheme, PJ_SUCCESS will be returned.
+ *
+ * @param prmUri The URL string.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error
+ * code.
+ *
+ * @see utilVerifyUri()
+ */
+ pj_status_t utilVerifySipUri(const string &prmUri);
+
+ /**
+ * This is a utility function to verify that valid URI is given. Unlike
+ * utilVerifySipUri(), this function will return PJ_SUCCESS if tel: URI
+ * is given.
+ *
+ * @param prmUri The URL string.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error
+ * code.
+ *
+ * @see pjsua_verify_sip_url()
+ */
+ pj_status_t utilVerifyUri(const string &prmUri);
+
+ /**
+ * Schedule a timer with the specified interval and user data. When the
+ * interval elapsed, onTimer() callback will be
+ * called. Note that the callback may be executed by different thread,
+ * depending on whether worker thread is enabled or not.
+ *
+ * @param prmMsecDelay The time interval in msec.
+ * @param prmUserData Arbitrary user data, to be given back to
+ * application in the callback.
+ *
+ * @return Token to identify the timer, which could be
+ * given to utilTimerCancel().
+ */
+ Token utilTimerSchedule(unsigned prmMsecDelay,
+ Token prmUserData) throw (Error);
+
+ /**
+ * Cancel previously scheduled timer with the specified timer token.
+ *
+ * @param prmToken The timer token, which was returned from
+ * previous utilTimerSchedule() call.
+ */
+ void utilTimerCancel(Token prmToken);
+
+ /**
+ * Utility to register a pending job to be executed by main thread.
+ * If EpConfig::UaConfig::mainThreadOnly is false, the job will be
+ * executed immediately.
+ *
+ * @param job The job class.
+ */
+ void utilAddPendingJob(PendingJob *job);
+
+ /**
+ * Get cipher list supported by SSL/TLS backend.
+ */
+ IntVector utilSslGetAvailableCiphers() throw (Error);
+
+ /*************************************************************************
+ * NAT operations
+ */
+ /**
+ * This is a utility function to detect NAT type in front of this endpoint.
+ * Once invoked successfully, this function will complete asynchronously
+ * and report the result in onNatDetectionComplete().
+ *
+ * After NAT has been detected and the callback is called, application can
+ * get the detected NAT type by calling natGetType(). Application
+ * can also perform NAT detection by calling natDetectType()
+ * again at later time.
+ *
+ * Note that STUN must be enabled to run this function successfully.
+ */
+ void natDetectType(void) throw(Error);
+
+ /**
+ * Get the NAT type as detected by natDetectType() function. This
+ * function will only return useful NAT type after natDetectType()
+ * has completed successfully and onNatDetectionComplete()
+ * callback has been called.
+ *
+ * Exception: if this function is called while detection is in progress,
+ * PJ_EPENDING exception will be raised.
+ */
+ pj_stun_nat_type natGetType() throw(Error);
+
+ /**
+ * Auxiliary function to resolve and contact each of the STUN server
+ * entries (sequentially) to find which is usable. The libInit() must
+ * have been called before calling this function.
+ *
+ * @param prmServers Array of STUN servers to try. The endpoint
+ * will try to resolve and contact each of the
+ * STUN server entry until it finds one that is
+ * usable. Each entry may be a domain name, host
+ * name, IP address, and it may contain an
+ * optional port number. For example:
+ * - "pjsip.org" (domain name)
+ * - "sip.pjsip.org" (host name)
+ * - "pjsip.org:33478" (domain name and a non-
+ * standard port number)
+ * - "10.0.0.1:3478" (IP address and port number)
+ * @param prmWait Specify if the function should block until
+ * it gets the result. In this case, the function
+ * will block while the resolution is being done,
+ * and the callback will be called before this
+ * function returns.
+ * @param prmUserData Arbitrary user data to be passed back to
+ * application in the callback.
+ *
+ * @see natCancelCheckStunServers()
+ */
+ void natCheckStunServers(const StringVector &prmServers,
+ bool prmWait,
+ Token prmUserData) throw(Error);
+
+ /**
+ * Cancel pending STUN resolution which match the specified token.
+ *
+ * @param token The token to match. This token was given to
+ * natCheckStunServers()
+ * @param notify_cb Boolean to control whether the callback should
+ * be called for cancelled resolutions. When the
+ * callback is called, the status in the result
+ * will be set as PJ_ECANCELLED.
+ *
+ * Exception: PJ_ENOTFOUND if there is no matching one, or other error.
+ */
+ void natCancelCheckStunServers(Token token,
+ bool notify_cb = false) throw(Error);
+
+ /*************************************************************************
+ * Transport operations
+ */
+
+ /**
+ * Create and start a new SIP transport according to the specified
+ * settings.
+ *
+ * @param type Transport type.
+ * @param cfg Transport configuration.
+ *
+ * @return The transport ID.
+ */
+ TransportId transportCreate(pjsip_transport_type_e type,
+ const TransportConfig &cfg) throw(Error);
+
+ /**
+ * Enumerate all transports currently created in the system. This
+ * function will return all transport IDs, and application may then
+ * call transportGetInfo() function to retrieve detailed information
+ * about the transport.
+ *
+ * @return Array of transport IDs.
+ */
+ IntVector transportEnum() throw(Error);
+
+ /**
+ * Get information about transport.
+ *
+ * @param id Transport ID.
+ *
+ * @return Transport info.
+ */
+ TransportInfo transportGetInfo(TransportId id) throw(Error);
+
+ /**
+ * Disable a transport or re-enable it. By default transport is always
+ * enabled after it is created. Disabling a transport does not necessarily
+ * close the socket, it will only discard incoming messages and prevent
+ * the transport from being used to send outgoing messages.
+ *
+ * @param id Transport ID.
+ * @param enabled Enable or disable the transport.
+ *
+ */
+ void transportSetEnable(TransportId id, bool enabled) throw(Error);
+
+ /**
+ * Close the transport. The system will wait until all transactions are
+ * closed while preventing new users from using the transport, and will
+ * close the transport when its usage count reaches zero.
+ *
+ * @param id Transport ID.
+ */
+ void transportClose(TransportId id) throw(Error);
+
+ /*************************************************************************
+ * Call operations
+ */
+
+ /**
+ * Terminate all calls. This will initiate call hangup for all
+ * currently active calls.
+ */
+ void hangupAllCalls(void);
+
+ /*************************************************************************
+ * Media operations
+ */
+
+ /**
+ * Add media to the media list.
+ *
+ * @param media media to be added.
+ */
+ void mediaAdd(AudioMedia &media);
+
+ /**
+ * Remove media from the media list.
+ *
+ * @param media media to be removed.
+ */
+ void mediaRemove(AudioMedia &media);
+
+ /**
+ * Check if media has been added to the media list.
+ *
+ * @param media media to be check.
+ *
+ * @return True if media has been added, false otherwise.
+ */
+ bool mediaExists(const AudioMedia &media) const;
+
+ /**
+ * Get maximum number of media port.
+ *
+ * @return Maximum number of media port in the conference bridge.
+ */
+ unsigned mediaMaxPorts() const;
+
+ /**
+ * Get current number of active media port in the bridge.
+ *
+ * @return The number of active media port.
+ */
+ unsigned mediaActivePorts() const;
+
+ /**
+ * Enumerate all media port.
+ *
+ * @return The list of media port.
+ */
+ const AudioMediaVector &mediaEnumPorts() const throw(Error);
+
+ /**
+ * Get the instance of Audio Device Manager.
+ *
+ * @return The Audio Device Manager.
+ */
+ AudDevManager &audDevManager();
+
+ /*************************************************************************
+ * Codec management operations
+ */
+
+ /**
+ * Enum all supported codecs in the system.
+ *
+ * @return Array of codec info.
+ */
+ const CodecInfoVector &codecEnum() throw(Error);
+
+ /**
+ * Change codec priority.
+ *
+ * @param codec_id Codec ID, which is a string that uniquely identify
+ * the codec (such as "speex/8000").
+ * @param priority Codec priority, 0-255, where zero means to disable
+ * the codec.
+ *
+ */
+ void codecSetPriority(const string &codec_id,
+ pj_uint8_t priority) throw(Error);
+
+ /**
+ * Get codec parameters.
+ *
+ * @param codec_id Codec ID.
+ *
+ * @return Codec parameters. If codec is not found, Error
+ * will be thrown.
+ *
+ */
+ CodecParam codecGetParam(const string &codec_id) const throw(Error);
+
+ /**
+ * Set codec parameters.
+ *
+ * @param codec_id Codec ID.
+ * @param param Codec parameter to set. Set to NULL to reset
+ * codec parameter to library default settings.
+ *
+ */
+ void codecSetParam(const string &codec_id,
+ const CodecParam param) throw(Error);
+
+
+public:
+ /*
+ * Overrideables callbacks
+ */
+
+ /**
+ * Callback when the Endpoint has finished performing NAT type
+ * detection that is initiated with natDetectType().
+ *
+ * @param prm Callback parameters containing the detection
+ * result.
+ */
+ virtual void onNatDetectionComplete(
+ const OnNatDetectionCompleteParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
+ /**
+ * Callback when the Endpoint has finished performing STUN server
+ * checking that is initiated with natCheckStunServers().
+ *
+ * @param prm Callback parameters.
+ */
+ virtual void onNatCheckStunServersComplete(
+ const OnNatCheckStunServersCompleteParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
+ /**
+ * This callback is called when transport state has changed.
+ *
+ * @param prm Callback parameters.
+ */
+ virtual void onTransportState(
+ const OnTransportStateParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
+ /**
+ * Callback when a timer has fired. The timer was scheduled by
+ * utilTimerSchedule().
+ *
+ * @param prm Callback parameters.
+ */
+ virtual void onTimer(const OnTimerParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
+ /**
+ * This callback can be used by application to override the account
+ * to be used to handle an incoming message. Initially, the account to
+ * be used will be calculated automatically by the library. This initial
+ * account will be used if application does not implement this callback,
+ * or application sets an invalid account upon returning from this
+ * callback.
+ *
+ * Note that currently the incoming messages requiring account assignment
+ * are INVITE, MESSAGE, SUBSCRIBE, and unsolicited NOTIFY. This callback
+ * may be called before the callback of the SIP event itself, i.e:
+ * incoming call, pager, subscription, or unsolicited-event.
+ *
+ * @param prm Callback parameters.
+ */
+ virtual void onSelectAccount(OnSelectAccountParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
+private:
+ static Endpoint *instance_; // static instance
+ LogWriter *writer; // Custom writer, if any
+ AudioMediaVector mediaList;
+ AudDevManager audioDevMgr;
+ CodecInfoVector codecInfoList;
+
+ /* Pending logging */
+ bool mainThreadOnly;
+ void *mainThread;
+ unsigned pendingJobSize;
+ std::list<PendingJob*> pendingJobs;
+
+ void performPendingJobs();
+
+ /* Endpoint static callbacks */
+ static void logFunc(int level, const char *data, int len);
+ static void stun_resolve_cb(const pj_stun_resolve_result *result);
+ static void on_timer(pj_timer_heap_t *timer_heap,
+ struct pj_timer_entry *entry);
+ static void on_nat_detect(const pj_stun_nat_detect_result *res);
+ static void on_transport_state(pjsip_transport *tp,
+ pjsip_transport_state state,
+ const pjsip_transport_state_info *info);
+
+private:
+ /*
+ * Account & Call lookups
+ */
+ static Account *lookupAcc(int acc_id, const char *op);
+ static Call *lookupCall(int call_id, const char *op);
+
+ /* static callbacks */
+ static void on_incoming_call(pjsua_acc_id acc_id,
+ pjsua_call_id call_id,
+ pjsip_rx_data *rdata);
+ static void on_reg_started(pjsua_acc_id acc_id,
+ pj_bool_t renew);
+ static void on_reg_state2(pjsua_acc_id acc_id,
+ pjsua_reg_info *info);
+ static void on_incoming_subscribe(pjsua_acc_id acc_id,
+ pjsua_srv_pres *srv_pres,
+ pjsua_buddy_id buddy_id,
+ const pj_str_t *from,
+ pjsip_rx_data *rdata,
+ pjsip_status_code *code,
+ pj_str_t *reason,
+ pjsua_msg_data *msg_data);
+ static void on_pager2(pjsua_call_id call_id,
+ const pj_str_t *from,
+ const pj_str_t *to,
+ const pj_str_t *contact,
+ const pj_str_t *mime_type,
+ const pj_str_t *body,
+ pjsip_rx_data *rdata,
+ pjsua_acc_id acc_id);
+ static void on_pager_status2(pjsua_call_id call_id,
+ const pj_str_t *to,
+ const pj_str_t *body,
+ void *user_data,
+ pjsip_status_code status,
+ const pj_str_t *reason,
+ pjsip_tx_data *tdata,
+ pjsip_rx_data *rdata,
+ pjsua_acc_id acc_id);
+ static void on_typing2(pjsua_call_id call_id,
+ const pj_str_t *from,
+ const pj_str_t *to,
+ const pj_str_t *contact,
+ pj_bool_t is_typing,
+ pjsip_rx_data *rdata,
+ pjsua_acc_id acc_id);
+ static void on_mwi_info(pjsua_acc_id acc_id,
+ pjsua_mwi_info *mwi_info);
+
+ static void on_buddy_state(pjsua_buddy_id buddy_id);
+ // Call callbacks
+ static void on_call_state(pjsua_call_id call_id, pjsip_event *e);
+ static void on_call_tsx_state(pjsua_call_id call_id,
+ pjsip_transaction *tsx,
+ pjsip_event *e);
+ static void on_call_media_state(pjsua_call_id call_id);
+ static void on_call_sdp_created(pjsua_call_id call_id,
+ pjmedia_sdp_session *sdp,
+ pj_pool_t *pool,
+ const pjmedia_sdp_session *rem_sdp);
+ static void on_stream_created(pjsua_call_id call_id,
+ pjmedia_stream *strm,
+ unsigned stream_idx,
+ pjmedia_port **p_port);
+ static void on_stream_destroyed(pjsua_call_id call_id,
+ pjmedia_stream *strm,
+ unsigned stream_idx);
+ static void on_dtmf_digit(pjsua_call_id call_id, int digit);
+ static void on_call_transfer_request(pjsua_call_id call_id,
+ const pj_str_t *dst,
+ pjsip_status_code *code);
+ static void on_call_transfer_request2(pjsua_call_id call_id,
+ const pj_str_t *dst,
+ pjsip_status_code *code,
+ pjsua_call_setting *opt);
+ static void on_call_transfer_status(pjsua_call_id call_id,
+ int st_code,
+ const pj_str_t *st_text,
+ pj_bool_t final,
+ pj_bool_t *p_cont);
+ static void on_call_replace_request(pjsua_call_id call_id,
+ pjsip_rx_data *rdata,
+ int *st_code,
+ pj_str_t *st_text);
+ static void on_call_replace_request2(pjsua_call_id call_id,
+ pjsip_rx_data *rdata,
+ int *st_code,
+ pj_str_t *st_text,
+ pjsua_call_setting *opt);
+ static void on_call_replaced(pjsua_call_id old_call_id,
+ pjsua_call_id new_call_id);
+ static void on_call_rx_offer(pjsua_call_id call_id,
+ const pjmedia_sdp_session *offer,
+ void *reserved,
+ pjsip_status_code *code,
+ pjsua_call_setting *opt);
+ static pjsip_redirect_op on_call_redirected(pjsua_call_id call_id,
+ const pjsip_uri *target,
+ const pjsip_event *e);
+ static pj_status_t
+ on_call_media_transport_state(pjsua_call_id call_id,
+ const pjsua_med_tp_state_info *info);
+ static void on_call_media_event(pjsua_call_id call_id,
+ unsigned med_idx,
+ pjmedia_event *event);
+ static pjmedia_transport*
+ on_create_media_transport(pjsua_call_id call_id,
+ unsigned media_idx,
+ pjmedia_transport *base_tp,
+ unsigned flags);
+
+private:
+ void clearCodecInfoList();
+
+};
+
+
+
+/**
+ * @} PJSUA2_UA
+ */
+
+}
+/* End pj namespace */
+
+
+#endif /* __PJSUA2_UA_HPP__ */
+
diff --git a/pjsip/include/pjsua2/json.hpp b/pjsip/include/pjsua2/json.hpp
new file mode 100644
index 00000000..0c28c6a8
--- /dev/null
+++ b/pjsip/include/pjsua2/json.hpp
@@ -0,0 +1,116 @@
+/* $Id$ */
+/*
+ * 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
+ */
+#ifndef __PJSUA2_JSON_HPP__
+#define __PJSUA2_JSON_HPP__
+
+/**
+ * @file pjsua2/persistent.hpp
+ * @brief PJSUA2 Persistent Services
+ */
+#include <pjsua2/persistent.hpp>
+#include <pjlib-util/json.h>
+#include <pj/pool.h>
+#include <string>
+
+/** PJSUA2 API is inside pj namespace */
+namespace pj
+{
+
+/**
+ * @defgroup PJSUA2_JSON JSON Persistent Support
+ * @ingroup PJSUA2_PERSISTENT
+ * @{
+ * Provides object serialization and deserialization to/from JSON document.
+ */
+
+using std::string;
+
+/**
+ * Persistent document (file) with JSON format.
+ */
+class JsonDocument : public PersistentDocument
+{
+public:
+ /** Default constructor */
+ JsonDocument();
+
+ /** Destructor */
+ ~JsonDocument();
+
+ /**
+ * Load this document from a file.
+ *
+ * @param filename The file name.
+ */
+ virtual void loadFile(const string &filename) throw(Error);
+
+ /**
+ * Load this document from string.
+ *
+ * @param input The string.
+ */
+ virtual void loadString(const string &input) throw(Error);
+
+ /**
+ * Write this document to a file.
+ *
+ * @param filename The file name.
+ */
+ virtual void saveFile(const string &filename) throw(Error);
+
+ /**
+ * Write this document to string.
+ */
+ virtual string saveString() throw(Error);
+
+ /**
+ * Get the root container node for this document
+ */
+ virtual ContainerNode & getRootContainer() const;
+
+ /**
+ * An internal function to create JSON element.
+ */
+ pj_json_elem* allocElement() const;
+
+ /**
+ * An internal function to get the pool.
+ */
+ pj_pool_t* getPool();
+
+private:
+ pj_caching_pool cp;
+ mutable ContainerNode rootNode;
+ mutable pj_json_elem *root;
+ mutable pj_pool_t *pool;
+
+ void initRoot() const;
+};
+
+
+
+
+/**
+ * @} PJSUA2
+ */
+
+} // namespace pj
+
+
+#endif /* __PJSUA2_JSON_HPP__ */
diff --git a/pjsip/include/pjsua2/media.hpp b/pjsip/include/pjsua2/media.hpp
new file mode 100644
index 00000000..4c4e65f4
--- /dev/null
+++ b/pjsip/include/pjsua2/media.hpp
@@ -0,0 +1,1162 @@
+/* $Id$ */
+/*
+ * 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
+ */
+
+#ifndef __PJSUA2_MEDIA_HPP__
+#define __PJSUA2_MEDIA_HPP__
+
+/**
+ * @file pjsua2/media.hpp
+ * @brief PJSUA2 media operations
+ */
+#include <pjsua-lib/pjsua.h>
+#include <pjsua2/types.hpp>
+
+/** PJSUA2 API is inside pj namespace */
+namespace pj
+{
+
+/**
+ * @defgroup PJSUA2_MED Media
+ * @ingroup PJSUA2_Ref
+ * @{
+ */
+
+using std::string;
+using std::vector;
+
+/**
+ * This structure contains all the information needed to completely describe
+ * a media.
+ */
+struct MediaFormat
+{
+ /**
+ * The format id that specifies the audio sample or video pixel format.
+ * Some well known formats ids are declared in pjmedia_format_id
+ * enumeration.
+ *
+ * @see pjmedia_format_id
+ */
+ pj_uint32_t id;
+
+ /**
+ * The top-most type of the media, as an information.
+ */
+ pjmedia_type type;
+};
+
+/**
+ * This structure describe detail information about an audio media.
+ */
+struct MediaFormatAudio : public MediaFormat
+{
+ unsigned clockRate; /**< Audio clock rate in samples or Hz. */
+ unsigned channelCount; /**< Number of channels. */
+ unsigned frameTimeUsec; /**< Frame interval, in microseconds. */
+ unsigned bitsPerSample; /**< Number of bits per sample. */
+ pj_uint32_t avgBps; /**< Average bitrate */
+ pj_uint32_t maxBps; /**< Maximum bitrate */
+
+ /**
+ * Construct from pjmedia_format.
+ */
+ void fromPj(const pjmedia_format &format);
+
+ /**
+ * Export to pjmedia_format.
+ */
+ pjmedia_format toPj() const;
+};
+
+/**
+ * This structure describe detail information about an video media.
+ */
+struct MediaFormatVideo : public MediaFormat
+{
+ unsigned width; /**< Video width. */
+ unsigned height; /**< Video height. */
+ int fpsNum; /**< Frames per second numerator. */
+ int fpsDenum; /**< Frames per second denumerator. */
+ pj_uint32_t avgBps; /**< Average bitrate. */
+ pj_uint32_t maxBps; /**< Maximum bitrate. */
+};
+
+/** Array of MediaFormat */
+typedef std::vector<MediaFormat*> MediaFormatVector;
+
+/**
+ * This structure descibes information about a particular media port that
+ * has been registered into the conference bridge.
+ */
+struct ConfPortInfo
+{
+ /**
+ * Conference port number.
+ */
+ int portId;
+
+ /**
+ * Port name.
+ */
+ string name;
+
+ /**
+ * Media audio format information
+ */
+ MediaFormatAudio format;
+
+ /**
+ * Tx level adjustment. Value 1.0 means no adjustment, value 0 means
+ * the port is muted, value 2.0 means the level is amplified two times.
+ */
+ float txLevelAdj;
+
+ /**
+ * Rx level adjustment. Value 1.0 means no adjustment, value 0 means
+ * the port is muted, value 2.0 means the level is amplified two times.
+ */
+ float rxLevelAdj;
+
+ /**
+ * Array of listeners (in other words, ports where this port is
+ * transmitting to.
+ */
+ IntVector listeners;
+
+public:
+ /**
+ * Construct from pjsua_conf_port_info.
+ */
+ void fromPj(const pjsua_conf_port_info &port_info);
+};
+
+/**
+ * Media port, corresponds to pjmedia_port
+ */
+typedef void *MediaPort;
+
+/**
+ * Media.
+ */
+class Media
+{
+public:
+ /**
+ * Virtual destructor.
+ */
+ virtual ~Media();
+
+ /**
+ * Get type of the media.
+ *
+ * @return The media type.
+ */
+ pjmedia_type getType() const;
+
+protected:
+ /**
+ * Constructor.
+ */
+ Media(pjmedia_type med_type);
+
+private:
+ /**
+ * Media type.
+ */
+ pjmedia_type type;
+};
+
+/**
+ * Audio Media.
+ */
+class AudioMedia : public Media
+{
+public:
+ /**
+ * Get information about the specified conference port.
+ */
+ ConfPortInfo getPortInfo() const throw(Error);
+
+ /**
+ * Get port Id.
+ */
+ int getPortId() const;
+
+ /**
+ * Get information from specific port id.
+ */
+ static ConfPortInfo getPortInfoFromId(int port_id) throw(Error);
+
+ /**
+ * Establish unidirectional media flow to sink. This media port
+ * will act as a source, and it may transmit to multiple destinations/sink.
+ * And if multiple sources are transmitting to the same sink, the media
+ * will be mixed together. Source and sink may refer to the same Media,
+ * effectively looping the media.
+ *
+ * If bidirectional media flow is desired, application needs to call
+ * this method twice, with the second one called from the opposite source
+ * media.
+ *
+ * @param sink The destination Media.
+ */
+ void startTransmit(const AudioMedia &sink) const throw(Error);
+
+ /**
+ * Stop media flow to destination/sink port.
+ *
+ * @param sink The destination media.
+ *
+ */
+ void stopTransmit(const AudioMedia &sink) const throw(Error);
+
+ /**
+ * Adjust the signal level to be transmitted from the bridge to this
+ * media port by making it louder or quieter.
+ *
+ * @param level Signal level adjustment. Value 1.0 means no
+ * level adjustment, while value 0 means to mute
+ * the port.
+ */
+ void adjustRxLevel(float level) throw(Error);
+
+ /**
+ * Adjust the signal level to be received from this media port (to
+ * the bridge) by making it louder or quieter.
+ *
+ * @param level Signal level adjustment. Value 1.0 means no
+ * level adjustment, while value 0 means to mute
+ * the port.
+ */
+ void adjustTxLevel(float level) throw(Error);
+
+ /**
+ * Get the last received signal level.
+ *
+ * @return Signal level in percent.
+ */
+ unsigned getRxLevel() const throw(Error);
+
+ /**
+ * Get the last transmitted signal level.
+ *
+ * @return Signal level in percent.
+ */
+ unsigned getTxLevel() const throw(Error);
+
+ /**
+ * Typecast from base class Media. This is useful for application written
+ * in language that does not support downcasting such as Python.
+ *
+ * @param media The object to be downcasted
+ *
+ * @return The object as AudioMedia instance
+ */
+ static AudioMedia* typecastFromMedia(Media *media);
+
+ /**
+ * Virtual Destructor
+ */
+ virtual ~AudioMedia();
+
+protected:
+ /**
+ * Conference port Id.
+ */
+ int id;
+
+protected:
+ /**
+ * Default Constructor.
+ */
+ AudioMedia();
+
+ /**
+ * This method needs to be called by descendants of this class to register
+ * the media port created to the conference bridge and Endpoint's
+ * media list.
+ *
+ * param port the media port to be registered to the conference bridge.
+ *
+ */
+ void registerMediaPort(MediaPort port) throw(Error);
+
+ /**
+ * This method needs to be called by descendants of this class to remove
+ * the media port from the conference bridge and Endpoint's media list.
+ * Descendant should only call this method if it has registered the media
+ * with the previous call to registerMediaPort().
+ */
+ void unregisterMediaPort();
+
+private:
+ pj_caching_pool mediaCachingPool;
+ pj_pool_t *mediaPool;
+
+private:
+ unsigned getSignalLevel(bool is_rx = true) const throw(Error);
+};
+
+/** Array of Audio Media */
+typedef std::vector<AudioMedia*> AudioMediaVector;
+
+/**
+ * Audio Media Player.
+ */
+class AudioMediaPlayer : public AudioMedia
+{
+public:
+ /**
+ * Constructor.
+ */
+ AudioMediaPlayer();
+
+ /**
+ * Create a file player, and automatically add this
+ * player to the conference bridge.
+ *
+ * @param file_name The filename to be played. Currently only
+ * WAV files are supported, and the WAV file MUST be
+ * formatted as 16bit PCM mono/single channel (any
+ * clock rate is supported).
+ * @param options Optional option flag. Application may specify
+ * PJMEDIA_FILE_NO_LOOP to prevent playback loop.
+ */
+ void createPlayer(const string &file_name,
+ unsigned options=PJMEDIA_FILE_NO_LOOP) throw(Error);
+
+ /**
+ * Create a file playlist media port, and automatically add the port
+ * to the conference bridge.
+ *
+ * @param file_names Array of file names to be added to the play list.
+ * Note that the files must have the same clock rate,
+ * number of channels, and number of bits per sample.
+ * @param label Optional label to be set for the media port.
+ * @param options Optional option flag. Application may specify
+ * PJMEDIA_FILE_NO_LOOP to prevent looping.
+ */
+ void createPlaylist(const StringVector &file_names,
+ const string &label="",
+ unsigned options=PJMEDIA_FILE_NO_LOOP) throw(Error);
+
+ /**
+ * Set playback position. This operation is not valid for playlist.
+ */
+ void setPos(pj_uint32_t samples) throw(Error);
+
+ /**
+ * Typecast from base class AudioMedia. This is useful for application
+ * written in language that does not support downcasting such as Python.
+ *
+ * @param media The object to be downcasted
+ *
+ * @return The object as AudioMediaPlayer instance
+ */
+ static AudioMediaPlayer* typecastFromAudioMedia(AudioMedia *media);
+
+ /**
+ * Virtual destructor.
+ */
+ virtual ~AudioMediaPlayer();
+
+private:
+ /**
+ * Player Id.
+ */
+ int playerId;
+
+};
+
+/**
+ * Audio Media Recorder.
+ */
+class AudioMediaRecorder : public AudioMedia
+{
+public:
+ /**
+ * Constructor.
+ */
+ AudioMediaRecorder();
+
+ /**
+ * Create a file recorder, and automatically connect this recorder to
+ * the conference bridge. The recorder currently supports recording WAV
+ * file. The type of the recorder to use is determined by the extension of
+ * the file (e.g. ".wav").
+ *
+ * @param file_name Output file name. The function will determine the
+ * default format to be used based on the file extension.
+ * Currently ".wav" is supported on all platforms.
+ * @param enc_type Optionally specify the type of encoder to be used to
+ * compress the media, if the file can support different
+ * encodings. This value must be zero for now.
+ * @param max_size Maximum file size. Specify zero or -1 to remove size
+ * limitation. This value must be zero or -1 for now.
+ * @param options Optional options.
+ */
+ void createRecorder(const string &file_name,
+ unsigned enc_type=0,
+ pj_ssize_t max_size=0,
+ unsigned options=PJMEDIA_FILE_WRITE_PCM) throw(Error);
+
+ /**
+ * Typecast from base class AudioMedia. This is useful for application
+ * written in language that does not support downcasting such as Python.
+ *
+ * @param media The object to be downcasted
+ *
+ * @return The object as AudioMediaRecorder instance
+ */
+ static AudioMediaRecorder* typecastFromAudioMedia(AudioMedia *media);
+
+ /**
+ * Virtual destructor.
+ */
+ virtual ~AudioMediaRecorder();
+
+private:
+ /**
+ * Recorder Id.
+ */
+ int recorderId;
+};
+
+/*************************************************************************
+* Sound device management
+*/
+
+/**
+ * Audio device information structure.
+ */
+struct AudioDevInfo
+{
+ /**
+ * The device name
+ */
+ string name;
+
+ /**
+ * Maximum number of input channels supported by this device. If the
+ * value is zero, the device does not support input operation (i.e.
+ * it is a playback only device).
+ */
+ unsigned inputCount;
+
+ /**
+ * Maximum number of output channels supported by this device. If the
+ * value is zero, the device does not support output operation (i.e.
+ * it is an input only device).
+ */
+ unsigned outputCount;
+
+ /**
+ * Default sampling rate.
+ */
+ unsigned defaultSamplesPerSec;
+
+ /**
+ * The underlying driver name
+ */
+ string driver;
+
+ /**
+ * Device capabilities, as bitmask combination of pjmedia_aud_dev_cap.
+ */
+ unsigned caps;
+
+ /**
+ * Supported audio device routes, as bitmask combination of
+ * pjmedia_aud_dev_route. The value may be zero if the device
+ * does not support audio routing.
+ */
+ unsigned routes;
+
+ /**
+ * Array of supported extended audio formats
+ */
+ MediaFormatVector extFmt;
+
+ /**
+ * Construct from pjmedia_aud_dev_info.
+ */
+ void fromPj(const pjmedia_aud_dev_info &dev_info);
+
+ /**
+ * Destructor.
+ */
+ ~AudioDevInfo();
+};
+
+/** Array of audio device info */
+typedef std::vector<AudioDevInfo*> AudioDevInfoVector;
+
+/**
+ * Audio device manager.
+ */
+class AudDevManager
+{
+public:
+ /**
+ * Get currently active capture sound devices. If sound devices has not been
+ * created, it is possible that the function returns -1 as device IDs.
+ *
+ * @return Device ID of the capture device.
+ */
+ int getCaptureDev() const throw(Error);
+
+ /**
+ * Get the AudioMedia of the capture audio device.
+ *
+ * @return Audio media for the capture device.
+ */
+ AudioMedia &getCaptureDevMedia() throw(Error);
+
+ /**
+ * Get currently active playback sound devices. If sound devices has not
+ * been created, it is possible that the function returns -1 as device IDs.
+ *
+ * @return Device ID of the playback device.
+ */
+ int getPlaybackDev() const throw(Error);
+
+ /**
+ * Get the AudioMedia of the speaker/playback audio device.
+ *
+ * @return Audio media for the speaker/playback device.
+ */
+ AudioMedia &getPlaybackDevMedia() throw(Error);
+
+ /**
+ * Select or change capture sound device. Application may call this
+ * function at any time to replace current sound device.
+ *
+ * @param capture_dev Device ID of the capture device.
+ */
+ void setCaptureDev(int capture_dev) const throw(Error);
+
+ /**
+ * Select or change playback sound device. Application may call this
+ * function at any time to replace current sound device.
+ *
+ * @param playback_dev Device ID of the playback device.
+ */
+ void setPlaybackDev(int playback_dev) const throw(Error);
+
+ /**
+ * Enum all audio devices installed in the system.
+ *
+ * @return The list of audio device info.
+ */
+ const AudioDevInfoVector &enumDev() throw(Error);
+
+ /**
+ * Set pjsua to use null sound device. The null sound device only provides
+ * the timing needed by the conference bridge, and will not interract with
+ * any hardware.
+ *
+ */
+ void setNullDev() throw(Error);
+
+ /**
+ * Disconnect the main conference bridge from any sound devices, and let
+ * application connect the bridge to it's own sound device/master port.
+ *
+ * @return The port interface of the conference bridge,
+ * so that application can connect this to it's
+ * own sound device or master port.
+ */
+ MediaPort *setNoDev();
+
+ /**
+ * Change the echo cancellation settings.
+ *
+ * The behavior of this function depends on whether the sound device is
+ * currently active, and if it is, whether device or software AEC is
+ * being used.
+ *
+ * If the sound device is currently active, and if the device supports AEC,
+ * this function will forward the change request to the device and it will
+ * be up to the device on whether support the request. If software AEC is
+ * being used (the software EC will be used if the device does not support
+ * AEC), this function will change the software EC settings. In all cases,
+ * the setting will be saved for future opening of the sound device.
+ *
+ * If the sound device is not currently active, this will only change the
+ * default AEC settings and the setting will be applied next time the
+ * sound device is opened.
+ *
+ * @param tail_msec The tail length, in miliseconds. Set to zero to
+ * disable AEC.
+ * @param options Options to be passed to pjmedia_echo_create().
+ * Normally the value should be zero.
+ *
+ */
+ void setEcOptions(unsigned tail_msec, unsigned options) throw(Error);
+
+ /**
+ * Get current echo canceller tail length.
+ *
+ * @return The EC tail length in milliseconds,
+ * If AEC is disabled, the value will be zero.
+ */
+ unsigned getEcTail() const throw(Error);
+
+ /**
+ * Check whether the sound device is currently active. The sound device
+ * may be inactive if the application has set the auto close feature to
+ * non-zero (the sndAutoCloseTime setting in MediaConfig), or
+ * if null sound device or no sound device has been configured via the
+ * setNoDev() function.
+ */
+ bool sndIsActive() const;
+
+ /**
+ * Refresh the list of sound devices installed in the system. This method
+ * will only refresh the list of audio device so all active audio streams
+ * will be unaffected. After refreshing the device list, application MUST
+ * make sure to update all index references to audio devices before calling
+ * any method that accepts audio device index as its parameter.
+ *
+ */
+ void refreshDevs() throw(Error);
+
+ /**
+ * Get the number of sound devices installed in the system.
+ *
+ * @return The number of sound devices installed in the
+ * system.
+ *
+ */
+ unsigned getDevCount() const;
+
+ /**
+ * Get device information.
+ *
+ * @param id The audio device ID.
+ *
+ * @return The device information which will be filled in
+ * by this method once it returns successfully.
+ */
+ AudioDevInfo getDevInfo(int id) const throw(Error);
+
+ /**
+ * Lookup device index based on the driver and device name.
+ *
+ * @param drv_name The driver name.
+ * @param dev_name The device name.
+ *
+ * @return The device ID. If the device is not found,
+ * Error will be thrown.
+ */
+ int lookupDev(const string &drv_name,
+ const string &dev_name) const throw(Error);
+
+ /**
+ * Get string info for the specified capability.
+ *
+ * @param cap The capability ID.
+ *
+ * @return Capability name.
+ */
+ string capName(pjmedia_aud_dev_cap cap) const;
+
+ /**
+ * This will configure audio format capability (other than PCM) to the
+ * sound device being used. If sound device is currently active, the method
+ * will forward the setting to the sound device instance to be applied
+ * immediately, if it supports it.
+ *
+ * This method is only valid if the device has
+ * PJMEDIA_AUD_DEV_CAP_EXT_FORMAT capability in AudioDevInfo.caps flags,
+ * otherwise Error will be thrown.
+ *
+ * Note that in case the setting is kept for future use, it will be applied
+ * to any devices, even when application has changed the sound device to be
+ * used.
+ *
+ * @param format The audio format.
+ * @param keep Specify whether the setting is to be kept for
+ * future use.
+ *
+ */
+ void
+ setExtFormat(const MediaFormatAudio &format, bool keep=true) throw(Error);
+
+ /**
+ * Get the audio format capability (other than PCM) of the sound device
+ * being used. If sound device is currently active, the method will forward
+ * the request to the sound device. If sound device is currently inactive,
+ * and if application had previously set the setting and mark the setting
+ * as kept, then that setting will be returned. Otherwise, this method
+ * will raise error.
+ *
+ * This method is only valid if the device has
+ * PJMEDIA_AUD_DEV_CAP_EXT_FORMAT capability in AudioDevInfo.caps flags,
+ * otherwise Error will be thrown.
+ *
+ * @return The audio format.
+ *
+ */
+ MediaFormatAudio getExtFormat() const throw(Error);
+
+ /**
+ * This will configure audio input latency control or query capability to
+ * the sound device being used. If sound device is currently active,
+ * the method will forward the setting to the sound device instance to be
+ * applied immediately, if it supports it.
+ *
+ * This method is only valid if the device has
+ * PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY capability in AudioDevInfo.caps flags,
+ * otherwise Error will be thrown.
+ *
+ * Note that in case the setting is kept for future use, it will be applied
+ * to any devices, even when application has changed the sound device to be
+ * used.
+ *
+ * @param latency_msec The input latency.
+ * @param keep Specify whether the setting is to be kept
+ * for future use.
+ */
+ void
+ setInputLatency(unsigned latency_msec, bool keep=true) throw(Error);
+
+ /**
+ * Get the audio input latency control or query capability of the sound
+ * device being used. If sound device is currently active, the method will
+ * forward the request to the sound device. If sound device is currently
+ * inactive, and if application had previously set the setting and mark the
+ * setting as kept, then that setting will be returned. Otherwise, this
+ * method will raise error.
+ *
+ * This method is only valid if the device has
+ * PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY capability in AudioDevInfo.caps flags,
+ * otherwise Error will be thrown.
+ *
+ * @return The audio input latency.
+ *
+ */
+ unsigned getInputLatency() const throw(Error);
+
+ /**
+ * This will configure audio output latency control or query capability to
+ * the sound device being used. If sound device is currently active,
+ * the method will forward the setting to the sound device instance to be
+ * applied immediately, if it supports it.
+ *
+ * This method is only valid if the device has
+ * PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY capability in AudioDevInfo.caps flags,
+ * otherwise Error will be thrown.
+ *
+ * Note that in case the setting is kept for future use, it will be applied
+ * to any devices, even when application has changed the sound device to be
+ * used.
+ *
+ * @param latency_msec The output latency.
+ * @param keep Specify whether the setting is to be kept
+ * for future use.
+ *
+ */
+ void
+ setOutputLatency(unsigned latency_msec, bool keep=true) throw(Error);
+
+ /**
+ * Get the audio output latency control or query capability of the sound
+ * device being used. If sound device is currently active, the method will
+ * forward the request to the sound device. If sound device is currently
+ * inactive, and if application had previously set the setting and mark the
+ * setting as kept, then that setting will be returned. Otherwise, this
+ * method will raise error.
+ *
+ * This method is only valid if the device has
+ * PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY capability in AudioDevInfo.caps flags,
+ * otherwise Error will be thrown.
+ *
+ * @return The audio output latency.
+ *
+ */
+ unsigned getOutputLatency() const throw(Error);
+
+ /**
+ * This will configure audio input volume level capability to the
+ * sound device being used.
+ * If sound device is currently active, the method will forward the
+ * setting to the sound device instance to be applied immediately,
+ * if it supports it.
+ *
+ * This method is only valid if the device has
+ * PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING capability in AudioDevInfo.caps
+ * flags, otherwise Error will be thrown.
+ *
+ * Note that in case the setting is kept for future use, it will be applied
+ * to any devices, even when application has changed the sound device to be
+ * used.
+ *
+ * @param volume The input volume level, in percent.
+ * @param keep Specify whether the setting is to be kept for
+ * future use.
+ *
+ */
+ void setInputVolume(unsigned volume, bool keep=true) throw(Error);
+
+ /**
+ * Get the audio input volume level capability of the sound device being
+ * used. If sound device is currently active, the method will forward the
+ * request to the sound device. If sound device is currently inactive,
+ * and if application had previously set the setting and mark the setting
+ * as kept, then that setting will be returned. Otherwise, this method
+ * will raise error.
+ *
+ * This method is only valid if the device has
+ * PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING capability in AudioDevInfo.caps
+ * flags, otherwise Error will be thrown. *
+
+ * @return The audio input volume level, in percent.
+ *
+ */
+ unsigned getInputVolume() const throw(Error);
+
+ /**
+ * This will configure audio output volume level capability to the sound
+ * device being used. If sound device is currently active, the method will
+ * forward the setting to the sound device instance to be applied
+ * immediately, if it supports it.
+ *
+ * This method is only valid if the device has
+ * PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING capability in AudioDevInfo.caps
+ * flags, otherwise Error will be thrown.
+ *
+ * Note that in case the setting is kept for future use, it will be applied
+ * to any devices, even when application has changed the sound device to be
+ * used.
+ *
+ * @param volume The output volume level, in percent.
+ * @param keep Specify whether the setting is to be kept
+ * for future use.
+ *
+ */
+ void setOutputVolume(unsigned volume, bool keep=true) throw(Error);
+
+ /**
+ * Get the audio output volume level capability of the sound device being
+ * used. If sound device is currently active, the method will forward the
+ * request to the sound device. If sound device is currently inactive,
+ * and if application had previously set the setting and mark the setting
+ * as kept, then that setting will be returned. Otherwise, this method
+ * will raise error.
+ *
+ * This method is only valid if the device has
+ * PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING capability in AudioDevInfo.caps
+ * flags, otherwise Error will be thrown.
+ *
+ * @return The audio output volume level, in percent.
+ *
+ */
+ unsigned getOutputVolume() const throw(Error);
+
+ /**
+ * Get the audio input signal level capability of the sound device being
+ * used. If sound device is currently active, the method will forward the
+ * request to the sound device. If sound device is currently inactive,
+ * and if application had previously set the setting and mark the setting
+ * as kept, then that setting will be returned. Otherwise, this method
+ * will raise error.
+ *
+ * This method is only valid if the device has
+ * PJMEDIA_AUD_DEV_CAP_INPUT_SIGNAL_METER capability in AudioDevInfo.caps
+ * flags, otherwise Error will be thrown.
+ *
+ * @return The audio input signal level, in percent.
+ *
+ */
+ unsigned getInputSignal() const throw(Error);
+
+ /**
+ * Get the audio output signal level capability of the sound device being
+ * used. If sound device is currently active, the method will forward the
+ * request to the sound device. If sound device is currently inactive,
+ * and if application had previously set the setting and mark the setting
+ * as kept, then that setting will be returned. Otherwise, this method
+ * will raise error.
+ *
+ * This method is only valid if the device has
+ * PJMEDIA_AUD_DEV_CAP_OUTPUT_SIGNAL_METER capability in AudioDevInfo.caps
+ * flags, otherwise Error will be thrown.
+ *
+ * @return The audio output signal level, in percent.
+ *
+ */
+ unsigned getOutputSignal() const throw(Error);
+
+ /**
+ * This will configure audio input route capability to the sound device
+ * being used. If sound device is currently active, the method will
+ * forward the setting to the sound device instance to be applied
+ * immediately, if it supports it.
+ *
+ * This method is only valid if the device has
+ * PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE capability in AudioDevInfo.caps
+ * flags, otherwise Error will be thrown.
+ *
+ * Note that in case the setting is kept for future use, it will be applied
+ * to any devices, even when application has changed the sound device to be
+ * used.
+ *
+ * @param route The audio input route.
+ * @param keep Specify whether the setting is to be kept
+ * for future use.
+ *
+ */
+ void
+ setInputRoute(pjmedia_aud_dev_route route, bool keep=true) throw(Error);
+
+ /**
+ * Get the audio input route capability of the sound device being used.
+ * If sound device is currently active, the method will forward the
+ * request to the sound device. If sound device is currently inactive,
+ * and if application had previously set the setting and mark the setting
+ * as kept, then that setting will be returned. Otherwise, this method
+ * will raise error.
+ *
+ * This method is only valid if the device has
+ * PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE capability in AudioDevInfo.caps
+ * flags, otherwise Error will be thrown.
+ *
+ * @return The audio input route.
+ *
+ */
+ pjmedia_aud_dev_route getInputRoute() const throw(Error);
+
+ /**
+ * This will configure audio output route capability to the sound device
+ * being used. If sound device is currently active, the method will
+ * forward the setting to the sound device instance to be applied
+ * immediately, if it supports it.
+ *
+ * This method is only valid if the device has
+ * PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE capability in AudioDevInfo.caps
+ * flags, otherwise Error will be thrown.
+ *
+ * Note that in case the setting is kept for future use, it will be applied
+ * to any devices, even when application has changed the sound device to be
+ * used.
+ *
+ * @param route The audio output route.
+ * @param keep Specify whether the setting is to be kept
+ * for future use.
+ *
+ */
+ void
+ setOutputRoute(pjmedia_aud_dev_route route, bool keep=true) throw(Error);
+
+ /**
+ * Get the audio output route capability of the sound device being used.
+ * If sound device is currently active, the method will forward the
+ * request to the sound device. If sound device is currently inactive,
+ * and if application had previously set the setting and mark the setting
+ * as kept, then that setting will be returned. Otherwise, this method
+ * will raise error.
+ *
+ * This method is only valid if the device has
+ * PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE capability in AudioDevInfo.caps
+ * flags, otherwise Error will be thrown.
+ *
+ * @return The audio output route.
+ *
+ */
+ pjmedia_aud_dev_route getOutputRoute() const throw(Error);
+
+ /**
+ * This will configure audio voice activity detection capability to
+ * the sound device being used. If sound device is currently active,
+ * the method will forward the setting to the sound device instance
+ * to be applied immediately, if it supports it.
+ *
+ * This method is only valid if the device has PJMEDIA_AUD_DEV_CAP_VAD
+ * capability in AudioDevInfo.caps flags, otherwise Error will be thrown.
+ *
+ * Note that in case the setting is kept for future use, it will be applied
+ * to any devices, even when application has changed the sound device to be
+ * used.
+ *
+ * @param enable Enable/disable voice activity detection
+ * feature. Set true to enable.
+ * @param keep Specify whether the setting is to be kept for
+ * future use.
+ *
+ */
+ void setVad(bool enable, bool keep=true) throw(Error);
+
+ /**
+ * Get the audio voice activity detection capability of the sound device
+ * being used. If sound device is currently active, the method will
+ * forward the request to the sound device. If sound device is currently
+ * inactive, and if application had previously set the setting and mark
+ * the setting as kept, then that setting will be returned. Otherwise,
+ * this method will raise error.
+ *
+ * This method is only valid if the device has PJMEDIA_AUD_DEV_CAP_VAD
+ * capability in AudioDevInfo.caps flags, otherwise Error will be thrown.
+ *
+ * @return The audio voice activity detection feature.
+ *
+ */
+ bool getVad() const throw(Error);
+
+ /**
+ * This will configure audio comfort noise generation capability to
+ * the sound device being used. If sound device is currently active,
+ * the method will forward the setting to the sound device instance
+ * to be applied immediately, if it supports it.
+ *
+ * This method is only valid if the device has PJMEDIA_AUD_DEV_CAP_CNG
+ * capability in AudioDevInfo.caps flags, otherwise Error will be thrown.
+ *
+ * Note that in case the setting is kept for future use, it will be applied
+ * to any devices, even when application has changed the sound device to be
+ * used.
+ *
+ * @param enable Enable/disable comfort noise generation
+ * feature. Set true to enable.
+ * @param keep Specify whether the setting is to be kept for
+ * future use.
+ *
+ */
+ void setCng(bool enable, bool keep=true) throw(Error);
+
+ /**
+ * Get the audio comfort noise generation capability of the sound device
+ * being used. If sound device is currently active, the method will
+ * forward the request to the sound device. If sound device is currently
+ * inactive, and if application had previously set the setting and mark
+ * the setting as kept, then that setting will be returned. Otherwise,
+ * this method will raise error.
+ *
+ * This method is only valid if the device has PJMEDIA_AUD_DEV_CAP_CNG
+ * capability in AudioDevInfo.caps flags, otherwise Error will be thrown.
+ *
+ * @return The audio comfort noise generation feature.
+ *
+ */
+ bool getCng() const throw(Error);
+
+ /**
+ * This will configure audio packet loss concealment capability to
+ * the sound device being used. If sound device is currently active,
+ * the method will forward the setting to the sound device instance
+ * to be applied immediately, if it supports it.
+ *
+ * This method is only valid if the device has PJMEDIA_AUD_DEV_CAP_PLC
+ * capability in AudioDevInfo.caps flags, otherwise Error will be thrown.
+ *
+ * Note that in case the setting is kept for future use, it will be applied
+ * to any devices, even when application has changed the sound device to be
+ * used.
+ *
+ * @param enable Enable/disable packet loss concealment
+ * feature. Set true to enable.
+ * @param keep Specify whether the setting is to be kept for
+ * future use.
+ *
+ */
+ void setPlc(bool enable, bool keep=true) throw(Error);
+
+ /**
+ * Get the audio packet loss concealment capability of the sound device
+ * being used. If sound device is currently active, the method will
+ * forward the request to the sound device. If sound device is currently
+ * inactive, and if application had previously set the setting and mark
+ * the setting as kept, then that setting will be returned. Otherwise,
+ * this method will raise error.
+ *
+ * This method is only valid if the device has PJMEDIA_AUD_DEV_CAP_PLC
+ * capability in AudioDevInfo.caps flags, otherwise Error will be thrown.
+ *
+ * @return The audio packet loss concealment feature.
+ *
+ */
+ bool getPlc() const throw(Error);
+
+private:
+ AudioDevInfoVector audioDevList;
+ AudioMedia *devMedia;
+
+ /**
+ * Constructor.
+ */
+ AudDevManager();
+
+ /**
+ * Destructor.
+ */
+ ~AudDevManager();
+
+ void clearAudioDevList();
+ int getActiveDev(bool is_capture) const throw(Error);
+
+ friend class Endpoint;
+};
+
+/*************************************************************************
+* Codec management
+*/
+
+/**
+ * This structure describes codec information.
+ */
+struct CodecInfo
+{
+ /**
+ * Codec unique identification.
+ */
+ string codecId;
+
+ /**
+ * Codec priority (integer 0-255).
+ */
+ pj_uint8_t priority;
+
+ /**
+ * Codec description.
+ */
+ string desc;
+
+ /**
+ * Construct from pjsua_codec_info.
+ */
+ void fromPj(const pjsua_codec_info &codec_info);
+};
+
+/** Array of codec info */
+typedef std::vector<CodecInfo*> CodecInfoVector;
+
+/**
+ * Codec parameters, corresponds to pjmedia_codec_param or
+ * pjmedia_vid_codec_param.
+ */
+typedef void *CodecParam;
+
+
+/**
+ * @} // PJSUA2_MED
+ */
+
+} // namespace pj
+
+#endif /* __PJSUA2_MEDIA_HPP__ */
diff --git a/pjsip/include/pjsua2/persistent.hpp b/pjsip/include/pjsua2/persistent.hpp
new file mode 100644
index 00000000..c086b01d
--- /dev/null
+++ b/pjsip/include/pjsua2/persistent.hpp
@@ -0,0 +1,689 @@
+/* $Id$ */
+/*
+ * 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
+ */
+#ifndef __PJSUA2_PERSISTENT_HPP__
+#define __PJSUA2_PERSISTENT_HPP__
+
+/**
+ * @file pjsua2/persistent.hpp
+ * @brief PJSUA2 Persistent Services
+ */
+#include <pjsua2/types.hpp>
+
+#include <string>
+#include <vector>
+
+/** PJSUA2 API is inside pj namespace */
+namespace pj
+{
+
+/**
+ * @defgroup PJSUA2_PERSISTENT Persistent API
+ * @ingroup PJSUA2_Ref
+ * @{
+ * The persistent API provides functionality to read/write data from/to
+ * a document (string or file). The data can be simple data types such
+ * as boolean, number, string, and string arrays, or a user defined object.
+ * Currently the implementation supports reading and writing from/to JSON
+ * document, but the framework allows application to extend the API to
+ * support other document formats.
+ */
+
+using std::string;
+using std::vector;
+
+/* Forward declaration for ContainerNode */
+class ContainerNode;
+
+/**
+ * This is the abstract base class of objects that can be serialized to/from
+ * persistent document.
+ */
+class PersistentObject
+{
+public:
+ /**
+ * Read this object from a container node.
+ *
+ * @param node Container to read values from.
+ */
+ virtual void readObject(const ContainerNode &node) throw(Error) = 0;
+
+ /**
+ * Write this object to a container node.
+ *
+ * @param node Container to write values to.
+ */
+ virtual void writeObject(ContainerNode &node) const throw(Error) = 0;
+};
+
+
+/**
+ * This a the abstract base class for a persistent document. A document
+ * is created either by loading from a string or a file, or by constructing
+ * it manually when writing data to it. The document then can be saved
+ * to either string or to a file. A document contains one root ContainerNode
+ * where all data are stored under.
+ *
+ * Document is read and written serially, hence the order of reading must be
+ * the same as the order of writing. The PersistentDocument class provides
+ * API to read and write to the root node, but for more flexible operations
+ * application can use the ContainerNode methods instead. Indeed the read
+ * and write API in PersistentDocument is just a shorthand which calls the
+ * relevant methods in the ContainerNode. As a tip, normally application only
+ * uses the readObject() and writeObject() methods declared here to read/write
+ * top level objects, and use the macros that are explained in ContainerNode
+ * documentation to read/write more detailed data.
+ */
+class PersistentDocument
+{
+public:
+ /**
+ * Virtual destructor
+ */
+ virtual ~PersistentDocument()
+ {}
+
+ /**
+ * Load this document from a file.
+ *
+ * @param filename The file name.
+ */
+ virtual void loadFile(const string &filename) throw(Error) = 0;
+
+ /**
+ * Load this document from string.
+ *
+ * @param input The string.
+ */
+ virtual void loadString(const string &input) throw(Error) = 0;
+
+ /**
+ * Write this document to a file.
+ *
+ * @param filename The file name.
+ */
+ virtual void saveFile(const string &filename) throw(Error) = 0;
+
+ /**
+ * Write this document to string.
+ *
+ * @return The string document.
+ */
+ virtual string saveString() throw(Error) = 0;
+
+ /**
+ * Get the root container node for this document
+ *
+ * @return The root node.
+ */
+ virtual ContainerNode & getRootContainer() const = 0;
+
+
+ /*
+ * Shorthand functions for reading and writing from/to the root container
+ */
+
+
+ /**
+ * Determine if there is unread element. If yes, then app can use one of
+ * the readXxx() functions to read it.
+ *
+ * @return True if there is.
+ */
+ bool hasUnread() const;
+
+ /**
+ * Get the name of the next unread element. It will throw Error if there
+ * is no more element to read.
+ *
+ * @return The name of the next element .
+ */
+ string unreadName() const throw(Error);
+
+ /**
+ * Read an integer value from the document and return the value.
+ * This will throw Error if the current element is not a number.
+ * The read position will be advanced to the next element.
+ *
+ * @param name If specified, then the function will check if the
+ * name of the next element matches the specified
+ * name and throw Error if it doesn't match.
+ *
+ * @return The value.
+ */
+ int readInt(const string &name="") const throw(Error);
+
+ /**
+ * Read a float value from the document and return the value.
+ * This will throw Error if the current element is not a number.
+ * The read position will be advanced to the next element.
+ *
+ * @param name If specified, then the function will check if the
+ * name of the next element matches the specified
+ * name and throw Error if it doesn't match.
+ *
+ * @return The value.
+ */
+ float readNumber(const string &name="") const throw(Error);
+
+ /**
+ * Read a boolean value from the container and return the value.
+ * This will throw Error if the current element is not a boolean.
+ * The read position will be advanced to the next element.
+ *
+ * @param name If specified, then the function will check if the
+ * name of the next element matches the specified
+ * name and throw Error if it doesn't match.
+ *
+ * @return The value.
+ */
+ bool readBool(const string &name="") const throw(Error);
+
+ /**
+ * Read a string value from the container and return the value.
+ * This will throw Error if the current element is not a string.
+ * The read position will be advanced to the next element.
+ *
+ * @param name If specified, then the function will check if the
+ * name of the next element matches the specified
+ * name and throw Error if it doesn't match.
+ *
+ * @return The value.
+ */
+ string readString(const string &name="") const throw(Error);
+
+ /**
+ * Read a string array from the container. This will throw Error
+ * if the current element is not a string array. The read position
+ * will be advanced to the next element.
+ *
+ * @param name If specified, then the function will check if the
+ * name of the next element matches the specified
+ * name and throw Error if it doesn't match.
+ *
+ * @return The value.
+ */
+ StringVector readStringVector(const string &name="") const
+ throw(Error);
+
+ /**
+ * Read the specified object from the container. This is equal to
+ * calling PersistentObject.readObject(ContainerNode);
+ *
+ * @param obj The object to read.
+ */
+ void readObject(PersistentObject &obj) const throw(Error);
+
+ /**
+ * Read a container from the container. This will throw Error if the
+ * current element is not an object. The read position will be advanced
+ * to the next element.
+ *
+ * @param name If specified, then the function will check if the
+ * name of the next element matches the specified
+ * name and throw Error if it doesn't match.
+ *
+ * @return Container object.
+ */
+ ContainerNode readContainer(const string &name="") const
+ throw(Error);
+
+ /**
+ * Read array container from the container. This will throw Error if the
+ * current element is not an array. The read position will be advanced
+ * to the next element.
+ *
+ * @param name If specified, then the function will check if the
+ * name of the next element matches the specified
+ * name and throw Error if it doesn't match.
+ *
+ * @return Container object.
+ */
+ ContainerNode readArray(const string &name="") const
+ throw(Error);
+
+ /**
+ * Write a number value to the container.
+ *
+ * @param name The name for the value in the container.
+ * @param num The value to be written.
+ */
+ void writeNumber(const string &name,
+ float num) throw(Error);
+
+ /**
+ * Write a number value to the container.
+ *
+ * @param name The name for the value in the container.
+ * @param num The value to be written.
+ */
+ void writeInt(const string &name,
+ int num) throw(Error);
+
+ /**
+ * Write a boolean value to the container.
+ *
+ * @param name The name for the value in the container.
+ * @param value The value to be written.
+ */
+ void writeBool(const string &name,
+ bool value) throw(Error);
+
+ /**
+ * Write a string value to the container.
+ *
+ * @param name The name for the value in the container.
+ * @param value The value to be written.
+ */
+ void writeString(const string &name,
+ const string &value) throw(Error);
+
+ /**
+ * Write string vector to the container.
+ *
+ * @param name The name for the value in the container.
+ * @param arr The vector to be written.
+ */
+ void writeStringVector(const string &name,
+ const StringVector &arr)
+ throw(Error);
+
+ /**
+ * Write an object to the container. This is equal to calling
+ * PersistentObject.writeObject(ContainerNode);
+ *
+ * @param obj The object to be written
+ */
+ void writeObject(const PersistentObject &obj) throw(Error);
+
+ /**
+ * Create and write an empty Object node that can be used as parent
+ * for subsequent write operations.
+ *
+ * @param name The name for the new container in the container.
+ *
+ * @return A sub-container.
+ */
+ ContainerNode writeNewContainer(const string &name)
+ throw(Error);
+
+ /**
+ * Create and write an empty array node that can be used as parent
+ * for subsequent write operations.
+ *
+ * @param name The name for the array.
+ *
+ * @return A sub-container.
+ */
+ ContainerNode writeNewArray(const string &name)
+ throw(Error);
+};
+
+
+/**
+ * Forward declaration of container_node_op.
+ */
+struct container_node_op;
+
+
+/**
+ * Internal data for ContainerNode. See ContainerNode implementation notes
+ * for more info.
+ */
+struct container_node_internal_data
+{
+ void *doc; /**< The document. */
+ void *data1; /**< Internal data 1 */
+ void *data2; /**< Internal data 2 */
+};
+
+/**
+ * A container node is a placeholder for storing other data elements, which
+ * could be boolean, number, string, array of strings, or another container.
+ * Each data in the container is basically a name/value pair, with a type
+ * internally associated with it so that written data can be read in the
+ * correct type. Data is read and written serially, hence the order of
+ * reading must be the same as the order of writing.
+ *
+ * Application can read data from it by using the various read methods, and
+ * write data to it using the various write methods. Alternatively, it
+ * may be more convenient to use the provided macros below to read and write
+ * the data, because these macros set the name automatically:
+ * - NODE_READ_BOOL(node,item)
+ * - NODE_READ_UNSIGNED(node,item)
+ * - NODE_READ_INT(node,item)
+ * - NODE_READ_FLOAT(node,item)
+ * - NODE_READ_NUM_T(node,type,item)
+ * - NODE_READ_STRING(node,item)
+ * - NODE_READ_STRINGV(node,item)
+ * - NODE_READ_OBJ(node,item)
+ * - NODE_WRITE_BOOL(node,item)
+ * - NODE_WRITE_UNSIGNED(node,item)
+ * - NODE_WRITE_INT(node,item)
+ * - NODE_WRITE_FLOAT(node,item)
+ * - NODE_WRITE_NUM_T(node,type,item)
+ * - NODE_WRITE_STRING(node,item)
+ * - NODE_WRITE_STRINGV(node,item)
+ * - NODE_WRITE_OBJ(node,item)
+ *
+ * Implementation notes:
+ *
+ * The ContainerNode class is subclass-able, but not in the usual C++ way.
+ * With the usual C++ inheritance, some methods will be made pure virtual
+ * and must be implemented by the actual class. However, doing so will
+ * require dynamic instantiation of the ContainerNode class, which means
+ * we will need to pass around the class as pointer, for example as the
+ * return value of readContainer() and writeNewContainer() methods. Then
+ * we will need to establish who needs or how to delete these objects, or
+ * use shared pointer mechanism, each of which is considered too inconvenient
+ * or complicated for the purpose.
+ *
+ * So hence we use C style "inheritance", where the methods are declared in
+ * container_node_op and the data in container_node_internal_data structures.
+ * An implementation of ContainerNode class will need to set up these members
+ * with values that makes sense to itself. The methods in container_node_op
+ * contains the pointer to the actual implementation of the operation, which
+ * would be specific according to the format of the document. The methods in
+ * this ContainerNode class are just thin wrappers which call the
+ * implementation in the container_node_op structure.
+ *
+ */
+class ContainerNode
+{
+public:
+ /**
+ * Determine if there is unread element. If yes, then app can use one of
+ * the readXxx() functions to read it.
+ */
+ bool hasUnread() const;
+
+ /**
+ * Get the name of the next unread element.
+ */
+ string unreadName() const throw(Error);
+
+ /**
+ * Read an integer value from the document and return the value.
+ * This will throw Error if the current element is not a number.
+ * The read position will be advanced to the next element.
+ *
+ * @param name If specified, then the function will check if the
+ * name of the next element matches the specified
+ * name and throw Error if it doesn't match.
+ *
+ * @return The value.
+ */
+ int readInt(const string &name="") const throw(Error);
+
+ /**
+ * Read a number value from the document and return the value.
+ * This will throw Error if the current element is not a number.
+ * The read position will be advanced to the next element.
+ *
+ * @param name If specified, then the function will check if the
+ * name of the next element matches the specified
+ * name and throw Error if it doesn't match.
+ *
+ * @return The value.
+ */
+ float readNumber(const string &name="") const throw(Error);
+
+ /**
+ * Read a boolean value from the container and return the value.
+ * This will throw Error if the current element is not a boolean.
+ * The read position will be advanced to the next element.
+ *
+ * @param name If specified, then the function will check if the
+ * name of the next element matches the specified
+ * name and throw Error if it doesn't match.
+ *
+ * @return The value.
+ */
+ bool readBool(const string &name="") const throw(Error);
+
+ /**
+ * Read a string value from the container and return the value.
+ * This will throw Error if the current element is not a string.
+ * The read position will be advanced to the next element.
+ *
+ * @param name If specified, then the function will check if the
+ * name of the next element matches the specified
+ * name and throw Error if it doesn't match.
+ *
+ * @return The value.
+ */
+ string readString(const string &name="") const throw(Error);
+
+ /**
+ * Read a string array from the container. This will throw Error
+ * if the current element is not a string array. The read position
+ * will be advanced to the next element.
+ *
+ * @param name If specified, then the function will check if the
+ * name of the next element matches the specified
+ * name and throw Error if it doesn't match.
+ *
+ * @return The value.
+ */
+ StringVector readStringVector(const string &name="") const
+ throw(Error);
+
+ /**
+ * Read the specified object from the container. This is equal to
+ * calling PersistentObject.readObject(ContainerNode);
+ *
+ * @param obj The object to read.
+ */
+ void readObject(PersistentObject &obj) const throw(Error);
+
+ /**
+ * Read a container from the container. This will throw Error if the
+ * current element is not a container. The read position will be advanced
+ * to the next element.
+ *
+ * @param name If specified, then the function will check if the
+ * name of the next element matches the specified
+ * name and throw Error if it doesn't match.
+ *
+ * @return Container object.
+ */
+ ContainerNode readContainer(const string &name="") const
+ throw(Error);
+
+ /**
+ * Read array container from the container. This will throw Error if the
+ * current element is not an array. The read position will be advanced
+ * to the next element.
+ *
+ * @param name If specified, then the function will check if the
+ * name of the next element matches the specified
+ * name and throw Error if it doesn't match.
+ *
+ * @return Container object.
+ */
+ ContainerNode readArray(const string &name="") const
+ throw(Error);
+
+ /**
+ * Write a number value to the container.
+ *
+ * @param name The name for the value in the container.
+ * @param num The value to be written.
+ */
+ void writeNumber(const string &name,
+ float num) throw(Error);
+
+ /**
+ * Write a number value to the container.
+ *
+ * @param name The name for the value in the container.
+ * @param num The value to be written.
+ */
+ void writeInt(const string &name,
+ int num) throw(Error);
+
+ /**
+ * Write a boolean value to the container.
+ *
+ * @param name The name for the value in the container.
+ * @param value The value to be written.
+ */
+ void writeBool(const string &name,
+ bool value) throw(Error);
+
+ /**
+ * Write a string value to the container.
+ *
+ * @param name The name for the value in the container.
+ * @param value The value to be written.
+ */
+ void writeString(const string &name,
+ const string &value) throw(Error);
+
+ /**
+ * Write string vector to the container.
+ *
+ * @param name The name for the value in the container.
+ * @param arr The vector to be written.
+ */
+ void writeStringVector(const string &name,
+ const StringVector &arr)
+ throw(Error);
+
+ /**
+ * Write an object to the container. This is equal to calling
+ * PersistentObject.writeObject(ContainerNode);
+ *
+ * @param obj The object to be written
+ */
+ void writeObject(const PersistentObject &obj) throw(Error);
+
+ /**
+ * Create and write an empty Object node that can be used as parent
+ * for subsequent write operations.
+ *
+ * @param name The name for the new container in the container.
+ *
+ * @return A sub-container.
+ */
+ ContainerNode writeNewContainer(const string &name)
+ throw(Error);
+
+ /**
+ * Create and write an empty array node that can be used as parent
+ * for subsequent write operations.
+ *
+ * @param name The name for the array.
+ *
+ * @return A sub-container.
+ */
+ ContainerNode writeNewArray(const string &name)
+ throw(Error);
+
+public:
+ /* internal data */
+ container_node_op *op; /**< Method table. */
+ container_node_internal_data data; /**< Internal data */
+};
+
+
+/**
+ * Pointer to actual ContainerNode implementation. See ContainerNode
+ * implementation notes for more info.
+ */
+//! @cond Doxygen_Suppress
+struct container_node_op
+{
+ bool (*hasUnread)(const ContainerNode*);
+ string (*unreadName)(const ContainerNode*)
+ throw(Error);
+ float (*readNumber)(const ContainerNode*,
+ const string&)
+ throw(Error);
+ bool (*readBool)(const ContainerNode*,
+ const string&)
+ throw(Error);
+ string (*readString)(const ContainerNode*,
+ const string&)
+ throw(Error);
+ StringVector (*readStringVector)(const ContainerNode*,
+ const string&)
+ throw(Error);
+ ContainerNode (*readContainer)(const ContainerNode*,
+ const string &)
+ throw(Error);
+ ContainerNode (*readArray)(const ContainerNode*,
+ const string &)
+ throw(Error);
+ void (*writeNumber)(ContainerNode*,
+ const string &name,
+ float num)
+ throw(Error);
+ void (*writeBool)(ContainerNode*,
+ const string &name,
+ bool value)
+ throw(Error);
+ void (*writeString)(ContainerNode*,
+ const string &name,
+ const string &value)
+ throw(Error);
+ void (*writeStringVector)(ContainerNode*,
+ const string &name,
+ const StringVector &value)
+ throw(Error);
+ ContainerNode (*writeNewContainer)(ContainerNode*,
+ const string &name)
+ throw(Error);
+ ContainerNode (*writeNewArray)(ContainerNode*,
+ const string &name)
+ throw(Error);
+};
+
+/*
+ * Convenient macros.
+ */
+#define NODE_READ_BOOL(node,item) item = node.readBool(#item)
+#define NODE_READ_UNSIGNED(node,item) item = (unsigned)node.readNumber(#item)
+#define NODE_READ_INT(node,item) item = (int) node.readNumber(#item)
+#define NODE_READ_FLOAT(node,item) item = node.readNumber(#item)
+#define NODE_READ_NUM_T(node,T,item) item = (T)(int)node.readNumber(#item)
+#define NODE_READ_STRING(node,item) item = node.readString(#item)
+#define NODE_READ_STRINGV(node,item) item = node.readStringVector(#item)
+#define NODE_READ_OBJ(node,item) node.readObject(item)
+
+#define NODE_WRITE_BOOL(node,item) node.writeBool(#item, item)
+#define NODE_WRITE_UNSIGNED(node,item) node.writeNumber(#item, (float)item)
+#define NODE_WRITE_INT(node,item) node.writeNumber(#item, (float)item)
+#define NODE_WRITE_NUM_T(node,T,item) node.writeNumber(#item, (float)item)
+#define NODE_WRITE_FLOAT(node,item) node.writeNumber(#item, item)
+#define NODE_WRITE_STRING(node,item) node.writeString(#item, item)
+#define NODE_WRITE_STRINGV(node,item) node.writeStringVector(#item, item)
+#define NODE_WRITE_OBJ(node,item) node.writeObject(item)
+
+//! @endcond
+
+/**
+ * @} PJSUA2
+ */
+
+} // namespace pj
+
+
+
+#endif /* __PJSUA2_PERSISTENT_HPP__ */
diff --git a/pjsip/include/pjsua2/presence.hpp b/pjsip/include/pjsua2/presence.hpp
new file mode 100644
index 00000000..5106344a
--- /dev/null
+++ b/pjsip/include/pjsua2/presence.hpp
@@ -0,0 +1,296 @@
+/* $Id$ */
+/*
+ * 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
+ */
+#ifndef __PJSUA2_PRESENCE_HPP__
+#define __PJSUA2_PRESENCE_HPP__
+
+/**
+ * @file pjsua2/presence.hpp
+ * @brief PJSUA2 Presence Operations
+ */
+#include <pjsua2/persistent.hpp>
+#include <pjsua2/siptypes.hpp>
+
+/** PJSUA2 API is inside pj namespace */
+namespace pj
+{
+
+/**
+ * @defgroup PJSUA2_PRES Presence
+ * @ingroup PJSUA2_Ref
+ * @{
+ */
+
+using std::string;
+using std::vector;
+
+
+/**
+ * This describes presence status.
+ */
+struct PresenceStatus
+{
+ /**
+ * Buddy's online status.
+ */
+ pjsua_buddy_status status;
+
+ /**
+ * Text to describe buddy's online status.
+ */
+ string statusText;
+
+ /**
+ * Activity type.
+ */
+ pjrpid_activity activity;
+
+ /**
+ * Optional text describing the person/element.
+ */
+ string note;
+
+ /**
+ * Optional RPID ID string.
+ */
+ string rpidId;
+
+public:
+ /**
+ * Constructor.
+ */
+ PresenceStatus();
+};
+
+
+/**
+ * This structure describes buddy configuration when adding a buddy to
+ * the buddy list with Buddy::create().
+ */
+struct BuddyConfig : public PersistentObject
+{
+ /**
+ * Buddy URL or name address.
+ */
+ string uri;
+
+ /**
+ * Specify whether presence subscription should start immediately.
+ */
+ bool subscribe;
+
+public:
+ /**
+ * Read this object from a container node.
+ *
+ * @param node Container to read values from.
+ */
+ virtual void readObject(const ContainerNode &node) throw(Error);
+
+ /**
+ * Write this object to a container node.
+ *
+ * @param node Container to write values to.
+ */
+ virtual void writeObject(ContainerNode &node) const throw(Error);
+};
+
+
+/**
+ * This structure describes buddy info, which can be retrieved by via
+ * Buddy::getInfo().
+ */
+struct BuddyInfo
+{
+ /**
+ * The full URI of the buddy, as specified in the configuration.
+ */
+ string uri;
+
+ /**
+ * Buddy's Contact, only available when presence subscription has
+ * been established to the buddy.
+ */
+ string contact;
+
+ /**
+ * Flag to indicate that we should monitor the presence information for
+ * this buddy (normally yes, unless explicitly disabled).
+ */
+ bool presMonitorEnabled;
+
+ /**
+ * If \a presMonitorEnabled is true, this specifies the last state of
+ * the presence subscription. If presence subscription session is currently
+ * active, the value will be PJSIP_EVSUB_STATE_ACTIVE. If presence
+ * subscription request has been rejected, the value will be
+ * PJSIP_EVSUB_STATE_TERMINATED, and the termination reason will be
+ * specified in \a subTermReason.
+ */
+ pjsip_evsub_state subState;
+
+ /**
+ * String representation of subscription state.
+ */
+ string subStateName;
+
+ /**
+ * Specifies the last presence subscription termination code. This would
+ * return the last status of the SUBSCRIBE request. If the subscription
+ * is terminated with NOTIFY by the server, this value will be set to
+ * 200, and subscription termination reason will be given in the
+ * \a subTermReason field.
+ */
+ pjsip_status_code subTermCode;
+
+ /**
+ * Specifies the last presence subscription termination reason. If
+ * presence subscription is currently active, the value will be empty.
+ */
+ string subTermReason;
+
+ /**
+ * Presence status.
+ */
+ PresenceStatus presStatus;
+
+public:
+ /** Import from pjsip structure */
+ void fromPj(const pjsua_buddy_info &pbi);
+};
+
+
+/**
+ * Buddy.
+ */
+class Buddy
+{
+public:
+ /**
+ * Constructor.
+ */
+ Buddy();
+
+ /**
+ * Destructor. Note that if the Buddy instance is deleted, it will also
+ * delete the corresponding buddy in the PJSUA-LIB.
+ */
+ virtual ~Buddy();
+
+ /**
+ * Create buddy and register the buddy to PJSUA-LIB.
+ *
+ * @param acc The account for this buddy.
+ * @param cfg The buddy config.
+ */
+ void create(Account &acc, const BuddyConfig &cfg) throw(Error);
+
+ /**
+ * Check if this buddy is valid.
+ *
+ * @return True if it is.
+ */
+ bool isValid() const;
+
+ /**
+ * Get detailed buddy info.
+ *
+ * @return Buddy info.
+ */
+ BuddyInfo getInfo() const throw(Error);
+
+ /**
+ * Enable/disable buddy's presence monitoring. Once buddy's presence is
+ * subscribed, application will be informed about buddy's presence status
+ * changed via \a onBuddyState() callback.
+ *
+ * @param subscribe Specify true to activate presence
+ * subscription.
+ */
+ void subscribePresence(bool subscribe) throw(Error);
+
+ /**
+ * Update the presence information for the buddy. Although the library
+ * periodically refreshes the presence subscription for all buddies,
+ * some application may want to refresh the buddy's presence subscription
+ * immediately, and in this case it can use this function to accomplish
+ * this.
+ *
+ * Note that the buddy's presence subscription will only be initiated
+ * if presence monitoring is enabled for the buddy. See
+ * subscribePresence() for more info. Also if presence subscription for
+ * the buddy is already active, this function will not do anything.
+ *
+ * Once the presence subscription is activated successfully for the buddy,
+ * application will be notified about the buddy's presence status in the
+ * \a onBuddyState() callback.
+ */
+ void updatePresence(void) throw(Error);
+
+ /**
+ * Send instant messaging outside dialog, using this buddy's specified
+ * account for route set and authentication.
+ *
+ * @param prm Sending instant message parameter.
+ */
+ void sendInstantMessage(const SendInstantMessageParam &prm) throw(Error);
+
+ /**
+ * Send typing indication outside dialog.
+ *
+ * @param prm Sending instant message parameter.
+ */
+ void sendTypingIndication(const SendTypingIndicationParam &prm)
+ throw(Error);
+
+public:
+ /*
+ * Callbacks
+ */
+
+ /**
+ * Notify application when the buddy state has changed.
+ * Application may then query the buddy info to get the details.
+ */
+ virtual void onBuddyState()
+ {}
+
+private:
+ /**
+ * Buddy ID.
+ */
+ pjsua_buddy_id id;
+
+ /**
+ * Account.
+ */
+ Account *acc;
+};
+
+
+/** Array of buddies */
+typedef std::vector<Buddy*> BuddyVector;
+
+
+/**
+ * @} // PJSUA2_PRES
+ */
+
+} // namespace pj
+
+#endif /* __PJSUA2_PRESENCE_HPP__ */
diff --git a/pjsip/include/pjsua2/siptypes.hpp b/pjsip/include/pjsua2/siptypes.hpp
new file mode 100644
index 00000000..a5e7550f
--- /dev/null
+++ b/pjsip/include/pjsua2/siptypes.hpp
@@ -0,0 +1,910 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2032 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
+ */
+#ifndef __PJSUA2_SIPTYPES_HPP__
+#define __PJSUA2_SIPTYPES_HPP__
+
+/**
+ * @file pjsua2/types.hpp
+ * @brief PJSUA2 Base Types
+ */
+#include <pjsua2/types.hpp>
+#include <pjsua2/persistent.hpp>
+
+#include <string>
+#include <vector>
+
+/** PJSUA2 API is inside pj namespace */
+namespace pj
+{
+
+/**
+ * @defgroup PJSUA2_SIP_Types SIP Types
+ * @ingroup PJSUA2_DS
+ * @{
+ */
+
+/**
+ * Credential information. Credential contains information to authenticate
+ * against a service.
+ */
+struct AuthCredInfo : public PersistentObject
+{
+ /**
+ * The authentication scheme (e.g. "digest").
+ */
+ string scheme;
+
+ /**
+ * Realm on which this credential is to be used. Use "*" to make
+ * a credential that can be used to authenticate against any challenges.
+ */
+ string realm;
+
+ /**
+ * Authentication user name.
+ */
+ string username;
+
+ /**
+ * Type of data that is contained in the "data" field. Use 0 if the data
+ * contains plain text password.
+ */
+ int dataType;
+
+ /**
+ * The data, which can be a plain text password or a hashed digest.
+ */
+ string data;
+
+ /*
+ * Digest AKA credential information. Note that when AKA credential
+ * is being used, the \a data field of this pjsip_cred_info is
+ * not used, but it still must be initialized to an empty string.
+ * Please see PJSIP_AUTH_AKA_API for more information.
+ */
+
+ /** Permanent subscriber key. */
+ string akaK;
+
+ /** Operator variant key. */
+ string akaOp;
+
+ /** Authentication Management Field */
+ string akaAmf;
+
+public:
+ /** Default constructor */
+ AuthCredInfo();
+
+ /** Construct a credential with the specified parameters */
+ AuthCredInfo(const string &scheme,
+ const string &realm,
+ const string &user_name,
+ const int data_type,
+ const string data);
+
+ /**
+ * Read this object from a container node.
+ *
+ * @param node Container to read values from.
+ */
+ virtual void readObject(const ContainerNode &node) throw(Error);
+
+ /**
+ * Write this object to a container node.
+ *
+ * @param node Container to write values to.
+ */
+ virtual void writeObject(ContainerNode &node) const throw(Error);
+};
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+/**
+ * TLS transport settings, to be specified in TransportConfig.
+ */
+struct TlsConfig : public PersistentObject
+{
+ /**
+ * Certificate of Authority (CA) list file.
+ */
+ string CaListFile;
+
+ /**
+ * Public endpoint certificate file, which will be used as client-
+ * side certificate for outgoing TLS connection, and server-side
+ * certificate for incoming TLS connection.
+ */
+ string certFile;
+
+ /**
+ * Optional private key of the endpoint certificate to be used.
+ */
+ string privKeyFile;
+
+ /**
+ * Password to open private key.
+ */
+ string password;
+
+ /**
+ * TLS protocol method from pjsip_ssl_method.
+ *
+ * Default is PJSIP_SSL_UNSPECIFIED_METHOD (0), which in turn will
+ * use PJSIP_SSL_DEFAULT_METHOD, which default value is
+ * PJSIP_TLSV1_METHOD.
+ */
+ pjsip_ssl_method method;
+
+ /**
+ * Ciphers and order preference. The Endpoint::utilSslGetAvailableCiphers()
+ * can be used to check the available ciphers supported by backend.
+ * If the array is empty, then default cipher list of the backend
+ * will be used.
+ */
+ IntVector ciphers;
+
+ /**
+ * Specifies TLS transport behavior on the server TLS certificate
+ * verification result:
+ * - If \a verifyServer is disabled, TLS transport will just notify
+ * the application via pjsip_tp_state_callback with state
+ * PJSIP_TP_STATE_CONNECTED regardless TLS verification result.
+ * - If \a verifyServer is enabled, TLS transport will be shutdown
+ * and application will be notified with state
+ * PJSIP_TP_STATE_DISCONNECTED whenever there is any TLS verification
+ * error, otherwise PJSIP_TP_STATE_CONNECTED will be notified.
+ *
+ * In any cases, application can inspect pjsip_tls_state_info in the
+ * callback to see the verification detail.
+ *
+ * Default value is false.
+ */
+ bool verifyServer;
+
+ /**
+ * Specifies TLS transport behavior on the client TLS certificate
+ * verification result:
+ * - If \a verifyClient is disabled, TLS transport will just notify
+ * the application via pjsip_tp_state_callback with state
+ * PJSIP_TP_STATE_CONNECTED regardless TLS verification result.
+ * - If \a verifyClient is enabled, TLS transport will be shutdown
+ * and application will be notified with state
+ * PJSIP_TP_STATE_DISCONNECTED whenever there is any TLS verification
+ * error, otherwise PJSIP_TP_STATE_CONNECTED will be notified.
+ *
+ * In any cases, application can inspect pjsip_tls_state_info in the
+ * callback to see the verification detail.
+ *
+ * Default value is PJ_FALSE.
+ */
+ bool verifyClient;
+
+ /**
+ * When acting as server (incoming TLS connections), reject incoming
+ * connection if client doesn't supply a TLS certificate.
+ *
+ * This setting corresponds to SSL_VERIFY_FAIL_IF_NO_PEER_CERT flag.
+ * Default value is PJ_FALSE.
+ */
+ bool requireClientCert;
+
+ /**
+ * TLS negotiation timeout to be applied for both outgoing and incoming
+ * connection, in milliseconds. If zero, the SSL negotiation doesn't
+ * have a timeout.
+ *
+ * Default: zero
+ */
+ unsigned msecTimeout;
+
+ /**
+ * QoS traffic type to be set on this transport. When application wants
+ * to apply QoS tagging to the transport, it's preferable to set this
+ * field rather than \a qosParam fields since this is more portable.
+ *
+ * Default value is PJ_QOS_TYPE_BEST_EFFORT.
+ */
+ pj_qos_type qosType;
+
+ /**
+ * Set the low level QoS parameters to the transport. This is a lower
+ * level operation than setting the \a qosType field and may not be
+ * supported on all platforms.
+ *
+ * By default all settings in this structure are disabled.
+ */
+ pj_qos_params qosParams;
+
+ /**
+ * Specify if the transport should ignore any errors when setting the QoS
+ * traffic type/parameters.
+ *
+ * Default: PJ_TRUE
+ */
+ bool qosIgnoreError;
+
+public:
+ /** Default constructor initialises with default values */
+ TlsConfig();
+
+ /** Convert to pjsip */
+ pjsip_tls_setting toPj() const;
+
+ /** Convert from pjsip */
+ void fromPj(const pjsip_tls_setting &prm);
+
+ /**
+ * Read this object from a container node.
+ *
+ * @param node Container to read values from.
+ */
+ virtual void readObject(const ContainerNode &node) throw(Error);
+
+ /**
+ * Write this object to a container node.
+ *
+ * @param node Container to write values to.
+ */
+ virtual void writeObject(ContainerNode &node) const throw(Error);
+};
+
+
+/**
+ * Parameters to create a transport instance.
+ */
+struct TransportConfig : public PersistentObject
+{
+ /**
+ * UDP port number to bind locally. This setting MUST be specified
+ * even when default port is desired. If the value is zero, the
+ * transport will be bound to any available port, and application
+ * can query the port by querying the transport info.
+ */
+ unsigned port;
+
+ /**
+ * Specify the port range for socket binding, relative to the start
+ * port number specified in \a port. Note that this setting is only
+ * applicable when the start port number is non zero.
+ *
+ * Default value is zero.
+ */
+ unsigned portRange;
+
+ /**
+ * Optional address to advertise as the address of this transport.
+ * Application can specify any address or hostname for this field,
+ * for example it can point to one of the interface address in the
+ * system, or it can point to the public address of a NAT router
+ * where port mappings have been configured for the application.
+ *
+ * Note: this option can be used for both UDP and TCP as well!
+ */
+ string publicAddress;
+
+ /**
+ * Optional address where the socket should be bound to. This option
+ * SHOULD only be used to selectively bind the socket to particular
+ * interface (instead of 0.0.0.0), and SHOULD NOT be used to set the
+ * published address of a transport (the public_addr field should be
+ * used for that purpose).
+ *
+ * Note that unlike public_addr field, the address (or hostname) here
+ * MUST correspond to the actual interface address in the host, since
+ * this address will be specified as bind() argument.
+ */
+ string boundAddress;
+
+ /**
+ * This specifies TLS settings for TLS transport. It is only be used
+ * when this transport config is being used to create a SIP TLS
+ * transport.
+ */
+ TlsConfig tlsConfig;
+
+ /**
+ * QoS traffic type to be set on this transport. When application wants
+ * to apply QoS tagging to the transport, it's preferable to set this
+ * field rather than \a qosParam fields since this is more portable.
+ *
+ * Default is QoS not set.
+ */
+ pj_qos_type qosType;
+
+ /**
+ * Set the low level QoS parameters to the transport. This is a lower
+ * level operation than setting the \a qosType field and may not be
+ * supported on all platforms.
+ *
+ * Default is QoS not set.
+ */
+ pj_qos_params qosParams;
+
+public:
+ /** Default constructor initialises with default values */
+ TransportConfig();
+
+ /** Convert from pjsip */
+ void fromPj(const pjsua_transport_config &prm);
+
+ /** Convert to pjsip */
+ pjsua_transport_config toPj() const;
+
+ /**
+ * Read this object from a container node.
+ *
+ * @param node Container to read values from.
+ */
+ virtual void readObject(const ContainerNode &node) throw(Error);
+
+ /**
+ * Write this object to a container node.
+ *
+ * @param node Container to write values to.
+ */
+ virtual void writeObject(ContainerNode &node) const throw(Error);
+};
+
+/**
+ * This structure describes transport information returned by
+ * Endpoint::transportGetInfo() function.
+ */
+struct TransportInfo
+{
+ /** PJSUA transport identification. */
+ TransportId id;
+
+ /** Transport type. */
+ pjsip_transport_type_e type;
+
+ /** Transport type name. */
+ string typeName;
+
+ /** Transport string info/description. */
+ string info;
+
+ /** Transport flags (see pjsip_transport_flags_e). */
+ unsigned flags;
+
+ /** Local/bound address. */
+ SocketAddress localAddress;
+
+ /** Published address (or transport address name). */
+ SocketAddress localName;
+
+ /** Current number of objects currently referencing this transport. */
+ unsigned usageCount;
+
+public:
+ /** Construct from pjsua_transport_info */
+ void fromPj(const pjsua_transport_info &info);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+/**
+ * This structure describes an incoming SIP message. It corresponds to the
+ * pjsip_rx_data structure in PJSIP library.
+ */
+struct SipRxData
+{
+ /**
+ * A short info string describing the request, which normally contains
+ * the request method and its CSeq.
+ */
+ string info;
+
+ /**
+ * The whole message data as a string, containing both the header section
+ * and message body section.
+ */
+ string wholeMsg;
+
+ /**
+ * Source address of the message.
+ */
+ SocketAddress srcAddress;
+
+ /**
+ * Pointer to original pjsip_rx_data. Only valid when the struct
+ * is constructed from PJSIP's pjsip_rx_data.
+ */
+ void *pjRxData;
+
+public:
+ /**
+ * Default constructor.
+ */
+ SipRxData();
+
+ /**
+ * Construct from PJSIP's pjsip_rx_data
+ */
+ void fromPj(pjsip_rx_data &rdata);
+};
+
+/**
+ * This structure describes an outgoing SIP message. It corresponds to the
+ * pjsip_tx_data structure in PJSIP library.
+ */
+struct SipTxData
+{
+ /**
+ * A short info string describing the request, which normally contains
+ * the request method and its CSeq.
+ */
+ string info;
+
+ /**
+ * The whole message data as a string, containing both the header section
+ * and message body section.
+ */
+ string wholeMsg;
+
+ /**
+ * Destination address of the message.
+ */
+ SocketAddress dstAddress;
+
+ /**
+ * Pointer to original pjsip_tx_data. Only valid when the struct
+ * is constructed from PJSIP's pjsip_tx_data.
+ */
+ void *pjTxData;
+
+public:
+ /**
+ * Default constructor.
+ */
+ SipTxData();
+
+ /**
+ * Construct from PJSIP's pjsip_tx_data
+ */
+ void fromPj(pjsip_tx_data &tdata);
+};
+
+/**
+ * This structure describes SIP transaction object. It corresponds to the
+ * pjsip_transaction structure in PJSIP library.
+ */
+struct SipTransaction
+{
+ /* Transaction identification. */
+ pjsip_role_e role; /**< Role (UAS or UAC) */
+ string method; /**< The method. */
+
+ /* State and status. */
+ int statusCode; /**< Last status code seen. */
+ string statusText; /**< Last reason phrase. */
+ pjsip_tsx_state_e state; /**< State. */
+
+ /* Messages and timer. */
+ SipTxData lastTx; /**< Msg kept for retrans. */
+
+ /* Original pjsip_transaction. */
+ void *pjTransaction; /**< pjsip_transaction. */
+
+public:
+ /**
+ * Default constructor.
+ */
+ SipTransaction();
+
+ /**
+ * Construct from PJSIP's pjsip_transaction
+ */
+ void fromPj(pjsip_transaction &tsx);
+};
+
+/**
+ * This structure describes timer event.
+ */
+struct TimerEvent
+{
+ TimerEntry entry; /**< The timer entry. */
+};
+
+/**
+ * This structure describes transaction state changed event.
+ */
+struct TsxStateEvent
+{
+ struct
+ {
+ SipRxData rdata; /**< The incoming message. */
+ SipTxData tdata; /**< The outgoing message. */
+ TimerEntry timer; /**< The timer. */
+ pj_status_t status; /**< Transport error status. */
+ GenericData data; /**< Generic data. */
+ } src; /**< Event source. */
+ SipTransaction tsx; /**< The transaction. */
+ pjsip_tsx_state_e prevState; /**< Previous state. */
+ pjsip_event_id_e type; /**< Type of event source:
+ * - PJSIP_EVENT_TX_MSG
+ * - PJSIP_EVENT_RX_MSG,
+ * - PJSIP_EVENT_TRANSPORT_ERROR
+ * - PJSIP_EVENT_TIMER
+ * - PJSIP_EVENT_USER
+ */
+};
+
+/**
+ * This structure describes message transmission event.
+ */
+struct TxMsgEvent
+{
+ SipTxData tdata; /**< The transmit data buffer. */
+};
+
+/**
+ * This structure describes transmission error event.
+ */
+struct TxErrorEvent
+{
+ SipTxData tdata; /**< The transmit data. */
+ SipTransaction tsx; /**< The transaction. */
+};
+
+/**
+ * This structure describes message arrival event.
+ */
+struct RxMsgEvent
+{
+ SipRxData rdata; /**< The receive data buffer. */
+};
+
+/**
+ * This structure describes user event.
+ */
+struct UserEvent
+{
+ GenericData user1; /**< User data 1. */
+ GenericData user2; /**< User data 2. */
+ GenericData user3; /**< User data 3. */
+ GenericData user4; /**< User data 4. */
+};
+
+/**
+ * This structure describe event descriptor to fully identify a SIP event. It
+ * corresponds to the pjsip_event structure in PJSIP library.
+ */
+struct SipEvent
+{
+ /**
+ * The event type, can be any value of \b pjsip_event_id_e.
+ */
+ pjsip_event_id_e type;
+
+ /**
+ * The event body, which fields depends on the event type.
+ */
+ struct
+ {
+ /**
+ * Timer event.
+ */
+ TimerEvent timer;
+
+ /**
+ * Transaction state has changed event.
+ */
+ TsxStateEvent tsxState;
+
+ /**
+ * Message transmission event.
+ */
+ TxMsgEvent txMsg;
+
+ /**
+ * Transmission error event.
+ */
+ TxErrorEvent txError;
+
+ /**
+ * Message arrival event.
+ */
+ RxMsgEvent rxMsg;
+
+ /**
+ * User event.
+ */
+ UserEvent user;
+
+ } body;
+
+ /**
+ * Pointer to its original pjsip_event. Only valid when the struct is
+ * constructed from PJSIP's pjsip_event.
+ */
+ void *pjEvent;
+
+public:
+ /**
+ * Default constructor.
+ */
+ SipEvent();
+
+ /**
+ * Construct from PJSIP's pjsip_event
+ */
+ void fromPj(const pjsip_event &ev);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+/**
+ * SIP media type containing type and subtype. For example, for
+ * "application/sdp", the type is "application" and the subtype is "sdp".
+ */
+struct SipMediaType
+{
+ /** Media type. */
+ string type;
+
+ /** Media subtype. */
+ string subType;
+
+public:
+ /**
+ * Construct from PJSIP's pjsip_media_type
+ */
+ void fromPj(const pjsip_media_type &prm);
+
+ /**
+ * Convert to PJSIP's pjsip_media_type.
+ */
+ pjsip_media_type toPj() const;
+};
+
+/**
+ * Simple SIP header.
+ */
+struct SipHeader
+{
+ /**
+ * Header name.
+ */
+ string hName;
+
+ /**
+ * Header value.
+ */
+ string hValue;
+
+public:
+ /**
+ * Initiaize from PJSIP header.
+ */
+ void fromPj(const pjsip_hdr *) throw(Error);
+
+ /**
+ * Convert to PJSIP header.
+ */
+ pjsip_generic_string_hdr &toPj() const;
+
+private:
+ /** Interal buffer for conversion to PJSIP header */
+ mutable pjsip_generic_string_hdr pjHdr;
+};
+
+
+/** Array of strings */
+typedef std::vector<SipHeader> SipHeaderVector;
+
+/**
+ * This describes each multipart part.
+ */
+struct SipMultipartPart
+{
+ /**
+ * Optional headers to be put in this multipart part.
+ */
+ SipHeaderVector headers;
+
+ /**
+ * The MIME type of the body part of this multipart part.
+ */
+ SipMediaType contentType;
+
+ /**
+ * The body part of tthis multipart part.
+ */
+ string body;
+
+public:
+ /**
+ * Initiaize from PJSIP's pjsip_multipart_part.
+ */
+ void fromPj(const pjsip_multipart_part &prm) throw(Error);
+
+ /**
+ * Convert to PJSIP's pjsip_multipart_part.
+ */
+ pjsip_multipart_part& toPj() const;
+
+private:
+ /** Interal buffer for conversion to PJSIP pjsip_multipart_part */
+ mutable pjsip_multipart_part pjMpp;
+ mutable pjsip_msg_body pjMsgBody;
+};
+
+/** Array of multipart parts */
+typedef std::vector<SipMultipartPart> SipMultipartPartVector;
+
+/**
+ * Additional options when sending outgoing SIP message. This corresponds to
+ * pjsua_msg_data structure in PJSIP library.
+ */
+struct SipTxOption
+{
+ /**
+ * Optional remote target URI (i.e. Target header). If empty (""), the
+ * target will be set to the remote URI (To header). At the moment this
+ * field is only used when sending initial INVITE and MESSAGE requests.
+ */
+ string targetUri;
+
+ /**
+ * Additional message headers to be included in the outgoing message.
+ */
+ SipHeaderVector headers;
+
+ /**
+ * MIME type of the message body, if application specifies the messageBody
+ * in this structure.
+ */
+ string contentType;
+
+ /**
+ * Optional message body to be added to the message, only when the
+ * message doesn't have a body.
+ */
+ string msgBody;
+
+ /**
+ * Content type of the multipart body. If application wants to send
+ * multipart message bodies, it puts the parts in multipartParts and set
+ * the content type in multipartContentType. If the message already
+ * contains a body, the body will be added to the multipart bodies.
+ */
+ SipMediaType multipartContentType;
+
+ /**
+ * Array of multipart parts. If application wants to send multipart
+ * message bodies, it puts the parts in \a parts and set the content
+ * type in \a multipart_ctype. If the message already contains a body,
+ * the body will be added to the multipart bodies.
+ */
+ SipMultipartPartVector multipartParts;
+
+public:
+ /**
+ * Check if the options are empty. If the options are set with empty
+ * values, there will be no additional information sent with outgoing
+ * SIP message.
+ *
+ * @return True if the options are empty.
+ */
+ bool isEmpty() const;
+
+ /**
+ * Initiaize from PJSUA's pjsua_msg_data.
+ */
+ void fromPj(const pjsua_msg_data &prm) throw(Error);
+
+ /**
+ * Convert to PJSUA's pjsua_msg_data.
+ */
+ void toPj(pjsua_msg_data &msg_data) const;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+/**
+ * This structure contains parameters for sending instance message methods,
+ * e.g: Buddy::sendInstantMessage(), Call:sendInstantMessage().
+ */
+struct SendInstantMessageParam
+{
+ /**
+ * MIME type. Default is "text/plain".
+ */
+ string contentType;
+
+ /**
+ * The message content.
+ */
+ string content;
+
+ /**
+ * List of headers etc to be included in outgoing request.
+ */
+ SipTxOption txOption;
+
+ /**
+ * User data, which will be given back when the IM callback is called.
+ */
+ Token userData;
+
+public:
+ /**
+ * Default constructor initializes with zero/empty values.
+ */
+ SendInstantMessageParam();
+};
+
+
+/**
+ * This structure contains parameters for sending typing indication methods,
+ * e.g: Buddy::sendTypingIndication(), Call:sendTypingIndication().
+ */
+struct SendTypingIndicationParam
+{
+ /**
+ * True to indicate to remote that local person is currently typing an IM.
+ */
+ bool isTyping;
+
+ /**
+ * List of headers etc to be included in outgoing request.
+ */
+ SipTxOption txOption;
+
+public:
+ /**
+ * Default constructor initializes with zero/empty values.
+ */
+ SendTypingIndicationParam();
+};
+
+
+/* Utilities */
+#ifndef SWIG
+//! @cond Doxygen_Suppress
+void readIntVector( ContainerNode &node,
+ const string &array_name,
+ IntVector &v) throw(Error);
+void writeIntVector(ContainerNode &node,
+ const string &array_name,
+ const IntVector &v) throw(Error);
+void readQosParams( ContainerNode &node,
+ pj_qos_params &qos) throw(Error);
+void writeQosParams( ContainerNode &node,
+ const pj_qos_params &qos) throw(Error);
+void readSipHeaders( const ContainerNode &node,
+ const string &array_name,
+ SipHeaderVector &headers) throw(Error);
+void writeSipHeaders(ContainerNode &node,
+ const string &array_name,
+ const SipHeaderVector &headers) throw(Error);
+//! @endcond
+#endif // SWIG
+
+/**
+ * @} PJSUA2
+ */
+
+} // namespace pj
+
+
+
+#endif /* __PJSUA2_SIPTYPES_HPP__ */
diff --git a/pjsip/include/pjsua2/types.hpp b/pjsip/include/pjsua2/types.hpp
new file mode 100644
index 00000000..129ac4a6
--- /dev/null
+++ b/pjsip/include/pjsua2/types.hpp
@@ -0,0 +1,266 @@
+/* $Id$ */
+/*
+ * 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
+ */
+#ifndef __PJSUA2_TYPES_HPP__
+#define __PJSUA2_TYPES_HPP__
+
+#ifdef _MSC_VER
+# pragma warning( disable : 4290 ) // exception spec ignored
+# pragma warning( disable : 4512 ) // can't generate assignment op
+#endif
+
+/**
+ * @file pjsua2/types.hpp
+ * @brief PJSUA2 Base Types
+ */
+#include <pjsua2/config.hpp>
+
+#include <string>
+#include <vector>
+
+/** PJSUA2 API is inside pj namespace */
+namespace pj
+{
+
+/**
+ * @defgroup PJSUA2_TYPES General Data Structure
+ * @ingroup PJSUA2_DS
+ * @{
+ */
+
+using std::string;
+using std::vector;
+
+/** Array of strings */
+typedef std::vector<std::string> StringVector;
+
+/** Array of integers */
+typedef std::vector<int> IntVector;
+
+/**
+ * Type of token, i.e. arbitrary application user data
+ */
+typedef void *Token;
+
+/**
+ * Socket address, encoded as string. The socket address contains host
+ * and port number in "host[:port]" format. The host part may contain
+ * hostname, domain name, IPv4 or IPv6 address. For IPv6 address, the
+ * address will be enclosed with square brackets, e.g. "[::1]:5060".
+ */
+typedef string SocketAddress;
+
+/**
+ * Transport ID is an integer.
+ */
+typedef int TransportId;
+
+/**
+ * Transport handle, corresponds to pjsip_transport instance.
+ */
+typedef void *TransportHandle;
+
+/**
+ * Timer entry, corresponds to pj_timer_entry
+ */
+typedef void *TimerEntry;
+
+/**
+ * Generic data
+ */
+typedef void *GenericData;
+
+/*
+ * Forward declaration of Account and Call to be used
+ * by Endpoint.
+ */
+class Account;
+class Call;
+
+
+/**
+ * Constants
+ */
+enum
+{
+ /** Invalid ID, equal to PJSUA_INVALID_ID */
+ INVALID_ID = -1,
+
+ /** Success, equal to PJ_SUCCESS */
+ SUCCESS = 0
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+/**
+ * This structure contains information about an error that is thrown
+ * as an exception.
+ */
+struct Error
+{
+ /** The error code. */
+ pj_status_t status;
+
+ /** The PJSUA API operation that throws the error. */
+ string title;
+
+ /** The error message */
+ string reason;
+
+ /** The PJSUA source file that throws the error */
+ string srcFile;
+
+ /** The line number of PJSUA source file that throws the error */
+ int srcLine;
+
+ /** Build error string. */
+ string info(bool multi_line=false) const;
+
+ /** Default constructor */
+ Error();
+
+ /**
+ * Construct an Error instance from the specified parameters. If
+ * \a prm_reason is empty, it will be filled with the error description
+ * for the status code.
+ */
+ Error(pj_status_t prm_status,
+ const string &prm_title,
+ const string &prm_reason,
+ const string &prm_src_file,
+ int prm_src_line);
+};
+
+
+/*
+ * Error utilities.
+ */
+#if PJSUA2_ERROR_HAS_EXTRA_INFO
+# define PJSUA2_RAISE_ERROR(status) \
+ PJSUA2_RAISE_ERROR2(status, __FUNCTION__)
+
+# define PJSUA2_RAISE_ERROR2(status,op) \
+ PJSUA2_RAISE_ERROR3(status, op, string())
+
+# define PJSUA2_RAISE_ERROR3(status,op,txt) \
+ do { \
+ Error err_ = Error(status, op, txt, __FILE__, __LINE__); \
+ PJ_LOG(1,(THIS_FILE, "%s", err_.info().c_str())); \
+ throw err_; \
+ } while (0)
+
+#else
+ /** Raise Error exception */
+# define PJSUA2_RAISE_ERROR(status) \
+ PJSUA2_RAISE_ERROR2(status, string())
+
+/** Raise Error exception */
+# define PJSUA2_RAISE_ERROR2(status,op) \
+ PJSUA2_RAISE_ERROR3(status, op, string())
+
+/** Raise Error exception */
+# define PJSUA2_RAISE_ERROR3(status,op,txt) \
+ do { \
+ Error err_ = Error(status, op, txt, string(), 0); \
+ PJ_LOG(1,(THIS_FILE, "%s", err_.info().c_str())); \
+ throw err_; \
+ } while (0)
+
+#endif
+
+/** Raise Error exception if the expression fails */
+#define PJSUA2_CHECK_RAISE_ERROR2(status, op) \
+ do { \
+ if (status != PJ_SUCCESS) { \
+ PJSUA2_RAISE_ERROR2(status, op); \
+ } \
+ } while (0)
+
+/** Raise Error exception if the status fails */
+#define PJSUA2_CHECK_RAISE_ERROR(status) \
+ PJSUA2_CHECK_RAISE_ERROR2(status, "")
+
+/** Raise Error exception if the expression fails */
+#define PJSUA2_CHECK_EXPR(expr) \
+ do { \
+ pj_status_t the_status = expr; \
+ PJSUA2_CHECK_RAISE_ERROR2(the_status, #expr); \
+ } while (0)
+
+//////////////////////////////////////////////////////////////////////////////
+/**
+ * Version information.
+ */
+struct Version
+{
+ /** Major number */
+ int major;
+
+ /** Minor number */
+ int minor;
+
+ /** Additional revision number */
+ int rev;
+
+ /** Version suffix (e.g. "-svn") */
+ string suffix;
+
+ /** The full version info (e.g. "2.1.0-svn") */
+ string full;
+
+ /**
+ * PJLIB version number as three bytes with the following format:
+ * 0xMMIIRR00, where MM: major number, II: minor number, RR: revision
+ * number, 00: always zero for now.
+ */
+ unsigned numeric;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Representation of time value.
+ */
+struct TimeValue
+{
+ /**
+ * The seconds part of the time.
+ */
+ long sec;
+
+ /**
+ * The miliseconds fraction of the time.
+ */
+ long msec;
+
+public:
+ /**
+ * Convert from pjsip
+ */
+ void fromPj(const pj_time_val &prm);
+};
+
+/**
+ * @} PJSUA2
+ */
+
+} // namespace pj
+
+
+
+#endif /* __PJSUA2_TYPES_HPP__ */
diff --git a/pjsip/src/pjsip/sip_endpoint.c b/pjsip/src/pjsip/sip_endpoint.c
index 7a3a3a38..d1f66b8c 100644
--- a/pjsip/src/pjsip/sip_endpoint.c
+++ b/pjsip/src/pjsip/sip_endpoint.c
@@ -923,6 +923,8 @@ static void endpt_on_rx_msg( pjsip_endpoint *endpt,
pjsip_process_rdata_param proc_prm;
pj_bool_t handled = PJ_FALSE;
+ PJ_UNUSED_ARG(msg);
+
if (status != PJ_SUCCESS) {
char info[30];
char errmsg[PJ_ERR_MSG_SIZE];
diff --git a/pjsip/src/pjsua-lib/pjsua_aud.c b/pjsip/src/pjsua-lib/pjsua_aud.c
index e15c54aa..0f5172e9 100644
--- a/pjsip/src/pjsua-lib/pjsua_aud.c
+++ b/pjsip/src/pjsua-lib/pjsua_aud.c
@@ -741,10 +741,13 @@ PJ_DEF(pj_status_t) pjsua_conf_get_port_info( pjsua_conf_port_id id,
pj_bzero(info, sizeof(*info));
info->slot_id = id;
info->name = cinfo.name;
+ pjmedia_format_copy(&info->format, &cinfo.format);
info->clock_rate = cinfo.clock_rate;
info->channel_count = cinfo.channel_count;
info->samples_per_frame = cinfo.samples_per_frame;
info->bits_per_sample = cinfo.bits_per_sample;
+ info->tx_level_adj = ((float)cinfo.tx_adj_level) / 128 + 1;
+ info->rx_level_adj = ((float)cinfo.rx_adj_level) / 128 + 1;
/* Build array of listeners */
info->listener_cnt = cinfo.listener_cnt;
diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c
index 8b0f0e62..e4893401 100644
--- a/pjsip/src/pjsua-lib/pjsua_core.c
+++ b/pjsip/src/pjsua-lib/pjsua_core.c
@@ -699,6 +699,50 @@ static int worker_thread(void *arg)
return 0;
}
+PJ_DEF(pj_status_t) pjsua_register_worker_thread(const char *name)
+{
+ pj_thread_desc desc;
+ pj_thread_t *thread;
+ pj_status_t status;
+
+ if (pjsua_var.thread_quit_flag)
+ return PJ_EGONE;
+
+ status = pj_thread_register(NULL, desc, &thread);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ if (name)
+ PJ_LOG(4,(THIS_FILE, "Worker thread %s started", name));
+
+ worker_thread(NULL);
+
+ if (name)
+ PJ_LOG(4,(THIS_FILE, "Worker thread %s stopped", name));
+
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(void) pjsua_stop_worker_threads(void)
+{
+ unsigned i;
+
+ pjsua_var.thread_quit_flag = 1;
+
+ /* Wait worker threads to quit: */
+ for (i=0; i<(int)pjsua_var.ua_cfg.thread_cnt; ++i) {
+ if (pjsua_var.thread[i]) {
+ pj_status_t status;
+ status = pj_thread_join(pjsua_var.thread[i]);
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(4,(THIS_FILE, status, "Error joining worker thread"));
+ pj_thread_sleep(1000);
+ }
+ pj_thread_destroy(pjsua_var.thread[i]);
+ pjsua_var.thread[i] = NULL;
+ }
+ }
+}
/* Init random seed */
static void init_random_seed(void)
@@ -1478,21 +1522,7 @@ PJ_DEF(pj_status_t) pjsua_destroy2(unsigned flags)
}
/* Signal threads to quit: */
- pjsua_var.thread_quit_flag = 1;
-
- /* Wait worker threads to quit: */
- for (i=0; i<(int)pjsua_var.ua_cfg.thread_cnt; ++i) {
- if (pjsua_var.thread[i]) {
- pj_status_t status;
- status = pj_thread_join(pjsua_var.thread[i]);
- if (status != PJ_SUCCESS) {
- PJ_PERROR(4,(THIS_FILE, status, "Error joining worker thread"));
- pj_thread_sleep(1000);
- }
- pj_thread_destroy(pjsua_var.thread[i]);
- pjsua_var.thread[i] = NULL;
- }
- }
+ pjsua_stop_worker_threads();
if (pjsua_var.endpt) {
unsigned max_wait;
diff --git a/pjsip/src/pjsua2-test/main.cpp b/pjsip/src/pjsua2-test/main.cpp
new file mode 100644
index 00000000..c76811bb
--- /dev/null
+++ b/pjsip/src/pjsua2-test/main.cpp
@@ -0,0 +1,38 @@
+/* $Id$ */
+/*
+ * 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
+ */
+#include <pjsua2/endpoint.hpp>
+
+using namespace pj;
+
+int main(int argc, char *argv[])
+{
+ Endpoint &ep = Endpoint::instance();
+
+ EpConfig epCfg;
+
+ epCfg.uaConfig.userAgent = "pjsua++-test";
+
+ ep.libCreate();
+ ep.libInit(epCfg);
+ ep.libStart();
+ ep.libDestroy();
+
+ return 0;
+}
+
diff --git a/pjsip/src/pjsua2/account.cpp b/pjsip/src/pjsua2/account.cpp
new file mode 100644
index 00000000..247c4a4a
--- /dev/null
+++ b/pjsip/src/pjsua2/account.cpp
@@ -0,0 +1,799 @@
+/* $Id$ */
+/*
+ * 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
+ */
+#include <pjsua2/account.hpp>
+#include <pjsua2/endpoint.hpp>
+#include <pjsua2/presence.hpp>
+#include <pj/ctype.h>
+#include "util.hpp"
+
+using namespace pj;
+using namespace std;
+
+#define THIS_FILE "account.cpp"
+
+///////////////////////////////////////////////////////////////////////////////
+
+void AccountRegConfig::readObject(const ContainerNode &node) throw(Error)
+{
+ ContainerNode this_node = node.readContainer("AccountRegConfig");
+
+ NODE_READ_STRING (this_node, registrarUri);
+ NODE_READ_BOOL (this_node, registerOnAdd);
+ NODE_READ_UNSIGNED (this_node, timeoutSec);
+ NODE_READ_UNSIGNED (this_node, retryIntervalSec);
+ NODE_READ_UNSIGNED (this_node, firstRetryIntervalSec);
+ NODE_READ_UNSIGNED (this_node, delayBeforeRefreshSec);
+ NODE_READ_BOOL (this_node, dropCallsOnFail);
+ NODE_READ_UNSIGNED (this_node, unregWaitSec);
+ NODE_READ_UNSIGNED (this_node, proxyUse);
+
+ readSipHeaders(this_node, "headers", headers);
+}
+
+void AccountRegConfig::writeObject(ContainerNode &node) const throw(Error)
+{
+ ContainerNode this_node = node.writeNewContainer("AccountRegConfig");
+
+ NODE_WRITE_STRING (this_node, registrarUri);
+ NODE_WRITE_BOOL (this_node, registerOnAdd);
+ NODE_WRITE_UNSIGNED (this_node, timeoutSec);
+ NODE_WRITE_UNSIGNED (this_node, retryIntervalSec);
+ NODE_WRITE_UNSIGNED (this_node, firstRetryIntervalSec);
+ NODE_WRITE_UNSIGNED (this_node, delayBeforeRefreshSec);
+ NODE_WRITE_BOOL (this_node, dropCallsOnFail);
+ NODE_WRITE_UNSIGNED (this_node, unregWaitSec);
+ NODE_WRITE_UNSIGNED (this_node, proxyUse);
+
+ writeSipHeaders(this_node, "headers", headers);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void AccountSipConfig::readObject(const ContainerNode &node) throw(Error)
+{
+ ContainerNode this_node = node.readContainer("AccountSipConfig");
+
+ NODE_READ_STRINGV (this_node, proxies);
+ NODE_READ_STRING (this_node, contactForced);
+ NODE_READ_STRING (this_node, contactParams);
+ NODE_READ_STRING (this_node, contactUriParams);
+ NODE_READ_BOOL (this_node, authInitialEmpty);
+ NODE_READ_STRING (this_node, authInitialAlgorithm);
+ NODE_READ_INT (this_node, transportId);
+
+ ContainerNode creds_node = this_node.readArray("authCreds");
+ authCreds.resize(0);
+ while (creds_node.hasUnread()) {
+ AuthCredInfo cred;
+ cred.readObject(creds_node);
+ authCreds.push_back(cred);
+ }
+}
+
+void AccountSipConfig::writeObject(ContainerNode &node) const throw(Error)
+{
+ ContainerNode this_node = node.writeNewContainer("AccountSipConfig");
+
+ NODE_WRITE_STRINGV (this_node, proxies);
+ NODE_WRITE_STRING (this_node, contactForced);
+ NODE_WRITE_STRING (this_node, contactParams);
+ NODE_WRITE_STRING (this_node, contactUriParams);
+ NODE_WRITE_BOOL (this_node, authInitialEmpty);
+ NODE_WRITE_STRING (this_node, authInitialAlgorithm);
+ NODE_WRITE_INT (this_node, transportId);
+
+ ContainerNode creds_node = this_node.writeNewArray("authCreds");
+ for (unsigned i=0; i<authCreds.size(); ++i) {
+ authCreds[i].writeObject(creds_node);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void AccountCallConfig::readObject(const ContainerNode &node) throw(Error)
+{
+ ContainerNode this_node = node.readContainer("AccountCallConfig");
+
+ NODE_READ_NUM_T ( this_node, pjsua_call_hold_type, holdType);
+ NODE_READ_NUM_T ( this_node, pjsua_100rel_use, prackUse);
+ NODE_READ_NUM_T ( this_node, pjsua_sip_timer_use, timerUse);
+ NODE_READ_UNSIGNED( this_node, timerMinSESec);
+ NODE_READ_UNSIGNED( this_node, timerSessExpiresSec);
+}
+
+void AccountCallConfig::writeObject(ContainerNode &node) const throw(Error)
+{
+ ContainerNode this_node = node.writeNewContainer("AccountCallConfig");
+
+ NODE_WRITE_NUM_T ( this_node, pjsua_call_hold_type, holdType);
+ NODE_WRITE_NUM_T ( this_node, pjsua_100rel_use, prackUse);
+ NODE_WRITE_NUM_T ( this_node, pjsua_sip_timer_use, timerUse);
+ NODE_WRITE_UNSIGNED( this_node, timerMinSESec);
+ NODE_WRITE_UNSIGNED( this_node, timerSessExpiresSec);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void AccountPresConfig::readObject(const ContainerNode &node) throw(Error)
+{
+ ContainerNode this_node = node.readContainer("AccountPresConfig");
+
+ NODE_READ_BOOL ( this_node, publishEnabled);
+ NODE_READ_BOOL ( this_node, publishQueue);
+ NODE_READ_UNSIGNED( this_node, publishShutdownWaitMsec);
+ NODE_READ_STRING ( this_node, pidfTupleId);
+
+ readSipHeaders(this_node, "headers", headers);
+}
+
+void AccountPresConfig::writeObject(ContainerNode &node) const throw(Error)
+{
+ ContainerNode this_node = node.writeNewContainer("AccountPresConfig");
+
+ NODE_WRITE_BOOL ( this_node, publishEnabled);
+ NODE_WRITE_BOOL ( this_node, publishQueue);
+ NODE_WRITE_UNSIGNED( this_node, publishShutdownWaitMsec);
+ NODE_WRITE_STRING ( this_node, pidfTupleId);
+
+ writeSipHeaders(this_node, "headers", headers);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void AccountMwiConfig::readObject(const ContainerNode &node) throw(Error)
+{
+ ContainerNode this_node = node.readContainer("AccountMwiConfig");
+
+ NODE_READ_BOOL ( this_node, enabled);
+ NODE_READ_UNSIGNED( this_node, expirationSec);
+}
+
+void AccountMwiConfig::writeObject(ContainerNode &node) const throw(Error)
+{
+ ContainerNode this_node = node.writeNewContainer("AccountMwiConfig");
+
+ NODE_WRITE_BOOL ( this_node, enabled);
+ NODE_WRITE_UNSIGNED( this_node, expirationSec);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void AccountNatConfig::readObject(const ContainerNode &node) throw(Error)
+{
+ ContainerNode this_node = node.readContainer("AccountNatConfig");
+
+ NODE_READ_NUM_T ( this_node, pjsua_stun_use, sipStunUse);
+ NODE_READ_NUM_T ( this_node, pjsua_stun_use, mediaStunUse);
+ NODE_READ_BOOL ( this_node, iceEnabled);
+ NODE_READ_INT ( this_node, iceMaxHostCands);
+ NODE_READ_BOOL ( this_node, iceAggressiveNomination);
+ NODE_READ_UNSIGNED( this_node, iceNominatedCheckDelayMsec);
+ NODE_READ_INT ( this_node, iceWaitNominationTimeoutMsec);
+ NODE_READ_BOOL ( this_node, iceNoRtcp);
+ NODE_READ_BOOL ( this_node, iceAlwaysUpdate);
+ NODE_READ_BOOL ( this_node, turnEnabled);
+ NODE_READ_STRING ( this_node, turnServer);
+ NODE_READ_NUM_T ( this_node, pj_turn_tp_type, turnConnType);
+ NODE_READ_STRING ( this_node, turnUserName);
+ NODE_READ_INT ( this_node, turnPasswordType);
+ NODE_READ_STRING ( this_node, turnPassword);
+ NODE_READ_INT ( this_node, contactRewriteUse);
+ NODE_READ_INT ( this_node, contactRewriteMethod);
+ NODE_READ_INT ( this_node, viaRewriteUse);
+ NODE_READ_INT ( this_node, sdpNatRewriteUse);
+ NODE_READ_INT ( this_node, sipOutboundUse);
+ NODE_READ_STRING ( this_node, sipOutboundInstanceId);
+ NODE_READ_STRING ( this_node, sipOutboundRegId);
+ NODE_READ_UNSIGNED( this_node, udpKaIntervalSec);
+ NODE_READ_STRING ( this_node, udpKaData);
+}
+
+void AccountNatConfig::writeObject(ContainerNode &node) const throw(Error)
+{
+ ContainerNode this_node = node.writeNewContainer("AccountNatConfig");
+
+ NODE_WRITE_NUM_T ( this_node, pjsua_stun_use, sipStunUse);
+ NODE_WRITE_NUM_T ( this_node, pjsua_stun_use, mediaStunUse);
+ NODE_WRITE_BOOL ( this_node, iceEnabled);
+ NODE_WRITE_INT ( this_node, iceMaxHostCands);
+ NODE_WRITE_BOOL ( this_node, iceAggressiveNomination);
+ NODE_WRITE_UNSIGNED( this_node, iceNominatedCheckDelayMsec);
+ NODE_WRITE_INT ( this_node, iceWaitNominationTimeoutMsec);
+ NODE_WRITE_BOOL ( this_node, iceNoRtcp);
+ NODE_WRITE_BOOL ( this_node, iceAlwaysUpdate);
+ NODE_WRITE_BOOL ( this_node, turnEnabled);
+ NODE_WRITE_STRING ( this_node, turnServer);
+ NODE_WRITE_NUM_T ( this_node, pj_turn_tp_type, turnConnType);
+ NODE_WRITE_STRING ( this_node, turnUserName);
+ NODE_WRITE_INT ( this_node, turnPasswordType);
+ NODE_WRITE_STRING ( this_node, turnPassword);
+ NODE_WRITE_INT ( this_node, contactRewriteUse);
+ NODE_WRITE_INT ( this_node, contactRewriteMethod);
+ NODE_WRITE_INT ( this_node, viaRewriteUse);
+ NODE_WRITE_INT ( this_node, sdpNatRewriteUse);
+ NODE_WRITE_INT ( this_node, sipOutboundUse);
+ NODE_WRITE_STRING ( this_node, sipOutboundInstanceId);
+ NODE_WRITE_STRING ( this_node, sipOutboundRegId);
+ NODE_WRITE_UNSIGNED( this_node, udpKaIntervalSec);
+ NODE_WRITE_STRING ( this_node, udpKaData);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void AccountMediaConfig::readObject(const ContainerNode &node) throw(Error)
+{
+ ContainerNode this_node = node.readContainer("AccountMediaConfig");
+
+ NODE_READ_BOOL ( this_node, lockCodecEnabled);
+ NODE_READ_BOOL ( this_node, streamKaEnabled);
+ NODE_READ_NUM_T ( this_node, pjmedia_srtp_use, srtpUse);
+ NODE_READ_INT ( this_node, srtpSecureSignaling);
+ NODE_READ_NUM_T ( this_node, pjsua_ipv6_use, ipv6Use);
+ NODE_READ_OBJ ( this_node, transportConfig);
+}
+
+void AccountMediaConfig::writeObject(ContainerNode &node) const throw(Error)
+{
+ ContainerNode this_node = node.writeNewContainer("AccountMediaConfig");
+
+ NODE_WRITE_BOOL ( this_node, lockCodecEnabled);
+ NODE_WRITE_BOOL ( this_node, streamKaEnabled);
+ NODE_WRITE_NUM_T ( this_node, pjmedia_srtp_use, srtpUse);
+ NODE_WRITE_INT ( this_node, srtpSecureSignaling);
+ NODE_WRITE_NUM_T ( this_node, pjsua_ipv6_use, ipv6Use);
+ NODE_WRITE_OBJ ( this_node, transportConfig);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void AccountVideoConfig::readObject(const ContainerNode &node) throw(Error)
+{
+ ContainerNode this_node = node.readContainer("AccountVideoConfig");
+
+ NODE_READ_BOOL ( this_node, autoShowIncoming);
+ NODE_READ_BOOL ( this_node, autoTransmitOutgoing);
+ NODE_READ_UNSIGNED( this_node, windowFlags);
+ NODE_READ_NUM_T ( this_node, pjmedia_vid_dev_index, defaultCaptureDevice);
+ NODE_READ_NUM_T ( this_node, pjmedia_vid_dev_index, defaultRenderDevice);
+ NODE_READ_NUM_T ( this_node, pjmedia_vid_stream_rc_method, rateControlMethod);
+ NODE_READ_UNSIGNED( this_node, rateControlBandwidth);
+}
+
+void AccountVideoConfig::writeObject(ContainerNode &node) const throw(Error)
+{
+ ContainerNode this_node = node.writeNewContainer("AccountVideoConfig");
+
+ NODE_WRITE_BOOL ( this_node, autoShowIncoming);
+ NODE_WRITE_BOOL ( this_node, autoTransmitOutgoing);
+ NODE_WRITE_UNSIGNED( this_node, windowFlags);
+ NODE_WRITE_NUM_T ( this_node, pjmedia_vid_dev_index, defaultCaptureDevice);
+ NODE_WRITE_NUM_T ( this_node, pjmedia_vid_dev_index, defaultRenderDevice);
+ NODE_WRITE_NUM_T ( this_node, pjmedia_vid_stream_rc_method, rateControlMethod);
+ NODE_WRITE_UNSIGNED( this_node, rateControlBandwidth);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+AccountConfig::AccountConfig()
+{
+ pjsua_acc_config acc_cfg;
+ pjsua_acc_config_default(&acc_cfg);
+ pjsua_media_config med_cfg;
+ pjsua_media_config_default(&med_cfg);
+ fromPj(acc_cfg, &med_cfg);
+}
+
+/* Convert to pjsip. */
+void AccountConfig::toPj(pjsua_acc_config &ret) const
+{
+ unsigned i;
+
+ pjsua_acc_config_default(&ret);
+
+ // Global
+ ret.priority = priority;
+ ret.id = str2Pj(idUri);
+
+ // AccountRegConfig
+ ret.reg_uri = str2Pj(regConfig.registrarUri);
+ ret.register_on_acc_add = regConfig.registerOnAdd;
+ ret.reg_timeout = regConfig.timeoutSec;
+ ret.reg_retry_interval = regConfig.retryIntervalSec;
+ ret.reg_first_retry_interval= regConfig.firstRetryIntervalSec;
+ ret.reg_delay_before_refresh= regConfig.delayBeforeRefreshSec;
+ ret.drop_calls_on_reg_fail = regConfig.dropCallsOnFail;
+ ret.unreg_timeout = regConfig.unregWaitSec;
+ ret.reg_use_proxy = regConfig.proxyUse;
+ for (i=0; i<regConfig.headers.size(); ++i) {
+ pj_list_push_back(&ret.reg_hdr_list, &regConfig.headers[i].toPj());
+ }
+
+ // AccountSipConfig
+ ret.cred_count = 0;
+ if (sipConfig.authCreds.size() > PJ_ARRAY_SIZE(ret.cred_info))
+ PJSUA2_RAISE_ERROR(PJ_ETOOMANY);
+ for (i=0; i<sipConfig.authCreds.size(); ++i) {
+ const AuthCredInfo &src = sipConfig.authCreds[i];
+ pjsip_cred_info *dst = &ret.cred_info[i];
+
+ dst->realm = str2Pj(src.realm);
+ dst->scheme = str2Pj(src.scheme);
+ dst->username = str2Pj(src.username);
+ dst->data_type = src.dataType;
+ dst->data = str2Pj(src.data);
+ dst->ext.aka.k = str2Pj(src.akaK);
+ dst->ext.aka.op = str2Pj(src.akaOp);
+ dst->ext.aka.amf= str2Pj(src.akaAmf);
+
+ ret.cred_count++;
+ }
+ ret.proxy_cnt = 0;
+ if (sipConfig.proxies.size() > PJ_ARRAY_SIZE(ret.proxy))
+ PJSUA2_RAISE_ERROR(PJ_ETOOMANY);
+ for (i=0; i<sipConfig.proxies.size(); ++i) {
+ ret.proxy[ret.proxy_cnt++] = str2Pj(sipConfig.proxies[i]);
+ }
+ ret.force_contact = str2Pj(sipConfig.contactForced);
+ ret.contact_params = str2Pj(sipConfig.contactParams);
+ ret.contact_uri_params = str2Pj(sipConfig.contactUriParams);
+ ret.auth_pref.initial_auth = sipConfig.authInitialEmpty;
+ ret.auth_pref.algorithm = str2Pj(sipConfig.authInitialAlgorithm);
+ ret.transport_id = sipConfig.transportId;
+
+ // AccountCallConfig
+ ret.call_hold_type = callConfig.holdType;
+ ret.require_100rel = callConfig.prackUse;
+ ret.use_timer = callConfig.timerUse;
+ ret.timer_setting.min_se = callConfig.timerMinSESec;
+ ret.timer_setting.sess_expires = callConfig.timerSessExpiresSec;
+
+ // AccountPresConfig
+ for (i=0; i<presConfig.headers.size(); ++i) {
+ pj_list_push_back(&ret.sub_hdr_list, &presConfig.headers[i].toPj());
+ }
+ ret.publish_enabled = presConfig.publishEnabled;
+ ret.publish_opt.queue_request= presConfig.publishQueue;
+ ret.unpublish_max_wait_time_msec = presConfig.publishShutdownWaitMsec;
+ ret.pidf_tuple_id = str2Pj(presConfig.pidfTupleId);
+
+ // AccountNatConfig
+ ret.sip_stun_use = natConfig.sipStunUse;
+ ret.media_stun_use = natConfig.mediaStunUse;
+ ret.ice_cfg_use = PJSUA_ICE_CONFIG_USE_CUSTOM;
+ ret.ice_cfg.enable_ice = natConfig.iceEnabled;
+ ret.ice_cfg.ice_max_host_cands = natConfig.iceMaxHostCands;
+ ret.ice_cfg.ice_opt.aggressive = natConfig.iceAggressiveNomination;
+ ret.ice_cfg.ice_opt.nominated_check_delay = natConfig.iceNominatedCheckDelayMsec;
+ ret.ice_cfg.ice_opt.controlled_agent_want_nom_timeout = natConfig.iceWaitNominationTimeoutMsec;
+ ret.ice_cfg.ice_no_rtcp = natConfig.iceNoRtcp;
+ ret.ice_cfg.ice_always_update = natConfig.iceAlwaysUpdate;
+
+ ret.turn_cfg_use = PJSUA_TURN_CONFIG_USE_CUSTOM;
+ ret.turn_cfg.enable_turn = natConfig.turnEnabled;
+ ret.turn_cfg.turn_server = str2Pj(natConfig.turnServer);
+ ret.turn_cfg.turn_conn_type = natConfig.turnConnType;
+ ret.turn_cfg.turn_auth_cred.type = PJ_STUN_AUTH_CRED_STATIC;
+ ret.turn_cfg.turn_auth_cred.data.static_cred.username = str2Pj(natConfig.turnUserName);
+ ret.turn_cfg.turn_auth_cred.data.static_cred.data_type = (pj_stun_passwd_type)natConfig.turnPasswordType;
+ ret.turn_cfg.turn_auth_cred.data.static_cred.data = str2Pj(natConfig.turnPassword);
+ ret.turn_cfg.turn_auth_cred.data.static_cred.realm = pj_str((char*)"");
+ ret.turn_cfg.turn_auth_cred.data.static_cred.nonce = pj_str((char*)"");
+
+ ret.allow_contact_rewrite = natConfig.contactRewriteUse;
+ ret.contact_rewrite_method = natConfig.contactRewriteMethod;
+ ret.allow_via_rewrite = natConfig.viaRewriteUse;
+ ret.allow_sdp_nat_rewrite = natConfig.sdpNatRewriteUse;
+ ret.use_rfc5626 = natConfig.sipOutboundUse;
+ ret.rfc5626_instance_id = str2Pj(natConfig.sipOutboundInstanceId);
+ ret.rfc5626_reg_id = str2Pj(natConfig.sipOutboundRegId);
+ ret.ka_interval = natConfig.udpKaIntervalSec;
+ ret.ka_data = str2Pj(natConfig.udpKaData);
+
+ // AccountMediaConfig
+ ret.rtp_cfg = mediaConfig.transportConfig.toPj();
+ ret.lock_codec = mediaConfig.lockCodecEnabled;
+#if defined(PJMEDIA_STREAM_ENABLE_KA) && (PJMEDIA_STREAM_ENABLE_KA != 0)
+ ret.use_stream_ka = mediaConfig.streamKaEnabled;
+#endif
+ ret.use_srtp = mediaConfig.srtpUse;
+ ret.srtp_secure_signaling = mediaConfig.srtpSecureSignaling;
+ ret.ipv6_media_use = mediaConfig.ipv6Use;
+
+ // AccountVideoConfig
+ ret.vid_in_auto_show = videoConfig.autoShowIncoming;
+ ret.vid_out_auto_transmit = videoConfig.autoTransmitOutgoing;
+ ret.vid_wnd_flags = videoConfig.windowFlags;
+ ret.vid_cap_dev = videoConfig.defaultCaptureDevice;
+ ret.vid_rend_dev = videoConfig.defaultRenderDevice;
+ ret.vid_stream_rc_cfg.method= videoConfig.rateControlMethod;
+ ret.vid_stream_rc_cfg.bandwidth = videoConfig.rateControlBandwidth;
+}
+
+/* Initialize from pjsip. */
+void AccountConfig::fromPj(const pjsua_acc_config &prm,
+ const pjsua_media_config *mcfg)
+{
+ const pjsip_hdr *hdr;
+ unsigned i;
+
+ // Global
+ priority = prm.priority;
+ idUri = pj2Str(prm.id);
+
+ // AccountRegConfig
+ regConfig.registrarUri = pj2Str(prm.reg_uri);
+ regConfig.registerOnAdd = (prm.register_on_acc_add != 0);
+ regConfig.timeoutSec = prm.reg_timeout;
+ regConfig.retryIntervalSec = prm.reg_retry_interval;
+ regConfig.firstRetryIntervalSec = prm.reg_first_retry_interval;
+ regConfig.delayBeforeRefreshSec = prm.reg_delay_before_refresh;
+ regConfig.dropCallsOnFail = PJ2BOOL(prm.drop_calls_on_reg_fail);
+ regConfig.unregWaitSec = prm.unreg_timeout;
+ regConfig.proxyUse = prm.reg_use_proxy;
+ regConfig.headers.clear();
+ hdr = prm.reg_hdr_list.next;
+ while (hdr != &prm.reg_hdr_list) {
+ SipHeader new_hdr;
+ new_hdr.fromPj(hdr);
+
+ regConfig.headers.push_back(new_hdr);
+
+ hdr = hdr->next;
+ }
+
+ // AccountSipConfig
+ sipConfig.authCreds.clear();
+ for (i=0; i<prm.cred_count; ++i) {
+ AuthCredInfo cred;
+ const pjsip_cred_info &src = prm.cred_info[i];
+
+ cred.realm = pj2Str(src.realm);
+ cred.scheme = pj2Str(src.scheme);
+ cred.username = pj2Str(src.username);
+ cred.dataType = src.data_type;
+ cred.data = pj2Str(src.data);
+ cred.akaK = pj2Str(src.ext.aka.k);
+ cred.akaOp = pj2Str(src.ext.aka.op);
+ cred.akaAmf = pj2Str(src.ext.aka.amf);
+
+ sipConfig.authCreds.push_back(cred);
+ }
+ sipConfig.proxies.clear();
+ for (i=0; i<prm.proxy_cnt; ++i) {
+ sipConfig.proxies.push_back(pj2Str(prm.proxy[i]));
+ }
+ sipConfig.contactForced = pj2Str(prm.force_contact);
+ sipConfig.contactParams = pj2Str(prm.contact_params);
+ sipConfig.contactUriParams = pj2Str(prm.contact_uri_params);
+ sipConfig.authInitialEmpty = PJ2BOOL(prm.auth_pref.initial_auth);
+ sipConfig.authInitialAlgorithm = pj2Str(prm.auth_pref.algorithm);
+ sipConfig.transportId = prm.transport_id;
+
+ // AccountCallConfig
+ callConfig.holdType = prm.call_hold_type;
+ callConfig.prackUse = prm.require_100rel;
+ callConfig.timerUse = prm.use_timer;
+ callConfig.timerMinSESec = prm.timer_setting.min_se;
+ callConfig.timerSessExpiresSec = prm.timer_setting.sess_expires;
+
+ // AccountPresConfig
+ presConfig.headers.clear();
+ hdr = prm.sub_hdr_list.next;
+ while (hdr != &prm.sub_hdr_list) {
+ SipHeader new_hdr;
+ new_hdr.fromPj(hdr);
+ presConfig.headers.push_back(new_hdr);
+ hdr = hdr->next;
+ }
+ presConfig.publishEnabled = PJ2BOOL(prm.publish_enabled);
+ presConfig.publishQueue = PJ2BOOL(prm.publish_opt.queue_request);
+ presConfig.publishShutdownWaitMsec = prm.unpublish_max_wait_time_msec;
+ presConfig.pidfTupleId = pj2Str(prm.pidf_tuple_id);
+
+ // AccountMwiConfig
+ mwiConfig.enabled = PJ2BOOL(prm.mwi_enabled);
+ mwiConfig.expirationSec = prm.mwi_expires;
+
+ // AccountNatConfig
+ natConfig.sipStunUse = prm.sip_stun_use;
+ natConfig.mediaStunUse = prm.media_stun_use;
+ if (prm.ice_cfg_use == PJSUA_ICE_CONFIG_USE_CUSTOM) {
+ natConfig.iceEnabled = PJ2BOOL(prm.ice_cfg.enable_ice);
+ natConfig.iceMaxHostCands = prm.ice_cfg.ice_max_host_cands;
+ natConfig.iceAggressiveNomination = PJ2BOOL(prm.ice_cfg.ice_opt.aggressive);
+ natConfig.iceNominatedCheckDelayMsec = prm.ice_cfg.ice_opt.nominated_check_delay;
+ natConfig.iceWaitNominationTimeoutMsec = prm.ice_cfg.ice_opt.controlled_agent_want_nom_timeout;
+ natConfig.iceNoRtcp = PJ2BOOL(prm.ice_cfg.ice_no_rtcp);
+ natConfig.iceAlwaysUpdate = PJ2BOOL(prm.ice_cfg.ice_always_update);
+ } else {
+ pjsua_media_config default_mcfg;
+ if (!mcfg) {
+ pjsua_media_config_default(&default_mcfg);
+ mcfg = &default_mcfg;
+ }
+ natConfig.iceEnabled = PJ2BOOL(mcfg->enable_ice);
+ natConfig.iceMaxHostCands= mcfg->ice_max_host_cands;
+ natConfig.iceAggressiveNomination = PJ2BOOL(mcfg->ice_opt.aggressive);
+ natConfig.iceNominatedCheckDelayMsec = mcfg->ice_opt.nominated_check_delay;
+ natConfig.iceWaitNominationTimeoutMsec = mcfg->ice_opt.controlled_agent_want_nom_timeout;
+ natConfig.iceNoRtcp = PJ2BOOL(mcfg->ice_no_rtcp);
+ natConfig.iceAlwaysUpdate = PJ2BOOL(mcfg->ice_always_update);
+ }
+
+ if (prm.turn_cfg_use == PJSUA_TURN_CONFIG_USE_CUSTOM) {
+ natConfig.turnEnabled = PJ2BOOL(prm.turn_cfg.enable_turn);
+ natConfig.turnServer = pj2Str(prm.turn_cfg.turn_server);
+ natConfig.turnConnType = prm.turn_cfg.turn_conn_type;
+ natConfig.turnUserName = pj2Str(prm.turn_cfg.turn_auth_cred.data.static_cred.username);
+ natConfig.turnPasswordType = prm.turn_cfg.turn_auth_cred.data.static_cred.data_type;
+ natConfig.turnPassword = pj2Str(prm.turn_cfg.turn_auth_cred.data.static_cred.data);
+ } else {
+ pjsua_media_config default_mcfg;
+ if (!mcfg) {
+ pjsua_media_config_default(&default_mcfg);
+ mcfg = &default_mcfg;
+ }
+ natConfig.turnEnabled = PJ2BOOL(mcfg->enable_turn);
+ natConfig.turnServer = pj2Str(mcfg->turn_server);
+ natConfig.turnConnType = mcfg->turn_conn_type;
+ natConfig.turnUserName = pj2Str(mcfg->turn_auth_cred.data.static_cred.username);
+ natConfig.turnPasswordType = mcfg->turn_auth_cred.data.static_cred.data_type;
+ natConfig.turnPassword = pj2Str(mcfg->turn_auth_cred.data.static_cred.data);
+ }
+ natConfig.contactRewriteUse = prm.allow_contact_rewrite;
+ natConfig.contactRewriteMethod = prm.contact_rewrite_method;
+ natConfig.viaRewriteUse = prm.allow_via_rewrite;
+ natConfig.sdpNatRewriteUse = prm.allow_sdp_nat_rewrite;
+ natConfig.sipOutboundUse = prm.use_rfc5626;
+ natConfig.sipOutboundInstanceId = pj2Str(prm.rfc5626_instance_id);
+ natConfig.sipOutboundRegId = pj2Str(prm.rfc5626_reg_id);
+ natConfig.udpKaIntervalSec = prm.ka_interval;
+ natConfig.udpKaData = pj2Str(prm.ka_data);
+
+ // AccountMediaConfig
+ mediaConfig.transportConfig.fromPj(prm.rtp_cfg);
+ mediaConfig.lockCodecEnabled= PJ2BOOL(prm.lock_codec);
+#if defined(PJMEDIA_STREAM_ENABLE_KA) && (PJMEDIA_STREAM_ENABLE_KA != 0)
+ mediaConfig.streamKaEnabled = PJ2BOOL(prm.use_stream_ka);
+#else
+ mediaConfig.streamKaEnabled = false;
+#endif
+ mediaConfig.srtpUse = prm.use_srtp;
+ mediaConfig.srtpSecureSignaling = prm.srtp_secure_signaling;
+ mediaConfig.ipv6Use = prm.ipv6_media_use;
+
+ // AccountVideoConfig
+ videoConfig.autoShowIncoming = PJ2BOOL(prm.vid_in_auto_show);
+ videoConfig.autoTransmitOutgoing = PJ2BOOL(prm.vid_out_auto_transmit);
+ videoConfig.windowFlags = prm.vid_wnd_flags;
+ videoConfig.defaultCaptureDevice = prm.vid_cap_dev;
+ videoConfig.defaultRenderDevice = prm.vid_rend_dev;
+ videoConfig.rateControlMethod = prm.vid_stream_rc_cfg.method;
+ videoConfig.rateControlBandwidth = prm.vid_stream_rc_cfg.bandwidth;
+}
+
+void AccountConfig::readObject(const ContainerNode &node) throw(Error)
+{
+ ContainerNode this_node = node.readContainer("AccountConfig");
+
+ NODE_READ_INT ( this_node, priority);
+ NODE_READ_STRING ( this_node, idUri);
+ NODE_READ_OBJ ( this_node, regConfig);
+ NODE_READ_OBJ ( this_node, sipConfig);
+ NODE_READ_OBJ ( this_node, callConfig);
+ NODE_READ_OBJ ( this_node, presConfig);
+ NODE_READ_OBJ ( this_node, mwiConfig);
+ NODE_READ_OBJ ( this_node, natConfig);
+ NODE_READ_OBJ ( this_node, mediaConfig);
+ NODE_READ_OBJ ( this_node, videoConfig);
+}
+
+void AccountConfig::writeObject(ContainerNode &node) const throw(Error)
+{
+ ContainerNode this_node = node.writeNewContainer("AccountConfig");
+
+ NODE_WRITE_INT ( this_node, priority);
+ NODE_WRITE_STRING ( this_node, idUri);
+ NODE_WRITE_OBJ ( this_node, regConfig);
+ NODE_WRITE_OBJ ( this_node, sipConfig);
+ NODE_WRITE_OBJ ( this_node, callConfig);
+ NODE_WRITE_OBJ ( this_node, presConfig);
+ NODE_WRITE_OBJ ( this_node, mwiConfig);
+ NODE_WRITE_OBJ ( this_node, natConfig);
+ NODE_WRITE_OBJ ( this_node, mediaConfig);
+ NODE_WRITE_OBJ ( this_node, videoConfig);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+void AccountInfo::fromPj(const pjsua_acc_info &pai)
+{
+ id = pai.id;
+ isDefault = pai.is_default != 0;
+ uri = pj2Str(pai.acc_uri);
+ regIsConfigured = pai.has_registration != 0;
+ regIsActive = pai.has_registration && pai.expires > 0 &&
+ (pai.status / 100 == 2);
+ regExpiresSec = pai.expires;
+ regStatus = pai.status;
+ regStatusText = pj2Str(pai.status_text);
+ regLastErr = pai.reg_last_err;
+ onlineStatus = pai.online_status != 0;
+ onlineStatusText = pj2Str(pai.online_status_text);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+Account::Account()
+: id(PJSUA_INVALID_ID)
+{
+}
+
+Account::~Account()
+{
+ /* If this instance is deleted, also delete the corresponding account in
+ * PJSUA library.
+ */
+ if (isValid() && pjsua_get_state() < PJSUA_STATE_CLOSING) {
+ // Cleanup buddies in the buddy list
+ while(buddyList.size() > 0) {
+ Buddy *b = buddyList[0];
+ delete b; /* this will remove itself from the list */
+ }
+
+ pjsua_acc_set_user_data(id, NULL);
+ pjsua_acc_del(id);
+ }
+}
+
+void Account::create(const AccountConfig &acc_cfg,
+ bool make_default) throw(Error)
+{
+ pjsua_acc_config pj_acc_cfg;
+
+ acc_cfg.toPj(pj_acc_cfg);
+ pj_acc_cfg.user_data = (void*)this;
+ PJSUA2_CHECK_EXPR( pjsua_acc_add(&pj_acc_cfg, make_default, &id) );
+}
+
+void Account::modify(const AccountConfig &acc_cfg) throw(Error)
+{
+ pjsua_acc_config pj_acc_cfg;
+
+ acc_cfg.toPj(pj_acc_cfg);
+ pj_acc_cfg.user_data = (void*)this;
+ PJSUA2_CHECK_EXPR( pjsua_acc_modify(id, &pj_acc_cfg) );
+}
+
+bool Account::isValid() const
+{
+ return pjsua_acc_is_valid(id) != 0;
+}
+
+void Account::setDefault() throw(Error)
+{
+ PJSUA2_CHECK_EXPR( pjsua_acc_set_default(id) );
+}
+
+bool Account::isDefault() const
+{
+ return pjsua_acc_get_default() == id;
+}
+
+int Account::getId() const
+{
+ return id;
+}
+
+Account *Account::lookup(int acc_id)
+{
+ return (Account*)pjsua_acc_get_user_data(acc_id);
+}
+
+AccountInfo Account::getInfo() const throw(Error)
+{
+ pjsua_acc_info pj_ai;
+ AccountInfo ai;
+
+ PJSUA2_CHECK_EXPR( pjsua_acc_get_info(id, &pj_ai) );
+ ai.fromPj(pj_ai);
+ return ai;
+}
+
+void Account::setRegistration(bool renew) throw(Error)
+{
+ PJSUA2_CHECK_EXPR( pjsua_acc_set_registration(id, renew) );
+}
+
+void
+Account::setOnlineStatus(const PresenceStatus &pres_st) throw(Error)
+{
+ pjrpid_element pj_rpid;
+
+ pj_bzero(&pj_rpid, sizeof(pj_rpid));
+ pj_rpid.type = PJRPID_ELEMENT_TYPE_PERSON;
+ pj_rpid.activity = pres_st.activity;
+ pj_rpid.id = str2Pj(pres_st.rpidId);
+ pj_rpid.note = str2Pj(pres_st.note);
+
+ PJSUA2_CHECK_EXPR( pjsua_acc_set_online_status2(
+ id, pres_st.status == PJSUA_BUDDY_STATUS_ONLINE,
+ &pj_rpid) );
+}
+
+void Account::setTransport(TransportId tp_id) throw(Error)
+{
+ PJSUA2_CHECK_EXPR( pjsua_acc_set_transport(id, tp_id) );
+}
+
+void Account::presNotify(const PresNotifyParam &prm) throw(Error)
+{
+ pj_str_t pj_state_str = str2Pj(prm.stateStr);
+ pj_str_t pj_reason = str2Pj(prm.reason);
+ pjsua_msg_data msg_data;
+ prm.txOption.toPj(msg_data);
+
+ PJSUA2_CHECK_EXPR( pjsua_pres_notify(id, (pjsua_srv_pres*)prm.srvPres,
+ prm.state, &pj_state_str,
+ &pj_reason, prm.withBody,
+ &msg_data) );
+}
+
+const BuddyVector& Account::enumBuddies() const throw(Error)
+{
+ return buddyList;
+}
+
+Buddy* Account::findBuddy(string uri, FindBuddyMatch *buddy_match) const
+ throw(Error)
+{
+ if (!buddy_match) {
+ static FindBuddyMatch def_bm;
+ buddy_match = &def_bm;
+ }
+
+ for (unsigned i = 0; i < buddyList.size(); i++) {
+ if (buddy_match->match(uri, *buddyList[i]))
+ return buddyList[i];
+ }
+ PJSUA2_RAISE_ERROR(PJ_ENOTFOUND);
+}
+
+void Account::addBuddy(Buddy *buddy)
+{
+ pj_assert(buddy);
+
+ buddyList.push_back(buddy);
+}
+
+void Account::removeBuddy(Buddy *buddy)
+{
+ pj_assert(buddy);
+
+ BuddyVector::iterator it;
+ for (it = buddyList.begin(); it != buddyList.end(); it++) {
+ if (*it == buddy) {
+ buddyList.erase(it);
+ return;
+ }
+ }
+
+ pj_assert(!"Bug! Buddy to be removed is not in the buddy list!");
+}
diff --git a/pjsip/src/pjsua2/call.cpp b/pjsip/src/pjsua2/call.cpp
new file mode 100644
index 00000000..69a91829
--- /dev/null
+++ b/pjsip/src/pjsua2/call.cpp
@@ -0,0 +1,719 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2012-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/account.hpp>
+#include <pjsua2/call.hpp>
+#include <pjsua2/endpoint.hpp>
+#include <pj/ctype.h>
+#include "util.hpp"
+
+using namespace pj;
+using namespace std;
+
+#define THIS_FILE "call.cpp"
+
+///////////////////////////////////////////////////////////////////////////////
+
+#define SDP_BUFFER_SIZE 1024
+
+MathStat::MathStat()
+: n(0), max(0), min(0), last(0), mean(0)
+{
+}
+
+void MathStat::fromPj(const pj_math_stat &prm)
+{
+ this->n = prm.n;
+ this->max = prm.max;
+ this->min = prm.min;
+ this->last = prm.last;
+ this->mean = prm.mean;
+}
+
+void RtcpStreamStat::fromPj(const pjmedia_rtcp_stream_stat &prm)
+{
+ this->update.fromPj(prm.update);
+ this->updateCount = prm.update_cnt;
+ this->pkt = (unsigned)prm.pkt;
+ this->bytes = (unsigned)prm.bytes;
+ this->discard = prm.discard;
+ this->loss = prm.loss;
+ this->reorder = prm.loss;
+ this->dup = prm.dup;
+ this->lossPeriodUsec.fromPj(prm.loss_period);
+ this->lossType.burst = prm.loss_type.burst;
+ this->lossType.random = prm.loss_type.random;
+ this->jitterUsec.fromPj(prm.jitter);
+}
+
+void RtcpSdes::fromPj(const pjmedia_rtcp_sdes &prm)
+{
+ this->cname = pj2Str(prm.cname);
+ this->name = pj2Str(prm.name);
+ this->email = pj2Str(prm.email);
+ this->phone = pj2Str(prm.phone);
+ this->loc = pj2Str(prm.loc);
+ this->tool = pj2Str(prm.tool);
+ this->note = pj2Str(prm.note);
+}
+
+void RtcpStat::fromPj(const pjmedia_rtcp_stat &prm)
+{
+ this->start.fromPj(prm.start);
+ this->txStat.fromPj(prm.tx);
+ this->rxStat.fromPj(prm.rx);
+ this->rttUsec.fromPj(prm.rtt);
+ this->rtpTxLastTs = prm.rtp_tx_last_ts;
+ this->rtpTxLastSeq = prm.rtp_tx_last_seq;
+#if defined(PJMEDIA_RTCP_STAT_HAS_IPDV) && PJMEDIA_RTCP_STAT_HAS_IPDV!=0
+ this->rxIpdvUsec.fromPj(prm.rx_ipdv);
+#endif
+#if defined(PJMEDIA_RTCP_STAT_HAS_RAW_JITTER) && \
+ PJMEDIA_RTCP_STAT_HAS_RAW_JITTER!=0
+ this->rxRawJitterUsec.fromPj(prm.rx_raw_jitter);
+#endif
+ this->peerSdes.fromPj(prm.peer_sdes);
+}
+
+void JbufState::fromPj(const pjmedia_jb_state &prm)
+{
+ this->frameSize = prm.frame_size;
+ this->minPrefetch = prm.min_prefetch;
+ this->maxPrefetch = prm.max_prefetch;
+ this->burst = prm.burst;
+ this->prefetch = prm.prefetch;
+ this->size = prm.size;
+ this->avgDelayMsec = prm.avg_delay;
+ this->minDelayMsec = prm.min_delay;
+ this->maxDelayMsec = prm.max_delay;
+ this->devDelayMsec = prm.dev_delay;
+ this->avgBurst = prm.avg_burst;
+ this->lost = prm.lost;
+ this->discard = prm.discard;
+ this->empty = prm.empty;
+}
+
+void SdpSession::fromPj(const pjmedia_sdp_session &sdp)
+{
+ char buf[SDP_BUFFER_SIZE];
+ int len;
+
+ len = pjmedia_sdp_print(&sdp, buf, sizeof(buf));
+ wholeSdp = (len > -1? string(buf, len): "");
+ pjSdpSession = (void *)&sdp;
+}
+
+void MediaEvent::fromPj(const pjmedia_event &ev)
+{
+ type = ev.type;
+ if (type == PJMEDIA_EVENT_FMT_CHANGED) {
+ data.fmtChanged.newWidth = ev.data.fmt_changed.new_fmt.det.vid.size.w;
+ data.fmtChanged.newHeight = ev.data.fmt_changed.new_fmt.det.vid.size.h;
+ }
+ pjMediaEvent = (void *)&ev;
+}
+
+void MediaTransportInfo::fromPj(const pjmedia_transport_info &info)
+{
+ char straddr[PJ_INET6_ADDRSTRLEN+10];
+
+ pj_sockaddr_print(&info.src_rtp_name, straddr, sizeof(straddr), 3);
+ srcRtpName = straddr;
+ pj_sockaddr_print(&info.src_rtcp_name, straddr, sizeof(straddr), 3);
+ srcRtcpName = straddr;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+/* Call Audio Media. */
+class CallAudioMedia : public AudioMedia
+{
+public:
+ /*
+ * Set the conference port identification associated with the
+ * call audio media.
+ */
+ void setPortId(int id);
+};
+
+
+void CallAudioMedia::setPortId(int id)
+{
+ this->id = id;
+}
+
+CallOpParam::CallOpParam(bool useDefaultCallSetting)
+: statusCode(pjsip_status_code(0)), reason(""), options(0)
+{
+ if (useDefaultCallSetting)
+ opt = CallSetting(true);
+}
+
+CallSendRequestParam::CallSendRequestParam()
+: method("")
+{
+}
+
+CallVidSetStreamParam::CallVidSetStreamParam()
+{
+#if PJSUA_HAS_VIDEO
+ pjsua_call_vid_strm_op_param prm;
+
+ pjsua_call_vid_strm_op_param_default(&prm);
+ this->medIdx = prm.med_idx;
+ this->dir = prm.dir;
+ this->capDev = prm.cap_dev;
+#endif
+}
+
+CallSetting::CallSetting(pj_bool_t useDefaultValues)
+{
+ if (useDefaultValues) {
+ pjsua_call_setting setting;
+
+ pjsua_call_setting_default(&setting);
+ fromPj(setting);
+ } else {
+ flag = 0;
+ reqKeyframeMethod = 0;
+ audioCount = 0;
+ videoCount = 0;
+ }
+}
+
+bool CallSetting::isEmpty() const
+{
+ return (flag == 0 && reqKeyframeMethod == 0 && audioCount == 0 &&
+ videoCount == 0);
+}
+
+void CallSetting::fromPj(const pjsua_call_setting &prm)
+{
+ this->flag = prm.flag;
+ this->reqKeyframeMethod = prm.req_keyframe_method;
+ this->audioCount = prm.aud_cnt;
+ this->videoCount = prm.vid_cnt;
+}
+
+pjsua_call_setting CallSetting::toPj() const
+{
+ pjsua_call_setting setting;
+
+ setting.flag = this->flag;
+ setting.req_keyframe_method = this->reqKeyframeMethod;
+ setting.aud_cnt = this->audioCount;
+ setting.vid_cnt = this->videoCount;
+
+ return setting;
+}
+
+
+CallMediaInfo::CallMediaInfo()
+{
+}
+
+void CallMediaInfo::fromPj(const pjsua_call_media_info &prm)
+{
+ this->index = prm.index;
+ this->type = prm.type;
+ this->dir = prm.dir;
+ this->status = prm.status;
+ if (this->type == PJMEDIA_TYPE_AUDIO) {
+ this->audioConfSlot = (int)prm.stream.aud.conf_slot;
+ } else if (this->type == PJMEDIA_TYPE_VIDEO) {
+ this->videoIncomingWindowId = prm.stream.vid.win_in;
+ this->videoCapDev = prm.stream.vid.cap_dev;
+ }
+}
+
+void CallInfo::fromPj(const pjsua_call_info &pci)
+{
+ unsigned mi;
+
+ id = pci.id;
+ role = pci.role;
+ accId = pci.acc_id;
+ localUri = pj2Str(pci.local_info);
+ localContact = pj2Str(pci.local_contact);
+ remoteUri = pj2Str(pci.remote_info);
+ remoteContact = pj2Str(pci.remote_contact);
+ callIdString = pj2Str(pci.call_id);
+ setting.fromPj(pci.setting);
+ state = pci.state;
+ stateText = pj2Str(pci.state_text);
+ lastStatusCode = pci.last_status;
+ lastReason = pj2Str(pci.last_status_text);
+ connectDuration.fromPj(pci.connect_duration);
+ totalDuration.fromPj(pci.total_duration);
+ remOfferer = PJ2BOOL(pci.rem_offerer);
+ remAudioCount = pci.rem_aud_cnt;
+ remVideoCount = pci.rem_vid_cnt;
+
+ for (mi = 0; mi < pci.media_cnt; mi++) {
+ CallMediaInfo med;
+
+ med.fromPj(pci.media[mi]);
+ media.push_back(med);
+ }
+ for (mi = 0; mi < pci.prov_media_cnt; mi++) {
+ CallMediaInfo med;
+
+ med.fromPj(pci.prov_media[mi]);
+ provMedia.push_back(med);
+ }
+}
+
+void StreamInfo::fromPj(const pjsua_stream_info &info)
+{
+ char straddr[PJ_INET6_ADDRSTRLEN+10];
+
+ type = info.type;
+ if (type == PJMEDIA_TYPE_AUDIO) {
+ proto = info.info.aud.proto;
+ dir = info.info.aud.dir;
+ pj_sockaddr_print(&info.info.aud.rem_addr, straddr, sizeof(straddr), 3);
+ remoteRtpAddress = straddr;
+ pj_sockaddr_print(&info.info.aud.rem_rtcp, straddr, sizeof(straddr), 3);
+ remoteRtcpAddress = straddr;
+ txPt = info.info.aud.tx_pt;
+ rxPt = info.info.aud.rx_pt;
+ codecName = pj2Str(info.info.aud.fmt.encoding_name);
+ codecClockRate = info.info.aud.fmt.clock_rate;
+ codecParam = info.info.aud.param;
+ } else if (type == PJMEDIA_TYPE_VIDEO) {
+ proto = info.info.vid.proto;
+ dir = info.info.vid.dir;
+ pj_sockaddr_print(&info.info.vid.rem_addr, straddr, sizeof(straddr), 3);
+ remoteRtpAddress = straddr;
+ pj_sockaddr_print(&info.info.vid.rem_rtcp, straddr, sizeof(straddr), 3);
+ remoteRtcpAddress = straddr;
+ txPt = info.info.vid.tx_pt;
+ rxPt = info.info.vid.rx_pt;
+ codecName = pj2Str(info.info.vid.codec_info.encoding_name);
+ codecClockRate = info.info.vid.codec_info.clock_rate;
+ codecParam = info.info.vid.codec_param;
+ }
+}
+
+void StreamStat::fromPj(const pjsua_stream_stat &prm)
+{
+ rtcp.fromPj(prm.rtcp);
+ jbuf.fromPj(prm.jbuf);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+struct call_param
+{
+ pjsua_msg_data msg_data;
+ pjsua_msg_data *p_msg_data;
+ pjsua_call_setting opt;
+ pjsua_call_setting *p_opt;
+ pj_str_t reason;
+ pj_str_t *p_reason;
+
+public:
+ /**
+ * Default constructors with specified parameters.
+ */
+ call_param(const SipTxOption &tx_option);
+ call_param(const SipTxOption &tx_option, const CallSetting &setting,
+ const string &reason_str);
+};
+
+call_param::call_param(const SipTxOption &tx_option)
+{
+ if (tx_option.isEmpty()) {
+ p_msg_data = NULL;
+ } else {
+ tx_option.toPj(msg_data);
+ p_msg_data = &msg_data;
+ }
+
+ p_opt = NULL;
+ p_reason = NULL;
+}
+
+call_param::call_param(const SipTxOption &tx_option, const CallSetting &setting,
+ const string &reason_str)
+{
+ if (tx_option.isEmpty()) {
+ p_msg_data = NULL;
+ } else {
+ tx_option.toPj(msg_data);
+ p_msg_data = &msg_data;
+ }
+
+ if (setting.isEmpty()) {
+ p_opt = NULL;
+ } else {
+ opt = setting.toPj();
+ p_opt = &opt;
+ }
+
+ reason = str2Pj(reason_str);
+ p_reason = (reason.slen == 0? NULL: &reason);
+}
+
+Call::Call(Account& account, int call_id)
+: acc(account), id(call_id)
+{
+ if (call_id != PJSUA_INVALID_ID)
+ pjsua_call_set_user_data(call_id, this);
+}
+
+Call::~Call()
+{
+ /**
+ * If this instance is deleted, also hangup the corresponding call in
+ * PJSUA library.
+ */
+ if (id != PJSUA_INVALID_ID && pjsua_get_state() < PJSUA_STATE_CLOSING) {
+ pjsua_call_set_user_data(id, NULL);
+ if (isActive()) {
+ CallOpParam prm;
+ hangup(prm);
+ }
+ }
+}
+
+CallInfo Call::getInfo() const throw(Error)
+{
+ pjsua_call_info pj_ci;
+ CallInfo ci;
+
+ PJSUA2_CHECK_EXPR( pjsua_call_get_info(id, &pj_ci) );
+ ci.fromPj(pj_ci);
+ return ci;
+}
+
+bool Call::isActive() const
+{
+ if (id == PJSUA_INVALID_ID)
+ return false;
+
+ return (pjsua_call_is_active(id) != 0);
+}
+
+int Call::getId() const
+{
+ return id;
+}
+
+Call *Call::lookup(int call_id)
+{
+ Call *call = (Call*)pjsua_call_get_user_data(call_id);
+ if (call)
+ call->id = call_id;
+ return call;
+}
+
+bool Call::hasMedia() const
+{
+ return (pjsua_call_has_media(id) != 0);
+}
+
+Media *Call::getMedia(unsigned med_idx) const
+{
+ /* Check if the media index is valid and if the media has a valid port ID */
+ if (med_idx >= medias.size() ||
+ (medias[med_idx] && medias[med_idx]->getType() == PJMEDIA_TYPE_AUDIO &&
+ ((AudioMedia *)medias[med_idx])->getPortId() == PJSUA_INVALID_ID))
+ {
+ return NULL;
+ }
+
+ return medias[med_idx];
+}
+
+pjsip_dialog_cap_status Call::remoteHasCap(int htype,
+ const string &hname,
+ const string &token) const
+{
+ pj_str_t pj_hname = str2Pj(hname);
+ pj_str_t pj_token = str2Pj(token);
+
+ return pjsua_call_remote_has_cap(id, htype,
+ (htype == PJSIP_H_OTHER)? &pj_hname: NULL,
+ &pj_token);
+}
+
+void Call::setUserData(Token user_data)
+{
+ userData = user_data;
+}
+
+Token Call::getUserData() const
+{
+ return userData;
+}
+
+pj_stun_nat_type Call::getRemNatType() throw(Error)
+{
+ pj_stun_nat_type nat;
+
+ PJSUA2_CHECK_EXPR( pjsua_call_get_rem_nat_type(id, &nat) );
+
+ return nat;
+}
+
+void Call::makeCall(const string &dst_uri, const CallOpParam &prm) throw(Error)
+{
+ pj_str_t pj_dst_uri = str2Pj(dst_uri);
+ call_param param(prm.txOption, prm.opt, prm.reason);
+
+ PJSUA2_CHECK_EXPR( pjsua_call_make_call(acc.getId(), &pj_dst_uri,
+ param.p_opt, this,
+ param.p_msg_data, &id) );
+}
+
+void Call::answer(const CallOpParam &prm) throw(Error)
+{
+ call_param param(prm.txOption, prm.opt, prm.reason);
+
+ PJSUA2_CHECK_EXPR( pjsua_call_answer2(id, param.p_opt, prm.statusCode,
+ param.p_reason, param.p_msg_data) );
+}
+
+void Call::hangup(const CallOpParam &prm) throw(Error)
+{
+ call_param param(prm.txOption, prm.opt, prm.reason);
+
+ PJSUA2_CHECK_EXPR( pjsua_call_hangup(id, prm.statusCode, param.p_reason,
+ param.p_msg_data) );
+}
+
+void Call::setHold(const CallOpParam &prm) throw(Error)
+{
+ call_param param(prm.txOption, prm.opt, prm.reason);
+
+ PJSUA2_CHECK_EXPR( pjsua_call_set_hold2(id, prm.options, param.p_msg_data));
+}
+
+void Call::reinvite(const CallOpParam &prm) throw(Error)
+{
+ call_param param(prm.txOption, prm.opt, prm.reason);
+
+ PJSUA2_CHECK_EXPR( pjsua_call_reinvite2(id, param.p_opt, param.p_msg_data));
+}
+
+void Call::update(const CallOpParam &prm) throw(Error)
+{
+ call_param param(prm.txOption, prm.opt, prm.reason);
+
+ PJSUA2_CHECK_EXPR( pjsua_call_update2(id, param.p_opt, param.p_msg_data) );
+}
+
+void Call::xfer(const string &dest, const CallOpParam &prm) throw(Error)
+{
+ call_param param(prm.txOption);
+ pj_str_t pj_dest = str2Pj(dest);
+
+ PJSUA2_CHECK_EXPR( pjsua_call_xfer(id, &pj_dest, param.p_msg_data) );
+}
+
+void Call::xferReplaces(const Call& dest_call,
+ const CallOpParam &prm) throw(Error)
+{
+ call_param param(prm.txOption);
+
+ PJSUA2_CHECK_EXPR(pjsua_call_xfer_replaces(id, dest_call.getId(),
+ prm.options, param.p_msg_data) );
+}
+
+void Call::processRedirect(pjsip_redirect_op cmd) throw(Error)
+{
+ PJSUA2_CHECK_EXPR(pjsua_call_process_redirect(id, cmd));
+}
+
+void Call::dialDtmf(const string &digits) throw(Error)
+{
+ pj_str_t pj_digits = str2Pj(digits);
+
+ PJSUA2_CHECK_EXPR(pjsua_call_dial_dtmf(id, &pj_digits));
+}
+
+void Call::sendInstantMessage(const SendInstantMessageParam& prm)
+ throw(Error)
+{
+ pj_str_t mime_type = str2Pj(prm.contentType);
+ pj_str_t content = str2Pj(prm.content);
+ call_param param(prm.txOption);
+
+ PJSUA2_CHECK_EXPR(pjsua_call_send_im(id, &mime_type, &content,
+ param.p_msg_data, prm.userData) );
+}
+
+void Call::sendTypingIndication(const SendTypingIndicationParam &prm)
+ throw(Error)
+{
+ call_param param(prm.txOption);
+
+ PJSUA2_CHECK_EXPR(pjsua_call_send_typing_ind(id,
+ (prm.isTyping?
+ PJ_TRUE: PJ_FALSE),
+ param.p_msg_data) );
+}
+
+void Call::sendRequest(const CallSendRequestParam &prm) throw(Error)
+{
+ pj_str_t method = str2Pj(prm.method);
+ call_param param(prm.txOption);
+
+ PJSUA2_CHECK_EXPR(pjsua_call_send_request(id, &method, param.p_msg_data) );
+}
+
+string Call::dump(bool with_media, const string indent) throw(Error)
+{
+#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
+ char buffer[1024 * 10];
+#else
+ char buffer[1024 * 3];
+#endif
+
+ PJSUA2_CHECK_EXPR(pjsua_call_dump(id, (with_media? PJ_TRUE: PJ_FALSE),
+ buffer, sizeof(buffer),
+ indent.c_str()));
+
+ return buffer;
+}
+
+int Call::vidGetStreamIdx() const
+{
+#if PJSUA_HAS_VIDEO
+ return pjsua_call_get_vid_stream_idx(id);
+#else
+ return PJSUA_INVALID_ID;
+#endif
+}
+
+bool Call::vidStreamIsRunning(int med_idx, pjmedia_dir dir) const
+{
+#if PJSUA_HAS_VIDEO
+ return pjsua_call_vid_stream_is_running(id, med_idx, dir);
+#else
+ PJ_UNUSED_ARG(med_idx);
+ PJ_UNUSED_ARG(dir);
+ return false;
+#endif
+}
+
+void Call::vidSetStream(pjsua_call_vid_strm_op op,
+ const CallVidSetStreamParam &param) throw(Error)
+{
+#if PJSUA_HAS_VIDEO
+ pjsua_call_vid_strm_op_param prm;
+
+ prm.med_idx = param.medIdx;
+ prm.dir = param.dir;
+ prm.cap_dev = param.capDev;
+ PJSUA2_CHECK_EXPR( pjsua_call_set_vid_strm(id, op, &prm) );
+#else
+ PJ_UNUSED_ARG(op);
+ PJ_UNUSED_ARG(param);
+ PJSUA2_RAISE_ERROR(PJ_EINVALIDOP);
+#endif
+}
+
+StreamInfo Call::getStreamInfo(unsigned med_idx) const throw(Error)
+{
+ pjsua_stream_info pj_si;
+ StreamInfo si;
+
+ PJSUA2_CHECK_EXPR( pjsua_call_get_stream_info(id, med_idx, &pj_si) );
+ si.fromPj(pj_si);
+ return si;
+}
+
+StreamStat Call::getStreamStat(unsigned med_idx) const throw(Error)
+{
+ pjsua_stream_stat pj_ss;
+ StreamStat ss;
+
+ PJSUA2_CHECK_EXPR( pjsua_call_get_stream_stat(id, med_idx, &pj_ss) );
+ ss.fromPj(pj_ss);
+ return ss;
+}
+
+MediaTransportInfo Call::getMedTransportInfo(unsigned med_idx) const
+ throw(Error)
+{
+ pjmedia_transport_info pj_mti;
+ MediaTransportInfo mti;
+
+ PJSUA2_CHECK_EXPR( pjsua_call_get_med_transport_info(id, med_idx,
+ &pj_mti) );
+ mti.fromPj(pj_mti);
+ return mti;
+}
+
+void Call::processMediaUpdate(OnCallMediaStateParam &prm)
+{
+ pjsua_call_info pj_ci;
+ unsigned mi;
+
+ if (pjsua_call_get_info(id, &pj_ci) == PJ_SUCCESS) {
+ for (mi = 0; mi < pj_ci.media_cnt; mi++) {
+ if (mi >= medias.size()) {
+ if (pj_ci.media[mi].type == PJMEDIA_TYPE_AUDIO) {
+ medias.push_back(new CallAudioMedia);
+ } else {
+ medias.push_back(NULL);
+ }
+ }
+
+ if (pj_ci.media[mi].type == PJMEDIA_TYPE_AUDIO) {
+ CallAudioMedia *aud_med = (CallAudioMedia *)medias[mi];
+
+ aud_med->setPortId(pj_ci.media[mi].stream.aud.conf_slot);
+ /* Add media if the conference slot ID is valid. */
+ if (pj_ci.media[mi].stream.aud.conf_slot != PJSUA_INVALID_ID)
+ {
+ Endpoint::instance().mediaAdd((AudioMedia &)*aud_med);
+ } else {
+ Endpoint::instance().mediaRemove((AudioMedia &)*aud_med);
+ }
+ }
+ }
+ }
+
+ /* Call media state callback. */
+ onCallMediaState(prm);
+}
+
+void Call::processStateChange(OnCallStateParam &prm)
+{
+ pjsua_call_info pj_ci;
+ unsigned mi;
+
+ if (pjsua_call_get_info(id, &pj_ci) == PJ_SUCCESS &&
+ pj_ci.state == PJSIP_INV_STATE_DISCONNECTED)
+ {
+ /* Clear medias. */
+ for (mi = 0; mi < medias.size(); mi++) {
+ if (medias[mi])
+ delete medias[mi];
+ }
+ medias.clear();
+ }
+
+ onCallState(prm);
+ /* If the state is DISCONNECTED, this call may have already been deleted
+ * by the application in the callback, so do not access it anymore here.
+ */
+}
diff --git a/pjsip/src/pjsua2/endpoint.cpp b/pjsip/src/pjsua2/endpoint.cpp
new file mode 100644
index 00000000..d3ba3719
--- /dev/null
+++ b/pjsip/src/pjsua2/endpoint.cpp
@@ -0,0 +1,1612 @@
+/* $Id$ */
+/*
+ * 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
+ */
+#include <pjsua2/endpoint.hpp>
+#include <pjsua2/account.hpp>
+#include <pjsua2/call.hpp>
+#include <pjsua2/presence.hpp>
+#include <algorithm>
+#include "util.hpp"
+
+using namespace pj;
+using namespace std;
+
+#include <pjsua2/account.hpp>
+#include <pjsua2/call.hpp>
+
+#define THIS_FILE "endpoint.cpp"
+#define MAX_STUN_SERVERS 32
+#define TIMER_SIGNATURE 0x600D878A
+#define MAX_CODEC_NUM 64
+
+struct UserTimer
+{
+ pj_uint32_t signature;
+ OnTimerParam prm;
+ pj_timer_entry entry;
+};
+
+Endpoint *Endpoint::instance_;
+
+///////////////////////////////////////////////////////////////////////////////
+
+UaConfig::UaConfig()
+{
+ pjsua_config ua_cfg;
+
+ pjsua_config_default(&ua_cfg);
+ fromPj(ua_cfg);
+}
+
+void UaConfig::fromPj(const pjsua_config &ua_cfg)
+{
+ unsigned i;
+
+ this->maxCalls = ua_cfg.max_calls;
+ this->threadCnt = ua_cfg.thread_cnt;
+ this->userAgent = pj2Str(ua_cfg.user_agent);
+
+ for (i=0; i<ua_cfg.nameserver_count; ++i) {
+ this->nameserver.push_back(pj2Str(ua_cfg.nameserver[i]));
+ }
+
+ for (i=0; i<ua_cfg.stun_srv_cnt; ++i) {
+ this->stunServer.push_back(pj2Str(ua_cfg.stun_srv[i]));
+ }
+
+ this->stunIgnoreFailure = PJ2BOOL(ua_cfg.stun_ignore_failure);
+ this->natTypeInSdp = ua_cfg.nat_type_in_sdp;
+ this->mwiUnsolicitedEnabled = PJ2BOOL(ua_cfg.enable_unsolicited_mwi);
+}
+
+pjsua_config UaConfig::toPj() const
+{
+ unsigned i;
+ pjsua_config pua_cfg;
+
+ pjsua_config_default(&pua_cfg);
+
+ pua_cfg.max_calls = this->maxCalls;
+ pua_cfg.thread_cnt = this->threadCnt;
+ pua_cfg.user_agent = str2Pj(this->userAgent);
+
+ for (i=0; i<this->nameserver.size() && i<PJ_ARRAY_SIZE(pua_cfg.nameserver);
+ ++i)
+ {
+ pua_cfg.nameserver[i] = str2Pj(this->nameserver[i]);
+ }
+ pua_cfg.nameserver_count = i;
+
+ for (i=0; i<this->stunServer.size() && i<PJ_ARRAY_SIZE(pua_cfg.stun_srv);
+ ++i)
+ {
+ pua_cfg.stun_srv[i] = str2Pj(this->stunServer[i]);
+ }
+ pua_cfg.stun_srv_cnt = i;
+
+ pua_cfg.nat_type_in_sdp = this->natTypeInSdp;
+ pua_cfg.enable_unsolicited_mwi = this->mwiUnsolicitedEnabled;
+
+ return pua_cfg;
+}
+
+void UaConfig::readObject(const ContainerNode &node) throw(Error)
+{
+ ContainerNode this_node = node.readContainer("UaConfig");
+
+ NODE_READ_UNSIGNED( this_node, maxCalls);
+ NODE_READ_UNSIGNED( this_node, threadCnt);
+ NODE_READ_BOOL ( this_node, mainThreadOnly);
+ NODE_READ_STRINGV ( this_node, nameserver);
+ NODE_READ_STRING ( this_node, userAgent);
+ NODE_READ_STRINGV ( this_node, stunServer);
+ NODE_READ_BOOL ( this_node, stunIgnoreFailure);
+ NODE_READ_INT ( this_node, natTypeInSdp);
+ NODE_READ_BOOL ( this_node, mwiUnsolicitedEnabled);
+}
+
+void UaConfig::writeObject(ContainerNode &node) const throw(Error)
+{
+ ContainerNode this_node = node.writeNewContainer("UaConfig");
+
+ NODE_WRITE_UNSIGNED( this_node, maxCalls);
+ NODE_WRITE_UNSIGNED( this_node, threadCnt);
+ NODE_WRITE_BOOL ( this_node, mainThreadOnly);
+ NODE_WRITE_STRINGV ( this_node, nameserver);
+ NODE_WRITE_STRING ( this_node, userAgent);
+ NODE_WRITE_STRINGV ( this_node, stunServer);
+ NODE_WRITE_BOOL ( this_node, stunIgnoreFailure);
+ NODE_WRITE_INT ( this_node, natTypeInSdp);
+ NODE_WRITE_BOOL ( this_node, mwiUnsolicitedEnabled);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+LogConfig::LogConfig()
+{
+ pjsua_logging_config lc;
+
+ pjsua_logging_config_default(&lc);
+ fromPj(lc);
+}
+
+void LogConfig::fromPj(const pjsua_logging_config &lc)
+{
+ this->msgLogging = lc.msg_logging;
+ this->level = lc.level;
+ this->consoleLevel = lc.console_level;
+ this->decor = lc.decor;
+ this->filename = pj2Str(lc.log_filename);
+ this->fileFlags = lc.log_file_flags;
+ this->writer = NULL;
+}
+
+pjsua_logging_config LogConfig::toPj() const
+{
+ pjsua_logging_config lc;
+
+ pjsua_logging_config_default(&lc);
+
+ lc.msg_logging = this->msgLogging;
+ lc.level = this->level;
+ lc.console_level = this->consoleLevel;
+ lc.decor = this->decor;
+ lc.log_file_flags = this->fileFlags;
+ lc.log_filename = str2Pj(this->filename);
+
+ return lc;
+}
+
+void LogConfig::readObject(const ContainerNode &node) throw(Error)
+{
+ ContainerNode this_node = node.readContainer("LogConfig");
+
+ NODE_READ_UNSIGNED( this_node, msgLogging);
+ NODE_READ_UNSIGNED( this_node, level);
+ NODE_READ_UNSIGNED( this_node, consoleLevel);
+ NODE_READ_UNSIGNED( this_node, decor);
+ NODE_READ_STRING ( this_node, filename);
+ NODE_READ_UNSIGNED( this_node, fileFlags);
+}
+
+void LogConfig::writeObject(ContainerNode &node) const throw(Error)
+{
+ ContainerNode this_node = node.writeNewContainer("LogConfig");
+
+ NODE_WRITE_UNSIGNED( this_node, msgLogging);
+ NODE_WRITE_UNSIGNED( this_node, level);
+ NODE_WRITE_UNSIGNED( this_node, consoleLevel);
+ NODE_WRITE_UNSIGNED( this_node, decor);
+ NODE_WRITE_STRING ( this_node, filename);
+ NODE_WRITE_UNSIGNED( this_node, fileFlags);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+MediaConfig::MediaConfig()
+{
+ pjsua_media_config mc;
+
+ pjsua_media_config_default(&mc);
+ fromPj(mc);
+}
+
+void MediaConfig::fromPj(const pjsua_media_config &mc)
+{
+ this->clockRate = mc.clock_rate;
+ this->sndClockRate = mc.snd_clock_rate;
+ this->channelCount = mc.channel_count;
+ this->audioFramePtime = mc.audio_frame_ptime;
+ this->maxMediaPorts = mc.max_media_ports;
+ this->hasIoqueue = PJ2BOOL(mc.has_ioqueue);
+ this->threadCnt = mc.thread_cnt;
+ this->quality = mc.quality;
+ this->ptime = mc.ptime;
+ this->noVad = PJ2BOOL(mc.no_vad);
+ this->ilbcMode = mc.ilbc_mode;
+ this->txDropPct = mc.tx_drop_pct;
+ this->rxDropPct = mc.rx_drop_pct;
+ this->ecOptions = mc.ec_options;
+ this->ecTailLen = mc.ec_tail_len;
+ this->sndRecLatency = mc.snd_rec_latency;
+ this->sndPlayLatency = mc.snd_play_latency;
+ this->jbInit = mc.jb_init;
+ this->jbMinPre = mc.jb_min_pre;
+ this->jbMaxPre = mc.jb_max_pre;
+ this->jbMax = mc.jb_max;
+ this->sndAutoCloseTime = mc.snd_auto_close_time;
+ this->vidPreviewEnableNative = PJ2BOOL(mc.vid_preview_enable_native);
+}
+
+pjsua_media_config MediaConfig::toPj() const
+{
+ pjsua_media_config mcfg;
+
+ pjsua_media_config_default(&mcfg);
+
+ mcfg.clock_rate = this->clockRate;
+ mcfg.snd_clock_rate = this->sndClockRate;
+ mcfg.channel_count = this->channelCount;
+ mcfg.audio_frame_ptime = this->audioFramePtime;
+ mcfg.max_media_ports = this->maxMediaPorts;
+ mcfg.has_ioqueue = this->hasIoqueue;
+ mcfg.thread_cnt = this->threadCnt;
+ mcfg.quality = this->quality;
+ mcfg.ptime = this->ptime;
+ mcfg.no_vad = this->noVad;
+ mcfg.ilbc_mode = this->ilbcMode;
+ mcfg.tx_drop_pct = this->txDropPct;
+ mcfg.rx_drop_pct = this->rxDropPct;
+ mcfg.ec_options = this->ecOptions;
+ mcfg.ec_tail_len = this->ecTailLen;
+ mcfg.snd_rec_latency = this->sndRecLatency;
+ mcfg.snd_play_latency = this->sndPlayLatency;
+ mcfg.jb_init = this->jbInit;
+ mcfg.jb_min_pre = this->jbMinPre;
+ mcfg.jb_max_pre = this->jbMaxPre;
+ mcfg.jb_max = this->jbMax;
+ mcfg.snd_auto_close_time = this->sndAutoCloseTime;
+ mcfg.vid_preview_enable_native = this->vidPreviewEnableNative;
+
+ return mcfg;
+}
+
+void MediaConfig::readObject(const ContainerNode &node) throw(Error)
+{
+ ContainerNode this_node = node.readContainer("MediaConfig");
+
+ NODE_READ_UNSIGNED( this_node, clockRate);
+ NODE_READ_UNSIGNED( this_node, sndClockRate);
+ NODE_READ_UNSIGNED( this_node, channelCount);
+ NODE_READ_UNSIGNED( this_node, audioFramePtime);
+ NODE_READ_UNSIGNED( this_node, maxMediaPorts);
+ NODE_READ_BOOL ( this_node, hasIoqueue);
+ NODE_READ_UNSIGNED( this_node, threadCnt);
+ NODE_READ_UNSIGNED( this_node, quality);
+ NODE_READ_UNSIGNED( this_node, ptime);
+ NODE_READ_BOOL ( this_node, noVad);
+ NODE_READ_UNSIGNED( this_node, ilbcMode);
+ NODE_READ_UNSIGNED( this_node, txDropPct);
+ NODE_READ_UNSIGNED( this_node, rxDropPct);
+ NODE_READ_UNSIGNED( this_node, ecOptions);
+ NODE_READ_UNSIGNED( this_node, ecTailLen);
+ NODE_READ_UNSIGNED( this_node, sndRecLatency);
+ NODE_READ_UNSIGNED( this_node, sndPlayLatency);
+ NODE_READ_INT ( this_node, jbInit);
+ NODE_READ_INT ( this_node, jbMinPre);
+ NODE_READ_INT ( this_node, jbMaxPre);
+ NODE_READ_INT ( this_node, jbMax);
+ NODE_READ_INT ( this_node, sndAutoCloseTime);
+ NODE_READ_BOOL ( this_node, vidPreviewEnableNative);
+}
+
+void MediaConfig::writeObject(ContainerNode &node) const throw(Error)
+{
+ ContainerNode this_node = node.writeNewContainer("MediaConfig");
+
+ NODE_WRITE_UNSIGNED( this_node, clockRate);
+ NODE_WRITE_UNSIGNED( this_node, sndClockRate);
+ NODE_WRITE_UNSIGNED( this_node, channelCount);
+ NODE_WRITE_UNSIGNED( this_node, audioFramePtime);
+ NODE_WRITE_UNSIGNED( this_node, maxMediaPorts);
+ NODE_WRITE_BOOL ( this_node, hasIoqueue);
+ NODE_WRITE_UNSIGNED( this_node, threadCnt);
+ NODE_WRITE_UNSIGNED( this_node, quality);
+ NODE_WRITE_UNSIGNED( this_node, ptime);
+ NODE_WRITE_BOOL ( this_node, noVad);
+ NODE_WRITE_UNSIGNED( this_node, ilbcMode);
+ NODE_WRITE_UNSIGNED( this_node, txDropPct);
+ NODE_WRITE_UNSIGNED( this_node, rxDropPct);
+ NODE_WRITE_UNSIGNED( this_node, ecOptions);
+ NODE_WRITE_UNSIGNED( this_node, ecTailLen);
+ NODE_WRITE_UNSIGNED( this_node, sndRecLatency);
+ NODE_WRITE_UNSIGNED( this_node, sndPlayLatency);
+ NODE_WRITE_INT ( this_node, jbInit);
+ NODE_WRITE_INT ( this_node, jbMinPre);
+ NODE_WRITE_INT ( this_node, jbMaxPre);
+ NODE_WRITE_INT ( this_node, jbMax);
+ NODE_WRITE_INT ( this_node, sndAutoCloseTime);
+ NODE_WRITE_BOOL ( this_node, vidPreviewEnableNative);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void EpConfig::readObject(const ContainerNode &node) throw(Error)
+{
+ ContainerNode this_node = node.readContainer("EpConfig");
+ NODE_READ_OBJ( this_node, uaConfig);
+ NODE_READ_OBJ( this_node, logConfig);
+ NODE_READ_OBJ( this_node, medConfig);
+}
+
+void EpConfig::writeObject(ContainerNode &node) const throw(Error)
+{
+ ContainerNode this_node = node.writeNewContainer("EpConfig");
+ NODE_WRITE_OBJ( this_node, uaConfig);
+ NODE_WRITE_OBJ( this_node, logConfig);
+ NODE_WRITE_OBJ( this_node, medConfig);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/* Class to post log to main thread */
+struct PendingLog : public PendingJob
+{
+ LogEntry entry;
+ virtual void execute(bool is_pending)
+ {
+ PJ_UNUSED_ARG(is_pending);
+ Endpoint::instance().utilLogWrite(entry);
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * Endpoint instance
+ */
+Endpoint::Endpoint()
+: writer(NULL), mainThreadOnly(false), mainThread(NULL), pendingJobSize(0)
+{
+ if (instance_) {
+ PJSUA2_RAISE_ERROR(PJ_EEXISTS);
+ }
+
+ instance_ = this;
+}
+
+Endpoint& Endpoint::instance() throw(Error)
+{
+ if (!instance_) {
+ PJSUA2_RAISE_ERROR(PJ_ENOTFOUND);
+ }
+ return *instance_;
+}
+
+Endpoint::~Endpoint()
+{
+ while (!pendingJobs.empty()) {
+ delete pendingJobs.front();
+ pendingJobs.pop_front();
+ }
+
+ while(mediaList.size() > 0) {
+ AudioMedia *cur_media = mediaList[0];
+ delete cur_media; /* this will remove itself from the list */
+ }
+
+ clearCodecInfoList();
+
+ try {
+ libDestroy();
+ } catch (Error &err) {
+ // Ignore
+ PJ_UNUSED_ARG(err);
+ }
+
+ instance_ = NULL;
+}
+
+void Endpoint::utilAddPendingJob(PendingJob *job)
+{
+ enum {
+ MAX_PENDING_JOBS = 1024
+ };
+
+ /* See if we can execute immediately */
+ if (!mainThreadOnly || pj_thread_this()==mainThread) {
+ job->execute(false);
+ delete job;
+ return;
+ }
+
+ if (pendingJobSize > MAX_PENDING_JOBS) {
+ enum { NUMBER_TO_DISCARD = 5 };
+
+ pj_enter_critical_section();
+ for (unsigned i=0; i<NUMBER_TO_DISCARD; ++i) {
+ delete pendingJobs.back();
+ pendingJobs.pop_back();
+ }
+
+ pendingJobSize -= NUMBER_TO_DISCARD;
+ pj_leave_critical_section();
+
+ utilLogWrite(1, THIS_FILE,
+ "*** ERROR: Job queue full!! Jobs discarded!!! ***");
+ }
+
+ pj_enter_critical_section();
+ pendingJobs.push_back(job);
+ pendingJobSize++;
+ pj_leave_critical_section();
+}
+
+/* Handle log callback */
+void Endpoint::utilLogWrite(LogEntry &entry)
+{
+ if (mainThreadOnly && pj_thread_this() != mainThread) {
+ PendingLog *job = new PendingLog;
+ job->entry = entry;
+ utilAddPendingJob(job);
+ } else {
+ writer->write(entry);
+ }
+}
+
+/* Run pending jobs only in main thread */
+void Endpoint::performPendingJobs()
+{
+ if (pj_thread_this() != mainThread)
+ return;
+
+ if (pendingJobSize == 0)
+ return;
+
+ for (;;) {
+ PendingJob *job = NULL;
+
+ pj_enter_critical_section();
+ if (pendingJobSize != 0) {
+ job = pendingJobs.front();
+ pendingJobs.pop_front();
+ pendingJobSize--;
+ }
+ pj_leave_critical_section();
+
+ if (job) {
+ job->execute(true);
+ delete job;
+ } else
+ break;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * Endpoint static callbacks
+ */
+void Endpoint::logFunc(int level, const char *data, int len)
+{
+ Endpoint &ep = Endpoint::instance();
+
+ if (!ep.writer)
+ return;
+
+ LogEntry entry;
+ entry.level = level;
+ entry.msg = string(data, len);
+ entry.threadId = (long)pj_thread_this();
+ entry.threadName = string(pj_thread_get_name(pj_thread_this()));
+
+ ep.utilLogWrite(entry);
+}
+
+void Endpoint::stun_resolve_cb(const pj_stun_resolve_result *res)
+{
+ Endpoint &ep = Endpoint::instance();
+
+ if (!res)
+ return;
+
+ OnNatCheckStunServersCompleteParam prm;
+
+ prm.userData = res->token;
+ prm.status = res->status;
+ if (res->status == PJ_SUCCESS) {
+ char straddr[PJ_INET6_ADDRSTRLEN+10];
+
+ prm.name = string(res->name.ptr, res->name.slen);
+ pj_sockaddr_print(&res->addr, straddr, sizeof(straddr), 3);
+ prm.addr = straddr;
+ }
+
+ ep.onNatCheckStunServersComplete(prm);
+}
+
+void Endpoint::on_timer(pj_timer_heap_t *timer_heap,
+ pj_timer_entry *entry)
+{
+ PJ_UNUSED_ARG(timer_heap);
+
+ Endpoint &ep = Endpoint::instance();
+ UserTimer *ut = (UserTimer*) entry->user_data;
+
+ if (ut->signature != TIMER_SIGNATURE)
+ return;
+
+ ep.onTimer(ut->prm);
+}
+
+void Endpoint::on_nat_detect(const pj_stun_nat_detect_result *res)
+{
+ Endpoint &ep = Endpoint::instance();
+
+ if (!res)
+ return;
+
+ OnNatDetectionCompleteParam prm;
+
+ prm.status = res->status;
+ prm.reason = res->status_text;
+ prm.natType = res->nat_type;
+ prm.natTypeName = res->nat_type_name;
+
+ ep.onNatDetectionComplete(prm);
+}
+
+void Endpoint::on_transport_state( pjsip_transport *tp,
+ pjsip_transport_state state,
+ const pjsip_transport_state_info *info)
+{
+ Endpoint &ep = Endpoint::instance();
+
+ OnTransportStateParam prm;
+
+ prm.hnd = (TransportHandle)tp;
+ prm.state = state;
+ prm.lastError = info ? info->status : PJ_SUCCESS;
+
+ ep.onTransportState(prm);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * Account static callbacks
+ */
+
+Account *Endpoint::lookupAcc(int acc_id, const char *op)
+{
+ Account *acc = Account::lookup(acc_id);
+ if (!acc) {
+ PJ_LOG(1,(THIS_FILE,
+ "Error: cannot find Account instance for account id %d in "
+ "%s", acc_id, op));
+ }
+
+ return acc;
+}
+
+Call *Endpoint::lookupCall(int call_id, const char *op)
+{
+ Call *call = Call::lookup(call_id);
+ if (!call) {
+ PJ_LOG(1,(THIS_FILE,
+ "Error: cannot find Call instance for call id %d in "
+ "%s", call_id, op));
+ }
+
+ return call;
+}
+
+void Endpoint::on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id,
+ pjsip_rx_data *rdata)
+{
+ Account *acc = lookupAcc(acc_id, "on_incoming_call()");
+ if (!acc) {
+ pjsua_call_hangup(call_id, PJSIP_SC_INTERNAL_SERVER_ERROR, NULL, NULL);
+ return;
+ }
+
+ /* call callback */
+ OnIncomingCallParam prm;
+ prm.callId = call_id;
+ prm.rdata.fromPj(*rdata);
+
+ acc->onIncomingCall(prm);
+
+ /* disconnect if callback doesn't handle the call */
+ pjsua_call_info ci;
+
+ pjsua_call_get_info(call_id, &ci);
+ if (!pjsua_call_get_user_data(call_id) &&
+ ci.state != PJSIP_INV_STATE_DISCONNECTED)
+ {
+ pjsua_call_hangup(call_id, PJSIP_SC_INTERNAL_SERVER_ERROR, NULL, NULL);
+ }
+}
+
+void Endpoint::on_reg_started(pjsua_acc_id acc_id, pj_bool_t renew)
+{
+ Account *acc = lookupAcc(acc_id, "on_reg_started()");
+ if (!acc) {
+ return;
+ }
+
+ OnRegStartedParam prm;
+ prm.renew = PJ2BOOL(renew);
+ acc->onRegStarted(prm);
+}
+
+void Endpoint::on_reg_state2(pjsua_acc_id acc_id, pjsua_reg_info *info)
+{
+ Account *acc = lookupAcc(acc_id, "on_reg_state2()");
+ if (!acc) {
+ return;
+ }
+
+ OnRegStateParam prm;
+ prm.status = info->cbparam->status;
+ prm.code = (pjsip_status_code) info->cbparam->code;
+ prm.reason = pj2Str(info->cbparam->reason);
+ if (info->cbparam->rdata)
+ prm.rdata.fromPj(*info->cbparam->rdata);
+ prm.expiration = info->cbparam->expiration;
+
+ acc->onRegState(prm);
+}
+
+void Endpoint::on_incoming_subscribe(pjsua_acc_id acc_id,
+ pjsua_srv_pres *srv_pres,
+ pjsua_buddy_id buddy_id,
+ const pj_str_t *from,
+ pjsip_rx_data *rdata,
+ pjsip_status_code *code,
+ pj_str_t *reason,
+ pjsua_msg_data *msg_data)
+{
+ PJ_UNUSED_ARG(buddy_id);
+ PJ_UNUSED_ARG(srv_pres);
+
+ Account *acc = lookupAcc(acc_id, "on_incoming_subscribe()");
+ if (!acc) {
+ /* default behavior should apply */
+ return;
+ }
+
+ OnIncomingSubscribeParam prm;
+ prm.srvPres = srv_pres;
+ prm.fromUri = pj2Str(*from);
+ prm.rdata.fromPj(*rdata);
+ prm.code = *code;
+ prm.reason = pj2Str(*reason);
+ prm.txOption.fromPj(*msg_data);
+
+ acc->onIncomingSubscribe(prm);
+
+ *code = prm.code;
+ acc->tmpReason = prm.reason;
+ *reason = str2Pj(acc->tmpReason);
+ prm.txOption.toPj(*msg_data);
+}
+
+void Endpoint::on_pager2(pjsua_call_id call_id,
+ const pj_str_t *from,
+ const pj_str_t *to,
+ const pj_str_t *contact,
+ const pj_str_t *mime_type,
+ const pj_str_t *body,
+ pjsip_rx_data *rdata,
+ pjsua_acc_id acc_id)
+{
+ OnInstantMessageParam prm;
+ prm.fromUri = pj2Str(*from);
+ prm.toUri = pj2Str(*to);
+ prm.contactUri = pj2Str(*contact);
+ prm.contentType = pj2Str(*mime_type);
+ prm.msgBody = pj2Str(*body);
+ prm.rdata.fromPj(*rdata);
+
+ if (call_id != PJSUA_INVALID_ID) {
+ Call *call = lookupCall(call_id, "on_pager2()");
+ if (!call) {
+ /* Ignored */
+ return;
+ }
+
+ call->onInstantMessage(prm);
+ } else {
+ Account *acc = lookupAcc(acc_id, "on_pager2()");
+ if (!acc) {
+ /* Ignored */
+ return;
+ }
+
+ acc->onInstantMessage(prm);
+ }
+}
+
+void Endpoint::on_pager_status2( pjsua_call_id call_id,
+ const pj_str_t *to,
+ const pj_str_t *body,
+ void *user_data,
+ pjsip_status_code status,
+ const pj_str_t *reason,
+ pjsip_tx_data *tdata,
+ pjsip_rx_data *rdata,
+ pjsua_acc_id acc_id)
+{
+ PJ_UNUSED_ARG(tdata);
+
+ OnInstantMessageStatusParam prm;
+ prm.userData = user_data;
+ prm.toUri = pj2Str(*to);
+ prm.msgBody = pj2Str(*body);
+ prm.code = status;
+ prm.reason = pj2Str(*reason);
+ if (rdata)
+ prm.rdata.fromPj(*rdata);
+
+ if (call_id != PJSUA_INVALID_ID) {
+ Call *call = lookupCall(call_id, "on_pager_status2()");
+ if (!call) {
+ /* Ignored */
+ return;
+ }
+
+ call->onInstantMessageStatus(prm);
+ } else {
+ Account *acc = lookupAcc(acc_id, "on_pager_status2()");
+ if (!acc) {
+ /* Ignored */
+ return;
+ }
+
+ acc->onInstantMessageStatus(prm);
+ }
+}
+
+void Endpoint::on_typing2( pjsua_call_id call_id,
+ const pj_str_t *from,
+ const pj_str_t *to,
+ const pj_str_t *contact,
+ pj_bool_t is_typing,
+ pjsip_rx_data *rdata,
+ pjsua_acc_id acc_id)
+{
+ OnTypingIndicationParam prm;
+ prm.fromUri = pj2Str(*from);
+ prm.toUri = pj2Str(*to);
+ prm.contactUri = pj2Str(*contact);
+ prm.isTyping = is_typing != 0;
+ prm.rdata.fromPj(*rdata);
+
+ if (call_id != PJSUA_INVALID_ID) {
+ Call *call = lookupCall(call_id, "on_typing2()");
+ if (!call) {
+ /* Ignored */
+ return;
+ }
+
+ call->onTypingIndication(prm);
+ } else {
+ Account *acc = lookupAcc(acc_id, "on_typing2()");
+ if (!acc) {
+ /* Ignored */
+ return;
+ }
+
+ acc->onTypingIndication(prm);
+ }
+}
+
+void Endpoint::on_mwi_info(pjsua_acc_id acc_id,
+ pjsua_mwi_info *mwi_info)
+{
+ OnMwiInfoParam prm;
+ prm.state = pjsip_evsub_get_state(mwi_info->evsub);
+ prm.rdata.fromPj(*mwi_info->rdata);
+
+ Account *acc = lookupAcc(acc_id, "on_mwi_info()");
+ if (!acc) {
+ /* Ignored */
+ return;
+ }
+
+ acc->onMwiInfo(prm);
+}
+
+void Endpoint::on_buddy_state(pjsua_buddy_id buddy_id)
+{
+ Buddy *buddy = (Buddy*)pjsua_buddy_get_user_data(buddy_id);
+ if (!buddy || !buddy->isValid()) {
+ /* Ignored */
+ return;
+ }
+
+ buddy->onBuddyState();
+}
+
+// Call callbacks
+void Endpoint::on_call_state(pjsua_call_id call_id, pjsip_event *e)
+{
+ Call *call = Call::lookup(call_id);
+ if (!call) {
+ return;
+ }
+
+ OnCallStateParam prm;
+ prm.e.fromPj(*e);
+
+ call->processStateChange(prm);
+ /* If the state is DISCONNECTED, call may have already been deleted
+ * by the application in the callback, so do not access it anymore here.
+ */
+}
+
+void Endpoint::on_call_tsx_state(pjsua_call_id call_id,
+ pjsip_transaction *tsx,
+ pjsip_event *e)
+{
+ PJ_UNUSED_ARG(tsx);
+
+ Call *call = Call::lookup(call_id);
+ if (!call) {
+ return;
+ }
+
+ OnCallTsxStateParam prm;
+ prm.e.fromPj(*e);
+
+ call->onCallTsxState(prm);
+}
+
+void Endpoint::on_call_media_state(pjsua_call_id call_id)
+{
+ Call *call = Call::lookup(call_id);
+ if (!call) {
+ return;
+ }
+
+ OnCallMediaStateParam prm;
+ call->processMediaUpdate(prm);
+}
+
+void Endpoint::on_call_sdp_created(pjsua_call_id call_id,
+ pjmedia_sdp_session *sdp,
+ pj_pool_t *pool,
+ const pjmedia_sdp_session *rem_sdp)
+{
+ Call *call = Call::lookup(call_id);
+ if (!call) {
+ return;
+ }
+
+ OnCallSdpCreatedParam prm;
+ string orig_sdp;
+
+ prm.sdp.fromPj(*sdp);
+ orig_sdp = prm.sdp.wholeSdp;
+ if (rem_sdp)
+ prm.remSdp.fromPj(*rem_sdp);
+
+ call->onCallSdpCreated(prm);
+
+ /* Check if application modifies the SDP */
+ if (orig_sdp != prm.sdp.wholeSdp) {
+ pjmedia_sdp_parse(pool, (char*)prm.sdp.wholeSdp.c_str(),
+ prm.sdp.wholeSdp.size(), &sdp);
+ }
+}
+
+void Endpoint::on_stream_created(pjsua_call_id call_id,
+ pjmedia_stream *strm,
+ unsigned stream_idx,
+ pjmedia_port **p_port)
+{
+ Call *call = Call::lookup(call_id);
+ if (!call) {
+ return;
+ }
+
+ OnStreamCreatedParam prm;
+ prm.stream = strm;
+ prm.streamIdx = stream_idx;
+ prm.pPort = (void *)*p_port;
+
+ call->onStreamCreated(prm);
+
+ if (prm.pPort != (void *)*p_port)
+ *p_port = (pjmedia_port *)prm.pPort;
+}
+
+void Endpoint::on_stream_destroyed(pjsua_call_id call_id,
+ pjmedia_stream *strm,
+ unsigned stream_idx)
+{
+ Call *call = Call::lookup(call_id);
+ if (!call) {
+ return;
+ }
+
+ OnStreamDestroyedParam prm;
+ prm.stream = strm;
+ prm.streamIdx = stream_idx;
+
+ call->onStreamDestroyed(prm);
+}
+
+struct PendingOnDtmfDigitCallback : public PendingJob
+{
+ int call_id;
+ OnDtmfDigitParam prm;
+
+ virtual void execute(bool is_pending)
+ {
+ PJ_UNUSED_ARG(is_pending);
+
+ Call *call = Call::lookup(call_id);
+ if (!call)
+ return;
+
+ call->onDtmfDigit(prm);
+ }
+};
+
+void Endpoint::on_dtmf_digit(pjsua_call_id call_id, int digit)
+{
+ Call *call = Call::lookup(call_id);
+ if (!call) {
+ return;
+ }
+
+ PendingOnDtmfDigitCallback *job = new PendingOnDtmfDigitCallback;
+ job->call_id = call_id;
+ char buf[10];
+ pj_ansi_sprintf(buf, "%c", digit);
+ job->prm.digit = (string)buf;
+
+ Endpoint::instance().utilAddPendingJob(job);
+}
+
+void Endpoint::on_call_transfer_request2(pjsua_call_id call_id,
+ const pj_str_t *dst,
+ pjsip_status_code *code,
+ pjsua_call_setting *opt)
+{
+ Call *call = Call::lookup(call_id);
+ if (!call) {
+ return;
+ }
+
+ OnCallTransferRequestParam prm;
+ prm.dstUri = pj2Str(*dst);
+ prm.statusCode = *code;
+ prm.opt.fromPj(*opt);
+
+ call->onCallTransferRequest(prm);
+
+ *code = prm.statusCode;
+ *opt = prm.opt.toPj();
+}
+
+void Endpoint::on_call_transfer_status(pjsua_call_id call_id,
+ int st_code,
+ const pj_str_t *st_text,
+ pj_bool_t final,
+ pj_bool_t *p_cont)
+{
+ Call *call = Call::lookup(call_id);
+ if (!call) {
+ return;
+ }
+
+ OnCallTransferStatusParam prm;
+ prm.statusCode = (pjsip_status_code)st_code;
+ prm.reason = pj2Str(*st_text);
+ prm.finalNotify = PJ2BOOL(final);
+ prm.cont = PJ2BOOL(*p_cont);
+
+ call->onCallTransferStatus(prm);
+
+ *p_cont = prm.cont;
+}
+
+void Endpoint::on_call_replace_request2(pjsua_call_id call_id,
+ pjsip_rx_data *rdata,
+ int *st_code,
+ pj_str_t *st_text,
+ pjsua_call_setting *opt)
+{
+ Call *call = Call::lookup(call_id);
+ if (!call) {
+ return;
+ }
+
+ OnCallReplaceRequestParam prm;
+ prm.rdata.fromPj(*rdata);
+ prm.statusCode = (pjsip_status_code)*st_code;
+ prm.reason = pj2Str(*st_text);
+ prm.opt.fromPj(*opt);
+
+ call->onCallReplaceRequest(prm);
+
+ *st_code = prm.statusCode;
+ *st_text = str2Pj(prm.reason);
+ *opt = prm.opt.toPj();
+}
+
+void Endpoint::on_call_replaced(pjsua_call_id old_call_id,
+ pjsua_call_id new_call_id)
+{
+ Call *call = Call::lookup(old_call_id);
+ if (!call) {
+ return;
+ }
+
+ OnCallReplacedParam prm;
+ prm.newCallId = new_call_id;
+
+ call->onCallReplaced(prm);
+}
+
+void Endpoint::on_call_rx_offer(pjsua_call_id call_id,
+ const pjmedia_sdp_session *offer,
+ void *reserved,
+ pjsip_status_code *code,
+ pjsua_call_setting *opt)
+{
+ PJ_UNUSED_ARG(reserved);
+
+ Call *call = Call::lookup(call_id);
+ if (!call) {
+ return;
+ }
+
+ OnCallRxOfferParam prm;
+ prm.offer.fromPj(*offer);
+ prm.statusCode = *code;
+ prm.opt.fromPj(*opt);
+
+ call->onCallRxOffer(prm);
+
+ *code = prm.statusCode;
+ *opt = prm.opt.toPj();
+}
+
+pjsip_redirect_op Endpoint::on_call_redirected(pjsua_call_id call_id,
+ const pjsip_uri *target,
+ const pjsip_event *e)
+{
+ Call *call = Call::lookup(call_id);
+ if (!call) {
+ return PJSIP_REDIRECT_STOP;
+ }
+
+ OnCallRedirectedParam prm;
+ char uristr[PJSIP_MAX_URL_SIZE];
+ int len = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, target, uristr,
+ sizeof(uristr));
+ if (len < 1) {
+ pj_ansi_strcpy(uristr, "--URI too long--");
+ }
+ prm.targetUri = string(uristr);
+ if (e)
+ prm.e.fromPj(*e);
+ else
+ prm.e.type = PJSIP_EVENT_UNKNOWN;
+
+ return call->onCallRedirected(prm);
+}
+
+
+struct PendingOnMediaTransportCallback : public PendingJob
+{
+ int call_id;
+ OnCallMediaTransportStateParam prm;
+
+ virtual void execute(bool is_pending)
+ {
+ PJ_UNUSED_ARG(is_pending);
+
+ Call *call = Call::lookup(call_id);
+ if (!call)
+ return;
+
+ call->onCallMediaTransportState(prm);
+ }
+};
+
+pj_status_t
+Endpoint::on_call_media_transport_state(pjsua_call_id call_id,
+ const pjsua_med_tp_state_info *info)
+{
+ Call *call = Call::lookup(call_id);
+ if (!call) {
+ return PJ_SUCCESS;
+ }
+
+ PendingOnMediaTransportCallback *job = new PendingOnMediaTransportCallback;
+
+ job->call_id = call_id;
+ job->prm.medIdx = info->med_idx;
+ job->prm.state = info->state;
+ job->prm.status = info->status;
+ job->prm.sipErrorCode = info->sip_err_code;
+
+ Endpoint::instance().utilAddPendingJob(job);
+
+ return PJ_SUCCESS;
+}
+
+struct PendingOnMediaEventCallback : public PendingJob
+{
+ int call_id;
+ OnCallMediaEventParam prm;
+
+ virtual void execute(bool is_pending)
+ {
+ Call *call = Call::lookup(call_id);
+ if (!call)
+ return;
+
+ if (is_pending) {
+ /* Can't do this anymore, pointer is invalid */
+ prm.ev.pjMediaEvent = NULL;
+ }
+
+ call->onCallMediaEvent(prm);
+ }
+};
+
+void Endpoint::on_call_media_event(pjsua_call_id call_id,
+ unsigned med_idx,
+ pjmedia_event *event)
+{
+ Call *call = Call::lookup(call_id);
+ if (!call) {
+ return;
+ }
+
+ PendingOnMediaEventCallback *job = new PendingOnMediaEventCallback;
+
+ job->call_id = call_id;
+ job->prm.medIdx = med_idx;
+ job->prm.ev.fromPj(*event);
+
+ Endpoint::instance().utilAddPendingJob(job);
+}
+
+pjmedia_transport*
+Endpoint::on_create_media_transport(pjsua_call_id call_id,
+ unsigned media_idx,
+ pjmedia_transport *base_tp,
+ unsigned flags)
+{
+ Call *call = Call::lookup(call_id);
+ if (!call) {
+ return base_tp;
+ }
+
+ OnCreateMediaTransportParam prm;
+ prm.mediaIdx = media_idx;
+ prm.mediaTp = base_tp;
+ prm.flags = flags;
+
+ call->onCreateMediaTransport(prm);
+
+ return (pjmedia_transport *)prm.mediaTp;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * Endpoint library operations
+ */
+Version Endpoint::libVersion() const
+{
+ Version ver;
+ ver.major = PJ_VERSION_NUM_MAJOR;
+ ver.minor = PJ_VERSION_NUM_MINOR;
+ ver.rev = PJ_VERSION_NUM_REV;
+ ver.suffix = PJ_VERSION_NUM_EXTRA;
+ ver.full = pj_get_version();
+ ver.numeric = PJ_VERSION_NUM;
+ return ver;
+}
+
+void Endpoint::libCreate() throw(Error)
+{
+ PJSUA2_CHECK_EXPR( pjsua_create() );
+ mainThread = pj_thread_this();
+}
+
+pjsua_state Endpoint::libGetState() const
+{
+ return pjsua_get_state();
+}
+
+void Endpoint::libInit(const EpConfig &prmEpConfig) throw(Error)
+{
+ pjsua_config ua_cfg;
+ pjsua_logging_config log_cfg;
+ pjsua_media_config med_cfg;
+
+ ua_cfg = prmEpConfig.uaConfig.toPj();
+ log_cfg = prmEpConfig.logConfig.toPj();
+ med_cfg = prmEpConfig.medConfig.toPj();
+
+ /* Setup log callback */
+ if (prmEpConfig.logConfig.writer) {
+ this->writer = prmEpConfig.logConfig.writer;
+ log_cfg.cb = &Endpoint::logFunc;
+ }
+ mainThreadOnly = prmEpConfig.uaConfig.mainThreadOnly;
+
+ /* Setup UA callbacks */
+ pj_bzero(&ua_cfg.cb, sizeof(ua_cfg.cb));
+ ua_cfg.cb.on_nat_detect = &Endpoint::on_nat_detect;
+ ua_cfg.cb.on_transport_state = &Endpoint::on_transport_state;
+
+ ua_cfg.cb.on_incoming_call = &Endpoint::on_incoming_call;
+ ua_cfg.cb.on_reg_started = &Endpoint::on_reg_started;
+ ua_cfg.cb.on_reg_state2 = &Endpoint::on_reg_state2;
+ ua_cfg.cb.on_incoming_subscribe = &Endpoint::on_incoming_subscribe;
+ ua_cfg.cb.on_pager2 = &Endpoint::on_pager2;
+ ua_cfg.cb.on_pager_status2 = &Endpoint::on_pager_status2;
+ ua_cfg.cb.on_typing2 = &Endpoint::on_typing2;
+ ua_cfg.cb.on_mwi_info = &Endpoint::on_mwi_info;
+ ua_cfg.cb.on_buddy_state = &Endpoint::on_buddy_state;
+
+ /* Call callbacks */
+ ua_cfg.cb.on_call_state = &Endpoint::on_call_state;
+ ua_cfg.cb.on_call_tsx_state = &Endpoint::on_call_tsx_state;
+ ua_cfg.cb.on_call_media_state = &Endpoint::on_call_media_state;
+ ua_cfg.cb.on_call_sdp_created = &Endpoint::on_call_sdp_created;
+ ua_cfg.cb.on_stream_created = &Endpoint::on_stream_created;
+ ua_cfg.cb.on_stream_destroyed = &Endpoint::on_stream_destroyed;
+ ua_cfg.cb.on_dtmf_digit = &Endpoint::on_dtmf_digit;
+ ua_cfg.cb.on_call_transfer_request2 = &Endpoint::on_call_transfer_request2;
+ ua_cfg.cb.on_call_transfer_status = &Endpoint::on_call_transfer_status;
+ ua_cfg.cb.on_call_replace_request2 = &Endpoint::on_call_replace_request2;
+ ua_cfg.cb.on_call_replaced = &Endpoint::on_call_replaced;
+ ua_cfg.cb.on_call_rx_offer = &Endpoint::on_call_rx_offer;
+ ua_cfg.cb.on_call_redirected = &Endpoint::on_call_redirected;
+ ua_cfg.cb.on_call_media_transport_state =
+ &Endpoint::on_call_media_transport_state;
+ ua_cfg.cb.on_call_media_event = &Endpoint::on_call_media_event;
+ ua_cfg.cb.on_create_media_transport = &Endpoint::on_create_media_transport;
+
+ /* Init! */
+ PJSUA2_CHECK_EXPR( pjsua_init(&ua_cfg, &log_cfg, &med_cfg) );
+}
+
+void Endpoint::libStart() throw(Error)
+{
+ PJSUA2_CHECK_EXPR(pjsua_start());
+}
+
+void Endpoint::libRegisterWorkerThread(const string &name) throw(Error)
+{
+ PJSUA2_CHECK_EXPR(pjsua_register_worker_thread(name.c_str()));
+}
+
+void Endpoint::libStopWorkerThreads()
+{
+ pjsua_stop_worker_threads();
+}
+
+int Endpoint::libHandleEvents(unsigned msec_timeout)
+{
+ performPendingJobs();
+ return pjsua_handle_events(msec_timeout);
+}
+
+void Endpoint::libDestroy(unsigned flags) throw(Error)
+{
+ pj_status_t status;
+
+ status = pjsua_destroy2(flags);
+
+ delete this->writer;
+ this->writer = NULL;
+
+ if (pj_log_get_log_func() == &Endpoint::logFunc) {
+ pj_log_set_log_func(NULL);
+ }
+
+ PJSUA2_CHECK_RAISE_ERROR(status);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * Endpoint Utilities
+ */
+string Endpoint::utilStrError(pj_status_t prmErr)
+{
+ char errmsg[PJ_ERR_MSG_SIZE];
+ pj_strerror(prmErr, errmsg, sizeof(errmsg));
+ return errmsg;
+}
+
+static void ept_log_write(int level, const char *sender,
+ const char *format, ...)
+{
+ va_list arg;
+ va_start(arg, format);
+ pj_log(sender, level, format, arg );
+ va_end(arg);
+}
+
+void Endpoint::utilLogWrite(int prmLevel,
+ const string &prmSender,
+ const string &prmMsg)
+{
+ ept_log_write(prmLevel, prmSender.c_str(), "%s", prmMsg.c_str());
+}
+
+pj_status_t Endpoint::utilVerifySipUri(const string &prmUri)
+{
+ return pjsua_verify_sip_url(prmUri.c_str());
+}
+
+pj_status_t Endpoint::utilVerifyUri(const string &prmUri)
+{
+ return pjsua_verify_url(prmUri.c_str());
+}
+
+Token Endpoint::utilTimerSchedule(unsigned prmMsecDelay,
+ Token prmUserData) throw (Error)
+{
+ UserTimer *ut;
+ pj_time_val delay;
+ pj_status_t status;
+
+ ut = new UserTimer;
+ ut->signature = TIMER_SIGNATURE;
+ ut->prm.msecDelay = prmMsecDelay;
+ ut->prm.userData = prmUserData;
+ pj_timer_entry_init(&ut->entry, 1, ut, &Endpoint::on_timer);
+
+ delay.sec = 0;
+ delay.msec = prmMsecDelay;
+ pj_time_val_normalize(&delay);
+
+ status = pjsua_schedule_timer(&ut->entry, &delay);
+ if (status != PJ_SUCCESS) {
+ delete ut;
+ PJSUA2_CHECK_RAISE_ERROR(status);
+ }
+
+ return (Token)ut;
+}
+
+void Endpoint::utilTimerCancel(Token prmTimerToken)
+{
+ UserTimer *ut = (UserTimer*)(void*)prmTimerToken;
+
+ if (ut->signature != TIMER_SIGNATURE) {
+ PJ_LOG(1,(THIS_FILE,
+ "Invalid timer token in Endpoint::utilTimerCancel()"));
+ return;
+ }
+
+ ut->entry.id = 0;
+ ut->signature = 0xFFFFFFFE;
+ pjsua_cancel_timer(&ut->entry);
+
+ delete ut;
+}
+
+IntVector Endpoint::utilSslGetAvailableCiphers() throw (Error)
+{
+#if PJ_HAS_SSL_SOCK
+ pj_ssl_cipher ciphers[64];
+ unsigned count = PJ_ARRAY_SIZE(ciphers);
+
+ PJSUA2_CHECK_EXPR( pj_ssl_cipher_get_availables(ciphers, &count) );
+
+ return IntVector(ciphers, ciphers + count);
+#else
+ return IntVector();
+#endif
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * Endpoint NAT operations
+ */
+void Endpoint::natDetectType(void) throw(Error)
+{
+ PJSUA2_CHECK_EXPR( pjsua_detect_nat_type() );
+}
+
+pj_stun_nat_type Endpoint::natGetType() throw(Error)
+{
+ pj_stun_nat_type type;
+
+ PJSUA2_CHECK_EXPR( pjsua_get_nat_type(&type) );
+
+ return type;
+}
+
+void Endpoint::natCheckStunServers(const StringVector &servers,
+ bool wait,
+ Token token) throw(Error)
+{
+ pj_str_t srv[MAX_STUN_SERVERS];
+ unsigned i, count = 0;
+
+ for (i=0; i<servers.size() && i<MAX_STUN_SERVERS; ++i) {
+ srv[count].ptr = (char*)servers[i].c_str();
+ srv[count].slen = servers[i].size();
+ ++count;
+ }
+
+ PJSUA2_CHECK_EXPR(pjsua_resolve_stun_servers(count, srv, wait, token,
+ &Endpoint::stun_resolve_cb) );
+}
+
+void Endpoint::natCancelCheckStunServers(Token token,
+ bool notify_cb) throw(Error)
+{
+ PJSUA2_CHECK_EXPR( pjsua_cancel_stun_resolution(token, notify_cb) );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * Transport API
+ */
+TransportId Endpoint::transportCreate(pjsip_transport_type_e type,
+ const TransportConfig &cfg) throw(Error)
+{
+ pjsua_transport_config tcfg;
+ pjsua_transport_id tid;
+
+ tcfg = cfg.toPj();
+ PJSUA2_CHECK_EXPR( pjsua_transport_create(type,
+ &tcfg, &tid) );
+
+ return tid;
+}
+
+IntVector Endpoint::transportEnum() throw(Error)
+{
+ pjsua_transport_id tids[32];
+ unsigned count = PJ_ARRAY_SIZE(tids);
+
+ PJSUA2_CHECK_EXPR( pjsua_enum_transports(tids, &count) );
+
+ return IntVector(tids, tids+count);
+}
+
+TransportInfo Endpoint::transportGetInfo(TransportId id) throw(Error)
+{
+ pjsua_transport_info pj_tinfo;
+ TransportInfo tinfo;
+
+ PJSUA2_CHECK_EXPR( pjsua_transport_get_info(id, &pj_tinfo) );
+ tinfo.fromPj(pj_tinfo);
+
+ return tinfo;
+}
+
+void Endpoint::transportSetEnable(TransportId id, bool enabled) throw(Error)
+{
+ PJSUA2_CHECK_EXPR( pjsua_transport_set_enable(id, enabled) );
+}
+
+void Endpoint::transportClose(TransportId id) throw(Error)
+{
+ PJSUA2_CHECK_EXPR( pjsua_transport_close(id, PJ_FALSE) );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * Call operations
+ */
+
+void Endpoint::hangupAllCalls(void)
+{
+ pjsua_call_hangup_all();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * Media API
+ */
+unsigned Endpoint::mediaMaxPorts() const
+{
+ return pjsua_conf_get_max_ports();
+}
+
+unsigned Endpoint::mediaActivePorts() const
+{
+ return pjsua_conf_get_active_ports();
+}
+
+const AudioMediaVector &Endpoint::mediaEnumPorts() const throw(Error)
+{
+ return mediaList;
+}
+
+void Endpoint::mediaAdd(AudioMedia &media)
+{
+ if (mediaExists(media))
+ return;
+
+ mediaList.push_back(&media);
+}
+
+void Endpoint::mediaRemove(AudioMedia &media)
+{
+ AudioMediaVector::iterator it = std::find(mediaList.begin(),
+ mediaList.end(),
+ &media);
+
+ if (it != mediaList.end())
+ mediaList.erase(it);
+
+}
+
+bool Endpoint::mediaExists(const AudioMedia &media) const
+{
+ AudioMediaVector::const_iterator it = std::find(mediaList.begin(),
+ mediaList.end(),
+ &media);
+
+ return (it != mediaList.end());
+}
+
+AudDevManager &Endpoint::audDevManager()
+{
+ return audioDevMgr;
+}
+
+/*
+ * Codec operations.
+ */
+const CodecInfoVector &Endpoint::codecEnum() throw(Error)
+{
+ pjsua_codec_info pj_codec[MAX_CODEC_NUM];
+ unsigned count = 0;
+
+ PJSUA2_CHECK_EXPR( pjsua_enum_codecs(pj_codec, &count) );
+
+ pj_enter_critical_section();
+ clearCodecInfoList();
+ for (unsigned i=0;(i<count && i<MAX_CODEC_NUM);++i) {
+ CodecInfo *codec_info = new CodecInfo;
+
+ codec_info->fromPj(pj_codec[i]);
+ codecInfoList.push_back(codec_info);
+ }
+ pj_leave_critical_section();
+ return codecInfoList;
+}
+
+void Endpoint::codecSetPriority(const string &codec_id,
+ pj_uint8_t priority) throw(Error)
+{
+ pj_str_t codec_str = str2Pj(codec_id);
+ PJSUA2_CHECK_EXPR( pjsua_codec_set_priority(&codec_str, priority) );
+}
+
+CodecParam Endpoint::codecGetParam(const string &codec_id) const throw(Error)
+{
+ pjmedia_codec_param *pj_param = NULL;
+ pj_str_t codec_str = str2Pj(codec_id);
+
+ PJSUA2_CHECK_EXPR( pjsua_codec_get_param(&codec_str, pj_param) );
+
+ return pj_param;
+}
+
+void Endpoint::codecSetParam(const string &codec_id,
+ const CodecParam param) throw(Error)
+{
+ pj_str_t codec_str = str2Pj(codec_id);
+ pjmedia_codec_param *pj_param = (pjmedia_codec_param*)param;
+
+ PJSUA2_CHECK_EXPR( pjsua_codec_set_param(&codec_str, pj_param) );
+}
+
+void Endpoint::clearCodecInfoList()
+{
+ for (unsigned i=0;i<codecInfoList.size();++i) {
+ delete codecInfoList[i];
+ }
+ codecInfoList.clear();
+}
diff --git a/pjsip/src/pjsua2/json.cpp b/pjsip/src/pjsua2/json.cpp
new file mode 100644
index 00000000..afa25989
--- /dev/null
+++ b/pjsip/src/pjsua2/json.cpp
@@ -0,0 +1,544 @@
+/* $Id$ */
+/*
+ * 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
+ */
+#include <pjsua2/json.hpp>
+#include <pjlib-util/errno.h>
+#include <pj/file_io.h>
+#include "util.hpp"
+
+#define THIS_FILE "json.cpp"
+
+using namespace pj;
+using namespace std;
+
+/* Json node operations */
+static bool jsonNode_hasUnread(const ContainerNode*);
+static string jsonNode_unreadName(const ContainerNode*n)
+ throw(Error);
+static float jsonNode_readNumber(const ContainerNode*,
+ const string&)
+ throw(Error);
+static bool jsonNode_readBool(const ContainerNode*,
+ const string&)
+ throw(Error);
+static string jsonNode_readString(const ContainerNode*,
+ const string&)
+ throw(Error);
+static StringVector jsonNode_readStringVector(const ContainerNode*,
+ const string&)
+ throw(Error);
+static ContainerNode jsonNode_readContainer(const ContainerNode*,
+ const string &)
+ throw(Error);
+static ContainerNode jsonNode_readArray(const ContainerNode*,
+ const string &)
+ throw(Error);
+static void jsonNode_writeNumber(ContainerNode*,
+ const string &name,
+ float num)
+ throw(Error);
+static void jsonNode_writeBool(ContainerNode*,
+ const string &name,
+ bool value)
+ throw(Error);
+static void jsonNode_writeString(ContainerNode*,
+ const string &name,
+ const string &value)
+ throw(Error);
+static void jsonNode_writeStringVector(ContainerNode*,
+ const string &name,
+ const StringVector &value)
+ throw(Error);
+static ContainerNode jsonNode_writeNewContainer(ContainerNode*,
+ const string &name)
+ throw(Error);
+static ContainerNode jsonNode_writeNewArray(ContainerNode*,
+ const string &name)
+ throw(Error);
+
+static container_node_op json_op =
+{
+ &jsonNode_hasUnread,
+ &jsonNode_unreadName,
+ &jsonNode_readNumber,
+ &jsonNode_readBool,
+ &jsonNode_readString,
+ &jsonNode_readStringVector,
+ &jsonNode_readContainer,
+ &jsonNode_readArray,
+ &jsonNode_writeNumber,
+ &jsonNode_writeBool,
+ &jsonNode_writeString,
+ &jsonNode_writeStringVector,
+ &jsonNode_writeNewContainer,
+ &jsonNode_writeNewArray
+};
+
+///////////////////////////////////////////////////////////////////////////////
+JsonDocument::JsonDocument()
+: root(NULL)
+{
+ pj_caching_pool_init(&cp, NULL, 0);
+ pool = pj_pool_create(&cp.factory, "jsondoc", 512, 512, NULL);
+ if (!pool)
+ PJSUA2_RAISE_ERROR(PJ_ENOMEM);
+}
+
+JsonDocument::~JsonDocument()
+{
+ if (pool)
+ pj_pool_release(pool);
+ pj_caching_pool_destroy(&cp);
+}
+
+void JsonDocument::initRoot() const
+{
+ rootNode.op = &json_op;
+ rootNode.data.doc = (void*)this;
+ rootNode.data.data1 = (void*)root;
+ rootNode.data.data2 = root->value.children.next;
+}
+
+void JsonDocument::loadFile(const string &filename) throw(Error)
+{
+ if (root)
+ PJSUA2_RAISE_ERROR3(PJ_EINVALIDOP, "JsonDocument.loadString()",
+ "Document already initialized");
+
+ if (!pj_file_exists(filename.c_str()))
+ PJSUA2_RAISE_ERROR(PJ_ENOTFOUND);
+
+ pj_ssize_t size = (pj_ssize_t)pj_file_size(filename.c_str());
+ pj_status_t status;
+
+ char *buffer = (char*)pj_pool_alloc(pool, size+1);
+ pj_oshandle_t fd = 0;
+ unsigned parse_size;
+ char err_msg[120];
+ pj_json_err_info err_info;
+
+ err_msg[0] = '\0';
+
+ status = pj_file_open(pool, filename.c_str(), PJ_O_RDONLY, &fd);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ status = pj_file_read(fd, buffer, &size);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ pj_file_close(fd);
+ fd = NULL;
+
+ if (size <= 0) {
+ status = PJ_EEOF;
+ goto on_error;
+ }
+
+ parse_size = (unsigned)size;
+ root = pj_json_parse(pool, buffer, &parse_size, &err_info);
+ if (root == NULL) {
+ pj_ansi_snprintf(err_msg, sizeof(err_msg),
+ "JSON parsing failed: syntax error in file '%s' at "
+ "line %d column %d",
+ filename.c_str(), err_info.line, err_info.col);
+ PJ_LOG(1,(THIS_FILE, err_msg));
+ status = PJLIB_UTIL_EINJSON;
+ goto on_error;
+ }
+
+ initRoot();
+ return;
+
+on_error:
+ if (fd)
+ pj_file_close(fd);
+ if (err_msg[0])
+ PJSUA2_RAISE_ERROR3(status, "loadFile()", err_msg);
+ else
+ PJSUA2_RAISE_ERROR(status);
+}
+
+void JsonDocument::loadString(const string &input) throw(Error)
+{
+ if (root)
+ PJSUA2_RAISE_ERROR3(PJ_EINVALIDOP, "JsonDocument.loadString()",
+ "Document already initialized");
+
+ unsigned size = input.size();
+ char *buffer = (char*)pj_pool_alloc(pool, size+1);
+ unsigned parse_size = (unsigned)size;
+ pj_json_err_info err_info;
+
+ pj_memcpy(buffer, input.c_str(), size);
+
+ root = pj_json_parse(pool, buffer, &parse_size, &err_info);
+ if (root == NULL) {
+ char err_msg[80];
+
+ pj_ansi_snprintf(err_msg, sizeof(err_msg),
+ "JSON parsing failed at line %d column %d",
+ err_info.line, err_info.col);
+ PJ_LOG(1,(THIS_FILE, err_msg));
+ PJSUA2_RAISE_ERROR3(PJLIB_UTIL_EINJSON, "loadString()", err_msg);
+ }
+ initRoot();
+}
+
+struct save_file_data
+{
+ pj_oshandle_t fd;
+};
+
+static pj_status_t json_file_writer(const char *s,
+ unsigned size,
+ void *user_data)
+{
+ save_file_data *sd = (save_file_data*)user_data;
+ pj_ssize_t ssize = (pj_ssize_t)size;
+ return pj_file_write(sd->fd, s, &ssize);
+}
+
+void JsonDocument::saveFile(const string &filename) throw(Error)
+{
+ struct save_file_data sd;
+ pj_status_t status;
+
+ /* Make sure root container has been created */
+ getRootContainer();
+
+ status = pj_file_open(pool, filename.c_str(), PJ_O_WRONLY, &sd.fd);
+ if (status != PJ_SUCCESS)
+ PJSUA2_RAISE_ERROR(status);
+
+ status = pj_json_writef(root, &json_file_writer, &sd.fd);
+ pj_file_close(sd.fd);
+
+ if (status != PJ_SUCCESS)
+ PJSUA2_RAISE_ERROR(status);
+}
+
+struct save_string_data
+{
+ string output;
+};
+
+static pj_status_t json_string_writer(const char *s,
+ unsigned size,
+ void *user_data)
+{
+ save_string_data *sd = (save_string_data*)user_data;
+ sd->output.append(s, size);
+ return PJ_SUCCESS;
+}
+
+string JsonDocument::saveString() throw(Error)
+{
+ struct save_string_data sd;
+ pj_status_t status;
+
+ /* Make sure root container has been created */
+ getRootContainer();
+
+ status = pj_json_writef(root, &json_string_writer, &sd);
+ if (status != PJ_SUCCESS)
+ PJSUA2_RAISE_ERROR(status);
+
+ return sd.output;
+}
+
+ContainerNode & JsonDocument::getRootContainer() const
+{
+ if (!root) {
+ root = allocElement();
+ pj_json_elem_obj(root, NULL);
+ initRoot();
+ }
+
+ return rootNode;
+}
+
+pj_json_elem* JsonDocument::allocElement() const
+{
+ return (pj_json_elem*)pj_pool_alloc(pool, sizeof(pj_json_elem));
+}
+
+pj_pool_t *JsonDocument::getPool()
+{
+ return pool;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+struct json_node_data
+{
+ JsonDocument *doc;
+ pj_json_elem *jnode;
+ pj_json_elem *childPtr;
+};
+
+static bool jsonNode_hasUnread(const ContainerNode *node)
+{
+ json_node_data *jdat = (json_node_data*)&node->data;
+ return jdat->childPtr != (pj_json_elem*)&jdat->jnode->value.children;
+}
+
+static void json_verify(struct json_node_data *jdat,
+ const char *op,
+ const string &name,
+ pj_json_val_type type)
+{
+ if (jdat->childPtr == (pj_json_elem*)&jdat->jnode->value.children)
+ PJSUA2_RAISE_ERROR3(PJ_EEOF, op, "No unread element");
+
+ /* If name is specified, then check if the names match, except
+ * when the node name itself is empty and the parent node is
+ * an array, then ignore the checking (JSON doesn't allow array
+ * elements to have name).
+ */
+ if (name.size() && name.compare(0, name.size(),
+ jdat->childPtr->name.ptr,
+ jdat->childPtr->name.slen) &&
+ jdat->childPtr->name.slen &&
+ jdat->jnode->type != PJ_JSON_VAL_ARRAY)
+ {
+ char err_msg[80];
+ pj_ansi_snprintf(err_msg, sizeof(err_msg),
+ "Name mismatch: expecting '%s' got '%.*s'",
+ name.c_str(), (int)jdat->childPtr->name.slen,
+ jdat->childPtr->name.ptr);
+ PJSUA2_RAISE_ERROR3(PJLIB_UTIL_EINJSON, op, err_msg);
+ }
+
+ if (type != PJ_JSON_VAL_NULL && jdat->childPtr->type != type) {
+ char err_msg[80];
+ pj_ansi_snprintf(err_msg, sizeof(err_msg),
+ "Type mismatch: expecting %d got %d",
+ type, jdat->childPtr->type);
+ PJSUA2_RAISE_ERROR3(PJLIB_UTIL_EINJSON, op, err_msg);
+ }
+}
+
+static string jsonNode_unreadName(const ContainerNode *node)
+ throw(Error)
+{
+ json_node_data *jdat = (json_node_data*)&node->data;
+ json_verify(jdat, "unreadName()", "", PJ_JSON_VAL_NULL);
+ return pj2Str(jdat->childPtr->name);
+}
+
+static float jsonNode_readNumber(const ContainerNode *node,
+ const string &name)
+ throw(Error)
+{
+ json_node_data *jdat = (json_node_data*)&node->data;
+ json_verify(jdat, "readNumber()", name, PJ_JSON_VAL_NUMBER);
+ jdat->childPtr = jdat->childPtr->next;
+ return jdat->childPtr->prev->value.num;
+}
+
+static bool jsonNode_readBool(const ContainerNode *node,
+ const string &name)
+ throw(Error)
+{
+ json_node_data *jdat = (json_node_data*)&node->data;
+ json_verify(jdat, "readBool()", name, PJ_JSON_VAL_BOOL);
+ jdat->childPtr = jdat->childPtr->next;
+ return PJ2BOOL(jdat->childPtr->prev->value.is_true);
+}
+
+static string jsonNode_readString(const ContainerNode *node,
+ const string &name)
+ throw(Error)
+{
+ json_node_data *jdat = (json_node_data*)&node->data;
+ json_verify(jdat, "readString()", name, PJ_JSON_VAL_STRING);
+ jdat->childPtr = jdat->childPtr->next;
+ return pj2Str(jdat->childPtr->prev->value.str);
+}
+
+static StringVector jsonNode_readStringVector(const ContainerNode *node,
+ const string &name)
+ throw(Error)
+{
+ json_node_data *jdat = (json_node_data*)&node->data;
+ json_verify(jdat, "readStringVector()", name, PJ_JSON_VAL_ARRAY);
+
+ StringVector result;
+ pj_json_elem *child = jdat->childPtr->value.children.next;
+ while (child != (pj_json_elem*)&jdat->childPtr->value.children) {
+ if (child->type != PJ_JSON_VAL_STRING) {
+ char err_msg[80];
+ pj_ansi_snprintf(err_msg, sizeof(err_msg),
+ "Elements not string but type %d",
+ child->type);
+ PJSUA2_RAISE_ERROR3(PJLIB_UTIL_EINJSON, "readStringVector()",
+ err_msg);
+ }
+ result.push_back(pj2Str(child->value.str));
+ child = child->next;
+ }
+
+ jdat->childPtr = jdat->childPtr->next;
+ return result;
+}
+
+static ContainerNode jsonNode_readContainer(const ContainerNode *node,
+ const string &name)
+ throw(Error)
+{
+ json_node_data *jdat = (json_node_data*)&node->data;
+ json_verify(jdat, "readContainer()", name, PJ_JSON_VAL_OBJ);
+
+ ContainerNode json_node;
+
+ json_node.op = &json_op;
+ json_node.data.doc = (void*)jdat->doc;
+ json_node.data.data1 = (void*)jdat->childPtr;
+ json_node.data.data2 = (void*)jdat->childPtr->value.children.next;
+
+ jdat->childPtr = jdat->childPtr->next;
+ return json_node;
+}
+
+static ContainerNode jsonNode_readArray(const ContainerNode *node,
+ const string &name)
+ throw(Error)
+{
+ json_node_data *jdat = (json_node_data*)&node->data;
+ json_verify(jdat, "readArray()", name, PJ_JSON_VAL_ARRAY);
+
+ ContainerNode json_node;
+
+ json_node.op = &json_op;
+ json_node.data.doc = (void*)jdat->doc;
+ json_node.data.data1 = (void*)jdat->childPtr;
+ json_node.data.data2 = (void*)jdat->childPtr->value.children.next;
+
+ jdat->childPtr = jdat->childPtr->next;
+ return json_node;
+}
+
+static pj_str_t alloc_name(JsonDocument *doc, const string &name)
+{
+ pj_str_t new_name;
+ pj_strdup2(doc->getPool(), &new_name, name.c_str());
+ return new_name;
+}
+
+static void jsonNode_writeNumber(ContainerNode *node,
+ const string &name,
+ float num)
+ throw(Error)
+{
+ json_node_data *jdat = (json_node_data*)&node->data;
+ pj_json_elem *el = jdat->doc->allocElement();
+ pj_str_t nm = alloc_name(jdat->doc, name);
+ pj_json_elem_number(el, &nm, num);
+ pj_json_elem_add(jdat->jnode, el);
+}
+
+static void jsonNode_writeBool(ContainerNode *node,
+ const string &name,
+ bool value)
+ throw(Error)
+{
+ json_node_data *jdat = (json_node_data*)&node->data;
+ pj_json_elem *el = jdat->doc->allocElement();
+ pj_str_t nm = alloc_name(jdat->doc, name);
+ pj_json_elem_bool(el, &nm, value);
+ pj_json_elem_add(jdat->jnode, el);
+}
+
+static void jsonNode_writeString(ContainerNode *node,
+ const string &name,
+ const string &value)
+ throw(Error)
+{
+ json_node_data *jdat = (json_node_data*)&node->data;
+ pj_json_elem *el = jdat->doc->allocElement();
+ pj_str_t nm = alloc_name(jdat->doc, name);
+ pj_str_t new_val;
+ pj_strdup2(jdat->doc->getPool(), &new_val, value.c_str());
+ pj_json_elem_string(el, &nm, &new_val);
+
+ pj_json_elem_add(jdat->jnode, el);
+}
+
+static void jsonNode_writeStringVector(ContainerNode *node,
+ const string &name,
+ const StringVector &value)
+ throw(Error)
+{
+ json_node_data *jdat = (json_node_data*)&node->data;
+ pj_json_elem *el = jdat->doc->allocElement();
+ pj_str_t nm = alloc_name(jdat->doc, name);
+
+ pj_json_elem_array(el, &nm);
+ for (unsigned i=0; i<value.size(); ++i) {
+ pj_str_t new_val;
+
+ pj_strdup2(jdat->doc->getPool(), &new_val, value[i].c_str());
+ pj_json_elem *child = jdat->doc->allocElement();
+ pj_json_elem_string(child, NULL, &new_val);
+ pj_json_elem_add(el, child);
+ }
+
+ pj_json_elem_add(jdat->jnode, el);
+}
+
+static ContainerNode jsonNode_writeNewContainer(ContainerNode *node,
+ const string &name)
+ throw(Error)
+{
+ json_node_data *jdat = (json_node_data*)&node->data;
+ pj_json_elem *el = jdat->doc->allocElement();
+ pj_str_t nm = alloc_name(jdat->doc, name);
+
+ pj_json_elem_obj(el, &nm);
+ pj_json_elem_add(jdat->jnode, el);
+
+ ContainerNode json_node;
+
+ json_node.op = &json_op;
+ json_node.data.doc = (void*)jdat->doc;
+ json_node.data.data1 = (void*)el;
+ json_node.data.data2 = (void*)el->value.children.next;
+
+ return json_node;
+}
+
+static ContainerNode jsonNode_writeNewArray(ContainerNode *node,
+ const string &name)
+ throw(Error)
+{
+ json_node_data *jdat = (json_node_data*)&node->data;
+ pj_json_elem *el = jdat->doc->allocElement();
+ pj_str_t nm = alloc_name(jdat->doc, name);
+
+ pj_json_elem_array(el, &nm);
+ pj_json_elem_add(jdat->jnode, el);
+
+ ContainerNode json_node;
+
+ json_node.op = &json_op;
+ json_node.data.doc = (void*)jdat->doc;
+ json_node.data.data1 = (void*)el;
+ json_node.data.data2 = (void*)el->value.children.next;
+
+ return json_node;
+}
diff --git a/pjsip/src/pjsua2/media.cpp b/pjsip/src/pjsua2/media.cpp
new file mode 100644
index 00000000..175d5987
--- /dev/null
+++ b/pjsip/src/pjsua2/media.cpp
@@ -0,0 +1,779 @@
+/* $Id$ */
+/*
+ * 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
+ */
+#include <pj/ctype.h>
+#include <pjsua2/media.hpp>
+#include <pjsua2/types.hpp>
+#include <pjsua2/endpoint.hpp>
+#include "util.hpp"
+
+using namespace pj;
+using namespace std;
+
+#define THIS_FILE "media.cpp"
+#define MAX_FILE_NAMES 64
+#define MAX_DEV_COUNT 64
+
+///////////////////////////////////////////////////////////////////////////////
+void MediaFormatAudio::fromPj(const pjmedia_format &format)
+{
+ if ((format.type != PJMEDIA_TYPE_AUDIO) &&
+ (format.detail_type != PJMEDIA_FORMAT_DETAIL_AUDIO))
+ {
+ type = PJMEDIA_TYPE_UNKNOWN;
+ return;
+ }
+
+ id = format.id;
+ type = format.type;
+
+ /* Detail. */
+ clockRate = format.det.aud.clock_rate;
+ channelCount = format.det.aud.channel_count;
+ frameTimeUsec = format.det.aud.frame_time_usec;
+ bitsPerSample = format.det.aud.bits_per_sample;
+ avgBps = format.det.aud.avg_bps;
+ maxBps = format.det.aud.max_bps;
+}
+
+pjmedia_format MediaFormatAudio::toPj() const
+{
+ pjmedia_format pj_format;
+
+ pj_format.id = id;
+ pj_format.type = type;
+
+ pj_format.detail_type = PJMEDIA_FORMAT_DETAIL_AUDIO;
+ pj_format.det.aud.clock_rate = clockRate;
+ pj_format.det.aud.channel_count = channelCount;
+ pj_format.det.aud.frame_time_usec = frameTimeUsec;
+ pj_format.det.aud.bits_per_sample = bitsPerSample;
+ pj_format.det.aud.avg_bps = avgBps;
+ pj_format.det.aud.max_bps = maxBps;
+
+ return pj_format;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/* Audio Media operations. */
+void ConfPortInfo::fromPj(const pjsua_conf_port_info &port_info)
+{
+ portId = port_info.slot_id;
+ name = pj2Str(port_info.name);
+ format.fromPj(port_info.format);
+ txLevelAdj = port_info.tx_level_adj;
+ rxLevelAdj = port_info.rx_level_adj;
+
+ /*
+ format.id = PJMEDIA_FORMAT_PCM;
+ format.type = PJMEDIA_TYPE_AUDIO;
+ format.clockRate = port_info.clock_rate;
+ format.channelCount = port_info.channel_count;
+ format.bitsPerSample = port_info.bits_per_sample;
+ format.frameTimeUsec = (port_info.samples_per_frame *
+ 1000000) /
+ (port_info.clock_rate *
+ port_info.channel_count);
+
+ format.avgBps = format.maxBps = port_info.clock_rate *
+ port_info.channel_count *
+ port_info.bits_per_sample;
+ */
+ listeners.clear();
+ for (unsigned i=0; i<port_info.listener_cnt; ++i) {
+ listeners.push_back(port_info.listeners[i]);
+ }
+}
+///////////////////////////////////////////////////////////////////////////////
+Media::Media(pjmedia_type med_type)
+: type(med_type)
+{
+
+}
+
+Media::~Media()
+{
+
+}
+
+pjmedia_type Media::getType() const
+{
+ return type;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+AudioMedia::AudioMedia()
+: Media(PJMEDIA_TYPE_AUDIO), id(PJSUA_INVALID_ID), mediaPool(NULL)
+{
+
+}
+
+void AudioMedia::registerMediaPort(MediaPort port) throw(Error)
+{
+ /* Check if media already added to Conf bridge. */
+ pj_assert(!Endpoint::instance().mediaExists(*this));
+
+ if (port != NULL) {
+ pj_assert(id == PJSUA_INVALID_ID);
+
+ pj_caching_pool_init(&mediaCachingPool, NULL, 0);
+
+ mediaPool = pj_pool_create(&mediaCachingPool.factory,
+ "media",
+ 512,
+ 512,
+ NULL);
+
+ if (!mediaPool) {
+ pj_caching_pool_destroy(&mediaCachingPool);
+ PJSUA2_RAISE_ERROR(PJ_ENOMEM);
+ }
+
+ PJSUA2_CHECK_EXPR( pjsua_conf_add_port(mediaPool,
+ (pjmedia_port *)port,
+ &id) );
+ }
+
+ Endpoint::instance().mediaAdd(*this);
+}
+
+void AudioMedia::unregisterMediaPort()
+{
+ if (id != PJSUA_INVALID_ID) {
+ pjsua_conf_remove_port(id);
+ id = PJSUA_INVALID_ID;
+ }
+
+ if (mediaPool) {
+ pj_pool_release(mediaPool);
+ mediaPool = NULL;
+ pj_caching_pool_destroy(&mediaCachingPool);
+ }
+
+ Endpoint::instance().mediaRemove(*this);
+}
+
+AudioMedia::~AudioMedia()
+{
+ unregisterMediaPort();
+}
+
+ConfPortInfo AudioMedia::getPortInfo() const throw(Error)
+{
+ return AudioMedia::getPortInfoFromId(id);
+}
+
+int AudioMedia::getPortId() const
+{
+ return id;
+}
+
+ConfPortInfo AudioMedia::getPortInfoFromId(int port_id) throw(Error)
+{
+ pjsua_conf_port_info pj_info;
+ ConfPortInfo pi;
+
+ PJSUA2_CHECK_EXPR( pjsua_conf_get_port_info(port_id, &pj_info) );
+ pi.fromPj(pj_info);
+ return pi;
+}
+
+void AudioMedia::startTransmit(const AudioMedia &sink) const throw(Error)
+{
+ PJSUA2_CHECK_EXPR( pjsua_conf_connect(id, sink.id) );
+}
+
+void AudioMedia::stopTransmit(const AudioMedia &sink) const throw(Error)
+{
+ PJSUA2_CHECK_EXPR( pjsua_conf_disconnect(id, sink.id) );
+}
+
+void AudioMedia::adjustRxLevel(float level) throw(Error)
+{
+ PJSUA2_CHECK_EXPR( pjsua_conf_adjust_rx_level(id, level) );
+}
+
+void AudioMedia::adjustTxLevel(float level) throw(Error)
+{
+ PJSUA2_CHECK_EXPR( pjsua_conf_adjust_tx_level(id, level) );
+}
+
+unsigned AudioMedia::getRxLevel() const throw(Error)
+{
+ return getSignalLevel(true);
+}
+
+unsigned AudioMedia::getTxLevel() const throw(Error)
+{
+ return getSignalLevel(false);
+}
+
+unsigned AudioMedia::getSignalLevel(bool is_rx) const throw(Error)
+{
+ unsigned rx_level;
+ unsigned tx_level;
+
+ PJSUA2_CHECK_EXPR( pjsua_conf_get_signal_level(id, &tx_level, &rx_level) );
+ return is_rx?rx_level:tx_level;
+}
+
+AudioMedia* AudioMedia::typecastFromMedia(Media *media)
+{
+ return static_cast<AudioMedia*>(media);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+AudioMediaPlayer::AudioMediaPlayer()
+: playerId(PJSUA_INVALID_ID)
+{
+
+}
+
+AudioMediaPlayer::~AudioMediaPlayer()
+{
+ if (playerId != PJSUA_INVALID_ID)
+ pjsua_player_destroy(playerId);
+}
+
+void AudioMediaPlayer::createPlayer(const string &file_name,
+ unsigned options)
+ throw(Error)
+{
+ pj_str_t pj_name = str2Pj(file_name);
+
+ PJSUA2_CHECK_EXPR( pjsua_player_create(&pj_name,
+ options,
+ &playerId) );
+
+ /* Get media port id. */
+ id = pjsua_player_get_conf_port(playerId);
+
+ registerMediaPort(NULL);
+}
+
+void AudioMediaPlayer::createPlaylist(const StringVector &file_names,
+ const string &label,
+ unsigned options)
+ throw(Error)
+{
+ pj_str_t pj_files[MAX_FILE_NAMES];
+ unsigned i, count = 0;
+ pj_str_t pj_lbl = str2Pj(label);
+
+ count = PJ_ARRAY_SIZE(pj_files);
+
+ for(i=0; i<file_names.size() && i<count;++i)
+ {
+ const string &file_name = file_names[i];
+
+ pj_files[i] = str2Pj(file_name);
+ }
+
+ PJSUA2_CHECK_EXPR( pjsua_playlist_create(pj_files,
+ i,
+ &pj_lbl,
+ options,
+ &playerId) );
+
+ /* Get media port id. */
+ id = pjsua_player_get_conf_port(playerId);
+
+ registerMediaPort(NULL);
+}
+
+void AudioMediaPlayer::setPos(pj_uint32_t samples) throw(Error)
+{
+ PJSUA2_CHECK_EXPR( pjsua_player_set_pos(playerId, samples) );
+}
+
+AudioMediaPlayer* AudioMediaPlayer::typecastFromAudioMedia(
+ AudioMedia *media)
+{
+ return static_cast<AudioMediaPlayer*>(media);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+AudioMediaRecorder::AudioMediaRecorder()
+: recorderId(PJSUA_INVALID_ID)
+{
+
+}
+
+AudioMediaRecorder::~AudioMediaRecorder()
+{
+ if (recorderId != PJSUA_INVALID_ID)
+ pjsua_recorder_destroy(recorderId);
+}
+
+void AudioMediaRecorder::createRecorder(const string &file_name,
+ unsigned enc_type,
+ pj_ssize_t max_size,
+ unsigned options)
+ throw(Error)
+{
+ PJ_UNUSED_ARG(max_size);
+
+ pj_str_t pj_name = str2Pj(file_name);
+
+ PJSUA2_CHECK_EXPR( pjsua_recorder_create(&pj_name,
+ enc_type,
+ NULL,
+ -1,
+ options,
+ &recorderId) );
+
+ /* Get media port id. */
+ id = pjsua_recorder_get_conf_port(recorderId);
+
+ registerMediaPort(NULL);
+}
+
+AudioMediaRecorder* AudioMediaRecorder::typecastFromAudioMedia(
+ AudioMedia *media)
+{
+ return static_cast<AudioMediaRecorder*>(media);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+void AudioDevInfo::fromPj(const pjmedia_aud_dev_info &dev_info)
+{
+ name = dev_info.name;
+ inputCount = dev_info.input_count;
+ outputCount = dev_info.output_count;
+ defaultSamplesPerSec = dev_info.default_samples_per_sec;
+ driver = dev_info.driver;
+ caps = dev_info.caps;
+ routes = dev_info.routes;
+
+ for (unsigned i=0; i<dev_info.ext_fmt_cnt;++i) {
+ MediaFormatAudio *format = new MediaFormatAudio;
+
+ format->fromPj(dev_info.ext_fmt[i]);
+ if (format->type == PJMEDIA_TYPE_AUDIO)
+ extFmt.push_back(format);
+ }
+}
+
+AudioDevInfo::~AudioDevInfo()
+{
+ for(unsigned i=0;i<extFmt.size();++i) {
+ delete extFmt[i];
+ }
+ extFmt.clear();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * Simple AudioMedia class for sound device.
+ */
+class DevAudioMedia : public AudioMedia
+{
+public:
+ DevAudioMedia();
+ ~DevAudioMedia();
+};
+
+DevAudioMedia::DevAudioMedia()
+{
+ this->id = 0;
+ registerMediaPort(NULL);
+}
+
+DevAudioMedia::~DevAudioMedia()
+{
+ /* Avoid removing this port (conf port id=0) from conference */
+ this->id = PJSUA_INVALID_ID;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/* Audio device operations. */
+
+AudDevManager::AudDevManager()
+: devMedia(NULL)
+{
+}
+
+AudDevManager::~AudDevManager()
+{
+ // At this point, devMedia should have been cleaned up by Endpoint,
+ // as AudDevManager destructor is called after Endpoint destructor.
+ //delete devMedia;
+
+ clearAudioDevList();
+}
+
+int AudDevManager::getCaptureDev() const throw(Error)
+{
+ return getActiveDev(true);
+}
+
+AudioMedia &AudDevManager::getCaptureDevMedia() throw(Error)
+{
+ if (!devMedia)
+ devMedia = new DevAudioMedia;
+ return *devMedia;
+}
+
+int AudDevManager::getPlaybackDev() const throw(Error)
+{
+ return getActiveDev(false);
+}
+
+AudioMedia &AudDevManager::getPlaybackDevMedia() throw(Error)
+{
+ if (!devMedia)
+ devMedia = new DevAudioMedia;
+ return *devMedia;
+}
+
+void AudDevManager::setCaptureDev(int capture_dev) const throw(Error)
+{
+ int playback_dev = getPlaybackDev();
+
+ PJSUA2_CHECK_EXPR( pjsua_set_snd_dev(capture_dev, playback_dev) );
+}
+
+void AudDevManager::setPlaybackDev(int playback_dev) const throw(Error)
+{
+ int capture_dev = getCaptureDev();
+
+ PJSUA2_CHECK_EXPR( pjsua_set_snd_dev(capture_dev, playback_dev) );
+}
+
+const AudioDevInfoVector &AudDevManager::enumDev() throw(Error)
+{
+ pjmedia_aud_dev_info pj_info[MAX_DEV_COUNT];
+ unsigned count;
+
+ PJSUA2_CHECK_EXPR( pjsua_enum_aud_devs(pj_info, &count) );
+
+ pj_enter_critical_section();
+ clearAudioDevList();
+ for (unsigned i = 0; (i<count && i<MAX_DEV_COUNT) ;++i) {
+ AudioDevInfo *dev_info = new AudioDevInfo;
+ dev_info->fromPj(pj_info[i]);
+ audioDevList.push_back(dev_info);
+ }
+ pj_leave_critical_section();
+ return audioDevList;
+}
+
+void AudDevManager::setNullDev() throw(Error)
+{
+ PJSUA2_CHECK_EXPR( pjsua_set_null_snd_dev() );
+}
+
+MediaPort *AudDevManager::setNoDev()
+{
+ return (MediaPort*)pjsua_set_no_snd_dev();
+}
+
+void AudDevManager::setEcOptions(unsigned tail_msec,
+ unsigned options) throw(Error)
+{
+ PJSUA2_CHECK_EXPR( pjsua_set_ec(tail_msec, options) );
+}
+
+unsigned AudDevManager::getEcTail() const throw(Error)
+{
+ unsigned tail_msec = 0;
+
+ PJSUA2_CHECK_EXPR( pjsua_get_ec_tail(&tail_msec) );
+
+ return tail_msec;
+}
+
+bool AudDevManager::sndIsActive() const
+{
+ return PJ2BOOL(pjsua_snd_is_active());
+}
+
+void AudDevManager::refreshDevs() throw(Error)
+{
+ PJSUA2_CHECK_EXPR( pjmedia_aud_dev_refresh() );
+}
+
+unsigned AudDevManager::getDevCount() const
+{
+ return pjmedia_aud_dev_count();
+}
+
+AudioDevInfo
+AudDevManager::getDevInfo(int id) const throw(Error)
+{
+ AudioDevInfo dev_info;
+ pjmedia_aud_dev_info pj_info;
+
+ PJSUA2_CHECK_EXPR( pjmedia_aud_dev_get_info(id, &pj_info) );
+
+ dev_info.fromPj(pj_info);
+ return dev_info;
+}
+
+int AudDevManager::lookupDev(const string &drv_name,
+ const string &dev_name) const throw(Error)
+{
+ pjmedia_aud_dev_index pj_idx = 0;
+
+ PJSUA2_CHECK_EXPR( pjmedia_aud_dev_lookup(drv_name.c_str(),
+ dev_name.c_str(),
+ &pj_idx) );
+
+ return pj_idx;
+}
+
+
+string AudDevManager::capName(pjmedia_aud_dev_cap cap) const
+{
+ return pjmedia_aud_dev_cap_name(cap, NULL);
+}
+
+void
+AudDevManager::setExtFormat(const MediaFormatAudio &format,
+ bool keep) throw(Error)
+{
+ pjmedia_format pj_format = format.toPj();
+
+ PJSUA2_CHECK_EXPR( pjsua_snd_set_setting(PJMEDIA_AUD_DEV_CAP_EXT_FORMAT,
+ &pj_format,
+ keep) );
+}
+
+MediaFormatAudio AudDevManager::getExtFormat() const throw(Error)
+{
+ pjmedia_format pj_format;
+ MediaFormatAudio format;
+
+ PJSUA2_CHECK_EXPR( pjsua_snd_get_setting(PJMEDIA_AUD_DEV_CAP_EXT_FORMAT,
+ &pj_format) );
+
+ format.fromPj(pj_format);
+
+ return format;
+}
+
+void AudDevManager::setInputLatency(unsigned latency_msec,
+ bool keep) throw(Error)
+{
+ PJSUA2_CHECK_EXPR( pjsua_snd_set_setting(PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY,
+ &latency_msec,
+ keep) );
+}
+
+unsigned AudDevManager::getInputLatency() const throw(Error)
+{
+ unsigned latency_msec = 0;
+
+ PJSUA2_CHECK_EXPR( pjsua_snd_get_setting(PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY,
+ &latency_msec) );
+
+ return latency_msec;
+}
+
+void
+AudDevManager::setOutputLatency(unsigned latency_msec,
+ bool keep) throw(Error)
+{
+ PJSUA2_CHECK_EXPR( pjsua_snd_set_setting(PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY,
+ &latency_msec,
+ keep) );
+}
+
+unsigned AudDevManager::getOutputLatency() const throw(Error)
+{
+ unsigned latency_msec = 0;
+
+ PJSUA2_CHECK_EXPR( pjsua_snd_get_setting(PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY,
+ &latency_msec) );
+
+ return latency_msec;
+}
+
+void AudDevManager::setInputVolume(unsigned volume, bool keep) throw(Error)
+{
+ PJSUA2_CHECK_EXPR(
+ pjsua_snd_set_setting(PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING,
+ &volume,
+ keep) );
+}
+
+unsigned AudDevManager::getInputVolume() const throw(Error)
+{
+ unsigned volume = 0;
+
+ PJSUA2_CHECK_EXPR(
+ pjsua_snd_get_setting(PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING,
+ &volume) );
+
+ return volume;
+}
+
+void AudDevManager::setOutputVolume(unsigned volume, bool keep) throw(Error)
+{
+ PJSUA2_CHECK_EXPR(
+ pjsua_snd_set_setting(PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING,
+ &volume,
+ keep) );
+}
+
+unsigned AudDevManager::getOutputVolume() const throw(Error)
+{
+ unsigned volume = 0;
+
+ PJSUA2_CHECK_EXPR(
+ pjsua_snd_get_setting(PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING,
+ &volume) );
+
+ return volume;
+}
+
+unsigned AudDevManager::getInputSignal() const throw(Error)
+{
+ unsigned signal = 0;
+
+ PJSUA2_CHECK_EXPR(
+ pjsua_snd_get_setting(PJMEDIA_AUD_DEV_CAP_INPUT_SIGNAL_METER,
+ &signal) );
+
+ return signal;
+}
+
+unsigned AudDevManager::getOutputSignal() const throw(Error)
+{
+ unsigned signal = 0;
+
+ PJSUA2_CHECK_EXPR(
+ pjsua_snd_get_setting(PJMEDIA_AUD_DEV_CAP_OUTPUT_SIGNAL_METER,
+ &signal) );
+
+ return signal;
+}
+
+void
+AudDevManager::setInputRoute(pjmedia_aud_dev_route route,
+ bool keep) throw(Error)
+{
+ PJSUA2_CHECK_EXPR( pjsua_snd_set_setting(PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE,
+ &route,
+ keep) );
+}
+
+pjmedia_aud_dev_route AudDevManager::getInputRoute() const throw(Error)
+{
+ pjmedia_aud_dev_route route = PJMEDIA_AUD_DEV_ROUTE_DEFAULT;
+
+ PJSUA2_CHECK_EXPR( pjsua_snd_get_setting(PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE,
+ &route) );
+
+ return route;
+}
+
+void
+AudDevManager::setOutputRoute(pjmedia_aud_dev_route route,
+ bool keep) throw(Error)
+{
+ PJSUA2_CHECK_EXPR( pjsua_snd_set_setting(PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE,
+ &route,
+ keep) );
+}
+
+pjmedia_aud_dev_route AudDevManager::getOutputRoute() const throw(Error)
+{
+ pjmedia_aud_dev_route route = PJMEDIA_AUD_DEV_ROUTE_DEFAULT;
+
+ PJSUA2_CHECK_EXPR( pjsua_snd_get_setting(PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE,
+ &route) );
+
+ return route;
+}
+
+void AudDevManager::setVad(bool enable, bool keep) throw(Error)
+{
+ PJSUA2_CHECK_EXPR( pjsua_snd_set_setting(PJMEDIA_AUD_DEV_CAP_VAD,
+ &enable,
+ keep) );
+}
+
+bool AudDevManager::getVad() const throw(Error)
+{
+ bool enable = false;
+
+ PJSUA2_CHECK_EXPR( pjsua_snd_get_setting(PJMEDIA_AUD_DEV_CAP_VAD,
+ &enable) );
+
+ return enable;
+}
+
+void AudDevManager::setCng(bool enable, bool keep) throw(Error)
+{
+ PJSUA2_CHECK_EXPR( pjsua_snd_set_setting(PJMEDIA_AUD_DEV_CAP_CNG,
+ &enable,
+ keep) );
+}
+
+bool AudDevManager::getCng() const throw(Error)
+{
+ bool enable = false;
+
+ PJSUA2_CHECK_EXPR( pjsua_snd_get_setting(PJMEDIA_AUD_DEV_CAP_CNG,
+ &enable) );
+
+ return enable;
+}
+
+void AudDevManager::setPlc(bool enable, bool keep) throw(Error)
+{
+ PJSUA2_CHECK_EXPR( pjsua_snd_set_setting(PJMEDIA_AUD_DEV_CAP_PLC,
+ &enable,
+ keep) );
+}
+
+bool AudDevManager::getPlc() const throw(Error)
+{
+ bool enable = false;
+
+ PJSUA2_CHECK_EXPR( pjsua_snd_get_setting(PJMEDIA_AUD_DEV_CAP_PLC,
+ &enable) );
+
+ return enable;
+}
+
+void AudDevManager::clearAudioDevList()
+{
+ for(unsigned i=0;i<audioDevList.size();++i) {
+ delete audioDevList[i];
+ }
+ audioDevList.clear();
+}
+
+int AudDevManager::getActiveDev(bool is_capture) const throw(Error)
+{
+ int capture_dev = 0, playback_dev = 0;
+ PJSUA2_CHECK_EXPR( pjsua_get_snd_dev(&capture_dev, &playback_dev) );
+
+ return is_capture?capture_dev:playback_dev;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+void CodecInfo::fromPj(const pjsua_codec_info &codec_info)
+{
+ codecId = pj2Str(codec_info.codec_id);
+ priority = codec_info.priority;
+ desc = pj2Str(codec_info.desc);
+}
diff --git a/pjsip/src/pjsua2/persistent.cpp b/pjsip/src/pjsua2/persistent.cpp
new file mode 100644
index 00000000..cd94316c
--- /dev/null
+++ b/pjsip/src/pjsua2/persistent.cpp
@@ -0,0 +1,227 @@
+/* $Id$ */
+/*
+ * 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
+ */
+#include <pjsua2/persistent.hpp>
+
+using namespace pj;
+using namespace std;
+
+
+bool PersistentDocument::hasUnread() const
+{
+ return getRootContainer().hasUnread();
+}
+
+string PersistentDocument::unreadName() const throw(Error)
+{
+ return getRootContainer().unreadName();
+}
+
+int PersistentDocument::readInt(const string &name) const throw(Error)
+{
+ return (int)getRootContainer().readNumber(name);
+}
+
+float PersistentDocument::readNumber(const string &name) const throw(Error)
+{
+ return getRootContainer().readNumber(name);
+}
+
+bool PersistentDocument::readBool(const string &name) const throw(Error)
+{
+ return getRootContainer().readBool(name);
+}
+
+string PersistentDocument::readString(const string &name) const throw(Error)
+{
+ return getRootContainer().readString(name);
+}
+
+StringVector PersistentDocument::readStringVector(const string &name) const
+ throw(Error)
+{
+ return getRootContainer().readStringVector(name);
+}
+
+void PersistentDocument::readObject(PersistentObject &obj) const throw(Error)
+{
+ getRootContainer().readObject(obj);
+}
+
+ContainerNode PersistentDocument::readContainer(const string &name) const
+ throw(Error)
+{
+ return getRootContainer().readContainer(name);
+}
+
+ContainerNode PersistentDocument::readArray(const string &name) const
+ throw(Error)
+{
+ return getRootContainer().readArray(name);
+}
+
+void PersistentDocument::writeNumber(const string &name,
+ float num) throw(Error)
+{
+ getRootContainer().writeNumber(name, num);
+}
+
+void PersistentDocument::writeInt(const string &name,
+ int num) throw(Error)
+{
+ getRootContainer().writeNumber(name, (float)num);
+}
+
+void PersistentDocument::writeBool(const string &name,
+ bool value) throw(Error)
+{
+ getRootContainer().writeBool(name, value);
+}
+
+void PersistentDocument::writeString(const string &name,
+ const string &value) throw(Error)
+{
+ getRootContainer().writeString(name, value);
+}
+
+void PersistentDocument::writeStringVector(const string &name,
+ const StringVector &value)
+ throw(Error)
+{
+ getRootContainer().writeStringVector(name, value);
+}
+
+void PersistentDocument::writeObject(const PersistentObject &obj) throw(Error)
+{
+ getRootContainer().writeObject(obj);
+}
+
+ContainerNode PersistentDocument::writeNewContainer(const string &name)
+ throw(Error)
+{
+ return getRootContainer().writeNewContainer(name);
+}
+
+ContainerNode PersistentDocument::writeNewArray(const string &name)
+ throw(Error)
+{
+ return getRootContainer().writeNewArray(name);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool ContainerNode::hasUnread() const
+{
+ return op->hasUnread(this);
+}
+
+string ContainerNode::unreadName() const throw(Error)
+{
+ return op->unreadName(this);
+}
+
+int ContainerNode::readInt(const string &name) const throw(Error)
+{
+ return (int)op->readNumber(this, name);
+}
+
+float ContainerNode::readNumber(const string &name) const throw(Error)
+{
+ return op->readNumber(this, name);
+}
+
+bool ContainerNode::readBool(const string &name) const throw(Error)
+{
+ return op->readBool(this, name);
+}
+
+string ContainerNode::readString(const string &name) const throw(Error)
+{
+ return op->readString(this, name);
+}
+
+StringVector ContainerNode::readStringVector(const string &name) const
+ throw(Error)
+{
+ return op->readStringVector(this, name);
+}
+
+void ContainerNode::readObject(PersistentObject &obj) const throw(Error)
+{
+ obj.readObject(*this);
+}
+
+ContainerNode ContainerNode::readContainer(const string &name) const
+ throw(Error)
+{
+ return op->readContainer(this, name);
+}
+
+ContainerNode ContainerNode::readArray(const string &name) const
+ throw(Error)
+{
+ return op->readArray(this, name);
+}
+
+void ContainerNode::writeNumber(const string &name,
+ float num) throw(Error)
+{
+ return op->writeNumber(this, name, num);
+}
+
+void ContainerNode::writeInt(const string &name,
+ int num) throw(Error)
+{
+ return op->writeNumber(this, name, (float)num);
+}
+
+void ContainerNode::writeBool(const string &name,
+ bool value) throw(Error)
+{
+ return op->writeBool(this, name, value);
+}
+
+void ContainerNode::writeString(const string &name,
+ const string &value) throw(Error)
+{
+ return op->writeString(this, name, value);
+}
+
+void ContainerNode::writeStringVector(const string &name,
+ const StringVector &value)
+ throw(Error)
+{
+ return op->writeStringVector(this, name, value);
+}
+
+void ContainerNode::writeObject(const PersistentObject &obj) throw(Error)
+{
+ obj.writeObject(*this);
+}
+
+ContainerNode ContainerNode::writeNewContainer(const string &name)
+ throw(Error)
+{
+ return op->writeNewContainer(this, name);
+}
+
+ContainerNode ContainerNode::writeNewArray(const string &name)
+ throw(Error)
+{
+ return op->writeNewArray(this, name);
+}
diff --git a/pjsip/src/pjsua2/presence.cpp b/pjsip/src/pjsua2/presence.cpp
new file mode 100644
index 00000000..205a85ee
--- /dev/null
+++ b/pjsip/src/pjsua2/presence.cpp
@@ -0,0 +1,190 @@
+/* $Id$ */
+/*
+ * 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
+ */
+#include <pjsua2/presence.hpp>
+#include <pjsua2/account.hpp>
+#include "util.hpp"
+
+using namespace pj;
+using namespace std;
+
+#define THIS_FILE "presence.cpp"
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+PresenceStatus::PresenceStatus()
+: status(PJSUA_BUDDY_STATUS_UNKNOWN), activity(PJRPID_ACTIVITY_UNKNOWN)
+{
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+void BuddyConfig::readObject(const ContainerNode &node) throw(Error)
+{
+ ContainerNode this_node = node.readContainer("BuddyConfig");
+
+ NODE_READ_STRING ( this_node, uri);
+ NODE_READ_BOOL ( this_node, subscribe);
+}
+
+void BuddyConfig::writeObject(ContainerNode &node) const throw(Error)
+{
+ ContainerNode this_node = node.writeNewContainer("BuddyConfig");
+
+ NODE_WRITE_STRING ( this_node, uri);
+ NODE_WRITE_BOOL ( this_node, subscribe);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void BuddyInfo::fromPj(const pjsua_buddy_info &pbi)
+{
+ uri = pj2Str(pbi.uri);
+ contact = pj2Str(pbi.contact);
+ presMonitorEnabled = PJ2BOOL(pbi.monitor_pres);
+ subState = pbi.sub_state;
+ subStateName = string(pbi.sub_state_name);
+ subTermCode = (pjsip_status_code)pbi.sub_term_code;
+ subTermReason = pj2Str(pbi.sub_term_reason);
+
+ /* Presence status */
+ presStatus.status = pbi.status;
+ presStatus.statusText = pj2Str(pbi.status_text);
+ presStatus.activity = pbi.rpid.activity;
+ presStatus.note = pj2Str(pbi.rpid.note);
+ presStatus.rpidId = pj2Str(pbi.rpid.id);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+/*
+ * Constructor.
+ */
+Buddy::Buddy()
+: id(PJSUA_INVALID_ID)
+{
+}
+
+/*
+ * Destructor.
+ */
+Buddy::~Buddy()
+{
+ if (isValid()) {
+ pjsua_buddy_set_user_data(id, NULL);
+ pjsua_buddy_del(id);
+
+ /* Remove from account buddy list */
+ acc->removeBuddy(this);
+ }
+}
+
+/*
+ * Create buddy and register the buddy to PJSUA-LIB.
+ */
+void Buddy::create(Account &account, const BuddyConfig &cfg) throw(Error)
+{
+ pjsua_buddy_config pj_cfg;
+ pjsua_buddy_config_default(&pj_cfg);
+
+ if (!account.isValid())
+ PJSUA2_RAISE_ERROR3(PJ_EINVAL, "Buddy::create()", "Invalid account");
+
+ pj_cfg.uri = str2Pj(cfg.uri);
+ pj_cfg.subscribe = cfg.subscribe;
+ pj_cfg.user_data = (void*)this;
+ PJSUA2_CHECK_EXPR( pjsua_buddy_add(&pj_cfg, &id) );
+
+ acc = &account;
+ acc->addBuddy(this);
+}
+
+/*
+ * Check if this buddy is valid.
+ */
+bool Buddy::isValid() const
+{
+ return PJ2BOOL( pjsua_buddy_is_valid(id) );
+}
+
+/*
+ * Get detailed buddy info.
+ */
+BuddyInfo Buddy::getInfo() const throw(Error)
+{
+ pjsua_buddy_info pj_bi;
+ BuddyInfo bi;
+
+ PJSUA2_CHECK_EXPR( pjsua_buddy_get_info(id, &pj_bi) );
+ bi.fromPj(pj_bi);
+ return bi;
+}
+
+/*
+ * Enable/disable buddy's presence monitoring.
+ */
+void Buddy::subscribePresence(bool subscribe) throw(Error)
+{
+ PJSUA2_CHECK_EXPR( pjsua_buddy_subscribe_pres(id, subscribe) );
+}
+
+
+/*
+ * Update the presence information for the buddy.
+ */
+void Buddy::updatePresence(void) throw(Error)
+{
+ PJSUA2_CHECK_EXPR( pjsua_buddy_update_pres(id) );
+}
+
+/*
+ * Send instant messaging outside dialog.
+ */
+void Buddy::sendInstantMessage(const SendInstantMessageParam &prm) throw(Error)
+{
+ BuddyInfo bi = getInfo();
+
+ pj_str_t to = str2Pj(bi.contact.empty()? bi.uri : bi.contact);
+ pj_str_t mime_type = str2Pj(prm.contentType);
+ pj_str_t content = str2Pj(prm.content);
+ void *user_data = (void*)prm.userData;
+ pjsua_msg_data msg_data;
+ prm.txOption.toPj(msg_data);
+
+ PJSUA2_CHECK_EXPR( pjsua_im_send(acc->getId(), &to, &mime_type, &content,
+ &msg_data, user_data) );
+}
+
+/*
+ * Send typing indication outside dialog.
+ */
+void Buddy::sendTypingIndication(const SendTypingIndicationParam &prm)
+ throw(Error)
+{
+ BuddyInfo bi = getInfo();
+
+ pj_str_t to = str2Pj(bi.contact.empty()? bi.uri : bi.contact);
+ pjsua_msg_data msg_data;
+ prm.txOption.toPj(msg_data);
+
+ PJSUA2_CHECK_EXPR( pjsua_im_typing(acc->getId(), &to, prm.isTyping,
+ &msg_data) );
+}
+
diff --git a/pjsip/src/pjsua2/siptypes.cpp b/pjsip/src/pjsua2/siptypes.cpp
new file mode 100644
index 00000000..f1d8bf2b
--- /dev/null
+++ b/pjsip/src/pjsua2/siptypes.cpp
@@ -0,0 +1,590 @@
+/* $Id$ */
+/*
+ * 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
+ */
+#include <pjsua2/types.hpp>
+#include <pjsua2/siptypes.hpp>
+#include "util.hpp"
+
+using namespace pj;
+using namespace std;
+
+#define THIS_FILE "siptypes.cpp"
+
+///////////////////////////////////////////////////////////////////////////////
+namespace pj
+{
+void readIntVector( ContainerNode &node,
+ const string &array_name,
+ IntVector &v) throw(Error)
+{
+ ContainerNode array_node = node.readArray(array_name);
+ v.resize(0);
+ while (array_node.hasUnread()) {
+ v.push_back((int)array_node.readNumber());
+ }
+}
+
+void writeIntVector(ContainerNode &node,
+ const string &array_name,
+ const IntVector &v) throw(Error)
+{
+ ContainerNode array_node = node.writeNewArray(array_name);
+ for (unsigned i=0; i<v.size(); ++i) {
+ array_node.writeNumber("", (float)v[i]);
+ }
+}
+
+void readQosParams( ContainerNode &node,
+ pj_qos_params &qos) throw(Error)
+{
+ ContainerNode this_node = node.readContainer("qosParams");
+
+ NODE_READ_NUM_T( this_node, pj_uint8_t, qos.flags);
+ NODE_READ_NUM_T( this_node, pj_uint8_t, qos.dscp_val);
+ NODE_READ_NUM_T( this_node, pj_uint8_t, qos.so_prio);
+ NODE_READ_NUM_T( this_node, pj_qos_wmm_prio, qos.wmm_prio);
+}
+
+void writeQosParams( ContainerNode &node,
+ const pj_qos_params &qos) throw(Error)
+{
+ ContainerNode this_node = node.writeNewContainer("qosParams");
+
+ NODE_WRITE_NUM_T( this_node, pj_uint8_t, qos.flags);
+ NODE_WRITE_NUM_T( this_node, pj_uint8_t, qos.dscp_val);
+ NODE_WRITE_NUM_T( this_node, pj_uint8_t, qos.so_prio);
+ NODE_WRITE_NUM_T( this_node, pj_qos_wmm_prio, qos.wmm_prio);
+}
+
+void readSipHeaders( const ContainerNode &node,
+ const string &array_name,
+ SipHeaderVector &headers) throw(Error)
+{
+ ContainerNode headers_node = node.readArray(array_name);
+ headers.resize(0);
+ while (headers_node.hasUnread()) {
+ SipHeader hdr;
+
+ ContainerNode header_node = headers_node.readContainer("header");
+ hdr.hName = header_node.readString("hname");
+ hdr.hValue = header_node.readString("hvalue");
+ headers.push_back(hdr);
+ }
+}
+
+void writeSipHeaders(ContainerNode &node,
+ const string &array_name,
+ const SipHeaderVector &headers) throw(Error)
+{
+ ContainerNode headers_node = node.writeNewArray(array_name);
+ for (unsigned i=0; i<headers.size(); ++i) {
+ ContainerNode header_node = headers_node.writeNewContainer("header");
+ header_node.writeString("hname", headers[i].hName);
+ header_node.writeString("hvalue", headers[i].hValue);
+ }
+}
+
+} // namespace
+///////////////////////////////////////////////////////////////////////////////
+
+AuthCredInfo::AuthCredInfo()
+: scheme("digest"), realm("*"), dataType(0)
+{
+}
+
+AuthCredInfo::AuthCredInfo(const string &param_scheme,
+ const string &param_realm,
+ const string &param_user_name,
+ const int param_data_type,
+ const string param_data)
+: scheme(param_scheme), realm(param_realm), username(param_user_name),
+ dataType(param_data_type), data(param_data)
+{
+}
+
+void AuthCredInfo::readObject(const ContainerNode &node) throw(Error)
+{
+ ContainerNode this_node = node.readContainer("AuthCredInfo");
+
+ NODE_READ_STRING( this_node, scheme);
+ NODE_READ_STRING( this_node, realm);
+ NODE_READ_STRING( this_node, username);
+ NODE_READ_INT ( this_node, dataType);
+ NODE_READ_STRING( this_node, data);
+ NODE_READ_STRING( this_node, akaK);
+ NODE_READ_STRING( this_node, akaOp);
+ NODE_READ_STRING( this_node, akaAmf);
+}
+
+void AuthCredInfo::writeObject(ContainerNode &node) const throw(Error)
+{
+ ContainerNode this_node = node.writeNewContainer("AuthCredInfo");
+
+ NODE_WRITE_STRING( this_node, scheme);
+ NODE_WRITE_STRING( this_node, realm);
+ NODE_WRITE_STRING( this_node, username);
+ NODE_WRITE_INT ( this_node, dataType);
+ NODE_WRITE_STRING( this_node, data);
+ NODE_WRITE_STRING( this_node, akaK);
+ NODE_WRITE_STRING( this_node, akaOp);
+ NODE_WRITE_STRING( this_node, akaAmf);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+TlsConfig::TlsConfig()
+{
+ pjsip_tls_setting ts;
+ pjsip_tls_setting_default(&ts);
+ this->fromPj(ts);
+}
+
+pjsip_tls_setting TlsConfig::toPj() const
+{
+ pjsip_tls_setting ts;
+
+ ts.ca_list_file = str2Pj(this->CaListFile);
+ ts.cert_file = str2Pj(this->certFile);
+ ts.privkey_file = str2Pj(this->privKeyFile);
+ ts.password = str2Pj(this->password);
+ ts.method = this->method;
+ ts.ciphers_num = this->ciphers.size();
+ // The following will only work if sizeof(enum)==sizeof(int)
+ pj_assert(sizeof(ts.ciphers[0]) == sizeof(int));
+ ts.ciphers = ts.ciphers_num?
+ (pj_ssl_cipher*)&this->ciphers[0] : NULL;
+ ts.verify_server = this->verifyServer;
+ ts.verify_client = this->verifyClient;
+ ts.require_client_cert = this->requireClientCert;
+ ts.timeout.sec = this->msecTimeout / 1000;
+ ts.timeout.msec = this->msecTimeout % 1000;
+ ts.qos_type = this->qosType;
+ ts.qos_params = this->qosParams;
+ ts.qos_ignore_error = this->qosIgnoreError;
+
+ return ts;
+}
+
+void TlsConfig::fromPj(const pjsip_tls_setting &prm)
+{
+ this->CaListFile = pj2Str(prm.ca_list_file);
+ this->certFile = pj2Str(prm.cert_file);
+ this->privKeyFile = pj2Str(prm.privkey_file);
+ this->password = pj2Str(prm.password);
+ this->method = (pjsip_ssl_method)prm.method;
+ // The following will only work if sizeof(enum)==sizeof(int)
+ pj_assert(sizeof(prm.ciphers[0]) == sizeof(int));
+ this->ciphers = IntVector(prm.ciphers, prm.ciphers+prm.ciphers_num);
+ this->verifyServer = PJ2BOOL(prm.verify_server);
+ this->verifyClient = PJ2BOOL(prm.verify_client);
+ this->requireClientCert = PJ2BOOL(prm.require_client_cert);
+ this->msecTimeout = PJ_TIME_VAL_MSEC(prm.timeout);
+ this->qosType = prm.qos_type;
+ this->qosParams = prm.qos_params;
+ this->qosIgnoreError = PJ2BOOL(prm.qos_ignore_error);
+}
+
+void TlsConfig::readObject(const ContainerNode &node) throw(Error)
+{
+ ContainerNode this_node = node.readContainer("TlsConfig");
+
+ NODE_READ_STRING ( this_node, CaListFile);
+ NODE_READ_STRING ( this_node, certFile);
+ NODE_READ_STRING ( this_node, privKeyFile);
+ NODE_READ_STRING ( this_node, password);
+ NODE_READ_NUM_T ( this_node, pjsip_ssl_method, method);
+ readIntVector ( this_node, "ciphers", ciphers);
+ NODE_READ_BOOL ( this_node, verifyServer);
+ NODE_READ_BOOL ( this_node, verifyClient);
+ NODE_READ_BOOL ( this_node, requireClientCert);
+ NODE_READ_UNSIGNED( this_node, msecTimeout);
+ NODE_READ_NUM_T ( this_node, pj_qos_type, qosType);
+ readQosParams ( this_node, qosParams);
+ NODE_READ_BOOL ( this_node, qosIgnoreError);
+}
+
+void TlsConfig::writeObject(ContainerNode &node) const throw(Error)
+{
+ ContainerNode this_node = node.writeNewContainer("TlsConfig");
+
+ NODE_WRITE_STRING ( this_node, CaListFile);
+ NODE_WRITE_STRING ( this_node, certFile);
+ NODE_WRITE_STRING ( this_node, privKeyFile);
+ NODE_WRITE_STRING ( this_node, password);
+ NODE_WRITE_NUM_T ( this_node, pjsip_ssl_method, method);
+ writeIntVector ( this_node, "ciphers", ciphers);
+ NODE_WRITE_BOOL ( this_node, verifyServer);
+ NODE_WRITE_BOOL ( this_node, verifyClient);
+ NODE_WRITE_BOOL ( this_node, requireClientCert);
+ NODE_WRITE_UNSIGNED( this_node, msecTimeout);
+ NODE_WRITE_NUM_T ( this_node, pj_qos_type, qosType);
+ writeQosParams ( this_node, qosParams);
+ NODE_WRITE_BOOL ( this_node, qosIgnoreError);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+TransportConfig::TransportConfig()
+{
+ pjsua_transport_config tc;
+ pjsua_transport_config_default(&tc);
+ this->fromPj(tc);
+}
+
+void TransportConfig::fromPj(const pjsua_transport_config &prm)
+{
+ this->port = prm.port;
+ this->portRange = prm.port_range;
+ this->publicAddress = pj2Str(prm.public_addr);
+ this->boundAddress = pj2Str(prm.bound_addr);
+ this->tlsConfig.fromPj(prm.tls_setting);
+ this->qosType = prm.qos_type;
+ this->qosParams = prm.qos_params;
+}
+
+pjsua_transport_config TransportConfig::toPj() const
+{
+ pjsua_transport_config tc;
+
+ tc.port = this->port;
+ tc.port_range = this->portRange;
+ tc.public_addr = str2Pj(this->publicAddress);
+ tc.bound_addr = str2Pj(this->boundAddress);
+ tc.tls_setting = this->tlsConfig.toPj();
+ tc.qos_type = this->qosType;
+ tc.qos_params = this->qosParams;
+
+ return tc;
+}
+
+void TransportConfig::readObject(const ContainerNode &node) throw(Error)
+{
+ ContainerNode this_node = node.readContainer("TransportConfig");
+
+ NODE_READ_UNSIGNED ( this_node, port);
+ NODE_READ_UNSIGNED ( this_node, portRange);
+ NODE_READ_STRING ( this_node, publicAddress);
+ NODE_READ_STRING ( this_node, boundAddress);
+ NODE_READ_NUM_T ( this_node, pj_qos_type, qosType);
+ readQosParams ( this_node, qosParams);
+ NODE_READ_OBJ ( this_node, tlsConfig);
+}
+
+void TransportConfig::writeObject(ContainerNode &node) const throw(Error)
+{
+ ContainerNode this_node = node.writeNewContainer("TransportConfig");
+
+ NODE_WRITE_UNSIGNED ( this_node, port);
+ NODE_WRITE_UNSIGNED ( this_node, portRange);
+ NODE_WRITE_STRING ( this_node, publicAddress);
+ NODE_WRITE_STRING ( this_node, boundAddress);
+ NODE_WRITE_NUM_T ( this_node, pj_qos_type, qosType);
+ writeQosParams ( this_node, qosParams);
+ NODE_WRITE_OBJ ( this_node, tlsConfig);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void TransportInfo::fromPj(const pjsua_transport_info &info)
+{
+ this->id = info.id;
+ this->type = info.type;
+ this->typeName = pj2Str(info.type_name);
+ this->info = pj2Str(info.info);
+ this->flags = info.flag;
+
+ char straddr[PJ_INET6_ADDRSTRLEN+10];
+ pj_sockaddr_print(&info.local_addr, straddr, sizeof(straddr), 3);
+ this->localAddress = straddr;
+
+ pj_ansi_snprintf(straddr, sizeof(straddr), "%.*s:%d",
+ (int)info.local_name.host.slen,
+ info.local_name.host.ptr,
+ info.local_name.port);
+ this->localName = straddr;
+ this->usageCount = info.usage_count;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SipRxData::SipRxData()
+: pjRxData(NULL)
+{
+}
+
+void SipRxData::fromPj(pjsip_rx_data &rdata)
+{
+ char straddr[PJ_INET6_ADDRSTRLEN+10];
+
+ info = pjsip_rx_data_get_info(&rdata);
+ wholeMsg = string(rdata.msg_info.msg_buf, rdata.msg_info.len);
+ pj_sockaddr_print(&rdata.pkt_info.src_addr, straddr, sizeof(straddr), 3);
+ srcAddress = straddr;
+ pjRxData = (void *)&rdata;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void SipMediaType::fromPj(const pjsip_media_type &prm)
+{
+ type = pj2Str(prm.type);
+ subType = pj2Str(prm.subtype);
+}
+
+pjsip_media_type SipMediaType::toPj() const
+{
+ pjsip_media_type pj_mt;
+ pj_bzero(&pj_mt, sizeof(pj_mt));
+ pj_mt.type = str2Pj(type);
+ pj_mt.subtype = str2Pj(subType);
+ return pj_mt;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void SipHeader::fromPj(const pjsip_hdr *hdr) throw(Error)
+{
+ char buf[256];
+
+ int len = pjsip_hdr_print_on((void*)hdr, buf, sizeof(buf)-1);
+ if (len <= 0)
+ PJSUA2_RAISE_ERROR(PJ_ETOOSMALL);
+ buf[len] = '\0';
+
+ char *pos = strchr(buf, ':');
+ if (!pos)
+ PJSUA2_RAISE_ERROR(PJSIP_EINVALIDHDR);
+
+ // Trim white space after header name
+ char *end_name = pos;
+ while (end_name>buf && pj_isspace(*(end_name-1))) --end_name;
+
+ // Trim whitespaces after colon
+ char *start_val = pos+1;
+ while (*start_val && pj_isspace(*start_val)) ++start_val;
+
+ hName = string(buf, end_name);
+ hValue = string(start_val);
+}
+
+pjsip_generic_string_hdr &SipHeader::toPj() const
+{
+ pj_str_t hname = str2Pj(hName);
+ pj_str_t hvalue = str2Pj(hValue);
+
+ pjsip_generic_string_hdr_init2(&pjHdr, &hname, &hvalue);
+ return pjHdr;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void SipMultipartPart::fromPj(const pjsip_multipart_part &prm) throw(Error)
+{
+ headers.clear();
+ pjsip_hdr* pj_hdr = prm.hdr.next;
+ while (pj_hdr != &prm.hdr) {
+ SipHeader sh;
+ sh.fromPj(pj_hdr);
+ headers.push_back(sh);
+ pj_hdr = pj_hdr->next;
+ }
+
+ if (!prm.body)
+ PJSUA2_RAISE_ERROR(PJ_EINVAL);
+
+ contentType.fromPj(prm.body->content_type);
+ body = string((char*)prm.body->data, prm.body->len);
+}
+
+pjsip_multipart_part& SipMultipartPart::toPj() const
+{
+ pj_list_init(&pjMpp.hdr);
+ for (unsigned i = 0; i < headers.size(); i++) {
+ pjsip_generic_string_hdr& pj_hdr = headers[i].toPj();
+ pj_list_push_back(&pjMpp.hdr, &pj_hdr);
+ }
+
+ pj_bzero(&pjMsgBody, sizeof(pjMsgBody));
+ pjMsgBody.content_type = contentType.toPj();
+ pjMsgBody.print_body = &pjsip_print_text_body;
+ pjMsgBody.clone_data = &pjsip_clone_text_data;
+ pjMsgBody.data = (void*)body.c_str();
+ pjMsgBody.len = body.size();
+ pjMpp.body = &pjMsgBody;
+
+ return pjMpp;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SipEvent::SipEvent()
+: type(PJSIP_EVENT_UNKNOWN), pjEvent(NULL)
+{
+}
+
+void SipEvent::fromPj(const pjsip_event &ev)
+{
+ type = ev.type;
+ if (type == PJSIP_EVENT_TIMER) {
+ body.timer.entry = ev.body.timer.entry;
+ } else if (type == PJSIP_EVENT_TSX_STATE) {
+ body.tsxState.prevState = (pjsip_tsx_state_e)
+ ev.body.tsx_state.prev_state;
+ body.tsxState.tsx.fromPj(*ev.body.tsx_state.tsx);
+ if (body.tsxState.type == PJSIP_EVENT_TX_MSG) {
+ if (ev.body.tsx_state.src.tdata)
+ body.tsxState.src.tdata.fromPj(*ev.body.tsx_state.src.tdata);
+ } else if (body.tsxState.type == PJSIP_EVENT_RX_MSG) {
+ if (ev.body.tsx_state.src.rdata)
+ body.tsxState.src.rdata.fromPj(*ev.body.tsx_state.src.rdata);
+ } else if (body.tsxState.type == PJSIP_EVENT_TRANSPORT_ERROR) {
+ body.tsxState.src.status = ev.body.tsx_state.src.status;
+ } else if (body.tsxState.type == PJSIP_EVENT_TIMER) {
+ body.tsxState.src.timer = ev.body.tsx_state.src.timer;
+ } else if (body.tsxState.type == PJSIP_EVENT_USER) {
+ body.tsxState.src.data = ev.body.tsx_state.src.data;
+ }
+ } else if (type == PJSIP_EVENT_TX_MSG) {
+ if (ev.body.tx_msg.tdata)
+ body.txMsg.tdata.fromPj(*ev.body.tx_msg.tdata);
+ } else if (type == PJSIP_EVENT_RX_MSG) {
+ if (ev.body.rx_msg.rdata)
+ body.rxMsg.rdata.fromPj(*ev.body.rx_msg.rdata);
+ } else if (type == PJSIP_EVENT_TRANSPORT_ERROR) {
+ if (ev.body.tx_error.tdata)
+ body.txError.tdata.fromPj(*ev.body.tx_error.tdata);
+ if (ev.body.tx_error.tsx)
+ body.txError.tsx.fromPj(*ev.body.tx_error.tsx);
+ } else if (type == PJSIP_EVENT_USER) {
+ body.user.user1 = ev.body.user.user1;
+ body.user.user2 = ev.body.user.user2;
+ body.user.user3 = ev.body.user.user3;
+ body.user.user4 = ev.body.user.user4;
+ }
+ pjEvent = (void *)&ev;
+}
+
+SipTxData::SipTxData()
+: pjTxData(NULL)
+{
+}
+
+void SipTxData::fromPj(pjsip_tx_data &tdata)
+{
+ char straddr[PJ_INET6_ADDRSTRLEN+10];
+
+ info = pjsip_tx_data_get_info(&tdata);
+ pjsip_tx_data_encode(&tdata);
+ wholeMsg = string(tdata.buf.start, tdata.buf.end - tdata.buf.start);
+ if (pj_sockaddr_has_addr(&tdata.tp_info.dst_addr)) {
+ pj_sockaddr_print(&tdata.tp_info.dst_addr, straddr, sizeof(straddr), 3);
+ dstAddress = straddr;
+ } else {
+ dstAddress = "";
+ }
+ pjTxData = (void *)&tdata;
+}
+
+SipTransaction::SipTransaction()
+: role(PJSIP_ROLE_UAC), statusCode(0), pjTransaction(NULL)
+{
+}
+
+void SipTransaction::fromPj(pjsip_transaction &tsx)
+{
+ this->role = tsx.role;
+ this->method = pj2Str(tsx.method.name);
+ this->statusCode = tsx.status_code;
+ this->statusText = pj2Str(tsx.status_text);
+ if (tsx.last_tx)
+ this->lastTx.fromPj(*tsx.last_tx);
+ else
+ this->lastTx.pjTxData = NULL;
+ this->pjTransaction = (void *)&tsx;
+}
+
+bool SipTxOption::isEmpty() const
+{
+ return (targetUri == "" && headers.size() == 0 && contentType == "" &&
+ msgBody == "" && multipartContentType.type == "" &&
+ multipartContentType.subType == "" && multipartParts.size() == 0);
+}
+
+void SipTxOption::fromPj(const pjsua_msg_data &prm) throw(Error)
+{
+ targetUri = pj2Str(prm.target_uri);
+
+ headers.clear();
+ pjsip_hdr* pj_hdr = prm.hdr_list.next;
+ while (pj_hdr != &prm.hdr_list) {
+ SipHeader sh;
+ sh.fromPj(pj_hdr);
+ headers.push_back(sh);
+ pj_hdr = pj_hdr->next;
+ }
+
+ contentType = pj2Str(prm.content_type);
+ msgBody = pj2Str(prm.msg_body);
+ multipartContentType.fromPj(prm.multipart_ctype);
+
+ multipartParts.clear();
+ pjsip_multipart_part* pj_mp = prm.multipart_parts.next;
+ while (pj_mp != &prm.multipart_parts) {
+ SipMultipartPart smp;
+ smp.fromPj(*pj_mp);
+ multipartParts.push_back(smp);
+ pj_mp = pj_mp->next;
+ }
+}
+
+void SipTxOption::toPj(pjsua_msg_data &msg_data) const
+{
+ unsigned i;
+
+ pjsua_msg_data_init(&msg_data);
+
+ msg_data.target_uri = str2Pj(targetUri);
+
+ pj_list_init(&msg_data.hdr_list);
+ for (i = 0; i < headers.size(); i++) {
+ pjsip_generic_string_hdr& pj_hdr = headers[i].toPj();
+ pj_list_push_back(&msg_data.hdr_list, &pj_hdr);
+ }
+
+ msg_data.content_type = str2Pj(contentType);
+ msg_data.msg_body = str2Pj(msgBody);
+ msg_data.multipart_ctype = multipartContentType.toPj();
+
+ pj_list_init(&msg_data.multipart_parts);
+ for (i = 0; i < multipartParts.size(); i++) {
+ pjsip_multipart_part& pj_part = multipartParts[i].toPj();
+ pj_list_push_back(&msg_data.multipart_parts, &pj_part);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+SendInstantMessageParam::SendInstantMessageParam()
+: contentType("text/plain"), content(""), userData(NULL)
+{
+}
+
+SendTypingIndicationParam::SendTypingIndicationParam()
+: isTyping(false)
+{
+}
diff --git a/pjsip/src/pjsua2/types.cpp b/pjsip/src/pjsua2/types.cpp
new file mode 100644
index 00000000..26740cc7
--- /dev/null
+++ b/pjsip/src/pjsua2/types.cpp
@@ -0,0 +1,95 @@
+/* $Id$ */
+/*
+ * 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
+ */
+#include <pjsua2/types.hpp>
+#include "util.hpp"
+
+using namespace pj;
+using namespace std;
+
+#define THIS_FILE "types.cpp"
+
+///////////////////////////////////////////////////////////////////////////////
+
+Error::Error()
+: status(PJ_SUCCESS), srcLine(0)
+{
+}
+
+Error::Error( pj_status_t prm_status,
+ const string &prm_title,
+ const string &prm_reason,
+ const string &prm_src_file,
+ int prm_src_line)
+: status(prm_status), title(prm_title), reason(prm_reason),
+ srcFile(prm_src_file), srcLine(prm_src_line)
+{
+ if (this->status != PJ_SUCCESS && prm_reason.empty()) {
+ char errmsg[PJ_ERR_MSG_SIZE];
+ pj_strerror(this->status, errmsg, sizeof(errmsg));
+ this->reason = errmsg;
+ }
+}
+
+string Error::info(bool multi_line) const
+{
+ string output;
+
+ if (status==PJ_SUCCESS) {
+ output = "No error";
+ } else if (!multi_line) {
+ char temp[80];
+
+ if (!title.empty()) {
+ output += title + " error: ";
+ }
+ snprintf(temp, sizeof(temp), " (status=%d)", status);
+ output += reason + temp;
+ if (!srcFile.empty()) {
+ output += " [";
+ output += srcFile;
+ snprintf(temp, sizeof(temp), ":%d]", srcLine);
+ output += temp;
+ }
+ } else {
+ char temp[80];
+
+ if (!title.empty()) {
+ output += string("Title: ") + title + "\n";
+ }
+
+ snprintf(temp, sizeof(temp), "%d\n", status);
+ output += string("Code: ") + temp;
+ output += string("Description: ") + reason + "\n";
+ if (!srcFile.empty()) {
+ snprintf(temp, sizeof(temp), ":%d\n", srcLine);
+ output += string("Location: ") + srcFile + temp;
+ }
+ }
+
+ return output;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void TimeValue::fromPj(const pj_time_val &prm)
+{
+ this->sec = prm.sec;
+ this->msec = prm.msec;
+}
+
diff --git a/pjsip/src/pjsua2/util.hpp b/pjsip/src/pjsua2/util.hpp
new file mode 100644
index 00000000..ae72af63
--- /dev/null
+++ b/pjsip/src/pjsua2/util.hpp
@@ -0,0 +1,45 @@
+/* $Id$ */
+/*
+ * 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
+ */
+
+#include <pjsua2/types.hpp>
+#include <string>
+
+#define PJ2BOOL(var) ((var) != PJ_FALSE)
+
+namespace pj
+{
+using std::string;
+
+inline pj_str_t str2Pj(const string &input_str)
+{
+ pj_str_t output_str;
+ output_str.ptr = (char*)input_str.c_str();
+ output_str.slen = input_str.size();
+ return output_str;
+}
+
+inline string pj2Str(const pj_str_t &input_str)
+{
+ if (input_str.ptr)
+ return string(input_str.ptr, input_str.slen);
+ return string();
+}
+
+
+} // namespace