Merge remote-tracking branch 'public/master' into belle-sip

Conflicts:
	.cproject
	.project
	Makefile.am
	configure.ac
	coreapi/Makefile.am
	coreapi/callbacks.c
	coreapi/linphonecore.c
This commit is contained in:
Jehan Monnier 2012-12-19 11:13:52 +01:00
commit 1f9453fea6
138 changed files with 12703 additions and 4809 deletions

172
.cproject
View file

@ -3,97 +3,94 @@
<cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
<storageModule moduleId="org.eclipse.cdt.core.settings">
<cconfiguration id="0.2131511368">
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="0.2131511368" moduleId="org.eclipse.cdt.core.settings" name="Default">
<cconfiguration id="0.2079208171">
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="0.2079208171" moduleId="org.eclipse.cdt.core.settings" name="Default">
<externalSettings/>
<extensions>
<extension id="org.eclipse.cdt.core.MachO64" point="org.eclipse.cdt.core.BinaryParser"/>
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
<extension id="org.eclipse.cdt.core.VCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
</extensions>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<configuration artifactName="linphone-private" buildProperties="" description="" id="0.2131511368" name="Default" parent="org.eclipse.cdt.build.core.prefbase.cfg">
<folderInfo id="0.2131511368." name="/" resourcePath="">
<toolChain id="org.eclipse.cdt.build.core.prefbase.toolchain.1521961344" name="No ToolChain" resourceTypeBasedDiscovery="false" superClass="org.eclipse.cdt.build.core.prefbase.toolchain">
<targetPlatform binaryParser="org.eclipse.cdt.core.MachO64" id="org.eclipse.cdt.build.core.prefbase.toolchain.1521961344.1164784940" name=""/>
<builder id="org.eclipse.cdt.build.core.settings.default.builder.760634908" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="org.eclipse.cdt.build.core.settings.default.builder"/>
<tool id="org.eclipse.cdt.build.core.settings.holder.libs.733819718" name="holder for library settings" superClass="org.eclipse.cdt.build.core.settings.holder.libs"/>
<tool id="org.eclipse.cdt.build.core.settings.holder.855204815" name="Assembly" superClass="org.eclipse.cdt.build.core.settings.holder">
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.180698630" languageId="org.eclipse.cdt.core.assembly" languageName="Assembly" sourceContentType="org.eclipse.cdt.core.asmSource" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
<configuration artifactName="linphone" buildProperties="" description="" id="0.2079208171" name="Default" parent="org.eclipse.cdt.build.core.prefbase.cfg">
<folderInfo id="0.2079208171." name="/" resourcePath="">
<toolChain id="org.eclipse.cdt.build.core.prefbase.toolchain.2084203071" name="No ToolChain" resourceTypeBasedDiscovery="false" superClass="org.eclipse.cdt.build.core.prefbase.toolchain">
<targetPlatform binaryParser="org.eclipse.cdt.core.MachO64;org.eclipse.cdt.core.ELF" id="org.eclipse.cdt.build.core.prefbase.toolchain.2084203071.81924294" name=""/>
<builder arguments="CFLAGS=&quot;-g -Werror -Wall&quot; CXXFLAGS=&quot;-g&quot; V=1" command="make" id="org.eclipse.cdt.build.core.settings.default.builder.731584538" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="org.eclipse.cdt.build.core.settings.default.builder"/>
<tool id="org.eclipse.cdt.build.core.settings.holder.libs.1252970003" name="holder for library settings" superClass="org.eclipse.cdt.build.core.settings.holder.libs"/>
<tool id="org.eclipse.cdt.build.core.settings.holder.1371414073" name="GNU C++" superClass="org.eclipse.cdt.build.core.settings.holder">
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.306286573" languageId="org.eclipse.cdt.core.g++" languageName="GNU C++" sourceContentType="org.eclipse.cdt.core.cxxSource,org.eclipse.cdt.core.cxxHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
</tool>
<tool id="org.eclipse.cdt.build.core.settings.holder.700732108" name="GNU C++" superClass="org.eclipse.cdt.build.core.settings.holder">
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.313206468" languageId="org.eclipse.cdt.core.g++" languageName="GNU C++" sourceContentType="org.eclipse.cdt.core.cxxSource,org.eclipse.cdt.core.cxxHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
<tool id="org.eclipse.cdt.build.core.settings.holder.391709798" name="GNU C" superClass="org.eclipse.cdt.build.core.settings.holder">
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.1702094818" languageId="org.eclipse.cdt.core.gcc" languageName="GNU C" sourceContentType="org.eclipse.cdt.core.cSource,org.eclipse.cdt.core.cHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
</tool>
<tool id="org.eclipse.cdt.build.core.settings.holder.1875794262" name="GNU C" superClass="org.eclipse.cdt.build.core.settings.holder">
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.1686102409" languageId="org.eclipse.cdt.core.gcc" languageName="GNU C" sourceContentType="org.eclipse.cdt.core.cSource,org.eclipse.cdt.core.cHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
<tool id="org.eclipse.cdt.build.core.settings.holder.754828354" name="Assembly" superClass="org.eclipse.cdt.build.core.settings.holder">
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.585510934" languageId="org.eclipse.cdt.core.assembly" languageName="Assembly" sourceContentType="org.eclipse.cdt.core.asmSource" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
</tool>
</toolChain>
</folderInfo>
<sourceEntries>
<entry excluding="coreapi/sal_eXosip2.h" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
</sourceEntries>
</configuration>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
</cconfiguration>
<cconfiguration id="0.2131511368.593515799">
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="0.2131511368.593515799" moduleId="org.eclipse.cdt.core.settings" name="debug">
<externalSettings/>
<extensions>
<extension id="org.eclipse.cdt.core.MachO64" point="org.eclipse.cdt.core.BinaryParser"/>
<extension id="org.eclipse.cdt.core.VCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
</extensions>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<configuration artifactName="linphone-private" buildProperties="" description="debug" id="0.2131511368.593515799" name="debug" parent="org.eclipse.cdt.build.core.prefbase.cfg">
<folderInfo id="0.2131511368.593515799." name="/" resourcePath="">
<toolChain id="org.eclipse.cdt.build.core.prefbase.toolchain.1930099439" name="No ToolChain" resourceTypeBasedDiscovery="false" superClass="org.eclipse.cdt.build.core.prefbase.toolchain">
<targetPlatform binaryParser="org.eclipse.cdt.core.MachO64" id="org.eclipse.cdt.build.core.prefbase.toolchain.1930099439.714963030" name=""/>
<builder arguments="CFLAGS=&quot;-g -Wall -Werror -Wno-deprecated-declarations -Wno-unused-function&quot; V=1" command="make" id="org.eclipse.cdt.build.core.settings.default.builder.896899734" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="org.eclipse.cdt.build.core.settings.default.builder"/>
<tool id="org.eclipse.cdt.build.core.settings.holder.libs.1682581923" name="holder for library settings" superClass="org.eclipse.cdt.build.core.settings.holder.libs"/>
<tool id="org.eclipse.cdt.build.core.settings.holder.730520342" name="Assembly" superClass="org.eclipse.cdt.build.core.settings.holder">
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.552841386" languageId="org.eclipse.cdt.core.assembly" languageName="Assembly" sourceContentType="org.eclipse.cdt.core.asmSource" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
</tool>
<tool id="org.eclipse.cdt.build.core.settings.holder.1390526543" name="GNU C++" superClass="org.eclipse.cdt.build.core.settings.holder">
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.559579929" languageId="org.eclipse.cdt.core.g++" languageName="GNU C++" sourceContentType="org.eclipse.cdt.core.cxxSource,org.eclipse.cdt.core.cxxHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
</tool>
<tool id="org.eclipse.cdt.build.core.settings.holder.1823518174" name="GNU C" superClass="org.eclipse.cdt.build.core.settings.holder">
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.1618204218" languageId="org.eclipse.cdt.core.gcc" languageName="GNU C" sourceContentType="org.eclipse.cdt.core.cSource,org.eclipse.cdt.core.cHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
</tool>
</toolChain>
</folderInfo>
<sourceEntries>
<entry excluding="coreapi/sal_eXosip2.h|coreapi/sal_eXosip2.c" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
</sourceEntries>
</configuration>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
</cconfiguration>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<project id="linphone-private.null.17244867" name="linphone-private"/>
<project id="linphone.null.1149313048" name="linphone"/>
</storageModule>
<storageModule moduleId="refreshScope" versionNumber="2">
<configuration configurationName="Default">
<resource resourceType="PROJECT" workspacePath="/linphone-private"/>
</configuration>
<configuration configurationName="debug">
<resource resourceType="PROJECT" workspacePath="/linphone-private"/>
<resource resourceType="PROJECT" workspacePath="/linphone"/>
</configuration>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets">
<buildTargets>
<target name="test" path="mediastreamer2/tests" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildTarget>all</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="all" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildArguments>CFLAGS="-g"</buildArguments>
<buildTarget>install</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="install" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildArguments>CFLAGS="-g"</buildArguments>
<buildTarget>install</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="doc" path="coreapi/help" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildTarget>all</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="doc" path="mediastreamer2/help" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildTarget>all</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
</buildTargets>
</storageModule>
<storageModule moduleId="scannerConfiguration">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
@ -146,38 +143,15 @@
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<scannerConfigBuildInfo instanceId="0.2131511368.593515799">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"/>
<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="discovery" command="make" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
<buildOutputProvider>
<openAction enabled="true" filePath="/Users/jehanmonnier/workspaces/workspace-sip-parser/linphone-private/make discovery"/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="makefileGenerator">
<runAction arguments="-E -P -v -dD" command="" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
</scannerConfigBuildInfo>
<scannerConfigBuildInfo instanceId="0.2079208171">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"/>
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile"/>
<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-s -C src discovery" command="make" useDefault="true"/>
<runAction arguments="discovery" command="make discovery" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
@ -197,7 +171,7 @@
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-s -C src discovery" command="make" useDefault="true"/>
<runAction arguments="-s discovery" command="make" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
@ -222,18 +196,6 @@
</scannerInfoProvider>
</profile>
</scannerConfigBuildInfo>
<scannerConfigBuildInfo instanceId="0.2131511368">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"/>
<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-s discovery" command="make" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
</scannerConfigBuildInfo>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
</cproject>

View file

@ -23,7 +23,7 @@
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.buildArguments</key>
<value>CFLAGS=&quot;-g -Wall -Werror&quot; V=1</value>
<value>CFLAGS=&quot;-g -Werror -Wall&quot; CXXFLAGS=&quot;-g&quot; V=1</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.buildCommand</key>

View file

@ -4,7 +4,7 @@
ACLOCAL_AMFLAGS = -I m4 $(ACLOCAL_MACOS_FLAGS)
SUBDIRS = build m4 pixmaps po @ORTP_DIR@ @MS2_DIR@ \
coreapi console gtk share scripts tester
coreapi console gtk share scripts tools tester
@ -18,13 +18,13 @@ OPTIONAL_SOUNDS=\
share/sounds/linphone/rings/rock.wav
INSTALLDIR=$(shell cd $(top_builddir) && pwd)/linphone-install
INSTALLDIR=$(abs_top_builddir)/linphone-install
INSTALLDIR_WITH_PREFIX=$(INSTALLDIR)/$(prefix)
ZIPFILE=$(shell cd $(top_builddir) && pwd)/$(PACKAGE)-win32-$(VERSION).zip
ZIPFILE=$(abs_top_builddir)/$(PACKAGE)-win32-$(VERSION).zip
ZIP_EXCLUDED=include lib \
$(OPTIONAL_SOUNDS)
SDK_ZIPFILE=$(shell cd $(top_builddir) && pwd)/lib$(PACKAGE)-win32-$(VERSION).zip
SDK_ZIPFILE=$(abs_top_builddir)/lib$(PACKAGE)-win32-$(VERSION).zip
SDK_EXCLUDED= \
bin/linphone.exe \
lib/*.la \
@ -38,11 +38,11 @@ SDK_EXCLUDED= \
GTK_PREFIX=/
GTK_THEME=Outcrop
GTK_FILELIST=gtk+-2.22.1.filelist
GTK_FILELIST_PATH=$(shell cd $(top_srcdir) && pwd)/$(GTK_FILELIST)
GTK_FILELIST_PATH=$(abs_top_srcdir)/$(GTK_FILELIST)
LINPHONEDEPS_FILELIST=linphone-deps.filelist
WINBINDIST_FILES=$(shell cat $(top_srcdir)/$(LINPHONEDEPS_FILELIST))
WINBINDIST_FILES=`cat $(abs_top_srcdir)/$(LINPHONEDEPS_FILELIST)`
ISS_SCRIPT=linphone.iss
ISS_SCRIPT_PATH=$(shell cd $(top_srcdir) && pwd)/$(ISS_SCRIPT)
ISS_SCRIPT_PATH=$(abs_top_srcdir)/$(ISS_SCRIPT)
#path to Inno Setup 5 compiler
ISCC=ISCC.exe
PACKAGE_WIN32_FILELIST=$(PACKAGE)-win32.filelist
@ -102,7 +102,7 @@ other-cherrypick:
cd $(GTK_PREFIX) && \
for file in $(WINBINDIST_FILES) ; do \
if test -d $$file; then \
mkdir -p $(INSTALLDIR_WITH_PREFIX)/$$file ;\
$(MKDIR_P) $(INSTALLDIR_WITH_PREFIX)/$$file ;\
else \
cp $$file $(INSTALLDIR_WITH_PREFIX)/$$file ;\
fi \
@ -119,18 +119,18 @@ gtk-cherrypick:
cd $(GTK_PREFIX) && \
for file in `cat $(GTK_FILELIST_PATH)` ; do \
if test -d $$file; then \
mkdir -p $(INSTALLDIR_WITH_PREFIX)/$$file ;\
$(MKDIR_P) $(INSTALLDIR_WITH_PREFIX)/$$file ;\
else \
cp $$file $(INSTALLDIR_WITH_PREFIX)/$$file ;\
fi \
done && \
mkdir -p $(INSTALLDIR_WITH_PREFIX)/share/themes && \
$(MKDIR_P) $(INSTALLDIR_WITH_PREFIX)/share/themes && \
cp -rf share/themes/$(GTK_THEME) $(INSTALLDIR_WITH_PREFIX)/share/themes/.
zip:
rm -f $(ZIPFILE)
rm -rf $(INSTALLDIR)
mkdir -p $(INSTALLDIR)
$(MKDIR_P) $(INSTALLDIR)
make install DESTDIR=$(INSTALLDIR)
#remove unwanted linphone stuff
cd $(INSTALLDIR_WITH_PREFIX) && rm -rf $(ZIP_EXCLUDED)
@ -145,7 +145,7 @@ zip:
sdk:
rm -f $(SDK_ZIPFILE)
rm -rf $(INSTALLDIR)
mkdir -p $(INSTALLDIR)
$(MKDIR_P) $(INSTALLDIR)
make install DESTDIR=$(INSTALLDIR)
# remove unwanted stuff (gtk interface)
cd $(INSTALLDIR_WITH_PREFIX) && rm -rf $(SDK_EXCLUDED)
@ -182,12 +182,12 @@ newdate:
cd gtk && $(MAKE) newdate
if HAVE_MD5SUM
GEN_MD5=$(shell $(MD5SUM) linphone-$(VERSION).tar.gz | awk {'print $$4'})
GEN_MD5=`$(MD5SUM) linphone-$(VERSION).tar.gz | awk {'print $$4'}`
else
GEN_MD5=$(shell $(MD5SUM) linphone-$(VERSION).tar.gz | awk {'print $$1'})
GEN_MD5=`$(MD5SUM) linphone-$(VERSION).tar.gz | awk {'print $$1'}`
endif
Portfile: $(top_srcdir)/scripts/Portfile.tmpl dist
Portfile: $(top_srcdir)/scripts/Portfile.tmpl dist
sed -e 's/\@VERSION\@/$(LINPHONE_VERSION)/g' \
-e 's/\@LINPHONE_MD5\@/$(GEN_MD5)/' < $< > $@
@ -210,7 +210,7 @@ $(LIBICONV_HACK):
bundle: $(LIBICONV_HACK)
rm -rf $(INSTALLDIR)
mkdir -p $(INSTALLDIR)
$(MKDIR_P) $(INSTALLDIR)
make install DESTDIR=$(INSTALLDIR)
BUNDLE_PREFIX=$(BUNDLEPREFIX) \
LINPHONE_INSTALL_PREFIX=$(INSTALLDIR_WITH_PREFIX) \
@ -218,7 +218,9 @@ bundle: $(LIBICONV_HACK)
MS2_PLUGINS_INSTALL_PREFIX=$(prefix) \
gtk-mac-bundler $(PACKAGE_BUNDLE_FILE)
printf "[Pango]\nModuleFiles=./etc/pango/pango.modules\n" \
> $(BUNDLEDIR)/Contents/Resources/etc/pango/pangorc
> $(BUNDLEDIR)/Contents/Resources/etc/pango/pangorc
cp -f $(BUNDLEDIR)/Contents/Resources/etc/pango/pango.modules $(BUNDLEDIR)/Contents/Resources/etc/pango/pango.modules.orig
sed -e 's:@executable_path/../Resources:../..:g' $(BUNDLEDIR)/Contents/Resources/etc/pango/pango.modules.orig > $(BUNDLEDIR)/Contents/Resources/etc/pango/pango.modules
cp -f $(LIBICONV_HACK) $(BUNDLEDIR)/Contents/Resources/lib/.
cd $(BUNDLEDIR)/.. && rm -f $(MACAPPZIP) && zip -r $(MACAPPZIP) $(MACAPPNAME) && cd -
@ -229,4 +231,5 @@ clean-local:
rm -rf $(BUNDLEDIR)
discovery:
touch specs.cpp
$(CC) $(CFLAGS) -include $(top_builddir)/config.h $(MEDIASTREAMER2_CFLAGS) $(ORTP_CFLAGS) $(SIPSTACK_CFLAGS) $(CUNIT_CFLAGS)-E -P -v -dD specs.cpp
$(CC) --include $(top_builddir)/config.h \
$(TUNNEL_CFLAGS) $(CFLAGS) $(MEDIASTREAMER2_CFLAGS) $(ORTP_CFLAGS) $(SIPSTACK_CFLAGS) $(CUNIT_CFLAGS) -E -P -v -dD specs.cpp

4
NEWS
View file

@ -1,3 +1,7 @@
linphone-3.xxx --
* fix bug in zRTP support (upgrade required)
*
linphone-3.5.2 -- February 22, 2012
* updated oRTP to 0.20.0
* updated mediastreamer2 to 2.8.2

View file

@ -16,6 +16,7 @@ You need:
$ port install libeXosip2 #WARNING: currently outdated in macport
$ port install ffmpeg-devel
$ port install libvpx
$ port install readline
- Install srtp (optional) for call encryption
$ port install srtp
@ -27,7 +28,7 @@ You need:
- Install zrtpcpp (optional), for unbreakable call encryption
$ port install cmake
$ git clone git://git.linphone.org/zrtpcpp.git
$ cd zrtpcpp && cmake -Denable_ccrtp=false . && make
$ cd zrtpcpp && cmake -Denable-ccrtp=false . && make
$ sudo make install
- Install gtk. It is recommended to use the quartz backend for better integration.

View file

@ -26,7 +26,7 @@ Download lastest linphone-deps-win32 zip from
http://download.savannah.gnu.org/releases-noredirect/linphone/misc
using your browser.
Download lastest gtk+ win32 bundle from http://www.gtk.org
Download lastest gtk+2 win32 bundle from http://www.gtk.org
Install all these three package in /:
@ -65,20 +65,38 @@ WARNING: During the build, windows might slow down suddenly. Using ctl+alt+del t
you might see a process 'LVpSRV.exe' or something like this that eats 90% of cpu.
Kill it. Don't know what it is, but once killed, windows runs normally.
#Compile and install tunnel
cd tunnel && ./autogen.sh && ./configure --prefix=/opt/linphone && make && make install
#Compile and install tunnel (optional, available under proprietary licensing)
cd tunnel && ./autogen.sh && ./configure --prefix=/usr --enable-shared --disable-static && make && make install
#Build linphone itself:
#run autogen.sh after a git checkout or update
./autogen.sh
./configure --prefix=/opt/linphone --enable-shared --disable-static
#note: in order to use the tunnel, append --enable-tunnel to the configure line above.
#compile:
make
#will install to /opt/linphone, required for compilation of plugins.
#now install to /opt/linphone, required for compilation of plugins.
make install
#make a binary zip of linphone
make zip
#additionally you can make binary installer if you have Inno Setup 5 installed in its default path
make setup.exe
#now you're done, you have a fresh linphone windows installer in the current directory.
#build plugins
cd mediastreamer2/plugins/msx264
./autogen.sh

View file

@ -0,0 +1,46 @@
##
## Android.mk -Android build script-
##
##
## Copyright (C) 2010 Belledonne Communications, Grenoble, France
##
## 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.
##
LOCAL_PATH:= $(call my-dir)/../../coreapi
include $(CLEAR_VARS)
include $(linphone-root-dir)/submodules/linphone/build/android/common.mk
ifeq ($(LINPHONE_VIDEO),1)
LOCAL_SHARED_LIBRARIES += \
libavcodecnoneon \
libswscale \
libavcore \
libavutil
endif
LOCAL_MODULE := liblinphonenoneon
ifeq ($(TARGET_ARCH_ABI),armeabi)
LOCAL_MODULE_FILENAME := liblinphonearmv5
endif
include $(BUILD_SHARED_LIBRARY)
$(call import-module,android/cpufeatures)

View file

@ -24,128 +24,9 @@ LOCAL_PATH:= $(call my-dir)/../../coreapi
include $(CLEAR_VARS)
LOCAL_CPP_EXTENSION := .cc
LOCAL_SRC_FILES := \
linphonecore.c \
misc.c \
enum.c \
presence.c \
proxy.c \
friend.c \
authentication.c \
lpconfig.c \
chat.c \
sipsetup.c \
siplogin.c \
address.c \
linphonecore_jni.cc \
sal.c \
sal_eXosip2.c \
sal_eXosip2_presence.c \
sal_eXosip2_sdp.c \
offeranswer.c \
callbacks.c \
linphonecall.c \
conference.c \
ec-calibrator.c
ifndef MY_LOG_DOMAIN
MY_LOG_DOMAIN = \"Linphone\"
endif
LOCAL_CFLAGS += \
-D_BYTE_ORDER=_LITTLE_ENDIAN \
-DORTP_INET6 \
-DINET6 \
-DOSIP_MT \
-DENABLE_TRACE \
-DLINPHONE_VERSION=\"3.4.0\" \
-DLINPHONE_PLUGINS_DIR=\"\\tmp\" \
-DLOG_DOMAIN=$(MY_LOG_DOMAIN)
LOCAL_CFLAGS += -DIN_LINPHONE
include $(linphone-root-dir)/submodules/linphone/build/android/common.mk
ifeq ($(LINPHONE_VIDEO),1)
LOCAL_CFLAGS += -DVIDEO_ENABLED
ifeq ($(BUILD_X264),1)
LOCAL_CFLAGS += -DHAVE_X264
endif
endif
LOCAL_C_INCLUDES += \
$(LOCAL_PATH) \
$(LOCAL_PATH)/include \
$(LOCAL_PATH)/../oRTP/include \
$(LOCAL_PATH)/../mediastreamer2/include \
$(LOCAL_PATH)/../../externals/exosip/include \
$(LOCAL_PATH)/../../externals/osip/include
LOCAL_LDLIBS += -llog -ldl
LOCAL_STATIC_LIBRARIES := \
cpufeatures \
libmediastreamer2 \
libortp \
libeXosip2 \
libosip2 \
libgsm
ifeq ($(BUILD_TUNNEL),1)
LOCAL_CFLAGS +=-DTUNNEL_ENABLED
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../tunnel/include $(LOCAL_PATH)/../../tunnel/src
LOCAL_SRC_FILES += linphone_tunnel.cc TunnelManager.cc
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
LOCAL_SHARED_LIBRARIES += libtunnelclient
else
LOCAL_STATIC_LIBRARIES += libtunnelclient
endif
endif
_BUILD_AMR=0
ifneq ($(BUILD_AMRNB), 0)
_BUILD_AMR=1
endif
ifneq ($(BUILD_AMRWB), 0)
_BUILD_AMR=1
endif
ifneq ($(_BUILD_AMR), 0)
LOCAL_CFLAGS += -DHAVE_AMR
LOCAL_STATIC_LIBRARIES += \
libmsamr \
libopencoreamr
endif
ifneq ($(BUILD_AMRWB), 0)
LOCAL_STATIC_LIBRARIES += \
libvoamrwbenc
endif
ifeq ($(BUILD_SILK),1)
LOCAL_CFLAGS += -DHAVE_SILK
LOCAL_STATIC_LIBRARIES += libmssilk
endif
ifeq ($(BUILD_G729),1)
LOCAL_CFLAGS += -DHAVE_G729
LOCAL_SHARED_LIBRARIES += libbcg729
LOCAL_STATIC_LIBRARIES += libmsbcg729
endif
ifeq ($(LINPHONE_VIDEO),1)
LOCAL_LDLIBS += -lGLESv2
LOCAL_STATIC_LIBRARIES += libvpx
ifeq ($(BUILD_X264),1)
LOCAL_STATIC_LIBRARIES += \
libmsx264 \
libx264
endif
LOCAL_SHARED_LIBRARIES += \
libavcodec \
libswscale \
@ -153,47 +34,8 @@ LOCAL_SHARED_LIBRARIES += \
libavutil
endif
LOCAL_STATIC_LIBRARIES += libspeex
ifeq ($(BUILD_SRTP), 1)
LOCAL_C_INCLUDES += $(SRTP_C_INCLUDE)
endif
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
LOCAL_CFLAGS += -DHAVE_ILBC=1
LOCAL_STATIC_LIBRARIES += libmsilbc
endif
LOCAL_C_INCLUDES += $(LIBLINPHONE_EXTENDED_C_INCLUDES)
LOCAL_WHOLE_STATIC_LIBRARIES += $(LIBLINPHONE_EXTENDED_STATIC_LIBS)
LOCAL_SRC_FILES += $(LIBLINPHONE_EXTENDED_SRC_FILES)
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
LOCAL_SHARED_LIBRARIES += liblinssl liblincrypto
ifeq ($(BUILD_GPLV3_ZRTP),1)
LOCAL_SHARED_LIBRARIES += libzrtpcpp
endif
ifeq ($(BUILD_SRTP),1)
LOCAL_SHARED_LIBRARIES += libsrtp
endif
else
LOCAL_LDLIBS += -lz
#LOCAL_STATIC_LIBRARIES += libz libdl
LOCAL_STATIC_LIBRARIES += \
libssl-static libcrypto-static
ifeq ($(BUILD_GPLV3_ZRTP),1)
LOCAL_STATIC_LIBRARIES += libzrtpcpp-static
endif
ifeq ($(BUILD_SRTP),1)
LOCAL_STATIC_LIBRARIES += libsrtp-static
endif
endif
LOCAL_MODULE := liblinphone
include $(BUILD_SHARED_LIBRARY)
$(call import-module,android/cpufeatures)

197
build/android/common.mk Normal file
View file

@ -0,0 +1,197 @@
##
## Android.mk -Android build script-
##
##
## Copyright (C) 2010 Belledonne Communications, Grenoble, France
##
## 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.
##
LOCAL_CPP_EXTENSION := .cc
LOCAL_SRC_FILES := \
linphonecore.c \
misc.c \
enum.c \
presence.c \
proxy.c \
friend.c \
authentication.c \
lpconfig.c \
chat.c \
sipsetup.c \
siplogin.c \
address.c \
linphonecore_jni.cc \
sal.c \
sal_eXosip2.c \
sal_eXosip2_presence.c \
sal_eXosip2_sdp.c \
offeranswer.c \
callbacks.c \
linphonecall.c \
conference.c \
ec-calibrator.c \
linphone_tunnel.cc
ifndef MY_LOG_DOMAIN
MY_LOG_DOMAIN = \"Linphone\"
endif
ifndef LINPHONE_VERSION
LINPHONE_VERSION = "Devel"
endif
LOCAL_CFLAGS += \
-D_BYTE_ORDER=_LITTLE_ENDIAN \
-DORTP_INET6 \
-DINET6 \
-DOSIP_MT \
-DHAVE_EXOSIP_GET_VERSION \
-DHAVE_EXOSIP_RESET_TRANSPORTS \
-DENABLE_TRACE \
-DLINPHONE_VERSION=\"$(LINPHONE_VERSION)\" \
-DLINPHONE_PLUGINS_DIR=\"\\tmp\" \
-DLOG_DOMAIN=$(MY_LOG_DOMAIN) \
-DHAVE_EXOSIP_TRYLOCK=1 \
-DHAVE_EXOSIP_TLS_VERIFY_CERTIFICATE=1
LOCAL_CFLAGS += -DIN_LINPHONE
ifeq ($(LINPHONE_VIDEO),1)
LOCAL_CFLAGS += -DVIDEO_ENABLED
ifeq ($(BUILD_X264),1)
LOCAL_CFLAGS += -DHAVE_X264
endif
endif
ifeq ($(USE_JAVAH),1)
LOCAL_CFLAGS += -DUSE_JAVAH
endif
LOCAL_C_INCLUDES += \
$(LOCAL_PATH) \
$(LOCAL_PATH)/include \
$(LOCAL_PATH)/../oRTP/include \
$(LOCAL_PATH)/../mediastreamer2/include \
$(LOCAL_PATH)/../../externals/exosip/include \
$(LOCAL_PATH)/../../externals/osip/include \
$(LOCAL_PATH)/../../../gen
LOCAL_LDLIBS += -llog -ldl
LOCAL_STATIC_LIBRARIES := \
cpufeatures \
libmediastreamer2 \
libortp \
libeXosip2 \
libosip2 \
libgsm
ifeq ($(BUILD_TUNNEL),1)
LOCAL_CFLAGS +=-DTUNNEL_ENABLED
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../tunnel/include $(LOCAL_PATH)/../../tunnel/src
LOCAL_SRC_FILES += TunnelManager.cc
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
LOCAL_SHARED_LIBRARIES += libtunnelclient
else
LOCAL_STATIC_LIBRARIES += libtunnelclient
endif
endif
_BUILD_AMR=0
ifneq ($(BUILD_AMRNB), 0)
_BUILD_AMR=1
endif
ifneq ($(BUILD_AMRWB), 0)
_BUILD_AMR=1
endif
ifneq ($(_BUILD_AMR), 0)
LOCAL_CFLAGS += -DHAVE_AMR
LOCAL_STATIC_LIBRARIES += \
libmsamr \
libopencoreamr
endif
ifneq ($(BUILD_AMRWB), 0)
LOCAL_STATIC_LIBRARIES += \
libvoamrwbenc
endif
ifeq ($(BUILD_SILK),1)
LOCAL_CFLAGS += -DHAVE_SILK
LOCAL_STATIC_LIBRARIES += libmssilk
endif
ifeq ($(BUILD_G729),1)
LOCAL_CFLAGS += -DHAVE_G729
LOCAL_SHARED_LIBRARIES += libbcg729
LOCAL_STATIC_LIBRARIES += libmsbcg729
endif
ifeq ($(LINPHONE_VIDEO),1)
LOCAL_LDLIBS += -lGLESv2
LOCAL_STATIC_LIBRARIES += libvpx
ifeq ($(BUILD_X264),1)
LOCAL_STATIC_LIBRARIES += \
libmsx264 \
libx264
endif
endif
LOCAL_STATIC_LIBRARIES += libspeex
ifeq ($(BUILD_SRTP), 1)
LOCAL_C_INCLUDES += $(SRTP_C_INCLUDE)
endif
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
LOCAL_CFLAGS += -DHAVE_ILBC=1
LOCAL_STATIC_LIBRARIES += libmsilbc
endif
LOCAL_C_INCLUDES += $(LIBLINPHONE_EXTENDED_C_INCLUDES)
LOCAL_WHOLE_STATIC_LIBRARIES += $(LIBLINPHONE_EXTENDED_STATIC_LIBS)
LOCAL_SRC_FILES += $(LIBLINPHONE_EXTENDED_SRC_FILES)
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
LOCAL_SHARED_LIBRARIES += liblinssl liblincrypto
ifeq ($(BUILD_GPLV3_ZRTP),1)
LOCAL_SHARED_LIBRARIES += libzrtpcpp
endif
ifeq ($(BUILD_SRTP),1)
LOCAL_SHARED_LIBRARIES += libsrtp
endif
else
LOCAL_LDLIBS += -lz
#LOCAL_STATIC_LIBRARIES += libz libdl
LOCAL_STATIC_LIBRARIES += \
libssl-static libcrypto-static
ifeq ($(BUILD_GPLV3_ZRTP),1)
LOCAL_STATIC_LIBRARIES += libzrtpcpp-static
endif
ifeq ($(BUILD_SRTP),1)
LOCAL_STATIC_LIBRARIES += libsrtp-static
endif
endif

View file

@ -1,6 +1,6 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT([linphone],[3.5.2],[linphone-developers@nongnu.org])
AC_INIT([linphone],[3.5.99.0],[linphone-developers@nongnu.org])
AC_CANONICAL_SYSTEM
AC_CONFIG_SRCDIR([coreapi/linphonecore.c])
@ -17,7 +17,7 @@ if test "$LINPHONE_EXTRA_VERSION" != "" ;then
LINPHONE_VERSION=$LINPHONE_VERSION.${LINPHONE_EXTRA_VERSION}
fi
LIBLINPHONE_SO_CURRENT=4 dnl increment this number when you add/change/remove an interface
LIBLINPHONE_SO_CURRENT=5 dnl increment this number when you add/change/remove an interface
LIBLINPHONE_SO_REVISION=0 dnl increment this number when you change source code, without changing interfaces; set to 0 when incrementing CURRENT
LIBLINPHONE_SO_AGE=0 dnl increment this number when you add an interface, set to 0 if you remove an interface
@ -32,9 +32,9 @@ AC_MSG_NOTICE([licensed under the terms of the General Public License (GPL)])
AM_INIT_AUTOMAKE
AC_SUBST([LIBTOOL_DEPS])
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])],)
AC_SUBST([docdir], [${datadir}/doc])
AC_CONFIG_HEADER(config.h)
AC_CONFIG_MACRO_DIR([m4])
AC_SUBST([mkdir_p])
AC_ISC_POSIX
AC_PROG_CC
AC_PROG_CXX
@ -61,7 +61,7 @@ case $target in
CONSOLE_FLAGS="-mconsole"
mingw_found=yes
;;
armv6-apple-darwin|armv7-apple-darwin|i386-apple-darwin)
armv6-apple-darwin|armv7-apple-darwin|i386-apple-darwin|armv7s-apple-darwin)
CFLAGS="$CFLAGS -DTARGET_OS_IPHONE "
build_tests=no
ios_found=yes
@ -102,9 +102,14 @@ AC_SUBST(ALL_LINGUAS)
AC_DEFINE_UNQUOTED(LINPHONE_ALL_LANGS, "$ALL_LINGUAS", [All supported languages])
if test "$mingw_found" != "yes" ; then
dnl gettext macro does not work properly under mingw. And we want to use the one provided by GTK.
AM_GNU_GETTEXT([external])
LIBS="$LIBS $LIBINTL"
dnl gettext macro does not work properly under mingw. And we want to use the one provided by GTK.
dnl AM_GNU_GETTEXT pollutes CPPFLAGS: workaround this.
CPPFLAGS_save=$CPPFLAGS
AM_GNU_GETTEXT([external])
AC_SUBST(INTLLIBS)
CPPFLAGS=$CPPFLAGS_save
LIBS="$LIBS $LIBINTL"
else
AC_DEFINE(ENABLE_NLS,1,[Tells whether localisation is possible])
AC_DEFINE(HAVE_GETTEXT,1,[Tells wheter localisation is possible])
@ -113,31 +118,58 @@ fi
GETTEXT_PACKAGE=linphone
AC_SUBST(GETTEXT_PACKAGE)
AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE",[The name of the gettext package name])
AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE",[The name of the gettext package name])
dnl AC_CHECK_LIB(intl,libintl_gettext)
AC_CHECK_FUNCS([get_current_dir_name strndup stpcpy] )
AC_ARG_ENABLE(x11,
[ --disable-x11 Disable X11 support],
[case "${enableval}" in
yes) enable_x11=true ;;
no) enable_x11=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --disable-x11) ;;
esac],[enable_x11=true])
[AS_HELP_STRING([--disable-x11], [Disable X11 support (default=no)])],
[case "${enableval}" in
yes) enable_x11=true ;;
no) enable_x11=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --disable-x11) ;;
esac],[enable_x11=true])
dnl conditionnal build of console interface.
AC_ARG_ENABLE(console_ui,
[ --enable-console_ui=[yes/no] Turn on or off compilation of console interface [default=yes]],
[AS_HELP_STRING([--enable-console_ui=[yes/no]], [Turn on or off compilation of console interface (default=yes)])],
[case "${enableval}" in
yes) console_ui=true ;;
no) console_ui=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-console_ui) ;;
esac],[console_ui=true])
dnl conditionnal build of tools.
AC_ARG_ENABLE(tools,
[AS_HELP_STRING([--enable-tools=[yes/no]], [Turn on or off compilation of console interface (default=yes)])],
[case "${enableval}" in
yes) build_tools=true ;;
no) build_tools=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-tools) ;;
esac],[build_tools=check])
dnl check libxml2 (needed for tools)
if test "$build_tools" != "false" ; then
PKG_CHECK_MODULES(LIBXML2, [libxml-2.0],[],
[
if test "$build_tools" = "true" ; then
AC_MSG_ERROR([Could not found libxml2, tools cannot be compiled.])
else
build_tools=false
fi
])
fi
AM_CONDITIONAL(BUILD_TOOLS, test x$build_tools != xfalse)
if test "$build_tools" != "false" ; then
build_tools=true
AC_DEFINE(BUILD_TOOLS, 1, [Define if tools enabled] )
fi
dnl conditionnal build of gtk interface.
AC_ARG_ENABLE(gtk_ui,
[ --enable-gtk_ui=[yes/no] Turn on or off compilation of gtk interface [default=yes]],
[AS_HELP_STRING([--enable-gtk_ui=[yes/no]], [Turn on or off compilation of gtk interface (default=yes)])],
[case "${enableval}" in
yes) gtk_ui=true ;;
no) gtk_ui=false ;;
@ -155,12 +187,12 @@ else
fi
AC_ARG_ENABLE(notify,
[ --enable-notify=[yes/no] Enable libnotify support [default=yes]],
[case "${enableval}" in
yes) notify=true ;;
no) notify=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-notify) ;;
esac],[notify=true])
[AS_HELP_STRING([--enable-notify=[yes/no]], [Enable libnotify support (default=yes)])],
[case "${enableval}" in
yes) notify=true ;;
no) notify=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-notify) ;;
esac],[notify=true])
dnl conditionnal build of the notify library
if test "$gtk_ui" = "true" ; then
@ -200,14 +232,14 @@ case "$host_cpu" in
;;
esac
AC_ARG_WITH( configdir,
[ --with-configdir Set a APPDATA subdir where linphone is supposed to find its config (windows only) ],
AC_ARG_WITH(configdir,
[AS_HELP_STRING([--with-configdir], [Set a APPDATA subdir where linphone is supposed to find its config (windows only)])],
[ configdir=${withval}],[ configdir="Linphone" ])
AC_DEFINE_UNQUOTED(LINPHONE_CONFIG_DIR,"$configdir",[Windows appdata subdir where linphonerc can be found])
AC_ARG_ENABLE(relativeprefix,
[ --enable-relativeprefix Build a linphone that finds its resources relatively to the directory where it is installed],
[AS_HELP_STRING([--enable-relativeprefix], [Build a linphone that finds its resources relatively to the directory where it is installed])],
[case "${enableval}" in
yes) relativeprefix=yes ;;
no) relativeprefix=no ;;
@ -215,7 +247,7 @@ AC_ARG_ENABLE(relativeprefix,
esac],[relativeprefix=guess])
AC_ARG_ENABLE(date,
[ --enable-date Use build date in internal version number],
[AS_HELP_STRING([--enable-date], [Use build date in internal version number])],
[case "${enableval}" in
yes) use_date=yes ;;
no) use_date=no ;;
@ -229,7 +261,7 @@ fi
dnl enable ipv6 support
AC_ARG_ENABLE(ipv6,
[ --enable-ipv6 Turn on ipv6 support],
[AS_HELP_STRING([--enable-ipv6], [Turn on ipv6 support])],
[case "${enableval}" in
yes) ipv6=true;;
no) ipv6=false;;
@ -241,9 +273,26 @@ if test x$ipv6 = xtrue ; then
fi
AC_SUBST(IPV6_CFLAGS)
dnl enable timestamp support
AC_ARG_ENABLE(ntp-timestamp,
[AS_HELP_STRING([--enable-ntp-timestamp], [Turn on NTP timestamping on received packet])],
[case "${enableval}" in
yes) ntptimestamp=true;;
no) ntptimestamp=false;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-ntp-timestamp) ;;
esac],[ntptimestamp=false])
AC_ARG_ENABLE(debug,
[AS_HELP_STRING([--enable-debug=[yes/no]], [Enables the display of traces showing the execution of the library. (default=yes)])],
[case "${enableval}" in
yes) debug_enabled=yes;;
no) debug_enabled=no;;
*) AC_MSG_ERROR("Bad value for --enable-debug");;
esac],[debug_enabled=no])
dnl enable truespeech codec support
AC_ARG_ENABLE(truespeech,
[ --enable-truespeech Turn on TrueSpeech support (x86 only)],
[AS_HELP_STRING([--enable-truespeech], [Turn on TrueSpeech support (x86 only)])],
[case "${enableval}" in
yes) truespeech=true;;
no) truespeech=false;;
@ -257,11 +306,11 @@ AC_SUBST(TRUESPEECH_CFLAGS)
AM_CONDITIONAL([BUILD_TRUESPEECH], [test x$truespeech = xtrue])
AC_ARG_ENABLE(nonstandard-gsm,
[ --enable-nonstandard-gsm Enable GSM codec at nonstandard rates (11025hz, 16000hz)],
[AS_HELP_STRING([--enable-nonstandard-gsm], [Enable GSM codec at nonstandard rates (11025hz, 16000hz)])],
[case "${enableval}" in
yes) exotic_gsm=yes
AC_DEFINE(ENABLE_NONSTANDARD_GSM,1,[Defined when using gsm at nonstandard rates])
;;
AC_DEFINE(ENABLE_NONSTANDARD_GSM,1,[Defined when using gsm at nonstandard rates])
;;
no) exotic_gsm=no ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-nonstandard-gsm) ;;
esac],[exotic_gsm=no])
@ -269,7 +318,7 @@ AC_ARG_ENABLE(nonstandard-gsm,
dnl support for RSVP (by Vincent Maury)
AC_ARG_ENABLE(rsvp,
[ --enable-rsvp enable support for QoS reservations.],
[AS_HELP_STRING([--enable-rsvp], [Enable support for QoS reservations.])],
AC_DEFINE(VINCENT_MAURY_RSVP,1,[Tell whether RSVP support
should be compiled.]) )
@ -308,12 +357,12 @@ LP_CHECK_OSIP2
dnl conditionnal build for ssl
AC_ARG_ENABLE(ssl,
[ --enable-ssl Turn on ssl support compiling. Required for sip tls. default = false],
[case "${enableval}" in
yes) build_ssl=true ;;
no) build_ssl=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-ssl) ;;
esac],[build_ssl=false])
[AS_HELP_STRING([--enable-ssl], [Turn on ssl support compiling. Required for sip tls. (default=false)])],
[case "${enableval}" in
yes) build_ssl=true ;;
no) build_ssl=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-ssl) ;;
esac],[build_ssl=false])
if test "$build_ssl" = "true"; then
PKG_CHECK_MODULES(OPENSSL, libssl >= 0.9.8)
@ -344,16 +393,16 @@ fi
dnl conditionnal build of video support
AC_ARG_ENABLE(video,
[ --enable-video Turn on video support compiling],
[case "${enableval}" in
yes) video=true ;;
no) video=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-video) ;;
esac],[video=true])
[AS_HELP_STRING([--enable-video], [Turn on video support compiling])],
[case "${enableval}" in
yes) video=true ;;
no) video=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-video) ;;
esac],[video=true])
AC_ARG_WITH( ffmpeg,
[ --with-ffmpeg Sets the installation prefix of ffmpeg, needed for video support. [default=/usr] ],
[ ffmpegdir=${withval}],[ ffmpegdir=/usr ])
[AS_HELP_STRING([--with-ffmpeg], [Sets the installation prefix of ffmpeg, needed for video support. (default=/usr)])],
[ ffmpegdir=${withval}],[ ffmpegdir=/usr ])
if test "$video" = "true"; then
@ -370,7 +419,7 @@ if test "$video" = "true"; then
fi
AC_ARG_ENABLE(alsa,
[ --enable-alsa Turn on alsa native support compiling],
[AS_HELP_STRING([--enable-alsa], [Turn on alsa native support compiling])],
[case "${enableval}" in
yes) alsa=true ;;
no) alsa=false ;;
@ -378,7 +427,7 @@ AC_ARG_ENABLE(alsa,
esac],[alsa=true])
AC_ARG_ENABLE(zrtp,
[ --enable-zrtp Turn on zrtp support ],
[AS_HELP_STRING([--enable-zrtp], [Turn on zrtp support])],
[case "${enableval}" in
yes) zrtp=true ;;
no) zrtp=false ;;
@ -387,7 +436,7 @@ AC_ARG_ENABLE(zrtp,
AC_ARG_ENABLE(portaudio,
[ --enable-portaudio Turn on portaudio native support compiling],
[AS_HELP_STRING([--enable-portaudio], [Turn on portaudio native support compiling])],
[case "${enableval}" in
yes) portaudio=true ;;
no) portaudio=false ;;
@ -396,8 +445,10 @@ AC_ARG_ENABLE(portaudio,
dnl build console if required
AM_CONDITIONAL(BUILD_CONSOLE, test x$console_ui = xtrue)
dnl special things for arm-linux cross compilation toolchain
AM_CONDITIONAL(ARMBUILD, test x$use_arm_toolchain = xyes)
dnl compilation of gtk user interface
AM_CONDITIONAL(BUILD_GTK_UI, [test x$gtk_ui = xtrue ] )
AM_CONDITIONAL(BUILD_WIN32, test x$mingw_found = xyes )
@ -417,7 +468,7 @@ if test "$has_sighandler_t" = "yes" ; then
fi
AC_ARG_ENABLE(assistant,
[ --enable-assistant Turn on assistant compiling],
[AS_HELP_STRING([--enable-assistant], [Turn on assistant compiling])],
[case "${enableval}" in
yes) build_wizard=true ;;
no) build_wizard=false ;;
@ -426,7 +477,7 @@ AC_ARG_ENABLE(assistant,
dnl check libsoup (needed for wizard)
if test "$build_wizard" != "false" ; then
PKG_CHECK_MODULES(LIBSOUP, [libsoup-2.4 >= 2.26],[build_wizard=true],
PKG_CHECK_MODULES(LIBSOUP, [libsoup-2.4 >= 2.26],[],
[
if test "$build_wizard" = "true" ; then
AC_MSG_ERROR([Could not found libsoup, assistant cannot be compiled.])
@ -435,11 +486,22 @@ if test "$build_wizard" != "false" ; then
fi
])
fi
if test "$build_wizard" != "false" ; then
PKG_CHECK_MODULES(LIBGTKWIZARD, [gtk+-2.0 >= 2.22.0],[],
[
if test "$build_wizard" = "true" ; then
AC_MSG_ERROR([gtk+-2.0 < 2.22.0, assistant cannot be compiled.])
else
build_wizard=false
fi
])
fi
AC_SUBST(LIBSOUP_CFLAGS)
AC_SUBST(LIBSOUP_LIBS)
AM_CONDITIONAL(BUILD_WIZARD, test x$build_wizard = xtrue)
if test "$build_wizard" = "true" ; then
AC_DEFINE( BUILD_WIZARD, 1, [Define if wizard enabled] )
AM_CONDITIONAL(BUILD_WIZARD, test x$build_wizard != xfalse)
if test "$build_wizard" != "false" ; then
build_wizard=true
AC_DEFINE(BUILD_WIZARD, 1, [Define if wizard enabled] )
fi
AC_CHECK_HEADERS(libudev.h)
@ -480,7 +542,7 @@ AS_CASE($enable_external_mediastreamer,
AC_CONFIG_SUBDIRS( mediastreamer2 )
MEDIASTREAMER_DIR=${top_srcdir}/mediastreamer2
MEDIASTREAMER_CFLAGS="-I\$(top_srcdir)/mediastreamer2/include"
MEDIASTREAMER_LIBS="\$(top_builddir)/mediastreamer2/src/libmediastreamer.la"
MEDIASTREAMER_LIBS="\$(top_builddir)/mediastreamer2/src/libmediastreamer_base.la \$(top_builddir)/mediastreamer2/src/libmediastreamer_voip.la"
dnl need to temporary change quotes to allow square brackets
changequote(<<, >>)
MS2_VERSION=`grep -e '^.C_INIT(' $MEDIASTREAMER_DIR/configure.ac | sed -e 's:\([^(]\+\)(\[mediastreamer\],\[\(.*\)\]):\2:g'`
@ -497,7 +559,7 @@ AC_SUBST([MS2_DIR])
AC_ARG_ENABLE(tunnel,
[ --enable-tunnel=[yes/no] Turn on compilation of tunnel support [default=no]],
[AS_HELP_STRING([--enable-tunnel=[yes/no]], [Turn on compilation of tunnel support (default=no)])],
[case "${enableval}" in
yes) enable_tunnel=true ;;
no) enable_tunnel=false ;;
@ -555,7 +617,7 @@ LINPHONE_PLUGINS_DIR="${package_prefix}/lib/liblinphone/plugins"
AC_SUBST(LINPHONE_PLUGINS_DIR)
AC_ARG_ENABLE(external-ortp,
[ --enable-external-ortp Use external oRTP library],
[AS_HELP_STRING([--enable-external-ortp], [Use external oRTP library])],
[case "${enableval}" in
yes) external_ortp=true ;;
no) external_ortp=false ;;
@ -572,6 +634,9 @@ else
if test x$ac_cv_c_bigendian = xyes ; then
ORTP_CFLAGS="$ORTP_CFLAGS -DORTP_BIGENDIAN"
fi
if test x$ntptimestamp = xtrue ; then
ORTP_CFLAGS="$ORTP_CFLAGS -DORTP_TIMESTAMP"
fi
ORTP_DIR=oRTP
changequote(<<, >>)
ORTP_VERSION=`grep -E ^[AC]+_INIT ${top_srcdir}/oRTP/configure.ac | sed -e 's:^.*_INIT(.*,\[\(.*\)\]):\1:g'`
@ -582,9 +647,14 @@ AC_SUBST(ORTP_LIBS)
AC_SUBST([ORTP_VERSION])
AC_SUBST([ORTP_DIR])
AC_ARG_ENABLE([tests],
AS_HELP_STRING([--disable-tests], [Disable the tests]))
AM_CONDITIONAL([ENABLE_TESTS], [test "x$enable_tests" != "xno"])
AC_ARG_ENABLE(tests_enabled,
[AS_HELP_STRING([--disable-tests], [Disable compilation of tests])],
[case "${enableval}" in
yes) tests_enabled=true ;;
no) tests_enabled=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --disable-tests) ;;
esac],[tests_enabled=false])
AM_CONDITIONAL(ENABLE_TESTS, test x$tests_enabled = xyes)
PKG_CHECK_MODULES(CUNIT, cunit, [found_cunit=yes],[found_cunit=no])
@ -635,9 +705,11 @@ share/fr/Makefile
share/it/Makefile
share/ja/Makefile
share/cs/Makefile
share/xml/Makefile
share/linphone.pc
share/linphone.desktop
scripts/Makefile
tools/Makefile
linphone.spec
linphone.iss
])
@ -650,6 +722,7 @@ printf "* Video support\t\t\t%s\n" $video
printf "* GTK interface\t\t\t%s\n" $gtk_ui
printf "* Account assistant\t\t%s\n" $build_wizard
printf "* Console interface\t\t%s\n" $console_ui
printf "* Tools\t\t\t\t%s\n" $build_tools
printf "* zRTP encryption (GPLv3)\t%s\n" $zrtp
if test "$enable_tunnel" = "true" ; then
@ -662,4 +735,3 @@ else
fi
echo "Now type 'make' to compile, and then 'make install' as root to install it."

View file

@ -1,25 +1,32 @@
## Process this file with automake to produce Makefile.in
COMMON_CFLAGS=$(STRICT_OPTIONS) -DIN_LINPHONE -DENABLE_TRACE -D_ORTP_SOURCE $(VIDEO_CFLAGS) $(READLINE_CFLAGS) $(OSIP_CFLAGS)
AM_CPPFLAGS=\
-I$(top_srcdir) \
-I$(top_srcdir)/coreapi \
-I$(top_srcdir)/exosip
COMMON_CFLAGS=\
-DIN_LINPHONE \
-DENABLE_TRACE \
-D_ORTP_SOURCE \
$(STRICT_OPTIONS) \
$(VIDEO_CFLAGS) \
$(READLINE_CFLAGS) \
$(OSIP_CFLAGS) \
$(ORTP_CFLAGS) \
$(MEDIASTREAMER_CFLAGS)
if BUILD_CONSOLE
INCLUDES = \
-I$(top_srcdir)\
-I$(top_srcdir)/coreapi\
$(ORTP_CFLAGS) \
-I$(top_srcdir)/exosip \
$(MEDIASTREAMER_CFLAGS)
bin_PROGRAMS = linphonec linphonecsh
bin_PROGRAMS=linphonec linphonecsh
if BUILD_WIN32
bin_PROGRAMS += linphoned
bin_PROGRAMS+=linphoned
endif
linphonec_SOURCES = linphonec.c linphonec.h commands.c
linphonec_SOURCES=linphonec.c linphonec.h commands.c
linphonec_CFLAGS=$(COMMON_CFLAGS) $(CONSOLE_FLAGS)
linphonec_LDADD = $(top_builddir)/coreapi/liblinphone.la $(READLINE_LIBS) \
linphonec_LDADD=$(top_builddir)/coreapi/liblinphone.la $(READLINE_LIBS) \
$(MEDIASTREAMER_LIBS) \
$(ORTP_LIBS) \
$(SPEEX_LIBS) \
@ -28,15 +35,15 @@ linphonec_LDADD = $(top_builddir)/coreapi/liblinphone.la $(READLINE_LIBS) \
if BUILD_WIN32
#special build of linphonec to detach from the windows console
linphoned_SOURCES = $(linphonec_SOURCES)
linphoned_SOURCES=$(linphonec_SOURCES)
linphoned_CFLAGS=$(COMMON_CFLAGS) $(GUI_FLAGS)
linphoned_LDADD=$(linphonec_LDADD)
endif
linphonecsh_SOURCES = shell.c
linphonecsh_CFLAGS = $(CONSOLE_FLAGS)
linphonecsh_LDADD = $(ORTP_LIBS)
linphonecsh_SOURCES=shell.c
linphonecsh_CFLAGS=$(COMMON_CFLAGS) $(CONSOLE_FLAGS)
linphonecsh_LDADD=$(ORTP_LIBS)
endif

View file

@ -850,6 +850,16 @@ lpc_cmd_firewall(LinphoneCore *lc, char *args)
{
linphone_core_set_firewall_policy(lc,LinphonePolicyNoFirewall);
}
else if (strcmp(args,"ice")==0)
{
setting = linphone_core_get_stun_server(lc);
if ( ! setting )
{
linphonec_out("No stun server address is defined, use 'stun <address>' first\n");
return 1;
}
linphone_core_set_firewall_policy(lc,LinphonePolicyUseIce);
}
else if (strcmp(args,"stun")==0)
{
setting = linphone_core_get_stun_server(lc);
@ -883,6 +893,9 @@ lpc_cmd_firewall(LinphoneCore *lc, char *args)
case LinphonePolicyUseNatAddress:
linphonec_out("Using supplied nat address %s.\n", setting ? setting : linphone_core_get_nat_address(lc));
break;
case LinphonePolicyUseIce:
linphonec_out("Using ice with stun server %s to discover firewall address\n", setting ? setting : linphone_core_get_stun_server(lc));
break;
}
return 1;
}

View file

@ -346,7 +346,7 @@ static void linphonec_call_state_changed(LinphoneCore *lc, LinphoneCall *call, L
linphonec_out("Resuming call %i with %s.\n", id, from);
break;
case LinphoneCallStreamsRunning:
linphonec_out("Media streams established with %s for call %i.\n", from,id);
linphonec_out("Media streams established with %s for call %i (%s).\n", from,id,( linphone_call_params_video_enabled( linphone_call_get_current_params(call)) ? "video":"audio"));
break;
case LinphoneCallPausing:
linphonec_out("Pausing call %i with %s.\n", id, from);

View file

@ -29,13 +29,12 @@
#include "config.h"
#endif
#ifdef HAVE_READLINE
#ifdef HAVE_READLINE_H
#include <readline.h>
#define HAVE_READLINE
#else
#ifdef HAVE_READLINE_READLINE_H
#include <readline/readline.h>
#define HAVE_READLINE
#endif
#endif
#ifdef HAVE_HISTORY_H
@ -45,6 +44,7 @@
#include <readline/history.h>
#endif
#endif
#endif
#undef PARAMS
/**************************************************************************

View file

@ -97,7 +97,7 @@ void call_accept(Call *call)
osip_message_set_content_type(msg,"application/sdp");
osip_message_set_body(msg,call->sdpc->answerstr,strlen(call->sdpc->answerstr));
eXosip_call_send_answer(call->tid,200,msg);
call->audio_stream=audio_stream_new(call->audio.localport,call->root->ipv6);
call->audio_stream=audio_stream_new(call->audio.localport,call->audio.localport+1,call->root->ipv6);
audio_stream_start_with_files(call->audio_stream, call->profile,
call->audio.remaddr,call->audio.remoteport,call->audio.remoteport+1,
call->audio.pt,20,hellofile,record_file);

1
coreapi/.gitignore vendored
View file

@ -5,3 +5,4 @@ Makefile.in
*.lo
*.la
*.loT
liblinphone_gitversion.h

View file

@ -1,7 +1,17 @@
GITVERSION_FILE=liblinphone_gitversion.h
GITVERSION_FILE_TMP=liblinphone_gitversion.h.tmp
GITDESCRIBE=`git describe`
GITREVISION=`git rev-parse HEAD`
ECHO=/bin/echo
SUBDIRS=. help
EXTRA_DIST=linphonecore_jni.cc
EXTRA_DIST=linphonecore_jni.cc $(GITVERSION_FILE)
BUILT_SOURCES=$(GITVERSION_FILE)
CLEANFILES=$(GITVERSION_FILE)
## Process this file with automake to produce Makefile.in
linphone_includedir=$(includedir)/linphone
@ -12,10 +22,6 @@ if BUILD_TUNNEL
linphone_include_HEADERS+=linphone_tunnel.h
endif
INCLUDES = \
-I$(top_srcdir)
lib_LTLIBRARIES=liblinphone.la
liblinphone_la_SOURCES=\
@ -38,7 +44,9 @@ liblinphone_la_SOURCES=\
lsd.c linphonecore_utils.h \
ec-calibrator.c \
conference.c \
linphone_tunnel.cc
linphone_tunnel.cc \
$(GITVERSION_FILE)
if USE_BELLESIP
liblinphone_la_SOURCES+= bellesip_sal/sal_address_impl.c \
bellesip_sal/sal_impl.c \
@ -73,7 +81,7 @@ liblinphone_la_LIBADD= \
$(LIBSOUP_LIBS)
if BUILD_TESTS
noinst_PROGRAMS=test_lsd test_ecc
noinst_PROGRAMS=test_lsd test_ecc test_numbers
test_lsd_SOURCES=test_lsd.c
@ -82,10 +90,17 @@ test_lsd_LDADD=liblinphone.la $(liblinphone_la_LIBADD)
test_ecc_SOURCES=test_ecc.c
test_ecc_LDADD=liblinphone.la $(liblinphone_la_LIBADD)
test_numbers_SOURCES=test_numbers.c
test_numbers_LDADD=liblinphone.la $(liblinphone_la_LIBADD)
endif
AM_CPPFLAGS=\
-I$(top_srcdir)
AM_CFLAGS=$(STRICT_OPTIONS) -DIN_LINPHONE \
AM_CFLAGS=\
$(STRICT_OPTIONS) -DIN_LINPHONE \
$(ORTP_CFLAGS) \
$(MEDIASTREAMER_CFLAGS) \
$(SIPSTACK_CFLAGS) \
@ -102,3 +117,21 @@ AM_CFLAGS+= -DBUILD_WIZARD
endif
AM_CXXFLAGS=$(AM_CFLAGS)
make_gitversion_h:
if test "$(GITDESCRIBE)" != "" ; then \
$(ECHO) -n "#define LIBLINPHONE_GIT_VERSION \"$(GITDESCRIBE)\"" > $(GITVERSION_FILE_TMP) ; \
elif test "$(GITREVISION)" != "" ; then \
$(ECHO) -n "#define LIBLINPHONE_GIT_VERSION \"$(LINPHONE_VERSION)_$(GITREVISION)\"" > $(GITVERSION_FILE_TMP) ; \
else \
$(ECHO) -n "" > $(GITVERSION_FILE_TMP) ; \
fi
if test ! -f $(srcdir)/$(GITVERSION_FILE) ; then \
cp -f $(GITVERSION_FILE_TMP) $(srcdir)/$(GITVERSION_FILE) ; \
fi
if test "`cat $(GITVERSION_FILE_TMP)`" != "`cat $(srcdir)/$(GITVERSION_FILE)`" ; then \
cp -f $(GITVERSION_FILE_TMP) $(srcdir)/$(GITVERSION_FILE) ; \
fi
rm -f $(GITVERSION_FILE_TMP) ;
$(GITVERSION_FILE): make_gitversion_h

View file

@ -25,20 +25,22 @@
using namespace belledonnecomm;
using namespace ::std;
Mutex TunnelManager::sMutex;
int TunnelManager::eXosipSendto(int fd,const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen,void* userdata){
TunnelManager* lTunnelMgr=(TunnelManager*)userdata;
int err;
sMutex.lock();
if (lTunnelMgr->mSipSocket==NULL){
sMutex.unlock();
return len;//let ignore the error
return len;
}
err=lTunnelMgr->mSipSocket->sendto(buf,len,to,tolen);
lTunnelMgr->mSipSocket->sendto(buf,len,to,tolen);
sMutex.unlock();
return err;
//ignore the error in all cases, retransmissions might be successful.
return len;
}
int TunnelManager::eXosipRecvfrom(int fd, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen,void* userdata){
@ -57,12 +59,12 @@ int TunnelManager::eXosipRecvfrom(int fd, void *buf, size_t len, int flags, stru
int TunnelManager::eXosipSelect(int max_fds, fd_set *s1, fd_set *s2, fd_set *s3, struct timeval *tv,void* userdata){
struct timeval begin,cur;
TunnelManager* lTunnelMgr=(TunnelManager*)userdata;
if (tv!=0 && tv->tv_sec){
if (s1 && tv!=0 && tv->tv_sec){
/*this is the select from udp.c, the one that is interesting to us*/
NativeSocket udp_fd=(NativeSocket)eXosip_get_udp_socket();
NativeSocket controlfd=(NativeSocket)eXosip_get_control_fd();
FD_ZERO(s1);
FD_ZERO(s1);
gettimeofday(&begin,NULL);
do{
struct timeval abit;
@ -210,7 +212,6 @@ TunnelManager::TunnelManager(LinphoneCore* lc) :TunnelClientController()
mExosipTransport.recvfrom=eXosipRecvfrom;
mExosipTransport.sendto=eXosipSendto;
mExosipTransport.select=eXosipSelect;
mStateChanged=false;
linphone_core_add_iterate_hook(mCore,(LinphoneCoreIterateHook)sOnIterate,this);
mTransportFactories.audio_rtcp_func=sCreateRtpTransport;
mTransportFactories.audio_rtcp_func_data=this;
@ -240,12 +241,13 @@ void TunnelManager::stopClient(){
}
}
void TunnelManager::processTunnelEvent(){
void TunnelManager::processTunnelEvent(const Event &ev){
LinphoneProxyConfig* lProxy;
linphone_core_get_default_proxy(mCore, &lProxy);
if (mEnabled && mTunnelClient->isReady()){
ms_message("Tunnel is up, registering now");
ms_message("Tunnel is up, registering now");
linphone_core_set_firewall_policy(mCore,LinphonePolicyNoFirewall);
linphone_core_set_rtp_transport_factories(mCore,&mTransportFactories);
eXosip_transport_hook_register(&mExosipTransport);
//force transport to udp
@ -256,7 +258,7 @@ void TunnelManager::processTunnelEvent(){
lTransport.tls_port=0;
lTransport.dtls_port=0;
linphone_core_set_sip_transports(mCore, &lTransport);
linphone_core_set_sip_transports(mCore, &lTransport);
//register
if (lProxy) {
linphone_proxy_config_done(lProxy);
@ -275,7 +277,7 @@ void TunnelManager::waitUnRegistration(){
LinphoneProxyConfig* lProxy;
linphone_core_get_default_proxy(mCore, &lProxy);
if (lProxy && linphone_proxy_config_get_state(lProxy)==LinphoneRegistrationOk) {
int i;
int i=0;
linphone_proxy_config_edit(lProxy);
//make sure unregister is sent and authenticated
do{
@ -294,8 +296,9 @@ void TunnelManager::enable(bool isEnable) {
ms_message("Turning tunnel [%s]",(isEnable?"on":"off"));
if (isEnable && !mEnabled){
mEnabled=true;
//1 save transport
//1 save transport and firewall policy
linphone_core_get_sip_transports(mCore, &mRegularTransport);
mPreviousFirewallPolicy=linphone_core_get_firewall_policy(mCore);
//2 unregister
waitUnRegistration();
//3 insert tunnel
@ -310,8 +313,9 @@ void TunnelManager::enable(bool isEnable) {
linphone_core_set_rtp_transport_factories(mCore,NULL);
eXosip_transport_hook_register(NULL);
//Restore transport
//Restore transport and firewall policy
linphone_core_set_sip_transports(mCore, &mRegularTransport);
linphone_core_set_firewall_policy(mCore, mPreviousFirewallPolicy);
//register
LinphoneProxyConfig* lProxy;
linphone_core_get_default_proxy(mCore, &lProxy);
@ -323,15 +327,31 @@ void TunnelManager::enable(bool isEnable) {
}
void TunnelManager::tunnelCallback(bool connected, TunnelManager *zis){
zis->mStateChanged=true;
Event ev;
ev.mType=TunnelEvent;
ev.mData.mConnected=connected;
zis->postEvent(ev);
}
void TunnelManager::onIterate(){
mMutex.lock();
while(!mEvq.empty()){
Event ev=mEvq.front();
mEvq.pop();
mMutex.unlock();
if (ev.mType==TunnelEvent)
processTunnelEvent(ev);
else if (ev.mType==UdpMirrorClientEvent){
processUdpMirrorEvent(ev);
}
mMutex.lock();
}
mMutex.unlock();
}
/*invoked from linphone_core_iterate() */
void TunnelManager::sOnIterate(TunnelManager *zis){
if (zis->mStateChanged){
zis->mStateChanged=false;
zis->processTunnelEvent();
}
zis->onIterate();
}
#ifdef ANDROID
@ -372,26 +392,39 @@ void TunnelManager::enableLogs(bool isEnabled,LogHandler logHandler) {
bool TunnelManager::isEnabled() {
return mEnabled;
}
void TunnelManager::UdpMirrorClientListener(bool isUdpAvailable, void* data) {
TunnelManager* thiz = (TunnelManager*)data;
if (isUdpAvailable) {
void TunnelManager::processUdpMirrorEvent(const Event &ev){
if (ev.mData.mHaveUdp) {
LOGI("Tunnel is not required, disabling");
thiz->enable(false);
thiz->mAutoDetectStarted = false;
enable(false);
mAutoDetectStarted = false;
} else {
if (++thiz->mCurrentUdpMirrorClient !=thiz->mUdpMirrorClients.end()) {
//1 enable tunnable but also try backup server
if (mCurrentUdpMirrorClient !=mUdpMirrorClients.end()) {
// enable tunnel but also try backup server
LOGI("Tunnel is required, enabling; Trying backup udp mirror");
UdpMirrorClient &lUdpMirrorClient=*thiz->mCurrentUdpMirrorClient;
lUdpMirrorClient.start(TunnelManager::UdpMirrorClientListener,(void*)thiz);
UdpMirrorClient &lUdpMirrorClient=*mCurrentUdpMirrorClient;
lUdpMirrorClient.start(TunnelManager::sUdpMirrorClientCallback,(void*)this);
} else {
LOGI("Tunnel is required, enabling; no backup udp mirror available");
thiz->mAutoDetectStarted = false;
mAutoDetectStarted = false;
}
thiz->enable(true);
enable(true);
}
return;
}
void TunnelManager::postEvent(const Event &ev){
mMutex.lock();
mEvq.push(ev);
mMutex.unlock();
}
void TunnelManager::sUdpMirrorClientCallback(bool isUdpAvailable, void* data) {
TunnelManager* thiz = (TunnelManager*)data;
Event ev;
ev.mType=UdpMirrorClientEvent;
ev.mData.mHaveUdp=isUdpAvailable;
thiz->postEvent(ev);
}
void TunnelManager::autoDetect() {
@ -407,7 +440,7 @@ void TunnelManager::autoDetect() {
mAutoDetectStarted=true;
mCurrentUdpMirrorClient =mUdpMirrorClients.begin();
UdpMirrorClient &lUdpMirrorClient=*mCurrentUdpMirrorClient;
lUdpMirrorClient.start(TunnelManager::UdpMirrorClientListener,(void*)this);
lUdpMirrorClient.start(TunnelManager::sUdpMirrorClientCallback,(void*)this);
}

View file

@ -130,9 +130,21 @@ class UdpMirrorClient;
LinphoneCore *getLinphoneCore();
virtual void setHttpProxy(const char *host,int port, const char *username, const char *passwd);
private:
enum EventType{
UdpMirrorClientEvent,
TunnelEvent,
};
struct Event{
EventType mType;
union EventData{
bool mConnected;
bool mHaveUdp;
}mData;
};
typedef std::list<UdpMirrorClient> UdpMirrorClientList;
virtual bool isStarted();
virtual bool isReady() const;
void onIterate();
static int customSendto(struct _RtpTransport *t, mblk_t *msg , int flags, const struct sockaddr *to, socklen_t tolen);
static int customRecvfrom(struct _RtpTransport *t, mblk_t *msg, int flags, struct sockaddr *from, socklen_t *fromlen);
static int eXosipSendto(int fd,const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen,void* userdata);
@ -140,9 +152,11 @@ class UdpMirrorClient;
static int eXosipSelect(int nfds, fd_set *s1, fd_set *s2, fd_set *s3, struct timeval *tv,void* userdata);
static void tunnelCallback(bool connected, TunnelManager *zis);
static void sOnIterate(TunnelManager *zis);
static void UdpMirrorClientListener(bool result, void* data);
static void sUdpMirrorClientCallback(bool result, void* data);
void waitUnRegistration();
void processTunnelEvent();
void processTunnelEvent(const Event &ev);
void processUdpMirrorEvent(const Event &ev);
void postEvent(const Event &ev);
LinphoneCore* mCore;
LCSipTransports mRegularTransport;
TunnelSocket *mSipSocket;
@ -150,19 +164,21 @@ class UdpMirrorClient;
StateCallback mCallback;
void * mCallbackData;
bool mEnabled;
bool mStateChanged;
std::queue<Event> mEvq;
std::list <ServerAddr> mServerAddrs;
UdpMirrorClientList mUdpMirrorClients;
UdpMirrorClientList::iterator mCurrentUdpMirrorClient;
TunnelClient* mTunnelClient;
void stopClient();
Mutex mMutex;
static Mutex sMutex;
bool mAutoDetectStarted;
LinphoneRtpTransportFactories mTransportFactories;
std::string mHttpUserName;
std::string mHttpPasswd;
std::string mHttpProxyHost;
int mHttpProxyPort;
int mHttpProxyPort;
LinphoneFirewallPolicy mPreviousFirewallPolicy;
};
/**

View file

@ -83,6 +83,11 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev
belle_sip_header_to_t* to;
belle_sip_header_content_type_t* content_type;
belle_sip_response_t* resp;
belle_sip_header_call_id_t* call_id = belle_sip_message_get_header_by_type(req,belle_sip_header_call_id_t);
belle_sip_header_cseq_t* cseq = belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t);
SalMessage salmsg;
char message_id[256]={0};
from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t);
char* from;
@ -105,7 +110,14 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev
address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header))
,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header)));
from=belle_sip_object_to_string(BELLE_SIP_OBJECT(address));
((Sal*)sal)->callbacks.text_received((Sal*)sal,from,belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)));
snprintf(message_id,sizeof(message_id)-1,"%s%i"
,belle_sip_header_call_id_get_call_id(call_id)
,belle_sip_header_cseq_get_seq_number(cseq));
salmsg.from=from;
salmsg.text=belle_sip_message_get_body(BELLE_SIP_MESSAGE(req));
salmsg.url=NULL; /*not implemented yet*/
salmsg.message_id=message_id;
((Sal*)sal)->callbacks.text_received((Sal*)sal,&salmsg);
belle_sip_object_unref(address);
belle_sip_free(from);
return;
@ -481,3 +493,15 @@ void sal_get_default_local_ip(Sal *sal, int address_family, char *ip, size_t ipl
ms_fatal("sal_get_default_local_ip not implemented yet");
return ;
}
const char *sal_get_root_ca(Sal* ctx) {
ms_fatal("sal_get_root_ca not implemented yet");
return NULL;
}
int sal_reset_transports(Sal *ctx){
ms_warning("sal_reset_transports() not implemented in this version.");
return -1;
}
void sal_set_dscp(Sal *ctx, int dscp){
ms_warning("sal_set_dscp not implemented");
}

View file

@ -40,11 +40,12 @@ static void sdp_process(SalOp *h){
h->result->bandwidth=h->base.remote_media->bandwidth;
for(i=0;i<h->result->nstreams;++i){
if (h->result->streams[i].port>0){
strcpy(h->result->streams[i].addr,h->base.remote_media->streams[i].addr);
if (h->result->streams[i].rtp_port>0){
/*fixme add rtcp*/
strcpy(h->result->streams[i].rtp_addr,h->base.remote_media->streams[i].rtp_addr);
h->result->streams[i].ptime=h->base.remote_media->streams[i].ptime;
h->result->streams[i].bandwidth=h->base.remote_media->streams[i].bandwidth;
h->result->streams[i].port=h->base.remote_media->streams[i].port;
h->result->streams[i].rtp_port=h->base.remote_media->streams[i].rtp_port;
if (h->result->streams[i].proto == SalProtoRtpSavp) {
h->result->streams[i].crypto[0] = h->base.remote_media->streams[i].crypto[0];
@ -624,4 +625,15 @@ int sal_call_is_offerer(const SalOp *h){
return h->sdp_offering;
}
int sal_call_notify_refer_state(SalOp *h, SalOp *newcall){
ms_fatal("sal_call_notify_refer_state not implemented yet");
return -1;
}
void sal_expire_old_registration_contacts(Sal *ctx, bool_t enabled){
ms_warning("sal_expire_old_registration_contacts not implemented ");
}
void sal_use_dates(Sal *ctx, bool_t enabled){
ms_warning("sal_use_dates not implemented yet");
}

View file

@ -22,9 +22,11 @@ static void message_response_event(void *op_base, const belle_sip_response_event
/*nop for futur use*/
}
int sal_text_send(SalOp *op, const char *from, const char *to, const char *text){
int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg){
belle_sip_request_t* req;
size_t content_length = strlen(text);
char content_type_raw[256];
size_t content_length = strlen(msg);
if (!op->callbacks.process_response_event)
op->callbacks.process_response_event=message_response_event;
if (from)
@ -32,8 +34,13 @@ int sal_text_send(SalOp *op, const char *from, const char *to, const char *text)
if (to)
sal_op_set_to(op,to);
req=sal_op_build_request(op,"MESSAGE");
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_type_create("text","plain")));
snprintf(content_type_raw,sizeof(content_type_raw),BELLE_SIP_CONTENT_TYPE ": %s",content_type);
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_type_parse(content_type_raw)));
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length)));
belle_sip_message_set_body(BELLE_SIP_MESSAGE(req),text,content_length);
belle_sip_message_set_body(BELLE_SIP_MESSAGE(req),msg,content_length);
return sal_op_send_request(op,req);
}
int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg) {
return sal_message_send(op,from,to,"text/plain",msg);
}

View file

@ -478,7 +478,7 @@ static void presence_process_request_event(void *op_base, const belle_sip_reques
belle_sip_header_expires_t* expires = belle_sip_message_get_header_by_type(req,belle_sip_header_expires_t);;
const char* body = belle_sip_message_get_body(BELLE_SIP_MESSAGE(req));
SalPresenceStatus estatus=SalPresenceOffline;
SalSubscribeState sub_state;
SalSubscribeStatus sub_state;
belle_sip_response_t* resp;
belle_sip_object_ref(server_transaction);
if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans);

View file

@ -67,7 +67,7 @@ belle_sdp_session_description_t * media_description_to_sdp(const SalMediaDescrip
for (i=0; i<desc->nstreams;i++) {
media_desc = belle_sdp_media_description_create(sal_stream_type_to_string(desc->streams[i].type)
,desc->streams[i].port
,desc->streams[i].rtp_port
,1
,sal_media_proto_to_string(desc->streams[i].proto)
,NULL);
@ -195,10 +195,10 @@ int sdp_to_media_description(belle_sdp_session_description_t *session_desc, Sal
}
}
if ((cnx=belle_sdp_media_description_get_connection(media_desc)) && belle_sdp_connection_get_address(cnx)) {
strncpy(stream->addr,belle_sdp_connection_get_address(cnx),sizeof(stream->addr));
strncpy(stream->rtp_addr,belle_sdp_connection_get_address(cnx),sizeof(stream->rtp_addr));
}
stream->port=belle_sdp_media_get_media_port(media);
stream->rtp_port=belle_sdp_media_get_media_port(media);
mtype = belle_sdp_media_get_media_type(media);
if (strcasecmp("audio", mtype) == 0){

View file

@ -27,9 +27,63 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details);
static bool_t media_parameters_changed(LinphoneCall *call, SalMediaDescription *oldmd, SalMediaDescription *newmd){
if (call->params.in_conference!=call->current_params.in_conference) return TRUE;
return !sal_media_description_equals(oldmd,newmd) || call->up_bw!=linphone_core_get_upload_bandwidth(call->core);
static int media_parameters_changed(LinphoneCall *call, SalMediaDescription *oldmd, SalMediaDescription *newmd) {
if (call->params.in_conference != call->current_params.in_conference) return SAL_MEDIA_DESCRIPTION_CHANGED;
if (call->up_bw != linphone_core_get_upload_bandwidth(call->core)) return SAL_MEDIA_DESCRIPTION_CHANGED;
return sal_media_description_equals(oldmd, newmd);
}
void linphone_core_update_streams_destinations(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md) {
SalStreamDescription *old_audiodesc = NULL;
SalStreamDescription *old_videodesc = NULL;
SalStreamDescription *new_audiodesc = NULL;
SalStreamDescription *new_videodesc = NULL;
char *rtp_addr, *rtcp_addr;
int i;
for (i = 0; i < old_md->nstreams; i++) {
if (old_md->streams[i].type == SalAudio) {
old_audiodesc = &old_md->streams[i];
} else if (old_md->streams[i].type == SalVideo) {
old_videodesc = &old_md->streams[i];
}
}
for (i = 0; i < new_md->nstreams; i++) {
if (new_md->streams[i].type == SalAudio) {
new_audiodesc = &new_md->streams[i];
} else if (new_md->streams[i].type == SalVideo) {
new_videodesc = &new_md->streams[i];
}
}
if (call->audiostream && new_audiodesc) {
rtp_addr = (new_audiodesc->rtp_addr[0] != '\0') ? new_audiodesc->rtp_addr : new_md->addr;
rtcp_addr = (new_audiodesc->rtcp_addr[0] != '\0') ? new_audiodesc->rtcp_addr : new_md->addr;
ms_message("Change audio stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, new_audiodesc->rtp_port, rtcp_addr, new_audiodesc->rtcp_port);
rtp_session_set_remote_addr_full(call->audiostream->session, rtp_addr, new_audiodesc->rtp_port, rtcp_addr, new_audiodesc->rtcp_port);
}
#ifdef VIDEO_ENABLED
if (call->videostream && new_videodesc) {
rtp_addr = (new_videodesc->rtp_addr[0] != '\0') ? new_videodesc->rtp_addr : new_md->addr;
rtcp_addr = (new_videodesc->rtcp_addr[0] != '\0') ? new_videodesc->rtcp_addr : new_md->addr;
ms_message("Change video stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, new_videodesc->rtp_port, rtcp_addr, new_videodesc->rtcp_port);
rtp_session_set_remote_addr_full(call->videostream->session, rtp_addr, new_videodesc->rtp_port, rtcp_addr, new_videodesc->rtcp_port);
}
#endif
/* Copy address and port values from new_md to old_md since we will keep old_md as resultdesc */
strcpy(old_md->addr, new_md->addr);
if (old_audiodesc && new_audiodesc) {
strcpy(old_audiodesc->rtp_addr, new_audiodesc->rtp_addr);
strcpy(old_audiodesc->rtcp_addr, new_audiodesc->rtcp_addr);
old_audiodesc->rtp_port = new_audiodesc->rtp_port;
old_audiodesc->rtcp_port = new_audiodesc->rtcp_port;
}
if (old_videodesc && new_videodesc) {
strcpy(old_videodesc->rtp_addr, new_videodesc->rtp_addr);
strcpy(old_videodesc->rtcp_addr, new_videodesc->rtcp_addr);
old_videodesc->rtp_port = new_videodesc->rtp_port;
old_videodesc->rtcp_port = new_videodesc->rtcp_port;
}
}
void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md){
@ -46,10 +100,11 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia
call->media_pending=TRUE;
}
call->resultdesc=new_md;
if (call->audiostream && call->audiostream->ticker){
if ((call->audiostream && call->audiostream->ticker) || (call->videostream && call->videostream->ticker)){
/* we already started media: check if we really need to restart it*/
if (oldmd){
if (!media_parameters_changed(call,oldmd,new_md) && !call->playing_ringbacktone){
int md_changed = media_parameters_changed(call, oldmd, new_md);
if ((md_changed == SAL_MEDIA_DESCRIPTION_UNCHANGED) && !call->playing_ringbacktone) {
/*as nothing has changed, keep the oldmd */
call->resultdesc=oldmd;
sal_media_description_unref(new_md);
@ -66,6 +121,12 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia
}
ms_message("No need to restart streams, SDP is unchanged.");
return;
} else if ((md_changed == SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED) && !call->playing_ringbacktone) {
call->resultdesc = oldmd;
ms_message("Network parameters have changed, update them.");
linphone_core_update_streams_destinations(lc, call, oldmd, new_md);
sal_media_description_unref(new_md);
return;
}else{
ms_message("Media descriptions are different, need to restart the streams.");
}
@ -140,16 +201,10 @@ static bool_t already_a_call_pending(LinphoneCore *lc){
static void call_received(SalOp *h){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
char *barmesg;
LinphoneCall *call;
const char *from,*to;
char *tmp;
LinphoneAddress *from_parsed;
LinphoneAddress *from_addr, *to_addr;
SalMediaDescription *md;
bool_t propose_early_media=lp_config_get_int(lc->config,"sip","incoming_calls_early_media",FALSE);
bool_t prevent_colliding_calls=lp_config_get_int(lc->config,"sip","prevent_colliding_calls",TRUE);
const char *ringback_tone=linphone_core_get_remote_ringback_tone (lc);
/* first check if we can answer successfully to this invite */
if (lc->presence_mode==LinphoneStatusBusy ||
@ -187,73 +242,18 @@ static void call_received(SalOp *h){
}
call=linphone_call_new_incoming(lc,from_addr,to_addr,h);
sal_call_set_local_media_description(h,call->localdesc);
md=sal_call_get_final_media_description(h);
if (md && sal_media_description_empty(md)){
sal_call_decline(h,SalReasonMedia,NULL);
linphone_call_unref(call);
return;
}
/* the call is acceptable so we can now add it to our list */
linphone_core_add_call(lc,call);
from_parsed=linphone_address_new(sal_op_get_from(h));
linphone_address_clean(from_parsed);
tmp=linphone_address_as_string(from_parsed);
linphone_address_destroy(from_parsed);
barmesg=ortp_strdup_printf("%s %s%s",tmp,_("is contacting you"),
(sal_call_autoanswer_asked(h)) ?_(" and asked autoanswer."):_("."));
if (lc->vtable.show) lc->vtable.show(lc);
if (lc->vtable.display_status)
lc->vtable.display_status(lc,barmesg);
/* play the ring if this is the only call*/
if (ms_list_size(lc->calls)==1){
lc->current_call=call;
if (lc->ringstream && lc->dmfs_playing_start_time!=0){
ring_stop(lc->ringstream);
lc->ringstream=NULL;
lc->dmfs_playing_start_time=0;
}
if (lc->sound_conf.ring_sndcard!=NULL){
if(lc->ringstream==NULL && lc->sound_conf.local_ring){
MSSndCard *ringcard=lc->sound_conf.lsd_card ?lc->sound_conf.lsd_card : lc->sound_conf.ring_sndcard;
ms_message("Starting local ring...");
lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,ringcard);
}
else
{
ms_message("the local ring is already started");
}
}
}else{
/* else play a tone within the context of the current call */
call->ringing_beep=TRUE;
linphone_core_play_tone(lc);
}
linphone_call_ref(call); /*prevent the call from being destroyed while we are notifying, if the user declines within the state callback */
linphone_call_set_state(call,LinphoneCallIncomingReceived,"Incoming call");
if (call->state==LinphoneCallIncomingReceived){
sal_call_notify_ringing(h,propose_early_media || ringback_tone!=NULL);
if (propose_early_media || ringback_tone!=NULL){
linphone_call_set_state(call,LinphoneCallIncomingEarlyMedia,"Incoming call early media");
md=sal_call_get_final_media_description(h);
linphone_core_update_streams(lc,call,md);
}
if (sal_call_get_replaces(call->op)!=NULL && lp_config_get_int(lc->config,"sip","auto_answer_replacing_calls",1)){
linphone_core_accept_call(lc,call);
}
if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)) {
/* Defer ringing until the end of the ICE candidates gathering process. */
ms_message("Defer ringing to gather ICE candidates");
return;
}
linphone_call_unref(call);
ms_free(barmesg);
ms_free(tmp);
linphone_core_notify_incoming_call(lc,call);
}
static void call_ringing(SalOp *h){
@ -276,6 +276,10 @@ static void call_ringing(SalOp *h){
if (lc->ringstream!=NULL) return; /*already ringing !*/
if (lc->sound_conf.play_sndcard!=NULL){
MSSndCard *ringcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
if (call->localdesc->streams[0].max_rate>0) ms_snd_card_set_preferred_sample_rate(ringcard, call->localdesc->streams[0].max_rate);
/*we release sound before playing ringback tone*/
if (call->audiostream)
audio_stream_unprepare_sound(call->audiostream);
lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,ringcard);
}
ms_message("Remote ringing...");
@ -284,7 +288,7 @@ static void call_ringing(SalOp *h){
linphone_call_set_state(call,LinphoneCallOutgoingRinging,"Remote ringing");
}else{
/*accept early media */
if (call->audiostream && call->audiostream->ticker!=NULL){
if (call->audiostream && audio_stream_started(call->audiostream)){
/*streams already started */
ms_message("Early media already started.");
return;
@ -298,7 +302,7 @@ static void call_ringing(SalOp *h){
lc->ringstream=NULL;
}
ms_message("Doing early media...");
linphone_core_update_streams (lc,call,md);
linphone_core_update_streams(lc,call,md);
}
}
@ -316,13 +320,20 @@ static void call_accepted(SalOp *op){
ms_warning("No call to accept.");
return ;
}
/* Handle remote ICE attributes if any. */
if (call->ice_session != NULL) {
linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op));
}
md=sal_call_get_final_media_description(op);
call->params.has_video &= linphone_core_media_description_contains_video_stream(md);
if (call->state==LinphoneCallOutgoingProgress ||
call->state==LinphoneCallOutgoingRinging ||
call->state==LinphoneCallOutgoingEarlyMedia){
linphone_call_set_state(call,LinphoneCallConnected,"Connected");
if (call->referer) linphone_core_notify_refer_state(lc,call->referer,call);
}
if (md && !sal_media_description_empty(md)){
if (sal_media_description_has_dir(md,SalStreamSendOnly) ||
@ -336,6 +347,8 @@ static void call_accepted(SalOp *op){
}
linphone_core_update_streams (lc,call,md);
linphone_call_set_state(call,LinphoneCallPaused,"Call paused");
if (call->refer_pending)
linphone_core_start_refered_call(lc,call);
}else if (sal_media_description_has_dir(md,SalStreamRecvOnly)){
/*we are put on hold when the call is initially accepted */
if (lc->vtable.display_status){
@ -348,11 +361,7 @@ static void call_accepted(SalOp *op){
linphone_core_update_streams (lc,call,md);
linphone_call_set_state(call,LinphoneCallPausedByRemote,"Call paused by remote");
}else{
if (call->state==LinphoneCallStreamsRunning){
/*media was running before, the remote as acceted a call modification (that is
a reinvite made by us. We must notify the application this reinvite was accepted*/
linphone_call_set_state(call, LinphoneCallUpdated, "Call updated");
}else{
if (call->state!=LinphoneCallUpdating){
if (call->state==LinphoneCallResuming){
if (lc->vtable.display_status){
lc->vtable.display_status(lc,_("Call resumed."));
@ -368,9 +377,9 @@ static void call_accepted(SalOp *op){
}
}
linphone_core_update_streams (lc,call,md);
linphone_call_set_state(call, LinphoneCallStreamsRunning, "Streams running");
if (!call->current_params.in_conference)
lc->current_call=call;
linphone_call_set_state(call, LinphoneCallStreamsRunning, "Streams running");
}
}else{
/*send a bye*/
@ -389,11 +398,6 @@ static void call_ack(SalOp *op){
if (call->media_pending){
SalMediaDescription *md=sal_call_get_final_media_description(op);
if (md && !sal_media_description_empty(md)){
if (call->state==LinphoneCallStreamsRunning){
/*media was running before, the remote as acceted a call modification (that is
a reinvite made by us. We must notify the application this reinvite was accepted*/
linphone_call_set_state(call, LinphoneCallUpdated, "Call updated");
}
linphone_core_update_streams (lc,call,md);
linphone_call_set_state (call,LinphoneCallStreamsRunning,"Connected (streams running)");
}else{
@ -407,6 +411,11 @@ static void call_ack(SalOp *op){
static void call_accept_update(LinphoneCore *lc, LinphoneCall *call){
SalMediaDescription *md;
SalMediaDescription *rmd=sal_call_get_remote_media_description(call->op);
if ((rmd!=NULL) && (call->ice_session!=NULL)) {
linphone_core_update_ice_from_remote_media_description(call,rmd);
linphone_core_update_local_media_description_from_ice(call->localdesc,call->ice_session);
}
sal_call_accept(call->op);
md=sal_call_get_final_media_description(call->op);
if (md && !sal_media_description_empty(md))
@ -418,6 +427,7 @@ static void call_resumed(LinphoneCore *lc, LinphoneCall *call){
if(lc->vtable.display_status)
lc->vtable.display_status(lc,_("We have been resumed."));
linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)");
linphone_call_set_transfer_state(call, LinphoneCallIdle);
}
static void call_paused_by_remote(LinphoneCore *lc, LinphoneCall *call){
@ -455,7 +465,7 @@ static void call_updating(SalOp *op){
case LinphoneCallPausedByRemote:
if (sal_media_description_has_dir(rmd,SalStreamSendRecv) || sal_media_description_has_dir(rmd,SalStreamRecvOnly)){
call_resumed(lc,call);
}
}else call_paused_by_remote(lc,call);
break;
case LinphoneCallStreamsRunning:
case LinphoneCallConnected:
@ -476,9 +486,18 @@ static void call_terminated(SalOp *op, const char *from){
if (call==NULL) return;
if (linphone_call_get_state(call)==LinphoneCallEnd || linphone_call_get_state(call)==LinphoneCallError){
ms_warning("call_terminated: ignoring.");
return;
switch(linphone_call_get_state(call)){
case LinphoneCallEnd:
case LinphoneCallError:
ms_warning("call_terminated: ignoring.");
return;
break;
case LinphoneCallIncomingReceived:
case LinphoneCallIncomingEarlyMedia:
call->reason=LinphoneReasonNotAnswered;
break;
default:
break;
}
ms_message("Current call terminated...");
//we stop the call only if we have this current call or if we are in call
@ -558,16 +577,18 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de
int i;
ms_message("Outgoing call failed with SRTP (SAVP) enabled - retrying with AVP");
linphone_call_stop_media_streams(call);
/* clear SRTP local params */
call->params.media_encryption = LinphoneMediaEncryptionNone;
for(i=0; i<call->localdesc->nstreams; i++) {
call->localdesc->streams[i].proto = SalProtoRtpAvp;
memset(call->localdesc->streams[i].crypto, 0, sizeof(call->localdesc->streams[i].crypto));
if (call->state==LinphoneCallOutgoingInit || call->state==LinphoneCallOutgoingProgress){
/* clear SRTP local params */
call->params.media_encryption = LinphoneMediaEncryptionNone;
for(i=0; i<call->localdesc->nstreams; i++) {
call->localdesc->streams[i].proto = SalProtoRtpAvp;
memset(call->localdesc->streams[i].crypto, 0, sizeof(call->localdesc->streams[i].crypto));
}
linphone_core_start_invite(lc, call);
}
linphone_core_start_invite(lc, call, NULL);
return;
}
msg=_("No common codecs");
msg=_("Incompatible media parameters.");
if (lc->vtable.display_status)
lc->vtable.display_status(lc,msg);
break;
@ -582,6 +603,10 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de
lc->ringstream=NULL;
}
linphone_call_stop_media_streams (call);
if (call->referer && linphone_call_get_state(call->referer)==LinphoneCallPaused && call->referer->was_automatically_paused){
/*resume to the call that send us the refer automatically*/
linphone_core_resume_call(lc,call->referer);
}
if (sr == SalReasonDeclined) {
call->reason=LinphoneReasonDeclined;
linphone_call_set_state(call,LinphoneCallEnd,"Call declined.");
@ -744,18 +769,43 @@ static void refer_received(Sal *sal, SalOp *op, const char *referto){
if (call->state!=LinphoneCallPaused){
ms_message("Automatically pausing current call to accept transfer.");
linphone_core_pause_call(lc,call);
}
linphone_core_start_refered_call(lc,call);
sal_call_accept_refer(op);
call->was_automatically_paused=TRUE;
/*then we will start the refered when the pause is accepted, in order to serialize transactions within the dialog.
* Indeed we need to avoid to send a NOTIFY to inform about of state of the refered call while the pause isn't completed.
**/
}else linphone_core_start_refered_call(lc,call);
}else if (lc->vtable.refer_received){
lc->vtable.refer_received(lc,referto);
sal_call_accept_refer(op);
}
}
static void text_received(Sal *sal, const char *from, const char *msg){
static bool_t is_duplicate_msg(LinphoneCore *lc, const char *msg_id){
MSList *elem=lc->last_recv_msg_ids;
MSList *tail=NULL;
int i;
bool_t is_duplicate=FALSE;
for(i=0;elem!=NULL;elem=elem->next,i++){
if (strcmp((const char*)elem->data,msg_id)==0){
is_duplicate=TRUE;
}
tail=elem;
}
if (!is_duplicate){
lc->last_recv_msg_ids=ms_list_prepend(lc->last_recv_msg_ids,ms_strdup(msg_id));
}
if (i>=10){
ms_free(tail->data);
lc->last_recv_msg_ids=ms_list_remove_link(lc->last_recv_msg_ids,tail);
}
return is_duplicate;
}
static void text_received(Sal *sal, const SalMessage *msg){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
linphone_core_text_received(lc,from,msg);
if (is_duplicate_msg(lc,msg->message_id)==FALSE){
linphone_core_message_received(lc,msg->from,msg->text,msg->url);
}
}
static void notify(SalOp *op, const char *from, const char *msg){
@ -766,7 +816,7 @@ static void notify(SalOp *op, const char *from, const char *msg){
lc->vtable.notify_recv(lc,call,from,msg);
}
static void notify_presence(SalOp *op, SalSubscribeState ss, SalPresenceStatus status, const char *msg){
static void notify_presence(SalOp *op, SalSubscribeStatus ss, SalPresenceStatus status, const char *msg){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
linphone_notify_recv(lc,op,ss,status);
}
@ -786,7 +836,8 @@ static void ping_reply(SalOp *op){
ms_message("ping reply !");
if (call){
if (call->state==LinphoneCallOutgoingInit){
linphone_core_start_invite(call->core,call,NULL);
call->ping_replied=TRUE;
linphone_core_proceed_with_invite_if_ready(call->core,call,NULL);
}
}
else
@ -821,6 +872,66 @@ static bool_t auth_requested(Sal* sal, SalAuthInfo* sai) {
return FALSE;
}
}
static void notify_refer(SalOp *op, SalReferStatus status){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=(LinphoneCall*) sal_op_get_user_pointer(op);
LinphoneCallState cstate;
if (call==NULL) {
ms_warning("Receiving notify_refer for unknown call.");
return ;
}
switch(status){
case SalReferTrying:
cstate=LinphoneCallOutgoingProgress;
break;
case SalReferSuccess:
cstate=LinphoneCallConnected;
break;
case SalReferFailed:
cstate=LinphoneCallError;
break;
default:
cstate=LinphoneCallError;
}
linphone_call_set_transfer_state(call, cstate);
if (cstate==LinphoneCallConnected){
/*automatically terminate the call as the transfer is complete.*/
linphone_core_terminate_call(lc,call);
}
}
static LinphoneChatMessageState chatStatusSal2Linphone(SalTextDeliveryStatus status){
switch(status){
case SalTextDeliveryInProgress:
return LinphoneChatMessageStateInProgress;
case SalTextDeliveryDone:
return LinphoneChatMessageStateDelivered;
case SalTextDeliveryFailed:
return LinphoneChatMessageStateNotDelivered;
}
return LinphoneChatMessageStateIdle;
}
static int op_equals(LinphoneCall *a, SalOp *b) {
return a->op !=b; /*return 0 if equals*/
}
static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status){
LinphoneChatMessage *chat_msg=(LinphoneChatMessage* )sal_op_get_user_pointer(op);
const MSList* calls = linphone_core_get_calls(chat_msg->chat_room->lc);
if (chat_msg && chat_msg->cb) {
chat_msg->cb(chat_msg
,chatStatusSal2Linphone(status)
,chat_msg->cb_ud);
}
linphone_chat_message_destroy(chat_msg);
if (!ms_list_find_custom((MSList*)calls, (MSCompareFunc) op_equals, op)) {
/*op was only create for messaging purpose, destroying*/
sal_op_release(op);
}
}
SalCallbacks linphone_sal_callbacks={
call_received,
call_ringing,
@ -838,8 +949,10 @@ SalCallbacks linphone_sal_callbacks={
dtmf_received,
refer_received,
text_received,
text_delivery_update,
notify,
notify_presence,
notify_refer,
subscribe_received,
subscribe_closed,
ping_reply,

View file

@ -22,8 +22,9 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "linphonecore.h"
#include "private.h"
#include "linphonecore.h"
#include "private.h"
#include "lpconfig.h"
LinphoneChatRoom * linphone_core_create_chat_room(LinphoneCore *lc, const char *to){
LinphoneAddress *parsed_url=NULL;
@ -45,49 +46,69 @@
lc->chatrooms=ms_list_remove(lc->chatrooms,(void *) cr);
linphone_address_destroy(cr->peer_url);
ms_free(cr->peer);
if (cr->op)
sal_op_release(cr->op);
}
void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg){
static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatMessage* msg){
const char *route=NULL;
const char *identity=linphone_core_find_best_identity(cr->lc,cr->peer_url,&route);
SalOp *op;
SalOp *op=NULL;
LinphoneCall *call;
if((call = linphone_core_get_call_by_remote_address(cr->lc,cr->peer))!=NULL)
{
ms_message("send SIP message into the call\n");
op = call->op;
char* content_type;
if (lp_config_get_int(cr->lc->config,"sip","chat_use_call_dialogs",1)){
if((call = linphone_core_get_call_by_remote_address(cr->lc,cr->peer))!=NULL){
if (call->state==LinphoneCallConnected ||
call->state==LinphoneCallStreamsRunning ||
call->state==LinphoneCallPaused ||
call->state==LinphoneCallPausing ||
call->state==LinphoneCallPausedByRemote){
ms_message("send SIP message through the existing call.");
op = call->op;
call->pending_message=msg;
}
}
}
else
{
if (op==NULL){
/*sending out of calls*/
op = sal_op_new(cr->lc->sal);
sal_op_set_route(op,route);
if (cr->op!=NULL){
sal_op_release (cr->op);
cr->op=NULL;
}
cr->op=op;
sal_op_set_user_pointer(op, msg); /*if out of call, directly store msg*/
}
sal_text_send(op,identity,cr->peer,msg);
if (msg->external_body_url) {
content_type=ms_strdup_printf("message/external-body; access-type=URL; URL=\"%s\"",msg->external_body_url);
sal_message_send(op,identity,cr->peer,content_type,NULL);
ms_free(content_type);
} else {
sal_text_send(op, identity, cr->peer, msg->message);
}
}
void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg) {
_linphone_chat_room_send_message(cr,linphone_chat_room_create_message(cr,msg));
}
bool_t linphone_chat_room_matches(LinphoneChatRoom *cr, const LinphoneAddress *from){
if (linphone_address_get_username(cr->peer_url) && linphone_address_get_username(from) &&
strcmp(linphone_address_get_username(cr->peer_url),linphone_address_get_username(from))==0) return TRUE;
return FALSE;
}
void linphone_chat_room_text_received(LinphoneChatRoom *cr, LinphoneCore *lc, const LinphoneAddress *from, const char *msg){
if (lc->vtable.text_received!=NULL) lc->vtable.text_received(lc, cr, from, msg);
void linphone_chat_room_message_received(LinphoneChatRoom *cr, LinphoneCore *lc, LinphoneChatMessage *msg){
if (msg->message)
//legacy API
if (lc->vtable.text_received!=NULL) lc->vtable.text_received(lc, cr, msg->from, msg->message);
if (lc->vtable.message_received!=NULL) lc->vtable.message_received(lc, cr,msg);
}
void linphone_core_text_received(LinphoneCore *lc, const char *from, const char *msg){
void linphone_core_message_received(LinphoneCore *lc, const char *from, const char *raw_msg,const char* external_url){
MSList *elem;
LinphoneChatRoom *cr=NULL;
LinphoneAddress *addr;
char *cleanfrom;
LinphoneChatMessage* msg;
addr=linphone_address_new(from);
linphone_address_clean(addr);
for(elem=lc->chatrooms;elem!=NULL;elem=ms_list_next(elem)){
@ -102,12 +123,23 @@ void linphone_core_text_received(LinphoneCore *lc, const char *from, const char
/* create a new chat room */
cr=linphone_core_create_chat_room(lc,cleanfrom);
}
msg = linphone_chat_room_create_message(cr, raw_msg);
linphone_chat_message_set_from(msg, cr->peer_url);
if (external_url) {
linphone_chat_message_set_external_body_url(msg, external_url);
}
linphone_address_destroy(addr);
linphone_chat_room_text_received(cr,lc,cr->peer_url,msg);
linphone_chat_room_message_received(cr,lc,msg);
ms_free(cleanfrom);
}
LinphoneCore* linphone_chat_room_get_lc(LinphoneChatRoom *cr){
return cr->lc;
}
LinphoneChatRoom* linphone_chat_message_get_chat_room(LinphoneChatMessage *msg){
return msg->chat_room;
}
void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void * ud){
cr->user_data=ud;
@ -118,3 +150,96 @@ void * linphone_chat_room_get_user_data(LinphoneChatRoom *cr){
const LinphoneAddress* linphone_chat_room_get_peer_address(LinphoneChatRoom *cr) {
return cr->peer_url;
}
LinphoneChatMessage* linphone_chat_room_create_message(const LinphoneChatRoom *cr,const char* message) {
LinphoneChatMessage* msg = ms_new0(LinphoneChatMessage,1);
msg->chat_room=(LinphoneChatRoom*)cr;
msg->message=message?ms_strdup(message):NULL;
return msg;
}
void linphone_chat_message_destroy(LinphoneChatMessage* msg) {
if (msg->message) ms_free(msg->message);
if (msg->external_body_url) ms_free(msg->external_body_url);
if (msg->from) linphone_address_destroy(msg->from);
ms_free(msg);
}
void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* msg,LinphoneChatMessageStateChangeCb status_cb,void* ud) {
msg->cb=status_cb;
msg->cb_ud=ud;
_linphone_chat_room_send_message(cr, msg);
}
const char* linphone_chat_message_state_to_string(const LinphoneChatMessageState state) {
switch (state) {
case LinphoneChatMessageStateIdle:return "LinphoneChatMessageStateIdle";
case LinphoneChatMessageStateInProgress:return "LinphoneChatMessageStateInProgress";
case LinphoneChatMessageStateDelivered:return "LinphoneChatMessageStateDelivered";
case LinphoneChatMessageStateNotDelivered:return "LinphoneChatMessageStateNotDelivered";
default: return "Unknown state";
}
}
char* linphone_chat_message_get_message(LinphoneChatMessage* msg) {
return msg->message;
}
const LinphoneAddress* linphone_chat_message_get_peer_address(LinphoneChatMessage *msg) {
return linphone_chat_room_get_peer_address(msg->chat_room);
}
/**
* user pointer set function
*/
void linphone_chat_message_set_user_data(LinphoneChatMessage* message,void* ud) {
message->message_userdata=ud;
}
/**
* user pointer get function
*/
void* linphone_chat_message_get_user_data(const LinphoneChatMessage* message) {
return message->message_userdata;
}
const char* linphone_chat_message_get_external_body_url(const LinphoneChatMessage* message) {
return message->external_body_url;
}
void linphone_chat_message_set_external_body_url(LinphoneChatMessage* message,const char* url) {
if (message->external_body_url) {
ms_free(message->external_body_url);
}
message->external_body_url=url?ms_strdup(url):NULL;
}
void linphone_chat_message_set_from(LinphoneChatMessage* message, const LinphoneAddress* from) {
if(message->from) linphone_address_destroy(message->from);
message->from=linphone_address_clone(from);
}
LinphoneAddress* linphone_chat_message_get_from(const LinphoneChatMessage* message) {
return message->from;
}
const char * linphone_chat_message_get_text(const LinphoneChatMessage* message) {
return message->message;
}
LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* msg) {
/*struct _LinphoneChatMessage {
char* message;
LinphoneChatRoom* chat_room;
LinphoneChatMessageStateChangeCb cb;
void* cb_ud;
void* message_userdata;
char* external_body_url;
LinphoneAddress* from;
};*/
LinphoneChatMessage* new_message = linphone_chat_room_create_message(msg->chat_room,msg->message);
if (msg->external_body_url) new_message->external_body_url=ms_strdup(msg->external_body_url);
new_message->cb=msg->cb;
new_message->cb_ud=msg->cb_ud;
new_message->message_userdata=msg->message_userdata;
new_message->cb=msg->cb;
if (msg->from) new_message->from=linphone_address_clone(msg->from);
return new_message;
}

View file

@ -28,6 +28,12 @@
#include "mediastreamer2/msvolume.h"
/**
* @addtogroup conferencing
* @{
**/
static int convert_conference_to_call(LinphoneCore *lc);
static void conference_check_init(LinphoneConference *ctx, int samplerate){
@ -104,7 +110,7 @@ static RtpProfile *make_dummy_profile(int samplerate){
static void add_local_endpoint(LinphoneConference *conf,LinphoneCore *lc){
/*create a dummy audiostream in order to extract the local part of it */
/* network address and ports have no meaning and are not used here. */
AudioStream *st=audio_stream_new(65000,FALSE);
AudioStream *st=audio_stream_new(65000,65001,FALSE);
MSSndCard *playcard=lc->sound_conf.lsd_card ?
lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
MSSndCard *captcard=lc->sound_conf.capt_sndcard;
@ -114,6 +120,7 @@ static void add_local_endpoint(LinphoneConference *conf,LinphoneCore *lc){
audio_stream_start_full(st, conf->local_dummy_profile,
"127.0.0.1",
65000,
"127.0.0.1",
65001,
0,
40,
@ -130,6 +137,11 @@ static void add_local_endpoint(LinphoneConference *conf,LinphoneCore *lc){
}
/**
* Returns the sound volume (mic input) of the local participant of the conference.
* @param lc the linphone core
* @returns the measured input volume expressed in dbm0.
**/
float linphone_core_get_conference_local_input_volume(LinphoneCore *lc){
LinphoneConference *conf=&lc->conf_ctx;
AudioStream *st=conf->local_participant;
@ -142,6 +154,16 @@ float linphone_core_get_conference_local_input_volume(LinphoneCore *lc){
return LINPHONE_VOLUME_DB_LOWEST;
}
/**
* Merge a call into a conference.
* @param lc the linphone core
* @param call an established call, either in LinphoneCallStreamsRunning or LinphoneCallPaused state.
*
* If this is the first call that enters the conference, the virtual conference will be created automatically.
* If the local user was actively part of the call (ie not in paused state), then the local user is automatically entered into the conference.
*
* @returns 0 if successful, -1 otherwise.
**/
int linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *call){
LinphoneCallParams params;
LinphoneConference *conf=&lc->conf_ctx;
@ -228,7 +250,18 @@ static int convert_conference_to_call(LinphoneCore *lc){
return err;
}
/**
* Remove a call from the conference.
* @param lc the linphone core
* @param call a call that has been previously merged into the conference.
*
* After removing the remote participant belonging to the supplied call, the call becomes a normal call in paused state.
* If one single remote participant is left alone in the conference after the removal, then it is
* automatically removed from the conference and put into a simple call, like before entering the conference.
* The conference's resources are then automatically destroyed.
*
* @returns 0 if successful, -1 otherwise.
**/
int linphone_core_remove_from_conference(LinphoneCore *lc, LinphoneCall *call){
char * str=linphone_call_get_remote_address_as_string(call);
ms_message("Removing call %s from the conference", str);
@ -248,10 +281,21 @@ int linphone_core_remove_from_conference(LinphoneCore *lc, LinphoneCall *call){
return err;
}
/**
* Indicates whether the local participant is part of the conference.
* @param lc the linphone core
* @returns TRUE if the local participant is in the conference, FALSE otherwise.
**/
bool_t linphone_core_is_in_conference(const LinphoneCore *lc){
return lc->conf_ctx.local_participant!=NULL;
}
/**
* Moves the local participant out of the conference.
* @param lc the linphone core
* When the local participant is out of the conference, the remote participants can continue to talk normally.
* @returns 0 if successful, -1 otherwise.
**/
int linphone_core_leave_conference(LinphoneCore *lc){
LinphoneConference *conf=&lc->conf_ctx;
if (linphone_core_is_in_conference(lc))
@ -259,7 +303,17 @@ int linphone_core_leave_conference(LinphoneCore *lc){
return 0;
}
/**
* Moves the local participant inside the conference.
* @param lc the linphone core
*
* Makes the local participant to join the conference.
* Typically, the local participant is by default always part of the conference when joining an active call into a conference.
* However, by calling linphone_core_leave_conference() and linphone_core_enter_conference() the application can decide to temporarily
* move out and in the local participant from the conference.
*
* @returns 0 if successful, -1 otherwise
**/
int linphone_core_enter_conference(LinphoneCore *lc){
if (linphone_core_sound_resources_locked(lc)) {
return -1;
@ -272,6 +326,14 @@ int linphone_core_enter_conference(LinphoneCore *lc){
return 0;
}
/**
* Add all calls into a conference.
* @param lc the linphone core
*
* Merge all established calls (either in LinphoneCallStreamsRunning or LinphoneCallPaused) into a conference.
*
* @returns 0 if successful, -1 otherwise
**/
int linphone_core_add_all_to_conference(LinphoneCore *lc) {
MSList *calls=lc->calls;
while (calls) {
@ -285,6 +347,14 @@ int linphone_core_add_all_to_conference(LinphoneCore *lc) {
return 0;
}
/**
* Terminates the conference and the calls associated with it.
* @param lc the linphone core
*
* All the calls that were merged to the conference are terminated, and the conference resources are destroyed.
*
* @returns 0 if successful, -1 otherwise
**/
int linphone_core_terminate_conference(LinphoneCore *lc) {
MSList *calls=lc->calls;
while (calls) {
@ -297,9 +367,23 @@ int linphone_core_terminate_conference(LinphoneCore *lc) {
return 0;
}
/**
* Returns the number of participants to the conference, including the local participant.
* @param lc the linphone core
*
* Typically, after merging two calls into the conference, there is total of 3 participants:
* the local participant (or local user), and two remote participants that were the destinations of the two previously establised calls.
*
* @returns the number of participants to the conference
**/
int linphone_core_get_conference_size(LinphoneCore *lc) {
if (lc->conf_ctx.conf == NULL) {
return 0;
}
return ms_audio_conference_get_size(lc->conf_ctx.conf);
}
/**
* @}
**/

View file

@ -29,45 +29,57 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
static void ecc_init_filters(EcCalibrator *ecc){
unsigned int rate;
ecc->ticker=ms_ticker_new();
MSTickerParams params={0};
params.name="Echo calibrator";
params.prio=MS_TICKER_PRIO_HIGH;
ecc->ticker=ms_ticker_new_with_params(&params);
ecc->sndread=ms_snd_card_create_reader(ecc->play_card);
ms_filter_call_method(ecc->sndread,MS_FILTER_SET_SAMPLE_RATE,&ecc->rate);
ms_filter_call_method(ecc->sndread,MS_FILTER_GET_SAMPLE_RATE,&rate);
ecc->read_resampler=ms_filter_new(MS_RESAMPLE_ID);
ms_filter_call_method(ecc->read_resampler,MS_FILTER_SET_SAMPLE_RATE,&rate);
ms_filter_call_method(ecc->read_resampler,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&ecc->rate);
ecc->det=ms_filter_new(MS_TONE_DETECTOR_ID);
ms_filter_call_method(ecc->det,MS_FILTER_SET_SAMPLE_RATE,&ecc->rate);
ecc->rec=ms_filter_new(MS_FILE_REC_ID);
ms_filter_link(ecc->sndread,0,ecc->det,0);
ms_filter_link(ecc->sndread,0,ecc->read_resampler,0);
ms_filter_link(ecc->read_resampler,0,ecc->det,0);
ms_filter_link(ecc->det,0,ecc->rec,0);
ecc->play=ms_filter_new(MS_FILE_PLAYER_ID);
ecc->gen=ms_filter_new(MS_DTMF_GEN_ID);
ms_filter_call_method(ecc->gen,MS_FILTER_SET_SAMPLE_RATE,&ecc->rate);
ecc->resampler=ms_filter_new(MS_RESAMPLE_ID);
ecc->write_resampler=ms_filter_new(MS_RESAMPLE_ID);
ecc->sndwrite=ms_snd_card_create_writer(ecc->capt_card);
ms_filter_link(ecc->play,0,ecc->gen,0);
ms_filter_link(ecc->gen,0,ecc->resampler,0);
ms_filter_link(ecc->resampler,0,ecc->sndwrite,0);
ms_filter_call_method(ecc->sndwrite,MS_FILTER_SET_SAMPLE_RATE,&ecc->rate);
ms_filter_call_method(ecc->sndwrite,MS_FILTER_GET_SAMPLE_RATE,&rate);
ms_filter_call_method(ecc->resampler,MS_FILTER_SET_SAMPLE_RATE,&ecc->rate);
ms_filter_call_method(ecc->resampler,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&rate);
ms_filter_call_method(ecc->write_resampler,MS_FILTER_SET_SAMPLE_RATE,&ecc->rate);
ms_filter_call_method(ecc->write_resampler,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&rate);
ms_filter_link(ecc->play,0,ecc->gen,0);
ms_filter_link(ecc->gen,0,ecc->write_resampler,0);
ms_filter_link(ecc->write_resampler,0,ecc->sndwrite,0);
ms_ticker_attach(ecc->ticker,ecc->play);
ms_ticker_attach(ecc->ticker,ecc->sndread);
ms_ticker_attach(ecc->ticker,ecc->play);
}
static void ecc_deinit_filters(EcCalibrator *ecc){
ms_ticker_detach(ecc->ticker,ecc->play);
ms_ticker_detach(ecc->ticker,ecc->sndread);
ms_ticker_detach(ecc->ticker,ecc->play);
ms_filter_unlink(ecc->play,0,ecc->gen,0);
ms_filter_unlink(ecc->gen,0,ecc->resampler,0);
ms_filter_unlink(ecc->resampler,0,ecc->sndwrite,0);
ms_filter_unlink(ecc->gen,0,ecc->write_resampler,0);
ms_filter_unlink(ecc->write_resampler,0,ecc->sndwrite,0);
ms_filter_unlink(ecc->sndread,0,ecc->det,0);
ms_filter_unlink(ecc->sndread,0,ecc->read_resampler,0);
ms_filter_unlink(ecc->read_resampler,0,ecc->det,0);
ms_filter_unlink(ecc->det,0,ecc->rec,0);
ms_filter_destroy(ecc->sndread);
@ -75,7 +87,8 @@ static void ecc_deinit_filters(EcCalibrator *ecc){
ms_filter_destroy(ecc->rec);
ms_filter_destroy(ecc->play);
ms_filter_destroy(ecc->gen);
ms_filter_destroy(ecc->resampler);
ms_filter_destroy(ecc->read_resampler);
ms_filter_destroy(ecc->write_resampler);
ms_filter_destroy(ecc->sndwrite);
ms_ticker_destroy(ecc->ticker);
@ -101,7 +114,6 @@ static void ecc_play_tones(EcCalibrator *ecc){
MSDtmfGenCustomTone tone;
MSToneDetectorDef expected_tone;
ms_filter_set_notify_callback(ecc->det,on_tone_received,ecc);
expected_tone.frequency=2000;
@ -110,7 +122,7 @@ static void ecc_play_tones(EcCalibrator *ecc){
ms_filter_call_method (ecc->det,MS_TONE_DETECTOR_ADD_SCAN,&expected_tone);
tone.frequency=1000;
tone.frequency=1300;
tone.duration=1000;
tone.amplitude=1.0;
@ -129,20 +141,29 @@ static void ecc_play_tones(EcCalibrator *ecc){
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
ms_sleep(1);
if (ecc->sent_count==3 && ecc->recv_count==3){
int delay=ecc->acc/3;
if (delay<0){
ms_error("Quite surprising calibration result, delay=%i",delay);
ecc->status=LinphoneEcCalibratorFailed;
}else{ms_message("Echo calibration estimated delay to be %i ms",delay);
ecc->delay=delay;
ecc->status=LinphoneEcCalibratorDone;
if (ecc->sent_count==3) {
if (ecc->recv_count==3){
int delay=ecc->acc/3;
if (delay<0){
ms_error("Quite surprising calibration result, delay=%i",delay);
ecc->status=LinphoneEcCalibratorFailed;
}else{
ms_message("Echo calibration estimated delay to be %i ms",delay);
ecc->delay=delay;
ecc->status=LinphoneEcCalibratorDone;
}
} else if (ecc->recv_count == 0) {
ms_message("Echo calibration succeeded, no echo has been detected");
ecc->status = LinphoneEcCalibratorDoneNoEcho;
} else {
ecc->status = LinphoneEcCalibratorFailed;
}
}else{
ms_error("Echo calibration failed, tones received = %i",ecc->recv_count);
ecc->status=LinphoneEcCalibratorFailed;
}
if (ecc->status == LinphoneEcCalibratorFailed) {
ms_error("Echo calibration failed, tones received = %i",ecc->recv_count);
}
}
static void * ecc_thread(void *p){

View file

@ -399,8 +399,8 @@ void linphone_core_add_friend(LinphoneCore *lc, LinphoneFriend *lf)
void linphone_core_remove_friend(LinphoneCore *lc, LinphoneFriend* fl){
MSList *el=ms_list_find(lc->friends,(void *)fl);
if (el!=NULL){
lc->friends=ms_list_remove_link(lc->friends,el);
linphone_friend_destroy((LinphoneFriend*)el->data);
lc->friends=ms_list_remove_link(lc->friends,el);
linphone_core_write_friends_config(lc);
}
}

View file

@ -1,21 +1,20 @@
EXTRA_DIST = Doxyfile.in doxygen.dox
EXTRA_DIST=Doxyfile.in doxygen.dox
SOURCES= doxygen.dox $(top_srcdir)/coreapi/help/*.c $(top_srcdir)/coreapi/*.c $(top_srcdir)/coreapi/*.h
SOURCES=doxygen.dox $(top_srcdir)/coreapi/help/*.c $(top_srcdir)/coreapi/*.c $(top_srcdir)/coreapi/*.h
#html doc
# html doc
if HAVE_DOXYGEN
# doxdir & pkgdocdir are not always defined by automake
docdir=$(datadir)/doc
# docdir & pkgdocdir are not always defined by automake
pkgdocdir=$(docdir)/$(PACKAGE)-$(VERSION)
doc_htmldir=$(pkgdocdir)/html
doc_html_DATA = $(top_builddir)/coreapi/help/doc/html/html.tar
$(doc_html_DATA): $(top_builddir)/coreapi/help/doc/html/index.html
cd $(<D) && tar cf html.tar *
cd $(top_builddir)/coreapi/help/doc/html/ && tar cf html.tar *
$(top_builddir)/coreapi/help/doc/html/index.html: $(SOURCES) Doxyfile Makefile.am
rm -rf doc
@ -60,21 +59,20 @@ LINPHONE_TUTOS+=$(chatroom_SOURCES)
chatroom_LDADD=$(helloworld_LDADD)
endif
endif
endif
INCLUDES=-I$(top_srcdir)/coreapi \
$(MEDIASTREAMER_CFLAGS)
AM_CFLAGS=$(STRICT_OPTIONS) -DIN_LINPHONE \
AM_CFLAGS=\
$(STRICT_OPTIONS) \
-DIN_LINPHONE \
$(ORTP_CFLAGS) \
$(OSIP_CFLAGS) \
$(MEDIASTREAMER_CFLAGS) \
$(EXOSIP_CFLAGS) \
-DENABLE_TRACE \
-DLOG_DOMAIN=\"LinphoneCore\" \
$(IPV6_CFLAGS) \
-DORTP_INET6 \
$(VIDEO_CFLAGS)
$(IPV6_CFLAGS) \
-DORTP_INET6 \
$(VIDEO_CFLAGS)
tutodir=$(datadir)/tutorials/linphone

View file

@ -195,6 +195,27 @@ void text_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddre
* This api is useful for manipulating SIP addresses ('from' or 'to' headers).
**/
/**
* @defgroup conferencing Making an audio conference.
* This API allows to create a conference entirely managed by the client. No server capabilities are required.
* The way such conference is created is by doing the following:<br>
* The application shall makes "normal" calls to several destinations (using linphone_core_invite() ), one after another.
* While initiating the second call, the first one is automatically paused.
* Then, once the second call is established, the application has the possibility to merge the two calls to form a conference where each participant
* (the local participant, the remote destination of the first call, the remote destination of the second call) can talk together.
* This must be done by adding the two calls to the conference using \link linphone_call_add_to_conference() \endlink
*
* Once merged into a conference the LinphoneCall objects representing the calls that were established remain unchanged, except that
* they are tagged as part of the conference (see \link linphone_call_is_in_conference() \endlink ). The calls in a conference are in the LinphoneCallStreamsRunning state.
*
* Only a single conference can be created: the purpose of this feature is to allow the local user to create, take part and manage the conference.
* This API is not designed to create a conference server application.
*
* Up to 10 calls can be merged into the conference, however depending on the CPU usage required for doing the encoding/decoding of the streams of each participants,
* the effective limit can be lower.
*
**/
/**
* @defgroup misc Miscenalleous: logs, version strings, config storage
**/

View file

@ -20,6 +20,8 @@ package org.linphone.core.tutorials;
import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneCall;
import org.linphone.core.LinphoneCallStats;
import org.linphone.core.LinphoneChatMessage;
import org.linphone.core.LinphoneChatRoom;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCore.EcCalibratorStatus;
@ -96,8 +98,11 @@ public class TutorialBuddyStatus implements LinphoneCoreListener {
public void globalState(LinphoneCore lc, GlobalState state, String message) {}
public void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from, String message) {}
public void callState(LinphoneCore lc, LinphoneCall call, State cstate, String msg) {}
public void callStatsUpdated(LinphoneCore lc, LinphoneCall call, LinphoneCallStats stats) {}
public void ecCalibrationStatus(LinphoneCore lc, EcCalibratorStatus status,int delay_ms, Object data) {}
public void callEncryptionChanged(LinphoneCore lc, LinphoneCall call,boolean encrypted, String authenticationToken) {}
public void notifyReceived(LinphoneCore lc, LinphoneCall call, LinphoneAddress from, byte[] event){}
public void dtmfReceived(LinphoneCore lc, LinphoneCall call, int dtmf) {}
public static void main(String[] args) {
@ -230,5 +235,11 @@ public class TutorialBuddyStatus implements LinphoneCoreListener {
TutorialNotifier.notify(s);
}
@Override
public void messageReceived(LinphoneCore lc, LinphoneChatRoom cr, LinphoneChatMessage message) {
// TODO Auto-generated method stub
}
}

View file

@ -20,6 +20,8 @@ package org.linphone.core.tutorials;
import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneCall;
import org.linphone.core.LinphoneCallStats;
import org.linphone.core.LinphoneChatMessage;
import org.linphone.core.LinphoneChatRoom;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCore.EcCalibratorStatus;
@ -74,8 +76,11 @@ public class TutorialChatRoom implements LinphoneCoreListener {
public void newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf,String url) {}
public void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf) {}
public void callState(LinphoneCore lc, LinphoneCall call, State cstate, String msg){}
public void callStatsUpdated(LinphoneCore lc, LinphoneCall call, LinphoneCallStats stats) {}
public void ecCalibrationStatus(LinphoneCore lc, EcCalibratorStatus status,int delay_ms, Object data) {}
public void callEncryptionChanged(LinphoneCore lc, LinphoneCall call,boolean encrypted, String authenticationToken) {}
public void notifyReceived(LinphoneCore lc, LinphoneCall call, LinphoneAddress from, byte[] event){}
public void dtmfReceived(LinphoneCore lc, LinphoneCall call, int dtmf) {}
public void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from, String message) {
write("Message ["+message+"] received from ["+from.asString()+"]");
@ -145,5 +150,12 @@ public class TutorialChatRoom implements LinphoneCoreListener {
TutorialNotifier.notify(s);
}
@Override
public void messageReceived(LinphoneCore lc, LinphoneChatRoom cr,
LinphoneChatMessage message) {
// TODO Auto-generated method stub
}
}

View file

@ -20,6 +20,8 @@ package org.linphone.core.tutorials;
import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneCall;
import org.linphone.core.LinphoneCallStats;
import org.linphone.core.LinphoneChatMessage;
import org.linphone.core.LinphoneChatRoom;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCore.EcCalibratorStatus;
@ -68,9 +70,11 @@ public class TutorialHelloWorld implements LinphoneCoreListener {
public void newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf,String url) {}
public void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf) {}
public void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from, String message) {}
public void callStatsUpdated(LinphoneCore lc, LinphoneCall call, LinphoneCallStats stats) {}
public void ecCalibrationStatus(LinphoneCore lc, EcCalibratorStatus status,int delay_ms, Object data) {}
public void callEncryptionChanged(LinphoneCore lc, LinphoneCall call,boolean encrypted, String authenticationToken) {}
public void notifyReceived(LinphoneCore lc, LinphoneCall call, LinphoneAddress from, byte[] event){}
public void dtmfReceived(LinphoneCore lc, LinphoneCall call, int dtmf) {}
/*
* Call state notification listener
*/
@ -156,5 +160,12 @@ public class TutorialHelloWorld implements LinphoneCoreListener {
TutorialNotifier.notify(s);
}
@Override
public void messageReceived(LinphoneCore lc, LinphoneChatRoom cr,
LinphoneChatMessage message) {
// TODO Auto-generated method stub
}
}

View file

@ -20,6 +20,8 @@ package org.linphone.core.tutorials;
import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneCall;
import org.linphone.core.LinphoneCallStats;
import org.linphone.core.LinphoneChatMessage;
import org.linphone.core.LinphoneChatRoom;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCore.EcCalibratorStatus;
@ -79,8 +81,11 @@ public class TutorialRegistration implements LinphoneCoreListener {
public void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf) {}
public void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from, String message) {}
public void callState(LinphoneCore lc, LinphoneCall call, State cstate, String msg) {}
public void callStatsUpdated(LinphoneCore lc, LinphoneCall call, LinphoneCallStats stats) {}
public void ecCalibrationStatus(LinphoneCore lc, EcCalibratorStatus status,int delay_ms, Object data) {}
public void callEncryptionChanged(LinphoneCore lc, LinphoneCall call,boolean encrypted, String authenticationToken) {}
public void notifyReceived(LinphoneCore lc, LinphoneCall call, LinphoneAddress from, byte[] event){}
public void dtmfReceived(LinphoneCore lc, LinphoneCall call, int dtmf) {}
public static void main(String[] args) {
// Check tutorial was called with the right number of arguments
@ -186,6 +191,13 @@ public class TutorialRegistration implements LinphoneCoreListener {
TutorialNotifier.notify(s);
}
@Override
public void messageReceived(LinphoneCore lc, LinphoneChatRoom cr,
LinphoneChatMessage message) {
// TODO Auto-generated method stub
}
}

View file

@ -152,6 +152,17 @@ void linphone_tunnel_set_http_proxy_auth_info(LinphoneTunnel *tunnel, const char
void linphone_tunnel_set_http_proxy(LinphoneTunnel*tunnel, const char *host, int port, const char* username,const char* passwd){
bcTunnel(tunnel)->setHttpProxy(host, port, username, passwd);
lp_config_set_string(config(tunnel),"tunnel","http_proxy_host",host);
lp_config_set_int(config(tunnel),"tunnel","http_proxy_port",port);
lp_config_set_string(config(tunnel),"tunnel","http_proxy_username",username);
lp_config_set_string(config(tunnel),"tunnel","http_proxy_password",passwd);
}
void linphone_tunnel_get_http_proxy(LinphoneTunnel*tunnel,const char **host, int *port, const char **username, const char **passwd){
if (host) *host=lp_config_get_string(config(tunnel),"tunnel","http_proxy_host",NULL);
if (port) *port=lp_config_get_int(config(tunnel),"tunnel","http_proxy_port",0);
if (username) *username=lp_config_get_string(config(tunnel),"tunnel","http_proxy_username",NULL);
if (passwd) *passwd=lp_config_get_string(config(tunnel),"tunnel","http_proxy_password",NULL);
}
void linphone_tunnel_reconnect(LinphoneTunnel *tunnel){
@ -163,18 +174,25 @@ void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel){
}
static void tunnel_add_servers_from_config(LinphoneTunnel *tunnel, const char* confaddress){
char *addresses=(char*)ms_strdup(confaddress);
char *str1;
for(str1=addresses;;str1=NULL){
char *port;
char *address=strtok(str1," "); // Not thread safe
if (!address) break;
port=strchr(address, ':');
if (!port) ms_fatal("Bad tunnel address %s", address);
*port++='\0';
linphone_tunnel_add_server(tunnel, address, atoi(port));
}
ms_free(addresses);
char *tmp=(char*)ms_malloc0(strlen(confaddress)+1);
const char *it=confaddress;
int adv;
do{
int ret=sscanf(it,"%s%n",tmp,&adv);
if (ret>=1){
it+=adv;
char *port=strchr(tmp,':');
if (!port){
ms_error("Tunnel server addresses incorrectly specified from config file: %s",it);
break;
}else{
*port='\0';
port++;
bcTunnel(tunnel)->addServer(tmp, atoi(port));
}
}else break;
}while(1);
ms_free(tmp);
}
static void my_ortp_logv(OrtpLogLevel level, const char *fmt, va_list args){
@ -189,14 +207,11 @@ void linphone_tunnel_configure(LinphoneTunnel *tunnel){
bool_t enabled=(bool_t)lp_config_get_int(config(tunnel),"tunnel","enabled",FALSE);
const char* addresses=lp_config_get_string(config(tunnel),"tunnel","server_addresses", NULL);
linphone_tunnel_enable_logs_with_handler(tunnel,TRUE,my_ortp_logv);
linphone_tunnel_clean_servers(tunnel);
if (addresses){
if (addresses)
tunnel_add_servers_from_config(tunnel,addresses);
}
linphone_tunnel_enable(tunnel, enabled);
}
#else
/*stubs to avoid to have #ifdef TUNNEL_ENABLED in upper layers*/
@ -225,8 +240,6 @@ bool_t linphone_tunnel_enabled(LinphoneTunnel *tunnel){
return FALSE;
}
void linphone_tunnel_enable_logs(LinphoneTunnel *tunnel, bool_t enabled){
}
void linphone_tunnel_enable_logs_with_handler(LinphoneTunnel *tunnel, bool_t enabled, OrtpLogFunc logHandler){
}
@ -237,6 +250,9 @@ void linphone_tunnel_set_http_proxy_auth_info(LinphoneTunnel *tunnel, const char
void linphone_tunnel_set_http_proxy(LinphoneTunnel*tunnel, const char *host, int port, const char* username,const char* passwd){
}
void linphone_tunnel_get_http_proxy(LinphoneTunnel*tunnel,const char **host, int *port, const char **username, const char **passwd){
}
void linphone_tunnel_reconnect(LinphoneTunnel *tunnel){
}

View file

@ -28,29 +28,113 @@
#include "linphonecore.h"
/*
* Linphone VoIP tunnel extension API
/**
* @addtogroup tunnel
* @{
**/
/**
* This set of methods enhance LinphoneCore functionalities in order to provide an easy to use API to
* - provision tunnel servers ip addresses and ports. This functionality is an option not implemented under GPL.
* - start/stop the tunneling service
* - perform auto-detection whether tunneling is required, based on a test of sending/receiving a flow of UDP packets.
*
* It takes in charge automatically the SIP registration procedure when connecting or disconnecting to a tunnel server.
* No other action on LinphoneCore is required to enable full operation in tunnel mode.
**/
#ifdef __cplusplus
extern "C"
{
#endif
/**
* Add a tunnel server. At least one should be provided to be able to connect.
* When several addresses are provided, the tunnel client may try each of them until it gets connected.
* @param tunnel object
* @param host server ip address
* @param port tunnel server tls port, recommended value is 443
*/
void linphone_tunnel_add_server(LinphoneTunnel *tunnel, const char *host, int port);
void linphone_tunnel_add_server_and_mirror(LinphoneTunnel *tunnel, const char *host, int port, int remote_udp_mirror, int delay);
/*returns a string of space separated list of host:port of tunnel server addresses*/
/**
*Add tunnel server with auto detection capabilities
*
* @param tunnel object
* @param host tunnel server ip address
* @param port tunnel server tls port, recommended value is 443
* @param remote_udp_mirror_port remote port on the tunnel server side used to test udp reachability
* @param delay udp packet round trip delay in ms considered as acceptable. recommended value is 1000 ms.
*/
void linphone_tunnel_add_server_and_mirror(LinphoneTunnel *tunnel, const char *host, int port, int remote_udp_mirror_port, int delay);
/**
* @param tunnel object
* returns a string of space separated list of host:port of tunnel server addresses
* */
char *linphone_tunnel_get_servers(LinphoneTunnel *tunnel);
/**
* @param tunnel object
* Removes all tunnel server address previously entered with addServer()
**/
void linphone_tunnel_clean_servers(LinphoneTunnel *tunnel);
/**
* Sets whether tunneling of SIP and RTP is required.
* @param tunnel object
* @param enabled If true enter in tunneled mode, if false exits from tunneled mode.
* The TunnelManager takes care of refreshing SIP registration when switching on or off the tunneled mode.
*
**/
void linphone_tunnel_enable(LinphoneTunnel *tunnel, bool_t enabled);
/**
* @param tunnel object
* Returns a boolean indicating whether tunneled operation is enabled.
**/
bool_t linphone_tunnel_enabled(LinphoneTunnel *tunnel);
/**
* @param tunnel object
* Forces reconnection to the tunnel server.
* This method is useful when the device switches from wifi to Edge/3G or vice versa. In most cases the tunnel client socket
* won't be notified promptly that its connection is now zombie, so it is recommended to call this method that will cause
* the lost connection to be closed and new connection to be issued.
**/
void linphone_tunnel_reconnect(LinphoneTunnel *tunnel);
/**
* Start tunnel need detection.
* @param tunnel object
* In auto detect mode, the tunnel manager try to establish a real time rtp cummunication with the tunnel server on specified port.
*<br>In case of success, the tunnel is automatically turned off. Otherwise, if no udp commmunication is feasible, tunnel mode is turned on.
*<br> Call this method each time to run the auto detection algorithm
*/
void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel);
/**
* Set an optional http proxy to go through when connecting to tunnel server.
* @param tunnel LinphoneTunnel object
* @param host Http proxy host.
* @param port http proxy port.
* @param username optional http proxy username if the proxy request authentication. Currently only basic authentication is supported. Use NULL if not needed.
* @param password optional http proxy password. Use NULL if not needed.
**/
void linphone_tunnel_set_http_proxy(LinphoneTunnel *tunnel, const char *host, int port, const char* username,const char* passwd);
/**
* Retrieve optional http proxy configuration previously set with linphone_tunnel_set_http_proxy().
* @param tunnel LinphoneTunnel object
* @param host Http proxy host.
* @param port http proxy port.
* @param username optional http proxy username if the proxy request authentication. Currently only basic authentication is supported. Use NULL if not needed.
* @param password optional http proxy password. Use NULL if not needed.
**/
void linphone_tunnel_get_http_proxy(LinphoneTunnel*tunnel,const char **host, int *port, const char **username, const char **passwd);
void linphone_tunnel_set_http_proxy_auth_info(LinphoneTunnel*tunnel, const char* username,const char* passwd);
void linphone_tunnel_enable_logs(LinphoneTunnel *tunnel, bool_t enabled);
/**
* @}
**/
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -146,22 +146,32 @@ typedef struct _LinphoneCallLog{
LinphoneCallStatus status; /**< The status of the call*/
LinphoneAddress *from; /**<Originator of the call as a LinphoneAddress object*/
LinphoneAddress *to; /**<Destination of the call as a LinphoneAddress object*/
char start_date[128]; /**<Human readable string containg the start date*/
char start_date[128]; /**<Human readable string containing the start date*/
int duration; /**<Duration of the call in seconds*/
char *refkey;
void *user_pointer;
rtp_stats_t local_stats;
rtp_stats_t remote_stats;
float quality;
int video_enabled;
struct _LinphoneCore *lc;
time_t start_date_time; /**Start date of the call in seconds as expressed in a time_t */
const char* call_id; /**unique id of a call*/
} LinphoneCallLog;
/**
* Enum describing type of media encryption types.
**/
enum LinphoneMediaEncryption {
LinphoneMediaEncryptionNone,
LinphoneMediaEncryptionSRTP,
LinphoneMediaEncryptionZRTP
};
/**
* Enum describing type of media encryption types.
**/
typedef enum LinphoneMediaEncryption LinphoneMediaEncryption;
/*public: */
@ -173,15 +183,17 @@ const rtp_stats_t *linphone_call_log_get_local_stats(const LinphoneCallLog *cl);
const rtp_stats_t *linphone_call_log_get_remote_stats(const LinphoneCallLog *cl);
char * linphone_call_log_to_str(LinphoneCallLog *cl);
struct _LinphoneCallParams;
/**
* The LinphoneCallParams is an object containing various call related parameters.
* It can be used to retrieve parameters from a currently running call or modify the call's characteristics
* dynamically.
**/
struct _LinphoneCallParams;
typedef struct _LinphoneCallParams LinphoneCallParams;
const PayloadType* linphone_call_params_get_used_audio_codec(const LinphoneCallParams *cp);
const PayloadType* linphone_call_params_get_used_video_codec(const LinphoneCallParams *cp);
LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp);
void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled);
bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp);
@ -192,6 +204,8 @@ bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams
bool_t linphone_call_params_local_conference_mode(const LinphoneCallParams *cp);
void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int bw);
void linphone_call_params_destroy(LinphoneCallParams *cp);
bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp);
void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t enabled);
/**
* Enum describing failure reasons.
@ -202,15 +216,22 @@ enum _LinphoneReason{
LinphoneReasonNoResponse, /**<No response received from remote*/
LinphoneReasonBadCredentials, /**<Authentication failed due to bad or missing credentials*/
LinphoneReasonDeclined, /**<The call has been declined*/
LinphoneReasonNotFound,
LinphoneReasonNotFound, /**<Destination of the calls was not found.*/
LinphoneReasonNotAnswered, /**<The call was not answered in time*/
LinphoneReasonBusy /**<Phone line was busy */
};
/**
* Enum describing failure reasons.
* @ingroup initializing
**/
typedef enum _LinphoneReason LinphoneReason;
const char *linphone_reason_to_string(LinphoneReason err);
/**
* Structure describing policy regarding video streams establishments.
* @ingroup media_parameters
**/
struct _LinphoneVideoPolicy{
bool_t automatically_initiate; /**<Whether video shall be automatically proposed for outgoing calls.*/
@ -218,14 +239,91 @@ struct _LinphoneVideoPolicy{
bool_t unused[2];
};
/**
* Structure describing policy regarding video streams establishments.
* @ingroup media_parameters
**/
typedef struct _LinphoneVideoPolicy LinphoneVideoPolicy;
/**
* The LinphoneCall object represents a call issued or received by the LinphoneCore
* @ingroup call_control
**/
struct _LinphoneCall;
/**
* The LinphoneCall object represents a call issued or received by the LinphoneCore
* @ingroup call_control
**/
typedef struct _LinphoneCall LinphoneCall;
/**
* @addtogroup call_misc
* @{
**/
#define LINPHONE_CALL_STATS_AUDIO 0
#define LINPHONE_CALL_STATS_VIDEO 1
/**
* Enum describing ICE states.
* @ingroup initializing
**/
enum _LinphoneIceState{
LinphoneIceStateNotActivated, /**< ICE has not been activated for this call */
LinphoneIceStateFailed, /**< ICE processing has failed */
LinphoneIceStateInProgress, /**< ICE process is in progress */
LinphoneIceStateHostConnection, /**< ICE has established a direct connection to the remote host */
LinphoneIceStateReflexiveConnection, /**< ICE has established a connection to the remote host through one or several NATs */
LinphoneIceStateRelayConnection /**< ICE has established a connection through a relay */
};
/**
* Enum describing Ice states.
* @ingroup initializing
**/
typedef enum _LinphoneIceState LinphoneIceState;
/**
* The LinphoneCallStats objects carries various statistic informations regarding quality of audio or video streams.
*
* To receive these informations periodically and as soon as they are computed, the application is invited to place a #CallStatsUpdated callback in the LinphoneCoreVTable structure
* it passes for instanciating the LinphoneCore object (see linphone_core_new() ).
*
* At any time, the application can access last computed statistics using linphone_call_get_audio_stats() or linphone_call_get_video_stats().
**/
typedef struct _LinphoneCallStats LinphoneCallStats;
/**
* The LinphoneCallStats objects carries various statistic informations regarding quality of audio or video streams.
*
* To receive these informations periodically and as soon as they are computed, the application is invited to place a #CallStatsUpdated callback in the LinphoneCoreVTable structure
* it passes for instanciating the LinphoneCore object (see linphone_core_new() ).
*
* At any time, the application can access last computed statistics using linphone_call_get_audio_stats() or linphone_call_get_video_stats().
**/
struct _LinphoneCallStats {
int type; /**< Can be either LINPHONE_CALL_STATS_AUDIO or LINPHONE_CALL_STATS_VIDEO*/
jitter_stats_t jitter_stats; /**<jitter buffer statistics, see oRTP documentation for details */
mblk_t* received_rtcp; /**<Last RTCP packet received, as a mblk_t structure. See oRTP documentation for details how to extract information from it*/
mblk_t* sent_rtcp;/**<Last RTCP packet sent, as a mblk_t structure. See oRTP documentation for details how to extract information from it*/
float round_trip_delay; /**<Round trip propagation time in seconds if known, -1 if unknown.*/
LinphoneIceState ice_state; /**< State of ICE processing. */
float download_bandwidth; /**<Download bandwidth measurement of received stream, expressed in kbit/s, including IP/UDP/RTP headers*/
float upload_bandwidth; /**<Download bandwidth measurement of sent stream, expressed in kbit/s, including IP/UDP/RTP headers*/
};
/**
* @}
**/
const LinphoneCallStats *linphone_call_get_audio_stats(const LinphoneCall *call);
const LinphoneCallStats *linphone_call_get_video_stats(const LinphoneCall *call);
/** Callback prototype */
typedef void (*LinphoneCallCbFunc)(struct _LinphoneCall *call,void * user_data);
/**
* LinphoneCallState enum represents the different state a call can reach into.
* The application is notified of state changes through the LinphoneCoreVTable::call_state_changed callback.
@ -249,7 +347,7 @@ typedef enum _LinphoneCallState{
LinphoneCallPausedByRemote, /**<The call is paused by remote end*/
LinphoneCallUpdatedByRemote, /**<The call's parameters change is requested by remote end, used for example when video is added by remote */
LinphoneCallIncomingEarlyMedia, /**<We are proposing early media to an incoming call */
LinphoneCallUpdated, /**<The remote accepted the call update initiated by us */
LinphoneCallUpdating, /**<A call update has been initiated by us */
LinphoneCallReleased /**< The call object is no more retained by the core */
} LinphoneCallState;
@ -286,6 +384,17 @@ void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t
void linphone_call_send_vfu_request(LinphoneCall *call);
void *linphone_call_get_user_pointer(LinphoneCall *call);
void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer);
void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data);
LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call);
void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy);
/**
* Return TRUE if this call is currently part of a conference
*@param call #LinphoneCall
*@return TRUE if part of a conference.
*
@ingroup call_control
*/
bool_t linphone_call_is_in_conference(const LinphoneCall *call);
/**
* Enables or disable echo cancellation for this call
* @param call
@ -316,7 +425,12 @@ void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_t val);
bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call);
/*keep this in sync with mediastreamer2/msvolume.h*/
#define LINPHONE_VOLUME_DB_LOWEST (-120) /**< Lowest measured that can be returned.*/
/**
* Lowest volume measurement that can be returned by linphone_call_get_play_volume() or linphone_call_get_record_volume(), corresponding to pure silence.
* @ingroup call_misc
**/
#define LINPHONE_VOLUME_DB_LOWEST (-120)
/**
* @addtogroup proxies
@ -394,6 +508,8 @@ const char *linphone_proxy_config_get_addr(const LinphoneProxyConfig *obj);
int linphone_proxy_config_get_expires(const LinphoneProxyConfig *obj);
bool_t linphone_proxy_config_register_enabled(const LinphoneProxyConfig *obj);
void linphone_proxy_config_refresh_register(LinphoneProxyConfig *obj);
const char *linphone_proxy_config_get_contact_parameters(const LinphoneProxyConfig *obj);
void linphone_proxy_config_set_contact_parameters(LinphoneProxyConfig *obj, const char *contact_params);
struct _LinphoneCore * linphone_proxy_config_get_core(const LinphoneProxyConfig *obj);
bool_t linphone_proxy_config_get_dial_escape_plus(const LinphoneProxyConfig *cfg);
@ -497,11 +613,19 @@ struct _LinphoneChatRoom;
* @addtogroup chatroom
* @{
*/
/**
* A chat room message to old content to be sent.
* <br> Can be created by linphone_chat_room_create_message().
*/
typedef struct _LinphoneChatMessage LinphoneChatMessage;
/**
* A chat room is the place where text messages are exchanged.
* <br> Can be created by linphone_core_create_chat_room().
*/
typedef struct _LinphoneChatRoom LinphoneChatRoom;
/**
* Create a new chat room for messaging from a sip uri like sip:joe@sip.linphone.org
* @param lc #LinphoneCore object
@ -515,6 +639,11 @@ LinphoneChatRoom * linphone_core_create_chat_room(LinphoneCore *lc, const char *
*/
void linphone_chat_room_destroy(LinphoneChatRoom *cr);
/**
* create a message attached to a dedicated chat room;
*/
LinphoneChatMessage* linphone_chat_room_create_message(const LinphoneChatRoom *cr,const char* message);
/**
* get peer address \link linphone_core_create_chat_room() associated to \endlink this #LinphoneChatRoom
@ -528,7 +657,91 @@ const LinphoneAddress* linphone_chat_room_get_peer_address(LinphoneChatRoom *cr)
* @param msg message to be sent
*/
void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg);
/**
*LinphoneChatMessageState is used to notify if messages have been succesfully delivered or not.
*/
typedef enum _LinphoneChatMessageStates {
LinphoneChatMessageStateIdle, /**<initial state*/
LinphoneChatMessageStateInProgress, /**<delivery in progress**/
LinphoneChatMessageStateDelivered, /**<message succesffully delivered an acknoleged by remote end point*/
LinphoneChatMessageStateNotDelivered /**<message was not delivered*/
}LinphoneChatMessageState;
/**
* to string function
*/
const char* linphone_chat_message_state_to_string(const LinphoneChatMessageState state);
/**
* Clone a chat message
*@param message #LinphoneChatMessage obj
*@return #LinphoneChatMessage
*/
LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* message);
/**
* Set origin of the message
*@param message #LinphoneChatMessage obj
*@param from #LinphoneAddress origin of this message (copied)
*/
void linphone_chat_message_set_from(LinphoneChatMessage* message, const LinphoneAddress* from);
/**
* Get origin of the message
*@param message #LinphoneChatMessage obj
*@return #LinphoneAddress
*/
LinphoneAddress* linphone_chat_message_get_from(const LinphoneChatMessage* message);
/**
* Linphone message can carry external body as defined by rfc2017
* @param message #LinphoneChatMessage
* @return external body url or NULL if not present.
*/
const char* linphone_chat_message_get_external_body_url(const LinphoneChatMessage* message);
/**
* Linphone message can carry external body as defined by rfc2017
*
* @param message a LinphoneChatMessage
* @param url ex: access-type=URL; URL="http://www.foo.com/file"
*/
void linphone_chat_message_set_external_body_url(LinphoneChatMessage* message,const char* url);
/**
* Get text part of this message
* @return text or NULL if no text.
*/
const char * linphone_chat_message_get_text(const LinphoneChatMessage* message);
/**
* user pointer get function
*/
void* linphone_chat_message_get_user_data(const LinphoneChatMessage* message);
/**
* user pointer set function
*/
void linphone_chat_message_set_user_data(LinphoneChatMessage* message,void*);
/**
* Call back used to notify message delivery status
*@param msg #LinphoneChatMessage object
*@param status LinphoneChatMessageState
*@param ud application user data
*/
typedef void (*LinphoneChatMessageStateChangeCb)(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud);
/**
* send a message to peer member of this chat room.
* @param cr #LinphoneChatRoom object
* @param msg #LinphoneChatMessage message to be sent
* @param status_cb LinphoneChatMessageStateChangeCb status callback invoked when message is delivered or could not be delivered. May be NULL
* @param ud user data for the status cb.
*/
void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* msg,LinphoneChatMessageStateChangeCb status_cb,void* ud);
LinphoneCore* linphone_chat_room_get_lc(LinphoneChatRoom *cr);
LinphoneChatRoom* linphone_chat_message_get_chat_room(LinphoneChatMessage *msg);
char* linphone_chat_message_get_message(LinphoneChatMessage *msg);
const LinphoneAddress* linphone_chat_message_get_peer_address(LinphoneChatMessage *msg);
void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void * ud);
void * linphone_chat_room_get_user_data(LinphoneChatRoom *cr);
@ -600,6 +813,7 @@ typedef void (*AuthInfoRequested)(struct _LinphoneCore *lc, const char *realm, c
typedef void (*CallLogUpdated)(struct _LinphoneCore *lc, struct _LinphoneCallLog *newcl);
/**
* Callback prototype
* @deprecated use #MessageReceived instead.
*
* @param lc #LinphoneCore object
* @param room #LinphoneChatRoom involved in this conversation. Can be be created by the framework in case \link #LinphoneAddress the from \endlink is not present in any chat room.
@ -607,12 +821,25 @@ typedef void (*CallLogUpdated)(struct _LinphoneCore *lc, struct _LinphoneCallLog
* @param message incoming message
* */
typedef void (*TextMessageReceived)(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from, const char *message);
/**
* Chat message callback prototype
*
* @param lc #LinphoneCore object
* @param room #LinphoneChatRoom involved in this conversation. Can be be created by the framework in case \link #LinphoneAddress the from \endlink is not present in any chat room.
* @param LinphoneChatMessage incoming message
* */
typedef void (*MessageReceived)(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *message);
/** Callback prototype */
typedef void (*DtmfReceived)(struct _LinphoneCore* lc, LinphoneCall *call, int dtmf);
/** Callback prototype */
typedef void (*ReferReceived)(struct _LinphoneCore *lc, const char *refer_to);
/** Callback prototype */
typedef void (*BuddyInfoUpdated)(struct _LinphoneCore *lc, LinphoneFriend *lf);
/** Callback prototype for in progress transfers. The new_call_state is the state of the call resulting of the transfer, at the other party. */
typedef void (*LinphoneTransferStateChanged)(struct _LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state);
/** Callback prototype for receiving quality statistics for calls*/
typedef void (*CallStatsUpdated)(struct _LinphoneCore *lc, LinphoneCall *call, const LinphoneCallStats *stats);
/**
* This structure holds all callbacks that the application should implement.
@ -626,17 +853,20 @@ typedef struct _LinphoneVTable{
NewSubscribtionRequestCb new_subscription_request; /**< Notify about pending subscription request */
AuthInfoRequested auth_info_requested; /**< Ask the application some authentication information */
CallLogUpdated call_log_updated; /**< Notifies that call log list has been updated */
TextMessageReceived text_received; /**< A text message has been received */
TextMessageReceived text_received; /** @deprecated, use #message_received instead <br> A text message has been received */
MessageReceived message_received; /** a message is received, can be text or external body*/
DtmfReceived dtmf_received; /**< A dtmf has been received received */
ReferReceived refer_received; /**< An out of call refer was received */
CallEncryptionChangedCb call_encryption_changed; /**<Notifies on change in the encryption of call streams */
LinphoneTransferStateChanged transfer_state_changed; /**<Notifies when a transfer is in progress */
BuddyInfoUpdated buddy_info_updated; /**< a LinphoneFriend's BuddyInfo has changed*/
NotifyReceivedCb notify_recv; /**< Other notifications*/
DisplayStatusCb display_status; /**< Callback that notifies various events with human readable text.*/
DisplayMessageCb display_message;/**< Callback to display a message to the user */
DisplayMessageCb display_warning;/** Callback to display a warning to the user */
DisplayUrlCb display_url;
ShowInterfaceCb show; /**< Notifies the application that it should show up*/
CallEncryptionChangedCb call_encryption_changed; /**<Notifies on change in the encryption of call streams */
CallStatsUpdated call_stats_updated; /**<Notifies on refreshing of call's statistics. */
DisplayStatusCb display_status; /**< DEPRECATED Callback that notifies various events with human readable text.*/
DisplayMessageCb display_message;/**< DEPRECATED Callback to display a message to the user */
DisplayMessageCb display_warning;/**< DEPRECATED Callback to display a warning to the user */
DisplayUrlCb display_url; /**< DEPRECATED */
ShowInterfaceCb show; /**< DEPRECATED Notifies the application that it should show up*/
} LinphoneCoreVTable;
/**
@ -654,7 +884,8 @@ typedef struct _LCCallbackObj
typedef enum _LinphoneFirewallPolicy{
LinphonePolicyNoFirewall,
LinphonePolicyUseNatAddress,
LinphonePolicyUseStun
LinphonePolicyUseStun,
LinphonePolicyUseIce
} LinphoneFirewallPolicy;
typedef enum _LinphoneWaitingState{
@ -670,15 +901,37 @@ typedef void * (*LinphoneWaitingCallback)(struct _LinphoneCore *lc, void *contex
void linphone_core_enable_logs(FILE *file);
void linphone_core_enable_logs_with_cb(OrtpLogFunc logfunc);
void linphone_core_disable_logs(void);
/*sets the user-agent string in sip messages, must be set before linphone_core_new() or linphone_core_init() */
void linphone_core_set_user_agent(const char *ua_name, const char *version);
const char *linphone_core_get_version(void);
const char *linphone_core_get_user_agent_name(void);
const char *linphone_core_get_user_agent_version(void);
LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable,
const char *config_path, const char *factory_config, void* userdata);
/* function to be periodically called in a main loop */
/* For ICE to work properly it should be called every 20ms */
void linphone_core_iterate(LinphoneCore *lc);
#if 0 /*not implemented yet*/
/**
* @ingroup initializing
* Provide Linphone Core with an unique identifier. This be later used to identified contact address coming from this device.
* Value is not saved.
* @param lc object
* @param string identifying the device, can be EMEI or UDID
*
*/
void linphone_core_set_device_identifier(LinphoneCore *lc,const char* device_id);
/**
* @ingroup initializing
* get Linphone unique identifier
*
*/
const char* linphone_core_get_device_identifier(const LinphoneCore *lc);
#endif
/*sets the user-agent string in sip messages, ideally called just after linphone_core_new() or linphone_core_init() */
void linphone_core_set_user_agent(LinphoneCore *lc, const char *ua_name, const char *version);
LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url);
@ -708,6 +961,8 @@ int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *call);
int linphone_core_redirect_call(LinphoneCore *lc, LinphoneCall *call, const char *redirect_uri);
int linphone_core_decline_call(LinphoneCore *lc, LinphoneCall * call, LinphoneReason reason);
int linphone_core_terminate_all_calls(LinphoneCore *lc);
int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call);
@ -776,16 +1031,46 @@ const MSList *linphone_core_get_video_codecs(const LinphoneCore *lc);
int linphone_core_set_video_codecs(LinphoneCore *lc, MSList *codecs);
bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, PayloadType *pt);
bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, const PayloadType *pt);
int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadType *pt, bool_t enable);
PayloadType* linphone_core_find_payload_type(LinphoneCore* lc, const char* type, int rate) ;
/**
* Wildcard value used by #linphone_core_find_payload_type to ignore rate in search algirithm
* @ingroup media_parameters
*/
#define LINPHONE_FIND_PAYLOAD_IGNORE_RATE -1
/**
* Wildcard value used by #linphone_core_find_payload_type to ignore channel in search algirithm
* @ingroup media_parameters
*/
#define LINPHONE_FIND_PAYLOAD_IGNORE_CHANNELS -1
/**
* Get payload type from mime type and clock rate
* @ingroup media_parameters
* This function searches in audio and video codecs for the given payload type name and clockrate.
* @param lc #LinphoneCore object
* @param type payload mime type (I.E SPEEX, PCMU, VP8)
* @param rate can be #LINPHONE_FIND_PAYLOAD_IGNORE_RATE
* @param channels number of channels, can be #LINPHONE_FIND_PAYLOAD_IGNORE_CHANNELS
* @return Returns NULL if not found.
*/
PayloadType* linphone_core_find_payload_type(LinphoneCore* lc, const char* type, int rate, int channels) ;
int linphone_core_get_payload_type_number(LinphoneCore *lc, const PayloadType *pt);
const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt);
bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, PayloadType *pt);
/**
* @ingroup proxy
*Create a proxy config with default value from Linphone core.
*@param lc #LinphoneCore object
*@return #LinphoneProxyConfig with defualt value set
*/
LinphoneProxyConfig * linphone_core_create_proxy_config(LinphoneCore *lc);
int linphone_core_add_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config);
void linphone_core_clear_proxy_config(LinphoneCore *lc);
@ -812,20 +1097,40 @@ void linphone_core_abort_authentication(LinphoneCore *lc, LinphoneAuthInfo *inf
void linphone_core_clear_all_auth_info(LinphoneCore *lc);
void linphone_core_enable_audio_adaptive_jittcomp(LinphoneCore *lc, bool_t enable);
bool_t linphone_core_audio_adaptive_jittcomp_enabled(LinphoneCore *lc);
int linphone_core_get_audio_jittcomp(LinphoneCore *lc);
void linphone_core_set_audio_jittcomp(LinphoneCore *lc, int value);
void linphone_core_enable_video_adaptive_jittcomp(LinphoneCore *lc, bool_t enable);
bool_t linphone_core_video_adaptive_jittcomp_enabled(LinphoneCore *lc);
int linphone_core_get_video_jittcomp(LinphoneCore *lc);
void linphone_core_set_video_jittcomp(LinphoneCore *lc, int value);
int linphone_core_get_audio_port(const LinphoneCore *lc);
void linphone_core_get_audio_port_range(const LinphoneCore *lc, int *min_port, int *max_port);
int linphone_core_get_video_port(const LinphoneCore *lc);
void linphone_core_get_video_port_range(const LinphoneCore *lc, int *min_port, int *max_port);
int linphone_core_get_nortp_timeout(const LinphoneCore *lc);
void linphone_core_set_audio_port(LinphoneCore *lc, int port);
void linphone_core_set_audio_port_range(LinphoneCore *lc, int min_port, int max_port);
void linphone_core_set_video_port(LinphoneCore *lc, int port);
void linphone_core_set_video_port_range(LinphoneCore *lc, int min_port, int max_port);
void linphone_core_set_nortp_timeout(LinphoneCore *lc, int port);
void linphone_core_set_use_info_for_dtmf(LinphoneCore *lc, bool_t use_info);
@ -855,6 +1160,10 @@ void linphone_core_set_inc_timeout(LinphoneCore *lc, int seconds);
int linphone_core_get_inc_timeout(LinphoneCore *lc);
void linphone_core_set_in_call_timeout(LinphoneCore *lc, int seconds);
int linphone_core_get_in_call_timeout(LinphoneCore *lc);
void linphone_core_set_stun_server(LinphoneCore *lc, const char *server);
const char * linphone_core_get_stun_server(const LinphoneCore *lc);
@ -883,9 +1192,11 @@ int linphone_core_get_rec_level(LinphoneCore *lc);
void linphone_core_set_ring_level(LinphoneCore *lc, int level);
void linphone_core_set_play_level(LinphoneCore *lc, int level);
void linphone_core_set_mic_gain_db(LinphoneCore *lc, float level);
float linphone_core_get_mic_gain_db(LinphoneCore *lc);
void linphone_core_set_playback_gain_db(LinphoneCore *lc, float level);
float linphone_core_get_playback_gain_db(LinphoneCore *lc);
void linphone_core_set_rec_level(LinphoneCore *lc, int level);
const char * linphone_core_get_ringer_device(LinphoneCore *lc);
const char * linphone_core_get_playback_device(LinphoneCore *lc);
@ -899,6 +1210,7 @@ void linphone_core_set_ring(LinphoneCore *lc, const char *path);
const char *linphone_core_get_ring(const LinphoneCore *lc);
void linphone_core_verify_server_certificates(LinphoneCore *lc, bool_t yesno);
void linphone_core_set_root_ca(LinphoneCore *lc, const char *path);
const char *linphone_core_get_root_ca(LinphoneCore *lc);
void linphone_core_set_ringback(LinphoneCore *lc, const char *path);
const char * linphone_core_get_ringback(const LinphoneCore *lc);
@ -923,7 +1235,6 @@ void linphone_core_mute_mic(LinphoneCore *lc, bool_t muted);
**/
bool_t linphone_core_is_mic_muted(LinphoneCore *lc);
bool_t linphone_core_is_audio_muted(LinphoneCore *lc);
bool_t linphone_core_is_rtp_muted(LinphoneCore *lc);
bool_t linphone_core_get_rtp_no_xmit_on_audio_mute(const LinphoneCore *lc);
@ -933,6 +1244,9 @@ void linphone_core_set_rtp_no_xmit_on_audio_mute(LinphoneCore *lc, bool_t val);
/* returns a list of LinphoneCallLog */
const MSList * linphone_core_get_call_logs(LinphoneCore *lc);
void linphone_core_clear_call_logs(LinphoneCore *lc);
int linphone_core_get_missed_calls_count(LinphoneCore *lc);
void linphone_core_reset_missed_calls_count(LinphoneCore *lc);
void linphone_core_remove_call_log(LinphoneCore *lc, LinphoneCallLog *call_log);
/* video support */
bool_t linphone_core_video_supported(LinphoneCore *lc);
@ -964,8 +1278,9 @@ const char** linphone_core_get_video_devices(const LinphoneCore *lc);
int linphone_core_set_video_device(LinphoneCore *lc, const char *id);
const char *linphone_core_get_video_device(const LinphoneCore *lc);
/* Set static picture to be used when "Static picture" is the video device */
/* Set and get static picture to be used when "Static picture" is the video device */
int linphone_core_set_static_picture(LinphoneCore *lc, const char *path);
const char *linphone_core_get_static_picture(LinphoneCore *lc);
/* Set and get frame rate for static picture */
int linphone_core_set_static_picture_fps(LinphoneCore *lc, float fps);
@ -1002,17 +1317,15 @@ void linphone_core_set_mtu(LinphoneCore *lc, int mtu);
/**
* @ingroup network_parameters
* This method is called by the application to notify the linphone core library when network is reachable.
* Calling this method with true trigger linphone to initiate a registration process for all proxy
* configuration with parameter register set to enable.
* This method disable the automatic registration mode. It means you must call this method after each network state changes
*
* Calling this method with true trigger linphone to initiate a registration process for all proxies.
* Calling this method disables the automatic network detection mode. It means you must call this method after each network state changes.
*/
void linphone_core_set_network_reachable(LinphoneCore* lc,bool_t value);
/**
* @ingroup network_parameters
* return network state either as positioned by the application or by linphone
* return network state either as positioned by the application or by linphone itself.
*/
bool_t linphone_core_is_network_reachabled(LinphoneCore* lc);
bool_t linphone_core_is_network_reachable(LinphoneCore* lc);
/**
* @ingroup network_parameters
@ -1058,6 +1371,8 @@ void linphone_core_set_rtp_transport_factories(LinphoneCore* lc, LinphoneRtpTran
int linphone_core_get_current_call_stats(LinphoneCore *lc, rtp_stats_t *local, rtp_stats_t *remote);
int linphone_core_get_calls_nb(const LinphoneCore *lc);
const MSList *linphone_core_get_calls(LinphoneCore *lc);
LinphoneGlobalState linphone_core_get_global_state(const LinphoneCore *lc);
@ -1069,7 +1384,7 @@ void linphone_core_refresh_registers(LinphoneCore* lc);
/* Path to the file storing secrets cache */
void linphone_core_set_zrtp_secrets_file(LinphoneCore *lc, const char* file);
const char *linphone_core_get_zrtp_secrets_file(LinphoneCore *lc);
const LinphoneCall* linphone_core_find_call_from_uri(LinphoneCore *lc, const char *uri);
@ -1120,6 +1435,17 @@ typedef struct LinphoneTunnel LinphoneTunnel;
*/
LinphoneTunnel *linphone_core_get_tunnel(LinphoneCore *lc);
void linphone_core_set_sip_dscp(LinphoneCore *lc, int dscp);
int linphone_core_get_sip_dscp(const LinphoneCore *lc);
void linphone_core_set_audio_dscp(LinphoneCore *lc, int dscp);
int linphone_core_get_audio_dscp(const LinphoneCore *lc);
void linphone_core_set_video_dscp(LinphoneCore *lc, int dscp);
int linphone_core_get_video_dscp(const LinphoneCore *lc);
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -56,9 +56,10 @@ void linphone_sound_daemon_destroy(LinphoneSoundDaemon *obj);
* Enum describing the result of the echo canceller calibration process.
**/
typedef enum {
LinphoneEcCalibratorInProgress,
LinphoneEcCalibratorDone,
LinphoneEcCalibratorFailed
LinphoneEcCalibratorInProgress, /**< The echo canceller calibration process is on going. */
LinphoneEcCalibratorDone, /**< The echo canceller calibration has been performed and produced an echo delay measure. */
LinphoneEcCalibratorFailed, /**< The echo canceller calibration process has failed. */
LinphoneEcCalibratorDoneNoEcho /**< The echo canceller calibration has been performed and no echo has been detected. */
}LinphoneEcCalibratorStatus;
@ -86,6 +87,20 @@ typedef bool_t (*LinphoneCoreIterateHook)(void *data);
void linphone_core_add_iterate_hook(LinphoneCore *lc, LinphoneCoreIterateHook hook, void *hook_data);
void linphone_core_remove_iterate_hook(LinphoneCore *lc, LinphoneCoreIterateHook hook, void *hook_data);
/**
* @ingroup misc
*Function to get call country code from ISO 3166-1 alpha-2 code, ex: FR returns 33
*@param iso country code alpha2
*@return call country code or -1 if not found
*/
int linphone_dial_plan_lookup_ccc_from_iso(const char* iso);
/**
* @ingroup misc
*Function to get call country code from an e164 number, ex: +33952650121 will return 33
*@param e164 phone number
*@return call country code or -1 if not found
*/
int linphone_dial_plan_lookup_ccc_from_e164(const char* e164);
#ifdef __cplusplus
}

View file

@ -184,10 +184,10 @@ void lp_config_parse(LpConfig *lpconfig, FILE *file){
if (pos2==NULL) pos2=pos1+strlen(pos1);
else {
*pos2='\0'; /*replace the '\n' */
pos2--;
}
/* remove ending white spaces */
for (; pos2>pos1 && *pos2==' ';pos2--) *pos2='\0';
for (; pos2>pos1 && pos2[-1]==' ';pos2--) pos2[-1]='\0';
if (pos2-pos1>=0){
/* found a pair key,value */
if (cur!=NULL){
@ -198,7 +198,7 @@ void lp_config_parse(LpConfig *lpconfig, FILE *file){
ms_free(item->value);
item->value=strdup(pos1);
}
/*printf("Found %s %s=%s\n",cur->name,key,pos1);*/
/*printf("Found %s %s={%s}\n",cur->name,key,pos1);*/
}else{
ms_warning("found key,item but no sections");
}
@ -271,9 +271,46 @@ const char *lp_config_get_string(LpConfig *lpconfig, const char *section, const
return default_string;
}
bool_t lp_config_get_range(LpConfig *lpconfig, const char *section, const char *key, int *min, int *max, int default_min, int default_max) {
const char *str = lp_config_get_string(lpconfig, section, key, NULL);
if (str != NULL) {
char *minusptr = strchr(str, '-');
if ((minusptr == NULL) || (minusptr == str)) {
*min = default_min;
*max = default_max;
return FALSE;
}
*min = atoi(str);
*max = atoi(minusptr + 1);
return TRUE;
} else {
*min = default_min;
*max = default_max;
return TRUE;
}
}
int lp_config_get_int(LpConfig *lpconfig,const char *section, const char *key, int default_value){
const char *str=lp_config_get_string(lpconfig,section,key,NULL);
if (str!=NULL) return atoi(str);
if (str!=NULL) {
int ret=0;
if (strstr(str,"0x")==str){
sscanf(str,"%x",&ret);
}else ret=atoi(str);
return ret;
}
else return default_value;
}
int64_t lp_config_get_int64(LpConfig *lpconfig,const char *section, const char *key, int64_t default_value){
const char *str=lp_config_get_string(lpconfig,section,key,NULL);
if (str!=NULL) {
#ifdef WIN32
return (int64_t)_atoi64(str);
#else
return atoll(str);
#endif
}
else return default_value;
}
@ -306,12 +343,31 @@ void lp_config_set_string(LpConfig *lpconfig,const char *section, const char *ke
lpconfig->modified++;
}
void lp_config_set_range(LpConfig *lpconfig, const char *section, const char *key, int min_value, int max_value) {
char tmp[30];
snprintf(tmp, sizeof(tmp), "%i-%i", min_value, max_value);
lp_config_set_string(lpconfig, section, key, tmp);
}
void lp_config_set_int(LpConfig *lpconfig,const char *section, const char *key, int value){
char tmp[30];
snprintf(tmp,sizeof(tmp),"%i",value);
lp_config_set_string(lpconfig,section,key,tmp);
}
void lp_config_set_int_hex(LpConfig *lpconfig,const char *section, const char *key, int value){
char tmp[30];
snprintf(tmp,sizeof(tmp),"0x%x",value);
lp_config_set_string(lpconfig,section,key,tmp);
}
void lp_config_set_int64(LpConfig *lpconfig,const char *section, const char *key, int64_t value){
char tmp[30];
snprintf(tmp,sizeof(tmp),"%lli",(long long)value);
lp_config_set_string(lpconfig,section,key,tmp);
}
void lp_config_set_float(LpConfig *lpconfig,const char *section, const char *key, float value){
char tmp[30];
snprintf(tmp,sizeof(tmp),"%f",value);

View file

@ -25,6 +25,8 @@
#ifndef LPCONFIG_H
#define LPCONFIG_H
#include <ortp/port.h>
/**
* The LpConfig object is used to manipulate a configuration file.
*
@ -49,6 +51,20 @@ typedef struct _LpConfig LpConfig;
extern "C" {
#endif
#define LP_CONFIG_DEFAULT_STRING(config, name, default) \
(config) ? (lp_config_get_string(config, "default_values", name, default)) : (default)
#define LP_CONFIG_DEFAULT_INT(config, name, default) \
(config) ? (lp_config_get_int(config, "default_values", name, default)) : (default)
#define LP_CONFIG_DEFAULT_INT64(config, name, default) \
(config) ? (lp_config_get_int64(config, "default_values", name, default)) : (default)
#define LP_CONFIG_DEFAULT_FLOAT(config, name, default) \
(config) ? (lp_config_get_float(config, "default_values", name, default)) : (default)
LpConfig * lp_config_new(const char *filename);
int lp_config_read_file(LpConfig *lpconfig, const char *filename);
/**
@ -59,6 +75,14 @@ int lp_config_read_file(LpConfig *lpconfig, const char *filename);
**/
const char *lp_config_get_string(LpConfig *lpconfig, const char *section, const char *key, const char *default_string);
int lp_config_read_file(LpConfig *lpconfig, const char *filename);
/**
* Retrieves a configuration item as a range, given its section, key, and default min and max values.
*
* @ingroup misc
* @return TRUE if the value is successfully parsed as a range, FALSE otherwise.
* If FALSE is returned, min and max are filled respectively with default_min and default_max values.
*/
bool_t lp_config_get_range(LpConfig *lpconfig, const char *section, const char *key, int *min, int *max, int default_min, int default_max);
/**
* Retrieves a configuration item as an integer, given its section, key, and default value.
*
@ -66,6 +90,16 @@ int lp_config_read_file(LpConfig *lpconfig, const char *filename);
* The default integer value is returned if the config item isn't found.
**/
int lp_config_get_int(LpConfig *lpconfig,const char *section, const char *key, int default_value);
/**
* Retrieves a configuration item as a 64 bit integer, given its section, key, and default value.
*
* @ingroup misc
* The default integer value is returned if the config item isn't found.
**/
int64_t lp_config_get_int64(LpConfig *lpconfig,const char *section, const char *key, int64_t default_value);
int lp_config_read_file(LpConfig *lpconfig, const char *filename);
/**
* Retrieves a configuration item as a float, given its section, key, and default value.
@ -80,12 +114,33 @@ float lp_config_get_float(LpConfig *lpconfig,const char *section, const char *ke
* @ingroup misc
**/
void lp_config_set_string(LpConfig *lpconfig,const char *section, const char *key, const char *value);
/**
* Sets a range config item
*
* @ingroup misc
*/
void lp_config_set_range(LpConfig *lpconfig, const char *section, const char *key, int min_value, int max_value);
/**
* Sets an integer config item
*
* @ingroup misc
**/
void lp_config_set_int(LpConfig *lpconfig,const char *section, const char *key, int value);
/**
* Sets an integer config item, but store it as hexadecimal
*
* @ingroup misc
**/
void lp_config_set_int_hex(LpConfig *lpconfig,const char *section, const char *key, int value);
/**
* Sets a 64 bits integer config item
*
* @ingroup misc
**/
void lp_config_set_int64(LpConfig *lpconfig,const char *section, const char *key, int64_t value);
/**
* Sets a float config item
*

View file

@ -19,6 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "private.h"
#include "lpconfig.h"
#include "mediastreamer2/mediastream.h"
#include <stdlib.h>
#include <stdio.h>
@ -181,12 +182,12 @@ static void payload_type_set_enable(PayloadType *pt,int value)
else payload_type_unset_flag(pt,PAYLOAD_TYPE_ENABLED);
}
static bool_t payload_type_enabled(PayloadType *pt) {
static bool_t payload_type_enabled(const PayloadType *pt) {
return (((pt)->flags & PAYLOAD_TYPE_ENABLED)!=0);
}
bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, PayloadType *pt){
if (ms_list_find(lc->codecs_conf.audio_codecs,pt) || ms_list_find(lc->codecs_conf.video_codecs,pt)){
bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, const PayloadType *pt){
if (ms_list_find(lc->codecs_conf.audio_codecs, (PayloadType*) pt) || ms_list_find(lc->codecs_conf.video_codecs, (PayloadType*)pt)){
return payload_type_enabled(pt);
}
ms_error("Getting enablement status of codec not in audio or video list of PayloadType !");
@ -196,12 +197,17 @@ bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, PayloadType *pt){
int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadType *pt, bool_t enabled){
if (ms_list_find(lc->codecs_conf.audio_codecs,pt) || ms_list_find(lc->codecs_conf.video_codecs,pt)){
payload_type_set_enable(pt,enabled);
_linphone_core_codec_config_write(lc);
return 0;
}
ms_error("Enabling codec not in audio or video list of PayloadType !");
return -1;
}
int linphone_core_get_payload_type_number(LinphoneCore *lc, const PayloadType *pt){
return payload_type_get_number(pt);
}
const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt){
if (ms_filter_codec_supported(pt->mime_type)){
MSFilterDesc *desc=ms_filter_get_encoder(pt->mime_type);
@ -402,19 +408,29 @@ static int sendStunRequest(int sock, const struct sockaddr *server, socklen_t ad
int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen){
struct addrinfo hints,*res=NULL;
int family = PF_INET;
int port_int = 3478;
int ret;
const char *port;
char port[6];
char host[NI_MAXHOST];
char *p;
host[NI_MAXHOST-1]='\0';
strncpy(host,server,sizeof(host)-1);
p=strchr(host,':');
if (p) {
*p='\0';
port=p+1;
}else port="3478";
char *p1, *p2;
if ((sscanf(server, "[%64[^]]]:%d", host, &port_int) == 2) || (sscanf(server, "[%64[^]]]", host) == 1)) {
family = PF_INET6;
} else {
p1 = strchr(server, ':');
p2 = strrchr(server, ':');
if (p1 && p2 && (p1 != p2)) {
family = PF_INET6;
host[NI_MAXHOST-1]='\0';
strncpy(host, server, sizeof(host) - 1);
} else if (sscanf(server, "%[^:]:%d", host, &port_int) != 2) {
host[NI_MAXHOST-1]='\0';
strncpy(host, server, sizeof(host) - 1);
}
}
snprintf(port, sizeof(port), "%d", port_int);
memset(&hints,0,sizeof(hints));
hints.ai_family=PF_INET;
hints.ai_family=family;
hints.ai_socktype=SOCK_DGRAM;
hints.ai_protocol=IPPROTO_UDP;
ret=getaddrinfo(host,port,&hints,&res);
@ -450,12 +466,15 @@ static int recvStunResponse(ortp_socket_t sock, char *ipaddr, int *port, int *id
return len;
}
void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
/* this functions runs a simple stun test and return the number of milliseconds to complete the tests, or -1 if the test were failed.*/
int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
const char *server=linphone_core_get_stun_server(lc);
StunCandidate *ac=&call->ac;
StunCandidate *vc=&call->vc;
if (lc->sip_conf.ipv6_enabled){
ms_warning("stun support is not implemented for ipv6");
return;
return -1;
}
if (server!=NULL){
struct sockaddr_storage ss;
@ -466,30 +485,28 @@ void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
bool_t got_audio,got_video;
bool_t cone_audio=FALSE,cone_video=FALSE;
struct timeval init,cur;
SalEndpointCandidate *ac,*vc;
ac=&call->localdesc->streams[0].candidates[0];
vc=&call->localdesc->streams[1].candidates[0];
double elapsed;
int ret=0;
if (parse_hostname_to_addr(server,&ss,&ss_len)<0){
ms_error("Fail to parser stun server address: %s",server);
return;
return -1;
}
if (lc->vtable.display_status!=NULL)
lc->vtable.display_status(lc,_("Stun lookup in progress..."));
/*create the two audio and video RTP sockets, and send STUN message to our stun server */
sock1=create_socket(call->audio_port);
if (sock1==-1) return;
if (sock1==-1) return -1;
if (video_enabled){
sock2=create_socket(call->video_port);
if (sock2==-1) return ;
if (sock2==-1) return -1;
}
got_audio=FALSE;
got_video=FALSE;
gettimeofday(&init,NULL);
do{
double elapsed;
int id;
if (loops%20==0){
ms_message("Sending stun requests...");
@ -528,10 +545,12 @@ void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
elapsed=((cur.tv_sec-init.tv_sec)*1000.0) + ((cur.tv_usec-init.tv_usec)/1000.0);
if (elapsed>2000) {
ms_message("Stun responses timeout, going ahead.");
ret=-1;
break;
}
loops++;
}while(!(got_audio && (got_video||sock2==-1) ) );
if (ret==0) ret=(int)elapsed;
if (!got_audio){
ms_error("No stun server response for audio port.");
}else{
@ -548,13 +567,392 @@ void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
}
}
}
if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0)
|| sock2==-1){
strcpy(call->localdesc->addr,ac->addr);
}
close_socket(sock1);
if (sock2!=-1) close_socket(sock2);
return ret;
}
return -1;
}
int linphone_core_get_edge_bw(LinphoneCore *lc){
int edge_bw=lp_config_get_int(lc->config,"net","edge_bw",20);
return edge_bw;
}
int linphone_core_get_edge_ptime(LinphoneCore *lc){
int edge_ptime=lp_config_get_int(lc->config,"net","edge_ptime",100);
return edge_ptime;
}
void linphone_core_adapt_to_network(LinphoneCore *lc, int ping_time_ms, LinphoneCallParams *params){
if (ping_time_ms>0 && lp_config_get_int(lc->config,"net","activate_edge_workarounds",0)==1){
ms_message("Stun server ping time is %i ms",ping_time_ms);
int threshold=lp_config_get_int(lc->config,"net","edge_ping_time",500);
if (ping_time_ms>threshold){
/* we might be in a 2G network*/
params->low_bandwidth=TRUE;
}/*else use default settings */
}
if (params->low_bandwidth){
params->up_bw=params->down_bw=linphone_core_get_edge_bw(lc);
params->up_ptime=params->down_ptime=linphone_core_get_edge_ptime(lc);
params->has_video=FALSE;
}
}
int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call)
{
char local_addr[64];
struct sockaddr_storage ss;
socklen_t ss_len;
IceCheckList *audio_check_list;
IceCheckList *video_check_list;
const char *server = linphone_core_get_stun_server(lc);
if ((server == NULL) || (call->ice_session == NULL)) return -1;
audio_check_list = ice_session_check_list(call->ice_session, 0);
video_check_list = ice_session_check_list(call->ice_session, 1);
if (audio_check_list == NULL) return -1;
if (lc->sip_conf.ipv6_enabled){
ms_warning("stun support is not implemented for ipv6");
return -1;
}
if (parse_hostname_to_addr(server, &ss, &ss_len) < 0) {
ms_error("Fail to parser stun server address: %s", server);
return -1;
}
if (lc->vtable.display_status != NULL)
lc->vtable.display_status(lc, _("ICE local candidates gathering in progress..."));
/* Gather local host candidates. */
if (linphone_core_get_local_ip_for(AF_INET, server, local_addr) < 0) {
ms_error("Fail to get local ip");
return -1;
}
if ((ice_check_list_state(audio_check_list) != ICL_Completed) && (ice_check_list_candidates_gathered(audio_check_list) == FALSE)) {
ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port, 1, NULL);
ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port + 1, 2, NULL);
call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateInProgress;
}
if (call->params.has_video && (video_check_list != NULL)
&& (ice_check_list_state(video_check_list) != ICL_Completed) && (ice_check_list_candidates_gathered(video_check_list) == FALSE)) {
ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port, 1, NULL);
ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port + 1, 2, NULL);
call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateInProgress;
}
ms_message("ICE: gathering candidate from [%s]",server);
/* Gather local srflx candidates. */
ice_session_gather_candidates(call->ice_session, ss, ss_len);
return 0;
}
void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call)
{
IceCheckList *audio_check_list;
IceCheckList *video_check_list;
IceSessionState session_state;
if (call->ice_session == NULL) return;
audio_check_list = ice_session_check_list(call->ice_session, 0);
video_check_list = ice_session_check_list(call->ice_session, 1);
if (audio_check_list == NULL) return;
session_state = ice_session_state(call->ice_session);
if ((session_state == IS_Completed) || ((session_state == IS_Failed) && (ice_session_has_completed_check_list(call->ice_session) == TRUE))) {
if (ice_check_list_state(audio_check_list) == ICL_Completed) {
switch (ice_check_list_selected_valid_candidate_type(audio_check_list)) {
case ICT_HostCandidate:
call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateHostConnection;
break;
case ICT_ServerReflexiveCandidate:
case ICT_PeerReflexiveCandidate:
call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateReflexiveConnection;
break;
case ICT_RelayedCandidate:
call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateRelayConnection;
break;
}
} else {
call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateFailed;
}
if (call->params.has_video && (video_check_list != NULL)) {
if (ice_check_list_state(video_check_list) == ICL_Completed) {
switch (ice_check_list_selected_valid_candidate_type(video_check_list)) {
case ICT_HostCandidate:
call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateHostConnection;
break;
case ICT_ServerReflexiveCandidate:
case ICT_PeerReflexiveCandidate:
call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateReflexiveConnection;
break;
case ICT_RelayedCandidate:
call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateRelayConnection;
break;
}
} else {
call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateFailed;
}
}
} else if (session_state == IS_Running) {
call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateInProgress;
if (call->params.has_video && (video_check_list != NULL)) {
call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateInProgress;
}
} else {
call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateFailed;
if (call->params.has_video && (video_check_list != NULL)) {
call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateFailed;
}
}
}
void linphone_core_update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session)
{
const char *rtp_addr, *rtcp_addr;
IceSessionState session_state = ice_session_state(session);
int nb_candidates;
int i, j;
bool_t result;
if (session_state == IS_Completed) {
desc->ice_completed = TRUE;
result = ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, 0), &rtp_addr, NULL, NULL, NULL);
if (result == TRUE) {
strncpy(desc->addr, rtp_addr, sizeof(desc->addr));
} else {
ms_warning("If ICE has completed successfully, rtp_addr should be set!");
}
}
else {
desc->ice_completed = FALSE;
}
strncpy(desc->ice_pwd, ice_session_local_pwd(session), sizeof(desc->ice_pwd));
strncpy(desc->ice_ufrag, ice_session_local_ufrag(session), sizeof(desc->ice_ufrag));
for (i = 0; i < desc->nstreams; i++) {
SalStreamDescription *stream = &desc->streams[i];
IceCheckList *cl = ice_session_check_list(session, i);
nb_candidates = 0;
if (cl == NULL) continue;
if (ice_check_list_state(cl) == ICL_Completed) {
stream->ice_completed = TRUE;
result = ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, i), &rtp_addr, &stream->rtp_port, &rtcp_addr, &stream->rtcp_port);
} else {
stream->ice_completed = FALSE;
result = ice_check_list_default_local_candidate(ice_session_check_list(session, i), &rtp_addr, &stream->rtp_port, &rtcp_addr, &stream->rtcp_port);
}
if (result == TRUE) {
strncpy(stream->rtp_addr, rtp_addr, sizeof(stream->rtp_addr));
strncpy(stream->rtcp_addr, rtcp_addr, sizeof(stream->rtcp_addr));
} else {
memset(stream->rtp_addr, 0, sizeof(stream->rtp_addr));
memset(stream->rtcp_addr, 0, sizeof(stream->rtcp_addr));
}
if ((strlen(ice_check_list_local_pwd(cl)) != strlen(desc->ice_pwd)) || (strcmp(ice_check_list_local_pwd(cl), desc->ice_pwd)))
strncpy(stream->ice_pwd, ice_check_list_local_pwd(cl), sizeof(stream->ice_pwd));
else
memset(stream->ice_pwd, 0, sizeof(stream->ice_pwd));
if ((strlen(ice_check_list_local_ufrag(cl)) != strlen(desc->ice_ufrag)) || (strcmp(ice_check_list_local_ufrag(cl), desc->ice_ufrag)))
strncpy(stream->ice_ufrag, ice_check_list_local_ufrag(cl), sizeof(stream->ice_ufrag));
else
memset(stream->ice_pwd, 0, sizeof(stream->ice_pwd));
stream->ice_mismatch = ice_check_list_is_mismatch(cl);
if ((ice_check_list_state(cl) == ICL_Running) || (ice_check_list_state(cl) == ICL_Completed)) {
memset(stream->ice_candidates, 0, sizeof(stream->ice_candidates));
for (j = 0; j < MIN(ms_list_size(cl->local_candidates), SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES); j++) {
SalIceCandidate *sal_candidate = &stream->ice_candidates[nb_candidates];
IceCandidate *ice_candidate = ms_list_nth_data(cl->local_candidates, j);
const char *default_addr = NULL;
int default_port = 0;
if (ice_candidate->componentID == 1) {
default_addr = stream->rtp_addr;
default_port = stream->rtp_port;
} else if (ice_candidate->componentID == 2) {
default_addr = stream->rtcp_addr;
default_port = stream->rtcp_port;
} else continue;
if (default_addr[0] == '\0') default_addr = desc->addr;
/* Only include the candidates matching the default destination for each component of the stream if the state is Completed as specified in RFC5245 section 9.1.2.2. */
if ((ice_check_list_state(cl) == ICL_Completed)
&& !((ice_candidate->taddr.port == default_port) && (strlen(ice_candidate->taddr.ip) == strlen(default_addr)) && (strcmp(ice_candidate->taddr.ip, default_addr) == 0)))
continue;
strncpy(sal_candidate->foundation, ice_candidate->foundation, sizeof(sal_candidate->foundation));
sal_candidate->componentID = ice_candidate->componentID;
sal_candidate->priority = ice_candidate->priority;
strncpy(sal_candidate->type, ice_candidate_type(ice_candidate), sizeof(sal_candidate->type));
strncpy(sal_candidate->addr, ice_candidate->taddr.ip, sizeof(sal_candidate->addr));
sal_candidate->port = ice_candidate->taddr.port;
if ((ice_candidate->base != NULL) && (ice_candidate->base != ice_candidate)) {
strncpy(sal_candidate->raddr, ice_candidate->base->taddr.ip, sizeof(sal_candidate->raddr));
sal_candidate->rport = ice_candidate->base->taddr.port;
}
nb_candidates++;
}
}
if ((ice_check_list_state(cl) == ICL_Completed) && (ice_session_role(session) == IR_Controlling)) {
int rtp_port, rtcp_port;
memset(stream->ice_remote_candidates, 0, sizeof(stream->ice_remote_candidates));
if (ice_check_list_selected_valid_remote_candidate(cl, &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port) == TRUE) {
strncpy(stream->ice_remote_candidates[0].addr, rtp_addr, sizeof(stream->ice_remote_candidates[0].addr));
stream->ice_remote_candidates[0].port = rtp_port;
strncpy(stream->ice_remote_candidates[1].addr, rtcp_addr, sizeof(stream->ice_remote_candidates[1].addr));
stream->ice_remote_candidates[1].port = rtcp_port;
} else {
ms_error("ice: Selected valid remote candidates should be present if the check list is in the Completed state");
}
} else {
for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES; j++) {
stream->ice_remote_candidates[j].addr[0] = '\0';
stream->ice_remote_candidates[j].port = 0;
}
}
}
}
static void get_default_addr_and_port(uint16_t componentID, const SalMediaDescription *md, const SalStreamDescription *stream, const char **addr, int *port)
{
if (componentID == 1) {
*addr = stream->rtp_addr;
*port = stream->rtp_port;
} else if (componentID == 2) {
*addr = stream->rtcp_addr;
*port = stream->rtcp_port;
} else return;
if ((*addr)[0] == '\0') *addr = md->addr;
}
void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md)
{
bool_t ice_restarted = FALSE;
if ((md->ice_pwd[0] != '\0') && (md->ice_ufrag[0] != '\0')) {
int i, j;
/* Check for ICE restart and set remote credentials. */
if ((strcmp(md->addr, "0.0.0.0") == 0) || (strcmp(md->addr, "::0") == 0)) {
ice_session_restart(call->ice_session);
ice_restarted = TRUE;
} else {
for (i = 0; i < md->nstreams; i++) {
const SalStreamDescription *stream = &md->streams[i];
IceCheckList *cl = ice_session_check_list(call->ice_session, i);
if (cl && (strcmp(stream->rtp_addr, "0.0.0.0") == 0)) {
ice_session_restart(call->ice_session);
ice_restarted = TRUE;
break;
}
}
}
if ((ice_session_remote_ufrag(call->ice_session) == NULL) && (ice_session_remote_pwd(call->ice_session) == NULL)) {
ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd);
} else if (ice_session_remote_credentials_changed(call->ice_session, md->ice_ufrag, md->ice_pwd)) {
if (ice_restarted == FALSE) {
ice_session_restart(call->ice_session);
ice_restarted = TRUE;
}
ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd);
}
for (i = 0; i < md->nstreams; i++) {
const SalStreamDescription *stream = &md->streams[i];
IceCheckList *cl = ice_session_check_list(call->ice_session, i);
if (cl && (stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) {
if (ice_check_list_remote_credentials_changed(cl, stream->ice_ufrag, stream->ice_pwd)) {
if (ice_restarted == FALSE) {
ice_session_restart(call->ice_session);
ice_restarted = TRUE;
}
ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd);
break;
}
}
}
/* Create ICE check lists if needed and parse ICE attributes. */
for (i = 0; i < md->nstreams; i++) {
const SalStreamDescription *stream = &md->streams[i];
IceCheckList *cl = ice_session_check_list(call->ice_session, i);
if (cl == NULL) {
cl = ice_check_list_new();
ice_session_add_check_list(call->ice_session, cl);
switch (stream->type) {
case SalAudio:
if (call->audiostream != NULL) call->audiostream->ice_check_list = cl;
break;
case SalVideo:
if (call->videostream != NULL) call->videostream->ice_check_list = cl;
break;
default:
break;
}
}
if (stream->ice_mismatch == TRUE) {
ice_check_list_set_state(cl, ICL_Failed);
} else if (stream->rtp_port == 0) {
ice_session_remove_check_list(call->ice_session, cl);
} else {
if ((stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0'))
ice_check_list_set_remote_credentials(cl, stream->ice_ufrag, stream->ice_pwd);
for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES; j++) {
const SalIceCandidate *candidate = &stream->ice_candidates[j];
bool_t default_candidate = FALSE;
const char *addr = NULL;
int port = 0;
if (candidate->addr[0] == '\0') break;
if ((candidate->componentID == 0) || (candidate->componentID > 2)) continue;
get_default_addr_and_port(candidate->componentID, md, stream, &addr, &port);
if (addr && (candidate->port == port) && (strlen(candidate->addr) == strlen(addr)) && (strcmp(candidate->addr, addr) == 0))
default_candidate = TRUE;
ice_add_remote_candidate(cl, candidate->type, candidate->addr, candidate->port, candidate->componentID,
candidate->priority, candidate->foundation, default_candidate);
}
if (ice_restarted == FALSE) {
bool_t losing_pairs_added = FALSE;
for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES; j++) {
const SalIceRemoteCandidate *candidate = &stream->ice_remote_candidates[j];
const char *addr = NULL;
int port = 0;
int componentID = j + 1;
if (candidate->addr[0] == '\0') break;
get_default_addr_and_port(componentID, md, stream, &addr, &port);
if (j == 0) {
/* If we receive a re-invite and we finished ICE processing on our side, use the candidates given by the remote. */
ice_check_list_unselect_valid_pairs(cl);
}
ice_add_losing_pair(cl, j + 1, candidate->addr, candidate->port, addr, port);
losing_pairs_added = TRUE;
}
if (losing_pairs_added == TRUE) ice_check_list_check_completed(cl);
}
}
}
for (i = ice_session_nb_check_lists(call->ice_session); i > md->nstreams; i--) {
ice_session_remove_check_list(call->ice_session, ice_session_check_list(call->ice_session, i - 1));
}
ice_session_check_mismatch(call->ice_session);
} else {
/* Response from remote does not contain mandatory ICE attributes, delete the session. */
linphone_call_delete_ice_session(call);
return;
}
if (ice_session_nb_check_lists(call->ice_session) == 0) {
linphone_call_delete_ice_session(call);
}
}
bool_t linphone_core_media_description_contains_video_stream(const SalMediaDescription *md)
{
int i;
for (i = 0; i < md->nstreams; i++) {
if ((md->streams[i].type == SalVideo) && (md->streams[i].rtp_port != 0))
return TRUE;
}
return FALSE;
}
LinphoneCall * is_a_linphone_call(void *user_pointer){
@ -569,6 +967,37 @@ LinphoneProxyConfig * is_a_linphone_proxy_config(void *user_pointer){
return cfg->magic==linphone_proxy_config_magic ? cfg : NULL;
}
unsigned int linphone_core_get_audio_features(LinphoneCore *lc){
unsigned int ret=0;
const char *features=lp_config_get_string(lc->config,"sound","features",NULL);
if (features){
char tmp[256]={0};
char name[256];
char *p,*n;
strncpy(tmp,features,sizeof(tmp)-1);
for(p=tmp;*p!='\0';p++){
if (*p==' ') continue;
n=strchr(p,'|');
if (n) *n='\0';
sscanf(p,"%s",name);
ms_message("Found audio feature %s",name);
if (strcasecmp(name,"PLC")==0) ret|=AUDIO_STREAM_FEATURE_PLC;
else if (strcasecmp(name,"EC")==0) ret|=AUDIO_STREAM_FEATURE_EC;
else if (strcasecmp(name,"EQUALIZER")==0) ret|=AUDIO_STREAM_FEATURE_EQUALIZER;
else if (strcasecmp(name,"VOL_SND")==0) ret|=AUDIO_STREAM_FEATURE_VOL_SND;
else if (strcasecmp(name,"VOL_RCV")==0) ret|=AUDIO_STREAM_FEATURE_VOL_RCV;
else if (strcasecmp(name,"DTMF")==0) ret|=AUDIO_STREAM_FEATURE_DTMF;
else if (strcasecmp(name,"DTMF_ECHO")==0) ret|=AUDIO_STREAM_FEATURE_DTMF_ECHO;
else if (strcasecmp(name,"ALL")==0) ret|=AUDIO_STREAM_FEATURE_ALL;
else if (strcasecmp(name,"NONE")==0) ret=0;
else ms_error("Unsupported audio feature %s requested in config file.",name);
if (!n) break;
p=n;
}
}else ret=AUDIO_STREAM_FEATURE_ALL;
return ret;
}
#ifdef HAVE_GETIFADDRS
@ -582,10 +1011,15 @@ static int get_local_ip_with_getifaddrs(int type, char *address, int size)
if (getifaddrs(&ifpstart) < 0) {
return -1;
}
#ifndef __linux
#define UP_FLAG IFF_UP /* interface is up */
#else
#define UP_FLAG IFF_RUNNING /* resources allocated */
#endif
for (ifp = ifpstart; ifp != NULL; ifp = ifp->ifa_next) {
if (ifp->ifa_addr && ifp->ifa_addr->sa_family == type
&& (ifp->ifa_flags & IFF_RUNNING) && !(ifp->ifa_flags & IFF_LOOPBACK))
&& (ifp->ifa_flags & UP_FLAG) && !(ifp->ifa_flags & IFF_LOOPBACK))
{
getnameinfo(ifp->ifa_addr,
(type == AF_INET6) ?
@ -692,7 +1126,6 @@ int linphone_core_get_local_ip_for(int type, const char *dest, char *result){
void _linphone_core_configure_resolver(){
/*bionic declares _res but does not define nor export it !!*/
#ifdef ANDROID

View file

@ -21,9 +21,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "offeranswer.h"
static bool_t only_telephone_event(const MSList *l){
PayloadType *p=(PayloadType*)l->data;
if (strcasecmp(p->mime_type,"telephone-event")!=0){
return FALSE;
for(;l!=NULL;l=l->next){
PayloadType *p=(PayloadType*)l->data;
if (strcasecmp(p->mime_type,"telephone-event")!=0){
return FALSE;
}
}
return TRUE;
}
@ -203,25 +205,27 @@ static SalStreamDir compute_dir_incoming(SalStreamDir local, SalStreamDir offere
static void initiate_outgoing(const SalStreamDescription *local_offer,
const SalStreamDescription *remote_answer,
SalStreamDescription *result){
if (remote_answer->port!=0)
if (remote_answer->rtp_port!=0)
result->payloads=match_payloads(local_offer->payloads,remote_answer->payloads,TRUE,FALSE);
result->proto=remote_answer->proto;
result->type=local_offer->type;
result->dir=compute_dir_outgoing(local_offer->dir,remote_answer->dir);
if (result->payloads && !only_telephone_event(result->payloads)){
strcpy(result->addr,remote_answer->addr);
result->port=remote_answer->port;
strcpy(result->rtp_addr,remote_answer->rtp_addr);
strcpy(result->rtcp_addr,remote_answer->rtcp_addr);
result->rtp_port=remote_answer->rtp_port;
result->rtcp_port=remote_answer->rtcp_port;
result->bandwidth=remote_answer->bandwidth;
result->ptime=remote_answer->ptime;
}else{
result->port=0;
result->rtp_port=0;
}
if (result->proto == SalProtoRtpSavp) {
/* verify crypto algo */
memset(result->crypto, 0, sizeof(result->crypto));
if (!match_crypto_algo(local_offer->crypto, remote_answer->crypto, &result->crypto[0], &result->crypto_local_tag, FALSE))
result->port = 0;
result->rtp_port = 0;
}
}
@ -233,22 +237,29 @@ static void initiate_incoming(const SalStreamDescription *local_cap,
result->proto=remote_offer->proto;
result->type=local_cap->type;
result->dir=compute_dir_incoming(local_cap->dir,remote_offer->dir);
if (result->payloads && !only_telephone_event(result->payloads)){
strcpy(result->addr,local_cap->addr);
memcpy(result->candidates,local_cap->candidates,sizeof(result->candidates));
result->port=local_cap->port;
if (result->payloads && !only_telephone_event(result->payloads) && (remote_offer->rtp_port!=0 || remote_offer->rtp_port==SalStreamSendOnly)){
strcpy(result->rtp_addr,local_cap->rtp_addr);
strcpy(result->rtcp_addr,local_cap->rtcp_addr);
result->rtp_port=local_cap->rtp_port;
result->rtcp_port=local_cap->rtcp_port;
result->bandwidth=local_cap->bandwidth;
result->ptime=local_cap->ptime;
result->ptime=local_cap->ptime;
}else{
result->port=0;
result->rtp_port=0;
}
if (result->proto == SalProtoRtpSavp) {
/* select crypto algo */
memset(result->crypto, 0, sizeof(result->crypto));
if (!match_crypto_algo(local_cap->crypto, remote_offer->crypto, &result->crypto[0], &result->crypto_local_tag, TRUE))
result->port = 0;
result->rtp_port = 0;
}
strcpy(result->ice_pwd, local_cap->ice_pwd);
strcpy(result->ice_ufrag, local_cap->ice_ufrag);
result->ice_mismatch = local_cap->ice_mismatch;
result->ice_completed = local_cap->ice_completed;
memcpy(result->ice_candidates, local_cap->ice_candidates, sizeof(result->ice_candidates));
memcpy(result->ice_remote_candidates, local_cap->ice_remote_candidates, sizeof(result->ice_remote_candidates));
}
/**
@ -303,7 +314,7 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities
else {
/* create an inactive stream for the answer, as there where no matching stream a local capability */
result->streams[i].dir=SalStreamInactive;
result->streams[i].port=0;
result->streams[i].rtp_port=0;
result->streams[i].type=rs->type;
result->streams[i].proto=rs->proto;
if (rs->type==SalOther){
@ -317,5 +328,9 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities
result->bandwidth=local_capabilities->bandwidth;
result->session_ver=local_capabilities->session_ver;
result->session_id=local_capabilities->session_id;
strcpy(result->ice_pwd, local_capabilities->ice_pwd);
strcpy(result->ice_ufrag, local_capabilities->ice_ufrag);
result->ice_lite = local_capabilities->ice_lite;
result->ice_completed = local_capabilities->ice_completed;
return 0;
}

View file

@ -1,10 +1,8 @@
SUBDIRS=src
INSTALLDIR=$(shell cd $(top_builddir) && pwd)/$(PACKAGE)-install
INSTALLDIR=$(abs_top_builddir)/$(PACKAGE)-install
INSTALLDIR_WITH_PREFIX=$(INSTALLDIR)/$(prefix)
ZIPFILE=$(shell cd $(top_builddir) && pwd)/$(PACKAGE)-win32-$(VERSION).zip
ZIPFILE=$(abs_top_builddir)/$(PACKAGE)-win32-$(VERSION).zip
ZIP_EXCLUDED=include
PLUGIN_DEPS_PREFIX=/usr/bin
PLUGIN_DEPS= libsoup-2.4-1.dll \
@ -20,9 +18,9 @@ PLUGIN_DEPS= libsoup-2.4-1.dll \
zip:
rm -f $(ZIPFILE)
rm -rf $(INSTALLDIR)
mkdir -p $(INSTALLDIR)
$(MKDIR_P) $(INSTALLDIR)
make install DESTDIR=$(INSTALLDIR)
mkdir -p $(INSTALLDIR_WITH_PREFIX)/bin
$(MKDIR_P) $(INSTALLDIR_WITH_PREFIX)/bin
cd $(PLUGIN_DEPS_PREFIX) && \
cp -f $(PLUGIN_DEPS) $(INSTALLDIR_WITH_PREFIX)/bin/.
cd $(INSTALLDIR)/$(prefix) && rm -rf $(ZIP_EXCLUDED) && \

View file

@ -101,7 +101,7 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){
ms_free(tmp);
}
void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeState ss, SalPresenceStatus sal_status){
void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, SalPresenceStatus sal_status){
char *tmp;
LinphoneFriend *lf;
LinphoneAddress *friend=NULL;

View file

@ -35,6 +35,7 @@ extern "C" {
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "mediastreamer2/ice.h"
#include "mediastreamer2/mediastream.h"
#include "mediastreamer2/msconference.h"
@ -68,15 +69,43 @@ struct _LinphoneCallParams{
LinphoneCall *referer; /*in case this call creation is consecutive to an incoming transfer, this points to the original call */
int audio_bw; /* bandwidth limit for audio stream */
LinphoneMediaEncryption media_encryption;
PayloadType *audio_codec; /*audio codec currently in use */
PayloadType *video_codec; /*video codec currently in use */
int down_bw;
int up_bw;
int down_ptime;
int up_ptime;
bool_t has_video;
bool_t real_early_media; /*send real media even during early media (for outgoing calls)*/
bool_t in_conference; /*in conference mode */
bool_t pad;
bool_t low_bandwidth;
};
typedef struct _CallCallbackObj
{
LinphoneCallCbFunc _func;
void * _user_data;
}CallCallbackObj;
static const int linphone_call_magic=0x3343;
struct _LinphoneChatMessage {
char* message;
LinphoneChatRoom* chat_room;
LinphoneChatMessageStateChangeCb cb;
void* cb_ud;
void* message_userdata;
char* external_body_url;
LinphoneAddress* from;
};
typedef struct StunCandidate{
char addr[64];
int port;
}StunCandidate;
struct _LinphoneCall
{
int magic; /*used to distinguish from proxy config*/
@ -84,6 +113,7 @@ struct _LinphoneCall
SalMediaDescription *localdesc;
SalMediaDescription *resultdesc;
LinphoneCallDir dir;
LinphoneCall *referer; /*when this call is the result of a transfer, referer is set to the original call that caused the transfer*/
struct _RtpProfile *audio_profile;
struct _RtpProfile *video_profile;
struct _LinphoneCallLog *log;
@ -93,11 +123,14 @@ struct _LinphoneCall
time_t start_time; /*time at which the call was initiated*/
time_t media_start_time; /*time at which it was accepted, media streams established*/
LinphoneCallState state;
LinphoneCallState transfer_state; /*idle if no transfer*/
LinphoneReason reason;
LinphoneProxyConfig *dest_proxy;
int refcnt;
void * user_pointer;
int audio_port;
int video_port;
StunCandidate ac,vc; /*audio video ip/port discovered by STUN*/
struct _AudioStream *audiostream; /**/
struct _VideoStream *videostream;
MSAudioEndpoint *endpoint; /*used for conferencing*/
@ -107,21 +140,31 @@ struct _LinphoneCall
LinphoneCallParams remote_params;
int up_bw; /*upload bandwidth setting at the time the call is started. Used to detect if it changes during a call */
int audio_bw; /*upload bandwidth used by audio */
OrtpEvQueue *audiostream_app_evq;
char *auth_token;
OrtpEvQueue *videostream_app_evq;
CallCallbackObj nextVideoFrameDecoded;
LinphoneCallStats stats[2];
IceSession *ice_session;
LinphoneChatMessage* pending_message;
int ping_time;
bool_t refer_pending;
bool_t media_pending;
bool_t audio_muted;
bool_t camera_active;
bool_t all_muted; /*this flag is set during early medias*/
bool_t playing_ringbacktone;
bool_t owns_call_log;
bool_t ringing_beep; /* whether this call is ringing through an already existent current call*/
OrtpEvQueue *audiostream_app_evq;
char *auth_token;
OrtpEvQueue *videostream_app_evq;
bool_t videostream_encrypted;
bool_t audiostream_encrypted;
bool_t auth_token_verified;
bool_t defer_update;
bool_t was_automatically_paused;
bool_t ping_replied;
};
@ -133,6 +176,7 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const
LinphoneCallLog * linphone_call_log_new(LinphoneCall *call, LinphoneAddress *local, LinphoneAddress * remote);
void linphone_call_log_completed(LinphoneCall *call);
void linphone_call_log_destroy(LinphoneCallLog *cl);
void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state);
void linphone_auth_info_write_config(struct _LpConfig *config, LinphoneAuthInfo *obj, int pos);
@ -153,10 +197,7 @@ int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, sock
int set_lock_file();
int get_lock_file();
int remove_lock_file();
int do_registration(LinphoneCore *lc, bool_t doit);
void check_for_registration(LinphoneCore *lc);
void check_sound_device(LinphoneCore *lc);
void linphone_core_verify_codecs(LinphoneCore *lc);
void linphone_core_get_local_ip(LinphoneCore *lc, const char *to, char *result);
bool_t host_has_ipv6_network();
bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret);
@ -193,7 +234,7 @@ SalPresenceStatus linphone_online_status_to_sal(LinphoneOnlineStatus os);
void linphone_process_authentication(LinphoneCore* lc, SalOp *op);
void linphone_authentication_ok(LinphoneCore *lc, SalOp *op);
void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from);
void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeState ss, SalPresenceStatus status);
void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, SalPresenceStatus status);
void linphone_proxy_config_process_authentication_failure(LinphoneCore *lc, SalOp *op);
void linphone_subscription_answered(LinphoneCore *lc, SalOp *op);
@ -203,7 +244,14 @@ MSList *linphone_find_friend(MSList *fl, const LinphoneAddress *fri, LinphoneFri
void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc);
void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall *call, const PayloadType *pt);
void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call);
int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call);
void linphone_core_adapt_to_network(LinphoneCore *lc, int ping_time_ms, LinphoneCallParams *params);
int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call);
void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call);
void linphone_core_update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session);
void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md);
bool_t linphone_core_media_description_contains_video_stream(const SalMediaDescription *md);
void linphone_core_send_initial_subscribes(LinphoneCore *lc);
void linphone_core_write_friends_config(LinphoneCore* lc);
@ -221,13 +269,22 @@ void linphone_proxy_config_write_to_config_file(struct _LpConfig* config,Linphon
int linphone_proxy_config_normalize_number(LinphoneProxyConfig *cfg, const char *username, char *result, size_t result_len);
void linphone_core_text_received(LinphoneCore *lc, const char *from, const char *msg);
void linphone_core_message_received(LinphoneCore *lc, const char *from, const char *raw_msg,const char* external_url);
void linphone_core_play_tone(LinphoneCore *lc);
void linphone_call_init_stats(LinphoneCallStats *stats, int type);
void linphone_call_init_audio_stream(LinphoneCall *call);
void linphone_call_init_video_stream(LinphoneCall *call);
void linphone_call_init_media_streams(LinphoneCall *call);
void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone);
void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call);
void linphone_call_stop_audio_stream(LinphoneCall *call);
void linphone_call_stop_video_stream(LinphoneCall *call);
void linphone_call_stop_media_streams(LinphoneCall *call);
void linphone_call_delete_ice_session(LinphoneCall *call);
void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call);
const char * linphone_core_get_identity(LinphoneCore *lc);
const char * linphone_core_get_route(LinphoneCore *lc);
@ -235,8 +292,12 @@ void linphone_core_start_waiting(LinphoneCore *lc, const char *purpose);
void linphone_core_update_progress(LinphoneCore *lc, const char *purpose, float progresses);
void linphone_core_stop_waiting(LinphoneCore *lc);
int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy);
int linphone_core_proceed_with_invite_if_ready(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy);
int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call);
int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call);
int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call);
void linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *call);
void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call);
extern SalCallbacks linphone_sal_callbacks;
void linphone_proxy_config_set_error(LinphoneProxyConfig *cfg, LinphoneReason error);
bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc);
@ -246,6 +307,10 @@ LinphoneProxyConfig * is_a_linphone_proxy_config(void *user_pointer);
static const int linphone_proxy_config_magic=0x7979;
/*chat*/
void linphone_chat_message_destroy(LinphoneChatMessage* msg);
/**/
struct _LinphoneProxyConfig
{
int magic;
@ -254,6 +319,7 @@ struct _LinphoneProxyConfig
char *reg_identity;
char *reg_route;
char *realm;
char *contact_params;
int expires;
int reg_time;
SalOp *op;
@ -288,10 +354,11 @@ struct _LinphoneChatRoom{
struct _LinphoneCore *lc;
char *peer;
LinphoneAddress *peer_url;
SalOp *op;
void * user_data;
};
struct _LinphoneFriend{
LinphoneAddress *uri;
SalOp *insub;
@ -315,6 +382,7 @@ typedef struct sip_config
MSList *proxies;
MSList *deleted_proxies;
int inc_timeout; /*timeout after an un-answered incoming call is rejected*/
int in_call_timeout; /*timeout after a call is hangup */
unsigned int keepalive_period; /* interval in ms between keep alive messages sent to the proxy server*/
LCSipTransports transports;
bool_t use_info;
@ -330,13 +398,18 @@ typedef struct sip_config
typedef struct rtp_config
{
int audio_rtp_port;
int video_rtp_port;
int audio_rtp_min_port;
int audio_rtp_max_port;
int video_rtp_min_port;
int video_rtp_max_port;
int audio_jitt_comp; /*jitter compensation*/
int video_jitt_comp; /*jitter compensation*/
int nortp_timeout;
bool_t rtp_no_xmit_on_audio_mute;
/* stop rtp xmit when audio muted */
bool_t audio_adaptive_jitt_comp_enabled;
bool_t video_adaptive_jitt_comp_enabled;
bool_t pad;
}rtp_config_t;
@ -351,7 +424,6 @@ typedef struct net_config
int upload_bw;
int firewall_policy;
int mtu;
int down_ptime;
bool_t nat_sdp_only;
}net_config_t;
@ -364,10 +436,11 @@ typedef struct sound_config
struct _MSSndCard * lsd_card; /* dummy playback card for Linphone Sound Daemon extension */
const char **cards;
int latency; /* latency in samples of the current used sound device */
float soft_play_lev; /*playback gain in db.*/
float soft_mic_lev; /*mic gain in db.*/
char rec_lev;
char play_lev;
char ring_lev;
char soft_play_lev;
char source;
char *local_ring;
char *remote_ring;
@ -485,11 +558,16 @@ struct _LinphoneCore
bool_t network_reachable;
bool_t use_preview_window;
time_t network_last_check;
bool_t network_last_status;
bool_t ringstream_autorelease;
bool_t pad[3];
int device_rotation;
int max_calls;
LinphoneTunnel *tunnel;
char* device_id;
MSList *last_recv_msg_ids;
};
LinphoneTunnel *linphone_core_tunnel_new(LinphoneCore *lc);
@ -504,10 +582,7 @@ int linphone_core_set_as_current_call(LinphoneCore *lc, LinphoneCall *call);
int linphone_core_get_calls_nb(const LinphoneCore *lc);
void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message);
SalMediaDescription *create_local_media_description(LinphoneCore *lc, LinphoneCall *call);
void update_local_media_description(LinphoneCore *lc, LinphoneCall *call);
void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call);
void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md);
bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, PayloadType *pt, int bandwidth_limit);
@ -519,7 +594,8 @@ struct _EcCalibrator{
ms_thread_t thread;
MSSndCard *play_card,*capt_card;
MSFilter *sndread,*det,*rec;
MSFilter *play, *gen, *sndwrite,*resampler;
MSFilter *play, *gen, *sndwrite;
MSFilter *read_resampler,*write_resampler;
MSTicker *ticker;
LinphoneEcCalibrationCallback cb;
void *cb_data;
@ -549,8 +625,11 @@ void linphone_call_add_to_conf(LinphoneCall *call, bool_t muted);
void linphone_call_remove_from_conf(LinphoneCall *call);
void linphone_core_conference_check_uninit(LinphoneCore *lc);
bool_t linphone_core_sound_resources_available(LinphoneCore *lc);
void linphone_core_notify_refer_state(LinphoneCore *lc, LinphoneCall *referer, LinphoneCall *newcall);
unsigned int linphone_core_get_audio_features(LinphoneCore *lc);
void __linphone_core_invalidate_registers(LinphoneCore* lc);
void _linphone_core_codec_config_write(LinphoneCore *lc);
#define HOLD_OFF (0)
#define HOLD_ON (1)
@ -560,7 +639,8 @@ void __linphone_core_invalidate_registers(LinphoneCore* lc);
#endif
void call_logs_write_to_config_file(LinphoneCore *lc);
int linphone_core_get_edge_bw(LinphoneCore *lc);
int linphone_core_get_edge_ptime(LinphoneCore *lc);
#ifdef __cplusplus
}

View file

@ -24,7 +24,6 @@ Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org)
#include "private.h"
#include "mediastreamer2/mediastream.h"
#include <ctype.h>
@ -42,10 +41,12 @@ void linphone_proxy_config_write_all_to_config_file(LinphoneCore *lc){
lp_config_set_int(lc->config,"sip","default_proxy",linphone_core_get_default_proxy(lc,NULL));
}
void linphone_proxy_config_init(LinphoneProxyConfig *obj){
static void linphone_proxy_config_init(LinphoneCore* lc,LinphoneProxyConfig *obj){
memset(obj,0,sizeof(LinphoneProxyConfig));
obj->magic=linphone_proxy_config_magic;
obj->expires=3600;
obj->expires=LP_CONFIG_DEFAULT_INT((lc?lc->config:NULL),"reg_expires",3600);
obj->dial_prefix=ms_strdup(LP_CONFIG_DEFAULT_STRING((lc?lc->config:NULL),"dial_prefix",'\0'));
obj->dial_escape_plus=LP_CONFIG_DEFAULT_INT((lc?lc->config:NULL),"dial_escape_plus",0);
}
/**
@ -54,15 +55,21 @@ void linphone_proxy_config_init(LinphoneProxyConfig *obj){
**/
/**
* Creates an empty proxy config.
* @deprecated, use #linphone_core_create_proxy_config instead
*Creates an empty proxy config.
**/
LinphoneProxyConfig *linphone_proxy_config_new(){
LinphoneProxyConfig *linphone_proxy_config_new() {
return linphone_core_create_proxy_config(NULL);
}
LinphoneProxyConfig * linphone_core_create_proxy_config(LinphoneCore *lc) {
LinphoneProxyConfig *obj=NULL;
obj=ms_new(LinphoneProxyConfig,1);
linphone_proxy_config_init(obj);
linphone_proxy_config_init(lc,obj);
return obj;
}
/**
* Destroys a proxy config.
*
@ -112,7 +119,7 @@ int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char *
if (addr==NULL)
addr=linphone_address_new(server_addr);
if (addr){
obj->reg_proxy=linphone_address_as_string_uri_only(addr);
obj->reg_proxy=linphone_address_as_string(addr);
linphone_address_destroy(addr);
}else{
ms_warning("Could not parse %s",server_addr);
@ -218,7 +225,7 @@ void linphone_proxy_config_enableregister(LinphoneProxyConfig *obj, bool_t val){
* Sets the registration expiration time in seconds.
**/
void linphone_proxy_config_expires(LinphoneProxyConfig *obj, int val){
if (val<=0) val=600;
if (val<0) val=600;
obj->expires=val;
}
@ -256,9 +263,10 @@ static char *guess_contact_for_register(LinphoneProxyConfig *obj){
if (proxy==NULL) return NULL;
host=linphone_address_get_domain (proxy);
if (host!=NULL){
LinphoneAddress *contact;
char localip[LINPHONE_IPADDR_SIZE];
char *tmp;
LCSipTransports tr;
LinphoneAddress *contact;
linphone_core_get_local_ip(obj->lc,host,localip);
contact=linphone_address_new(obj->reg_identity);
@ -274,8 +282,12 @@ static char *guess_contact_for_register(LinphoneProxyConfig *obj){
sal_address_set_param(contact,"transport","tls");
}
}
ret=linphone_address_as_string(contact);
tmp=linphone_address_as_string_uri_only(contact);
if (obj->contact_params)
ret=ms_strdup_printf("<%s;%s>",tmp,obj->contact_params);
else ret=ms_strdup_printf("<%s>",tmp);
linphone_address_destroy(contact);
ms_free(tmp);
}
linphone_address_destroy (proxy);
return ret;
@ -318,7 +330,8 @@ void linphone_proxy_config_refresh_register(LinphoneProxyConfig *obj){
/**
* Sets a dialing prefix to be automatically prepended when inviting a number with
* #linphone_core_invite.
* linphone_core_invite();
* This dialing prefix shall usually be the country code of the country where the user is living.
*
**/
void linphone_proxy_config_set_dial_prefix(LinphoneProxyConfig *cfg, const char *prefix){
@ -339,7 +352,7 @@ const char *linphone_proxy_config_get_dial_prefix(const LinphoneProxyConfig *cfg
}
/**
* Sets whether liblinphone should replace "+" by "00" in dialed numbers (passed to
* Sets whether liblinphone should replace "+" by international calling prefix in dialed numbers (passed to
* #linphone_core_invite ).
*
**/
@ -355,13 +368,304 @@ void linphone_proxy_config_set_dial_escape_plus(LinphoneProxyConfig *cfg, bool_t
bool_t linphone_proxy_config_get_dial_escape_plus(const LinphoneProxyConfig *cfg){
return cfg->dial_escape_plus;
}
/*
* http://en.wikipedia.org/wiki/Telephone_numbering_plan
* http://en.wikipedia.org/wiki/Telephone_numbers_in_Europe
*/
typedef struct dial_plan{
const char *country;
const char* iso_country_code; /* ISO 3166-1 alpha-2 code, ex: FR for France*/
char ccc[8]; /*country calling code*/
int nnl; /*maximum national number length*/
const char * icp; /*international call prefix, ex: 00 in europe*/
}dial_plan_t;
/* TODO: fill with information for all countries over the world*/
static dial_plan_t const dial_plans[]={
{"Afghanistan" ,"AF" , "93" , 9 , "00" },
{"Albania" ,"AL" , "355" , 9 , "00" },
{"Algeria" ,"DZ" , "213" , 9 , "00" },
{"American Samoa" ,"AS" , "1" , 10 , "011" },
{"Andorra" ,"AD" , "376" , 6 , "00" },
{"Angola" ,"AO" , "244" , 9 , "00" },
{"Anguilla" ,"AI" , "1" , 10 , "011" },
{"Antigua and Barbuda" ,"AG" , "1" , 10 , "011" },
{"Argentina" ,"AR" , "54" , 10 , "00" },
{"Armenia" ,"AM" , "374" , 8 , "00" },
{"Aruba" ,"AW" , "297" , 7 , "011" },
{"Australia" ,"AU" , "61" , 9 , "0011"},
{"Austria" ,"AT" , "43" , 10 , "00" },
{"Azerbaijan" ,"AZ" , "994" , 9 , "00" },
{"Bahamas" ,"BS" , "1" , 10 , "011" },
{"Bahrain" ,"BH" , "973" , 8 , "00" },
{"Bangladesh" ,"BD" , "880" , 10 , "00" },
{"Barbados" ,"BB" , "1" , 10 , "011" },
{"Belarus" ,"BY" , "375" , 9 , "00" },
{"Belgium" ,"BE" , "32" , 9 , "00" },
{"Belize" ,"BZ" , "501" , 7 , "00" },
{"Benin" ,"BJ" , "229" , 8 , "00" },
{"Bermuda" ,"BM" , "1" , 10 , "011" },
{"Bhutan" ,"BT" , "975" , 8 , "00" },
{"Bolivia" ,"BO" , "591" , 8 , "00" },
{"Bosnia and Herzegovina" ,"BA" , "387" , 8 , "00" },
{"Botswana" ,"BW" , "267" , 8 , "00" },
{"Brazil" ,"BR" , "55" , 10 , "00" },
{"Brunei Darussalam" ,"BN" , "673" , 7 , "00" },
{"Bulgaria" ,"BG" , "359" , 9 , "00" },
{"Burkina Faso" ,"BF" , "226" , 8 , "00" },
{"Burundi" ,"BI" , "257" , 8 , "011" },
{"Cambodia" ,"KH" , "855" , 9 , "00" },
{"Cameroon" ,"CM" , "237" , 8 , "00" },
{"Canada" ,"CA" , "1" , 10 , "011" },
{"Cape Verde" ,"CV" , "238" , 7 , "00" },
{"Cayman Islands" ,"KY" , "1" , 10 , "011" },
{"Central African Republic" ,"CF" , "236" , 8 , "00" },
{"Chad" ,"TD" , "235" , 8 , "00" },
{"Chile" ,"CL" , "56" , 9 , "00" },
{"China" ,"CN" , "86" , 11 , "00" },
{"Colombia" ,"CO" , "57" , 10 , "00" },
{"Comoros" ,"KM" , "269" , 7 , "00" },
{"Congo" ,"CG" , "242" , 9 , "00" },
{"Congo Democratic Republic" ,"CD" , "243" , 9 , "00" },
{"Cook Islands" ,"CK" , "682" , 5 , "00" },
{"Costa Rica" ,"CR" , "506" , 8 , "00" },
{"C™te d'Ivoire" ,"AD" , "225" , 8 , "00" },
{"Croatia" ,"HR" , "385" , 9 , "00" },
{"Cuba" ,"CU" , "53" , 8 , "119" },
{"Cyprus" ,"CY" , "357" , 8 , "00" },
{"Czech Republic" ,"CZ" , "420" , 9 , "00" },
{"Denmark" ,"DK" , "45" , 8 , "00" },
{"Djibouti" ,"DJ" , "253" , 8 , "00" },
{"Dominica" ,"DM" , "1" , 10 , "011" },
{"Dominican Republic" ,"DO" , "1" , 10 , "011" },
{"Ecuador" ,"EC" , "593" , 9 , "00" },
{"Egypt" ,"EG" , "20" , 10 , "00" },
{"El Salvador" ,"SV" , "503" , 8 , "00" },
{"Equatorial Guinea" ,"GQ" , "240" , 9 , "00" },
{"Eritrea" ,"ER" , "291" , 7 , "00" },
{"Estonia" ,"EE" , "372" , 8 , "00" },
{"Ethiopia" ,"ET" , "251" , 9 , "00" },
{"Falkland Islands" ,"FK" , "500" , 5 , "00" },
{"Faroe Islands" ,"FO" , "298" , 6 , "00" },
{"Fiji" ,"FJ" , "679" , 7 , "00" },
{"Finland" ,"FI" , "358" , 9 , "00" },
{"France" ,"FR" , "33" , 9 , "00" },
{"French Guiana" ,"GF" , "594" , 9 , "00" },
{"French Polynesia" ,"PF" , "689" , 6 , "00" },
{"Gabon" ,"GA" , "241" , 8 , "00" },
{"Gambia" ,"GM" , "220" , 7 , "00" },
{"Georgia" ,"GE" , "995" , 9 , "00" },
{"Germany" ,"DE" , "49" , 11 , "00" },
{"Ghana" ,"GH" , "233" , 9 , "00" },
{"Gibraltar" ,"GI" , "350" , 8 , "00" },
{"Greece" ,"GR" , "30" ,10 , "00" },
{"Greenland" ,"GL" , "299" , 6 , "00" },
{"Grenada" ,"GD" , "1" , 10 , "011" },
{"Guadeloupe" ,"GP" , "590" , 9 , "00" },
{"Guam" ,"GU" , "1" , 10 , "011" },
{"Guatemala" ,"GT" , "502" , 8 , "00" },
{"Guinea" ,"GN" , "224" , 8 , "00" },
{"Guinea-Bissau" ,"GW" , "245" , 7 , "00" },
{"Guyana" ,"GY" , "592" , 7 , "001" },
{"Haiti" ,"HT" , "509" , 8 , "00" },
{"Honduras" ,"HN" , "504" , 8 , "00" },
{"Hong Kong" ,"HK" , "852" , 8 , "001" },
{"Hungary" ,"HU" , "36" , 9 , "00" },
{"Iceland" ,"IS" , "354" , 9 , "00" },
{"India" ,"IN" , "91" , 10 , "00" },
{"Indonesia" ,"ID" , "62" , 10 , "001" },
{"Iran" ,"IR" , "98" , 10 , "00" },
{"Iraq" ,"IQ" , "964" , 10 , "00" },
{"Ireland" ,"IE" , "353" , 9 , "00" },
{"Israel" ,"IL" , "972" , 9 , "00" },
{"Italy" ,"IT" , "39" , 10 , "00" },
{"Jamaica" ,"JM" , "1" , 10 , "011" },
{"Japan" ,"JP" , "81" , 10 , "010" },
{"Jordan" ,"JO" , "962" , 9 , "00" },
{"Kazakhstan" ,"KZ" , "7" , 10 , "00" },
{"Kenya" ,"KE" , "254" , 9 , "000" },
{"Kiribati" ,"KI" , "686" , 5 , "00" },
{"Korea, North" ,"KP" , "850" , 12 , "99" },
{"Korea, South" ,"KR" , "82" , 12 , "001" },
{"Kuwait" ,"KW" , "965" , 8 , "00" },
{"Kyrgyzstan" ,"KG" , "996" , 9 , "00" },
{"Laos" ,"LA" , "856" , 10 , "00" },
{"Latvia" ,"LV" , "371" , 8 , "00" },
{"Lebanon" ,"LB" , "961" , 7 , "00" },
{"Lesotho" ,"LS" , "266" , 8 , "00" },
{"Liberia" ,"LR" , "231" , 8 , "00" },
{"Libya" ,"LY" , "218" , 8 , "00" },
{"Liechtenstein" ,"LI" , "423" , 7 , "00" },
{"Lithuania" ,"LT" , "370" , 8 , "00" },
{"Luxembourg" ,"LU" , "352" , 9 , "00" },
{"Macau" ,"MO" , "853" , 8 , "00" },
{"Macedonia" ,"MK" , "389" , 8 , "00" },
{"Madagascar" ,"MG" , "261" , 9 , "00" },
{"Malawi" ,"MW" , "265" , 9 , "00" },
{"Malaysia" ,"MY" , "60" , 9 , "00" },
{"Maldives" ,"MV" , "960" , 7 , "00" },
{"Mali" ,"ML" , "223" , 8 , "00" },
{"Malta" ,"MT" , "356" , 8 , "00" },
{"Marshall Islands" ,"MH" , "692" , 7 , "011" },
{"Martinique" ,"MQ" , "596" , 9 , "00" },
{"Mauritania" ,"MR" , "222" , 8 , "00" },
{"Mauritius" ,"MU" , "230" , 7 , "00" },
{"Mayotte Island" ,"YT" , "262" , 9 , "00" },
{"Mexico" ,"MX" , "52" , 10 , "00" },
{"Micronesia" ,"FM" , "691" , 7 , "011" },
{"Moldova" ,"MD" , "373" , 8 , "00" },
{"Monaco" ,"MC" , "377" , 8 , "00" },
{"Mongolia" ,"MN" , "976" , 8 , "001" },
{"Montenegro" ,"ME" , "382" , 8 , "00" },
{"Montserrat" ,"MS" , "664" , 10 , "011" },
{"Morocco" ,"MA" , "212" , 9 , "00" },
{"Mozambique" ,"MZ" , "258" , 9 , "00" },
{"Myanmar" ,"MM" , "95" , 8 , "00" },
{"Namibia" ,"NA" , "264" , 9 , "00" },
{"Nauru" ,"NR" , "674" , 7 , "00" },
{"Nepal" ,"NP" , "43" , 10 , "00" },
{"Netherlands" ,"NL" , "31" , 9 , "00" },
{"New Caledonia" ,"NC" , "687" , 6 , "00" },
{"New Zealand" ,"NZ" , "64" , 10 , "00" },
{"Nicaragua" ,"NI" , "505" , 8 , "00" },
{"Niger" ,"NE" , "227" , 8 , "00" },
{"Nigeria" ,"NG" , "234" , 10 , "009" },
{"Niue" ,"NU" , "683" , 4 , "00" },
{"Norfolk Island" ,"NF" , "672" , 5 , "00" },
{"Northern Mariana Islands" ,"MP" , "1" , 10 , "011" },
{"Norway" ,"NO" , "47" , 8 , "00" },
{"Oman" ,"OM" , "968" , 8 , "00" },
{"Pakistan" ,"PK" , "92" , 10 , "00" },
{"Palau" ,"PW" , "680" , 7 , "011" },
{"Palestine" ,"PS" , "970" , 9 , "00" },
{"Panama" ,"PA" , "507" , 8 , "00" },
{"Papua New Guinea" ,"PG" , "675" , 8 , "00" },
{"Paraguay" ,"PY" , "595" , 9 , "00" },
{"Peru" ,"PE" , "51" , 9 , "00" },
{"Philippines" ,"PH" , "63" , 10 , "00" },
{"Poland" ,"PL" , "48" , 9 , "00" },
{"Portugal" ,"PT" , "351" , 9 , "00" },
{"Puerto Rico" ,"PR" , "1" , 10 , "011" },
{"Qatar" ,"QA" , "974" , 8 , "00" },
{"RŽunion Island" ,"RE" , "262" , 9 , "011" },
{"Romania" ,"RO" , "40" , 9 , "00" },
{"Russian Federation" ,"RU" , "7" , 10 , "8" },
{"Rwanda" ,"RW" , "250" , 9 , "00" },
{"Saint Helena" ,"SH" , "290" , 4 , "00" },
{"Saint Kitts and Nevis" ,"KN" , "1" , 10 , "011" },
{"Saint Lucia" ,"LC" , "1" , 10 , "011" },
{"Saint Pierre and Miquelon" ,"PM" , "508" , 6 , "00" },
{"Saint Vincent and the Grenadines","VC" , "1" , 10 , "011" },
{"Samoa" ,"WS" , "685" , 7 , "0" },
{"San Marino" ,"SM" , "378" , 10 , "00" },
{"So TomŽ and Prncipe" ,"ST" , "239" , 7 , "00" },
{"Saudi Arabia" ,"SA" , "966" , 9 , "00" },
{"Senegal" ,"SN" , "221" , 9 , "00" },
{"Serbia" ,"RS" , "381" , 9 , "00" },
{"Seychelles" ,"SC" , "248" , 7 , "00" },
{"Sierra Leone" ,"SL" , "232" , 8 , "00" },
{"Singapore" ,"SG" , "65" , 8 , "001" },
{"Slovakia" ,"SK" , "421" , 9 , "00" },
{"Slovenia" ,"SI" , "386" , 8 , "00" },
{"Solomon Islands" ,"SB" , "677" , 7 , "00" },
{"Somalia" ,"SO" , "252" , 8 , "00" },
{"South Africa" ,"ZA" , "27" , 9 , "00" },
{"Spain" ,"ES" , "34" , 9 , "00" },
{"Sri Lanka" ,"LK" , "94" , 9 , "00" },
{"Sudan" ,"SD" , "249" , 9 , "00" },
{"Suriname" ,"SR" , "597" , 7 , "00" },
{"Swaziland" ,"SZ" , "268" , 8 , "00" },
{"Sweden" ,"SE" , "1" , 9 , "00" },
{"Switzerland" ,"XK" , "41" , 9 , "00" },
{"Syria" ,"SY" , "963" , 9 , "00" },
{"Taiwan" ,"TW" , "886" , 9 , "810" },
{"Tajikistan" ,"TJ" , "992" , 9 , "002" },
{"Tanzania" ,"TZ" , "255" , 9 , "000" },
{"Thailand" ,"TH" , "66" , 9 , "001" },
{"Togo" ,"TG" , "228" , 8 , "00" },
{"Tokelau" ,"TK" , "690" , 4 , "00" },
{"Tonga" ,"TO" , "676" , 5 , "00" },
{"Trinidad and Tobago" ,"TT" , "1" , 10 , "011" },
{"Tunisia" ,"TN" , "216" , 8 , "00" },
{"Turkey" ,"TR" , "90" , 10 , "00" },
{"Turkmenistan" ,"TM" , "993" , 8 , "00" },
{"Turks and Caicos Islands" ,"TC" , "1" , 7 , "0" },
{"Tuvalu" ,"TV" , "688" , 5 , "00" },
{"Uganda" ,"UG" , "256" , 9 , "000" },
{"Ukraine" ,"UA" , "380" , 9 , "00" },
{"United Arab Emirates" ,"AE" , "971" , 9 , "00" },
{"United Kingdom" ,"UK" , "44" , 10 , "00" },
{"United States" ,"US" , "1" , 10 , "011" },
{"Uruguay" ,"UY" , "598" , 8 , "00" },
{"Uzbekistan" ,"UZ" , "998" , 9 , "8" },
{"Vanuatu" ,"VU" , "678" , 7 , "00" },
{"Venezuela" ,"VE" , "58" , 10 , "00" },
{"Vietnam" ,"VN" , "84" , 9 , "00" },
{"Wallis and Futuna" ,"WF" , "681" , 5 , "00" },
{"Yemen" ,"YE" , "967" , 9 , "00" },
{"Zambia" ,"ZM" , "260" , 9 , "00" },
{"Zimbabwe" ,"ZW" , "263" , 9 , "00" },
{NULL ,NULL , "" , 0 , NULL }
};
static dial_plan_t most_common_dialplan={ "generic" ,"", "", 10, "00"};
int linphone_dial_plan_lookup_ccc_from_e164(const char* e164) {
dial_plan_t* dial_plan;
dial_plan_t* elected_dial_plan=NULL;
unsigned int found;
unsigned int i=0;
if (e164[1]=='1') {
/*USA case*/
return 1;
}
do {
found=0;
i++;
for (dial_plan=(dial_plan_t*)dial_plans; dial_plan->country!=NULL; dial_plan++) {
if (strncmp(dial_plan->ccc,&e164[1],i) == 0) {
elected_dial_plan=dial_plan;
found++;
}
}
} while (found>1 || found==0);
if (found==1) {
return atoi(elected_dial_plan->ccc);
} else {
return -1; /*not found */
}
}
int linphone_dial_plan_lookup_ccc_from_iso(const char* iso) {
dial_plan_t* dial_plan;
for (dial_plan=(dial_plan_t*)dial_plans; dial_plan->country!=NULL; dial_plan++) {
if (strcmp(iso, dial_plan->iso_country_code)==0) {
return atoi(dial_plan->ccc);
}
}
return -1;
}
static void lookup_dial_plan(const char *ccc, dial_plan_t *plan){
int i;
for(i=0;dial_plans[i].country!=NULL;++i){
if (strcmp(ccc,dial_plans[i].ccc)==0){
*plan=dial_plans[i];
return;
}
}
/*else return a generic "most common" dial plan*/
*plan=most_common_dialplan;
strcpy(plan->ccc,ccc);
}
static bool_t is_a_phone_number(const char *username){
const char *p;
for(p=username;*p!='\0';++p){
if (isdigit(*p) ||
*p==' ' ||
*p=='.' ||
*p=='-' ||
*p==')' ||
*p=='(' ||
@ -385,14 +689,12 @@ static char *flatten_number(const char *number){
return result;
}
static void copy_result(const char *src, char *dest, size_t destlen, bool_t escape_plus){
static void replace_plus(const char *src, char *dest, size_t destlen, const char *icp){
int i=0;
if (escape_plus && src[0]=='+' && destlen>2){
dest[0]='0';
dest[1]='0';
if (icp && src[0]=='+' && (destlen>(i=strlen(icp))) ){
src++;
i=2;
strcpy(dest,icp);
}
for(;(i<destlen-1) && *src!='\0';++i){
@ -403,37 +705,53 @@ static void copy_result(const char *src, char *dest, size_t destlen, bool_t esca
}
static char *append_prefix(const char *number, const char *prefix){
char *res=ms_malloc(strlen(number)+strlen(prefix)+1);
strcpy(res,prefix);
return strcat(res,number);
}
int linphone_proxy_config_normalize_number(LinphoneProxyConfig *proxy, const char *username, char *result, size_t result_len){
char *flatten;
int numlen;
if (is_a_phone_number(username)){
char *flatten;
flatten=flatten_number(username);
ms_message("Flattened number is '%s'",flatten);
numlen=strlen(flatten);
if (numlen>10 || flatten[0]=='+' || proxy->dial_prefix==NULL || proxy->dial_prefix[0]=='\0'){
ms_message("No need to add a prefix");
/* prefix is already there */
copy_result(flatten,result,result_len,proxy->dial_escape_plus);
if (proxy->dial_prefix==NULL || proxy->dial_prefix[0]=='\0'){
/*no prefix configured, nothing else to do*/
strncpy(result,flatten,result_len);
ms_free(flatten);
return 0;
}else if (proxy->dial_prefix && proxy->dial_prefix[0]!='\0'){
char *prefixed;
int skipped=0;
ms_message("Need to prefix with %s",proxy->dial_prefix);
if (numlen==10){
/*remove initial number before prepending prefix*/
skipped=1;
}else{
dial_plan_t dialplan;
lookup_dial_plan(proxy->dial_prefix,&dialplan);
ms_message("Using dialplan '%s'",dialplan.country);
if (flatten[0]=='+' || strstr(flatten,dialplan.icp)==flatten){
/* the number has international prefix or +, so nothing to do*/
ms_message("Prefix already present.");
/*eventually replace the plus*/
replace_plus(flatten,result,result_len,proxy->dial_escape_plus ? dialplan.icp : NULL);
ms_free(flatten);
return 0;
}else{
int i=0;
int skip;
numlen=strlen(flatten);
/*keep at most national number significant digits */
skip=numlen-dialplan.nnl;
if (skip<0) skip=0;
/*first prepend internation calling prefix or +*/
if (proxy->dial_escape_plus){
strncpy(result,dialplan.icp,result_len);
i+=strlen(dialplan.icp);
}else{
strncpy(result,"+",result_len);
i+=1;
}
/*add prefix*/
if (result_len-i>strlen(dialplan.ccc)){
strcpy(result+i,dialplan.ccc);
i+=strlen(dialplan.ccc);
}
/*add user digits */
strncpy(result+i,flatten+skip,result_len-i-1);
ms_free(flatten);
}
prefixed=append_prefix(flatten+skipped,proxy->dial_prefix);
ms_free(flatten);
copy_result(prefixed,result,result_len,proxy->dial_escape_plus);
ms_free(prefixed);
}
}else strncpy(result,username,result_len);
return 0;
@ -481,7 +799,7 @@ const char *linphone_proxy_config_get_route(const LinphoneProxyConfig *obj){
/**
* Returns the SIP identity that belongs to this proxy configuration.
*
* The SIP identity is a SIP address (Display Name <sip:username@domain> )
* The SIP identity is a SIP address (Display Name <sip:username@@domain> )
**/
const char *linphone_proxy_config_get_identity(const LinphoneProxyConfig *obj){
return obj->reg_identity;
@ -515,6 +833,31 @@ bool_t linphone_proxy_config_register_enabled(const LinphoneProxyConfig *obj){
return obj->reg_sendregister;
}
/**
* Set optional contact parameters that will be added to the contact information sent in the registration.
* @param obj the proxy config object
* @param contact_params a string contaning the additional parameters in text form, like "myparam=something;myparam2=something_else"
*
* The main use case for this function is provide the proxy additional information regarding the user agent, like for example unique identifier or apple push id.
* As an example, the contact address in the SIP register sent will look like <sip:joe@15.128.128.93:50421;apple-push-id=43143-DFE23F-2323-FA2232>.
**/
void linphone_proxy_config_set_contact_parameters(LinphoneProxyConfig *obj, const char *contact_params){
if (obj->contact_params) {
ms_free(obj->contact_params);
obj->contact_params=NULL;
}
if (contact_params){
obj->contact_params=ms_strdup(contact_params);
}
}
/**
* Returns previously set contact parameters.
**/
const char *linphone_proxy_config_get_contact_parameters(const LinphoneProxyConfig *obj){
return obj->contact_params;
}
struct _LinphoneCore * linphone_proxy_config_get_core(const LinphoneProxyConfig *obj){
return obj->lc;
}
@ -641,6 +984,9 @@ void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyC
if (obj->reg_identity!=NULL){
lp_config_set_string(config,key,"reg_identity",obj->reg_identity);
}
if (obj->contact_params!=NULL){
lp_config_set_string(config,key,"contact_params",obj->contact_params);
}
lp_config_set_int(config,key,"reg_expires",obj->expires);
lp_config_set_int(config,key,"reg_sendregister",obj->reg_sendregister);
lp_config_set_int(config,key,"publish",obj->publish);
@ -675,13 +1021,15 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config
tmp=lp_config_get_string(config,key,"reg_route",NULL);
if (tmp!=NULL) linphone_proxy_config_set_route(cfg,tmp);
linphone_proxy_config_expires(cfg,lp_config_get_int(config,key,"reg_expires",600));
linphone_proxy_config_set_contact_parameters(cfg,lp_config_get_string(config,key,"contact_parameters",NULL));
linphone_proxy_config_expires(cfg,lp_config_get_int(config,key,"reg_expires",LP_CONFIG_DEFAULT_INT(config,"reg_expires",600)));
linphone_proxy_config_enableregister(cfg,lp_config_get_int(config,key,"reg_sendregister",0));
linphone_proxy_config_enable_publish(cfg,lp_config_get_int(config,key,"publish",0));
linphone_proxy_config_set_dial_escape_plus(cfg,lp_config_get_int(config,key,"dial_escape_plus",0));
linphone_proxy_config_set_dial_prefix(cfg,lp_config_get_string(config,key,"dial_prefix",NULL));
linphone_proxy_config_set_dial_escape_plus(cfg,lp_config_get_int(config,key,"dial_escape_plus",LP_CONFIG_DEFAULT_INT(config,"dial_escape_plus",0)));
linphone_proxy_config_set_dial_prefix(cfg,lp_config_get_string(config,key,"dial_prefix",LP_CONFIG_DEFAULT_STRING(config,"dial_prefix",NULL)));
tmp=lp_config_get_string(config,key,"type",NULL);
if (tmp!=NULL && strlen(tmp)>0)

View file

@ -88,7 +88,7 @@ bool_t sal_media_description_empty(const SalMediaDescription *md){
int i;
for(i=0;i<md->nstreams;++i){
const SalStreamDescription *ss=&md->streams[i];
if (ss->port!=0) return FALSE;
if (ss->rtp_port!=0) return FALSE;
}
return TRUE;
}
@ -115,7 +115,7 @@ static bool_t has_dir(const SalMediaDescription *md, SalStreamDir stream_dir){
const SalStreamDescription *ss=&md->streams[i];
if (ss->dir==stream_dir) return TRUE;
/*compatibility check for phones that only used the null address and no attributes */
if (ss->dir==SalStreamSendRecv && stream_dir==SalStreamSendOnly && (is_null_address(md->addr) || is_null_address(ss->addr)))
if (ss->dir==SalStreamSendRecv && stream_dir==SalStreamSendOnly && (is_null_address(md->addr) || is_null_address(ss->rtp_addr)))
return TRUE;
}
return FALSE;
@ -163,6 +163,10 @@ static bool_t payload_type_equals(const PayloadType *p1, const PayloadType *p2){
return TRUE;
}
static bool_t is_recv_only(PayloadType *p){
return (p->flags & PAYLOAD_TYPE_FLAG_CAN_RECV) && ! (p->flags & PAYLOAD_TYPE_FLAG_CAN_SEND);
}
static bool_t payload_list_equals(const MSList *l1, const MSList *l2){
const MSList *e1,*e2;
for(e1=l1,e2=l2;e1!=NULL && e2!=NULL; e1=e1->next,e2=e2->next){
@ -171,6 +175,12 @@ static bool_t payload_list_equals(const MSList *l1, const MSList *l2){
if (!payload_type_equals(p1,p2))
return FALSE;
}
if (e1!=NULL){
/*skip possible recv-only payloads*/
for(;e1!=NULL && is_recv_only((PayloadType*)e1->data);e1=e1->next){
ms_message("Skipping recv-only payload type...");
}
}
if (e1!=NULL || e2!=NULL){
/*means one list is longer than the other*/
return FALSE;
@ -178,30 +188,40 @@ static bool_t payload_list_equals(const MSList *l1, const MSList *l2){
return TRUE;
}
bool_t sal_stream_description_equals(const SalStreamDescription *sd1, const SalStreamDescription *sd2){
if (sd1->proto!=sd2->proto) return FALSE;
if (sd1->type!=sd2->type) return FALSE;
if (strcmp(sd1->addr,sd2->addr)!=0) return FALSE;
if (sd1->port!=sd2->port) return FALSE;
if (!payload_list_equals(sd1->payloads,sd2->payloads)) return FALSE;
if (sd1->bandwidth!=sd2->bandwidth) return FALSE;
if (sd1->ptime!=sd2->ptime) return FALSE;
/* compare candidates: TODO */
if (sd1->dir!=sd2->dir) return FALSE;
return TRUE;
int sal_stream_description_equals(const SalStreamDescription *sd1, const SalStreamDescription *sd2) {
int result = SAL_MEDIA_DESCRIPTION_UNCHANGED;
/* A different proto should result in SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED but the encryption change
needs a stream restart for now, so use SAL_MEDIA_DESCRIPTION_CODEC_CHANGED */
if (sd1->proto != sd2->proto) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
if (sd1->type != sd2->type) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
if (strcmp(sd1->rtp_addr, sd2->rtp_addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
if (sd1->rtp_port != sd2->rtp_port) {
if ((sd1->rtp_port == 0) || (sd2->rtp_port == 0)) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
else result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
}
if (strcmp(sd1->rtcp_addr, sd2->rtcp_addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
if (sd1->rtcp_port != sd2->rtcp_port) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
if (!payload_list_equals(sd1->payloads, sd2->payloads)) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
if (sd1->bandwidth != sd2->bandwidth) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
if (sd1->ptime != sd2->ptime) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
if (sd1->dir != sd2->dir) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
return result;
}
bool_t sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2){
int sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2) {
int result = SAL_MEDIA_DESCRIPTION_UNCHANGED;
int i;
if (strcmp(md1->addr,md2->addr)!=0) return FALSE;
if (md1->nstreams!=md2->nstreams) return FALSE;
if (md1->bandwidth!=md2->bandwidth) return FALSE;
for(i=0;i<md1->nstreams;++i){
if (!sal_stream_description_equals(&md1->streams[i],&md2->streams[i]))
return FALSE;
if (strcmp(md1->addr, md2->addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
if (md1->nstreams != md2->nstreams) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
if (md1->bandwidth != md2->bandwidth) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
for(i = 0; i < md1->nstreams; ++i){
result |= sal_stream_description_equals(&md1->streams[i], &md2->streams[i]);
}
return TRUE;
return result;
}
static void assign_address(SalAddress** address, const char *value){
if (*address){
@ -317,7 +337,9 @@ const char *sal_op_get_proxy(const SalOp *op){
const char *sal_op_get_network_origin(const SalOp *op){
return ((SalOpBase*)op)->origin;
}
const char* sal_op_get_call_id(const SalOp *op) {
return ((SalOpBase*)op)->call_id;
}
void __sal_op_init(SalOp *b, Sal *sal){
memset(b,0,sizeof(SalOpBase));
((SalOpBase*)b)->root=sal;
@ -363,6 +385,8 @@ void __sal_op_free(SalOp *op){
sal_media_description_unref(b->local_media);
if (b->remote_media)
sal_media_description_unref(b->remote_media);
if (b->call_id)
ms_free((void*)b->call_id);
ms_free(op);
}

View file

@ -53,6 +53,11 @@ typedef enum {
SalTransportDTLS /*DTLS*/
}SalTransport;
#define SAL_MEDIA_DESCRIPTION_UNCHANGED 0x00
#define SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED 0x01
#define SAL_MEDIA_DESCRIPTION_CODEC_CHANGED 0x02
#define SAL_MEDIA_DESCRIPTION_CHANGED (SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED | SAL_MEDIA_DESCRIPTION_CODEC_CHANGED)
const char* sal_transport_to_string(SalTransport transport);
SalTransport sal_transport_parse(const char*);
/* Address manipulation API*/
@ -108,13 +113,35 @@ typedef enum{
}SalStreamDir;
const char* sal_stream_dir_to_string(SalStreamDir type);
typedef struct SalEndpointCandidate{
char addr[64];
int port;
}SalEndpointCandidate;
#define SAL_ENDPOINT_CANDIDATE_MAX 2
#define SAL_MEDIA_DESCRIPTION_MAX_ICE_ADDR_LEN 64
#define SAL_MEDIA_DESCRIPTION_MAX_ICE_FOUNDATION_LEN 32
#define SAL_MEDIA_DESCRIPTION_MAX_ICE_TYPE_LEN 6
typedef struct SalIceCandidate {
char addr[SAL_MEDIA_DESCRIPTION_MAX_ICE_ADDR_LEN];
char raddr[SAL_MEDIA_DESCRIPTION_MAX_ICE_ADDR_LEN];
char foundation[SAL_MEDIA_DESCRIPTION_MAX_ICE_FOUNDATION_LEN];
char type[SAL_MEDIA_DESCRIPTION_MAX_ICE_TYPE_LEN];
unsigned int componentID;
unsigned int priority;
int port;
int rport;
} SalIceCandidate;
#define SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES 10
typedef struct SalIceRemoteCandidate {
char addr[SAL_MEDIA_DESCRIPTION_MAX_ICE_ADDR_LEN];
int port;
} SalIceRemoteCandidate;
#define SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES 2
#define SAL_MEDIA_DESCRIPTION_MAX_ICE_UFRAG_LEN 256
#define SAL_MEDIA_DESCRIPTION_MAX_ICE_PWD_LEN 256
typedef struct SalSrtpCryptoAlgo {
unsigned int tag;
enum ortp_srtp_crypto_suite_t algo;
@ -128,15 +155,23 @@ typedef struct SalStreamDescription{
SalMediaProto proto;
SalStreamType type;
char typeother[32];
char addr[64];
int port;
char rtp_addr[64];
char rtcp_addr[64];
int rtp_port;
int rtcp_port;
MSList *payloads; //<list of PayloadType
int bandwidth;
int ptime;
SalEndpointCandidate candidates[SAL_ENDPOINT_CANDIDATE_MAX];
SalStreamDir dir;
SalSrtpCryptoAlgo crypto[SAL_CRYPTO_ALGO_MAX];
unsigned int crypto_local_tag;
int max_rate;
SalIceCandidate ice_candidates[SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES];
SalIceRemoteCandidate ice_remote_candidates[SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES];
char ice_ufrag[SAL_MEDIA_DESCRIPTION_MAX_ICE_UFRAG_LEN];
char ice_pwd[SAL_MEDIA_DESCRIPTION_MAX_ICE_PWD_LEN];
bool_t ice_mismatch;
bool_t ice_completed;
} SalStreamDescription;
#define SAL_MEDIA_DESCRIPTION_MAX_STREAMS 4
@ -150,13 +185,26 @@ typedef struct SalMediaDescription{
unsigned int session_ver;
unsigned int session_id;
SalStreamDescription streams[SAL_MEDIA_DESCRIPTION_MAX_STREAMS];
char ice_ufrag[SAL_MEDIA_DESCRIPTION_MAX_ICE_UFRAG_LEN];
char ice_pwd[SAL_MEDIA_DESCRIPTION_MAX_ICE_PWD_LEN];
bool_t ice_lite;
bool_t ice_completed;
} SalMediaDescription;
typedef struct SalMessage{
const char *from;
const char *text;
const char *url;
const char *message_id;
}SalMessage;
#define SAL_MEDIA_DESCRIPTION_MAX_MESSAGE_ATTRIBUTES 5
SalMediaDescription *sal_media_description_new();
void sal_media_description_ref(SalMediaDescription *md);
void sal_media_description_unref(SalMediaDescription *md);
bool_t sal_media_description_empty(const SalMediaDescription *md);
bool_t sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2);
int sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2);
bool_t sal_media_description_has_dir(const SalMediaDescription *md, SalStreamDir dir);
SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md,
SalMediaProto proto, SalStreamType type);
@ -179,6 +227,7 @@ typedef struct SalOpBase{
SalMediaDescription *local_media;
SalMediaDescription *remote_media;
void *user_pointer;
const char* call_id;
} SalOpBase;
@ -216,10 +265,22 @@ typedef enum SalPresenceStatus{
SalPresenceAltService,
}SalPresenceStatus;
typedef enum SalSubscribeState{
typedef enum SalReferStatus{
SalReferTrying,
SalReferSuccess,
SalReferFailed
}SalReferStatus;
typedef enum SalSubscribeStatus{
SalSubscribeActive,
SalSubscribeTerminated
}SalSubscribeState;
}SalSubscribeStatus;
typedef enum SalTextDeliveryStatus{
SalTextDeliveryInProgress,
SalTextDeliveryDone,
SalTextDeliveryFailed
}SalTextDeliveryStatus;
typedef struct SalAuthInfo{
char *username;
@ -245,9 +306,11 @@ typedef void (*SalOnRegisterFailure)(SalOp *op, SalError error, SalReason reason
typedef void (*SalOnVfuRequest)(SalOp *op);
typedef void (*SalOnDtmfReceived)(SalOp *op, char dtmf);
typedef void (*SalOnRefer)(Sal *sal, SalOp *op, const char *referto);
typedef void (*SalOnTextReceived)(Sal *sal, const char *from, const char *msg);
typedef void (*SalOnNotify)(SalOp *op, const char *from, const char *value);
typedef void (*SalOnNotifyPresence)(SalOp *op, SalSubscribeState ss, SalPresenceStatus status, const char *msg);
typedef void (*SalOnTextReceived)(Sal *sal, const SalMessage *msg);
typedef void (*SalOnTextDeliveryUpdate)(SalOp *op, SalTextDeliveryStatus status);
typedef void (*SalOnNotify)(SalOp *op, const char *from, const char *event);
typedef void (*SalOnNotifyRefer)(SalOp *op, SalReferStatus state);
typedef void (*SalOnNotifyPresence)(SalOp *op, SalSubscribeStatus ss, SalPresenceStatus status, const char *msg);
typedef void (*SalOnSubscribeReceived)(SalOp *salop, const char *from);
typedef void (*SalOnSubscribeClosed)(SalOp *salop, const char *from);
typedef void (*SalOnPingReply)(SalOp *salop);
@ -272,8 +335,10 @@ typedef struct SalCallbacks{
SalOnDtmfReceived dtmf_received;
SalOnRefer refer_received;
SalOnTextReceived text_received;
SalOnTextDeliveryUpdate text_delivery_update;
SalOnNotify notify;
SalOnNotifyPresence notify_presence;
SalOnNotifyRefer notify_refer;
SalOnSubscribeReceived subscribe_received;
SalOnSubscribeClosed subscribe_closed;
SalOnPingReply ping_reply;
@ -289,6 +354,8 @@ void sal_auth_info_delete(const SalAuthInfo* auth_info);
void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs);
int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure);
int sal_unlisten_ports(Sal *ctx);
void sal_set_dscp(Sal *ctx, int dscp);
int sal_reset_transports(Sal *ctx);
ortp_socket_t sal_get_socket(Sal *ctx);
void sal_set_user_agent(Sal *ctx, const char *user_agent);
/*keepalive period in ms*/
@ -300,11 +367,14 @@ void sal_set_keepalive_period(Sal *ctx,unsigned int value);
unsigned int sal_get_keepalive_period(Sal *ctx);
void sal_use_session_timers(Sal *ctx, int expires);
void sal_use_double_registrations(Sal *ctx, bool_t enabled);
void sal_expire_old_registration_contacts(Sal *ctx, bool_t enabled);
void sal_use_dates(Sal *ctx, bool_t enabled);
void sal_reuse_authorization(Sal *ctx, bool_t enabled);
void sal_use_one_matching_codec_policy(Sal *ctx, bool_t one_matching_codec);
void sal_use_rport(Sal *ctx, bool_t use_rports);
void sal_use_101(Sal *ctx, bool_t use_101);
void sal_set_root_ca(Sal* ctx, const char* rootCa);
const char *sal_get_root_ca(Sal* ctx);
void sal_verify_server_certificates(Sal *ctx, bool_t verify);
int sal_iterate(Sal *sal);
@ -343,6 +413,7 @@ const SalAddress *sal_op_get_network_origin_address(const SalOp *op);
/*returns far-end "User-Agent" string */
const char *sal_op_get_remote_ua(const SalOp *op);
void *sal_op_get_user_pointer(const SalOp *op);
const char* sal_op_get_call_id(const SalOp *op);
/*Call API*/
int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc);
@ -366,6 +437,7 @@ int sal_call_terminate(SalOp *h);
bool_t sal_call_autoanswer_asked(SalOp *op);
void sal_call_send_vfu_request(SalOp *h);
int sal_call_is_offerer(const SalOp *h);
int sal_call_notify_refer_state(SalOp *h, SalOp *newcall);
/*Registration*/
int sal_register(SalOp *op, const char *proxy, const char *from, int expires);
@ -374,6 +446,7 @@ int sal_unregister(SalOp *h);
/*Messaging */
int sal_text_send(SalOp *op, const char *from, const char *to, const char *text);
int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg);
/*presence Subscribe/notify*/
int sal_subscribe_presence(SalOp *op, const char *from, const char *to);

View file

@ -21,7 +21,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#endif
#include "sal_eXosip2.h"
#include "private.h"
#include "offeranswer.h"
#ifdef ANDROID
@ -33,7 +32,7 @@ static bool_t call_failure(Sal *sal, eXosip_event_t *ev);
static void text_received(Sal *sal, eXosip_event_t *ev);
static void masquerade_via(osip_message_t *msg, const char *ip, const char *port);
static bool_t fix_message_contact(SalOp *op, osip_message_t *request,osip_message_t *last_answer);
static bool_t fix_message_contact(SalOp *op, osip_message_t *request,osip_message_t *last_answer, bool_t expire_last_contact);
static void update_contact_from_response(SalOp *op, osip_message_t *response);
void _osip_list_set_empty(osip_list_t *l, void (*freefunc)(void*)){
@ -98,12 +97,12 @@ static void sal_remove_register(Sal *sal, int rid){
}
}
static SalOp * sal_find_other(Sal *sal, osip_message_t *response){
static SalOp * sal_find_other(Sal *sal, osip_message_t *message){
const MSList *elem;
SalOp *op;
osip_call_id_t *callid=osip_message_get_call_id(response);
osip_call_id_t *callid=osip_message_get_call_id(message);
if (callid==NULL) {
ms_error("There is no call-id in this response !");
ms_error("There is no call-id in this message !");
return NULL;
}
for(elem=sal->other_transactions;elem!=NULL;elem=elem->next){
@ -162,7 +161,7 @@ void sal_exosip_fix_route(SalOp *op){
}
SalOp * sal_op_new(Sal *sal){
SalOp *op=ms_new(SalOp,1);
SalOp *op=ms_new0(SalOp,1);
__sal_op_init(op,sal);
op->cid=op->did=op->tid=op->rid=op->nid=op->sid=-1;
op->result=NULL;
@ -283,6 +282,9 @@ Sal * sal_init(){
sal->reuse_authorization=FALSE;
sal->rootCa = 0;
sal->verify_server_certs=TRUE;
sal->expire_old_contact=FALSE;
sal->add_dates=FALSE;
sal->dscp=-1;
return sal;
}
@ -352,6 +354,38 @@ int sal_unlisten_ports(Sal *ctx){
return 0;
}
int sal_reset_transports(Sal *ctx){
#ifdef HAVE_EXOSIP_RESET_TRANSPORTS
if (ctx->running){
ms_message("Exosip transports reset.");
eXosip_reset_transports();
}
return 0;
#else
ms_warning("sal_reset_transports() not implemented in this version.");
return -1;
#endif
}
static void set_tls_options(Sal *ctx){
if (ctx->rootCa) {
eXosip_tls_ctx_t tlsCtx;
memset(&tlsCtx, 0, sizeof(tlsCtx));
snprintf(tlsCtx.root_ca_cert, sizeof(tlsCtx.client.cert), "%s", ctx->rootCa);
eXosip_set_tls_ctx(&tlsCtx);
}
#ifdef HAVE_EXOSIP_TLS_VERIFY_CERTIFICATE
eXosip_tls_verify_certificate(ctx->verify_server_certs);
#endif
}
void sal_set_dscp(Sal *ctx, int dscp){
ctx->dscp=dscp;
if (dscp!=-1)
eXosip_set_option(EXOSIP_OPT_SET_DSCP,&ctx->dscp);
}
int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure){
int err;
bool_t ipv6;
@ -368,16 +402,7 @@ int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int i
proto= IPPROTO_TCP;
keepalive=-1;
eXosip_set_option (EXOSIP_OPT_UDP_KEEP_ALIVE,&keepalive);
if (ctx->rootCa) {
eXosip_tls_ctx_t tlsCtx;
memset(&tlsCtx, 0, sizeof(tlsCtx));
snprintf(tlsCtx.root_ca_cert, sizeof(tlsCtx.client.cert), "%s", ctx->rootCa);
eXosip_set_tls_ctx(&tlsCtx);
}
#ifdef HAVE_EXOSIP_TLS_VERIFY_CERTIFICATE
eXosip_tls_verify_certificate(ctx->verify_server_certs);
#endif
set_tls_options(ctx);
break;
default:
ms_warning("unexpected proto, using datagram");
@ -387,6 +412,8 @@ int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int i
eXosip_set_option(EXOSIP_OPT_USE_RPORT,&use_rports);
int dont_use_101 = !ctx->use_101; // Copy char to int to avoid bad alignment
eXosip_set_option(EXOSIP_OPT_DONT_SEND_101,&dont_use_101);
sal_set_dscp(ctx,ctx->dscp);
sal_use_dates(ctx,ctx->add_dates);
ipv6=strchr(addr,':')!=NULL;
eXosip_enable_ipv6(ipv6);
@ -429,6 +456,22 @@ void sal_use_double_registrations(Sal *ctx, bool_t enabled){
ctx->double_reg=enabled;
}
void sal_expire_old_registration_contacts(Sal *ctx, bool_t enabled){
ctx->expire_old_contact=enabled;
}
void sal_use_dates(Sal *ctx, bool_t enabled){
ctx->add_dates=enabled;
#ifdef EXOSIP_OPT_REGISTER_WITH_DATE
{
int tmp=enabled;
eXosip_set_option(EXOSIP_OPT_REGISTER_WITH_DATE,&tmp);
}
#else
if (enabled) ms_warning("Exosip does not support EXOSIP_OPT_REGISTER_WITH_DATE option.");
#endif
}
void sal_use_rport(Sal *ctx, bool_t use_rports){
ctx->use_rports=use_rports;
}
@ -440,6 +483,11 @@ void sal_set_root_ca(Sal* ctx, const char* rootCa) {
if (ctx->rootCa)
ms_free(ctx->rootCa);
ctx->rootCa = ms_strdup(rootCa);
set_tls_options(ctx);
}
const char *sal_get_root_ca(Sal* ctx) {
return ctx->rootCa;
}
void sal_verify_server_certificates(Sal *ctx, bool_t verify){
@ -528,11 +576,13 @@ static void sdp_process(SalOp *h){
h->result->bandwidth=h->base.remote_media->bandwidth;
for(i=0;i<h->result->nstreams;++i){
if (h->result->streams[i].port>0){
strcpy(h->result->streams[i].addr,h->base.remote_media->streams[i].addr);
if (h->result->streams[i].rtp_port>0){
strcpy(h->result->streams[i].rtp_addr,h->base.remote_media->streams[i].rtp_addr);
strcpy(h->result->streams[i].rtcp_addr,h->base.remote_media->streams[i].rtcp_addr);
h->result->streams[i].ptime=h->base.remote_media->streams[i].ptime;
h->result->streams[i].bandwidth=h->base.remote_media->streams[i].bandwidth;
h->result->streams[i].port=h->base.remote_media->streams[i].port;
h->result->streams[i].rtp_port=h->base.remote_media->streams[i].rtp_port;
h->result->streams[i].rtcp_port=h->base.remote_media->streams[i].rtcp_port;
if (h->result->streams[i].proto == SalProtoRtpSavp) {
h->result->streams[i].crypto[0] = h->base.remote_media->streams[i].crypto[0];
@ -569,6 +619,7 @@ int sal_call(SalOp *h, const char *from, const char *to){
int err;
const char *route;
osip_message_t *invite=NULL;
osip_call_id_t *callid;
sal_op_set_from(h,from);
sal_op_set_to(h,to);
sal_exosip_fix_route(h);
@ -609,6 +660,8 @@ int sal_call(SalOp *h, const char *from, const char *to){
ms_error("Fail to send invite ! Error code %d", err);
return -1;
}else{
callid=osip_message_get_call_id(invite);
osip_call_id_to_str(callid,(char **)(&h->base.call_id));
sal_add_call(h->base.root,h);
}
return 0;
@ -728,6 +781,48 @@ int sal_call_set_referer(SalOp *h, SalOp *refered_call){
return 0;
}
static int send_notify_for_refer(int did, const char *sipfrag){
osip_message_t *msg;
eXosip_lock();
eXosip_call_build_notify(did,EXOSIP_SUBCRSTATE_ACTIVE,&msg);
if (msg==NULL){
eXosip_unlock();
ms_warning("Could not build NOTIFY for refer.");
return -1;
}
osip_message_set_content_type(msg,"message/sipfrag");
osip_message_set_header(msg,"Event","refer");
osip_message_set_body(msg,sipfrag,strlen(sipfrag));
eXosip_call_send_request(did,msg);
eXosip_unlock();
return 0;
}
/* currently only support to notify trying and 200Ok*/
int sal_call_notify_refer_state(SalOp *h, SalOp *newcall){
if (newcall==NULL){
/* in progress*/
send_notify_for_refer(h->did,"SIP/2.0 100 Trying\r\n");
}
else if (newcall->cid!=-1){
if (newcall->did==-1){
/* not yet established*/
if (!newcall->terminated){
/* in progress*/
send_notify_for_refer(h->did,"SIP/2.0 100 Trying\r\n");
}
}else{
if (!newcall->terminated){
if (send_notify_for_refer(h->did,"SIP/2.0 200 Ok\r\n")==-1){
/* we need previous notify transaction to complete, so buffer the request for later*/
h->sipfrag_pending="SIP/2.0 200 Ok\r\n";
}
}
}
}
return 0;
}
int sal_ping(SalOp *op, const char *from, const char *to){
osip_message_t *options=NULL;
@ -748,26 +843,6 @@ int sal_ping(SalOp *op, const char *from, const char *to){
return -1;
}
int sal_call_accept_refer(SalOp *op){
osip_message_t *msg=NULL;
int err=0;
eXosip_lock();
err = eXosip_call_build_notify(op->did,EXOSIP_SUBCRSTATE_ACTIVE,&msg);
if(msg != NULL)
{
osip_message_set_header(msg,(const char *)"event","refer");
osip_message_set_content_type(msg,"message/sipfrag");
osip_message_set_body(msg,"SIP/2.0 100 Trying",sizeof("SIP/2.0 100 Trying"));
eXosip_call_send_request(op->did,msg);
}
else
{
ms_error("could not get a notify built\n");
}
eXosip_unlock();
return err;
}
int sal_call_refer(SalOp *h, const char *refer_to){
osip_message_t *msg=NULL;
int err=0;
@ -861,6 +936,7 @@ int sal_call_terminate(SalOp *h){
}
void sal_op_authenticate(SalOp *h, const SalAuthInfo *info){
if (h->terminated) return;
if (h->pending_auth){
push_auth_to_exosip(info);
@ -883,9 +959,9 @@ void sal_op_authenticate(SalOp *h, const SalAuthInfo *info){
}
void sal_op_cancel_authentication(SalOp *h) {
if (h->rid >0) {
sal_op_get_sal(h)->callbacks.register_failure(h,SalErrorFailure, SalReasonForbidden,_("Authentication failure"));
sal_op_get_sal(h)->callbacks.register_failure(h,SalErrorFailure, SalReasonForbidden,"Authentication failure");
} else if (h->cid >0) {
sal_op_get_sal(h)->callbacks.call_failure(h,SalErrorFailure, SalReasonForbidden,_("Authentication failure"),0);
sal_op_get_sal(h)->callbacks.call_failure(h,SalErrorFailure, SalReasonForbidden,"Authentication failure",0);
} else {
ms_warning("Auth failure not handled");
}
@ -951,6 +1027,7 @@ static SalOp *find_op(Sal *sal, eXosip_event_t *ev){
return sal_find_in_subscribe(sal,ev->nid);
}
if (ev->response) return sal_find_other(sal,ev->response);
else if (ev->request) return sal_find_other(sal,ev->request);
return NULL;
}
@ -960,6 +1037,8 @@ static void inc_new_call(Sal *sal, eXosip_event_t *ev){
osip_call_info_t *call_info;
char *tmp;
sdp_message_t *sdp=eXosip_get_sdp_info(ev->request);
osip_call_id_t *callid=osip_message_get_call_id(ev->request);
osip_call_id_to_str(callid,(char**)(&op->base.call_id));
set_network_origin(op,ev->request);
set_remote_ua(op,ev->request);
@ -996,7 +1075,6 @@ static void inc_new_call(Sal *sal, eXosip_event_t *ev){
op->tid=ev->tid;
op->cid=ev->cid;
op->did=ev->did;
sal_add_call(op->base.root,op);
sal->callbacks.call_received(op);
}
@ -1040,6 +1118,10 @@ static void handle_ack(Sal *sal, eXosip_event_t *ev){
ms_warning("ack for non-existing call !");
return;
}
if (op->terminated) {
ms_warning("ack for terminated call, ignoring");
return;
}
if (op->sdp_offering){
sdp=eXosip_get_sdp_info(ev->ack);
@ -1517,6 +1599,51 @@ static void process_refer(Sal *sal, SalOp *op, eXosip_event_t *ev){
}
}
static void process_notify(Sal *sal, eXosip_event_t *ev){
osip_header_t *h=NULL;
char *from=NULL;
SalOp *op=find_op(sal,ev);
osip_message_t *ans=NULL;
ms_message("Receiving NOTIFY request !");
osip_from_to_str(ev->request->from,&from);
osip_message_header_get_byname(ev->request,"Event",0,&h);
if(h){
osip_body_t *body=NULL;
//osip_content_type_t *ct=NULL;
osip_message_get_body(ev->request,0,&body);
//ct=osip_message_get_content_type(ev->request);
if (h->hvalue && strcasecmp(h->hvalue,"refer")==0){
/*special handling of refer events*/
if (body && body->body){
osip_message_t *msg;
osip_message_init(&msg);
if (osip_message_parse_sipfrag(msg,body->body,strlen(body->body))==0){
int code=osip_message_get_status_code(msg);
if (code==100){
sal->callbacks.notify_refer(op,SalReferTrying);
}else if (code==200){
sal->callbacks.notify_refer(op,SalReferSuccess);
}else if (code>=400){
sal->callbacks.notify_refer(op,SalReferFailed);
}
}
osip_message_free(msg);
}
}else{
/*generic handling*/
sal->callbacks.notify(op,from,h->hvalue);
}
}
/*answer that we received the notify*/
eXosip_lock();
eXosip_call_build_answer(ev->tid,200,&ans);
if (ans)
eXosip_call_send_answer(ev->tid,200,ans);
eXosip_unlock();
osip_free(from);
}
static void call_message_new(Sal *sal, eXosip_event_t *ev){
osip_message_t *ans=NULL;
if (ev->request){
@ -1559,22 +1686,7 @@ static void call_message_new(Sal *sal, eXosip_event_t *ev){
ms_message("Receiving REFER request !");
process_refer(sal,op,ev);
}else if(MSG_IS_NOTIFY(ev->request)){
osip_header_t *h=NULL;
char *from=NULL;
SalOp *op=find_op(sal,ev);
ms_message("Receiving NOTIFY request !");
osip_from_to_str(ev->request->from,&from);
osip_message_header_get_byname(ev->request,"Event",0,&h);
if(h)
sal->callbacks.notify(op,from,h->hvalue);
/*answer that we received the notify*/
eXosip_lock();
eXosip_call_build_answer(ev->tid,200,&ans);
if (ans)
eXosip_call_send_answer(ev->tid,200,ans);
eXosip_unlock();
osip_free(from);
process_notify(sal,ev);
}else if (MSG_IS_OPTIONS(ev->request)){
eXosip_lock();
eXosip_call_build_answer(ev->tid,200,&ans);
@ -1618,16 +1730,54 @@ static bool_t comes_from_local_if(osip_message_t *msg){
static void text_received(Sal *sal, eXosip_event_t *ev){
osip_body_t *body=NULL;
char *from=NULL,*msg;
char *from=NULL,*msg=NULL;
osip_content_type_t* content_type;
osip_uri_param_t* external_body_url;
char unquoted_external_body_url [256];
int external_body_size=0;
SalMessage salmsg;
char message_id[256]={0};
osip_message_get_body(ev->request,0,&body);
if (body==NULL){
ms_error("Could not get text message from SIP body");
content_type= osip_message_get_content_type(ev->request);
if (!content_type) {
ms_error("Could not get message because no content type");
return;
}
msg=body->body;
osip_from_to_str(ev->request->from,&from);
sal->callbacks.text_received(sal,from,msg);
if (content_type->type
&& strcmp(content_type->type, "text")==0
&& content_type->subtype
&& strcmp(content_type->subtype, "plain")==0 ) {
osip_message_get_body(ev->request,0,&body);
if (body==NULL){
ms_error("Could not get text message from SIP body");
osip_free(from);
return;
}
msg=body->body;
}else if (content_type->type
&& strcmp(content_type->type, "message")==0
&& content_type->subtype
&& strcmp(content_type->subtype, "external-body")==0 ) {
osip_content_type_param_get_byname(content_type, "URL", &external_body_url);
/*remove both first and last character*/
strncpy(unquoted_external_body_url
,&external_body_url->gvalue[1]
,external_body_size=MIN(strlen(external_body_url->gvalue)-1,sizeof(unquoted_external_body_url)));
unquoted_external_body_url[external_body_size-1]='\0';
} else {
ms_warning("Unsupported content type [%s/%s]",content_type->type,content_type->subtype);
osip_free(from);
return;
}
snprintf(message_id,sizeof(message_id)-1,"%s%s",ev->request->call_id->number,ev->request->cseq->number);
salmsg.from=from;
salmsg.text=msg;
salmsg.url=external_body_size>0 ? unquoted_external_body_url : NULL;
salmsg.message_id=message_id;
sal->callbacks.text_received(sal,&salmsg);
osip_free(from);
}
@ -1651,7 +1801,7 @@ static void other_request(Sal *sal, eXosip_event_t *ev){
}else ms_warning("Ignored REFER not coming from this local loopback interface.");
}else if (strncmp(ev->request->sip_method, "UPDATE", 6) == 0){
inc_update(sal,ev);
}else {
}else {
char *tmp=NULL;
size_t msglen=0;
osip_message_to_str(ev->request,&tmp,&msglen);
@ -1676,7 +1826,7 @@ static void masquerade_via(osip_message_t *msg, const char *ip, const char *port
}
static bool_t fix_message_contact(SalOp *op, osip_message_t *request,osip_message_t *last_answer) {
static bool_t fix_message_contact(SalOp *op, osip_message_t *request,osip_message_t *last_answer, bool_t expire_last_contact) {
osip_contact_t *ctt=NULL;
const char *received;
int rport;
@ -1689,6 +1839,23 @@ static bool_t fix_message_contact(SalOp *op, osip_message_t *request,osip_messag
ms_warning("fix_message_contact(): no contact to update");
return FALSE;
}
if (expire_last_contact){
osip_contact_t *oldct=NULL,*prevct;
osip_generic_param_t *param=NULL;
osip_contact_clone(ctt,&oldct);
while ((prevct=(osip_contact_t*)osip_list_get(&request->contacts,1))!=NULL){
osip_contact_free(prevct);
osip_list_remove(&request->contacts,1);
}
osip_list_add(&request->contacts,oldct,1);
osip_contact_param_get_byname(oldct,"expires",&param);
if (param){
if (param->gvalue) osip_free(param->gvalue);
param->gvalue=osip_strdup("0");
}else{
osip_contact_param_add(oldct,osip_strdup("expires"),osip_strdup("0"));
}
}
if (ctt->url->host!=NULL){
osip_free(ctt->url->host);
}
@ -1715,52 +1882,64 @@ static bool_t register_again_with_updated_contact(SalOp *op, osip_message_t *ori
char* tmp;
osip_message_t *msg=NULL;
Sal* sal=op->base.root;
int i=0;
bool_t found_valid_contact=FALSE;
bool_t from_request=FALSE;
if (sal->double_reg==FALSE ) return FALSE;
if (extract_received_rport(last_answer,&received,&rport,&transport)==-1) return FALSE;
osip_message_get_contact(orig_request,0,&ctt);
osip_contact_to_str(ctt,&tmp);
ori_contact_address = sal_address_new(tmp);
do{
ctt=NULL;
osip_message_get_contact(last_answer,i,&ctt);
if (!from_request && ctt==NULL) {
osip_message_get_contact(orig_request,0,&ctt);
from_request=TRUE;
}
if (ctt){
osip_contact_to_str(ctt,&tmp);
ori_contact_address = sal_address_new(tmp);
/*check if contact is up to date*/
if (strcmp(sal_address_get_domain(ori_contact_address),received) ==0
&& sal_address_get_port_int(ori_contact_address) == rport
&& sal_address_get_transport(ori_contact_address) == transport) {
ms_message("Register has up to date contact, doing nothing.");
osip_free(tmp);
sal_address_destroy(ori_contact_address);
return FALSE;
} else ms_message("contact do not match, need to update the register (%s with %s:%i;transport=%s)"
,tmp
,received
,rport
,sal_transport_to_string(transport));
osip_free(tmp);
sal_address_destroy(ori_contact_address);
/*check if contact is up to date*/
if (strcmp(sal_address_get_domain(ori_contact_address),received) ==0
&& sal_address_get_port_int(ori_contact_address) == rport
&& sal_address_get_transport(ori_contact_address) == transport) {
if (!from_request){
ms_message("Register response has up to date contact, doing nothing.");
}else {
ms_warning("Register response does not have up to date contact, but last request had."
"Stupid registrar detected, giving up.");
}
found_valid_contact=TRUE;
}
osip_free(tmp);
sal_address_destroy(ori_contact_address);
}else break;
i++;
}while(!found_valid_contact);
if (!found_valid_contact)
ms_message("Contact do not match, resending register.");
else return FALSE;
if (transport == SalTransportUDP) {
eXosip_lock();
eXosip_register_build_register(op->rid,op->expires,&msg);
if (msg==NULL){
eXosip_unlock();
ms_warning("Fail to create a contact updated register.");
return FALSE;
}
if (fix_message_contact(op,msg,last_answer)) {
eXosip_register_send_register(op->rid,msg);
eXosip_unlock();
ms_message("Resending new register with updated contact");
return TRUE;
} else {
ms_warning("Fail to send updated register.");
eXosip_unlock();
return FALSE;
}
eXosip_unlock();
eXosip_lock();
eXosip_register_build_register(op->rid,op->expires,&msg);
if (msg==NULL){
eXosip_unlock();
ms_warning("Fail to create a contact updated register.");
return FALSE;
}
update_contact_from_response(op,last_answer);
if (fix_message_contact(op,msg,last_answer,op->base.root->expire_old_contact)) {
eXosip_register_send_register(op->rid,msg);
eXosip_unlock();
ms_message("Resending new register with updated contact");
update_contact_from_response(op,last_answer);
return TRUE;
} else {
ms_warning("Fail to send updated register.");
eXosip_unlock();
return FALSE;
}
eXosip_unlock();
return FALSE;
}
@ -1842,16 +2021,40 @@ static bool_t registration_failure(Sal *sal, eXosip_event_t *ev){
static void other_request_reply(Sal *sal,eXosip_event_t *ev){
SalOp *op=find_op(sal,ev);
if (op==NULL){
ms_warning("other_request_reply(): Receiving response to unknown request.");
return;
}
if (ev->response){
ms_message("Processing reponse status [%i] for method [%s]",ev->response->status_code,osip_message_get_method(ev->request));
update_contact_from_response(op,ev->response);
if (ev->request && strcmp(osip_message_get_method(ev->request),"OPTIONS")==0)
sal->callbacks.ping_reply(op);
}
if (ev->request && strcmp(osip_message_get_method(ev->request),"MESSAGE")==0) {
/*out of call message acknolegment*/
SalTextDeliveryStatus status=SalTextDeliveryFailed;
if (ev->response){
if (ev->response->status_code<200){
status=SalTextDeliveryInProgress;
}else if (ev->response->status_code<300 && ev->response->status_code>=200){
status=SalTextDeliveryDone;
}
}
sal->callbacks.text_delivery_update(op,status);
}
}
static void process_in_call_reply(Sal *sal, eXosip_event_t *ev){
SalOp *op=find_op(sal,ev);
if (ev->response){
if (ev->request && strcmp(osip_message_get_method(ev->request),"NOTIFY")==0){
if (op->sipfrag_pending){
send_notify_for_refer(op->did,op->sipfrag_pending);
op->sipfrag_pending=NULL;
}
}
}
}
static bool_t process_event(Sal *sal, eXosip_event_t *ev){
@ -1904,6 +2107,7 @@ static bool_t process_event(Sal *sal, eXosip_event_t *ev){
case EXOSIP_CALL_RINGING:
ms_message("CALL_RINGING");
call_ringing(sal,ev);
authentication_ok(sal,ev);
break;
case EXOSIP_CALL_MESSAGE_NEW:
ms_message("EXOSIP_CALL_MESSAGE_NEW");
@ -1915,6 +2119,10 @@ static bool_t process_event(Sal *sal, eXosip_event_t *ev){
return process_authentication(sal,ev);
}
break;
case EXOSIP_CALL_MESSAGE_ANSWERED:
ms_message("EXOSIP_CALL_MESSAGE_ANSWERED ");
process_in_call_reply(sal,ev);
break;
case EXOSIP_IN_SUBSCRIPTION_NEW:
ms_message("CALL_IN_SUBSCRIPTION_NEW ");
sal_exosip_subscription_recv(sal,ev);
@ -1942,8 +2150,8 @@ static bool_t process_event(Sal *sal, eXosip_event_t *ev){
if (ev->response && (ev->response->status_code == 407 || ev->response->status_code == 401)){
return process_authentication(sal,ev);
}
case EXOSIP_SUBSCRIPTION_SERVERFAILURE:
case EXOSIP_SUBSCRIPTION_GLOBALFAILURE:
case EXOSIP_SUBSCRIPTION_SERVERFAILURE:
case EXOSIP_SUBSCRIPTION_GLOBALFAILURE:
sal_exosip_subscription_closed(sal,ev);
break;
case EXOSIP_REGISTRATION_FAILURE:
@ -2025,13 +2233,24 @@ static void register_set_contact(osip_message_t *msg, const char *contact){
}
static void sal_register_add_route(osip_message_t *msg, const char *proxy){
char tmp[256]={0};
snprintf(tmp,sizeof(tmp)-1,"<%s;lr>",proxy);
osip_route_t *route;
osip_list_special_free(&msg->routes,(void (*)(void*))osip_route_free);
osip_message_set_route(msg,tmp);
osip_route_init(&route);
if (osip_route_parse(route,proxy)==0){
osip_uri_param_t *lr_param = NULL;
osip_uri_uparam_get_byname(route->url, "lr", &lr_param);
if (lr_param == NULL){
osip_uri_uparam_add(route->url,osip_strdup("lr"),NULL);
}
osip_list_add(&msg->routes,route,0);
return;
}
osip_route_free(route);
}
int sal_register(SalOp *h, const char *proxy, const char *from, int expires){
osip_message_t *msg;
const char *contact=sal_op_get_contact(h);
@ -2040,11 +2259,21 @@ int sal_register(SalOp *h, const char *proxy, const char *from, int expires){
if (h->rid==-1){
SalAddress *from_parsed=sal_address_new(from);
char domain[256];
char *uri, *domain_ptr = NULL;
if (from_parsed==NULL) {
ms_warning("sal_register() bad from %s",from);
return -1;
}
snprintf(domain,sizeof(domain),"sip:%s",sal_address_get_domain(from_parsed));
/* Get domain using sal_address_as_string_uri_only() and stripping the username part instead of
using sal_address_get_domain() because to have a properly formatted domain with IPv6 proxy addresses. */
uri = sal_address_as_string_uri_only(from_parsed);
if (uri) domain_ptr = strchr(uri, '@');
if (domain_ptr) {
snprintf(domain,sizeof(domain),"sip:%s",domain_ptr+1);
} else {
snprintf(domain,sizeof(domain),"sip:%s",sal_address_get_domain(from_parsed));
}
if (uri) ms_free(uri);
sal_address_destroy(from_parsed);
eXosip_lock();
h->rid=eXosip_register_build_initial_register(from,domain,NULL,expires,&msg);
@ -2062,8 +2291,9 @@ int sal_register(SalOp *h, const char *proxy, const char *from, int expires){
eXosip_register_build_register(h->rid,expires,&msg);
sal_register_add_route(msg,proxy);
}
if (msg)
if (msg){
eXosip_register_send_register(h->rid,msg);
}
eXosip_unlock();
h->expires=expires;
return (msg != NULL) ? 0 : -1;
@ -2072,12 +2302,28 @@ int sal_register(SalOp *h, const char *proxy, const char *from, int expires){
int sal_register_refresh(SalOp *op, int expires){
osip_message_t *msg=NULL;
const char *contact=sal_op_get_contact(op);
if (op->rid==-1){
ms_error("Unexistant registration context, not possible to refresh.");
return -1;
}
#ifdef HAVE_EXOSIP_TRYLOCK
{
int tries=0;
/*iOS hack: in the keep alive handler, we have no more than 10 seconds to refresh registers, otherwise the application is suspended forever.
* In order to prevent this case that can occur when the exosip thread is busy with DNS while network isn't in a good shape, we try to take
* the exosip lock in a non blocking way, and give up if it takes too long*/
while (eXosip_trylock()!=0){
ms_usleep(100000);
if (tries>30) {/*after 3 seconds, give up*/
ms_warning("Could not obtain exosip lock in a reasonable time, giving up.");
return -1;
}
}
}
#else
eXosip_lock();
#endif
eXosip_register_build_register(op->rid,expires,&msg);
if (msg!=NULL){
if (contact) register_set_contact(msg,contact);
@ -2296,6 +2542,10 @@ int sal_call_update(SalOp *h, const char *subject){
eXosip_unlock();
osip_message_set_subject(reinvite,subject);
osip_message_set_allow(reinvite, "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO");
if (h->base.contact){
_osip_list_set_empty(&reinvite->contacts,(void (*)(void*))osip_contact_free);
osip_message_set_contact(reinvite,h->base.contact);
}
if (h->base.root->session_expires!=0){
osip_message_set_header(reinvite, "Session-expires", "200");
osip_message_set_supported(reinvite, "timer");

View file

@ -41,12 +41,15 @@ struct Sal{
int keepalive_period;
void *up; /*user pointer*/
char* rootCa; /* File _or_ folder containing root CA */
int dscp;
bool_t one_matching_codec;
bool_t double_reg;
bool_t use_rports;
bool_t use_101;
bool_t reuse_authorization;
bool_t verify_server_certs;
bool_t expire_old_contact;
bool_t add_dates;
};
struct SalOp{
@ -66,6 +69,7 @@ struct SalOp{
char *replaces;
char *referred_by;
const SalAuthInfo *auth_info;
const char *sipfrag_pending;
bool_t supports_session_timers;
bool_t sdp_offering;
bool_t reinvite;

View file

@ -81,7 +81,7 @@ void sal_remove_in_subscribe(Sal *sal, SalOp *op){
sal->in_subscribes=ms_list_remove(sal->in_subscribes,op);
}
int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg){
int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg){
osip_message_t *sip=NULL;
if(op->cid == -1)
@ -97,8 +97,8 @@ int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg){
eXosip_message_build_request(&sip,"MESSAGE",sal_op_get_to(op),
sal_op_get_from(op),sal_op_get_route(op));
if (sip!=NULL){
osip_message_set_content_type(sip,"text/plain");
osip_message_set_body(sip,msg,strlen(msg));
osip_message_set_content_type(sip,content_type);
if (msg) osip_message_set_body(sip,msg,strlen(msg));
sal_add_other(op->base.root,op,sip);
eXosip_message_send_request(sip);
}else{
@ -118,14 +118,16 @@ int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg){
eXosip_unlock();
return -1;
}
osip_message_set_content_type(sip,"text/plain");
osip_message_set_body(sip,msg,strlen(msg));
osip_message_set_content_type(sip,content_type);
if (msg) osip_message_set_body(sip,msg,strlen(msg));
eXosip_call_send_request(op->did,sip);
eXosip_unlock();
}
return 0;
}
int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg) {
return sal_message_send(op,from,to,"text/plain",msg);
}
/*presence Subscribe/notify*/
int sal_subscribe_presence(SalOp *op, const char *from, const char *to){
osip_message_t *msg=NULL;

View file

@ -18,6 +18,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "ortp/port.h"
#include "ortp/b64.h"
#include "ortp/ortp_srtp.h"
#include "sal.h"
@ -116,7 +117,7 @@ static int _sdp_message_get_mline_dir(sdp_message_t *sdp, int mline){
}else if (keywordcmp("sendonly",attr->a_att_field)==0){
return SalStreamSendOnly;
}else if (keywordcmp("recvonly",attr->a_att_field)==0){
return SalStreamSendOnly;
return SalStreamRecvOnly;
}else if (keywordcmp("inactive",attr->a_att_field)==0){
return SalStreamInactive;
}
@ -130,6 +131,7 @@ static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc)
int inet6;
char sessid[16];
char sessver[16];
const char *rtp_addr = desc->addr;
snprintf(sessid,16,"%i",desc->session_id);
snprintf(sessver,16,"%i",desc->session_ver);
@ -143,11 +145,12 @@ static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc)
osip_strdup ("IN"), inet6 ? osip_strdup("IP6") : osip_strdup ("IP4"),
osip_strdup (desc->addr));
sdp_message_s_name_set (local, osip_strdup ("Talk"));
if(!sal_media_description_has_dir (desc,SalStreamSendOnly))
/* Do not set the c= line to 0.0.0.0 if there is an ICE session. */
if((desc->ice_ufrag[0] != '\0') || !sal_media_description_has_dir (desc,SalStreamSendOnly))
{
sdp_message_c_connection_add (local, -1,
osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"),
osip_strdup (desc->addr), NULL, NULL);
osip_strdup (rtp_addr), NULL, NULL);
}
else
{
@ -158,6 +161,10 @@ static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc)
sdp_message_t_time_descr_add (local, osip_strdup ("0"), osip_strdup ("0"));
if (desc->bandwidth>0) sdp_message_b_bandwidth_add (local, -1, osip_strdup ("AS"),
int_2char(desc->bandwidth));
if (desc->ice_completed == TRUE) sdp_message_a_attribute_add(local, -1, osip_strdup("nortpproxy"), osip_strdup("yes"));
if (desc->ice_pwd[0] != '\0') sdp_message_a_attribute_add(local, -1, osip_strdup("ice-pwd"), osip_strdup(desc->ice_pwd));
if (desc->ice_ufrag[0] != '\0') sdp_message_a_attribute_add(local, -1, osip_strdup("ice-ufrag"), osip_strdup(desc->ice_ufrag));
return local;
}
@ -197,14 +204,66 @@ static void add_payload(sdp_message_t *msg, int line, const PayloadType *pt, boo
}
}
static void add_ice_candidates(sdp_message_t *msg, int lineno, const SalStreamDescription *desc)
{
char buffer[1024];
const SalIceCandidate *candidate;
int nb;
int i;
for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES; i++) {
candidate = &desc->ice_candidates[i];
if ((candidate->addr[0] == '\0') || (candidate->port == 0)) break;
nb = snprintf(buffer, sizeof(buffer), "%s %u UDP %u %s %d typ %s",
candidate->foundation, candidate->componentID, candidate->priority, candidate->addr, candidate->port, candidate->type);
if (nb < 0) {
ms_error("Cannot add ICE candidate attribute!");
return;
}
if (candidate->raddr[0] != '\0') {
nb = snprintf(buffer + nb, sizeof(buffer) - nb, " raddr %s rport %d", candidate->raddr, candidate->rport);
if (nb < 0) {
ms_error("Cannot add ICE candidate attribute!");
return;
}
}
sdp_message_a_attribute_add(msg, lineno, osip_strdup("candidate"), osip_strdup(buffer));
}
}
static void add_ice_remote_candidates(sdp_message_t *msg, int lineno, const SalStreamDescription *desc)
{
char buffer[1024];
char *ptr = buffer;
const SalIceRemoteCandidate *candidate;
int offset = 0;
int i;
buffer[0] = '\0';
for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES; i++) {
candidate = &desc->ice_remote_candidates[i];
if ((candidate->addr[0] != '\0') && (candidate->port != 0)) {
offset = snprintf(ptr, buffer + sizeof(buffer) - ptr, "%s%d %s %d", (i > 0) ? " " : "", i + 1, candidate->addr, candidate->port);
if (offset < 0) {
ms_error("Cannot add ICE remote-candidates attribute!");
return;
}
ptr += offset;
}
}
if (buffer[0] != '\0') sdp_message_a_attribute_add(msg, lineno, osip_strdup("remote-candidates"), osip_strdup(buffer));
}
static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription *desc){
const char *mt=NULL;
const MSList *elem;
const char *addr;
const char *rtp_addr;
const char *rtcp_addr;
const char *dir="sendrecv";
int port;
int rtp_port;
int rtcp_port;
bool_t strip_well_known_rtpmaps;
bool_t different_rtp_and_rtcp_addr;
switch (desc->type) {
case SalAudio:
@ -217,29 +276,16 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription
mt=desc->typeother;
break;
}
if (desc->candidates[0].addr[0]!='\0'){
addr=desc->candidates[0].addr;
port=desc->candidates[0].port;
}else{
addr=desc->addr;
port=desc->port;
}
/*only add a c= line within the stream description if address are differents*/
if (strcmp(addr,sdp_message_c_addr_get(msg, -1, 0))!=0){
bool_t inet6;
if (strchr(addr,':')!=NULL){
inet6=TRUE;
}else inet6=FALSE;
sdp_message_c_connection_add (msg, lineno,
osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"),
osip_strdup (addr), NULL, NULL);
}
rtp_addr=desc->rtp_addr;
rtcp_addr=desc->rtcp_addr;
rtp_port=desc->rtp_port;
rtcp_port=desc->rtcp_port;
if (desc->proto == SalProtoRtpSavp) {
int i;
sdp_message_m_media_add (msg, osip_strdup (mt),
int_2char (port), NULL,
int_2char (rtp_port), NULL,
osip_strdup ("RTP/SAVP"));
/* add crypto lines */
@ -271,10 +317,22 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription
} else {
sdp_message_m_media_add (msg, osip_strdup (mt),
int_2char (port), NULL,
int_2char (rtp_port), NULL,
osip_strdup ("RTP/AVP"));
}
/*only add a c= line within the stream description if address are differents*/
if (rtp_addr[0]!='\0' && strcmp(rtp_addr,sdp_message_c_addr_get(msg, -1, 0))!=0){
bool_t inet6;
if (strchr(rtp_addr,':')!=NULL){
inet6=TRUE;
}else inet6=FALSE;
sdp_message_c_connection_add (msg, lineno,
osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"),
osip_strdup (rtp_addr), NULL, NULL);
}
if (desc->bandwidth>0) sdp_message_b_bandwidth_add (msg, lineno, osip_strdup ("AS"),
int_2char(desc->bandwidth));
if (desc->ptime>0) sdp_message_a_attribute_add(msg,lineno,osip_strdup("ptime"),
@ -305,8 +363,34 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription
break;
}
if (dir) sdp_message_a_attribute_add (msg, lineno, osip_strdup (dir),NULL);
if (rtp_port != 0) {
different_rtp_and_rtcp_addr = (rtcp_addr[0] != '\0') && (strcmp(rtp_addr, rtcp_addr) != 0);
if ((rtcp_port != (rtp_port + 1)) || (different_rtp_and_rtcp_addr == TRUE)) {
if (different_rtp_and_rtcp_addr == TRUE) {
char buffer[1024];
snprintf(buffer, sizeof(buffer), "%u IN IP4 %s", rtcp_port, rtcp_addr);
sdp_message_a_attribute_add(msg, lineno, osip_strdup("rtcp"), osip_strdup(buffer));
} else {
sdp_message_a_attribute_add(msg, lineno, osip_strdup("rtcp"), int_2char(rtcp_port));
}
}
}
if (desc->ice_completed == TRUE) {
sdp_message_a_attribute_add(msg, lineno, osip_strdup("nortpproxy"), osip_strdup("yes"));
}
if (desc->ice_mismatch == TRUE) {
sdp_message_a_attribute_add(msg, lineno, osip_strdup("ice-mismatch"), NULL);
} else {
if (desc->rtp_port != 0) {
if (desc->ice_pwd[0] != '\0') sdp_message_a_attribute_add(msg, lineno, osip_strdup("ice-pwd"), osip_strdup(desc->ice_pwd));
if (desc->ice_ufrag[0] != '\0') sdp_message_a_attribute_add(msg, lineno, osip_strdup("ice-ufrag"), osip_strdup(desc->ice_ufrag));
add_ice_candidates(msg, lineno, desc);
add_ice_remote_candidates(msg, lineno, desc);
}
}
}
sdp_message_t *media_description_to_sdp(const SalMediaDescription *desc){
int i;
sdp_message_t *msg=create_generic_sdp(desc);
@ -349,25 +433,39 @@ static int payload_type_fill_from_rtpmap(PayloadType *pt, const char *rtpmap){
int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){
int i,j;
const char *mtype,*proto,*port,*addr,*number;
const char *mtype,*proto,*rtp_port,*rtp_addr,*number;
sdp_bandwidth_t *sbw=NULL;
addr=sdp_message_c_addr_get (msg, -1, 0);
if (addr)
strncpy(desc->addr,addr,sizeof(desc->addr));
sdp_attribute_t *attr;
int nb_ice_candidates;
rtp_addr=sdp_message_c_addr_get (msg, -1, 0);
if (rtp_addr)
strncpy(desc->addr,rtp_addr,sizeof(desc->addr));
for(j=0;(sbw=sdp_message_bandwidth_get(msg,-1,j))!=NULL;++j){
if (strcasecmp(sbw->b_bwtype,"AS")==0) desc->bandwidth=atoi(sbw->b_bandwidth);
}
/* Get ICE remote ufrag and remote pwd, and ice_lite flag */
for (i = 0; (i < SAL_MEDIA_DESCRIPTION_MAX_MESSAGE_ATTRIBUTES) && ((attr = sdp_message_attribute_get(msg, -1, i)) != NULL); i++) {
if ((keywordcmp("ice-ufrag", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) {
strncpy(desc->ice_ufrag, attr->a_att_value, sizeof(desc->ice_ufrag));
} else if ((keywordcmp("ice-pwd", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) {
strncpy(desc->ice_pwd, attr->a_att_value, sizeof(desc->ice_pwd));
} else if (keywordcmp("ice-lite", attr->a_att_field) == 0) {
desc->ice_lite = TRUE;
}
}
/* for each m= line */
for (i=0; !sdp_message_endof_media (msg, i) && i<SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++)
{
SalStreamDescription *stream=&desc->streams[i];
nb_ice_candidates = 0;
memset(stream,0,sizeof(*stream));
mtype = sdp_message_m_media_get(msg, i);
proto = sdp_message_m_proto_get (msg, i);
port = sdp_message_m_port_get(msg, i);
rtp_port = sdp_message_m_port_get(msg, i);
stream->proto=SalProtoUnknown;
if (proto){
if (strcasecmp(proto,"RTP/AVP")==0)
@ -376,11 +474,11 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){
stream->proto=SalProtoRtpSavp;
}
}
addr = sdp_message_c_addr_get (msg, i, 0);
if (addr != NULL)
strncpy(stream->addr,addr,sizeof(stream->addr));
if (port)
stream->port=atoi(port);
rtp_addr = sdp_message_c_addr_get (msg, i, 0);
if (rtp_addr != NULL)
strncpy(stream->rtp_addr,rtp_addr,sizeof(stream->rtp_addr));
if (rtp_port)
stream->rtp_port=atoi(rtp_port);
stream->ptime=_sdp_message_get_a_ptime(msg,i);
if (strcasecmp("audio", mtype) == 0){
@ -394,7 +492,7 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){
for(j=0;(sbw=sdp_message_bandwidth_get(msg,i,j))!=NULL;++j){
if (strcasecmp(sbw->b_bwtype,"AS")==0) stream->bandwidth=atoi(sbw->b_bandwidth);
}
stream->dir=_sdp_message_get_mline_dir(msg,i);
stream->dir=_sdp_message_get_mline_dir(msg,i);
/* for each payload type */
for (j=0;((number=sdp_message_m_payload_get (msg, i,j)) != NULL); j++){
const char *rtpmap,*fmtp;
@ -412,11 +510,27 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){
pt->send_fmtp ? pt->send_fmtp : "");
}
}
/* Get media specific RTCP attribute */
stream->rtcp_port = stream->rtp_port + 1;
snprintf(stream->rtcp_addr, sizeof(stream->rtcp_addr), "%s", stream->rtp_addr);
for (j = 0; ((attr = sdp_message_attribute_get(msg, i, j)) != NULL); j++) {
if ((keywordcmp("rtcp", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) {
char tmp[256];
int nb = sscanf(attr->a_att_value, "%d IN IP4 %s", &stream->rtcp_port, tmp);
if (nb == 1) {
/* SDP rtcp attribute only contains the port */
} else if (nb == 2) {
strncpy(stream->rtcp_addr, tmp, sizeof(stream->rtcp_addr));
} else {
ms_warning("sdp has a strange a= line (%s) nb=%i", attr->a_att_value, nb);
}
}
}
/* read crypto lines if any */
if (stream->proto == SalProtoRtpSavp) {
int k, valid_count = 0;
sdp_attribute_t *attr;
memset(&stream->crypto, 0, sizeof(stream->crypto));
for (k=0;valid_count < SAL_CRYPTO_ALGO_MAX && (attr=sdp_message_attribute_get(msg,i,k))!=NULL;k++){
@ -455,6 +569,38 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){
}
ms_message("Found: %d valid crypto lines", valid_count);
}
/* Get ICE candidate attributes if any */
for (j = 0; (attr = sdp_message_attribute_get(msg, i, j)) != NULL; j++) {
if ((keywordcmp("candidate", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) {
SalIceCandidate *candidate = &stream->ice_candidates[nb_ice_candidates];
int nb = sscanf(attr->a_att_value, "%s %u UDP %u %s %d typ %s raddr %s rport %d",
candidate->foundation, &candidate->componentID, &candidate->priority, candidate->addr, &candidate->port,
candidate->type, candidate->raddr, &candidate->rport);
if ((nb == 6) || (nb == 8)) nb_ice_candidates++;
else memset(candidate, 0, sizeof(*candidate));
} else if ((keywordcmp("remote-candidates", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) {
SalIceRemoteCandidate candidate;
unsigned int componentID;
int offset;
char *ptr = attr->a_att_value;
while (3 == sscanf(ptr, "%u %s %u%n", &componentID, candidate.addr, &candidate.port, &offset)) {
if ((componentID > 0) && (componentID <= SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES)) {
SalIceRemoteCandidate *remote_candidate = &stream->ice_remote_candidates[componentID - 1];
strncpy(remote_candidate->addr, candidate.addr, sizeof(remote_candidate->addr));
remote_candidate->port = candidate.port;
}
ptr += offset;
if (ptr[offset] == ' ') ptr += 1;
}
} else if ((keywordcmp("ice-ufrag", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) {
strncpy(stream->ice_ufrag, attr->a_att_value, sizeof(stream->ice_ufrag));
} else if ((keywordcmp("ice-pwd", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) {
strncpy(stream->ice_pwd, attr->a_att_value, sizeof(stream->ice_pwd));
} else if (keywordcmp("ice-mismatch", attr->a_att_field) == 0) {
stream->ice_mismatch = TRUE;
}
}
}
desc->nstreams=i;
return 0;

48
coreapi/test_numbers.c Normal file
View file

@ -0,0 +1,48 @@
/*
linphone
Copyright (C) 2012 Belledonne Communications SARL
Author: Simon MORLAT (simon.morlat@linphone.org)
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 "linphonecore.h"
#include "linphonecore_utils.h"
int main(int argc , char *argv[]){
LinphoneProxyConfig *cfg;
char normalized_number[32];
if (argc<2){
fprintf(stderr,"Usage:\n%s <phone number> [<country code>] [--escape-plus]\nReturns normalized number.", argv[0]);
return -1;
}
linphone_core_enable_logs(stderr);
cfg=linphone_proxy_config_new();
if (argc>2)
linphone_proxy_config_set_dial_prefix(cfg,argv[2]);
if (argc>3 && strcmp(argv[3],"--escape-plus")==0)
linphone_proxy_config_set_dial_escape_plus(cfg,TRUE);
linphone_proxy_config_normalize_number(cfg,argv[1],normalized_number,sizeof(normalized_number));
printf("Normalized number is %s\n",normalized_number);
/*check extracted ccc*/
if (linphone_dial_plan_lookup_ccc_from_e164(normalized_number) != atoi(linphone_proxy_config_get_dial_prefix(cfg))) {
printf("Error ccc [%i] not correctly parsed\n",linphone_dial_plan_lookup_ccc_from_e164(normalized_number));
} else {
printf("Extracted ccc is [%i] \n",linphone_dial_plan_lookup_ccc_from_e164(normalized_number));
}
return 0;
}

View file

@ -9,7 +9,9 @@ UI_FILES= about.ui \
log.ui \
buddylookup.ui \
tunnel_config.ui \
waiting.ui
waiting.ui \
dscp_settings.ui \
call_statistics.ui
PIXMAPS= \
stock_people.png

212
gtk/call_statistics.ui Normal file
View file

@ -0,0 +1,212 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="2.24"/>
<!-- interface-naming-policy project-wide -->
<object class="GtkDialog" id="call_statistics">
<property name="can_focus">False</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Call statistics</property>
<property name="type_hint">dialog</property>
<signal name="response" handler="linphone_gtk_call_statistics_closed" swapped="no"/>
<child internal-child="vbox">
<object class="GtkVBox" id="dialog-vbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkHButtonBox" id="dialog-action_area1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<placeholder/>
</child>
<child>
<object class="GtkButton" id="button1">
<property name="label">gtk-close</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="frame1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="left_padding">12</property>
<child>
<object class="GtkTable" id="table1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="n_rows">6</property>
<property name="n_columns">2</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkLabel" id="audio_codec_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Audio codec</property>
</object>
<packing>
<property name="x_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="video_codec_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Video codec</property>
</object>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Audio IP bandwidth usage</property>
</object>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="audio_codec">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="video_codec">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="audio_bandwidth_usage">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Media connectivity</property>
</object>
<packing>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
<property name="x_options"></property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<object class="GtkLabel" id="media_connectivity">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Video IP bandwidth usage</property>
</object>
<packing>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="x_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="video_bandwidth_usage">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="call_statistics_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;Call statistics and information&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="0">button1</action-widget>
</action-widgets>
</object>
</interface>

View file

@ -57,6 +57,16 @@ void linphone_gtk_call_log_update(GtkWidget *w){
const char *display;
gchar *logtxt, *minutes, *seconds;
gchar quality[20];
const char *status=NULL;
gchar *start_date=NULL;
#if GLIB_CHECK_VERSION(2,26,0)
if (cl->start_date_time){
GDateTime *dt=g_date_time_new_from_unix_local(cl->start_date_time);
start_date=g_date_time_format(dt,"%c");
g_date_time_unref(dt);
}
#endif
display=linphone_address_get_display_name (la);
if (display==NULL){
@ -67,19 +77,38 @@ void linphone_gtk_call_log_update(GtkWidget *w){
if (cl->quality!=-1){
snprintf(quality,sizeof(quality),"%.1f",cl->quality);
}
switch(cl->status){
case LinphoneCallAborted:
status=_("Aborted");
break;
case LinphoneCallMissed:
status=_("Missed");
break;
case LinphoneCallDeclined:
status=_("Declined");
break;
default:
break;
}
minutes=g_markup_printf_escaped(
ngettext("%i minute", "%i minutes", cl->duration/60),
cl->duration/60);
seconds=g_markup_printf_escaped(
ngettext("%i second", "%i seconds", cl->duration%60),
cl->duration%60);
logtxt=g_markup_printf_escaped(
if (status==NULL) logtxt=g_markup_printf_escaped(
_("<big><b>%s</b></big>\t<small><i>%s</i>\t"
"<i>Quality: %s</i></small>\n%s\t%s %s\t"),
display, addr, cl->quality!=-1 ? quality : _("n/a"),
cl->start_date, minutes, seconds);
start_date ? start_date : cl->start_date, minutes, seconds);
else logtxt=g_markup_printf_escaped(
_("<big><b>%s</b></big>\t<small><i>%s</i></small>\t"
"\n%s\t%s"),
display, addr,
start_date ? start_date : cl->start_date, status);
g_free(minutes);
g_free(seconds);
if (start_date) g_free(start_date);
gtk_list_store_append (store,&iter);
gtk_list_store_set (store,&iter,
0, cl->dir==LinphoneCallOutgoing ? GTK_STOCK_GO_UP : GTK_STOCK_GO_DOWN,

View file

@ -19,6 +19,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "linphone.h"
#ifdef HAVE_GTK_OSX
#include <gtkosxapplication.h>
#endif
GtkWidget * linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const char *with){
GtkWidget *w;
GtkTextBuffer *b;
@ -37,6 +42,7 @@ GtkWidget * linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const char *with){
}
void linphone_gtk_create_chatroom(const char *with){
LinphoneChatRoom *cr=linphone_core_create_chat_room(linphone_gtk_get_core(),with);
if (!cr) return;
linphone_gtk_init_chatroom(cr,with);
@ -84,6 +90,10 @@ const char* linphone_gtk_get_used_identity(){
else return linphone_core_get_primary_contact(lc);
}
static void on_chat_state_changed(LinphoneChatMessage *msg, LinphoneChatMessageState state, void *user_pointer){
g_message("chat message state is %s",linphone_chat_message_state_to_string(state));
}
void linphone_gtk_send_text(GtkWidget *button){
GtkWidget *w=gtk_widget_get_toplevel(button);
GtkWidget *entry=linphone_gtk_get_widget(w,"text_entry");
@ -91,19 +101,37 @@ void linphone_gtk_send_text(GtkWidget *button){
const gchar *entered;
entered=gtk_entry_get_text(GTK_ENTRY(entry));
if (strlen(entered)>0) {
LinphoneChatMessage *msg;
linphone_gtk_push_text(GTK_TEXT_VIEW(linphone_gtk_get_widget(w,"textlog")),
linphone_gtk_get_used_identity(),
entered,TRUE);
linphone_chat_room_send_message(cr,entered);
msg=linphone_chat_room_create_message(cr,entered);
linphone_chat_room_send_message2(cr,msg,on_chat_state_changed,NULL);
gtk_entry_set_text(GTK_ENTRY(entry),"");
}
}
void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from, const char *message){
GtkWidget *w=(GtkWidget*)linphone_chat_room_get_user_data(room);
if (w==NULL){
GtkWidget *w=(GtkWidget*)linphone_chat_room_get_user_data(room);
if (w==NULL){
w=linphone_gtk_init_chatroom(room,linphone_address_as_string_uri_only(from));
g_object_set_data(G_OBJECT(w),"is_notified",GINT_TO_POINTER(FALSE));
}
#ifdef HAVE_GTK_OSX
/* Notified when a new message is sent */
linphone_gtk_status_icon_set_blinking(TRUE);
#else
if (!gtk_window_is_active((GtkWindow*)w)){
if(!GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"is_notified"))){
linphone_gtk_notify(NULL,message);
g_object_set_data(G_OBJECT(w),"is_notified",GINT_TO_POINTER(TRUE));
}
} else {
g_object_set_data(G_OBJECT(w),"is_notified",GINT_TO_POINTER(FALSE));
}
#endif
linphone_gtk_push_text(GTK_TEXT_VIEW(linphone_gtk_get_widget(w,"textlog")),
linphone_address_as_string_uri_only(from),
message,FALSE);

178
gtk/dscp_settings.ui Normal file
View file

@ -0,0 +1,178 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="2.18"/>
<!-- interface-naming-policy project-wide -->
<object class="GtkDialog" id="dscp_settings">
<property name="can_focus">False</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Dscp settings</property>
<property name="modal">True</property>
<property name="type_hint">dialog</property>
<signal name="response" handler="linphone_gtk_dscp_edit_response" swapped="no"/>
<child internal-child="vbox">
<object class="GtkVBox" id="dialog-vbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkHButtonBox" id="dialog-action_area1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="button2">
<property name="label">gtk-close</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button1">
<property name="label">gtk-ok</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="frame1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkTable" id="table1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="n_rows">3</property>
<property name="n_columns">2</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkEntry" id="sip_dscp">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
<property name="invisible_char_set">True</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="audio_dscp">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
<property name="invisible_char_set">True</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="video_dscp">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
<property name="invisible_char_set">True</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">SIP</property>
</object>
</child>
<child>
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Audio RTP stream</property>
</object>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Video RTP stream</property>
</object>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;Set DSCP values (in hexadecimal)&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="-6">button2</action-widget>
<action-widget response="-5">button1</action-widget>
</action-widgets>
</object>
</interface>

View file

@ -193,6 +193,102 @@ void linphone_gtk_enable_conference_button(LinphoneCore *lc, gboolean value){
}
}
static void show_used_codecs(GtkWidget *callstats, LinphoneCall *call){
const LinphoneCallParams *params=linphone_call_get_current_params(call);
if (params){
const PayloadType *acodec=linphone_call_params_get_used_audio_codec(params);
const PayloadType *vcodec=linphone_call_params_get_used_video_codec(params);
GtkWidget *acodec_ui=linphone_gtk_get_widget(callstats,"audio_codec");
GtkWidget *vcodec_ui=linphone_gtk_get_widget(callstats,"video_codec");
if (acodec){
char tmp[64]={0};
snprintf(tmp,sizeof(tmp)-1,"%s/%i/%i",acodec->mime_type,acodec->clock_rate,acodec->channels);
gtk_label_set_label(GTK_LABEL(acodec_ui),tmp);
}else gtk_label_set_label(GTK_LABEL(acodec_ui),_("Not used"));
if (vcodec){
gtk_label_set_label(GTK_LABEL(vcodec_ui),vcodec->mime_type);
}else gtk_label_set_label(GTK_LABEL(vcodec_ui),_("Not used"));
}
}
static const char *ice_state_to_string(LinphoneIceState ice_state){
switch(ice_state){
case LinphoneIceStateNotActivated:
return _("ICE not activated");
case LinphoneIceStateFailed:
return _("ICE failed");
case LinphoneIceStateInProgress:
return _("ICE in progress");
case LinphoneIceStateReflexiveConnection:
return _("Going through one or more NATs");
case LinphoneIceStateHostConnection:
return _("Direct");
case LinphoneIceStateRelayConnection:
return _("Through a relay server");
}
return "invalid";
}
static void _refresh_call_stats(GtkWidget *callstats, LinphoneCall *call){
const LinphoneCallStats *as=linphone_call_get_audio_stats(call);
const LinphoneCallStats *vs=linphone_call_get_video_stats(call);
LinphoneIceState ice_state=as->ice_state;
gchar *tmp=g_strdup_printf(_("download: %f\nupload: %f (kbit/s)"),
as->download_bandwidth,as->upload_bandwidth);
gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"audio_bandwidth_usage")),tmp);
g_free(tmp);
tmp=g_strdup_printf(_("download: %f\nupload: %f (kbit/s)"),
vs->download_bandwidth,vs->upload_bandwidth);
gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"video_bandwidth_usage")),tmp);
g_free(tmp);
gtk_label_set_text(GTK_LABEL(linphone_gtk_get_widget(callstats,"media_connectivity")),ice_state_to_string(ice_state));
}
static gboolean refresh_call_stats(GtkWidget *callstats){
LinphoneCall *call=(LinphoneCall*)g_object_get_data(G_OBJECT(callstats),"call");
switch (linphone_call_get_state(call)){
case LinphoneCallError:
case LinphoneCallEnd:
case LinphoneCallReleased:
gtk_widget_destroy(callstats);
return FALSE;
break;
case LinphoneCallStreamsRunning:
_refresh_call_stats(callstats,call);
break;
default:
break;
}
return TRUE;
}
static void on_call_stats_destroyed(GtkWidget *call_view){
GtkWidget *call_stats=(GtkWidget*)g_object_get_data(G_OBJECT(call_view),"call_stats");
LinphoneCall *call=(LinphoneCall*)g_object_get_data(G_OBJECT(call_stats),"call");
g_source_remove(GPOINTER_TO_INT(g_object_get_data(G_OBJECT(call_stats),"tid")));
g_object_set_data(G_OBJECT(call_view),"call_stats",NULL);
linphone_call_unref(call);
}
static void linphone_gtk_show_call_stats(LinphoneCall *call){
GtkWidget *w=(GtkWidget*)linphone_call_get_user_pointer(call);
GtkWidget *call_stats=(GtkWidget*)g_object_get_data(G_OBJECT(w),"call_stats");
if (call_stats==NULL){
guint tid;
call_stats=linphone_gtk_create_window("call_statistics");
g_object_set_data(G_OBJECT(w),"call_stats",call_stats);
g_object_set_data(G_OBJECT(call_stats),"call",linphone_call_ref(call));
tid=g_timeout_add(1000,(GSourceFunc)refresh_call_stats,call_stats);
g_object_set_data(G_OBJECT(call_stats),"tid",GINT_TO_POINTER(tid));
g_signal_connect_swapped(G_OBJECT(call_stats),"destroy",(GCallback)on_call_stats_destroyed,(gpointer)w);
show_used_codecs(call_stats,call);
refresh_call_stats(call_stats);
gtk_widget_show(call_stats);
}
}
void linphone_gtk_create_in_call_view(LinphoneCall *call){
GtkWidget *call_view=linphone_gtk_create_widget("main","in_call_frame");
GtkWidget *main_window=linphone_gtk_get_main_window ();
@ -217,6 +313,7 @@ void linphone_gtk_create_in_call_view(LinphoneCall *call){
linphone_gtk_enable_hold_button (call,FALSE,TRUE);
linphone_gtk_enable_mute_button(
GTK_BUTTON(linphone_gtk_get_widget(call_view,"incall_mute")),FALSE);
g_signal_connect_swapped(G_OBJECT(linphone_gtk_get_widget(call_view,"quality_indicator")),"button-press-event",(GCallback)linphone_gtk_show_call_stats,call);
}
static void video_button_clicked(GtkWidget *button, LinphoneCall *call){
@ -506,6 +603,7 @@ void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){
GtkWidget *duration=linphone_gtk_get_widget(callview,"in_call_duration");
guint taskid=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(callview),"taskid"));
gboolean in_conf=linphone_call_params_local_conference_mode(linphone_call_get_current_params(call));
GtkWidget *call_stats=(GtkWidget*)g_object_get_data(G_OBJECT(callview),"call_stats");
display_peer_name_in_label(callee,linphone_call_get_remote_address (call));
@ -524,6 +622,7 @@ void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){
linphone_gtk_in_call_view_enable_audio_view(call, !in_conf);
linphone_gtk_in_call_view_show_encryption(call);
if (in_conf) linphone_gtk_set_in_conference(call);
if (call_stats) show_used_codecs(call_stats,call);
}
void linphone_gtk_in_call_view_set_paused(LinphoneCall *call){
@ -557,6 +656,7 @@ void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_m
guint taskid=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(callview),"taskid"));
gboolean in_conf=linphone_call_params_local_conference_mode(linphone_call_get_current_params(call));
if ((callview==NULL) || (status==NULL)) return;
if (error_msg==NULL)
gtk_label_set_markup(GTK_LABEL(status),_("<b>Call ended.</b>"));
else{
@ -579,6 +679,28 @@ void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_m
linphone_gtk_terminate_conference_participant(call);
}
void linphone_gtk_in_call_view_set_transfer_status(LinphoneCall *call,LinphoneCallState cstate){
GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call);
if (callview){
GtkWidget *duration=linphone_gtk_get_widget(callview,"in_call_duration");
const char *transfer_status="unknown";
switch(cstate){
case LinphoneCallOutgoingProgress:
transfer_status=_("Transfer in progress");
break;
case LinphoneCallConnected:
transfer_status=_("Transfer done.");
break;
case LinphoneCallError:
transfer_status=_("Transfer failed.");
break;
default:
break;
}
gtk_label_set_text(GTK_LABEL(duration),transfer_status);
}
}
void linphone_gtk_draw_mute_button(GtkButton *button, gboolean active){
g_object_set_data(G_OBJECT(button),"active",GINT_TO_POINTER(active));
if (active){
@ -653,3 +775,8 @@ void linphone_gtk_enable_hold_button(LinphoneCall *call, gboolean sensitive, gbo
gtk_widget_set_visible(GTK_WIDGET(button),sensitive);
linphone_gtk_draw_hold_button(GTK_BUTTON(button),!holdon);
}
void linphone_gtk_call_statistics_closed(GtkWidget *call_stats){
gtk_widget_destroy(call_stats);
}

View file

@ -97,6 +97,9 @@ void * linphone_gtk_wait(LinphoneCore *lc, void *ctx, LinphoneWaitingState ws, c
void linphone_gtk_show_directory_search(void);
void linphone_gtk_status_icon_set_blinking(gboolean val);
void linphone_gtk_notify(LinphoneCall *call, const char *msg);
/*functions controlling the different views*/
gboolean linphone_gtk_use_in_call_view();
LinphoneCall *linphone_gtk_get_currently_displayed_call(gboolean *is_conf);
@ -107,6 +110,7 @@ void linphone_gtk_in_call_view_update_duration(LinphoneCall *call);
void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_msg);
void linphone_gtk_in_call_view_set_incoming(LinphoneCall *call);
void linphone_gtk_in_call_view_set_paused(LinphoneCall *call);
void linphone_gtk_in_call_view_set_transfer_status(LinphoneCall *call,LinphoneCallState cstate);
void linphone_gtk_mute_clicked(GtkButton *button);
void linphone_gtk_enable_mute_button(GtkButton *button, gboolean sensitive);
void linphone_gtk_enable_hold_button(LinphoneCall *call, gboolean sensitive, gboolean holdon);

View file

@ -206,6 +206,7 @@ static void linphone_gtk_log_file(OrtpLogLevel lev, const char *msg)
case of a crash (which is one of the main reasons we have a
log facility in the first place). */
fprintf(outlog, "[%s] [%s] %s\n", date, lname, msg);
fflush(outlog);
}
}

View file

@ -49,6 +49,7 @@ static gboolean do_login_noprompt(LinphoneProxyConfig *cfg){
tmp=linphone_address_as_string (addr);
do_login(ssctx,tmp,NULL);
linphone_address_destroy(addr);
linphone_gtk_load_identities();
return FALSE;
}
@ -62,14 +63,14 @@ void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg){
int nettype;
const char *passwd=NULL;
if (linphone_core_get_download_bandwidth(lc)==512 &&
linphone_core_get_upload_bandwidth(lc)==512)
nettype=NetworkKindOpticalFiber;
else nettype=NetworkKindAdsl;
gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget(mw,"login_internet_kind")),nettype);
gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget(mw,"internet_kind")),nettype);
//gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget(mw,"internet_kind")),nettype);
if (linphone_gtk_get_ui_config_int("automatic_login",0) ){
g_timeout_add(250,(GSourceFunc)do_login_noprompt,cfg);
return;
@ -88,7 +89,6 @@ void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg){
gtk_widget_hide(linphone_gtk_get_widget(mw,"disconnect_item"));
gtk_widget_hide(linphone_gtk_get_widget(mw,"main_frame"));
gtk_widget_show(linphone_gtk_get_widget(mw,"login_frame"));
gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"main_menu"),FALSE);
gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"options_menu"),FALSE);
str=g_strdup_printf(_("Please enter login information for %s"),linphone_proxy_config_get_domain(cfg));
gtk_label_set_text(GTK_LABEL(label),str);
@ -118,7 +118,6 @@ void linphone_gtk_exit_login_frame(void){
GtkWidget *mw=linphone_gtk_get_main_window();
gtk_widget_show(linphone_gtk_get_widget(mw,"main_frame"));
gtk_widget_hide(linphone_gtk_get_widget(mw,"login_frame"));
gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"main_menu"),TRUE);
gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"options_menu"),TRUE);
gtk_widget_show(linphone_gtk_get_widget(mw,"disconnect_item"));
}

View file

@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#define VIDEOSELFVIEW_DEFAULT 1
#define VIDEOSELFVIEW_DEFAULT 0
#include "linphone.h"
#include "lpconfig.h"
@ -63,17 +63,22 @@ static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const ch
static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl);
static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg);
static void linphone_gtk_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t enabled, const char *token);
static void linphone_gtk_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate);
static gboolean linphone_gtk_auto_answer(LinphoneCall *call);
static void linphone_gtk_status_icon_set_blinking(gboolean val);
void linphone_gtk_status_icon_set_blinking(gboolean val);
void _linphone_gtk_enable_video(gboolean val);
static gboolean verbose=0;
static gboolean auto_answer = 0;
static gchar * addr_to_call = NULL;
static gboolean no_video=FALSE;
static gboolean iconified=FALSE;
static gchar *workingdir=NULL;
static char *progpath=NULL;
gchar *linphone_logfile=NULL;
static gboolean workaround_gtk_entry_chinese_bug=FALSE;
static GOptionEntry linphone_options[]={
{
@ -90,6 +95,13 @@ static GOptionEntry linphone_options[]={
.arg_data = &linphone_logfile,
.description = N_("path to a file to write logs into.")
},
{
.long_name = "no-video",
.short_name = '\0',
.arg = G_OPTION_ARG_NONE,
.arg_data = (gpointer)&no_video,
.description = N_("Start linphone with video disabled.")
},
{
.long_name="iconified",
.short_name= '\0',
@ -225,13 +237,18 @@ static void linphone_gtk_init_liblinphone(const char *config_file,
vtable.refer_received=linphone_gtk_refer_received;
vtable.buddy_info_updated=linphone_gtk_buddy_info_updated;
vtable.call_encryption_changed=linphone_gtk_call_encryption_changed;
vtable.transfer_state_changed=linphone_gtk_transfer_state_changed;
linphone_core_set_user_agent("Linphone", LINPHONE_VERSION);
the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL);
linphone_core_set_user_agent(the_core,"Linphone", LINPHONE_VERSION);
linphone_core_set_waiting_callback(the_core,linphone_gtk_wait,NULL);
linphone_core_set_zrtp_secrets_file(the_core,secrets_file);
g_free(secrets_file);
linphone_core_enable_video(the_core,TRUE,TRUE);
if (no_video) {
_linphone_gtk_enable_video(FALSE);
linphone_gtk_set_ui_config_int("videoselfview",0);
}
}
@ -262,8 +279,10 @@ static void linphone_gtk_configure_window(GtkWidget *w, const char *window_name)
linphone_gtk_visibility_set(shown,window_name,w,TRUE);
if (icon_path) {
GdkPixbuf *pbuf=create_pixbuf(icon_path);
gtk_window_set_icon(GTK_WINDOW(w),pbuf);
g_object_unref(G_OBJECT(pbuf));
if(pbuf != NULL) {
gtk_window_set_icon(GTK_WINDOW(w),pbuf);
g_object_unref(G_OBJECT(pbuf));
}
}
}
@ -332,9 +351,16 @@ GtkWidget *linphone_gtk_create_widget(const char *filename, const char *widget_n
return w;
}
static void entry_unmapped(GtkWidget *entry){
g_message("Entry is unmapped, calling unrealize to workaround chinese bug.");
gtk_widget_unrealize(entry);
}
GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){
GtkBuilder *builder=(GtkBuilder*)g_object_get_data(G_OBJECT(window),"builder");
GtkBuilder *builder;
GObject *w;
if (window==NULL) return NULL;
builder=(GtkBuilder*)g_object_get_data(G_OBJECT(window),"builder");
if (builder==NULL){
g_error("Fail to retrieve builder from window !");
return NULL;
@ -343,6 +369,15 @@ GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){
if (w==NULL){
g_error("No widget named %s found in xml interface.",name);
}
if (workaround_gtk_entry_chinese_bug){
if (strcmp(G_OBJECT_TYPE_NAME(w),"GtkEntry")==0){
if (g_object_get_data(G_OBJECT(w),"entry_bug_workaround")==NULL){
g_object_set_data(G_OBJECT(w),"entry_bug_workaround",GINT_TO_POINTER(1));
g_message("%s is a GtkEntry",name);
g_signal_connect(G_OBJECT(w),"unmap",(GCallback)entry_unmapped,NULL);
}
}
}
return GTK_WIDGET(w);
}
@ -646,10 +681,8 @@ bool_t linphone_gtk_video_enabled(void){
void linphone_gtk_show_main_window(){
GtkWidget *w=linphone_gtk_get_main_window();
LinphoneCore *lc=linphone_gtk_get_core();
if (linphone_gtk_video_enabled()){
linphone_core_enable_video_preview(lc,linphone_gtk_get_ui_config_int("videoselfview",
linphone_core_enable_video_preview(lc,linphone_gtk_get_ui_config_int("videoselfview",
VIDEOSELFVIEW_DEFAULT));
}
gtk_widget_show(w);
gtk_window_present(GTK_WINDOW(w));
}
@ -770,15 +803,12 @@ void linphone_gtk_answer_clicked(GtkWidget *button){
}
}
void linphone_gtk_enable_video(GtkWidget *w){
gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
GtkWidget *selfview_item=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"selfview_item");
void _linphone_gtk_enable_video(gboolean val){
LinphoneVideoPolicy policy={0};
policy.automatically_initiate=policy.automatically_accept=val;
linphone_core_enable_video(linphone_gtk_get_core(),TRUE,TRUE);
linphone_core_set_video_policy(linphone_gtk_get_core(),&policy);
gtk_widget_set_sensitive(selfview_item,val);
if (val){
linphone_core_enable_video_preview(linphone_gtk_get_core(),
linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT));
@ -787,6 +817,12 @@ void linphone_gtk_enable_video(GtkWidget *w){
}
}
void linphone_gtk_enable_video(GtkWidget *w){
gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
//GtkWidget *selfview_item=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"selfview_item");
_linphone_gtk_enable_video(val);
}
void linphone_gtk_enable_self_view(GtkWidget *w){
gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
LinphoneCore *lc=linphone_gtk_get_core();
@ -805,6 +841,18 @@ void linphone_gtk_used_identity_changed(GtkWidget *w){
if (sel) g_free(sel);
}
void on_proxy_refresh_button_clicked(GtkWidget *w){
LinphoneCore *lc=linphone_gtk_get_core();
MSList const *item=linphone_core_get_proxy_config_list(lc);
while (item != NULL) {
LinphoneProxyConfig *lpc=(LinphoneProxyConfig*)item->data;
linphone_proxy_config_edit(lpc);
linphone_proxy_config_done(lpc);
item = item->next;
}
}
static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid){
linphone_gtk_show_friends();
}
@ -983,18 +1031,20 @@ static void make_notification(const char *title, const char *body){
#endif
static void linphone_gtk_notify(LinphoneCall *call, const char *msg){
void linphone_gtk_notify(LinphoneCall *call, const char *msg){
#ifdef HAVE_NOTIFY
if (!notify_is_initted())
if (!notify_init ("Linphone")) ms_error("Libnotify failed to init.");
#endif
if (!call) {
#ifdef HAVE_NOTIFY
if (!notify_notification_show(notify_notification_new("Linphone",msg,NULL
#ifdef HAVE_NOTIFY1
,NULL
#endif
),NULL))
ms_error("Failed to send notification.");
#else
linphone_gtk_show_main_window();
@ -1133,6 +1183,10 @@ static void linphone_gtk_call_encryption_changed(LinphoneCore *lc, LinphoneCall
linphone_gtk_in_call_view_show_encryption(call);
}
static void linphone_gtk_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate){
linphone_gtk_in_call_view_set_transfer_status(call,cstate);
}
static void update_registration_status(LinphoneProxyConfig *cfg, LinphoneRegistrationState rs){
GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
GtkTreeModel *model=gtk_combo_box_get_model(box);
@ -1298,7 +1352,7 @@ static gboolean do_icon_blink(GtkStatusIcon *gi){
#endif
static void linphone_gtk_status_icon_set_blinking(gboolean val){
void linphone_gtk_status_icon_set_blinking(gboolean val){
#ifdef HAVE_GTK_OSX
static gint attention_id;
GtkOSXApplication *theMacApp=(GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
@ -1412,7 +1466,6 @@ static void linphone_gtk_check_menu_items(void){
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(linphone_gtk_get_widget(
linphone_gtk_get_main_window(),"enable_video_item")), video_enabled);
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(selfview_item),selfview);
gtk_widget_set_sensitive(selfview_item,video_enabled);
}
static gboolean linphone_gtk_can_manage_accounts(){
@ -1475,8 +1528,10 @@ static void linphone_gtk_configure_main_window(){
}
if (search_icon){
GdkPixbuf *pbuf=create_pixbuf(search_icon);
gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"directory_search_button_icon")),pbuf);
g_object_unref(G_OBJECT(pbuf));
if(pbuf != NULL) {
gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"directory_search_button_icon")),pbuf);
g_object_unref(G_OBJECT(pbuf));
}
}
if (home){
gchar *tmp;
@ -1734,6 +1789,9 @@ int main(int argc, char *argv[]){
char tmp[128];
snprintf(tmp,sizeof(tmp),"LANG=%s",lang);
_putenv(tmp);
if (strncmp(lang,"zh",2)==0){
workaround_gtk_entry_chinese_bug=TRUE;
}
#else
setenv("LANG",lang,1);
#endif

View file

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="2.18"/>
<!-- interface-naming-policy toplevel-contextual -->
<object class="GtkWindow" id="dummy_conf_window">
<property name="can_focus">False</property>
<child>
@ -318,7 +319,7 @@
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
@ -369,6 +370,7 @@
<object class="GtkProgressBar" id="quality_indicator">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="events">GDK_BUTTON_PRESS_MASK | GDK_STRUCTURE_MASK</property>
<property name="tooltip_text" translatable="yes">Call quality rating</property>
</object>
<packing>
@ -498,7 +500,7 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_action_appearance">False</property>
<property name="label" translatable="yes">Enable video</property>
<property name="label" translatable="yes">Always start video</property>
<property name="use_underline">True</property>
<signal name="toggled" handler="linphone_gtk_enable_video" swapped="no"/>
</object>
@ -518,7 +520,6 @@
<object class="GtkSeparatorMenuItem" id="separatormenuitem2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_action_appearance">False</property>
</object>
</child>
<child>
@ -680,6 +681,8 @@
<property name="invisible_char">●</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
<signal name="activate" handler="linphone_gtk_uri_bar_activate" swapped="no"/>
</object>
<packing>
@ -771,6 +774,8 @@
<property name="invisible_char_set">True</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
<signal name="changed" handler="linphone_gtk_show_friends" swapped="no"/>
</object>
<packing>
@ -838,9 +843,6 @@
<signal name="cursor-changed" handler="linphone_gtk_contact_clicked" swapped="no"/>
<signal name="row-activated" handler="linphone_gtk_contact_activated" swapped="no"/>
<signal name="popup-menu" handler="linphone_gtk_popup_contact_menu" swapped="no"/>
<child internal-child="selection">
<object class="GtkTreeSelection" id="treeview-selection1"/>
</child>
</object>
</child>
</object>
@ -866,6 +868,8 @@
<property name="invisible_char_set">True</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
<signal name="activate" handler="linphone_gtk_directory_search_activate" swapped="no"/>
<signal name="icon-press" handler="linphone_gtk_directory_search_activate" swapped="no"/>
<signal name="focus-in-event" handler="linphone_gtk_directory_search_focus_in" swapped="no"/>
@ -1065,9 +1069,6 @@
<property name="headers_visible">False</property>
<signal name="cursor-changed" handler="linphone_gtk_history_row_selected" swapped="no"/>
<signal name="row-activated" handler="linphone_gtk_history_row_activated" swapped="no"/>
<child internal-child="selection">
<object class="GtkTreeSelection" id="treeview-selection2"/>
</child>
</object>
</child>
</object>
@ -1471,12 +1472,45 @@
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label17">
<object class="GtkHBox" id="hbox7">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">My current identity:</property>
<property name="use_markup">True</property>
<property name="spacing">5</property>
<child>
<object class="GtkLabel" id="label17">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">My current identity:</property>
<property name="use_markup">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="proxy_refresh_button">
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<property name="relief">none</property>
<signal name="clicked" handler="on_proxy_refresh_button_clicked" swapped="no"/>
<child>
<object class="GtkImage" id="image20">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-refresh</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
@ -1573,6 +1607,8 @@
<property name="invisible_char">●</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
</object>
<packing>
<property name="left_attach">1</property>
@ -1587,6 +1623,8 @@
<property name="invisible_char">●</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
</object>
<packing>
<property name="left_attach">1</property>

View file

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="2.18"/>
<!-- interface-naming-policy toplevel-contextual -->
<object class="GtkAdjustment" id="adjustment1">
<property name="lower">500</property>
<property name="upper">3001</property>
@ -47,7 +48,22 @@
<property name="step_increment">1</property>
<property name="page_increment">9.9999999995529656</property>
</object>
<object class="GtkAdjustment" id="adjustment_audio_port">
<object class="GtkAdjustment" id="adjustment_max_audio_port">
<property name="upper">65535</property>
<property name="step_increment">2</property>
<property name="page_increment">10</property>
</object>
<object class="GtkAdjustment" id="adjustment_max_video_port">
<property name="upper">65535</property>
<property name="step_increment">2</property>
<property name="page_increment">10</property>
</object>
<object class="GtkAdjustment" id="adjustment_min_audio_port">
<property name="upper">65535</property>
<property name="step_increment">2</property>
<property name="page_increment">10</property>
</object>
<object class="GtkAdjustment" id="adjustment_min_video_port">
<property name="upper">65535</property>
<property name="step_increment">2</property>
<property name="page_increment">10</property>
@ -58,11 +74,6 @@
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
<object class="GtkAdjustment" id="adjustment_video_port">
<property name="upper">65535</property>
<property name="step_increment">2</property>
<property name="page_increment">10</property>
</object>
<object class="GtkListStore" id="liststore1"/>
<object class="GtkListStore" id="model1">
<columns>
@ -206,10 +217,10 @@
<child>
<object class="GtkCheckButton" id="mtu_set">
<property name="label" translatable="yes">Set Maximum Transmission Unit:</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="linphone_gtk_mtu_set" swapped="no"/>
</object>
@ -225,6 +236,8 @@
<property name="can_focus">True</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
<property name="adjustment">adjustment1</property>
<signal name="value-changed" handler="linphone_gtk_mtu_changed" swapped="no"/>
</object>
@ -244,10 +257,10 @@
<child>
<object class="GtkCheckButton" id="dtmf_sipinfo">
<property name="label" translatable="yes">Send DTMFs as SIP info</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="linphone_gtk_use_sip_info_dtmf_toggled" swapped="no"/>
</object>
@ -260,11 +273,11 @@
<child>
<object class="GtkCheckButton" id="ipv6_enabled">
<property name="label" translatable="yes">Use IPv6 instead of IPv4</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="use_action_appearance">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="linphone_gtk_ipv6_toggled" swapped="no"/>
</object>
@ -312,7 +325,7 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="n_rows">5</property>
<property name="n_rows">6</property>
<property name="n_columns">2</property>
<child>
<object class="GtkComboBox" id="proto_combo">
@ -335,6 +348,8 @@
<property name="invisible_char_set">True</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
<property name="adjustment">adjustment7</property>
</object>
<packing>
@ -372,23 +387,24 @@
<property name="label" translatable="yes">Tunnel</property>
</object>
<packing>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
<property name="top_attach">5</property>
<property name="bottom_attach">6</property>
</packing>
</child>
<child>
<object class="GtkButton" id="tunnel_edit_button">
<property name="label" translatable="yes">edit</property>
<property name="label">gtk-edit</property>
<property name="use_action_appearance">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="linphone_gtk_edit_tunnel" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
<property name="top_attach">5</property>
<property name="bottom_attach">6</property>
</packing>
</child>
<child>
@ -418,13 +434,92 @@
</packing>
</child>
<child>
<object class="GtkSpinButton" id="audio_rtp_port">
<object class="GtkLabel" id="label13">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">DSCP fields</property>
</object>
<packing>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
</packing>
</child>
<child>
<object class="GtkButton" id="dscp_edit_button">
<property name="label">gtk-edit</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
<property name="adjustment">adjustment_audio_port</property>
<property name="numeric">True</property>
<signal name="value-changed" handler="linphone_gtk_audio_port_changed" swapped="no"/>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="linphone_gtk_dscp_edit" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
</packing>
</child>
<child>
<object class="GtkHBox" id="hbox6">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkSpinButton" id="audio_min_rtp_port">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
<property name="adjustment">adjustment_min_audio_port</property>
<property name="numeric">True</property>
<signal name="value-changed" handler="linphone_gtk_min_audio_port_changed" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="audio_max_rtp_port">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
<property name="invisible_char_set">True</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
<property name="adjustment">adjustment_max_audio_port</property>
<property name="numeric">True</property>
<signal name="value-changed" handler="linphone_gtk_max_audio_port_changed" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="fixed_audio_port">
<property name="label" translatable="yes">Fixed</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="linphone_gtk_fixed_audio_port_toggle" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">1</property>
@ -434,13 +529,64 @@
</packing>
</child>
<child>
<object class="GtkSpinButton" id="video_rtp_port">
<object class="GtkHBox" id="hbox17">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
<property name="adjustment">adjustment_video_port</property>
<property name="numeric">True</property>
<signal name="value-changed" handler="linphone_gtk_video_port_changed" swapped="no"/>
<property name="can_focus">False</property>
<child>
<object class="GtkSpinButton" id="video_min_rtp_port">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
<property name="adjustment">adjustment_min_video_port</property>
<property name="numeric">True</property>
<signal name="value-changed" handler="linphone_gtk_min_video_port_changed" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="video_max_rtp_port">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
<property name="invisible_char_set">True</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
<property name="adjustment">adjustment_max_video_port</property>
<property name="numeric">True</property>
<signal name="value-changed" handler="linphone_gtk_max_video_port_changed" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="fixed_video_port">
<property name="label" translatable="yes">Fixed</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="linphone_gtk_fixed_video_port_toggle" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">1</property>
@ -483,10 +629,10 @@
<child>
<object class="GtkRadioButton" id="no_nat">
<property name="label" translatable="yes">Direct connection to the Internet</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="linphone_gtk_no_firewall_toggled" swapped="no"/>
@ -504,10 +650,10 @@
<child>
<object class="GtkRadioButton" id="use_nat_address">
<property name="label" translatable="yes">Behind NAT / Firewall (specify gateway IP below)</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">no_nat</property>
@ -545,6 +691,8 @@
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
<signal name="changed" handler="linphone_gtk_nat_address_changed" swapped="no"/>
</object>
<packing>
@ -568,20 +716,51 @@
</packing>
</child>
<child>
<object class="GtkVBox" id="vbox5">
<object class="GtkRadioButton" id="use_stun">
<property name="label" translatable="yes">Behind NAT / Firewall (use STUN to resolve)</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<property name="group">no_nat</property>
<signal name="toggled" handler="linphone_gtk_use_stun_toggled" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="use_ice">
<property name="label" translatable="yes">Behind NAT / Firewall (use ICE)</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<property name="group">no_nat</property>
<signal name="toggled" handler="linphone_gtk_use_ice_toggled" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkHBox" id="hbox24">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<object class="GtkRadioButton" id="use_stun">
<property name="label" translatable="yes">Behind NAT / Firewall (use STUN to resolve)</property>
<object class="GtkLabel" id="label42">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">no_nat</property>
<signal name="toggled" handler="linphone_gtk_use_stun_toggled" swapped="no"/>
<property name="can_focus">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">Stun server:</property>
<property name="justify">right</property>
</object>
<packing>
<property name="expand">True</property>
@ -590,39 +769,17 @@
</packing>
</child>
<child>
<object class="GtkHBox" id="hbox24">
<object class="GtkEntry" id="stun_server">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<object class="GtkLabel" id="label42">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">Stun server:</property>
<property name="justify">right</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="stun_server">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<signal name="changed" handler="linphone_gtk_stun_server_changed" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<property name="invisible_char">●</property>
<property name="invisible_char_set">True</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
<signal name="changed" handler="linphone_gtk_stun_server_changed" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
@ -632,9 +789,9 @@
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
</object>
@ -719,6 +876,9 @@
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="n_rows">6</property>
<property name="n_columns">2</property>
<child>
<placeholder/>
</child>
<child>
<object class="GtkHBox" id="ring_sound_box">
<property name="visible">True</property>
@ -740,11 +900,11 @@
<child>
<object class="GtkButton" id="play_ring">
<property name="label">gtk-media-play</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="linphone_gtk_play_ring_file" swapped="no"/>
</object>
@ -783,6 +943,8 @@
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
<signal name="editing-done" handler="linphone_gtk_alsa_special_device_changed" swapped="no"/>
</object>
<packing>
@ -915,10 +1077,10 @@
<child>
<object class="GtkCheckButton" id="echo_cancelation">
<property name="label" translatable="yes">Enable echo cancellation</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="linphone_gtk_echo_cancelation_toggled" swapped="no"/>
</object>
@ -929,9 +1091,6 @@
<property name="bottom_attach">6</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
</object>
@ -1134,6 +1293,8 @@
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
<signal name="changed" handler="linphone_gtk_update_my_contact" swapped="no"/>
</object>
<packing>
@ -1172,6 +1333,8 @@
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
<signal name="changed" handler="linphone_gtk_update_my_contact" swapped="no"/>
</object>
<packing>
@ -1189,6 +1352,8 @@
<property name="editable">False</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
</object>
<packing>
<property name="left_attach">1</property>
@ -1245,9 +1410,6 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="treeview-selection1"/>
</child>
</object>
</child>
</object>
@ -1264,10 +1426,10 @@
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<object class="GtkButton" id="wizard">
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="linphone_gtk_display_wizard" swapped="no"/>
<child>
<object class="GtkHBox" id="hbox5">
@ -1311,11 +1473,11 @@
</child>
<child>
<object class="GtkButton" id="add_proxy">
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="linphone_gtk_add_proxy" swapped="no"/>
<child>
<object class="GtkHBox" id="hbox14">
@ -1359,11 +1521,11 @@
</child>
<child>
<object class="GtkButton" id="edit_proxy">
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="linphone_gtk_edit_proxy" swapped="no"/>
<child>
<object class="GtkHBox" id="hbox16">
@ -1407,11 +1569,11 @@
</child>
<child>
<object class="GtkButton" id="remove_proxy">
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="linphone_gtk_remove_proxy" swapped="no"/>
<child>
<object class="GtkHBox" id="hbox7">
@ -1455,9 +1617,9 @@
</child>
<child>
<object class="GtkButton" id="create_phonics">
<property name="use_action_appearance">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="linphone_gtk_create_fonics_account" swapped="no"/>
<child>
<object class="GtkHBox" id="hbox1">
@ -1544,11 +1706,11 @@ virtual network !</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<object class="GtkButton" id="erase_passwords">
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="linphone_gtk_clear_passwords" swapped="no"/>
<child>
<object class="GtkHBox" id="hbox18">
@ -1713,9 +1875,6 @@ virtual network !</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="has_tooltip">True</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="treeview-selection2"/>
</child>
</object>
</child>
</object>
@ -1733,11 +1892,11 @@ virtual network !</property>
<child>
<object class="GtkButton" id="button4">
<property name="label">gtk-go-up</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="linphone_gtk_codec_up" swapped="no"/>
</object>
@ -1750,11 +1909,11 @@ virtual network !</property>
<child>
<object class="GtkButton" id="up_codec">
<property name="label">gtk-go-down</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="linphone_gtk_codec_down" swapped="no"/>
</object>
@ -1766,11 +1925,11 @@ virtual network !</property>
</child>
<child>
<object class="GtkButton" id="enable_codec">
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="linphone_gtk_codec_enable" swapped="no"/>
<child>
<object class="GtkHBox" id="hbox8">
@ -1814,11 +1973,11 @@ virtual network !</property>
</child>
<child>
<object class="GtkButton" id="disable_codec">
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="linphone_gtk_codec_disable" swapped="no"/>
<child>
<object class="GtkHBox" id="hbox9">
@ -1922,6 +2081,8 @@ virtual network !</property>
<property name="tooltip_text" translatable="yes">0 stands for "unlimited"</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
<property name="adjustment">adjustment5</property>
<signal name="value-changed" handler="linphone_gtk_upload_bw_changed" swapped="no"/>
</object>
@ -1931,7 +2092,7 @@ virtual network !</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
<property name="y_options"/>
</packing>
</child>
<child>
@ -1942,6 +2103,8 @@ virtual network !</property>
<property name="tooltip_text" translatable="yes">0 stands for "unlimited"</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
<property name="adjustment">adjustment6</property>
<signal name="value-changed" handler="linphone_gtk_download_bw_changed" swapped="no"/>
</object>
@ -1977,10 +2140,10 @@ virtual network !</property>
<child>
<object class="GtkCheckButton" id="adaptive_rate_control">
<property name="label" translatable="yes">Enable adaptive rate control</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="linphone_gtk_adaptive_rate_control_toggled" swapped="no"/>
@ -1991,7 +2154,7 @@ virtual network !</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
<property name="y_options"/>
</packing>
</child>
<child>
@ -2006,7 +2169,7 @@ virtual network !</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
<property name="y_options"/>
</packing>
</child>
</object>
@ -2132,10 +2295,10 @@ virtual network !</property>
<child>
<object class="GtkCheckButton" id="ui_level">
<property name="label" translatable="yes">Show advanced settings</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="linphone_gtk_ui_level_toggled" swapped="no"/>
</object>
@ -2212,11 +2375,11 @@ virtual network !</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="button5">
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="linphone_gtk_parameters_closed" swapped="no"/>
<child>
<object class="GtkHBox" id="hbox3">

View file

@ -146,14 +146,74 @@ void linphone_gtk_ipv6_toggled(GtkWidget *w){
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)));
}
void linphone_gtk_audio_port_changed(GtkWidget *w){
linphone_core_set_audio_port(linphone_gtk_get_core(),
(gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(w)));
void linphone_gtk_min_audio_port_changed(GtkWidget *w){
GtkWidget *mw = linphone_gtk_get_main_window();
GtkWidget *pb = (GtkWidget *) g_object_get_data(G_OBJECT(mw), "parameters");
GtkSpinButton *min_button = GTK_SPIN_BUTTON(w);
GtkSpinButton *max_button = GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "audio_max_rtp_port"));
gboolean fixed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb, "fixed_audio_port")));
if (fixed) {
linphone_core_set_audio_port(linphone_gtk_get_core(), (gint) gtk_spin_button_get_value(min_button));
gtk_spin_button_set_value(max_button, gtk_spin_button_get_value(min_button));
} else {
gint min_port = gtk_spin_button_get_value(min_button);
gint max_port = gtk_spin_button_get_value(max_button);
if (min_port > max_port) {
gtk_spin_button_set_value(max_button, min_port);
max_port = min_port;
}
linphone_core_set_audio_port_range(linphone_gtk_get_core(), min_port, max_port);
}
}
void linphone_gtk_video_port_changed(GtkWidget *w){
linphone_core_set_video_port(linphone_gtk_get_core(),
(gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(w)));
void linphone_gtk_max_audio_port_changed(GtkWidget *w){
GtkWidget *mw = linphone_gtk_get_main_window();
GtkWidget *pb = (GtkWidget *) g_object_get_data(G_OBJECT(mw), "parameters");
GtkSpinButton *min_button = GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "audio_min_rtp_port"));
GtkSpinButton *max_button = GTK_SPIN_BUTTON(w);
gint min_port = gtk_spin_button_get_value(min_button);
gint max_port = gtk_spin_button_get_value(max_button);
if (max_port < min_port) {
gtk_spin_button_set_value(min_button, max_port);
min_port = max_port;
}
linphone_core_set_audio_port_range(linphone_gtk_get_core(), min_port, max_port);
}
void linphone_gtk_min_video_port_changed(GtkWidget *w){
GtkWidget *mw = linphone_gtk_get_main_window();
GtkWidget *pb = (GtkWidget *) g_object_get_data(G_OBJECT(mw), "parameters");
GtkSpinButton *min_button = GTK_SPIN_BUTTON(w);
GtkSpinButton *max_button = GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "video_max_rtp_port"));
gboolean fixed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb, "fixed_video_port")));
if (fixed) {
linphone_core_set_video_port(linphone_gtk_get_core(), (gint) gtk_spin_button_get_value(min_button));
gtk_spin_button_set_value(max_button, gtk_spin_button_get_value(min_button));
} else {
gint min_port = gtk_spin_button_get_value(min_button);
gint max_port = gtk_spin_button_get_value(max_button);
if (min_port > max_port) {
gtk_spin_button_set_value(max_button, min_port);
max_port = min_port;
}
linphone_core_set_video_port_range(linphone_gtk_get_core(), min_port, max_port);
}
}
void linphone_gtk_max_video_port_changed(GtkWidget *w){
GtkWidget *mw = linphone_gtk_get_main_window();
GtkWidget *pb = (GtkWidget *) g_object_get_data(G_OBJECT(mw), "parameters");
GtkSpinButton *min_button = GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "video_min_rtp_port"));
GtkSpinButton *max_button = GTK_SPIN_BUTTON(w);
gint min_port = gtk_spin_button_get_value(min_button);
gint max_port = gtk_spin_button_get_value(max_button);
if (max_port < min_port) {
gtk_spin_button_set_value(min_button, max_port);
min_port = max_port;
}
linphone_core_set_video_port_range(linphone_gtk_get_core(), min_port, max_port);
}
void linphone_gtk_no_firewall_toggled(GtkWidget *w){
@ -171,6 +231,11 @@ void linphone_gtk_use_stun_toggled(GtkWidget *w){
linphone_core_set_firewall_policy(linphone_gtk_get_core(),LinphonePolicyUseStun);
}
void linphone_gtk_use_ice_toggled(GtkWidget *w){
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)))
linphone_core_set_firewall_policy(linphone_gtk_get_core(),LinphonePolicyUseIce);
}
void linphone_gtk_mtu_changed(GtkWidget *w){
if (GTK_WIDGET_SENSITIVE(w))
linphone_core_set_mtu(linphone_gtk_get_core(),gtk_spin_button_get_value(GTK_SPIN_BUTTON(w)));
@ -872,6 +937,7 @@ static void linphone_gtk_show_media_encryption(GtkWidget *pb){
void linphone_gtk_parameters_destroyed(GtkWidget *pb){
GtkWidget *mw=linphone_gtk_get_main_window();
ms_error("linphone_gtk_paramters_destroyed");
g_object_set_data(G_OBJECT(mw),"parameters",NULL);
}
@ -903,12 +969,15 @@ void linphone_gtk_show_parameters(void){
int mtu;
int ui_advanced;
LCSipTransports tr;
int min_port = 0, max_port = 0;
if (pb==NULL) {
pb=linphone_gtk_create_window("parameters");
g_object_set_data(G_OBJECT(mw),"parameters",pb);
ms_error("linphone_gtk_show_paramters: create");
}else {
gtk_widget_show(pb);
ms_error("linphone_gtk_show_parameters: show");
return;
}
codec_list=linphone_gtk_get_widget(pb,"codec_list");
@ -934,10 +1003,20 @@ void linphone_gtk_show_parameters(void){
tr.udp_port);
}
gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"audio_rtp_port")),
linphone_core_get_audio_port(lc));
gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"video_rtp_port")),
linphone_core_get_video_port(lc));
linphone_core_get_audio_port_range(lc, &min_port, &max_port);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "audio_min_rtp_port")), min_port);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "audio_max_rtp_port")), max_port);
if (min_port == max_port) {
gtk_widget_set_sensitive(GTK_WIDGET(linphone_gtk_get_widget(pb, "audio_max_rtp_port")), FALSE);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb, "fixed_audio_port")), TRUE);
}
linphone_core_get_video_port_range(lc, &min_port, &max_port);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "video_min_rtp_port")), min_port);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "video_max_rtp_port")), max_port);
if (min_port == max_port) {
gtk_widget_set_sensitive(GTK_WIDGET(linphone_gtk_get_widget(pb, "video_max_rtp_port")), FALSE);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb, "fixed_video_port")), TRUE);
}
linphone_gtk_show_media_encryption(pb);
@ -956,6 +1035,9 @@ void linphone_gtk_show_parameters(void){
case LinphonePolicyUseStun:
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"use_stun")),TRUE);
break;
case LinphonePolicyUseIce:
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"use_ice")),TRUE);
break;
}
mtu=linphone_core_get_mtu(lc);
if (mtu<=0){
@ -1024,6 +1106,36 @@ void linphone_gtk_show_parameters(void){
}
void linphone_gtk_fixed_audio_port_toggle(void) {
GtkWidget *mw = linphone_gtk_get_main_window();
GtkWidget *pb = (GtkWidget *) g_object_get_data(G_OBJECT(mw), "parameters");
gboolean fixed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb, "fixed_audio_port")));
gint min_port = gtk_spin_button_get_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "audio_min_rtp_port")));
gint max_port = gtk_spin_button_get_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "audio_max_rtp_port")));
gtk_widget_set_sensitive(GTK_WIDGET(linphone_gtk_get_widget(pb, "audio_max_rtp_port")), !fixed);
if (fixed) {
linphone_core_set_audio_port(linphone_gtk_get_core(), min_port);
} else {
linphone_core_set_audio_port_range(linphone_gtk_get_core(), min_port, max_port);
}
}
void linphone_gtk_fixed_video_port_toggle(void) {
GtkWidget *mw = linphone_gtk_get_main_window();
GtkWidget *pb = (GtkWidget *) g_object_get_data(G_OBJECT(mw), "parameters");
gboolean fixed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb, "fixed_video_port")));
gint min_port = gtk_spin_button_get_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "video_min_rtp_port")));
gint max_port = gtk_spin_button_get_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "video_max_rtp_port")));
gtk_widget_set_sensitive(GTK_WIDGET(linphone_gtk_get_widget(pb, "video_max_rtp_port")), !fixed);
if (fixed) {
linphone_core_set_video_port(linphone_gtk_get_core(), min_port);
} else {
linphone_core_set_video_port_range(linphone_gtk_get_core(), min_port, max_port);
}
}
void linphone_gtk_edit_tunnel_closed(GtkWidget *button){
GtkWidget *pb=gtk_widget_get_toplevel(button);
gtk_widget_destroy(pb);
@ -1077,6 +1189,19 @@ void linphone_gtk_edit_tunnel(GtkButton *button){
} else{
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"radio_disable")),1);
}
{
const char *proxy=NULL,*username=NULL,*password=NULL;
port=0;
linphone_tunnel_get_http_proxy(tunnel,&proxy,&port,&username,&password);
if (proxy)
gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"http_host")),proxy);
if (port>0)
gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(w,"http_port")), port);
if (username)
gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"username")),username);
if (password)
gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"password")),password);
}
g_object_weak_ref(G_OBJECT(w),(GWeakNotify)linphone_gtk_edit_tunnel_closed,w);
gtk_widget_show(w);
@ -1090,12 +1215,19 @@ void linphone_gtk_tunnel_ok(GtkButton *button){
gint port = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(w,"port")));
gboolean enabled=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"radio_enable")));
const char *host=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"host")));
const char *http_host=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"http_host")));
gint http_port = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(w,"http_port")));
const char *username=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"username")));
const char *password=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"password")));
if (tunnel==NULL) return;
if (host && *host=='\0') host=NULL;
if (http_port==0) http_port=8080;
linphone_tunnel_clean_servers(tunnel);
linphone_tunnel_add_server(tunnel,host,port);
linphone_tunnel_enable(tunnel,enabled);
linphone_tunnel_set_http_proxy(tunnel,http_host,http_port,username,password);
gtk_widget_destroy(w);
}
@ -1103,3 +1235,55 @@ void linphone_gtk_tunnel_ok(GtkButton *button){
void linphone_gtk_tunnel_cancel(GtkButton *button){
}
static void show_dscp(GtkWidget *entry, int val){
char tmp[20];
snprintf(tmp,sizeof(tmp),"0x%x",val);
gtk_entry_set_text(GTK_ENTRY(entry),tmp);
}
static int read_dscp(GtkWidget *entry){
const char *val=gtk_entry_get_text(GTK_ENTRY(entry));
const char *begin;
int ret=0;
if (val==NULL || val[0]=='\0') return 0;
/*skip potential 0x*/
begin=strstr(val,"0x");
if (begin) begin+=2;
else begin=val;
if (sscanf(begin,"%x",&ret)==1)
return ret;
return -1;
}
void linphone_gtk_dscp_edit(){
LinphoneCore *lc=linphone_gtk_get_core();
GtkWidget *widget=linphone_gtk_create_window("dscp_settings");
show_dscp(linphone_gtk_get_widget(widget,"sip_dscp"),
linphone_core_get_sip_dscp(lc));
show_dscp(linphone_gtk_get_widget(widget,"audio_dscp"),
linphone_core_get_audio_dscp(lc));
show_dscp(linphone_gtk_get_widget(widget,"video_dscp"),
linphone_core_get_video_dscp(lc));
gtk_widget_show(widget);
}
void linphone_gtk_dscp_edit_response(GtkWidget *dialog, guint response_id){
LinphoneCore *lc=linphone_gtk_get_core();
switch(response_id){
case GTK_RESPONSE_OK:
linphone_core_set_sip_dscp(lc,
read_dscp(linphone_gtk_get_widget(dialog,"sip_dscp")));
linphone_core_set_audio_dscp(lc,
read_dscp(linphone_gtk_get_widget(dialog,"audio_dscp")));
linphone_core_set_video_dscp(lc,
read_dscp(linphone_gtk_get_widget(dialog,"video_dscp")));
break;
default:
break;
}
gtk_widget_destroy(dialog);
}

View file

@ -538,11 +538,6 @@ GtkWidget * linphone_gtk_create_assistant(void){
ok = create_pixbuf(linphone_gtk_get_ui_config("ok","ok.png"));
notok = create_pixbuf(linphone_gtk_get_ui_config("notok","notok.png"));
#if !GLIB_CHECK_VERSION(2, 31, 0)
g_thread_init (NULL);
#endif
gdk_threads_init ();
GtkWidget *p1=create_intro();
GtkWidget *p2=create_setup_signin_choice();
GtkWidget *p31=create_account_informations_page();
@ -605,3 +600,4 @@ GtkWidget * linphone_gtk_create_assistant(void){
return w;
}

View file

@ -1,49 +1,65 @@
<?xml version="1.0"?>
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="2.18"/>
<!-- interface-requires gtk+ 3.0 -->
<!-- interface-naming-policy toplevel-contextual -->
<object class="GtkAdjustment" id="adjustment1">
<property name="value">3600</property>
<property name="upper">100000</property>
<property name="lower">1</property>
<property name="upper">65535</property>
<property name="value">443</property>
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
<object class="GtkAdjustment" id="adjustment2">
<property name="lower">1</property>
<property name="upper">65535</property>
<property name="value">8080</property>
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
<object class="GtkDialog" id="tunnel_config">
<property name="can_focus">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Linphone - Configure a SIP account</property>
<property name="title" translatable="yes">Configure VoIP tunnel</property>
<property name="window_position">center-on-parent</property>
<property name="icon">linphone2.png</property>
<property name="type_hint">dialog</property>
<child internal-child="vbox">
<object class="GtkVBox" id="dialog-vbox2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="spacing">2</property>
<child>
<object class="GtkFrame" id="frame15">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment15">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="left_padding">12</property>
<child>
<object class="GtkVBox" id="vbox11">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<object class="GtkTable" id="table6">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="n_rows">4</property>
<property name="n_columns">2</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkLabel" id="label38">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">Host</property>
<property name="justify">right</property>
@ -55,6 +71,10 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
</object>
<packing>
<property name="left_attach">1</property>
@ -64,6 +84,7 @@
<child>
<object class="GtkLabel" id="label39">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">Port</property>
<property name="justify">right</property>
@ -73,14 +94,35 @@
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="port">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">●</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
<property name="adjustment">adjustment1</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="radio_enable">
<property name="label" translatable="yes">Enable</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="xalign">0</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">radio_disable</property>
</object>
<packing>
<property name="left_attach">1</property>
@ -95,9 +137,10 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="xalign">0</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">radio_enable</property>
</object>
<packing>
<property name="left_attach">1</property>
@ -106,20 +149,6 @@
<property name="bottom_attach">4</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="port">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
<property name="adjustment">adjustment1</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<placeholder/>
</child>
@ -128,6 +157,8 @@
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
@ -138,19 +169,168 @@
<child type="label">
<object class="GtkLabel" id="label42">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">Configure tunnel</property>
<property name="label" translatable="yes">&lt;b&gt;Configure tunnel&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="frame1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="left_padding">12</property>
<child>
<object class="GtkTable" id="table1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="n_rows">4</property>
<property name="n_columns">2</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Host</property>
</object>
</child>
<child>
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Port</property>
</object>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Username</property>
</object>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Password</property>
</object>
<packing>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="http_port">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">●</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
<property name="adjustment">adjustment2</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="http_host">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">●</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="username">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">●</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="password">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="visibility">False</property>
<property name="invisible_char">●</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;Configure http proxy (optional)&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child internal-child="action_area">
<object class="GtkHButtonBox" id="dialog-action_area2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="layout_style">end</property>
<child>
@ -160,8 +340,9 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="linphone_gtk_tunnel_ok"/>
<signal name="clicked" handler="linphone_gtk_tunnel_ok" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
@ -176,8 +357,9 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="linphone_gtk_proxy_cancel"/>
<signal name="clicked" handler="linphone_gtk_proxy_cancel" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
@ -188,8 +370,9 @@
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
<property name="position">2</property>
</packing>
</child>
</object>

View file

@ -21,7 +21,7 @@ package org.linphone.core;
import java.util.Vector;
/**
* Object representing a Call. calls are created using {@link LinphoneCore#invite(LinphoneAddress)} or passed to the application by listener {@link LinphoneCoreListener#callState(LinphoneCore, LinphoneCall, State, String)}
* Object representing a call. Calls are created using {@link LinphoneCore#invite(LinphoneAddress)} or passed to the application by listener {@link LinphoneCoreListener#callState}
*
*/
@ -31,8 +31,8 @@ public interface LinphoneCall {
*
*/
static class State {
@SuppressWarnings("unchecked")
static private Vector values = new Vector();
static private Vector<State> values = new Vector<State>();
private final int mValue;
public final int value() {return mValue;}
@ -119,7 +119,7 @@ public interface LinphoneCall {
*/
public static final State CallReleased = new State(18,"CallReleased");
@SuppressWarnings("unchecked")
private State(int value,String stringValue) {
mValue = value;
values.addElement(this);
@ -159,6 +159,30 @@ public interface LinphoneCall {
* @Return LinphoneCallLog
**/
LinphoneCallLog getCallLog();
/**
* Set the audio statistics associated with this call.
* @return LinphoneCallStats
*/
void setAudioStats(LinphoneCallStats stats);
/**
* Set the video statistics associated with this call.
* @return LinphoneCallStats
*/
void setVideoStats(LinphoneCallStats stats);
/**
* Get the audio statistics associated with this call.
* @return LinphoneCallStats
*/
LinphoneCallStats getAudioStats();
/**
* Get the video statistics associated with this call.
* @return LinphoneCallStats
*/
LinphoneCallStats getVideoStats();
LinphoneCallParams getRemoteParams();
@ -244,4 +268,19 @@ public interface LinphoneCall {
boolean isInConference();
float getPlayVolume();
/**
* Obtain the remote user agent string.
*/
String getRemoteUserAgent();
/**
* Take a photo of currently received video and write it into a jpeg file.
*/
void takeSnapshot(String path);
/**
* Scale the video by factor, and center it using cx,cy point
*/
void zoomVideo(float factor, float cx, float cy);
}

View file

@ -31,14 +31,14 @@ public interface LinphoneCallLog {
*
*/
static class CallStatus {
@SuppressWarnings("unchecked")
static private Vector values = new Vector();
static private Vector<CallStatus> values = new Vector<CallStatus>();
private final int mValue;
private final String mStringValue;
/**
* Call success.
*/
public final static CallStatus Sucess = new CallStatus(0,"Sucess");
public final static CallStatus Success = new CallStatus(0,"Sucess");
/**
* Call aborted.
*/
@ -52,7 +52,7 @@ public interface LinphoneCallLog {
*/
public final static CallStatus Declined = new CallStatus(3,"Declined");
@SuppressWarnings("unchecked")
private CallStatus(int value,String stringValue) {
mValue = value;
values.addElement(this);
@ -94,4 +94,23 @@ public interface LinphoneCallLog {
* @return
*/
public CallStatus getStatus();
/**
* @return a human readble String with the start date/time of the call
*/
public String getStartDate();
/**
* @return a timestamp of the start date/time of the call in milliseconds since January 1st 1970
*/
public long getTimestamp();
/**
* @return the call duration, in seconds
*/
public int getCallDuration();
/**
* @return the call id from signaling
*/
public int getCallId();
}

View file

@ -34,7 +34,7 @@ public interface LinphoneCallParams {
* @param value 0 to disable limitation
*/
void setAudioBandwidth(int value);
/**
* return selected media encryption
* @return MediaEncryption.None MediaEncryption.SRTP or MediaEncryption.ZRTP
@ -45,5 +45,24 @@ public interface LinphoneCallParams {
* @params menc: MediaEncryption.None, MediaEncryption.SRTP or MediaEncryption.ZRTP
*/
void setMediaEnctyption(MediaEncryption menc);
/**
* Get the currently used audio codec
* @return PayloadType or null
*/
PayloadType getUsedAudioCodec();
/**
* Get the currently used video codec
* @return PayloadType or null
*/
PayloadType getUsedVideoCodec();
/**
* Indicate low bandwith mode.
* Configuring a call to low bandwidth mode will result in the core to activate several settings for the call in order to ensure that bitrate usage
* is lowered to the minimum possible. Typically, ptime (packetization time) will be increased, audio codec's output bitrate will be targetted to 20kbit/s provided
* that it is achievable by the codec selected after SDP handshake. Video is automatically disabled.
**/
void enableLowBandwidth(boolean enable);
}

View file

@ -0,0 +1,164 @@
/*
LinPhoneCallStats.java
Copyright (C) 2010 Belledonne Communications, Grenoble, France
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.linphone.core;
import java.util.Vector;
public interface LinphoneCallStats {
static public class MediaType {
static private Vector<MediaType> values = new Vector<MediaType>();
/**
* Audio
*/
static public MediaType Audio = new MediaType(0, "Audio");
/**
* Video
*/
static public MediaType Video = new MediaType(1, "Video");
protected final int mValue;
private final String mStringValue;
private MediaType(int value, String stringValue) {
mValue = value;
values.addElement(this);
mStringValue = stringValue;
}
public static MediaType fromInt(int value) {
for (int i = 0; i < values.size(); i++) {
MediaType mtype = (MediaType) values.elementAt(i);
if (mtype.mValue == value) return mtype;
}
throw new RuntimeException("MediaType not found [" + value + "]");
}
public String toString() {
return mStringValue;
}
}
static public class IceState {
static private Vector<IceState> values = new Vector<IceState>();
/**
* Not activated
*/
static public IceState NotActivated = new IceState(0, "Not activated");
/**
* Failed
*/
static public IceState Failed = new IceState(1, "Failed");
/**
* In progress
*/
static public IceState InProgress = new IceState(2, "In progress");
/**
* Host connection
*/
static public IceState HostConnection = new IceState(3, "Host connection");
/**
* Reflexive connection
*/
static public IceState ReflexiveConnection = new IceState(4, "Reflexive connection");
/**
* Relay connection
*/
static public IceState RelayConnection = new IceState(5, "Relay connection");
protected final int mValue;
private final String mStringValue;
private IceState(int value, String stringValue) {
mValue = value;
values.addElement(this);
mStringValue = stringValue;
}
public static IceState fromInt(int value) {
for (int i = 0; i < values.size(); i++) {
IceState mstate = (IceState) values.elementAt(i);
if (mstate.mValue == value) return mstate;
}
throw new RuntimeException("IceState not found [" + value + "]");
}
public String toString() {
return mStringValue;
}
}
/**
* Get the stats media type
* @return MediaType
*/
public MediaType getMediaType();
/**
* Get the ICE state
*/
public IceState getIceState();
/**
* Get the download bandwidth in kbit/s
* @return The download bandwidth
*/
public float getDownloadBandwidth();
/**
* Get the upload bandwidth in kbit/s
* @return The upload bandwidth
*/
public float getUploadBandwidth();
/**
* Get the sender loss rate since last report
* @return The sender loss rate
*/
public float getSenderLossRate();
/**
* Get the receiver loss rate since last report
* @return The receiver loss rate
*/
public float getReceiverLossRate();
/**
* Get the sender interarrival jitter
* @return The interarrival jitter at last emitted sender report
*/
public float getSenderInterarrivalJitter();
/**
* Get the receiver interarrival jitter
* @return The interarrival jitter at last received receiver report
*/
public float getReceiverInterarrivalJitter();
/**
* Get the round trip delay
* @return The round trip delay in seconds, -1 if the information is not available
*/
public float getRoundTripDelay();
/**
* Get the cumulative number of late packets
* @return The cumulative number of late packets
*/
public long getLatePacketsCumulativeNumber();
/**
* Get the jitter buffer size
* @return The jitter buffer size in milliseconds
*/
public float getJitterBufferSize();
}

View file

@ -0,0 +1,95 @@
package org.linphone.core;
import java.util.Vector;
public interface LinphoneChatMessage {
interface StateListener{
void onLinphoneChatMessageStateChanged(LinphoneChatMessage msg, State state);
}
public static class State {
static private Vector<State> values = new Vector<State>();
private final int mValue;
public final int value() {return mValue;}
private final String mStringValue;
/**
* Idle
*/
public final static State Idle = new State(0,"Idle");
/**
* Incoming call received.
*/
public final static State InProgress = new State(1,"InProgress");
/**
* Outgoing call initialiazed.
*/
public final static State Delivered = new State(2,"Delivered");
/**
* Outgoing call in progress.
*/
public final static State NotDelivered = new State(3,"NotDelivered");
private State(int value,String stringValue) {
mValue = value;
values.addElement(this);
mStringValue=stringValue;
}
public static State fromInt(int value) {
for (int i=0; i<values.size();i++) {
State state = (State) values.elementAt(i);
if (state.mValue == value) return state;
}
throw new RuntimeException("state not found ["+value+"]");
}
public String toString() {
return mStringValue;
}
public int toInt() {
return mValue;
}
}
long getNativePtr();
Object getUserData();
void setUserData();
/**
* get text associated to this LinphoneChatMessage
*
* @return text sent along with the message
*/
String getMessage();
/**
* get peer address associated to this LinphoneChatMessage
*
* @return LinphoneAddress peer address
*/
LinphoneAddress getPeerAddress();
/**
* get from address associated to this LinphoneChatMessage
*
* @return LinphoneAddress from address
*/
LinphoneAddress getFrom();
/**
* Linphone message can carry external body as defined by rfc2017
* @param message #LinphoneChatMessage
* @return return external body url null if not present.
*/
String getExternalBodyUrl();
/**
* Linphone message can carry external body as defined by rfc2017
* @param #LinphoneChatMessage
* @param url ex: access-type=URL; URL="http://www.foo.com/file"
*/
void setExternalBodyUrl(String url);
}

View file

@ -35,5 +35,17 @@ public interface LinphoneChatRoom {
* @param message to be sent
*/
void sendMessage(String message);
/**
* Send a message to peer member of this chat room.
* @param chat message
*/
void sendMessage(LinphoneChatMessage message, LinphoneChatMessage.StateListener listener);
/**
* Create a LinphoneChatMessage
* @param chatRoom chat room associated to the message
* @param message message to send
* @return LinphoneChatMessage object
*/
LinphoneChatMessage createLinphoneChatMessage(String message);
}

View file

@ -18,12 +18,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.linphone.core;
import java.util.List;
import java.util.Vector;
import org.linphone.core.LinphoneCallParams;
/**
* Linphone core main object created by method {@link LinphoneCoreFactory#createLinphoneCore(LinphoneCoreListener, String, String, Object)}.
*
@ -34,8 +30,8 @@ public interface LinphoneCore {
* linphone core states
*/
static public class GlobalState {
@SuppressWarnings("unchecked")
static private Vector values = new Vector();
static private Vector<GlobalState> values = new Vector<GlobalState>();
/**
* Off
*/
@ -56,7 +52,7 @@ public interface LinphoneCore {
private final int mValue;
private final String mStringValue;
@SuppressWarnings("unchecked")
private GlobalState(int value,String stringValue) {
mValue = value;
values.addElement(this);
@ -79,8 +75,8 @@ public interface LinphoneCore {
*
*/
static public class RegistrationState {
@SuppressWarnings("unchecked")
private static Vector values = new Vector();
private static Vector<RegistrationState> values = new Vector<RegistrationState>();
/**
* None
*/
@ -104,7 +100,7 @@ public interface LinphoneCore {
private final int mValue;
private final String mStringValue;
@SuppressWarnings("unchecked")
private RegistrationState(int value,String stringValue) {
mValue = value;
values.addElement(this);
@ -127,8 +123,8 @@ public interface LinphoneCore {
*
*/
static public class FirewallPolicy {
@SuppressWarnings("unchecked")
static private Vector values = new Vector();
static private Vector<FirewallPolicy> values = new Vector<FirewallPolicy>();
/**
* No firewall is assumed.
*/
@ -141,11 +137,15 @@ public interface LinphoneCore {
* Use stun server to discover RTP addresses and ports.
*/
static public FirewallPolicy UseStun = new FirewallPolicy(2,"UseStun");
/**
* Use ICE.
*/
static public FirewallPolicy UseIce = new FirewallPolicy(3,"UseIce");
private final int mValue;
private final String mStringValue;
@SuppressWarnings("unchecked")
private FirewallPolicy(int value,String stringValue) {
mValue = value;
values.addElement(this);
@ -181,30 +181,33 @@ public interface LinphoneCore {
this.tcp = t.tcp;
this.tls = t.tls;
}
public String toString() {
return "udp["+udp+"] tcp["+tcp+"] tls["+tls+"]";
}
}
/**
* Media (RTP) encryption enum-like.
*
*/
static public class MediaEncryption {
@SuppressWarnings("unchecked")
static private Vector values = new Vector();
static public final class MediaEncryption {
static private Vector<MediaEncryption> values = new Vector<MediaEncryption>();
/**
* None
*/
static public MediaEncryption None = new MediaEncryption(0,"None");
static public final MediaEncryption None = new MediaEncryption(0,"None");
/**
* SRTP
*/
static public MediaEncryption SRTP = new MediaEncryption(1,"SRTP");
static public final MediaEncryption SRTP = new MediaEncryption(1,"SRTP");
/**
* ZRTP
*/
static public MediaEncryption ZRTP = new MediaEncryption(2,"ZRTP");
static public final MediaEncryption ZRTP = new MediaEncryption(2,"ZRTP");
protected final int mValue;
private final String mStringValue;
@SuppressWarnings("unchecked")
private MediaEncryption(int value,String stringValue) {
mValue = value;
values.addElement(this);
@ -226,28 +229,35 @@ public interface LinphoneCore {
* EC Calibrator Status
*/
static public class EcCalibratorStatus {
@SuppressWarnings("unchecked")
static private Vector values = new Vector();
static private Vector<EcCalibratorStatus> values = new Vector<EcCalibratorStatus>();
/* Do not change the values of these constants or the strings associated with them to prevent breaking
the collection of echo canceller calibration results during the wizard! */
public static final int IN_PROGRESS_STATUS=0;
public static final int DONE_STATUS=1;
public static final int FAILED_STATUS=2;
public static final int DONE_NO_ECHO_STATUS=3;
/**
* Calibration in progress
*/
static public EcCalibratorStatus InProgress = new EcCalibratorStatus(IN_PROGRESS_STATUS,"InProgress");
static public EcCalibratorStatus InProgress = new EcCalibratorStatus(IN_PROGRESS_STATUS,"InProgress");
/**
* Calibration done
* Calibration done that produced an echo delay measure
*/
static public EcCalibratorStatus Done = new EcCalibratorStatus(DONE_STATUS,"Done");
static public EcCalibratorStatus Done = new EcCalibratorStatus(DONE_STATUS,"Done");
/**
* Calibration in progress
* Calibration failed
*/
static public EcCalibratorStatus Failed = new EcCalibratorStatus(FAILED_STATUS,"Failed");
/**
* Calibration done with no echo detected
*/
static public EcCalibratorStatus DoneNoEcho = new EcCalibratorStatus(DONE_NO_ECHO_STATUS, "DoneNoEcho");
private final int mValue;
private final String mStringValue;
@SuppressWarnings("unchecked")
private EcCalibratorStatus(int value,String stringValue) {
mValue = value;
values.addElement(this);
@ -268,6 +278,12 @@ public interface LinphoneCore {
return mValue;
}
}
/**
* Set the context of creation of the LinphoneCore.
*/
public void setContext(Object context);
/**
* clear all added proxy configs
*/
@ -367,7 +383,7 @@ public interface LinphoneCore {
* Accept an incoming call.
*
* Basically the application is notified of incoming calls within the
* {@link LinphoneCoreListener#inviteReceived(LinphoneCore, String)} listener.
* {@link LinphoneCoreListener#callState} listener method.
* The application can later respond positively to the call using
* this method.
* @throws LinphoneCoreException
@ -378,7 +394,7 @@ public interface LinphoneCore {
* Accept an incoming call.
*
* Basically the application is notified of incoming calls within the
* {@link LinphoneCoreListener#inviteReceived(LinphoneCore, String)} listener.
* {@link LinphoneCoreListener#callState} listener method.
* The application can later respond positively to the call using
* this method.
* @throws LinphoneCoreException
@ -389,7 +405,7 @@ public interface LinphoneCore {
* Accept call modifications initiated by other end.
*
* Basically the application is notified of incoming calls within the
* {@link LinphoneCoreListener#inviteReceived(LinphoneCore, String)} listener.
* {@link LinphoneCoreListener#callState} listener method.
* The application can later respond positively to the call using
* this method.
* @throws LinphoneCoreException
@ -401,18 +417,19 @@ public interface LinphoneCore {
* Prevent LinphoneCore from performing an automatic answer
*
* Basically the application is notified of incoming calls within the
* {@link LinphoneCoreListener#inviteReceived(LinphoneCore, String)} listener.
* {@link LinphoneCoreListener#callState} listener method.
* The application can later respond positively to the call using
* this method.
* @throws LinphoneCoreException
*/
public void deferCallUpdate(LinphoneCall aCall) throws LinphoneCoreException;
public void startRinging();
/**
* @return a list of LinphoneCallLog
*/
@SuppressWarnings("unchecked")
public List getCallLogs();
public LinphoneCallLog[] getCallLogs();
/**
* This method is called by the application to notify the Linphone core library when network is reachable.
@ -463,7 +480,7 @@ public interface LinphoneCore {
* @return true is mic is muted
*/
boolean isMicMuted();
/**
* Initiate a dtmf signal if in call
* @param number
@ -486,11 +503,17 @@ public interface LinphoneCore {
*/
void clearCallLogs();
/***
* get payload type from mime type an clock rate
* get payload type from mime type, clock rate, and number of channels.-
*
* return null if not found
*/
PayloadType findPayloadType(String mime,int clockRate);
PayloadType findPayloadType(String mime, int clockRate, int channels);
/***
* get payload type from mime type and clock rate..
*
* return null if not found
*/
PayloadType findPayloadType(String mime, int clockRate);
/**
* not implemented yet
* @param pt
@ -509,7 +532,7 @@ public interface LinphoneCore {
*/
boolean isEchoCancellationEnabled();
/**
* Get echo limiter status (another method of doing echo suppressionn, more brute force)
* Get echo limiter status (another method of doing echo suppression, more brute force)
* @return true if echo limiter is enabled
*/
boolean isEchoLimiterEnabled();
@ -522,13 +545,13 @@ public interface LinphoneCore {
*/
Transports getSignalingTransportPorts();
/**
* not implemented
* Activates or deactivates the speaker.
* @param value
*/
void enableSpeaker(boolean value);
/**
* not implemented
* @return
* Tells whether the speaker is activated.
* @return true if speaker enabled, false otherwise
*/
boolean isSpeakerEnabled();
/**
@ -672,6 +695,10 @@ public interface LinphoneCore {
void startEchoCalibration(Object data) throws LinphoneCoreException;
void enableIpv6(boolean enable);
/**
* @deprecated
* @param i
*/
void adjustSoftwareVolume(int i);
boolean pauseCall(LinphoneCall call);
@ -693,7 +720,7 @@ public interface LinphoneCore {
int getConferenceSize();
void terminateAllCalls();
@SuppressWarnings("unchecked") List getCalls();
LinphoneCall[] getCalls();
int getCallsNb();
@ -744,8 +771,8 @@ public interface LinphoneCore {
void setPlayFile(String path);
void tunnelEnable(boolean enable);
void tunnelAutoDetect();
void tunnelEnableLogs(boolean enable);
void tunnelCleanServers();
void tunnelSetHttpProxy(String proxy_host, int port, String username, String password);
/**
* @param host tunnel server ip address
* @param port tunnel server tls port, recommended value is 443
@ -761,4 +788,90 @@ public interface LinphoneCore {
void setVideoPolicy(boolean autoInitiate, boolean autoAccept);
void setUserAgent(String name, String version);
void setCpuCount(int count);
/**
* remove a call log
*/
public void removeCallLog(LinphoneCallLog log);
/**
* @return count of missed calls
*/
public int getMissedCallsCount();
/**
* Set missed calls count to zero
*/
public void resetMissedCallsCount();
/**
* re-initiates registration if network is up.
*/
public void refreshRegisters();
/**
* return the version code of linphone core
*/
public String getVersion();
/**
* remove a linphone friend from linphone core and linphonerc
*/
void removeFriend(LinphoneFriend lf);
/**
* return a linphone friend (if exists) that matches the sip address
*/
LinphoneFriend findFriendByAddress(String sipUri);
/**
* Sets the UDP port used for audio streaming.
**/
void setAudioPort(int port);
/**
* Sets the UDP port range from which to randomly select the port used for audio streaming.
*/
void setAudioPortRange(int minPort, int maxPort);
/**
* Sets the UDP port used for video streaming.
**/
void setVideoPort(int port);
/**
* Sets the UDP port range from which to randomly select the port used for video streaming.
*/
void setVideoPortRange(int minPort, int maxPort);
/**
* Set the incoming call timeout in seconds.
* If an incoming call isn't answered for this timeout period, it is
* automatically declined.
**/
void setIncomingTimeout(int timeout);
/**
* Set the call timeout in seconds.
* Once this time is elapsed (ringing included), the call is automatically hung up.
**/
void setInCallTimeout(int timeout);
void setMicrophoneGain(float gain);
/**
* Set username and display name to use if no LinphoneProxyConfig configured
*/
void setPrimaryContact(String displayName, String username);
/**
* Enable/Disable the use of SIP INFO for DTMFs
*/
void setUseSipInfoForDtmfs(boolean use);
/**
* Enable/Disable the use of inband DTMFs
*/
void setUseRfc2833ForDtmfs(boolean use);
}

View file

@ -36,11 +36,11 @@ abstract public class LinphoneCoreFactory {
factoryName = className;
}
@SuppressWarnings("unchecked")
public static final synchronized LinphoneCoreFactory instance() {
try {
if (theLinphoneCoreFactory == null) {
Class lFactoryClass = Class.forName(factoryName);
Class<?> lFactoryClass = Class.forName(factoryName);
theLinphoneCoreFactory = (LinphoneCoreFactory) lFactoryClass.newInstance();
}
} catch (Exception e) {

View file

@ -24,27 +24,10 @@ package org.linphone.core;
*This interface holds all callbacks that the application should implement. None is mandatory.
*/
public interface LinphoneCoreListener {
/**< Notifies the application that it should show up
* @return */
void show(LinphoneCore lc);
/**< Ask the application some authentication information
* @return */
void authInfoRequested(LinphoneCore lc,String realm,String username);
/**< Callback that notifies various events with human readable text.
* @return */
void displayStatus(LinphoneCore lc,String message);
/**< Callback to display a message to the user
* @return */
void displayMessage(LinphoneCore lc,String message);
/** Callback to display a warning to the user
* @return */
void displayWarning(LinphoneCore lc,String message);
/** General State notification
* @param state LinphoneCore.State
* @return
@ -57,6 +40,11 @@ public interface LinphoneCoreListener {
* */
void callState(LinphoneCore lc, LinphoneCall call, LinphoneCall.State cstate,String message);
/**
* Call stats notification
*/
void callStatsUpdated(LinphoneCore lc, LinphoneCall call, LinphoneCallStats stats);
/**
* Callback to display change in encryption state.
* @param encrypted true if all streams of the call are encrypted
@ -93,8 +81,24 @@ public interface LinphoneCoreListener {
* @param from LinphoneAddress from
* @param message incoming message
*/
void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from,String message);
void textReceived(LinphoneCore lc, LinphoneChatRoom cr, LinphoneAddress from, String message);
/**
* invoked when a new linphone chat message is received
* @param lc LinphoneCore
* @param room LinphoneChatRoom involved in this conversation. Can be be created by the framework in case the from is not present in any chat room.
* @param message incoming linphone chat message message
*/
void messageReceived(LinphoneCore lc, LinphoneChatRoom cr, LinphoneChatMessage message);
/**
* invoked when a new dtmf is received
* @param lc LinphoneCore
* @param call LinphoneCall involved in the dtmf sending
* @param dtmf value of the dtmf sent
*/
void dtmfReceived(LinphoneCore lc, LinphoneCall call, int dtmf);
/**
* Invoked when echo cancalation calibration is completed
* @param lc LinphoneCore
@ -103,5 +107,31 @@ public interface LinphoneCoreListener {
* @param data
*/
void ecCalibrationStatus(LinphoneCore lc,LinphoneCore.EcCalibratorStatus status, int delay_ms, Object data);
/**
* Report Notified message received for this identity.
* @param lc LinphoneCore
* @param call LinphoneCall in case the notify is part of a dialog, may be null
* @param from LinphoneAddress the message comes from
* @param event String the raw body of the notify event.
*
*/
void notifyReceived(LinphoneCore lc, LinphoneCall call, LinphoneAddress from, byte[] event);
/**< @Deprecated Notifies the application that it should show up
* @return */
void show(LinphoneCore lc);
/**< @Deprecated Callback that notifies various events with human readable text.
* @return */
void displayStatus(LinphoneCore lc,String message);
/**< @Deprecated Callback to display a message to the user
* @return */
void displayMessage(LinphoneCore lc,String message);
/** @Deprecated Callback to display a warning to the user
* @return */
void displayWarning(LinphoneCore lc,String message);
}

View file

@ -36,8 +36,8 @@ public interface LinphoneFriend {
*/
static class SubscribePolicy {
@SuppressWarnings("unchecked")
static private Vector values = new Vector();
static private Vector<SubscribePolicy> values = new Vector<SubscribePolicy>();
protected final int mValue;
private final String mStringValue;
/**
@ -54,7 +54,7 @@ public interface LinphoneFriend {
*/
public final static SubscribePolicy SPAccept = new SubscribePolicy(2,"SPAccept");
@SuppressWarnings("unchecked")
private SubscribePolicy(int value,String stringValue) {
mValue = value;
values.addElement(this);
@ -123,5 +123,8 @@ public interface LinphoneFriend {
*/
String toString();
/**
* Return the native pointer for this object
*/
long getNativePtr();
}

View file

@ -133,4 +133,16 @@ public interface LinphoneProxyConfig {
* @param delay expiration time in seconds
*/
void setExpires(int delay);
/**
* Sets parameters for the contact
* @param parameters to add
*/
public void setContactParameters(String params);
/**
* Return the international prefix for the given country
* @param country iso code
*/
public int lookupCCCFromIso(String iso);
}

View file

@ -27,8 +27,8 @@ import java.util.Vector;
*/
public class OnlineStatus {
@SuppressWarnings("unchecked")
static private Vector values = new Vector();
static private Vector<OnlineStatus> values = new Vector<OnlineStatus>();
/**
* Offline
*/
@ -77,7 +77,7 @@ public class OnlineStatus {
protected final int mValue;
private final String mStringValue;
@SuppressWarnings("unchecked")
private OnlineStatus(int value,String stringValue) {
mValue = value;
values.addElement(this);

View file

@ -21,4 +21,6 @@ package org.linphone.core;
public interface PayloadType {
String getMime();
int getRate();
}

View file

@ -41,14 +41,18 @@ Liblinphone is a high level library for bringing SIP video call functionnality i
LibLinphone package is organized in submodules.
<ul>
<li><a href="#proxy">Managing proxies</a>
<li><a href="#proxy">Managing proxies</a></li>
</ul>
<ul>
<li><a href="#buddy">Managing Buddies and buddy list and presence</a>
<li><a href="#buddy">Managing Buddies and buddy list and presence</a></li>
</ul>
<ul>
<li><a href="#chat">Chat room and Messaging</a>
<li><a href="#chat">Chat room and Messaging</a></li>
</ul>
<ul>
<li><a href="#echo">Sound and echo cancellation settings</a></li>
</ul>
<h2>Related Documentation</h2>
@ -189,6 +193,109 @@ from a peer sip uri.
System.out.println("Message ["+message+"] received from ["+from+"] ");
}
</code>
</pre>
<h3>
<a name="echo">Sound and echo cancellation settings</a>
</h3>
<b>Sound levels</b>
<br>
It is possible to tune the microphone input gain and speaker/receiver output gain by setting parameters into the linphonerc factory config file loaded when instanciating the {@link org.linphone.core.LinphoneCore LinphoneCore}. These gains are liblinphone's internal software gains and are unrelated to volume levels managed by the operating system. For example: <br>
<pre>
<code>
[sound]
#set the speaker or receiver playback gain in dbm0 (0 db = no change).
playback_gain_db=-3
#set the microphone gain in linear scale:
mic_gain=0.1
</code>
</pre>
<br>
<b>Echo cancellation</b>
<br>
On Android devices, there are two kind of situations regarding echo cancellation:<br>
<ul>
<li>The new (after 2011) high end devices, on which manufacturers often include a hardware echo cancellation. If available, liblinphone will make use of it and no software correction is required. Source file linphone-android/submodules/linphone/mediastreamer2/java/src/org/linphone/mediastream/video/capture/hwconf/Hacks.java contains a method hasBuiltInEchoCanceller() that returns true if an hardware echo canceller is available, based on device model identifier. The current list is incomplete.</li>
<li>The other devices, for which it is recommended to enable the software echo canceller of liblinphone.</li>
</ul>
<br>
<b>Echo calibration tool</b>
<br>
The echo calibration procedure is a five second audio test which consists in playing small beeps to the receiver while the microphone input is recorded.
If the device is subject to echo (or doesn't have hardware echo cancellation), then beeps recorded by the microphone will be detected and a measurement of echo delay can be computed.
Echo calibration procedure can be started by calling {@link org.linphone.core.LinphoneCore#startEchoCalibration LinphoneCore.startEchoCalibration}.
The measurement of the echo delay is important to save CPU computations by restricting the temporal area where the software echo canceller has to perform.
<br>
<br>
<b>Echo limiter</b>
<br>
The echo limiter is a liblinphone algorithm to clear out echo with a brute force method. It consists in cutting down the microphone signal when active signal is played by the speaker/receiver, to prevent voice to feed back into the microphone. This algorithm has disadvantages compared to the hardware or software echo cancellers because the remote user will be not hear any background noise when speaking, which is confusing. As a result the echo limiter method shall be used only under situation where echo canceller can't perform, that is loud signals with heavy saturations, which usually happens when using the device in speaker mode. Echo limiter can be enabled or disabled during a call with {@link org.linphone.core.LinphoneCall#enableEchoLimiter LinphoneCall.enableEchoLimiter()}.
<br>
<br>
<b>Recommandations to applications for optimal audio performance</b>
<br>
<br>
In order to benefit from the best echo cancellation solution, we recommend applications to run the following procedure, when they are run for the first time:<br>
<ul>
<li>Use the Hacks.hasBuiltInEchoCanceller() method to first check if the device has hardware echo cancellation. If yes, then echo canceller must be turned off.</li>
<li>If hasBuiltInEchoCanceller() returned false, then it is recommended to run the echo calibration procedure. This procedure can produce the following results:
<ul>
<li>success with no echo detected: it means that the device has an hardware echo canceller but is not (yet) referenced in our list of devices having hardware echo cancellation. Echo cancellation should be disabled with {@link org.linphone.core.LinphoneCore#enableEchoCancellation LinphoneCore.enableEchoCancellation(false)}</li>
<li>success with an estimated echo delay: the echo canceller should be enabled.</li>
<li>failure: it means that some echo has been detected but the delay could not be estimated. In this case it is recommended to activate the echo canceller. A typical for android minimum delay of 250 ms will be used as default.</li>
</ul>
</li>
</ul>
During calls, the echo limiter should be disabled while using the receiver, but enabled while using the hands-free speaker. It is also recommended to disable echo canceller while using the echo limiter, because the first one would be useless. Therefore you should have the following situations:
<ul>
<li>While using the receiver</li>
<ul>
<li>Echo canceller enabled, unless the device has hardware echo cancellation</li>
<li>Echo limiter disabled</li>
</ul>
<li>While using the hands-free speaker</li>
<ul>
<li>Echo canceller disabled</li>
<li>Echo limiter enabled, unless the device has hardware echo cancellation.</li>
</ul>
</li>
</ul>
Controlling echo limiter during a call has to be done with {@link org.linphone.core.LinphoneCall#enableEchoLimiter LinphoneCall.enableEchoLimiter()}.
Controlling echo canceller during a call has to be done with {@link org.linphone.core.LinphoneCall#enableEchoCancellation LinphoneCall.enableEchoCancellation()}.
<br><br>
<b>Echo limiter settings</b>
<br>
Echo limiter requires settings to be defined in linphonerc factory config file for correction operation.
Typical settings are:
<pre>
<code>
[sound]
el_type=mic
#speaker energy threshold (linear scale) above which echo limiter decreases mic gain.
el_thres=0.03
#attenuation applied to mic gain (linear scale)
el_force=100000
#minimum time in milliseconds during which attenuation is applied
el_sustain=600
#double talk detection: threshold of ratio mic-energy/speaker-energy above which mic input is sent anyway.
el_transmit_thres=1.7
#noise gate floorgain (gain applied when no voice is detected).
ng_floorgain=0.01
</code>
</pre>
Up to date settings must be found from linphone-android/res/raw/linphonerc file.
<br>
</body>
</html>

View file

@ -0,0 +1,100 @@
/*
LinphoneAddressImpl.java
Copyright (C) 2010 Belledonne Communications, Grenoble, France
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.linphone.core;
public class LinphoneAddressImpl implements LinphoneAddress {
protected final long nativePtr;
boolean ownPtr = false;
private native long newLinphoneAddressImpl(String uri,String displayName);
private native void delete(long ptr);
private native String getDisplayName(long ptr);
private native String getUserName(long ptr);
private native String getDomain(long ptr);
private native String toUri(long ptr);
private native void setDisplayName(long ptr,String name);
private native String toString(long ptr);
protected LinphoneAddressImpl(String identity) {
nativePtr = newLinphoneAddressImpl(identity, null);
}
protected LinphoneAddressImpl(String username,String domain,String displayName) {
nativePtr = newLinphoneAddressImpl("sip:"+username+"@"+domain, displayName);
}
protected LinphoneAddressImpl(long aNativePtr,boolean javaOwnPtr) {
nativePtr = aNativePtr;
ownPtr=javaOwnPtr;
}
protected LinphoneAddressImpl(long aNativePtr) {
nativePtr = aNativePtr;
ownPtr=false;
}
protected void finalize() throws Throwable {
if (ownPtr) delete(nativePtr);
}
public String getDisplayName() {
return getDisplayName(nativePtr);
}
public String getDomain() {
return getDomain(nativePtr);
}
public String getUserName() {
return getUserName(nativePtr);
}
public String toString() {
return toString(nativePtr);
}
public String toUri() {
return toUri(nativePtr);
}
public void setDisplayName(String name) {
setDisplayName(nativePtr,name);
}
public String asString() {
return toString();
}
public String asStringUriOnly() {
return toUri(nativePtr);
}
public void clean() {
throw new RuntimeException("Not implemented");
}
public String getPort() {
return String.valueOf(getPortInt());
}
public int getPortInt() {
return getPortInt();
}
public void setDomain(String domain) {
throw new RuntimeException("Not implemented");
}
public void setPort(String port) {
throw new RuntimeException("Not implemented");
}
public void setPortInt(int port) {
throw new RuntimeException("Not implemented");
}
public void setUserName(String username) {
throw new RuntimeException("Not implemented");
}
}

View file

@ -0,0 +1,55 @@
/*
LinphoneAuthInfoImpl.java
Copyright (C) 2010 Belledonne Communications, Grenoble, France
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.linphone.core;
class LinphoneAuthInfoImpl implements LinphoneAuthInfo {
protected final long nativePtr;
private native long newLinphoneAuthInfo(String username, String userid, String passwd, String ha1,String realm);
private native void delete(long ptr);
protected LinphoneAuthInfoImpl(String username,String password, String realm) {
nativePtr = newLinphoneAuthInfo(username,"",password,"","");
}
protected void finalize() throws Throwable {
delete(nativePtr);
}
public String getPassword() {
// TODO Auto-generated method stub
throw new RuntimeException("not implemeneted yet");
}
public String getRealm() {
// TODO Auto-generated method stub
throw new RuntimeException("not implemeneted yet");
}
public String getUsername() {
// TODO Auto-generated method stub
throw new RuntimeException("not implemeneted yet");
}
public void setPassword(String password) {
// TODO Auto-generated method stub
throw new RuntimeException("not implemeneted yet");
}
public void setRealm(String realm) {
// TODO Auto-generated method stub
throw new RuntimeException("not implemeneted yet");
}
public void setUsername(String username) {
// TODO Auto-generated method stub
throw new RuntimeException("not implemeneted yet");
}
}

View file

@ -0,0 +1,192 @@
/*
LinphoneCallImpl.java
Copyright (C) 2010 Belledonne Communications, Grenoble, France
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.linphone.core;
class LinphoneCallImpl implements LinphoneCall {
protected final long nativePtr;
boolean ownPtr = false;
private LinphoneCallStats audioStats;
private LinphoneCallStats videoStats;
native private void finalize(long nativePtr);
native private long getCallLog(long nativePtr);
private native boolean isIncoming(long nativePtr);
native private long getRemoteAddress(long nativePtr);
native private int getState(long nativePtr);
private native long getCurrentParamsCopy(long nativePtr);
private native long getRemoteParams(long nativePtr);
private native void enableCamera(long nativePtr, boolean enabled);
private native boolean cameraEnabled(long nativePtr);
private native void enableEchoCancellation(long nativePtr,boolean enable);
private native boolean isEchoCancellationEnabled(long nativePtr) ;
private native void enableEchoLimiter(long nativePtr,boolean enable);
private native boolean isEchoLimiterEnabled(long nativePtr);
private native Object getReplacedCall(long nativePtr);
private native int getDuration(long nativePtr);
private native float getCurrentQuality(long nativePtr);
private native float getAverageQuality(long nativePtr);
/*
* This method must always be called from JNI, nothing else.
*/
private LinphoneCallImpl(long aNativePtr) {
nativePtr = aNativePtr;
}
protected void finalize() throws Throwable {
finalize(nativePtr);
}
public LinphoneCallLog getCallLog() {
long lNativePtr = getCallLog(nativePtr);
if (lNativePtr!=0) {
return new LinphoneCallLogImpl(lNativePtr);
} else {
return null;
}
}
public void setAudioStats(LinphoneCallStats stats) {
audioStats = stats;
}
public void setVideoStats(LinphoneCallStats stats) {
videoStats = stats;
}
public LinphoneCallStats getAudioStats() {
return audioStats;
}
public LinphoneCallStats getVideoStats() {
return videoStats;
}
public CallDirection getDirection() {
return isIncoming(nativePtr)?CallDirection.Incoming:CallDirection.Outgoing;
}
public LinphoneAddress getRemoteAddress() {
long lNativePtr = getRemoteAddress(nativePtr);
if (lNativePtr!=0) {
return new LinphoneAddressImpl(lNativePtr);
} else {
return null;
}
}
public State getState() {
return LinphoneCall.State.fromInt(getState(nativePtr));
}
public LinphoneCallParams getCurrentParamsCopy() {
return new LinphoneCallParamsImpl(getCurrentParamsCopy(nativePtr));
}
public LinphoneCallParams getRemoteParams() {
long remoteParamsPtr = getRemoteParams(nativePtr);
if (remoteParamsPtr == 0) {
return null;
}
return new LinphoneCallParamsImpl(remoteParamsPtr);
}
public void enableCamera(boolean enabled) {
enableCamera(nativePtr, enabled);
}
public boolean cameraEnabled() {
return cameraEnabled(nativePtr);
}
@Override
public boolean equals(Object call) {
if (this == call) return true;
if (call == null) return false;
if (!(call instanceof LinphoneCallImpl)) return false;
return nativePtr == ((LinphoneCallImpl)call).nativePtr;
}
@Override
public int hashCode() {
int result = 17;
result = 31 * result + (int) (nativePtr ^ (nativePtr >>> 32));
return result;
}
public void enableEchoCancellation(boolean enable) {
enableEchoCancellation(nativePtr,enable);
}
public boolean isEchoCancellationEnabled() {
return isEchoCancellationEnabled(nativePtr);
}
public void enableEchoLimiter(boolean enable) {
enableEchoLimiter(nativePtr,enable);
}
public boolean isEchoLimiterEnabled() {
return isEchoLimiterEnabled(nativePtr);
}
public LinphoneCall getReplacedCall(){
return (LinphoneCall)getReplacedCall(nativePtr);
}
public int getDuration() {
return getDuration(nativePtr);
}
public float getAverageQuality() {
return getAverageQuality(nativePtr);
}
public float getCurrentQuality() {
return getCurrentQuality(nativePtr);
}
private native String getAuthenticationToken(long nativePtr);
public String getAuthenticationToken(){
return getAuthenticationToken(nativePtr);
}
private native boolean isAuthenticationTokenVerified(long nativePtr);
public boolean isAuthenticationTokenVerified(){
return isAuthenticationTokenVerified(nativePtr);
}
private native void setAuthenticationTokenVerified(long nativePtr, boolean verified);
public void setAuthenticationTokenVerified(boolean verified){
setAuthenticationTokenVerified(nativePtr, verified);
}
public boolean isInConference() {
LinphoneCallParamsImpl params = new LinphoneCallParamsImpl(getCurrentParamsCopy(nativePtr));
return params.localConferenceMode();
}
@Override
public String toString() {
return "Call " + nativePtr;
}
private native float getPlayVolume(long nativePtr);
public float getPlayVolume() {
return getPlayVolume(nativePtr);
}
private native String getRemoteUserAgent(long nativePtr);
public String getRemoteUserAgent() {
return getRemoteUserAgent(nativePtr);
}
private native void takeSnapshot(long nativePtr, String path);
public void takeSnapshot(String path) {
takeSnapshot(nativePtr, path);
}
private native void zoomVideo(long nativePtr, float factor, float cx, float cy);
public void zoomVideo(float factor, float cx, float cy) {
zoomVideo(nativePtr, factor, cx, cy);
}
}

View file

@ -0,0 +1,72 @@
/*
LinPhoneCallLogImpl.java
Copyright (C) 2010 Belledonne Communications, Grenoble, France
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.linphone.core;
class LinphoneCallLogImpl implements LinphoneCallLog {
protected final long nativePtr;
private native long getFrom(long nativePtr);
private native long getTo(long nativePtr);
private native boolean isIncoming(long nativePtr);
private native int getStatus(long nativePtr);
private native String getStartDate(long nativePtr);
private native int getCallDuration(long nativePtr);
private native int getCallId(long nativePtr);
private native long getTimestamp(long nativePtr);
LinphoneCallLogImpl(long aNativePtr) {
nativePtr = aNativePtr;
}
public CallDirection getDirection() {
return isIncoming(nativePtr)?CallDirection.Incoming:CallDirection.Outgoing;
}
public LinphoneAddress getFrom() {
return new LinphoneAddressImpl(getFrom(nativePtr));
}
public LinphoneAddress getTo() {
return new LinphoneAddressImpl(getTo(nativePtr));
}
public CallStatus getStatus() {
return LinphoneCallLog.CallStatus.fromInt(getStatus(nativePtr));
}
public long getNativePtr() {
return nativePtr;
}
public String getStartDate() {
return getStartDate(nativePtr);
}
public int getCallDuration() {
return getCallDuration(nativePtr);
}
public int getCallId() {
return getCallId(nativePtr);
}
public long getTimestamp() {
return getTimestamp(nativePtr) * 1000; // Need milliseconds, not seconds
}
}

View file

@ -0,0 +1,86 @@
/*
LinphoneCallParamsImpl.java
Copyright (C) 2010 Belledonne Communications, Grenoble, France
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.linphone.core;
import org.linphone.core.LinphoneCore.MediaEncryption;
public class LinphoneCallParamsImpl implements LinphoneCallParams {
protected final long nativePtr;
public LinphoneCallParamsImpl(long nativePtr) {
this.nativePtr = nativePtr;
}
private native void enableVideo(long nativePtr, boolean b);
private native boolean getVideoEnabled(long nativePtr);
private native void audioBandwidth(long nativePtr, int bw);
private native void setMediaEncryption(long nativePtr, int menc);
private native int getMediaEncryption(long nativePtr);
private native long getUsedAudioCodec(long nativePtr);
private native long getUsedVideoCodec(long nativePtr);
private native void destroy(long nativePtr);
private native void enableLowBandwidth(long nativePtr, boolean enable);
public boolean getVideoEnabled() {
return getVideoEnabled(nativePtr);
}
public void setVideoEnabled(boolean b) {
enableVideo(nativePtr, b);
}
@Override
protected void finalize() throws Throwable {
destroy(nativePtr);
super.finalize();
}
public void setAudioBandwidth(int value) {
audioBandwidth(nativePtr, value);
}
public MediaEncryption getMediaEncryption() {
return MediaEncryption.fromInt(getMediaEncryption(nativePtr));
}
public void setMediaEnctyption(MediaEncryption menc) {
setMediaEncryption(nativePtr, menc.mValue);
}
public PayloadType getUsedAudioCodec() {
long ptr = getUsedAudioCodec(nativePtr);
if (ptr == 0) return null;
return new PayloadTypeImpl(ptr);
}
public PayloadType getUsedVideoCodec() {
long ptr = getUsedVideoCodec(nativePtr);
if (ptr == 0) return null;
return new PayloadTypeImpl(ptr);
}
private native boolean localConferenceMode(long nativePtr);
public boolean localConferenceMode() {
return localConferenceMode(nativePtr);
}
public void enableLowBandwidth(boolean enable) {
enableLowBandwidth(nativePtr, enable);
}
}

View file

@ -0,0 +1,104 @@
/*
LinPhoneCallStatsImpl.java
Copyright (C) 2010 Belledonne Communications, Grenoble, France
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.linphone.core;
class LinphoneCallStatsImpl implements LinphoneCallStats {
private int mediaType;
private int iceState;
private float downloadBandwidth;
private float uploadBandwidth;
private float senderLossRate;
private float receiverLossRate;
private float senderInterarrivalJitter;
private float receiverInterarrivalJitter;
private float roundTripDelay;
private long latePacketsCumulativeNumber;
private float jitterBufferSize;
private native int getMediaType(long nativeStatsPtr);
private native int getIceState(long nativeStatsPtr);
private native float getDownloadBandwidth(long nativeStatsPtr);
private native float getUploadBandwidth(long nativeStatsPtr);
private native float getSenderLossRate(long nativeStatsPtr);
private native float getReceiverLossRate(long nativeStatsPtr);
private native float getSenderInterarrivalJitter(long nativeStatsPtr, long nativeCallPtr);
private native float getReceiverInterarrivalJitter(long nativeStatsPtr, long nativeCallPtr);
private native float getRoundTripDelay(long nativeStatsPtr);
private native long getLatePacketsCumulativeNumber(long nativeStatsPtr, long nativeCallPtr);
private native float getJitterBufferSize(long nativeStatsPtr);
protected LinphoneCallStatsImpl(long nativeCallPtr, long nativeStatsPtr) {
mediaType = getMediaType(nativeStatsPtr);
iceState = getIceState(nativeStatsPtr);
downloadBandwidth = getDownloadBandwidth(nativeStatsPtr);
uploadBandwidth = getUploadBandwidth(nativeStatsPtr);
senderLossRate = getSenderLossRate(nativeStatsPtr);
receiverLossRate = getReceiverLossRate(nativeStatsPtr);
senderInterarrivalJitter = getSenderInterarrivalJitter(nativeStatsPtr, nativeCallPtr);
receiverInterarrivalJitter = getReceiverInterarrivalJitter(nativeStatsPtr, nativeCallPtr);
roundTripDelay = getRoundTripDelay(nativeStatsPtr);
latePacketsCumulativeNumber = getLatePacketsCumulativeNumber(nativeStatsPtr, nativeCallPtr);
jitterBufferSize = getJitterBufferSize(nativeStatsPtr);
}
public MediaType getMediaType() {
return MediaType.fromInt(mediaType);
}
public IceState getIceState() {
return IceState.fromInt(iceState);
}
public float getDownloadBandwidth() {
return downloadBandwidth;
}
public float getUploadBandwidth() {
return uploadBandwidth;
}
public float getSenderLossRate() {
return senderLossRate;
}
public float getReceiverLossRate() {
return receiverLossRate;
}
public float getSenderInterarrivalJitter() {
return senderInterarrivalJitter;
}
public float getReceiverInterarrivalJitter() {
return receiverInterarrivalJitter;
}
public float getRoundTripDelay() {
return roundTripDelay;
}
public long getLatePacketsCumulativeNumber() {
return latePacketsCumulativeNumber;
}
public float getJitterBufferSize() {
return jitterBufferSize;
}
}

View file

@ -0,0 +1,56 @@
package org.linphone.core;
public class LinphoneChatMessageImpl implements LinphoneChatMessage {
protected final long nativePtr;
private native void setUserData(long ptr);
private native String getMessage(long ptr);
private native long getPeerAddress(long ptr);
private native String getExternalBodyUrl(long ptr);
private native void setExternalBodyUrl(long ptr, String url);
private native long getFrom(long ptr);
protected LinphoneChatMessageImpl(long aNativePtr) {
nativePtr = aNativePtr;
setUserData();
}
public long getNativePtr() {
return nativePtr;
}
@Override
public Object getUserData() {
// TODO Auto-generated method stub
return null;
}
@Override
public void setUserData() {
setUserData(nativePtr);
}
@Override
public String getMessage() {
return getMessage(nativePtr);
}
@Override
public LinphoneAddress getPeerAddress() {
return new LinphoneAddressImpl(getPeerAddress(nativePtr));
}
@Override
public String getExternalBodyUrl() {
return getExternalBodyUrl(nativePtr);
}
@Override
public void setExternalBodyUrl(String url) {
setExternalBodyUrl(nativePtr, url);
}
@Override
public LinphoneAddress getFrom() {
return new LinphoneAddressImpl(getFrom(nativePtr));
}
}

View file

@ -0,0 +1,52 @@
/*
LinphoneChatRoomImpl.java
Copyright (C) 2010 Belledonne Communications, Grenoble, France
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.linphone.core;
import org.linphone.core.LinphoneChatMessage.StateListener;
class LinphoneChatRoomImpl implements LinphoneChatRoom {
protected final long nativePtr;
private native long createLinphoneChatMessage(long ptr, String message);
private native long getPeerAddress(long ptr);
private native void sendMessage(long ptr, String message);
private native void sendMessage2(long ptr, long message, StateListener listener);
protected LinphoneChatRoomImpl(long aNativePtr) {
nativePtr = aNativePtr;
}
public LinphoneAddress getPeerAddress() {
return new LinphoneAddressImpl(getPeerAddress(nativePtr));
}
public void sendMessage(String message) {
sendMessage(nativePtr,message);
}
@Override
public void sendMessage(LinphoneChatMessage message, StateListener listener) {
sendMessage2(nativePtr, message.getNativePtr(), listener);
}
@Override
public LinphoneChatMessage createLinphoneChatMessage(String message) {
return new LinphoneChatMessageImpl(createLinphoneChatMessage(nativePtr, message));
}
}

View file

@ -0,0 +1,182 @@
/*
LinphoneCoreFactoryImpl.java
Copyright (C) 2010 Belledonne Communications, Grenoble, France
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.linphone.core;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import org.linphone.mediastream.Version;
import android.util.Log;
public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory {
private static boolean loadOptionalLibrary(String s) {
try {
System.loadLibrary(s);
return true;
} catch (Throwable e) {
Log.w("Unable to load optional library lib", s);
}
return false;
}
static {
// FFMPEG (audio/video)
loadOptionalLibrary("avutil");
loadOptionalLibrary("swscale");
loadOptionalLibrary("avcore");
if (!hasNeonInCpuFeatures()) {
boolean noNeonLibrariesLoaded = loadOptionalLibrary("avcodecnoneon");
if (!noNeonLibrariesLoaded) {
loadOptionalLibrary("avcodec");
}
} else {
loadOptionalLibrary("avcodec");
}
// OPENSSL (cryptography)
// lin prefix avoids collision with libs in /system/lib
loadOptionalLibrary("lincrypto");
loadOptionalLibrary("linssl");
// Secure RTP and key negotiation
loadOptionalLibrary("srtp");
loadOptionalLibrary("zrtpcpp"); // GPLv3+
// Tunnel
loadOptionalLibrary("tunnelclient");
// g729 A implementation
loadOptionalLibrary("bcg729");
//Main library
if (!hasNeonInCpuFeatures()) {
try {
if (!isArmv7() && !Version.isX86()) {
System.loadLibrary("linphonearmv5");
} else {
System.loadLibrary("linphonenoneon");
}
Log.w("linphone", "No-neon liblinphone loaded");
} catch (UnsatisfiedLinkError ule) {
Log.w("linphone", "Failed to load no-neon liblinphone, loading neon liblinphone");
System.loadLibrary("linphone");
}
} else {
System.loadLibrary("linphone");
}
Version.dumpCapabilities();
}
@Override
public LinphoneAuthInfo createAuthInfo(String username, String password,
String realm) {
return new LinphoneAuthInfoImpl(username,password,realm);
}
@Override
public LinphoneAddress createLinphoneAddress(String username,
String domain, String displayName) {
return new LinphoneAddressImpl(username,domain,displayName);
}
@Override
public LinphoneAddress createLinphoneAddress(String identity) {
return new LinphoneAddressImpl(identity);
}
@Override
public LinphoneCore createLinphoneCore(LinphoneCoreListener listener,
String userConfig, String factoryConfig, Object userdata)
throws LinphoneCoreException {
try {
return new LinphoneCoreImpl(listener,new File(userConfig),new File(factoryConfig),userdata);
} catch (IOException e) {
throw new LinphoneCoreException("Cannot create LinphoneCore",e);
}
}
@Override
public LinphoneCore createLinphoneCore(LinphoneCoreListener listener) throws LinphoneCoreException {
try {
return new LinphoneCoreImpl(listener);
} catch (IOException e) {
throw new LinphoneCoreException("Cannot create LinphoneCore",e);
}
}
@Override
public LinphoneProxyConfig createProxyConfig(String identity, String proxy,
String route, boolean enableRegister) throws LinphoneCoreException {
return new LinphoneProxyConfigImpl(identity,proxy,route,enableRegister);
}
@Override
public native void setDebugMode(boolean enable);
@Override
public void setLogHandler(LinphoneLogHandler handler) {
//not implemented on Android
}
@Override
public LinphoneFriend createLinphoneFriend(String friendUri) {
return new LinphoneFriendImpl(friendUri);
}
@Override
public LinphoneFriend createLinphoneFriend() {
return createLinphoneFriend(null);
}
public static boolean hasNeonInCpuFeatures()
{
ProcessBuilder cmd;
boolean result = false;
try {
String[] args = {"/system/bin/cat", "/proc/cpuinfo"};
cmd = new ProcessBuilder(args);
Process process = cmd.start();
InputStream in = process.getInputStream();
byte[] re = new byte[1024];
while(in.read(re) != -1){
String line = new String(re);
if (line.contains("Features")) {
result = line.contains("neon");
break;
}
}
in.close();
} catch(IOException ex){
ex.printStackTrace();
}
return result;
}
public static boolean isArmv7()
{
return System.getProperty("os.arch").contains("armv7");
}
}

View file

@ -0,0 +1,863 @@
/*
LinphoneCoreImpl.java
Copyright (C) 2010 Belledonne Communications, Grenoble, France
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.linphone.core;
import static android.media.AudioManager.MODE_IN_CALL;
import static android.media.AudioManager.MODE_RINGTONE;
import android.content.Context;
import android.media.AudioManager;
import java.io.File;
import java.io.IOException;
import org.linphone.core.LinphoneCall.State;
import org.linphone.mediastream.video.capture.hwconf.Hacks;
class LinphoneCoreImpl implements LinphoneCore {
private final LinphoneCoreListener mListener; //to make sure to keep a reference on this object
private long nativePtr = 0;
private Context mContext = null;
private AudioManager mAudioManager = null;
private boolean mSpeakerEnabled = false;
private native long newLinphoneCore(LinphoneCoreListener listener,String userConfig,String factoryConfig,Object userdata);
private native void iterate(long nativePtr);
private native long getDefaultProxyConfig(long nativePtr);
private native void setDefaultProxyConfig(long nativePtr,long proxyCfgNativePtr);
private native int addProxyConfig(LinphoneProxyConfig jprtoxyCfg,long nativePtr,long proxyCfgNativePtr);
private native void clearAuthInfos(long nativePtr);
private native void clearProxyConfigs(long nativePtr);
private native void addAuthInfo(long nativePtr,long authInfoNativePtr);
private native Object invite(long nativePtr,String uri);
private native void terminateCall(long nativePtr, long call);
private native long getRemoteAddress(long nativePtr);
private native boolean isInCall(long nativePtr);
private native boolean isInComingInvitePending(long nativePtr);
private native void acceptCall(long nativePtr, long call);
private native long getCallLog(long nativePtr,int position);
private native int getNumberOfCallLogs(long nativePtr);
private native void delete(long nativePtr);
private native void setNetworkStateReachable(long nativePtr,boolean isReachable);
private native boolean isNetworkStateReachable(long nativePtr);
private native void setPlaybackGain(long nativeptr, float gain);
private native float getPlaybackGain(long nativeptr);
private native void muteMic(long nativePtr,boolean isMuted);
private native long interpretUrl(long nativePtr,String destination);
private native Object inviteAddress(long nativePtr,long to);
private native Object inviteAddressWithParams(long nativePtrLc,long to, long nativePtrParam);
private native void sendDtmf(long nativePtr,char dtmf);
private native void clearCallLogs(long nativePtr);
private native boolean isMicMuted(long nativePtr);
private native long findPayloadType(long nativePtr, String mime, int clockRate, int channels);
private native int enablePayloadType(long nativePtr, long payloadType, boolean enable);
private native void enableEchoCancellation(long nativePtr,boolean enable);
private native boolean isEchoCancellationEnabled(long nativePtr);
private native Object getCurrentCall(long nativePtr) ;
private native void playDtmf(long nativePtr,char dtmf,int duration);
private native void stopDtmf(long nativePtr);
private native void setVideoWindowId(long nativePtr, Object wid);
private native void setPreviewWindowId(long nativePtr, Object wid);
private native void setDeviceRotation(long nativePtr, int rotation);
private native void addFriend(long nativePtr,long friend);
private native void setPresenceInfo(long nativePtr,int minute_away, String alternative_contact,int status);
private native long createChatRoom(long nativePtr,String to);
private native void enableVideo(long nativePtr,boolean vcap_enabled,boolean display_enabled);
private native boolean isVideoEnabled(long nativePtr);
private native void setFirewallPolicy(long nativePtr, int enum_value);
private native int getFirewallPolicy(long nativePtr);
private native void setStunServer(long nativePtr, String stun_server);
private native String getStunServer(long nativePtr);
private native long createDefaultCallParams(long nativePtr);
private native int updateCall(long ptrLc, long ptrCall, long ptrParams);
private native void setUploadBandwidth(long nativePtr, int bw);
private native void setDownloadBandwidth(long nativePtr, int bw);
private native void setPreferredVideoSize(long nativePtr, int width, int heigth);
private native int[] getPreferredVideoSize(long nativePtr);
private native void setRing(long nativePtr, String path);
private native String getRing(long nativePtr);
private native void setRootCA(long nativePtr, String path);
private native long[] listVideoPayloadTypes(long nativePtr);
private native long[] getProxyConfigList(long nativePtr);
private native long[] listAudioPayloadTypes(long nativePtr);
private native void enableKeepAlive(long nativePtr,boolean enable);
private native boolean isKeepAliveEnabled(long nativePtr);
private native int startEchoCalibration(long nativePtr,Object data);
private native int getSignalingTransportPort(long nativePtr, int code);
private native void setSignalingTransportPorts(long nativePtr, int udp, int tcp, int tls);
private native void enableIpv6(long nativePtr,boolean enable);
private native int pauseCall(long nativePtr, long callPtr);
private native int pauseAllCalls(long nativePtr);
private native int resumeCall(long nativePtr, long callPtr);
private native void setUploadPtime(long nativePtr, int ptime);
private native void setDownloadPtime(long nativePtr, int ptime);
private native void setZrtpSecretsCache(long nativePtr, String file);
private native void enableEchoLimiter(long nativePtr2, boolean val);
private native int setVideoDevice(long nativePtr2, int id);
private native int getVideoDevice(long nativePtr2);
private native int getMediaEncryption(long nativePtr);
private native void setMediaEncryption(long nativePtr, int menc);
private native boolean isMediaEncryptionMandatory(long nativePtr);
private native void setMediaEncryptionMandatory(long nativePtr, boolean yesno);
private native void removeCallLog(long nativePtr, long callLogPtr);
private native int getMissedCallsCount(long nativePtr);
private native void resetMissedCallsCount(long nativePtr);
private native String getVersion(long nativePtr);
private native void setAudioPort(long nativePtr, int port);
private native void setVideoPort(long nativePtr, int port);
private native void setAudioPortRange(long nativePtr, int minPort, int maxPort);
private native void setVideoPortRange(long nativePtr, int minPort, int maxPort);
private native void setIncomingTimeout(long nativePtr, int timeout);
private native void setInCallTimeout(long nativePtr, int timeout);
private native void setPrimaryContact(long nativePtr, String displayName, String username);
LinphoneCoreImpl(LinphoneCoreListener listener, File userConfig,File factoryConfig,Object userdata) throws IOException {
mListener=listener;
nativePtr = newLinphoneCore(listener,userConfig.getCanonicalPath(),factoryConfig.getCanonicalPath(),userdata);
}
LinphoneCoreImpl(LinphoneCoreListener listener) throws IOException {
mListener=listener;
nativePtr = newLinphoneCore(listener,null,null,null);
}
protected void finalize() throws Throwable {
}
private boolean contextInitialized() {
if (mContext == null) {
Log.e("Context of LinphoneCore has not been initialized, call setContext() after creating LinphoneCore.");
return false;
}
return true;
}
public void setContext(Object context) {
mContext = (Context)context;
mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
}
public synchronized void addAuthInfo(LinphoneAuthInfo info) {
isValid();
addAuthInfo(nativePtr,((LinphoneAuthInfoImpl)info).nativePtr);
}
public synchronized LinphoneProxyConfig getDefaultProxyConfig() {
isValid();
long lNativePtr = getDefaultProxyConfig(nativePtr);
if (lNativePtr!=0) {
return new LinphoneProxyConfigImpl(lNativePtr);
} else {
return null;
}
}
public synchronized LinphoneCall invite(String uri) {
isValid();
return (LinphoneCall)invite(nativePtr,uri);
}
public synchronized void iterate() {
isValid();
iterate(nativePtr);
}
public synchronized void setDefaultProxyConfig(LinphoneProxyConfig proxyCfg) {
isValid();
setDefaultProxyConfig(nativePtr,((LinphoneProxyConfigImpl)proxyCfg).nativePtr);
}
public synchronized void addProxyConfig(LinphoneProxyConfig proxyCfg) throws LinphoneCoreException{
isValid();
if (addProxyConfig(proxyCfg,nativePtr,((LinphoneProxyConfigImpl)proxyCfg).nativePtr) !=0) {
throw new LinphoneCoreException("bad proxy config");
}
}
public synchronized void clearAuthInfos() {
isValid();
clearAuthInfos(nativePtr);
}
public synchronized void clearProxyConfigs() {
isValid();
clearProxyConfigs(nativePtr);
}
public synchronized void terminateCall(LinphoneCall aCall) {
isValid();
if (aCall!=null)terminateCall(nativePtr,((LinphoneCallImpl)aCall).nativePtr);
}
public synchronized LinphoneAddress getRemoteAddress() {
isValid();
long ptr = getRemoteAddress(nativePtr);
if (ptr==0) {
return null;
} else {
return new LinphoneAddressImpl(ptr);
}
}
public synchronized boolean isIncall() {
isValid();
return isInCall(nativePtr);
}
public synchronized boolean isInComingInvitePending() {
isValid();
return isInComingInvitePending(nativePtr);
}
public synchronized void acceptCall(LinphoneCall aCall) {
isValid();
acceptCall(nativePtr,((LinphoneCallImpl)aCall).nativePtr);
}
public synchronized LinphoneCallLog[] getCallLogs() {
isValid();
LinphoneCallLog[] logs = new LinphoneCallLog[getNumberOfCallLogs(nativePtr)];
for (int i=0;i < getNumberOfCallLogs(nativePtr);i++) {
logs[i] = new LinphoneCallLogImpl(getCallLog(nativePtr, i));
}
return logs;
}
public synchronized void destroy() {
isValid();
delete(nativePtr);
nativePtr = 0;
}
private void isValid() {
if (nativePtr == 0) {
throw new RuntimeException("object already destroyed");
}
}
public synchronized void setNetworkReachable(boolean isReachable) {
setNetworkStateReachable(nativePtr,isReachable);
}
public synchronized void setPlaybackGain(float gain) {
setPlaybackGain(nativePtr,gain);
}
public synchronized float getPlaybackGain() {
return getPlaybackGain(nativePtr);
}
public synchronized void muteMic(boolean isMuted) {
muteMic(nativePtr,isMuted);
}
public synchronized LinphoneAddress interpretUrl(String destination) throws LinphoneCoreException {
long lAddress = interpretUrl(nativePtr,destination);
if (lAddress != 0) {
return new LinphoneAddressImpl(lAddress,true);
} else {
throw new LinphoneCoreException("Cannot interpret ["+destination+"]");
}
}
public synchronized LinphoneCall invite(LinphoneAddress to) throws LinphoneCoreException {
LinphoneCall call = (LinphoneCall)inviteAddress(nativePtr,((LinphoneAddressImpl)to).nativePtr);
if (call!=null) {
return call;
} else {
throw new LinphoneCoreException("Unable to invite address " + to.asString());
}
}
public synchronized void sendDtmf(char number) {
sendDtmf(nativePtr,number);
}
public synchronized void clearCallLogs() {
clearCallLogs(nativePtr);
}
public synchronized boolean isMicMuted() {
return isMicMuted(nativePtr);
}
public synchronized PayloadType findPayloadType(String mime, int clockRate, int channels) {
isValid();
long playLoadType = findPayloadType(nativePtr, mime, clockRate, channels);
if (playLoadType == 0) {
return null;
} else {
return new PayloadTypeImpl(playLoadType);
}
}
public synchronized void enablePayloadType(PayloadType pt, boolean enable)
throws LinphoneCoreException {
isValid();
if (enablePayloadType(nativePtr,((PayloadTypeImpl)pt).nativePtr,enable) != 0) {
throw new LinphoneCoreException("cannot enable payload type ["+pt+"]");
}
}
public synchronized void enableEchoCancellation(boolean enable) {
isValid();
enableEchoCancellation(nativePtr, enable);
}
public synchronized boolean isEchoCancellationEnabled() {
isValid();
return isEchoCancellationEnabled(nativePtr);
}
public synchronized LinphoneCall getCurrentCall() {
isValid();
return (LinphoneCall)getCurrentCall(nativePtr);
}
public int getPlayLevel() {
// TODO Auto-generated method stub
return 0;
}
public void setPlayLevel(int level) {
// TODO Auto-generated method stub
}
private void applyAudioHacks() {
if (Hacks.needGalaxySAudioHack()) {
/* The microphone gain is way too high on the Galaxy S so correct it here. */
setMicrophoneGain(-9.0f);
}
}
private void setAudioModeIncallForGalaxyS() {
if (!contextInitialized()) return;
mAudioManager.setMode(MODE_IN_CALL);
}
public void routeAudioToSpeakerHelper(boolean speakerOn) {
if (!contextInitialized()) return;
if (Hacks.needGalaxySAudioHack())
setAudioModeIncallForGalaxyS();
mAudioManager.setSpeakerphoneOn(speakerOn);
}
private native void forceSpeakerState(long nativePtr, boolean speakerOn);
public void enableSpeaker(boolean value) {
final LinphoneCall call = getCurrentCall();
mSpeakerEnabled = value;
applyAudioHacks();
if (call != null && call.getState() == State.StreamsRunning && Hacks.needGalaxySAudioHack()) {
Log.d("Hack to have speaker=", value, " while on call");
forceSpeakerState(nativePtr, value);
} else {
routeAudioToSpeakerHelper(value);
}
}
public boolean isSpeakerEnabled() {
return mSpeakerEnabled;
}
public synchronized void playDtmf(char number, int duration) {
playDtmf(nativePtr,number, duration);
}
public synchronized void stopDtmf() {
stopDtmf(nativePtr);
}
public synchronized void addFriend(LinphoneFriend lf) throws LinphoneCoreException {
addFriend(nativePtr,((LinphoneFriendImpl)lf).nativePtr);
}
public synchronized void setPresenceInfo(int minute_away, String alternative_contact,
OnlineStatus status) {
setPresenceInfo(nativePtr,minute_away,alternative_contact,status.mValue);
}
public synchronized LinphoneChatRoom createChatRoom(String to) {
return new LinphoneChatRoomImpl(createChatRoom(nativePtr,to));
}
public synchronized void setPreviewWindow(Object w) {
setPreviewWindowId(nativePtr,w);
}
public synchronized void setVideoWindow(Object w) {
setVideoWindowId(nativePtr, w);
}
public synchronized void setDeviceRotation(int rotation) {
setDeviceRotation(nativePtr, rotation);
}
public synchronized void enableVideo(boolean vcap_enabled, boolean display_enabled) {
enableVideo(nativePtr,vcap_enabled, display_enabled);
}
public synchronized boolean isVideoEnabled() {
return isVideoEnabled(nativePtr);
}
public synchronized FirewallPolicy getFirewallPolicy() {
return FirewallPolicy.fromInt(getFirewallPolicy(nativePtr));
}
public synchronized String getStunServer() {
return getStunServer(nativePtr);
}
public synchronized void setFirewallPolicy(FirewallPolicy pol) {
setFirewallPolicy(nativePtr,pol.value());
}
public synchronized void setStunServer(String stunServer) {
setStunServer(nativePtr,stunServer);
}
public synchronized LinphoneCallParams createDefaultCallParameters() {
return new LinphoneCallParamsImpl(createDefaultCallParams(nativePtr));
}
public synchronized LinphoneCall inviteAddressWithParams(LinphoneAddress to, LinphoneCallParams params) throws LinphoneCoreException {
long ptrDestination = ((LinphoneAddressImpl)to).nativePtr;
long ptrParams =((LinphoneCallParamsImpl)params).nativePtr;
LinphoneCall call = (LinphoneCall)inviteAddressWithParams(nativePtr, ptrDestination, ptrParams);
if (call!=null) {
return call;
} else {
throw new LinphoneCoreException("Unable to invite with params " + to.asString());
}
}
public synchronized int updateCall(LinphoneCall call, LinphoneCallParams params) {
long ptrCall = ((LinphoneCallImpl) call).nativePtr;
long ptrParams = params!=null ? ((LinphoneCallParamsImpl)params).nativePtr : 0;
return updateCall(nativePtr, ptrCall, ptrParams);
}
public synchronized void setUploadBandwidth(int bw) {
setUploadBandwidth(nativePtr, bw);
}
public synchronized void setDownloadBandwidth(int bw) {
setDownloadBandwidth(nativePtr, bw);
}
public synchronized void setPreferredVideoSize(VideoSize vSize) {
setPreferredVideoSize(nativePtr, vSize.width, vSize.height);
}
public synchronized VideoSize getPreferredVideoSize() {
int[] nativeSize = getPreferredVideoSize(nativePtr);
VideoSize vSize = new VideoSize();
vSize.width = nativeSize[0];
vSize.height = nativeSize[1];
return vSize;
}
public synchronized void setRing(String path) {
setRing(nativePtr, path);
}
public synchronized String getRing() {
return getRing(nativePtr);
}
public synchronized void setRootCA(String path) {
setRootCA(nativePtr, path);
}
public synchronized LinphoneProxyConfig[] getProxyConfigList() {
long[] typesPtr = getProxyConfigList(nativePtr);
if (typesPtr == null) return null;
LinphoneProxyConfig[] proxies = new LinphoneProxyConfig[typesPtr.length];
for (int i=0; i < proxies.length; i++) {
proxies[i] = new LinphoneProxyConfigImpl(typesPtr[i]);
}
return proxies;
}
public synchronized PayloadType[] getVideoCodecs() {
long[] typesPtr = listVideoPayloadTypes(nativePtr);
if (typesPtr == null) return null;
PayloadType[] codecs = new PayloadType[typesPtr.length];
for (int i=0; i < codecs.length; i++) {
codecs[i] = new PayloadTypeImpl(typesPtr[i]);
}
return codecs;
}
public synchronized PayloadType[] getAudioCodecs() {
long[] typesPtr = listAudioPayloadTypes(nativePtr);
if (typesPtr == null) return null;
PayloadType[] codecs = new PayloadType[typesPtr.length];
for (int i=0; i < codecs.length; i++) {
codecs[i] = new PayloadTypeImpl(typesPtr[i]);
}
return codecs;
}
public synchronized boolean isNetworkReachable() {
return isNetworkStateReachable(nativePtr);
}
public synchronized void enableKeepAlive(boolean enable) {
enableKeepAlive(nativePtr,enable);
}
public synchronized boolean isKeepAliveEnabled() {
return isKeepAliveEnabled(nativePtr);
}
public synchronized void startEchoCalibration(Object data) throws LinphoneCoreException {
startEchoCalibration(nativePtr, data);
}
public synchronized Transports getSignalingTransportPorts() {
Transports transports = new Transports();
transports.udp = getSignalingTransportPort(nativePtr, 0);
transports.tcp = getSignalingTransportPort(nativePtr, 1);
transports.tls = getSignalingTransportPort(nativePtr, 3);
// See C struct LCSipTransports in linphonecore.h
// Code is the index in the structure
return transports;
}
public synchronized void setSignalingTransportPorts(Transports transports) {
setSignalingTransportPorts(nativePtr, transports.udp, transports.tcp, transports.tls);
}
public synchronized void enableIpv6(boolean enable) {
enableIpv6(nativePtr,enable);
}
public synchronized void adjustSoftwareVolume(int i) {
//deprecated, does the same as setPlaybackGain().
}
public synchronized boolean pauseCall(LinphoneCall call) {
return 0 == pauseCall(nativePtr, ((LinphoneCallImpl) call).nativePtr);
}
public synchronized boolean resumeCall(LinphoneCall call) {
return 0 == resumeCall(nativePtr, ((LinphoneCallImpl) call).nativePtr);
}
public synchronized boolean pauseAllCalls() {
return 0 == pauseAllCalls(nativePtr);
}
public synchronized void setDownloadPtime(int ptime) {
setDownloadPtime(nativePtr,ptime);
}
public synchronized void setUploadPtime(int ptime) {
setUploadPtime(nativePtr,ptime);
}
public synchronized void setZrtpSecretsCache(String file) {
setZrtpSecretsCache(nativePtr,file);
}
public synchronized void enableEchoLimiter(boolean val) {
enableEchoLimiter(nativePtr,val);
}
public void setVideoDevice(int id) {
Log.i("Setting camera id :", id);
if (setVideoDevice(nativePtr, id) != 0) {
Log.e("Failed to set video device to id:", id);
}
}
public int getVideoDevice() {
return getVideoDevice(nativePtr);
}
private native void leaveConference(long nativePtr);
public synchronized void leaveConference() {
leaveConference(nativePtr);
}
private native boolean enterConference(long nativePtr);
public synchronized boolean enterConference() {
return enterConference(nativePtr);
}
private native boolean isInConference(long nativePtr);
public synchronized boolean isInConference() {
return isInConference(nativePtr);
}
private native void terminateConference(long nativePtr);
public synchronized void terminateConference() {
terminateConference(nativePtr);
}
private native int getConferenceSize(long nativePtr);
public synchronized int getConferenceSize() {
return getConferenceSize(nativePtr);
}
private native int getCallsNb(long nativePtr);
public synchronized int getCallsNb() {
return getCallsNb(nativePtr);
}
private native void terminateAllCalls(long nativePtr);
public synchronized void terminateAllCalls() {
terminateAllCalls(nativePtr);
}
private native Object getCall(long nativePtr, int position);
public synchronized LinphoneCall[] getCalls() {
int size = getCallsNb(nativePtr);
LinphoneCall[] calls = new LinphoneCall[size];
for (int i=0; i < size; i++) {
calls[i]=((LinphoneCall)getCall(nativePtr, i));
}
return calls;
}
private native void addAllToConference(long nativePtr);
public synchronized void addAllToConference() {
addAllToConference(nativePtr);
}
private native void addToConference(long nativePtr, long nativePtrLcall);
public synchronized void addToConference(LinphoneCall call) {
addToConference(nativePtr, getCallPtr(call));
}
private native void removeFromConference(long nativePtr, long nativeCallPtr);
public synchronized void removeFromConference(LinphoneCall call) {
removeFromConference(nativePtr,getCallPtr(call));
}
private long getCallPtr(LinphoneCall call) {
return ((LinphoneCallImpl)call).nativePtr;
}
private long getCallParamsPtr(LinphoneCallParams callParams) {
return ((LinphoneCallParamsImpl)callParams).nativePtr;
}
private native int transferCall(long nativePtr, long callPtr, String referTo);
public synchronized void transferCall(LinphoneCall call, String referTo) {
transferCall(nativePtr, getCallPtr(call), referTo);
}
private native int transferCallToAnother(long nativePtr, long callPtr, long destPtr);
public synchronized void transferCallToAnother(LinphoneCall call, LinphoneCall dest) {
transferCallToAnother(nativePtr, getCallPtr(call), getCallPtr(dest));
}
private native Object findCallFromUri(long nativePtr, String uri);
@Override
public synchronized LinphoneCall findCallFromUri(String uri) {
return (LinphoneCall) findCallFromUri(nativePtr, uri);
}
public synchronized MediaEncryption getMediaEncryption() {
return MediaEncryption.fromInt(getMediaEncryption(nativePtr));
}
public synchronized boolean isMediaEncryptionMandatory() {
return isMediaEncryptionMandatory(nativePtr);
}
public synchronized void setMediaEncryption(MediaEncryption menc) {
setMediaEncryption(nativePtr, menc.mValue);
}
public synchronized void setMediaEncryptionMandatory(boolean yesno) {
setMediaEncryptionMandatory(nativePtr, yesno);
}
private native int getMaxCalls(long nativePtr);
public synchronized int getMaxCalls() {
return getMaxCalls(nativePtr);
}
@Override
public boolean isMyself(String uri) {
LinphoneProxyConfig lpc = getDefaultProxyConfig();
if (lpc == null) return false;
return uri.equals(lpc.getIdentity());
}
private native boolean soundResourcesLocked(long nativePtr);
public synchronized boolean soundResourcesLocked() {
return soundResourcesLocked(nativePtr);
}
private native void setMaxCalls(long nativePtr, int max);
@Override
public synchronized void setMaxCalls(int max) {
setMaxCalls(nativePtr, max);
}
private native boolean isEchoLimiterEnabled(long nativePtr);
@Override
public synchronized boolean isEchoLimiterEnabled() {
return isEchoLimiterEnabled(nativePtr);
}
private native boolean mediaEncryptionSupported(long nativePtr, int menc);
@Override
public synchronized boolean mediaEncryptionSupported(MediaEncryption menc) {
return mediaEncryptionSupported(nativePtr,menc.mValue);
}
private native void setPlayFile(long nativePtr, String path);
@Override
public synchronized void setPlayFile(String path) {
setPlayFile(nativePtr, path);
}
private native void tunnelAddServerAndMirror(long nativePtr, String host, int port, int mirror, int ms);
@Override
public synchronized void tunnelAddServerAndMirror(String host, int port, int mirror, int ms) {
tunnelAddServerAndMirror(nativePtr, host, port, mirror, ms);
}
private native void tunnelAutoDetect(long nativePtr);
@Override
public synchronized void tunnelAutoDetect() {
tunnelAutoDetect(nativePtr);
}
private native void tunnelCleanServers(long nativePtr);
@Override
public synchronized void tunnelCleanServers() {
tunnelCleanServers(nativePtr);
}
private native void tunnelEnable(long nativePtr, boolean enable);
@Override
public synchronized void tunnelEnable(boolean enable) {
tunnelEnable(nativePtr, enable);
}
@Override
public native boolean isTunnelAvailable();
private native void acceptCallWithParams(long nativePtr, long aCall,
long params);
@Override
public synchronized void acceptCallWithParams(LinphoneCall aCall,
LinphoneCallParams params) throws LinphoneCoreException {
acceptCallWithParams(nativePtr, getCallPtr(aCall), getCallParamsPtr(params));
}
private native void acceptCallUpdate(long nativePtr, long aCall, long params);
@Override
public synchronized void acceptCallUpdate(LinphoneCall aCall, LinphoneCallParams params)
throws LinphoneCoreException {
acceptCallUpdate(nativePtr, getCallPtr(aCall), getCallParamsPtr(params));
}
private native void deferCallUpdate(long nativePtr, long aCall);
@Override
public synchronized void deferCallUpdate(LinphoneCall aCall)
throws LinphoneCoreException {
deferCallUpdate(nativePtr, getCallPtr(aCall));
}
public synchronized void startRinging() {
if (!contextInitialized()) return;
if (Hacks.needGalaxySAudioHack()) {
mAudioManager.setMode(MODE_RINGTONE);
}
}
private native void setVideoPolicy(long nativePtr, boolean autoInitiate, boolean autoAccept);
public synchronized void setVideoPolicy(boolean autoInitiate, boolean autoAccept) {
setVideoPolicy(nativePtr, autoInitiate, autoAccept);
}
private native void setUserAgent(long nativePtr, String name, String version);
@Override
public void setUserAgent(String name, String version) {
setUserAgent(nativePtr,name,version);
}
private native void setCpuCountNative(int count);
public void setCpuCount(int count)
{
setCpuCountNative(count);
}
public int getMissedCallsCount() {
return getMissedCallsCount(nativePtr);
}
public void removeCallLog(LinphoneCallLog log) {
removeCallLog(nativePtr, ((LinphoneCallLogImpl) log).getNativePtr());
}
public void resetMissedCallsCount() {
resetMissedCallsCount(nativePtr);
}
private native void tunnelSetHttpProxy(long nativePtr, String proxy_host, int port,
String username, String password);
@Override
public void tunnelSetHttpProxy(String proxy_host, int port,
String username, String password) {
tunnelSetHttpProxy(nativePtr, proxy_host, port, username, password);
}
private native void refreshRegisters(long nativePtr);
public void refreshRegisters() {
refreshRegisters(nativePtr);
}
@Override
public String getVersion() {
return getVersion(nativePtr);
}
@Override
public PayloadType findPayloadType(String mime, int clockRate) {
return findPayloadType(mime, clockRate, 1);
}
private native void removeFriend(long ptr, long lf);
@Override
public void removeFriend(LinphoneFriend lf) {
removeFriend(nativePtr, lf.getNativePtr());
}
private native long getFriendByAddress(long ptr, String sipUri);
@Override
public LinphoneFriend findFriendByAddress(String sipUri) {
long ptr = getFriendByAddress(nativePtr, sipUri);
if (ptr == 0) {
return null;
}
return new LinphoneFriendImpl(ptr);
}
public void setAudioPort(int port) {
setAudioPort(nativePtr, port);
}
public void setVideoPort(int port) {
setVideoPort(nativePtr, port);
}
public void setAudioPortRange(int minPort, int maxPort) {
setAudioPortRange(nativePtr, minPort, maxPort);
}
public void setVideoPortRange(int minPort, int maxPort) {
setVideoPortRange(nativePtr, minPort, maxPort);
}
public void setIncomingTimeout(int timeout) {
setIncomingTimeout(nativePtr, timeout);
}
public void setInCallTimeout(int timeout)
{
setInCallTimeout(nativePtr, timeout);
}
private native void setMicrophoneGain(long ptr, float gain);
public void setMicrophoneGain(float gain) {
setMicrophoneGain(nativePtr, gain);
}
public void setPrimaryContact(String displayName, String username) {
setPrimaryContact(nativePtr, displayName, username);
}
private native void setUseSipInfoForDtmfs(long ptr, boolean use);
public void setUseSipInfoForDtmfs(boolean use) {
setUseSipInfoForDtmfs(nativePtr, use);
}
private native void setUseRfc2833ForDtmfs(long ptr, boolean use);
public void setUseRfc2833ForDtmfs(boolean use) {
setUseRfc2833ForDtmfs(nativePtr, use);
}
}

View file

@ -0,0 +1,81 @@
/*
LinphoneFriendImpl.java
Copyright (C) 2010 Belledonne Communications, Grenoble, France
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.linphone.core;
import java.io.Serializable;
class LinphoneFriendImpl implements LinphoneFriend, Serializable {
protected final long nativePtr;
private native long newLinphoneFriend(String friendUri);
private native void setAddress(long nativePtr,long friend);
private native long getAddress(long nativePtr);
private native void setIncSubscribePolicy(long nativePtr,int enumValue);
private native int getIncSubscribePolicy(long nativePtr);
private native void enableSubscribes(long nativePtr,boolean value);
private native boolean isSubscribesEnabled(long nativePtr);
private native int getStatus(long nativePtr);
private native void edit(long nativePtr);
private native void done(long nativePtr);
private native void delete(long ptr);
boolean ownPtr = false;
protected LinphoneFriendImpl() {
nativePtr = newLinphoneFriend(null);
}
protected LinphoneFriendImpl(String friendUri) {
nativePtr = newLinphoneFriend(friendUri);
}
protected LinphoneFriendImpl(long aNativePtr) {
nativePtr = aNativePtr;
ownPtr=false;
}
protected void finalize() throws Throwable {
if (ownPtr) delete(nativePtr);
}
public void setAddress(LinphoneAddress anAddress) {
this.setAddress(nativePtr, ((LinphoneAddressImpl)anAddress).nativePtr);
}
public LinphoneAddress getAddress() {
return new LinphoneAddressImpl(getAddress(nativePtr));
}
public void setIncSubscribePolicy(SubscribePolicy policy) {
setIncSubscribePolicy(nativePtr,policy.mValue);
}
public SubscribePolicy getIncSubscribePolicy() {
return SubscribePolicy.fromInt(getIncSubscribePolicy(nativePtr)) ;
}
public void enableSubscribes(boolean enable) {
enableSubscribes(nativePtr, enable);
}
public boolean isSubscribesEnabled() {
return isSubscribesEnabled(nativePtr);
}
public OnlineStatus getStatus() {
return OnlineStatus.fromInt(getStatus(nativePtr));
}
public void edit() {
edit(nativePtr);
}
public void done() {
done(nativePtr);
}
public long getNativePtr() {
return nativePtr;
}
}

View file

@ -0,0 +1,156 @@
/*
LinphoneProxyConfigImpl.java
Copyright (C) 2010 Belledonne Communications, Grenoble, France
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.linphone.core;
import org.linphone.core.LinphoneCore.RegistrationState;
class LinphoneProxyConfigImpl implements LinphoneProxyConfig {
protected final long nativePtr;
private native int getState(long nativePtr);
private native void setExpires(long nativePtr, int delay);
boolean ownPtr = false;
protected LinphoneProxyConfigImpl(String identity,String proxy,String route, boolean enableRegister) throws LinphoneCoreException {
nativePtr = newLinphoneProxyConfig();
setIdentity(identity);
setProxy(proxy);
enableRegister(enableRegister);
ownPtr=true;
}
protected LinphoneProxyConfigImpl(long aNativePtr) {
nativePtr = aNativePtr;
ownPtr=false;
}
protected void finalize() throws Throwable {
//Log.e(LinphoneService.TAG,"fixme, should release underlying proxy config");
if (ownPtr) delete(nativePtr);
}
private native long newLinphoneProxyConfig();
private native void delete(long ptr);
private native void edit(long ptr);
private native void done(long ptr);
private native void setIdentity(long ptr,String identity);
private native String getIdentity(long ptr);
private native int setProxy(long ptr,String proxy);
private native String getProxy(long ptr);
private native void enableRegister(long ptr,boolean value);
private native boolean isRegisterEnabled(long ptr);
private native boolean isRegistered(long ptr);
private native void setDialPrefix(long ptr, String prefix);
private native String normalizePhoneNumber(long ptr,String number);
private native String getDomain(long ptr);
private native void setDialEscapePlus(long ptr, boolean value);
private native String getRoute(long ptr);
private native int setRoute(long ptr,String uri);
private native void enablePublish(long ptr,boolean enable);
private native boolean publishEnabled(long ptr);
private native void setContactParameters(long ptr, String params);
private native int lookupCCCFromIso(long nativePtr, String iso);
public void enableRegister(boolean value) {
enableRegister(nativePtr,value);
}
public void done() {
done(nativePtr);
}
public void edit() {
edit(nativePtr);
}
public void setIdentity(String identity) throws LinphoneCoreException {
setIdentity(nativePtr,identity);
}
public void setProxy(String proxyUri) throws LinphoneCoreException {
if (setProxy(nativePtr,proxyUri)!=0) {
throw new LinphoneCoreException("Bad proxy address ["+proxyUri+"]");
}
}
public String normalizePhoneNumber(String number) {
return normalizePhoneNumber(nativePtr,number);
}
public void setDialPrefix(String prefix) {
setDialPrefix(nativePtr, prefix);
}
public String getDomain() {
return getDomain(nativePtr);
}
public void setDialEscapePlus(boolean value) {
setDialEscapePlus(nativePtr,value);
}
public String getIdentity() {
return getIdentity(nativePtr);
}
public String getProxy() {
return getProxy(nativePtr);
}
public boolean isRegistered() {
return isRegistered(nativePtr);
}
public boolean registerEnabled() {
return isRegisterEnabled(nativePtr);
}
public String getRoute() {
return getRoute(nativePtr);
}
public void setRoute(String routeUri) throws LinphoneCoreException {
if (setRoute(nativePtr, routeUri) != 0) {
throw new LinphoneCoreException("cannot set route ["+routeUri+"]");
}
}
public void enablePublish(boolean enable) {
enablePublish(nativePtr,enable);
}
public RegistrationState getState() {
return RegistrationState.fromInt(getState(nativePtr));
}
public void setExpires(int delay) {
setExpires(nativePtr, delay);
}
public boolean publishEnabled() {
return publishEnabled(nativePtr);
}
@Override
public void setContactParameters(String params) {
setContactParameters(nativePtr, params);
}
@Override
public int lookupCCCFromIso(String iso) {
return lookupCCCFromIso(nativePtr, iso);
}
}

View file

@ -0,0 +1,112 @@
/*
Log.java
Copyright (C) 2011 Belledonne Communications, Grenoble, France
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.linphone.core;
import static android.util.Log.DEBUG;
import static android.util.Log.ERROR;
import static android.util.Log.INFO;
import static android.util.Log.WARN;
/**
* Convenient wrapper for Android logs.
*
* @author Guillaume Beraudo
*/
public final class Log {
public static final String TAG = "Linphone";
private static final boolean useIsLoggable = false;
@SuppressWarnings(value="all")
private static boolean isLoggable(int level) {
return !useIsLoggable || android.util.Log.isLoggable(TAG, level);
}
public static void i(Object...objects) {
if (isLoggable(INFO)) {
android.util.Log.i(TAG, toString(objects));
}
}
public static void i(Throwable t, Object...objects) {
if (isLoggable(INFO)) {
android.util.Log.i(TAG, toString(objects), t);
}
}
public static void d(Object...objects) {
if (isLoggable(DEBUG)) {
android.util.Log.d(TAG, toString(objects));
}
}
public static void d(Throwable t, Object...objects) {
if (isLoggable(DEBUG)) {
android.util.Log.d(TAG, toString(objects), t);
}
}
public static void w(Object...objects) {
if (isLoggable(WARN)) {
android.util.Log.w(TAG, toString(objects));
}
}
public static void w(Throwable t, Object...objects) {
if (isLoggable(WARN)) {
android.util.Log.w(TAG, toString(objects), t);
}
}
public static void e(Object...objects) {
if (isLoggable(ERROR)) {
android.util.Log.e(TAG, toString(objects));
}
}
public static void e(Throwable t, Object...objects) {
if (isLoggable(ERROR)) {
android.util.Log.e(TAG, toString(objects), t);
}
}
/**
* @throws RuntimeException always throw after logging the error message.
*/
public static void f(Object...objects) {
if (isLoggable(ERROR)) {
android.util.Log.e(TAG, toString(objects));
throw new RuntimeException("Fatal error : " + toString(objects));
}
}
/**
* @throws RuntimeException always throw after logging the error message.
*/
public static void f(Throwable t, Object...objects) {
if (isLoggable(ERROR)) {
android.util.Log.e(TAG, toString(objects), t);
throw new RuntimeException("Fatal error : " + toString(objects), t);
}
}
private static String toString(Object...objects) {
StringBuilder sb = new StringBuilder();
for (Object o : objects) {
sb.append(o);
}
return sb.toString();
}
}

View file

@ -0,0 +1,45 @@
/*
PayloadTypeImpl.java
Copyright (C) 2010 Belledonne Communications, Grenoble, France
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.linphone.core;
class PayloadTypeImpl implements PayloadType {
protected final long nativePtr;
private native String toString(long ptr);
private native String getMime(long ptr);
private native int getRate(long ptr);
protected PayloadTypeImpl(long aNativePtr) {
nativePtr = aNativePtr;
}
public int getRate() {
return getRate(nativePtr);
}
public String getMime() {
return getMime(nativePtr);
}
public String toString() {
return toString(nativePtr);
}
}

Some files were not shown because too many files have changed in this diff Show more