Merge branch 'master' of git.linphone.org:linphone-private

This commit is contained in:
Jehan Monnier 2010-11-26 20:02:21 +01:00
commit 2667f001eb
118 changed files with 11547 additions and 6585 deletions

455
.cproject
View file

@ -2,231 +2,232 @@
<?fileVersion 4.0.0?>
<cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
<storageModule moduleId="org.eclipse.cdt.core.settings">
<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.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.MakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
</extensions>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<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 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.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.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>
</configuration>
</storageModule>
<storageModule moduleId="scannerConfiguration">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="makefileGenerator">
<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-c 'gcc -E -P -v -dD &quot;${plugin_state_location}/${specs_file}&quot;'" command="sh" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-c 'g++ -E -P -v -dD &quot;${plugin_state_location}/specs.cpp&quot;'" command="sh" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-c 'gcc -E -P -v -dD &quot;${plugin_state_location}/specs.c&quot;'" command="sh" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<scannerConfigBuildInfo instanceId="0.2079208171">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="makefileGenerator">
<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-c 'gcc -E -P -v -dD &quot;${plugin_state_location}/${specs_file}&quot;'" command="sh" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-c 'g++ -E -P -v -dD &quot;${plugin_state_location}/specs.cpp&quot;'" command="sh" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-c 'gcc -E -P -v -dD &quot;${plugin_state_location}/specs.c&quot;'" command="sh" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
</scannerConfigBuildInfo>
</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"/>
<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets">
<buildTargets>
<target name="all" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildTarget>all</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/>
<buildTarget>install</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
</buildTargets>
</storageModule>
</cconfiguration>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<project id="linphone.null.1149313048" name="linphone"/>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.settings">
<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.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" 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 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.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.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>
</configuration>
</storageModule>
<storageModule moduleId="scannerConfiguration">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="makefileGenerator">
<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-c 'gcc -E -P -v -dD &quot;${plugin_state_location}/${specs_file}&quot;'" command="sh" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-c 'g++ -E -P -v -dD &quot;${plugin_state_location}/specs.cpp&quot;'" command="sh" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-c 'gcc -E -P -v -dD &quot;${plugin_state_location}/specs.c&quot;'" command="sh" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<scannerConfigBuildInfo instanceId="0.2079208171">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="makefileGenerator">
<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-c 'gcc -E -P -v -dD &quot;${plugin_state_location}/${specs_file}&quot;'" command="sh" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-c 'g++ -E -P -v -dD &quot;${plugin_state_location}/specs.cpp&quot;'" command="sh" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-c 'gcc -E -P -v -dD &quot;${plugin_state_location}/specs.c&quot;'" command="sh" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
</scannerConfigBuildInfo>
</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"/>
<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets">
<buildTargets>
<target name="all" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildArguments/>
<buildTarget>all</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>false</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="install" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildTarget>install</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
</buildTargets>
</storageModule>
</cconfiguration>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<project id="linphone.null.1149313048" name="linphone"/>
</storageModule>
</cproject>

1
.gitignore vendored
View file

@ -39,7 +39,6 @@ INSTALL
Specfile
.anjuta/
.anjuta_sym_db.db
coreapi/help/doxygen.dox
gtk-glade/version_date.h
share/linphone.desktop

View file

@ -3,14 +3,21 @@
# let make re-run automake upon need
ACLOCAL_AMFLAGS = -I m4 $(ACLOCAL_MACOS_FLAGS)
if EXTERNAL_ORTP
ORTP_DIR =
if EXTERNAL_MEDIASTREAMER
MS2_DIR=
else
ORTP_DIR = oRTP
MS2_DIR=mediastreamer2
endif
SUBDIRS = m4 pixmaps po $(ORTP_DIR) mediastreamer2\
coreapi console gtk-glade share scripts
if EXTERNAL_ORTP
ORTP_DIR=
else
ORTP_DIR=oRTP
endif
SUBDIRS = m4 pixmaps po $(ORTP_DIR) $(MS2_DIR) \
coreapi console gtk share scripts
@ -42,6 +49,7 @@ SDK_EXCLUDED= \
GTK_PREFIX=/usr
GTK_THEME=Outcrop
GTK_FILELIST=gtk+-2.18.5.filelist
GTK_FILELIST_PATH=$(shell cd $(top_srcdir) && pwd)/$(GTK_FILELIST)
LINPHONEDEPS_FILELIST=linphone-deps.filelist
@ -113,7 +121,8 @@ gtk-cherrypick:
cp $$file $(INSTALLDIR_WITH_PREFIX)/$$file ;\
fi \
done && \
cp -rf share/themes $(INSTALLDIR_WITH_PREFIX)/share/.
mkdir -p $(INSTALLDIR_WITH_PREFIX)/share/themes && \
cp -rf share/themes/$(GTK_THEME) $(INSTALLDIR_WITH_PREFIX)/share/themes/.
zip:
rm -f $(ZIPFILE)
@ -125,7 +134,7 @@ zip:
#add gtk dlls and files
make gtk-cherrypick
make other-cherrypick
cp -f $(top_srcdir)/gtk-glade/gtkrc $(INSTALLDIR_WITH_PREFIX)/.
cp -f $(top_srcdir)/gtk/gtkrc $(INSTALLDIR_WITH_PREFIX)/.
cp -f $(top_srcdir)/README $(INSTALLDIR_WITH_PREFIX)/.
cp -f $(top_srcdir)/COPYING $(INSTALLDIR_WITH_PREFIX)/.
cd $(INSTALLDIR_WITH_PREFIX) && zip -r $(ZIPFILE) *
@ -162,7 +171,7 @@ setup.exe: filelist
rm -f $(INSTALLDIR_WITH_PREFIX)/$(ISS_SCRIPT)
newdate:
cd gtk-glade && $(MAKE) newdate
cd gtk && $(MAKE) newdate
Portfile: $(top_srcdir)/scripts/Portfile.tmpl dist

10
TODO
View file

@ -3,20 +3,12 @@ hot stuff:
* ice support
* run a user given command upon incoming calls
* linphonec on win32
* RTP inactivity timeout to close lost calls.
* SIP/TLS and SRTP
low priority:
-------------
* random RTP ports (to enable direct mapping NAT)
* zeroconf support for advertising services (cool stuff!)
* have the possibility to define several profiles (config files) and switch between them
* display call duration
* help tips for the registration box
* The length (or duration) of the call could be displayed (see icons2.png)
* 2. There could be a sound effect for "busy" - a short "beep-beep-beep" would be sufficient (try http://www.google.com/search?q=busy.wav)
* The call history could be a bit more clear (see history.png). And it
should be saved somewhere, so you can track your calls if you need to...
* move resampling stuff to use speex instead of libresample.

View file

@ -30,14 +30,12 @@ LOCAL_SRC_FILES = \
linphonecore.c \
misc.c \
enum.c \
enum.h \
presence.c \
proxy.c \
friend.c \
authentication.c \
lpconfig.c \
chat.c \
general_state.c \
sipsetup.c \
siplogin.c \
address.c \
@ -47,7 +45,8 @@ LOCAL_SRC_FILES = \
sal_eXosip2_presence.c \
sal_eXosip2_sdp.c \
offeranswer.c \
callbacks.c
callbacks.c \
linphonecall.c
LOCAL_CFLAGS += \
-D_BYTE_ORDER=_LITTLE_ENDIAN \
@ -58,7 +57,10 @@ LOCAL_CFLAGS += \
-DLOG_DOMAIN=\"Linphone\"
LOCAL_CFLAGS += -DIN_LINPHONE
#LOCAL_CFLAGS += -DVIDEO_ENABLED -DIN_LINPHONE
ifeq ($(LINPHONE_VIDEO),1)
LOCAL_CFLAGS += -DVIDEO_ENABLED
endif
LOCAL_C_INCLUDES += \
$(LOCAL_PATH) \
@ -68,7 +70,7 @@ LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/../../externals/exosip/include \
$(LOCAL_PATH)/../../externals/osip/include
LOCAL_LDLIBS += -llog
LOCAL_LDLIBS += -llog -ldl
LOCAL_STATIC_LIBRARIES := \
libmediastreamer2 \
@ -77,6 +79,15 @@ LOCAL_STATIC_LIBRARIES := \
libeXosip2 \
libosip2 \
libgsm
ifeq ($(LINPHONE_VIDEO),1)
LOCAL_STATIC_LIBRARIES += \
libavcodec \
libswscale \
libavcore \
libavutil
endif
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
LOCAL_CFLAGS += -DHAVE_ILBC=1
LOCAL_STATIC_LIBRARIES += libmsilbc

View file

@ -1,7 +1,8 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT([linphone],[3.3.2],[linphone-developers@nongnu.org])
AC_INIT([linphone],[3.3.99.10],[linphone-developers@nongnu.org])
AC_CANONICAL_SYSTEM
AC_CONFIG_SRCDIR([coreapi/linphonecore.c])
dnl Source packaging numbers
@ -15,7 +16,12 @@ LINPHONE_VERSION=$LINPHONE_MAJOR_VERSION.$LINPHONE_MINOR_VERSION.${LINPHONE_MICR
if test "$LINPHONE_EXTRA_VERSION" != "" ;then
LINPHONE_VERSION=$LINPHONE_VERSION.${LINPHONE_EXTRA_VERSION}
fi
LIBLINPHONE_SO_VERSION=`expr $LINPHONE_MINOR_VERSION + $LINPHONE_MAJOR_VERSION`:$LINPHONE_MICRO_VERSION:$LINPHONE_MINOR_VERSION
LIBLINPHONE_SO_CURRENT=4 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
LIBLINPHONE_SO_VERSION=$LIBLINPHONE_SO_CURRENT:$LIBLINPHONE_SO_REVISION:$LIBLINPHONE_SO_AGE
AC_SUBST(LIBLINPHONE_SO_VERSION, $LIBLINPHONE_SO_VERSION)
AC_SUBST(LINPHONE_VERSION)
@ -23,7 +29,8 @@ AC_SUBST(LINPHONE_VERSION)
AC_MSG_NOTICE([$PACKAGE_NAME-$PACKAGE_VERSION A full featured audio/video sip phone.])
AC_MSG_NOTICE([licensed under the terms of the General Public License (GPL)])
AM_INIT_AUTOMAKE([tar-ustar])
AM_INIT_AUTOMAKE
AC_SUBST([LIBTOOL_DEPS])
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])],)
AC_CONFIG_HEADER(config.h)
AC_CONFIG_MACRO_DIR([m4])
@ -62,7 +69,8 @@ AC_SUBST(CONSOLE_FLAGS)
AC_SUBST(GUI_FLAGS)
dnl localization tools
ifdef([IT_PROG_INTLTOOL],[IT_PROG_INTLTOOL],[AC_PROG_INTLTOOL])
IT_PROG_INTLTOOL([0.40], [no-xml])
dnl Initialize libtool
AC_LIBTOOL_WIN32_DLL
AC_PROG_LIBTOOL
@ -130,11 +138,8 @@ AC_ARG_ENABLE(gtk_ui,
if test "$gtk_ui" = "true" ; then
PKG_CHECK_MODULES(LIBGTK, gtk+-2.0 >= 2.4.0 gthread-2.0)
PKG_CHECK_MODULES(LIBGLADE, libglade-2.0 >= 2.4.0)
AC_SUBST(LIBGTK_CFLAGS)
AC_SUBST(LIBGTK_LIBS)
AC_SUBST(LIBGLADE_CFLAGS)
AC_SUBST(LIBGLADE_LIBS)
else
echo "GTK interface compilation is disabled."
fi
@ -288,11 +293,19 @@ AC_ARG_WITH( ffmpeg,
[ --with-ffmpeg Sets the installation prefix of ffmpeg, needed for video support. [default=/usr] ],
[ ffmpegdir=${withval}],[ ffmpegdir=/usr ])
AC_ARG_WITH( sdl,
[ --with-sdl Sets the installation prefix of libSDL, needed for video support. [default=/usr] ],
[ libsdldir=${withval}],[ libsdldir=/usr ])
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])
if test "$video" = "true"; then
if test "$enable_x11" = "true"; then
AC_CHECK_HEADERS(X11/Xlib.h)
fi
AC_DEFINE(VIDEO_ENABLED,1,[defined if video support is available])
fi
@ -324,8 +337,8 @@ 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-glade user interface
AM_CONDITIONAL(BUILD_GLADE_UI, [test x$gtk_ui = xtrue ] )
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 )
dnl check getenv
@ -360,15 +373,40 @@ fi
AC_SUBST(STRICT_OPTIONS)
AC_CONFIG_SUBDIRS( mediastreamer2 )
top_srcdir=`dirname $0`
AC_ARG_ENABLE([external-mediastreamer],
[AS_HELP_STRING([--enable-external-mediastreamer],[Use external mediastreamer library])],,
[enable_external_mediastreamer=no])
AS_CASE($enable_external_mediastreamer,
[yes],[
PKG_CHECK_MODULES([MEDIASTREAMER], [mediastreamer])
MS2_VERSION=`$PKG_CONFIG --modversion mediastreamer`
AM_CONDITIONAL(EXTERNAL_MEDIASTREAMER, [true])],
[no],[
AC_CONFIG_SUBDIRS( mediastreamer2 )
MEDIASTREAMER_DIR=${top_srcdir}/mediastreamer2
MEDIASTREAMER_CFLAGS="-I\$(top_srcdir)/mediastreamer2/include"
MEDIASTREAMER_LIBS="\$(top_builddir)/mediastreamer2/src/libmediastreamer.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'`
changequote([, ])
AM_CONDITIONAL(EXTERNAL_MEDIASTREAMER, [false])],
[AC_MSG_ERROR([bad value '${enable_external_mediastreamer}' for --enable-external-mediastreamer])])
AC_SUBST(MEDIASTREAMER_CFLAGS)
AC_SUBST(MEDIASTREAMER_LIBS)
AC_SUBST([MS2_VERSION])
dnl check for db2html (docbook) to generate html user manual
AC_CHECK_PROG(have_sgmltools,sgmltools, yes, no)
AM_CONDITIONAL(ENABLE_MANUAL, test x$have_sgmltools$build_manual = xyesyes )
dnl for external use of linphone libs
LINPHONE_CFLAGS="-I${includedir} -I${includedir}/linphone "
LINPHONE_LIBS="-L${libdir} -llinphone"
LINPHONE_CFLAGS="-I${includedir} -I${includedir}/linphone"
LINPHONE_LIBS="-L${libdir} -llinphone"
if test x$mingw_found = xyes ; then
LINPHONE_LIBS="$LINPHONE_LIBS $OSIP_LIBS"
@ -376,7 +414,6 @@ fi
AC_SUBST(LINPHONE_CFLAGS)
AC_SUBST(LINPHONE_LIBS)
AC_DEFINE_UNQUOTED(LINPHONE_VERSION,"$PACKAGE_VERSION",[Linphone's version number])
AC_DEFINE_UNQUOTED(LINPHONE_PLUGINS_DIR, "${package_prefix}/lib/liblinphone/plugins" ,[path of liblinphone plugins, not mediastreamer2 plugins])
@ -392,7 +429,8 @@ AC_ARG_ENABLE(external-ortp,
esac],[external_ortp=false])
if test "$external_ortp" = 'true'; then
LP_CHECK_ORTP
PKG_CHECK_MODULES([ORTP], [ortp])
ORTP_VERSION=`$PKG_CONFIG --modversion ortp`
else
AC_CONFIG_SUBDIRS( oRTP )
ORTP_CFLAGS="-I\$(top_srcdir)/oRTP/include"
@ -400,22 +438,16 @@ else
if test x$ac_cv_c_bigendian = xyes ; then
ORTP_CFLAGS="$ORTP_CFLAGS -DORTP_BIGENDIAN"
fi
changequote(<<, >>)
ORTP_VERSION=`grep -E ^[AC]+_INIT ${top_srcdir}/oRTP/configure.ac | sed -e 's:^.*_INIT(.*,\[\(.*\)\]):\1:g'`
changequote([, ])
fi
AC_SUBST(ORTP_CFLAGS)
AC_SUBST(ORTP_LIBS)
AC_SUBST([ORTP_VERSION])
AM_CONDITIONAL(EXTERNAL_ORTP, [test "$external_ortp" = 'true'])
dnl Packaging: Pick oRTP version from ${top_srcdir}/oRTP/configure.ac
dnl Feel free to propose an alternative & cleaner version...
top_srcdir=`dirname $0`
changequote(, )dnl
ORTP_VERSION=`grep -E ^[AC]+_INIT ${top_srcdir}/oRTP/configure.ac | sed -e 's:^.*_INIT(.*,\[\(.*\)\]):\1:g'`
MS2_VERSION=`grep -E ^[AC]+_INIT ${top_srcdir}/mediastreamer2/configure.ac | sed -e 's:^.*_INIT(.*,\[\(.*\)\]):\1:g'`
changequote([, ])dnl
AC_SUBST([ORTP_VERSION])
AC_SUBST([MS2_VERSION])
dnl ##################################################
dnl # Check for doxygen
dnl ##################################################
@ -427,13 +459,12 @@ AM_CONDITIONAL(HAVE_DOXYGEN, test $DOXYGEN != false)
AC_OUTPUT([
Makefile
m4/Makefile
po/Makefile.in
po/Makefile.in
pixmaps/Makefile
coreapi/Makefile
coreapi/help/Makefile
coreapi/help/Doxyfile
coreapi/help/doxygen.dox
gtk-glade/Makefile
gtk/Makefile
console/Makefile
share/Makefile
share/C/Makefile

View file

@ -9,9 +9,7 @@ INCLUDES = \
-I$(top_srcdir)/coreapi\
$(ORTP_CFLAGS) \
-I$(top_srcdir)/exosip \
-I$(top_srcdir)/mediastreamer2/include
$(MEDIASTREAMER_CFLAGS)
bin_PROGRAMS = linphonec linphonecsh
@ -22,7 +20,7 @@ endif
linphonec_SOURCES = linphonec.c linphonec.h commands.c
linphonec_CFLAGS=$(COMMON_CFLAGS) $(CONSOLE_FLAGS)
linphonec_LDADD = $(top_builddir)/coreapi/liblinphone.la $(READLINE_LIBS) \
$(top_builddir)/mediastreamer2/src/libmediastreamer.la \
$(MEDIASTREAMER_LIBS) \
$(ORTP_LIBS) \
$(SPEEX_LIBS) \
$(OSIP_LIBS)
@ -41,7 +39,7 @@ sipomatic_CFLAGS= $(COMMON_CFLAGS) $(CONSOLE_FLAGS)
sipomatic_LDADD= $(INTLLIBS) \
$(top_builddir)/coreapi/liblinphone.la \
$(top_builddir)/mediastreamer2/src/libmediastreamer.la \
$(MEDIASTREAMER_LIBS) \
$(ORTP_LIBS) \
$(SPEEX_LIBS) \
$(OSIP_LIBS)
@ -53,6 +51,3 @@ linphonecsh_LDADD = $(ORTP_LIBS)
endif

File diff suppressed because it is too large Load diff

View file

@ -77,6 +77,11 @@
#define PACKAGE_DIR ""
#endif
#ifdef HAVE_X11_XLIB_H
#include <X11/Xlib.h>
#include <SDL/SDL_syswm.h>
#endif
/***************************************************************************
*
* Types
@ -112,25 +117,24 @@ static char **linephonec_readline_completion(const char *text,
#endif
/* These are callback for linphone core */
static void linphonec_call_received(LinphoneCore *lc, const char *from);
static void linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm,
const char *username);
static void linphonec_display_refer (LinphoneCore * lc,const char *refer_to);
static void linphonec_display_refer (LinphoneCore * lc, const char *refer_to);
static void linphonec_display_something (LinphoneCore * lc, const char *something);
static void linphonec_display_url (LinphoneCore * lc, const char *something, const char *url);
static void linphonec_display_warning (LinphoneCore * lc, const char *something);
static void stub () {}
static void linphonec_notify_received(LinphoneCore *lc,const char *from,const char *msg);
static void linphonec_notify_received(LinphoneCore *lc, LinphoneCall *call, const char *from,const char *event);
static void linphonec_notify_presence_received(LinphoneCore *lc,LinphoneFriend *fid);
static void linphonec_new_unknown_subscriber(LinphoneCore *lc,
LinphoneFriend *lf, const char *url);
static void linphonec_bye_received(LinphoneCore *lc, const char *from);
static void linphonec_text_received(LinphoneCore *lc, LinphoneChatRoom *cr,
const char *from, const char *msg);
const LinphoneAddress *from, const char *msg);
static void linphonec_display_status (LinphoneCore * lc, const char *something);
static void linphonec_general_state (LinphoneCore * lc, LinphoneGeneralState *gstate);
static void linphonec_dtmf_received(LinphoneCore *lc, int dtmf);
static void linphonec_dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf);
static void print_prompt(LinphoneCore *opm);
void linphonec_out(const char *fmt,...);
/***************************************************************************
*
* Global variables
@ -156,6 +160,7 @@ LPC_AUTH_STACK auth_stack;
static int trace_level = 0;
static char *logfile_name = NULL;
static char configfile_name[PATH_MAX];
static const char *factory_configfile_name=NULL;
static char *sipAddr = NULL; /* for autocall */
#if !defined(_WIN32_WCE)
static ortp_pipe_t client_sock=ORTP_PIPE_INVALID;
@ -169,35 +174,27 @@ static bool_t pipe_reader_run=FALSE;
static ortp_pipe_t server_sock;
#endif /*_WIN32_WCE*/
bool_t linphonec_camera_enabled=TRUE;
LinphoneCoreVTable linphonec_vtable
#if !defined (_MSC_VER)
= {
.show =(ShowInterfaceCb) stub,
.inv_recv = linphonec_call_received,
.bye_recv = linphonec_bye_received,
.notify_recv = linphonec_notify_received,
.notify_presence_recv = linphonec_notify_presence_received,
.new_unknown_subscriber = linphonec_new_unknown_subscriber,
.auth_info_requested = linphonec_prompt_for_auth,
.display_status = linphonec_display_status,
.display_message=linphonec_display_something,
#ifdef VINCENT_MAURY_RSVP
/* the yes/no dialog box */
.display_yes_no= (DisplayMessageCb) stub,
#endif
.display_warning=linphonec_display_warning,
.display_url=linphonec_display_url,
.display_question=(DisplayQuestionCb)stub,
.text_received=linphonec_text_received,
.general_state=linphonec_general_state,
.dtmf_received=linphonec_dtmf_received,
.refer_received=linphonec_display_refer
void linphonec_call_identify(LinphoneCall* call){
static long callid=1;
linphone_call_set_user_pointer (call,(void*)callid);
callid++;
}
#endif /*_WIN32_WCE*/
;
LinphoneCall *linphonec_get_call(long id){
const MSList *elem=linphone_core_get_calls(linphonec);
for (;elem!=NULL;elem=elem->next){
LinphoneCall *call=(LinphoneCall*)elem->data;
if (linphone_call_get_user_pointer (call)==(void*)id){
return call;
}
}
linphonec_out("Sorry, no call with id %i exists at this time.\n",id);
return NULL;
}
/***************************************************************************
*
@ -209,10 +206,9 @@ LinphoneCoreVTable linphonec_vtable
* Linphone core callback
*/
static void
linphonec_display_refer (LinphoneCore * lc,const char *refer_to)
linphonec_display_refer (LinphoneCore * lc, const char *refer_to)
{
fprintf (stdout, "The distant end point asked to transfer the call to %s,don't forget to terminate the call if not\n%s", refer_to,prompt);
fflush(stdout);
linphonec_out("Receiving out of call refer to %s\n", refer_to);
}
/*
@ -254,19 +250,6 @@ linphonec_display_url (LinphoneCore * lc, const char *something, const char *url
fprintf (stdout, "%s : %s\n", something, url);
}
/*
* Linphone core callback
*/
static void
linphonec_call_received(LinphoneCore *lc, const char *from)
{
linphonec_set_caller(from);
if ( auto_answer) {
answer_call=TRUE;
}
}
/*
* Linphone core callback
*/
@ -296,16 +279,16 @@ linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm, const char *usern
* Linphone core callback
*/
static void
linphonec_notify_received(LinphoneCore *lc,const char *from,const char *msg)
linphonec_notify_received(LinphoneCore *lc, LinphoneCall *call, const char *from,const char *event)
{
printf("Notify type %s from %s\n", msg, from);
if(!strcmp(msg,"refer"))
if(!strcmp(event,"refer"))
{
printf("The distant SIP end point get the refer we can close the call\n");
linphonec_parse_command_line(linphonec, "terminate");
linphonec_out("The distand endpoint %s of call %li has been transfered, you can safely close the call.\n",
from,(long)linphone_call_get_user_pointer (call));
}
}
/*
* Linphone core callback
*/
@ -332,17 +315,73 @@ linphonec_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf,
}
/*
* Linphone core callback
*/
static void
linphonec_bye_received(LinphoneCore *lc, const char *from)
{
// Should change prompt back to original maybe
static void linphonec_call_updated(LinphoneCall *call){
const LinphoneCallParams *cp=linphone_call_get_current_params(call);
if (!linphone_call_camera_enabled (call) && linphone_call_params_video_enabled (cp)){
linphonec_out("Far end requests to share video.\nType 'camera on' if you agree.\n");
}
}
// printing this is unneeded as we'd get a "Communication ended"
// message trough display_status callback anyway
//printf("Bye received from %s\n", from);
static void linphonec_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState st, const char *msg){
char *from=linphone_call_get_remote_address_as_string(call);
long id=(long)linphone_call_get_user_pointer (call);
switch(st){
case LinphoneCallEnd:
linphonec_out("Call %i with %s ended.\n", id, from);
break;
case LinphoneCallResuming:
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);
break;
case LinphoneCallPausing:
linphonec_out("Pausing call %i with %s.\n", id, from);
break;
case LinphoneCallPaused:
linphonec_out("Call %i with %s is now paused.\n", id, from);
break;
case LinphoneCallPausedByRemote:
linphonec_out("Call %i has been paused by %s.\n",id,from);
break;
case LinphoneCallIncomingReceived:
linphonec_call_identify(call);
linphone_call_enable_camera (call,linphonec_camera_enabled);
id=(long)linphone_call_get_user_pointer (call);
linphonec_set_caller(from);
if ( auto_answer) {
answer_call=TRUE;
}
linphonec_out("Receiving new incoming call from %s, assigned id %i\n", from,id);
break;
case LinphoneCallOutgoingInit:
linphonec_call_identify(call);
id=(long)linphone_call_get_user_pointer (call);
from=linphone_call_get_remote_address_as_string(call);
linphonec_out("Establishing call id to %s, assigned id %i\n", from,id);
break;
case LinphoneCallUpdatedByRemote:
linphonec_call_updated(call);
break;
case LinphoneCallOutgoingProgress:
linphonec_out("Call %i to %s in progress.\n", id, from);
break;
case LinphoneCallOutgoingRinging:
linphonec_out("Call %i to %s ringing.\n", id, from);
break;
case LinphoneCallConnected:
linphonec_out("Call %i with %s connected.\n", id, from);
break;
case LinphoneCallOutgoingEarlyMedia:
linphonec_out("Call %i with %s early media.\n", id, from);
break;
case LinphoneCallError:
linphonec_out("Call %i with %s error.\n", id, from);
break;
default:
break;
}
ms_free(from);
}
/*
@ -350,71 +389,18 @@ linphonec_bye_received(LinphoneCore *lc, const char *from)
*/
static void
linphonec_text_received(LinphoneCore *lc, LinphoneChatRoom *cr,
const char *from, const char *msg)
const LinphoneAddress *from, const char *msg)
{
printf("%s: %s\n", from, msg);
printf("%s: %s\n", linphone_address_as_string(from), msg);
// TODO: provide mechanism for answering.. ('say' command?)
}
static void linphonec_dtmf_received(LinphoneCore *lc, int dtmf){
fprintf(stdout,"Receiving tone %c\n",dtmf);
static void linphonec_dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf){
char *from=linphone_call_get_remote_address_as_string(call);
fprintf(stdout,"Receiving tone %c from %s\n",dtmf,from);
fflush(stdout);
}
static void
linphonec_general_state (LinphoneCore * lc, LinphoneGeneralState *gstate)
{
if (show_general_state) {
switch(gstate->new_state) {
case GSTATE_POWER_OFF:
printf("GSTATE_POWER_OFF");
break;
case GSTATE_POWER_STARTUP:
printf("GSTATE_POWER_STARTUP");
break;
case GSTATE_POWER_ON:
printf("GSTATE_POWER_ON");
break;
case GSTATE_POWER_SHUTDOWN:
printf("GSTATE_POWER_SHUTDOWN");
break;
case GSTATE_REG_NONE:
printf("GSTATE_REG_NONE");
break;
case GSTATE_REG_OK:
printf("GSTATE_REG_OK");
break;
case GSTATE_REG_FAILED:
printf("GSTATE_REG_FAILED");
break;
case GSTATE_CALL_IDLE:
printf("GSTATE_CALL_IDLE");
break;
case GSTATE_CALL_OUT_INVITE:
printf("GSTATE_CALL_OUT_INVITE");
break;
case GSTATE_CALL_OUT_CONNECTED:
printf("GSTATE_CALL_OUT_CONNECTED");
break;
case GSTATE_CALL_IN_INVITE:
printf("GSTATE_CALL_IN_INVITE");
break;
case GSTATE_CALL_IN_CONNECTED:
printf("GSTATE_CALL_IN_CONNECTED");
break;
case GSTATE_CALL_END:
printf("GSTATE_CALL_END");
break;
case GSTATE_CALL_ERROR:
printf("GSTATE_CALL_ERROR");
break;
default:
printf("GSTATE_UNKNOWN_%d",gstate->new_state);
}
if (gstate->message) printf(" %s", gstate->message);
printf("\n");
}
ms_free(from);
}
static char received_prompt[PROMPT_MAX_LEN];
@ -596,6 +582,8 @@ bool_t linphonec_get_autoanswer(){
return auto_answer;
}
LinphoneCoreVTable linphonec_vtable={0};
/***************************************************************************/
/*
* Main
@ -621,31 +609,24 @@ char **convert_args_to_ascii(int argc, _TCHAR **wargv){
int _tmain(int argc, _TCHAR* wargv[]) {
char **argv=convert_args_to_ascii(argc,wargv);
trace_level=6;
linphonec_vtable.show =(ShowInterfaceCb) stub;
linphonec_vtable.inv_recv = linphonec_call_received;
linphonec_vtable.bye_recv = linphonec_bye_received;
linphonec_vtable.notify_presence_recv = linphonec_notify_received;
linphonec_vtable.new_unknown_subscriber = linphonec_new_unknown_subscriber;
linphonec_vtable.auth_info_requested = linphonec_prompt_for_auth;
linphonec_vtable.display_status = linphonec_display_status;
linphonec_vtable.display_message=linphonec_display_something;
#ifdef VINCENT_MAURY_RSVP
/* the yes/no dialog box */
linphonec_vtable.display_yes_no= (DisplayMessageCb) stub;
#endif
linphonec_vtable.display_warning=linphonec_display_warning;
linphonec_vtable.display_url=linphonec_display_url;
linphonec_vtable.display_question=(DisplayQuestionCb)stub;
linphonec_vtable.text_received=linphonec_text_received;
linphonec_vtable.general_state=linphonec_general_state;
linphonec_vtable.dtmf_received=linphonec_dtmf_received;
#else
int
main (int argc, char *argv[]) {
#endif
linphonec_vtable.call_state_changed=linphonec_call_state_changed;
linphonec_vtable.notify_presence_recv = linphonec_notify_presence_received;
linphonec_vtable.new_subscription_request = linphonec_new_unknown_subscriber;
linphonec_vtable.auth_info_requested = linphonec_prompt_for_auth;
linphonec_vtable.display_status = linphonec_display_status;
linphonec_vtable.display_message=linphonec_display_something;
linphonec_vtable.display_warning=linphonec_display_warning;
linphonec_vtable.display_url=linphonec_display_url;
linphonec_vtable.text_received=linphonec_text_received;
linphonec_vtable.dtmf_received=linphonec_dtmf_received;
linphonec_vtable.refer_received=linphonec_display_refer;
linphonec_vtable.notify_recv=linphonec_notify_received;
if (! linphonec_init(argc, argv) ) exit(EXIT_FAILURE);
linphonec_main_loop (linphonec, sipAddr);
@ -733,8 +714,7 @@ linphonec_init(int argc, char **argv)
/*
* Initialize linphone core
*/
linphonec=linphone_core_new (&linphonec_vtable, configfile_name, NULL,
NULL);
linphonec=linphone_core_new (&linphonec_vtable, configfile_name, factory_configfile_name, NULL);
linphone_core_enable_video(linphonec,vcap_enabled,display_enabled);
linphone_core_enable_video_preview(linphonec,preview_enabled);
if (!(vcap_enabled || display_enabled)) printf("Warning: video is disabled in linphonec, use -V or -C or -D to enable.\n");
@ -766,11 +746,14 @@ void linphonec_main_loop_exit(void){
void
linphonec_finish(int exit_status)
{
printf("Terminating...\n");
// Do not allow concurrent destroying to prevent glibc errors
static bool_t terminating=FALSE;
if (terminating) return;
terminating=TRUE;
linphonec_out("Terminating...\n");
/* Terminate any pending call */
linphonec_parse_command_line(linphonec, "terminate");
linphonec_command_finished();
linphone_core_terminate_all_calls(linphonec);
#ifdef HAVE_READLINE
linphonec_finish_readline();
#endif
@ -785,7 +768,7 @@ linphonec_finish(int exit_status)
{
fclose (mylogfile);
}
printf("\n");
exit(exit_status);
}
@ -885,6 +868,7 @@ print_usage (int exit_status)
usage: linphonec [-c file] [-s sipaddr] [-a] [-V] [-d level ] [-l logfile]\n\
linphonec -v\n\
\n\
-b file specify path of readonly factory configuration file.\n\
-c file specify path of configuration file.\n\
-d level be verbose. 0 is no output. 6 is all output\n\
-l logfile specify the log file for your SIP phone\n\
@ -899,6 +883,75 @@ usage: linphonec [-c file] [-s sipaddr] [-a] [-V] [-d level ] [-l logfile]\n\
exit(exit_status);
}
#ifdef VIDEO_ENABLED
#ifdef HAVE_X11_XLIB_H
static void x11_apply_video_params(VideoParams *params, Window window){
XWindowChanges wc;
unsigned int flags=0;
static Display *display = NULL;
const char *dname=getenv("DISPLAY");
if (display==NULL && dname!=NULL){
display=XOpenDisplay(dname);
}
if (display==NULL){
ms_error("Could not open display %s",dname);
return;
}
memset(&wc,0,sizeof(wc));
wc.x=params->x;
wc.y=params->y;
wc.width=params->w;
wc.height=params->h;
if (params->x!=-1 ){
flags|=CWX|CWY;
}
if (params->w!=-1){
flags|=CWWidth|CWHeight;
}
/*printf("XConfigureWindow x=%i,y=%i,w=%i,h=%i\n",
wc.x, wc.y ,wc.width, wc.height);*/
XConfigureWindow(display,window,flags,&wc);
if (params->show)
XMapWindow(display,window);
else
XUnmapWindow(display,window);
XSync(display,FALSE);
}
#endif
static void lpc_apply_video_params(){
static unsigned long old_wid=0,old_pwid=0;
unsigned long wid=linphone_core_get_native_video_window_id (linphonec);
unsigned long pwid=linphone_core_get_native_preview_window_id (linphonec);
if (wid!=0 && (lpc_video_params.refresh || old_wid!=wid)){
lpc_video_params.refresh=FALSE;
#ifdef HAVE_X11_XLIB_H
if (lpc_video_params.wid==0){ // do not manage window if embedded
x11_apply_video_params(&lpc_video_params,wid);
}
#endif
}
old_wid=wid;
if (pwid!=0 && (lpc_preview_params.refresh || old_pwid!=pwid)){
lpc_preview_params.refresh=FALSE;
#ifdef HAVE_X11_XLIB_H
/*printf("wid=%lu pwid=%lu\n",wid,pwid);*/
if (lpc_preview_params.wid==0){ // do not manage window if embedded
printf("Refreshing\n");
x11_apply_video_params(&lpc_preview_params,pwid);
}
#endif
}
old_pwid=pwid;
}
#endif
/*
*
@ -940,6 +993,10 @@ linphonec_idle_call ()
#endif
}
#ifdef VIDEO_ENABLED
lpc_apply_video_params();
#endif
return 0;
}
@ -1112,6 +1169,20 @@ linphonec_parse_cmdline(int argc, char **argv)
#endif /*_WIN32_WCE*/
snprintf(configfile_name, PATH_MAX, "%s", argv[arg_num]);
}
else if (strncmp ("-b", argv[arg_num], 2) == 0)
{
if ( ++arg_num >= argc ) print_usage(EXIT_FAILURE);
#if !defined(_WIN32_WCE)
if (access(argv[arg_num],F_OK)!=0 )
{
fprintf (stderr,
"Cannot open config file %s.\n",
argv[arg_num]);
exit(EXIT_FAILURE);
}
#endif /*_WIN32_WCE*/
factory_configfile_name = argv[arg_num];
}
else if (strncmp ("-s", argv[arg_num], 2) == 0)
{
arg_num++;

View file

@ -97,6 +97,17 @@ typedef struct {
char *doc; /* Long description. */
} LPC_COMMAND;
typedef struct {
int x,y,w,h;
unsigned long wid;
bool_t show;
bool_t refresh;
} VideoParams;
extern VideoParams lpc_video_params;
extern VideoParams lpc_preview_params;
/***************************************************************************
*
* Forward declarations
@ -112,6 +123,10 @@ void linphonec_set_autoanswer(bool_t enabled);
bool_t linphonec_get_autoanswer();
void linphonec_command_finished(void);
void linphonec_set_caller(const char *caller);
LinphoneCall *linphonec_get_call(long id);
void linphonec_call_identify(LinphoneCall* call);
extern bool_t linphonec_camera_enabled;
#endif /* def LINPHONEC_H */

View file

@ -1,16 +1,16 @@
SUBDIRS=help
SUBDIRS=. help
EXTRA_DIST=linphonecore_jni.cc
## Process this file with automake to produce Makefile.in
linphone_includedir=$(includedir)/linphone
linphone_include_HEADERS=linphonecore.h ../config.h lpconfig.h sipsetup.h
linphone_include_HEADERS=linphonecore.h linphonefriend.h linphonecore_utils.h ../config.h lpconfig.h sipsetup.h
INCLUDES = \
-I$(top_srcdir)\
-I$(top_srcdir)/mediastreamer2/include
$(MEDIASTREAMER_CFLAGS)
lib_LTLIBRARIES=liblinphone.la
@ -32,26 +32,35 @@ liblinphone_la_SOURCES=\
authentication.c \
lpconfig.c lpconfig.h \
chat.c \
general_state.c \
linphonecall.c \
sipsetup.c sipsetup.h \
siplogin.c
siplogin.c \
lsd.c linphonecore_utils.h
liblinphone_la_LDFLAGS= -version-info $(LIBLINPHONE_SO_VERSION) -no-undefined
liblinphone_la_LIBADD= \
$(EXOSIP_LIBS) \
$(top_builddir)/mediastreamer2/src/libmediastreamer.la \
$(MEDIASTREAMER_LIBS) \
$(ORTP_LIBS)
if BUILD_WIN32
liblinphone_la_LIBADD+=$(top_builddir)/oRTP/src/libortp.la
endif
noinst_PROGRAMS=test_lsd
test_lsd_SOURCES=test_lsd.c
test_lsd_LDADD=liblinphone.la \
$(MEDIASTREAMER_LIBS) \
$(ORTP_LIBS)
AM_CFLAGS=$(STRICT_OPTIONS) -DIN_LINPHONE \
$(ORTP_CFLAGS) \
$(OSIP_CFLAGS) \
$(MEDIASTREAMER_CFLAGS) \
$(EXOSIP_CFLAGS) \
-DENABLE_TRACE \
-DLOG_DOMAIN=\"LinphoneCore\" \

View file

@ -129,6 +129,29 @@ char *linphone_address_as_string_uri_only(const LinphoneAddress *u){
return sal_address_as_string_uri_only(u);
}
static bool_t strings_equals(const char *s1, const char *s2){
if (s1==NULL && s2==NULL) return TRUE;
if (s1!=NULL && s2!=NULL && strcmp(s1,s2)==0) return TRUE;
return FALSE;
}
/**
* Compare two LinphoneAddress ignoring tags and headers, basically just domain, username, and port.
* Returns TRUE if they are equal.
**/
bool_t linphone_address_weak_equal(const LinphoneAddress *a1, const LinphoneAddress *a2){
const char *u1,*u2;
const char *h1,*h2;
int p1,p2;
u1=linphone_address_get_username(a1);
u2=linphone_address_get_username(a2);
p1=linphone_address_get_port_int(a1);
p2=linphone_address_get_port_int(a2);
h1=linphone_address_get_domain(a1);
h2=linphone_address_get_domain(a2);
return strings_equals(u1,u2) && strings_equals(h1,h2) && p1==p2;
}
/**
* Destroys a LinphoneAddress object.
**/
@ -139,6 +162,7 @@ void linphone_address_destroy(LinphoneAddress *u){
int linphone_address_get_port_int(const LinphoneAddress *u) {
return sal_address_get_port_int(u);
}
const char* linphone_address_get_port(const LinphoneAddress *u) {
return sal_address_get_port(u);
}

View file

@ -23,19 +23,85 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "linphonecore.h"
#include "private.h"
#include "mediastreamer2/mediastream.h"
#include "lpconfig.h"
static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details);
static void linphone_connect_incoming(LinphoneCore *lc, LinphoneCall *call){
if (lc->vtable.show)
lc->vtable.show(lc);
if (lc->vtable.display_status)
lc->vtable.display_status(lc,_("Connected."));
call->state=LCStateAVRunning;
static bool_t media_parameters_changed(LinphoneCall *call, SalMediaDescription *oldmd, SalMediaDescription *newmd){
return !sal_media_description_equals(oldmd,newmd) || call->up_bw!=linphone_core_get_upload_bandwidth(call->core);
}
void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md){
SalMediaDescription *oldmd=call->resultdesc;
if (lc->ringstream!=NULL){
ring_stop(lc->ringstream);
lc->ringstream=NULL;
}
linphone_core_start_media_streams(lc,call);
if (new_md!=NULL){
sal_media_description_ref(new_md);
call->media_pending=FALSE;
}else{
call->media_pending=TRUE;
}
call->resultdesc=new_md;
if (call->audiostream && call->audiostream->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){
sal_media_description_unref(oldmd);
if (call->all_muted){
ms_message("Early media finished, unmuting inputs...");
/*we were in early media, now we want to enable real media */
linphone_call_enable_camera (call,linphone_call_camera_enabled (call));
if (call->audiostream)
linphone_core_mute_mic (lc, linphone_core_is_mic_muted(lc));
#ifdef VIDEO_ENABLED
if (call->videostream && call->camera_active)
video_stream_change_camera(call->videostream,lc->video_conf.device );
#endif
}
ms_message("No need to restart streams, SDP is unchanged.");
return;
}else{
ms_message("Media descriptions are different, need to restart the streams.");
}
}
linphone_call_stop_media_streams (call);
linphone_call_init_media_streams (call);
}
if (oldmd)
sal_media_description_unref(oldmd);
if (new_md) {
bool_t all_muted=FALSE;
bool_t send_ringbacktone=FALSE;
if (call->audiostream==NULL){
/*this happens after pausing the call locally. The streams is destroyed and then we wait the 200Ok to recreate it*/
linphone_call_init_media_streams (call);
}
if (call->state==LinphoneCallIncomingEarlyMedia && linphone_core_get_remote_ringback_tone (lc)!=NULL){
send_ringbacktone=TRUE;
}
if (call->state==LinphoneCallIncomingEarlyMedia ||
(call->state==LinphoneCallOutgoingEarlyMedia && !call->params.real_early_media)){
all_muted=TRUE;
}
linphone_call_start_media_streams(call,all_muted,send_ringbacktone);
}
}
static bool_t is_duplicate_call(LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to){
MSList *elem;
for(elem=lc->calls;elem!=NULL;elem=elem->next){
LinphoneCall *call=(LinphoneCall*)elem->data;
if (linphone_address_weak_equal(call->log->from,from) &&
linphone_address_weak_equal(call->log->to, to)){
return TRUE;
}
}
return FALSE;
}
static void call_received(SalOp *h){
@ -45,228 +111,310 @@ static void call_received(SalOp *h){
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);
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!=LINPHONE_STATUS_ONLINE){
ms_message("Not present !! presence mode : %d\n",lc->presence_mode);
if (lc->presence_mode==LINPHONE_STATUS_BUSY)
if (lc->presence_mode==LinphoneStatusBusy ||
lc->presence_mode==LinphoneStatusOffline ||
lc->presence_mode==LinphoneStatusDoNotDisturb ||
lc->presence_mode==LinphoneStatusMoved){
if (lc->presence_mode==LinphoneStatusBusy )
sal_call_decline(h,SalReasonBusy,NULL);
else if (lc->presence_mode==LINPHONE_STATUS_AWAY
||lc->presence_mode==LINPHONE_STATUS_BERIGHTBACK
||lc->presence_mode==LINPHONE_STATUS_ONTHEPHONE
||lc->presence_mode==LINPHONE_STATUS_OUTTOLUNCH
||lc->presence_mode==LINPHONE_STATUS_OFFLINE)
else if (lc->presence_mode==LinphoneStatusOffline)
sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL);
else if (lc->presence_mode==LINPHONE_STATUS_NOT_DISTURB)
else if (lc->presence_mode==LinphoneStatusDoNotDisturb)
sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL);
else if (lc->alt_contact!=NULL && lc->presence_mode==LINPHONE_STATUS_MOVED)
else if (lc->alt_contact!=NULL && lc->presence_mode==LinphoneStatusMoved)
sal_call_decline(h,SalReasonRedirect,lc->alt_contact);
else
sal_call_decline(h,SalReasonBusy,NULL);
sal_op_release(h);
return;
}
if (lc->call!=NULL){/*busy*/
if (!linphone_core_can_we_add_call(lc)){/*busy*/
sal_call_decline(h,SalReasonBusy,NULL);
sal_op_release(h);
return;
}
from=sal_op_get_from(h);
to=sal_op_get_to(h);
call=linphone_call_new_incoming(lc,linphone_address_new(from),linphone_address_new(to),h);
lc->call=call;
sal_call_set_local_media_description(h,call->localdesc);
call->resultdesc=sal_call_get_final_media_description(h);
if (call->resultdesc)
sal_media_description_ref(call->resultdesc);
if (call->resultdesc && sal_media_description_empty(call->resultdesc)){
sal_call_decline(h,SalReasonMedia,NULL);
linphone_call_destroy(call);
lc->call=NULL;
from_addr=linphone_address_new(from);
to_addr=linphone_address_new(to);
if (is_duplicate_call(lc,from_addr,to_addr)){
ms_warning("Receiving duplicated call, refusing this one.");
sal_call_decline(h,SalReasonBusy,NULL);
linphone_address_destroy(from_addr);
linphone_address_destroy(to_addr);
return;
}
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);
gstate_new_state(lc, GSTATE_CALL_IN_INVITE, tmp);
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 (lc->sound_conf.ring_sndcard!=NULL){
ms_message("Starting local ring...");
lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,lc->sound_conf.ring_sndcard);
/* play the ring if this is the only call*/
if (lc->sound_conf.ring_sndcard!=NULL && 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->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{
/*TODO : play a tone within the context of the current call */
}
linphone_call_set_state(call,LinphoneCallIncomingReceived,"Incoming call");
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");
linphone_core_update_streams(lc,call,md);
}
linphone_call_set_state(call,LCStateRinging);
sal_call_notify_ringing(h);
#if !(__IPHONE_OS_VERSION_MIN_REQUIRED >= 40000)
linphone_core_init_media_streams(lc,lc->call);
#endif
if (lc->vtable.inv_recv) lc->vtable.inv_recv(lc,tmp);
ms_free(barmesg);
ms_free(tmp);
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);
}
}
static void call_ringing(SalOp *h){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
LinphoneCall *call=lc->call;
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(h);
SalMediaDescription *md;
if (call==NULL) return;
if (lc->vtable.display_status)
lc->vtable.display_status(lc,_("Remote ringing."));
md=sal_call_get_final_media_description(h);
if (md==NULL){
if (lc->ringstream && lc->dmfs_playing_start_time!=0){
ring_stop(lc->ringstream);
lc->ringstream=NULL;
lc->dmfs_playing_start_time=0;
}
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;
ms_message("Remote ringing...");
lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,lc->sound_conf.play_sndcard);
gstate_new_state(lc, GSTATE_CALL_OUT_RINGING, NULL);
lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,ringcard);
linphone_call_set_state(call,LinphoneCallOutgoingRinging,"Remote ringing");
}
}else{
/*accept early media */
if (lc->audiostream && lc->audiostream->ticker!=NULL){
if (call->audiostream && call->audiostream->ticker!=NULL){
/*streams already started */
ms_message("Early media already started.");
return;
}
sal_media_description_ref(md);
call->resultdesc=md;
if (lc->vtable.show) lc->vtable.show(lc);
if (lc->vtable.display_status)
lc->vtable.display_status(lc,_("Early media."));
gstate_new_state(lc, GSTATE_CALL_OUT_RINGING, NULL);
linphone_call_set_state(call,LinphoneCallOutgoingEarlyMedia,"Early media");
if (lc->ringstream!=NULL){
ring_stop(lc->ringstream);
lc->ringstream=NULL;
}
ms_message("Doing early media...");
linphone_core_start_media_streams(lc,call);
call->media_pending=TRUE;
linphone_core_update_streams (lc,call,md);
}
call->state=LCStateRinging;
}
/*
* could be reach :
* - when the call is accepted
* - when a request is accepted (pause, resume)
*/
static void call_accepted(SalOp *op){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=lc->call;
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
SalMediaDescription *md;
if (call==NULL){
ms_warning("No call to accept.");
return ;
}
if (sal_op_get_user_pointer(op)!=lc->call){
ms_warning("call_accepted: ignoring.");
return;
md=sal_call_get_final_media_description(op);
if (call->state==LinphoneCallOutgoingProgress ||
call->state==LinphoneCallOutgoingRinging ||
call->state==LinphoneCallOutgoingEarlyMedia){
linphone_call_set_state(call,LinphoneCallConnected,"Connected");
}
if (call->state==LCStateAVRunning){
return ; /*already accepted*/
}
if (lc->audiostream->ticker!=NULL){
/*case where we accepted early media */
linphone_core_stop_media_streams(lc,call);
linphone_core_init_media_streams(lc,call);
}
if (call->resultdesc)
sal_media_description_unref(call->resultdesc);
call->resultdesc=sal_call_get_final_media_description(op);
if (call->resultdesc){
sal_media_description_ref(call->resultdesc);
call->media_pending=FALSE;
}
if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){
gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL);
linphone_connect_incoming(lc,call);
if (md && !sal_media_description_empty(md)){
if (sal_media_description_has_dir(md,SalStreamSendOnly) ||
sal_media_description_has_dir(md,SalStreamInactive)){
if (lc->vtable.display_status){
char *tmp=linphone_call_get_remote_address_as_string (call);
char *msg=ms_strdup_printf(_("Call with %s is paused."),tmp);
lc->vtable.display_status(lc,msg);
ms_free(tmp);
ms_free(msg);
}
linphone_call_set_state(call,LinphoneCallPaused,"Call paused");
}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){
char *tmp=linphone_call_get_remote_address_as_string (call);
char *msg=ms_strdup_printf(_("Call answered by %s - on hold."),tmp);
lc->vtable.display_status(lc,msg);
ms_free(tmp);
ms_free(msg);
}
linphone_call_set_state(call,LinphoneCallPaused,"Call paused");
}else{
if (lc->vtable.display_status){
lc->vtable.display_status(lc,_("Call answered - connected."));
}
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_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)");
}
linphone_core_update_streams (lc,call,md);
}else{
/*send a bye*/
ms_error("Incompatible SDP offer received in 200Ok, need to abort the call");
linphone_core_terminate_call(lc,NULL);
linphone_core_abort_call(lc,call,"No codec intersection");
}
}
static void call_ack(SalOp *op){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=lc->call;
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
if (call==NULL){
ms_warning("No call to be ACK'd");
return ;
}
if (sal_op_get_user_pointer(op)!=lc->call){
ms_warning("call_ack: ignoring.");
return;
}
if (call->media_pending){
if (lc->audiostream->ticker!=NULL){
/*case where we accepted early media */
linphone_core_stop_media_streams(lc,call);
linphone_core_init_media_streams(lc,call);
}
if (call->resultdesc)
sal_media_description_unref(call->resultdesc);
call->resultdesc=sal_call_get_final_media_description(op);
if (call->resultdesc)
sal_media_description_ref(call->resultdesc);
if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){
gstate_new_state(lc, GSTATE_CALL_IN_CONNECTED, NULL);
linphone_connect_incoming(lc,call);
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{
/*send a bye*/
ms_error("Incompatible SDP response received in ACK, need to abort the call");
linphone_core_terminate_call(lc,NULL);
linphone_core_abort_call(lc,call,"No codec intersection");
return;
}
call->media_pending=FALSE;
}
}
static void call_updated(SalOp *op){
/* this callback is called when an incoming re-INVITE modifies the session*/
static void call_updating(SalOp *op){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
linphone_core_stop_media_streams(lc,call);
linphone_core_init_media_streams(lc,call);
if (call->resultdesc)
sal_media_description_unref(call->resultdesc);
call->resultdesc=sal_call_get_final_media_description(op);
if (call->resultdesc){
sal_media_description_ref(call->resultdesc);
if (!sal_media_description_empty(call->resultdesc)){
linphone_connect_incoming(lc,call);
LinphoneCallState prevstate=LinphoneCallIdle;
SalMediaDescription *md;
md=sal_call_get_final_media_description(op);
if (md && !sal_media_description_empty(md))
{
if ((call->state==LinphoneCallPausedByRemote || call->state==LinphoneCallPaused) &&
sal_media_description_has_dir(md,SalStreamSendRecv) && strcmp(md->addr,"0.0.0.0")!=0){
/*make sure we can be resumed */
if (lc->current_call!=NULL && lc->current_call!=call){
ms_warning("Attempt to be resumed but already in call with somebody else!");
/*we are actively running another call, reject with a busy*/
sal_call_decline (op,SalReasonBusy,NULL);
return;
}
if(lc->vtable.display_status)
lc->vtable.display_status(lc,_("We have been resumed..."));
linphone_call_set_state (call,LinphoneCallStreamsRunning,"Connected (streams running)");
}
else if(call->state==LinphoneCallStreamsRunning &&
( sal_media_description_has_dir(md,SalStreamRecvOnly)
|| sal_media_description_has_dir(md,SalStreamInactive)
|| strcmp(md->addr,"0.0.0.0")==0)){
if(lc->vtable.display_status)
lc->vtable.display_status(lc,_("We are being paused..."));
linphone_call_set_state (call,LinphoneCallPausedByRemote,"Call paused by remote");
if (lc->current_call!=call){
ms_error("Inconsitency detected: current call is %p but call %p is being paused !",lc->current_call,call);
}
}else{
prevstate=call->state;
linphone_call_set_state(call, LinphoneCallUpdatedByRemote,"Call updated by remote");
}
/*accept the modification (sends a 200Ok)*/
sal_call_accept(op);
linphone_core_update_streams (lc,call,md);
if (prevstate!=LinphoneCallIdle){
linphone_call_set_state (call,prevstate,"Connected (streams running)");
}
}
}
static void call_terminated(SalOp *op, const char *from){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
if (sal_op_get_user_pointer(op)!=lc->call){
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
if (call==NULL) return;
if (linphone_call_get_state(call)==LinphoneCallEnd || linphone_call_get_state(call)==LinphoneCallError){
ms_warning("call_terminated: ignoring.");
return;
}
ms_message("Current call terminated...");
if (lc->ringstream!=NULL) {
//we stop the call only if we have this current call or if we are in call
if (lc->ringstream!=NULL && ( (ms_list_size(lc->calls) == 1) || linphone_core_in_call(lc) )) {
ring_stop(lc->ringstream);
lc->ringstream=NULL;
}
linphone_core_stop_media_streams(lc,lc->call);
lc->vtable.show(lc);
lc->vtable.display_status(lc,_("Call terminated."));
gstate_new_state(lc, GSTATE_CALL_END, NULL);
if (lc->vtable.bye_recv!=NULL){
LinphoneAddress *addr=linphone_address_new(from);
char *tmp;
linphone_address_clean(addr);
tmp=linphone_address_as_string(addr);
lc->vtable.bye_recv(lc,tmp);
ms_free(tmp);
linphone_address_destroy(addr);
}
linphone_call_destroy(lc->call);
lc->call=NULL;
linphone_call_stop_media_streams(call);
if (lc->vtable.show!=NULL)
lc->vtable.show(lc);
if (lc->vtable.display_status!=NULL)
lc->vtable.display_status(lc,_("Call terminated."));
linphone_call_set_state(call, LinphoneCallEnd,"Call ended");
}
static void call_failure(SalOp *op, SalError error, SalReason sr, const char *details){
static void call_failure(SalOp *op, SalError error, SalReason sr, const char *details, int code){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
char *msg486=_("User is busy.");
char *msg480=_("User is temporarily unavailable.");
@ -274,12 +422,13 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de
char *msg600=_("User does not want to be disturbed.");
char *msg603=_("Call declined.");
const char *msg=details;
LinphoneCall *call=lc->call;
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
if (sal_op_get_user_pointer(op)!=lc->call){
ms_warning("call_failure: ignoring.");
return;
if (call==NULL){
ms_warning("Call faillure reported on already cleaned call ?");
return ;
}
if (lc->vtable.show) lc->vtable.show(lc);
if (error==SalErrorNoResponse){
@ -332,16 +481,16 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de
lc->vtable.display_status(lc,_("Call failed."));
}
}
if (lc->ringstream!=NULL) {
ring_stop(lc->ringstream);
lc->ringstream=NULL;
}
linphone_core_stop_media_streams(lc,call);
if (call!=NULL) {
linphone_call_destroy(call);
if (sr!=SalReasonDeclined) gstate_new_state(lc, GSTATE_CALL_ERROR, msg);
else gstate_new_state(lc, GSTATE_CALL_END, msg);
lc->call=NULL;
linphone_call_stop_media_streams (call);
if (sr!=SalReasonDeclined) linphone_call_set_state(call,LinphoneCallError,msg);
else{
call->reason=LinphoneReasonDeclined;
linphone_call_set_state(call,LinphoneCallEnd,"Call declined.");
}
}
@ -359,6 +508,9 @@ static void auth_requested(SalOp *h, const char *realm, const char *username){
sal_op_authenticate(h,&sai);
ai->usecount++;
}else{
if (ai && ai->works==FALSE) {
register_failure(h, SalErrorFailure, SalReasonForbidden, _("Authentication failure"));
}
if (lc->vtable.auth_info_requested)
lc->vtable.auth_info_requested(lc,realm,username);
}
@ -377,42 +529,87 @@ static void register_success(SalOp *op, bool_t registered){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op);
char *msg;
cfg->registered=registered;
gstate_new_state(lc, GSTATE_REG_OK, NULL);
if (cfg->registered) msg=ms_strdup_printf(_("Registration on %s successful."),sal_op_get_proxy(op));
else msg=ms_strdup_printf(_("Unregistration on %s done."),sal_op_get_proxy(op));
if (lc->vtable.display_status)
linphone_proxy_config_set_error(cfg,LinphoneReasonNone);
linphone_proxy_config_set_state(cfg, registered ? LinphoneRegistrationOk : LinphoneRegistrationCleared ,
registered ? "Registration sucessful" : "Unregistration done");
if (lc->vtable.display_status){
if (cfg->registered) msg=ms_strdup_printf(_("Registration on %s successful."),sal_op_get_proxy(op));
else msg=ms_strdup_printf(_("Unregistration on %s done."),sal_op_get_proxy(op));
lc->vtable.display_status(lc,msg);
ms_free(msg);
ms_free(msg);
}
}
static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
char *msg=ortp_strdup_printf(_("Registration on %s failed: %s"),sal_op_get_proxy(op),(details!=NULL) ? details : _("no response timeout"));
if (lc->vtable.display_status) lc->vtable.display_status(lc,msg);
gstate_new_state(lc, GSTATE_REG_FAILED, msg);
ms_free(msg);
LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op);
if (cfg==NULL){
ms_warning("Registration failed for unknown proxy config.");
return ;
}
if (details==NULL)
details=_("no response timeout");
if (lc->vtable.display_status) {
char *msg=ortp_strdup_printf(_("Registration on %s failed: %s"),sal_op_get_proxy(op),details );
lc->vtable.display_status(lc,msg);
ms_free(msg);
}
if (error== SalErrorFailure && reason == SalReasonForbidden) {
linphone_proxy_config_set_error(cfg, LinphoneReasonBadCredentials);
} else if (error == SalErrorNoResponse) {
linphone_proxy_config_set_error(cfg, LinphoneReasonNoResponse);
}
linphone_proxy_config_set_state(cfg,LinphoneRegistrationFailed,details);
}
static void vfu_request(SalOp *op){
#ifdef VIDEO_ENABLED
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
if (lc->videostream)
video_stream_send_vfu(lc->videostream);
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer (op);
if (call==NULL){
ms_warning("VFU request but no call !");
return ;
}
if (call->videostream)
video_stream_send_vfu(call->videostream);
#endif
}
static void dtmf_received(SalOp *op, char dtmf){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
if (lc->vtable.dtmf_received != NULL)
lc->vtable.dtmf_received(lc, dtmf);
lc->vtable.dtmf_received(lc, call, dtmf);
}
static void refer_received(Sal *sal, SalOp *op, const char *referto){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
if (lc->vtable.refer_received){
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
if (call){
if (call->refer_to!=NULL){
ms_free(call->refer_to);
}
call->refer_to=ms_strdup(referto);
call->refer_pending=TRUE;
linphone_call_set_state(call,LinphoneCallRefered,"Refered");
if (lc->vtable.display_status){
char *msg=ms_strdup_printf(_("We are transferred to %s"),referto);
lc->vtable.display_status(lc,msg);
ms_free(msg);
}
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);
}else if (lc->vtable.refer_received){
lc->vtable.refer_received(lc,referto);
if (op) sal_refer_accept(op);
sal_call_accept_refer(op);
}
}
@ -423,10 +620,10 @@ static void text_received(Sal *sal, const char *from, const char *msg){
static void notify(SalOp *op, const char *from, const char *msg){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer (op);
ms_message("get a %s notify from %s",msg,from);
if(lc->vtable.notify_recv)
lc->vtable.notify_recv(lc,from,msg);
lc->vtable.notify_recv(lc,call,from,msg);
}
static void notify_presence(SalOp *op, SalSubscribeState ss, SalPresenceStatus status, const char *msg){
@ -454,10 +651,14 @@ static void ping_reply(SalOp *op){
LinphoneCall *call=(LinphoneCall*) sal_op_get_user_pointer(op);
ms_message("ping reply !");
if (call){
if (call->state==LCStatePreEstablishing){
if (call->state==LinphoneCallOutgoingInit){
linphone_core_start_invite(call->core,call,NULL);
}
}
else
{
ms_warning("ping reply without call attached...");
}
}
SalCallbacks linphone_sal_callbacks={
@ -465,7 +666,7 @@ SalCallbacks linphone_sal_callbacks={
call_ringing,
call_accepted,
call_ack,
call_updated,
call_updating,
call_terminated,
call_failure,
auth_requested,

View file

@ -33,7 +33,6 @@
cr->lc=lc;
cr->peer=linphone_address_as_string(parsed_url);
cr->peer_url=parsed_url;
cr->route=ms_strdup(linphone_core_get_route(lc));
lc->chatrooms=ms_list_append(lc->chatrooms,(void *)cr);
return cr;
}
@ -46,21 +45,29 @@
lc->chatrooms=ms_list_remove(lc->chatrooms,(void *) cr);
linphone_address_destroy(cr->peer_url);
ms_free(cr->peer);
ms_free(cr->route);
if (cr->op)
sal_op_release(cr->op);
}
void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg){
const char *identity=linphone_core_get_identity(cr->lc);
const char *route=NULL;
const char *identity=linphone_core_find_best_identity(cr->lc,cr->peer_url,&route);
SalOp *op;
if(linphone_core_is_in_communication_with(cr->lc,cr->peer))
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 = cr->lc->call->op;
op = call->op;
}
else
{
op = sal_op_new(cr->lc->sal);
sal_op_set_route(op,cr->route);
sal_op_set_route(op,route);
if (cr->op!=NULL){
sal_op_release (cr->op);
cr->op=NULL;
}
cr->op=op;
}
sal_text_send(op,identity,cr->peer,msg);
}
@ -71,7 +78,7 @@ bool_t linphone_chat_room_matches(LinphoneChatRoom *cr, const LinphoneAddress *f
return FALSE;
}
void linphone_chat_room_text_received(LinphoneChatRoom *cr, LinphoneCore *lc, const char *from, const char *msg){
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);
}
@ -95,8 +102,9 @@ 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);
}
linphone_address_destroy(addr);
linphone_chat_room_text_received(cr,lc,cleanfrom,msg);
linphone_chat_room_text_received(cr,lc,cr->peer_url,msg);
ms_free(cleanfrom);
}
@ -107,3 +115,6 @@ void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void * ud){
void * linphone_chat_room_get_user_data(LinphoneChatRoom *cr){
return cr->user_data;
}
const LinphoneAddress* linphone_chat_room_get_peer_address(LinphoneChatRoom *cr) {
return cr->peer_url;
}

File diff suppressed because it is too large Load diff

View file

@ -1,40 +0,0 @@
/*
linphone
Copyright (C) 2000 Simon MORLAT (simon.morlat@free.fr)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef EXEVENTS_H
#define EXEVENTS_H
#include <eXosip2/eXosip.h>
#include "sdphandler.h"
void linphone_core_process_event(LinphoneCore *lc, eXosip_event_t *ev);
/* these are the SdpHandler callbacks: we are called in to be aware of the content
of the SDP messages exchanged */
int linphone_set_audio_offer(sdp_context_t *ctx);
int linphone_set_video_offer(sdp_context_t *ctx);
int linphone_accept_audio_offer(sdp_context_t *ctx,sdp_payload_t *payload);
int linphone_accept_video_offer(sdp_context_t *ctx,sdp_payload_t *payload);
int linphone_read_audio_answer(sdp_context_t *ctx,sdp_payload_t *payload);
int linphone_read_video_answer(sdp_context_t *ctx,sdp_payload_t *payload);
void linphone_core_text_received(LinphoneCore *lc, eXosip_event_t *ev);
#endif

View file

@ -29,37 +29,37 @@
const char *linphone_online_status_to_string(LinphoneOnlineStatus ss){
const char *str=NULL;
switch(ss){
case LINPHONE_STATUS_ONLINE:
case LinphoneStatusOnline:
str=_("Online");
break;
case LINPHONE_STATUS_BUSY:
case LinphoneStatusBusy:
str=_("Busy");
break;
case LINPHONE_STATUS_BERIGHTBACK:
case LinphoneStatusBeRightBack:
str=_("Be right back");
break;
case LINPHONE_STATUS_AWAY:
case LinphoneStatusAway:
str=_("Away");
break;
case LINPHONE_STATUS_ONTHEPHONE:
case LinphoneStatusOnThePhone:
str=_("On the phone");
break;
case LINPHONE_STATUS_OUTTOLUNCH:
case LinphoneStatusOutToLunch:
str=_("Out to lunch");
break;
case LINPHONE_STATUS_NOT_DISTURB:
case LinphoneStatusDoNotDisturb:
str=_("Do not disturb");
break;
case LINPHONE_STATUS_MOVED:
case LinphoneStatusMoved:
str=_("Moved");
break;
case LINPHONE_STATUS_ALT_SERVICE:
case LinphoneStatusAltService:
str=_("Using another messaging service");
break;
case LINPHONE_STATUS_OFFLINE:
case LinphoneStatusOffline:
str=_("Offline");
break;
case LINPHONE_STATUS_PENDING:
case LinphoneStatusPending:
str=_("Pending");
break;
default:
@ -68,31 +68,11 @@ const char *linphone_online_status_to_string(LinphoneOnlineStatus ss){
return str;
}
static int friend_data_compare(const void * a, const void * b, void * data){
static int friend_compare(const void * a, const void * b){
LinphoneAddress *fa=((LinphoneFriend*)a)->uri;
LinphoneAddress *fb=((LinphoneFriend*)b)->uri;
const char *ua,*ub;
ua=linphone_address_get_username(fa);
ub=linphone_address_get_username(fb);
if (ua!=NULL && ub!=NULL) {
//printf("Comparing usernames %s,%s\n",ua,ub);
return strcasecmp(ua,ub);
}
else {
/* compare hosts*/
ua=linphone_address_get_domain(fa);
ub=linphone_address_get_domain(fb);
if (ua!=NULL && ub!=NULL){
int ret=strcasecmp(ua,ub);
//printf("Comparing hostnames %s,%s,res=%i\n",ua,ub,ret);
return ret;
}
else return -1;
}
}
static int friend_compare(const void * a, const void * b){
return friend_data_compare(a,b,NULL);
if (linphone_address_weak_equal (fa,fb)) return 0;
return 1;
}
@ -128,6 +108,7 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){
char *friend=NULL;
const char *route=NULL;
const char *from=NULL;
const char *fixed_contact=NULL;
LinphoneProxyConfig *cfg;
friend=linphone_address_as_string(fr->uri);
@ -135,10 +116,16 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){
if (cfg!=NULL){
route=linphone_proxy_config_get_route(cfg);
from=linphone_proxy_config_get_identity(cfg);
if (cfg->op){
fixed_contact=sal_op_get_contact(cfg->op);
if (fixed_contact) {
ms_message("Contact for subscribe has been fixed using proxy to %s",fixed_contact);
}
}
}else from=linphone_core_get_primary_contact(fr->lc);
if (fr->outsub==NULL){
/* people for which we don't have yet an answer should appear as offline */
fr->status=LINPHONE_STATUS_OFFLINE;
fr->status=LinphoneStatusOffline;
/*
if (fr->lc->vtable.notify_recv)
fr->lc->vtable.notify_recv(fr->lc,(LinphoneFriend*)fr);
@ -149,6 +136,7 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){
}
fr->outsub=sal_op_new(fr->lc->sal);
sal_op_set_route(fr->outsub,route);
sal_op_set_contact(fr->outsub,fixed_contact);
sal_subscribe_presence(fr->outsub,from,friend);
fr->subscribe_active=TRUE;
ms_free(friend);
@ -157,14 +145,19 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){
LinphoneFriend * linphone_friend_new(){
LinphoneFriend *obj=ms_new0(LinphoneFriend,1);
obj->pol=LinphoneSPAccept;
obj->status=LINPHONE_STATUS_OFFLINE;
obj->status=LinphoneStatusOffline;
obj->subscribe=TRUE;
return obj;
}
LinphoneFriend *linphone_friend_new_with_addr(const char *addr){
LinphoneAddress* linphone_address = linphone_address_new(addr);
if (linphone_address == NULL) {
ms_error("Cannot create friend for address [%s]",addr?addr:"null");
return NULL;
}
LinphoneFriend *fr=linphone_friend_new();
if (linphone_friend_set_sip_addr(fr,addr)<0){
if (linphone_friend_set_addr(fr,linphone_address)<0){
linphone_friend_destroy(fr);
return NULL;
}
@ -208,8 +201,8 @@ void linphone_core_interpret_friend_uri(LinphoneCore *lc, const char *uri, char
linphone_address_destroy(fr);
}
int linphone_friend_set_sip_addr(LinphoneFriend *lf, const char *addr){
LinphoneAddress *fr=linphone_address_new(addr);
int linphone_friend_set_addr(LinphoneFriend *lf, const LinphoneAddress *addr){
LinphoneAddress *fr=linphone_address_clone(addr);
if (fr==NULL) {
ms_warning("Invalid friend sip uri: %s",addr);
return -1;
@ -230,7 +223,7 @@ int linphone_friend_set_name(LinphoneFriend *lf, const char *name){
return 0;
}
int linphone_friend_send_subscribe(LinphoneFriend *fr, bool_t val){
int linphone_friend_enable_subscribes(LinphoneFriend *fr, bool_t val){
fr->subscribe=val;
return 0;
}
@ -243,37 +236,37 @@ int linphone_friend_set_inc_subscribe_policy(LinphoneFriend *fr, LinphoneSubscri
SalPresenceStatus linphone_online_status_to_sal(LinphoneOnlineStatus os){
switch(os){
case LINPHONE_STATUS_OFFLINE:
case LinphoneStatusOffline:
return SalPresenceOffline;
break;
case LINPHONE_STATUS_ONLINE:
case LinphoneStatusOnline:
return SalPresenceOnline;
break;
case LINPHONE_STATUS_BUSY:
case LinphoneStatusBusy:
return SalPresenceBusy;
break;
case LINPHONE_STATUS_BERIGHTBACK:
case LinphoneStatusBeRightBack:
return SalPresenceBerightback;
break;
case LINPHONE_STATUS_AWAY:
case LinphoneStatusAway:
return SalPresenceAway;
break;
case LINPHONE_STATUS_ONTHEPHONE:
case LinphoneStatusOnThePhone:
return SalPresenceOnthephone;
break;
case LINPHONE_STATUS_OUTTOLUNCH:
case LinphoneStatusOutToLunch:
return SalPresenceOuttolunch;
break;
case LINPHONE_STATUS_NOT_DISTURB:
case LinphoneStatusDoNotDisturb:
return SalPresenceDonotdisturb;
break;
case LINPHONE_STATUS_MOVED:
case LinphoneStatusMoved:
return SalPresenceMoved;
break;
case LINPHONE_STATUS_ALT_SERVICE:
case LinphoneStatusAltService:
return SalPresenceAltService;
break;
case LINPHONE_STATUS_PENDING:
case LinphoneStatusPending:
return SalPresenceOffline;
break;
default:
@ -347,7 +340,7 @@ void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc){
if (fr->inc_subscribe_pending){
switch(fr->pol){
case LinphoneSPWait:
linphone_friend_notify(fr,LINPHONE_STATUS_PENDING);
linphone_friend_notify(fr,LinphoneStatusPending);
break;
case LinphoneSPAccept:
if (fr->lc!=NULL)
@ -356,7 +349,7 @@ void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc){
}
break;
case LinphoneSPDeny:
linphone_friend_notify(fr,LINPHONE_STATUS_OFFLINE);
linphone_friend_notify(fr,LinphoneStatusOffline);
break;
}
fr->inc_subscribe_pending=FALSE;
@ -367,6 +360,7 @@ void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc){
}
ms_message("linphone_friend_apply() done.");
lc->bl_refresh=TRUE;
fr->commit=FALSE;
}
void linphone_friend_edit(LinphoneFriend *fr){
@ -391,7 +385,8 @@ void linphone_core_add_friend(LinphoneCore *lc, LinphoneFriend *lf)
return ;
}
lc->friends=ms_list_append(lc->friends,lf);
linphone_friend_apply(lf,lc);
if ( linphone_core_ready(lc)) linphone_friend_apply(lf,lc);
else lf->commit=TRUE;
return ;
}
@ -404,6 +399,15 @@ void linphone_core_remove_friend(LinphoneCore *lc, LinphoneFriend* fl){
}
}
void linphone_core_send_initial_subscribes(LinphoneCore *lc){
const MSList *elem;
for(elem=lc->friends;elem!=NULL;elem=elem->next){
LinphoneFriend *f=(LinphoneFriend*)elem->data;
if (f->commit)
linphone_friend_apply(f,lc);
}
}
void linphone_friend_set_ref_key(LinphoneFriend *lf, const char *key){
if (lf->refkey!=NULL){
ms_free(lf->refkey);
@ -562,7 +566,7 @@ void linphone_core_write_friends_config(LinphoneCore* lc)
{
MSList *elem;
int i;
if (!lc->ready) return; /*dont write config when reading it !*/
if (! linphone_core_ready(lc)) return; /*dont write config when reading it !*/
for (elem=lc->friends,i=0; elem!=NULL; elem=ms_list_next(elem),i++){
linphone_friend_write_to_config_file(lc->config,(LinphoneFriend*)elem->data,i);
}

View file

@ -1,117 +0,0 @@
/****************************************************************************
*
* File: general_state.c
*
* Copyright (C) 2006, 2007 Thomas Reitmayr <treitmayr@yahoo.com>
*
****************************************************************************
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
****************************************************************************/
#include "linphonecore.h"
#include "private.h"
#if 0
static const char *_gstates_text[] = {
"GSTATE_POWER_OFF", /* 0 */
"GSTATE_POWER_STARTUP", /* 1 */
"GSTATE_POWER_ON", /* 2 */
"GSTATE_POWER_SHUTDOWN", /* 3 */
NULL, NULL, NULL, NULL, NULL, NULL,
"GSTATE_REG_NONE", /* 10 */
"GSTATE_REG_OK", /* 11 */
"GSTATE_REG_FAILED", /* 12 */
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
"GSTATE_CALL_IDLE", /* 20 */
"GSTATE_CALL_OUT_INVITE", /* 21 */
"GSTATE_CALL_OUT_CONNECTED", /* 22 */
"GSTATE_CALL_IN_INVITE", /* 23 */
"GSTATE_CALL_IN_CONNECTED", /* 24 */
"GSTATE_CALL_END", /* 25 */
"GSTATE_CALL_ERROR" /* 26 */
};
#endif
/* set the initial states */
void gstate_initialize(LinphoneCore *lc) {
lc->gstate_power = GSTATE_POWER_OFF;
lc->gstate_reg = GSTATE_REG_NONE;
lc->gstate_call = GSTATE_CALL_IDLE;
}
gstate_t linphone_core_get_state(const LinphoneCore *lc, gstate_group_t group){
switch(group){
case GSTATE_GROUP_POWER:
return lc->gstate_power;
case GSTATE_GROUP_REG:
return lc->gstate_reg;
case GSTATE_GROUP_CALL:
return lc->gstate_call;
}
return GSTATE_INVALID;
}
static void linphone_core_set_state(LinphoneCore *lc, gstate_group_t group, gstate_t new_state){
switch(group){
case GSTATE_GROUP_POWER:
lc->gstate_power=new_state;
break;
case GSTATE_GROUP_REG:
lc->gstate_reg=new_state;
break;
case GSTATE_GROUP_CALL:
lc->gstate_call=new_state;
break;
}
}
void gstate_new_state(struct _LinphoneCore *lc,
gstate_t new_state,
const char *message) {
LinphoneGeneralState states_arg;
/* determine the affected group */
if (new_state < GSTATE_REG_NONE)
states_arg.group = GSTATE_GROUP_POWER;
else if (new_state < GSTATE_CALL_IDLE)
states_arg.group = GSTATE_GROUP_REG;
else
states_arg.group = GSTATE_GROUP_CALL;
/* store the new state while remembering the old one */
states_arg.new_state = new_state;
states_arg.old_state = linphone_core_get_state(lc,states_arg.group);
linphone_core_set_state(lc, states_arg.group,new_state);
states_arg.message = message;
/*printf("gstate_new_state: %s\t-> %s\t(%s)\n",
_gstates_text[states_arg.old_state],
_gstates_text[states_arg.new_state],
message);*/
/* call the virtual method */
if (lc->vtable.general_state)
lc->vtable.general_state(lc, &states_arg);
/* immediately proceed to idle state */
if (new_state == GSTATE_CALL_END ||
new_state == GSTATE_CALL_ERROR)
gstate_new_state(lc, GSTATE_CALL_IDLE, NULL);
}

View file

@ -89,7 +89,7 @@ RECURSIVE = NO
EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS =
EXAMPLE_PATH = ../
EXAMPLE_PATH = ../../ .
EXAMPLE_PATTERNS =
EXAMPLE_RECURSIVE = NO
IMAGE_PATH =

View file

@ -1,7 +1,7 @@
EXTRA_DIST = Doxyfile.in doxygen.dox.in
EXTRA_DIST = Doxyfile.in doxygen.dox
SOURCES=$(top_srcdir)/coreapi/*.h $(top_srcdir)/coreapi/*.c
SOURCES= doxygen.dox $(top_srcdir)/coreapi/help/*.c $(top_srcdir)/coreapi/*.c $(top_srcdir)/coreapi/*.h
#html doc
@ -31,3 +31,40 @@ endif
clean-local:
rm -rf doc
noinst_PROGRAMS=helloworld registration buddy_status chatroom
helloworld_SOURCES=helloworld.c
helloworld_LDADD=$(top_builddir)/coreapi/liblinphone.la \
$(MEDIASTREAMER_LIBS) \
$(ORTP_LIBS)
registration_SOURCES=registration.c
registration_LDADD=$(helloworld_LDADD)
buddy_status_SOURCES=buddy_status.c
buddy_status_LDADD=$(helloworld_LDADD)
chatroom_SOURCES=chatroom.c
chatroom_LDADD=$(helloworld_LDADD)
INCLUDES=-I$(top_srcdir)/coreapi \
$(MEDIASTREAMER_CFLAGS)
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)

137
coreapi/help/buddy_status.c Normal file
View file

@ -0,0 +1,137 @@
/*
buddy_status
Copyright (C) 2010 Belledonne Communications SARL
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.
*/
/**
* @defgroup buddy_tutorials Basic buddy status notification
* @ingroup tutorials
*This program is a _very_ simple usage example of liblinphone,
*demonstrating how to initiate SIP subscriptions and receive notifications from a sip uri identity passed from the command line.
*<br>Argument must be like sip:jehan@sip.linphone.org .
*<br>
*ex budy_list sip:jehan@sip.linphone.org
*<br>Subscription is cleared on SIGINT
*<br>
*@include buddy_status.c
*
*/
#ifdef IN_LINPHONE
#include "linphonecore.h"
#else
#include "linphone/linphonecore.h"
#endif
#include <signal.h>
static bool_t running=TRUE;
static void stop(int signum){
running=FALSE;
}
/**
* presence state change notification callback
*/
static void notify_presence_recv_updated (LinphoneCore *lc, LinphoneFriend *friend) {
const LinphoneAddress* friend_address = linphone_friend_get_address(friend);
printf("New state state [%s] for user id [%s] \n"
,linphone_online_status_to_string(linphone_friend_get_status(friend))
,linphone_address_as_string (friend_address));
}
static void new_subscription_request (LinphoneCore *lc, LinphoneFriend *friend, const char* url) {
const LinphoneAddress* friend_address = linphone_friend_get_address(friend);
printf(" [%s] wants to see your status, accepting\n"
,linphone_address_as_string (friend_address));
linphone_friend_edit(friend); /* start editing friend */
linphone_friend_set_inc_subscribe_policy(friend,LinphoneSPAccept); /* Accept incoming subscription request for this friend*/
linphone_friend_done(friend); /*commit change*/
linphone_core_add_friend(lc,friend); /* add this new friend to the buddy list*/
}
LinphoneCore *lc;
int main(int argc, char *argv[]){
LinphoneCoreVTable vtable={0};
char* dest_friend=NULL;
/* takes sip uri identity from the command line arguments */
if (argc>1){
dest_friend=argv[1];
}
signal(SIGINT,stop);
//#define DEBUG
#ifdef DEBUG
linphone_core_enable_logs(NULL); /*enable liblinphone logs.*/
#endif
/*
Fill the LinphoneCoreVTable with application callbacks.
All are optional. Here we only use the both notify_presence_recv and new_subscription_request callbacks
in order to get notifications about friend status.
*/
vtable.notify_presence_recv=notify_presence_recv_updated;
vtable.new_subscription_request=new_subscription_request;
/*
Instantiate a LinphoneCore object given the LinphoneCoreVTable
*/
lc=linphone_core_new(&vtable,NULL,NULL,NULL);
LinphoneFriend* my_friend=NULL;
if (dest_friend) {
my_friend = linphone_friend_new_with_addr(dest_friend); /*creates friend object from dest*/
if (my_friend == NULL) {
printf("bad destination uri for friend [%s]\n",dest_friend);
goto end;
}
linphone_friend_enable_subscribes(my_friend,TRUE); /*configure this friend to emit SUBSCRIBE message after being added to LinphoneCore*/
linphone_friend_set_inc_subscribe_policy(my_friend,LinphoneSPAccept); /* Accept incoming subscription request for this friend*/
linphone_core_add_friend(lc,my_friend); /* add my friend to the buddy list, initiate SUBSCRIBE message*/
}
linphone_core_set_presence_info(lc,0,NULL,LinphoneStatusOnline); /*set my status to online*/
/* main loop for receiving notifications and doing background linphone core work: */
while(running){
linphone_core_iterate(lc); /* first iterate initiates subscription */
ms_usleep(50000);
}
linphone_core_set_presence_info(lc,0,NULL,LinphoneStatusOffline); /* change my presence status to offline*/
linphone_core_iterate(lc); /* just to make sure new status is initiate message is issued */
linphone_friend_edit(my_friend); /* start editing friend */
linphone_friend_enable_subscribes(my_friend,FALSE); /*disable subscription for this friend*/
linphone_friend_done(my_friend); /*commit changes triggering an UNSUBSCRIBE message*/
linphone_core_iterate(lc); /* just to make sure unsubscribe message is issued */
end:
printf("Shutting down...\n");
linphone_core_destroy(lc);
printf("Exited\n");
return 0;
}

100
coreapi/help/chatroom.c Normal file
View file

@ -0,0 +1,100 @@
/*
linphone
Copyright (C) 2010 Belledonne Communications SARL
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.
*/
/**
* @defgroup chatroom_tuto Chat room and messaging
* @ingroup tutorials
*This program is a _very_ simple usage example of liblinphone,
*desmonstrating how to send/receive SIP MESSAGE from a sip uri identity passed from the command line.
*<br>Argument must be like sip:jehan@sip.linphone.org .
*<br>
*ex chatroom sip:jehan@sip.linphone.org
*<br>
*@include chatroom.c
*
*/
#ifdef IN_LINPHONE
#include "linphonecore.h"
#else
#include "linphone/linphonecore.h"
#endif
#include <signal.h>
static bool_t running=TRUE;
static void stop(int signum){
running=FALSE;
}
void text_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from, const char *message) {
printf(" Message [%s] received from [%s] \n",message,linphone_address_as_string (from));
}
LinphoneCore *lc;
int main(int argc, char *argv[]){
LinphoneCoreVTable vtable={0};
char* dest_friend=NULL;
/* takes sip uri identity from the command line arguments */
if (argc>1){
dest_friend=argv[1];
}
signal(SIGINT,stop);
//#define DEBUG
#ifdef DEBUG
linphone_core_enable_logs(NULL); /*enable liblinphone logs.*/
#endif
/*
Fill the LinphoneCoreVTable with application callbacks.
All are optional. Here we only use the text_received callback
in order to get notifications about incoming message.
*/
vtable.text_received=text_received;
/*
Instantiate a LinphoneCore object given the LinphoneCoreVTable
*/
lc=linphone_core_new(&vtable,NULL,NULL,NULL);
/*Next step is to create a chat root*/
LinphoneChatRoom* chat_room = linphone_core_create_chat_room(lc,dest_friend);
linphone_chat_room_send_message(chat_room,"Hello world"); /*sending message*/
/* main loop for receiving incoming messages and doing background linphone core work: */
while(running){
linphone_core_iterate(lc);
ms_usleep(50000);
}
printf("Shutting down...\n");
linphone_chat_room_destroy(chat_room);
linphone_core_destroy(lc);
printf("Exited\n");
return 0;
}

193
coreapi/help/doxygen.dox Normal file
View file

@ -0,0 +1,193 @@
/**
* @mainpage
*
* @see http://www.linphone.org
*
* @section what_is_it What is liblinphone
*
* Liblinphone is a high level library for bringing SIP video call functionnality
* into an application. It aims at making easy the integration of the SIP
* video calls into any applications. All variants of linphone are directly based
* on it:
* - linphone (gtk interface)
*
* - linphonec (console interface)
*
* Liblinphone is GPL (see COPYING file). Please understand the licencing details
* before using it!
*
* For any use of this library beyond the rights granted to you by the
* GPL license, please contact Belledonne Communications
* (contact@belledonne-communications.com)
*
*
**/
/**
* @page liblinphone_license COPYING
* @verbinclude COPYING
*/
/**
* @defgroup initializing Initializing liblinphone
**/
/**
* @defgroup call_control Placing and receiving calls
**/
/**
* @defgroup media_parameters Controlling media parameters
**/
/**
* @defgroup proxies Managing proxies
*User registration is controled by #LinphoneProxyConfig settings.<br> Each #LinphoneProxyConfig object can be configured with registration informations
*like \link linphone_proxy_config_set_server_addr() proxy address \endlink , \link linphone_proxy_config_set_identity() user id \endlink, \link linphone_proxy_config_expires() refresh period \endlink, and so on.
*<br> A created proxy config using linphone_proxy_config_new(), once configured, must be added to #LinphoneCore using function linphone_core_add_proxy_config().
*<br> It is recommended to set a default \link #LinphoneProxyConfig proxy config \endlink using function linphone_core_set_default_proxy(). Once done, if \link #LinphoneProxyConfig a proxy config \endlink has been configured with attribute \link linphone_proxy_config_enable_register() enable register \endlink , next call to linphone_core_iterate() triggers a SIP register.
*<br> Registration status is reported by #LinphoneRegistrationStateCb.
*<br>
*<br> This pseudo code demonstrates basic registration operations:
*<br> \code
*
* LinphoneProxyConfig* proxy_cfg;
* /*create proxy config*/
* proxy_cfg = linphone_proxy_config_new();
* /*parse identity*/
* LinphoneAddress *from = linphone_address_new("sip:toto@sip.titi.com");
* LinphoneAuthInfo *info;
* if (password!=NULL){
* info=linphone_auth_info_new(linphone_address_get_username(from),NULL,"secret",NULL,NULL); /*create authentication structure from identity*/
* linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/
* }
* // configure proxy entries
* linphone_proxy_config_set_identity(proxy_cfg,identity); /*set identity with user name and domain*/
* const char* server_addr = linphone_address_get_domain(from); /*extract domain address from identity*/
* linphone_proxy_config_set_server_addr(proxy_cfg,server_addr); /* we assume domain = proxy server address*/
* linphone_proxy_config_enable_register(proxy_cfg,TRUE); /*activate registration for this proxy config*/
* linphone_address_destroy(from); /*release resource*/
*
* linphone_core_add_proxy_config(lc,proxy_cfg); /*add proxy config to linphone core*/
* linphone_core_set_default_proxy(lc,proxy_cfg); /*set to default proxy*/ \endcode
*<br>
* Registration sate call back:
\code
static void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message){
printf("New registration state %s for user id [%s] at proxy [%s]\n"
,linphone_registration_state_to_string(cstate)
,linphone_proxy_config_get_identity(cfg)
,linphone_proxy_config_get_addr(cfg));
}
\endcode
*<br><b>Authentication:</b>
*<br>Most of the time, registration requires \ref authentication "authentication" to succed. #LinphoneAuthInfo info must be either added to #LinphoneCore using function linphone_core_add_auth_info() before #LinphoneProxyConfig is added to Linphone core, or on demand from call back #AuthInfoRequested .
*<br>
*<br><b>Unregistration:</b>
*<br> Unregistration or any changes to #LinphoneProxyConfig must be first started by a call to function linphone_proxy_config_edit() and validated by function linphone_proxy_config_done()
*<br> This pseudo code shows how to unregister a user associated to a #LinphoneProxyConfig
*\code
LinphoneProxyConfig* proxy_cfg;
linphone_core_get_default_proxy(lc,&proxy_cfg); /* get default proxy config*/
linphone_proxy_config_edit(proxy_cfg); /*start editing proxy configuration*/
linphone_proxy_config_enable_register(proxy_cfg,FALSE); /*de-activate registration for this proxy config*/
linphone_proxy_config_done(proxy_cfg); /*initiate REGISTER with expire = 0*/
\endcode
<br>
A complete tutorial can be found at : \ref registration_tutorials "Registration tutorial"
**/
/**
* @defgroup network_parameters Controlling network parameters (ports, mtu...)
**/
/**
* @defgroup authentication Managing authentication: userid and passwords
**/
/**
* @defgroup buddy_list Managing Buddies and buddy list and presence
<b>Buddies and buddy list</b>
<br>Each buddy is represented by a #LinphoneFriend object created by function linphone_friend_new().
Buddy configuration parameters like \link linphone_friend_set_addr() sip uri \endlink or \link linphone_friend_set_inc_subscribe_policy() status publication \endlink policy for this \link #LinphoneFriend friend \endlink are configurable for each buddy.
<br>Here under a typical buddy creation:
<br>
\code
LinphoneFriend* my_friend=linphone_friend_new_with_addr("sip:joe@sip.linphone.org"); /*creates friend object for buddy joe*/
linphone_friend_enable_subscribes(my_friend,TRUE); /*configure this friend to emit SUBSCRIBE message after being added to LinphoneCore*/
linphone_friend_set_inc_subscribe_policy(my_friend,LinphoneSPAccept); /* accept Incoming subscription request for this friend*/
\endcode
\link #LinphoneFriend friends \endlink status changes are reported by callback LinphoneCoreVTable.notify_presence_recv
\code
static void notify_presence_recv_updated (struct _LinphoneCore *lc, LinphoneFriend *friend) {
const LinphoneAddress* friend_address = linphone_friend_get_address(friend);
printf("New state state [%s] for user id [%s] \n"
,linphone_online_status_to_string(linphone_friend_get_status(friend))
,linphone_address_as_string (friend_address));
}
\endcode
<br>Once created a buddy can be added to the buddy list using function linphone_core_add_friend() . Added friends will be notified about \link linphone_core_set_presence_info() local status changes \endlink
<br>
Any subsequente modifications to #LinphoneFriend must be first started by a call to function linphone_friend_edit() and validated by function linphone_friend_done()
\code
linphone_friend_edit(my_friend); /* start editing friend */
linphone_friend_enable_subscribes(my_friend,FALSE); /*disable subscription for this friend*/
linphone_friend_done(my_friend); /*commit changes triggering an UNSUBSCRIBE message*/
\endcode
<b> Publishing presence status </b>
<br>Local presence status can be changed using function linphone_core_set_presence_info() .New status is propagated to all friends \link linphone_core_add_friend() previously added \endlink to #LinphoneCore.
<b>Handling incoming subscription request</b>
<br> New incoming subscription requests are process according to \link linphone_friend_set_inc_subscribe_policy() the incoming subscription policy state \endlink for subscription initiated by \link linphone_core_add_friend() members of the buddy list. \endlink
<br> For incoming request comming from an unknown buddy, the call back LinphoneCoreVTable.new_subscription_request is invoked.
<br> A complete tutorial can be found at : \ref buddy_tutorials "Registration tutorial"
**/
/**
* @defgroup chatroom Chat room and Messaging
<b> Exchanging text messages</b>
<br> Messages are sent using #LinphoneChatRoom object. First step is to create a \link linphone_core_create_chat_room() chat room \endlink
from a peer sip uri.
\code
LinphoneChatRoom* chat_room = linphone_core_create_chat_room(lc,"sip:joe@sip.linphone.org");
\endcode
<br>Once created, messages are sent using function linphone_chat_room_send_message() .
\code
linphone_chat_room_send_message(chat_room,"Hello world"); /*sending message*/
\endcode
<br>Incoming message are received from call back LinphoneCoreVTable.text_received
\code
void text_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from, const char *message) {
printf(" Message [%s] received from [%s] \n",message,linphone_address_as_string (from));
}
\endcode
<br> A complete tutorial can be found at : \ref chatroom_tuto "Chat room tutorial"
**/
/**
* @defgroup call_logs Managing call logs
**/
/**
* @defgroup linphone_address SIP address parser API.
* This api is useful for manipulating SIP addresses ('from' or 'to' headers).
**/
/**
* @defgroup misc Miscenalleous: logs, version strings, config storage
**/
/**
* @defgroup tutorials Tutorials:
*
**/

View file

@ -1,119 +0,0 @@
/**
* @mainpage
*
* @see http://www.linphone.org
*
* @section what_is_it What is liblinphone
*
* Liblinphone is a high level library for bringing SIP video call functionnality
* into an application. It aims at making easy the integration of the SIP
* video calls into any applications. All variants of linphone are directly based
* on it:
* - linphone (gtk interface)
*
* - linphonec (console interface)
*
* Liblinphone is GPL (see COPYING file). Please understand the licencing details
* before using it!
*
* For any use of this library beyond the rights granted to you by the
* GPL license, please contact Belledonne Communications
* (contact@belledonne-communications.com)
*
*
**/
/**
* @page liblinphone_license COPYING
* @verbinclude COPYING
*/
/**
* @defgroup tutorial_liblinphone Tutorial: Placing and receiving calls with liblinphone
*
<H1>Initialize liblinphone</H1>
The first thing to do is to initialize the library passing it a set of callbacks functions to receive
various notifications: incoming calls, progress of calls etc...
These callbacks are all grouped in the LinphoneCoreVTable structure.
All are optionnals (use NULL if you don't need them).
The following code shows how initialize liblinphone:
<PRE>
##include <linphonecore.h>
//callback function for notification of incoming calls
static void on_invite_recv(LinphoneCore *lc, const char *from){
printf("Receiving a call from %s\n",from);
}
//callback function for notification end of calls (by remote)
static void on_bye_recv(LinphoneCore *lc, const char *from){
printf("Remote end hangup\n");
}
/
static void on_display_status(LinphoneCore *lc, const char *msg){
printf("%s",msg);
}
int main(int argc, char *argv[]){
LinphoneCoreVTable vtable;
memset(&vtable,0,sizeof(vtable));
vtable.inv_recv=&on_invite_recv;
vtable.bye_recv=&on_bye_recv;
vtable.display_status=&on_display_status;
}
</PRE>
/**
* @defgroup initializing Initialization and destruction
*
**/
/**
* @defgroup call_control Call control
*
* The application can initiate outgoing calls with linphone_core_invite().
* It is notified of incoming call thanks to the inv_recv callback of the LinphoneCoreVTable
* structure that is passed at creation of the LinphoneCore object.
* It can then answer calls with linphone_core_accept_call().
* Calls can be terminated or declined with linphone_core_terminate_call().
* The application is notified when the remote party hangups thanks to
* bye_recv callback of the #LinphoneCoreVTable.
**/
/**
* @defgroup media_parameters Controlling media parameters
**/
/**
* @defgroup proxies Managing proxies
**/
/**
* @defgroup network_parameters Controlling network parameters (ports, mtu...)
**/
/**
* @defgroup authentication Managing authentication: userid and passwords
**/
/**
* @defgroup call_logs Managing call logs
**/
/**
* @defgroup linphone_address SIP address parser API.
* This api is useful for manipulating SIP addresses ('from' or 'to' headers).
**/
/**
* @defgroup misc Miscenalleous: logs, version strings, config storage
**/

130
coreapi/help/helloworld.c Normal file
View file

@ -0,0 +1,130 @@
/*
linphone
Copyright (C) 2010 Belledonne Communications SARL
(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.
*/
/**
* @defgroup basic_call_tutorials Basic call
* @ingroup tutorials
This program is a _very_ simple usage example of liblinphone.
It just takes a sip-uri as first argument and attempts to call it
@include helloworld.c
*/
#ifdef IN_LINPHONE
#include "linphonecore.h"
#else
#include "linphone/linphonecore.h"
#endif
#include <signal.h>
static bool_t running=TRUE;
static void stop(int signum){
running=FALSE;
}
/*
* Call state notification callback
*/
static void call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *msg){
switch(cstate){
case LinphoneCallOutgoingRinging:
printf("It is now ringing remotely !\n");
break;
case LinphoneCallOutgoingEarlyMedia:
printf("Receiving some early media\n");
break;
case LinphoneCallConnected:
printf("We are connected !\n");
break;
case LinphoneCallStreamsRunning:
printf("Media streams established !\n");
break;
case LinphoneCallEnd:
printf("Call is terminated.\n");
break;
case LinphoneCallError:
printf("Call failure !");
break;
default:
printf("Unhandled notification %i\n",cstate);
}
}
int main(int argc, char *argv[]){
LinphoneCoreVTable vtable={0};
LinphoneCore *lc;
LinphoneCall *call=NULL;
const char *dest=NULL;
/* take the destination sip uri from the command line arguments */
if (argc>1){
dest=argv[1];
}
signal(SIGINT,stop);
#ifdef DEBUG
linphone_core_enable_logs(NULL); /*enable liblinphone logs.*/
#endif
/*
Fill the LinphoneCoreVTable with application callbacks.
All are optional. Here we only use the call_state_changed callbacks
in order to get notifications about the progress of the call.
*/
vtable.call_state_changed=call_state_changed;
/*
Instanciate a LinphoneCore object given the LinphoneCoreVTable
*/
lc=linphone_core_new(&vtable,NULL,NULL,NULL);
if (dest){
/*
Place an outgoing call
*/
call=linphone_core_invite(lc,dest);
if (call==NULL){
printf("Could not place call to %s\n",dest);
goto end;
}else printf("Call to %s is in progress...",dest);
linphone_call_ref(call);
}
/* main loop for receiving notifications and doing background linphonecore work: */
while(running){
linphone_core_iterate(lc);
ms_usleep(50000);
}
if (call && linphone_call_get_state(call)!=LinphoneCallEnd){
/* terminate the call */
printf("Terminating the call...\n");
linphone_core_terminate_call(lc,call);
/*at this stage we don't need the call object */
linphone_call_unref(call);
}
end:
printf("Shutting down...\n");
linphone_core_destroy(lc);
printf("Exited\n");
return 0;
}

View file

@ -0,0 +1,194 @@
/*
TutorialBuddyStatus
Copyright (C) 2010 Belledonne Communications SARL
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.tutorials;
import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneCall;
import org.linphone.core.LinphoneChatRoom;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCoreException;
import org.linphone.core.LinphoneCoreFactory;
import org.linphone.core.LinphoneCoreListener;
import org.linphone.core.LinphoneFriend;
import org.linphone.core.LinphoneProxyConfig;
import org.linphone.core.OnlineStatus;
import org.linphone.core.LinphoneCall.State;
import org.linphone.core.LinphoneCore.GlobalState;
import org.linphone.core.LinphoneCore.RegistrationState;
import org.linphone.core.LinphoneFriend.SubscribePolicy;
/**
*
* This program is a _very_ simple usage example of liblinphone,
* demonstrating how to initiate SIP subscriptions and receive notifications
* from a sip uri identity passed from the command line.
* <br>Argument must be like sip:jehan@sip.linphone.org .
* ex budy_list sip:jehan@sip.linphone.org
* <br>Subscription is cleared on SIGINT
*
* Ported from buddy_status.c
*
* @author Guillaume Beraudo
*
*/
public class TutorialBuddyStatus implements LinphoneCoreListener {
private boolean running;
private TutorialNotifier TutorialNotifier;
public TutorialBuddyStatus(TutorialNotifier TutorialNotifier) {
this.TutorialNotifier = TutorialNotifier;
}
public TutorialBuddyStatus() {
this.TutorialNotifier = new TutorialNotifier();
}
public void newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf,String url) {
write("["+lf.getAddress().getUserName()+"] wants to see your status, accepting");
lf.edit(); // start editing friend
lf.setIncSubscribePolicy(SubscribePolicy.SPAccept); // accept incoming subscription request for this friend
lf.done(); // commit change
try {
// add this new friend to the buddy list
lc.addFriend(lf);
} catch (LinphoneCoreException e) {
write("Error while adding friend [" + lf.getAddress().getUserName() + "] to linphone in the callback");
}
}
public void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf) {
write("New state [" + lf.getStatus() +"] for user id ["+lf.getAddress().getUserName()+"]");
}
public void registrationState(LinphoneCore lc, LinphoneProxyConfig cfg,RegistrationState cstate, String smessage) {}
public void show(LinphoneCore lc) {}
public void byeReceived(LinphoneCore lc, String from) {}
public void authInfoRequested(LinphoneCore lc, String realm, String username) {}
public void displayStatus(LinphoneCore lc, String message) {}
public void displayMessage(LinphoneCore lc, String message) {}
public void displayWarning(LinphoneCore lc, String message) {}
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 static void main(String[] args) {
// Check tutorial was called with the right number of arguments
if (args.length != 1) {
throw new IllegalArgumentException("Bad number of arguments");
}
// Create tutorial object
TutorialBuddyStatus tutorial = new TutorialBuddyStatus();
try {
// takes sip uri identity from the command line arguments
String userSipAddress = args[1];
tutorial.launchTutorial(userSipAddress);
} catch (Exception e) {
e.printStackTrace();
}
}
public void launchTutorial(String sipAddress) throws LinphoneCoreException {
final LinphoneCoreFactory lcFactory = LinphoneCoreFactory.instance();
// First instantiate the core Linphone object given only a listener.
// The listener will react to events in Linphone core.
LinphoneCore lc = lcFactory.createLinphoneCore(this);
try {
// Create friend object from string address
LinphoneFriend lf = lcFactory.createLinphoneFriend(sipAddress);
if (lf == null) {
write("Could not create friend; weird SIP address?");
return;
}
// configure this friend to emit SUBSCRIBE message after being added to LinphoneCore
lf.enableSubscribes(true);
// accept incoming subscription request for this friend
lf.setIncSubscribePolicy(SubscribePolicy.SPAccept);
try {
// add my friend to the buddy list, initiate SUBSCRIBE message
lc.addFriend(lf);
} catch (LinphoneCoreException e) {
write("Error while adding friend " + lf.getAddress().getUserName() + " to linphone");
return;
}
// set my status to online
lc.setPresenceInfo(0, null, OnlineStatus.Online);
// main loop for receiving notifications and doing background linphonecore work
running = true;
while (running) {
lc.iterate(); // first iterate initiates subscription
try{
Thread.sleep(50);
} catch(InterruptedException ie) {
write("Interrupted!\nAborting");
return;
}
}
// change my presence status to offline
lc.setPresenceInfo(0, null, OnlineStatus.Offline);
// just to make sure new status is initiate message is issued
lc.iterate();
lf.edit(); // start editing friend
lf.enableSubscribes(false); // disable subscription for this friend
lf.done(); // commit changes triggering an UNSUBSCRIBE message
lc.iterate(); // just to make sure unsubscribe message is issued
} finally {
write("Shutting down...");
// You need to destroy the LinphoneCore object when no longer used
lc.destroy();
write("Exited");
}
}
public void stopMainLoop() {
running=false;
}
private void write(String s) {
TutorialNotifier.notify(s);
}
}

View file

@ -0,0 +1,147 @@
/*
TutorialChatRoom.java
Copyright (C) 2010 Belledonne Communications SARL
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.tutorials;
import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneCall;
import org.linphone.core.LinphoneChatRoom;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCoreException;
import org.linphone.core.LinphoneCoreFactory;
import org.linphone.core.LinphoneCoreListener;
import org.linphone.core.LinphoneFriend;
import org.linphone.core.LinphoneProxyConfig;
import org.linphone.core.LinphoneCall.State;
import org.linphone.core.LinphoneCore.GlobalState;
import org.linphone.core.LinphoneCore.RegistrationState;
/**
* This program is a _very_ simple usage example of liblinphone.
* It demonstrates how to send/receive SIP MESSAGE from a sip uri identity
* passed from the command line.
*
* Argument must be like sip:jehan@sip.linphone.org .
*
* ex chatroom sip:jehan@sip.linphone.org
* just takes a sip-uri as first argument and attempts to call it.
*
* Ported from chatroom.c
*
* @author Guillaume Beraudo
*
*/
public class TutorialChatRoom implements LinphoneCoreListener {
private boolean running;
private TutorialNotifier TutorialNotifier;
public TutorialChatRoom(TutorialNotifier TutorialNotifier) {
this.TutorialNotifier = TutorialNotifier;
}
public TutorialChatRoom() {
this.TutorialNotifier = new TutorialNotifier();
}
public void show(LinphoneCore lc) {}
public void byeReceived(LinphoneCore lc, String from) {}
public void authInfoRequested(LinphoneCore lc, String realm, String username) {}
public void displayStatus(LinphoneCore lc, String message) {}
public void displayMessage(LinphoneCore lc, String message) {}
public void displayWarning(LinphoneCore lc, String message) {}
public void globalState(LinphoneCore lc, GlobalState state, String message) {}
public void registrationState(LinphoneCore lc, LinphoneProxyConfig cfg,RegistrationState cstate, String smessage) {}
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 textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from, String message) {
write("Message ["+message+"] received from ["+from.asString()+"]");
}
public static void main(String[] args) {
// Check tutorial was called with the right number of arguments
// Takes the sip uri identity from the command line arguments
if (args.length != 1) {
throw new IllegalArgumentException("Bad number of arguments");
}
// Create tutorial object
TutorialChatRoom tutorial = new TutorialChatRoom();
try {
String destinationSipAddress = args[1];
tutorial.launchTutorial(destinationSipAddress);
} catch (Exception e) {
e.printStackTrace();
}
}
public void launchTutorial(String destinationSipAddress) throws LinphoneCoreException {
// First instantiate the core Linphone object given only a listener.
// The listener will react to events in Linphone core.
LinphoneCore lc = LinphoneCoreFactory.instance().createLinphoneCore(this);
try {
// Next step is to create a chat room
LinphoneChatRoom chatRoom = lc.createChatRoom(destinationSipAddress);
// Send message
chatRoom.sendMessage("Hello world");
// main loop for receiving notifications and doing background linphonecore work
running = true;
while (running) {
lc.iterate();
try{
Thread.sleep(50);
} catch(InterruptedException ie) {
write("Interrupted!\nAborting");
return;
}
}
} finally {
write("Shutting down...");
// You need to destroy the LinphoneCore object when no longer used
lc.destroy();
write("Exited");
}
}
public void stopMainLoop() {
running=false;
}
private void write(String s) {
TutorialNotifier.notify(s);
}
}

View file

@ -0,0 +1,156 @@
/*
TutorialHelloWorld.java
Copyright (C) 2010 Belledonne Communications SARL
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.tutorials;
import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneCall;
import org.linphone.core.LinphoneChatRoom;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCoreException;
import org.linphone.core.LinphoneCoreFactory;
import org.linphone.core.LinphoneCoreListener;
import org.linphone.core.LinphoneFriend;
import org.linphone.core.LinphoneProxyConfig;
import org.linphone.core.LinphoneCall.State;
import org.linphone.core.LinphoneCore.GlobalState;
import org.linphone.core.LinphoneCore.RegistrationState;
/**
* This program is a _very_ simple usage example of liblinphone.
* It just takes a sip-uri as first argument and attempts to call it.
*
* Ported from helloworld.c
*
* @author Guillaume Beraudo
*
*/
public class TutorialHelloWorld implements LinphoneCoreListener {
private boolean running;
private TutorialNotifier TutorialNotifier;
public TutorialHelloWorld(TutorialNotifier TutorialNotifier) {
this.TutorialNotifier = TutorialNotifier;
}
public TutorialHelloWorld() {
this.TutorialNotifier = new TutorialNotifier();
}
public void show(LinphoneCore lc) {}
public void byeReceived(LinphoneCore lc, String from) {}
public void authInfoRequested(LinphoneCore lc, String realm, String username) {}
public void displayStatus(LinphoneCore lc, String message) {}
public void displayMessage(LinphoneCore lc, String message) {}
public void displayWarning(LinphoneCore lc, String message) {}
public void globalState(LinphoneCore lc, GlobalState state, String message) {}
public void registrationState(LinphoneCore lc, LinphoneProxyConfig cfg,RegistrationState cstate, String smessage) {}
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) {}
/*
* Call state notification listener
*/
public void callState(LinphoneCore lc, LinphoneCall call, State cstate, String msg){
write("State: " + msg);
if (State.CallEnd.equals(cstate))
running = false;
}
public static void main(String[] args) {
// Check tutorial was called with the right number of arguments
if (args.length != 1) {
throw new IllegalArgumentException("Bad number of arguments");
}
// Create tutorial object
TutorialHelloWorld helloWorld = new TutorialHelloWorld();
try {
String destinationSipAddress = args[1];
helloWorld.launchTutorial(destinationSipAddress);
} catch (Exception e) {
e.printStackTrace();
}
}
public void launchTutorial(String destinationSipAddress) throws LinphoneCoreException {
// First instantiate the core Linphone object given only a listener.
// The listener will react to events in Linphone core.
LinphoneCore lc = LinphoneCoreFactory.instance().createLinphoneCore(this);
try {
// Send the INVITE message to destination SIP address
LinphoneCall call = lc.invite(destinationSipAddress);
if (call == null) {
write("Could not place call to " + destinationSipAddress);
write("Aborting");
return;
}
write("Call to " + destinationSipAddress + " is in progress...");
// main loop for receiving notifications and doing background linphonecore work
running = true;
while (running) {
lc.iterate();
try{
Thread.sleep(50);
} catch(InterruptedException ie) {
write("Interrupted!\nAborting");
return;
}
}
if (!State.CallEnd.equals(call.getState())) {
write("Terminating the call");
lc.terminateCall(call);
}
} finally {
write("Shutting down...");
// You need to destroy the LinphoneCore object when no longer used
lc.destroy();
write("Exited");
}
}
public void stopMainLoop() {
running=false;
}
private void write(String s) {
TutorialNotifier.notify(s);
}
}

View file

@ -0,0 +1,33 @@
/*
TutorialNotifier.java
Copyright (C) 2010 Belledonne Communications SARL
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.tutorials;
/**
* Notify to the standard output.
* Subclass to define another text output.
*
* @author Guillaume Beraudo
*
*/
public class TutorialNotifier {
public void notify(String s) {
System.out.println(s);
}
}

View file

@ -0,0 +1,170 @@
/*
TutorialRegistration.java
Copyright (C) 2010 Belledonne Communications SARL
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.tutorials;
import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneCall;
import org.linphone.core.LinphoneChatRoom;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCoreException;
import org.linphone.core.LinphoneCoreFactory;
import org.linphone.core.LinphoneCoreListener;
import org.linphone.core.LinphoneFriend;
import org.linphone.core.LinphoneProxyConfig;
import org.linphone.core.LinphoneCall.State;
import org.linphone.core.LinphoneCore.GlobalState;
import org.linphone.core.LinphoneCore.RegistrationState;
/**
* This program is a _very_ simple usage example of liblinphone.
* Demonstrating how to initiate a SIP registration from a sip uri identity
* passed from the command line.
*
* First argument must be like sip:jehan@sip.linphone.org, second must be password.
* <br>
* ex registration sip:jehan@sip.linphone.org secret
*
* Ported from registration.c
*
* @author Guillaume Beraudo
*
*/
public class TutorialRegistration implements LinphoneCoreListener {
private boolean running;
private TutorialNotifier TutorialNotifier;
public TutorialRegistration(TutorialNotifier TutorialNotifier) {
this.TutorialNotifier = TutorialNotifier;
}
public TutorialRegistration() {
this.TutorialNotifier = new TutorialNotifier();
}
/*
* Registration state notification listener
*/
public void registrationState(LinphoneCore lc, LinphoneProxyConfig cfg,RegistrationState cstate, String smessage) {
write(cfg.getIdentity() + " : "+smessage+"\n");
if (RegistrationState.RegistrationOk.equals(cstate))
running = false;
}
public void show(LinphoneCore lc) {}
public void byeReceived(LinphoneCore lc, String from) {}
public void authInfoRequested(LinphoneCore lc, String realm, String username) {}
public void displayStatus(LinphoneCore lc, String message) {}
public void displayMessage(LinphoneCore lc, String message) {}
public void displayWarning(LinphoneCore lc, String message) {}
public void globalState(LinphoneCore lc, GlobalState state, String message) {}
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 callState(LinphoneCore lc, LinphoneCall call, State cstate, String msg) {}
public static void main(String[] args) {
// Check tutorial was called with the right number of arguments
if (args.length != 2) {
throw new IllegalArgumentException("Bad number of arguments");
}
// Create tutorial object
TutorialRegistration tutorial = new TutorialRegistration();
try {
// takes sip uri identity from the command line arguments
String userSipAddress = args[1];
// takes password from the command line arguments
String userSipPassword = args[2];
tutorial.launchTutorial(userSipAddress, userSipPassword);
} catch (Exception e) {
e.printStackTrace();
}
}
public void launchTutorial(String sipAddress, String password) throws LinphoneCoreException {
final LinphoneCoreFactory lcFactory = LinphoneCoreFactory.instance();
// First instantiate the core Linphone object given only a listener.
// The listener will react to events in Linphone core.
LinphoneCore lc = lcFactory.createLinphoneCore(this);
try {
// Parse identity
LinphoneAddress address = lcFactory.createLinphoneAddress(sipAddress);
String username = address.getUserName();
String domain = address.getDomain();
if (password != null) {
// create authentication structure from identity and add to linphone
lc.addAuthInfo(lcFactory.createAuthInfo(username, password, null));
}
// create proxy config
LinphoneProxyConfig proxyCfg = lcFactory.createProxyConfig(sipAddress, domain, null, true);
lc.addProxyConfig(proxyCfg); // add it to linphone
lc.setDefaultProxyConfig(proxyCfg);
// main loop for receiving notifications and doing background linphonecore work
running = true;
while (running) {
lc.iterate(); // first iterate initiates registration
try{
Thread.sleep(50);
} catch(InterruptedException ie) {
write("Interrupted!\nAborting");
return;
}
}
// Automatic unregistration on exit
} finally {
write("Shutting down...");
// You need to destroy the LinphoneCore object when no longer used
lc.destroy();
write("Exited");
}
}
public void stopMainLoop() {
running=false;
}
private void write(String s) {
TutorialNotifier.notify(s);
}
}

142
coreapi/help/registration.c Normal file
View file

@ -0,0 +1,142 @@
/*
linphone
Copyright (C) 2010 Belledonne Communications SARL
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.
*/
/**
* @defgroup registration_tutorials Basic registration
* @ingroup tutorials
*This program is a _very_ simple usage example of liblinphone.
*Desmonstrating how to initiate a SIP registration from a sip uri identity passed from the command line.
*first argument must be like sip:jehan@sip.linphone.org , second must be password .
*<br>
*ex registration sip:jehan@sip.linphone.org secret
*<br>Registration is cleared on SIGINT
*<br>
*@include registration.c
*
*/
#ifdef IN_LINPHONE
#include "linphonecore.h"
#else
#include "linphone/linphonecore.h"
#endif
#include <signal.h>
static bool_t running=TRUE;
static void stop(int signum){
running=FALSE;
}
/**
* Registration state notification callback
*/
static void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message){
printf("New registration state %s for user id [%s] at proxy [%s]\n"
,linphone_registration_state_to_string(cstate)
,linphone_proxy_config_get_identity(cfg)
,linphone_proxy_config_get_addr(cfg));
}
LinphoneCore *lc;
int main(int argc, char *argv[]){
LinphoneCoreVTable vtable={0};
char* identity=NULL;
char* password=NULL;
/* takes sip uri identity from the command line arguments */
if (argc>1){
identity=argv[1];
}
/* takes password from the command line arguments */
if (argc>2){
password=argv[2];
}
signal(SIGINT,stop);
#ifdef DEBUG
linphone_core_enable_logs(NULL); /*enable liblinphone logs.*/
#endif
/*
Fill the LinphoneCoreVTable with application callbacks.
All are optional. Here we only use the registration_state_changed callbacks
in order to get notifications about the progress of the registration.
*/
vtable.registration_state_changed=registration_state_changed;
/*
Instanciate a LinphoneCore object given the LinphoneCoreVTable
*/
lc=linphone_core_new(&vtable,NULL,NULL,NULL);
LinphoneProxyConfig* proxy_cfg;
/*create proxy config*/
proxy_cfg = linphone_proxy_config_new();
/*parse identity*/
LinphoneAddress *from = linphone_address_new(identity);
if (from==NULL){
printf("%s not a valid sip uri, must be like sip:toto@sip.linphone.org \n",identity);
goto end;
}
LinphoneAuthInfo *info;
if (password!=NULL){
info=linphone_auth_info_new(linphone_address_get_username(from),NULL,password,NULL,NULL); /*create authentication structure from identity*/
linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/
}
// configure proxy entries
linphone_proxy_config_set_identity(proxy_cfg,identity); /*set identity with user name and domain*/
const char* server_addr = linphone_address_get_domain(from); /*extract domain address from identity*/
linphone_proxy_config_set_server_addr(proxy_cfg,server_addr); /* we assume domain = proxy server address*/
linphone_proxy_config_enable_register(proxy_cfg,TRUE); /*activate registration for this proxy config*/
linphone_address_destroy(from); /*release resource*/
linphone_core_add_proxy_config(lc,proxy_cfg); /*add proxy config to linphone core*/
linphone_core_set_default_proxy(lc,proxy_cfg); /*set to default proxy*/
/* main loop for receiving notifications and doing background linphonecore work: */
while(running){
linphone_core_iterate(lc); /* first iterate initiates registration */
ms_usleep(50000);
}
linphone_core_get_default_proxy(lc,&proxy_cfg); /* get default proxy config*/
linphone_proxy_config_edit(proxy_cfg); /*start editing proxy configuration*/
linphone_proxy_config_enable_register(proxy_cfg,FALSE); /*de-activate registration for this proxy config*/
linphone_proxy_config_done(proxy_cfg); /*initiate REGISTER with expire = 0*/
while(linphone_proxy_config_get_state(proxy_cfg) != LinphoneRegistrationCleared){
linphone_core_iterate(lc); /*to make sure we receive call backs before shutting down*/
ms_usleep(50000);
}
end:
printf("Shutting down...\n");
linphone_core_destroy(lc);
printf("Exited\n");
return 0;
}

955
coreapi/linphonecall.c Normal file
View file

@ -0,0 +1,955 @@
/*
linphone
Copyright (C) 2010 Belledonne Communications SARL
(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.
*/
#ifdef WIN32
#include <time.h>
#endif
#include "linphonecore.h"
#include "sipsetup.h"
#include "lpconfig.h"
#include "private.h"
#include "mediastreamer2/mediastream.h"
#include "mediastreamer2/msvolume.h"
#include "mediastreamer2/msequalizer.h"
#include "mediastreamer2/msfileplayer.h"
#include "mediastreamer2/msjpegwriter.h"
#ifdef VIDEO_ENABLED
static MSWebCam *get_nowebcam_device(){
return ms_web_cam_manager_get_cam(ms_web_cam_manager_get(),"StaticImage: Static picture");
}
#endif
static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandwidth_limit){
MSList *l=NULL;
const MSList *it;
for(it=codecs;it!=NULL;it=it->next){
PayloadType *pt=(PayloadType*)it->data;
if (pt->flags & PAYLOAD_TYPE_ENABLED){
if (bandwidth_limit>0 && !linphone_core_is_payload_type_usable_for_bandwidth(lc,pt,bandwidth_limit)){
ms_message("Codec %s/%i eliminated because of audio bandwidth constraint.",pt->mime_type,pt->clock_rate);
continue;
}
if (linphone_core_check_payload_type_usability(lc,pt)){
l=ms_list_append(l,payload_type_clone(pt));
}
}
}
return l;
}
SalMediaDescription *create_local_media_description(LinphoneCore *lc, LinphoneCall *call){
MSList *l;
PayloadType *pt;
const char *me=linphone_core_get_identity(lc);
LinphoneAddress *addr=linphone_address_new(me);
const char *username=linphone_address_get_username (addr);
SalMediaDescription *md=sal_media_description_new();
md->nstreams=1;
strncpy(md->addr,call->localip,sizeof(md->addr));
strncpy(md->username,username,sizeof(md->username));
md->bandwidth=linphone_core_get_download_bandwidth(lc);
/*set audio capabilities */
strncpy(md->streams[0].addr,call->localip,sizeof(md->streams[0].addr));
md->streams[0].port=call->audio_port;
md->streams[0].proto=SalProtoRtpAvp;
md->streams[0].type=SalAudio;
md->streams[0].ptime=lc->net_conf.down_ptime;
l=make_codec_list(lc,lc->codecs_conf.audio_codecs,call->params.audio_bw);
pt=payload_type_clone(rtp_profile_get_payload_from_mime(&av_profile,"telephone-event"));
l=ms_list_append(l,pt);
md->streams[0].payloads=l;
if (lc->dw_audio_bw>0)
md->streams[0].bandwidth=lc->dw_audio_bw;
if (call->params.has_video){
md->nstreams++;
md->streams[1].port=call->video_port;
md->streams[1].proto=SalProtoRtpAvp;
md->streams[1].type=SalVideo;
l=make_codec_list(lc,lc->codecs_conf.video_codecs,0);
md->streams[1].payloads=l;
if (lc->dw_video_bw)
md->streams[1].bandwidth=lc->dw_video_bw;
}
linphone_address_destroy(addr);
return md;
}
static int find_port_offset(LinphoneCore *lc){
int offset;
MSList *elem;
int audio_port;
bool_t already_used=FALSE;
for(offset=0;offset<100;offset+=2){
audio_port=linphone_core_get_audio_port (lc)+offset;
already_used=FALSE;
for(elem=lc->calls;elem!=NULL;elem=elem->next){
LinphoneCall *call=(LinphoneCall*)elem->data;
if (call->audio_port==audio_port) {
already_used=TRUE;
break;
}
}
if (!already_used) break;
}
if (offset==100){
ms_error("Could not find any free port !");
return -1;
}
return offset;
}
static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
int port_offset;
call->refcnt=1;
call->state=LinphoneCallIdle;
call->start_time=time(NULL);
call->media_start_time=0;
call->log=linphone_call_log_new(call, from, to);
linphone_core_notify_all_friends(call->core,LinphoneStatusOnThePhone);
port_offset=find_port_offset (call->core);
if (port_offset==-1) return;
call->audio_port=linphone_core_get_audio_port(call->core)+port_offset;
call->video_port=linphone_core_get_video_port(call->core)+port_offset;
}
static void discover_mtu(LinphoneCore *lc, const char *remote){
int mtu;
if (lc->net_conf.mtu==0 ){
/*attempt to discover mtu*/
mtu=ms_discover_mtu(remote);
if (mtu>0){
ms_set_mtu(mtu);
ms_message("Discovered mtu is %i, RTP payload max size is %i",
mtu, ms_get_payload_max_size());
}
}
}
LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params)
{
LinphoneCall *call=ms_new0(LinphoneCall,1);
call->dir=LinphoneCallOutgoing;
call->op=sal_op_new(lc->sal);
sal_op_set_user_pointer(call->op,call);
call->core=lc;
linphone_core_get_local_ip(lc,linphone_address_get_domain(to),call->localip);
linphone_call_init_common(call,from,to);
call->params=*params;
call->localdesc=create_local_media_description (lc,call);
call->camera_active=params->has_video;
if (linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseStun)
linphone_core_run_stun_tests(call->core,call);
discover_mtu(lc,linphone_address_get_domain (to));
if (params->referer){
sal_call_set_referer (call->op,params->referer->op);
}
return call;
}
LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){
LinphoneCall *call=ms_new0(LinphoneCall,1);
char *to_str;
char *from_str;
call->dir=LinphoneCallIncoming;
sal_op_set_user_pointer(op,call);
call->op=op;
call->core=lc;
if (lc->sip_conf.ping_with_options){
/*the following sends an option request back to the caller so that
we get a chance to discover our nat'd address before answering.*/
call->ping_op=sal_op_new(lc->sal);
to_str=linphone_address_as_string(to);
from_str=linphone_address_as_string(from);
sal_op_set_route(call->ping_op,sal_op_get_network_origin(call->op));
sal_op_set_user_pointer(call->ping_op,call);
sal_ping(call->ping_op,to_str,from_str);
ms_free(to_str);
ms_free(from_str);
}
linphone_address_clean(from);
linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip);
linphone_call_init_common(call, from, to);
call->params.has_video=linphone_core_video_enabled(lc);
call->localdesc=create_local_media_description (lc,call);
call->camera_active=call->params.has_video;
if (linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseStun)
linphone_core_run_stun_tests(call->core,call);
discover_mtu(lc,linphone_address_get_domain(from));
return call;
}
/* this function is called internally to get rid of a call.
It performs the following tasks:
- remove the call from the internal list of calls
- unref the LinphoneCall object
- update the call logs accordingly
*/
static void linphone_call_set_terminated(LinphoneCall *call){
LinphoneCallStatus status=LinphoneCallAborted;
LinphoneCore *lc=call->core;
linphone_core_update_allocated_audio_bandwidth(lc);
if (call->state==LinphoneCallEnd){
if (call->reason==LinphoneReasonDeclined){
status=LinphoneCallDeclined;
}
else status=LinphoneCallSuccess;
}
linphone_call_log_completed(call->log,call, status);
if (call == lc->current_call){
ms_message("Resetting the current call");
lc->current_call=NULL;
}
if (linphone_core_del_call(lc,call) != 0){
ms_error("Could not remove the call from the list !!!");
}
if (ms_list_size(lc->calls)==0)
linphone_core_notify_all_friends(lc,lc->presence_mode);
if (call->op!=NULL) {
/* so that we cannot have anymore upcalls for SAL
concerning this call*/
sal_op_release(call->op);
call->op=NULL;
}
linphone_call_unref(call);
}
const char *linphone_call_state_to_string(LinphoneCallState cs){
switch (cs){
case LinphoneCallIdle:
return "LinphoneCallIdle";
case LinphoneCallIncomingReceived:
return "LinphoneCallIncomingReceived";
case LinphoneCallOutgoingInit:
return "LinphoneCallOutgoingInit";
case LinphoneCallOutgoingProgress:
return "LinphoneCallOutgoingProgress";
case LinphoneCallOutgoingRinging:
return "LinphoneCallOutgoingRinging";
case LinphoneCallOutgoingEarlyMedia:
return "LinphoneCallOutgoingEarlyMedia";
case LinphoneCallConnected:
return "LinphoneCallConnected";
case LinphoneCallStreamsRunning:
return "LinphoneCallStreamsRunning";
case LinphoneCallPausing:
return "LinphoneCallPausing";
case LinphoneCallPaused:
return "LinphoneCallPaused";
case LinphoneCallResuming:
return "LinphoneCallResuming";
case LinphoneCallRefered:
return "LinphoneCallRefered";
case LinphoneCallError:
return "LinphoneCallError";
case LinphoneCallEnd:
return "LinphoneCallEnd";
case LinphoneCallPausedByRemote:
return "LinphoneCallPausedByRemote";
case LinphoneCallUpdatedByRemote:
return "LinphoneCallUpdatedByRemote";
case LinphoneCallIncomingEarlyMedia:
return "LinphoneCallIncomingEarlyMedia";
case LinphoneCallUpdated:
return "LinphoneCallUpdated";
}
return "undefined state";
}
void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message){
LinphoneCore *lc=call->core;
bool_t finalize_call=FALSE;
if (call->state!=cstate){
ms_message("Call %p: moving from state %s to %s",call,linphone_call_state_to_string(call->state),
linphone_call_state_to_string(cstate));
if (cstate!=LinphoneCallRefered){
/*LinphoneCallRefered is rather an event, not a state.
Indeed it does not change the state of the call (still paused or running)*/
call->state=cstate;
}
if (cstate==LinphoneCallEnd || cstate==LinphoneCallError){
finalize_call=TRUE;
linphone_call_ref(call);
linphone_call_set_terminated (call);
}
if (lc->vtable.call_state_changed)
lc->vtable.call_state_changed(lc,call,cstate,message);
if (finalize_call)
linphone_call_unref(call);
}
}
static void linphone_call_destroy(LinphoneCall *obj)
{
if (obj->op!=NULL) {
sal_op_release(obj->op);
obj->op=NULL;
}
if (obj->resultdesc!=NULL) {
sal_media_description_unref(obj->resultdesc);
obj->resultdesc=NULL;
}
if (obj->localdesc!=NULL) {
sal_media_description_unref(obj->localdesc);
obj->localdesc=NULL;
}
if (obj->ping_op) {
sal_op_release(obj->ping_op);
}
if (obj->refer_to){
ms_free(obj->refer_to);
}
ms_free(obj);
}
/**
* @addtogroup call_control
* @{
**/
/**
* Increments the call 's reference count.
* An application that wishes to retain a pointer to call object
* must use this function to unsure the pointer remains
* valid. Once the application no more needs this pointer,
* it must call linphone_call_unref().
**/
void linphone_call_ref(LinphoneCall *obj){
obj->refcnt++;
}
/**
* Decrements the call object reference count.
* See linphone_call_ref().
**/
void linphone_call_unref(LinphoneCall *obj){
obj->refcnt--;
if (obj->refcnt==0){
linphone_call_destroy(obj);
}
}
/**
* Returns current parameters associated to the call.
**/
const LinphoneCallParams * linphone_call_get_current_params(const LinphoneCall *call){
return &call->params;
}
/**
* Returns the remote address associated to this call
*
**/
const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call){
return call->dir==LinphoneCallIncoming ? call->log->from : call->log->to;
}
/**
* Returns the remote address associated to this call as a string.
*
* The result string must be freed by user using ms_free().
**/
char *linphone_call_get_remote_address_as_string(const LinphoneCall *call){
return linphone_address_as_string(linphone_call_get_remote_address(call));
}
/**
* Retrieves the call's current state.
**/
LinphoneCallState linphone_call_get_state(const LinphoneCall *call){
return call->state;
}
/**
* Returns the reason for a call termination (either error or normal termination)
**/
LinphoneReason linphone_call_get_reason(const LinphoneCall *call){
return call->reason;
}
/**
* Get the user_pointer in the LinphoneCall
*
* @ingroup call_control
*
* return user_pointer an opaque user pointer that can be retrieved at any time
**/
void *linphone_call_get_user_pointer(LinphoneCall *call)
{
return call->user_pointer;
}
/**
* Set the user_pointer in the LinphoneCall
*
* @ingroup call_control
*
* the user_pointer is an opaque user pointer that can be retrieved at any time in the LinphoneCall
**/
void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer)
{
call->user_pointer = user_pointer;
}
/**
* Returns the call log associated to this call.
**/
LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call){
return call->log;
}
/**
* Returns the refer-to uri (if the call was transfered).
**/
const char *linphone_call_get_refer_to(const LinphoneCall *call){
return call->refer_to;
}
/**
* Returns direction of the call (incoming or outgoing).
**/
LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call){
return call->log->dir;
}
/**
* Returns the far end's user agent description string, if available.
**/
const char *linphone_call_get_remote_user_agent(LinphoneCall *call){
if (call->op){
return sal_op_get_remote_ua (call->op);
}
return NULL;
}
/**
* Returns true if this calls has received a transfer that has not been
* executed yet.
* Pending transfers are executed when this call is being paused or closed,
* locally or by remote endpoint.
* If the call is already paused while receiving the transfer request, the
* transfer immediately occurs.
**/
bool_t linphone_call_has_transfer_pending(const LinphoneCall *call){
return call->refer_pending;
}
/**
* Returns call's duration in seconds.
**/
int linphone_call_get_duration(const LinphoneCall *call){
if (call->media_start_time==0) return 0;
return time(NULL)-call->media_start_time;
}
/**
* Indicate whether camera input should be sent to remote end.
**/
void linphone_call_enable_camera (LinphoneCall *call, bool_t enable){
#ifdef VIDEO_ENABLED
if (call->videostream!=NULL && call->videostream->ticker!=NULL){
LinphoneCore *lc=call->core;
MSWebCam *nowebcam=get_nowebcam_device();
if (call->camera_active!=enable && lc->video_conf.device!=nowebcam){
video_stream_change_camera(call->videostream,
enable ? lc->video_conf.device : nowebcam);
}
}
call->camera_active=enable;
#endif
}
/**
* Take a photo of currently received video and write it into a jpeg file.
**/
int linphone_call_take_video_snapshot(LinphoneCall *call, const char *file){
#ifdef VIDEO_ENABLED
if (call->videostream!=NULL && call->videostream->jpegwriter!=NULL){
return ms_filter_call_method(call->videostream->jpegwriter,MS_JPEG_WRITER_TAKE_SNAPSHOT,(void*)file);
}
ms_warning("Cannot take snapshot: no currently running video stream on this call.");
return -1;
#endif
return -1;
}
/**
*
**/
bool_t linphone_call_camera_enabled (const LinphoneCall *call){
return call->camera_active;
}
/**
*
**/
void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled){
cp->has_video=enabled;
}
/**
*
**/
bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp){
return cp->has_video;
}
/**
* Enable sending of real early media (during outgoing calls).
**/
void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, bool_t enabled){
cp->real_early_media=enabled;
}
bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp){
return cp->real_early_media;
}
/**
* Refine bandwidth settings for this call by setting a bandwidth limit for audio streams.
* As a consequence, codecs whose bitrates are not compatible with this limit won't be used.
**/
void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int bandwidth){
cp->audio_bw=bandwidth;
}
/**
*
**/
LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp){
LinphoneCallParams *ncp=ms_new0(LinphoneCallParams,1);
memcpy(ncp,cp,sizeof(LinphoneCallParams));
return ncp;
}
/**
*
**/
void linphone_call_params_destroy(LinphoneCallParams *p){
ms_free(p);
}
/**
* @}
**/
#ifdef TEST_EXT_RENDERER
static void rendercb(void *data, const MSPicture *local, const MSPicture *remote){
ms_message("rendercb, local buffer=%p, remote buffer=%p",
local ? local->planes[0] : NULL, remote? remote->planes[0] : NULL);
}
#endif
void linphone_call_init_media_streams(LinphoneCall *call){
LinphoneCore *lc=call->core;
SalMediaDescription *md=call->localdesc;
AudioStream *audiostream;
call->audiostream=audiostream=audio_stream_new(md->streams[0].port,linphone_core_ipv6_enabled(lc));
if (linphone_core_echo_limiter_enabled(lc)){
const char *type=lp_config_get_string(lc->config,"sound","el_type","mic");
if (strcasecmp(type,"mic")==0)
audio_stream_enable_echo_limiter(audiostream,ELControlMic);
else if (strcasecmp(type,"full")==0)
audio_stream_enable_echo_limiter(audiostream,ELControlFull);
}
audio_stream_enable_gain_control(audiostream,TRUE);
if (linphone_core_echo_cancellation_enabled(lc)){
int len,delay,framesize;
len=lp_config_get_int(lc->config,"sound","ec_tail_len",0);
delay=lp_config_get_int(lc->config,"sound","ec_delay",0);
framesize=lp_config_get_int(lc->config,"sound","ec_framesize",0);
audio_stream_set_echo_canceller_params(audiostream,len,delay,framesize);
}
audio_stream_enable_automatic_gain_control(audiostream,linphone_core_agc_enabled(lc));
{
int enabled=lp_config_get_int(lc->config,"sound","noisegate",0);
audio_stream_enable_noise_gate(audiostream,enabled);
}
if (lc->a_rtp)
rtp_session_set_transports(audiostream->session,lc->a_rtp,lc->a_rtcp);
#ifdef VIDEO_ENABLED
if ((lc->video_conf.display || lc->video_conf.capture) && md->streams[1].port>0){
call->videostream=video_stream_new(md->streams[1].port,linphone_core_ipv6_enabled(lc));
if( lc->video_conf.displaytype != NULL)
video_stream_set_display_filter_name(call->videostream,lc->video_conf.displaytype);
#ifdef TEST_EXT_RENDERER
video_stream_set_render_callback(call->videostream,rendercb,NULL);
#endif
}
#else
call->videostream=NULL;
#endif
}
static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'};
static void linphone_core_dtmf_received(RtpSession* s, int dtmf, void* user_data){
LinphoneCore* lc = (LinphoneCore*)user_data;
if (dtmf<0 || dtmf>15){
ms_warning("Bad dtmf value %i",dtmf);
return;
}
if (lc->vtable.dtmf_received != NULL)
lc->vtable.dtmf_received(lc, linphone_core_get_current_call(lc), dtmf_tab[dtmf]);
}
static void parametrize_equalizer(LinphoneCore *lc, AudioStream *st){
if (st->equalizer){
MSFilter *f=st->equalizer;
int enabled=lp_config_get_int(lc->config,"sound","eq_active",0);
const char *gains=lp_config_get_string(lc->config,"sound","eq_gains",NULL);
ms_filter_call_method(f,MS_EQUALIZER_SET_ACTIVE,&enabled);
if (enabled){
if (gains){
do{
int bytes;
MSEqualizerGain g;
if (sscanf(gains,"%f:%f:%f %n",&g.frequency,&g.gain,&g.width,&bytes)==3){
ms_message("Read equalizer gains: %f(~%f) --> %f",g.frequency,g.width,g.gain);
ms_filter_call_method(f,MS_EQUALIZER_SET_GAIN,&g);
gains+=bytes;
}else break;
}while(1);
}
}
}
}
static void post_configure_audio_streams(LinphoneCall*call){
AudioStream *st=call->audiostream;
LinphoneCore *lc=call->core;
float mic_gain=lp_config_get_float(lc->config,"sound","mic_gain",1);
float thres = 0;
float recv_gain;
float ng_thres=lp_config_get_float(lc->config,"sound","ng_thres",0.05);
float ng_floorgain=lp_config_get_float(lc->config,"sound","ng_floorgain",0);
int dc_removal=lp_config_get_int(lc->config,"sound","dc_removal",0);
if (!call->audio_muted)
audio_stream_set_mic_gain(st,mic_gain);
else
audio_stream_set_mic_gain(st,0);
recv_gain = lc->sound_conf.soft_play_lev;
if (recv_gain != 0) {
linphone_core_set_playback_gain_db (lc,recv_gain);
}
if (st->volsend){
ms_filter_call_method(st->volsend,MS_VOLUME_REMOVE_DC,&dc_removal);
}
if (linphone_core_echo_limiter_enabled(lc)){
float speed=lp_config_get_float(lc->config,"sound","el_speed",-1);
thres=lp_config_get_float(lc->config,"sound","el_thres",-1);
float force=lp_config_get_float(lc->config,"sound","el_force",-1);
int sustain=lp_config_get_int(lc->config,"sound","el_sustain",-1);
MSFilter *f=NULL;
if (st->el_type!=ELInactive){
f=st->volsend;
if (speed==-1) speed=0.03;
if (force==-1) force=25;
ms_filter_call_method(f,MS_VOLUME_SET_EA_SPEED,&speed);
ms_filter_call_method(f,MS_VOLUME_SET_EA_FORCE,&force);
if (thres!=-1)
ms_filter_call_method(f,MS_VOLUME_SET_EA_THRESHOLD,&thres);
if (sustain!=-1)
ms_filter_call_method(f,MS_VOLUME_SET_EA_SUSTAIN,&sustain);
}
}
if (st->volsend){
ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&ng_floorgain);
}
if (st->volrecv){
/* parameters for a limited noise-gate effect, using echo limiter threshold */
float floorgain = 1/mic_gain;
ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&thres);
ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&floorgain);
}
parametrize_equalizer(lc,st);
if (lc->vtable.dtmf_received!=NULL){
/* replace by our default action*/
audio_stream_play_received_dtmfs(call->audiostream,FALSE);
rtp_session_signal_connect(call->audiostream->session,"telephone-event",(RtpCallback)linphone_core_dtmf_received,(unsigned long)lc);
}
}
static RtpProfile *make_profile(LinphoneCore *lc, const SalMediaDescription *md, const SalStreamDescription *desc, int *used_pt){
int bw;
const MSList *elem;
RtpProfile *prof=rtp_profile_new("Call profile");
bool_t first=TRUE;
int remote_bw=0;
*used_pt=-1;
for(elem=desc->payloads;elem!=NULL;elem=elem->next){
PayloadType *pt=(PayloadType*)elem->data;
int number;
if (first) {
if (desc->type==SalAudio){
linphone_core_update_allocated_audio_bandwidth_in_call(lc,pt);
}
*used_pt=payload_type_get_number(pt);
first=FALSE;
}
if (desc->bandwidth>0) remote_bw=desc->bandwidth;
else if (md->bandwidth>0) {
/*case where b=AS is given globally, not per stream*/
remote_bw=md->bandwidth;
if (desc->type==SalVideo){
remote_bw-=lc->audio_bw;
}
}
if (desc->type==SalAudio){
bw=get_min_bandwidth(lc->up_audio_bw,remote_bw);
}else bw=get_min_bandwidth(lc->up_video_bw,remote_bw);
if (bw>0) pt->normal_bitrate=bw*1000;
else if (desc->type==SalAudio){
pt->normal_bitrate=-1;
}
if (desc->ptime>0){
char tmp[40];
snprintf(tmp,sizeof(tmp),"ptime=%i",desc->ptime);
payload_type_append_send_fmtp(pt,tmp);
}
number=payload_type_get_number(pt);
if (rtp_profile_get_payload(prof,number)!=NULL){
ms_warning("A payload type with number %i already exists in profile !",number);
}else
rtp_profile_set_payload(prof,number,pt);
}
return prof;
}
static void setup_ring_player(LinphoneCore *lc, LinphoneCall *call){
int pause_time=3000;
audio_stream_play(call->audiostream,lc->sound_conf.ringback_tone);
ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
}
void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone){
LinphoneCore *lc=call->core;
LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc);
const char *tool="linphone-" LINPHONE_VERSION;
char *cname;
int used_pt=-1;
if(call->audiostream == NULL)
{
ms_fatal("start_media_stream() called without prior init !");
return;
}
/* adjust rtp jitter compensation. It must be at least the latency of the sound card */
int jitt_comp=MAX(lc->sound_conf.latency,lc->rtp_conf.audio_jitt_comp);
if (call->media_start_time==0) call->media_start_time=time(NULL);
cname=linphone_address_as_string_uri_only(me);
{
const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc,
SalProtoRtpAvp,SalAudio);
if (stream && stream->dir!=SalStreamInactive){
MSSndCard *playcard=lc->sound_conf.lsd_card ?
lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
MSSndCard *captcard=lc->sound_conf.capt_sndcard;
const char *playfile=lc->play_file;
const char *recfile=lc->rec_file;
call->audio_profile=make_profile(lc,call->resultdesc,stream,&used_pt);
if (used_pt!=-1){
if (playcard==NULL) {
ms_warning("No card defined for playback !");
}
if (captcard==NULL) {
ms_warning("No card defined for capture !");
}
/*Replace soundcard filters by inactive file players or recorders
when placed in recvonly or sendonly mode*/
if (stream->port==0 || stream->dir==SalStreamRecvOnly){
captcard=NULL;
playfile=NULL;
}else if (stream->dir==SalStreamSendOnly){
playcard=NULL;
captcard=NULL;
recfile=NULL;
playfile=NULL;
}
if (send_ringbacktone){
captcard=NULL;
playfile=NULL;/* it is setup later*/
}
/*if playfile are supplied don't use soundcards*/
if (lc->use_files) {
captcard=NULL;
playcard=NULL;
}
audio_stream_start_full(
call->audiostream,
call->audio_profile,
stream->addr[0]!='\0' ? stream->addr : call->resultdesc->addr,
stream->port,
stream->port+1,
used_pt,
jitt_comp,
playfile,
recfile,
playcard,
captcard,
captcard==NULL ? FALSE : linphone_core_echo_cancellation_enabled(lc));
post_configure_audio_streams(call);
if (all_inputs_muted && !send_ringbacktone){
audio_stream_set_mic_gain(call->audiostream,0);
}
if (send_ringbacktone){
setup_ring_player(lc,call);
}
audio_stream_set_rtcp_information(call->audiostream, cname, tool);
}else ms_warning("No audio stream accepted ?");
}
}
#ifdef VIDEO_ENABLED
{
const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc,
SalProtoRtpAvp,SalVideo);
used_pt=-1;
/* shutdown preview */
if (lc->previewstream!=NULL) {
video_preview_stop(lc->previewstream);
lc->previewstream=NULL;
}
if (stream && stream->dir!=SalStreamInactive) {
const char *addr=stream->addr[0]!='\0' ? stream->addr : call->resultdesc->addr;
call->video_profile=make_profile(lc,call->resultdesc,stream,&used_pt);
if (used_pt!=-1){
VideoStreamDir dir=VideoStreamSendRecv;
MSWebCam *cam=lc->video_conf.device;
bool_t is_inactive=FALSE;
call->params.has_video=TRUE;
video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc));
video_stream_enable_self_view(call->videostream,lc->video_conf.selfview);
if (lc->video_window_id!=0)
video_stream_set_native_window_id(call->videostream,lc->video_window_id);
if (lc->preview_window_id!=0)
video_stream_set_native_preview_window_id (call->videostream,lc->preview_window_id);
video_stream_use_preview_video_window (call->videostream,lc->use_preview_window);
if (stream->dir==SalStreamSendOnly && lc->video_conf.capture ){
cam=get_nowebcam_device();
dir=VideoStreamSendOnly;
}else if (stream->dir==SalStreamRecvOnly && lc->video_conf.display ){
dir=VideoStreamRecvOnly;
}else if (stream->dir==SalStreamSendRecv){
if (lc->video_conf.display && lc->video_conf.capture)
dir=VideoStreamSendRecv;
else if (lc->video_conf.display)
dir=VideoStreamRecvOnly;
else
dir=VideoStreamSendOnly;
}else{
ms_warning("video stream is inactive.");
/*either inactive or incompatible with local capabilities*/
is_inactive=TRUE;
}
if (call->camera_active==FALSE || all_inputs_muted){
cam=get_nowebcam_device();
}
if (!is_inactive){
video_stream_set_direction (call->videostream, dir);
video_stream_start(call->videostream,
call->video_profile, addr, stream->port,
stream->port+1,
used_pt, jitt_comp, cam);
video_stream_set_rtcp_information(call->videostream, cname,tool);
}
}else ms_warning("No video stream accepted.");
}else{
ms_warning("No valid video stream defined.");
}
}
#endif
call->all_muted=all_inputs_muted;
call->playing_ringbacktone=send_ringbacktone;
call->up_bw=linphone_core_get_upload_bandwidth(lc);
goto end;
end:
ms_free(cname);
linphone_address_destroy(me);
}
static void linphone_call_log_fill_stats(LinphoneCallLog *log, AudioStream *st){
audio_stream_get_local_rtp_stats (st,&log->local_stats);
}
void linphone_call_stop_media_streams(LinphoneCall *call){
if (call->audiostream!=NULL) {
linphone_call_log_fill_stats (call->log,call->audiostream);
audio_stream_stop(call->audiostream);
call->audiostream=NULL;
}
#ifdef VIDEO_ENABLED
if (call->videostream!=NULL){
video_stream_stop(call->videostream);
call->videostream=NULL;
}
#endif
if (call->audio_profile){
rtp_profile_clear_all(call->audio_profile);
rtp_profile_destroy(call->audio_profile);
call->audio_profile=NULL;
}
if (call->video_profile){
rtp_profile_clear_all(call->video_profile);
rtp_profile_destroy(call->video_profile);
call->video_profile=NULL;
}
}

File diff suppressed because it is too large Load diff

View file

@ -39,6 +39,11 @@ extern "C" {
struct _MSSndCard;
struct _LinphoneCore;
/**
* Linphone core main object created by function linphone_core_new() .
* @ingroup initializing
*/
typedef struct _LinphoneCore LinphoneCore;
struct SalOp;
struct _LpConfig;
@ -68,6 +73,11 @@ typedef struct _LCSipTransports LCSipTransports;
* @var LinphoneAddress
*/
typedef struct SalAddress LinphoneAddress;
#ifdef IN_LINPHONE
#include "linphonefriend.h"
#else
#include "linphone/linphonefriend.h"
#endif
LinphoneAddress * linphone_address_new(const char *uri);
LinphoneAddress * linphone_address_clone(const LinphoneAddress *uri);
@ -93,18 +103,12 @@ void linphone_address_set_port_int(LinphoneAddress *uri, int port);
void linphone_address_clean(LinphoneAddress *uri);
char *linphone_address_as_string(const LinphoneAddress *u);
char *linphone_address_as_string_uri_only(const LinphoneAddress *u);
bool_t linphone_address_weak_equal(const LinphoneAddress *a1, const LinphoneAddress *a2);
void linphone_address_destroy(LinphoneAddress *u);
struct _SipSetupContext;
/**
* The LinphoneCall object represents a call issued or received by the LinphoneCore
**/
struct _LinphoneCall;
typedef struct _LinphoneCall LinphoneCall;
bool_t linphone_call_asked_to_autoanswer(struct _LinphoneCall *call);
/**
* Enum representing the direction of a call.
* @ingroup call_logs
@ -127,7 +131,8 @@ typedef enum _LinphoneCallDir LinphoneCallDir;
typedef enum _LinphoneCallStatus {
LinphoneCallSuccess, /**< The call was sucessful*/
LinphoneCallAborted, /**< The call was aborted */
LinphoneCallMissed /**< The call was missed (unanswered)*/
LinphoneCallMissed, /**< The call was missed (unanswered)*/
LinphoneCallDeclined /**< The call was declined, either locally or by remote end*/
} LinphoneCallStatus;
/**
@ -161,52 +166,87 @@ 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);
typedef enum{
LinphoneSPWait,
LinphoneSPDeny,
LinphoneSPAccept
}LinphoneSubscribePolicy;
typedef enum _LinphoneOnlineStatus{
LINPHONE_STATUS_OFFLINE,
LINPHONE_STATUS_ONLINE,
LINPHONE_STATUS_BUSY,
LINPHONE_STATUS_BERIGHTBACK,
LINPHONE_STATUS_AWAY,
LINPHONE_STATUS_ONTHEPHONE,
LINPHONE_STATUS_OUTTOLUNCH,
LINPHONE_STATUS_NOT_DISTURB,
LINPHONE_STATUS_MOVED,
LINPHONE_STATUS_ALT_SERVICE,
LINPHONE_STATUS_PENDING,
LINPHONE_STATUS_END
}LinphoneOnlineStatus;
/**
* 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 char *linphone_online_status_to_string(LinphoneOnlineStatus ss);
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);
void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, bool_t enabled);
bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp);
void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int bw);
void linphone_call_params_destroy(LinphoneCallParams *cp);
struct _LinphoneFriend;
/**
* Enum describing failure reasons.
**/
enum _LinphoneReason{
LinphoneReasonNone,
LinphoneReasonNoResponse, /**<No response received from remote*/
LinphoneReasonBadCredentials, /**<Authentication failed due to bad or missing credentials*/
LinphoneReasonDeclined, /**<The call has been declined*/
};
typedef struct _LinphoneFriend LinphoneFriend;
typedef enum _LinphoneReason LinphoneReason;
LinphoneFriend * linphone_friend_new();
LinphoneFriend *linphone_friend_new_with_addr(const char *addr);
int linphone_friend_set_sip_addr(LinphoneFriend *fr, const char *uri);
int linphone_friend_set_name(LinphoneFriend *fr, const char *name);
int linphone_friend_send_subscribe(LinphoneFriend *fr, bool_t val);
int linphone_friend_set_inc_subscribe_policy(LinphoneFriend *fr, LinphoneSubscribePolicy pol);
void linphone_friend_edit(LinphoneFriend *fr);
void linphone_friend_done(LinphoneFriend *fr);
void linphone_friend_destroy(LinphoneFriend *lf);
const LinphoneAddress *linphone_friend_get_address(const LinphoneFriend *lf);
bool_t linphone_friend_get_send_subscribe(const LinphoneFriend *lf);
LinphoneSubscribePolicy linphone_friend_get_inc_subscribe_policy(const LinphoneFriend *lf);
LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf);
BuddyInfo * linphone_friend_get_info(const LinphoneFriend *lf);
void linphone_friend_set_ref_key(LinphoneFriend *lf, const char *key);
const char *linphone_friend_get_ref_key(const LinphoneFriend *lf);
bool_t linphone_friend_in_list(const LinphoneFriend *lf);
const char *linphone_reason_to_string(LinphoneReason err);
#define linphone_friend_url(lf) ((lf)->url)
/**
* The LinphoneCall object represents a call issued or received by the LinphoneCore
**/
struct _LinphoneCall;
typedef struct _LinphoneCall LinphoneCall;
typedef enum _LinphoneCallState{
LinphoneCallIdle,
LinphoneCallIncomingReceived, /**<This is a new incoming call */
LinphoneCallOutgoingInit, /**<An outgoing call is started */
LinphoneCallOutgoingProgress, /**<An outgoing call is in progress */
LinphoneCallOutgoingRinging, /**<An outgoing call is ringing at remote end */
LinphoneCallOutgoingEarlyMedia, /**<An outgoing call is proposed early media */
LinphoneCallConnected, /**<Connected, the call is answered */
LinphoneCallStreamsRunning, /**<The media streams are established and running*/
LinphoneCallPausing, /**<The call is pausing at the initiative of local end */
LinphoneCallPaused, /**< The call is paused, remote end has accepted the pause */
LinphoneCallResuming, /**<The call is being resumed by local end*/
LinphoneCallRefered, /**<The call is being transfered to another party, resulting in a new outgoing call to follow immediately*/
LinphoneCallError, /**<The call encountered an error*/
LinphoneCallEnd, /**<The call ended normally*/
LinphoneCallPausedByRemote, /**<The call is paused by remote end*/
LinphoneCallUpdatedByRemote, /**<The call's parameters are updated, used for example when video is asked by remote */
LinphoneCallIncomingEarlyMedia, /**<We are proposing early media to an incoming call */
LinphoneCallUpdated /**<The remote accepted the call update initiated by us */
} LinphoneCallState;
const char *linphone_call_state_to_string(LinphoneCallState cs);
LinphoneCallState linphone_call_get_state(const LinphoneCall *call);
bool_t linphone_call_asked_to_autoanswer(LinphoneCall *call);
const LinphoneAddress * linphone_core_get_current_call_remote_address(struct _LinphoneCore *lc);
const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call);
char *linphone_call_get_remote_address_as_string(const LinphoneCall *call);
LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call);
void linphone_call_ref(LinphoneCall *call);
void linphone_call_unref(LinphoneCall *call);
LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call);
const char *linphone_call_get_refer_to(const LinphoneCall *call);
bool_t linphone_call_has_transfer_pending(const LinphoneCall *call);
int linphone_call_get_duration(const LinphoneCall *call);
const LinphoneCallParams * linphone_call_get_current_params(const LinphoneCall *call);
void linphone_call_enable_camera(LinphoneCall *lc, bool_t enabled);
bool_t linphone_call_camera_enabled(const LinphoneCall *lc);
int linphone_call_take_video_snapshot(LinphoneCall *call, const char *file);
LinphoneReason linphone_call_get_reason(const LinphoneCall *call);
const char *linphone_call_get_remote_user_agent(LinphoneCall *call);
void *linphone_call_get_user_pointer(LinphoneCall *call);
void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer);
/**
@ -231,11 +271,34 @@ bool_t linphone_friend_in_list(const LinphoneFriend *lf);
**/
typedef struct _LinphoneProxyConfig LinphoneProxyConfig;
/**
* LinphoneRegistrationState describes proxy registration states.
**/
typedef enum _LinphoneRegistrationState{
LinphoneRegistrationNone,
LinphoneRegistrationProgress,
LinphoneRegistrationOk,
LinphoneRegistrationCleared,
LinphoneRegistrationFailed
}LinphoneRegistrationState;
/**
* Human readable version of the #LinphoneRegistrationState
* @param cs sate
*/
const char *linphone_registration_state_to_string(LinphoneRegistrationState cs);
LinphoneProxyConfig *linphone_proxy_config_new(void);
int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char *server_addr);
int linphone_proxy_config_set_identity(LinphoneProxyConfig *obj, const char *identity);
int linphone_proxy_config_set_route(LinphoneProxyConfig *obj, const char *route);
void linphone_proxy_config_expires(LinphoneProxyConfig *obj, int expires);
/**
* Indicates either or not, REGISTRATION must be issued for this #LinphoneProxyConfig .
* <br> In case this #LinphoneProxyConfig has been added to #LinphoneCore, follows the linphone_proxy_config_edit() rule.
* @param obj object pointer
* @param val if true, registration will be engaged
*/
void linphone_proxy_config_enable_register(LinphoneProxyConfig *obj, bool_t val);
#define linphone_proxy_config_enableregister linphone_proxy_config_enable_register
void linphone_proxy_config_edit(LinphoneProxyConfig *obj);
@ -244,6 +307,7 @@ void linphone_proxy_config_enable_publish(LinphoneProxyConfig *obj, bool_t val);
void linphone_proxy_config_set_dial_escape_plus(LinphoneProxyConfig *cfg, bool_t val);
void linphone_proxy_config_set_dial_prefix(LinphoneProxyConfig *cfg, const char *prefix);
LinphoneRegistrationState linphone_proxy_config_get_state(const LinphoneProxyConfig *obj);
bool_t linphone_proxy_config_is_registered(const LinphoneProxyConfig *obj);
const char *linphone_proxy_config_get_domain(const LinphoneProxyConfig *cfg);
@ -258,6 +322,8 @@ struct _LinphoneCore * linphone_proxy_config_get_core(const LinphoneProxyConfig
bool_t linphone_proxy_config_get_dial_escape_plus(const LinphoneProxyConfig *cfg);
const char * linphone_proxy_config_get_dial_prefix(const LinphoneProxyConfig *cfg);
LinphoneReason linphone_proxy_config_get_error(const LinphoneProxyConfig *cfg);
/* destruction is called automatically when removing the proxy config */
void linphone_proxy_config_destroy(LinphoneProxyConfig *cfg);
void linphone_proxy_config_set_sip_setup(LinphoneProxyConfig *cfg, const char *type);
@ -341,95 +407,115 @@ const char *linphone_auth_info_get_userid(const LinphoneAuthInfo *i);
void linphone_auth_info_destroy(LinphoneAuthInfo *info);
LinphoneAuthInfo * linphone_auth_info_new_from_config_file(struct _LpConfig *config, int pos);
struct _LinphoneChatRoom;
typedef struct _LinphoneChatRoom LinphoneChatRoom;
LinphoneChatRoom * linphone_core_create_chat_room(struct _LinphoneCore *lc, const char *to);
void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg);
struct _LinphoneChatRoom;
/**
* @addtogroup chatroom
* @{
*/
/**
* 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
* @param to destination address for messages
* @return #LinphoneChatRoom where messaging can take place.
*/
LinphoneChatRoom * linphone_core_create_chat_room(LinphoneCore *lc, const char *to);
/**
* Destructor
* @param cr #LinphoneChatRoom object
*/
void linphone_chat_room_destroy(LinphoneChatRoom *cr);
/**
* get peer address \link linphone_core_create_chat_room() associated to \endlink this #LinphoneChatRoom
* @param cr #LinphoneChatRoom object
* @return #LinphoneAddress peer address
*/
const LinphoneAddress* linphone_chat_room_get_peer_address(LinphoneChatRoom *cr);
/**
* send a message to peer member of this chat room.
* @param cr #LinphoneChatRoom object
* @param msg message to be sent
*/
void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg);
void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void * ud);
void * linphone_chat_room_get_user_data(LinphoneChatRoom *cr);
/* describes the different groups of states */
typedef enum _gstate_group {
GSTATE_GROUP_POWER,
GSTATE_GROUP_REG,
GSTATE_GROUP_CALL
} gstate_group_t;
/**
* @}
*/
typedef enum _LinphoneGlobalState{
LinphoneGlobalOff,
LinphoneGlobalStartup,
LinphoneGlobalOn,
LinphoneGlobalShutdown
}LinphoneGlobalState;
typedef enum _gstate {
/* states for GSTATE_GROUP_POWER */
GSTATE_POWER_OFF = 0, /* initial state */
GSTATE_POWER_STARTUP,
GSTATE_POWER_ON,
GSTATE_POWER_SHUTDOWN,
/* states for GSTATE_GROUP_REG */
GSTATE_REG_NONE = 10, /* initial state */
GSTATE_REG_OK,
GSTATE_REG_FAILED,
GSTATE_REG_PENDING, /* a registration request is ongoing*/
/* states for GSTATE_GROUP_CALL */
GSTATE_CALL_IDLE = 20, /* initial state */
GSTATE_CALL_OUT_INVITE,
GSTATE_CALL_OUT_CONNECTED,
GSTATE_CALL_IN_INVITE,
GSTATE_CALL_IN_CONNECTED,
GSTATE_CALL_END,
GSTATE_CALL_ERROR,
GSTATE_INVALID,
GSTATE_CALL_OUT_RINGING /*remote ringing*/
} gstate_t;
struct _LinphoneGeneralState {
gstate_t old_state;
gstate_t new_state;
gstate_group_t group;
const char *message;
};
typedef struct _LinphoneGeneralState LinphoneGeneralState;
/* private: set a new state */
void gstate_new_state(struct _LinphoneCore *lc, gstate_t new_state, const char *message);
/*private*/
void gstate_initialize(struct _LinphoneCore *lc) ;
const char *linphone_global_state_to_string(LinphoneGlobalState gs);
/**
* @addtogroup initializing
* @{
**/
/**Call state notification callback prototype*/
typedef void (*LinphoneGlobalStateCb)(struct _LinphoneCore *lc, LinphoneGlobalState gstate, const char *message);
/**Call state notification callback prototype*/
typedef void (*LinphoneCallStateCb)(struct _LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *message);
/** @ingroup Proxies
* Registration state notification callback prototype
* */
typedef void (*LinphoneRegistrationStateCb)(struct _LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message);
/** Callback prototype */
typedef void (*ShowInterfaceCb)(struct _LinphoneCore *lc);
/** Callback prototype */
typedef void (*InviteReceivedCb)(struct _LinphoneCore *lc, const char *from);
/** Callback prototype */
typedef void (*ByeReceivedCb)(struct _LinphoneCore *lc, const char *from);
/** Callback prototype */
typedef void (*DisplayStatusCb)(struct _LinphoneCore *lc, const char *message);
/** Callback prototype */
typedef void (*DisplayMessageCb)(struct _LinphoneCore *lc, const char *message);
/** Callback prototype */
typedef void (*DisplayUrlCb)(struct _LinphoneCore *lc, const char *message, const char *url);
/** Callback prototype */
typedef void (*DisplayQuestionCb)(struct _LinphoneCore *lc, const char *message);
/** Callback prototype */
typedef void (*LinphoneCoreCbFunc)(struct _LinphoneCore *lc,void * user_data);
/** Callback prototype */
typedef void (*NotifyReceivedCb)(struct _LinphoneCore *lc, const char *from, const char *msg);
/** Callback prototype */
typedef void (*NotifyPresenceReceivedCb)(struct _LinphoneCore *lc, LinphoneFriend * fid);
/** Callback prototype */
typedef void (*NewUnknownSubscriberCb)(struct _LinphoneCore *lc, LinphoneFriend *lf, const char *url);
typedef void (*NotifyReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call, const char *from, const char *event);
/**
* Report status change for a friend previously \link linphone_core_add_friend() added \endlink to #LinphoneCore.
* @param lc #LinphoneCore object .
* @param lf Updated #LinphoneFriend .
*/
typedef void (*NotifyPresenceReceivedCb)(struct _LinphoneCore *lc, LinphoneFriend * lf);
/**
* Reports that a new subscription request has been received and wait for a decision.
* <br> Status on this subscription request is notified by \link linphone_friend_set_inc_subscribe_policy() changing policy \endlink for this friend
* @param lc #LinphoneCore object
* @param lf #LinphoneFriend corresponding to the subscriber
* @param url of the subscriber
* Callback prototype
* */
typedef void (*NewSubscribtionRequestCb)(struct _LinphoneCore *lc, LinphoneFriend *lf, const char *url);
/** Callback prototype */
typedef void (*AuthInfoRequested)(struct _LinphoneCore *lc, const char *realm, const char *username);
/** Callback prototype */
typedef void (*CallLogUpdated)(struct _LinphoneCore *lc, struct _LinphoneCallLog *newcl);
/**
* 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 from #LinphoneAddress from
* @param message incoming message
* */
typedef void (*TextMessageReceived)(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from, const char *message);
/** Callback prototype */
typedef void (*TextMessageReceived)(struct _LinphoneCore *lc, LinphoneChatRoom *room, const char *from, const char *message);
/** Callback prototype */
typedef void (*GeneralStateChange)(struct _LinphoneCore *lc, LinphoneGeneralState *gstate);
/** Callback prototype */
typedef void (*DtmfReceived)(struct _LinphoneCore* lc, int dtmf);
typedef void (*DtmfReceived)(struct _LinphoneCore* lc, LinphoneCall *call, int dtmf);
/** Callback prototype */
typedef void (*ReferReceived)(struct _LinphoneCore *lc, const char *refer_to);
/** Callback prototype */
@ -437,28 +523,26 @@ typedef void (*BuddyInfoUpdated)(struct _LinphoneCore *lc, LinphoneFriend *lf);
/**
* This structure holds all callbacks that the application should implement.
*
* None is mandatory.
**/
typedef struct _LinphoneVTable
{
ShowInterfaceCb show; /**< Notifies the application that it should show up*/
InviteReceivedCb inv_recv; /**< Notifies incoming calls */
ByeReceivedCb bye_recv; /**< Notify calls terminated by far end*/
typedef struct _LinphoneVTable{
LinphoneGlobalStateCb global_state_changed; /**<Notifies globlal state changes*/
LinphoneRegistrationStateCb registration_state_changed;/**<Notifies registration state changes*/
LinphoneCallStateCb call_state_changed;/**<Notifies call state changes*/
NotifyPresenceReceivedCb notify_presence_recv; /**< Notify received presence events*/
NewUnknownSubscriberCb new_unknown_subscriber; /**< Notify about unknown subscriber */
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 */
DtmfReceived dtmf_received; /**< A dtmf has been received received */
ReferReceived refer_received; /**< An out of call refer was received */
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;
DisplayQuestionCb display_question;
CallLogUpdated call_log_updated; /**< Notifies that call log list has been updated */
TextMessageReceived text_received; /**< A text message has been received */
GeneralStateChange general_state; /**< State notification callback */
DtmfReceived dtmf_received; /**< A dtmf has been received received */
ReferReceived refer_received; /**< A refer was received */
BuddyInfoUpdated buddy_info_updated; /**< a LinphoneFriend's BuddyInfo has changed*/
NotifyReceivedCb notify_recv; /**< Other notifications*/
ShowInterfaceCb show; /**< Notifies the application that it should show up*/
} LinphoneCoreVTable;
/**
@ -474,9 +558,9 @@ typedef struct _LCCallbackObj
typedef enum _LinphoneFirewallPolicy{
LINPHONE_POLICY_NO_FIREWALL,
LINPHONE_POLICY_USE_NAT_ADDRESS,
LINPHONE_POLICY_USE_STUN
LinphonePolicyNoFirewall,
LinphonePolicyUseNatAddress,
LinphonePolicyUseStun
} LinphoneFirewallPolicy;
typedef enum _LinphoneWaitingState{
@ -486,7 +570,6 @@ typedef enum _LinphoneWaitingState{
} LinphoneWaitingState;
typedef void * (*LinphoneWaitingCallback)(struct _LinphoneCore *lc, void *context, LinphoneWaitingState ws, const char *purpose, float progress);
typedef struct _LinphoneCore LinphoneCore;
/* THE main API */
@ -505,21 +588,41 @@ void linphone_core_iterate(LinphoneCore *lc);
LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url);
int linphone_core_invite(LinphoneCore *lc, const char *url);
LinphoneCall * linphone_core_invite(LinphoneCore *lc, const char *url);
int linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddress *addr);
LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddress *addr);
int linphone_core_refer(LinphoneCore *lc, const char *url);
LinphoneCall * linphone_core_invite_with_params(LinphoneCore *lc, const char *url, const LinphoneCallParams *params);
LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const LinphoneAddress *addr, const LinphoneCallParams *params);
int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char *refer_to);
int linphone_core_transfer_call_to_another(LinphoneCore *lc, LinphoneCall *call, LinphoneCall *dest);
bool_t linphone_core_inc_invite_pending(LinphoneCore*lc);
bool_t linphone_core_in_call(const LinphoneCore *lc);
LinphoneCall *linphone_core_get_current_call(LinphoneCore *lc);
LinphoneCall *linphone_core_get_current_call(const LinphoneCore *lc);
int linphone_core_accept_call(LinphoneCore *lc, const char *url);
int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call);
int linphone_core_terminate_call(LinphoneCore *lc, const char *url);
int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *call);
int linphone_core_terminate_all_calls(LinphoneCore *lc);
int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call);
int linphone_core_pause_all_calls(LinphoneCore *lc);
int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call);
int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, LinphoneCallParams *params);
LinphoneCallParams *linphone_core_create_default_call_parameters(LinphoneCore *lc);
LinphoneCall *linphone_core_get_call_by_remote_address(LinphoneCore *lc, const char *remote_address);
void linphone_core_send_dtmf(LinphoneCore *lc,char dtmf);
@ -527,6 +630,8 @@ int linphone_core_set_primary_contact(LinphoneCore *lc, const char *contact);
const char *linphone_core_get_primary_contact(LinphoneCore *lc);
const char * linphone_core_get_identity(LinphoneCore *lc);
void linphone_core_set_guess_hostname(LinphoneCore *lc, bool_t val);
bool_t linphone_core_get_guess_hostname(LinphoneCore *lc);
@ -534,7 +639,7 @@ bool_t linphone_core_ipv6_enabled(LinphoneCore *lc);
void linphone_core_enable_ipv6(LinphoneCore *lc, bool_t val);
LinphoneAddress *linphone_core_get_primary_contact_parsed(LinphoneCore *lc);
const char * linphone_core_get_identity(LinphoneCore *lc);
/*0= no bandwidth limit*/
void linphone_core_set_download_bandwidth(LinphoneCore *lc, int bw);
void linphone_core_set_upload_bandwidth(LinphoneCore *lc, int bw);
@ -553,13 +658,6 @@ void linphone_core_set_download_ptime(LinphoneCore *lc, int ptime);
*/
int linphone_core_get_download_ptime(LinphoneCore *lc);
#ifdef VINCENT_MAURY_RSVP
/* QoS functions */
int linphone_core_set_rpc_mode(LinphoneCore *lc, int on); /* on = 1 (RPC_ENABLE = 1) */
int linphone_core_set_rsvp_mode(LinphoneCore *lc, int on); /* on = 1 (RSVP_ENABLE = 1) */
int linphone_core_change_qos(LinphoneCore *lc, int answer); /* answer = 1 for yes, 0 for no */
#endif
/* returns a MSList of PayloadType */
const MSList *linphone_core_get_audio_codecs(const LinphoneCore *lc);
@ -573,12 +671,6 @@ bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, PayloadType *pt);
int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadType *pt, bool_t enable);
/*
* get payload type from mime type an clock rate
* @ingroup media_parameters
* iterates both audio an video
* return NULL if not found
*/
PayloadType* linphone_core_find_payload_type(LinphoneCore* lc, const char* type, int rate) ;
const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt);
@ -692,6 +784,10 @@ void linphone_core_set_ring(LinphoneCore *lc, const char *path);
const char *linphone_core_get_ring(const LinphoneCore *lc);
void linphone_core_set_ringback(LinphoneCore *lc, const char *path);
const char * linphone_core_get_ringback(const LinphoneCore *lc);
void linphone_core_set_remote_ringback_tone(LinphoneCore *lc,const char *);
const char *linphone_core_get_remote_ringback_tone(const LinphoneCore *lc);
int linphone_core_preview_ring(LinphoneCore *lc, const char *ring,LinphoneCoreCbFunc func,void * userdata);
void linphone_core_enable_echo_cancellation(LinphoneCore *lc, bool_t val);
bool_t linphone_core_echo_cancellation_enabled(LinphoneCore *lc);
@ -716,20 +812,6 @@ bool_t linphone_core_is_rtp_muted(LinphoneCore *lc);
bool_t linphone_core_get_rtp_no_xmit_on_audio_mute(const LinphoneCore *lc);
void linphone_core_set_rtp_no_xmit_on_audio_mute(LinphoneCore *lc, bool_t val);
void linphone_core_set_presence_info(LinphoneCore *lc,int minutes_away,const char *contact,LinphoneOnlineStatus os);
LinphoneOnlineStatus linphone_core_get_presence_info(const LinphoneCore *lc);
void linphone_core_interpret_friend_uri(LinphoneCore *lc, const char *uri, char **result);
void linphone_core_add_friend(LinphoneCore *lc, LinphoneFriend *fr);
void linphone_core_remove_friend(LinphoneCore *lc, LinphoneFriend *fr);
void linphone_core_reject_subscriber(LinphoneCore *lc, LinphoneFriend *lf);
/* a list of LinphoneFriend */
const MSList * linphone_core_get_friend_list(const LinphoneCore *lc);
/* notify all friends that have subscribed */
void linphone_core_notify_all_friends(LinphoneCore *lc, LinphoneOnlineStatus os);
LinphoneFriend *linphone_core_get_friend_by_address(const LinphoneCore *lc, const char *addr);
LinphoneFriend *linphone_core_get_friend_by_ref_key(const LinphoneCore *lc, const char *key);
/* returns a list of LinphoneCallLog */
const MSList * linphone_core_get_call_logs(LinphoneCore *lc);
@ -764,18 +846,29 @@ const char *linphone_core_get_video_device(const LinphoneCore *lc);
/* Set static picture to be used when "Static picture" is the video device */
int linphone_core_set_static_picture(LinphoneCore *lc, const char *path);
/* Set and get frame rate for static picture */
int linphone_core_set_static_picture_fps(LinphoneCore *lc, float fps);
float linphone_core_get_static_picture_fps(LinphoneCore *lc);
/*function to be used for eventually setting window decorations (icons, title...)*/
unsigned long linphone_core_get_native_video_window_id(const LinphoneCore *lc);
void linphone_core_set_native_video_window_id(LinphoneCore *lc, unsigned long id);
unsigned long linphone_core_get_native_preview_window_id(const LinphoneCore *lc);
void linphone_core_set_native_preview_window_id(LinphoneCore *lc, unsigned long id);
void linphone_core_use_preview_window(LinphoneCore *lc, bool_t yesno);
/*play/record support: use files instead of soundcard*/
void linphone_core_use_files(LinphoneCore *lc, bool_t yesno);
void linphone_core_set_play_file(LinphoneCore *lc, const char *file);
void linphone_core_set_record_file(LinphoneCore *lc, const char *file);
gstate_t linphone_core_get_state(const LinphoneCore *lc, gstate_group_t group);
void linphone_core_play_dtmf(LinphoneCore *lc, char dtmf, int duration_ms);
void linphone_core_stop_dtmf(LinphoneCore *lc);
int linphone_core_get_current_call_duration(const LinphoneCore *lc);
const LinphoneAddress *linphone_core_get_remote_uri(LinphoneCore *lc);
int linphone_core_get_mtu(const LinphoneCore *lc);
void linphone_core_set_mtu(LinphoneCore *lc, int mtu);
@ -821,8 +914,14 @@ void linphone_core_set_audio_transports(LinphoneCore *lc, RtpTransport *rtp, Rtp
int linphone_core_get_current_call_stats(LinphoneCore *lc, rtp_stats_t *local, rtp_stats_t *remote);
const MSList *linphone_core_get_calls(LinphoneCore *lc);
LinphoneGlobalState linphone_core_get_global_state(const LinphoneCore *lc);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -24,6 +24,8 @@ extern "C" void libmsilbc_init();
#endif /*ANDROID*/
extern "C" void ms_andsnd_set_jvm(JavaVM *jvm) ;
extern "C" void ms_andvid_set_jvm(JavaVM *jvm) ;
static JavaVM *jvm=0;
#ifdef ANDROID
@ -45,6 +47,9 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *ajvm, void *reserved)
{
#ifdef ANDROID
ms_andsnd_set_jvm(ajvm);
#ifdef VIDEO_ENABLED
ms_andvid_set_jvm(ajvm);
#endif /*VIDEO_ENABLED*/
#endif /*ANDROID*/
jvm=ajvm;
return JNI_VERSION_1_2;
@ -72,21 +77,57 @@ public:
userdata = auserdata?env->NewGlobalRef(auserdata):0;
memset(&vTable,0,sizeof(vTable));
vTable.show = showInterfaceCb;
vTable.inv_recv = inviteReceivedCb;
vTable.auth_info_requested = authInfoRequested;
vTable.display_status = displayStatusCb;
vTable.display_message = displayMessageCb;
vTable.display_warning = displayMessageCb;
vTable.general_state = generalStateChange;
vTable.global_state_changed = globalStateChange;
vTable.registration_state_changed = registrationStateChange;
vTable.call_state_changed = callStateChange;
vTable.text_received = text_received;
vTable.new_subscription_request = new_subscription_request;
vTable.notify_presence_recv = notify_presence_recv;
listernerClass = (jclass)env->NewGlobalRef(env->GetObjectClass( alistener));
/*displayStatus(LinphoneCore lc,String message);*/
displayStatusId = env->GetMethodID(listernerClass,"displayStatus","(Lorg/linphone/core/LinphoneCore;Ljava/lang/String;)V");
/*void generalState(LinphoneCore lc,int state); */
generalStateId = env->GetMethodID(listernerClass,"generalState","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCore$GeneralState;Ljava/lang/String;)V");
globalStateId = env->GetMethodID(listernerClass,"globalState","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCore$GlobalState;Ljava/lang/String;)V");
globalStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCore$GlobalState"));
globalStateFromIntId = env->GetStaticMethodID(globalStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneCore$GlobalState;");
/*registrationState(LinphoneCore lc, LinphoneProxyConfig cfg, LinphoneCore.RegistrationState cstate, String smessage);*/
registrationStateId = env->GetMethodID(listernerClass,"registrationState","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneProxyConfig;Lorg/linphone/core/LinphoneCore$RegistrationState;Ljava/lang/String;)V");
registrationStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCore$RegistrationState"));
registrationStateFromIntId = env->GetStaticMethodID(registrationStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneCore$RegistrationState;");
/*callState(LinphoneCore lc, LinphoneCall call, LinphoneCall.State cstate,String message);*/
callStateId = env->GetMethodID(listernerClass,"callState","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;Lorg/linphone/core/LinphoneCall$State;Ljava/lang/String;)V");
callStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCall$State"));
callStateFromIntId = env->GetStaticMethodID(callStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneCall$State;");
/*void newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf, String url)*/
newSubscriptionRequestId = env->GetMethodID(listernerClass,"newSubscriptionRequest","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneFriend;Ljava/lang/String;)V");
/*void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf);*/
notifyPresenceReceivedId = env->GetMethodID(listernerClass,"notifyPresenceReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneFriend;)V");
/*void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from,String message);*/
textReceivedId = env->GetMethodID(listernerClass,"textReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;Lorg/linphone/core/LinphoneAddress;Ljava/lang/String;)V");
proxyClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneProxyConfigImpl"));
proxyCtrId = env->GetMethodID(proxyClass,"<init>", "(J)V");
callClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCallImpl"));
callCtrId = env->GetMethodID(callClass,"<init>", "(J)V");
chatRoomClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneChatRoomImpl"));
chatRoomCtrId = env->GetMethodID(chatRoomClass,"<init>", "(J)V");
friendClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneFriendImpl"));;
friendCtrId =env->GetMethodID(friendClass,"<init>", "(J)V");
addressClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneAddressImpl"));
addressCtrId =env->GetMethodID(addressClass,"<init>", "(J)V");
generalStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCore$GeneralState"));
generalStateFromIntId = env->GetStaticMethodID(generalStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneCore$GeneralState;");
}
~LinphoneCoreData() {
@ -96,24 +137,56 @@ public:
env->DeleteGlobalRef(listener);
if (userdata) env->DeleteGlobalRef(userdata);
env->DeleteGlobalRef(listernerClass);
env->DeleteGlobalRef(generalStateClass);
env->DeleteGlobalRef(globalStateClass);
env->DeleteGlobalRef(registrationStateClass);
env->DeleteGlobalRef(callStateClass);
env->DeleteGlobalRef(proxyClass);
env->DeleteGlobalRef(callClass);
env->DeleteGlobalRef(chatRoomClass);
env->DeleteGlobalRef(friendClass);
}
jobject core;
jobject listener;
jobject userdata;
jclass listernerClass;
jclass generalStateClass;
jmethodID displayStatusId;
jmethodID generalStateId;
jmethodID generalStateFromIntId;
jmethodID newSubscriptionRequestId;
jmethodID notifyPresenceReceivedId;
jmethodID textReceivedId;
jclass globalStateClass;
jmethodID globalStateId;
jmethodID globalStateFromIntId;
jclass registrationStateClass;
jmethodID registrationStateId;
jmethodID registrationStateFromIntId;
jclass callStateClass;
jmethodID callStateId;
jmethodID callStateFromIntId;
jclass proxyClass;
jmethodID proxyCtrId;
jclass callClass;
jmethodID callCtrId;
jclass chatRoomClass;
jmethodID chatRoomCtrId;
jclass friendClass;
jmethodID friendCtrId;
jclass addressClass;
jmethodID addressCtrId;
LinphoneCoreVTable vTable;
static void showInterfaceCb(LinphoneCore *lc) {
}
static void inviteReceivedCb(LinphoneCore *lc, const char *from) {
}
static void byeReceivedCb(LinphoneCore *lc, const char *from) {
@ -134,7 +207,7 @@ public:
static void authInfoRequested(LinphoneCore *lc, const char *realm, const char *username) {
}
static void generalStateChange(LinphoneCore *lc, LinphoneGeneralState *gstate) {
static void globalStateChange(LinphoneCore *lc, LinphoneGlobalState gstate,const char* message) {
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
@ -143,11 +216,84 @@ public:
}
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc);
env->CallVoidMethod(lcData->listener
,lcData->generalStateId
,lcData->globalStateId
,lcData->core
,env->CallStaticObjectMethod(lcData->generalStateClass,lcData->generalStateFromIntId,gstate->new_state),
gstate->message ? env->NewStringUTF(gstate->message) : NULL);
,env->CallStaticObjectMethod(lcData->globalStateClass,lcData->globalStateFromIntId,(jint)gstate),
message ? env->NewStringUTF(message) : NULL);
}
static void registrationStateChange(LinphoneCore *lc, LinphoneProxyConfig* proxy,LinphoneRegistrationState state,const char* message) {
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
ms_error("cannot attach VM\n");
return;
}
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc);
env->CallVoidMethod(lcData->listener
,lcData->registrationStateId
,lcData->core
,env->NewObject(lcData->proxyClass,lcData->proxyCtrId,(jlong)proxy)
,env->CallStaticObjectMethod(lcData->registrationStateClass,lcData->registrationStateFromIntId,(jint)state),
message ? env->NewStringUTF(message) : NULL);
}
static void callStateChange(LinphoneCore *lc, LinphoneCall* call,LinphoneCallState state,const char* message) {
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
ms_error("cannot attach VM\n");
return;
}
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc);
env->CallVoidMethod(lcData->listener
,lcData->callStateId
,lcData->core
,env->NewObject(lcData->callClass,lcData->callCtrId,(jlong)call)
,env->CallStaticObjectMethod(lcData->callStateClass,lcData->callStateFromIntId,(jint)state),
message ? env->NewStringUTF(message) : NULL);
}
static void notify_presence_recv (LinphoneCore *lc, LinphoneFriend *my_friend) {
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
ms_error("cannot attach VM\n");
return;
}
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc);
env->CallVoidMethod(lcData->listener
,lcData->notifyPresenceReceivedId
,lcData->core
,env->NewObject(lcData->friendClass,lcData->friendCtrId,(jlong)my_friend));
}
static void new_subscription_request (LinphoneCore *lc, LinphoneFriend *my_friend, const char* url) {
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
ms_error("cannot attach VM\n");
return;
}
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc);
env->CallVoidMethod(lcData->listener
,lcData->newSubscriptionRequestId
,lcData->core
,env->NewObject(lcData->friendClass,lcData->friendCtrId,(jlong)my_friend)
,url ? env->NewStringUTF(url) : NULL);
}
static void text_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from, const char *message) {
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
ms_error("cannot attach VM\n");
return;
}
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc);
env->CallVoidMethod(lcData->listener
,lcData->textReceivedId
,lcData->core
,env->NewObject(lcData->chatRoomClass,lcData->chatRoomCtrId,(jlong)room)
,env->NewObject(lcData->addressClass,lcData->addressCtrId,(jlong)from)
,message ? env->NewStringUTF(message) : NULL);
}
};
extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_newLinphoneCore(JNIEnv* env
@ -157,8 +303,8 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_newLinphoneCore(JNIEnv*
,jstring jfactoryConfig
,jobject juserdata){
const char* userConfig = env->GetStringUTFChars(juserConfig, NULL);
const char* factoryConfig = env->GetStringUTFChars(jfactoryConfig, NULL);
const char* userConfig = juserConfig?env->GetStringUTFChars(juserConfig, NULL):NULL;
const char* factoryConfig = jfactoryConfig?env->GetStringUTFChars(jfactoryConfig, NULL):NULL;
LinphoneCoreData* ldata = new LinphoneCoreData(env,thiz,jlistener,juserdata);
#ifdef ANDROID
ms_andsnd_set_jvm(jvm);
@ -176,8 +322,8 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_newLinphoneCore(JNIEnv*
//clear existing proxy config
linphone_core_clear_proxy_config((LinphoneCore*) nativePtr);
env->ReleaseStringUTFChars(juserConfig, userConfig);
env->ReleaseStringUTFChars(jfactoryConfig, factoryConfig);
if (userConfig) env->ReleaseStringUTFChars(juserConfig, userConfig);
if (factoryConfig) env->ReleaseStringUTFChars(jfactoryConfig, factoryConfig);
return nativePtr;
}
extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_delete(JNIEnv* env
@ -232,31 +378,33 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_iterate( JNIEnv* env
,jlong lc) {
linphone_core_iterate((LinphoneCore*)lc);
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_invite( JNIEnv* env
extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_invite( JNIEnv* env
,jobject thiz
,jlong lc
,jstring juri) {
const char* uri = env->GetStringUTFChars(juri, NULL);
linphone_core_invite((LinphoneCore*)lc,uri);
LinphoneCall* lCall = linphone_core_invite((LinphoneCore*)lc,uri);
env->ReleaseStringUTFChars(juri, uri);
return (jlong)lCall;
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_inviteAddress( JNIEnv* env
extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_inviteAddress( JNIEnv* env
,jobject thiz
,jlong lc
,jlong to) {
linphone_core_invite_address((LinphoneCore*)lc,(LinphoneAddress*)to);
return (jlong) linphone_core_invite_address((LinphoneCore*)lc,(LinphoneAddress*)to);
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_terminateCall( JNIEnv* env
,jobject thiz
,jlong lc) {
linphone_core_terminate_call((LinphoneCore*)lc,NULL);
,jlong lc
,jlong call) {
linphone_core_terminate_call((LinphoneCore*)lc,(LinphoneCall*)call);
}
extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_getRemoteAddress( JNIEnv* env
,jobject thiz
,jlong lc) {
return (jlong)linphone_core_get_remote_uri((LinphoneCore*)lc);
return (jlong)linphone_core_get_current_call_remote_address((LinphoneCore*)lc);
}
extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isInCall( JNIEnv* env
,jobject thiz
@ -272,9 +420,10 @@ extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isInComingInvitePend
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_acceptCall( JNIEnv* env
,jobject thiz
,jlong lc) {
,jlong lc
,jlong call) {
linphone_core_accept_call((LinphoneCore*)lc,NULL);
linphone_core_accept_call((LinphoneCore*)lc,(LinphoneCall*)call);
}
extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_getCallLog( JNIEnv* env
@ -330,6 +479,19 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_sendDtmf( JNIEnv* env
,jchar dtmf) {
linphone_core_send_dtmf((LinphoneCore*)lc,dtmf);
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_playDtmf( JNIEnv* env
,jobject thiz
,jlong lc
,jchar dtmf
,jint duration) {
linphone_core_play_dtmf((LinphoneCore*)lc,dtmf,duration);
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_stopDtmf( JNIEnv* env
,jobject thiz
,jlong lc) {
linphone_core_stop_dtmf((LinphoneCore*)lc);
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_clearCallLogs(JNIEnv* env
,jobject thiz
,jlong lc) {
@ -370,6 +532,74 @@ extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isEchoCancellationEn
return linphone_core_echo_cancellation_enabled((LinphoneCore*)lc);
}
extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_getCurrentCall(JNIEnv* env
,jobject thiz
,jlong lc
) {
return (jlong)linphone_core_get_current_call((LinphoneCore*)lc);
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_addFriend(JNIEnv* env
,jobject thiz
,jlong lc
,jlong aFriend
) {
linphone_core_add_friend((LinphoneCore*)lc,(LinphoneFriend*)aFriend);
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPresenceInfo(JNIEnv* env
,jobject thiz
,jlong lc
,jint minute_away
,jstring jalternative_contact
,jint status) {
const char* alternative_contact = jalternative_contact?env->GetStringUTFChars(jalternative_contact, NULL):NULL;
linphone_core_set_presence_info((LinphoneCore*)lc,minute_away,alternative_contact,(LinphoneOnlineStatus)status);
if (alternative_contact) env->ReleaseStringUTFChars(jalternative_contact, alternative_contact);
}
extern "C" long Java_org_linphone_core_LinphoneCoreImpl_createChatRoom(JNIEnv* env
,jobject thiz
,jlong lc
,jstring jto) {
const char* to = env->GetStringUTFChars(jto, NULL);
LinphoneChatRoom* lResult = linphone_core_create_chat_room((LinphoneCore*)lc,to);
env->ReleaseStringUTFChars(jto, to);
return (long)lResult;
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_enableVideo(JNIEnv* env
,jobject thiz
,jlong lc
,jboolean vcap_enabled
,jboolean display_enabled) {
linphone_core_enable_video((LinphoneCore*)lc, vcap_enabled,display_enabled);
}
extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isVideoEnabled(JNIEnv* env
,jobject thiz
,jlong lc) {
return linphone_core_video_enabled((LinphoneCore*)lc);
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setRing(JNIEnv* env
,jobject thiz
,jlong lc
,jstring jpath) {
const char* path = jpath?env->GetStringUTFChars(jpath, NULL):NULL;
linphone_core_set_ring((LinphoneCore*)lc,path);
if (path) env->ReleaseStringUTFChars(jpath, path);
}
extern "C" jstring Java_org_linphone_core_LinphoneCoreImpl_getRing(JNIEnv* env
,jobject thiz
,jlong lc
) {
const char* path = linphone_core_get_ring((LinphoneCore*)lc);
if (path) {
return env->NewStringUTF(path);
} else {
return NULL;
}
}
//ProxyConfig
@ -409,10 +639,14 @@ extern "C" jstring Java_org_linphone_core_LinphoneProxyConfigImpl_getProxy(JNIEn
}
}
extern "C" int Java_org_linphone_core_LinphoneProxyConfigImpl_setRoute(JNIEnv* env,jobject thiz,jlong proxyCfg,jstring jroute) {
const char* route = env->GetStringUTFChars(jroute, NULL);
int err=linphone_proxy_config_set_route((LinphoneProxyConfig*)proxyCfg,route);
env->ReleaseStringUTFChars(jroute, route);
return err;
if (jroute != NULL) {
const char* route = env->GetStringUTFChars(jroute, NULL);
int err=linphone_proxy_config_set_route((LinphoneProxyConfig*)proxyCfg,route);
env->ReleaseStringUTFChars(jroute, route);
return err;
} else {
return linphone_proxy_config_set_route((LinphoneProxyConfig*)proxyCfg,NULL);
}
}
extern "C" jstring Java_org_linphone_core_LinphoneProxyConfigImpl_getRoute(JNIEnv* env,jobject thiz,jlong proxyCfg) {
const char* route = linphone_proxy_config_get_route((LinphoneProxyConfig*)proxyCfg);
@ -477,6 +711,7 @@ extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_setDialPrefix(JNI
env->ReleaseStringUTFChars(jprefix, prefix);
}
//Auth Info
extern "C" jlong Java_org_linphone_core_LinphoneAuthInfoImpl_newLinphoneAuthInfo(JNIEnv* env
@ -612,3 +847,203 @@ extern "C" jstring Java_org_linphone_core_PayloadTypeImpl_toString(JNIEnv* env
ms_free(value);
return jvalue;
}
//LinphoneCall
extern "C" void Java_org_linphone_core_LinphoneCallImpl_ref(JNIEnv* env
,jobject thiz
,jlong ptr) {
linphone_call_ref((LinphoneCall*)ptr);
}
extern "C" void Java_org_linphone_core_LinphoneCallImpl_unref(JNIEnv* env
,jobject thiz
,jlong ptr) {
linphone_call_unref((LinphoneCall*)ptr);
}
extern "C" jlong Java_org_linphone_core_LinphoneCallImpl_getCallLog( JNIEnv* env
,jobject thiz
,jlong ptr) {
return (jlong)linphone_call_get_call_log((LinphoneCall*)ptr);
}
extern "C" jboolean Java_org_linphone_core_LinphoneCallImpl_isIncoming( JNIEnv* env
,jobject thiz
,jlong ptr) {
return linphone_call_get_dir((LinphoneCall*)ptr)==LinphoneCallIncoming?JNI_TRUE:JNI_FALSE;
}
extern "C" jlong Java_org_linphone_core_LinphoneCallImpl_getRemoteAddress( JNIEnv* env
,jobject thiz
,jlong ptr) {
return (jlong)linphone_call_get_remote_address((LinphoneCall*)ptr);
}
extern "C" jint Java_org_linphone_core_LinphoneCallImpl_getState( JNIEnv* env
,jobject thiz
,jlong ptr) {
return (jint)linphone_call_get_state((LinphoneCall*)ptr);
}
//LinphoneFriend
extern "C" long Java_org_linphone_core_LinphoneFriendImpl_newLinphoneFriend(JNIEnv* env
,jobject thiz
,jstring jFriendUri) {
LinphoneFriend* lResult;
if (jFriendUri) {
const char* friendUri = env->GetStringUTFChars(jFriendUri, NULL);
lResult= linphone_friend_new_with_addr(friendUri);
env->ReleaseStringUTFChars(jFriendUri, friendUri);
} else {
lResult = linphone_friend_new();
}
return (long)lResult;
}
extern "C" void Java_org_linphone_core_LinphoneFriendImpl_setAddress(JNIEnv* env
,jobject thiz
,jlong ptr
,jlong linphoneAddress) {
linphone_friend_set_addr((LinphoneFriend*)ptr,(LinphoneAddress*)linphoneAddress);
}
extern "C" long Java_org_linphone_core_LinphoneFriendImpl_getAddress(JNIEnv* env
,jobject thiz
,jlong ptr) {
return (long)linphone_friend_get_address((LinphoneFriend*)ptr);
}
extern "C" void Java_org_linphone_core_LinphoneFriendImpl_setIncSubscribePolicy(JNIEnv* env
,jobject thiz
,jlong ptr
,jint policy) {
linphone_friend_set_inc_subscribe_policy((LinphoneFriend*)ptr,(LinphoneSubscribePolicy)policy);
}
extern "C" jint Java_org_linphone_core_LinphoneFriendImpl_getIncSubscribePolicy(JNIEnv* env
,jobject thiz
,jlong ptr) {
return linphone_friend_get_inc_subscribe_policy((LinphoneFriend*)ptr);
}
extern "C" void Java_org_linphone_core_LinphoneFriendImpl_enableSubscribes(JNIEnv* env
,jobject thiz
,jlong ptr
,jboolean value) {
linphone_friend_enable_subscribes((LinphoneFriend*)ptr,value);
}
extern "C" jboolean Java_org_linphone_core_LinphoneFriendImpl_isSubscribesEnabled(JNIEnv* env
,jobject thiz
,jlong ptr) {
return linphone_friend_subscribes_enabled((LinphoneFriend*)ptr);
}
extern "C" jboolean Java_org_linphone_core_LinphoneFriendImpl_getStatus(JNIEnv* env
,jobject thiz
,jlong ptr) {
return linphone_friend_get_status((LinphoneFriend*)ptr);
}
extern "C" void Java_org_linphone_core_LinphoneFriendImpl_edit(JNIEnv* env
,jobject thiz
,jlong ptr) {
return linphone_friend_edit((LinphoneFriend*)ptr);
}
extern "C" void Java_org_linphone_core_LinphoneFriendImpl_done(JNIEnv* env
,jobject thiz
,jlong ptr) {
linphone_friend_done((LinphoneFriend*)ptr);
}
//LinphoneChatRoom
extern "C" long Java_org_linphone_core_LinphoneChatRoomImpl_getPeerAddress(JNIEnv* env
,jobject thiz
,jlong ptr) {
return (long) linphone_chat_room_get_peer_address((LinphoneChatRoom*)ptr);
}
extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_sendMessage(JNIEnv* env
,jobject thiz
,jlong ptr
,jstring jmessage) {
const char* message = env->GetStringUTFChars(jmessage, NULL);
linphone_chat_room_send_message((LinphoneChatRoom*)ptr,message);
env->ReleaseStringUTFChars(jmessage, message);
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setVideoWindowId(JNIEnv* env
,jobject thiz
,jlong lc
,jobject obj) {
linphone_core_set_native_video_window_id((LinphoneCore*)lc,(unsigned long)obj);
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setFirewallPolicy(JNIEnv *env, jobject thiz, jlong lc, int enum_value){
linphone_core_set_firewall_policy((LinphoneCore*)lc,(LinphoneFirewallPolicy)enum_value);
}
extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getFirewallPolicy(JNIEnv *env, jobject thiz, jlong lc){
return linphone_core_get_firewall_policy((LinphoneCore*)lc);
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setStunServer(JNIEnv *env, jobject thiz, jlong lc, jstring jserver){
const char* server = NULL;
if (jserver) server=env->GetStringUTFChars(jserver, NULL);
linphone_core_set_stun_server((LinphoneCore*)lc,server);
if (server) env->ReleaseStringUTFChars(jserver,server);
}
extern "C" jstring Java_org_linphone_core_LinphoneCoreImpl_getStunServer(JNIEnv *env, jobject thiz, jlong lc){
const char *ret= linphone_core_get_stun_server((LinphoneCore*)lc);
if (ret==NULL) return NULL;
jstring jvalue =env->NewStringUTF(ret);
return jvalue;
}
extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_enableVideo(JNIEnv *env, jobject thiz, jlong lcp, jboolean b){
linphone_call_params_enable_video((LinphoneCallParams*)lcp, b);
}
extern "C" jboolean Java_org_linphone_core_LinphoneCallParamsImpl_getVideoEnabled(JNIEnv *env, jobject thiz, jlong lcp){
return linphone_call_params_video_enabled((LinphoneCallParams*)lcp);
}
extern "C" jlong Java_org_linphone_core_LinphoneCallParamsImpl_copy(JNIEnv *env, jobject thiz, jlong lcp){
return (jlong) linphone_call_params_copy((LinphoneCallParams*)lcp);
}
extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_createDefaultCallParams(JNIEnv *env, jobject thiz, jlong lc){
return (jlong) linphone_core_create_default_call_parameters((LinphoneCore*)lc);
}
extern "C" jlong Java_org_linphone_core_LinphoneCallImpl_getCurrentParams(JNIEnv *env, jobject thiz, jlong lc){
return (jlong) linphone_call_get_current_params((LinphoneCall*)lc);
}
extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_inviteAddressWithParams(JNIEnv *env, jobject thiz, jlong lc, jlong addr, jlong params){
return (jlong) linphone_core_invite_address_with_params((LinphoneCore *)lc, (const LinphoneAddress *)addr, (const LinphoneCallParams *)params);
}
extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_updateAddressWithParams(JNIEnv *env, jobject thiz, jlong lc, jlong call, jlong params){
return (jint) linphone_core_update_call((LinphoneCore *)lc, (LinphoneCall *)call, (LinphoneCallParams *)params);
}
extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_updateCall(JNIEnv *env, jobject thiz, jlong lc, jlong call, jlong params){
return (jint) linphone_core_update_call((LinphoneCore *)lc, (LinphoneCall *)call, (LinphoneCallParams *)params);
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPreferredVideoSize(JNIEnv *env, jobject thiz, jlong lc, jint width, jint height){
MSVideoSize vsize;
vsize.width = (int)width;
vsize.height = (int)height;
linphone_core_set_preferred_video_size((LinphoneCore *)lc, vsize);
}
extern "C" jintArray Java_org_linphone_core_LinphoneCoreImpl_getPreferredVideoSize(JNIEnv *env, jobject thiz, jlong lc){
MSVideoSize vsize = linphone_core_get_preferred_video_size((LinphoneCore *)lc);
jintArray arr = env->NewIntArray(2);
int tVsize [2]= {vsize.width,vsize.height};
env->SetIntArrayRegion(arr, 0, 2, tVsize);
return arr;
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setDownloadBandwidth(JNIEnv *env, jobject thiz, jlong lc, jint bw){
linphone_core_set_download_bandwidth((LinphoneCore *)lc, (int) bw);
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setUploadBandwidth(JNIEnv *env, jobject thiz, jlong lc, jint bw){
linphone_core_set_upload_bandwidth((LinphoneCore *)lc, (int) bw);
}

View file

@ -0,0 +1,52 @@
/*
linphone
Copyright (C) 2010 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.
*/
#ifndef LINPHONECORE_UTILS_H
#define LINPHONECORE_UTILS_H
#ifdef IN_LINPHONE
#include "linphonecore.h"
#else
#include "linphone/linphonecore.h"
#endif
typedef struct _LsdPlayer LsdPlayer;
typedef struct _LinphoneSoundDaemon LinphoneSoundDaemon;
typedef void (*LsdEndOfPlayCallback)(LsdPlayer *p);
void lsd_player_set_callback(LsdPlayer *p, LsdEndOfPlayCallback cb);
void lsd_player_set_user_pointer(LsdPlayer *p, void *up);
void *lsd_player_get_user_pointer(const LsdPlayer *p);
int lsd_player_play(LsdPlayer *p, const char *filename);
int lsd_player_stop(LsdPlayer *p);
void lsd_player_enable_loop(LsdPlayer *p, bool_t loopmode);
bool_t lsd_player_loop_enabled(const LsdPlayer *p);
void lsd_player_set_gain(LsdPlayer *p, float gain);
LinphoneSoundDaemon *lsd_player_get_daemon(const LsdPlayer *p);
LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname, int rate, int nchannels);
LsdPlayer * linphone_sound_daemon_get_player(LinphoneSoundDaemon *lsd);
void linphone_sound_daemon_release_player(LinphoneSoundDaemon *lsd, LsdPlayer *lsdplayer);
void linphone_sound_daemon_stop_all_players(LinphoneSoundDaemon *obj);
void linphone_sound_daemon_release_all_players(LinphoneSoundDaemon *obj);
void linphone_core_use_sound_daemon(LinphoneCore *lc, LinphoneSoundDaemon *lsd);
void linphone_sound_daemon_destroy(LinphoneSoundDaemon *obj);
#endif

267
coreapi/linphonefriend.h Normal file
View file

@ -0,0 +1,267 @@
/*
linphonefriend.h
Copyright (C) 2010 Belledonne Communications SARL
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef LINPHONEFRIEND_H_
#define LINPHONEFRIEND_H_
#ifdef __cplusplus
extern "C" {
#endif
/**
* @addtogroup buddy_list
* @{
*/
/**
* @ingroup buddy_list
* Enum controlling behavior for incoming subscription request.
* <br> Use by linphone_friend_set_inc_subscribe_policy()
*/
typedef enum {
/**
* Does not automatically accept an incoming subscription request.
* This policy implies that a decision has to be taken for each incoming subscription request notified by callback LinphoneCoreVTable.new_subscription_request
*
*/
LinphoneSPWait,
/**
* Rejects incoming subscription request.
*/
LinphoneSPDeny,
/**
* Automatically accepts a subscription request.
*/
LinphoneSPAccept
}LinphoneSubscribePolicy;
/**
* Enum describing remote friend status
*/
typedef enum _LinphoneOnlineStatus{
/**
* Offline
*/
LinphoneStatusOffline,
/**
* Online
*/
LinphoneStatusOnline,
/**
* Busy
*/
LinphoneStatusBusy,
/**
* Be right back
*/
LinphoneStatusBeRightBack,
/**
* Away
*/
LinphoneStatusAway,
/**
* On the phone
*/
LinphoneStatusOnThePhone,
/**
* Out to lunch
*/
LinphoneStatusOutToLunch,
/**
* Do not disturb
*/
LinphoneStatusDoNotDisturb,
/**
* Moved in this sate, call can be redirected if an alternate contact address has been set using function linphone_core_set_presence_info()
*/
LinphoneStatusMoved,
/**
* Using another messaging service
*/
LinphoneStatusAltService,
/**
* Pending
*/
LinphoneStatusPending,
LinphoneStatusEnd
}LinphoneOnlineStatus;
struct _LinphoneFriend;
/**
* Represents a buddy, all presence actions like subscription and status change notification are performed on this object
*/
typedef struct _LinphoneFriend LinphoneFriend;
/**
* Contructor
* @return a new empty #LinphoneFriend
*/
LinphoneFriend * linphone_friend_new();
/**
* Contructor same as linphone_friend_new() + linphone_friend_set_addr()
* @param addr a buddy address, must be a sip uri like sip:joe@sip.linphone.org
* @return a new #LinphoneFriend with \link linphone_friend_get_address() address initialized \endlink
*/
LinphoneFriend *linphone_friend_new_with_addr(const char *addr);
/**
* Destructor
* @param lf #LinphoneFriend object
*/
void linphone_friend_destroy(LinphoneFriend *lf);
/**
* set #LinphoneAddress for this friend
* @param fr #LinphoneFriend object
* @param address #LinphoneAddress
*/
int linphone_friend_set_addr(LinphoneFriend *fr, const LinphoneAddress* address);
/**
* get address of this friend
* @param lf #LinphoneFriend object
* @return #LinphoneAddress
*/
const LinphoneAddress *linphone_friend_get_address(const LinphoneFriend *lf);
/**
* get subscription flag value
* @param lf #LinphoneFriend object
* @return returns true is subscription is activated for this friend
*
*/
bool_t linphone_friend_subscribes_enabled(const LinphoneFriend *lf);
#define linphone_friend_get_send_subscribe linphone_friend_subscribes_enabled
/**
* Configure #LinphoneFriend to subscribe to presence information
* @param fr #LinphoneFriend object
* @param val if TRUE this friend will receive subscription message
*/
int linphone_friend_enable_subscribes(LinphoneFriend *fr, bool_t val);
#define linphone_friend_send_subscribe linphone_friend_enable_subscribes
/**
* Configure incoming subscription policy for this friend.
* @param fr #LinphoneFriend object
* @param pol #LinphoneSubscribePolicy policy to apply.
*/
int linphone_friend_set_inc_subscribe_policy(LinphoneFriend *fr, LinphoneSubscribePolicy pol);
/**
* get current subscription policy for this #LinphoneFriend
* @param lf #LinphoneFriend object
* @return #LinphoneSubscribePolicy
*
*/
LinphoneSubscribePolicy linphone_friend_get_inc_subscribe_policy(const LinphoneFriend *lf);
/**
* Starts editing a friend configuration.
*
* Because friend configuration must be consistent, applications MUST
* call linphone_friend_edit() before doing any attempts to modify
* friend configuration (such as \link linphone_friend_set_addr() address \endlink or \link linphone_friend_set_inc_subscribe_policy() subscription policy\endlink and so on).
* Once the modifications are done, then the application must call
* linphone_friend_done() to commit the changes.
**/
void linphone_friend_edit(LinphoneFriend *fr);
/**
* Commits modification made to the friend configuration.
* @param fr #LinphoneFriend object
**/
void linphone_friend_done(LinphoneFriend *fr);
/**
* get friend status
* @return #LinphoneOnlineStatus
*/
LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf);
BuddyInfo * linphone_friend_get_info(const LinphoneFriend *lf);
void linphone_friend_set_ref_key(LinphoneFriend *lf, const char *key);
const char *linphone_friend_get_ref_key(const LinphoneFriend *lf);
bool_t linphone_friend_in_list(const LinphoneFriend *lf);
#define linphone_friend_url(lf) ((lf)->url)
/**
* return humain readable presence status
* @param ss
*/
const char *linphone_online_status_to_string(LinphoneOnlineStatus ss);
/**
* Set my presence status
* @param lc #LinphoneCore object
* @param minutes_away how long in away
* @param alternative_contact sip uri used to redirect call in state #LinphoneStatusMoved
* @param os #LinphoneOnlineStatus
*/
void linphone_core_set_presence_info(LinphoneCore *lc,int minutes_away,const char *alternative_contact,LinphoneOnlineStatus os);
/**
* get my presence status
* @param lc #LinphoneCore object
* @return #LinphoneOnlineStatus
*/
LinphoneOnlineStatus linphone_core_get_presence_info(const LinphoneCore *lc);
void linphone_core_interpret_friend_uri(LinphoneCore *lc, const char *uri, char **result);
/**
* Add a friend to the current buddy list, if \link linphone_friend_enable_subscribes() subscription attribute \endlink is set, a SIP SUBSCRIBE message is sent.
* @param lc #LinphoneCore object
* @param fr #LinphoneFriend to add
*/
void linphone_core_add_friend(LinphoneCore *lc, LinphoneFriend *fr);
/**
* remove a friend from the buddy list
* @param lc #LinphoneCore object
* @param fr #LinphoneFriend to add
*/
void linphone_core_remove_friend(LinphoneCore *lc, LinphoneFriend *fr);
/**
* Black list a friend. same as linphone_friend_set_inc_subscribe_policy() with #LinphoneSPDeny policy;
* @param lc #LinphoneCore object
* @param lf #LinphoneFriend to add
*/
void linphone_core_reject_subscriber(LinphoneCore *lc, LinphoneFriend *lf);
/**
* get Buddy list of LinphoneFriend
* @param lc #LinphoneCore object
* */
const MSList * linphone_core_get_friend_list(const LinphoneCore *lc);
/**
* notify all friends that have subscribed
* @param lc #LinphoneCore object
* @param os #LinphoneOnlineStatus to notify
* */
void linphone_core_notify_all_friends(LinphoneCore *lc, LinphoneOnlineStatus os);
LinphoneFriend *linphone_core_get_friend_by_address(const LinphoneCore *lc, const char *addr);
LinphoneFriend *linphone_core_get_friend_by_ref_key(const LinphoneCore *lc, const char *key);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* LINPHONEFRIEND_H_ */

308
coreapi/lsd.c Normal file
View file

@ -0,0 +1,308 @@
/*
linphone
Copyright (C) 2010 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.
*/
/* Linphone Sound Daemon: is a lightweight utility to play sounds to speaker during a conversation.
This is useful for embedded platforms, where sound apis are not performant enough to allow
simultaneous sound access.
*/
#include "linphonecore_utils.h"
#include "private.h"
#include "mediastreamer2/msticker.h"
#include "mediastreamer2/mssndcard.h"
#include "mediastreamer2/msaudiomixer.h"
#include "mediastreamer2/mschanadapter.h"
#include "mediastreamer2/msfileplayer.h"
#include "mediastreamer2/msitc.h"
static struct _MSSndCard *linphone_sound_daemon_get_proxy_card(LinphoneSoundDaemon *obj);
#define MAX_BRANCHES 10
struct _LsdPlayer{
struct _LinphoneSoundDaemon *lsd;
MSFilter *player;
MSFilter *rateconv;
MSFilter *chanadapter;
LsdEndOfPlayCallback eop_cb;
int mixer_pin;
void *user_data;
bool_t loop;
bool_t pad[3];
};
struct _LinphoneSoundDaemon {
int out_rate;
int out_nchans;
MSFilter *mixer;
MSFilter *soundout;
MSTicker *ticker;
MSSndCard *proxycard;
LsdPlayer branches[MAX_BRANCHES];
};
static MSFilter *create_writer(MSSndCard *c){
LinphoneSoundDaemon *lsd=(LinphoneSoundDaemon*)c->data;
MSFilter *itcsink=ms_filter_new(MS_ITC_SINK_ID);
ms_filter_call_method(itcsink,MS_ITC_SINK_CONNECT,lsd->branches[0].player);
return itcsink;
}
static MSSndCardDesc proxycard={
"Linphone Sound Daemon",
/*detect*/ NULL,
/*init*/ NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
/*create_reader*/ NULL,
create_writer,
/*uninit,*/
};
LsdPlayer *linphone_sound_daemon_get_player(LinphoneSoundDaemon *obj){
int i;
for(i=1;i<MAX_BRANCHES;++i){
LsdPlayer *b=&obj->branches[i];
MSFilter *p=b->player;
int state;
ms_filter_call_method(p,MS_PLAYER_GET_STATE,&state);
if (state==MSPlayerClosed){
lsd_player_set_gain(b,1);
lsd_player_enable_loop (b,FALSE);
return b;
}
}
ms_warning("No more free players !");
return NULL;
}
void linphone_sound_daemon_release_player(LinphoneSoundDaemon *obj, LsdPlayer * player){
int state;
ms_filter_call_method(player->player,MS_PLAYER_GET_STATE,&state);
if (state!=MSPlayerClosed){
ms_filter_call_method(player->player,MS_PLAYER_CLOSE,&state);
}
}
LinphoneSoundDaemon *lsd_player_get_daemon(const LsdPlayer *p){
return p->lsd;
}
int lsd_player_stop(LsdPlayer *p){
ms_filter_call_method_noarg(p->player,MS_PLAYER_PAUSE);
return 0;
}
static void lsd_player_init(LsdPlayer *p, MSConnectionPoint mixer, MSFilterId playerid, LinphoneSoundDaemon *lsd){
MSConnectionHelper h;
p->player=ms_filter_new(playerid);
p->rateconv=ms_filter_new(MS_RESAMPLE_ID);
p->chanadapter=ms_filter_new(MS_CHANNEL_ADAPTER_ID);
ms_connection_helper_start(&h);
ms_connection_helper_link(&h,p->player,-1,0);
ms_connection_helper_link(&h,p->rateconv,0,0);
ms_connection_helper_link(&h,p->chanadapter,0,0);
ms_connection_helper_link(&h,mixer.filter,mixer.pin,-1);
p->mixer_pin=mixer.pin;
p->loop=FALSE;
p->lsd=lsd;
}
static void lsd_player_uninit(LsdPlayer *p, MSConnectionPoint mixer){
MSConnectionHelper h;
ms_connection_helper_start(&h);
ms_connection_helper_unlink (&h,p->player,-1,0);
ms_connection_helper_unlink(&h,p->rateconv,0,0);
ms_connection_helper_unlink(&h,p->chanadapter,0,0);
ms_connection_helper_unlink(&h,mixer.filter,mixer.pin,-1);
ms_filter_destroy(p->player);
ms_filter_destroy(p->rateconv);
ms_filter_destroy(p->chanadapter);
}
void lsd_player_set_callback(LsdPlayer *p, LsdEndOfPlayCallback cb){
p->eop_cb=cb;
}
void lsd_player_set_user_pointer(LsdPlayer *p, void *up){
p->user_data=up;
}
void *lsd_player_get_user_pointer(const LsdPlayer *p){
return p->user_data;
}
static void lsd_player_on_eop(void * userdata, unsigned int id, void *arg){
LsdPlayer *p=(LsdPlayer *)userdata;
if (p->eop_cb!=NULL)
p->eop_cb(p);
}
static void lsd_player_configure(LsdPlayer *b){
int rate,chans;
LinphoneSoundDaemon *lsd=b->lsd;
if (ms_filter_get_id(b->player)==MS_ITC_SOURCE_ID)
ms_message("Configuring branch coming from audio call...");
ms_filter_call_method(b->player,MS_FILTER_GET_SAMPLE_RATE,&rate);
ms_filter_call_method(b->player,MS_FILTER_GET_NCHANNELS,&chans);
ms_filter_call_method(b->rateconv,MS_FILTER_SET_SAMPLE_RATE,&rate);
ms_filter_call_method(b->rateconv,MS_FILTER_SET_NCHANNELS,&chans);
ms_filter_call_method(b->rateconv,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&lsd->out_rate);
ms_filter_call_method(b->chanadapter,MS_FILTER_SET_NCHANNELS,&chans);
ms_filter_call_method(b->chanadapter,MS_CHANNEL_ADAPTER_SET_OUTPUT_NCHANNELS,&lsd->out_nchans);
ms_message("player configured for rate=%i, channels=%i",rate,chans);
}
int lsd_player_play(LsdPlayer *b, const char *filename ){
int state;
ms_filter_call_method(b->player,MS_PLAYER_GET_STATE,&state);
if (state!=MSPlayerClosed){
ms_filter_call_method_noarg(b->player,MS_PLAYER_CLOSE);
}
if (ms_filter_call_method(b->player,MS_PLAYER_OPEN,(void*)filename)!=0){
ms_warning("Could not play %s",filename);
return -1;
}
ms_filter_set_notify_callback (b->player,lsd_player_on_eop,b);
lsd_player_configure(b);
ms_filter_call_method_noarg (b->player,MS_PLAYER_START);
return 0;
}
void lsd_player_enable_loop(LsdPlayer *p, bool_t loopmode){
if (ms_filter_get_id(p->player)==MS_FILE_PLAYER_ID){
int arg=loopmode ? 0 : -1;
ms_filter_call_method(p->player,MS_FILE_PLAYER_LOOP,&arg);
p->loop=loopmode;
}
}
bool_t lsd_player_loop_enabled(const LsdPlayer *p){
return p->loop;
}
void lsd_player_set_gain(LsdPlayer *p, float gain){
MSAudioMixerCtl gainctl;
gainctl.pin=p->mixer_pin;
gainctl.gain=gain;
ms_filter_call_method(p->lsd->mixer,MS_AUDIO_MIXER_SET_INPUT_GAIN,&gainctl);
}
LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname, int rate, int nchannels){
int i;
MSConnectionPoint mp;
LinphoneSoundDaemon *lsd;
MSSndCard *card=ms_snd_card_manager_get_card(
ms_snd_card_manager_get(),
cardname);
if (card==NULL){
card=ms_snd_card_manager_get_default_playback_card (
ms_snd_card_manager_get());
if (card==NULL){
ms_error("linphone_sound_daemon_new(): No playback soundcard available");
return NULL;
}
}
lsd=ms_new0(LinphoneSoundDaemon,1);
lsd->soundout=ms_snd_card_create_writer(card);
lsd->mixer=ms_filter_new(MS_AUDIO_MIXER_ID);
lsd->out_rate=rate;
lsd->out_nchans=nchannels;
ms_filter_call_method(lsd->soundout,MS_FILTER_SET_SAMPLE_RATE,&lsd->out_rate);
ms_filter_call_method(lsd->soundout,MS_FILTER_SET_NCHANNELS,&lsd->out_nchans);
ms_filter_call_method(lsd->mixer,MS_FILTER_SET_SAMPLE_RATE,&lsd->out_rate);
ms_filter_call_method(lsd->mixer,MS_FILTER_SET_NCHANNELS,&lsd->out_nchans);
mp.filter=lsd->mixer;
mp.pin=0;
lsd_player_init(&lsd->branches[0],mp,MS_ITC_SOURCE_ID,lsd);
ms_filter_set_notify_callback(lsd->branches[0].player,(MSFilterNotifyFunc)lsd_player_configure,&lsd->branches[0]);
ms_filter_enable_synchronous_notifcations (lsd->branches[0].player,TRUE);
for(i=1;i<MAX_BRANCHES;++i){
mp.pin=i;
lsd_player_init(&lsd->branches[i],mp,MS_FILE_PLAYER_ID,lsd);
}
ms_filter_link(lsd->mixer,0,lsd->soundout,0);
lsd->ticker=ms_ticker_new();
ms_ticker_attach(lsd->ticker,lsd->soundout);
lsd->proxycard=ms_snd_card_new(&proxycard);
lsd->proxycard->data=lsd;
ms_message("LinphoneSoundDaemon started with rate=%i, nchannels=%i",rate,nchannels);
return lsd;
}
void linphone_sound_daemon_stop_all_players(LinphoneSoundDaemon *obj){
int i;
for(i=1;i<MAX_BRANCHES;++i){
lsd_player_stop(&obj->branches[i]);
}
}
void linphone_sound_daemon_release_all_players(LinphoneSoundDaemon *obj){
int i;
for(i=1;i<MAX_BRANCHES;++i){
linphone_sound_daemon_release_player(obj,&obj->branches[i]);
}
}
void linphone_sound_daemon_destroy(LinphoneSoundDaemon *obj){
int i;
MSConnectionPoint mp;
ms_ticker_detach(obj->ticker,obj->soundout);
mp.filter=obj->mixer;
for(i=0;i<MAX_BRANCHES;++i){
mp.pin=i;
if (i!=0) linphone_sound_daemon_release_player(obj,&obj->branches[i]);
lsd_player_uninit (&obj->branches[i],mp);
}
ms_filter_unlink(obj->mixer,0,obj->soundout,0);
ms_ticker_destroy(obj->ticker);
ms_filter_destroy(obj->soundout);
ms_filter_destroy(obj->mixer);
}
MSSndCard *linphone_sound_daemon_get_proxy_card(LinphoneSoundDaemon *lsd){
return lsd->proxycard;
}
void linphone_core_use_sound_daemon(LinphoneCore *lc, LinphoneSoundDaemon *lsd){
if (lsd!=NULL){
lc->sound_conf.lsd_card=linphone_sound_daemon_get_proxy_card (lsd);
}else {
lc->sound_conf.lsd_card=NULL;
}
}

View file

@ -258,6 +258,39 @@ void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc){
}
}
bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, PayloadType *pt, int bandwidth_limit)
{
double codec_band;
bool_t ret=FALSE;
switch (pt->type){
case PAYLOAD_AUDIO_CONTINUOUS:
case PAYLOAD_AUDIO_PACKETIZED:
codec_band=get_audio_payload_bandwidth(lc,pt);
ret=bandwidth_is_greater(bandwidth_limit*1000,codec_band);
/*hack to avoid using uwb codecs when having low bitrate and video*/
if (bandwidth_is_greater(199,bandwidth_limit)){
if (linphone_core_video_enabled(lc) && pt->clock_rate>16000){
ret=FALSE;
}
}
//ms_message("Payload %s: %g",pt->mime_type,codec_band);
break;
case PAYLOAD_VIDEO:
if (bandwidth_limit!=0) {/* infinite (-1) or strictly positive*/
/*let the video use all the bandwidth minus the maximum bandwidth used by audio */
if (bandwidth_limit>0)
pt->normal_bitrate=bandwidth_limit*1000;
else
pt->normal_bitrate=1500000; /*around 1.5 Mbit/s*/
ret=TRUE;
}
else ret=FALSE;
break;
}
return ret;
}
/* return TRUE if codec can be used with bandwidth, FALSE else*/
bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, PayloadType *pt)
{
@ -462,8 +495,13 @@ static int recvStunResponse(ortp_socket_t sock, char *ipaddr, int *port, int *id
struct in_addr ia;
stunParseMessage(buf,len, &resp );
*id=resp.msgHdr.tr_id.octet[0];
*port = resp.mappedAddress.ipv4.port;
ia.s_addr=htonl(resp.mappedAddress.ipv4.addr);
if (resp.hasXorMappedAddress){
*port = resp.xorMappedAddress.ipv4.port;
ia.s_addr=htonl(resp.xorMappedAddress.ipv4.addr);
}else if (resp.hasMappedAddress){
*port = resp.mappedAddress.ipv4.port;
ia.s_addr=htonl(resp.mappedAddress.ipv4.addr);
}else return -1;
strncpy(ipaddr,inet_ntoa(ia),LINPHONE_IPADDR_SIZE);
}
return len;
@ -497,10 +535,10 @@ void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
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(linphone_core_get_audio_port(lc));
sock1=create_socket(call->audio_port);
if (sock1<0) return;
if (video_enabled){
sock2=create_socket(linphone_core_get_video_port(lc));
sock2=create_socket(call->video_port);
if (sock2<0) return ;
}
sendStunRequest(sock1,(struct sockaddr*)&ss,ss_len,11,TRUE);
@ -754,14 +792,10 @@ static int get_local_ip_for_with_connect(int type, const char *dest, char *resul
}
int linphone_core_get_local_ip_for(int type, const char *dest, char *result){
if (dest==NULL) {
if (type==AF_INET)
dest="87.98.157.38"; /*a public IP address*/
else dest="2a00:1450:8002::68";
}
strcpy(result,type==AF_INET ? "127.0.0.1" : "::1");
#ifdef HAVE_GETIFADDRS
{
if (dest==NULL) {
/*we use getifaddrs for lookup of default interface */
int found_ifs;
found_ifs=get_local_ip_with_getifaddrs(type,result,LINPHONE_IPADDR_SIZE);
@ -774,5 +808,33 @@ int linphone_core_get_local_ip_for(int type, const char *dest, char *result){
}
#endif
/*else use connect to find the best local ip address */
if (type==AF_INET)
dest="87.98.157.38"; /*a public IP address*/
else dest="2a00:1450:8002::68";
return get_local_ip_for_with_connect(type,dest,result);
}
#ifndef WIN32
#include <resolv.h>
void _linphone_core_configure_resolver(){
/*bionic declares _res but does not define nor export it !!*/
#ifdef ANDROID
/*timeout and attempts are the same as retrans and retry, but are android specific names.*/
setenv("RES_OPTIONS","timeout:1 attempts:2 retrans:1 retry:2",1);
#else
res_init();
_res.retrans=1; /*retransmit every second*/
_res.retry=2; /*only two times per DNS server*/
#endif
}
#else
void _linphone_core_configure_resolver(){
}
#endif

View file

@ -20,6 +20,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "sal.h"
#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;
}
return TRUE;
}
static PayloadType * find_payload_type_best_match(const MSList *l, const PayloadType *refpt){
PayloadType *pt;
@ -29,7 +36,10 @@ static PayloadType * find_payload_type_best_match(const MSList *l, const Payload
for (elem=l;elem!=NULL;elem=elem->next){
pt=(PayloadType*)elem->data;
if (strcasecmp(pt->mime_type,refpt->mime_type)==0 && pt->clock_rate==refpt->clock_rate){
/* the compare between G729 and G729A is for some stupid uncompliant phone*/
if ( (strcasecmp(pt->mime_type,refpt->mime_type)==0 ||
(strcasecmp(pt->mime_type, "G729") == 0 && strcasecmp(refpt->mime_type, "G729A") == 0 ))
&& pt->clock_rate==refpt->clock_rate){
candidate=pt;
/*good candidate, check fmtp for H264 */
if (strcasecmp(pt->mime_type,"H264")==0){
@ -50,19 +60,46 @@ static PayloadType * find_payload_type_best_match(const MSList *l, const Payload
return candidate;
}
static MSList *match_payloads(const MSList *local, const MSList *remote){
static MSList *match_payloads(const MSList *local, const MSList *remote, bool_t reading_response, bool_t one_matching_codec){
const MSList *e2;
MSList *res=NULL;
PayloadType *matched;
bool_t found_codec=FALSE;
for(e2=remote;e2!=NULL;e2=e2->next){
PayloadType *p2=(PayloadType*)e2->data;
matched=find_payload_type_best_match(local,p2);
if (matched){
matched=payload_type_clone(matched);
PayloadType *newp;
int local_number=payload_type_get_number(matched);
int remote_number=payload_type_get_number(p2);
if (one_matching_codec){
if (strcasecmp(matched->mime_type,"telephone-event")!=0){
if (found_codec){/* we have found a real codec already*/
continue; /*this codec won't be added*/
}else found_codec=TRUE;
}
}
newp=payload_type_clone(matched);
if (p2->send_fmtp)
payload_type_set_send_fmtp(matched,p2->send_fmtp);
res=ms_list_append(res,matched);
payload_type_set_number(matched,payload_type_get_number(p2));
payload_type_set_send_fmtp(newp,p2->send_fmtp);
res=ms_list_append(res,newp);
/* we should use the remote numbering even when parsing a response */
payload_type_set_number(newp,remote_number);
if (reading_response && remote_number!=local_number){
ms_warning("For payload type %s, proposed number was %i but the remote phone answered %i",
newp->mime_type, local_number, remote_number);
/*
We must add this payload type with our local numbering in order to be able to receive it.
Indeed despite we must sent with the remote numbering, we must be able to receive with
our local one.
*/
newp=payload_type_clone(matched);
payload_type_set_number(newp,local_number);
res=ms_list_append(res,newp);
}
}else{
ms_message("No match for %s/%i",p2->mime_type,p2->clock_rate);
}
@ -70,21 +107,32 @@ static MSList *match_payloads(const MSList *local, const MSList *remote){
return res;
}
static bool_t only_telephone_event(const MSList *l){
PayloadType *p=(PayloadType*)l->data;
if (strcasecmp(p->mime_type,"telephone-event")!=0){
return FALSE;
static SalStreamDir compute_dir(SalStreamDir local, SalStreamDir answered){
SalStreamDir res=local;
if (local==SalStreamSendRecv){
if (answered==SalStreamRecvOnly){
res=SalStreamSendOnly;
}else if (answered==SalStreamSendOnly){
res=SalStreamRecvOnly;
}
}
return TRUE;
if (answered==SalStreamInactive){
res=SalStreamInactive;
}
return res;
}
static void initiate_outgoing(const SalStreamDescription *local_offer,
const SalStreamDescription *remote_answer,
SalStreamDescription *result){
if (remote_answer->port!=0)
result->payloads=match_payloads(local_offer->payloads,remote_answer->payloads);
result->payloads=match_payloads(local_offer->payloads,remote_answer->payloads,TRUE,FALSE);
result->proto=local_offer->proto;
result->type=local_offer->type;
result->dir=compute_dir(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;
@ -98,10 +146,17 @@ static void initiate_outgoing(const SalStreamDescription *local_offer,
static void initiate_incoming(const SalStreamDescription *local_cap,
const SalStreamDescription *remote_offer,
SalStreamDescription *result){
result->payloads=match_payloads(local_cap->payloads,remote_offer->payloads);
SalStreamDescription *result, bool_t one_matching_codec){
result->payloads=match_payloads(local_cap->payloads,remote_offer->payloads, FALSE, one_matching_codec);
result->proto=local_cap->proto;
result->type=local_cap->type;
if (remote_offer->dir==SalStreamSendOnly)
result->dir=SalStreamRecvOnly;
else if (remote_offer->dir==SalStreamRecvOnly){
result->dir=SalStreamSendOnly;
}else if (remote_offer->dir==SalStreamInactive){
result->dir=SalStreamInactive;
}else result->dir=SalStreamSendRecv;
if (result->payloads && !only_telephone_event(result->payloads)){
strcpy(result->addr,local_cap->addr);
result->port=local_cap->port;
@ -124,7 +179,7 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
for(i=0,j=0;i<local_offer->nstreams;++i){
ms_message("Processing for stream %i",i);
ls=&local_offer->streams[i];
rs=sal_media_description_find_stream(remote_answer,ls->proto,ls->type);
rs=sal_media_description_find_stream((SalMediaDescription*)remote_answer,ls->proto,ls->type);
if (rs) {
initiate_outgoing(ls,rs,&result->streams[j]);
++j;
@ -143,16 +198,16 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
**/
int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities,
const SalMediaDescription *remote_offer,
SalMediaDescription *result){
SalMediaDescription *result, bool_t one_matching_codec){
int i,j;
const SalStreamDescription *ls,*rs;
for(i=0,j=0;i<remote_offer->nstreams;++i){
rs=&remote_offer->streams[i];
ms_message("Processing for stream %i",i);
ls=sal_media_description_find_stream(local_capabilities,rs->proto,rs->type);
ls=sal_media_description_find_stream((SalMediaDescription*)local_capabilities,rs->proto,rs->type);
if (ls){
initiate_incoming(ls,rs,&result->streams[j]);
initiate_incoming(ls,rs,&result->streams[j],one_matching_codec);
++j;
}
}

View file

@ -41,7 +41,7 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
**/
int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities,
const SalMediaDescription *remote_offer,
SalMediaDescription *result);
SalMediaDescription *result, bool_t one_matching_codec);
#endif

View file

@ -31,9 +31,9 @@ void linphone_core_add_subscriber(LinphoneCore *lc, const char *subscriber, SalO
linphone_friend_set_inc_subscribe_policy(fl,LinphoneSPAccept);
fl->inc_subscribe_pending=TRUE;
lc->subscribers=ms_list_append(lc->subscribers,(void *)fl);
if (lc->vtable.new_unknown_subscriber!=NULL) {
if (lc->vtable.new_subscription_request!=NULL) {
char *tmp=linphone_address_as_string(fl->uri);
lc->vtable.new_unknown_subscriber(lc,fl,tmp);
lc->vtable.new_subscription_request(lc,fl,tmp);
ms_free(tmp);
}
}
@ -57,11 +57,24 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){
LinphoneFriend *lf=NULL;
char *tmp;
LinphoneAddress *uri;
LinphoneProxyConfig *cfg;
const char *fixed_contact;
uri=linphone_address_new(from);
linphone_address_clean(uri);
tmp=linphone_address_as_string(uri);
ms_message("Receiving new subscription from %s.",from);
cfg=linphone_core_lookup_known_proxy(lc,uri);
if (cfg!=NULL){
if (cfg->op){
fixed_contact=sal_op_get_contact(cfg->op);
if (fixed_contact) {
sal_op_set_contact (op,fixed_contact);
ms_message("Contact for next subscribe answer has been fixed using proxy to %s",fixed_contact);
}
}
}
/* check if we answer to this subscription */
if (linphone_find_friend(lc->friends,uri,&lf)!=NULL){
lf->insub=op;
@ -92,36 +105,36 @@ void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeState ss, Sal
char *tmp;
LinphoneFriend *lf;
LinphoneAddress *friend=NULL;
LinphoneOnlineStatus estatus=LINPHONE_STATUS_OFFLINE;
LinphoneOnlineStatus estatus=LinphoneStatusOffline;
switch(sal_status){
case SalPresenceOffline:
estatus=LINPHONE_STATUS_OFFLINE;
estatus=LinphoneStatusOffline;
break;
case SalPresenceOnline:
estatus=LINPHONE_STATUS_ONLINE;
estatus=LinphoneStatusOnline;
break;
case SalPresenceBusy:
estatus=LINPHONE_STATUS_BUSY;
estatus=LinphoneStatusBusy;
break;
case SalPresenceBerightback:
estatus=LINPHONE_STATUS_AWAY;
estatus=LinphoneStatusBeRightBack;
break;
case SalPresenceAway:
estatus=LINPHONE_STATUS_AWAY;
estatus=LinphoneStatusAway;
break;
case SalPresenceOnthephone:
estatus=LINPHONE_STATUS_ONTHEPHONE;
estatus=LinphoneStatusOnThePhone;
break;
case SalPresenceOuttolunch:
estatus=LINPHONE_STATUS_OUTTOLUNCH;
estatus=LinphoneStatusOutToLunch;
break;
case SalPresenceDonotdisturb:
estatus=LINPHONE_STATUS_BUSY;
estatus=LinphoneStatusDoNotDisturb;
break;
case SalPresenceMoved:
case SalPresenceAltService:
estatus=LINPHONE_STATUS_AWAY;
estatus=LinphoneStatusMoved;
break;
}
lf=linphone_find_friend_by_out_subscribe(lc->friends,op);
@ -130,7 +143,8 @@ void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeState ss, Sal
tmp=linphone_address_as_string(friend);
lf->status=estatus;
lf->subscribe_active=TRUE;
lc->vtable.notify_presence_recv(lc,(LinphoneFriend*)lf);
if (lc->vtable.notify_presence_recv)
lc->vtable.notify_presence_recv(lc,(LinphoneFriend*)lf);
ms_free(tmp);
}else{
ms_message("But this person is not part of our friend list, so we don't care.");

View file

@ -31,6 +31,7 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "mediastreamer2/mediastream.h"
#ifndef LIBLINPHONE_VERSION
#define LIBLINPHONE_VERSION LINPHONE_VERSION
@ -54,13 +55,14 @@
#endif
#endif
typedef enum _LCState{
LCStateInit,
LCStatePreEstablishing,
LCStateRinging,
LCStateAVRunning
}LCState;
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 */
bool_t has_video;
bool_t real_early_media; /*send real media even during early media (for outgoing calls)*/
bool_t pad[2];
};
struct _LinphoneCall
{
@ -76,29 +78,43 @@ struct _LinphoneCall
char localip[LINPHONE_IPADDR_SIZE]; /* our best guess for local ipaddress for this call */
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*/
LCState state;
LinphoneCallState state;
LinphoneReason reason;
int refcnt;
void * user_pointer;
int audio_port;
int video_port;
struct _AudioStream *audiostream; /**/
struct _VideoStream *videostream;
char *refer_to;
LinphoneCallParams params;
int up_bw; /*upload bandwidth setting at the time the call is started. Used to detect if it changes during a call */
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;
};
LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to);
LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params);
LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op);
#define linphone_call_set_state(lcall,st) (lcall)->state=(st)
void linphone_call_destroy(struct _LinphoneCall *obj);
void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message);
/* private: */
LinphoneCallLog * linphone_call_log_new(LinphoneCall *call, LinphoneAddress *local, LinphoneAddress * remote);
void linphone_call_log_completed(LinphoneCallLog *calllog, LinphoneCall *call);
void linphone_call_log_completed(LinphoneCallLog *calllog, LinphoneCall *call, LinphoneCallStatus status);
void linphone_call_log_destroy(LinphoneCallLog *cl);
void linphone_core_init_media_streams(LinphoneCore *lc, LinphoneCall *call);
void linphone_auth_info_write_config(struct _LpConfig *config, LinphoneAuthInfo *obj, int pos);
void linphone_core_update_proxy_register(LinphoneCore *lc);
void linphone_core_refresh_subscribes(LinphoneCore *lc);
int linphone_core_abort_call(LinphoneCore *lc, LinphoneCall *call, const char *error);
int linphone_proxy_config_send_publish(LinphoneProxyConfig *cfg, LinphoneOnlineStatus os);
void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrationState rstate, const char *message);
int linphone_online_status_to_eXosip(LinphoneOnlineStatus os);
void linphone_friend_close_subscriptions(LinphoneFriend *lf);
@ -157,6 +173,7 @@ void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc);
void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCore *lc, const PayloadType *pt);
void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call);
void linphone_core_send_initial_subscribes(LinphoneCore *lc);
void linphone_core_write_friends_config(LinphoneCore* lc);
void linphone_friend_write_to_config_file(struct _LpConfig *config, LinphoneFriend *lf, int index);
LinphoneFriend * linphone_friend_new_from_config_file(struct _LinphoneCore *lc, int index);
@ -164,6 +181,7 @@ LinphoneFriend * linphone_friend_new_from_config_file(struct _LinphoneCore *lc,
void linphone_proxy_config_update(LinphoneProxyConfig *cfg);
void linphone_proxy_config_get_contact(LinphoneProxyConfig *cfg, const char **ip, int *port);
LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const LinphoneAddress *uri);
const char *linphone_core_find_best_identity(LinphoneCore *lc, const LinphoneAddress *to, const char **route);
int linphone_core_get_local_ip_for(int type, const char *dest, char *result);
LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(struct _LpConfig *config, int index);
@ -173,19 +191,20 @@ int linphone_proxy_config_normalize_number(LinphoneProxyConfig *cfg, const char
void linphone_core_text_received(LinphoneCore *lc, const char *from, const char *msg);
void linphone_core_start_media_streams(LinphoneCore *lc, struct _LinphoneCall *call);
void linphone_core_stop_media_streams(LinphoneCore *lc, struct _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_stop_media_streams(LinphoneCall *call);
const char * linphone_core_get_identity(LinphoneCore *lc);
const char * linphone_core_get_route(LinphoneCore *lc);
bool_t linphone_core_is_in_communication_with(LinphoneCore *lc, const char *to);
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);
void linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *call);
extern SalCallbacks linphone_sal_callbacks;
void linphone_proxy_config_set_error(LinphoneProxyConfig *cfg, LinphoneReason error);
struct _LinphoneProxyConfig
{
@ -201,6 +220,8 @@ struct _LinphoneProxyConfig
struct _SipSetupContext *ssctx;
int auth_failures;
char *dial_prefix;
LinphoneRegistrationState state;
SalOp *publish_op;
bool_t commit;
bool_t reg_sendregister;
bool_t registered;
@ -208,6 +229,7 @@ struct _LinphoneProxyConfig
bool_t dial_escape_plus;
void* user_data;
time_t deletion_date;
LinphoneReason error;
};
struct _LinphoneAuthInfo
@ -224,8 +246,8 @@ struct _LinphoneAuthInfo
struct _LinphoneChatRoom{
struct _LinphoneCore *lc;
char *peer;
char *route;
LinphoneAddress *peer_url;
SalOp *op;
void * user_data;
};
@ -241,6 +263,7 @@ struct _LinphoneFriend{
bool_t subscribe;
bool_t subscribe_active;
bool_t inc_subscribe_pending;
bool_t commit;
};
@ -259,7 +282,6 @@ typedef struct sip_config
bool_t loopback_only;
bool_t ipv6_enabled;
bool_t sdp_200_ack;
bool_t only_one_codec; /*in SDP answers*/
bool_t register_only_when_network_is_up;
bool_t ping_with_options;
bool_t auto_net_state_mon;
@ -297,6 +319,7 @@ typedef struct sound_config
struct _MSSndCard * ring_sndcard; /* the playback sndcard currently used */
struct _MSSndCard * play_sndcard; /* the playback sndcard currently used */
struct _MSSndCard * capt_sndcard; /* the capture sndcard currently used */
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 */
char rec_lev;
@ -306,6 +329,7 @@ typedef struct sound_config
char source;
char *local_ring;
char *remote_ring;
char *ringback_tone;
bool_t ec;
bool_t ea;
bool_t agc;
@ -325,6 +349,7 @@ typedef struct video_config{
bool_t show_local;
bool_t display;
bool_t selfview; /*during calls*/
const char *displaytype;
}video_config_t;
typedef struct ui_config
@ -351,6 +376,7 @@ struct _LinphoneCore
{
LinphoneCoreVTable vtable;
Sal *sal;
LinphoneGlobalState state;
struct _LpConfig *config;
net_config_t net_conf;
sip_config_t sip_conf;
@ -364,22 +390,22 @@ struct _LinphoneCore
MSList *friends;
MSList *auth_info;
struct _RingStream *ringstream;
time_t dmfs_playing_start_time;
LCCallbackObj preview_finished_cb;
struct _LinphoneCall *call; /* the current call, in the future it will be a list of calls (conferencing)*/
LinphoneCall *current_call; /* the current call */
MSList *calls; /* all the processed calls */
MSList *queued_calls; /* used by the autoreplier */
MSList *call_logs;
MSList *chatrooms;
int max_call_logs;
int missed_calls;
struct _AudioStream *audiostream; /**/
struct _VideoStream *videostream;
struct _VideoStream *previewstream;
VideoPreview *previewstream;
struct _MSEventQueue *msevq;
RtpTransport *a_rtp,*a_rtcp;
MSList *bl_reqs;
MSList *subscribers; /* unknown subscribers */
int minutes_away;
LinphoneOnlineStatus presence_mode;
LinphoneOnlineStatus prev_mode;
char *alt_contact;
void *data;
char *play_file;
@ -390,19 +416,43 @@ struct _LinphoneCore
int dw_video_bw;
int up_video_bw;
int audio_bw;
gstate_t gstate_power;
gstate_t gstate_reg;
gstate_t gstate_call;
LinphoneWaitingCallback wait_cb;
void *wait_ctx;
unsigned long video_window_id;
unsigned long preview_window_id;
time_t netup_time; /*time when network went reachable */
bool_t use_files;
bool_t apply_nat_settings;
bool_t ready;
bool_t initial_subscribes_sent;
bool_t bl_refresh;
bool_t preview_finished;
bool_t auto_net_state_mon;
bool_t network_reachable;
bool_t audio_muted;
bool_t use_preview_window;
};
bool_t linphone_core_can_we_add_call(LinphoneCore *lc);
int linphone_core_add_call( LinphoneCore *lc, LinphoneCall *call);
int linphone_core_del_call( LinphoneCore *lc, LinphoneCall *call);
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 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);
#define linphone_core_ready(lc) ((lc)->state!=LinphoneGlobalStartup)
void _linphone_core_configure_resolver();
#define HOLD_OFF (0)
#define HOLD_ON (1)
#ifndef NB_MAX_CALLS
#define NB_MAX_CALLS (10)
#endif
#endif /* _PRIVATE_H */

View file

@ -72,6 +72,7 @@ void linphone_proxy_config_destroy(LinphoneProxyConfig *obj){
if (obj->type!=NULL) ms_free(obj->type);
if (obj->dial_prefix!=NULL) ms_free(obj->dial_prefix);
if (obj->op) sal_op_release(obj->op);
if (obj->publish_op) sal_op_release(obj->publish_op);
}
/**
@ -166,10 +167,16 @@ int linphone_proxy_config_set_route(LinphoneProxyConfig *obj, const char *route)
obj->reg_route=NULL;
}
if (route!=NULL){
LinphoneAddress *addr;
/*try to prepend 'sip:' */
if (strstr(route,"sip:")==NULL){
obj->reg_route=ms_strdup_printf("sip:%s",route);
}else obj->reg_route=ms_strdup(route);
addr=linphone_address_new(obj->reg_route);
if (addr==NULL){
ms_free(obj->reg_route);
obj->reg_route=NULL;
}else linphone_address_destroy(addr);
}
return 0;
}
@ -263,6 +270,7 @@ static char *guess_contact_for_register(LinphoneProxyConfig *obj){
static void linphone_proxy_config_register(LinphoneProxyConfig *obj){
const char *id_str;
if (obj->reg_identity!=NULL) id_str=obj->reg_identity;
else id_str=linphone_core_get_primary_contact(obj->lc);
if (obj->reg_sendregister){
@ -274,10 +282,10 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *obj){
sal_op_set_contact(obj->op,contact);
ms_free(contact);
sal_op_set_user_pointer(obj->op,obj);
if (!sal_register(obj->op,obj->reg_proxy,obj->reg_identity,obj->expires)) {
gstate_new_state(obj->lc,GSTATE_REG_PENDING,NULL);
if (sal_register(obj->op,obj->reg_proxy,obj->reg_identity,obj->expires)==0) {
linphone_proxy_config_set_state(obj,LinphoneRegistrationProgress,"Registration in progress");
} else {
gstate_new_state(obj->lc,GSTATE_REG_FAILED,NULL);
linphone_proxy_config_set_state(obj,LinphoneRegistrationFailed,"Registration failed");
}
}
}
@ -432,7 +440,9 @@ int linphone_proxy_config_send_publish(LinphoneProxyConfig *proxy,
SalOp *op=sal_op_new(proxy->lc->sal);
err=sal_publish(op,linphone_proxy_config_get_identity(proxy),
linphone_proxy_config_get_identity(proxy),linphone_online_status_to_sal(presence_mode));
sal_op_release(op);
if (proxy->publish_op!=NULL)
sal_op_release(proxy->publish_op);
proxy->publish_op=op;
return err;
}
@ -690,8 +700,11 @@ void linphone_proxy_config_update(LinphoneProxyConfig *cfg){
if (cfg->type && cfg->ssctx==NULL){
linphone_proxy_config_activate_sip_setup(cfg);
}
if (lc->sip_conf.register_only_when_network_is_up || lc->network_reachable)
if (!lc->sip_conf.register_only_when_network_is_up || lc->network_reachable)
linphone_proxy_config_register(cfg);
if (cfg->publish && cfg->publish_op==NULL){
linphone_proxy_config_send_publish(cfg,lc->presence_mode);
}
cfg->commit=FALSE;
}
}
@ -796,6 +809,45 @@ void * linphone_proxy_config_get_user_data(LinphoneProxyConfig *cr) {
return cr->user_data;
}
void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrationState state, const char *message){
LinphoneCore *lc=cfg->lc;
cfg->state=state;
if (lc && lc->vtable.registration_state_changed){
lc->vtable.registration_state_changed(lc,cfg,state,message);
}
}
LinphoneRegistrationState linphone_proxy_config_get_state(const LinphoneProxyConfig *cfg){
return cfg->state;
}
const char *linphone_registration_state_to_string(LinphoneRegistrationState cs){
switch(cs){
case LinphoneRegistrationCleared:
return "LinphoneRegistrationCleared";
break;
case LinphoneRegistrationNone:
return "LinphoneRegistrationNone";
break;
case LinphoneRegistrationProgress:
return "LinphoneRegistrationProgress";
break;
case LinphoneRegistrationOk:
return "LinphoneRegistrationOk";
break;
case LinphoneRegistrationFailed:
return "LinphoneRegistrationFailed";
break;
}
return NULL;
}
LinphoneReason linphone_proxy_config_get_error(const LinphoneProxyConfig *cfg) {
return cfg->error;
}
void linphone_proxy_config_set_error(LinphoneProxyConfig *cfg,LinphoneReason error) {
cfg->error = error;
}

View file

@ -52,21 +52,110 @@ void sal_media_description_unref(SalMediaDescription *md){
}
}
const SalStreamDescription *sal_media_description_find_stream(const SalMediaDescription *md,
SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md,
SalMediaProto proto, SalStreamType type){
int i;
for(i=0;i<md->nstreams;++i){
const SalStreamDescription *ss=&md->streams[i];
SalStreamDescription *ss=&md->streams[i];
if (ss->proto==proto && ss->type==type) return ss;
}
return NULL;
}
bool_t sal_media_description_empty(SalMediaDescription *md){
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;
}
return TRUE;
}
void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_dir){
int i;
for(i=0;i<md->nstreams;++i){
SalStreamDescription *ss=&md->streams[i];
if (ss->port!=0) return FALSE;
ss->dir=stream_dir;
}
}
bool_t sal_media_description_has_dir(const SalMediaDescription *md, SalStreamDir stream_dir){
int i;
bool_t found=FALSE;
/* we are looking for at least one stream with requested direction, inactive streams are ignored*/
for(i=0;i<md->nstreams;++i){
const SalStreamDescription *ss=&md->streams[i];
if (ss->dir==stream_dir) found=TRUE;
else{
if (ss->dir!=SalStreamInactive) return FALSE;
}
}
return found;
}
/*
static bool_t fmtp_equals(const char *p1, const char *p2){
if (p1 && p2 && strcmp(p1,p2)==0) return TRUE;
if (p1==NULL && p2==NULL) return TRUE;
return FALSE;
}
*/
static bool_t payload_type_equals(const PayloadType *p1, const PayloadType *p2){
if (p1->type!=p2->type) return FALSE;
if (strcmp(p1->mime_type,p2->mime_type)!=0) return FALSE;
if (p1->clock_rate!=p2->clock_rate) return FALSE;
if (p1->channels!=p2->channels) return FALSE;
/*
Do not compare fmtp right now: they are modified internally when the call is started
*/
/*
if (!fmtp_equals(p1->recv_fmtp,p2->recv_fmtp) ||
!fmtp_equals(p1->send_fmtp,p2->send_fmtp))
return FALSE;
*/
return TRUE;
}
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){
PayloadType *p1=(PayloadType*)e1->data;
PayloadType *p2=(PayloadType*)e2->data;
if (!payload_type_equals(p1,p2))
return FALSE;
}
if (e1!=NULL || e2!=NULL){
/*means one list is longer than the other*/
abort();
return FALSE;
}
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;
}
bool_t sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2){
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;
}
return TRUE;
}
@ -120,6 +209,10 @@ const char *sal_op_get_route(const SalOp *op){
return ((SalOpBase*)op)->route;
}
const char *sal_op_get_remote_ua(const SalOp *op){
return ((SalOpBase*)op)->remote_ua;
}
void *sal_op_get_user_pointer(const SalOp *op){
return ((SalOpBase*)op)->user_pointer;
}
@ -164,6 +257,10 @@ void __sal_op_free(SalOp *op){
ms_free(b->origin);
b->origin=NULL;
}
if (b->remote_ua){
ms_free(b->remote_ua);
b->remote_ua=NULL;
}
if (b->local_media)
sal_media_description_unref(b->local_media);
if (b->remote_media)

View file

@ -86,6 +86,13 @@ typedef enum{
SalProtoRtpSavp
}SalMediaProto;
typedef enum{
SalStreamSendRecv,
SalStreamSendOnly,
SalStreamRecvOnly,
SalStreamInactive
}SalStreamDir;
typedef struct SalEndpointCandidate{
char addr[64];
int port;
@ -102,6 +109,7 @@ typedef struct SalStreamDescription{
int bandwidth;
int ptime;
SalEndpointCandidate candidates[SAL_ENDPOINT_CANDIDATE_MAX];
SalStreamDir dir;
} SalStreamDescription;
#define SAL_MEDIA_DESCRIPTION_MAX_STREAMS 4
@ -118,9 +126,12 @@ typedef struct SalMediaDescription{
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(SalMediaDescription *md);
const SalStreamDescription *sal_media_description_find_stream(const SalMediaDescription *md,
bool_t sal_media_description_empty(const SalMediaDescription *md);
bool_t 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);
void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_dir);
/*this structure must be at the first byte of the SalOp structure defined by implementors*/
typedef struct SalOpBase{
@ -130,6 +141,7 @@ typedef struct SalOpBase{
char *from;
char *to;
char *origin;
char *remote_ua;
SalMediaDescription *local_media;
SalMediaDescription *remote_media;
void *user_pointer;
@ -177,9 +189,9 @@ typedef void (*SalOnCallReceived)(SalOp *op);
typedef void (*SalOnCallRinging)(SalOp *op);
typedef void (*SalOnCallAccepted)(SalOp *op);
typedef void (*SalOnCallAck)(SalOp *op);
typedef void (*SalOnCallUpdated)(SalOp *op);
typedef void (*SalOnCallUpdating)(SalOp *op);/*< Called when a reINVITE is received*/
typedef void (*SalOnCallTerminated)(SalOp *op, const char *from);
typedef void (*SalOnCallFailure)(SalOp *op, SalError error, SalReason reason, const char *details);
typedef void (*SalOnCallFailure)(SalOp *op, SalError error, SalReason reason, const char *details, int code);
typedef void (*SalOnAuthRequested)(SalOp *op, const char *realm, const char *username);
typedef void (*SalOnAuthSuccess)(SalOp *op, const char *realm, const char *username);
typedef void (*SalOnRegisterSuccess)(SalOp *op, bool_t registered);
@ -200,7 +212,7 @@ typedef struct SalCallbacks{
SalOnCallRinging call_ringing;
SalOnCallAccepted call_accepted;
SalOnCallAck call_ack;
SalOnCallUpdated call_updated;
SalOnCallUpdating call_updating;
SalOnCallTerminated call_terminated;
SalOnCallFailure call_failure;
SalOnAuthRequested auth_requested;
@ -234,6 +246,7 @@ void sal_set_user_agent(Sal *ctx, const char *user_agent);
/*keepalive period in ms*/
void sal_set_keepalive_period(Sal *ctx,unsigned int value);
void sal_use_session_timers(Sal *ctx, int expires);
void sal_use_one_matching_codec_policy(Sal *ctx, bool_t one_matching_codec);
int sal_iterate(Sal *sal);
MSList * sal_get_pending_auths(Sal *sal);
@ -257,17 +270,27 @@ const char *sal_op_get_route(const SalOp *op);
const char *sal_op_get_proxy(const SalOp *op);
/*for incoming requests, returns the origin of the packet as a sip uri*/
const char *sal_op_get_network_origin(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);
/*Call API*/
int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc);
int sal_call(SalOp *h, const char *from, const char *to);
int sal_call_notify_ringing(SalOp *h);
int sal_call_notify_ringing(SalOp *h, bool_t early_media);
/*accept an incoming call or, during a call accept a reINVITE*/
int sal_call_accept(SalOp*h);
int sal_call_decline(SalOp *h, SalReason reason, const char *redirection /*optional*/);
int sal_call_hold(SalOp *h, bool_t holdon);
int sal_call_update(SalOp *h);
SalMediaDescription * sal_call_get_final_media_description(SalOp *h);
int sal_refer(SalOp *h, const char *refer_to);
int sal_refer_accept(SalOp *h);
int sal_call_refer(SalOp *h, const char *refer_to);
int sal_call_refer_with_replaces(SalOp *h, SalOp *other_call_h);
int sal_call_accept_refer(SalOp *h);
/*informs this call is consecutive to an incoming refer */
int sal_call_set_referer(SalOp *h, SalOp *refered_call);
/* returns the SalOp of a call that should be replaced by h, if any */
SalOp *sal_call_get_replaces(SalOp *h);
int sal_call_send_dtmf(SalOp *h, char dtmf);
int sal_call_terminate(SalOp *h);
bool_t sal_call_autoanswer_asked(SalOp *op);
@ -306,5 +329,4 @@ void __sal_op_init(SalOp *b, Sal *sal);
void __sal_op_set_network_origin(SalOp *op, const char *origin /*a sip uri*/);
void __sal_op_free(SalOp *b);
#endif

View file

@ -26,7 +26,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
static void text_received(Sal *sal, eXosip_event_t *ev);
static void _osip_list_set_empty(osip_list_t *l, void (*freefunc)(void*)){
void _osip_list_set_empty(osip_list_t *l, void (*freefunc)(void*)){
void *data;
while((data=osip_list_get(l,0))!=NULL){
osip_list_remove(l,0);
@ -102,7 +102,7 @@ static SalOp * sal_find_other(Sal *sal, osip_message_t *response){
return NULL;
}
static void sal_add_other(Sal *sal, SalOp *op, osip_message_t *request){
void sal_add_other(Sal *sal, SalOp *op, osip_message_t *request){
osip_call_id_t *callid=osip_message_get_call_id(request);
if (callid==NULL) {
ms_error("There is no call id in the request !");
@ -161,6 +161,8 @@ SalOp * sal_op_new(Sal *sal){
op->sdp_answer=NULL;
op->reinvite=FALSE;
op->call_id=NULL;
op->replaces=NULL;
op->referred_by=NULL;
op->masquerade_via=FALSE;
op->auto_answer_asked=FALSE;
return op;
@ -201,6 +203,12 @@ void sal_op_release(SalOp *op){
sal_remove_other(op->base.root,op);
osip_call_id_free(op->call_id);
}
if (op->replaces){
ms_free(op->replaces);
}
if (op->referred_by){
ms_free(op->referred_by);
}
__sal_op_free(op);
}
@ -284,8 +292,8 @@ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){
ctx->callbacks.call_failure=(SalOnCallFailure)unimplemented_stub;
if (ctx->callbacks.call_terminated==NULL)
ctx->callbacks.call_terminated=(SalOnCallTerminated)unimplemented_stub;
if (ctx->callbacks.call_updated==NULL)
ctx->callbacks.call_updated=(SalOnCallUpdated)unimplemented_stub;
if (ctx->callbacks.call_updating==NULL)
ctx->callbacks.call_updating=(SalOnCallUpdating)unimplemented_stub;
if (ctx->callbacks.auth_requested==NULL)
ctx->callbacks.auth_requested=(SalOnAuthRequested)unimplemented_stub;
if (ctx->callbacks.auth_success==NULL)
@ -371,6 +379,10 @@ void sal_use_session_timers(Sal *ctx, int expires){
ctx->session_expires=expires;
}
void sal_use_one_matching_codec_policy(Sal *ctx, bool_t one_matching_codec){
ctx->one_matching_codec=one_matching_codec;
}
MSList *sal_get_pending_auths(Sal *sal){
return ms_list_copy(sal->pending_auths);
}
@ -441,7 +453,7 @@ static void sdp_process(SalOp *h){
offer_answer_initiate_outgoing(h->base.local_media,h->base.remote_media,h->result);
}else{
int i;
offer_answer_initiate_incoming(h->base.local_media,h->base.remote_media,h->result);
offer_answer_initiate_incoming(h->base.local_media,h->base.remote_media,h->result,h->base.root->one_matching_codec);
h->sdp_answer=media_description_to_sdp(h->result);
strcpy(h->result->addr,h->base.remote_media->addr);
h->result->bandwidth=h->base.remote_media->bandwidth;
@ -490,6 +502,12 @@ int sal_call(SalOp *h, const char *from, const char *to){
h->sdp_offering=TRUE;
set_sdp_from_desc(invite,h->base.local_media);
}else h->sdp_offering=FALSE;
if (h->replaces){
osip_message_set_header(invite,"Replaces",h->replaces);
if (h->referred_by)
osip_message_set_header(invite,"Referred-By",h->referred_by);
}
eXosip_lock();
err=eXosip_call_send_initial_invite(invite);
eXosip_unlock();
@ -503,10 +521,31 @@ int sal_call(SalOp *h, const char *from, const char *to){
return 0;
}
int sal_call_notify_ringing(SalOp *h){
eXosip_lock();
eXosip_call_send_answer(h->tid,180,NULL);
eXosip_unlock();
int sal_call_notify_ringing(SalOp *h, bool_t early_media){
osip_message_t *msg;
int err;
/*if early media send also 180 and 183 */
if (early_media && h->sdp_answer){
msg=NULL;
eXosip_lock();
err=eXosip_call_build_answer(h->tid,180,&msg);
if (msg){
set_sdp(msg,h->sdp_answer);
eXosip_call_send_answer(h->tid,180,msg);
}
msg=NULL;
err=eXosip_call_build_answer(h->tid,183,&msg);
if (msg){
set_sdp(msg,h->sdp_answer);
eXosip_call_send_answer(h->tid,183,msg);
}
eXosip_unlock();
}else{
eXosip_lock();
eXosip_call_send_answer(h->tid,180,NULL);
eXosip_unlock();
}
return 0;
}
@ -585,6 +624,14 @@ SalMediaDescription * sal_call_get_final_media_description(SalOp *h){
return h->result;
}
int sal_call_set_referer(SalOp *h, SalOp *refered_call){
if (refered_call->replaces)
h->replaces=ms_strdup(refered_call->replaces);
if (refered_call->referred_by)
h->referred_by=ms_strdup(refered_call->referred_by);
return 0;
}
int sal_ping(SalOp *op, const char *from, const char *to){
osip_message_t *options=NULL;
@ -603,7 +650,7 @@ int sal_ping(SalOp *op, const char *from, const char *to){
return -1;
}
int sal_refer_accept(SalOp *op){
int sal_call_accept_refer(SalOp *op){
osip_message_t *msg=NULL;
int err=0;
eXosip_lock();
@ -623,7 +670,7 @@ int sal_refer_accept(SalOp *op){
return err;
}
int sal_refer(SalOp *h, const char *refer_to){
int sal_call_refer(SalOp *h, const char *refer_to){
osip_message_t *msg=NULL;
int err=0;
eXosip_lock();
@ -634,6 +681,38 @@ int sal_refer(SalOp *h, const char *refer_to){
return err;
}
int sal_call_refer_with_replaces(SalOp *h, SalOp *other_call_h){
osip_message_t *msg=NULL;
char referto[256]={0};
int err=0;
eXosip_lock();
if (eXosip_call_get_referto(other_call_h->did,referto,sizeof(referto)-1)!=0){
ms_error("eXosip_call_get_referto() failed for did=%i",other_call_h->did);
eXosip_unlock();
return -1;
}
eXosip_call_build_refer(h->did,referto, &msg);
osip_message_set_header(msg,"Referred-By",h->base.from);
if (msg) err=eXosip_call_send_request(h->did, msg);
else err=-1;
eXosip_unlock();
return err;
}
SalOp *sal_call_get_replaces(SalOp *h){
if (h->replaces!=NULL){
int cid;
eXosip_lock();
cid=eXosip_call_find_by_replaces(h->replaces);
eXosip_unlock();
if (cid>0){
SalOp *ret=sal_find_call(h->base.root,cid);
return ret;
}
}
return NULL;
}
int sal_call_send_dtmf(SalOp *h, char dtmf){
osip_message_t *msg=NULL;
char dtmf_body[128];
@ -654,9 +733,13 @@ int sal_call_send_dtmf(SalOp *h, char dtmf){
}
int sal_call_terminate(SalOp *h){
int err;
eXosip_lock();
eXosip_call_terminate(h->cid,h->did);
err=eXosip_call_terminate(h->cid,h->did);
eXosip_unlock();
if (err!=0){
ms_warning("Exosip could not terminate the call: cid=%i did=%i", h->cid,h->did);
}
sal_remove_call(h->base.root,h);
h->cid=-1;
return 0;
@ -697,6 +780,31 @@ static void set_network_origin(SalOp *op, osip_message_t *req){
__sal_op_set_network_origin(op,origin);
}
static void set_remote_ua(SalOp* op, osip_message_t *req){
if (op->base.remote_ua==NULL){
osip_header_t *h=NULL;
osip_message_get_user_agent(req,0,&h);
if (h){
op->base.remote_ua=ms_strdup(h->hvalue);
}
}
}
static void set_replaces(SalOp *op, osip_message_t *req){
osip_header_t *h=NULL;
if (op->replaces){
ms_free(op->replaces);
op->replaces=NULL;
}
osip_message_header_get_byname(req,"replaces",0,&h);
if (h){
if (h->hvalue && h->hvalue[0]!='\0'){
op->replaces=ms_strdup(h->hvalue);
}
}
}
static SalOp *find_op(Sal *sal, eXosip_event_t *ev){
if (ev->cid>0){
return sal_find_call(sal,ev->cid);
@ -704,6 +812,9 @@ static SalOp *find_op(Sal *sal, eXosip_event_t *ev){
if (ev->rid>0){
return sal_find_register(sal,ev->rid);
}
if (ev->sid>0){
return sal_find_out_subscribe(sal,ev->sid);
}
if (ev->response) return sal_find_other(sal,ev->response);
return NULL;
}
@ -716,6 +827,8 @@ static void inc_new_call(Sal *sal, eXosip_event_t *ev){
sdp_message_t *sdp=eXosip_get_sdp_info(ev->request);
set_network_origin(op,ev->request);
set_remote_ua(op,ev->request);
set_replaces(op,ev->request);
if (sdp){
op->sdp_offering=FALSE;
@ -769,35 +882,27 @@ static void handle_reinvite(Sal *sal, eXosip_event_t *ev){
sal_media_description_unref(op->base.remote_media);
op->base.remote_media=NULL;
}
eXosip_lock();
eXosip_call_build_answer(ev->tid,200,&msg);
eXosip_unlock();
if (msg==NULL) return;
if (op->base.root->session_expires!=0){
if (op->supports_session_timers) osip_message_set_supported(msg, "timer");
}
if (op->base.contact){
_osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free);
osip_message_set_contact(msg,op->base.contact);
if (op->result){
sal_media_description_unref(op->result);
op->result=NULL;
}
if (sdp){
op->sdp_offering=FALSE;
op->base.remote_media=sal_media_description_new();
sdp_to_media_description(sdp,op->base.remote_media);
sdp_message_free(sdp);
sdp_process(op);
if (op->sdp_answer!=NULL){
set_sdp(msg,op->sdp_answer);
sdp_message_free(op->sdp_answer);
op->sdp_answer=NULL;
}
sal->callbacks.call_updating(op);
}else {
op->sdp_offering=TRUE;
set_sdp_from_desc(msg,op->base.local_media);
eXosip_lock();
eXosip_call_build_answer(ev->tid,200,&msg);
if (msg!=NULL){
set_sdp_from_desc(msg,op->base.local_media);
eXosip_call_send_answer(ev->tid,200,msg);
}
eXosip_unlock();
}
eXosip_lock();
eXosip_call_send_answer(ev->tid,200,msg);
eXosip_unlock();
}
static void handle_ack(Sal *sal, eXosip_event_t *ev){
@ -816,7 +921,7 @@ static void handle_ack(Sal *sal, eXosip_event_t *ev){
sdp_message_free(sdp);
}
if (op->reinvite){
sal->callbacks.call_updated(op);
if (sdp) sal->callbacks.call_updating(op);
op->reinvite=FALSE;
}else{
sal->callbacks.call_ack(op);
@ -840,6 +945,7 @@ static void update_contact_from_response(SalOp *op, osip_message_t *response){
tmp=sal_address_as_string(addr);
ms_message("Contact address updated to %s for this dialog",tmp);
sal_op_set_contact(op,tmp);
sal_address_destroy(addr);
ms_free(tmp);
}
}
@ -855,7 +961,8 @@ static int call_proceeding(Sal *sal, eXosip_event_t *ev){
eXosip_unlock();
return -1;
}
op->did=ev->did;
if (ev->did>0)
op->did=ev->did;
op->tid=ev->tid;
/* update contact if received and rport are set by the server
@ -868,7 +975,8 @@ static void call_ringing(Sal *sal, eXosip_event_t *ev){
sdp_message_t *sdp;
SalOp *op=find_op(sal,ev);
if (call_proceeding(sal, ev)==-1) return;
set_remote_ua(op,ev->response);
sdp=eXosip_get_sdp_info(ev->response);
if (sdp){
op->base.remote_media=sal_media_description_new();
@ -891,7 +999,8 @@ static void call_accepted(Sal *sal, eXosip_event_t *ev){
}
op->did=ev->did;
set_remote_ua(op,ev->response);
sdp=eXosip_get_sdp_info(ev->response);
if (sdp){
op->base.remote_media=sal_media_description_new();
@ -938,7 +1047,7 @@ static void call_released(Sal *sal, eXosip_event_t *ev){
}
op->cid=-1;
if (op->did==-1)
sal->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,NULL);
sal->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,NULL, 487);
}
static int get_auth_data_from_response(osip_message_t *resp, const char **realm, const char **username){
@ -1100,7 +1209,7 @@ static bool_t call_failure(Sal *sal, eXosip_event_t *ev){
sr=SalReasonUnknown;
}else error=SalErrorNoResponse;
}
sal->callbacks.call_failure(op,error,sr,reason);
sal->callbacks.call_failure(op,error,sr,reason,code);
if (computedReason != NULL){
ms_free(computedReason);
}
@ -1127,8 +1236,18 @@ static void process_media_control_xml(Sal *sal, eXosip_event_t *ev){
eXosip_call_build_answer(ev->tid,200,&ans);
if (ans)
eXosip_call_send_answer(ev->tid,200,ans);
return;
}
}
/*in all other cases we must say it is not implemented.*/
{
osip_message_t *ans=NULL;
eXosip_lock();
eXosip_call_build_answer(ev->tid,501,&ans);
if (ans)
eXosip_call_send_answer(ev->tid,501,ans);
eXosip_unlock();
}
}
static void process_dtmf_relay(Sal *sal, eXosip_event_t *ev){
@ -1162,6 +1281,59 @@ static void process_dtmf_relay(Sal *sal, eXosip_event_t *ev){
}
}
static void fill_options_answer(osip_message_t *options){
osip_message_set_allow(options,"INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, SUBSCRIBE, NOTIFY, INFO");
osip_message_set_accept(options,"application/sdp");
}
static void process_refer(Sal *sal, SalOp *op, eXosip_event_t *ev){
osip_header_t *h=NULL;
osip_message_t *ans=NULL;
ms_message("Receiving REFER request !");
osip_message_header_get_byname(ev->request,"Refer-To",0,&h);
if (h){
osip_from_t *from=NULL;
char *tmp;
osip_from_init(&from);
if (osip_from_parse(from,h->hvalue)==0){
if (op ){
osip_uri_header_t *uh=NULL;
osip_header_t *referred_by=NULL;
osip_uri_header_get_byname(&from->url->url_headers,(char*)"Replaces",&uh);
if (uh!=NULL && uh->gvalue && uh->gvalue[0]!='\0'){
ms_message("Found replaces in Refer-To");
if (op->replaces){
ms_free(op->replaces);
}
op->replaces=ms_strdup(uh->gvalue);
}
osip_message_header_get_byname(ev->request,"Referred-By",0,&referred_by);
if (referred_by && referred_by->hvalue && referred_by->hvalue[0]!='\0'){
if (op->referred_by)
ms_free(op->referred_by);
op->referred_by=ms_strdup(referred_by->hvalue);
}
}
osip_uri_header_freelist(&from->url->url_headers);
osip_from_to_str(from,&tmp);
sal->callbacks.refer_received(sal,op,tmp);
osip_free(tmp);
osip_from_free(from);
}
eXosip_lock();
eXosip_call_build_answer(ev->tid,202,&ans);
if (ans)
eXosip_call_send_answer(ev->tid,202,ans);
eXosip_unlock();
}
else
{
ms_warning("cannot do anything with the refer without destination\n");
}
}
static void call_message_new(Sal *sal, eXosip_event_t *ev){
osip_message_t *ans=NULL;
if (ev->request){
@ -1190,8 +1362,7 @@ static void call_message_new(Sal *sal, eXosip_event_t *ev){
eXosip_call_send_answer(ev->tid,200,ans);
eXosip_unlock();
}
}
if(MSG_IS_MESSAGE(ev->request)){
}else if(MSG_IS_MESSAGE(ev->request)){
/* SIP messages could be received into call */
text_received(sal, ev);
eXosip_lock();
@ -1199,27 +1370,12 @@ static void call_message_new(Sal *sal, eXosip_event_t *ev){
if (ans)
eXosip_call_send_answer(ev->tid,200,ans);
eXosip_unlock();
}
if(MSG_IS_REFER(ev->request)){
osip_header_t *h=NULL;
}else if(MSG_IS_REFER(ev->request)){
SalOp *op=find_op(sal,ev);
ms_message("Receiving REFER request !");
osip_message_header_get_byname(ev->request,"Refer-To",0,&h);
eXosip_lock();
eXosip_call_build_answer(ev->tid,202,&ans);
if (ans)
eXosip_call_send_answer(ev->tid,202,ans);
eXosip_unlock();
if (h){
sal->callbacks.refer_received(sal,op,h->hvalue);
}
else
{
ms_warning("cannot do anything with the refer without destination\n");
}
}
if(MSG_IS_NOTIFY(ev->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);
@ -1236,6 +1392,14 @@ static void call_message_new(Sal *sal, eXosip_event_t *ev){
eXosip_call_send_answer(ev->tid,200,ans);
eXosip_unlock();
osip_free(from);
}else if (MSG_IS_OPTIONS(ev->request)){
eXosip_lock();
eXosip_call_build_answer(ev->tid,200,&ans);
if (ans){
fill_options_answer(ans);
eXosip_call_send_answer(ev->tid,200,ans);
}
eXosip_unlock();
}
}else ms_warning("call_message_new: No request ?");
}
@ -1284,6 +1448,8 @@ static void text_received(Sal *sal, eXosip_event_t *ev){
osip_free(from);
}
static void other_request(Sal *sal, eXosip_event_t *ev){
ms_message("in other_request");
if (ev->request==NULL) return;
@ -1293,8 +1459,7 @@ static void other_request(Sal *sal, eXosip_event_t *ev){
}else if (strcmp(ev->request->sip_method,"OPTIONS")==0){
osip_message_t *options=NULL;
eXosip_options_build_answer(ev->tid,200,&options);
osip_message_set_allow(options,"INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, SUBSCRIBE, NOTIFY, INFO");
osip_message_set_accept(options,"application/sdp");
fill_options_answer(options);
eXosip_options_send_answer(ev->tid,200,options);
}else if (strcmp(ev->request->sip_method,"WAKEUP")==0
&& comes_from_local_if(ev->request)) {
@ -1304,12 +1469,7 @@ static void other_request(Sal *sal, eXosip_event_t *ev){
}else if (strncmp(ev->request->sip_method, "REFER", 5) == 0){
ms_message("Receiving REFER request !");
if (comes_from_local_if(ev->request)) {
osip_header_t *h=NULL;
osip_message_header_get_byname(ev->request,"Refer-To",0,&h);
eXosip_message_send_answer(ev->tid,200,NULL);
if (h){
sal->callbacks.refer_received(sal,NULL,h->hvalue);
}
process_refer(sal,NULL,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);
@ -1405,7 +1565,9 @@ static void registration_success(Sal *sal, eXosip_event_t *ev){
if (!register_again_with_updated_contact(op,ev->request,ev->response)){
sal->callbacks.register_success(op,registered);
}
}else registered=FALSE;
}else {
sal->callbacks.register_success(op,FALSE);
}
}
static bool_t registration_failure(Sal *sal, eXosip_event_t *ev){
@ -1574,8 +1736,16 @@ static bool_t process_event(Sal *sal, eXosip_event_t *ev){
other_request_reply(sal,ev);
break;
case EXOSIP_MESSAGE_REQUESTFAILURE:
if (ev->response && (ev->response->status_code == 407 || ev->response->status_code == 401)){
return process_authentication(sal,ev);
if (ev->response) {
switch (ev->response->status_code) {
case 407:
case 401:
return process_authentication(sal,ev);
case 412: {
eXosip_automatic_action ();
return 1;
}
}
}
other_request_reply(sal,ev);
break;
@ -1764,10 +1934,12 @@ void sal_set_keepalive_period(Sal *ctx,unsigned int value) {
ctx->keepalive_period=value;
eXosip_set_option (EXOSIP_OPT_UDP_KEEP_ALIVE, &value);
}
const char * sal_address_get_port(const SalAddress *addr) {
const osip_from_t *u=(const osip_from_t*)addr;
return null_if_empty(u->url->port);
}
int sal_address_get_port_int(const SalAddress *uri) {
const char* port = sal_address_get_port(uri);
if (port != NULL) {
@ -1777,3 +1949,58 @@ int sal_address_get_port_int(const SalAddress *uri) {
}
}
/*
* Send a re-Invite used to hold the current call
*/
int sal_call_hold(SalOp *h, bool_t holdon)
{
int err=0;
osip_message_t *reinvite=NULL;
if(eXosip_call_build_request(h->did,"INVITE",&reinvite) != OSIP_SUCCESS || reinvite==NULL)
return -1;
osip_message_set_subject(reinvite,holdon ? "Phone call hold" : "Phone call resume" );
osip_message_set_allow(reinvite, "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO");
if (h->base.root->session_expires!=0){
osip_message_set_header(reinvite, "Session-expires", "200");
osip_message_set_supported(reinvite, "timer");
}
//add something to say that the distant sip phone will be in sendonly/sendrecv mode
if (h->base.local_media){
h->sdp_offering=TRUE;
sal_media_description_set_dir(h->base.local_media, holdon ? SalStreamSendOnly : SalStreamSendRecv);
set_sdp_from_desc(reinvite,h->base.local_media);
}else h->sdp_offering=FALSE;
eXosip_lock();
err = eXosip_call_send_request(h->did, reinvite);
eXosip_unlock();
return err;
}
/* sends a reinvite. Local media description may have changed by application since call establishment*/
int sal_call_update(SalOp *h){
int err=0;
osip_message_t *reinvite=NULL;
eXosip_lock();
if(eXosip_call_build_request(h->did,"INVITE",&reinvite) != OSIP_SUCCESS || reinvite==NULL){
eXosip_unlock();
return -1;
}
eXosip_unlock();
osip_message_set_subject(reinvite,osip_strdup("Phone call parameters updated"));
osip_message_set_allow(reinvite, "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO");
if (h->base.root->session_expires!=0){
osip_message_set_header(reinvite, "Session-expires", "200");
osip_message_set_supported(reinvite, "timer");
}
if (h->base.local_media){
h->sdp_offering=TRUE;
set_sdp_from_desc(reinvite,h->base.local_media);
}else h->sdp_offering=FALSE;
eXosip_lock();
err = eXosip_call_send_request(h->did, reinvite);
eXosip_unlock();
return err;
}

View file

@ -40,6 +40,7 @@ struct Sal{
int session_expires;
int keepalive_period;
void *up;
bool_t one_matching_codec;
};
struct SalOp{
@ -56,6 +57,8 @@ struct SalOp{
eXosip_event_t *pending_auth;
osip_call_id_t *call_id; /*used for out of calls transaction in order
to retrieve the operation when receiving a response*/
char *replaces;
char *referred_by;
bool_t supports_session_timers;
bool_t sdp_offering;
bool_t reinvite;
@ -65,6 +68,7 @@ struct SalOp{
void sal_remove_out_subscribe(Sal *sal, SalOp *op);
void sal_remove_in_subscribe(Sal *sal, SalOp *op);
void sal_add_other(Sal *sal, SalOp *op, osip_message_t *request);
void sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev);
void sal_exosip_subscription_answered(Sal *sal,eXosip_event_t *ev);
@ -72,8 +76,9 @@ void sal_exosip_notify_recv(Sal *sal,eXosip_event_t *ev);
void sal_exosip_subscription_closed(Sal *sal,eXosip_event_t *ev);
void sal_exosip_in_subscription_closed(Sal *sal, eXosip_event_t *ev);
SalOp * sal_find_out_subscribe(Sal *sal, int sid);
void sal_exosip_fix_route(SalOp *op);
void _osip_list_set_empty(osip_list_t *l, void (*freefunc)(void*));
#endif

View file

@ -20,8 +20,19 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "sal_eXosip2.h"
typedef enum {
PIDF = 0,
RFCxxxx = 1,
MSOLDPRES = 2
} presence_type_t;
static SalOp * sal_find_out_subscribe(Sal *sal, int sid){
/*
* REVISIT: this static variable forces every dialog to use the same presence description type depending
* on what is received on a single dialog...
*/
static presence_type_t presence_style = PIDF;
SalOp * sal_find_out_subscribe(Sal *sal, int sid){
const MSList *elem;
SalOp *op;
for(elem=sal->out_subscribes;elem!=NULL;elem=elem->next){
@ -83,9 +94,14 @@ int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg){
eXosip_lock();
eXosip_message_build_request(&sip,"MESSAGE",sal_op_get_to(op),
sal_op_get_from(op),sal_op_get_route(op));
osip_message_set_content_type(sip,"text/plain");
osip_message_set_body(sip,msg,strlen(msg));
eXosip_message_send_request(sip);
if (sip!=NULL){
osip_message_set_content_type(sip,"text/plain");
osip_message_set_body(sip,msg,strlen(msg));
sal_add_other(op->base.root,op,sip);
eXosip_message_send_request(sip);
}else{
ms_error("Could not build MESSAGE request !");
}
eXosip_unlock();
}
else
@ -93,22 +109,16 @@ int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg){
/* we are currently in communication with the destination */
eXosip_lock();
//First we generate an INFO message to get the current call_id and a good cseq
eXosip_call_build_info(op->did,&sip);
eXosip_call_build_request(op->did,"MESSAGE",&sip);
if(sip == NULL)
{
ms_warning("could not get a build info to send MESSAGE, maybe no previous call established ?");
osip_message_free(sip);
eXosip_unlock();
return -1;
}
//change the sip_message to be a MESSAGE ...
osip_free(osip_message_get_method(sip));
osip_message_set_method(sip,osip_strdup("MESSAGE"));
osip_free(osip_cseq_get_method(osip_message_get_cseq(sip)));
osip_cseq_set_method(osip_message_get_cseq(sip),osip_strdup("MESSAGE"));
osip_message_set_content_type(sip,"text/plain");
osip_message_set_body(sip,msg,strlen(msg));
eXosip_message_send_request(sip);
eXosip_call_send_request(op->did,sip);
eXosip_unlock();
}
return 0;
@ -125,6 +135,10 @@ int sal_subscribe_presence(SalOp *op, const char *from, const char *to){
eXosip_lock();
eXosip_subscribe_build_initial_request(&msg,sal_op_get_to(op),sal_op_get_from(op),
sal_op_get_route(op),"presence",600);
if (op->base.contact){
_osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free);
osip_message_set_contact(msg,op->base.contact);
}
op->sid=eXosip_subscribe_send_initial_request(msg);
eXosip_unlock();
if (op->sid==-1){
@ -156,6 +170,10 @@ int sal_subscribe_accept(SalOp *op){
osip_message_t *msg;
eXosip_lock();
eXosip_insubscription_build_answer(op->tid,202,&msg);
if (op->base.contact){
_osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free);
osip_message_set_contact(msg,op->base.contact);
}
eXosip_insubscription_send_answer(op->tid,202,msg);
eXosip_unlock();
return 0;
@ -168,268 +186,372 @@ int sal_subscribe_decline(SalOp *op){
return 0;
}
static void add_presence_body(osip_message_t *notify, SalPresenceStatus online_status)
{
char buf[1000];
#ifdef SUPPORT_MSN
int atom_id = 1000;
#endif
char *contact_info;
static void mk_presence_body (const SalPresenceStatus online_status, const char *contact_info,
char *buf, size_t buflen, presence_type_t ptype) {
switch (ptype) {
case RFCxxxx: {
/* definition from http://msdn.microsoft.com/en-us/library/cc246202%28PROT.10%29.aspx */
int atom_id = 1000;
osip_from_t *from=NULL;
from=osip_message_get_from(notify);
osip_uri_to_str(from->url,&contact_info);
#ifdef SUPPORT_MSN
if (online_status==SalPresenceOnline)
{
sprintf(buf, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence\n\
PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
if (online_status==SalPresenceOnline)
{
snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
<address uri=\"%s\" priority=\"0.800000\">\n\
<status status=\"open\" />\n\
<msnsubstatus substatus=\"online\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
else if (online_status==SalPresenceBusy)
{
sprintf(buf, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence\n\
PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
}
else if (online_status == SalPresenceBusy ||
online_status == SalPresenceDonotdisturb)
{
snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
<address uri=\"%s\" priority=\"0.800000\">\n\
<status status=\"inuse\" />\n\
<msnsubstatus substatus=\"busy\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
</atom>\n</presence>", contact_info, atom_id, contact_info);
}
else if (online_status==SalPresenceBerightback)
{
sprintf(buf, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence\n\
PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
}
else if (online_status==SalPresenceBerightback)
{
snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
<status status=\"inactive\" />\n\
<address uri=\"%s\" priority=\"0.800000\">\n\
<status status=\"open\" />\n\
<msnsubstatus substatus=\"berightback\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
else if (online_status==SalPresenceAway)
{
sprintf(buf, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence\n\
PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
}
else if (online_status == SalPresenceAway ||
online_status == SalPresenceMoved)
{
snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
<status status=\"inactive\" />\n\
<address uri=\"%s\" priority=\"0.800000\">\n\
<status status=\"open\" />\n\
<msnsubstatus substatus=\"away\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
else if (online_status==SalPresenceOnthephone)
{
sprintf(buf, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence\n\
PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
}
else if (online_status==SalPresenceOnthephone)
{
snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
<address uri=\"%s\" priority=\"0.800000\">\n\
<status status=\"inuse\" />\n\
<msnsubstatus substatus=\"onthephone\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
else if (online_status==SalPresenceOuttolunch)
{
sprintf(buf, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence\n\
PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
}
else if (online_status==SalPresenceOuttolunch)
{
snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
<address uri=\"%s\" priority=\"0.800000\">\n\
<status status=\"open\" />\n\
<msnsubstatus substatus=\"outtolunch\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
else
{
snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s\" priority=\"0.800000\">\n\
<status status=\"closed\" />\n\
<msnsubstatus substatus=\"away\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
break;
}
case MSOLDPRES: {
/* Couldn't find schema http://schemas.microsoft.com/2002/09/sip/presence
* so messages format has been taken from Communigate that can send notify
* requests with this schema
*/
int atom_id = 1000;
if (online_status==SalPresenceOnline)
{
snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence SYSTEM \"http://schemas.microsoft.com/2002/09/sip/presence\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s\">\n\
<status status=\"open\" />\n\
<msnsubstatus substatus=\"online\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
else if (online_status == SalPresenceBusy ||
online_status == SalPresenceDonotdisturb)
{
snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence SYSTEM \"http://schemas.microsoft.com/2002/09/sip/presence\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s\">\n\
<status status=\"inuse\" />\n\
<msnsubstatus substatus=\"busy\" />\n\
</address>\n\
</atom>\n</presence>", contact_info, atom_id, contact_info);
}
else if (online_status==SalPresenceBerightback)
{
snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence SYSTEM \"http://schemas.microsoft.com/2002/09/sip/presence\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s\">\n\
<status status=\"inactive\" />\n\
<msnsubstatus substatus=\"berightback\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
else if (online_status == SalPresenceAway ||
online_status == SalPresenceMoved)
{
snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence SYSTEM \"http://schemas.microsoft.com/2002/09/sip/presence\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s\">\n\
<status status=\"inactive\" />\n\
<msnsubstatus substatus=\"idle\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
else if (online_status==SalPresenceOnthephone)
{
snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence SYSTEM \"http://schemas.microsoft.com/2002/09/sip/presence\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s\">\n\
<status status=\"inuse\" />\n\
<msnsubstatus substatus=\"onthephone\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
else if (online_status==SalPresenceOuttolunch)
{
snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence SYSTEM \"http://schemas.microsoft.com/2002/09/sip/presence\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s\">\n\
<status status=\"inactive\" />\n\
<msnsubstatus substatus=\"outtolunch\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
else
{
sprintf(buf, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence\n\
PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
}
else
{
snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence SYSTEM \"http://schemas.microsoft.com/2002/09/sip/presence\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
<status status=\"inactive\" />\n\
<msnsubstatus substatus=\"away\" />\n\
<address uri=\"%s\">\n\
<status status=\"closed\" />\n\
<msnsubstatus substatus=\"offline\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
}
break;
}
default: { /* use pidf+xml as default format, rfc4479, rfc4480, rfc3863 */
osip_message_set_body(notify, buf, strlen(buf));
osip_message_set_content_type(notify, "application/xpidf+xml");
#else
if (online_status==SalPresenceOnline)
{
snprintf(buf, buflen, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\" \
xmlns:dm=\"urn:ietf:params:xml:ns:pidf:data-model\" \
xmlns:rpid=\"urn:ietf:params:xml:ns:pidf:rpid\" \
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status><basic>open</basic></status>\n\
<contact priority=\"0.8\">%s</contact>\n\
</tuple>\n\
</presence>",
contact_info, contact_info);
}
else if (online_status == SalPresenceBusy ||
online_status == SalPresenceDonotdisturb)
{
snprintf(buf, buflen, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\" \
xmlns:dm=\"urn:ietf:params:xml:ns:pidf:data-model\" \
xmlns:rpid=\"urn:ietf:params:xml:ns:pidf:rpid\" \
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status><basic>open</basic></status>\n\
<contact priority=\"0.8\">%s</contact>\n\
</tuple>\n\
<dm:person id=\"sg89aep\">\n\
<rpid:activities><rpid:busy/></rpid:activities>\n\
</dm:person>\n\
</presence>",
contact_info, contact_info);
}
else if (online_status==SalPresenceBerightback)
{
snprintf(buf, buflen, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\" \
xmlns:dm=\"urn:ietf:params:xml:ns:pidf:data-model\" \
xmlns:rpid=\"urn:ietf:params:xml:ns:pidf:rpid\" \
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status><basic>open</basic></status>\n\
<contact priority=\"0.8\">%s</contact>\n\
</tuple>\n\
<dm:person id=\"sg89aep\">\n\
<rpid:activities><rpid:in-transit/></rpid:activities>\n\
</dm:person>\n\
</presence>",
contact_info, contact_info);
}
else if (online_status == SalPresenceAway ||
online_status == SalPresenceMoved)
{
snprintf(buf, buflen, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\" \
xmlns:dm=\"urn:ietf:params:xml:ns:pidf:data-model\" \
xmlns:rpid=\"urn:ietf:params:xml:ns:pidf:rpid\" \
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status><basic>open</basic></status>\n\
<contact priority=\"0.8\">%s</contact>\n\
</tuple>\n\
<dm:person id=\"sg89aep\">\n\
<rpid:activities><rpid:away/></rpid:activities>\n\
</dm:person>\n\
</presence>",
contact_info, contact_info);
}
else if (online_status==SalPresenceOnthephone)
{
snprintf(buf, buflen, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\" \
xmlns:dm=\"urn:ietf:params:xml:ns:pidf:data-model\" \
xmlns:rpid=\"urn:ietf:params:xml:ns:pidf:rpid\" \
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status><basic>open</basic></status>\n\
<contact priority=\"0.8\">%s</contact>\n\
</tuple>\n\
<dm:person id=\"sg89aep\">\n\
<rpid:activities><rpid:on-the-phone/></rpid:activities>\n\
</dm:person>\n\
</presence>",
contact_info, contact_info);
}
else if (online_status==SalPresenceOuttolunch)
{
snprintf(buf, buflen, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\" \
xmlns:dm=\"urn:ietf:params:xml:ns:pidf:data-model\" \
xmlns:rpid=\"urn:ietf:params:xml:ns:pidf:rpid\" \
entity=\"%s\">\n\
<tuple id=\"7777\">\n\
<status><basic>open</basic></status>\n\
<contact priority=\"0.8\">%s</contact>\n\
</tuple>\n\
<dm:person id=\"78787878\">\n\
<rpid:activities><rpid:meal/></rpid:activities>\n\
<rpid:note>Out to lunch</rpid:note> \n\
</dm:person>\n\
</presence>",
contact_info, contact_info);
}
else
{
snprintf(buf, buflen, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\" \
xmlns:dm=\"urn:ietf:params:xml:ns:pidf:data-model\" \
xmlns:rpid=\"urn:ietf:params:xml:ns:pidf:rpid\" \
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status><basic>closed</basic></status>\n\
<contact priority=\"0.8\">%s</contact>\n\
</tuple>\n\
</presence>\n", contact_info, contact_info);
}
break;
}
} // switch
if (online_status==SalPresenceOnline)
{
sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>online</note>\n\
</tuple>\n\
</presence>",
contact_info, contact_info);
}
else if (online_status==SalPresenceBusy)
{
sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
<es:activities>\n\
<es:activity>busy</es:activity>\n\
</es:activities>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>busy</note>\n\
</tuple>\n\
</presence>",
contact_info, contact_info);
}
else if (online_status==SalPresenceBerightback)
{
sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
<es:activities>\n\
<es:activity>in-transit</es:activity>\n\
</es:activities>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>be right back</note>\n\
</tuple>\n\
</presence>",
contact_info, contact_info);
}
else if (online_status==SalPresenceAway)
{
sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
<es:activities>\n\
<es:activity>away</es:activity>\n\
</es:activities>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>away</note>\n\
</tuple>\n\
</presence>",
contact_info, contact_info);
}
else if (online_status==SalPresenceOnthephone)
{
sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
<es:activities>\n\
<es:activity>on-the-phone</es:activity>\n\
</es:activities>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>on the phone</note>\n\
</tuple>\n\
</presence>",
contact_info, contact_info);
}
else if (online_status==SalPresenceOuttolunch)
{
sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
<es:activities>\n\
<es:activity>meal</es:activity>\n\
</es:activities>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>out to lunch</note>\n\
</tuple>\n\
</presence>",
contact_info, contact_info);
}
else
{
/* */
sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n%s",
contact_info,
"<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>closed</basic>\n\
<es:activities>\n\
<es:activity>permanent-absence</es:activity>\n\
</es:activities>\n\
</status>\n\
</tuple>\n\
\n</presence>\n");
}
osip_message_set_body(notify, buf, strlen(buf));
osip_message_set_content_type(notify, "application/pidf+xml");
}
static void add_presence_body(osip_message_t *notify, SalPresenceStatus online_status)
{
char buf[1000];
char *contact_info;
osip_from_t *from=NULL;
from=osip_message_get_from(notify);
osip_uri_to_str(from->url,&contact_info);
mk_presence_body (online_status, contact_info, buf, sizeof (buf), presence_style);
osip_message_set_body(notify, buf, strlen(buf));
osip_message_set_content_type(notify,
presence_style ? "application/xpidf+xml" : "application/pidf+xml");
#endif
osip_free(contact_info);
}
@ -476,137 +598,10 @@ int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus p
int i;
char buf[1024];
if (presence_mode==SalPresenceOnline)
{
snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>online</note>\n\
</tuple>\n\
</presence>",
from, from);
}
else if (presence_mode==SalPresenceBusy
||presence_mode==SalPresenceDonotdisturb)
{
snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
<es:activities>\n\
<es:activity>busy</es:activity>\n\
</es:activities>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>busy</note>\n\
</tuple>\n\
</presence>",
from, from);
}
else if (presence_mode==SalPresenceBerightback)
{
snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
<es:activities>\n\
<es:activity>in-transit</es:activity>\n\
</es:activities>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>be right back</note>\n\
</tuple>\n\
</presence>",
from,from);
}
else if (presence_mode==SalPresenceAway
||presence_mode==SalPresenceMoved)
{
snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
<es:activities>\n\
<es:activity>away</es:activity>\n\
</es:activities>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>away</note>\n\
</tuple>\n\
</presence>",
from, from);
}
else if (presence_mode==SalPresenceOnthephone)
{
snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
<es:activities>\n\
<es:activity>on-the-phone</es:activity>\n\
</es:activities>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>on the phone</note>\n\
</tuple>\n\
</presence>",
from, from);
}
else if (presence_mode==SalPresenceOuttolunch)
{
snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
<es:activities>\n\
<es:activity>meal</es:activity>\n\
</es:activities>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>out to lunch</note>\n\
</tuple>\n\
</presence>",
from, from);
}
else{
/* offline */
snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n%s",
from,
"<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>closed</basic>\n\
<es:activities>\n\
<es:activity>permanent-absence</e:activity>\n\
</es:activities>\n\
</status>\n\
</tuple>\n\
\n</presence>\n");
}
mk_presence_body (presence_mode, from, buf, sizeof (buf), presence_style);
i = eXosip_build_publish(&pub,from, to, NULL, "presence", "1800", "application/pidf+xml", buf);
i = eXosip_build_publish(&pub,from, to, NULL, "presence", "300",
presence_style ? "application/xpidf+xml" : "application/pidf+xml", buf);
if (i<0){
ms_warning("Failed to build publish request.");
return -1;
@ -620,6 +615,7 @@ int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus p
ms_message("Failed to send publish request.");
return -1;
}
sal_add_other(sal_op_get_sal(op),op,pub);
return 0;
}
@ -691,7 +687,8 @@ void sal_exosip_notify_recv(Sal *sal, eXosip_event_t *ev){
}else if (strstr(body->body,"berightback")!=NULL
|| strstr(body->body,"in-transit")!=NULL ){
estatus=SalPresenceBerightback;
}else if (strstr(body->body,"away")!=NULL){
}else if (strstr(body->body,"away")!=NULL
|| strstr(body->body,"idle")){
estatus=SalPresenceAway;
}else if (strstr(body->body,"onthephone")!=NULL
|| strstr(body->body,"on-the-phone")!=NULL){
@ -714,6 +711,15 @@ void sal_exosip_notify_recv(Sal *sal, eXosip_event_t *ev){
ms_message("And outgoing subscription terminated by remote.");
}
sal->callbacks.notify_presence(op,op->sid!=-1 ? SalSubscribeActive : SalSubscribeTerminated, estatus,NULL);
/* try to detect presence message style used by server,
* and switch our presence messages to servers style */
if (strstr (body->body, "//IETF//DTD RFCxxxx XPIDF 1.0//EN") != NULL) {
presence_style = RFCxxxx;
} else if (strstr(body->body,"http://schemas.microsoft.com/2002/09/sip/presence")!=NULL) {
presence_style = MSOLDPRES;
}
osip_free(tmp);
}

View file

@ -106,6 +106,23 @@ static int _sdp_message_get_a_ptime(sdp_message_t *sdp, int mline){
return 0;
}
static int _sdp_message_get_mline_dir(sdp_message_t *sdp, int mline){
int i;
sdp_attribute_t *attr;
for (i=0;(attr=sdp_message_attribute_get(sdp,mline,i))!=NULL;i++){
if (keywordcmp("sendrecv",attr->a_att_field)==0){
return SalStreamSendRecv;
}else if (keywordcmp("sendonly",attr->a_att_field)==0){
return SalStreamSendOnly;
}else if (keywordcmp("recvonly",attr->a_att_field)==0){
return SalStreamSendOnly;
}else if (keywordcmp("inactive",attr->a_att_field)==0){
return SalStreamInactive;
}
}
return SalStreamSendRecv;
}
static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc)
{
sdp_message_t *local;
@ -121,12 +138,21 @@ 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 ("A conversation"));
sdp_message_c_connection_add (local, -1,
osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"),
osip_strdup (desc->addr), NULL, NULL);
if(!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);
}
else
{
sdp_message_c_connection_add (local, -1,
osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"),
inet6 ? osip_strdup ("::0") : osip_strdup ("0.0.0.0"), NULL, NULL);
}
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));
int_2char(desc->bandwidth));
return local;
}
@ -158,6 +184,7 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription
const char *mt=desc->type==SalAudio ? "audio" : "video";
const MSList *elem;
const char *addr;
const char *dir="sendrecv";
int port;
if (desc->candidates[0].addr[0]!='\0'){
addr=desc->candidates[0].addr;
@ -186,6 +213,21 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription
for(elem=desc->payloads;elem!=NULL;elem=elem->next){
add_payload(msg, lineno, (PayloadType*)elem->data);
}
switch(desc->dir){
case SalStreamSendRecv:
dir="sendrecv";
break;
case SalStreamRecvOnly:
dir="recvonly";
break;
case SalStreamSendOnly:
dir="sendonly";
break;
case SalStreamInactive:
dir="inactive";
break;
}
sdp_message_a_attribute_add (msg, lineno, osip_strdup (dir),NULL);
}
sdp_message_t *media_description_to_sdp(const SalMediaDescription *desc){
@ -272,6 +314,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);
/* for each payload type */
for (j=0;((number=sdp_message_m_payload_get (msg, i,j)) != NULL); j++){
const char *rtpmap,*fmtp;
@ -280,13 +323,14 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){
payload_type_set_number(pt,ptn);
/* get the rtpmap associated to this codec, if any */
rtpmap=sdp_message_a_attr_value_get_with_pt(msg, i,ptn,"rtpmap");
payload_type_fill_from_rtpmap(pt,rtpmap);
/* get the fmtp, if any */
fmtp=sdp_message_a_attr_value_get_with_pt(msg, i, ptn,"fmtp");
payload_type_set_send_fmtp(pt,fmtp);
stream->payloads=ms_list_append(stream->payloads,pt);
ms_message("Found payload %s/%i fmtp=%s",pt->mime_type,pt->clock_rate,
pt->send_fmtp ? pt->send_fmtp : "");
if (payload_type_fill_from_rtpmap(pt,rtpmap)==0){
/* get the fmtp, if any */
fmtp=sdp_message_a_attr_value_get_with_pt(msg, i, ptn,"fmtp");
payload_type_set_send_fmtp(pt,fmtp);
stream->payloads=ms_list_append(stream->payloads,pt);
ms_message("Found payload %s/%i fmtp=%s",pt->mime_type,pt->clock_rate,
pt->send_fmtp ? pt->send_fmtp : "");
}
}
}
desc->nstreams=i;

View file

@ -1,694 +0,0 @@
/*
* Linphone is sip (RFC3261) compatible internet phone.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "sdphandler.h"
#include <osipparser2/osip_port.h>
#include <osipparser2/sdp_message.h>
#include <eXosip2/eXosip.h>
#include "linphonecore.h"
#include "ortp/b64.h"
#define keywordcmp(key,str) strncmp(key,str,strlen(key))
#define sstrdup_sprintf ms_strdup_printf
#define eXosip_trace(loglevel,args) do \
{ \
char *__strmsg; \
__strmsg=ms_strdup_printf args ; \
OSIP_TRACE(osip_trace(__FILE__,__LINE__,(loglevel),NULL,"%s\n",__strmsg)); \
osip_free (__strmsg); \
}while (0);
static char *make_relay_session_id(const char *username, const char *relay){
/*ideally this should be a hash of the parameters with a random part*/
char tmp[128];
int s1=(int)random();
int s2=(int)random();
long long int res=((long long int)s1)<<32 | (long long int) s2;
void *src=&res;
b64_encode(src, sizeof(long long int), tmp, sizeof(tmp));
return osip_strdup(tmp);
}
char * int_2char(int a){
char *p=osip_malloc(16);
snprintf(p,16,"%i",a);
return p;
}
/* return the value of attr "field" for payload pt at line pos (field=rtpmap,fmtp...)*/
char *sdp_message_a_attr_value_get_with_pt(sdp_message_t *sdp,int pos,int pt,const char *field)
{
int i,tmppt=0,scanned=0;
char *tmp;
sdp_attribute_t *attr;
for (i=0;(attr=sdp_message_attribute_get(sdp,pos,i))!=NULL;i++){
if (keywordcmp(field,attr->a_att_field)==0 && attr->a_att_value!=NULL){
int nb = sscanf(attr->a_att_value,"%i %n",&tmppt,&scanned);
/* the return value may depend on how %n is interpreted by the libc: see manpage*/
if (nb == 1 || nb==2 ){
if (pt==tmppt){
tmp=attr->a_att_value+scanned;
if (strlen(tmp)>0)
return tmp;
}
}else eXosip_trace(OSIP_WARNING,("sdp has a strange a= line (%s) nb=%i",attr->a_att_value,nb));
}
}
return NULL;
}
/* return the value of attr "field" */
char *sdp_message_a_attr_value_get(sdp_message_t *sdp,int pos,const char *field)
{
int i;
sdp_attribute_t *attr;
for (i=0;(attr=sdp_message_attribute_get(sdp,pos,i))!=NULL;i++){
if (keywordcmp(field,attr->a_att_field)==0 && attr->a_att_value!=NULL){
return attr->a_att_value;
}
}
return NULL;
}
static int _sdp_message_get_a_ptime(sdp_message_t *sdp, int mline){
int i,ret;
sdp_attribute_t *attr;
for (i=0;(attr=sdp_message_attribute_get(sdp,mline,i))!=NULL;i++){
if (keywordcmp("ptime",attr->a_att_field)==0){
int nb = sscanf(attr->a_att_value,"%i",&ret);
/* the return value may depend on how %n is interpreted by the libc: see manpage*/
if (nb == 1){
return ret;
}else eXosip_trace(OSIP_WARNING,("sdp has a strange a=ptime line (%s) ",attr->a_att_value));
}
}
return 0;
}
int
sdp_payload_init (sdp_payload_t * payload)
{
memset (payload, 0, sizeof (sdp_payload_t));
return 0;
}
sdp_context_t *sdp_handler_create_context(sdp_handler_t *handler, const char *localip, const char *username, const char *relay){
sdp_context_t *ctx=osip_malloc(sizeof(sdp_context_t));
memset(ctx,0,sizeof(sdp_context_t));
if (localip!=NULL) ctx->localip=osip_strdup(localip);
ctx->username=osip_strdup(username);
ctx->handler=handler;
if (relay){
ctx->relay=osip_strdup(relay);
ctx->relay_session_id=make_relay_session_id(username,relay);
}
return ctx;
}
void sdp_context_set_user_pointer(sdp_context_t * ctx, void* up){
ctx->reference=up;
}
void *sdp_context_get_user_pointer(sdp_context_t * ctx){
return ctx->reference;
}
int sdp_context_get_status(sdp_context_t* ctx){
return ctx->negoc_status;
}
/* generate a template sdp */
sdp_message_t *
sdp_context_generate_template (sdp_context_t * ctx)
{
sdp_message_t *local;
int inet6;
sdp_message_init (&local);
if (strchr(ctx->localip,':')!=NULL){
inet6=1;
}else inet6=0;
if (!inet6){
sdp_message_v_version_set (local, osip_strdup ("0"));
sdp_message_o_origin_set (local, osip_strdup (ctx->username),
osip_strdup ("123456"), osip_strdup ("654321"),
osip_strdup ("IN"), osip_strdup ("IP4"),
osip_strdup (ctx->localip));
sdp_message_s_name_set (local, osip_strdup ("A conversation"));
sdp_message_c_connection_add (local, -1,
osip_strdup ("IN"), osip_strdup ("IP4"),
osip_strdup (ctx->localip), NULL, NULL);
sdp_message_t_time_descr_add (local, osip_strdup ("0"), osip_strdup ("0"));
}else{
sdp_message_v_version_set (local, osip_strdup ("0"));
sdp_message_o_origin_set (local, osip_strdup (ctx->username),
osip_strdup ("123456"), osip_strdup ("654321"),
osip_strdup ("IN"), osip_strdup ("IP6"),
osip_strdup (ctx->localip));
sdp_message_s_name_set (local, osip_strdup ("A conversation"));
sdp_message_c_connection_add (local, -1,
osip_strdup ("IN"), osip_strdup ("IP6"),
osip_strdup (ctx->localip), NULL, NULL);
sdp_message_t_time_descr_add (local, osip_strdup ("0"), osip_strdup ("0"));
}
return local;
}
static void add_relay_info(sdp_message_t *sdp, int mline, const char *relay, const char *relay_session_id){
if (relay) sdp_message_a_attribute_add(sdp, mline,
osip_strdup ("relay-addr"),osip_strdup(relay));
if (relay_session_id) sdp_message_a_attribute_add(sdp, mline,
osip_strdup ("relay-session-id"), osip_strdup(relay_session_id));
}
/* to add payloads to the offer, must be called inside the write_offer callback */
void
sdp_context_add_payload (sdp_context_t * ctx, sdp_payload_t * payload, char *media)
{
sdp_message_t *offer = ctx->offer;
char *attr_field;
if (!ctx->incb)
{
eXosip_trace (OSIP_ERROR,
("You must not call sdp_context_add_*_payload outside the write_offer callback\n"));
#if !defined(_WIN32_WCE)
abort();
#else
exit(-1);
#endif /*_WIN32_WCE*/
}
if (payload->proto == NULL)
payload->proto = "RTP/AVP";
/*printf("payload->line=%i payload->pt=%i\n",payload->line, payload->pt);*/
if (sdp_message_m_media_get (offer, payload->line) == NULL)
{
/*printf("Adding new mline %s \n",media);*/
/* need a new line */
sdp_message_m_media_add (offer, osip_strdup (media),
int_2char (payload->localport), NULL,
osip_strdup (payload->proto));
if (ctx->relay){
add_relay_info(offer,payload->line,ctx->relay,ctx->relay_session_id);
}
}
sdp_message_m_payload_add (offer, payload->line, int_2char (payload->pt));
if (payload->a_rtpmap != NULL)
{
attr_field =
sstrdup_sprintf ("%i %s", payload->pt,
payload->a_rtpmap);
sdp_message_a_attribute_add (offer, payload->line,
osip_strdup ("rtpmap"), attr_field);
}
if (payload->a_fmtp != NULL)
{
attr_field =
sstrdup_sprintf ("%i %s", payload->pt,
payload->a_fmtp);
sdp_message_a_attribute_add (offer, payload->line, osip_strdup ("fmtp"),
attr_field);
}
if (payload->b_as_bandwidth != 0)
{
if (sdp_message_bandwidth_get(offer,payload->line,0)==NULL){
attr_field =
sstrdup_sprintf ("%i", payload->b_as_bandwidth);
sdp_message_b_bandwidth_add (offer, payload->line, osip_strdup ("AS"),
attr_field);
}
}
if (payload->a_ptime !=0) {
attr_field = sstrdup_sprintf ("%i", payload->a_ptime);
sdp_message_a_attribute_add(offer, payload->line,osip_strdup ("ptime"),attr_field);
ms_message("adding ptime [%s]",attr_field);
}
}
void
sdp_context_add_audio_payload (sdp_context_t * ctx, sdp_payload_t * payload)
{
sdp_context_add_payload (ctx, payload, "audio");
}
void
sdp_context_add_video_payload (sdp_context_t * ctx, sdp_payload_t * payload)
{
sdp_context_add_payload (ctx, payload, "video");
}
char *
sdp_context_get_offer ( sdp_context_t * ctx)
{
sdp_message_t *offer;
sdp_handler_t *sdph=ctx->handler;
char *tmp;
offer = sdp_context_generate_template (ctx);
/* add audio codecs */
ctx->offer = offer;
ctx->incb = 1;
if (sdph->set_audio_codecs != NULL)
sdph->set_audio_codecs (ctx);
if (sdph->set_video_codecs != NULL)
sdph->set_video_codecs (ctx);
ctx->incb = 0;
sdp_message_to_str(offer,&tmp);
ctx->offerstr=tmp;
return tmp;
}
/* refuse the line */
static void refuse_mline(sdp_message_t *answer,char *mtype,char *proto, int mline)
{
sdp_message_m_media_add (answer,
osip_strdup (mtype),
int_2char (0), NULL,
osip_strdup (proto));
/* add a payload just to comply with sdp RFC.*/
sdp_message_m_payload_add(answer,mline,int_2char(0));
}
static char * parse_relay_addr(char *addr, int *port)
{
char *semicolon=NULL;
char *p;
*port=56789;
semicolon=strchr(addr,':');
for (p=addr+strlen(addr)-1;p>addr;p--){
if (*p==':') {
semicolon=p;
break;
}
}
if (semicolon){
*port=atoi(semicolon+1);
*semicolon='\0';
}
return addr;
}
char *
sdp_context_get_answer ( sdp_context_t *ctx,sdp_message_t *remote)
{
sdp_message_t *answer=NULL;
char *mtype=NULL, *tmp=NULL;
char *proto=NULL, *port=NULL, *pt=NULL;
int i, j, ncodec, m_lines_accepted = 0;
int err;
sdp_payload_t payload;
sdp_payload_t init_payload;
sdp_handler_t *sdph=ctx->handler;
sdp_bandwidth_t *sbw=NULL;
char *relay;
tmp = sdp_message_c_addr_get (remote, 0, 0);
if (tmp == NULL)
tmp = sdp_message_c_addr_get (remote, -1, 0);
if (ctx->localip==NULL) {
/* NULL means guess, otherwise we use the address given as localip */
ctx->localip=osip_malloc(128);
eXosip_guess_localip(strchr(tmp,':') ? AF_INET6 : AF_INET,ctx->localip,128);
}
else eXosip_trace(OSIP_INFO1,("Using firewall address in sdp."));
answer = sdp_context_generate_template (ctx);
/* for each m= line */
for (i = 0; !sdp_message_endof_media (remote, i); i++){
sdp_payload_init(&init_payload);
mtype = sdp_message_m_media_get (remote, i);
proto = sdp_message_m_proto_get (remote, i);
port = sdp_message_m_port_get (remote, i);
init_payload.remoteport = osip_atoi (port);
init_payload.proto = proto;
init_payload.line = i;
init_payload.c_addr = sdp_message_c_addr_get (remote, i, 0);
if (init_payload.c_addr == NULL)
init_payload.c_addr = sdp_message_c_addr_get (remote, -1, 0);
/*parse relay address if given*/
relay=sdp_message_a_attr_value_get(remote,i,"relay-addr");
if (relay){
init_payload.relay_host=parse_relay_addr(relay,&init_payload.relay_port);
}
init_payload.relay_session_id=sdp_message_a_attr_value_get(remote,i,"relay-session-id");
/* get application specific bandwidth, if any */
for(j=0;(sbw=sdp_message_bandwidth_get(remote,i,j))!=NULL;j++){
if (strcasecmp(sbw->b_bwtype,"AS")==0) init_payload.b_as_bandwidth=atoi(sbw->b_bandwidth);
}
init_payload.a_ptime=_sdp_message_get_a_ptime(remote,i);
if (keywordcmp ("audio", mtype) == 0)
{
if (sdph->accept_audio_codecs != NULL)
{
ncodec = 0;
/* for each payload type */
for (j = 0;
((pt =
sdp_message_m_payload_get (remote, i,
j)) != NULL); j++)
{
memcpy(&payload,&init_payload,sizeof(payload));
payload.pt = osip_atoi (pt);
/* get the rtpmap associated to this codec, if any */
payload.a_rtpmap =
sdp_message_a_attr_value_get_with_pt
(remote, i, payload.pt,
"rtpmap");
/* get the fmtp, if any */
payload.a_fmtp =
sdp_message_a_attr_value_get_with_pt
(remote, i, payload.pt,
"fmtp");
/* ask the application if this codec is supported */
err = sdph->accept_audio_codecs (ctx,
&payload);
if (err == 0)
{
ncodec++;
/* codec accepted */
if (ncodec == 1)
{
/* first codec accepted, setup the line */
sdp_message_m_media_add
(answer,
osip_strdup
(mtype),
int_2char
(payload.
localport),
NULL,
osip_strdup
(proto));
/* and accept the remote relay addr if we planned to use our own */
if (ctx->relay!=NULL && relay){
add_relay_info(answer,i,relay,payload.relay_session_id);
}
}
/* add the payload, rtpmap, fmtp */
sdp_message_m_payload_add (answer, i,
int_2char
(payload.
pt));
if (payload.a_rtpmap != NULL)
{
sdp_message_a_attribute_add
(answer, i,
osip_strdup
("rtpmap"),
sstrdup_sprintf
("%i %s",
payload.pt,
payload.
a_rtpmap));
}
if (payload.a_fmtp != NULL)
{
sdp_message_a_attribute_add
(answer, i,
osip_strdup
("fmtp"),
sstrdup_sprintf
("%i %s",
payload.pt,
payload.
a_fmtp));
}
if (payload.b_as_bandwidth !=
0)
{
if (sdp_message_bandwidth_get(answer,i,0)==NULL)
sdp_message_b_bandwidth_add
(answer, i,
osip_strdup
("AS"),
sstrdup_sprintf
("%i",
payload.
b_as_bandwidth));
}
}
}
if (ncodec == 0)
{
/* refuse the line */
refuse_mline(answer,mtype,proto,i);
}
else
m_lines_accepted++;
}
else
{
/* refuse this line (leave port to 0) */
refuse_mline(answer,mtype,proto,i);
}
}
else if (keywordcmp ("video", mtype) == 0)
{
if (sdph->accept_video_codecs != NULL)
{
ncodec = 0;
/* for each payload type */
for (j = 0;
((pt =
sdp_message_m_payload_get (remote, i,
j)) != NULL); j++)
{
memcpy(&payload,&init_payload,sizeof(payload));
payload.pt = osip_atoi (pt);
/* get the rtpmap associated to this codec, if any */
payload.a_rtpmap =
sdp_message_a_attr_value_get_with_pt
(remote, i, payload.pt,
"rtpmap");
/* get the fmtp, if any */
payload.a_fmtp =
sdp_message_a_attr_value_get_with_pt
(remote, i, payload.pt,
"fmtp");
/* ask the application if this codec is supported */
err = sdph->accept_video_codecs (ctx,
&payload);
if (err == 0 )
{
ncodec++;
/* codec accepted */
if (ncodec == 1)
{
/* first codec accepted, setup the line */
sdp_message_m_media_add
(answer,
osip_strdup
(mtype),
int_2char
(payload.localport), NULL,
osip_strdup
(proto));
/* and accept the remote relay addr if we planned to use our own */
if (ctx->relay!=NULL && relay){
add_relay_info(answer,i,relay,payload.relay_session_id);
}
}
/* add the payload, rtpmap, fmtp */
sdp_message_m_payload_add (answer, i,
int_2char
(payload.
pt));
if (payload.a_rtpmap != NULL)
{
sdp_message_a_attribute_add
(answer, i,
osip_strdup
("rtpmap"),
sstrdup_sprintf
("%i %s",
payload.pt,
payload.
a_rtpmap));
}
if (payload.a_fmtp != NULL)
{
sdp_message_a_attribute_add
(answer, i,
osip_strdup
("fmtp"),
sstrdup_sprintf
("%i %s",
payload.pt,
payload.
a_fmtp));
}
if (payload.b_as_bandwidth !=0)
{
if (sdp_message_bandwidth_get(answer,i,0)==NULL)
sdp_message_b_bandwidth_add
(answer, i,
osip_strdup
("AS"),
sstrdup_sprintf
("%i",
payload.
b_as_bandwidth));
}
}
}
if (ncodec == 0)
{
/* refuse the line */
refuse_mline(answer,mtype,proto,i);
}
else
m_lines_accepted++;
}
else
{
/* refuse the line */
refuse_mline(answer,mtype,proto,i);
}
}
}
if (ctx->answer!=NULL)
sdp_message_free(ctx->answer);
ctx->answer = answer;
if (m_lines_accepted > 0){
ctx->negoc_status = 200;
sdp_message_to_str(answer,&tmp);
if (ctx->answerstr!=NULL)
osip_free(ctx->answerstr);
ctx->answerstr=tmp;
return tmp;
}else{
ctx->negoc_status = 415;
return NULL;
}
}
void
sdp_context_read_answer (sdp_context_t *ctx, sdp_message_t *remote)
{
char *mtype;
char *proto, *port, *pt;
int i, j,err;
char *relay;
sdp_payload_t payload,arg_payload;
sdp_handler_t *sdph=ctx->handler;
sdp_bandwidth_t *sbw=NULL;
/* for each m= line */
for (i = 0; !sdp_message_endof_media (remote, i); i++)
{
sdp_payload_init(&payload);
mtype = sdp_message_m_media_get (remote, i);
proto = sdp_message_m_proto_get (remote, i);
port = sdp_message_m_port_get (remote, i);
payload.remoteport = osip_atoi (port);
payload.localport = osip_atoi (sdp_message_m_port_get (ctx->offer, i));
payload.proto = proto;
payload.line = i;
payload.c_addr = sdp_message_c_addr_get (remote, i, 0);
if (payload.c_addr == NULL)
payload.c_addr = sdp_message_c_addr_get (remote, -1, 0);
/*parse relay address if given*/
relay=sdp_message_a_attr_value_get(remote,i,"relay-addr");
if (relay){
payload.relay_host=parse_relay_addr(relay,&payload.relay_port);
}
payload.relay_session_id=sdp_message_a_attr_value_get(remote,i,"relay-session-id");
for(j=0;(sbw=sdp_message_bandwidth_get(remote,i,j))!=NULL;++j){
if (strcasecmp(sbw->b_bwtype,"AS")==0) payload.b_as_bandwidth=atoi(sbw->b_bandwidth);
}
payload.a_ptime=_sdp_message_get_a_ptime(remote,i);
if (keywordcmp ("audio", mtype) == 0)
{
if (sdph->get_audio_codecs != NULL)
{
/* for each payload type */
for (j = 0;
((pt =
sdp_message_m_payload_get (remote, i,
j)) != NULL); j++)
{
payload.pt = osip_atoi (pt);
/* get the rtpmap associated to this codec, if any */
payload.a_rtpmap =
sdp_message_a_attr_value_get_with_pt
(remote, i, payload.pt,
"rtpmap");
/* get the fmtp, if any */
payload.a_fmtp =
sdp_message_a_attr_value_get_with_pt
(remote, i, payload.pt,
"fmtp");
/* ask the application if this codec is supported */
memcpy(&arg_payload,&payload,sizeof(payload));
err = sdph->get_audio_codecs (ctx,
&arg_payload);
}
}
}
else if (keywordcmp ("video", mtype) == 0)
{
if (sdph->get_video_codecs != NULL)
{
/* for each payload type */
for (j = 0;
((pt =
sdp_message_m_payload_get (remote, i,
j)) != NULL); j++)
{
payload.pt = osip_atoi (pt);
/* get the rtpmap associated to this codec, if any */
payload.a_rtpmap =
sdp_message_a_attr_value_get_with_pt
(remote, i, payload.pt,
"rtpmap");
/* get the fmtp, if any */
payload.a_fmtp =
sdp_message_a_attr_value_get_with_pt
(remote, i, payload.pt,
"fmtp");
/* ask the application if this codec is supported */
memcpy(&arg_payload,&payload,sizeof(payload));
err = sdph->get_video_codecs (ctx,
&arg_payload);
}
}
}
}
}
void sdp_context_free(sdp_context_t *ctx){
osip_free(ctx->localip);
osip_free(ctx->username);
if (ctx->offer!=NULL) sdp_message_free(ctx->offer);
if (ctx->answer!=NULL) sdp_message_free(ctx->answer);
if (ctx->offerstr!=NULL) osip_free(ctx->offerstr);
if (ctx->answerstr!=NULL) osip_free(ctx->answerstr);
if (ctx->relay!=NULL) osip_free(ctx->relay);
if (ctx->relay_session_id!=NULL) osip_free(ctx->relay_session_id);
osip_free(ctx);
}

View file

@ -1,101 +0,0 @@
/*
* Linphone is sip (RFC3261) compatible internet phone.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef SDP_HANDLER_H
#define SDP_HANDLER_H
#include <osipparser2/sdp_message.h>
#include "linphonecore.h"
typedef struct _sdp_payload
{
int line; /* the index of the m= line */
int pt; /*payload type */
int localport;
int remoteport;
int b_as_bandwidth; /* application specific bandwidth */
char *proto;
char *c_nettype;
char *c_addrtype;
char *c_addr;
char *c_addr_multicast_ttl;
char *c_addr_multicast_int;
char *a_rtpmap;
char *a_fmtp;
char *relay_host;
int relay_port;
char *relay_session_id;
int a_ptime;
} sdp_payload_t;
typedef struct _sdp_context sdp_context_t;
typedef int (*sdp_handler_read_codec_func_t) (struct _sdp_context *,
sdp_payload_t *);
typedef int (*sdp_handler_write_codec_func_t) (struct _sdp_context *);
typedef struct _sdp_handler
{
sdp_handler_read_codec_func_t accept_audio_codecs; /*from remote sdp */
sdp_handler_read_codec_func_t accept_video_codecs; /*from remote sdp */
sdp_handler_write_codec_func_t set_audio_codecs; /*to local sdp */
sdp_handler_write_codec_func_t set_video_codecs; /*to local sdp */
sdp_handler_read_codec_func_t get_audio_codecs; /*from incoming answer */
sdp_handler_read_codec_func_t get_video_codecs; /*from incoming answer */
} sdp_handler_t;
typedef enum _sdp_context_state
{
SDP_CONTEXT_STATE_INIT,
SDP_CONTEXT_STATE_NEGOCIATION_OPENED,
SDP_CONTEXT_STATE_NEGOCIATION_CLOSED
} sdp_context_state_t;
struct _sdp_context
{
sdp_handler_t *handler;
char *localip;
char *username;
void *reference;
sdp_message_t *offer; /* the local sdp to be used for outgoing request */
char *offerstr;
sdp_message_t *answer; /* the local sdp generated from an inc request */
char *answerstr;
char *relay;
char *relay_session_id;
int negoc_status; /* in sip code */
int incb;
sdp_context_state_t state;
};
/* create a context for a sdp negociation: localip is the ip address to be used in the sdp message, can
be a firewall address.
It can be null when negociating for an incoming offer; In that case it will be guessed. */
sdp_context_t *sdp_handler_create_context(sdp_handler_t *handler, const char *localip, const char *username, const char *relay);
void sdp_context_set_user_pointer(sdp_context_t * ctx, void* up);
void *sdp_context_get_user_pointer(sdp_context_t * ctx);
void sdp_context_add_audio_payload( sdp_context_t * ctx, sdp_payload_t * payload);
void sdp_context_add_video_payload( sdp_context_t * ctx, sdp_payload_t * payload);
char * sdp_context_get_offer(sdp_context_t *ctx);
char * sdp_context_get_answer(sdp_context_t* ctx, sdp_message_t *remote_offer);
int sdp_context_get_status(sdp_context_t* ctx);
void sdp_context_read_answer(sdp_context_t *ctx, sdp_message_t *remote_answer);
void sdp_context_free(sdp_context_t *ctx);
int sdp_payload_init (sdp_payload_t * payload);
#endif

104
coreapi/test_lsd.c Normal file
View file

@ -0,0 +1,104 @@
/*
linphone
Copyright (C) 2010 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.
*/
/* Linphone Sound Daemon: is a lightweight utility to play sounds to speaker during a conversation.
This is useful for embedded platforms, where sound apis are not performant enough to allow
simultaneous sound access.
This file is a test program that plays several sound files and places a call simultatenously.
*/
#include "linphonecore_utils.h"
static void play_finished(LsdPlayer *p){
const char *filename=(const char *)lsd_player_get_user_pointer (p);
ms_message("Playing of %s is finished.",filename);
if (!lsd_player_loop_enabled (p)){
linphone_sound_daemon_release_player (lsd_player_get_daemon(p),p);
}
}
static void wait_a_bit(LinphoneCore *lc, int seconds){
time_t orig=ms_time(NULL);
while(ms_time(NULL)-orig<seconds){
/* we need to call iterate to receive notifications */
linphone_core_iterate(lc);
ms_usleep (50000);
}
}
int main(int argc, char *argv[]){
LinphoneCore *lc;
LinphoneCoreVTable vtable={0};
LinphoneSoundDaemon *lsd;
LsdPlayer *p;
linphone_core_enable_logs(stdout);
lc=linphone_core_new(&vtable,NULL,NULL,NULL);
lsd=linphone_sound_daemon_new (NULL,44100,1);
linphone_core_use_sound_daemon(lc,lsd);
/* start a play */
p=linphone_sound_daemon_get_player(lsd);
lsd_player_set_callback (p,play_finished);
lsd_player_set_user_pointer (p,"share/hello8000.wav");
lsd_player_play (p,"share/hello8000.wav");
wait_a_bit (lc,2);
/*start another one */
p=linphone_sound_daemon_get_player(lsd);
lsd_player_set_callback (p,play_finished);
lsd_player_set_user_pointer (p,"share/hello16000.wav");
lsd_player_enable_loop (p,TRUE);
lsd_player_play (p,"share/hello16000.wav");
/* after a few seconds decrease the volume */
wait_a_bit (lc,3);
lsd_player_set_gain (p,0.3);
wait_a_bit(lc,5);
/*now play some stereo music*/
p=linphone_sound_daemon_get_player(lsd);
lsd_player_set_callback (p,play_finished);
lsd_player_set_user_pointer (p,"share/rings/rock.wav");
lsd_player_play(p,"share/rings/rock.wav");
wait_a_bit(lc,2);
/*now play some stereo music at 22khz in order to test
stereo resampling */
p=linphone_sound_daemon_get_player(lsd);
lsd_player_set_callback (p,play_finished);
lsd_player_set_user_pointer (p,"share/rings/bigben.wav");
lsd_player_play(p,"share/rings/bigben.wav");
wait_a_bit(lc,6);
/* now place an outgoing call if sip address argument is given */
if (argc>1){
linphone_core_invite(lc,argv[1]);
wait_a_bit(lc,10);
linphone_core_terminate_call(lc,NULL);
}
linphone_core_use_sound_daemon(lc,NULL);
linphone_sound_daemon_destroy(lsd);
linphone_core_destroy(lc);
return 0;
}

View file

@ -1,66 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
<!--Generated with glade3 3.4.5 on Wed Jul 30 17:55:28 2008 -->
<glade-interface>
<widget class="GtkDialog" id="call_logs">
<property name="width_request">500</property>
<property name="height_request">370</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Call history</property>
<property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
<property name="icon">linphone2.png</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
<property name="has_separator">False</property>
<child internal-child="vbox">
<widget class="GtkVBox" id="dialog-vbox1">
<property name="visible">True</property>
<property name="spacing">2</property>
<child>
<widget class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<child>
<widget class="GtkTextView" id="logtextview">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="editable">False</property>
<property name="wrap_mode">GTK_WRAP_WORD</property>
</widget>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
<child internal-child="action_area">
<widget class="GtkHButtonBox" id="dialog-action_area1">
<property name="visible">True</property>
<property name="layout_style">GTK_BUTTONBOX_END</property>
<child>
<placeholder/>
</child>
<child>
<widget class="GtkButton" id="button1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="label" translatable="yes">gtk-close</property>
<property name="use_stock">True</property>
<property name="response_id">0</property>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="pack_type">GTK_PACK_END</property>
</packing>
</child>
</widget>
</child>
</widget>
</glade-interface>

View file

@ -1,69 +0,0 @@
/*
linphone, gtk-glade interface.
Copyright (C) 2008 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 "linphone.h"
void linphone_gtk_call_log_update(GtkWidget *w){
GtkTextView *v=GTK_TEXT_VIEW(linphone_gtk_get_widget(w,"logtextview"));
GtkTextBuffer *b=gtk_text_view_get_buffer(v);
GtkTextIter iter,begin;
int off;
char *logmsg;
const MSList *logs;
for (logs=linphone_core_get_call_logs(linphone_gtk_get_core());logs!=NULL;logs=logs->next){
LinphoneCallLog *cl=(LinphoneCallLog*)logs->data;
logmsg=linphone_call_log_to_str(cl);
gtk_text_buffer_get_end_iter(b,&iter);
off=gtk_text_iter_get_offset(&iter);
gtk_text_buffer_insert(b,&iter,logmsg,-1);
gtk_text_buffer_get_end_iter(b,&iter);
gtk_text_buffer_insert(b,&iter,"\n",-1);
gtk_text_buffer_get_end_iter(b,&iter);
gtk_text_buffer_get_iter_at_offset(b,&begin,off);
gtk_text_buffer_apply_tag_by_name(b,cl->dir==LinphoneCallOutgoing ? "green" : "blue" ,&begin,&iter);
ms_free(logmsg);
}
gtk_text_buffer_get_end_iter(b,&iter);
gtk_text_view_scroll_to_iter(v,&iter,0,FALSE,0,0);
}
void linphone_gtk_call_log_response(GtkWidget *w){
GtkWidget *mw=linphone_gtk_get_main_window();
g_object_set_data(G_OBJECT(mw),"call_logs",NULL);
gtk_widget_destroy(w);
}
GtkWidget * linphone_gtk_show_call_logs(void){
GtkWidget *mw=linphone_gtk_get_main_window();
GtkTextBuffer *b;
GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"call_logs");
if (w==NULL){
w=linphone_gtk_create_window("call_logs");
g_object_set_data(G_OBJECT(mw),"call_logs",w);
g_signal_connect(G_OBJECT(w),"response",(GCallback)linphone_gtk_call_log_response,NULL);
gtk_widget_show(w);
b=gtk_text_view_get_buffer(GTK_TEXT_VIEW(linphone_gtk_get_widget(w,"logtextview")));
gtk_text_buffer_create_tag(b,"blue","foreground","blue",NULL);
gtk_text_buffer_create_tag(b,"green","foreground","green",NULL);
linphone_gtk_call_log_update(w);
}else gtk_window_present(GTK_WINDOW(w));
return w;
}

View file

@ -1,208 +0,0 @@
/*
linphone, gtk-glade interface.
Copyright (C) 2009 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.
*/
/*
* C Implementation: incall_frame
*
* Description:
*
*
* Author: Simon Morlat <simon.morlat@linphone.org>, (C) 2009
*
*
*/
#include "linphone.h"
gboolean linphone_gtk_use_in_call_view(){
static int val=-1;
if (val==-1) val=linphone_gtk_get_ui_config_int("use_incall_view",1);
return val;
}
void linphone_gtk_show_in_call_view(void){
GtkWidget *main_window=linphone_gtk_get_main_window();
GtkNotebook *notebook=(GtkNotebook *)linphone_gtk_get_widget(main_window,"viewswitch");
GtkWidget *in_call_frame=linphone_gtk_get_widget(main_window,"in_call_frame");
gint idx;
/* Make the in call frame visible and arrange for the notebook to
show that page */
gtk_widget_show(in_call_frame);
idx = gtk_notebook_page_num(notebook, in_call_frame);
if (idx >= 0) {
gtk_notebook_set_current_page(notebook, idx);
}
}
void linphone_gtk_show_idle_view(void){
GtkWidget *main_window=linphone_gtk_get_main_window();
GtkNotebook *notebook=(GtkNotebook *)linphone_gtk_get_widget(main_window,"viewswitch");
GtkWidget *idle_frame=linphone_gtk_get_widget(main_window,"idle_frame");
GtkWidget *in_call_frame=linphone_gtk_get_widget(main_window,"in_call_frame");
gint idx;
/* Switch back to the idle frame page, maybe we should have
remembered where we were in gtk_show_in_call_view() to switch
back to that page of the notebook, but this should do in most
cases. */
gtk_widget_show(idle_frame); /* Make sure it is visible... */
idx = gtk_notebook_page_num(notebook, idle_frame);
if (idx >= 0) {
gtk_notebook_set_current_page(notebook, idx);
gtk_widget_hide(in_call_frame);
}
}
void display_peer_name_in_label(GtkWidget *label, const char *uri){
LinphoneAddress *from;
const char *displayname=NULL;
char *id=NULL;
char *uri_label;
if (uri==NULL) {
ms_error("Strange: in call with nobody ?");
return;
}
from=linphone_address_new(uri);
if (from!=NULL){
displayname=linphone_address_get_display_name(from);
id=linphone_address_as_string_uri_only(from);
}else id=ms_strdup(uri);
if (displayname!=NULL){
uri_label=g_markup_printf_escaped("<span size=\"large\">%s</span>\n<i>%s</i>",
displayname,id);
}else
uri_label=g_markup_printf_escaped("<span size=\"large\"><i>%s</i></span>\n",id);
gtk_label_set_markup(GTK_LABEL(label),uri_label);
ms_free(id);
g_free(uri_label);
if (from!=NULL) linphone_address_destroy(from);
}
void linphone_gtk_in_call_view_set_calling(const char *uri){
GtkWidget *main_window=linphone_gtk_get_main_window();
GtkWidget *status=linphone_gtk_get_widget(main_window,"in_call_status");
GtkWidget *callee=linphone_gtk_get_widget(main_window,"in_call_uri");
GtkWidget *duration=linphone_gtk_get_widget(main_window,"in_call_duration");
GtkWidget *animation=linphone_gtk_get_widget(main_window,"in_call_animation");
GdkPixbufAnimation *pbuf=create_pixbuf_animation("calling_anim.gif");
gtk_label_set_markup(GTK_LABEL(status),_("<b>Calling...</b>"));
display_peer_name_in_label(callee,uri);
gtk_label_set_text(GTK_LABEL(duration),_("00::00::00"));
if (pbuf!=NULL){
gtk_image_set_from_animation(GTK_IMAGE(animation),pbuf);
g_object_unref(G_OBJECT(pbuf));
}else gtk_image_set_from_stock(GTK_IMAGE(animation),GTK_STOCK_INFO,GTK_ICON_SIZE_DIALOG);
}
void linphone_gtk_in_call_view_set_in_call(){
LinphoneCore *lc=linphone_gtk_get_core();
GtkWidget *main_window=linphone_gtk_get_main_window();
GtkWidget *status=linphone_gtk_get_widget(main_window,"in_call_status");
GtkWidget *callee=linphone_gtk_get_widget(main_window,"in_call_uri");
GtkWidget *duration=linphone_gtk_get_widget(main_window,"in_call_duration");
GtkWidget *animation=linphone_gtk_get_widget(main_window,"in_call_animation");
GdkPixbufAnimation *pbuf=create_pixbuf_animation("incall_anim.gif");
const LinphoneAddress *uri=linphone_core_get_remote_uri(lc);
char *tmp=linphone_address_as_string(uri);
display_peer_name_in_label(callee,tmp);
ms_free(tmp);
gtk_label_set_markup(GTK_LABEL(status),_("<b>In call with</b>"));
gtk_label_set_text(GTK_LABEL(duration),_("00::00::00"));
if (pbuf!=NULL){
gtk_image_set_from_animation(GTK_IMAGE(animation),pbuf);
g_object_unref(G_OBJECT(pbuf));
}else gtk_image_set_from_stock(GTK_IMAGE(animation),GTK_STOCK_INFO,GTK_ICON_SIZE_DIALOG);
linphone_gtk_enable_mute_button(
GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(main_window,"incall_mute")),TRUE);
}
void linphone_gtk_in_call_view_update_duration(int duration){
GtkWidget *main_window=linphone_gtk_get_main_window();
GtkWidget *duration_label=linphone_gtk_get_widget(main_window,"in_call_duration");
char tmp[256]={0};
int seconds=duration%60;
int minutes=(duration/60)%60;
int hours=duration/3600;
snprintf(tmp,sizeof(tmp)-1,_("%02i::%02i::%02i"),hours,minutes,seconds);
gtk_label_set_text(GTK_LABEL(duration_label),tmp);
}
static gboolean in_call_view_terminated(){
linphone_gtk_show_idle_view();
return FALSE;
}
void linphone_gtk_in_call_view_terminate(const char *error_msg){
GtkWidget *main_window=linphone_gtk_get_main_window();
GtkWidget *status=linphone_gtk_get_widget(main_window,"in_call_status");
GtkWidget *animation=linphone_gtk_get_widget(main_window,"in_call_animation");
GdkPixbuf *pbuf=create_pixbuf(linphone_gtk_get_ui_config("stop_call_icon","stopcall-red.png"));
if (error_msg==NULL)
gtk_label_set_markup(GTK_LABEL(status),_("<b>Call ended.</b>"));
else{
char *msg=g_markup_printf_escaped("<span color=\"red\"><b>%s</b></span>",error_msg);
gtk_label_set_markup(GTK_LABEL(status),msg);
g_free(msg);
}
if (pbuf!=NULL){
gtk_image_set_from_pixbuf(GTK_IMAGE(animation),pbuf);
g_object_unref(G_OBJECT(pbuf));
}
linphone_gtk_enable_mute_button(
GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(main_window,"incall_mute")),FALSE);
g_timeout_add_seconds(2,(GSourceFunc)in_call_view_terminated,NULL);
}
void linphone_gtk_draw_mute_button(GtkToggleButton *button, gboolean active){
if (active){
GtkWidget *image=create_pixmap("mic_muted.png");
gtk_button_set_label(GTK_BUTTON(button),_("Unmute"));
if (image!=NULL) {
gtk_button_set_image(GTK_BUTTON(button),image);
gtk_widget_show(image);
}
}else{
GtkWidget *image=create_pixmap("mic_active.png");
gtk_button_set_label(GTK_BUTTON(button),_("Mute"));
if (image!=NULL) {
gtk_button_set_image(GTK_BUTTON(button),image);
gtk_widget_show(image);
}
}
}
void linphone_gtk_mute_toggled(GtkToggleButton *button){
gboolean active=gtk_toggle_button_get_active(button);
linphone_core_mute_mic(linphone_gtk_get_core(),active);
linphone_gtk_draw_mute_button(button,active);
}
void linphone_gtk_enable_mute_button(GtkToggleButton *button, gboolean sensitive){
gtk_widget_set_sensitive(GTK_WIDGET(button),sensitive);
linphone_gtk_draw_mute_button(button,FALSE);
}

View file

@ -1,15 +1,14 @@
GLADE_FILES= about.glade \
main.glade \
password.glade \
contact.glade \
incoming_call.glade \
parameters.glade \
sip_account.glade \
chatroom.glade \
call_logs.glade \
log.glade \
buddylookup.glade \
waiting.glade
UI_FILES= about.ui \
main.ui \
password.ui \
contact.ui \
parameters.ui \
sip_account.ui \
chatroom.ui \
call_logs.ui \
log.ui \
buddylookup.ui \
waiting.ui
PIXMAPS= \
stock_people.png
@ -18,13 +17,13 @@ LINPHONE_ICO_RC_FILE=linphone.rc
LINPHONE_ICO_FILE=linphone.ico
EXTRA_DIST= $(PIXMAPS) \
$(GLADE_FILES) \
$(UI_FILES) \
linphone.iss \
$(LINPHONE_ICO_RC_FILE) \
$(LINPHONE_ICO_FILE)
if BUILD_GLADE_UI
if BUILD_GTK_UI
BUILT_SOURCES=version_date.h
@ -46,11 +45,10 @@ linphone_3_SOURCES= \
loginframe.c \
linphone.h
linphone_3_LDADD=$(top_builddir)/oRTP/src/libortp.la \
$(top_builddir)/mediastreamer2/src/libmediastreamer.la \
linphone_3_LDADD=$(ORTP_LIBS) \
$(MEDIASTREAMER_LIBS) \
$(top_builddir)/coreapi/liblinphone.la \
$(LIBGTK_LIBS) $(INTLLIBS) \
$(LIBGLADE_LIBS)
$(LIBGTK_LIBS) $(INTLLIBS)
if BUILD_WIN32
@ -64,25 +62,20 @@ else
linphone_3_LDFLAGS=-export-dynamic
endif
gladedir=$(datadir)/linphone
glade_DATA=$(GLADE_FILES) $(PIXMAPS) $(top_srcdir)/COPYING
#all-local: gtk-linphone.ui
#gtk-linphone.ui: gtk-linphone.glade
# gtk-builder-convert gtk-linphone.glade $@
uidir=$(datadir)/linphone
ui_DATA=$(UI_FILES) $(PIXMAPS) $(top_srcdir)/COPYING
endif
AM_CFLAGS= -DIN_LINPHONE -I$(top_srcdir)/coreapi/ \
-I$(top_srcdir)/mediastreamer2/include/ \
$(MEDIASTREAMER_CFLAGS) \
$(ORTP_CFLAGS) \
$(LIBGLADE_CFLAGS) $(STRICT_OPTIONS) $(LIBGTK_CFLAGS) $(IPV6_CFLAGS) \
$(STRICT_OPTIONS) $(LIBGTK_CFLAGS) $(IPV6_CFLAGS) \
$(OSIP_CFLAGS)
version_date.h: $(top_srcdir)/configure.in
version_date.h: $(top_srcdir)/configure.ac
echo "#define LINPHONE_VERSION_DATE \"$(VERSION)-`date +%y%m%d`\"" > $@
newdate:

View file

@ -1,19 +1,18 @@
<?xml version="1.0"?>
<glade-interface>
<interface>
<!-- interface-requires gtk+ 2.12 -->
<!-- interface-naming-policy toplevel-contextual -->
<widget class="GtkAboutDialog" id="about">
<object class="GtkAboutDialog" id="about">
<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">About linphone</property>
<property name="resizable">False</property>
<property name="window_position">center-on-parent</property>
<property name="icon">linphone2.png</property>
<property name="type_hint">dialog</property>
<property name="has_separator">False</property>
<property name="program_name">Linphone</property>
<property name="version">undef</property>
<property name="copyright" translatable="yes">Created by Simon Morlat
<property name="copyright" translatable="yes">(C) Belledonne Communications,2010
</property>
<property name="comments" translatable="yes">An internet video phone using the standard SIP (rfc3261) protocol.</property>
<property name="website">http://www.linphone.org</property>
@ -35,7 +34,7 @@ hu: anonymous
<property name="artists">Icons by kerosine.fr</property>
<signal name="response" handler="linphone_gtk_about_response"/>
<child internal-child="vbox">
<widget class="GtkVBox" id="dialog-vbox8">
<object class="GtkVBox" id="dialog-vbox8">
<property name="visible">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="orientation">vertical</property>
@ -44,18 +43,18 @@ hu: anonymous
<placeholder/>
</child>
<child internal-child="action_area">
<widget class="GtkHButtonBox" id="dialog-action_area7">
<object class="GtkHButtonBox" id="dialog-action_area7">
<property name="visible">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="layout_style">end</property>
</widget>
</object>
<packing>
<property name="expand">False</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
</widget>
</object>
</child>
</widget>
</glade-interface>
</object>
</interface>

View file

@ -1,94 +1,94 @@
<?xml version="1.0"?>
<glade-interface>
<interface>
<!-- interface-requires gtk+ 2.16 -->
<!-- interface-naming-policy toplevel-contextual -->
<widget class="GtkDialog" id="buddylookup">
<object class="GtkDialog" id="buddylookup">
<property name="border_width">5</property>
<property name="title" translatable="yes">Search contacts in directory</property>
<property name="window_position">center-on-parent</property>
<property name="icon">linphone2.png</property>
<property name="type_hint">dialog</property>
<property name="has_separator">False</property>
<signal name="response" handler="gtk_widget_destroy"/>
<signal handler="gtk_widget_destroy" name="response"/>
<child internal-child="vbox">
<widget class="GtkVBox" id="dialog-vbox1">
<object class="GtkVBox" id="dialog-vbox1">
<property name="visible">True</property>
<property name="spacing">2</property>
<child>
<widget class="GtkFrame" id="frame1">
<object class="GtkFrame" id="frame1">
<property name="visible">True</property>
<property name="border_width">5</property>
<property name="label_xalign">0</property>
<child>
<widget class="GtkAlignment" id="alignment1">
<object class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkVBox" id="vbox2">
<object class="GtkVBox" id="vbox2">
<property name="visible">True</property>
<child>
<widget class="GtkEntry" id="keyword">
<object class="GtkEntry" id="keyword">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="has_focus">True</property>
<signal name="changed" handler="linphone_gtk_keyword_changed"/>
</widget>
<signal handler="linphone_gtk_keyword_changed" name="changed"/>
</object>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkScrolledWindow" id="scrolledwindow1">
<object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">automatic</property>
<property name="vscrollbar_policy">automatic</property>
<property name="shadow_type">etched-in</property>
<child>
<widget class="GtkTreeView" id="search_results">
<object class="GtkTreeView" id="search_results">
<property name="width_request">512</property>
<property name="height_request">140</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<signal name="row_activated" handler="linphone_gtk_buddy_lookup_contact_activated"/>
</widget>
<signal handler="linphone_gtk_buddy_lookup_contact_activated" name="row_activated"/>
</object>
</child>
</widget>
</object>
<packing>
<property name="padding">6</property>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkProgressBar" id="progressbar">
<object class="GtkProgressBar" id="progressbar">
<property name="visible">True</property>
<property name="activity_mode">True</property>
<property name="show_text">True</property>
</widget>
</object>
<packing>
<property name="expand">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<widget class="GtkHButtonBox" id="hbuttonbox1">
<object class="GtkHButtonBox" id="hbuttonbox1">
<property name="visible">True</property>
<child>
<widget class="GtkButton" id="add_buddy">
<object class="GtkButton" id="add_buddy">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="linphone_gtk_add_buddy_from_database"/>
<signal handler="linphone_gtk_add_buddy_from_database" name="clicked"/>
<child>
<widget class="GtkHBox" id="hbox1">
<object class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<child>
<widget class="GtkImage" id="image1">
<object class="GtkImage" id="image1">
<property name="visible">True</property>
<property name="stock">gtk-add</property>
</widget>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
@ -96,17 +96,17 @@
</packing>
</child>
<child>
<widget class="GtkLabel" id="label2">
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="label" translatable="yes">Add to my list</property>
</widget>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
</object>
</child>
</widget>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
@ -114,34 +114,31 @@
<property name="position">0</property>
</packing>
</child>
</widget>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">3</property>
</packing>
</child>
</widget>
</object>
</child>
</widget>
</object>
</child>
<child>
<widget class="GtkLabel" id="label1">
<child type="label">
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;b&gt;Search somebody&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="type">label_item</property>
</packing>
</object>
</child>
</widget>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child internal-child="action_area">
<widget class="GtkHButtonBox" id="dialog-action_area1">
<object class="GtkHButtonBox" id="dialog-action_area1">
<property name="visible">True</property>
<property name="layout_style">end</property>
<child>
@ -150,14 +147,14 @@
<child>
<placeholder/>
</child>
</widget>
</object>
<packing>
<property name="expand">False</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
</widget>
</object>
</child>
</widget>
</glade-interface>
</object>
</interface>

109
gtk/call_logs.ui Normal file
View file

@ -0,0 +1,109 @@
<?xml version="1.0"?>
<interface>
<requires lib="gtk+" version="2.16"/>
<!-- interface-naming-policy toplevel-contextual -->
<object class="GtkListStore" id="call_logs_store">
<columns>
<!-- column-name icon -->
<column type="gchar"/>
<!-- column-name sipaddress -->
<column type="gchar"/>
</columns>
</object>
<object class="GtkDialog" id="call_logs">
<property name="width_request">500</property>
<property name="height_request">370</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Call history</property>
<property name="window_position">center-on-parent</property>
<property name="type_hint">dialog</property>
<property name="has_separator">False</property>
<child internal-child="vbox">
<object class="GtkVBox" id="dialog-vbox1">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">never</property>
<property name="vscrollbar_policy">automatic</property>
<child>
<object class="GtkTreeView" id="logs_view">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="headers_visible">False</property>
<signal name="row_activated" handler="linphone_gtk_history_row_activated"/>
</object>
</child>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child internal-child="action_area">
<object class="GtkHButtonBox" id="dialog-action_area1">
<property name="visible">True</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="button1">
<property name="label" translatable="yes">Clear all</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="image">image1</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="call_back_button">
<property name="label" translatable="yes">Call back</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="call_logs_close">
<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_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="2">button1</action-widget>
<action-widget response="1">call_back_button</action-widget>
<action-widget response="0">call_logs_close</action-widget>
</action-widgets>
</object>
<object class="GtkImage" id="image1">
<property name="visible">True</property>
<property name="stock">gtk-clear</property>
</object>
</interface>

131
gtk/calllogs.c Normal file
View file

@ -0,0 +1,131 @@
/*
linphone, gtk-glade interface.
Copyright (C) 2008 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 "linphone.h"
void linphone_gtk_call_log_update(GtkWidget *w){
GtkTreeView *v=GTK_TREE_VIEW(linphone_gtk_get_widget(w,"logs_view"));
GtkListStore *store;
const MSList *logs;
store=(GtkListStore*)gtk_tree_view_get_model(v);
if (store==NULL){
store=gtk_list_store_new(3,G_TYPE_STRING,G_TYPE_STRING, G_TYPE_POINTER);
gtk_tree_view_set_model(v,GTK_TREE_MODEL(store));
g_object_unref(G_OBJECT(store));
}
gtk_list_store_clear (store);
for (logs=linphone_core_get_call_logs(linphone_gtk_get_core());logs!=NULL;logs=logs->next){
LinphoneCallLog *cl=(LinphoneCallLog*)logs->data;
GtkTreeIter iter;
LinphoneAddress *la=cl->dir==LinphoneCallIncoming ? cl->from : cl->to;
char *addr= linphone_address_as_string_uri_only (la);
const char *display;
gchar *logtxt;
display=linphone_address_get_display_name (la);
if (display==NULL){
display=linphone_address_get_username (la);
if (display==NULL)
display=linphone_address_get_domain (la);
}
logtxt=g_markup_printf_escaped("<big><b>%s</b></big>\t<small><i>%s</i></small>\n"
"%s\t%i minutes %i seconds",display, addr, cl->start_date,
cl->duration/60,cl->duration%60);
gtk_list_store_append (store,&iter);
gtk_list_store_set (store,&iter,
0, cl->dir==LinphoneCallOutgoing ? GTK_STOCK_GO_UP : GTK_STOCK_GO_DOWN,
1, logtxt,2,la,-1);
ms_free(addr);
g_free(logtxt);
}
}
static bool_t put_selection_to_uribar(GtkWidget *treeview){
GtkTreeSelection *sel;
sel=gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
if (sel!=NULL){
GtkTreeModel *model=NULL;
GtkTreeIter iter;
if (gtk_tree_selection_get_selected (sel,&model,&iter)){
gpointer pla;
LinphoneAddress *la;
char *tmp;
gtk_tree_model_get(model,&iter,2,&pla,-1);
la=(LinphoneAddress*)pla;
tmp=linphone_address_as_string (la);
gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar")),tmp);
ms_free(tmp);
return TRUE;
}
}
return FALSE;
}
void linphone_gtk_history_row_activated(GtkWidget *treeview){
put_selection_to_uribar(treeview);
}
void linphone_gtk_call_log_response(GtkWidget *w, guint response_id){
GtkWidget *mw=linphone_gtk_get_main_window();
if (response_id==1){
if (put_selection_to_uribar(linphone_gtk_get_widget(w,"logs_view")))
linphone_gtk_start_call(linphone_gtk_get_widget(mw,"start_call"));
}else if (response_id==2){
linphone_core_clear_call_logs (linphone_gtk_get_core());
linphone_gtk_call_log_update(w);
return;
}
g_object_set_data(G_OBJECT(mw),"call_logs",NULL);
gtk_widget_destroy(w);
}
static void fill_renderers(GtkTreeView *v){
GtkTreeViewColumn *c;
GtkCellRenderer *r=gtk_cell_renderer_pixbuf_new ();
g_object_set(r,"stock-size",GTK_ICON_SIZE_BUTTON,NULL);
c=gtk_tree_view_column_new_with_attributes("icon",r,"stock-id",0,NULL);
gtk_tree_view_append_column (v,c);
r=gtk_cell_renderer_text_new ();
c=gtk_tree_view_column_new_with_attributes("sipaddress",r,"markup",1,NULL);
gtk_tree_view_append_column (v,c);
}
GtkWidget * linphone_gtk_show_call_logs(void){
GtkWidget *mw=linphone_gtk_get_main_window();
GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"call_logs");
if (w==NULL){
w=linphone_gtk_create_window("call_logs");
gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"call_back_button")),
create_pixmap (linphone_gtk_get_ui_config("callback_button","status-green.png")));
fill_renderers(GTK_TREE_VIEW(linphone_gtk_get_widget(w,"logs_view")));
g_object_set_data(G_OBJECT(mw),"call_logs",w);
g_signal_connect(G_OBJECT(w),"response",(GCallback)linphone_gtk_call_log_response,NULL);
gtk_widget_show(w);
linphone_gtk_call_log_update(w);
}else gtk_window_present(GTK_WINDOW(w));
return w;
}

View file

@ -94,13 +94,13 @@ void linphone_gtk_send_text(GtkWidget *button){
}
}
void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, const char *from, const char *message){
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){
w=linphone_gtk_init_chatroom(room,from);
w=linphone_gtk_init_chatroom(room,linphone_address_as_string_uri_only(from));
}
linphone_gtk_push_text(GTK_TEXT_VIEW(linphone_gtk_get_widget(w,"textlog")),
from,
linphone_address_as_string_uri_only(from),
message,FALSE);
gtk_window_present(GTK_WINDOW(w));
/*gtk_window_set_urgency_hint(GTK_WINDOW(w),TRUE);*/

View file

@ -1,69 +1,67 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
<?xml version="1.0"?>
<!--Generated with glade3 3.4.5 on Wed Jul 30 15:51:13 2008 -->
<glade-interface>
<widget class="GtkWindow" id="chatroom">
<signal name="destroy" handler="linphone_gtk_chat_destroyed"/>
<interface>
<object class="GtkWindow" id="chatroom">
<signal handler="linphone_gtk_chat_destroyed" name="destroy"/>
<child>
<widget class="GtkVBox" id="vbox1">
<object class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<child>
<widget class="GtkTextView" id="textlog">
<object class="GtkTextView" id="textlog">
<property name="width_request">200</property>
<property name="height_request">200</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="editable">False</property>
<property name="wrap_mode">GTK_WRAP_WORD</property>
</widget>
</object>
</child>
<child>
<widget class="GtkHBox" id="hbox1">
<object class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<child>
<widget class="GtkEntry" id="text_entry">
<object class="GtkEntry" id="text_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="has_focus">True</property>
<signal name="activate" handler="linphone_gtk_send_text"/>
</widget>
<signal handler="linphone_gtk_send_text" name="activate"/>
</object>
</child>
<child>
<widget class="GtkButton" id="send">
<object class="GtkButton" id="send">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="response_id">0</property>
<signal name="clicked" handler="linphone_gtk_send_text"/>
<signal handler="linphone_gtk_send_text" name="clicked"/>
<child>
<widget class="GtkHBox" id="hbox2">
<object class="GtkHBox" id="hbox2">
<property name="visible">True</property>
<child>
<widget class="GtkImage" id="image1">
<object class="GtkImage" id="image1">
<property name="visible">True</property>
<property name="stock">gtk-ok</property>
</widget>
</object>
</child>
<child>
<widget class="GtkLabel" id="label1">
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="label" translatable="yes">Send</property>
</widget>
</object>
<packing>
<property name="padding">7</property>
<property name="position">1</property>
</packing>
</child>
</widget>
</object>
</child>
</widget>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
@ -71,30 +69,29 @@
</packing>
</child>
<child>
<widget class="GtkHButtonBox" id="hbuttonbox1">
<object class="GtkHButtonBox" id="hbuttonbox1">
<property name="visible">True</property>
<property name="layout_style">GTK_BUTTONBOX_END</property>
<child>
<widget class="GtkButton" id="button1">
<object class="GtkButton" id="button1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="label" translatable="yes">gtk-close</property>
<property name="use_stock">True</property>
<property name="response_id">0</property>
<signal name="clicked" handler="linphone_gtk_chat_close"/>
</widget>
<signal handler="linphone_gtk_chat_close" name="clicked"/>
</object>
<packing>
<property name="pack_type">GTK_PACK_END</property>
</packing>
</child>
</widget>
</object>
<packing>
<property name="expand">False</property>
<property name="position">2</property>
</packing>
</child>
</widget>
</object>
</child>
</widget>
</glade-interface>
</object>
</interface>

View file

@ -1,8 +1,8 @@
<?xml version="1.0"?>
<glade-interface>
<interface>
<!-- interface-requires gtk+ 2.16 -->
<!-- interface-naming-policy toplevel-contextual -->
<widget class="GtkDialog" id="contact">
<object class="GtkDialog" id="contact">
<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="window_position">center-on-parent</property>
@ -10,46 +10,46 @@
<property name="type_hint">dialog</property>
<property name="has_separator">False</property>
<child internal-child="vbox">
<widget class="GtkVBox" id="dialog-vbox7">
<object class="GtkVBox" id="dialog-vbox7">
<property name="visible">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="spacing">2</property>
<child>
<widget class="GtkFrame" id="frame17">
<object class="GtkFrame" id="frame17">
<property name="visible">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="label_xalign">0</property>
<child>
<widget class="GtkAlignment" id="alignment17">
<object class="GtkAlignment" id="alignment17">
<property name="visible">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="left_padding">12</property>
<child>
<widget class="GtkVBox" id="vbox13">
<object class="GtkVBox" id="vbox13">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<widget class="GtkTable" id="table7">
<object class="GtkTable" id="table7">
<property name="visible">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="n_rows">2</property>
<property name="n_columns">2</property>
<child>
<widget class="GtkLabel" id="label45">
<object class="GtkLabel" id="label45">
<property name="visible">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="label" translatable="yes">Name</property>
</widget>
</object>
<packing>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label46">
<object class="GtkLabel" id="label46">
<property name="visible">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="label" translatable="yes">SIP Address</property>
</widget>
</object>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
@ -57,11 +57,11 @@
</packing>
</child>
<child>
<widget class="GtkEntry" id="name">
<object class="GtkEntry" id="name">
<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>
</widget>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
@ -69,11 +69,11 @@
</packing>
</child>
<child>
<widget class="GtkEntry" id="sip_address">
<object class="GtkEntry" id="sip_address">
<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>
</widget>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
@ -82,14 +82,14 @@
<property name="y_options">GTK_FILL</property>
</packing>
</child>
</widget>
</object>
<packing>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="show_presence">
<object class="GtkCheckButton" id="show_presence">
<property name="label" translatable="yes">Show this contact presence status</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
@ -97,13 +97,13 @@
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
</widget>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="allow_presence">
<object class="GtkCheckButton" id="allow_presence">
<property name="label" translatable="yes">Allow this contact to see my presence status</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
@ -111,46 +111,43 @@
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
</widget>
</object>
<packing>
<property name="position">2</property>
</packing>
</child>
</widget>
</object>
</child>
</widget>
</object>
</child>
<child>
<widget class="GtkLabel" id="label47">
<child type="label">
<object class="GtkLabel" id="label47">
<property name="visible">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="label" translatable="yes">&lt;b&gt;Contact information&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="type">label_item</property>
</packing>
</object>
</child>
</widget>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child internal-child="action_area">
<widget class="GtkHButtonBox" id="dialog-action_area7">
<object class="GtkHButtonBox" id="dialog-action_area7">
<property name="visible">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="layout_style">end</property>
<child>
<widget class="GtkButton" id="cancel_button">
<object class="GtkButton" id="cancel_button">
<property name="label" translatable="yes">gtk-cancel</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_stock">True</property>
<signal name="clicked" handler="linphone_gtk_contact_cancel"/>
</widget>
<signal handler="linphone_gtk_contact_cancel" name="clicked"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
@ -158,29 +155,29 @@
</packing>
</child>
<child>
<widget class="GtkButton" id="ok_button">
<object class="GtkButton" id="ok_button">
<property name="label" translatable="yes">gtk-ok</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_stock">True</property>
<signal name="clicked" handler="linphone_gtk_contact_ok"/>
</widget>
<signal handler="linphone_gtk_contact_ok" name="clicked"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
</object>
<packing>
<property name="expand">False</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
</widget>
</object>
</child>
</widget>
</glade-interface>
</object>
</interface>

View file

@ -39,18 +39,18 @@ typedef struct _status_picture_tab_t{
} status_picture_tab_t;
status_picture_tab_t status_picture_tab[]={
{ LINPHONE_STATUS_ONLINE, "status-green.png" },
{ LINPHONE_STATUS_BUSY, "status-orange.png" },
{ LINPHONE_STATUS_BERIGHTBACK, "status-orange.png" },
{ LINPHONE_STATUS_AWAY, "status-orange.png" },
{ LINPHONE_STATUS_ONTHEPHONE, "status-orange.png" },
{ LINPHONE_STATUS_OUTTOLUNCH, "status-orange.png" },
{ LINPHONE_STATUS_NOT_DISTURB, "status-red.png" },
{ LINPHONE_STATUS_MOVED, "status-orange.png" },
{ LINPHONE_STATUS_ALT_SERVICE, "status-orange.png" },
{ LINPHONE_STATUS_OFFLINE, "status-offline.png" },
{ LINPHONE_STATUS_PENDING, "status-offline.png" },
{ LINPHONE_STATUS_END, NULL },
{ LinphoneStatusOnline, "status-green.png" },
{ LinphoneStatusBusy, "status-orange.png" },
{ LinphoneStatusBeRightBack, "status-orange.png" },
{ LinphoneStatusAway, "status-orange.png" },
{ LinphoneStatusOnThePhone, "status-orange.png" },
{ LinphoneStatusOutToLunch, "status-orange.png" },
{ LinphoneStatusDoNotDisturb, "status-red.png" },
{ LinphoneStatusMoved, "status-orange.png" },
{ LinphoneStatusAltService, "status-orange.png" },
{ LinphoneStatusOffline, "status-offline.png" },
{ LinphoneStatusPending, "status-offline.png" },
{ LinphoneStatusEnd, NULL },
};
static GdkPixbuf *create_status_picture(LinphoneOnlineStatus ss){
@ -132,7 +132,7 @@ static GtkWidget * create_presence_menu(){
GdkPixbuf *pbuf;
status_picture_tab_t *t;
for(t=status_picture_tab;t->img!=NULL;++t){
if (t->status==LINPHONE_STATUS_PENDING){
if (t->status==LinphoneStatusPending){
continue;
}
menu_item=gtk_image_menu_item_new_with_label(linphone_online_status_to_string(t->status));
@ -317,7 +317,7 @@ void linphone_gtk_show_friends(void){
continue;
}
}
if (!online_only || (linphone_friend_get_status(lf)!=LINPHONE_STATUS_OFFLINE)){
if (!online_only || (linphone_friend_get_status(lf)!=LinphoneStatusOffline)){
BuddyInfo *bi;
if (name==NULL || name[0]=='\0') display=uri;
gtk_list_store_append(store,&iter);
@ -450,9 +450,12 @@ void linphone_gtk_contact_ok(GtkWidget *button){
linphone_gtk_display_something(GTK_MESSAGE_WARNING,_("Invalid sip contact !"));
return ;
}
linphone_friend_set_sip_addr(lf,fixed_uri);
LinphoneAddress* friend_address = linphone_address_new(fixed_uri);
linphone_address_set_display_name(friend_address,name);
linphone_friend_set_addr(lf,friend_address);
ms_free(fixed_uri);
linphone_friend_set_name(lf,name);
linphone_address_destroy(friend_address);
linphone_friend_send_subscribe(lf,show_presence);
linphone_friend_set_inc_subscribe_policy(lf,allow_presence==TRUE ? LinphoneSPAccept : LinphoneSPDeny);
if (linphone_friend_in_list(lf)) {

315
gtk/incall_view.c Normal file
View file

@ -0,0 +1,315 @@
/*
linphone, gtk-glade interface.
Copyright (C) 2009 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.
*/
/*
* C Implementation: incall_frame
*
* Description:
*
*
* Author: Simon Morlat <simon.morlat@linphone.org>, (C) 2009
*
*
*/
#include "linphone.h"
gboolean linphone_gtk_use_in_call_view(){
static int val=-1;
if (val==-1) val=linphone_gtk_get_ui_config_int("use_incall_view",1);
return val;
}
LinphoneCall *linphone_gtk_get_currently_displayed_call(){
LinphoneCore *lc=linphone_gtk_get_core();
GtkWidget *main_window=linphone_gtk_get_main_window ();
GtkNotebook *notebook=(GtkNotebook *)linphone_gtk_get_widget(main_window,"viewswitch");
const MSList *calls=linphone_core_get_calls(lc);
if (!linphone_gtk_use_in_call_view() || ms_list_size(calls)==1){
if (calls) return (LinphoneCall*)calls->data;
}else{
int idx=gtk_notebook_get_current_page (notebook);
GtkWidget *page=gtk_notebook_get_nth_page(notebook,idx);
if (page!=NULL){
LinphoneCall *call=(LinphoneCall*)g_object_get_data(G_OBJECT(page),"call");
return call;
}
}
return NULL;
}
static GtkWidget *make_tab_header(int number){
GtkWidget *w=gtk_hbox_new (FALSE,0);
GtkWidget *i=create_pixmap ("status-green.png");
GtkWidget *l;
gchar *text=g_strdup_printf("Call %i",number);
l=gtk_label_new (text);
gtk_box_pack_start (GTK_BOX(w),i,FALSE,FALSE,0);
gtk_box_pack_end(GTK_BOX(w),l,TRUE,TRUE,0);
gtk_widget_show_all(w);
return w;
}
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 ();
GtkNotebook *notebook=(GtkNotebook *)linphone_gtk_get_widget(main_window,"viewswitch");
static int call_index=1;
int idx;
if (ms_list_size(linphone_core_get_calls(linphone_gtk_get_core()))==1){
/*this is the only call at this time */
call_index=1;
}
g_object_set_data(G_OBJECT(call_view),"call",call);
linphone_call_set_user_pointer (call,call_view);
linphone_call_ref(call);
gtk_notebook_append_page (notebook,call_view,make_tab_header(call_index));
gtk_widget_show(call_view);
idx = gtk_notebook_page_num(notebook, call_view);
gtk_notebook_set_current_page(notebook, idx);
call_index++;
linphone_gtk_enable_hold_button (call,FALSE,TRUE);
linphone_gtk_enable_mute_button(
GTK_BUTTON(linphone_gtk_get_widget(call_view,"incall_mute")),FALSE);
}
void linphone_gtk_remove_in_call_view(LinphoneCall *call){
GtkWidget *w=(GtkWidget*)linphone_call_get_user_pointer (call);
GtkWidget *main_window=linphone_gtk_get_main_window ();
GtkWidget *nb=linphone_gtk_get_widget(main_window,"viewswitch");
int idx;
g_return_if_fail(w!=NULL);
idx=gtk_notebook_page_num(GTK_NOTEBOOK(nb),w);
gtk_notebook_remove_page (GTK_NOTEBOOK(nb),idx);
gtk_widget_destroy(w);
linphone_call_set_user_pointer (call,NULL);
linphone_call_unref(call);
gtk_notebook_set_current_page(GTK_NOTEBOOK(nb), 0);
}
static void display_peer_name_in_label(GtkWidget *label, const LinphoneAddress *from){
const char *displayname=NULL;
const char *id;
char *uri_label;
displayname=linphone_address_get_display_name(from);
id=linphone_address_as_string_uri_only(from);
if (displayname!=NULL){
uri_label=g_markup_printf_escaped("<span size=\"large\">%s</span>\n<i>%s</i>",
displayname,id);
}else
uri_label=g_markup_printf_escaped("<span size=\"large\"><i>%s</i></span>\n",id);
gtk_label_set_markup(GTK_LABEL(label),uri_label);
g_free(uri_label);
}
void linphone_gtk_in_call_view_set_calling(LinphoneCall *call){
GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call);
GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status");
GtkWidget *callee=linphone_gtk_get_widget(callview,"in_call_uri");
GtkWidget *duration=linphone_gtk_get_widget(callview,"in_call_duration");
GtkWidget *animation=linphone_gtk_get_widget(callview,"in_call_animation");
GdkPixbufAnimation *pbuf=create_pixbuf_animation("calling_anim.gif");
gtk_label_set_markup(GTK_LABEL(status),_("<b>Calling...</b>"));
display_peer_name_in_label(callee,linphone_call_get_remote_address (call));
gtk_label_set_text(GTK_LABEL(duration),_("00::00::00"));
if (pbuf!=NULL){
gtk_image_set_from_animation(GTK_IMAGE(animation),pbuf);
g_object_unref(G_OBJECT(pbuf));
}else gtk_image_set_from_stock(GTK_IMAGE(animation),GTK_STOCK_FIND,GTK_ICON_SIZE_DIALOG);
}
void linphone_gtk_in_call_view_set_incoming(LinphoneCall *call, bool_t with_pause){
GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call);
GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status");
GtkWidget *callee=linphone_gtk_get_widget(callview,"in_call_uri");
GtkWidget *animation=linphone_gtk_get_widget(callview,"in_call_animation");
GdkPixbufAnimation *pbuf=create_pixbuf_animation("calling_anim.gif");
GtkWidget *answer_button;
gtk_label_set_markup(GTK_LABEL(status),_("<b>Incoming call</b>"));
gtk_widget_show_all(linphone_gtk_get_widget(callview,"answer_decline_panel"));
gtk_widget_hide(linphone_gtk_get_widget(callview,"duration_frame"));
gtk_widget_hide(linphone_gtk_get_widget(callview,"mute_pause_buttons"));
display_peer_name_in_label(callee,linphone_call_get_remote_address (call));
answer_button=linphone_gtk_get_widget(callview,"accept_call");
gtk_button_set_image(GTK_BUTTON(answer_button),
create_pixmap (linphone_gtk_get_ui_config("start_call_icon","startcall-green.png")));
if (with_pause){
gtk_button_set_label(GTK_BUTTON(answer_button),
_("Pause all calls\nand answer"));
}else gtk_button_set_label(GTK_BUTTON(answer_button),_("Answer"));
gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(callview,"decline_call")),
create_pixmap (linphone_gtk_get_ui_config("stop_call_icon","stopcall-red.png")));
if (pbuf!=NULL){
gtk_image_set_from_animation(GTK_IMAGE(animation),pbuf);
g_object_unref(G_OBJECT(pbuf));
}else gtk_image_set_from_stock(GTK_IMAGE(animation),GTK_STOCK_EXECUTE,GTK_ICON_SIZE_DIALOG);
}
void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){
GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call);
GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status");
GtkWidget *callee=linphone_gtk_get_widget(callview,"in_call_uri");
GtkWidget *duration=linphone_gtk_get_widget(callview,"in_call_duration");
GtkWidget *animation=linphone_gtk_get_widget(callview,"in_call_animation");
GdkPixbufAnimation *pbuf=create_pixbuf_animation("incall_anim.gif");
display_peer_name_in_label(callee,linphone_call_get_remote_address (call));
gtk_widget_show(linphone_gtk_get_widget(callview,"duration_frame"));
gtk_widget_show(linphone_gtk_get_widget(callview,"mute_pause_buttons"));
gtk_widget_hide(linphone_gtk_get_widget(callview,"answer_decline_panel"));
gtk_label_set_markup(GTK_LABEL(status),_("<b>In call</b>"));
gtk_label_set_text(GTK_LABEL(duration),_("00::00::00"));
if (pbuf!=NULL){
gtk_image_set_from_animation(GTK_IMAGE(animation),pbuf);
g_object_unref(G_OBJECT(pbuf));
}else gtk_image_set_from_stock(GTK_IMAGE(animation),GTK_STOCK_EXECUTE,GTK_ICON_SIZE_DIALOG);
linphone_gtk_enable_mute_button(
GTK_BUTTON(linphone_gtk_get_widget(callview,"incall_mute")),TRUE);
}
void linphone_gtk_in_call_view_set_paused(LinphoneCall *call){
GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call);
GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status");
GtkWidget *animation=linphone_gtk_get_widget(callview,"in_call_animation");
gtk_widget_hide(linphone_gtk_get_widget(callview,"answer_decline_panel"));
gtk_label_set_markup(GTK_LABEL(status),_("<b>Paused call</b>"));
gtk_image_set_from_stock(GTK_IMAGE(animation),GTK_STOCK_MEDIA_PAUSE,GTK_ICON_SIZE_DIALOG);
}
void linphone_gtk_in_call_view_update_duration(LinphoneCall *call){
GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call);
GtkWidget *duration_label=linphone_gtk_get_widget(callview,"in_call_duration");
int duration=linphone_call_get_duration(call);
char tmp[256]={0};
int seconds=duration%60;
int minutes=(duration/60)%60;
int hours=duration/3600;
snprintf(tmp,sizeof(tmp)-1,_("%02i::%02i::%02i"),hours,minutes,seconds);
gtk_label_set_text(GTK_LABEL(duration_label),tmp);
}
static gboolean in_call_view_terminated(LinphoneCall *call){
linphone_gtk_remove_in_call_view(call);
return FALSE;
}
void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_msg){
GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call);
GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status");
GtkWidget *animation=linphone_gtk_get_widget(callview,"in_call_animation");
GdkPixbuf *pbuf=create_pixbuf(linphone_gtk_get_ui_config("stop_call_icon","stopcall-red.png"));
if (error_msg==NULL)
gtk_label_set_markup(GTK_LABEL(status),_("<b>Call ended.</b>"));
else{
char *msg=g_markup_printf_escaped("<span color=\"red\"><b>%s</b></span>",error_msg);
gtk_label_set_markup(GTK_LABEL(status),msg);
g_free(msg);
}
if (pbuf!=NULL){
gtk_image_set_from_pixbuf(GTK_IMAGE(animation),pbuf);
g_object_unref(G_OBJECT(pbuf));
}
gtk_widget_hide(linphone_gtk_get_widget(callview,"answer_decline_panel"));
linphone_gtk_enable_mute_button(
GTK_BUTTON(linphone_gtk_get_widget(callview,"incall_mute")),FALSE);
linphone_gtk_enable_hold_button(call,FALSE,TRUE);
g_timeout_add_seconds(2,(GSourceFunc)in_call_view_terminated,call);
}
void linphone_gtk_draw_mute_button(GtkButton *button, gboolean active){
g_object_set_data(G_OBJECT(button),"active",GINT_TO_POINTER(active));
if (active){
GtkWidget *image=create_pixmap("mic_muted.png");
gtk_button_set_label(GTK_BUTTON(button),_("Unmute"));
if (image!=NULL) {
gtk_button_set_image(GTK_BUTTON(button),image);
gtk_widget_show(image);
}
}else{
GtkWidget *image=create_pixmap("mic_active.png");
gtk_button_set_label(GTK_BUTTON(button),_("Mute"));
if (image!=NULL) {
gtk_button_set_image(GTK_BUTTON(button),image);
gtk_widget_show(image);
}
}
}
void linphone_gtk_mute_clicked(GtkButton *button){
int active=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button),"active"));
linphone_core_mute_mic(linphone_gtk_get_core(),!active);
linphone_gtk_draw_mute_button(button,!active);
}
void linphone_gtk_enable_mute_button(GtkButton *button, gboolean sensitive)
{
gtk_widget_set_sensitive(GTK_WIDGET(button),sensitive);
linphone_gtk_draw_mute_button(button,FALSE);
}
void linphone_gtk_draw_hold_button(GtkButton *button, gboolean active){
g_object_set_data(G_OBJECT(button),"active",GINT_TO_POINTER(active));
if (active){
GtkWidget *image=create_pixmap("hold_off.png");
gtk_button_set_label(GTK_BUTTON(button),_("Resume"));
if (image!=NULL) {
gtk_button_set_image(GTK_BUTTON(button),image);
gtk_widget_show(image);
}
}else{
GtkWidget *image=create_pixmap("hold_on.png");
gtk_button_set_label(GTK_BUTTON(button),_("Pause"));
if (image!=NULL) {
gtk_button_set_image(GTK_BUTTON(button),image);
gtk_widget_show(image);
}
}
}
void linphone_gtk_hold_clicked(GtkButton *button){
int active=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button),"active"));
LinphoneCall *call=linphone_gtk_get_currently_displayed_call ();
if(!active)
{
linphone_core_pause_call(linphone_gtk_get_core(),call);
}
else
{
linphone_core_resume_call(linphone_gtk_get_core(),call);
}
}
void linphone_gtk_enable_hold_button(LinphoneCall *call, gboolean sensitive, gboolean holdon){
GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer (call);
GtkWidget *button;
g_return_if_fail(callview!=NULL);
button=linphone_gtk_get_widget(callview,"hold_call");
gtk_widget_set_sensitive(GTK_WIDGET(button),sensitive);
linphone_gtk_draw_hold_button(GTK_BUTTON(button),!holdon);
}

View file

@ -1,8 +1,8 @@
<?xml version="1.0"?>
<glade-interface>
<interface>
<!-- interface-requires gtk+ 2.16 -->
<!-- interface-naming-policy toplevel-contextual -->
<widget class="GtkDialog" id="incoming_call">
<object class="GtkDialog" id="incoming_call">
<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="type">popup</property>
@ -13,84 +13,81 @@
<property name="urgency_hint">True</property>
<property name="deletable">False</property>
<child internal-child="vbox">
<widget class="GtkVBox" id="dialog-vbox8">
<object class="GtkVBox" id="dialog-vbox8">
<property name="visible">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="spacing">2</property>
<child>
<widget class="GtkFrame" id="frame16">
<object class="GtkFrame" id="frame16">
<property name="visible">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="label_xalign">0</property>
<child>
<widget class="GtkAlignment" id="alignment16">
<object class="GtkAlignment" id="alignment16">
<property name="visible">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="left_padding">12</property>
<child>
<widget class="GtkLabel" id="message">
<object class="GtkLabel" id="message">
<property name="visible">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="label" translatable="yes">Incoming call from</property>
</widget>
</object>
</child>
</widget>
</object>
</child>
<child>
<widget class="GtkLabel" id="label43">
<child type="label">
<object class="GtkLabel" id="label43">
<property name="visible">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="label" translatable="yes">Incoming call</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="type">label_item</property>
</packing>
</object>
</child>
</widget>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child internal-child="action_area">
<widget class="GtkHButtonBox" id="dialog-action_area7">
<object class="GtkHButtonBox" id="dialog-action_area7">
<property name="visible">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="layout_style">spread</property>
<child>
<widget class="GtkButton" id="accept_call">
<object class="GtkButton" id="accept_call">
<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>
<signal name="clicked" handler="linphone_gtk_accept_call"/>
<signal handler="linphone_gtk_accept_call" name="clicked"/>
<child>
<widget class="GtkHBox" id="hbox17">
<object class="GtkHBox" id="hbox17">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<widget class="GtkImage" id="image12">
<object class="GtkImage" id="image12">
<property name="visible">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="stock">gtk-yes</property>
</widget>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label44">
<object class="GtkLabel" id="label44">
<property name="visible">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="label" translatable="yes">Accept</property>
</widget>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
</object>
</child>
</widget>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
@ -98,53 +95,53 @@
</packing>
</child>
<child>
<widget class="GtkButton" id="decline_cal">
<object class="GtkButton" id="decline_cal">
<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>
<signal name="clicked" handler="linphone_gtk_decline_call"/>
<signal handler="linphone_gtk_decline_call" name="clicked"/>
<child>
<widget class="GtkHBox" id="hbox20">
<object class="GtkHBox" id="hbox20">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<widget class="GtkImage" id="image13">
<object class="GtkImage" id="image13">
<property name="visible">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="stock">gtk-no</property>
</widget>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="decline_call">
<object class="GtkLabel" id="decline_call">
<property name="visible">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="label" translatable="yes">Decline</property>
</widget>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
</object>
</child>
</widget>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
</object>
<packing>
<property name="expand">False</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
</widget>
</object>
</child>
</widget>
</glade-interface>
</object>
</interface>

View file

@ -48,6 +48,8 @@ GdkPixbuf *_gdk_pixbuf_new_from_memory_at_scale(const void *data, gint len, gint
GtkWidget *linphone_gtk_create_window(const char *window_name);
GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name);
GtkWidget *linphone_gtk_create_widget(const char *filename, const char *widget_name);
LinphoneCore *linphone_gtk_get_core(void);
GtkWidget *linphone_gtk_get_main_window();
void linphone_gtk_display_something(GtkMessageType type,const gchar *message);
@ -59,7 +61,7 @@ void linphone_gtk_set_my_presence(LinphoneOnlineStatus ss);
void linphone_gtk_show_parameters(void);
void linphone_gtk_load_identities(void);
void linphone_gtk_create_chatroom(const char *with);
void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, const char *from, const char *message);
void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from, const char *message);
void linphone_gtk_call_log_update(GtkWidget *w);
void linphone_gtk_create_log_window(void);
void linphone_gtk_log_show(void);
@ -85,13 +87,17 @@ void linphone_gtk_show_directory_search(void);
/*functions controlling the different views*/
gboolean linphone_gtk_use_in_call_view();
void linphone_gtk_show_in_call_view(void);
void linphone_gtk_show_idle_view(void);
void linphone_gtk_in_call_view_set_calling(const char *uri);
void linphone_gtk_in_call_view_set_in_call(void);
void linphone_gtk_in_call_view_update_duration(int duration);
void linphone_gtk_in_call_view_terminate(const char *error_msg);
void linphone_gtk_enable_mute_button(GtkToggleButton *button, gboolean sensitive);
LinphoneCall *linphone_gtk_get_currently_displayed_call();
void linphone_gtk_create_in_call_view(LinphoneCall *call);
void linphone_gtk_in_call_view_set_calling(LinphoneCall *call);
void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call);
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, bool_t with_pause);
void linphone_gtk_in_call_view_set_paused(LinphoneCall *call);
void linphone_gtk_enable_mute_button(GtkButton *button, gboolean sensitive);
void linphone_gtk_enable_hold_button(LinphoneCall *call, gboolean sensitive, gboolean holdon);
void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg);
void linphone_gtk_exit_login_frame(void);
void linphone_gtk_set_ui_config(const char *key, const char *value);

View file

Before

Width:  |  Height:  |  Size: 95 KiB

After

Width:  |  Height:  |  Size: 95 KiB

View file

@ -1,24 +1,24 @@
<?xml version="1.0"?>
<glade-interface>
<!-- interface-requires gtk+ 2.16 -->
<interface>
<requires lib="gtk+" version="2.16"/>
<!-- interface-naming-policy toplevel-contextual -->
<widget class="GtkDialog" id="log">
<object class="GtkDialog" id="log">
<property name="width_request">540</property>
<property name="height_request">290</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Linphone debug window</property>
<property name="window_position">center-on-parent</property>
<property name="icon">linphone2.png</property>
<property name="type_hint">dialog</property>
<property name="type_hint">normal</property>
<property name="deletable">False</property>
<property name="has_separator">False</property>
<signal name="response" handler="gtk_widget_hide"/>
<child internal-child="vbox">
<widget class="GtkVBox" id="dialog-vbox1">
<object class="GtkVBox" id="dialog-vbox1">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child>
<widget class="GtkScrolledWindow" id="scrolledwindow1">
<object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">never</property>
@ -27,48 +27,51 @@
<property name="window_placement_set">True</property>
<property name="shadow_type">in</property>
<child>
<widget class="GtkTextView" id="textview">
<object class="GtkTextView" id="textview">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="editable">False</property>
<property name="wrap_mode">word</property>
</widget>
</object>
</child>
</widget>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child internal-child="action_area">
<widget class="GtkHButtonBox" id="dialog-action_area1">
<object class="GtkHButtonBox" id="dialog-action_area1">
<property name="visible">True</property>
<property name="layout_style">end</property>
<child>
<placeholder/>
</child>
<child>
<widget class="GtkButton" id="button1">
<property name="label" translatable="yes">gtk-close</property>
<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_stock">True</property>
<signal name="clicked" handler="linphone_gtk_log_hide"/>
</widget>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
</object>
<packing>
<property name="expand">False</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
</widget>
</object>
</child>
</widget>
</glade-interface>
<action-widgets>
<action-widget response="0">button1</action-widget>
</action-widgets>
</object>
</interface>

View file

@ -213,14 +213,6 @@ static void linphone_gtk_log_file(OrtpLogLevel lev, const char *msg)
}
}
static gboolean delete_event_cb (GtkWidget *widget, GdkEvent *event, gpointer data)
{
gtk_widget_hide (widget);
return TRUE;
}
void linphone_gtk_log_hide(){
if (log_window)
gtk_widget_hide(log_window);
@ -234,7 +226,7 @@ void linphone_gtk_create_log_window(void){
gtk_text_buffer_create_tag(b,"orange","foreground","orange",NULL);
/*prevent the log window from being destroyed*/
g_signal_connect (G_OBJECT (log_window), "delete-event",
G_CALLBACK (delete_event_cb), NULL);
G_CALLBACK (gtk_widget_hide_on_delete), log_window);
}

View file

@ -27,28 +27,28 @@ enum {
NetworkKindOpticalFiber
};
static gboolean check_login_ok(LinphoneProxyConfig *cfg){
if (linphone_proxy_config_is_registered(cfg)){
linphone_gtk_exit_login_frame();
return FALSE;
}
return TRUE;
}
static void do_login(SipSetupContext *ssctx, const char *identity, const char * passwd){
GtkWidget *mw=linphone_gtk_get_main_window();
if (sip_setup_context_login_account(ssctx,identity,passwd)==0){
guint t=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(mw),"login_tout"));
if (t!=0) g_source_remove(t);
t=g_timeout_add(50,(GSourceFunc)check_login_ok,sip_setup_context_get_proxy_config(ssctx));
g_object_set_data(G_OBJECT(mw),"login_tout",GINT_TO_POINTER(t));
}
}
static gboolean do_login_noprompt(LinphoneProxyConfig *cfg){
SipSetupContext *ssctx=linphone_proxy_config_get_sip_setup_context(cfg);
LinphoneAddress *addr;
const char *username;
char *tmp;
if (ssctx==NULL) return TRUE;/*not ready ?*/
do_login(ssctx,linphone_proxy_config_get_identity(cfg),NULL);
username=linphone_gtk_get_ui_config ("login_username",NULL);
if (username==NULL) {
linphone_gtk_set_ui_config_int("automatic_login",0);
linphone_gtk_show_login_frame(cfg);
return FALSE;
}
addr=linphone_address_new(linphone_proxy_config_get_identity(cfg));
linphone_address_set_username(addr,username);
tmp=linphone_address_as_string (addr);
do_login(ssctx,tmp,NULL);
linphone_address_destroy(addr);
return FALSE;
}
@ -75,17 +75,32 @@ void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg){
return;
}
gtk_widget_hide(linphone_gtk_get_widget(mw,"logout"));
gtk_widget_hide(linphone_gtk_get_widget(mw,"idle_frame"));
{
const char *login_image=linphone_gtk_get_ui_config("login_image",NULL);
if (login_image){
GdkPixbuf *pbuf=create_pixbuf (login_image);
gtk_image_set_from_pixbuf (GTK_IMAGE(linphone_gtk_get_widget(mw,"login_image")),
pbuf);
g_object_unref(G_OBJECT(pbuf));
}
}
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,"modes"),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);
g_object_set_data(G_OBJECT(mw),"login_proxy_config",cfg);
g_free(str);
from=linphone_address_new(linphone_proxy_config_get_identity(cfg));
if (linphone_address_get_username(from)[0]=='?'){
const char *username=linphone_gtk_get_ui_config ("login_username",NULL);
if (username)
linphone_address_set_username(from,username);
}
ai=linphone_core_find_auth_info(lc,linphone_proxy_config_get_domain(cfg),linphone_address_get_username(from));
/*display the last entered username, if not '?????'*/
@ -101,11 +116,11 @@ void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg){
void linphone_gtk_exit_login_frame(void){
GtkWidget *mw=linphone_gtk_get_main_window();
gtk_widget_show(linphone_gtk_get_widget(mw,"idle_frame"));
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,"modes"),TRUE);
gtk_widget_show(linphone_gtk_get_widget(mw,"logout"));
gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"options_menu"),TRUE);
gtk_widget_show(linphone_gtk_get_widget(mw,"disconnect_item"));
}
void linphone_gtk_logout_clicked(){
@ -142,6 +157,7 @@ void linphone_gtk_login_frame_connect_clicked(GtkWidget *button){
autologin=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(mw,"automatic_login")));
linphone_gtk_set_ui_config_int("automatic_login",autologin);
linphone_gtk_set_ui_config("login_username",username);
from=linphone_address_new(linphone_proxy_config_get_identity(cfg));
linphone_address_set_username(from,username);

View file

@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#define USE_LIBGLADE 1
//#define USE_LIBGLADE 1
#define VIDEOSELFVIEW_DEFAULT 1
@ -41,9 +41,8 @@ const char *this_program_ident_string="linphone_ident_string=" LINPHONE_VERSION;
static LinphoneCore *the_core=NULL;
static GtkWidget *the_ui=NULL;
static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState rs, const char *msg);
static void linphone_gtk_show(LinphoneCore *lc);
static void linphone_gtk_inv_recv(LinphoneCore *lc, const char *from);
static void linphone_gtk_bye_recv(LinphoneCore *lc, const char *from);
static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid);
static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url);
static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username);
@ -51,30 +50,11 @@ static void linphone_gtk_display_status(LinphoneCore *lc, const char *status);
static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg);
static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning);
static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url);
static void linphone_gtk_display_question(LinphoneCore *lc, const char *question);
static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl);
static void linphone_gtk_general_state(LinphoneCore *lc, LinphoneGeneralState *gstate);
static void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to);
static gboolean linphone_gtk_auto_answer(GtkWidget *incall_window);
static void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to);
static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg);
static gboolean linphone_gtk_auto_answer(LinphoneCall *call);
static LinphoneCoreVTable vtable={
.show=linphone_gtk_show,
.inv_recv=linphone_gtk_inv_recv,
.bye_recv=linphone_gtk_bye_recv,
.notify_presence_recv=linphone_gtk_notify_recv,
.new_unknown_subscriber=linphone_gtk_new_unknown_subscriber,
.auth_info_requested=linphone_gtk_auth_info_requested,
.display_status=linphone_gtk_display_status,
.display_message=linphone_gtk_display_message,
.display_warning=linphone_gtk_display_warning,
.display_url=linphone_gtk_display_url,
.display_question=linphone_gtk_display_question,
.call_log_updated=linphone_gtk_call_log_updated,
.text_received=linphone_gtk_text_received,
.general_state=linphone_gtk_general_state,
.refer_received=linphone_gtk_refer_received,
.buddy_info_updated=linphone_gtk_buddy_info_updated
};
static gboolean verbose=0;
static gboolean auto_answer = 0;
@ -115,7 +95,7 @@ static GOptionEntry linphone_options[]={
.description = N_("if set automatically answer incoming calls")
},
#ifdef WIN32
{ /* zsd addition */
{
.long_name = "workdir",
.short_name = '\0',
.arg = G_OPTION_ARG_STRING,
@ -127,7 +107,7 @@ static GOptionEntry linphone_options[]={
};
#define INSTALLED_XML_DIR PACKAGE_DATA_DIR "/linphone"
#define BUILD_TREE_XML_DIR "gtk-glade"
#define BUILD_TREE_XML_DIR "gtk"
#ifndef WIN32
#define CONFIG_FILE ".linphonerc"
@ -211,6 +191,23 @@ static const char *linphone_gtk_get_factory_config_file(){
static void linphone_gtk_init_liblinphone(const char *config_file,
const char *factory_config_file) {
LinphoneCoreVTable vtable={0};
vtable.call_state_changed=linphone_gtk_call_state_changed;
vtable.registration_state_changed=linphone_gtk_registration_state_changed;
vtable.show=linphone_gtk_show;
vtable.notify_presence_recv=linphone_gtk_notify_recv;
vtable.new_subscription_request=linphone_gtk_new_unknown_subscriber;
vtable.auth_info_requested=linphone_gtk_auth_info_requested;
vtable.display_status=linphone_gtk_display_status;
vtable.display_message=linphone_gtk_display_message;
vtable.display_warning=linphone_gtk_display_warning;
vtable.display_url=linphone_gtk_display_url;
vtable.call_log_updated=linphone_gtk_call_log_updated;
vtable.text_received=linphone_gtk_text_received;
vtable.refer_received=linphone_gtk_refer_received;
vtable.buddy_info_updated=linphone_gtk_buddy_info_updated;
linphone_core_set_user_agent("Linphone", LINPHONE_VERSION);
the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL);
linphone_core_set_waiting_callback(the_core,linphone_gtk_wait,NULL);
@ -283,12 +280,78 @@ GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){
#else
static int get_ui_file(const char *name, char *path, int pathsize){
snprintf(path,pathsize,"%s/%s.ui",BUILD_TREE_XML_DIR,name);
if (access(path,F_OK)!=0){
snprintf(path,pathsize,"%s/%s.ui",INSTALLED_XML_DIR,name);
if (access(path,F_OK)!=0){
g_error("Could not locate neither %s/%s.ui and %s/%s.ui .",BUILD_TREE_XML_DIR,name,
INSTALLED_XML_DIR,name);
return -1;
}
}
return 0;
}
GtkWidget *linphone_gtk_create_window(const char *window_name){
GError* error = NULL;
GtkBuilder* builder = gtk_builder_new ();
char path[512];
GtkWidget *w;
if (get_ui_file(window_name,path,sizeof(path))==-1) return NULL;
if (!gtk_builder_add_from_file (builder, path, &error)){
g_error("Couldn't load builder file: %s", error->message);
g_error_free (error);
return NULL;
}
w=GTK_WIDGET(gtk_builder_get_object (builder,window_name));
if (w==NULL){
g_error("Could not retrieve '%s' window from xml file",window_name);
return NULL;
}
g_object_set_data(G_OBJECT(w),"builder",builder);
gtk_builder_connect_signals(builder,w);
linphone_gtk_configure_window(w,window_name);
return w;
}
GtkWidget *linphone_gtk_create_widget(const char *filename, const char *widget_name){
char path[2048];
GtkWidget *w;
GtkBuilder* builder = gtk_builder_new ();
GError *error=NULL;
gchar *object_ids[2];
object_ids[0]=g_strdup(widget_name);
object_ids[1]=NULL;
if (get_ui_file(filename,path,sizeof(path))==-1) return NULL;
if (!gtk_builder_add_objects_from_file(builder,path,object_ids,&error)){
g_error("Couldn't load %s from builder file %s: %s", widget_name,path,error->message);
g_error_free (error);
g_free(object_ids[0]);
return NULL;
}
g_free(object_ids[0]);
w=GTK_WIDGET(gtk_builder_get_object (builder,widget_name));
if (w==NULL){
g_error("Could not retrieve '%s' window from xml file",widget_name);
return NULL;
}
g_object_set_data(G_OBJECT(w),"builder",builder);
gtk_builder_connect_signals(builder,w);
return w;
}
GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){
GObject *w=gtk_builder_get_object(the_ui,name);
GtkBuilder *builder=(GtkBuilder*)g_object_get_data(G_OBJECT(window),"builder");
GObject *w;
if (builder==NULL){
g_error("Fail to retrieve builder from window !");
return NULL;
}
w=gtk_builder_get_object(builder,name);
if (w==NULL){
g_error("No widget named %s found in xml interface.",name);
}
@ -352,8 +415,10 @@ void linphone_gtk_show_about(){
struct stat filestat;
const char *license_file=PACKAGE_DATA_DIR "/linphone/COPYING";
GtkWidget *about;
const char *tmp;
GdkPixbuf *logo=create_pixbuf(
linphone_gtk_get_ui_config("logo","linphone-banner.png"));
static const char *defcfg="defcfg";
about=linphone_gtk_create_window("about");
gtk_about_dialog_set_url_hook(about_url_clicked,NULL,NULL);
@ -375,7 +440,19 @@ void linphone_gtk_show_about(){
gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("title","Linphone"));
gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("home","http://www.linphone.org"));
if (logo) gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about),logo);
tmp=linphone_gtk_get_ui_config("artists",defcfg);
if (tmp!=defcfg){
const char *tmp2[2];
tmp2[0]=tmp;
tmp2[1]=NULL;
gtk_about_dialog_set_artists(GTK_ABOUT_DIALOG(about),tmp2);
}
tmp=linphone_gtk_get_ui_config("translators",defcfg);
if (tmp!=defcfg)
gtk_about_dialog_set_translator_credits (GTK_ABOUT_DIALOG(about),tmp);
tmp=linphone_gtk_get_ui_config("comments",defcfg);
if (tmp!=defcfg)
gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about),tmp);
gtk_widget_show(about);
}
@ -390,7 +467,7 @@ static void set_video_window_decorations(GdkWindow *w){
gdk_window_set_keep_above(w, FALSE);
}else{
LinphoneAddress *uri =
linphone_address_clone(linphone_core_get_remote_uri(linphone_gtk_get_core()));
linphone_address_clone(linphone_core_get_current_call_remote_address(linphone_gtk_get_core()));
char *display_name;
linphone_address_clean(uri);
@ -435,6 +512,7 @@ static gboolean linphone_gtk_iterate(LinphoneCore *lc){
static gboolean first_time=TRUE;
unsigned long id;
static unsigned long previd=0;
static unsigned long preview_previd=0;
static gboolean in_iterate=FALSE;
/*avoid reentrancy*/
@ -457,6 +535,25 @@ static gboolean linphone_gtk_iterate(LinphoneCore *lc){
w=gdk_window_foreign_new(id);
#else
w=gdk_window_foreign_new((HANDLE)id);
#endif
if (w) {
set_video_window_decorations(w);
g_object_unref(G_OBJECT(w));
}
else ms_error("gdk_window_foreign_new() failed");
if (video_needs_update) video_needs_update=FALSE;
}
}
id=linphone_core_get_native_preview_window_id (lc);
if (id!=preview_previd ){
GdkWindow *w;
preview_previd=id;
if (id!=0){
ms_message("Updating window decorations for preview");
#ifndef WIN32
w=gdk_window_foreign_new(id);
#else
w=gdk_window_foreign_new((HANDLE)id);
#endif
if (w) {
set_video_window_decorations(w);
@ -553,88 +650,119 @@ static void completion_add_text(GtkEntry *entry, const char *text){
save_uri_history();
}
void linphone_gtk_call_terminated(const char *error){
void linphone_gtk_call_terminated(LinphoneCall *call, const char *error){
GtkWidget *mw=linphone_gtk_get_main_window();
GtkWidget *icw;
gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),FALSE);
gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),TRUE);
linphone_gtk_enable_mute_button(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(mw,"main_mute")),FALSE);
if (linphone_gtk_use_in_call_view())
linphone_gtk_in_call_view_terminate(error);
if (linphone_gtk_use_in_call_view() && call)
linphone_gtk_in_call_view_terminate(call,error);
update_video_title();
icw=GTK_WIDGET(g_object_get_data(G_OBJECT(mw),"incoming_call"));
if (icw!=NULL){
g_object_set_data(G_OBJECT(mw),"incoming_call",NULL);
gtk_widget_destroy(icw);
}
}
static gboolean in_call_timer(){
if (linphone_core_in_call(linphone_gtk_get_core())){
linphone_gtk_in_call_view_update_duration(
linphone_core_get_current_call_duration(linphone_gtk_get_core()));
LinphoneCall *call=linphone_core_get_current_call(linphone_gtk_get_core());
if (call){
linphone_gtk_in_call_view_update_duration(call);
return TRUE;
}
return FALSE;
}
static void linphone_gtk_call_started(GtkWidget *mw){
gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),FALSE);
gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),TRUE);
static bool_t all_other_calls_paused(LinphoneCall *refcall, const MSList *calls){
for(;calls!=NULL;calls=calls->next){
LinphoneCall *call=(LinphoneCall*)calls->data;
LinphoneCallState cs=linphone_call_get_state(call);
if (refcall!=call){
if (cs!=LinphoneCallPaused && cs!=LinphoneCallPausing)
return FALSE;
}
}
return TRUE;
}
static void linphone_gtk_update_call_buttons(LinphoneCall *call){
LinphoneCore *lc=linphone_gtk_get_core();
GtkWidget *mw=linphone_gtk_get_main_window();
const MSList *calls=linphone_core_get_calls(lc);
GtkWidget *button;
bool_t start_active=TRUE;
bool_t stop_active=FALSE;
bool_t add_call=FALSE;
if (calls==NULL){
start_active=TRUE;
stop_active=FALSE;
}else{
stop_active=TRUE;
if (all_other_calls_paused(NULL,calls)){
start_active=TRUE;
add_call=TRUE;
}else if (call!=NULL && linphone_call_get_state(call)==LinphoneCallIncomingReceived && all_other_calls_paused(call,calls)){
if (ms_list_size(calls)>1){
start_active=TRUE;
add_call=TRUE;
}else{
start_active=TRUE;
add_call=FALSE;
}
}else{
start_active=FALSE;
}
}
button=linphone_gtk_get_widget(mw,"start_call");
gtk_widget_set_sensitive(button,start_active);
gtk_widget_set_visible(button,!add_call);
button=linphone_gtk_get_widget(mw,"add_call");
gtk_widget_set_sensitive(button,start_active);
gtk_widget_set_visible(button,add_call);
gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),stop_active);
if (linphone_core_get_calls(lc)==NULL){
linphone_gtk_enable_mute_button(
GTK_BUTTON(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"main_mute")),
FALSE);
}
update_video_title();
if (linphone_gtk_use_in_call_view())
g_timeout_add(250,(GSourceFunc)in_call_timer,NULL);
}
static gboolean linphone_gtk_start_call_do(GtkWidget *uri_bar){
const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar));
if (linphone_core_invite(linphone_gtk_get_core(),entered)==0) {
if (linphone_core_invite(linphone_gtk_get_core(),entered)!=NULL) {
completion_add_text(GTK_ENTRY(uri_bar),entered);
}else{
linphone_gtk_call_terminated(NULL);
linphone_gtk_call_terminated(NULL,NULL);
}
return FALSE;
}
static void _linphone_gtk_accept_call(){
LinphoneCore *lc=linphone_gtk_get_core();
GtkWidget *mw=linphone_gtk_get_main_window();
GtkWidget *icw=GTK_WIDGET(g_object_get_data(G_OBJECT(mw),"incoming_call"));
if (icw!=NULL){
g_object_set_data(G_OBJECT(mw),"incoming_call",NULL);
gtk_widget_destroy(icw);
static gboolean linphone_gtk_auto_answer(LinphoneCall *call){
if (linphone_call_get_state(call)==LinphoneCallIncomingReceived){
linphone_core_accept_call (linphone_gtk_get_core(),call);
linphone_call_unref(call);
}
linphone_core_accept_call(lc,NULL);
linphone_gtk_call_started(linphone_gtk_get_main_window());
if (linphone_gtk_use_in_call_view()){
linphone_gtk_in_call_view_set_in_call();
linphone_gtk_show_in_call_view();
}
linphone_gtk_enable_mute_button(
GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"main_mute"))
,TRUE);
return FALSE;
}
void linphone_gtk_start_call(GtkWidget *w){
LinphoneCore *lc=linphone_gtk_get_core();
if (linphone_core_inc_invite_pending(lc)){
/*accept the call*/
_linphone_gtk_accept_call();
}else if (linphone_core_in_call(lc)) {
/*already in call */
LinphoneCall *call;
/*change into in-call mode, then do the work later as it might block a bit */
GtkWidget *mw=gtk_widget_get_toplevel(w);
GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
call=linphone_gtk_get_currently_displayed_call ();
if (call!=NULL && linphone_call_get_state(call)==LinphoneCallIncomingReceived){
linphone_core_accept_call(lc,call);
}else{
/*change into in-call mode, then do the work later as it might block a bit */
GtkWidget *mw=gtk_widget_get_toplevel(w);
GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar));
linphone_gtk_call_started(mw);
if (linphone_gtk_use_in_call_view()){
linphone_gtk_in_call_view_set_calling(entered);
linphone_gtk_show_in_call_view();
}
/*immediately disable the button and delay a bit the execution the linphone_core_invite()
so that we don't freeze the button. linphone_core_invite() might block for some hundreds of milliseconds*/
gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),FALSE);
g_timeout_add(100,(GSourceFunc)linphone_gtk_start_call_do,uri_bar);
}
}
void linphone_gtk_uri_bar_activate(GtkWidget *w){
@ -643,21 +771,23 @@ void linphone_gtk_uri_bar_activate(GtkWidget *w){
void linphone_gtk_terminate_call(GtkWidget *button){
linphone_core_terminate_call(linphone_gtk_get_core(),NULL);
LinphoneCall *call=linphone_gtk_get_currently_displayed_call ();
if (call)
linphone_core_terminate_call(linphone_gtk_get_core(),call);
}
void linphone_gtk_decline_call(GtkWidget *button){
linphone_core_terminate_call(linphone_gtk_get_core(),NULL);
gtk_widget_destroy(gtk_widget_get_toplevel(button));
void linphone_gtk_decline_clicked(GtkWidget *button){
LinphoneCall *call=linphone_gtk_get_currently_displayed_call ();
if (call)
linphone_core_terminate_call(linphone_gtk_get_core(),call);
}
void linphone_gtk_accept_call(GtkWidget *button){
_linphone_gtk_accept_call();
}
static gboolean linphone_gtk_auto_answer(GtkWidget *incall_window){
linphone_gtk_accept_call(linphone_gtk_get_widget(incall_window,"accept_call"));
return FALSE;
void linphone_gtk_answer_clicked(GtkWidget *button){
LinphoneCall *call=linphone_gtk_get_currently_displayed_call ();
if (call){
linphone_core_pause_all_calls(linphone_gtk_get_core());
linphone_core_accept_call(linphone_gtk_get_core(),call);
}
}
void linphone_gtk_set_audio_video(){
@ -704,35 +834,6 @@ static void linphone_gtk_show(LinphoneCore *lc){
linphone_gtk_show_main_window();
}
static void linphone_gtk_inv_recv(LinphoneCore *lc, const char *from){
GtkWidget *w=linphone_gtk_create_window("incoming_call");
GtkWidget *label;
gchar *msg;
if (auto_answer){
g_timeout_add(2000,(GSourceFunc)linphone_gtk_auto_answer,w);
}
gtk_window_set_transient_for(GTK_WINDOW(w),GTK_WINDOW(linphone_gtk_get_main_window()));
gtk_window_set_position(GTK_WINDOW(w),GTK_WIN_POS_CENTER_ON_PARENT);
label=linphone_gtk_get_widget(w,"message");
msg=g_strdup_printf(_("Incoming call from %s"),from);
gtk_label_set_text(GTK_LABEL(label),msg);
gtk_window_set_title(GTK_WINDOW(w),msg);
gtk_widget_show(w);
gtk_window_present(GTK_WINDOW(w));
/*gtk_window_set_urgency_hint(GTK_WINDOW(w),TRUE);*/
g_free(msg);
g_object_set_data(G_OBJECT(linphone_gtk_get_main_window()),"incoming_call",w);
gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar")),
from);
}
static void linphone_gtk_bye_recv(LinphoneCore *lc, const char *from){
}
static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid){
linphone_gtk_show_friends();
}
@ -868,36 +969,75 @@ static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const ch
linphone_gtk_display_something(GTK_MESSAGE_INFO,richtext);
}
static void linphone_gtk_display_question(LinphoneCore *lc, const char *question){
linphone_gtk_display_something(GTK_MESSAGE_QUESTION,question);
}
static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl){
GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"call_logs");
if (w) linphone_gtk_call_log_update(w);
}
static void linphone_gtk_general_state(LinphoneCore *lc, LinphoneGeneralState *gstate){
switch(gstate->new_state){
case GSTATE_CALL_OUT_CONNECTED:
case GSTATE_CALL_IN_CONNECTED:
if (linphone_gtk_use_in_call_view())
linphone_gtk_in_call_view_set_in_call();
static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg){
switch(cs){
case LinphoneCallOutgoingInit:
linphone_gtk_create_in_call_view (call);
break;
case LinphoneCallOutgoingProgress:
linphone_gtk_in_call_view_set_calling (call);
break;
case LinphoneCallStreamsRunning:
linphone_gtk_in_call_view_set_in_call(call);
linphone_gtk_enable_mute_button(
GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"main_mute")),
GTK_BUTTON(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"main_mute")),
TRUE);
g_timeout_add(250,(GSourceFunc)in_call_timer,NULL);
break;
case GSTATE_CALL_ERROR:
linphone_gtk_call_terminated(gstate->message);
case LinphoneCallError:
linphone_gtk_in_call_view_terminate (call,msg);
break;
case GSTATE_CALL_END:
linphone_gtk_call_terminated(NULL);
case LinphoneCallEnd:
linphone_gtk_in_call_view_terminate(call,NULL);
break;
case LinphoneCallIncomingReceived:
linphone_gtk_create_in_call_view (call);
linphone_gtk_in_call_view_set_incoming(call,!all_other_calls_paused (call,linphone_core_get_calls(lc)));
if (auto_answer) {
linphone_call_ref(call);
g_timeout_add(2000,(GSourceFunc)linphone_gtk_auto_answer ,call);
}
break;
case LinphoneCallResuming:
linphone_gtk_enable_hold_button(call,TRUE,TRUE);
linphone_gtk_in_call_view_set_in_call (call);
break;
case LinphoneCallPausing:
linphone_gtk_enable_hold_button(call,TRUE,FALSE);
case LinphoneCallPausedByRemote:
linphone_gtk_in_call_view_set_paused(call);
break;
case LinphoneCallConnected:
linphone_gtk_enable_hold_button (call,TRUE,TRUE);
break;
default:
break;
}
linphone_gtk_update_call_buttons (call);
}
static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg,
LinphoneRegistrationState rs, const char *msg){
switch (rs){
case LinphoneRegistrationOk:
if (cfg){
SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
linphone_gtk_exit_login_frame();
}
}
break;
default:
break;
}
}
static void icon_popup_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data){
GtkWidget *menu=(GtkWidget*)g_object_get_data(G_OBJECT(status_icon),"menu");
gtk_menu_popup(GTK_MENU(menu),NULL,NULL,gtk_status_icon_position_menu,status_icon,button,activate_time);
@ -1001,24 +1141,29 @@ void linphone_gtk_load_identities(void){
gtk_combo_box_set_active(box,def_index);
}
static void linphone_gtk_dtmf_clicked(GtkButton *button){
static void linphone_gtk_dtmf_pressed(GtkButton *button){
const char *label=gtk_button_get_label(button);
GtkWidget *uri_bar=linphone_gtk_get_widget(gtk_widget_get_toplevel(GTK_WIDGET(button)),"uribar");
int pos=-1;
gtk_editable_insert_text(GTK_EDITABLE(uri_bar),label,1,&pos);
linphone_core_play_dtmf (linphone_gtk_get_core(),label[0],-1);
if (linphone_core_in_call(linphone_gtk_get_core())){
linphone_core_send_dtmf(linphone_gtk_get_core(),label[0]);
}else{
GtkWidget *uri_bar=linphone_gtk_get_widget(gtk_widget_get_toplevel(GTK_WIDGET(button)),"uribar");
int pos=-1;
gtk_editable_insert_text(GTK_EDITABLE(uri_bar),label,1,&pos);
}
}
static void linphone_gtk_dtmf_released(GtkButton *button){
linphone_core_stop_dtmf (linphone_gtk_get_core());
}
static void linphone_gtk_connect_digits(void){
GtkContainer *cont=GTK_CONTAINER(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"dtmf_table"));
GList *children=gtk_container_get_children(cont);
GList *elem;
for(elem=children;elem!=NULL;elem=elem->next){
GtkButton *button=GTK_BUTTON(elem->data);
g_signal_connect(G_OBJECT(button),"clicked",(GCallback)linphone_gtk_dtmf_clicked,NULL);
g_signal_connect(G_OBJECT(button),"pressed",(GCallback)linphone_gtk_dtmf_pressed,NULL);
g_signal_connect(G_OBJECT(button),"released",(GCallback)linphone_gtk_dtmf_released,NULL);
}
}
@ -1049,19 +1194,23 @@ static void linphone_gtk_configure_main_window(){
static const char *title;
static const char *home;
static const char *start_call_icon;
static const char *add_call_icon;
static const char *stop_call_icon;
static const char *search_icon;
static gboolean update_check_menu;
static gboolean buttons_have_borders;
static gboolean show_abcd;
GtkWidget *w=linphone_gtk_get_main_window();
if (!config_loaded){
title=linphone_gtk_get_ui_config("title","Linphone");
home=linphone_gtk_get_ui_config("home","http://www.linphone.org");
start_call_icon=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png");
add_call_icon=linphone_gtk_get_ui_config("add_call_icon","addcall-green.png");
stop_call_icon=linphone_gtk_get_ui_config("stop_call_icon","stopcall-red.png");
search_icon=linphone_gtk_get_ui_config("directory_search_icon",NULL);
update_check_menu=linphone_gtk_get_ui_config_int("update_check_menu",0);
buttons_have_borders=linphone_gtk_get_ui_config_int("buttons_border",1);
show_abcd=linphone_gtk_get_ui_config_int("show_abcd",1);
config_loaded=TRUE;
}
linphone_gtk_configure_window(w,"main_window");
@ -1072,18 +1221,22 @@ static void linphone_gtk_configure_main_window(){
#endif
}
if (start_call_icon){
GdkPixbuf *pbuf=create_pixbuf(start_call_icon);
gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"start_call_icon")),pbuf);
if (buttons_have_borders)
gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),GTK_RELIEF_NORMAL);
g_object_unref(G_OBJECT(pbuf));
gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),
create_pixmap (start_call_icon));
if (!buttons_have_borders)
gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),GTK_RELIEF_NONE);
}
if (add_call_icon){
gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),
create_pixmap (add_call_icon));
if (!buttons_have_borders)
gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),GTK_RELIEF_NONE);
}
if (stop_call_icon){
GdkPixbuf *pbuf=create_pixbuf(stop_call_icon);
gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"terminate_call_icon")),pbuf);
if (buttons_have_borders)
gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"terminate_call")),GTK_RELIEF_NORMAL);
g_object_unref(G_OBJECT(pbuf));
gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"terminate_call")),
create_pixmap (stop_call_icon));
if (!buttons_have_borders)
gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"terminate_call")),GTK_RELIEF_NONE);
}
if (search_icon){
GdkPixbuf *pbuf=create_pixbuf(search_icon);
@ -1110,10 +1263,17 @@ static void linphone_gtk_configure_main_window(){
g_object_unref(G_OBJECT(pbuf));
}
}
if (!linphone_gtk_can_manage_accounts())
gtk_widget_hide(linphone_gtk_get_widget(w,"run_assistant"));
if (linphone_gtk_can_manage_accounts())
gtk_widget_show(linphone_gtk_get_widget(w,"assistant_item"));
if (update_check_menu){
gtk_widget_show(linphone_gtk_get_widget(w,"versioncheck"));
gtk_widget_show(linphone_gtk_get_widget(w,"versioncheck_item"));
}
if (!show_abcd){
gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_A"));
gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_B"));
gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_C"));
gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_D"));
gtk_table_resize(GTK_TABLE(linphone_gtk_get_widget(w,"dtmf_table")),4,3);
}
}
@ -1129,6 +1289,18 @@ void linphone_gtk_manage_login(void){
}
}
gboolean linphone_gtk_close(GtkWidget *mw){
/*shutdown calls if any*/
LinphoneCore *lc=linphone_gtk_get_core();
if (linphone_core_in_call(lc)){
linphone_core_terminate_all_calls(lc);
}
linphone_core_enable_video_preview(lc,FALSE);
gtk_widget_hide(mw);
return TRUE;
}
static void linphone_gtk_init_main_window(){
GtkWidget *main_window;
@ -1141,36 +1313,23 @@ static void linphone_gtk_init_main_window(){
linphone_gtk_connect_digits();
linphone_gtk_check_menu_items();
main_window=linphone_gtk_get_main_window();
linphone_gtk_enable_mute_button(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(main_window,
linphone_gtk_enable_mute_button(GTK_BUTTON(linphone_gtk_get_widget(main_window,
"main_mute")),FALSE);
linphone_gtk_enable_mute_button(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(main_window,
"incall_mute")),FALSE);
if (!linphone_gtk_use_in_call_view()) {
gtk_widget_show(linphone_gtk_get_widget(main_window, "main_mute"));
}
if (linphone_core_in_call(linphone_gtk_get_core())) linphone_gtk_call_started(
linphone_gtk_get_main_window());/*hide the call button, show terminate button*/
linphone_gtk_update_call_buttons (NULL);
/*prevent the main window from being destroyed by a user click on WM controls, instead we hide it*/
g_signal_connect (G_OBJECT (main_window), "delete-event",
G_CALLBACK (linphone_gtk_close), main_window);
}
void linphone_gtk_close(){
/* couldn't find a way to prevent closing to destroy the main window*/
LinphoneCore *lc=linphone_gtk_get_core();
the_ui=NULL;
the_ui=linphone_gtk_create_window("main");
linphone_gtk_init_main_window();
/*shutdown call if any*/
if (linphone_core_in_call(lc)){
linphone_core_terminate_call(lc,NULL);
linphone_gtk_call_terminated(NULL);
}
linphone_core_enable_video_preview(lc,FALSE);
}
void linphone_gtk_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){
if (verbose){
const char *lname="undef";
char *msg;
#ifdef __linux
#if defined(__linux) || defined(__APPLE__)
va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/
#endif
switch(lev){
@ -1192,7 +1351,7 @@ void linphone_gtk_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){
default:
g_error("Bad level !");
}
#ifdef __linux
#if defined(__linux) || defined(__APPLE__)
va_copy(cap,args);
msg=g_strdup_vprintf(fmt,cap);
va_end(cap);
@ -1284,6 +1443,7 @@ int main(int argc, char *argv[]){
}
settings=gtk_settings_get_default();
g_type_class_unref (g_type_class_ref (GTK_TYPE_IMAGE_MENU_ITEM));
g_object_set(settings, "gtk-menu-images", TRUE, NULL);
g_object_set(settings, "gtk-button-images", TRUE, NULL);
#ifdef WIN32
@ -1308,9 +1468,7 @@ int main(int argc, char *argv[]){
add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps/linphone");
g_set_application_name("Linphone");
pbuf=create_pixbuf(linphone_gtk_get_ui_config("icon",LINPHONE_ICON));
if (pbuf!=NULL) gtk_window_set_default_icon(pbuf);
the_ui=linphone_gtk_create_window("main");
@ -1318,6 +1476,11 @@ int main(int argc, char *argv[]){
linphone_core_enable_logs_with_cb(linphone_gtk_log_handler);
linphone_gtk_init_liblinphone(config_file, factory_config_file);
g_set_application_name(linphone_gtk_get_ui_config("title","Linphone"));
pbuf=create_pixbuf(linphone_gtk_get_ui_config("icon",LINPHONE_ICON));
if (pbuf!=NULL) gtk_window_set_default_icon(pbuf);
/* do not lower timeouts under 30 ms because it exhibits a bug on gtk+/win32, with cpu running 20% all the time...*/
gtk_timeout_add(30,(GtkFunction)linphone_gtk_iterate,(gpointer)linphone_gtk_get_core());
gtk_timeout_add(30,(GtkFunction)linphone_gtk_check_logs,(gpointer)NULL);

File diff suppressed because it is too large Load diff

View file

@ -1,13 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
<?xml version="1.0"?>
<!--Generated with glade3 3.4.5 on Sun Mar 29 21:17:24 2009 -->
<glade-interface>
<widget class="GtkAssistant" id="p2pwizard">
<interface>
<object class="GtkAssistant" id="p2pwizard">
<property name="title" translatable="yes">Creating a FONICS account</property>
<signal name="apply" handler="linphone_gtk_fonis_wizard_apply"/>
<signal name="prepare" handler="linphone_gtk_fonis_wizard_prepare"/>
<signal handler="linphone_gtk_fonis_wizard_apply" name="apply"/>
<signal handler="linphone_gtk_fonis_wizard_prepare" name="prepare"/>
<child>
<widget class="GtkLabel" id="label1">
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="label" translatable="yes">Welcome !
This wizard will help you to setup a SIP account.
@ -16,119 +15,115 @@ This wizard will help you to setup a SIP account.
<property name="justify">GTK_JUSTIFY_CENTER</property>
<property name="wrap">True</property>
<property name="selectable">True</property>
</widget>
</object>
<packing>
<property name="page_type">GTK_ASSISTANT_PAGE_INTRO</property>
<property name="title">Introduction</property>
</packing>
</child>
<child>
<widget class="GtkVBox" id="vbox1">
<object class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<child>
<widget class="GtkLabel" id="label2">
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="label" translatable="yes">Please choose a username:</property>
</widget>
</object>
</child>
<child>
<widget class="GtkFrame" id="frame1">
<object class="GtkFrame" id="frame1">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<child>
<widget class="GtkAlignment" id="alignment1">
<object class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkVBox" id="vbox2">
<object class="GtkVBox" id="vbox2">
<property name="visible">True</property>
<child>
<widget class="GtkHBox" id="hbox1">
<object class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<child>
<widget class="GtkEntry" id="username">
<object class="GtkEntry" id="username">
<property name="visible">True</property>
<property name="can_focus">True</property>
</widget>
</object>
</child>
<child>
<widget class="GtkButton" id="button1">
<object class="GtkButton" id="button1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="response_id">0</property>
<signal name="clicked" handler="linphone_gtk_fonis_wizard_check_username_clicked"/>
<signal handler="linphone_gtk_fonis_wizard_check_username_clicked" name="clicked"/>
<child>
<widget class="GtkHBox" id="hbox2">
<object class="GtkHBox" id="hbox2">
<property name="visible">True</property>
<child>
<widget class="GtkImage" id="image1">
<object class="GtkImage" id="image1">
<property name="visible">True</property>
<property name="stock">gtk-apply</property>
</widget>
</object>
</child>
<child>
<widget class="GtkLabel" id="label5">
<object class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="label" translatable="yes">Check availability</property>
</widget>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
</object>
</child>
</widget>
</object>
<packing>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
</object>
<packing>
<property name="expand">False</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="check_result">
<object class="GtkLabel" id="check_result">
<property name="visible">True</property>
</widget>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
</object>
</child>
</widget>
</object>
</child>
<child>
<widget class="GtkLabel" id="label4">
<child type="label">
<object class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="type">label_item</property>
</packing>
</object>
</child>
</widget>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
</object>
<packing>
<property name="title">Create your account !</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label3">
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="label" translatable="yes">Done ! Your account is now created and ready to use.</property>
</widget>
</object>
<packing>
<property name="page_type">GTK_ASSISTANT_PAGE_CONFIRM</property>
<property name="title">Finished !</property>
</packing>
</child>
</widget>
</glade-interface>
</object>
</interface>

File diff suppressed because it is too large Load diff

View file

@ -1,8 +1,8 @@
<?xml version="1.0"?>
<glade-interface>
<interface>
<!-- interface-requires gtk+ 2.16 -->
<!-- interface-naming-policy toplevel-contextual -->
<widget class="GtkDialog" id="password">
<object class="GtkDialog" id="password">
<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 - Authentication required</property>
@ -12,68 +12,68 @@
<property name="type_hint">dialog</property>
<property name="has_separator">False</property>
<child internal-child="vbox">
<widget class="GtkVBox" id="dialog-vbox9">
<object class="GtkVBox" id="dialog-vbox9">
<property name="visible">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="spacing">2</property>
<child>
<widget class="GtkVBox" id="vbox12">
<object class="GtkVBox" id="vbox12">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<widget class="GtkLabel" id="message">
<object class="GtkLabel" id="message">
<property name="visible">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="label" translatable="yes">Please enter the domain password</property>
<property name="justify">center</property>
<property name="wrap">True</property>
</widget>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkTable" id="table1">
<object class="GtkTable" id="table1">
<property name="visible">True</property>
<property name="n_rows">2</property>
<property name="n_columns">2</property>
<child>
<widget class="GtkLabel" id="userid_label">
<object class="GtkLabel" id="userid_label">
<property name="visible">True</property>
<property name="label" translatable="yes">UserID</property>
</widget>
</object>
</child>
<child>
<widget class="GtkEntry" id="userid_entry">
<object class="GtkEntry" id="userid_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
</widget>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label1">
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="label" translatable="yes">Password:</property>
<property name="justify">right</property>
</widget>
</object>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="password_entry">
<object class="GtkEntry" id="password_entry">
<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="visibility">False</property>
<property name="invisible_char">&#x25CF;</property>
<signal name="activate" handler="linphone_gtk_password_ok"/>
</widget>
<signal handler="linphone_gtk_password_ok" name="activate"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
@ -81,31 +81,31 @@
<property name="bottom_attach">2</property>
</packing>
</child>
</widget>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child internal-child="action_area">
<widget class="GtkHButtonBox" id="dialog-action_area8">
<object class="GtkHButtonBox" id="dialog-action_area8">
<property name="visible">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="layout_style">end</property>
<child>
<widget class="GtkButton" id="button8">
<object class="GtkButton" id="button8">
<property name="label" translatable="yes">gtk-ok</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_stock">True</property>
<signal name="clicked" handler="linphone_gtk_password_ok"/>
</widget>
<signal handler="linphone_gtk_password_ok" name="clicked"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
@ -113,29 +113,29 @@
</packing>
</child>
<child>
<widget class="GtkButton" id="button9">
<object class="GtkButton" id="button9">
<property name="label" translatable="yes">gtk-cancel</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_stock">True</property>
<signal name="clicked" handler="linphone_gtk_password_cancel"/>
</widget>
<signal handler="linphone_gtk_password_cancel" name="clicked"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
</object>
<packing>
<property name="expand">False</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
</widget>
</object>
</child>
</widget>
</glade-interface>
</object>
</interface>

View file

@ -102,9 +102,22 @@ void linphone_gtk_ipv6_toggled(GtkWidget *w){
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)));
}
void linphone_gtk_sip_port_changed(GtkWidget *w){
linphone_core_set_sip_port(linphone_gtk_get_core(),
(gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(w)));
void linphone_gtk_udp_sip_port_changed(GtkWidget *w){
LCSipTransports tr;
LinphoneCore *lc=linphone_gtk_get_core();
linphone_core_get_sip_transports(lc,&tr);
tr.udp_port = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(w));
linphone_core_set_sip_transports(lc,&tr);
}
void linphone_gtk_tcp_sip_port_changed(GtkWidget *w){
LCSipTransports tr;
LinphoneCore *lc=linphone_gtk_get_core();
linphone_core_get_sip_transports(lc,&tr);
tr.tcp_port = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(w));
linphone_core_set_sip_transports(lc,&tr);
}
void linphone_gtk_audio_port_changed(GtkWidget *w){
@ -119,17 +132,17 @@ void linphone_gtk_video_port_changed(GtkWidget *w){
void linphone_gtk_no_firewall_toggled(GtkWidget *w){
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)))
linphone_core_set_firewall_policy(linphone_gtk_get_core(),LINPHONE_POLICY_NO_FIREWALL);
linphone_core_set_firewall_policy(linphone_gtk_get_core(),LinphonePolicyNoFirewall);
}
void linphone_gtk_use_nat_address_toggled(GtkWidget *w){
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)))
linphone_core_set_firewall_policy(linphone_gtk_get_core(),LINPHONE_POLICY_USE_NAT_ADDRESS);
linphone_core_set_firewall_policy(linphone_gtk_get_core(),LinphonePolicyUseNatAddress);
}
void linphone_gtk_use_stun_toggled(GtkWidget *w){
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)))
linphone_core_set_firewall_policy(linphone_gtk_get_core(),LINPHONE_POLICY_USE_STUN);
linphone_core_set_firewall_policy(linphone_gtk_get_core(),LinphonePolicyUseStun);
}
void linphone_gtk_mtu_changed(GtkWidget *w){
@ -746,12 +759,16 @@ void linphone_gtk_show_parameters(void){
GtkWidget *codec_list=linphone_gtk_get_widget(pb,"codec_list");
int mtu;
int ui_advanced;
LCSipTransports tr;
/* NETWORK CONFIG */
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"ipv6_enabled")),
linphone_core_ipv6_enabled(lc));
gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"sip_port")),
linphone_core_get_sip_port(lc));
linphone_core_get_sip_transports(lc,&tr);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"udp_sip_port")),
tr.udp_port);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"tcp_sip_port")),
tr.tcp_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")),
@ -762,13 +779,13 @@ void linphone_gtk_show_parameters(void){
if (tmp) gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(pb,"stun_server")),tmp);
pol=linphone_core_get_firewall_policy(lc);
switch(pol){
case LINPHONE_POLICY_NO_FIREWALL:
case LinphonePolicyNoFirewall:
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"no_nat")),TRUE);
break;
case LINPHONE_POLICY_USE_NAT_ADDRESS:
case LinphonePolicyUseNatAddress:
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"use_nat_address")),TRUE);
break;
case LINPHONE_POLICY_USE_STUN:
case LinphonePolicyUseStun:
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"use_stun")),TRUE);
break;
}
@ -813,11 +830,13 @@ void linphone_gtk_show_parameters(void){
linphone_gtk_show_sip_accounts(pb);
/* CODECS CONFIG */
linphone_gtk_init_codec_list(GTK_TREE_VIEW(codec_list));
linphone_gtk_draw_codec_list(GTK_TREE_VIEW(codec_list),0);
gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget(pb,"codec_view")),0);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"download_bw")),
linphone_core_get_download_bandwidth(lc));
gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"upload_bw")),
linphone_core_get_upload_bandwidth(lc));
/* UI CONFIG */
linphone_gtk_fill_langs(pb);

View file

@ -1,8 +1,16 @@
<?xml version="1.0"?>
<glade-interface>
<interface>
<object class="GtkAdjustment" id="adjustment1">
<property name="upper">100000</property>
<property name="lower">0</property>
<property name="page_increment">10</property>
<property name="step_increment">1</property>
<property name="page_size">10</property>
<property name="value">3600</property>
</object>
<!-- interface-requires gtk+ 2.6 -->
<!-- interface-naming-policy toplevel-contextual -->
<widget class="GtkDialog" id="sip_account">
<object class="GtkDialog" id="sip_account">
<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>
@ -11,74 +19,74 @@
<property name="type_hint">dialog</property>
<property name="has_separator">False</property>
<child internal-child="vbox">
<widget class="GtkVBox" id="dialog-vbox2">
<object class="GtkVBox" id="dialog-vbox2">
<property name="visible">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="orientation">vertical</property>
<property name="spacing">2</property>
<child>
<widget class="GtkFrame" id="frame15">
<object class="GtkFrame" id="frame15">
<property name="visible">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="label_xalign">0</property>
<child>
<widget class="GtkAlignment" id="alignment15">
<object class="GtkAlignment" id="alignment15">
<property name="visible">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="left_padding">12</property>
<child>
<widget class="GtkVBox" id="vbox11">
<object class="GtkVBox" id="vbox11">
<property name="visible">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="orientation">vertical</property>
<child>
<widget class="GtkTable" id="table6">
<object class="GtkTable" id="table6">
<property name="visible">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="n_rows">4</property>
<property name="n_columns">2</property>
<child>
<widget class="GtkLabel" id="label38">
<object class="GtkLabel" id="label38">
<property name="visible">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="label" translatable="yes">Your SIP identity:</property>
<property name="justify">right</property>
</widget>
</object>
</child>
<child>
<widget class="GtkEntry" id="identity">
<object class="GtkEntry" id="identity">
<property name="width_request">275</property>
<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="tooltip" translatable="yes">Looks like sip:&lt;username&gt;@&lt;domain&gt;</property>
<property name="tooltip-text" translatable="yes">Looks like sip:&lt;username&gt;@&lt;domain&gt;</property>
<property name="text" translatable="yes">sip:</property>
</widget>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label39">
<object class="GtkLabel" id="label39">
<property name="visible">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="label" translatable="yes">SIP Proxy address:</property>
<property name="justify">right</property>
</widget>
</object>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="proxy">
<object class="GtkEntry" id="proxy">
<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="tooltip" translatable="yes">Looks like sip:&lt;proxy hostname&gt;</property>
<property name="tooltip-text" translatable="yes">Looks like sip:&lt;proxy hostname&gt;</property>
<property name="text" translatable="yes">sip:</property>
</widget>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
@ -87,23 +95,23 @@
</packing>
</child>
<child>
<widget class="GtkLabel" id="label40">
<object class="GtkLabel" id="label40">
<property name="visible">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="label" translatable="yes">Route (optional):</property>
<property name="justify">right</property>
</widget>
</object>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="route">
<object class="GtkEntry" id="route">
<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>
</widget>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
@ -112,24 +120,24 @@
</packing>
</child>
<child>
<widget class="GtkLabel" id="label41">
<object class="GtkLabel" id="label41">
<property name="visible">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="label" translatable="yes">Registration duration (sec):</property>
<property name="justify">right</property>
</widget>
</object>
<packing>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
<child>
<widget class="GtkSpinButton" id="regperiod">
<object class="GtkSpinButton" id="regperiod">
<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="adjustment">3600 0 100000 1 10 10</property>
</widget>
<property name="adjustment">adjustment1</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
@ -137,73 +145,70 @@
<property name="bottom_attach">4</property>
</packing>
</child>
</widget>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="register">
<object class="GtkCheckButton" id="register">
<property name="label" translatable="yes">Register at startup</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
</widget>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="publish">
<object class="GtkCheckButton" id="publish">
<property name="label" translatable="yes">Publish presence information</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="draw_indicator">True</property>
</widget>
</object>
<packing>
<property name="expand">False</property>
<property name="position">2</property>
</packing>
</child>
</widget>
</object>
</child>
</widget>
</object>
</child>
<child>
<widget class="GtkLabel" id="label42">
<child type="label">
<object class="GtkLabel" id="label42">
<property name="visible">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="label" translatable="yes">Configure a SIP account</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="type">label_item</property>
</packing>
</object>
</child>
</widget>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child internal-child="action_area">
<widget class="GtkHButtonBox" id="dialog-action_area2">
<object class="GtkHButtonBox" id="dialog-action_area2">
<property name="visible">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="layout_style">end</property>
<child>
<widget class="GtkButton" id="button6">
<object class="GtkButton" id="button6">
<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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="linphone_gtk_proxy_ok"/>
</widget>
<signal handler="linphone_gtk_proxy_ok" name="clicked"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
@ -211,29 +216,29 @@
</packing>
</child>
<child>
<widget class="GtkButton" id="button7">
<object class="GtkButton" id="button7">
<property name="label">gtk-cancel</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_stock">True</property>
<signal name="clicked" handler="linphone_gtk_proxy_cancel"/>
</widget>
<signal handler="linphone_gtk_proxy_cancel" name="clicked"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
</object>
<packing>
<property name="expand">False</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
</widget>
</object>
</child>
</widget>
</glade-interface>
</object>
</interface>

View file

Before

Width:  |  Height:  |  Size: 764 B

After

Width:  |  Height:  |  Size: 764 B

View file

@ -177,7 +177,7 @@ const gchar *linphone_gtk_get_ui_config(const char *key, const char *def){
LpConfig *cfg=linphone_core_get_config(linphone_gtk_get_core());
return lp_config_get_string(cfg,"GtkUi",key,def);
}else{
ms_warning ("Cannot read config, no core created yet.");
g_error ("Cannot read config, no core created yet.");
return NULL;
}
}
@ -192,6 +192,10 @@ void linphone_gtk_set_ui_config_int(const char *key , int val){
lp_config_set_int(cfg,"GtkUi",key,val);
}
void linphone_gtk_set_ui_config(const char *key , const char * val){
LpConfig *cfg=linphone_core_get_config(linphone_gtk_get_core());
lp_config_set_string(cfg,"GtkUi",key,val);
}
static void parse_item(const char *item, const char *window_name, GtkWidget *w, gboolean show){
char tmp[64];

View file

@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
<?xml version="1.0"?>
<!--Generated with glade3 3.4.5 on Sun Mar 29 15:33:09 2009 -->
<glade-interface>
<widget class="GtkWindow" id="waiting">
<interface>
<object class="GtkWindow" id="waiting">
<property name="title" translatable="yes">Linphone</property>
<property name="resizable">False</property>
<property name="modal">True</property>
@ -10,52 +9,49 @@
<property name="icon">linphone2.png</property>
<property name="deletable">False</property>
<child>
<widget class="GtkFrame" id="frame1">
<object class="GtkFrame" id="frame1">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<child>
<widget class="GtkAlignment" id="alignment1">
<object class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkHBox" id="hbox1">
<object class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<property name="spacing">5</property>
<child>
<widget class="GtkImage" id="image1">
<object class="GtkImage" id="image1">
<property name="visible">True</property>
<property name="stock">gtk-dialog-info</property>
</widget>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkProgressBar" id="progressbar">
<object class="GtkProgressBar" id="progressbar">
<property name="visible">True</property>
</widget>
</object>
<packing>
<property name="padding">5</property>
<property name="position">1</property>
</packing>
</child>
</widget>
</object>
</child>
</widget>
</object>
</child>
<child>
<widget class="GtkLabel" id="label1">
<child type="label">
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="label" translatable="yes">Please wait</property>
<property name="use_markup">True</property>
<property name="justify">GTK_JUSTIFY_CENTER</property>
</widget>
<packing>
<property name="type">label_item</property>
</packing>
</object>
</child>
</widget>
</object>
</child>
</widget>
</glade-interface>
</object>
</interface>

View file

@ -17,7 +17,16 @@ 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;
/**
* Object that represents a SIP address.
* The LinphoneAddress is an opaque object to represents SIP addresses, ie the content of SIP's 'from' and 'to' headers.
* A SIP address is made of display name, username, domain name, port, and various uri headers (such as tags).
* It looks like 'Alice <sip:alice@example.net>'. The LinphoneAddress has methods to extract and manipulate all parts of the address.
* When some part of the address (for example the username) is empty, the accessor methods return null.
* <br> Can be instanciated using both {@link LinphoneCoreFactory#createLinphoneAddress(String, String, String)} or {@link LinphoneCoreFactory#createLinphoneAddress(String)}
* @author jehanmonnier
*
*/
public interface LinphoneAddress {
/**
* Human display name
@ -58,6 +67,9 @@ public interface LinphoneAddress {
*/
public String asStringUriOnly();
/*must return the same thing as asString()*/
/**
* same as {@link #asString()}
*
* */
public String toString();
}

View file

@ -17,13 +17,51 @@ 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;
/**
* Object holding authentication information.
* In most case, authentication information consists of a username and password. Sometimes, a userid is required by proxy, and realm can be useful to discriminate different SIP domains.
*<br>This object is instanciated using {@link LinphoneCoreFactory#createAuthInfo(String, String, String)}.
*<br>
*Once created and filled, a LinphoneAuthInfo must be added to the LinphoneCore in order to become known and used automatically when needed.
*Use {@link LinphoneCore#addAuthInfo(LinphoneAuthInfo)} for that purpose.
*<br>
*The LinphoneCore object can take the initiative to request authentication information when needed to the application
*through the {@link LinphoneCoreListener#authInfoRequested(LinphoneCore, String, String)} listener.
*<br>
*The application can respond to this information request later using {@link LinphoneCore#addAuthInfo(LinphoneAuthInfo)}.
*This will unblock all pending authentication transactions and retry them with authentication headers.
*
*/
public interface LinphoneAuthInfo {
/**
* get user name
* @return username
*/
String getUsername();
String getPassword();
String getRealm();
/**
* Sets the username.
* @param username
*/
void setUsername(String username);
/**
* get password
* @return password
*/
String getPassword();
/**
* sets password
* @param password
*/
void setPassword(String password);
/**
* get realm
* @return
*/
String getRealm();
/**
* set realm
* @param realm
*/
void setRealm(String realm);
}

View file

@ -0,0 +1,158 @@
/*
LinphoneCall.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;
/**
* Object representing a Call. calls are created using {@link LinphoneCore#invite(LinphoneAddress)} or paased to the application by listener {@link LinphoneCoreListener#callState(LinphoneCore, LinphoneCall, State, String)}
*
*/
public interface LinphoneCall {
/**
* Linphone call states
*
*/
static class State {
static private Vector values = new Vector();
private final int mValue;
private final String mStringValue;
/**
* Idle
*/
public final static State Idle = new State(0,"Idle");
/**
* Incoming call received.
*/
public final static State IncomingReceived = new State(1,"IncomingReceived");
/**
* Outgoing call initialiazed.
*/
public final static State OutgoingInit = new State(2,"OutgoingInit");
/**
* Outgoing call in progress.
*/
public final static State OutgoingProgress = new State(3,"OutgoingProgress");
/**
* Outgoing call ringing.
*/
public final static State OutgoingRinging = new State(4,"OutgoingRinging");
/**
* Outgoing call early media
*/
public final static State OutgoingEarlyMedia = new State(5,"OutgoingEarlyMedia");
/**
* Connected
*/
public final static State Connected = new State(6,"Connected");
/**
* Streams running
*/
public final static State StreamsRunning = new State(7,"StreamsRunning");
/**
* Paussing
*/
public final static State Pausing = new State(8,"Pausing");
/**
* Paused
*/
public final static State Paused = new State(9,"Paused");
/**
* Resuming
*/
public final static State Resuming = new State(10,"Resuming");
/**
* Refered
*/
public final static State Refered = new State(11,"Refered");
/**
* Error
*/
public final static State Error = new State(12,"Error");
/**
* Call end
*/
public final static State CallEnd = new State(13,"CallEnd");
/**
* Paused by remote
*/
public final static State PausedByRemote = new State(14,"PausedByRemote");
/**
* The call's parameters are updated, used for example when video is asked by remote
*/
public static final State CallUpdatedByRemote = new State(15, "CallUpdatedByRemote");
/**
* We are proposing early media to an incoming call
*/
public static final State CallIncomingEarlyMedia = new State(16,"CallIncomingEarlyMedia");
/**
* The remote accepted the call update initiated by us
*/
public static final State CallUpdated = new State(17, "CallUpdated");
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;
}
}
/**
* Retrieves the call's current state.
**/
public State getState();
/**
* Returns the remote address associated to this call
*
**/
public LinphoneAddress getRemoteAddress();
/**
* get direction of the call (incoming or outgoing).
* @return CallDirection
*/
public CallDirection getDirection();
/**
* get the call log associated to this call.
* @Return LinphoneCallLog
**/
public LinphoneCallLog getCallLog();
/**
* @return parameters for this call; read only, call copy() to get a read/write version.
*/
public LinphoneCallParams getCurrentParamsReadOnly();
}

View file

@ -17,13 +17,78 @@ 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;
/**
* Call data records object
*
*/
import java.util.Vector;
public interface LinphoneCallLog {
/**
* Represents call status
*
*/
static class CallStatus {
static private Vector values = new Vector();
private final int mValue;
private final String mStringValue;
/**
* Call success.
*/
public final static CallStatus Sucess = new CallStatus(0,"Sucess");
/**
* Call aborted.
*/
public final static CallStatus Aborted = new CallStatus(1,"Aborted");
/**
* missed incoming call.
*/
public final static CallStatus Missed = new CallStatus(2,"Missed");
/**
* remote call declined.
*/
public final static CallStatus Declined = new CallStatus(3,"Declined");
private CallStatus(int value,String stringValue) {
mValue = value;
values.addElement(this);
mStringValue=stringValue;
}
public static CallStatus fromInt(int value) {
for (int i=0; i<values.size();i++) {
CallStatus state = (CallStatus) values.elementAt(i);
if (state.mValue == value) return state;
}
throw new RuntimeException("CallStatus not found ["+value+"]");
}
public String toString() {
return mStringValue;
}
public int toInt() {
return mValue;
}
}
/**
* Originator of the call as a LinphoneAddress object.
* @return LinphoneAddress
*/
public LinphoneAddress getFrom();
/**
* Destination of the call as a LinphoneAddress object.
* @return
*/
public LinphoneAddress getTo ();
/**
* The direction of the call
* @return CallDirection
*/
public CallDirection getDirection();
/**
* get status of this call
* @return
*/
public CallStatus getStatus();
}

View file

@ -0,0 +1,32 @@
/*
LinphoneCallParameters.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;
/**
* 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.
* @author Guillaume Beraudo
*
*/
public interface LinphoneCallParams {
void setVideoEnabled(boolean b);
boolean getVideoEnabled();
LinphoneCallParams copy();
}

View file

@ -0,0 +1,39 @@
/*
LinphoneChatRoom.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;
/**
*
* A chat room is the place where text messages are exchanged.
Can be created by linphone_core_create_chat_room().
*
*/
public interface LinphoneChatRoom {
/**
* get peer address associated to this LinphoneChatRoom
*
* @return LinphoneAddress peer address
*/
LinphoneAddress getPeerAddress();
/**
* send a message to peer member of this chat room.
* @param message to be sent
*/
void sendMessage(String message);
}

View file

@ -21,48 +21,45 @@ package org.linphone.core;
import java.util.Vector;
/**
* Linphone core main object created by method {@link LinphoneCoreFactory#createLinphoneCore(LinphoneCoreListener, String, String, Object)}.
*
*/
public interface LinphoneCore {
/*
/**
* linphone core states
*/
static public class GeneralState {
static public class GlobalState {
static private Vector values = new Vector();
/* states for GSTATE_GROUP_POWER */
static public GeneralState GSTATE_POWER_OFF = new GeneralState(0,"GSTATE_POWER_OFF"); /* initial state */
static public GeneralState GSTATE_POWER_STARTUP = new GeneralState(1,"GSTATE_POWER_STARTUP");
static public GeneralState GSTATE_POWER_ON = new GeneralState(2,"GSTATE_POWER_ON");
static public GeneralState GSTATE_POWER_SHUTDOWN = new GeneralState(3,"GSTATE_POWER_SHUTDOWN");
/* states for GSTATE_GROUP_REG */
static public GeneralState GSTATE_REG_NONE = new GeneralState(10,"GSTATE_REG_NONE"); /* initial state */
static public GeneralState GSTATE_REG_OK = new GeneralState(11,"GSTATE_REG_OK");
static public GeneralState GSTATE_REG_FAILED = new GeneralState(12,"GSTATE_REG_FAILED");
static public GeneralState GSTATE_REG_PENDING = new GeneralState(13,"GSTATE_REG_PENDING");
/* states for GSTATE_GROUP_CALL */
static public GeneralState GSTATE_CALL_IDLE = new GeneralState(20,"GSTATE_CALL_IDLE"); /* initial state */
static public GeneralState GSTATE_CALL_OUT_INVITE = new GeneralState(21,"GSTATE_CALL_OUT_INVITE");
static public GeneralState GSTATE_CALL_OUT_CONNECTED = new GeneralState(22,"GSTATE_CALL_OUT_CONNECTED");
static public GeneralState GSTATE_CALL_IN_INVITE = new GeneralState(23,"GSTATE_CALL_IN_INVITE");
static public GeneralState GSTATE_CALL_IN_CONNECTED = new GeneralState(24,"GSTATE_CALL_IN_CONNECTED");
static public GeneralState GSTATE_CALL_END = new GeneralState(25,"GSTATE_CALL_END");
static public GeneralState GSTATE_CALL_ERROR = new GeneralState(26,"GSTATE_CALL_ERROR");
static public GeneralState GSTATE_INVALID = new GeneralState(27,"GSTATE_INVALID");
static public GeneralState GSTATE_CALL_OUT_RINGING = new GeneralState(28,"GSTATE_CALL_OUT_RINGING");
/**
* Off
*/
static public GlobalState GlobalOff = new GlobalState(0,"GlobalOff");
/**
* Startup
*/
static public GlobalState GlobalStartup = new GlobalState(1,"GlobalStartup");
/**
* On
*/
static public GlobalState GlobalOn = new GlobalState(2,"GlobalOn");
/**
* Shutdown
*/
static public GlobalState GlobalShutdown = new GlobalState(3,"GlobalShutdown");
private final int mValue;
private final String mStringValue;
private GeneralState(int value,String stringValue) {
private GlobalState(int value,String stringValue) {
mValue = value;
values.addElement(this);
mStringValue=stringValue;
}
public static GeneralState fromInt(int value) {
public static GlobalState fromInt(int value) {
for (int i=0; i<values.size();i++) {
GeneralState state = (GeneralState) values.elementAt(i);
GlobalState state = (GlobalState) values.elementAt(i);
if (state.mValue == value) return state;
}
throw new RuntimeException("state not found ["+value+"]");
@ -71,9 +68,106 @@ public interface LinphoneCore {
return mStringValue;
}
}
/**
* Describes proxy registration states.
*
*/
static public class RegistrationState {
static private Vector values = new Vector();
/**
* None
*/
static public RegistrationState RegistrationNone = new RegistrationState(0,"RegistrationNone");
/**
* In Progress
*/
static public RegistrationState RegistrationProgress = new RegistrationState(1,"RegistrationProgress");
/**
* Ok
*/
static public RegistrationState RegistrationOk = new RegistrationState(2,"RegistrationOk");
/**
* Cleared
*/
static public RegistrationState RegistrationCleared = new RegistrationState(3,"RegistrationCleared");
/**
* Failed
*/
static public RegistrationState RegistrationFailed = new RegistrationState(4,"RegistrationFailed");
private final int mValue;
private final String mStringValue;
private RegistrationState(int value,String stringValue) {
mValue = value;
values.addElement(this);
mStringValue=stringValue;
}
public static RegistrationState fromInt(int value) {
for (int i=0; i<values.size();i++) {
RegistrationState state = (RegistrationState) values.elementAt(i);
if (state.mValue == value) return state;
}
throw new RuntimeException("state not found ["+value+"]");
}
public String toString() {
return mStringValue;
}
}
/**
* Describes firewall policy.
*
*/
static public class FirewallPolicy {
static private Vector values = new Vector();
/**
* No firewall is assumed.
*/
static public FirewallPolicy NoFirewall = new FirewallPolicy(0,"NoFirewall");
/**
* Use NAT address (discouraged)
*/
static public FirewallPolicy UseNatAddress = new FirewallPolicy(1,"UseNatAddress");
/**
* Use stun server to discover RTP addresses and ports.
*/
static public FirewallPolicy UseStun = new FirewallPolicy(2,"UseStun");
private final int mValue;
private final String mStringValue;
private FirewallPolicy(int value,String stringValue) {
mValue = value;
values.addElement(this);
mStringValue=stringValue;
}
public static FirewallPolicy fromInt(int value) {
for (int i=0; i<values.size();i++) {
FirewallPolicy state = (FirewallPolicy) values.elementAt(i);
if (state.mValue == value) return state;
}
throw new RuntimeException("state not found ["+value+"]");
}
public String toString() {
return mStringValue;
}
public int value(){
return mValue;
}
}
/**
* Signaling transports
*
*/
static public class Transport {
/**
* UDP transport
*/
public final static Transport udp =new Transport("udp");
/**
* TCP transport
*/
public final static Transport tcp =new Transport("tcp");
private final String mStringValue;
@ -85,15 +179,26 @@ public interface LinphoneCore {
}
}
/**
* clear all added proxy config
* clear all added proxy configs
*/
public void clearProxyConfigs();
/**
* Add a proxy configuration. This will start registration on the proxy, if registration is enabled.
* @param proxyCfg
* @throws LinphoneCoreException
*/
public void addProxyConfig(LinphoneProxyConfig proxyCfg) throws LinphoneCoreException;
/**
* Sets the default proxy.
*<br>
* This default proxy must be part of the list of already entered {@link LinphoneProxyConfig}.
* Toggling it as default will make LinphoneCore use the identity associated with the proxy configuration in all incoming and outgoing calls.
* @param proxyCfg
*/
public void setDefaultProxyConfig(LinphoneProxyConfig proxyCfg);
/**
* get he default proxy configuration, that is the one used to determine the current identity.
* @return null if no default proxy config
*/
public LinphoneProxyConfig getDefaultProxyConfig() ;
@ -102,7 +207,11 @@ public interface LinphoneCore {
* clear all the added auth info
*/
void clearAuthInfos();
/**
* Adds authentication information to the LinphoneCore.
* <br>This information will be used during all SIP transacations that require authentication.
* @param info
*/
void addAuthInfo(LinphoneAuthInfo info);
/**
@ -114,16 +223,31 @@ public interface LinphoneCore {
public LinphoneAddress interpretUrl(String destination) throws LinphoneCoreException;
/**
* Starts a call given a destination. Internally calls interpretUrl() then invite(LinphoneAddress).
* Starts a call given a destination. Internally calls {@link #interpretUrl(String)} then {@link #invite(LinphoneAddress)}.
* @param uri
*/
public void invite(String destination)throws LinphoneCoreException;
public void invite(LinphoneAddress to)throws LinphoneCoreException;
public void terminateCall();
public LinphoneCall invite(String destination)throws LinphoneCoreException;
/**
* get the remote address in case of in/out call
* Initiates an outgoing call given a destination LinphoneAddress
*<br>The LinphoneAddress can be constructed directly using linphone_address_new(), or created by linphone_core_interpret_url(). The application doesn't own a reference to the returned LinphoneCall object. Use linphone_call_ref() to safely keep the LinphoneCall pointer valid within your application.
* @param to the destination of the call (sip address).
* @return LinphoneCall
* @throws LinphoneCoreException
*/
public LinphoneCall invite(LinphoneAddress to)throws LinphoneCoreException;
/**
* Terminates a call.
* @param aCall to be terminated
*/
public void terminateCall(LinphoneCall aCall);
/**
* Returns The LinphoneCall the current call if one is in call
*
**/
public LinphoneCall getCurrentCall();
/**
* get current call remote address in case of in/out call
* @return null if no call engaged yet
*/
public LinphoneAddress getRemoteAddress();
@ -137,6 +261,17 @@ public interface LinphoneCore {
* @return Returns true if in incoming call is pending, ie waiting for being answered or declined.
*/
public boolean isInComingInvitePending();
/**
* Main loop function. It is crucial that your application call it periodically.
*
* #iterate() performs various backgrounds tasks:
* <li>receiving of SIP messages
* <li> handles timers and timeout
* <li> performs registration to proxies
* <li> authentication retries The application MUST call this function from periodically, in its main loop.
* <br> Be careful that this function must be call from the same thread as other liblinphone methods. In not the case make sure all liblinphone calls are serialized with a mutex.
*/
public void iterate();
/**
* Accept an incoming call.
@ -147,7 +282,7 @@ public interface LinphoneCore {
* this method.
* @throws LinphoneCoreException
*/
public void acceptCall() throws LinphoneCoreException;
public void acceptCall(LinphoneCall aCall) throws LinphoneCoreException;
/**
@ -211,24 +346,143 @@ public interface LinphoneCore {
*/
public void sendDtmf(char number);
/**
*
* Initiate a dtmf signal to the speqker if not in call
* @param number
* @param duration in ms , -1 for unlimited
*/
public void playDtmf(char number,int duration);
/**
* stop current dtmf
*/
public void stopDtmf();
/**
* remove all call logs
*/
public void clearCallLogs();
/***
* get payload type from mime type an clock rate
*
* return null if not found
*/
public PayloadType findPayloadType(String mime,int clockRate);
/**
* not implemented yet
* @param pt
* @param enable
* @throws LinphoneCoreException
*/
public void enablePayloadType(PayloadType pt, boolean enable) throws LinphoneCoreException;
/**
* Enables or disable echo cancellation.
* @param enable
*/
public void enableEchoCancellation(boolean enable);
/**
* get EC status
* @return true if echo cancellation is enabled.
*/
public boolean isEchoCancellationEnabled();
/**
* not implemented yet
* @param aTransport
*/
public void setSignalingTransport(Transport aTransport);
/**
* not implemented
* @param value
*/
public void enableSpeaker(boolean value);
/**
* not implemented
* @return
*/
public boolean isSpeakerEnabled();
/**
* add a friend to the current buddy list, if subscription attribute is set, a SIP SUBSCRIBE message is sent.
* @param lf LinphoenFriend to add
* @throws LinphoneCoreException
*/
void addFriend(LinphoneFriend lf) throws LinphoneCoreException;
/**
* Set my presence status
* @param minute_away how long in away
* @param status sip uri used to redirect call in state LinphoneStatusMoved
*/
void setPresenceInfo(int minute_away,String alternative_contact, OnlineStatus status);
/**
* Create a new chat room for messaging from a sip uri like sip:joe@sip.linphone.org
* @param to destination address for messages
*
* @return {@link LinphoneChatRoom} where messaging can take place.
*/
LinphoneChatRoom createChatRoom(String to);
public void setVideoWindow(Object w);
public void setPreviewWindow(Object w);
/**
* Enables video globally.
*
*
* This function does not have any effect during calls. It just indicates #LinphoneCore to
* initiate future calls with video or not. The two boolean parameters indicate in which
* direction video is enabled. Setting both to false disables video entirely.
*
* @param vcap_enabled indicates whether video capture is enabled
* @param display_enabled indicates whether video display should be shown
*
**/
void enableVideo(boolean vcap_enabled, boolean display_enabled);
/**
* Returns TRUE if video is enabled, FALSE otherwise.
*
***/
boolean isVideoEnabled();
/**
* Specify a STUN server to help firewall traversal.
* @param stun_server Stun server address and port, such as stun.linphone.org or stun.linphone.org:3478
*/
public void setStunServer(String stun_server);
/**
* @return stun server address if previously set.
*/
public String getStunServer();
/**
* Sets policy regarding workarounding NATs
* @param pol one of the FirewallPolicy members.
**/
public void setFirewallPolicy(FirewallPolicy pol);
/**
* @return previously set firewall policy.
*/
public FirewallPolicy getFirewallPolicy();
public LinphoneCall inviteAddressWithParams(LinphoneAddress destination, LinphoneCallParams params) throws LinphoneCoreException ;
public int updateCall(LinphoneCall call, LinphoneCallParams params);
public LinphoneCallParams createDefaultCallParameters();
/**
* Sets the path to a wav file used for ringing.
*
* @param path The file must be a wav 16bit linear. Local ring is disabled if null
*/
public void setRing(String path);
/**
* gets the path to a wav file used for ringing.
*
* @param null if not set
*/
public String getRing();
public void setUploadBandwidth(int bw);
public void setDownloadBandwidth(int bw);
public void setPreferredVideoSize(VideoSize vSize);
public VideoSize getPreferredVideoSize();
}

View file

@ -21,6 +21,7 @@ package org.linphone.core;
abstract public class LinphoneCoreFactory {
private static String factoryName = "org.linphone.core.LinphoneCoreFactoryImpl";
@ -49,9 +50,21 @@ abstract public class LinphoneCoreFactory {
abstract public LinphoneAuthInfo createAuthInfo(String username,String password, String realm);
abstract public LinphoneCore createLinphoneCore(LinphoneCoreListener listener, String userConfig,String factoryConfig,Object userdata) throws LinphoneCoreException;
abstract public LinphoneCore createLinphoneCore(LinphoneCoreListener listener) throws LinphoneCoreException;
/**
* Constructs a LinphoneAddress object
* @param username
* @param domain
* @param displayName
* @return
*/
abstract public LinphoneAddress createLinphoneAddress(String username,String domain,String displayName);
/**
* Constructs a LinphoneAddress object by parsing the user supplied address, given as a string.
* @param address should be like sip:joe@sip.linphone.org
* @return
*/
abstract public LinphoneAddress createLinphoneAddress(String address);
abstract public LinphoneProxyConfig createProxyConfig(String identity, String proxy,String route,boolean enableRegister) throws LinphoneCoreException;
@ -62,4 +75,17 @@ abstract public class LinphoneCoreFactory {
abstract public void setDebugMode(boolean enable);
abstract public void setLogHandler(LinphoneLogHandler handler);
/**
* Create a LinphoneFriend, similar to {@link #createLinphoneFriend()} + {@link LinphoneFriend#setAddress(LinphoneAddress)}
* @param friendUri a buddy address, must be a sip uri like sip:joe@sip.linphone.org
* @return a new LinphoneFriend with address initialized
*/
abstract public LinphoneFriend createLinphoneFriend(String friendUri);
/**
* Create a new LinphoneFriend
* @return
*/
abstract public LinphoneFriend createLinphoneFriend();
}

View file

@ -19,18 +19,15 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
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 */
public void show(LinphoneCore lc);
/**< Notifies incoming calls
* @return */
public void inviteReceived(LinphoneCore lc,String from);
/**< Notify calls terminated by far end
* @return */
public void byeReceived(LinphoneCore lc,String from);
/**< Ask the application some authentication information
* @return */
public void authInfoRequested(LinphoneCore lc,String realm,String username);
@ -43,10 +40,43 @@ public interface LinphoneCoreListener {
/** Callback to display a warning to the user
* @return */
public void displayWarning(LinphoneCore lc,String message);
/** State notification callback
* @param state LinphoneCore.GeneralState
/** General State notification
* @param state LinphoneCore.State
* @return
* */
public void generalState(LinphoneCore lc,LinphoneCore.GeneralState state, String message);
public void globalState(LinphoneCore lc,LinphoneCore.GlobalState state, String message);
/** Call State notification
* @param state LinphoneCall.State
* @return
* */
public void callState(LinphoneCore lc, LinphoneCall call, LinphoneCall.State cstate,String message);
/**
* Registration state notification
* */
public void registrationState(LinphoneCore lc, LinphoneProxyConfig cfg, LinphoneCore.RegistrationState cstate, String smessage);
/**
* Reports that a new subscription request has been received and wait for a decision.
*Status on this subscription request is notified by changing policy for this friend
*@param lc LinphoneCore
*@param lf LinphoneFriend corresponding to the subscriber
*@param url of the subscriber
*
*/
public void newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf, String url);
/**
* Report status change for a friend previously added to LinphoneCore.
* @param lc LinphoneCore
* @param lf updated LinphoneFriend
*/
public void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf);
/**
* invoked when a new text 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 from LinphoneAddress from
* @param message incoming message
*/
public void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from,String message);
}

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