Merge remote-tracking branch 'linphone/master'

This commit is contained in:
Simon Morlat 2014-07-02 15:13:55 +02:00
commit fd685faaf1
139 changed files with 12526 additions and 7863 deletions

View file

@ -60,47 +60,6 @@
<resource resourceType="PROJECT" workspacePath="/linphone"/>
</configuration>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets">
<buildTargets>
<target name="test" path="mediastreamer2/tests" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildTarget>all</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="all" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildArguments>CFLAGS="-g"</buildArguments>
<buildTarget>install</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="install" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildArguments>CFLAGS="-g"</buildArguments>
<buildTarget>install</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="doc" path="coreapi/help" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildTarget>all</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="doc" path="mediastreamer2/help" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildTarget>all</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
</buildTargets>
</storageModule>
<storageModule moduleId="scannerConfiguration">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
@ -209,4 +168,40 @@
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets">
<buildTargets>
<target name="test" path="mediastreamer2/tests" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildArguments>-j4 CFLAGS="-g -Wall -Werror -Qunused-arguments" CXXFLAGS="-g"</buildArguments>
<buildTarget>all</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="all" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildArguments>-j4 CFLAGS="-g -Wall -Werror -Qunused-arguments" CXXFLAGS="-g"</buildArguments>
<buildTarget/>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="doc" path="coreapi/help" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildArguments>-j4 CFLAGS="-g -Wall -Werror -Qunused-arguments" CXXFLAGS="-g"</buildArguments>
<buildTarget>all</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="doc" path="mediastreamer2/help" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildArguments>-j4 CFLAGS="-g -Wall -Werror -Qunused-arguments" CXXFLAGS="-g"</buildArguments>
<buildTarget>all</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
</buildTargets>
</storageModule>
</cproject>

2
.gitignore vendored
View file

@ -74,3 +74,5 @@ tester/liblinphone_tester
tools/lp-gen-wrappers
tools/lpc2xml_test
tools/xml2lpc_test
coreapi/help/filetransfer
tester/receive_file.dump

View file

@ -160,10 +160,31 @@ LOCAL_CFLAGS += -DHAVE_SILK
LOCAL_STATIC_LIBRARIES += libmssilk
endif
ifeq ($(BUILD_WEBRTC_ISAC),1)
LOCAL_CFLAGS += -DHAVE_ISAC
LOCAL_STATIC_LIBRARIES += libwebrtc_isacfix_neon
LOCAL_STATIC_LIBRARIES += libwebrtc_spl libwebrtc_isacfix libmsisac
ifneq ($(BUILD_WEBRTC_AECM)$(BUILD_WEBRTC_ISAC),00)
LOCAL_CFLAGS += -DHAVE_WEBRTC
LOCAL_STATIC_LIBRARIES += libmswebrtc
endif
ifneq ($(BUILD_WEBRTC_AECM),0)
LOCAL_STATIC_LIBRARIES += \
libwebrtc_aecm \
libwebrtc_apm_utility \
libwebrtc_spl \
libwebrtc_system_wrappers
ifeq ($(TARGET_ARCH_ABI), armeabi-v7a)
LOCAL_STATIC_LIBRARIES += \
libwebrtc_aecm_neon \
libwebrtc_spl_neon
endif
endif
ifneq ($(BUILD_WEBRTC_ISAC),0)
LOCAL_STATIC_LIBRARIES += \
libwebrtc_isacfix \
libwebrtc_spl
ifeq ($(TARGET_ARCH_ABI), armeabi-v7a)
LOCAL_STATIC_LIBRARIES += \
libwebrtc_isacfix_neon \
libwebrtc_spl_neon
endif
endif
ifeq ($(BUILD_G729),1)

View file

@ -12,21 +12,22 @@ common_SRC_FILES := \
stun_tester.c \
flexisip_tester.c \
tester.c \
remote_provisioning_tester.c
remote_provisioning_tester.c \
quality_reporting_tester.c
common_C_INCLUDES += \
$(LOCAL_PATH) \
$(LOCAL_PATH)/../include \
$(LOCAL_PATH)/../coreapi \
$(LOCAL_PATH)/../oRTP/include \
$(LOCAL_PATH)/../mediastreamer2/include
$(LOCAL_PATH)/../mediastreamer2/include
include $(CLEAR_VARS)
LOCAL_MODULE := liblinphone_tester
LOCAL_MODULE := liblinphone_tester
LOCAL_MODULE_FILENAME := liblinphone_tester-$(TARGET_ARCH_ABI)
LOCAL_SRC_FILES += $(common_SRC_FILES)
LOCAL_SRC_FILES += $(common_SRC_FILES)
LOCAL_C_INCLUDES = $(common_C_INCLUDES)
LOCAL_CFLAGS = -DIN_LINPHONE
LOCAL_LDLIBS := -llog

View file

@ -1,279 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM">
<Configuration>Debug</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM">
<Configuration>Release</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{08dd0d38-d9b5-4626-b60d-b4d76b571142}</ProjectGuid>
<RootNamespace>LibLinphone</RootNamespace>
<DefaultLanguage>en-US</DefaultLanguage>
<MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v110</PlatformToolset>
<IgnoreImportLibrary>false</IgnoreImportLibrary>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v110_wp80</PlatformToolset>
<IgnoreImportLibrary>false</IgnoreImportLibrary>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v110</PlatformToolset>
<IgnoreImportLibrary>false</IgnoreImportLibrary>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v110_wp80</PlatformToolset>
<IgnoreImportLibrary>false</IgnoreImportLibrary>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\$(TargetName)\</IntDir>
</PropertyGroup>
<PropertyGroup>
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>__STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<CompileAsWinRT>false</CompileAsWinRT>
<AdditionalUsingDirectories>$(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>belle-sip_dll.lib;mediastreamer2_dll.lib;ws2_32.lib;ortp_dll.lib;gsm_dll.lib;speex_dll.lib;speexdsp_dll.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(SolutionDir)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<ImportLibrary>$(TargetDir)$(TargetName)_dll.lib</ImportLibrary>
</Link>
<CustomBuildStep>
<Outputs>$(TargetDir)$(TargetName)_dll.lib;%(Outputs)</Outputs>
</CustomBuildStep>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>__STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<FunctionLevelLinking>true</FunctionLevelLinking>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<CompileAsWinRT>false</CompileAsWinRT>
<AdditionalUsingDirectories>$(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
<GenerateDebugInformation>false</GenerateDebugInformation>
<AdditionalDependencies>belle-sip_dll.lib;mediastreamer2_dll.lib;ws2_32.lib;ortp_dll.lib;gsm_dll.lib;speex_dll.lib;speexdsp_dll.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(SolutionDir)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<ImportLibrary>$(TargetDir)$(TargetName)_dll.lib</ImportLibrary>
</Link>
<CustomBuildStep>
<Outputs>$(TargetDir)$(TargetName)_dll.lib;%(Outputs)</Outputs>
</CustomBuildStep>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>__STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";UNICODE;_XKEYCHECK_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<CompileAsWinRT>false</CompileAsWinRT>
<AdditionalUsingDirectories>$(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<PreprocessToFile>false</PreprocessToFile>
<IgnoreStandardIncludePath>false</IgnoreStandardIncludePath>
<ExceptionHandling>SyncCThrow</ExceptionHandling>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(SolutionDir)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<ImportLibrary>$(TargetDir)$(TargetName)_dll.lib</ImportLibrary>
<IgnoreSpecificDefaultLibraries>ole32.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
<WindowsMetadataFile>
</WindowsMetadataFile>
</Link>
<CustomBuildStep>
<Outputs>$(TargetDir)$(TargetName)_dll.lib;%(Outputs)</Outputs>
</CustomBuildStep>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>__STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";UNICODE;_XKEYCHECK_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<FunctionLevelLinking>true</FunctionLevelLinking>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<CompileAsWinRT>false</CompileAsWinRT>
<AdditionalUsingDirectories>$(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
<GenerateDebugInformation>false</GenerateDebugInformation>
<AdditionalDependencies>belle-sip_dll.lib;mediastreamer2_dll.lib;ws2_32.lib;ortp_dll.lib;gsm_dll.lib;speex_dll.lib;speexdsp_dll.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(SolutionDir)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<ImportLibrary>$(TargetDir)$(TargetName)_dll.lib</ImportLibrary>
</Link>
<CustomBuildStep>
<Outputs>$(TargetDir)$(TargetName)_dll.lib;%(Outputs)</Outputs>
</CustomBuildStep>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\..\coreapi\address.c" />
<ClCompile Include="..\..\..\coreapi\authentication.c" />
<ClCompile Include="..\..\..\coreapi\bellesip_sal\sal_address_impl.c" />
<ClCompile Include="..\..\..\coreapi\bellesip_sal\sal_impl.c" />
<ClCompile Include="..\..\..\coreapi\bellesip_sal\sal_op_call.c" />
<ClCompile Include="..\..\..\coreapi\bellesip_sal\sal_op_call_transfer.c" />
<ClCompile Include="..\..\..\coreapi\bellesip_sal\sal_op_events.c" />
<ClCompile Include="..\..\..\coreapi\bellesip_sal\sal_op_impl.c" />
<ClCompile Include="..\..\..\coreapi\bellesip_sal\sal_op_info.c" />
<ClCompile Include="..\..\..\coreapi\bellesip_sal\sal_op_message.c" />
<ClCompile Include="..\..\..\coreapi\bellesip_sal\sal_op_presence.c" />
<ClCompile Include="..\..\..\coreapi\bellesip_sal\sal_op_publish.c" />
<ClCompile Include="..\..\..\coreapi\bellesip_sal\sal_op_registration.c" />
<ClCompile Include="..\..\..\coreapi\bellesip_sal\sal_sdp.c" />
<ClCompile Include="..\..\..\coreapi\callbacks.c" />
<ClCompile Include="..\..\..\coreapi\chat.c" />
<ClCompile Include="..\..\..\coreapi\conference.c" />
<ClCompile Include="..\..\..\coreapi\ec-calibrator.c" />
<ClCompile Include="..\..\..\coreapi\enum.c" />
<ClCompile Include="..\..\..\coreapi\event.c" />
<ClCompile Include="..\..\..\coreapi\friend.c" />
<ClCompile Include="..\..\..\coreapi\info.c" />
<ClCompile Include="..\..\..\coreapi\linphonecall.c" />
<ClCompile Include="..\..\..\coreapi\linphonecore.c" />
<ClCompile Include="..\..\..\coreapi\linphone_tunnel.cc" />
<ClCompile Include="..\..\..\coreapi\linphone_tunnel_config.c" />
<ClCompile Include="..\..\..\coreapi\lpconfig.c" />
<ClCompile Include="..\..\..\coreapi\lsd.c" />
<ClCompile Include="..\..\..\coreapi\message_storage.c" />
<ClCompile Include="..\..\..\coreapi\misc.c" />
<ClCompile Include="..\..\..\coreapi\offeranswer.c" />
<ClCompile Include="..\..\..\coreapi\presence.c" />
<ClCompile Include="..\..\..\coreapi\proxy.c" />
<ClCompile Include="..\..\..\coreapi\quality_reporting.c" />
<ClCompile Include="..\..\..\coreapi\sal.c" />
<ClCompile Include="..\..\..\coreapi\siplogin.c" />
<ClCompile Include="..\..\..\coreapi\sipsetup.c" />
<ClCompile Include="..\..\..\coreapi\TunnelManager.cc" />
<ClCompile Include="..\..\..\coreapi\xml.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\coreapi\bellesip_sal\sal_impl.h" />
<ClInclude Include="..\..\..\coreapi\enum.h" />
<ClInclude Include="..\..\..\coreapi\event.h" />
<ClInclude Include="..\..\..\coreapi\linphonecore.h" />
<ClInclude Include="..\..\..\coreapi\linphonecore_utils.h" />
<ClInclude Include="..\..\..\coreapi\linphonefriend.h" />
<ClInclude Include="..\..\..\coreapi\linphone_tunnel.h" />
<ClInclude Include="..\..\..\coreapi\lpconfig.h" />
<ClInclude Include="..\..\..\coreapi\offeranswer.h" />
<ClInclude Include="..\..\..\coreapi\private.h" />
<ClInclude Include="..\..\..\coreapi\sipsetup.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\belle-sip\build\windows\belle-sip\belle-sip.vcxproj">
<Project>{4c225a82-800b-427b-ba7b-61686a9b347f}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\..\mediastreamer2\build\vsx\mediastreamer2\mediastreamer2\mediastreamer2.vcxproj">
<Project>{027bad0e-9179-48c1-9733-7aa7e2c2ec70}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\..\msamr\build\windows\msamr\msamr\msamr.vcxproj">
<Project>{9924ac72-f96c-4e56-94d9-2b025da43c6b}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\..\msilbc\build\windows\msilbc\msilbc\msilbc.vcxproj">
<Project>{072fad20-7007-4da2-b2e7-16ce2b219f67}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\..\msisac\build\windows\msisac\msisac\msisac.vcxproj">
<Project>{b16b81a9-bef2-44c9-b603-1065183ae844}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\..\mssilk\build\windows\mssilk\mssilk\mssilk.vcxproj">
<Project>{36b528f9-fb79-4078-a16b-0a7442581bb7}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\..\mswasapi\mswasapi\mswasapi\mswasapi.vcxproj">
<Project>{d22bd217-d0f8-4274-9b3a-f3f35f46482c}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\..\oRTP\build\vsx\oRTP\oRTP\oRTP.vcxproj">
<Project>{ffc7b532-0502-4d88-ac98-9e89071cbc97}</Project>
<Private>false</Private>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
<UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
</ProjectReference>
<ProjectReference Include="..\..\..\..\tunnel\build\windows\tunnel\tunnel\tunnel.vcxproj">
<Project>{59500dd1-b192-4ddf-a402-8a8e3739e032}</Project>
</ProjectReference>
<ProjectReference Include="..\libxml2\libxml2\libxml2.vcxproj">
<Project>{5dfa07b4-0be9-46a9-ba32-fdf5a55c580b}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup Condition="'$(Platform)'=='ARM'">
<Reference Include="Windows">
<IsWinMDFile>true</IsWinMDFile>
</Reference>
<Reference Include="platform.winmd">
<IsWinMDFile>true</IsWinMDFile>
<Private>false</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<None Include="..\..\..\coreapi\TunnelManager.hh" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsPhone\v$(TargetPlatformVersion)\Microsoft.Cpp.WindowsPhone.$(TargetPlatformVersion).targets" Condition="'$(Platform)'=='ARM'" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -1,522 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Express 2012 for Windows Phone
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibLinphoneTester-wp8", "LibLinphoneTester-wp8\LibLinphoneTester-wp8.csproj", "{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}"
ProjectSection(ProjectDependencies) = postProject
{5E94A00B-B14A-4E42-8284-8CB0EF099534} = {5E94A00B-B14A-4E42-8284-8CB0EF099534}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibLinphone", "..\LibLinphone\LibLinphone.vcxproj", "{08DD0D38-D9B5-4626-B60D-B4D76B571142}"
ProjectSection(ProjectDependencies) = postProject
{D22BD217-D0F8-4274-9B3A-F3F35F46482C} = {D22BD217-D0F8-4274-9B3A-F3F35F46482C}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibLinphoneTester", "..\LibLinphoneTester\LibLinphoneTester.vcxproj", "{5E94A00B-B14A-4E42-8284-8CB0EF099534}"
ProjectSection(ProjectDependencies) = postProject
{902DAF1D-EBF1-4D03-B598-143500A50AB4} = {902DAF1D-EBF1-4D03-B598-143500A50AB4}
{08DD0D38-D9B5-4626-B60D-B4D76B571142} = {08DD0D38-D9B5-4626-B60D-B4D76B571142}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "belle-sip", "..\..\..\..\belle-sip\build\windows\belle-sip\belle-sip.vcxproj", "{4C225A82-800B-427B-BA7B-61686A9B347F}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mediastreamer2", "..\..\..\..\mediastreamer2\build\vsx\mediastreamer2\mediastreamer2\mediastreamer2.vcxproj", "{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "oRTP", "..\..\..\..\oRTP\build\vsx\oRTP\oRTP\oRTP.vcxproj", "{FFC7B532-0502-4D88-AC98-9E89071CBC97}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libantlr3c", "..\..\..\..\antlr3\runtime\C\build\vsx\libantlr3c\libantlr3c.vcxproj", "{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gsm", "..\..\..\..\gsm\build\windows\gsm\gsm\gsm.vcxproj", "{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "speex", "..\..\..\..\speex\build\windows\speex\speex\speex.vcxproj", "{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "speexdsp", "..\..\..\..\speex\build\windows\speex\speexdsp\speexdsp.vcxproj", "{6BD78980-9C71-4341-8775-AD19E9EC7305}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cunit", "..\..\..\..\cunit\build\windows\cunit\cunit.vcxproj", "{902DAF1D-EBF1-4D03-B598-143500A50AB4}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmswasapi", "..\..\..\..\mswasapi\mswasapi\mswasapi\mswasapi.vcxproj", "{D22BD217-D0F8-4274-9B3A-F3F35F46482C}"
ProjectSection(ProjectDependencies) = postProject
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70} = {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}
{FFC7B532-0502-4D88-AC98-9E89071CBC97} = {FFC7B532-0502-4D88-AC98-9E89071CBC97}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "webrtcaecm", "..\..\..\..\webrtc\build\windows\webrtcaecm\webrtcaecm\webrtcaecm.vcxproj", "{1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libilbc-rfc3951", "..\..\..\..\libilbc-rfc3951\build\windows\libilbc-rfc3951\libilbc-rfc3951\libilbc-rfc3951.vcxproj", "{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmsilbc", "..\..\..\..\msilbc\build\windows\msilbc\msilbc\msilbc.vcxproj", "{072FAD20-7007-4DA2-B2E7-16CE2B219F67}"
ProjectSection(ProjectDependencies) = postProject
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70} = {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}
{FFC7B532-0502-4D88-AC98-9E89071CBC97} = {FFC7B532-0502-4D88-AC98-9E89071CBC97}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmssilk", "..\..\..\..\mssilk\build\windows\mssilk\mssilk\mssilk.vcxproj", "{36B528F9-FB79-4078-A16B-0A7442581BB7}"
ProjectSection(ProjectDependencies) = postProject
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70} = {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}
{FFC7B532-0502-4D88-AC98-9E89071CBC97} = {FFC7B532-0502-4D88-AC98-9E89071CBC97}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmsamr", "..\..\..\..\msamr\build\windows\msamr\msamr\msamr.vcxproj", "{9924AC72-F96C-4E56-94D9-2B025DA43C6B}"
ProjectSection(ProjectDependencies) = postProject
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70} = {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}
{018A4428-535C-4566-9AE0-E93AFF0D3ED2} = {018A4428-535C-4566-9AE0-E93AFF0D3ED2}
{7AC65D2A-6981-4D17-856D-C37A522739D8} = {7AC65D2A-6981-4D17-856D-C37A522739D8}
{88191E75-2993-48D7-AA76-652F274EF0FE} = {88191E75-2993-48D7-AA76-652F274EF0FE}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vo-amrwbenc", "..\..\..\..\msamr\build\windows\msamr\vo-amrwbenc\vo-amrwbenc.vcxproj", "{018A4428-535C-4566-9AE0-E93AFF0D3ED2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opencore_amrnb", "..\..\..\..\msamr\build\windows\msamr\opencore_amrnb\opencore_amrnb.vcxproj", "{88191E75-2993-48D7-AA76-652F274EF0FE}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opencore_amrwb", "..\..\..\..\msamr\build\windows\msamr\opencore_amrwb\opencore_amrwb.vcxproj", "{7AC65D2A-6981-4D17-856D-C37A522739D8}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "polarssl", "..\..\..\..\polarssl\build\windows\polarssl\polarssl\polarssl.vcxproj", "{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tunnel", "..\..\..\..\tunnel\build\windows\tunnel\tunnel\tunnel.vcxproj", "{59500DD1-B192-4DDF-A402-8A8E3739E032}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libxml2", "..\libxml2\libxml2\libxml2.vcxproj", "{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|ARM = Debug|ARM
Debug|Mixed Platforms = Debug|Mixed Platforms
Debug|Win32 = Debug|Win32
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|ARM = Release|ARM
Release|Mixed Platforms = Release|Mixed Platforms
Release|Win32 = Release|Win32
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Any CPU.Build.0 = Debug|Any CPU
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|ARM.ActiveCfg = Debug|ARM
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|ARM.Build.0 = Debug|ARM
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|ARM.Deploy.0 = Debug|ARM
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Mixed Platforms.ActiveCfg = Debug|ARM
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Mixed Platforms.Build.0 = Debug|ARM
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Mixed Platforms.Deploy.0 = Debug|ARM
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Win32.ActiveCfg = Debug|x86
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Win32.Build.0 = Debug|x86
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Win32.Deploy.0 = Debug|x86
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|x86.ActiveCfg = Debug|x86
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|x86.Build.0 = Debug|x86
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|x86.Deploy.0 = Debug|x86
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|Any CPU.ActiveCfg = Release|Any CPU
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|Any CPU.Build.0 = Release|Any CPU
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|Any CPU.Deploy.0 = Release|Any CPU
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|ARM.ActiveCfg = Release|ARM
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|ARM.Build.0 = Release|ARM
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|ARM.Deploy.0 = Release|ARM
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|Mixed Platforms.ActiveCfg = Release|x86
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|Mixed Platforms.Build.0 = Release|x86
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|Mixed Platforms.Deploy.0 = Release|x86
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|Win32.ActiveCfg = Release|x86
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|Win32.Build.0 = Release|x86
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|Win32.Deploy.0 = Release|x86
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|x86.ActiveCfg = Release|x86
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|x86.Build.0 = Release|x86
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|x86.Deploy.0 = Release|x86
{08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|Any CPU.ActiveCfg = Debug|Win32
{08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|ARM.ActiveCfg = Debug|ARM
{08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|ARM.Build.0 = Debug|ARM
{08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|Mixed Platforms.ActiveCfg = Debug|ARM
{08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|Mixed Platforms.Build.0 = Debug|ARM
{08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|Win32.ActiveCfg = Debug|Win32
{08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|Win32.Build.0 = Debug|Win32
{08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|x86.ActiveCfg = Debug|Win32
{08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|x86.Build.0 = Debug|Win32
{08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|Any CPU.ActiveCfg = Release|Win32
{08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|ARM.ActiveCfg = Release|ARM
{08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|ARM.Build.0 = Release|ARM
{08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|Mixed Platforms.Build.0 = Release|Win32
{08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|Win32.ActiveCfg = Release|Win32
{08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|Win32.Build.0 = Release|Win32
{08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|x86.ActiveCfg = Release|Win32
{08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|x86.Build.0 = Release|Win32
{5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|Any CPU.ActiveCfg = Debug|Win32
{5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|ARM.ActiveCfg = Debug|ARM
{5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|ARM.Build.0 = Debug|ARM
{5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|Mixed Platforms.ActiveCfg = Debug|ARM
{5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|Mixed Platforms.Build.0 = Debug|ARM
{5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|Win32.ActiveCfg = Debug|Win32
{5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|Win32.Build.0 = Debug|Win32
{5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|x86.ActiveCfg = Debug|Win32
{5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|x86.Build.0 = Debug|Win32
{5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|Any CPU.ActiveCfg = Release|Win32
{5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|ARM.ActiveCfg = Release|ARM
{5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|ARM.Build.0 = Release|ARM
{5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|Mixed Platforms.Build.0 = Release|Win32
{5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|Win32.ActiveCfg = Release|Win32
{5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|Win32.Build.0 = Release|Win32
{5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|x86.ActiveCfg = Release|Win32
{5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|x86.Build.0 = Release|Win32
{4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|Any CPU.ActiveCfg = Debug|Win32
{4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|ARM.ActiveCfg = Debug|ARM
{4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|ARM.Build.0 = Debug|ARM
{4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|Mixed Platforms.ActiveCfg = Debug|ARM
{4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|Mixed Platforms.Build.0 = Debug|ARM
{4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|Win32.ActiveCfg = Debug|Win32
{4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|Win32.Build.0 = Debug|Win32
{4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|x86.ActiveCfg = Debug|Win32
{4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|x86.Build.0 = Debug|Win32
{4C225A82-800B-427B-BA7B-61686A9B347F}.Release|Any CPU.ActiveCfg = Release|Win32
{4C225A82-800B-427B-BA7B-61686A9B347F}.Release|ARM.ActiveCfg = Release|ARM
{4C225A82-800B-427B-BA7B-61686A9B347F}.Release|ARM.Build.0 = Release|ARM
{4C225A82-800B-427B-BA7B-61686A9B347F}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{4C225A82-800B-427B-BA7B-61686A9B347F}.Release|Mixed Platforms.Build.0 = Release|Win32
{4C225A82-800B-427B-BA7B-61686A9B347F}.Release|Win32.ActiveCfg = Release|Win32
{4C225A82-800B-427B-BA7B-61686A9B347F}.Release|Win32.Build.0 = Release|Win32
{4C225A82-800B-427B-BA7B-61686A9B347F}.Release|x86.ActiveCfg = Release|Win32
{4C225A82-800B-427B-BA7B-61686A9B347F}.Release|x86.Build.0 = Release|Win32
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|Any CPU.ActiveCfg = Debug|Win32
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|ARM.ActiveCfg = Debug|ARM
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|ARM.Build.0 = Debug|ARM
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|Mixed Platforms.ActiveCfg = Debug|ARM
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|Mixed Platforms.Build.0 = Debug|ARM
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|Win32.ActiveCfg = Debug|Win32
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|Win32.Build.0 = Debug|Win32
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|x86.ActiveCfg = Debug|Win32
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|x86.Build.0 = Debug|Win32
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|Any CPU.ActiveCfg = Release|Win32
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|ARM.ActiveCfg = Release|ARM
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|ARM.Build.0 = Release|ARM
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|Mixed Platforms.Build.0 = Release|Win32
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|Win32.ActiveCfg = Release|Win32
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|Win32.Build.0 = Release|Win32
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|x86.ActiveCfg = Release|Win32
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|x86.Build.0 = Release|Win32
{FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|Any CPU.ActiveCfg = Debug|Win32
{FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|ARM.ActiveCfg = Debug|ARM
{FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|ARM.Build.0 = Debug|ARM
{FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|Mixed Platforms.ActiveCfg = Debug|ARM
{FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|Mixed Platforms.Build.0 = Debug|ARM
{FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|Win32.ActiveCfg = Debug|Win32
{FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|Win32.Build.0 = Debug|Win32
{FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|x86.ActiveCfg = Debug|Win32
{FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|x86.Build.0 = Debug|Win32
{FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|Any CPU.ActiveCfg = Release|Win32
{FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|ARM.ActiveCfg = Release|ARM
{FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|ARM.Build.0 = Release|ARM
{FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|Mixed Platforms.Build.0 = Release|Win32
{FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|Win32.ActiveCfg = Release|Win32
{FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|Win32.Build.0 = Release|Win32
{FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|x86.ActiveCfg = Release|Win32
{FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|x86.Build.0 = Release|Win32
{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|Any CPU.ActiveCfg = Debug|Win32
{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|ARM.ActiveCfg = Debug|ARM
{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|ARM.Build.0 = Debug|ARM
{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|Mixed Platforms.ActiveCfg = Debug|ARM
{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|Mixed Platforms.Build.0 = Debug|ARM
{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|Win32.ActiveCfg = Debug|Win32
{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|Win32.Build.0 = Debug|Win32
{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|x86.ActiveCfg = Debug|Win32
{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|x86.Build.0 = Debug|Win32
{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|Any CPU.ActiveCfg = Release|Win32
{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|ARM.ActiveCfg = Release|ARM
{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|ARM.Build.0 = Release|ARM
{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|Mixed Platforms.Build.0 = Release|Win32
{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|Win32.ActiveCfg = Release|Win32
{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|Win32.Build.0 = Release|Win32
{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|x86.ActiveCfg = Release|Win32
{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|x86.Build.0 = Release|Win32
{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|Any CPU.ActiveCfg = Debug|Win32
{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|ARM.ActiveCfg = Debug|ARM
{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|ARM.Build.0 = Debug|ARM
{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|Mixed Platforms.ActiveCfg = Debug|ARM
{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|Mixed Platforms.Build.0 = Debug|ARM
{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|Win32.ActiveCfg = Debug|Win32
{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|Win32.Build.0 = Debug|Win32
{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|x86.ActiveCfg = Debug|Win32
{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|x86.Build.0 = Debug|Win32
{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|Any CPU.ActiveCfg = Release|Win32
{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|ARM.ActiveCfg = Release|ARM
{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|ARM.Build.0 = Release|ARM
{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|Mixed Platforms.Build.0 = Release|Win32
{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|Win32.ActiveCfg = Release|Win32
{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|Win32.Build.0 = Release|Win32
{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|x86.ActiveCfg = Release|Win32
{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|x86.Build.0 = Release|Win32
{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|Any CPU.ActiveCfg = Debug|Win32
{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|ARM.ActiveCfg = Debug|ARM
{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|ARM.Build.0 = Debug|ARM
{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|Mixed Platforms.ActiveCfg = Debug|ARM
{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|Mixed Platforms.Build.0 = Debug|ARM
{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|Win32.ActiveCfg = Debug|Win32
{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|Win32.Build.0 = Debug|Win32
{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|x86.ActiveCfg = Debug|Win32
{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|x86.Build.0 = Debug|Win32
{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|Any CPU.ActiveCfg = Release|Win32
{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|ARM.ActiveCfg = Release|ARM
{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|ARM.Build.0 = Release|ARM
{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|Mixed Platforms.Build.0 = Release|Win32
{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|Win32.ActiveCfg = Release|Win32
{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|Win32.Build.0 = Release|Win32
{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|x86.ActiveCfg = Release|Win32
{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|x86.Build.0 = Release|Win32
{6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|Any CPU.ActiveCfg = Debug|Win32
{6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|ARM.ActiveCfg = Debug|ARM
{6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|ARM.Build.0 = Debug|ARM
{6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|Mixed Platforms.ActiveCfg = Debug|ARM
{6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|Mixed Platforms.Build.0 = Debug|ARM
{6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|Win32.ActiveCfg = Debug|Win32
{6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|Win32.Build.0 = Debug|Win32
{6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|x86.ActiveCfg = Debug|Win32
{6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|x86.Build.0 = Debug|Win32
{6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|Any CPU.ActiveCfg = Release|Win32
{6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|ARM.ActiveCfg = Release|ARM
{6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|ARM.Build.0 = Release|ARM
{6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|Mixed Platforms.Build.0 = Release|Win32
{6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|Win32.ActiveCfg = Release|Win32
{6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|Win32.Build.0 = Release|Win32
{6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|x86.ActiveCfg = Release|Win32
{6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|x86.Build.0 = Release|Win32
{902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|Any CPU.ActiveCfg = Debug|Win32
{902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|ARM.ActiveCfg = Debug|ARM
{902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|ARM.Build.0 = Debug|ARM
{902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|Mixed Platforms.ActiveCfg = Debug|ARM
{902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|Mixed Platforms.Build.0 = Debug|ARM
{902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|Win32.ActiveCfg = Debug|Win32
{902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|Win32.Build.0 = Debug|Win32
{902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|x86.ActiveCfg = Debug|Win32
{902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|x86.Build.0 = Debug|Win32
{902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|Any CPU.ActiveCfg = Release|Win32
{902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|ARM.ActiveCfg = Release|ARM
{902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|ARM.Build.0 = Release|ARM
{902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|Mixed Platforms.Build.0 = Release|Win32
{902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|Win32.ActiveCfg = Release|Win32
{902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|Win32.Build.0 = Release|Win32
{902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|x86.ActiveCfg = Release|Win32
{902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|x86.Build.0 = Release|Win32
{D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|Any CPU.ActiveCfg = Debug|Win32
{D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|ARM.ActiveCfg = Debug|ARM
{D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|ARM.Build.0 = Debug|ARM
{D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
{D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|Mixed Platforms.Build.0 = Debug|Win32
{D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|Win32.ActiveCfg = Debug|Win32
{D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|Win32.Build.0 = Debug|Win32
{D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|x86.ActiveCfg = Debug|Win32
{D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|x86.Build.0 = Debug|Win32
{D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|Any CPU.ActiveCfg = Release|Win32
{D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|ARM.ActiveCfg = Release|ARM
{D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|ARM.Build.0 = Release|ARM
{D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|Mixed Platforms.Build.0 = Release|Win32
{D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|Win32.ActiveCfg = Release|Win32
{D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|Win32.Build.0 = Release|Win32
{D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|x86.ActiveCfg = Release|Win32
{D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|x86.Build.0 = Release|Win32
{1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Debug|Any CPU.ActiveCfg = Debug|Win32
{1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Debug|ARM.ActiveCfg = Debug|ARM
{1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Debug|ARM.Build.0 = Debug|ARM
{1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
{1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Debug|Mixed Platforms.Build.0 = Debug|Win32
{1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Debug|Win32.ActiveCfg = Debug|Win32
{1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Debug|Win32.Build.0 = Debug|Win32
{1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Debug|x86.ActiveCfg = Debug|Win32
{1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Debug|x86.Build.0 = Debug|Win32
{1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|Any CPU.ActiveCfg = Release|Win32
{1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|ARM.ActiveCfg = Release|ARM
{1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|ARM.Build.0 = Release|ARM
{1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|Mixed Platforms.Build.0 = Release|Win32
{1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|Win32.ActiveCfg = Release|Win32
{1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|Win32.Build.0 = Release|Win32
{1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|x86.ActiveCfg = Release|Win32
{1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|x86.Build.0 = Release|Win32
{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|Any CPU.ActiveCfg = Debug|Win32
{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|ARM.ActiveCfg = Debug|ARM
{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|ARM.Build.0 = Debug|ARM
{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|Mixed Platforms.Build.0 = Debug|Win32
{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|Win32.ActiveCfg = Debug|Win32
{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|Win32.Build.0 = Debug|Win32
{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|x86.ActiveCfg = Debug|Win32
{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|x86.Build.0 = Debug|Win32
{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|Any CPU.ActiveCfg = Release|Win32
{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|ARM.ActiveCfg = Release|ARM
{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|ARM.Build.0 = Release|ARM
{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|Mixed Platforms.Build.0 = Release|Win32
{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|Win32.ActiveCfg = Release|Win32
{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|Win32.Build.0 = Release|Win32
{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|x86.ActiveCfg = Release|Win32
{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|x86.Build.0 = Release|Win32
{072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|Any CPU.ActiveCfg = Debug|Win32
{072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|ARM.ActiveCfg = Debug|ARM
{072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|ARM.Build.0 = Debug|ARM
{072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
{072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|Mixed Platforms.Build.0 = Debug|Win32
{072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|Win32.ActiveCfg = Debug|Win32
{072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|Win32.Build.0 = Debug|Win32
{072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|x86.ActiveCfg = Debug|Win32
{072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|x86.Build.0 = Debug|Win32
{072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|Any CPU.ActiveCfg = Release|Win32
{072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|ARM.ActiveCfg = Release|ARM
{072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|ARM.Build.0 = Release|ARM
{072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|Mixed Platforms.Build.0 = Release|Win32
{072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|Win32.ActiveCfg = Release|Win32
{072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|Win32.Build.0 = Release|Win32
{072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|x86.ActiveCfg = Release|Win32
{072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|x86.Build.0 = Release|Win32
{36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|Any CPU.ActiveCfg = Debug|Win32
{36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|ARM.ActiveCfg = Debug|ARM
{36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|ARM.Build.0 = Debug|ARM
{36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
{36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|Mixed Platforms.Build.0 = Debug|Win32
{36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|Win32.ActiveCfg = Debug|Win32
{36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|Win32.Build.0 = Debug|Win32
{36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|x86.ActiveCfg = Debug|Win32
{36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|x86.Build.0 = Debug|Win32
{36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|Any CPU.ActiveCfg = Release|Win32
{36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|ARM.ActiveCfg = Release|ARM
{36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|ARM.Build.0 = Release|ARM
{36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|Mixed Platforms.Build.0 = Release|Win32
{36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|Win32.ActiveCfg = Release|Win32
{36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|Win32.Build.0 = Release|Win32
{36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|x86.ActiveCfg = Release|Win32
{36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|x86.Build.0 = Release|Win32
{9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|Any CPU.ActiveCfg = Debug|Win32
{9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|ARM.ActiveCfg = Debug|ARM
{9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|ARM.Build.0 = Debug|ARM
{9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
{9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|Mixed Platforms.Build.0 = Debug|Win32
{9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|Win32.ActiveCfg = Debug|Win32
{9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|Win32.Build.0 = Debug|Win32
{9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|x86.ActiveCfg = Debug|Win32
{9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|x86.Build.0 = Debug|Win32
{9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|Any CPU.ActiveCfg = Release|Win32
{9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|ARM.ActiveCfg = Release|ARM
{9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|ARM.Build.0 = Release|ARM
{9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|Mixed Platforms.Build.0 = Release|Win32
{9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|Win32.ActiveCfg = Release|Win32
{9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|Win32.Build.0 = Release|Win32
{9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|x86.ActiveCfg = Release|Win32
{9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|x86.Build.0 = Release|Win32
{018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|Any CPU.ActiveCfg = Debug|Win32
{018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|ARM.ActiveCfg = Debug|ARM
{018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|ARM.Build.0 = Debug|ARM
{018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
{018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|Mixed Platforms.Build.0 = Debug|Win32
{018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|Win32.ActiveCfg = Debug|Win32
{018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|Win32.Build.0 = Debug|Win32
{018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|x86.ActiveCfg = Debug|Win32
{018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|x86.Build.0 = Debug|Win32
{018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|Any CPU.ActiveCfg = Release|Win32
{018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|ARM.ActiveCfg = Release|ARM
{018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|ARM.Build.0 = Release|ARM
{018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|Mixed Platforms.Build.0 = Release|Win32
{018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|Win32.ActiveCfg = Release|Win32
{018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|Win32.Build.0 = Release|Win32
{018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|x86.ActiveCfg = Release|Win32
{018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|x86.Build.0 = Release|Win32
{88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|Any CPU.ActiveCfg = Debug|Win32
{88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|ARM.ActiveCfg = Debug|ARM
{88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|ARM.Build.0 = Debug|ARM
{88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
{88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|Mixed Platforms.Build.0 = Debug|Win32
{88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|Win32.ActiveCfg = Debug|Win32
{88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|Win32.Build.0 = Debug|Win32
{88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|x86.ActiveCfg = Debug|Win32
{88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|x86.Build.0 = Debug|Win32
{88191E75-2993-48D7-AA76-652F274EF0FE}.Release|Any CPU.ActiveCfg = Release|Win32
{88191E75-2993-48D7-AA76-652F274EF0FE}.Release|ARM.ActiveCfg = Release|ARM
{88191E75-2993-48D7-AA76-652F274EF0FE}.Release|ARM.Build.0 = Release|ARM
{88191E75-2993-48D7-AA76-652F274EF0FE}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{88191E75-2993-48D7-AA76-652F274EF0FE}.Release|Mixed Platforms.Build.0 = Release|Win32
{88191E75-2993-48D7-AA76-652F274EF0FE}.Release|Win32.ActiveCfg = Release|Win32
{88191E75-2993-48D7-AA76-652F274EF0FE}.Release|Win32.Build.0 = Release|Win32
{88191E75-2993-48D7-AA76-652F274EF0FE}.Release|x86.ActiveCfg = Release|Win32
{88191E75-2993-48D7-AA76-652F274EF0FE}.Release|x86.Build.0 = Release|Win32
{7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|Any CPU.ActiveCfg = Debug|Win32
{7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|ARM.ActiveCfg = Debug|ARM
{7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|ARM.Build.0 = Debug|ARM
{7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
{7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|Mixed Platforms.Build.0 = Debug|Win32
{7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|Win32.ActiveCfg = Debug|Win32
{7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|Win32.Build.0 = Debug|Win32
{7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|x86.ActiveCfg = Debug|Win32
{7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|x86.Build.0 = Debug|Win32
{7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|Any CPU.ActiveCfg = Release|Win32
{7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|ARM.ActiveCfg = Release|ARM
{7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|ARM.Build.0 = Release|ARM
{7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|Mixed Platforms.Build.0 = Release|Win32
{7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|Win32.ActiveCfg = Release|Win32
{7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|Win32.Build.0 = Release|Win32
{7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|x86.ActiveCfg = Release|Win32
{7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|x86.Build.0 = Release|Win32
{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|Any CPU.ActiveCfg = Debug|Win32
{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|ARM.ActiveCfg = Debug|ARM
{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|ARM.Build.0 = Debug|ARM
{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|Mixed Platforms.Build.0 = Debug|Win32
{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|Win32.ActiveCfg = Debug|Win32
{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|Win32.Build.0 = Debug|Win32
{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|x86.ActiveCfg = Debug|Win32
{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|x86.Build.0 = Debug|Win32
{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|Any CPU.ActiveCfg = Release|Win32
{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|ARM.ActiveCfg = Release|ARM
{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|ARM.Build.0 = Release|ARM
{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|Mixed Platforms.Build.0 = Release|Win32
{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|Win32.ActiveCfg = Release|Win32
{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|Win32.Build.0 = Release|Win32
{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|x86.ActiveCfg = Release|Win32
{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|x86.Build.0 = Release|Win32
{59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|Any CPU.ActiveCfg = Debug|Win32
{59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|ARM.ActiveCfg = Debug|ARM
{59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|ARM.Build.0 = Debug|ARM
{59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
{59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|Mixed Platforms.Build.0 = Debug|Win32
{59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|Win32.ActiveCfg = Debug|Win32
{59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|Win32.Build.0 = Debug|Win32
{59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|x86.ActiveCfg = Debug|Win32
{59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|x86.Build.0 = Debug|Win32
{59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|Any CPU.ActiveCfg = Release|Win32
{59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|ARM.ActiveCfg = Release|ARM
{59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|ARM.Build.0 = Release|ARM
{59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|Mixed Platforms.Build.0 = Release|Win32
{59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|Win32.ActiveCfg = Release|Win32
{59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|Win32.Build.0 = Release|Win32
{59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|x86.ActiveCfg = Release|Win32
{59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|x86.Build.0 = Release|Win32
{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|Any CPU.ActiveCfg = Debug|Win32
{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|ARM.ActiveCfg = Debug|ARM
{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|ARM.Build.0 = Debug|ARM
{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|Mixed Platforms.Build.0 = Debug|Win32
{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|Win32.ActiveCfg = Debug|Win32
{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|Win32.Build.0 = Debug|Win32
{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|x86.ActiveCfg = Debug|Win32
{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|x86.Build.0 = Debug|Win32
{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|Any CPU.ActiveCfg = Release|Win32
{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|ARM.ActiveCfg = Release|ARM
{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|ARM.Build.0 = Release|ARM
{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|Mixed Platforms.Build.0 = Release|Win32
{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|Win32.ActiveCfg = Release|Win32
{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|Win32.Build.0 = Release|Win32
{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|x86.ActiveCfg = Release|Win32
{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View file

@ -1,45 +0,0 @@
[sip]
sip_port=5082
sip_tcp_port=5082
sip_tls_port=5083
default_proxy=0
ping_with_options=0
register_only_when_network_is_up=0
incoming_calls_early_media=1
[auth_info_0]
username=marie
userid=marie
passwd=secret
realm="sip.example.org"
[proxy_0]
reg_proxy=sip.example.org;transport=tcp
reg_route=sip.example.org;transport=tcp;lr
reg_identity=sip:marie@sip.example.org
reg_expires=3600
reg_sendregister=1
publish=0
dial_escape_plus=0
[friend_0]
url="Paupoche" <sip:pauline@sip.example.org>
pol=accept
subscribe=0
[rtp]
audio_rtp_port=8070
video_rtp_port=8072
[video]
display=0
capture=0
show_local=0
size=vga
enabled=0
self_view=0
automatically_initiate=0
automatically_accept=0
device=StaticImage: Static picture

View file

@ -1,249 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM">
<Configuration>Debug</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM">
<Configuration>Release</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{5dfa07b4-0be9-46a9-ba32-fdf5a55c580b}</ProjectGuid>
<RootNamespace>libxml2</RootNamespace>
<DefaultLanguage>en-US</DefaultLanguage>
<MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v110</PlatformToolset>
<IgnoreImportLibrary>false</IgnoreImportLibrary>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v110_wp80</PlatformToolset>
<IgnoreImportLibrary>false</IgnoreImportLibrary>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v110</PlatformToolset>
<IgnoreImportLibrary>false</IgnoreImportLibrary>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v110_wp80</PlatformToolset>
<IgnoreImportLibrary>false</IgnoreImportLibrary>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\$(TargetName)\</IntDir>
</PropertyGroup>
<PropertyGroup>
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<AdditionalIncludeDirectories>$(SolutionDir)$(Platform)\$(Configuration)\include;$(ProjectDir)..\..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_WIN32;_WINDLL;_USRDLL;_CRT_SECURE_NO_WARNINGS;HAVE_WIN32_THREADS;HAVE_COMPILER_TLS;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<UndefinePreprocessorDefinitions>LIBXML_MODULES_ENABLED</UndefinePreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<CompileAsWinRT>false</CompileAsWinRT>
<AdditionalUsingDirectories>$(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<ForcedIncludeFiles>$(ProjectDir)libxml2_port.h</ForcedIncludeFiles>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ImportLibrary>$(TargetDir)$(TargetName)_dll.lib</ImportLibrary>
<AdditionalDependencies>Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>install_headers.bat $(SolutionDir)$(Platform)\$(Configuration)\include</Command>
</PreBuildEvent>
<CustomBuildStep>
<Outputs>$(TargetDir)$(TargetName)_dll.lib;%(Outputs)</Outputs>
</CustomBuildStep>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<AdditionalIncludeDirectories>$(SolutionDir)$(Platform)\$(Configuration)\include;$(ProjectDir)..\..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_WIN32;_WINDLL;_USRDLL;NDEBUG;_CRT_SECURE_NO_WARNINGS;HAVE_WIN32_THREADS;HAVE_COMPILER_TLS;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<UndefinePreprocessorDefinitions>LIBXML_MODULES_ENABLED</UndefinePreprocessorDefinitions>
<StringPooling>true</StringPooling>
<FunctionLevelLinking>true</FunctionLevelLinking>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<CompileAsWinRT>false</CompileAsWinRT>
<AdditionalUsingDirectories>$(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<ForcedIncludeFiles>$(ProjectDir)libxml2_port.h</ForcedIncludeFiles>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
<GenerateDebugInformation>false</GenerateDebugInformation>
<ImportLibrary>$(TargetDir)$(TargetName)_dll.lib</ImportLibrary>
<AdditionalDependencies>Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>install_headers.bat $(SolutionDir)$(Platform)\$(Configuration)\include</Command>
</PreBuildEvent>
<CustomBuildStep>
<Outputs>$(TargetDir)$(TargetName)_dll.lib;%(Outputs)</Outputs>
</CustomBuildStep>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<AdditionalIncludeDirectories>$(SolutionDir)$(Platform)\$(Configuration)\include;$(ProjectDir)..\..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_WIN32;WIN32;_WINDLL;_USRDLL;_CRT_SECURE_NO_WARNINGS;HAVE_WIN32_THREADS;HAVE_COMPILER_TLS;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<UndefinePreprocessorDefinitions>LIBXML_MODULES_ENABLED</UndefinePreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<CompileAsWinRT>false</CompileAsWinRT>
<AdditionalUsingDirectories>$(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<ForcedIncludeFiles>$(ProjectDir)libxml2_port.h</ForcedIncludeFiles>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ImportLibrary>$(TargetDir)$(TargetName)_dll.lib</ImportLibrary>
<AdditionalDependencies>Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>install_headers.bat $(SolutionDir)$(Platform)\$(Configuration)\include</Command>
</PreBuildEvent>
<CustomBuildStep>
<Outputs>$(TargetDir)$(TargetName)_dll.lib;%(Outputs)</Outputs>
</CustomBuildStep>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<AdditionalIncludeDirectories>$(SolutionDir)$(Platform)\$(Configuration)\include;$(ProjectDir)..\..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_WIN32;_WINDLL;_USRDLL;NDEBUG;_CRT_SECURE_NO_WARNINGS;HAVE_WIN32_THREADS;HAVE_COMPILER_TLS;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<UndefinePreprocessorDefinitions>LIBXML_MODULES_ENABLED</UndefinePreprocessorDefinitions>
<StringPooling>true</StringPooling>
<FunctionLevelLinking>true</FunctionLevelLinking>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<CompileAsWinRT>false</CompileAsWinRT>
<AdditionalUsingDirectories>$(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<ForcedIncludeFiles>$(ProjectDir)libxml2_port.h</ForcedIncludeFiles>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
<GenerateDebugInformation>false</GenerateDebugInformation>
<ImportLibrary>$(TargetDir)$(TargetName)_dll.lib</ImportLibrary>
<AdditionalDependencies>Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>install_headers.bat $(SolutionDir)$(Platform)\$(Configuration)\include</Command>
</PreBuildEvent>
<CustomBuildStep>
<Outputs>$(TargetDir)$(TargetName)_dll.lib;%(Outputs)</Outputs>
</CustomBuildStep>
</ItemDefinitionGroup>
<ItemGroup>
<Reference Include="Windows" Condition="'$(Platform)'=='ARM'">
<IsWinMDFile>true</IsWinMDFile>
</Reference>
<Reference Include="platform.winmd">
<IsWinMDFile>true</IsWinMDFile>
<Private>false</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\..\..\libxml2\c14n.c" />
<ClCompile Include="..\..\..\..\..\libxml2\catalog.c" />
<ClCompile Include="..\..\..\..\..\libxml2\chvalid.c" />
<ClCompile Include="..\..\..\..\..\libxml2\debugXML.c" />
<ClCompile Include="..\..\..\..\..\libxml2\dict.c" />
<ClCompile Include="..\..\..\..\..\libxml2\DOCBparser.c" />
<ClCompile Include="..\..\..\..\..\libxml2\encoding.c" />
<ClCompile Include="..\..\..\..\..\libxml2\entities.c" />
<ClCompile Include="..\..\..\..\..\libxml2\error.c" />
<ClCompile Include="..\..\..\..\..\libxml2\globals.c" />
<ClCompile Include="..\..\..\..\..\libxml2\hash.c" />
<ClCompile Include="..\..\..\..\..\libxml2\HTMLparser.c" />
<ClCompile Include="..\..\..\..\..\libxml2\HTMLtree.c" />
<ClCompile Include="..\..\..\..\..\libxml2\legacy.c" />
<ClCompile Include="..\..\..\..\..\libxml2\list.c" />
<ClCompile Include="..\..\..\..\..\libxml2\nanoftp.c" />
<ClCompile Include="..\..\..\..\..\libxml2\nanohttp.c" />
<ClCompile Include="..\..\..\..\..\libxml2\parser.c" />
<ClCompile Include="..\..\..\..\..\libxml2\parserInternals.c" />
<ClCompile Include="..\..\..\..\..\libxml2\pattern.c" />
<ClCompile Include="..\..\..\..\..\libxml2\relaxng.c" />
<ClCompile Include="..\..\..\..\..\libxml2\SAX.c" />
<ClCompile Include="..\..\..\..\..\libxml2\SAX2.c" />
<ClCompile Include="..\..\..\..\..\libxml2\schematron.c" />
<ClCompile Include="..\..\..\..\..\libxml2\threads.c" />
<ClCompile Include="..\..\..\..\..\libxml2\tree.c" />
<ClCompile Include="..\..\..\..\..\libxml2\uri.c" />
<ClCompile Include="..\..\..\..\..\libxml2\valid.c" />
<ClCompile Include="..\..\..\..\..\libxml2\xinclude.c" />
<ClCompile Include="..\..\..\..\..\libxml2\xlink.c" />
<ClCompile Include="..\..\..\..\..\libxml2\xmlcatalog.c" />
<ClCompile Include="..\..\..\..\..\libxml2\xmlIO.c" />
<ClCompile Include="..\..\..\..\..\libxml2\xmlmemory.c" />
<ClCompile Include="..\..\..\..\..\libxml2\xmlmodule.c" />
<ClCompile Include="..\..\..\..\..\libxml2\xmlreader.c" />
<ClCompile Include="..\..\..\..\..\libxml2\xmlregexp.c" />
<ClCompile Include="..\..\..\..\..\libxml2\xmlsave.c" />
<ClCompile Include="..\..\..\..\..\libxml2\xmlschemas.c" />
<ClCompile Include="..\..\..\..\..\libxml2\xmlschemastypes.c" />
<ClCompile Include="..\..\..\..\..\libxml2\xmlstring.c" />
<ClCompile Include="..\..\..\..\..\libxml2\xmlunicode.c" />
<ClCompile Include="..\..\..\..\..\libxml2\xmlwriter.c" />
<ClCompile Include="..\..\..\..\..\libxml2\xpath.c" />
<ClCompile Include="..\..\..\..\..\libxml2\xpointer.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\..\..\libxml2\elfgcchack.h" />
<ClInclude Include="..\..\..\..\..\libxml2\libxml.h" />
<ClInclude Include="..\..\..\..\..\libxml2\win32\VC10\config.h" />
<ClInclude Include="libxml2_port.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsPhone\v$(TargetPlatformVersion)\Microsoft.Cpp.WindowsPhone.$(TargetPlatformVersion).targets" Condition="'$(Platform)'=='ARM'" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -0,0 +1,204 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM">
<Configuration>Debug</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM">
<Configuration>Release</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{08dd0d38-d9b5-4626-b60d-b4d76b571142}</ProjectGuid>
<RootNamespace>LibLinphone</RootNamespace>
<DefaultLanguage>en-US</DefaultLanguage>
<MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v110_wp80</PlatformToolset>
<IgnoreImportLibrary>false</IgnoreImportLibrary>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v110_wp80</PlatformToolset>
<IgnoreImportLibrary>false</IgnoreImportLibrary>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\$(TargetName)\</IntDir>
</PropertyGroup>
<PropertyGroup>
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\belle-sip\include;$(ProjectDir)..\..\oRTP\include;$(ProjectDir)..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\tunnel\include;$(ProjectDir)..\..\coreapi;$(ProjectDir)..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>__STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";UNICODE;_XKEYCHECK_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<CompileAsWinRT>false</CompileAsWinRT>
<AdditionalUsingDirectories>$(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
<AdditionalDependencies>belle-sip.lib;mediastreamer2.lib;ws2_32.lib;ortp.lib;gsm.lib;speex.lib;speexdsp.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(SolutionDir)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<ImportLibrary>$(TargetDir)$(TargetName).lib</ImportLibrary>
</Link>
<CustomBuildStep>
<Outputs>$(TargetDir)$(TargetName)_dll.lib;%(Outputs)</Outputs>
</CustomBuildStep>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
<ClCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
<ClCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Optimization>MaxSpeed</Optimization>
<StringPooling>true</StringPooling>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
</ClCompile>
<Link>
<GenerateDebugInformation>false</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\coreapi\address.c" />
<ClCompile Include="..\..\coreapi\authentication.c" />
<ClCompile Include="..\..\coreapi\bellesip_sal\sal_address_impl.c" />
<ClCompile Include="..\..\coreapi\bellesip_sal\sal_impl.c" />
<ClCompile Include="..\..\coreapi\bellesip_sal\sal_op_call.c" />
<ClCompile Include="..\..\coreapi\bellesip_sal\sal_op_call_transfer.c" />
<ClCompile Include="..\..\coreapi\bellesip_sal\sal_op_events.c" />
<ClCompile Include="..\..\coreapi\bellesip_sal\sal_op_impl.c" />
<ClCompile Include="..\..\coreapi\bellesip_sal\sal_op_info.c" />
<ClCompile Include="..\..\coreapi\bellesip_sal\sal_op_message.c" />
<ClCompile Include="..\..\coreapi\bellesip_sal\sal_op_presence.c" />
<ClCompile Include="..\..\coreapi\bellesip_sal\sal_op_publish.c" />
<ClCompile Include="..\..\coreapi\bellesip_sal\sal_op_registration.c" />
<ClCompile Include="..\..\coreapi\bellesip_sal\sal_sdp.c" />
<ClCompile Include="..\..\coreapi\callbacks.c" />
<ClCompile Include="..\..\coreapi\chat.c" />
<ClCompile Include="..\..\coreapi\conference.c" />
<ClCompile Include="..\..\coreapi\ec-calibrator.c" />
<ClCompile Include="..\..\coreapi\enum.c" />
<ClCompile Include="..\..\coreapi\event.c" />
<ClCompile Include="..\..\coreapi\friend.c" />
<ClCompile Include="..\..\coreapi\info.c" />
<ClCompile Include="..\..\coreapi\linphonecall.c" />
<ClCompile Include="..\..\coreapi\linphonecore.c" />
<ClCompile Include="..\..\coreapi\linphone_tunnel.cc" />
<ClCompile Include="..\..\coreapi\linphone_tunnel_config.c" />
<ClCompile Include="..\..\coreapi\lpconfig.c" />
<ClCompile Include="..\..\coreapi\lsd.c" />
<ClCompile Include="..\..\coreapi\message_storage.c" />
<ClCompile Include="..\..\coreapi\misc.c" />
<ClCompile Include="..\..\coreapi\offeranswer.c" />
<ClCompile Include="..\..\coreapi\presence.c" />
<ClCompile Include="..\..\coreapi\proxy.c" />
<ClCompile Include="..\..\coreapi\quality_reporting.c" />
<ClCompile Include="..\..\coreapi\remote_provisioning.c" />
<ClCompile Include="..\..\coreapi\sal.c" />
<ClCompile Include="..\..\coreapi\siplogin.c" />
<ClCompile Include="..\..\coreapi\sipsetup.c" />
<ClCompile Include="..\..\coreapi\TunnelManager.cc" />
<ClCompile Include="..\..\coreapi\xml.c" />
<ClCompile Include="..\..\coreapi\xml2lpc.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\coreapi\bellesip_sal\sal_impl.h" />
<ClInclude Include="..\..\coreapi\enum.h" />
<ClInclude Include="..\..\coreapi\event.h" />
<ClInclude Include="..\..\coreapi\linphonecore.h" />
<ClInclude Include="..\..\coreapi\linphonecore_utils.h" />
<ClInclude Include="..\..\coreapi\linphonefriend.h" />
<ClInclude Include="..\..\coreapi\linphone_tunnel.h" />
<ClInclude Include="..\..\coreapi\lpconfig.h" />
<ClInclude Include="..\..\coreapi\offeranswer.h" />
<ClInclude Include="..\..\coreapi\private.h" />
<ClInclude Include="..\..\coreapi\sipsetup.h" />
<ClInclude Include="..\..\coreapi\xml2lpc.h" />
</ItemGroup>
<ItemGroup>
<Reference Include="Windows">
<IsWinMDFile>true</IsWinMDFile>
</Reference>
<Reference Include="platform.winmd">
<IsWinMDFile>true</IsWinMDFile>
<Private>false</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<None Include="..\..\coreapi\TunnelManager.hh" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\bcg729\build\wp8\bcg729\bcg729.vcxproj">
<Project>{1db09afe-fc9b-472e-a746-0e33f8ef8883}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\belle-sip\build\wp8\belle-sip\belle-sip.vcxproj">
<Project>{4c225a82-800b-427b-ba7b-61686a9b347f}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\msamr\build\wp8\msamr\msamr.vcxproj">
<Project>{9924ac72-f96c-4e56-94d9-2b025da43c6b}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\msilbc\build\wp8\msilbc\msilbc.vcxproj">
<Project>{072fad20-7007-4da2-b2e7-16ce2b219f67}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\mssilk\build\wp8\mssilk\mssilk.vcxproj">
<Project>{36b528f9-fb79-4078-a16b-0a7442581bb7}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\mswasapi\mswasapi\mswasapi.vcxproj">
<Project>{d22bd217-d0f8-4274-9b3a-f3f35f46482c}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\mswebrtc\build\wp8\mswebrtc\mswebrtc.vcxproj">
<Project>{b16b81a9-bef2-44c9-b603-1065183ae844}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\mswp8vid\mswp8vid\mswp8vid.vcxproj">
<Project>{0565952a-ea62-46a2-8261-f5b4b490da42}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\tunnel\build\wp8\tunnel\tunnel.vcxproj">
<Project>{59500dd1-b192-4ddf-a402-8a8e3739e032}</Project>
</ProjectReference>
<ProjectReference Include="..\..\mediastreamer2\build\wp8\mediastreamer2\mediastreamer2.vcxproj">
<Project>{027bad0e-9179-48c1-9733-7aa7e2c2ec70}</Project>
</ProjectReference>
<ProjectReference Include="..\..\oRTP\build\wp8\oRTP\oRTP.vcxproj">
<Project>{ffc7b532-0502-4d88-ac98-9e89071cbc97}</Project>
</ProjectReference>
<ProjectReference Include="libxml2\libxml2.vcxproj">
<Project>{5dfa07b4-0be9-46a9-ba32-fdf5a55c580b}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsPhone\v$(TargetPlatformVersion)\Microsoft.Cpp.WindowsPhone.$(TargetPlatformVersion).targets" />
</Project>

View file

@ -26,26 +26,13 @@
<WinMDAssembly>true</WinMDAssembly>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v110_wp80</PlatformToolset>
<IgnoreImportLibrary>false</IgnoreImportLibrary>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v110_wp80</PlatformToolset>
<IgnoreImportLibrary>true</IgnoreImportLibrary>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v110_wp80</PlatformToolset>
<IgnoreImportLibrary>false</IgnoreImportLibrary>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
@ -60,66 +47,42 @@
<PropertyGroup>
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PreprocessorDefinitions>_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<CompileAsWinRT>false</CompileAsWinRT>
<AdditionalUsingDirectories>$(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PreprocessorDefinitions>_USRDLL;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<CompileAsWinRT>false</CompileAsWinRT>
<AdditionalUsingDirectories>$(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
<GenerateDebugInformation>false</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<ItemDefinitionGroup>
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_WINRT_DLL;_CRT_SECURE_NO_WARNINGS;HAVE_CU_GET_SUITE;IN_LINPHONE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDir)..\..\..\tester;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(ProjectDir)..\..\..\..\cunit\build\windows\cunit\$(Platform)\$(Configuration);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\oRTP\include;$(ProjectDir)..\..\..\mediastreamer2\include;$(ProjectDir)..\..\..\tester;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(ProjectDir)..\..\..\..\cunit\build\wp8\cunit\$(Platform)\$(Configuration);$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_WINDOWS;_WINRT_DLL;_CRT_SECURE_NO_WARNINGS;HAVE_CU_GET_SUITE;IN_LINPHONE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<AdditionalUsingDirectories>$(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<CompileAsWinRT>false</CompileAsWinRT>
<ExceptionHandling>Async</ExceptionHandling>
<AdditionalUsingDirectories>$(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<IgnoreSpecificDefaultLibraries>ole32.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
<GenerateWindowsMetadata>true</GenerateWindowsMetadata>
<IgnoreSpecificDefaultLibraries>ole32.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
<AdditionalDependencies>WindowsPhoneCore.lib;RuntimeObject.lib;PhoneAppModelHost.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(SolutionDir)$(Platform)\$(Configuration)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
<ClCompile>
<PreprocessorDefinitions>_USRDLL;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<CompileAsWinRT>false</CompileAsWinRT>
<AdditionalUsingDirectories>$(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDir)..\..\..\tester;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(ProjectDir)..\..\..\..\cunit\build\windows\cunit\$(Platform)\$(Configuration);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
<ClCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Optimization>MaxSpeed</Optimization>
<StringPooling>true</StringPooling>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
<GenerateDebugInformation>false</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
@ -132,13 +95,18 @@
<ItemGroup>
<ClCompile Include="..\..\..\tester\call_tester.c" />
<ClCompile Include="..\..\..\tester\eventapi_tester.c" />
<ClCompile Include="..\..\..\tester\flexisip_tester.c" />
<ClCompile Include="..\..\..\tester\liblinphone_tester.c" />
<ClCompile Include="..\..\..\tester\message_tester.c" />
<ClCompile Include="..\..\..\tester\presence_tester.c" />
<ClCompile Include="..\..\..\tester\quality_reporting_tester.c" />
<ClCompile Include="..\..\..\tester\register_tester.c" />
<ClCompile Include="..\..\..\tester\remote_provisioning_tester.c" />
<ClCompile Include="..\..\..\tester\setup_tester.c" />
<ClCompile Include="..\..\..\tester\stun_tester.c" />
<ClCompile Include="..\..\..\tester\tester.c" />
<ClCompile Include="linphone-tester-native.cpp">
<CompileAsWinRT Condition="'$(Platform)'=='ARM'">true</CompileAsWinRT>
<CompileAsWinRT>true</CompileAsWinRT>
</ClCompile>
</ItemGroup>
<ItemGroup>
@ -146,21 +114,43 @@
<ClInclude Include="linphone-tester-native.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\cunit\build\windows\cunit\cunit.vcxproj">
<ProjectReference Include="..\..\..\..\bcg729\build\wp8\bcg729\bcg729.vcxproj">
<Project>{1db09afe-fc9b-472e-a746-0e33f8ef8883}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\..\belle-sip\build\wp8\belle-sip\belle-sip.vcxproj">
<Project>{4c225a82-800b-427b-ba7b-61686a9b347f}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\..\cunit\build\wp8\cunit\cunit.vcxproj">
<Project>{902daf1d-ebf1-4d03-b598-143500a50ab4}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\..\mediastreamer2\build\vsx\mediastreamer2\mediastreamer2\mediastreamer2.vcxproj">
<ProjectReference Include="..\..\..\..\msamr\build\wp8\msamr\msamr.vcxproj">
<Project>{9924ac72-f96c-4e56-94d9-2b025da43c6b}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\..\msilbc\build\wp8\msilbc\msilbc.vcxproj">
<Project>{072fad20-7007-4da2-b2e7-16ce2b219f67}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\..\mssilk\build\wp8\mssilk\mssilk.vcxproj">
<Project>{36b528f9-fb79-4078-a16b-0a7442581bb7}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\..\mswasapi\mswasapi\mswasapi.vcxproj">
<Project>{d22bd217-d0f8-4274-9b3a-f3f35f46482c}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\..\mswebrtc\build\wp8\mswebrtc\mswebrtc.vcxproj">
<Project>{b16b81a9-bef2-44c9-b603-1065183ae844}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\..\mswp8vid\mswp8vid\mswp8vid.vcxproj">
<Project>{0565952a-ea62-46a2-8261-f5b4b490da42}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\mediastreamer2\build\wp8\mediastreamer2\mediastreamer2.vcxproj">
<Project>{027bad0e-9179-48c1-9733-7aa7e2c2ec70}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\..\oRTP\build\vsx\oRTP\oRTP\oRTP.vcxproj">
<ProjectReference Include="..\..\..\oRTP\build\wp8\oRTP\oRTP.vcxproj">
<Project>{ffc7b532-0502-4d88-ac98-9e89071cbc97}</Project>
</ProjectReference>
<ProjectReference Include="..\LibLinphone\LibLinphone.vcxproj">
<ProjectReference Include="..\LibLinphone.vcxproj">
<Project>{08dd0d38-d9b5-4626-b60d-b4d76b571142}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsPhone\v$(TargetPlatformVersion)\Microsoft.Cpp.WindowsPhone.$(TargetPlatformVersion).targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

View file

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View file

@ -26,27 +26,6 @@
<MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
<ThrowErrorsInValidation>true</ThrowErrorsInValidation>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>Bin\Debug</OutputPath>
<DefineConstants>DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>Bin\Release</OutputPath>
<DefineConstants>TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
@ -171,12 +150,15 @@
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\LibLinphoneTester\LibLinphoneTester.vcxproj">
<ProjectReference Include="..\..\..\..\mswp8vid\mswp8vid\mswp8vid.vcxproj">
<Project>{0565952A-EA62-46A2-8261-F5B4B490DA42}</Project>
<Name>libmswp8vid</Name>
</ProjectReference>
<ProjectReference Include="..\LibLinphoneTester-native\LibLinphoneTester-native.vcxproj">
<Project>{5E94A00B-B14A-4E42-8284-8CB0EF099534}</Project>
<Name>LibLinphoneTester</Name>
<Name>LibLinphoneTester-native</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\$(TargetFrameworkIdentifier)\$(TargetFrameworkVersion)\Microsoft.$(TargetFrameworkIdentifier).$(TargetFrameworkVersion).Overrides.targets" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\$(TargetFrameworkIdentifier)\$(TargetFrameworkVersion)\Microsoft.$(TargetFrameworkIdentifier).CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
@ -188,6 +170,6 @@
-->
<ProjectExtensions />
<PropertyGroup>
<PreBuildEvent>Xcopy /I /Y $(ProjectDir)..\..\..\..\tester\*rc $(ProjectDir)Assets\</PreBuildEvent>
<PreBuildEvent>Xcopy /I /Y $(ProjectDir)..\..\..\tester\rcfiles\*_rc $(ProjectDir)Assets\</PreBuildEvent>
</PropertyGroup>
</Project>

View file

@ -0,0 +1,336 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Express 2012 for Windows Phone
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibLinphoneTester-wp8", "LibLinphoneTester-wp8.csproj", "{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}"
ProjectSection(ProjectDependencies) = postProject
{5E94A00B-B14A-4E42-8284-8CB0EF099534} = {5E94A00B-B14A-4E42-8284-8CB0EF099534}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibLinphone", "..\LibLinphone.vcxproj", "{08DD0D38-D9B5-4626-B60D-B4D76B571142}"
ProjectSection(ProjectDependencies) = postProject
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70} = {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}
{59500DD1-B192-4DDF-A402-8A8E3739E032} = {59500DD1-B192-4DDF-A402-8A8E3739E032}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibLinphoneTester-native", "..\LibLinphoneTester-native\LibLinphoneTester-native.vcxproj", "{5E94A00B-B14A-4E42-8284-8CB0EF099534}"
ProjectSection(ProjectDependencies) = postProject
{D22BD217-D0F8-4274-9B3A-F3F35F46482C} = {D22BD217-D0F8-4274-9B3A-F3F35F46482C}
{902DAF1D-EBF1-4D03-B598-143500A50AB4} = {902DAF1D-EBF1-4D03-B598-143500A50AB4}
{072FAD20-7007-4DA2-B2E7-16CE2B219F67} = {072FAD20-7007-4DA2-B2E7-16CE2B219F67}
{0565952A-EA62-46A2-8261-F5B4B490DA42} = {0565952A-EA62-46A2-8261-F5B4B490DA42}
{08DD0D38-D9B5-4626-B60D-B4D76B571142} = {08DD0D38-D9B5-4626-B60D-B4D76B571142}
{9924AC72-F96C-4E56-94D9-2B025DA43C6B} = {9924AC72-F96C-4E56-94D9-2B025DA43C6B}
{B16B81A9-BEF2-44C9-B603-1065183AE844} = {B16B81A9-BEF2-44C9-B603-1065183AE844}
{36B528F9-FB79-4078-A16B-0A7442581BB7} = {36B528F9-FB79-4078-A16B-0A7442581BB7}
{1DB09AFE-FC9B-472E-A746-0E33F8EF8883} = {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "belle-sip", "..\..\..\..\belle-sip\build\wp8\belle-sip\belle-sip.vcxproj", "{4C225A82-800B-427B-BA7B-61686A9B347F}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mediastreamer2", "..\..\..\mediastreamer2\build\wp8\mediastreamer2\mediastreamer2.vcxproj", "{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "oRTP", "..\..\..\oRTP\build\wp8\oRTP\oRTP.vcxproj", "{FFC7B532-0502-4D88-AC98-9E89071CBC97}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libantlr3c", "..\..\..\..\antlr3\runtime\C\build\wp8\libantlr3c\libantlr3c.vcxproj", "{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gsm", "..\..\..\..\gsm\build\wp8\gsm\gsm.vcxproj", "{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "speex", "..\..\..\..\speex\build\wp8\speex\speex.vcxproj", "{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "speexdsp", "..\..\..\..\speex\build\wp8\speex\speexdsp.vcxproj", "{6BD78980-9C71-4341-8775-AD19E9EC7305}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cunit", "..\..\..\..\cunit\build\wp8\cunit\cunit.vcxproj", "{902DAF1D-EBF1-4D03-B598-143500A50AB4}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmswasapi", "..\..\..\..\mswasapi\mswasapi\mswasapi.vcxproj", "{D22BD217-D0F8-4274-9B3A-F3F35F46482C}"
ProjectSection(ProjectDependencies) = postProject
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70} = {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}
{FFC7B532-0502-4D88-AC98-9E89071CBC97} = {FFC7B532-0502-4D88-AC98-9E89071CBC97}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libilbc-rfc3951", "..\..\..\..\libilbc-rfc3951\build\wp8\libilbc-rfc3951\libilbc-rfc3951.vcxproj", "{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmsilbc", "..\..\..\..\msilbc\build\wp8\msilbc\msilbc.vcxproj", "{072FAD20-7007-4DA2-B2E7-16CE2B219F67}"
ProjectSection(ProjectDependencies) = postProject
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70} = {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}
{FFC7B532-0502-4D88-AC98-9E89071CBC97} = {FFC7B532-0502-4D88-AC98-9E89071CBC97}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmssilk", "..\..\..\..\mssilk\build\wp8\mssilk\mssilk.vcxproj", "{36B528F9-FB79-4078-A16B-0A7442581BB7}"
ProjectSection(ProjectDependencies) = postProject
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70} = {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}
{FFC7B532-0502-4D88-AC98-9E89071CBC97} = {FFC7B532-0502-4D88-AC98-9E89071CBC97}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmsamr", "..\..\..\..\msamr\build\wp8\msamr\msamr.vcxproj", "{9924AC72-F96C-4E56-94D9-2B025DA43C6B}"
ProjectSection(ProjectDependencies) = postProject
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70} = {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}
{018A4428-535C-4566-9AE0-E93AFF0D3ED2} = {018A4428-535C-4566-9AE0-E93AFF0D3ED2}
{7AC65D2A-6981-4D17-856D-C37A522739D8} = {7AC65D2A-6981-4D17-856D-C37A522739D8}
{88191E75-2993-48D7-AA76-652F274EF0FE} = {88191E75-2993-48D7-AA76-652F274EF0FE}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vo-amrwbenc", "..\..\..\..\msamr\build\wp8\msamr\vo-amrwbenc.vcxproj", "{018A4428-535C-4566-9AE0-E93AFF0D3ED2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opencore_amrnb", "..\..\..\..\msamr\build\wp8\msamr\opencore_amrnb.vcxproj", "{88191E75-2993-48D7-AA76-652F274EF0FE}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opencore_amrwb", "..\..\..\..\msamr\build\wp8\msamr\opencore_amrwb.vcxproj", "{7AC65D2A-6981-4D17-856D-C37A522739D8}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "polarssl", "..\..\..\..\polarssl\build\wp8\polarssl\polarssl.vcxproj", "{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tunnel", "..\..\..\..\tunnel\build\wp8\tunnel\tunnel.vcxproj", "{59500DD1-B192-4DDF-A402-8A8E3739E032}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libxml2", "..\libxml2\libxml2.vcxproj", "{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "srtp", "..\..\..\..\srtp\build\wp8\srtp\srtp.vcxproj", "{B4B96BC4-2B72-4964-98E4-7FD048A43363}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmswp8vid", "..\..\..\..\mswp8vid\mswp8vid\mswp8vid.vcxproj", "{0565952A-EA62-46A2-8261-F5B4B490DA42}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmswebrtc", "..\..\..\..\mswebrtc\build\wp8\mswebrtc\mswebrtc.vcxproj", "{B16B81A9-BEF2-44C9-B603-1065183AE844}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "webrtc", "..\..\..\..\mswebrtc\webrtc\build\wp8\webrtc\webrtc.vcxproj", "{A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmsbcg729", "..\..\..\..\bcg729\build\wp8\bcg729\bcg729.vcxproj", "{1DB09AFE-FC9B-472E-A746-0E33F8EF8883}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opus", "..\..\..\..\opus\build\wp8\opus\opus.vcxproj", "{D450EC75-DF02-48B0-A4FB-ACA79BD894AB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM = Debug|ARM
Debug|x86 = Debug|x86
Release|ARM = Release|ARM
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|ARM.ActiveCfg = Debug|ARM
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|ARM.Build.0 = Debug|ARM
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|ARM.Deploy.0 = Debug|ARM
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|x86.ActiveCfg = Debug|x86
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|x86.Build.0 = Debug|x86
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|x86.Deploy.0 = Debug|x86
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|ARM.ActiveCfg = Release|ARM
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|ARM.Build.0 = Release|ARM
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|ARM.Deploy.0 = Release|ARM
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|x86.ActiveCfg = Release|x86
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|x86.Build.0 = Release|x86
{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|x86.Deploy.0 = Release|x86
{08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|ARM.ActiveCfg = Debug|ARM
{08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|ARM.Build.0 = Debug|ARM
{08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|x86.ActiveCfg = Debug|Win32
{08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|x86.Build.0 = Debug|Win32
{08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|ARM.ActiveCfg = Release|ARM
{08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|ARM.Build.0 = Release|ARM
{08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|x86.ActiveCfg = Release|Win32
{08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|x86.Build.0 = Release|Win32
{5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|ARM.ActiveCfg = Debug|ARM
{5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|ARM.Build.0 = Debug|ARM
{5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|x86.ActiveCfg = Debug|Win32
{5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|x86.Build.0 = Debug|Win32
{5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|ARM.ActiveCfg = Release|ARM
{5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|ARM.Build.0 = Release|ARM
{5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|x86.ActiveCfg = Release|Win32
{5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|x86.Build.0 = Release|Win32
{4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|ARM.ActiveCfg = Debug|ARM
{4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|ARM.Build.0 = Debug|ARM
{4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|x86.ActiveCfg = Debug|Win32
{4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|x86.Build.0 = Debug|Win32
{4C225A82-800B-427B-BA7B-61686A9B347F}.Release|ARM.ActiveCfg = Release|ARM
{4C225A82-800B-427B-BA7B-61686A9B347F}.Release|ARM.Build.0 = Release|ARM
{4C225A82-800B-427B-BA7B-61686A9B347F}.Release|x86.ActiveCfg = Release|Win32
{4C225A82-800B-427B-BA7B-61686A9B347F}.Release|x86.Build.0 = Release|Win32
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|ARM.ActiveCfg = Debug|ARM
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|ARM.Build.0 = Debug|ARM
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|x86.ActiveCfg = Debug|Win32
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|x86.Build.0 = Debug|Win32
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|ARM.ActiveCfg = Release|ARM
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|ARM.Build.0 = Release|ARM
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|x86.ActiveCfg = Release|Win32
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|x86.Build.0 = Release|Win32
{FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|ARM.ActiveCfg = Debug|ARM
{FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|ARM.Build.0 = Debug|ARM
{FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|x86.ActiveCfg = Debug|Win32
{FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|x86.Build.0 = Debug|Win32
{FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|ARM.ActiveCfg = Release|ARM
{FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|ARM.Build.0 = Release|ARM
{FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|x86.ActiveCfg = Release|Win32
{FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|x86.Build.0 = Release|Win32
{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|ARM.ActiveCfg = Debug|ARM
{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|ARM.Build.0 = Debug|ARM
{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|x86.ActiveCfg = Debug|Win32
{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|x86.Build.0 = Debug|Win32
{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|ARM.ActiveCfg = Release|ARM
{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|ARM.Build.0 = Release|ARM
{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|x86.ActiveCfg = Release|Win32
{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|x86.Build.0 = Release|Win32
{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|ARM.ActiveCfg = Debug|ARM
{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|ARM.Build.0 = Debug|ARM
{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|x86.ActiveCfg = Debug|Win32
{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|x86.Build.0 = Debug|Win32
{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|ARM.ActiveCfg = Release|ARM
{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|ARM.Build.0 = Release|ARM
{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|x86.ActiveCfg = Release|Win32
{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|x86.Build.0 = Release|Win32
{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|ARM.ActiveCfg = Debug|ARM
{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|ARM.Build.0 = Debug|ARM
{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|x86.ActiveCfg = Debug|Win32
{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|x86.Build.0 = Debug|Win32
{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|ARM.ActiveCfg = Release|ARM
{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|ARM.Build.0 = Release|ARM
{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|x86.ActiveCfg = Release|Win32
{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|x86.Build.0 = Release|Win32
{6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|ARM.ActiveCfg = Debug|ARM
{6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|ARM.Build.0 = Debug|ARM
{6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|x86.ActiveCfg = Debug|Win32
{6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|x86.Build.0 = Debug|Win32
{6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|ARM.ActiveCfg = Release|ARM
{6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|ARM.Build.0 = Release|ARM
{6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|x86.ActiveCfg = Release|Win32
{6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|x86.Build.0 = Release|Win32
{902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|ARM.ActiveCfg = Debug|ARM
{902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|ARM.Build.0 = Debug|ARM
{902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|x86.ActiveCfg = Debug|Win32
{902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|x86.Build.0 = Debug|Win32
{902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|ARM.ActiveCfg = Release|ARM
{902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|ARM.Build.0 = Release|ARM
{902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|x86.ActiveCfg = Release|Win32
{902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|x86.Build.0 = Release|Win32
{D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|ARM.ActiveCfg = Debug|ARM
{D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|ARM.Build.0 = Debug|ARM
{D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|x86.ActiveCfg = Debug|Win32
{D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|x86.Build.0 = Debug|Win32
{D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|ARM.ActiveCfg = Release|ARM
{D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|ARM.Build.0 = Release|ARM
{D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|x86.ActiveCfg = Release|Win32
{D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|x86.Build.0 = Release|Win32
{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|ARM.ActiveCfg = Debug|ARM
{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|ARM.Build.0 = Debug|ARM
{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|x86.ActiveCfg = Debug|Win32
{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|x86.Build.0 = Debug|Win32
{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|ARM.ActiveCfg = Release|ARM
{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|ARM.Build.0 = Release|ARM
{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|x86.ActiveCfg = Release|Win32
{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|x86.Build.0 = Release|Win32
{072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|ARM.ActiveCfg = Debug|ARM
{072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|ARM.Build.0 = Debug|ARM
{072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|x86.ActiveCfg = Debug|Win32
{072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|x86.Build.0 = Debug|Win32
{072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|ARM.ActiveCfg = Release|ARM
{072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|ARM.Build.0 = Release|ARM
{072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|x86.ActiveCfg = Release|Win32
{072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|x86.Build.0 = Release|Win32
{36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|ARM.ActiveCfg = Debug|ARM
{36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|ARM.Build.0 = Debug|ARM
{36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|x86.ActiveCfg = Debug|Win32
{36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|x86.Build.0 = Debug|Win32
{36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|ARM.ActiveCfg = Release|ARM
{36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|ARM.Build.0 = Release|ARM
{36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|x86.ActiveCfg = Release|Win32
{36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|x86.Build.0 = Release|Win32
{9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|ARM.ActiveCfg = Debug|ARM
{9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|ARM.Build.0 = Debug|ARM
{9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|x86.ActiveCfg = Debug|Win32
{9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|x86.Build.0 = Debug|Win32
{9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|ARM.ActiveCfg = Release|ARM
{9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|ARM.Build.0 = Release|ARM
{9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|x86.ActiveCfg = Release|Win32
{9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|x86.Build.0 = Release|Win32
{018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|ARM.ActiveCfg = Debug|ARM
{018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|ARM.Build.0 = Debug|ARM
{018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|x86.ActiveCfg = Debug|Win32
{018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|x86.Build.0 = Debug|Win32
{018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|ARM.ActiveCfg = Release|ARM
{018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|ARM.Build.0 = Release|ARM
{018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|x86.ActiveCfg = Release|Win32
{018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|x86.Build.0 = Release|Win32
{88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|ARM.ActiveCfg = Debug|ARM
{88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|ARM.Build.0 = Debug|ARM
{88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|x86.ActiveCfg = Debug|Win32
{88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|x86.Build.0 = Debug|Win32
{88191E75-2993-48D7-AA76-652F274EF0FE}.Release|ARM.ActiveCfg = Release|ARM
{88191E75-2993-48D7-AA76-652F274EF0FE}.Release|ARM.Build.0 = Release|ARM
{88191E75-2993-48D7-AA76-652F274EF0FE}.Release|x86.ActiveCfg = Release|Win32
{88191E75-2993-48D7-AA76-652F274EF0FE}.Release|x86.Build.0 = Release|Win32
{7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|ARM.ActiveCfg = Debug|ARM
{7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|ARM.Build.0 = Debug|ARM
{7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|x86.ActiveCfg = Debug|Win32
{7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|x86.Build.0 = Debug|Win32
{7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|ARM.ActiveCfg = Release|ARM
{7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|ARM.Build.0 = Release|ARM
{7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|x86.ActiveCfg = Release|Win32
{7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|x86.Build.0 = Release|Win32
{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|ARM.ActiveCfg = Debug|ARM
{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|ARM.Build.0 = Debug|ARM
{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|x86.ActiveCfg = Debug|Win32
{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|x86.Build.0 = Debug|Win32
{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|ARM.ActiveCfg = Release|ARM
{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|ARM.Build.0 = Release|ARM
{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|x86.ActiveCfg = Release|Win32
{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|x86.Build.0 = Release|Win32
{59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|ARM.ActiveCfg = Debug|ARM
{59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|ARM.Build.0 = Debug|ARM
{59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|x86.ActiveCfg = Debug|Win32
{59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|x86.Build.0 = Debug|Win32
{59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|ARM.ActiveCfg = Release|ARM
{59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|ARM.Build.0 = Release|ARM
{59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|x86.ActiveCfg = Release|Win32
{59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|x86.Build.0 = Release|Win32
{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|ARM.ActiveCfg = Debug|ARM
{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|ARM.Build.0 = Debug|ARM
{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|x86.ActiveCfg = Debug|Win32
{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|x86.Build.0 = Debug|Win32
{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|ARM.ActiveCfg = Release|ARM
{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|ARM.Build.0 = Release|ARM
{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|x86.ActiveCfg = Release|Win32
{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|x86.Build.0 = Release|Win32
{B4B96BC4-2B72-4964-98E4-7FD048A43363}.Debug|ARM.ActiveCfg = Debug|ARM
{B4B96BC4-2B72-4964-98E4-7FD048A43363}.Debug|ARM.Build.0 = Debug|ARM
{B4B96BC4-2B72-4964-98E4-7FD048A43363}.Debug|x86.ActiveCfg = Debug|Win32
{B4B96BC4-2B72-4964-98E4-7FD048A43363}.Debug|x86.Build.0 = Debug|Win32
{B4B96BC4-2B72-4964-98E4-7FD048A43363}.Release|ARM.ActiveCfg = Release|ARM
{B4B96BC4-2B72-4964-98E4-7FD048A43363}.Release|ARM.Build.0 = Release|ARM
{B4B96BC4-2B72-4964-98E4-7FD048A43363}.Release|x86.ActiveCfg = Release|Win32
{B4B96BC4-2B72-4964-98E4-7FD048A43363}.Release|x86.Build.0 = Release|Win32
{0565952A-EA62-46A2-8261-F5B4B490DA42}.Debug|ARM.ActiveCfg = Debug|ARM
{0565952A-EA62-46A2-8261-F5B4B490DA42}.Debug|ARM.Build.0 = Debug|ARM
{0565952A-EA62-46A2-8261-F5B4B490DA42}.Debug|x86.ActiveCfg = Debug|Win32
{0565952A-EA62-46A2-8261-F5B4B490DA42}.Debug|x86.Build.0 = Debug|Win32
{0565952A-EA62-46A2-8261-F5B4B490DA42}.Release|ARM.ActiveCfg = Release|ARM
{0565952A-EA62-46A2-8261-F5B4B490DA42}.Release|ARM.Build.0 = Release|ARM
{0565952A-EA62-46A2-8261-F5B4B490DA42}.Release|x86.ActiveCfg = Release|Win32
{0565952A-EA62-46A2-8261-F5B4B490DA42}.Release|x86.Build.0 = Release|Win32
{B16B81A9-BEF2-44C9-B603-1065183AE844}.Debug|ARM.ActiveCfg = Debug|ARM
{B16B81A9-BEF2-44C9-B603-1065183AE844}.Debug|ARM.Build.0 = Debug|ARM
{B16B81A9-BEF2-44C9-B603-1065183AE844}.Debug|x86.ActiveCfg = Debug|Win32
{B16B81A9-BEF2-44C9-B603-1065183AE844}.Debug|x86.Build.0 = Debug|Win32
{B16B81A9-BEF2-44C9-B603-1065183AE844}.Release|ARM.ActiveCfg = Release|ARM
{B16B81A9-BEF2-44C9-B603-1065183AE844}.Release|ARM.Build.0 = Release|ARM
{B16B81A9-BEF2-44C9-B603-1065183AE844}.Release|x86.ActiveCfg = Release|Win32
{B16B81A9-BEF2-44C9-B603-1065183AE844}.Release|x86.Build.0 = Release|Win32
{A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Debug|ARM.ActiveCfg = Debug|ARM
{A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Debug|ARM.Build.0 = Debug|ARM
{A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Debug|x86.ActiveCfg = Debug|Win32
{A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Debug|x86.Build.0 = Debug|Win32
{A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Release|ARM.ActiveCfg = Release|ARM
{A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Release|ARM.Build.0 = Release|ARM
{A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Release|x86.ActiveCfg = Release|Win32
{A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Release|x86.Build.0 = Release|Win32
{1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Debug|ARM.ActiveCfg = Debug|ARM
{1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Debug|ARM.Build.0 = Debug|ARM
{1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Debug|x86.ActiveCfg = Debug|Win32
{1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Debug|x86.Build.0 = Debug|Win32
{1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Release|ARM.ActiveCfg = Release|ARM
{1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Release|ARM.Build.0 = Release|ARM
{1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Release|x86.ActiveCfg = Release|Win32
{1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Release|x86.Build.0 = Release|Win32
{D450EC75-DF02-48B0-A4FB-ACA79BD894AB}.Debug|ARM.ActiveCfg = Debug|ARM
{D450EC75-DF02-48B0-A4FB-ACA79BD894AB}.Debug|ARM.Build.0 = Debug|ARM
{D450EC75-DF02-48B0-A4FB-ACA79BD894AB}.Debug|x86.ActiveCfg = Debug|Win32
{D450EC75-DF02-48B0-A4FB-ACA79BD894AB}.Debug|x86.Build.0 = Debug|Win32
{D450EC75-DF02-48B0-A4FB-ACA79BD894AB}.Release|ARM.ActiveCfg = Release|ARM
{D450EC75-DF02-48B0-A4FB-ACA79BD894AB}.Release|ARM.Build.0 = Release|ARM
{D450EC75-DF02-48B0-A4FB-ACA79BD894AB}.Release|x86.ActiveCfg = Release|Win32
{D450EC75-DF02-48B0-A4FB-ACA79BD894AB}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View file

@ -1,5 +1,5 @@
SET curdir=%CD%
SET incdir=..\..\..\..\..\libxml2\include\libxml
SET incdir=..\..\..\..\libxml2\include\libxml
SET installdir=%1\libxml
Xcopy /I /Y %incdir%\*.h %installdir%\

View file

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Express 2012 for Windows Phone
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libxml2", "libxml2\libxml2.vcxproj", "{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libxml2", "libxml2.vcxproj", "{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution

View file

@ -0,0 +1,159 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM">
<Configuration>Debug</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM">
<Configuration>Release</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{5dfa07b4-0be9-46a9-ba32-fdf5a55c580b}</ProjectGuid>
<RootNamespace>libxml2</RootNamespace>
<DefaultLanguage>en-US</DefaultLanguage>
<MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v110_wp80</PlatformToolset>
<IgnoreImportLibrary>false</IgnoreImportLibrary>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v110_wp80</PlatformToolset>
<IgnoreImportLibrary>false</IgnoreImportLibrary>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\$(TargetName)\</IntDir>
</PropertyGroup>
<PropertyGroup>
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<AdditionalIncludeDirectories>$(SolutionDir)$(Platform)\$(Configuration)\include;$(ProjectDir)..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_WIN32;_WINDLL;_USRDLL;_CRT_SECURE_NO_WARNINGS;HAVE_WIN32_THREADS;HAVE_COMPILER_TLS;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<UndefinePreprocessorDefinitions>LIBXML_MODULES_ENABLED</UndefinePreprocessorDefinitions>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<CompileAsWinRT>false</CompileAsWinRT>
<AdditionalUsingDirectories>$(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<ForcedIncludeFiles>$(ProjectDir)libxml2_port.h</ForcedIncludeFiles>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
<ImportLibrary>$(TargetDir)$(TargetName).lib</ImportLibrary>
<AdditionalDependencies>Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>install_headers.bat $(SolutionDir)$(Platform)\$(Configuration)\include</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
<ClCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
<ClCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Optimization>MaxSpeed</Optimization>
<StringPooling>true</StringPooling>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
</ClCompile>
<Link>
<GenerateDebugInformation>false</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<Reference Include="Windows">
<IsWinMDFile>true</IsWinMDFile>
</Reference>
<Reference Include="platform.winmd">
<IsWinMDFile>true</IsWinMDFile>
<Private>false</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\..\libxml2\c14n.c" />
<ClCompile Include="..\..\..\..\libxml2\catalog.c" />
<ClCompile Include="..\..\..\..\libxml2\chvalid.c" />
<ClCompile Include="..\..\..\..\libxml2\debugXML.c" />
<ClCompile Include="..\..\..\..\libxml2\dict.c" />
<ClCompile Include="..\..\..\..\libxml2\DOCBparser.c" />
<ClCompile Include="..\..\..\..\libxml2\encoding.c" />
<ClCompile Include="..\..\..\..\libxml2\entities.c" />
<ClCompile Include="..\..\..\..\libxml2\error.c" />
<ClCompile Include="..\..\..\..\libxml2\globals.c" />
<ClCompile Include="..\..\..\..\libxml2\hash.c" />
<ClCompile Include="..\..\..\..\libxml2\HTMLparser.c" />
<ClCompile Include="..\..\..\..\libxml2\HTMLtree.c" />
<ClCompile Include="..\..\..\..\libxml2\legacy.c" />
<ClCompile Include="..\..\..\..\libxml2\list.c" />
<ClCompile Include="..\..\..\..\libxml2\nanoftp.c" />
<ClCompile Include="..\..\..\..\libxml2\nanohttp.c" />
<ClCompile Include="..\..\..\..\libxml2\parser.c" />
<ClCompile Include="..\..\..\..\libxml2\parserInternals.c" />
<ClCompile Include="..\..\..\..\libxml2\pattern.c" />
<ClCompile Include="..\..\..\..\libxml2\relaxng.c" />
<ClCompile Include="..\..\..\..\libxml2\SAX.c" />
<ClCompile Include="..\..\..\..\libxml2\SAX2.c" />
<ClCompile Include="..\..\..\..\libxml2\schematron.c" />
<ClCompile Include="..\..\..\..\libxml2\threads.c" />
<ClCompile Include="..\..\..\..\libxml2\tree.c" />
<ClCompile Include="..\..\..\..\libxml2\uri.c" />
<ClCompile Include="..\..\..\..\libxml2\valid.c" />
<ClCompile Include="..\..\..\..\libxml2\xinclude.c" />
<ClCompile Include="..\..\..\..\libxml2\xlink.c" />
<ClCompile Include="..\..\..\..\libxml2\xmlcatalog.c" />
<ClCompile Include="..\..\..\..\libxml2\xmlIO.c" />
<ClCompile Include="..\..\..\..\libxml2\xmlmemory.c" />
<ClCompile Include="..\..\..\..\libxml2\xmlmodule.c" />
<ClCompile Include="..\..\..\..\libxml2\xmlreader.c" />
<ClCompile Include="..\..\..\..\libxml2\xmlregexp.c" />
<ClCompile Include="..\..\..\..\libxml2\xmlsave.c" />
<ClCompile Include="..\..\..\..\libxml2\xmlschemas.c" />
<ClCompile Include="..\..\..\..\libxml2\xmlschemastypes.c" />
<ClCompile Include="..\..\..\..\libxml2\xmlstring.c" />
<ClCompile Include="..\..\..\..\libxml2\xmlunicode.c" />
<ClCompile Include="..\..\..\..\libxml2\xmlwriter.c" />
<ClCompile Include="..\..\..\..\libxml2\xpath.c" />
<ClCompile Include="..\..\..\..\libxml2\xpointer.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\..\libxml2\elfgcchack.h" />
<ClInclude Include="..\..\..\..\libxml2\libxml.h" />
<ClInclude Include="..\..\..\..\libxml2\win32\VC10\config.h" />
<ClInclude Include="libxml2_port.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsPhone\v$(TargetPlatformVersion)\Microsoft.Cpp.WindowsPhone.$(TargetPlatformVersion).targets" />
</Project>

View file

@ -925,7 +925,7 @@ printf "* %-30s %s\n" "Account assistant" $build_wizard
printf "* %-30s %s\n" "Console interface" $console_ui
printf "* %-30s %s\n" "Tools" $build_tools
printf "* %-30s %s\n" "Message storage" $enable_msg_storage
printf "* %-30s %s\n" "zRTP encryption (GPLv3)" $zrtp
printf "* %-30s %s\n" "zRTP encryption" $zrtp
printf "* %-30s %s\n" "uPnP support" $build_upnp
printf "* %-30s %s\n" "LDAP support" $enable_ldap

View file

@ -45,7 +45,7 @@
/***************************************************************************
*
* Forward declarations
* Forward declarations
*
***************************************************************************/
@ -190,19 +190,19 @@ static LPC_COMMAND commands[] = {
"'conference add <call id> : join the call with id 'call id' into the audio conference."
"'conference rm <call id> : remove the call with id 'call id' from the audio conference."
},
{ "mute", lpc_cmd_mute_mic,
{ "mute", lpc_cmd_mute_mic,
"Mute microphone and suspend voice transmission."},
#ifdef VIDEO_ENABLED
{ "camera", lpc_cmd_camera, "Send camera output for current call.",
"'camera on'\t: allow sending of local camera video to remote end.\n"
"'camera off'\t: disable sending of local camera's video to remote end.\n"},
#endif
{ "unmute", lpc_cmd_unmute_mic,
{ "unmute", lpc_cmd_unmute_mic,
"Unmute microphone and resume voice transmission."},
{ "playbackgain", lpc_cmd_playback_gain,
{ "playbackgain", lpc_cmd_playback_gain,
"Adjust playback gain."},
{ "duration", lpc_cmd_duration, "Print duration in seconds of the last call.", NULL },
{ "autoanswer", lpc_cmd_autoanswer, "Show/set auto-answer mode",
"'autoanswer' \t: show current autoanswer mode\n"
"'autoanswer enable'\t: enable autoanswer mode\n"
@ -291,7 +291,7 @@ static LPC_COMMAND advanced_commands[] = {
{ "nortp-on-audio-mute", lpc_cmd_rtp_no_xmit_on_audio_mute,
"Set the rtp_no_xmit_on_audio_mute configuration parameter",
" If set to 1 then rtp transmission will be muted when\n"
" audio is muted , otherwise rtp is always sent."},
" audio is muted , otherwise rtp is always sent."},
#ifdef VIDEO_ENABLED
{ "vwindow", lpc_cmd_video_window, "Control video display window",
"'vwindow show': shows video window\n"
@ -321,11 +321,11 @@ static LPC_COMMAND advanced_commands[] = {
},
{ "register", lpc_cmd_register, "Register in one line to a proxy" , "register <sip identity> <sip proxy> <password>"},
{ "unregister", lpc_cmd_unregister, "Unregister from default proxy", NULL },
{ "status", lpc_cmd_status, "Print various status information",
{ "status", lpc_cmd_status, "Print various status information",
"'status register' \t: print status concerning registration\n"
"'status autoanswer'\t: tell whether autoanswer mode is enabled\n"
"'status hook' \t: print hook status\n" },
{ "ports", lpc_cmd_ports, "Network ports configuration",
{ "ports", lpc_cmd_ports, "Network ports configuration",
"'ports' \t: prints current used ports.\n"
"'ports sip <port number>'\t: Sets the sip port.\n" },
{ "param", lpc_cmd_param, "parameter set or read as normally given in .linphonerc",
@ -365,7 +365,7 @@ static LPC_COMMAND advanced_commands[] = {
/***************************************************************************
*
* Public interface
* Public interface
*
***************************************************************************/
@ -476,7 +476,7 @@ linphonec_command_generator(const char *text, int state)
/***************************************************************************
*
* Command handlers
* Command handlers
*
***************************************************************************/
@ -497,7 +497,7 @@ lpc_cmd_help(LinphoneCore *lc, char *arg)
commands[i].help);
i++;
}
linphonec_out("---------------------------\n");
linphonec_out("Type 'help <command>' for more details or\n");
linphonec_out(" 'help advanced' to list additional commands.\n");
@ -515,13 +515,13 @@ lpc_cmd_help(LinphoneCore *lc, char *arg)
advanced_commands[i].help);
i++;
}
linphonec_out("---------------------------\n");
linphonec_out("Type 'help <command>' for more details.\n");
return 1;
}
cmd=lpc_find_command(arg);
if ( !cmd )
{
@ -579,7 +579,7 @@ lpc_cmd_call(LinphoneCore *lc, char *args)
return 1;
}
static int
static int
lpc_cmd_calls(LinphoneCore *lc, char *args){
const MSList *calls = linphone_core_get_calls(lc);
if(calls)
@ -692,7 +692,7 @@ lpc_cmd_terminate(LinphoneCore *lc, char *args)
}
return 1;
}
if(strcmp(args,"all")==0){
linphonec_out("We are going to stop all the calls.\n");
linphone_core_terminate_all_calls(lc);
@ -709,7 +709,7 @@ lpc_cmd_terminate(LinphoneCore *lc, char *args)
return 1;
}
return 0;
}
static int
@ -852,7 +852,7 @@ lpc_cmd_firewall(LinphoneCore *lc, char *args)
{
linphone_core_set_firewall_policy(lc,LinphonePolicyNoFirewall);
}
else if (strcmp(args,"upnp")==0)
else if (strcmp(args,"upnp")==0)
{
linphone_core_set_firewall_policy(lc,LinphonePolicyUseUpnp);
}
@ -930,7 +930,7 @@ lpc_friend_name(char **args, char **name)
*args = ++end;
} else {
*name = strsep(args, " ");
if (NULL == *args) { /* Means there was no separator */
fprintf(stderr, "Either name or address is missing\n");
return 0;
@ -960,7 +960,7 @@ lpc_cmd_friend(LinphoneCore *lc, char *args)
args+=4;
if ( ! *args ) return 0;
friend_num = strtol(args, NULL, 10);
#ifndef _WIN32_WCE
#ifndef _WIN32_WCE
if ( errno == ERANGE ) {
linphonec_out("Invalid friend number\n");
return 0;
@ -978,11 +978,11 @@ lpc_cmd_friend(LinphoneCore *lc, char *args)
if (!strncmp(args, "all", 3))
{
friend_num = -1;
}
}
else
{
friend_num = strtol(args, NULL, 10);
#ifndef _WIN32_WCE
#ifndef _WIN32_WCE
if ( errno == ERANGE ) {
linphonec_out("Invalid friend number\n");
return 0;
@ -1411,7 +1411,7 @@ static int lpc_cmd_pause(LinphoneCore *lc, char *args){
}
static int lpc_cmd_resume(LinphoneCore *lc, char *args){
if(linphone_core_in_call(lc))
{
linphonec_out("There is already a call in process pause or stop it first");
@ -1450,7 +1450,7 @@ static int lpc_cmd_resume(LinphoneCore *lc, char *args){
}
}
return 0;
}
static int lpc_cmd_conference(LinphoneCore *lc, char *args){
@ -1659,7 +1659,7 @@ linphonec_proxy_add(LinphoneCore *lc)
}
/*
* Final confirmation
* Final confirmation
*/
while (1)
{
@ -1742,12 +1742,12 @@ linphonec_proxy_list(LinphoneCore *lc)
const MSList *proxies;
int n;
int def=linphone_core_get_default_proxy(lc,NULL);
proxies=linphone_core_get_proxy_config_list(lc);
for(n=0;proxies!=NULL;proxies=ms_list_next(proxies),n++){
if (n==def)
linphonec_out("****** Proxy %i - this is the default one - *******\n",n);
else
else
linphonec_out("****** Proxy %i *******\n",n);
linphonec_proxy_display((LinphoneProxyConfig*)proxies->data);
}
@ -1789,7 +1789,7 @@ linphonec_friend_display(LinphoneFriend *fr)
{
LinphoneAddress *uri=linphone_address_clone(linphone_friend_get_address(fr));
char *str;
linphonec_out("name: %s\n", linphone_address_get_display_name(uri));
linphone_address_set_display_name(uri,NULL);
str=linphone_address_as_string(uri);
@ -1874,7 +1874,7 @@ linphonec_friend_delete(LinphoneCore *lc, int num)
}
}
if (-1 == num)
if (-1 == num)
{
unsigned int i;
for (i = 0 ; i < n ; i++)
@ -1900,7 +1900,7 @@ static int lpc_cmd_register(LinphoneCore *lc, char *args){
char passwd[512];
LinphoneProxyConfig *cfg;
const MSList *elem;
if (!args)
{
/* it means that you want to register the default proxy */
@ -1979,7 +1979,7 @@ static int lpc_cmd_duration(LinphoneCore *lc, char *args){
static int lpc_cmd_status(LinphoneCore *lc, char *args)
{
LinphoneProxyConfig *cfg;
if ( ! args ) return 0;
linphone_core_get_default_proxy(lc,&cfg);
if (strstr(args,"register"))
@ -2042,7 +2042,7 @@ static int lpc_cmd_status(LinphoneCore *lc, char *args)
default:
break;
}
}
else return 0;
@ -2101,19 +2101,23 @@ static int lpc_cmd_speak(LinphoneCore *lc, char *args){
char voice[64];
char *sentence;
char cl[128];
char *wavfile;
char wavfile[128]="/tmp/linphonec-espeak-XXXXXX";
int status;
FILE *file;
if (!args) return 0;
memset(voice,0,sizeof(voice));
sscanf(args,"%63s",voice);
sentence=args+strlen(voice);
#ifdef __APPLE__
wavfile=mktemp("/tmp/linphonec-espeak-XXXXXX");
mktemp(wavfile);
#else
wavfile=tempnam("/tmp/","linphonec-espeak-");
if (mkstemp(wavfile)==-1){
ms_error("Could not create temporary filename: %s", strerror(errno));
linphonec_out("An error occured, please consult logs for details.");
return 1;
}
#endif
snprintf(cl,sizeof(cl),"espeak -v %s -s 100 -w %s --stdin",voice,wavfile);
@ -2200,7 +2204,7 @@ static void linphonec_codec_list(int type, LinphoneCore *lc){
for(;node!=NULL;node=ms_list_next(node)){
pt=(PayloadType*)(node->data);
linphonec_out("%2d: %s (%d) %s\n", index, pt->mime_type, pt->clock_rate,
linphonec_out("%2d: %s (%d) %s\n", index, pt->mime_type, pt->clock_rate,
linphone_core_payload_type_enabled(lc,pt) ? "enabled" : "disabled");
index++;
}
@ -2274,7 +2278,7 @@ static int lpc_cmd_echocancellation(LinphoneCore *lc, char *args){
if (arg2 != 0) {
n = sscanf(arg2, "%d %d %d", &delay, &tail_len, &frame_size);
if (n == 1) {
if (n == 1) {
lp_config_set_int(config,"sound","ec_delay",delay);
}
else if (n == 2) {
@ -2292,11 +2296,11 @@ static int lpc_cmd_echocancellation(LinphoneCore *lc, char *args){
linphone_core_enable_echo_cancellation(lc,0);
}
else if (strcmp(arg1,"show")==0){
linphonec_out("echo cancellation is %s; delay %d, tail length %d, frame size %d\n",
linphonec_out("echo cancellation is %s; delay %d, tail length %d, frame size %d\n",
linphone_core_echo_cancellation_enabled(lc) ? "on" : "off",
lp_config_get_int(config,"sound","ec_delay",0),
lp_config_get_int(config,"sound","ec_tail_len",0),
lp_config_get_int(config,"sound","ec_framesize",0));
lp_config_get_int(config,"sound","ec_framesize",0));
}
else {
return 0;
@ -2346,7 +2350,7 @@ static int lpc_cmd_rtp_no_xmit_on_audio_mute(LinphoneCore *lc, char *args)
if(strstr(args,"1"))rtp_xmit_off=TRUE;
if(linphone_core_get_current_call (lc)==NULL)
linphone_core_set_rtp_no_xmit_on_audio_mute(lc,rtp_xmit_off);
else
else
linphonec_out("nortp-on-audio-mute: call in progress - cannot change state\n");
}
rtp_xmit_off=linphone_core_get_rtp_no_xmit_on_audio_mute(lc);
@ -2434,7 +2438,7 @@ static void lpc_display_call_states(LinphoneCore *lc){
for(;elem!=NULL;elem=elem->next){
const char *flag;
call=(LinphoneCall*)elem->data;
bool_t in_conference=linphone_call_params_local_conference_mode(linphone_call_get_current_params(call));
bool_t in_conference=linphone_call_params_get_local_conference_mode(linphone_call_get_current_params(call));
tmp=linphone_call_get_remote_address_as_string (call);
flag=in_conference ? "conferencing" : "";
flag=linphone_call_has_transfer_pending(call) ? "transfer pending" : flag;
@ -2487,7 +2491,7 @@ static int lpc_cmd_states(LinphoneCore *lc, char *args){
static int lpc_cmd_camera(LinphoneCore *lc, char *args){
LinphoneCall *call=linphone_core_get_current_call(lc);
bool_t activated=FALSE;
if (linphone_core_video_enabled (lc)==FALSE){
linphonec_out("Video is disabled, re-run linphonec with -V option.");
return 1;

View file

@ -551,7 +551,7 @@ char *linphonec_readline(char *prompt){
should. Maybe should we only have this on when the option -V
or -D is on? */
MSG msg;
if (PeekMessage(&msg, NULL, 0, 0,1)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
@ -648,7 +648,7 @@ main (int argc, char *argv[]) {
linphonec_vtable.refer_received=linphonec_display_refer;
linphonec_vtable.transfer_state_changed=linphonec_transfer_state_changed;
linphonec_vtable.call_encryption_changed=linphonec_call_encryption_changed;
if (! linphonec_init(argc, argv) ) exit(EXIT_FAILURE);
linphonec_main_loop (linphonec);
@ -671,8 +671,8 @@ linphonec_init(int argc, char **argv)
* Set initial values for global variables
*/
mylogfile = NULL;
#ifndef _WIN32
snprintf(configfile_name, PATH_MAX, "%s/.linphonerc",
getenv("HOME"));
@ -701,7 +701,6 @@ linphonec_init(int argc, char **argv)
default:
break;
}
#ifdef ENABLE_NLS
if (NULL == bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR))
perror ("bindtextdomain failed");
@ -741,10 +740,12 @@ linphonec_init(int argc, char **argv)
* Initialize linphone core
*/
linphonec=linphone_core_new (&linphonec_vtable, configfile_name, factory_configfile_name, NULL);
linphone_core_set_user_agent(linphonec,"Linphonec", LINPHONE_VERSION);
linphone_core_set_zrtp_secrets_file(linphonec,zrtpsecrets);
linphone_core_enable_video_capture(linphonec, vcap_enabled);
linphone_core_enable_video_display(linphonec, display_enabled);
if (display_enabled && window_id != 0)
if (display_enabled && window_id != 0)
{
printf ("Setting window_id: 0x%x\n", window_id);
linphone_core_set_native_video_window_id(linphonec,window_id);
@ -782,7 +783,7 @@ linphonec_finish(int exit_status)
{
// Do not allow concurrent destroying to prevent glibc errors
static bool_t terminating=FALSE;
if (terminating) return;
if (terminating) return;
terminating=TRUE;
linphonec_out("Terminating...\n");
@ -829,9 +830,9 @@ linphonec_prompt_for_auth_final(LinphoneCore *lc)
#endif
if (reentrancy!=0) return 0;
reentrancy++;
LinphoneAuthInfo *pending_auth=auth_stack.elem[auth_stack.nitems-1];
snprintf(auth_prompt, 256, "Password for %s on %s: ",
@ -1159,7 +1160,6 @@ linphonec_main_loop (LinphoneCore * opm)
add_history(iptr);
}
#endif
linphonec_parse_command_line(linphonec, iptr);
linphonec_command_finished();
free(input);

View file

@ -91,7 +91,7 @@ if HAVE_LD_OUTPUT_DEF
liblinphone_la_LDFLAGS += -Wl,--output-def,liblinphone-$(LIBLINPHONE_SO_CURRENT).def
defexecdir = $(libdir)
defexec_DATA = liblinphone-$(LIBLINPHONE_SO_CURRENT).def
CLEANFILES = $(defexec_DATA)
CLEANFILES += $(defexec_DATA)
liblinphone-$(LIBLINPHONE_SO_CURRENT).def: liblinphone.la
@ -156,15 +156,21 @@ AM_CFLAGS+= -DUSE_BELLESIP
AM_CXXFLAGS=$(AM_CFLAGS)
#Make sure that we are in linphone's git tree by doing git log $(top_srcdir)/configure.ac.
#if it is something known to git, then that will be ok to check the git describe number and make sure it is consistent with
#the PACKAGE_VERSION given in configure.ac
make_gitversion_h:
if test "$(GITDESCRIBE)" != "" ; then \
if test "$(GIT_TAG)" != "$(PACKAGE_VERSION)" ; then \
echo "*** PACKAGE_VERSION and git tag differ. Please put them identical."; \
exit 1; \
if test -d $(top_srcdir)/.git ; then \
if test "$(GITDESCRIBE)" != "" ; then \
if test "$(GIT_TAG)" != "$(PACKAGE_VERSION)" ; then \
echo "*** PACKAGE_VERSION and git tag differ. Please put them identical."; \
exit 1; \
fi ; \
$(ECHO) -n "#define LIBLINPHONE_GIT_VERSION \"$(GITDESCRIBE)\"" > $(GITVERSION_FILE_TMP) ; \
elif test "$(GITREVISION)" != "" ; then \
$(ECHO) -n "#define LIBLINPHONE_GIT_VERSION \"$(LINPHONE_VERSION)_$(GITREVISION)\"" > $(GITVERSION_FILE_TMP) ; \
fi ; \
$(ECHO) -n "#define LIBLINPHONE_GIT_VERSION \"$(GITDESCRIBE)\"" > $(GITVERSION_FILE_TMP) ; \
elif test "$(GITREVISION)" != "" ; then \
$(ECHO) -n "#define LIBLINPHONE_GIT_VERSION \"$(LINPHONE_VERSION)_$(GITREVISION)\"" > $(GITVERSION_FILE_TMP) ; \
else \
$(ECHO) -n "" > $(GITVERSION_FILE_TMP) ; \
fi

View file

@ -30,82 +30,6 @@
using namespace belledonnecomm;
using namespace ::std;
#ifndef USE_BELLESIP
Mutex TunnelManager::sMutex;
int TunnelManager::eXosipSendto(int fd,const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen,void* userdata){
TunnelManager* lTunnelMgr=(TunnelManager*)userdata;
sMutex.lock();
if (lTunnelMgr->mSipSocket==NULL){
sMutex.unlock();
return len;
}
lTunnelMgr->mSipSocket->sendto(buf,len,to,tolen);
sMutex.unlock();
//ignore the error in all cases, retransmissions might be successful.
return len;
}
int TunnelManager::eXosipRecvfrom(int fd, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen,void* userdata){
TunnelManager* lTunnelMgr=(TunnelManager*)userdata;
int err;
sMutex.lock();
if (lTunnelMgr->mSipSocket==NULL){
sMutex.unlock();
return 0;//let ignore the error
}
err=lTunnelMgr->mSipSocket->recvfrom(buf,len,from,*fromlen);
sMutex.unlock();
return err;
}
int TunnelManager::eXosipSelect(int max_fds, fd_set *s1, fd_set *s2, fd_set *s3, struct timeval *tv,void* userdata){
struct timeval begin,cur;
TunnelManager* lTunnelMgr=(TunnelManager*)userdata;
if (s1 && tv!=0 && tv->tv_sec){
/*this is the select from udp.c, the one that is interesting to us*/
NativeSocket udp_fd=(NativeSocket)eXosip_get_udp_socket();
NativeSocket controlfd=(NativeSocket)eXosip_get_control_fd();
FD_ZERO(s1);
gettimeofday(&begin,NULL);
do{
struct timeval abit;
abit.tv_sec=0;
abit.tv_usec=20000;
sMutex.lock();
if (lTunnelMgr->mSipSocket!=NULL){
if (lTunnelMgr->mSipSocket->hasData()) {
sMutex.unlock();
/* we make exosip believe that it has udp data to read*/
FD_SET(udp_fd,s1);
return 1;
}
}
sMutex.unlock();
gettimeofday(&cur,NULL);
if (cur.tv_sec-begin.tv_sec>tv->tv_sec) {
FD_SET(controlfd,s1);
FD_SET(udp_fd,s1);
return 0;
}
FD_ZERO(s1);
FD_SET(controlfd,s1);
if (select(max_fds,s1,s2,s3,&abit)==1) {
return 1;
}
}while(1);
}else{
/*select called from other places, only the control fd is present */
return select(max_fds,s1,s2,s3,tv);
}
}
#endif
void TunnelManager::addServer(const char *ip, int port,unsigned int udpMirrorPort,unsigned int delay) {
if (ip == NULL) {
@ -186,10 +110,6 @@ void TunnelManager::start() {
mTunnelClient->setHttpProxy(mHttpProxyHost.c_str(), mHttpProxyPort, mHttpUserName.c_str(), mHttpPasswd.c_str());
}
mTunnelClient->start();
#ifndef USE_BELLESIP
if (mSipSocket == NULL) mSipSocket =mTunnelClient->createSocket(5060);
#endif
}
bool TunnelManager::isStarted() {
@ -217,9 +137,6 @@ int TunnelManager::customRecvfrom(struct _RtpTransport *t, mblk_t *msg, int flag
TunnelManager::TunnelManager(LinphoneCore* lc) :TunnelClientController()
,mCore(lc)
#ifndef USE_BELLESIP
,mSipSocket(NULL)
#endif
,mCallback(NULL)
,mEnabled(false)
,mTunnelClient(NULL)
@ -227,12 +144,6 @@ TunnelManager::TunnelManager(LinphoneCore* lc) :TunnelClientController()
,mReady(false)
,mHttpProxyPort(0){
#ifndef USE_BELLESIP
mExosipTransport.data=this;
mExosipTransport.recvfrom=eXosipRecvfrom;
mExosipTransport.sendto=eXosipSendto;
mExosipTransport.select=eXosipSelect;
#endif
linphone_core_add_iterate_hook(mCore,(LinphoneCoreIterateHook)sOnIterate,this);
mTransportFactories.audio_rtcp_func=sCreateRtpTransport;
mTransportFactories.audio_rtcp_func_data=this;
@ -249,17 +160,7 @@ TunnelManager::~TunnelManager(){
}
void TunnelManager::stopClient(){
#ifdef USE_BELLESIP
sal_disable_tunnel(mCore->sal);
#else
eXosip_transport_hook_register(NULL);
if (mSipSocket != NULL){
sMutex.lock();
mTunnelClient->closeSocket(mSipSocket);
mSipSocket = NULL;
sMutex.unlock();
}
#endif
if (mTunnelClient){
delete mTunnelClient;
mTunnelClient=NULL;
@ -279,16 +180,11 @@ void TunnelManager::processTunnelEvent(const Event &ev){
//register
if (lProxy) {
linphone_proxy_config_done(lProxy);
linphone_proxy_config_refresh_register(lProxy);
}
mReady=true;
}else if (mEnabled && !mTunnelClient->isReady()){
/* we got disconnected from the tunnel */
if (lProxy && linphone_proxy_config_is_registered(lProxy)) {
/*forces de-registration so that we register again when the tunnel is up*/
linphone_proxy_config_edit(lProxy);
linphone_core_iterate(mCore);
}
mReady=false;
}
}
@ -299,6 +195,8 @@ void TunnelManager::waitUnRegistration(){
if (lProxy && linphone_proxy_config_get_state(lProxy)==LinphoneRegistrationOk) {
int i=0;
linphone_proxy_config_edit(lProxy);
linphone_proxy_config_enable_register(lProxy,FALSE);
linphone_proxy_config_done(lProxy);
//make sure unregister is sent and authenticated
do{
linphone_core_iterate(mCore);
@ -348,6 +246,8 @@ void TunnelManager::enable(bool isEnable) {
LinphoneProxyConfig* lProxy;
linphone_core_get_default_proxy(mCore, &lProxy);
if (lProxy) {
linphone_proxy_config_edit(lProxy);
linphone_proxy_config_enable_register(lProxy,TRUE);
linphone_proxy_config_done(lProxy);
}

View file

@ -97,14 +97,13 @@ void sal_disable_logs() {
void sal_add_pending_auth(Sal *sal, SalOp *op){
if (ms_list_find(sal->pending_auths,op)==NULL){
sal->pending_auths=ms_list_append(sal->pending_auths,sal_op_ref(op));
sal->pending_auths=ms_list_append(sal->pending_auths,op);
}
}
void sal_remove_pending_auth(Sal *sal, SalOp *op){
if (ms_list_find(sal->pending_auths,op)){
sal->pending_auths=ms_list_remove(sal->pending_auths,op);
sal_op_unref(op);
}
}
@ -157,7 +156,10 @@ void sal_process_authentication(SalOp *op) {
}
}
/*always store auth info, for case of wrong credential*/
if (op->auth_info) sal_auth_info_delete(op->auth_info);
if (op->auth_info) {
sal_auth_info_delete(op->auth_info);
op->auth_info=NULL;
}
if (auth_list){
auth_event=(belle_sip_auth_event_t*)(auth_list->data);
op->auth_info=sal_auth_info_create(auth_event);
@ -321,9 +323,8 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even
belle_sip_message("Op is terminated, nothing to do with this [%i]",response_code);
return;
}
if (!op->base.remote_ua) {
sal_op_set_remote_ua(op,BELLE_SIP_MESSAGE(response));
}
/*do it all the time, since we can receive provisional responses from a different instance than the final one*/
sal_op_set_remote_ua(op,BELLE_SIP_MESSAGE(response));
if(remote_contact) {
__sal_op_set_remote_contact(op, belle_sip_header_get_unparsed_value(BELLE_SIP_HEADER(remote_contact)));
@ -342,7 +343,6 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even
break;
case 401:
case 407:
/*belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),NULL);*//*remove op from trans*/
if (op->state == SalOpStateTerminating && strcmp("BYE",belle_sip_request_get_method(request))!=0) {
/*only bye are completed*/
belle_sip_message("Op is in state terminating, nothing else to do ");
@ -376,8 +376,8 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even
ms_error("Unhandled event response [%p]",event);
}
}
}
static void process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) {
belle_sip_client_transaction_t* client_transaction = belle_sip_timeout_event_get_client_transaction(event);
SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction));
@ -387,6 +387,7 @@ static void process_timeout(void *user_ctx, const belle_sip_timeout_event_t *eve
ms_error("Unhandled event timeout [%p]",event);
}
}
static void process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) {
belle_sip_client_transaction_t* client_transaction = belle_sip_transaction_terminated_event_get_client_transaction(event);
belle_sip_server_transaction_t* server_transaction = belle_sip_transaction_terminated_event_get_server_transaction(event);
@ -396,7 +397,7 @@ static void process_transaction_terminated(void *user_ctx, const belle_sip_trans
if(client_transaction)
trans=BELLE_SIP_TRANSACTION(client_transaction);
else
trans=BELLE_SIP_TRANSACTION(server_transaction);
trans=BELLE_SIP_TRANSACTION(server_transaction);
op = (SalOp*)belle_sip_transaction_get_application_data(trans);
if (op && op->callbacks && op->callbacks->process_transaction_terminated) {
@ -404,8 +405,7 @@ static void process_transaction_terminated(void *user_ctx, const belle_sip_trans
} else {
ms_message("Unhandled transaction terminated [%p]",trans);
}
if (op && client_transaction) sal_op_unref(op); /*because every client transaction ref op*/
if (op) sal_op_unref(op); /*because every transaction ref op*/
}
@ -423,19 +423,21 @@ static void process_auth_requested(void *sal, belle_sip_auth_event_t *event) {
Sal * sal_init(){
belle_sip_listener_callbacks_t listener_callbacks;
Sal * sal=ms_new0(Sal,1);
/*belle_sip_object_enable_marshal_check(TRUE);*/
sal->auto_contacts=TRUE;
/*first create the stack, which initializes the belle-sip object's pool for this thread*/
belle_sip_set_log_handler(_belle_sip_log);
sal->stack = belle_sip_stack_new(NULL);
sal->user_agent=belle_sip_header_user_agent_new();
#if defined(PACKAGE_NAME) && defined(LINPHONE_VERSION)
belle_sip_header_user_agent_add_product(sal->user_agent, PACKAGE_NAME "/" LINPHONE_VERSION);
#endif
sal_append_stack_string_to_user_agent(sal);
belle_sip_object_ref(sal->user_agent);
sal->prov = belle_sip_stack_create_provider(sal->stack,NULL);
sal_nat_helper_enable(sal,TRUE);
memset(&listener_callbacks,0,sizeof(listener_callbacks));
@ -451,6 +453,7 @@ Sal * sal_init(){
sal->tls_verify=TRUE;
sal->tls_verify_cn=TRUE;
sal->refresher_retry_after=60000; /*default value in ms*/
sal->enable_sip_update=TRUE;
return sal;
}
@ -613,6 +616,12 @@ void sal_set_user_agent(Sal *ctx, const char *user_agent){
return ;
}
const char* sal_get_user_agent(Sal *ctx){
static char user_agent[255];
belle_sip_header_user_agent_get_products_as_string(ctx->user_agent, user_agent, 254);
return user_agent;
}
void sal_append_stack_string_to_user_agent(Sal *ctx) {
char stack_string[64];
snprintf(stack_string, sizeof(stack_string) - 1, "(belle-sip/%s)", belle_sip_version_to_string());
@ -999,3 +1008,7 @@ void sal_cancel_timer(Sal *sal, belle_sip_source_t *timer) {
belle_sip_main_loop_t *ml = belle_sip_stack_get_main_loop(sal->stack);
belle_sip_main_loop_remove_source(ml, timer);
}
void sal_enable_sip_update_method(Sal *ctx,bool_t value) {
ctx->enable_sip_update=value;
}

View file

@ -48,6 +48,7 @@ struct Sal{
bool_t auto_contacts;
bool_t enable_test_features;
bool_t no_initial_route;
bool_t enable_sip_update; /*true by default*/
};
typedef enum SalOpState {

View file

@ -27,16 +27,11 @@ static void call_set_released(SalOp* op){
op->state=SalOpStateTerminated;
op->base.root->callbacks.call_released(op);
op->call_released=TRUE;
/*be aware that the following line may destroy the op*/
set_or_update_dialog(op,NULL);
}
}
/*used when the SalOp was ref'd by the dialog, in which case we rely only on the dialog terminated notification*/
static void call_set_released_and_unref(SalOp* op) {
call_set_released(op);
sal_op_unref(op);
}
static void call_set_error(SalOp* op,belle_sip_response_t* response){
sal_op_set_error_info_from_response(op,response);
op->base.root->callbacks.call_failure(op);
@ -62,7 +57,7 @@ static void sdp_process(SalOp *h){
strcpy(h->result->addr,h->base.remote_media->addr);
h->result->bandwidth=h->base.remote_media->bandwidth;
for(i=0;i<h->result->n_active_streams;++i){
for(i=0;i<sal_media_description_get_nb_active_streams(h->result);++i){
strcpy(h->result->streams[i].rtp_addr,h->base.remote_media->streams[i].rtp_addr);
h->result->streams[i].ptime=h->base.remote_media->streams[i].ptime;
h->result->streams[i].bandwidth=h->base.remote_media->streams[i].bandwidth;
@ -70,7 +65,7 @@ static void sdp_process(SalOp *h){
strcpy(h->result->streams[i].rtcp_addr,h->base.remote_media->streams[i].rtcp_addr);
h->result->streams[i].rtcp_port=h->base.remote_media->streams[i].rtcp_port;
if (h->result->streams[i].proto == SalProtoRtpSavp) {
if ((h->result->streams[i].proto == SalProtoRtpSavpf) || (h->result->streams[i].proto == SalProtoRtpSavp)) {
h->result->streams[i].crypto[0] = h->base.remote_media->streams[i].crypto[0];
}
}
@ -142,7 +137,7 @@ static void process_dialog_terminated(void *ctx, const belle_sip_dialog_terminat
break;
}
belle_sip_main_loop_do_later(belle_sip_stack_get_main_loop(op->base.root->stack)
,(belle_sip_callback_t) call_set_released_and_unref
,(belle_sip_callback_t) call_set_released
, op);
} else {
ms_error("dialog unknown for op ");
@ -152,6 +147,10 @@ static void process_dialog_terminated(void *ctx, const belle_sip_dialog_terminat
static void handle_sdp_from_response(SalOp* op,belle_sip_response_t* response) {
belle_sdp_session_description_t* sdp;
SalReason reason;
if (op->base.remote_media){
sal_media_description_unref(op->base.remote_media);
op->base.remote_media=NULL;
}
if (extract_sdp(BELLE_SIP_MESSAGE(response),&sdp,&reason)==0) {
if (sdp){
op->base.remote_media=sal_media_description_new();
@ -168,12 +167,14 @@ static void cancelling_invite(SalOp* op ){
sal_op_send_request(op,cancel);
op->state=SalOpStateTerminating;
}
static int vfu_retry (void *user_data, unsigned int events) {
SalOp *op=(SalOp *)user_data;
sal_call_send_vfu_request(op);
sal_op_unref(op);
return BELLE_SIP_STOP;
}
static void call_process_response(void *op_base, const belle_sip_response_event_t *event){
SalOp* op = (SalOp*)op_base;
belle_sip_request_t* ack;
@ -183,17 +184,17 @@ static void call_process_response(void *op_base, const belle_sip_response_event_
belle_sip_response_t* response=belle_sip_response_event_get_response(event);
int code = belle_sip_response_get_status_code(response);
belle_sip_header_content_type_t *header_content_type=NULL;
belle_sip_dialog_t *dialog=belle_sip_response_event_get_dialog(event);
if (!client_transaction) {
ms_warning("Discarding stateless response [%i] on op [%p]",code,op);
return;
}
req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction));
set_or_update_dialog(op,belle_sip_response_event_get_dialog(event));
dialog_state=op->dialog?belle_sip_dialog_get_state(op->dialog):BELLE_SIP_DIALOG_NULL;
set_or_update_dialog(op,dialog);
dialog_state=dialog ? belle_sip_dialog_get_state(dialog) : BELLE_SIP_DIALOG_NULL;
ms_message("Op [%p] receiving call response [%i], dialog is [%p] in state [%s]",op,code,op->dialog,belle_sip_dialog_state_to_string(dialog_state));
ms_message("Op [%p] receiving call response [%i], dialog is [%p] in state [%s]",op,code,dialog,belle_sip_dialog_state_to_string(dialog_state));
switch(dialog_state) {
case BELLE_SIP_DIALOG_NULL:
@ -215,14 +216,18 @@ static void call_process_response(void *op_base, const belle_sip_response_event_
if (op->dialog==NULL) call_set_released(op);
}
}
} else if (code >= 180 && code<300) {
handle_sdp_from_response(op,response);
op->base.root->callbacks.call_ringing(op);
} else if (code >= 180 && code<200) {
belle_sip_response_t *prev_response=belle_sip_object_data_get(BELLE_SIP_OBJECT(dialog),"early_response");
if (!prev_response || code>belle_sip_response_get_status_code(prev_response)){
handle_sdp_from_response(op,response);
op->base.root->callbacks.call_ringing(op);
}
belle_sip_object_data_set(BELLE_SIP_OBJECT(dialog),"early_response",belle_sip_object_ref(response),belle_sip_object_unref);
} else if (code>=300){
call_set_error(op,response);
if (op->dialog==NULL) call_set_released(op);
}
} else if ( code >=200
} else if (code >=200
&& code<300
&& strcmp("UPDATE",belle_sip_request_get_method(req))==0) {
handle_sdp_from_response(op,response);
@ -364,7 +369,7 @@ static int extract_sdp(belle_sip_message_t* message,belle_sdp_session_descriptio
}
static int is_media_description_acceptable(SalMediaDescription *md){
if (md->n_total_streams==0){
if (md->nb_streams==0){
ms_warning("Media description does not define any stream.");
return FALSE;
}
@ -418,8 +423,7 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t
if (strcmp("ACK",method)!=0){ /*ACK does'nt create srv transaction*/
server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,belle_sip_request_event_get_request(event));
belle_sip_object_ref(server_transaction);
belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(server_transaction),op);
sal_op_ref(op);
belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(server_transaction),sal_op_ref(op));
}
if (strcmp("INVITE",method)==0) {
@ -561,6 +565,9 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t
} else if (strcmp("MESSAGE",method)==0){
sal_process_incoming_message(op,event);
} else if (strcmp("UPDATE",method)==0) {
/*FIXME jehan: It might be better to silently accept UPDATE which do not modify either the number or the nature of streams*/
/*rfc 3311
* 5.2 Receiving an UPDATE
* ...
@ -568,8 +575,9 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t
* the request with a 504 response.
*/
resp=sal_op_create_response_from_request(op,req,504);
belle_sip_message_add_header( BELLE_SIP_MESSAGE(resp)
,belle_sip_header_create( "Warning", "Cannot change the session parameters without prompting the user"));
belle_sip_response_set_reason_phrase(resp,"Cannot change the session parameters without prompting the user");
/*belle_sip_message_add_header( BELLE_SIP_MESSAGE(resp)
,belle_sip_header_create( "Warning", "Cannot change the session parameters without prompting the user"));*/
belle_sip_server_transaction_send_response(server_transaction,resp);
return;
}else{
@ -607,14 +615,16 @@ int sal_call_set_local_media_description(SalOp *op, SalMediaDescription *desc){
return 0;
}
static belle_sip_header_allow_t *create_allow(){
static belle_sip_header_allow_t *create_allow(bool_t enable_update){
belle_sip_header_allow_t* header_allow;
header_allow = belle_sip_header_allow_create("INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO, UPDATE");
char allow [256];
snprintf(allow,sizeof(allow),"INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO%s",(enable_update?", UPDATE":""));
header_allow = belle_sip_header_allow_create(allow);
return header_allow;
}
static void sal_op_fill_invite(SalOp *op, belle_sip_request_t* invite) {
belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),BELLE_SIP_HEADER(create_allow()));
belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),BELLE_SIP_HEADER(create_allow(op->base.root->enable_sip_update)));
if (op->base.root->session_expires!=0){
belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),belle_sip_header_create( "Session-expires", "200"));
@ -742,7 +752,7 @@ int sal_call_accept(SalOp*h){
ms_error("Fail to build answer for call");
return -1;
}
belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(create_allow()));
belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(create_allow(h->base.root->enable_sip_update)));
if (h->base.root->session_expires!=0){
if (h->supports_session_timers) {
belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),belle_sip_header_create("Supported", "timer"));

View file

@ -122,9 +122,9 @@ int sal_call_set_referer(SalOp *h, SalOp *refered_call){
SalOp *sal_call_get_replaces(SalOp *op){
if (op && op->replaces){
belle_sip_dialog_t* dialog=belle_sip_provider_find_dialog(op->base.root->prov
,belle_sip_header_replaces_get_call_id(op->replaces)
,belle_sip_header_replaces_get_from_tag(op->replaces)
,belle_sip_header_replaces_get_to_tag(op->replaces));
,belle_sip_header_replaces_get_call_id(op->replaces)
,belle_sip_header_replaces_get_from_tag(op->replaces)
,belle_sip_header_replaces_get_to_tag(op->replaces));
if (dialog) {
return (SalOp*)belle_sip_dialog_get_application_data(dialog);
@ -208,7 +208,7 @@ void sal_op_process_refer(SalOp *op, const belle_sip_request_event_t *event, bel
belle_sip_free(refer_to_uri_str);
} else {
ms_warning("cannot do anything with the refer without destination\n");
resp = sal_op_create_response_from_request(op,req,501);
resp = sal_op_create_response_from_request(op,req,400);
belle_sip_server_transaction_send_response(server_transaction,resp);
}
@ -233,9 +233,9 @@ void sal_op_call_process_notify(SalOp *op, const belle_sip_request_event_t *even
if (sipfrag){
int code=belle_sip_response_get_status_code(sipfrag);
SalReferStatus status=SalReferFailed;
if (code==100){
if (code<200){
status=SalReferTrying;
}else if (code==200){
}else if (code<300){
status=SalReferSuccess;
}else if (code>=400){
status=SalReferFailed;

View file

@ -44,8 +44,8 @@ void sal_op_release(SalOp *op){
void sal_op_release_impl(SalOp *op){
ms_message("Destroying op [%p] of type [%s]",op,sal_op_type_to_string(op->type));
if (op->pending_auth_transaction) belle_sip_object_unref(op->pending_auth_transaction);
sal_remove_pending_auth(op->base.root,op);
if (op->auth_info) {
sal_remove_pending_auth(op->base.root,op);
sal_auth_info_delete(op->auth_info);
}
if (op->sdp_answer) belle_sip_object_unref(op->sdp_answer);
@ -560,21 +560,30 @@ const SalErrorInfo *sal_op_get_error_info(const SalOp *op){
return &op->error_info;
}
static void unlink_op_with_dialog(SalOp *op, belle_sip_dialog_t* dialog){
belle_sip_dialog_set_application_data(dialog,NULL);
sal_op_unref(op);
belle_sip_object_unref(dialog);
}
static belle_sip_dialog_t *link_op_with_dialog(SalOp *op, belle_sip_dialog_t* dialog){
belle_sip_dialog_set_application_data(dialog,sal_op_ref(op));
belle_sip_object_ref(dialog);
return dialog;
}
void set_or_update_dialog(SalOp* op, belle_sip_dialog_t* dialog) {
/*check if dialog has changed*/
if (dialog && dialog != op->dialog) {
ms_message("Dialog set from [%p] to [%p] for op [%p]",op->dialog,dialog,op);
/*fixme, shouldn't we cancel previous dialog*/
if (op->dialog) {
belle_sip_dialog_set_application_data(op->dialog,NULL);
belle_sip_object_unref(op->dialog);
sal_op_unref(op);
ms_message("op [%p] : set_or_update_dialog() current=[%p] new=[%p]",op,op->dialog,dialog);
sal_op_ref(op);
if (op->dialog!=dialog){
if (op->dialog){
/*FIXME: shouldn't we delete unconfirmed dialogs ?*/
unlink_op_with_dialog(op,op->dialog);
op->dialog=NULL;
}
op->dialog=dialog;
belle_sip_dialog_set_application_data(op->dialog,op);
sal_op_ref(op);
belle_sip_object_ref(op->dialog);
if (dialog) op->dialog=link_op_with_dialog(op,dialog);
}
sal_op_unref(op);
}
/*return reffed op*/
SalOp* sal_op_ref(SalOp* op) {
@ -599,6 +608,13 @@ int sal_op_send_and_create_refresher(SalOp* op,belle_sip_request_t* req, int exp
belle_sip_object_unref(op->refresher);
}
if ((op->refresher = belle_sip_client_transaction_create_refresher(op->pending_client_trans))) {
/*since refresher acquires the transaction, we should remove our context from the transaction, because we won't be notified
* that it is terminated anymore.*/
sal_op_unref(op);/*loose the reference that was given to the transaction when creating it*/
/* Note that the refresher will replace our data with belle_sip_transaction_set_application_data().
Something in the design is not very good here, it makes things complicated to the belle-sip user.
Possible ideas to improve things: refresher shall not use belle_sip_transaction_set_application_data() internally, refresher should let the first transaction
notify the user as a normal transaction*/
belle_sip_refresher_set_listener(op->refresher,listener,op);
belle_sip_refresher_set_retry_after(op->refresher,op->base.root->refresher_retry_after);
belle_sip_refresher_enable_manual_mode(op->refresher,op->manual_refresher);

View file

@ -55,6 +55,11 @@ static void process_response_event(void *op_base, const belle_sip_response_event
op->base.root->callbacks.text_delivery_update(op,status);
}
static bool_t is_rcs_filetransfer(belle_sip_header_content_type_t* content_type) {
return strcmp("application",belle_sip_header_content_type_get_type(content_type))==0
&& strcmp("vnd.gsma.rcs-ft-http+xml",belle_sip_header_content_type_get_subtype(content_type))==0;
}
static bool_t is_plain_text(belle_sip_header_content_type_t* content_type) {
return strcmp("text",belle_sip_header_content_type_get_type(content_type))==0
&& strcmp("plain",belle_sip_header_content_type_get_subtype(content_type))==0;
@ -69,7 +74,7 @@ static bool_t is_im_iscomposing(belle_sip_header_content_type_t* content_type) {
}
static void add_message_accept(belle_sip_message_t *msg){
belle_sip_message_add_header(msg,belle_sip_header_create("Accept","text/plain, message/external-body, application/im-iscomposing+xml"));
belle_sip_message_add_header(msg,belle_sip_header_create("Accept","text/plain, message/external-body, application/im-iscomposing+xml, application/vnd.gsma.rcs-ft-http+xml"));
}
void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *event){
@ -85,11 +90,13 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve
char* from;
bool_t plain_text=FALSE;
bool_t external_body=FALSE;
bool_t rcs_filetransfer=FALSE;
from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t);
content_type=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_content_type_t);
if (content_type && ((plain_text=is_plain_text(content_type))
|| (external_body=is_external_body(content_type)))) {
|| (external_body=is_external_body(content_type))
|| (rcs_filetransfer=is_rcs_filetransfer(content_type)))) {
SalMessage salmsg;
char message_id[256]={0};
@ -104,8 +111,12 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve
,belle_sip_header_call_id_get_call_id(call_id)
,belle_sip_header_cseq_get_seq_number(cseq));
salmsg.from=from;
salmsg.text=plain_text?belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)):NULL;
salmsg.text=(plain_text||rcs_filetransfer)?belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)):NULL;
salmsg.url=NULL;
salmsg.content_type = NULL;
if (rcs_filetransfer) { /* if we have a rcs file transfer, set the type, message body (stored in salmsg.text) contains all needed information to retrieve the file */
salmsg.content_type = "application/vnd.gsma.rcs-ft-http+xml";
}
if (external_body && belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")) {
size_t url_length=strlen(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL"));
salmsg.url = ms_strdup(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")+1); /* skip first "*/

View file

@ -56,13 +56,15 @@ static void register_refresher_listener (belle_sip_refresher_t* refresher
chooses not to re-register, the UA SHOULD discard any stored service
route for that address-of-record. */
sal_op_set_service_route(op,NULL);
sal_op_ref(op); /*take a ref while invoking the callback to make sure the operations done after are valid*/
op->base.root->callbacks.register_failure(op);
if (op->auth_info) {
if (op->state!=SalOpStateTerminated && op->auth_info) {
/*add pending auth*/
sal_add_pending_auth(op->base.root,op);
if (status_code==403 || status_code==401 || status_code==407 )
op->base.root->callbacks.auth_failure(op,op->auth_info);
}
sal_op_unref(op);
}
}

View file

@ -68,6 +68,82 @@ static void add_ice_remote_candidates(belle_sdp_media_description_t *md, const S
if (buffer[0] != '\0') belle_sdp_media_description_add_attribute(md,belle_sdp_attribute_create("remote-candidates",buffer));
}
static bool_t is_rtcp_fb_trr_int_the_same_for_all_payloads(const SalStreamDescription *stream, uint16_t *trr_int) {
MSList *pt_it;
bool_t first = TRUE;
for (pt_it = stream->payloads; pt_it != NULL; pt_it = pt_it->next) {
PayloadType *pt = (PayloadType *)pt_it->data;
if (payload_type_get_flags(pt) & PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED) {
if (first == TRUE) {
*trr_int = payload_type_get_avpf_params(pt).trr_interval;
first = FALSE;
} else if (payload_type_get_avpf_params(pt).trr_interval != *trr_int) {
return FALSE;
}
}
}
return TRUE;
}
static void add_rtcp_fb_trr_int_attribute(belle_sdp_media_description_t *media_desc, int8_t id, uint16_t trr_int) {
belle_sdp_rtcp_fb_attribute_t *attribute = belle_sdp_rtcp_fb_attribute_new();
belle_sdp_rtcp_fb_attribute_set_id(attribute, id);
belle_sdp_rtcp_fb_attribute_set_type(attribute, BELLE_SDP_RTCP_FB_TRR_INT);
belle_sdp_rtcp_fb_attribute_set_trr_int(attribute, trr_int);
belle_sdp_media_description_add_attribute(media_desc, BELLE_SDP_ATTRIBUTE(attribute));
}
static void add_rtcp_fb_nack_attribute(belle_sdp_media_description_t *media_desc, int8_t id, belle_sdp_rtcp_fb_val_param_t param) {
belle_sdp_rtcp_fb_attribute_t *attribute = belle_sdp_rtcp_fb_attribute_new();
belle_sdp_rtcp_fb_attribute_set_id(attribute, id);
belle_sdp_rtcp_fb_attribute_set_type(attribute, BELLE_SDP_RTCP_FB_NACK);
belle_sdp_rtcp_fb_attribute_set_param(attribute, param);
belle_sdp_media_description_add_attribute(media_desc, BELLE_SDP_ATTRIBUTE(attribute));
}
static void add_rtcp_fb_ccm_attribute(belle_sdp_media_description_t *media_desc, int8_t id, belle_sdp_rtcp_fb_val_param_t param) {
belle_sdp_rtcp_fb_attribute_t *attribute = belle_sdp_rtcp_fb_attribute_new();
belle_sdp_rtcp_fb_attribute_set_id(attribute, id);
belle_sdp_rtcp_fb_attribute_set_type(attribute, BELLE_SDP_RTCP_FB_CCM);
belle_sdp_rtcp_fb_attribute_set_param(attribute, param);
belle_sdp_media_description_add_attribute(media_desc, BELLE_SDP_ATTRIBUTE(attribute));
}
static void add_rtcp_fb_attributes(belle_sdp_media_description_t *media_desc, const SalMediaDescription *md, const SalStreamDescription *stream) {
MSList *pt_it;
PayloadType *pt;
PayloadTypeAvpfParams avpf_params;
bool_t general_trr_int;
uint16_t trr_int = 0;
general_trr_int = is_rtcp_fb_trr_int_the_same_for_all_payloads(stream, &trr_int);
if (general_trr_int == TRUE) {
add_rtcp_fb_trr_int_attribute(media_desc, -1, trr_int);
}
for (pt_it = stream->payloads; pt_it != NULL; pt_it = pt_it->next) {
pt = (PayloadType *)pt_it->data;
/* AVPF/SAVPF profile is used so enable AVPF for all paylad types. */
payload_type_set_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED);
avpf_params = payload_type_get_avpf_params(pt);
/* Add rtcp-fb attributes according to the AVPF features of the payload types. */
if (avpf_params.features & PAYLOAD_TYPE_AVPF_PLI) {
add_rtcp_fb_nack_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_PLI);
}
if (avpf_params.features & PAYLOAD_TYPE_AVPF_SLI) {
add_rtcp_fb_nack_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_SLI);
}
if (avpf_params.features & PAYLOAD_TYPE_AVPF_RPSI) {
add_rtcp_fb_nack_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_RPSI);
}
if (avpf_params.features & PAYLOAD_TYPE_AVPF_FIR) {
add_rtcp_fb_ccm_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_FIR);
}
}
}
static belle_sdp_attribute_t * create_rtcp_xr_attribute(const OrtpRtcpXrConfiguration *config) {
belle_sdp_rtcp_xr_attribute_t *attribute = belle_sdp_rtcp_xr_attribute_new();
if (config->rcvr_rtt_mode != OrtpRtcpXrRcvrRttNone) {
@ -100,12 +176,12 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session
int rtp_port;
int rtcp_port;
bool_t different_rtp_and_rtcp_addr;
rtp_addr=stream->rtp_addr;
rtcp_addr=stream->rtcp_addr;
rtp_port=stream->rtp_port;
rtcp_port=stream->rtcp_port;
media_desc = belle_sdp_media_description_create ( sal_stream_description_get_type_as_string(stream)
,stream->rtp_port
,1
@ -139,43 +215,22 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session
}else inet6=FALSE;
belle_sdp_media_description_set_connection(media_desc,belle_sdp_connection_create("IN", inet6 ? "IP6" : "IP4", rtp_addr));
}
if ( stream->bandwidth>0 )
belle_sdp_media_description_set_bandwidth ( media_desc,"AS",stream->bandwidth );
if ( stream->proto == SalProtoRtpSavp ) {
if ((stream->proto == SalProtoRtpSavpf) || (stream->proto == SalProtoRtpSavp)) {
/* add crypto lines */
for ( j=0; j<SAL_CRYPTO_ALGO_MAX; j++ ) {
const char *enc_name=NULL;
switch ( stream->crypto[j].algo ) {
case MS_AES_128_SHA1_80:
enc_name="AES_CM_128_HMAC_SHA1_80";
break;
case MS_AES_128_SHA1_32:
enc_name="AES_CM_128_HMAC_SHA1_32";
break;
case MS_AES_256_SHA1_32:
enc_name="AES_CM_256_HMAC_SHA1_32";
break;
case MS_AES_256_SHA1_80:
enc_name="AES_CM_256_HMAC_SHA1_32";
break;
case MS_AES_128_NO_AUTH:
ms_warning ( "Unsupported crypto suite: AES_128_NO_AUTH" );
break;
case MS_NO_CIPHER_SHA1_80:
ms_warning ( "Unsupported crypto suite: NO_CIPHER_SHA1_80" );
break;
default:
j = SAL_CRYPTO_ALGO_MAX;
/* no break */
}
if (enc_name){
snprintf ( buffer, sizeof ( buffer )-1, "%d %s inline:%s",
stream->crypto[j].tag, enc_name, stream->crypto[j].master_key );
belle_sdp_media_description_add_attribute ( media_desc,belle_sdp_attribute_create ( "crypto",buffer ) );
}
MSCryptoSuiteNameParams desc;
if (ms_crypto_suite_to_name_params(stream->crypto[j].algo,&desc)==0){
if (desc.params)
snprintf ( buffer, sizeof ( buffer )-1, "%d %s inline:%s %s", stream->crypto[j].tag, desc.name, stream->crypto[j].master_key,desc.params);
else
snprintf ( buffer, sizeof ( buffer )-1, "%d %s inline:%s", stream->crypto[j].tag, desc.name, stream->crypto[j].master_key );
belle_sdp_media_description_add_attribute( media_desc,belle_sdp_attribute_create ("crypto", buffer));
}else break;
}
}
switch ( stream->dir ) {
@ -222,7 +277,11 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session
}
}
if (stream->rtcp_xr.enabled == TRUE) {
if ((rtp_port != 0) && ((stream->proto == SalProtoRtpAvpf) || (stream->proto == SalProtoRtpSavpf))) {
add_rtcp_fb_attributes(media_desc, md, stream);
}
if ((rtp_port != 0) && (stream->rtcp_xr.enabled == TRUE)) {
char sastr[1024] = {0};
char mastr[1024] = {0};
size_t saoff = 0;
@ -296,7 +355,7 @@ belle_sdp_session_description_t * media_description_to_sdp ( const SalMediaDescr
belle_sdp_session_description_add_attribute(session_desc, create_rtcp_xr_attribute(&desc->rtcp_xr));
}
for ( i=0; i<desc->n_total_streams; i++ ) {
for ( i=0; i<desc->nb_streams; i++ ) {
stream_description_to_sdp(session_desc, desc, &desc->streams[i]);
}
return session_desc;
@ -305,9 +364,11 @@ belle_sdp_session_description_t * media_description_to_sdp ( const SalMediaDescr
static void sdp_parse_payload_types(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) {
PayloadType *pt;
PayloadTypeAvpfParams avpf_params;
belle_sip_list_t* mime_param_it=NULL;
belle_sdp_mime_parameter_t* mime_param;
belle_sip_list_t* mime_params=belle_sdp_media_description_build_mime_parameters ( media_desc );
memset(&avpf_params, 0, sizeof(avpf_params));
for ( mime_param_it=mime_params
; mime_param_it!=NULL
; mime_param_it=mime_param_it->next ) {
@ -319,6 +380,7 @@ static void sdp_parse_payload_types(belle_sdp_media_description_t *media_desc, S
pt->mime_type=ms_strdup ( belle_sdp_mime_parameter_get_type ( mime_param ) );
pt->channels=belle_sdp_mime_parameter_get_channel_count ( mime_param );
payload_type_set_send_fmtp ( pt,belle_sdp_mime_parameter_get_parameters ( mime_param ) );
payload_type_set_avpf_params(pt, avpf_params);
stream->payloads=ms_list_append ( stream->payloads,pt );
stream->ptime=belle_sdp_mime_parameter_get_ptime ( mime_param );
ms_message ( "Found payload %s/%i fmtp=%s",pt->mime_type,pt->clock_rate,
@ -330,7 +392,7 @@ static void sdp_parse_payload_types(belle_sdp_media_description_t *media_desc, S
static void sdp_parse_media_crypto_parameters(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) {
belle_sip_list_t *attribute_it;
belle_sdp_attribute_t *attribute;
char tmp[256], tmp2[256];
char tmp[256], tmp2[256], parameters[256]={0};
int valid_count = 0;
int nb;
@ -341,42 +403,39 @@ static void sdp_parse_media_crypto_parameters(belle_sdp_media_description_t *med
attribute=BELLE_SDP_ATTRIBUTE ( attribute_it->data );
if ( keywordcmp ( "crypto",belle_sdp_attribute_get_name ( attribute ) ) ==0 && belle_sdp_attribute_get_value ( attribute ) !=NULL ) {
nb = sscanf ( belle_sdp_attribute_get_value ( attribute ), "%d %256s inline:%256s",
nb = sscanf ( belle_sdp_attribute_get_value ( attribute ), "%d %256s inline:%256s %256s",
&stream->crypto[valid_count].tag,
tmp,
tmp2 );
ms_message ( "Found valid crypto line (tag:%d algo:'%s' key:'%s'",
stream->crypto[valid_count].tag,
tmp,
tmp2 );
if ( nb == 3 ) {
if ( keywordcmp ( "AES_CM_128_HMAC_SHA1_80",tmp ) == 0 ){
stream->crypto[valid_count].algo = MS_AES_128_SHA1_80;
}else if ( keywordcmp ( "AES_CM_128_HMAC_SHA1_32",tmp ) == 0 ){
stream->crypto[valid_count].algo = MS_AES_128_SHA1_32;
}else if ( keywordcmp ( "AES_CM_256_HMAC_SHA1_32",tmp ) == 0 ){
stream->crypto[valid_count].algo = MS_AES_256_SHA1_32;
}else if ( keywordcmp ( "AES_CM_256_HMAC_SHA1_80",tmp ) == 0 ){
stream->crypto[valid_count].algo = MS_AES_256_SHA1_80;
}else {
tmp2, parameters );
if ( nb >= 3 ) {
MSCryptoSuite cs;
MSCryptoSuiteNameParams np;
np.name=tmp;
np.params=parameters[0]!='\0' ? parameters : NULL;
cs=ms_crypto_suite_build_from_name_params(&np);
if (cs==MS_CRYPTO_SUITE_INVALID){
ms_warning ( "Failed to parse crypto-algo: '%s'", tmp );
stream->crypto[valid_count].algo = 0;
}
if ( stream->crypto[valid_count].algo ) {
strncpy ( stream->crypto[valid_count].master_key, tmp2, 41 );
stream->crypto[valid_count].master_key[40] = '\0';
}else{
char *sep;
strncpy ( stream->crypto[valid_count].master_key, tmp2, sizeof(stream->crypto[valid_count].master_key)-1 );
sep=strchr(stream->crypto[valid_count].master_key,'|');
if (sep) *sep='\0';
stream->crypto[valid_count].algo = cs;
ms_message ( "Found valid crypto line (tag:%d algo:'%s' key:'%s'",
stream->crypto[valid_count].tag,
tmp,
stream->crypto[valid_count].master_key );
valid_count++;
}
} else {
}else{
ms_warning ( "sdp has a strange a= line (%s) nb=%i",belle_sdp_attribute_get_value ( attribute ),nb );
}
}
}
ms_message ( "Found: %d valid crypto lines", valid_count );
ms_message("Found: %d valid crypto lines", valid_count );
}
static void sdp_parse_media_ice_parameters(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) {
@ -425,6 +484,92 @@ static void sdp_parse_media_ice_parameters(belle_sdp_media_description_t *media_
}
}
static void enable_avpf_for_stream(SalStreamDescription *stream) {
MSList *pt_it;
for (pt_it = stream->payloads; pt_it != NULL; pt_it = pt_it->next) {
PayloadType *pt = (PayloadType *)pt_it->data;
payload_type_set_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED);
}
}
static void apply_rtcp_fb_attribute_to_payload(belle_sdp_rtcp_fb_attribute_t *fb_attribute, PayloadType *pt) {
PayloadTypeAvpfParams avpf_params = payload_type_get_avpf_params(pt);
switch (belle_sdp_rtcp_fb_attribute_get_type(fb_attribute)) {
case BELLE_SDP_RTCP_FB_NACK:
switch (belle_sdp_rtcp_fb_attribute_get_param(fb_attribute)) {
case BELLE_SDP_RTCP_FB_NONE:
avpf_params.features |= PAYLOAD_TYPE_AVPF_PLI | PAYLOAD_TYPE_AVPF_SLI | PAYLOAD_TYPE_AVPF_RPSI;
break;
case BELLE_SDP_RTCP_FB_PLI:
avpf_params.features |= PAYLOAD_TYPE_AVPF_PLI;
break;
case BELLE_SDP_RTCP_FB_SLI:
avpf_params.features |= PAYLOAD_TYPE_AVPF_SLI;
break;
case BELLE_SDP_RTCP_FB_RPSI:
avpf_params.features |= PAYLOAD_TYPE_AVPF_RPSI;
break;
default:
break;
}
break;
case BELLE_SDP_RTCP_FB_TRR_INT:
avpf_params.trr_interval = belle_sdp_rtcp_fb_attribute_get_trr_int(fb_attribute);
break;
case BELLE_SDP_RTCP_FB_CCM:
switch (belle_sdp_rtcp_fb_attribute_get_param(fb_attribute)) {
case BELLE_SDP_RTCP_FB_FIR:
avpf_params.features |= PAYLOAD_TYPE_AVPF_FIR;
break;
default:
break;
}
break;
case BELLE_SDP_RTCP_FB_ACK:
default:
break;
}
payload_type_set_avpf_params(pt, avpf_params);
}
static void sdp_parse_rtcp_fb_parameters(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) {
belle_sip_list_t *it;
belle_sdp_attribute_t *attribute;
belle_sdp_rtcp_fb_attribute_t *fb_attribute;
MSList *pt_it;
PayloadType *pt;
int8_t pt_num;
/* Handle rtcp-fb attributes that concern all payload types. */
for (it = belle_sdp_media_description_get_attributes(media_desc); it != NULL; it = it->next) {
attribute = BELLE_SDP_ATTRIBUTE(it->data);
if (keywordcmp("rtcp-fb", belle_sdp_attribute_get_name(attribute)) == 0) {
fb_attribute = BELLE_SDP_RTCP_FB_ATTRIBUTE(attribute);
if (belle_sdp_rtcp_fb_attribute_get_id(fb_attribute) == -1) {
for (pt_it = stream->payloads; pt_it != NULL; pt_it = pt_it->next) {
pt = (PayloadType *)pt_it->data;
apply_rtcp_fb_attribute_to_payload(fb_attribute, pt);
}
}
}
}
/* Handle rtcp-fb attributes that are specefic to a payload type. */
for (it = belle_sdp_media_description_get_attributes(media_desc); it != NULL; it = it->next) {
attribute = BELLE_SDP_ATTRIBUTE(it->data);
if (keywordcmp("rtcp-fb", belle_sdp_attribute_get_name(attribute)) == 0) {
fb_attribute = BELLE_SDP_RTCP_FB_ATTRIBUTE(attribute);
pt_num = belle_sdp_rtcp_fb_attribute_get_id(fb_attribute);
for (pt_it = stream->payloads; pt_it != NULL; pt_it = pt_it->next) {
pt = (PayloadType *)pt_it->data;
if (payload_type_get_number(pt) == (int)pt_num) {
apply_rtcp_fb_attribute_to_payload(fb_attribute, pt);
}
}
}
}
}
static void sal_init_rtcp_xr_description(OrtpRtcpXrConfiguration *config) {
config->enabled = FALSE;
config->rcvr_rtt_mode = OrtpRtcpXrRcvrRttNone;
@ -450,7 +595,7 @@ static void sdp_parse_rtcp_xr_parameters(const belle_sdp_attribute_t *attribute,
}
config->stat_summary_enabled = (belle_sdp_rtcp_xr_attribute_has_stat_summary(xr_attr) != 0);
if (config->stat_summary_enabled) {
belle_sip_list_t *stat_summary_flag_it;
const belle_sip_list_t *stat_summary_flag_it;
for (stat_summary_flag_it = belle_sdp_rtcp_xr_attribute_get_stat_summary_flags(xr_attr); stat_summary_flag_it != NULL; stat_summary_flag_it = stat_summary_flag_it->next ) {
const char *flag = (const char *)stat_summary_flag_it->data;
if (flag != NULL) {
@ -485,7 +630,7 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md,
const char* value;
const char *mtype,*proto;
stream=&md->streams[md->n_total_streams];
stream=&md->streams[md->nb_streams];
media=belle_sdp_media_description_get_media ( media_desc );
memset ( stream,0,sizeof ( *stream ) );
@ -493,11 +638,15 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md,
proto = belle_sdp_media_get_protocol ( media );
stream->proto=SalProtoOther;
if ( proto ) {
if ( strcasecmp ( proto,"RTP/AVP" ) ==0 )
stream->proto=SalProtoRtpAvp;
else if ( strcasecmp ( proto,"RTP/SAVP" ) ==0 ) {
stream->proto=SalProtoRtpSavp;
}else{
if (strcasecmp(proto, "RTP/AVP") == 0) {
stream->proto = SalProtoRtpAvp;
} else if (strcasecmp(proto, "RTP/SAVP") == 0) {
stream->proto = SalProtoRtpSavp;
} else if (strcasecmp(proto, "RTP/AVPF") == 0) {
stream->proto = SalProtoRtpAvpf;
} else if (strcasecmp(proto, "RTP/SAVPF") == 0) {
stream->proto = SalProtoRtpSavpf;
} else {
strncpy(stream->proto_other,proto,sizeof(stream->proto_other)-1);
}
}
@ -507,9 +656,6 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md,
stream->rtp_port=belle_sdp_media_get_media_port ( media );
if ( stream->rtp_port > 0 )
md->n_active_streams++;
mtype = belle_sdp_media_get_media_type ( media );
if ( strcasecmp ( "audio", mtype ) == 0 ) {
stream->type=SalAudio;
@ -556,18 +702,24 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md,
}
/* Read crypto lines if any */
if ( stream->proto == SalProtoRtpSavp ) {
if ((stream->proto == SalProtoRtpSavpf) || (stream->proto == SalProtoRtpSavp)) {
sdp_parse_media_crypto_parameters(media_desc, stream);
}
/* Get ICE candidate attributes if any */
sdp_parse_media_ice_parameters(media_desc, stream);
/* Get RTCP-FB attributes if any */
if ((stream->proto == SalProtoRtpAvpf) || (stream->proto == SalProtoRtpSavpf)) {
enable_avpf_for_stream(stream);
sdp_parse_rtcp_fb_parameters(media_desc, stream);
}
/* Get RTCP-XR attributes if any */
stream->rtcp_xr = md->rtcp_xr; // Use session parameters if no stream parameters are defined
sdp_parse_media_rtcp_xr_parameters(media_desc, &stream->rtcp_xr);
md->n_total_streams++;
md->nb_streams++;
return stream;
}
@ -579,8 +731,7 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S
belle_sdp_session_name_t *sname;
const char* value;
desc->n_active_streams = 0;
desc->n_total_streams = 0;
desc->nb_streams = 0;
desc->dir = SalStreamSendRecv;
if ( ( cnx=belle_sdp_session_description_get_connection ( session_desc ) ) && belle_sdp_connection_get_address ( cnx ) ) {
@ -621,8 +772,8 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S
for ( media_desc_it=belle_sdp_session_description_get_media_descriptions ( session_desc )
; media_desc_it!=NULL
; media_desc_it=media_desc_it->next ) {
if (desc->n_total_streams==SAL_MEDIA_DESCRIPTION_MAX_STREAMS){
ms_warning("Cannot convert mline at position [%i] from SDP to SalMediaDescription",desc->n_total_streams);
if (desc->nb_streams==SAL_MEDIA_DESCRIPTION_MAX_STREAMS){
ms_warning("Cannot convert mline at position [%i] from SDP to SalMediaDescription",desc->nb_streams);
break;
}
media_desc=BELLE_SDP_MEDIA_DESCRIPTION ( media_desc_it->data );

View file

@ -47,7 +47,8 @@ void linphone_core_update_streams_destinations(LinphoneCore *lc, LinphoneCall *c
char *rtp_addr, *rtcp_addr;
int i;
for (i = 0; i < new_md->n_active_streams; i++) {
for (i = 0; i < new_md->nb_streams; i++) {
if (!sal_stream_description_active(&new_md->streams[i])) continue;
if (new_md->streams[i].type == SalAudio) {
new_audiodesc = &new_md->streams[i];
} else if (new_md->streams[i].type == SalVideo) {
@ -72,6 +73,32 @@ void linphone_core_update_streams_destinations(LinphoneCore *lc, LinphoneCall *c
#endif
}
static void _clear_early_media_destinations(LinphoneCall *call, MediaStream *ms){
RtpSession *session=ms->sessions.rtp_session;
rtp_session_clear_aux_remote_addr(session);
if (!call->ice_session) rtp_session_set_symmetric_rtp(session,TRUE);/*restore symmetric rtp if ICE is not used*/
}
static void clear_early_media_destinations(LinphoneCall *call){
if (call->audiostream){
_clear_early_media_destinations(call,(MediaStream*)call->audiostream);
}
if (call->videostream){
_clear_early_media_destinations(call,(MediaStream*)call->videostream);
}
}
static void prepare_early_media_forking(LinphoneCall *call){
/*we need to disable symmetric rtp otherwise our outgoing streams will be switching permanently between the multiple destinations*/
if (call->audiostream){
rtp_session_set_symmetric_rtp(call->audiostream->ms.sessions.rtp_session,FALSE);
}
if (call->videostream){
rtp_session_set_symmetric_rtp(call->videostream->ms.sessions.rtp_session,FALSE);
}
}
void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md){
SalMediaDescription *oldmd=call->resultdesc;
bool_t all_muted=FALSE;
@ -82,7 +109,7 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia
ms_error("linphone_core_update_streams() called with null media description");
return;
}
if (call->biggestdesc==NULL || new_md->n_total_streams>call->biggestdesc->n_total_streams){
if (call->biggestdesc==NULL || new_md->nb_streams>call->biggestdesc->nb_streams){
/*we have been offered and now are ready to proceed, or we added a new stream*/
/*store the media description to remember the mapping of calls*/
if (call->biggestdesc){
@ -98,6 +125,7 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia
call->expect_media_in_ack=FALSE;
call->resultdesc=new_md;
if ((call->audiostream && call->audiostream->ms.state==MSStreamStarted) || (call->videostream && call->videostream->ms.state==MSStreamStarted)){
clear_early_media_destinations(call);
/* we already started media: check if we really need to restart it*/
if (oldmd){
int md_changed = media_parameters_changed(call, oldmd, new_md);
@ -146,6 +174,9 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia
if ((call->state==LinphoneCallIncomingEarlyMedia || call->state==LinphoneCallOutgoingEarlyMedia) && !call->params.real_early_media){
all_muted=TRUE;
}
if (call->params.real_early_media && call->state==LinphoneCallOutgoingEarlyMedia){
prepare_early_media_forking(call);
}
linphone_call_start_media_streams(call,all_muted,send_ringbacktone);
if (call->state==LinphoneCallPausing && call->paused_by_app && ms_list_size(lc->calls)==1){
linphone_core_play_named_tone(lc,LinphoneToneCallOnHold);
@ -189,6 +220,7 @@ static bool_t already_a_call_pending(LinphoneCore *lc){
for(elem=lc->calls;elem!=NULL;elem=elem->next){
LinphoneCall *call=(LinphoneCall*)elem->data;
if (call->state==LinphoneCallIncomingReceived
|| call->state==LinphoneCallIncomingEarlyMedia
|| call->state==LinphoneCallOutgoingInit
|| call->state==LinphoneCallOutgoingProgress
|| call->state==LinphoneCallOutgoingEarlyMedia
@ -276,6 +308,39 @@ static void call_received(SalOp *h){
linphone_core_notify_incoming_call(lc,call);
}
static void try_early_media_forking(LinphoneCall *call, SalMediaDescription *md){
SalMediaDescription *cur_md=call->resultdesc;
int i;
SalStreamDescription *ref_stream,*new_stream;
ms_message("Early media response received from another branch, checking if media can be forked to this new destination.");
for (i=0;i<cur_md->nb_streams;++i){
if (!sal_stream_description_active(&cur_md->streams[i])) continue;
ref_stream=&cur_md->streams[i];
new_stream=&md->streams[i];
if (ref_stream->type==new_stream->type && ref_stream->payloads && new_stream->payloads){
PayloadType *refpt, *newpt;
refpt=(PayloadType*)ref_stream->payloads->data;
newpt=(PayloadType*)new_stream->payloads->data;
if (strcmp(refpt->mime_type,newpt->mime_type)==0 && refpt->clock_rate==newpt->clock_rate
&& payload_type_get_number(refpt)==payload_type_get_number(newpt)){
MediaStream *ms=NULL;
if (ref_stream->type==SalAudio){
ms=(MediaStream*)call->audiostream;
}else if (ref_stream->type==SalVideo){
ms=(MediaStream*)call->videostream;
}
if (ms){
RtpSession *session=ms->sessions.rtp_session;
const char *rtp_addr=new_stream->rtp_addr[0]!='\0' ? new_stream->rtp_addr : md->addr;
const char *rtcp_addr=new_stream->rtcp_addr[0]!='\0' ? new_stream->rtcp_addr : md->addr;
rtp_session_add_aux_remote_addr_full(session,rtp_addr,new_stream->rtp_port,rtcp_addr,new_stream->rtcp_port);
}
}
}
}
}
static void call_ringing(SalOp *h){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(h);
@ -309,7 +374,7 @@ static void call_ringing(SalOp *h){
/*accept early media */
if (call->audiostream && audio_stream_started(call->audiostream)){
/*streams already started */
ms_message("Early media already started.");
try_early_media_forking(call,md);
return;
}
if (lc->vtable.show) lc->vtable.show(lc);
@ -460,6 +525,8 @@ static void call_accept_update(LinphoneCore *lc, LinphoneCall *call){
}
static void call_resumed(LinphoneCore *lc, LinphoneCall *call){
/*when we are resumed, increment session id, because sdp is changed (a=recvonly disapears)*/
linphone_call_increment_local_media_description(call);
call_accept_update(lc,call);
if(lc->vtable.display_status)
lc->vtable.display_status(lc,_("We have been resumed."));
@ -467,6 +534,8 @@ static void call_resumed(LinphoneCore *lc, LinphoneCall *call){
}
static void call_paused_by_remote(LinphoneCore *lc, LinphoneCall *call){
/*when we are resumed, increment session id, because sdp is changed (a=recvonly appears)*/
linphone_call_increment_local_media_description(call);
call_accept_update(lc,call);
/* we are being paused */
if(lc->vtable.display_status)
@ -666,24 +735,33 @@ static void call_failure(SalOp *op){
break;
case SalReasonUnsupportedContent: /*<this is for compatibility: linphone sent 415 because of SDP offer answer failure*/
case SalReasonNotAcceptable:
//media_encryption_mandatory
if (call->params.media_encryption == LinphoneMediaEncryptionSRTP &&
!linphone_core_is_media_encryption_mandatory(lc)) {
ms_message("Outgoing call [%p] failed with SRTP and/or AVPF enabled", call);
if ((call->state == LinphoneCallOutgoingInit)
|| (call->state == LinphoneCallOutgoingProgress)
|| (call->state == LinphoneCallOutgoingRinging) /* Push notification case */
|| (call->state == LinphoneCallOutgoingEarlyMedia)) {
int i;
ms_message("Outgoing call [%p] failed with SRTP (SAVP) enabled",call);
if (call->state==LinphoneCallOutgoingInit
|| call->state==LinphoneCallOutgoingProgress
|| call->state==LinphoneCallOutgoingRinging /*push case*/
|| call->state==LinphoneCallOutgoingEarlyMedia){
ms_message("Retrying call [%p] with AVP",call);
/* clear SRTP local params */
call->params.media_encryption = LinphoneMediaEncryptionNone;
for(i=0; i<call->localdesc->n_active_streams; i++) {
call->localdesc->streams[i].proto = SalProtoRtpAvp;
memset(call->localdesc->streams[i].crypto, 0, sizeof(call->localdesc->streams[i].crypto));
for (i = 0; i < call->localdesc->nb_streams; i++) {
if (!sal_stream_description_active(&call->localdesc->streams[i])) continue;
if (call->params.media_encryption == LinphoneMediaEncryptionSRTP) {
if (call->params.avpf_enabled == TRUE) {
if (i == 0) ms_message("Retrying call [%p] with SAVP", call);
call->params.avpf_enabled = FALSE;
linphone_core_restart_invite(lc, call);
return;
} else if (!linphone_core_is_media_encryption_mandatory(lc)) {
if (i == 0) ms_message("Retrying call [%p] with AVP", call);
call->params.media_encryption = LinphoneMediaEncryptionNone;
memset(call->localdesc->streams[i].crypto, 0, sizeof(call->localdesc->streams[i].crypto));
linphone_core_restart_invite(lc, call);
return;
}
} else if (call->params.avpf_enabled == TRUE) {
if (i == 0) ms_message("Retrying call [%p] with AVP", call);
call->params.avpf_enabled = FALSE;
linphone_core_restart_invite(lc, call);
return;
}
linphone_core_restart_invite(lc, call);
return;
}
}
msg=_("Incompatible media parameters.");
@ -740,7 +818,11 @@ static void call_released(SalOp *op){
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
if (call!=NULL){
linphone_call_set_state(call,LinphoneCallReleased,"Call released");
}else ms_error("call_released() for already destroyed call ?");
}else{
/*we can arrive here when the core manages call at Sal level without creating a LinphoneCall object. Typicially:
* - when declining an incoming call with busy because maximum number of calls is reached.
*/
}
}
static void auth_failure(SalOp *op, SalAuthInfo* info) {

View file

@ -25,13 +25,152 @@
#include "linphonecore.h"
#include "private.h"
#include "lpconfig.h"
#include "belle-sip/belle-sip.h"
#include <libxml/parser.h>
#include <libxml/xmlwriter.h>
#define COMPOSING_DEFAULT_IDLE_TIMEOUT 15
#define COMPOSING_DEFAULT_REFRESH_TIMEOUT 60
#define COMPOSING_DEFAULT_REMOTE_REFRESH_TIMEOUT 120
static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatMessage* msg);
#define MULTIPART_BOUNDARY "---------------------------14737809831466499882746641449"
#define FILEPART_HEADER_1 "Content-Disposition: form-data; name=\"File\"; filename=\""
#define FILEPART_HEADER_2 "\"\r\n" \
"Content-Type: "
#define FILEPART_HEADER_3 "\r\n\r\n"
const char *multipart_boundary=MULTIPART_BOUNDARY;
static size_t linphone_chat_message_compute_filepart_header_size(const char *filename, const char *content_type) {
return strlen(FILEPART_HEADER_1)+strlen(filename)+strlen(FILEPART_HEADER_2)+strlen(content_type)+strlen(FILEPART_HEADER_3);
}
static void process_io_error(void *data, const belle_sip_io_error_event_t *event){
LinphoneChatMessage* msg=(LinphoneChatMessage *)data;
msg->cb(msg, LinphoneChatMessageStateNotDelivered, msg->chat_room->lc);
}
static void process_auth_requested(void *data, belle_sip_auth_event_t *event){
printf("We have a auth requested!\n");
}
/**
* Callback called during upload or download of a file from server
* It is just forwarding the call and some parameters to the vtable defined callback
*/
static void linphone_chat_message_file_transfer_on_progress(belle_sip_body_handler_t *bh, belle_sip_message_t *msg, void *data, size_t offset, size_t total){
LinphoneChatMessage* chatMsg=(LinphoneChatMessage *)data;
LinphoneCore *lc = chatMsg->chat_room->lc;
/* call back given by application level */
if (lc->vtable.file_transfer_progress_indication != NULL) {
lc->vtable.file_transfer_progress_indication(lc, chatMsg, chatMsg->file_transfer_information, (size_t)(((double)offset/(double)total)*100.0));
}
return;
}
/**
* Callback called when posting a file to server (following rcs5.1 recommendation)
*
* @param bh the body handler
* @param msg the belle sip message
* @param data the user data associated to the handler, contains the linphoneChatMessage we're working on
* @param offset current position in the input buffer
* @param buffer the ouput buffer we to copy the data to be uploaded
* @param size size in byte of the data requested, as output it will contain the effective copied size
*
*/
static int linphone_chat_message_file_transfer_on_send_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *msg, void *data, size_t offset, uint8_t *buffer, size_t *size){
LinphoneChatMessage* chatMsg=(LinphoneChatMessage *)data;
LinphoneCore *lc = chatMsg->chat_room->lc;
char *buf = (char *)buffer;
char *content_type=belle_sip_strdup_printf("%s/%s", chatMsg->file_transfer_information->type, chatMsg->file_transfer_information->subtype);
size_t end_of_file=linphone_chat_message_compute_filepart_header_size(chatMsg->file_transfer_information->name, content_type)+chatMsg->file_transfer_information->size;
if (offset==0){
int partlen=linphone_chat_message_compute_filepart_header_size(chatMsg->file_transfer_information->name, content_type);
memcpy(buf,FILEPART_HEADER_1,strlen(FILEPART_HEADER_1));
buf += strlen(FILEPART_HEADER_1);
memcpy(buf,chatMsg->file_transfer_information->name,strlen(chatMsg->file_transfer_information->name));
buf += strlen(chatMsg->file_transfer_information->name);
memcpy(buf,FILEPART_HEADER_2,strlen(FILEPART_HEADER_2));
buf += strlen(FILEPART_HEADER_2);
memcpy(buf,content_type,strlen(content_type));
buf += strlen(content_type);
memcpy(buf,FILEPART_HEADER_3,strlen(FILEPART_HEADER_3));
*size=partlen;
}else if (offset<end_of_file){
/* get data from call back */
lc->vtable.file_transfer_send(lc, chatMsg, chatMsg->file_transfer_information, buf, size);
}
belle_sip_free(content_type);
return BELLE_SIP_CONTINUE;
}
/**
* Callback function called when we have a response from server during a file upload to server (rcs5.1 recommandation)
* Note: The first post is empty and the server shall reply a 204 (No content) message, this will trigger a new post request to the server
* to upoad the file. The server response to this second post is processed by this same function
*
* @param data the user define pointer associated with the request, it contains the linphoneChatMessage we're trying to send
* @param event the response from server
*/
static void linphone_chat_message_process_response_from_post_file(void *data, const belle_http_response_event_t *event){
LinphoneChatMessage* msg=(LinphoneChatMessage *)data;
/* check the answer code */
if (event->response){
int code=belle_http_response_get_status_code(event->response);
if (code == 204) { /* this is the reply to the first post to the server - an empty message */
/* start uploading the file */
belle_http_request_listener_callbacks_t cbs={0};
belle_http_request_listener_t *l;
belle_generic_uri_t *uri;
belle_http_request_t *req;
char *content_type=belle_sip_strdup_printf("%s/%s", msg->file_transfer_information->type, msg->file_transfer_information->subtype);
/* create a user body handler to take care of the file */
belle_sip_user_body_handler_t *first_part_bh=belle_sip_user_body_handler_new(msg->file_transfer_information->size+linphone_chat_message_compute_filepart_header_size(msg->file_transfer_information->name, content_type), NULL, NULL, linphone_chat_message_file_transfer_on_send_body, msg);
/* insert it in a multipart body handler which will manage the boundaries of multipart message */
belle_sip_multipart_body_handler_t *bh=belle_sip_multipart_body_handler_new(linphone_chat_message_file_transfer_on_progress, msg, (belle_sip_body_handler_t *)first_part_bh);
char* ua = ms_strdup_printf("%s/%s", linphone_core_get_user_agent_name(), linphone_core_get_user_agent_version());
belle_sip_free(content_type);
content_type=belle_sip_strdup_printf("multipart/form-data; boundary=%s",multipart_boundary);
uri=belle_generic_uri_parse(msg->chat_room->lc->file_transfer_server);
req=belle_http_request_create("POST",
uri,
belle_sip_header_create("User-Agent",ua),
belle_sip_header_create("Content-type",content_type),
NULL);
ms_free(ua);
belle_sip_free(content_type);
belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(req),BELLE_SIP_BODY_HANDLER(bh));
cbs.process_response=linphone_chat_message_process_response_from_post_file;
cbs.process_io_error=process_io_error;
cbs.process_auth_requested=process_auth_requested;
l=belle_http_request_listener_create_from_callbacks(&cbs,msg);
belle_http_provider_send_request(msg->chat_room->lc->http_provider,req,l);
}
if (code == 200 ) { /* file has been uplaoded correctly, get server reply and send it */
const char *body = belle_sip_message_get_body((belle_sip_message_t *)event->response);
msg->message = ms_strdup(body);
linphone_content_uninit(msg->file_transfer_information);
ms_free(msg->file_transfer_information);
msg->file_transfer_information = NULL;
msg->content_type = ms_strdup("application/vnd.gsma.rcs-ft-http+xml");
_linphone_chat_room_send_message(msg->chat_room, msg);
}
}
}
static void _linphone_chat_message_destroy(LinphoneChatMessage* msg);
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneChatMessage);
@ -75,9 +214,9 @@ bool_t linphone_core_chat_enabled(const LinphoneCore *lc){
}
/**
* Returns an array of chat rooms
* Returns an list of chat rooms
* @param lc #LinphoneCore object
* @return An array of #LinpĥoneChatRoom
* @return A list of #LinphoneChatRoom
**/
MSList* linphone_core_get_chat_rooms(LinphoneCore *lc) {
return lc->chatrooms;
@ -177,6 +316,30 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM
char* content_type;
const char *identity=NULL;
time_t t=time(NULL);
linphone_chat_message_ref(msg);
/* Check if we shall upload a file to a server */
if (msg->file_transfer_information != NULL) {
/* open a transaction with the server and send an empty request(RCS5.1 section 3.5.4.8.3.1) */
belle_http_request_listener_callbacks_t cbs={0};
belle_http_request_listener_t *l;
belle_generic_uri_t *uri;
belle_http_request_t *req;
uri=belle_generic_uri_parse(cr->lc->file_transfer_server);
req=belle_http_request_create("POST",
uri,
NULL,
NULL,
NULL);
cbs.process_response=linphone_chat_message_process_response_from_post_file;
cbs.process_io_error=process_io_error;
cbs.process_auth_requested=process_auth_requested;
l=belle_http_request_listener_create_from_callbacks(&cbs,msg); /* give msg to listener to be able to start the actual file upload when server answer a 204 No content */
belle_http_provider_send_request(cr->lc->http_provider,req,l);
linphone_chat_message_unref(msg);
return;
}
if (lp_config_get_int(cr->lc->config,"sip","chat_use_call_dialogs",0)){
if((call = linphone_core_get_call_by_remote_address(cr->lc,cr->peer))!=NULL){
@ -207,7 +370,11 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM
sal_message_send(op,identity,cr->peer,content_type, NULL);
ms_free(content_type);
} else {
sal_text_send(op, identity, cr->peer,msg->message);
if (msg->content_type == NULL) {
sal_text_send(op, identity, cr->peer,msg->message);
} else {
sal_message_send(op, identity, cr->peer, msg->content_type, msg->message);
}
}
msg->dir=LinphoneChatMessageOutgoing;
msg->from=linphone_address_new(identity);
@ -221,6 +388,7 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM
}
linphone_chat_room_delete_composing_idle_timer(cr);
linphone_chat_room_delete_composing_refresh_timer(cr);
linphone_chat_message_unref(msg);
}
/**
@ -247,7 +415,7 @@ void linphone_chat_room_message_received(LinphoneChatRoom *cr, LinphoneCore *lc,
/**
* Retrieve an existing chat room whose peer is the supplied address, if exists.
* @param lc the linphone core
* @param add a linphone address.
* @param addr a linphone address.
* @returns the matching chatroom, or NULL if no such chatroom exists.
**/
LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAddress *addr){
@ -280,7 +448,68 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag
/* create a new chat room */
cr=linphone_core_create_chat_room(lc,cleanfrom);
}
msg = linphone_chat_room_create_message(cr, sal_msg->text);
if (sal_msg->content_type != NULL) { /* content_type field is, for now, used only for rcs file transfer bu twe shall strcmp it with "application/vnd.gsma.rcs-ft-http+xml" */
xmlChar *file_url = NULL;
xmlDocPtr xmlMessageBody;
xmlNodePtr cur;
msg = linphone_chat_room_create_message(cr, NULL); /* create a message with empty body */
msg->content_type = ms_strdup(sal_msg->content_type); /* add the content_type "application/vnd.gsma.rcs-ft-http+xml" */
msg->file_transfer_information = (LinphoneContent *)malloc(sizeof(LinphoneContent));
memset(msg->file_transfer_information, 0, sizeof(*(msg->file_transfer_information)));
/* parse the message body to get all informations from it */
xmlMessageBody = xmlParseDoc((const xmlChar *)sal_msg->text);
cur = xmlDocGetRootElement(xmlMessageBody);
if (cur != NULL) {
cur = cur->xmlChildrenNode;
while (cur!=NULL) {
if (!xmlStrcmp(cur->name, (const xmlChar *)"file-info")) { /* we found a file info node, check it has a type="file" attribute */
xmlChar *typeAttribute = xmlGetProp(cur, (const xmlChar *)"type");
if(!xmlStrcmp(typeAttribute, (const xmlChar *)"file")) { /* this is the node we are looking for */
cur = cur->xmlChildrenNode; /* now loop on the content of the file-info node */
while (cur!=NULL) {
if (!xmlStrcmp(cur->name, (const xmlChar *)"file-size")) {
xmlChar *fileSizeString = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1);
msg->file_transfer_information->size = strtol((const char*)fileSizeString, NULL, 10);
xmlFree(fileSizeString);
}
if (!xmlStrcmp(cur->name, (const xmlChar *)"file-name")) {
msg->file_transfer_information->name = (char *)xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1);
}
if (!xmlStrcmp(cur->name, (const xmlChar *)"content-type")) {
xmlChar *contentType = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1);
int contentTypeIndex = 0;
while (contentType[contentTypeIndex]!='/' && contentType[contentTypeIndex]!='\0') {
contentTypeIndex++;
}
msg->file_transfer_information->type = ms_strndup((char *)contentType, contentTypeIndex);
msg->file_transfer_information->subtype = ms_strdup(((char *)contentType+contentTypeIndex+1));
xmlFree(contentType);
}
if (!xmlStrcmp(cur->name, (const xmlChar *)"data")) {
file_url = xmlGetProp(cur, (const xmlChar *)"url");
}
cur=cur->next;
}
xmlFree(typeAttribute);
break;
}
xmlFree(typeAttribute);
}
cur = cur->next;
}
}
xmlFreeDoc(xmlMessageBody);
linphone_chat_message_set_external_body_url(msg, (const char *)file_url);
xmlFree(file_url);
} else { /* message is not rcs file transfer, create it with provided sal_msg->text as ->message */
msg = linphone_chat_room_create_message(cr, sal_msg->text);
}
linphone_chat_message_set_from(msg, cr->peer_url);
{
@ -299,6 +528,7 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag
if (sal_msg->url) {
linphone_chat_message_set_external_body_url(msg, sal_msg->url);
}
linphone_address_destroy(addr);
msg->storage_id=linphone_chat_message_store(msg);
linphone_chat_room_message_received(cr,lc,msg);
@ -387,11 +617,19 @@ bool_t linphone_chat_room_is_remote_composing(const LinphoneChatRoom *cr) {
/**
* Returns back pointer to LinphoneCore object.
* @deprecated use linphone_chat_room_get_core()
**/
LinphoneCore* linphone_chat_room_get_lc(LinphoneChatRoom *cr){
return cr->lc;
}
/**
* Returns back pointer to LinphoneCore object.
**/
LinphoneCore* linphone_chat_room_get_core(LinphoneChatRoom *cr){
return cr->lc;
}
/**
* Assign a user pointer to the chat room.
**/
@ -426,6 +664,8 @@ LinphoneChatMessage* linphone_chat_room_create_message(LinphoneChatRoom *cr, con
msg->chat_room=(LinphoneChatRoom*)cr;
msg->message=message?ms_strdup(message):NULL;
msg->is_read=TRUE;
msg->content_type = NULL; /* this property is used only when transfering file */
msg->file_transfer_information = NULL; /* this property is used only when transfering file */
return msg;
}
@ -452,6 +692,8 @@ LinphoneChatMessage* linphone_chat_room_create_message_2(
msg->time=time;
msg->state=state;
msg->is_read=is_read;
msg->content_type = NULL; /* this property is used only when transfering file */
msg->file_transfer_information = NULL; /* this property is used only when transfering file */
if (is_incoming) {
msg->dir=LinphoneChatMessageIncoming;
linphone_chat_message_set_from(msg, linphone_chat_room_get_peer_address(cr));
@ -668,6 +910,120 @@ void linphone_chat_message_set_external_body_url(LinphoneChatMessage* message,co
message->external_body_url=url?ms_strdup(url):NULL;
}
/**
* Linphone message has an app-specific field that can store a text. The application might want
* to use it for keeping data over restarts, like thumbnail image path.
* @param message #LinphoneChatMessage
* @return the application-specific data or NULL if none has been stored.
*/
const char* linphone_chat_message_get_appdata(const LinphoneChatMessage* message){
return message->appdata;
}
/**
* Linphone message has an app-specific field that can store a text. The application might want
* to use it for keeping data over restarts, like thumbnail image path.
*
* Invoking this function will attempt to update the message storage to reflect the changeif it is
* enabled.
*
* @param message #LinphoneChatMessage
* @param data the data to store into the message
*/
void linphone_chat_message_set_appdata(LinphoneChatMessage* message, const char* data){
if( message->appdata ){
ms_free(message->appdata);
}
message->appdata = data? ms_strdup(data) : NULL;
linphone_chat_message_store_appdata(message);
}
/**
* Get the file_transfer_information (used by call backs to recover informations during a rcs file transfer)
*
* @param message #LinphoneChatMessage
* @return a pointer to the LinphoneContent structure or NULL if not present.
*/
const LinphoneContent *linphone_chat_message_get_file_transfer_information(const LinphoneChatMessage*message) {
return message->file_transfer_information;
}
static void on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *msg, void *data, size_t offset, const uint8_t *buffer, size_t size){
//printf("Receive %ld bytes\n\n%s\n\n", size, (char *)buffer);
LinphoneChatMessage* chatMsg=(LinphoneChatMessage *)data;
LinphoneCore *lc = chatMsg->chat_room->lc;
/* call back given by application level */
if (lc->vtable.file_transfer_received != NULL) {
lc->vtable.file_transfer_received(lc, chatMsg, chatMsg->file_transfer_information, (char *)buffer, size);
}
return;
/* feed the callback with the received data */
}
static void linphone_chat_process_response_headers_from_get_file(void *data, const belle_http_response_event_t *event){
if (event->response){
/*we are receiving a response, set a specific body handler to acquire the response.
* if not done, belle-sip will create a memory body handler, the default*/
LinphoneChatMessage *message=(LinphoneChatMessage *)belle_sip_object_data_get(BELLE_SIP_OBJECT(event->request),"message");
belle_sip_message_set_body_handler(
(belle_sip_message_t*)event->response,
(belle_sip_body_handler_t*)belle_sip_user_body_handler_new(message->file_transfer_information->size, linphone_chat_message_file_transfer_on_progress,on_recv_body,NULL,message)
);
}
}
static void linphone_chat_process_response_from_get_file(void *data, const belle_http_response_event_t *event){
//LinphoneChatMessage* msg=(LinphoneChatMessage *)data;
/* check the answer code */
if (event->response){
int code=belle_http_response_get_status_code(event->response);
if (code==200) {
LinphoneChatMessage* chatMsg=(LinphoneChatMessage *)data;
LinphoneCore *lc = chatMsg->chat_room->lc;
/* file downloaded succesfully, call again the callback with size at zero */
if (lc->vtable.file_transfer_received != NULL) {
lc->vtable.file_transfer_received(lc, chatMsg, chatMsg->file_transfer_information, NULL, 0);
}
}
}
}
/**
* Start the download of the file from remote server
*
* @param message #LinphoneChatMessage
*/
void linphone_chat_message_start_file_download(const LinphoneChatMessage *message) {
belle_http_request_listener_callbacks_t cbs={0};
belle_http_request_listener_t *l;
belle_generic_uri_t *uri;
belle_http_request_t *req;
const char *url=message->external_body_url;
char* ua = ms_strdup_printf("%s/%s", linphone_core_get_user_agent_name(), linphone_core_get_user_agent_version());
uri=belle_generic_uri_parse(url);
req=belle_http_request_create("GET",
uri,
belle_sip_header_create("User-Agent",ua),
NULL);
ms_free(ua);
cbs.process_response_headers=linphone_chat_process_response_headers_from_get_file;
cbs.process_response=linphone_chat_process_response_from_get_file;
cbs.process_io_error=process_io_error;
cbs.process_auth_requested=process_auth_requested;
l=belle_http_request_listener_create_from_callbacks(&cbs, (void *)message);
belle_sip_object_data_set(BELLE_SIP_OBJECT(req),"message",(void *)message,NULL);
belle_http_provider_send_request(message->chat_room->lc->http_provider,req,l);
}
/**
* Set origin of the message
*@param message #LinphoneChatMessage obj
@ -805,6 +1161,7 @@ LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* msg)
};*/
LinphoneChatMessage* new_message = linphone_chat_room_create_message(msg->chat_room,msg->message);
if (msg->external_body_url) new_message->external_body_url=ms_strdup(msg->external_body_url);
if (msg->appdata) new_message->appdata = ms_strdup(msg->appdata);
new_message->cb=msg->cb;
new_message->cb_ud=msg->cb_ud;
new_message->message_userdata=msg->message_userdata;
@ -831,9 +1188,15 @@ static void _linphone_chat_message_destroy(LinphoneChatMessage* msg) {
if (msg->op) sal_op_release(msg->op);
if (msg->message) ms_free(msg->message);
if (msg->external_body_url) ms_free(msg->external_body_url);
if (msg->appdata) ms_free(msg->appdata);
if (msg->from) linphone_address_destroy(msg->from);
if (msg->to) linphone_address_destroy(msg->to);
if (msg->custom_headers) sal_custom_header_free(msg->custom_headers);
if (msg->content_type) ms_free(msg->content_type);
if (msg->file_transfer_information) {
linphone_content_uninit(msg->file_transfer_information);
ms_free(msg->file_transfer_information);
}
}
@ -868,6 +1231,29 @@ LinphoneReason linphone_chat_message_get_reason(LinphoneChatMessage* msg) {
return linphone_error_info_get_reason(linphone_chat_message_get_error_info(msg));
}
/**
* Create a message attached to a dedicated chat room with a particular content. Use #linphone_chat_room_send_message2 to initiate the transfer
* @param cr the chat room.
* @param a #LinphoneContent initial content. #LinphoneCoreVTable.file_transfer_send is invoked later to notify file transfer progress and collect next chunk of the message if #LinphoneContent.data is NULL.
* @return a new #LinphoneChatMessage
*/
LinphoneChatMessage* linphone_chat_room_create_file_transfer_message(LinphoneChatRoom *cr, LinphoneContent* initial_content) {
LinphoneChatMessage* msg = belle_sip_object_new(LinphoneChatMessage);
msg->chat_room=(LinphoneChatRoom*)cr;
msg->message = NULL;
msg->file_transfer_information = (LinphoneContent *)malloc(sizeof(LinphoneContent));
memset(msg->file_transfer_information, 0, sizeof(LinphoneContent));
linphone_content_copy(msg->file_transfer_information, initial_content);
msg->dir=LinphoneChatMessageOutgoing;
linphone_chat_message_set_to(msg, linphone_chat_room_get_peer_address(cr));
linphone_chat_message_set_from(msg, linphone_address_new(linphone_core_get_identity(cr->lc)));
msg->content_type=NULL; /* this will be set to application/vnd.gsma.rcs-ft-http+xml when we will transfer the xml reply from server to the peers */
return msg;
}
/**
* @}
*/

View file

@ -200,7 +200,8 @@ int linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *call){
params->has_video=FALSE;
if (call->audiostream || call->videostream){
linphone_call_stop_media_streams (call); /*free the audio & video local resources*/
linphone_call_stop_media_streams(call); /*free the audio & video local resources*/
linphone_call_init_media_streams(call);
}
if (call==lc->current_call){
lc->current_call=NULL;

View file

@ -79,12 +79,15 @@ static LinphoneEvent *linphone_event_new_with_op_base(LinphoneCore *lc, SalOp *o
lev->is_out_of_dialog_op=is_out_of_dialog;
return lev;
}
LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name) {
return linphone_event_new_with_op_base(lc,op,dir,name,FALSE);
}
LinphoneEvent *linphone_event_new_with_out_of_dialog_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name) {
return linphone_event_new_with_op_base(lc,op,dir,name,TRUE);
}
void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState state){
LinphoneCore *lc=lev->lc;
if (lev->subscription_state!=state){
@ -107,9 +110,22 @@ void linphone_event_set_publish_state(LinphoneEvent *lev, LinphonePublishState s
if (lc->vtable.publish_state_changed){
lc->vtable.publish_state_changed(lev->lc,lev,state);
}
if (state==LinphonePublishCleared){
linphone_event_unref(lev);
switch(state){
case LinphonePublishCleared:
linphone_event_unref(lev);
break;
case LinphonePublishOk:
case LinphonePublishError:
if (lev->expires==-1)
linphone_event_unref(lev);
break;
case LinphonePublishNone:
case LinphonePublishProgress:
case LinphonePublishExpiring:
/*nothing special to do*/
break;
}
}
}

View file

@ -37,9 +37,9 @@ typedef struct _LinphoneEvent LinphoneEvent;
* Enum for subscription direction (incoming or outgoing).
**/
enum _LinphoneSubscriptionDir{
LinphoneSubscriptionIncoming,
LinphoneSubscriptionOutgoing,
LinphoneSubscriptionInvalidDir
LinphoneSubscriptionIncoming, /**< Incoming subscription. */
LinphoneSubscriptionOutgoing, /**< Outgoing subscription. */
LinphoneSubscriptionInvalidDir /**< Invalid subscription direction. */
};
/**
@ -97,12 +97,12 @@ typedef void (*LinphoneCoreNotifyReceivedCb)(LinphoneCore *lc, LinphoneEvent *le
/**
* Callback prototype for notifying the application about changes of subscription states, including arrival of new subscriptions.
**/
**/
typedef void (*LinphoneCoreSubscriptionStateChangedCb)(LinphoneCore *lc, LinphoneEvent *lev, LinphoneSubscriptionState state);
/**
* Callback prototype for notifying the application about changes of publish states.
**/
**/
typedef void (*LinphoneCorePublishStateChangedCb)(LinphoneCore *lc, LinphoneEvent *lev, LinphonePublishState state);
/**
@ -125,7 +125,6 @@ LINPHONE_PUBLIC LinphoneEvent *linphone_core_subscribe(LinphoneCore *lc, const L
* @param resource the destination resource
* @param event the event name
* @param expires the whished duration of the subscription
* @param body an optional body, may be NULL.
* @return a LinphoneEvent holding the context of the created subcription.
**/
LINPHONE_PUBLIC LinphoneEvent *linphone_core_create_subscribe(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires);
@ -211,7 +210,7 @@ LINPHONE_PUBLIC LinphoneReason linphone_event_get_reason(const LinphoneEvent *le
/**
* Get full details about an error occured.
**/
const LinphoneErrorInfo *linphone_event_get_error_info(const LinphoneEvent *lev);
LINPHONE_PUBLIC const LinphoneErrorInfo *linphone_event_get_error_info(const LinphoneEvent *lev);
/**
* Get subscription state. If the event object was not created by a subscription mechanism, #LinphoneSubscriptionNone is returned.
@ -258,7 +257,7 @@ LINPHONE_PUBLIC const char *linphone_event_get_custom_header(LinphoneEvent *ev,
/**
* Terminate an incoming or outgoing subscription that was previously acccepted, or a previous publication.
* This function does not unref the object. The core will unref() if it does not need this object anymore.
*
*
* For subscribed event, when the subscription is terminated normally or because of an error, the core will unref.
* For published events, no unref is performed. This is because it is allowed to re-publish an expired publish, as well as retry it in case of error.
**/
@ -270,7 +269,7 @@ LINPHONE_PUBLIC void linphone_event_terminate(LinphoneEvent *lev);
* By default LinphoneEvents created by the core are owned by the core only.
* An application that wishes to retain a reference to it must call linphone_event_ref().
* When this reference is no longer needed, linphone_event_unref() must be called.
*
*
**/
LINPHONE_PUBLIC LinphoneEvent *linphone_event_ref(LinphoneEvent *lev);

View file

@ -46,7 +46,7 @@ clean-local:
if ENABLE_TUTORIALS
noinst_PROGRAMS=helloworld registration buddy_status chatroom notify
noinst_PROGRAMS=helloworld registration buddy_status chatroom notify filetransfer
helloworld_SOURCES=helloworld.c
LINPHONE_TUTOS=$(helloworld_SOURCES)
@ -76,6 +76,11 @@ LINPHONE_TUTOS+=$(notify_SOURCES)
notify_LDADD=$(helloworld_LDADD)
filetransfer_SOURCES=filetransfer.c
LINPHONE_TUTOS+=$(filetransfer_SOURCES)
filetransfer_LDADD=$(helloworld_LDADD)
AM_CFLAGS=\
-I$(top_srcdir)/coreapi \
$(STRICT_OPTIONS) \

View file

@ -61,7 +61,7 @@
*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> Registration status is reported by LinphoneCoreRegistrationStateChangedCb.
*<br>
*<br> This pseudo code demonstrates basic registration operations:
*<br> \code
@ -96,7 +96,7 @@
}
\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>Most of the time, registration requires \ref authentication "authentication" to succeed. #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 #LinphoneCoreAuthInfoRequestedCb.
*<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()
@ -203,7 +203,7 @@ void text_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddre
* While initiating the second call, the first one is automatically paused.
* Then, once the second call is established, the application has the possibility to merge the two calls to form a conference where each participant
* (the local participant, the remote destination of the first call, the remote destination of the second call) can talk together.
* This must be done by adding the two calls to the conference using \link linphone_call_add_to_conference() \endlink
* This must be done by adding the two calls to the conference using \link linphone_core_add_to_conference() \endlink
*
* Once merged into a conference the LinphoneCall objects representing the calls that were established remain unchanged, except that
* they are tagged as part of the conference (see \link linphone_call_is_in_conference() \endlink ). The calls in a conference are in the LinphoneCallStreamsRunning state.
@ -270,7 +270,7 @@ and register a keep-alive handler for periodically refreshing the registration.
}];
\endcode
<li><b>Incoming call notification while in background mode</b>
<br>Assuming application using liblinphone is well configured for multitasking, incoming calls arriving while liblinphone is in background mode will simply wakeup liblinphone thread but not resume GUI. To wakeup GUI, it is recommended to send a Local Notification to the user from the #LinphoneCallStateCb. Here under a speudo code for this operation:
<br>Assuming application using liblinphone is well configured for multitasking, incoming calls arriving while liblinphone is in background mode will simply wakeup liblinphone thread but not resume GUI. To wakeup GUI, it is recommended to send a Local Notification to the user from the #LinphoneCoreCallStateChangedCb. Here under a speudo code for this operation:
\code
if ([UIApplication sharedApplication].applicationState != UIApplicationStateActive) {
// Create a new notification

217
coreapi/help/filetransfer.c Normal file
View file

@ -0,0 +1,217 @@
/*
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;
}
/**
* function invoked to report file transfer progress.
* */
static void file_transfer_progress_indication(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, size_t progress) {
const LinphoneAddress* from_address = linphone_chat_message_get_from(message);
const LinphoneAddress* to_address = linphone_chat_message_get_to(message);
char *address = linphone_chat_message_is_outgoing(message)?linphone_address_as_string(to_address):linphone_address_as_string(from_address);
printf(" File transfer [%d%%] %s of type [%s/%s] %s [%s] \n", (int)progress
,(linphone_chat_message_is_outgoing(message)?"sent":"received")
, content->type
, content->subtype
,(linphone_chat_message_is_outgoing(message)?"to":"from")
, address);
free(address);
}
/**
* function invoked when a file transfer is received.
**/
static void file_transfer_received(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, const char* buff, size_t size){
FILE* file=NULL;
if (!linphone_chat_message_get_user_data(message)) {
/*first chunk, creating file*/
file = fopen("receive_file.dump","wb");
linphone_chat_message_set_user_data(message,(void*)file); /*store fd for next chunks*/
} else {
/*next chunk*/
file = (FILE*)linphone_chat_message_get_user_data(message);
if (size==0) {
printf("File transfert completed\n");
linphone_chat_room_destroy(linphone_chat_message_get_chat_room(message));
linphone_chat_message_destroy(message);
fclose(file);
running=FALSE;
} else { /* store content on a file*/
if (fwrite(buff,size,1,file)==-1){
ms_warning("file_transfer_received() write failed: %s",strerror(errno));
}
}
}
}
char big_file [128000];
/*
* function called when the file transfer is initiated. file content should be feed into object LinphoneContent
* */
static void file_transfer_send(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, char* buff, size_t* size){
int offset=-1;
if (!linphone_chat_message_get_user_data(message)) {
/*first chunk*/
offset=0;
} else {
/*subsequent chunk*/
offset = (int)((long)(linphone_chat_message_get_user_data(message))&0x00000000FFFFFFFF);
}
*size = MIN(*size,sizeof(big_file)-offset); /*updating content->size with minimun between remaining data and requested size*/
if (*size==0) {
/*end of file*/
return;
}
memcpy(buff,big_file+offset,*size);
/*store offset for next chunk*/
linphone_chat_message_set_user_data(message,(void*)(offset+*size));
}
/*
* Call back called when a message is received
*/
static void message_received(LinphoneCore *lc, LinphoneChatRoom *cr, LinphoneChatMessage *msg) {
const LinphoneContent *file_transfer_info = linphone_chat_message_get_file_transfer_information(msg);
printf ("Do you really want to download %s (size %ld)?[Y/n]\nOk, let's go\n", file_transfer_info->name, (long int)file_transfer_info->size);
linphone_chat_message_start_file_download(msg);
}
/*
* Call back to get delivery status of a message
* */
static void linphone_file_transfer_state_changed(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud) {
const LinphoneAddress* to_address = linphone_chat_message_get_to(msg);
char *to = linphone_address_as_string(to_address);
printf("File transfer sent to [%s] delivery status is [%s] \n" , to
, linphone_chat_message_state_to_string(state));
free(to);
}
LinphoneCore *lc;
int main(int argc, char *argv[]){
LinphoneCoreVTable vtable={0};
const char* dest_friend=NULL;
int i;
const char* big_file_content="big file";
/*seting dummy file content to something*/
for (i=0;i<sizeof(big_file);i+=strlen(big_file_content))
memcpy(big_file+i, big_file_content, strlen(big_file_content));
big_file[0]=*"S";
big_file[sizeof(big_file)-1]=*"E";
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 file_transfer_received callback
in order to get notifications about incoming file receive, file_transfer_send to feed file to be transfered
and file_transfer_progress_indication to print progress.
*/
vtable.file_transfer_received=file_transfer_received;
vtable.file_transfer_send=file_transfer_send;
vtable.file_transfer_progress_indication=file_transfer_progress_indication;
vtable.message_received=message_received;
/*
Instantiate a LinphoneCore object given the LinphoneCoreVTable
*/
lc=linphone_core_new(&vtable,NULL,NULL,NULL);
dest_friend = linphone_core_get_primary_contact(lc);
printf("Send message to me : %s\n", dest_friend);
/**
* Globally configure an http file transfer server.
*/
//linphone_core_set_file_transfer_server(lc,"http://npasc.al/lft.php");
linphone_core_set_file_transfer_server(lc,"https://www.linphone.org:444/lft.php");
/*Next step is to create a chat room*/
LinphoneChatRoom* chat_room = linphone_core_create_chat_room(lc,dest_friend);
LinphoneContent content;
memset(&content,0,sizeof(content));
content.type="text";
content.subtype="plain";
content.size=sizeof(big_file); /*total size to be transfered*/
content.name = "bigfile.txt";
/*now create a chat message with custom content*/
LinphoneChatMessage* chat_message = linphone_chat_room_create_file_transfer_message(chat_room,&content);
if (chat_message == NULL) {
printf("returned message is null\n");
}
/*initiating file transfer*/
linphone_chat_room_send_message2(chat_room, chat_message, linphone_file_transfer_state_changed, NULL);
/* 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;
}

View file

@ -42,10 +42,11 @@ struct _LinphoneInfoMessage{
ptr->field=ms_strdup(val); \
}
static void linphone_content_copy(LinphoneContent *obj, const LinphoneContent *ref){
void linphone_content_copy(LinphoneContent *obj, const LinphoneContent *ref){
SET_STRING(obj,type,ref->type);
SET_STRING(obj,subtype,ref->subtype);
SET_STRING(obj,encoding,ref->encoding);
SET_STRING(obj,name,ref->name);
if (obj->data) {
ms_free(obj->data);
obj->data=NULL;
@ -63,6 +64,7 @@ void linphone_content_uninit(LinphoneContent * obj){
if (obj->subtype) ms_free(obj->subtype);
if (obj->data) ms_free(obj->data);
if (obj->encoding) ms_free(obj->encoding);
if (obj->name) ms_free(obj->name);
}
LinphoneContent *linphone_content_copy_from_sal_body(LinphoneContent *obj, const SalBody *ref){

View file

@ -22,7 +22,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef LINPHONETUNNEL_H
#define LINPHONETUNNEL_H
@ -86,7 +86,7 @@ LINPHONE_PUBLIC void linphone_tunnel_config_set_port(LinphoneTunnelConfig *tunne
LINPHONE_PUBLIC int linphone_tunnel_config_get_port(const LinphoneTunnelConfig *tunnel);
/**
* Set the remote port on the tunnel server side used to test udp reachability.
* Set the remote port on the tunnel server side used to test udp reachability.
*
* @param tunnel configuration object
* @param remote_udp_mirror_port remote port on the tunnel server side used to test udp reachability, set to -1 to disable the feature
@ -110,7 +110,7 @@ LINPHONE_PUBLIC void linphone_tunnel_config_set_delay(LinphoneTunnelConfig *tunn
/**
* Get the udp packet round trip delay in ms for a tunnel configuration.
*
*
* @param tunnel configuration object
*/
LINPHONE_PUBLIC int linphone_tunnel_config_get_delay(const LinphoneTunnelConfig *tunnel);
@ -132,7 +132,7 @@ LINPHONE_PUBLIC void linphone_tunnel_add_server(LinphoneTunnel *tunnel, Linphone
/**
* Remove tunnel server configuration
*
*
* @param tunnel object
* @param tunnel_config object
*/
@ -208,7 +208,7 @@ LINPHONE_PUBLIC bool_t linphone_tunnel_auto_detect_enabled(LinphoneTunnel *tunne
* @param host Http proxy host.
* @param port http proxy port.
* @param username optional http proxy username if the proxy request authentication. Currently only basic authentication is supported. Use NULL if not needed.
* @param password optional http proxy password. Use NULL if not needed.
* @param passwd optional http proxy password. Use NULL if not needed.
**/
LINPHONE_PUBLIC void linphone_tunnel_set_http_proxy(LinphoneTunnel *tunnel, const char *host, int port, const char* username,const char* passwd);
@ -218,7 +218,7 @@ LINPHONE_PUBLIC void linphone_tunnel_set_http_proxy(LinphoneTunnel *tunnel, cons
* @param host Http proxy host.
* @param port http proxy port.
* @param username optional http proxy username if the proxy request authentication. Currently only basic authentication is supported. Use NULL if not needed.
* @param password optional http proxy password. Use NULL if not needed.
* @param passwd optional http proxy password. Use NULL if not needed.
**/
LINPHONE_PUBLIC void linphone_tunnel_get_http_proxy(LinphoneTunnel*tunnel,const char **host, int *port, const char **username, const char **passwd);

View file

@ -37,6 +37,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "mediastreamer2/mseventqueue.h"
#include "mediastreamer2/mssndcard.h"
static void linphone_call_stats_uninit(LinphoneCallStats *stats);
#ifdef VIDEO_ENABLED
static MSWebCam *get_nowebcam_device(){
return ms_web_cam_manager_get_cam(ms_web_cam_manager_get(),"StaticImage: Static picture");
@ -94,27 +96,63 @@ bool_t linphone_call_get_authentication_token_verified(LinphoneCall *call){
return call->auth_token_verified;
}
static bool_t linphone_call_are_all_streams_encrypted(LinphoneCall *call) {
static bool_t linphone_call_all_streams_encrypted(const LinphoneCall *call) {
int number_of_encrypted_stream = 0;
int number_of_active_stream = 0;
if (call) {
if (call->audiostream && media_stream_get_state((MediaStream *)call->audiostream) == MSStreamStarted) {
number_of_active_stream++;
if(media_stream_is_secured((MediaStream *)call->audiostream))
if(media_stream_secured((MediaStream *)call->audiostream))
number_of_encrypted_stream++;
}
if (call->videostream && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) {
number_of_active_stream++;
if (media_stream_is_secured((MediaStream *)call->videostream))
if (media_stream_secured((MediaStream *)call->videostream))
number_of_encrypted_stream++;
}
}
return number_of_active_stream>0 && number_of_active_stream==number_of_encrypted_stream;
}
static bool_t linphone_call_all_streams_avpf_enabled(const LinphoneCall *call) {
int nb_active_streams = 0;
int nb_avpf_enabled_streams = 0;
if (call) {
if (call->audiostream && media_stream_get_state((MediaStream *)call->audiostream) == MSStreamStarted) {
nb_active_streams++;
if (media_stream_avpf_enabled((MediaStream *)call->audiostream))
nb_avpf_enabled_streams++;
}
if (call->videostream && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) {
nb_active_streams++;
if (media_stream_avpf_enabled((MediaStream *)call->videostream))
nb_avpf_enabled_streams++;
}
}
return ((nb_active_streams > 0) && (nb_active_streams == nb_avpf_enabled_streams));
}
static uint16_t linphone_call_get_avpf_rr_interval(const LinphoneCall *call) {
uint16_t rr_interval = 0;
uint16_t stream_rr_interval;
if (call) {
if (call->audiostream && media_stream_get_state((MediaStream *)call->audiostream) == MSStreamStarted) {
stream_rr_interval = media_stream_get_avpf_rr_interval((MediaStream *)call->audiostream);
if (stream_rr_interval > rr_interval) rr_interval = stream_rr_interval;
}
if (call->videostream && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) {
stream_rr_interval = media_stream_get_avpf_rr_interval((MediaStream *)call->videostream);
if (stream_rr_interval > rr_interval) rr_interval = stream_rr_interval;
}
} else {
rr_interval = 5000;
}
return rr_interval;
}
static void propagate_encryption_changed(LinphoneCall *call){
LinphoneCore *lc=call->core;
if (!linphone_call_are_all_streams_encrypted(call)) {
if (!linphone_call_all_streams_encrypted(call)) {
ms_message("Some streams are not encrypted");
call->current_params.media_encryption=LinphoneMediaEncryptionNone;
if (lc->vtable.call_encryption_changed)
@ -197,7 +235,6 @@ static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandw
if (max_sample_rate) *max_sample_rate=0;
for(it=codecs;it!=NULL;it=it->next){
PayloadType *pt=(PayloadType*)it->data;
payload_type_unset_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED); /* Disable AVPF for the moment. */
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 of %i kbit/s",
@ -217,11 +254,12 @@ static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandw
static void update_media_description_from_stun(SalMediaDescription *md, const StunCandidate *ac, const StunCandidate *vc){
int i;
for (i = 0; i < md->n_active_streams; i++) {
for (i = 0; i < md->nb_streams; i++) {
if (!sal_stream_description_active(&md->streams[i])) continue;
if ((md->streams[i].type == SalAudio) && (ac->port != 0)) {
strcpy(md->streams[0].rtp_addr,ac->addr);
md->streams[0].rtp_port=ac->port;
if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0) || md->n_active_streams==1){
if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0) || sal_media_description_get_nb_active_streams(md)==1){
strcpy(md->addr,ac->addr);
}
}
@ -232,35 +270,80 @@ static void update_media_description_from_stun(SalMediaDescription *md, const St
}
}
static int setup_encryption_key(SalSrtpCryptoAlgo *crypto, MSCryptoSuite suite, unsigned int tag){
int keylen=0;
crypto->tag=tag;
crypto->algo=suite;
switch(suite){
case MS_AES_128_SHA1_80:
case MS_AES_128_SHA1_32:
case MS_AES_128_NO_AUTH:
case MS_NO_CIPHER_SHA1_80: /*not sure for this one*/
keylen=30;
break;
case MS_AES_256_SHA1_80:
case MS_AES_256_SHA1_32:
keylen=46;
break;
case MS_CRYPTO_SUITE_INVALID:
break;
}
if (keylen==0 || !generate_b64_crypto_key(30, crypto->master_key, SAL_SRTP_KEY_SIZE)){
ms_error("Could not generate SRTP key.");
crypto->algo = 0;
return -1;
}
return 0;
}
static void setup_encryption_keys(LinphoneCall *call, SalMediaDescription *md){
LinphoneCore *lc=call->core;
int i;
int i,j;
SalMediaDescription *old_md=call->localdesc;
bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",1);
for(i=0; i<md->n_active_streams; i++) {
if (md->streams[i].proto == SalProtoRtpSavp) {
if (keep_srtp_keys && old_md && old_md->streams[i].proto==SalProtoRtpSavp){
for(i=0; i<md->nb_streams; i++) {
if (!sal_stream_description_active(&md->streams[i])) continue;
if (sal_stream_description_has_srtp(&md->streams[i]) == TRUE) {
if (keep_srtp_keys && old_md && sal_stream_description_has_srtp(&old_md->streams[i]) == TRUE){
int j;
ms_message("Keeping same crypto keys.");
for(j=0;j<SAL_CRYPTO_ALGO_MAX;++j){
memcpy(&md->streams[i].crypto[j],&old_md->streams[i].crypto[j],sizeof(SalSrtpCryptoAlgo));
}
}else{
md->streams[i].crypto[0].tag = 1;
md->streams[i].crypto[0].algo = MS_AES_128_SHA1_80;
if (!generate_b64_crypto_key(30, md->streams[i].crypto[0].master_key, SAL_SRTP_KEY_SIZE))
md->streams[i].crypto[0].algo = 0;
md->streams[i].crypto[1].tag = 2;
md->streams[i].crypto[1].algo = MS_AES_128_SHA1_32;
if (!generate_b64_crypto_key(30, md->streams[i].crypto[1].master_key, SAL_SRTP_KEY_SIZE))
md->streams[i].crypto[1].algo = 0;
md->streams[i].crypto[2].algo = 0;
const MSCryptoSuite *suites=linphone_core_get_srtp_crypto_suites(lc);
for(j=0;suites!=NULL && suites[j]!=MS_CRYPTO_SUITE_INVALID && j<SAL_CRYPTO_ALGO_MAX;++j){
setup_encryption_key(&md->streams[i].crypto[j],suites[j],j+1);
}
}
}
}
}
static void setup_rtcp_fb(LinphoneCall *call, SalMediaDescription *md) {
MSList *pt_it;
PayloadType *pt;
PayloadTypeAvpfParams avpf_params;
int i;
for (i = 0; i < md->nb_streams; i++) {
if (!sal_stream_description_active(&md->streams[i])) continue;
for (pt_it = md->streams[i].payloads; pt_it != NULL; pt_it = pt_it->next) {
pt = (PayloadType *)pt_it->data;
if (call->params.avpf_enabled == TRUE) {
payload_type_set_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED);
avpf_params = payload_type_get_avpf_params(pt);
avpf_params.trr_interval = call->params.avpf_rr_interval;
} else {
payload_type_unset_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED);
memset(&avpf_params, 0, sizeof(avpf_params));
}
payload_type_set_avpf_params(pt, avpf_params);
}
}
}
static void setup_rtcp_xr(LinphoneCall *call, SalMediaDescription *md) {
LinphoneCore *lc = call->core;
int i;
@ -280,16 +363,30 @@ static void setup_rtcp_xr(LinphoneCall *call, SalMediaDescription *md) {
}
md->rtcp_xr.voip_metrics_enabled = lp_config_get_int(lc->config, "rtp", "rtcp_xr_voip_metrics_enabled", 0);
}
for (i = 0; i < md->n_active_streams; i++) {
for (i = 0; i < md->nb_streams; i++) {
if (!sal_stream_description_active(&md->streams[i])) continue;
memcpy(&md->streams[i].rtcp_xr, &md->rtcp_xr, sizeof(md->streams[i].rtcp_xr));
}
}
void linphone_call_increment_local_media_description(LinphoneCall *call){
SalMediaDescription *md=call->localdesc;
md->session_ver++;
}
static SalMediaProto get_proto_from_call_params(const LinphoneCallParams *params) {
if ((params->media_encryption == LinphoneMediaEncryptionSRTP) && params->avpf_enabled) return SalProtoRtpSavpf;
if (params->media_encryption == LinphoneMediaEncryptionSRTP) return SalProtoRtpSavp;
if (params->avpf_enabled) return SalProtoRtpAvpf;
return SalProtoRtpAvp;
}
void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call){
MSList *l;
PayloadType *pt;
SalMediaDescription *old_md=call->localdesc;
int i;
int nb_active_streams = 0;
const char *me;
SalMediaDescription *md=sal_media_description_new();
LinphoneAddress *addr;
@ -306,7 +403,7 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *
md->session_id=(old_md ? old_md->session_id : (rand() & 0xfff));
md->session_ver=(old_md ? (old_md->session_ver+1) : (rand() & 0xfff));
md->n_total_streams=(call->biggestdesc ? call->biggestdesc->n_total_streams : 1);
md->nb_streams=(call->biggestdesc ? call->biggestdesc->nb_streams : 1);
strncpy(md->addr,local_ip,sizeof(md->addr));
strncpy(md->username,linphone_address_get_username(addr),sizeof(md->username));
@ -317,14 +414,12 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *
else md->bandwidth=linphone_core_get_download_bandwidth(lc);
/*set audio capabilities */
md->n_active_streams=1;
strncpy(md->streams[0].rtp_addr,local_ip,sizeof(md->streams[0].rtp_addr));
strncpy(md->streams[0].rtcp_addr,local_ip,sizeof(md->streams[0].rtcp_addr));
strncpy(md->streams[0].name,"Audio",sizeof(md->streams[0].name)-1);
md->streams[0].rtp_port=call->media_ports[0].rtp_port;
md->streams[0].rtcp_port=call->media_ports[0].rtcp_port;
md->streams[0].proto=(call->params.media_encryption == LinphoneMediaEncryptionSRTP) ?
SalProtoRtpSavp : SalProtoRtpAvp;
md->streams[0].proto=get_proto_from_call_params(&call->params);
md->streams[0].type=SalAudio;
if (call->params.down_ptime)
md->streams[0].ptime=call->params.down_ptime;
@ -334,22 +429,26 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *
pt=payload_type_clone(rtp_profile_get_payload_from_mime(lc->default_profile,"telephone-event"));
l=ms_list_append(l,pt);
md->streams[0].payloads=l;
nb_active_streams++;
if (call->params.has_video){
md->n_active_streams++;
strncpy(md->streams[0].name,"Video",sizeof(md->streams[0].name)-1);
strncpy(md->streams[1].rtp_addr,local_ip,sizeof(md->streams[1].rtp_addr));
strncpy(md->streams[1].rtcp_addr,local_ip,sizeof(md->streams[1].rtcp_addr));
strncpy(md->streams[1].name,"Video",sizeof(md->streams[1].name)-1);
md->streams[1].rtp_port=call->media_ports[1].rtp_port;
md->streams[1].rtcp_port=call->media_ports[1].rtcp_port;
md->streams[1].proto=md->streams[0].proto;
md->streams[1].type=SalVideo;
l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL,-1);
md->streams[1].payloads=l;
nb_active_streams++;
}
if (md->n_total_streams < md->n_active_streams)
md->n_total_streams = md->n_active_streams;
if (md->nb_streams < nb_active_streams)
md->nb_streams = nb_active_streams;
/* Deactivate inactive streams. */
for (i = md->n_active_streams; i < md->n_total_streams; i++) {
for (i = nb_active_streams; i < md->nb_streams; i++) {
md->streams[i].rtp_port = 0;
md->streams[i].rtcp_port = 0;
md->streams[i].proto = call->biggestdesc->streams[i].proto;
@ -360,6 +459,7 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *
}
setup_encryption_keys(call,md);
setup_rtcp_fb(call, md);
setup_rtcp_xr(call, md);
update_media_description_from_stun(md,&call->ac,&call->vc);
@ -461,7 +561,7 @@ static void port_config_set(LinphoneCall *call, int stream_index, int min_port,
static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
int min_port, max_port;
ms_message("New LinphoneCall [%p] initialized (LinphoneCore version: %s)",call,linphone_core_get_version());
call->magic=linphone_call_magic;
call->refcnt=1;
call->state=LinphoneCallIdle;
@ -579,6 +679,26 @@ static void linphone_call_incoming_select_ip_version(LinphoneCall *call){
}else call->af=AF_INET;
}
/**
* Fix call parameters on incoming call to eg. enable AVPF if the incoming call propose it and it is not enabled locally.
*/
void linphone_call_set_compatible_incoming_call_parameters(LinphoneCall *call, const SalMediaDescription *md) {
call->params.has_video &= linphone_core_media_description_contains_video_stream(md);
/* Handle AVPF and SRTP. */
call->params.avpf_enabled = sal_media_description_has_avpf(md);
if (call->params.avpf_enabled == TRUE) {
if (call->dest_proxy != NULL) {
call->params.avpf_rr_interval = linphone_proxy_config_get_avpf_rr_interval(call->dest_proxy) * 1000;
} else {
call->params.avpf_rr_interval = 5000;
}
}
if ((sal_media_description_has_srtp(md) == TRUE) && (media_stream_srtp_supported() == TRUE)) {
call->params.media_encryption = LinphoneMediaEncryptionSRTP;
}
}
LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){
LinphoneCall *call=ms_new0(LinphoneCall,1);
char *from_str;
@ -613,6 +733,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
linphone_core_get_local_ip(lc,call->af,call->localip);
linphone_call_init_common(call, from, to);
call->log->call_id=ms_strdup(sal_op_get_call_id(op)); /*must be known at that time*/
call->dest_proxy = linphone_core_lookup_known_proxy(call->core, to);
linphone_core_init_default_params(lc, &call->params);
/*
@ -623,11 +744,11 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
call->current_params.privacy=(LinphonePrivacyMask)sal_op_get_privacy(call->op);
/*set video support */
md=sal_call_get_remote_media_description(op);
call->params.has_video = !!lc->video_policy.automatically_accept;
call->params.has_video = lc->video_policy.automatically_accept;
if (md) {
// It is licit to receive an INVITE without SDP
// In this case WE chose the media parameters according to policy.
call->params.has_video &= linphone_core_media_description_contains_video_stream(md);
linphone_call_set_compatible_incoming_call_parameters(call, md);
}
fpol=linphone_core_get_firewall_policy(call->core);
/*create the ice session now if ICE is required*/
@ -686,7 +807,8 @@ static void linphone_call_set_terminated(LinphoneCall *call){
linphone_call_delete_upnp_session(call);
linphone_call_delete_ice_session(call);
linphone_core_update_allocated_audio_bandwidth(lc);
linphone_call_stats_uninit(&call->stats[0]);
linphone_call_stats_uninit(&call->stats[1]);
call->owns_call_log=FALSE;
linphone_call_log_completed(call);
@ -709,6 +831,7 @@ static void linphone_call_set_terminated(LinphoneCall *call){
void linphone_call_fix_call_parameters(LinphoneCall *call){
call->params.has_video=call->current_params.has_video;
if (call->params.media_encryption != LinphoneMediaEncryptionZRTP) /*in case of ZRTP call parameter are handle after zrtp negociation*/
call->params.media_encryption=call->current_params.media_encryption;
}
@ -796,17 +919,10 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const
call->media_start_time=time(NULL);
}
if (cstate == LinphoneCallStreamsRunning) {
linphone_reporting_update_ip(call);
}
if (lc->vtable.call_state_changed)
lc->vtable.call_state_changed(lc,call,cstate,message);
if (cstate==LinphoneCallEnd){
if (call->log->status == LinphoneCallSuccess)
linphone_reporting_publish(call);
}
linphone_reporting_call_state_updated(call);
if (cstate==LinphoneCallReleased){
if (call->op!=NULL) {
@ -922,7 +1038,7 @@ const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){
}
#endif
if (linphone_call_are_all_streams_encrypted(call)) {
if (linphone_call_all_streams_encrypted(call)) {
if (linphone_call_get_authentication_token(call)) {
call->current_params.media_encryption=LinphoneMediaEncryptionZRTP;
} else {
@ -931,14 +1047,16 @@ const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){
} else {
call->current_params.media_encryption=LinphoneMediaEncryptionNone;
}
call->current_params.avpf_enabled = linphone_call_all_streams_avpf_enabled(call);
if (call->current_params.avpf_enabled == TRUE) {
call->current_params.avpf_rr_interval = linphone_call_get_avpf_rr_interval(call);
} else {
call->current_params.avpf_rr_interval = 0;
}
return &call->current_params;
}
static bool_t is_video_active(const SalStreamDescription *sd){
return sd->rtp_port!=0 && sd->dir!=SalStreamInactive;
}
/**
* Returns call parameters proposed by remote.
*
@ -950,19 +1068,20 @@ const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){
memset(cp,0,sizeof(*cp));
if (call->op){
SalMediaDescription *md=sal_call_get_remote_media_description(call->op);
if (md){
SalStreamDescription *asd,*vsd,*secure_asd,*secure_vsd;
if (md) {
SalStreamDescription *sd;
unsigned int i;
unsigned int nb_audio_streams = sal_media_description_nb_active_streams_of_type(md, SalAudio);
unsigned int nb_video_streams = sal_media_description_nb_active_streams_of_type(md, SalVideo);
asd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalAudio);
vsd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalVideo);
secure_asd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalAudio);
secure_vsd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalVideo);
if (secure_vsd){
cp->has_video=is_video_active(secure_vsd);
if (secure_asd || asd==NULL)
cp->media_encryption=LinphoneMediaEncryptionSRTP;
}else if (vsd){
cp->has_video=is_video_active(vsd);
for (i = 0; i < nb_video_streams; i++) {
sd = sal_media_description_get_active_stream_of_type(md, SalVideo, i);
if (sal_stream_description_active(sd) == TRUE) cp->has_video = TRUE;
if (sal_stream_description_has_srtp(sd) == TRUE) cp->media_encryption = LinphoneMediaEncryptionSRTP;
}
for (i = 0; i < nb_audio_streams; i++) {
sd = sal_media_description_get_active_stream_of_type(md, SalAudio, i);
if (sal_stream_description_has_srtp(sd) == TRUE) cp->media_encryption = LinphoneMediaEncryptionSRTP;
}
if (!cp->has_video){
if (md->bandwidth>0 && md->bandwidth<=linphone_core_get_edge_bw(call->core)){
@ -1217,6 +1336,10 @@ MSVideoSize linphone_call_params_get_received_video_size(const LinphoneCallParam
return cp->recv_vsize;
}
const char * linphone_call_params_get_rtp_profile(const LinphoneCallParams *cp) {
return sal_media_proto_to_string(get_proto_from_call_params(cp));
}
/**
* @ingroup call_control
* Use to know if this call has been configured in low bandwidth mode.
@ -1281,7 +1404,7 @@ bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams
/**
* Returns true if the call is part of the locally managed conference.
**/
bool_t linphone_call_params_local_conference_mode(const LinphoneCallParams *cp){
bool_t linphone_call_params_get_local_conference_mode(const LinphoneCallParams *cp){
return cp->in_conference;
}
@ -1338,7 +1461,7 @@ void _linphone_call_params_copy(LinphoneCallParams *ncp, const LinphoneCallParam
* Set requested level of privacy for the call.
* \xmlonly <language-tags>javascript</language-tags> \endxmlonly
* @param params the call parameters to be modified
* @param LinphonePrivacy to configure privacy
* @param privacy LinphonePrivacy to configure privacy
* */
void linphone_call_params_set_privacy(LinphoneCallParams *params, LinphonePrivacyMask privacy) {
params->privacy=privacy;
@ -1408,7 +1531,6 @@ static void rendercb(void *data, const MSPicture *local, const MSPicture *remote
#ifdef VIDEO_ENABLED
static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const unsigned int event_id, const void *args){
LinphoneCall* call = (LinphoneCall*) user_pointer;
ms_warning("In linphonecall.c: video_stream_event_cb");
switch (event_id) {
case MS_VIDEO_DECODER_DECODING_ERRORS:
ms_warning("Case is MS_VIDEO_DECODER_DECODING_ERRORS");
@ -1422,6 +1544,11 @@ static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const u
if (call->nextVideoFrameDecoded._func != NULL)
call->nextVideoFrameDecoded._func(call, call->nextVideoFrameDecoded._user_data);
break;
case MS_VIDEO_DECODER_SEND_PLI:
case MS_VIDEO_DECODER_SEND_SLI:
case MS_VIDEO_DECODER_SEND_RPSI:
/* Handled internally by mediastreamer2. */
break;
default:
ms_warning("Unhandled event %i", event_id);
break;
@ -1452,7 +1579,7 @@ static void _linphone_call_prepare_ice_for_stream(LinphoneCall *call, int stream
cl=ice_session_check_list(call->ice_session, stream_index);
if (cl == NULL && create_checklist) {
cl=ice_check_list_new();
ice_session_add_check_list(call->ice_session, cl);
ice_session_add_check_list(call->ice_session, cl, stream_index);
ms_message("Created new ICE check list for stream [%i]",stream_index);
}
if (cl){
@ -1469,7 +1596,7 @@ int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer){
if ((linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
if (incoming_offer){
remote=sal_call_get_remote_media_description(call->op);
has_video=linphone_core_media_description_contains_video_stream(remote);
has_video=call->params.has_video && linphone_core_media_description_contains_video_stream(remote);
}else has_video=call->params.has_video;
_linphone_call_prepare_ice_for_stream(call,0,TRUE);
@ -1505,6 +1632,7 @@ void linphone_call_init_audio_stream(LinphoneCall *call){
if (call->audiostream != NULL) return;
if (call->sessions[0].rtp_session==NULL){
call->audiostream=audiostream=audio_stream_new(call->media_ports[0].rtp_port,call->media_ports[0].rtcp_port,call->af==AF_INET6);
rtp_session_set_symmetric_rtp(audiostream->ms.sessions.rtp_session,linphone_core_symmetric_rtp_enabled(lc));
}else{
call->audiostream=audio_stream_new_with_sessions(&call->sessions[0]);
}
@ -1565,6 +1693,7 @@ void linphone_call_init_video_stream(LinphoneCall *call){
if (call->sessions[1].rtp_session==NULL){
call->videostream=video_stream_new(call->media_ports[1].rtp_port,call->media_ports[1].rtcp_port, call->af==AF_INET6);
rtp_session_set_symmetric_rtp(call->videostream->ms.sessions.rtp_session,linphone_core_symmetric_rtp_enabled(lc));
}else{
call->videostream=video_stream_new_with_sessions(&call->sessions[1]);
}
@ -1711,7 +1840,7 @@ static int get_ideal_audio_bw(LinphoneCall *call, const SalMediaDescription *md,
const LinphoneCallParams *params=&call->params;
bool_t will_use_video=linphone_core_media_description_contains_video_stream(md);
bool_t forced=FALSE;
if (desc->bandwidth>0) remote_bw=desc->bandwidth;
else if (md->bandwidth>0) {
/*case where b=AS is given globally, not per stream*/
@ -1723,7 +1852,7 @@ static int get_ideal_audio_bw(LinphoneCall *call, const SalMediaDescription *md,
}else upload_bw=total_upload_bw;
upload_bw=get_min_bandwidth(upload_bw,remote_bw);
if (!will_use_video || forced) return upload_bw;
if (bandwidth_is_greater(upload_bw,512)){
upload_bw=100;
}else if (bandwidth_is_greater(upload_bw,256)){
@ -1756,13 +1885,14 @@ static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *m
LinphoneCore *lc=call->core;
int up_ptime=0;
const LinphoneCallParams *params=&call->params;
*used_pt=-1;
if (desc->type==SalAudio)
bw=get_ideal_audio_bw(call,md,desc);
else if (desc->type==SalVideo)
bw=get_video_bw(call,md,desc);
for(elem=desc->payloads;elem!=NULL;elem=elem->next){
PayloadType *pt=(PayloadType*)elem->data;
int number;
@ -1784,6 +1914,7 @@ static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *m
first=FALSE;
}
if (pt->flags & PAYLOAD_TYPE_BITRATE_OVERRIDE){
ms_message("Payload type [%s/%i] has explicit bitrate [%i] kbit/s", pt->mime_type, pt->clock_rate, pt->normal_bitrate/1000);
pt->normal_bitrate=get_min_bandwidth(pt->normal_bitrate,bw*1000);
} else pt->normal_bitrate=bw*1000;
if (desc->ptime>0){
@ -1835,12 +1966,10 @@ static void configure_rtp_session_for_rtcp_xr(LinphoneCore *lc, LinphoneCall *ca
const SalStreamDescription *localstream;
const SalStreamDescription *remotestream;
localstream = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, type);
if (!localstream) localstream = sal_media_description_find_stream(call->localdesc, SalProtoRtpAvp, type);
localstream = sal_media_description_find_best_stream(call->localdesc, type);
if (!localstream) return;
localconfig = &localstream->rtcp_xr;
remotestream = sal_media_description_find_stream(sal_call_get_remote_media_description(call->op), SalProtoRtpSavp, type);
if (!remotestream) remotestream = sal_media_description_find_stream(sal_call_get_remote_media_description(call->op), SalProtoRtpAvp, type);
remotestream = sal_media_description_find_best_stream(sal_call_get_remote_media_description(call->op), type);
if (!remotestream) return;
remoteconfig = &remotestream->rtcp_xr;
@ -1859,15 +1988,6 @@ static void configure_rtp_session_for_rtcp_xr(LinphoneCore *lc, LinphoneCall *ca
session = call->videostream->ms.sessions.rtp_session;
}
rtp_session_configure_rtcp_xr(session, &currentconfig);
if (currentconfig.rcvr_rtt_mode != OrtpRtcpXrRcvrRttNone) {
rtp_session_set_rtcp_xr_rcvr_rtt_interval(session, lp_config_get_int(lc->config, "rtp", "rtcp_xr_rcvr_rtt_interval_duration", 5000));
}
if (currentconfig.stat_summary_enabled == TRUE) {
rtp_session_set_rtcp_xr_stat_summary_interval(session, lp_config_get_int(lc->config, "rtp", "rtcp_xr_stat_summary_interval_duration", 5000));
}
if (currentconfig.voip_metrics_enabled == TRUE) {
rtp_session_set_rtcp_xr_voip_metrics_interval(session, lp_config_get_int(lc->config, "rtp", "rtcp_xr_voip_metrics_interval_duration", 5000));
}
}
static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cname, bool_t muted, bool_t send_ringbacktone, bool_t use_arc){
@ -1885,14 +2005,8 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna
int crypto_idx;
snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
/* look for savp stream first */
stream=sal_media_description_find_stream(call->resultdesc,
SalProtoRtpSavp,SalAudio);
/* no savp audio stream, use avp */
if (!stream)
stream=sal_media_description_find_stream(call->resultdesc,
SalProtoRtpAvp,SalAudio);
stream = sal_media_description_find_best_stream(call->resultdesc, SalAudio);
if (stream && stream->dir!=SalStreamInactive && stream->rtp_port!=0){
playcard=lc->sound_conf.lsd_card ?
lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
@ -1948,8 +2062,8 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna
call->current_params.record_file=ms_strdup(call->params.record_file);
}
/* valid local tags are > 0 */
if (stream->proto == SalProtoRtpSavp) {
local_st_desc=sal_media_description_find_stream(call->localdesc,SalProtoRtpSavp,SalAudio);
if (sal_stream_description_has_srtp(stream) == TRUE) {
local_st_desc=sal_media_description_find_stream(call->localdesc,stream->proto,SalAudio);
crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag);
if (crypto_idx >= 0) {
@ -1960,6 +2074,7 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna
}
}
configure_rtp_session_for_rtcp_xr(lc, call, SalAudio);
audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool);
audio_stream_start_full(
call->audiostream,
call->audio_profile,
@ -1986,7 +2101,6 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna
if (send_ringbacktone){
setup_ring_player(lc,call);
}
audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool);
if (call->params.in_conference){
/*transform the graph to connect it to the conference filter */
@ -2003,17 +2117,10 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna
#ifdef VIDEO_ENABLED
LinphoneCore *lc=call->core;
int used_pt=-1;
/* look for savp stream first */
const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
SalProtoRtpSavp,SalVideo);
char rtcp_tool[128]={0};
snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
const SalStreamDescription *vstream;
/* no savp audio stream, use avp */
if (!vstream)
vstream=sal_media_description_find_stream(call->resultdesc,
SalProtoRtpAvp,SalVideo);
snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
/* shutdown preview */
if (lc->previewstream!=NULL) {
@ -2021,6 +2128,7 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna
lc->previewstream=NULL;
}
vstream = sal_media_description_find_best_stream(call->resultdesc, SalVideo);
if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->rtp_port!=0) {
const char *rtp_addr=vstream->rtp_addr[0]!='\0' ? vstream->rtp_addr : call->resultdesc->addr;
const char *rtcp_addr=vstream->rtcp_addr[0]!='\0' ? vstream->rtcp_addr : call->resultdesc->addr;
@ -2071,7 +2179,7 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna
cam=get_nowebcam_device();
}
if (!is_inactive){
if (vstream->proto == SalProtoRtpSavp) {
if (sal_stream_description_has_srtp(vstream) == TRUE) {
int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, vstream->crypto_local_tag);
if (crypto_idx >= 0) {
media_stream_set_srtp_recv_key(&call->videostream->ms,vstream->crypto[0].algo,vstream->crypto[0].master_key);
@ -2084,12 +2192,13 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna
video_stream_set_direction (call->videostream, dir);
ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation);
video_stream_set_device_rotation(call->videostream, lc->device_rotation);
video_stream_set_rtcp_information(call->videostream, cname, rtcp_tool);
video_stream_set_freeze_on_error(call->videostream, lp_config_get_int(lc->config, "video", "freeze_on_error", 0));
video_stream_start(call->videostream,
call->video_profile, rtp_addr, vstream->rtp_port,
rtcp_addr,
linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port ? vstream->rtcp_port : vstream->rtp_port+1) : 0,
used_pt, linphone_core_get_video_jittcomp(lc), cam);
video_stream_set_rtcp_information(call->videostream, cname,rtcp_tool);
}
}else ms_warning("No video stream accepted.");
}else{
@ -2104,8 +2213,7 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut
char *cname;
bool_t use_arc=linphone_core_adaptive_rate_control_enabled(lc);
#ifdef VIDEO_ENABLED
const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
SalProtoRtpAvp,SalVideo);
const SalStreamDescription *vstream=sal_media_description_find_best_stream(call->resultdesc,SalVideo);
#endif
call->current_params.audio_codec = NULL;
@ -2123,11 +2231,15 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut
use_arc=FALSE;
}
#endif
ms_message("linphone_call_start_media_streams() call=[%p] local upload_bandwidth=[%i] kbit/s; local download_bandwidth=[%i] kbit/s",
call, linphone_core_get_upload_bandwidth(lc),linphone_core_get_download_bandwidth(lc));
if (call->audiostream!=NULL) {
linphone_call_start_audio_stream(call,cname,all_inputs_muted,send_ringbacktone,use_arc);
}
call->current_params.has_video=FALSE;
if (call->videostream!=NULL) {
if (call->audiostream) audio_stream_link_video(call->audiostream,call->videostream);
linphone_call_start_video_stream(call,cname,all_inputs_muted);
}
@ -2142,14 +2254,14 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut
params.zid_file=lc->zrtp_secrets_cache;
audio_stream_enable_zrtp(call->audiostream,&params);
#if VIDEO_ENABLED
if (media_stream_is_secured((MediaStream *)call->audiostream) && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) {
if (media_stream_secured((MediaStream *)call->audiostream) && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) {
/*audio stream is already encrypted and video stream is active*/
memset(&params,0,sizeof(OrtpZrtpParams));
video_stream_enable_zrtp(call->videostream,call->audiostream,&params);
}
#endif
}else{
call->current_params.media_encryption=linphone_call_are_all_streams_encrypted(call) ?
call->current_params.media_encryption=linphone_call_all_streams_encrypted(call) ?
LinphoneMediaEncryptionSRTP : LinphoneMediaEncryptionNone;
}
@ -2192,17 +2304,17 @@ void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescript
SalStreamDescription *new_stream;
const SalStreamDescription *local_st_desc;
local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalAudio);
old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalAudio);
new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalAudio);
local_st_desc = sal_media_description_find_secure_stream_of_type(call->localdesc, SalAudio);
old_stream = sal_media_description_find_secure_stream_of_type(old_md, SalAudio);
new_stream = sal_media_description_find_secure_stream_of_type(new_md, SalAudio);
if (call->audiostream && local_st_desc && old_stream && new_stream &&
update_stream_crypto_params(call,local_st_desc,old_stream,new_stream,&call->audiostream->ms)){
}
#ifdef VIDEO_ENABLED
local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalVideo);
old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalVideo);
new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalVideo);
local_st_desc = sal_media_description_find_secure_stream_of_type(call->localdesc, SalVideo);
old_stream = sal_media_description_find_secure_stream_of_type(old_md, SalVideo);
new_stream = sal_media_description_find_secure_stream_of_type(new_md, SalVideo);
if (call->videostream && local_st_desc && old_stream && new_stream &&
update_stream_crypto_params(call,local_st_desc,old_stream,new_stream,&call->videostream->ms)){
}
@ -2248,9 +2360,9 @@ static void linphone_call_log_fill_stats(LinphoneCallLog *log, MediaStream *st){
}
}
void linphone_call_stop_audio_stream(LinphoneCall *call) {
static void linphone_call_stop_audio_stream(LinphoneCall *call) {
if (call->audiostream!=NULL) {
linphone_reporting_update(call, LINPHONE_CALL_STATS_AUDIO);
linphone_reporting_update_media_info(call, LINPHONE_CALL_STATS_AUDIO);
media_stream_reclaim_sessions(&call->audiostream->ms,&call->sessions[0]);
rtp_session_unregister_event_queue(call->audiostream->ms.sessions.rtp_session,call->audiostream_app_evq);
ortp_ev_queue_flush(call->audiostream_app_evq);
@ -2276,10 +2388,10 @@ void linphone_call_stop_audio_stream(LinphoneCall *call) {
}
}
void linphone_call_stop_video_stream(LinphoneCall *call) {
static void linphone_call_stop_video_stream(LinphoneCall *call) {
#ifdef VIDEO_ENABLED
if (call->videostream!=NULL){
linphone_reporting_update(call, LINPHONE_CALL_STATS_VIDEO);
linphone_reporting_update_media_info(call, LINPHONE_CALL_STATS_VIDEO);
media_stream_reclaim_sessions(&call->videostream->ms,&call->sessions[1]);
rtp_session_unregister_event_queue(call->videostream->ms.sessions.rtp_session,call->videostream_app_evq);
ortp_ev_queue_flush(call->videostream_app_evq);
@ -2300,6 +2412,8 @@ static void unset_rtp_profile(LinphoneCall *call, int i){
void linphone_call_stop_media_streams(LinphoneCall *call){
if (call->audiostream || call->videostream) {
if (call->audiostream && call->videostream)
audio_stream_unlink_video(call->audiostream, call->videostream);
linphone_call_stop_audio_stream(call);
linphone_call_stop_video_stream(call);
@ -2663,20 +2777,14 @@ static void report_bandwidth(LinphoneCall *call, MediaStream *as, MediaStream *v
}
static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){
char temp[256];
char temp[256]={0};
char *from=NULL;
if(call)
from = linphone_call_get_remote_address_as_string(call);
if (from)
{
snprintf(temp,sizeof(temp),"Remote end %s seems to have disconnected, the call is going to be closed.",from);
ms_free(from);
}
else
{
snprintf(temp,sizeof(temp),"Remote end seems to have disconnected, the call is going to be closed.");
}
ms_message("On call [%p] %s",call,temp);
from = linphone_call_get_remote_address_as_string(call);
snprintf(temp,sizeof(temp)-1,"Remote end %s seems to have disconnected, the call is going to be closed.",from ? from : "");
if (from) ms_free(from);
ms_message("On call [%p]: %s",call,temp);
if (lc->vtable.display_warning!=NULL)
lc->vtable.display_warning(lc,temp);
linphone_core_terminate_call(lc,call);
@ -2784,11 +2892,22 @@ void linphone_call_stats_fill(LinphoneCallStats *stats, MediaStream *ms, OrtpEve
}
}
void linphone_call_stats_uninit(LinphoneCallStats *stats){
if (stats->received_rtcp) {
freemsg(stats->received_rtcp);
stats->received_rtcp=NULL;
}
if (stats->sent_rtcp){
freemsg(stats->sent_rtcp);
stats->sent_rtcp=NULL;
}
}
void linphone_call_notify_stats_updated(LinphoneCall *call, int stream_index){
LinphoneCallStats *stats=&call->stats[stream_index];
LinphoneCore *lc=call->core;
if (stats->updated){
linphone_reporting_call_stats_updated(call, stream_index);
linphone_reporting_on_rtcp_update(call, stream_index);
if (lc->vtable.call_stats_updated)
lc->vtable.call_stats_updated(lc, call, stats);
stats->updated = 0;
@ -2918,8 +3037,8 @@ void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState stat
if (state != call->transfer_state) {
LinphoneCore* lc = call->core;
ms_message("Transfer state for call [%p] changed from [%s] to [%s]",call
,linphone_call_state_to_string(call->transfer_state)
,linphone_call_state_to_string(state));
,linphone_call_state_to_string(call->transfer_state)
,linphone_call_state_to_string(state));
call->transfer_state = state;
if (lc->vtable.transfer_state_changed)
lc->vtable.transfer_state_changed(lc, call, state);
@ -2990,7 +3109,7 @@ static LinphoneAddress *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call ,
} else {
ctt=linphone_core_get_primary_contact_parsed(lc);
if (ctt!=NULL){
/*otherwise use supllied localip*/
/*otherwise use supplied localip*/
linphone_address_set_domain(ctt,localip);
linphone_address_set_port(ctt,linphone_core_get_sip_port(lc));
ms_message("Contact has been fixed using local ip"/* to %s",ret*/);

View file

@ -129,8 +129,8 @@ LinphoneCallLog * linphone_call_log_new(LinphoneCall *call, LinphoneAddress *fro
cl->status=LinphoneCallAborted; /*default status*/
cl->quality=-1;
cl->reports[LINPHONE_CALL_STATS_AUDIO]=linphone_reporting_new();
cl->reports[LINPHONE_CALL_STATS_VIDEO]=linphone_reporting_new();
cl->reporting.reports[LINPHONE_CALL_STATS_AUDIO]=linphone_reporting_new();
cl->reporting.reports[LINPHONE_CALL_STATS_VIDEO]=linphone_reporting_new();
return cl;
}
@ -394,8 +394,8 @@ void linphone_call_log_destroy(LinphoneCallLog *cl){
if (cl->to!=NULL) linphone_address_destroy(cl->to);
if (cl->refkey!=NULL) ms_free(cl->refkey);
if (cl->call_id) ms_free(cl->call_id);
if (cl->reports[LINPHONE_CALL_STATS_AUDIO]!=NULL) linphone_reporting_destroy(cl->reports[LINPHONE_CALL_STATS_AUDIO]);
if (cl->reports[LINPHONE_CALL_STATS_VIDEO]!=NULL) linphone_reporting_destroy(cl->reports[LINPHONE_CALL_STATS_VIDEO]);
if (cl->reporting.reports[LINPHONE_CALL_STATS_AUDIO]!=NULL) linphone_reporting_destroy(cl->reporting.reports[LINPHONE_CALL_STATS_AUDIO]);
if (cl->reporting.reports[LINPHONE_CALL_STATS_VIDEO]!=NULL) linphone_reporting_destroy(cl->reporting.reports[LINPHONE_CALL_STATS_VIDEO]);
ms_free(cl);
}
@ -717,7 +717,7 @@ static void sip_config_read(LinphoneCore *lc)
/* get proxies config */
for(i=0;; i++){
LinphoneProxyConfig *cfg=linphone_proxy_config_new_from_config_file(lc->config,i);
LinphoneProxyConfig *cfg=linphone_proxy_config_new_from_config_file(lc,i);
if (cfg!=NULL){
linphone_core_add_proxy_config(lc,cfg);
}else{
@ -754,6 +754,7 @@ static void sip_config_read(LinphoneCore *lc)
linphone_core_enable_keep_alive(lc, (lc->sip_conf.keepalive_period > 0));
sal_use_one_matching_codec_policy(lc->sal,lp_config_get_int(lc->config,"sip","only_one_codec",0));
sal_use_dates(lc->sal,lp_config_get_int(lc->config,"sip","put_date",0));
sal_enable_sip_update_method(lc->sal,lp_config_get_int(lc->config,"sip","sip_update",1));
}
static void rtp_config_read(LinphoneCore *lc)
@ -1392,6 +1393,8 @@ static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtab
lc->http_verify_policy = belle_tls_verify_policy_new();
belle_http_provider_set_tls_verify_policy(lc->http_provider,lc->http_verify_policy);
lc->file_transfer_server = NULL;
certificates_config_read(lc);
remote_provisioning_uri = linphone_core_get_provisioning_uri(lc);
@ -1911,6 +1914,15 @@ void linphone_core_set_user_agent(LinphoneCore *lc, const char *name, const char
apply_user_agent(lc);
#endif
}
const char *linphone_core_get_user_agent(LinphoneCore *lc){
#if USE_BELLESIP
return sal_get_user_agent(lc->sal);
#else
static char ua_buffer[255] = {0};
snprintf(ua_buffer, "%s/%s", _ua_name, _ua_version, 254);
return ua_buffer;
#endif
}
const char *linphone_core_get_user_agent_name(void){
return _ua_name;
@ -2036,6 +2048,7 @@ int linphone_core_get_sip_transports(LinphoneCore *lc, LCSipTransports *tr){
* A zero value means that the transport is not activated.
* If LC_SIP_TRANSPORT_RANDOM was passed to linphone_core_set_sip_transports(), the random port choosed by the system is returned.
* @ingroup network_parameters
* @param lc the LinphoneCore
* @param tr a LCSipTransports structure.
**/
void linphone_core_get_sip_transports_used(LinphoneCore *lc, LCSipTransports *tr){
@ -2373,7 +2386,7 @@ void linphone_core_iterate(LinphoneCore *lc){
*
* @ingroup call_control
*
* A sip address should look like DisplayName <sip:username@domain:port> .
* A sip address should look like DisplayName \<sip:username\@domain:port\> .
* Basically this function performs the following tasks
* - if a phone number is entered, prepend country prefix of the default proxy
* configuration, eventually escape the '+' by 00.
@ -2557,6 +2570,7 @@ static MSList *make_routes_for_proxy(LinphoneProxyConfig *proxy, const LinphoneA
LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const LinphoneAddress *uri){
const MSList *elem;
LinphoneProxyConfig *found_cfg=NULL;
LinphoneProxyConfig *found_reg_cfg=NULL;
LinphoneProxyConfig *found_noreg_cfg=NULL;
LinphoneProxyConfig *default_cfg=lc->default_proxy;
@ -2569,21 +2583,25 @@ LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const L
}
}
/*otherwise return first registering matching, otherwise first matching */
/*otherwise return first registered, then first registering matching, otherwise first matching */
for (elem=linphone_core_get_proxy_config_list(lc);elem!=NULL;elem=elem->next){
LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
const char *domain=linphone_proxy_config_get_domain(cfg);
if (domain!=NULL && strcmp(domain,linphone_address_get_domain(uri))==0){
if (linphone_proxy_config_register_enabled(cfg)) {
if (linphone_proxy_config_get_state(cfg) == LinphoneRegistrationOk ){
found_cfg=cfg;
goto end;
break;
} else if (!found_reg_cfg && linphone_proxy_config_register_enabled(cfg)) {
found_reg_cfg=cfg;
} else if (!found_noreg_cfg){
found_noreg_cfg=cfg;
}
}
}
end:
if (!found_cfg && found_noreg_cfg) found_cfg = found_noreg_cfg;
if ( !found_cfg && found_reg_cfg) found_cfg = found_reg_cfg;
else if( !found_cfg && found_noreg_cfg ) found_cfg = found_noreg_cfg;
if (found_cfg && found_cfg!=default_cfg){
ms_debug("Overriding default proxy setting for this call/message/subscribe operation.");
}else if (!found_cfg) found_cfg=default_cfg; /*when no matching proxy config is found, use the default proxy config*/
@ -2825,6 +2843,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const
char *real_url=NULL;
LinphoneCall *call;
bool_t defer = FALSE;
LinphoneCallParams *cp = linphone_call_params_copy(params);
linphone_core_preempt_sound_resources(lc);
@ -2837,20 +2856,24 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const
real_url=linphone_address_as_string(addr);
proxy=linphone_core_lookup_known_proxy(lc,addr);
if (proxy!=NULL)
if (proxy!=NULL) {
from=linphone_proxy_config_get_identity(proxy);
cp->avpf_enabled = linphone_proxy_config_avpf_enabled(proxy);
cp->avpf_rr_interval = linphone_proxy_config_get_avpf_rr_interval(proxy) * 1000;
}
/* if no proxy or no identity defined for this proxy, default to primary contact*/
if (from==NULL) from=linphone_core_get_primary_contact(lc);
parsed_url2=linphone_address_new(from);
call=linphone_call_new_outgoing(lc,parsed_url2,linphone_address_clone(addr),params,proxy);
call=linphone_call_new_outgoing(lc,parsed_url2,linphone_address_clone(addr),cp,proxy);
if(linphone_core_add_call(lc,call)!= 0)
{
ms_warning("we had a problem in adding the call into the invite ... weird");
linphone_call_unref(call);
linphone_call_params_destroy(cp);
return NULL;
}
@ -2895,6 +2918,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const
if (defer==FALSE) linphone_core_start_invite(lc,call,NULL);
if (real_url!=NULL) ms_free(real_url);
linphone_call_params_destroy(cp);
return call;
}
@ -2907,7 +2931,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const
*
* It is possible to follow the progress of the transfer provided that transferee sends notification about it.
* In this case, the transfer_state_changed callback of the #LinphoneCoreVTable is invoked to notify of the state of the new call at the other party.
* The notified states are #LinphoneCallOutgoingInit , #LinphoneCallOutgoingProgress, #LinphoneCallOutgoingRinging and #LinphoneCallOutgoingConnected.
* The notified states are #LinphoneCallOutgoingInit , #LinphoneCallOutgoingProgress, #LinphoneCallOutgoingRinging and #LinphoneCallConnected.
**/
int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char *url)
{
@ -2947,7 +2971,7 @@ int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char
*
* It is possible to follow the progress of the transfer provided that transferee sends notification about it.
* In this case, the transfer_state_changed callback of the #LinphoneCoreVTable is invoked to notify of the state of the new call at the other party.
* The notified states are #LinphoneCallOutgoingInit , #LinphoneCallOutgoingProgress, #LinphoneCallOutgoingRinging and #LinphoneCallOutgoingConnected.
* The notified states are #LinphoneCallOutgoingInit , #LinphoneCallOutgoingProgress, #LinphoneCallOutgoingRinging and #LinphoneCallConnected.
**/
int linphone_core_transfer_call_to_another(LinphoneCore *lc, LinphoneCall *call, LinphoneCall *dest){
int result = sal_call_refer_with_replaces (call->op,dest->op);
@ -2966,21 +2990,8 @@ bool_t linphone_core_inc_invite_pending(LinphoneCore*lc){
return FALSE;
}
bool_t linphone_core_media_description_has_srtp(const SalMediaDescription *md){
int i;
if (md->n_active_streams==0) return FALSE;
for(i=0;i<md->n_active_streams;i++){
const SalStreamDescription *sd=&md->streams[i];
if (sd->proto!=SalProtoRtpSavp){
return FALSE;
}
}
return TRUE;
}
bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription *md){
return linphone_core_is_media_encryption_mandatory(lc) && linphone_core_get_media_encryption(lc)==LinphoneMediaEncryptionSRTP && !linphone_core_media_description_has_srtp(md);
return linphone_core_is_media_encryption_mandatory(lc) && linphone_core_get_media_encryption(lc)==LinphoneMediaEncryptionSRTP && !sal_media_description_has_srtp(md);
}
void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){
@ -3150,26 +3161,37 @@ int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call){
**/
int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){
int err=0;
#ifdef VIDEO_ENABLED
#if defined(VIDEO_ENABLED) && defined(BUILD_UPNP)
bool_t has_video = FALSE;
#endif
switch(call->state){
case LinphoneCallIncomingEarlyMedia:
case LinphoneCallIncomingReceived:
case LinphoneCallStreamsRunning:
/*these states are allowed for linphone_core_update_call()*/
break;
default:
ms_error("linphone_core_update_call() is not allowed in [%s] state",linphone_call_state_to_string(call->state));
return -1;
}
if (params!=NULL){
linphone_call_set_state(call,LinphoneCallUpdating,"Updating call");
#ifdef VIDEO_ENABLED
#if defined(VIDEO_ENABLED) && defined(BUILD_UPNP)
has_video = call->params.has_video;
// Video removing
if((call->videostream != NULL) && !params->has_video) {
#ifdef BUILD_UPNP
if(call->upnp_session != NULL) {
if (linphone_core_update_upnp(lc, call)<0) {
/* uPnP port mappings failed, proceed with the call anyway. */
linphone_call_delete_upnp_session(call);
}
}
#endif //BUILD_UPNP
}
#endif /* VIDEO_ENABLED */
#endif /* defined(VIDEO_ENABLED) && defined(BUILD_UPNP) */
_linphone_call_params_copy(&call->params,params);
err=linphone_call_prepare_ice(call,FALSE);
@ -3178,10 +3200,9 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho
return 0;
}
#ifdef VIDEO_ENABLED
#if defined(VIDEO_ENABLED) && defined(BUILD_UPNP)
// Video adding
if (!has_video && call->params.has_video) {
#ifdef BUILD_UPNP
if(call->upnp_session != NULL) {
ms_message("Defer call update to add uPnP port mappings");
video_stream_prepare_video(call->videostream);
@ -3192,9 +3213,8 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho
return err;
}
}
#endif //BUILD_UPNP
}
#endif //VIDEO_ENABLED
#endif //defined(VIDEO_ENABLED) && defined(BUILD_UPNP)
err = linphone_core_start_update_call(lc, call);
}else{
#ifdef VIDEO_ENABLED
@ -3251,7 +3271,6 @@ int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call)
linphone_core_update_streams (lc,call,md);
linphone_call_fix_call_parameters(call);
}
if (call->state != LinphoneCallOutgoingEarlyMedia) /*don't change the state in case of outgoing early (SIP UPDATE)*/
linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)");
return 0;
@ -3422,7 +3441,10 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call,
_linphone_call_params_copy(&call->params,params);
// There might not be a md if the INVITE was lacking an SDP
// In this case we use the parameters as is.
if (md) call->params.has_video &= linphone_core_media_description_contains_video_stream(md);
if (md) {
linphone_call_set_compatible_incoming_call_parameters(call, md);
}
linphone_call_prepare_ice(call,TRUE);
linphone_call_make_local_media_description(lc,call);
sal_call_set_local_media_description(call->op,call->localdesc);
sal_op_set_sent_custom_header(call->op,params->custom_headers);
@ -5603,6 +5625,7 @@ void linphone_core_set_rtp_transport_factories(LinphoneCore* lc, LinphoneRtpTran
/**
* Retrieve RTP statistics regarding current call.
* @param lc the LinphoneCore
* @param local RTP statistics computed locally.
* @param remote RTP statistics computed by far end (obtained via RTCP feedback).
*
@ -5664,7 +5687,7 @@ void sip_config_uninit(LinphoneCore *lc)
if (lc->network_reachable) {
for(elem=config->proxies;elem!=NULL;elem=ms_list_next(elem)){
LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)(elem->data);
linphone_proxy_config_edit(cfg); /* to unregister */
_linphone_proxy_config_unregister(cfg); /* to unregister without changing the stored flag enable_register */
}
ms_message("Unregistration started.");
@ -5738,6 +5761,7 @@ void rtp_config_uninit(LinphoneCore *lc)
lp_config_set_int(lc->config,"rtp","nortp_timeout",config->nortp_timeout);
lp_config_set_int(lc->config,"rtp","audio_adaptive_jitt_comp_enabled",config->audio_adaptive_jitt_comp_enabled);
lp_config_set_int(lc->config,"rtp","video_adaptive_jitt_comp_enabled",config->video_adaptive_jitt_comp_enabled);
ms_free(config->srtp_suites);
}
static void sound_config_uninit(LinphoneCore *lc)
@ -5880,6 +5904,15 @@ static void linphone_core_uninit(LinphoneCore *lc)
}
#endif //BUILD_UPNP
if (lc->chatrooms){
MSList *cr=ms_list_copy(lc->chatrooms);
MSList *elem;
for(elem=cr;elem!=NULL;elem=elem->next){
linphone_chat_room_destroy((LinphoneChatRoom*)elem->data);
}
ms_list_free(cr);
}
if (lp_config_needs_commit(lc->config)) lp_config_sync(lc->config);
lp_config_destroy(lc->config);
lc->config = NULL; /* Mark the config as NULL to block further calls */
@ -5891,6 +5924,8 @@ static void linphone_core_uninit(LinphoneCore *lc)
lc->last_recv_msg_ids=ms_list_free(lc->last_recv_msg_ids);
// Free struct variable
ms_free(lc->file_transfer_server);
if(lc->zrtp_secrets_cache != NULL) {
ms_free(lc->zrtp_secrets_cache);
}
@ -5904,7 +5939,7 @@ static void linphone_core_uninit(LinphoneCore *lc)
linphone_presence_model_unref(lc->presence_model);
}
linphone_core_free_payload_types(lc);
if (lc->supported_formats) ms_free(lc->supported_formats);
linphone_core_message_storage_close(lc);
ms_exit();
linphone_core_set_state(lc,LinphoneGlobalOff,"Off");
@ -6428,6 +6463,7 @@ void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *para
params->media_encryption=linphone_core_get_media_encryption(lc);
params->in_conference=FALSE;
params->privacy=LinphonePrivacyDefault;
params->avpf_enabled=FALSE;
}
void linphone_core_set_device_identifier(LinphoneCore *lc,const char* device_id) {
@ -6536,3 +6572,6 @@ bool_t linphone_core_sdp_200_ack_enabled(const LinphoneCore *lc) {
return lc->sip_conf.sdp_200_ack!=0;
}
void linphone_core_set_file_transfer_server(LinphoneCore *core, const char * server_url) {
core->file_transfer_server=ms_strdup(server_url);
}

View file

@ -120,7 +120,6 @@ typedef enum _LinphoneTransportType LinphoneTransportType;
* return NULL.
*
* @ingroup linphone_address
* @var LinphoneAddress
*/
typedef struct SalAddress LinphoneAddress;
@ -133,9 +132,11 @@ typedef struct belle_sip_dict LinphoneDictionary;
struct _LinphoneContent{
char *type; /**<mime type for the data, for example "application"*/
char *subtype; /**<mime subtype for the data, for example "html"*/
void *data; /**<the actual data buffer, usually a string */
size_t size; /**<the size of the data buffer, excluding null character despite null character is always set for convenience.*/
void *data; /**<the actual data buffer, usually a string. Null when provided by callbacks #LinphoneCoreFileTransferSendCb or #LinphoneCoreFileTransferRecvCb*/
size_t size; /**<the size of the data buffer, excluding null character despite null character is always set for convenience.
When provided by callback #LinphoneCoreFileTransferSendCb or #LinphoneCoreFileTransferRecvCb, it states the total number of bytes of the transfered file*/
char *encoding; /**<The encoding of the data buffer, for example "gzip"*/
char *name; /**< used by RCS File transfer messages to store the original filename of the file to be downloaded from server */
};
/**
@ -387,7 +388,8 @@ LINPHONE_PUBLIC LinphoneMediaEncryption linphone_call_params_get_media_encryptio
LINPHONE_PUBLIC void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, LinphoneMediaEncryption e);
LINPHONE_PUBLIC void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, bool_t enabled);
LINPHONE_PUBLIC bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp);
LINPHONE_PUBLIC bool_t linphone_call_params_local_conference_mode(const LinphoneCallParams *cp);
#define linphone_call_params_local_conference_mode linphone_call_params_get_local_conference_mode /* Deprecated */
LINPHONE_PUBLIC bool_t linphone_call_params_get_local_conference_mode(const LinphoneCallParams *cp);
LINPHONE_PUBLIC void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int bw);
LINPHONE_PUBLIC void linphone_call_params_destroy(LinphoneCallParams *cp);
LINPHONE_PUBLIC bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp);
@ -429,6 +431,13 @@ LINPHONE_PUBLIC MSVideoSize linphone_call_params_get_sent_video_size(const Linph
*/
LINPHONE_PUBLIC MSVideoSize linphone_call_params_get_received_video_size(const LinphoneCallParams *cp);
/**
* Gets the RTP profile being used.
* @param[in] cp #LinphoneCallParams object
* @returns The RTP profile.
*/
LINPHONE_PUBLIC const char * linphone_call_params_get_rtp_profile(const LinphoneCallParams *cp);
/*
* Note for developers: this enum must be kept synchronized with the SalPrivacy enum declared in sal.h
@ -585,7 +594,7 @@ typedef enum _LinphoneUpnpState LinphoneUpnpState;
/**
* The LinphoneCallStats objects carries various statistic informations regarding quality of audio or video streams.
*
* To receive these informations periodically and as soon as they are computed, the application is invited to place a #CallStatsUpdated callback in the LinphoneCoreVTable structure
* To receive these informations periodically and as soon as they are computed, the application is invited to place a #LinphoneCoreCallStatsUpdatedCb callback in the LinphoneCoreVTable structure
* it passes for instanciating the LinphoneCore object (see linphone_core_new() ).
*
* At any time, the application can access last computed statistics using linphone_call_get_audio_stats() or linphone_call_get_video_stats().
@ -595,7 +604,7 @@ typedef struct _LinphoneCallStats LinphoneCallStats;
/**
* The LinphoneCallStats objects carries various statistic informations regarding quality of audio or video streams.
*
* To receive these informations periodically and as soon as they are computed, the application is invited to place a #CallStatsUpdated callback in the LinphoneCoreVTable structure
* To receive these informations periodically and as soon as they are computed, the application is invited to place a #LinphoneCoreCallStatsUpdatedCb callback in the LinphoneCoreVTable structure
* it passes for instanciating the LinphoneCore object (see linphone_core_new() ).
*
* At any time, the application can access last computed statistics using linphone_call_get_audio_stats() or linphone_call_get_video_stats().
@ -812,7 +821,7 @@ LINPHONE_PUBLIC void linphone_proxy_config_enable_publish(LinphoneProxyConfig *o
/**
* Set the publish expiration time in second.
* @param obj proxy config
* @param exires in second
* @param expires in second
* */
LINPHONE_PUBLIC void linphone_proxy_config_set_publish_expires(LinphoneProxyConfig *obj, int expires);
@ -827,16 +836,54 @@ LINPHONE_PUBLIC int linphone_proxy_config_get_publish_expires(const LinphoneProx
LINPHONE_PUBLIC void linphone_proxy_config_set_dial_escape_plus(LinphoneProxyConfig *cfg, bool_t val);
LINPHONE_PUBLIC void linphone_proxy_config_set_dial_prefix(LinphoneProxyConfig *cfg, const char *prefix);
/**
* Indicates either or not, quality statistics during call should be stored and sent to a collector at termination.
* @param cfg #LinphoneProxyConfig object
* @param val if true, quality statistics publish will be stored and sent to the collector
*
/**
* Indicates whether quality statistics during call should be stored and sent to a collector according to RFC 6035.
* @param[in] cfg #LinphoneProxyConfig object
* @param[in] enable True to sotre quality statistics and sent them to the collector, false to disable it.
*/
LINPHONE_PUBLIC void linphone_proxy_config_enable_statistics(LinphoneProxyConfig *cfg, bool_t val);
LINPHONE_PUBLIC bool_t linphone_proxy_config_send_statistics_enabled(LinphoneProxyConfig *cfg);
LINPHONE_PUBLIC void linphone_proxy_config_set_statistics_collector(LinphoneProxyConfig *cfg, const char *collector);
LINPHONE_PUBLIC const char *linphone_proxy_config_get_statistics_collector(const LinphoneProxyConfig *obj);
LINPHONE_PUBLIC void linphone_proxy_config_enable_quality_reporting(LinphoneProxyConfig *cfg, bool_t enable);
/**
* Indicates whether quality statistics during call should be stored and sent to a collector according to RFC 6035.
* @param[in] cfg #LinphoneProxyConfig object
* @return True if quality repotring is enabled, false otherwise.
*/
LINPHONE_PUBLIC bool_t linphone_proxy_config_quality_reporting_enabled(LinphoneProxyConfig *cfg);
/**
* Set the SIP address of the collector end-point when using quality reporting. This SIP address
* should be used on server-side to process packets directly then discard packets. Collector address
* should be a non existing account and should not received any packets.
* @param[in] cfg #LinphoneProxyConfig object
* @param[in] collector SIP address of the collector end-point.
*/
LINPHONE_PUBLIC void linphone_proxy_config_set_quality_reporting_collector(LinphoneProxyConfig *cfg, const char *collector);
/**
* Get the SIP address of the collector end-point when using quality reporting. This SIP address
* should be used on server-side to process packets directly then discard packets. Collector address
* should be a non existing account and should not received any packets.
* @param[in] cfg #LinphoneProxyConfig object
* @return The SIP address of the collector end-point.
*/
LINPHONE_PUBLIC const char *linphone_proxy_config_get_quality_reporting_collector(const LinphoneProxyConfig *cfg);
/**
* Set the interval between 2 interval reports sending when using quality reporting. If call exceed interval size, an
* interval report will be sent to the collector. On call termination, a session report will be sent
* for the remaining period. Value must be 0 (disabled) or positive.
* @param[in] cfg #LinphoneProxyConfig object
* @param[in] interval The interval in seconds, 0 means interval reports are disabled.
*/
LINPHONE_PUBLIC void linphone_proxy_config_set_quality_reporting_interval(LinphoneProxyConfig *cfg, uint8_t interval);
/**
* Get the interval between interval reports when using quality reporting.
* @param[in] cfg #LinphoneProxyConfig object
* @return The interval in seconds, 0 means interval reports are disabled.
*/
LINPHONE_PUBLIC int linphone_proxy_config_get_quality_reporting_interval(LinphoneProxyConfig *cfg);
/**
* Get the registration state of the given proxy config.
@ -857,10 +904,12 @@ LINPHONE_PUBLIC const char *linphone_proxy_config_get_domain(const LinphoneProxy
LINPHONE_PUBLIC const char *linphone_proxy_config_get_route(const LinphoneProxyConfig *obj);
LINPHONE_PUBLIC const char *linphone_proxy_config_get_identity(const LinphoneProxyConfig *obj);
LINPHONE_PUBLIC bool_t linphone_proxy_config_publish_enabled(const LinphoneProxyConfig *obj);
LINPHONE_PUBLIC const char *linphone_proxy_config_get_addr(const LinphoneProxyConfig *obj);
LINPHONE_PUBLIC const char *linphone_proxy_config_get_server_addr(const LinphoneProxyConfig *obj);
#define linphone_proxy_config_get_addr linphone_proxy_config_get_server_addr
LINPHONE_PUBLIC int linphone_proxy_config_get_expires(const LinphoneProxyConfig *obj);
LINPHONE_PUBLIC bool_t linphone_proxy_config_register_enabled(const LinphoneProxyConfig *obj);
LINPHONE_PUBLIC void linphone_proxy_config_refresh_register(LinphoneProxyConfig *obj);
LINPHONE_PUBLIC void linphone_proxy_config_pause_register(LinphoneProxyConfig *obj);
LINPHONE_PUBLIC const char *linphone_proxy_config_get_contact_parameters(const LinphoneProxyConfig *obj);
LINPHONE_PUBLIC void linphone_proxy_config_set_contact_parameters(LinphoneProxyConfig *obj, const char *contact_params);
LINPHONE_PUBLIC void linphone_proxy_config_set_contact_uri_parameters(LinphoneProxyConfig *obj, const char *contact_uri_params);
@ -918,16 +967,56 @@ LINPHONE_PUBLIC void * linphone_proxy_config_get_user_data(LinphoneProxyConfig *
/**
* Set default privacy policy for all calls routed through this proxy.
* @param params to be modified
* @param LinphonePrivacy to configure privacy
* @param cfg #LinphoneProxyConfig object to be modified
* @param privacy LinphonePrivacy to configure privacy
* */
LINPHONE_PUBLIC void linphone_proxy_config_set_privacy(LinphoneProxyConfig *params, LinphonePrivacyMask privacy);
LINPHONE_PUBLIC void linphone_proxy_config_set_privacy(LinphoneProxyConfig *cfg, LinphonePrivacyMask privacy);
/**
* Get default privacy policy for all calls routed through this proxy.
* @param params object
* @param cfg #LinphoneProxyConfig object
* @return Privacy mode
* */
LINPHONE_PUBLIC LinphonePrivacyMask linphone_proxy_config_get_privacy(const LinphoneProxyConfig *params);
LINPHONE_PUBLIC LinphonePrivacyMask linphone_proxy_config_get_privacy(const LinphoneProxyConfig *cfg);
/**
* Set the http file transfer server to be used for content type application/vnd.gsma.rcs-ft-http+xml
* @param cfg #LinphoneProxyConfig object to be modified
* @param server_url URL of the file server like https://file.linphone.org/upload.php
* */
LINPHONE_PUBLIC void linphone_proxy_config_set_file_transfer_server(LinphoneProxyConfig *cfg, const char * server_url);
/**
* Get the http file transfer server to be used for content type application/vnd.gsma.rcs-ft-http+xml
* @param cfg #LinphoneProxyConfig object
* @return URL of the file server like https://file.linphone.org/upload.php
* */
LINPHONE_PUBLIC const char* linphone_proxy_config_get_file_transfer_server(const LinphoneProxyConfig *cfg);
/**
* Indicates whether AVPF/SAVPF must be used for calls using this proxy config.
* @param[in] cfg #LinphoneProxyConfig object
* @param[in] enable True to enable AVPF/SAVF, false to disable it.
*/
LINPHONE_PUBLIC void linphone_proxy_config_enable_avpf(LinphoneProxyConfig *cfg, bool_t enable);
/**
* Indicates whether AVPF/SAVPF is being used for calls using this proxy config.
* @param[in] cfg #LinphoneProxyConfig object
* @return True if AVPF/SAVPF is enabled, false otherwise.
*/
LINPHONE_PUBLIC bool_t linphone_proxy_config_avpf_enabled(LinphoneProxyConfig *cfg);
/**
* Set the interval between regular RTCP reports when using AVPF/SAVPF.
* @param[in] cfg #LinphoneProxyConfig object
* @param[in] interval The interval in seconds (between 0 and 5 seconds).
*/
LINPHONE_PUBLIC void linphone_proxy_config_set_avpf_rr_interval(LinphoneProxyConfig *cfg, uint8_t interval);
/**
* Get the interval between regular RTCP reports when using AVPF/SAVPF.
* @param[in] cfg #LinphoneProxyConfig object
* @return The interval in seconds.
*/
LINPHONE_PUBLIC uint8_t linphone_proxy_config_get_avpf_rr_interval(const LinphoneProxyConfig *cfg);
/**
* @}
@ -1061,6 +1150,15 @@ LINPHONE_PUBLIC bool_t linphone_core_chat_enabled(const LinphoneCore *lc);
LINPHONE_PUBLIC void linphone_chat_room_destroy(LinphoneChatRoom *cr);
LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_message(LinphoneChatRoom *cr,const char* message);
LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_message_2(LinphoneChatRoom *cr, const char* message, const char* external_body_url, LinphoneChatMessageState state, time_t time, bool_t is_read, bool_t is_incoming);
/**
* Create a message attached to a dedicated chat room with a particular content. Use #linphone_chat_room_file_transfer_send to initiate the transfer
* @param[in] cr the chat room.
* @param[in] initial_content #LinphoneContent initial content. #LinphoneCoreVTable.file_transfer_send is invoked later to notify file transfer progress and collect next chunk of the message if #LinphoneContentSourceType.src_type is set to LINPHONE_CONTENT_SOURCE_CHUNKED_BUFFER.
* @return a new #LinphoneChatMessage
*/
LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_file_transfer_message(LinphoneChatRoom *cr, LinphoneContent* initial_content);
LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_room_get_peer_address(LinphoneChatRoom *cr);
LINPHONE_PUBLIC void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg);
LINPHONE_PUBLIC void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* msg,LinphoneChatMessageStateChangedCb status_cb,void* ud);
@ -1085,6 +1183,7 @@ LINPHONE_PUBLIC bool_t linphone_chat_room_is_remote_composing(const LinphoneChat
LINPHONE_PUBLIC int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr);
LINPHONE_PUBLIC LinphoneCore* linphone_chat_room_get_lc(LinphoneChatRoom *cr);
LINPHONE_PUBLIC LinphoneCore* linphone_chat_room_get_core(LinphoneChatRoom *cr);
LINPHONE_PUBLIC void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void * ud);
LINPHONE_PUBLIC void * linphone_chat_room_get_user_data(LinphoneChatRoom *cr);
LINPHONE_PUBLIC MSList* linphone_core_get_chat_rooms(LinphoneCore *lc);
@ -1102,7 +1201,11 @@ LINPHONE_PUBLIC void linphone_chat_message_set_to(LinphoneChatMessage* message,
LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_to(const LinphoneChatMessage* message);
LINPHONE_PUBLIC const char* linphone_chat_message_get_external_body_url(const LinphoneChatMessage* message);
LINPHONE_PUBLIC void linphone_chat_message_set_external_body_url(LinphoneChatMessage* message,const char* url);
LINPHONE_PUBLIC const char * linphone_chat_message_get_text(const LinphoneChatMessage* message);
LINPHONE_PUBLIC const LinphoneContent* linphone_chat_message_get_file_transfer_information(const LinphoneChatMessage* message);
LINPHONE_PUBLIC void linphone_chat_message_start_file_download(const LinphoneChatMessage*message);
LINPHONE_PUBLIC const char* linphone_chat_message_get_appdata(const LinphoneChatMessage* message);
LINPHONE_PUBLIC void linphone_chat_message_set_appdata(LinphoneChatMessage* message, const char* data);
LINPHONE_PUBLIC const char* linphone_chat_message_get_text(const LinphoneChatMessage* message);
LINPHONE_PUBLIC time_t linphone_chat_message_get_time(const LinphoneChatMessage* message);
LINPHONE_PUBLIC void* linphone_chat_message_get_user_data(const LinphoneChatMessage* message);
LINPHONE_PUBLIC void linphone_chat_message_set_user_data(LinphoneChatMessage* message,void*);
@ -1223,7 +1326,7 @@ typedef void (*LinphoneCoreCallLogUpdatedCb)(LinphoneCore *lc, LinphoneCallLog *
/**
* Callback prototype
* @deprecated use #LinphoneMessageReceived instead.
* @deprecated use #LinphoneCoreMessageReceivedCb instead.
*
* @param lc #LinphoneCore object
* @param room #LinphoneChatRoom involved in this conversation. Can be be created by the framework in case \link #LinphoneAddress the from \endlink is not present in any chat room.
@ -1241,6 +1344,43 @@ typedef void (*LinphoneCoreTextMessageReceivedCb)(LinphoneCore *lc, LinphoneChat
*/
typedef void (*LinphoneCoreMessageReceivedCb)(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *message);
/**
* File transfer receive callback prototype. This function is called by the core upon an incoming File transfer is started. This function may be call several time for the same file in case of large file.
*
*
* @param lc #LinphoneCore object
* @param message #LinphoneChatMessage message from which the body is received.
* @param content #LinphoneContent incoming content information
* @param buff pointer to the received data
* @param size number of bytes to be read from buff. 0 means end of file.
*
*/
typedef void (*LinphoneCoreFileTransferRecvCb)(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, const char* buff, size_t size);
/**
* File transfer send callback prototype. This function is called by the core upon an outgoing File transfer is started. This function is called until size is set to 0.
* <br> a #LinphoneContent with a size equal zero
*
* @param lc #LinphoneCore object
* @param message #LinphoneChatMessage message from which the body is received.
* @param content #LinphoneContent outgoing content
* @param buff pointer to the buffer where data chunk shall be written by the app
* @param size as input value, it represents the number of bytes expected by the framework. As output value, it means the number of bytes wrote by the application in the buffer. 0 means end of file.
*
*/
typedef void (*LinphoneCoreFileTransferSendCb)(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, char* buff, size_t* size);
/**
* File transfer progress indication callback prototype.
*
* @param lc #LinphoneCore object
* @param message #LinphoneChatMessage message from which the body is received.
* @param content #LinphoneContent incoming content information
* @param progress number of bytes sent/received from the begening of the transfer.
*
*/
typedef void (*LinphoneCoreFileTransferProgressIndicationCb)(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, size_t progress);
/**
* Is composing notification callback prototype.
*
@ -1314,7 +1454,7 @@ typedef struct _LinphoneCoreVTable{
LinphoneCoreNewSubscriptionRequestedCb new_subscription_requested; /**< Notify about pending presence subscription request */
LinphoneCoreAuthInfoRequestedCb auth_info_requested; /**< Ask the application some authentication information */
LinphoneCoreCallLogUpdatedCb call_log_updated; /**< Notifies that call log list has been updated */
LinphoneCoreMessageReceivedCb message_received; /** a message is received, can be text or external body*/
LinphoneCoreMessageReceivedCb message_received; /**< a message is received, can be text or external body*/
LinphoneCoreIsComposingReceivedCb is_composing_received; /**< An is-composing notification has been received */
LinphoneCoreDtmfReceivedCb dtmf_received; /**< A dtmf has been received received */
LinphoneCoreReferReceivedCb refer_received; /**< An out of call refer was received */
@ -1333,6 +1473,9 @@ typedef struct _LinphoneCoreVTable{
DisplayUrlCb display_url; /**< @deprecated */
ShowInterfaceCb show; /**< @deprecated Notifies the application that it should show up*/
LinphoneCoreTextMessageReceivedCb text_received; /** @deprecated, use #message_received instead <br> A text message has been received */
LinphoneCoreFileTransferRecvCb file_transfer_received; /** Callback to store file received attached to a #LinphoneChatMessage */
LinphoneCoreFileTransferSendCb file_transfer_send; /** Callback to collect file chunk to be sent for a #LinphoneChatMessage */
LinphoneCoreFileTransferProgressIndicationCb file_transfer_progress_indication; /**Callback to indicate file transfer progress*/
} LinphoneCoreVTable;
/**
@ -1401,7 +1544,14 @@ LINPHONE_PUBLIC void linphone_core_enable_logs(FILE *file);
LINPHONE_PUBLIC void linphone_core_enable_logs_with_cb(OrtpLogFunc logfunc);
LINPHONE_PUBLIC void linphone_core_disable_logs(void);
LINPHONE_PUBLIC const char *linphone_core_get_version(void);
LINPHONE_PUBLIC const char *linphone_core_get_user_agent(LinphoneCore *lc);
/**
* @deprecated Use #linphone_core_get_user_agent instead.
**/
LINPHONE_PUBLIC const char *linphone_core_get_user_agent_name(void);
/**
* @deprecated Use #linphone_core_get_user_agent instead.
**/
LINPHONE_PUBLIC const char *linphone_core_get_user_agent_version(void);
LINPHONE_PUBLIC LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable,
@ -1506,7 +1656,7 @@ LINPHONE_PUBLIC int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneC
/**
* @ingroup media_parameters
* Get default call parameters reflecting current linphone core configuration
* @param LinphoneCore object
* @param lc LinphoneCore object
* @return LinphoneCallParams
*/
LINPHONE_PUBLIC LinphoneCallParams *linphone_core_create_default_call_parameters(LinphoneCore *lc);
@ -1594,7 +1744,7 @@ LINPHONE_PUBLIC bool_t linphone_core_payload_type_is_vbr(LinphoneCore *lc, const
* @param[in] lc the #LinphoneCore object
* @param[in] pt the #PayloadType to modify.
* @param[in] bitrate the IP bitrate in kbit/s.
* @ingroup media_parameters
* @ingroup media_parameters
**/
LINPHONE_PUBLIC void linphone_core_set_payload_type_bitrate(LinphoneCore *lc, PayloadType *pt, int bitrate);
@ -1603,7 +1753,7 @@ LINPHONE_PUBLIC void linphone_core_set_payload_type_bitrate(LinphoneCore *lc, Pa
* @param[in] lc the #LinphoneCore object
* @param[in] pt the #PayloadType to modify.
* @return bitrate the IP bitrate in kbit/s, or -1 if an error occured.
* @ingroup media_parameters
* @ingroup media_parameters
**/
LINPHONE_PUBLIC int linphone_core_get_payload_type_bitrate(LinphoneCore *lc, const PayloadType *pt);
@ -1675,6 +1825,7 @@ LINPHONE_PUBLIC int linphone_core_get_default_proxy(LinphoneCore *lc, LinphonePr
* @param[in] passwd String containing the password of the authentication credentials (optional, either passwd or ha1 must be set)
* @param[in] ha1 String containing a ha1 hash of the password (optional, either passwd or ha1 must be set)
* @param[in] realm String used to discriminate different SIP authentication domains (optional)
* @param[in] domain String containing the SIP domain for which this authentication information is valid, if it has to be restricted for a single SIP domain.
* @return #LinphoneAuthInfo with default values set
* @ingroup authentication
*/
@ -1948,7 +2099,7 @@ LINPHONE_PUBLIC void linphone_core_mute_mic(LinphoneCore *lc, bool_t muted);
/**
* Get mic state.
* @deprecated Use #linphone_core_is_mic_enabled instead
* @deprecated Use #linphone_core_mic_enabled instead
**/
LINPHONE_PUBLIC bool_t linphone_core_is_mic_muted(LinphoneCore *lc);
@ -2168,7 +2319,7 @@ LINPHONE_PUBLIC int linphone_core_get_camera_sensor_rotation(LinphoneCore *lc);
void linphone_core_show_video(LinphoneCore *lc, bool_t show);
/*play/record support: use files instead of soundcard*/
void linphone_core_use_files(LinphoneCore *lc, bool_t yesno);
LINPHONE_PUBLIC void linphone_core_use_files(LinphoneCore *lc, bool_t yesno);
LINPHONE_PUBLIC void linphone_core_set_play_file(LinphoneCore *lc, const char *file);
LINPHONE_PUBLIC void linphone_core_set_record_file(LinphoneCore *lc, const char *file);
@ -2356,7 +2507,12 @@ LINPHONE_PUBLIC void linphone_core_init_default_params(LinphoneCore*lc, Linphone
*/
LINPHONE_PUBLIC bool_t linphone_core_tunnel_available(void);
/**
* Linphone tunnel object.
* @ingroup tunnel
*/
typedef struct _LinphoneTunnel LinphoneTunnel;
/**
* get tunnel instance if available
*/
@ -2452,6 +2608,22 @@ typedef enum _LinphoneToneID LinphoneToneID;
LINPHONE_PUBLIC void linphone_core_set_call_error_tone(LinphoneCore *lc, LinphoneReason reason, const char *audiofile);
LINPHONE_PUBLIC void linphone_core_set_tone(LinphoneCore *lc, LinphoneToneID id, const char *audiofile);
/**
* Globaly set an http file transfer server to be used for content type application/vnd.gsma.rcs-ft-http+xml. This value can also be set for a dedicated account using #linphone_proxy_config_set_file_transfer_server
* @param[in] core #LinphoneCore to be modified
* @param[in] server_url URL of the file server like https://file.linphone.org/upload.php
* */
LINPHONE_PUBLIC void linphone_core_set_file_transfer_server(LinphoneCore *core, const char * server_url);
/**
* Returns a null terminated table of strings containing the file format extension supported for call recording.
* @param core the core
* @return the supported formats, typically 'wav' and 'mkv'
* @ingroup media_parameters
**/
LINPHONE_PUBLIC const char ** linphone_core_get_supported_file_formats(LinphoneCore *core);
#ifdef __cplusplus
}
#endif

View file

@ -52,8 +52,8 @@ extern "C" void libmssilk_init();
#ifdef HAVE_G729
extern "C" void libmsbcg729_init();
#endif
#ifdef HAVE_ISAC
extern "C" void libmsisac_init();
#ifdef HAVE_WEBRTC
extern "C" void libmswebrtc_init();
#endif
#endif /*ANDROID*/
@ -121,7 +121,13 @@ static void linphone_android_ortp_log_handler(OrtpLogLevel lev, const char *fmt,
}
if (handler_obj){
JNIEnv *env=ms_get_jni_env();
env->CallVoidMethod(handler_obj,loghandler_id,env->NewStringUTF(LogDomain),(jint)lev,env->NewStringUTF(levname),env->NewStringUTF(str),NULL);
jstring jdomain=env->NewStringUTF(LogDomain);
jstring jlevname=env->NewStringUTF(levname);
jstring jstr=env->NewStringUTF(str);
env->CallVoidMethod(handler_obj,loghandler_id,jdomain,(jint)lev,jlevname,jstr,NULL);
if (jdomain) env->DeleteLocalRef(jdomain);
if (jlevname) env->DeleteLocalRef(jlevname);
if (jstr) env->DeleteLocalRef(jstr);
}else
linphone_android_log_handler(prio, str);
}
@ -781,8 +787,8 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_newLinphoneCore(JNIEnv*
#ifdef HAVE_G729
libmsbcg729_init();
#endif
#ifdef HAVE_ISAC
libmsisac_init();
#ifdef HAVE_WEBRTC
libmswebrtc_init();
#endif
jlong nativePtr = (jlong)linphone_core_new( &ldata->vTable
@ -2624,6 +2630,15 @@ static void chat_room_impl_callback(LinphoneChatMessage* msg, LinphoneChatMessag
linphone_chat_message_set_user_data(msg,NULL);
}
}
extern "C" jobject Java_org_linphone_core_LinphoneChatRoomImpl_getCore(JNIEnv* env
,jobject thiz
,jlong chatroom_ptr){
LinphoneCore *lc=linphone_chat_room_get_core((LinphoneChatRoom*)chatroom_ptr);
LinphoneCoreData *lcd=(LinphoneCoreData*)linphone_core_get_user_data(lc);
return lcd->core;
}
extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_sendMessage2(JNIEnv* env
,jobject thiz
,jlong chatroom_ptr
@ -2774,7 +2789,7 @@ extern "C" jboolean Java_org_linphone_core_LinphoneCallParamsImpl_getVideoEnable
}
extern "C" jboolean Java_org_linphone_core_LinphoneCallParamsImpl_localConferenceMode(JNIEnv *env, jobject thiz, jlong lcp){
return (jboolean)linphone_call_params_local_conference_mode((LinphoneCallParams*)lcp);
return (jboolean)linphone_call_params_get_local_conference_mode((LinphoneCallParams*)lcp);
}
extern "C" jstring Java_org_linphone_core_LinphoneCallParamsImpl_getCustomHeader(JNIEnv *env, jobject thiz, jlong lcp, jstring jheader_name){
@ -2938,6 +2953,22 @@ extern "C" jint Java_org_linphone_core_LinphoneProxyConfigImpl_getPrivacy(JNIEnv
return linphone_proxy_config_get_privacy((LinphoneProxyConfig *) ptr);
}
JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneProxyConfigImpl_enableAvpf(JNIEnv *env, jobject thiz, jlong ptr, jboolean enable) {
linphone_proxy_config_enable_avpf((LinphoneProxyConfig *)ptr, (bool)enable);
}
JNIEXPORT jboolean JNICALL Java_org_linphone_core_LinphoneProxyConfigImpl_avpfEnabled(JNIEnv *env, jobject thiz, jlong ptr) {
return linphone_proxy_config_avpf_enabled((LinphoneProxyConfig *)ptr);
}
JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneProxyConfigImpl_setAvpfRRInterval(JNIEnv *env, jobject thiz, jlong ptr, jint interval) {
linphone_proxy_config_set_avpf_rr_interval((LinphoneProxyConfig *)ptr, (uint8_t)interval);
}
JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneProxyConfigImpl_getAvpfRRInterval(JNIEnv *env, jobject thiz, jlong ptr) {
return (jint)linphone_proxy_config_get_avpf_rr_interval((LinphoneProxyConfig *)ptr);
}
extern "C" jint Java_org_linphone_core_LinphoneCallImpl_getDuration(JNIEnv* env,jobject thiz,jlong ptr) {
return (jint)linphone_call_get_duration((LinphoneCall *) ptr);
}
@ -3647,6 +3678,12 @@ JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneCoreFactoryImpl__1setLogHa
}
}
JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneEventImpl_getCore(JNIEnv *env, jobject jobj, jlong evptr){
LinphoneCore *lc=linphone_event_get_core((LinphoneEvent*)evptr);
LinphoneCoreData *lcd=(LinphoneCoreData*)linphone_core_get_user_data(lc);
return lcd->core;
}
/*
* Class: org_linphone_core_LinphoneEventImpl
* Method: getEventName

View file

@ -426,7 +426,7 @@ LINPHONE_PUBLIC int linphone_presence_model_clear_persons(LinphonePresenceModel
*
* The created presence service has the basic status 'closed'.
*/
LINPHONE_PUBLIC LinphonePresenceService * linphone_presence_service_new(const char *id, LinphonePresenceBasicStatus, const char *contact);
LINPHONE_PUBLIC LinphonePresenceService * linphone_presence_service_new(const char *id, LinphonePresenceBasicStatus basic_status, const char *contact);
/**
* Gets the id of a presence service.

View file

@ -49,6 +49,7 @@
typedef struct _LpItem{
char *key;
char *value;
int is_comment;
} LpItem;
typedef struct _LpSectionParam{
@ -78,6 +79,13 @@ LpItem * lp_item_new(const char *key, const char *value){
return item;
}
LpItem * lp_comment_new(const char *comment){
LpItem *item=lp_new0(LpItem,1);
item->value=ortp_strdup(comment);
item->is_comment=TRUE;
return item;
}
LpSectionParam *lp_section_param_new(const char *key, const char *value){
LpSectionParam *param = lp_new0(LpSectionParam, 1);
param->key = ortp_strdup(key);
@ -93,7 +101,7 @@ LpSection *lp_section_new(const char *name){
void lp_item_destroy(void *pitem){
LpItem *item=(LpItem*)pitem;
ortp_free(item->key);
if (item->key) ortp_free(item->key);
ortp_free(item->value);
free(item);
}
@ -138,6 +146,14 @@ static bool_t is_first_char(const char *start, const char *pos){
return TRUE;
}
static int is_a_comment(const char *str){
while (*str==' '){
str++;
}
if (*str=='#') return 1;
return 0;
}
LpSection *lp_config_find_section(const LpConfig *lpconfig, const char *name){
LpSection *sec;
MSList *elem;
@ -170,7 +186,7 @@ LpItem *lp_section_find_item(const LpSection *sec, const char *name){
/*printf("Looking for item %s\n",name);*/
for (elem=sec->items;elem!=NULL;elem=ms_list_next(elem)){
item=(LpItem*)elem->data;
if (strcmp(item->key,name)==0) {
if (!item->is_comment && strcmp(item->key,name)==0) {
/*printf("Item %s found\n",name);*/
return item;
}
@ -182,9 +198,10 @@ static LpSection* lp_config_parse_line(LpConfig* lpconfig, const char* line, LpS
LpSectionParam *params = NULL;
char *pos1,*pos2;
int nbs;
static char secname[MAX_LEN];
static char key[MAX_LEN];
static char value[MAX_LEN];
int size=strlen(line)+1;
char *secname=ms_malloc(size);
char *key=ms_malloc(size);
char *value=ms_malloc(size);
LpItem *item;
pos1=strchr(line,'[');
@ -230,43 +247,53 @@ static LpSection* lp_config_parse_line(LpConfig* lpconfig, const char* line, LpS
}
}
}else {
pos1=strchr(line,'=');
if (pos1!=NULL){
key[0]='\0';
if (is_a_comment(line)){
if (cur){
LpItem *comment=lp_comment_new(line);
lp_section_add_item(cur,comment);
}
}else{
pos1=strchr(line,'=');
if (pos1!=NULL){
key[0]='\0';
*pos1='\0';
if (sscanf(line,"%s",key)>0){
*pos1='\0';
if (sscanf(line,"%s",key)>0){
pos1++;
pos2=strchr(pos1,'\r');
if (pos2==NULL)
pos2=strchr(pos1,'\n');
if (pos2==NULL) pos2=pos1+strlen(pos1);
else {
*pos2='\0'; /*replace the '\n' */
}
/* remove ending white spaces */
for (; pos2>pos1 && pos2[-1]==' ';pos2--) pos2[-1]='\0';
pos1++;
pos2=strchr(pos1,'\r');
if (pos2==NULL)
pos2=strchr(pos1,'\n');
if (pos2==NULL) pos2=pos1+strlen(pos1);
else {
*pos2='\0'; /*replace the '\n' */
}
/* remove ending white spaces */
for (; pos2>pos1 && pos2[-1]==' ';pos2--) pos2[-1]='\0';
if (pos2-pos1>=0){
/* found a pair key,value */
if (pos2-pos1>=0){
/* found a pair key,value */
if (cur!=NULL){
item=lp_section_find_item(cur,key);
if (item==NULL){
lp_section_add_item(cur,lp_item_new(key,pos1));
if (cur!=NULL){
item=lp_section_find_item(cur,key);
if (item==NULL){
lp_section_add_item(cur,lp_item_new(key,pos1));
}else{
ortp_free(item->value);
item->value=ortp_strdup(pos1);
}
/*ms_message("Found %s=%s",key,pos1);*/
}else{
ortp_free(item->value);
item->value=ortp_strdup(pos1);
ms_warning("found key,item but no sections");
}
/*ms_message("Found %s=%s",key,pos1);*/
}else{
ms_warning("found key,item but no sections");
}
}
}
}
}
ms_free(key);
ms_free(value);
ms_free(secname);
return cur;
}
@ -425,13 +452,16 @@ bool_t lp_config_get_range(const LpConfig *lpconfig, const char *section, const
}
}
int lp_config_get_int(const LpConfig *lpconfig,const char *section, const char *key, int default_value){
const char *str=lp_config_get_string(lpconfig,section,key,NULL);
if (str!=NULL) {
int ret=0;
if (strstr(str,"0x")==str){
sscanf(str,"%x",&ret);
}else ret=atoi(str);
}else
sscanf(str,"%i",&ret);
return ret;
}
else return default_value;
@ -510,7 +540,10 @@ void lp_config_set_float(LpConfig *lpconfig,const char *section, const char *key
}
void lp_item_write(LpItem *item, FILE *file){
fprintf(file,"%s=%s\n",item->key,item->value);
if (item->is_comment)
fprintf(file,"%s",item->value);
else
fprintf(file,"%s=%s\n",item->key,item->value);
}
void lp_section_param_write(LpSectionParam *param, FILE *file){
@ -566,7 +599,8 @@ void lp_config_for_each_entry(const LpConfig *lpconfig, const char *section, voi
if (sec!=NULL){
for (elem=sec->items;elem!=NULL;elem=ms_list_next(elem)){
item=(LpItem*)elem->data;
callback(item->key, ctx);
if (!item->is_comment)
callback(item->key, ctx);
}
}
}

View file

@ -1,440 +1,502 @@
/*
message_storage.c
Copyright (C) 2012 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.
*/
#include "private.h"
#include "linphonecore.h"
#ifdef WIN32
static inline char *my_ctime_r(const time_t *t, char *buf){
strcpy(buf,ctime(t));
return buf;
}
#else
#define my_ctime_r ctime_r
#endif
#ifdef MSG_STORAGE_ENABLED
#include "sqlite3.h"
static inline LinphoneChatMessage* get_transient_message(LinphoneChatRoom* cr, unsigned int storage_id){
MSList* transients = cr->transient_messages;
LinphoneChatMessage* chat;
while( transients ){
chat = (LinphoneChatMessage*)transients->data;
if(chat->storage_id == storage_id){
return linphone_chat_message_ref(chat);
}
transients = transients->next;
}
return NULL;
}
static void create_chat_message(char **argv, void *data){
LinphoneChatRoom *cr = (LinphoneChatRoom *)data;
LinphoneAddress *from;
unsigned int storage_id = atoi(argv[0]);
// check if the message exists in the transient list, in which case we should return that one.
LinphoneChatMessage* new_message = get_transient_message(cr, storage_id);
if( new_message == NULL ){
new_message = linphone_chat_room_create_message(cr, argv[4]);
if(atoi(argv[3])==LinphoneChatMessageIncoming){
new_message->dir=LinphoneChatMessageIncoming;
from=linphone_address_new(argv[2]);
} else {
new_message->dir=LinphoneChatMessageOutgoing;
from=linphone_address_new(argv[1]);
}
linphone_chat_message_set_from(new_message,from);
linphone_address_destroy(from);
if( argv[9] != NULL ){
new_message->time = (time_t)atol(argv[9]);
} else {
new_message->time = time(NULL);
}
new_message->is_read=atoi(argv[6]);
new_message->state=atoi(argv[7]);
new_message->storage_id=storage_id;
new_message->external_body_url=argv[8]?ms_strdup(argv[8]):NULL;
}
cr->messages_hist=ms_list_prepend(cr->messages_hist,new_message);
}
// Called when fetching all conversations from database
static int callback_all(void *data, int argc, char **argv, char **colName){
LinphoneCore* lc = (LinphoneCore*) data;
char* address = argv[0];
linphone_core_create_chat_room(lc, address);
return 0;
}
static int callback(void *data, int argc, char **argv, char **colName){
create_chat_message(argv,data);
return 0;
}
void linphone_sql_request_message(sqlite3 *db,const char *stmt,LinphoneChatRoom *cr){
char* errmsg=NULL;
int ret;
ret=sqlite3_exec(db,stmt,callback,cr,&errmsg);
if(ret != SQLITE_OK) {
ms_error("Error in creation: %s.\n", errmsg);
sqlite3_free(errmsg);
}
}
void linphone_sql_request(sqlite3* db,const char *stmt){
char* errmsg=NULL;
int ret;
ret=sqlite3_exec(db,stmt,NULL,NULL,&errmsg);
if(ret != SQLITE_OK) {
ms_error("linphone_sql_request: error sqlite3_exec(): %s.\n", errmsg);
sqlite3_free(errmsg);
}
}
// Process the request to fetch all chat contacts
void linphone_sql_request_all(sqlite3* db,const char *stmt, LinphoneCore* lc){
char* errmsg=NULL;
int ret;
ret=sqlite3_exec(db,stmt,callback_all,lc,&errmsg);
if(ret != SQLITE_OK) {
ms_error("linphone_sql_request_all: error sqlite3_exec(): %s.\n", errmsg);
sqlite3_free(errmsg);
}
}
unsigned int linphone_chat_message_store(LinphoneChatMessage *msg){
LinphoneCore *lc=linphone_chat_room_get_lc(msg->chat_room);
int id=0;
if (lc->db){
char *peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(msg->chat_room));
char *local_contact=linphone_address_as_string_uri_only(linphone_chat_message_get_local_address(msg));
char *buf=sqlite3_mprintf("INSERT INTO history VALUES(NULL,%Q,%Q,%i,%Q,%Q,%i,%i,%Q,%i);",
local_contact,
peer,
msg->dir,
msg->message,
"-1", /* use UTC field now */
msg->is_read,
msg->state,
msg->external_body_url,
msg->time);
linphone_sql_request(lc->db,buf);
sqlite3_free(buf);
ms_free(local_contact);
ms_free(peer);
id = (unsigned int) sqlite3_last_insert_rowid (lc->db);
}
return id;
}
void linphone_chat_message_store_state(LinphoneChatMessage *msg){
LinphoneCore *lc=msg->chat_room->lc;
if (lc->db){
char *buf=sqlite3_mprintf("UPDATE history SET status=%i WHERE message = %Q AND utc = %i;",
msg->state,msg->message,msg->time);
linphone_sql_request(lc->db,buf);
sqlite3_free(buf);
}
if( msg->state == LinphoneChatMessageStateDelivered
|| msg->state == LinphoneChatMessageStateNotDelivered ){
// message is not transient anymore, we can remove it from our transient list:
msg->chat_room->transient_messages = ms_list_remove(msg->chat_room->transient_messages, msg);
linphone_chat_message_unref(msg);
}
}
void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr){
LinphoneCore *lc=linphone_chat_room_get_lc(cr);
int read=1;
if (lc->db==NULL) return ;
char *peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr));
char *buf=sqlite3_mprintf("UPDATE history SET read=%i WHERE remoteContact = %Q;",
read,peer);
linphone_sql_request(lc->db,buf);
sqlite3_free(buf);
ms_free(peer);
}
void linphone_chat_room_update_url(LinphoneChatRoom *cr, LinphoneChatMessage *msg) {
LinphoneCore *lc=linphone_chat_room_get_lc(cr);
if (lc->db==NULL) return ;
char *buf=sqlite3_mprintf("UPDATE history SET url=%Q WHERE id=%i;",msg->external_body_url,msg->storage_id);
linphone_sql_request(lc->db,buf);
sqlite3_free(buf);
}
int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr){
LinphoneCore *lc=linphone_chat_room_get_lc(cr);
int numrows=0;
if (lc->db==NULL) return 0;
char *peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr));
char *buf=sqlite3_mprintf("SELECT count(*) FROM history WHERE remoteContact = %Q AND read = 0;",peer);
sqlite3_stmt *selectStatement;
int returnValue = sqlite3_prepare_v2(lc->db,buf,-1,&selectStatement,NULL);
if (returnValue == SQLITE_OK){
if(sqlite3_step(selectStatement) == SQLITE_ROW){
numrows= sqlite3_column_int(selectStatement, 0);
}
}
sqlite3_finalize(selectStatement);
sqlite3_free(buf);
ms_free(peer);
return numrows;
}
void linphone_chat_room_delete_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg) {
LinphoneCore *lc=cr->lc;
if (lc->db==NULL) return ;
char *buf=sqlite3_mprintf("DELETE FROM history WHERE id = %i;", msg->storage_id);
linphone_sql_request(lc->db,buf);
sqlite3_free(buf);
}
void linphone_chat_room_delete_history(LinphoneChatRoom *cr){
LinphoneCore *lc=cr->lc;
if (lc->db==NULL) return ;
char *peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr));
char *buf=sqlite3_mprintf("DELETE FROM history WHERE remoteContact = %Q;",peer);
linphone_sql_request(lc->db,buf);
sqlite3_free(buf);
ms_free(peer);
}
MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message){
LinphoneCore *lc=linphone_chat_room_get_lc(cr);
MSList *ret;
char *buf;
char *peer;
if (lc->db==NULL) return NULL;
peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr));
cr->messages_hist = NULL;
if (nb_message > 0)
buf=sqlite3_mprintf("SELECT * FROM history WHERE remoteContact = %Q ORDER BY id DESC LIMIT %i ;",peer,nb_message);
else
buf=sqlite3_mprintf("SELECT * FROM history WHERE remoteContact = %Q ORDER BY id DESC;",peer);
linphone_sql_request_message(lc->db,buf,cr);
sqlite3_free(buf);
ret=cr->messages_hist;
cr->messages_hist=NULL;
ms_free(peer);
return ret;
}
void linphone_close_storage(sqlite3* db){
sqlite3_close(db);
}
void linphone_create_table(sqlite3* db){
char* errmsg=NULL;
int ret;
ret=sqlite3_exec(db,"CREATE TABLE IF NOT EXISTS history ("
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
"localContact TEXT NOT NULL,"
"remoteContact TEXT NOT NULL,"
"direction INTEGER,"
"message TEXT,"
"time TEXT NOT NULL,"
"read INTEGER,"
"status INTEGER"
");",
0,0,&errmsg);
if(ret != SQLITE_OK) {
ms_error("Error in creation: %s.\n", errmsg);
sqlite3_free(errmsg);
}
}
static const char *days[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
static const char *months[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
static time_t parse_time_from_db( const char* time ){
/* messages used to be stored in the DB by using string-based time */
struct tm ret={0};
char tmp1[80]={0};
char tmp2[80]={0};
int i,j;
time_t parsed = 0;
if( sscanf(time,"%3c %3c%d%d:%d:%d %d",tmp1,tmp2,&ret.tm_mday,
&ret.tm_hour,&ret.tm_min,&ret.tm_sec,&ret.tm_year) == 7 ){
ret.tm_year-=1900;
for(i=0;i<7;i++) {
if(strcmp(tmp1,days[i])==0) ret.tm_wday=i;
}
for(j=0;j<12;j++) {
if(strcmp(tmp2,months[j])==0) ret.tm_mon=j;
}
ret.tm_isdst=-1;
parsed = mktime(&ret);
}
return parsed;
}
static int migrate_messages(void* data,int argc, char** argv, char** column_names) {
time_t new_time = parse_time_from_db(argv[1]);
if( new_time ){
/* replace 'time' by -1 and set 'utc' to the timestamp */
char *buf = sqlite3_mprintf("UPDATE history SET utc=%i,time='-1' WHERE id=%i", new_time, atoi(argv[0]));
if( buf) {
linphone_sql_request((sqlite3*)data, buf);
sqlite3_free(buf);
}
} else {
printf("Cannot parse time %s from id %s", argv[1], argv[0]);
}
return 0;
}
static void linphone_migrate_timestamps(sqlite3* db){
int ret;
char* errmsg = NULL;
ret = sqlite3_exec(db,"SELECT id,time,direction FROM history WHERE time != '-1'", migrate_messages, db, &errmsg);
if( ret != SQLITE_OK ){
printf("Error migrating outgoing messages: %s.\n", errmsg);
sqlite3_free(errmsg);
} else {
printf("Migrated message timestamps to UTC\n");
}
}
void linphone_update_table(sqlite3* db) {
char* errmsg=NULL;
int ret;
// for image url storage
ret=sqlite3_exec(db,"ALTER TABLE history ADD COLUMN url TEXT;",NULL,NULL,&errmsg);
if(ret != SQLITE_OK) {
ms_warning("Table already up to date: %s.\n", errmsg);
sqlite3_free(errmsg);
} else {
ms_debug("Table updated successfully for URL.");
}
// for UTC timestamp storage
ret = sqlite3_exec(db, "ALTER TABLE history ADD COLUMN utc INTEGER;", NULL,NULL,&errmsg);
if( ret != SQLITE_OK ){
ms_warning("Table already up to date: %s.\n", errmsg);
sqlite3_free(errmsg);
} else {
ms_debug("Table updated successfully for UTC.");
}
// migrate from old text-based timestamps to unix time-based timestamps
linphone_migrate_timestamps(db);
}
void linphone_message_storage_init_chat_rooms(LinphoneCore *lc) {
char *buf;
if (lc->db==NULL) return;
buf=sqlite3_mprintf("SELECT remoteContact FROM history GROUP BY remoteContact;");
linphone_sql_request_all(lc->db,buf,lc);
sqlite3_free(buf);
}
void linphone_core_message_storage_init(LinphoneCore *lc){
int ret;
const char *errmsg;
sqlite3 *db;
ret=sqlite3_open(lc->chat_db_file,&db);
if(ret != SQLITE_OK) {
errmsg=sqlite3_errmsg(db);
ms_error("Error in the opening: %s.\n", errmsg);
sqlite3_close(db);
}
linphone_create_table(db);
linphone_update_table(db);
lc->db=db;
// Create a chatroom for each contact in the chat history
linphone_message_storage_init_chat_rooms(lc);
}
void linphone_core_message_storage_close(LinphoneCore *lc){
if (lc->db){
sqlite3_close(lc->db);
lc->db=NULL;
}
}
#else
unsigned int linphone_chat_message_store(LinphoneChatMessage *cr){
return 0;
}
void linphone_chat_message_store_state(LinphoneChatMessage *cr){
}
void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr){
}
MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message){
return NULL;
}
void linphone_chat_room_delete_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg) {
}
void linphone_chat_room_delete_history(LinphoneChatRoom *cr){
}
void linphone_message_storage_init_chat_rooms(LinphoneCore *lc) {
}
void linphone_core_message_storage_init(LinphoneCore *lc){
}
void linphone_core_message_storage_close(LinphoneCore *lc){
}
void linphone_chat_room_update_url(LinphoneChatRoom *cr, LinphoneChatMessage *msg) {
}
int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr){
return 0;
}
#endif
/*
message_storage.c
Copyright (C) 2012 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.
*/
#include "private.h"
#include "linphonecore.h"
#ifdef MSG_STORAGE_ENABLED
#include "sqlite3.h"
static inline LinphoneChatMessage* get_transient_message(LinphoneChatRoom* cr, unsigned int storage_id){
MSList* transients = cr->transient_messages;
LinphoneChatMessage* chat;
while( transients ){
chat = (LinphoneChatMessage*)transients->data;
if(chat->storage_id == storage_id){
return linphone_chat_message_ref(chat);
}
transients = transients->next;
}
return NULL;
}
/* DB layout:
* | 0 | storage_id
* | 1 | localContact
* | 2 | remoteContact
* | 3 | direction flag
* | 4 | message
* | 5 | time (unused now, used to be string-based timestamp)
* | 6 | read flag
* | 7 | status
* | 8 | external body url
* | 9 | utc timestamp
* | 10 | app data text
*/
static void create_chat_message(char **argv, void *data){
LinphoneChatRoom *cr = (LinphoneChatRoom *)data;
LinphoneAddress *from;
unsigned int storage_id = atoi(argv[0]);
// check if the message exists in the transient list, in which case we should return that one.
LinphoneChatMessage* new_message = get_transient_message(cr, storage_id);
if( new_message == NULL ){
new_message = linphone_chat_room_create_message(cr, argv[4]);
if(atoi(argv[3])==LinphoneChatMessageIncoming){
new_message->dir=LinphoneChatMessageIncoming;
from=linphone_address_new(argv[2]);
} else {
new_message->dir=LinphoneChatMessageOutgoing;
from=linphone_address_new(argv[1]);
}
linphone_chat_message_set_from(new_message,from);
linphone_address_destroy(from);
if( argv[9] != NULL ){
new_message->time = (time_t)atol(argv[9]);
} else {
new_message->time = time(NULL);
}
new_message->is_read=atoi(argv[6]);
new_message->state=atoi(argv[7]);
new_message->storage_id=storage_id;
new_message->external_body_url= argv[8] ? ms_strdup(argv[8]) : NULL;
new_message->appdata = argv[10]? ms_strdup(argv[10]) : NULL;
}
cr->messages_hist=ms_list_prepend(cr->messages_hist,new_message);
}
// Called when fetching all conversations from database
static int callback_all(void *data, int argc, char **argv, char **colName){
LinphoneCore* lc = (LinphoneCore*) data;
char* address = argv[0];
linphone_core_get_or_create_chat_room(lc, address);
return 0;
}
static int callback(void *data, int argc, char **argv, char **colName){
create_chat_message(argv,data);
return 0;
}
void linphone_sql_request_message(sqlite3 *db,const char *stmt,LinphoneChatRoom *cr){
char* errmsg=NULL;
int ret;
ret=sqlite3_exec(db,stmt,callback,cr,&errmsg);
if(ret != SQLITE_OK) {
ms_error("Error in creation: %s.\n", errmsg);
sqlite3_free(errmsg);
}
}
int linphone_sql_request(sqlite3* db,const char *stmt){
char* errmsg=NULL;
int ret;
ret=sqlite3_exec(db,stmt,NULL,NULL,&errmsg);
if(ret != SQLITE_OK) {
ms_error("linphone_sql_request: error sqlite3_exec(): %s.\n", errmsg);
sqlite3_free(errmsg);
}
return ret;
}
// Process the request to fetch all chat contacts
void linphone_sql_request_all(sqlite3* db,const char *stmt, LinphoneCore* lc){
char* errmsg=NULL;
int ret;
ret=sqlite3_exec(db,stmt,callback_all,lc,&errmsg);
if(ret != SQLITE_OK) {
ms_error("linphone_sql_request_all: error sqlite3_exec(): %s.\n", errmsg);
sqlite3_free(errmsg);
}
}
unsigned int linphone_chat_message_store(LinphoneChatMessage *msg){
LinphoneCore *lc=linphone_chat_room_get_lc(msg->chat_room);
int id=0;
if (lc->db){
char *peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(msg->chat_room));
char *local_contact=linphone_address_as_string_uri_only(linphone_chat_message_get_local_address(msg));
char *buf=sqlite3_mprintf("INSERT INTO history VALUES(NULL,%Q,%Q,%i,%Q,%Q,%i,%i,%Q,%i,%Q);",
local_contact,
peer,
msg->dir,
msg->message,
"-1", /* use UTC field now */
msg->is_read,
msg->state,
msg->external_body_url,
msg->time,
msg->appdata);
linphone_sql_request(lc->db,buf);
sqlite3_free(buf);
ms_free(local_contact);
ms_free(peer);
id = (unsigned int) sqlite3_last_insert_rowid (lc->db);
}
return id;
}
void linphone_chat_message_store_state(LinphoneChatMessage *msg){
LinphoneCore *lc=msg->chat_room->lc;
if (lc->db){
char *buf=sqlite3_mprintf("UPDATE history SET status=%i WHERE (message = %Q OR url = %Q) AND utc = %i;",
msg->state,msg->message,msg->external_body_url,msg->time);
linphone_sql_request(lc->db,buf);
sqlite3_free(buf);
}
if( msg->state == LinphoneChatMessageStateDelivered
|| msg->state == LinphoneChatMessageStateNotDelivered ){
// message is not transient anymore, we can remove it from our transient list:
msg->chat_room->transient_messages = ms_list_remove(msg->chat_room->transient_messages, msg);
linphone_chat_message_unref(msg);
}
}
void linphone_chat_message_store_appdata(LinphoneChatMessage* msg){
LinphoneCore *lc=msg->chat_room->lc;
if (lc->db){
char *buf=sqlite3_mprintf("UPDATE history SET appdata=%Q WHERE id=%i;",
msg->appdata,msg->storage_id);
linphone_sql_request(lc->db,buf);
sqlite3_free(buf);
}
}
void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr){
LinphoneCore *lc=linphone_chat_room_get_lc(cr);
int read=1;
if (lc->db==NULL) return ;
char *peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr));
char *buf=sqlite3_mprintf("UPDATE history SET read=%i WHERE remoteContact = %Q;",
read,peer);
linphone_sql_request(lc->db,buf);
sqlite3_free(buf);
ms_free(peer);
}
void linphone_chat_room_update_url(LinphoneChatRoom *cr, LinphoneChatMessage *msg) {
LinphoneCore *lc=linphone_chat_room_get_lc(cr);
if (lc->db==NULL) return ;
char *buf=sqlite3_mprintf("UPDATE history SET url=%Q WHERE id=%i;",msg->external_body_url,msg->storage_id);
linphone_sql_request(lc->db,buf);
sqlite3_free(buf);
}
int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr){
LinphoneCore *lc=linphone_chat_room_get_lc(cr);
int numrows=0;
if (lc->db==NULL) return 0;
char *peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr));
char *buf=sqlite3_mprintf("SELECT count(*) FROM history WHERE remoteContact = %Q AND read = 0;",peer);
sqlite3_stmt *selectStatement;
int returnValue = sqlite3_prepare_v2(lc->db,buf,-1,&selectStatement,NULL);
if (returnValue == SQLITE_OK){
if(sqlite3_step(selectStatement) == SQLITE_ROW){
numrows= sqlite3_column_int(selectStatement, 0);
}
}
sqlite3_finalize(selectStatement);
sqlite3_free(buf);
ms_free(peer);
return numrows;
}
void linphone_chat_room_delete_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg) {
LinphoneCore *lc=cr->lc;
if (lc->db==NULL) return ;
char *buf=sqlite3_mprintf("DELETE FROM history WHERE id = %i;", msg->storage_id);
linphone_sql_request(lc->db,buf);
sqlite3_free(buf);
}
void linphone_chat_room_delete_history(LinphoneChatRoom *cr){
LinphoneCore *lc=cr->lc;
if (lc->db==NULL) return ;
char *peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr));
char *buf=sqlite3_mprintf("DELETE FROM history WHERE remoteContact = %Q;",peer);
linphone_sql_request(lc->db,buf);
sqlite3_free(buf);
ms_free(peer);
}
MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message){
LinphoneCore *lc=linphone_chat_room_get_lc(cr);
MSList *ret;
char *buf;
char *peer;
uint64_t begin,end;
if (lc->db==NULL) return NULL;
peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr));
cr->messages_hist = NULL;
if (nb_message > 0)
buf=sqlite3_mprintf("SELECT * FROM history WHERE remoteContact = %Q ORDER BY id DESC LIMIT %i ;",peer,nb_message);
else
buf=sqlite3_mprintf("SELECT * FROM history WHERE remoteContact = %Q ORDER BY id DESC;",peer);
begin=ortp_get_cur_time_ms();
linphone_sql_request_message(lc->db,buf,cr);
end=ortp_get_cur_time_ms();
ms_message("linphone_chat_room_get_history(): completed in %i ms",(int)(end-begin));
sqlite3_free(buf);
ret=cr->messages_hist;
cr->messages_hist=NULL;
ms_free(peer);
return ret;
}
void linphone_close_storage(sqlite3* db){
sqlite3_close(db);
}
void linphone_create_table(sqlite3* db){
char* errmsg=NULL;
int ret;
ret=sqlite3_exec(db,"CREATE TABLE IF NOT EXISTS history ("
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
"localContact TEXT NOT NULL,"
"remoteContact TEXT NOT NULL,"
"direction INTEGER,"
"message TEXT,"
"time TEXT NOT NULL,"
"read INTEGER,"
"status INTEGER"
");",
0,0,&errmsg);
if(ret != SQLITE_OK) {
ms_error("Error in creation: %s.\n", errmsg);
sqlite3_free(errmsg);
}
}
static const char *days[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
static const char *months[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
static time_t parse_time_from_db( const char* time ){
/* messages used to be stored in the DB by using string-based time */
struct tm ret={0};
char tmp1[80]={0};
char tmp2[80]={0};
int i,j;
time_t parsed = 0;
if( sscanf(time,"%3c %3c%d%d:%d:%d %d",tmp1,tmp2,&ret.tm_mday,
&ret.tm_hour,&ret.tm_min,&ret.tm_sec,&ret.tm_year) == 7 ){
ret.tm_year-=1900;
for(i=0;i<7;i++) {
if(strcmp(tmp1,days[i])==0) ret.tm_wday=i;
}
for(j=0;j<12;j++) {
if(strcmp(tmp2,months[j])==0) ret.tm_mon=j;
}
ret.tm_isdst=-1;
parsed = mktime(&ret);
}
return parsed;
}
static int migrate_messages_timestamp(void* data,int argc, char** argv, char** column_names) {
time_t new_time = parse_time_from_db(argv[1]);
if( new_time ){
/* replace 'time' by -1 and set 'utc' to the timestamp */
char *buf = sqlite3_mprintf("UPDATE history SET utc=%i,time='-1' WHERE id=%i;", new_time, atoi(argv[0]));
if( buf) {
linphone_sql_request((sqlite3*)data, buf);
sqlite3_free(buf);
}
} else {
ms_warning("Cannot parse time %s from id %s", argv[1], argv[0]);
}
return 0;
}
static void linphone_migrate_timestamps(sqlite3* db){
int ret;
char* errmsg = NULL;
uint64_t begin=ortp_get_cur_time_ms();
linphone_sql_request(db,"BEGIN TRANSACTION");
ret = sqlite3_exec(db,"SELECT id,time,direction FROM history WHERE time != '-1';", migrate_messages_timestamp, db, &errmsg);
if( ret != SQLITE_OK ){
ms_warning("Error migrating outgoing messages: %s.\n", errmsg);
sqlite3_free(errmsg);
linphone_sql_request(db, "ROLLBACK");
} else {
linphone_sql_request(db, "COMMIT");
uint64_t end=ortp_get_cur_time_ms();
ms_message("Migrated message timestamps to UTC in %i ms",(int)(end-begin));
}
}
void linphone_update_table(sqlite3* db) {
char* errmsg=NULL;
int ret;
// for image url storage
ret=sqlite3_exec(db,"ALTER TABLE history ADD COLUMN url TEXT;",NULL,NULL,&errmsg);
if(ret != SQLITE_OK) {
ms_message("Table already up to date: %s.", errmsg);
sqlite3_free(errmsg);
} else {
ms_debug("Table updated successfully for URL.");
}
// for UTC timestamp storage
ret = sqlite3_exec(db, "ALTER TABLE history ADD COLUMN utc INTEGER;", NULL,NULL,&errmsg);
if( ret != SQLITE_OK ){
ms_message("Table already up to date: %s.", errmsg);
sqlite3_free(errmsg);
} else {
ms_debug("Table updated successfully for UTC.");
// migrate from old text-based timestamps to unix time-based timestamps
linphone_migrate_timestamps(db);
}
// new field for app-specific storage
ret=sqlite3_exec(db,"ALTER TABLE history ADD COLUMN appdata TEXT;",NULL,NULL,&errmsg);
if(ret != SQLITE_OK) {
ms_message("Table already up to date: %s.", errmsg);
sqlite3_free(errmsg);
} else {
ms_debug("Table updated successfully for app-specific data.");
}
}
void linphone_message_storage_init_chat_rooms(LinphoneCore *lc) {
char *buf;
if (lc->db==NULL) return;
buf=sqlite3_mprintf("SELECT remoteContact FROM history GROUP BY remoteContact;");
linphone_sql_request_all(lc->db,buf,lc);
sqlite3_free(buf);
}
static void _linphone_message_storage_profile(void*data,const char*statement, sqlite3_uint64 duration){
ms_warning("SQL statement '%s' took %" PRIu64 " microseconds", statement, (uint64_t)(duration / 1000LL) );
}
static void linphone_message_storage_activate_debug(sqlite3* db, bool_t debug){
if( debug ){
sqlite3_profile(db, _linphone_message_storage_profile, NULL );
} else {
sqlite3_profile(db, NULL, NULL );
}
}
void linphone_core_message_storage_set_debug(LinphoneCore *lc, bool_t debug){
lc->debug_storage = debug;
if( lc->db ){
linphone_message_storage_activate_debug(lc->db, debug);
}
}
void linphone_core_message_storage_init(LinphoneCore *lc){
int ret;
const char *errmsg;
sqlite3 *db;
linphone_core_message_storage_close(lc);
ret=sqlite3_open(lc->chat_db_file,&db);
if(ret != SQLITE_OK) {
errmsg=sqlite3_errmsg(db);
ms_error("Error in the opening: %s.\n", errmsg);
sqlite3_close(db);
}
linphone_message_storage_activate_debug(db, lc->debug_storage);
linphone_create_table(db);
linphone_update_table(db);
lc->db=db;
// Create a chatroom for each contact in the chat history
linphone_message_storage_init_chat_rooms(lc);
}
void linphone_core_message_storage_close(LinphoneCore *lc){
if (lc->db){
sqlite3_close(lc->db);
lc->db=NULL;
}
}
#else
unsigned int linphone_chat_message_store(LinphoneChatMessage *cr){
return 0;
}
void linphone_chat_message_store_state(LinphoneChatMessage *cr){
}
void linphone_chat_message_store_appdata(LinphoneChatMessage *msg){
}
void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr){
}
MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message){
return NULL;
}
void linphone_chat_room_delete_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg) {
}
void linphone_chat_room_delete_history(LinphoneChatRoom *cr){
}
void linphone_message_storage_init_chat_rooms(LinphoneCore *lc) {
}
void linphone_core_message_storage_init(LinphoneCore *lc){
}
void linphone_core_message_storage_close(LinphoneCore *lc){
}
void linphone_chat_room_update_url(LinphoneChatRoom *cr, LinphoneChatMessage *msg) {
}
int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr){
return 0;
}
#endif

View file

@ -711,11 +711,11 @@ void linphone_core_update_local_media_description_from_ice(SalMediaDescription *
}
strncpy(desc->ice_pwd, ice_session_local_pwd(session), sizeof(desc->ice_pwd));
strncpy(desc->ice_ufrag, ice_session_local_ufrag(session), sizeof(desc->ice_ufrag));
for (i = 0; i < desc->n_active_streams; i++) {
for (i = 0; i < desc->nb_streams; i++) {
SalStreamDescription *stream = &desc->streams[i];
IceCheckList *cl = ice_session_check_list(session, i);
nb_candidates = 0;
if (cl == NULL) continue;
if (!sal_stream_description_active(stream) || (cl == NULL)) continue;
if (ice_check_list_state(cl) == ICL_Completed) {
stream->ice_completed = TRUE;
result = ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, i), &rtp_addr, &stream->rtp_port, &rtcp_addr, &stream->rtcp_port);
@ -803,6 +803,13 @@ static void get_default_addr_and_port(uint16_t componentID, const SalMediaDescri
if ((*addr)[0] == '\0') *addr = md->addr;
}
static void clear_ice_check_list(LinphoneCall *call, IceCheckList *removed){
if (call->audiostream && call->audiostream->ms.ice_check_list==removed)
call->audiostream->ms.ice_check_list=NULL;
if (call->videostream && call->videostream->ms.ice_check_list==removed)
call->videostream->ms.ice_check_list=NULL;
}
void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md)
{
bool_t ice_restarted = FALSE;
@ -815,7 +822,7 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call,
ice_session_restart(call->ice_session);
ice_restarted = TRUE;
} else {
for (i = 0; i < md->n_total_streams; i++) {
for (i = 0; i < md->nb_streams; i++) {
const SalStreamDescription *stream = &md->streams[i];
IceCheckList *cl = ice_session_check_list(call->ice_session, i);
if (cl && (strcmp(stream->rtp_addr, "0.0.0.0") == 0)) {
@ -834,7 +841,7 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call,
}
ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd);
}
for (i = 0; i < md->n_total_streams; i++) {
for (i = 0; i < md->nb_streams; i++) {
const SalStreamDescription *stream = &md->streams[i];
IceCheckList *cl = ice_session_check_list(call->ice_session, i);
if (cl && (stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) {
@ -850,9 +857,10 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call,
}
/* Create ICE check lists if needed and parse ICE attributes. */
for (i = 0; i < md->n_total_streams; i++) {
for (i = 0; i < md->nb_streams; i++) {
const SalStreamDescription *stream = &md->streams[i];
IceCheckList *cl = ice_session_check_list(call->ice_session, i);
/*
if ((cl == NULL) && (i < md->n_active_streams)) {
cl = ice_check_list_new();
ice_session_add_check_list(call->ice_session, cl);
@ -867,16 +875,13 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call,
break;
}
}
*/
if (cl==NULL) continue;
if (stream->ice_mismatch == TRUE) {
ice_check_list_set_state(cl, ICL_Failed);
} else if (stream->rtp_port == 0) {
ice_session_remove_check_list(call->ice_session, cl);
#ifdef VIDEO_ENABLED
if (stream->type==SalVideo && call->videostream){
video_stream_stop(call->videostream);
call->videostream=NULL;
}
#endif
clear_ice_check_list(call,cl);
} else {
if ((stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0'))
ice_check_list_set_remote_credentials(cl, stream->ice_ufrag, stream->ice_pwd);
@ -913,13 +918,12 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call,
}
}
}
for (i = ice_session_nb_check_lists(call->ice_session); i > md->n_active_streams; i--) {
IceCheckList *removed=ice_session_check_list(call->ice_session, i - 1);
ice_session_remove_check_list(call->ice_session, removed);
if (call->audiostream && call->audiostream->ms.ice_check_list==removed)
call->audiostream->ms.ice_check_list=NULL;
if (call->videostream && call->videostream->ms.ice_check_list==removed)
call->videostream->ms.ice_check_list=NULL;
for (i = 0; i < md->nb_streams; i++) {
IceCheckList * cl = ice_session_check_list(call->ice_session, i);
if (!sal_stream_description_active(&md->streams[i]) && (cl != NULL)) {
ice_session_remove_check_list_from_idx(call->ice_session, i);
clear_ice_check_list(call, cl);
}
}
ice_session_check_mismatch(call->ice_session);
} else {
@ -932,12 +936,11 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call,
}
}
bool_t linphone_core_media_description_contains_video_stream(const SalMediaDescription *md)
{
bool_t linphone_core_media_description_contains_video_stream(const SalMediaDescription *md){
int i;
for (i = 0; i < md->n_active_streams; i++) {
if (md->streams[i].type == SalVideo)
for (i = 0; i < md->nb_streams; i++) {
if (md->streams[i].type == SalVideo && md->streams[i].rtp_port!=0)
return TRUE;
}
return FALSE;
@ -1471,3 +1474,71 @@ void linphone_core_set_tone(LinphoneCore *lc, LinphoneToneID id, const char *aud
_linphone_core_set_tone(lc, LinphoneReasonNone, id, audiofile);
}
const MSCryptoSuite * linphone_core_get_srtp_crypto_suites(LinphoneCore *lc){
const char *config=lp_config_get_string(lc->config,"sip","srtp_crypto_suites","AES_CM_128_HMAC_SHA1_80, AES_CM_128_HMAC_SHA1_32");
char *tmp=ms_strdup(config);
char *sep;
char *pos;
char *nextpos;
char *params;
int found=0;
MSCryptoSuite *result=NULL;
pos=tmp;
do{
sep=strchr(pos,',');
if (!sep) {
sep=pos+strlen(pos);
nextpos=NULL;
}else {
*sep='\0';
nextpos=sep+1;
}
while(*pos==' ') ++pos; /*strip leading spaces*/
params=strchr(pos,' '); /*look for params that arrive after crypto suite name*/
if (params){
while(*params==' ') ++params; /*strip parameters leading space*/
}
if (sep-pos>0){
MSCryptoSuiteNameParams np;
MSCryptoSuite suite;
np.name=pos;
np.params=params;
suite=ms_crypto_suite_build_from_name_params(&np);
if (suite!=MS_CRYPTO_SUITE_INVALID){
result=ms_realloc(result,(found+2)*sizeof(MSCryptoSuite));
result[found]=suite;
result[found+1]=MS_CRYPTO_SUITE_INVALID;
found++;
ms_message("Configured srtp crypto suite: %s %s",np.name,np.params ? np.params : "");
}
}
pos=nextpos;
}while(pos);
ms_free(tmp);
if (lc->rtp_conf.srtp_suites){
ms_free(lc->rtp_conf.srtp_suites);
lc->rtp_conf.srtp_suites=NULL;
}
lc->rtp_conf.srtp_suites=result;
return result;
}
const char ** linphone_core_get_supported_file_formats(LinphoneCore *core){
static const char *mkv="mkv";
static const char *wav="wav";
if (core->supported_formats==NULL){
core->supported_formats=ms_malloc0(3*sizeof(char*));
core->supported_formats[0]=wav;
if (ms_factory_lookup_filter_by_id(ms_factory_get_fallback(),MS_MKV_RECORDER_ID)){
core->supported_formats[1]=mkv;
}
}
return core->supported_formats;
}
bool_t linphone_core_symmetric_rtp_enabled(LinphoneCore*lc){
return lp_config_get_int(lc->config,"rtp","symmetric",1);
}

View file

@ -99,6 +99,14 @@ static MSList *match_payloads(const MSList *local, const MSList *remote, bool_t
if (p2->send_fmtp)
payload_type_set_send_fmtp(newp,p2->send_fmtp);
newp->flags|=PAYLOAD_TYPE_FLAG_CAN_RECV|PAYLOAD_TYPE_FLAG_CAN_SEND;
if (p2->flags & PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED) {
newp->flags |= PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED;
newp->avpf = payload_type_get_avpf_params(p2); /* Take remote AVPF features */
/* Take bigger AVPF trr interval */
if (p2->avpf.trr_interval < matched->avpf.trr_interval) {
newp->avpf.trr_interval = matched->avpf.trr_interval;
}
}
res=ms_list_append(res,newp);
/* we should use the remote numbering even when parsing a response */
payload_type_set_number(newp,remote_number);
@ -156,17 +164,16 @@ static bool_t match_crypto_algo(const SalSrtpCryptoAlgo* local, const SalSrtpCry
result->algo = remote[i].algo;
/* We're answering an SDP offer. Supply our master key, associated with the remote supplied tag */
if (use_local_key) {
strncpy(result->master_key, local[j].master_key, 41);
strncpy(result->master_key, local[j].master_key, sizeof(result->master_key) );
result->tag = remote[i].tag;
*choosen_local_tag = local[j].tag;
}
/* We received an answer to our SDP crypto proposal. Copy matching algo remote master key to result, and memorize local tag */
else {
strncpy(result->master_key, remote[i].master_key, 41);
strncpy(result->master_key, remote[i].master_key, sizeof(result->master_key));
result->tag = local[j].tag;
*choosen_local_tag = local[j].tag;
}
result->master_key[40] = '\0';
return TRUE;
}
}
@ -234,7 +241,7 @@ static void initiate_outgoing(const SalStreamDescription *local_offer,
}else{
result->rtp_port=0;
}
if (result->proto == SalProtoRtpSavp) {
if (sal_stream_description_has_srtp(result) == TRUE) {
/* verify crypto algo */
memset(result->crypto, 0, sizeof(result->crypto));
if (!match_crypto_algo(local_offer->crypto, remote_answer->crypto, &result->crypto[0], &result->crypto_local_tag, FALSE))
@ -260,7 +267,7 @@ static void initiate_incoming(const SalStreamDescription *local_cap,
}else{
result->rtp_port=0;
}
if (result->proto == SalProtoRtpSavp) {
if (sal_stream_description_has_srtp(result) == TRUE) {
/* select crypto algo */
memset(result->crypto, 0, sizeof(result->crypto));
if (!match_crypto_algo(local_cap->crypto, remote_offer->crypto, &result->crypto[0], &result->crypto_local_tag, TRUE))
@ -286,7 +293,7 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
int i,j;
const SalStreamDescription *ls,*rs;
for(i=0,j=0;i<local_offer->n_total_streams;++i){
for(i=0,j=0;i<local_offer->nb_streams;++i){
ms_message("Processing for stream %i",i);
ls=&local_offer->streams[i];
rs=sal_media_description_find_stream((SalMediaDescription*)remote_answer,ls->proto,ls->type);
@ -300,8 +307,7 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
}
else ms_warning("No matching stream for %i",i);
}
result->n_active_streams=j;
result->n_total_streams=local_offer->n_total_streams;
result->nb_streams=local_offer->nb_streams;
result->bandwidth=remote_answer->bandwidth;
strcpy(result->addr,remote_answer->addr);
memcpy(&result->rtcp_xr, &local_offer->rtcp_xr, sizeof(result->rtcp_xr));
@ -314,7 +320,7 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
static bool_t local_stream_not_already_used(const SalMediaDescription *result, const SalStreamDescription *stream){
int i;
for(i=0;i<result->n_total_streams;++i){
for(i=0;i<result->nb_streams;++i){
const SalStreamDescription *ss=&result->streams[i];
if (strcmp(ss->name,stream->name)==0){
ms_message("video stream already used in answer");
@ -324,17 +330,19 @@ static bool_t local_stream_not_already_used(const SalMediaDescription *result, c
return TRUE;
}
/*in answering mode, we consider that if we are able to make SAVP, then we can do AVP as well*/
static bool_t proto_compatible(SalMediaProto local, SalMediaProto remote){
if (local==remote) return TRUE;
if (remote==SalProtoRtpAvp && local==SalProtoRtpSavp) return TRUE;
/*in answering mode, we consider that if we are able to make AVPF/SAVP/SAVPF, then we can do AVP as well*/
static bool_t proto_compatible(SalMediaProto local, SalMediaProto remote) {
if (local == remote) return TRUE;
if ((remote == SalProtoRtpAvp) && ((local == SalProtoRtpSavp) || (local == SalProtoRtpSavpf))) return TRUE;
if ((remote == SalProtoRtpAvpf) && (local == SalProtoRtpSavpf)) return TRUE;
return FALSE;
}
static const SalStreamDescription *find_local_matching_stream(const SalMediaDescription *result, const SalMediaDescription *local_capabilities, const SalStreamDescription *remote_stream){
int i;
for(i=0;i<local_capabilities->n_active_streams;++i){
for(i=0;i<local_capabilities->nb_streams;++i){
const SalStreamDescription *ss=&local_capabilities->streams[i];
if (!sal_stream_description_active(ss)) continue;
if (ss->type==remote_stream->type && proto_compatible(ss->proto,remote_stream->proto)
&& local_stream_not_already_used(result,ss)) return ss;
}
@ -352,15 +360,13 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities
int i;
const SalStreamDescription *ls=NULL,*rs;
result->n_active_streams=0;
for(i=0;i<remote_offer->n_total_streams;++i){
for(i=0;i<remote_offer->nb_streams;++i){
rs=&remote_offer->streams[i];
if (rs->proto!=SalProtoOther){
ls=find_local_matching_stream(result,local_capabilities,rs);
}else ms_warning("Unknown protocol for mline %i, declining",i);
if (ls){
initiate_incoming(ls,rs,&result->streams[i],one_matching_codec);
if (result->streams[i].rtp_port!=0) result->n_active_streams++;
// Handle media RTCP XR attribute
memset(&result->streams[i].rtcp_xr, 0, sizeof(result->streams[i].rtcp_xr));
@ -389,7 +395,7 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities
}
}
}
result->n_total_streams=i;
result->nb_streams=i;
strcpy(result->username, local_capabilities->username);
strcpy(result->addr,local_capabilities->addr);
result->bandwidth=local_capabilities->bandwidth;

View file

@ -81,15 +81,17 @@ static const char *person_prefix = "/pidf:presence/dm:person";
/*****************************************************************************
* PRIVATE FUNCTIONS *
****************************************************************************/
static char presence_id_valid_characters[] = "0123456789abcdefghijklmnopqrstuvwxyz";
/*defined in http://www.w3.org/TR/REC-xml/*/
static char presence_id_valid_characters[] = "0123456789abcdefghijklmnopqrstuvwxyz-.";
/*NameStartChar (NameChar)**/
static char presence_id_valid_start_characters[] = ":_abcdefghijklmnopqrstuvwxyz";
static char * generate_presence_id(void) {
char id[7];
int i;
for (i = 0; i < 6; i++) {
id[i] = presence_id_valid_characters[random() % sizeof(presence_id_valid_characters)];
id[0] = presence_id_valid_start_characters[random() % (sizeof(presence_id_valid_start_characters)-1)];
for (i = 1; i < 6; i++) {
id[i] = presence_id_valid_characters[random() % (sizeof(presence_id_valid_characters)-1)];
}
id[6] = '\0';
@ -278,6 +280,7 @@ LinphonePresenceBasicStatus linphone_presence_model_get_basic_status(const Linph
int linphone_presence_model_set_basic_status(LinphonePresenceModel *model, LinphonePresenceBasicStatus basic_status) {
LinphonePresenceService *service;
int err = 0;
if (model == NULL) return -1;
@ -285,8 +288,9 @@ int linphone_presence_model_set_basic_status(LinphonePresenceModel *model, Linph
service = linphone_presence_service_new(NULL, basic_status, NULL);
if (service == NULL) return -1;
if (linphone_presence_model_add_service(model, service) < 0) return -1;
return 0;
err = linphone_presence_model_add_service(model, service);
linphone_presence_service_unref(service);
return err;
}
static void presence_service_find_newer_timestamp(LinphonePresenceService *service, time_t *timestamp) {
@ -363,6 +367,7 @@ LinphonePresenceActivity * linphone_presence_model_get_activity(const LinphonePr
int linphone_presence_model_set_activity(LinphonePresenceModel *model, LinphonePresenceActivityType acttype, const char *description) {
LinphonePresenceBasicStatus basic_status = LinphonePresenceBasicStatusOpen;
LinphonePresenceActivity *activity;
int err = 0;
if (model == NULL) return -1;
@ -383,8 +388,9 @@ int linphone_presence_model_set_activity(LinphonePresenceModel *model, LinphoneP
linphone_presence_model_clear_activities(model);
activity = linphone_presence_activity_new(acttype, description);
if (activity == NULL) return -1;
return linphone_presence_model_add_activity(model, activity);
err = linphone_presence_model_add_activity(model, activity);
linphone_presence_activity_unref(activity);
return err;
}
unsigned int linphone_presence_model_get_nb_activities(const LinphonePresenceModel *model) {

View file

@ -95,10 +95,18 @@ struct _LinphoneCallParams{
char *session_name;
SalCustomHeader *custom_headers;
bool_t has_video;
bool_t avpf_enabled; /* RTCP feedback messages are enabled */
bool_t real_early_media; /*send real media even during early media (for outgoing calls)*/
bool_t in_conference; /*in conference mode */
bool_t low_bandwidth;
LinphonePrivacyMask privacy;
uint16_t avpf_rr_interval;
};
struct _LinphoneQualityReporting{
reporting_session_report_t * reports[2]; /**Store information on audio and video media streams (RFC 6035) */
bool_t was_video_running; /*Keep video state since last check in order to detect its (de)activation*/
LinphoneQualityReportingReportSendCb on_report_sent;
};
struct _LinphoneCallLog{
@ -117,10 +125,12 @@ struct _LinphoneCallLog{
time_t start_date_time; /**Start date of the call in seconds as expressed in a time_t */
char* call_id; /**unique id of a call*/
reporting_session_report_t * reports[2]; /**<Quality statistics of the call (rfc6035) */
struct _LinphoneQualityReporting reporting;
bool_t video_enabled;
};
typedef struct _CallCallbackObj
{
LinphoneCallCbFunc _func;
@ -142,6 +152,7 @@ struct _LinphoneChatMessage {
LinphoneChatMessageStateChangedCb cb;
void* cb_ud;
void* message_userdata;
char* appdata;
char* external_body_url;
LinphoneAddress *from;
LinphoneAddress *to;
@ -151,6 +162,8 @@ struct _LinphoneChatMessage {
bool_t is_read;
unsigned int storage_id;
SalOp *op;
LinphoneContent *file_transfer_information;
char *content_type;
};
BELLE_SIP_DECLARE_VPTR(LinphoneChatMessage);
@ -242,6 +255,7 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr
LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op);
void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message);
void linphone_call_set_contact_op(LinphoneCall* call);
void linphone_call_set_compatible_incoming_call_parameters(LinphoneCall *call, const SalMediaDescription *md);
/* private: */
LinphoneCallLog * linphone_call_log_new(LinphoneCall *call, LinphoneAddress *local, LinphoneAddress * remote);
void linphone_call_log_completed(LinphoneCall *call);
@ -280,24 +294,24 @@ void linphone_core_get_local_ip(LinphoneCore *lc, int af, char *result);
bool_t host_has_ipv6_network();
bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret);
static inline int get_min_bandwidth(int dbw, int ubw){
static MS2_INLINE int get_min_bandwidth(int dbw, int ubw){
if (dbw<=0) return ubw;
if (ubw<=0) return dbw;
return MIN(dbw,ubw);
}
static inline bool_t bandwidth_is_greater(int bw1, int bw2){
static MS2_INLINE bool_t bandwidth_is_greater(int bw1, int bw2){
if (bw1<0) return TRUE;
else if (bw2<0) return FALSE;
else return bw1>=bw2;
}
static inline int get_remaining_bandwidth_for_video(int total, int audio){
static MS2_INLINE int get_remaining_bandwidth_for_video(int total, int audio){
if (total<=0) return 0;
return total-audio-10;
}
static inline void set_string(char **dest, const char *src){
static MS2_INLINE void set_string(char **dest, const char *src){
if (*dest){
ms_free(*dest);
*dest=NULL;
@ -324,7 +338,7 @@ void linphone_subscription_closed(LinphoneCore *lc, SalOp *op);
void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc);
void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall *call, const PayloadType *pt, int maxbw);
int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call);
LINPHONE_PUBLIC int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call);
void linphone_core_resolve_stun_server(LinphoneCore *lc);
const struct addrinfo *linphone_core_get_stun_server_addrinfo(LinphoneCore *lc);
void linphone_core_adapt_to_network(LinphoneCore *lc, int ping_time_ms, LinphoneCallParams *params);
@ -334,7 +348,6 @@ void linphone_call_stats_fill(LinphoneCallStats *stats, MediaStream *ms, OrtpEve
void linphone_core_update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session);
void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md);
bool_t linphone_core_media_description_contains_video_stream(const SalMediaDescription *md);
bool_t linphone_core_media_description_has_srtp(const SalMediaDescription *md);
void linphone_core_send_initial_subscribes(LinphoneCore *lc);
void linphone_core_write_friends_config(LinphoneCore* lc);
@ -347,7 +360,7 @@ LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const L
const char *linphone_core_find_best_identity(LinphoneCore *lc, const LinphoneAddress *to);
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);
LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LinphoneCore *lc, int index);
void linphone_proxy_config_write_to_config_file(struct _LpConfig* config,LinphoneProxyConfig *obj, int index);
int linphone_proxy_config_normalize_number(LinphoneProxyConfig *cfg, const char *username, char *result, size_t result_len);
@ -362,8 +375,6 @@ void linphone_call_init_video_stream(LinphoneCall *call);
void linphone_call_init_media_streams(LinphoneCall *call);
void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone);
void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call);
void linphone_call_stop_audio_stream(LinphoneCall *call);
void linphone_call_stop_video_stream(LinphoneCall *call);
void linphone_call_stop_media_streams(LinphoneCall *call);
void linphone_call_delete_ice_session(LinphoneCall *call);
void linphone_call_delete_upnp_session(LinphoneCall *call);
@ -371,6 +382,7 @@ void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call);
void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md);
void linphone_call_update_remote_session_id_and_ver(LinphoneCall *call);
const char * linphone_core_get_identity(LinphoneCore *lc);
void linphone_core_start_waiting(LinphoneCore *lc, const char *purpose);
@ -386,6 +398,7 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call);
bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription *md);
extern SalCallbacks linphone_sal_callbacks;
bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc);
bool_t linphone_core_symmetric_rtp_enabled(LinphoneCore*lc);
LinphoneCall * is_a_linphone_call(void *user_pointer);
LinphoneProxyConfig * is_a_linphone_proxy_config(void *user_pointer);
@ -393,6 +406,9 @@ LinphoneProxyConfig * is_a_linphone_proxy_config(void *user_pointer);
void linphone_core_queue_task(LinphoneCore *lc, belle_sip_source_func_t task_fun, void *data, const char *task_description);
static const int linphone_proxy_config_magic=0x7979;
LINPHONE_PUBLIC bool_t linphone_proxy_config_address_equal(const LinphoneAddress *a, const LinphoneAddress *b);
LINPHONE_PUBLIC bool_t linphone_proxy_config_is_server_config_changed(const LinphoneProxyConfig* obj);
void _linphone_proxy_config_unregister(LinphoneProxyConfig *obj);
/*chat*/
void linphone_chat_message_destroy(LinphoneChatMessage* msg);
@ -405,7 +421,7 @@ struct _LinphoneProxyConfig
char *reg_proxy;
char *reg_identity;
char *reg_route;
char *statistics_collector;
char *quality_reporting_collector;
char *realm;
char *contact_params;
char *contact_uri_params;
@ -423,11 +439,19 @@ struct _LinphoneProxyConfig
bool_t publish;
bool_t dial_escape_plus;
bool_t send_publish;
bool_t send_statistics;
bool_t pad[3];
bool_t quality_reporting_enabled;
bool_t avpf_enabled;
bool_t pad;
uint8_t avpf_rr_interval;
uint8_t quality_reporting_interval;
void* user_data;
time_t deletion_date;
LinphonePrivacyMask privacy;
/*use to check if server config has changed between edit() and done()*/
LinphoneAddress *saved_proxy;
LinphoneAddress *saved_identity;
/*---*/
};
struct _LinphoneAuthInfo
@ -511,6 +535,7 @@ typedef struct rtp_config
int video_jitt_comp; /*jitter compensation*/
int nortp_timeout;
int disable_upnp;
MSCryptoSuite *srtp_suites;
bool_t rtp_no_xmit_on_audio_mute;
/* stop rtp xmit when audio muted */
bool_t audio_adaptive_jitt_comp_enabled;
@ -692,6 +717,7 @@ struct _LinphoneCore
char *chat_db_file;
#ifdef MSG_STORAGE_ENABLED
sqlite3 *db;
bool_t debug_storage;
#endif
#ifdef BUILD_UPNP
UpnpContext *upnp;
@ -700,6 +726,8 @@ struct _LinphoneCore
belle_tls_verify_policy_t *http_verify_policy;
MSList *tones;
LinphoneReason chat_deny_code;
char *file_transfer_server;
const char **supported_formats;
};
@ -732,6 +760,7 @@ int linphone_core_get_calls_nb(const LinphoneCore *lc);
void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message);
void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call);
void linphone_call_increment_local_media_description(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, const PayloadType *pt, int bandwidth_limit);
@ -804,8 +833,10 @@ sqlite3 * linphone_message_storage_init();
void linphone_message_storage_init_chat_rooms(LinphoneCore *lc);
#endif
void linphone_chat_message_store_state(LinphoneChatMessage *msg);
void linphone_chat_message_store_appdata(LinphoneChatMessage* msg);
void linphone_core_message_storage_init(LinphoneCore *lc);
void linphone_core_message_storage_close(LinphoneCore *lc);
void linphone_core_message_storage_set_debug(LinphoneCore *lc, bool_t debug);
void linphone_core_play_named_tone(LinphoneCore *lc, LinphoneToneID id);
bool_t linphone_core_tone_indications_enabled(LinphoneCore*lc);
@ -815,6 +846,7 @@ void linphone_call_create_op(LinphoneCall *call);
int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer);
void linphone_core_notify_info_message(LinphoneCore* lc,SalOp *op, const SalBody *body);
void linphone_content_uninit(LinphoneContent * obj);
void linphone_content_copy(LinphoneContent *obj, const LinphoneContent *ref);
LinphoneContent *linphone_content_copy_from_sal_body(LinphoneContent *obj, const SalBody *ref);
SalBody *sal_body_from_content(SalBody *body, const LinphoneContent *lc);
SalReason linphone_reason_to_sal(LinphoneReason reason);
@ -831,7 +863,6 @@ LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatu
const LinphoneContent *linphone_content_from_sal_body(LinphoneContent *obj, const SalBody *ref);
void linphone_core_invalidate_friend_subscriptions(LinphoneCore *lc);
/*****************************************************************************
* REMOTE PROVISIONING FUNCTIONS *
****************************************************************************/
@ -873,11 +904,12 @@ xmlXPathObjectPtr linphone_get_xml_xpath_object_for_node_list(xmlparsing_context
char * linphone_timestamp_to_rfc3339_string(time_t timestamp);
static inline const LinphoneErrorInfo *linphone_error_info_from_sal_op(const SalOp *op){
static MS2_INLINE const LinphoneErrorInfo *linphone_error_info_from_sal_op(const SalOp *op){
if (op==NULL) return (LinphoneErrorInfo*)sal_error_info_none();
return (const LinphoneErrorInfo*)sal_op_get_error_info(op);
}
const MSCryptoSuite * linphone_core_get_srtp_crypto_suites(LinphoneCore *lc);
/** Belle Sip-based objects need unique ids
*/

View file

@ -26,6 +26,54 @@ Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org)
#include <ctype.h>
/*store current config related to server location*/
static void linphone_proxy_config_store_server_config(LinphoneProxyConfig* obj) {
if (obj->saved_identity) linphone_address_destroy(obj->saved_identity);
if (obj->reg_identity)
obj->saved_identity = linphone_address_new(obj->reg_identity);
else
obj->saved_identity = NULL;
if (obj->saved_proxy) linphone_address_destroy(obj->saved_proxy);
if (obj->reg_proxy)
obj->saved_proxy = linphone_address_new(obj->reg_proxy);
else
obj->saved_proxy = NULL;
}
bool_t linphone_proxy_config_address_equal(const LinphoneAddress *a, const LinphoneAddress *b) {
if (a == NULL && b == NULL)
return TRUE;
else if (!a || !b)
return FALSE;
if (linphone_address_weak_equal(a,b)) {
/*also check both transport and uri */
return linphone_address_is_secure(a) == linphone_address_is_secure(b) && linphone_address_get_transport(a) == linphone_address_get_transport(b);
} else
return FALSE; /*either username, domain or port ar not equals*/
}
bool_t linphone_proxy_config_is_server_config_changed(const LinphoneProxyConfig* obj) {
LinphoneAddress *current_identity=obj->reg_identity?linphone_address_new(obj->reg_identity):NULL;
LinphoneAddress *current_proxy=obj->reg_proxy?linphone_address_new(obj->reg_proxy):NULL;
bool_t result=FALSE;
if (!linphone_proxy_config_address_equal(obj->saved_identity,current_identity)){
result=TRUE;
goto end;
}
if (!linphone_proxy_config_address_equal(obj->saved_proxy,current_proxy)){
result=TRUE;
goto end;
}
end:
if (current_identity) linphone_address_destroy(current_identity);
if (current_proxy) linphone_address_destroy(current_proxy);
return result;
}
void linphone_proxy_config_write_all_to_config_file(LinphoneCore *lc){
MSList *elem;
@ -46,7 +94,7 @@ static void linphone_proxy_config_init(LinphoneCore* lc, LinphoneProxyConfig *ob
const char *identity = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_identity", NULL) : NULL;
const char *proxy = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_proxy", NULL) : NULL;
const char *route = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_route", NULL) : NULL;
const char *statistics_collector = lc ? lp_config_get_default_string(lc->config, "proxy", "statistics_collector", NULL) : NULL;
const char *quality_reporting_collector = lc ? lp_config_get_default_string(lc->config, "proxy", "quality_reporting_collector", NULL) : NULL;
const char *contact_params = lc ? lp_config_get_default_string(lc->config, "proxy", "contact_parameters", NULL) : NULL;
const char *contact_uri_params = lc ? lp_config_get_default_string(lc->config, "proxy", "contact_uri_parameters", NULL) : NULL;
@ -60,10 +108,13 @@ static void linphone_proxy_config_init(LinphoneCore* lc, LinphoneProxyConfig *ob
obj->reg_identity = identity ? ms_strdup(identity) : NULL;
obj->reg_proxy = proxy ? ms_strdup(proxy) : NULL;
obj->reg_route = route ? ms_strdup(route) : NULL;
obj->statistics_collector = statistics_collector ? ms_strdup(statistics_collector) : NULL;
obj->send_statistics = lc ? lp_config_get_default_int(lc->config, "proxy", "send_statistics", 0) : 0;
obj->quality_reporting_enabled = lc ? lp_config_get_default_int(lc->config, "proxy", "quality_reporting_enabled", 0) : 0;
obj->quality_reporting_collector = quality_reporting_collector ? ms_strdup(quality_reporting_collector) : NULL;
obj->quality_reporting_interval = lc ? lp_config_get_default_int(lc->config, "proxy", "quality_reporting_interval", 0) : 0;
obj->contact_params = contact_params ? ms_strdup(contact_params) : NULL;
obj->contact_uri_params = contact_uri_params ? ms_strdup(contact_uri_params) : NULL;
obj->avpf_enabled = lc ? lp_config_get_default_int(lc->config, "proxy", "avpf", 0) : 0;
obj->avpf_rr_interval = lc ? lp_config_get_default_int(lc->config, "proxy", "avpf_rr_interval", 5) : 5;
obj->publish_expires=-1;
}
@ -97,7 +148,7 @@ void linphone_proxy_config_destroy(LinphoneProxyConfig *obj){
if (obj->reg_proxy!=NULL) ms_free(obj->reg_proxy);
if (obj->reg_identity!=NULL) ms_free(obj->reg_identity);
if (obj->reg_route!=NULL) ms_free(obj->reg_route);
if (obj->statistics_collector!=NULL) ms_free(obj->statistics_collector);
if (obj->quality_reporting_collector!=NULL) ms_free(obj->quality_reporting_collector);
if (obj->ssctx!=NULL) sip_setup_context_free(obj->ssctx);
if (obj->realm!=NULL) ms_free(obj->realm);
if (obj->type!=NULL) ms_free(obj->type);
@ -106,6 +157,8 @@ void linphone_proxy_config_destroy(LinphoneProxyConfig *obj){
if (obj->publish_op) sal_op_release(obj->publish_op);
if (obj->contact_params) ms_free(obj->contact_params);
if (obj->contact_uri_params) ms_free(obj->contact_uri_params);
if (obj->saved_proxy!=NULL) linphone_address_destroy(obj->saved_proxy);
if (obj->saved_identity!=NULL) linphone_address_destroy(obj->saved_identity);
ms_free(obj);
}
@ -254,6 +307,19 @@ void linphone_proxy_config_set_expires(LinphoneProxyConfig *obj, int val){
void linphone_proxy_config_enable_publish(LinphoneProxyConfig *obj, bool_t val){
obj->publish=val;
}
/**
* Prevent a proxy config from refreshing its registration.
* This is useful to let registrations to expire naturally (or) when the application wants to keep control on when
* refreshes are sent.
* However, linphone_core_set_network_reachable(lc,TRUE) will always request the proxy configs to refresh their registrations.
* The refreshing operations can be resumed with linphone_proxy_config_refresh_register().
* @param obj the proxy config
**/
void linphone_proxy_config_pause_register(LinphoneProxyConfig *obj){
if (obj->op) sal_op_stop_refreshing(obj->op);
}
/**
* Starts editing a proxy configuration.
*
@ -265,21 +331,16 @@ void linphone_proxy_config_enable_publish(LinphoneProxyConfig *obj, bool_t val){
**/
void linphone_proxy_config_edit(LinphoneProxyConfig *obj){
if (obj->publish && obj->publish_op){
/*unpublish*/
sal_publish_presence(obj->publish_op,NULL,NULL,0,(SalPresenceModel *)NULL);
sal_op_release(obj->publish_op);
obj->publish_op=NULL;
}
if (obj->reg_sendregister){
/* unregister */
if (obj->state == LinphoneRegistrationOk
|| obj->state == LinphoneRegistrationProgress) {
sal_unregister(obj->op);
} else {
/*stop refresher*/
if (obj->op) sal_op_stop_refreshing(obj->op);
}
/*unpublish*/
sal_publish_presence(obj->publish_op,NULL,NULL,0,(SalPresenceModel *)NULL);
sal_op_release(obj->publish_op);
obj->publish_op=NULL;
}
/*store current config related to server location*/
linphone_proxy_config_store_server_config(obj);
/*stop refresher in any case*/
linphone_proxy_config_pause_register(obj);
}
void linphone_proxy_config_apply(LinphoneProxyConfig *obj,LinphoneCore *lc){
@ -336,13 +397,21 @@ LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *obj){
return ret;
}
/**
* unregister without moving the register_enable flag
*/
void _linphone_proxy_config_unregister(LinphoneProxyConfig *obj) {
if (obj->state == LinphoneRegistrationOk) {
sal_unregister(obj->op);
}
}
static void linphone_proxy_config_register(LinphoneProxyConfig *obj){
if (obj->reg_sendregister){
LinphoneAddress* proxy=linphone_address_new(obj->reg_proxy);
char* proxy_string;
LinphoneAddress *contact;
ms_message("LinphoneProxyConfig [%p] about to register (LinphoneCore version: %s)",obj,linphone_core_get_version());
proxy_string=linphone_address_as_string_uri_only(proxy);
linphone_address_destroy(proxy);
if (obj->op)
@ -360,8 +429,14 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *obj){
}
ms_free(proxy_string);
} else {
/*stop refresher, just in case*/
if (obj->op) sal_op_stop_refreshing(obj->op);
/* unregister if registered*/
if (obj->state == LinphoneRegistrationProgress) {
linphone_proxy_config_set_state(obj,LinphoneRegistrationCleared,"Registration cleared");
}
_linphone_proxy_config_unregister(obj);
}
}
@ -419,33 +494,43 @@ bool_t linphone_proxy_config_get_dial_escape_plus(const LinphoneProxyConfig *cfg
return cfg->dial_escape_plus;
}
void linphone_proxy_config_enable_statistics(LinphoneProxyConfig *cfg, bool_t val){
cfg->send_statistics = val;
void linphone_proxy_config_enable_quality_reporting(LinphoneProxyConfig *cfg, bool_t val){
cfg->quality_reporting_enabled = val;
}
bool_t linphone_proxy_config_send_statistics_enabled(LinphoneProxyConfig *cfg){
bool_t linphone_proxy_config_quality_reporting_enabled(LinphoneProxyConfig *cfg){
// ensure that collector address is set too!
return cfg->send_statistics && cfg->statistics_collector != NULL;
return cfg->quality_reporting_enabled && cfg->quality_reporting_collector != NULL;
}
void linphone_proxy_config_set_statistics_collector(LinphoneProxyConfig *cfg, const char *collector){
void linphone_proxy_config_set_quality_reporting_interval(LinphoneProxyConfig *cfg, uint8_t interval) {
cfg->quality_reporting_interval = interval;
}
int linphone_proxy_config_get_quality_reporting_interval(LinphoneProxyConfig *cfg) {
return cfg->quality_reporting_interval;
}
void linphone_proxy_config_set_quality_reporting_collector(LinphoneProxyConfig *cfg, const char *collector){
if (collector!=NULL && strlen(collector)>0){
LinphoneAddress *addr=linphone_address_new(collector);
if (!addr || linphone_address_get_username(addr)==NULL){
ms_warning("Invalid sip collector identity: %s",collector);
if (addr)
linphone_address_destroy(addr);
ms_error("Invalid SIP collector URI: %s. Quality reporting will be DISABLED.",collector);
} else {
if (cfg->statistics_collector != NULL)
ms_free(cfg->statistics_collector);
cfg->statistics_collector = ms_strdup(collector);
if (cfg->quality_reporting_collector != NULL){
ms_free(cfg->quality_reporting_collector);
}
cfg->quality_reporting_collector = ms_strdup(collector);
}
if (addr){
linphone_address_destroy(addr);
}
}
}
const char *linphone_proxy_config_get_statistics_collector(const LinphoneProxyConfig *cfg){
return cfg->statistics_collector;
const char *linphone_proxy_config_get_quality_reporting_collector(const LinphoneProxyConfig *cfg){
return cfg->quality_reporting_collector;
}
@ -843,7 +928,19 @@ int linphone_proxy_config_normalize_number(LinphoneProxyConfig *proxy, const cha
**/
int linphone_proxy_config_done(LinphoneProxyConfig *obj)
{
if (!linphone_proxy_config_check(obj->lc,obj)) return -1;
if (!linphone_proxy_config_check(obj->lc,obj))
return -1;
/*check if server address as changed*/
if (linphone_proxy_config_is_server_config_changed(obj)) {
/* server config has changed, need to unregister from previous first*/
if (obj->op) {
_linphone_proxy_config_unregister(obj);
sal_op_set_user_pointer(obj->op,NULL); /*we don't want to receive status for this un register*/
sal_op_unref(obj->op); /*but we keep refresher to handle authentication if needed*/
obj->op=NULL;
}
}
obj->commit=TRUE;
linphone_proxy_config_write_all_to_config_file(obj->lc);
return 0;
@ -908,7 +1005,7 @@ bool_t linphone_proxy_config_publish_enabled(const LinphoneProxyConfig *obj){
/**
* Returns the proxy's SIP address.
**/
const char *linphone_proxy_config_get_addr(const LinphoneProxyConfig *obj){
const char *linphone_proxy_config_get_server_addr(const LinphoneProxyConfig *obj){
return obj->reg_proxy;
}
@ -947,7 +1044,7 @@ void linphone_proxy_config_set_contact_parameters(LinphoneProxyConfig *obj, cons
/**
* Set optional contact parameters that will be added to the contact information sent in the registration, inside the URI.
* @param obj the proxy config object
* @param contact_params a string contaning the additional parameters in text form, like "myparam=something;myparam2=something_else"
* @param contact_uri_params a string containing the additional parameters in text form, like "myparam=something;myparam2=something_else"
*
* The main use case for this function is provide the proxy additional information regarding the user agent, like for example unique identifier or apple push id.
* As an example, the contact address in the SIP register sent will look like <sip:joe@15.128.128.93:50421;apple-push-id=43143-DFE23F-2323-FA2232>.
@ -1006,7 +1103,7 @@ int linphone_core_add_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *cfg){
void linphone_core_remove_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *cfg){
/* check this proxy config is in the list before doing more*/
if (ms_list_find(lc->sip_conf.proxies,cfg)==NULL){
ms_error("linphone_core_remove_proxy_config: LinphoneProxyConfig %p is not known by LinphoneCore (programming error?)",cfg);
ms_error("linphone_core_remove_proxy_config: LinphoneProxyConfig [%p] is not known by LinphoneCore (programming error?)",cfg);
return;
}
lc->sip_conf.proxies=ms_list_remove(lc->sip_conf.proxies,cfg);
@ -1014,8 +1111,11 @@ void linphone_core_remove_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *cf
lc->sip_conf.deleted_proxies=ms_list_append(lc->sip_conf.deleted_proxies,cfg);
cfg->deletion_date=ms_time(NULL);
if (cfg->state==LinphoneRegistrationOk){
/* this will unREGISTER */
/* unREGISTER */
linphone_proxy_config_edit(cfg);
linphone_proxy_config_enable_register(cfg,FALSE);
linphone_proxy_config_done(cfg);
linphone_proxy_config_update(cfg); /*so that it has an effect*/
}
if (lc->default_proxy==cfg){
lc->default_proxy=NULL;
@ -1099,9 +1199,6 @@ void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyC
if (obj->reg_route!=NULL){
lp_config_set_string(config,key,"reg_route",obj->reg_route);
}
if (obj->statistics_collector!=NULL){
lp_config_set_string(config,key,"statistics_collector",obj->statistics_collector);
}
if (obj->reg_identity!=NULL){
lp_config_set_string(config,key,"reg_identity",obj->reg_identity);
}
@ -1111,24 +1208,41 @@ void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyC
if (obj->contact_uri_params!=NULL){
lp_config_set_string(config,key,"contact_uri_parameters",obj->contact_uri_params);
}
if (obj->quality_reporting_collector!=NULL){
lp_config_set_string(config,key,"quality_reporting_collector",obj->quality_reporting_collector);
}
lp_config_set_int(config,key,"quality_reporting_enabled",obj->quality_reporting_enabled);
lp_config_set_int(config,key,"quality_reporting_interval",obj->quality_reporting_interval);
lp_config_set_int(config,key,"reg_expires",obj->expires);
lp_config_set_int(config,key,"reg_sendregister",obj->reg_sendregister);
lp_config_set_int(config,key,"publish",obj->publish);
lp_config_set_int(config, key, "avpf", obj->avpf_enabled);
lp_config_set_int(config, key, "avpf_rr_interval", obj->avpf_rr_interval);
lp_config_set_int(config,key,"dial_escape_plus",obj->dial_escape_plus);
lp_config_set_int(config,key,"send_statistics",obj->send_statistics);
lp_config_set_string(config,key,"dial_prefix",obj->dial_prefix);
lp_config_set_int(config,key,"privacy",obj->privacy);
}
#define CONFIGURE_STRING_VALUE(obj,config,key,param,param_name) \
{\
char* default_value = linphone_proxy_config_get_##param(obj)?ms_strdup(linphone_proxy_config_get_##param(obj)):NULL;\
linphone_proxy_config_set_##param(obj,lp_config_get_string(config,key,param_name,default_value)); \
if ( default_value) ms_free(default_value); \
}
LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config, int index)
#define CONFIGURE_BOOL_VALUE(obj,config,key,param,param_name) \
linphone_proxy_config_enable_##param(obj,lp_config_get_int(config,key,param_name,linphone_proxy_config_##param##_enabled(obj)));
#define CONFIGURE_INT_VALUE(obj,config,key,param,param_name) \
linphone_proxy_config_set_##param(obj,lp_config_get_int(config,key,param_name,linphone_proxy_config_get_##param(obj)));
LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LinphoneCore* lc, int index)
{
const char *tmp;
const char *identity;
const char *proxy;
LinphoneProxyConfig *cfg;
char key[50];
LpConfig *config=lc->config;
sprintf(key,"proxy_%i",index);
@ -1136,39 +1250,33 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config
return NULL;
}
cfg=linphone_proxy_config_new();
cfg=linphone_core_create_proxy_config(lc);
identity=lp_config_get_string(config,key,"reg_identity",NULL);
proxy=lp_config_get_string(config,key,"reg_proxy",NULL);
CONFIGURE_STRING_VALUE(cfg,config,key,identity,"reg_identity")
CONFIGURE_STRING_VALUE(cfg,config,key,server_addr,"reg_proxy")
CONFIGURE_STRING_VALUE(cfg,config,key,route,"reg_route")
linphone_proxy_config_set_identity(cfg,identity);
linphone_proxy_config_set_server_addr(cfg,proxy);
CONFIGURE_BOOL_VALUE(cfg,config,key,quality_reporting,"quality_reporting_enabled")
tmp=lp_config_get_string(config,key,"reg_route",NULL);
if (tmp!=NULL) linphone_proxy_config_set_route(cfg,tmp);
CONFIGURE_STRING_VALUE(cfg,config,key,quality_reporting_collector,"quality_reporting_collector")
tmp=lp_config_get_string(config,key,"statistics_collector",NULL);
if (tmp!=NULL) linphone_proxy_config_set_statistics_collector(cfg,tmp);
linphone_proxy_config_enable_statistics(cfg,lp_config_get_int(config,key,"send_statistics",0));
CONFIGURE_INT_VALUE(cfg,config,key,quality_reporting_interval,"quality_reporting_interval")
linphone_proxy_config_set_contact_parameters(cfg,lp_config_get_string(config,key,"contact_parameters",NULL));
CONFIGURE_STRING_VALUE(cfg,config,key,contact_parameters,"contact_parameters")
CONFIGURE_STRING_VALUE(cfg,config,key,contact_uri_parameters,"contact_uri_parameters")
linphone_proxy_config_set_contact_uri_parameters(cfg,lp_config_get_string(config,key,"contact_uri_parameters",NULL));
linphone_proxy_config_expires(cfg,lp_config_get_int(config,key,"reg_expires",lp_config_get_default_int(config,"proxy","reg_expires",600)));
linphone_proxy_config_enableregister(cfg,lp_config_get_int(config,key,"reg_sendregister",0));
linphone_proxy_config_enable_publish(cfg,lp_config_get_int(config,key,"publish",0));
linphone_proxy_config_set_dial_escape_plus(cfg,lp_config_get_int(config,key,"dial_escape_plus",lp_config_get_default_int(config,"proxy","dial_escape_plus",0)));
linphone_proxy_config_set_dial_prefix(cfg,lp_config_get_string(config,key,"dial_prefix",lp_config_get_default_string(config,"proxy","dial_prefix",NULL)));
CONFIGURE_INT_VALUE(cfg,config,key,expires,"reg_expires")
CONFIGURE_BOOL_VALUE(cfg,config,key,register,"reg_sendregister")
CONFIGURE_BOOL_VALUE(cfg,config,key,publish,"publish")
CONFIGURE_BOOL_VALUE(cfg,config,key,avpf,"avpf")
CONFIGURE_INT_VALUE(cfg,config,key,avpf_rr_interval,"avpf_rr_interval")
CONFIGURE_INT_VALUE(cfg,config,key,dial_escape_plus,"dial_escape_plus")
CONFIGURE_STRING_VALUE(cfg,config,key,dial_prefix,"dial_prefix")
tmp=lp_config_get_string(config,key,"type",NULL);
if (tmp!=NULL && strlen(tmp)>0)
linphone_proxy_config_set_sip_setup(cfg,tmp);
linphone_proxy_config_set_privacy(cfg,lp_config_get_int(config,key,"privacy",lp_config_get_default_int(config,"proxy","privacy",LinphonePrivacyDefault)));
CONFIGURE_INT_VALUE(cfg,config,key,privacy,"privacy")
return cfg;
}
@ -1472,3 +1580,20 @@ int linphone_proxy_config_get_publish_expires(const LinphoneProxyConfig *obj) {
}
}
void linphone_proxy_config_enable_avpf(LinphoneProxyConfig *cfg, bool_t enable) {
cfg->avpf_enabled = enable;
}
bool_t linphone_proxy_config_avpf_enabled(LinphoneProxyConfig *cfg) {
return cfg->avpf_enabled;
}
void linphone_proxy_config_set_avpf_rr_interval(LinphoneProxyConfig *cfg, uint8_t interval) {
if (interval > 5) interval = 5;
cfg->avpf_rr_interval = interval;
}
uint8_t linphone_proxy_config_get_avpf_rr_interval(const LinphoneProxyConfig *cfg) {
return cfg->avpf_rr_interval;
}

View file

@ -28,18 +28,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <math.h>
/***************************************************************************
* TODO / REMINDER LIST
****************************************************************************/
/*For codecs that are able to change sample rates, the lowest and highest sample rates MUST be reported (e.g., 8000;16000).
moslq == moscq
video: what happens if doing stop/resume?
one time value: average? worst value?
rlq value: need algo to compute it*/
/***************************************************************************
* END OF TODO / REMINDER LIST
****************************************************************************/
#define STR_REASSIGN(dest, src) {\
if (dest != NULL) \
ms_free(dest); \
@ -73,13 +61,13 @@ static void append_to_buffer_valist(char **buff, size_t *buff_size, size_t *offs
/*if we are out of memory, we add some size to buffer*/
if (ret == BELLE_SIP_BUFFER_OVERFLOW) {
/*some compilers complain that size_t cannot be formatted as unsigned long, hence forcing cast*/
ms_warning("Buffer was too small to contain the whole report - doubling its size from %lu to %lu",
(unsigned long)*buff_size, (unsigned long)2 * *buff_size);
ms_warning("QualityReporting: Buffer was too small to contain the whole report - increasing its size from %lu to %lu",
(unsigned long)*buff_size, (unsigned long)*buff_size + 2048);
*buff_size += 2048;
*buff = (char *) ms_realloc(*buff, *buff_size);
*offset = prevoffset;
/*recall myself since we did not write all things into the buffer but
/*recall itself since we did not write all things into the buffer but
only a part of it*/
append_to_buffer_valist(buff, buff_size, offset, fmt, args);
}
@ -92,44 +80,84 @@ static void append_to_buffer(char **buff, size_t *buff_size, size_t *offset, con
va_end(args);
}
static void reset_avg_metrics(reporting_session_report_t * report){
int i;
reporting_content_metrics_t * metrics[2] = {&report->local_metrics, &report->remote_metrics};
for (i = 0; i < 2; i++) {
metrics[i]->rtcp_sr_count = 0;
metrics[i]->rtcp_xr_count = 0;
metrics[i]->jitter_buffer.nominal = 0;
metrics[i]->jitter_buffer.max = 0;
metrics[i]->quality_estimates.moslq = 0;
metrics[i]->quality_estimates.moscq = 0;
metrics[i]->delay.round_trip_delay = 0;
}
report->last_report_date = ms_time(NULL);
}
#define APPEND_IF_NOT_NULL_STR(buffer, size, offset, fmt, arg) if (arg != NULL) append_to_buffer(buffer, size, offset, fmt, arg)
#define APPEND_IF_NUM_IN_RANGE(buffer, size, offset, fmt, arg, inf, sup) if (inf <= arg && arg <= sup) append_to_buffer(buffer, size, offset, fmt, arg)
#define APPEND_IF(buffer, size, offset, fmt, arg, cond) if (cond) append_to_buffer(buffer, size, offset, fmt, arg)
#define IF_NUM_IN_RANGE(num, inf, sup, statement) if (inf <= num && num <= sup) statement
static bool_t are_metrics_filled(const reporting_content_metrics_t rm) {
IF_NUM_IN_RANGE(rm.packet_loss.network_packet_loss_rate, 0, 255, return TRUE);
IF_NUM_IN_RANGE(rm.packet_loss.jitter_buffer_discard_rate, 0, 255, return TRUE);
IF_NUM_IN_RANGE(rm.quality_estimates.moslq, 1, 5, return TRUE);
IF_NUM_IN_RANGE(rm.quality_estimates.moscq, 1, 5, return TRUE);
#define METRICS_PACKET_LOSS 1 << 0
#define METRICS_QUALITY_ESTIMATES 1 << 1
#define METRICS_SESSION_DESCRIPTION 1 << 2
#define METRICS_JITTER_BUFFER 1 << 3
#define METRICS_DELAY 1 << 4
#define METRICS_SIGNAL 1 << 5
#define METRICS_ADAPTIVE_ALGORITHM 1 << 6
/*since these are same values than local ones, do not check them*/
/*if (rm.session_description.payload_type != -1) return TRUE;*/
/*if (rm.session_description.payload_desc != NULL) return TRUE;*/
/*if (rm.session_description.sample_rate != -1) return TRUE;*/
if (rm.session_description.frame_duration != -1) return TRUE;
/*if (rm.session_description.fmtp != NULL) return TRUE;*/
if (rm.session_description.packet_loss_concealment != -1) return TRUE;
static uint8_t are_metrics_filled(const reporting_content_metrics_t rm) {
uint8_t ret = 0;
IF_NUM_IN_RANGE(rm.jitter_buffer.adaptive, 0, 3, return TRUE);
IF_NUM_IN_RANGE(rm.jitter_buffer.nominal, 0, 65535, return TRUE);
IF_NUM_IN_RANGE(rm.jitter_buffer.max, 0, 65535, return TRUE);
IF_NUM_IN_RANGE(rm.jitter_buffer.abs_max, 0, 65535, return TRUE);
IF_NUM_IN_RANGE(rm.packet_loss.network_packet_loss_rate, 0, 255, ret|=METRICS_PACKET_LOSS);
IF_NUM_IN_RANGE(rm.packet_loss.jitter_buffer_discard_rate, 0, 255, ret|=METRICS_PACKET_LOSS);
IF_NUM_IN_RANGE(rm.delay.round_trip_delay, 0, 65535, return TRUE);
IF_NUM_IN_RANGE(rm.delay.end_system_delay, 0, 65535, return TRUE);
IF_NUM_IN_RANGE(rm.delay.symm_one_way_delay, 0, 65535, return TRUE);
IF_NUM_IN_RANGE(rm.delay.interarrival_jitter, 0, 65535, return TRUE);
IF_NUM_IN_RANGE(rm.delay.mean_abs_jitter, 0, 65535, return TRUE);
if (rm.session_description.payload_type != -1) ret|=METRICS_SESSION_DESCRIPTION;
if (rm.session_description.payload_desc != NULL) ret|=METRICS_SESSION_DESCRIPTION;
if (rm.session_description.sample_rate != -1) ret|=METRICS_SESSION_DESCRIPTION;
if (rm.session_description.fmtp != NULL) ret|=METRICS_SESSION_DESCRIPTION;
if (rm.signal.level != 127) return TRUE;
if (rm.signal.noise_level != 127) return TRUE;
IF_NUM_IN_RANGE(rm.jitter_buffer.adaptive, 0, 3, ret|=METRICS_JITTER_BUFFER);
IF_NUM_IN_RANGE(rm.jitter_buffer.abs_max, 0, 65535, ret|=METRICS_JITTER_BUFFER);
IF_NUM_IN_RANGE(rm.quality_estimates.rlq, 1, 120, return TRUE);
IF_NUM_IN_RANGE(rm.quality_estimates.rcq, 1, 120, return TRUE);
IF_NUM_IN_RANGE(rm.delay.end_system_delay, 0, 65535, ret|=METRICS_DELAY);
IF_NUM_IN_RANGE(rm.delay.interarrival_jitter, 0, 65535, ret|=METRICS_DELAY);
IF_NUM_IN_RANGE(rm.delay.mean_abs_jitter, 0, 65535, ret|=METRICS_DELAY);
return FALSE;
if (rm.signal.level != 127) ret|=METRICS_SIGNAL;
if (rm.signal.noise_level != 127) ret|=METRICS_SIGNAL;
IF_NUM_IN_RANGE(rm.quality_estimates.moslq, 1, 5, ret|=METRICS_QUALITY_ESTIMATES);
IF_NUM_IN_RANGE(rm.quality_estimates.moscq, 1, 5, ret|=METRICS_QUALITY_ESTIMATES);
if (rm.rtcp_xr_count>0){
IF_NUM_IN_RANGE(rm.jitter_buffer.nominal/rm.rtcp_xr_count, 0, 65535, ret|=METRICS_JITTER_BUFFER);
IF_NUM_IN_RANGE(rm.jitter_buffer.max/rm.rtcp_xr_count, 0, 65535, ret|=METRICS_JITTER_BUFFER);
}
if (rm.rtcp_sr_count+rm.rtcp_xr_count>0){
IF_NUM_IN_RANGE(rm.delay.round_trip_delay/(rm.rtcp_sr_count+rm.rtcp_xr_count), 0, 65535, ret|=METRICS_DELAY);
}
return ret;
}
static bool_t quality_reporting_enabled(const LinphoneCall * call) {
return (call->dest_proxy != NULL && linphone_proxy_config_quality_reporting_enabled(call->dest_proxy));
}
static bool_t media_report_enabled(LinphoneCall * call, int stats_type){
if (! quality_reporting_enabled(call))
return FALSE;
if (stats_type == LINPHONE_CALL_STATS_VIDEO && !linphone_call_params_video_enabled(linphone_call_get_current_params(call)))
return FALSE;
return (call->log->reporting.reports[stats_type] != NULL);
}
static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * offset, const reporting_content_metrics_t rm) {
@ -140,79 +168,83 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off
/*char * gap_loss_density_str = NULL;*/
char * moslq_str = NULL;
char * moscq_str = NULL;
uint8_t available_metrics = are_metrics_filled(rm);
if (rm.timestamps.start > 0)
timestamps_start_str = linphone_timestamp_to_rfc3339_string(rm.timestamps.start);
if (rm.timestamps.stop > 0)
timestamps_stop_str = linphone_timestamp_to_rfc3339_string(rm.timestamps.stop);
IF_NUM_IN_RANGE(rm.packet_loss.network_packet_loss_rate, 0, 255, network_packet_loss_rate_str = float_to_one_decimal_string(rm.packet_loss.network_packet_loss_rate / 256));
IF_NUM_IN_RANGE(rm.packet_loss.jitter_buffer_discard_rate, 0, 255, jitter_buffer_discard_rate_str = float_to_one_decimal_string(rm.packet_loss.jitter_buffer_discard_rate / 256));
/*IF_NUM_IN_RANGE(rm.burst_gap_loss.gap_loss_density, 0, 10, gap_loss_density_str = float_to_one_decimal_string(rm.burst_gap_loss.gap_loss_density));*/
IF_NUM_IN_RANGE(rm.quality_estimates.moslq, 1, 5, moslq_str = float_to_one_decimal_string(rm.quality_estimates.moslq));
IF_NUM_IN_RANGE(rm.quality_estimates.moscq, 1, 5, moscq_str = float_to_one_decimal_string(rm.quality_estimates.moscq));
append_to_buffer(buffer, size, offset, "Timestamps:");
APPEND_IF_NOT_NULL_STR(buffer, size, offset, " START=%s", timestamps_start_str);
APPEND_IF_NOT_NULL_STR(buffer, size, offset, " STOP=%s", timestamps_stop_str);
append_to_buffer(buffer, size, offset, "\r\nSessionDesc:");
APPEND_IF(buffer, size, offset, " PT=%d", rm.session_description.payload_type, rm.session_description.payload_type != -1);
APPEND_IF_NOT_NULL_STR(buffer, size, offset, " PD=%s", rm.session_description.payload_desc);
APPEND_IF(buffer, size, offset, " SR=%d", rm.session_description.sample_rate, rm.session_description.sample_rate != -1);
APPEND_IF(buffer, size, offset, " FD=%d", rm.session_description.frame_duration, rm.session_description.frame_duration != -1);
/*append_to_buffer(buffer, size, offset, " FO=%d", rm.session_description.frame_ocets);*/
/*append_to_buffer(buffer, size, offset, " FPP=%d", rm.session_description.frames_per_sec);*/
/*append_to_buffer(buffer, size, offset, " PPS=%d", rm.session_description.packets_per_sec);*/
APPEND_IF_NOT_NULL_STR(buffer, size, offset, " FMTP=\"%s\"", rm.session_description.fmtp);
APPEND_IF(buffer, size, offset, " PLC=%d", rm.session_description.packet_loss_concealment, rm.session_description.packet_loss_concealment != -1);
/*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " SSUP=%s", rm.session_description.silence_suppression_state);*/
if ((available_metrics & METRICS_SESSION_DESCRIPTION) != 0){
append_to_buffer(buffer, size, offset, "\r\nSessionDesc:");
APPEND_IF(buffer, size, offset, " PT=%d", rm.session_description.payload_type, rm.session_description.payload_type != -1);
APPEND_IF_NOT_NULL_STR(buffer, size, offset, " PD=%s", rm.session_description.payload_desc);
APPEND_IF(buffer, size, offset, " SR=%d", rm.session_description.sample_rate, rm.session_description.sample_rate != -1);
APPEND_IF(buffer, size, offset, " FD=%d", rm.session_description.frame_duration, rm.session_description.frame_duration != -1);
APPEND_IF_NOT_NULL_STR(buffer, size, offset, " FMTP=\"%s\"", rm.session_description.fmtp);
APPEND_IF(buffer, size, offset, " PLC=%d", rm.session_description.packet_loss_concealment, rm.session_description.packet_loss_concealment != -1);
}
append_to_buffer(buffer, size, offset, "\r\nJitterBuffer:");
APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBA=%d", rm.jitter_buffer.adaptive, 0, 3);
/*APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBR=%d", rm.jitter_buffer.rate, 0, 15);*/
APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBN=%d", rm.jitter_buffer.nominal, 0, 65535);
APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBM=%d", rm.jitter_buffer.max, 0, 65535);
APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBX=%d", rm.jitter_buffer.abs_max, 0, 65535);
if ((available_metrics & METRICS_JITTER_BUFFER) != 0){
append_to_buffer(buffer, size, offset, "\r\nJitterBuffer:");
APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBA=%d", rm.jitter_buffer.adaptive, 0, 3);
if (rm.rtcp_xr_count){
APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBN=%d", rm.jitter_buffer.nominal/rm.rtcp_xr_count, 0, 65535);
APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBM=%d", rm.jitter_buffer.max/rm.rtcp_xr_count, 0, 65535);
}
APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBX=%d", rm.jitter_buffer.abs_max, 0, 65535);
append_to_buffer(buffer, size, offset, "\r\nPacketLoss:");
APPEND_IF_NOT_NULL_STR(buffer, size, offset, " NLR=%s", network_packet_loss_rate_str);
APPEND_IF_NOT_NULL_STR(buffer, size, offset, " JDR=%s", jitter_buffer_discard_rate_str);
append_to_buffer(buffer, size, offset, "\r\nPacketLoss:");
IF_NUM_IN_RANGE(rm.packet_loss.network_packet_loss_rate, 0, 255, network_packet_loss_rate_str = float_to_one_decimal_string(rm.packet_loss.network_packet_loss_rate / 256));
IF_NUM_IN_RANGE(rm.packet_loss.jitter_buffer_discard_rate, 0, 255, jitter_buffer_discard_rate_str = float_to_one_decimal_string(rm.packet_loss.jitter_buffer_discard_rate / 256));
/*append_to_buffer(buffer, size, offset, "\r\nBurstGapLoss:");*/
/* append_to_buffer(buffer, size, offset, " BLD=%d", rm.burst_gap_loss.burst_loss_density);*/
/* append_to_buffer(buffer, size, offset, " BD=%d", rm.burst_gap_loss.burst_duration);*/
/* APPEND_IF_NOT_NULL_STR(buffer, size, offset, " GLD=%s", gap_loss_density_str);*/
/* append_to_buffer(buffer, size, offset, " GD=%d", rm.burst_gap_loss.gap_duration);*/
/* append_to_buffer(buffer, size, offset, " GMIN=%d", rm.burst_gap_loss.min_gap_threshold);*/
APPEND_IF_NOT_NULL_STR(buffer, size, offset, " NLR=%s", network_packet_loss_rate_str);
APPEND_IF_NOT_NULL_STR(buffer, size, offset, " JDR=%s", jitter_buffer_discard_rate_str);
}
append_to_buffer(buffer, size, offset, "\r\nDelay:");
APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " RTD=%d", rm.delay.round_trip_delay, 0, 65535);
APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " ESD=%d", rm.delay.end_system_delay, 0, 65535);
/*APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " OWD=%d", rm.delay.one_way_delay, 0, 65535);*/
APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " SOWD=%d", rm.delay.symm_one_way_delay, 0, 65535);
APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " IAJ=%d", rm.delay.interarrival_jitter, 0, 65535);
APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " MAJ=%d", rm.delay.mean_abs_jitter, 0, 65535);
/*append_to_buffer(buffer, size, offset, "\r\nBurstGapLoss:");*/
/*IF_NUM_IN_RANGE(rm.burst_gap_loss.gap_loss_density, 0, 10, gap_loss_density_str = float_to_one_decimal_string(rm.burst_gap_loss.gap_loss_density));*/
/* append_to_buffer(buffer, size, offset, " BLD=%d", rm.burst_gap_loss.burst_loss_density);*/
/* append_to_buffer(buffer, size, offset, " BD=%d", rm.burst_gap_loss.burst_duration);*/
/* APPEND_IF_NOT_NULL_STR(buffer, size, offset, " GLD=%s", gap_loss_density_str);*/
/* append_to_buffer(buffer, size, offset, " GD=%d", rm.burst_gap_loss.gap_duration);*/
/* append_to_buffer(buffer, size, offset, " GMIN=%d", rm.burst_gap_loss.min_gap_threshold);*/
append_to_buffer(buffer, size, offset, "\r\nSignal:");
APPEND_IF(buffer, size, offset, " SL=%d", rm.signal.level, rm.signal.level != 127);
APPEND_IF(buffer, size, offset, " NL=%d", rm.signal.noise_level, rm.signal.noise_level != 127);
/*append_to_buffer(buffer, size, offset, " RERL=%d", rm.signal.residual_echo_return_loss);*/
if ((available_metrics & METRICS_DELAY) != 0){
append_to_buffer(buffer, size, offset, "\r\nDelay:");
if (rm.rtcp_xr_count+rm.rtcp_sr_count){
APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " RTD=%d", rm.delay.round_trip_delay/(rm.rtcp_xr_count+rm.rtcp_sr_count), 0, 65535);
}
APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " ESD=%d", rm.delay.end_system_delay, 0, 65535);
APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " IAJ=%d", rm.delay.interarrival_jitter, 0, 65535);
APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " MAJ=%d", rm.delay.mean_abs_jitter, 0, 65535);
}
if ((available_metrics & METRICS_SIGNAL) != 0){
append_to_buffer(buffer, size, offset, "\r\nSignal:");
APPEND_IF(buffer, size, offset, " SL=%d", rm.signal.level, rm.signal.level != 127);
APPEND_IF(buffer, size, offset, " NL=%d", rm.signal.noise_level, rm.signal.noise_level != 127);
}
/*if quality estimates metrics are available, rtcp_xr_count should be always not null*/
if ((available_metrics & METRICS_QUALITY_ESTIMATES) != 0){
IF_NUM_IN_RANGE(rm.quality_estimates.moslq, 1, 5, moslq_str = float_to_one_decimal_string(rm.quality_estimates.moslq));
IF_NUM_IN_RANGE(rm.quality_estimates.moscq, 1, 5, moscq_str = float_to_one_decimal_string(rm.quality_estimates.moscq));
append_to_buffer(buffer, size, offset, "\r\nQualityEst:");
APPEND_IF_NOT_NULL_STR(buffer, size, offset, " MOSLQ=%s", moslq_str);
APPEND_IF_NOT_NULL_STR(buffer, size, offset, " MOSCQ=%s", moscq_str);
}
if (rm.user_agent!=NULL){
append_to_buffer(buffer, size, offset, "\r\nLinphoneExt:");
APPEND_IF_NOT_NULL_STR(buffer, size, offset, " UA=\"%s\"", rm.user_agent);
}
append_to_buffer(buffer, size, offset, "\r\nQualityEst:");
APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " RLQ=%d", rm.quality_estimates.rlq, 1, 120);
/*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " RLQEstAlg=%s", rm.quality_estimates.rlqestalg);*/
APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " RCQ=%d", rm.quality_estimates.rcq, 1, 120);
/*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " RCQEstAlgo=%s", rm.quality_estimates.rcqestalg);*/
/*append_to_buffer(buffer, size, offset, " EXTRI=%d", rm.quality_estimates.extri);*/
/*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " ExtRIEstAlg=%s", rm.quality_estimates.extriestalg);*/
/*append_to_buffer(buffer, size, offset, " EXTRO=%d", rm.quality_estimates.extro);*/
/*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " ExtROEstAlg=%s", rm.quality_estimates.extroutestalg);*/
APPEND_IF_NOT_NULL_STR(buffer, size, offset, " MOSLQ=%s", moslq_str);
/*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " MOSLQEstAlgo=%s", rm.quality_estimates.moslqestalg);*/
APPEND_IF_NOT_NULL_STR(buffer, size, offset, " MOSCQ=%s", moscq_str);
/*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " MOSCQEstAlgo=%s", rm.quality_estimates.moscqestalg);*/
/*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " QoEEstAlg=%s", rm.quality_estimates.qoestalg);*/
append_to_buffer(buffer, size, offset, "\r\n");
ms_free(timestamps_start_str);
@ -224,151 +256,252 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off
ms_free(moscq_str);
}
static void reporting_publish(const LinphoneCall* call, const reporting_session_report_t * report) {
static int send_report(LinphoneCall* call, reporting_session_report_t * report, const char * report_event) {
LinphoneContent content = {0};
LinphoneAddress *addr;
int expires = -1;
size_t offset = 0;
size_t size = 2048;
char * buffer;
int ret = 0;
/*if we are on a low bandwidth network, do not send reports to not overload it*/
if (linphone_call_params_low_bandwidth_enabled(linphone_call_get_current_params(call))){
ms_warning("QualityReporting[%p]: Avoid sending reports on low bandwidth network", call);
ret = 1;
goto end;
}
/*if the call was hung up too early, we might have invalid IPs information
in that case, we abort the report since it's not useful data*/
if (report->info.local_addr.ip == NULL || strlen(report->info.local_addr.ip) == 0
|| report->info.remote_addr.ip == NULL || strlen(report->info.remote_addr.ip) == 0) {
ms_warning("The call was hang up too early (duration: %d sec) and IP could "
"not be retrieved so dropping this report", linphone_call_get_duration(call));
return;
ms_warning("QualityReporting[%p]: Trying to submit a %s too early (call duration: %d sec) but %s IP could "
"not be retrieved so dropping this report"
, call
, report_event
, linphone_call_get_duration(call)
, (report->info.local_addr.ip == NULL || strlen(report->info.local_addr.ip) == 0) ? "local" : "remote");
ret = 2;
goto end;
}
addr = linphone_address_new(linphone_proxy_config_get_quality_reporting_collector(call->dest_proxy));
if (addr == NULL) {
ms_warning("QualityReporting[%p]: Asked to submit reporting statistics but no collector address found"
, call);
ret = 3;
goto end;
}
buffer = (char *) ms_malloc(size);
content.type = ms_strdup("application");
content.subtype = ms_strdup("vq-rtcpxr");
append_to_buffer(&buffer, &size, &offset, "VQSessionReport: CallTerm\r\n");
append_to_buffer(&buffer, &size, &offset, "%s\r\n", report_event);
append_to_buffer(&buffer, &size, &offset, "CallID: %s\r\n", report->info.call_id);
append_to_buffer(&buffer, &size, &offset, "LocalID: %s\r\n", report->info.local_id);
append_to_buffer(&buffer, &size, &offset, "RemoteID: %s\r\n", report->info.remote_id);
append_to_buffer(&buffer, &size, &offset, "LocalID: %s\r\n", report->info.local_addr.id);
append_to_buffer(&buffer, &size, &offset, "RemoteID: %s\r\n", report->info.remote_addr.id);
append_to_buffer(&buffer, &size, &offset, "OrigID: %s\r\n", report->info.orig_id);
APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "LocalGroup: %s\r\n", report->info.local_group);
APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "RemoteGroup: %s\r\n", report->info.remote_group);
append_to_buffer(&buffer, &size, &offset, "LocalAddr: IP=%s PORT=%d SSRC=%d\r\n", report->info.local_addr.ip, report->info.local_addr.port, report->info.local_addr.ssrc);
APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "LocalMAC: %s\r\n", report->info.local_mac_addr);
append_to_buffer(&buffer, &size, &offset, "RemoteAddr: IP=%s PORT=%d SSRC=%d\r\n", report->info.remote_addr.ip, report->info.remote_addr.port, report->info.remote_addr.ssrc);
APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "RemoteMAC: %s\r\n", report->info.remote_mac_addr);
APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "LocalGroup: %s\r\n", report->info.local_addr.group);
APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "RemoteGroup: %s\r\n", report->info.remote_addr.group);
append_to_buffer(&buffer, &size, &offset, "LocalAddr: IP=%s PORT=%d SSRC=%u\r\n", report->info.local_addr.ip, report->info.local_addr.port, report->info.local_addr.ssrc);
APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "LocalMAC: %s\r\n", report->info.local_addr.mac);
append_to_buffer(&buffer, &size, &offset, "RemoteAddr: IP=%s PORT=%d SSRC=%u\r\n", report->info.remote_addr.ip, report->info.remote_addr.port, report->info.remote_addr.ssrc);
APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "RemoteMAC: %s\r\n", report->info.remote_addr.mac);
append_to_buffer(&buffer, &size, &offset, "LocalMetrics:\r\n");
append_metrics_to_buffer(&buffer, &size, &offset, report->local_metrics);
if (are_metrics_filled(report->remote_metrics)) {
if (are_metrics_filled(report->remote_metrics)!=0) {
append_to_buffer(&buffer, &size, &offset, "RemoteMetrics:\r\n");
append_metrics_to_buffer(&buffer, &size, &offset, report->remote_metrics);
}
APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "DialogID: %s\r\n", report->dialog_id);
content.data = buffer;
content.size = strlen((char*)content.data);
addr = linphone_address_new(call->dest_proxy->statistics_collector);
if (addr != NULL) {
linphone_core_publish(call->core, addr, "vq-rtcpxr", expires, &content);
linphone_address_destroy(addr);
} else {
ms_warning("Asked to submit reporting statistics but no collector address found");
if (report->qos_analyzer.timestamp!=NULL){
append_to_buffer(&buffer, &size, &offset, "AdaptiveAlg:");
APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, " NAME=\"%s\"", report->qos_analyzer.name);
APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, " TS=\"%s\"", report->qos_analyzer.timestamp);
APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, " IN_LEG=\"%s\"", report->qos_analyzer.input_leg);
APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, " IN=\"%s\"", report->qos_analyzer.input);
APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, " OUT_LEG=\"%s\"", report->qos_analyzer.output_leg);
APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, " OUT=\"%s\"", report->qos_analyzer.output);
append_to_buffer(&buffer, &size, &offset, "\r\n");
}
content.data = buffer;
content.size = strlen(buffer);
if (call->log->reporting.on_report_sent != NULL){
call->log->reporting.on_report_sent(
call,
(report==call->log->reporting.reports[0])?LINPHONE_CALL_STATS_AUDIO:LINPHONE_CALL_STATS_VIDEO,
&content);
}
if (! linphone_core_publish(call->core, addr, "vq-rtcpxr", expires, &content)){
ret=4;
} else {
reset_avg_metrics(report);
STR_REASSIGN(report->qos_analyzer.timestamp, NULL);
STR_REASSIGN(report->qos_analyzer.input_leg, NULL);
STR_REASSIGN(report->qos_analyzer.input, NULL);
STR_REASSIGN(report->qos_analyzer.output_leg, NULL);
STR_REASSIGN(report->qos_analyzer.output, NULL);
}
linphone_address_destroy(addr);
linphone_content_uninit(&content);
end:
ms_message("QualityReporting[%p]: Send '%s' with status %d",
call,
report_event,
ret
);
return ret;
}
static const SalStreamDescription * get_media_stream_for_desc(const SalMediaDescription * smd, SalStreamType sal_stream_type) {
int count;
if (smd != NULL) {
for (count = 0; count < smd->n_total_streams; ++count) {
for (count = 0; count < smd->nb_streams; ++count) {
if (smd->streams[count].type == sal_stream_type) {
return &smd->streams[count];
}
}
}
if (smd == NULL || count == smd->n_total_streams) {
ms_warning("Could not find the associated stream of type %d", sal_stream_type);
}
return NULL;
}
static void reporting_update_ip(LinphoneCall * call, int stats_type) {
static void update_ip(LinphoneCall * call, int stats_type) {
SalStreamType sal_stream_type = (stats_type == LINPHONE_CALL_STATS_AUDIO) ? SalAudio : SalVideo;
if (call->log->reports[stats_type] != NULL) {
const SalStreamDescription * local_desc = get_media_stream_for_desc(call->localdesc, sal_stream_type);
const SalStreamDescription * remote_desc = get_media_stream_for_desc(sal_call_get_remote_media_description(call->op), sal_stream_type);
const SalStreamDescription * local_desc = get_media_stream_for_desc(call->localdesc, sal_stream_type);
const SalStreamDescription * remote_desc = get_media_stream_for_desc(sal_call_get_remote_media_description(call->op), sal_stream_type);
/*local info are always up-to-date and correct*/
if (local_desc != NULL) {
call->log->reports[stats_type]->info.local_addr.port = local_desc->rtp_port;
STR_REASSIGN(call->log->reports[stats_type]->info.local_addr.ip, ms_strdup(local_desc->rtp_addr));
if (local_desc != NULL) {
/*since this function might be called for video stream AFTER it has been uninitialized, local description might
be invalid. In any other case, IP/port should be always filled and valid*/
if (local_desc->rtp_addr != NULL && strlen(local_desc->rtp_addr) > 0) {
call->log->reporting.reports[stats_type]->info.local_addr.port = local_desc->rtp_port;
STR_REASSIGN(call->log->reporting.reports[stats_type]->info.local_addr.ip, ms_strdup(local_desc->rtp_addr));
}
}
if (remote_desc != NULL) {
/*port is always stored in stream description struct*/
call->log->reports[stats_type]->info.remote_addr.port = remote_desc->rtp_port;
if (remote_desc != NULL) {
/*port is always stored in stream description struct*/
call->log->reporting.reports[stats_type]->info.remote_addr.port = remote_desc->rtp_port;
/*for IP it can be not set if we are using a direct route*/
if (remote_desc->rtp_addr != NULL && strlen(remote_desc->rtp_addr) > 0) {
STR_REASSIGN(call->log->reports[stats_type]->info.remote_addr.ip, ms_strdup(remote_desc->rtp_addr));
} else {
STR_REASSIGN(call->log->reports[stats_type]->info.remote_addr.ip, ms_strdup(sal_call_get_remote_media_description(call->op)->addr));
/*for IP it can be not set if we are using a direct route*/
if (remote_desc->rtp_addr != NULL && strlen(remote_desc->rtp_addr) > 0) {
STR_REASSIGN(call->log->reporting.reports[stats_type]->info.remote_addr.ip, ms_strdup(remote_desc->rtp_addr));
} else {
STR_REASSIGN(call->log->reporting.reports[stats_type]->info.remote_addr.ip, ms_strdup(sal_call_get_remote_media_description(call->op)->addr));
}
}
}
typedef struct on_action_suggested_struct{
LinphoneCall *call;
int stats_type;
}on_action_suggested_struct_t;
static void qos_analyzer_on_action_suggested(void *user_data, int datac, const char** datav){
on_action_suggested_struct_t * oass = (on_action_suggested_struct_t *)user_data;
LinphoneCall *call = oass->call;
reporting_session_report_t *report = call->log->reporting.reports[oass->stats_type];
char * appendbuf;
int i;
int ptime = -1;
int bitrate[2] = {-1, -1};
int up_bw[2] = {-1, -1};
int down_bw[2] = {-1, -1};
MediaStream *streams[2] = {(MediaStream*) call->audiostream, (MediaStream *) call->videostream};
for (i=0;i<2;i++){
if (streams[i]!=NULL){
if (streams[i]->encoder!=NULL){
if (ms_filter_has_method(streams[i]->encoder,MS_FILTER_GET_BITRATE)){
ms_filter_call_method(streams[i]->encoder,MS_FILTER_GET_BITRATE,&bitrate[i]);
bitrate[i] /= 1000.f;
}
}
up_bw[i] = media_stream_get_up_bw(streams[i])/1000.f;
down_bw[i] = media_stream_get_down_bw(streams[i])/1000.f;
}
}
if (call->audiostream!=NULL){
if (call->audiostream->ms.encoder!=NULL){
if(ms_filter_has_method(call->audiostream->ms.encoder,MS_AUDIO_ENCODER_GET_PTIME)){
ms_filter_call_method(call->audiostream->ms.encoder,MS_AUDIO_ENCODER_GET_PTIME,&ptime);
}
}
}
}
static bool_t reporting_enabled(const LinphoneCall * call) {
return (call->dest_proxy != NULL && linphone_proxy_config_send_statistics_enabled(call->dest_proxy));
appendbuf=ms_strdup_printf("%s%d;", report->qos_analyzer.timestamp?report->qos_analyzer.timestamp:"", ms_time(0));
STR_REASSIGN(report->qos_analyzer.timestamp,appendbuf);
STR_REASSIGN(report->qos_analyzer.input_leg, ms_strdup_printf("%s aenc_ptime aenc_br a_dbw a_ubw venc_br v_dbw v_ubw", datav[0]));
appendbuf=ms_strdup_printf("%s%s %d %d %d %d %d %d %d;", report->qos_analyzer.input?report->qos_analyzer.input:"", datav[1],
ptime, bitrate[0], down_bw[0], up_bw[0], bitrate[1], down_bw[1], up_bw[1] );
STR_REASSIGN(report->qos_analyzer.input,appendbuf);
STR_REASSIGN(report->qos_analyzer.output_leg, ms_strdup(datav[2]));
appendbuf=ms_strdup_printf("%s%s;", report->qos_analyzer.output?report->qos_analyzer.output:"", datav[3]);
STR_REASSIGN(report->qos_analyzer.output, appendbuf);
}
void linphone_reporting_update_ip(LinphoneCall * call) {
/*This function can be called in two different cases:
- 1) at start when call is starting, remote ip/port info might be the proxy ones to which callee is registered
- 2) later, if we found a direct route between caller and callee with ICE/Stun, ip/port are updated for the direct route access*/
if (! reporting_enabled(call))
return;
reporting_update_ip(call, LINPHONE_CALL_STATS_AUDIO);
if (linphone_call_params_video_enabled(linphone_call_get_current_params(call))) {
reporting_update_ip(call, LINPHONE_CALL_STATS_VIDEO);
}
update_ip(call, LINPHONE_CALL_STATS_AUDIO);
update_ip(call, LINPHONE_CALL_STATS_VIDEO);
}
void linphone_reporting_update(LinphoneCall * call, int stats_type) {
reporting_session_report_t * report = call->log->reports[stats_type];
void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type) {
MediaStream * stream = NULL;
const PayloadType * local_payload = NULL;
const PayloadType * remote_payload = NULL;
const LinphoneCallParams * current_params = linphone_call_get_current_params(call);
reporting_session_report_t * report = call->log->reporting.reports[stats_type];
char * dialog_id;
if (! reporting_enabled(call))
if (!media_report_enabled(call, stats_type))
return;
dialog_id = sal_op_get_dialog_id(call->op);
STR_REASSIGN(report->info.call_id, ms_strdup(call->log->call_id));
STR_REASSIGN(report->info.local_group, ms_strdup_printf("linphone-%s-%s-%s", (stats_type == LINPHONE_CALL_STATS_AUDIO ? "audio" : "video"),
linphone_core_get_user_agent_name(), report->info.call_id));
STR_REASSIGN(report->info.remote_group, ms_strdup_printf("linphone-%s-%s-%s", (stats_type == LINPHONE_CALL_STATS_AUDIO ? "audio" : "video"),
linphone_call_get_remote_user_agent(call), report->info.call_id));
STR_REASSIGN(report->local_metrics.user_agent, ms_strdup(linphone_core_get_user_agent(call->core)));
STR_REASSIGN(report->remote_metrics.user_agent, ms_strdup(linphone_call_get_remote_user_agent(call)));
// RFC states: "LocalGroupID provides the identification for the purposes
// of aggregation for the local endpoint.".
STR_REASSIGN(report->info.local_addr.group, ms_strdup_printf("%s-%s-%s"
, dialog_id
, "local"
, report->local_metrics.user_agent
)
);
STR_REASSIGN(report->info.remote_addr.group, ms_strdup_printf("%s-%s-%s"
, dialog_id
, "remote"
, report->remote_metrics.user_agent
)
);
if (call->dir == LinphoneCallIncoming) {
STR_REASSIGN(report->info.remote_id, linphone_address_as_string(call->log->from));
STR_REASSIGN(report->info.local_id, linphone_address_as_string(call->log->to));
STR_REASSIGN(report->info.orig_id, ms_strdup(report->info.remote_id));
STR_REASSIGN(report->info.remote_addr.id, linphone_address_as_string(call->log->from));
STR_REASSIGN(report->info.local_addr.id, linphone_address_as_string(call->log->to));
STR_REASSIGN(report->info.orig_id, ms_strdup(report->info.remote_addr.id));
} else {
STR_REASSIGN(report->info.remote_id, linphone_address_as_string(call->log->to));
STR_REASSIGN(report->info.local_id, linphone_address_as_string(call->log->from));
STR_REASSIGN(report->info.orig_id, ms_strdup(report->info.local_id));
STR_REASSIGN(report->info.remote_addr.id, linphone_address_as_string(call->log->to));
STR_REASSIGN(report->info.local_addr.id, linphone_address_as_string(call->log->from));
STR_REASSIGN(report->info.orig_id, ms_strdup(report->info.local_addr.id));
}
STR_REASSIGN(report->dialog_id, sal_op_get_dialog_id(call->op));
report->local_metrics.timestamps.start = call->log->start_date_time;
report->local_metrics.timestamps.stop = call->log->start_date_time + linphone_call_get_duration(call);
@ -377,6 +510,7 @@ void linphone_reporting_update(LinphoneCall * call, int stats_type) {
report->remote_metrics.timestamps.start = call->log->start_date_time;
report->remote_metrics.timestamps.stop = call->log->start_date_time + linphone_call_get_duration(call);
/*yet we use the same payload config for local and remote, since this is the largest use case*/
if (stats_type == LINPHONE_CALL_STATS_AUDIO && call->audiostream != NULL) {
stream = &call->audiostream->ms;
@ -393,13 +527,22 @@ void linphone_reporting_update(LinphoneCall * call, int stats_type) {
report->info.local_addr.ssrc = rtp_session_get_send_ssrc(session);
report->info.remote_addr.ssrc = rtp_session_get_recv_ssrc(session);
if (stream->qi != NULL){
report->local_metrics.quality_estimates.moslq = ms_quality_indicator_get_average_lq_rating(stream->qi) >= 0 ?
MAX(1, ms_quality_indicator_get_average_lq_rating(stream->qi)) : -1;
report->local_metrics.quality_estimates.moscq = ms_quality_indicator_get_average_rating(stream->qi) >= 0 ?
MAX(1, ms_quality_indicator_get_average_rating(stream->qi)) : -1;
}
}
STR_REASSIGN(report->dialog_id, ms_strdup_printf("%s;%u", dialog_id, report->info.local_addr.ssrc));
if (local_payload != NULL) {
report->local_metrics.session_description.payload_type = local_payload->type;
STR_REASSIGN(report->local_metrics.session_description.payload_desc, ms_strdup(local_payload->mime_type));
if (local_payload->mime_type!=NULL) STR_REASSIGN(report->local_metrics.session_description.payload_desc, ms_strdup(local_payload->mime_type));
report->local_metrics.session_description.sample_rate = local_payload->clock_rate;
STR_REASSIGN(report->local_metrics.session_description.fmtp, ms_strdup(local_payload->recv_fmtp));
if (local_payload->recv_fmtp!=NULL) STR_REASSIGN(report->local_metrics.session_description.fmtp, ms_strdup(local_payload->recv_fmtp));
}
if (remote_payload != NULL) {
@ -408,120 +551,218 @@ void linphone_reporting_update(LinphoneCall * call, int stats_type) {
report->remote_metrics.session_description.sample_rate = remote_payload->clock_rate;
STR_REASSIGN(report->remote_metrics.session_description.fmtp, ms_strdup(remote_payload->recv_fmtp));
}
ms_free(dialog_id);
}
void linphone_reporting_call_stats_updated(LinphoneCall *call, int stats_type) {
reporting_session_report_t * report = call->log->reports[stats_type];
reporting_content_metrics_t * metrics = NULL;
/* generate random float in interval ] 0.9 t ; 1.1 t [*/
static float reporting_rand(float t){
return t * (.2f * (rand() / (RAND_MAX * 1.0f)) + 0.9f);
}
void linphone_reporting_on_rtcp_update(LinphoneCall *call, int stats_type) {
reporting_session_report_t * report = call->log->reporting.reports[stats_type];
reporting_content_metrics_t * metrics = NULL;
LinphoneCallStats stats = call->stats[stats_type];
mblk_t *block = NULL;
int report_interval;
if (! reporting_enabled(call))
if (! media_report_enabled(call,stats_type))
return;
report_interval = linphone_proxy_config_get_quality_reporting_interval(call->dest_proxy);
if (stats.updated == LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE) {
metrics = &report->remote_metrics;
if (rtcp_is_XR(stats.received_rtcp) == TRUE) {
block = stats.received_rtcp;
}
block = stats.received_rtcp;
} else if (stats.updated == LINPHONE_CALL_STATS_SENT_RTCP_UPDATE) {
metrics = &report->local_metrics;
if (rtcp_is_XR(stats.sent_rtcp) == TRUE) {
block = stats.sent_rtcp;
}
block = stats.sent_rtcp;
}
if (block != NULL) {
switch (rtcp_XR_get_block_type(block)) {
case RTCP_XR_VOIP_METRICS: {
uint8_t config;
do{
if (rtcp_is_XR(block) && (rtcp_XR_get_block_type(block) == RTCP_XR_VOIP_METRICS)){
metrics->quality_estimates.rcq = rtcp_XR_voip_metrics_get_r_factor(block);
metrics->quality_estimates.moslq = rtcp_XR_voip_metrics_get_mos_lq(block) / 10.f;
metrics->quality_estimates.moscq = rtcp_XR_voip_metrics_get_mos_cq(block) / 10.f;
uint8_t config = rtcp_XR_voip_metrics_get_rx_config(block);
metrics->jitter_buffer.nominal = rtcp_XR_voip_metrics_get_jb_nominal(block);
metrics->jitter_buffer.max = rtcp_XR_voip_metrics_get_jb_maximum(block);
metrics->jitter_buffer.abs_max = rtcp_XR_voip_metrics_get_jb_abs_max(block);
metrics->packet_loss.network_packet_loss_rate = rtcp_XR_voip_metrics_get_loss_rate(block);
metrics->packet_loss.jitter_buffer_discard_rate = rtcp_XR_voip_metrics_get_discard_rate(block);
metrics->rtcp_xr_count++;
config = rtcp_XR_voip_metrics_get_rx_config(block);
metrics->session_description.packet_loss_concealment = (config >> 6) & 0x3;
metrics->jitter_buffer.adaptive = (config >> 4) & 0x3;
break;
} default: {
break;
// for local mos rating, we'll use the quality indicator directly
// because rtcp XR might not be enabled
if (stats.updated == LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE){
metrics->quality_estimates.moslq = (rtcp_XR_voip_metrics_get_mos_lq(block)==127) ?
127 : rtcp_XR_voip_metrics_get_mos_lq(block) / 10.f;
metrics->quality_estimates.moscq = (rtcp_XR_voip_metrics_get_mos_cq(block)==127) ?
127 : rtcp_XR_voip_metrics_get_mos_cq(block) / 10.f;
}
metrics->jitter_buffer.nominal += rtcp_XR_voip_metrics_get_jb_nominal(block);
metrics->jitter_buffer.max += rtcp_XR_voip_metrics_get_jb_maximum(block);
metrics->jitter_buffer.abs_max = rtcp_XR_voip_metrics_get_jb_abs_max(block);
metrics->jitter_buffer.adaptive = (config >> 4) & 0x3;
metrics->packet_loss.network_packet_loss_rate = rtcp_XR_voip_metrics_get_loss_rate(block);
metrics->packet_loss.jitter_buffer_discard_rate = rtcp_XR_voip_metrics_get_discard_rate(block);
metrics->session_description.packet_loss_concealment = (config >> 6) & 0x3;
metrics->delay.round_trip_delay += rtcp_XR_voip_metrics_get_round_trip_delay(block);
}else if (rtcp_is_SR(block)){
MediaStream *ms=(stats_type==0 ? &call->audiostream->ms : &call->videostream->ms);
float rtt = rtp_session_get_round_trip_propagation(ms->sessions.rtp_session);
if (rtt > 1e-6){
metrics->rtcp_sr_count++;
metrics->delay.round_trip_delay += 1000*rtt;
}
}
}while(rtcp_next_packet(block));
/* check if we should send an interval report - use a random sending time to
dispatch reports and avoid sending them too close from each other */
if (report_interval>0 && ms_time(NULL)-report->last_report_date>reporting_rand(report_interval)){
linphone_reporting_update_media_info(call, stats_type);
send_report(call, report, "VQIntervalReport");
}
}
void linphone_reporting_publish(LinphoneCall* call) {
if (! reporting_enabled(call))
return;
if (call->log->reports[LINPHONE_CALL_STATS_AUDIO] != NULL) {
reporting_publish(call, call->log->reports[LINPHONE_CALL_STATS_AUDIO]);
static int publish_report(LinphoneCall *call, const char *event_type){
int ret = 0;
int i;
for (i = 0; i < 2; i++){
if (media_report_enabled(call, i)){
int sndret;
linphone_reporting_update_media_info(call, i);
sndret=send_report(call, call->log->reporting.reports[i], event_type);
if (sndret>0){
ret += 10+(i+1)*sndret;
}
} else{
ret += i+1;
}
}
return ret;
}
if (call->log->reports[LINPHONE_CALL_STATS_VIDEO] != NULL
&& linphone_call_params_video_enabled(linphone_call_get_current_params(call))) {
reporting_publish(call, call->log->reports[LINPHONE_CALL_STATS_VIDEO]);
int linphone_reporting_publish_session_report(LinphoneCall* call, bool_t call_term) {
char * session_type = call_term?"VQSessionReport: CallTerm":"VQSessionReport";
return publish_report(call, session_type);
}
int linphone_reporting_publish_interval_report(LinphoneCall* call) {
return publish_report(call, "VQIntervalReport");
}
void linphone_reporting_call_state_updated(LinphoneCall *call){
LinphoneCallState state=linphone_call_get_state(call);
if (! quality_reporting_enabled(call)){
return;
}
switch (state){
case LinphoneCallStreamsRunning:{
bool_t video_enabled=media_report_enabled(call, LINPHONE_CALL_STATS_VIDEO);
int i;
MediaStream *streams[2] = {(MediaStream*) call->audiostream, (MediaStream *) call->videostream};
MSQosAnalyzer *analyzer;
for (i=0;i<2;i++){
if (streams[i]==NULL||streams[i]->rc==NULL){
ms_message("QualityReporting[%p] Cannot set on_action_suggested"
" callback for %s stream because something is null", call, i?"video":"audio");
continue;
}
analyzer=ms_bitrate_controller_get_qos_analyzer(streams[i]->rc);
if (analyzer){
on_action_suggested_struct_t * oass = ms_new0(on_action_suggested_struct_t, 1);
oass->call = call;
oass->stats_type = i;
STR_REASSIGN(call->log->reporting.reports[i]->qos_analyzer.name, ms_strdup(ms_qos_analyzer_get_name(analyzer)));
ms_qos_analyzer_set_on_action_suggested(analyzer,
qos_analyzer_on_action_suggested,
oass);
}
}
linphone_reporting_update_ip(call);
if (!video_enabled && call->log->reporting.was_video_running){
send_report(call, call->log->reporting.reports[LINPHONE_CALL_STATS_VIDEO], "VQSessionReport");
}
call->log->reporting.was_video_running=video_enabled;
break;
}
case LinphoneCallEnd:{
if (call->log->status==LinphoneCallSuccess || call->log->status==LinphoneCallAborted){
linphone_reporting_publish_session_report(call, TRUE);
}
break;
}
default:{
break;
}
}
}
reporting_session_report_t * linphone_reporting_new() {
int i;
reporting_session_report_t * rm = ms_new0(reporting_session_report_t,1);
reporting_content_metrics_t * metrics[2] = {&rm->local_metrics, &rm->remote_metrics};
memset(rm, 0, sizeof(reporting_session_report_t));
for (i = 0; i < 2; i++) {
metrics[i]->session_description.payload_type = -1;
metrics[i]->session_description.sample_rate = -1;
metrics[i]->session_description.frame_duration = -1;
metrics[i]->session_description.packet_loss_concealment = -1;
metrics[i]->packet_loss.network_packet_loss_rate = -1;
metrics[i]->packet_loss.jitter_buffer_discard_rate = -1;
metrics[i]->session_description.packet_loss_concealment = -1;
metrics[i]->jitter_buffer.adaptive = -1;
/*metrics[i]->jitter_buffer.rate = -1;*/
metrics[i]->jitter_buffer.nominal = -1;
metrics[i]->jitter_buffer.max = -1;
metrics[i]->jitter_buffer.abs_max = -1;
metrics[i]->delay.round_trip_delay = -1;
metrics[i]->delay.end_system_delay = -1;
/*metrics[i]->delay.one_way_delay = -1;*/
metrics[i]->delay.symm_one_way_delay = -1;
metrics[i]->delay.interarrival_jitter = -1;
metrics[i]->delay.mean_abs_jitter = -1;
metrics[i]->signal.level = 127;
metrics[i]->signal.noise_level = 127;
}
reset_avg_metrics(rm);
return rm;
}
void linphone_reporting_destroy(reporting_session_report_t * report) {
if (report->info.call_id != NULL) ms_free(report->info.call_id);
if (report->info.local_id != NULL) ms_free(report->info.local_id);
if (report->info.remote_id != NULL) ms_free(report->info.remote_id);
if (report->info.orig_id != NULL) ms_free(report->info.orig_id);
if (report->info.local_addr.ip != NULL) ms_free(report->info.local_addr.ip);
if (report->info.remote_addr.ip != NULL) ms_free(report->info.remote_addr.ip);
if (report->info.local_group != NULL) ms_free(report->info.local_group);
if (report->info.remote_group != NULL) ms_free(report->info.remote_group);
if (report->info.local_mac_addr != NULL) ms_free(report->info.local_mac_addr);
if (report->info.remote_mac_addr != NULL) ms_free(report->info.remote_mac_addr);
if (report->dialog_id != NULL) ms_free(report->dialog_id);
if (report->local_metrics.session_description.fmtp != NULL) ms_free(report->local_metrics.session_description.fmtp);
if (report->local_metrics.session_description.payload_desc != NULL) ms_free(report->local_metrics.session_description.payload_desc);
if (report->remote_metrics.session_description.fmtp != NULL) ms_free(report->remote_metrics.session_description.fmtp);
if (report->remote_metrics.session_description.payload_desc != NULL) ms_free(report->remote_metrics.session_description.payload_desc);
STR_REASSIGN(report->info.call_id, NULL);
STR_REASSIGN(report->info.local_addr.id, NULL);
STR_REASSIGN(report->info.remote_addr.id, NULL);
STR_REASSIGN(report->info.orig_id, NULL);
STR_REASSIGN(report->info.local_addr.ip, NULL);
STR_REASSIGN(report->info.remote_addr.ip, NULL);
STR_REASSIGN(report->info.local_addr.group, NULL);
STR_REASSIGN(report->info.remote_addr.group, NULL);
STR_REASSIGN(report->info.local_addr.mac, NULL);
STR_REASSIGN(report->info.remote_addr.mac, NULL);
STR_REASSIGN(report->dialog_id, NULL);
STR_REASSIGN(report->local_metrics.session_description.fmtp, NULL);
STR_REASSIGN(report->local_metrics.session_description.payload_desc, NULL);
STR_REASSIGN(report->local_metrics.user_agent, NULL);
STR_REASSIGN(report->remote_metrics.session_description.fmtp, NULL);
STR_REASSIGN(report->remote_metrics.session_description.payload_desc, NULL);
STR_REASSIGN(report->remote_metrics.user_agent, NULL);
STR_REASSIGN(report->qos_analyzer.name, NULL);
STR_REASSIGN(report->qos_analyzer.timestamp, NULL);
STR_REASSIGN(report->qos_analyzer.input_leg, NULL);
STR_REASSIGN(report->qos_analyzer.input, NULL);
STR_REASSIGN(report->qos_analyzer.output_leg, NULL);
STR_REASSIGN(report->qos_analyzer.output, NULL);
ms_free(report);
}
void linphone_reporting_set_on_report_send(LinphoneCall *call, LinphoneQualityReportingReportSendCb cb){
call->log->reporting.on_report_sent = cb;
}

View file

@ -28,12 +28,16 @@ extern "C"{
/**
* Linphone quality report sub object storing address related information (ip / port / MAC).
* Linphone quality report sub object storing address related information.
*/
typedef struct reporting_addr {
char * id;
char * ip;
int port;
uint32_t ssrc;
char * group;
char * mac; // optional
} reporting_addr_t;
/**
@ -50,19 +54,19 @@ typedef struct reporting_content_metrics {
// session description - optional
struct {
int payload_type;
char * payload_desc; // mime type
int sample_rate; // clock rate
int frame_duration; // to check (ptime?) - audio only
char * payload_desc;
int sample_rate;
int frame_duration;
char * fmtp;
int packet_loss_concealment; // in voip metrics - audio only
int packet_loss_concealment;
} session_description;
// jitter buffet - optional
struct {
int adaptive; // constant
int nominal; // no may vary during the call <- average? worst score?
int max; // no may vary during the call <- average?
int abs_max; // constant
int adaptive;
int nominal;
int max;
int abs_max;
} jitter_buffer;
// packet loss - optional
@ -73,26 +77,32 @@ typedef struct reporting_content_metrics {
// delay - optional
struct {
int round_trip_delay; // no - vary
int end_system_delay; // no - not implemented yet
int symm_one_way_delay; // no - vary (depends on round_trip_delay) + not implemented (depends on end_system_delay)
int interarrival_jitter; // no - not implemented yet
int mean_abs_jitter; // to check
int round_trip_delay;
int end_system_delay;
int symm_one_way_delay;
int interarrival_jitter;
int mean_abs_jitter;
} delay;
// signal - optional
struct {
int level; // no - vary
int noise_level; // no - vary
int level;
int noise_level;
} signal;
// quality estimates - optional
struct {
int rlq; // linked to moslq - in [0..120]
int rcq; //voip metrics R factor - no - vary or avg in [0..120]
float moslq; // no - vary or avg - voip metrics - in [0..4.9]
float moscq; // no - vary or avg - voip metrics - in [0..4.9]
float moslq;
float moscq;
} quality_estimates;
// custom extension
char * user_agent;
// for internal processing
uint8_t rtcp_xr_count; // number of RTCP XR packets received since last report, used to compute average of instantaneous parameters as stated in the RFC 6035 (4.5)
uint8_t rtcp_sr_count; // number of RTCP SR packets received since last report, used to compute RTT average values in case RTCP XR voip metrics is not enabled
} reporting_content_metrics_t;
@ -103,24 +113,35 @@ typedef struct reporting_content_metrics {
typedef struct reporting_session_report {
struct {
char * call_id;
char * local_id;
char * remote_id;
char * orig_id;
reporting_addr_t local_addr;
reporting_addr_t remote_addr;
char * local_group;
char * remote_group;
char * local_mac_addr; // optional
char * remote_mac_addr; // optional
} info;
reporting_content_metrics_t local_metrics;
reporting_content_metrics_t remote_metrics; // optional
char * dialog_id; // optional
// Quality of Service analyzer - custom extension
/* This should allow us to analysis bad network conditions and quality adaptation
on server side*/
struct {
char * name; /*type of the QoS analyzer used*/
char* timestamp; /*time of each decision in seconds*/
char* input_leg; /*input parameters' name*/
char* input; /*set of inputs for each semicolon separated decision*/
char* output_leg; /*output parameters' name*/
char* output; /*set of outputs for each semicolon separated decision*/
} qos_analyzer;
// for internal processing
time_t last_report_date;
} reporting_session_report_t;
typedef void (*LinphoneQualityReportingReportSendCb)(const LinphoneCall *call, int stream_type, const LinphoneContent *content);
reporting_session_report_t * linphone_reporting_new();
void linphone_reporting_destroy(reporting_session_report_t * report);
@ -131,31 +152,60 @@ void linphone_reporting_destroy(reporting_session_report_t * report);
* @param stats_type the media type (LINPHONE_CALL_STATS_AUDIO or LINPHONE_CALL_STATS_VIDEO)
*
*/
void linphone_reporting_update(LinphoneCall * call, int stats_type);
void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type);
/**
* Fill IP information about a given call. This function must be called each
* time state is 'LinphoneCallStreamsRunning' since IP might be updated (if we
* time call state is 'LinphoneCallStreamsRunning' since IP might be updated (if we
* found a direct route between caller and callee for example).
* When call is starting, remote IP/port might be the proxy ones to which callee is registered
* @param call #LinphoneCall object to consider
*
*/
void linphone_reporting_update_ip(LinphoneCall * call);
/**
* Publish the report on the call end.
* Publish a session report. This function should be called when session terminates,
* media change (codec change or session fork), session terminates due to no media packets being received.
* @param call #LinphoneCall object to consider
* @param call_term whether the call has ended or is continuing
*
* @return error code. 0 for success, positive value otherwise.
*/
void linphone_reporting_publish(LinphoneCall* call);
int linphone_reporting_publish_session_report(LinphoneCall* call, bool_t call_term);
/**
* Update publish report data with fresh RTCP stats, if needed.
* Publish an interval report. This function should be used for periodic interval
* @param call #LinphoneCall object to consider
* @return error code. 0 for success, positive value otherwise.
*
*/
int linphone_reporting_publish_interval_report(LinphoneCall* call);
/**
* Update publish reports with newly sent/received RTCP-XR packets (if available).
* @param call #LinphoneCall object to consider
* @param stats_type the media type (LINPHONE_CALL_STATS_AUDIO or LINPHONE_CALL_STATS_VIDEO)
*
*/
void linphone_reporting_call_stats_updated(LinphoneCall *call, int stats_type);
void linphone_reporting_on_rtcp_update(LinphoneCall *call, int stats_type);
/**
* Update publish reports on call state change.
* @param call #LinphoneCall object to consider
*
*/
void linphone_reporting_call_state_updated(LinphoneCall *call);
/**
* Setter of the #LinphoneQualityReportingReportSendCb callback method which is
* notified each time a report will be submitted to the collector, if quality
* reporting is enabled
* @param call #LinphoneCall object to consider
* @param cb #LinphoneQualityReportingReportSendCb callback function to notify
*
*/
LINPHONE_PUBLIC void linphone_reporting_set_on_report_send(LinphoneCall *call, LinphoneQualityReportingReportSendCb cb);
#ifdef __cplusplus
}

View file

@ -84,26 +84,72 @@ void sal_media_description_unref(SalMediaDescription *md){
SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md,
SalMediaProto proto, SalStreamType type){
int i;
for(i=0;i<md->n_active_streams;++i){
for(i=0;i<md->nb_streams;++i){
SalStreamDescription *ss=&md->streams[i];
if (!sal_stream_description_active(ss)) continue;
if (ss->proto==proto && ss->type==type) return ss;
}
return NULL;
}
unsigned int sal_media_description_nb_active_streams_of_type(SalMediaDescription *md, SalStreamType type) {
unsigned int i;
unsigned int nb = 0;
for (i = 0; i < md->nb_streams; ++i) {
if (!sal_stream_description_active(&md->streams[i])) continue;
if (md->streams[i].type == type) nb++;
}
return nb;
}
SalStreamDescription * sal_media_description_get_active_stream_of_type(SalMediaDescription *md, SalStreamType type, unsigned int idx) {
unsigned int i;
for (i = 0; i < md->nb_streams; ++i) {
if (!sal_stream_description_active(&md->streams[i])) continue;
if (md->streams[i].type == type) {
if (idx-- == 0) return &md->streams[i];
}
}
return NULL;
}
SalStreamDescription * sal_media_description_find_secure_stream_of_type(SalMediaDescription *md, SalStreamType type) {
SalStreamDescription *desc = sal_media_description_find_stream(md, SalProtoRtpSavpf, type);
if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpSavp, type);
return desc;
}
SalStreamDescription * sal_media_description_find_best_stream(SalMediaDescription *md, SalStreamType type) {
SalStreamDescription *desc = sal_media_description_find_stream(md, SalProtoRtpSavpf, type);
if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpSavp, type);
if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpAvpf, type);
if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpAvp, type);
return desc;
}
bool_t sal_media_description_empty(const SalMediaDescription *md){
if (md->n_active_streams > 0) return FALSE;
if (sal_media_description_get_nb_active_streams(md) > 0) return FALSE;
return TRUE;
}
void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_dir){
int i;
for(i=0;i<md->n_active_streams;++i){
for(i=0;i<md->nb_streams;++i){
SalStreamDescription *ss=&md->streams[i];
if (!sal_stream_description_active(ss)) continue;
ss->dir=stream_dir;
}
}
int sal_media_description_get_nb_active_streams(const SalMediaDescription *md) {
int i;
int nb = 0;
for (i = 0; i < md->nb_streams; i++) {
if (sal_stream_description_active(&md->streams[i])) nb++;
}
return nb;
}
static bool_t is_null_address(const char *addr){
return strcmp(addr,"0.0.0.0")==0 || strcmp(addr,"::0")==0;
@ -114,8 +160,9 @@ static bool_t has_dir(const SalMediaDescription *md, SalStreamDir stream_dir){
int i;
/* we are looking for at least one stream with requested direction, inactive streams are ignored*/
for(i=0;i<md->n_active_streams;++i){
for(i=0;i<md->nb_streams;++i){
const SalStreamDescription *ss=&md->streams[i];
if (!sal_stream_description_active(ss)) continue;
if (ss->dir==stream_dir) return TRUE;
/*compatibility check for phones that only used the null address and no attributes */
if (ss->dir==SalStreamSendRecv && stream_dir==SalStreamSendOnly && (is_null_address(md->addr) || is_null_address(ss->rtp_addr)))
@ -142,6 +189,38 @@ bool_t sal_media_description_has_dir(const SalMediaDescription *md, SalStreamDir
return FALSE;
}
bool_t sal_stream_description_active(const SalStreamDescription *sd) {
return (sd->rtp_port > 0);
}
bool_t sal_stream_description_has_avpf(const SalStreamDescription *sd) {
return ((sd->proto == SalProtoRtpAvpf) || (sd->proto == SalProtoRtpSavpf));
}
bool_t sal_stream_description_has_srtp(const SalStreamDescription *sd) {
return ((sd->proto == SalProtoRtpSavp) || (sd->proto == SalProtoRtpSavpf));
}
bool_t sal_media_description_has_avpf(const SalMediaDescription *md) {
int i;
if (md->nb_streams == 0) return FALSE;
for (i = 0; i < md->nb_streams; i++) {
if (!sal_stream_description_active(&md->streams[i])) continue;
if (sal_stream_description_has_avpf(&md->streams[i]) != TRUE) return FALSE;
}
return TRUE;
}
bool_t sal_media_description_has_srtp(const SalMediaDescription *md) {
int i;
if (md->nb_streams == 0) return FALSE;
for (i = 0; i < md->nb_streams; i++) {
if (!sal_stream_description_active(&md->streams[i])) continue;
if (sal_stream_description_has_srtp(&md->streams[i]) != TRUE) return FALSE;
}
return TRUE;
}
/*
static bool_t fmtp_equals(const char *p1, const char *p2){
if (p1 && p2 && strcmp(p1,p2)==0) return TRUE;
@ -228,9 +307,9 @@ int sal_media_description_equals(const SalMediaDescription *md1, const SalMediaD
int i;
if (strcmp(md1->addr, md2->addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
if (md1->n_total_streams != md2->n_total_streams) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
if (md1->nb_streams != md2->nb_streams) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
if (md1->bandwidth != md2->bandwidth) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
for(i = 0; i < md1->n_total_streams; ++i){
for(i = 0; i < md1->nb_streams; ++i){
result |= sal_stream_description_equals(&md1->streams[i], &md2->streams[i]);
}
return result;
@ -515,6 +594,8 @@ const char* sal_media_proto_to_string(SalMediaProto type) {
switch (type) {
case SalProtoRtpAvp:return "RTP/AVP";
case SalProtoRtpSavp:return "RTP/SAVP";
case SalProtoRtpAvpf:return "RTP/AVPF";
case SalProtoRtpSavpf:return "RTP/SAVPF";
default: return "unknown";
}
}

View file

@ -731,7 +731,7 @@ int linphone_core_update_upnp_from_remote_media_description(LinphoneCall *call,
int i;
const SalStreamDescription *stream;
for (i = 0; i < md->n_total_streams; i++) {
for (i = 0; i < md->nb_streams; i++) {
stream = &md->streams[i];
if(stream->type == SalAudio) {
audio = TRUE;
@ -1058,8 +1058,9 @@ int linphone_core_update_local_media_description_from_upnp(SalMediaDescription *
SalStreamDescription *stream;
UpnpStream *upnpStream;
for (i = 0; i < desc->n_active_streams; i++) {
for (i = 0; i < desc->nb_streams; i++) {
stream = &desc->streams[i];
if (!sal_stream_description_active(stream)) continue;
upnpStream = NULL;
if(stream->type == SalAudio) {
upnpStream = session->audio;

View file

@ -1,115 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0"?>
<interface>
<requires lib="gtk+" version="2.16"/>
<!-- interface-naming-policy project-wide -->
<object class="GtkDialog" id="call_statistics">
<property name="can_focus">False</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Call statistics</property>
<property name="type_hint">dialog</property>
<signal name="response" handler="linphone_gtk_call_statistics_closed" swapped="no"/>
<signal name="response" handler="linphone_gtk_call_statistics_closed"/>
<child internal-child="vbox">
<object class="GtkVBox" id="dialog-vbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkHButtonBox" id="dialog-action_area1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<placeholder/>
</child>
<child>
<object class="GtkButton" id="button1">
<property name="label">gtk-close</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="frame1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="left_padding">12</property>
<child>
<object class="GtkTable" id="table1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="n_rows">9</property>
<property name="n_rows">10</property>
<property name="n_columns">2</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkLabel" id="audio_codec_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Audio codec</property>
</object>
<packing>
<property name="x_options"></property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options"/>
</packing>
</child>
<child>
<object class="GtkLabel" id="video_codec_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Video codec</property>
</object>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options"></property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options"/>
</packing>
</child>
<child>
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Audio IP bandwidth usage</property>
</object>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options"></property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="x_options"/>
</packing>
</child>
<child>
<object class="GtkLabel" id="audio_codec">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="video_codec">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="left_attach">1</property>
@ -119,9 +71,8 @@
</packing>
</child>
<child>
<object class="GtkLabel" id="audio_bandwidth_usage">
<object class="GtkLabel" id="video_codec">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="left_attach">1</property>
@ -130,22 +81,53 @@
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="audio_bandwidth_usage">
<property name="visible">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Audio Media connectivity</property>
</object>
<packing>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
<property name="x_options"></property>
<property name="top_attach">5</property>
<property name="bottom_attach">6</property>
<property name="x_options"/>
</packing>
</child>
<child>
<object class="GtkLabel" id="audio_media_connectivity">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">5</property>
<property name="bottom_attach">6</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="label" translatable="yes">Video IP bandwidth usage</property>
</object>
<packing>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
<property name="x_options"/>
</packing>
</child>
<child>
<object class="GtkLabel" id="video_bandwidth_usage">
<property name="visible">True</property>
</object>
<packing>
<property name="left_attach">1</property>
@ -154,120 +136,106 @@
<property name="bottom_attach">5</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Video IP bandwidth usage</property>
</object>
<packing>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="x_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="video_bandwidth_usage">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Video Media connectivity</property>
</object>
<packing>
<property name="top_attach">5</property>
<property name="bottom_attach">6</property>
<property name="top_attach">6</property>
<property name="bottom_attach">7</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="video_media_connectivity">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">5</property>
<property name="bottom_attach">6</property>
<property name="top_attach">6</property>
<property name="bottom_attach">7</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Round trip time</property>
</object>
<packing>
<property name="top_attach">6</property>
<property name="bottom_attach">7</property>
<property name="top_attach">7</property>
<property name="bottom_attach">8</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="round_trip_time">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">6</property>
<property name="bottom_attach">7</property>
<property name="top_attach">7</property>
<property name="bottom_attach">8</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="video_size_recv_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Video resolution received</property>
</object>
<packing>
<property name="top_attach">7</property>
<property name="bottom_attach">8</property>
<property name="top_attach">8</property>
<property name="bottom_attach">9</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="video_size_recv">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">7</property>
<property name="bottom_attach">8</property>
<property name="top_attach">8</property>
<property name="bottom_attach">9</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="video_size_sent_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Video resolution sent</property>
</object>
<packing>
<property name="top_attach">8</property>
<property name="bottom_attach">9</property>
<property name="top_attach">9</property>
<property name="bottom_attach">10</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="video_size_sent">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">8</property>
<property name="bottom_attach">9</property>
<property name="top_attach">9</property>
<property name="bottom_attach">10</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="rtp_profile_label">
<property name="visible">True</property>
<property name="label" translatable="yes">RTP profile</property>
</object>
<packing>
<property name="x_options"/>
</packing>
</child>
<child>
<object class="GtkLabel" id="rtp_profile">
<property name="visible">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
</packing>
</child>
</object>
@ -277,7 +245,6 @@
<child type="label">
<object class="GtkLabel" id="call_statistics_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;Call statistics and information&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
@ -289,6 +256,34 @@
<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>
<placeholder/>
</child>
<child>
<object class="GtkButton" id="button1">
<property name="label">gtk-close</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
</object>
</child>
<action-widgets>

View file

@ -84,13 +84,13 @@ void linphone_gtk_call_update_tab_header(LinphoneCall *call,gboolean pause){
GtkWidget *i=NULL;
GtkWidget *l;
gchar *text;
if(pause){
i=gtk_image_new_from_stock(GTK_STOCK_MEDIA_PAUSE,GTK_ICON_SIZE_SMALL_TOOLBAR);
} else {
i=create_pixmap ("startcall-small.png");
}
text=g_strdup_printf(_("Call #%i"),call_index);
l=gtk_label_new (text);
gtk_box_pack_start (GTK_BOX(new_label),i,FALSE,FALSE,0);
@ -98,6 +98,7 @@ void linphone_gtk_call_update_tab_header(LinphoneCall *call,gboolean pause){
gtk_notebook_set_tab_label(notebook,w,new_label);
gtk_widget_show_all(new_label);
g_free(text);
}
static void linphone_gtk_in_call_set_animation_image(GtkWidget *callview, const char *image_name, gboolean is_stock){
@ -181,7 +182,7 @@ static void conference_button_clicked(GtkWidget *button, gpointer call_ref){
gtk_widget_set_sensitive(button,FALSE);
g_object_set_data(G_OBJECT(linphone_gtk_get_main_window()),"conf_frame",NULL);
linphone_core_add_all_to_conference(linphone_gtk_get_core());
}
void linphone_gtk_enable_conference_button(LinphoneCore *lc, gboolean value){
@ -258,9 +259,12 @@ static void _refresh_call_stats(GtkWidget *callstats, LinphoneCall *call){
gboolean has_video=linphone_call_params_video_enabled(linphone_call_get_current_params(call));
MSVideoSize size_received = linphone_call_params_get_received_video_size(linphone_call_get_current_params(call));
MSVideoSize size_sent = linphone_call_params_get_sent_video_size(linphone_call_get_current_params(call));
gchar *tmp=g_strdup_printf(_("download: %f\nupload: %f (kbit/s)"),
const char *rtp_profile = linphone_call_params_get_rtp_profile(linphone_call_get_current_params(call));
gchar *tmp = g_strdup_printf("%s", rtp_profile);
gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"rtp_profile")),tmp);
g_free(tmp);
tmp=g_strdup_printf(_("download: %f\nupload: %f (kbit/s)"),
as->download_bandwidth,as->upload_bandwidth);
gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"audio_bandwidth_usage")),tmp);
g_free(tmp);
if (has_video){
@ -268,7 +272,7 @@ static void _refresh_call_stats(GtkWidget *callstats, LinphoneCall *call){
gchar *size_s=g_strdup_printf(_("%ix%i"),size_sent.width,size_sent.height);
gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"video_size_recv")),size_r);
gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"video_size_sent")),size_s);
tmp=g_strdup_printf(_("download: %f\nupload: %f (kbit/s)"),vs->download_bandwidth,vs->upload_bandwidth);
g_free(size_r);
g_free(size_s);
@ -283,7 +287,7 @@ static void _refresh_call_stats(GtkWidget *callstats, LinphoneCall *call){
audio_media_connectivity = ice_state_to_string(as->ice_state);
}
gtk_label_set_text(GTK_LABEL(linphone_gtk_get_widget(callstats,"audio_media_connectivity")),audio_media_connectivity);
if (has_video){
if(vs->upnp_state != LinphoneUpnpStateNotAvailable && vs->upnp_state != LinphoneUpnpStateIdle) {
video_media_connectivity = upnp_state_to_string(vs->upnp_state);
@ -292,7 +296,7 @@ static void _refresh_call_stats(GtkWidget *callstats, LinphoneCall *call){
}
}else video_media_connectivity=NULL;
gtk_label_set_text(GTK_LABEL(linphone_gtk_get_widget(callstats,"video_media_connectivity")),video_media_connectivity);
if (as->round_trip_delay>0){
tmp=g_strdup_printf(_("%.3f seconds"),as->round_trip_delay);
gtk_label_set_text(GTK_LABEL(linphone_gtk_get_widget(callstats,"round_trip_time")),tmp);
@ -438,7 +442,7 @@ 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");
gboolean in_conf=linphone_call_params_local_conference_mode(linphone_call_get_current_params(call));
gboolean in_conf=linphone_call_params_get_local_conference_mode(linphone_call_get_current_params(call));
int idx;
g_return_if_fail(w!=NULL);
idx=gtk_notebook_page_num(GTK_NOTEBOOK(nb),w);
@ -464,7 +468,7 @@ void linphone_gtk_remove_in_call_view(LinphoneCall *call){
static void display_peer_name_in_label(GtkWidget *label, const LinphoneAddress *from){
const char *displayname=NULL;
const char *id;
char *id;
char *uri_label;
displayname=linphone_address_get_display_name(from);
id=linphone_address_as_string_uri_only(from);
@ -476,6 +480,7 @@ static void display_peer_name_in_label(GtkWidget *label, const LinphoneAddress *
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);
g_free(id);
}
void linphone_gtk_in_call_view_set_calling(LinphoneCall *call){
@ -679,14 +684,14 @@ void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){
GtkWidget *callee=linphone_gtk_get_widget(callview,"in_call_uri");
GtkWidget *duration=linphone_gtk_get_widget(callview,"in_call_duration");
guint taskid=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(callview),"taskid"));
gboolean in_conf=linphone_call_params_local_conference_mode(linphone_call_get_current_params(call));
gboolean in_conf=linphone_call_params_get_local_conference_mode(linphone_call_get_current_params(call));
GtkWidget *call_stats=(GtkWidget*)g_object_get_data(G_OBJECT(callview),"call_stats");
display_peer_name_in_label(callee,linphone_call_get_remote_address (call));
gtk_widget_hide(linphone_gtk_get_widget(callview,"answer_decline_panel"));
gtk_label_set_markup(GTK_LABEL(status),in_conf ? _("In conference") : _("<b>In call</b>"));
gtk_widget_set_sensitive(linphone_gtk_get_widget(callview,"conference_button"),!in_conf);
gtk_widget_set_sensitive(linphone_gtk_get_widget(callview,"transfer_button"),!in_conf);
@ -695,7 +700,7 @@ void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){
linphone_gtk_call_update_tab_header(call,FALSE);
linphone_gtk_enable_mute_button(
GTK_BUTTON(linphone_gtk_get_widget(callview,"incall_mute")),TRUE);
if (taskid==0){
taskid=g_timeout_add(250,(GSourceFunc)linphone_gtk_in_call_view_refresh,call);
g_object_set_data(G_OBJECT(callview),"taskid",GINT_TO_POINTER(taskid));
@ -748,7 +753,7 @@ void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_m
if(callview==NULL) return;
GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status");
guint taskid=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(callview),"taskid"));
gboolean in_conf=linphone_call_params_local_conference_mode(linphone_call_get_current_params(call));
gboolean in_conf=linphone_call_params_get_local_conference_mode(linphone_call_get_current_params(call));
if (status==NULL) return;
if (error_msg==NULL)
@ -769,7 +774,7 @@ void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_m
linphone_gtk_enable_mute_button(
GTK_BUTTON(linphone_gtk_get_widget(callview,"incall_mute")),FALSE);
linphone_gtk_enable_hold_button(call,FALSE,TRUE);
if (taskid!=0) g_source_remove(taskid);
g_timeout_add_seconds(2,(GSourceFunc)in_call_view_terminated,call);
if (in_conf)
@ -906,7 +911,7 @@ void linphone_gtk_record_call_toggled(GtkWidget *button){
return;
}
message=g_strdup_printf(_("<small><i>Recording into\n%s %s</i></small>"),filepath,active ? "" : _("(Paused)"));
if (active){
if (call)
linphone_call_start_recording(call);
@ -917,7 +922,7 @@ void linphone_gtk_record_call_toggled(GtkWidget *button){
linphone_call_stop_recording(call);
else
linphone_core_stop_conference_recording(lc);
}
gtk_label_set_markup(GTK_LABEL(label),message);
g_free(message);

View file

@ -418,9 +418,9 @@ GtkWidget *linphone_gtk_create_widget(const char *filename, const char *widget_n
object_ids[1]=NULL;
if (get_ui_file(filename,path,sizeof(path))==-1) return NULL;
gtk_builder_set_translation_domain(builder,GETTEXT_PACKAGE);
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);
@ -983,27 +983,37 @@ gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_
char date[64]={0};
time_t curtime=time(NULL);
struct tm loctime;
const char **fmts=linphone_core_get_supported_file_formats(linphone_gtk_get_core());
int i;
const char *ext="wav";
#ifdef WIN32
loctime=*localtime(&curtime);
#else
localtime_r(&curtime,&loctime);
#endif
snprintf(date,sizeof(date)-1,"%i%02i%02i-%02i%02i",loctime.tm_year+1900,loctime.tm_mon+1,loctime.tm_mday, loctime.tm_hour, loctime.tm_min);
for (i=0;fmts[i]!=NULL;++i){
if (strcmp(fmts[i],"mkv")==0){
ext="mkv";
break;
}
}
if (address){
id=linphone_address_get_username(address);
if (id==NULL) id=linphone_address_get_domain(address);
}
if (is_conference){
snprintf(filename,sizeof(filename)-1,"%s-conference-%s.wav",
snprintf(filename,sizeof(filename)-1,"%s-conference-%s.%s",
linphone_gtk_get_ui_config("title","Linphone"),
date);
date,ext);
}else{
snprintf(filename,sizeof(filename)-1,"%s-call-%s-%s.wav",
snprintf(filename,sizeof(filename)-1,"%s-call-%s-%s.%s",
linphone_gtk_get_ui_config("title","Linphone"),
date,
id);
id,ext);
}
if (!dir) {
ms_message ("No directory for music, using [%s] instead",dir=getenv("HOME"));
@ -1015,7 +1025,7 @@ static gboolean linphone_gtk_start_call_do(GtkWidget *uri_bar){
const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar));
LinphoneCore *lc=linphone_gtk_get_core();
LinphoneAddress *addr=linphone_core_interpret_url(lc,entered);
if (addr!=NULL){
LinphoneCallParams *params=linphone_core_create_default_call_parameters(lc);
gchar *record_file=linphone_gtk_get_record_path(addr,FALSE);
@ -1313,12 +1323,16 @@ static bool_t notify_actions_supported() {
return accepts_actions;
}
static NotifyNotification* build_notification(const char *title, const char *body){
return notify_notification_new(title,body,linphone_gtk_get_ui_config("icon",LINPHONE_ICON)
static NotifyNotification* build_notification(const char *title, const char *body) {
const char *icon_path = linphone_gtk_get_ui_config("icon", LINPHONE_ICON);
GdkPixbuf *pbuf = create_pixbuf(icon_path);
NotifyNotification *n = notify_notification_new(title, body, NULL
#ifdef HAVE_NOTIFY1
,NULL
,NULL
#endif
);
notify_notification_set_icon_from_pixbuf(n, pbuf);
return n;
}
static void show_notification(NotifyNotification* n){
@ -1628,13 +1642,13 @@ static GtkWidget *create_icon_menu(){
}
void linphone_gtk_save_main_window_position(GtkWindow* mw, GdkEvent *event, gpointer data){
gtk_window_get_position(GTK_WINDOW(mw), &main_window_x, &main_window_y);
gtk_window_get_position(GTK_WINDOW(mw), &main_window_x, &main_window_y);
}
static void handle_icon_click() {
GtkWidget *mw=linphone_gtk_get_main_window();
if (!gtk_window_is_active((GtkWindow*)mw)) {
if(!gtk_widget_is_drawable(mw)){
if(!gtk_widget_is_drawable(mw)){
//we only move if window was hidden. If it was simply behind the window stack, ie, drawable, we keep it as it was
gtk_window_move (GTK_WINDOW(mw), main_window_x, main_window_y);
}
@ -2176,6 +2190,7 @@ int main(int argc, char *argv[]){
const char *app_name="Linphone";
LpConfig *factory;
const char *db_file;
GError *error=NULL;
#if !GLIB_CHECK_VERSION(2, 31, 0)
g_thread_init(NULL);
@ -2230,8 +2245,9 @@ int main(int argc, char *argv[]){
gdk_threads_enter();
if (!gtk_init_with_args(&argc,&argv,_("A free SIP video-phone"),
linphone_options,NULL,NULL)){
linphone_options,NULL,&error)){
gdk_threads_leave();
g_critical("%s", error->message);
return -1;
}
if (config_file) free(config_file);
@ -2257,7 +2273,7 @@ int main(int argc, char *argv[]){
g_error("Could not change directory to %s : %s",workingdir,strerror(errno));
}
}
#if defined(__APPLE__) && defined(ENABLE_NLS)
/*workaround for bundles. GTK is unable to find translations in the bundle (obscure bug again).
So we help it:*/
@ -2269,6 +2285,9 @@ int main(int argc, char *argv[]){
}
}
#endif
add_pixmap_directory("pixmaps");
add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps/linphone");
/* Now, look for the factory configuration file, we do it this late
since we want to have had time to change directory and to parse
the options, in case we needed to access the working directory */
@ -2283,9 +2302,6 @@ int main(int argc, char *argv[]){
pbuf=create_pixbuf(icon_path);
if (pbuf!=NULL) gtk_window_set_default_icon(pbuf);
add_pixmap_directory("pixmaps");
add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps/linphone");
#ifdef HAVE_GTK_OSX
GtkosxApplication *theMacApp = gtkosx_application_get();
g_signal_connect(G_OBJECT(theMacApp),"NSApplicationDidBecomeActive",(GCallback)linphone_gtk_show_main_window,NULL);
@ -2308,23 +2324,24 @@ core_start:
linphone_gtk_create_log_window();
linphone_core_enable_logs_with_cb(linphone_gtk_log_handler);
db_file=linphone_gtk_message_storage_get_db_file(NULL);
linphone_gtk_init_liblinphone(config_file, factory_config_file, db_file);
/* 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)linphone_gtk_get_core());
gtk_main();
linphone_gtk_quit();
if (restart){
quit_done=FALSE;
restart=FALSE;
goto core_start;
}
if (config_file) free(config_file);
#ifndef HAVE_GTK_OSX
/*workaround a bug on win32 that makes status icon still present in the systray even after program exit.*/
if (icon) gtk_status_icon_set_visible(icon,FALSE);

View file

@ -1772,7 +1772,7 @@
<property name="can_focus">False</property>
<property name="model">model4</property>
<property name="active">0</property>
<signal name="changed" handler="linphone_gtk_internet_kind_changed" swapped="no"/>
<!-- <signal name="changed" handler="linphone_gtk_internet_kind_changed" swapped="no"/> -->
<child>
<object class="GtkCellRendererText" id="renderer4"/>
<attributes>

View file

@ -25,8 +25,8 @@ void linphone_gtk_fill_combo_box(GtkWidget *combo, const char **devices, const c
const char **p=devices;
int i=0,active=-1;
GtkTreeModel *model;
if ((model=gtk_combo_box_get_model(GTK_COMBO_BOX(combo)))==NULL){
/*case where combo box is created with no model*/
GtkCellRenderer *renderer=gtk_cell_renderer_text_new();
@ -40,7 +40,7 @@ void linphone_gtk_fill_combo_box(GtkWidget *combo, const char **devices, const c
unless we fill it with a dummy text.
This dummy text needs to be removed first*/
}
for(;*p!=NULL;++p){
if ( cap==CAP_IGNORE
|| (cap==CAP_CAPTURE && linphone_core_sound_device_can_capture(linphone_gtk_get_core(),*p))
@ -836,9 +836,9 @@ static void linphone_gtk_proxy_closed(GtkWidget *w){
static void fill_transport_combo_box(GtkWidget *combo, LinphoneTransportType choice, gboolean is_sensitive){
GtkTreeModel *model;
GtkTreeIter iter;
if (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(combo),"combo-updating"))) return;
if ((model=gtk_combo_box_get_model(GTK_COMBO_BOX(combo)))==NULL){
/*case where combo box is created with no model*/
GtkCellRenderer *renderer=gtk_cell_renderer_text_new();
@ -882,9 +882,9 @@ void linphone_gtk_proxy_transport_changed(GtkWidget *combo){
const char *addr=gtk_entry_get_text(GTK_ENTRY(proxy));
LinphoneAddress *laddr;
LinphoneTransportType new_transport=(LinphoneTransportType)index;
if (index==-1) return;
g_object_set_data(G_OBJECT(w),"combo-updating",GINT_TO_POINTER(1));
laddr=linphone_address_new(addr);
if (laddr){
@ -922,6 +922,10 @@ void linphone_gtk_show_proxy_config(GtkWidget *pb, LinphoneProxyConfig *cfg){
linphone_proxy_config_register_enabled(cfg));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"publish")),
linphone_proxy_config_publish_enabled(cfg));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"avpf")),
linphone_proxy_config_avpf_enabled(cfg));
gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(w,"avpf_rr_interval")),
linphone_proxy_config_get_avpf_rr_interval(cfg));
}
g_object_set_data(G_OBJECT(w),"config",(gpointer)cfg);
g_object_set_data(G_OBJECT(w),"parameters",(gpointer)pb);
@ -941,7 +945,7 @@ void linphone_gtk_proxy_ok(GtkButton *button){
int index=gtk_combo_box_get_active(GTK_COMBO_BOX(linphone_gtk_get_widget(w,"transport")));
LinphoneTransportType tport=(LinphoneTransportType)index;
gboolean was_editing=TRUE;
if (!cfg){
was_editing=FALSE;
cfg=linphone_proxy_config_new();
@ -978,7 +982,13 @@ void linphone_gtk_proxy_ok(GtkButton *button){
linphone_proxy_config_enable_register(cfg,
gtk_toggle_button_get_active(
GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"register"))));
linphone_proxy_config_enable_avpf(cfg,
gtk_toggle_button_get_active(
GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"avpf"))));
linphone_proxy_config_set_avpf_rr_interval(cfg,
(int)gtk_spin_button_get_value(
GTK_SPIN_BUTTON(linphone_gtk_get_widget(w,"avpf_rr_interval"))));
/* check if tls was asked but is not enabled in transport configuration*/
if (tport==LinphoneTransportTls){
LCSipTransports tports;
@ -988,7 +998,7 @@ void linphone_gtk_proxy_ok(GtkButton *button){
}
linphone_core_set_sip_transports(lc,&tports);
}
if (was_editing){
if (linphone_proxy_config_done(cfg)==-1)
return;
@ -1203,15 +1213,15 @@ static void linphone_gtk_show_media_encryption(GtkWidget *pb){
GtkListStore *store;
GtkTreeIter iter;
GtkCellRenderer *renderer=gtk_cell_renderer_text_new();
model=GTK_TREE_MODEL((store=gtk_list_store_new(1,G_TYPE_STRING)));
gtk_combo_box_set_model(GTK_COMBO_BOX(combo),model);
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo),renderer,TRUE);
gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo),renderer,"text",0,NULL);
gtk_list_store_append(store,&iter);
gtk_list_store_set(store,&iter,0,_("None"),-1);
if (linphone_core_media_encryption_supported(lc,LinphoneMediaEncryptionSRTP)){
gtk_list_store_append(store,&iter);
gtk_list_store_set(store,&iter,0,_("SRTP"),-1);
@ -1293,19 +1303,26 @@ void linphone_gtk_fill_video_renderers(GtkWidget *pb){
GtkTreeModel *model=GTK_TREE_MODEL(store=gtk_list_store_new(2,G_TYPE_STRING,G_TYPE_STRING));
if (current_renderer==NULL) current_renderer=video_stream_get_default_video_renderer();
gtk_combo_box_set_model(GTK_COMBO_BOX(combo),model);
gtk_cell_layout_clear(GTK_CELL_LAYOUT(combo));
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo),renderer,TRUE);
gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo),renderer,"text",1,NULL);
for(i=0,elem=l;elem!=NULL && i<4 ;elem=elem->next,++i){
for(i=0,elem=l;elem!=NULL && i<4 ;elem=elem->next){
MSFilterDesc *desc=(MSFilterDesc *)elem->data;
GtkTreeIter iter;
/* do not offer the user to select combo 'decoding/rendering' filter */
if (desc->enc_fmt != NULL)
continue;
gtk_list_store_append(store,&iter);
gtk_list_store_set(store,&iter,0,desc->name,1,desc->text,-1);
if (current_renderer && strcmp(current_renderer,desc->name)==0)
active=i;
i++;
}
ms_list_free(l);
if (active!=-1) gtk_combo_box_set_active(GTK_COMBO_BOX(combo),active);
@ -1386,7 +1403,7 @@ void linphone_gtk_show_parameters(void){
tr.udp_port);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"sip_tcp_port")),
tr.tcp_port);
linphone_core_get_audio_port_range(lc, &min_port, &max_port);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "audio_min_rtp_port")), min_port);
@ -1404,7 +1421,7 @@ void linphone_gtk_show_parameters(void){
}
linphone_gtk_show_media_encryption(pb);
tmp=linphone_core_get_nat_address(lc);
if (tmp) gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(pb,"nat_address")),tmp);
tmp=linphone_core_get_stun_server(lc);
@ -1466,6 +1483,8 @@ void linphone_gtk_show_parameters(void){
}
#ifdef BUILD_WIZARD
gtk_widget_show(linphone_gtk_get_widget(pb,"wizard"));
#else
gtk_widget_hide(linphone_gtk_get_widget(pb,"wizard"));
#endif
linphone_gtk_show_sip_accounts(pb);
/* CODECS CONFIG */
@ -1548,9 +1567,9 @@ void linphone_gtk_edit_tunnel(GtkButton *button){
const MSList *configs;
const char *host = NULL;
int port=0;
if (!tunnel) return;
configs = linphone_tunnel_get_servers(tunnel);
if(configs != NULL) {
LinphoneTunnelConfig *ltc = (LinphoneTunnelConfig *)configs->data;
@ -1598,7 +1617,7 @@ void linphone_gtk_tunnel_ok(GtkButton *button){
gint http_port = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(w,"http_port")));
const char *username=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"username")));
const char *password=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"password")));
if (tunnel==NULL) return;
if (host && *host=='\0') host=NULL;
if (http_port==0) http_port=8080;
@ -1608,7 +1627,7 @@ void linphone_gtk_tunnel_ok(GtkButton *button){
linphone_tunnel_add_server(tunnel, config);
linphone_tunnel_enable(tunnel,enabled);
linphone_tunnel_set_http_proxy(tunnel,http_host,http_port,username,password);
gtk_widget_destroy(w);
}
@ -1621,7 +1640,7 @@ static void show_dscp(GtkWidget *entry, int val){
char tmp[20];
snprintf(tmp,sizeof(tmp),"0x%x",val);
gtk_entry_set_text(GTK_ENTRY(entry),tmp);
}
static int read_dscp(GtkWidget *entry){
@ -1660,7 +1679,7 @@ void linphone_gtk_dscp_edit_response(GtkWidget *dialog, guint response_id){
read_dscp(linphone_gtk_get_widget(dialog,"audio_dscp")));
linphone_core_set_video_dscp(lc,
read_dscp(linphone_gtk_get_widget(dialog,"video_dscp")));
break;
default:
break;

View file

@ -8,6 +8,13 @@
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
<object class="GtkAdjustment" id="adjustment2">
<property name="upper">5</property>
<property name="lower">1</property>
<property name="value">5</property>
<property name="step_increment">1</property>
<property name="page_increment">1</property>
</object>
<object class="GtkDialog" id="sip_account">
<property name="can_focus">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
@ -235,6 +242,37 @@
<property name="bottom_attach">6</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="avpf_rr_interval_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">AVPF regular RTCP interval (sec):</property>
<property name="justify">right</property>
</object>
<packing>
<property name="top_attach">6</property>
<property name="bottom_attach">7</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="avpf_rr_interval">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
<property name="adjustment">adjustment2</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">6</property>
<property name="bottom_attach">7</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label40">
<property name="visible">True</property>
@ -311,6 +349,22 @@
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="avpf">
<property name="label" translatable="yes">Enable AVPF</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="use_action_appearance">False</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
</child>
</object>

View file

@ -123,6 +123,8 @@ const char* sal_stream_type_to_string(SalStreamType type);
typedef enum{
SalProtoRtpAvp,
SalProtoRtpSavp,
SalProtoRtpAvpf,
SalProtoRtpSavpf,
SalProtoOther
}SalMediaProto;
const char* sal_media_proto_to_string(SalMediaProto type);
@ -166,7 +168,7 @@ typedef struct SalIceRemoteCandidate {
#define SAL_MEDIA_DESCRIPTION_MAX_ICE_PWD_LEN 256
/*sufficient for 256bit keys encoded in base 64*/
#define SAL_SRTP_KEY_SIZE 64
#define SAL_SRTP_KEY_SIZE 128
typedef struct SalSrtpCryptoAlgo {
unsigned int tag;
@ -213,8 +215,7 @@ typedef struct SalMediaDescription{
char name[64];
char addr[64];
char username[64];
int n_active_streams;
int n_total_streams;
int nb_streams;
int bandwidth;
unsigned int session_ver;
unsigned int session_id;
@ -233,6 +234,7 @@ typedef struct SalMessage{
const char *text;
const char *url;
const char *message_id;
const char *content_type;
time_t time;
}SalMessage;
@ -251,7 +253,17 @@ int sal_media_description_equals(const SalMediaDescription *md1, const SalMediaD
bool_t sal_media_description_has_dir(const SalMediaDescription *md, SalStreamDir dir);
SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md,
SalMediaProto proto, SalStreamType type);
unsigned int sal_media_description_nb_active_streams_of_type(SalMediaDescription *md, SalStreamType type);
SalStreamDescription * sal_media_description_get_active_stream_of_type(SalMediaDescription *md, SalStreamType type, unsigned int idx);
SalStreamDescription * sal_media_description_find_secure_stream_of_type(SalMediaDescription *md, SalStreamType type);
SalStreamDescription * sal_media_description_find_best_stream(SalMediaDescription *md, SalStreamType type);
void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_dir);
bool_t sal_stream_description_active(const SalStreamDescription *sd);
bool_t sal_stream_description_has_avpf(const SalStreamDescription *sd);
bool_t sal_stream_description_has_srtp(const SalStreamDescription *sd);
bool_t sal_media_description_has_avpf(const SalMediaDescription *md);
bool_t sal_media_description_has_srtp(const SalMediaDescription *md);
int sal_media_description_get_nb_active_streams(const SalMediaDescription *md);
/*this structure must be at the first byte of the SalOp structure defined by implementors*/
@ -507,12 +519,16 @@ void sal_set_dscp(Sal *ctx, int dscp);
int sal_reset_transports(Sal *ctx);
ortp_socket_t sal_get_socket(Sal *ctx);
void sal_set_user_agent(Sal *ctx, const char *user_agent);
const char* sal_get_user_agent(Sal *ctx);
void sal_append_stack_string_to_user_agent(Sal *ctx);
/*keepalive period in ms*/
void sal_set_keepalive_period(Sal *ctx,unsigned int value);
void sal_use_tcp_tls_keepalive(Sal *ctx, bool_t enabled);
int sal_enable_tunnel(Sal *ctx, void *tunnelclient);
void sal_disable_tunnel(Sal *ctx);
/*Default value is true*/
void sal_enable_sip_update_method(Sal *ctx,bool_t value);
/**
* returns keepalive period in ms
* 0 desactiaved
@ -529,7 +545,7 @@ void sal_verify_server_certificates(Sal *ctx, bool_t verify);
void sal_verify_server_cn(Sal *ctx, bool_t verify);
void sal_set_uuid(Sal*ctx, const char *uuid);
int sal_create_uuid(Sal*ctx, char *uuid, size_t len);
void sal_enable_test_features(Sal*ctx, bool_t enabled);
LINPHONE_PUBLIC void sal_enable_test_features(Sal*ctx, bool_t enabled);
void sal_use_no_initial_route(Sal *ctx, bool_t enabled);
int sal_iterate(Sal *sal);
@ -551,6 +567,9 @@ void sal_op_set_to_address(SalOp *op, const SalAddress *to);
SalOp *sal_op_ref(SalOp* h);
void sal_op_stop_refreshing(SalOp *op);
void sal_op_release(SalOp *h);
/*same as release, but does not stop refresher if any*/
void* sal_op_unref(SalOp* op);
void sal_op_authenticate(SalOp *h, const SalAuthInfo *info);
void sal_op_cancel_authentication(SalOp *h);
void sal_op_set_user_pointer(SalOp *h, void *up);

View file

@ -114,4 +114,9 @@ public interface LinphoneChatRoom {
* @return LinphoneChatMessage object
*/
LinphoneChatMessage createLinphoneChatMessage(String message, String url, State state, long timestamp, boolean isRead, boolean isIncoming);
/**
* Returns a back pointer to the core managing the chat room.
* @return the LinphoneCore
*/
LinphoneCore getCore();
}

View file

@ -66,7 +66,24 @@ abstract public class LinphoneCoreFactory {
* */
abstract public LinphoneAuthInfo createAuthInfo(String username, String userid, String passwd, String ha1, String realm, String domain);
/**
* Create a LinphoneCore object. The LinphoneCore is the root for all liblinphone operations. You need only one per application.
* @param listener listener to receive notifications from the core
* @param userConfig path where to read/write configuration (optional)
* @param factoryConfig path where to read factory configuration (optional)
* @param userdata any kind of application specific data
* @param context an application context, on android this MUST be the android.content.Context object used by the application.
* @return a LinphoneCore object.
* @throws LinphoneCoreException
*/
abstract public LinphoneCore createLinphoneCore(LinphoneCoreListener listener, String userConfig,String factoryConfig,Object userdata, Object context) throws LinphoneCoreException;
/**
* Create a LinphoneCore object. The LinphoneCore is the root for all liblinphone operations. You need only one per application.
* @param listener listener to receive notifications from the core.
* @param context an application context, on android this MUST be the android.content.Context object used by the application.
* @return the LinphoneCore object.
* @throws LinphoneCoreException
*/
abstract public LinphoneCore createLinphoneCore(LinphoneCoreListener listener, Object context) throws LinphoneCoreException;

View file

@ -100,4 +100,10 @@ public interface LinphoneEvent {
* @param body the new data to be published
*/
void sendPublish(LinphoneContent body);
/**
* Get a back pointer to the LinphoneCore object managing this LinphoneEvent.
* @return
*/
LinphoneCore getCore();
}

View file

@ -163,6 +163,29 @@ public interface LinphoneProxyConfig {
*/
int getPrivacy();
/**
* Indicates whether AVPF/SAVPF must be used for calls using this proxy config.
* @param enable True to enable AVPF/SAVF, false to disable it.
*/
void enableAvpf(boolean enable);
/**
* Set the interval between regular RTCP reports when using AVPF/SAVPF.
* @param interval The interval in seconds (between 0 and 5 seconds).
*/
void setAvpfRRInterval(int interval);
/**
* Get the interval between regular RTCP reports when using AVPF/SAVPF.
* @return The interval in seconds.
*/
int getAvpfRRInterval();
/**
* Whether AVPF is used for calls through this proxy.
* @return
*/
boolean avpfEnabled();
/**
* Set optional contact parameters that will be added to the contact information sent in the registration.

View file

@ -44,79 +44,110 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom {
nativePtr = aNativePtr;
}
public LinphoneAddress getPeerAddress() {
public synchronized LinphoneAddress getPeerAddress() {
return new LinphoneAddressImpl(getPeerAddress(nativePtr),LinphoneAddressImpl.WrapMode.FromConst);
}
public void sendMessage(String message) {
sendMessage(nativePtr,message);
}
@Override
public void sendMessage(LinphoneChatMessage message, StateListener listener) {
sendMessage2(nativePtr, message, ((LinphoneChatMessageImpl)message).getNativePtr(), listener);
}
@Override
public LinphoneChatMessage createLinphoneChatMessage(String message) {
return new LinphoneChatMessageImpl(createLinphoneChatMessage(nativePtr, message));
}
public LinphoneChatMessage[] getHistory() {
return getHistory(0);
}
public LinphoneChatMessage[] getHistory(int limit) {
long[] typesPtr = getHistory(nativePtr, limit);
if (typesPtr == null) return null;
LinphoneChatMessage[] messages = new LinphoneChatMessage[typesPtr.length];
for (int i=0; i < messages.length; i++) {
messages[i] = new LinphoneChatMessageImpl(typesPtr[i]);
public synchronized void sendMessage(String message) {
synchronized(getCore()){
sendMessage(nativePtr,message);
}
return messages;
}
public void destroy() {
@Override
public synchronized void sendMessage(LinphoneChatMessage message, StateListener listener) {
synchronized(getCore()){
sendMessage2(nativePtr, message, ((LinphoneChatMessageImpl)message).getNativePtr(), listener);
}
}
@Override
public synchronized LinphoneChatMessage createLinphoneChatMessage(String message) {
synchronized(getCore()){
return new LinphoneChatMessageImpl(createLinphoneChatMessage(nativePtr, message));
}
}
public synchronized LinphoneChatMessage[] getHistory() {
synchronized(getCore()){
return getHistory(0);
}
}
public synchronized LinphoneChatMessage[] getHistory(int limit) {
synchronized(getCore()){
long[] typesPtr = getHistory(nativePtr, limit);
if (typesPtr == null) return null;
LinphoneChatMessage[] messages = new LinphoneChatMessage[typesPtr.length];
for (int i=0; i < messages.length; i++) {
messages[i] = new LinphoneChatMessageImpl(typesPtr[i]);
}
return messages;
}
}
public synchronized void destroy() {
destroy(nativePtr);
}
public int getUnreadMessagesCount() {
return getUnreadMessagesCount(nativePtr);
public synchronized int getUnreadMessagesCount() {
synchronized(getCore()){
return getUnreadMessagesCount(nativePtr);
}
}
public void deleteHistory() {
deleteHistory(nativePtr);
public synchronized void deleteHistory() {
synchronized(getCore()){
deleteHistory(nativePtr);
}
}
public void compose() {
compose(nativePtr);
public synchronized void compose() {
synchronized(getCore()){
compose(nativePtr);
}
}
public boolean isRemoteComposing() {
return isRemoteComposing(nativePtr);
public synchronized boolean isRemoteComposing() {
synchronized(getCore()){
return isRemoteComposing(nativePtr);
}
}
public void markAsRead() {
markAsRead(nativePtr);
public synchronized void markAsRead() {
synchronized(getCore()){
markAsRead(nativePtr);
}
}
public void deleteMessage(LinphoneChatMessage message) {
if (message != null)
deleteMessage(nativePtr, ((LinphoneChatMessageImpl)message).getNativePtr());
public synchronized void deleteMessage(LinphoneChatMessage message) {
synchronized(getCore()){
if (message != null)
deleteMessage(nativePtr, ((LinphoneChatMessageImpl)message).getNativePtr());
}
}
public void updateUrl(LinphoneChatMessage message) {
if (message != null)
updateUrl(nativePtr, ((LinphoneChatMessageImpl)message).getNativePtr());
public synchronized void updateUrl(LinphoneChatMessage message) {
synchronized(getCore()){
if (message != null)
updateUrl(nativePtr, ((LinphoneChatMessageImpl)message).getNativePtr());
}
}
@Override
public LinphoneChatMessage createLinphoneChatMessage(String message,
public synchronized LinphoneChatMessage createLinphoneChatMessage(String message,
String url, State state, long timestamp, boolean isRead,
boolean isIncoming) {
return new LinphoneChatMessageImpl(createLinphoneChatMessage2(
nativePtr, message, url, state.value(), timestamp / 1000, isRead, isIncoming));
synchronized(getCore()){
return new LinphoneChatMessageImpl(createLinphoneChatMessage2(
nativePtr, message, url, state.value(), timestamp / 1000, isRead, isIncoming));
}
}
private native Object getCore(long nativePtr);
@Override
public synchronized LinphoneCore getCore() {
return (LinphoneCore)getCore(nativePtr);
}
}

View file

@ -610,13 +610,13 @@ class LinphoneCoreImpl implements LinphoneCore {
public synchronized void enableEchoLimiter(boolean val) {
enableEchoLimiter(nativePtr,val);
}
public void setVideoDevice(int id) {
public synchronized void setVideoDevice(int id) {
Log.i("Setting camera id :", id);
if (setVideoDevice(nativePtr, id) != 0) {
Log.e("Failed to set video device to id:", id);
}
}
public int getVideoDevice() {
public synchronized int getVideoDevice() {
return getVideoDevice(nativePtr);
}
@ -847,7 +847,7 @@ class LinphoneCoreImpl implements LinphoneCore {
private native void tunnelSetHttpProxy(long nativePtr, String proxy_host, int port,
String username, String password);
@Override
public void tunnelSetHttpProxy(String proxy_host, int port,
public synchronized void tunnelSetHttpProxy(String proxy_host, int port,
String username, String password) {
tunnelSetHttpProxy(nativePtr, proxy_host, port, username, password);
}
@ -1185,17 +1185,17 @@ class LinphoneCoreImpl implements LinphoneCore {
}
@Override
public void stopRinging() {
public synchronized void stopRinging() {
stopRinging(nativePtr);
}
private native void setPayloadTypeBitrate(long coreptr, long payload_ptr, int bitrate);
@Override
public void setPayloadTypeBitrate(PayloadType pt, int bitrate) {
public synchronized void setPayloadTypeBitrate(PayloadType pt, int bitrate) {
setPayloadTypeBitrate(nativePtr, ((PayloadTypeImpl)pt).nativePtr, bitrate);
}
private native int getPayloadTypeBitrate(long coreptr, long payload_ptr);
@Override
public int getPayloadTypeBitrate(PayloadType pt) {
public synchronized int getPayloadTypeBitrate(PayloadType pt) {
return getPayloadTypeBitrate(nativePtr, ((PayloadTypeImpl)pt).nativePtr);
}

View file

@ -11,71 +11,83 @@ public class LinphoneEventImpl implements LinphoneEvent {
private native String getEventName(long nativeptr);
@Override
public String getEventName() {
public synchronized String getEventName() {
return getEventName(mNativePtr);
}
private native int acceptSubscription(long nativeptr);
@Override
public void acceptSubscription() {
acceptSubscription(mNativePtr);
public synchronized void acceptSubscription() {
synchronized(getCore()){
acceptSubscription(mNativePtr);
}
}
private native int denySubscription(long nativeptr, int reason);
@Override
public void denySubscription(Reason reason) {
denySubscription(mNativePtr,reason.mValue);
public synchronized void denySubscription(Reason reason) {
synchronized(getCore()){
denySubscription(mNativePtr,reason.mValue);
}
}
private native int notify(long nativeptr, String type, String subtype, byte data[], String encoding);
@Override
public void notify(LinphoneContent content) {
notify(mNativePtr,content.getType(),content.getSubtype(),content.getData(),content.getEncoding());
public synchronized void notify(LinphoneContent content) {
synchronized(getCore()){
notify(mNativePtr,content.getType(),content.getSubtype(),content.getData(),content.getEncoding());
}
}
private native int updateSubscribe(long nativePtr, String type, String subtype, byte data[], String encoding);
@Override
public void updateSubscribe(LinphoneContent content) {
updateSubscribe(mNativePtr,content.getType(), content.getSubtype(),content.getData(),content.getEncoding());
public synchronized void updateSubscribe(LinphoneContent content) {
synchronized(getCore()){
updateSubscribe(mNativePtr,content.getType(), content.getSubtype(),content.getData(),content.getEncoding());
}
}
private native int updatePublish(long nativePtr, String type, String subtype, byte data[], String encoding);
@Override
public void updatePublish(LinphoneContent content) {
updatePublish(mNativePtr,content.getType(), content.getSubtype(),content.getData(),content.getEncoding());
public synchronized void updatePublish(LinphoneContent content) {
synchronized(getCore()){
updatePublish(mNativePtr,content.getType(), content.getSubtype(),content.getData(),content.getEncoding());
}
}
private native int terminate(long nativePtr);
@Override
public void terminate() {
terminate(mNativePtr);
public synchronized void terminate() {
synchronized(getCore()){
terminate(mNativePtr);
}
}
private native int getReason(long nativePtr);
@Override
public Reason getReason() {
public synchronized Reason getReason() {
return Reason.fromInt(getReason(mNativePtr));
}
@Override
public void setUserContext(Object obj) {
public synchronized void setUserContext(Object obj) {
mUserContext=obj;
}
@Override
public Object getUserContext() {
public synchronized Object getUserContext() {
return mUserContext;
}
private native int getSubscriptionDir(long nativeptr);
@Override
public SubscriptionDir getSubscriptionDir() {
public synchronized SubscriptionDir getSubscriptionDir() {
return SubscriptionDir.fromInt(getSubscriptionDir(mNativePtr));
}
private native int getSubscriptionState(long nativeptr);
@Override
public SubscriptionState getSubscriptionState() {
public synchronized SubscriptionState getSubscriptionState() {
try {
return SubscriptionState.fromInt(getSubscriptionState(mNativePtr));
} catch (LinphoneCoreException e) {
@ -91,37 +103,47 @@ public class LinphoneEventImpl implements LinphoneEvent {
private native void addCustomHeader(long ptr, String name, String value);
@Override
public void addCustomHeader(String name, String value) {
public synchronized void addCustomHeader(String name, String value) {
addCustomHeader(mNativePtr, name, value);
}
private native String getCustomHeader(long ptr, String name);
@Override
public String getCustomHeader(String name) {
public synchronized String getCustomHeader(String name) {
return getCustomHeader(mNativePtr, name);
}
private native void sendSubscribe(long ptr, String type, String subtype, byte data [], String encoding);
@Override
public void sendSubscribe(LinphoneContent body) {
if (body != null)
sendSubscribe(mNativePtr, body.getType(), body.getSubtype(), body.getData(), body.getEncoding());
else
sendSubscribe(mNativePtr, null, null, null, null);
public synchronized void sendSubscribe(LinphoneContent body) {
synchronized(getCore()){
if (body != null)
sendSubscribe(mNativePtr, body.getType(), body.getSubtype(), body.getData(), body.getEncoding());
else
sendSubscribe(mNativePtr, null, null, null, null);
}
}
private native void sendPublish(long ptr, String type, String subtype, byte data [], String encoding);
@Override
public void sendPublish(LinphoneContent body) {
if (body != null)
sendPublish(mNativePtr, body.getType(), body.getSubtype(), body.getData(), body.getEncoding());
else
sendPublish(mNativePtr, null, null, null, null);
public synchronized void sendPublish(LinphoneContent body) {
synchronized(getCore()){
if (body != null)
sendPublish(mNativePtr, body.getType(), body.getSubtype(), body.getData(), body.getEncoding());
else
sendPublish(mNativePtr, null, null, null, null);
}
}
private native long getErrorInfo(long nativePtr);
@Override
public ErrorInfo getErrorInfo() {
public synchronized ErrorInfo getErrorInfo() {
return new ErrorInfoImpl(getErrorInfo(mNativePtr));
}
private native Object getCore(long nativePtr);
@Override
public synchronized LinphoneCore getCore() {
return (LinphoneCore)getCore(mNativePtr);
}
}

View file

@ -198,6 +198,30 @@ class LinphoneProxyConfigImpl implements LinphoneProxyConfig {
return getPrivacy(nativePtr);
}
private native void enableAvpf(long nativePtr, boolean enable);
@Override
public void enableAvpf(boolean enable) {
enableAvpf(nativePtr, enable);
}
private native boolean avpfEnabled(long nativePtr);
@Override
public boolean avpfEnabled() {
return avpfEnabled(nativePtr);
}
private native void setAvpfRRInterval(long nativePtr, int interval);
@Override
public void setAvpfRRInterval(int interval) {
setAvpfRRInterval(nativePtr, interval);
}
private native int getAvpfRRInterval(long nativePtr);
@Override
public int getAvpfRRInterval() {
return getAvpfRRInterval(nativePtr);
}
private native String getContactParameters(long ptr);
@Override
public String getContactParameters() {

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