Merge branch 'master' into dev_rtt

This commit is contained in:
Sylvain Berfini 2015-09-10 14:19:52 +02:00
commit 1a43b01696
139 changed files with 12488 additions and 8073 deletions

64
.clang-format Normal file
View file

@ -0,0 +1,64 @@
---
# BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: true
AlignEscapedNewlinesLeft: false
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: false
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: false
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false
BinPackArguments: true
BinPackParameters: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
IndentCaseLabels: false
IndentFunctionDeclarationAfterType: false
IndentWidth: 4
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: true
Language: Cpp
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
SpaceAfterCStyleCast: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 4
UseTab: Always
...

51
.git-pre-commit Executable file
View file

@ -0,0 +1,51 @@
#!/bin/bash
# This hook purpose is to keep coding style consistent between all developers
# It is automatically installed in .git/hooks folder by cmake on first run.
# From https://github.com/tatsuhiro-t/nghttp2/blob/master/pre-commit
function invalid-format-detected {
cat git-clang-format.diff
echo "*****************"
echo "$0: Invalid coding style detected (see git-clang-format.diff for issues). Please correct it using one of the following:"
echo "1) Apply patch located at git-clang-format.diff using:"
echo " cd $(git rev-parse --show-toplevel) && $1"
echo "2) Use clang-format to correctly format source code using:"
echo " $2"
echo "3) Reformat these lines manually."
echo "*** Aborting commit.***"
exit 1
}
function git-clang-format-diffing {
format_diff=$(which git-clang-format)
format_diff_options="--style=file"
#only diffing commited files, ignored staged one
$format_diff $format_diff_options --diff $(git --no-pager diff --cached --name-status | grep -v '^D' | cut -f2) > git-clang-format.diff
if ! grep -q -E '(no modified files to format|clang-format did not modify any files)' git-clang-format.diff; then
invalid-format-detected "git apply git-clang-format.diff" "clang-format $format_diff_options -i <some_file.c>"
fi
}
function clang-format-diff-diffing {
format_diff=$(find /usr/bin/ -name 'clang-format-diff*' -type f | tail -n1)
format_diff_options="-style file"
git diff-index --cached --diff-filter=ACMR -p HEAD -- | $format_diff $format_diff_options -p1 > git-clang-format.diff
if [ -s git-clang-format.diff ]; then
invalid-format-detected "patch -p0 < git-clang-format.diff" "${format_diff/-diff/} $format_diff_options -i <some_file.cpp>"
fi
}
set -e
if which git-clang-format &>/dev/null; then
git-clang-format-diffing $@
elif [ ! -z "$(find /usr/bin/ /usr/local/bin/ /opt/bin/ -name 'clang-format-diff*' -type f 2>/dev/null)" ]; then
# Warning! We need at least version 1.6...
clang-format-diff-diffing $@
else
echo "$0: Please install clang-format (coding style checker) - could not find git-clang-format nor clang-format-diff in PATH. Skipping code verification..."
exit 0
fi

3
.gitignore vendored
View file

@ -89,3 +89,6 @@ tester/record_for_lc_*.wav
tester/record-call_with_file_player.wav
tester/ZIDCache*.xml
tester/stereo-record.wav
.dirstamp
git-clang-format.diff

View file

@ -127,7 +127,6 @@ if(ENABLE_GTK_UI)
set(GTK2_ADDITIONAL_SUFFIXES "../lib/glib-2.0/include" "../lib/gtk-2.0/include")
endif()
find_package(GTK2 2.18 REQUIRED gtk)
find_package(Intl REQUIRED)
if(ENABLE_ASSISTANT AND GTK2_VERSION VERSION_LESS 2.22)
message(WARNING "You need at least GTK 2.22 to enable the assistant")
set(ENABLE_ASSISTANT OFF CACHE BOOL "Turn on assistant compiling." FORCE)
@ -136,12 +135,16 @@ endif()
if(ENABLE_ASSISTANT)
set(BUILD_WIZARD 1)
endif()
find_package(Gettext)
if(ENABLE_NLS)
find_package(Gettext REQUIRED)
find_package(Intl REQUIRED)
include_directories(${INTL_INCLUDE_DIRS})
endif()
if(UNIX AND NOT APPLE)
include(CheckIncludeFiles)
check_include_files(libudev.h HAVE_LIBUDEV_H)
endif()
include_directories(
include/

View file

@ -16,19 +16,25 @@ else
AUTOMAKE=automake-${AM_VERSION}
fi
if test -f /opt/local/bin/glibtoolize ; then
# darwin
LIBTOOLIZE=/opt/local/bin/glibtoolize
else
LIBTOOLIZE=libtoolize
fi
LIBTOOLIZE="libtoolize"
for lt in glibtoolize libtoolize15 libtoolize14 libtoolize13 ; do
if test -x /usr/bin/$lt ; then
LIBTOOLIZE=$lt ; break
fi
if test -x /usr/local/bin/$lt ; then
LIBTOOLIZE=$lt ; break
fi
if test -x /opt/local/bin/$lt ; then
LIBTOOLIZE=$lt ; break
fi
done
if test -d /opt/local/share/aclocal ; then
ACLOCAL_ARGS="-I /opt/local/share/aclocal"
ACLOCAL_ARGS="-I /opt/local/share/aclocal"
fi
if test -d /share/aclocal ; then
ACLOCAL_ARGS="$ACLOCAL_ARGS -I /share/aclocal"
ACLOCAL_ARGS="$ACLOCAL_ARGS -I /share/aclocal"
fi
INTLTOOLIZE=$(which intltoolize)
@ -49,6 +55,13 @@ $AUTOMAKE --force-missing --add-missing --copy
autoconf
set +x
#install git pre-commit hooks if possible
if [ -d .git/hooks ] && [ ! -f .git/hooks/pre-commit ]; then
cp .git-pre-commit .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
fi
if [ "$srcdir" = "." ]; then
if [ -x oRTP/autogen.sh ]; then
echo "Generating build scripts in oRTP..."

View file

@ -118,6 +118,7 @@ LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/../build/android \
$(LOCAL_PATH)/../oRTP/include \
$(LOCAL_PATH)/../mediastreamer2/include \
$(LOCAL_PATH)/../mediastreamer2/src/audiofilters/ \
$(LOCAL_PATH)/../../belle-sip/include \
$(LOCAL_PATH)/../../../gen \
$(LOCAL_PATH)/../../externals/libxml2/include \
@ -172,6 +173,11 @@ LOCAL_CFLAGS += -DHAVE_SILK
LOCAL_STATIC_LIBRARIES += libmssilk
endif
ifeq ($(BUILD_CODEC2),1)
LOCAL_CFLAGS += -DHAVE_CODEC2
LOCAL_STATIC_LIBRARIES += libcodec2 libmscodec2
endif
ifneq ($(BUILD_WEBRTC_AECM)$(BUILD_WEBRTC_ISAC),00)
LOCAL_CFLAGS += -DHAVE_WEBRTC
LOCAL_STATIC_LIBRARIES += libmswebrtc

View file

@ -76,7 +76,7 @@
</binary>
<data>
${prefix}/share/mime/globs
${prefix}/share/mime/mime.cache
</data>
<binary>
@ -136,6 +136,10 @@
${prefix:linphone}/share/images
</data>
<data>
${prefix:linphone}/share/icons
</data>
<!-- Copy in the themes data. You may want to trim this to save space
in your bundle. -->

View file

@ -37,6 +37,7 @@ namespace liblinphone_tester
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
LibLinphoneTester.Instance.setWritableDirectory(ApplicationData.Current.LocalFolder);
_suites = UnitTestDataSource.GetSuites(LibLinphoneTester.Instance);
TryAutoLaunch();
}

View file

@ -70,7 +70,9 @@
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Store</ApplicationType>
<ApplicationTypeRevision>8.2</ApplicationTypeRevision>
<ApplicationTypeRevision>10</ApplicationTypeRevision>
<WindowsTargetPlatformVersion>10.0.10240.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.10069.0</WindowsTargetPlatformMinVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">

View file

@ -81,7 +81,9 @@
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Store</ApplicationType>
<ApplicationTypeRevision>8.2</ApplicationTypeRevision>
<ApplicationTypeRevision>10</ApplicationTypeRevision>
<WindowsTargetPlatformVersion>10.0.10240.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.10069.0</WindowsTargetPlatformMinVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">

View file

@ -11,20 +11,18 @@
<AssemblyName>liblinphone-tester</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion>10.0.10069.0</TargetPlatformVersion>
<TargetPlatformVersion>10.0.10240.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.10069.0</TargetPlatformMinVersion>
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
<EnableDotNetNativeCompatibleProfile>true</EnableDotNetNativeCompatibleProfile>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<PackageCertificateKeyFile>liblinphone-tester_TemporaryKey.pfx</PackageCertificateKeyFile>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\ARM\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UAP</DefineConstants>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>ARM</PlatformTarget>
@ -34,7 +32,7 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
<OutputPath>bin\ARM\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UAP</DefineConstants>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
@ -47,7 +45,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UAP</DefineConstants>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
@ -57,7 +55,7 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UAP</DefineConstants>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
@ -70,7 +68,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UAP</DefineConstants>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
@ -80,7 +78,7 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UAP</DefineConstants>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
@ -90,6 +88,13 @@
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<ItemGroup>
<!-- A reference to the entire .Net Framework and Windows SDK are automatically included -->
<Content Include="ApplicationInsights.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<None Include="project.json" />
</ItemGroup>
<ItemGroup>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
@ -104,7 +109,10 @@
<AppxManifest Include="Package.appxmanifest">
<SubType>Designer</SubType>
</AppxManifest>
<None Include="ApplicationInsights.config" />
<None Include="liblinphone-tester_TemporaryKey.pfx" />
</ItemGroup>
<ItemGroup>
<Content Include="Properties\Default.rd.xml" />
<Content Include="Assets\images\nowebcamCIF.jpg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@ -261,14 +269,9 @@
<Content Include="Assets\certificates\cn\openssl-cn.cnf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<None Include="liblinphone-tester_TemporaryKey.pfx" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Content Include="Assets\Logo.png" />
<Content Include="Assets\SmallLogo.png" />
<Content Include="Assets\SplashScreen.png" />
<Content Include="Properties\Default.rd.xml" />
<Content Include="Assets\WideLogo.scale-100.png" />
</ItemGroup>
<ItemGroup>
@ -281,28 +284,6 @@
<SubType>Designer</SubType>
</Page>
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.ApplicationInsights, Version=0.14.3.177, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>packages\Microsoft.ApplicationInsights.0.14.3-build00177\lib\portable-win81+wpa81\Microsoft.ApplicationInsights.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.ApplicationInsights.Extensibility.Windows, Version=0.14.3.177, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>packages\Microsoft.ApplicationInsights.WindowsApps.0.14.3-build00177\lib\win81\Microsoft.ApplicationInsights.Extensibility.Windows.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.ApplicationInsights.PersistenceChannel, Version=0.14.3.186, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>packages\Microsoft.ApplicationInsights.PersistenceChannel.0.14.3-build00177\lib\portable-win81+wpa81\Microsoft.ApplicationInsights.PersistenceChannel.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Numerics.Vectors, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.Numerics.Vectors.4.0.0\lib\win8\System.Numerics.Vectors.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Numerics.Vectors.WindowsRuntime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.Numerics.Vectors.4.0.0\lib\win8\System.Numerics.Vectors.WindowsRuntime.dll</HintPath>
<Private>True</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="liblinphone-tester-runtime-component\liblinphone-tester-runtime-component.vcxproj">
<Project>{1ce10f06-8fad-437f-b3d7-3b7a8909a190}</Project>
@ -314,15 +295,6 @@
<VisualStudioVersion>14.0</VisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
<Import Project="packages\Microsoft.Diagnostics.Tracing.EventSource.Redist.1.1.16-beta\build\portable-net45+win8+wpa81\Microsoft.Diagnostics.Tracing.EventSource.Redist.targets" Condition="Exists('packages\Microsoft.Diagnostics.Tracing.EventSource.Redist.1.1.16-beta\build\portable-net45+win8+wpa81\Microsoft.Diagnostics.Tracing.EventSource.Redist.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('packages\Microsoft.Diagnostics.Tracing.EventSource.Redist.1.1.16-beta\build\portable-net45+win8+wpa81\Microsoft.Diagnostics.Tracing.EventSource.Redist.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.Diagnostics.Tracing.EventSource.Redist.1.1.16-beta\build\portable-net45+win8+wpa81\Microsoft.Diagnostics.Tracing.EventSource.Redist.targets'))" />
<Error Condition="!Exists('packages\Microsoft.ApplicationInsights.0.14.3-build00177\build\portable-win81+wpa81\Microsoft.ApplicationInsights.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.ApplicationInsights.0.14.3-build00177\build\portable-win81+wpa81\Microsoft.ApplicationInsights.targets'))" />
</Target>
<Import Project="packages\Microsoft.ApplicationInsights.0.14.3-build00177\build\portable-win81+wpa81\Microsoft.ApplicationInsights.targets" Condition="Exists('packages\Microsoft.ApplicationInsights.0.14.3-build00177\build\portable-win81+wpa81\Microsoft.ApplicationInsights.targets')" />
<PropertyGroup>
<PreBuildEvent>XCopy /I /Y $(ProjectDir)..\..\..\tester\tester_hosts $(ProjectDir)Assets\
XCopy /I /Y $(ProjectDir)..\..\..\tester\certificates\altname $(ProjectDir)Assets\certificates\altname

View file

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.ApplicationInsights" version="0.14.3-build00177" targetFramework="win81" userInstalled="true" />
<package id="Microsoft.ApplicationInsights.PersistenceChannel" version="0.14.3-build00177" targetFramework="win81" userInstalled="true" />
<package id="Microsoft.ApplicationInsights.WindowsApps" version="0.14.3-build00177" targetFramework="win81" userInstalled="true" />
<package id="Microsoft.Diagnostics.Tracing.EventSource.Redist" version="1.1.16-beta" targetFramework="win81" userInstalled="true" />
<package id="System.Numerics.Vectors" version="4.0.0" targetFramework="win81" userInstalled="true" />
</packages>

View file

@ -0,0 +1,19 @@
{
"dependencies": {
"Microsoft.ApplicationInsights": "1.0.0",
"Microsoft.ApplicationInsights.PersistenceChannel": "1.0.0",
"Microsoft.ApplicationInsights.WindowsApps": "1.0.0",
"Microsoft.NETCore.UniversalWindowsPlatform": "5.0.0"
},
"frameworks": {
"uap10.0": {}
},
"runtimes": {
"win10-arm": {},
"win10-arm-aot": {},
"win10-x86": {},
"win10-x86-aot": {},
"win10-x64": {},
"win10-x64-aot": {}
}
}

View file

@ -135,7 +135,9 @@
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Store</ApplicationType>
<ApplicationTypeRevision>8.2</ApplicationTypeRevision>
<ApplicationTypeRevision>10</ApplicationTypeRevision>
<WindowsTargetPlatformVersion>10.0.10240.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.10069.0</WindowsTargetPlatformMinVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">

View file

@ -42,4 +42,5 @@
#cmakedefine HAVE_ZLIB 1
#cmakedefine HAVE_CU_GET_SUITE 1
#cmakedefine HAVE_CU_CURSES 1
#cmakedefine HAVE_LIBUDEV_H 0
#cmakedefine ENABLE_NLS 1

View file

@ -633,7 +633,7 @@ lpc_cmd_chat(LinphoneCore *lc, char *args)
/* missing one parameter */
return 0;
}
cr = linphone_core_create_chat_room(lc,arg1);
cr = linphone_core_get_chat_room_from_uri(lc,arg1);
linphone_chat_room_send_message(cr,arg2);
return 1;
}

View file

@ -56,7 +56,7 @@ namespace belledonnecomm {
* @param ip tunnel server ip address
* @param port tunnel server tls port, recommended value is 443
* @param udpMirrorPort remote port on the tunnel server side used to test udp reachability
* @param delay udp packet round trip delay in ms considered as acceptable. recommanded value is 1000 ms.
* @param delay udp packet round trip delay in ms considered as acceptable. recommended value is 1000 ms.
*/
void addServer(const char *ip, int port,unsigned int udpMirrorPort,unsigned int delay);
/**

View file

@ -84,6 +84,7 @@ static void _linphone_account_creator_destroy(LinphoneAccountCreator *creator) {
if (creator->domain) ms_free(creator->domain);
if (creator->route) ms_free(creator->route);
if (creator->email) ms_free(creator->email);
if (creator->display_name) ms_free(creator->display_name);
ms_free(creator);
}
@ -155,6 +156,14 @@ const char * linphone_account_creator_get_route(const LinphoneAccountCreator *cr
return creator->route;
}
void linphone_account_creator_set_display_name(LinphoneAccountCreator *creator, const char *display_name) {
set_string(&creator->display_name, display_name);
}
const char * linphone_account_creator_get_display_name(const LinphoneAccountCreator *creator) {
return creator->display_name;
}
void linphone_account_creator_set_email(LinphoneAccountCreator *creator, const char *email) {
set_string(&creator->email, email);
}
@ -269,12 +278,15 @@ LinphoneAccountCreatorStatus linphone_account_creator_validate(LinphoneAccountCr
}
LinphoneProxyConfig * linphone_account_creator_configure(const LinphoneAccountCreator *creator) {
const LinphoneAddress *identity;
LinphoneAuthInfo *info;
LinphoneProxyConfig *cfg = linphone_core_create_proxy_config(creator->core);
char *identity_str = ms_strdup_printf("sip:%s@%s", creator->username, creator->domain);
LinphoneAddress *identity = linphone_address_new(identity_str);
if (creator->display_name) {
linphone_address_set_display_name(identity, creator->display_name);
}
linphone_proxy_config_set_identity(cfg, identity_str);
linphone_proxy_config_set_identity(cfg, linphone_address_as_string(identity));
linphone_proxy_config_set_server_addr(cfg, creator->domain);
linphone_proxy_config_set_route(cfg, creator->route);
linphone_proxy_config_enable_publish(cfg, FALSE);
@ -298,9 +310,9 @@ LinphoneProxyConfig * linphone_account_creator_configure(const LinphoneAccountCr
linphone_core_set_firewall_policy(creator->core, LinphonePolicyUseIce);
}
identity = linphone_proxy_config_get_identity_address(cfg);
info = linphone_auth_info_new(linphone_address_get_username(identity), NULL, creator->password, NULL, NULL, linphone_address_get_domain(identity));
linphone_core_add_auth_info(creator->core, info);
linphone_address_destroy(identity);
if (linphone_core_add_proxy_config(creator->core, cfg) != -1) {
linphone_core_set_default_proxy(creator->core, cfg);

View file

@ -161,6 +161,20 @@ LINPHONE_PUBLIC void linphone_account_creator_set_route(LinphoneAccountCreator *
**/
LINPHONE_PUBLIC const char * linphone_account_creator_get_route(const LinphoneAccountCreator *creator);
/**
* Set the email.
* @param[in] creator LinphoneAccountCreator object
* @param[in] display_name The display name to set
**/
LINPHONE_PUBLIC void linphone_account_creator_set_display_name(LinphoneAccountCreator *creator, const char *display_name);
/**
* Get the email.
* @param[in] creator LinphoneAccountCreator object
* @return The display name of the LinphoneAccountCreator
**/
LINPHONE_PUBLIC const char * linphone_account_creator_get_display_name(const LinphoneAccountCreator *creator);
/**
* Set the email.
* @param[in] creator LinphoneAccountCreator object

View file

@ -93,7 +93,6 @@ struct SalOp{
belle_sip_header_referred_by_t *referred_by;
SalMediaDescription *result;
belle_sdp_session_description_t *sdp_answer;
bool_t supports_session_timers;
SalOpState state;
SalOpDir dir;
belle_sip_refresher_t* refresher;
@ -101,14 +100,15 @@ struct SalOp{
SalOpType type;
SalPrivacyMask privacy;
belle_sip_header_t *event; /*used by SalOpSubscribe kinds*/
SalOpSDPHandling sdp_handling;
int auth_requests; /*number of auth requested for this op*/
bool_t cnx_ip_to_0000_if_sendonly_enabled;
bool_t auto_answer_asked;
bool_t sdp_offering;
bool_t call_released;
bool_t manual_refresher;
bool_t has_auth_pending;
SalOpSDPHandling sdp_handling;
int auth_requests; /*number of auth requested for this op*/
bool_t cnx_ip_to_0000_if_sendonly_enabled; /*for */
bool_t supports_session_timers;
};

View file

@ -302,10 +302,10 @@ static void call_process_response(void *op_base, const belle_sip_response_event_
&& (header_content_type = belle_sip_message_get_header_by_type(req,belle_sip_header_content_type_t))
&& strcmp("application",belle_sip_header_content_type_get_type(header_content_type))==0
&& strcmp("media_control+xml",belle_sip_header_content_type_get_subtype(header_content_type))==0) {
unsigned int retry_in =1000*((float)rand()/RAND_MAX);
belle_sip_source_t *s=sal_create_timer(op->base.root,vfu_retry,sal_op_ref(op), retry_in, "vfu request retry");
ms_message("Rejected vfu request on op [%p], just retry in [%ui] ms",op,retry_in);
belle_sip_object_unref(s);
unsigned int retry_in =1000*((float)rand()/RAND_MAX);
belle_sip_source_t *s=sal_create_timer(op->base.root,vfu_retry,sal_op_ref(op), retry_in, "vfu request retry");
ms_message("Rejected vfu request on op [%p], just retry in [%ui] ms",op,retry_in);
belle_sip_object_unref(s);
}else {
/*ignoring*/
}
@ -323,7 +323,7 @@ static void call_process_response(void *op_base, const belle_sip_response_event_
}
break;
case BELLE_SIP_DIALOG_TERMINATED: {
if (code >= 300){
if (strcmp("INVITE",method)==0 && code >= 300){
call_set_error(op,response);
}
}
@ -578,22 +578,27 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t
case BELLE_SIP_DIALOG_CONFIRMED:
/*great ACK received*/
if (strcmp("ACK",method)==0) {
if (op->sdp_offering){
SalReason reason;
if (extract_sdp(op,BELLE_SIP_MESSAGE(req),&sdp,&reason)==0){
if (sdp){
if (op->base.remote_media)
sal_media_description_unref(op->base.remote_media);
op->base.remote_media=sal_media_description_new();
sdp_to_media_description(sdp,op->base.remote_media);
sdp_process(op);
belle_sip_object_unref(sdp);
}else{
ms_warning("SDP expected in ACK but not found.");
if (!op->pending_client_trans ||
!belle_sip_transaction_state_is_transient(belle_sip_transaction_get_state((belle_sip_transaction_t*)op->pending_client_trans))){
if (op->sdp_offering){
SalReason reason;
if (extract_sdp(op,BELLE_SIP_MESSAGE(req),&sdp,&reason)==0){
if (sdp){
if (op->base.remote_media)
sal_media_description_unref(op->base.remote_media);
op->base.remote_media=sal_media_description_new();
sdp_to_media_description(sdp,op->base.remote_media);
sdp_process(op);
belle_sip_object_unref(sdp);
}else{
ms_warning("SDP expected in ACK but not found.");
}
}
}
op->base.root->callbacks.call_ack(op);
}else{
ms_message("Ignored received ack since a new client transaction has been started since.");
}
op->base.root->callbacks.call_ack(op);
} else if(strcmp("BYE",method)==0) {
resp=sal_op_create_response_from_request(op,req,200);
belle_sip_server_transaction_send_response(server_transaction,resp);

View file

@ -128,6 +128,12 @@ static void add_rtcp_fb_attributes(belle_sdp_media_description_t *media_desc, co
if (general_trr_int == TRUE) {
add_rtcp_fb_trr_int_attribute(media_desc, -1, trr_int);
}
if (stream->rtcp_fb.generic_nack_enabled == TRUE) {
add_rtcp_fb_nack_attribute(media_desc, -1, BELLE_SDP_RTCP_FB_NONE);
}
if (stream->rtcp_fb.tmmbr_enabled == TRUE) {
add_rtcp_fb_ccm_attribute(media_desc, -1, BELLE_SDP_RTCP_FB_TMMBR);
}
for (pt_it = stream->payloads; pt_it != NULL; pt_it = pt_it->next) {
pt = (PayloadType *)pt_it->data;
@ -261,7 +267,7 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session
/* insert DTLS session attribute if needed */
if ((stream->proto == SalProtoUdpTlsRtpSavpf) || (stream->proto == SalProtoUdpTlsRtpSavp)) {
char* ssrc_attribute = ms_strdup_printf("%u cname:%s",htonl(stream->rtp_ssrc),stream->rtcp_cname);
char* ssrc_attribute = ms_strdup_printf("%u cname:%s",stream->rtp_ssrc,stream->rtcp_cname);
if ((stream->dtls_role != SalDtlsRoleInvalid) && (strlen(stream->dtls_fingerprint)>0)) {
switch(stream->dtls_role) {
case SalDtlsRoleIsClient:
@ -277,7 +283,7 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session
}
belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("fingerprint",stream->dtls_fingerprint));
}
belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("ssrc",ssrc_attribute)); /* truc de Jehan a virer? */
belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("ssrc",ssrc_attribute));
ms_free(ssrc_attribute);
}
@ -550,7 +556,7 @@ static void enable_avpf_for_stream(SalStreamDescription *stream) {
}
}
static void apply_rtcp_fb_attribute_to_payload(belle_sdp_rtcp_fb_attribute_t *fb_attribute, PayloadType *pt) {
static void apply_rtcp_fb_attribute_to_payload(belle_sdp_rtcp_fb_attribute_t *fb_attribute, SalStreamDescription *stream, 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_ACK:
@ -574,6 +580,8 @@ static void apply_rtcp_fb_attribute_to_payload(belle_sdp_rtcp_fb_attribute_t *fb
avpf_params.rpsi_compatibility = TRUE;
break;
case BELLE_SDP_RTCP_FB_NONE:
stream->rtcp_fb.generic_nack_enabled = TRUE;
break;
default:
break;
}
@ -586,6 +594,9 @@ static void apply_rtcp_fb_attribute_to_payload(belle_sdp_rtcp_fb_attribute_t *fb
case BELLE_SDP_RTCP_FB_FIR:
avpf_params.features |= PAYLOAD_TYPE_AVPF_FIR;
break;
case BELLE_SDP_RTCP_FB_TMMBR:
stream->rtcp_fb.tmmbr_enabled = TRUE;
break;
default:
break;
}
@ -612,7 +623,7 @@ static void sdp_parse_rtcp_fb_parameters(belle_sdp_media_description_t *media_de
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);
apply_rtcp_fb_attribute_to_payload(fb_attribute, stream, pt);
}
}
}
@ -627,7 +638,7 @@ static void sdp_parse_rtcp_fb_parameters(belle_sdp_media_description_t *media_de
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);
apply_rtcp_fb_attribute_to_payload(fb_attribute, stream, pt);
}
}
}

View file

@ -43,6 +43,9 @@ SalStreamDir sal_dir_from_call_params_dir(LinphoneMediaDirection cpdir) {
return SalStreamRecvOnly;
case LinphoneMediaDirectionSendRecv:
return SalStreamSendRecv;
case LinphoneMediaDirectionInvalid:
ms_error("LinphoneMediaDirectionInvalid shall not be used.");
return SalStreamInactive;
}
return SalStreamSendRecv;
}

View file

@ -34,11 +34,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* Indicates for a given media the stream direction
* */
enum _LinphoneMediaDirection {
LinphoneMediaDirectionInvalid = -1,
LinphoneMediaDirectionInactive, /** No active media not supported yet*/
LinphoneMediaDirectionSendOnly, /** Send only mode*/
LinphoneMediaDirectionRecvOnly, /** recv only mode*/
LinphoneMediaDirectionSendRecv, /*send receive mode not supported yet*/
LinphoneMediaDirectionSendRecv, /** send receive*/
};
/**
* Typedef for enum

View file

@ -111,16 +111,14 @@ void linphone_call_update_frozen_payloads(LinphoneCall *call, SalMediaDescriptio
/*new codec, needs to be added to the list*/
local->streams[i].already_assigned_payloads=ms_list_append(local->streams[i].already_assigned_payloads, payload_type_clone(pt));
ms_message("LinphoneCall[%p] : payload type %i %s/%i fmtp=%s added to frozen list.",
call, payload_type_get_number(pt), pt->mime_type, pt->clock_rate, pt->recv_fmtp ? pt->recv_fmtp : NULL);
call, payload_type_get_number(pt), pt->mime_type, pt->clock_rate, pt->recv_fmtp ? pt->recv_fmtp : "");
}
}
}
}
void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md){
void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md, LinphoneCallState target_state){
SalMediaDescription *oldmd=call->resultdesc;
bool_t all_muted=FALSE;
bool_t send_ringbacktone=FALSE;
int md_changed=0;
@ -144,7 +142,6 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia
call->biggestdesc=sal_media_description_ref(sal_call_get_remote_media_description(call->op));
}
sal_media_description_ref(new_md);
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);
@ -201,25 +198,11 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia
/*this happens after pausing the call locally. The streams are destroyed and then we wait the 200Ok to recreate them*/
linphone_call_init_media_streams (call);
}
if (call->state==LinphoneCallIncomingEarlyMedia && linphone_core_get_remote_ringback_tone (lc)!=NULL){
send_ringbacktone=TRUE;
}
if ((call->state==LinphoneCallIncomingEarlyMedia || call->state==LinphoneCallOutgoingEarlyMedia) && !call->params->real_early_media){
all_muted=TRUE;
}
if (call->params->real_early_media && call->state==LinphoneCallOutgoingEarlyMedia){
prepare_early_media_forking(call);
}
#ifdef VIDEO_ENABLED
if (call->state==LinphoneCallPausing) {
/*change cam to noweb cam*/
call->cam = get_nowebcam_device();
} else if (call->state != LinphoneCallPaused) {
/*restaure web cam*/
call->cam = lc->video_conf.device;
}
#endif /*VIDEO*/
linphone_call_start_media_streams(call,all_muted,send_ringbacktone);
linphone_call_start_media_streams(call, target_state);
if (call->state==LinphoneCallPausing && call->paused_by_app && ms_list_size(lc->calls)==1){
linphone_core_play_named_tone(lc,LinphoneToneCallOnHold);
}
@ -346,7 +329,7 @@ static void call_received(SalOp *h){
call=linphone_call_new_incoming(lc,from_addr,to_addr,h);
linphone_call_make_local_media_description(lc,call);
linphone_call_make_local_media_description(call);
sal_call_set_local_media_description(call->op,call->localdesc);
md=sal_call_get_final_media_description(call->op);
if (md){
@ -476,7 +459,7 @@ static void call_ringing(SalOp *h){
linphone_call_set_state(call,LinphoneCallOutgoingEarlyMedia,"Early media");
linphone_core_stop_ringing(lc);
ms_message("Doing early media...");
linphone_core_update_streams(lc,call,md);
linphone_core_update_streams(lc,call,md, call->state);
if ((linphone_call_params_get_audio_direction(linphone_call_get_current_params(call)) == LinphoneMediaDirectionInactive) && call->audiostream) {
if (lc->ringstream != NULL) return; /* Already ringing! */
start_remote_ring(lc, call);
@ -484,24 +467,41 @@ static void call_ringing(SalOp *h){
}
}
/*
* could be reach :
* - when the call is accepted
* - when a request is accepted (pause, resume)
*/
static void call_accepted(SalOp *op){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
SalMediaDescription *md, *rmd;
bool_t update_state=TRUE;
static void start_pending_refer(LinphoneCall *call){
linphone_core_start_refered_call(call->core, call,NULL);
}
if (call==NULL){
ms_warning("No call to accept.");
return ;
static void process_call_accepted(LinphoneCore *lc, LinphoneCall *call, SalOp *op){
SalMediaDescription *md, *rmd;
LinphoneCallState next_state = LinphoneCallIdle;
const char *next_state_str = NULL;
LinphoneTaskList tl;
switch (call->state){/*immediately notify the connected state, even if errors occur after*/
case LinphoneCallOutgoingProgress:
case LinphoneCallOutgoingRinging:
case LinphoneCallOutgoingEarlyMedia:
/*immediately notify the connected state*/
linphone_call_set_state(call,LinphoneCallConnected,"Connected");
{
char *tmp=linphone_call_get_remote_address_as_string (call);
char *msg=ms_strdup_printf(_("Call answered by %s"),tmp);
linphone_core_notify_display_status(lc,msg);
ms_free(tmp);
ms_free(msg);
}
break;
default:
break;
}
linphone_task_list_init(&tl);
rmd=sal_call_get_remote_media_description(op);
/*set privacy*/
call->current_params->privacy=(LinphonePrivacyMask)sal_op_get_privacy(call->op);
/*reset the internal call update flag, so it doesn't risk to be copied and used in further re-INVITEs*/
if (call->params->internal_call_update)
call->params->internal_call_update = FALSE;
/* Handle remote ICE attributes if any. */
if (call->ice_session != NULL && rmd) {
@ -514,130 +514,108 @@ static void call_accepted(SalOp *op){
#endif //BUILD_UPNP
md=sal_call_get_final_media_description(op);
switch (call->state){
case LinphoneCallOutgoingProgress:
case LinphoneCallOutgoingRinging:
case LinphoneCallOutgoingEarlyMedia:
linphone_call_set_state(call,LinphoneCallConnected,"Connected");
if (call->referer) linphone_core_notify_refer_state(lc,call->referer,call);
break;
case LinphoneCallEarlyUpdating:
linphone_call_set_state(call,call->prevstate,"Early update accepted");
update_state=FALSE;
break;
default:
break;
if (md == NULL && call->prevstate == LinphoneCallOutgoingEarlyMedia && call->resultdesc != NULL){
ms_message("Using early media SDP since none was received with the 200 OK");
md = call->resultdesc;
}
if( (call->prevstate == LinphoneCallOutgoingEarlyMedia) && (md == NULL || sal_media_description_empty(md)) ){
/* media description is null or empty because no SDP was received in the 200 OK, we can possibly use the early-media SDP. */
if( call->resultdesc != NULL){
ms_message("Using early media SDP since none were received with the 200 OK");
md = call->resultdesc;
}
if (md && (sal_media_description_empty(md) || linphone_core_incompatible_security(lc,md))){
md = NULL;
}
if (md && !sal_media_description_empty(md) && !linphone_core_incompatible_security(lc,md)){
linphone_call_update_remote_session_id_and_ver(call);
linphone_core_update_ice_state_in_call_stats(call);
if (sal_media_description_has_dir(md,SalStreamSendOnly) ||
sal_media_description_has_dir(md,SalStreamInactive)){
{
char *tmp=linphone_call_get_remote_address_as_string (call);
char *msg=ms_strdup_printf(_("Call with %s is paused."),tmp);
linphone_core_notify_display_status(lc,msg);
ms_free(tmp);
ms_free(msg);
}
linphone_core_update_streams (lc,call,md);
if (update_state) linphone_call_set_state(call,LinphoneCallPaused,"Call paused");
if (call->refer_pending)
linphone_core_start_refered_call(lc,call,NULL);
}else if (sal_media_description_has_dir(md,SalStreamRecvOnly)){
/*we are put on hold when the call is initially accepted */
{
char *tmp=linphone_call_get_remote_address_as_string (call);
char *msg=ms_strdup_printf(_("Call answered by %s - on hold."),tmp);
linphone_core_notify_display_status(lc,msg);
ms_free(tmp);
ms_free(msg);
}
linphone_core_update_streams (lc,call,md);
if (update_state) linphone_call_set_state(call,LinphoneCallPausedByRemote,"Call paused by remote");
}else{
if (call->state!=LinphoneCallUpdating){
if (call->state==LinphoneCallResuming){
linphone_core_notify_display_status(lc,_("Call resumed."));
if (md){ /*there is a valid SDP in the response, either offer or answer, and we're able to start/update the streams*/
switch (call->state){
case LinphoneCallResuming:
linphone_core_notify_display_status(lc,_("Call resumed."));
/*intentionally no break*/
case LinphoneCallConnected:
if (call->referer) linphone_core_notify_refer_state(lc,call->referer,call);
/*intentionally no break*/
case LinphoneCallUpdating:
case LinphoneCallUpdatedByRemote:
if (!sal_media_description_has_dir(call->localdesc, SalStreamInactive) &&
(sal_media_description_has_dir(md,SalStreamRecvOnly) ||
sal_media_description_has_dir(md,SalStreamInactive))){
next_state = LinphoneCallPausedByRemote;
next_state_str = "Call paused by remote";
}else{
{
char *tmp=linphone_call_get_remote_address_as_string (call);
char *msg=ms_strdup_printf(_("Call answered by %s."),tmp);
linphone_core_notify_display_status(lc,msg);
ms_free(tmp);
ms_free(msg);
}
if (!call->current_params->in_conference)
lc->current_call=call;
next_state = LinphoneCallStreamsRunning;
next_state_str = "Streams running";
}
}
linphone_core_update_streams(lc,call,md);
/*also reflect the change if the "wished" params, in order to avoid to propose SAVP or video again
* further in the call, for example during pause,resume, conferencing reINVITEs*/
linphone_call_fix_call_parameters(call);
if (!call->current_params->in_conference)
lc->current_call=call;
if (update_state) linphone_call_set_state(call, LinphoneCallStreamsRunning, "Streams running");
break;
case LinphoneCallEarlyUpdating:
next_state_str = "Early update accepted";
next_state = call->prevstate;
break;
case LinphoneCallPausing:
/*when we entered the pausing state, we always reach the paused state whatever the content of the remote SDP is.
Our streams are all send-only (with music), soundcard and camera are never used*/
next_state = LinphoneCallPaused;
next_state_str = "Call paused";
if (call->refer_pending)
linphone_task_list_add(&tl, (LinphoneCoreIterateHook)start_pending_refer, call);
break;
default:
ms_error("call_accepted(): don't know what to do in state [%s]", linphone_call_state_to_string(call->state));
break;
}
}else{
if (next_state != LinphoneCallIdle){
linphone_call_update_remote_session_id_and_ver(call);
linphone_core_update_ice_state_in_call_stats(call);
linphone_core_update_streams(lc, call, md, next_state);
linphone_call_fix_call_parameters(call);
linphone_call_set_state(call, next_state, next_state_str);
}else{
ms_error("BUG: next_state is not set in call_accepted(), current state is %s", linphone_call_state_to_string(call->state));
}
}else{ /*invalid or no SDP*/
switch (call->prevstate){
/*send a bye only in case of outgoing state*/
/*send a bye only in case of early states*/
case LinphoneCallOutgoingInit:
case LinphoneCallOutgoingProgress:
case LinphoneCallOutgoingRinging:
case LinphoneCallOutgoingEarlyMedia:
ms_error("Incompatible SDP offer received in 200 OK, need to abort the call");
case LinphoneCallIncomingReceived:
case LinphoneCallIncomingEarlyMedia:
ms_error("Incompatible SDP answer received, need to abort the call");
linphone_core_abort_call(lc,call,_("Incompatible, check codecs or security settings..."));
break;
/*otherwise we are able to resume previous state*/
default:
ms_message("Incompatible SDP offer received in 200 OK, restoring previous state[%s]",linphone_call_state_to_string(call->prevstate));
ms_message("Incompatible SDP answer received, restoring previous state [%s]",linphone_call_state_to_string(call->prevstate));
linphone_call_set_state(call,call->prevstate,_("Incompatible media parameters."));
break;
}
}
linphone_task_list_run(&tl);
linphone_task_list_free(&tl);
}
static void call_ack(SalOp *op){
/*
* could be reach :
* - when the call is accepted
* - when a request is accepted (pause, resume)
*/
static void call_accepted(SalOp *op){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
if (call==NULL){
ms_warning("No call to be ACK'd");
if (call == NULL){
ms_warning("call_accepted: call does no longer exist.");
return ;
}
if (call->expect_media_in_ack){
SalMediaDescription *md=sal_call_get_final_media_description(op);
if (md && !sal_media_description_empty(md)){
linphone_core_update_streams(lc,call,md);
linphone_call_set_state (call,LinphoneCallStreamsRunning,"Connected (streams running)");
}else{
/*send a bye*/
ms_error("Incompatible SDP response received in ACK, need to abort the call");
linphone_core_abort_call(lc,call,"No codec intersection");
return;
}
}
process_call_accepted(lc, call, op);
}
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);
linphone_core_notify_display_status(lc,_("We have been resumed."));
_linphone_core_accept_call_update(lc,call,NULL,LinphoneCallStreamsRunning,"Connected (streams running)");
}
static void call_paused_by_remote(LinphoneCore *lc, LinphoneCall *call){
LinphoneCallParams *params;
/*when we are paused, increment session id, because sdp is changed (a=recvonly appears)*/
linphone_call_increment_local_media_description(call);
/* we are being paused */
linphone_core_notify_display_status(lc,_("We are paused by other party."));
params = linphone_call_params_copy(call->params);
@ -648,100 +626,49 @@ static void call_paused_by_remote(LinphoneCore *lc, LinphoneCall *call){
linphone_call_params_unref(params);
}
static void call_updated_by_remote(LinphoneCore *lc, LinphoneCall *call, bool_t is_update){
/*first check if media capabilities are compatible*/
SalMediaDescription *md;
SalMediaDescription *rmd=sal_call_get_remote_media_description(call->op);
SalMediaDescription *prev_result_desc=call->resultdesc;
if (rmd!=NULL){
if (call->state!=LinphoneCallPaused){
/*in paused state, we must stay in paused state.*/
linphone_call_make_local_media_description(lc,call);
sal_call_set_local_media_description(call->op,call->localdesc);
}
md=sal_call_get_final_media_description(call->op);
if (md && (sal_media_description_empty(md) || linphone_core_incompatible_security(lc,md))){
sal_call_decline(call->op,SalReasonNotAcceptable,NULL);
return;
}
if (is_update && prev_result_desc && md){
int diff=sal_media_description_equals(prev_result_desc,md);
if (diff & (SAL_MEDIA_DESCRIPTION_CRYPTO_POLICY_CHANGED|SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED)){
ms_warning("Cannot accept this update, it is changing parameters that require user approval");
sal_call_decline(call->op,SalReasonNotAcceptable,NULL); /*FIXME should send 504 Cannot change the session parameters without prompting the user"*/
return;
}
}
}
if ( call->state == LinphoneCallStreamsRunning) {
/*reINVITE and in-dialogs UPDATE go here*/
linphone_core_notify_display_status(lc,_("Call is updated by remote."));
call->defer_update = lp_config_get_int(lc->config, "sip", "defer_update_default", FALSE);
linphone_call_set_state(call, LinphoneCallUpdatedByRemote,"Call updated by remote");
if (call->defer_update==FALSE){
linphone_core_accept_call_update(lc,call,NULL);
}
if (rmd==NULL){
call->expect_media_in_ack=TRUE;
}
} else if( call->state == LinphoneCallPausedByRemote ){
/* Case where no SDP is present and we were paused by remote.
* We send back an ACK with our SDP and expect the remote to send its own.
* No state change here until an answer is received. */
call->defer_update = lp_config_get_int(lc->config, "sip", "defer_update_default", FALSE);
if (call->defer_update==FALSE){
_linphone_core_accept_call_update(lc,call,NULL,call->state,linphone_call_state_to_string(call->state));
}
if (rmd==NULL){
call->expect_media_in_ack=TRUE;
}
} else if (is_update){ /*SIP UPDATE case, can occur in early states*/
linphone_call_set_state(call, LinphoneCallEarlyUpdatedByRemote, "EarlyUpdatedByRemote");
_linphone_core_accept_call_update(lc,call,NULL,call->prevstate,linphone_call_state_to_string(call->prevstate));
}
}
/* this callback is called when an incoming re-INVITE/ SIP UPDATE modifies the session*/
static void call_updating(SalOp *op, bool_t is_update){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
static void call_updated(LinphoneCore *lc, LinphoneCall *call, SalOp *op, bool_t is_update){
SalMediaDescription *rmd=sal_call_get_remote_media_description(op);
if (rmd==NULL){
/* case of a reINVITE or UPDATE without SDP */
call_updated_by_remote(lc,call,is_update);
return;
}
call->defer_update = lp_config_get_int(lc->config, "sip", "defer_update_default", FALSE);
switch(call->state){
case LinphoneCallPausedByRemote:
if (sal_media_description_has_dir(rmd,SalStreamSendRecv) || sal_media_description_has_dir(rmd,SalStreamRecvOnly)){
call_resumed(lc,call);
}else call_updated_by_remote(lc,call,is_update);
}else{
/*we are staying in PausedByRemote*/
linphone_core_notify_display_status(lc,_("Call is updated by remote."));
linphone_call_set_state(call, LinphoneCallUpdatedByRemote,"Call updated by remote");
if (call->defer_update == FALSE){
linphone_core_accept_call_update(lc,call,NULL);
}
}
break;
/*SIP UPDATE CASE*/
case LinphoneCallOutgoingRinging:
case LinphoneCallOutgoingEarlyMedia:
case LinphoneCallIncomingEarlyMedia:
if (is_update) call_updated_by_remote(lc,call,is_update);
if (is_update) {
linphone_call_set_state(call, LinphoneCallEarlyUpdatedByRemote, "EarlyUpdatedByRemote");
_linphone_core_accept_call_update(lc,call,NULL,call->prevstate,linphone_call_state_to_string(call->prevstate));
}
break;
case LinphoneCallStreamsRunning:
case LinphoneCallConnected:
if (sal_media_description_has_dir(rmd,SalStreamSendOnly) || sal_media_description_has_dir(rmd,SalStreamInactive)){
call_paused_by_remote(lc,call);
}else{
call_updated_by_remote(lc,call,is_update);
linphone_core_notify_display_status(lc,_("Call is updated by remote."));
linphone_call_set_state(call, LinphoneCallUpdatedByRemote,"Call updated by remote");
if (call->defer_update == FALSE){
linphone_core_accept_call_update(lc,call,NULL);
}
}
break;
case LinphoneCallPaused:
if (sal_media_description_has_dir(rmd,SalStreamSendOnly) || sal_media_description_has_dir(rmd,SalStreamInactive)){
call_paused_by_remote(lc,call);
}else{
call_updated_by_remote(lc,call,is_update);
}
/*we'll remain in pause state but accept the offer anyway according to default parameters*/
_linphone_core_accept_call_update(lc,call,NULL,call->state,linphone_call_state_to_string(call->state));
break;
case LinphoneCallUpdating:
case LinphoneCallPausing:
@ -764,6 +691,71 @@ static void call_updating(SalOp *op, bool_t is_update){
}
}
/* this callback is called when an incoming re-INVITE/ SIP UPDATE modifies the session*/
static void call_updating(SalOp *op, bool_t is_update){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
SalMediaDescription *rmd=sal_call_get_remote_media_description(op);
if (!call) {
ms_error("call_updating(): call doesn't exist anymore");
return ;
}
if (call->state!=LinphoneCallPaused){
/*Refresh the local description, but in paused state, we don't change anything.*/
linphone_call_make_local_media_description(call);
sal_call_set_local_media_description(call->op,call->localdesc);
}
if (rmd == NULL){
/* case of a reINVITE or UPDATE without SDP */
call->expect_media_in_ack = TRUE;
sal_call_accept(op); /*respond with an offer*/
/*don't do anything else in this case, wait for the ACK to receive to notify the app*/
}else {
SalMediaDescription *md;
SalMediaDescription *prev_result_desc=call->resultdesc;
call->expect_media_in_ack = FALSE;
md=sal_call_get_final_media_description(call->op);
if (md && (sal_media_description_empty(md) || linphone_core_incompatible_security(lc,md))){
sal_call_decline(call->op,SalReasonNotAcceptable,NULL);
return;
}
if (is_update && prev_result_desc && md){
int diff=sal_media_description_equals(prev_result_desc,md);
if (diff & (SAL_MEDIA_DESCRIPTION_CRYPTO_POLICY_CHANGED|SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED)){
ms_warning("Cannot accept this update, it is changing parameters that require user approval");
sal_call_decline(call->op,SalReasonNotAcceptable,NULL); /*FIXME should send 504 Cannot change the session parameters without prompting the user"*/
return;
}
}
call_updated(lc, call, op, is_update);
}
}
static void call_ack(SalOp *op){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
if (call == NULL){
ms_warning("call_ack(): no call for which an ack is expected");
return;
}
if (call->expect_media_in_ack){
switch(call->state){
case LinphoneCallStreamsRunning:
case LinphoneCallPausedByRemote:
linphone_call_set_state(call, LinphoneCallUpdatedByRemote, "UpdatedByRemote");
break;
default:
break;
}
process_call_accepted(lc, call, op);
}
}
static void call_terminated(SalOp *op, const char *from){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
@ -920,16 +912,11 @@ static void call_failure(SalOp *op){
msg=_("Incompatible media parameters.");
linphone_core_notify_display_status(lc,msg);
break;
case SalReasonRequestPending:
/*restore previous state, the application will decide to resubmit the action if relevant*/
linphone_call_set_state(call,call->prevstate,msg);
return;
break;
default:
linphone_core_notify_display_status(lc,_("Call failed."));
}
/*some call error are not fatal*/
/*some call errors are not fatal*/
switch (call->state) {
case LinphoneCallUpdating:
case LinphoneCallPausing:
@ -1119,6 +1106,7 @@ static void text_received(SalOp *op, const SalMessage *msg){
static void is_composing_received(SalOp *op, const SalIsComposing *is_composing) {
LinphoneCore *lc = (LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
linphone_core_is_composing_received(lc, op, is_composing);
sal_op_release(op);
}
static void parse_presence_requested(SalOp *op, const char *content_type, const char *content_subtype, const char *body, SalPresenceModel **result) {
@ -1262,17 +1250,19 @@ static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status){
// Do not handle delivery status for isComposing messages.
return;
}
// check that the message does not belong to an already destroyed chat room - if so, do not invoke callbacks
if (chat_msg->chat_room != NULL) {
chat_msg->state=chatStatusSal2Linphone(status);
linphone_chat_message_update_state(chat_msg);
chat_msg->state=chatStatusSal2Linphone(status);
linphone_chat_message_update_state(chat_msg);
if (chat_msg && (chat_msg->cb || (chat_msg->callbacks && linphone_chat_message_cbs_get_msg_state_changed(chat_msg->callbacks)))) {
ms_message("Notifying text delivery with status %s",linphone_chat_message_state_to_string(chat_msg->state));
if (chat_msg->callbacks && linphone_chat_message_cbs_get_msg_state_changed(chat_msg->callbacks)) {
linphone_chat_message_cbs_get_msg_state_changed(chat_msg->callbacks)(chat_msg, chat_msg->state);
} else {
/* Legacy */
chat_msg->cb(chat_msg,chat_msg->state,chat_msg->cb_ud);
if (chat_msg && (chat_msg->cb || (chat_msg->callbacks && linphone_chat_message_cbs_get_msg_state_changed(chat_msg->callbacks)))) {
ms_message("Notifying text delivery with status %s",linphone_chat_message_state_to_string(chat_msg->state));
if (chat_msg->callbacks && linphone_chat_message_cbs_get_msg_state_changed(chat_msg->callbacks)) {
linphone_chat_message_cbs_get_msg_state_changed(chat_msg->callbacks)(chat_msg, chat_msg->state);
} else {
/* Legacy */
chat_msg->cb(chat_msg,chat_msg->state,chat_msg->cb_ud);
}
}
}
if (status != SalTextDeliveryInProgress) { /*only release op if not in progress*/

View file

@ -39,6 +39,9 @@
#define FILE_TRANSFER_KEY_SIZE 32
static void linphone_chat_message_release(LinphoneChatMessage *msg);
static LinphoneChatMessageCbs * linphone_chat_message_cbs_new(void) {
return belle_sip_object_new(LinphoneChatMessageCbs);
}
@ -106,26 +109,13 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM
static void process_io_error_upload(void *data, const belle_sip_io_error_event_t *event){
LinphoneChatMessage* msg=(LinphoneChatMessage *)data;
msg->state = LinphoneChatMessageStateNotDelivered;
ms_error("I/O Error during file upload to %s - msg [%p] chat room[%p]", linphone_core_get_file_transfer_server(msg->chat_room->lc), msg, msg->chat_room);
if (msg->cb) {
msg->cb(msg, msg->state, msg->cb_ud);
}
if (linphone_chat_message_cbs_get_msg_state_changed(msg->callbacks)) {
linphone_chat_message_cbs_get_msg_state_changed(msg->callbacks)(msg, msg->state);
}
linphone_chat_message_cancel_file_transfer(msg);
}
static void process_auth_requested_upload(void *data, belle_sip_auth_event_t *event){
LinphoneChatMessage* msg=(LinphoneChatMessage *)data;
msg->state = LinphoneChatMessageStateNotDelivered;
ms_error("Error during file upload : auth requested to connect %s - msg [%p] chat room[%p]", linphone_core_get_file_transfer_server(msg->chat_room->lc), msg, msg->chat_room);
if (msg->cb) {
msg->cb(msg, msg->state, msg->cb_ud);
}
if (linphone_chat_message_cbs_get_msg_state_changed(msg->callbacks)) {
linphone_chat_message_cbs_get_msg_state_changed(msg->callbacks)(msg, msg->state);
}
ms_error("Error during file upload: auth requested to connect %s - msg [%p] chat room[%p]", linphone_core_get_file_transfer_server(msg->chat_room->lc), msg, msg->chat_room);
linphone_chat_message_cancel_file_transfer(msg);
}
static void process_io_error_download(void *data, const belle_sip_io_error_event_t *event){
@ -376,7 +366,8 @@ void linphone_core_enable_chat(LinphoneCore *lc){
bool_t linphone_core_chat_enabled(const LinphoneCore *lc){
return lc->chat_deny_code!=LinphoneReasonNone;
}
MSList* linphone_core_get_chat_rooms(LinphoneCore *lc) {
const MSList* linphone_core_get_chat_rooms(LinphoneCore *lc) {
return lc->chatrooms;
}
@ -442,14 +433,6 @@ static LinphoneChatRoom * _linphone_core_get_or_create_chat_room(LinphoneCore* l
return ret;
}
LinphoneChatRoom* linphone_core_get_or_create_chat_room(LinphoneCore* lc, const char* to) {
return _linphone_core_get_or_create_chat_room(lc, to);
}
LinphoneChatRoom * linphone_core_create_chat_room(LinphoneCore *lc, const char *to) {
return _linphone_core_get_or_create_chat_room(lc, to);
}
LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAddress *addr){
LinphoneChatRoom *ret = _linphone_core_get_chat_room(lc, addr);
if (!ret) {
@ -458,6 +441,18 @@ LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAd
return ret;
}
void linphone_core_delete_chat_room(LinphoneCore *lc, LinphoneChatRoom *cr){
if (ms_list_find(lc->chatrooms, cr)){
lc->chatrooms = ms_list_remove(cr->lc->chatrooms, cr);
linphone_chat_room_delete_history(cr);
linphone_chat_room_unref(cr);
}else{
ms_error("linphone_core_delete_chat_room(): chatroom [%p] isn't part of LinphoneCore.",
cr);
}
}
LinphoneChatRoom * linphone_core_get_chat_room_from_uri(LinphoneCore *lc, const char *to) {
return _linphone_core_get_or_create_chat_room(lc, to);
}
@ -490,12 +485,18 @@ static void linphone_chat_room_delete_remote_composing_refresh_timer(LinphoneCha
}
static void _linphone_chat_room_destroy(LinphoneChatRoom *cr){
ms_list_free_with_data(cr->transient_messages, (void (*)(void*))linphone_chat_message_unref);
ms_list_free_with_data(cr->transient_messages, (void (*)(void*))linphone_chat_message_release);
linphone_chat_room_delete_composing_idle_timer(cr);
linphone_chat_room_delete_composing_refresh_timer(cr);
linphone_chat_room_delete_remote_composing_refresh_timer(cr);
if (cr->lc != NULL) {
cr->lc->chatrooms=ms_list_remove(cr->lc->chatrooms,(void *) cr);
if (ms_list_find(cr->lc->chatrooms, cr)){
ms_error("LinphoneChatRoom[%p] is destroyed while still being used by the LinphoneCore. This is abnormal."
" linphone_core_get_chat_room() doesn't give a reference, there is no need to call linphone_chat_room_unref(). "
"In order to remove a chat room from the core, use linphone_core_delete_chat_room().",
cr);
}
cr->lc->chatrooms=ms_list_remove(cr->lc->chatrooms, cr);
}
linphone_address_destroy(cr->peer_url);
if (cr->pending_message)
@ -820,14 +821,17 @@ static void process_im_is_composing_notification(LinphoneChatRoom *cr, xmlparsin
xmlXPathRegisterNs(xml_ctx->xpath_ctx, (const xmlChar *)"xsi", (const xmlChar *)"urn:ietf:params:xml:ns:im-iscomposing");
iscomposing_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, iscomposing_prefix);
if ((iscomposing_object != NULL) && (iscomposing_object->nodesetval != NULL)) {
for (i = 1; i <= iscomposing_object->nodesetval->nodeNr; i++) {
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/xsi:state", iscomposing_prefix, i);
state_str = linphone_get_xml_text_content(xml_ctx, xpath_str);
if (state_str == NULL) continue;
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/xsi:refresh", iscomposing_prefix, i);
refresh_str = linphone_get_xml_text_content(xml_ctx, xpath_str);
if (iscomposing_object != NULL){
if(iscomposing_object->nodesetval != NULL) {
for (i = 1; i <= iscomposing_object->nodesetval->nodeNr; i++) {
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/xsi:state", iscomposing_prefix, i);
state_str = linphone_get_xml_text_content(xml_ctx, xpath_str);
if (state_str == NULL) continue;
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/xsi:refresh", iscomposing_prefix, i);
refresh_str = linphone_get_xml_text_content(xml_ctx, xpath_str);
}
}
xmlXPathFreeObject(iscomposing_object);
}
if (state_str != NULL) {
@ -867,7 +871,8 @@ static void linphone_chat_room_notify_is_composing(LinphoneChatRoom *cr, const c
}
void linphone_core_is_composing_received(LinphoneCore *lc, SalOp *op, const SalIsComposing *is_composing) {
LinphoneChatRoom *cr = linphone_core_get_or_create_chat_room(lc, is_composing->from);
LinphoneAddress *addr = linphone_address_new(is_composing->from);
LinphoneChatRoom *cr = _linphone_core_get_chat_room(lc, addr);
if (cr != NULL) {
/*rtt stub*/
LinphoneCall *call = linphone_core_find_call_from_uri(lc,cr->peer);
@ -916,6 +921,7 @@ void linphone_core_is_composing_received(LinphoneCore *lc, SalOp *op, const SalI
}
linphone_chat_room_notify_is_composing(cr, is_composing->text);
}
linphone_address_destroy(addr);
}
bool_t linphone_chat_room_is_remote_composing(const LinphoneChatRoom *cr) {
@ -1042,37 +1048,22 @@ static char * linphone_chat_room_create_is_composing_xml(LinphoneChatRoom *cr) {
static void linphone_chat_room_send_is_composing_notification(LinphoneChatRoom *cr) {
SalOp *op = NULL;
LinphoneCall *call;
const char *identity = NULL;
char *content = NULL;
LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(cr->lc, cr->peer_url);
if (proxy)
identity = linphone_proxy_config_get_identity(proxy);
else
identity = linphone_core_get_primary_contact(cr->lc);
/*sending out of calls*/
op = sal_op_new(cr->lc->sal);
linphone_configure_op(cr->lc, op, cr->peer_url, NULL, lp_config_get_int(cr->lc->config, "sip", "chat_msg_with_contact", 0));
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) {
if (call->state == LinphoneCallConnected ||
call->state == LinphoneCallStreamsRunning ||
call->state == LinphoneCallPaused ||
call->state == LinphoneCallPausing ||
call->state == LinphoneCallPausedByRemote) {
ms_message("send SIP message through the existing call.");
op = call->op;
identity = linphone_core_find_best_identity(cr->lc, linphone_call_get_remote_address(call));
}
}
}
if (op == NULL) {
LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(cr->lc, cr->peer_url);
if (proxy)
identity = linphone_proxy_config_get_identity(proxy);
else
identity = linphone_core_get_primary_contact(cr->lc);
/*sending out of calls*/
op = sal_op_new(cr->lc->sal);
linphone_configure_op(cr->lc, op, cr->peer_url, NULL, lp_config_get_int(cr->lc->config, "sip", "chat_msg_with_contact", 0));
}
content = linphone_chat_room_create_is_composing_xml(cr);
if (content != NULL) {
sal_message_send(op, identity, cr->peer, "application/im-iscomposing+xml", content, NULL);
ms_free(content);
sal_op_unref(op);
}
}
@ -1498,7 +1489,6 @@ static void _linphone_chat_message_destroy(LinphoneChatMessage* msg) {
ms_free(msg->file_transfer_filepath);
}
linphone_chat_message_cbs_unref(msg->callbacks);
ms_message("LinphoneChatMessage [%p] destroyed.",msg);
}
LinphoneChatMessage * linphone_chat_message_ref(LinphoneChatMessage *msg){
@ -1510,6 +1500,12 @@ void linphone_chat_message_unref(LinphoneChatMessage *msg){
belle_sip_object_unref(msg);
}
static void linphone_chat_message_release(LinphoneChatMessage *msg){
/*mark the chat message as orphan (it has no chat room anymore), and unref it*/
msg->chat_room = NULL;
linphone_chat_message_unref(msg);
}
const LinphoneErrorInfo *linphone_chat_message_get_error_info(const LinphoneChatMessage *msg){
return linphone_error_info_from_sal_op(msg->op);
}
@ -1534,7 +1530,7 @@ LinphoneChatMessageCbs * linphone_chat_message_get_callbacks(const LinphoneChatM
return msg->callbacks;
}
LinphoneChatMessage* linphone_chat_room_create_file_transfer_message(LinphoneChatRoom *cr, LinphoneContent* initial_content) {
LinphoneChatMessage* linphone_chat_room_create_file_transfer_message(LinphoneChatRoom *cr, const LinphoneContent* initial_content) {
LinphoneChatMessage* msg = belle_sip_object_new(LinphoneChatMessage);
msg->callbacks=linphone_chat_message_cbs_new();
msg->chat_room=(LinphoneChatRoom*)cr;

View file

@ -92,7 +92,7 @@ LinphoneFriend *linphone_find_friend_by_inc_subscribe(MSList *l, SalOp *op){
MSList *elem;
for (elem=l;elem!=NULL;elem=elem->next){
LinphoneFriend *lf=(LinphoneFriend*)elem->data;
if (lf->insub==op) return lf;
if (ms_list_find(lf->insubs, op)) return lf;
}
return NULL;
}
@ -227,12 +227,24 @@ int linphone_friend_set_inc_subscribe_policy(LinphoneFriend *fr, LinphoneSubscri
}
void linphone_friend_notify(LinphoneFriend *lf, LinphonePresenceModel *presence){
char *addr=linphone_address_as_string(linphone_friend_get_address(lf));
ms_message("Want to notify %s, insub=%p",addr,lf->insub);
ms_free(addr);
if (lf->insub!=NULL){
sal_notify_presence(lf->insub,(SalPresenceModel *)presence);
MSList *elem;
if (lf->insubs){
char *addr=linphone_address_as_string(linphone_friend_get_address(lf));
ms_message("Want to notify %s",addr);
ms_free(addr);
}
for(elem=lf->insubs; elem!=NULL; elem=elem->next){
SalOp *op = (SalOp*)elem->data;
sal_notify_presence(op,(SalPresenceModel *)presence);
}
}
void linphone_friend_add_incoming_subscription(LinphoneFriend *lf, SalOp *op){
lf->insubs = ms_list_append(lf->insubs, op);
}
void linphone_friend_remove_incoming_subscription(LinphoneFriend *lf, SalOp *op){
lf->insubs = ms_list_remove(lf->insubs, op);
}
static void linphone_friend_unsubscribe(LinphoneFriend *lf){
@ -260,17 +272,12 @@ static void linphone_friend_invalidate_subscription(LinphoneFriend *lf){
void linphone_friend_close_subscriptions(LinphoneFriend *lf){
linphone_friend_unsubscribe(lf);
if (lf->insub){
sal_notify_presence_close(lf->insub);
ms_list_for_each(lf->insubs, (MSIterateFunc) sal_notify_presence_close);
}
}
static void _linphone_friend_destroy(LinphoneFriend *lf){
if (lf->insub) {
sal_op_release(lf->insub);
lf->insub=NULL;
}
lf->insubs = ms_list_free_with_data(lf->insubs, (MSIterateFunc) sal_op_release);
if (lf->outsub){
sal_op_release(lf->outsub);
lf->outsub=NULL;

View file

@ -81,7 +81,7 @@ int main(int argc, char *argv[]){
/*Next step is to create a chat root*/
chat_room = linphone_core_create_chat_room(lc,dest_friend);
chat_room = linphone_core_get_chat_room_from_uri(lc,dest_friend);
linphone_chat_room_send_message(chat_room,"Hello world"); /*sending message*/
@ -92,7 +92,6 @@ int main(int argc, char *argv[]){
}
printf("Shutting down...\n");
linphone_chat_room_destroy(chat_room);
linphone_core_destroy(lc);
printf("Exited\n");
return 0;

View file

@ -160,7 +160,7 @@ int main(int argc, char *argv[]){
/*Next step is to create a chat room*/
chat_room = linphone_core_create_chat_room(lc,dest_friend);
chat_room = linphone_core_get_chat_room_from_uri(lc,dest_friend);
content = linphone_core_create_content(lc);
linphone_content_set_type(content,"text");
@ -196,7 +196,6 @@ int main(int argc, char *argv[]){
printf("Shutting down...\n");
linphone_content_unref(content);
linphone_chat_room_destroy(chat_room);
linphone_core_destroy(lc);
printf("Exited\n");
return 0;

View file

@ -104,7 +104,6 @@ public class TutorialBuddyStatus implements LinphoneCoreListener {
public void displayMessage(LinphoneCore lc, String message) {}
public void displayWarning(LinphoneCore lc, String message) {}
public void globalState(LinphoneCore lc, GlobalState state, String message) {}
public void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from, String message) {}
public void callState(LinphoneCore lc, LinphoneCall call, State cstate, String msg) {}
public void callStatsUpdated(LinphoneCore lc, LinphoneCall call, LinphoneCallStats stats) {}
public void ecCalibrationStatus(LinphoneCore lc, EcCalibratorStatus status,int delay_ms, Object data) {}

View file

@ -90,10 +90,6 @@ public class TutorialChatRoom implements LinphoneCoreListener, LinphoneChatMessa
public void callEncryptionChanged(LinphoneCore lc, LinphoneCall call,boolean encrypted, String authenticationToken) {}
public void notifyReceived(LinphoneCore lc, LinphoneCall call, LinphoneAddress from, byte[] event){}
public void dtmfReceived(LinphoneCore lc, LinphoneCall call, int dtmf) {}
public void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from, String message) {
//Deprecated
}

View file

@ -88,7 +88,6 @@ public class TutorialRegistration implements LinphoneCoreListener {
public void globalState(LinphoneCore lc, GlobalState state, String message) {}
public void newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf,String url) {}
public void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf) {}
public void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from, String message) {}
public void callState(LinphoneCore lc, LinphoneCall call, State cstate, String msg) {}
public void callStatsUpdated(LinphoneCore lc, LinphoneCall call, LinphoneCallStats stats) {}
public void ecCalibrationStatus(LinphoneCore lc, EcCalibratorStatus status,int delay_ms, Object data) {}

View file

@ -1,5 +1,5 @@
/*
Copyright (C) 2000 - 2010 Simon MORLAT (simon.morlat@linphone.org)
Copyright (C) 2010-2015 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
@ -15,14 +15,20 @@ You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef LINPHONE_PROXY_CONFIG_H
#define LINPHONE_PROXY_CONFIG_H
/**
* @addtogroup proxies
* @{
**/
/**
* Creates an empty proxy config.
* @deprecated, use #linphone_core_create_proxy_config instead
**/
LINPHONE_PUBLIC LinphoneProxyConfig *linphone_proxy_config_new(void);
LINPHONE_PUBLIC LinphoneProxyConfig *linphone_proxy_config_new(void);
/**
* Acquire a reference to the proxy config.
@ -59,7 +65,7 @@ LINPHONE_PUBLIC void linphone_proxy_config_set_user_data(LinphoneProxyConfig *cf
* - IP address with port: sip:87.98.157.38:5062
* - hostnames : sip:sip.example.net
**/
LINPHONE_PUBLIC int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *cfg, const char *server_addr);
LINPHONE_PUBLIC int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *cfg, const char *server_addr);
/**
* @deprecated Use linphone_proxy_config_set_identity_address()
@ -75,28 +81,29 @@ LINPHONE_PUBLIC int linphone_proxy_config_set_identity(LinphoneProxyConfig *cfg,
* The REGISTER messages will have from and to set to this identity.
*
**/
LINPHONE_PUBLIC int linphone_proxy_config_set_identity_address(LinphoneProxyConfig *cfg, const LinphoneAddress *identity);
LINPHONE_PUBLIC int linphone_proxy_config_set_identity_address(LinphoneProxyConfig *cfg, const LinphoneAddress *identity);
/**
* Sets a SIP route.
* When a route is set, all outgoing calls will go to the route's destination if this proxy
* is the default one (see linphone_core_set_default_proxy() ).
**/
LINPHONE_PUBLIC int linphone_proxy_config_set_route(LinphoneProxyConfig *cfg, const char *route);
LINPHONE_PUBLIC int linphone_proxy_config_set_route(LinphoneProxyConfig *cfg, const char *route);
/**
* Sets the registration expiration time in seconds.
**/
LINPHONE_PUBLIC void linphone_proxy_config_set_expires(LinphoneProxyConfig *cfg, int expires);
LINPHONE_PUBLIC void linphone_proxy_config_set_expires(LinphoneProxyConfig *cfg, int expires);
#define linphone_proxy_config_expires linphone_proxy_config_set_expires
/**
* Indicates either or not, REGISTRATION must be issued for this #LinphoneProxyConfig .
* <br> In case this #LinphoneProxyConfig has been added to #LinphoneCore, follows the linphone_proxy_config_edit() rule.
* @param[in] cfg #LinphoneProxyConfig object.
* @param val if true, registration will be engaged
*/
LINPHONE_PUBLIC void linphone_proxy_config_enable_register(LinphoneProxyConfig *cfg, bool_t val);
LINPHONE_PUBLIC void linphone_proxy_config_enable_register(LinphoneProxyConfig *cfg, bool_t val);
#define linphone_proxy_config_enableregister linphone_proxy_config_enable_register
@ -109,12 +116,13 @@ LINPHONE_PUBLIC void linphone_proxy_config_enable_register(LinphoneProxyConfig *
* Once the modifications are done, then the application must call
* linphone_proxy_config_done() to commit the changes.
**/
LINPHONE_PUBLIC void linphone_proxy_config_edit(LinphoneProxyConfig *cfg);
LINPHONE_PUBLIC void linphone_proxy_config_edit(LinphoneProxyConfig *cfg);
/**
* Commits modification made to the proxy configuration.
**/
LINPHONE_PUBLIC int linphone_proxy_config_done(LinphoneProxyConfig *cfg);
LINPHONE_PUBLIC int linphone_proxy_config_done(LinphoneProxyConfig *cfg);
/**
* Indicates either or not, PUBLISH must be issued for this #LinphoneProxyConfig .
* <br> In case this #LinphoneProxyConfig has been added to #LinphoneCore, follows the linphone_proxy_config_edit() rule.
@ -122,28 +130,27 @@ LINPHONE_PUBLIC int linphone_proxy_config_done(LinphoneProxyConfig *cfg);
* @param val if true, publish will be engaged
*
*/
LINPHONE_PUBLIC void linphone_proxy_config_enable_publish(LinphoneProxyConfig *cfg, bool_t val);
LINPHONE_PUBLIC void linphone_proxy_config_enable_publish(LinphoneProxyConfig *cfg, bool_t val);
/**
* Set the publish expiration time in second.
* @param[in] cfg #LinphoneProxyConfig object.
* @param expires in second
* */
LINPHONE_PUBLIC void linphone_proxy_config_set_publish_expires(LinphoneProxyConfig *cfg, int expires);
LINPHONE_PUBLIC void linphone_proxy_config_set_publish_expires(LinphoneProxyConfig *cfg, int expires);
/**
* get the publish expiration time in second. Default value is the registration expiration value.
* @param[in] cfg #LinphoneProxyConfig object.
* @return expires in second
* */
LINPHONE_PUBLIC int linphone_proxy_config_get_publish_expires(const LinphoneProxyConfig *cfg);
LINPHONE_PUBLIC int linphone_proxy_config_get_publish_expires(const LinphoneProxyConfig *cfg);
/**
* Sets whether liblinphone should replace "+" by international calling prefix in dialed numbers (passed to
* #linphone_core_invite ).
*
**/
LINPHONE_PUBLIC void linphone_proxy_config_set_dial_escape_plus(LinphoneProxyConfig *cfg, bool_t val);
LINPHONE_PUBLIC void linphone_proxy_config_set_dial_escape_plus(LinphoneProxyConfig *cfg, bool_t val);
/**
* Sets a dialing prefix to be automatically prepended when inviting a number with
@ -151,21 +158,21 @@ LINPHONE_PUBLIC void linphone_proxy_config_set_dial_escape_plus(LinphoneProxyCon
* This dialing prefix shall usually be the country code of the country where the user is living, without "+".
*
**/
LINPHONE_PUBLIC void linphone_proxy_config_set_dial_prefix(LinphoneProxyConfig *cfg, const char *prefix);
LINPHONE_PUBLIC void linphone_proxy_config_set_dial_prefix(LinphoneProxyConfig *cfg, const char *prefix);
/**
* 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_quality_reporting(LinphoneProxyConfig *cfg, bool_t enable);
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);
LINPHONE_PUBLIC bool_t linphone_proxy_config_quality_reporting_enabled(LinphoneProxyConfig *cfg);
/**
* Set the route of the collector end-point when using quality reporting. This SIP address
@ -175,7 +182,7 @@ LINPHONE_PUBLIC bool_t linphone_proxy_config_quality_reporting_enabled(LinphoneP
* @param[in] cfg #LinphoneProxyConfig object.
* @param[in] collector route of the collector end-point, if NULL PUBLISH will be sent to the proxy domain.
*/
LINPHONE_PUBLIC void linphone_proxy_config_set_quality_reporting_collector(LinphoneProxyConfig *cfg, const char *collector);
LINPHONE_PUBLIC void linphone_proxy_config_set_quality_reporting_collector(LinphoneProxyConfig *cfg, const char *collector);
/**
* Get the route of the collector end-point when using quality reporting. This SIP address
@ -185,7 +192,7 @@ LINPHONE_PUBLIC void linphone_proxy_config_set_quality_reporting_collector(Linph
* @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);
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
@ -209,73 +216,79 @@ LINPHONE_PUBLIC int linphone_proxy_config_get_quality_reporting_interval(Linphon
* @param[in] cfg #LinphoneProxyConfig object.
* @return The registration state of the proxy config.
**/
LINPHONE_PUBLIC LinphoneRegistrationState linphone_proxy_config_get_state(const LinphoneProxyConfig *cfg);
LINPHONE_PUBLIC LinphoneRegistrationState linphone_proxy_config_get_state(const LinphoneProxyConfig *cfg);
/**
* @return a boolean indicating that the user is sucessfully registered on the proxy.
* @deprecated Use linphone_proxy_config_get_state() instead.
**/
LINPHONE_PUBLIC bool_t linphone_proxy_config_is_registered(const LinphoneProxyConfig *cfg);
LINPHONE_PUBLIC bool_t linphone_proxy_config_is_registered(const LinphoneProxyConfig *cfg);
/**
* Get the domain name of the given proxy config.
* @param[in] cfg #LinphoneProxyConfig object.
* @return The domain name of the proxy config.
**/
LINPHONE_PUBLIC const char *linphone_proxy_config_get_domain(const LinphoneProxyConfig *cfg);
LINPHONE_PUBLIC const char *linphone_proxy_config_get_domain(const LinphoneProxyConfig *cfg);
/**
* Get the realm of the given proxy config.
* @param[in] cfg #LinphoneProxyConfig object.
* @return The realm of the proxy config.
**/
LINPHONE_PUBLIC const char *linphone_proxy_config_get_realm(const LinphoneProxyConfig *cfg);
LINPHONE_PUBLIC const char *linphone_proxy_config_get_realm(const LinphoneProxyConfig *cfg);
/**
* Set the realm of the given proxy config.
* @param[in] cfg #LinphoneProxyConfig object.
* @param[in] realm New realm value.
* @return The realm of the proxy config.
**/
LINPHONE_PUBLIC void linphone_proxy_config_set_realm(LinphoneProxyConfig *cfg, const char * realm);
LINPHONE_PUBLIC void linphone_proxy_config_set_realm(LinphoneProxyConfig *cfg, const char * realm);
/**
* @return the route set for this proxy configuration.
**/
LINPHONE_PUBLIC const char *linphone_proxy_config_get_route(const LinphoneProxyConfig *cfg);
LINPHONE_PUBLIC const char *linphone_proxy_config_get_route(const LinphoneProxyConfig *cfg);
/**
* @return the SIP identity that belongs to this proxy configuration.
**/
LINPHONE_PUBLIC const LinphoneAddress *linphone_proxy_config_get_identity_address(const LinphoneProxyConfig *cfg);
LINPHONE_PUBLIC const LinphoneAddress *linphone_proxy_config_get_identity_address(const LinphoneProxyConfig *cfg);
/**
* @deprecated use linphone_proxy_config_get_identity_address()
**/
LINPHONE_PUBLIC const char *linphone_proxy_config_get_identity(const LinphoneProxyConfig *cfg);
LINPHONE_PUBLIC const char *linphone_proxy_config_get_identity(const LinphoneProxyConfig *cfg);
/**
* @return TRUE if PUBLISH request is enabled for this proxy.
**/
LINPHONE_PUBLIC bool_t linphone_proxy_config_publish_enabled(const LinphoneProxyConfig *cfg);
LINPHONE_PUBLIC bool_t linphone_proxy_config_publish_enabled(const LinphoneProxyConfig *cfg);
/**
* @return the proxy's SIP address.
**/
LINPHONE_PUBLIC const char *linphone_proxy_config_get_server_addr(const LinphoneProxyConfig *cfg);
#define linphone_proxy_config_get_addr linphone_proxy_config_get_server_addr
/**
* @return the duration of registration.
**/
LINPHONE_PUBLIC int linphone_proxy_config_get_expires(const LinphoneProxyConfig *cfg);
LINPHONE_PUBLIC int linphone_proxy_config_get_expires(const LinphoneProxyConfig *cfg);
/**
* @return TRUE if registration to the proxy is enabled.
**/
LINPHONE_PUBLIC bool_t linphone_proxy_config_register_enabled(const LinphoneProxyConfig *cfg);
LINPHONE_PUBLIC bool_t linphone_proxy_config_register_enabled(const LinphoneProxyConfig *cfg);
/**
* Refresh a proxy registration.
* This is useful if for example you resuming from suspend, thus IP address may have changed.
**/
LINPHONE_PUBLIC void linphone_proxy_config_refresh_register(LinphoneProxyConfig *cfg);
LINPHONE_PUBLIC void linphone_proxy_config_refresh_register(LinphoneProxyConfig *cfg);
/**
* 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
@ -291,7 +304,8 @@ LINPHONE_PUBLIC const LinphoneAddress* linphone_proxy_config_get_contact(const L
/**
* @return previously set contact parameters.
**/
LINPHONE_PUBLIC const char *linphone_proxy_config_get_contact_parameters(const LinphoneProxyConfig *cfg);
LINPHONE_PUBLIC const char *linphone_proxy_config_get_contact_parameters(const LinphoneProxyConfig *cfg);
/**
* Set optional contact parameters that will be added to the contact information sent in the registration.
* @param[in] cfg #LinphoneProxyConfig object.
@ -300,7 +314,7 @@ LINPHONE_PUBLIC const char *linphone_proxy_config_get_contact_parameters(const L
* 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.
**/
LINPHONE_PUBLIC void linphone_proxy_config_set_contact_parameters(LinphoneProxyConfig *cfg, const char *contact_params);
LINPHONE_PUBLIC void linphone_proxy_config_set_contact_parameters(LinphoneProxyConfig *cfg, const char *contact_params);
/**
* Set optional contact parameters that will be added to the contact information sent in the registration, inside the URI.
@ -329,7 +343,7 @@ LINPHONE_PUBLIC LinphoneCore * linphone_proxy_config_get_core(const LinphoneProx
* #linphone_core_invite ).
*
**/
LINPHONE_PUBLIC bool_t linphone_proxy_config_get_dial_escape_plus(const LinphoneProxyConfig *cfg);
LINPHONE_PUBLIC bool_t linphone_proxy_config_get_dial_escape_plus(const LinphoneProxyConfig *cfg);
/**
* @return dialing prefix.
@ -357,7 +371,6 @@ LINPHONE_PUBLIC const LinphoneErrorInfo *linphone_proxy_config_get_error_info(co
**/
LINPHONE_PUBLIC const char* linphone_proxy_config_get_transport(const LinphoneProxyConfig *cfg);
/**
* Destroys a proxy config.
* @deprecated
@ -390,8 +403,7 @@ LINPHONE_PUBLIC bool_t linphone_proxy_config_is_phone_number(LinphoneProxyConfig
* @param result_len the size of the normalized number \a result
* @return TRUE if a phone number was recognized, FALSE otherwise.
*/
LINPHONE_PUBLIC bool_t linphone_proxy_config_normalize_number(LinphoneProxyConfig *proxy, const char *username,
char *result, size_t result_len);
LINPHONE_PUBLIC bool_t linphone_proxy_config_normalize_number(LinphoneProxyConfig *proxy, const char *username, char *result, size_t result_len);
/**
* Same objective as linphone_proxy_config_normalize_number but allocates a new string
@ -399,7 +411,7 @@ LINPHONE_PUBLIC bool_t linphone_proxy_config_normalize_number(LinphoneProxyConfi
* @param username the string to parse
* @return NULL if invalid phone number, normalized phone number from username input otherwise.
*/
LINPHONE_PUBLIC char* linphone_proxy_config_normalize_phone_number(LinphoneProxyConfig *proxy, const char *username);
LINPHONE_PUBLIC char* linphone_proxy_config_normalize_phone_number(LinphoneProxyConfig *proxy, const char *username);
/**
* Normalize a human readable sip uri into a fully qualified LinphoneAddress.
@ -414,7 +426,7 @@ LINPHONE_PUBLIC char* linphone_proxy_config_normalize_phone_number(LinphoneProxy
* @param username the string to parse
* @return NULL if invalid input, normalized sip address otherwise.
*/
LINPHONE_PUBLIC LinphoneAddress* linphone_proxy_config_normalize_sip_uri(LinphoneProxyConfig *proxy, const char *username);
LINPHONE_PUBLIC LinphoneAddress* linphone_proxy_config_normalize_sip_uri(LinphoneProxyConfig *proxy, const char *username);
/**
* Set default privacy policy for all calls routed through this proxy.
@ -422,18 +434,21 @@ LINPHONE_PUBLIC LinphoneAddress* linphone_proxy_config_normalize_sip_uri(Linphon
* @param privacy LinphonePrivacy to configure 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[in] cfg #LinphoneProxyConfig object.
* @return Privacy mode
* */
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[in] cfg #LinphoneProxyConfig object.
* @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[in] cfg #LinphoneProxyConfig object.
@ -501,4 +516,8 @@ LINPHONE_PUBLIC const char *linphone_proxy_config_get_custom_header(LinphoneProx
**/
LINPHONE_PUBLIC void linphone_proxy_config_set_custom_header(LinphoneProxyConfig *cfg, const char *header_name, const char *header_value);
/**
* @}
*/
#endif

View file

@ -43,11 +43,15 @@ static const char *EC_STATE_STORE = ".linphone.ecstate";
static void linphone_call_stats_uninit(LinphoneCallStats *stats);
static void linphone_call_get_local_ip(LinphoneCall *call, const LinphoneAddress *remote_addr);
#ifdef VIDEO_ENABLED
MSWebCam *get_nowebcam_device(){
#ifdef VIDEO_ENABLED
return ms_web_cam_manager_get_cam(ms_web_cam_manager_get(),"StaticImage: Static picture");
}
#else
return NULL;
#endif
}
static bool_t generate_b64_crypto_key(int key_length, char* key_out, size_t key_out_size) {
int b64_size;
@ -485,10 +489,13 @@ static void setup_rtcp_fb(LinphoneCall *call, SalMediaDescription *md) {
MSList *pt_it;
PayloadType *pt;
PayloadTypeAvpfParams avpf_params;
LinphoneCore *lc = call->core;
int i;
for (i = 0; i < md->nb_streams; i++) {
if (!sal_stream_description_active(&md->streams[i])) continue;
md->streams[i].rtcp_fb.generic_nack_enabled = lp_config_get_int(lc->config, "rtp", "rtcp_fb_generic_nack_enabled", 0);
md->streams[i].rtcp_fb.tmmbr_enabled = lp_config_get_int(lc->config, "rtp", "rtcp_fb_tmmbr_enabled", 0);
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) {
@ -575,11 +582,30 @@ static const char *linphone_call_get_public_ip_for_stream(LinphoneCall *call, in
return public_ip;
}
void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call) {
linphone_call_make_local_media_description_with_params(lc, call, call->params);
static void force_streams_dir_according_to_state(LinphoneCall *call, SalMediaDescription *md){
int i;
switch (call->state){
case LinphoneCallPausing:
case LinphoneCallPaused:
break;
default:
return;
break;
}
for (i=0; i<2; ++i){
SalStreamDescription *sd = &md->streams[i];
sd->dir = SalStreamSendOnly;
if (sd->type == SalVideo){
if (lp_config_get_int(call->core->config, "sip", "inactive_video_on_pause", 0)) {
sd->dir = SalStreamInactive;
}
}
}
}
void linphone_call_make_local_media_description_with_params(LinphoneCore *lc, LinphoneCall *call, LinphoneCallParams *params) {
void linphone_call_make_local_media_description(LinphoneCall *call) {
MSList *l;
SalMediaDescription *old_md=call->localdesc;
int i;
@ -588,6 +614,9 @@ void linphone_call_make_local_media_description_with_params(LinphoneCore *lc, Li
LinphoneAddress *addr;
const char *subject;
CodecConstraints codec_hints={0};
LinphoneCallParams *params = call->params;
LinphoneCore *lc = call->core;
/*multicast is only set in case of outgoing call*/
if (call->dir == LinphoneCallOutgoing && linphone_call_params_audio_multicast_enabled(params)) {
@ -711,6 +740,7 @@ void linphone_call_make_local_media_description_with_params(LinphoneCore *lc, Li
call->localdesc_changed=sal_media_description_equals(md,old_md);
sal_media_description_unref(old_md);
}
force_streams_dir_according_to_state(call, md);
}
static int find_port_offset(LinphoneCore *lc, int stream_index, int base_port){
@ -815,9 +845,6 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from,
linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO], LINPHONE_CALL_STATS_AUDIO);
linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO], LINPHONE_CALL_STATS_VIDEO);
#ifdef VIDEO_ENABLED
call->cam = call->core->video_conf.device;
#endif
}
void linphone_call_init_stats(LinphoneCallStats *stats, int type) {
@ -945,6 +972,7 @@ void linphone_call_fill_media_multicast_addr(LinphoneCall *call) {
} else
call->media_ports[1].multicast_ip[0]='\0';
}
LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg){
LinphoneCall *call = belle_sip_object_new(LinphoneCall);
@ -952,7 +980,7 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr
call->core=lc;
linphone_call_outgoing_select_ip_version(call,to,cfg);
linphone_call_get_local_ip(call, to);
linphone_call_init_common(call,from,to);
linphone_call_init_common(call, from, to);
call->params = linphone_call_params_copy(params);
linphone_call_fill_media_multicast_addr(call);
@ -1260,7 +1288,7 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const
call->prevstate=call->state;
if (call->state==LinphoneCallEnd || call->state==LinphoneCallError){
if (cstate!=LinphoneCallReleased){
ms_warning("Spurious call state change from %s to %s, ignored." ,linphone_call_state_to_string(call->state)
ms_fatal("Spurious call state change from %s to %s, ignored." ,linphone_call_state_to_string(call->state)
,linphone_call_state_to_string(cstate));
return;
}
@ -1286,11 +1314,11 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const
break;
case LinphoneCallEnd:
case LinphoneCallError:
switch(call->non_op_error.reason){
case SalReasonDeclined:
switch(linphone_error_info_get_reason(linphone_call_get_error_info(call))) {
case LinphoneReasonDeclined:
call->log->status=LinphoneCallDeclined;
break;
case SalReasonRequestTimeout:
case LinphoneReasonNotAnswered:
call->log->status=LinphoneCallMissed;
break;
default:
@ -1324,7 +1352,13 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const
linphone_call_cancel_dtmfs(call);
}
}
linphone_core_notify_call_state_changed(lc,call,cstate,message);
if (!message) {
ms_error("%s(): You must fill a reason when changing call state (from %s o %s)."
, __FUNCTION__
, linphone_call_state_to_string(call->prevstate)
, linphone_call_state_to_string(call->state));
}
linphone_core_notify_call_state_changed(lc,call,cstate,message?message:"");
linphone_reporting_call_state_updated(call);
if (cstate==LinphoneCallReleased) {/*shall be performed after app notification*/
linphone_call_set_released(call);
@ -2009,6 +2043,7 @@ void linphone_call_init_audio_stream(LinphoneCall *call){
ms_free(cname);
rtp_session_set_symmetric_rtp(audiostream->ms.sessions.rtp_session,linphone_core_symmetric_rtp_enabled(lc));
setup_dtls_params(call, &audiostream->ms);
media_stream_reclaim_sessions(&audiostream->ms, &call->sessions[0]);
}else{
call->audiostream=audio_stream_new_with_sessions(&call->sessions[0]);
}
@ -2108,8 +2143,8 @@ void linphone_call_init_video_stream(LinphoneCall *call){
video_stream_set_rtcp_information(call->videostream, cname, rtcp_tool);
ms_free(cname);
rtp_session_set_symmetric_rtp(call->videostream->ms.sessions.rtp_session,linphone_core_symmetric_rtp_enabled(lc));
setup_dtls_params(call, &call->videostream->ms);
media_stream_reclaim_sessions(&call->videostream->ms, &call->sessions[1]);
}else{
call->videostream=video_stream_new_with_sessions(&call->sessions[1]);
}
@ -2395,6 +2430,27 @@ static int find_crypto_index_from_tag(const SalSrtpCryptoAlgo crypto[],unsigned
return -1;
}
static void configure_rtp_session_for_rtcp_fb(LinphoneCall *call, const SalStreamDescription *stream) {
RtpSession *session = NULL;
if (stream->type == SalAudio) {
session = call->audiostream->ms.sessions.rtp_session;
} else if (stream->type == SalVideo) {
session = call->videostream->ms.sessions.rtp_session;
} else {
// Do nothing for streams that are not audio or video
return;
}
if (stream->rtcp_fb.generic_nack_enabled)
rtp_session_enable_avpf_feature(session, ORTP_AVPF_FEATURE_GENERIC_NACK, TRUE);
else
rtp_session_enable_avpf_feature(session, ORTP_AVPF_FEATURE_GENERIC_NACK, FALSE);
if (stream->rtcp_fb.tmmbr_enabled)
rtp_session_enable_avpf_feature(session, ORTP_AVPF_FEATURE_TMMBR, TRUE);
else
rtp_session_enable_avpf_feature(session, ORTP_AVPF_FEATURE_TMMBR, FALSE);
}
static void configure_rtp_session_for_rtcp_xr(LinphoneCore *lc, LinphoneCall *call, SalStreamType type) {
RtpSession *session;
const OrtpRtcpXrConfiguration *localconfig;
@ -2508,6 +2564,7 @@ static RtpSession * create_audio_rtp_io_session(LinphoneCall *call) {
int remote_port = lp_config_get_int(lc->config, "sound", "rtp_remote_port", 17078);
int ptnum = lp_config_get_int(lc->config, "sound", "rtp_ptnum", 0);
const char *rtpmap = lp_config_get_string(lc->config, "sound", "rtp_map", "pcmu/8000/1");
int symmetric = lp_config_get_int(lc->config, "sound", "rtp_symmetric", 0);
RtpSession *rtp_session = NULL;
pt = rtp_profile_get_payload_from_rtpmap(call->audio_profile, rtpmap);
if (pt != NULL) {
@ -2519,13 +2576,13 @@ static RtpSession * create_audio_rtp_io_session(LinphoneCall *call) {
rtp_session_enable_rtcp(rtp_session, FALSE);
rtp_session_set_payload_type(rtp_session, ptnum);
rtp_session_set_jitter_compensation(rtp_session, linphone_core_get_audio_jittcomp(lc));
rtp_session_set_symmetric_rtp(rtp_session, (bool_t)symmetric);
}
return rtp_session;
}
static void linphone_call_start_audio_stream(LinphoneCall *call, bool_t muted, bool_t send_ringbacktone, bool_t use_arc){
static void linphone_call_start_audio_stream(LinphoneCall *call, LinphoneCallState next_state, bool_t use_arc){
LinphoneCore *lc=call->core;
LpConfig* conf;
int used_pt=-1;
char rtcp_tool[128]={0};
const SalStreamDescription *stream;
@ -2537,7 +2594,7 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, bool_t muted, b
const char *recfile;
const SalStreamDescription *local_st_desc;
int crypto_idx;
AudioStreamIO io = { 0 };
MSMediaStreamIO io = MS_MEDIA_STREAM_IO_INITIALIZER;
bool_t use_rtp_io = lp_config_get_int(lc->config, "sound", "rtp_io", FALSE);
snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
@ -2562,27 +2619,24 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, bool_t muted, b
if (captcard==NULL) {
ms_warning("No card defined for capture !");
}
/*Replace soundcard filters by inactive file players or recorders
when placed in recvonly or sendonly mode*/
/*Don't use file or soundcard capture when placed in recv-only mode*/
if (stream->rtp_port==0
|| stream->dir==SalStreamRecvOnly
|| (stream->multicast_role == SalMulticastReceiver && is_multicast)){
captcard=NULL;
playfile=NULL;
}else if (stream->dir==SalStreamSendOnly){
}
if (next_state == LinphoneCallPaused){
/*in paused state, we never use soundcard*/
playcard=NULL;
/*jehan: why capture card should be null in this case ? Not very good to only rely on stream dir to detect paused state.
* It can also be a simple call in one way audio*/
captcard=NULL;
recfile=NULL;
/*And we will eventually play "playfile" if set by the user*/
/*playfile=NULL;*/
}
if (send_ringbacktone){
conf = linphone_core_get_config(lc);
if (call->playing_ringbacktone){
captcard=NULL;
playfile=NULL;/* it is setup later*/
if( conf && lp_config_get_int(conf,"sound","send_ringback_without_playback", 0) == 1){
if (lp_config_get_int(lc->config,"sound","send_ringback_without_playback", 0) == 1){
playcard = NULL;
recfile = NULL;
}
@ -2601,12 +2655,14 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, bool_t muted, b
captcard=playcard=NULL;
}
use_ec=captcard==NULL ? FALSE : linphone_core_echo_cancellation_enabled(lc);
audio_stream_enable_echo_canceller(call->audiostream, use_ec);
if (playcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(playcard, stream->max_rate);
if (captcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(captcard, stream->max_rate);
audio_stream_enable_adaptive_bitrate_control(call->audiostream,use_arc);
media_stream_set_adaptive_bitrate_algorithm(&call->audiostream->ms,
ms_qos_analyzer_algorithm_from_string(linphone_core_get_adaptive_rate_algorithm(lc)));
ms_qos_analyzer_algorithm_from_string(linphone_core_get_adaptive_rate_algorithm(lc)));
audio_stream_enable_adaptive_jittcomp(call->audiostream, linphone_core_audio_adaptive_jittcomp_enabled(lc));
rtp_session_set_jitter_compensation(call->audiostream->ms.sessions.rtp_session,linphone_core_get_audio_jittcomp(lc));
if (!call->params->in_conference && call->params->record_file){
audio_stream_mixed_record_open(call->audiostream,call->params->record_file);
call->current_params->record_file=ms_strdup(call->params->record_file);
@ -2617,29 +2673,39 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, bool_t muted, b
crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag);
if (crypto_idx >= 0) {
media_stream_set_srtp_recv_key_b64(&(call->audiostream->ms.sessions),stream->crypto[0].algo,stream->crypto[0].master_key);
media_stream_set_srtp_send_key_b64(&(call->audiostream->ms.sessions),stream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key);
ms_media_stream_sessions_set_srtp_recv_key_b64(&call->audiostream->ms.sessions, stream->crypto[0].algo,stream->crypto[0].master_key);
ms_media_stream_sessions_set_srtp_send_key_b64(&call->audiostream->ms.sessions, stream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key);
} else {
ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag);
}
}
configure_rtp_session_for_rtcp_fb(call, stream);
configure_rtp_session_for_rtcp_xr(lc, call, SalAudio);
if (is_multicast)
rtp_session_set_multicast_ttl(call->audiostream->ms.sessions.rtp_session,stream->ttl);
if (lc->use_files) {
io.input_file = playfile;
io.output_file = recfile;
} else if (use_rtp_io) {
io.rtp_session = create_audio_rtp_io_session(call);
if (io.rtp_session == NULL) {
if (use_rtp_io) {
io.input.type = io.output.type = MSResourceRtp;
io.input.session = io.output.session = create_audio_rtp_io_session(call);
if (io.input.session == NULL) {
ok = FALSE;
}
} else if (stream->dir==SalStreamSendOnly) { /*no very good, io.xx versus playcard,captcard and call state should be reworked*/
io.input_file = playfile; /*quick fix to restaure current behavior which is SalStreamSendOnly=Paused=playfile*/
} else {
io.playback_card = playcard;
io.capture_card = captcard;
}else {
if (playcard){
io.output.type = MSResourceSoundcard;
io.output.soundcard = playcard;
}else{
io.output.type = MSResourceFile;
io.output.file = recfile;
}
if (captcard){
io.input.type = MSResourceSoundcard;
io.input.soundcard = captcard;
}else{
io.input.type = MSResourceFile;
io.input.file = playfile;
}
}
if (ok == TRUE) {
audio_stream_start_from_io(call->audiostream,
@ -2649,26 +2715,24 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, bool_t muted, b
stream->rtcp_addr[0]!='\0' ? stream->rtcp_addr : call->resultdesc->addr,
(linphone_core_rtcp_enabled(lc) && !is_multicast) ? (stream->rtcp_port ? stream->rtcp_port : stream->rtp_port+1) : 0,
used_pt,
linphone_core_get_audio_jittcomp(lc),
use_ec,
&io
);
post_configure_audio_streams(call, muted && !send_ringbacktone);
post_configure_audio_streams(call, (call->all_muted || call->audio_muted) && !call->playing_ringbacktone);
}
media_stream_session_encryption_mandatory_enable(&call->audiostream->ms.sessions,linphone_core_is_media_encryption_mandatory(call->core));
ms_media_stream_sessions_set_encryption_mandatory(&call->audiostream->ms.sessions,linphone_core_is_media_encryption_mandatory(call->core));
if (stream->dir==SalStreamSendOnly && playfile!=NULL){
if (next_state == LinphoneCallPaused && captcard == NULL && playfile != NULL){
int pause_time=500;
ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
}
if (send_ringbacktone){
if (call->playing_ringbacktone){
setup_ring_player(lc,call);
}
if (call->params->in_conference){
/*transform the graph to connect it to the conference filter */
mute=stream->dir==SalStreamRecvOnly;
mute = stream->dir==SalStreamRecvOnly;
linphone_call_add_to_conf(call, mute);
}
call->current_params->in_conference=call->params->in_conference;
@ -2687,6 +2751,7 @@ static RtpSession * create_video_rtp_io_session(LinphoneCall *call) {
int remote_port = lp_config_get_int(lc->config, "video", "rtp_remote_port", 19078);
int ptnum = lp_config_get_int(lc->config, "video", "rtp_ptnum", 0);
const char *rtpmap = lp_config_get_string(lc->config, "video", "rtp_map", "vp8/90000/1");
int symmetric = lp_config_get_int(lc->config, "video", "rtp_symmetric", 0);
RtpSession *rtp_session = NULL;
pt = rtp_profile_get_payload_from_rtpmap(call->video_profile, rtpmap);
if (pt != NULL) {
@ -2697,12 +2762,13 @@ static RtpSession * create_video_rtp_io_session(LinphoneCall *call) {
rtp_session_set_remote_addr_and_port(rtp_session, remote_ip, remote_port, -1);
rtp_session_enable_rtcp(rtp_session, FALSE);
rtp_session_set_payload_type(rtp_session, ptnum);
rtp_session_set_symmetric_rtp(rtp_session, (bool_t)symmetric);
}
return rtp_session;
}
#endif
static void linphone_call_start_video_stream(LinphoneCall *call, bool_t all_inputs_muted){
static void linphone_call_start_video_stream(LinphoneCall *call, LinphoneCallState next_state){
#ifdef VIDEO_ENABLED
LinphoneCore *lc=call->core;
int used_pt=-1;
@ -2710,14 +2776,12 @@ static void linphone_call_start_video_stream(LinphoneCall *call, bool_t all_inpu
MSFilter* source = NULL;
bool_t reused_preview = FALSE;
bool_t use_rtp_io = lp_config_get_int(lc->config, "video", "rtp_io", FALSE);
VideoStreamIO io = { 0 };
MSMediaStreamIO io = MS_MEDIA_STREAM_IO_INITIALIZER;
/* shutdown preview */
if (lc->previewstream!=NULL) {
if( lc->video_conf.reuse_preview_source == FALSE) video_preview_stop(lc->previewstream);
else source = video_preview_stop_reuse_source(lc->previewstream);
lc->previewstream=NULL;
}
@ -2730,9 +2794,10 @@ static void linphone_call_start_video_stream(LinphoneCall *call, bool_t all_inpu
call->video_profile=make_profile(call,call->resultdesc,vstream,&used_pt);
if (used_pt!=-1){
VideoStreamDir dir=VideoStreamSendRecv;
MediaStreamDir dir= MediaStreamSendRecv;
bool_t is_inactive=FALSE;
MSWebCam *cam;
call->current_params->video_codec = rtp_profile_get_payload(call->video_profile, used_pt);
call->current_params->has_video=TRUE;
@ -2741,6 +2806,7 @@ static void linphone_call_start_video_stream(LinphoneCall *call, bool_t all_inpu
media_stream_set_adaptive_bitrate_algorithm(&call->videostream->ms,
ms_qos_analyzer_algorithm_from_string(linphone_core_get_adaptive_rate_algorithm(lc)));
video_stream_enable_adaptive_jittcomp(call->videostream, linphone_core_video_adaptive_jittcomp_enabled(lc));
rtp_session_set_jitter_compensation(call->videostream->ms.sessions.rtp_session, linphone_core_get_video_jittcomp(lc));
if (lc->video_conf.preview_vsize.width!=0)
video_stream_set_preview_size(call->videostream,lc->video_conf.preview_vsize);
video_stream_set_fps(call->videostream,linphone_core_get_preferred_framerate(lc));
@ -2756,38 +2822,35 @@ static void linphone_call_start_video_stream(LinphoneCall *call, bool_t all_inpu
if (is_multicast){
if (vstream->multicast_role == SalMulticastReceiver)
dir=VideoStreamRecvOnly;
dir=MediaStreamRecvOnly;
else
dir=VideoStreamSendOnly;
dir=MediaStreamSendOnly;
} else if (vstream->dir==SalStreamSendOnly && lc->video_conf.capture ){
dir=VideoStreamSendOnly;
dir=MediaStreamSendOnly;
}else if (vstream->dir==SalStreamRecvOnly && lc->video_conf.display ){
dir=VideoStreamRecvOnly;
dir=MediaStreamRecvOnly;
}else if (vstream->dir==SalStreamSendRecv){
if (lc->video_conf.display && lc->video_conf.capture)
dir=VideoStreamSendRecv;
dir=MediaStreamSendRecv;
else if (lc->video_conf.display)
dir=VideoStreamRecvOnly;
dir=MediaStreamRecvOnly;
else
dir=VideoStreamSendOnly;
dir=MediaStreamSendOnly;
}else{
ms_warning("video stream is inactive.");
/*either inactive or incompatible with local capabilities*/
is_inactive=TRUE;
}
if (all_inputs_muted){
cam=get_nowebcam_device();
} else {
cam = linphone_call_get_video_device(call);
}
cam = linphone_call_get_video_device(call);
if (!is_inactive){
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_b64(&(call->videostream->ms.sessions),vstream->crypto[0].algo,vstream->crypto[0].master_key);
media_stream_set_srtp_send_key_b64(&(call->videostream->ms.sessions),vstream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key);
ms_media_stream_sessions_set_srtp_recv_key_b64(&call->videostream->ms.sessions, vstream->crypto[0].algo,vstream->crypto[0].master_key);
ms_media_stream_sessions_set_srtp_send_key_b64(&call->videostream->ms.sessions, vstream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key);
}
}
configure_rtp_session_for_rtcp_fb(call, vstream);
configure_rtp_session_for_rtcp_xr(lc, call, SalVideo);
call->log->video_enabled = TRUE;
@ -2810,23 +2873,26 @@ static void linphone_call_start_video_stream(LinphoneCall *call, bool_t all_inpu
} else {
bool_t ok = TRUE;
if (use_rtp_io) {
io.rtp_session = create_video_rtp_io_session(call);
if (io.rtp_session == NULL) {
io.input.type = io.output.type = MSResourceRtp;
io.input.session = io.output.session = create_video_rtp_io_session(call);
if (io.input.session == NULL) {
ok = FALSE;
ms_warning("Cannot create video RTP IO session");
}
} else {
io.cam = cam;
io.input.type = MSResourceCamera;
io.input.camera = cam;
io.output.type = MSResourceDefault;
}
if (ok) {
video_stream_start_from_io(call->videostream,
call->video_profile, rtp_addr, vstream->rtp_port,
rtcp_addr,
(linphone_core_rtcp_enabled(lc) && !is_multicast) ? (vstream->rtcp_port ? vstream->rtcp_port : vstream->rtp_port+1) : 0,
used_pt, linphone_core_get_video_jittcomp(lc), &io);
used_pt, &io);
}
}
media_stream_session_encryption_mandatory_enable(&call->videostream->ms.sessions,linphone_core_is_media_encryption_mandatory(call->core));
ms_media_stream_sessions_set_encryption_mandatory(&call->videostream->ms.sessions,linphone_core_is_media_encryption_mandatory(call->core));
}
}else ms_warning("No video stream accepted.");
}else{
@ -2895,13 +2961,29 @@ static void setZrtpCryptoTypesParameters(MSZrtpParams *params, LinphoneCore *lc)
params->keyAgreementsCount = linphone_core_get_zrtp_key_agreement_suites(lc, params->keyAgreements);
}
void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone){
void linphone_call_start_media_streams(LinphoneCall *call, LinphoneCallState next_state){
LinphoneCore *lc=call->core;
bool_t use_arc=linphone_core_adaptive_rate_control_enabled(lc);
bool_t use_arc = linphone_core_adaptive_rate_control_enabled(lc);
#ifdef VIDEO_ENABLED
const SalStreamDescription *vstream=sal_media_description_find_best_stream(call->resultdesc,SalVideo);
#endif
switch (next_state){
case LinphoneCallIncomingEarlyMedia:
if (linphone_core_get_remote_ringback_tone(lc)){
call->playing_ringbacktone = TRUE;
}
case LinphoneCallOutgoingEarlyMedia:
if (!call->params->real_early_media){
call->all_muted = TRUE;
}
break;
default:
call->playing_ringbacktone = FALSE;
call->all_muted = FALSE;
break;
}
call->current_params->audio_codec = NULL;
call->current_params->video_codec = NULL;
@ -2919,18 +3001,16 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut
call, linphone_core_get_upload_bandwidth(lc),linphone_core_get_download_bandwidth(lc));
if (call->audiostream!=NULL) {
linphone_call_start_audio_stream(call,all_inputs_muted||call->audio_muted,send_ringbacktone,use_arc);
linphone_call_start_audio_stream(call, next_state, use_arc);
} else {
ms_warning("DTLS no audio stream!");
}
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,all_inputs_muted);
linphone_call_start_video_stream(call, next_state);
}
call->all_muted=all_inputs_muted;
call->playing_ringbacktone=send_ringbacktone;
call->up_bw=linphone_core_get_upload_bandwidth(lc);
/*might be moved in audio/video stream_start*/
@ -2975,9 +3055,9 @@ static bool_t update_stream_crypto_params(LinphoneCall *call, const SalStreamDes
int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
if (crypto_idx >= 0) {
if (call->localdesc_changed & SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED)
media_stream_set_srtp_send_key_b64(&(ms->sessions),new_stream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key);
ms_media_stream_sessions_set_srtp_send_key_b64(&ms->sessions, new_stream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key);
if (strcmp(old_stream->crypto[0].master_key,new_stream->crypto[0].master_key)!=0){
media_stream_set_srtp_recv_key_b64(&(ms->sessions),new_stream->crypto[0].algo,new_stream->crypto[0].master_key);
ms_media_stream_sessions_set_srtp_recv_key_b64(&ms->sessions, new_stream->crypto[0].algo,new_stream->crypto[0].master_key);
}
return TRUE;
} else {
@ -3049,6 +3129,17 @@ static void linphone_call_log_fill_stats(LinphoneCallLog *log, MediaStream *st){
}
}
static void update_rtp_stats(LinphoneCall *call, int stream_index) {
if (stream_index >= linphone_call_get_stream_count(call)) {
return;
}
if (call->sessions[stream_index].rtp_session) {
const rtp_stats_t *stats = rtp_session_get_stats(call->sessions[stream_index].rtp_session);
memcpy(&call->stats[stream_index].rtp_stats, stats, sizeof(*stats));
}
}
static void linphone_call_stop_audio_stream(LinphoneCall *call) {
if (call->audiostream!=NULL) {
linphone_reporting_update_media_info(call, LINPHONE_CALL_STATS_AUDIO);
@ -3068,6 +3159,7 @@ static void linphone_call_stop_audio_stream(LinphoneCall *call) {
linphone_call_remove_from_conf(call);
}
audio_stream_stop(call->audiostream);
update_rtp_stats(call, 0);
rtp_session_unregister_event_queue(call->sessions[0].rtp_session, call->audiostream_app_evq);
ortp_ev_queue_flush(call->audiostream_app_evq);
ortp_ev_queue_destroy(call->audiostream_app_evq);
@ -3085,6 +3177,7 @@ static void linphone_call_stop_video_stream(LinphoneCall *call) {
linphone_call_log_fill_stats(call->log,(MediaStream*)call->videostream);
video_stream_stop(call->videostream);
call->videostream=NULL;
update_rtp_stats(call, 1);
rtp_session_unregister_event_queue(call->sessions[1].rtp_session, call->videostream_app_evq);
ortp_ev_queue_flush(call->videostream_app_evq);
ortp_ev_queue_destroy(call->videostream_app_evq);
@ -3206,28 +3299,28 @@ float linphone_call_get_record_volume(LinphoneCall *call){
return LINPHONE_VOLUME_DB_LOWEST;
}
double linphone_call_get_play_percent_volume(const LinphoneCall *call) {
float linphone_call_get_speaker_volume_gain(const LinphoneCall *call) {
if(call->audiostream) return audio_stream_get_sound_card_output_gain(call->audiostream);
else {
ms_error("Could not get playback volume: no audio stream");
return -1.0;
return -1.0f;
}
}
void linphone_call_set_play_percent_volume(LinphoneCall *call, double volume) {
void linphone_call_set_speaker_volume_gain(LinphoneCall *call, float volume) {
if(call->audiostream) audio_stream_set_sound_card_output_gain(call->audiostream, volume);
else ms_error("Could not set playback volume: no audio stream");
}
double linphone_call_get_record_percent_volume(const LinphoneCall *call) {
float linphone_call_get_microphone_volume_gain(const LinphoneCall *call) {
if(call->audiostream) return audio_stream_get_sound_card_input_gain(call->audiostream);
else {
ms_error("Could not get record volume: no audio stream");
return -1.0;
return -1.0f;
}
}
void linphone_call_set_record_percent_volume(LinphoneCall *call, double volume) {
void linphone_call_set_microphone_volume_gain(LinphoneCall *call, float volume) {
if(call->audiostream) audio_stream_set_sound_card_input_gain(call->audiostream, volume);
else ms_error("Could not set record volume: no audio stream");
}
@ -3278,19 +3371,20 @@ float linphone_call_get_average_quality(LinphoneCall *call){
return -1;
}
static void update_local_stats(LinphoneCallStats *stats, MediaStream *stream){
const MSQualityIndicator *qi=media_stream_get_quality_indicator(stream);
static void update_local_stats(LinphoneCallStats *stats, MediaStream *stream) {
const MSQualityIndicator *qi = media_stream_get_quality_indicator(stream);
if (qi) {
stats->local_late_rate=ms_quality_indicator_get_local_late_rate(qi);
stats->local_loss_rate=ms_quality_indicator_get_local_loss_rate(qi);
}
media_stream_get_local_rtp_stats(stream, &stats->rtp_stats);
}
/**
* Access last known statistics for audio stream, for a given call.
**/
const LinphoneCallStats *linphone_call_get_audio_stats(LinphoneCall *call) {
LinphoneCallStats *stats=&call->stats[LINPHONE_CALL_STATS_AUDIO];
LinphoneCallStats *stats = &call->stats[LINPHONE_CALL_STATS_AUDIO];
if (call->audiostream){
update_local_stats(stats,(MediaStream*)call->audiostream);
}
@ -3301,7 +3395,7 @@ const LinphoneCallStats *linphone_call_get_audio_stats(LinphoneCall *call) {
* Access last known statistics for video stream, for a given call.
**/
const LinphoneCallStats *linphone_call_get_video_stats(LinphoneCall *call) {
LinphoneCallStats *stats=&call->stats[LINPHONE_CALL_STATS_VIDEO];
LinphoneCallStats *stats = &call->stats[LINPHONE_CALL_STATS_VIDEO];
if (call->videostream){
update_local_stats(stats,(MediaStream*)call->videostream);
}
@ -3435,18 +3529,14 @@ float linphone_call_stats_get_receiver_interarrival_jitter(const LinphoneCallSta
return (float)report_block_get_interarrival_jitter(rrb) / (float)pt->clock_rate;
}
rtp_stats_t linphone_call_stats_get_rtp_stats(const LinphoneCallStats *stats, LinphoneCall *call) {
rtp_stats_t linphone_call_stats_get_rtp_stats(const LinphoneCallStats *stats) {
rtp_stats_t rtp_stats;
memset(&rtp_stats, 0, sizeof(rtp_stats));
if (stats && call) {
if (stats->type == LINPHONE_CALL_STATS_AUDIO && call->audiostream != NULL)
audio_stream_get_local_rtp_stats(call->audiostream, &rtp_stats);
#ifdef VIDEO_ENABLED
else if (call->videostream != NULL)
video_stream_get_local_rtp_stats(call->videostream, &rtp_stats);
#endif
if (stats) {
memcpy(&rtp_stats, &stats->rtp_stats, sizeof(stats->rtp_stats));
}
return rtp_stats;
}
@ -3455,7 +3545,7 @@ rtp_stats_t linphone_call_stats_get_rtp_stats(const LinphoneCallStats *stats, Li
* @return The cumulative number of late packets
**/
uint64_t linphone_call_stats_get_late_packets_cumulative_number(const LinphoneCallStats *stats, LinphoneCall *call) {
return linphone_call_stats_get_rtp_stats(stats, call).outoftime;
return linphone_call_stats_get_rtp_stats(stats).outoftime;
}
/**
@ -3539,12 +3629,13 @@ static void report_bandwidth(LinphoneCall *call, MediaStream *as, MediaStream *v
call->stats[LINPHONE_CALL_STATS_AUDIO].updated|=LINPHONE_CALL_STATS_PERIODICAL_UPDATE;
linphone_core_notify_call_stats_updated(call->core, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
call->stats[LINPHONE_CALL_STATS_AUDIO].updated=0;
update_local_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO], as);
}
if (vs_active) {
call->stats[LINPHONE_CALL_STATS_VIDEO].updated|=LINPHONE_CALL_STATS_PERIODICAL_UPDATE;
linphone_core_notify_call_stats_updated(call->core, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
call->stats[LINPHONE_CALL_STATS_VIDEO].updated=0;
update_local_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO], vs);
}
ms_message( "Bandwidth usage for call [%p]:\n"
@ -3563,16 +3654,23 @@ static void report_bandwidth(LinphoneCall *call, MediaStream *as, MediaStream *v
}
static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){
char temp[256]={0};
static void linphone_call_lost(LinphoneCall *call, LinphoneReason reason){
LinphoneCore *lc = call->core;
char *temp = NULL;
char *from=NULL;
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 : "");
switch(reason){
case LinphoneReasonIOError:
temp = ms_strdup_printf("Call with %s disconnected because of network, it is going to be closed.", from ? from : "?");
break;
default:
temp = ms_strdup_printf("Media connectivity with %s is lost, call is going to be closed.", from ? from : "?");
break;
}
if (from) ms_free(from);
ms_message("On call [%p]: %s",call,temp);
linphone_core_notify_display_warning(lc,temp);
ms_message("LinphoneCall [%p]: %s",call, temp);
linphone_core_notify_display_warning(lc, temp);
linphone_core_terminate_call(lc,call);
linphone_core_play_named_tone(lc,LinphoneToneCallLost);
}
@ -3757,10 +3855,10 @@ void linphone_call_handle_stream_events(LinphoneCall *call, int stream_index){
if (call->ice_session == NULL) ms->ice_check_list = NULL;
switch(ms->type){
case AudioStreamType:
case MSAudio:
audio_stream_iterate((AudioStream*)ms);
break;
case VideoStreamType:
case MSVideo:
#ifdef VIDEO_ENABLED
video_stream_iterate((VideoStream*)ms);
#endif
@ -3779,17 +3877,17 @@ void linphone_call_handle_stream_events(LinphoneCall *call, int stream_index){
linphone_call_notify_stats_updated(call,stream_index);
if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
if (ms->type==AudioStreamType)
if (ms->type==MSAudio)
linphone_call_audiostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
else if (ms->type==VideoStreamType)
else if (ms->type==MSVideo)
propagate_encryption_changed(call);
} else if (evt == ORTP_EVENT_ZRTP_SAS_READY) {
if (ms->type==AudioStreamType)
if (ms->type==MSAudio)
linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified);
} else if (evt == ORTP_EVENT_DTLS_ENCRYPTION_CHANGED) {
if (ms->type==AudioStreamType)
if (ms->type==MSAudio)
linphone_call_audiostream_encryption_changed(call, evd->info.dtls_stream_encrypted);
else if (ms->type==VideoStreamType)
else if (ms->type==MSVideo)
propagate_encryption_changed(call);
}else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
|| (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
@ -3840,7 +3938,7 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse
&& call->audiostream->ms.state==MSStreamStarted && disconnect_timeout>0 )
disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout);
if (disconnected)
linphone_core_disconnected(call->core,call);
linphone_call_lost(call, LinphoneReasonUnknown);
}
void linphone_call_log_completed(LinphoneCall *call){
@ -4091,14 +4189,20 @@ void linphone_call_set_native_video_window_id(LinphoneCall *call, void *id) {
}
#endif
}
#ifdef VIDEO_ENABLED
MSWebCam *linphone_call_get_video_device(const LinphoneCall *call) {
if (call->camera_enabled==FALSE)
if (call->all_muted || call->camera_enabled == FALSE)
return get_nowebcam_device();
else
return call->cam;
return call->core->video_conf.device;
}
void linphone_call_set_audio_route(LinphoneCall *call, LinphoneAudioRoute route) {
if (call != NULL && call->audiostream != NULL){
audio_stream_set_audio_route(call->audiostream, (MSAudioRoute) route);
}
}
#endif
LinphoneChatRoom * linphone_call_get_chat_room(LinphoneCall *call) {
/*stubbed implementation*/
@ -4106,3 +4210,93 @@ LinphoneChatRoom * linphone_call_get_chat_room(LinphoneCall *call) {
chat_room->call=linphone_call_ref(call);
return chat_room;
}
int linphone_call_get_stream_count(LinphoneCall *call) {
// Revisit when multiple media streams will be implemented
#ifdef VIDEO_ENABLED
return 2;
#else
return 1;
#endif
}
MSFormatType linphone_call_get_stream_type(LinphoneCall *call, int stream_index) {
// Revisit when multiple media streams will be implemented
if (stream_index == 0) {
return MSAudio;
}
return MSVideo;
}
RtpTransport* linphone_call_get_meta_rtp_transport(LinphoneCall *call, int stream_index) {
RtpTransport *meta_rtp;
RtpTransport *meta_rtcp;
if (!call || stream_index < 0 || stream_index >= linphone_call_get_stream_count(call)) {
return NULL;
}
rtp_session_get_transports(call->sessions[stream_index].rtp_session, &meta_rtp, &meta_rtcp);
return meta_rtp;
}
RtpTransport* linphone_call_get_meta_rtcp_transport(LinphoneCall *call, int stream_index) {
RtpTransport *meta_rtp;
RtpTransport *meta_rtcp;
if (!call || stream_index < 0 || stream_index >= linphone_call_get_stream_count(call)) {
return NULL;
}
rtp_session_get_transports(call->sessions[stream_index].rtp_session, &meta_rtp, &meta_rtcp);
return meta_rtcp;
}
void linphone_call_set_broken(LinphoneCall *call){
switch(call->state){
/*for all the early states, we prefer to drop the call*/
case LinphoneCallOutgoingInit:
case LinphoneCallOutgoingRinging:
case LinphoneCallOutgoingEarlyMedia:
case LinphoneCallIncomingReceived:
case LinphoneCallIncomingEarlyMedia:
linphone_call_lost(call, LinphoneReasonIOError);
break;
case LinphoneCallStreamsRunning:
case LinphoneCallPaused:
case LinphoneCallPausedByRemote:
call->broken = TRUE;
break;
default:
ms_error("linphone_call_set_broken() unimplemented case.");
break;
}
}
void linphone_call_repair_if_broken(LinphoneCall *call){
LinphoneCallParams *params;
if (!call->broken) return;
/*First, make sure that the proxy from which we received this call, or to which we routed this call is registered*/
if (!call->dest_proxy || linphone_proxy_config_get_state(call->dest_proxy) != LinphoneRegistrationOk) return;
switch (call->state){
case LinphoneCallStreamsRunning:
case LinphoneCallPaused:
case LinphoneCallPausedByRemote:
ms_message("LinphoneCall[%p] is going to be updated (reINVITE) in order to recover from lost connectivity", call);
if (call->ice_session){
ice_session_restart(call->ice_session);
ice_session_set_role(call->ice_session, IR_Controlling);
}
params = linphone_core_create_call_params(call->core, call);
linphone_core_update_call(call->core, call, params);
linphone_call_params_unref(params);
break;
default:
ms_error("linphone_call_resume_if_broken(): don't know what to do in state [%s]", linphone_call_state_to_string(call->state));
break;
}
}

View file

@ -100,7 +100,6 @@ static ortp_mutex_t liblinphone_log_collection_mutex;
static bool_t liblinphone_serialize_logs = FALSE;
static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime);
static void linphone_core_run_hooks(LinphoneCore *lc);
static void linphone_core_free_hooks(LinphoneCore *lc);
#include "enum.h"
#include "contact_providers_priv.h"
@ -1565,6 +1564,8 @@ static void linphone_core_register_default_codecs(LinphoneCore *lc){
linphone_core_register_payload_type(lc,&payload_type_aal2_g726_24,NULL,FALSE);
linphone_core_register_payload_type(lc,&payload_type_aal2_g726_32,NULL,FALSE);
linphone_core_register_payload_type(lc,&payload_type_aal2_g726_40,NULL,FALSE);
linphone_core_register_payload_type(lc,&payload_type_codec2,NULL,FALSE);
@ -1588,7 +1589,7 @@ static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtab
lc->config=lp_config_ref(config);
lc->data=userdata;
lc->ringstream_autorelease=TRUE;
linphone_task_list_init(&lc->hooks);
memcpy(local_vtable,vtable,sizeof(LinphoneCoreVTable));
_linphone_core_add_listener(lc, local_vtable, TRUE);
@ -2767,7 +2768,7 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, const Linph
linphone_call_set_contact_op(call);
linphone_core_stop_dtmf_stream(lc);
linphone_call_make_local_media_description(lc,call);
linphone_call_make_local_media_description(call);
if (lc->ringstream==NULL) {
if (lc->sound_conf.play_sndcard && lc->sound_conf.capt_sndcard){
@ -2775,7 +2776,8 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, const Linph
if (call->localdesc->streams[0].max_rate>0) {
ms_snd_card_set_preferred_sample_rate(lc->sound_conf.play_sndcard, call->localdesc->streams[0].max_rate);
}
audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard);
if (!lc->use_files)
audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard);
}
}
real_url=linphone_address_as_string( destination ? destination : call->log->to);
@ -2922,21 +2924,6 @@ void linphone_configure_op(LinphoneCore *lc, SalOp *op, const LinphoneAddress *d
sal_op_cnx_ip_to_0000_if_sendonly_enable(op,lp_config_get_default_int(lc->config,"sip","cnx_ip_to_0000_if_sendonly_enabled",0)); /*also set in linphone_call_new_incoming*/
}
/**
* Initiates an outgoing call given a destination LinphoneAddress
*
* @ingroup call_control
* @param lc the LinphoneCore object
* @param addr the destination of the call (sip address).
@param params call parameters
*
* The LinphoneAddress can be constructed directly using linphone_address_new(), or
* created by linphone_core_interpret_url().
* The application doesn't own a reference to the returned LinphoneCall object.
* Use linphone_call_ref() to safely keep the LinphoneCall pointer valid within your application.
*
* @return a LinphoneCall object or NULL in case of failure
**/
LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const LinphoneAddress *addr, const LinphoneCallParams *params)
{
const char *from=NULL;
@ -3189,16 +3176,16 @@ int linphone_core_accept_early_media_with_params(LinphoneCore* lc, LinphoneCall*
// if parameters are passed, update the media description
if ( params ) {
linphone_call_set_new_params(call,params);
linphone_call_make_local_media_description ( lc,call );
linphone_call_make_local_media_description (call);
sal_call_set_local_media_description ( call->op,call->localdesc );
sal_op_set_sent_custom_header ( call->op,params->custom_headers );
}
sal_call_notify_ringing(call->op,TRUE);
sal_call_notify_ringing(call->op, TRUE);
linphone_call_set_state(call,LinphoneCallIncomingEarlyMedia,"Incoming call early media");
md=sal_call_get_final_media_description(call->op);
if (md) linphone_core_update_streams(lc,call,md);
if (md) linphone_core_update_streams(lc, call, md, call->state);
return 0;
}else{
ms_error("Bad state %s for linphone_core_accept_early_media_with_params()", linphone_call_state_to_string(call->state));
@ -3227,7 +3214,7 @@ int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call){
linphone_call_fill_media_multicast_addr(call);
if (!no_user_consent) linphone_call_make_local_media_description(lc,call);
if (!no_user_consent) linphone_call_make_local_media_description(call);
#ifdef BUILD_UPNP
if(call->upnp_session != NULL) {
linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
@ -3289,6 +3276,8 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho
nextstate=LinphoneCallEarlyUpdating;
break;
case LinphoneCallStreamsRunning:
case LinphoneCallPaused:
case LinphoneCallPausedByRemote:
nextstate=LinphoneCallUpdating;
break;
default:
@ -3297,6 +3286,7 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho
}
if (params!=NULL){
call->broken = FALSE;
linphone_call_set_state(call,nextstate,"Updating call");
#if defined(VIDEO_ENABLED) && defined(BUILD_UPNP)
has_video = call->params->has_video;
@ -3336,7 +3326,7 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho
#endif //defined(VIDEO_ENABLED) && defined(BUILD_UPNP)
if ((err = linphone_core_start_update_call(lc, call)) && call->state!=initial_state) {
/*Restore initial state*/
linphone_call_set_state(call,initial_state,NULL);
linphone_call_set_state(call,initial_state,"Restore initial state");
}
}else{
@ -3345,7 +3335,7 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho
video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc));
video_stream_set_fps(call->videostream, linphone_core_get_preferred_framerate(lc));
if (call->camera_enabled && call->videostream->cam!=lc->video_conf.device){
video_stream_change_camera(call->videostream,call->cam = lc->video_conf.device);
video_stream_change_camera(call->videostream, lc->video_conf.device);
}else video_stream_update_video_params(call->videostream);
}
#endif
@ -3367,14 +3357,23 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho
* Then, when the user responds to dialog prompt, it becomes possible to call linphone_core_accept_call_update() to answer
* the reINVITE, with eventually video enabled in the LinphoneCallParams argument.
*
* @return 0 if successful, -1 if the linphone_core_defer_call_update() was done outside a #LinphoneCallUpdatedByRemote notification, which is illegal.
* The #LinphoneCallUpdatedByRemote notification can also arrive when receiving an INVITE without SDP. In such case, an unchanged offer is made
* in the 200Ok, and when the ACK containing the SDP answer is received, #LinphoneCallUpdatedByRemote is triggered to notify the application of possible
* changes in the media session. However in such case defering the update has no meaning since we just generating an offer.
*
* @return 0 if successful, -1 if the linphone_core_defer_call_update() was done outside a valid #LinphoneCallUpdatedByRemote notification.
**/
int linphone_core_defer_call_update(LinphoneCore *lc, LinphoneCall *call){
if (call->state==LinphoneCallUpdatedByRemote){
if (call->expect_media_in_ack){
ms_error("linphone_core_defer_call_update() is not possible during a late offer incoming reINVITE (INVITE without SDP)");
return -1;
}
call->defer_update=TRUE;
return 0;
}else{
ms_error("linphone_core_defer_call_update() not done in state LinphoneCallUpdatedByRemote");
}
ms_error("linphone_core_defer_call_update() not done in state LinphoneCallUpdatedByRemote");
return -1;
}
@ -3386,7 +3385,7 @@ int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call,
return 0;
}
}
linphone_call_make_local_media_description(lc,call);
linphone_call_make_local_media_description(call);
linphone_call_update_remote_session_id_and_ver(call);
linphone_call_stop_ice_for_inactive_streams(call);
@ -3394,7 +3393,7 @@ int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call,
sal_call_accept(call->op);
md=sal_call_get_final_media_description(call->op);
if (md && !sal_media_description_empty(md)){
linphone_core_update_streams (lc,call,md);
linphone_core_update_streams(lc, call, md, next_state);
linphone_call_fix_call_parameters(call);
}
linphone_call_set_state(call,next_state,state_info);
@ -3603,7 +3602,7 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call,
linphone_call_set_compatible_incoming_call_parameters(call, md);
}
linphone_call_prepare_ice(call,TRUE);
linphone_call_make_local_media_description(lc,call);
linphone_call_make_local_media_description(call);
sal_call_set_local_media_description(call->op,call->localdesc);
sal_op_set_sent_custom_header(call->op,params->custom_headers);
}
@ -3617,7 +3616,7 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call,
ms_snd_card_set_preferred_sample_rate(lc->sound_conf.capt_sndcard, call->localdesc->streams[0].max_rate);
}
if (!was_ringing && call->audiostream->ms.state==MSStreamInitialized){
if (!was_ringing && call->audiostream->ms.state==MSStreamInitialized && !lc->use_files){
audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard);
}
@ -3629,7 +3628,7 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call,
linphone_call_set_state(call,LinphoneCallConnected,"Connected");
new_md=sal_call_get_final_media_description(call->op);
if (new_md){
linphone_core_update_streams(lc, call, new_md);
linphone_core_update_streams(lc, call, new_md, LinphoneCallStreamsRunning);
linphone_call_fix_call_parameters(call);
linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)");
}else call->expect_media_in_ack=TRUE;
@ -3813,10 +3812,8 @@ int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call){
}
/* Internal version that does not play tone indication*/
int _linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call)
{
int _linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call){
const char *subject=NULL;
LinphoneCallParams *params;
if (call->state!=LinphoneCallStreamsRunning && call->state!=LinphoneCallPausedByRemote){
ms_warning("Cannot pause this call, it is not active.");
@ -3830,15 +3827,8 @@ int _linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call)
ms_error("No reason to pause this call, it is already paused or inactive.");
return -1;
}
params = linphone_call_params_copy(call->params);
linphone_call_params_set_audio_direction(params, LinphoneMediaDirectionSendOnly);
if (lp_config_get_int(lc->config, "sip", "inactive_video_on_pause", 0)) {
linphone_call_params_set_video_direction(params, LinphoneMediaDirectionInactive);
} else {
linphone_call_params_set_video_direction(params, LinphoneMediaDirectionSendOnly);
}
linphone_call_make_local_media_description_with_params(lc, call, params);
linphone_call_params_unref(params);
linphone_call_set_state(call, LinphoneCallPausing, "Pausing call");
linphone_call_make_local_media_description(call);
#ifdef BUILD_UPNP
if(call->upnp_session != NULL) {
linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
@ -3852,7 +3842,6 @@ int _linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call)
linphone_core_notify_display_status(lc,_("Pausing the current call..."));
if (call->audiostream || call->videostream)
linphone_call_stop_media_streams (call);
linphone_call_set_state(call,LinphoneCallPausing,"Pausing call");
call->paused_by_app=FALSE;
return 0;
}
@ -3919,7 +3908,7 @@ int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call){
prevents the participants to hear it while the 200OK comes back.*/
if (call->audiostream) audio_stream_play(call->audiostream, NULL);
linphone_call_make_local_media_description(lc,call);
linphone_call_make_local_media_description(call);
#ifdef BUILD_UPNP
if(call->upnp_session != NULL) {
linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
@ -5946,7 +5935,8 @@ void sip_config_uninit(LinphoneCore *lc)
sal_iterate(lc->sal);
for(elem=config->proxies;elem!=NULL;elem=ms_list_next(elem)){
LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)(elem->data);
still_registered|=linphone_proxy_config_is_registered(cfg);
LinphoneRegistrationState state = linphone_proxy_config_get_state(cfg);
still_registered|=(state==LinphoneRegistrationOk||state==LinphoneRegistrationProgress);
}
ms_usleep(100000);
}
@ -6111,7 +6101,7 @@ LpConfig * linphone_core_create_lp_config(LinphoneCore *lc, const char *filename
static void linphone_core_uninit(LinphoneCore *lc)
{
linphone_core_free_hooks(lc);
linphone_task_list_free(&lc->hooks);
lc->video_conf.show_local = FALSE;
while(lc->calls)
@ -6216,6 +6206,8 @@ static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t cu
if (!lc->network_reachable){
linphone_core_invalidate_friend_subscriptions(lc);
sal_reset_transports(lc->sal);
/*mark all calls as broken, so that they can be either dropped immediately or restaured when network will be back*/
ms_list_for_each(lc->calls, (MSIterateFunc) linphone_call_set_broken);
}else{
linphone_core_resolve_stun_server(lc);
}
@ -6573,47 +6565,18 @@ void linphone_core_set_max_calls(LinphoneCore *lc, int max) {
lc->max_calls=max;
}
typedef struct Hook{
LinphoneCoreIterateHook fun;
void *data;
}Hook;
static Hook *hook_new(LinphoneCoreIterateHook hook, void *hook_data){
Hook *h=ms_new0(Hook,1);
h->fun=hook;
h->data=hook_data;
return h;
}
static void hook_invoke(Hook *h){
h->fun(h->data);
}
void linphone_core_add_iterate_hook(LinphoneCore *lc, LinphoneCoreIterateHook hook, void *hook_data){
lc->hooks=ms_list_append(lc->hooks,hook_new(hook,hook_data));
linphone_task_list_add(&lc->hooks, hook, hook_data);
}
static void linphone_core_run_hooks(LinphoneCore *lc){
ms_list_for_each(lc->hooks,(void (*)(void*))hook_invoke);
}
static void linphone_core_free_hooks(LinphoneCore *lc){
ms_list_for_each(lc->hooks,(void (*)(void*))ms_free);
ms_list_free(lc->hooks);
lc->hooks=NULL;
linphone_task_list_run(&lc->hooks);
}
void linphone_core_remove_iterate_hook(LinphoneCore *lc, LinphoneCoreIterateHook hook, void *hook_data){
MSList *elem;
for(elem=lc->hooks;elem!=NULL;elem=elem->next){
Hook *h=(Hook*)elem->data;
if (h->fun==hook && h->data==hook_data){
lc->hooks = ms_list_remove_link(lc->hooks,elem);
ms_free(h);
return;
}
}
ms_error("linphone_core_remove_iterate_hook(): No such hook found.");
linphone_task_list_remove(&lc->hooks, hook, hook_data);
}
void linphone_core_set_zrtp_secrets_file(LinphoneCore *lc, const char* file){

View file

@ -551,6 +551,7 @@ struct _LinphoneCallStats {
int updated; /**< Tell which RTCP packet has been updated (received_rtcp or sent_rtcp). Can be either LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE or LINPHONE_CALL_STATS_SENT_RTCP_UPDATE */
float rtcp_download_bandwidth; /**<RTCP download bandwidth measurement of received stream, expressed in kbit/s, including IP/UDP/RTP headers*/
float rtcp_upload_bandwidth; /**<RTCP download bandwidth measurement of sent stream, expressed in kbit/s, including IP/UDP/RTP headers*/
rtp_stats_t rtp_stats; /**< RTP stats */
};
/**
@ -563,7 +564,7 @@ LINPHONE_PUBLIC float linphone_call_stats_get_sender_loss_rate(const LinphoneCal
LINPHONE_PUBLIC float linphone_call_stats_get_receiver_loss_rate(const LinphoneCallStats *stats);
LINPHONE_PUBLIC float linphone_call_stats_get_sender_interarrival_jitter(const LinphoneCallStats *stats, LinphoneCall *call);
LINPHONE_PUBLIC float linphone_call_stats_get_receiver_interarrival_jitter(const LinphoneCallStats *stats, LinphoneCall *call);
LINPHONE_PUBLIC rtp_stats_t linphone_call_stats_get_rtp_stats(const LinphoneCallStats *statss, LinphoneCall *call);
LINPHONE_PUBLIC rtp_stats_t linphone_call_stats_get_rtp_stats(const LinphoneCallStats *statss);
LINPHONE_PUBLIC uint64_t linphone_call_stats_get_late_packets_cumulative_number(const LinphoneCallStats *stats, LinphoneCall *call);
LINPHONE_PUBLIC float linphone_call_stats_get_download_bandwidth(const LinphoneCallStats *stats);
LINPHONE_PUBLIC float linphone_call_stats_get_upload_bandwidth(const LinphoneCallStats *stats);
@ -598,7 +599,7 @@ LINPHONE_PUBLIC void linphone_player_close(LinphonePlayer *obj);
LINPHONE_PUBLIC void linphone_player_destroy(LinphonePlayer *obj);
/**
* @brief Create an independent media file player.
* Create an independent media file player.
* This player support WAVE and MATROSKA formats.
* @param lc A LinphoneCore object
* @param snd_card Playback sound card. If NULL, the sound card set in LinphoneCore will be used
@ -609,7 +610,7 @@ LINPHONE_PUBLIC void linphone_player_destroy(LinphonePlayer *obj);
LINPHONE_PUBLIC LinphonePlayer *linphone_core_create_local_player(LinphoneCore *lc, MSSndCard *snd_card, const char *video_out, void *window_id);
/**
* @brief Check whether Matroksa format is supported by the player
* Check whether Matroksa format is supported by the player
* @return TRUE if it is supported
*/
LINPHONE_PUBLIC bool_t linphone_local_player_matroska_supported(void);
@ -719,7 +720,21 @@ LINPHONE_PUBLIC LinphoneReason linphone_call_get_reason(const LinphoneCall *call
LINPHONE_PUBLIC const LinphoneErrorInfo *linphone_call_get_error_info(const LinphoneCall *call);
LINPHONE_PUBLIC const char *linphone_call_get_remote_user_agent(LinphoneCall *call);
LINPHONE_PUBLIC const char *linphone_call_get_remote_contact(LinphoneCall *call);
/**
* Get the mesured playback volume level.
*
* @param call The call.
* @return float Volume level in percentage.
*/
LINPHONE_PUBLIC float linphone_call_get_play_volume(LinphoneCall *call);
/**
* Get the mesured record volume level
*
* @param call The call.
* @return float Volume level in percentage.
*/
LINPHONE_PUBLIC float linphone_call_get_record_volume(LinphoneCall *call);
struct _LinphoneChatRoom;
@ -732,40 +747,44 @@ LINPHONE_PUBLIC struct _LinphoneChatRoom * linphone_call_get_chat_room(LinphoneC
/**
* @brief Get playback volume.
*
* Get speaker volume gain.
* If the sound backend supports it, the returned gain is equal to the gain set
* with the system mixer.
*
* @param call The call.
* @return double Percenatge of the max supported volume. Valid values are in [ 0.0 : 1.0 ].
* @return Percenatge of the max supported volume gain. Valid values are in [ 0.0 : 1.0 ].
* In case of failure, a negative value is returned
*/
LINPHONE_PUBLIC double linphone_call_get_play_percent_volume(const LinphoneCall *call);
LINPHONE_PUBLIC float linphone_call_get_speaker_volume_gain(const LinphoneCall *call);
/**
* @brief Set playback volume.
*
* Set speaker volume gain.
* If the sound backend supports it, the new gain will synchronized with the system mixer.
*
* @param call The call.
* @param volume New volume in percentage of the max supported volume. Valid values are in [ 0.0 : 1.0 ].
* @return void
* @param volume Percentage of the max supported gain. Valid values are in [ 0.0 : 1.0 ].
*/
LINPHONE_PUBLIC void linphone_call_set_play_percent_volume(LinphoneCall *call, double volume);
LINPHONE_PUBLIC void linphone_call_set_speaker_volume_gain(LinphoneCall *call, float volume);
/**
* @brief Get record volume.
*
* Get microphone volume gain.
* If the sound backend supports it, the returned gain is equal to the gain set
* with the system mixer.
*
* @param call The call.
* @return double Percenatge of the max supported volume. Valid values are in [ 0.0 : 1.0 ].
* @return double Percenatge of the max supported volume gain. Valid values are in [ 0.0 : 1.0 ].
* In case of failure, a negative value is returned
*/
LINPHONE_PUBLIC double linphone_call_get_record_percent_volume(const LinphoneCall *call);
LINPHONE_PUBLIC float linphone_call_get_microphone_volume_gain(const LinphoneCall *call);
/**
* @brief Set record volume.
*
* Set microphone volume gain.
* If the sound backend supports it, the new gain will synchronized with the system mixer.
*
* @param call The call.
* @param volume New volume in percentage of the max supported volume. Valid values are in [ 0.0 : 1.0 ].
* @return void
* @param volume Percentage of the max supported gain. Valid values are in [ 0.0 : 1.0 ].
*/
LINPHONE_PUBLIC void linphone_call_set_record_percent_volume(LinphoneCall *call, double volume);
LINPHONE_PUBLIC void linphone_call_set_microphone_volume_gain(LinphoneCall *call, float volume);
LINPHONE_PUBLIC float linphone_call_get_current_quality(LinphoneCall *call);
LINPHONE_PUBLIC float linphone_call_get_average_quality(LinphoneCall *call);
@ -867,6 +886,66 @@ LINPHONE_PUBLIC void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_
**/
LINPHONE_PUBLIC bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call);
/**
* Enum describing type of audio route.
* @ingroup call_control
**/
enum _LinphoneAudioRoute {
LinphoneAudioRouteEarpiece = MSAudioRouteEarpiece,
LinphoneAudioRouteSpeaker = MSAudioRouteSpeaker
};
/**
* Enum describing type of audio route.
* @ingroup call_control
**/
typedef enum _LinphoneAudioRoute LinphoneAudioRoute;
/**
* Change the playback output device (currently only used for blackberry)
* @param call
* @param route the wanted audio route (earpiece, speaker, ...)
*
* @ingroup call_control
**/
LINPHONE_PUBLIC void linphone_call_set_audio_route(LinphoneCall *call, LinphoneAudioRoute route);
/**
* Returns the number of stream for the given call.
* Currently there is only two (Audio, Video), but later there will be more.
* @param call
*
* @return 2
**/
LINPHONE_PUBLIC int linphone_call_get_stream_count(LinphoneCall *call);
/**
* Returns the type of stream for the given stream index.
* @param call
* @param stream_index
*
* @return MsAudio if stream_index = 0, MsVideo otherwise
**/
LINPHONE_PUBLIC MSFormatType linphone_call_get_stream_type(LinphoneCall *call, int stream_index);
/**
* Returns the meta rtp transport for the given stream index.
* @param call
* @param stream_index
*
* @return a pointer to the meta rtp transport if it exists, NULL otherwise
**/
LINPHONE_PUBLIC RtpTransport* linphone_call_get_meta_rtp_transport(LinphoneCall *call, int stream_index);
/**
* Returns the meta rtcp transport for the given stream index.
* @param call
* @param stream_index
*
* @return a pointer to the meta rtcp transport if it exists, NULL otherwise
**/
LINPHONE_PUBLIC RtpTransport* linphone_call_get_meta_rtcp_transport(LinphoneCall *call, int stream_index);
/*keep this in sync with mediastreamer2/msvolume.h*/
/**
@ -879,6 +958,7 @@ LINPHONE_PUBLIC bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *ca
* @addtogroup proxies
* @{
**/
/**
* The LinphoneProxyConfig object represents a proxy configuration to be used
* by the LinphoneCore object.
@ -914,6 +994,10 @@ typedef enum _LinphoneRegistrationState{
*/
LINPHONE_PUBLIC const char *linphone_registration_state_to_string(LinphoneRegistrationState cs);
/**
* @}
*/
#include "linphone_proxy_config.h"
struct _LinphoneAuthInfo;
@ -1157,24 +1241,11 @@ typedef LinphoneBuffer * (*LinphoneChatMessageCbsFileTransferSendCb)(LinphoneCha
typedef void (*LinphoneChatMessageCbsFileTransferProgressIndicationCb)(LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t total);
LINPHONE_PUBLIC void linphone_core_set_chat_database_path(LinphoneCore *lc, const char *path);
/**
* Create a new chat room for messaging from a sip uri like sip:joe@sip.linphone.org
* @param lc #LinphoneCore object
* @param to destination address for messages
* @return #LinphoneChatRoom where messaging can take place.
* @deprecated Use linphone_core_get_chat_room() or linphone_core_get_chat_room_from_uri() instead.
*/
LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_create_chat_room(LinphoneCore *lc, const char *to);
/**
* Create a new chat room for messaging from a sip uri like sip:joe@sip.linphone.org if not already existing, else return exisiting one
* @param lc #LinphoneCore object
* @param to destination address for messages
* @return #LinphoneChatRoom where messaging can take place.
* @deprecated Use linphone_core_get_chat_room() or linphone_core_get_chat_room_from_uri() instead.
*/
LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_get_or_create_chat_room(LinphoneCore *lc, const char *to);
/**
* Get a chat room whose peer is the supplied address. If it does not exist yet, it will be created.
* No reference is transfered to the application. The LinphoneCore keeps a reference on the chat room.
* @param lc the linphone core
* @param addr a linphone address.
* @return #LinphoneChatRoom where messaging can take place.
@ -1182,11 +1253,20 @@ LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_get_or_create_chat_room(Linphon
LINPHONE_PUBLIC LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAddress *addr);
/**
* Get a chat room for messaging from a sip uri like sip:joe@sip.linphone.org. If it does not exist yet, it will be created.
* No reference is transfered to the application. The LinphoneCore keeps a reference on the chat room.
* @param lc The linphone core
* @param to The destination address for messages.
* @return #LinphoneChatRoom where messaging can take place.
**/
LINPHONE_PUBLIC LinphoneChatRoom *linphone_core_get_chat_room_from_uri(LinphoneCore *lc, const char *to);
/**
* Removes a chatroom including all message history from the LinphoneCore.
* @param lc The linphone core
* @param to The chatroom.
**/
LINPHONE_PUBLIC void linphone_core_delete_chat_room(LinphoneCore *lc, LinphoneChatRoom *cr);
/**
* Inconditionnaly disable incoming chat messages.
* @param lc the core
@ -1258,17 +1338,17 @@ LINPHONE_PUBLIC void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void
/**
* Create a message attached to a dedicated chat room with a particular content.
* Use #linphone_chat_room_send_message2 to initiate the transfer
* Use #linphone_chat_room_send_message to initiate the transfer
* @param cr the chat room.
* @param 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 #LinphoneContent.data is NULL.
* @return a new #LinphoneChatMessage
*/
LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_file_transfer_message(LinphoneChatRoom *cr, LinphoneContent* initial_content);
LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_file_transfer_message(LinphoneChatRoom *cr, const LinphoneContent* initial_content);
LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_room_get_peer_address(LinphoneChatRoom *cr);
/**
* Send a message to peer member of this chat room.
* @deprecated linphone_chat_room_send_message2() gives more control on the message expedition.
* @deprecated Use linphone_chat_room_send_chat_message() instead.
* @param cr #LinphoneChatRoom object
* @param msg message to be sent
*/
@ -1281,6 +1361,7 @@ LINPHONE_PUBLIC void linphone_chat_room_send_message(LinphoneChatRoom *cr, const
* @param ud user data for the status cb.
* @deprecated Use linphone_chat_room_send_chat_message() instead.
* @note The LinphoneChatMessage must not be destroyed until the the callback is called.
* The LinphoneChatMessage reference is transfered to the function and thus doesn't need to be unref'd by the application.
*/
LINPHONE_PUBLIC void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* msg,LinphoneChatMessageStateChangedCb status_cb,void* ud);
/**
@ -1289,6 +1370,7 @@ LINPHONE_PUBLIC void linphone_chat_room_send_message2(LinphoneChatRoom *cr, Linp
* @param[in] msg LinphoneChatMessage object
* The state of the message sending will be notified via the callbacks defined in the LinphoneChatMessageCbs object that can be obtained
* by calling linphone_chat_message_get_callbacks().
* The LinphoneChatMessage reference is transfered to the function and thus doesn't need to be unref'd by the application.
*/
LINPHONE_PUBLIC void linphone_chat_room_send_chat_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg);
@ -1375,7 +1457,7 @@ LINPHONE_PUBLIC uint32_t linphone_chat_room_get_char(const LinphoneChatRoom *cr)
* @param[in] lc #LinphoneCore object
* @return \mslist{LinphoneChatRoom}
**/
LINPHONE_PUBLIC MSList* linphone_core_get_chat_rooms(LinphoneCore *lc);
LINPHONE_PUBLIC const MSList* linphone_core_get_chat_rooms(LinphoneCore *lc);
LINPHONE_PUBLIC unsigned int linphone_chat_message_store(LinphoneChatMessage *msg);
/**
@ -1516,7 +1598,7 @@ LINPHONE_PUBLIC void linphone_chat_message_set_user_data(LinphoneChatMessage* me
**/
LINPHONE_PUBLIC LinphoneChatRoom* linphone_chat_message_get_chat_room(LinphoneChatMessage *msg);
/**
* get peer address \link linphone_core_create_chat_room() associated to \endlink this #LinphoneChatRoom
* get peer address \link linphone_core_get_chat_room() associated to \endlink this #LinphoneChatRoom
* @param cr #LinphoneChatRoom object
* @return #LinphoneAddress peer address
*/
@ -1722,7 +1804,7 @@ typedef void (*LinphoneCoreGlobalStateChangedCb)(LinphoneCore *lc, LinphoneGloba
* @param lc the LinphoneCore
* @param call the call object whose state is changed.
* @param cstate the new state of the call
* @param message an informational message about the state.
* @param message a non NULL informational message about the state.
*/
typedef void (*LinphoneCoreCallStateChangedCb)(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *message);
@ -2273,6 +2355,21 @@ LINPHONE_PUBLIC LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, co
LINPHONE_PUBLIC LinphoneCall * linphone_core_invite_with_params(LinphoneCore *lc, const char *url, const LinphoneCallParams *params);
/**
* Initiates an outgoing call given a destination LinphoneAddress
*
* @ingroup call_control
* @param lc the LinphoneCore object
* @param addr the destination of the call (sip address).
@param params call parameters
*
* The LinphoneAddress can be constructed directly using linphone_address_new(), or
* created by linphone_core_interpret_url().
* The application doesn't own a reference to the returned LinphoneCall object.
* Use linphone_call_ref() to safely keep the LinphoneCall pointer valid within your application.
*
* @return a LinphoneCall object or NULL in case of failure
**/
LINPHONE_PUBLIC LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const LinphoneAddress *addr, const LinphoneCallParams *params);
LINPHONE_PUBLIC int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char *refer_to);
@ -2530,7 +2627,7 @@ LINPHONE_PUBLIC int linphone_core_get_upload_ptime(LinphoneCore *lc);
* @param[in] timeout_ms The SIP transport timeout in milliseconds.
* @ingroup media_parameters
*/
void linphone_core_set_sip_transport_timeout(LinphoneCore *lc, int timeout_ms);
LINPHONE_PUBLIC void linphone_core_set_sip_transport_timeout(LinphoneCore *lc, int timeout_ms);
/**
* Get the SIP transport timeout.
@ -2671,30 +2768,32 @@ LINPHONE_PUBLIC int linphone_core_get_payload_type_number(LinphoneCore *lc, cons
**/
LINPHONE_PUBLIC void linphone_core_set_payload_type_number(LinphoneCore *lc, PayloadType *pt, int number);
LINPHONE_PUBLIC const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt);
LINPHONE_PUBLIC const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt);
LINPHONE_PUBLIC bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, const PayloadType *pt);
LINPHONE_PUBLIC bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, const PayloadType *pt);
/**
* @addtogroup proxies
* @{
*/
/**
* Create a proxy config with default values from Linphone core.
* @param[in] lc #LinphoneCore object
* @return #LinphoneProxyConfig with default values set
* @ingroup proxy
*/
LINPHONE_PUBLIC LinphoneProxyConfig * linphone_core_create_proxy_config(LinphoneCore *lc);
LINPHONE_PUBLIC LinphoneProxyConfig * linphone_core_create_proxy_config(LinphoneCore *lc);
/**
* Add a proxy configuration.
* This will start registration on the proxy, if registration is enabled.
**/
LINPHONE_PUBLIC int linphone_core_add_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config);
LINPHONE_PUBLIC int linphone_core_add_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config);
/**
* Erase all proxies from config.
*
* @ingroup proxy
**/
LINPHONE_PUBLIC void linphone_core_clear_proxy_config(LinphoneCore *lc);
LINPHONE_PUBLIC void linphone_core_clear_proxy_config(LinphoneCore *lc);
/**
* Removes a proxy configuration.
@ -2702,14 +2801,14 @@ LINPHONE_PUBLIC void linphone_core_clear_proxy_config(LinphoneCore *lc);
* LinphoneCore will then automatically unregister and place the proxy configuration
* on a deleted list. For that reason, a removed proxy does NOT need to be freed.
**/
LINPHONE_PUBLIC void linphone_core_remove_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config);
LINPHONE_PUBLIC void linphone_core_remove_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config);
/**
* Returns an unmodifiable list of entered proxy configurations.
* @param[in] lc The LinphoneCore object
* @return \mslist{LinphoneProxyConfig}
**/
LINPHONE_PUBLIC const MSList *linphone_core_get_proxy_config_list(const LinphoneCore *lc);
LINPHONE_PUBLIC const MSList *linphone_core_get_proxy_config_list(const LinphoneCore *lc);
/** @deprecated Use linphone_core_set_default_proxy_config() instead. */
#define linphone_core_set_default_proxy(lc, config) linphone_core_set_default_proxy_config(lc, config)
@ -2720,7 +2819,7 @@ LINPHONE_PUBLIC void linphone_core_set_default_proxy_index(LinphoneCore *lc, int
* @return the default proxy configuration, that is the one used to determine the current identity.
* @deprecated Use linphone_core_get_default_proxy_config() instead.
**/
LINPHONE_PUBLIC int linphone_core_get_default_proxy(LinphoneCore *lc, LinphoneProxyConfig **config);
LINPHONE_PUBLIC int linphone_core_get_default_proxy(LinphoneCore *lc, LinphoneProxyConfig **config);
/**
* @return the default proxy configuration, that is the one used to determine the current identity.
@ -2740,6 +2839,10 @@ LINPHONE_PUBLIC LinphoneProxyConfig * linphone_core_get_default_proxy_config(Lin
**/
LINPHONE_PUBLIC void linphone_core_set_default_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config);
/**
* @}
*/
/**
* Create an authentication information with default values from Linphone core.
* @param[in] lc #LinphoneCore object

View file

@ -29,6 +29,7 @@ extern "C" {
#include "mediastreamer2/mscommon.h"
#include "mediastreamer2/msmediaplayer.h"
#include "mediastreamer2/msutils.h"
#include "devices.h"
}
#include "mediastreamer2/msjava.h"
#include "private.h"
@ -57,6 +58,9 @@ extern "C" void libmsbcg729_init();
#ifdef HAVE_WEBRTC
extern "C" void libmswebrtc_init();
#endif
#ifdef HAVE_CODEC2
extern "C" void libmscodec2_init();
#endif
#include <belle-sip/wakelock.h>
#endif /*ANDROID*/
@ -136,12 +140,18 @@ static void linphone_android_ortp_log_handler(OrtpLogLevel lev, const char *fmt,
int dumbMethodForAllowingUsageOfCpuFeaturesFromStaticLibMediastream() {
return (android_getCpuFamily() == ANDROID_CPU_FAMILY_ARM && (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0);
}
int dumbMethodForAllowingUsageOfMsAudioDiffFromStaticLibMediastream() {
return ms_audio_diff(NULL, NULL, NULL, 0, NULL, NULL);
}
#endif /*ANDROID*/
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *ajvm, void *reserved)
{
#ifdef ANDROID
ms_set_jvm(ajvm);
#endif /*ANDROID*/
jvm=ajvm;
return JNI_VERSION_1_2;
@ -371,12 +381,6 @@ public:
vTable->notify_presence_received = notify_presence_received;
}
/*void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from,String message);*/
textReceivedId = env->GetMethodID(listenerClass,"textReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;Lorg/linphone/core/LinphoneAddress;Ljava/lang/String;)V");
if (textReceivedId) {
vTable->text_received = text_received;
}
messageReceivedId = env->GetMethodID(listenerClass,"messageReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;Lorg/linphone/core/LinphoneChatMessage;)V");
if (messageReceivedId) {
vTable->message_received = message_received;
@ -516,7 +520,6 @@ public:
jmethodID displayStatusId;
jmethodID newSubscriptionRequestId;
jmethodID notifyPresenceReceivedId;
jmethodID textReceivedId;
jmethodID messageReceivedId;
jmethodID isComposingReceivedId;
jmethodID dtmfReceivedId;
@ -780,23 +783,6 @@ public:
,dtmf);
handle_possible_java_exception(env, lcData->listener);
}
static void text_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from, const char *message) {
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
ms_error("cannot attach VM");
return;
}
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
env->CallVoidMethod(lcData->listener
,lcData->textReceivedId
,lcData->core
,env->NewObject(lcData->chatRoomClass,lcData->chatRoomCtrId,(jlong)room)
,env->NewObject(lcData->addressClass,lcData->addressCtrId,(jlong)from)
,message ? env->NewStringUTF(message) : NULL);
handle_possible_java_exception(env, lcData->listener);
}
static void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *msg) {
JNIEnv *env = 0;
jobject jmsg;
@ -1159,6 +1145,9 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_newLinphoneCore(JNIEnv*
#ifdef HAVE_WEBRTC
libmswebrtc_init();
#endif
#ifdef HAVE_CODEC2
libmscodec2_init();
#endif
jobject core = env->NewGlobalRef(thiz);
jlong nativePtr = (jlong)linphone_core_new(vTable, userConfig, factoryConfig, core);
@ -2002,24 +1991,29 @@ extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_needsEchoCalibration
ms_error("Could not get soundcard %s", card);
return TRUE;
}
SoundDeviceDescription *sound_description = sound_device_description_get();
if(sound_description != NULL && sound_description == &genericSoundDeviceDescriptor){
return TRUE;
}
if (ms_snd_card_get_capabilities(sndcard) & MS_SND_CARD_CAP_BUILTIN_ECHO_CANCELLER) return FALSE;
if (ms_snd_card_get_minimal_latency(sndcard) != 0) return FALSE;
return TRUE;
}
extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_needsEchoCanceler(JNIEnv *env, jobject thiz, jlong lc) {
extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_hasBuiltInEchoCanceler(JNIEnv *env, jobject thiz, jlong lc) {
MSSndCard *sndcard;
MSSndCardManager *m = ms_snd_card_manager_get();
const char *card = linphone_core_get_capture_device((LinphoneCore*)lc);
sndcard = ms_snd_card_manager_get_card(m, card);
if (sndcard == NULL) {
ms_error("Could not get soundcard %s", card);
return TRUE;
return FALSE;
}
if (ms_snd_card_get_capabilities(sndcard) & MS_SND_CARD_CAP_BUILTIN_ECHO_CANCELLER) return FALSE;
return TRUE;
if (ms_snd_card_get_capabilities(sndcard) & MS_SND_CARD_CAP_BUILTIN_ECHO_CANCELLER) return TRUE;
return FALSE;
}
extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getMediaEncryption(JNIEnv* env

View file

@ -86,7 +86,7 @@ struct _LpConfig{
};
char* lp_realpath(const char* file, char* name) {
#ifdef _WIN32
#if defined(_WIN32) || defined(__QNX__) || defined(ANDROID)
return ms_strdup(file);
#else
char * output = realpath(file, name);
@ -370,7 +370,15 @@ LpConfig *lp_config_new_with_factory(const char *config_filename, const char *fa
LpConfig *lpconfig=lp_new0(LpConfig,1);
lpconfig->refcnt=1;
if (config_filename!=NULL){
lpconfig->filename=lp_realpath(config_filename, NULL);
if(ortp_file_exist(config_filename) == 0) {
lpconfig->filename=lp_realpath(config_filename, NULL);
if(lpconfig->filename == NULL) {
ms_error("Could not find the real path of %s: %s", config_filename, strerror(errno));
goto fail;
}
} else {
lpconfig->filename = ms_strdup(config_filename);
}
lpconfig->tmpfilename=ortp_strdup_printf("%s.tmp",lpconfig->filename);
ms_message("Using (r/w) config information from %s", lpconfig->filename);
@ -408,6 +416,10 @@ LpConfig *lp_config_new_with_factory(const char *config_filename, const char *fa
lp_config_read_file(lpconfig, factory_config_filename);
}
return lpconfig;
fail:
ms_free(lpconfig);
return NULL;
}
int lp_config_read_file(LpConfig *lpconfig, const char *filename){
@ -716,19 +728,30 @@ const char* lp_config_get_default_string(const LpConfig *lpconfig, const char *s
return lp_config_get_string(lpconfig, default_section, key, default_value);
}
static char *_lp_config_dirname(char *path) {
/*
* WARNING: this function is very dangerous.
* Read carefuly the folowing notices:
* 1. The 'path' parameter may be modify by
* the function. Be care to keep a copy of
* the original string.
* 2. The return pointer may points on a part of
* 'path'. So, be care to not free the string
* pointed by 'path' before the last used of
* the returned pointer.
* 3. Do not feed it after midnight
*/
static const char *_lp_config_dirname(char *path) {
#ifdef _MSC_VER
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
static char dirname[_MAX_DRIVE + _MAX_DIR];
_splitpath(path, drive, dir, fname, ext);
return ms_strdup_printf("%s%s", drive, dir);
snprintf(dirname, sizeof(dirname), "%s%s", drive, dir);
return dirname;
#else
char *tmp = ms_strdup(path);
char *dir = ms_strdup(dirname(tmp));
ms_free(tmp);
return dir;
return dirname(path);
#endif
}
@ -736,12 +759,18 @@ bool_t lp_config_relative_file_exists(const LpConfig *lpconfig, const char *file
if (lpconfig->filename == NULL) {
return FALSE;
} else {
char *dir = _lp_config_dirname(lpconfig->filename);
char *filename = ms_strdup(lpconfig->filename);
const char *dir = _lp_config_dirname(filename);
char *filepath = ms_strdup_printf("%s/%s", dir, filename);
char *realfilepath = lp_realpath(filepath, NULL);
FILE *file = fopen(realfilepath, "r");
ms_free(dir);
FILE *file;
ms_free(filename);
ms_free(filepath);
if(realfilepath == NULL) return FALSE;
file = fopen(realfilepath, "r");
ms_free(realfilepath);
if (file) {
fclose(file);
@ -751,54 +780,81 @@ bool_t lp_config_relative_file_exists(const LpConfig *lpconfig, const char *file
}
void lp_config_write_relative_file(const LpConfig *lpconfig, const char *filename, const char *data) {
char *dup_config_file = NULL;
const char *dir = NULL;
char *filepath = NULL;
char *realfilepath = NULL;
FILE *file;
if (lpconfig->filename == NULL) return;
if(strlen(data) > 0) {
char *dir = _lp_config_dirname(lpconfig->filename);
char *filepath = ms_strdup_printf("%s/%s", dir, filename);
char *realfilepath = lp_realpath(filepath, NULL);
FILE *file = fopen(realfilepath, "w");
if(file != NULL) {
fprintf(file, "%s", data);
fclose(file);
} else {
ms_error("Could not open %s for write", realfilepath);
}
ms_free(dir);
ms_free(filepath);
ms_free(realfilepath);
} else {
if(strlen(data) == 0) {
ms_warning("%s has not been created because there is no data to write", filename);
return;
}
dup_config_file = ms_strdup(lpconfig->filename);
dir = _lp_config_dirname(dup_config_file);
filepath = ms_strdup_printf("%s/%s", dir, filename);
realfilepath = lp_realpath(filepath, NULL);
if(realfilepath == NULL) {
ms_error("Could not resolv %s: %s", filepath, strerror(errno));
goto end;
}
file = fopen(realfilepath, "w");
if(file == NULL) {
ms_error("Could not open %s for write", realfilepath);
goto end;
}
fprintf(file, "%s", data);
fclose(file);
end:
ms_free(dup_config_file);
ms_free(filepath);
if(realfilepath) ms_free(realfilepath);
}
int lp_config_read_relative_file(const LpConfig *lpconfig, const char *filename, char *data, size_t max_length) {
char *dir;
char *filepath;
FILE *file;
char* realfilepath;
char *dup_config_file = NULL;
const char *dir = NULL;
char *filepath = NULL;
FILE *file = NULL;
char* realfilepath = NULL;
if (lpconfig->filename == NULL) return -1;
dir = _lp_config_dirname(lpconfig->filename);
dup_config_file = ms_strdup(lpconfig->filename);
dir = _lp_config_dirname(dup_config_file);
filepath = ms_strdup_printf("%s/%s", dir, filename);
realfilepath = lp_realpath(filepath, NULL);
if(realfilepath == NULL) {
ms_error("Could not resolv %s: %s", filepath, strerror(errno));
goto err;
}
file = fopen(realfilepath, "r");
if(file != NULL) {
if(fread(data, 1, max_length, file)<=0) {
ms_error("%s could not be loaded. %s", realfilepath, strerror(errno));
goto err;
}
fclose(file);
} else {
if(file == NULL) {
ms_error("Could not open %s for read. %s", realfilepath, strerror(errno));
goto err;
}
ms_free(dir);
if(fread(data, 1, max_length, file)<=0) {
ms_error("%s could not be loaded. %s", realfilepath, strerror(errno));
goto err;
}
fclose(file);
ms_free(dup_config_file);
ms_free(filepath);
ms_free(realfilepath);
return 0;
err:
ms_free(dir);
ms_free(filepath);
ms_free(realfilepath);
ms_free(filepath);
if(realfilepath) ms_free(realfilepath);
return -1;
}

View file

@ -94,6 +94,20 @@ static void fetch_content_from_database(sqlite3 *db, LinphoneChatMessage *messag
sqlite3_free(buf);
}
// 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];
LinphoneAddress *addr = linphone_address_new(address);
if (addr){
linphone_core_get_chat_room(lc, addr);
linphone_address_destroy(addr);
}
return 0;
}
/* DB layout:
* | 0 | storage_id
* | 1 | localContact
@ -106,13 +120,12 @@ static void fetch_content_from_database(sqlite3 *db, LinphoneChatMessage *messag
* | 8 | external body url
* | 9 | utc timestamp
* | 10 | app data text
* | 11 | linphone content
* | 11 | linphone content id
*/
static void create_chat_message(char **argv, void *data){
static int create_chat_message(void *data, int argc, char **argv, char **colName){
LinphoneChatRoom *cr = (LinphoneChatRoom *)data;
LinphoneAddress *from;
LinphoneAddress *to;
unsigned int storage_id = atoi(argv[0]);
// check if the message exists in the transient list, in which case we should return that one.
@ -136,17 +149,12 @@ static void create_chat_message(char **argv, void *data){
linphone_address_destroy(to);
}
if( argv[9] != NULL ){
new_message->time = (time_t)atol(argv[9]);
} else {
new_message->time = time(NULL);
}
new_message->time = (time_t)atol(argv[9]);
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;
new_message->external_body_url= ms_strdup(argv[8]);
new_message->appdata = ms_strdup(argv[10]);
if (argv[11] != NULL) {
int id = atoi(argv[11]);
@ -156,25 +164,14 @@ static void create_chat_message(char **argv, void *data){
}
}
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);
ret=sqlite3_exec(db,stmt,create_chat_message,cr,&errmsg);
if(ret != SQLITE_OK) {
ms_error("Error in creation: %s.", errmsg);
sqlite3_free(errmsg);
@ -287,7 +284,7 @@ void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr){
char *buf;
if (lc->db==NULL) return ;
// optimization: do not modify the database if no message is marked as unread
if(linphone_chat_room_get_unread_messages_count(cr) == 0) return;
@ -297,7 +294,7 @@ void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr){
linphone_sql_request(lc->db,buf);
sqlite3_free(buf);
ms_free(peer);
cr->unread_count = 0;
}
@ -321,7 +318,7 @@ static int linphone_chat_room_get_messages_count(LinphoneChatRoom *cr, bool_t un
int returnValue;
if (lc->db==NULL) return 0;
// optimization: do not read database if the count is already available in memory
if(unread_only && cr->unread_count >= 0) return cr->unread_count;
@ -336,11 +333,11 @@ static int linphone_chat_room_get_messages_count(LinphoneChatRoom *cr, bool_t un
sqlite3_finalize(selectStatement);
sqlite3_free(buf);
ms_free(peer);
/* no need to test the sign of cr->unread_count here
* because it has been tested above */
if(unread_only) cr->unread_count = numrows;
return numrows;
}
@ -361,7 +358,7 @@ void linphone_chat_room_delete_message(LinphoneChatRoom *cr, LinphoneChatMessage
buf=sqlite3_mprintf("DELETE FROM history WHERE id = %i;", msg->storage_id);
linphone_sql_request(lc->db,buf);
sqlite3_free(buf);
if(cr->unread_count >= 0 && !msg->is_read) {
assert(cr->unread_count > 0);
cr->unread_count--;
@ -380,7 +377,7 @@ void linphone_chat_room_delete_history(LinphoneChatRoom *cr){
linphone_sql_request(lc->db,buf);
sqlite3_free(buf);
ms_free(peer);
if(cr->unread_count > 0) cr->unread_count = 0;
}
@ -618,7 +615,7 @@ static int _linphone_sqlite3_open(const char *db_file, sqlite3 **db) {
#elif defined(_WIN32)
int ret;
wchar_t db_file_utf16[MAX_PATH_SIZE];
ret = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, db_file, MAX_PATH_SIZE, db_file_utf16, MAX_PATH_SIZE);
ret = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, db_file, -1, db_file_utf16, MAX_PATH_SIZE);
if(ret == 0) db_file_utf16[0] = '\0';
return sqlite3_open16(db_file_utf16, db);
#else
@ -627,7 +624,7 @@ static int _linphone_sqlite3_open(const char *db_file, sqlite3 **db) {
char *inbuf=db_file_locale, *outbuf=db_file_utf8;
size_t inbyteleft = MAX_PATH_SIZE, outbyteleft = MAX_PATH_SIZE;
iconv_t cb;
strncpy(db_file_locale, db_file, MAX_PATH_SIZE-1);
cb = iconv_open("UTF-8", nl_langinfo(CODESET));
if(cb != (iconv_t)-1) {

View file

@ -1788,3 +1788,48 @@ const char *linphone_tunnel_mode_to_string(LinphoneTunnelMode mode) {
return "invalid";
}
typedef struct Hook{
LinphoneCoreIterateHook fun;
void *data;
}Hook;
void linphone_task_list_init(LinphoneTaskList *t){
t->hooks = NULL;
}
static Hook *hook_new(LinphoneCoreIterateHook hook, void *hook_data){
Hook *h=ms_new0(Hook,1);
h->fun=hook;
h->data=hook_data;
return h;
}
static void hook_invoke(Hook *h){
h->fun(h->data);
}
void linphone_task_list_add(LinphoneTaskList *t, LinphoneCoreIterateHook hook, void *hook_data){
t->hooks = ms_list_append(t->hooks,hook_new(hook,hook_data));
}
void linphone_task_list_remove(LinphoneTaskList *t, LinphoneCoreIterateHook hook, void *hook_data){
MSList *elem;
for(elem=t->hooks;elem!=NULL;elem=elem->next){
Hook *h=(Hook*)elem->data;
if (h->fun==hook && h->data==hook_data){
t->hooks = ms_list_remove_link(t->hooks,elem);
ms_free(h);
return;
}
}
ms_error("linphone_task_list_remove(): No such hook found.");
}
void linphone_task_list_run(LinphoneTaskList *t){
ms_list_for_each(t->hooks,(void (*)(void*))hook_invoke);
}
void linphone_task_list_free(LinphoneTaskList *t){
t->hooks = ms_list_free_with_data(t->hooks, (void (*)(void*))ms_free);
}

View file

@ -503,6 +503,8 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
if ((ls->rtcp_xr.enabled == TRUE) && (rs->rtcp_xr.enabled == FALSE)) {
result->streams[i].rtcp_xr.enabled = FALSE;
}
result->streams[i].rtcp_fb.generic_nack_enabled = ls->rtcp_fb.generic_nack_enabled & rs->rtcp_fb.generic_nack_enabled;
result->streams[i].rtcp_fb.tmmbr_enabled = ls->rtcp_fb.tmmbr_enabled & rs->rtcp_fb.tmmbr_enabled;
++j;
}
else ms_warning("No matching stream for %i",i);
@ -569,6 +571,9 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities
}else ms_warning("Unknown protocol for mline %i, declining",i);
if (ls){
initiate_incoming(ls,rs,&result->streams[i],one_matching_codec);
// Handle global RTCP FB attributes
result->streams[i].rtcp_fb.generic_nack_enabled = rs->rtcp_fb.generic_nack_enabled;
result->streams[i].rtcp_fb.tmmbr_enabled = rs->rtcp_fb.tmmbr_enabled;
// Handle media RTCP XR attribute
memset(&result->streams[i].rtcp_xr, 0, sizeof(result->streams[i].rtcp_xr));
if (rs->rtcp_xr.enabled == TRUE) {

View file

@ -1445,7 +1445,7 @@ static LinphonePresenceModel * process_pidf_xml_presence_notification(xmlparsing
void linphone_core_add_subscriber(LinphoneCore *lc, const char *subscriber, SalOp *op){
LinphoneFriend *fl=linphone_friend_new_with_address(subscriber);
if (fl==NULL) return ;
fl->insub=op;
linphone_friend_add_incoming_subscription(fl, op);
linphone_friend_set_inc_subscribe_policy(fl,LinphoneSPAccept);
fl->inc_subscribe_pending=TRUE;
lc->subscribers=ms_list_append(lc->subscribers,(void *)fl);
@ -1468,9 +1468,7 @@ void linphone_core_notify_all_friends(LinphoneCore *lc, LinphonePresenceModel *p
if (activity_str != NULL) ms_free(activity_str);
for(elem=lc->friends;elem!=NULL;elem=elem->next){
LinphoneFriend *lf=(LinphoneFriend *)elem->data;
if (lf->insub){
linphone_friend_notify(lf,presence);
}
linphone_friend_notify(lf,presence);
}
}
@ -1478,26 +1476,15 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){
LinphoneFriend *lf=NULL;
char *tmp;
LinphoneAddress *uri;
LinphoneProxyConfig *cfg;
uri=linphone_address_new(from);
linphone_address_clean(uri);
tmp=linphone_address_as_string(uri);
ms_message("Receiving new subscription from %s.",from);
cfg=linphone_core_lookup_known_proxy(lc,uri);
if (cfg!=NULL){
if (cfg->op){
if (sal_op_get_contact_address(cfg->op)) {
sal_op_set_contact_address (op,sal_op_get_contact_address(cfg->op));
ms_message("Contact for next subscribe answer has been fixed using proxy "/*to %s",fixed_contact*/);
}
}
}
/* check if we answer to this subscription */
if (linphone_find_friend_by_address(lc->friends,uri,&lf)!=NULL){
lf->insub=op;
linphone_friend_add_incoming_subscription(lf, op);
lf->inc_subscribe_pending=TRUE;
sal_subscribe_accept(op);
linphone_friend_done(lf); /*this will do all necessary actions */
@ -1904,7 +1891,7 @@ void linphone_subscription_closed(LinphoneCore *lc, SalOp *op){
lf=linphone_find_friend_by_inc_subscribe(lc->friends,op);
sal_op_release(op);
if (lf!=NULL){
lf->insub=NULL;
linphone_friend_remove_incoming_subscription(lf, op);
}else{
ms_warning("Receiving unsuscribe for unknown in-subscribtion from %s", sal_op_get_from(op));
}

View file

@ -79,7 +79,7 @@ extern "C" {
#endif
#include <libintl.h>
#ifndef _
#define _(String) dgettext(GETTEXT_PACKAGE,String)
#endif
@ -312,8 +312,7 @@ struct _LinphoneCall{
bool_t record_active;
bool_t paused_by_app;
MSWebCam *cam; /*webcam use for this call*/
bool_t broken; /*set to TRUE when the call is in broken state due to network disconnection or transport */
};
BELLE_SIP_DECLARE_VPTR(LinphoneCall);
@ -358,6 +357,8 @@ const LinphoneAddress* linphone_proxy_config_get_service_route(const LinphonePro
void linphone_friend_close_subscriptions(LinphoneFriend *lf);
void linphone_friend_update_subscribes(LinphoneFriend *fr, LinphoneProxyConfig *cfg, bool_t only_when_registered);
void linphone_friend_notify(LinphoneFriend *lf, LinphonePresenceModel *presence);
void linphone_friend_add_incoming_subscription(LinphoneFriend *lf, SalOp *op);
void linphone_friend_remove_incoming_subscription(LinphoneFriend *lf, SalOp *op);
LinphoneFriend *linphone_find_friend_by_inc_subscribe(MSList *l, SalOp *op);
LinphoneFriend *linphone_find_friend_by_out_subscribe(MSList *l, SalOp *op);
MSList *linphone_find_friend_by_address(MSList *fl, const LinphoneAddress *addr, LinphoneFriend **lf);
@ -452,7 +453,7 @@ void linphone_call_fix_call_parameters(LinphoneCall *call);
void linphone_call_init_audio_stream(LinphoneCall *call);
void linphone_call_init_video_stream(LinphoneCall *call);
void linphone_call_init_media_streams(LinphoneCall *call);
void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone);
void linphone_call_start_media_streams(LinphoneCall *call, LinphoneCallState target_state);
void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call);
void linphone_call_stop_media_streams(LinphoneCall *call);
void linphone_call_delete_ice_session(LinphoneCall *call);
@ -590,7 +591,7 @@ struct _LinphoneFriend{
belle_sip_object_t base;
void *user_data;
LinphoneAddress *uri;
SalOp *insub;
MSList *insubs; /*list of SalOp. There can be multiple instances of a same Friend that subscribe to our presence*/
SalOp *outsub;
LinphoneSubscribePolicy pol;
LinphonePresenceModel *presence;
@ -761,6 +762,16 @@ const char *linphone_core_get_tone_file(const LinphoneCore *lc, LinphoneToneID i
int _linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params, LinphoneCallState next_state, const char *state_info);
typedef struct _LinphoneConference LinphoneConference;
typedef struct _LinphoneTaskList{
MSList *hooks;
}LinphoneTaskList;
void linphone_task_list_init(LinphoneTaskList *t);
void linphone_task_list_add(LinphoneTaskList *t, LinphoneCoreIterateHook hook, void *hook_data);
void linphone_task_list_remove(LinphoneTaskList *t, LinphoneCoreIterateHook hook, void *hook_data);
void linphone_task_list_run(LinphoneTaskList *t);
void linphone_task_list_free(LinphoneTaskList *t);
struct _LinphoneCore
{
MSList* vtable_refs;
@ -808,7 +819,7 @@ struct _LinphoneCore
void *preview_window_id;
time_t netup_time; /*time when network went reachable */
struct _EcCalibrator *ecc;
MSList *hooks;
LinphoneTaskList hooks; /*tasks periodically executed in linphone_core_iterate()*/
LinphoneConference conf_ctx;
char* zrtp_secrets_cache;
char* user_certificates_path;
@ -892,11 +903,11 @@ int linphone_core_set_as_current_call(LinphoneCore *lc, LinphoneCall *call);
int linphone_core_get_calls_nb(const LinphoneCore *lc);
void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message);
void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call);
void linphone_call_make_local_media_description(LinphoneCall *call);
void linphone_call_make_local_media_description_with_params(LinphoneCore *lc, LinphoneCall *call, LinphoneCallParams *params);
void linphone_call_increment_local_media_description(LinphoneCall *call);
void linphone_call_fill_media_multicast_addr(LinphoneCall *call);
void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md);
void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md, LinphoneCallState target_state);
bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, const PayloadType *pt, int bandwidth_limit);
@ -928,6 +939,8 @@ LinphoneEcCalibratorStatus ec_calibrator_get_status(EcCalibrator *ecc);
void ec_calibrator_destroy(EcCalibrator *ecc);
void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapsed);
void linphone_call_set_broken(LinphoneCall *call);
void linphone_call_repair_if_broken(LinphoneCall *call);
void linphone_core_preempt_sound_resources(LinphoneCore *lc);
int _linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call);
@ -1086,6 +1099,7 @@ struct _LinphoneAccountCreator {
char *route;
char *email;
bool_t subscribe_to_newsletter;
char *display_name;
};
BELLE_SIP_DECLARE_VPTR(LinphoneAccountCreator);

View file

@ -402,9 +402,10 @@ LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *cfg){
return ret;
}
void _linphone_proxy_config_unregister(LinphoneProxyConfig *cfg) {
if (cfg->op && cfg->state == LinphoneRegistrationOk) {
sal_unregister(cfg->op);
void _linphone_proxy_config_unregister(LinphoneProxyConfig *obj) {
if (obj->op && (obj->state == LinphoneRegistrationOk ||
(obj->state == LinphoneRegistrationProgress && obj->expires != 0))) {
sal_unregister(obj->op);
}
}
@ -1002,7 +1003,7 @@ LinphoneAddress* linphone_proxy_config_normalize_sip_uri(LinphoneProxyConfig *pr
char *tmpurl;
LinphoneAddress *uri;
if (*username=='\0') return NULL;
if (!username || *username=='\0') return NULL;
if (is_enum(username,&enum_domain)){
if (proxy) {
@ -1035,8 +1036,9 @@ LinphoneAddress* linphone_proxy_config_normalize_sip_uri(LinphoneProxyConfig *pr
}
if (proxy!=NULL){
/* append the proxy domain suffix */
/* append the proxy domain suffix but remove any custom parameters/headers */
LinphoneAddress *uri=linphone_address_clone(linphone_proxy_config_get_identity_address(proxy));
linphone_address_clean(uri);
if (uri==NULL){
return NULL;
} else {
@ -1489,6 +1491,13 @@ void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrat
LinphoneCore *lc=cfg->lc;
bool_t update_friends=FALSE;
if (state==LinphoneRegistrationProgress) {
char *msg=ortp_strdup_printf(_("Refreshing on %s..."), linphone_proxy_config_get_identity(cfg));
linphone_core_notify_display_status(lc,msg);
ms_free(msg);
}
if (cfg->state!=state || state==LinphoneRegistrationOk) { /*allow multiple notification of LinphoneRegistrationOk for refreshing*/
ms_message("Proxy config [%p] for identity [%s] moving from state [%s] to [%s]" , cfg,
linphone_proxy_config_get_identity(cfg),
@ -1503,8 +1512,13 @@ void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrat
if (update_friends){
linphone_core_update_friends_subscriptions(lc,cfg,TRUE);
}
if (lc)
if (lc){
linphone_core_notify_registration_state_changed(lc,cfg,state,message);
if (lc->calls && lp_config_get_int(lc->config, "sip", "repair_broken_calls", 1)){
/*if we are registered and there were broken calls due to a past network disconnection, attempt to repair them*/
ms_list_for_each(lc->calls, (MSIterateFunc) linphone_call_repair_if_broken);
}
}
} else {
/*state already reported*/
}

View file

@ -160,26 +160,27 @@ static bool_t is_null_address(const char *addr){
/*check for the presence of at least one stream with requested direction */
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->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)))
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))){
return TRUE;
}
}
return FALSE;
}
bool_t sal_media_description_has_dir(const SalMediaDescription *md, SalStreamDir stream_dir){
if (stream_dir==SalStreamRecvOnly){
if (has_dir(md,SalStreamSendOnly) || has_dir(md,SalStreamSendRecv)) return FALSE;
else return TRUE;
return has_dir(md, SalStreamRecvOnly) && !(has_dir(md,SalStreamSendOnly) || has_dir(md,SalStreamSendRecv));
}else if (stream_dir==SalStreamSendOnly){
if (has_dir(md,SalStreamRecvOnly) || has_dir(md,SalStreamSendRecv)) return FALSE;
else return TRUE;
return has_dir(md, SalStreamSendOnly) && !(has_dir(md,SalStreamRecvOnly) || has_dir(md,SalStreamSendRecv));
}else if (stream_dir==SalStreamSendRecv){
return has_dir(md,SalStreamSendRecv);
}else{

4
gtk/.directory Normal file
View file

@ -0,0 +1,4 @@
[Dolphin]
Timestamp=2015,8,9,21,25,40
Version=3
ViewMode=2

View file

@ -39,6 +39,11 @@ set(UI_FILES
sip_account.ui
tunnel_config.ui
waiting.ui
chatroom_frame.ui
in_call_frame.ui
conf_frame.ui
callee_frame.ui
login_frame.ui
)
set(PIXMAPS stock_people.png)
@ -92,6 +97,10 @@ if(ENABLE_NOTIFY)
target_link_libraries(linphone-gtk ${NOTIFY_LIBRARIES})
endif()
if (HAVE_LIBUDEV_H)
target_link_libraries(linphone-gtk udev)
endif()
install(TARGETS linphone-gtk
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib

View file

@ -15,7 +15,12 @@ UI_FILES= about.ui \
ldap.ui \
config-uri.ui \
provisioning-fetch.ui \
audio_assistant.ui
audio_assistant.ui \
chatroom_frame.ui \
in_call_frame.ui \
conf_frame.ui \
callee_frame.ui \
login_frame.ui
PIXMAPS= \
stock_people.png
@ -23,13 +28,12 @@ PIXMAPS= \
LINPHONE_ICO_RC_FILE=linphone.rc
LINPHONE_ICO_FILE=linphone.ico
EXTRA_DIST= $(PIXMAPS) \
$(UI_FILES) \
linphone.iss \
$(LINPHONE_ICO_RC_FILE) \
$(LINPHONE_ICO_FILE)
gtkrc \
gtkrc.mac
EXTRA_DIST= \
linphone.iss \
$(LINPHONE_ICO_RC_FILE) \
$(LINPHONE_ICO_FILE)
gtkrc \
gtkrc.mac
if BUILD_GTK_UI
@ -85,7 +89,7 @@ linphone_LDFLAGS=-export-dynamic
endif
uidir=$(datadir)/linphone
ui_DATA=$(UI_FILES) $(PIXMAPS) $(top_srcdir)/COPYING
dist_ui_DATA=$(UI_FILES) $(PIXMAPS) $(top_srcdir)/COPYING
endif

84
gtk/callee_frame.ui Normal file
View file

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="2.24"/>
<!-- interface-naming-policy project-wide -->
<object class="GtkFrame" id="callee_frame">
<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="alignment_conf">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="left_padding">12</property>
<child>
<object class="GtkAlignment" id="conf_alignment1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="left_padding">12</property>
<child>
<object class="GtkHBox" id="conf_hbox3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkHBox" id="conf_hbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkButton" id="conference_control">
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="callee_name_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;Callee name&lt;/b&gt;</property>
<property name="use_markup">True</property>
<property name="justify">right</property>
<property name="ellipsize">end</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkProgressBar" id="sound_indicator">
<property name="width_request">90</property>
<property name="height_request">30</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
<child type="label_item">
<placeholder/>
</child>
</object>
</interface>

View file

@ -282,8 +282,7 @@ void linphone_gtk_call_log_update(GtkWidget *w){
LinphoneFriend *lf=NULL;
int duration=linphone_call_log_get_duration(cl);
time_t start_date_time=linphone_call_log_get_start_date(cl);
GdkPixbuf *incoming;
GdkPixbuf *outgoing;
GdkPixbuf *pbuf;
#if GLIB_CHECK_VERSION(2,26,0)
if (start_date_time){
@ -348,14 +347,13 @@ void linphone_gtk_call_log_update(GtkWidget *w){
g_free(seconds);
if (start_date) g_free(start_date);
gtk_tree_store_append (store,&iter,NULL);
incoming = create_pixbuf("call_status_incoming.png");
outgoing = create_pixbuf("call_status_outgoing.png");
pbuf = linphone_call_log_get_dir(cl)==LinphoneCallOutgoing ? create_pixbuf("call_status_outgoing.png") : create_pixbuf("call_status_incoming.png");
gtk_tree_store_set (store,&iter,
0, linphone_call_log_get_dir(cl)==LinphoneCallOutgoing ? outgoing : incoming,
0, pbuf,
1, headtxt,2,cl,-1);
gtk_tree_store_append (store,&iter2,&iter);
gtk_tree_store_set (store,&iter2,1,logtxt,-1);
g_object_unref(pbuf);
ms_free(addr);
g_free(logtxt);
g_free(headtxt);

View file

@ -31,13 +31,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define CONFIG_FILE ".linphone-history.db"
const char *linphone_gtk_message_storage_get_db_file(const char *filename){
char *linphone_gtk_message_storage_get_db_file(const char *filename){
const int path_max=1024;
static char *db_file=NULL;
char *db_file=NULL;
if (db_file) return db_file;
db_file=(char *)malloc(path_max*sizeof(char));
db_file=(char *)g_malloc(path_max*sizeof(char));
if (filename==NULL) filename=CONFIG_FILE;
/*try accessing a local file first if exists*/
if (access(CONFIG_FILE,F_OK)==0){
@ -66,7 +64,6 @@ void linphone_gtk_quit_chatroom(LinphoneChatRoom *cr) {
GtkWidget *friendlist=linphone_gtk_get_widget(main_window,"contact_list");
GtkWidget *w=g_object_get_data(G_OBJECT(friendlist),"chatview");
gchar *from;
GHashTable *table=g_object_get_data(G_OBJECT(w),"table");
g_return_if_fail(w!=NULL);
gtk_notebook_remove_page(GTK_NOTEBOOK(nb),gtk_notebook_page_num(GTK_NOTEBOOK(nb),w));
@ -78,7 +75,6 @@ void linphone_gtk_quit_chatroom(LinphoneChatRoom *cr) {
g_object_set_data(G_OBJECT(w),"from_message",NULL);
g_free(from);
}
g_hash_table_destroy(table);
g_object_set_data(G_OBJECT(w),"cr",NULL);
linphone_gtk_friend_list_set_active_address(NULL);
gtk_widget_destroy(w);
@ -192,7 +188,7 @@ void linphone_gtk_push_text(GtkWidget *w, const LinphoneAddress *from,
int tnow_year;
gtk_text_buffer_get_end_iter(buffer, &iter);
if(g_strcmp0(from_message,from_str)!=0){
if (g_strcmp0(from_message,from_str)!=0){
gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, get_display_name(from), -1,
"from", me ? "me" : NULL, NULL);
gtk_text_buffer_insert_with_tags_by_name(buffer,&iter, " : ", -1,
@ -200,8 +196,8 @@ void linphone_gtk_push_text(GtkWidget *w, const LinphoneAddress *from,
gtk_text_buffer_insert(buffer,&iter,"\n",-1);
g_free(from_message);
g_object_set_data(G_OBJECT(w),"from_message",g_strdup(from_str));
ms_free(from_str);
}
ms_free(from_str);
link_start_mark = gtk_text_buffer_create_mark(buffer, NULL, &iter, TRUE);
gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, linphone_chat_message_get_text(msg), -1,
@ -217,7 +213,7 @@ void linphone_gtk_push_text(GtkWidget *w, const LinphoneAddress *from,
g_hash_table_insert(table,(gpointer)msg,GINT_TO_POINTER(gtk_text_iter_get_line(&iter)));
gtk_text_buffer_insert_with_tags_by_name(buffer,&iter,"Sending ..",-1,
"status", me ? "me" : NULL, NULL);
g_object_set_data(G_OBJECT(w),"table",table);
//g_object_set_data(G_OBJECT(w),"table",table);
break;
case LinphoneChatMessageStateDelivered:
tnow=time(NULL);
@ -295,7 +291,7 @@ void update_chat_state_message(LinphoneChatMessageState state,LinphoneChatMessag
}
gtk_text_buffer_insert_with_tags_by_name(b,&iter,result,-1,
"status", "me", NULL);
g_object_set_data(G_OBJECT(page),"table",table);
//g_object_set_data(G_OBJECT(page),"table",table);
}
}
@ -350,7 +346,7 @@ void linphone_gtk_free_list(MSList *messages){
}
void display_history_message(GtkWidget *chat_view,MSList *messages,const LinphoneAddress *with){
if(messages != NULL){
if (messages != NULL){
MSList *it;
char *from_str;
char *with_str;
@ -363,14 +359,15 @@ void display_history_message(GtkWidget *chat_view,MSList *messages,const Linphon
linphone_chat_message_get_from(msg),
strcmp(from_str,with_str)==0? FALSE : TRUE,
linphone_chat_message_get_chat_room(msg),msg,TRUE);
ms_free(from_str);
ms_free(with_str);
}
tmp=g_object_get_data(G_OBJECT(chat_view),"from_message");
if (tmp){
g_object_set_data(G_OBJECT(chat_view),"from_message",NULL);
g_free(tmp);
}
ms_free(from_str);
ms_free(with_str);
linphone_gtk_free_list(messages);
}
}
@ -411,12 +408,7 @@ static gboolean link_event_handler(GtkTextTag *tag, GObject *text_view,GdkEvent
gtk_text_iter_forward_to_tag_toggle(&uri_end, tag);
uri = gtk_text_iter_get_slice(&uri_begin, &uri_end);
if(((GdkEventButton *)event)->button == 1) {
GError *error = NULL;
gtk_show_uri(NULL, uri, gdk_event_get_time(event), &error);
if(error) {
g_warning("Could not open %s from chat: %s", uri, error->message);
g_error_free(error);
}
linphone_gtk_open_browser(uri);
} else if(((GdkEventButton *)event)->button == 3) {
GtkMenu *menu = GTK_MENU(g_object_get_data(text_view, "link_ctx_menu"));
g_object_set_data_full(G_OBJECT(menu), "uri", g_strdup(uri), g_free);
@ -481,7 +473,7 @@ static gboolean copy_uri_into_clipboard_handler(GtkMenuItem *menuitem, gpointer
}
GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddress *with){
GtkWidget *chat_view=linphone_gtk_create_widget("main","chatroom_frame");
GtkWidget *chat_view=linphone_gtk_create_widget("chatroom_frame");
GtkWidget *main_window=linphone_gtk_get_main_window();
GtkNotebook *notebook=(GtkNotebook *)linphone_gtk_get_widget(main_window,"viewswitch");
GtkWidget *text=linphone_gtk_get_widget(chat_view,"textview");
@ -493,12 +485,10 @@ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddres
GtkWidget *entry = linphone_gtk_get_widget(chat_view,"text_entry");
MSList *messages;
GHashTable *table;
char *with_str;
GtkTextTag *tmp_tag;
GtkWidget *link_ctx_menu = gtk_menu_new();
GtkWidget *link_ctx_menu_copy_item = gtk_menu_item_new_with_label(_("Copy"));
with_str=linphone_address_as_string_uri_only(with);
gtk_notebook_append_page(notebook,chat_view,create_tab_chat_header(cr,with));
idx = gtk_notebook_page_num(notebook, chat_view);
gtk_notebook_set_current_page(notebook, idx);
@ -506,7 +496,7 @@ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddres
table=g_hash_table_new_full(g_direct_hash,g_direct_equal,NULL,NULL);
g_object_set_data(G_OBJECT(chat_view),"cr",cr);
g_object_set_data(G_OBJECT(chat_view),"from_message",NULL);
g_object_set_data(G_OBJECT(chat_view),"table",table);
g_object_set_data_full(G_OBJECT(chat_view),"table",table,(GDestroyNotify)g_hash_table_destroy);
gtk_text_buffer_create_tag(
gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)),
@ -558,14 +548,11 @@ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddres
g_signal_connect_swapped(G_OBJECT(entry),"activate",(GCallback)linphone_gtk_send_text,NULL);
g_signal_connect_swapped(G_OBJECT(entry),"changed",(GCallback)linphone_gtk_compose_text,NULL);
g_signal_connect(G_OBJECT(notebook),"switch_page",(GCallback)linphone_gtk_notebook_tab_select,NULL);
ms_free(with_str);
return chat_view;
}
LinphoneChatRoom * linphone_gtk_create_chatroom(const LinphoneAddress *with){
char *tmp=linphone_address_as_string(with);
LinphoneChatRoom *cr=linphone_core_get_or_create_chat_room(linphone_gtk_get_core(),tmp);
ms_free(tmp);
LinphoneChatRoom *cr=linphone_core_get_chat_room(linphone_gtk_get_core(), with);
return cr;
}

113
gtk/chatroom_frame.ui Normal file
View file

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="2.18"/>
<!-- interface-naming-policy project-wide -->
<object class="GtkFrame" id="chatroom_frame">
<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="GtkVBox" id="vbox4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow3">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">never</property>
<child>
<object class="GtkTextView" id="textview">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="border_width">4</property>
<property name="editable">False</property>
<property name="wrap_mode">word-char</property>
<property name="cursor_visible">False</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkHBox" id="hbox10">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkEntry" id="text_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
<property name="invisible_char_set">True</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="send">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<child>
<object class="GtkHBox" id="hbox11">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImage" id="send_picture">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-ok</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</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">Send</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="padding">7</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</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">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<child type="label_item">
<placeholder/>
</child>
</object>
</interface>

86
gtk/conf_frame.ui Normal file
View file

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="2.24"/>
<!-- interface-naming-policy project-wide -->
<object class="GtkFrame" id="conf_frame">
<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="GtkVBox" id="conf_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkHButtonBox" id="button_conf">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkButton" id="terminate_conf">
<property name="label" translatable="yes">End conference</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkHBox" id="conf_record_hbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkToggleButton" id="conf_record_button">
<property name="label">gtk-media-record</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<signal name="toggled" handler="linphone_gtk_record_call_toggled" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="conf_record_status">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="wrap">True</property>
<property name="wrap_mode">char</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
</object>
</interface>

View file

@ -81,7 +81,7 @@ static GtkWidget *find_conferencee_from_call(LinphoneCall *call){
static GtkWidget * create_conference_panel(void){
GtkWidget *mw=linphone_gtk_get_main_window();
GtkWidget *conf_frame=linphone_gtk_create_widget("main","conf_frame");
GtkWidget *conf_frame=linphone_gtk_create_widget("conf_frame");
GtkWidget *conf_box=linphone_gtk_get_widget(conf_frame,"conf_box");
GtkWidget *button_conf=linphone_gtk_get_widget(conf_frame,"terminate_conf");
GtkWidget *image=create_pixmap("stopcall-small.png");
@ -94,7 +94,7 @@ static GtkWidget * create_conference_panel(void){
g_object_set_data(G_OBJECT(mw),"conf_frame",(gpointer)conf_frame);
box=gtk_vbox_new(FALSE,0);
participant=linphone_gtk_create_widget("main","callee_frame");
participant=linphone_gtk_create_widget("callee_frame");
gtk_widget_show(participant);
gtk_box_set_homogeneous(GTK_BOX(box),TRUE);
init_local_participant(participant);
@ -126,7 +126,7 @@ void linphone_gtk_set_in_conference(LinphoneCall *call){
const LinphoneAddress *addr=linphone_call_get_remote_address(call);
gchar *markup;
participant=linphone_gtk_create_widget("main","callee_frame");
participant=linphone_gtk_create_widget("callee_frame");
gtk_widget_show(participant);
if (linphone_address_get_display_name(addr)!=NULL){
markup=g_strdup_printf("<b>%s</b>",linphone_address_get_display_name(addr));

View file

@ -243,20 +243,23 @@ void linphone_gtk_friend_list_update_chat_picture(){
int nbmsg=0;
if (gtk_tree_model_get_iter_first(model,&iter)) {
do{
GdkPixbuf *pbuf = NULL;
gtk_tree_model_get (model, &iter,FRIEND_CHATROOM , &cr, -1);
nbmsg=linphone_chat_room_get_unread_messages_count(cr);
is_composing=linphone_chat_room_is_remote_composing(cr);
if(nbmsg != 0){
if (is_composing == TRUE)
gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_composing_unread_msg(),-1);
pbuf = create_composing_unread_msg();
else
gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_unread_msg(),-1);
pbuf = create_unread_msg();
} else {
if (is_composing == TRUE)
gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_composing_chat_picture(),-1);
pbuf = create_composing_chat_picture();
else
gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_chat_picture(),-1);
pbuf = create_chat_picture();
}
gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,pbuf,-1);
if (pbuf) g_object_unref(pbuf);
}while(gtk_tree_model_iter_next(model,&iter));
}
}
@ -269,9 +272,7 @@ static gboolean grab_focus(GtkWidget *w){
void linphone_gtk_friend_list_set_active_address(const LinphoneAddress *addr){
GtkWidget *w=linphone_gtk_get_main_window();
GtkWidget *friendlist=linphone_gtk_get_widget(w,"contact_list");
LinphoneAddress *old_addr=(LinphoneAddress*)g_object_get_data(G_OBJECT(friendlist),"from");
g_object_set_data(G_OBJECT(friendlist),"from", addr ? linphone_address_clone(addr) : NULL);
if (old_addr) linphone_address_unref(old_addr);
g_object_set_data_full(G_OBJECT(friendlist),"from", addr ? linphone_address_clone(addr) : NULL, (GDestroyNotify)linphone_address_destroy);
}
const LinphoneAddress *linphone_gtk_friend_list_get_active_address(void){
@ -831,6 +832,7 @@ void linphone_gtk_show_friends(void){
char *escaped=NULL;
//char buf[26]={0};
int nbmsg=0;
GdkPixbuf *pbuf, *pbuf2, *pbuf3;
/*if (lookup){
if (strstr(uri,search)==NULL){
@ -844,14 +846,22 @@ void linphone_gtk_show_friends(void){
display=linphone_address_get_username(f_uri);
}
gtk_list_store_append(store,&iter);
pbuf = create_chat_picture();
pbuf2 = create_call_picture();
pbuf3 = send_subscribe ? create_status_picture(linphone_friend_get_status(lf)) : NULL;
gtk_list_store_set(store,&iter,FRIEND_NAME, display,FRIEND_ID,lf,
FRIEND_PRESENCE_IMG, send_subscribe ? create_status_picture(linphone_friend_get_status(lf)) : NULL,
FRIEND_CHAT,create_chat_picture(),FRIEND_CALL,create_call_picture(),-1);
FRIEND_PRESENCE_IMG, pbuf3,
FRIEND_CHAT,pbuf,FRIEND_CALL,pbuf2,-1);
g_object_unref(pbuf);
g_object_unref(pbuf2);
if (pbuf3) g_object_unref(pbuf3);
cr=linphone_gtk_create_chatroom(f_uri);
gtk_list_store_set(store,&iter,FRIEND_CHATROOM,cr,-1);
nbmsg=linphone_chat_room_get_unread_messages_count(cr);
if(nbmsg != 0){
gtk_list_store_set(store,&iter,FRIEND_CHAT,create_unread_msg(),-1);
pbuf = create_unread_msg();
gtk_list_store_set(store,&iter,FRIEND_CHAT,pbuf,-1);
g_object_unref(pbuf);
}
escaped=g_markup_escape_text(uri,-1);
gtk_list_store_set(store,&iter,FRIEND_SIP_ADDRESS,escaped,-1);

426
gtk/in_call_frame.ui Normal file
View file

@ -0,0 +1,426 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="2.24"/>
<!-- interface-naming-policy project-wide -->
<object class="GtkFrame" id="in_call_frame">
<property name="can_focus">False</property>
<property name="extension_events">cursor</property>
<property name="label_xalign">0.5</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>
<property name="right_padding">12</property>
<child>
<object class="GtkVBox" id="vbox3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel" id="in_call_uri">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="justify">center</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkVBox" id="in_call_animation">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkHBox" id="encryption_box">
<property name="can_focus">False</property>
<child>
<object class="GtkImage" id="dialog_authenticator_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-dialog-authentication</property>
<property name="icon-size">1</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkImage" id="encryption_status_icon">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-apply</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="encryption_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="padding">2</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="encryption_verify_button">
<property name="label" translatable="yes">Set verified</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="linphone_gtk_auth_token_verified_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkHBox" id="incall_audioview">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkHBox" id="incall_mic_vol_control">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkVolumeButton" id="incall_mic_vol_ctrl_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="has_tooltip">True</property>
<property name="relief">none</property>
<property name="focus_on_click">False</property>
<property name="orientation">vertical</property>
<property name="icons">linphone-micro-enabled</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="padding">5</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkProgressBar" id="mic_audiolevel">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="padding">5</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">False</property>
<property name="padding">10</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkHBox" id="incall_spk_vol_control">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkVolumeButton" id="incall_spk_vol_ctrl_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Click here to set the speakers volume</property>
<property name="relief">none</property>
<property name="focus_on_click">False</property>
<property name="orientation">vertical</property>
<property name="icons">linphone-speaker-enabled</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="padding">5</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkProgressBar" id="spk_audiolevel">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="padding">5</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">False</property>
<property name="padding">10</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="padding">5</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkHButtonBox" id="answer_decline_panel">
<property name="can_focus">False</property>
<property name="layout_style">spread</property>
<child>
<object class="GtkButton" id="accept_call">
<property name="label" translatable="yes">Answer</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="linphone_gtk_answer_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="decline_call">
<property name="label" translatable="yes">Decline</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="linphone_gtk_decline_clicked" swapped="no"/>
</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">False</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkHBox" id="record_hbox">
<property name="can_focus">False</property>
<child>
<object class="GtkToggleButton" id="record_button">
<property name="label">gtk-media-record</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Record this call to an audio file</property>
<property name="use_stock">True</property>
<signal name="toggled" handler="linphone_gtk_record_call_toggled" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="record_status">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="wrap">True</property>
<property name="wrap_mode">char</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">5</property>
</packing>
</child>
<child>
<object class="GtkTable" id="buttons_panel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="n_rows">2</property>
<property name="n_columns">3</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkButton" id="video_button">
<property name="label" translatable="yes">Video</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
</child>
<child>
<object class="GtkButton" id="hold_call">
<property name="label" translatable="yes">Pause</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="linphone_gtk_hold_clicked" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="incall_mute">
<property name="label" translatable="yes">Mute</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="linphone_gtk_mute_clicked" swapped="no"/>
</object>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
</packing>
</child>
<child>
<object class="GtkButton" id="transfer_button">
<property name="label" translatable="yes">Transfer</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="terminate_call">
<property name="label" translatable="yes">Hang up</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="linphone_gtk_terminate_call" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="conference_button">
<property name="label" translatable="yes">Conference</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="padding">7</property>
<property name="position">6</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkHBox" id="heading_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkLabel" id="in_call_status">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">In call</property>
<property name="use_markup">True</property>
<property name="justify">center</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="in_call_duration">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Duration</property>
<property name="justify">center</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkProgressBar" id="quality_indicator">
<property name="width_request">90</property>
<property name="height_request">10</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
<property name="tooltip_text" translatable="yes">Call quality rating</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

View file

@ -361,7 +361,7 @@ void linphone_gtk_enable_video_button(LinphoneCall *call, gboolean sensitive, gb
}
void linphone_gtk_create_in_call_view(LinphoneCall *call){
GtkWidget *call_view=linphone_gtk_create_widget("main","in_call_frame");
GtkWidget *call_view=linphone_gtk_create_widget("in_call_frame");
GtkWidget *main_window=linphone_gtk_get_main_window ();
GtkNotebook *notebook=(GtkNotebook *)linphone_gtk_get_widget(main_window,"viewswitch");
static int call_index=1;
@ -510,7 +510,7 @@ void linphone_gtk_in_call_view_set_calling(LinphoneCall *call){
gtk_label_set_markup(GTK_LABEL(status),_("<b>Calling...</b>"));
display_peer_name_in_label(callee,linphone_call_get_remote_address (call));
gtk_label_set_text(GTK_LABEL(duration),_("00::00::00"));
gtk_label_set_text(GTK_LABEL(duration),_("00:00:00"));
linphone_gtk_in_call_set_animation_spinner(callview);
}
@ -607,10 +607,12 @@ static gboolean update_audio_meter(volume_ctx_t *ctx){
return TRUE;
}
static void on_audio_meter_destroy(guint task_id){
static void on_audio_meter_destroy(GtkWidget *w, gpointer data){
guint task_id = GPOINTER_TO_INT(data);
g_source_remove(task_id);
}
void linphone_gtk_init_audio_meter(GtkWidget *w, get_volume_t get_volume, void *data){
guint task_id=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"task_id"));
if (task_id==0){
@ -621,7 +623,8 @@ void linphone_gtk_init_audio_meter(GtkWidget *w, get_volume_t get_volume, void *
ctx->last_value=0;
g_object_set_data_full(G_OBJECT(w),"ctx",ctx,g_free);
task_id=g_timeout_add(50,(GSourceFunc)update_audio_meter,ctx);
g_object_set_data_full(G_OBJECT(w),"task_id",GINT_TO_POINTER(task_id),(GDestroyNotify)on_audio_meter_destroy);
g_object_set_data(G_OBJECT(w), "task_id", GINT_TO_POINTER(task_id));
g_signal_connect(G_OBJECT(w), "destroy", (GCallback)on_audio_meter_destroy, GINT_TO_POINTER(task_id));
}
}
@ -630,6 +633,7 @@ void linphone_gtk_uninit_audio_meter(GtkWidget *w){
if (task_id!=0){
g_object_set_data(G_OBJECT(w),"ctx",NULL);
g_object_set_data(G_OBJECT(w),"task_id",NULL);
g_source_remove(task_id);
}
}
@ -637,25 +641,35 @@ typedef enum { VOLUME_CTRL_PLAYBACK, VOLUME_CTRL_RECORD } VolumeControlType;
static void volume_control_value_changed(GtkScaleButton *button, gdouble value, gpointer user_data) {
LinphoneCall *call = (LinphoneCall *)g_object_get_data(G_OBJECT(button), "call");
VolumeControlType method = (VolumeControlType)g_object_get_data(G_OBJECT(button), "method");
VolumeControlType type = (VolumeControlType)g_object_get_data(G_OBJECT(button), "type");
if(method == VOLUME_CTRL_PLAYBACK) {
linphone_call_set_play_percent_volume(call, value);
} else if(method == VOLUME_CTRL_RECORD) {
linphone_call_set_record_percent_volume(call, value);
if(type == VOLUME_CTRL_PLAYBACK) {
linphone_call_set_speaker_volume_gain(call, value);
} else if(type == VOLUME_CTRL_RECORD) {
linphone_call_set_microphone_volume_gain(call, value);
}
}
static void volume_control_button_update_value(GtkWidget *widget) {
LinphoneCall *call = (LinphoneCall *)g_object_get_data(G_OBJECT(widget), "call");
VolumeControlType type = (VolumeControlType)g_object_get_data(G_OBJECT(widget), "type");
if(type == VOLUME_CTRL_PLAYBACK) {
gtk_scale_button_set_value(GTK_SCALE_BUTTON(widget), linphone_call_get_speaker_volume_gain(call));
} else if(type == VOLUME_CTRL_RECORD) {
gtk_scale_button_set_value(GTK_SCALE_BUTTON(widget), linphone_call_get_microphone_volume_gain(call));
}
}
static gboolean volume_control_button_enter_event_handler(GtkWidget *widget) {
volume_control_button_update_value(widget);
return FALSE;
}
static void volume_control_init(GtkWidget *vol_ctrl, VolumeControlType type, LinphoneCall *call) {
g_object_set_data(G_OBJECT(vol_ctrl), "call", call);
g_object_set_data(G_OBJECT(vol_ctrl), "type", (gpointer)type);
if(type == VOLUME_CTRL_PLAYBACK) {
gtk_scale_button_set_value(GTK_SCALE_BUTTON(vol_ctrl), linphone_call_get_play_volume(call));
} else if(type == VOLUME_CTRL_RECORD) {
gtk_scale_button_set_value(GTK_SCALE_BUTTON(vol_ctrl), linphone_call_get_record_percent_volume(call));
}
g_signal_connect(G_OBJECT(vol_ctrl), "enter-notify-event", G_CALLBACK(volume_control_button_enter_event_handler), NULL);
g_signal_connect(G_OBJECT(vol_ctrl), "value-changed", G_CALLBACK(volume_control_value_changed), NULL);
}
@ -750,7 +764,7 @@ void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){
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);
gtk_label_set_text(GTK_LABEL(duration),_("00::00::00"));
gtk_label_set_text(GTK_LABEL(duration),_("00:00:00"));
linphone_gtk_in_call_set_animation_image(callview,GTK_STOCK_MEDIA_PLAY,TRUE);
linphone_gtk_call_update_tab_header(call,FALSE);
linphone_gtk_enable_mute_button(
@ -864,22 +878,11 @@ void linphone_gtk_in_call_view_set_transfer_status(LinphoneCall *call,LinphoneCa
}
void linphone_gtk_draw_mute_button(GtkButton *button, gboolean active){
const char *icon_name = active ? "linphone-micro-muted" : "linphone-micro-enabled";
GtkWidget *image = gtk_image_new_from_icon_name(icon_name, GTK_ICON_SIZE_BUTTON);
gtk_button_set_image(button, image);
gtk_widget_show(image);
g_object_set_data(G_OBJECT(button),"active",GINT_TO_POINTER(active));
if (active){
GtkWidget *image=create_pixmap("mic_muted.png");
/*gtk_button_set_label(GTK_BUTTON(button),_("Unmute"));*/
if (image!=NULL) {
gtk_button_set_image(GTK_BUTTON(button),image);
gtk_widget_show(image);
}
}else{
GtkWidget *image=create_pixmap("mic_active.png");
/*gtk_button_set_label(GTK_BUTTON(button),_("Mute"));*/
if (image!=NULL) {
gtk_button_set_image(GTK_BUTTON(button),image);
gtk_widget_show(image);
}
}
}
void linphone_gtk_mute_clicked(GtkButton *button){

View file

@ -98,16 +98,15 @@ GdkPixbuf *_gdk_pixbuf_new_from_memory_at_scale(const void *data, gint len, gint
LINPHONE_PUBLIC void linphone_gtk_destroy_window(GtkWidget *window);
LINPHONE_PUBLIC GtkWidget *linphone_gtk_create_window(const char *window_name, GtkWidget *parent);
LINPHONE_PUBLIC GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name);
LINPHONE_PUBLIC GtkWidget *linphone_gtk_create_widget(const char *filename, const char *widget_name);
LINPHONE_PUBLIC GtkWidget *linphone_gtk_create_widget(const char* widget_name);
const char *linphone_gtk_message_storage_get_db_file(const char *filename);
char *linphone_gtk_message_storage_get_db_file(const char *filename);
LINPHONE_PUBLIC void linphone_gtk_show_assistant(GtkWidget* parent);
LINPHONE_PUBLIC void linphone_gtk_close_assistant(void);
LINPHONE_PUBLIC LinphoneCore *linphone_gtk_get_core(void);
LINPHONE_PUBLIC GtkWidget *linphone_gtk_get_main_window();
LINPHONE_PUBLIC void linphone_gtk_display_something(GtkMessageType type, const gchar *message);
LINPHONE_PUBLIC void linphone_gtk_start_call(GtkWidget *button);
LINPHONE_PUBLIC void linphone_gtk_call_terminated();
LINPHONE_PUBLIC void linphone_gtk_set_my_presence(LinphoneOnlineStatus ss);
LINPHONE_PUBLIC void linphone_gtk_show_parameters(void);
@ -213,7 +212,7 @@ LINPHONE_PUBLIC void linphone_gtk_in_call_show_video(LinphoneCall *call);
LINPHONE_PUBLIC char *linphone_gtk_address(const LinphoneAddress *addr);/*return human readable identifier for a LinphoneAddress */
LINPHONE_PUBLIC GtkWidget *linphone_gtk_get_camera_preview_window(void);
LINPHONE_PUBLIC void linphone_gtk_login_frame_connect_clicked(GtkWidget *button);
LINPHONE_PUBLIC void linphone_gtk_login_frame_connect_clicked(GtkWidget *button, GtkWidget *login_frame);
LINPHONE_PUBLIC gboolean linphone_gtk_call_log_reset_missed_call(GtkWidget *w, GdkEvent *event, gpointer user_data);
LINPHONE_PUBLIC void linphone_gtk_history_row_activated(GtkWidget *treeview);
@ -240,6 +239,7 @@ LINPHONE_PUBLIC void linphone_gtk_logout_clicked(void);
LINPHONE_PUBLIC void linphone_gtk_about_response(GtkDialog *dialog, gint id);
LINPHONE_PUBLIC void linphone_gtk_show_about(void);
LINPHONE_PUBLIC void linphone_gtk_start_call(GtkWidget *w);
LINPHONE_PUBLIC void linphone_gtk_start_chat(GtkWidget *w);
LINPHONE_PUBLIC void linphone_gtk_uri_bar_activate(GtkWidget *w);
LINPHONE_PUBLIC void linphone_gtk_terminate_call(GtkWidget *button);
LINPHONE_PUBLIC void linphone_gtk_decline_clicked(GtkWidget *button);
@ -307,6 +307,7 @@ LINPHONE_PUBLIC void linphone_gtk_video_preset_changed(GtkWidget *w);
LINPHONE_PUBLIC void linphone_gtk_show_camera_preview_clicked(GtkButton *button);
LINPHONE_PUBLIC void linphone_gtk_update_my_contact(GtkWidget *w);
LINPHONE_PUBLIC void linphone_gtk_add_proxy(GtkButton *button);
LINPHONE_PUBLIC void linphone_gtk_show_sip_accounts(GtkWidget *w);
LINPHONE_PUBLIC void linphone_gtk_edit_proxy(GtkButton *button);
LINPHONE_PUBLIC void linphone_gtk_remove_proxy(GtkButton *button);
LINPHONE_PUBLIC void linphone_gtk_clear_passwords(GtkWidget *button);
@ -333,3 +334,6 @@ LINPHONE_PUBLIC void linphone_gtk_proxy_cancel(GtkButton *button);
LINPHONE_PUBLIC void linphone_gtk_proxy_address_changed(GtkEditable *editable);
LINPHONE_PUBLIC void linphone_gtk_proxy_transport_changed(GtkWidget *combo);
LINPHONE_PUBLIC void linphone_gtk_tunnel_ok(GtkButton *button);
LINPHONE_PUBLIC void linphone_gtk_notebook_current_page_changed(GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer user_data);
LINPHONE_PUBLIC void linphone_gtk_reload_sound_devices(void);
LINPHONE_PUBLIC void linphone_gtk_reload_video_devices(void);

250
gtk/login_frame.ui Normal file
View file

@ -0,0 +1,250 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="2.24"/>
<!-- interface-naming-policy project-wide -->
<object class="GtkFrame" id="login_frame">
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">etched-out</property>
<child>
<object class="GtkAlignment" id="alignment2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="left_padding">12</property>
<child>
<object class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImage" id="login_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-missing-image</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="frame5">
<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="alignment3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="left_padding">12</property>
<property name="right_padding">12</property>
<child>
<object class="GtkTable" id="table1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="n_rows">5</property>
<property name="n_columns">2</property>
<child>
<placeholder/>
</child>
<child>
<object class="GtkLabel" id="label8">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Username</property>
</object>
</child>
<child>
<object class="GtkLabel" id="label10">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Password</property>
</object>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label13">
<property name="can_focus">False</property>
<property name="label" translatable="yes">Internet connection:</property>
</object>
<packing>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="login_username">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">●</property>
<property name="invisible_char_set">True</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="login_password">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="visibility">False</property>
<property name="invisible_char">●</property>
<property name="invisible_char_set">True</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<object class="GtkComboBox" id="login_internet_kind">
<property name="can_focus">False</property>
<property name="active">0</property>
<child>
<object class="GtkCellRendererText" id="renderer4"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</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="GtkCheckButton" id="automatic_login">
<property name="label" translatable="yes">Automatically log me in</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="userid">
<property name="can_focus">False</property>
<property name="label" translatable="yes">UserID</property>
</object>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="login_userid">
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
<property name="invisible_char_set">True</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="login_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Login information</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="padding">10</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkHButtonBox" id="hbuttonbox3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkButton" id="login_connect">
<property name="label">gtk-connect</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="linphone_gtk_login_frame_connect_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label6">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;Welcome!&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<object class="GtkListStore" id="model4">
<columns>
<!-- column-name gchararray -->
<column type="gchararray"/>
</columns>
<data>
<row>
<col id="0" translatable="yes">ADSL</col>
</row>
<row>
<col id="0" translatable="yes">Fiber Channel</col>
</row>
</data>
</object>
</interface>

View file

@ -48,47 +48,35 @@ static gboolean do_login_noprompt(LinphoneProxyConfig *cfg){
return FALSE;
}
void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg, gboolean disable_auto_login){
GtkWidget *mw=linphone_gtk_get_main_window();
GtkWidget *label=linphone_gtk_get_widget(mw,"login_label");
const LinphoneAuthInfo *ai;
static void linphone_gtk_init_login_frame(GtkWidget *login_frame, LinphoneProxyConfig *cfg) {
gboolean auto_login=linphone_gtk_get_ui_config_int("automatic_login",0);
const char *login_image=linphone_gtk_get_ui_config("login_image","linphone-banner.png");
GtkWidget *label=linphone_gtk_get_widget(login_frame,"login_label");
LinphoneCore *lc=linphone_gtk_get_core();
gchar *str;
LinphoneAddress *from;
LinphoneCore *lc=linphone_gtk_get_core();
const LinphoneAuthInfo *ai;
const char *passwd=NULL;
const char *userid=NULL;
gboolean auto_login=linphone_gtk_get_ui_config_int("automatic_login",0);
if (auto_login && !disable_auto_login){
g_timeout_add(250,(GSourceFunc)do_login_noprompt,cfg);
return;
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(login_frame, "automatic_login")),auto_login);
if (login_image){
GdkPixbuf *pbuf=create_pixbuf (login_image);
gtk_image_set_from_pixbuf (GTK_IMAGE(linphone_gtk_get_widget(login_frame, "login_image")), pbuf);
g_object_unref(G_OBJECT(pbuf));
}
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(mw,"automatic_login")),auto_login);
{
const char *login_image=linphone_gtk_get_ui_config("login_image","linphone-banner.png");
if (login_image){
GdkPixbuf *pbuf=create_pixbuf (login_image);
gtk_image_set_from_pixbuf (GTK_IMAGE(linphone_gtk_get_widget(mw,"login_image")),
pbuf);
g_object_unref(G_OBJECT(pbuf));
}
}
gtk_widget_hide(linphone_gtk_get_widget(mw,"disconnect_item"));
gtk_widget_hide(linphone_gtk_get_widget(mw,"main_frame"));
gtk_widget_show(linphone_gtk_get_widget(mw,"login_frame"));
if (linphone_gtk_get_ui_config_int("login_needs_userid",FALSE)){
gtk_widget_show(linphone_gtk_get_widget(mw,"userid"));
gtk_widget_show(linphone_gtk_get_widget(mw,"login_userid"));
gtk_widget_show(linphone_gtk_get_widget(login_frame,"userid"));
gtk_widget_show(linphone_gtk_get_widget(login_frame,"login_userid"));
}
gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"options_menu"),FALSE);
str=g_strdup_printf(_("Please enter login information for %s"),linphone_proxy_config_get_domain(cfg));
gtk_label_set_text(GTK_LABEL(label),str);
g_object_set_data(G_OBJECT(mw),"login_proxy_config",cfg);
g_object_set_data(G_OBJECT(login_frame),"login_proxy_config",cfg);
g_free(str);
from=linphone_address_new(linphone_proxy_config_get_identity(cfg));
if (linphone_address_get_username(from)[0]=='?'){
const char *username=linphone_gtk_get_ui_config ("login_username",NULL);
@ -99,24 +87,55 @@ void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg, gboolean disable_au
ai=linphone_core_find_auth_info(lc,linphone_proxy_config_get_domain(cfg),linphone_address_get_username(from),NULL);
/*display the last entered username, if not '?????'*/
if (linphone_address_get_username(from)[0]!='?')
gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(mw,"login_username")),
gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(login_frame,"login_username")),
linphone_address_get_username(from));
if (ai) {
passwd=linphone_auth_info_get_passwd(ai);
userid=linphone_auth_info_get_userid(ai);
}
gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(mw,"login_password")),
gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(login_frame,"login_password")),
passwd!=NULL ? passwd : "");
gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(mw,"login_userid")),
gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(login_frame,"login_userid")),
userid ? userid : "");
linphone_address_destroy(from);
}
void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg, gboolean disable_auto_login){
GtkWidget *mw=linphone_gtk_get_main_window();
gboolean auto_login=linphone_gtk_get_ui_config_int("automatic_login",0);
GtkWidget *main_frame = linphone_gtk_get_widget(mw, "main_frame");
GtkWidget *main_layout = linphone_gtk_get_widget(mw, "main_layout");
GtkWidget *login_frame;
if (auto_login && !disable_auto_login){
g_timeout_add(250,(GSourceFunc)do_login_noprompt,cfg);
return;
}
login_frame = linphone_gtk_create_widget("login_frame");
linphone_gtk_init_login_frame(login_frame, cfg);
g_object_set_data_full(G_OBJECT(mw), "main_frame", g_object_ref(main_frame), g_object_unref);
g_object_set_data(G_OBJECT(mw), "login_frame", login_frame);
gtk_container_remove(GTK_CONTAINER(main_layout), main_frame);
gtk_box_pack_start(GTK_BOX(main_layout), login_frame, TRUE, TRUE, 0);
gtk_widget_show(login_frame);
gtk_widget_hide(linphone_gtk_get_widget(mw,"disconnect_item"));
gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"options_menu"),FALSE);
}
void linphone_gtk_exit_login_frame(void){
GtkWidget *mw=linphone_gtk_get_main_window();
gtk_widget_show(linphone_gtk_get_widget(mw,"main_frame"));
gtk_widget_hide(linphone_gtk_get_widget(mw,"login_frame"));
GtkWidget *main_layout = linphone_gtk_get_widget(mw, "main_layout");
GtkWidget *main_frame = GTK_WIDGET(g_object_get_data(G_OBJECT(mw), "main_frame"));
GtkWidget *login_frame = GTK_WIDGET(g_object_get_data(G_OBJECT(mw), "login_frame"));
gtk_container_remove(GTK_CONTAINER(main_layout), login_frame);
gtk_box_pack_start(GTK_BOX(main_layout), main_frame, TRUE, TRUE, 0);
g_object_set_data(G_OBJECT(mw), "login_frame", NULL);
g_object_set_data(G_OBJECT(mw), "main_frame", NULL);
gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"options_menu"),TRUE);
gtk_widget_show(linphone_gtk_get_widget(mw,"disconnect_item"));
}
@ -136,25 +155,24 @@ void linphone_gtk_logout_clicked(void){
void linphone_gtk_login_frame_connect_clicked(GtkWidget *button){
GtkWidget *mw=gtk_widget_get_toplevel(button);
void linphone_gtk_login_frame_connect_clicked(GtkWidget *button, GtkWidget *login_frame){
const char *username;
const char *password;
const char *userid;
char *identity;
gboolean autologin;
LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)g_object_get_data(G_OBJECT(mw),"login_proxy_config");
LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)g_object_get_data(G_OBJECT(login_frame),"login_proxy_config");
LinphoneAddress *from;
SipSetupContext *ssctx=linphone_proxy_config_get_sip_setup_context(cfg);
username=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(mw,"login_username")));
password=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(mw,"login_password")));
userid=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(mw,"login_userid")));
username=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(login_frame,"login_username")));
password=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(login_frame,"login_password")));
userid=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(login_frame,"login_userid")));
if (username==NULL || username[0]=='\0')
return;
autologin=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(mw,"automatic_login")));
autologin=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(login_frame,"automatic_login")));
linphone_gtk_set_ui_config_int("automatic_login",autologin);
linphone_gtk_set_ui_config("login_username",username);

View file

@ -191,10 +191,10 @@ char *linphone_gtk_get_config_file(const char *filename){
#define FACTORY_CONFIG_FILE "linphonerc.factory"
static char _factory_config_file[1024];
static const char *linphone_gtk_get_factory_config_file(){
char* path = NULL;
/*try accessing a local file first if exists*/
if (access(FACTORY_CONFIG_FILE,F_OK)==0){
snprintf(_factory_config_file,sizeof(_factory_config_file),
"%s",FACTORY_CONFIG_FILE);
path = ms_strdup(FACTORY_CONFIG_FILE);
} else {
char *progdir;
@ -206,33 +206,31 @@ static const char *linphone_gtk_get_factory_config_file(){
if (basename != NULL) {
basename ++;
*basename = '\0';
snprintf(_factory_config_file, sizeof(_factory_config_file),
"%s\\..\\%s", progdir, FACTORY_CONFIG_FILE);
} else {
if (workingdir!=NULL) {
snprintf(_factory_config_file, sizeof(_factory_config_file),
"%s\\%s", workingdir, FACTORY_CONFIG_FILE);
} else {
free(progdir);
return NULL;
}
path = ms_strdup_printf("%s\\..\\%s", progdir, FACTORY_CONFIG_FILE);
} else if (workingdir!=NULL) {
path = ms_strdup_printf("%s\\%s", workingdir, FACTORY_CONFIG_FILE);
}
#else
basename = strrchr(progdir, '/');
if (basename != NULL) {
basename ++;
*basename = '\0';
snprintf(_factory_config_file, sizeof(_factory_config_file),
"%s/../share/linphone/%s", progdir, FACTORY_CONFIG_FILE);
} else {
free(progdir);
return NULL;
path = ms_strdup_printf("%s/../share/linphone/%s", progdir, FACTORY_CONFIG_FILE);
}
#endif
free(progdir);
}
}
return _factory_config_file;
if (path) {
//use factory file only if it exists
if (access(path,F_OK)==0){
snprintf(_factory_config_file, sizeof(_factory_config_file), "%s", path);
ms_free(path);
return _factory_config_file;
}
ms_free(path);
}
return NULL;
}
LinphoneLDAPContactProvider* linphone_gtk_get_ldap(void){
@ -379,67 +377,47 @@ void linphone_gtk_destroy_window(GtkWidget *widget) {
g_object_unref (G_OBJECT (builder));
}
GtkWidget *linphone_gtk_create_window(const char *window_name, GtkWidget *parent){
GError* error = NULL;
GtkBuilder* builder = gtk_builder_new ();
char path[512];
GtkWidget *w;
GtkWidget *linphone_gtk_create_widget(const char *widget_name) {
char path[2048];
GtkBuilder *builder = gtk_builder_new();
GError *error = NULL;
GObject *obj;
if (get_ui_file(window_name,path,sizeof(path))==-1) return NULL;
if(get_ui_file(widget_name, path, sizeof(path)) == -1) goto fail;
gtk_builder_set_translation_domain(builder,GETTEXT_PACKAGE);
gtk_builder_set_translation_domain(builder, GETTEXT_PACKAGE);
if (!gtk_builder_add_from_file (builder, path, &error)){
if(gtk_builder_add_from_file(builder, path, &error) == 0) {
g_error("Couldn't load builder file: %s", error->message);
g_error_free (error);
return NULL;
g_error_free(error);
goto fail;
}
w=GTK_WIDGET(gtk_builder_get_object (builder,window_name));
if (w==NULL){
g_error("Could not retrieve '%s' window from xml file",window_name);
return NULL;
obj = gtk_builder_get_object(builder, widget_name);
if(obj == NULL) {
g_error("'%s' widget not found", widget_name);
goto fail;
}
g_object_set_data(G_OBJECT(w), "builder",builder);
gtk_builder_connect_signals(builder,w);
linphone_gtk_configure_window(w,window_name);
if(parent) {
// gtk_window_set_modal(GTK_WINDOW(w), TRUE);
gtk_window_set_transient_for(GTK_WINDOW(w), GTK_WINDOW(parent));
gtk_window_set_position(GTK_WINDOW(w), GTK_WIN_POS_CENTER_ON_PARENT);
} else {
// gtk_window_set_modal(GTK_WINDOW(w), FALSE);
}
return w;
g_object_set_data(G_OBJECT(obj), "builder", builder);
g_signal_connect_data(G_OBJECT(obj),"destroy",(GCallback)g_object_unref,builder, NULL, G_CONNECT_AFTER|G_CONNECT_SWAPPED);
gtk_builder_connect_signals(builder, obj);
return GTK_WIDGET(obj);
fail:
g_object_unref(builder);
return NULL;
}
GtkWidget *linphone_gtk_create_widget(const char *filename, const char *widget_name){
char path[2048];
GtkWidget *w;
GtkBuilder* builder = gtk_builder_new ();
GError *error=NULL;
gchar *object_ids[2];
object_ids[0]=g_strdup(widget_name);
object_ids[1]=NULL;
if (get_ui_file(filename,path,sizeof(path))==-1) return NULL;
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);
g_free(object_ids[0]);
return NULL;
GtkWidget *linphone_gtk_create_window(const char *window_name, GtkWidget *parent){
GtkWidget *w = linphone_gtk_create_widget(window_name);
if(w) {
linphone_gtk_configure_window(w,window_name);
if(parent) {
gtk_window_set_transient_for(GTK_WINDOW(w), GTK_WINDOW(parent));
gtk_window_set_position(GTK_WINDOW(w), GTK_WIN_POS_CENTER_ON_PARENT);
}
}
g_free(object_ids[0]);
w=GTK_WIDGET(gtk_builder_get_object (builder,widget_name));
if (w==NULL){
g_error("Could not retrieve '%s' window from xml file",widget_name);
return NULL;
}
g_object_set_data(G_OBJECT(w),"builder",builder);
g_signal_connect_swapped(G_OBJECT(w),"destroy",(GCallback)g_object_unref,builder);
gtk_builder_connect_signals(builder,w);
return w;
}
@ -484,16 +462,16 @@ void linphone_gtk_display_something(GtkMessageType type,const gchar *message){
/* draw a question box. link to dialog_click callback */
dialog = gtk_message_dialog_new (
GTK_WINDOW(main_window),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_QUESTION,
GTK_BUTTONS_YES_NO,
"%s",
GTK_BUTTONS_YES_NO,
"%s",
(const gchar*)message);
/* connect to some callback : REVISIT */
/*
g_signal_connect_swapped (G_OBJECT (dialog), "response",
G_CALLBACK (dialog_click),
G_OBJECT (dialog));
G_CALLBACK (dialog_click),
G_OBJECT (dialog));
*/
/* actually show the box */
gtk_widget_show(dialog);
@ -501,15 +479,15 @@ void linphone_gtk_display_something(GtkMessageType type,const gchar *message){
else
{
dialog = gtk_message_dialog_new (GTK_WINDOW(main_window),
GTK_DIALOG_DESTROY_WITH_PARENT,
type,
GTK_BUTTONS_CLOSE,
"%s",
(const gchar*)message);
GTK_DIALOG_DESTROY_WITH_PARENT,
type,
GTK_BUTTONS_CLOSE,
"%s",
(const gchar*)message);
/* Destroy the dialog when the user responds to it (e.g. clicks a button) */
g_signal_connect_swapped (G_OBJECT (dialog), "response",
G_CALLBACK (gtk_widget_destroy),
G_OBJECT (dialog));
G_CALLBACK (gtk_widget_destroy),
G_OBJECT (dialog));
gtk_widget_show(dialog);
}
}
@ -531,7 +509,7 @@ void linphone_gtk_show_about(void){
GtkWidget *about;
const char *tmp;
GdkPixbuf *logo=create_pixbuf(
linphone_gtk_get_ui_config("logo","linphone-banner.png"));
linphone_gtk_get_ui_config("logo","linphone-banner.png"));
static const char *defcfg="defcfg";
about=linphone_gtk_create_window("about", the_ui);
@ -593,8 +571,7 @@ static gboolean linphone_gtk_iterate(LinphoneCore *lc){
if (addr_to_call!=NULL){
/*make sure we are not showing the login screen*/
GtkWidget *mw=linphone_gtk_get_main_window();
GtkWidget *login_frame=linphone_gtk_get_widget(mw,"login_frame");
if (!GTK_WIDGET_VISIBLE(login_frame)){
if (g_object_get_data(G_OBJECT(mw), "login_frame") == NULL){
GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
gtk_entry_set_text(GTK_ENTRY(uri_bar),addr_to_call);
addr_to_call=NULL;
@ -829,7 +806,7 @@ void linphone_gtk_show_main_window(){
void linphone_gtk_call_terminated(LinphoneCall *call, const char *error){
GtkWidget *mw=linphone_gtk_get_main_window();
if (linphone_core_get_calls(linphone_gtk_get_core())==NULL){
gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),TRUE);
gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),TRUE);
}
if (linphone_gtk_use_in_call_view() && call)
linphone_gtk_in_call_view_terminate(call,error);
@ -840,29 +817,20 @@ static void linphone_gtk_update_call_buttons(LinphoneCall *call){
GtkWidget *mw=linphone_gtk_get_main_window();
const MSList *calls=linphone_core_get_calls(lc);
GtkWidget *button;
bool_t start_active=TRUE;
//bool_t stop_active=FALSE;
bool_t add_call=FALSE;
bool_t add_call=(calls!=NULL);
int call_list_size=ms_list_size(calls);
GtkWidget *conf_frame;
if (calls==NULL){
start_active=TRUE;
//stop_active=FALSE;
}else{
//stop_active=TRUE;
start_active=TRUE;
add_call=TRUE;
}
button=linphone_gtk_get_widget(mw,"start_call");
gtk_widget_set_sensitive(button,start_active);
gtk_widget_set_sensitive(button,TRUE);
gtk_widget_set_visible(button,!add_call);
button=linphone_gtk_get_widget(mw,"add_call");
if (linphone_core_sound_resources_locked(lc) || (call && linphone_call_get_state(call)==LinphoneCallIncomingReceived)) {
gtk_widget_set_sensitive(button,FALSE);
} else {
gtk_widget_set_sensitive(button,start_active);
gtk_widget_set_sensitive(button,TRUE);
}
gtk_widget_set_visible(button,add_call);
@ -981,6 +949,18 @@ void linphone_gtk_start_call(GtkWidget *w){
}
void linphone_gtk_start_chat(GtkWidget *w){
GtkWidget *mw=gtk_widget_get_toplevel(w);
GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar));
LinphoneCore *lc=linphone_gtk_get_core();
LinphoneAddress *addr=linphone_core_interpret_url(lc,entered);
if (addr) {
linphone_gtk_friend_list_set_chat_conversation(addr);
linphone_address_destroy(addr);
}
}
void linphone_gtk_uri_bar_activate(GtkWidget *w){
linphone_gtk_start_call(w);
}
@ -1078,10 +1058,10 @@ static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend
message=g_strdup_printf(_("%s would like to add you to his/her contact list.\nWould you add him/her to your contact list and allow him/her to see your presence status?\nIf you answer no, this person will be temporarily blacklisted."),url);
dialog = gtk_message_dialog_new (
GTK_WINDOW(linphone_gtk_get_main_window()),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_QUESTION,
GTK_BUTTONS_YES_NO,
"%s",
GTK_BUTTONS_YES_NO,
"%s",
message);
g_free(message);
g_signal_connect(G_OBJECT (dialog), "response",
@ -1146,7 +1126,7 @@ static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm
gchar *msg;
GtkWidget *mw=linphone_gtk_get_main_window();
if (mw && GTK_WIDGET_VISIBLE(linphone_gtk_get_widget(mw,"login_frame"))){
if (mw && g_object_get_data(G_OBJECT(mw), "login_frame") != NULL){
/*don't prompt for authentication when login frame is visible*/
linphone_core_abort_authentication(lc,NULL);
return;
@ -1346,7 +1326,7 @@ static void linphone_gtk_call_updated_by_remote(LinphoneCall *call){
gboolean video_requested=linphone_call_params_video_enabled(rparams);
gboolean video_used=linphone_call_params_video_enabled(current_params);
g_message("Video used=%i, video requested=%i, automatically_accept=%i",
video_used,video_requested,pol->automatically_accept);
video_used,video_requested,pol->automatically_accept);
if (!video_used && video_requested && !pol->automatically_accept){
linphone_core_defer_call_update(lc,call);
{
@ -1356,13 +1336,13 @@ static void linphone_gtk_call_updated_by_remote(LinphoneCall *call){
if (dname==NULL) dname=linphone_address_get_username(addr);
if (dname==NULL) dname=linphone_address_get_domain(addr);
dialog=gtk_message_dialog_new(GTK_WINDOW(linphone_gtk_get_main_window()),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_WARNING,
GTK_BUTTONS_YES_NO,
_("%s proposed to start video. Do you accept ?"),dname);
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_WARNING,
GTK_BUTTONS_YES_NO,
_("%s proposed to start video. Do you accept ?"),dname);
g_object_set_data_full(G_OBJECT(dialog), "call", linphone_call_ref(call), (GDestroyNotify)linphone_call_unref);
g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(on_call_updated_response), NULL);
g_timeout_add(20000,(GSourceFunc)on_call_updated_timeout,dialog);
g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(on_call_updated_response), NULL);
g_timeout_add(20000,(GSourceFunc)on_call_updated_timeout,dialog);
gtk_widget_show(dialog);
}
}
@ -1470,7 +1450,7 @@ static void update_registration_status(LinphoneProxyConfig *cfg, LinphoneRegistr
}
static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg,
LinphoneRegistrationState rs, const char *msg){
LinphoneRegistrationState rs, const char *msg){
switch (rs){
case LinphoneRegistrationOk:
if (cfg){
@ -1486,18 +1466,29 @@ static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphonePr
update_registration_status(cfg,rs);
}
void linphone_gtk_open_browser(const char *url){
/*in gtk 2.16, gtk_show_uri does not work...*/
#ifndef WIN32
#if GTK_CHECK_VERSION(2,18,3)
gtk_show_uri(NULL,url,GDK_CURRENT_TIME,NULL);
void linphone_gtk_open_browser(const char *uri) {
#ifdef __APPLE__
GError *error = NULL;
char cmd_line[256];
g_snprintf(cmd_line, sizeof(cmd_line), "%s %s", "/usr/bin/open", uri);
g_spawn_command_line_async(cmd_line, &error);
if (error) {
g_warning("Could not open %s: %s", uri, error->message);
g_error_free(error);
}
#elif defined(WIN32)
HINSTANCE instance = ShellExecute(NULL, "open", uri, NULL, NULL, SW_SHOWNORMAL);
if ((int)instance <= 32) {
g_warning("Could not open %s (error #%i)", uri, (int)instance);
}
#else
char cl[255];
snprintf(cl,sizeof(cl),"/usr/bin/x-www-browser %s",url);
g_spawn_command_line_async(cl,NULL);
#endif
#else /*WIN32*/
ShellExecute(0,"open",url,NULL,NULL,1);
GError *error = NULL;
gtk_show_uri(NULL, uri, GDK_CURRENT_TIME, &error);
if (error) {
g_warning("Could not open %s: %s", uri, error->message);
g_error_free(error);
}
#endif
}
@ -1541,7 +1532,7 @@ static GtkWidget *create_icon_menu(){
#ifndef HAVE_GTK_OSX
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);
}
#endif
@ -1643,8 +1634,8 @@ void linphone_gtk_load_identities(void){
LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
gtk_list_store_append(store,&iter);
gtk_list_store_set(store,&iter,0,linphone_proxy_config_get_identity(cfg),1,
linphone_proxy_config_is_registered(cfg) ? GTK_STOCK_YES : NULL,
2,cfg,-1);
linphone_proxy_config_is_registered(cfg) ? GTK_STOCK_YES : NULL,
2,cfg,-1);
if (cfg==def) {
def_index=i;
}
@ -1707,6 +1698,7 @@ static void linphone_gtk_configure_main_window(){
static const char *home;
static const char *start_call_icon;
static const char *add_call_icon;
static const char *start_chat_icon;
static const char *search_icon;
static gboolean update_check_menu;
static gboolean buttons_have_borders;
@ -1716,8 +1708,9 @@ static void linphone_gtk_configure_main_window(){
if (!config_loaded){
title=linphone_gtk_get_ui_config("title","Linphone");
home=linphone_gtk_get_ui_config("home","http://www.linphone.org");
start_call_icon=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png");
add_call_icon=linphone_gtk_get_ui_config("add_call_icon","addcall-green.png");
start_call_icon=linphone_gtk_get_ui_config("start_call_icon","call_start.png");
add_call_icon=linphone_gtk_get_ui_config("add_call_icon","call_add.png");
start_chat_icon=linphone_gtk_get_ui_config("start_chat_icon","chat_start.png");
search_icon=linphone_gtk_get_ui_config("directory_search_icon",NULL);
update_check_menu=linphone_gtk_get_ui_config_int("update_check_menu",0);
buttons_have_borders=linphone_gtk_get_ui_config_int("buttons_border",1);
@ -1730,16 +1723,22 @@ static void linphone_gtk_configure_main_window(){
}
if (start_call_icon){
gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),
create_pixmap (start_call_icon));
create_pixmap (start_call_icon));
if (!buttons_have_borders)
gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),GTK_RELIEF_NONE);
}
if (add_call_icon){
gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),
create_pixmap (add_call_icon));
create_pixmap (add_call_icon));
if (!buttons_have_borders)
gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),GTK_RELIEF_NONE);
}
if (start_chat_icon){
gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"start_chat")),
create_pixmap (start_chat_icon));
if (!buttons_have_borders)
gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"start_chat")),GTK_RELIEF_NONE);
}
if (search_icon){
GdkPixbuf *pbuf=create_pixbuf(search_icon);
if(pbuf) {
@ -1751,7 +1750,7 @@ static void linphone_gtk_configure_main_window(){
gchar *tmp;
GtkWidget *menu_item=linphone_gtk_get_widget(w,"home_item");
tmp=g_strdup(home);
g_object_set_data(G_OBJECT(menu_item),"home",tmp);
g_object_set_data_full(G_OBJECT(menu_item),"home",tmp, (GDestroyNotify)g_free);
}
{
/*
@ -2064,7 +2063,7 @@ int main(int argc, char *argv[]){
GdkPixbuf *pbuf;
const char *app_name="Linphone";
LpConfig *factory;
const char *db_file;
char *db_file;
GError *error=NULL;
const char *tmp;
@ -2203,8 +2202,8 @@ core_start:
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);
g_free(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());

File diff suppressed because it is too large Load diff

View file

@ -211,6 +211,7 @@
<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>
<signal name="switch-page" handler="linphone_gtk_notebook_current_page_changed" swapped="no"/>
<child>
<object class="GtkVBox" id="sip_tab">
<property name="visible">True</property>

View file

@ -557,9 +557,9 @@ static void bitrate_edited(GtkCellRendererText *renderer, gchar *path, gchar *ne
GtkListStore *store=(GtkListStore*)userdata;
GtkTreeIter iter;
float newbitrate=0;
if (!new_text) return;
if (sscanf(new_text, "%f", &newbitrate)!=1) return;
if (gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(store),&iter,path)){
@ -606,10 +606,10 @@ static void linphone_gtk_init_codec_list(GtkTreeView *listview){
"foreground",CODEC_COLOR,
NULL);
gtk_tree_view_append_column (listview, column);
g_value_init(&editable, G_TYPE_BOOLEAN);
g_value_set_boolean(&editable, TRUE);
renderer = gtk_cell_renderer_text_new ();
g_object_set_property(G_OBJECT(renderer), "editable", &editable);
column = gtk_tree_view_column_new_with_attributes (
@ -620,7 +620,7 @@ static void linphone_gtk_init_codec_list(GtkTreeView *listview){
NULL);
g_signal_connect(G_OBJECT(renderer),"edited",G_CALLBACK(bitrate_edited),store);
gtk_tree_view_append_column (listview, column);
renderer = gtk_cell_renderer_text_new ();
g_object_set_property(G_OBJECT(renderer), "editable", &editable);
column = gtk_tree_view_column_new_with_attributes (
@ -785,13 +785,13 @@ static void linphone_gtk_codec_move(GtkWidget *button, int dir, int type){ /* 0=
if (gtk_tree_selection_count_selected_rows(sel) == 1){
MSList *sel_elem,*before;
MSList *codec_list;
GList *selected_rows = gtk_tree_selection_get_selected_rows(sel, &mod);
gtk_tree_model_get_iter(mod, &iter, (GtkTreePath *)g_list_nth_data(selected_rows, 0));
gtk_tree_model_get(mod,&iter,CODEC_PRIVDATA,&pt,-1);
g_list_foreach(selected_rows, _g_list_func_destroy_tree_path, NULL);
g_list_free(selected_rows);
if (pt->type==PAYLOAD_VIDEO)
codec_list=ms_list_copy(linphone_core_get_video_codecs(lc));
else codec_list=ms_list_copy(linphone_core_get_audio_codecs(lc));
@ -885,6 +885,9 @@ void linphone_gtk_show_sip_accounts(GtkWidget *w){
GtkTreeModel *model=gtk_tree_view_get_model(v);
GtkListStore *store;
GtkTreeSelection *select;
const LinphoneProxyConfig *default_pc = linphone_core_get_default_proxy_config(linphone_gtk_get_core());
GtkTreePath *default_pc_path = NULL;
const MSList *elem;
if (!model){
GtkCellRenderer *renderer;
@ -914,6 +917,11 @@ void linphone_gtk_show_sip_accounts(GtkWidget *w){
gtk_list_store_append(store,&iter);
gtk_list_store_set(store,&iter,PROXY_CONFIG_IDENTITY,linphone_proxy_config_get_identity(cfg),
PROXY_CONFIG_REF,cfg,-1);
if(cfg == default_pc) default_pc_path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
}
if(default_pc_path) {
gtk_tree_selection_select_path(gtk_tree_view_get_selection(v), default_pc_path);
gtk_tree_path_free(default_pc_path);
}
}
@ -1893,3 +1901,15 @@ void linphone_gtk_auto_answer_delay_changed(GtkSpinButton *spinbutton, gpointer
int delay = gtk_spin_button_get_value(spinbutton);
linphone_gtk_set_ui_config_int("auto_answer_delay", delay);
}
void linphone_gtk_notebook_current_page_changed (GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer user_data) {
#ifndef HAVE_LIBUDEV_H
if (page_num == 1) {
// Multimedia settings - we reload audio and video devices to detect
// hot-plugged devices
g_message("Opened multimedia page... reloading audio and video devices!");
linphone_gtk_reload_sound_devices();
linphone_gtk_reload_video_devices();
}
#endif
}

View file

@ -21,7 +21,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <glib.h>
#include <glib/gprintf.h>
static const int PASSWORD_MIN_SIZE = 6;
static const int LOGIN_MIN_SIZE = 4;
static GtkWidget *the_assistant = NULL;
@ -190,8 +189,8 @@ static int external_account_configuration_complete(GtkWidget *w) {
if ((gtk_entry_get_text_length(username) > 0)
&& (gtk_entry_get_text_length(domain) > 0)
&& (g_regex_match_simple("^[a-zA-Z0-9]+[a-zA-Z0-9.\\-_]{2,}$", gtk_entry_get_text(username), 0, 0))
&& (g_regex_match_simple("^(sip:)?([a-zA-Z0-9]+([\\.-][a-zA-Z0-9]+)*)$", gtk_entry_get_text(domain), 0, 0))) {
&& (g_regex_match_simple("^[a-zA-Z0-9+]+[a-zA-Z0-9.\\+\\-_]{2,}$", gtk_entry_get_text(username), 0, 0))
&& (g_regex_match_simple("^(sip:)?([a-zA-Z0-9\\+]+([\\.-][a-zA-Z0-9+]+)*)$", gtk_entry_get_text(domain), 0, 0))) {
return 1;
}
return 0;
@ -316,7 +315,7 @@ static gboolean update_interface_with_username_availability(void *w) {
gtk_label_set_text(usernameError, "");
} else {
GdkPixbuf *nok_pixbuf = GDK_PIXBUF(g_object_get_data(G_OBJECT(the_assistant), "nok_pixbuf"));
gtk_label_set_text(usernameError, "Username is already in use !");
gtk_label_set_text(usernameError, "Username is already in use!");
g_object_set_data(G_OBJECT(w), "is_username_available", GINT_TO_POINTER(0));
gtk_image_set_from_pixbuf(isUsernameOk, nok_pixbuf);
}
@ -327,7 +326,7 @@ static gboolean update_interface_with_username_availability(void *w) {
static void linphone_gtk_test_account_existence_cb(LinphoneAccountCreator *creator, LinphoneAccountCreatorStatus status) {
GtkWidget *assistant = (GtkWidget *)linphone_account_creator_get_user_data(creator);
GtkWidget *page = g_object_get_data(G_OBJECT(assistant), "linphone_account_creation_configuration");
int account_existing = (status == LinphoneAccountCreatorOk) ? 0 : 1;
int account_existing = (status != LinphoneAccountCreatorOk);
g_object_set_data(G_OBJECT(page), "is_username_used", GINT_TO_POINTER(account_existing));
gdk_threads_add_idle((GSourceFunc)update_interface_with_username_availability, (void*)page);
}
@ -376,7 +375,7 @@ static void linphone_account_creation_email_changed(GtkEntry *entry, GtkWidget *
GtkImage* isEmailOk = GTK_IMAGE(g_object_get_data(G_OBJECT(w), "emailOk"));
GtkWidget *assistant = gtk_widget_get_toplevel(w);
if (g_regex_match_simple("^[a-z0-9]+([_\\.-][a-z0-9]+)*@([a-z0-9]+([\\.-][a-z0-9]+)*)+\\.[a-z]{2,}$", gtk_entry_get_text(email), 0, 0)) {
if (g_regex_match_simple("^[a-z0-9]([a-z0-9_\\+\\.-]+)@[a-z0-9]([a-z0-9\\.-]+)\\.[a-z]{2,}$", gtk_entry_get_text(email), 0, 0)) {
GdkPixbuf *ok_pixbuf = GDK_PIXBUF(g_object_get_data(G_OBJECT(the_assistant), "ok_pixbuf"));
g_object_set_data(G_OBJECT(w), "is_email_correct", GINT_TO_POINTER(1));
gtk_image_set_from_pixbuf(isEmailOk, ok_pixbuf);
@ -622,14 +621,26 @@ void linphone_gtk_show_assistant(GtkWidget *parent) {
g_signal_connect(G_OBJECT(w), "close", (GCallback)linphone_gtk_assistant_closed, NULL);
g_signal_connect(G_OBJECT(w), "cancel", (GCallback)linphone_gtk_assistant_closed, NULL);
g_signal_connect(G_OBJECT(w), "prepare", (GCallback)linphone_gtk_assistant_prepare, NULL);
gtk_window_set_transient_for(GTK_WINDOW(the_assistant), GTK_WINDOW(linphone_gtk_get_main_window()));
gtk_widget_show(w);
}
void linphone_gtk_close_assistant(void) {
if (the_assistant == NULL) return;
GtkWidget *mw;
if (the_assistant == NULL) {
return;
}
gtk_widget_destroy(the_assistant);
the_assistant = NULL;
//reload list of proxy configs because a new one was probably created...
mw=linphone_gtk_get_main_window();
if (mw) {
GtkWidget* pb = (GtkWidget*)g_object_get_data(G_OBJECT(mw),"parameters");
if (pb) {
linphone_gtk_show_sip_accounts(pb);
}
}
}

View file

@ -117,7 +117,7 @@ static gboolean _linphone_status_icon_desc_is_supported(
gboolean *result,
LinphoneStatusIconDescIsSupportedResultCb cb,
void *user_data) {
return desc->is_supported(desc, result, cb, user_data);
}
@ -131,7 +131,7 @@ static void _linphone_status_icon_desc_is_supported_result_cb(
const _LinphoneStatusIconDesc *desc,
gboolean result,
_LinphoneStatusIconDescSearchCtx *ctx) {
if(!result) {
ctx->i = g_slist_next(ctx->i);
for(; ctx->i; ctx->i = g_slist_next(ctx->i)) {
@ -140,12 +140,12 @@ static void _linphone_status_icon_desc_is_supported_result_cb(
&result,
(LinphoneStatusIconDescIsSupportedResultCb)_linphone_status_icon_desc_is_supported_result_cb,
ctx)) {
if(result) break;
} else return;
}
}
if(ctx->i) {
const _LinphoneStatusIconDesc *desc = (const _LinphoneStatusIconDesc *)g_slist_nth_data(ctx->i, 0);
ms_message("StatusIcon: found implementation: %s", desc->impl_name);
@ -153,7 +153,7 @@ static void _linphone_status_icon_desc_is_supported_result_cb(
} else {
g_warning("StatusIcon: no implementation found");
}
g_free(ctx);
}
@ -161,21 +161,21 @@ static gboolean _linphone_status_icon_find_first_available_impl(
const _LinphoneStatusIconDesc **desc,
LinphoneStatusIconDescFindResultCb cb,
void *user_data) {
gboolean result;
_LinphoneStatusIconDescSearchCtx *ctx = g_new0(_LinphoneStatusIconDescSearchCtx, 1);
ctx->cb = cb;
ctx->user_data = user_data;
ms_message("StatusIcon: looking for implementation...");
for(ctx->i=_linphone_status_icon_impls; ctx->i; ctx->i = g_slist_next(ctx->i)) {
if(_linphone_status_icon_desc_is_supported(
(const _LinphoneStatusIconDesc *)g_slist_nth_data(ctx->i, 0),
&result,
(LinphoneStatusIconDescIsSupportedResultCb)_linphone_status_icon_desc_is_supported_result_cb,
ctx)) {
if(result) {
*desc = (const _LinphoneStatusIconDesc *)g_slist_nth_data(ctx->i, 0);
ms_message("StatusIcon: found implementation: %s", (*desc)->impl_name);
@ -187,7 +187,7 @@ static gboolean _linphone_status_icon_find_first_available_impl(
}
g_warning("StatusIcon: no implementation found");
*desc = NULL;
sync_return:
g_free(ctx);
return 1;
@ -266,15 +266,15 @@ void _linphone_status_icon_create_implementations_list(void) {
gboolean linphone_status_icon_init(LinphoneStatusIconReadyCb ready_cb, void *user_data) {
const _LinphoneStatusIconDesc *desc;
void **ctx;
ms_message("StatusIcon: Initialising");
_linphone_status_icon_create_implementations_list();
ctx = g_new(void *, 2);
ctx[0] = ready_cb;
ctx[1] = user_data;
if(_linphone_status_icon_find_first_available_impl(&desc, _linphone_status_icon_init_cb, ctx)) {
_linphone_status_icon_selected_desc = desc;
g_free(ctx);
@ -317,7 +317,7 @@ static void _linphone_status_icon_impl_gtk_popup_menu(GtkStatusIcon *status_icon
static void _linphone_status_icon_impl_gtk_init(LinphoneStatusIcon *si) {
const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
const char *call_icon_path=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png");
const char *call_icon_path=linphone_gtk_get_ui_config("start_call_icon","call_start.png");
GdkPixbuf *pbuf=create_pixbuf(icon_path);
GtkStatusIcon *icon=gtk_status_icon_new_from_pixbuf(pbuf);
g_signal_connect_swapped(G_OBJECT(icon),"activate", G_CALLBACK(_linphone_status_icon_impl_gtk_on_click_cb), si);
@ -375,7 +375,7 @@ static gboolean _linphone_status_icon_impl_is_supported(
gboolean *result,
LinphoneStatusIconDescIsSupportedResultCb cb,
void *user_data) {
*result = 1;
return 1;
}
@ -409,7 +409,7 @@ static gboolean _linphone_status_icon_impl_gtkosx_app_is_supported(
gboolean *result,
LinphoneStatusIconDescIsSupportedResultCb cb,
void *user_data) {
*result = 1;
return 1;
}
@ -472,10 +472,10 @@ static void _linphone_status_icon_impl_sn_start(LinphoneStatusIcon *si) {
BcStatusNotifierParams *params;
BcStatusNotifierToolTip *tooltip = bc_status_notifier_tool_tip_new("linphone", si->params->title, si->params->desc);
BcStatusNotifierSignalsVTable vtable = {NULL};
vtable.activate_called_cb = _linphone_status_icon_impl_sn_activated_cb;
vtable.context_menu_called_cb = _linphone_status_icon_impl_sn_menu_called_cb;
params = bc_status_notifier_params_new();
bc_status_notifier_params_set_dbus_prefix(params, "org.kde");
bc_status_notifier_params_set_category(params, BcStatusNotifierCategoryCommunications);
@ -484,15 +484,15 @@ static void _linphone_status_icon_impl_sn_start(LinphoneStatusIcon *si) {
bc_status_notifier_params_set_icon_name(params, "linphone");
bc_status_notifier_params_set_tool_tip(params, tooltip);
bc_status_notifier_params_set_vtable(params, &vtable, si);
bc_status_notifier_start(sn, params, NULL, NULL);
bc_status_notifier_tool_tip_unref(tooltip);
bc_status_notifier_params_unref(params);
}
static void _linphone_status_icon_impl_sn_enable_blinking(LinphoneStatusIcon *si, gboolean val) {
BcStatusNotifier *sn = (BcStatusNotifier *)si->data;
BcStatusNotifier *sn = (BcStatusNotifier *)si->data;
if(val) {
bc_status_notifier_update_status(sn, BcStatusNotifierStatusNeedsAttention);
} else {
@ -513,16 +513,16 @@ static gboolean _linphone_status_icon_impl_sn_is_supported(
gboolean *result,
LinphoneStatusIconDescIsSupportedResultCb cb,
void *user_data) {
_LinphoneStatusIconDesc *desc2;
void **data;
const char *desktop = g_getenv("XDG_CURRENT_DESKTOP");
if(desktop == NULL || g_strcmp0(desktop, "KDE") != 0) {
*result = FALSE;
return TRUE;
}
desc2 = g_new(_LinphoneStatusIconDesc, 1);
*desc2 = *desc;
data = g_new(void *, 3);

View file

@ -230,6 +230,7 @@ typedef struct SalStreamDescription{
SalSrtpCryptoAlgo crypto[SAL_CRYPTO_ALGO_MAX];
unsigned int crypto_local_tag;
int max_rate;
OrtpRtcpFbConfiguration rtcp_fb;
OrtpRtcpXrConfiguration rtcp_xr;
SalIceCandidate ice_candidates[SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES];
SalIceRemoteCandidate ice_remote_candidates[SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES];

View file

@ -1186,7 +1186,7 @@ public interface LinphoneCore {
* Returns true if the software echo canceler needs to be turned on.
* If the device has a builtin echo canceller, it will return false.
*/
boolean needsEchoCanceler();
boolean hasBuiltInEchoCanceler();
void enableIpv6(boolean enable);

View file

@ -53,15 +53,6 @@ public interface LinphoneCoreListener {
*/
void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf);
/**
* invoked when a new text message is received
* @param lc LinphoneCore
* @param room LinphoneChatRoom involved in this conversation. Can be be created by the framework in case the from is not present in any chat room.
* @param from LinphoneAddress from
* @param message incoming message
*/
void textReceived(LinphoneCore lc, LinphoneChatRoom cr, LinphoneAddress from, String message);
/**
* invoked when a new dtmf is received
* @param lc LinphoneCore

View file

@ -38,13 +38,6 @@ public class LinphoneCoreListenerBase implements LinphoneCoreListener {
}
@Override
public void textReceived(LinphoneCore lc, LinphoneChatRoom cr,
LinphoneAddress from, String message) {
// TODO Auto-generated method stub
}
@Override
public void dtmfReceived(LinphoneCore lc, LinphoneCall call, int dtmf) {
// TODO Auto-generated method stub

View file

@ -1057,10 +1057,10 @@ class LinphoneCoreImpl implements LinphoneCore {
public synchronized boolean needsEchoCalibration() {
return needsEchoCalibration(nativePtr);
}
private native boolean needsEchoCanceler(long ptr);
private native boolean hasBuiltInEchoCanceler(long ptr);
@Override
public synchronized boolean needsEchoCanceler() {
return needsEchoCanceler(nativePtr);
public synchronized boolean hasBuiltInEchoCanceler() {
return hasBuiltInEchoCanceler(nativePtr);
}
private native void declineCall(long coreptr, long callptr, int reason);
@Override

@ -1 +1 @@
Subproject commit aa8c0587e8c8e8e86d642a5e5d01866d3c881f94
Subproject commit 93cf916ac44dea93db7744b1d66ea3655c8345d9

2
oRTP

@ -1 +1 @@
Subproject commit 32f4e635db66d2acec21c4633d37776cd6ed34df
Subproject commit bb95930a77e8a1432e5c31dc170f05ecd15518e5

View file

@ -20,50 +20,39 @@
#
############################################################################
set(PIXMAPS
active_chat.png
addcall-green.png
call.png
call_status_incoming.png
call_status_outgoing.png
chat_message_delivered.png
chat_message_inprogress.png
chat_message_not_delivered.png
chat.png
composing_active_chat.png
composing_chat.png
contact-orange.png
contact_starred.png
contact_unstarred.png
dialer-orange.png
dialer.png
history-orange.png
hold_off.png
hold_on.png
linphone-banner.png
linphone.icns
linphone.png
mic_active.png
mic_muted.png
notok.png
ok.png
speaker.png
startcall-green.png
startcall-small.png
status-green.png
status-offline.png
status-orange.png
status-red.png
stopcall-red.png
stopcall-small.png
)
set(ICONS_INSTALL_DIR ${PACKAGE_DATA_DIR}/icons/hicolor)
file(GLOB PIXMAPS "*.png" "linphone.icns")
install(FILES ${PIXMAPS}
DESTINATION ${PACKAGE_DATA_DIR}/pixmaps/linphone
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
)
install(FILES svg/linphone-micro-muted.svg
svg/linphone-speaker-muted.svg
svg/linphone-micro-enabled.svg
svg/linphone-speaker-enabled.svg
DESTINATION ${ICONS_INSTALL_DIR}/scalable/status
PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ
)
install(FILES linphone-micro-muted.png
linphone-speaker-muted.png
linphone-micro-enabled.png
linphone-speaker-enabled.png
DESTINATION ${ICONS_INSTALL_DIR}/48x48/status
PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ
)
install(FILES linphone.png
DESTINATION ${PACKAGE_DATA_DIR}/icons/hicolor/48x48/apps
DESTINATION ${ICONS_INSTALL_DIR}/48x48/apps
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
)
if(WIN32)
install(FILES index.theme
DESTINATION ${ICONS_INSTALL_DIR}
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
)
endif()

View file

@ -1,29 +1,41 @@
pixmapdir=$(datadir)/pixmaps/linphone
pixmap_DATA= \
dist_pixmap_DATA= \
hold_on.png hold_off.png \
mic_muted.png mic_active.png \
linphone.png linphone-banner.png \
status-green.png \
status-orange.png \
status-red.png \
status-offline.png \
call.png \
chat.png active_chat.png composing_chat.png composing_active_chat.png\
chat.png chat_start.png active_chat.png composing_chat.png composing_active_chat.png\
chat_message_inprogress.png chat_message_delivered.png chat_message_not_delivered.png\
contact-orange.png dialer-orange.png history-orange.png\
startcall-green.png startcall-small.png stopcall-red.png stopcall-small.png addcall-green.png linphone.icns \
contact-orange.png history-orange.png\
call_start.png startcall-small.png stopcall-red.png stopcall-small.png call_add.png linphone.icns \
contact_starred.png contact_unstarred.png \
speaker.png \
call_status_incoming.png call_status_outgoing.png \
ok.png \
dialer.png \
notok.png
iconsdir=$(datadir)/icons/hicolor
if BUILD_WIN32
dist_icons_DATA=index.theme
endif
iconsdir=$(datadir)/icons/hicolor/48x48/apps
appiconsdir=$(iconsdir)/48x48/apps
dist_appicons_DATA= linphone.png
icons_DATA= linphone.png
status48iconsdir=$(iconsdir)/48x48/status
dist_status48icons_DATA= \
linphone-micro-muted.png \
linphone-speaker-muted.png \
linphone-micro-enabled.png \
linphone-speaker-enabled.png
statussvgiconsdir=$(iconsdir)/scalable/status
dist_statussvgicons_DATA= \
svg/linphone-micro-muted.svg \
svg/linphone-speaker-muted.svg \
svg/linphone-micro-enabled.svg \
svg/linphone-speaker-enabled.svg
EXTRA_DIST=$(pixmap_DATA) $(icons_DATA)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

BIN
pixmaps/call_add.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

BIN
pixmaps/call_start.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

BIN
pixmaps/chat_start.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 5 KiB

1836
pixmaps/index.theme Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 455 B

4
pixmaps/svg/.directory Normal file
View file

@ -0,0 +1,4 @@
[Dolphin]
PreviewsShown=true
Timestamp=2015,8,3,13,7,36
Version=3

View file

@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="128"
height="128"
viewBox="0 0 128 128"
version="1.1"
id="svg2"
inkscape:version="0.91 r13725"
sodipodi:docname="linphone-micro-enabled.svg"
inkscape:export-filename="/home/francois/projects/linphone/linphone/pixmaps/hicolor/16x16/linphone-micro-muted.png"
inkscape:export-xdpi="11.25"
inkscape:export-ydpi="11.25">
<metadata
id="metadata17">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>micro_default</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1133"
id="namedview15"
showgrid="false"
inkscape:zoom="2.1454545"
inkscape:cx="-69.09746"
inkscape:cy="55"
inkscape:window-x="-6"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" />
<!-- Generator: Sketch 3.3.3 (12081) - http://www.bohemiancoding.com/sketch -->
<title
id="title4">micro_default</title>
<desc
id="desc6">Created with Sketch.</desc>
<defs
id="defs8" />
<g
id="g3348">
<path
sodipodi:nodetypes="cssssscccsccccccccsc"
d="m 44.924259,68.391695 c 0,10.054618 8.187424,18.210235 18.282433,18.210235 10.09808,0 18.285504,-8.155617 18.285504,-18.210235 l 0,-45.74882 c 0,-10.060734 -8.187424,-18.2163505 -18.285504,-18.2163505 -10.095009,0 -18.282433,8.1556165 -18.282433,18.2163505 l 0,45.74882 z m 52.901346,-22.208536 0,19.875302 c 0,19.049648 -15.500088,34.486299 -34.618913,34.486299 m 0,0 0,21.47768 z m -10.771796,23.87819 21.548197,0 z M 28.58931,46.183159 l 0,19.875302 c 0,19.049648 15.500092,34.486299 34.618917,34.486299"
id="micro_off"
sketch:type="MSShapeGroup"
inkscape:connector-curvature="0"
style="fill:none;fill-rule:evenodd;stroke:#444444;stroke-width:5.78692436;stroke-linecap:round;stroke-linejoin:round" />
<rect
id="Rectangle-250-Copy-6"
sketch:type="MSShapeGroup"
x="-25.377115"
y="-24.508099"
width="178.23727"
height="178.23727"
style="fill:#ffffff;fill-opacity:0;fill-rule:evenodd;stroke:none;stroke-width:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View file

@ -0,0 +1,90 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="128"
height="128"
viewBox="0 0 128 128"
version="1.1"
id="svg2"
inkscape:version="0.91 r13725"
sodipodi:docname="linphone-micro-muted.svg"
inkscape:export-filename="/home/francois/projects/linphone/linphone/pixmaps/hicolor/16x16/linphone-micro-muted.png"
inkscape:export-xdpi="11.25"
inkscape:export-ydpi="11.25">
<metadata
id="metadata17">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>micro_default</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1133"
id="namedview15"
showgrid="false"
inkscape:zoom="2.1454545"
inkscape:cx="-69.09746"
inkscape:cy="55"
inkscape:window-x="-6"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" />
<!-- Generator: Sketch 3.3.3 (12081) - http://www.bohemiancoding.com/sketch -->
<title
id="title4">micro_default</title>
<desc
id="desc6">Created with Sketch.</desc>
<defs
id="defs8" />
<g
id="OUTILS"
sketch:type="MSPage"
style="fill:none;fill-rule:evenodd;stroke:none;stroke-width:1"
transform="matrix(1.1573849,0,0,1.1573849,13.973971,0.95399506)">
<g
id="linphone_v2.0_icones_buttons"
sketch:type="MSArtboardGroup"
transform="translate(-1684,-19406)">
<g
id="micro_default"
sketch:type="MSLayerGroup"
transform="translate(1650,19384)">
<path
d="m 60.741568,80.266982 c 0,8.687359 7.074072,15.733949 15.79633,15.733949 8.72491,0 15.798982,-7.04659 15.798982,-15.733949 l 0,-39.527749 C 92.33688,32.04659 85.262808,25 76.537898,25 67.81564,25 60.741568,32.04659 60.741568,40.739233 l 0,39.527749 0,0 z m 45.707652,-19.188548 0,17.172595 c 0,16.459216 -13.392336,29.796741 -29.911322,29.796741 m 0,0 0,18.55708 0,-18.55708 z m -9.307013,20.63116 18.618004,0 -18.618004,0 z m -20.602987,-67.600496 0,17.172595 c 0,16.459216 13.39234,29.796741 29.911326,29.796741 M 37,116.69154 117,36.987393 37,116.69154 Z"
id="micro_off"
sketch:type="MSShapeGroup"
inkscape:connector-curvature="0"
style="stroke:#444444;stroke-width:5;stroke-linecap:round;stroke-linejoin:round" />
<rect
id="Rectangle-250-Copy-6"
sketch:type="MSShapeGroup"
x="0"
y="0"
width="154"
height="154"
style="fill:#ffffff;fill-opacity:0" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

View file

@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="128"
height="128"
viewBox="0 0 128 128"
version="1.1"
id="svg2"
inkscape:version="0.91 r13725"
sodipodi:docname="linphone-speaker-enabled.svg">
<metadata
id="metadata17">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>speaker_default</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1133"
id="namedview15"
showgrid="false"
inkscape:zoom="3.1052632"
inkscape:cx="40.5"
inkscape:cy="25.118644"
inkscape:window-x="-6"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" />
<!-- Generator: Sketch 3.3.3 (12081) - http://www.bohemiancoding.com/sketch -->
<title
id="title4">speaker_default</title>
<desc
id="desc6">Created with Sketch.</desc>
<defs
id="defs8" />
<g
id="OUTILS"
sketch:type="MSPage"
style="fill:none;fill-rule:evenodd;stroke:none;stroke-width:1"
transform="matrix(1.5813339,0,0,1.5813339,0.25511819,2.6974466)">
<g
id="linphone_v2.0_icones_buttons"
sketch:type="MSArtboardGroup"
transform="translate(-1687,-19654)">
<g
id="speaker_default"
sketch:type="MSLayerGroup"
transform="translate(1650,19615)">
<path
d="m 40.603728,91.675608 22.168645,0 L 87.743025,112 l 0,-70 -24.970652,20.323222 -22.772373,0 0,29.352386 0.603728,0 0,0 z m 59.422202,-7.801955 c 4.01893,-3.972926 4.01893,-10.413137 0,-14.383722 m 9.53653,20.165288 c 7.24946,-7.164369 7.25065,-18.783656 0,-25.948024"
id="speaker_on"
sketch:type="MSShapeGroup"
inkscape:connector-curvature="0"
style="stroke:#444444;stroke-width:5;stroke-linecap:round;stroke-linejoin:round" />
<rect
id="Rectangle-250-Copy-7"
sketch:type="MSShapeGroup"
x="0"
y="0"
width="154"
height="154"
style="fill:#ffffff;fill-opacity:0" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View file

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="128"
height="128"
viewBox="0 0 128 128"
version="1.1"
id="svg2"
inkscape:version="0.91 r13725"
sodipodi:docname="linphone-speaker-muted.svg">
<metadata
id="metadata17">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>speaker_default</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1133"
id="namedview15"
showgrid="false"
inkscape:zoom="3.1052632"
inkscape:cx="-21.974575"
inkscape:cy="50.881356"
inkscape:window-x="-6"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" />
<!-- Generator: Sketch 3.3.3 (12081) - http://www.bohemiancoding.com/sketch -->
<title
id="title4">speaker_default</title>
<desc
id="desc6">Created with Sketch.</desc>
<defs
id="defs8" />
<path
style="fill:none;fill-rule:evenodd;stroke:#444444;stroke-width:7.907;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
inkscape:connector-curvature="0"
sketch:type="MSShapeGroup"
id="speaker_on"
d="m 5.9537866,85.995196 35.0560294,0 39.486939,32.139654 0,-110.6933772 -39.486939,32.1378002 -36.010725,0 0,46.415923 0.9546956,0 0,0 z M 99.920129,73.6577 c 6.355271,-6.282523 6.355271,-16.466647 0,-22.745467 m 15.080441,31.888053 c 11.46381,-11.329259 11.4657,-29.703232 0,-41.03249" />
<rect
style="fill:#ffffff;fill-opacity:0;fill-rule:evenodd;stroke:none;stroke-width:1"
height="243.52542"
width="243.52542"
y="-58.974552"
x="-58.254265"
sketch:type="MSShapeGroup"
id="Rectangle-250-Copy-7" />
<path
style="fill:none;fill-rule:evenodd;stroke:#444444;stroke-width:8;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
d="M 6.7627118,115.76271 122.05085,5.6271203"
id="path3348"
inkscape:connector-curvature="0" />
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -32,6 +32,11 @@ gtk/audio_assistant.c
[type: gettext/glade]gtk/ldap.ui
[type: gettext/glade]gtk/config-uri.ui
[type: gettext/glade]gtk/provisioning-fetch.ui
[type: gettext/glade]gtk/chatroom_frame.ui
[type: gettext/glade]gtk/callee_frame.ui
[type: gettext/glade]gtk/conf_frame.ui
[type: gettext/glade]gtk/in_call_frame.ui
[type: gettext/glade]gtk/login_frame.ui
coreapi/linphonecore.c
coreapi/misc.c
coreapi/presence.c

609
po/ar.po

File diff suppressed because it is too large Load diff

562
po/cs.po

File diff suppressed because it is too large Load diff

635
po/de.po

File diff suppressed because it is too large Load diff

553
po/es.po

File diff suppressed because it is too large Load diff

627
po/fr.po

File diff suppressed because it is too large Load diff

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