mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-01-17 11:08:06 +00:00
Merge remote-tracking branch 'public/master' into daemon
This commit is contained in:
commit
fa758db1fa
269 changed files with 32520 additions and 9494 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -103,3 +103,5 @@ tester/stereo-record.wav
|
|||
git-clang-format.diff
|
||||
*.log
|
||||
.bc_tester_utils.tmp
|
||||
tools/lp-test-ecc
|
||||
tools/lp-sendmsg
|
||||
|
|
|
|||
|
|
@ -21,13 +21,13 @@
|
|||
############################################################################
|
||||
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
project(LINPHONE C CXX)
|
||||
project(linphone VERSION 3.9.1 LANGUAGES C CXX)
|
||||
|
||||
|
||||
set(LINPHONE_MAJOR_VERSION "3")
|
||||
set(LINPHONE_MINOR_VERSION "9")
|
||||
set(LINPHONE_MICRO_VERSION "1")
|
||||
set(LINPHONE_VERSION "${LINPHONE_MAJOR_VERSION}.${LINPHONE_MINOR_VERSION}.${LINPHONE_MICRO_VERSION}")
|
||||
set(LINPHONE_MAJOR_VERSION ${PROJECT_VERSION_MAJOR})
|
||||
set(LINPHONE_MINOR_VERSION ${PROJECT_VERSION_MINOR})
|
||||
set(LINPHONE_MICRO_VERSION ${PROJECT_VERSION_PATCH})
|
||||
set(LINPHONE_VERSION ${PROJECT_VERSION})
|
||||
set(LINPHONE_SO_VERSION "8")
|
||||
|
||||
file(GLOB LINPHONE_PO_FILES RELATIVE "${CMAKE_CURRENT_LIST_DIR}/po" "${CMAKE_CURRENT_LIST_DIR}/po/*.po")
|
||||
|
|
@ -36,7 +36,8 @@ string(REPLACE ";" " " LINPHONE_ALL_LANGS "${LINPHONE_ALL_LANGS_LIST}")
|
|||
|
||||
include(CMakeDependentOption)
|
||||
|
||||
option(ENABLE_STATIC "Build static library (default is shared library)." NO)
|
||||
option(ENABLE_SHARED "Build shared library." YES)
|
||||
option(ENABLE_STATIC "Build static library." YES)
|
||||
option(ENABLE_CONSOLE_UI "Turn on or off compilation of console interface." YES)
|
||||
option(ENABLE_DATE "Use build date in internal version number." NO)
|
||||
option(ENABLE_DOC "Enable documentation generation with Doxygen." YES)
|
||||
|
|
@ -44,7 +45,7 @@ option(ENABLE_GTK_UI "Turn on or off compilation of gtk interface." YES)
|
|||
option(ENABLE_LDAP "Enable LDAP support." NO)
|
||||
option(ENABLE_LIME "Enable Instant Messaging Encryption." NO)
|
||||
option(ENABLE_MSG_STORAGE "Turn on compilation of message storage." YES)
|
||||
cmake_dependent_option(ENABLE_NOTIFY "Enable libnotify support." YES "ENABLE_GTK_UI" NO)
|
||||
cmake_dependent_option(ENABLE_NOTIFY "Enable libnotify support." YES "ENABLE_GTK_UI;NOT APPLE" NO)
|
||||
option(ENABLE_RELATIVE_PREFIX "Find resources relatively to the installation directory." NO)
|
||||
option(ENABLE_STRICT "Build with strict compile options." YES)
|
||||
option(ENABLE_TOOLS "Turn on or off compilation of tools." YES)
|
||||
|
|
@ -57,6 +58,8 @@ cmake_dependent_option(ENABLE_ASSISTANT "Turn on assistant compiling." YES "ENAB
|
|||
option(ENABLE_DEBUG_LOGS "Turn on or off debug level logs." NO)
|
||||
option(ENABLE_NLS "Build with internationalisation support" YES)
|
||||
option(ENABLE_CALL_LOGS_STORAGE "Turn on compilation of call logs storage." YES)
|
||||
option(ENABLE_FRIENDS_SQL_STORAGE "Turn on compilation of friends sql storage." YES)
|
||||
option(ENABLE_VCARD "Turn on compilation of vcard4 support." YES)
|
||||
|
||||
|
||||
macro(apply_compile_flags SOURCE_FILES)
|
||||
|
|
@ -79,6 +82,12 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
|||
|
||||
include(CheckSymbolExists)
|
||||
include(CMakePushCheckState)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
if(NOT CMAKE_INSTALL_RPATH AND CMAKE_INSTALL_PREFIX)
|
||||
set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR})
|
||||
message(STATUS "Setting install rpath to ${CMAKE_INSTALL_RPATH}")
|
||||
endif()
|
||||
|
||||
set(MSVC_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include/MSVC")
|
||||
if(MSVC)
|
||||
|
|
@ -91,26 +100,15 @@ endif()
|
|||
if(LINPHONE_BUILDER_GROUP_EXTERNAL_SOURCE_PATH_BUILDERS)
|
||||
include("${EP_bellesip_CONFIG_DIR}/BelleSIPConfig.cmake")
|
||||
include("${EP_ms2_CONFIG_DIR}/Mediastreamer2Config.cmake")
|
||||
set(BcToolbox_FIND_COMPONENTS tester)
|
||||
include("${EP_bctoolbox_CONFIG_DIR}/BcToolboxConfig.cmake")
|
||||
else()
|
||||
find_package(BelleSIP REQUIRED)
|
||||
find_package(Mediastreamer2 REQUIRED)
|
||||
find_package(BcToolbox REQUIRED OPTIONAL_COMPONENTS tester)
|
||||
endif()
|
||||
find_package(XML2 REQUIRED)
|
||||
find_package(Zlib)
|
||||
if(ENABLE_UNIT_TESTS)
|
||||
find_package(CUnit)
|
||||
if(CUNIT_FOUND)
|
||||
cmake_push_check_state(RESET)
|
||||
list(APPEND CMAKE_REQUIRED_INCLUDES ${CUNIT_INCLUDE_DIRS})
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES ${CUNIT_LIBRARIES})
|
||||
check_symbol_exists("CU_get_suite" "CUnit/CUnit.h" HAVE_CU_GET_SUITE)
|
||||
check_symbol_exists("CU_curses_run_tests" "CUnit/CUnit.h" HAVE_CU_CURSES)
|
||||
cmake_pop_check_state()
|
||||
else()
|
||||
message(WARNING "Could not find the cunit library!")
|
||||
set(ENABLE_UNIT_TESTS OFF CACHE BOOL "Enable compilation of unit tests." FORCE)
|
||||
endif()
|
||||
endif()
|
||||
if(ENABLE_TUNNEL)
|
||||
if(LINPHONE_BUILDER_GROUP_EXTERNAL_SOURCE_PATH_BUILDERS)
|
||||
include("${EP_tunnel_CONFIG_DIR}/TunnelConfig.cmake")
|
||||
|
|
@ -163,9 +161,25 @@ endif()
|
|||
if(ENABLE_CALL_LOGS_STORAGE)
|
||||
find_package(Sqlite3 REQUIRED)
|
||||
endif()
|
||||
if (ENABLE_FRIENDS_SQL_STORAGE)
|
||||
find_package(Sqlite3 REQUIRED)
|
||||
endif()
|
||||
if(ENABLE_LIME)
|
||||
set(HAVE_LIME 1)
|
||||
endif()
|
||||
if (ENABLE_VCARD)
|
||||
if(LINPHONE_BUILDER_GROUP_EXTERNAL_SOURCE_PATH_BUILDERS)
|
||||
include("${EP_belcard_CONFIG_DIR}/BelcardConfig.cmake")
|
||||
else()
|
||||
find_package(Belcard)
|
||||
endif()
|
||||
if(NOT BELCARD_FOUND)
|
||||
message(WARNING "Could not find the belcard library!")
|
||||
set(ENABLE_VCARD OFF CACHE BOOL "Enable vcard support." FORCE)
|
||||
else()
|
||||
add_definitions(-DVCARD_ENABLED)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
include(CheckIncludeFiles)
|
||||
|
|
@ -181,10 +195,14 @@ include_directories(
|
|||
${CMAKE_CURRENT_BINARY_DIR}/coreapi/
|
||||
${BELLESIP_INCLUDE_DIRS}
|
||||
${MEDIASTREAMER2_INCLUDE_DIRS}
|
||||
${BCTOOLBOX_CORE_INCLUDE_DIRS}
|
||||
)
|
||||
if(ENABLE_TUNNEL)
|
||||
include_directories(${TUNNEL_INCLUDE_DIRS})
|
||||
endif()
|
||||
if (ENABLE_VCARD)
|
||||
include_directories(${BELCARD_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
include_directories(${XML2_INCLUDE_DIRS})
|
||||
|
||||
|
|
@ -200,6 +218,9 @@ if(SQLITE3_FOUND)
|
|||
if(ENABLE_CALL_LOGS_STORAGE)
|
||||
add_definitions("-DCALL_LOGS_STORAGE_ENABLED")
|
||||
endif()
|
||||
if(ENABLE_FRIENDS_SQL_STORAGE)
|
||||
add_definitions("-DFRIENDS_SQL_STORAGE_ENABLED")
|
||||
endif()
|
||||
endif()
|
||||
if(INTL_FOUND)
|
||||
set(HAVE_INTL 1)
|
||||
|
|
@ -213,9 +234,13 @@ add_definitions("-DIN_LINPHONE")
|
|||
if(ENABLE_DEBUG_LOGS)
|
||||
add_definitions("-DDEBUG")
|
||||
endif()
|
||||
if(ANDROID)
|
||||
add_definitions("-DANDROID")
|
||||
endif()
|
||||
|
||||
set(STRICT_OPTIONS_CPP )
|
||||
set(STRICT_OPTIONS_C )
|
||||
set(STRICT_OPTIONS_CXX )
|
||||
set(STRICT_OPTIONS_OBJC )
|
||||
if(NOT MSVC)
|
||||
list(APPEND STRICT_OPTIONS_CPP "-Wall" "-Wuninitialized" "-Wno-error=deprecated-declarations")
|
||||
|
|
@ -230,6 +255,9 @@ if(NOT MSVC)
|
|||
list(APPEND STRICT_OPTIONS_CPP "-Werror" "-fno-strict-aliasing")
|
||||
endif()
|
||||
endif()
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
|
||||
list(APPEND STRICT_OPTIONS_CPP "/wd4996")
|
||||
endif()
|
||||
if(STRICT_OPTIONS_CPP)
|
||||
list(REMOVE_DUPLICATES STRICT_OPTIONS_CPP)
|
||||
endif()
|
||||
|
|
@ -244,13 +272,13 @@ if(ENABLE_RELATIVE_PREFIX)
|
|||
else()
|
||||
set(LINPHONE_DATA_DIR "${CMAKE_INSTALL_PREFIX}")
|
||||
endif()
|
||||
set(LINPHONE_PLUGINS_DIR "${LINPHONE_DATA_DIR}/lib/liblinphone/plugins")
|
||||
set(LINPHONE_PLUGINS_DIR "${LINPHONE_DATA_DIR}/${CMAKE_INSTALL_LIBDIR}/liblinphone/plugins")
|
||||
if(WIN32)
|
||||
set(LINPHONE_CONFIG_DIR "Linphone")
|
||||
endif()
|
||||
set(PACKAGE_LOCALE_DIR "${LINPHONE_DATA_DIR}/share/locale")
|
||||
set(PACKAGE_DATA_DIR "${LINPHONE_DATA_DIR}/share")
|
||||
set(PACKAGE_SOUND_DIR "${LINPHONE_DATA_DIR}/share/sounds/linphone")
|
||||
set(PACKAGE_LOCALE_DIR "${LINPHONE_DATA_DIR}/${CMAKE_INSTALL_DATADIR}/locale")
|
||||
set(PACKAGE_DATA_DIR "${LINPHONE_DATA_DIR}/${CMAKE_INSTALL_DATADIR}")
|
||||
set(PACKAGE_SOUND_DIR "${LINPHONE_DATA_DIR}/${CMAKE_INSTALL_DATADIR}/sounds/linphone")
|
||||
set(PACKAGE_RING_DIR "${PACKAGE_SOUND_DIR}/rings")
|
||||
set(PACKAGE_FREEDESKTOP_DIR "${PACKAGE_DATA_DIR}/applications")
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
|
||||
|
|
@ -270,6 +298,7 @@ else()
|
|||
endif()
|
||||
|
||||
|
||||
add_subdirectory(java)
|
||||
add_subdirectory(coreapi)
|
||||
add_subdirectory(share)
|
||||
if(ENABLE_CONSOLE_UI)
|
||||
|
|
@ -283,7 +312,7 @@ endif()
|
|||
if(ENABLE_TOOLS)
|
||||
add_subdirectory(tools)
|
||||
endif()
|
||||
if(ENABLE_UNIT_TESTS)
|
||||
if(ENABLE_UNIT_TESTS AND BCTOOLBOX_TESTER_FOUND)
|
||||
add_subdirectory(tester)
|
||||
endif()
|
||||
|
||||
|
|
@ -302,13 +331,13 @@ configure_file(cmake/LinphoneConfig.cmake.in
|
|||
@ONLY
|
||||
)
|
||||
|
||||
set(ConfigPackageLocation lib/cmake/Linphone)
|
||||
set(CONFIG_PACKAGE_LOCATION "${CMAKE_INSTALL_DATADIR}/Linphone/cmake")
|
||||
install(EXPORT ${EXPORT_TARGETS_NAME}Targets
|
||||
FILE LinphoneTargets.cmake
|
||||
DESTINATION ${ConfigPackageLocation}
|
||||
DESTINATION ${CONFIG_PACKAGE_LOCATION}
|
||||
)
|
||||
install(FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/LinphoneConfig.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/LinphoneConfigVersion.cmake"
|
||||
DESTINATION ${ConfigPackageLocation}
|
||||
DESTINATION ${CONFIG_PACKAGE_LOCATION}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -243,7 +243,7 @@ pkg: $(MACAPPNAME)
|
|||
cp ${srcdir}/pixmaps/linphone.png ./packaging
|
||||
pkgbuild --install-location /Applications --scripts ${srcdir}/build/macos/pkg-scripts --component $(MACAPPNAME) ./packaging/linphone.pkg
|
||||
productbuild --resources . --distribution ${srcdir}/build/macos/pkg-distribution.xml --package-path ./packaging $(MACAPPPKG)
|
||||
|
||||
|
||||
signed-pkg: pkg
|
||||
mv $(MACAPPPKG) $(MACAPPPKG).tmp
|
||||
productsign --sign "$(BUNDLE_SIGNING_ID)" $(MACAPPPKG).tmp $(MACAPPPKG)
|
||||
|
|
@ -258,7 +258,7 @@ clean-local:
|
|||
discovery:
|
||||
touch specs.c
|
||||
$(CC) --include $(top_builddir)/config.h \
|
||||
$(TUNNEL_CFLAGS) $(CFLAGS) $(MEDIASTREAMER2_CFLAGS) $(ORTP_CFLAGS) $(SIPSTACK_CFLAGS) $(CUNIT_CFLAGS) -E -P -v -dD specs.c
|
||||
$(TUNNEL_CFLAGS) $(CFLAGS) $(MEDIASTREAMER2_CFLAGS) $(ORTP_CFLAGS) $(SIPSTACK_CFLAGS) $(BCTOOLBOXTESTER_CFLAGS) -E -P -v -dD specs.c
|
||||
|
||||
.PHONY: $(MACAPPNAME) pkg
|
||||
|
||||
|
|
|
|||
1
README
1
README
|
|
@ -11,6 +11,7 @@ This is Linphone, a free (GPL) video softphone based on the SIP protocol.
|
|||
- belle-sip>=1.3.0
|
||||
- speex>=1.2.0 (including libspeexdsp part)
|
||||
- libxml2
|
||||
- bctoolbox
|
||||
|
||||
+ if you want the gtk/glade interface:
|
||||
- libgtk >=2.16.0
|
||||
|
|
|
|||
|
|
@ -45,14 +45,16 @@ LOCAL_SRC_FILES := \
|
|||
callbacks.c \
|
||||
call_log.c \
|
||||
call_params.c \
|
||||
carddav.c \
|
||||
chat.c \
|
||||
chat_file_transfer.c \
|
||||
conference.c \
|
||||
conference.cc \
|
||||
content.c \
|
||||
ec-calibrator.c \
|
||||
enum.c \
|
||||
event.c \
|
||||
friend.c \
|
||||
friendlist.c \
|
||||
info.c \
|
||||
linphonecall.c \
|
||||
linphonecore.c \
|
||||
|
|
@ -76,7 +78,8 @@ LOCAL_SRC_FILES := \
|
|||
xml2lpc.c \
|
||||
xml.c \
|
||||
xmlrpc.c \
|
||||
vtables.c
|
||||
vtables.c \
|
||||
ringtoneplayer.c
|
||||
|
||||
ifndef LIBLINPHONE_VERSION
|
||||
LIBLINPHONE_VERSION = "Devel"
|
||||
|
|
@ -121,11 +124,12 @@ LOCAL_C_INCLUDES += \
|
|||
$(LOCAL_PATH)/../oRTP/include \
|
||||
$(LOCAL_PATH)/../mediastreamer2/include \
|
||||
$(LOCAL_PATH)/../mediastreamer2/src/audiofilters/ \
|
||||
$(LOCAL_PATH)/../../bctoolbox/include \
|
||||
$(LOCAL_PATH)/../../belle-sip/include \
|
||||
$(LOCAL_PATH)/../../../gen \
|
||||
$(LOCAL_PATH)/../../externals/libxml2/include \
|
||||
$(LOCAL_PATH)/../../externals/build/libxml2 \
|
||||
$(LOCAL_PATH)/../../externals/polarssl/include
|
||||
$(LOCAL_PATH)/../../externals/polarssl/include \
|
||||
|
||||
LOCAL_LDLIBS += -llog -ldl -lz
|
||||
|
||||
|
|
@ -134,6 +138,7 @@ LOCAL_STATIC_LIBRARIES := \
|
|||
libmediastreamer2 \
|
||||
libortp \
|
||||
libbellesip \
|
||||
libbctoolbox \
|
||||
libgsm \
|
||||
liblpxml2
|
||||
|
||||
|
|
@ -180,33 +185,52 @@ LOCAL_CFLAGS += -DHAVE_CODEC2
|
|||
LOCAL_STATIC_LIBRARIES += libcodec2 libmscodec2
|
||||
endif
|
||||
|
||||
ifneq ($(BUILD_WEBRTC_AECM)$(BUILD_WEBRTC_ISAC),00)
|
||||
ifneq ($(BUILD_WEBRTC_AECM)$(BUILD_WEBRTC_ISAC)$(BUILD_ILBC),000)
|
||||
LOCAL_CFLAGS += -DHAVE_WEBRTC
|
||||
LOCAL_STATIC_LIBRARIES += libmswebrtc
|
||||
endif
|
||||
|
||||
ifneq ($(BUILD_WEBRTC_AECM),0)
|
||||
LOCAL_STATIC_LIBRARIES += \
|
||||
libwebrtc_aecm \
|
||||
libwebrtc_aecm
|
||||
ifeq ($(TARGET_ARCH_ABI), armeabi-v7a)
|
||||
LOCAL_STATIC_LIBRARIES += \
|
||||
libwebrtc_aecm_neon
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
ifneq ($(BUILD_WEBRTC_ISAC),0)
|
||||
LOCAL_STATIC_LIBRARIES += \
|
||||
libwebrtc_isacfix
|
||||
ifeq ($(TARGET_ARCH_ABI), armeabi-v7a)
|
||||
LOCAL_STATIC_LIBRARIES += \
|
||||
libwebrtc_isacfix_neon
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(BUILD_ILBC),0)
|
||||
LOCAL_STATIC_LIBRARIES += \
|
||||
libwebrtc_ilbc
|
||||
endif
|
||||
|
||||
|
||||
ifneq ($(BUILD_WEBRTC_AECM)$(BUILD_WEBRTC_ISAC)$(BUILD_ILBC),000)
|
||||
|
||||
LOCAL_STATIC_LIBRARIES += \
|
||||
libwebrtc_apm_utility \
|
||||
libwebrtc_system_wrappers \
|
||||
libwebrtc_apm_utility \
|
||||
libwebrtc_spl \
|
||||
libwebrtc_system_wrappers
|
||||
ifeq ($(TARGET_ARCH_ABI), armeabi-v7a)
|
||||
LOCAL_STATIC_LIBRARIES += \
|
||||
libwebrtc_aecm_neon \
|
||||
libwebrtc_spl_neon
|
||||
endif
|
||||
endif
|
||||
ifneq ($(BUILD_WEBRTC_ISAC),0)
|
||||
LOCAL_STATIC_LIBRARIES += \
|
||||
libwebrtc_isacfix \
|
||||
libwebrtc_spl
|
||||
ifeq ($(TARGET_ARCH_ABI), armeabi-v7a)
|
||||
LOCAL_STATIC_LIBRARIES += \
|
||||
libwebrtc_isacfix_neon \
|
||||
libwebrtc_spl_neon
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
|
||||
ifeq ($(BUILD_G729),1)
|
||||
LOCAL_CFLAGS += -DHAVE_G729
|
||||
LOCAL_STATIC_LIBRARIES += libbcg729 libmsbcg729
|
||||
|
|
@ -238,6 +262,10 @@ ifeq ($(BUILD_SRTP), 1)
|
|||
LOCAL_C_INCLUDES += $(SRTP_C_INCLUDE)
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_VCARD),1)
|
||||
LOCAL_C_INCLUDES += $(VCARD_C_INCLUDE)
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_ILBC), 1)
|
||||
ifneq ($(TARGET_ARCH_ABI),armeabi)
|
||||
LOCAL_CFLAGS += -DHAVE_ILBC=1
|
||||
|
|
@ -259,8 +287,16 @@ ifeq ($(BUILD_SRTP),1)
|
|||
LOCAL_STATIC_LIBRARIES += libsrtp
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_VCARD),1)
|
||||
LOCAL_CFLAGS += -DVCARD_ENABLED
|
||||
LOCAL_SRC_FILES += vcard.cc
|
||||
LOCAL_STATIC_LIBRARIES += libbelr libbelcard
|
||||
else
|
||||
LOCAL_SRC_FILES += vcard_stubs.c
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_SQLITE),1)
|
||||
LOCAL_CFLAGS += -DMSG_STORAGE_ENABLED -DCALL_LOGS_STORAGE_ENABLED
|
||||
LOCAL_CFLAGS += -DMSG_STORAGE_ENABLED -DCALL_LOGS_STORAGE_ENABLED -DFRIENDS_SQL_STORAGE_ENABLED
|
||||
LOCAL_STATIC_LIBRARIES += liblinsqlite
|
||||
LOCAL_C_INCLUDES += \
|
||||
$(LOCAL_PATH)/../../externals/sqlite3/
|
||||
|
|
@ -282,7 +318,7 @@ LOCAL_MODULE_FILENAME := liblinphone-$(TARGET_ARCH_ABI)
|
|||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
LOCAL_CPPFLAGS=$(LOCAL_CFLAGS)
|
||||
LOCAL_CPPFLAGS += $(LOCAL_CFLAGS)
|
||||
LOCAL_CFLAGS += -Wdeclaration-after-statement
|
||||
LOCAL_LDFLAGS := -Wl,-soname,$(LOCAL_MODULE_FILENAME).so
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
LOCAL_PATH := $(call my-dir)/../../tester
|
||||
|
||||
common_SRC_FILES := \
|
||||
common/bc_tester_utils.c \
|
||||
accountmanager.c \
|
||||
call_tester.c \
|
||||
dtmf_tester.c \
|
||||
|
|
@ -24,14 +23,15 @@ common_SRC_FILES := \
|
|||
tunnel_tester.c \
|
||||
upnp_tester.c \
|
||||
multicast_call_tester.c \
|
||||
vcard_tester.c \
|
||||
complex_sip_call_tester.c \
|
||||
|
||||
common_C_INCLUDES += \
|
||||
$(LOCAL_PATH) \
|
||||
$(LOCAL_PATH)/../include \
|
||||
$(LOCAL_PATH)/../coreapi \
|
||||
$(LOCAL_PATH)/../oRTP/include \
|
||||
$(LOCAL_PATH)/../mediastreamer2/include \
|
||||
$(LOCAL_PATH)/common
|
||||
$(LOCAL_PATH)/../mediastreamer2/include
|
||||
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
|
@ -47,6 +47,8 @@ ifeq ($(BUILD_MATROSKA), 1)
|
|||
LOCAL_CFLAGS += -DHAVE_MATROSKA -DHAVE_ZLIB
|
||||
endif
|
||||
|
||||
LOCAL_STATIC_LIBRARIES := bctoolbox_tester
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := cunit liblinphone
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
|
|
|
|||
|
|
@ -187,12 +187,12 @@
|
|||
${project}/../../gtk/gtkrc.mac
|
||||
</data>
|
||||
|
||||
<data dest="${bundle}/Contents/Resources/share/sounds/linphone/rings/oldphone.wav">
|
||||
${prefix:linphone}/share/sounds/linphone/rings/oldphone.wav
|
||||
<data dest="${bundle}/Contents/Resources/share/sounds/linphone/rings/oldphone-mono.wav">
|
||||
${prefix:linphone}/share/sounds/linphone/rings/oldphone-mono.wav
|
||||
</data>
|
||||
|
||||
<data dest="${bundle}/Contents/Resources/share/sounds/linphone/rings/toy-mono.wav">
|
||||
${prefix:linphone}/share/sounds/linphone/rings/toy-mono.wav
|
||||
<data dest="${bundle}/Contents/Resources/share/sounds/linphone/toy-mono.wav">
|
||||
${prefix:linphone}/share/sounds/linphone/toy-mono.wav
|
||||
</data>
|
||||
|
||||
<data dest="${bundle}/Contents/Resources/share/sounds/linphone/ringback.wav">
|
||||
|
|
|
|||
|
|
@ -277,6 +277,12 @@
|
|||
<Content Include="Assets\certificates\cn\openssl-cn.cnf">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Assets\common\vcards.vcf">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Assets\common\thousand_vcards.vcf">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Assets\Logo.png" />
|
||||
<Content Include="Assets\SmallLogo.png" />
|
||||
<Content Include="Assets\SplashScreen.png" />
|
||||
|
|
@ -309,7 +315,8 @@ XCopy /I /Y $(ProjectDir)..\..\..\tester\certificates\altname $(ProjectDir)Asset
|
|||
XCopy /I /Y $(ProjectDir)..\..\..\tester\certificates\cn $(ProjectDir)Assets\certificates\cn
|
||||
XCopy /I /Y $(ProjectDir)..\..\..\tester\images $(ProjectDir)Assets\images
|
||||
XCopy /I /Y $(ProjectDir)..\..\..\tester\rcfiles $(ProjectDir)Assets\rcfiles
|
||||
XCopy /I /Y $(ProjectDir)..\..\..\tester\sounds $(ProjectDir)Assets\sounds</PreBuildEvent>
|
||||
XCopy /I /Y $(ProjectDir)..\..\..\tester\sounds $(ProjectDir)Assets\sounds
|
||||
XCopy /I /Y $(ProjectDir)..\..\..\tester\common $(ProjectDir)Assets\common</PreBuildEvent>
|
||||
</PropertyGroup>
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
|
|
@ -318,4 +325,4 @@ XCopy /I /Y $(ProjectDir)..\..\..\tester\sounds $(ProjectDir)Assets\sounds</PreB
|
|||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -1,58 +0,0 @@
|
|||
############################################################################
|
||||
# FindCUnit.txt
|
||||
# Copyright (C) 2015 Belledonne Communications, Grenoble France
|
||||
#
|
||||
############################################################################
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
############################################################################
|
||||
#
|
||||
# - Find the CUnit include file and library
|
||||
#
|
||||
# CUNIT_FOUND - system has CUnit
|
||||
# CUNIT_INCLUDE_DIRS - the CUnit include directory
|
||||
# CUNIT_LIBRARIES - The libraries needed to use CUnit
|
||||
|
||||
include(CheckIncludeFile)
|
||||
include(CheckLibraryExists)
|
||||
|
||||
set(_CUNIT_ROOT_PATHS
|
||||
${CMAKE_INSTALL_PREFIX}
|
||||
)
|
||||
|
||||
find_path(CUNIT_INCLUDE_DIRS
|
||||
NAMES CUnit/CUnit.h
|
||||
HINTS _CUNIT_ROOT_PATHS
|
||||
PATH_SUFFIXES include
|
||||
)
|
||||
|
||||
if(CUNIT_INCLUDE_DIRS)
|
||||
set(HAVE_CUNIT_CUNIT_H 1)
|
||||
endif()
|
||||
|
||||
find_library(CUNIT_LIBRARIES
|
||||
NAMES cunit
|
||||
HINTS ${_CUNIT_ROOT_PATHS}
|
||||
PATH_SUFFIXES bin lib
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(CUnit
|
||||
DEFAULT_MSG
|
||||
CUNIT_INCLUDE_DIRS CUNIT_LIBRARIES
|
||||
)
|
||||
|
||||
mark_as_advanced(CUNIT_INCLUDE_DIRS CUNIT_LIBRARIES)
|
||||
|
|
@ -26,10 +26,6 @@
|
|||
# ZLIB_INCLUDE_DIRS - the zlib include directory
|
||||
# ZLIB_LIBRARIES - The libraries needed to use zlib
|
||||
|
||||
set(_ZLIB_ROOT_PATHS
|
||||
${CMAKE_INSTALL_PREFIX}
|
||||
)
|
||||
|
||||
find_path(ZLIB_INCLUDE_DIRS
|
||||
NAMES zlib.h
|
||||
HINTS _ZLIB_ROOT_PATHS
|
||||
|
|
@ -41,20 +37,13 @@ if(ZLIB_INCLUDE_DIRS)
|
|||
endif()
|
||||
|
||||
if(ENABLE_STATIC)
|
||||
if(IOS OR QNX)
|
||||
set(_ZLIB_STATIC_NAMES z)
|
||||
else()
|
||||
set(_ZLIB_STATIC_NAMES zstatic zlibstatic zlibstaticd)
|
||||
endif()
|
||||
find_library(ZLIB_LIBRARIES
|
||||
NAMES ${_ZLIB_STATIC_NAMES}
|
||||
HINTS ${_ZLIB_ROOT_PATHS}
|
||||
NAMES zstatic zlibstatic zlibstaticd z
|
||||
PATH_SUFFIXES bin lib
|
||||
)
|
||||
else()
|
||||
find_library(ZLIB_LIBRARIES
|
||||
NAMES z zlib zlibd
|
||||
HINTS ${_ZLIB_ROOT_PATHS}
|
||||
PATH_SUFFIXES bin lib
|
||||
)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -36,12 +36,27 @@ endif()
|
|||
find_package(Mediastreamer2 REQUIRED)
|
||||
find_package(BelleSIP REQUIRED)
|
||||
if(@ENABLE_TUNNEL@)
|
||||
find_package(Tunnel)
|
||||
if(LINPHONE_BUILDER_GROUP_EXTERNAL_SOURCE_PATH_BUILDERS)
|
||||
include("${EP_tunnel_CONFIG_DIR}/TunnelConfig.cmake")
|
||||
else()
|
||||
find_package(Tunnel)
|
||||
endif()
|
||||
endif()
|
||||
if(@ENABLE_VCARD@)
|
||||
if(LINPHONE_BUILDER_GROUP_EXTERNAL_SOURCE_PATH_BUILDERS)
|
||||
include("${EP_belcard_CONFIG_DIR}/BelcardConfig.cmake")
|
||||
else()
|
||||
find_package(Belcard)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
get_filename_component(LINPHONE_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
||||
set(LINPHONE_INCLUDE_DIRS "${LINPHONE_CMAKE_DIR}/../../../include")
|
||||
set(LINPHONE_LIBRARIES linphone)
|
||||
if(@ENABLE_SHARED@)
|
||||
set(LINPHONE_LIBRARIES linphone)
|
||||
else()
|
||||
set(LINPHONE_LIBRARIES linphone-static)
|
||||
endif()
|
||||
set(LINPHONE_LDFLAGS @LINK_FLAGS@)
|
||||
list(APPEND LINPHONE_INCLUDE_DIRS ${MEDIASTREAMER2_INCLUDE_DIRS} ${BELLESIP_INCLUDE_DIRS})
|
||||
list(APPEND LINPHONE_LIBRARIES ${MEDIASTREAMER2_LIBRARIES} ${BELLESIP_LIBRARIES})
|
||||
|
|
@ -51,4 +66,8 @@ if(TUNNEL_FOUND)
|
|||
list(APPEND LINPHONE_INCLUDE_DIRS ${TUNNEL_INCLUDE_DIRS})
|
||||
list(APPEND LINPHONE_LIBRARIES ${TUNNEL_LIBRARIES})
|
||||
endif()
|
||||
if(BELCARD_FOUND)
|
||||
list(APPEND LINPHONE_INCLUDE_DIRS ${BELCARD_INCLUDE_DIRS})
|
||||
list(APPEND LINPHONE_LIBRARIES ${BELCARD_LIBRARIES})
|
||||
endif()
|
||||
set(LINPHONE_FOUND 1)
|
||||
|
|
|
|||
117
configure.ac
117
configure.ac
|
|
@ -17,7 +17,7 @@ if test "$LINPHONE_EXTRA_VERSION" != "" ;then
|
|||
LINPHONE_VERSION=$LINPHONE_VERSION.${LINPHONE_EXTRA_VERSION}
|
||||
fi
|
||||
|
||||
LIBLINPHONE_SO_CURRENT=8 dnl increment this number when you add/change/remove an interface
|
||||
LIBLINPHONE_SO_CURRENT=9 dnl increment this number when you add/change/remove an interface
|
||||
LIBLINPHONE_SO_REVISION=0 dnl increment this number when you change source code, without changing interfaces; set to 0 when incrementing CURRENT
|
||||
LIBLINPHONE_SO_AGE=0 dnl increment this number when you add an interface, set to 0 if you remove an interface
|
||||
|
||||
|
|
@ -39,6 +39,7 @@ AC_CONFIG_MACRO_DIR([m4])
|
|||
dnl do not put anythingelse before AC_PROG_CC unless checking if macro still work for clang
|
||||
AC_PROG_CXX(["xcrun clang++" g++])
|
||||
AC_PROG_CC(["xcrun clang" gcc])
|
||||
AC_PROG_OBJC(["xcrun clang" gcc])
|
||||
|
||||
gl_LD_OUTPUT_DEF
|
||||
|
||||
|
|
@ -595,6 +596,8 @@ AC_ARG_WITH(ffmpeg,
|
|||
[ ffmpegdir=/usr ]
|
||||
)
|
||||
|
||||
AM_CONDITIONAL([BUILD_MACOS], [test "x$build_macos" = "xyes"])
|
||||
|
||||
if test "$video" = "true"; then
|
||||
|
||||
if test "$enable_x11" = "true"; then
|
||||
|
|
@ -877,6 +880,40 @@ if test x$enable_tunnel = xtrue; then
|
|||
AC_DEFINE(TUNNEL_ENABLED,1,[Tells tunnel extension is built-in])
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(vcard,
|
||||
[AS_HELP_STRING([--enable-vcard=[yes/no]], [Turn on compilation of vcard (default=auto)])],
|
||||
[case "${enableval}" in
|
||||
yes) enable_vcard=true ;;
|
||||
no) enable_vcard=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-vcard) ;;
|
||||
esac],
|
||||
[enable_vcard=auto]
|
||||
)
|
||||
|
||||
if test x$enable_vcard != xfalse; then
|
||||
PKG_CHECK_MODULES(BELCARD, belcard, [found_vcard=yes],[found_vcard=no])
|
||||
if test "$found_vcard" = "no"; then
|
||||
dnl Check the lib presence in case the PKG-CONFIG version is not found
|
||||
AC_LANG_CPLUSPLUS
|
||||
AC_CHECK_LIB(belcard, main, [BELCARD_LIBS+=" -lbelr -lbelcard"; found_vcard=yes], [foo=bar])
|
||||
AC_LANG_C
|
||||
fi
|
||||
if test "$found_vcard" = "yes"; then
|
||||
BELCARD_CFLAGS+=" -DVCARD_ENABLED"
|
||||
enable_vcard=true
|
||||
else
|
||||
if test x$enable_vcard = xtrue; then
|
||||
AC_MSG_ERROR([belcard, required for vcard support, not found])
|
||||
fi
|
||||
enable_vcard=false
|
||||
fi
|
||||
|
||||
AC_SUBST(BELCARD_CFLAGS)
|
||||
AC_SUBST(BELCARD_LIBS)
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL(BUILD_VCARD, test x$enable_vcard = xtrue)
|
||||
|
||||
AC_ARG_ENABLE(msg-storage,
|
||||
[AS_HELP_STRING([--enable-msg-storage=[yes/no]], [Turn on compilation of message storage (default=auto)])],
|
||||
[case "${enableval}" in
|
||||
|
|
@ -947,6 +984,41 @@ fi
|
|||
|
||||
AM_CONDITIONAL(BUILD_CALL_LOGS_STORAGE, test x$enable_call_logs_storage = xtrue)
|
||||
|
||||
AC_ARG_ENABLE(friends-db-storage,
|
||||
[AS_HELP_STRING([--enable-friends-db-storage=[yes/no]], [Turn on compilation of friends database storage (default=auto)])],
|
||||
[case "${enableval}" in
|
||||
yes) enable_friends_db_storage=true ;;
|
||||
no) enable_friends_db_storage=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-friends-db-storage) ;;
|
||||
esac],
|
||||
[enable_friends_db_storage=auto]
|
||||
)
|
||||
|
||||
if test x$enable_friends_db_storage != xfalse; then
|
||||
PKG_CHECK_MODULES(SQLITE3,[sqlite3 >= 3.6.0],[found_sqlite=yes],[found_sqlite=no])
|
||||
if test "$found_sqlite" = "no"; then
|
||||
dnl Check the lib presence in case the PKG-CONFIG version is not found
|
||||
AC_CHECK_LIB(sqlite3, sqlite3_open, [SQLITE3_LIBS+=" -lsqlite3 "; found_sqlite=yes], [foo=bar])
|
||||
fi
|
||||
if test "$found_sqlite" = "yes"; then
|
||||
SQLITE3_CFLAGS+=" -DFRIENDS_SQL_STORAGE_ENABLED"
|
||||
if test "$build_macos" = "yes" -o "$ios_found" = "yes"; then
|
||||
SQLITE3_LIBS+=" -liconv"
|
||||
fi
|
||||
enable_friends_db_storage=true
|
||||
else
|
||||
if test x$enable_friends_db_storage = xtrue; then
|
||||
AC_MSG_ERROR([sqlite3, required for friends database storage, not found])
|
||||
fi
|
||||
enable_friends_db_storage=false
|
||||
fi
|
||||
|
||||
AC_SUBST(SQLITE3_CFLAGS)
|
||||
AC_SUBST(SQLITE3_LIBS)
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL(BUILD_FRIENDS_DB_STORAGE, test x$enable_friends_db_storage = xtrue)
|
||||
|
||||
PKG_CHECK_MODULES(BELLESIP, [belle-sip >= 1.4.0])
|
||||
|
||||
SIPSTACK_CFLAGS="$BELLESIP_CFLAGS"
|
||||
|
|
@ -997,44 +1069,13 @@ AC_ARG_ENABLE(tests,
|
|||
)
|
||||
AM_CONDITIONAL(ENABLE_TESTS, test x$tests_enabled = xyes)
|
||||
|
||||
PKG_CHECK_MODULES(CUNIT, cunit, [found_cunit=yes],[found_cunit=no])
|
||||
PKG_CHECK_MODULES(BCTOOLBOXTESTER, bctoolbox-tester, [found_pkg_config_bctoolboxtester=yes],[found_pkg_config_bctoolboxtester=no])
|
||||
|
||||
if test "$found_cunit" = "no" ; then
|
||||
AC_CHECK_HEADERS(CUnit/CUnit.h,
|
||||
[
|
||||
AC_CHECK_LIB(cunit,CU_add_suite,[
|
||||
found_cunit=yes
|
||||
CUNIT_LIBS+=" -lcunit"
|
||||
])
|
||||
|
||||
])
|
||||
AM_CONDITIONAL([ENABLE_TESTS], [test x$found_pkg_config_bctoolboxtester = xyes && test x$tests_enabled != xfalse])
|
||||
if test "$found_pkg_config_bctoolboxtester" = "no" ; then
|
||||
AC_MSG_WARN([Could not find bctoolbox-tester wrapper, tests are not compiled.])
|
||||
fi
|
||||
|
||||
case "$target_os" in
|
||||
*darwin*)
|
||||
#hack for macport
|
||||
CUNIT_LIBS+=" -lncurses"
|
||||
;;
|
||||
esac
|
||||
AM_CONDITIONAL([BUILD_CUNIT_TESTS], [test x$found_cunit = xyes && test x$tests_enabled != xfalse])
|
||||
if test "$found_cunit" = "no" ; then
|
||||
AC_MSG_WARN([Could not find cunit framework, tests are not compiled.])
|
||||
else
|
||||
AC_CHECK_LIB(cunit,CU_get_suite,[
|
||||
AC_DEFINE(HAVE_CU_GET_SUITE,1,[defined when CU_get_suite is available])
|
||||
],[foo=bar],[$CUNIT_LIBS])
|
||||
|
||||
AC_CHECK_LIB(cunit,CU_curses_run_tests,[
|
||||
AC_DEFINE(HAVE_CU_CURSES,1,[defined when CU_curses_run_tests is available])
|
||||
],[foo=bar],[$CUNIT_LIBS])
|
||||
fi
|
||||
|
||||
case "$target_os" in
|
||||
*linux*)
|
||||
# Eliminate -lstdc++ addition to postdeps for cross compiles.
|
||||
postdeps_CXX=`echo " $postdeps_CXX " | sed 's, -lstdc++ ,,g'`
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
dnl ##################################################
|
||||
|
|
@ -1106,7 +1147,9 @@ printf "* %-30s %s\n" "Account assistant" $build_wizard
|
|||
printf "* %-30s %s\n" "Console interface" $console_ui
|
||||
printf "* %-30s %s\n" "Tools" $build_tools
|
||||
printf "* %-30s %s\n" "Message storage" $enable_msg_storage
|
||||
printf "* %-30s %s\n" "Call logs storage" $enable_call_logs_storage
|
||||
printf "* %-30s %s\n" "Call logs storage" $enable_call_logs_storage
|
||||
printf "* %-30s %s\n" "Friends db storage" $enable_friends_db_storage
|
||||
printf "* %-30s %s\n" "VCard support" $enable_vcard
|
||||
printf "* %-30s %s\n" "IM encryption" $lime
|
||||
printf "* %-30s %s\n" "uPnP support" $build_upnp
|
||||
printf "* %-30s %s\n" "LDAP support" $enable_ldap
|
||||
|
|
|
|||
|
|
@ -47,8 +47,8 @@ if(WIN32)
|
|||
endif()
|
||||
|
||||
install(TARGETS ${INSTALL_TARGETS}
|
||||
RUNTIME DESTINATION bin
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
|
||||
)
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
#include "linphonec.h"
|
||||
#include "lpconfig.h"
|
||||
|
||||
#ifndef WIN32
|
||||
#ifndef _WIN32
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
|
@ -118,7 +118,7 @@ static void linphonec_friend_display(LinphoneFriend *fr);
|
|||
static int linphonec_friend_list(LinphoneCore *lc, char *arg);
|
||||
static void linphonec_display_command_help(LPC_COMMAND *cmd);
|
||||
static int linphonec_friend_call(LinphoneCore *lc, unsigned int num);
|
||||
#ifndef WIN32
|
||||
#ifndef _WIN32
|
||||
static int linphonec_friend_add(LinphoneCore *lc, const char *name, const char *addr);
|
||||
#endif
|
||||
static int linphonec_friend_delete(LinphoneCore *lc, int num);
|
||||
|
|
@ -287,10 +287,10 @@ static LPC_COMMAND advanced_commands[] = {
|
|||
"'codec list' : list audio codecs\n"
|
||||
"'codec enable <index>' : enable available audio codec\n"
|
||||
"'codec disable <index>' : disable audio codec" },
|
||||
{ "vcodec", lpc_cmd_vcodec, "Video codec configuration",
|
||||
"'vcodec list' : list video codecs\n"
|
||||
"'vcodec enable <index>' : enable available video codec\n"
|
||||
"'vcodec disable <index>' : disable video codec" },
|
||||
{ "vcodec", lpc_cmd_vcodec, "Video codec configuration",
|
||||
"'vcodec list' : list video codecs\n"
|
||||
"'vcodec enable <index>' : enable available video codec\n"
|
||||
"'vcodec disable <index>' : disable video codec" },
|
||||
{ "ec", lpc_cmd_echocancellation, "Echo cancellation",
|
||||
"'ec on [<delay>] [<tail>] [<framesize>]' : turn EC on with given delay, tail length and framesize\n"
|
||||
"'ec off' : turn echo cancellation (EC) off\n"
|
||||
|
|
@ -367,7 +367,8 @@ static LPC_COMMAND advanced_commands[] = {
|
|||
"'ringback disable'\t: Disable playing of ringback tone to callers\n"
|
||||
},
|
||||
{ "redirect", lpc_cmd_redirect, "Redirect an incoming call",
|
||||
"'redirect <redirect-uri>'\t: Redirect all pending incoming calls to the <redirect-uri>\n"
|
||||
"'redirect <id> <redirect-uri>'\t: Redirect the specified call to the <redirect-uri>\n"
|
||||
"'redirect all <redirect-uri>'\t: Redirect all pending incoming calls to the <redirect-uri>\n"
|
||||
},
|
||||
{ "zrtp-set-verified", lpc_cmd_zrtp_verified,"Set ZRTP SAS verified.",
|
||||
"'Set ZRTP SAS verified'\n"
|
||||
|
|
@ -414,7 +415,8 @@ linphonec_parse_command_line(LinphoneCore *lc, char *cl)
|
|||
{
|
||||
while ( isdigit(*cl) || *cl == '#' || *cl == '*' )
|
||||
{
|
||||
linphone_core_send_dtmf(lc, *cl);
|
||||
if (linphone_core_get_current_call(lc))
|
||||
linphone_call_send_dtmf(linphone_core_get_current_call(lc), *cl);
|
||||
linphone_core_play_dtmf (lc,*cl,100);
|
||||
ms_sleep(1); // be nice
|
||||
++cl;
|
||||
|
|
@ -739,17 +741,37 @@ lpc_cmd_redirect(LinphoneCore *lc, char *args){
|
|||
linphonec_out("No active calls.\n");
|
||||
return 1;
|
||||
}
|
||||
while(elem!=NULL){
|
||||
LinphoneCall *call=(LinphoneCall*)elem->data;
|
||||
if (linphone_call_get_state(call)==LinphoneCallIncomingReceived){
|
||||
linphone_core_redirect_call(lc,call,args);
|
||||
didit=1;
|
||||
/*as the redirection closes the call, we need to re-check the call list that is invalidated.*/
|
||||
elem=linphone_core_get_calls(lc);
|
||||
}else elem=elem->next;
|
||||
}
|
||||
if (didit==0){
|
||||
linphonec_out("There is no pending incoming call to redirect.");
|
||||
if (strncmp(args, "all ", 4) == 0) {
|
||||
while(elem!=NULL){
|
||||
LinphoneCall *call=(LinphoneCall*)elem->data;
|
||||
if (linphone_call_get_state(call)==LinphoneCallIncomingReceived){
|
||||
if (linphone_core_redirect_call(lc,call,args+4) != 0) {
|
||||
linphonec_out("Could not redirect call.\n");
|
||||
elem=elem->next;
|
||||
} else {
|
||||
didit=1;
|
||||
/*as the redirection closes the call, we need to re-check the call list that is invalidated.*/
|
||||
elem=linphone_core_get_calls(lc);
|
||||
}
|
||||
}else elem=elem->next;
|
||||
}
|
||||
if (didit==0){
|
||||
linphonec_out("There is no pending incoming call to redirect.\n");
|
||||
}
|
||||
} else {
|
||||
char space;
|
||||
long id;
|
||||
int charRead;
|
||||
if ( sscanf(args, "%li%c%n", &id, &space, &charRead) == 2 && space == ' ') {
|
||||
LinphoneCall * call = linphonec_get_call(id);
|
||||
if ( call != NULL ) {
|
||||
if (linphone_call_get_state(call)!=LinphoneCallIncomingReceived) {
|
||||
linphonec_out("The state of the call is not incoming, can't be redirected.\n");
|
||||
} else if (linphone_core_redirect_call(lc,call,args+charRead) != 0) {
|
||||
linphonec_out("Could not redirect call.\n");
|
||||
}
|
||||
}
|
||||
} else return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -927,7 +949,7 @@ lpc_cmd_firewall(LinphoneCore *lc, char *args)
|
|||
return 1;
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
#ifndef _WIN32
|
||||
/* Helper function for processing freind names */
|
||||
static int
|
||||
lpc_friend_name(char **args, char **name)
|
||||
|
|
@ -1012,7 +1034,7 @@ lpc_cmd_friend(LinphoneCore *lc, char *args)
|
|||
}
|
||||
else if ( !strncmp(args, "add", 3) )
|
||||
{
|
||||
#ifndef WIN32
|
||||
#ifndef _WIN32
|
||||
char *name;
|
||||
char addr[80];
|
||||
char *addr_p = addr;
|
||||
|
|
@ -1040,7 +1062,7 @@ lpc_cmd_friend(LinphoneCore *lc, char *args)
|
|||
linphonec_friend_add(lc, name, addr);
|
||||
#else
|
||||
LinphoneFriend *new_friend;
|
||||
new_friend = linphone_friend_new_with_address(args);
|
||||
new_friend = linphone_core_create_friend_with_address(lc, args);
|
||||
linphone_core_add_friend(lc, new_friend);
|
||||
#endif
|
||||
return 1;
|
||||
|
|
@ -1242,12 +1264,16 @@ static int lpc_cmd_soundcard(LinphoneCore *lc, char *args)
|
|||
|
||||
if (strcmp(arg1, "show")==0)
|
||||
{
|
||||
linphonec_out("Ringer device: %s\n",
|
||||
linphone_core_get_ringer_device(lc));
|
||||
linphonec_out("Playback device: %s\n",
|
||||
linphone_core_get_playback_device(lc));
|
||||
linphonec_out("Capture device: %s\n",
|
||||
linphone_core_get_capture_device(lc));
|
||||
if (linphone_core_get_use_files(lc)) {
|
||||
linphonec_out("Using files.\n");
|
||||
} else {
|
||||
linphonec_out("Ringer device: %s\n",
|
||||
linphone_core_get_ringer_device(lc));
|
||||
linphonec_out("Playback device: %s\n",
|
||||
linphone_core_get_playback_device(lc));
|
||||
linphonec_out("Capture device: %s\n",
|
||||
linphone_core_get_capture_device(lc));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -1260,6 +1286,8 @@ static int lpc_cmd_soundcard(LinphoneCore *lc, char *args)
|
|||
return 1;
|
||||
}
|
||||
|
||||
linphone_core_use_files(lc,FALSE);
|
||||
|
||||
dev=linphone_core_get_sound_devices(lc);
|
||||
index=atoi(arg2); /* FIXME: handle not-a-number */
|
||||
for(i=0;dev[i]!=NULL;i++)
|
||||
|
|
@ -1275,6 +1303,7 @@ static int lpc_cmd_soundcard(LinphoneCore *lc, char *args)
|
|||
linphonec_out("No such sound device\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strcmp(arg1, "capture")==0)
|
||||
{
|
||||
const char *devname=linphone_core_get_capture_device(lc);
|
||||
|
|
@ -1857,7 +1886,7 @@ linphonec_friend_call(LinphoneCore *lc, unsigned int num)
|
|||
return 1;
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
#ifndef _WIN32
|
||||
static int
|
||||
linphonec_friend_add(LinphoneCore *lc, const char *name, const char *addr)
|
||||
{
|
||||
|
|
@ -1866,7 +1895,7 @@ linphonec_friend_add(LinphoneCore *lc, const char *name, const char *addr)
|
|||
char url[PATH_MAX];
|
||||
|
||||
snprintf(url, PATH_MAX, "%s <%s>", name, addr);
|
||||
newFriend = linphone_friend_new_with_address(url);
|
||||
newFriend = linphone_core_create_friend_with_address(lc, url);
|
||||
linphone_core_add_friend(lc, newFriend);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1917,8 +1946,7 @@ static int lpc_cmd_register(LinphoneCore *lc, char *args){
|
|||
if (!args)
|
||||
{
|
||||
/* it means that you want to register the default proxy */
|
||||
LinphoneProxyConfig *cfg=NULL;
|
||||
linphone_core_get_default_proxy(lc,&cfg);
|
||||
LinphoneProxyConfig *cfg = linphone_core_get_default_proxy_config(lc);
|
||||
if (cfg)
|
||||
{
|
||||
if(!linphone_proxy_config_is_registered(cfg)) {
|
||||
|
|
@ -1965,8 +1993,7 @@ static int lpc_cmd_register(LinphoneCore *lc, char *args){
|
|||
}
|
||||
|
||||
static int lpc_cmd_unregister(LinphoneCore *lc, char *args){
|
||||
LinphoneProxyConfig *cfg=NULL;
|
||||
linphone_core_get_default_proxy(lc,&cfg);
|
||||
LinphoneProxyConfig *cfg = linphone_core_get_default_proxy_config(lc);
|
||||
if (cfg && linphone_proxy_config_is_registered(cfg)) {
|
||||
linphone_proxy_config_edit(cfg);
|
||||
linphone_proxy_config_enable_register(cfg,FALSE);
|
||||
|
|
@ -1994,7 +2021,7 @@ static int lpc_cmd_status(LinphoneCore *lc, char *args)
|
|||
LinphoneProxyConfig *cfg;
|
||||
|
||||
if ( ! args ) return 0;
|
||||
linphone_core_get_default_proxy(lc,&cfg);
|
||||
cfg = linphone_core_get_default_proxy_config(lc);
|
||||
if (strstr(args,"register"))
|
||||
{
|
||||
if (cfg)
|
||||
|
|
@ -2110,7 +2137,7 @@ static int lpc_cmd_param(LinphoneCore *lc, char *args)
|
|||
}
|
||||
|
||||
static int lpc_cmd_speak(LinphoneCore *lc, char *args){
|
||||
#ifndef WIN32
|
||||
#ifndef _WIN32
|
||||
char voice[64];
|
||||
char *sentence;
|
||||
char cl[128];
|
||||
|
|
@ -2336,12 +2363,12 @@ static int lpc_cmd_echolimiter(LinphoneCore *lc, char *args){
|
|||
|
||||
static int lpc_cmd_mute_mic(LinphoneCore *lc, char *args)
|
||||
{
|
||||
linphone_core_mute_mic(lc, 1);
|
||||
linphone_core_enable_mic(lc, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lpc_cmd_unmute_mic(LinphoneCore *lc, char *args){
|
||||
linphone_core_mute_mic(lc, 0);
|
||||
linphone_core_enable_mic(lc, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -2452,7 +2479,7 @@ static void lpc_display_call_states(LinphoneCore *lc){
|
|||
const char *flag;
|
||||
bool_t in_conference;
|
||||
call=(LinphoneCall*)elem->data;
|
||||
in_conference=linphone_call_params_get_local_conference_mode(linphone_call_get_current_params(call));
|
||||
in_conference=(linphone_call_get_conference(call) != NULL);
|
||||
tmp=linphone_call_get_remote_address_as_string (call);
|
||||
flag=in_conference ? "conferencing" : "";
|
||||
flag=linphone_call_has_transfer_pending(call) ? "transfer pending" : flag;
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@
|
|||
|
||||
#include "linphonec.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef _WIN32
|
||||
#include <ws2tcpip.h>
|
||||
#include <ctype.h>
|
||||
#ifndef _WIN32_WCE
|
||||
|
|
@ -102,7 +102,7 @@ static int linphonec_main_loop (LinphoneCore * opm);
|
|||
static int linphonec_idle_call (void);
|
||||
#ifdef HAVE_READLINE
|
||||
static int linphonec_initialize_readline(void);
|
||||
static int linphonec_finish_readline();
|
||||
static int linphonec_finish_readline(void);
|
||||
static char **linephonec_readline_completion(const char *text,
|
||||
int start, int end);
|
||||
#endif
|
||||
|
|
@ -439,7 +439,7 @@ static void start_prompt_reader(void){
|
|||
#if !defined(_WIN32_WCE)
|
||||
static ortp_pipe_t create_server_socket(void){
|
||||
char path[128];
|
||||
#ifndef WIN32
|
||||
#ifndef _WIN32
|
||||
snprintf(path,sizeof(path)-1,"linphonec-%i",getuid());
|
||||
#else
|
||||
{
|
||||
|
|
@ -459,7 +459,7 @@ static void *pipe_thread(void*p){
|
|||
if (server_sock==ORTP_PIPE_INVALID) return NULL;
|
||||
while(pipe_reader_run){
|
||||
while(client_sock!=ORTP_PIPE_INVALID){ /*sleep until the last command is finished*/
|
||||
#ifndef WIN32
|
||||
#ifndef _WIN32
|
||||
usleep(20000);
|
||||
#else
|
||||
Sleep(20);
|
||||
|
|
@ -537,7 +537,7 @@ char *linphonec_readline(char *prompt){
|
|||
}
|
||||
ms_mutex_unlock(&prompt_mutex);
|
||||
linphonec_idle_call();
|
||||
#ifdef WIN32
|
||||
#ifdef _WIN32
|
||||
{
|
||||
MSG msg;
|
||||
Sleep(20);
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef _WIN32
|
||||
#include <ws2tcpip.h>
|
||||
#include <windows.h>
|
||||
#include <winbase.h>
|
||||
|
|
@ -82,7 +82,7 @@ static int send_command(const char *command, char *reply, int reply_len, int pri
|
|||
int i;
|
||||
int err;
|
||||
char path[128];
|
||||
#ifndef WIN32
|
||||
#ifndef _WIN32
|
||||
snprintf(path,sizeof(path)-1,"linphonec-%i",getuid());
|
||||
#else
|
||||
{
|
||||
|
|
@ -130,7 +130,7 @@ static void print_usage(void){
|
|||
exit(-1);
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef _WIN32
|
||||
static char *argv_to_line(int argc, char *argv[]) {
|
||||
int i;
|
||||
int line_length;
|
||||
|
|
@ -157,7 +157,7 @@ static char *argv_to_line(int argc, char *argv[]) {
|
|||
|
||||
#define MAX_ARGS 10
|
||||
|
||||
#ifndef WIN32
|
||||
#ifndef _WIN32
|
||||
static void spawn_linphonec(int argc, char *argv[]){
|
||||
char * args[MAX_ARGS];
|
||||
int i,j;
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ void call_accept(Call *call)
|
|||
sdp_context_t *ctx;
|
||||
PayloadType *payload;
|
||||
char *hellofile;
|
||||
static int call_count=0;
|
||||
static int call_count=0;
|
||||
char record_file[250];
|
||||
osip_message_t *msg=NULL;
|
||||
sprintf(record_file,"/tmp/sipomatic%i.wav",call_count);
|
||||
|
|
@ -105,7 +105,7 @@ void call_accept(Call *call)
|
|||
#ifdef VIDEO_ENABLED
|
||||
if (call->video.remoteport!=0){
|
||||
video_stream_send_only_start(call->video_stream,call->profile,
|
||||
call->video.remaddr,call->video.remoteport,call->video.remoteport+1,call->video.pt, 60,
|
||||
call->video.remaddr,call->video.remoteport,call->video.remoteport+1,call->video.pt, 60,
|
||||
ms_web_cam_manager_get_default_cam(ms_web_cam_manager_get()));
|
||||
}
|
||||
#endif
|
||||
|
|
@ -124,7 +124,7 @@ PayloadType * sipomatic_payload_is_supported(sdp_payload_t *payload,RtpProfile *
|
|||
localpt=payload->pt;
|
||||
ms_warning("payload has no rtpmap.");
|
||||
}
|
||||
|
||||
|
||||
if (localpt>=0){
|
||||
/* this payload is supported in our local rtp profile, so add it to the dialog rtp
|
||||
profile */
|
||||
|
|
@ -160,7 +160,7 @@ int sipomatic_accept_audio_offer(sdp_context_t *ctx,sdp_payload_t *payload)
|
|||
Call *call=(Call*)sdp_context_get_user_pointer(ctx);
|
||||
PayloadType *supported;
|
||||
struct stream_params *params=&call->audio;
|
||||
|
||||
|
||||
/* see if this codec is supported in our local rtp profile*/
|
||||
supported=sipomatic_payload_is_supported(payload,&av_profile,call->profile);
|
||||
if (supported==NULL) {
|
||||
|
|
@ -191,7 +191,7 @@ int sipomatic_accept_video_offer(sdp_context_t *ctx,sdp_payload_t *payload)
|
|||
Call *call=(Call*)sdp_context_get_user_pointer(ctx);
|
||||
PayloadType *supported;
|
||||
struct stream_params *params=&call->video;
|
||||
|
||||
|
||||
/* see if this codec is supported in our local rtp profile*/
|
||||
supported=sipomatic_payload_is_supported(payload,&av_profile,call->profile);
|
||||
if (supported==NULL) {
|
||||
|
|
@ -221,9 +221,9 @@ void sipomatic_init(Sipomatic *obj, char *url, bool_t ipv6)
|
|||
{
|
||||
osip_uri_t *uri=NULL;
|
||||
int port=5064;
|
||||
|
||||
|
||||
obj->ipv6=ipv6;
|
||||
|
||||
|
||||
if (url==NULL){
|
||||
url=getenv("SIPOMATIC_URL");
|
||||
if (url==NULL){
|
||||
|
|
@ -237,7 +237,7 @@ void sipomatic_init(Sipomatic *obj, char *url, bool_t ipv6)
|
|||
if (uri->port!=NULL) port=atoi(uri->port);
|
||||
}else{
|
||||
ms_warning("Invalid identity uri:%s",url);
|
||||
}
|
||||
}
|
||||
}
|
||||
ms_message("Starting using url %s",url);
|
||||
ms_mutex_init(&obj->lock,NULL);
|
||||
|
|
@ -324,7 +324,7 @@ Call * call_new(Sipomatic *root, eXosip_event_t *ev)
|
|||
int status;
|
||||
sdp_message_t *sdp;
|
||||
sdp_context_t *sdpc;
|
||||
|
||||
|
||||
sdp=eXosip_get_sdp_info(ev->request);
|
||||
sdpc=sdp_handler_create_context(&sipomatic_sdp_handler,NULL,"sipomatic",NULL);
|
||||
obj=ms_new0(Call,1);
|
||||
|
|
@ -334,7 +334,7 @@ Call * call_new(Sipomatic *root, eXosip_event_t *ev)
|
|||
sdpans=sdp_context_get_answer(sdpc,sdp);
|
||||
if (sdpans!=NULL){
|
||||
eXosip_call_send_answer(ev->tid,180,NULL);
|
||||
|
||||
|
||||
}else{
|
||||
status=sdp_context_get_status(sdpc);
|
||||
eXosip_call_send_answer(ev->tid,status,NULL);
|
||||
|
|
@ -409,7 +409,7 @@ int main(int argc, char *argv[])
|
|||
char *url=NULL;
|
||||
bool_t ipv6=FALSE;
|
||||
int i;
|
||||
|
||||
|
||||
for(i=1;i<argc;i++){
|
||||
if ( (strcmp(argv[i],"-h")==0) || (strcmp(argv[i],"--help")==0) ){
|
||||
display_help();
|
||||
|
|
@ -441,7 +441,7 @@ int main(int argc, char *argv[])
|
|||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
signal(SIGINT,stop_handler);
|
||||
ortp_init();
|
||||
ms_init();
|
||||
|
|
@ -453,18 +453,18 @@ int main(int argc, char *argv[])
|
|||
rtp_profile_set_payload(&av_profile,101,&payload_type_telephone_event);
|
||||
rtp_profile_set_payload(&av_profile,116,&payload_type_truespeech);
|
||||
rtp_profile_set_payload(&av_profile,98,&payload_type_h263_1998);
|
||||
|
||||
|
||||
sipomatic_init(&sipomatic,url,ipv6);
|
||||
if (file!=NULL) sipomatic_set_annouce_file(&sipomatic,file);
|
||||
|
||||
|
||||
while (run_cond){
|
||||
sipomatic_iterate(&sipomatic);
|
||||
#ifndef WIN32
|
||||
#ifndef _WIN32
|
||||
usleep(20000);
|
||||
#else
|
||||
Sleep(20);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
#
|
||||
############################################################################
|
||||
|
||||
if(MSVC AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsPhone")
|
||||
if(MSVC AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsPhone" AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
|
||||
find_library(LIBGCC NAMES gcc)
|
||||
find_library(LIBMINGWEX NAMES mingwex)
|
||||
endif()
|
||||
|
|
@ -35,8 +35,11 @@ set(LINPHONE_HEADER_FILES
|
|||
buffer.h
|
||||
call_log.h
|
||||
call_params.h
|
||||
carddav.h
|
||||
conference.h
|
||||
content.h
|
||||
event.h
|
||||
friendlist.h
|
||||
linphonecore.h
|
||||
linphonecore_utils.h
|
||||
linphonefriend.h
|
||||
|
|
@ -45,9 +48,11 @@ set(LINPHONE_HEADER_FILES
|
|||
linphone_tunnel.h
|
||||
lpc2xml.h
|
||||
lpconfig.h
|
||||
ringtoneplayer.h
|
||||
sipsetup.h
|
||||
xml2lpc.h
|
||||
xmlrpc.h
|
||||
vcard.h
|
||||
)
|
||||
|
||||
set(LINPHONE_SOURCE_FILES_C
|
||||
|
|
@ -71,9 +76,9 @@ set(LINPHONE_SOURCE_FILES_C
|
|||
callbacks.c
|
||||
call_log.c
|
||||
call_params.c
|
||||
carddav.c
|
||||
chat.c
|
||||
chat_file_transfer.c
|
||||
conference.c
|
||||
contactprovider.c
|
||||
content.c
|
||||
dict.c
|
||||
|
|
@ -82,6 +87,7 @@ set(LINPHONE_SOURCE_FILES_C
|
|||
enum.h
|
||||
event.c
|
||||
friend.c
|
||||
friendlist.c
|
||||
info.c
|
||||
ldap/ldapprovider.c
|
||||
lime.c
|
||||
|
|
@ -103,6 +109,7 @@ set(LINPHONE_SOURCE_FILES_C
|
|||
proxy.c
|
||||
quality_reporting.c
|
||||
remote_provisioning.c
|
||||
ringtoneplayer.c
|
||||
sal.c
|
||||
siplogin.c
|
||||
sipsetup.c
|
||||
|
|
@ -111,7 +118,17 @@ set(LINPHONE_SOURCE_FILES_C
|
|||
xmlrpc.c
|
||||
vtables.c
|
||||
)
|
||||
set(LINPHONE_SOURCE_FILES_CXX )
|
||||
set(LINPHONE_SOURCE_FILES_CXX conference.cc)
|
||||
if(ANDROID)
|
||||
list(APPEND LINPHONE_SOURCE_FILES_CXX linphonecore_jni.cc)
|
||||
set_source_files_properties(linphonecore_jni.cc PROPERTIES COMPILE_DEFINITIONS "USE_JAVAH")
|
||||
endif()
|
||||
|
||||
set(LINPHONE_SOURCE_FILES_OBJC)
|
||||
if (IOS)
|
||||
list(APPEND LINPHONE_SOURCE_FILES_OBJC ringtoneplayer_ios.m ringtoneplayer_ios.h)
|
||||
endif()
|
||||
|
||||
|
||||
if(ENABLE_TUNNEL)
|
||||
list(APPEND LINPHONE_SOURCE_FILES_CXX
|
||||
|
|
@ -125,7 +142,7 @@ endif()
|
|||
|
||||
find_package(Git)
|
||||
add_custom_target(liblinphone-git-version
|
||||
COMMAND ${CMAKE_COMMAND} -DGIT_EXECUTABLE=${GIT_EXECUTABLE} -DWORK_DIR=${CMAKE_CURRENT_SOURCE_DIR} -DOUTPUT_DIR=${CMAKE_CURRENT_BINARY_DIR} -P ${CMAKE_CURRENT_SOURCE_DIR}/gitversion.cmake
|
||||
COMMAND ${CMAKE_COMMAND} -DGIT_EXECUTABLE=${GIT_EXECUTABLE} -DLINPHONE_VERSION=${LINPHONE_VERSION} -DWORK_DIR=${CMAKE_CURRENT_SOURCE_DIR} -DOUTPUT_DIR=${CMAKE_CURRENT_BINARY_DIR} -P ${CMAKE_CURRENT_SOURCE_DIR}/gitversion.cmake
|
||||
BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/liblinphone_gitversion.h"
|
||||
)
|
||||
|
||||
|
|
@ -134,10 +151,8 @@ add_definitions(
|
|||
-DLIBLINPHONE_EXPORTS
|
||||
)
|
||||
|
||||
apply_compile_flags(LINPHONE_SOURCE_FILES_C "CPP" "C")
|
||||
apply_compile_flags(LINPHONE_SOURCE_FILES_CXX "CPP" "CXX")
|
||||
|
||||
set(LIBS
|
||||
${BCTOOLBOX_CORE_LIBRARIES}
|
||||
${BELLESIP_LIBRARIES}
|
||||
${MEDIASTREAMER2_LIBRARIES}
|
||||
${XML2_LIBRARIES}
|
||||
|
|
@ -154,54 +169,106 @@ endif()
|
|||
if(ENABLE_TUNNEL)
|
||||
list(APPEND LIBS ${TUNNEL_LIBRARIES})
|
||||
endif()
|
||||
if(MSVC AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsPhone")
|
||||
if(MSVC AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsPhone" AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
|
||||
list(APPEND LIBS ${LIBGCC} ${LIBMINGWEX})
|
||||
endif()
|
||||
if(WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsPhone")
|
||||
if(WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsPhone" AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
|
||||
list(APPEND LIBS shlwapi)
|
||||
endif()
|
||||
if(INTL_FOUND)
|
||||
list(APPEND LIBS ${INTL_LIBRARIES})
|
||||
endif()
|
||||
if(BELCARD_FOUND)
|
||||
list(APPEND LIBS ${BELCARD_LIBRARIES})
|
||||
list(APPEND LINPHONE_SOURCE_FILES_CXX vcard.cc)
|
||||
if(NOT MSVC)
|
||||
list(APPEND STRICT_OPTIONS_CXX "-std=c++11")
|
||||
endif()
|
||||
if(APPLE)
|
||||
list(APPEND STRICT_OPTIONS_CXX "-stdlib=libc++")
|
||||
endif()
|
||||
else()
|
||||
list(APPEND LINPHONE_SOURCE_FILES_C vcard_stubs.c)
|
||||
endif()
|
||||
|
||||
apply_compile_flags(LINPHONE_SOURCE_FILES_C "CPP" "C")
|
||||
apply_compile_flags(LINPHONE_SOURCE_FILES_CXX "CPP" "CXX")
|
||||
apply_compile_flags(LINPHONE_SOURCE_FILES_OBJC "CPP" "OBJC")
|
||||
|
||||
if(ENABLE_STATIC)
|
||||
add_library(linphone STATIC ${LINPHONE_HEADER_FILES} ${LINPHONE_SOURCE_FILES_C} ${LINPHONE_SOURCE_FILES_CXX})
|
||||
target_link_libraries(linphone ${LIBS})
|
||||
else()
|
||||
add_library(linphone SHARED ${LINPHONE_HEADER_FILES} ${LINPHONE_SOURCE_FILES_C} ${LINPHONE_SOURCE_FILES_CXX})
|
||||
set_target_properties(linphone PROPERTIES VERSION ${LINPHONE_SO_VERSION} LINKER_LANGUAGE CXX)
|
||||
add_library(linphone-static STATIC ${LINPHONE_HEADER_FILES} ${LINPHONE_SOURCE_FILES_C} ${LINPHONE_SOURCE_FILES_CXX} ${LINPHONE_SOURCE_FILES_OBJC})
|
||||
set_target_properties(linphone-static PROPERTIES OUTPUT_NAME linphone)
|
||||
add_dependencies(linphone-static liblinphone-git-version)
|
||||
target_link_libraries(linphone-static ${LIBS})
|
||||
if(ANDROID)
|
||||
add_dependencies(linphone-static linphonecore-jni-header)
|
||||
endif()
|
||||
if(IOS)
|
||||
target_link_libraries(linphone-static "-framework Foundation" "-framework AVFoundation")
|
||||
endif()
|
||||
install(TARGETS linphone-static EXPORT ${EXPORT_TARGETS_NAME}Targets
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
|
||||
)
|
||||
endif()
|
||||
if(ENABLE_SHARED)
|
||||
add_library(linphone SHARED ${LINPHONE_HEADER_FILES} ${LINPHONE_SOURCE_FILES_C} ${LINPHONE_SOURCE_FILES_CXX} ${LINPHONE_SOURCE_FILES_OBJC})
|
||||
|
||||
if(BELCARD_FOUND)
|
||||
if(APPLE)
|
||||
set_target_properties(linphone PROPERTIES LINK_FLAGS "-stdlib=libc++")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set_target_properties(linphone PROPERTIES LINKER_LANGUAGE CXX)
|
||||
if(NOT ANDROID)
|
||||
# Do not version shared library on Android
|
||||
set_target_properties(linphone PROPERTIES SOVERSION ${LINPHONE_SO_VERSION})
|
||||
endif()
|
||||
add_dependencies(linphone liblinphone-git-version)
|
||||
target_link_libraries(linphone ${LIBS})
|
||||
if(WIN32 AND CMAKE_SYSTEM_NAME STREQUAL "WindowsPhone" AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
|
||||
set_target_properties(linphone PROPERTIES PREFIX "lib")
|
||||
elseif(ANDROID)
|
||||
set_target_properties(linphone PROPERTIES OUTPUT_NAME "linphone-${CMAKE_SYSTEM_PROCESSOR}")
|
||||
add_dependencies(linphone linphonecore-jni-header)
|
||||
endif()
|
||||
if(MSVC)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Debug/linphone.pdb
|
||||
DESTINATION bin
|
||||
DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
add_dependencies(linphone liblinphone-git-version)
|
||||
if(WIN32 AND CMAKE_SYSTEM_NAME STREQUAL "WindowsPhone")
|
||||
set_target_properties(linphone PROPERTIES PREFIX "lib")
|
||||
install(TARGETS linphone EXPORT ${EXPORT_TARGETS_NAME}Targets
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
|
||||
)
|
||||
endif()
|
||||
if(ICONV_FOUND)
|
||||
if(APPLE)
|
||||
# Prevent conflict between the system iconv.h header and the one from macports.
|
||||
target_compile_options(linphone PRIVATE "-include" "${ICONV_INCLUDE_DIRS}/iconv.h")
|
||||
if(ENABLE_STATIC)
|
||||
target_compile_options(linphone-static PRIVATE "-include" "${ICONV_INCLUDE_DIRS}/iconv.h")
|
||||
endif()
|
||||
if(ENABLE_SHARED)
|
||||
target_compile_options(linphone PRIVATE "-include" "${ICONV_INCLUDE_DIRS}/iconv.h")
|
||||
endif()
|
||||
else()
|
||||
target_include_directories(linphone PRIVATE ${ICONV_INCLUDE_DIRS})
|
||||
if(ENABLE_STATIC)
|
||||
target_include_directories(linphone-static PRIVATE ${ICONV_INCLUDE_DIRS})
|
||||
endif()
|
||||
if(ENABLE_SHARED)
|
||||
target_include_directories(linphone PRIVATE ${ICONV_INCLUDE_DIRS})
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
install(TARGETS linphone EXPORT ${EXPORT_TARGETS_NAME}Targets
|
||||
RUNTIME DESTINATION bin
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
|
||||
)
|
||||
|
||||
install(FILES ${LINPHONE_HEADER_FILES}
|
||||
DESTINATION include/linphone
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/linphone
|
||||
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -29,10 +29,13 @@ linphone_include_HEADERS=\
|
|||
buffer.h \
|
||||
call_log.h \
|
||||
call_params.h \
|
||||
conference.h \
|
||||
content.h \
|
||||
event.h \
|
||||
friendlist.h \
|
||||
linphonecore.h \
|
||||
linphonecore_utils.h \
|
||||
ringtoneplayer.h \
|
||||
linphonefriend.h \
|
||||
linphonepresence.h \
|
||||
linphone_proxy_config.h \
|
||||
|
|
@ -41,7 +44,9 @@ linphone_include_HEADERS=\
|
|||
lpconfig.h \
|
||||
sipsetup.h \
|
||||
xml2lpc.h \
|
||||
xmlrpc.h
|
||||
xmlrpc.h \
|
||||
vcard.h \
|
||||
carddav.h
|
||||
|
||||
lib_LTLIBRARIES=liblinphone.la
|
||||
|
||||
|
|
@ -55,7 +60,7 @@ liblinphone_la_SOURCES=\
|
|||
call_params.c \
|
||||
chat.c \
|
||||
chat_file_transfer.c \
|
||||
conference.c \
|
||||
conference.cc conference_private.h \
|
||||
contactprovider.c contactprovider.h contact_providers_priv.h \
|
||||
content.c \
|
||||
dict.c \
|
||||
|
|
@ -63,6 +68,7 @@ liblinphone_la_SOURCES=\
|
|||
enum.c enum.h \
|
||||
event.c \
|
||||
friend.c \
|
||||
friendlist.c \
|
||||
info.c \
|
||||
ldap/ldapprovider.c ldap/ldapprovider.h \
|
||||
linphonecall.c \
|
||||
|
|
@ -88,6 +94,8 @@ liblinphone_la_SOURCES=\
|
|||
xml.c \
|
||||
xmlrpc.c \
|
||||
vtables.c \
|
||||
carddav.c \
|
||||
ringtoneplayer.c ringtoneplayer.h\
|
||||
$(GITVERSION_FILE)
|
||||
|
||||
if BUILD_UPNP
|
||||
|
|
@ -114,7 +122,11 @@ else
|
|||
liblinphone_la_SOURCES+=linphone_tunnel_stubs.c linphone_tunnel.h
|
||||
endif
|
||||
|
||||
|
||||
if BUILD_VCARD
|
||||
liblinphone_la_SOURCES+=vcard.cc
|
||||
else
|
||||
liblinphone_la_SOURCES+=vcard_stubs.c
|
||||
endif
|
||||
|
||||
liblinphone_la_LDFLAGS= -version-info $(LIBLINPHONE_SO_VERSION) -no-undefined
|
||||
|
||||
|
|
@ -142,19 +154,22 @@ liblinphone_la_LIBADD= \
|
|||
$(LIBXML2_LIBS) \
|
||||
$(LDAP_LIBS) \
|
||||
$(SASL_LIBS) \
|
||||
$(BELCARD_LIBS) \
|
||||
$(ZLIB_LIBS)
|
||||
|
||||
|
||||
AM_CPPFLAGS=\
|
||||
-DIN_LINPHONE \
|
||||
-I$(top_srcdir) -I$(top_srcdir)/include -I$(builddir) \
|
||||
$(ORTP_CFLAGS) \
|
||||
$(MEDIASTREAMER_CFLAGS)
|
||||
$(ORTP_CFLAGS) \
|
||||
$(MEDIASTREAMER_CFLAGS) \
|
||||
$(LIBXML2_CFLAGS)
|
||||
|
||||
COMMON_CFLAGS=\
|
||||
$(STRICT_OPTIONS) \
|
||||
-DIN_LINPHONE \
|
||||
$(SIPSTACK_CFLAGS) \
|
||||
-DENABLE_TRACE \
|
||||
-DENABLE_TRACE \
|
||||
-DLOG_DOMAIN=\"LinphoneCore\" \
|
||||
$(IPV6_CFLAGS) \
|
||||
-DORTP_INET6 \
|
||||
|
|
@ -164,6 +179,7 @@ COMMON_CFLAGS=\
|
|||
$(LIBXML2_CFLAGS) \
|
||||
$(LDAP_CFLAGS) \
|
||||
$(SASL_CFLAGS) \
|
||||
$(BELCARD_CFLAGS) \
|
||||
$(ZLIB_CFLAGS)
|
||||
|
||||
if BUILD_WIZARD
|
||||
|
|
@ -174,6 +190,9 @@ COMMON_CFLAGS+= -DUSE_BELLESIP
|
|||
|
||||
AM_CFLAGS=$(COMMON_CFLAGS) $(STRICT_OPTIONS_CC)
|
||||
AM_CXXFLAGS=$(COMMON_CFLAGS) $(STRICT_OPTIONS_CXX)
|
||||
if BUILD_VCARD
|
||||
AM_CXXFLAGS+=-std=c++11
|
||||
endif
|
||||
|
||||
#Make sure that we are in linphone's git tree by doing git log $(top_srcdir)/configure.ac.
|
||||
#if it is something known to git, then that will be ok to check the git describe number and make sure it is consistent with
|
||||
|
|
|
|||
|
|
@ -47,7 +47,10 @@ void TunnelManager::addServer(const char *ip, int port) {
|
|||
|
||||
void TunnelManager::cleanServers() {
|
||||
mServerAddrs.clear();
|
||||
|
||||
if (mLongRunningTaskId > 0) {
|
||||
sal_end_background_task(mLongRunningTaskId);
|
||||
mLongRunningTaskId = 0;
|
||||
}
|
||||
UdpMirrorClientList::iterator it;
|
||||
for (it = mUdpMirrorClients.begin(); it != mUdpMirrorClients.end();) {
|
||||
UdpMirrorClient& s=*it++;
|
||||
|
|
@ -89,6 +92,7 @@ RtpTransport *TunnelManager::createRtpTransport(int port){
|
|||
t->t_close=sCloseRtpTransport;
|
||||
t->t_destroy=sDestroyRtpTransport;
|
||||
t->data=socket;
|
||||
ms_message("Creating tunnel RTP transport for local virtual port %i", port);
|
||||
return t;
|
||||
}
|
||||
|
||||
|
|
@ -134,7 +138,8 @@ TunnelManager::TunnelManager(LinphoneCore* lc) :
|
|||
mTunnelizeSipPackets(true),
|
||||
mTunnelClient(NULL),
|
||||
mHttpProxyPort(0),
|
||||
mVTable(NULL)
|
||||
mVTable(NULL),
|
||||
mLongRunningTaskId(0)
|
||||
{
|
||||
linphone_core_add_iterate_hook(mCore,(LinphoneCoreIterateHook)sOnIterate,this);
|
||||
mTransportFactories.audio_rtcp_func=sCreateRtpTransport;
|
||||
|
|
@ -152,17 +157,22 @@ TunnelManager::TunnelManager(LinphoneCore* lc) :
|
|||
}
|
||||
|
||||
TunnelManager::~TunnelManager(){
|
||||
if (mLongRunningTaskId > 0) {
|
||||
sal_end_background_task(mLongRunningTaskId);
|
||||
mLongRunningTaskId = 0;
|
||||
}
|
||||
for(UdpMirrorClientList::iterator udpMirror = mUdpMirrorClients.begin(); udpMirror != mUdpMirrorClients.end(); udpMirror++) {
|
||||
udpMirror->stop();
|
||||
}
|
||||
if(mTunnelClient) delete mTunnelClient;
|
||||
sal_set_tunnel(mCore->sal,NULL);
|
||||
linphone_core_remove_listener(mCore, mVTable);
|
||||
linphone_core_v_table_destroy(mVTable);
|
||||
}
|
||||
|
||||
void TunnelManager::doRegistration(){
|
||||
LinphoneProxyConfig* lProxy;
|
||||
linphone_core_get_default_proxy(mCore, &lProxy);
|
||||
lProxy = linphone_core_get_default_proxy_config(mCore);
|
||||
if (lProxy) {
|
||||
ms_message("TunnelManager: New registration");
|
||||
lProxy->commit = TRUE;
|
||||
|
|
@ -171,7 +181,7 @@ void TunnelManager::doRegistration(){
|
|||
|
||||
void TunnelManager::doUnregistration() {
|
||||
LinphoneProxyConfig *lProxy;
|
||||
linphone_core_get_default_proxy(mCore, &lProxy);
|
||||
lProxy = linphone_core_get_default_proxy_config(mCore);
|
||||
if(lProxy) {
|
||||
_linphone_proxy_config_unregister(lProxy);
|
||||
}
|
||||
|
|
@ -188,7 +198,7 @@ void TunnelManager::processTunnelEvent(const Event &ev){
|
|||
_linphone_core_apply_transports(mCore);
|
||||
doRegistration();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
} else {
|
||||
ms_error("TunnelManager: tunnel has been disconnected");
|
||||
|
|
@ -247,6 +257,10 @@ void TunnelManager::setMode(LinphoneTunnelMode mode) {
|
|||
|
||||
void TunnelManager::tunnelCallback(bool connected, TunnelManager *zis){
|
||||
Event ev;
|
||||
if (zis->mLongRunningTaskId > 0) {
|
||||
sal_end_background_task(zis->mLongRunningTaskId);
|
||||
zis->mLongRunningTaskId = 0;
|
||||
}
|
||||
ev.mType=TunnelEvent;
|
||||
ev.mData.mConnected=connected;
|
||||
zis->postEvent(ev);
|
||||
|
|
@ -323,6 +337,7 @@ void TunnelManager::processUdpMirrorEvent(const Event &ev){
|
|||
ms_message("TunnelManager: UDP mirror test succeed");
|
||||
if(mTunnelClient) {
|
||||
if(mTunnelizeSipPackets) doUnregistration();
|
||||
sal_set_tunnel(mCore->sal,NULL);
|
||||
delete mTunnelClient;
|
||||
mTunnelClient = NULL;
|
||||
if(mTunnelizeSipPackets) doRegistration();
|
||||
|
|
@ -333,6 +348,8 @@ void TunnelManager::processUdpMirrorEvent(const Event &ev){
|
|||
mCurrentUdpMirrorClient++;
|
||||
if (mCurrentUdpMirrorClient !=mUdpMirrorClients.end()) {
|
||||
ms_message("TunnelManager: trying another UDP mirror");
|
||||
if (mLongRunningTaskId == 0)
|
||||
mLongRunningTaskId = sal_begin_background_task("Tunnel auto detect", NULL, NULL);
|
||||
UdpMirrorClient &lUdpMirrorClient=*mCurrentUdpMirrorClient;
|
||||
lUdpMirrorClient.start(TunnelManager::sUdpMirrorClientCallback,(void*)this);
|
||||
} else {
|
||||
|
|
@ -377,6 +394,8 @@ bool TunnelManager::startAutoDetection() {
|
|||
}
|
||||
ms_message("TunnelManager: Starting auto-detection");
|
||||
mCurrentUdpMirrorClient = mUdpMirrorClients.begin();
|
||||
if (mLongRunningTaskId == 0)
|
||||
mLongRunningTaskId = sal_begin_background_task("Tunnel auto detect", NULL, NULL);
|
||||
UdpMirrorClient &lUdpMirrorClient=*mCurrentUdpMirrorClient;
|
||||
lUdpMirrorClient.start(TunnelManager::sUdpMirrorClientCallback,(void*)this);
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -201,6 +201,7 @@ namespace belledonnecomm {
|
|||
Mutex mMutex;
|
||||
std::queue<Event> mEvq;
|
||||
char mLocalAddr[64];
|
||||
unsigned long mLongRunningTaskId;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -130,14 +130,14 @@ void linphone_account_creator_set_user_data(LinphoneAccountCreator *creator, voi
|
|||
}
|
||||
|
||||
static LinphoneAccountCreatorStatus validate_uri(const char* username, const char* domain, const char* route, const char* display_name) {
|
||||
LinphoneProxyConfig* proxy = linphone_proxy_config_new();
|
||||
LinphoneAddress* addr;
|
||||
|
||||
linphone_proxy_config_set_identity(proxy, "sip:user@domain.com");
|
||||
LinphoneAccountCreatorStatus status = LinphoneAccountCreatorOK;
|
||||
LinphoneProxyConfig* proxy = linphone_proxy_config_new();
|
||||
linphone_proxy_config_set_identity(proxy, "sip:userame@domain.com");
|
||||
|
||||
if (route && linphone_proxy_config_set_route(proxy, route) != 0) {
|
||||
linphone_proxy_config_destroy(proxy);
|
||||
return LinphoneAccountCreatorRouteInvalid;
|
||||
status = LinphoneAccountCreatorRouteInvalid;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (username) {
|
||||
|
|
@ -145,24 +145,39 @@ static LinphoneAccountCreatorStatus validate_uri(const char* username, const cha
|
|||
} else {
|
||||
addr = linphone_address_clone(linphone_proxy_config_get_identity_address(proxy));
|
||||
}
|
||||
linphone_proxy_config_destroy(proxy);
|
||||
|
||||
if (addr == NULL) {
|
||||
return LinphoneAccountCreatorUsernameInvalid;
|
||||
status = LinphoneAccountCreatorUsernameInvalid;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (domain) {
|
||||
ms_error("TODO: detect invalid domain");
|
||||
linphone_address_set_domain(addr, domain);
|
||||
if (domain && linphone_address_set_domain(addr, domain) != 0) {
|
||||
status = LinphoneAccountCreatorDomainInvalid;
|
||||
}
|
||||
|
||||
if (display_name) {
|
||||
ms_error("TODO: detect invalid display name");
|
||||
linphone_address_set_display_name(addr, display_name);
|
||||
if (display_name && (!strlen(display_name) || linphone_address_set_display_name(addr, display_name) != 0)) {
|
||||
status = LinphoneAccountCreatorDisplayNameInvalid;
|
||||
}
|
||||
|
||||
linphone_address_unref(addr);
|
||||
return LinphoneAccountCreatorOK;
|
||||
end:
|
||||
linphone_proxy_config_destroy(proxy);
|
||||
return status;
|
||||
}
|
||||
|
||||
static char* _get_identity(const LinphoneAccountCreator *creator) {
|
||||
char *identity = NULL;
|
||||
if (creator->username && creator->domain) {
|
||||
//we must escape username
|
||||
LinphoneProxyConfig* proxy = linphone_proxy_config_new();
|
||||
LinphoneAddress* addr;
|
||||
linphone_proxy_config_set_identity(proxy, "sip:userame@domain.com");
|
||||
addr = linphone_proxy_config_normalize_sip_uri(proxy, creator->username);
|
||||
linphone_address_set_domain(addr, creator->domain);
|
||||
identity = linphone_address_as_string(addr);
|
||||
linphone_address_destroy(addr);
|
||||
linphone_proxy_config_destroy(proxy);
|
||||
}
|
||||
return identity;
|
||||
}
|
||||
|
||||
static bool_t is_matching_regex(const char *entry, const char* regex) {
|
||||
|
|
@ -185,13 +200,16 @@ static bool_t is_matching_regex(const char *entry, const char* regex) {
|
|||
}
|
||||
|
||||
LinphoneAccountCreatorStatus linphone_account_creator_set_username(LinphoneAccountCreator *creator, const char *username) {
|
||||
int min_length = lp_config_get_int(creator->core->config, "assistant", "username_min_length", 0);
|
||||
int fixed_length = lp_config_get_int(creator->core->config, "assistant", "username_length", 0);
|
||||
int min_length = lp_config_get_int(creator->core->config, "assistant", "username_min_length", -1);
|
||||
int fixed_length = lp_config_get_int(creator->core->config, "assistant", "username_length", -1);
|
||||
int max_length = lp_config_get_int(creator->core->config, "assistant", "username_max_length", -1);
|
||||
bool_t use_phone_number = lp_config_get_int(creator->core->config, "assistant", "use_phone_number", 0);
|
||||
const char* regex = lp_config_get_string(creator->core->config, "assistant", "username_regex", 0);
|
||||
LinphoneAccountCreatorStatus status;
|
||||
if (min_length > 0 && strlen(username) < min_length) {
|
||||
return LinphoneAccountCreatorUsernameTooShort;
|
||||
} else if (max_length > 0 && strlen(username) > max_length) {
|
||||
return LinphoneAccountCreatorUsernameTooLong;
|
||||
} else if (fixed_length > 0 && strlen(username) != fixed_length) {
|
||||
return LinphoneAccountCreatorUsernameInvalidSize;
|
||||
} else if (use_phone_number && !linphone_proxy_config_is_phone_number(NULL, username)) {
|
||||
|
|
@ -201,7 +219,9 @@ LinphoneAccountCreatorStatus linphone_account_creator_set_username(LinphoneAccou
|
|||
} else if ((status = validate_uri(username, NULL, NULL, NULL)) != LinphoneAccountCreatorOK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
set_string(&creator->username, username, TRUE);
|
||||
|
||||
return LinphoneAccountCreatorOK;
|
||||
}
|
||||
|
||||
|
|
@ -210,9 +230,12 @@ const char * linphone_account_creator_get_username(const LinphoneAccountCreator
|
|||
}
|
||||
|
||||
LinphoneAccountCreatorStatus linphone_account_creator_set_password(LinphoneAccountCreator *creator, const char *password){
|
||||
int min_length = lp_config_get_int(creator->core->config, "assistant", "password_min_length", 0);
|
||||
int min_length = lp_config_get_int(creator->core->config, "assistant", "password_min_length", -1);
|
||||
int max_length = lp_config_get_int(creator->core->config, "assistant", "password_max_length", -1);
|
||||
if (min_length > 0 && strlen(password) < min_length) {
|
||||
return LinphoneAccountCreatorPasswordTooShort;
|
||||
} else if (max_length > 0 && strlen(password) > max_length) {
|
||||
return LinphoneAccountCreatorPasswordTooLong;
|
||||
}
|
||||
set_string(&creator->password, password, FALSE);
|
||||
return LinphoneAccountCreatorOK;
|
||||
|
|
@ -308,15 +331,14 @@ static void _test_existence_cb(LinphoneXmlRpcRequest *request) {
|
|||
|
||||
LinphoneAccountCreatorStatus linphone_account_creator_test_existence(LinphoneAccountCreator *creator) {
|
||||
LinphoneXmlRpcRequest *request;
|
||||
char *identity;
|
||||
|
||||
if (!creator->username || !creator->domain) {
|
||||
char *identity = _get_identity(creator);
|
||||
if (!identity) {
|
||||
if (creator->callbacks->existence_tested != NULL) {
|
||||
creator->callbacks->existence_tested(creator, LinphoneAccountCreatorReqFailed);
|
||||
}
|
||||
return LinphoneAccountCreatorReqFailed;
|
||||
}
|
||||
identity = ms_strdup_printf("%s@%s", creator->username, creator->domain);
|
||||
|
||||
request = linphone_xml_rpc_request_new_with_args("check_account", LinphoneXmlRpcArgInt,
|
||||
LinphoneXmlRpcArgString, identity,
|
||||
LinphoneXmlRpcArgNone);
|
||||
|
|
@ -342,16 +364,13 @@ static void _test_validation_cb(LinphoneXmlRpcRequest *request) {
|
|||
|
||||
LinphoneAccountCreatorStatus linphone_account_creator_test_validation(LinphoneAccountCreator *creator) {
|
||||
LinphoneXmlRpcRequest *request;
|
||||
char *identity;
|
||||
|
||||
if (!creator->username || !creator->domain) {
|
||||
char *identity = _get_identity(creator);
|
||||
if (!identity) {
|
||||
if (creator->callbacks->validation_tested != NULL) {
|
||||
creator->callbacks->validation_tested(creator, LinphoneAccountCreatorReqFailed);
|
||||
}
|
||||
return LinphoneAccountCreatorReqFailed;
|
||||
}
|
||||
|
||||
identity = ms_strdup_printf("%s@%s", creator->username, creator->domain);
|
||||
request = linphone_xml_rpc_request_new_with_args("check_account_validated", LinphoneXmlRpcArgInt,
|
||||
LinphoneXmlRpcArgString, identity,
|
||||
LinphoneXmlRpcArgNone);
|
||||
|
|
@ -377,16 +396,15 @@ static void _create_account_cb(LinphoneXmlRpcRequest *request) {
|
|||
|
||||
LinphoneAccountCreatorStatus linphone_account_creator_create_account(LinphoneAccountCreator *creator) {
|
||||
LinphoneXmlRpcRequest *request;
|
||||
char *identity;
|
||||
|
||||
if (!creator->username || !creator->domain || !creator->email) {
|
||||
char *identity = _get_identity(creator);
|
||||
if (!identity || !creator->email) {
|
||||
if (creator->callbacks->create_account != NULL) {
|
||||
creator->callbacks->create_account(creator, LinphoneAccountCreatorReqFailed);
|
||||
}
|
||||
if (identity) ms_free(identity);
|
||||
return LinphoneAccountCreatorReqFailed;
|
||||
}
|
||||
|
||||
identity = ms_strdup_printf("%s@%s", creator->username, creator->domain);
|
||||
request = linphone_xml_rpc_request_new_with_args("create_account", LinphoneXmlRpcArgInt,
|
||||
LinphoneXmlRpcArgString, identity,
|
||||
LinphoneXmlRpcArgString, creator->password,
|
||||
|
|
@ -404,18 +422,25 @@ LinphoneAccountCreatorStatus linphone_account_creator_create_account(LinphoneAcc
|
|||
LinphoneProxyConfig * linphone_account_creator_configure(const LinphoneAccountCreator *creator) {
|
||||
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);
|
||||
char *identity_str = _get_identity(creator);
|
||||
LinphoneAddress *identity = linphone_address_new(identity_str);
|
||||
char *route = NULL;
|
||||
char *domain = NULL;
|
||||
ms_free(identity_str);
|
||||
if (creator->display_name) {
|
||||
linphone_address_set_display_name(identity, creator->display_name);
|
||||
}
|
||||
|
||||
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);
|
||||
if (creator->route) {
|
||||
route = ms_strdup_printf("%s;transport=%s", creator->route, linphone_transport_to_string(creator->transport));
|
||||
}
|
||||
if (creator->domain) {
|
||||
domain = ms_strdup_printf("%s;transport=%s", creator->domain, linphone_transport_to_string(creator->transport));
|
||||
}
|
||||
linphone_proxy_config_set_identity_address(cfg, identity);
|
||||
linphone_proxy_config_set_server_addr(cfg, domain);
|
||||
linphone_proxy_config_set_route(cfg, route);
|
||||
linphone_proxy_config_enable_publish(cfg, FALSE);
|
||||
linphone_proxy_config_enable_register(cfg, TRUE);
|
||||
ms_free(identity_str);
|
||||
|
||||
if (strcmp(creator->domain, "sip.linphone.org") == 0) {
|
||||
linphone_proxy_config_enable_avpf(cfg, TRUE);
|
||||
|
|
|
|||
|
|
@ -20,13 +20,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#ifndef LINPHONE_ACCOUNT_CREATOR_H_
|
||||
#define LINPHONE_ACCOUNT_CREATOR_H_
|
||||
|
||||
#include "linphonecore.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "linphonecore.h"
|
||||
|
||||
/**
|
||||
* @addtogroup misc
|
||||
* @{
|
||||
|
|
@ -51,8 +50,10 @@ typedef enum _LinphoneAccountCreatorStatus {
|
|||
LinphoneAccountCreatorEmailInvalid,
|
||||
LinphoneAccountCreatorUsernameInvalid,
|
||||
LinphoneAccountCreatorUsernameTooShort,
|
||||
LinphoneAccountCreatorUsernameTooLong,
|
||||
LinphoneAccountCreatorUsernameInvalidSize,
|
||||
LinphoneAccountCreatorPasswordTooShort,
|
||||
LinphoneAccountCreatorPasswordTooLong,
|
||||
LinphoneAccountCreatorDomainInvalid,
|
||||
LinphoneAccountCreatorRouteInvalid,
|
||||
LinphoneAccountCreatorDisplayNameInvalid,
|
||||
|
|
|
|||
|
|
@ -89,37 +89,51 @@ const char *linphone_address_get_domain(const LinphoneAddress *u){
|
|||
/**
|
||||
* Sets the display name.
|
||||
**/
|
||||
void linphone_address_set_display_name(LinphoneAddress *u, const char *display_name){
|
||||
int linphone_address_set_display_name(LinphoneAddress *u, const char *display_name){
|
||||
sal_address_set_display_name(u,display_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the username.
|
||||
**/
|
||||
void linphone_address_set_username(LinphoneAddress *uri, const char *username){
|
||||
int linphone_address_set_username(LinphoneAddress *uri, const char *username){
|
||||
sal_address_set_username(uri,username);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the domain.
|
||||
**/
|
||||
void linphone_address_set_domain(LinphoneAddress *uri, const char *host){
|
||||
sal_address_set_domain(uri,host);
|
||||
int linphone_address_set_domain(LinphoneAddress *uri, const char *host){
|
||||
if (host) {
|
||||
char *identity = ms_strdup_printf("sip:%s", host);
|
||||
LinphoneAddress* test = linphone_address_new(identity);
|
||||
ms_free(identity);
|
||||
if (test) {
|
||||
sal_address_set_domain(uri,host);
|
||||
linphone_address_destroy(test);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the port number.
|
||||
**/
|
||||
void linphone_address_set_port(LinphoneAddress *uri, int port){
|
||||
int linphone_address_set_port(LinphoneAddress *uri, int port){
|
||||
sal_address_set_port(uri,port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a transport.
|
||||
**/
|
||||
void linphone_address_set_transport(LinphoneAddress *uri, LinphoneTransportType tp){
|
||||
int linphone_address_set_transport(LinphoneAddress *uri, LinphoneTransportType tp){
|
||||
sal_address_set_transport(uri,(SalTransport)tp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -129,6 +143,20 @@ LinphoneTransportType linphone_address_get_transport(const LinphoneAddress *uri)
|
|||
return (LinphoneTransportType)sal_address_get_transport(uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of the method parameter
|
||||
**/
|
||||
void linphone_address_set_method_param(LinphoneAddress *addr, const char *method) {
|
||||
sal_address_set_method_param(addr, method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the method parameter
|
||||
**/
|
||||
const char *linphone_address_get_method_param(const LinphoneAddress *addr) {
|
||||
return sal_address_get_method_param(addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes address's tags and uri headers so that it is displayable to the user.
|
||||
**/
|
||||
|
|
|
|||
|
|
@ -114,6 +114,15 @@ const char* sal_address_get_transport_name(const SalAddress* addr){
|
|||
return NULL;
|
||||
}
|
||||
|
||||
const char *sal_address_get_method_param(const SalAddress *addr) {
|
||||
belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr);
|
||||
belle_sip_uri_t* uri = belle_sip_header_address_get_uri(header_addr);
|
||||
if (uri) {
|
||||
return belle_sip_uri_get_method_param(uri);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void sal_address_set_display_name(SalAddress *addr, const char *display_name){
|
||||
belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr);
|
||||
belle_sip_header_address_set_displayname(header_addr,display_name);
|
||||
|
|
@ -199,6 +208,11 @@ void sal_address_set_uri_params(SalAddress *addr, const char *params){
|
|||
belle_sip_parameters_set(parameters,params);
|
||||
}
|
||||
|
||||
bool_t sal_address_has_uri_param(SalAddress *addr, const char *name){
|
||||
belle_sip_parameters_t* parameters = BELLE_SIP_PARAMETERS(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(addr)));
|
||||
return belle_sip_parameters_has_parameter(parameters, name);
|
||||
}
|
||||
|
||||
void sal_address_set_header(SalAddress *addr, const char *header_name, const char *header_value){
|
||||
belle_sip_uri_set_header(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(addr)),header_name, header_value);
|
||||
}
|
||||
|
|
@ -213,6 +227,10 @@ void sal_address_set_transport_name(SalAddress* addr,const char *transport){
|
|||
SAL_ADDRESS_SET(addr,transport_param,transport);
|
||||
}
|
||||
|
||||
void sal_address_set_method_param(SalAddress *addr, const char *method) {
|
||||
SAL_ADDRESS_SET(addr, method_param, method);
|
||||
}
|
||||
|
||||
SalAddress *sal_address_ref(SalAddress *addr){
|
||||
return (SalAddress*)belle_sip_object_ref(BELLE_SIP_HEADER_ADDRESS(addr));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,8 +82,8 @@ void _belle_sip_log(belle_sip_log_level lev, const char *fmt, va_list args) {
|
|||
ortp_level=ORTP_DEBUG;
|
||||
break;
|
||||
}
|
||||
if (ortp_log_level_enabled(ortp_level)){
|
||||
ortp_logv(ortp_level,fmt,args);
|
||||
if (ortp_log_level_enabled("belle-sip", ortp_level)){
|
||||
ortp_logv("belle-sip", ortp_level,fmt,args);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -464,13 +464,13 @@ static void process_auth_requested(void *sal, belle_sip_auth_event_t *event) {
|
|||
sal_auth_info_delete(auth_info);
|
||||
}
|
||||
|
||||
Sal * sal_init(){
|
||||
Sal * sal_init(MSFactory *factory){
|
||||
belle_sip_listener_callbacks_t listener_callbacks;
|
||||
Sal * sal=ms_new0(Sal,1);
|
||||
|
||||
/*belle_sip_object_enable_marshal_check(TRUE);*/
|
||||
sal->auto_contacts=TRUE;
|
||||
|
||||
sal->factory = factory;
|
||||
/*first create the stack, which initializes the belle-sip object's pool for this thread*/
|
||||
belle_sip_set_log_handler(_belle_sip_log);
|
||||
sal->stack = belle_sip_stack_new(NULL);
|
||||
|
|
@ -478,6 +478,8 @@ Sal * sal_init(){
|
|||
sal->user_agent=belle_sip_header_user_agent_new();
|
||||
#if defined(PACKAGE_NAME) && defined(LIBLINPHONE_VERSION)
|
||||
belle_sip_header_user_agent_add_product(sal->user_agent, PACKAGE_NAME "/" LIBLINPHONE_VERSION);
|
||||
#else
|
||||
belle_sip_header_user_agent_add_product(sal->user_agent, "Unknown");
|
||||
#endif
|
||||
sal_append_stack_string_to_user_agent(sal);
|
||||
belle_sip_object_ref(sal->user_agent);
|
||||
|
|
@ -542,8 +544,8 @@ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){
|
|||
ctx->callbacks.notify=(SalOnNotify)unimplemented_stub;
|
||||
if (ctx->callbacks.subscribe_received==NULL)
|
||||
ctx->callbacks.subscribe_received=(SalOnSubscribeReceived)unimplemented_stub;
|
||||
if (ctx->callbacks.subscribe_closed==NULL)
|
||||
ctx->callbacks.subscribe_closed=(SalOnSubscribeClosed)unimplemented_stub;
|
||||
if (ctx->callbacks.incoming_subscribe_closed==NULL)
|
||||
ctx->callbacks.incoming_subscribe_closed=(SalOnIncomingSubscribeClosed)unimplemented_stub;
|
||||
if (ctx->callbacks.parse_presence_requested==NULL)
|
||||
ctx->callbacks.parse_presence_requested=(SalOnParsePresenceRequested)unimplemented_stub;
|
||||
if (ctx->callbacks.convert_presence_to_xml_requested==NULL)
|
||||
|
|
@ -595,6 +597,10 @@ int sal_transport_available(Sal *sal, SalTransport t){
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
bool_t sal_content_encoding_available(Sal *sal, const char *content_encoding) {
|
||||
return (bool_t)belle_sip_stack_content_encoding_available(sal->stack, content_encoding);
|
||||
}
|
||||
|
||||
static int sal_add_listen_port(Sal *ctx, SalAddress* addr, bool_t is_tunneled){
|
||||
int result;
|
||||
belle_sip_listening_point_t* lp;
|
||||
|
|
@ -734,13 +740,14 @@ static void set_tls_properties(Sal *ctx){
|
|||
belle_sip_listening_point_t *lp=belle_sip_provider_get_listening_point(ctx->prov,"TLS");
|
||||
if (lp){
|
||||
belle_sip_tls_listening_point_t *tlp=BELLE_SIP_TLS_LISTENING_POINT(lp);
|
||||
int verify_exceptions=0;
|
||||
|
||||
if (!ctx->tls_verify) verify_exceptions=BELLE_SIP_TLS_LISTENING_POINT_BADCERT_ANY_REASON;
|
||||
else if (!ctx->tls_verify_cn) verify_exceptions=BELLE_SIP_TLS_LISTENING_POINT_BADCERT_CN_MISMATCH;
|
||||
|
||||
belle_sip_tls_listening_point_set_root_ca(tlp,ctx->root_ca); /*root_ca might be NULL */
|
||||
belle_sip_tls_listening_point_set_verify_exceptions(tlp,verify_exceptions);
|
||||
belle_tls_crypto_config_t *crypto_config = belle_tls_crypto_config_new();
|
||||
int verify_exceptions = BELLE_TLS_VERIFY_NONE;
|
||||
if (!ctx->tls_verify) verify_exceptions = BELLE_TLS_VERIFY_ANY_REASON;
|
||||
else if (!ctx->tls_verify_cn) verify_exceptions = BELLE_TLS_VERIFY_CN_MISMATCH;
|
||||
belle_tls_crypto_config_set_verify_exceptions(crypto_config, verify_exceptions);
|
||||
if (ctx->root_ca != NULL) belle_tls_crypto_config_set_root_ca(crypto_config, ctx->root_ca);
|
||||
belle_sip_tls_listening_point_set_crypto_config(tlp, crypto_config);
|
||||
belle_sip_object_unref(crypto_config);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -816,6 +823,7 @@ bool_t sal_nat_helper_enabled(Sal *sal) {
|
|||
void sal_set_dns_timeout(Sal* sal,int timeout) {
|
||||
belle_sip_stack_set_dns_timeout(sal->stack, timeout);
|
||||
}
|
||||
|
||||
int sal_get_dns_timeout(const Sal* sal) {
|
||||
return belle_sip_stack_get_dns_timeout(sal->stack);
|
||||
}
|
||||
|
|
@ -823,12 +831,26 @@ int sal_get_dns_timeout(const Sal* sal) {
|
|||
void sal_set_transport_timeout(Sal* sal,int timeout) {
|
||||
belle_sip_stack_set_transport_timeout(sal->stack, timeout);
|
||||
}
|
||||
|
||||
int sal_get_transport_timeout(const Sal* sal) {
|
||||
return belle_sip_stack_get_transport_timeout(sal->stack);
|
||||
}
|
||||
|
||||
void sal_set_dns_servers(Sal *sal, const MSList *servers){
|
||||
belle_sip_list_t *l = NULL;
|
||||
|
||||
/*we have to convert the MSList into a belle_sip_list_t first*/
|
||||
for (; servers != NULL; servers = servers->next){
|
||||
l = belle_sip_list_append(l, servers->data);
|
||||
}
|
||||
belle_sip_stack_set_dns_servers(sal->stack, l);
|
||||
belle_sip_list_free(l);
|
||||
}
|
||||
|
||||
void sal_enable_dns_srv(Sal *sal, bool_t enable) {
|
||||
belle_sip_stack_enable_dns_srv(sal->stack, (unsigned char)enable);
|
||||
}
|
||||
|
||||
bool_t sal_dns_srv_enabled(const Sal *sal) {
|
||||
return (bool_t)belle_sip_stack_dns_srv_enabled(sal->stack);
|
||||
}
|
||||
|
|
@ -976,12 +998,11 @@ typedef struct {
|
|||
unsigned char node[6];
|
||||
} sal_uuid_t;
|
||||
|
||||
|
||||
int sal_create_uuid(Sal*ctx, char *uuid, size_t len){
|
||||
int sal_generate_uuid(char *uuid, size_t len) {
|
||||
sal_uuid_t uuid_struct;
|
||||
int i;
|
||||
int written;
|
||||
|
||||
|
||||
if (len==0) return -1;
|
||||
/*create an UUID as described in RFC4122, 4.4 */
|
||||
belle_sip_random_bytes((unsigned char*)&uuid_struct, sizeof(sal_uuid_t));
|
||||
|
|
@ -1000,10 +1021,17 @@ int sal_create_uuid(Sal*ctx, char *uuid, size_t len){
|
|||
for (i = 0; i < 6; i++)
|
||||
written+=snprintf(uuid+written,len-written,"%2.2x", uuid_struct.node[i]);
|
||||
uuid[len-1]='\0';
|
||||
sal_set_uuid(ctx,uuid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sal_create_uuid(Sal*ctx, char *uuid, size_t len) {
|
||||
if (sal_generate_uuid(uuid, len) == 0) {
|
||||
sal_set_uuid(ctx, uuid);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void make_supported_header(Sal *sal){
|
||||
MSList *it;
|
||||
char *alltags=NULL;
|
||||
|
|
@ -1018,7 +1046,7 @@ static void make_supported_header(Sal *sal){
|
|||
const char *tag=(const char*)it->data;
|
||||
size_t taglen=strlen(tag);
|
||||
if (alltags==NULL || (written+taglen+1>=buflen)) alltags=ms_realloc(alltags,(buflen=buflen*2));
|
||||
snprintf(alltags+written,buflen-written,it->next ? "%s, " : "%s",tag);
|
||||
written+=snprintf(alltags+written,buflen-written,it->next ? "%s, " : "%s",tag);
|
||||
}
|
||||
if (alltags){
|
||||
sal->supported=belle_sip_header_create("Supported",alltags);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "belle-sip/belle-sdp.h"
|
||||
|
||||
struct Sal{
|
||||
MSFactory *factory;
|
||||
SalCallbacks callbacks;
|
||||
MSList *pending_auths;/*MSList of SalOp */
|
||||
belle_sip_stack_t* stack;
|
||||
|
|
@ -166,10 +167,9 @@ belle_sip_response_t *sal_create_response_from_request(Sal *sal, belle_sip_reque
|
|||
|
||||
void sal_op_assign_recv_headers(SalOp *op, belle_sip_message_t *incoming);
|
||||
|
||||
void sal_op_add_body(SalOp *op, belle_sip_message_t *req, const SalBody *body);
|
||||
bool_t sal_op_get_body(SalOp *op, belle_sip_message_t *msg, SalBody *salbody);
|
||||
SalBodyHandler * sal_op_get_body_handler(SalOp *op, belle_sip_message_t *msg);
|
||||
|
||||
SalReason sal_reason_to_sip_code(SalReason r);
|
||||
int sal_reason_to_sip_code(SalReason r);
|
||||
|
||||
void _sal_op_add_custom_headers(SalOp *op, belle_sip_message_t *msg);
|
||||
|
||||
|
|
|
|||
|
|
@ -57,13 +57,13 @@ static void sdp_process(SalOp *h){
|
|||
|
||||
h->result=sal_media_description_new();
|
||||
if (h->sdp_offering){
|
||||
offer_answer_initiate_outgoing(h->base.local_media,h->base.remote_media,h->result);
|
||||
offer_answer_initiate_outgoing(h->base.root->factory, h->base.local_media,h->base.remote_media,h->result);
|
||||
}else{
|
||||
int i;
|
||||
if (h->sdp_answer){
|
||||
belle_sip_object_unref(h->sdp_answer);
|
||||
}
|
||||
offer_answer_initiate_incoming(h->base.local_media,h->base.remote_media,h->result,h->base.root->one_matching_codec);
|
||||
offer_answer_initiate_incoming(h->base.root->factory, h->base.local_media,h->base.remote_media,h->result,h->base.root->one_matching_codec);
|
||||
/*for backward compatibility purpose*/
|
||||
if(h->cnx_ip_to_0000_if_sendonly_enabled && sal_media_description_has_dir(h->result,SalStreamSendOnly)) {
|
||||
set_addr_to_0000(h->result->addr);
|
||||
|
|
@ -308,7 +308,7 @@ static void call_process_response(void *op_base, const belle_sip_response_event_
|
|||
if (code >=200 && code<300) {
|
||||
handle_sdp_from_response(op,response);
|
||||
ack=belle_sip_dialog_create_ack(op->dialog,belle_sip_dialog_get_local_seq_number(op->dialog));
|
||||
if (ack==NULL) {
|
||||
if (ack == NULL) {
|
||||
ms_error("This call has been already terminated.");
|
||||
return ;
|
||||
}
|
||||
|
|
@ -317,6 +317,7 @@ static void call_process_response(void *op_base, const belle_sip_response_event_
|
|||
belle_sip_object_unref(op->sdp_answer);
|
||||
op->sdp_answer=NULL;
|
||||
}
|
||||
belle_sip_message_add_header(BELLE_SIP_MESSAGE(ack),BELLE_SIP_HEADER(op->base.root->user_agent));
|
||||
belle_sip_dialog_send_ack(op->dialog,ack);
|
||||
op->base.root->callbacks.call_accepted(op); /*INVITE*/
|
||||
op->state=SalOpStateActive;
|
||||
|
|
@ -669,15 +670,19 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t
|
|||
|
||||
}
|
||||
}else{
|
||||
SalBody salbody;
|
||||
if (sal_op_get_body(op,(belle_sip_message_t*)req,&salbody)) {
|
||||
if (sal_body_has_type(&salbody,"application","dtmf-relay")){
|
||||
belle_sip_message_t *msg = BELLE_SIP_MESSAGE(req);
|
||||
belle_sip_body_handler_t *body_handler = BELLE_SIP_BODY_HANDLER(sal_op_get_body_handler(op, msg));
|
||||
if (body_handler) {
|
||||
belle_sip_header_content_type_t *content_type = belle_sip_message_get_header_by_type(msg, belle_sip_header_content_type_t);
|
||||
if (content_type
|
||||
&& (strcmp(belle_sip_header_content_type_get_type(content_type), "application") == 0)
|
||||
&& (strcmp(belle_sip_header_content_type_get_subtype(content_type), "dtmf-relay") == 0)) {
|
||||
char tmp[10];
|
||||
if (sal_lines_get_value(salbody.data, "Signal",tmp, sizeof(tmp))){
|
||||
if (sal_lines_get_value(belle_sip_message_get_body(msg), "Signal",tmp, sizeof(tmp))){
|
||||
op->base.root->callbacks.dtmf_received(op,tmp[0]);
|
||||
}
|
||||
}else
|
||||
op->base.root->callbacks.info_received(op,&salbody);
|
||||
op->base.root->callbacks.info_received(op, (SalBodyHandler *)body_handler);
|
||||
} else {
|
||||
op->base.root->callbacks.info_received(op,NULL);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ static void sal_op_set_referred_by(SalOp* op,belle_sip_header_referred_by_t* ref
|
|||
|
||||
int sal_call_refer_to(SalOp *op, belle_sip_header_refer_to_t* refer_to, belle_sip_header_referred_by_t* referred_by){
|
||||
char* tmp;
|
||||
belle_sip_request_t* req=op->dialog?belle_sip_dialog_create_request(op->dialog,"REFER"):NULL; /*cannot create request if dialog not set yet*/
|
||||
belle_sip_request_t* req=op->dialog?belle_sip_dialog_create_request(op->dialog,"REFER"):sal_op_build_request(op, "REFER");
|
||||
if (!req) {
|
||||
tmp=belle_sip_uri_to_string(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(refer_to)));
|
||||
ms_error("Cannot refer to [%s] for op [%p]",tmp,op);
|
||||
|
|
|
|||
|
|
@ -46,11 +46,15 @@ static void subscribe_refresher_listener (belle_sip_refresher_t* refresher
|
|||
if (status_code==200) sss=SalSubscribeActive;
|
||||
else if (status_code==202) sss=SalSubscribePending;
|
||||
set_or_update_dialog(op,belle_sip_transaction_get_dialog(tr));
|
||||
}
|
||||
if (status_code>=200){
|
||||
sal_error_info_set(&op->error_info,SalReasonUnknown,status_code,reason_phrase,NULL);
|
||||
op->base.root->callbacks.subscribe_response(op,sss);
|
||||
}else if (status_code==0){
|
||||
} else if (status_code >= 300) {
|
||||
SalReason reason = SalReasonUnknown;
|
||||
if (status_code == 503) { /*refresher returns 503 for IO error*/
|
||||
reason = SalReasonIOError;
|
||||
}
|
||||
sal_error_info_set(&op->error_info,reason,status_code,reason_phrase,NULL);
|
||||
op->base.root->callbacks.subscribe_response(op,sss);
|
||||
}if (status_code==0){
|
||||
op->base.root->callbacks.on_expire(op);
|
||||
}
|
||||
|
||||
|
|
@ -61,10 +65,20 @@ static void subscribe_process_io_error(void *user_ctx, const belle_sip_io_error_
|
|||
}
|
||||
|
||||
static void subscribe_process_dialog_terminated(void *ctx, const belle_sip_dialog_terminated_event_t *event) {
|
||||
belle_sip_dialog_t *dialog = belle_sip_dialog_terminated_event_get_dialog(event);
|
||||
SalOp* op= (SalOp*)ctx;
|
||||
if (op->dialog) {
|
||||
op->dialog=NULL;
|
||||
if (!belle_sip_dialog_is_server(dialog) && belle_sip_dialog_terminated_event_is_expired(event)){
|
||||
/*notify the app that our subscription is dead*/
|
||||
const char *eventname = NULL;
|
||||
if (op->event){
|
||||
eventname = belle_sip_header_get_unparsed_value(op->event);
|
||||
}
|
||||
op->base.root->callbacks.notify(op, SalSubscribeTerminated, eventname, NULL);
|
||||
}
|
||||
sal_op_unref(op);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -77,7 +91,7 @@ static void subscribe_process_timeout(void *user_ctx, const belle_sip_timeout_ev
|
|||
static void subscribe_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) {
|
||||
}
|
||||
|
||||
static void handle_notify(SalOp *op, belle_sip_request_t *req, const char *eventname, SalBody * body){
|
||||
static void handle_notify(SalOp *op, belle_sip_request_t *req, const char *eventname, SalBodyHandler* body_handler){
|
||||
SalSubscribeStatus sub_state;
|
||||
belle_sip_header_subscription_state_t* subscription_state_header=belle_sip_message_get_header_by_type(req,belle_sip_header_subscription_state_t);
|
||||
belle_sip_response_t* resp;
|
||||
|
|
@ -89,7 +103,7 @@ static void handle_notify(SalOp *op, belle_sip_request_t *req, const char *event
|
|||
} else
|
||||
sub_state=SalSubscribeActive;
|
||||
sal_op_ref(op);
|
||||
op->base.root->callbacks.notify(op,sub_state,eventname,body);
|
||||
op->base.root->callbacks.notify(op,sub_state,eventname,body_handler);
|
||||
resp=sal_op_create_response_from_request(op,req,200);
|
||||
belle_sip_server_transaction_send_response(server_transaction,resp);
|
||||
sal_op_unref(op);
|
||||
|
|
@ -102,7 +116,7 @@ static void subscribe_process_request_event(void *op_base, const belle_sip_reque
|
|||
belle_sip_dialog_state_t dialog_state;
|
||||
belle_sip_header_expires_t* expires = belle_sip_message_get_header_by_type(req,belle_sip_header_expires_t);
|
||||
belle_sip_header_t *event_header;
|
||||
SalBody body;
|
||||
belle_sip_body_handler_t *body_handler;
|
||||
belle_sip_response_t* resp;
|
||||
const char *eventname=NULL;
|
||||
const char *method=belle_sip_request_get_method(req);
|
||||
|
|
@ -112,12 +126,13 @@ static void subscribe_process_request_event(void *op_base, const belle_sip_reque
|
|||
op->pending_server_trans=server_transaction;
|
||||
|
||||
event_header=belle_sip_message_get_header((belle_sip_message_t*)req,"Event");
|
||||
sal_op_get_body(op,(belle_sip_message_t*)req,&body);
|
||||
body_handler = BELLE_SIP_BODY_HANDLER(sal_op_get_body_handler(op, BELLE_SIP_MESSAGE(req)));
|
||||
|
||||
if (event_header==NULL){
|
||||
ms_warning("No event header in incoming SUBSCRIBE.");
|
||||
resp=sal_op_create_response_from_request(op,req,400);
|
||||
belle_sip_server_transaction_send_response(server_transaction,resp);
|
||||
if (!op->dialog) sal_op_release(op);
|
||||
return;
|
||||
}
|
||||
if (op->event==NULL) {
|
||||
|
|
@ -128,11 +143,17 @@ static void subscribe_process_request_event(void *op_base, const belle_sip_reque
|
|||
|
||||
if (!op->dialog) {
|
||||
if (strcmp(method,"SUBSCRIBE")==0){
|
||||
op->dialog=belle_sip_provider_create_dialog(op->base.root->prov,BELLE_SIP_TRANSACTION(server_transaction));
|
||||
op->dialog = belle_sip_provider_create_dialog(op->base.root->prov,BELLE_SIP_TRANSACTION(server_transaction));
|
||||
if (!op->dialog){
|
||||
resp=sal_op_create_response_from_request(op,req,481);
|
||||
belle_sip_server_transaction_send_response(server_transaction,resp);
|
||||
sal_op_release(op);
|
||||
return;
|
||||
}
|
||||
belle_sip_dialog_set_application_data(op->dialog, sal_op_ref(op));
|
||||
ms_message("new incoming subscription from [%s] to [%s]",sal_op_get_from(op),sal_op_get_to(op));
|
||||
}else{ /*this is a NOTIFY*/
|
||||
handle_notify(op,req,eventname,&body);
|
||||
handle_notify(op, req, eventname, (SalBodyHandler *)body_handler);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -140,7 +161,10 @@ static void subscribe_process_request_event(void *op_base, const belle_sip_reque
|
|||
switch(dialog_state) {
|
||||
|
||||
case BELLE_SIP_DIALOG_NULL: {
|
||||
op->base.root->callbacks.subscribe_received(op,eventname,body.type ? &body : NULL);
|
||||
const char *type = NULL;
|
||||
belle_sip_header_content_type_t *content_type = belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req), belle_sip_header_content_type_t);
|
||||
if (content_type) type = belle_sip_header_content_type_get_type(content_type);
|
||||
op->base.root->callbacks.subscribe_received(op, eventname, type ? (SalBodyHandler *)body_handler : NULL);
|
||||
break;
|
||||
}
|
||||
case BELLE_SIP_DIALOG_EARLY:
|
||||
|
|
@ -149,7 +173,7 @@ static void subscribe_process_request_event(void *op_base, const belle_sip_reque
|
|||
|
||||
case BELLE_SIP_DIALOG_CONFIRMED:
|
||||
if (strcmp("NOTIFY",method)==0) {
|
||||
handle_notify(op,req,eventname,&body);
|
||||
handle_notify(op, req, eventname, (SalBodyHandler *)body_handler);
|
||||
} else if (strcmp("SUBSCRIBE",method)==0) {
|
||||
/*either a refresh of an unsubscribe*/
|
||||
if (expires && belle_sip_header_expires_get_expires(expires)>0) {
|
||||
|
|
@ -159,7 +183,7 @@ static void subscribe_process_request_event(void *op_base, const belle_sip_reque
|
|||
ms_message("Unsubscribe received from [%s]",sal_op_get_from(op));
|
||||
resp=sal_op_create_response_from_request(op,req,200);
|
||||
belle_sip_server_transaction_send_response(server_transaction,resp);
|
||||
op->base.root->callbacks.subscribe_closed(op);
|
||||
op->base.root->callbacks.incoming_subscribe_closed(op);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -171,6 +195,18 @@ static void subscribe_process_request_event(void *op_base, const belle_sip_reque
|
|||
|
||||
static belle_sip_listener_callbacks_t op_subscribe_callbacks={ 0 };
|
||||
|
||||
/*Invoke when sal_op_release is called by upper layer*/
|
||||
static void sal_op_release_cb(struct SalOpBase* op_base) {
|
||||
SalOp *op =(SalOp*)op_base;
|
||||
if(op->refresher) {
|
||||
belle_sip_refresher_stop(op->refresher);
|
||||
belle_sip_object_unref(op->refresher);
|
||||
op->refresher=NULL;
|
||||
set_or_update_dialog(op,NULL); /*only if we have refresher. else dialog terminated event will remove association*/
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void sal_op_subscribe_fill_cbs(SalOp*op) {
|
||||
if (op_subscribe_callbacks.process_io_error==NULL){
|
||||
op_subscribe_callbacks.process_io_error=subscribe_process_io_error;
|
||||
|
|
@ -182,10 +218,11 @@ void sal_op_subscribe_fill_cbs(SalOp*op) {
|
|||
}
|
||||
op->callbacks=&op_subscribe_callbacks;
|
||||
op->type=SalOpSubscribe;
|
||||
op->base.release_cb=sal_op_release_cb;
|
||||
}
|
||||
|
||||
|
||||
int sal_subscribe(SalOp *op, const char *from, const char *to, const char *eventname, int expires, const SalBody *body){
|
||||
int sal_subscribe(SalOp *op, const char *from, const char *to, const char *eventname, int expires, const SalBodyHandler *body_handler){
|
||||
belle_sip_request_t *req=NULL;
|
||||
|
||||
if (from)
|
||||
|
|
@ -195,7 +232,6 @@ int sal_subscribe(SalOp *op, const char *from, const char *to, const char *event
|
|||
|
||||
if (!op->dialog){
|
||||
sal_op_subscribe_fill_cbs(op);
|
||||
/*???sal_exosip_fix_route(op); make sure to ha ;lr*/
|
||||
req=sal_op_build_request(op,"SUBSCRIBE");
|
||||
if( req == NULL ) {
|
||||
return -1;
|
||||
|
|
@ -207,13 +243,13 @@ int sal_subscribe(SalOp *op, const char *from, const char *to, const char *event
|
|||
}
|
||||
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),op->event);
|
||||
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(expires)));
|
||||
sal_op_add_body(op,(belle_sip_message_t*)req,body);
|
||||
belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(req), BELLE_SIP_BODY_HANDLER(body_handler));
|
||||
return sal_op_send_and_create_refresher(op,req,expires,subscribe_refresher_listener);
|
||||
}else if (op->refresher){
|
||||
const belle_sip_transaction_t *tr=(const belle_sip_transaction_t*) belle_sip_refresher_get_transaction(op->refresher);
|
||||
belle_sip_request_t *last_req=belle_sip_transaction_get_request(tr);
|
||||
/* modify last request to update body*/
|
||||
sal_op_add_body(op,(belle_sip_message_t*)last_req,body);
|
||||
belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(last_req), BELLE_SIP_BODY_HANDLER(body_handler));
|
||||
return belle_sip_refresher_refresh(op->refresher,expires);
|
||||
}
|
||||
ms_warning("sal_subscribe(): no dialog and no refresher ?");
|
||||
|
|
@ -224,7 +260,7 @@ int sal_unsubscribe(SalOp *op){
|
|||
if (op->refresher){
|
||||
const belle_sip_transaction_t *tr=(const belle_sip_transaction_t*) belle_sip_refresher_get_transaction(op->refresher);
|
||||
belle_sip_request_t *last_req=belle_sip_transaction_get_request(tr);
|
||||
sal_op_add_body(op,(belle_sip_message_t*)last_req,NULL);
|
||||
belle_sip_message_set_body(BELLE_SIP_MESSAGE(last_req), NULL, 0);
|
||||
belle_sip_refresher_refresh(op->refresher,0);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -247,7 +283,7 @@ int sal_subscribe_decline(SalOp *op, SalReason reason){
|
|||
return 0;
|
||||
}
|
||||
|
||||
int sal_notify(SalOp *op, const SalBody *body){
|
||||
int sal_notify(SalOp *op, const SalBodyHandler *body_handler){
|
||||
belle_sip_request_t* notify;
|
||||
|
||||
if (!op->dialog) return -1;
|
||||
|
|
@ -258,8 +294,7 @@ int sal_notify(SalOp *op, const SalBody *body){
|
|||
|
||||
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify)
|
||||
,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_ACTIVE,600)));
|
||||
|
||||
sal_op_add_body(op,(belle_sip_message_t*)notify, body);
|
||||
belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(notify), BELLE_SIP_BODY_HANDLER(body_handler));
|
||||
return sal_op_send_request(op,notify);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@ void sal_op_release(SalOp *op){
|
|||
if (op->state!=SalOpStateTerminating)
|
||||
op->state=SalOpStateTerminated;
|
||||
sal_op_set_user_pointer(op,NULL);/*mandatory because releasing op doesn't not mean freeing op. Make sure back pointer will not be used later*/
|
||||
if (op->base.release_cb)
|
||||
op->base.release_cb(&op->base);
|
||||
if (op->refresher) {
|
||||
belle_sip_refresher_stop(op->refresher);
|
||||
}
|
||||
|
|
@ -163,7 +165,7 @@ belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method) {
|
|||
ms_error("No To: address, cannot build request");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
to_uri = belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(to_address));
|
||||
if( to_uri == NULL ){
|
||||
ms_error("To: address is invalid, cannot build request");
|
||||
|
|
@ -393,7 +395,7 @@ int sal_op_send_request(SalOp* op, belle_sip_request_t* request) {
|
|||
return _sal_op_send_request_with_contact(op, request,need_contact);
|
||||
}
|
||||
|
||||
SalReason sal_reason_to_sip_code(SalReason r){
|
||||
int sal_reason_to_sip_code(SalReason r){
|
||||
int ret=500;
|
||||
switch(r){
|
||||
case SalReasonNone:
|
||||
|
|
@ -518,14 +520,14 @@ SalReason _sal_reason_from_sip_code(int code) {
|
|||
return SalReasonNotImplemented;
|
||||
case 502:
|
||||
return SalReasonBadGateway;
|
||||
case 503:
|
||||
return SalReasonServiceUnavailable;
|
||||
case 504:
|
||||
return SalReasonServerTimeout;
|
||||
case 600:
|
||||
return SalReasonDoNotDisturb;
|
||||
case 603:
|
||||
return SalReasonDeclined;
|
||||
case 503:
|
||||
return SalReasonServiceUnavailable;
|
||||
default:
|
||||
return SalReasonUnknown;
|
||||
}
|
||||
|
|
@ -701,55 +703,21 @@ void sal_op_assign_recv_headers(SalOp *op, belle_sip_message_t *incoming){
|
|||
const char *sal_op_get_remote_contact(const SalOp *op){
|
||||
/*
|
||||
* remote contact is filled in process_response
|
||||
* return sal_custom_header_find(op->base.recv_custom_headers,"Contact");
|
||||
*/
|
||||
return op->base.remote_contact;
|
||||
}
|
||||
|
||||
void sal_op_add_body(SalOp *op, belle_sip_message_t *req, const SalBody *body){
|
||||
belle_sip_message_remove_header((belle_sip_message_t*)req,"Content-type");
|
||||
belle_sip_message_remove_header((belle_sip_message_t*)req,"Content-length");
|
||||
belle_sip_message_remove_header((belle_sip_message_t*)req,"Content-encoding");
|
||||
belle_sip_message_set_body((belle_sip_message_t*)req,NULL,0);
|
||||
if (body && body->type && body->subtype && body->data){
|
||||
belle_sip_message_add_header((belle_sip_message_t*)req,
|
||||
(belle_sip_header_t*)belle_sip_header_content_type_create(body->type,body->subtype));
|
||||
belle_sip_message_add_header((belle_sip_message_t*)req,
|
||||
(belle_sip_header_t*)belle_sip_header_content_length_create(body->size));
|
||||
belle_sip_message_set_body((belle_sip_message_t*)req,(const char*)body->data,body->size);
|
||||
if (body->encoding){
|
||||
belle_sip_message_add_header((belle_sip_message_t*)req,(belle_sip_header_t*)
|
||||
belle_sip_header_create("Content-encoding",body->encoding));
|
||||
}
|
||||
SalBodyHandler * sal_op_get_body_handler(SalOp *op, belle_sip_message_t *msg) {
|
||||
belle_sip_body_handler_t *body_handler = belle_sip_message_get_body_handler(msg);
|
||||
if (body_handler != NULL) {
|
||||
belle_sip_header_content_type_t *content_type = belle_sip_message_get_header_by_type(msg, belle_sip_header_content_type_t);
|
||||
belle_sip_header_content_length_t *content_length = belle_sip_message_get_header_by_type(msg, belle_sip_header_content_length_t);
|
||||
belle_sip_header_t *content_encoding = belle_sip_message_get_header(msg, "Content-Encoding");
|
||||
if (content_type != NULL) belle_sip_body_handler_add_header(body_handler, BELLE_SIP_HEADER(content_type));
|
||||
if (content_length != NULL) belle_sip_body_handler_add_header(body_handler, BELLE_SIP_HEADER(content_length));
|
||||
if (content_encoding != NULL) belle_sip_body_handler_add_header(body_handler, content_encoding);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool_t sal_op_get_body(SalOp *op, belle_sip_message_t *msg, SalBody *salbody){
|
||||
const char *body = NULL;
|
||||
belle_sip_header_content_type_t *content_type;
|
||||
belle_sip_header_content_length_t *clen=NULL;
|
||||
belle_sip_header_t *content_encoding;
|
||||
|
||||
content_type=belle_sip_message_get_header_by_type(msg,belle_sip_header_content_type_t);
|
||||
if (content_type){
|
||||
body=belle_sip_message_get_body(msg);
|
||||
clen=belle_sip_message_get_header_by_type(msg,belle_sip_header_content_length_t);
|
||||
}
|
||||
content_encoding=belle_sip_message_get_header(msg,"Content-encoding");
|
||||
|
||||
memset(salbody,0,sizeof(SalBody));
|
||||
|
||||
if (content_type && body && clen) {
|
||||
salbody->type=belle_sip_header_content_type_get_type(content_type);
|
||||
salbody->subtype=belle_sip_header_content_type_get_subtype(content_type);
|
||||
salbody->data=body;
|
||||
salbody->size=belle_sip_header_content_length_get_content_length(clen);
|
||||
if (content_encoding)
|
||||
salbody->encoding=belle_sip_header_get_unparsed_value(content_encoding);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
return (SalBodyHandler *)body_handler;
|
||||
}
|
||||
|
||||
void sal_op_set_privacy(SalOp* op,SalPrivacyMask privacy) {
|
||||
|
|
@ -823,3 +791,11 @@ bool_t sal_op_cnx_ip_to_0000_if_sendonly_enabled(SalOp *op) {
|
|||
bool_t sal_op_is_forked_of(const SalOp *op1, const SalOp *op2){
|
||||
return op1->base.call_id && op2->base.call_id && strcmp(op1->base.call_id, op2->base.call_id) == 0;
|
||||
}
|
||||
int sal_op_refresh(SalOp *op) {
|
||||
if (op->refresher) {
|
||||
belle_sip_refresher_refresh(op->refresher,belle_sip_refresher_get_expires(op->refresher));
|
||||
return 0;
|
||||
}
|
||||
ms_warning("sal_refresh on op [%p] of type [%s] no refresher",op,sal_op_type_to_string(op->type));
|
||||
return -1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,12 +19,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "sal_impl.h"
|
||||
|
||||
|
||||
int sal_send_info(SalOp *op, const char *from, const char *to, const SalBody *body){
|
||||
int sal_send_info(SalOp *op, const char *from, const char *to, const SalBodyHandler *body_handler){
|
||||
if (op->dialog){
|
||||
belle_sip_request_t *req;
|
||||
belle_sip_dialog_enable_pending_trans_checking(op->dialog,op->base.root->pending_trans_checking);
|
||||
req=belle_sip_dialog_create_queued_request(op->dialog,"INFO");
|
||||
sal_op_add_body(op,(belle_sip_message_t*)req,body);
|
||||
belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(req), BELLE_SIP_BODY_HANDLER(body_handler));
|
||||
return sal_op_send_request(op,req);
|
||||
}
|
||||
return -1;
|
||||
|
|
|
|||
|
|
@ -110,122 +110,127 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve
|
|||
|
||||
from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t);
|
||||
content_type=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_content_type_t);
|
||||
/* check if we have a xml/cipher message to be decrypted */
|
||||
if (content_type && (cipher_xml=is_cipher_xml(content_type))) {
|
||||
/* access the zrtp cache to get keys needed to decipher the message */
|
||||
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
|
||||
FILE *CACHEFD = fopen(lc->zrtp_secrets_cache, "rb+");
|
||||
if (CACHEFD == NULL) {
|
||||
ms_warning("Unable to access ZRTP ZID cache to decrypt message");
|
||||
goto error;
|
||||
} else {
|
||||
size_t cacheSize;
|
||||
char *cacheString;
|
||||
int retval;
|
||||
xmlDocPtr cacheXml;
|
||||
|
||||
cacheString=ms_load_file_content(CACHEFD, &cacheSize);
|
||||
if (!cacheString){
|
||||
ms_warning("Unable to load content of ZRTP ZID cache to decrypt message");
|
||||
goto error;
|
||||
}
|
||||
cacheString[cacheSize] = '\0';
|
||||
cacheSize += 1;
|
||||
fclose(CACHEFD);
|
||||
cacheXml = xmlParseDoc((xmlChar*)cacheString);
|
||||
ms_free(cacheString);
|
||||
retval = lime_decryptMultipartMessage(cacheXml, (uint8_t *)belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)), &decryptedMessage);
|
||||
if (retval != 0) {
|
||||
ms_warning("Unable to decrypt message, reason : %s - op [%p]", lime_error_code_to_string(retval), op);
|
||||
free(decryptedMessage);
|
||||
xmlFreeDoc(cacheXml);
|
||||
errcode = 488;
|
||||
|
||||
if (content_type){
|
||||
|
||||
/* check if we have a xml/cipher message to be decrypted */
|
||||
if ((cipher_xml=is_cipher_xml(content_type))) {
|
||||
/* access the zrtp cache to get keys needed to decipher the message */
|
||||
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
|
||||
FILE *CACHEFD = NULL;
|
||||
if (lc->zrtp_secrets_cache != NULL) CACHEFD = fopen(lc->zrtp_secrets_cache, "rb+");
|
||||
if (CACHEFD == NULL) {
|
||||
ms_warning("Unable to access ZRTP ZID cache to decrypt message");
|
||||
goto error;
|
||||
} else {
|
||||
/* dump updated cache to a string */
|
||||
xmlChar *xmlStringOutput;
|
||||
int xmlStringLength;
|
||||
xmlDocDumpFormatMemoryEnc(cacheXml, &xmlStringOutput, &xmlStringLength, "UTF-8", 0);
|
||||
/* write it to the cache file */
|
||||
CACHEFD = fopen(lc->zrtp_secrets_cache, "wb+");
|
||||
if (fwrite(xmlStringOutput, 1, xmlStringLength, CACHEFD)<=0){
|
||||
ms_warning("Fail to write cache");
|
||||
size_t cacheSize;
|
||||
char *cacheString;
|
||||
int retval;
|
||||
xmlDocPtr cacheXml;
|
||||
|
||||
cacheString=ms_load_file_content(CACHEFD, &cacheSize);
|
||||
if (!cacheString){
|
||||
ms_warning("Unable to load content of ZRTP ZID cache to decrypt message");
|
||||
goto error;
|
||||
}
|
||||
xmlFree(xmlStringOutput);
|
||||
cacheString[cacheSize] = '\0';
|
||||
cacheSize += 1;
|
||||
fclose(CACHEFD);
|
||||
cacheXml = xmlParseDoc((xmlChar*)cacheString);
|
||||
ms_free(cacheString);
|
||||
retval = lime_decryptMultipartMessage(cacheXml, (uint8_t *)belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)), &decryptedMessage);
|
||||
if (retval != 0) {
|
||||
ms_warning("Unable to decrypt message, reason : %s - op [%p]", lime_error_code_to_string(retval), op);
|
||||
free(decryptedMessage);
|
||||
xmlFreeDoc(cacheXml);
|
||||
errcode = 488;
|
||||
goto error;
|
||||
} else {
|
||||
/* dump updated cache to a string */
|
||||
xmlChar *xmlStringOutput;
|
||||
int xmlStringLength;
|
||||
xmlDocDumpFormatMemoryEnc(cacheXml, &xmlStringOutput, &xmlStringLength, "UTF-8", 0);
|
||||
/* write it to the cache file */
|
||||
CACHEFD = fopen(lc->zrtp_secrets_cache, "wb+");
|
||||
if (fwrite(xmlStringOutput, 1, xmlStringLength, CACHEFD)<=0){
|
||||
ms_warning("Fail to write cache");
|
||||
}
|
||||
xmlFree(xmlStringOutput);
|
||||
fclose(CACHEFD);
|
||||
}
|
||||
|
||||
xmlFreeDoc(cacheXml);
|
||||
}
|
||||
|
||||
xmlFreeDoc(cacheXml);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
rcs_filetransfer=is_rcs_filetransfer(content_type);
|
||||
if (content_type && ((plain_text=is_plain_text(content_type))
|
||||
|| (external_body=is_external_body(content_type))
|
||||
|| (decryptedMessage!=NULL)
|
||||
|| rcs_filetransfer)) {
|
||||
SalMessage salmsg;
|
||||
char message_id[256]={0};
|
||||
external_body=is_external_body(content_type);
|
||||
plain_text=is_plain_text(content_type);
|
||||
rcs_filetransfer = is_rcs_filetransfer(content_type);
|
||||
|
||||
if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans);
|
||||
op->pending_server_trans=server_transaction;
|
||||
belle_sip_object_ref(op->pending_server_trans);
|
||||
|
||||
address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header))
|
||||
,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header)));
|
||||
from=belle_sip_object_to_string(BELLE_SIP_OBJECT(address));
|
||||
snprintf(message_id,sizeof(message_id)-1,"%s%i"
|
||||
,belle_sip_header_call_id_get_call_id(call_id)
|
||||
,belle_sip_header_cseq_get_seq_number(cseq));
|
||||
salmsg.from=from;
|
||||
/* if we just deciphered a message, use the deciphered part(which can be a rcs xml body pointing to the file to retreive from server)*/
|
||||
if (cipher_xml) {
|
||||
salmsg.text = (char *)decryptedMessage;
|
||||
} else { /* message body wasn't ciphered */
|
||||
salmsg.text=(plain_text||rcs_filetransfer)?belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)):NULL;
|
||||
}
|
||||
salmsg.url=NULL;
|
||||
salmsg.content_type = NULL;
|
||||
if (rcs_filetransfer) { /* if we have a rcs file transfer, set the type, message body (stored in salmsg.text) contains all needed information to retrieve the file */
|
||||
salmsg.content_type = "application/vnd.gsma.rcs-ft-http+xml";
|
||||
}
|
||||
if (external_body && belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")) {
|
||||
size_t url_length=strlen(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL"));
|
||||
salmsg.url = ms_strdup(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")+1); /* skip first "*/
|
||||
((char*)salmsg.url)[url_length-2]='\0'; /*remove trailing "*/
|
||||
}
|
||||
salmsg.message_id=message_id;
|
||||
salmsg.time=date ? belle_sip_header_date_get_time(date) : time(NULL);
|
||||
op->base.root->callbacks.text_received(op,&salmsg);
|
||||
if (external_body || plain_text || rcs_filetransfer || decryptedMessage!=NULL) {
|
||||
SalMessage salmsg;
|
||||
char message_id[256]={0};
|
||||
|
||||
if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans);
|
||||
op->pending_server_trans=server_transaction;
|
||||
belle_sip_object_ref(op->pending_server_trans);
|
||||
|
||||
address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header))
|
||||
,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header)));
|
||||
from=belle_sip_object_to_string(BELLE_SIP_OBJECT(address));
|
||||
snprintf(message_id,sizeof(message_id)-1,"%s%i"
|
||||
,belle_sip_header_call_id_get_call_id(call_id)
|
||||
,belle_sip_header_cseq_get_seq_number(cseq));
|
||||
salmsg.from=from;
|
||||
/* if we just deciphered a message, use the deciphered part(which can be a rcs xml body pointing to the file to retreive from server)*/
|
||||
if (cipher_xml) {
|
||||
salmsg.text = (char *)decryptedMessage;
|
||||
} else { /* message body wasn't ciphered */
|
||||
salmsg.text=(plain_text||rcs_filetransfer)?belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)):NULL;
|
||||
}
|
||||
salmsg.url=NULL;
|
||||
salmsg.content_type = NULL;
|
||||
if (rcs_filetransfer) { /* if we have a rcs file transfer, set the type, message body (stored in salmsg.text) contains all needed information to retrieve the file */
|
||||
salmsg.content_type = "application/vnd.gsma.rcs-ft-http+xml";
|
||||
}
|
||||
if (external_body && belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")) {
|
||||
size_t url_length=strlen(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL"));
|
||||
salmsg.url = ms_strdup(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")+1); /* skip first "*/
|
||||
((char*)salmsg.url)[url_length-2]='\0'; /*remove trailing "*/
|
||||
}
|
||||
salmsg.message_id=message_id;
|
||||
salmsg.time=date ? belle_sip_header_date_get_time(date) : time(NULL);
|
||||
op->base.root->callbacks.text_received(op,&salmsg);
|
||||
|
||||
free(decryptedMessage);
|
||||
belle_sip_object_unref(address);
|
||||
belle_sip_free(from);
|
||||
if (salmsg.url) ms_free((char*)salmsg.url);
|
||||
} else if (content_type && is_im_iscomposing(content_type)) {
|
||||
SalIsComposing saliscomposing;
|
||||
address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header))
|
||||
,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header)));
|
||||
from=belle_sip_object_to_string(BELLE_SIP_OBJECT(address));
|
||||
saliscomposing.from=from;
|
||||
saliscomposing.text=belle_sip_message_get_body(BELLE_SIP_MESSAGE(req));
|
||||
op->base.root->callbacks.is_composing_received(op,&saliscomposing);
|
||||
resp = belle_sip_response_create_from_request(req,200);
|
||||
belle_sip_server_transaction_send_response(server_transaction,resp);
|
||||
belle_sip_object_unref(address);
|
||||
belle_sip_free(from);
|
||||
} else {
|
||||
ms_error("Unsupported MESSAGE (content-type not recognized)");
|
||||
resp = belle_sip_response_create_from_request(req,415);
|
||||
add_message_accept((belle_sip_message_t*)resp);
|
||||
belle_sip_server_transaction_send_response(server_transaction,resp);
|
||||
sal_op_release(op);
|
||||
return;
|
||||
free(decryptedMessage);
|
||||
belle_sip_object_unref(address);
|
||||
belle_sip_free(from);
|
||||
if (salmsg.url) ms_free((char*)salmsg.url);
|
||||
} else if (is_im_iscomposing(content_type)) {
|
||||
SalIsComposing saliscomposing;
|
||||
address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header))
|
||||
,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header)));
|
||||
from=belle_sip_object_to_string(BELLE_SIP_OBJECT(address));
|
||||
saliscomposing.from=from;
|
||||
saliscomposing.text=belle_sip_message_get_body(BELLE_SIP_MESSAGE(req));
|
||||
op->base.root->callbacks.is_composing_received(op,&saliscomposing);
|
||||
resp = belle_sip_response_create_from_request(req,200);
|
||||
belle_sip_server_transaction_send_response(server_transaction,resp);
|
||||
belle_sip_object_unref(address);
|
||||
belle_sip_free(from);
|
||||
}else{
|
||||
ms_error("Unsupported MESSAGE (content-type not recognized)");
|
||||
errcode = 415;
|
||||
goto error;
|
||||
}
|
||||
}else {
|
||||
ms_error("Unsupported MESSAGE (no Content-Type)");
|
||||
goto error;
|
||||
}
|
||||
return;
|
||||
error:
|
||||
resp = belle_sip_response_create_from_request(req, errcode);
|
||||
add_message_accept((belle_sip_message_t*)resp);
|
||||
belle_sip_server_transaction_send_response(server_transaction,resp);
|
||||
sal_op_release(op);
|
||||
}
|
||||
|
|
@ -239,8 +244,9 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co
|
|||
belle_sip_request_t* req;
|
||||
char content_type_raw[256];
|
||||
size_t content_length = msg?strlen(msg):0;
|
||||
time_t curtime=time(NULL);
|
||||
time_t curtime = ms_time(NULL);
|
||||
uint8_t *multipartEncryptedMessage = NULL;
|
||||
const char *body;
|
||||
int retval;
|
||||
|
||||
if (op->dialog){
|
||||
|
|
@ -321,7 +327,11 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co
|
|||
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_type_parse(content_type_raw)));
|
||||
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length)));
|
||||
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_date_create_from_time(&curtime)));
|
||||
belle_sip_message_set_body(BELLE_SIP_MESSAGE(req),(multipartEncryptedMessage==NULL)?msg:(const char *)multipartEncryptedMessage,content_length);
|
||||
body = (multipartEncryptedMessage==NULL) ? msg : (char*) multipartEncryptedMessage;
|
||||
if (body){
|
||||
/*don't call set_body() with null argument because it resets content type and content length*/
|
||||
belle_sip_message_set_body(BELLE_SIP_MESSAGE(req), body, content_length);
|
||||
}
|
||||
retval = sal_op_send_request(op,req);
|
||||
free(multipartEncryptedMessage);
|
||||
|
||||
|
|
|
|||
|
|
@ -52,15 +52,13 @@ static void presence_process_io_error(void *user_ctx, const belle_sip_io_error_e
|
|||
|
||||
static void presence_process_dialog_terminated(void *ctx, const belle_sip_dialog_terminated_event_t *event) {
|
||||
SalOp* op= (SalOp*)ctx;
|
||||
if (op->dialog) {
|
||||
if (belle_sip_dialog_is_server(op->dialog)){
|
||||
if (op->dialog && belle_sip_dialog_is_server(op->dialog)) {
|
||||
ms_message("Incoming subscribtion from [%s] terminated",sal_op_get_from(op));
|
||||
if (!op->op_released){
|
||||
op->base.root->callbacks.subscribe_presence_closed(op, sal_op_get_from(op));
|
||||
}
|
||||
}
|
||||
set_or_update_dialog(op, NULL);
|
||||
}
|
||||
set_or_update_dialog(op, NULL);
|
||||
}/* else client dialog is managed by refresher*/
|
||||
}
|
||||
|
||||
static void presence_refresher_listener(belle_sip_refresher_t* refresher, void* user_pointer, unsigned int status_code, const char* reason_phrase){
|
||||
|
|
@ -135,13 +133,6 @@ static void presence_response_event(void *op_base, const belle_sip_response_even
|
|||
}
|
||||
break;
|
||||
}
|
||||
case BELLE_SIP_DIALOG_TERMINATED:
|
||||
if (op->refresher) {
|
||||
belle_sip_refresher_stop(op->refresher);
|
||||
belle_sip_object_unref(op->refresher);
|
||||
op->refresher=NULL;
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
ms_error("presence op [%p] receive answer [%i] not implemented",op,code);
|
||||
}
|
||||
|
|
@ -245,6 +236,12 @@ static void presence_process_request_event(void *op_base, const belle_sip_reques
|
|||
if (!op->dialog) {
|
||||
if (strcmp(method,"SUBSCRIBE")==0){
|
||||
belle_sip_dialog_t *dialog = belle_sip_provider_create_dialog(op->base.root->prov,BELLE_SIP_TRANSACTION(server_transaction));
|
||||
if (!dialog){
|
||||
resp=sal_op_create_response_from_request(op,req,481);
|
||||
belle_sip_server_transaction_send_response(server_transaction,resp);
|
||||
sal_op_release(op);
|
||||
return;
|
||||
}
|
||||
set_or_update_dialog(op, dialog);
|
||||
ms_message("new incoming subscription from [%s] to [%s]",sal_op_get_from(op),sal_op_get_to(op));
|
||||
}else{ /* this is a NOTIFY */
|
||||
|
|
@ -282,6 +279,17 @@ static void presence_process_request_event(void *op_base, const belle_sip_reques
|
|||
|
||||
static belle_sip_listener_callbacks_t op_presence_callbacks={0};
|
||||
|
||||
/*Invoke when sal_op_release is called by upper layer*/
|
||||
static void sal_op_release_cb(struct SalOpBase* op_base) {
|
||||
SalOp *op =(SalOp*)op_base;
|
||||
if(op->refresher) {
|
||||
belle_sip_refresher_stop(op->refresher);
|
||||
belle_sip_object_unref(op->refresher);
|
||||
op->refresher=NULL;
|
||||
set_or_update_dialog(op,NULL); /*only if we have refresher. else dialog terminated event will remove association*/
|
||||
}
|
||||
|
||||
}
|
||||
void sal_op_presence_fill_cbs(SalOp*op) {
|
||||
if (op_presence_callbacks.process_request_event==NULL){
|
||||
op_presence_callbacks.process_io_error=presence_process_io_error;
|
||||
|
|
@ -293,6 +301,7 @@ void sal_op_presence_fill_cbs(SalOp*op) {
|
|||
}
|
||||
op->callbacks=&op_presence_callbacks;
|
||||
op->type=SalOpPresence;
|
||||
op->base.release_cb=sal_op_release_cb;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -365,6 +374,7 @@ int sal_notify_presence(SalOp *op, SalPresenceModel *presence){
|
|||
|
||||
int sal_notify_presence_close(SalOp *op){
|
||||
belle_sip_request_t* notify=NULL;
|
||||
int status;
|
||||
if (sal_op_check_dialog_state(op)) {
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -374,7 +384,9 @@ int sal_notify_presence_close(SalOp *op){
|
|||
sal_add_presence_info(op,BELLE_SIP_MESSAGE(notify),NULL); /*FIXME, what about expires ??*/
|
||||
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify)
|
||||
,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,-1)));
|
||||
return sal_op_send_request(op,notify);
|
||||
status = sal_op_send_request(op,notify);
|
||||
set_or_update_dialog(op,NULL); /*because we may be chalanged for the notify, so we must release dialog right now*/
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -25,17 +25,17 @@ static void publish_refresher_listener (belle_sip_refresher_t* refresher
|
|||
,const char* reason_phrase) {
|
||||
SalOp* op = (SalOp*)user_pointer;
|
||||
const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(op->refresher);
|
||||
belle_sip_request_t* last_publish=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(last_publish_trans));
|
||||
belle_sip_response_t *response=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(last_publish_trans));
|
||||
/*belle_sip_response_t* response=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(belle_sip_refresher_get_transaction(refresher)));*/
|
||||
ms_message("Publish refresher [%i] reason [%s] for proxy [%s]",status_code,reason_phrase?reason_phrase:"none",sal_op_get_proxy(op));
|
||||
if (status_code==412){
|
||||
/*resubmit the request after removing the SIP-If-Match*/
|
||||
belle_sip_message_remove_header((belle_sip_message_t*)last_publish,"SIP-If-Match");
|
||||
belle_sip_refresher_refresh(op->refresher,BELLE_SIP_REFRESHER_REUSE_EXPIRES);
|
||||
}else if (status_code==0){
|
||||
if (status_code==0){
|
||||
op->base.root->callbacks.on_expire(op);
|
||||
}else if (status_code>=200){
|
||||
belle_sip_header_t *sip_etag;
|
||||
const char *sip_etag_string = NULL;
|
||||
if (response && (sip_etag = belle_sip_message_get_header(BELLE_SIP_MESSAGE(response), "SIP-ETag"))) {
|
||||
sip_etag_string = belle_sip_header_get_unparsed_value(sip_etag);
|
||||
}
|
||||
sal_op_set_entity_tag(op, sip_etag_string);
|
||||
sal_error_info_set(&op->error_info,SalReasonUnknown,status_code,reason_phrase,NULL);
|
||||
sal_op_assign_recv_headers(op,(belle_sip_message_t*)response);
|
||||
op->base.root->callbacks.on_publish_response(op);
|
||||
|
|
@ -60,43 +60,7 @@ void sal_op_publish_fill_cbs(SalOp *op) {
|
|||
op->type=SalOpPublish;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sending a publish with 0 expires removes the event state and such request shall not contain a body.
|
||||
* See RFC3903, section 4.5
|
||||
*/
|
||||
|
||||
/*presence publish */
|
||||
int sal_publish_presence(SalOp *op, const char *from, const char *to, int expires, SalPresenceModel *presence){
|
||||
belle_sip_request_t *req=NULL;
|
||||
if(!op->refresher || !belle_sip_refresher_get_transaction(op->refresher)) {
|
||||
if (from)
|
||||
sal_op_set_from(op,from);
|
||||
if (to)
|
||||
sal_op_set_to(op,to);
|
||||
|
||||
op->type=SalOpPublish;
|
||||
req=sal_op_build_request(op,"PUBLISH");
|
||||
|
||||
if( req == NULL ){
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sal_op_get_contact_address(op)){
|
||||
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(sal_op_create_contact(op)));
|
||||
}
|
||||
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event","presence"));
|
||||
sal_add_presence_info(op,BELLE_SIP_MESSAGE(req),presence);
|
||||
return sal_op_send_and_create_refresher(op,req,expires,publish_refresher_listener);
|
||||
} else {
|
||||
/*update presence status*/
|
||||
const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(op->refresher);
|
||||
belle_sip_request_t* last_publish=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(last_publish_trans));
|
||||
sal_add_presence_info(op,BELLE_SIP_MESSAGE(last_publish),expires!=0 ? presence : NULL);
|
||||
return belle_sip_refresher_refresh(op->refresher,expires);
|
||||
}
|
||||
}
|
||||
|
||||
int sal_publish(SalOp *op, const char *from, const char *to, const char *eventname, int expires, const SalBody *body){
|
||||
int sal_publish(SalOp *op, const char *from, const char *to, const char *eventname, int expires, const SalBodyHandler *body_handler){
|
||||
belle_sip_request_t *req=NULL;
|
||||
if(!op->refresher || !belle_sip_refresher_get_transaction(op->refresher)) {
|
||||
if (from)
|
||||
|
|
@ -109,12 +73,16 @@ int sal_publish(SalOp *op, const char *from, const char *to, const char *eventna
|
|||
if( req == NULL ){
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (sal_op_get_entity_tag(op)) {
|
||||
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("SIP-If-Match", sal_op_get_entity_tag(op)));
|
||||
}
|
||||
|
||||
if (sal_op_get_contact_address(op)){
|
||||
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(sal_op_create_contact(op)));
|
||||
}
|
||||
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event",eventname));
|
||||
sal_op_add_body(op,BELLE_SIP_MESSAGE(req),body);
|
||||
belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(req), BELLE_SIP_BODY_HANDLER(body_handler));
|
||||
if (expires!=-1)
|
||||
return sal_op_send_and_create_refresher(op,req,expires,publish_refresher_listener);
|
||||
else return sal_op_send_request(op,req);
|
||||
|
|
@ -123,7 +91,22 @@ int sal_publish(SalOp *op, const char *from, const char *to, const char *eventna
|
|||
const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(op->refresher);
|
||||
belle_sip_request_t* last_publish=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(last_publish_trans));
|
||||
/*update body*/
|
||||
sal_op_add_body(op,BELLE_SIP_MESSAGE(last_publish),expires!=0 ? body : NULL);
|
||||
if (expires == 0) {
|
||||
belle_sip_message_set_body(BELLE_SIP_MESSAGE(last_publish), NULL, 0);
|
||||
} else {
|
||||
belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(last_publish), BELLE_SIP_BODY_HANDLER(body_handler));
|
||||
}
|
||||
return belle_sip_refresher_refresh(op->refresher,expires==-1 ? BELLE_SIP_REFRESHER_REUSE_EXPIRES : expires);
|
||||
}
|
||||
}
|
||||
|
||||
int sal_op_unpublish(SalOp *op){
|
||||
if (op->refresher){
|
||||
const belle_sip_transaction_t *tr=(const belle_sip_transaction_t*) belle_sip_refresher_get_transaction(op->refresher);
|
||||
belle_sip_request_t *last_req=belle_sip_transaction_get_request(tr);
|
||||
belle_sip_message_set_body(BELLE_SIP_MESSAGE(last_req), NULL, 0);
|
||||
belle_sip_refresher_refresh(op->refresher,0);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
/*
|
||||
linphone
|
||||
Copyright (C) 2012 Belledonne Communications, Grenoble, France
|
||||
|
|
@ -125,7 +126,7 @@ static void add_rtcp_fb_attributes(belle_sdp_media_description_t *media_desc, co
|
|||
uint16_t trr_int = 0;
|
||||
|
||||
general_trr_int = is_rtcp_fb_trr_int_the_same_for_all_payloads(stream, &trr_int);
|
||||
if (general_trr_int == TRUE) {
|
||||
if (general_trr_int == TRUE && trr_int != 0) {
|
||||
add_rtcp_fb_trr_int_attribute(media_desc, -1, trr_int);
|
||||
}
|
||||
if (stream->rtcp_fb.generic_nack_enabled == TRUE) {
|
||||
|
|
@ -143,7 +144,7 @@ static void add_rtcp_fb_attributes(belle_sdp_media_description_t *media_desc, co
|
|||
avpf_params = payload_type_get_avpf_params(pt);
|
||||
|
||||
/* Add trr-int if not set generally. */
|
||||
if (general_trr_int != TRUE) {
|
||||
if (general_trr_int != TRUE && trr_int != 0) {
|
||||
add_rtcp_fb_trr_int_attribute(media_desc, payload_type_get_number(pt), avpf_params.trr_interval);
|
||||
}
|
||||
|
||||
|
|
@ -319,7 +320,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 ("rtcp",buffer));
|
||||
}
|
||||
}
|
||||
if (stream->ice_completed == TRUE) {
|
||||
if (stream->set_nortpproxy == TRUE) {
|
||||
belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("nortpproxy","yes"));
|
||||
}
|
||||
if (stream->ice_mismatch == TRUE) {
|
||||
|
|
@ -335,7 +336,7 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session
|
|||
}
|
||||
}
|
||||
|
||||
if ((rtp_port != 0) && sal_stream_description_has_avpf(stream)) {
|
||||
if ((rtp_port != 0) && (sal_stream_description_has_avpf(stream) || sal_stream_description_has_implicit_avpf(stream))) {
|
||||
add_rtcp_fb_attributes(media_desc, md, stream);
|
||||
}
|
||||
|
||||
|
|
@ -422,7 +423,7 @@ belle_sdp_session_description_t * media_description_to_sdp ( const SalMediaDescr
|
|||
belle_sdp_session_description_set_bandwidth ( session_desc,"AS",desc->bandwidth );
|
||||
}
|
||||
|
||||
if (desc->ice_completed == TRUE) belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("nortpproxy","yes"));
|
||||
if (desc->set_nortpproxy == TRUE) belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("nortpproxy","yes"));
|
||||
if (desc->ice_pwd[0] != '\0') belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("ice-pwd",desc->ice_pwd));
|
||||
if (desc->ice_ufrag[0] != '\0') belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("ice-ufrag",desc->ice_ufrag));
|
||||
|
||||
|
|
@ -629,14 +630,15 @@ static void apply_rtcp_fb_attribute_to_payload(belle_sdp_rtcp_fb_attribute_t *fb
|
|||
payload_type_set_avpf_params(pt, avpf_params);
|
||||
}
|
||||
|
||||
static void sdp_parse_rtcp_fb_parameters(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) {
|
||||
static bool_t sdp_parse_rtcp_fb_parameters(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) {
|
||||
belle_sip_list_t *it;
|
||||
belle_sdp_attribute_t *attribute;
|
||||
belle_sdp_rtcp_fb_attribute_t *fb_attribute;
|
||||
MSList *pt_it;
|
||||
PayloadType *pt;
|
||||
int8_t pt_num;
|
||||
|
||||
bool_t retval = FALSE;
|
||||
|
||||
/* Handle rtcp-fb attributes that concern all payload types. */
|
||||
for (it = belle_sdp_media_description_get_attributes(media_desc); it != NULL; it = it->next) {
|
||||
attribute = BELLE_SDP_ATTRIBUTE(it->data);
|
||||
|
|
@ -646,6 +648,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;
|
||||
apply_rtcp_fb_attribute_to_payload(fb_attribute, stream, pt);
|
||||
retval = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -659,12 +662,14 @@ static void sdp_parse_rtcp_fb_parameters(belle_sdp_media_description_t *media_de
|
|||
pt_num = belle_sdp_rtcp_fb_attribute_get_id(fb_attribute);
|
||||
for (pt_it = stream->payloads; pt_it != NULL; pt_it = pt_it->next) {
|
||||
pt = (PayloadType *)pt_it->data;
|
||||
retval = TRUE;
|
||||
if (payload_type_get_number(pt) == (int)pt_num) {
|
||||
apply_rtcp_fb_attribute_to_payload(fb_attribute, stream, pt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void sal_init_rtcp_xr_description(OrtpRtcpXrConfiguration *config) {
|
||||
|
|
@ -727,6 +732,7 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md,
|
|||
belle_sip_list_t *custom_attribute_it;
|
||||
const char* value;
|
||||
const char *mtype,*proto;
|
||||
bool_t has_avpf_attributes;
|
||||
|
||||
stream=&md->streams[md->nb_streams];
|
||||
media=belle_sdp_media_description_get_media ( media_desc );
|
||||
|
|
@ -830,12 +836,17 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md,
|
|||
|
||||
/* Get ICE candidate attributes if any */
|
||||
sdp_parse_media_ice_parameters(media_desc, stream);
|
||||
|
||||
|
||||
has_avpf_attributes = sdp_parse_rtcp_fb_parameters(media_desc, stream);
|
||||
|
||||
/* Get RTCP-FB attributes if any */
|
||||
if (sal_stream_description_has_avpf(stream)) {
|
||||
enable_avpf_for_stream(stream);
|
||||
sdp_parse_rtcp_fb_parameters(media_desc, stream);
|
||||
}
|
||||
else if (has_avpf_attributes ){
|
||||
|
||||
stream->implicit_rtcp_fb = TRUE;
|
||||
}
|
||||
|
||||
/* Get RTCP-XR attributes if any */
|
||||
stream->rtcp_xr = md->rtcp_xr; // Use session parameters if no stream parameters are defined
|
||||
|
|
|
|||
|
|
@ -144,4 +144,4 @@ LINPHONE_PUBLIC bool_t linphone_buffer_is_empty(const LinphoneBuffer *buffer);
|
|||
}
|
||||
#endif
|
||||
|
||||
#endif /* LINPHONE_CONTENT_H_ */
|
||||
#endif /* LINPHONE_BUFFER_H_ */
|
||||
|
|
|
|||
|
|
@ -248,6 +248,10 @@ bool_t linphone_call_log_video_enabled(LinphoneCallLog *cl) {
|
|||
return cl->video_enabled;
|
||||
}
|
||||
|
||||
bool_t linphone_call_log_was_conference(LinphoneCallLog *cl) {
|
||||
return cl->was_conference;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Reference and user data handling functions *
|
||||
|
|
@ -345,7 +349,7 @@ static void linphone_create_table(sqlite3* db) {
|
|||
}
|
||||
}
|
||||
|
||||
void linphone_update_call_log_table(sqlite3* db) {
|
||||
static void linphone_update_call_log_table(sqlite3* db) {
|
||||
char* errmsg=NULL;
|
||||
int ret;
|
||||
|
||||
|
|
@ -419,6 +423,9 @@ static int create_call_log(void *data, int argc, char **argv, char **colName) {
|
|||
unsigned int storage_id = atoi(argv[0]);
|
||||
from = linphone_address_new(argv[1]);
|
||||
to = linphone_address_new(argv[2]);
|
||||
|
||||
if (from == NULL || to == NULL) goto error;
|
||||
|
||||
dir = (LinphoneCallDir) atoi(argv[3]);
|
||||
log = linphone_call_log_new(dir, from, to);
|
||||
|
||||
|
|
@ -441,11 +448,20 @@ static int create_call_log(void *data, int argc, char **argv, char **colName) {
|
|||
}
|
||||
|
||||
*list = ms_list_append(*list, log);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (from){
|
||||
linphone_address_destroy(from);
|
||||
}
|
||||
if (to){
|
||||
linphone_address_destroy(to);
|
||||
}
|
||||
ms_error("Bad call log at storage_id %u", storage_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void linphone_sql_request_call_log(sqlite3 *db, const char *stmt, MSList **list) {
|
||||
static void linphone_sql_request_call_log(sqlite3 *db, const char *stmt, MSList **list) {
|
||||
char* errmsg = NULL;
|
||||
int ret;
|
||||
ret = sqlite3_exec(db, stmt, create_call_log, list, &errmsg);
|
||||
|
|
@ -455,7 +471,7 @@ void linphone_sql_request_call_log(sqlite3 *db, const char *stmt, MSList **list)
|
|||
}
|
||||
}
|
||||
|
||||
int linphone_sql_request_generic(sqlite3* db, const char *stmt) {
|
||||
static int linphone_sql_request_generic(sqlite3* db, const char *stmt) {
|
||||
char* errmsg = NULL;
|
||||
int ret;
|
||||
ret = sqlite3_exec(db, stmt, NULL, NULL, &errmsg);
|
||||
|
|
|
|||
|
|
@ -179,6 +179,13 @@ LINPHONE_PUBLIC bool_t linphone_call_log_video_enabled(LinphoneCallLog *cl);
|
|||
**/
|
||||
LINPHONE_PUBLIC char * linphone_call_log_to_str(LinphoneCallLog *cl);
|
||||
|
||||
/**
|
||||
* Tells whether that call was a call to a conference server
|
||||
* @param[in] cl #LinphoneCallLog object
|
||||
* @return TRUE if the call was a call to a conference server
|
||||
*/
|
||||
LINPHONE_PUBLIC bool_t linphone_call_log_was_conference(LinphoneCallLog *cl);
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Reference and user data handling functions *
|
||||
|
|
|
|||
|
|
@ -125,6 +125,10 @@ LINPHONE_PUBLIC const char *linphone_call_params_get_custom_header(const Linphon
|
|||
|
||||
/**
|
||||
* Tell whether the call is part of the locally managed conference.
|
||||
* @warning If a conference server is used to manage conferences,
|
||||
* that function does not return TRUE even if the conference is running.<br/>
|
||||
* If you want to test whether the conference is running, you should test
|
||||
* whether linphone_core_get_conference() return a non-null pointer.
|
||||
* @param[in] cp LinphoneCallParams object
|
||||
* @return A boolean value telling whether the call is part of the locally managed conference.
|
||||
**/
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia
|
|||
ms_message("Media ip type has changed, destroying sessions context on call [%p]",call);
|
||||
ms_media_stream_sessions_uninit(&call->sessions[call->main_audio_stream_index]);
|
||||
ms_media_stream_sessions_uninit(&call->sessions[call->main_video_stream_index]);
|
||||
if (call->params->realtimetext_enabled) ms_media_stream_sessions_uninit(&call->sessions[call->main_text_stream_index]);
|
||||
ms_media_stream_sessions_uninit(&call->sessions[call->main_text_stream_index]);
|
||||
}
|
||||
linphone_call_init_media_streams (call);
|
||||
}
|
||||
|
|
@ -254,27 +254,19 @@ static void call_received(SalOp *h){
|
|||
if (linphone_presence_model_get_basic_status(lc->presence_model) == LinphonePresenceBasicStatusClosed) {
|
||||
LinphonePresenceActivity *activity = linphone_presence_model_get_activity(lc->presence_model);
|
||||
switch (linphone_presence_activity_get_type(activity)) {
|
||||
case LinphonePresenceActivityBusy:
|
||||
sal_call_decline(h,SalReasonBusy,NULL);
|
||||
break;
|
||||
case LinphonePresenceActivityAppointment:
|
||||
case LinphonePresenceActivityMeeting:
|
||||
case LinphonePresenceActivityOffline:
|
||||
case LinphonePresenceActivityWorship:
|
||||
sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL);
|
||||
break;
|
||||
case LinphonePresenceActivityPermanentAbsence:
|
||||
alt_contact = linphone_presence_model_get_contact(lc->presence_model);
|
||||
if (alt_contact != NULL) {
|
||||
sal_call_decline(h,SalReasonRedirect,alt_contact);
|
||||
ms_free(alt_contact);
|
||||
sal_op_release(h);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/*nothing special to be done*/
|
||||
break;
|
||||
}
|
||||
sal_op_release(h);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!linphone_core_can_we_add_call(lc)){/*busy*/
|
||||
|
|
@ -344,7 +336,7 @@ static void call_received(SalOp *h){
|
|||
|
||||
call->bg_task_id=sal_begin_background_task("liblinphone call notification", NULL, NULL);
|
||||
|
||||
if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)) {
|
||||
if (call->defer_notify_incoming) {
|
||||
/* Defer ringing until the end of the ICE candidates gathering process. */
|
||||
ms_message("Defer ringing to gather ICE candidates");
|
||||
return;
|
||||
|
|
@ -405,7 +397,7 @@ static void start_remote_ring(LinphoneCore *lc, LinphoneCall *call) {
|
|||
if (call->audiostream)
|
||||
audio_stream_unprepare_sound(call->audiostream);
|
||||
if( lc->sound_conf.remote_ring ){
|
||||
lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,ringcard);
|
||||
lc->ringstream=ring_start(lc->factory, lc->sound_conf.remote_ring,2000,ringcard);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -503,10 +495,7 @@ static void process_call_accepted(LinphoneCore *lc, LinphoneCall *call, SalOp *o
|
|||
if (call->params->internal_call_update)
|
||||
call->params->internal_call_update = FALSE;
|
||||
|
||||
/* Handle remote ICE attributes if any. */
|
||||
if (call->ice_session != NULL && rmd) {
|
||||
linphone_call_update_ice_from_remote_media_description(call, rmd);
|
||||
}
|
||||
|
||||
#ifdef BUILD_UPNP
|
||||
if (call->upnp_session != NULL && rmd) {
|
||||
linphone_core_update_upnp_from_remote_media_description(call, rmd);
|
||||
|
|
@ -522,6 +511,12 @@ static void process_call_accepted(LinphoneCore *lc, LinphoneCall *call, SalOp *o
|
|||
md = NULL;
|
||||
}
|
||||
if (md){ /*there is a valid SDP in the response, either offer or answer, and we're able to start/update the streams*/
|
||||
|
||||
/* Handle remote ICE attributes if any. */
|
||||
if (call->ice_session != NULL && rmd) {
|
||||
linphone_call_update_ice_from_remote_media_description(call, rmd, FALSE);
|
||||
}
|
||||
|
||||
switch (call->state){
|
||||
case LinphoneCallResuming:
|
||||
linphone_core_notify_display_status(lc,_("Call resumed."));
|
||||
|
|
@ -791,7 +786,7 @@ static void call_terminated(SalOp *op, const char *from){
|
|||
linphone_core_start_refered_call(lc,call,NULL);
|
||||
}
|
||||
//we stop the call only if we have this current call or if we are in call
|
||||
if (lc->ringstream!=NULL && ( (ms_list_size(lc->calls) == 1) || linphone_core_in_call(lc) )) {
|
||||
if ((ms_list_size(lc->calls) == 1) || linphone_core_in_call(lc)) {
|
||||
linphone_core_stop_ringing(lc);
|
||||
}
|
||||
linphone_call_stop_media_streams(call);
|
||||
|
|
@ -1035,10 +1030,11 @@ static void register_failure(SalOp *op){
|
|||
} else {
|
||||
linphone_proxy_config_set_state(cfg,LinphoneRegistrationFailed,details);
|
||||
}
|
||||
if (cfg->publish_op){
|
||||
if (cfg->long_term_event){
|
||||
/*prevent publish to be sent now until registration gets successful*/
|
||||
sal_op_release(cfg->publish_op);
|
||||
cfg->publish_op=NULL;
|
||||
linphone_event_terminate(cfg->long_term_event);
|
||||
linphone_event_unref(cfg->long_term_event);
|
||||
cfg->long_term_event=NULL;
|
||||
cfg->send_publish=cfg->publish;
|
||||
}
|
||||
}
|
||||
|
|
@ -1065,7 +1061,15 @@ static void dtmf_received(SalOp *op, char dtmf){
|
|||
static void refer_received(Sal *sal, SalOp *op, const char *referto){
|
||||
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
|
||||
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
|
||||
if (call){
|
||||
LinphoneAddress *refer_to_addr = linphone_address_new(referto);
|
||||
char method[20] = "";
|
||||
|
||||
if(refer_to_addr) {
|
||||
const char *tmp = linphone_address_get_method_param(refer_to_addr);
|
||||
if(tmp) strncpy(method, tmp, sizeof(method));
|
||||
linphone_address_destroy(refer_to_addr);
|
||||
}
|
||||
if (call && (strlen(method) == 0 || strcmp(method, "INVITE") == 0)) {
|
||||
if (call->refer_to!=NULL){
|
||||
ms_free(call->refer_to);
|
||||
}
|
||||
|
|
@ -1122,11 +1126,18 @@ static void is_composing_received(SalOp *op, const SalIsComposing *is_composing)
|
|||
}
|
||||
|
||||
static void parse_presence_requested(SalOp *op, const char *content_type, const char *content_subtype, const char *body, SalPresenceModel **result) {
|
||||
linphone_notify_parse_presence(op, content_type, content_subtype, body, result);
|
||||
linphone_notify_parse_presence(content_type, content_subtype, body, result);
|
||||
}
|
||||
|
||||
static void convert_presence_to_xml_requested(SalOp *op, SalPresenceModel *presence, const char *contact, char **content) {
|
||||
linphone_notify_convert_presence_to_xml(op, presence, contact, content);
|
||||
/*for backward compatibility because still used by notify. No loguer used for publish*/
|
||||
|
||||
if(linphone_presence_model_get_presentity((LinphonePresenceModel*)presence) == NULL) {
|
||||
LinphoneAddress * presentity = linphone_address_new(contact);
|
||||
linphone_presence_model_set_presentity((LinphonePresenceModel*)presence, presentity);
|
||||
linphone_address_unref(presentity);
|
||||
}
|
||||
*content = linphone_presence_model_to_xml((LinphonePresenceModel*)presence);
|
||||
}
|
||||
|
||||
static void notify_presence(SalOp *op, SalSubscribeStatus ss, SalPresenceModel *model, const char *msg){
|
||||
|
|
@ -1276,9 +1287,9 @@ static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status){
|
|||
}
|
||||
}
|
||||
|
||||
static void info_received(SalOp *op, const SalBody *body){
|
||||
static void info_received(SalOp *op, SalBodyHandler *body_handler){
|
||||
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
|
||||
linphone_core_notify_info_message(lc,op,body);
|
||||
linphone_core_notify_info_message(lc,op,body_handler);
|
||||
}
|
||||
|
||||
static void subscribe_response(SalOp *op, SalSubscribeStatus status){
|
||||
|
|
@ -1292,14 +1303,14 @@ static void subscribe_response(SalOp *op, SalSubscribeStatus status){
|
|||
}else if (status==SalSubscribePending){
|
||||
linphone_event_set_state(lev,LinphoneSubscriptionPending);
|
||||
}else{
|
||||
if (lev->subscription_state==LinphoneSubscriptionActive && ei->reason==SalReasonIOError){
|
||||
if (lev->subscription_state==LinphoneSubscriptionActive && (ei->reason==SalReasonIOError || ei->reason == SalReasonNoMatch)){
|
||||
linphone_event_set_state(lev,LinphoneSubscriptionOutgoingProgress);
|
||||
}
|
||||
else linphone_event_set_state(lev,LinphoneSubscriptionError);
|
||||
}
|
||||
}
|
||||
|
||||
static void notify(SalOp *op, SalSubscribeStatus st, const char *eventname, const SalBody *body){
|
||||
static void notify(SalOp *op, SalSubscribeStatus st, const char *eventname, SalBodyHandler *body_handler){
|
||||
LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op);
|
||||
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
|
||||
|
||||
|
|
@ -1308,15 +1319,18 @@ static void notify(SalOp *op, SalSubscribeStatus st, const char *eventname, cons
|
|||
lev=linphone_event_new_with_out_of_dialog_op(lc,op,LinphoneSubscriptionOutgoing,eventname);
|
||||
}
|
||||
{
|
||||
LinphoneContent *ct=linphone_content_from_sal_body(body);
|
||||
if (ct) linphone_core_notify_notify_received(lc,lev,eventname,ct);
|
||||
LinphoneContent *ct=linphone_content_from_sal_body_handler(body_handler);
|
||||
if (ct) {
|
||||
linphone_core_notify_notify_received(lc,lev,eventname,ct);
|
||||
linphone_content_unref(ct);
|
||||
}
|
||||
}
|
||||
if (st!=SalSubscribeNone){
|
||||
linphone_event_set_state(lev,linphone_subscription_state_from_sal(st));
|
||||
}
|
||||
}
|
||||
|
||||
static void subscribe_received(SalOp *op, const char *eventname, const SalBody *body){
|
||||
static void subscribe_received(SalOp *op, const char *eventname, const SalBodyHandler *body_handler){
|
||||
LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op);
|
||||
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
|
||||
|
||||
|
|
@ -1329,7 +1343,7 @@ static void subscribe_received(SalOp *op, const char *eventname, const SalBody *
|
|||
|
||||
}
|
||||
|
||||
static void subscribe_closed(SalOp *op){
|
||||
static void incoming_subscribe_closed(SalOp *op){
|
||||
LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op);
|
||||
|
||||
linphone_event_set_state(lev,LinphoneSubscriptionTerminated);
|
||||
|
|
@ -1386,7 +1400,7 @@ SalCallbacks linphone_sal_callbacks={
|
|||
is_composing_received,
|
||||
notify_refer,
|
||||
subscribe_received,
|
||||
subscribe_closed,
|
||||
incoming_subscribe_closed,
|
||||
subscribe_response,
|
||||
notify,
|
||||
subscribe_presence_received,
|
||||
|
|
|
|||
676
coreapi/carddav.c
Normal file
676
coreapi/carddav.c
Normal file
|
|
@ -0,0 +1,676 @@
|
|||
/*
|
||||
carddav.c
|
||||
Copyright (C) 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
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "linphonecore.h"
|
||||
#include "private.h"
|
||||
|
||||
LinphoneCardDavContext* linphone_carddav_context_new(LinphoneFriendList *lfl) {
|
||||
LinphoneCardDavContext *carddav_context = NULL;
|
||||
|
||||
if (!lfl || !lfl->uri) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef VCARD_ENABLED
|
||||
carddav_context = (LinphoneCardDavContext *)ms_new0(LinphoneCardDavContext, 1);
|
||||
carddav_context->friend_list = linphone_friend_list_ref(lfl);
|
||||
#else
|
||||
ms_error("vCard isn't available (maybe it wasn't compiled), can't do CardDAV sync");
|
||||
#endif
|
||||
return carddav_context;
|
||||
}
|
||||
|
||||
void linphone_carddav_context_destroy(LinphoneCardDavContext *cdc) {
|
||||
if (cdc) {
|
||||
if (cdc->friend_list) {
|
||||
linphone_friend_list_unref(cdc->friend_list);
|
||||
cdc->friend_list = NULL;
|
||||
}
|
||||
ms_free(cdc);
|
||||
}
|
||||
}
|
||||
|
||||
void linphone_carddav_set_user_data(LinphoneCardDavContext *cdc, void *ud) {
|
||||
cdc->user_data = ud;
|
||||
}
|
||||
|
||||
void* linphone_carddav_get_user_data(LinphoneCardDavContext *cdc) {
|
||||
return cdc->user_data;
|
||||
}
|
||||
|
||||
void linphone_carddav_synchronize(LinphoneCardDavContext *cdc) {
|
||||
cdc->ctag = cdc->friend_list->revision;
|
||||
linphone_carddav_get_current_ctag(cdc);
|
||||
}
|
||||
|
||||
static void linphone_carddav_sync_done(LinphoneCardDavContext *cdc, bool_t success, const char *msg) {
|
||||
if (success) {
|
||||
ms_debug("CardDAV sync successful, saving new cTag: %i", cdc->ctag);
|
||||
linphone_friend_list_update_revision(cdc->friend_list, cdc->ctag);
|
||||
} else {
|
||||
ms_error("CardDAV sync failure: %s", msg);
|
||||
}
|
||||
|
||||
if (cdc->sync_done_cb) {
|
||||
cdc->sync_done_cb(cdc, success, msg);
|
||||
}
|
||||
}
|
||||
|
||||
static int find_matching_friend(LinphoneFriend *lf1, LinphoneFriend *lf2) {
|
||||
LinphoneVcard *lvc1 = linphone_friend_get_vcard(lf1);
|
||||
LinphoneVcard *lvc2 = linphone_friend_get_vcard(lf2);
|
||||
const char *uid1 = NULL, *uid2 = NULL;
|
||||
if (!lvc1 || !lvc2) {
|
||||
return 1;
|
||||
}
|
||||
uid1 = linphone_vcard_get_uid(lvc1);
|
||||
uid2 = linphone_vcard_get_uid(lvc2);
|
||||
if (!uid1 || !uid2) {
|
||||
return 1;
|
||||
}
|
||||
return strcmp(uid1, uid2);
|
||||
}
|
||||
|
||||
static void linphone_carddav_vcards_pulled(LinphoneCardDavContext *cdc, MSList *vCards) {
|
||||
if (vCards != NULL && ms_list_size(vCards) > 0) {
|
||||
MSList *friends = cdc->friend_list->friends;
|
||||
while (vCards) {
|
||||
LinphoneCardDavResponse *vCard = (LinphoneCardDavResponse *)vCards->data;
|
||||
if (vCard) {
|
||||
LinphoneVcard *lvc = linphone_vcard_new_from_vcard4_buffer(vCard->vcard);
|
||||
LinphoneFriend *lf = NULL;
|
||||
MSList *local_friend = NULL;
|
||||
|
||||
if (lvc) {
|
||||
// Compute downloaded vCards' URL and save it (+ eTag)
|
||||
char *vCard_name = strrchr(vCard->url, '/');
|
||||
char full_url[300];
|
||||
snprintf(full_url, sizeof(full_url), "%s%s", cdc->friend_list->uri, vCard_name);
|
||||
linphone_vcard_set_url(lvc, full_url);
|
||||
linphone_vcard_set_etag(lvc, vCard->etag);
|
||||
ms_debug("Downloaded vCard etag/url are %s and %s", vCard->etag, full_url);
|
||||
}
|
||||
lf = linphone_friend_new_from_vcard(lvc);
|
||||
local_friend = ms_list_find_custom(friends, (int (*)(const void*, const void*))find_matching_friend, lf);
|
||||
|
||||
if (local_friend) {
|
||||
LinphoneFriend *lf2 = (LinphoneFriend *)local_friend->data;
|
||||
lf->storage_id = lf2->storage_id;
|
||||
lf->pol = lf2->pol;
|
||||
lf->subscribe = lf2->subscribe;
|
||||
lf->refkey = ms_strdup(lf2->refkey);
|
||||
lf->presence_received = lf2->presence_received;
|
||||
lf->lc = lf2->lc;
|
||||
lf->friend_list = lf2->friend_list;
|
||||
|
||||
if (cdc->contact_updated_cb) {
|
||||
ms_debug("Contact updated: %s", linphone_friend_get_name(lf));
|
||||
cdc->contact_updated_cb(cdc, lf, lf2);
|
||||
}
|
||||
} else {
|
||||
if (cdc->contact_created_cb) {
|
||||
ms_debug("Contact created: %s", linphone_friend_get_name(lf));
|
||||
cdc->contact_created_cb(cdc, lf);
|
||||
}
|
||||
}
|
||||
linphone_friend_unref(lf);
|
||||
}
|
||||
vCards = ms_list_next(vCards);
|
||||
}
|
||||
}
|
||||
ms_list_free(vCards);
|
||||
linphone_carddav_sync_done(cdc, TRUE, NULL);
|
||||
}
|
||||
|
||||
static MSList* parse_vcards_from_xml_response(const char *body) {
|
||||
MSList *result = NULL;
|
||||
xmlparsing_context_t *xml_ctx = linphone_xmlparsing_context_new();
|
||||
xmlSetGenericErrorFunc(xml_ctx, linphone_xmlparsing_genericxml_error);
|
||||
xml_ctx->doc = xmlReadDoc((const unsigned char*)body, 0, NULL, 0);
|
||||
if (xml_ctx->doc != NULL) {
|
||||
if (linphone_create_xml_xpath_context(xml_ctx) < 0) goto end;
|
||||
linphone_xml_xpath_context_init_carddav_ns(xml_ctx);
|
||||
{
|
||||
xmlXPathObjectPtr responses = linphone_get_xml_xpath_object_for_node_list(xml_ctx, "/d:multistatus/d:response");
|
||||
if (responses != NULL && responses->nodesetval != NULL) {
|
||||
xmlNodeSetPtr responses_nodes = responses->nodesetval;
|
||||
if (responses_nodes->nodeNr >= 1) {
|
||||
int i;
|
||||
for (i = 0; i < responses_nodes->nodeNr; i++) {
|
||||
xmlNodePtr response_node = responses_nodes->nodeTab[i];
|
||||
xml_ctx->xpath_ctx->node = response_node;
|
||||
{
|
||||
char *etag = linphone_get_xml_text_content(xml_ctx, "d:propstat/d:prop/d:getetag");
|
||||
char *url = linphone_get_xml_text_content(xml_ctx, "d:href");
|
||||
char *vcard = linphone_get_xml_text_content(xml_ctx, "d:propstat/d:prop/card:address-data");
|
||||
LinphoneCardDavResponse *response = ms_new0(LinphoneCardDavResponse, 1);
|
||||
response->etag = ms_strdup(etag);
|
||||
response->url = ms_strdup(url);
|
||||
response->vcard = ms_strdup(vcard);
|
||||
result = ms_list_append(result, response);
|
||||
ms_debug("Added vCard object with eTag %s, URL %s and vCard %s", etag, url, vcard);
|
||||
}
|
||||
}
|
||||
}
|
||||
xmlXPathFreeObject(responses);
|
||||
}
|
||||
}
|
||||
}
|
||||
end:
|
||||
linphone_xmlparsing_context_destroy(xml_ctx);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int find_matching_vcard(LinphoneCardDavResponse *response, LinphoneFriend *lf) {
|
||||
if (!response->url || !lf || !lf->vcard || !linphone_vcard_get_url(lf->vcard)) {
|
||||
return 1;
|
||||
}
|
||||
return strcmp(response->url, linphone_vcard_get_url(lf->vcard));
|
||||
}
|
||||
|
||||
static void linphone_carddav_vcards_fetched(LinphoneCardDavContext *cdc, MSList *vCards) {
|
||||
if (vCards != NULL && ms_list_size(vCards) > 0) {
|
||||
MSList *friends = cdc->friend_list->friends;
|
||||
MSList *friends_to_remove = NULL;
|
||||
MSList *temp_list = NULL;
|
||||
|
||||
while (friends) {
|
||||
LinphoneFriend *lf = (LinphoneFriend *)friends->data;
|
||||
if (lf) {
|
||||
MSList *vCard = ms_list_find_custom(vCards, (int (*)(const void*, const void*))find_matching_vcard, lf);
|
||||
if (!vCard) {
|
||||
ms_debug("Local friend %s isn't in the remote vCard list, delete it", linphone_friend_get_name(lf));
|
||||
temp_list = ms_list_append(temp_list, linphone_friend_ref(lf));
|
||||
} else {
|
||||
LinphoneCardDavResponse *response = (LinphoneCardDavResponse *)vCard->data;
|
||||
ms_debug("Local friend %s is in the remote vCard list, check eTag", linphone_friend_get_name(lf));
|
||||
if (response) {
|
||||
LinphoneVcard *lvc = linphone_friend_get_vcard(lf);
|
||||
const char *etag = linphone_vcard_get_etag(lvc);
|
||||
ms_debug("Local friend eTag is %s, remote vCard eTag is %s", etag, response->etag);
|
||||
if (lvc && etag && strcmp(etag, response->etag) == 0) {
|
||||
ms_list_remove(vCards, vCard);
|
||||
ms_free(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
friends = ms_list_next(friends);
|
||||
}
|
||||
friends_to_remove = temp_list;
|
||||
while(friends_to_remove) {
|
||||
LinphoneFriend *lf = (LinphoneFriend *)friends_to_remove->data;
|
||||
if (lf) {
|
||||
if (cdc->contact_removed_cb) {
|
||||
ms_debug("Contact removed: %s", linphone_friend_get_name(lf));
|
||||
cdc->contact_removed_cb(cdc, lf);
|
||||
}
|
||||
}
|
||||
friends_to_remove = ms_list_next(friends_to_remove);
|
||||
}
|
||||
temp_list = ms_list_free_with_data(temp_list, (void (*)(void *))linphone_friend_unref);
|
||||
|
||||
linphone_carddav_pull_vcards(cdc, vCards);
|
||||
}
|
||||
ms_list_free(vCards);
|
||||
}
|
||||
|
||||
static MSList* parse_vcards_etags_from_xml_response(const char *body) {
|
||||
MSList *result = NULL;
|
||||
xmlparsing_context_t *xml_ctx = linphone_xmlparsing_context_new();
|
||||
xmlSetGenericErrorFunc(xml_ctx, linphone_xmlparsing_genericxml_error);
|
||||
xml_ctx->doc = xmlReadDoc((const unsigned char*)body, 0, NULL, 0);
|
||||
if (xml_ctx->doc != NULL) {
|
||||
if (linphone_create_xml_xpath_context(xml_ctx) < 0) goto end;
|
||||
linphone_xml_xpath_context_init_carddav_ns(xml_ctx);
|
||||
{
|
||||
xmlXPathObjectPtr responses = linphone_get_xml_xpath_object_for_node_list(xml_ctx, "/d:multistatus/d:response");
|
||||
if (responses != NULL && responses->nodesetval != NULL) {
|
||||
xmlNodeSetPtr responses_nodes = responses->nodesetval;
|
||||
if (responses_nodes->nodeNr >= 1) {
|
||||
int i;
|
||||
for (i = 0; i < responses_nodes->nodeNr; i++) {
|
||||
xmlNodePtr response_node = responses_nodes->nodeTab[i];
|
||||
xml_ctx->xpath_ctx->node = response_node;
|
||||
{
|
||||
char *etag = linphone_get_xml_text_content(xml_ctx, "d:propstat/d:prop/d:getetag");
|
||||
char *url = linphone_get_xml_text_content(xml_ctx, "d:href");
|
||||
LinphoneCardDavResponse *response = ms_new0(LinphoneCardDavResponse, 1);
|
||||
response->etag = ms_strdup(etag);
|
||||
response->url = ms_strdup(url);
|
||||
result = ms_list_append(result, response);
|
||||
ms_debug("Added vCard object with eTag %s and URL %s", etag, url);
|
||||
}
|
||||
}
|
||||
}
|
||||
xmlXPathFreeObject(responses);
|
||||
}
|
||||
}
|
||||
}
|
||||
end:
|
||||
linphone_xmlparsing_context_destroy(xml_ctx);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void linphone_carddav_ctag_fetched(LinphoneCardDavContext *cdc, int ctag) {
|
||||
ms_debug("Remote cTag for CardDAV addressbook is %i, local one is %i", ctag, cdc->ctag);
|
||||
if (ctag == -1 || ctag > cdc->ctag) {
|
||||
cdc->ctag = ctag;
|
||||
linphone_carddav_fetch_vcards(cdc);
|
||||
} else {
|
||||
ms_message("No changes found on server, skipping sync");
|
||||
linphone_carddav_sync_done(cdc, TRUE, "Synchronization skipped because cTag already up to date");
|
||||
}
|
||||
}
|
||||
|
||||
static int parse_ctag_value_from_xml_response(const char *body) {
|
||||
int result = -1;
|
||||
xmlparsing_context_t *xml_ctx = linphone_xmlparsing_context_new();
|
||||
xmlSetGenericErrorFunc(xml_ctx, linphone_xmlparsing_genericxml_error);
|
||||
xml_ctx->doc = xmlReadDoc((const unsigned char*)body, 0, NULL, 0);
|
||||
if (xml_ctx->doc != NULL) {
|
||||
char *response = NULL;
|
||||
if (linphone_create_xml_xpath_context(xml_ctx) < 0) goto end;
|
||||
linphone_xml_xpath_context_init_carddav_ns(xml_ctx);
|
||||
response = linphone_get_xml_text_content(xml_ctx, "/d:multistatus/d:response/d:propstat/d:prop/x1:getctag");
|
||||
if (response) {
|
||||
result = atoi(response);
|
||||
linphone_free_xml_text_content(response);
|
||||
}
|
||||
}
|
||||
end:
|
||||
linphone_xmlparsing_context_destroy(xml_ctx);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void linphone_carddav_query_free(LinphoneCardDavQuery *query) {
|
||||
if (!query) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (query->http_request_listener) {
|
||||
belle_sip_object_unref(query->http_request_listener);
|
||||
query->http_request_listener = NULL;
|
||||
}
|
||||
|
||||
ms_free(query);
|
||||
}
|
||||
|
||||
static void process_response_from_carddav_request(void *data, const belle_http_response_event_t *event) {
|
||||
LinphoneCardDavQuery *query = (LinphoneCardDavQuery *)data;
|
||||
|
||||
if (event->response) {
|
||||
int code = belle_http_response_get_status_code(event->response);
|
||||
if (code == 207 || code == 200 || code == 201 || code == 204) {
|
||||
const char *body = belle_sip_message_get_body((belle_sip_message_t *)event->response);
|
||||
switch(query->type) {
|
||||
case LinphoneCardDavQueryTypePropfind:
|
||||
linphone_carddav_ctag_fetched(query->context, parse_ctag_value_from_xml_response(body));
|
||||
break;
|
||||
case LinphoneCardDavQueryTypeAddressbookQuery:
|
||||
linphone_carddav_vcards_fetched(query->context, parse_vcards_etags_from_xml_response(body));
|
||||
break;
|
||||
case LinphoneCardDavQueryTypeAddressbookMultiget:
|
||||
linphone_carddav_vcards_pulled(query->context, parse_vcards_from_xml_response(body));
|
||||
break;
|
||||
case LinphoneCardDavQueryTypePut:
|
||||
{
|
||||
belle_sip_header_t *header = belle_sip_message_get_header((belle_sip_message_t *)event->response, "ETag");
|
||||
LinphoneFriend *lf = (LinphoneFriend *)query->user_data;
|
||||
LinphoneVcard *lvc = linphone_friend_get_vcard(lf);
|
||||
if (lf && lvc) {
|
||||
if (header) {
|
||||
const char *etag = belle_sip_header_get_unparsed_value(header);
|
||||
if (!linphone_vcard_get_etag(lvc)) {
|
||||
ms_debug("eTag for newly created vCard is: %s", etag);
|
||||
} else {
|
||||
ms_debug("eTag for updated vCard is: %s", etag);
|
||||
}
|
||||
linphone_vcard_set_etag(lvc, etag);
|
||||
|
||||
linphone_carddav_sync_done(query->context, TRUE, NULL);
|
||||
linphone_friend_unref(lf);
|
||||
} else {
|
||||
// For some reason, server didn't return the eTag of the updated/created vCard
|
||||
// We need to do a GET on the vCard to get the correct one
|
||||
MSList *vcard = NULL;
|
||||
LinphoneCardDavResponse *response = (LinphoneCardDavResponse *)ms_new0(LinphoneCardDavResponse, 1);
|
||||
response->url = linphone_vcard_get_url(lvc);
|
||||
response->context = query->context;
|
||||
vcard = ms_list_append(vcard, response);
|
||||
linphone_carddav_pull_vcards(query->context, vcard);
|
||||
ms_list_free(vcard);
|
||||
}
|
||||
}
|
||||
else {
|
||||
linphone_carddav_sync_done(query->context, FALSE, "No LinphoneFriend found in user_date field of query");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LinphoneCardDavQueryTypeDelete:
|
||||
linphone_carddav_sync_done(query->context, TRUE, NULL);
|
||||
break;
|
||||
default:
|
||||
ms_error("Unknown request: %i", query->type);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
char msg[100];
|
||||
snprintf(msg, sizeof(msg), "Unexpected HTTP response code: %i", code);
|
||||
linphone_carddav_sync_done(query->context, FALSE, msg);
|
||||
}
|
||||
} else {
|
||||
linphone_carddav_sync_done(query->context, FALSE, "No response found");
|
||||
}
|
||||
linphone_carddav_query_free(query);
|
||||
}
|
||||
|
||||
static void process_io_error_from_carddav_request(void *data, const belle_sip_io_error_event_t *event) {
|
||||
LinphoneCardDavQuery *query = (LinphoneCardDavQuery *)data;
|
||||
ms_error("I/O error during CardDAV request sending");
|
||||
linphone_carddav_query_free(query);
|
||||
linphone_carddav_sync_done(query->context, FALSE, "I/O error during CardDAV request sending");
|
||||
}
|
||||
|
||||
static void process_auth_requested_from_carddav_request(void *data, belle_sip_auth_event_t *event) {
|
||||
LinphoneCardDavQuery *query = (LinphoneCardDavQuery *)data;
|
||||
LinphoneCardDavContext *cdc = query->context;
|
||||
const char *realm = belle_sip_auth_event_get_realm(event);
|
||||
belle_generic_uri_t *uri = belle_generic_uri_parse(query->url);
|
||||
const char *domain = belle_generic_uri_get_host(uri);
|
||||
LinphoneCore *lc = cdc->friend_list->lc;
|
||||
const MSList *auth_infos = linphone_core_get_auth_info_list(lc);
|
||||
|
||||
ms_debug("Looking for auth info for domain %s and realm %s", domain, realm);
|
||||
while (auth_infos) {
|
||||
LinphoneAuthInfo *auth_info = (LinphoneAuthInfo *)auth_infos->data;
|
||||
if (auth_info->domain && strcmp(domain, auth_info->domain) == 0) {
|
||||
if (!auth_info->realm || strcmp(realm, auth_info->realm) == 0) {
|
||||
belle_sip_auth_event_set_username(event, auth_info->username);
|
||||
belle_sip_auth_event_set_passwd(event, auth_info->passwd);
|
||||
belle_sip_auth_event_set_ha1(event, auth_info->ha1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
auth_infos = ms_list_next(auth_infos);
|
||||
}
|
||||
|
||||
if (!auth_infos) {
|
||||
ms_error("Authentication requested during CardDAV request sending, and username/password weren't provided");
|
||||
linphone_carddav_sync_done(query->context, FALSE, "Authentication requested during CardDAV request sending, and username/password weren't provided");
|
||||
linphone_carddav_query_free(query);
|
||||
}
|
||||
}
|
||||
|
||||
static void linphone_carddav_send_query(LinphoneCardDavQuery *query) {
|
||||
belle_http_request_listener_callbacks_t cbs = { 0 };
|
||||
belle_generic_uri_t *uri = NULL;
|
||||
belle_http_request_t *req = NULL;
|
||||
belle_sip_memory_body_handler_t *bh = NULL;
|
||||
|
||||
uri = belle_generic_uri_parse(query->url);
|
||||
if (!uri) {
|
||||
LinphoneCardDavContext *cdc = query->context;
|
||||
if (cdc && cdc->sync_done_cb) {
|
||||
cdc->sync_done_cb(cdc, FALSE, "Could not send request, URL is invalid");
|
||||
}
|
||||
belle_sip_error("Could not send request, URL %s is invalid", query->url);
|
||||
return;
|
||||
}
|
||||
req = belle_http_request_create(query->method, uri, belle_sip_header_content_type_create("application", "xml; charset=utf-8"), NULL);
|
||||
|
||||
if (!req) {
|
||||
LinphoneCardDavContext *cdc = query->context;
|
||||
if (cdc && cdc->sync_done_cb) {
|
||||
cdc->sync_done_cb(cdc, FALSE, "Could not create belle_http_request_t");
|
||||
}
|
||||
belle_sip_object_unref(uri);
|
||||
belle_sip_error("Could not create belle_http_request_t");
|
||||
return;
|
||||
}
|
||||
|
||||
if (query->depth) {
|
||||
belle_sip_message_add_header((belle_sip_message_t *)req, belle_sip_header_create("Depth", query->depth));
|
||||
} else if (query->ifmatch) {
|
||||
belle_sip_message_add_header((belle_sip_message_t *)req, belle_sip_header_create("If-Match", query->ifmatch));
|
||||
} else if (strcmp(query->method, "PUT")) {
|
||||
belle_sip_message_add_header((belle_sip_message_t *)req, belle_sip_header_create("If-None-Match", "*"));
|
||||
}
|
||||
|
||||
if (query->body) {
|
||||
bh = belle_sip_memory_body_handler_new_copy_from_buffer(query->body, strlen(query->body), NULL, NULL);
|
||||
belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(req), bh ? BELLE_SIP_BODY_HANDLER(bh) : NULL);
|
||||
}
|
||||
|
||||
cbs.process_response = process_response_from_carddav_request;
|
||||
cbs.process_io_error = process_io_error_from_carddav_request;
|
||||
cbs.process_auth_requested = process_auth_requested_from_carddav_request;
|
||||
query->http_request_listener = belle_http_request_listener_create_from_callbacks(&cbs, query);
|
||||
belle_http_provider_send_request(query->context->friend_list->lc->http_provider, req, query->http_request_listener);
|
||||
}
|
||||
|
||||
static LinphoneCardDavQuery* linphone_carddav_create_put_query(LinphoneCardDavContext *cdc, LinphoneVcard *lvc) {
|
||||
LinphoneCardDavQuery *query = (LinphoneCardDavQuery *)ms_new0(LinphoneCardDavQuery, 1);
|
||||
query->context = cdc;
|
||||
query->depth = NULL;
|
||||
query->ifmatch = linphone_vcard_get_etag(lvc);
|
||||
query->body = linphone_vcard_as_vcard4_string(lvc);
|
||||
query->method = "PUT";
|
||||
query->url = linphone_vcard_get_url(lvc);
|
||||
query->type = LinphoneCardDavQueryTypePut;
|
||||
return query;
|
||||
}
|
||||
|
||||
static char* generate_url_from_server_address_and_uid(const char *server_url) {
|
||||
char *result = NULL;
|
||||
if (server_url) {
|
||||
char *uuid = ms_malloc(64);
|
||||
if (sal_generate_uuid(uuid, 64) == 0) {
|
||||
char *url = ms_malloc(300);
|
||||
snprintf(url, 300, "%s/linphone-%s.vcf", server_url, uuid);
|
||||
ms_debug("Generated url is %s", url);
|
||||
result = ms_strdup(url);
|
||||
ms_free(url);
|
||||
}
|
||||
ms_free(uuid);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void linphone_carddav_put_vcard(LinphoneCardDavContext *cdc, LinphoneFriend *lf) {
|
||||
LinphoneVcard *lvc = linphone_friend_get_vcard(lf);
|
||||
if (lvc) {
|
||||
LinphoneCardDavQuery *query = NULL;
|
||||
if (!linphone_vcard_get_uid(lvc)) {
|
||||
linphone_vcard_generate_unique_id(lvc);
|
||||
}
|
||||
|
||||
if (!linphone_vcard_get_url(lvc)) {
|
||||
char *url = generate_url_from_server_address_and_uid(cdc->friend_list->uri);
|
||||
if (url) {
|
||||
linphone_vcard_set_url(lvc, url);
|
||||
ms_free(url);
|
||||
} else {
|
||||
const char *msg = "vCard doesn't have an URL, and friendlist doesn't have a CardDAV server set either, can't push it";
|
||||
ms_warning("%s", msg);
|
||||
if (cdc && cdc->sync_done_cb) {
|
||||
cdc->sync_done_cb(cdc, FALSE, msg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
query = linphone_carddav_create_put_query(cdc, lvc);
|
||||
query->user_data = linphone_friend_ref(lf);
|
||||
linphone_carddav_send_query(query);
|
||||
} else {
|
||||
const char *msg = NULL;
|
||||
if (!lvc) {
|
||||
msg = "LinphoneVcard is NULL";
|
||||
} else {
|
||||
msg = "Unknown error";
|
||||
}
|
||||
|
||||
if (msg) {
|
||||
ms_error("%s", msg);
|
||||
}
|
||||
|
||||
if (cdc && cdc->sync_done_cb) {
|
||||
cdc->sync_done_cb(cdc, FALSE, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static LinphoneCardDavQuery* linphone_carddav_create_delete_query(LinphoneCardDavContext *cdc, LinphoneVcard *lvc) {
|
||||
LinphoneCardDavQuery *query = (LinphoneCardDavQuery *)ms_new0(LinphoneCardDavQuery, 1);
|
||||
query->context = cdc;
|
||||
query->depth = NULL;
|
||||
query->ifmatch = linphone_vcard_get_etag(lvc);
|
||||
query->body = NULL;
|
||||
query->method = "DELETE";
|
||||
query->url = linphone_vcard_get_url(lvc);
|
||||
query->type = LinphoneCardDavQueryTypeDelete;
|
||||
return query;
|
||||
}
|
||||
|
||||
void linphone_carddav_delete_vcard(LinphoneCardDavContext *cdc, LinphoneFriend *lf) {
|
||||
LinphoneVcard *lvc = linphone_friend_get_vcard(lf);
|
||||
if (lvc && linphone_vcard_get_uid(lvc) && linphone_vcard_get_etag(lvc)) {
|
||||
LinphoneCardDavQuery *query = NULL;
|
||||
|
||||
if (!linphone_vcard_get_url(lvc)) {
|
||||
char *url = generate_url_from_server_address_and_uid(cdc->friend_list->uri);
|
||||
if (url) {
|
||||
linphone_vcard_set_url(lvc, url);
|
||||
ms_free(url);
|
||||
} else {
|
||||
const char *msg = "vCard doesn't have an URL, and friendlist doesn't have a CardDAV server set either, can't delete it";
|
||||
ms_warning("%s", msg);
|
||||
if (cdc && cdc->sync_done_cb) {
|
||||
cdc->sync_done_cb(cdc, FALSE, msg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
query = linphone_carddav_create_delete_query(cdc, lvc);
|
||||
linphone_carddav_send_query(query);
|
||||
} else {
|
||||
const char *msg = NULL;
|
||||
if (!lvc) {
|
||||
msg = "LinphoneVcard is NULL";
|
||||
} else if (!linphone_vcard_get_uid(lvc)) {
|
||||
msg = "LinphoneVcard doesn't have an UID";
|
||||
} else if (!linphone_vcard_get_etag(lvc)) {
|
||||
msg = "LinphoneVcard doesn't have an eTag";
|
||||
}
|
||||
|
||||
if (msg) {
|
||||
ms_error("%s", msg);
|
||||
}
|
||||
|
||||
if (cdc && cdc->sync_done_cb) {
|
||||
cdc->sync_done_cb(cdc, FALSE, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void linphone_carddav_set_synchronization_done_callback(LinphoneCardDavContext *cdc, LinphoneCardDavSynchronizationDoneCb cb) {
|
||||
cdc->sync_done_cb = cb;
|
||||
}
|
||||
|
||||
void linphone_carddav_set_new_contact_callback(LinphoneCardDavContext *cdc, LinphoneCardDavContactCreatedCb cb) {
|
||||
cdc->contact_created_cb = cb;
|
||||
}
|
||||
|
||||
void linphone_carddav_set_updated_contact_callback(LinphoneCardDavContext *cdc, LinphoneCardDavContactUpdatedCb cb) {
|
||||
cdc->contact_updated_cb = cb;
|
||||
}
|
||||
|
||||
void linphone_carddav_set_removed_contact_callback(LinphoneCardDavContext *cdc, LinphoneCardDavContactRemovedCb cb) {
|
||||
cdc->contact_removed_cb = cb;
|
||||
}
|
||||
|
||||
static LinphoneCardDavQuery* linphone_carddav_create_propfind_query(LinphoneCardDavContext *cdc) {
|
||||
LinphoneCardDavQuery *query = (LinphoneCardDavQuery *)ms_new0(LinphoneCardDavQuery, 1);
|
||||
query->context = cdc;
|
||||
query->depth = "0";
|
||||
query->ifmatch = NULL;
|
||||
query->body = "<d:propfind xmlns:d=\"DAV:\" xmlns:cs=\"http://calendarserver.org/ns/\"><d:prop><cs:getctag /></d:prop></d:propfind>";
|
||||
query->method = "PROPFIND";
|
||||
query->url = cdc->friend_list->uri;
|
||||
query->type = LinphoneCardDavQueryTypePropfind;
|
||||
return query;
|
||||
}
|
||||
|
||||
void linphone_carddav_get_current_ctag(LinphoneCardDavContext *cdc) {
|
||||
LinphoneCardDavQuery *query = linphone_carddav_create_propfind_query(cdc);
|
||||
linphone_carddav_send_query(query);
|
||||
}
|
||||
|
||||
static LinphoneCardDavQuery* linphone_carddav_create_addressbook_query(LinphoneCardDavContext *cdc) {
|
||||
LinphoneCardDavQuery *query = (LinphoneCardDavQuery *)ms_new0(LinphoneCardDavQuery, 1);
|
||||
query->context = cdc;
|
||||
query->depth = "1";
|
||||
query->ifmatch = NULL;
|
||||
query->body = "<card:addressbook-query xmlns:d=\"DAV:\" xmlns:card=\"urn:ietf:params:xml:ns:carddav\"><d:prop><d:getetag /></d:prop><card:filter></card:filter></card:addressbook-query>";
|
||||
query->method = "REPORT";
|
||||
query->url = cdc->friend_list->uri;
|
||||
query->type = LinphoneCardDavQueryTypeAddressbookQuery;
|
||||
return query;
|
||||
}
|
||||
|
||||
void linphone_carddav_fetch_vcards(LinphoneCardDavContext *cdc) {
|
||||
LinphoneCardDavQuery *query = linphone_carddav_create_addressbook_query(cdc);
|
||||
linphone_carddav_send_query(query);
|
||||
}
|
||||
|
||||
static LinphoneCardDavQuery* linphone_carddav_create_addressbook_multiget_query(LinphoneCardDavContext *cdc, MSList *vcards) {
|
||||
LinphoneCardDavQuery *query = (LinphoneCardDavQuery *)ms_new0(LinphoneCardDavQuery, 1);
|
||||
char *body = (char *)ms_malloc((ms_list_size(vcards) + 1) * 300 * sizeof(char));
|
||||
MSList *iterator = vcards;
|
||||
|
||||
query->context = cdc;
|
||||
query->depth = "1";
|
||||
query->ifmatch = NULL;
|
||||
query->method = "REPORT";
|
||||
query->url = cdc->friend_list->uri;
|
||||
query->type = LinphoneCardDavQueryTypeAddressbookMultiget;
|
||||
|
||||
sprintf(body, "%s", "<card:addressbook-multiget xmlns:d=\"DAV:\" xmlns:card=\"urn:ietf:params:xml:ns:carddav\"><d:prop><d:getetag /><card:address-data content-type='text/vcard' version='4.0'/></d:prop>");
|
||||
while (iterator) {
|
||||
LinphoneCardDavResponse *response = (LinphoneCardDavResponse *)iterator->data;
|
||||
if (response) {
|
||||
char temp_body[300];
|
||||
snprintf(temp_body, sizeof(temp_body), "<d:href>%s</d:href>", response->url);
|
||||
sprintf(body, "%s%s", body, temp_body);
|
||||
iterator = ms_list_next(iterator);
|
||||
}
|
||||
}
|
||||
sprintf(body, "%s%s", body, "</card:addressbook-multiget>");
|
||||
query->body = ms_strdup(body);
|
||||
ms_free(body);
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
void linphone_carddav_pull_vcards(LinphoneCardDavContext *cdc, MSList *vcards_to_pull) {
|
||||
LinphoneCardDavQuery *query = linphone_carddav_create_addressbook_multiget_query(cdc, vcards_to_pull);
|
||||
linphone_carddav_send_query(query);
|
||||
}
|
||||
170
coreapi/carddav.h
Normal file
170
coreapi/carddav.h
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
carddav.h
|
||||
Copyright (C) 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
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef LINPHONE_CARDDAV_H
|
||||
#define LINPHONE_CARDDAV_H
|
||||
|
||||
#include "linphonecore.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @addtogroup carddav_vcard
|
||||
* @{
|
||||
*/
|
||||
|
||||
typedef struct _LinphoneCardDavContext LinphoneCardDavContext;
|
||||
|
||||
typedef enum _LinphoneCardDavQueryType {
|
||||
LinphoneCardDavQueryTypePropfind,
|
||||
LinphoneCardDavQueryTypeAddressbookQuery,
|
||||
LinphoneCardDavQueryTypeAddressbookMultiget,
|
||||
LinphoneCardDavQueryTypePut,
|
||||
LinphoneCardDavQueryTypeDelete
|
||||
} LinphoneCardDavQueryType;
|
||||
|
||||
typedef struct _LinphoneCardDavQuery LinphoneCardDavQuery;
|
||||
|
||||
typedef struct _LinphoneCardDavResponse LinphoneCardDavResponse;
|
||||
|
||||
/**
|
||||
* Callback used to notify a new contact has been created on the CardDAV server
|
||||
**/
|
||||
typedef void (*LinphoneCardDavContactCreatedCb)(LinphoneCardDavContext *cdc, LinphoneFriend *lf);
|
||||
|
||||
/**
|
||||
* Callback used to notify a contact has been updated on the CardDAV server
|
||||
**/
|
||||
typedef void (*LinphoneCardDavContactUpdatedCb)(LinphoneCardDavContext *cdc, LinphoneFriend *new_friend, LinphoneFriend *old_friend);
|
||||
|
||||
/**
|
||||
* Callback used to notify a contact has been removed on the CardDAV server
|
||||
**/
|
||||
typedef void (*LinphoneCardDavContactRemovedCb)(LinphoneCardDavContext *cdc, LinphoneFriend *lf);
|
||||
|
||||
/**
|
||||
* Callback used to notify a contact has been removed on the CardDAV server
|
||||
**/
|
||||
typedef void (*LinphoneCardDavSynchronizationDoneCb)(LinphoneCardDavContext *cdc, bool_t success, const char *message);
|
||||
|
||||
/**
|
||||
* Creates a CardDAV context for all related operations
|
||||
* @param lfl LinphoneFriendList object
|
||||
* @return LinphoneCardDavContext object if vCard support is enabled and server URL is available, NULL otherwise
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneCardDavContext* linphone_carddav_context_new(LinphoneFriendList *lfl);
|
||||
|
||||
/**
|
||||
* Deletes a LinphoneCardDavContext object
|
||||
* @param cdc LinphoneCardDavContext object
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_carddav_context_destroy(LinphoneCardDavContext *cdc);
|
||||
|
||||
/**
|
||||
* Sets a user pointer to the LinphoneCardDAVContext object
|
||||
* @param cdc LinphoneCardDavContext object
|
||||
* @param ud The user data pointer
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_carddav_set_user_data(LinphoneCardDavContext *cdc, void *ud);
|
||||
|
||||
/**
|
||||
* Gets the user pointer set in the LinphoneCardDAVContext object
|
||||
* @param cdc LinphoneCardDavContext object
|
||||
* @return The user data pointer if set, NULL otherwise
|
||||
*/
|
||||
LINPHONE_PUBLIC void* linphone_carddav_get_user_data(LinphoneCardDavContext *cdc);
|
||||
|
||||
/**
|
||||
* Starts a synchronization with the remote server to update local friends with server changes
|
||||
* @param cdc LinphoneCardDavContext object
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_carddav_synchronize(LinphoneCardDavContext *cdc);
|
||||
|
||||
/**
|
||||
* Sends a LinphoneFriend to the CardDAV server for update or creation
|
||||
* @param cdc LinphoneCardDavContext object
|
||||
* @param lf a LinphoneFriend object to update/create on the server
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_carddav_put_vcard(LinphoneCardDavContext *cdc, LinphoneFriend *lf);
|
||||
|
||||
/**
|
||||
* Deletes a LinphoneFriend on the CardDAV server
|
||||
* @param cdc LinphoneCardDavContext object
|
||||
* @param lf a LinphoneFriend object to delete on the server
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_carddav_delete_vcard(LinphoneCardDavContext *cdc, LinphoneFriend *lf);
|
||||
|
||||
/**
|
||||
* Set the synchronization done callback.
|
||||
* @param cdc LinphoneCardDavContext object
|
||||
* @param cb The synchronization done callback to be used.
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_carddav_set_synchronization_done_callback(LinphoneCardDavContext *cdc, LinphoneCardDavSynchronizationDoneCb cb);
|
||||
|
||||
/**
|
||||
* Set the new contact callback.
|
||||
* @param cdc LinphoneCardDavContext object
|
||||
* @param cb The new contact callback to be used.
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_carddav_set_new_contact_callback(LinphoneCardDavContext *cdc, LinphoneCardDavContactCreatedCb cb);
|
||||
|
||||
/**
|
||||
* Set the updated contact callback.
|
||||
* @param cdc LinphoneCardDavContext object
|
||||
* @param cb The updated contact callback to be used.
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_carddav_set_updated_contact_callback(LinphoneCardDavContext *cdc, LinphoneCardDavContactUpdatedCb cb);
|
||||
|
||||
/**
|
||||
* Set the removed contact callback.
|
||||
* @param cdc LinphoneCardDavContext object
|
||||
* @param cb The removed contact callback to be used.
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_carddav_set_removed_contact_callback(LinphoneCardDavContext *cdc, LinphoneCardDavContactRemovedCb cb);
|
||||
|
||||
/**
|
||||
* Retrieves the current cTag value for the remote server
|
||||
* @param cdc LinphoneCardDavContext object
|
||||
*/
|
||||
void linphone_carddav_get_current_ctag(LinphoneCardDavContext *cdc);
|
||||
|
||||
/**
|
||||
* Retrieves a list of all the vCards on server side to be able to detect changes
|
||||
* @param cdc LinphoneCardDavContext object
|
||||
*/
|
||||
void linphone_carddav_fetch_vcards(LinphoneCardDavContext *cdc);
|
||||
|
||||
/**
|
||||
* Download asked vCards from the server
|
||||
* @param cdc LinphoneCardDavContext object
|
||||
* @param vcards_to_pull a MSList of LinphoneCardDavResponse objects with at least the url field filled
|
||||
*/
|
||||
void linphone_carddav_pull_vcards(LinphoneCardDavContext *cdc, MSList *vcards_to_pull);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -264,6 +264,10 @@ LinphoneChatRoom *linphone_core_get_chat_room_from_uri(LinphoneCore *lc, const c
|
|||
return _linphone_core_get_or_create_chat_room(lc, to);
|
||||
}
|
||||
|
||||
bool_t linphone_chat_room_lime_enabled(LinphoneChatRoom *cr) {
|
||||
return linphone_core_lime_enabled(cr->lc) != LinphoneLimeDisabled/*&& TODO: check that cr->peer_url has a verified token */;
|
||||
}
|
||||
|
||||
static void linphone_chat_room_delete_composing_idle_timer(LinphoneChatRoom *cr) {
|
||||
if (cr->composing_idle_timer) {
|
||||
if (cr->lc && cr->lc->sal)
|
||||
|
|
@ -377,7 +381,7 @@ void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatMessage
|
|||
char *peer_uri = linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr));
|
||||
const char *content_type;
|
||||
|
||||
if (linphone_core_lime_enabled(cr->lc)) {
|
||||
if (linphone_chat_room_lime_enabled(cr)) {
|
||||
/* ref the msg or it may be destroyed by callback if the encryption failed */
|
||||
if (msg->content_type && strcmp(msg->content_type, "application/vnd.gsma.rcs-ft-http+xml") == 0) {
|
||||
/* it's a file transfer, content type shall be set to
|
||||
|
|
@ -418,7 +422,10 @@ void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatMessage
|
|||
linphone_chat_room_delete_composing_refresh_timer(cr);
|
||||
|
||||
}
|
||||
linphone_chat_message_set_state(msg, LinphoneChatMessageStateInProgress);
|
||||
// if operation failed, we should not change message state
|
||||
if (msg->dir == LinphoneChatMessageOutgoing) {
|
||||
linphone_chat_message_set_state(msg, LinphoneChatMessageStateInProgress);
|
||||
}
|
||||
}
|
||||
|
||||
void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMessageState new_state) {
|
||||
|
|
@ -675,7 +682,7 @@ bool_t linphone_chat_room_is_remote_composing(const LinphoneChatRoom *cr) {
|
|||
}
|
||||
|
||||
LinphoneCore *linphone_chat_room_get_lc(LinphoneChatRoom *cr) {
|
||||
return cr->lc;
|
||||
return linphone_chat_room_get_core(cr);
|
||||
}
|
||||
|
||||
LinphoneCore *linphone_chat_room_get_core(LinphoneChatRoom *cr) {
|
||||
|
|
@ -704,7 +711,7 @@ LinphoneChatMessage *linphone_chat_room_create_message_2(LinphoneChatRoom *cr, c
|
|||
const char *external_body_url, LinphoneChatMessageState state,
|
||||
time_t time, bool_t is_read, bool_t is_incoming) {
|
||||
LinphoneChatMessage *msg = linphone_chat_room_create_message(cr, message);
|
||||
LinphoneCore *lc = linphone_chat_room_get_lc(cr);
|
||||
LinphoneCore *lc = linphone_chat_room_get_core(cr);
|
||||
msg->external_body_url = external_body_url ? ms_strdup(external_body_url) : NULL;
|
||||
msg->time = time;
|
||||
msg->is_read = is_read;
|
||||
|
|
@ -842,10 +849,10 @@ void linphone_core_real_time_text_received(LinphoneCore *lc, LinphoneChatRoom *c
|
|||
uint32_t new_line = 0x2028;
|
||||
uint32_t crlf = 0x0D0A;
|
||||
uint32_t lf = 0x0A;
|
||||
|
||||
|
||||
if (call && linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(call))) {
|
||||
LinphoneChatMessageCharacter *cmc = ms_new0(LinphoneChatMessageCharacter, 1);
|
||||
|
||||
|
||||
if (cr->pending_message == NULL) {
|
||||
cr->pending_message = linphone_chat_room_create_message(cr, "");
|
||||
}
|
||||
|
|
@ -856,7 +863,7 @@ void linphone_core_real_time_text_received(LinphoneCore *lc, LinphoneChatRoom *c
|
|||
|
||||
cr->remote_is_composing = LinphoneIsComposingActive;
|
||||
linphone_core_notify_is_composing_received(cr->lc, cr);
|
||||
|
||||
|
||||
if (character == new_line || character == crlf || character == lf) {
|
||||
// End of message
|
||||
LinphoneChatMessage *msg = cr->pending_message;
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
#define FILE_TRANSFER_KEY_SIZE 32
|
||||
|
||||
static bool_t file_transfer_in_progress_and_valid(LinphoneChatMessage* msg) {
|
||||
return (msg->chat_room && msg->http_request && !belle_http_request_is_cancelled(msg->http_request));
|
||||
return (msg->chat_room && msg->chat_room->lc && msg->http_request && !belle_http_request_is_cancelled(msg->http_request));
|
||||
}
|
||||
|
||||
static void _release_http_request(LinphoneChatMessage* msg) {
|
||||
|
|
@ -155,7 +155,7 @@ static int linphone_chat_message_file_transfer_on_send_body(belle_sip_user_body_
|
|||
static void linphone_chat_message_process_response_from_post_file(void *data,
|
||||
const belle_http_response_event_t *event) {
|
||||
LinphoneChatMessage *msg = (LinphoneChatMessage *)data;
|
||||
|
||||
|
||||
if (msg->http_request && !file_transfer_in_progress_and_valid(msg)) {
|
||||
ms_warning("Cancelled request for %s msg [%p], ignoring %s", msg->chat_room?"":"ORPHAN", msg, __FUNCTION__);
|
||||
_release_http_request(msg);
|
||||
|
|
@ -172,7 +172,8 @@ static void linphone_chat_message_process_response_from_post_file(void *data,
|
|||
belle_sip_body_handler_t *first_part_bh;
|
||||
|
||||
/* shall we encrypt the file */
|
||||
if (linphone_core_lime_for_file_sharing_enabled(msg->chat_room->lc)) {
|
||||
if (linphone_chat_room_lime_enabled(msg->chat_room) &&
|
||||
linphone_core_lime_for_file_sharing_enabled(msg->chat_room->lc)) {
|
||||
char keyBuffer
|
||||
[FILE_TRANSFER_KEY_SIZE]; /* temporary storage of generated key: 192 bits of key + 64 bits of
|
||||
initial vector */
|
||||
|
|
@ -315,18 +316,23 @@ const LinphoneContent *linphone_chat_message_get_file_transfer_information(const
|
|||
static void on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, void *data, size_t offset,
|
||||
const uint8_t *buffer, size_t size) {
|
||||
LinphoneChatMessage *msg = (LinphoneChatMessage *)data;
|
||||
LinphoneCore *lc = msg->chat_room->lc;
|
||||
|
||||
|
||||
LinphoneCore *lc;
|
||||
|
||||
if (!msg->chat_room) {
|
||||
linphone_chat_message_cancel_file_transfer(msg);
|
||||
return;
|
||||
}
|
||||
lc = msg->chat_room->lc;
|
||||
|
||||
if (lc == NULL){
|
||||
return; /*might happen during linphone_core_destroy()*/
|
||||
}
|
||||
|
||||
if (!msg->http_request || belle_http_request_is_cancelled(msg->http_request)) {
|
||||
ms_warning("Cancelled request for msg [%p], ignoring %s", msg, __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!msg->chat_room) {
|
||||
linphone_chat_message_cancel_file_transfer(msg);
|
||||
}
|
||||
|
||||
|
||||
/* first call may be with a zero size, ignore it */
|
||||
if (size == 0) {
|
||||
return;
|
||||
|
|
@ -460,7 +466,7 @@ static void linphone_chat_process_response_from_get_file(void *data, const belle
|
|||
|
||||
int _linphone_chat_room_start_http_transfer(LinphoneChatMessage *msg, const char* url, const char* action, const belle_http_request_listener_callbacks_t *cbs) {
|
||||
belle_generic_uri_t *uri = NULL;
|
||||
char* ua;
|
||||
const char* ua = linphone_core_get_user_agent(msg->chat_room->lc);
|
||||
|
||||
if (url == NULL) {
|
||||
ms_warning("Cannot process file transfer msg: no file remote URI configured.");
|
||||
|
|
@ -472,9 +478,7 @@ int _linphone_chat_room_start_http_transfer(LinphoneChatMessage *msg, const char
|
|||
goto error;
|
||||
}
|
||||
|
||||
ua = ms_strdup_printf("%s/%s", linphone_core_get_user_agent_name(), linphone_core_get_user_agent_version());
|
||||
msg->http_request = belle_http_request_create(action, uri, belle_sip_header_create("User-Agent", ua), NULL);
|
||||
ms_free(ua);
|
||||
|
||||
if (msg->http_request == NULL) {
|
||||
ms_warning("Could not create http request for uri %s", url);
|
||||
|
|
|
|||
|
|
@ -1,430 +0,0 @@
|
|||
/***************************************************************************
|
||||
* conference.c
|
||||
*
|
||||
* Mon Sep 12, 2011
|
||||
* Copyright 2011 Belledonne Communications
|
||||
* Author: Simon Morlat
|
||||
* Email simon dot morlat at linphone dot org
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "private.h"
|
||||
#include "lpconfig.h"
|
||||
|
||||
#include "mediastreamer2/msvolume.h"
|
||||
|
||||
/**
|
||||
* @addtogroup conferencing
|
||||
* @{
|
||||
**/
|
||||
|
||||
|
||||
static int convert_conference_to_call(LinphoneCore *lc);
|
||||
|
||||
static void conference_check_init(LinphoneConference *ctx, int samplerate){
|
||||
if (ctx->conf==NULL){
|
||||
MSAudioConferenceParams params;
|
||||
params.samplerate=samplerate;
|
||||
ctx->conf=ms_audio_conference_new(¶ms);
|
||||
ctx->terminated=FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void remove_local_endpoint(LinphoneConference *ctx){
|
||||
if (ctx->local_endpoint){
|
||||
ms_audio_conference_remove_member(ctx->conf,ctx->local_endpoint);
|
||||
ms_audio_endpoint_release_from_stream(ctx->local_endpoint);
|
||||
ctx->local_endpoint=NULL;
|
||||
audio_stream_stop(ctx->local_participant);
|
||||
ctx->local_participant=NULL;
|
||||
rtp_profile_destroy(ctx->local_dummy_profile);
|
||||
}
|
||||
}
|
||||
|
||||
static int linphone_conference_get_size(LinphoneConference *conf){
|
||||
if (conf->conf == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return ms_audio_conference_get_size(conf->conf) - (conf->record_endpoint ? 1 : 0);
|
||||
}
|
||||
|
||||
static int remote_participants_count(LinphoneConference *ctx) {
|
||||
int count=linphone_conference_get_size(ctx);
|
||||
if (count==0) return 0;
|
||||
if (!ctx->local_participant) return count;
|
||||
return count -1;
|
||||
}
|
||||
|
||||
void linphone_core_conference_check_uninit(LinphoneCore *lc){
|
||||
LinphoneConference *ctx=&lc->conf_ctx;
|
||||
if (ctx->conf){
|
||||
int remote_count=remote_participants_count(ctx);
|
||||
ms_message("conference_check_uninit(): size=%i",linphone_conference_get_size(ctx));
|
||||
if (remote_count==1 && !ctx->terminated){
|
||||
convert_conference_to_call(lc);
|
||||
}
|
||||
if (remote_count==0){
|
||||
if (ctx->local_participant!=NULL)
|
||||
remove_local_endpoint(ctx);
|
||||
if (ctx->record_endpoint){
|
||||
ms_audio_conference_remove_member(ctx->conf,ctx->record_endpoint);
|
||||
ms_audio_endpoint_destroy(ctx->record_endpoint);
|
||||
ctx->record_endpoint=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (ms_audio_conference_get_size(ctx->conf)==0){
|
||||
ms_audio_conference_destroy(ctx->conf);
|
||||
ctx->conf=NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void linphone_call_add_to_conf(LinphoneCall *call, bool_t muted){
|
||||
LinphoneCore *lc=call->core;
|
||||
LinphoneConference *conf=&lc->conf_ctx;
|
||||
MSAudioEndpoint *ep;
|
||||
call->params->has_video = FALSE;
|
||||
call->camera_enabled = FALSE;
|
||||
ep=ms_audio_endpoint_get_from_stream(call->audiostream,TRUE);
|
||||
ms_audio_conference_add_member(conf->conf,ep);
|
||||
ms_audio_conference_mute_member(conf->conf,ep,muted);
|
||||
call->endpoint=ep;
|
||||
}
|
||||
|
||||
void linphone_call_remove_from_conf(LinphoneCall *call){
|
||||
LinphoneCore *lc=call->core;
|
||||
LinphoneConference *conf=&lc->conf_ctx;
|
||||
|
||||
ms_audio_conference_remove_member(conf->conf,call->endpoint);
|
||||
ms_audio_endpoint_release_from_stream(call->endpoint);
|
||||
call->endpoint=NULL;
|
||||
}
|
||||
|
||||
static RtpProfile *make_dummy_profile(int samplerate){
|
||||
RtpProfile *prof=rtp_profile_new("dummy");
|
||||
PayloadType *pt=payload_type_clone(&payload_type_l16_mono);
|
||||
pt->clock_rate=samplerate;
|
||||
rtp_profile_set_payload(prof,0,pt);
|
||||
return prof;
|
||||
}
|
||||
|
||||
static void add_local_endpoint(LinphoneConference *conf,LinphoneCore *lc){
|
||||
/*create a dummy audiostream in order to extract the local part of it */
|
||||
/* network address and ports have no meaning and are not used here. */
|
||||
AudioStream *st=audio_stream_new(65000,65001,FALSE);
|
||||
MSSndCard *playcard=lc->sound_conf.lsd_card ?
|
||||
lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
|
||||
MSSndCard *captcard=lc->sound_conf.capt_sndcard;
|
||||
const MSAudioConferenceParams *params=ms_audio_conference_get_params(conf->conf);
|
||||
conf->local_dummy_profile=make_dummy_profile(params->samplerate);
|
||||
|
||||
audio_stream_start_full(st, conf->local_dummy_profile,
|
||||
"127.0.0.1",
|
||||
65000,
|
||||
"127.0.0.1",
|
||||
65001,
|
||||
0,
|
||||
40,
|
||||
NULL,
|
||||
NULL,
|
||||
playcard,
|
||||
captcard,
|
||||
linphone_core_echo_cancellation_enabled(lc)
|
||||
);
|
||||
_post_configure_audio_stream(st,lc,FALSE);
|
||||
conf->local_participant=st;
|
||||
conf->local_endpoint=ms_audio_endpoint_get_from_stream(st,FALSE);
|
||||
ms_audio_conference_add_member(conf->conf,conf->local_endpoint);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sound volume (mic input) of the local participant of the conference.
|
||||
* @param lc the linphone core
|
||||
* @return the measured input volume expressed in dbm0.
|
||||
**/
|
||||
float linphone_core_get_conference_local_input_volume(LinphoneCore *lc){
|
||||
LinphoneConference *conf=&lc->conf_ctx;
|
||||
AudioStream *st=conf->local_participant;
|
||||
if (st && st->volsend && !conf->local_muted){
|
||||
float vol=0;
|
||||
ms_filter_call_method(st->volsend,MS_VOLUME_GET,&vol);
|
||||
return vol;
|
||||
|
||||
}
|
||||
return LINPHONE_VOLUME_DB_LOWEST;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge a call into a conference.
|
||||
* @param lc the linphone core
|
||||
* @param call an established call, either in LinphoneCallStreamsRunning or LinphoneCallPaused state.
|
||||
*
|
||||
* If this is the first call that enters the conference, the virtual conference will be created automatically.
|
||||
* If the local user was actively part of the call (ie not in paused state), then the local user is automatically entered into the conference.
|
||||
* If the call was in paused state, then it is automatically resumed when entering into the conference.
|
||||
*
|
||||
* @return 0 if successful, -1 otherwise.
|
||||
**/
|
||||
int linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *call){
|
||||
LinphoneConference *conf=&lc->conf_ctx;
|
||||
|
||||
if (call->current_params->in_conference){
|
||||
ms_error("Already in conference");
|
||||
return -1;
|
||||
}
|
||||
conference_check_init(&lc->conf_ctx, lp_config_get_int(lc->config, "sound","conference_rate",16000));
|
||||
|
||||
if (call->state==LinphoneCallPaused){
|
||||
call->params->in_conference=TRUE;
|
||||
call->params->has_video=FALSE;
|
||||
linphone_core_resume_call(lc,call);
|
||||
}else if (call->state==LinphoneCallStreamsRunning){
|
||||
LinphoneCallParams *params=linphone_call_params_copy(linphone_call_get_current_params(call));
|
||||
params->in_conference=TRUE;
|
||||
params->has_video=FALSE;
|
||||
|
||||
if (call->audiostream || call->videostream){
|
||||
linphone_call_stop_media_streams(call); /*free the audio & video local resources*/
|
||||
linphone_call_init_media_streams(call);
|
||||
}
|
||||
if (call==lc->current_call){
|
||||
lc->current_call=NULL;
|
||||
}
|
||||
/*this will trigger a reINVITE that will later redraw the streams */
|
||||
/*FIXME probably a bit too much to just redraw streams !*/
|
||||
linphone_core_update_call(lc,call,params);
|
||||
linphone_call_params_destroy(params);
|
||||
add_local_endpoint(conf,lc);
|
||||
}else{
|
||||
ms_error("Call is in state %s, it cannot be added to the conference.",linphone_call_state_to_string(call->state));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int remove_from_conference(LinphoneCore *lc, LinphoneCall *call, bool_t active){
|
||||
int err=0;
|
||||
char *str;
|
||||
|
||||
if (!call->current_params->in_conference){
|
||||
if (call->params->in_conference){
|
||||
ms_warning("Not (yet) in conference, be patient");
|
||||
return -1;
|
||||
}else{
|
||||
ms_error("Not in a conference.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
call->params->in_conference=FALSE;
|
||||
|
||||
str=linphone_call_get_remote_address_as_string(call);
|
||||
ms_message("%s will be removed from conference", str);
|
||||
ms_free(str);
|
||||
if (active){
|
||||
LinphoneCallParams *params=linphone_call_params_copy(linphone_call_get_current_params(call));
|
||||
params->in_conference=FALSE;
|
||||
// reconnect local audio with this call
|
||||
if (linphone_core_is_in_conference(lc)){
|
||||
ms_message("Leaving conference for reconnecting with unique call.");
|
||||
linphone_core_leave_conference(lc);
|
||||
}
|
||||
ms_message("Updating call to actually remove from conference");
|
||||
err=linphone_core_update_call(lc,call,params);
|
||||
linphone_call_params_destroy(params);
|
||||
} else{
|
||||
ms_message("Pausing call to actually remove from conference");
|
||||
err=_linphone_core_pause_call(lc,call);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int convert_conference_to_call(LinphoneCore *lc){
|
||||
int err=0;
|
||||
MSList *calls=lc->calls;
|
||||
|
||||
if (remote_participants_count(&lc->conf_ctx)!=1){
|
||||
ms_error("No unique call remaining in conference.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (calls) {
|
||||
LinphoneCall *rc=(LinphoneCall*)calls->data;
|
||||
calls=calls->next;
|
||||
if (rc->params->in_conference) { // not using current_param
|
||||
bool_t active_after_removed=linphone_core_is_in_conference(lc);
|
||||
err=remove_from_conference(lc, rc, active_after_removed);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int linphone_core_remove_from_conference(LinphoneCore *lc, LinphoneCall *call){
|
||||
int err;
|
||||
char * str=linphone_call_get_remote_address_as_string(call);
|
||||
ms_message("Removing call %s from the conference", str);
|
||||
ms_free(str);
|
||||
err=remove_from_conference(lc,call, FALSE);
|
||||
if (err){
|
||||
ms_error("Error removing participant from conference.");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (remote_participants_count(&lc->conf_ctx)==1){
|
||||
ms_message("conference size is 1: need to be converted to plain call");
|
||||
err=convert_conference_to_call(lc);
|
||||
} else {
|
||||
ms_message("the conference need not to be converted as size is %i", remote_participants_count(&lc->conf_ctx));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
bool_t linphone_core_is_in_conference(const LinphoneCore *lc){
|
||||
return lc->conf_ctx.local_participant!=NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the local participant out of the conference.
|
||||
* @param lc the linphone core
|
||||
* When the local participant is out of the conference, the remote participants can continue to talk normally.
|
||||
* @return 0 if successful, -1 otherwise.
|
||||
**/
|
||||
int linphone_core_leave_conference(LinphoneCore *lc){
|
||||
LinphoneConference *conf=&lc->conf_ctx;
|
||||
if (linphone_core_is_in_conference(lc))
|
||||
remove_local_endpoint(conf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the local participant inside the conference.
|
||||
* @param lc the linphone core
|
||||
*
|
||||
* Makes the local participant to join the conference.
|
||||
* Typically, the local participant is by default always part of the conference when joining an active call into a conference.
|
||||
* However, by calling linphone_core_leave_conference() and linphone_core_enter_conference() the application can decide to temporarily
|
||||
* move out and in the local participant from the conference.
|
||||
*
|
||||
* @return 0 if successful, -1 otherwise
|
||||
**/
|
||||
int linphone_core_enter_conference(LinphoneCore *lc){
|
||||
LinphoneConference *conf;
|
||||
if (linphone_core_sound_resources_locked(lc)) {
|
||||
return -1;
|
||||
}
|
||||
if (lc->current_call != NULL) {
|
||||
_linphone_core_pause_call(lc, lc->current_call);
|
||||
}
|
||||
conf=&lc->conf_ctx;
|
||||
if (conf->local_participant==NULL) add_local_endpoint(conf,lc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all calls into a conference.
|
||||
* @param lc the linphone core
|
||||
*
|
||||
* Merge all established calls (either in LinphoneCallStreamsRunning or LinphoneCallPaused) into a conference.
|
||||
*
|
||||
* @return 0 if successful, -1 otherwise
|
||||
**/
|
||||
int linphone_core_add_all_to_conference(LinphoneCore *lc) {
|
||||
MSList *calls=lc->calls;
|
||||
while (calls) {
|
||||
LinphoneCall *call=(LinphoneCall*)calls->data;
|
||||
calls=calls->next;
|
||||
if (!call->current_params->in_conference) {
|
||||
linphone_core_add_to_conference(lc, call);
|
||||
}
|
||||
}
|
||||
linphone_core_enter_conference(lc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminates the conference and the calls associated with it.
|
||||
* @param lc the linphone core
|
||||
*
|
||||
* All the calls that were merged to the conference are terminated, and the conference resources are destroyed.
|
||||
*
|
||||
* @return 0 if successful, -1 otherwise
|
||||
**/
|
||||
int linphone_core_terminate_conference(LinphoneCore *lc) {
|
||||
MSList *calls=lc->calls;
|
||||
LinphoneConference *conf=&lc->conf_ctx;
|
||||
conf->terminated=TRUE;
|
||||
|
||||
while (calls) {
|
||||
LinphoneCall *call=(LinphoneCall*)calls->data;
|
||||
calls=calls->next;
|
||||
if (call->current_params->in_conference) {
|
||||
linphone_core_terminate_call(lc, call);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of participants to the conference, including the local participant.
|
||||
* @param lc the linphone core
|
||||
*
|
||||
* Typically, after merging two calls into the conference, there is total of 3 participants:
|
||||
* the local participant (or local user), and two remote participants that were the destinations of the two previously establised calls.
|
||||
*
|
||||
* @return the number of participants to the conference
|
||||
**/
|
||||
int linphone_core_get_conference_size(LinphoneCore *lc) {
|
||||
LinphoneConference *conf=&lc->conf_ctx;
|
||||
return linphone_conference_get_size(conf);
|
||||
}
|
||||
|
||||
|
||||
int linphone_core_start_conference_recording(LinphoneCore *lc, const char *path){
|
||||
LinphoneConference *conf=&lc->conf_ctx;
|
||||
if (conf->conf == NULL) {
|
||||
ms_warning("linphone_core_start_conference_recording(): no conference now.");
|
||||
return -1;
|
||||
}
|
||||
if (conf->record_endpoint==NULL){
|
||||
conf->record_endpoint=ms_audio_endpoint_new_recorder();
|
||||
ms_audio_conference_add_member(conf->conf,conf->record_endpoint);
|
||||
}
|
||||
ms_audio_recorder_endpoint_start(conf->record_endpoint,path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int linphone_core_stop_conference_recording(LinphoneCore *lc){
|
||||
LinphoneConference *conf=&lc->conf_ctx;
|
||||
if (conf->conf == NULL) {
|
||||
ms_warning("linphone_core_stop_conference_recording(): no conference now.");
|
||||
return -1;
|
||||
}
|
||||
if (conf->record_endpoint==NULL){
|
||||
ms_warning("linphone_core_stop_conference_recording(): no record active.");
|
||||
return -1;
|
||||
}
|
||||
ms_audio_recorder_endpoint_stop(conf->record_endpoint);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
**/
|
||||
|
||||
1041
coreapi/conference.cc
Normal file
1041
coreapi/conference.cc
Normal file
File diff suppressed because it is too large
Load diff
110
coreapi/conference.h
Normal file
110
coreapi/conference.h
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
/*******************************************************************************
|
||||
* conference.h
|
||||
*
|
||||
* Thu Nov 26, 2015
|
||||
* Copyright 2015 Belledonne Communications
|
||||
* Author: Linphone's team
|
||||
* Email info@belledonne-communications.com
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef CONFERENCE_H
|
||||
#define CONFERENCE_H
|
||||
|
||||
#include "linphonecore.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @addtogroup call_control
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* LinphoneConference class
|
||||
*/
|
||||
typedef struct _LinphoneConference LinphoneConference;
|
||||
/**
|
||||
* Parameters for initialization of conferences
|
||||
*/
|
||||
typedef struct _LinphoneCorferenceParams LinphoneConferenceParams;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a #LinphoneConferenceParams with default parameters set.
|
||||
* @param core #LinphoneCore to use to find out the default parameters. Can be NULL.
|
||||
* @return A freshly allocated #LinphoneConferenceParams
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneConferenceParams *linphone_conference_params_new(const LinphoneCore *core);
|
||||
/**
|
||||
* Free a #LinphoneConferenceParams
|
||||
* @param params #LinphoneConferenceParams to free
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_conference_params_free(LinphoneConferenceParams *params);
|
||||
/**
|
||||
* Clone a #LinphoneConferenceParams
|
||||
* @param params The #LinphoneConfrenceParams to clone
|
||||
* @return An allocated #LinphoneConferenceParams with the same parameters than params
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneConferenceParams *linphone_conference_params_clone(const LinphoneConferenceParams *params);
|
||||
/**
|
||||
* Enable video when starting a conference
|
||||
* @param params A #LinphoneConnferenceParams
|
||||
* @param enable If true, video will be enabled during conference
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_conference_params_enable_video(LinphoneConferenceParams *params, bool_t enable);
|
||||
/**
|
||||
* Check whether video will be enable at conference starting
|
||||
* @return if true, the video will be enable at conference starting
|
||||
*/
|
||||
LINPHONE_PUBLIC bool_t linphone_conference_params_video_requested(const LinphoneConferenceParams *params);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Remove a participant from a conference
|
||||
* @param obj A #LinphoneConference
|
||||
* @param uri SIP URI of the participant to remove
|
||||
* @warning The passed SIP URI must be one of the URIs returned by linphone_conference_get_participants()
|
||||
* @return 0 if succeeded, -1 if failed
|
||||
*/
|
||||
LINPHONE_PUBLIC int linphone_conference_remove_participant(LinphoneConference *obj, const LinphoneAddress *uri);
|
||||
/**
|
||||
* Get URIs of all participants of one conference
|
||||
* The returned MSList contains URIs of all participant. That list must be
|
||||
* freed after use and each URI must be unref with linphone_address_unref()
|
||||
* @param obj A #LinphoneConference
|
||||
* @return \mslist{LinphoneAddress}
|
||||
*/
|
||||
LINPHONE_PUBLIC MSList *linphone_conference_get_participants(const LinphoneConference *obj);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // CONFERENCE_H
|
||||
111
coreapi/conference_private.h
Normal file
111
coreapi/conference_private.h
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
/*******************************************************************************
|
||||
* conference_private.h
|
||||
*
|
||||
* Tue Jan 12, 2015
|
||||
* Copyright 2015 Belledonne Communications
|
||||
* Author: Linphone's team
|
||||
* Email info@belledonne-communications.com
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef CONFERENCE_PRIVATE_H
|
||||
#define CONFERENCE_PRIVATE_H
|
||||
|
||||
#include "linphonecore.h"
|
||||
#include "conference.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
LinphoneConferenceClassLocal,
|
||||
LinphoneConferenceClassRemote
|
||||
} LinphoneConferenceClass;
|
||||
|
||||
/**
|
||||
* List of states used by #LinphoneConference
|
||||
*/
|
||||
typedef enum {
|
||||
LinphoneConferenceStopped, /*< Initial state */
|
||||
LinphoneConferenceStarting, /*< A participant has been added but the conference is not running yet */
|
||||
LinphoneConferenceReady, /*< The conference is running */
|
||||
LinphoneConferenceStartingFailed /*< A participant has been added but the initialization of the conference has failed */
|
||||
} LinphoneConferenceState;
|
||||
/**
|
||||
* Type of the funtion to pass as callback to linphone_conference_params_set_state_changed_callback()
|
||||
* @param conference The conference instance which the state has changed
|
||||
* @param new_state The new state of the conferenece
|
||||
* @param user_data Pointer pass to user_data while linphone_conference_params_set_state_changed_callback() was being called
|
||||
*/
|
||||
typedef void (*LinphoneConferenceStateChangedCb)(LinphoneConference *conference, LinphoneConferenceState new_state, void *user_data);
|
||||
|
||||
|
||||
/**
|
||||
* A function to converte a #LinphoneConferenceState into a string
|
||||
*/
|
||||
const char *linphone_conference_state_to_string(LinphoneConferenceState state);
|
||||
|
||||
|
||||
/**
|
||||
* Set a callback which will be called when the state of the conferenec is switching
|
||||
* @param params A #LinphoneConferenceParams object
|
||||
* @param cb The callback to call
|
||||
* @param user_data Pointer to pass to the user_data parameter of #LinphoneConferenceStateChangedCb
|
||||
*/
|
||||
void linphone_conference_params_set_state_changed_callback(LinphoneConferenceParams *params, LinphoneConferenceStateChangedCb cb, void *user_data);
|
||||
|
||||
|
||||
LinphoneConference *linphone_local_conference_new(LinphoneCore *core);
|
||||
LinphoneConference *linphone_local_conference_new_with_params(LinphoneCore *core, const LinphoneConferenceParams *params);
|
||||
LinphoneConference *linphone_remote_conference_new(LinphoneCore *core);
|
||||
LinphoneConference *linphone_remote_conference_new_with_params(LinphoneCore *core, const LinphoneConferenceParams *params);
|
||||
void linphone_conference_free(LinphoneConference *obj);
|
||||
/**
|
||||
* Get the state of a conference
|
||||
*/
|
||||
LinphoneConferenceState linphone_conference_get_state(const LinphoneConference *obj);
|
||||
|
||||
int linphone_conference_add_participant(LinphoneConference *obj, LinphoneCall *call);
|
||||
int linphone_conference_remove_participant_with_call(LinphoneConference *obj, LinphoneCall *call);
|
||||
int linphone_conference_terminate(LinphoneConference *obj);
|
||||
int linphone_conference_get_size(const LinphoneConference *obj);
|
||||
|
||||
int linphone_conference_enter(LinphoneConference *obj);
|
||||
int linphone_conference_leave(LinphoneConference *obj);
|
||||
bool_t linphone_conference_is_in(const LinphoneConference *obj);
|
||||
|
||||
AudioStream *linphone_conference_get_audio_stream(const LinphoneConference *obj);
|
||||
|
||||
int linphone_conference_mute_microphone(LinphoneConference *obj, bool_t val);
|
||||
bool_t linphone_conference_microphone_is_muted(const LinphoneConference *obj);
|
||||
float linphone_conference_get_input_volume(const LinphoneConference *obj);
|
||||
|
||||
int linphone_conference_start_recording(LinphoneConference *obj, const char *path);
|
||||
int linphone_conference_stop_recording(LinphoneConference *obj);
|
||||
|
||||
void linphone_conference_on_call_stream_starting(LinphoneConference *obj, LinphoneCall *call, bool_t is_paused_by_remote);
|
||||
void linphone_conference_on_call_stream_stopping(LinphoneConference *obj, LinphoneCall *call);
|
||||
void linphone_conference_on_call_terminating(LinphoneConference *obj, LinphoneCall *call);
|
||||
|
||||
LINPHONE_PUBLIC bool_t linphone_conference_check_class(LinphoneConference *obj, LinphoneConferenceClass _class);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //CONFERENCE_PRIVATE_H
|
||||
|
|
@ -22,23 +22,46 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
|
||||
|
||||
|
||||
static void linphone_content_set_sal_body_handler(LinphoneContent *content, SalBodyHandler *body_handler) {
|
||||
if (content->body_handler != NULL) {
|
||||
sal_body_handler_unref(content->body_handler);
|
||||
content->body_handler = NULL;
|
||||
}
|
||||
content->body_handler = sal_body_handler_ref(body_handler);
|
||||
}
|
||||
|
||||
static LinphoneContent * linphone_content_new_with_body_handler(SalBodyHandler *body_handler) {
|
||||
LinphoneContent *content = belle_sip_object_new(LinphoneContent);
|
||||
belle_sip_object_ref(content);
|
||||
content->owned_fields = TRUE;
|
||||
content->cryptoContext = NULL; /* this field is managed externally by encryption/decryption functions so be careful to initialise it to NULL */
|
||||
if (body_handler == NULL) {
|
||||
linphone_content_set_sal_body_handler(content, sal_body_handler_new());
|
||||
} else {
|
||||
linphone_content_set_sal_body_handler(content, body_handler);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
static void linphone_content_destroy(LinphoneContent *content) {
|
||||
if (content->owned_fields == TRUE) {
|
||||
if (content->lcp.type) belle_sip_free(content->lcp.type);
|
||||
if (content->lcp.subtype) belle_sip_free(content->lcp.subtype);
|
||||
if (content->lcp.data) belle_sip_free(content->lcp.data);
|
||||
if (content->lcp.encoding) belle_sip_free(content->lcp.encoding);
|
||||
if (content->lcp.name) belle_sip_free(content->lcp.name);
|
||||
if (content->lcp.key) belle_sip_free(content->lcp.key);
|
||||
if (content->body_handler) sal_body_handler_unref(content->body_handler);
|
||||
if (content->name) belle_sip_free(content->name);
|
||||
if (content->key) belle_sip_free(content->key);
|
||||
/* note : crypto context is allocated/destroyed by the encryption function */
|
||||
}
|
||||
}
|
||||
|
||||
static void linphone_content_clone(LinphoneContent *obj, const LinphoneContent *ref) {
|
||||
obj->owned_fields = TRUE;
|
||||
linphone_content_set_type(obj, linphone_content_get_type(ref));
|
||||
linphone_content_set_subtype(obj, linphone_content_get_subtype(ref));
|
||||
linphone_content_set_encoding(obj, linphone_content_get_encoding(ref));
|
||||
linphone_content_set_sal_body_handler(obj, sal_body_handler_new());
|
||||
if ((linphone_content_get_type(ref) != NULL) || (linphone_content_get_subtype(ref) != NULL)) {
|
||||
linphone_content_set_type(obj, linphone_content_get_type(ref));
|
||||
linphone_content_set_subtype(obj, linphone_content_get_subtype(ref));
|
||||
}
|
||||
if (linphone_content_get_encoding(ref) != NULL) {
|
||||
linphone_content_set_encoding(obj, linphone_content_get_encoding(ref));
|
||||
}
|
||||
linphone_content_set_name(obj, linphone_content_get_name(ref));
|
||||
linphone_content_set_key(obj, linphone_content_get_key(ref), linphone_content_get_key_size(ref));
|
||||
if (linphone_content_get_buffer(ref) != NULL) {
|
||||
|
|
@ -81,163 +104,136 @@ void linphone_content_set_user_data(LinphoneContent *content, void *ud) {
|
|||
}
|
||||
|
||||
const char * linphone_content_get_type(const LinphoneContent *content) {
|
||||
return content->lcp.type;
|
||||
return sal_body_handler_get_type(content->body_handler);
|
||||
}
|
||||
|
||||
void linphone_content_set_type(LinphoneContent *content, const char *type) {
|
||||
if (content->lcp.type != NULL) {
|
||||
belle_sip_free(content->lcp.type);
|
||||
content->lcp.type = NULL;
|
||||
}
|
||||
if (type != NULL) {
|
||||
content->lcp.type = belle_sip_strdup(type);
|
||||
}
|
||||
sal_body_handler_set_type(content->body_handler, type);
|
||||
}
|
||||
|
||||
const char * linphone_content_get_subtype(const LinphoneContent *content) {
|
||||
return content->lcp.subtype;
|
||||
return sal_body_handler_get_subtype(content->body_handler);
|
||||
}
|
||||
|
||||
void linphone_content_set_subtype(LinphoneContent *content, const char *subtype) {
|
||||
if (content->lcp.subtype != NULL) {
|
||||
belle_sip_free(content->lcp.subtype);
|
||||
content->lcp.subtype = NULL;
|
||||
}
|
||||
if (subtype != NULL) {
|
||||
content->lcp.subtype = belle_sip_strdup(subtype);
|
||||
}
|
||||
sal_body_handler_set_subtype(content->body_handler, subtype);
|
||||
}
|
||||
|
||||
void * linphone_content_get_buffer(const LinphoneContent *content) {
|
||||
return content->lcp.data;
|
||||
return sal_body_handler_get_data(content->body_handler);
|
||||
}
|
||||
|
||||
void linphone_content_set_buffer(LinphoneContent *content, const void *buffer, size_t size) {
|
||||
content->lcp.size = size;
|
||||
content->lcp.data = belle_sip_malloc(size + 1);
|
||||
memcpy(content->lcp.data, buffer, size);
|
||||
((char *)content->lcp.data)[size] = '\0';
|
||||
void *data;
|
||||
sal_body_handler_set_size(content->body_handler, size);
|
||||
data = belle_sip_malloc(size + 1);
|
||||
memcpy(data, buffer, size);
|
||||
((char *)data)[size] = '\0';
|
||||
sal_body_handler_set_data(content->body_handler, data);
|
||||
}
|
||||
|
||||
const char * linphone_content_get_string_buffer(const LinphoneContent *content) {
|
||||
return (char *)content->lcp.data;
|
||||
return (const char *)linphone_content_get_buffer(content);
|
||||
}
|
||||
|
||||
void linphone_content_set_string_buffer(LinphoneContent *content, const char *buffer) {
|
||||
content->lcp.size = strlen(buffer);
|
||||
content->lcp.data = belle_sip_strdup(buffer);
|
||||
sal_body_handler_set_size(content->body_handler, strlen(buffer));
|
||||
sal_body_handler_set_data(content->body_handler, belle_sip_strdup(buffer));
|
||||
}
|
||||
|
||||
size_t linphone_content_get_size(const LinphoneContent *content) {
|
||||
return content->lcp.size;
|
||||
return sal_body_handler_get_size(content->body_handler);
|
||||
}
|
||||
|
||||
void linphone_content_set_size(LinphoneContent *content, size_t size) {
|
||||
content->lcp.size = size;
|
||||
sal_body_handler_set_size(content->body_handler, size);
|
||||
}
|
||||
|
||||
const char * linphone_content_get_encoding(const LinphoneContent *content) {
|
||||
return content->lcp.encoding;
|
||||
return sal_body_handler_get_encoding(content->body_handler);
|
||||
}
|
||||
|
||||
void linphone_content_set_encoding(LinphoneContent *content, const char *encoding) {
|
||||
if (content->lcp.encoding != NULL) {
|
||||
belle_sip_free(content->lcp.encoding);
|
||||
content->lcp.encoding = NULL;
|
||||
}
|
||||
if (encoding != NULL) {
|
||||
content->lcp.encoding = belle_sip_strdup(encoding);
|
||||
}
|
||||
sal_body_handler_set_encoding(content->body_handler, encoding);
|
||||
}
|
||||
|
||||
const char * linphone_content_get_name(const LinphoneContent *content) {
|
||||
return content->lcp.name;
|
||||
return content->name;
|
||||
}
|
||||
|
||||
void linphone_content_set_name(LinphoneContent *content, const char *name) {
|
||||
if (content->lcp.name != NULL) {
|
||||
belle_sip_free(content->lcp.name);
|
||||
content->lcp.name = NULL;
|
||||
if (content->name != NULL) {
|
||||
belle_sip_free(content->name);
|
||||
content->name = NULL;
|
||||
}
|
||||
if (name != NULL) {
|
||||
content->lcp.name = belle_sip_strdup(name);
|
||||
content->name = belle_sip_strdup(name);
|
||||
}
|
||||
}
|
||||
|
||||
size_t linphone_content_get_key_size(const LinphoneContent *content) {
|
||||
return content->lcp.keyLength;
|
||||
return content->keyLength;
|
||||
}
|
||||
|
||||
const char * linphone_content_get_key(const LinphoneContent *content) {
|
||||
return content->lcp.key;
|
||||
return content->key;
|
||||
}
|
||||
|
||||
void linphone_content_set_key(LinphoneContent *content, const char *key, const size_t keyLength) {
|
||||
if (content->lcp.key != NULL) {
|
||||
belle_sip_free(content->lcp.key);
|
||||
content->lcp.key = NULL;
|
||||
if (content->key != NULL) {
|
||||
belle_sip_free(content->key);
|
||||
content->key = NULL;
|
||||
}
|
||||
if (key != NULL) {
|
||||
content->lcp.key = belle_sip_malloc(keyLength);
|
||||
memcpy(content->lcp.key, key, keyLength);
|
||||
content->key = belle_sip_malloc(keyLength);
|
||||
memcpy(content->key, key, keyLength);
|
||||
}
|
||||
}
|
||||
|
||||
/* crypto context is managed(allocated/freed) by the encryption function, so provide the address of field in the private structure */
|
||||
void ** linphone_content_get_cryptoContext_address(LinphoneContent *content) {
|
||||
return &(content->lcp.cryptoContext);
|
||||
return &(content->cryptoContext);
|
||||
}
|
||||
|
||||
bool_t linphone_content_is_multipart(const LinphoneContent *content) {
|
||||
return sal_body_handler_is_multipart(content->body_handler);
|
||||
}
|
||||
|
||||
LinphoneContent * linphone_content_get_part(const LinphoneContent *content, int idx) {
|
||||
SalBodyHandler *part_body_handler;
|
||||
if (!linphone_content_is_multipart(content)) return NULL;
|
||||
part_body_handler = sal_body_handler_get_part(content->body_handler, idx);
|
||||
return linphone_content_from_sal_body_handler(part_body_handler);
|
||||
}
|
||||
|
||||
LinphoneContent * linphone_content_find_part_by_header(const LinphoneContent *content, const char *header_name, const char *header_value) {
|
||||
SalBodyHandler *part_body_handler;
|
||||
if (!linphone_content_is_multipart(content)) return NULL;
|
||||
part_body_handler = sal_body_handler_find_part_by_header(content->body_handler, header_name, header_value);
|
||||
return linphone_content_from_sal_body_handler(part_body_handler);
|
||||
}
|
||||
|
||||
const char * linphone_content_get_custom_header(const LinphoneContent *content, const char *header_name) {
|
||||
return sal_body_handler_get_header(content->body_handler, header_name);
|
||||
}
|
||||
|
||||
|
||||
LinphoneContent * linphone_content_new(void) {
|
||||
LinphoneContent *content = belle_sip_object_new(LinphoneContent);
|
||||
belle_sip_object_ref(content);
|
||||
content->owned_fields = TRUE;
|
||||
content->lcp.cryptoContext = NULL; /* this field is managed externally by encryption/decryption functions so be careful to initialise it to NULL */
|
||||
return content;
|
||||
return linphone_content_new_with_body_handler(NULL);
|
||||
}
|
||||
|
||||
LinphoneContent * linphone_content_copy(const LinphoneContent *ref) {
|
||||
return (LinphoneContent *)belle_sip_object_ref(belle_sip_object_clone(BELLE_SIP_OBJECT(ref)));
|
||||
}
|
||||
|
||||
LinphoneContent * linphone_content_from_sal_body(const SalBody *ref) {
|
||||
if (ref && ref->type) {
|
||||
LinphoneContent *content = linphone_content_new();
|
||||
linphone_content_set_type(content, ref->type);
|
||||
linphone_content_set_subtype(content, ref->subtype);
|
||||
linphone_content_set_encoding(content, ref->encoding);
|
||||
if (ref->data != NULL) {
|
||||
linphone_content_set_buffer(content, ref->data, ref->size);
|
||||
} else {
|
||||
linphone_content_set_size(content, ref->size);
|
||||
}
|
||||
return content;
|
||||
LinphoneContent * linphone_content_from_sal_body_handler(SalBodyHandler *body_handler) {
|
||||
if (body_handler) {
|
||||
return linphone_content_new_with_body_handler(body_handler);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SalBody *sal_body_from_content(SalBody *body, const LinphoneContent *content) {
|
||||
if (content && linphone_content_get_type(content)) {
|
||||
body->type = linphone_content_get_type(content);
|
||||
body->subtype = linphone_content_get_subtype(content);
|
||||
body->data = linphone_content_get_buffer(content);
|
||||
body->size = linphone_content_get_size(content);
|
||||
body->encoding = linphone_content_get_encoding(content);
|
||||
return body;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
LinphoneContent * linphone_content_private_to_linphone_content(const LinphoneContentPrivate *lcp) {
|
||||
LinphoneContent *content = belle_sip_object_new(LinphoneContent);
|
||||
memcpy(&content->lcp, lcp, sizeof(LinphoneContentPrivate));
|
||||
content->owned_fields = FALSE;
|
||||
return content;
|
||||
}
|
||||
|
||||
LinphoneContentPrivate * linphone_content_to_linphone_content_private(const LinphoneContent *content) {
|
||||
return (LinphoneContentPrivate *)&content->lcp;
|
||||
SalBodyHandler * sal_body_handler_from_content(const LinphoneContent *content) {
|
||||
if (content == NULL) return NULL;
|
||||
return content->body_handler;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,51 +40,6 @@ struct _LinphoneContent;
|
|||
**/
|
||||
typedef struct _LinphoneContent LinphoneContent;
|
||||
|
||||
/**
|
||||
* @deprecated Use LinphoneContent objects instead of this structure.
|
||||
*/
|
||||
struct _LinphoneContentPrivate{
|
||||
char *type; /**<mime type for the data, for example "application"*/
|
||||
char *subtype; /**<mime subtype for the data, for example "html"*/
|
||||
void *data; /**<the actual data buffer, usually a string. Null when provided by callbacks #LinphoneCoreFileTransferSendCb or #LinphoneCoreFileTransferRecvCb*/
|
||||
size_t size; /**<the size of the data buffer, excluding null character despite null character is always set for convenience.
|
||||
When provided by callback #LinphoneCoreFileTransferSendCb or #LinphoneCoreFileTransferRecvCb, it states the total number of bytes of the transfered file*/
|
||||
char *encoding; /**<The encoding of the data buffer, for example "gzip"*/
|
||||
char *name; /**< used by RCS File transfer messages to store the original filename of the file to be downloaded from server */
|
||||
char *key; /**< used by RCS File transfer messages to store the key to encrypt file if needed */
|
||||
size_t keyLength; /**< Length of key in bytes */
|
||||
void *cryptoContext; /**< crypto context used to encrypt file for RCS file transfer */
|
||||
};
|
||||
|
||||
/**
|
||||
* Alias to the LinphoneContentPrivate struct.
|
||||
* @deprecated
|
||||
**/
|
||||
typedef struct _LinphoneContentPrivate LinphoneContentPrivate;
|
||||
|
||||
/**
|
||||
* Convert a LinphoneContentPrivate structure to a LinphoneContent object.
|
||||
* @deprecated Utility macro to ease porting existing code from LinphoneContentPrivate structure (old LinphoneContent structure) to new LinphoneContent object.
|
||||
*/
|
||||
#define LINPHONE_CONTENT(lcp) linphone_content_private_to_linphone_content(lcp)
|
||||
|
||||
/**
|
||||
* Convert a LinphoneContentPrivate structure to a LinphoneContent object.
|
||||
* @deprecated Utility function to ease porting existing code from LinphoneContentPrivate structure (old LinphoneContent structure) to new LinphoneContent object.
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneContent * linphone_content_private_to_linphone_content(const LinphoneContentPrivate *lcp);
|
||||
|
||||
/**
|
||||
* Convert a LinphoneContent object to a LinphoneContentPrivate structure.
|
||||
* @deprecated Utility macro to ease porting existing code from LinphoneContentPrivate structure (old LinphoneContent structure) to new LinphoneContent object.
|
||||
*/
|
||||
#define LINPHONE_CONTENT_PRIVATE(lc) linphone_content_to_linphone_content_private(lc)
|
||||
|
||||
/**
|
||||
* Convert a LinphoneContent object to a LinphoneContentPrivate structure.
|
||||
* @deprecated Utility function to ease porting existing code from LinphoneContentPrivate structure (old LinphoneContent structure) to new LinphoneContent object.
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneContentPrivate * linphone_content_to_linphone_content_private(const LinphoneContent *content);
|
||||
|
||||
/**
|
||||
* Create a content with default values from Linphone core.
|
||||
|
|
@ -219,6 +174,38 @@ LINPHONE_PUBLIC const char * linphone_content_get_name(const LinphoneContent *co
|
|||
*/
|
||||
LINPHONE_PUBLIC void linphone_content_set_name(LinphoneContent *content, const char *name);
|
||||
|
||||
/**
|
||||
* Tell whether a content is a multipart content.
|
||||
* @param[in] content LinphoneContent object.
|
||||
* @return A boolean value telling whether the content is multipart or not.
|
||||
*/
|
||||
LINPHONE_PUBLIC bool_t linphone_content_is_multipart(const LinphoneContent *content);
|
||||
|
||||
/**
|
||||
* Get a part from a multipart content according to its index.
|
||||
* @param[in] content LinphoneContent object.
|
||||
* @param[in] idx The index of the part to get.
|
||||
* @return A LinphoneContent object holding the part if found, NULL otherwise.
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneContent * linphone_content_get_part(const LinphoneContent *content, int idx);
|
||||
|
||||
/**
|
||||
* Find a part from a multipart content looking for a part header with a specified value.
|
||||
* @param[in] content LinphoneContent object.
|
||||
* @param[in] header_name The name of the header to look for.
|
||||
* @param[in] header_value The value of the header to look for.
|
||||
* @return A LinphoneContent object object the part if found, NULL otherwise.
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneContent * linphone_content_find_part_by_header(const LinphoneContent *content, const char *header_name, const char *header_value);
|
||||
|
||||
/**
|
||||
* Get a custom header value of a content.
|
||||
* @param[in] content LinphoneContent object.
|
||||
* @param[in] header_name The name of the header to get the value from.
|
||||
* @return The value of the header if found, NULL otherwise.
|
||||
*/
|
||||
LINPHONE_PUBLIC const char * linphone_content_get_custom_header(const LinphoneContent *content, const char *header_name);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -41,25 +41,25 @@ static void ecc_init_filters(EcCalibrator *ecc){
|
|||
ms_filter_call_method(ecc->sndread,MS_FILTER_GET_SAMPLE_RATE,&rate);
|
||||
ms_filter_call_method(ecc->sndread,MS_FILTER_SET_NCHANNELS,&ecc_channels);
|
||||
ms_filter_call_method(ecc->sndread,MS_FILTER_GET_NCHANNELS,&channels);
|
||||
ecc->read_resampler=ms_filter_new(MS_RESAMPLE_ID);
|
||||
ecc->read_resampler=ms_factory_create_filter(ecc->factory, MS_RESAMPLE_ID);
|
||||
ms_filter_call_method(ecc->read_resampler,MS_FILTER_SET_SAMPLE_RATE,&rate);
|
||||
ms_filter_call_method(ecc->read_resampler,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&ecc->rate);
|
||||
ms_filter_call_method(ecc->read_resampler,MS_FILTER_SET_NCHANNELS,&ecc_channels);
|
||||
ms_filter_call_method(ecc->read_resampler,MS_FILTER_SET_OUTPUT_NCHANNELS,&channels);
|
||||
|
||||
|
||||
ecc->det=ms_filter_new(MS_TONE_DETECTOR_ID);
|
||||
ecc->det=ms_factory_create_filter(ecc->factory, MS_TONE_DETECTOR_ID);
|
||||
ms_filter_call_method(ecc->det,MS_FILTER_SET_SAMPLE_RATE,&ecc->rate);
|
||||
ecc->rec=ms_filter_new(MS_VOID_SINK_ID);
|
||||
ecc->rec=ms_factory_create_filter(ecc->factory, MS_VOID_SINK_ID);
|
||||
|
||||
ms_filter_link(ecc->sndread,0,ecc->read_resampler,0);
|
||||
ms_filter_link(ecc->read_resampler,0,ecc->det,0);
|
||||
ms_filter_link(ecc->det,0,ecc->rec,0);
|
||||
|
||||
ecc->play=ms_filter_new(MS_VOID_SOURCE_ID);
|
||||
ecc->gen=ms_filter_new(MS_DTMF_GEN_ID);
|
||||
ecc->play=ms_factory_create_filter(ecc->factory, MS_VOID_SOURCE_ID);
|
||||
ecc->gen=ms_factory_create_filter(ecc->factory, MS_DTMF_GEN_ID);
|
||||
ms_filter_call_method(ecc->gen,MS_FILTER_SET_SAMPLE_RATE,&ecc->rate);
|
||||
ecc->write_resampler=ms_filter_new(MS_RESAMPLE_ID);
|
||||
ecc->write_resampler=ms_factory_create_filter(ecc->factory, MS_RESAMPLE_ID);
|
||||
ecc->sndwrite=ms_snd_card_create_writer(ecc->play_card);
|
||||
|
||||
ms_filter_call_method(ecc->sndwrite,MS_FILTER_SET_SAMPLE_RATE,&ecc->rate);
|
||||
|
|
@ -193,36 +193,60 @@ static void ecc_play_tones(EcCalibrator *ecc){
|
|||
ms_filter_add_notify_callback(ecc->gen,on_tone_sent,ecc,TRUE);
|
||||
|
||||
/* play the three tones*/
|
||||
strncpy(tone.tone_name, "D", sizeof(tone.tone_name));
|
||||
tone.frequencies[0]=(int)2349.32;
|
||||
tone.duration=100;
|
||||
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
|
||||
ms_usleep(300000);
|
||||
|
||||
strncpy(tone.tone_name, "E", sizeof(tone.tone_name));
|
||||
tone.frequencies[0]=(int)2637.02;
|
||||
tone.duration=100;
|
||||
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
|
||||
ms_usleep(300000);
|
||||
|
||||
strncpy(tone.tone_name, "C", sizeof(tone.tone_name));
|
||||
tone.frequencies[0]=(int)2093;
|
||||
tone.duration=100;
|
||||
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
|
||||
ms_usleep(300000);
|
||||
if (ecc->play_cool_tones){
|
||||
strncpy(tone.tone_name, "D", sizeof(tone.tone_name));
|
||||
tone.frequencies[0]=(int)2349.32;
|
||||
tone.duration=100;
|
||||
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
|
||||
ms_usleep(300000);
|
||||
|
||||
strncpy(tone.tone_name, "E", sizeof(tone.tone_name));
|
||||
tone.frequencies[0]=(int)2637.02;
|
||||
tone.duration=100;
|
||||
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
|
||||
ms_usleep(300000);
|
||||
|
||||
strncpy(tone.tone_name, "C", sizeof(tone.tone_name));
|
||||
tone.frequencies[0]=(int)2093;
|
||||
tone.duration=100;
|
||||
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
|
||||
ms_usleep(300000);
|
||||
}else{
|
||||
strncpy(tone.tone_name, "C", sizeof(tone.tone_name));
|
||||
tone.frequencies[0]=(int)2093;
|
||||
tone.duration=100;
|
||||
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
|
||||
ms_usleep(300000);
|
||||
|
||||
strncpy(tone.tone_name, "D", sizeof(tone.tone_name));
|
||||
tone.frequencies[0]=(int)2349.32;
|
||||
tone.duration=100;
|
||||
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
|
||||
ms_usleep(300000);
|
||||
|
||||
strncpy(tone.tone_name, "E", sizeof(tone.tone_name));
|
||||
tone.frequencies[0]=(int)2637.02;
|
||||
tone.duration=100;
|
||||
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
|
||||
ms_usleep(300000);
|
||||
}
|
||||
|
||||
/*these two next ones are for lyrism*/
|
||||
if (ecc->play_cool_tones){
|
||||
tone.tone_name[0]='\0';
|
||||
tone.frequencies[0]=(int)1046.5;
|
||||
tone.duration=400;
|
||||
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
|
||||
ms_usleep(300000);
|
||||
|
||||
tone.tone_name[0]='\0';
|
||||
tone.frequencies[0]=(int)1567.98;
|
||||
tone.duration=400;
|
||||
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
|
||||
}
|
||||
|
||||
tone.tone_name[0]='\0';
|
||||
tone.frequencies[0]=(int)1046.5;
|
||||
tone.duration=400;
|
||||
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
|
||||
ms_usleep(300000);
|
||||
|
||||
tone.tone_name[0]='\0';
|
||||
tone.frequencies[0]=(int)1567.98;
|
||||
tone.duration=400;
|
||||
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
|
||||
ms_sleep(1);
|
||||
|
||||
if (ecc->freq1 && ecc->freq2 && ecc->freq3) {
|
||||
|
|
@ -257,7 +281,7 @@ static void * ecc_thread(void *p){
|
|||
return NULL;
|
||||
}
|
||||
|
||||
EcCalibrator * ec_calibrator_new(MSSndCard *play_card, MSSndCard *capt_card, unsigned int rate, LinphoneEcCalibrationCallback cb,
|
||||
EcCalibrator * ec_calibrator_new(MSFactory *factory, MSSndCard *play_card, MSSndCard *capt_card, unsigned int rate, LinphoneEcCalibrationCallback cb,
|
||||
LinphoneEcCalibrationAudioInit audio_init_cb, LinphoneEcCalibrationAudioUninit audio_uninit_cb, void *cb_data){
|
||||
EcCalibrator *ecc=ms_new0(EcCalibrator,1);
|
||||
|
||||
|
|
@ -268,16 +292,20 @@ EcCalibrator * ec_calibrator_new(MSSndCard *play_card, MSSndCard *capt_card, uns
|
|||
ecc->audio_uninit_cb=audio_uninit_cb;
|
||||
ecc->capt_card=capt_card;
|
||||
ecc->play_card=play_card;
|
||||
ms_thread_create(&ecc->thread,NULL,ecc_thread,ecc);
|
||||
ecc->factory=factory;
|
||||
return ecc;
|
||||
}
|
||||
|
||||
void ec_calibrator_start(EcCalibrator *ecc){
|
||||
ms_thread_create(&ecc->thread,NULL,ecc_thread,ecc);
|
||||
}
|
||||
|
||||
LinphoneEcCalibratorStatus ec_calibrator_get_status(EcCalibrator *ecc){
|
||||
return ecc->status;
|
||||
}
|
||||
|
||||
void ec_calibrator_destroy(EcCalibrator *ecc){
|
||||
ms_thread_join(ecc->thread,NULL);
|
||||
if (ecc->thread != 0) ms_thread_join(ecc->thread,NULL);
|
||||
ms_free(ecc);
|
||||
}
|
||||
|
||||
|
|
@ -290,7 +318,9 @@ int linphone_core_start_echo_calibration(LinphoneCore *lc, LinphoneEcCalibration
|
|||
return -1;
|
||||
}
|
||||
rate = lp_config_get_int(lc->config,"sound","echo_cancellation_rate",8000);
|
||||
lc->ecc=ec_calibrator_new(lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard,rate,cb,audio_init_cb,audio_uninit_cb,cb_data);
|
||||
lc->ecc=ec_calibrator_new(lc->factory, lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard,rate,cb,audio_init_cb,audio_uninit_cb,cb_data);
|
||||
lc->ecc->play_cool_tones = lp_config_get_int(lc->config, "sound", "ec_calibrator_cool_tones", 0);
|
||||
ec_calibrator_start(lc->ecc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,17 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "private.h"
|
||||
#include "lpconfig.h"
|
||||
|
||||
const char * linphone_subscription_dir_to_string(LinphoneSubscriptionDir dir){
|
||||
switch(dir){
|
||||
case LinphoneSubscriptionIncoming:
|
||||
return "LinphoneSubscriptionIncoming";
|
||||
case LinphoneSubscriptionOutgoing:
|
||||
return "LinphoneSubscriptionOutgoing";
|
||||
case LinphoneSubscriptionInvalidDir:
|
||||
return "LinphoneSubscriptionInvalidDir";
|
||||
}
|
||||
return "INVALID";
|
||||
}
|
||||
|
||||
LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatus ss){
|
||||
switch(ss){
|
||||
|
|
@ -35,7 +46,7 @@ const char *linphone_subscription_state_to_string(LinphoneSubscriptionState stat
|
|||
switch(state){
|
||||
case LinphoneSubscriptionNone: return "LinphoneSubscriptionNone";
|
||||
case LinphoneSubscriptionIncomingReceived: return "LinphoneSubscriptionIncomingReceived";
|
||||
case LinphoneSubscriptionOutgoingInit: return "LinphoneSubscriptionOutoingInit";
|
||||
case LinphoneSubscriptionOutgoingProgress: return "LinphoneSubscriptionOutgoingProgress";
|
||||
case LinphoneSubscriptionPending: return "LinphoneSubscriptionPending";
|
||||
case LinphoneSubscriptionActive: return "LinphoneSubscriptionActive";
|
||||
case LinphoneSubscriptionTerminated: return "LinphoneSubscriptionTerminated";
|
||||
|
|
@ -58,11 +69,10 @@ LINPHONE_PUBLIC const char *linphone_publish_state_to_string(LinphonePublishStat
|
|||
}
|
||||
|
||||
static LinphoneEvent * linphone_event_new_base(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name, SalOp *op){
|
||||
LinphoneEvent *lev=ms_new0(LinphoneEvent,1);
|
||||
LinphoneEvent *lev=belle_sip_object_new(LinphoneEvent);
|
||||
lev->lc=lc;
|
||||
lev->dir=dir;
|
||||
lev->op=op;
|
||||
lev->refcnt=1;
|
||||
lev->name=ms_strdup(name);
|
||||
sal_op_set_user_pointer(lev->op,lev);
|
||||
return lev;
|
||||
|
|
@ -88,12 +98,20 @@ LinphoneEvent *linphone_event_new_with_out_of_dialog_op(LinphoneCore *lc, SalOp
|
|||
return linphone_event_new_with_op_base(lc,op,dir,name,TRUE);
|
||||
}
|
||||
|
||||
void linphone_event_set_internal(LinphoneEvent *lev, bool_t internal) {
|
||||
lev->internal = internal;
|
||||
}
|
||||
|
||||
bool_t linphone_event_is_internal(LinphoneEvent *lev) {
|
||||
return lev->internal;
|
||||
}
|
||||
|
||||
void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState state){
|
||||
if (lev->subscription_state!=state){
|
||||
ms_message("LinphoneEvent [%p] moving to subscription state %s",lev,linphone_subscription_state_to_string(state));
|
||||
lev->subscription_state=state;
|
||||
linphone_core_notify_subscription_state_changed(lev->lc,lev,state);
|
||||
if (state==LinphoneSubscriptionTerminated){
|
||||
if (state==LinphoneSubscriptionTerminated || state == LinphoneSubscriptionError){
|
||||
linphone_event_unref(lev);
|
||||
}
|
||||
}
|
||||
|
|
@ -151,7 +169,7 @@ LinphoneEvent *linphone_core_subscribe(LinphoneCore *lc, const LinphoneAddress *
|
|||
|
||||
|
||||
int linphone_event_send_subscribe(LinphoneEvent *lev, const LinphoneContent *body){
|
||||
SalBody salbody;
|
||||
SalBodyHandler *body_handler;
|
||||
int err;
|
||||
|
||||
if (lev->dir!=LinphoneSubscriptionOutgoing){
|
||||
|
|
@ -176,10 +194,12 @@ int linphone_event_send_subscribe(LinphoneEvent *lev, const LinphoneContent *bod
|
|||
|
||||
if (lev->send_custom_headers){
|
||||
sal_op_set_sent_custom_header(lev->op,lev->send_custom_headers);
|
||||
sal_custom_header_free(lev->send_custom_headers);
|
||||
lev->send_custom_headers=NULL;
|
||||
}else sal_op_set_sent_custom_header(lev->op,NULL);
|
||||
|
||||
err=sal_subscribe(lev->op,NULL,NULL,lev->name,lev->expires,sal_body_from_content(&salbody,body));
|
||||
body_handler = sal_body_handler_from_content(body);
|
||||
err=sal_subscribe(lev->op,NULL,NULL,lev->name,lev->expires,body_handler);
|
||||
if (err==0){
|
||||
if (lev->subscription_state==LinphoneSubscriptionNone)
|
||||
linphone_event_set_state(lev,LinphoneSubscriptionOutgoingInit);
|
||||
|
|
@ -191,6 +211,10 @@ int linphone_event_update_subscribe(LinphoneEvent *lev, const LinphoneContent *b
|
|||
return linphone_event_send_subscribe(lev,body);
|
||||
}
|
||||
|
||||
int linphone_event_refresh_subscribe(LinphoneEvent *lev) {
|
||||
return sal_op_refresh(lev->op);
|
||||
}
|
||||
|
||||
int linphone_event_accept_subscription(LinphoneEvent *lev){
|
||||
int err;
|
||||
if (lev->subscription_state!=LinphoneSubscriptionIncomingReceived){
|
||||
|
|
@ -216,7 +240,7 @@ int linphone_event_deny_subscription(LinphoneEvent *lev, LinphoneReason reason){
|
|||
}
|
||||
|
||||
int linphone_event_notify(LinphoneEvent *lev, const LinphoneContent *body){
|
||||
SalBody salbody;
|
||||
SalBodyHandler *body_handler;
|
||||
if (lev->subscription_state!=LinphoneSubscriptionActive){
|
||||
ms_error("linphone_event_notify(): cannot notify if subscription is not active.");
|
||||
return -1;
|
||||
|
|
@ -225,7 +249,8 @@ int linphone_event_notify(LinphoneEvent *lev, const LinphoneContent *body){
|
|||
ms_error("linphone_event_notify(): cannot notify if not an incoming subscription.");
|
||||
return -1;
|
||||
}
|
||||
return sal_notify(lev->op,sal_body_from_content(&salbody,body));
|
||||
body_handler = sal_body_handler_from_content(body);
|
||||
return sal_notify(lev->op, body_handler);
|
||||
}
|
||||
|
||||
LinphoneEvent *linphone_core_create_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires){
|
||||
|
|
@ -236,7 +261,7 @@ LinphoneEvent *linphone_core_create_publish(LinphoneCore *lc, const LinphoneAddr
|
|||
}
|
||||
|
||||
static int _linphone_event_send_publish(LinphoneEvent *lev, const LinphoneContent *body, bool_t notify_err){
|
||||
SalBody salbody;
|
||||
SalBodyHandler *body_handler;
|
||||
int err;
|
||||
|
||||
if (lev->dir!=LinphoneSubscriptionInvalidDir){
|
||||
|
|
@ -245,9 +270,11 @@ static int _linphone_event_send_publish(LinphoneEvent *lev, const LinphoneConten
|
|||
}
|
||||
if (lev->send_custom_headers){
|
||||
sal_op_set_sent_custom_header(lev->op,lev->send_custom_headers);
|
||||
sal_custom_header_free(lev->send_custom_headers);
|
||||
lev->send_custom_headers=NULL;
|
||||
}else sal_op_set_sent_custom_header(lev->op,NULL);
|
||||
err=sal_publish(lev->op,NULL,NULL,lev->name,lev->expires,sal_body_from_content(&salbody,body));
|
||||
body_handler = sal_body_handler_from_content(body);
|
||||
err=sal_publish(lev->op,NULL,NULL,lev->name,lev->expires,body_handler);
|
||||
if (err==0){
|
||||
linphone_event_set_publish_state(lev,LinphonePublishProgress);
|
||||
}else if (notify_err){
|
||||
|
|
@ -276,6 +303,16 @@ int linphone_event_update_publish(LinphoneEvent* lev, const LinphoneContent* bod
|
|||
return linphone_event_send_publish(lev,body);
|
||||
}
|
||||
|
||||
int linphone_event_refresh_publish(LinphoneEvent *lev) {
|
||||
return sal_op_refresh(lev->op);
|
||||
}
|
||||
void linphone_event_pause_publish(LinphoneEvent *lev) {
|
||||
if (lev->op) sal_op_stop_refreshing(lev->op);
|
||||
}
|
||||
void linphone_event_unpublish(LinphoneEvent *lev) {
|
||||
lev->terminating = TRUE; /* needed to get clear event*/
|
||||
if (lev->op) sal_op_unpublish(lev->op);
|
||||
}
|
||||
void linphone_event_set_user_data(LinphoneEvent *ev, void *up){
|
||||
ev->userdata=up;
|
||||
}
|
||||
|
|
@ -305,7 +342,7 @@ void linphone_event_terminate(LinphoneEvent *lev){
|
|||
if (lev->publish_state!=LinphonePublishNone){
|
||||
if (lev->publish_state==LinphonePublishOk && lev->expires!=-1){
|
||||
sal_publish(lev->op,NULL,NULL,NULL,0,NULL);
|
||||
}else sal_op_stop_refreshing(lev->op);
|
||||
}else sal_op_unpublish(lev->op);
|
||||
linphone_event_set_publish_state(lev,LinphonePublishCleared);
|
||||
return;
|
||||
}
|
||||
|
|
@ -318,20 +355,18 @@ void linphone_event_terminate(LinphoneEvent *lev){
|
|||
|
||||
|
||||
LinphoneEvent *linphone_event_ref(LinphoneEvent *lev){
|
||||
lev->refcnt++;
|
||||
belle_sip_object_ref(lev);
|
||||
return lev;
|
||||
}
|
||||
|
||||
static void linphone_event_destroy(LinphoneEvent *lev){
|
||||
if (lev->op)
|
||||
sal_op_release(lev->op);
|
||||
if (lev->op) sal_op_release(lev->op);
|
||||
if (lev->send_custom_headers) sal_custom_header_free(lev->send_custom_headers);
|
||||
ms_free(lev->name);
|
||||
ms_free(lev);
|
||||
}
|
||||
|
||||
void linphone_event_unref(LinphoneEvent *lev){
|
||||
lev->refcnt--;
|
||||
if (lev->refcnt==0) linphone_event_destroy(lev);
|
||||
belle_sip_object_unref(lev);
|
||||
}
|
||||
|
||||
LinphoneSubscriptionDir linphone_event_get_subscription_dir(LinphoneEvent *lev){
|
||||
|
|
@ -366,3 +401,22 @@ LinphoneCore *linphone_event_get_core(const LinphoneEvent *lev){
|
|||
return lev->lc;
|
||||
}
|
||||
|
||||
static belle_sip_error_code _linphone_event_marshall(belle_sip_object_t *obj, char* buff, size_t buff_size, size_t *offset) {
|
||||
LinphoneEvent *ev = (LinphoneEvent*)obj;
|
||||
belle_sip_error_code err = BELLE_SIP_OK;
|
||||
|
||||
err = belle_sip_snprintf(buff, buff_size, offset, "%s of %s", ev->dir == LinphoneSubscriptionIncoming ?
|
||||
"Incoming Subscribe" : (ev->dir == LinphoneSubscriptionOutgoing ? "Outgoing subscribe" : "Publish"), ev->name);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneEvent);
|
||||
|
||||
BELLE_SIP_INSTANCIATE_VPTR(LinphoneEvent, belle_sip_object_t,
|
||||
(belle_sip_object_destroy_t) linphone_event_destroy,
|
||||
NULL, // clone
|
||||
_linphone_event_marshall,
|
||||
FALSE
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -138,12 +138,19 @@ LINPHONE_PUBLIC LinphoneEvent *linphone_core_create_subscribe(LinphoneCore *lc,
|
|||
LINPHONE_PUBLIC int linphone_event_send_subscribe(LinphoneEvent *ev, const LinphoneContent *body);
|
||||
|
||||
/**
|
||||
* Update (refresh) an outgoing subscription.
|
||||
* Update (refresh) an outgoing subscription, changing the body.
|
||||
* @param lev a LinphoneEvent
|
||||
* @param body an optional body to include in the subscription update, may be NULL.
|
||||
**/
|
||||
LINPHONE_PUBLIC int linphone_event_update_subscribe(LinphoneEvent *lev, const LinphoneContent *body);
|
||||
|
||||
/**
|
||||
* Refresh an outgoing subscription keeping the same body.
|
||||
* @param lev LinphoneEvent object.
|
||||
* @return 0 if successful, -1 otherwise.
|
||||
*/
|
||||
LINPHONE_PUBLIC int linphone_event_refresh_subscribe(LinphoneEvent *lev);
|
||||
|
||||
|
||||
/**
|
||||
* Accept an incoming subcription.
|
||||
|
|
@ -201,6 +208,21 @@ LINPHONE_PUBLIC int linphone_event_send_publish(LinphoneEvent *lev, const Linpho
|
|||
**/
|
||||
LINPHONE_PUBLIC int linphone_event_update_publish(LinphoneEvent *lev, const LinphoneContent *body);
|
||||
|
||||
/**
|
||||
* Refresh an outgoing publish keeping the same body.
|
||||
* @param lev LinphoneEvent object.
|
||||
* @return 0 if successful, -1 otherwise.
|
||||
*/
|
||||
LINPHONE_PUBLIC int linphone_event_refresh_publish(LinphoneEvent *lev);
|
||||
|
||||
/**
|
||||
* Prevent an event from refreshing its publish.
|
||||
* This is useful to let registrations to expire naturally (or) when the application wants to keep control on when
|
||||
* refreshes are sent.
|
||||
* The refreshing operations can be resumed with linphone_proxy_config_refresh_register().
|
||||
* @param[in] cfg #LinphoneEvent object.
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_event_pause_publish(LinphoneEvent *lev);
|
||||
|
||||
/**
|
||||
* Return reason code (in case of error state reached).
|
||||
|
|
@ -256,10 +278,8 @@ LINPHONE_PUBLIC const char *linphone_event_get_custom_header(LinphoneEvent *ev,
|
|||
|
||||
/**
|
||||
* Terminate an incoming or outgoing subscription that was previously acccepted, or a previous publication.
|
||||
* This function does not unref the object. The core will unref() if it does not need this object anymore.
|
||||
*
|
||||
* For subscribed event, when the subscription is terminated normally or because of an error, the core will unref.
|
||||
* For published events, no unref is performed. This is because it is allowed to re-publish an expired publish, as well as retry it in case of error.
|
||||
* The LinphoneEvent shall not be used anymore after this operation, unless the application explicitely took a reference on the object with
|
||||
* linphone_event_ref().
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_event_terminate(LinphoneEvent *lev);
|
||||
|
||||
|
|
|
|||
956
coreapi/friend.c
956
coreapi/friend.c
File diff suppressed because it is too large
Load diff
847
coreapi/friendlist.c
Normal file
847
coreapi/friendlist.c
Normal file
|
|
@ -0,0 +1,847 @@
|
|||
/*
|
||||
linphone
|
||||
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
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "linphonecore.h"
|
||||
#include "private.h"
|
||||
|
||||
#include <bctoolbox/crypto.h>
|
||||
|
||||
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneFriendListCbs);
|
||||
|
||||
BELLE_SIP_INSTANCIATE_VPTR(LinphoneFriendListCbs, belle_sip_object_t,
|
||||
NULL, // destroy
|
||||
NULL, // clone
|
||||
NULL, // Marshall
|
||||
FALSE
|
||||
);
|
||||
|
||||
static LinphoneFriendListCbs * linphone_friend_list_cbs_new(void) {
|
||||
return belle_sip_object_new(LinphoneFriendListCbs);
|
||||
}
|
||||
|
||||
LinphoneFriendListCbs * linphone_friend_list_get_callbacks(const LinphoneFriendList *list) {
|
||||
return list->cbs;
|
||||
}
|
||||
|
||||
LinphoneFriendListCbs * linphone_friend_list_cbs_ref(LinphoneFriendListCbs *cbs) {
|
||||
belle_sip_object_ref(cbs);
|
||||
return cbs;
|
||||
}
|
||||
|
||||
void linphone_friend_list_cbs_unref(LinphoneFriendListCbs *cbs) {
|
||||
belle_sip_object_unref(cbs);
|
||||
}
|
||||
|
||||
void *linphone_friend_list_cbs_get_user_data(const LinphoneFriendListCbs *cbs) {
|
||||
return cbs->user_data;
|
||||
}
|
||||
|
||||
void linphone_friend_list_cbs_set_user_data(LinphoneFriendListCbs *cbs, void *ud) {
|
||||
cbs->user_data = ud;
|
||||
}
|
||||
|
||||
LinphoneFriendListCbsContactCreatedCb linphone_friend_list_cbs_get_contact_created(const LinphoneFriendListCbs *cbs) {
|
||||
return cbs->contact_created_cb;
|
||||
}
|
||||
|
||||
void linphone_friend_list_cbs_set_contact_created(LinphoneFriendListCbs *cbs, LinphoneFriendListCbsContactCreatedCb cb) {
|
||||
cbs->contact_created_cb = cb;
|
||||
}
|
||||
|
||||
LinphoneFriendListCbsContactDeletedCb linphone_friend_list_cbs_get_contact_deleted(const LinphoneFriendListCbs *cbs) {
|
||||
return cbs->contact_deleted_cb;
|
||||
}
|
||||
|
||||
void linphone_friend_list_cbs_set_contact_deleted(LinphoneFriendListCbs *cbs, LinphoneFriendListCbsContactDeletedCb cb) {
|
||||
cbs->contact_deleted_cb = cb;
|
||||
}
|
||||
|
||||
LinphoneFriendListCbsContactUpdatedCb linphone_friend_list_cbs_get_contact_updated(const LinphoneFriendListCbs *cbs) {
|
||||
return cbs->contact_updated_cb;
|
||||
}
|
||||
|
||||
void linphone_friend_list_cbs_set_contact_updated(LinphoneFriendListCbs *cbs, LinphoneFriendListCbsContactUpdatedCb cb) {
|
||||
cbs->contact_updated_cb = cb;
|
||||
}
|
||||
|
||||
LinphoneFriendListCbsSyncStateChangedCb linphone_friend_list_cbs_get_sync_status_changed(const LinphoneFriendListCbs *cbs) {
|
||||
return cbs->sync_state_changed_cb;
|
||||
}
|
||||
|
||||
void linphone_friend_list_cbs_set_sync_status_changed(LinphoneFriendListCbs *cbs, LinphoneFriendListCbsSyncStateChangedCb cb) {
|
||||
cbs->sync_state_changed_cb = cb;
|
||||
}
|
||||
|
||||
static char * create_resource_list_xml(const LinphoneFriendList *list) {
|
||||
char *xml_content = NULL;
|
||||
MSList *elem;
|
||||
xmlBufferPtr buf;
|
||||
xmlTextWriterPtr writer;
|
||||
int err;
|
||||
|
||||
if (ms_list_size(list->friends) <= 0) return NULL;
|
||||
|
||||
buf = xmlBufferCreate();
|
||||
if (buf == NULL) {
|
||||
ms_error("%s: Error creating the XML buffer", __FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
writer = xmlNewTextWriterMemory(buf, 0);
|
||||
if (writer == NULL) {
|
||||
ms_error("%s: Error creating the XML writer", __FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
xmlTextWriterSetIndent(writer,1);
|
||||
err = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL);
|
||||
if (err >= 0) {
|
||||
err = xmlTextWriterStartElementNS(writer, NULL, (const xmlChar *)"resource-lists", (const xmlChar *)"urn:ietf:params:xml:ns:resource-lists");
|
||||
}
|
||||
if (err >= 0) {
|
||||
err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xmlns", (const xmlChar *)"xsi",
|
||||
NULL, (const xmlChar *)"http://www.w3.org/2001/XMLSchema-instance");
|
||||
}
|
||||
|
||||
if (err>= 0) {
|
||||
err = xmlTextWriterStartElement(writer, (const xmlChar *)"list");
|
||||
}
|
||||
for (elem = list->friends; elem != NULL; elem = elem->next) {
|
||||
LinphoneFriend *lf = (LinphoneFriend *)elem->data;
|
||||
char *uri = linphone_address_as_string_uri_only(lf->uri);
|
||||
if (err >= 0) {
|
||||
err = xmlTextWriterStartElement(writer, (const xmlChar *)"entry");
|
||||
}
|
||||
if (err >= 0) {
|
||||
err = xmlTextWriterWriteAttribute(writer, (const xmlChar *)"uri", (const xmlChar *)uri);
|
||||
}
|
||||
if (err >= 0) {
|
||||
/* Close the "entry" element. */
|
||||
err = xmlTextWriterEndElement(writer);
|
||||
}
|
||||
if (uri) ms_free(uri);
|
||||
}
|
||||
if (err >= 0) {
|
||||
/* Close the "list" element. */
|
||||
err = xmlTextWriterEndElement(writer);
|
||||
}
|
||||
|
||||
if (err >= 0) {
|
||||
/* Close the "resource-lists" element. */
|
||||
err = xmlTextWriterEndElement(writer);
|
||||
}
|
||||
if (err >= 0) {
|
||||
err = xmlTextWriterEndDocument(writer);
|
||||
}
|
||||
if (err > 0) {
|
||||
/* xmlTextWriterEndDocument returns the size of the content. */
|
||||
xml_content = ms_strdup((char *)buf->content);
|
||||
}
|
||||
xmlFreeTextWriter(writer);
|
||||
xmlBufferFree(buf);
|
||||
|
||||
return xml_content;
|
||||
}
|
||||
|
||||
static void linphone_friend_list_parse_multipart_related_body(LinphoneFriendList *list, const LinphoneContent *body, const char *first_part_body) {
|
||||
xmlparsing_context_t *xml_ctx = linphone_xmlparsing_context_new();
|
||||
xmlSetGenericErrorFunc(xml_ctx, linphone_xmlparsing_genericxml_error);
|
||||
xml_ctx->doc = xmlReadDoc((const unsigned char*)first_part_body, 0, NULL, 0);
|
||||
if (xml_ctx->doc != NULL) {
|
||||
char xpath_str[MAX_XPATH_LENGTH];
|
||||
LinphoneFriend *lf;
|
||||
LinphoneContent *presence_part;
|
||||
xmlXPathObjectPtr resource_object;
|
||||
const char *version_str = NULL;
|
||||
const char *full_state_str = NULL;
|
||||
const char *uri = NULL;
|
||||
bool_t full_state = FALSE;
|
||||
int version;
|
||||
int i;
|
||||
|
||||
if (linphone_create_xml_xpath_context(xml_ctx) < 0) goto end;
|
||||
xmlXPathRegisterNs(xml_ctx->xpath_ctx, (const xmlChar *)"rlmi", (const xmlChar *)"urn:ietf:params:xml:ns:rlmi");
|
||||
|
||||
version_str = linphone_get_xml_attribute_text_content(xml_ctx, "/rlmi:list", "version");
|
||||
if (version_str == NULL) {
|
||||
ms_warning("rlmi+xml: No version attribute in list");
|
||||
goto end;
|
||||
}
|
||||
version = atoi(version_str);
|
||||
linphone_free_xml_text_content(version_str);
|
||||
if (version < list->expected_notification_version) {
|
||||
ms_warning("rlmi+xml: Discarding received notification with version %d because %d was expected", version, list->expected_notification_version);
|
||||
linphone_friend_list_update_subscriptions(list, NULL, FALSE); /* Refresh subscription to get new full state notify. */
|
||||
goto end;
|
||||
}
|
||||
|
||||
full_state_str = linphone_get_xml_attribute_text_content(xml_ctx, "/rlmi:list", "fullState");
|
||||
if (full_state_str == NULL) {
|
||||
ms_warning("rlmi+xml: No fullState attribute in list");
|
||||
goto end;
|
||||
}
|
||||
if ((strcmp(full_state_str, "true") == 0) || (strcmp(full_state_str, "1") == 0)) {
|
||||
MSList *l = list->friends;
|
||||
for (; l != NULL; l = l->next) {
|
||||
lf = (LinphoneFriend *)l->data;
|
||||
linphone_friend_set_presence_model(lf, NULL);
|
||||
}
|
||||
full_state = TRUE;
|
||||
}
|
||||
linphone_free_xml_text_content(full_state_str);
|
||||
if ((list->expected_notification_version == 0) && (full_state == FALSE)) {
|
||||
ms_warning("rlmi+xml: Notification with version 0 is not full state, this is not valid");
|
||||
goto end;
|
||||
}
|
||||
list->expected_notification_version = version + 1;
|
||||
|
||||
resource_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, "/rlmi:list/rlmi:resource");
|
||||
if ((resource_object != NULL) && (resource_object->nodesetval != NULL)) {
|
||||
for (i = 1; i <= resource_object->nodesetval->nodeNr; i++) {
|
||||
snprintf(xpath_str, sizeof(xpath_str), "/rlmi:list/rlmi:resource[%i]/@uri", i);
|
||||
uri = linphone_get_xml_text_content(xml_ctx, xpath_str);
|
||||
if (uri == NULL) continue;
|
||||
lf = linphone_friend_list_find_friend_by_uri(list, uri);
|
||||
if (lf != NULL) {
|
||||
const char *state = NULL;
|
||||
snprintf(xpath_str, sizeof(xpath_str),"/rlmi:list/rlmi:resource[%i]/rlmi:instance/@state", i);
|
||||
state = linphone_get_xml_text_content(xml_ctx, xpath_str);
|
||||
if ((state != NULL) && (strcmp(state, "active") == 0)) {
|
||||
const char *cid = NULL;
|
||||
snprintf(xpath_str, sizeof(xpath_str),"/rlmi:list/rlmi:resource[%i]/rlmi:instance/@cid", i);
|
||||
cid = linphone_get_xml_text_content(xml_ctx, xpath_str);
|
||||
if (cid != NULL) {
|
||||
presence_part = linphone_content_find_part_by_header(body, "Content-Id", cid);
|
||||
if (presence_part == NULL) {
|
||||
ms_warning("rlmi+xml: Cannot find part with Content-Id: %s", cid);
|
||||
} else {
|
||||
SalPresenceModel *presence = NULL;
|
||||
linphone_notify_parse_presence(linphone_content_get_type(presence_part), linphone_content_get_subtype(presence_part), linphone_content_get_string_buffer(presence_part), &presence);
|
||||
if (presence != NULL) {
|
||||
lf->presence_received = TRUE;
|
||||
linphone_friend_set_presence_model(lf, (LinphonePresenceModel *)presence);
|
||||
if (full_state == FALSE) {
|
||||
linphone_core_notify_notify_presence_received(list->lc, lf);
|
||||
}
|
||||
}
|
||||
linphone_content_unref(presence_part);
|
||||
}
|
||||
}
|
||||
if (cid != NULL) linphone_free_xml_text_content(cid);
|
||||
}
|
||||
if (state != NULL) linphone_free_xml_text_content(state);
|
||||
lf->subscribe_active = TRUE;
|
||||
}
|
||||
linphone_free_xml_text_content(uri);
|
||||
}
|
||||
}
|
||||
if (resource_object != NULL) xmlXPathFreeObject(resource_object);
|
||||
|
||||
if (full_state == TRUE) {
|
||||
MSList *l = list->friends;
|
||||
for (; l != NULL; l = l->next) {
|
||||
lf = (LinphoneFriend *)l->data;
|
||||
if (linphone_friend_is_presence_received(lf) == TRUE) {
|
||||
linphone_core_notify_notify_presence_received(list->lc, lf);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ms_warning("Wrongly formatted rlmi+xml body: %s", xml_ctx->errorBuffer);
|
||||
}
|
||||
|
||||
end:
|
||||
linphone_xmlparsing_context_destroy(xml_ctx);
|
||||
}
|
||||
|
||||
static bool_t linphone_friend_list_has_subscribe_inactive(const LinphoneFriendList *list) {
|
||||
MSList *l = list->friends;
|
||||
bool_t has_subscribe_inactive = FALSE;
|
||||
for (; l != NULL; l = l->next) {
|
||||
LinphoneFriend *lf = (LinphoneFriend *)l->data;
|
||||
if (lf->subscribe_active != TRUE) {
|
||||
has_subscribe_inactive = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return has_subscribe_inactive;
|
||||
}
|
||||
|
||||
static LinphoneFriendList * linphone_friend_list_new(void) {
|
||||
LinphoneFriendList *list = belle_sip_object_new(LinphoneFriendList);
|
||||
list->cbs = linphone_friend_list_cbs_new();
|
||||
belle_sip_object_ref(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
static void linphone_friend_list_destroy(LinphoneFriendList *list) {
|
||||
if (list->display_name != NULL) ms_free(list->display_name);
|
||||
if (list->rls_uri != NULL) ms_free(list->rls_uri);
|
||||
if (list->content_digest != NULL) ms_free(list->content_digest);
|
||||
if (list->event != NULL) {
|
||||
linphone_event_terminate(list->event);
|
||||
linphone_event_unref(list->event);
|
||||
}
|
||||
if (list->uri != NULL) ms_free(list->uri);
|
||||
if (list->cbs) linphone_friend_list_cbs_unref(list->cbs);
|
||||
if (list->dirty_friends_to_update) list->dirty_friends_to_update = ms_list_free_with_data(list->dirty_friends_to_update, (void (*)(void *))linphone_friend_unref);
|
||||
if (list->friends) list->friends = ms_list_free_with_data(list->friends, (void (*)(void *))_linphone_friend_release);
|
||||
}
|
||||
|
||||
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneFriendList);
|
||||
|
||||
BELLE_SIP_INSTANCIATE_VPTR(LinphoneFriendList, belle_sip_object_t,
|
||||
(belle_sip_object_destroy_t)linphone_friend_list_destroy,
|
||||
NULL, // clone
|
||||
NULL, // marshal
|
||||
TRUE
|
||||
);
|
||||
|
||||
|
||||
LinphoneFriendList * linphone_core_create_friend_list(LinphoneCore *lc) {
|
||||
LinphoneFriendList *list = linphone_friend_list_new();
|
||||
list->lc = lc;
|
||||
return list;
|
||||
}
|
||||
|
||||
LinphoneFriendList * linphone_friend_list_ref(LinphoneFriendList *list) {
|
||||
belle_sip_object_ref(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
void _linphone_friend_list_release(LinphoneFriendList *list){
|
||||
/*drops all references to core and unref*/
|
||||
list->lc = NULL;
|
||||
if (list->event != NULL) {
|
||||
linphone_event_unref(list->event);
|
||||
list->event = NULL;
|
||||
}
|
||||
if (list->cbs) {
|
||||
linphone_friend_list_cbs_unref(list->cbs);
|
||||
list->cbs = NULL;
|
||||
}
|
||||
if (list->dirty_friends_to_update) {
|
||||
list->dirty_friends_to_update = ms_list_free_with_data(list->dirty_friends_to_update, (void (*)(void *))linphone_friend_unref);
|
||||
}
|
||||
if (list->friends) {
|
||||
list->friends = ms_list_free_with_data(list->friends, (void (*)(void *))_linphone_friend_release);
|
||||
}
|
||||
linphone_friend_list_unref(list);
|
||||
}
|
||||
|
||||
void linphone_friend_list_unref(LinphoneFriendList *list) {
|
||||
belle_sip_object_unref(list);
|
||||
}
|
||||
|
||||
void * linphone_friend_list_get_user_data(const LinphoneFriendList *list) {
|
||||
return list->user_data;
|
||||
}
|
||||
|
||||
void linphone_friend_list_set_user_data(LinphoneFriendList *list, void *ud) {
|
||||
list->user_data = ud;
|
||||
}
|
||||
|
||||
const char * linphone_friend_list_get_display_name(const LinphoneFriendList *list) {
|
||||
return list->display_name;
|
||||
}
|
||||
|
||||
void linphone_friend_list_set_display_name(LinphoneFriendList *list, const char *display_name) {
|
||||
if (list->display_name != NULL) {
|
||||
ms_free(list->display_name);
|
||||
list->display_name = NULL;
|
||||
}
|
||||
if (display_name != NULL) {
|
||||
list->display_name = ms_strdup(display_name);
|
||||
linphone_core_store_friends_list_in_db(list->lc, list);
|
||||
}
|
||||
}
|
||||
|
||||
const char * linphone_friend_list_get_rls_uri(const LinphoneFriendList *list) {
|
||||
return list->rls_uri;
|
||||
}
|
||||
|
||||
void linphone_friend_list_set_rls_uri(LinphoneFriendList *list, const char *rls_uri) {
|
||||
if (list->rls_uri != NULL) {
|
||||
ms_free(list->rls_uri);
|
||||
list->rls_uri = NULL;
|
||||
}
|
||||
if (rls_uri != NULL) {
|
||||
list->rls_uri = ms_strdup(rls_uri);
|
||||
linphone_core_store_friends_list_in_db(list->lc, list);
|
||||
}
|
||||
}
|
||||
|
||||
static LinphoneFriendListStatus _linphone_friend_list_add_friend(LinphoneFriendList *list, LinphoneFriend *lf, bool_t synchronize) {
|
||||
if (!list || !lf->uri || lf->friend_list) {
|
||||
if (!list)
|
||||
ms_error("linphone_friend_list_add_friend(): invalid list, null");
|
||||
if (!lf->uri)
|
||||
ms_error("linphone_friend_list_add_friend(): invalid friend, no sip uri");
|
||||
if (lf->friend_list)
|
||||
ms_error("linphone_friend_list_add_friend(): invalid friend, already in list");
|
||||
return LinphoneFriendListInvalidFriend;
|
||||
}
|
||||
if (ms_list_find(list->friends, lf) != NULL) {
|
||||
char *tmp = NULL;
|
||||
const LinphoneAddress *addr = linphone_friend_get_address(lf);
|
||||
if (addr) tmp = linphone_address_as_string(addr);
|
||||
ms_warning("Friend %s already in list [%s], ignored.", tmp ? tmp : "unknown", list->display_name);
|
||||
if (tmp) ms_free(tmp);
|
||||
} else {
|
||||
return linphone_friend_list_import_friend(list, lf, synchronize);
|
||||
}
|
||||
return LinphoneFriendListOK;
|
||||
}
|
||||
|
||||
LinphoneFriendListStatus linphone_friend_list_add_friend(LinphoneFriendList *list, LinphoneFriend *lf) {
|
||||
return _linphone_friend_list_add_friend(list, lf, TRUE);
|
||||
}
|
||||
|
||||
LinphoneFriendListStatus linphone_friend_list_add_local_friend(LinphoneFriendList *list, LinphoneFriend *lf) {
|
||||
return _linphone_friend_list_add_friend(list, lf, FALSE);
|
||||
}
|
||||
|
||||
LinphoneFriendListStatus linphone_friend_list_import_friend(LinphoneFriendList *list, LinphoneFriend *lf, bool_t synchronize) {
|
||||
if (!lf->uri || lf->friend_list) {
|
||||
if (!lf->uri)
|
||||
ms_error("linphone_friend_list_add_friend(): invalid friend, no sip uri");
|
||||
if (lf->friend_list)
|
||||
ms_error("linphone_friend_list_add_friend(): invalid friend, already in list");
|
||||
return LinphoneFriendListInvalidFriend;
|
||||
}
|
||||
lf->friend_list = list;
|
||||
lf->lc = list->lc;
|
||||
list->friends = ms_list_append(list->friends, linphone_friend_ref(lf));
|
||||
if (synchronize) {
|
||||
list->dirty_friends_to_update = ms_list_append(list->dirty_friends_to_update, linphone_friend_ref(lf));
|
||||
}
|
||||
#ifdef FRIENDS_SQL_STORAGE_ENABLED
|
||||
linphone_core_store_friend_in_db(lf->lc, lf);
|
||||
#endif
|
||||
return LinphoneFriendListOK;
|
||||
}
|
||||
|
||||
static void carddav_done(LinphoneCardDavContext *cdc, bool_t success, const char *msg) {
|
||||
if (cdc && cdc->friend_list->cbs->sync_state_changed_cb) {
|
||||
cdc->friend_list->cbs->sync_state_changed_cb(cdc->friend_list, success ? LinphoneFriendListSyncSuccessful : LinphoneFriendListSyncFailure, msg);
|
||||
}
|
||||
linphone_carddav_context_destroy(cdc);
|
||||
}
|
||||
|
||||
static LinphoneFriendListStatus _linphone_friend_list_remove_friend(LinphoneFriendList *list, LinphoneFriend *lf, bool_t remove_from_server) {
|
||||
MSList *elem = ms_list_find(list->friends, lf);
|
||||
if (elem == NULL) return LinphoneFriendListNonExistentFriend;
|
||||
|
||||
#ifdef FRIENDS_SQL_STORAGE_ENABLED
|
||||
if (lf && lf->lc && lf->lc->friends_db) {
|
||||
linphone_core_remove_friend_from_db(lf->lc, lf);
|
||||
}
|
||||
#endif
|
||||
if (remove_from_server) {
|
||||
LinphoneVcard *lvc = linphone_friend_get_vcard(lf);
|
||||
if (lvc && linphone_vcard_get_uid(lvc)) {
|
||||
LinphoneCardDavContext *cdc = linphone_carddav_context_new(list);
|
||||
if (cdc) {
|
||||
cdc->sync_done_cb = carddav_done;
|
||||
if (cdc->friend_list->cbs->sync_state_changed_cb) {
|
||||
cdc->friend_list->cbs->sync_state_changed_cb(cdc->friend_list, LinphoneFriendListSyncStarted, NULL);
|
||||
}
|
||||
linphone_carddav_delete_vcard(cdc, lf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lf->friend_list = NULL;
|
||||
linphone_friend_unref(lf);
|
||||
list->friends = ms_list_remove_link(list->friends, elem);
|
||||
return LinphoneFriendListOK;
|
||||
}
|
||||
|
||||
LinphoneFriendListStatus linphone_friend_list_remove_friend(LinphoneFriendList *list, LinphoneFriend *lf) {
|
||||
return _linphone_friend_list_remove_friend(list, lf, TRUE);
|
||||
}
|
||||
|
||||
const MSList * linphone_friend_list_get_friends(const LinphoneFriendList *list) {
|
||||
return list->friends;
|
||||
}
|
||||
|
||||
void linphone_friend_list_update_dirty_friends(LinphoneFriendList *list) {
|
||||
LinphoneCardDavContext *cdc = linphone_carddav_context_new(list);
|
||||
MSList *dirty_friends = list->dirty_friends_to_update;
|
||||
|
||||
if (cdc) {
|
||||
cdc->sync_done_cb = carddav_done;
|
||||
while (dirty_friends) {
|
||||
LinphoneFriend *lf = (LinphoneFriend *)dirty_friends->data;
|
||||
if (lf) {
|
||||
if (cdc->friend_list->cbs->sync_state_changed_cb) {
|
||||
cdc->friend_list->cbs->sync_state_changed_cb(cdc->friend_list, LinphoneFriendListSyncStarted, NULL);
|
||||
}
|
||||
linphone_carddav_put_vcard(cdc, lf);
|
||||
}
|
||||
dirty_friends = ms_list_next(dirty_friends);
|
||||
}
|
||||
list->dirty_friends_to_update = ms_list_free_with_data(list->dirty_friends_to_update, (void (*)(void *))linphone_friend_unref);
|
||||
}
|
||||
}
|
||||
|
||||
static void carddav_created(LinphoneCardDavContext *cdc, LinphoneFriend *lf) {
|
||||
if (cdc) {
|
||||
LinphoneFriendList *lfl = cdc->friend_list;
|
||||
linphone_friend_list_import_friend(lfl, lf, FALSE);
|
||||
if (cdc->friend_list->cbs->contact_created_cb) {
|
||||
cdc->friend_list->cbs->contact_created_cb(lfl, lf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void carddav_removed(LinphoneCardDavContext *cdc, LinphoneFriend *lf) {
|
||||
if (cdc) {
|
||||
LinphoneFriendList *lfl = cdc->friend_list;
|
||||
_linphone_friend_list_remove_friend(lfl, lf, FALSE);
|
||||
if (cdc->friend_list->cbs->contact_deleted_cb) {
|
||||
cdc->friend_list->cbs->contact_deleted_cb(lfl, lf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void carddav_updated(LinphoneCardDavContext *cdc, LinphoneFriend *lf_new, LinphoneFriend *lf_old) {
|
||||
if (cdc) {
|
||||
LinphoneFriendList *lfl = cdc->friend_list;
|
||||
MSList *elem = ms_list_find(lfl->friends, lf_old);
|
||||
if (elem) {
|
||||
elem->data = linphone_friend_ref(lf_new);
|
||||
}
|
||||
linphone_core_store_friend_in_db(lf_new->lc, lf_new);
|
||||
|
||||
if (cdc->friend_list->cbs->contact_updated_cb) {
|
||||
cdc->friend_list->cbs->contact_updated_cb(lfl, lf_new, lf_old);
|
||||
}
|
||||
linphone_friend_unref(lf_old);
|
||||
}
|
||||
}
|
||||
|
||||
void linphone_friend_list_synchronize_friends_from_server(LinphoneFriendList *list) {
|
||||
LinphoneCardDavContext *cdc = linphone_carddav_context_new(list);
|
||||
|
||||
if (cdc) {
|
||||
cdc->contact_created_cb = carddav_created;
|
||||
cdc->contact_removed_cb = carddav_removed;
|
||||
cdc->contact_updated_cb = carddav_updated;
|
||||
cdc->sync_done_cb = carddav_done;
|
||||
if (cdc && cdc->friend_list->cbs->sync_state_changed_cb) {
|
||||
cdc->friend_list->cbs->sync_state_changed_cb(cdc->friend_list, LinphoneFriendListSyncStarted, NULL);
|
||||
}
|
||||
linphone_carddav_synchronize(cdc);
|
||||
}
|
||||
}
|
||||
|
||||
LinphoneFriend * linphone_friend_list_find_friend_by_address(const LinphoneFriendList *list, const LinphoneAddress *address) {
|
||||
LinphoneFriend *lf = NULL;
|
||||
const MSList *elem;
|
||||
for (elem = list->friends; elem != NULL; elem = elem->next) {
|
||||
lf = (LinphoneFriend *)elem->data;
|
||||
if (linphone_address_weak_equal(lf->uri, address))
|
||||
return lf;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LinphoneFriend * linphone_friend_list_find_friend_by_uri(const LinphoneFriendList *list, const char *uri) {
|
||||
LinphoneAddress *address = linphone_address_new(uri);
|
||||
LinphoneFriend *lf = address ? linphone_friend_list_find_friend_by_address(list, address) : NULL;
|
||||
if (address) linphone_address_unref(address);
|
||||
return lf;
|
||||
}
|
||||
|
||||
LinphoneFriend * linphone_friend_list_find_friend_by_ref_key(const LinphoneFriendList *list, const char *ref_key) {
|
||||
const MSList *elem;
|
||||
if (ref_key == NULL) return NULL;
|
||||
for (elem = list->friends; elem != NULL; elem = elem->next) {
|
||||
LinphoneFriend *lf = (LinphoneFriend *)elem->data;
|
||||
if ((lf->refkey != NULL) && (strcmp(lf->refkey, ref_key) == 0)) return lf;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LinphoneFriend * linphone_friend_list_find_friend_by_inc_subscribe(const LinphoneFriendList *list, SalOp *op) {
|
||||
const MSList *elem;
|
||||
for (elem = list->friends; elem != NULL; elem = elem->next) {
|
||||
LinphoneFriend *lf = (LinphoneFriend *)elem->data;
|
||||
if (ms_list_find(lf->insubs, op)) return lf;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LinphoneFriend * linphone_friend_list_find_friend_by_out_subscribe(const LinphoneFriendList *list, SalOp *op) {
|
||||
const MSList *elem;
|
||||
for (elem = list->friends; elem != NULL; elem = elem->next) {
|
||||
LinphoneFriend *lf = (LinphoneFriend *)elem->data;
|
||||
if (lf->outsub && ((lf->outsub == op) || sal_op_is_forked_of(lf->outsub, op))) return lf;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void linphone_friend_list_close_subscriptions(LinphoneFriendList *list) {
|
||||
/* FIXME we should wait until subscription to complete. */
|
||||
if (list->event) {
|
||||
linphone_event_terminate(list->event);
|
||||
} else if (list->friends)
|
||||
ms_list_for_each(list->friends, (void (*)(void *))linphone_friend_close_subscriptions);
|
||||
}
|
||||
|
||||
void linphone_friend_list_update_subscriptions(LinphoneFriendList *list, LinphoneProxyConfig *cfg, bool_t only_when_registered) {
|
||||
const MSList *elem;
|
||||
if (list->rls_uri != NULL) {
|
||||
LinphoneAddress *address = linphone_address_new(list->rls_uri);
|
||||
char *xml_content = create_resource_list_xml(list);
|
||||
if ((address != NULL) && (xml_content != NULL) && (linphone_friend_list_has_subscribe_inactive(list) == TRUE)) {
|
||||
unsigned char digest[16];
|
||||
bctoolbox_md5((unsigned char *)xml_content, strlen(xml_content), digest);
|
||||
if ((list->event != NULL) && (list->content_digest != NULL) && (memcmp(list->content_digest, digest, sizeof(digest)) == 0)) {
|
||||
/* The content has not changed, only refresh the event. */
|
||||
linphone_event_refresh_subscribe(list->event);
|
||||
} else {
|
||||
LinphoneContent *content;
|
||||
int expires = lp_config_get_int(list->lc->config, "sip", "rls_presence_expires", 3600);
|
||||
list->expected_notification_version = 0;
|
||||
if (list->content_digest != NULL) ms_free(list->content_digest);
|
||||
list->content_digest = ms_malloc(sizeof(digest));
|
||||
memcpy(list->content_digest, digest, sizeof(digest));
|
||||
if (list->event != NULL) {
|
||||
linphone_event_terminate(list->event);
|
||||
linphone_event_unref(list->event);
|
||||
}
|
||||
list->event = linphone_core_create_subscribe(list->lc, address, "presence", expires);
|
||||
linphone_event_ref(list->event);
|
||||
linphone_event_set_internal(list->event, TRUE);
|
||||
linphone_event_add_custom_header(list->event, "Require", "recipient-list-subscribe");
|
||||
linphone_event_add_custom_header(list->event, "Supported", "eventlist");
|
||||
linphone_event_add_custom_header(list->event, "Accept", "multipart/related, application/pidf+xml, application/rlmi+xml");
|
||||
linphone_event_add_custom_header(list->event, "Content-Disposition", "recipient-list");
|
||||
content = linphone_core_create_content(list->lc);
|
||||
linphone_content_set_type(content, "application");
|
||||
linphone_content_set_subtype(content, "resource-lists+xml");
|
||||
linphone_content_set_string_buffer(content, xml_content);
|
||||
if (linphone_core_content_encoding_supported(list->lc, "deflate")) {
|
||||
linphone_content_set_encoding(content, "deflate");
|
||||
linphone_event_add_custom_header(list->event, "Accept-Encoding", "deflate");
|
||||
}
|
||||
linphone_event_send_subscribe(list->event, content);
|
||||
linphone_content_unref(content);
|
||||
linphone_event_set_user_data(list->event, list);
|
||||
}
|
||||
}
|
||||
if (address != NULL) linphone_address_unref(address);
|
||||
if (xml_content != NULL) ms_free(xml_content);
|
||||
} else {
|
||||
for (elem = list->friends; elem != NULL; elem = elem->next) {
|
||||
LinphoneFriend *lf = (LinphoneFriend *)elem->data;
|
||||
linphone_friend_update_subscribes(lf, cfg, only_when_registered);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void linphone_friend_list_invalidate_subscriptions(LinphoneFriendList *list) {
|
||||
const MSList *elem;
|
||||
for (elem = list->friends; elem != NULL; elem = elem->next) {
|
||||
LinphoneFriend *lf = (LinphoneFriend *)elem->data;
|
||||
linphone_friend_invalidate_subscription(lf);
|
||||
}
|
||||
}
|
||||
|
||||
void linphone_friend_list_notify_presence(LinphoneFriendList *list, LinphonePresenceModel *presence) {
|
||||
const MSList *elem;
|
||||
for(elem = list->friends; elem != NULL; elem = elem->next) {
|
||||
LinphoneFriend *lf = (LinphoneFriend *)elem->data;
|
||||
linphone_friend_notify(lf, presence);
|
||||
}
|
||||
}
|
||||
|
||||
void linphone_friend_list_notify_presence_received(LinphoneFriendList *list, LinphoneEvent *lev, const LinphoneContent *body) {
|
||||
if (linphone_content_is_multipart(body)) {
|
||||
LinphoneContent *first_part;
|
||||
const char *type = linphone_content_get_type(body);
|
||||
const char *subtype = linphone_content_get_subtype(body);
|
||||
|
||||
if ((strcmp(type, "multipart") != 0) || (strcmp(subtype, "related") != 0)) {
|
||||
ms_warning("multipart presence notified but it is not 'multipart/related'");
|
||||
return;
|
||||
}
|
||||
|
||||
first_part = linphone_content_get_part(body, 0);
|
||||
if (first_part == NULL) {
|
||||
ms_warning("'multipart/related' presence notified but it doesn't contain any part");
|
||||
return;
|
||||
}
|
||||
|
||||
type = linphone_content_get_type(first_part);
|
||||
subtype = linphone_content_get_subtype(first_part);
|
||||
if ((strcmp(type, "application") != 0) || (strcmp(subtype, "rlmi+xml") != 0)) {
|
||||
ms_warning("multipart presence notified but first part is not 'application/rlmi+xml'");
|
||||
linphone_content_unref(first_part);
|
||||
return;
|
||||
}
|
||||
|
||||
linphone_friend_list_parse_multipart_related_body(list, body, linphone_content_get_string_buffer(first_part));
|
||||
linphone_content_unref(first_part);
|
||||
}
|
||||
}
|
||||
|
||||
const char * linphone_friend_list_get_uri(const LinphoneFriendList *list) {
|
||||
return list->uri;
|
||||
}
|
||||
|
||||
void linphone_friend_list_set_uri(LinphoneFriendList *list, const char *uri) {
|
||||
if (list->uri != NULL) {
|
||||
ms_free(list->uri);
|
||||
list->uri = NULL;
|
||||
}
|
||||
if (uri != NULL) {
|
||||
list->uri = ms_strdup(uri);
|
||||
linphone_core_store_friends_list_in_db(list->lc, list);
|
||||
}
|
||||
}
|
||||
|
||||
void linphone_friend_list_update_revision(LinphoneFriendList *list, int rev) {
|
||||
list->revision = rev;
|
||||
linphone_core_store_friends_list_in_db(list->lc, list);
|
||||
}
|
||||
|
||||
void linphone_friend_list_subscription_state_changed(LinphoneCore *lc, LinphoneEvent *lev, LinphoneSubscriptionState state) {
|
||||
LinphoneFriendList *list = (LinphoneFriendList *)linphone_event_get_user_data(lev);
|
||||
if (!list) {
|
||||
ms_warning("core [%p] Receiving unexpected state [%s] for event [%p], no associated friend list",lc
|
||||
, linphone_subscription_state_to_string(state)
|
||||
, lev);
|
||||
} else {
|
||||
ms_message("Receiving new state [%s] for event [%p] for friend list [%p]"
|
||||
, linphone_subscription_state_to_string(state)
|
||||
, lev
|
||||
, list);
|
||||
|
||||
if (state == LinphoneSubscriptionOutgoingProgress && linphone_event_get_reason(lev) == LinphoneReasonNoMatch) {
|
||||
ms_message("Resseting version count for friend list [%p]",list);
|
||||
list->expected_notification_version = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LinphoneCore* linphone_friend_list_get_core(LinphoneFriendList *list) {
|
||||
return list->lc;
|
||||
}
|
||||
|
||||
int linphone_friend_list_import_friends_from_vcard4_file(LinphoneFriendList *list, const char *vcard_file) {
|
||||
MSList *vcards = linphone_vcard_list_from_vcard4_file(vcard_file);
|
||||
int count = 0;
|
||||
|
||||
#ifndef VCARD_ENABLED
|
||||
ms_error("vCard support wasn't enabled at compilation time");
|
||||
return -1;
|
||||
#endif
|
||||
if (!vcards) {
|
||||
ms_error("Failed to parse the file %s", vcard_file);
|
||||
return -1;
|
||||
}
|
||||
if (!list) {
|
||||
ms_error("Can't import into a NULL list");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (vcards != NULL && vcards->data != NULL) {
|
||||
LinphoneVcard *vcard = (LinphoneVcard *)vcards->data;
|
||||
LinphoneFriend *lf = linphone_friend_new_from_vcard(vcard);
|
||||
if (lf) {
|
||||
if (LinphoneFriendListOK == linphone_friend_list_import_friend(list, lf, TRUE)) {
|
||||
count++;
|
||||
}
|
||||
linphone_friend_unref(lf);
|
||||
} else {
|
||||
linphone_vcard_free(vcard);
|
||||
}
|
||||
vcards = ms_list_next(vcards);
|
||||
}
|
||||
#ifndef FRIENDS_SQL_STORAGE_ENABLED
|
||||
linphone_core_write_friends_config(list->lc);
|
||||
#endif
|
||||
return count;
|
||||
}
|
||||
|
||||
int linphone_friend_list_import_friends_from_vcard4_buffer(LinphoneFriendList *list, const char *vcard_buffer) {
|
||||
MSList *vcards = linphone_vcard_list_from_vcard4_buffer(vcard_buffer);
|
||||
int count = 0;
|
||||
|
||||
#ifndef VCARD_ENABLED
|
||||
ms_error("vCard support wasn't enabled at compilation time");
|
||||
return -1;
|
||||
#endif
|
||||
if (!vcards) {
|
||||
ms_error("Failed to parse the buffer");
|
||||
return -1;
|
||||
}
|
||||
if (!list) {
|
||||
ms_error("Can't import into a NULL list");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (vcards != NULL && vcards->data != NULL) {
|
||||
LinphoneVcard *vcard = (LinphoneVcard *)vcards->data;
|
||||
LinphoneFriend *lf = linphone_friend_new_from_vcard(vcard);
|
||||
if (lf) {
|
||||
if (LinphoneFriendListOK == linphone_friend_list_import_friend(list, lf, TRUE)) {
|
||||
count++;
|
||||
}
|
||||
linphone_friend_unref(lf);
|
||||
} else {
|
||||
linphone_vcard_free(vcard);
|
||||
}
|
||||
vcards = ms_list_next(vcards);
|
||||
}
|
||||
#ifndef FRIENDS_SQL_STORAGE_ENABLED
|
||||
linphone_core_write_friends_config(list->lc);
|
||||
#endif
|
||||
return count;
|
||||
}
|
||||
|
||||
void linphone_friend_list_export_friends_as_vcard4_file(LinphoneFriendList *list, const char *vcard_file) {
|
||||
FILE *file = NULL;
|
||||
const MSList *friends = linphone_friend_list_get_friends(list);
|
||||
|
||||
file = fopen(vcard_file, "wb");
|
||||
if (file == NULL) {
|
||||
ms_warning("Could not write %s ! Maybe it is read-only. Contacts will not be saved.", vcard_file);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef VCARD_ENABLED
|
||||
ms_error("vCard support wasn't enabled at compilation time");
|
||||
#endif
|
||||
while (friends != NULL && friends->data != NULL) {
|
||||
LinphoneFriend *lf = (LinphoneFriend *)friends->data;
|
||||
LinphoneVcard *vcard = linphone_friend_get_vcard(lf);
|
||||
if (vcard) {
|
||||
const char *vcard_text = linphone_vcard_as_vcard4_string(vcard);
|
||||
fprintf(file, "%s", vcard_text);
|
||||
} else {
|
||||
ms_warning("Couldn't export friend %s because it doesn't have a vCard attached", linphone_address_as_string(linphone_friend_get_address(lf)));
|
||||
}
|
||||
friends = ms_list_next(friends);
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
}
|
||||
419
coreapi/friendlist.h
Normal file
419
coreapi/friendlist.h
Normal file
|
|
@ -0,0 +1,419 @@
|
|||
/*
|
||||
friendlist.h
|
||||
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
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LINPHONE_FRIENDLIST_H_
|
||||
#define LINPHONE_FRIENDLIST_H_
|
||||
|
||||
|
||||
#ifdef IN_LINPHONE
|
||||
#include "linphonefriend.h"
|
||||
#include "linphonepresence.h"
|
||||
#else
|
||||
#include "linphone/linphonefriend.h"
|
||||
#include "linphone/linphonepresence.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @addtogroup buddy_list
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Enum describing the status of a LinphoneFriendList operation.
|
||||
**/
|
||||
typedef enum _LinphoneFriendListStatus {
|
||||
LinphoneFriendListOK,
|
||||
LinphoneFriendListNonExistentFriend,
|
||||
LinphoneFriendListInvalidFriend
|
||||
} LinphoneFriendListStatus;
|
||||
|
||||
/**
|
||||
* Enum describing the status of a CardDAV synchronization
|
||||
*/
|
||||
typedef enum _LinphoneFriendListSyncStatus {
|
||||
LinphoneFriendListSyncStarted,
|
||||
LinphoneFriendListSyncSuccessful,
|
||||
LinphoneFriendListSyncFailure
|
||||
} LinphoneFriendListSyncStatus;
|
||||
|
||||
/**
|
||||
* The LinphoneFriendList object representing a list of friends.
|
||||
**/
|
||||
typedef struct _LinphoneFriendList LinphoneFriendList;
|
||||
|
||||
/**
|
||||
* Create a new empty LinphoneFriendList object.
|
||||
* @param[in] lc LinphoneCore object.
|
||||
* @return A new LinphoneFriendList object.
|
||||
**/
|
||||
LINPHONE_PUBLIC LinphoneFriendList * linphone_core_create_friend_list(LinphoneCore *lc);
|
||||
|
||||
/**
|
||||
* Add a friend list.
|
||||
* @param[in] lc LinphoneCore object
|
||||
* @param[in] list LinphoneFriendList object
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_core_add_friend_list(LinphoneCore *lc, LinphoneFriendList *list);
|
||||
|
||||
/**
|
||||
* Removes a friend list.
|
||||
* @param[in] lc LinphoneCore object
|
||||
* @param[in] list LinphoneFriendList object
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_core_remove_friend_list(LinphoneCore *lc, LinphoneFriendList *list);
|
||||
|
||||
/**
|
||||
* Retrieves the list of LinphoneFriendList from the core.
|
||||
* @param[in] lc LinphoneCore object
|
||||
* @return \mslist{LinphoneFriendList} a list of LinphoneFriendList
|
||||
*/
|
||||
LINPHONE_PUBLIC const MSList * linphone_core_get_friends_lists(const LinphoneCore *lc);
|
||||
|
||||
/**
|
||||
* Retrieves the first list of LinphoneFriend from the core.
|
||||
* @param[in] lc LinphoneCore object
|
||||
* @return the first LinphoneFriendList object or NULL
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneFriendList * linphone_core_get_default_friend_list(const LinphoneCore *lc);
|
||||
|
||||
/**
|
||||
* Acquire a reference to the friend list.
|
||||
* @param[in] list LinphoneFriendList object.
|
||||
* @return The same LinphoneFriendList object.
|
||||
**/
|
||||
LINPHONE_PUBLIC LinphoneFriendList * linphone_friend_list_ref(LinphoneFriendList *list);
|
||||
|
||||
/**
|
||||
* Release reference to the friend list.
|
||||
* @param[in] list LinphoneFriendList object.
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_friend_list_unref(LinphoneFriendList *list);
|
||||
|
||||
/**
|
||||
* Retrieve the user pointer associated with the friend list.
|
||||
* @param[in] list LinphoneFriendList object.
|
||||
* @return The user pointer associated with the friend list.
|
||||
**/
|
||||
LINPHONE_PUBLIC void * linphone_friend_list_get_user_data(const LinphoneFriendList *list);
|
||||
|
||||
/**
|
||||
* Assign a user pointer to the friend list.
|
||||
* @param[in] list LinphoneFriendList object.
|
||||
* @param[in] ud The user pointer to associate with the friend list.
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_friend_list_set_user_data(LinphoneFriendList *list, void *ud);
|
||||
|
||||
/**
|
||||
* Get the display name of the friend list.
|
||||
* @param[in] list LinphoneFriendList object.
|
||||
* @return The display name of the friend list.
|
||||
**/
|
||||
LINPHONE_PUBLIC const char * linphone_friend_list_get_display_name(const LinphoneFriendList *list);
|
||||
|
||||
/**
|
||||
* Set the display name of the friend list.
|
||||
* @param[in] list LinphoneFriendList object.
|
||||
* @param[in] display_name The new display name of the friend list.
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_friend_list_set_display_name(LinphoneFriendList *list, const char *display_name);
|
||||
|
||||
/**
|
||||
* Get the RLS (Resource List Server) URI associated with the friend list to subscribe to these friends presence.
|
||||
* @param[in] list LinphoneFriendList object.
|
||||
* @return The RLS URI associated with the friend list.
|
||||
**/
|
||||
LINPHONE_PUBLIC const char * linphone_friend_list_get_rls_uri(const LinphoneFriendList *list);
|
||||
|
||||
/**
|
||||
* Set the RLS (Resource List Server) URI associated with the friend list to subscribe to these friends presence.
|
||||
* @param[in] list LinphoneFriendList object.
|
||||
* @param[in] rls_uri The RLS URI to associate with the friend list.
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_friend_list_set_rls_uri(LinphoneFriendList *list, const char *rls_uri);
|
||||
|
||||
/**
|
||||
* Add a friend to a friend list. If or when a remote CardDAV server will be attached to the list, the friend will be sent to the server.
|
||||
* @param[in] list LinphoneFriendList object.
|
||||
* @param[in] friend LinphoneFriend object to add to the friend list.
|
||||
* @return LinphoneFriendListOK if successfully added, LinphoneFriendListInvalidFriend if the friend is not valid.
|
||||
**/
|
||||
LINPHONE_PUBLIC LinphoneFriendListStatus linphone_friend_list_add_friend(LinphoneFriendList *list, LinphoneFriend *lf);
|
||||
|
||||
/**
|
||||
* Add a friend to a friend list. The friend will never be sent to a remote CardDAV server.
|
||||
* Warning! LinphoneFriends added this way will be removed on the next synchronization, and the callback contact_deleted will be called.
|
||||
* @param[in] list LinphoneFriendList object.
|
||||
* @param[in] friend LinphoneFriend object to add to the friend list.
|
||||
* @return LinphoneFriendListOK if successfully added, LinphoneFriendListInvalidFriend if the friend is not valid.
|
||||
**/
|
||||
LINPHONE_PUBLIC LinphoneFriendListStatus linphone_friend_list_add_local_friend(LinphoneFriendList *list, LinphoneFriend *lf);
|
||||
|
||||
/**
|
||||
* Remove a friend from a friend list.
|
||||
* @param[in] list LinphoneFriendList object.
|
||||
* @param[in] friend LinphoneFriend object to remove from the friend list.
|
||||
* @return LinphoneFriendListOK if removed successfully, LinphoneFriendListNonExistentFriend if the friend is not in the list.
|
||||
**/
|
||||
LINPHONE_PUBLIC LinphoneFriendListStatus linphone_friend_list_remove_friend(LinphoneFriendList *list, LinphoneFriend *afriend);
|
||||
|
||||
/**
|
||||
* Retrieves the list of LinphoneFriend from this LinphoneFriendList.
|
||||
* @param[in] list LinphoneFriendList object
|
||||
* @return \mslist{LinphoneFriend} a list of LinphoneFriend
|
||||
*/
|
||||
LINPHONE_PUBLIC const MSList * linphone_friend_list_get_friends(const LinphoneFriendList *list);
|
||||
|
||||
/**
|
||||
* Find a friend in the friend list using a LinphoneAddress.
|
||||
* @param[in] list LinphoneFriendList object.
|
||||
* @param[in] address LinphoneAddress object of the friend we want to search for.
|
||||
* @return A LinphoneFriend if found, NULL otherwise.
|
||||
**/
|
||||
LINPHONE_PUBLIC LinphoneFriend * linphone_friend_list_find_friend_by_address(const LinphoneFriendList *list, const LinphoneAddress *address);
|
||||
|
||||
/**
|
||||
* Find a friend in the friend list using an URI string.
|
||||
* @param[in] list LinphoneFriendList object.
|
||||
* @param[in] uri A string containing the URI of the friend we want to search for.
|
||||
* @return A LinphoneFriend if found, NULL otherwise.
|
||||
**/
|
||||
LINPHONE_PUBLIC LinphoneFriend * linphone_friend_list_find_friend_by_uri(const LinphoneFriendList *list, const char *uri);
|
||||
|
||||
/**
|
||||
* Find a frient in the friend list using a ref key.
|
||||
* @param[in] list LinphoneFriendList object.
|
||||
* @param[in] ref_key The ref key string of the friend we want to search for.
|
||||
* @return A LinphoneFriend if found, NULL otherwise.
|
||||
**/
|
||||
LINPHONE_PUBLIC LinphoneFriend * linphone_friend_list_find_friend_by_ref_key(const LinphoneFriendList *list, const char *ref_key);
|
||||
|
||||
LINPHONE_PUBLIC void linphone_friend_list_close_subscriptions(LinphoneFriendList *list);
|
||||
|
||||
LINPHONE_PUBLIC void linphone_friend_list_update_subscriptions(LinphoneFriendList *list, LinphoneProxyConfig *cfg, bool_t only_when_registered);
|
||||
|
||||
/**
|
||||
* Notify our presence to all the friends in the friend list that have subscribed to our presence directly (not using a RLS).
|
||||
* @param[in] list LinphoneFriendList object.
|
||||
* @param[in] presence LinphonePresenceModel object.
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_friend_list_notify_presence(LinphoneFriendList *list, LinphonePresenceModel *presence);
|
||||
|
||||
/**
|
||||
* Get the URI associated with the friend list.
|
||||
* @param[in] list LinphoneFriendList object.
|
||||
* @return The URI associated with the friend list.
|
||||
**/
|
||||
LINPHONE_PUBLIC const char * linphone_friend_list_get_uri(const LinphoneFriendList *list);
|
||||
|
||||
/**
|
||||
* Set the URI associated with the friend list.
|
||||
* @param[in] list LinphoneFriendList object.
|
||||
* @param[in] rls_uri The URI to associate with the friend list.
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_friend_list_set_uri(LinphoneFriendList *list, const char *uri);
|
||||
|
||||
/**
|
||||
* Sets the revision from the last synchronization.
|
||||
* @param[in] list LinphoneFriendList object.
|
||||
* @param[in] rev The revision
|
||||
*/
|
||||
void linphone_friend_list_update_revision(LinphoneFriendList *list, int rev);
|
||||
|
||||
/**
|
||||
* An object to handle the callbacks for LinphoneFriend synchronization.
|
||||
**/
|
||||
typedef struct _LinphoneFriendListCbs LinphoneFriendListCbs;
|
||||
|
||||
/**
|
||||
* Callback used to notify a new contact has been created on the CardDAV server and downloaded locally
|
||||
* @param list The LinphoneFriendList object the new contact is added to
|
||||
* @param lf The LinphoneFriend object that has been created
|
||||
**/
|
||||
typedef void (*LinphoneFriendListCbsContactCreatedCb)(LinphoneFriendList *list, LinphoneFriend *lf);
|
||||
|
||||
/**
|
||||
* Callback used to notify a contact has been deleted on the CardDAV server
|
||||
* @param list The LinphoneFriendList object a contact has been removed from
|
||||
* @param lf The LinphoneFriend object that has been deleted
|
||||
**/
|
||||
typedef void (*LinphoneFriendListCbsContactDeletedCb)(LinphoneFriendList *list, LinphoneFriend *lf);
|
||||
|
||||
/**
|
||||
* Callback used to notify a contact has been updated on the CardDAV server
|
||||
* @param list The LinphoneFriendList object in which a contact has been updated
|
||||
* @param new_friend The new LinphoneFriend object corresponding to the updated contact
|
||||
* @param old_friend The old LinphoneFriend object before update
|
||||
**/
|
||||
typedef void (*LinphoneFriendListCbsContactUpdatedCb)(LinphoneFriendList *list, LinphoneFriend *new_friend, LinphoneFriend *old_friend);
|
||||
|
||||
/**
|
||||
* Callback used to notify the status of the synchronization has changed
|
||||
* @param list The LinphoneFriendList object for which the status has changed
|
||||
* @param status The new synchronisation status
|
||||
* @param msg An additional information on the status update
|
||||
**/
|
||||
typedef void (*LinphoneFriendListCbsSyncStateChangedCb)(LinphoneFriendList *list, LinphoneFriendListSyncStatus status, const char *msg);
|
||||
|
||||
/**
|
||||
* Get the LinphoneFriendListCbs object associated with a LinphoneFriendList.
|
||||
* @param[in] request LinphoneXmlRpcRequest object
|
||||
* @return The LinphoneFriendListCbs object associated with the LinphoneFriendList.
|
||||
**/
|
||||
LINPHONE_PUBLIC LinphoneFriendListCbs * linphone_friend_list_get_callbacks(const LinphoneFriendList *list);
|
||||
|
||||
/**
|
||||
* Acquire a reference to a LinphoneFriendListCbs object.
|
||||
* @param[in] cbs LinphoneFriendListCbs object.
|
||||
* @return The same LinphoneFriendListCbs object.
|
||||
**/
|
||||
LINPHONE_PUBLIC LinphoneFriendListCbs * linphone_friend_list_cbs_ref(LinphoneFriendListCbs *cbs);
|
||||
|
||||
/**
|
||||
* Release a reference to a LinphoneFriendListCbs object.
|
||||
* @param[in] cbs LinphoneFriendListCbs object.
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_friend_list_cbs_unref(LinphoneFriendListCbs *cbs);
|
||||
|
||||
/**
|
||||
* Retrieve the user pointer associated with a LinphoneFriendListCbs object.
|
||||
* @param[in] cbs LinphoneFriendListCbs object.
|
||||
* @return The user pointer associated with the LinphoneFriendListCbs object.
|
||||
**/
|
||||
LINPHONE_PUBLIC void *linphone_friend_list_cbs_get_user_data(const LinphoneFriendListCbs *cbs);
|
||||
|
||||
/**
|
||||
* Assign a user pointer to a LinphoneFriendListCbs object.
|
||||
* @param[in] cbs LinphoneFriendListCbs object.
|
||||
* @param[in] ud The user pointer to associate with the LinphoneFriendListCbs object.
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_friend_list_cbs_set_user_data(LinphoneFriendListCbs *cbs, void *ud);
|
||||
|
||||
/**
|
||||
* Get the contact created callback.
|
||||
* @param[in] cbs LinphoneFriendListCbs object.
|
||||
* @return The current contact created callback.
|
||||
**/
|
||||
LINPHONE_PUBLIC LinphoneFriendListCbsContactCreatedCb linphone_friend_list_cbs_get_contact_created(const LinphoneFriendListCbs *cbs);
|
||||
|
||||
/**
|
||||
* Set the contact created callback.
|
||||
* @param[in] cbs LinphoneFriendListCbs object.
|
||||
* @param[in] cb The contact created to be used.
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_friend_list_cbs_set_contact_created(LinphoneFriendListCbs *cbs, LinphoneFriendListCbsContactCreatedCb cb);
|
||||
|
||||
/**
|
||||
* Get the contact deleted callback.
|
||||
* @param[in] cbs LinphoneFriendListCbs object.
|
||||
* @return The current contact deleted callback.
|
||||
**/
|
||||
LINPHONE_PUBLIC LinphoneFriendListCbsContactDeletedCb linphone_friend_list_cbs_get_contact_deleted(const LinphoneFriendListCbs *cbs);
|
||||
|
||||
/**
|
||||
* Set the contact deleted callback.
|
||||
* @param[in] cbs LinphoneFriendListCbs object.
|
||||
* @param[in] cb The contact deleted to be used.
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_friend_list_cbs_set_contact_deleted(LinphoneFriendListCbs *cbs, LinphoneFriendListCbsContactDeletedCb cb);
|
||||
|
||||
/**
|
||||
* Get the contact updated callback.
|
||||
* @param[in] cbs LinphoneFriendListCbs object.
|
||||
* @return The current contact updated callback.
|
||||
**/
|
||||
LINPHONE_PUBLIC LinphoneFriendListCbsContactUpdatedCb linphone_friend_list_cbs_get_contact_updated(const LinphoneFriendListCbs *cbs);
|
||||
|
||||
/**
|
||||
* Set the contact updated callback.
|
||||
* @param[in] cbs LinphoneFriendListCbs object.
|
||||
* @param[in] cb The contact updated to be used.
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_friend_list_cbs_set_contact_updated(LinphoneFriendListCbs *cbs, LinphoneFriendListCbsContactUpdatedCb cb);
|
||||
|
||||
/**
|
||||
* Get the sync status changed callback.
|
||||
* @param[in] cbs LinphoneFriendListCbs object.
|
||||
* @return The current sync status changedcallback.
|
||||
**/
|
||||
LINPHONE_PUBLIC LinphoneFriendListCbsSyncStateChangedCb linphone_friend_list_cbs_get_sync_status_changed(const LinphoneFriendListCbs *cbs);
|
||||
|
||||
/**
|
||||
* Set the contact updated callback.
|
||||
* @param[in] cbs LinphoneFriendListCbs object.
|
||||
* @param[in] cb The sync status changed to be used.
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_friend_list_cbs_set_sync_status_changed(LinphoneFriendListCbs *cbs, LinphoneFriendListCbsSyncStateChangedCb cb);
|
||||
|
||||
/**
|
||||
* Starts a CardDAV synchronization using value set using linphone_friend_list_set_uri.
|
||||
* @param[in] list LinphoneFriendList object.
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_friend_list_synchronize_friends_from_server(LinphoneFriendList *list);
|
||||
|
||||
/**
|
||||
* Goes through all the LinphoneFriend that are dirty and does a CardDAV PUT to update the server.
|
||||
* @param[in] list LinphoneFriendList object.
|
||||
*/
|
||||
void linphone_friend_list_update_dirty_friends(LinphoneFriendList *list);
|
||||
|
||||
/**
|
||||
* Returns the LinphoneCore object attached to this LinphoneFriendList.
|
||||
* @param[in] list LinphoneFriendList object.
|
||||
* @return a LinphoneCore object
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneCore* linphone_friend_list_get_core(LinphoneFriendList *list);
|
||||
|
||||
/**
|
||||
* Creates and adds LinphoneFriend objects to LinphoneFriendList from a file that contains the vCard(s) to parse
|
||||
* @param[in] list the LinphoneFriendList object
|
||||
* @param[in] vcard_file the path to a file that contains the vCard(s) to parse
|
||||
* @return the amount of linphone friends created
|
||||
*/
|
||||
LINPHONE_PUBLIC int linphone_friend_list_import_friends_from_vcard4_file(LinphoneFriendList *list, const char *vcard_file);
|
||||
|
||||
/**
|
||||
* Creates and adds LinphoneFriend objects to LinphoneFriendList from a buffer that contains the vCard(s) to parse
|
||||
* @param[in] list the LinphoneFriendList object
|
||||
* @param[in] vcard_buffer the buffer that contains the vCard(s) to parse
|
||||
* @return the amount of linphone friends created
|
||||
*/
|
||||
LINPHONE_PUBLIC int linphone_friend_list_import_friends_from_vcard4_buffer(LinphoneFriendList *list, const char *vcard_buffer);
|
||||
|
||||
/**
|
||||
* Creates and export LinphoneFriend objects from LinphoneFriendList to a file using vCard 4 format
|
||||
* @param[in] list the LinphoneFriendList object
|
||||
* @param[in] vcard_file the path to a file that will contain the vCards
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_friend_list_export_friends_as_vcard4_file(LinphoneFriendList *list, const char *vcard_file);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LINPHONE_FRIENDLIST_H_ */
|
||||
|
|
@ -21,14 +21,32 @@
|
|||
############################################################################
|
||||
|
||||
if(GIT_EXECUTABLE)
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXECUTABLE} describe --always
|
||||
WORKING_DIRECTORY ${WORK_DIR}
|
||||
OUTPUT_VARIABLE GIT_REVISION
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
else()
|
||||
set(GIT_REVISION "unknown")
|
||||
macro(GIT_COMMAND OUTPUT_VAR)
|
||||
set(GIT_ARGS ${ARGN})
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXECUTABLE} ${ARGN}
|
||||
WORKING_DIRECTORY ${WORK_DIR}
|
||||
OUTPUT_VARIABLE ${OUTPUT_VAR}
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
endmacro()
|
||||
|
||||
GIT_COMMAND(GIT_DESCRIBE describe --always)
|
||||
GIT_COMMAND(GIT_TAG describe --abbrev=0)
|
||||
GIT_COMMAND(GIT_REVISION rev-parse HEAD)
|
||||
endif()
|
||||
|
||||
configure_file("${WORK_DIR}/gitversion.h.in" "${OUTPUT_DIR}/liblinphone_gitversion.h" @ONLY)
|
||||
if(GIT_DESCRIBE)
|
||||
if(NOT GIT_TAG STREQUAL LINPHONE_VERSION)
|
||||
message(FATAL_ERROR "LINPHONE_VERSION and git tag differ. Please put them identical")
|
||||
endif()
|
||||
set(LIBLINPHONE_GIT_VERSION "${GIT_DESCRIBE}")
|
||||
configure_file("${WORK_DIR}/gitversion.h.in" "${OUTPUT_DIR}/liblinphone_gitversion.h" @ONLY)
|
||||
elseif(GIT_REVISION)
|
||||
set(LIBLINPHONE_GIT_VERSION "${LINPHONE_VERSION}_${GIT_REVISION}")
|
||||
configure_file("${WORK_DIR}/gitversion.h.in" "${OUTPUT_DIR}/liblinphone_gitversion.h" @ONLY)
|
||||
else()
|
||||
if(NOT EXISTS "${OUTPUT_DIR}/liblinphone_gitversion.h")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E touch "${OUTPUT_DIR}/liblinphone_gitversion.h")
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -18,4 +18,4 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
*/
|
||||
|
||||
|
||||
#define LIBLINPHONE_GIT_VERSION "@GIT_REVISION@"
|
||||
#define LIBLINPHONE_GIT_VERSION "@LIBLINPHONE_GIT_VERSION@"
|
||||
|
|
@ -38,7 +38,7 @@ if(DOXYGEN_FOUND)
|
|||
)
|
||||
add_custom_target(linphone-doc ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/doc/html/index.html")
|
||||
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/doc/html" "${CMAKE_CURRENT_BINARY_DIR}/doc/xml"
|
||||
DESTINATION "share/doc/linphone-${LINPHONE_VERSION}")
|
||||
DESTINATION "${CMAKE_INSTALL_DATADIR}/doc/linphone-${LINPHONE_VERSION}")
|
||||
else()
|
||||
message(WARNING "The dot program is needed to generate the linphone documentation. You can get it from http://www.graphviz.org/.")
|
||||
endif()
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -156,7 +156,7 @@ int main(int argc, char *argv[]){
|
|||
}
|
||||
|
||||
if (dest_friend) {
|
||||
my_friend = linphone_friend_new_with_address(dest_friend); /*creates friend object from dest*/
|
||||
my_friend = linphone_core_create_friend_with_address(lc, dest_friend); /*creates friend object from dest*/
|
||||
if (my_friend == NULL) {
|
||||
printf("bad destination uri for friend [%s]\n",dest_friend);
|
||||
goto end;
|
||||
|
|
|
|||
|
|
@ -16,16 +16,16 @@
|
|||
*
|
||||
* Liblinphone is GPL (see COPYING file). Please understand the licencing details
|
||||
* before using it!
|
||||
*
|
||||
*
|
||||
* For any use of this library beyond the rights granted to you by the
|
||||
* GPL license, please contact Belledonne Communications
|
||||
* GPL license, please contact Belledonne Communications
|
||||
* (contact@belledonne-communications.com)
|
||||
*
|
||||
*
|
||||
*
|
||||
**/
|
||||
|
||||
/**
|
||||
* @page liblinphone_license COPYING
|
||||
* @page liblinphone_license COPYING
|
||||
* @include COPYING
|
||||
*/
|
||||
|
||||
|
|
@ -54,7 +54,7 @@
|
|||
/**
|
||||
* @defgroup media_parameters Controlling media parameters
|
||||
*<b> Multicast </b>
|
||||
*<br> Call using rtp multicast addresses are supported for both audio and video with some limitations. Limitations are, no stun, no ice, no encryption.
|
||||
*<br> Call using rtp multicast addresses are supported for both audio and video with some limitations. Limitations are, no stun, no ice, no encryption.
|
||||
*<br><li> Incoming call with multicast address are automatically accepted. The called party switches in a media receive only mode.
|
||||
*<br><li> Outgoing call willing to send media to a multicast address can activate multicast using \link linphone_core_enable_video_multicast\endlink or
|
||||
*\link linphone_core_enable_audio_multicast\endlink . The calling party switches in a media listen send only mode.
|
||||
|
|
@ -62,15 +62,15 @@
|
|||
|
||||
/**
|
||||
* @defgroup proxies Managing proxies
|
||||
*User registration is controled by #LinphoneProxyConfig settings.<br> Each #LinphoneProxyConfig object can be configured with registration informations
|
||||
*like \link linphone_proxy_config_set_server_addr() proxy address \endlink , \link linphone_proxy_config_set_identity() user id \endlink, \link linphone_proxy_config_expires() refresh period \endlink, and so on.
|
||||
*User registration is controled by #LinphoneProxyConfig settings.<br> Each #LinphoneProxyConfig object can be configured with registration informations
|
||||
*like \link linphone_proxy_config_set_server_addr() proxy address \endlink , \link linphone_proxy_config_set_identity() user id \endlink, \link linphone_proxy_config_expires() refresh period \endlink, and so on.
|
||||
*<br> A created proxy config using linphone_proxy_config_new(), once configured, must be added to #LinphoneCore using function linphone_core_add_proxy_config().
|
||||
*<br> It is recommended to set a default \link #LinphoneProxyConfig proxy config \endlink using function linphone_core_set_default_proxy(). Once done, if \link #LinphoneProxyConfig a proxy config \endlink has been configured with attribute \link linphone_proxy_config_enable_register() enable register \endlink , next call to linphone_core_iterate() triggers a SIP register.
|
||||
*<br> It is recommended to set a default \link #LinphoneProxyConfig proxy config \endlink using function linphone_core_set_default_proxy(). Once done, if \link #LinphoneProxyConfig a proxy config \endlink has been configured with attribute \link linphone_proxy_config_enable_register() enable register \endlink , next call to linphone_core_iterate() triggers a SIP register.
|
||||
*<br> Registration status is reported by LinphoneCoreRegistrationStateChangedCb.
|
||||
*<br>
|
||||
*<br> This pseudo code demonstrates basic registration operations:
|
||||
*<br> \code
|
||||
*
|
||||
*
|
||||
* LinphoneProxyConfig* proxy_cfg;
|
||||
* /*create proxy config*/
|
||||
* proxy_cfg = linphone_proxy_config_new();
|
||||
|
|
@ -80,14 +80,14 @@
|
|||
* if (password!=NULL){
|
||||
* info=linphone_auth_info_new(linphone_address_get_username(from),NULL,"secret",NULL,NULL); /*create authentication structure from identity*/
|
||||
* linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/
|
||||
* }
|
||||
* }
|
||||
* // configure proxy entries
|
||||
* linphone_proxy_config_set_identity(proxy_cfg,identity); /*set identity with user name and domain*/
|
||||
* const char* server_addr = linphone_address_get_domain(from); /*extract domain address from identity*/
|
||||
* linphone_proxy_config_set_server_addr(proxy_cfg,server_addr); /* we assume domain = proxy server address*/
|
||||
* linphone_proxy_config_enable_register(proxy_cfg,TRUE); /*activate registration for this proxy config*/
|
||||
* linphone_address_destroy(from); /*release resource*/
|
||||
*
|
||||
*
|
||||
* linphone_core_add_proxy_config(lc,proxy_cfg); /*add proxy config to linphone core*/
|
||||
* linphone_core_set_default_proxy(lc,proxy_cfg); /*set to default proxy*/ \endcode
|
||||
*<br>
|
||||
|
|
@ -114,7 +114,7 @@
|
|||
linphone_proxy_config_done(proxy_cfg); /*initiate REGISTER with expire = 0*/
|
||||
\endcode
|
||||
<br>
|
||||
A complete tutorial can be found at : \ref registration_tutorials "Registration tutorial"
|
||||
A complete tutorial can be found at : \ref registration_tutorials "Registration tutorial"
|
||||
**/
|
||||
|
||||
/**
|
||||
|
|
@ -126,9 +126,9 @@
|
|||
**/
|
||||
|
||||
/**
|
||||
* @defgroup buddy_list Managing Buddies and buddy list and presence
|
||||
* @defgroup buddy_list Managing Buddies and buddy list and presence
|
||||
<b>Buddies and buddy list</b>
|
||||
<br>Each buddy is represented by a #LinphoneFriend object created by function linphone_friend_new().
|
||||
<br>Each buddy is represented by a #LinphoneFriend object created by function linphone_friend_new().
|
||||
Buddy configuration parameters like \link linphone_friend_set_addr() sip uri \endlink or \link linphone_friend_set_inc_subscribe_policy() status publication \endlink policy for this \link #LinphoneFriend friend \endlink are configurable for each buddy.
|
||||
<br>Here under a typical buddy creation:
|
||||
<br>
|
||||
|
|
@ -163,13 +163,13 @@ linphone_friend_done(my_friend); /*commit changes triggering an UNSUBSCRIBE mess
|
|||
<br> New incoming subscription requests are process according to \link linphone_friend_set_inc_subscribe_policy() the incoming subscription policy state \endlink for subscription initiated by \link linphone_core_add_friend() members of the buddy list. \endlink
|
||||
<br> For incoming request comming from an unknown buddy, the call back LinphoneCoreVTable.new_subscription_request is invoked.
|
||||
|
||||
<br> A complete tutorial can be found at : \ref buddy_tutorials "Registration tutorial"
|
||||
<br> A complete tutorial can be found at : \ref buddy_tutorials "Registration tutorial"
|
||||
|
||||
|
||||
**/
|
||||
|
||||
/**
|
||||
* @defgroup chatroom Chat room and Messaging
|
||||
* @defgroup chatroom Chat room and Messaging
|
||||
<b> Exchanging text messages</b>
|
||||
<br> Messages are sent using #LinphoneChatRoom object. First step is to create a \link linphone_core_create_chat_room() chat room \endlink
|
||||
from a peer sip uri.
|
||||
|
|
@ -177,7 +177,7 @@ from a peer sip uri.
|
|||
LinphoneChatRoom* chat_room = linphone_core_create_chat_room(lc,"sip:joe@sip.linphone.org");
|
||||
\endcode
|
||||
|
||||
<br>Once created, messages are sent using function linphone_chat_room_send_message() .
|
||||
<br>Once created, messages are sent using function linphone_chat_room_send_message() .
|
||||
\code
|
||||
linphone_chat_room_send_message(chat_room,"Hello world"); /*sending message*/
|
||||
\endcode
|
||||
|
|
@ -187,7 +187,7 @@ void text_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddre
|
|||
printf(" Message [%s] received from [%s] \n",message,linphone_address_as_string (from));
|
||||
}
|
||||
\endcode
|
||||
<br> A complete tutorial can be found at : \ref chatroom_tuto "Chat room tutorial"
|
||||
<br> A complete tutorial can be found at : \ref chatroom_tuto "Chat room tutorial"
|
||||
**/
|
||||
|
||||
/**
|
||||
|
|
@ -204,21 +204,21 @@ void text_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddre
|
|||
* @defgroup conferencing Making an audio conference.
|
||||
* This API allows to create a conference entirely managed by the client. No server capabilities are required.
|
||||
* The way such conference is created is by doing the following:<br>
|
||||
* The application shall makes "normal" calls to several destinations (using linphone_core_invite() ), one after another.
|
||||
* The application shall makes "normal" calls to several destinations (using linphone_core_invite() ), one after another.
|
||||
* While initiating the second call, the first one is automatically paused.
|
||||
* Then, once the second call is established, the application has the possibility to merge the two calls to form a conference where each participant
|
||||
* (the local participant, the remote destination of the first call, the remote destination of the second call) can talk together.
|
||||
* This must be done by adding the two calls to the conference using \link linphone_core_add_to_conference() \endlink
|
||||
*
|
||||
* Once merged into a conference the LinphoneCall objects representing the calls that were established remain unchanged, except that
|
||||
* Once merged into a conference the LinphoneCall objects representing the calls that were established remain unchanged, except that
|
||||
* they are tagged as part of the conference (see \link linphone_call_is_in_conference() \endlink ). The calls in a conference are in the LinphoneCallStreamsRunning state.
|
||||
*
|
||||
* Only a single conference can be created: the purpose of this feature is to allow the local user to create, take part and manage the conference.
|
||||
*
|
||||
* Only a single conference can be created: the purpose of this feature is to allow the local user to create, take part and manage the conference.
|
||||
* This API is not designed to create a conference server application.
|
||||
*
|
||||
* Up to 10 calls can be merged into the conference, however depending on the CPU usage required for doing the encoding/decoding of the streams of each participants,
|
||||
* the effective limit can be lower.
|
||||
*
|
||||
*
|
||||
**/
|
||||
|
||||
|
||||
|
|
@ -232,12 +232,12 @@ void text_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddre
|
|||
**/
|
||||
|
||||
/**
|
||||
* @defgroup tutorials Tutorials:
|
||||
* @defgroup tutorials Tutorials:
|
||||
*
|
||||
**/
|
||||
|
||||
/**
|
||||
* @defgroup port Portability:
|
||||
* @defgroup port Portability:
|
||||
*
|
||||
**/
|
||||
/**
|
||||
|
|
@ -257,8 +257,8 @@ void text_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddre
|
|||
<br>
|
||||
<ul>
|
||||
<li><b>SIP socket </b><br>Recommended mode is SIP over TCP, because UDP usually requires frequent keep alives for maintaining NAT association at the IP router level. This can be as frequent as one UDP packet every 15 seconds to maintain the NAT association accross NAT routers. Doing such drains the battery very fast, and furthermore the iOS keep-alive designed by Apple to handle this task can only be called with a minimum of 10 minutes interval.<br>
|
||||
For TCP, liblinphone automatically configures SIP socket for voip (I.E kCFStreamNetworkServiceType set to kCFStreamNetworkServiceTypeVoIP).
|
||||
<br><b>Since IOS > 4.1 Apple disabled voip mode for UDP sockets </b>
|
||||
For TCP, liblinphone automatically configures SIP socket for voip (I.E kCFStreamNetworkServiceType set to kCFStreamNetworkServiceTypeVoIP).
|
||||
<br><b>Since IOS > 4.1 Apple disabled voip mode for UDP sockets </b>
|
||||
<li><b>Entering background mode</b>
|
||||
<br> Before entering in background mode (through \code - (void)applicationDidEnterBackground:(UIApplication *)application \endcode ), the application must first refresh sip registration using function #linphone_core_refresh_registers();
|
||||
and register a keep-alive handler for periodically refreshing the registration. The speudo code below shows how to register a keep alive handler:
|
||||
|
|
@ -272,7 +272,7 @@ and register a keep-alive handler for periodically refreshing the registration.
|
|||
usleep(100000);
|
||||
}
|
||||
//register keepalive handler
|
||||
[[UIApplication sharedApplication] setKeepAliveTimeout:600/*minimal interval is 600 s*/
|
||||
[[UIApplication sharedApplication] setKeepAliveTimeout:600/*minimal interval is 600 s*/
|
||||
handler:^{
|
||||
//refresh sip registration
|
||||
linphone_core_refresh_registers(theLinphoneCore);
|
||||
|
|
@ -291,7 +291,7 @@ and register a keep-alive handler for periodically refreshing the registration.
|
|||
notif.alertBody =@"New incoming call";
|
||||
notif.alertAction = @"Answer";
|
||||
notif.soundName = @"oldphone-mono-30s.caf";
|
||||
|
||||
|
||||
[[UIApplication sharedApplication] presentLocalNotificationNow:notif];
|
||||
}
|
||||
\endcode
|
||||
|
|
@ -312,8 +312,8 @@ and register a keep-alive handler for periodically refreshing the registration.
|
|||
//try to write on this socket
|
||||
CFWriteStreamWrite (writeStream,(const UInt8*)buff,strlen(buff));
|
||||
CFWriteStreamClose (writeStream);
|
||||
}
|
||||
\endcode
|
||||
}
|
||||
\endcode
|
||||
It is recommanded to perform this task each time the application is woken up, including keep alive handler.
|
||||
<li><b>Managing IP connection state</b>
|
||||
<br>Liblinphone for IOS relies on the application to be informed of network connectivity changes. Network state changes when the IP connection moves from DOWN to UP, or from WIFI to WWAN. Applications using liblinphone must inform libliblinphone of this changes using function #linphone_core_set_network_reachable(). Usually this method is called from the IOS NetworkReachability callback. Here under a sample code:
|
||||
|
|
@ -339,8 +339,8 @@ void networkReachabilityCallBack(SCNetworkReachabilityRef target, SCNetworkReach
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
\endcode
|
||||
|
||||
\endcode
|
||||
</ul>
|
||||
<b> Sound cards </b>
|
||||
<br> Since IOS 5.0, liblinphone supports 2 sound cards. <i>AU: Audio Unit Receiver</i> based on IO units for voice calls plus <i>AQ: Audio Queue Device</i> dedicated to rings. Here under the recommended settings (I.E default one)
|
||||
|
|
@ -366,7 +366,7 @@ void networkReachabilityCallBack(SCNetworkReachabilityRef target, SCNetworkReach
|
|||
-(void) endInterruption {
|
||||
ms_message("Sound interruption ended!");
|
||||
const MSList* c = linphone_core_get_calls(theLinphoneCore);
|
||||
|
||||
|
||||
if (c) {
|
||||
ms_message("Auto resuming call");
|
||||
linphone_core_resume_call(theLinphoneCore, (LinphoneCall*) c->data);
|
||||
|
|
@ -387,7 +387,7 @@ void networkReachabilityCallBack(SCNetworkReachabilityRef target, SCNetworkReach
|
|||
\code
|
||||
UIView* display = [[UIView alloc] init];
|
||||
UIView* preview = [[UIView alloc] init];
|
||||
linphone_core_set_native_video_window_id(lc,(unsigned long)display);
|
||||
linphone_core_set_native_video_window_id(lc,(unsigned long)display);
|
||||
linphone_core_set_native_preview_window_id(lc,(unsigned long)preview);
|
||||
\endcode
|
||||
<br> Screen rotations are also handled by liblinphone. 2 positions are currently supported, namely <i>UIInterfaceOrientationPortrait</i> and <i>UIInterfaceOrientationLandscapeRight</i>. Applications may invoke #linphone_core_set_device_rotation() followed by #linphone_core_update_call() to notify liblinphone of an orientation change. Here under a speudo code to handle orientation changes
|
||||
|
|
@ -396,16 +396,16 @@ void networkReachabilityCallBack(SCNetworkReachabilityRef target, SCNetworkReach
|
|||
-(void) configureOrientation:(UIInterfaceOrientation) oritentation {
|
||||
int oldLinphoneOrientation = linphone_core_get_device_rotation(lc);
|
||||
if (oritentation == UIInterfaceOrientationPortrait ) {
|
||||
linphone_core_set_native_video_window_id(lc,(unsigned long)display-portrait);
|
||||
linphone_core_set_native_video_window_id(lc,(unsigned long)display-portrait);
|
||||
linphone_core_set_native_preview_window_id(lc,(unsigned long)preview-portrait);
|
||||
linphone_core_set_device_rotation(lc, 0);
|
||||
|
||||
|
||||
} else if (oritentation == UIInterfaceOrientationLandscapeRight ) {
|
||||
linphone_core_set_native_video_window_id(lc,(unsigned long)display-landscape);
|
||||
linphone_core_set_native_video_window_id(lc,(unsigned long)display-landscape);
|
||||
linphone_core_set_native_preview_window_id(lc,(unsigned long)preview-landscape);
|
||||
linphone_core_set_device_rotation(lc, 270);
|
||||
}
|
||||
|
||||
|
||||
if ((oldLinphoneOrientation != linphone_core_get_device_rotation(lc))
|
||||
&& linphone_core_get_current_call(lc)) {
|
||||
//Orientation has changed, must call update call
|
||||
|
|
@ -416,7 +416,49 @@ void networkReachabilityCallBack(SCNetworkReachabilityRef target, SCNetworkReach
|
|||
\endcode
|
||||
|
||||
<b>DTMF feebacks</b>
|
||||
<br>Liblinphone provides functions \link #linphone_core_play_dtmf() to play dtmf \endlink to the local user. Usually this is used to play a sound when the user presses a digit, inside or outside of any call. On IOS, libLinphone relies on AudioUnits for interfacing with the audio system. Unfortunately the Audio Unit initialization is a quite long operation that may trigger a bad user experience if performed each time a DTMF is played, the sound being delayed half a second after the press. To solve this issue and thus insure real-time precision, liblinphone introduces 2 functions for \link linphone_core_start_dtmf_stream() preloading \endlink and \link #linphone_core_start_dtmf_stream() unloading \endlink the underlying audio graph responsible for playing DTMFs.
|
||||
<br> For an application using function #linphone_core_play_dtmf(), it is recommanded to call #linphone_core_start_dtmf_stream() when entering in foreground and #linphone_core_stop_dtmf_stream() upon entering background mode.
|
||||
<br>Liblinphone provides functions \link #linphone_core_play_dtmf() to play dtmf \endlink to the local user. Usually this is used to play a sound when the user presses a digit, inside or outside of any call. On IOS, libLinphone relies on AudioUnits for interfacing with the audio system. Unfortunately the Audio Unit initialization is a quite long operation that may trigger a bad user experience if performed each time a DTMF is played, the sound being delayed half a second after the press. To solve this issue and thus insure real-time precision, liblinphone introduces 2 functions for \link linphone_core_start_dtmf_stream() preloading \endlink and \link #linphone_core_start_dtmf_stream() unloading \endlink the underlying audio graph responsible for playing DTMFs.
|
||||
<br> For an application using function #linphone_core_play_dtmf(), it is recommanded to call #linphone_core_start_dtmf_stream() when entering in foreground and #linphone_core_stop_dtmf_stream() upon entering background mode.
|
||||
|
||||
<b>Plugins</b>
|
||||
<br>On iOS, plugins are built as static libraries so Liblinphone will not be able to load them at runtime dynamically. Instead, you should declare their prototypes:
|
||||
|
||||
\code
|
||||
|
||||
extern void libmsamr_init(MSFactory *factory);
|
||||
extern void libmsx264_init(MSFactory *factory);
|
||||
extern void libmsopenh264_init(MSFactory *factory);
|
||||
extern void libmssilk_init(MSFactory *factory);
|
||||
extern void libmsbcg729_init(MSFactory *factory);
|
||||
extern void libmswebrtc_init(MSFactory *factory);
|
||||
|
||||
\endcode
|
||||
|
||||
Then you should register them after the instantiation of LinphoneCore:
|
||||
|
||||
\code
|
||||
|
||||
theLinphoneCore = linphone_core_new_with_config(/* options ... */);
|
||||
|
||||
// Load plugins if available in the linphone SDK - otherwise these calls will do nothing
|
||||
MSFactory *f = linphone_core_get_ms_factory(theLinphoneCore);
|
||||
libmssilk_init(f);
|
||||
libmsamr_init(f);
|
||||
libmsx264_init(f);
|
||||
libmsopenh264_init(f);
|
||||
libmsbcg729_init(f);
|
||||
libmswebrtc_init(f);
|
||||
linphone_core_reload_ms_plugins(theLinphoneCore, NULL);
|
||||
|
||||
\endcode
|
||||
|
||||
If the plugin has not been enabled at compilation time, a stubbed library will be generated with only libplugin_init method declared, doing nothing. You should see these trace in logs, if plugin is stubbed:
|
||||
|
||||
\code
|
||||
|
||||
I/lib/Could not find encoder for SILK
|
||||
I/lib/Could not find decoder for SILK
|
||||
|
||||
\endcode
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ import org.linphone.core.LinphoneCoreFactory;
|
|||
import org.linphone.core.LinphoneCoreListener;
|
||||
import org.linphone.core.LinphoneEvent;
|
||||
import org.linphone.core.LinphoneFriend;
|
||||
import org.linphone.core.LinphoneFriendList;
|
||||
import org.linphone.core.LinphoneFriend.SubscribePolicy;
|
||||
import org.linphone.core.LinphoneInfoMessage;
|
||||
import org.linphone.core.LinphoneProxyConfig;
|
||||
|
|
@ -335,4 +336,17 @@ public class TutorialBuddyStatus implements LinphoneCoreListener {
|
|||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void friendListCreated(LinphoneCore lc, LinphoneFriendList list) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void friendListRemoved(LinphoneCore lc, LinphoneFriendList list) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ import org.linphone.core.LinphoneCoreFactory;
|
|||
import org.linphone.core.LinphoneCoreListener;
|
||||
import org.linphone.core.LinphoneEvent;
|
||||
import org.linphone.core.LinphoneFriend;
|
||||
import org.linphone.core.LinphoneFriendList;
|
||||
import org.linphone.core.LinphoneInfoMessage;
|
||||
import org.linphone.core.LinphoneProxyConfig;
|
||||
import org.linphone.core.PublishState;
|
||||
|
|
@ -251,5 +252,17 @@ public class TutorialChatRoom implements LinphoneCoreListener, LinphoneChatMessa
|
|||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void friendListCreated(LinphoneCore lc, LinphoneFriendList list) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void friendListRemoved(LinphoneCore lc, LinphoneFriendList list) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ import org.linphone.core.LinphoneCoreFactory;
|
|||
import org.linphone.core.LinphoneCoreListener;
|
||||
import org.linphone.core.LinphoneEvent;
|
||||
import org.linphone.core.LinphoneFriend;
|
||||
import org.linphone.core.LinphoneFriendList;
|
||||
import org.linphone.core.LinphoneInfoMessage;
|
||||
import org.linphone.core.LinphoneProxyConfig;
|
||||
import org.linphone.core.PublishState;
|
||||
|
|
@ -257,5 +258,17 @@ public class TutorialHelloWorld implements LinphoneCoreListener {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void friendListCreated(LinphoneCore lc, LinphoneFriendList list) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void friendListRemoved(LinphoneCore lc, LinphoneFriendList list) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ import org.linphone.core.LinphoneCoreFactory;
|
|||
import org.linphone.core.LinphoneCoreListener;
|
||||
import org.linphone.core.LinphoneEvent;
|
||||
import org.linphone.core.LinphoneFriend;
|
||||
import org.linphone.core.LinphoneFriendList;
|
||||
import org.linphone.core.LinphoneInfoMessage;
|
||||
import org.linphone.core.LinphoneProxyConfig;
|
||||
import org.linphone.core.PublishState;
|
||||
|
|
@ -286,4 +287,18 @@ public class TutorialRegistration implements LinphoneCoreListener {
|
|||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void friendListCreated(LinphoneCore lc, LinphoneFriendList list) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void friendListRemoved(LinphoneCore lc, LinphoneFriendList list) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -152,16 +152,16 @@ int main(int argc, char *argv[]){
|
|||
ms_usleep(50000);
|
||||
++i;
|
||||
if (data->ev && i%100==0){
|
||||
LinphoneContentPrivate content;
|
||||
content.type="application";
|
||||
content.subtype="goodxml";
|
||||
content.data="really cool";
|
||||
content.size=strlen((const char*)content.data);
|
||||
linphone_event_notify(data->ev,LINPHONE_CONTENT(&content));
|
||||
LinphoneContent *content = linphone_core_create_content(lc);
|
||||
linphone_content_set_type(content, "application");
|
||||
linphone_content_set_subtype(content, "goodxml");
|
||||
linphone_content_set_string_buffer(content, "really cool");
|
||||
linphone_event_notify(data->ev, content);
|
||||
linphone_content_unref(content);
|
||||
}
|
||||
}
|
||||
|
||||
linphone_core_get_default_proxy(lc,&proxy_cfg); /* get default proxy config*/
|
||||
proxy_cfg = linphone_core_get_default_proxy_config(lc); /* get default proxy config*/
|
||||
linphone_proxy_config_edit(proxy_cfg); /*start editing proxy configuration*/
|
||||
linphone_proxy_config_enable_register(proxy_cfg,FALSE); /*de-activate registration for this proxy config*/
|
||||
linphone_proxy_config_done(proxy_cfg); /*initiate REGISTER with expire = 0*/
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
*/
|
||||
|
||||
/**
|
||||
* @defgroup real_time_text Real Time Text Sender
|
||||
* @defgroup real_time_text_sender Real Time Text Sender
|
||||
* @ingroup tutorials
|
||||
This program just send chat message in real time to dest uri. Use realtimetext_receiver to receive message.
|
||||
usage: ./realtimetext_sender sip:localhost:5060
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ int main(int argc, char *argv[]){
|
|||
ms_usleep(50000);
|
||||
}
|
||||
|
||||
linphone_core_get_default_proxy(lc,&proxy_cfg); /* get default proxy config*/
|
||||
proxy_cfg = linphone_core_get_default_proxy_config(lc); /* get default proxy config*/
|
||||
linphone_proxy_config_edit(proxy_cfg); /*start editing proxy configuration*/
|
||||
linphone_proxy_config_enable_register(proxy_cfg,FALSE); /*de-activate registration for this proxy config*/
|
||||
linphone_proxy_config_done(proxy_cfg); /*initiate REGISTER with expire = 0*/
|
||||
|
|
|
|||
|
|
@ -69,10 +69,10 @@ LinphoneInfoMessage *linphone_core_create_info_message(LinphoneCore *lc){
|
|||
* @param call the call
|
||||
* @param info the info message
|
||||
**/
|
||||
int linphone_call_send_info_message(LinphoneCall *call, const LinphoneInfoMessage *info){
|
||||
SalBody body;
|
||||
sal_op_set_sent_custom_header(call->op,info->headers);
|
||||
return sal_send_info(call->op,NULL, NULL, sal_body_from_content(&body,info->content));
|
||||
int linphone_call_send_info_message(LinphoneCall *call, const LinphoneInfoMessage *info) {
|
||||
SalBodyHandler *body_handler = sal_body_handler_from_content(info->content);
|
||||
sal_op_set_sent_custom_header(call->op, info->headers);
|
||||
return sal_send_info(call->op,NULL, NULL, body_handler);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -112,12 +112,12 @@ const LinphoneContent * linphone_info_message_get_content(const LinphoneInfoMess
|
|||
return (im->content && linphone_content_get_type(im->content)) ? im->content : NULL;
|
||||
}
|
||||
|
||||
void linphone_core_notify_info_message(LinphoneCore* lc,SalOp *op, const SalBody *body){
|
||||
void linphone_core_notify_info_message(LinphoneCore* lc,SalOp *op, SalBodyHandler *body_handler){
|
||||
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
|
||||
if (call){
|
||||
LinphoneInfoMessage *info=ms_new0(LinphoneInfoMessage,1);
|
||||
info->headers=sal_custom_header_clone(sal_op_get_recv_custom_header(op));
|
||||
if (body) info->content=linphone_content_from_sal_body(body);
|
||||
if (body_handler) info->content=linphone_content_from_sal_body_handler(body_handler);
|
||||
linphone_core_notify_info_received(lc,call,info);
|
||||
linphone_info_message_destroy(info);
|
||||
}
|
||||
|
|
|
|||
105
coreapi/lime.c
105
coreapi/lime.c
|
|
@ -4,19 +4,8 @@
|
|||
#endif
|
||||
|
||||
#ifdef HAVE_LIME
|
||||
|
||||
#include "linphonecore.h"
|
||||
#include "ortp/b64.h"
|
||||
#include "polarssl/gcm.h"
|
||||
|
||||
/* check polarssl version */
|
||||
#include <polarssl/version.h>
|
||||
|
||||
#if POLARSSL_VERSION_NUMBER >= 0x01030000 /* for Polarssl version 1.3 */
|
||||
#include "polarssl/sha256.h"
|
||||
#else /* for Polarssl version 1.2 */
|
||||
#include "polarssl/sha2.h"
|
||||
#endif
|
||||
#include "bctoolbox/crypto.h"
|
||||
|
||||
/**
|
||||
* @brief check at runtime if LIME is available
|
||||
|
|
@ -417,13 +406,6 @@ static int lime_deriveKey(limeKey_t *key) {
|
|||
return LIME_UNABLE_TO_DERIVE_KEY;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*not doing anything yet since key and sessionId are array, not pointers*/
|
||||
if ((key->key == NULL) || (key->sessionId == NULL)) {
|
||||
return LIME_UNABLE_TO_DERIVE_KEY;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Derivation is made derived Key = HMAC_SHA256(Key, 0x0000001||"MessageKey"||0x00||SessionId||SessionIndex||0x00000100)*/
|
||||
/* total data to be hashed is 55 bytes : 4 + 10 + 1 + 32 + 4 + 4 */
|
||||
inputData[0] = 0x00;
|
||||
|
|
@ -448,11 +430,7 @@ static int lime_deriveKey(limeKey_t *key) {
|
|||
inputData[54] = 0x00;
|
||||
|
||||
/* derive the key in a temp buffer */
|
||||
#if POLARSSL_VERSION_NUMBER >= 0x01030000 /* for Polarssl version 1.3 */
|
||||
sha256_hmac(key->key, 32, inputData, 55, derivedKey, 0); /* last param to zero to select SHA256 and not SHA224 */
|
||||
#else /* for Polarssl version 1.2 */
|
||||
sha2_hmac(key->key, 32, inputData, 55, derivedKey, 0); /* last param to zero to select SHA256 and not SHA224 */
|
||||
#endif /* POLARSSL_VERSION_NUMBER */
|
||||
bctoolbox_hmacSha256(key->key, 32, inputData, 55, 32, derivedKey);
|
||||
|
||||
/* overwrite the old key with the derived one */
|
||||
memcpy(key->key, derivedKey, 32);
|
||||
|
|
@ -481,7 +459,6 @@ void lime_freeKeys(limeURIKeys_t associatedKeys) {
|
|||
|
||||
int lime_encryptMessage(limeKey_t *key, uint8_t *plainMessage, uint32_t messageLength, uint8_t selfZID[12], uint8_t *encryptedMessage) {
|
||||
uint8_t authenticatedData[28];
|
||||
gcm_context gcmContext;
|
||||
/* Authenticated data is senderZID(12 bytes)||receiverZID(12 bytes)||sessionIndex(4 bytes) */
|
||||
memcpy(authenticatedData, selfZID, 12);
|
||||
memcpy(authenticatedData+12, key->peerZID, 12);
|
||||
|
|
@ -492,31 +469,31 @@ int lime_encryptMessage(limeKey_t *key, uint8_t *plainMessage, uint32_t messageL
|
|||
|
||||
/* AES-GCM : key is 192 bits long, Init Vector 64 bits. 256 bits key given is AES key||IV */
|
||||
/* tag is 16 bytes long and is set in the 16 first bytes of the encrypted message */
|
||||
gcm_init(&gcmContext, POLARSSL_CIPHER_ID_AES, key->key, 192);
|
||||
gcm_crypt_and_tag(&gcmContext, GCM_ENCRYPT, messageLength, key->key+24, 8, authenticatedData, 28, plainMessage, encryptedMessage+16, 16, encryptedMessage);
|
||||
gcm_free(&gcmContext);
|
||||
return bctoolbox_aes_gcm_encrypt_and_tag(key->key, 24,
|
||||
plainMessage, messageLength,
|
||||
authenticatedData, 28,
|
||||
key->key+24, 8, /* IV is at the end(last 64 bits) of the given key buffer */
|
||||
encryptedMessage, 16, /* the first 16 bytes of output are the authentication tag */
|
||||
encryptedMessage+16); /* actual encrypted message starts after 16 bytes of authentication tag */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lime_encryptFile(void **cryptoContext, unsigned char *key, size_t length, char *plain, char *cipher) {
|
||||
gcm_context *gcmContext;
|
||||
bctoolbox_aes_gcm_context_t *gcmContext;
|
||||
|
||||
if (*cryptoContext == NULL) { /* first call to the function, allocate a crypto context and initialise it */
|
||||
gcmContext = (gcm_context *)malloc(sizeof(gcm_context));
|
||||
*cryptoContext = (void *)gcmContext;
|
||||
gcm_init(gcmContext, POLARSSL_CIPHER_ID_AES, key, 192);
|
||||
gcm_starts(gcmContext, GCM_ENCRYPT, key+24, 8, NULL, 0); /* key contains 192bits of key || 64 bits of Initialisation Vector */
|
||||
/* key contains 192bits of key || 64 bits of Initialisation Vector, no additional data */
|
||||
gcmContext = bctoolbox_aes_gcm_context_new(key, 24, NULL, 0, key+24, 8, BCTOOLBOX_GCM_ENCRYPT);
|
||||
*cryptoContext = gcmContext;
|
||||
} else { /* this is not the first call, get the context */
|
||||
gcmContext = (gcm_context *)*cryptoContext;
|
||||
gcmContext = (bctoolbox_aes_gcm_context_t *)*cryptoContext;
|
||||
}
|
||||
|
||||
if (length != 0) {
|
||||
gcm_update(gcmContext, length, (const unsigned char *)plain, (unsigned char *)cipher);
|
||||
} else { /* lenght is 0, finish the stream */
|
||||
gcm_finish(gcmContext, NULL, 0); /* do not generate tag */
|
||||
gcm_free(gcmContext);
|
||||
free(*cryptoContext);
|
||||
bctoolbox_aes_gcm_process_chunk(gcmContext, (const uint8_t *)plain, length, (uint8_t *)cipher);
|
||||
} else { /* lenght is 0, finish the stream, no tag to be generated */
|
||||
bctoolbox_aes_gcm_finish(gcmContext, NULL, 0);
|
||||
*cryptoContext = NULL;
|
||||
}
|
||||
|
||||
|
|
@ -524,23 +501,20 @@ int lime_encryptFile(void **cryptoContext, unsigned char *key, size_t length, ch
|
|||
}
|
||||
|
||||
int lime_decryptFile(void **cryptoContext, unsigned char *key, size_t length, char *plain, char *cipher) {
|
||||
gcm_context *gcmContext;
|
||||
bctoolbox_aes_gcm_context_t *gcmContext;
|
||||
|
||||
if (*cryptoContext == NULL) { /* first call to the function, allocate a crypto context and initialise it */
|
||||
gcmContext = (gcm_context *)malloc(sizeof(gcm_context));
|
||||
*cryptoContext = (void *)gcmContext;
|
||||
gcm_init(gcmContext, POLARSSL_CIPHER_ID_AES, key, 192);
|
||||
gcm_starts(gcmContext, GCM_DECRYPT, key+24, 8, NULL, 0); /* key contains 192bits of key || 64 bits of Initialisation Vector */
|
||||
/* key contains 192bits of key || 64 bits of Initialisation Vector, no additional data */
|
||||
gcmContext = bctoolbox_aes_gcm_context_new(key, 24, NULL, 0, key+24, 8, BCTOOLBOX_GCM_DECRYPT);
|
||||
*cryptoContext = gcmContext;
|
||||
} else { /* this is not the first call, get the context */
|
||||
gcmContext = (gcm_context *)*cryptoContext;
|
||||
gcmContext = (bctoolbox_aes_gcm_context_t *)*cryptoContext;
|
||||
}
|
||||
|
||||
if (length != 0) {
|
||||
gcm_update(gcmContext, length, (const unsigned char *)cipher, (unsigned char *)plain);
|
||||
bctoolbox_aes_gcm_process_chunk(gcmContext, (const unsigned char *)cipher, length, (unsigned char *)plain);
|
||||
} else { /* lenght is 0, finish the stream */
|
||||
gcm_finish(gcmContext, NULL, 0); /* do not generate tag */
|
||||
gcm_free(gcmContext);
|
||||
free(*cryptoContext);
|
||||
bctoolbox_aes_gcm_finish(gcmContext, NULL, 0);
|
||||
*cryptoContext = NULL;
|
||||
}
|
||||
|
||||
|
|
@ -550,7 +524,6 @@ int lime_decryptFile(void **cryptoContext, unsigned char *key, size_t length, ch
|
|||
|
||||
int lime_decryptMessage(limeKey_t *key, uint8_t *encryptedMessage, uint32_t messageLength, uint8_t selfZID[12], uint8_t *plainMessage) {
|
||||
uint8_t authenticatedData[28];
|
||||
gcm_context gcmContext;
|
||||
int retval;
|
||||
|
||||
/* Authenticated data is senderZID(12 bytes)||receiverZID(12 bytes)||sessionIndex(4 bytes) */
|
||||
|
|
@ -563,10 +536,13 @@ int lime_decryptMessage(limeKey_t *key, uint8_t *encryptedMessage, uint32_t mess
|
|||
|
||||
/* AES-GCM : key is 192 bits long, Init Vector 64 bits. 256 bits key given is AES key||IV */
|
||||
/* tag is 16 bytes long and is the 16 first bytes of the encrypted message */
|
||||
gcm_init(&gcmContext, POLARSSL_CIPHER_ID_AES, key->key, 192);
|
||||
/* messageLength-16 is the length of encrypted data, messageLength include the 16 bytes tag included at the begining of encryptedMessage */
|
||||
retval = gcm_auth_decrypt(&gcmContext, messageLength-16, key->key+24, 8, authenticatedData, 28, encryptedMessage, 16, encryptedMessage+16, plainMessage);
|
||||
gcm_free(&gcmContext);
|
||||
retval = bctoolbox_aes_gcm_decrypt_and_auth(key->key, 24, /* key is 192 bits long */
|
||||
encryptedMessage+16, messageLength-16, /* encrypted message first 16 bytes store the authentication tag, then is the actual message */
|
||||
authenticatedData, 28, /* additionnal data needed for authentication */
|
||||
key->key+24, 8, /* last 8 bytes of key is the initialisation vector */
|
||||
encryptedMessage, 16, /* first 16 bytes of message is the authentication tag */
|
||||
plainMessage);
|
||||
|
||||
/* add the null termination char */
|
||||
plainMessage[messageLength-16] = '\0';
|
||||
|
||||
|
|
@ -621,8 +597,8 @@ int lime_createMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_t
|
|||
uint8_t peerZidHex[25];
|
||||
uint8_t sessionIndexHex[9];
|
||||
xmlNodePtr msgNode;
|
||||
int b64Size;
|
||||
char *encryptedMessageb64;
|
||||
size_t b64Size = 0;
|
||||
unsigned char *encryptedMessageb64;
|
||||
|
||||
/* encrypt message with current key */
|
||||
limeKey_t *currentKey = associatedKeys.peerKeys[i];
|
||||
|
|
@ -652,9 +628,9 @@ int lime_createMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_t
|
|||
xmlNewTextChild(msgNode, NULL, (const xmlChar *)"index", sessionIndexHex);
|
||||
|
||||
/* convert the cipherText to base 64 */
|
||||
b64Size = b64_encode(NULL, encryptedMessageLength, NULL, 0);
|
||||
encryptedMessageb64 = (char *)malloc(b64Size+1);
|
||||
b64Size = b64_encode(encryptedMessage, encryptedMessageLength, encryptedMessageb64, b64Size);
|
||||
bctoolbox_base64_encode(NULL, &b64Size, encryptedMessage, encryptedMessageLength); /* b64Size is 0, so it is set to the requested output buffer size */
|
||||
encryptedMessageb64 = malloc(b64Size+1); /* allocate a buffer of requested size +1 for NULL termination */
|
||||
bctoolbox_base64_encode(encryptedMessageb64, &b64Size, encryptedMessage, encryptedMessageLength); /* b64Size is 0, so it is set to the requested output buffer size */
|
||||
encryptedMessageb64[b64Size] = '\0'; /* libxml need a null terminated string */
|
||||
xmlNewTextChild(msgNode, NULL, (const xmlChar *)"text", (const xmlChar *)encryptedMessageb64);
|
||||
free(encryptedMessage);
|
||||
|
|
@ -685,7 +661,7 @@ int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_
|
|||
xmlChar *peerZidHex = NULL;
|
||||
xmlNodePtr cur;
|
||||
uint8_t *encryptedMessage = NULL;
|
||||
uint32_t encryptedMessageLength = 0;
|
||||
size_t encryptedMessageLength = 0;
|
||||
uint32_t usedSessionIndex = 0;
|
||||
xmlDocPtr xmlEncryptedMessage;
|
||||
|
||||
|
|
@ -750,14 +726,19 @@ int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_
|
|||
| (((uint32_t)lime_charToByte(sessionIndexHex[6]))<<4)
|
||||
| (((uint32_t)lime_charToByte(sessionIndexHex[7])));
|
||||
xmlFree(sessionIndexHex);
|
||||
|
||||
/* get the encrypted message */
|
||||
msgChildrenNode = msgChildrenNode->next;
|
||||
|
||||
/* convert the cipherText from base 64 */
|
||||
encryptedMessageb64 = xmlNodeListGetString(cacheBuffer, msgChildrenNode->xmlChildrenNode, 1);
|
||||
encryptedMessageLength = b64_decode((char *)encryptedMessageb64, strlen((char *)encryptedMessageb64), NULL, 0);
|
||||
bctoolbox_base64_decode(NULL, &encryptedMessageLength, encryptedMessageb64, strlen((char *)encryptedMessageb64)); /* encryptedMessageLength is 0, so it will be set to the requested buffer length */
|
||||
encryptedMessage = (uint8_t *)malloc(encryptedMessageLength);
|
||||
encryptedMessageLength = b64_decode((char *)encryptedMessageb64, strlen((char *)encryptedMessageb64), encryptedMessage, encryptedMessageLength);
|
||||
bctoolbox_base64_decode(encryptedMessage, &encryptedMessageLength, encryptedMessageb64, strlen((char *)encryptedMessageb64));
|
||||
|
||||
xmlFree(encryptedMessageb64);
|
||||
xmlFree(currentZidHex);
|
||||
break;
|
||||
}
|
||||
|
||||
cur = cur->next;
|
||||
|
|
|
|||
|
|
@ -394,10 +394,7 @@ LINPHONE_PUBLIC SipSetup *linphone_proxy_config_get_sip_setup(LinphoneProxyConfi
|
|||
LINPHONE_PUBLIC bool_t linphone_proxy_config_is_phone_number(LinphoneProxyConfig *proxy, const char *username);
|
||||
|
||||
/**
|
||||
* Normalize a human readable phone number into a basic string. 888-444-222 becomes 888444222
|
||||
* or +33888444222 depending on the #LinphoneProxyConfig object. However this argument is OPTIONNAL
|
||||
* and if not provided, a default one will be used.
|
||||
* This function will always generate a normalized username; if input is not a phone number, output will be a copy of input.
|
||||
* See linphone_proxy_config_normalize_phone_number
|
||||
* @param proxy #LinphoneProxyConfig object containing country code and/or escape symbol. If NULL passed, will use default configuration.
|
||||
* @param username the string to parse
|
||||
* @param result the newly normalized number
|
||||
|
|
@ -409,12 +406,11 @@ LINPHONE_PUBLIC bool_t linphone_proxy_config_normalize_number(LinphoneProxyConfi
|
|||
|
||||
/**
|
||||
* Normalize a human readable phone number into a basic string. 888-444-222 becomes 888444222
|
||||
* or +33888444222 depending on the #LinphoneProxyConfig object. However this argument is OPTIONNAL
|
||||
* and if not provided, a default one will be used.
|
||||
* This function will always generate a normalized username; if input is not a phone number, output will be a copy of input.
|
||||
* or +33888444222 depending on the #LinphoneProxyConfig object.
|
||||
* This function will always generate a normalized username if input is a phone number.
|
||||
* @param proxy #LinphoneProxyConfig object containing country code and/or escape symbol. If NULL passed, will use default configuration.
|
||||
* @param username the string to parse
|
||||
* @return NULL if invalid phone number, normalized phone number from username input otherwise.
|
||||
* @return NULL if input is an invalid phone number, normalized phone number from username input otherwise.
|
||||
*/
|
||||
LINPHONE_PUBLIC char* linphone_proxy_config_normalize_phone_number(LinphoneProxyConfig *proxy, const char *username);
|
||||
|
||||
|
|
@ -526,7 +522,7 @@ LINPHONE_PUBLIC void linphone_proxy_config_set_custom_header(LinphoneProxyConfig
|
|||
* @param[in] cfg #LinphoneProxyConfig object.
|
||||
* @return a #LinphoneAuthInfo matching proxy config criteria if possible, NULL if nothing can be found.
|
||||
**/
|
||||
LINPHONE_PUBLIC const struct _LinphoneAuthInfo* linphone_proxy_config_find_auth_info(const LinphoneProxyConfig *cfg);
|
||||
LINPHONE_PUBLIC const LinphoneAuthInfo* linphone_proxy_config_find_auth_info(const LinphoneProxyConfig *cfg);
|
||||
|
||||
/**
|
||||
* @}
|
||||
|
|
|
|||
|
|
@ -289,7 +289,7 @@ static void tunnelLogHandler(int level, const char *fmt, va_list l){
|
|||
ms_fatal("Unexepcted tunnel log %i: %s",level,fmt);
|
||||
break;
|
||||
}
|
||||
tunnelOrtpLogHandler(ortp_level,fmt,l);
|
||||
tunnelOrtpLogHandler("tunnel", ortp_level,fmt,l);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -330,8 +330,8 @@ bool_t linphone_tunnel_sip_enabled(const LinphoneTunnel *tunnel) {
|
|||
return bcTunnel(tunnel)->tunnelizeSipPacketsEnabled() ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
static void my_ortp_logv(OrtpLogLevel level, const char *fmt, va_list args){
|
||||
ortp_logv(level,fmt,args);
|
||||
static void my_ortp_logv(const char *domain, OrtpLogLevel level, const char *fmt, va_list args){
|
||||
ortp_logv(domain, level,fmt,args);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "sipsetup.h"
|
||||
#include "lpconfig.h"
|
||||
#include "private.h"
|
||||
#include "conference_private.h"
|
||||
#include <ortp/event.h>
|
||||
#include <ortp/b64.h>
|
||||
#include <math.h>
|
||||
|
|
@ -47,9 +48,9 @@ static void _linphone_call_set_next_video_frame_decoded_trigger(LinphoneCall *ca
|
|||
void linphone_call_handle_stream_events(LinphoneCall *call, int stream_index);
|
||||
|
||||
|
||||
MSWebCam *get_nowebcam_device(){
|
||||
MSWebCam *get_nowebcam_device(MSFactory* f){
|
||||
#ifdef VIDEO_ENABLED
|
||||
return ms_web_cam_manager_get_cam(ms_web_cam_manager_get(),"StaticImage: Static picture");
|
||||
return ms_web_cam_manager_get_cam(ms_factory_get_web_cam_manager(f),"StaticImage: Static picture");
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
|
|
@ -184,6 +185,11 @@ static void propagate_encryption_changed(LinphoneCall *call){
|
|||
}
|
||||
ms_message("All streams are encrypted key exchanged using %s", call->current_params->media_encryption==LinphoneMediaEncryptionZRTP?"ZRTP":call->current_params->media_encryption==LinphoneMediaEncryptionDTLS?"DTLS":"Unknown mechanism");
|
||||
linphone_core_notify_call_encryption_changed(call->core, call, TRUE, call->auth_token);
|
||||
#ifdef VIDEO_ENABLED
|
||||
if (call->current_params->encryption_mandatory && call->videostream && media_stream_started((MediaStream *)call->videostream)) {
|
||||
video_stream_send_vfu(call->videostream); /*nothing could have been sent yet so generating key frame*/
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -237,11 +243,13 @@ static void linphone_call_audiostream_auth_token_ready(void *data, const char* a
|
|||
* @ingroup call_control
|
||||
**/
|
||||
void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t verified){
|
||||
if (call->audiostream==NULL){
|
||||
ms_error("linphone_call_set_authentication_token_verified(): No audio stream");
|
||||
if (call->audiostream==NULL || !media_stream_started(&call->audiostream->ms)){
|
||||
ms_error("linphone_call_set_authentication_token_verified(): No audio stream or not started");
|
||||
return;
|
||||
}
|
||||
if (call->audiostream->ms.sessions.zrtp_context==NULL){
|
||||
ms_error("linphone_call_set_authentication_token_verified(): No zrtp context.");
|
||||
return;
|
||||
}
|
||||
if (!call->auth_token_verified && verified){
|
||||
ms_zrtp_sas_verified(call->audiostream->ms.sessions.zrtp_context);
|
||||
|
|
@ -299,7 +307,7 @@ static void linphone_core_assign_payload_type_numbers(LinphoneCore *lc, MSList *
|
|||
MSList *elem;
|
||||
int dyn_number=lc->codecs_conf.dyn_pt;
|
||||
PayloadType *red = NULL, *t140 = NULL;
|
||||
|
||||
|
||||
for (elem=codecs; elem!=NULL; elem=elem->next){
|
||||
PayloadType *pt=(PayloadType*)elem->data;
|
||||
int number=payload_type_get_number(pt);
|
||||
|
|
@ -326,14 +334,14 @@ static void linphone_core_assign_payload_type_numbers(LinphoneCore *lc, MSList *
|
|||
payload_type_set_enable(pt, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (strcmp(pt->mime_type, payload_type_t140_red.mime_type) == 0) {
|
||||
red = pt;
|
||||
} else if (strcmp(pt->mime_type, payload_type_t140.mime_type) == 0) {
|
||||
t140 = pt;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (t140 && red) {
|
||||
int t140_payload_type_number = payload_type_get_number(t140);
|
||||
const char *red_fmtp = ms_strdup_printf("%i/%i/%i", t140_payload_type_number, t140_payload_type_number, t140_payload_type_number);
|
||||
|
|
@ -526,15 +534,18 @@ static void setup_rtcp_fb(LinphoneCall *call, SalMediaDescription *md) {
|
|||
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);
|
||||
md->streams[i].implicit_rtcp_fb = call->params->implicit_rtcp_fb;
|
||||
|
||||
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) {
|
||||
|
||||
if (call->params->avpf_enabled == FALSE && call->params->implicit_rtcp_fb == FALSE) {
|
||||
payload_type_unset_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED);
|
||||
memset(&avpf_params, 0, sizeof(avpf_params));
|
||||
}else {
|
||||
payload_type_set_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED);
|
||||
avpf_params = payload_type_get_avpf_params(pt);
|
||||
avpf_params.trr_interval = call->params->avpf_rr_interval;
|
||||
} else {
|
||||
payload_type_unset_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED);
|
||||
memset(&avpf_params, 0, sizeof(avpf_params));
|
||||
}
|
||||
payload_type_set_avpf_params(pt, avpf_params);
|
||||
}
|
||||
|
|
@ -572,8 +583,11 @@ void linphone_call_increment_local_media_description(LinphoneCall *call){
|
|||
}
|
||||
|
||||
void linphone_call_update_local_media_description_from_ice_or_upnp(LinphoneCall *call){
|
||||
LinphoneCore *lc = call->core;
|
||||
if (call->ice_session != NULL) {
|
||||
_update_local_media_description_from_ice(call->localdesc, call->ice_session);
|
||||
/*set this to FALSE once flexisip are updated everywhere, let's say in December 2016.*/
|
||||
bool_t use_nortpproxy = lp_config_get_int(lc->config, "sip", "ice_uses_nortpproxy", TRUE);
|
||||
_update_local_media_description_from_ice(call->localdesc, call->ice_session, use_nortpproxy);
|
||||
linphone_core_update_ice_state_in_call_stats(call);
|
||||
}
|
||||
#ifdef BUILD_UPNP
|
||||
|
|
@ -702,7 +716,13 @@ void linphone_call_make_local_media_description(LinphoneCall *call) {
|
|||
md->custom_sdp_attributes = sal_custom_sdp_attribute_clone(params->custom_sdp_attributes);
|
||||
|
||||
/*set audio capabilities */
|
||||
if (params->has_audio) {
|
||||
|
||||
codec_hints.bandwidth_limit=params->audio_bw;
|
||||
codec_hints.max_codecs=-1;
|
||||
codec_hints.previously_used=old_md ? old_md->streams[call->main_audio_stream_index].already_assigned_payloads : NULL;
|
||||
l=make_codec_list(lc, &codec_hints, SalAudio, lc->codecs_conf.audio_codecs);
|
||||
|
||||
if (params->has_audio && l != NULL) {
|
||||
strncpy(md->streams[call->main_audio_stream_index].rtp_addr,linphone_call_get_public_ip_for_stream(call,call->main_audio_stream_index),sizeof(md->streams[call->main_audio_stream_index].rtp_addr));
|
||||
strncpy(md->streams[call->main_audio_stream_index].rtcp_addr,linphone_call_get_public_ip_for_stream(call,call->main_audio_stream_index),sizeof(md->streams[call->main_audio_stream_index].rtcp_addr));
|
||||
strncpy(md->streams[call->main_audio_stream_index].name,"Audio",sizeof(md->streams[call->main_audio_stream_index].name)-1);
|
||||
|
|
@ -716,10 +736,6 @@ void linphone_call_make_local_media_description(LinphoneCall *call) {
|
|||
md->streams[call->main_audio_stream_index].ptime=params->down_ptime;
|
||||
else
|
||||
md->streams[call->main_audio_stream_index].ptime=linphone_core_get_download_ptime(lc);
|
||||
codec_hints.bandwidth_limit=params->audio_bw;
|
||||
codec_hints.max_codecs=-1;
|
||||
codec_hints.previously_used=old_md ? old_md->streams[call->main_audio_stream_index].already_assigned_payloads : NULL;
|
||||
l=make_codec_list(lc, &codec_hints, SalAudio, lc->codecs_conf.audio_codecs);
|
||||
md->streams[call->main_audio_stream_index].max_rate=get_max_codec_sample_rate(l);
|
||||
md->streams[call->main_audio_stream_index].payloads=l;
|
||||
if (call->audiostream && call->audiostream->ms.sessions.rtp_session) {
|
||||
|
|
@ -745,15 +761,16 @@ void linphone_call_make_local_media_description(LinphoneCall *call) {
|
|||
md->streams[call->main_video_stream_index].rtcp_mux = rtcp_mux;
|
||||
strncpy(md->streams[call->main_video_stream_index].name,"Video",sizeof(md->streams[call->main_video_stream_index].name)-1);
|
||||
|
||||
if (params->has_video){
|
||||
codec_hints.bandwidth_limit=0;
|
||||
codec_hints.max_codecs=-1;
|
||||
codec_hints.previously_used=old_md ? old_md->streams[call->main_video_stream_index].already_assigned_payloads : NULL;
|
||||
l=make_codec_list(lc, &codec_hints, SalVideo, lc->codecs_conf.video_codecs);
|
||||
|
||||
if (params->has_video && l != NULL){
|
||||
strncpy(md->streams[call->main_video_stream_index].rtp_addr,linphone_call_get_public_ip_for_stream(call,call->main_video_stream_index),sizeof(md->streams[call->main_video_stream_index].rtp_addr));
|
||||
strncpy(md->streams[call->main_video_stream_index].rtcp_addr,linphone_call_get_public_ip_for_stream(call,call->main_video_stream_index),sizeof(md->streams[call->main_video_stream_index].rtcp_addr));
|
||||
md->streams[call->main_video_stream_index].rtp_port=call->media_ports[call->main_video_stream_index].rtp_port;
|
||||
md->streams[call->main_video_stream_index].rtcp_port=call->media_ports[call->main_video_stream_index].rtcp_port;
|
||||
codec_hints.bandwidth_limit=0;
|
||||
codec_hints.max_codecs=-1;
|
||||
codec_hints.previously_used=old_md ? old_md->streams[call->main_video_stream_index].already_assigned_payloads : NULL;
|
||||
l=make_codec_list(lc, &codec_hints, SalVideo, lc->codecs_conf.video_codecs);
|
||||
md->streams[call->main_video_stream_index].payloads=l;
|
||||
if (call->videostream && call->videostream->ms.sessions.rtp_session) {
|
||||
char* me = linphone_address_as_string_uri_only(call->me);
|
||||
|
|
@ -820,6 +837,7 @@ void linphone_call_make_local_media_description(LinphoneCall *call) {
|
|||
}
|
||||
setup_encryption_keys(call,md);
|
||||
setup_dtls_keys(call,md);
|
||||
|
||||
setup_rtcp_fb(call, md);
|
||||
setup_rtcp_xr(call, md);
|
||||
|
||||
|
|
@ -916,6 +934,7 @@ static void port_config_set(LinphoneCall *call, int stream_index, int min_port,
|
|||
static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
|
||||
int min_port, max_port;
|
||||
ms_message("New LinphoneCall [%p] initialized (LinphoneCore version: %s)",call,linphone_core_get_version());
|
||||
call->core->send_call_stats_periodical_updates = lp_config_get_int(call->core->config, "misc", "send_call_stats_periodical_updates", 0);
|
||||
call->main_audio_stream_index = LINPHONE_CALL_STATS_AUDIO;
|
||||
call->main_video_stream_index = LINPHONE_CALL_STATS_VIDEO;
|
||||
call->main_text_stream_index = LINPHONE_CALL_STATS_TEXT;
|
||||
|
|
@ -965,9 +984,9 @@ static void discover_mtu(LinphoneCore *lc, const char *remote){
|
|||
/*attempt to discover mtu*/
|
||||
mtu=ms_discover_mtu(remote);
|
||||
if (mtu>0){
|
||||
ms_set_mtu(mtu);
|
||||
ms_factory_set_mtu(lc->factory, mtu);
|
||||
ms_message("Discovered mtu is %i, RTP payload max size is %i",
|
||||
mtu, ms_get_payload_max_size());
|
||||
mtu, ms_factory_get_payload_max_size(lc->factory));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1072,6 +1091,21 @@ void linphone_call_fill_media_multicast_addr(LinphoneCall *call) {
|
|||
call->media_ports[call->main_video_stream_index].multicast_ip[0]='\0';
|
||||
}
|
||||
|
||||
static void linphone_call_create_ice_session(LinphoneCall *call, IceRole role){
|
||||
call->ice_session = ice_session_new();
|
||||
/*for backward compatibility purposes, shall be enabled by default in futur*/
|
||||
ice_session_enable_message_integrity_check(call->ice_session,lp_config_get_int(call->core->config,"net","ice_session_enable_message_integrity_check",1));
|
||||
if (lp_config_get_int(call->core->config, "net", "dont_default_to_stun_candidates", 0)){
|
||||
IceCandidateType types[ICT_CandidateTypeMax];
|
||||
types[0] = ICT_RelayedCandidate;
|
||||
types[1] = ICT_HostCandidate;
|
||||
types[2] = ICT_CandidateInvalid;
|
||||
ice_session_set_default_candidates_types(call->ice_session, types);
|
||||
}
|
||||
|
||||
ice_session_set_role(call->ice_session, role);
|
||||
}
|
||||
|
||||
LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg){
|
||||
LinphoneCall *call = belle_sip_object_new(LinphoneCall);
|
||||
|
||||
|
|
@ -1082,13 +1116,12 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr
|
|||
call->params = linphone_call_params_copy(params);
|
||||
linphone_call_init_common(call, from, to);
|
||||
|
||||
call->current_params->update_call_when_ice_completed = call->params->update_call_when_ice_completed; /*copy param*/
|
||||
|
||||
linphone_call_fill_media_multicast_addr(call);
|
||||
|
||||
if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) {
|
||||
call->ice_session = ice_session_new();
|
||||
/*for backward compatibility purposes, shall be enabled by default in futur*/
|
||||
ice_session_enable_message_integrity_check(call->ice_session,lp_config_get_int(lc->config,"net","ice_session_enable_message_integrity_check",0));
|
||||
ice_session_set_role(call->ice_session, IR_Controlling);
|
||||
linphone_call_create_ice_session(call, IR_Controlling);
|
||||
}
|
||||
if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseStun) {
|
||||
call->ping_time=linphone_core_run_stun_tests(call->core,call);
|
||||
|
|
@ -1289,6 +1322,9 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
|
|||
*/
|
||||
/*set privacy*/
|
||||
call->current_params->privacy=(LinphonePrivacyMask)sal_op_get_privacy(call->op);
|
||||
/*config params*/
|
||||
call->current_params->update_call_when_ice_completed = call->params->update_call_when_ice_completed; /*copy config params*/
|
||||
|
||||
/*set video support */
|
||||
call->params->has_video = linphone_core_video_enabled(lc) && lc->video_policy.automatically_accept;
|
||||
if (md) {
|
||||
|
|
@ -1314,10 +1350,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
|
|||
/*create the ice session now if ICE is required*/
|
||||
if (fpol==LinphonePolicyUseIce){
|
||||
if (md){
|
||||
call->ice_session = ice_session_new();
|
||||
/*for backward compatibility purposes, shall be enabled by default in futur*/
|
||||
ice_session_enable_message_integrity_check(call->ice_session,lp_config_get_int(lc->config,"net","ice_session_enable_message_integrity_check",0));
|
||||
ice_session_set_role(call->ice_session, IR_Controlled);
|
||||
linphone_call_create_ice_session(call, IR_Controlled);
|
||||
}else{
|
||||
fpol=LinphonePolicyNoFirewall;
|
||||
ms_warning("ICE not supported for incoming INVITE without SDP.");
|
||||
|
|
@ -1328,7 +1361,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
|
|||
linphone_call_init_media_streams(call);
|
||||
switch (fpol) {
|
||||
case LinphonePolicyUseIce:
|
||||
linphone_call_prepare_ice(call,TRUE);
|
||||
call->defer_notify_incoming = linphone_call_prepare_ice(call,TRUE) == 1;
|
||||
break;
|
||||
case LinphonePolicyUseStun:
|
||||
call->ping_time=linphone_core_run_stun_tests(call->core,call);
|
||||
|
|
@ -1362,10 +1395,12 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
|
|||
* (_linphone_call_destroy) if the call was never notified to the application.
|
||||
*/
|
||||
void linphone_call_free_media_resources(LinphoneCall *call){
|
||||
int i;
|
||||
|
||||
linphone_call_stop_media_streams(call);
|
||||
ms_media_stream_sessions_uninit(&call->sessions[call->main_audio_stream_index]);
|
||||
ms_media_stream_sessions_uninit(&call->sessions[call->main_video_stream_index]);
|
||||
if (call->params->realtimetext_enabled) ms_media_stream_sessions_uninit(&call->sessions[call->main_text_stream_index]);
|
||||
for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; ++i){
|
||||
ms_media_stream_sessions_uninit(&call->sessions[i]);
|
||||
}
|
||||
linphone_call_delete_upnp_session(call);
|
||||
linphone_call_delete_ice_session(call);
|
||||
linphone_call_stats_uninit(&call->stats[LINPHONE_CALL_STATS_AUDIO]);
|
||||
|
|
@ -1424,7 +1459,7 @@ static void linphone_call_set_terminated(LinphoneCall *call){
|
|||
if (linphone_core_del_call(lc,call) != 0){
|
||||
ms_error("Could not remove the call from the list !!!");
|
||||
}
|
||||
linphone_core_conference_check_uninit(lc);
|
||||
if(lc->conf_ctx) linphone_conference_on_call_terminating(lc->conf_ctx, call);
|
||||
if (call->ringing_beep){
|
||||
linphone_core_stop_dtmf(lc);
|
||||
call->ringing_beep=FALSE;
|
||||
|
|
@ -1445,6 +1480,7 @@ void linphone_call_fix_call_parameters(LinphoneCall *call, SalMediaDescription *
|
|||
if (rmd) {
|
||||
linphone_call_compute_streams_indexes(call, rmd);
|
||||
linphone_call_update_biggest_desc(call, rmd);
|
||||
call->params->implicit_rtcp_fb &= sal_media_description_has_implicit_avpf(rmd);
|
||||
}
|
||||
rcp = linphone_call_get_remote_params(call);
|
||||
if (rcp){
|
||||
|
|
@ -1456,12 +1492,12 @@ void linphone_call_fix_call_parameters(LinphoneCall *call, SalMediaDescription *
|
|||
ms_message("Call [%p]: disabling video in our call params because the remote doesn't want it.", call);
|
||||
call->params->has_video = FALSE;
|
||||
}
|
||||
|
||||
|
||||
if (rcp->has_video && call->core->video_policy.automatically_accept && linphone_core_video_enabled(call->core) && !call->params->has_video){
|
||||
ms_message("Call [%p]: re-enabling video in our call params because the remote wants it and the policy allows to automatically accept.", call);
|
||||
linphone_call_params_enable_video(call->params, TRUE);
|
||||
}
|
||||
|
||||
|
||||
if (rcp->realtimetext_enabled && !call->params->realtimetext_enabled) {
|
||||
call->params->realtimetext_enabled = TRUE;
|
||||
}
|
||||
|
|
@ -1740,7 +1776,8 @@ const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){
|
|||
if ((all_streams_encrypted = linphone_call_all_streams_encrypted(call)) && linphone_call_get_authentication_token(call)) {
|
||||
call->current_params->media_encryption=LinphoneMediaEncryptionZRTP;
|
||||
} else {
|
||||
ms_message("Encryption was requested to be %s, but isn't effective (all_streams_encrypted=%i, auth_token=%s)",
|
||||
/*to avoid to many traces*/
|
||||
ms_debug("Encryption was requested to be %s, but isn't effective (all_streams_encrypted=%i, auth_token=%s)",
|
||||
linphone_media_encryption_to_string(call->params->media_encryption), all_streams_encrypted, call->auth_token == NULL ? "" : call->auth_token);
|
||||
call->current_params->media_encryption=LinphoneMediaEncryptionNone;
|
||||
}
|
||||
|
|
@ -1752,7 +1789,8 @@ const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){
|
|||
if (linphone_call_get_n_active_streams(call)==0 || (all_streams_encrypted = linphone_call_all_streams_encrypted(call))) {
|
||||
call->current_params->media_encryption = call->params->media_encryption;
|
||||
} else {
|
||||
ms_message("Encryption was requested to be %s, but isn't effective (all_streams_encrypted=%i)",
|
||||
/*to avoid to many traces*/
|
||||
ms_debug("Encryption was requested to be %s, but isn't effective (all_streams_encrypted=%i)",
|
||||
linphone_media_encryption_to_string(call->params->media_encryption), all_streams_encrypted);
|
||||
call->current_params->media_encryption=LinphoneMediaEncryptionNone;
|
||||
}
|
||||
|
|
@ -1760,10 +1798,9 @@ const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){
|
|||
break;
|
||||
case LinphoneMediaEncryptionNone:
|
||||
call->current_params->media_encryption=LinphoneMediaEncryptionNone;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
call->current_params->avpf_enabled = linphone_call_all_streams_avpf_enabled(call);
|
||||
call->current_params->avpf_enabled = linphone_call_all_streams_avpf_enabled(call) && sal_media_description_has_avpf(md);
|
||||
if (call->current_params->avpf_enabled == TRUE) {
|
||||
call->current_params->avpf_rr_interval = linphone_call_get_avpf_rr_interval(call);
|
||||
} else {
|
||||
|
|
@ -1773,6 +1810,7 @@ const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){
|
|||
const char *rtp_addr;
|
||||
|
||||
SalStreamDescription *sd=sal_media_description_find_best_stream(md,SalAudio);
|
||||
|
||||
call->current_params->audio_dir=sd ? media_direction_from_sal_stream_dir(sd->dir) : LinphoneMediaDirectionInactive;
|
||||
if (call->current_params->audio_dir != LinphoneMediaDirectionInactive) {
|
||||
rtp_addr = sd->rtp_addr[0]!='\0' ? sd->rtp_addr : call->resultdesc->addr;
|
||||
|
|
@ -1781,6 +1819,7 @@ const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){
|
|||
call->current_params->audio_multicast_enabled = FALSE;
|
||||
|
||||
sd=sal_media_description_find_best_stream(md,SalVideo);
|
||||
call->current_params->implicit_rtcp_fb = sd ? sal_stream_description_has_implicit_avpf(sd): FALSE;
|
||||
call->current_params->video_dir=sd ? media_direction_from_sal_stream_dir(sd->dir) : LinphoneMediaDirectionInactive;
|
||||
if (call->current_params->video_dir != LinphoneMediaDirectionInactive) {
|
||||
rtp_addr = sd->rtp_addr[0]!='\0' ? sd->rtp_addr : call->resultdesc->addr;
|
||||
|
|
@ -1788,7 +1827,8 @@ const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){
|
|||
} else
|
||||
call->current_params->video_multicast_enabled = FALSE;
|
||||
|
||||
sd=sal_media_description_find_best_stream(md,SalText);
|
||||
|
||||
|
||||
}
|
||||
|
||||
return call->current_params;
|
||||
|
|
@ -1966,12 +2006,9 @@ const char *linphone_call_get_remote_user_agent(LinphoneCall *call){
|
|||
* Returns the far end's sip contact as a string, if available.
|
||||
**/
|
||||
const char *linphone_call_get_remote_contact(LinphoneCall *call){
|
||||
const LinphoneCallParams* lcp = linphone_call_get_remote_params(call);
|
||||
if( lcp ){
|
||||
// we're not using sal_op_get_remote_contact() here because the returned value is stripped from
|
||||
// params that we need, like the instanceid. Getting it from the headers will make sure we
|
||||
// get everything
|
||||
return linphone_call_params_get_custom_header(lcp, "Contact");
|
||||
if( call->op ){
|
||||
/*sal_op_get_remote_contact preserves header params*/
|
||||
return sal_op_get_remote_contact(call->op);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -2036,10 +2073,11 @@ void linphone_call_enable_camera (LinphoneCall *call, bool_t enable){
|
|||
void linphone_call_send_vfu_request(LinphoneCall *call) {
|
||||
#ifdef VIDEO_ENABLED
|
||||
const LinphoneCallParams *current_params = linphone_call_get_current_params(call);
|
||||
if (current_params->avpf_enabled && call->videostream && media_stream_get_state((const MediaStream *)call->videostream) == MSStreamStarted) {
|
||||
if ((current_params->avpf_enabled || current_params->implicit_rtcp_fb )&& call->videostream && media_stream_get_state((const MediaStream *)call->videostream) == MSStreamStarted) { // || sal_media_description_has_implicit_avpf((const SalMediaDescription *)call->resultdesc)
|
||||
ms_message("Request Full Intra Request on call [%p]", call);
|
||||
video_stream_send_fir(call->videostream);
|
||||
} else if (call->core->sip_conf.vfu_with_info) {
|
||||
ms_message("Request SIP INFO FIR on call [%p]", call);
|
||||
if (LinphoneCallStreamsRunning == linphone_call_get_state(call))
|
||||
sal_call_send_vfu_request(call->op);
|
||||
} else {
|
||||
|
|
@ -2188,15 +2226,15 @@ static void _linphone_call_prepare_ice_for_stream(LinphoneCall *call, int stream
|
|||
ice_session_add_check_list(call->ice_session, cl, stream_index);
|
||||
ms_message("Created new ICE check list for stream [%i]",stream_index);
|
||||
}
|
||||
if (cl){
|
||||
ms->ice_check_list = cl;
|
||||
ice_check_list_set_rtp_session(ms->ice_check_list, ms->sessions.rtp_session);
|
||||
if (cl) {
|
||||
media_stream_set_ice_check_list(ms, cl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer){
|
||||
SalMediaDescription *remote = NULL;
|
||||
int err;
|
||||
bool_t has_video=FALSE;
|
||||
|
||||
if ((linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
|
||||
|
|
@ -2210,7 +2248,7 @@ int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer){
|
|||
if (call->params->realtimetext_enabled) _linphone_call_prepare_ice_for_stream(call,call->main_text_stream_index,TRUE);
|
||||
/*start ICE gathering*/
|
||||
if (incoming_offer)
|
||||
linphone_call_update_ice_from_remote_media_description(call,remote); /*this may delete the ice session*/
|
||||
linphone_call_update_ice_from_remote_media_description(call, remote, TRUE); /*this may delete the ice session*/
|
||||
if (call->ice_session && !ice_session_candidates_gathered(call->ice_session)){
|
||||
if (call->audiostream->ms.state==MSStreamInitialized)
|
||||
audio_stream_prepare_sound(call->audiostream, NULL, NULL);
|
||||
|
|
@ -2222,14 +2260,13 @@ int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer){
|
|||
if (call->params->realtimetext_enabled) {
|
||||
text_stream_prepare_text(call->textstream);
|
||||
}
|
||||
|
||||
if (linphone_core_gather_ice_candidates(call->core,call)<0) {
|
||||
|
||||
if ((err=linphone_core_gather_ice_candidates(call->core,call))<0) {
|
||||
/* Ice candidates gathering failed, proceed with the call anyway. */
|
||||
linphone_call_delete_ice_session(call);
|
||||
linphone_call_stop_media_streams_for_ice_gathering(call);
|
||||
return -1;
|
||||
}
|
||||
return 1;/*gathering in progress, wait*/
|
||||
return err;/* 1= gathering in progress, wait; 0=proceed*/
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -2301,11 +2338,9 @@ void linphone_call_init_audio_stream(LinphoneCall *call){
|
|||
AudioStream *audiostream;
|
||||
const char *location;
|
||||
int dscp;
|
||||
char rtcp_tool[128]={0};
|
||||
const char *rtcp_tool=linphone_core_get_user_agent(call->core);
|
||||
char* cname;
|
||||
|
||||
snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
|
||||
|
||||
if (call->audiostream != NULL) return;
|
||||
if (call->sessions[call->main_audio_stream_index].rtp_session==NULL){
|
||||
SalMulticastRole multicast_role = linphone_call_get_multicast_role(call,SalAudio);
|
||||
|
|
@ -2315,7 +2350,7 @@ void linphone_call_init_audio_stream(LinphoneCall *call){
|
|||
if (remotedesc)
|
||||
stream_desc = sal_media_description_find_best_stream(remotedesc, SalAudio);
|
||||
|
||||
call->audiostream=audiostream=audio_stream_new2(linphone_call_get_bind_ip_for_stream(call,call->main_audio_stream_index),
|
||||
call->audiostream=audiostream=audio_stream_new2(lc->factory, linphone_call_get_bind_ip_for_stream(call,call->main_audio_stream_index),
|
||||
multicast_role == SalMulticastReceiver ? stream_desc->rtp_port : call->media_ports[call->main_audio_stream_index].rtp_port,
|
||||
multicast_role == SalMulticastReceiver ? 0 /*disabled for now*/ : call->media_ports[call->main_audio_stream_index].rtcp_port);
|
||||
if (multicast_role == SalMulticastReceiver)
|
||||
|
|
@ -2328,7 +2363,8 @@ void linphone_call_init_audio_stream(LinphoneCall *call){
|
|||
setup_dtls_params(call, &audiostream->ms);
|
||||
media_stream_reclaim_sessions(&audiostream->ms, &call->sessions[call->main_audio_stream_index]);
|
||||
}else{
|
||||
call->audiostream=audio_stream_new_with_sessions(&call->sessions[call->main_audio_stream_index]);
|
||||
call->audiostream=audio_stream_new_with_sessions(lc->factory, &call->sessions[call->main_audio_stream_index]);
|
||||
|
||||
}
|
||||
audiostream=call->audiostream;
|
||||
if (call->media_ports[call->main_audio_stream_index].rtp_port==-1){
|
||||
|
|
@ -2381,6 +2417,7 @@ void linphone_call_init_audio_stream(LinphoneCall *call){
|
|||
|
||||
rtp_session_get_transports(audiostream->ms.sessions.rtp_session,&meta_rtp,&meta_rtcp);
|
||||
if (meta_rtp_transport_get_endpoint(meta_rtp) == NULL) {
|
||||
ms_message("LinphoneCall[%p]: using custom audio RTP transport endpoint.", call);
|
||||
meta_rtp_transport_set_endpoint(meta_rtp,lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->media_ports[call->main_audio_stream_index].rtp_port));
|
||||
}
|
||||
if (meta_rtp_transport_get_endpoint(meta_rtcp) == NULL) {
|
||||
|
|
@ -2398,9 +2435,7 @@ void linphone_call_init_video_stream(LinphoneCall *call){
|
|||
#ifdef VIDEO_ENABLED
|
||||
LinphoneCore *lc=call->core;
|
||||
char* cname;
|
||||
char rtcp_tool[128];
|
||||
|
||||
snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
|
||||
const char *rtcp_tool = linphone_core_get_user_agent(call->core);
|
||||
|
||||
if (call->videostream == NULL){
|
||||
int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0);
|
||||
|
|
@ -2415,7 +2450,7 @@ void linphone_call_init_video_stream(LinphoneCall *call){
|
|||
if (remotedesc)
|
||||
stream_desc = sal_media_description_find_best_stream(remotedesc, SalVideo);
|
||||
|
||||
call->videostream=video_stream_new2(linphone_call_get_bind_ip_for_stream(call,call->main_video_stream_index),
|
||||
call->videostream=video_stream_new2(lc->factory, linphone_call_get_bind_ip_for_stream(call,call->main_video_stream_index),
|
||||
multicast_role == SalMulticastReceiver ? stream_desc->rtp_port : call->media_ports[call->main_video_stream_index].rtp_port,
|
||||
multicast_role == SalMulticastReceiver ? 0 /*disabled for now*/ : call->media_ports[call->main_video_stream_index].rtcp_port);
|
||||
if (multicast_role == SalMulticastReceiver)
|
||||
|
|
@ -2428,7 +2463,7 @@ void linphone_call_init_video_stream(LinphoneCall *call){
|
|||
setup_dtls_params(call, &call->videostream->ms);
|
||||
media_stream_reclaim_sessions(&call->videostream->ms, &call->sessions[call->main_video_stream_index]);
|
||||
}else{
|
||||
call->videostream=video_stream_new_with_sessions(&call->sessions[call->main_video_stream_index]);
|
||||
call->videostream=video_stream_new_with_sessions(lc->factory, &call->sessions[call->main_video_stream_index]);
|
||||
}
|
||||
|
||||
if (call->media_ports[call->main_video_stream_index].rtp_port==-1){
|
||||
|
|
@ -2449,6 +2484,7 @@ void linphone_call_init_video_stream(LinphoneCall *call){
|
|||
|
||||
rtp_session_get_transports(call->videostream->ms.sessions.rtp_session,&meta_rtp,&meta_rtcp);
|
||||
if (meta_rtp_transport_get_endpoint(meta_rtp) == NULL) {
|
||||
ms_message("LinphoneCall[%p]: using custom video RTP transport endpoint.", call);
|
||||
meta_rtp_transport_set_endpoint(meta_rtp,lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->media_ports[call->main_video_stream_index].rtp_port));
|
||||
}
|
||||
if (meta_rtp_transport_get_endpoint(meta_rtcp) == NULL) {
|
||||
|
|
@ -2472,7 +2508,7 @@ void linphone_call_init_text_stream(LinphoneCall *call){
|
|||
LinphoneCore *lc=call->core;
|
||||
char* cname;
|
||||
|
||||
if (call->textstream != NULL || !call->params->realtimetext_enabled) return;
|
||||
if (call->textstream != NULL) return;
|
||||
if (call->sessions[call->main_text_stream_index].rtp_session == NULL) {
|
||||
SalMulticastRole multicast_role = linphone_call_get_multicast_role(call, SalText);
|
||||
SalMediaDescription *remotedesc = NULL;
|
||||
|
|
@ -2480,7 +2516,7 @@ void linphone_call_init_text_stream(LinphoneCall *call){
|
|||
if (call->op) remotedesc = sal_call_get_remote_media_description(call->op);
|
||||
if (remotedesc) stream_desc = sal_media_description_find_best_stream(remotedesc, SalText);
|
||||
|
||||
call->textstream = textstream = text_stream_new2(linphone_call_get_bind_ip_for_stream(call,call->main_text_stream_index),
|
||||
call->textstream = textstream = text_stream_new2(lc->factory, linphone_call_get_bind_ip_for_stream(call,call->main_text_stream_index),
|
||||
multicast_role == SalMulticastReceiver ? stream_desc->rtp_port : call->media_ports[call->main_text_stream_index].rtp_port,
|
||||
multicast_role == SalMulticastReceiver ? 0 /*disabled for now*/ : call->media_ports[call->main_text_stream_index].rtcp_port);
|
||||
if (multicast_role == SalMulticastReceiver)
|
||||
|
|
@ -2492,7 +2528,7 @@ void linphone_call_init_text_stream(LinphoneCall *call){
|
|||
setup_dtls_params(call, &textstream->ms);
|
||||
media_stream_reclaim_sessions(&textstream->ms, &call->sessions[call->main_text_stream_index]);
|
||||
} else {
|
||||
call->textstream = text_stream_new_with_sessions(&call->sessions[call->main_text_stream_index]);
|
||||
call->textstream = text_stream_new_with_sessions(lc->factory, &call->sessions[call->main_text_stream_index]);
|
||||
}
|
||||
textstream = call->textstream;
|
||||
if (call->media_ports[call->main_text_stream_index].rtp_port == -1) {
|
||||
|
|
@ -2917,7 +2953,7 @@ static RtpSession * create_audio_rtp_io_session(LinphoneCall *call) {
|
|||
if (pt != NULL) {
|
||||
call->rtp_io_audio_profile = rtp_profile_new("RTP IO audio profile");
|
||||
rtp_profile_set_payload(call->rtp_io_audio_profile, ptnum, payload_type_clone(pt));
|
||||
rtp_session = ms_create_duplex_rtp_session(local_ip, local_port, -1);
|
||||
rtp_session = ms_create_duplex_rtp_session(local_ip, local_port, -1, ms_factory_get_mtu(lc->factory));
|
||||
rtp_session_set_profile(rtp_session, call->rtp_io_audio_profile);
|
||||
rtp_session_set_remote_addr_and_port(rtp_session, remote_ip, remote_port, -1);
|
||||
rtp_session_enable_rtcp(rtp_session, FALSE);
|
||||
|
|
@ -2942,7 +2978,6 @@ static void linphone_call_set_on_hold_file(LinphoneCall *call, const char *file)
|
|||
static void linphone_call_start_audio_stream(LinphoneCall *call, LinphoneCallState next_state, bool_t use_arc){
|
||||
LinphoneCore *lc=call->core;
|
||||
int used_pt=-1;
|
||||
char rtcp_tool[128]={0};
|
||||
const SalStreamDescription *stream;
|
||||
MSSndCard *playcard;
|
||||
MSSndCard *captcard;
|
||||
|
|
@ -2956,8 +2991,6 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, LinphoneCallSta
|
|||
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());
|
||||
|
||||
stream = sal_media_description_find_best_stream(call->resultdesc, SalAudio);
|
||||
if (stream && stream->dir!=SalStreamInactive && stream->rtp_port!=0){
|
||||
const char *rtp_addr=stream->rtp_addr[0]!='\0' ? stream->rtp_addr : call->resultdesc->addr;
|
||||
|
|
@ -3082,7 +3115,7 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, LinphoneCallSta
|
|||
}
|
||||
}
|
||||
|
||||
ms_media_stream_sessions_set_encryption_mandatory(&call->audiostream->ms.sessions,linphone_core_is_media_encryption_mandatory(call->core));
|
||||
ms_media_stream_sessions_set_encryption_mandatory(&call->audiostream->ms.sessions,call->current_params->encryption_mandatory);
|
||||
|
||||
if (next_state == LinphoneCallPaused && captcard == NULL && playfile != NULL){
|
||||
int pause_time=500;
|
||||
|
|
@ -3095,7 +3128,7 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, LinphoneCallSta
|
|||
if (call->params->in_conference){
|
||||
/*transform the graph to connect it to the conference filter */
|
||||
mute = stream->dir==SalStreamRecvOnly;
|
||||
linphone_call_add_to_conf(call, mute);
|
||||
linphone_conference_on_call_stream_starting(lc->conf_ctx, call, mute);
|
||||
}
|
||||
call->current_params->in_conference=call->params->in_conference;
|
||||
call->current_params->low_bandwidth=call->params->low_bandwidth;
|
||||
|
|
@ -3121,7 +3154,7 @@ static RtpSession * create_video_rtp_io_session(LinphoneCall *call) {
|
|||
if (pt != NULL) {
|
||||
call->rtp_io_video_profile = rtp_profile_new("RTP IO video profile");
|
||||
rtp_profile_set_payload(call->rtp_io_video_profile, ptnum, payload_type_clone(pt));
|
||||
rtp_session = ms_create_duplex_rtp_session(local_ip, local_port, -1);
|
||||
rtp_session = ms_create_duplex_rtp_session(local_ip, local_port, -1, ms_factory_get_mtu(lc->factory));
|
||||
rtp_session_set_profile(rtp_session, call->rtp_io_video_profile);
|
||||
rtp_session_set_remote_addr_and_port(rtp_session, remote_ip, remote_port, -1);
|
||||
rtp_session_enable_rtcp(rtp_session, FALSE);
|
||||
|
|
@ -3261,7 +3294,7 @@ static void linphone_call_start_video_stream(LinphoneCall *call, LinphoneCallSta
|
|||
used_pt, &io);
|
||||
}
|
||||
}
|
||||
ms_media_stream_sessions_set_encryption_mandatory(&call->videostream->ms.sessions,linphone_core_is_media_encryption_mandatory(call->core));
|
||||
ms_media_stream_sessions_set_encryption_mandatory(&call->videostream->ms.sessions,call->current_params->encryption_mandatory);
|
||||
_linphone_call_set_next_video_frame_decoded_trigger(call);
|
||||
}
|
||||
}else ms_warning("No video stream accepted.");
|
||||
|
|
@ -3309,7 +3342,7 @@ static void linphone_call_start_text_stream(LinphoneCall *call) {
|
|||
ms_media_stream_sessions_set_srtp_send_key_b64(&call->textstream->ms.sessions, tstream->crypto[0].algo, local_st_desc->crypto[crypto_idx].master_key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
configure_rtp_session_for_rtcp_fb(call, tstream);
|
||||
configure_rtp_session_for_rtcp_xr(lc, call, SalText);
|
||||
rtp_session_enable_rtcp_mux(call->textstream->ms.sessions.rtp_session, tstream->rtcp_mux);
|
||||
|
|
@ -3319,7 +3352,7 @@ static void linphone_call_start_text_stream(LinphoneCall *call) {
|
|||
text_stream_start(call->textstream, call->text_profile, rtp_addr, tstream->rtp_port, rtcp_addr, (linphone_core_rtcp_enabled(lc) && !is_multicast) ? (tstream->rtcp_port ? tstream->rtcp_port : tstream->rtp_port + 1) : 0, used_pt);
|
||||
ms_filter_add_notify_callback(call->textstream->rttsink, real_time_text_character_received, call, FALSE);
|
||||
|
||||
ms_media_stream_sessions_set_encryption_mandatory(&call->textstream->ms.sessions,linphone_core_is_media_encryption_mandatory(call->core));
|
||||
ms_media_stream_sessions_set_encryption_mandatory(&call->textstream->ms.sessions,call->current_params->encryption_mandatory);
|
||||
} else ms_warning("No text stream accepted.");
|
||||
} else {
|
||||
ms_message("No valid text stream defined.");
|
||||
|
|
@ -3381,6 +3414,16 @@ static void setZrtpCryptoTypesParameters(MSZrtpParams *params, LinphoneCore *lc)
|
|||
params->keyAgreementsCount = linphone_core_get_zrtp_key_agreement_suites(lc, params->keyAgreements);
|
||||
}
|
||||
|
||||
static void linphone_call_set_symmetric_rtp(LinphoneCall *call, bool_t val){
|
||||
int i;
|
||||
for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; ++i){
|
||||
MSMediaStreamSessions *mss = &call->sessions[i];
|
||||
if (mss->rtp_session){
|
||||
rtp_session_set_symmetric_rtp(mss->rtp_session, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
@ -3413,6 +3456,17 @@ void linphone_call_start_media_streams(LinphoneCall *call, LinphoneCallState nex
|
|||
return;
|
||||
}
|
||||
|
||||
if (call->ice_session != NULL){
|
||||
/*if there is an ICE session when we are about to start streams, then ICE will conduct the media path checking and authentication properly.
|
||||
* Symmetric RTP must be turned off*/
|
||||
linphone_call_set_symmetric_rtp(call, FALSE);
|
||||
}
|
||||
|
||||
if (call->params->media_encryption==LinphoneMediaEncryptionDTLS) {
|
||||
call->current_params->encryption_mandatory = TRUE;
|
||||
ms_message("Forcing encryption mandatory on call [%p]",call);
|
||||
}
|
||||
|
||||
call->nb_media_starts++;
|
||||
#if defined(VIDEO_ENABLED)
|
||||
if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->payloads!=NULL){
|
||||
|
|
@ -3426,7 +3480,7 @@ void linphone_call_start_media_streams(LinphoneCall *call, LinphoneCallState nex
|
|||
if (call->audiostream!=NULL) {
|
||||
linphone_call_start_audio_stream(call, next_state, use_arc);
|
||||
} else {
|
||||
ms_warning("DTLS no audio stream!");
|
||||
ms_warning("linphone_call_start_media_streams(): no audio stream!");
|
||||
}
|
||||
call->current_params->has_video=FALSE;
|
||||
if (call->videostream!=NULL) {
|
||||
|
|
@ -3437,6 +3491,8 @@ void linphone_call_start_media_streams(LinphoneCall *call, LinphoneCallState nex
|
|||
if (call->onhold_file && !call->params->in_conference && call->audiostream){
|
||||
MSFilter *player = audio_stream_open_remote_play(call->audiostream, call->onhold_file);
|
||||
if (player){
|
||||
int pause_time=500;
|
||||
ms_filter_call_method(player, MS_PLAYER_SET_LOOP, &pause_time);
|
||||
ms_filter_call_method_noarg(player, MS_PLAYER_START);
|
||||
}
|
||||
}
|
||||
|
|
@ -3468,6 +3524,10 @@ void linphone_call_start_media_streams(LinphoneCall *call, LinphoneCallState nex
|
|||
set_dtls_fingerprint_on_all_streams(call);
|
||||
|
||||
if ((call->ice_session != NULL) && (ice_session_state(call->ice_session) != IS_Completed)) {
|
||||
if (call->params->media_encryption==LinphoneMediaEncryptionDTLS) {
|
||||
call->current_params->update_call_when_ice_completed = FALSE;
|
||||
ms_message("Disabling update call when ice completed on call [%p]",call);
|
||||
}
|
||||
ice_session_start_connectivity_checks(call->ice_session);
|
||||
} else {
|
||||
/*should not start dtls until ice is completed*/
|
||||
|
|
@ -3587,6 +3647,7 @@ static void update_rtp_stats(LinphoneCall *call, int stream_index) {
|
|||
}
|
||||
|
||||
static void linphone_call_stop_audio_stream(LinphoneCall *call) {
|
||||
LinphoneCore *lc = call->core;
|
||||
if (call->audiostream!=NULL) {
|
||||
linphone_reporting_update_media_info(call, LINPHONE_CALL_STATS_AUDIO);
|
||||
media_stream_reclaim_sessions(&call->audiostream->ms,&call->sessions[call->main_audio_stream_index]);
|
||||
|
|
@ -3602,7 +3663,7 @@ static void linphone_call_stop_audio_stream(LinphoneCall *call) {
|
|||
audio_stream_get_local_rtp_stats(call->audiostream,&call->log->local_stats);
|
||||
linphone_call_log_fill_stats (call->log,(MediaStream*)call->audiostream);
|
||||
if (call->endpoint){
|
||||
linphone_call_remove_from_conf(call);
|
||||
linphone_conference_on_call_stream_stopping(lc->conf_ctx, call);
|
||||
}
|
||||
update_rtp_stats(call, call->main_audio_stream_index);
|
||||
audio_stream_stop(call->audiostream);
|
||||
|
|
@ -3893,7 +3954,7 @@ static bool_t ice_in_progress(LinphoneCallStats *stats){
|
|||
|
||||
/**
|
||||
* Indicates whether an operation is in progress at the media side.
|
||||
* It can a bad idea to initiate signaling operations (adding video, pausing the call, removing video, changing video parameters) while
|
||||
* It can be a bad idea to initiate signaling operations (adding video, pausing the call, removing video, changing video parameters) while
|
||||
* the media is busy in establishing the connection (typically ICE connectivity checks). It can result in failures generating loss of time
|
||||
* in future operations in the call.
|
||||
* Applications are invited to check this function after each call state change to decide whether certain operations are permitted or not.
|
||||
|
|
@ -4116,20 +4177,22 @@ static void report_bandwidth(LinphoneCall *call, MediaStream *as, MediaStream *v
|
|||
call->stats[LINPHONE_CALL_STATS_TEXT].rtcp_download_bandwidth=(ts_active) ? (float)(media_stream_get_rtcp_down_bw(ts)*1e-3) : 0.f;
|
||||
call->stats[LINPHONE_CALL_STATS_TEXT].rtcp_upload_bandwidth=(ts_active) ? (float)(media_stream_get_rtcp_up_bw(ts)*1e-3) : 0.f;
|
||||
|
||||
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;
|
||||
if (as) update_local_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO], as);
|
||||
if (call->core->send_call_stats_periodical_updates){
|
||||
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;
|
||||
if (as_active) update_local_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO], as);
|
||||
|
||||
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;
|
||||
if (vs) update_local_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO], vs);
|
||||
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;
|
||||
if (vs_active) update_local_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO], vs);
|
||||
|
||||
call->stats[LINPHONE_CALL_STATS_TEXT].updated|=LINPHONE_CALL_STATS_PERIODICAL_UPDATE;
|
||||
linphone_core_notify_call_stats_updated(call->core, call, &call->stats[LINPHONE_CALL_STATS_TEXT]);
|
||||
call->stats[LINPHONE_CALL_STATS_TEXT].updated=0;
|
||||
if (ts) update_local_stats(&call->stats[LINPHONE_CALL_STATS_TEXT], ts);
|
||||
call->stats[LINPHONE_CALL_STATS_TEXT].updated|=LINPHONE_CALL_STATS_PERIODICAL_UPDATE;
|
||||
linphone_core_notify_call_stats_updated(call->core, call, &call->stats[LINPHONE_CALL_STATS_TEXT]);
|
||||
call->stats[LINPHONE_CALL_STATS_TEXT].updated=0;
|
||||
if (ts_active) update_local_stats(&call->stats[LINPHONE_CALL_STATS_TEXT], ts);
|
||||
}
|
||||
|
||||
|
||||
ms_message( "Bandwidth usage for call [%p]:\n"
|
||||
|
|
@ -4174,40 +4237,6 @@ static void linphone_call_lost(LinphoneCall *call, LinphoneReason reason){
|
|||
ms_free(temp);
|
||||
}
|
||||
|
||||
static void change_ice_media_destinations(LinphoneCall *call) {
|
||||
const char *rtp_addr;
|
||||
const char *rtcp_addr;
|
||||
int rtp_port;
|
||||
int rtcp_port;
|
||||
bool_t result;
|
||||
|
||||
if (call->audiostream && ice_session_check_list(call->ice_session, call->main_audio_stream_index)) {
|
||||
result = ice_check_list_selected_valid_remote_candidate(ice_session_check_list(call->ice_session, call->main_audio_stream_index), &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port);
|
||||
if (result == TRUE) {
|
||||
ms_message("Change audio stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, rtp_port, rtcp_addr, rtcp_port);
|
||||
rtp_session_set_symmetric_rtp(call->audiostream->ms.sessions.rtp_session, FALSE);
|
||||
rtp_session_set_remote_addr_full(call->audiostream->ms.sessions.rtp_session, rtp_addr, rtp_port, rtcp_addr, rtcp_port);
|
||||
}
|
||||
}
|
||||
#ifdef VIDEO_ENABLED
|
||||
if (call->videostream && ice_session_check_list(call->ice_session, call->main_video_stream_index)) {
|
||||
result = ice_check_list_selected_valid_remote_candidate(ice_session_check_list(call->ice_session, call->main_video_stream_index), &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port);
|
||||
if (result == TRUE) {
|
||||
ms_message("Change video stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, rtp_port, rtcp_addr, rtcp_port);
|
||||
rtp_session_set_symmetric_rtp(call->videostream->ms.sessions.rtp_session, FALSE);
|
||||
rtp_session_set_remote_addr_full(call->videostream->ms.sessions.rtp_session, rtp_addr, rtp_port, rtcp_addr, rtcp_port);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (call->textstream && ice_session_check_list(call->ice_session, call->main_text_stream_index)) {
|
||||
result = ice_check_list_selected_valid_remote_candidate(ice_session_check_list(call->ice_session, call->main_text_stream_index), &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port);
|
||||
if (result == TRUE) {
|
||||
ms_message("Change text stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, rtp_port, rtcp_addr, rtcp_port);
|
||||
rtp_session_set_symmetric_rtp(call->textstream->ms.sessions.rtp_session, FALSE);
|
||||
rtp_session_set_remote_addr_full(call->textstream->ms.sessions.rtp_session, rtp_addr, rtp_port, rtcp_addr, rtcp_port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void linphone_call_on_ice_gathering_finished(LinphoneCall *call){
|
||||
int ping_time;
|
||||
|
|
@ -4244,38 +4273,27 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
|
|||
|
||||
switch (ice_session_state(call->ice_session)) {
|
||||
case IS_Completed:
|
||||
ice_session_select_candidates(call->ice_session);
|
||||
if (ice_session_role(call->ice_session) == IR_Controlling
|
||||
&& lp_config_get_int(call->core->config, "sip", "update_call_when_ice_completed", TRUE)) {
|
||||
params->internal_call_update = TRUE;
|
||||
linphone_core_update_call(call->core, call, params);
|
||||
}
|
||||
change_ice_media_destinations(call);
|
||||
start_dtls_on_all_streams(call);
|
||||
break;
|
||||
case IS_Failed:
|
||||
/* At least one ICE session has succeeded, so perform a call update. */
|
||||
if (ice_session_has_completed_check_list(call->ice_session) == TRUE) {
|
||||
ice_session_select_candidates(call->ice_session);
|
||||
if (ice_session_role(call->ice_session) == IR_Controlling) {
|
||||
/* At least one ICE session has succeeded, so perform a call update. */
|
||||
if (ice_session_role(call->ice_session) == IR_Controlling && params->update_call_when_ice_completed ) {
|
||||
params->internal_call_update = TRUE;
|
||||
linphone_core_update_call(call->core, call, params);
|
||||
}
|
||||
start_dtls_on_all_streams(call);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
linphone_core_update_ice_state_in_call_stats(call);
|
||||
linphone_call_params_unref(params);
|
||||
} else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) {
|
||||
|
||||
if (evd->info.ice_processing_successful==TRUE) {
|
||||
linphone_call_on_ice_gathering_finished(call);
|
||||
} else {
|
||||
ms_warning("No STUN answer from [%s], disabling ICE",linphone_core_get_stun_server(call->core));
|
||||
linphone_call_delete_ice_session(call);
|
||||
if (evd->info.ice_processing_successful==FALSE) {
|
||||
ms_warning("No STUN answer from [%s], continuing without STUN",linphone_core_get_stun_server(call->core));
|
||||
}
|
||||
linphone_call_on_ice_gathering_finished(call);
|
||||
switch (call->state) {
|
||||
case LinphoneCallUpdating:
|
||||
linphone_core_start_update_call(call->core, call);
|
||||
|
|
@ -4302,8 +4320,7 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
|
|||
linphone_core_update_ice_state_in_call_stats(call);
|
||||
}
|
||||
} else if (evt == ORTP_EVENT_ICE_RESTART_NEEDED) {
|
||||
ice_session_restart(call->ice_session);
|
||||
ice_session_set_role(call->ice_session, IR_Controlling);
|
||||
ice_session_restart(call->ice_session, IR_Controlling);
|
||||
linphone_core_update_call(call->core, call, call->current_params);
|
||||
}
|
||||
}
|
||||
|
|
@ -4362,6 +4379,28 @@ void linphone_call_notify_stats_updated(LinphoneCall *call, int stream_index){
|
|||
}
|
||||
}
|
||||
|
||||
static MediaStream * linphone_call_get_media_stream(LinphoneCall *call, int stream_index){
|
||||
if (stream_index == call->main_audio_stream_index)
|
||||
return (MediaStream*)call->audiostream;
|
||||
if (stream_index == call->main_video_stream_index)
|
||||
return (MediaStream*)call->videostream;
|
||||
if (stream_index == call->main_text_stream_index)
|
||||
return (MediaStream*)call->textstream;
|
||||
ms_error("linphone_call_get_media_stream(): no stream index %i", stream_index);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static OrtpEvQueue *linphone_call_get_event_queue(LinphoneCall *call, int stream_index){
|
||||
if (stream_index == call->main_audio_stream_index)
|
||||
return call->audiostream_app_evq;
|
||||
if (stream_index == call->main_video_stream_index)
|
||||
return call->videostream_app_evq;
|
||||
if (stream_index == call->main_text_stream_index)
|
||||
return call->textstream_app_evq;
|
||||
ms_error("linphone_call_get_event_queue(): no stream index %i", stream_index);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void linphone_call_handle_stream_events(LinphoneCall *call, int stream_index){
|
||||
MediaStream *ms = stream_index == call->main_audio_stream_index ? (MediaStream *)call->audiostream : (stream_index == call->main_video_stream_index ? (MediaStream *)call->videostream : (MediaStream *)call->textstream);
|
||||
OrtpEvQueue *evq;
|
||||
|
|
@ -4369,7 +4408,9 @@ void linphone_call_handle_stream_events(LinphoneCall *call, int stream_index){
|
|||
|
||||
if (ms){
|
||||
/* Ensure there is no dangling ICE check list. */
|
||||
if (call->ice_session == NULL) ms->ice_check_list = NULL;
|
||||
if (call->ice_session == NULL) {
|
||||
media_stream_set_ice_check_list(ms, NULL);
|
||||
}
|
||||
|
||||
switch(ms->type){
|
||||
case MSAudio:
|
||||
|
|
@ -4390,19 +4431,24 @@ void linphone_call_handle_stream_events(LinphoneCall *call, int stream_index){
|
|||
}
|
||||
}
|
||||
/*yes the event queue has to be taken at each iteration, because ice events may perform operations re-creating the streams*/
|
||||
while ((evq = stream_index == call->main_audio_stream_index ? call->audiostream_app_evq : (stream_index == call->main_video_stream_index ? call->videostream_app_evq : call->textstream_app_evq)) && (NULL != (ev=ortp_ev_queue_get(evq)))){
|
||||
while((evq = linphone_call_get_event_queue(call, stream_index)) != NULL && NULL != (ev=ortp_ev_queue_get(evq))){
|
||||
OrtpEventType evt=ortp_event_get_type(ev);
|
||||
OrtpEventData *evd=ortp_event_get_data(ev);
|
||||
|
||||
int stats_index = stream_index == call->main_audio_stream_index ? LINPHONE_CALL_STATS_AUDIO : (stream_index == call->main_video_stream_index ? LINPHONE_CALL_STATS_VIDEO : LINPHONE_CALL_STATS_TEXT);
|
||||
|
||||
/*and yes the MediaStream must be taken at each iteration, because it may have changed due to the handling of events
|
||||
* in this loop*/
|
||||
ms = linphone_call_get_media_stream(call, stream_index);
|
||||
|
||||
if (ms) linphone_call_stats_fill(&call->stats[stats_index],ms,ev);
|
||||
linphone_call_notify_stats_updated(call,stats_index);
|
||||
|
||||
if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
|
||||
if (stream_index == call->main_audio_stream_index)
|
||||
linphone_call_audiostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
|
||||
else if (stream_index == call->main_video_stream_index)
|
||||
else if (stream_index == call->main_video_stream_index) {
|
||||
propagate_encryption_changed(call);
|
||||
}
|
||||
} else if (evt == ORTP_EVENT_ZRTP_SAS_READY) {
|
||||
if (stream_index == call->main_audio_stream_index)
|
||||
linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified);
|
||||
|
|
@ -4531,6 +4577,10 @@ bool_t linphone_call_is_in_conference(const LinphoneCall *call) {
|
|||
return call->params->in_conference;
|
||||
}
|
||||
|
||||
LinphoneConference *linphone_call_get_conference(const LinphoneCall *call) {
|
||||
return call->conf_ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a zoom of the video displayed during a call.
|
||||
* @param call the call.
|
||||
|
|
@ -4732,7 +4782,7 @@ MSWebCam *linphone_call_get_video_device(const LinphoneCall *call) {
|
|||
LinphoneCallState state = linphone_call_get_state(call);
|
||||
bool_t paused = (state == LinphoneCallPausing) || (state == LinphoneCallPaused);
|
||||
if (paused || call->all_muted || (call->camera_enabled == FALSE))
|
||||
return get_nowebcam_device();
|
||||
return get_nowebcam_device(call->core->factory);
|
||||
else
|
||||
return call->core->video_conf.device;
|
||||
}
|
||||
|
|
@ -4774,8 +4824,10 @@ MSFormatType linphone_call_get_stream_type(LinphoneCall *call, int stream_index)
|
|||
return MSVideo;
|
||||
} else if (stream_index == call->main_text_stream_index) {
|
||||
return MSText;
|
||||
} else if (stream_index == call->main_audio_stream_index){
|
||||
return MSAudio;
|
||||
}
|
||||
return MSAudio;
|
||||
return MSUnknownMedia;
|
||||
}
|
||||
|
||||
RtpTransport* linphone_call_get_meta_rtp_transport(LinphoneCall *call, int stream_index) {
|
||||
|
|
@ -4834,6 +4886,7 @@ void linphone_call_repair_if_broken(LinphoneCall *call){
|
|||
/*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;
|
||||
|
||||
if (!call->core->media_network_reachable) return;
|
||||
|
||||
switch (call->state){
|
||||
case LinphoneCallStreamsRunning:
|
||||
|
|
@ -4841,15 +4894,15 @@ void linphone_call_repair_if_broken(LinphoneCall *call){
|
|||
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);
|
||||
ice_session_restart(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));
|
||||
ms_warning("linphone_call_resume_if_broken(): don't know what to do in state [%s]", linphone_call_state_to_string(call->state));
|
||||
call->broken = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -4863,4 +4916,3 @@ void linphone_call_refresh_sockets(LinphoneCall *call){
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -38,15 +38,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#define LINPHONE_HOSTNAME_SIZE 128
|
||||
|
||||
#ifndef LINPHONE_PUBLIC
|
||||
#define LINPHONE_PUBLIC MS2_PUBLIC
|
||||
#define LINPHONE_PUBLIC MS2_PUBLIC
|
||||
#endif
|
||||
|
||||
#ifndef LINPHONE_DEPRECATED
|
||||
#if defined(_MSC_VER)
|
||||
#define LINPHONE_DEPRECATED __declspec(deprecated)
|
||||
#else
|
||||
#define LINPHONE_DEPRECATED __attribute__ ((deprecated))
|
||||
#endif
|
||||
#define LINPHONE_DEPRECATED MS2_DEPRECATED
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -139,13 +135,12 @@ enum _LinphoneStreamType {
|
|||
* @ingroup initializing
|
||||
**/
|
||||
typedef enum _LinphoneStreamType LinphoneStreamType;
|
||||
|
||||
/**
|
||||
* Function returning a humain readable value for LinphoneStreamType.
|
||||
* @param LinphoneStreamType
|
||||
* @returns
|
||||
* Function returning a human readable value for LinphoneStreamType.
|
||||
* @ingroup initializing
|
||||
**/
|
||||
|
||||
|
||||
LINPHONE_PUBLIC const char *linphone_stream_type_to_string(const LinphoneStreamType);
|
||||
/**
|
||||
* Object that represents a SIP address.
|
||||
|
|
@ -412,6 +407,7 @@ LINPHONE_PUBLIC const char* linphone_privacy_to_string(LinphonePrivacy privacy);
|
|||
#include "event.h"
|
||||
#include "linphonefriend.h"
|
||||
#include "xmlrpc.h"
|
||||
#include "conference.h"
|
||||
#else
|
||||
#include "linphone/buffer.h"
|
||||
#include "linphone/call_log.h"
|
||||
|
|
@ -420,6 +416,7 @@ LINPHONE_PUBLIC const char* linphone_privacy_to_string(LinphonePrivacy privacy);
|
|||
#include "linphone/event.h"
|
||||
#include "linphone/linphonefriend.h"
|
||||
#include "linphone/xmlrpc.h"
|
||||
#include "linphone/conference.h"
|
||||
#endif
|
||||
|
||||
LINPHONE_PUBLIC LinphoneAddress * linphone_address_new(const char *addr);
|
||||
|
|
@ -431,10 +428,11 @@ LINPHONE_PUBLIC const char *linphone_address_get_display_name(const LinphoneAddr
|
|||
LINPHONE_PUBLIC const char *linphone_address_get_username(const LinphoneAddress *u);
|
||||
LINPHONE_PUBLIC const char *linphone_address_get_domain(const LinphoneAddress *u);
|
||||
LINPHONE_PUBLIC int linphone_address_get_port(const LinphoneAddress *u);
|
||||
LINPHONE_PUBLIC void linphone_address_set_display_name(LinphoneAddress *u, const char *display_name);
|
||||
LINPHONE_PUBLIC void linphone_address_set_username(LinphoneAddress *uri, const char *username);
|
||||
LINPHONE_PUBLIC void linphone_address_set_domain(LinphoneAddress *uri, const char *host);
|
||||
LINPHONE_PUBLIC void linphone_address_set_port(LinphoneAddress *uri, int port);
|
||||
LINPHONE_PUBLIC int linphone_address_set_display_name(LinphoneAddress *u, const char *display_name);
|
||||
LINPHONE_PUBLIC int linphone_address_set_username(LinphoneAddress *uri, const char *username);
|
||||
LINPHONE_PUBLIC int linphone_address_set_domain(LinphoneAddress *uri, const char *host);
|
||||
LINPHONE_PUBLIC int linphone_address_set_port(LinphoneAddress *uri, int port);
|
||||
LINPHONE_PUBLIC int linphone_address_set_transport(LinphoneAddress *uri,LinphoneTransportType type);
|
||||
/*remove tags, params etc... so that it is displayable to the user*/
|
||||
LINPHONE_PUBLIC void linphone_address_clean(LinphoneAddress *uri);
|
||||
LINPHONE_PUBLIC bool_t linphone_address_is_secure(const LinphoneAddress *addr);
|
||||
|
|
@ -442,7 +440,8 @@ LINPHONE_PUBLIC bool_t linphone_address_get_secure(const LinphoneAddress *addr);
|
|||
LINPHONE_PUBLIC void linphone_address_set_secure(LinphoneAddress *addr, bool_t enabled);
|
||||
LINPHONE_PUBLIC bool_t linphone_address_is_sip(const LinphoneAddress *uri);
|
||||
LINPHONE_PUBLIC LinphoneTransportType linphone_address_get_transport(const LinphoneAddress *uri);
|
||||
LINPHONE_PUBLIC void linphone_address_set_transport(LinphoneAddress *uri,LinphoneTransportType type);
|
||||
LINPHONE_PUBLIC const char *linphone_address_get_method_param(const LinphoneAddress *addr);
|
||||
LINPHONE_PUBLIC void linphone_address_set_method_param(LinphoneAddress *addr, const char *method);
|
||||
LINPHONE_PUBLIC char *linphone_address_as_string(const LinphoneAddress *u);
|
||||
LINPHONE_PUBLIC char *linphone_address_as_string_uri_only(const LinphoneAddress *u);
|
||||
LINPHONE_PUBLIC bool_t linphone_address_weak_equal(const LinphoneAddress *a1, const LinphoneAddress *a2);
|
||||
|
|
@ -890,10 +889,19 @@ LINPHONE_PUBLIC void linphone_call_set_native_video_window_id(LinphoneCall *call
|
|||
* @param call #LinphoneCall
|
||||
* @return TRUE if part of a conference.
|
||||
*
|
||||
* @deprecated Use linphone_call_params_get_local_conference_mode(linphone_call_get_current_params(call)) instead.
|
||||
* @deprecated Use linphone_call_get_conference() instead.
|
||||
* @ingroup call_control
|
||||
*/
|
||||
LINPHONE_PUBLIC LINPHONE_DEPRECATED bool_t linphone_call_is_in_conference(const LinphoneCall *call);
|
||||
|
||||
/**
|
||||
* Return the associated conference object
|
||||
* @param call #LinphoneCall
|
||||
* @return A pointer on #LinphoneConference or NULL if the call is not part
|
||||
* of any conference.
|
||||
* @ingroup call_control
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneConference *linphone_call_get_conference(const LinphoneCall *call);
|
||||
/**
|
||||
* Enables or disable echo cancellation for this call
|
||||
* @param call
|
||||
|
|
@ -1035,8 +1043,6 @@ LINPHONE_PUBLIC const char *linphone_registration_state_to_string(LinphoneRegist
|
|||
* @}
|
||||
*/
|
||||
|
||||
#include "linphone_proxy_config.h"
|
||||
|
||||
/**
|
||||
* @addtogroup authentication
|
||||
* @{
|
||||
|
|
@ -1065,7 +1071,7 @@ LINPHONE_PUBLIC const char *linphone_registration_state_to_string(LinphoneRegist
|
|||
typedef struct _LinphoneAuthInfo LinphoneAuthInfo;
|
||||
|
||||
/**
|
||||
* Creates a #LinphoneAuthInfo object with supplied information.
|
||||
* Creates a #_LinphoneAuthInfo object with supplied information.
|
||||
* The object can be created empty, that is with all arguments set to NULL.
|
||||
* Username, userid, password, realm and domain can be set later using specific methods.
|
||||
* At the end, username and passwd (or ha1) are required.
|
||||
|
|
@ -1075,7 +1081,7 @@ typedef struct _LinphoneAuthInfo LinphoneAuthInfo;
|
|||
* @param ha1 The ha1-encrypted password if password is not given in clear text.
|
||||
* @param realm The authentication domain (which can be larger than the sip domain. Unfortunately many SIP servers don't use this parameter.
|
||||
* @param domain The SIP domain for which this authentication information is valid, if it has to be restricted for a single SIP domain.
|
||||
* @return A #LinphoneAuthInfo object. linphone_auth_info_destroy() must be used to destroy it when no longer needed. The LinphoneCore makes a copy of LinphoneAuthInfo
|
||||
* @return A #_LinphoneAuthInfo object. linphone_auth_info_destroy() must be used to destroy it when no longer needed. The LinphoneCore makes a copy of LinphoneAuthInfo
|
||||
* passed through linphone_core_add_auth_info().
|
||||
**/
|
||||
LINPHONE_PUBLIC LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *userid,
|
||||
|
|
@ -1084,42 +1090,42 @@ LINPHONE_PUBLIC LinphoneAuthInfo *linphone_auth_info_new(const char *username, c
|
|||
/**
|
||||
* @addtogroup authentication
|
||||
* Instantiates a new auth info with values from source.
|
||||
* @param[in] source The #LinphoneAuthInfo object to be cloned
|
||||
* @return The newly created #LinphoneAuthInfo object.
|
||||
* @param[in] source The #_LinphoneAuthInfo object to be cloned
|
||||
* @return The newly created #_LinphoneAuthInfo object.
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneAuthInfo *linphone_auth_info_clone(const LinphoneAuthInfo* source);
|
||||
|
||||
/**
|
||||
* Sets the password.
|
||||
* @param[in] info The #LinphoneAuthInfo object
|
||||
* @param[in] info The #_LinphoneAuthInfo object
|
||||
* @param[in] passwd The password.
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_auth_info_set_passwd(LinphoneAuthInfo *info, const char *passwd);
|
||||
|
||||
/**
|
||||
* Sets the username.
|
||||
* @param[in] info The #LinphoneAuthInfo object
|
||||
* @param[in] info The #_LinphoneAuthInfo object
|
||||
* @param[in] username The username.
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_auth_info_set_username(LinphoneAuthInfo *info, const char *username);
|
||||
|
||||
/**
|
||||
* Sets the userid.
|
||||
* @param[in] info The #LinphoneAuthInfo object
|
||||
* @param[in] info The #_LinphoneAuthInfo object
|
||||
* @param[in] userid The userid.
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_auth_info_set_userid(LinphoneAuthInfo *info, const char *userid);
|
||||
|
||||
/**
|
||||
* Sets the realm.
|
||||
* @param[in] info The #LinphoneAuthInfo object
|
||||
* @param[in] info The #_LinphoneAuthInfo object
|
||||
* @param[in] realm The realm.
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_auth_info_set_realm(LinphoneAuthInfo *info, const char *realm);
|
||||
|
||||
/**
|
||||
* Sets the domain for which this authentication is valid.
|
||||
* @param[in] info The #LinphoneAuthInfo object
|
||||
* @param[in] info The #_LinphoneAuthInfo object
|
||||
* @param[in] domain The domain.
|
||||
* This should not be necessary because realm is supposed to be unique and sufficient.
|
||||
* However, many SIP servers don't set realm correctly, then domain has to be used to distinguish between several SIP account bearing the same username.
|
||||
|
|
@ -1128,7 +1134,7 @@ LINPHONE_PUBLIC void linphone_auth_info_set_domain(LinphoneAuthInfo *info, const
|
|||
|
||||
/**
|
||||
* Sets the ha1.
|
||||
* @param[in] info The #LinphoneAuthInfo object
|
||||
* @param[in] info The #_LinphoneAuthInfo object
|
||||
* @param[in] ha1 The ha1.
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_auth_info_set_ha1(LinphoneAuthInfo *info, const char *ha1);
|
||||
|
|
@ -1136,7 +1142,7 @@ LINPHONE_PUBLIC void linphone_auth_info_set_ha1(LinphoneAuthInfo *info, const ch
|
|||
/**
|
||||
* Gets the username.
|
||||
*
|
||||
* @param[in] info The #LinphoneAuthInfo object
|
||||
* @param[in] info The #_LinphoneAuthInfo object
|
||||
* @return The username.
|
||||
*/
|
||||
LINPHONE_PUBLIC const char *linphone_auth_info_get_username(const LinphoneAuthInfo *info);
|
||||
|
|
@ -1144,7 +1150,7 @@ LINPHONE_PUBLIC const char *linphone_auth_info_get_username(const LinphoneAuthIn
|
|||
/**
|
||||
* Gets the password.
|
||||
*
|
||||
* @param[in] info The #LinphoneAuthInfo object
|
||||
* @param[in] info The #_LinphoneAuthInfo object
|
||||
* @return The password.
|
||||
*/
|
||||
LINPHONE_PUBLIC const char *linphone_auth_info_get_passwd(const LinphoneAuthInfo *info);
|
||||
|
|
@ -1152,7 +1158,7 @@ LINPHONE_PUBLIC const char *linphone_auth_info_get_passwd(const LinphoneAuthInfo
|
|||
/**
|
||||
* Gets the userid.
|
||||
*
|
||||
* @param[in] info The #LinphoneAuthInfo object
|
||||
* @param[in] info The #_LinphoneAuthInfo object
|
||||
* @return The userid.
|
||||
*/
|
||||
LINPHONE_PUBLIC const char *linphone_auth_info_get_userid(const LinphoneAuthInfo *info);
|
||||
|
|
@ -1160,7 +1166,7 @@ LINPHONE_PUBLIC const char *linphone_auth_info_get_userid(const LinphoneAuthInfo
|
|||
/**
|
||||
* Gets the realm.
|
||||
*
|
||||
* @param[in] info The #LinphoneAuthInfo object
|
||||
* @param[in] info The #_LinphoneAuthInfo object
|
||||
* @return The realm.
|
||||
*/
|
||||
LINPHONE_PUBLIC const char *linphone_auth_info_get_realm(const LinphoneAuthInfo *info);
|
||||
|
|
@ -1168,7 +1174,7 @@ LINPHONE_PUBLIC const char *linphone_auth_info_get_realm(const LinphoneAuthInfo
|
|||
/**
|
||||
* Gets the domain.
|
||||
*
|
||||
* @param[in] info The #LinphoneAuthInfo object
|
||||
* @param[in] info The #_LinphoneAuthInfo object
|
||||
* @return The domain.
|
||||
*/
|
||||
LINPHONE_PUBLIC const char *linphone_auth_info_get_domain(const LinphoneAuthInfo *info);
|
||||
|
|
@ -1176,7 +1182,7 @@ LINPHONE_PUBLIC const char *linphone_auth_info_get_domain(const LinphoneAuthInfo
|
|||
/**
|
||||
* Gets the ha1.
|
||||
*
|
||||
* @param[in] info The #LinphoneAuthInfo object
|
||||
* @param[in] info The #_LinphoneAuthInfo object
|
||||
* @return The ha1.
|
||||
*/
|
||||
LINPHONE_PUBLIC const char *linphone_auth_info_get_ha1(const LinphoneAuthInfo *info);
|
||||
|
|
@ -1192,8 +1198,14 @@ LINPHONE_PUBLIC LinphoneAuthInfo * linphone_auth_info_new_from_config_file(LpCon
|
|||
|
||||
#ifdef IN_LINPHONE
|
||||
#include "account_creator.h"
|
||||
#include "friendlist.h"
|
||||
#include "linphone_proxy_config.h"
|
||||
#include "carddav.h"
|
||||
#else
|
||||
#include "linphone/account_creator.h"
|
||||
#include "linphone/friendlist.h"
|
||||
#include "linphone/linphone_proxy_config.h"
|
||||
#include "linphone/carddav.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -1231,6 +1243,12 @@ typedef enum _LinphoneChatMessageState {
|
|||
LinphoneChatMessageStateFileTransferDone /**< File transfer has been completed successfully. */
|
||||
} LinphoneChatMessageState;
|
||||
|
||||
typedef enum _LinphoneLimeState {
|
||||
LinphoneLimeDisabled, /**< Lime is not used at all */
|
||||
LinphoneLimeMandatory, /**< Lime is always used */
|
||||
LinphoneLimePreferred, /**< Lime is used only if we already shared a secret with remote */
|
||||
} LinphoneLimeState;
|
||||
|
||||
/**
|
||||
* Call back used to notify message delivery status
|
||||
* @param msg #LinphoneChatMessage object
|
||||
|
|
@ -1238,7 +1256,7 @@ typedef enum _LinphoneChatMessageState {
|
|||
* @param ud application user data
|
||||
* @deprecated
|
||||
*/
|
||||
typedef LINPHONE_DEPRECATED void (*LinphoneChatMessageStateChangedCb)(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud);
|
||||
typedef void (*LinphoneChatMessageStateChangedCb)(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud);
|
||||
|
||||
/**
|
||||
* Call back used to notify message delivery status
|
||||
|
|
@ -1379,7 +1397,13 @@ LINPHONE_PUBLIC void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void
|
|||
*/
|
||||
LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_file_transfer_message(LinphoneChatRoom *cr, const LinphoneContent* initial_content);
|
||||
|
||||
/**
|
||||
* get peer address \link linphone_core_get_chat_room() associated to \endlink this #LinphoneChatRoom
|
||||
* @param cr #LinphoneChatRoom object
|
||||
* @return #LinphoneAddress peer address
|
||||
*/
|
||||
LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_room_get_peer_address(LinphoneChatRoom *cr);
|
||||
|
||||
/**
|
||||
* Send a message to peer member of this chat room.
|
||||
* @deprecated Use linphone_chat_room_send_chat_message() instead.
|
||||
|
|
@ -1543,7 +1567,7 @@ LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_from_address(co
|
|||
/**
|
||||
* Set destination of the message
|
||||
* @param[in] message #LinphoneChatMessage obj
|
||||
* @param[in] to #LinphoneAddress destination of this message (copied)
|
||||
* @param[in] addr #LinphoneAddress destination of this message (copied)
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_chat_message_set_to_address(LinphoneChatMessage* message, const LinphoneAddress* addr);
|
||||
/** @deprecated Use linphone_chat_message_get_to_address() instead. */
|
||||
|
|
@ -1631,11 +1655,7 @@ LINPHONE_PUBLIC void linphone_chat_message_set_user_data(LinphoneChatMessage* me
|
|||
* Returns the chatroom this message belongs to.
|
||||
**/
|
||||
LINPHONE_PUBLIC LinphoneChatRoom* linphone_chat_message_get_chat_room(LinphoneChatMessage *msg);
|
||||
/**
|
||||
* get peer address \link linphone_core_get_chat_room() associated to \endlink this #LinphoneChatRoom
|
||||
* @param cr #LinphoneChatRoom object
|
||||
* @return #LinphoneAddress peer address
|
||||
*/
|
||||
|
||||
LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_peer_address(LinphoneChatMessage *msg);
|
||||
/**
|
||||
* Returns the origin address of a message if it was a outgoing message, or the destination address if it was an incoming message.
|
||||
|
|
@ -1692,8 +1712,6 @@ LINPHONE_PUBLIC void linphone_chat_message_set_file_transfer_filepath(LinphoneCh
|
|||
*/
|
||||
LINPHONE_PUBLIC const char * linphone_chat_message_get_file_transfer_filepath(LinphoneChatMessage *msg);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Fulfill a chat message char by char. Message linked to a Real Time Text Call send char in realtime following RFC 4103/T.140
|
||||
* To commit a message, use #linphone_chat_room_send_message
|
||||
|
|
@ -2052,6 +2070,20 @@ typedef void (*LinphoneCoreLogCollectionUploadStateChangedCb)(LinphoneCore *lc,
|
|||
*/
|
||||
typedef void (*LinphoneCoreLogCollectionUploadProgressIndicationCb)(LinphoneCore *lc, size_t offset, size_t total);
|
||||
|
||||
/**
|
||||
* Callback prototype for reporting when a friend list has been added to the core friends list.
|
||||
* @param[in] lc LinphoneCore object
|
||||
* @param[in] list LinphoneFriendList object
|
||||
*/
|
||||
typedef void (*LinphoneCoreFriendListCreatedCb) (LinphoneCore *lc, LinphoneFriendList *list);
|
||||
|
||||
/**
|
||||
* Callback prototype for reporting when a friend list has been removed from the core friends list.
|
||||
* @param[in] lc LinphoneCore object
|
||||
* @param[in] list LinphoneFriendList object
|
||||
*/
|
||||
typedef void (*LinphoneCoreFriendListRemovedCb) (LinphoneCore *lc, LinphoneFriendList *list);
|
||||
|
||||
/**
|
||||
* This structure holds all callbacks that the application should implement.
|
||||
* None is mandatory.
|
||||
|
|
@ -2089,6 +2121,8 @@ typedef struct _LinphoneCoreVTable{
|
|||
LinphoneCoreNetworkReachableCb network_reachable; /**< Callback to report IP network status (I.E up/down )*/
|
||||
LinphoneCoreLogCollectionUploadStateChangedCb log_collection_upload_state_changed; /**< Callback to upload collected logs */
|
||||
LinphoneCoreLogCollectionUploadProgressIndicationCb log_collection_upload_progress_indication; /**< Callback to indicate log collection upload progress */
|
||||
LinphoneCoreFriendListCreatedCb friend_list_created;
|
||||
LinphoneCoreFriendListRemovedCb friend_list_removed;
|
||||
void *user_data; /**<User data associated with the above callbacks */
|
||||
} LinphoneCoreVTable;
|
||||
|
||||
|
|
@ -2122,7 +2156,7 @@ LINPHONE_PUBLIC LinphoneCoreVTable *linphone_core_get_current_vtable(LinphoneCor
|
|||
|
||||
/**
|
||||
* Destroy a vtable.
|
||||
* @param vtable to be destroyed
|
||||
* @param table to be destroyed
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_core_v_table_destroy(LinphoneCoreVTable* table);
|
||||
|
||||
|
|
@ -2289,8 +2323,36 @@ LINPHONE_PUBLIC void linphone_core_set_log_level(OrtpLogLevel loglevel);
|
|||
* @param loglevel A bitmask of the log levels to set.
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_core_set_log_level_mask(OrtpLogLevel loglevel);
|
||||
|
||||
/**
|
||||
* Enable logs in supplied FILE*.
|
||||
*
|
||||
* @ingroup misc
|
||||
* @deprecated Use #linphone_core_set_log_file and #linphone_core_set_log_level instead.
|
||||
*
|
||||
* @param file a C FILE* where to fprintf logs. If null stdout is used.
|
||||
*
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_core_enable_logs(FILE *file);
|
||||
|
||||
/**
|
||||
* Enable logs through the user's supplied log callback.
|
||||
*
|
||||
* @ingroup misc
|
||||
* @deprecated Use #linphone_core_set_log_handler and #linphone_core_set_log_level instead.
|
||||
*
|
||||
* @param logfunc The address of a OrtpLogFunc callback whose protoype is
|
||||
* typedef void (*OrtpLogFunc)(OrtpLogLevel lev, const char *fmt, va_list args);
|
||||
*
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_core_enable_logs_with_cb(OrtpLogFunc logfunc);
|
||||
|
||||
/**
|
||||
* Entirely disable logging.
|
||||
*
|
||||
* @ingroup misc
|
||||
* @deprecated Use #linphone_core_set_log_level instead.
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_core_disable_logs(void);
|
||||
|
||||
/**
|
||||
|
|
@ -2307,6 +2369,10 @@ LINPHONE_PUBLIC void linphone_core_serialize_logs(void);
|
|||
*
|
||||
**/
|
||||
LINPHONE_PUBLIC const char *linphone_core_get_version(void);
|
||||
|
||||
/**
|
||||
* @return liblinphone's user agent as a string.
|
||||
**/
|
||||
LINPHONE_PUBLIC const char *linphone_core_get_user_agent(LinphoneCore *lc);
|
||||
/**
|
||||
* @deprecated Use #linphone_core_get_user_agent instead.
|
||||
|
|
@ -2337,7 +2403,7 @@ LINPHONE_PUBLIC LINPHONE_DEPRECATED const char *linphone_core_get_user_agent_ver
|
|||
* @see linphone_core_new_with_config
|
||||
**/
|
||||
LINPHONE_PUBLIC LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable,
|
||||
const char *config_path, const char *factory_config, void* userdata);
|
||||
const char *config_path, const char *factory_config_path, void* userdata);
|
||||
|
||||
/**
|
||||
* Instantiates a LinphoneCore object with a given LpConfig.
|
||||
|
|
@ -2362,16 +2428,14 @@ LINPHONE_PUBLIC void linphone_core_iterate(LinphoneCore *lc);
|
|||
* add a listener to be notified of linphone core events. Once events are received, registered vtable are invoked in order.
|
||||
* @param vtable a LinphoneCoreVTable structure holding your application callbacks. Object is owned by linphone core until linphone_core_remove_listener.
|
||||
* @param lc object
|
||||
* @param string identifying the device, can be EMEI or UDID
|
||||
*
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_core_add_listener(LinphoneCore *lc, LinphoneCoreVTable *vtable);
|
||||
/**
|
||||
* @ingroup initializing
|
||||
* remove a listener registred by linphone_core_add_listener.
|
||||
* @param vtable a LinphoneCoreVTable structure holding your application callbacks
|
||||
* @param lc object
|
||||
* @param string identifying the device, can be EMEI or UDID
|
||||
* @param vtable a LinphoneCoreVTable structure holding your application callbacks
|
||||
*
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_core_remove_listener(LinphoneCore *lc, const LinphoneCoreVTable *vtable);
|
||||
|
|
@ -2526,8 +2590,9 @@ LINPHONE_PUBLIC bool_t linphone_core_get_guess_hostname(LinphoneCore *lc);
|
|||
* Tells to LinphoneCore to use Linphone Instant Messaging encryption
|
||||
*
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_core_enable_lime(LinphoneCore *lc, bool_t val);
|
||||
LINPHONE_PUBLIC bool_t linphone_core_lime_enabled(const LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC void linphone_core_enable_lime(LinphoneCore *lc, LinphoneLimeState val);
|
||||
LINPHONE_PUBLIC LinphoneLimeState linphone_core_lime_enabled(const LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC bool_t linphone_core_lime_available(const LinphoneCore *lc);
|
||||
|
||||
LINPHONE_PUBLIC bool_t linphone_core_ipv6_enabled(LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC void linphone_core_enable_ipv6(LinphoneCore *lc, bool_t val);
|
||||
|
|
@ -2680,6 +2745,16 @@ LINPHONE_PUBLIC void linphone_core_enable_dns_srv(LinphoneCore *lc, bool_t enabl
|
|||
*/
|
||||
LINPHONE_PUBLIC bool_t linphone_core_dns_srv_enabled(const LinphoneCore *lc);
|
||||
|
||||
/**
|
||||
* Forces liblinphone to use the supplied list of dns servers, instead of system's ones.
|
||||
* @param[in] lc #LinphoneCore object.
|
||||
* @param[in] a #MSList of strings containing the IP addresses of DNS servers to be used.
|
||||
* Setting to NULL restores default behaviour, which is to use the DNS server list provided by the system.
|
||||
* The list is copied internally.
|
||||
* @ingroup media_parameters
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_core_set_dns_servers(LinphoneCore *lc, const MSList *servers);
|
||||
|
||||
/**
|
||||
* Returns the list of available audio codecs.
|
||||
* @param[in] lc The LinphoneCore object
|
||||
|
|
@ -2895,7 +2970,7 @@ LINPHONE_PUBLIC void linphone_core_set_default_proxy_config(LinphoneCore *lc, Li
|
|||
* @param[in] ha1 String containing a ha1 hash of the password (optional, either passwd or ha1 must be set)
|
||||
* @param[in] realm String used to discriminate different SIP authentication domains (optional)
|
||||
* @param[in] domain String containing the SIP domain for which this authentication information is valid, if it has to be restricted for a single SIP domain.
|
||||
* @return #LinphoneAuthInfo with default values set
|
||||
* @return #_LinphoneAuthInfo with default values set
|
||||
* @ingroup authentication
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneAuthInfo * linphone_core_create_auth_info(LinphoneCore *lc, const char *username, const char *userid, const char *passwd, const char *ha1, const char *realm, const char *domain);
|
||||
|
|
@ -2913,7 +2988,7 @@ LINPHONE_PUBLIC const MSList *linphone_core_get_auth_info_list(const LinphoneCor
|
|||
* @param realm the authentication 'realm' (optional)
|
||||
* @param username the SIP username to be authenticated (mandatory)
|
||||
* @param domain the SIP domain name (optional)
|
||||
* @return a #LinphoneAuthInfo
|
||||
* @return a #_LinphoneAuthInfo
|
||||
**/
|
||||
LINPHONE_PUBLIC const LinphoneAuthInfo *linphone_core_find_auth_info(LinphoneCore *lc, const char *realm, const char *username, const char *sip_domain);
|
||||
|
||||
|
|
@ -3023,6 +3098,8 @@ LINPHONE_PUBLIC void linphone_core_get_sip_transports_used(LinphoneCore *lc, LCS
|
|||
|
||||
LINPHONE_PUBLIC bool_t linphone_core_sip_transport_supported(const LinphoneCore *lc, LinphoneTransportType tp);
|
||||
|
||||
LINPHONE_PUBLIC bool_t linphone_core_content_encoding_supported(const LinphoneCore *lc, const char *content_encoding);
|
||||
|
||||
/**
|
||||
*
|
||||
* Give access to the UDP sip socket. Can be useful to configure this socket as persistent I.E kCFStreamNetworkServiceType set to kCFStreamNetworkServiceTypeVoIP)
|
||||
|
|
@ -3197,6 +3274,10 @@ LINPHONE_PUBLIC void linphone_core_set_ring_during_incoming_early_media(Linphone
|
|||
LINPHONE_PUBLIC bool_t linphone_core_get_ring_during_incoming_early_media(const LinphoneCore *lc);
|
||||
|
||||
LINPHONE_PUBLIC int linphone_core_preview_ring(LinphoneCore *lc, const char *ring,LinphoneCoreCbFunc func,void * userdata);
|
||||
/**
|
||||
* Returns the MSFactory (mediastreamer2 factory) used by the LinphoneCore to control mediastreamer2 library.
|
||||
**/
|
||||
LINPHONE_PUBLIC MSFactory* linphone_core_get_ms_factory(LinphoneCore* lc);
|
||||
LINPHONE_PUBLIC int linphone_core_play_local(LinphoneCore *lc, const char *audiofile);
|
||||
LINPHONE_PUBLIC void linphone_core_enable_echo_cancellation(LinphoneCore *lc, bool_t val);
|
||||
LINPHONE_PUBLIC bool_t linphone_core_echo_cancellation_enabled(LinphoneCore *lc);
|
||||
|
|
@ -3423,7 +3504,7 @@ LINPHONE_PUBLIC bool_t linphone_core_video_capture_enabled(LinphoneCore *lc);
|
|||
LINPHONE_PUBLIC bool_t linphone_core_video_display_enabled(LinphoneCore *lc);
|
||||
|
||||
LINPHONE_PUBLIC void linphone_core_set_video_policy(LinphoneCore *lc, const LinphoneVideoPolicy *policy);
|
||||
LINPHONE_PUBLIC const LinphoneVideoPolicy *linphone_core_get_video_policy(LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC const LinphoneVideoPolicy *linphone_core_get_video_policy(const LinphoneCore *lc);
|
||||
|
||||
typedef struct MSVideoSizeDef{
|
||||
MSVideoSize vsize;
|
||||
|
|
@ -3631,6 +3712,15 @@ void linphone_core_show_video(LinphoneCore *lc, bool_t show);
|
|||
**/
|
||||
LINPHONE_PUBLIC void linphone_core_set_use_files(LinphoneCore *lc, bool_t yesno);
|
||||
|
||||
/**
|
||||
* Gets whether linphone is currently streaming audio from and to files, rather
|
||||
* than using the soundcard.
|
||||
* @ingroup media_parameters
|
||||
* @param[in] lc LinphoneCore object
|
||||
* @return A boolean value representing whether linphone is streaming audio from and to files or not.
|
||||
**/
|
||||
LINPHONE_PUBLIC bool_t linphone_core_get_use_files(LinphoneCore *lc);
|
||||
|
||||
/**
|
||||
* Get the wav file that is played when putting somebody on hold,
|
||||
* or when files are used instead of soundcards (see linphone_core_set_use_files()).
|
||||
|
|
@ -3699,6 +3789,22 @@ LINPHONE_PUBLIC void linphone_core_set_network_reachable(LinphoneCore* lc,bool_t
|
|||
*/
|
||||
LINPHONE_PUBLIC bool_t linphone_core_is_network_reachable(LinphoneCore* lc);
|
||||
|
||||
/**
|
||||
* @ingroup network_parameters
|
||||
* This method is called by the application to notify the linphone core library when the SIP network is reachable.
|
||||
* This is for advanced usage, when SIP and RTP layers are required to use different interfaces.
|
||||
* Most applications just need linphone_core_set_network_reachable().
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_core_set_sip_network_reachable(LinphoneCore* lc,bool_t value);
|
||||
|
||||
/**
|
||||
* @ingroup network_parameters
|
||||
* This method is called by the application to notify the linphone core library when the media (RTP) network is reachable.
|
||||
* This is for advanced usage, when SIP and RTP layers are required to use different interfaces.
|
||||
* Most applications just need linphone_core_set_network_reachable().
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_core_set_media_network_reachable(LinphoneCore* lc,bool_t value);
|
||||
|
||||
/**
|
||||
* @ingroup network_parameters
|
||||
* enable signaling keep alive. small udp packet sent periodically to keep udp NAT association
|
||||
|
|
@ -3794,6 +3900,14 @@ LINPHONE_PUBLIC void linphone_core_set_user_certificates_path(LinphoneCore *lc,
|
|||
*/
|
||||
LINPHONE_PUBLIC const char *linphone_core_get_user_certificates_path(LinphoneCore *lc);
|
||||
|
||||
/**
|
||||
* Reload mediastreamer2 plugins from specified directory.
|
||||
* @param[in] lc #LinphoneCore object.
|
||||
* @param[in] directory the path from where plugins are to be loaded, pass NULL to use default (compile-time determined) plugin directory.
|
||||
* @ingroup initializing
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_core_reload_ms_plugins(LinphoneCore *lc, const char *path);
|
||||
|
||||
/**
|
||||
* Search from the list of current calls if a remote address match uri
|
||||
* @ingroup call_control
|
||||
|
|
@ -3803,8 +3917,36 @@ LINPHONE_PUBLIC const char *linphone_core_get_user_certificates_path(LinphoneCor
|
|||
*/
|
||||
LINPHONE_PUBLIC LinphoneCall* linphone_core_find_call_from_uri(const LinphoneCore *lc, const char *uri);
|
||||
|
||||
LINPHONE_PUBLIC int linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *call);
|
||||
LINPHONE_PUBLIC int linphone_core_add_all_to_conference(LinphoneCore *lc);
|
||||
/**
|
||||
* @addtogroup call_control
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a conference
|
||||
* @param lc The #LinphoneCore instance where the conference will be created inside.
|
||||
* @param params Parameters of the conference. See #LinphoneConferenceParms.
|
||||
* @return A pointer on the freshly created conference. That object will be automatically
|
||||
* freed by the core after calling linphone_core_terminate_conference().
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneConference *linphone_core_create_conference_with_params(LinphoneCore *lc, const LinphoneConferenceParams *params);
|
||||
/**
|
||||
* Add a participant to the conference. If no conference is going on
|
||||
* a new internal conference context is created and the participant is
|
||||
* added to it.
|
||||
* @param lc #LinphoneCore
|
||||
* @param call The current call with the participant to add
|
||||
* @return 0 if succeeded. Negative number if failed
|
||||
*/
|
||||
LINPHONE_PUBLIC int linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *call);
|
||||
/**
|
||||
* Add all current calls into the conference. If no conference is running
|
||||
* a new internal conference context is created and all current calls
|
||||
* are added to it.
|
||||
* @param lc #LinphoneCore
|
||||
* @return 0 if succeeded. Negative number if failed
|
||||
*/
|
||||
LINPHONE_PUBLIC int linphone_core_add_all_to_conference(LinphoneCore *lc);
|
||||
/**
|
||||
* Remove a call from the conference.
|
||||
* @param lc the linphone core
|
||||
|
|
@ -3820,21 +3962,75 @@ LINPHONE_PUBLIC int linphone_core_add_all_to_conference(LinphoneCore *lc);
|
|||
*
|
||||
* @return 0 if successful, -1 otherwise.
|
||||
**/
|
||||
LINPHONE_PUBLIC int linphone_core_remove_from_conference(LinphoneCore *lc, LinphoneCall *call);
|
||||
LINPHONE_PUBLIC int linphone_core_remove_from_conference(LinphoneCore *lc, LinphoneCall *call);
|
||||
/**
|
||||
* Indicates whether the local participant is part of a conference.
|
||||
* @warning That function automatically fails in the case of conferences using a
|
||||
* conferencet server (focus). If you use such a conference, you should use
|
||||
* linphone_conference_remove_participant() instead.
|
||||
* @param lc the linphone core
|
||||
* @return TRUE if the local participant is in a conference, FALSE otherwise.
|
||||
**/
|
||||
LINPHONE_PUBLIC bool_t linphone_core_is_in_conference(const LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC int linphone_core_enter_conference(LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC int linphone_core_leave_conference(LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC float linphone_core_get_conference_local_input_volume(LinphoneCore *lc);
|
||||
|
||||
LINPHONE_PUBLIC int linphone_core_terminate_conference(LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC int linphone_core_get_conference_size(LinphoneCore *lc);
|
||||
*/
|
||||
LINPHONE_PUBLIC bool_t linphone_core_is_in_conference(const LinphoneCore *lc);
|
||||
/**
|
||||
* Join the local participant to the running conference
|
||||
* @param lc #LinphoneCore
|
||||
* @return 0 if succeeded. Negative number if failed
|
||||
*/
|
||||
LINPHONE_PUBLIC int linphone_core_enter_conference(LinphoneCore *lc);
|
||||
/**
|
||||
* Make the local participant leave the running conference
|
||||
* @param lc #LinphoneCore
|
||||
* @return 0 if succeeded. Negative number if failed
|
||||
*/
|
||||
LINPHONE_PUBLIC int linphone_core_leave_conference(LinphoneCore *lc);
|
||||
/**
|
||||
* Get the set input volume of the local participant
|
||||
* @param lc #LinphoneCore
|
||||
* @return A value inside [0.0 ; 1.0]
|
||||
*/
|
||||
LINPHONE_PUBLIC float linphone_core_get_conference_local_input_volume(LinphoneCore *lc);
|
||||
/**
|
||||
* Terminate the running conference. If it is a local conference, all calls
|
||||
* inside it will become back separate calls and will be put in #LinphoneCallPaused state.
|
||||
* If it is a conference involving a focus server, all calls inside the conference
|
||||
* will be terminated.
|
||||
* @param lc #LinphoneCore
|
||||
* @return 0 if succeeded. Negative number if failed
|
||||
*/
|
||||
LINPHONE_PUBLIC int linphone_core_terminate_conference(LinphoneCore *lc);
|
||||
/**
|
||||
* Get the number of participant in the running conference. The local
|
||||
* participant is included in the count only if it is in the conference.
|
||||
* @param lc #LinphoneCore
|
||||
* @return The number of participant
|
||||
*/
|
||||
LINPHONE_PUBLIC int linphone_core_get_conference_size(LinphoneCore *lc);
|
||||
/**
|
||||
* Start recording the running conference
|
||||
* @param lc #LinphoneCore
|
||||
* @param path Path to the file where the recording will be written
|
||||
* @return 0 if succeeded. Negative number if failed
|
||||
*/
|
||||
LINPHONE_PUBLIC int linphone_core_start_conference_recording(LinphoneCore *lc, const char *path);
|
||||
/**
|
||||
* Stop recording the running conference
|
||||
* @param #LinphoneCore
|
||||
* @return 0 if succeeded. Negative number if failed
|
||||
*/
|
||||
LINPHONE_PUBLIC int linphone_core_stop_conference_recording(LinphoneCore *lc);
|
||||
/**
|
||||
* Get a pointer on the internal conference object.
|
||||
* @param lc #LinphoneCore
|
||||
* @return A pointer on #LinphoneConference or NULL if no conference are going on
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneConference *linphone_core_get_conference(LinphoneCore *lc);
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get the maximum number of simultaneous calls Linphone core can manage at a time. All new call above this limit are declined with a busy answer
|
||||
* @ingroup initializing
|
||||
|
|
@ -4035,6 +4231,15 @@ LINPHONE_PUBLIC const char * linphone_core_get_file_transfer_server(LinphoneCore
|
|||
**/
|
||||
LINPHONE_PUBLIC const char ** linphone_core_get_supported_file_formats(LinphoneCore *core);
|
||||
|
||||
/**
|
||||
* Returns whether a specific file format is supported.
|
||||
* @see linphone_core_get_supported_file_formats
|
||||
* @param lc the core
|
||||
* @param the format extension (wav, mkv).
|
||||
* @ingroup media_paramaters
|
||||
**/
|
||||
LINPHONE_PUBLIC bool_t linphone_core_file_format_supported(LinphoneCore *lc, const char *fmt);
|
||||
|
||||
LINPHONE_PUBLIC void linphone_core_add_supported_tag(LinphoneCore *core, const char *tag);
|
||||
|
||||
LINPHONE_PUBLIC void linphone_core_remove_supported_tag(LinphoneCore *core, const char *tag);
|
||||
|
|
@ -4057,7 +4262,7 @@ LINPHONE_PUBLIC int linphone_core_get_avpf_rr_interval(const LinphoneCore *lc);
|
|||
LINPHONE_PUBLIC int linphone_core_set_audio_multicast_addr(LinphoneCore *core, const char* ip);
|
||||
/**
|
||||
* Use to set multicast address to be used for video stream.
|
||||
* @param core #LinphoneCore
|
||||
* @param lc #LinphoneCore
|
||||
* @param ip an ipv4/6 multicast address
|
||||
* @return 0 in case of success
|
||||
* @ingroup media_parameters
|
||||
|
|
@ -4232,7 +4437,6 @@ LINPHONE_PUBLIC const char* linphone_transport_to_string(LinphoneTransportType t
|
|||
**/
|
||||
LINPHONE_PUBLIC LinphoneTransportType linphone_transport_parse(const char* transport);
|
||||
|
||||
|
||||
/**
|
||||
* @ingroup media_parameters
|
||||
* Get default call parameters reflecting current linphone core configuration
|
||||
|
|
@ -4242,6 +4446,11 @@ LINPHONE_PUBLIC LinphoneTransportType linphone_transport_parse(const char* trans
|
|||
*/
|
||||
LINPHONE_PUBLIC LINPHONE_DEPRECATED LinphoneCallParams *linphone_core_create_default_call_parameters(LinphoneCore *lc);
|
||||
|
||||
typedef struct _LinphoneRingtonePlayer LinphoneRingtonePlayer;
|
||||
|
||||
LINPHONE_PUBLIC LinphoneRingtonePlayer *linphone_core_get_ringtoneplayer(LinphoneCore *lc);
|
||||
|
||||
#include "ringtoneplayer.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -44,7 +44,7 @@ bool_t lsd_player_loop_enabled(const LsdPlayer *p);
|
|||
void lsd_player_set_gain(LsdPlayer *p, float gain);
|
||||
LinphoneSoundDaemon *lsd_player_get_daemon(const LsdPlayer *p);
|
||||
|
||||
LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname, int rate, int nchannels);
|
||||
LinphoneSoundDaemon * linphone_sound_daemon_new(MSFactory* factory, const char *cardname, int rate, int nchannels);
|
||||
LsdPlayer * linphone_sound_daemon_get_player(LinphoneSoundDaemon *lsd);
|
||||
void linphone_sound_daemon_release_player(LinphoneSoundDaemon *lsd, LsdPlayer *lsdplayer);
|
||||
void linphone_sound_daemon_stop_all_players(LinphoneSoundDaemon *obj);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#define LINPHONEFRIEND_H_
|
||||
|
||||
#include "linphonepresence.h"
|
||||
#include "vcard.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
@ -118,15 +119,17 @@ typedef struct _LinphoneFriend LinphoneFriend;
|
|||
/**
|
||||
* Contructor
|
||||
* @return a new empty #LinphoneFriend
|
||||
* @deprecated use #linphone_core_create_friend instead
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneFriend * linphone_friend_new(void);
|
||||
LINPHONE_PUBLIC LINPHONE_DEPRECATED LinphoneFriend * linphone_friend_new(void);
|
||||
|
||||
/**
|
||||
* Contructor same as linphone_friend_new() + linphone_friend_set_address()
|
||||
* @param addr a buddy address, must be a sip uri like sip:joe@sip.linphone.org
|
||||
* @return a new #LinphoneFriend with \link linphone_friend_get_address() address initialized \endlink
|
||||
* @deprecated use #linphone_core_create_friend_with_address instead
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneFriend *linphone_friend_new_with_address(const char *addr);
|
||||
LINPHONE_PUBLIC LINPHONE_DEPRECATED LinphoneFriend *linphone_friend_new_with_address(const char *addr);
|
||||
|
||||
/**
|
||||
* Contructor same as linphone_friend_new() + linphone_friend_set_address()
|
||||
|
|
@ -240,6 +243,20 @@ LINPHONE_PUBLIC LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFr
|
|||
*/
|
||||
LINPHONE_PUBLIC const LinphonePresenceModel * linphone_friend_get_presence_model(LinphoneFriend *lf);
|
||||
|
||||
/**
|
||||
* Set the presence model of a friend
|
||||
* @param[in] lf A #LinphoneFriend object
|
||||
* @param[in] presence The #LinphonePresenceModel object to set for the friend
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_friend_set_presence_model(LinphoneFriend *lf, LinphonePresenceModel *presence);
|
||||
|
||||
/**
|
||||
* Tells whether we already received presence information for a friend.
|
||||
* @param[in] lf A #LinphoneFriend object
|
||||
* @return TRUE if presence information has been received for the friend, FALSE otherwise.
|
||||
*/
|
||||
LINPHONE_PUBLIC bool_t linphone_friend_is_presence_received(const LinphoneFriend *lf);
|
||||
|
||||
/**
|
||||
* Store user pointer to friend object.
|
||||
**/
|
||||
|
|
@ -338,13 +355,15 @@ LINPHONE_PUBLIC void linphone_core_interpret_friend_uri(LinphoneCore *lc, const
|
|||
* Add a friend to the current buddy list, if \link linphone_friend_enable_subscribes() subscription attribute \endlink is set, a SIP SUBSCRIBE message is sent.
|
||||
* @param lc #LinphoneCore object
|
||||
* @param fr #LinphoneFriend to add
|
||||
* @deprecated use linphone_friend_list_add_friend() instead.
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_core_add_friend(LinphoneCore *lc, LinphoneFriend *fr);
|
||||
|
||||
/**
|
||||
* remove a friend from the buddy list
|
||||
* Removes a friend from the buddy list
|
||||
* @param lc #LinphoneCore object
|
||||
* @param fr #LinphoneFriend to add
|
||||
* @param fr #LinphoneFriend to remove
|
||||
* @deprecated use linphone_friend_list_remove_friend() instead.
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_core_remove_friend(LinphoneCore *lc, LinphoneFriend *fr);
|
||||
|
||||
|
|
@ -359,6 +378,7 @@ LINPHONE_PUBLIC void linphone_core_reject_subscriber(LinphoneCore *lc, LinphoneF
|
|||
* Get Buddy list of LinphoneFriend
|
||||
* @param[in] lc #LinphoneCore object
|
||||
* @return \mslist{LinphoneFriend}
|
||||
* @deprecated use linphone_core_get_friends_lists() or linphone_friend_list_get_friends() instead.
|
||||
*/
|
||||
LINPHONE_PUBLIC const MSList * linphone_core_get_friend_list(const LinphoneCore *lc);
|
||||
|
||||
|
|
@ -403,14 +423,60 @@ LINPHONE_PUBLIC LinphoneFriend * linphone_friend_ref(LinphoneFriend *lf);
|
|||
|
||||
/**
|
||||
* Release a reference to the linphone friend.
|
||||
* @param[in] lf LinohoneFriend object
|
||||
* @param[in] lf LinphoneFriend object
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_friend_unref(LinphoneFriend *lf);
|
||||
|
||||
/**
|
||||
* Returns the LinphoneCore object managing this friend, if any.
|
||||
* @param[in] fr LinphoneFriend object
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneCore *linphone_friend_get_core(const LinphoneFriend *fr);
|
||||
|
||||
/**
|
||||
* Returns the vCard object associated to this friend, if any
|
||||
* @param[in] fr LinphoneFriend object
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneVcard* linphone_friend_get_vcard(LinphoneFriend *fr);
|
||||
|
||||
/**
|
||||
* Binds a vCard object to a friend
|
||||
* @param[in] fr LinphoneFriend object
|
||||
* @param[in] vcard The vCard object to bind
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_friend_set_vcard(LinphoneFriend *fr, LinphoneVcard *vcard);
|
||||
|
||||
/**
|
||||
* Creates a vCard object associated to this friend if there isn't one yet and if the full name is available, either by the parameter or the one in the friend's SIP URI
|
||||
* @param[in] fr LinphoneFriend object
|
||||
* @param[in] name The full name of the friend or NULL to use the one from the friend's SIP URI
|
||||
* @return true if the vCard has been created, false if it wasn't possible (for exemple if name and the friend's SIP URI are null or if the friend's SIP URI doesn't have a display name), or if there is already one vcard
|
||||
*/
|
||||
LINPHONE_PUBLIC bool_t linphone_friend_create_vcard(LinphoneFriend *fr, const char *name);
|
||||
|
||||
/**
|
||||
* Contructor same as linphone_friend_new() + linphone_friend_set_address()
|
||||
* @param vcard a vCard object
|
||||
* @return a new #LinphoneFriend with \link linphone_friend_get_vcard() vCard initialized \endlink
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneFriend *linphone_friend_new_from_vcard(LinphoneVcard *vcard);
|
||||
|
||||
/**
|
||||
* Sets the database filename where friends will be stored.
|
||||
* If the file does not exist, it will be created.
|
||||
* @ingroup initializing
|
||||
* @param lc the linphone core
|
||||
* @param path filesystem path
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_core_set_friends_database_path(LinphoneCore *lc, const char *path);
|
||||
|
||||
/**
|
||||
* Migrates the friends from the linphonerc to the database if not done yet
|
||||
* @ingroup initializing
|
||||
* @param lc the linphone core
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_core_migrate_friends_from_rc_to_db(LinphoneCore *lc);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -261,6 +261,21 @@ LINPHONE_PUBLIC char * linphone_presence_model_get_contact(const LinphonePresenc
|
|||
*/
|
||||
LINPHONE_PUBLIC int linphone_presence_model_set_contact(LinphonePresenceModel *model, const char *contact);
|
||||
|
||||
/**
|
||||
* Sets the presentity of a presence model.
|
||||
* @param[in] model The #LinphonePresenceModel object for which to set the contact.
|
||||
* @param[in] presentity The presentity address to set (presentity is copied).
|
||||
* @return 0 if successful, a value < 0 in case of error.
|
||||
*/
|
||||
LINPHONE_PUBLIC int linphone_presence_model_set_presentity(LinphonePresenceModel *model, const LinphoneAddress *presentity);
|
||||
/**
|
||||
* Gets the presentity of a presence model.
|
||||
* @param[in] model The #LinphonePresenceModel object to get the contact from.
|
||||
* @return A pointer to a const LinphoneAddress, or NULL if no contact is found.
|
||||
*
|
||||
*/
|
||||
LINPHONE_PUBLIC const LinphoneAddress * linphone_presence_model_get_presentity(const LinphonePresenceModel *model);
|
||||
|
||||
/**
|
||||
* Gets the first activity of a presence model (there is usually only one).
|
||||
* @param[in] model The #LinphonePresenceModel object to get the activity from.
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ LinphonePlayer *linphone_core_create_local_player(LinphoneCore *lc, MSSndCard *s
|
|||
LinphonePlayer *obj = ms_new0(LinphonePlayer, 1);
|
||||
if(snd_card == NULL) snd_card = lc->sound_conf.ring_sndcard;
|
||||
if(video_out == NULL) video_out = linphone_core_get_video_display_filter(lc);
|
||||
obj->impl = ms_media_player_new(snd_card, video_out, window_id);
|
||||
obj->impl = ms_media_player_new(lc->factory, snd_card, video_out, window_id);
|
||||
obj->open = _local_player_open;
|
||||
obj->start = _local_player_start;
|
||||
obj->pause = _local_player_pause;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,36 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include <libxml/xmlversion.h>
|
||||
|
||||
#define LPC2XML_BZ 2048
|
||||
#define ISO_ENCODING "ISO-8859-1"
|
||||
|
||||
static xmlChar* convert_iso_to_utf8(const char *in) {
|
||||
xmlChar *out = NULL;
|
||||
int ret, size, out_size, temp;
|
||||
xmlCharEncodingHandlerPtr handler;
|
||||
|
||||
size = (int)strlen(in) + 1;
|
||||
out_size = size * 2 - 1;
|
||||
out = ms_malloc((size_t)out_size);
|
||||
|
||||
if (out) {
|
||||
handler = xmlFindCharEncodingHandler(ISO_ENCODING);
|
||||
if (!handler) {
|
||||
ms_free(out);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
temp = size-1;
|
||||
ret = handler->input(out, &out_size, (const xmlChar *)in, &temp);
|
||||
if (ret < 0 || temp - size + 1) {
|
||||
ms_free(out);
|
||||
return NULL;
|
||||
} else {
|
||||
out = ms_realloc(out, out_size + 1);
|
||||
out[out_size] = '\0';
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
struct _lpc2xml_context {
|
||||
const LpConfig *lpc;
|
||||
|
|
@ -94,13 +124,24 @@ static void lpc2xml_genericxml_warning(void *ctx, const char *fmt, ...) {
|
|||
|
||||
static int processEntry(const char *section, const char *entry, xmlNode *node, lpc2xml_context *ctx) {
|
||||
const char *content = lp_config_get_string(ctx->lpc, section, entry, NULL);
|
||||
xmlChar *converted_content = NULL;
|
||||
if (content == NULL) {
|
||||
lpc2xml_log(ctx, LPC2XML_ERROR, "Issue when reading the lpc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
lpc2xml_log(ctx, LPC2XML_MESSAGE, "Set %s|%s = %s", section, entry, content);
|
||||
xmlNodeSetContent(node, (const xmlChar *) content);
|
||||
converted_content = convert_iso_to_utf8(content);
|
||||
|
||||
if (converted_content) {
|
||||
// xmlNodeSetContent expects special characters to be escaped, xmlNodeAddContent doesn't (and escapes what needs to be)
|
||||
xmlNodeSetContent(node, (const xmlChar *) "");
|
||||
xmlNodeAddContent(node, (const xmlChar *) converted_content);
|
||||
ms_free(converted_content);
|
||||
} else {
|
||||
// xmlNodeSetContent expects special characters to be escaped, xmlNodeAddContent doesn't (and escapes what needs to be)
|
||||
xmlNodeSetContent(node, (const xmlChar *) "");
|
||||
xmlNodeAddContent(node, (const xmlChar *) content);
|
||||
}
|
||||
|
||||
if (lp_config_get_overwrite_flag_for_entry(ctx->lpc, section, entry) || lp_config_get_overwrite_flag_for_section(ctx->lpc, section)) {
|
||||
xmlSetProp(node, (const xmlChar *)"overwrite", (const xmlChar *) "true");
|
||||
|
|
|
|||
|
|
@ -818,13 +818,13 @@ bool_t lp_config_relative_file_exists(const LpConfig *lpconfig, const char *file
|
|||
if (lpconfig->filename == NULL) {
|
||||
return FALSE;
|
||||
} else {
|
||||
char *filename = ms_strdup(lpconfig->filename);
|
||||
const char *dir = _lp_config_dirname(filename);
|
||||
char *conf_path = ms_strdup(lpconfig->filename);
|
||||
const char *dir = _lp_config_dirname(conf_path);
|
||||
char *filepath = ms_strdup_printf("%s/%s", dir, filename);
|
||||
char *realfilepath = lp_realpath(filepath, NULL);
|
||||
FILE *file;
|
||||
|
||||
ms_free(filename);
|
||||
ms_free(conf_path);
|
||||
ms_free(filepath);
|
||||
|
||||
if(realfilepath == NULL) return FALSE;
|
||||
|
|
@ -912,7 +912,7 @@ int lp_config_read_relative_file(const LpConfig *lpconfig, const char *filename,
|
|||
return 0;
|
||||
|
||||
err:
|
||||
ms_free(filepath);
|
||||
ms_free(dup_config_file);
|
||||
ms_free(filepath);
|
||||
if(realfilepath) ms_free(realfilepath);
|
||||
return -1;
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ struct _LinphoneSoundDaemon {
|
|||
|
||||
static MSFilter *create_writer(MSSndCard *c){
|
||||
LinphoneSoundDaemon *lsd=(LinphoneSoundDaemon*)c->data;
|
||||
MSFilter *itcsink=ms_filter_new(MS_ITC_SINK_ID);
|
||||
MSFilter *itcsink=ms_factory_create_filter(ms_snd_card_get_factory(c), MS_ITC_SINK_ID);
|
||||
ms_filter_call_method(itcsink,MS_ITC_SINK_CONNECT,lsd->branches[0].player);
|
||||
return itcsink;
|
||||
}
|
||||
|
|
@ -114,11 +114,11 @@ int lsd_player_stop(LsdPlayer *p){
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void lsd_player_init(LsdPlayer *p, MSConnectionPoint mixer, MSFilterId playerid, LinphoneSoundDaemon *lsd){
|
||||
static void lsd_player_init(MSFactory* factory, LsdPlayer *p, MSConnectionPoint mixer, MSFilterId playerid, LinphoneSoundDaemon *lsd){
|
||||
MSConnectionHelper h;
|
||||
p->player=ms_filter_new(playerid);
|
||||
p->rateconv=ms_filter_new(MS_RESAMPLE_ID);
|
||||
p->chanadapter=ms_filter_new(MS_CHANNEL_ADAPTER_ID);
|
||||
p->player=ms_factory_create_filter(factory, playerid);
|
||||
p->rateconv=ms_factory_create_filter(factory,MS_RESAMPLE_ID);
|
||||
p->chanadapter=ms_factory_create_filter(factory,MS_CHANNEL_ADAPTER_ID);
|
||||
|
||||
ms_connection_helper_start(&h);
|
||||
ms_connection_helper_link(&h,p->player,-1,0);
|
||||
|
|
@ -219,16 +219,15 @@ void lsd_player_set_gain(LsdPlayer *p, float gain){
|
|||
ms_filter_call_method(p->lsd->mixer,MS_AUDIO_MIXER_SET_INPUT_GAIN,&gainctl);
|
||||
}
|
||||
|
||||
LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname, int rate, int nchannels){
|
||||
LinphoneSoundDaemon * linphone_sound_daemon_new(MSFactory* factory, const char *cardname, int rate, int nchannels){
|
||||
int i;
|
||||
MSConnectionPoint mp;
|
||||
LinphoneSoundDaemon *lsd;
|
||||
MSSndCard *card=ms_snd_card_manager_get_card(
|
||||
ms_snd_card_manager_get(),
|
||||
MSSndCard *card=ms_snd_card_manager_get_card(ms_factory_get_snd_card_manager(factory),
|
||||
cardname);
|
||||
if (card==NULL){
|
||||
card=ms_snd_card_manager_get_default_playback_card (
|
||||
ms_snd_card_manager_get());
|
||||
ms_factory_get_snd_card_manager(factory));
|
||||
if (card==NULL){
|
||||
ms_error("linphone_sound_daemon_new(): No playback soundcard available");
|
||||
return NULL;
|
||||
|
|
@ -237,7 +236,7 @@ LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname, int rate,
|
|||
|
||||
lsd=ms_new0(LinphoneSoundDaemon,1);
|
||||
lsd->soundout=ms_snd_card_create_writer(card);
|
||||
lsd->mixer=ms_filter_new(MS_AUDIO_MIXER_ID);
|
||||
lsd->mixer=ms_factory_create_filter(ms_snd_card_get_factory(card),MS_AUDIO_MIXER_ID);
|
||||
lsd->out_rate=rate;
|
||||
lsd->out_nchans=nchannels;
|
||||
ms_filter_call_method(lsd->soundout,MS_FILTER_SET_SAMPLE_RATE,&lsd->out_rate);
|
||||
|
|
@ -248,11 +247,11 @@ LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname, int rate,
|
|||
mp.filter=lsd->mixer;
|
||||
mp.pin=0;
|
||||
|
||||
lsd_player_init(&lsd->branches[0],mp,MS_ITC_SOURCE_ID,lsd);
|
||||
lsd_player_init(factory, &lsd->branches[0],mp,MS_ITC_SOURCE_ID,lsd);
|
||||
ms_filter_add_notify_callback(lsd->branches[0].player,(MSFilterNotifyFunc)lsd_player_configure,&lsd->branches[0],FALSE);
|
||||
for(i=1;i<MAX_BRANCHES;++i){
|
||||
mp.pin=i;
|
||||
lsd_player_init(&lsd->branches[i],mp,MS_FILE_PLAYER_ID,lsd);
|
||||
lsd_player_init(factory,&lsd->branches[i],mp,MS_FILE_PLAYER_ID,lsd);
|
||||
}
|
||||
ms_filter_link(lsd->mixer,0,lsd->soundout,0);
|
||||
lsd->ticker=ms_ticker_new();
|
||||
|
|
|
|||
|
|
@ -253,7 +253,7 @@ void linphone_sql_request_all(sqlite3* db,const char *stmt, LinphoneCore* lc){
|
|||
}
|
||||
|
||||
static int linphone_chat_message_store_content(LinphoneChatMessage *msg) {
|
||||
LinphoneCore *lc = linphone_chat_room_get_lc(msg->chat_room);
|
||||
LinphoneCore *lc = linphone_chat_room_get_core(msg->chat_room);
|
||||
int id = -1;
|
||||
if (lc->db) {
|
||||
LinphoneContent *content = msg->file_transfer_information;
|
||||
|
|
@ -273,7 +273,7 @@ static int linphone_chat_message_store_content(LinphoneChatMessage *msg) {
|
|||
}
|
||||
|
||||
unsigned int linphone_chat_message_store(LinphoneChatMessage *msg){
|
||||
LinphoneCore *lc=linphone_chat_room_get_lc(msg->chat_room);
|
||||
LinphoneCore *lc=linphone_chat_room_get_core(msg->chat_room);
|
||||
int id = 0;
|
||||
|
||||
if (lc->db){
|
||||
|
|
@ -330,7 +330,7 @@ void linphone_chat_message_store_appdata(LinphoneChatMessage* msg){
|
|||
}
|
||||
|
||||
void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr){
|
||||
LinphoneCore *lc=linphone_chat_room_get_lc(cr);
|
||||
LinphoneCore *lc=linphone_chat_room_get_core(cr);
|
||||
int read=1;
|
||||
char *peer;
|
||||
char *buf;
|
||||
|
|
@ -351,7 +351,7 @@ void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr){
|
|||
}
|
||||
|
||||
void linphone_chat_room_update_url(LinphoneChatRoom *cr, LinphoneChatMessage *msg) {
|
||||
LinphoneCore *lc=linphone_chat_room_get_lc(cr);
|
||||
LinphoneCore *lc=linphone_chat_room_get_core(cr);
|
||||
char *buf;
|
||||
|
||||
if (lc->db==NULL) return ;
|
||||
|
|
@ -362,7 +362,7 @@ void linphone_chat_room_update_url(LinphoneChatRoom *cr, LinphoneChatMessage *ms
|
|||
}
|
||||
|
||||
static int linphone_chat_room_get_messages_count(LinphoneChatRoom *cr, bool_t unread_only){
|
||||
LinphoneCore *lc=linphone_chat_room_get_lc(cr);
|
||||
LinphoneCore *lc=linphone_chat_room_get_core(cr);
|
||||
int numrows=0;
|
||||
char *peer;
|
||||
char *buf;
|
||||
|
|
@ -433,7 +433,7 @@ void linphone_chat_room_delete_history(LinphoneChatRoom *cr){
|
|||
}
|
||||
|
||||
MSList *linphone_chat_room_get_history_range(LinphoneChatRoom *cr, int startm, int endm){
|
||||
LinphoneCore *lc=linphone_chat_room_get_lc(cr);
|
||||
LinphoneCore *lc=linphone_chat_room_get_core(cr);
|
||||
MSList *ret;
|
||||
char *buf,*buf2;
|
||||
char *peer;
|
||||
|
|
@ -468,11 +468,15 @@ MSList *linphone_chat_room_get_history_range(LinphoneChatRoom *cr, int startm, i
|
|||
ms_free(buf);
|
||||
buf = buf2;
|
||||
}
|
||||
|
||||
|
||||
begin=ortp_get_cur_time_ms();
|
||||
linphone_sql_request_message(lc->db,buf,cr);
|
||||
end=ortp_get_cur_time_ms();
|
||||
ms_message("%s(): completed in %i ms",__FUNCTION__, (int)(end-begin));
|
||||
|
||||
if (endm+1-startm > 1) {
|
||||
//display message only if at least 2 messages are loaded
|
||||
ms_message("%s(): completed in %i ms",__FUNCTION__, (int)(end-begin));
|
||||
}
|
||||
ms_free(buf);
|
||||
ret=cr->messages_hist;
|
||||
cr->messages_hist=NULL;
|
||||
|
|
|
|||
110
coreapi/misc.c
110
coreapi/misc.c
|
|
@ -94,8 +94,9 @@ void linphone_core_set_payload_type_number(LinphoneCore *lc, PayloadType *pt, in
|
|||
}
|
||||
|
||||
const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt){
|
||||
if (ms_filter_codec_supported(pt->mime_type)){
|
||||
MSFilterDesc *desc=ms_filter_get_encoder(pt->mime_type);
|
||||
//if (ms_filter_codec_supported(pt->mime_type)){
|
||||
if (ms_factory_codec_supported(lc->factory, pt->mime_type)){
|
||||
MSFilterDesc *desc=ms_factory_get_encoder(lc->factory, pt->mime_type);
|
||||
#ifdef ENABLE_NLS
|
||||
return dgettext("mediastreamer",desc->text);
|
||||
#else
|
||||
|
|
@ -260,7 +261,7 @@ bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, const Payloa
|
|||
&& linphone_core_echo_cancellation_enabled(lc)
|
||||
&& (pt->clock_rate!=16000 && pt->clock_rate!=8000)
|
||||
&& strcasecmp(pt->mime_type,"opus")!=0
|
||||
&& ms_filter_lookup_by_name("MSWebRTCAEC")!=NULL){
|
||||
&& ms_factory_lookup_filter_by_name(lc->factory, "MSWebRTCAEC")!=NULL){
|
||||
ms_warning("Payload type %s/%i cannot be used because software echo cancellation is required but is unable to operate at this rate.",
|
||||
pt->mime_type,pt->clock_rate);
|
||||
ret=FALSE;
|
||||
|
|
@ -623,16 +624,19 @@ const struct addrinfo *linphone_core_get_stun_server_addrinfo(LinphoneCore *lc){
|
|||
return lc->net_conf.stun_addrinfo;
|
||||
}
|
||||
|
||||
int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call)
|
||||
{
|
||||
void linphone_core_enable_forced_ice_relay(LinphoneCore *lc, bool_t enable) {
|
||||
lc->forced_ice_relay = enable;
|
||||
}
|
||||
|
||||
int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call){
|
||||
char local_addr[64];
|
||||
const struct addrinfo *ai;
|
||||
const struct addrinfo *ai = NULL;
|
||||
IceCheckList *audio_check_list;
|
||||
IceCheckList *video_check_list;
|
||||
IceCheckList *text_check_list;
|
||||
const char *server = linphone_core_get_stun_server(lc);
|
||||
|
||||
if ((server == NULL) || (call->ice_session == NULL)) return -1;
|
||||
if (call->ice_session == NULL) return -1;
|
||||
audio_check_list = ice_session_check_list(call->ice_session, call->main_audio_stream_index);
|
||||
video_check_list = ice_session_check_list(call->ice_session, call->main_video_stream_index);
|
||||
text_check_list = ice_session_check_list(call->ice_session, call->main_text_stream_index);
|
||||
|
|
@ -642,13 +646,18 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call)
|
|||
ms_warning("Ice gathering is not implemented for ipv6");
|
||||
return -1;
|
||||
}
|
||||
ai=linphone_core_get_stun_server_addrinfo(lc);
|
||||
if (ai==NULL){
|
||||
ms_warning("Fail to resolve STUN server for ICE gathering.");
|
||||
return -1;
|
||||
if (server){
|
||||
ai=linphone_core_get_stun_server_addrinfo(lc);
|
||||
if (ai==NULL){
|
||||
ms_warning("Fail to resolve STUN server for ICE gathering, continuing without stun.");
|
||||
}
|
||||
}else{
|
||||
ms_warning("Ice is used without stun server.");
|
||||
}
|
||||
linphone_core_notify_display_status(lc, _("ICE local candidates gathering in progress..."));
|
||||
|
||||
ice_session_enable_forced_relay(call->ice_session, lc->forced_ice_relay);
|
||||
|
||||
/* Gather local host candidates. */
|
||||
if (linphone_core_get_local_ip_for(AF_INET, NULL, local_addr) < 0) {
|
||||
ms_error("Fail to get local ip");
|
||||
|
|
@ -671,10 +680,17 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call)
|
|||
ice_add_local_candidate(text_check_list, "host", local_addr, call->media_ports[call->main_text_stream_index].rtcp_port, 2, NULL);
|
||||
call->stats[LINPHONE_CALL_STATS_TEXT].ice_state = LinphoneIceStateInProgress;
|
||||
}
|
||||
|
||||
ms_message("ICE: gathering candidate from [%s]",server);
|
||||
/* Gather local srflx candidates. */
|
||||
ice_session_gather_candidates(call->ice_session, ai->ai_addr, (socklen_t)ai->ai_addrlen);
|
||||
if (ai){
|
||||
ms_message("ICE: gathering candidate from [%s]",server);
|
||||
/* Gather local srflx candidates. */
|
||||
ice_session_gather_candidates(call->ice_session, ai->ai_addr, (socklen_t)ai->ai_addrlen);
|
||||
return 1;
|
||||
} else {
|
||||
ms_message("ICE: bypass candidates gathering");
|
||||
ice_session_compute_candidates_foundations(call->ice_session);
|
||||
ice_session_eliminate_redundant_candidates(call->ice_session);
|
||||
ice_session_choose_default_candidates(call->ice_session);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -724,6 +740,10 @@ void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call)
|
|||
case ICT_RelayedCandidate:
|
||||
call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateRelayConnection;
|
||||
break;
|
||||
case ICT_CandidateInvalid:
|
||||
case ICT_CandidateTypeMax:
|
||||
/*shall not happen*/
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateFailed;
|
||||
|
|
@ -743,6 +763,10 @@ void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call)
|
|||
case ICT_RelayedCandidate:
|
||||
call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateRelayConnection;
|
||||
break;
|
||||
case ICT_CandidateInvalid:
|
||||
case ICT_CandidateTypeMax:
|
||||
/*shall not happen*/
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateFailed;
|
||||
|
|
@ -762,6 +786,10 @@ void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call)
|
|||
case ICT_RelayedCandidate:
|
||||
call->stats[LINPHONE_CALL_STATS_TEXT].ice_state = LinphoneIceStateRelayConnection;
|
||||
break;
|
||||
case ICT_CandidateInvalid:
|
||||
case ICT_CandidateTypeMax:
|
||||
/*shall not happen*/
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
call->stats[LINPHONE_CALL_STATS_TEXT].ice_state = LinphoneIceStateFailed;
|
||||
|
|
@ -806,7 +834,7 @@ void linphone_call_stop_ice_for_inactive_streams(LinphoneCall *call, SalMediaDes
|
|||
linphone_core_update_ice_state_in_call_stats(call);
|
||||
}
|
||||
|
||||
void _update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session) {
|
||||
void _update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session, bool_t use_nortpproxy) {
|
||||
const char *rtp_addr, *rtcp_addr;
|
||||
IceSessionState session_state = ice_session_state(session);
|
||||
int nb_candidates;
|
||||
|
|
@ -814,7 +842,7 @@ void _update_local_media_description_from_ice(SalMediaDescription *desc, IceSess
|
|||
bool_t result;
|
||||
|
||||
if (session_state == IS_Completed) {
|
||||
desc->ice_completed = TRUE;
|
||||
if (use_nortpproxy) desc->set_nortpproxy = TRUE;
|
||||
result = ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, 0), &rtp_addr, NULL, NULL, NULL);
|
||||
if (result == TRUE) {
|
||||
strncpy(desc->addr, rtp_addr, sizeof(desc->addr));
|
||||
|
|
@ -823,7 +851,7 @@ void _update_local_media_description_from_ice(SalMediaDescription *desc, IceSess
|
|||
}
|
||||
}
|
||||
else {
|
||||
desc->ice_completed = FALSE;
|
||||
desc->set_nortpproxy = FALSE;
|
||||
}
|
||||
strncpy(desc->ice_pwd, ice_session_local_pwd(session), sizeof(desc->ice_pwd));
|
||||
strncpy(desc->ice_ufrag, ice_session_local_ufrag(session), sizeof(desc->ice_ufrag));
|
||||
|
|
@ -833,10 +861,10 @@ void _update_local_media_description_from_ice(SalMediaDescription *desc, IceSess
|
|||
nb_candidates = 0;
|
||||
if (!sal_stream_description_active(stream) || (cl == NULL)) continue;
|
||||
if (ice_check_list_state(cl) == ICL_Completed) {
|
||||
stream->ice_completed = TRUE;
|
||||
if (use_nortpproxy) stream->set_nortpproxy = TRUE;
|
||||
result = ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, i), &rtp_addr, &stream->rtp_port, &rtcp_addr, &stream->rtcp_port);
|
||||
} else {
|
||||
stream->ice_completed = FALSE;
|
||||
stream->set_nortpproxy = FALSE;
|
||||
result = ice_check_list_default_local_candidate(ice_session_check_list(session, i), &rtp_addr, &stream->rtp_port, &rtcp_addr, &stream->rtcp_port);
|
||||
}
|
||||
if (result == TRUE) {
|
||||
|
|
@ -944,8 +972,7 @@ void linphone_call_clear_unused_ice_candidates(LinphoneCall *call, const SalMedi
|
|||
}
|
||||
}
|
||||
|
||||
void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md)
|
||||
{
|
||||
void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md, bool_t is_offer){
|
||||
const SalStreamDescription *stream;
|
||||
IceCheckList *cl = NULL;
|
||||
bool_t default_candidate = FALSE;
|
||||
|
|
@ -975,14 +1002,14 @@ void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call,
|
|||
if (ice_params_found) {
|
||||
/* Check for ICE restart and set remote credentials. */
|
||||
if ((strcmp(md->addr, "0.0.0.0") == 0) || (strcmp(md->addr, "::0") == 0)) {
|
||||
ice_session_restart(call->ice_session);
|
||||
ice_session_restart(call->ice_session, is_offer ? IR_Controlled : IR_Controlling);
|
||||
ice_restarted = TRUE;
|
||||
} else {
|
||||
for (i = 0; i < md->nb_streams; i++) {
|
||||
stream = &md->streams[i];
|
||||
cl = ice_session_check_list(call->ice_session, i);
|
||||
if (cl && (strcmp(stream->rtp_addr, "0.0.0.0") == 0)) {
|
||||
ice_session_restart(call->ice_session);
|
||||
ice_session_restart(call->ice_session, is_offer ? IR_Controlled : IR_Controlling);
|
||||
ice_restarted = TRUE;
|
||||
break;
|
||||
}
|
||||
|
|
@ -992,7 +1019,7 @@ void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call,
|
|||
ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd);
|
||||
} else if (ice_session_remote_credentials_changed(call->ice_session, md->ice_ufrag, md->ice_pwd)) {
|
||||
if (ice_restarted == FALSE) {
|
||||
ice_session_restart(call->ice_session);
|
||||
ice_session_restart(call->ice_session, is_offer ? IR_Controlled : IR_Controlling);
|
||||
ice_restarted = TRUE;
|
||||
}
|
||||
ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd);
|
||||
|
|
@ -1005,8 +1032,8 @@ void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call,
|
|||
if (ice_restarted == FALSE
|
||||
&& ice_check_list_get_remote_ufrag(cl)
|
||||
&& ice_check_list_get_remote_pwd(cl)) {
|
||||
/* restart onlu if remote ufrag/paswd was already set*/
|
||||
ice_session_restart(call->ice_session);
|
||||
/* restart only if remote ufrag/paswd was already set*/
|
||||
ice_session_restart(call->ice_session, is_offer ? IR_Controlled : IR_Controlling);
|
||||
ice_restarted = TRUE;
|
||||
}
|
||||
ice_check_list_set_remote_credentials(cl, stream->ice_ufrag, stream->ice_pwd);
|
||||
|
|
@ -1178,6 +1205,16 @@ static int get_local_ip_with_getifaddrs(int type, char *address, int size){
|
|||
}
|
||||
#endif
|
||||
|
||||
static const char *ai_family_to_string(int af){
|
||||
switch(af){
|
||||
case AF_INET: return "AF_INET";
|
||||
case AF_INET6: return "AF_INET6";
|
||||
case AF_UNSPEC: return "AF_UNSPEC";
|
||||
default:
|
||||
return "invalid address family";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static int get_local_ip_for_with_connect(int type, const char *dest, char *result){
|
||||
int err,tmp;
|
||||
|
|
@ -1202,13 +1239,18 @@ static int get_local_ip_for_with_connect(int type, const char *dest, char *resul
|
|||
return -1;
|
||||
}
|
||||
sock=socket(res->ai_family,SOCK_DGRAM,0);
|
||||
if (sock == (ortp_socket_t)-1){
|
||||
ms_error("get_local_ip_for_with_connect() could not create [%s] socket: %s",
|
||||
ai_family_to_string(res->ai_family), getSocketError());
|
||||
return -1;
|
||||
}
|
||||
tmp=1;
|
||||
err=setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(SOCKET_OPTION_VALUE)&tmp,sizeof(int));
|
||||
if (err<0){
|
||||
if (err == -1){
|
||||
ms_warning("Error in setsockopt: %s",strerror(errno));
|
||||
}
|
||||
err=connect(sock,res->ai_addr,(int)res->ai_addrlen);
|
||||
if (err<0) {
|
||||
if (err == -1) {
|
||||
/*the network isn't reachable*/
|
||||
if (getSocketErrorCode()!=ENETUNREACH) ms_error("Error in connect: %s",strerror(errno));
|
||||
freeaddrinfo(res);
|
||||
|
|
@ -1817,13 +1859,21 @@ const char ** linphone_core_get_supported_file_formats(LinphoneCore *core){
|
|||
if (core->supported_formats==NULL){
|
||||
core->supported_formats=ms_malloc0(3*sizeof(char*));
|
||||
core->supported_formats[0]=wav;
|
||||
if (ms_factory_lookup_filter_by_id(ms_factory_get_fallback(),MS_MKV_RECORDER_ID)){
|
||||
if (ms_factory_lookup_filter_by_id(core->factory,MS_MKV_RECORDER_ID)){
|
||||
core->supported_formats[1]=mkv;
|
||||
}
|
||||
}
|
||||
return core->supported_formats;
|
||||
}
|
||||
|
||||
bool_t linphone_core_file_format_supported(LinphoneCore *lc, const char *fmt){
|
||||
const char **formats=linphone_core_get_supported_file_formats(lc);
|
||||
for(;*formats!=NULL;++formats){
|
||||
if (strcasecmp(*formats,fmt)==0) return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool_t linphone_core_symmetric_rtp_enabled(LinphoneCore*lc){
|
||||
return lp_config_get_int(lc->config,"rtp","symmetric",1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ static bool_t only_telephone_event(const MSList *l){
|
|||
static PayloadType * opus_match(MSOfferAnswerContext *ctx, const MSList *local_payloads, const PayloadType *refpt, const MSList *remote_payloads, bool_t reading_response){
|
||||
PayloadType *pt;
|
||||
const MSList *elem;
|
||||
PayloadType *candidate=NULL;
|
||||
PayloadType *legacy_opus=NULL;
|
||||
|
||||
for (elem=local_payloads;elem!=NULL;elem=elem->next){
|
||||
pt=(PayloadType*)elem->data;
|
||||
|
|
@ -43,14 +43,18 @@ static PayloadType * opus_match(MSOfferAnswerContext *ctx, const MSList *local_p
|
|||
/*workaround a bug in earlier versions of linphone where opus/48000/1 is offered, which is uncompliant with opus rtp draft*/
|
||||
if (strcasecmp(pt->mime_type,"opus")==0 ){
|
||||
if (refpt->channels==1){
|
||||
pt->channels=1; /*so that we respond with same number of channels */
|
||||
candidate=pt;
|
||||
legacy_opus=pt;
|
||||
}else if (refpt->channels==2){
|
||||
return payload_type_clone(pt);
|
||||
}
|
||||
}
|
||||
}
|
||||
return candidate ? payload_type_clone(candidate) : NULL;
|
||||
if (legacy_opus){
|
||||
legacy_opus = payload_type_clone(legacy_opus);
|
||||
legacy_opus->channels=1; /*so that we respond with same number of channels */
|
||||
return legacy_opus;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static MSOfferAnswerContext *opus_offer_answer_create_context(void){
|
||||
|
|
@ -145,7 +149,7 @@ static PayloadType * generic_match(const MSList *local_payloads, const PayloadTy
|
|||
|
||||
|
||||
void linphone_core_register_offer_answer_providers(LinphoneCore *lc){
|
||||
MSFactory *factory = ms_factory_get_fallback();
|
||||
MSFactory *factory = lc->factory;
|
||||
ms_factory_register_offer_answer_provider(factory, &red_offer_answer_provider);
|
||||
ms_factory_register_offer_answer_provider(factory, &g729a_offer_answer_provider);
|
||||
ms_factory_register_offer_answer_provider(factory, &opus_offer_answer_provider);
|
||||
|
|
@ -154,10 +158,10 @@ void linphone_core_register_offer_answer_providers(LinphoneCore *lc){
|
|||
/*
|
||||
* Returns a PayloadType from the local list that matches a PayloadType offered or answered in the remote list
|
||||
*/
|
||||
static PayloadType * find_payload_type_best_match(const MSList *local_payloads, const PayloadType *refpt,
|
||||
static PayloadType * find_payload_type_best_match(MSFactory *factory, const MSList *local_payloads, const PayloadType *refpt,
|
||||
const MSList *remote_payloads, bool_t reading_response){
|
||||
PayloadType *ret = NULL;
|
||||
MSOfferAnswerContext *ctx = ms_factory_create_offer_answer_context(ms_factory_get_fallback(), refpt->mime_type);
|
||||
MSOfferAnswerContext *ctx = ms_factory_create_offer_answer_context(factory, refpt->mime_type);
|
||||
if (ctx){
|
||||
ms_message("Doing offer/answer processing with specific provider for codec [%s]", refpt->mime_type);
|
||||
ret = ms_offer_answer_context_match_payload(ctx, local_payloads, refpt, remote_payloads, reading_response);
|
||||
|
|
@ -168,7 +172,7 @@ static PayloadType * find_payload_type_best_match(const MSList *local_payloads,
|
|||
}
|
||||
|
||||
|
||||
static MSList *match_payloads(const MSList *local, const MSList *remote, bool_t reading_response, bool_t one_matching_codec){
|
||||
static MSList *match_payloads(MSFactory *factory, const MSList *local, const MSList *remote, bool_t reading_response, bool_t one_matching_codec){
|
||||
const MSList *e2,*e1;
|
||||
MSList *res=NULL;
|
||||
PayloadType *matched;
|
||||
|
|
@ -176,7 +180,7 @@ static MSList *match_payloads(const MSList *local, const MSList *remote, bool_t
|
|||
|
||||
for(e2=remote;e2!=NULL;e2=e2->next){
|
||||
PayloadType *p2=(PayloadType*)e2->data;
|
||||
matched=find_payload_type_best_match(local, p2, remote, reading_response);
|
||||
matched=find_payload_type_best_match(factory, local, p2, remote, reading_response);
|
||||
if (matched){
|
||||
int local_number=payload_type_get_number(matched);
|
||||
int remote_number=payload_type_get_number(p2);
|
||||
|
|
@ -321,11 +325,11 @@ static SalStreamDir compute_dir_incoming(SalStreamDir local, SalStreamDir offere
|
|||
return res;
|
||||
}
|
||||
|
||||
static void initiate_outgoing(const SalStreamDescription *local_offer,
|
||||
static void initiate_outgoing(MSFactory* factory, const SalStreamDescription *local_offer,
|
||||
const SalStreamDescription *remote_answer,
|
||||
SalStreamDescription *result){
|
||||
if (remote_answer->rtp_port!=0)
|
||||
result->payloads=match_payloads(local_offer->payloads,remote_answer->payloads,TRUE,FALSE);
|
||||
result->payloads=match_payloads(factory, local_offer->payloads,remote_answer->payloads,TRUE,FALSE);
|
||||
else {
|
||||
ms_message("Local stream description [%p] rejected by peer",local_offer);
|
||||
result->rtp_port=0;
|
||||
|
|
@ -434,13 +438,14 @@ static void initiate_outgoing(const SalStreamDescription *local_offer,
|
|||
result->dtls_role = SalDtlsRoleInvalid;
|
||||
}
|
||||
result->rtcp_mux = remote_answer->rtcp_mux && local_offer->rtcp_mux;
|
||||
result->implicit_rtcp_fb = local_offer->implicit_rtcp_fb && remote_answer->implicit_rtcp_fb;
|
||||
}
|
||||
|
||||
|
||||
static void initiate_incoming(const SalStreamDescription *local_cap,
|
||||
static void initiate_incoming(MSFactory *factory, const SalStreamDescription *local_cap,
|
||||
const SalStreamDescription *remote_offer,
|
||||
SalStreamDescription *result, bool_t one_matching_codec){
|
||||
result->payloads=match_payloads(local_cap->payloads,remote_offer->payloads, FALSE, one_matching_codec);
|
||||
result->payloads=match_payloads(factory, local_cap->payloads,remote_offer->payloads, FALSE, one_matching_codec);
|
||||
result->proto=remote_offer->proto;
|
||||
result->type=local_cap->type;
|
||||
result->dir=compute_dir_incoming(local_cap->dir,remote_offer->dir);
|
||||
|
|
@ -475,14 +480,16 @@ static void initiate_incoming(const SalStreamDescription *local_cap,
|
|||
if (sal_stream_description_has_srtp(result) == TRUE) {
|
||||
/* select crypto algo */
|
||||
memset(result->crypto, 0, sizeof(result->crypto));
|
||||
if (!match_crypto_algo(local_cap->crypto, remote_offer->crypto, &result->crypto[0], &result->crypto_local_tag, TRUE))
|
||||
if (!match_crypto_algo(local_cap->crypto, remote_offer->crypto, &result->crypto[0], &result->crypto_local_tag, TRUE)) {
|
||||
result->rtp_port = 0;
|
||||
ms_message("No matching crypto algo for remote stream's offer [%p]",remote_offer);
|
||||
}
|
||||
|
||||
}
|
||||
strcpy(result->ice_pwd, local_cap->ice_pwd);
|
||||
strcpy(result->ice_ufrag, local_cap->ice_ufrag);
|
||||
result->ice_mismatch = local_cap->ice_mismatch;
|
||||
result->ice_completed = local_cap->ice_completed;
|
||||
result->set_nortpproxy = local_cap->set_nortpproxy;
|
||||
memcpy(result->ice_candidates, local_cap->ice_candidates, sizeof(result->ice_candidates));
|
||||
memcpy(result->ice_remote_candidates, local_cap->ice_remote_candidates, sizeof(result->ice_remote_candidates));
|
||||
strcpy(result->name,local_cap->name);
|
||||
|
|
@ -502,6 +509,7 @@ static void initiate_incoming(const SalStreamDescription *local_cap,
|
|||
result->dtls_role = SalDtlsRoleInvalid;
|
||||
}
|
||||
result->rtcp_mux = remote_offer->rtcp_mux && local_cap->rtcp_mux;
|
||||
result->implicit_rtcp_fb = local_cap->implicit_rtcp_fb && remote_offer->implicit_rtcp_fb;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -509,7 +517,7 @@ static void initiate_incoming(const SalStreamDescription *local_cap,
|
|||
* Returns a media description to run the streams with, based on a local offer
|
||||
* and the returned response (remote).
|
||||
**/
|
||||
int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
|
||||
int offer_answer_initiate_outgoing(MSFactory *factory, const SalMediaDescription *local_offer,
|
||||
const SalMediaDescription *remote_answer,
|
||||
SalMediaDescription *result){
|
||||
int i;
|
||||
|
|
@ -520,7 +528,7 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
|
|||
ls=&local_offer->streams[i];
|
||||
rs=&remote_answer->streams[i];
|
||||
if (rs && ls->proto == rs->proto && rs->type == ls->type) {
|
||||
initiate_outgoing(ls,rs,&result->streams[i]);
|
||||
initiate_outgoing(factory, ls,rs,&result->streams[i]);
|
||||
memcpy(&result->streams[i].rtcp_xr, &ls->rtcp_xr, sizeof(result->streams[i].rtcp_xr));
|
||||
if ((ls->rtcp_xr.enabled == TRUE) && (rs->rtcp_xr.enabled == FALSE)) {
|
||||
result->streams[i].rtcp_xr.enabled = FALSE;
|
||||
|
|
@ -548,7 +556,7 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
|
|||
* and the received offer.
|
||||
* The returned media description is an answer and should be sent to the offerer.
|
||||
**/
|
||||
int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities,
|
||||
int offer_answer_initiate_incoming(MSFactory *factory, const SalMediaDescription *local_capabilities,
|
||||
const SalMediaDescription *remote_offer,
|
||||
SalMediaDescription *result, bool_t one_matching_codec){
|
||||
int i;
|
||||
|
|
@ -558,7 +566,7 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities
|
|||
rs = &remote_offer->streams[i];
|
||||
ls = &local_capabilities->streams[i];
|
||||
if (ls && rs->type == ls->type && rs->proto == ls->proto){
|
||||
initiate_incoming(ls,rs,&result->streams[i],one_matching_codec);
|
||||
initiate_incoming(factory, 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;
|
||||
|
|
@ -599,7 +607,7 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities
|
|||
strcpy(result->ice_pwd, local_capabilities->ice_pwd);
|
||||
strcpy(result->ice_ufrag, local_capabilities->ice_ufrag);
|
||||
result->ice_lite = local_capabilities->ice_lite;
|
||||
result->ice_completed = local_capabilities->ice_completed;
|
||||
result->set_nortpproxy = local_capabilities->set_nortpproxy;
|
||||
result->custom_sdp_attributes = sal_custom_sdp_attribute_clone(local_capabilities->custom_sdp_attributes);
|
||||
|
||||
strcpy(result->name,local_capabilities->name);
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
* Returns a media description to run the streams with, based on a local offer
|
||||
* and the returned response (remote).
|
||||
**/
|
||||
int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
|
||||
int offer_answer_initiate_outgoing(MSFactory *factory, const SalMediaDescription *local_offer,
|
||||
const SalMediaDescription *remote_answer,
|
||||
SalMediaDescription *result);
|
||||
|
||||
|
|
@ -39,7 +39,7 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
|
|||
* and the received offer.
|
||||
* The returned media description is an answer and should be sent to the offerer.
|
||||
**/
|
||||
int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities,
|
||||
int offer_answer_initiate_incoming(MSFactory* factory, const SalMediaDescription *local_capabilities,
|
||||
const SalMediaDescription *remote_offer,
|
||||
SalMediaDescription *result, bool_t one_matching_codec);
|
||||
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ struct _LinphonePresencePerson {
|
|||
* This model is not complete. For example, it does not handle devices.
|
||||
*/
|
||||
struct _LinphonePresenceModel {
|
||||
LinphoneAddress *presentity; /* "The model seeks to describe the presentity, identified by a presentity URI.*/
|
||||
void *user_data;
|
||||
int refcnt;
|
||||
MSList *services; /**< A list of _LinphonePresenceService structures. Also named tuples in the RFC. */
|
||||
|
|
@ -157,7 +158,7 @@ static void presence_activity_delete(LinphonePresenceActivity *activity) {
|
|||
static time_t parse_timestamp(const char *timestamp) {
|
||||
struct tm ret;
|
||||
time_t seconds;
|
||||
#ifdef LINPHONE_WINDOWS_UNIVERSAL
|
||||
#if defined(LINPHONE_WINDOWS_UNIVERSAL) || defined(LINPHONE_MSC_VER_GREATER_19)
|
||||
long adjust_timezone;
|
||||
#else
|
||||
time_t adjust_timezone;
|
||||
|
|
@ -174,7 +175,7 @@ static time_t parse_timestamp(const char *timestamp) {
|
|||
ms_error("mktime() failed: %s", strerror(errno));
|
||||
return (time_t)-1;
|
||||
}
|
||||
#ifdef LINPHONE_WINDOWS_UNIVERSAL
|
||||
#if defined(LINPHONE_WINDOWS_UNIVERSAL) || defined(LINPHONE_MSC_VER_GREATER_19)
|
||||
_get_timezone(&adjust_timezone);
|
||||
#else
|
||||
adjust_timezone = timezone;
|
||||
|
|
@ -246,7 +247,8 @@ static void presence_model_find_open_basic_status(LinphonePresenceService *servi
|
|||
|
||||
static void presence_model_delete(LinphonePresenceModel *model) {
|
||||
if (model == NULL) return;
|
||||
|
||||
if (model->presentity)
|
||||
linphone_address_unref(model->presentity);
|
||||
ms_list_for_each(model->services, (MSIterateFunc)linphone_presence_service_unref);
|
||||
ms_list_free(model->services);
|
||||
ms_list_for_each(model->persons, (MSIterateFunc)linphone_presence_person_unref);
|
||||
|
|
@ -671,7 +673,22 @@ int linphone_presence_model_clear_persons(LinphonePresenceModel *model) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int linphone_presence_model_set_presentity(LinphonePresenceModel *model, const LinphoneAddress *presentity) {
|
||||
|
||||
if (model->presentity) {
|
||||
linphone_address_unref(model->presentity);
|
||||
model->presentity = NULL;
|
||||
}
|
||||
if (presentity) {
|
||||
model->presentity=linphone_address_clone(presentity);
|
||||
linphone_address_clean(model->presentity);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const LinphoneAddress * linphone_presence_model_get_presentity(const LinphonePresenceModel *model) {
|
||||
return model->presentity;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* PRESENCE SERVICE FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES *
|
||||
|
|
@ -1443,10 +1460,11 @@ 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);
|
||||
LinphoneFriend *fl=linphone_core_create_friend_with_address(lc,subscriber);
|
||||
char *tmp;
|
||||
|
||||
if (fl==NULL) return ;
|
||||
fl->lc = lc;
|
||||
linphone_friend_add_incoming_subscription(fl, op);
|
||||
linphone_friend_set_inc_subscribe_policy(fl,LinphoneSPAccept);
|
||||
fl->inc_subscribe_pending=TRUE;
|
||||
|
|
@ -1464,15 +1482,11 @@ void linphone_core_reject_subscriber(LinphoneCore *lc, LinphoneFriend *lf){
|
|||
}
|
||||
|
||||
void linphone_core_notify_all_friends(LinphoneCore *lc, LinphonePresenceModel *presence){
|
||||
MSList *elem;
|
||||
LinphonePresenceActivity *activity = linphone_presence_model_get_activity(presence);
|
||||
char *activity_str = linphone_presence_activity_to_string(activity);
|
||||
ms_message("Notifying all friends that we are [%s]", activity_str);
|
||||
if (activity_str != NULL) ms_free(activity_str);
|
||||
for(elem=lc->friends;elem!=NULL;elem=elem->next){
|
||||
LinphoneFriend *lf=(LinphoneFriend *)elem->data;
|
||||
linphone_friend_notify(lf,presence);
|
||||
}
|
||||
linphone_friend_list_notify_presence(linphone_core_get_default_friend_list(lc), presence);
|
||||
}
|
||||
|
||||
void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){
|
||||
|
|
@ -1486,7 +1500,10 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){
|
|||
ms_message("Receiving new subscription from %s.",from);
|
||||
|
||||
/* check if we answer to this subscription */
|
||||
if (linphone_find_friend_by_address(lc->friends,uri,&lf)!=NULL){
|
||||
if (linphone_core_get_default_friend_list(lc) != NULL) {
|
||||
lf = linphone_friend_list_find_friend_by_address(linphone_core_get_default_friend_list(lc), uri);
|
||||
}
|
||||
if (lf!=NULL){
|
||||
linphone_friend_add_incoming_subscription(lf, op);
|
||||
lf->inc_subscribe_pending=TRUE;
|
||||
sal_subscribe_accept(op);
|
||||
|
|
@ -1511,7 +1528,7 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){
|
|||
ms_free(tmp);
|
||||
}
|
||||
|
||||
void linphone_notify_parse_presence(SalOp *op, const char *content_type, const char *content_subtype, const char *body, SalPresenceModel **result) {
|
||||
void linphone_notify_parse_presence(const char *content_type, const char *content_subtype, const char *body, SalPresenceModel **result) {
|
||||
xmlparsing_context_t *xml_ctx;
|
||||
LinphonePresenceModel *model = NULL;
|
||||
|
||||
|
|
@ -1772,24 +1789,28 @@ static void write_xml_presence_person_obj(LinphonePresencePerson *person, struct
|
|||
if (err < 0) *st->err = err;
|
||||
}
|
||||
|
||||
void linphone_notify_convert_presence_to_xml(SalOp *op, SalPresenceModel *presence, const char *contact, char **content) {
|
||||
LinphonePresenceModel *model;
|
||||
xmlBufferPtr buf;
|
||||
xmlTextWriterPtr writer;
|
||||
char *linphone_presence_model_to_xml(LinphonePresenceModel *model) {
|
||||
xmlBufferPtr buf = NULL;
|
||||
xmlTextWriterPtr writer = NULL;
|
||||
int err;
|
||||
|
||||
if ((contact == NULL) || (content == NULL)) return;
|
||||
|
||||
model = (LinphonePresenceModel *)presence;
|
||||
char *contact = NULL;
|
||||
char * content = NULL;
|
||||
|
||||
if (model->presentity) {
|
||||
contact = linphone_address_as_string_uri_only(model->presentity);
|
||||
} else {
|
||||
ms_error("Cannot convert presence model [%p] to xml because no presentity set", model);
|
||||
goto end;
|
||||
}
|
||||
buf = xmlBufferCreate();
|
||||
if (buf == NULL) {
|
||||
ms_error("Error creating the XML buffer");
|
||||
return;
|
||||
goto end;
|
||||
}
|
||||
writer = xmlNewTextWriterMemory(buf, 0);
|
||||
if (writer == NULL) {
|
||||
ms_error("Error creating the XML writer");
|
||||
return;
|
||||
goto end;
|
||||
}
|
||||
|
||||
xmlTextWriterSetIndent(writer,1);
|
||||
|
|
@ -1815,7 +1836,7 @@ void linphone_notify_convert_presence_to_xml(SalOp *op, SalPresenceModel *presen
|
|||
} else {
|
||||
struct _presence_service_obj_st st={0};
|
||||
st.writer = writer;
|
||||
st.contact = contact;
|
||||
st.contact = contact; /*default value*/
|
||||
st.err = &err;
|
||||
ms_list_for_each2(model->services, (MSIterate2Func)write_xml_presence_service_obj, &st);
|
||||
}
|
||||
|
|
@ -1842,23 +1863,27 @@ void linphone_notify_convert_presence_to_xml(SalOp *op, SalPresenceModel *presen
|
|||
}
|
||||
if (err > 0) {
|
||||
/* xmlTextWriterEndDocument returns the size of the content. */
|
||||
*content = ms_strdup((char *)buf->content);
|
||||
content = ms_strdup((char *)buf->content);
|
||||
}
|
||||
xmlFreeTextWriter(writer);
|
||||
xmlBufferFree(buf);
|
||||
|
||||
end:
|
||||
if (contact) ms_free(contact);
|
||||
if (writer) xmlFreeTextWriter(writer);
|
||||
if (buf) xmlBufferFree(buf);
|
||||
return content;
|
||||
}
|
||||
|
||||
void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, SalPresenceModel *model){
|
||||
char *tmp;
|
||||
LinphoneFriend *lf;
|
||||
LinphoneFriend *lf = NULL;
|
||||
LinphoneAddress *friend=NULL;
|
||||
LinphonePresenceModel *presence = model ? (LinphonePresenceModel *)model:linphone_presence_model_new_with_activity(LinphonePresenceActivityOffline, NULL);
|
||||
|
||||
lf=linphone_find_friend_by_out_subscribe(lc->friends,op);
|
||||
if (linphone_core_get_default_friend_list(lc) != NULL)
|
||||
lf=linphone_friend_list_find_friend_by_out_subscribe(linphone_core_get_default_friend_list(lc), op);
|
||||
if (lf==NULL && lp_config_get_int(lc->config,"sip","allow_out_of_subscribe_presence",0)){
|
||||
const SalAddress *addr=sal_op_get_from_address(op);
|
||||
lf=NULL;
|
||||
linphone_find_friend_by_address(lc->friends,(LinphoneAddress*)addr,&lf);
|
||||
lf = linphone_friend_list_find_friend_by_address(linphone_core_get_default_friend_list(lc), (LinphoneAddress *)addr);
|
||||
}
|
||||
if (lf!=NULL){
|
||||
LinphonePresenceActivity *activity = NULL;
|
||||
|
|
@ -1869,11 +1894,9 @@ void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, Sa
|
|||
activity_str = linphone_presence_activity_to_string(activity);
|
||||
ms_message("We are notified that [%s] has presence [%s]", tmp, activity_str);
|
||||
if (activity_str != NULL) ms_free(activity_str);
|
||||
if (lf->presence != NULL) {
|
||||
linphone_presence_model_unref(lf->presence);
|
||||
}
|
||||
lf->presence = presence;
|
||||
linphone_friend_set_presence_model(lf, presence);
|
||||
lf->subscribe_active=TRUE;
|
||||
lf->presence_received = TRUE;
|
||||
linphone_core_notify_notify_presence_received(lc,(LinphoneFriend*)lf);
|
||||
ms_free(tmp);
|
||||
if (op != lf->outsub){
|
||||
|
|
@ -1904,9 +1927,11 @@ void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, Sa
|
|||
}
|
||||
|
||||
void linphone_subscription_closed(LinphoneCore *lc, SalOp *op){
|
||||
LinphoneFriend *lf;
|
||||
lf=linphone_find_friend_by_inc_subscribe(lc->friends,op);
|
||||
|
||||
LinphoneFriend *lf = NULL;
|
||||
|
||||
if (linphone_core_get_default_friend_list(lc) != NULL)
|
||||
lf = linphone_friend_list_find_friend_by_inc_subscribe(linphone_core_get_default_friend_list(lc), op);
|
||||
|
||||
if (lf!=NULL){
|
||||
/*this will release the op*/
|
||||
linphone_friend_remove_incoming_subscription(lf, op);
|
||||
|
|
|
|||
|
|
@ -24,17 +24,18 @@
|
|||
|
||||
#ifndef _PRIVATE_H
|
||||
#define _PRIVATE_H
|
||||
#ifdef __cplusplus
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
#include "linphonecore.h"
|
||||
#include "linphonefriend.h"
|
||||
#include "friendlist.h"
|
||||
#include "linphone_tunnel.h"
|
||||
#include "linphonecore_utils.h"
|
||||
#include "conference.h"
|
||||
#include "sal/sal.h"
|
||||
#include "sipsetup.h"
|
||||
#include "quality_reporting.h"
|
||||
#include "ringtoneplayer.h"
|
||||
#include "vcard.h"
|
||||
|
||||
#include <belle-sip/object.h>
|
||||
#include <belle-sip/dict.h>
|
||||
|
|
@ -110,6 +111,20 @@ extern "C" {
|
|||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
#if (_MSC_VER >= 1900)
|
||||
#define LINPHONE_MSC_VER_GREATER_19
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <libxml/xmlreader.h>
|
||||
#include <libxml/xmlwriter.h>
|
||||
#include <libxml/xpath.h>
|
||||
#include <libxml/xpathInternals.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct _LinphoneCallParams{
|
||||
belle_sip_object_t base;
|
||||
|
|
@ -138,17 +153,21 @@ struct _LinphoneCallParams{
|
|||
bool_t has_audio;
|
||||
bool_t has_video;
|
||||
bool_t avpf_enabled; /* RTCP feedback messages are enabled */
|
||||
bool_t implicit_rtcp_fb;
|
||||
|
||||
bool_t real_early_media; /*send real media even during early media (for outgoing calls)*/
|
||||
bool_t in_conference; /*in conference mode */
|
||||
|
||||
bool_t low_bandwidth;
|
||||
bool_t no_user_consent;/*when set to TRUE an UPDATE request will be used instead of reINVITE*/
|
||||
uint16_t avpf_rr_interval; /*in milliseconds*/
|
||||
|
||||
uint16_t avpf_rr_interval; /*in milliseconds*/
|
||||
bool_t internal_call_update; /*use mark that call update was requested internally (might be by ice) - unused for the moment*/
|
||||
bool_t video_multicast_enabled;
|
||||
|
||||
bool_t audio_multicast_enabled;
|
||||
bool_t realtimetext_enabled;
|
||||
bool_t update_call_when_ice_completed;
|
||||
bool_t encryption_mandatory;
|
||||
};
|
||||
|
||||
BELLE_SIP_DECLARE_VPTR(LinphoneCallParams);
|
||||
|
|
@ -179,6 +198,7 @@ struct _LinphoneCallLog{
|
|||
char* call_id; /**unique id of a call*/
|
||||
struct _LinphoneQualityReporting reporting;
|
||||
bool_t video_enabled;
|
||||
bool_t was_conference; /**<That call was a call with a conference server */
|
||||
unsigned int storage_id;
|
||||
};
|
||||
|
||||
|
|
@ -320,6 +340,7 @@ struct _LinphoneCall{
|
|||
char *dtls_certificate_fingerprint; /**> This fingerprint is computed during stream init and is stored in call to be used when making local media description */
|
||||
char *onhold_file; /*set if a on-hold file is to be played*/
|
||||
LinphoneChatRoom *chat_room;
|
||||
LinphoneConference *conf_ref; /**> Point on the associated conference if this call is part of a conference. NULL instead. */
|
||||
bool_t refer_pending;
|
||||
bool_t expect_media_in_ack;
|
||||
bool_t audio_muted;
|
||||
|
|
@ -337,6 +358,7 @@ struct _LinphoneCall{
|
|||
|
||||
bool_t paused_by_app;
|
||||
bool_t broken; /*set to TRUE when the call is in broken state due to network disconnection or transport */
|
||||
bool_t defer_notify_incoming;
|
||||
};
|
||||
|
||||
BELLE_SIP_DECLARE_VPTR(LinphoneCall);
|
||||
|
|
@ -369,7 +391,6 @@ void linphone_core_write_auth_info(LinphoneCore *lc, LinphoneAuthInfo *ai);
|
|||
const LinphoneAuthInfo *_linphone_core_find_auth_info(LinphoneCore *lc, const char *realm, const char *username, const char *domain, bool_t ignore_realm);
|
||||
|
||||
void linphone_core_update_proxy_register(LinphoneCore *lc);
|
||||
void linphone_core_refresh_subscribes(LinphoneCore *lc);
|
||||
int linphone_core_abort_call(LinphoneCore *lc, LinphoneCall *call, const char *error);
|
||||
const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc);
|
||||
|
||||
|
|
@ -378,22 +399,39 @@ void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrat
|
|||
void linphone_proxy_config_stop_refreshing(LinphoneProxyConfig *obj);
|
||||
void linphone_proxy_config_write_all_to_config_file(LinphoneCore *lc);
|
||||
void _linphone_proxy_config_release(LinphoneProxyConfig *cfg);
|
||||
void _linphone_proxy_config_unpublish(LinphoneProxyConfig *obj);
|
||||
|
||||
/*
|
||||
* returns service route as defined in as defined by rfc3608, might be a list instead of just one.
|
||||
* Can be NULL
|
||||
* */
|
||||
const LinphoneAddress* linphone_proxy_config_get_service_route(const LinphoneProxyConfig* cfg);
|
||||
|
||||
void linphone_friend_list_invalidate_subscriptions(LinphoneFriendList *list);
|
||||
void linphone_friend_list_notify_presence_received(LinphoneFriendList *list, LinphoneEvent *lev, const LinphoneContent *body);
|
||||
void linphone_friend_list_subscription_state_changed(LinphoneCore *lc, LinphoneEvent *lev, LinphoneSubscriptionState state);
|
||||
void _linphone_friend_list_release(LinphoneFriendList *list);
|
||||
void linphone_friend_invalidate_subscription(LinphoneFriend *lf);
|
||||
void linphone_friend_close_subscriptions(LinphoneFriend *lf);
|
||||
void _linphone_friend_release(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);
|
||||
LinphoneFriend *linphone_friend_list_find_friend_by_inc_subscribe(const LinphoneFriendList *list, SalOp *op);
|
||||
LinphoneFriend *linphone_friend_list_find_friend_by_out_subscribe(const LinphoneFriendList *list, SalOp *op);
|
||||
MSList *linphone_find_friend_by_address(MSList *fl, const LinphoneAddress *addr, LinphoneFriend **lf);
|
||||
bool_t linphone_core_should_subscribe_friends_only_when_registered(const LinphoneCore *lc);
|
||||
void linphone_core_update_friends_subscriptions(LinphoneCore *lc, LinphoneProxyConfig *cfg, bool_t only_when_registered);
|
||||
void linphone_core_friends_storage_init(LinphoneCore *lc);
|
||||
void linphone_core_friends_storage_close(LinphoneCore *lc);
|
||||
void linphone_core_store_friend_in_db(LinphoneCore *lc, LinphoneFriend *lf);
|
||||
void linphone_core_remove_friend_from_db(LinphoneCore *lc, LinphoneFriend *lf);
|
||||
void linphone_core_store_friends_list_in_db(LinphoneCore *lc, LinphoneFriendList *list);
|
||||
void linphone_core_remove_friends_list_from_db(LinphoneCore *lc, LinphoneFriendList *list);
|
||||
LINPHONE_PUBLIC MSList* linphone_core_fetch_friends_from_db(LinphoneCore *lc, LinphoneFriendList *list);
|
||||
LINPHONE_PUBLIC MSList* linphone_core_fetch_friends_lists_from_db(LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC LinphoneFriendListStatus linphone_friend_list_import_friend(LinphoneFriendList *list, LinphoneFriend *lf, bool_t synchronize);
|
||||
|
||||
int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen, int default_port);
|
||||
|
||||
|
|
@ -440,7 +478,7 @@ void linphone_process_authentication(LinphoneCore* lc, SalOp *op);
|
|||
void linphone_authentication_ok(LinphoneCore *lc, SalOp *op);
|
||||
void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from);
|
||||
void linphone_core_send_presence(LinphoneCore *lc, LinphonePresenceModel *presence);
|
||||
void linphone_notify_parse_presence(SalOp *op, const char *content_type, const char *content_subtype, const char *body, SalPresenceModel **result);
|
||||
void linphone_notify_parse_presence(const char *content_type, const char *content_subtype, const char *body, SalPresenceModel **result);
|
||||
void linphone_notify_convert_presence_to_xml(SalOp *op, SalPresenceModel *presence, const char *contact, char **content);
|
||||
void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, SalPresenceModel *model);
|
||||
void linphone_proxy_config_process_authentication_failure(LinphoneCore *lc, SalOp *op);
|
||||
|
|
@ -458,12 +496,13 @@ void linphone_core_resolve_stun_server(LinphoneCore *lc);
|
|||
LINPHONE_PUBLIC const struct addrinfo *linphone_core_get_stun_server_addrinfo(LinphoneCore *lc);
|
||||
void linphone_core_adapt_to_network(LinphoneCore *lc, int ping_time_ms, LinphoneCallParams *params);
|
||||
int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call);
|
||||
LINPHONE_PUBLIC void linphone_core_enable_forced_ice_relay(LinphoneCore *lc, bool_t enable);
|
||||
void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call);
|
||||
void linphone_call_stats_fill(LinphoneCallStats *stats, MediaStream *ms, OrtpEvent *ev);
|
||||
void linphone_call_stop_ice_for_inactive_streams(LinphoneCall *call, SalMediaDescription *result);
|
||||
void _update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session);
|
||||
void _update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session, bool_t use_nortpproxy);
|
||||
void linphone_call_update_local_media_description_from_ice_or_upnp(LinphoneCall *call);
|
||||
void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md);
|
||||
void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md, bool_t is_offer);
|
||||
void linphone_call_clear_unused_ice_candidates(LinphoneCall *call, const SalMediaDescription *md);
|
||||
bool_t linphone_core_media_description_contains_video_stream(const SalMediaDescription *md);
|
||||
|
||||
|
|
@ -476,7 +515,7 @@ void linphone_proxy_config_update(LinphoneProxyConfig *cfg);
|
|||
LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const LinphoneAddress *uri);
|
||||
const char *linphone_core_find_best_identity(LinphoneCore *lc, const LinphoneAddress *to);
|
||||
int linphone_core_get_local_ip_for(int type, const char *dest, char *result);
|
||||
void linphone_core_get_local_ip(LinphoneCore *lc, int af, const char *dest, char *result);
|
||||
LINPHONE_PUBLIC void linphone_core_get_local_ip(LinphoneCore *lc, int af, const char *dest, char *result);
|
||||
|
||||
LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LinphoneCore *lc, int index);
|
||||
void linphone_proxy_config_write_to_config_file(struct _LpConfig* config,LinphoneProxyConfig *obj, int index);
|
||||
|
|
@ -517,7 +556,7 @@ int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call,
|
|||
void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call);
|
||||
bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription *md);
|
||||
extern SalCallbacks linphone_sal_callbacks;
|
||||
bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc);
|
||||
bool_t linphone_core_symmetric_rtp_enabled(LinphoneCore*lc);
|
||||
|
||||
void linphone_core_queue_task(LinphoneCore *lc, belle_sip_source_func_t task_fun, void *data, const char *task_description);
|
||||
|
|
@ -545,6 +584,7 @@ int linphone_chat_room_upload_file(LinphoneChatMessage *msg);
|
|||
void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg);
|
||||
LinphoneChatMessageCbs *linphone_chat_message_cbs_new(void);
|
||||
LinphoneChatRoom *_linphone_core_create_chat_room_from_call(LinphoneCall *call);
|
||||
bool_t linphone_chat_room_lime_enabled(LinphoneChatRoom *cr);
|
||||
/**/
|
||||
|
||||
struct _LinphoneProxyConfig
|
||||
|
|
@ -569,7 +609,6 @@ struct _LinphoneProxyConfig
|
|||
int auth_failures;
|
||||
char *dial_prefix;
|
||||
LinphoneRegistrationState state;
|
||||
SalOp *publish_op;
|
||||
LinphoneAVPFMode avpf_mode;
|
||||
|
||||
bool_t commit;
|
||||
|
|
@ -589,6 +628,8 @@ struct _LinphoneProxyConfig
|
|||
LinphoneAddress *saved_identity;
|
||||
/*---*/
|
||||
LinphoneAddress *pending_contact; /*use to store previous contact in case of network failure*/
|
||||
LinphoneEvent *long_term_event;
|
||||
unsigned long long previous_publish_config_hash[2];
|
||||
|
||||
};
|
||||
|
||||
|
|
@ -652,10 +693,45 @@ struct _LinphoneFriend{
|
|||
bool_t inc_subscribe_pending;
|
||||
bool_t commit;
|
||||
bool_t initial_subscribes_sent; /*used to know if initial subscribe message was sent or not*/
|
||||
bool_t presence_received;
|
||||
LinphoneVcard *vcard;
|
||||
unsigned int storage_id;
|
||||
LinphoneFriendList *friend_list;
|
||||
};
|
||||
|
||||
BELLE_SIP_DECLARE_VPTR(LinphoneFriend);
|
||||
|
||||
struct _LinphoneFriendListCbs {
|
||||
belle_sip_object_t base;
|
||||
void *user_data;
|
||||
LinphoneFriendListCbsContactCreatedCb contact_created_cb;
|
||||
LinphoneFriendListCbsContactDeletedCb contact_deleted_cb;
|
||||
LinphoneFriendListCbsContactUpdatedCb contact_updated_cb;
|
||||
LinphoneFriendListCbsSyncStateChangedCb sync_state_changed_cb;
|
||||
};
|
||||
|
||||
BELLE_SIP_DECLARE_VPTR(LinphoneFriendListCbs);
|
||||
|
||||
struct _LinphoneFriendList {
|
||||
belle_sip_object_t base;
|
||||
void *user_data;
|
||||
LinphoneCore *lc;
|
||||
LinphoneEvent *event;
|
||||
char *display_name;
|
||||
char *rls_uri;
|
||||
MSList *friends;
|
||||
unsigned char *content_digest;
|
||||
int expected_notification_version;
|
||||
unsigned int storage_id;
|
||||
char *uri;
|
||||
MSList *dirty_friends_to_update;
|
||||
int revision;
|
||||
LinphoneFriendListCbs *cbs;
|
||||
};
|
||||
|
||||
BELLE_SIP_DECLARE_VPTR(LinphoneFriendList);
|
||||
|
||||
|
||||
|
||||
typedef struct sip_config
|
||||
{
|
||||
|
|
@ -792,16 +868,6 @@ typedef struct autoreplier_config
|
|||
const char *message; /* the path of the file to be played */
|
||||
}autoreplier_config_t;
|
||||
|
||||
struct _LinphoneConference{
|
||||
MSAudioConference *conf;
|
||||
AudioStream *local_participant;
|
||||
MSAudioEndpoint *local_endpoint;
|
||||
MSAudioEndpoint *record_endpoint;
|
||||
RtpProfile *local_dummy_profile;
|
||||
bool_t local_muted;
|
||||
bool_t terminated;
|
||||
};
|
||||
|
||||
|
||||
typedef struct _LinphoneToneDescription{
|
||||
LinphoneReason reason;
|
||||
|
|
@ -816,7 +882,6 @@ void linphone_core_play_call_error_tone(LinphoneCore *lc, LinphoneReason reason)
|
|||
void _linphone_core_set_tone(LinphoneCore *lc, LinphoneReason reason, LinphoneToneID id, const char *audiofile);
|
||||
const char *linphone_core_get_tone_file(const LinphoneCore *lc, LinphoneToneID id);
|
||||
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;
|
||||
|
|
@ -830,6 +895,7 @@ void linphone_task_list_free(LinphoneTaskList *t);
|
|||
|
||||
struct _LinphoneCore
|
||||
{
|
||||
MSFactory* factory;
|
||||
MSList* vtable_refs;
|
||||
Sal *sal;
|
||||
LinphoneGlobalState state;
|
||||
|
|
@ -847,7 +913,7 @@ struct _LinphoneCore
|
|||
ui_config_t ui_conf;
|
||||
autoreplier_config_t autoreplier_conf;
|
||||
LinphoneProxyConfig *default_proxy;
|
||||
MSList *friends;
|
||||
MSList *friends_lists;
|
||||
MSList *auth_info;
|
||||
struct _RingStream *ringstream;
|
||||
time_t dmfs_playing_start_time;
|
||||
|
|
@ -878,7 +944,7 @@ struct _LinphoneCore
|
|||
time_t netup_time; /*time when network went reachable */
|
||||
struct _EcCalibrator *ecc;
|
||||
LinphoneTaskList hooks; /*tasks periodically executed in linphone_core_iterate()*/
|
||||
LinphoneConference conf_ctx;
|
||||
LinphoneConference *conf_ctx;
|
||||
char* zrtp_secrets_cache;
|
||||
char* user_certificates_path;
|
||||
LinphoneVideoPolicy video_policy;
|
||||
|
|
@ -891,13 +957,18 @@ struct _LinphoneCore
|
|||
|
||||
bool_t preview_finished;
|
||||
bool_t auto_net_state_mon;
|
||||
bool_t network_reachable;
|
||||
bool_t network_reachable_to_be_notified; /*set to true when state must be notified in next iterate*/
|
||||
bool_t sip_network_reachable;
|
||||
bool_t media_network_reachable;
|
||||
|
||||
bool_t network_reachable_to_be_notified; /*set to true when state must be notified in next iterate*/
|
||||
bool_t use_preview_window;
|
||||
bool_t network_last_status;
|
||||
bool_t ringstream_autorelease;
|
||||
|
||||
bool_t vtables_running;
|
||||
bool_t send_call_stats_periodical_updates;
|
||||
bool_t forced_ice_relay;
|
||||
bool_t pad;
|
||||
char localip[LINPHONE_IPADDR_SIZE];
|
||||
int device_rotation;
|
||||
int max_calls;
|
||||
|
|
@ -912,12 +983,16 @@ struct _LinphoneCore
|
|||
char *logs_db_file;
|
||||
#ifdef CALL_LOGS_STORAGE_ENABLED
|
||||
sqlite3 *logs_db;
|
||||
#endif
|
||||
char *friends_db_file;
|
||||
#ifdef FRIENDS_SQL_STORAGE_ENABLED
|
||||
sqlite3 *friends_db;
|
||||
#endif
|
||||
#ifdef BUILD_UPNP
|
||||
UpnpContext *upnp;
|
||||
#endif //BUILD_UPNP
|
||||
belle_http_provider_t *http_provider;
|
||||
belle_tls_verify_policy_t *http_verify_policy;
|
||||
belle_tls_crypto_config_t *http_crypto_config;
|
||||
belle_http_request_listener_t *provisioning_http_listener;
|
||||
MSList *tones;
|
||||
LinphoneReason chat_deny_code;
|
||||
|
|
@ -925,6 +1000,7 @@ struct _LinphoneCore
|
|||
const char **supported_formats;
|
||||
LinphoneContent *log_collection_upload_information;
|
||||
LinphoneCoreVTable *current_vtable; // the latest vtable to call a callback, see linphone_core_get_current_vtable
|
||||
LinphoneRingtonePlayer *ringtoneplayer;
|
||||
#ifdef ANDROID
|
||||
jobject wifi_lock;
|
||||
jclass wifi_lock_class;
|
||||
|
|
@ -939,6 +1015,7 @@ struct _LinphoneCore
|
|||
|
||||
|
||||
struct _LinphoneEvent{
|
||||
belle_sip_object_t base;
|
||||
LinphoneSubscriptionDir dir;
|
||||
LinphoneCore *lc;
|
||||
SalOp *op;
|
||||
|
|
@ -946,13 +1023,14 @@ struct _LinphoneEvent{
|
|||
LinphoneSubscriptionState subscription_state;
|
||||
LinphonePublishState publish_state;
|
||||
void *userdata;
|
||||
int refcnt;
|
||||
char *name;
|
||||
int expires;
|
||||
bool_t terminating;
|
||||
bool_t is_out_of_dialog_op; /*used for out of dialog notify*/
|
||||
bool_t internal;
|
||||
};
|
||||
|
||||
BELLE_SIP_DECLARE_VPTR(LinphoneEvent);
|
||||
|
||||
LinphoneTunnel *linphone_core_tunnel_new(LinphoneCore *lc);
|
||||
void linphone_tunnel_destroy(LinphoneTunnel *tunnel);
|
||||
|
|
@ -978,6 +1056,7 @@ bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, cons
|
|||
void _linphone_core_configure_resolver(void);
|
||||
|
||||
struct _EcCalibrator{
|
||||
MSFactory *factory;
|
||||
ms_thread_t thread;
|
||||
MSSndCard *play_card,*capt_card;
|
||||
MSFilter *sndread,*det,*rec;
|
||||
|
|
@ -993,6 +1072,7 @@ struct _EcCalibrator{
|
|||
unsigned int rate;
|
||||
LinphoneEcCalibratorStatus status;
|
||||
bool_t freq1,freq2,freq3;
|
||||
bool_t play_cool_tones;
|
||||
};
|
||||
|
||||
typedef struct _EcCalibrator EcCalibrator;
|
||||
|
|
@ -1004,18 +1084,12 @@ 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);
|
||||
void linphone_core_repair_calls(LinphoneCore *lc);
|
||||
int linphone_core_preempt_sound_resources(LinphoneCore *lc);
|
||||
int _linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call);
|
||||
|
||||
/*conferencing subsystem*/
|
||||
void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted);
|
||||
/* When a conference participant pause the conference he may send a music.
|
||||
* We don't want to hear that music or to send it to the other participants.
|
||||
* Use muted=yes to handle this case.
|
||||
*/
|
||||
void linphone_call_add_to_conf(LinphoneCall *call, bool_t muted);
|
||||
void linphone_call_remove_from_conf(LinphoneCall *call);
|
||||
void linphone_core_conference_check_uninit(LinphoneCore *lc);
|
||||
bool_t linphone_core_sound_resources_available(LinphoneCore *lc);
|
||||
void linphone_core_notify_refer_state(LinphoneCore *lc, LinphoneCall *referer, LinphoneCall *newcall);
|
||||
unsigned int linphone_core_get_audio_features(LinphoneCore *lc);
|
||||
|
|
@ -1065,22 +1139,25 @@ const char *linphone_core_create_uuid(LinphoneCore *lc);
|
|||
void linphone_configure_op(LinphoneCore *lc, SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact);
|
||||
void linphone_call_create_op(LinphoneCall *call);
|
||||
int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer);
|
||||
void linphone_core_notify_info_message(LinphoneCore* lc,SalOp *op, const SalBody *body);
|
||||
void linphone_core_notify_info_message(LinphoneCore* lc,SalOp *op, SalBodyHandler *body);
|
||||
LinphoneContent * linphone_content_new(void);
|
||||
LinphoneContent * linphone_content_copy(const LinphoneContent *ref);
|
||||
SalBody *sal_body_from_content(SalBody *body, const LinphoneContent *content);
|
||||
SalBodyHandler *sal_body_handler_from_content(const LinphoneContent *content);
|
||||
SalReason linphone_reason_to_sal(LinphoneReason reason);
|
||||
LinphoneReason linphone_reason_from_sal(SalReason reason);
|
||||
LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name, int expires);
|
||||
LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name);
|
||||
void linphone_event_unpublish(LinphoneEvent *lev);
|
||||
/**
|
||||
* Useful for out of dialog notify
|
||||
* */
|
||||
LinphoneEvent *linphone_event_new_with_out_of_dialog_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name);
|
||||
void linphone_event_set_internal(LinphoneEvent *lev, bool_t internal);
|
||||
bool_t linphone_event_is_internal(LinphoneEvent *lev);
|
||||
void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState state);
|
||||
void linphone_event_set_publish_state(LinphoneEvent *lev, LinphonePublishState state);
|
||||
LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatus ss);
|
||||
LinphoneContent *linphone_content_from_sal_body(const SalBody *ref);
|
||||
LinphoneContent *linphone_content_from_sal_body_handler(SalBodyHandler *ref);
|
||||
void linphone_core_invalidate_friend_subscriptions(LinphoneCore *lc);
|
||||
void linphone_core_register_offer_answer_providers(LinphoneCore *lc);
|
||||
|
||||
|
|
@ -1088,7 +1165,11 @@ void linphone_core_register_offer_answer_providers(LinphoneCore *lc);
|
|||
struct _LinphoneContent {
|
||||
belle_sip_object_t base;
|
||||
void *user_data;
|
||||
struct _LinphoneContentPrivate lcp;
|
||||
SalBodyHandler *body_handler;
|
||||
char *name; /**< used by RCS File transfer messages to store the original filename of the file to be downloaded from server */
|
||||
char *key; /**< used by RCS File transfer messages to store the key to encrypt file if needed */
|
||||
size_t keyLength; /**< Length of key in bytes */
|
||||
void *cryptoContext; /**< crypto context used to encrypt file for RCS file transfer */
|
||||
bool_t owned_fields;
|
||||
};
|
||||
|
||||
|
|
@ -1180,9 +1261,41 @@ struct _LinphoneAccountCreator {
|
|||
|
||||
BELLE_SIP_DECLARE_VPTR(LinphoneAccountCreator);
|
||||
|
||||
/*****************************************************************************
|
||||
* CardDAV interface *
|
||||
****************************************************************************/
|
||||
|
||||
struct _LinphoneCardDavContext {
|
||||
LinphoneFriendList *friend_list;
|
||||
int ctag;
|
||||
void *user_data;
|
||||
LinphoneCardDavContactCreatedCb contact_created_cb;
|
||||
LinphoneCardDavContactUpdatedCb contact_updated_cb;
|
||||
LinphoneCardDavContactRemovedCb contact_removed_cb;
|
||||
LinphoneCardDavSynchronizationDoneCb sync_done_cb;
|
||||
};
|
||||
|
||||
struct _LinphoneCardDavQuery {
|
||||
LinphoneCardDavContext *context;
|
||||
const char *url;
|
||||
const char *method;
|
||||
const char *body;
|
||||
const char *depth;
|
||||
const char *ifmatch;
|
||||
belle_http_request_listener_t *http_request_listener;
|
||||
void *user_data;
|
||||
LinphoneCardDavQueryType type;
|
||||
};
|
||||
|
||||
struct _LinphoneCardDavResponse {
|
||||
LinphoneCardDavContext *context;
|
||||
const char *etag;
|
||||
const char *url;
|
||||
const char *vcard;
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
* REMOTE PROVISIONING FUNCTIONS *
|
||||
* REMOTE PROVISIONING FUNCTIONS *
|
||||
****************************************************************************/
|
||||
|
||||
void linphone_configuring_terminated(LinphoneCore *lc, LinphoneConfiguringState state, const char *message);
|
||||
|
|
@ -1190,7 +1303,7 @@ int linphone_remote_provisioning_download_and_apply(LinphoneCore *lc, const char
|
|||
LINPHONE_PUBLIC int linphone_remote_provisioning_load_file( LinphoneCore* lc, const char* file_path);
|
||||
|
||||
/*****************************************************************************
|
||||
* Player interface
|
||||
* Player interface *
|
||||
****************************************************************************/
|
||||
|
||||
struct _LinphonePlayer{
|
||||
|
|
@ -1215,11 +1328,6 @@ void _linphone_player_destroy(LinphonePlayer *player);
|
|||
* XML UTILITY FUNCTIONS *
|
||||
****************************************************************************/
|
||||
|
||||
#include <libxml/xmlreader.h>
|
||||
#include <libxml/xmlwriter.h>
|
||||
#include <libxml/xpath.h>
|
||||
#include <libxml/xpathInternals.h>
|
||||
|
||||
#define XMLPARSING_BUFFER_LEN 2048
|
||||
#define MAX_XPATH_LENGTH 256
|
||||
|
||||
|
|
@ -1235,8 +1343,10 @@ void linphone_xmlparsing_context_destroy(xmlparsing_context_t *ctx);
|
|||
void linphone_xmlparsing_genericxml_error(void *ctx, const char *fmt, ...);
|
||||
int linphone_create_xml_xpath_context(xmlparsing_context_t *xml_ctx);
|
||||
char * linphone_get_xml_text_content(xmlparsing_context_t *xml_ctx, const char *xpath_expression);
|
||||
const char * linphone_get_xml_attribute_text_content(xmlparsing_context_t *xml_ctx, const char *xpath_expression, const char *attribute_name);
|
||||
void linphone_free_xml_text_content(const char *text);
|
||||
xmlXPathObjectPtr linphone_get_xml_xpath_object_for_node_list(xmlparsing_context_t *xml_ctx, const char *xpath_expression);
|
||||
void linphone_xml_xpath_context_init_carddav_ns(xmlparsing_context_t *xml_ctx);
|
||||
|
||||
/*****************************************************************************
|
||||
* OTHER UTILITY FUNCTIONS *
|
||||
|
|
@ -1288,10 +1398,13 @@ BELLE_SIP_TYPE_ID(LinphoneLDAPContactProvider),
|
|||
BELLE_SIP_TYPE_ID(LinphoneLDAPContactSearch),
|
||||
BELLE_SIP_TYPE_ID(LinphoneProxyConfig),
|
||||
BELLE_SIP_TYPE_ID(LinphoneFriend),
|
||||
BELLE_SIP_TYPE_ID(LinphoneFriendList),
|
||||
BELLE_SIP_TYPE_ID(LinphoneXmlRpcRequest),
|
||||
BELLE_SIP_TYPE_ID(LinphoneXmlRpcRequestCbs),
|
||||
BELLE_SIP_TYPE_ID(LinphoneXmlRpcSession),
|
||||
BELLE_SIP_TYPE_ID(LinphoneTunnelConfig)
|
||||
BELLE_SIP_TYPE_ID(LinphoneTunnelConfig),
|
||||
BELLE_SIP_TYPE_ID(LinphoneFriendListCbs),
|
||||
BELLE_SIP_TYPE_ID(LinphoneEvent)
|
||||
BELLE_SIP_DECLARE_TYPES_END
|
||||
|
||||
|
||||
|
|
@ -1332,6 +1445,8 @@ void linphone_core_notify_subscription_state_changed(LinphoneCore *lc, LinphoneE
|
|||
void linphone_core_notify_publish_state_changed(LinphoneCore *lc, LinphoneEvent *lev, LinphonePublishState state);
|
||||
void linphone_core_notify_log_collection_upload_state_changed(LinphoneCore *lc, LinphoneCoreLogCollectionUploadState state, const char *info);
|
||||
void linphone_core_notify_log_collection_upload_progress_indication(LinphoneCore *lc, size_t offset, size_t total);
|
||||
void linphone_core_notify_friend_list_created(LinphoneCore *lc, LinphoneFriendList *list);
|
||||
void linphone_core_notify_friend_list_removed(LinphoneCore *lc, LinphoneFriendList *list);
|
||||
|
||||
void set_mic_gain_db(AudioStream *st, float gain);
|
||||
void set_playback_gain_db(AudioStream *st, float gain);
|
||||
|
|
@ -1381,23 +1496,27 @@ struct _VTableReference{
|
|||
LinphoneCoreVTable *vtable;
|
||||
bool_t valid;
|
||||
bool_t autorelease;
|
||||
bool_t internal;
|
||||
};
|
||||
|
||||
typedef struct _VTableReference VTableReference;
|
||||
|
||||
void v_table_reference_destroy(VTableReference *ref);
|
||||
|
||||
void _linphone_core_add_listener(LinphoneCore *lc, LinphoneCoreVTable *vtable, bool_t autorelease);
|
||||
LINPHONE_PUBLIC void _linphone_core_add_listener(LinphoneCore *lc, LinphoneCoreVTable *vtable, bool_t autorelease, bool_t internal);
|
||||
|
||||
#ifdef VIDEO_ENABLED
|
||||
LINPHONE_PUBLIC MSWebCam *linphone_call_get_video_device(const LinphoneCall *call);
|
||||
MSWebCam *get_nowebcam_device(void);
|
||||
MSWebCam *get_nowebcam_device(MSFactory *f);
|
||||
#endif
|
||||
bool_t linphone_core_lime_for_file_sharing_enabled(const LinphoneCore *lc);
|
||||
LinphoneLimeState linphone_core_lime_for_file_sharing_enabled(const LinphoneCore *lc);
|
||||
|
||||
BELLE_SIP_DECLARE_VPTR(LinphoneTunnelConfig);
|
||||
|
||||
int linphone_core_get_default_proxy_config_index(LinphoneCore *lc);
|
||||
|
||||
|
||||
char *linphone_presence_model_to_xml(LinphonePresenceModel *model) ;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
175
coreapi/proxy.c
175
coreapi/proxy.c
|
|
@ -130,6 +130,50 @@ LinphoneProxyConfig *linphone_proxy_config_new() {
|
|||
return linphone_core_create_proxy_config(NULL);
|
||||
}
|
||||
|
||||
static char * append_linphone_address(LinphoneAddress *addr,char *out) {
|
||||
char *res = out;
|
||||
if (addr) {
|
||||
char *tmp;
|
||||
tmp = linphone_address_as_string(addr);
|
||||
res = ms_strcat_printf(out, "%s",tmp);
|
||||
ms_free(tmp);
|
||||
}
|
||||
return res;
|
||||
};
|
||||
static char * append_string(const char * string,char *out) {
|
||||
char *res = out;
|
||||
if (string) {
|
||||
res = ms_strcat_printf(out, "%s",string);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
/*
|
||||
* return true if computed value has changed
|
||||
*/
|
||||
bool_t linphone_proxy_config_compute_publish_params_hash(LinphoneProxyConfig * cfg) {
|
||||
char * source = NULL;
|
||||
char hash[33];
|
||||
char saved;
|
||||
unsigned long long previous_hash[2];
|
||||
previous_hash[0] = cfg->previous_publish_config_hash[0];
|
||||
previous_hash[1] = cfg->previous_publish_config_hash[1];
|
||||
|
||||
source = ms_strcat_printf(source, "%i",cfg->privacy);
|
||||
source=append_linphone_address(cfg->identity_address, source);
|
||||
source=append_string(cfg->reg_proxy,source);
|
||||
source=append_string(cfg->reg_route,source);
|
||||
source=append_string(cfg->realm,source);
|
||||
source = ms_strcat_printf(source, "%i",cfg->publish_expires);
|
||||
source = ms_strcat_printf(source, "%i",cfg->publish);
|
||||
belle_sip_auth_helper_compute_ha1(source, "dummy", "dummy", hash);
|
||||
ms_free(source);
|
||||
saved = hash[16];
|
||||
hash[16] = '\0';
|
||||
cfg->previous_publish_config_hash[0] = strtoull(hash, (char **)NULL, 16);
|
||||
hash[16] = saved;
|
||||
cfg->previous_publish_config_hash[1] = strtoull(&hash[16], (char **)NULL, 16);
|
||||
return previous_hash[0] != cfg->previous_publish_config_hash[0] || previous_hash[1] != cfg->previous_publish_config_hash[1];
|
||||
}
|
||||
static void _linphone_proxy_config_destroy(LinphoneProxyConfig *cfg);
|
||||
|
||||
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneProxyConfig);
|
||||
|
|
@ -152,9 +196,9 @@ void _linphone_proxy_config_release_ops(LinphoneProxyConfig *cfg){
|
|||
sal_op_release(cfg->op);
|
||||
cfg->op=NULL;
|
||||
}
|
||||
if (cfg->publish_op){
|
||||
sal_op_release(cfg->publish_op);
|
||||
cfg->publish_op=NULL;
|
||||
if (cfg->long_term_event){
|
||||
linphone_event_unref(cfg->long_term_event);
|
||||
cfg->long_term_event=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -320,15 +364,13 @@ void linphone_proxy_config_pause_register(LinphoneProxyConfig *cfg){
|
|||
}
|
||||
|
||||
void linphone_proxy_config_edit(LinphoneProxyConfig *cfg){
|
||||
if (cfg->publish && cfg->publish_op){
|
||||
/*unpublish*/
|
||||
sal_publish_presence(cfg->publish_op,NULL,NULL,0,(SalPresenceModel *)NULL);
|
||||
sal_op_release(cfg->publish_op);
|
||||
cfg->publish_op=NULL;
|
||||
}
|
||||
/*store current config related to server location*/
|
||||
linphone_proxy_config_store_server_config(cfg);
|
||||
linphone_proxy_config_compute_publish_params_hash(cfg);
|
||||
|
||||
if (cfg->publish && cfg->long_term_event){
|
||||
linphone_event_pause_publish(cfg->long_term_event);
|
||||
}
|
||||
/*stop refresher in any case*/
|
||||
linphone_proxy_config_pause_register(cfg);
|
||||
}
|
||||
|
|
@ -351,9 +393,10 @@ void linphone_proxy_config_stop_refreshing(LinphoneProxyConfig * cfg){
|
|||
cfg->pending_contact=contact_addr;
|
||||
|
||||
}
|
||||
if (cfg->publish_op){
|
||||
sal_op_release(cfg->publish_op);
|
||||
cfg->publish_op=NULL;
|
||||
if (cfg->long_term_event){ /*might probably do better*/
|
||||
linphone_event_terminate(cfg->long_term_event);
|
||||
linphone_event_unref(cfg->long_term_event);
|
||||
cfg->long_term_event=NULL;
|
||||
}
|
||||
if (cfg->op){
|
||||
sal_op_release(cfg->op);
|
||||
|
|
@ -961,10 +1004,8 @@ LinphoneAddress* linphone_proxy_config_normalize_sip_uri(LinphoneProxyConfig *pr
|
|||
if (uri==NULL){
|
||||
return NULL;
|
||||
} else {
|
||||
char* normalized_phone = linphone_proxy_config_normalize_phone_number(proxy,username);
|
||||
linphone_address_set_display_name(uri,NULL);
|
||||
linphone_address_set_username(uri,normalized_phone ? normalized_phone : username);
|
||||
ms_free(normalized_phone);
|
||||
linphone_address_set_username(uri,username);
|
||||
return _linphone_core_destroy_addr_if_not_sip(uri);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -1001,6 +1042,26 @@ int linphone_proxy_config_done(LinphoneProxyConfig *cfg)
|
|||
sal_op_unref(cfg->op); /*but we keep refresher to handle authentication if needed*/
|
||||
cfg->op=NULL;
|
||||
}
|
||||
if (cfg->long_term_event) {
|
||||
if (res == LinphoneProxyConfigAddressDifferent) {
|
||||
_linphone_proxy_config_unpublish(cfg);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (linphone_proxy_config_compute_publish_params_hash(cfg)) {
|
||||
ms_message("Publish params have changed on proxy config [%p]",cfg);
|
||||
if (cfg->long_term_event) {
|
||||
if (!cfg->publish) {
|
||||
/*publish is terminated*/
|
||||
linphone_event_terminate(cfg->long_term_event);
|
||||
}
|
||||
linphone_event_unref(cfg->long_term_event);
|
||||
cfg->long_term_event = NULL;
|
||||
}
|
||||
if (cfg->publish) cfg->send_publish=TRUE;
|
||||
} else {
|
||||
ms_message("Publish params have not changed on proxy config [%p]",cfg);
|
||||
}
|
||||
cfg->commit=TRUE;
|
||||
linphone_proxy_config_write_all_to_config_file(cfg->lc);
|
||||
|
|
@ -1023,26 +1084,46 @@ int linphone_proxy_config_send_publish(LinphoneProxyConfig *proxy, LinphonePrese
|
|||
int err=0;
|
||||
|
||||
if (proxy->state==LinphoneRegistrationOk || proxy->state==LinphoneRegistrationCleared){
|
||||
if (proxy->publish_op==NULL){
|
||||
const LinphoneAddress *to=linphone_proxy_config_get_identity_address(proxy);
|
||||
proxy->publish_op=sal_op_new(proxy->lc->sal);
|
||||
|
||||
linphone_configure_op(proxy->lc, proxy->publish_op,
|
||||
to, NULL, FALSE);
|
||||
|
||||
if (lp_config_get_int(proxy->lc->config,"sip","publish_msg_with_contact",0)){
|
||||
sal_op_set_contact_address(proxy->publish_op,linphone_proxy_config_get_identity_address(proxy));
|
||||
}
|
||||
LinphoneContent *content;
|
||||
char *presence_body;
|
||||
if (proxy->long_term_event==NULL){
|
||||
proxy->long_term_event = linphone_core_create_publish(proxy->lc
|
||||
, linphone_proxy_config_get_identity_address(proxy)
|
||||
, "presence"
|
||||
, linphone_proxy_config_get_publish_expires(proxy));
|
||||
linphone_event_ref(proxy->long_term_event);
|
||||
}
|
||||
err=sal_publish_presence(proxy->publish_op
|
||||
,NULL
|
||||
,NULL
|
||||
,linphone_proxy_config_get_publish_expires(proxy)
|
||||
,(SalPresenceModel *)presence);
|
||||
proxy->long_term_event->internal = TRUE;
|
||||
|
||||
if (linphone_presence_model_get_presentity(presence) == NULL) {
|
||||
ms_message("No presentity set for model [%p], using identity from proxy config [%p]", presence, proxy);
|
||||
linphone_presence_model_set_presentity(presence,linphone_proxy_config_get_identity_address(proxy));
|
||||
}
|
||||
|
||||
if (!(presence_body = linphone_presence_model_to_xml(presence))) {
|
||||
ms_error("Cannot publish presence model [%p] for proxy config [%p] because of xml serilization error",presence,proxy);
|
||||
return -1;
|
||||
}
|
||||
|
||||
content = linphone_content_new();
|
||||
linphone_content_set_buffer(content,presence_body,strlen(presence_body));
|
||||
linphone_content_set_type(content, "application");
|
||||
linphone_content_set_subtype(content,"pidf+xml");
|
||||
err = linphone_event_send_publish(proxy->long_term_event, content);
|
||||
linphone_content_unref(content);
|
||||
ms_free(presence_body);
|
||||
}else proxy->send_publish=TRUE; /*otherwise do not send publish if registration is in progress, this will be done later*/
|
||||
return err;
|
||||
}
|
||||
|
||||
void _linphone_proxy_config_unpublish(LinphoneProxyConfig *obj) {
|
||||
if (obj->long_term_event
|
||||
&& (linphone_event_get_publish_state(obj->long_term_event) == LinphonePublishOk ||
|
||||
(linphone_event_get_publish_state(obj->long_term_event) == LinphonePublishProgress && obj->publish_expires != 0))) {
|
||||
linphone_event_unpublish(obj->long_term_event);
|
||||
}
|
||||
}
|
||||
|
||||
const char *linphone_proxy_config_get_route(const LinphoneProxyConfig *cfg){
|
||||
return cfg->reg_route;
|
||||
}
|
||||
|
|
@ -1362,7 +1443,7 @@ static bool_t can_register(LinphoneProxyConfig *cfg){
|
|||
}
|
||||
#endif //BUILD_UPNP
|
||||
if (lc->sip_conf.register_only_when_network_is_up){
|
||||
return lc->network_reachable;
|
||||
return lc->sip_network_reachable;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -1376,7 +1457,6 @@ void linphone_proxy_config_update(LinphoneProxyConfig *cfg){
|
|||
if (can_register(cfg)){
|
||||
linphone_proxy_config_register(cfg);
|
||||
cfg->commit=FALSE;
|
||||
if (cfg->publish) cfg->send_publish=TRUE;
|
||||
}
|
||||
}
|
||||
if (cfg->send_publish && (cfg->state==LinphoneRegistrationOk || cfg->state==LinphoneRegistrationCleared)){
|
||||
|
|
@ -1409,7 +1489,6 @@ void * linphone_proxy_config_get_user_data(const LinphoneProxyConfig *cfg) {
|
|||
|
||||
void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrationState state, const char *message){
|
||||
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));
|
||||
|
|
@ -1419,25 +1498,25 @@ void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrat
|
|||
}
|
||||
|
||||
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),
|
||||
linphone_registration_state_to_string(cfg->state),
|
||||
linphone_registration_state_to_string(state));
|
||||
if (linphone_core_should_subscribe_friends_only_when_registered(lc)){
|
||||
update_friends=(state==LinphoneRegistrationOk && cfg->state!=LinphoneRegistrationOk)
|
||||
|| (state!=LinphoneRegistrationOk && cfg->state==LinphoneRegistrationOk);
|
||||
}
|
||||
cfg->state=state;
|
||||
|
||||
if (update_friends){
|
||||
ms_message("Proxy config [%p] for identity [%s] moving from state [%s] to [%s] on core [%p]" ,
|
||||
cfg,
|
||||
linphone_proxy_config_get_identity(cfg),
|
||||
linphone_registration_state_to_string(cfg->state),
|
||||
linphone_registration_state_to_string(state),
|
||||
cfg->lc);
|
||||
if (linphone_core_should_subscribe_friends_only_when_registered(lc) && cfg->state!=state && state == LinphoneRegistrationOk){
|
||||
ms_message("Updating friends for identity [%s] on core [%p]",linphone_proxy_config_get_identity(cfg),cfg->lc);
|
||||
/* state must be updated before calling linphone_core_update_friends_subscriptions*/
|
||||
cfg->state=state;
|
||||
linphone_core_update_friends_subscriptions(lc,cfg,TRUE);
|
||||
} else {
|
||||
/*at this point state must be updated*/
|
||||
cfg->state=state;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
linphone_core_repair_calls(lc);
|
||||
}
|
||||
} else {
|
||||
/*state already reported*/
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ static void append_to_buffer_valist(char **buff, size_t *buff_size, size_t *offs
|
|||
/*if we are out of memory, we add some size to buffer*/
|
||||
if (ret == BELLE_SIP_BUFFER_OVERFLOW) {
|
||||
/*some compilers complain that size_t cannot be formatted as unsigned long, hence forcing cast*/
|
||||
ms_warning("QualityReporting: Buffer was too small to contain the whole report - increasing its size from %lu to %lu",
|
||||
ms_debug("QualityReporting: Buffer was too small to contain the whole report - increasing its size from %lu to %lu",
|
||||
(unsigned long)*buff_size, (unsigned long)*buff_size + 2048);
|
||||
*buff_size += 2048;
|
||||
*buff = (char *) ms_realloc(*buff, *buff_size);
|
||||
|
|
@ -271,12 +271,11 @@ static int send_report(LinphoneCall* call, reporting_session_report_t * report,
|
|||
int ret = 0;
|
||||
LinphoneEvent *lev;
|
||||
LinphoneAddress *request_uri;
|
||||
char * domain;
|
||||
const char* route;
|
||||
const char* collector_uri;
|
||||
|
||||
/*if we are on a low bandwidth network, do not send reports to not overload it*/
|
||||
if (linphone_call_params_low_bandwidth_enabled(linphone_call_get_current_params(call))){
|
||||
ms_warning("QualityReporting[%p]: Avoid sending reports on low bandwidth network", call);
|
||||
ms_message("QualityReporting[%p]: Avoid sending reports on low bandwidth network", call);
|
||||
ret = 1;
|
||||
goto end;
|
||||
}
|
||||
|
|
@ -285,7 +284,7 @@ static int send_report(LinphoneCall* call, reporting_session_report_t * report,
|
|||
in that case, we abort the report since it's not useful data*/
|
||||
if (report->info.local_addr.ip == NULL || strlen(report->info.local_addr.ip) == 0
|
||||
|| report->info.remote_addr.ip == NULL || strlen(report->info.remote_addr.ip) == 0) {
|
||||
ms_warning("QualityReporting[%p]: Trying to submit a %s too early (call duration: %d sec) but %s IP could "
|
||||
ms_message("QualityReporting[%p]: Trying to submit a %s too early (call duration: %d sec) but %s IP could "
|
||||
"not be retrieved so dropping this report"
|
||||
, call
|
||||
, report_event
|
||||
|
|
@ -353,14 +352,21 @@ static int send_report(LinphoneCall* call, reporting_session_report_t * report,
|
|||
}
|
||||
|
||||
|
||||
route = linphone_proxy_config_get_quality_reporting_collector(call->dest_proxy);
|
||||
domain = ms_strdup_printf("sip:%s", linphone_proxy_config_get_domain(call->dest_proxy));
|
||||
request_uri = linphone_address_new(route ? route : domain);
|
||||
ms_free(domain);
|
||||
collector_uri = linphone_proxy_config_get_quality_reporting_collector(call->dest_proxy);
|
||||
if (!collector_uri){
|
||||
collector_uri = ms_strdup_printf("sip:%s", linphone_proxy_config_get_domain(call->dest_proxy));
|
||||
}
|
||||
request_uri = linphone_address_new(collector_uri);
|
||||
lev=linphone_core_create_publish(call->core, request_uri, "vq-rtcpxr", expires);
|
||||
if (route) {
|
||||
ms_message("Publishing report with custom route %s", route);
|
||||
sal_op_set_route(lev->op, route);
|
||||
/* Special exception for quality report PUBLISH: if the collector_uri has any transport related parameters
|
||||
* (port, transport, maddr), then it is sent directly.
|
||||
* Otherwise it is routed as any LinphoneEvent publish, following proxy config policy.
|
||||
**/
|
||||
if (sal_address_has_uri_param((SalAddress*)request_uri, "transport") ||
|
||||
sal_address_has_uri_param((SalAddress*)request_uri, "maddr") ||
|
||||
linphone_address_get_port(request_uri) != 0) {
|
||||
ms_message("Publishing report with custom route %s", collector_uri);
|
||||
sal_op_set_route(lev->op, collector_uri);
|
||||
}
|
||||
|
||||
if (linphone_event_send_publish(lev, content) != 0){
|
||||
|
|
|
|||
113
coreapi/ringtoneplayer.c
Normal file
113
coreapi/ringtoneplayer.c
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
linphone
|
||||
Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org)
|
||||
Copyright (C) 2010 Belledonne Communications SARL
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "private.h"
|
||||
#include <mediastreamer2/msfactory.h>
|
||||
|
||||
int linphone_ringtoneplayer_start(MSFactory *factory, LinphoneRingtonePlayer* rp, MSSndCard* card, const char* ringtone, int loop_pause_ms) {
|
||||
return linphone_ringtoneplayer_start_with_cb(factory, rp, card, ringtone, loop_pause_ms, NULL, NULL);
|
||||
}
|
||||
|
||||
#ifdef __ios
|
||||
|
||||
#include "ringtoneplayer_ios.h"
|
||||
|
||||
LinphoneRingtonePlayer* linphone_ringtoneplayer_new() {
|
||||
return linphone_ringtoneplayer_ios_new();
|
||||
}
|
||||
|
||||
void linphone_ringtoneplayer_destroy(LinphoneRingtonePlayer* rp) {
|
||||
linphone_ringtoneplayer_ios_destroy(rp);
|
||||
}
|
||||
|
||||
int linphone_ringtoneplayer_start_with_cb(MSFactory* f, LinphoneRingtonePlayer* rp, MSSndCard* card, const char* ringtone, int loop_pause_ms, LinphoneRingtonePlayerFunc end_of_ringtone, void * user_data) {
|
||||
if (linphone_ringtoneplayer_is_started(rp)) {
|
||||
ms_message("the local ringtone is already started");
|
||||
return 2;
|
||||
}
|
||||
if (ringtone){
|
||||
return linphone_ringtoneplayer_ios_start_with_cb(rp, ringtone, loop_pause_ms, end_of_ringtone, user_data);
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
bool_t linphone_ringtoneplayer_is_started(LinphoneRingtonePlayer* rp) {
|
||||
return linphone_ringtoneplayer_ios_is_started(rp);
|
||||
}
|
||||
|
||||
int linphone_ringtoneplayer_stop(LinphoneRingtonePlayer* rp) {
|
||||
return linphone_ringtoneplayer_ios_stop(rp);
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
struct _LinphoneRingtonePlayer {
|
||||
RingStream *ringstream;
|
||||
LinphoneRingtonePlayerFunc end_of_ringtone;
|
||||
void* end_of_ringtone_ud;
|
||||
};
|
||||
|
||||
LinphoneRingtonePlayer* linphone_ringtoneplayer_new() {
|
||||
LinphoneRingtonePlayer* rp = ms_new0(LinphoneRingtonePlayer, 1);
|
||||
return rp;
|
||||
}
|
||||
|
||||
void linphone_ringtoneplayer_destroy(LinphoneRingtonePlayer* rp) {
|
||||
if (rp->ringstream) {
|
||||
linphone_ringtoneplayer_stop(rp);
|
||||
}
|
||||
ms_free(rp);
|
||||
}
|
||||
|
||||
static void notify_end_of_ringtone(void *ud, MSFilter *f, unsigned int event, void *arg){
|
||||
LinphoneRingtonePlayer *rp=(LinphoneRingtonePlayer*)ud;
|
||||
if (event==MS_PLAYER_EOF && rp->end_of_ringtone){
|
||||
rp->end_of_ringtone(rp, rp->end_of_ringtone_ud, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int linphone_ringtoneplayer_start_with_cb(MSFactory *factory, LinphoneRingtonePlayer* rp, MSSndCard* card, const char* ringtone, int loop_pause_ms, LinphoneRingtonePlayerFunc end_of_ringtone, void * user_data) {
|
||||
if (linphone_ringtoneplayer_is_started(rp)) {
|
||||
ms_message("the local ringtone is already started");
|
||||
return 2;
|
||||
}
|
||||
if (card!=NULL && ringtone){
|
||||
ms_message("Starting local ringtone...");
|
||||
rp->end_of_ringtone = end_of_ringtone;
|
||||
rp->end_of_ringtone_ud = user_data;
|
||||
rp->ringstream=ring_start_with_cb(factory, ringtone,loop_pause_ms,card,notify_end_of_ringtone,rp);
|
||||
return rp->ringstream != NULL ? 0 : 1;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
bool_t linphone_ringtoneplayer_is_started(LinphoneRingtonePlayer* rp) {
|
||||
return (rp->ringstream!=NULL);
|
||||
}
|
||||
|
||||
int linphone_ringtoneplayer_stop(LinphoneRingtonePlayer* rp) {
|
||||
if (rp->ringstream) {
|
||||
ring_stop(rp->ringstream);
|
||||
rp->ringstream = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
41
coreapi/ringtoneplayer.h
Normal file
41
coreapi/ringtoneplayer.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
linphone
|
||||
Copyright (C) 2000 - 2010 Simon MORLAT (simon.morlat@linphone.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef RINGPLAYER_H
|
||||
#define RINGPLAYER_H
|
||||
|
||||
typedef void (*LinphoneRingtonePlayerFunc)(LinphoneRingtonePlayer* rp, void* user_data, int status);
|
||||
|
||||
LINPHONE_PUBLIC LinphoneRingtonePlayer* linphone_ringtoneplayer_new(void);
|
||||
LINPHONE_PUBLIC void linphone_ringtoneplayer_destroy(LinphoneRingtonePlayer* rp);
|
||||
|
||||
LINPHONE_PUBLIC int linphone_ringtoneplayer_start(MSFactory *factory, LinphoneRingtonePlayer* rp, MSSndCard* card, const char* ringtone, int loop_pause_ms);
|
||||
/**
|
||||
* Start a ringtone player
|
||||
* @param rp LinphoneRingtonePlayer object
|
||||
* @param card unused argument
|
||||
* @param ringtone path to the ringtone to play
|
||||
* @param loop_pause_ms pause interval in milliseconds to be observed between end of play and resuming at start. A value of -1 disables loop mode
|
||||
* @return 0 if the player successfully started, positive error code otherwise
|
||||
*/
|
||||
LINPHONE_PUBLIC int linphone_ringtoneplayer_start_with_cb(MSFactory *factory, LinphoneRingtonePlayer* rp, MSSndCard* card,
|
||||
const char* ringtone, int loop_pause_ms, LinphoneRingtonePlayerFunc end_of_ringtone, void * user_data);
|
||||
LINPHONE_PUBLIC bool_t linphone_ringtoneplayer_is_started(LinphoneRingtonePlayer* rp);
|
||||
LINPHONE_PUBLIC int linphone_ringtoneplayer_stop(LinphoneRingtonePlayer* rp);
|
||||
|
||||
#endif
|
||||
27
coreapi/ringtoneplayer_ios.h
Normal file
27
coreapi/ringtoneplayer_ios.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
linphone
|
||||
Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org)
|
||||
Copyright (C) 2010 Belledonne Communications SARL
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "linphonecore.h"
|
||||
|
||||
LinphoneRingtonePlayer* linphone_ringtoneplayer_ios_new();
|
||||
void linphone_ringtoneplayer_ios_destroy(LinphoneRingtonePlayer* rp);
|
||||
int linphone_ringtoneplayer_ios_start_with_cb(LinphoneRingtonePlayer* rp, const char* ringtone, int loop_pause_ms, LinphoneRingtonePlayerFunc end_of_ringtone, void * user_data);
|
||||
bool_t linphone_ringtoneplayer_ios_is_started(LinphoneRingtonePlayer* rp);
|
||||
int linphone_ringtoneplayer_ios_stop(LinphoneRingtonePlayer* rp);
|
||||
88
coreapi/ringtoneplayer_ios.m
Normal file
88
coreapi/ringtoneplayer_ios.m
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
linphone
|
||||
Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org)
|
||||
Copyright (C) 2010 Belledonne Communications SARL
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "ringtoneplayer_ios.h"
|
||||
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
|
||||
@interface AudioPlayerDelegate : NSObject <AVAudioPlayerDelegate>
|
||||
@property (assign) LinphoneRingtonePlayer* ringtonePlayer;
|
||||
@end
|
||||
|
||||
struct _LinphoneRingtonePlayer {
|
||||
AVAudioPlayer* player;
|
||||
AudioPlayerDelegate* playerDelegate;
|
||||
LinphoneRingtonePlayerFunc end_of_ringtone;
|
||||
void* end_of_ringtone_ud;
|
||||
};
|
||||
|
||||
@implementation AudioPlayerDelegate
|
||||
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
|
||||
if (_ringtonePlayer->end_of_ringtone) {
|
||||
_ringtonePlayer->end_of_ringtone(_ringtonePlayer, _ringtonePlayer->end_of_ringtone_ud, !flag);
|
||||
}
|
||||
}
|
||||
- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error {
|
||||
if (_ringtonePlayer->end_of_ringtone) {
|
||||
_ringtonePlayer->end_of_ringtone(_ringtonePlayer, _ringtonePlayer->end_of_ringtone_ud, 1);
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
|
||||
LinphoneRingtonePlayer* linphone_ringtoneplayer_ios_new() {
|
||||
LinphoneRingtonePlayer* rp = ms_new0(LinphoneRingtonePlayer, 1);
|
||||
rp->playerDelegate = [[AudioPlayerDelegate alloc] init];
|
||||
rp->playerDelegate.ringtonePlayer = rp;
|
||||
return rp;
|
||||
}
|
||||
|
||||
void linphone_ringtoneplayer_ios_destroy(LinphoneRingtonePlayer* rp) {
|
||||
linphone_ringtoneplayer_ios_stop(rp);
|
||||
ms_free(rp);
|
||||
}
|
||||
|
||||
int linphone_ringtoneplayer_ios_start_with_cb(LinphoneRingtonePlayer* rp, const char* ringtone, int loop_pause_ms, LinphoneRingtonePlayerFunc end_of_ringtone, void * user_data) {
|
||||
NSURL* url = [NSURL URLWithString:[NSString stringWithUTF8String:ringtone]];
|
||||
ms_message("%s: using ringtone %s", __FUNCTION__, ringtone);
|
||||
if (rp->player) {
|
||||
ms_warning("%s: a player is already instantiated, stopping it first.", __FUNCTION__);
|
||||
linphone_ringtoneplayer_ios_stop(rp);
|
||||
}
|
||||
rp->player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
|
||||
[rp->player prepareToPlay];
|
||||
rp->player.numberOfLoops = (loop_pause_ms >= 0) ? -1 : 0;
|
||||
rp->player.delegate = rp->playerDelegate;
|
||||
rp->end_of_ringtone = end_of_ringtone;
|
||||
rp->end_of_ringtone_ud = user_data;
|
||||
return [rp->player play] ? 0 : 1;
|
||||
}
|
||||
|
||||
bool_t linphone_ringtoneplayer_ios_is_started(LinphoneRingtonePlayer* rp) {
|
||||
return [rp->player isPlaying];
|
||||
}
|
||||
|
||||
int linphone_ringtoneplayer_ios_stop(LinphoneRingtonePlayer* rp) {
|
||||
[rp->player stop];
|
||||
[rp->player release];
|
||||
rp->player = nil;
|
||||
return 0;
|
||||
}
|
||||
182
coreapi/sal.c
182
coreapi/sal.c
|
|
@ -167,7 +167,7 @@ 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<SAL_MEDIA_DESCRIPTION_MAX_STREAMS;++i){
|
||||
const SalStreamDescription *ss=&md->streams[i];
|
||||
|
|
@ -219,6 +219,12 @@ bool_t sal_stream_description_has_avpf(const SalStreamDescription *sd) {
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
bool_t sal_stream_description_has_implicit_avpf(const SalStreamDescription *sd){
|
||||
if (sd->implicit_rtcp_fb){
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
/*these are switch case, so that when a new proto is added we can't forget to modify this function*/
|
||||
bool_t sal_stream_description_has_srtp(const SalStreamDescription *sd) {
|
||||
switch (sd->proto){
|
||||
|
|
@ -260,6 +266,16 @@ bool_t sal_media_description_has_avpf(const SalMediaDescription *md) {
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
bool_t sal_media_description_has_implicit_avpf(const SalMediaDescription *md) {
|
||||
int i;
|
||||
if (md->nb_streams == 0) return FALSE;
|
||||
for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) {
|
||||
if (!sal_stream_description_active(&md->streams[i])) continue;
|
||||
if (sal_stream_description_has_implicit_avpf(&md->streams[i]) != TRUE) return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool_t sal_media_description_has_srtp(const SalMediaDescription *md) {
|
||||
int i;
|
||||
if (md->nb_streams == 0) return FALSE;
|
||||
|
|
@ -554,13 +570,6 @@ const SalAddress *sal_op_get_to_address(const SalOp *op){
|
|||
return ((SalOpBase*)op)->to_address;
|
||||
}
|
||||
|
||||
const char *sal_op_get_route(const SalOp *op){
|
||||
#ifdef BELLE_SIP
|
||||
ms_fatal("sal_op_get_route not supported, use sal_op_get_route_addresses instead");
|
||||
#endif
|
||||
return ((SalOpBase*)op)->route;
|
||||
}
|
||||
|
||||
const char *sal_op_get_remote_ua(const SalOp *op){
|
||||
return ((SalOpBase*)op)->remote_ua;
|
||||
}
|
||||
|
|
@ -597,7 +606,9 @@ void __sal_op_set_network_origin(SalOp *op, const char *origin){
|
|||
}
|
||||
|
||||
void __sal_op_set_remote_contact(SalOp *op, const char* remote_contact){
|
||||
SET_PARAM(op,remote_contact);
|
||||
assign_address(&((SalOpBase*)op)->remote_contact_address,remote_contact);\
|
||||
/*to preserve header params*/
|
||||
assign_string(&((SalOpBase*)op)->remote_contact,remote_contact); \
|
||||
}
|
||||
|
||||
void __sal_op_set_network_origin_address(SalOp *op, SalAddress *origin){
|
||||
|
|
@ -678,6 +689,11 @@ void __sal_op_free(SalOp *op){
|
|||
sal_custom_header_free(b->recv_custom_headers);
|
||||
if (b->sent_custom_headers)
|
||||
sal_custom_header_free(b->sent_custom_headers);
|
||||
|
||||
if (b->entity_tag != NULL){
|
||||
ms_free(b->entity_tag);
|
||||
b->entity_tag = NULL;
|
||||
}
|
||||
ms_free(op);
|
||||
}
|
||||
|
||||
|
|
@ -807,7 +823,7 @@ const char* sal_privacy_to_string(SalPrivacy privacy) {
|
|||
}
|
||||
|
||||
static void remove_trailing_spaces(char *line){
|
||||
size_t i;
|
||||
int i;
|
||||
for(i=strlen(line)-1;i>=0;--i){
|
||||
if (isspace(line[i])) line[i]='\0';
|
||||
else break;
|
||||
|
|
@ -849,10 +865,134 @@ int sal_lines_get_value(const char *data, const char *key, char *value, size_t v
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
int sal_body_has_type(const SalBody *body, const char *type, const char *subtype){
|
||||
return body->type && body->subtype
|
||||
&& strcmp(body->type,type)==0
|
||||
&& strcmp(body->subtype,subtype)==0;
|
||||
static belle_sip_header_t * sal_body_handler_find_header(const SalBodyHandler *body_handler, const char *header_name) {
|
||||
belle_sip_body_handler_t *bsbh = BELLE_SIP_BODY_HANDLER(body_handler);
|
||||
const belle_sip_list_t *l = belle_sip_body_handler_get_headers(bsbh);
|
||||
for (; l != NULL; l = l->next) {
|
||||
belle_sip_header_t *header = BELLE_SIP_HEADER(l->data);
|
||||
if (strcmp(belle_sip_header_get_name(header), header_name) == 0) {
|
||||
return header;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SalBodyHandler * sal_body_handler_new(void) {
|
||||
belle_sip_memory_body_handler_t *body_handler = belle_sip_memory_body_handler_new(NULL, NULL);
|
||||
return (SalBodyHandler *)BELLE_SIP_BODY_HANDLER(body_handler);
|
||||
}
|
||||
|
||||
SalBodyHandler * sal_body_handler_ref(SalBodyHandler *body_handler) {
|
||||
return (SalBodyHandler *)belle_sip_object_ref(BELLE_SIP_OBJECT(body_handler));
|
||||
}
|
||||
|
||||
void sal_body_handler_unref(SalBodyHandler *body_handler) {
|
||||
belle_sip_object_unref(BELLE_SIP_OBJECT(body_handler));
|
||||
}
|
||||
|
||||
const char * sal_body_handler_get_type(const SalBodyHandler *body_handler) {
|
||||
belle_sip_header_content_type_t *content_type = BELLE_SIP_HEADER_CONTENT_TYPE(sal_body_handler_find_header(body_handler, "Content-Type"));
|
||||
if (content_type != NULL) {
|
||||
return belle_sip_header_content_type_get_type(content_type);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void sal_body_handler_set_type(SalBodyHandler *body_handler, const char *type) {
|
||||
belle_sip_header_content_type_t *content_type = BELLE_SIP_HEADER_CONTENT_TYPE(sal_body_handler_find_header(body_handler, "Content-Type"));
|
||||
if (content_type == NULL) {
|
||||
content_type = belle_sip_header_content_type_new();
|
||||
belle_sip_body_handler_add_header(BELLE_SIP_BODY_HANDLER(body_handler), BELLE_SIP_HEADER(content_type));
|
||||
}
|
||||
belle_sip_header_content_type_set_type(content_type, type);
|
||||
}
|
||||
|
||||
const char * sal_body_handler_get_subtype(const SalBodyHandler *body_handler) {
|
||||
belle_sip_header_content_type_t *content_type = BELLE_SIP_HEADER_CONTENT_TYPE(sal_body_handler_find_header(body_handler, "Content-Type"));
|
||||
if (content_type != NULL) {
|
||||
return belle_sip_header_content_type_get_subtype(content_type);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void sal_body_handler_set_subtype(SalBodyHandler *body_handler, const char *subtype) {
|
||||
belle_sip_header_content_type_t *content_type = BELLE_SIP_HEADER_CONTENT_TYPE(sal_body_handler_find_header(body_handler, "Content-Type"));
|
||||
if (content_type == NULL) {
|
||||
content_type = belle_sip_header_content_type_new();
|
||||
belle_sip_body_handler_add_header(BELLE_SIP_BODY_HANDLER(body_handler), BELLE_SIP_HEADER(content_type));
|
||||
}
|
||||
belle_sip_header_content_type_set_subtype(content_type, subtype);
|
||||
}
|
||||
|
||||
const char * sal_body_handler_get_encoding(const SalBodyHandler *body_handler) {
|
||||
belle_sip_header_t *content_encoding = sal_body_handler_find_header(body_handler, "Content-Encoding");
|
||||
if (content_encoding != NULL) {
|
||||
return belle_sip_header_get_unparsed_value(content_encoding);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void sal_body_handler_set_encoding(SalBodyHandler *body_handler, const char *encoding) {
|
||||
belle_sip_header_t *content_encoding = sal_body_handler_find_header(body_handler, "Content-Encoding");
|
||||
if (content_encoding != NULL) {
|
||||
belle_sip_body_handler_remove_header_from_ptr(BELLE_SIP_BODY_HANDLER(body_handler), content_encoding);
|
||||
}
|
||||
belle_sip_body_handler_add_header(BELLE_SIP_BODY_HANDLER(body_handler), belle_sip_header_create("Content-Encoding", encoding));
|
||||
}
|
||||
|
||||
void * sal_body_handler_get_data(const SalBodyHandler *body_handler) {
|
||||
return belle_sip_memory_body_handler_get_buffer(BELLE_SIP_MEMORY_BODY_HANDLER(body_handler));
|
||||
}
|
||||
|
||||
void sal_body_handler_set_data(SalBodyHandler *body_handler, void *data) {
|
||||
belle_sip_memory_body_handler_set_buffer(BELLE_SIP_MEMORY_BODY_HANDLER(body_handler), data);
|
||||
}
|
||||
|
||||
size_t sal_body_handler_get_size(const SalBodyHandler *body_handler) {
|
||||
return belle_sip_body_handler_get_size(BELLE_SIP_BODY_HANDLER(body_handler));
|
||||
}
|
||||
|
||||
void sal_body_handler_set_size(SalBodyHandler *body_handler, size_t size) {
|
||||
belle_sip_header_content_length_t *content_length = BELLE_SIP_HEADER_CONTENT_LENGTH(sal_body_handler_find_header(body_handler, "Content-Length"));
|
||||
if (content_length == NULL) {
|
||||
content_length = belle_sip_header_content_length_new();
|
||||
belle_sip_body_handler_add_header(BELLE_SIP_BODY_HANDLER(body_handler), BELLE_SIP_HEADER(content_length));
|
||||
}
|
||||
belle_sip_header_content_length_set_content_length(content_length, size);
|
||||
belle_sip_body_handler_set_size(BELLE_SIP_BODY_HANDLER(body_handler), size);
|
||||
}
|
||||
|
||||
bool_t sal_body_handler_is_multipart(const SalBodyHandler *body_handler) {
|
||||
if (BELLE_SIP_IS_INSTANCE_OF(body_handler, belle_sip_multipart_body_handler_t)) return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
SalBodyHandler * sal_body_handler_get_part(const SalBodyHandler *body_handler, int idx) {
|
||||
const belle_sip_list_t *l = belle_sip_multipart_body_handler_get_parts(BELLE_SIP_MULTIPART_BODY_HANDLER(body_handler));
|
||||
return (SalBodyHandler *)belle_sip_list_nth_data(l, idx);
|
||||
}
|
||||
|
||||
SalBodyHandler * sal_body_handler_find_part_by_header(const SalBodyHandler *body_handler, const char *header_name, const char *header_value) {
|
||||
const belle_sip_list_t *l = belle_sip_multipart_body_handler_get_parts(BELLE_SIP_MULTIPART_BODY_HANDLER(body_handler));
|
||||
for (; l != NULL; l = l->next) {
|
||||
belle_sip_body_handler_t *bsbh = BELLE_SIP_BODY_HANDLER(l->data);
|
||||
const belle_sip_list_t *headers = belle_sip_body_handler_get_headers(bsbh);
|
||||
for (; headers != NULL; headers = headers->next) {
|
||||
belle_sip_header_t *header = BELLE_SIP_HEADER(headers->data);
|
||||
if ((strcmp(belle_sip_header_get_name(header), header_name) == 0) && (strcmp(belle_sip_header_get_unparsed_value(header), header_value) == 0)) {
|
||||
return (SalBodyHandler *)bsbh;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char * sal_body_handler_get_header(const SalBodyHandler *body_handler, const char *header_name) {
|
||||
belle_sip_header_t *header = sal_body_handler_find_header(body_handler, header_name);
|
||||
if (header != NULL) {
|
||||
return belle_sip_header_get_unparsed_value(header);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
belle_sip_stack_t *sal_get_belle_sip_stack(Sal *sal) {
|
||||
|
|
@ -865,3 +1005,17 @@ char* sal_op_get_public_uri(SalOp *op) {
|
|||
}
|
||||
return NULL;
|
||||
}
|
||||
const char *sal_op_get_entity_tag(const SalOp* op) {
|
||||
SalOpBase* op_base = (SalOpBase*)op;
|
||||
return op_base->entity_tag;
|
||||
}
|
||||
void sal_op_set_entity_tag(SalOp *op, const char* entity_tag) {
|
||||
SalOpBase* op_base = (SalOpBase*)op;
|
||||
if (op_base->entity_tag != NULL){
|
||||
ms_free(op_base->entity_tag);
|
||||
}
|
||||
if (entity_tag)
|
||||
op_base->entity_tag = ms_strdup(entity_tag);
|
||||
else
|
||||
op_base->entity_tag = NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,9 +35,10 @@ void sip_setup_register(SipSetup *ss){
|
|||
registered_sip_setups=ms_list_append(registered_sip_setups,ss);
|
||||
}
|
||||
|
||||
void sip_setup_register_all(void){
|
||||
void sip_setup_register_all(MSFactory *factory){
|
||||
SipSetup **p=all_sip_setups;
|
||||
ms_load_plugins(LINPHONE_PLUGINS_DIR);
|
||||
ms_factory_load_plugins(factory, LINPHONE_PLUGINS_DIR);
|
||||
//ms_load_plugins(LINPHONE_PLUGINS_DIR);
|
||||
while(*p!=NULL){
|
||||
sip_setup_register(*p);
|
||||
p++;
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ void buddy_lookup_request_set_max_results(BuddyLookupRequest *req, int ncount);
|
|||
|
||||
|
||||
void sip_setup_register(SipSetup *ss);
|
||||
void sip_setup_register_all(void);
|
||||
void sip_setup_register_all(MSFactory* factory);
|
||||
SipSetup *sip_setup_lookup(const char *type_name);
|
||||
void sip_setup_unregister_all(void);
|
||||
LINPHONE_PUBLIC unsigned int sip_setup_get_capabilities(SipSetup *s);
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue