Merge remote-tracking branch 'origin/master' into dev_dtls

This commit is contained in:
Johan Pascal 2015-01-05 18:17:05 +01:00
commit e93a80f322
73 changed files with 2254 additions and 840 deletions

View file

@ -101,6 +101,15 @@ if(ENABLE_NOTIFY)
set(ENABLE_NOTIFY OFF CACHE BOOL "Enable libnotify support." FORCE)
endif()
endif()
if(ENABLE_ASSISTANT)
find_package(Soup)
if(SOUP_FOUND)
set(BUILD_WIZARD 1)
else()
message(WARNING "Could not find the soup library!")
set(ENABLE_ASSISTANT OFF CACHE BOOL "Turn on assistant compiling." FORCE)
endif()
endif()
find_package(Gettext)
@ -120,6 +129,9 @@ endif()
if(ENABLE_TUNNEL)
include_directories(${TUNNEL_INCLUDE_DIRS})
endif()
if(ENABLE_ASSISTANT)
include_directories(${SOUP_INCLUDE_DIRS})
endif()
if(MSVC)
include_directories(${CMAKE_PREFIX_PATH}/include/MSVC)

11
NEWS
View file

@ -1,3 +1,14 @@
linphone-3.8.0 -- Date to be defined
Application level improvements:
* The video window has now controls in order to switch fullscreen mode and terminate call.
* The out of call video preview feature (to test camera) is moved into the settings and is no longer linked to the in-call video preview feature.
* Lots of updated translations.
Liblinphone level improvements:
* Support for RTP/AVPF (RFCxxxx) for video streams, allowing fast transmission error recovery with VP8 codec only.
* API enhancements, most objects can be ref-counted.
* Call video recording feature, in mkv format (H264 streams only for the moment)
linphone-3.7.0 -- February 20th, 2014
Application level improvements:
* It is now possible to configure multiple proxy accounts with different transports (UDP, TCP, TLS)

View file

@ -1,12 +1,18 @@
# Compiling Linphone on MacOS X
# Linphone on MacOS X
## Dependencies
## Build prerequisite
* Xcode (download from apple or using appstore application)
* Java SE
* [HomeBrew](http://brew.sh) or [Macports](http://www.macports.org/).
* [Java SE](http://www.oracle.com/technetwork/java/javase/downloads/index.html) or openJDK
This is required to generate a C sourcefile from SIP grammar using [antlr3](http://www.antlr3.org/) generator.
* [HomeBrew](http://brew.sh) or [Macports](http://www.macports.org/).
* [XQuartz](https://xquartz.macosforge.org) for GTK version.
### Multiple MacOS version support
### Dependencies
#### Using MacPorts
##### Multiple MacOS version support
In order to enable generation of bundle for multiple MacOS version and 32 bit processors, it is recommended to:
@ -18,17 +24,16 @@ In order to enable generation of bundle for multiple MacOS version and 32 bit pr
> +universal
### Build time dependencies
#### Using MacPorts
##### Linphone library (liblinphone)
* Linphone core dependencies
sudo port install automake autoconf libtool intltool wget cunit \
sudo port install automake autoconf libtool pkgconfig intltool wget cunit \
antlr3 speex libvpx readline sqlite3 libsoup openldap libupnp \
ffmpeg-devel -gpl2
* UI dependencies: install `GTK`. It is recommended to use the `quartz` backend for better integration.
##### Linphone UI (GTK version)
Install `GTK`. It is recommended to use the `quartz` backend for better integration.
sudo port install gtk2 +quartz +no_x11
sudo port install gtk-osx-application -python27
@ -36,15 +41,21 @@ In order to enable generation of bundle for multiple MacOS version and 32 bit pr
#### Using HomeBrew
brew install automake intltool libtool pkg-config coreutils \
yasm nasm wget imagemagick gettext gtk+ speex ffmpeg pygtk
brew link gettext --force
# readline is required from linphonec.c otherwise compilation will fail
brew link readline --force
##### Linphone library (liblinphone)
# then you have to install some dependencies from a tap.
brew tap Gui13/linphone
brew install antlr3.2 libantlr3.4c mattintosh4/gtk-mac-integration/gtk-mac-integration
brew install intltool libtool wget pkg-config automake libantlr3.4c \
antlr3.2 gettext speex ffmpeg readline libvpx opus
ln -s /usr/local/bin/glibtoolize /usr/local/bin/libtoolize
brew link --force gettext
##### Linphone UI (GTK version)
brew install cairo --without-x11
brew install gtk+ --without-x11
brew install gettext gtk-mac-integration libsoup
#readline is required from linphonec.c otherwise compilation will fail
brew link readline --force
### Building Linphone
@ -58,7 +69,7 @@ The next pieces need to be compiled manually.
export CXXFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5"
export LDFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5 -Wl,-headerpad_max_install_names -Wl,-read_only_relocs -Wl,suppress"
* Install libantlr3c (library used by belle-sip for parsing)
* (MacPorts only) Install libantlr3c (library used by belle-sip for parsing)
git clone -b linphone git://git.linphone.org/antlr3.git
cd antlr3/runtime/C
@ -112,11 +123,12 @@ The libvpx build isn't able to produce dual architecture files. To workaround th
If you got the source code from git, run `./autogen.sh` first.
Then or otherwise, :
PKG_CONFIG_PATH=/usr/local/lib/pkgconfig ./configure --prefix=/opt/local --disable-x11 --with-srtp=/opt/local --with-gsm=/opt/local --enable-zrtp --disable-strict && make
PKG_CONFIG_PATH=/usr/local/lib/pkgconfig ./configure --prefix=/opt/local --with-srtp=/opt/local --with-gsm=/opt/local --enable-zrtp --disable-strict && make
* Install on the system
sudo make install
You are done.
### Generate portable bundle
@ -126,7 +138,7 @@ If you want to generate a portable bundle, then install `gtk-mac-bundler`:
git clone https://github.com/jralls/gtk-mac-bundler.git
cd gtk-mac-bundler && make install
export PATH=$PATH:~/.local/bin
#make this dummy charset.alias file for the bundler to be happy:
# make this dummy charset.alias file for the bundler to be happy:
sudo touch /opt/local/lib/charset.alias
The bundler file in `build/MacOS/linphone.bundle` expects some plugins to be installed in `/opt/local/lib/mediastreamer/plugins`.

View file

@ -40,6 +40,7 @@ LOCAL_SRC_FILES := \
bellesip_sal/sal_op_publish.c \
bellesip_sal/sal_op_registration.c \
bellesip_sal/sal_sdp.c \
buffer.c \
callbacks.c \
call_log.c \
call_params.c \

View file

@ -110,6 +110,7 @@
<ClCompile Include="..\..\coreapi\bellesip_sal\sal_op_publish.c" />
<ClCompile Include="..\..\coreapi\bellesip_sal\sal_op_registration.c" />
<ClCompile Include="..\..\coreapi\bellesip_sal\sal_sdp.c" />
<ClCompile Include="..\..\coreapi\buffer.c" />
<ClCompile Include="..\..\coreapi\call_log.c" />
<ClCompile Include="..\..\coreapi\call_params.c" />
<ClCompile Include="..\..\coreapi\callbacks.c" />
@ -145,6 +146,7 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\coreapi\bellesip_sal\sal_impl.h" />
<ClInclude Include="..\..\coreapi\buffer.h" />
<ClInclude Include="..\..\coreapi\content.h" />
<ClInclude Include="..\..\coreapi\enum.h" />
<ClInclude Include="..\..\coreapi\event.h" />

View file

@ -22,9 +22,9 @@
#
# - Find the notify include file and library
#
# NOTIFY_FOUND - system has linphone
# NOTIFY_INCLUDE_DIRS - the linphone include directory
# NOTIFY_LIBRARIES - The libraries needed to use linphone
# NOTIFY_FOUND - system has libnotify
# NOTIFY_INCLUDE_DIRS - the libnotify include directory
# NOTIFY_LIBRARIES - The libraries needed to use libnotify
set(_NOTIFY_ROOT_PATHS
${WITH_NOTIFY}

63
cmake/FindSoup.cmake Normal file
View file

@ -0,0 +1,63 @@
############################################################################
# FindSoup.cmake
# Copyright (C) 2014 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 soup include file and library
#
# SOUP_FOUND - system has libsoup
# SOUP_INCLUDE_DIRS - the libsoup include directory
# SOUP_LIBRARIES - The libraries needed to use libsoup
find_package(GTK2 2.18 REQUIRED gtk)
set(_SOUP_ROOT_PATHS
${WITH_SOUP}
${CMAKE_INSTALL_PREFIX}
)
find_path(SOUP_INCLUDE_DIRS
NAMES libsoup/soup.h
HINTS _SOUP_ROOT_PATHS
PATH_SUFFIXES include/libsoup-2.4
)
if(SOUP_INCLUDE_DIRS)
set(HAVE_LIBSOUP_SOUP_H 1)
list(APPEND SOUP_INCLUDE_DIRS ${GTK2_INCLUDE_DIRS})
endif()
find_library(SOUP_LIBRARIES
NAMES soup-2.4
HINTS ${_SOUP_ROOT_PATHS}
PATH_SUFFIXES bin lib
)
if(SOUP_LIBRARIES)
list(APPEND SOUP_LIBRARIES ${GTK2_LIBRARIES})
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Soup
DEFAULT_MSG
SOUP_INCLUDE_DIRS SOUP_LIBRARIES HAVE_LIBSOUP_SOUP_H
)
mark_as_advanced(SOUP_INCLUDE_DIRS SOUP_LIBRARIES HAVE_LIBSOUP_SOUP_H)

View file

@ -36,6 +36,7 @@
#define PACKAGE_DATA_DIR "${PACKAGE_DATA_DIR}"
#define PACKAGE_SOUND_DIR "${PACKAGE_SOUND_DIR}"
#cmakedefine BUILD_WIZARD
#cmakedefine HAVE_NOTIFY4
#cmakedefine HAVE_CU_GET_SUITE 1
#cmakedefine HAVE_CU_CURSES 1

View file

@ -158,13 +158,16 @@ dnl AC_CHECK_LIB(intl,libintl_gettext)
AC_CHECK_FUNCS([get_current_dir_name strndup stpcpy] )
AC_ARG_ENABLE(x11,
[AS_HELP_STRING([--disable-x11], [Disable X11 support (default=no)])],
[AS_HELP_STRING([--disable-x11], [Disable X11 support (default=yes for MacOSX, no otherwise)])],
[case "${enableval}" in
yes) enable_x11=true ;;
no) enable_x11=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --disable-x11) ;;
esac],
[enable_x11=true]
[case "$target_os" in
*darwin*) enable_x11=false ;; #disable x11 on MacOS by default
*) enable_x11=true ;;
esac]
)
dnl conditional build of LDAP support
@ -792,8 +795,6 @@ AC_ARG_ENABLE(msg-storage,
[enable_msg_storage=auto]
)
AM_CONDITIONAL(BUILD_MSG_STORAGE, test x$enable_msg_storage = xtrue)
if test x$enable_msg_storage != xfalse; then
PKG_CHECK_MODULES(SQLITE3,[sqlite3 >= 3.6.0],[found_sqlite=yes],[found_sqlite=no])
if test "$found_sqlite" = "no"; then
@ -802,6 +803,7 @@ if test x$enable_msg_storage != xfalse; then
fi
if test "$found_sqlite" = "yes"; then
SQLITE3_CFLAGS+="-DMSG_STORAGE_ENABLED"
enable_msg_storage=true
else
if test x$enable_msg_storage = xtrue; then
AC_MSG_ERROR([sqlite3, required for message storage, not found])
@ -813,7 +815,7 @@ if test x$enable_msg_storage != xfalse; then
AC_SUBST(SQLITE3_LIBS)
fi
AM_CONDITIONAL(BUILD_MSG_STORAGE, test x$enable_msg_storage = xtrue)
PKG_CHECK_MODULES(BELLESIP, [belle-sip >= 1.3.1])

View file

@ -42,6 +42,7 @@ set(SOURCE_FILES
bellesip_sal/sal_op_publish.c
bellesip_sal/sal_op_registration.c
bellesip_sal/sal_sdp.c
buffer.c
callbacks.c
call_log.c
call_params.c
@ -96,6 +97,9 @@ if(ENABLE_TUNNEL)
else()
list(APPEND SOURCE_FILES linphone_tunnel_stubs.c)
endif()
if(ENABLE_ASSISTANT)
list(APPEND SOURCE_FILES sipwizard.c)
endif()
set(GENERATED_SOURCE_FILES
${CMAKE_CURRENT_BINARY_DIR}/liblinphone_gitversion.h
@ -123,6 +127,9 @@ endif()
if(ENABLE_TUNNEL)
list(APPEND LIBS ${TUNNEL_LIBRARIES})
endif()
if(ENABLE_ASSISTANT)
list(APPEND LIBS ${SOUP_LIBRARIES})
endif()
if(WIN32)
list(APPEND LIBS shlwapi)
endif()
@ -153,6 +160,7 @@ install(TARGETS linphone
set(HEADER_FILES
buffer.h
call_log.h
call_params.h
content.h

View file

@ -25,6 +25,7 @@ CLEANFILES=$(GITVERSION_FILE)
linphone_includedir=$(includedir)/linphone
linphone_include_HEADERS=\
buffer.h \
call_log.h \
call_params.h \
content.h \
@ -44,6 +45,7 @@ lib_LTLIBRARIES=liblinphone.la
liblinphone_la_SOURCES=\
address.c \
authentication.c \
buffer.c \
callbacks.c \
call_log.c \
call_params.c \

View file

@ -1077,27 +1077,27 @@ void sal_signing_key_parse_file(SalAuthInfo* auth_info, const char* path, const
* Parse a directory to get a certificate with the given subject common name
*
*/
void sal_certificates_chain_parse_directory(unsigned char **certificate_pem, unsigned char **key_pem, unsigned char **fingerprint, const char* path, const char *subject, SalCertificateRawFormat format, bool_t generate_certificate, bool_t generate_dtls_fingerprint) {
void sal_certificates_chain_parse_directory(char **certificate_pem, char **key_pem, char **fingerprint, const char* path, const char *subject, SalCertificateRawFormat format, bool_t generate_certificate, bool_t generate_dtls_fingerprint) {
belle_sip_certificates_chain_t *certificate = NULL;
belle_sip_signing_key_t *key = NULL;
*certificate_pem = NULL;
*key_pem = NULL;
if (belle_sip_get_certificate_and_pkey_in_dir(path, subject, &certificate, &key, (belle_sip_certificate_raw_format_t)format) == 0) {
*certificate_pem = belle_sip_get_certificates_pem(certificate);
*key_pem = belle_sip_get_key_pem(key);
*certificate_pem = belle_sip_certificates_chain_get_pem(certificate);
*key_pem = belle_sip_signing_key_get_pem(key);
ms_message("Retrieve certificate with CN=%s successful\n", subject);
} else {
if (generate_certificate == TRUE) {
if ( belle_sip_generate_self_signed_certificate(path, subject, &certificate, &key) == 0) {
*certificate_pem = belle_sip_get_certificates_pem(certificate);
*key_pem = belle_sip_get_key_pem(key);
*certificate_pem = belle_sip_certificates_chain_get_pem(certificate);
*key_pem = belle_sip_signing_key_get_pem(key);
ms_message("Generate self-signed certificate with CN=%s successful\n", subject);
}
}
}
/* generate the fingerprint as described in RFC4572 if needed */
if ((generate_dtls_fingerprint == TRUE) && (fingerprint != NULL)) {
*fingerprint = belle_sip_generate_certificate_fingerprint(certificate);
*fingerprint = belle_sip_certificates_chain_get_fingerprint(certificate);
}
/* free key and certificate */

View file

@ -62,16 +62,19 @@ static void sdp_process(SalOp *h){
strcpy(h->result->addr,h->base.remote_media->addr);
h->result->bandwidth=h->base.remote_media->bandwidth;
for(i=0;i<sal_media_description_get_nb_active_streams(h->result);++i){
strcpy(h->result->streams[i].rtp_addr,h->base.remote_media->streams[i].rtp_addr);
h->result->streams[i].ptime=h->base.remote_media->streams[i].ptime;
h->result->streams[i].bandwidth=h->base.remote_media->streams[i].bandwidth;
h->result->streams[i].rtp_port=h->base.remote_media->streams[i].rtp_port;
strcpy(h->result->streams[i].rtcp_addr,h->base.remote_media->streams[i].rtcp_addr);
h->result->streams[i].rtcp_port=h->base.remote_media->streams[i].rtcp_port;
for(i=0;i<h->result->nb_streams;++i){
/*copy back parameters from remote description that we need in our result description*/
if (h->result->streams[i].rtp_port!=0){ /*if stream was accepted*/
strcpy(h->result->streams[i].rtp_addr,h->base.remote_media->streams[i].rtp_addr);
h->result->streams[i].ptime=h->base.remote_media->streams[i].ptime;
h->result->streams[i].bandwidth=h->base.remote_media->streams[i].bandwidth;
h->result->streams[i].rtp_port=h->base.remote_media->streams[i].rtp_port;
strcpy(h->result->streams[i].rtcp_addr,h->base.remote_media->streams[i].rtcp_addr);
h->result->streams[i].rtcp_port=h->base.remote_media->streams[i].rtcp_port;
if ((h->result->streams[i].proto == SalProtoRtpSavpf) || (h->result->streams[i].proto == SalProtoRtpSavp)) {
h->result->streams[i].crypto[0] = h->base.remote_media->streams[i].crypto[0];
if ((h->result->streams[i].proto == SalProtoRtpSavpf) || (h->result->streams[i].proto == SalProtoRtpSavp)) {
h->result->streams[i].crypto[0] = h->base.remote_media->streams[i].crypto[0];
}
}
}
}

View file

@ -252,10 +252,8 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session
}
belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("fingerprint",stream->dtls_fingerprint));
}
/*belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("ssrc",ssrc_attribute));*/
belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("ssrc",ssrc_attribute)); /* truc de Jehan a virer? */
ms_free(ssrc_attribute);
}
switch ( stream->dir ) {
@ -771,13 +769,13 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md,
stream->dtls_role = SalDtlsRoleIsServer;
}
if (stream->dtls_role != SalDtlsRoleInvalid) {
if (stream->dtls_role != SalDtlsRoleInvalid || md->dtls_role != SalDtlsRoleInvalid) {
attribute=belle_sdp_media_description_get_attribute(media_desc,"fingerprint");
if (attribute && (value=belle_sdp_attribute_get_value(attribute))!=NULL){
strncpy(stream->dtls_fingerprint, value, strlen(value)+1);
strncpy(stream->dtls_fingerprint, value, sizeof(stream->dtls_fingerprint)-1);
} else {
/* no valid stream attributes, get them from session */
stream->dtls_role = md->dtls_role;
if (stream->dtls_role == SalDtlsRoleInvalid) stream->dtls_role = md->dtls_role;
strncpy(stream->dtls_fingerprint, md->dtls_fingerprint, strlen(md->dtls_fingerprint)+1);
}
}
@ -858,17 +856,11 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S
}
}
if (desc->dtls_role != SalDtlsRoleInvalid) {
value=belle_sdp_session_description_get_attribute_value(session_desc,"fingerprint");
if (value){
strncpy(desc->dtls_fingerprint, value, strlen(value)+1);
} else {
desc->dtls_role = SalDtlsRoleInvalid;
}
value=belle_sdp_session_description_get_attribute_value(session_desc,"fingerprint");
if (value){
strncpy(desc->dtls_fingerprint, value, sizeof(desc->dtls_fingerprint)-1);
}
/* Get ICE remote ufrag and remote pwd, and ice_lite flag */
value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-ufrag");
if (value) strncpy(desc->ice_ufrag, value, sizeof(desc->ice_ufrag) - 1);

106
coreapi/buffer.c Normal file
View file

@ -0,0 +1,106 @@
/*
linphone
Copyright (C) 2010-2014 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"
static void linphone_buffer_destroy(LinphoneBuffer *buffer) {
if (buffer->content) belle_sip_free(buffer->content);
}
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneBuffer);
BELLE_SIP_INSTANCIATE_VPTR(LinphoneBuffer, belle_sip_object_t,
(belle_sip_object_destroy_t)linphone_buffer_destroy,
NULL, // clone
NULL, // marshal
TRUE
);
LinphoneBuffer * linphone_buffer_new(void) {
LinphoneBuffer *buffer = belle_sip_object_new(LinphoneBuffer);
belle_sip_object_ref(buffer);
return buffer;
}
LinphoneBuffer * linphone_buffer_new_from_data(const uint8_t *data, size_t size) {
LinphoneBuffer *buffer = linphone_buffer_new();
linphone_buffer_set_content(buffer, data, size);
return buffer;
}
LinphoneBuffer * linphone_buffer_new_from_string(const char *data) {
LinphoneBuffer *buffer = linphone_buffer_new();
linphone_buffer_set_string_content(buffer, data);
return buffer;
}
LinphoneBuffer * linphone_buffer_ref(LinphoneBuffer *buffer) {
belle_sip_object_ref(buffer);
return buffer;
}
void linphone_buffer_unref(LinphoneBuffer *buffer) {
belle_sip_object_unref(buffer);
}
void *linphone_buffer_get_user_data(const LinphoneBuffer *buffer) {
return buffer->user_data;
}
void linphone_buffer_set_user_data(LinphoneBuffer *buffer, void *ud) {
buffer->user_data = ud;
}
const uint8_t * linphone_buffer_get_content(const LinphoneBuffer *buffer) {
return buffer->content;
}
void linphone_buffer_set_content(LinphoneBuffer *buffer, const uint8_t *content, size_t size) {
buffer->size = size;
if (buffer->content) belle_sip_free(buffer->content);
buffer->content = belle_sip_malloc(size + 1);
memcpy(buffer->content, content, size);
((char *)buffer->content)[size] = '\0';
}
const char * linphone_buffer_get_string_content(const LinphoneBuffer *buffer) {
return (const char *)buffer->content;
}
void linphone_buffer_set_string_content(LinphoneBuffer *buffer, const char *content) {
buffer->size = strlen(content);
if (buffer->content) belle_sip_free(buffer->content);
buffer->content = (uint8_t *)belle_sip_strdup(content);
}
size_t linphone_buffer_get_size(const LinphoneBuffer *buffer) {
return buffer->size;
}
void linphone_buffer_set_size(LinphoneBuffer *buffer, size_t size) {
buffer->size = size;
}
bool_t linphone_buffer_is_empty(const LinphoneBuffer *buffer) {
return (buffer->size == 0) ? TRUE : FALSE;
}

147
coreapi/buffer.h Normal file
View file

@ -0,0 +1,147 @@
/*
buffer.h
Copyright (C) 2010-2014 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_BUFFER_H_
#define LINPHONE_BUFFER_H_
#ifdef __cplusplus
extern "C" {
#endif
/**
* @addtogroup misc
* @{
*/
/**
* The LinphoneContent object representing a data buffer.
**/
typedef struct _LinphoneBuffer LinphoneBuffer;
/**
* Create a new empty LinphoneBuffer object.
* @return A new LinphoneBuffer object.
*/
LINPHONE_PUBLIC LinphoneBuffer * linphone_buffer_new(void);
/**
* Create a new LinphoneBuffer object from existing data.
* @param[in] data The initial data to store in the LinphoneBuffer.
* @param[in] size The size of the initial data to stroe in the LinphoneBuffer.
* @return A new LinphoneBuffer object.
*/
LINPHONE_PUBLIC LinphoneBuffer * linphone_buffer_new_from_data(const uint8_t *data, size_t size);
/**
* Create a new LinphoneBuffer object from a string.
* @param[in] data The initial string content of the LinphoneBuffer.
* @return A new LinphoneBuffer object.
*/
LINPHONE_PUBLIC LinphoneBuffer * linphone_buffer_new_from_string(const char *data);
/**
* Acquire a reference to the buffer.
* @param[in] buffer LinphoneBuffer object.
* @return The same LinphoneBuffer object.
**/
LINPHONE_PUBLIC LinphoneBuffer * linphone_buffer_ref(LinphoneBuffer *buffer);
/**
* Release reference to the buffer.
* @param[in] buffer LinphoneBuffer object.
**/
LINPHONE_PUBLIC void linphone_buffer_unref(LinphoneBuffer *buffer);
/**
* Retrieve the user pointer associated with the buffer.
* @param[in] buffer LinphoneBuffer object.
* @return The user pointer associated with the buffer.
**/
LINPHONE_PUBLIC void *linphone_buffer_get_user_data(const LinphoneBuffer *buffer);
/**
* Assign a user pointer to the buffer.
* @param[in] buffer LinphoneBuffer object.
* @param[in] ud The user pointer to associate with the buffer.
**/
LINPHONE_PUBLIC void linphone_buffer_set_user_data(LinphoneBuffer *buffer, void *ud);
/**
* Get the content of the data buffer.
* @param[in] buffer LinphoneBuffer object.
* @return The content of the data buffer.
*/
LINPHONE_PUBLIC const uint8_t * linphone_buffer_get_content(const LinphoneBuffer *buffer);
/**
* Set the content of the data buffer.
* @param[in] buffer LinphoneBuffer object.
* @param[in] content The content of the data buffer.
* @param[in] size The size of the content of the data buffer.
*/
LINPHONE_PUBLIC void linphone_buffer_set_content(LinphoneBuffer *buffer, const uint8_t *content, size_t size);
/**
* Get the string content of the data buffer.
* @param[in] buffer LinphoneBuffer object
* @return The string content of the data buffer.
*/
LINPHONE_PUBLIC const char * linphone_buffer_get_string_content(const LinphoneBuffer *buffer);
/**
* Set the string content of the data buffer.
* @param[in] buffer LinphoneBuffer object.
* @param[in] content The string content of the data buffer.
*/
LINPHONE_PUBLIC void linphone_buffer_set_string_content(LinphoneBuffer *buffer, const char *content);
/**
* Get the size of the content of the data buffer.
* @param[in] buffer LinphoneBuffer object.
* @return The size of the content of the data buffer.
*/
LINPHONE_PUBLIC size_t linphone_buffer_get_size(const LinphoneBuffer *buffer);
/**
* Set the size of the content of the data buffer.
* @param[in] buffer LinphoneBuffer object
* @param[in] size The size of the content of the data buffer.
*/
LINPHONE_PUBLIC void linphone_buffer_set_size(LinphoneBuffer *buffer, size_t size);
/**
* Tell whether the LinphoneBuffer is empty.
* @param[in] buffer LinphoneBuffer object
* @return A boolean value telling whether the LinphoneBuffer is empty or not.
*/
LINPHONE_PUBLIC bool_t linphone_buffer_is_empty(const LinphoneBuffer *buffer);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* LINPHONE_CONTENT_H_ */

View file

@ -217,7 +217,7 @@ char * linphone_call_log_to_str(LinphoneCallLog *cl){
default:
status=_("unknown");
}
tmp=ortp_strdup_printf(_("%s at %s\nFrom: %s\nTo: %s\nStatus: %s\nDuration: %i mn %i sec\n"),
tmp=ms_strdup_printf(_("%s at %s\nFrom: %s\nTo: %s\nStatus: %s\nDuration: %i mn %i sec\n"),
(cl->dir==LinphoneCallIncoming) ? _("Incoming call") : _("Outgoing call"),
cl->start_date,
from,

View file

@ -246,7 +246,13 @@ static int linphone_chat_message_file_transfer_on_send_body(belle_sip_user_body_
if (offset<linphone_content_get_size(chatMsg->file_transfer_information)){
/* get data from call back */
if (linphone_chat_message_cbs_get_file_transfer_send(chatMsg->callbacks)) {
linphone_chat_message_cbs_get_file_transfer_send(chatMsg->callbacks)(chatMsg, chatMsg->file_transfer_information, buf, size);
LinphoneBuffer *lb = linphone_chat_message_cbs_get_file_transfer_send(chatMsg->callbacks)(chatMsg, chatMsg->file_transfer_information, offset, *size);
if (lb == NULL) *size = 0;
else {
*size = linphone_buffer_get_size(lb);
memcpy(buffer, linphone_buffer_get_content(lb), *size);
linphone_buffer_unref(lb);
}
} else {
/* Legacy */
linphone_core_notify_file_transfer_send(lc, chatMsg, chatMsg->file_transfer_information, buf, size);
@ -287,6 +293,11 @@ static void linphone_chat_message_process_response_from_post_file(void *data, co
/* create a user body handler to take care of the file and add the content disposition and content-type headers */
if (msg->file_transfer_filepath != NULL) {
first_part_bh=(belle_sip_body_handler_t *)belle_sip_file_body_handler_new(msg->file_transfer_filepath,NULL,msg);
} else if (linphone_content_get_buffer(msg->file_transfer_information) != NULL) {
first_part_bh=(belle_sip_body_handler_t *)belle_sip_memory_body_handler_new_from_buffer(
linphone_content_get_buffer(msg->file_transfer_information),
linphone_content_get_size(msg->file_transfer_information),
NULL,msg);
} else {
first_part_bh=(belle_sip_body_handler_t *)belle_sip_user_body_handler_new(linphone_content_get_size(msg->file_transfer_information),NULL,NULL,linphone_chat_message_file_transfer_on_send_body,msg);
}
@ -578,8 +589,13 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM
belle_http_request_listener_t *l;
belle_generic_uri_t *uri;
belle_http_request_t *req;
const char *transfer_server = linphone_core_get_file_transfer_server(cr->lc);
uri=belle_generic_uri_parse(linphone_core_get_file_transfer_server(cr->lc));
if (transfer_server == NULL) {
ms_warning("Cannot send file transfer message: no file transfer server configured.");
return;
}
uri=belle_generic_uri_parse(transfer_server);
req=belle_http_request_create("POST",
uri,
@ -1205,7 +1221,9 @@ static void on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t
return;
}
if (linphone_chat_message_cbs_get_file_transfer_recv(chatMsg->callbacks)) {
linphone_chat_message_cbs_get_file_transfer_recv(chatMsg->callbacks)(chatMsg, chatMsg->file_transfer_information, (char *)buffer, size);
LinphoneBuffer *lb = linphone_buffer_new_from_data(buffer, size);
linphone_chat_message_cbs_get_file_transfer_recv(chatMsg->callbacks)(chatMsg, chatMsg->file_transfer_information, lb);
linphone_buffer_unref(lb);
} else {
/* Legacy: call back given by application level */
linphone_core_notify_file_transfer_recv(lc, chatMsg, chatMsg->file_transfer_information, (char *)buffer, size);
@ -1262,10 +1280,12 @@ static void linphone_chat_process_response_headers_from_get_file(void *data, con
(belle_sip_body_handler_t*)belle_sip_user_body_handler_new(body_size, linphone_chat_message_file_transfer_on_progress,on_recv_body,NULL,message)
);
} else {
belle_sip_message_set_body_handler(
(belle_sip_message_t *)event->response,
(belle_sip_body_handler_t *)belle_sip_file_body_handler_new(message->file_transfer_filepath, linphone_chat_message_file_transfer_on_progress, message)
);
belle_sip_body_handler_t *bh = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(message->file_transfer_filepath, linphone_chat_message_file_transfer_on_progress, message);
if (belle_sip_body_handler_get_size(bh) == 0) {
/* If the size of the body has not been initialized from the file stat, use the one from the file_transfer_information. */
belle_sip_body_handler_set_size(bh, body_size);
}
belle_sip_message_set_body_handler((belle_sip_message_t *)event->response, bh);
}
}
}
@ -1279,7 +1299,9 @@ static void linphone_chat_process_response_from_get_file(void *data, const belle
LinphoneCore *lc = chatMsg->chat_room->lc;
/* file downloaded succesfully, call again the callback with size at zero */
if (linphone_chat_message_cbs_get_file_transfer_recv(chatMsg->callbacks)) {
linphone_chat_message_cbs_get_file_transfer_recv(chatMsg->callbacks)(chatMsg, chatMsg->file_transfer_information, NULL, 0);
LinphoneBuffer *lb = linphone_buffer_new();
linphone_chat_message_cbs_get_file_transfer_recv(chatMsg->callbacks)(chatMsg, chatMsg->file_transfer_information, lb);
linphone_buffer_unref(lb);
} else {
linphone_core_notify_file_transfer_recv(lc, chatMsg, chatMsg->file_transfer_information, NULL, 0);
}

View file

@ -115,7 +115,7 @@ void linphone_content_set_buffer(LinphoneContent *content, const void *buffer, s
((char *)content->lcp.data)[size] = '\0';
}
char * linphone_content_get_string_buffer(const LinphoneContent *content) {
const char * linphone_content_get_string_buffer(const LinphoneContent *content) {
return (char *)content->lcp.data;
}

View file

@ -165,7 +165,7 @@ LINPHONE_PUBLIC void linphone_content_set_buffer(LinphoneContent *content, const
* @param[in] content LinphoneContent object
* @return The string content data buffer.
*/
LINPHONE_PUBLIC char * linphone_content_get_string_buffer(const LinphoneContent *content);
LINPHONE_PUBLIC const char * linphone_content_get_string_buffer(const LinphoneContent *content);
/**
* Set the string content data buffer.

View file

@ -63,56 +63,37 @@ static void file_transfer_progress_indication(LinphoneChatMessage *message, cons
/**
* function invoked when a file transfer is received.
**/
static void file_transfer_received(LinphoneChatMessage *message, const LinphoneContent* content, const char* buff, size_t size){
static void file_transfer_received(LinphoneChatMessage *message, const LinphoneContent* content, const LinphoneBuffer *buffer){
FILE* file=NULL;
if (!linphone_chat_message_get_user_data(message)) {
/*first chunk, creating file*/
file = fopen("receive_file.dump","wb");
linphone_chat_message_set_user_data(message,(void*)file); /*store fd for next chunks*/
} else {
/*next chunk*/
file = (FILE*)linphone_chat_message_get_user_data(message);
}
if (size==0) {
printf("File transfert completed\n");
linphone_chat_room_destroy(linphone_chat_message_get_chat_room(message));
linphone_chat_message_destroy(message);
fclose(file);
running=FALSE;
} else { /* store content on a file*/
if (fwrite(buff,size,1,file)==-1){
ms_warning("file_transfer_received() write failed: %s",strerror(errno));
}
file = (FILE*)linphone_chat_message_get_user_data(message);
if (linphone_buffer_is_empty(buffer)) {
printf("File transfert completed\n");
linphone_chat_room_destroy(linphone_chat_message_get_chat_room(message));
linphone_chat_message_destroy(message);
fclose(file);
running=FALSE;
} else { /* store content on a file*/
if (fwrite(linphone_buffer_get_content(buffer),linphone_buffer_get_size(buffer),1,file)==-1){
ms_warning("file_transfer_received() write failed: %s",strerror(errno));
}
}
}
char big_file [128000];
/*
* function called when the file transfer is initiated. file content should be feed into object LinphoneContent
* */
static void file_transfer_send(LinphoneChatMessage *message, const LinphoneContent* content, char* buff, size_t* size){
int offset=-1;
if (!linphone_chat_message_get_user_data(message)) {
/*first chunk*/
offset=0;
} else {
/*subsequent chunk*/
offset = (int)((long)(linphone_chat_message_get_user_data(message))&0x00000000FFFFFFFF);
}
*size = MIN(*size,sizeof(big_file)-offset); /*updating content->size with minimun between remaining data and requested size*/
if (*size==0) {
/*end of file*/
return;
}
memcpy(buff,big_file+offset,*size);
/*store offset for next chunk*/
linphone_chat_message_set_user_data(message,(void*)(offset+*size));
static LinphoneBuffer * file_transfer_send(LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t size){
size_t size_to_send = MIN(size, sizeof(big_file) - offset);
if (size == 0) return linphone_buffer_new(); /*end of file*/
return linphone_buffer_new_from_data((uint8_t *)big_file + offset, size_to_send);
}
/*

View file

@ -30,6 +30,7 @@ import org.linphone.core.LinphoneContent;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCore.EcCalibratorStatus;
import org.linphone.core.LinphoneCore.GlobalState;
import org.linphone.core.LinphoneCore.LogCollectionUploadState;
import org.linphone.core.LinphoneCore.RegistrationState;
import org.linphone.core.LinphoneCore.RemoteProvisioningState;
import org.linphone.core.LinphoneCoreException;
@ -322,4 +323,17 @@ public class TutorialBuddyStatus implements LinphoneListener {
// TODO Auto-generated method stub
return 0;
}
@Override
public void uploadProgressIndication(LinphoneCore lc, int offset, int total) {
// TODO Auto-generated method stub
}
@Override
public void uploadStateChanged(LinphoneCore lc,
LogCollectionUploadState state, String info) {
// TODO Auto-generated method stub
}
}

View file

@ -30,6 +30,7 @@ import org.linphone.core.LinphoneContent;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCore.EcCalibratorStatus;
import org.linphone.core.LinphoneCore.GlobalState;
import org.linphone.core.LinphoneCore.LogCollectionUploadState;
import org.linphone.core.LinphoneCore.RegistrationState;
import org.linphone.core.LinphoneCore.RemoteProvisioningState;
import org.linphone.core.LinphoneCoreException;
@ -241,5 +242,18 @@ public class TutorialChatRoom implements LinphoneListener, LinphoneChatMessage.S
return 0;
}
@Override
public void uploadProgressIndication(LinphoneCore lc, int offset, int total) {
// TODO Auto-generated method stub
}
@Override
public void uploadStateChanged(LinphoneCore lc,
LogCollectionUploadState state, String info) {
// TODO Auto-generated method stub
}
}

View file

@ -30,6 +30,7 @@ import org.linphone.core.LinphoneContent;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCore.EcCalibratorStatus;
import org.linphone.core.LinphoneCore.GlobalState;
import org.linphone.core.LinphoneCore.LogCollectionUploadState;
import org.linphone.core.LinphoneCore.RegistrationState;
import org.linphone.core.LinphoneCore.RemoteProvisioningState;
import org.linphone.core.LinphoneCoreException;
@ -243,5 +244,18 @@ public class TutorialHelloWorld implements LinphoneListener {
return 0;
}
@Override
public void uploadProgressIndication(LinphoneCore lc, int offset, int total) {
// TODO Auto-generated method stub
}
@Override
public void uploadStateChanged(LinphoneCore lc,
LogCollectionUploadState state, String info) {
// TODO Auto-generated method stub
}
}

View file

@ -30,6 +30,7 @@ import org.linphone.core.LinphoneContent;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCore.EcCalibratorStatus;
import org.linphone.core.LinphoneCore.GlobalState;
import org.linphone.core.LinphoneCore.LogCollectionUploadState;
import org.linphone.core.LinphoneCore.RegistrationState;
import org.linphone.core.LinphoneCore.RemoteProvisioningState;
import org.linphone.core.LinphoneCoreException;
@ -274,6 +275,16 @@ public class TutorialRegistration implements LinphoneListener {
return 0;
}
@Override
public void uploadProgressIndication(LinphoneCore lc, int offset, int total) {
// TODO Auto-generated method stub
}
@Override
public void uploadStateChanged(LinphoneCore lc,
LogCollectionUploadState state, String info) {
// TODO Auto-generated method stub
}
}

View file

@ -38,6 +38,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "mediastreamer2/mssndcard.h"
static const char EC_STATE_STORE[] = ".linphone.ecstate";
#define EC_STATE_MAX_LEN 1048576 // 1Mo
static void linphone_call_stats_uninit(LinphoneCallStats *stats);
@ -785,7 +786,7 @@ void linphone_call_set_compatible_incoming_call_parameters(LinphoneCall *call, c
if ((sal_media_description_has_dtls(md) == TRUE) && (media_stream_dtls_supported() == TRUE)) {
call->params->media_encryption = LinphoneMediaEncryptionDTLS;
}
if ((sal_media_description_has_srtp(md) == TRUE) && (media_stream_srtp_supported() == TRUE)) {
if ((sal_media_description_has_srtp(md) == TRUE) && (ms_srtp_supported() == TRUE)) {
call->params->media_encryption = LinphoneMediaEncryptionSRTP;
}
}
@ -1631,7 +1632,7 @@ void linphone_call_init_audio_stream(LinphoneCall *call){
rtp_session_set_symmetric_rtp(audiostream->ms.sessions.rtp_session,linphone_core_symmetric_rtp_enabled(lc));
if (call->params->media_encryption==LinphoneMediaEncryptionDTLS) {
MSDtlsSrtpParams params;
unsigned char *certificate, *key;
char *certificate, *key;
memset(&params,0,sizeof(MSDtlsSrtpParams));
/* TODO : search for a certificate with CNAME=sip uri(retrieved from variable me) or defautl celui par default linphone-dtls-default-identity */
/* This will parse the directory to find a matching fingerprint or generate it if not found */
@ -1684,13 +1685,15 @@ void linphone_call_init_audio_stream(LinphoneCall *call){
audio_stream_enable_gain_control(audiostream,TRUE);
if (linphone_core_echo_cancellation_enabled(lc)){
int len,delay,framesize;
char *statestr=lp_config_read_relative_file(lc->config, EC_STATE_STORE);
len=lp_config_get_int(lc->config,"sound","ec_tail_len",0);
delay=lp_config_get_int(lc->config,"sound","ec_delay",0);
framesize=lp_config_get_int(lc->config,"sound","ec_framesize",0);
audio_stream_set_echo_canceller_params(audiostream,len,delay,framesize);
if (statestr && audiostream->ec){
ms_filter_call_method(audiostream->ec,MS_ECHO_CANCELLER_SET_STATE_STRING,(void*)statestr);
if (audiostream->ec) {
char *statestr=ms_malloc0(EC_STATE_MAX_LEN);
if (lp_config_read_relative_file(lc->config, EC_STATE_STORE, statestr, EC_STATE_MAX_LEN) == 0) {
ms_filter_call_method(audiostream->ec, MS_ECHO_CANCELLER_SET_STATE_STRING, statestr);
}
ms_free(statestr);
}
}
@ -1754,6 +1757,7 @@ void linphone_call_init_video_stream(LinphoneCall *call){
if (display_filter != NULL)
video_stream_set_display_filter_name(call->videostream,display_filter);
video_stream_set_event_callback(call->videostream,video_stream_event_cb, call);
if (lc->rtptf){
RtpTransport *meta_rtp;
RtpTransport *meta_rtcp;
@ -2076,7 +2080,9 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, bool_t muted, b
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);
ms_message("DTLS: call_start_audio_stream, stream is %s", stream==NULL?"NULL":"not NULL");
if (stream && stream->dir!=SalStreamInactive && stream->rtp_port!=0){
ms_message("DTLS: call_start_audio_stream : we have stream and all stuff to start it");
playcard=lc->sound_conf.lsd_card ?
lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
captcard=lc->sound_conf.capt_sndcard;
@ -2085,6 +2091,7 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, bool_t muted, b
call->audio_profile=make_profile(call,call->resultdesc,stream,&used_pt);
if (used_pt!=-1){
ms_message("DTLS: call_start_audio_stream : we made a profile and have used_pt != -1");
call->current_params->audio_codec = rtp_profile_get_payload(call->audio_profile, used_pt);
if (playcard==NULL) {
ms_warning("No card defined for playback !");
@ -2143,8 +2150,8 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, bool_t muted, b
crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag);
if (crypto_idx >= 0) {
media_stream_set_srtp_recv_key(&call->audiostream->ms,stream->crypto[0].algo,stream->crypto[0].master_key, TRUE);
media_stream_set_srtp_send_key(&call->audiostream->ms,stream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key, TRUE);
media_stream_set_srtp_recv_key_b64(&call->audiostream->ms,stream->crypto[0].algo,stream->crypto[0].master_key);
media_stream_set_srtp_send_key_b64(&call->audiostream->ms,stream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key);
} else {
ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag);
}
@ -2262,8 +2269,8 @@ static void linphone_call_start_video_stream(LinphoneCall *call, bool_t all_inpu
if (sal_stream_description_has_srtp(vstream) == TRUE) {
int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, vstream->crypto_local_tag);
if (crypto_idx >= 0) {
media_stream_set_srtp_recv_key(&call->videostream->ms,vstream->crypto[0].algo,vstream->crypto[0].master_key, TRUE);
media_stream_set_srtp_send_key(&call->videostream->ms,vstream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key, TRUE);
media_stream_set_srtp_recv_key_b64(&call->videostream->ms,vstream->crypto[0].algo,vstream->crypto[0].master_key);
media_stream_set_srtp_send_key_b64(&call->videostream->ms,vstream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key);
}
}
configure_rtp_session_for_rtcp_xr(lc, call, SalVideo);
@ -2326,6 +2333,8 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut
if (call->audiostream!=NULL) {
linphone_call_start_audio_stream(call,all_inputs_muted||call->audio_muted,send_ringbacktone,use_arc);
} else {
ms_warning("DTLS no audio stream!");
}
call->current_params->has_video=FALSE;
if (call->videostream!=NULL) {
@ -2397,9 +2406,9 @@ static bool_t update_stream_crypto_params(LinphoneCall *call, const SalStreamDes
int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
if (crypto_idx >= 0) {
if (call->localdesc_changed & SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED)
media_stream_set_srtp_send_key(ms,new_stream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key, TRUE);
media_stream_set_srtp_send_key_b64(ms,new_stream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key);
if (strcmp(old_stream->crypto[0].master_key,new_stream->crypto[0].master_key)!=0){
media_stream_set_srtp_recv_key(ms,new_stream->crypto[0].algo,new_stream->crypto[0].master_key,TRUE);
media_stream_set_srtp_recv_key_b64(ms,new_stream->crypto[0].algo,new_stream->crypto[0].master_key);
}
return TRUE;
} else {
@ -2906,14 +2915,17 @@ void linphone_call_stop_recording(LinphoneCall *call){
**/
static void report_bandwidth(LinphoneCall *call, MediaStream *as, MediaStream *vs){
call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth=(as!=NULL) ? (media_stream_get_down_bw(as)*1e-3) : 0;
call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth=(as!=NULL) ? (media_stream_get_up_bw(as)*1e-3) : 0;
call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth=(vs!=NULL) ? (media_stream_get_down_bw(vs)*1e-3) : 0;
call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth=(vs!=NULL) ? (media_stream_get_up_bw(vs)*1e-3) : 0;
call->stats[LINPHONE_CALL_STATS_AUDIO].rtcp_download_bandwidth=(as!=NULL) ? (media_stream_get_rtcp_down_bw(as)*1e-3) : 0;
call->stats[LINPHONE_CALL_STATS_AUDIO].rtcp_upload_bandwidth=(as!=NULL) ? (media_stream_get_rtcp_up_bw(as)*1e-3) : 0;
call->stats[LINPHONE_CALL_STATS_VIDEO].rtcp_download_bandwidth=(vs!=NULL) ? (media_stream_get_rtcp_down_bw(vs)*1e-3) : 0;
call->stats[LINPHONE_CALL_STATS_VIDEO].rtcp_upload_bandwidth=(vs!=NULL) ? (media_stream_get_rtcp_up_bw(vs)*1e-3) : 0;
bool_t as_active = as ? (media_stream_get_state(as) == MSStreamStarted) : FALSE;
bool_t vs_active = vs ? (media_stream_get_state(vs) == MSStreamStarted) : FALSE;
call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth=(as_active) ? (media_stream_get_down_bw(as)*1e-3) : 0;
call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth=(as_active) ? (media_stream_get_up_bw(as)*1e-3) : 0;
call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth=(vs_active) ? (media_stream_get_down_bw(vs)*1e-3) : 0;
call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth=(vs_active) ? (media_stream_get_up_bw(vs)*1e-3) : 0;
call->stats[LINPHONE_CALL_STATS_AUDIO].rtcp_download_bandwidth=(as_active) ? (media_stream_get_rtcp_down_bw(as)*1e-3) : 0;
call->stats[LINPHONE_CALL_STATS_AUDIO].rtcp_upload_bandwidth=(as_active) ? (media_stream_get_rtcp_up_bw(as)*1e-3) : 0;
call->stats[LINPHONE_CALL_STATS_VIDEO].rtcp_download_bandwidth=(vs_active) ? (media_stream_get_rtcp_down_bw(vs)*1e-3) : 0;
call->stats[LINPHONE_CALL_STATS_VIDEO].rtcp_upload_bandwidth=(vs_active) ? (media_stream_get_rtcp_up_bw(vs)*1e-3) : 0;
ms_message("Bandwidth usage for call [%p]: audio[ rtp]=[d=%.1f,u=%.1f], video[ rtp]=[d=%.1f,u=%.1f] kbit/sec",
call,

View file

@ -2131,7 +2131,7 @@ void linphone_core_set_use_rfc2833_for_dtmf(LinphoneCore *lc,bool_t use_rfc2833)
/**
* Returns the UDP port used by SIP.
*
* Deprecated: use linphone_core_get_sip_transports() instead.
* @deprecated use linphone_core_get_sip_transports() instead.
* @ingroup network_parameters
**/
int linphone_core_get_sip_port(LinphoneCore *lc){
@ -2299,7 +2299,7 @@ void linphone_core_get_sip_transports_used(LinphoneCore *lc, LCSipTransports *tr
/**
* Sets the UDP port to be used by SIP.
*
* Deprecated: use linphone_core_set_sip_transports() instead.
* @deprecated use linphone_core_set_sip_transports() instead.
* @ingroup network_parameters
**/
void linphone_core_set_sip_port(LinphoneCore *lc,int port)
@ -3944,10 +3944,10 @@ int _linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call)
linphone_core_notify_display_warning(lc,_("Could not pause the call"));
}
lc->current_call=NULL;
linphone_call_set_state(call,LinphoneCallPausing,"Pausing call");
linphone_core_notify_display_status(lc,_("Pausing the current call..."));
if (call->audiostream || call->videostream)
linphone_call_stop_media_streams (call);
linphone_call_set_state(call,LinphoneCallPausing,"Pausing call");
call->paused_by_app=FALSE;
return 0;
}
@ -5631,6 +5631,26 @@ MSVideoSize linphone_core_get_preview_video_size(const LinphoneCore *lc){
return lc->video_conf.preview_vsize;
}
/**
* Returns the effective video size for the captured video as provided by the camera.
* When preview is disabled or not yet started, this function returns a zeroed video size.
* @see linphone_core_set_preview_video_size()
* @ingroup media_parameters
* @param lc the core
* @return a MSVideoSize
**/
MSVideoSize linphone_core_get_current_preview_video_size(const LinphoneCore *lc){
MSVideoSize ret={0};
#ifndef VIDEO_ENABLED
ms_error("linphone_core_get_current_preview_video_size() fail. Support for video is disabled");
#else
if (lc->previewstream){
ret=video_preview_get_current_size(lc->previewstream);
}
#endif
return ret;
}
/**
* Sets the preview video size by its name. See linphone_core_set_preview_video_size() for more information about this feature.
*
@ -6416,20 +6436,20 @@ static void notify_soundcard_usage(LinphoneCore *lc, bool_t used){
void linphone_core_soundcard_hint_check( LinphoneCore* lc){
MSList* the_calls = lc->calls;
LinphoneCall* call = NULL;
bool_t remaining_paused = FALSE;
bool_t dont_need_sound = TRUE;
/* check if the remaining calls are paused */
while( the_calls ){
call = the_calls->data;
if( call->state == LinphoneCallPausing || call->state == LinphoneCallPaused ){
remaining_paused = TRUE;
if( call->state != LinphoneCallPausing && call->state != LinphoneCallPaused ){
dont_need_sound = FALSE;
break;
}
the_calls = the_calls->next;
}
/* if no more calls or all calls are paused, we can free the soundcard */
if ( (lc->calls==NULL || remaining_paused) && !lc->use_files){
if ( (lc->calls==NULL || dont_need_sound) && !lc->use_files){
ms_message("Notifying soundcard that we don't need it anymore for calls.");
notify_soundcard_usage(lc,FALSE);
}
@ -6462,8 +6482,6 @@ int linphone_core_del_call( LinphoneCore *lc, LinphoneCall *call)
}
lc->calls = the_calls;
linphone_core_soundcard_hint_check(lc);
return 0;
}
@ -6814,7 +6832,7 @@ const char *linphone_media_encryption_to_string(LinphoneMediaEncryption menc){
bool_t linphone_core_media_encryption_supported(const LinphoneCore *lc, LinphoneMediaEncryption menc){
switch(menc){
case LinphoneMediaEncryptionSRTP:
return media_stream_srtp_supported();
return ms_srtp_supported();
case LinphoneMediaEncryptionDTLS:
return ms_dtls_available();
case LinphoneMediaEncryptionZRTP:
@ -6829,7 +6847,7 @@ int linphone_core_set_media_encryption(LinphoneCore *lc, LinphoneMediaEncryption
const char *type="none";
int ret=0;
if (menc == LinphoneMediaEncryptionSRTP){
if (!media_stream_srtp_supported()){
if (!ms_srtp_supported()){
ms_warning("SRTP not supported by library.");
type="none";
ret=-1;
@ -7074,7 +7092,7 @@ int linphone_payload_type_get_normal_bitrate(const LinphonePayloadType *pt) {
return pt->normal_bitrate;
}
char * linphone_payload_type_get_mime_type(const LinphonePayloadType *pt) {
const char * linphone_payload_type_get_mime_type(const LinphonePayloadType *pt) {
return pt->mime_type;
}
@ -7087,9 +7105,6 @@ LinphoneCoreVTable *linphone_core_v_table_new() {
}
void linphone_core_v_table_set_user_data(LinphoneCoreVTable *table, void *data) {
if (table->user_data) {
ms_free(table->user_data);
}
table->user_data = data;
}
@ -7098,9 +7113,6 @@ void* linphone_core_v_table_get_user_data(LinphoneCoreVTable *table) {
}
void linphone_core_v_table_destroy(LinphoneCoreVTable* table) {
if (table->user_data) {
ms_free(table->user_data);
}
ms_free(table);
}

View file

@ -257,7 +257,7 @@ LINPHONE_PUBLIC int linphone_payload_type_get_normal_bitrate(const LinphonePaylo
* @param[in] pt LinphonePayloadType object
* @return The mime type.
*/
LINPHONE_PUBLIC char * linphone_payload_type_get_mime_type(const LinphonePayloadType *pt);
LINPHONE_PUBLIC const char * linphone_payload_type_get_mime_type(const LinphonePayloadType *pt);
/**
* Get the number of channels.
@ -367,12 +367,14 @@ LINPHONE_PUBLIC const char* linphone_privacy_to_string(LinphonePrivacy privacy);
#ifdef IN_LINPHONE
#include "buffer.h"
#include "call_log.h"
#include "call_params.h"
#include "content.h"
#include "event.h"
#include "linphonefriend.h"
#else
#include "linphone/buffer.h"
#include "linphone/call_log.h"
#include "linphone/call_params.h"
#include "linphone/content.h"
@ -1351,30 +1353,24 @@ typedef void (*LinphoneChatMessageCbsMsgStateChangedCb)(LinphoneChatMessage* msg
/**
* File transfer receive callback prototype. This function is called by the core upon an incoming File transfer is started. This function may be call several time for the same file in case of large file.
*
* @param message #LinphoneChatMessage message from which the body is received.
* @param content #LinphoneContent incoming content information
* @param buff pointer to the received data
* @param size number of bytes to be read from buff. 0 means end of file.
*
* @param buffer #LinphoneBuffer holding the received data. Empty buffer means end of file.
*/
typedef void (*LinphoneChatMessageCbsFileTransferRecvCb)(LinphoneChatMessage *message, const LinphoneContent* content, const char* buff, size_t size);
typedef void (*LinphoneChatMessageCbsFileTransferRecvCb)(LinphoneChatMessage *message, const LinphoneContent* content, const LinphoneBuffer *buffer);
/**
* File transfer send callback prototype. This function is called by the core upon an outgoing File transfer is started. This function is called until size is set to 0.
* <br> a #LinphoneContent with a size equal zero
*
* File transfer send callback prototype. This function is called by the core when an outgoing file transfer is started. This function is called until size is set to 0.
* @param message #LinphoneChatMessage message from which the body is received.
* @param content #LinphoneContent outgoing content
* @param buff pointer to the buffer where data chunk shall be written by the app
* @param size as input value, it represents the number of bytes expected by the framework. As output value, it means the number of bytes wrote by the application in the buffer. 0 means end of file.
*
* @param offset the offset in the file from where to get the data to be sent
* @param size the number of bytes expected by the framework
* @return A LinphoneBuffer object holding the data written by the application. An empty buffer means end of file.
*/
typedef void (*LinphoneChatMessageCbsFileTransferSendCb)(LinphoneChatMessage *message, const LinphoneContent* content, char* buff, size_t* size);
typedef LinphoneBuffer * (*LinphoneChatMessageCbsFileTransferSendCb)(LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t size);
/**
* File transfer progress indication callback prototype.
*
* @param message #LinphoneChatMessage message from which the body is received.
* @param content #LinphoneContent incoming content information
* @param offset The number of bytes sent/received since the beginning of the transfer.
@ -2816,6 +2812,7 @@ LINPHONE_PUBLIC void linphone_core_set_preferred_video_size(LinphoneCore *lc, MS
LINPHONE_PUBLIC void linphone_core_set_preview_video_size(LinphoneCore *lc, MSVideoSize vsize);
LINPHONE_PUBLIC void linphone_core_set_preview_video_size_by_name(LinphoneCore *lc, const char *name);
LINPHONE_PUBLIC MSVideoSize linphone_core_get_preview_video_size(const LinphoneCore *lc);
LINPHONE_PUBLIC MSVideoSize linphone_core_get_current_preview_video_size(const LinphoneCore *lc);
LINPHONE_PUBLIC MSVideoSize linphone_core_get_preferred_video_size(const LinphoneCore *lc);
/**

View file

@ -170,7 +170,7 @@ jobject getProxy(JNIEnv *env, LinphoneProxyConfig *proxy, jobject core){
jobject jobj=0;
if (proxy!=NULL){
jclass proxyClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneProxyConfigImpl"));
jclass proxyClass = (jclass)env->FindClass("org/linphone/core/LinphoneProxyConfigImpl");
jmethodID proxyCtrId = env->GetMethodID(proxyClass,"<init>", "(Lorg/linphone/core/LinphoneCoreImpl;J)V");
void *up=linphone_proxy_config_get_user_data(proxy);
@ -188,7 +188,7 @@ jobject getProxy(JNIEnv *env, LinphoneProxyConfig *proxy, jobject core){
linphone_proxy_config_set_user_data(proxy,(void*)env->NewWeakGlobalRef(jobj));
}
}
env->DeleteGlobalRef(proxyClass);
env->DeleteLocalRef(proxyClass);
}
return jobj;
}
@ -197,7 +197,7 @@ jobject getCall(JNIEnv *env, LinphoneCall *call){
jobject jobj=0;
if (call!=NULL){
jclass callClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCallImpl"));
jclass callClass = (jclass)env->FindClass("org/linphone/core/LinphoneCallImpl");
jmethodID callCtrId = env->GetMethodID(callClass,"<init>", "(J)V");
void *up=linphone_call_get_user_pointer(call);
@ -210,7 +210,7 @@ jobject getCall(JNIEnv *env, LinphoneCall *call){
}else{
jobj=(jobject)up;
}
env->DeleteGlobalRef(callClass);
env->DeleteLocalRef(callClass);
}
return jobj;
}
@ -219,7 +219,7 @@ jobject getChatMessage(JNIEnv *env, LinphoneChatMessage *msg){
jobject jobj = 0;
if (msg != NULL){
jclass chatMessageClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneChatMessageImpl"));
jclass chatMessageClass = (jclass)env->FindClass("org/linphone/core/LinphoneChatMessageImpl");
jmethodID chatMessageCtrId = env->GetMethodID(chatMessageClass,"<init>", "(J)V");
void *up = linphone_chat_message_get_user_data(msg);
@ -231,7 +231,7 @@ jobject getChatMessage(JNIEnv *env, LinphoneChatMessage *msg){
} else {
jobj = (jobject)up;
}
env->DeleteGlobalRef(chatMessageClass);
env->DeleteLocalRef(chatMessageClass);
}
return jobj;
}
@ -240,14 +240,14 @@ jobject getEvent(JNIEnv *env, LinphoneEvent *lev){
if (lev==NULL) return NULL;
jobject jev=(jobject)linphone_event_get_user_data(lev);
if (jev==NULL){
jclass linphoneEventClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneEventImpl"));
jclass linphoneEventClass = (jclass)env->FindClass("org/linphone/core/LinphoneEventImpl");
jmethodID linphoneEventCtrId = env->GetMethodID(linphoneEventClass,"<init>", "(J)V");
jev=env->NewObject(linphoneEventClass,linphoneEventCtrId,(jlong)linphone_event_ref(lev));
jev=env->NewGlobalRef(jev);
linphone_event_set_user_data(lev,jev);
env->DeleteGlobalRef(linphoneEventClass);
env->DeleteLocalRef(linphoneEventClass);
}
return jev;
}
@ -420,6 +420,19 @@ public:
if (fileTransferRecvId) {
vTable->file_transfer_recv = fileTransferRecv;
}
logCollectionUploadStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCore$LogCollectionUploadState"));
logCollectionUploadStateFromIntId = env->GetStaticMethodID(logCollectionUploadStateClass, "fromInt", "(I)Lorg/linphone/core/LinphoneCore$LogCollectionUploadState;");
logCollectionUploadProgressId = env->GetMethodID(listenerClass, "uploadProgressIndication", "(Lorg/linphone/core/LinphoneCore;II)V");
env->ExceptionClear();
if (logCollectionUploadProgressId) {
vTable->log_collection_upload_progress_indication = logCollectionUploadProgressIndication;
}
logCollectionUploadStateId = env->GetMethodID(listenerClass, "uploadStateChanged", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCore$LogCollectionUploadState;Ljava/lang/String;)V");
env->ExceptionClear();
if (logCollectionUploadStateId) {
vTable->log_collection_upload_state_changed = logCollectionUploadStateChange;
}
chatMessageStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneChatMessage$State"));
chatMessageStateFromIntId = env->GetStaticMethodID(chatMessageStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneChatMessage$State;");
@ -479,6 +492,7 @@ public:
env->DeleteGlobalRef(linphoneEventClass);
env->DeleteGlobalRef(subscriptionStateClass);
env->DeleteGlobalRef(subscriptionDirClass);
env->DeleteGlobalRef(logCollectionUploadStateClass);
}
jobject core;
jobject listener;
@ -566,6 +580,11 @@ public:
jmethodID fileTransferSendId;
jmethodID fileTransferRecvId;
jclass logCollectionUploadStateClass;
jmethodID logCollectionUploadStateId;
jmethodID logCollectionUploadStateFromIntId;
jmethodID logCollectionUploadProgressId;
LinphoneCoreVTable vTable;
static void displayStatusCb(LinphoneCore *lc, const char *message) {
@ -577,7 +596,11 @@ public:
}
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
env->CallVoidMethod(lcData->listener,lcData->displayStatusId,lcData->core,message ? env->NewStringUTF(message) : NULL);
jstring msg = message ? env->NewStringUTF(message) : NULL;
env->CallVoidMethod(lcData->listener,lcData->displayStatusId,lcData->core,msg);
if (msg) {
env->DeleteLocalRef(msg);
}
}
static void authInfoRequested(LinphoneCore *lc, const char *realm, const char *username, const char *domain) {
JNIEnv *env = 0;
@ -588,12 +611,24 @@ public:
}
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
jstring r = realm ? env->NewStringUTF(realm) : NULL;
jstring u = username ? env->NewStringUTF(username) : NULL;
jstring d = domain ? env->NewStringUTF(domain) : NULL;
env->CallVoidMethod(lcData->listener,
lcData->authInfoRequestedId,
lcData->core,
realm ? env->NewStringUTF(realm):NULL,
username ? env->NewStringUTF(username) : NULL,
domain ? env->NewStringUTF(domain) : NULL);
r,
u,
d);
if (r) {
env->DeleteLocalRef(r);
}
if (u) {
env->DeleteLocalRef(u);
}
if (d) {
env->DeleteLocalRef(d);
}
}
static void globalStateChange(LinphoneCore *lc, LinphoneGlobalState gstate,const char* message) {
JNIEnv *env = 0;
@ -604,11 +639,15 @@ public:
}
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
jstring msg = message ? env->NewStringUTF(message) : NULL;
env->CallVoidMethod(lcData->listener
,lcData->globalStateId
,lcData->core
,env->CallStaticObjectMethod(lcData->globalStateClass,lcData->globalStateFromIntId,(jint)gstate),
message ? env->NewStringUTF(message) : NULL);
msg);
if (msg) {
env->DeleteLocalRef(msg);
}
}
static void registrationStateChange(LinphoneCore *lc, LinphoneProxyConfig* proxy,LinphoneRegistrationState state,const char* message) {
JNIEnv *env = 0;
@ -620,12 +659,16 @@ public:
}
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
jstring msg = message ? env->NewStringUTF(message) : NULL;
env->CallVoidMethod(lcData->listener
,lcData->registrationStateId
,lcData->core
,(jproxy=getProxy(env,proxy,lcData->core))
,env->CallStaticObjectMethod(lcData->registrationStateClass,lcData->registrationStateFromIntId,(jint)state),
message ? env->NewStringUTF(message) : NULL);
msg);
if (msg) {
env->DeleteLocalRef(msg);
}
}
static void callStateChange(LinphoneCore *lc, LinphoneCall* call,LinphoneCallState state,const char* message) {
@ -638,16 +681,20 @@ public:
}
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
jstring msg = message ? env->NewStringUTF(message) : NULL;
env->CallVoidMethod(lcData->listener
,lcData->callStateId
,lcData->core
,(jcall=getCall(env,call))
,env->CallStaticObjectMethod(lcData->callStateClass,lcData->callStateFromIntId,(jint)state),
message ? env->NewStringUTF(message) : NULL);
if (state==LinphoneCallReleased){
msg);
if (state==LinphoneCallReleased) {
linphone_call_set_user_pointer(call,NULL);
env->DeleteGlobalRef(jcall);
}
if (msg) {
env->DeleteLocalRef(msg);
}
}
static void callEncryptionChange(LinphoneCore *lc, LinphoneCall* call, bool_t encrypted,const char* authentication_token) {
JNIEnv *env = 0;
@ -763,17 +810,22 @@ public:
ms_error("cannot attach VM");
return;
}
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
env->CallVoidMethod(lcData->listener
,lcData->ecCalibrationStatusId
,lcData->core
,env->CallStaticObjectMethod(lcData->ecCalibratorStatusClass,lcData->ecCalibratorStatusFromIntId,(jint)status)
,delay_ms
,data ? data : NULL);
if (data != NULL &&status !=LinphoneEcCalibratorInProgress ) {
//final state, releasing global ref
env->DeleteGlobalRef((jobject)data);
LinphoneCoreVTable *table = (LinphoneCoreVTable*) data;
if (table) {
LinphoneCoreData* lcData = (LinphoneCoreData*) linphone_core_v_table_get_user_data(table);
if (lcData->ecCalibrationStatusId) {
jobject state = env->CallStaticObjectMethod(lcData->ecCalibratorStatusClass, lcData->ecCalibratorStatusFromIntId, (jint)status);
env->CallVoidMethod(lcData->listener
,lcData->ecCalibrationStatusId
,lcData->core
,state
,delay_ms
,NULL);
}
if (status != LinphoneEcCalibratorInProgress) {
linphone_core_v_table_destroy(table);
}
}
}
@ -968,6 +1020,40 @@ public:
jbytes,
size);
}
static void logCollectionUploadProgressIndication(LinphoneCore *lc, size_t offset, size_t total) {
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
ms_error("cannot attach VM");
return;
}
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
env->CallVoidMethod(lcData->listener
,lcData->logCollectionUploadProgressId
,lcData->core
,(jlong)offset
,(jlong)total);
}
static void logCollectionUploadStateChange(LinphoneCore *lc, LinphoneCoreLogCollectionUploadState state, const char *info) {
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
ms_error("cannot attach VM");
return;
}
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
jstring msg = info ? env->NewStringUTF(info) : NULL;
env->CallVoidMethod(lcData->listener
,lcData->logCollectionUploadStateId
,lcData->core
,env->CallStaticObjectMethod(lcData->logCollectionUploadStateClass,lcData->logCollectionUploadStateFromIntId,(jint)state),
msg);
if (msg) {
env->DeleteLocalRef(msg);
}
}
};
extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_newLinphoneCore(JNIEnv* env
@ -1049,6 +1135,22 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_removeListener(JNIEnv* e
env->DeleteGlobalRef(listener);
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_uploadLogCollection(JNIEnv* env, jobject thiz, jlong lc) {
LinphoneCore *core = (LinphoneCore*)lc;
linphone_core_upload_log_collection(core);
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_enableLogCollection(JNIEnv* env, jclass cls, jboolean enable) {
linphone_core_enable_log_collection(enable ? LinphoneLogCollectionEnabledWithoutPreviousLogHandler : LinphoneLogCollectionDisabled);
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setLogCollectionPath(JNIEnv* env, jclass cls, jstring jpath) {
const char* path = env->GetStringUTFChars(jpath, NULL);
linphone_core_set_log_collection_path(path);
env->ReleaseStringUTFChars(jpath, path);
}
extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_migrateToMultiTransport(JNIEnv* env
,jobject thiz
,jlong lc) {
@ -1727,11 +1829,11 @@ extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_startEchoCalibration(JNI
,jobject thiz
,jlong lc
,jobject data) {
return (jint)linphone_core_start_echo_calibration((LinphoneCore*)lc
, LinphoneCoreData::ecCalibrationStatus
, NULL
, NULL
, data?env->NewGlobalRef(data):NULL);
LinphoneCoreVTable *vTable = linphone_core_v_table_new();
LinphoneCoreData* ldata = new LinphoneCoreData(env, thiz, vTable, data);
linphone_core_v_table_set_user_data(vTable, ldata);
return (jint)linphone_core_start_echo_calibration((LinphoneCore*)lc, ldata->ecCalibrationStatus, NULL, NULL, vTable);
}
@ -2855,11 +2957,13 @@ extern "C" jbyteArray Java_org_linphone_core_LinphoneChatMessageImpl_getText(JNI
,jobject thiz
,jlong ptr) {
const char *message = linphone_chat_message_get_text((LinphoneChatMessage*)ptr);
size_t length = strlen(message);
jbyteArray array = env->NewByteArray(length);
env->SetByteArrayRegion(array, 0, length, (const jbyte*)message);
return array;
if (message){
size_t length = strlen(message);
jbyteArray array = env->NewByteArray(length);
env->SetByteArrayRegion(array, 0, length, (const jbyte*)message);
return array;
}
return NULL;
}
extern "C" jint Java_org_linphone_core_LinphoneChatMessageImpl_getReason(JNIEnv* env

View file

@ -734,25 +734,26 @@ void lp_config_write_relative_file(const LpConfig *lpconfig, const char *filenam
}
}
char *lp_config_read_relative_file(const LpConfig *lpconfig, const char *filename) {
int lp_config_read_relative_file(const LpConfig *lpconfig, const char *filename, char *data, size_t max_length) {
char *dir = _lp_config_dirname(lpconfig->filename);
char *filepath = ms_strdup_printf("%s/%s", dir, filename);
char *result = NULL;
if(ortp_file_exist(filepath) == 0) {
FILE *file = fopen(filepath, "r");
if(file != NULL) {
result = ms_new0(char, MAX_LEN);
if(fgets(result, MAX_LEN, file) == NULL) {
ms_error("%s could not be loaded", filepath);
}
fclose(file);
} else {
ms_error("Could not open %s for read", filepath);
FILE *file = fopen(filepath, "r");
if(file != NULL) {
if(fread(data, 1, max_length, file)<=0) {
ms_error("%s could not be loaded. %s", filepath, strerror(errno));
goto err;
}
fclose(file);
} else {
ms_message("%s does not exist", filepath);
ms_error("Could not open %s for read. %s", filepath, strerror(errno));
goto err;
}
ms_free(dir);
ms_free(filepath);
return result;
return 0;
err:
ms_free(dir);
ms_free(filepath);
return -1;
}

View file

@ -281,12 +281,14 @@ LINPHONE_PUBLIC void lp_config_unref(LpConfig *lpconfig);
LINPHONE_PUBLIC void lp_config_write_relative_file(const LpConfig *lpconfig, const char *filename, const char *data);
/**
* @brief Read a string from a file placed relatively with the Linphone configuration file
* @brief Read a string from a file placed beside the Linphone configuration file
* @param lpconfig LpConfig instance used as a reference
* @param filename Name of the file where data will be read from. The name is relative to the place of the config file
* @return The read string
* @param data Buffer where read string will be stored
* @param max_length Length of the buffer
* @return 0 on success, -1 on failure
*/
LINPHONE_PUBLIC char *lp_config_read_relative_file(const LpConfig *lpconfig, const char *filename);
LINPHONE_PUBLIC int lp_config_read_relative_file(const LpConfig *lpconfig, const char *filename, char *data, size_t max_length);
#ifdef __cplusplus
}

View file

@ -254,7 +254,7 @@ struct _LinphoneCall{
char *dtmf_sequence; /*DTMF sequence needed to be sent using #dtmfs_timer*/
belle_sip_source_t *dtmfs_timer; /*DTMF timer needed to send a DTMF sequence*/
unsigned 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 *dtls_certificate_fingerprint; /**> This fingerprint is computed during stream init and is stored in call to be used when making local media description */
bool_t refer_pending;
bool_t expect_media_in_ack;
bool_t audio_muted;
@ -925,6 +925,14 @@ struct _LinphoneContent {
BELLE_SIP_DECLARE_VPTR(LinphoneContent);
struct _LinphoneBuffer {
belle_sip_object_t base;
void *user_data;
uint8_t *content; /**< A pointer to the buffer content */
size_t size; /**< The size of the buffer content */
};
BELLE_SIP_DECLARE_VPTR(LinphoneBuffer);
/*****************************************************************************
@ -1001,6 +1009,7 @@ const MSCryptoSuite * linphone_core_get_srtp_crypto_suites(LinphoneCore *lc);
*/
BELLE_SIP_DECLARE_TYPES_BEGIN(linphone,10000)
BELLE_SIP_TYPE_ID(LinphoneBuffer),
BELLE_SIP_TYPE_ID(LinphoneContactProvider),
BELLE_SIP_TYPE_ID(LinphoneContactSearch),
BELLE_SIP_TYPE_ID(LinphoneCall),

View file

@ -65,6 +65,10 @@ set(SOURCE_FILES
videowindow.c
)
if(ENABLE_ASSISTANT)
list(APPEND SOURCE_FILES setupwizard.c)
endif()
if(GETTEXT_FOUND)
add_definitions("-DENABLE_NLS")
endif()
@ -77,6 +81,9 @@ if(ENABLE_NOTIFY)
target_include_directories(linphone-gtk PUBLIC ${NOTIFY_INCLUDE_DIRS})
target_link_libraries(linphone-gtk ${NOTIFY_LIBRARIES})
endif()
if(ENABLE_ASSISTANT)
target_link_libraries(linphone-gtk ${SOUP_LIBRARIES})
endif()
install(TARGETS linphone-gtk
RUNTIME DESTINATION bin

View file

@ -199,4 +199,5 @@ void linphone_gtk_close_config_fetching(GtkWidget *w, LinphoneConfiguringState s
const char *linphone_gtk_get_sound_path(const char *file);
void linphone_gtk_in_call_show_video(LinphoneCall *call);
char *linphone_gtk_address(const LinphoneAddress *addr);/*return human readable identifier for a LinphoneAddress */
GtkWidget *linphone_gtk_get_camera_preview_window(void);

View file

@ -832,9 +832,6 @@ bool_t linphone_gtk_video_enabled(void){
void linphone_gtk_show_main_window(){
GtkWidget *w=linphone_gtk_get_main_window();
LinphoneCore *lc=linphone_gtk_get_core();
linphone_core_enable_video_preview(lc,linphone_gtk_get_ui_config_int("videoselfview",
VIDEOSELFVIEW_DEFAULT));
gtk_widget_show(w);
gtk_window_present(GTK_WINDOW(w));
}
@ -1028,13 +1025,6 @@ void _linphone_gtk_enable_video(gboolean val){
linphone_core_enable_video_capture(linphone_gtk_get_core(), TRUE);
linphone_core_enable_video_display(linphone_gtk_get_core(), TRUE);
linphone_core_set_video_policy(linphone_gtk_get_core(),&policy);
if (val){
linphone_core_enable_video_preview(linphone_gtk_get_core(),
linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT));
}else{
linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
}
}
void linphone_gtk_enable_video(GtkWidget *w){
@ -1046,7 +1036,6 @@ void linphone_gtk_enable_video(GtkWidget *w){
void linphone_gtk_enable_self_view(GtkWidget *w){
gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
LinphoneCore *lc=linphone_gtk_get_core();
linphone_core_enable_video_preview(lc,val);
linphone_core_enable_self_view(lc,val);
linphone_gtk_set_ui_config_int("videoselfview",val);
}
@ -1843,10 +1832,11 @@ void linphone_gtk_manage_login(void){
gboolean linphone_gtk_close(GtkWidget *mw){
/*shutdown calls if any*/
LinphoneCore *lc=linphone_gtk_get_core();
GtkWidget *camera_preview=linphone_gtk_get_camera_preview_window();
if (linphone_core_in_call(lc)){
linphone_core_terminate_all_calls(lc);
}
linphone_core_enable_video_preview(lc,FALSE);
if (camera_preview) gtk_widget_destroy(camera_preview);
#ifdef __APPLE__ /*until with have a better option*/
gtk_window_iconify(GTK_WINDOW(mw));
#else
@ -1857,13 +1847,6 @@ gboolean linphone_gtk_close(GtkWidget *mw){
#ifdef HAVE_GTK_OSX
static gboolean on_window_state_event(GtkWidget *w, GdkEventWindowState *event){
bool_t video_enabled=linphone_gtk_video_enabled();
if ((event->new_window_state & GDK_WINDOW_STATE_ICONIFIED) ||(event->new_window_state & GDK_WINDOW_STATE_WITHDRAWN) ){
linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
}else{
linphone_core_enable_video_preview(linphone_gtk_get_core(),
linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT) && video_enabled);
}
return FALSE;
}
#endif
@ -1974,6 +1957,7 @@ static void linphone_gtk_init_main_window(){
g_signal_connect(G_OBJECT(main_window), "window-state-event",G_CALLBACK(on_window_state_event), NULL);
#endif
linphone_gtk_check_menu_items();
linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
}
void linphone_gtk_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){

View file

@ -1233,7 +1233,7 @@
<object class="GtkTable" id="table2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="n_rows">3</property>
<property name="n_rows">4</property>
<property name="n_columns">2</property>
<child>
<object class="GtkLabel" id="label9">
@ -1330,6 +1330,22 @@
<property name="y_options">GTK_EXPAND</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button2">
<property name="label" translatable="yes">Show camera preview</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="linphone_gtk_show_camera_preview_clicked" swapped="no"/>
</object>
<packing>
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="x_options">GTK_EXPAND</property>
</packing>
</child>
</object>
</child>
</object>
@ -2188,7 +2204,7 @@
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
<property name="y_options"/>
</packing>
</child>
<child>
@ -2250,7 +2266,7 @@
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
<property name="y_options"/>
</packing>
</child>
<child>
@ -2265,7 +2281,7 @@
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
<property name="y_options"/>
</packing>
</child>
</object>
@ -2538,7 +2554,7 @@
<object class="GtkLabel" id="ldap_server">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="no">label</property>
<property name="label">label</property>
</object>
<packing>
<property name="left_attach">1</property>
@ -2550,7 +2566,7 @@
<object class="GtkLabel" id="ldap_auth_method">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="no">label</property>
<property name="label">label</property>
</object>
<packing>
<property name="left_attach">1</property>
@ -2564,7 +2580,7 @@
<object class="GtkLabel" id="ldap_username">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="no">label</property>
<property name="label">label</property>
</object>
<packing>
<property name="left_attach">1</property>

View file

@ -94,7 +94,7 @@ static gboolean drag_drop(GtkWidget *widget, GdkDragContext *drag_context, gint
return TRUE;
}
unsigned long get_native_handle(GdkWindow *gdkw){
static unsigned long get_native_handle(GdkWindow *gdkw){
#ifdef GDK_WINDOWING_X11
return (unsigned long)GDK_WINDOW_XID(gdkw);
#elif defined(WIN32)
@ -106,6 +106,15 @@ unsigned long get_native_handle(GdkWindow *gdkw){
return 0;
}
static void _resize_video_window(GtkWidget *video_window, MSVideoSize vsize){
MSVideoSize cur;
gtk_window_get_size(GTK_WINDOW(video_window),&cur.width,&cur.height);
if (vsize.width*vsize.height > cur.width*cur.height ||
ms_video_size_get_orientation(vsize)!=ms_video_size_get_orientation(cur) ){
gtk_window_resize(GTK_WINDOW(video_window),vsize.width,vsize.height);
}
}
static gint resize_video_window(LinphoneCall *call){
const LinphoneCallParams *params=linphone_call_get_current_params(call);
if (params){
@ -114,13 +123,7 @@ static gint resize_video_window(LinphoneCall *call){
GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call);
GtkWidget *video_window=(GtkWidget*)g_object_get_data(G_OBJECT(callview),"video_window");
if (video_window){
MSVideoSize cur;
gtk_window_get_size(GTK_WINDOW(video_window),&cur.width,&cur.height);
if (vsize.width*vsize.height > cur.width*cur.height ||
ms_video_size_get_orientation(vsize)!=ms_video_size_get_orientation(cur) ){
g_message("Resized to %ix%i",vsize.width,vsize.height);
gtk_window_resize(GTK_WINDOW(video_window),vsize.width,vsize.height);
}
_resize_video_window(video_window,vsize);
}
}
}
@ -308,3 +311,55 @@ void linphone_gtk_in_call_show_video(LinphoneCall *call){
}
}
}
static void on_video_preview_destroyed(GtkWidget *video_preview, GtkWidget *mw){
LinphoneCore *lc=linphone_gtk_get_core();
guint timeout_id=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(video_preview),"timeout-id"));
g_object_set_data(G_OBJECT(mw),"video_preview",NULL);
linphone_core_enable_video_preview(lc,FALSE);
linphone_core_set_native_preview_window_id(lc,-1);
g_source_remove(timeout_id);
}
GtkWidget *linphone_gtk_get_camera_preview_window(void){
return (GtkWidget *)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"video_preview");
}
static gboolean check_preview_size(GtkWidget *video_preview){
MSVideoSize vsize=linphone_core_get_current_preview_video_size(linphone_gtk_get_core());
if (vsize.width && vsize.height){
MSVideoSize cur;
gtk_window_get_size(GTK_WINDOW(video_preview),&cur.width,&cur.height);
if (cur.width!=vsize.width || cur.height!=vsize.height){
gtk_window_resize(GTK_WINDOW(video_preview),vsize.width,vsize.height);
}
}
return TRUE;
}
void linphone_gtk_show_camera_preview_clicked(GtkButton *button){
GtkWidget *mw=linphone_gtk_get_main_window();
GtkWidget *video_preview=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"video_preview");
if (!video_preview){
gchar *title;
LinphoneCore *lc=linphone_gtk_get_core();
GdkColor color;
guint tid;
video_preview=gtk_window_new(GTK_WINDOW_TOPLEVEL);
title=g_strdup_printf("%s - Video preview",linphone_gtk_get_ui_config("title","Linphone"));
gtk_window_set_title(GTK_WINDOW(video_preview),title);
gdk_color_parse("black",&color);
gtk_widget_modify_bg(video_preview,GTK_STATE_NORMAL,&color);
g_free(title);
g_object_set_data(G_OBJECT(mw),"video_preview",video_preview);
g_signal_connect(video_preview,"destroy",(GCallback)on_video_preview_destroyed,mw);
gtk_widget_show(video_preview);
linphone_core_set_native_preview_window_id(lc,get_native_handle(gtk_widget_get_window(video_preview)));
linphone_core_enable_video_preview(lc,TRUE);
tid=g_timeout_add(100,(GSourceFunc)check_preview_size,video_preview);
g_object_set_data(G_OBJECT(video_preview),"timeout-id",GINT_TO_POINTER(tid));
}
}

View file

@ -540,7 +540,7 @@ void sal_signing_key_parse_file(SalAuthInfo* auth_info, const char* path, const
* @param[in] generate_certificate if true, if matching certificate and key can't be found, generate it and store it into the given dir, filename will be subject.pem
* @param[in] generate_dtls_fingerprint if true and we have a certificate, generate the dtls fingerprint as described in rfc4572
*/
void sal_certificates_chain_parse_directory(unsigned char **certificate_pem, unsigned char **key_pem, unsigned char **fingerprint, const char* path, const char *subject, SalCertificateRawFormat format, bool_t generate_certificate, bool_t generate_dtls_fingerprint);
void sal_certificates_chain_parse_directory(char **certificate_pem, char **key_pem, char **fingerprint, const char* path, const char *subject, SalCertificateRawFormat format, bool_t generate_certificate, bool_t generate_dtls_fingerprint);
void sal_certificates_chain_delete(SalCertificatesChain *chain);
void sal_signing_key_delete(SalSigningKey *key);

View file

@ -20,6 +20,7 @@ package org.linphone.core;
import java.util.Vector;
import org.linphone.core.LinphoneCoreListener.LinphoneEchoCalibrationListener;
import org.linphone.mediastream.video.AndroidVideoWindowImpl;
import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration;
@ -429,6 +430,45 @@ public interface LinphoneCore {
return mStringValue;
}
}
/**
* linphone log collection upload states
*/
static public class LogCollectionUploadState {
static private Vector<LogCollectionUploadState> values = new Vector<LogCollectionUploadState>();
/**
* Delivery in progress
*/
static public LogCollectionUploadState LogCollectionUploadStateInProgress = new LogCollectionUploadState(0,"LinphoneCoreLogCollectionUploadStateInProgress");
/**
* Log collection upload successfully delivered and acknowledged by remote end point
*/
static public LogCollectionUploadState LogCollectionUploadStateDelivered = new LogCollectionUploadState(1,"LinphoneCoreLogCollectionUploadStateDelivered");
/**
* Log collection upload was not delivered
*/
static public LogCollectionUploadState LogCollectionUploadStateNotDelivered = new LogCollectionUploadState(2,"LinphoneCoreLogCollectionUploadStateNotDelivered");
private final int mValue;
private final String mStringValue;
private LogCollectionUploadState(int value, String stringValue) {
mValue = value;
values.addElement(this);
mStringValue=stringValue;
}
public static LogCollectionUploadState fromInt(int value) {
for (int i=0; i<values.size();i++) {
LogCollectionUploadState state = (LogCollectionUploadState) values.elementAt(i);
if (state.mValue == value) return state;
}
throw new RuntimeException("state not found ["+value+"]");
}
public String toString() {
return mStringValue;
}
}
/**
* Set the context of creation of the LinphoneCore.
@ -1057,10 +1097,10 @@ public interface LinphoneCore {
/**
* Start an echo calibration of the sound devices, in order to find adequate settings for the echo canceler automatically.
* status is notified to {@link LinphoneCoreListener#ecCalibrationStatus(EcCalibratorStatus, int, Object)}
* @param User object
* @param listener the LinphoneEchoCalibrationListener to call when the calibration is done
* @throws LinphoneCoreException if operation is still in progress;
**/
void startEchoCalibration(Object data) throws LinphoneCoreException;
void startEchoCalibration(LinphoneEchoCalibrationListener listener) throws LinphoneCoreException;
/**
* Returns true if echo calibration is recommended.
@ -1812,4 +1852,8 @@ public interface LinphoneCore {
*/
String getRemoteRingbackTone();
/**
* Upload the log collection to the configured server url.
*/
public void uploadLogCollection();
}

View file

@ -20,7 +20,6 @@ package org.linphone.core;
import java.nio.ByteBuffer;
import org.linphone.core.LinphoneCore.RemoteProvisioningState;
/**
*
@ -31,7 +30,7 @@ public interface LinphoneCoreListener {
public interface LinphoneListener extends LinphoneCoreListener,
LinphoneRemoteProvisioningListener, LinphoneMessageListener, LinphoneCallStateListener,
LinphoneCallEncryptionStateListener, LinphoneNotifyListener, LinphoneComposingListener,
LinphoneGlobalStateListener, LinphoneRegistrationStateListener {
LinphoneGlobalStateListener, LinphoneRegistrationStateListener, LinphoneLogCollectionUploadListener {
/**< Ask the application some authentication information
* @return */
void authInfoRequested(LinphoneCore lc, String realm, String username, String Domain);
@ -75,15 +74,6 @@ public interface LinphoneCoreListener {
*/
void dtmfReceived(LinphoneCore lc, LinphoneCall call, int dtmf);
/**
* Invoked when echo cancalation calibration is completed
* @param lc LinphoneCore
* @param status
* @param delay_ms echo delay
* @param data
*/
void ecCalibrationStatus(LinphoneCore lc,LinphoneCore.EcCalibratorStatus status, int delay_ms, Object data);
/**
* Report Notified message received for this identity.
* @param lc LinphoneCore
@ -194,7 +184,7 @@ public interface LinphoneCoreListener {
* @param state the RemoteProvisioningState
* @param message the error message if state == Failed
*/
void configuringStatus(LinphoneCore lc, RemoteProvisioningState state, String message);
void configuringStatus(LinphoneCore lc, LinphoneCore.RemoteProvisioningState state, String message);
}
public interface LinphoneMessageListener extends LinphoneCoreListener {
@ -243,5 +233,31 @@ public interface LinphoneCoreListener {
*/
void isComposingReceived(LinphoneCore lc, LinphoneChatRoom cr);
}
public interface LinphoneEchoCalibrationListener extends LinphoneCoreListener {
/**
* Invoked when echo cancalation calibration is completed
* @param lc LinphoneCore
* @param status
* @param delay_ms echo delay
* @param data
*/
void ecCalibrationStatus(LinphoneCore lc, LinphoneCore.EcCalibratorStatus status, int delay_ms, Object data);
}
public interface LinphoneLogCollectionUploadListener extends LinphoneCoreListener {
/**
* Callback prototype for reporting log collection upload progress indication.
*/
void uploadProgressIndication(LinphoneCore lc, int offset, int total);
/**
* Callback prototype for reporting log collection upload state change.
* @param lc LinphoneCore object
* @param state The state of the log collection upload
* @param info Additional information: error message in case of error state, URL of uploaded file in case of success.
*/
void uploadStateChanged(LinphoneCore lc, LinphoneCore.LogCollectionUploadState state, String info);
}
}

View file

@ -27,8 +27,10 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage {
@Override
public String getText() {
byte rawText[];
try {
return new String(getText(nativePtr), "UTF-8");
rawText=getText(nativePtr);
if (rawText!=null) return new String(rawText, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}

View file

@ -173,5 +173,4 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory {
public PresenceModel createPresenceModel(PresenceActivityType type, String description, String note, String lang) {
return new PresenceModelImpl(type, description, note, lang);
}
}

View file

@ -24,6 +24,7 @@ import java.io.File;
import java.io.IOException;
import org.linphone.core.LinphoneCall.State;
import org.linphone.core.LinphoneCoreListener.LinphoneEchoCalibrationListener;
import org.linphone.mediastream.Log;
import org.linphone.mediastream.video.AndroidVideoWindowImpl;
import org.linphone.mediastream.video.capture.hwconf.Hacks;
@ -31,8 +32,7 @@ import org.linphone.mediastream.video.capture.hwconf.Hacks;
import android.content.Context;
import android.media.AudioManager;
class LinphoneCoreImpl implements LinphoneCore {
public class LinphoneCoreImpl implements LinphoneCore {
private final LinphoneCoreListener mListener; //to make sure to keep a reference on this object
protected long nativePtr = 0;
@ -558,8 +558,8 @@ class LinphoneCoreImpl implements LinphoneCore {
public synchronized boolean isKeepAliveEnabled() {
return isKeepAliveEnabled(nativePtr);
}
public synchronized void startEchoCalibration(Object data) throws LinphoneCoreException {
startEchoCalibration(nativePtr, data);
public synchronized void startEchoCalibration(LinphoneEchoCalibrationListener listener) throws LinphoneCoreException {
startEchoCalibration(nativePtr, listener);
}
public synchronized Transports getSignalingTransportPorts() {
@ -1313,4 +1313,21 @@ class LinphoneCoreImpl implements LinphoneCore {
public String getRemoteRingbackTone() {
return getRemoteRingbackTone(nativePtr);
}
private native void uploadLogCollection(long nativePtr);
@Override
public void uploadLogCollection() {
uploadLogCollection(nativePtr);
}
/**
* Enable the linphone core log collection to upload logs on a server.
*/
public native static void enableLogCollection(boolean enable);
/**
* Set the path where the log files will be written for log collection.
* @param path The path where the log files will be written.
*/
public native static void setLogCollectionPath(String path);
}

@ -1 +1 @@
Subproject commit 08ed3f8a65ad830baa1023e5c0d3ec9e5421ef32
Subproject commit 11c45ba45de82e5ad5e0b1cd54d81c5d605b9d2c

2
oRTP

@ -1 +1 @@
Subproject commit 227f06f7256302404e29d2e2ab40dde00c5d1aca
Subproject commit 04034c570d6ffa8f670383e7b9f12c77b3e8b2dd

View file

@ -188,7 +188,6 @@ bool_t call_with_params2(LinphoneCoreManager* caller_mgr
stats initial_caller=caller_mgr->stat;
stats initial_callee=callee_mgr->stat;
bool_t result=FALSE;
char hellopath[256];
LinphoneCallParams *caller_params = caller_test_params->base;
LinphoneCallParams *callee_params = callee_test_params->base;
bool_t did_received_call;
@ -196,10 +195,6 @@ bool_t call_with_params2(LinphoneCoreManager* caller_mgr
sal_default_enable_sdp_removal(caller_mgr->lc->sal, caller_test_params->sdp_removal);
sal_default_enable_sdp_removal(callee_mgr->lc->sal, callee_test_params->sdp_removal);
/*use playfile for callee to avoid locking on capture card*/
linphone_core_use_files (callee_mgr->lc,TRUE);
snprintf(hellopath,sizeof(hellopath), "%s/sounds/hello8000.wav", liblinphone_tester_file_prefix);
linphone_core_set_play_file(callee_mgr->lc,hellopath);
if (!caller_params){
CU_ASSERT_PTR_NOT_NULL(linphone_core_invite_address(caller_mgr->lc,callee_mgr->identity));
}else{
@ -326,12 +321,32 @@ static void simple_call(void) {
LinphoneCoreManager* pauline;
const LinphoneAddress *from;
LinphoneCall *pauline_call;
LinphoneProxyConfig* marie_cfg;
const char* marie_id = NULL;
belle_sip_object_enable_leak_detector(TRUE);
begin=belle_sip_object_get_object_count();
marie = linphone_core_manager_new( "marie_rc");
pauline = linphone_core_manager_new( "pauline_rc");
/* with the account manager, we might lose the identity */
marie_cfg = linphone_core_get_default_proxy_config(marie->lc);
marie_id = linphone_proxy_config_get_identity(marie_cfg);
{
LinphoneAddress* marie_addr = linphone_address_new(marie_id);
char* marie_tmp_id = NULL;
linphone_address_set_display_name(marie_addr, "Super Marie");
marie_tmp_id = linphone_address_as_string(marie_addr);
linphone_proxy_config_edit(marie_cfg);
linphone_proxy_config_set_identity(marie_cfg,marie_tmp_id);
linphone_proxy_config_done(marie_cfg);
ms_free(marie_tmp_id);
linphone_address_unref(marie_addr);
}
CU_ASSERT_TRUE(call(marie,pauline));
pauline_call=linphone_core_get_current_call(pauline->lc);
CU_ASSERT_PTR_NOT_NULL(pauline_call);
@ -368,15 +383,9 @@ static void direct_call_over_ipv6(){
if (liblinphone_tester_ipv6_available()){
LCSipTransports pauline_transports;
LinphoneAddress* pauline_dest = linphone_address_new("sip:[::1];transport=tcp");
char hellopath[256];
marie = linphone_core_manager_new( "marie_rc");
pauline = linphone_core_manager_new( "pauline_tcp_rc");
/*use playfile for callee to avoid locking on capture card*/
snprintf(hellopath,sizeof(hellopath), "%s/sounds/hello8000.wav", liblinphone_tester_file_prefix);
linphone_core_set_play_file(pauline->lc,hellopath);
linphone_core_use_files (pauline->lc,TRUE);
linphone_core_enable_ipv6(marie->lc,TRUE);
linphone_core_enable_ipv6(pauline->lc,TRUE);
linphone_core_set_default_proxy_config(marie->lc,NULL);
@ -448,7 +457,6 @@ static void multiple_answers_call() {
/* Scenario is this: pauline calls marie, which is registered 2 times.
Both linphones answer at the same time, and only one should get the
call running, the other should be terminated */
char ringbackpath[256];
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc" );
LinphoneCoreManager* marie1 = linphone_core_manager_new( "marie_rc" );
LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc" );
@ -459,11 +467,6 @@ static void multiple_answers_call() {
lcs = ms_list_append(lcs,marie1->lc);
lcs = ms_list_append(lcs,marie2->lc);
linphone_core_use_files(pauline->lc, TRUE);
linphone_core_use_files(marie1->lc, TRUE);
linphone_core_use_files(marie2->lc, TRUE);
snprintf(ringbackpath,sizeof(ringbackpath), "%s/sounds/hello8000.wav" /*use hello because rinback is too short*/, liblinphone_tester_file_prefix);
CU_ASSERT_TRUE(wait_for_until(pauline->lc, NULL, &pauline->stat.number_of_LinphoneRegistrationOk, 1, 2000));
@ -499,7 +502,6 @@ static void multiple_answers_call_with_media_relay() {
/* Scenario is this: pauline calls marie, which is registered 2 times.
* Both linphones answer at the same time, and only one should get the
* call running, the other should be terminated */
char ringbackpath[256];
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc" );
LinphoneCoreManager* marie1 = linphone_core_manager_new( "marie_rc" );
LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc" );
@ -510,16 +512,10 @@ static void multiple_answers_call_with_media_relay() {
lcs = ms_list_append(lcs,marie1->lc);
lcs = ms_list_append(lcs,marie2->lc);
linphone_core_use_files(pauline->lc, TRUE);
linphone_core_use_files(marie1->lc, TRUE);
linphone_core_use_files(marie2->lc, TRUE);
linphone_core_set_user_agent(pauline->lc, "Natted Linphone", NULL);
linphone_core_set_user_agent(marie1->lc, "Natted Linphone", NULL);
linphone_core_set_user_agent(marie2->lc, "Natted Linphone", NULL);
snprintf(ringbackpath,sizeof(ringbackpath), "%s/sounds/hello8000.wav" /*use hello because rinback is too short*/, liblinphone_tester_file_prefix);
CU_ASSERT_TRUE(wait_for_until(pauline->lc, NULL, &pauline->stat.number_of_LinphoneRegistrationOk, 1, 2000));
CU_ASSERT_PTR_NOT_NULL( linphone_core_invite_address(pauline->lc, marie1->identity ) );
@ -894,6 +890,26 @@ static void call_with_no_sdp(void) {
linphone_core_manager_destroy(pauline);
}
static void call_with_no_sdp_ack_without_sdp(void){
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
LinphoneCall *call;
linphone_core_enable_sdp_200_ack(marie->lc,TRUE);
linphone_core_invite_address(marie->lc,pauline->identity);
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallIncomingReceived,1));
call=linphone_core_get_current_call(pauline->lc);
if (call){
sal_call_enable_sdp_removal(call->op, TRUE); /*this will have the effect that the SDP received in the ACK will be ignored*/
linphone_core_accept_call(pauline->lc, call);
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallError,1));
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1));
}
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
static bool_t check_ice(LinphoneCoreManager* caller, LinphoneCoreManager* callee, LinphoneIceState state) {
LinphoneCall *c1,*c2;
@ -1249,6 +1265,32 @@ static void call_paused_resumed_from_callee(void) {
linphone_core_manager_destroy(pauline);
}
static void audio_call_with_ice_no_matching_audio_codecs(void) {
LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_rc");
LinphoneCall *out_call;
linphone_core_enable_payload_type(marie->lc, linphone_core_find_payload_type(marie->lc, "PCMU", 8000, 1), FALSE); /* Disable PCMU */
linphone_core_enable_payload_type(marie->lc, linphone_core_find_payload_type(marie->lc, "PCMA", 8000, 1), TRUE); /* Enable PCMA */
linphone_core_set_firewall_policy(marie->lc, LinphonePolicyUseIce);
linphone_core_set_stun_server(marie->lc, "stun.linphone.org");
linphone_core_set_firewall_policy(pauline->lc, LinphonePolicyUseIce);
linphone_core_set_stun_server(pauline->lc, "stun.linphone.org");
out_call = linphone_core_invite_address(marie->lc, pauline->identity);
linphone_call_ref(out_call);
CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallOutgoingInit, 1));
/* flexisip will retain the 488 until the "urgent reply" timeout arrives. */
CU_ASSERT_TRUE(wait_for_until(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallError, 1, 6000));
CU_ASSERT_EQUAL(linphone_call_get_reason(out_call), LinphoneReasonNotAcceptable);
CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallIncomingReceived, 0);
linphone_call_unref(out_call);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
#ifdef VIDEO_ENABLED
static LinphoneCall* setup_video(LinphoneCoreManager* caller,LinphoneCoreManager* callee) {
LinphoneVideoPolicy caller_policy;
@ -1495,6 +1537,7 @@ static void video_call_base(LinphoneCoreManager* pauline,LinphoneCoreManager* ma
LinphoneCall* marie_call;
LinphoneCall* pauline_call;
LinphoneVideoPolicy marie_policy, pauline_policy;
linphone_core_enable_video_capture(marie->lc, TRUE);
linphone_core_enable_video_display(marie->lc, TRUE);
linphone_core_enable_video_capture(pauline->lc, TRUE);
@ -1615,27 +1658,51 @@ static void call_with_ice_video_added(void) {
linphone_core_manager_destroy(pauline);
}
static void video_call_with_ice_no_matching_audio_codecs(void) {
static void video_call_with_early_media_no_matching_audio_codecs(void) {
LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_rc");
LinphoneCall *out_call;
LinphoneVideoPolicy vpol={0};
linphone_core_enable_video_capture(marie->lc, TRUE);
linphone_core_enable_video_display(marie->lc, TRUE);
linphone_core_enable_video_capture(pauline->lc, TRUE);
linphone_core_enable_video_display(pauline->lc, FALSE);
vpol.automatically_initiate=TRUE;
vpol.automatically_accept=TRUE;
linphone_core_set_video_policy(pauline->lc,&vpol);
linphone_core_set_video_policy(marie->lc,&vpol);
linphone_core_enable_payload_type(marie->lc, linphone_core_find_payload_type(marie->lc, "PCMU", 8000, 1), FALSE); /* Disable PCMU */
linphone_core_enable_payload_type(marie->lc, linphone_core_find_payload_type(marie->lc, "PCMA", 8000, 1), TRUE); /* Enable PCMA */
linphone_core_set_firewall_policy(marie->lc, LinphonePolicyUseIce);
linphone_core_set_stun_server(marie->lc, "stun.linphone.org");
linphone_core_set_firewall_policy(pauline->lc, LinphonePolicyUseIce);
linphone_core_set_stun_server(pauline->lc, "stun.linphone.org");
out_call = linphone_core_invite_address(marie->lc, pauline->identity);
linphone_call_ref(out_call);
CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallOutgoingInit, 1));
CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallIncomingReceived, 1));
CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallOutgoingRinging, 1));
/* flexisip will retain the 488 until the "urgent reply" timeout arrives. */
CU_ASSERT_TRUE(wait_for_until(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallError, 1, 6000));
CU_ASSERT_EQUAL(linphone_call_get_reason(out_call), LinphoneReasonNotAcceptable);
CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallIncomingReceived, 0);
linphone_core_accept_early_media(pauline->lc,linphone_core_get_current_call(pauline->lc));
CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallIncomingEarlyMedia, 1));
CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallOutgoingEarlyMedia, 1));
/*audio stream shall not have been requested to start*/
CU_ASSERT_PTR_NULL(linphone_core_get_current_call(pauline->lc)->audiostream->soundread);
CU_ASSERT_TRUE(linphone_call_params_video_enabled(linphone_call_get_current_params(out_call))==TRUE);
CU_ASSERT_TRUE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc)))==TRUE);
linphone_core_accept_call(pauline->lc, linphone_core_get_current_call(pauline->lc));
CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1));
CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 1));
linphone_core_terminate_call(marie->lc, out_call);
CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallEnd, 1));
CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallEnd, 1));
linphone_call_unref(out_call);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
@ -1799,7 +1866,6 @@ static void call_waiting_indication_with_param(bool_t enable_caller_privacy) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc");
char hellopath[256];
MSList *iterator;
MSList* lcs;
LinphoneCall* pauline_called_by_marie;
@ -1817,12 +1883,6 @@ static void call_waiting_indication_with_param(bool_t enable_caller_privacy) {
CU_ASSERT_TRUE(call_with_caller_params(marie,pauline,marie_params));
pauline_called_by_marie=linphone_core_get_current_call(pauline->lc);
/*use playfile for callee to avoid locking on capture card*/
linphone_core_use_files (laure->lc,TRUE);
linphone_core_use_files (marie->lc,TRUE);
snprintf(hellopath,sizeof(hellopath), "%s/sounds/hello8000.wav", liblinphone_tester_file_prefix);
linphone_core_set_play_file(laure->lc,hellopath);
if (enable_caller_privacy)
linphone_call_params_set_privacy(laure_params,LinphonePrivacyId);
@ -2043,7 +2103,9 @@ static void call_with_file_player(void) {
CU_ASSERT_TRUE(linphone_player_open(player,hellopath,on_eof,marie)==0);
CU_ASSERT_TRUE(linphone_player_start(player)==0);
}
CU_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&marie->stat.number_of_player_eof,1,12000));
/* This assert should be modified to be at least as long as the hello8000.wav file */
CU_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&marie->stat.number_of_player_eof,1,30000));
/*just to sleep*/
linphone_core_terminate_all_calls(marie->lc);
@ -2272,14 +2334,13 @@ static void early_media_call(void) {
}
static void early_media_call_with_ringing(void){
char hellopath[256];
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_rc");
MSList* lcs = NULL;
LinphoneCall* marie_call;
LinphoneCallLog *marie_call_log;
time_t connected_time=0;
time_t ended_time=0;
uint64_t connected_time=0;
uint64_t ended_time=0;
int dummy=0;
lcs = ms_list_append(lcs,marie->lc);
@ -2288,11 +2349,6 @@ static void early_media_call_with_ringing(void){
Marie calls Pauline, and after the call has rung, transitions to an early_media session
*/
/*use playfile for callee to avoid locking on capture card*/
linphone_core_use_files (pauline->lc,TRUE);
snprintf(hellopath,sizeof(hellopath), "%s/sounds/hello8000.wav", liblinphone_tester_file_prefix);
linphone_core_set_play_file(pauline->lc,hellopath);
marie_call = linphone_core_invite_address(marie->lc, pauline->identity);
marie_call_log = linphone_call_get_call_log(marie_call);
@ -2313,7 +2369,7 @@ static void early_media_call_with_ringing(void){
linphone_core_accept_call(pauline->lc, linphone_core_get_current_call(pauline->lc));
CU_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallConnected, 1,1000));
connected_time=time(NULL);
connected_time=ms_get_cur_time_ms();
CU_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 1,1000));
CU_ASSERT_EQUAL(marie_call, linphone_core_get_current_call(marie->lc));
@ -2326,8 +2382,8 @@ static void early_media_call_with_ringing(void){
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,1000));
ended_time=time(NULL);
CU_ASSERT_TRUE (labs (linphone_call_log_get_duration(marie_call_log) - (ended_time - connected_time)) <1 );
ended_time=ms_get_cur_time_ms();
CU_ASSERT_TRUE( labs((linphone_call_log_get_duration(marie_call_log)*1000) - (int64_t)(ended_time - connected_time)) <=1000 );
ms_list_free(lcs);
}
@ -2336,7 +2392,6 @@ static void early_media_call_with_ringing(void){
}
static void early_media_call_with_update_base(bool_t media_change){
char hellopath[256];
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_rc");
MSList* lcs = NULL;
@ -2353,11 +2408,6 @@ static void early_media_call_with_update_base(bool_t media_change){
Marie calls Pauline, and after the call has rung, transitions to an early_media session
*/
/*use playfile for callee to avoid locking on capture card*/
linphone_core_use_files (pauline->lc,TRUE);
snprintf(hellopath,sizeof(hellopath), "%s/sounds/hello8000.wav", liblinphone_tester_file_prefix);
linphone_core_set_play_file(pauline->lc,hellopath);
marie_call = linphone_core_invite_address(marie->lc, pauline->identity);
CU_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingReceived,1,1000));
@ -2575,9 +2625,6 @@ static void call_transfer_existing_call_outgoing_call(void) {
MSList* lcs=ms_list_append(NULL,marie->lc);
const MSList* calls;
linphone_core_use_files (pauline->lc,TRUE);
linphone_core_use_files (laure->lc,TRUE);
lcs=ms_list_append(lcs,pauline->lc);
lcs=ms_list_append(lcs,laure->lc);
@ -2604,8 +2651,8 @@ static void call_transfer_existing_call_outgoing_call(void) {
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallRefered,1,2000));
/*pauline pausing marie*/
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallPausing,1,2000));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallPaused,1,2000));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallPausing,1,4000));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallPaused,1,4000));
/*pauline calling laure*/
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingProgress,1,2000));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransferCallOutgoingInit,1,2000));
@ -2743,7 +2790,6 @@ static void call_established_with_rejected_incoming_reinvite(void) {
}
static void call_redirect(void){
char hellopath[256];
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_rc");
LinphoneCoreManager* laure = linphone_core_manager_new("laure_rc");
@ -2758,13 +2804,6 @@ static void call_redirect(void){
Marie calls Pauline, which will redirect the call to Laure via a 302
*/
/*use playfile for callee to avoid locking on capture card*/
linphone_core_use_files (pauline->lc,TRUE);
linphone_core_use_files (laure->lc,TRUE);
snprintf(hellopath,sizeof(hellopath), "%s/sounds/hello8000.wav", liblinphone_tester_file_prefix);
linphone_core_set_play_file(pauline->lc,hellopath);
linphone_core_set_play_file(laure->lc,hellopath);
marie_call = linphone_core_invite_address(marie->lc, pauline->identity);
CU_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingReceived,1,1000));
@ -2889,9 +2928,9 @@ static void call_rejected_without_403_because_wrong_credentials_no_auth_req_cb()
#ifdef VIDEO_ENABLED
/*this is call forking with early media managed at client side (not by flexisip server)*/
static void multiple_early_media(void) {
LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_tcp_rc");
LinphoneCoreManager* marie1 = linphone_core_manager_new("marie_early_rc");
LinphoneCoreManager* marie2 = linphone_core_manager_new("marie_early_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_tcp_rc");
MSList *lcs=NULL;
LinphoneCallParams *params=linphone_core_create_default_call_parameters(pauline->lc);
LinphoneVideoPolicy pol;
@ -2900,9 +2939,6 @@ static void multiple_early_media(void) {
LinphoneCall *pauline_call;
LinphoneInfoMessage *info;
int dummy=0;
char ringbackpath[256];
snprintf(ringbackpath,sizeof(ringbackpath), "%s/sounds/hello8000.wav" /*use hello because rinback is too short*/, liblinphone_tester_file_prefix);
pol.automatically_accept=1;
pol.automatically_initiate=1;
@ -2910,18 +2946,11 @@ static void multiple_early_media(void) {
linphone_core_enable_video(marie1->lc,TRUE,TRUE);
linphone_core_set_video_policy(marie1->lc,&pol);
/*use playfile for marie1 to avoid locking on capture card*/
linphone_core_use_files(marie1->lc,TRUE);
linphone_core_set_play_file(marie1->lc,ringbackpath);
linphone_core_enable_video(marie2->lc,TRUE,TRUE);
linphone_core_set_video_policy(marie2->lc,&pol);
linphone_core_set_audio_port_range(marie2->lc,40200,40300);
linphone_core_set_video_port_range(marie2->lc,40400,40500);
/*use playfile for marie2 to avoid locking on capture card*/
linphone_core_use_files(marie2->lc,TRUE);
linphone_core_set_play_file(marie2->lc,ringbackpath);
lcs=ms_list_append(lcs,marie1->lc);
lcs=ms_list_append(lcs,marie2->lc);
@ -2942,7 +2971,7 @@ static void multiple_early_media(void) {
marie2_call=linphone_core_get_current_call(marie2->lc);
/*wait a bit that streams are established*/
wait_for_list(lcs,&dummy,1,6000);
wait_for_list(lcs,&dummy,1,3000);
CU_ASSERT_TRUE(linphone_call_get_audio_stats(pauline_call)->download_bandwidth>70);
CU_ASSERT_TRUE(linphone_call_get_audio_stats(marie1_call)->download_bandwidth>70);
CU_ASSERT_TRUE(linphone_call_get_audio_stats(marie2_call)->download_bandwidth>70);
@ -3487,6 +3516,7 @@ test_t call_tests[] = {
{ "Early-media call with updated codec", early_media_call_with_codec_update},
{ "Call terminated by caller", call_terminated_by_caller },
{ "Call without SDP", call_with_no_sdp},
{ "Call without SDP and ACK without SDP", call_with_no_sdp_ack_without_sdp},
{ "Call paused resumed", call_paused_resumed },
{ "Call paused resumed with loss", call_paused_resumed_with_loss },
{ "Call paused resumed from callee", call_paused_resumed_from_callee },
@ -3496,6 +3526,7 @@ test_t call_tests[] = {
{ "SRTP call with declined srtp", call_with_declined_srtp },
{ "Call with file player", call_with_file_player},
{ "Call with mkv file player", call_with_mkv_file_player},
{ "Audio call with ICE no matching audio codecs", audio_call_with_ice_no_matching_audio_codecs },
#ifdef VIDEO_ENABLED
{ "Simple video call",video_call},
{ "Simple video call using policy",video_call_using_policy},
@ -3511,9 +3542,9 @@ test_t call_tests[] = {
{ "Call with multiple early media", multiple_early_media },
{ "Call with ICE from video to non-video", call_with_ice_video_to_novideo},
{ "Call with ICE and video added", call_with_ice_video_added },
{ "Video call with ICE no matching audio codecs", video_call_with_ice_no_matching_audio_codecs },
{ "Video call recording", video_call_recording_test },
{ "Snapshot", video_call_snapshot },
{ "Video call with early media and no matching audio codecs", video_call_with_early_media_no_matching_audio_codecs },
#endif
{ "SRTP ice call", srtp_ice_call },
{ "ZRTP ice call", zrtp_ice_call },

View file

@ -307,7 +307,6 @@ static void call_forking_cancelled(void){
}
static void call_forking_declined(bool_t declined_globaly){
char hellopath[256];
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc");
@ -323,11 +322,6 @@ static void call_forking_declined(bool_t declined_globaly){
linphone_core_set_user_agent(marie3->lc,"Natted Linphone",NULL);
linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL);
/*use playfile for callee to avoid locking on capture card*/
linphone_core_use_files (pauline->lc,TRUE);
snprintf(hellopath,sizeof(hellopath), "%s/sounds/hello8000.wav", liblinphone_tester_file_prefix);
linphone_core_set_play_file(pauline->lc,hellopath);
linphone_core_invite_address(pauline->lc,marie->identity);
/*pauline should hear ringback*/
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,3000));
@ -376,7 +370,6 @@ static void call_forking_declined_localy(void){
}
static void call_forking_with_push_notification_single(void){
char hellopath[256];
MSList* lcs;
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
@ -391,11 +384,6 @@ static void call_forking_with_push_notification_single(void){
/*unfortunately marie gets unreachable due to crappy 3G operator or iOS bug...*/
linphone_core_set_network_reachable(marie->lc,FALSE);
/*use playfile for callee to avoid locking on capture card*/
linphone_core_use_files (pauline->lc,TRUE);
snprintf(hellopath,sizeof(hellopath), "%s/sounds/hello8000.wav", liblinphone_tester_file_prefix);
linphone_core_set_play_file(pauline->lc,hellopath);
linphone_core_invite_address(pauline->lc,marie->identity);
/*the server is expected to send a push notification to marie, this will wake up linphone, that will reconnect:*/
@ -425,7 +413,6 @@ static void call_forking_with_push_notification_single(void){
}
static void call_forking_with_push_notification_multiple(void){
char hellopath[256];
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc");
@ -442,13 +429,6 @@ static void call_forking_with_push_notification_multiple(void){
/*unfortunately marie gets unreachable due to crappy 3G operator or iOS bug...*/
linphone_core_set_network_reachable(marie2->lc,FALSE);
/*use playfile for callee to avoid locking on capture card*/
snprintf(hellopath,sizeof(hellopath), "%s/sounds/hello8000.wav", liblinphone_tester_file_prefix);
linphone_core_use_files (marie->lc,TRUE);
linphone_core_set_play_file(marie->lc,hellopath);
linphone_core_use_files (marie2->lc,TRUE);
linphone_core_set_play_file(marie2->lc,hellopath);
linphone_core_invite_address(pauline->lc,marie->identity);
/*marie1 will ring*/
@ -523,9 +503,9 @@ void call_forking_not_responded(void){
}
static void early_media_call_forking(void) {
LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_tcp_rc");
LinphoneCoreManager* marie1 = linphone_core_manager_new("marie_early_rc");
LinphoneCoreManager* marie2 = linphone_core_manager_new("marie_early_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_tcp_rc");
MSList *lcs=NULL;
LinphoneCallParams *params=linphone_core_create_default_call_parameters(pauline->lc);
LinphoneVideoPolicy pol;
@ -533,9 +513,7 @@ static void early_media_call_forking(void) {
LinphoneCall *marie2_call;
LinphoneCall *pauline_call;
int dummy=0;
char ringbackpath[256];
snprintf(ringbackpath,sizeof(ringbackpath), "%s/sounds/hello8000.wav" /*use hello because rinback is too short*/, liblinphone_tester_file_prefix);
pol.automatically_accept=1;
pol.automatically_initiate=1;
@ -547,18 +525,11 @@ static void early_media_call_forking(void) {
linphone_core_enable_video(marie1->lc,TRUE,TRUE);
linphone_core_set_video_policy(marie1->lc,&pol);
/*use playfile for marie1 to avoid locking on capture card*/
linphone_core_use_files (marie1->lc,TRUE);
linphone_core_set_play_file(marie1->lc,ringbackpath);
linphone_core_enable_video(marie2->lc,TRUE,TRUE);
linphone_core_set_video_policy(marie2->lc,&pol);
linphone_core_set_audio_port_range(marie2->lc,40200,40300);
linphone_core_set_video_port_range(marie2->lc,40400,40500);
/*use playfile for marie2 to avoid locking on capture card*/
linphone_core_use_files (marie2->lc,TRUE);
linphone_core_set_play_file(marie2->lc,ringbackpath);
lcs=ms_list_append(lcs,marie1->lc);
lcs=ms_list_append(lcs,marie2->lc);
@ -581,12 +552,12 @@ static void early_media_call_forking(void) {
/*wait a bit that streams are established*/
wait_for_list(lcs,&dummy,1,3000);
CU_ASSERT_TRUE(linphone_call_get_audio_stats(pauline_call)->download_bandwidth>70
&& linphone_call_get_audio_stats(pauline_call)->download_bandwidth<90);
CU_ASSERT_TRUE(linphone_call_get_audio_stats(marie1_call)->download_bandwidth>70
&& linphone_call_get_audio_stats(marie1_call)->download_bandwidth<90);
CU_ASSERT_TRUE(linphone_call_get_audio_stats(marie2_call)->download_bandwidth>70
&& linphone_call_get_audio_stats(marie2_call)->download_bandwidth<90);
CU_ASSERT_TRUE(linphone_call_get_audio_stats(pauline_call)->download_bandwidth>60
&& linphone_call_get_audio_stats(pauline_call)->download_bandwidth<99);
CU_ASSERT_TRUE(linphone_call_get_audio_stats(marie1_call)->download_bandwidth>60
&& linphone_call_get_audio_stats(marie1_call)->download_bandwidth<99);
CU_ASSERT_TRUE(linphone_call_get_audio_stats(marie2_call)->download_bandwidth>60
&& linphone_call_get_audio_stats(marie2_call)->download_bandwidth<99);
linphone_core_accept_call(marie1->lc,linphone_core_get_current_call(marie1->lc));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallStreamsRunning,1,3000));
@ -597,10 +568,10 @@ static void early_media_call_forking(void) {
/*wait a bit that streams are established*/
wait_for_list(lcs,&dummy,1,3000);
CU_ASSERT_TRUE(linphone_call_get_audio_stats(pauline_call)->download_bandwidth>71
&& linphone_call_get_audio_stats(pauline_call)->download_bandwidth<91 );
CU_ASSERT_TRUE(linphone_call_get_audio_stats(marie1_call)->download_bandwidth>71
&& linphone_call_get_audio_stats(marie1_call)->download_bandwidth<91 );
CU_ASSERT_TRUE(linphone_call_get_audio_stats(pauline_call)->download_bandwidth>60
&& linphone_call_get_audio_stats(pauline_call)->download_bandwidth<99 );
CU_ASSERT_TRUE(linphone_call_get_audio_stats(marie1_call)->download_bandwidth>60
&& linphone_call_get_audio_stats(marie1_call)->download_bandwidth<99 );
linphone_core_terminate_all_calls(pauline->lc);
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,1000));

View file

@ -135,6 +135,8 @@ void helper(const char *name) {
#if HAVE_CU_CURSES
"\t\t\t--curses\n"
#endif
"\t\t\t--xml\n"
"\t\t\t--xml-file <xml file prefix (will be suffixed by '-Results.xml')>\n"
, name);
}
@ -153,6 +155,8 @@ int main (int argc, char *argv[])
int ret;
const char *suite_name=NULL;
const char *test_name=NULL;
const char *xml_file=NULL;
int xml = 0;
FILE* log_file=NULL;
#if defined(ANDROID)
linphone_core_set_log_handler(linphone_android_ortp_log_handler);
@ -198,6 +202,11 @@ int main (int argc, char *argv[])
suite_name = argv[i];
liblinphone_tester_list_suite_tests(suite_name);
return 0;
} else if (strcmp(argv[i], "--xml-file") == 0){
CHECK_ARG("--xml-file", ++i, argc);
xml_file = argv[i];
} else if (strcmp(argv[i], "--xml") == 0){
xml = 1;
} else if (strcmp(argv[i],"--log-file")==0){
CHECK_ARG("--log-file", ++i, argc);
log_file=fopen(argv[i],"w");
@ -216,6 +225,17 @@ int main (int argc, char *argv[])
}
}
if( xml && (suite_name || test_name) ){
printf("Cannot use both xml and specific test suite\n");
return -1;
}
if( xml_file != NULL ){
liblinphone_tester_set_xml_output(xml_file);
}
liblinphone_tester_enable_xml(xml);
ret = liblinphone_tester_run_tests(suite_name, test_name);
liblinphone_tester_uninit();
return ret;

View file

@ -79,6 +79,11 @@ extern void liblinphone_tester_set_fileprefix(const char* file_prefix);
extern void liblinphone_tester_set_writable_dir_prefix(const char* writable_dir_prefix);
extern int liblinphone_tester_ipv6_available(void);
extern void liblinphone_tester_enable_xml( bool_t enable );
extern void liblinphone_tester_set_xml_output(const char *xml_path );
extern const char* liblinphone_tester_get_xml_output(void);
/**
* @brief Tells the tester whether or not to clean the accounts it has created between runs.
* @details Setting this to 1 will not clear the list of created accounts between successive
@ -257,8 +262,9 @@ void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered,
void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf);
void text_message_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from_address, const char *message);
void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage* message);
void file_transfer_received(LinphoneChatMessage *message, const LinphoneContent* content, const char* buff, size_t size);
void file_transfer_send(LinphoneChatMessage *message, const LinphoneContent* content, char* buff, size_t* size);
void file_transfer_received(LinphoneChatMessage *message, const LinphoneContent* content, const LinphoneBuffer *buffer);
LinphoneBuffer * file_transfer_send(LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t size);
LinphoneBuffer * memory_file_transfer_send(LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t size);
void file_transfer_progress_indication(LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t total);
void is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room);
void info_message_received(LinphoneCore *lc, LinphoneCall *call, const LinphoneInfoMessage *msg);

View file

@ -100,8 +100,15 @@ LinphoneCoreManager* setup(bool_t enable_logs) {
return marie;
}
time_t check_file(char * filepath) {
time_t time_curr = -1;
time_t check_file(LinphoneCoreManager* mgr) {
time_t last_log = ms_time(NULL);
char* filepath = linphone_core_compress_log_collection(mgr->lc);
time_t time_curr = -1;
uint32_t timediff = 0;
CU_ASSERT_PTR_NOT_NULL(filepath);
if (filepath != NULL) {
int line_count = 0;
FILE *file = fopen(filepath, "r");
@ -134,6 +141,13 @@ time_t check_file(char * filepath) {
fclose(file);
ms_free(filepath);
}
timediff = labs((long int)time_curr - (long int)last_log);
CU_ASSERT_TRUE( timediff <= 1 );
if( !(timediff <= 1) ){
ms_error("time_curr: %ld, last_log: %ld timediff: %d", time_curr, last_log, timediff );
}
// return latest time in file
return time_curr;
}
@ -159,38 +173,28 @@ static void collect_files_disabled() {
static void collect_files_filled() {
LinphoneCoreManager* marie = setup(TRUE);
char * filepath = linphone_core_compress_log_collection(marie->lc);
CU_ASSERT_PTR_NOT_NULL(filepath);
CU_ASSERT_EQUAL(check_file(filepath), ms_time(0));
check_file(marie);
linphone_core_manager_destroy(marie);
}
static void collect_files_small_size() {
LinphoneCoreManager* marie = setup(TRUE);
char * filepath;
linphone_core_set_log_collection_max_file_size(5000);
filepath = linphone_core_compress_log_collection(marie->lc);
CU_ASSERT_PTR_NOT_NULL(filepath);
CU_ASSERT_EQUAL(check_file(filepath), ms_time(0));
check_file(marie);
linphone_core_manager_destroy(marie);
}
static void collect_files_changing_size() {
LinphoneCoreManager* marie = setup(TRUE);
char * filepath;
int waiting = 100;
filepath = linphone_core_compress_log_collection(marie->lc);
CU_ASSERT_PTR_NOT_NULL(filepath);
CU_ASSERT_EQUAL(check_file(filepath), ms_time(0));
check_file(marie);
linphone_core_set_log_collection_max_file_size(5000);
// Generate some logs
while (--waiting) ms_error("(test error)Waiting %d...", waiting);
filepath = linphone_core_compress_log_collection(marie->lc);
CU_ASSERT_PTR_NOT_NULL(filepath);
CU_ASSERT_EQUAL(check_file(filepath), ms_time(0));
check_file(marie);
linphone_core_manager_destroy(marie);
}

View file

@ -62,7 +62,7 @@ void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMess
/**
* function invoked when a file transfer is received.
* */
void file_transfer_received(LinphoneChatMessage *message, const LinphoneContent* content, const char* buff, size_t size){
void file_transfer_received(LinphoneChatMessage *message, const LinphoneContent* content, const LinphoneBuffer *buffer){
FILE* file=NULL;
char receive_file[256];
LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(message);
@ -72,18 +72,17 @@ void file_transfer_received(LinphoneChatMessage *message, const LinphoneContent*
/*first chunk, creating file*/
file = fopen(receive_file,"wb");
linphone_chat_message_set_user_data(message,(void*)file); /*store fd for next chunks*/
} else {
/*next chunk*/
file = (FILE*)linphone_chat_message_get_user_data(message);
}
if (size==0) { /* tranfer complete */
stats* counters = get_stats(lc);
counters->number_of_LinphoneMessageExtBodyReceived++;
fclose(file);
} else { /* store content on a file*/
if (fwrite(buff,size,1,file)==-1){
ms_error("file_transfer_received(): write() failed: %s",strerror(errno));
}
file = (FILE*)linphone_chat_message_get_user_data(message);
if (linphone_buffer_is_empty(buffer)) { /* tranfer complete */
stats* counters = get_stats(lc);
counters->number_of_LinphoneMessageExtBodyReceived++;
fclose(file);
} else { /* store content on a file*/
if (fwrite(linphone_buffer_get_content(buffer),linphone_buffer_get_size(buffer),1,file)==-1){
ms_error("file_transfer_received(): write() failed: %s",strerror(errno));
}
}
}
@ -93,26 +92,31 @@ static char big_file [128000]; /* a buffer to simulate a big file for the file t
/*
* function called when the file transfer is initiated. file content should be feed into object LinphoneContent
* */
void file_transfer_send(LinphoneChatMessage *message, const LinphoneContent* content, char* buff, size_t* size){
int offset=-1;
if (!linphone_chat_message_get_user_data(message)) {
/*first chunk*/
offset=0;
} else {
/*subsequent chunk*/
offset = (int)((long)(linphone_chat_message_get_user_data(message))&0x00000000FFFFFFFF);
LinphoneBuffer * file_transfer_send(LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t size){
LinphoneBuffer *lb;
size_t file_size;
size_t size_to_send;
FILE *file_to_send;
uint8_t *buf;
if (size == 0) return linphone_buffer_new(); /*end of file*/
file_to_send = linphone_chat_message_get_user_data(message);
fseek(file_to_send, 0, SEEK_END);
file_size = ftell(file_to_send);
fseek(file_to_send, offset, SEEK_SET);
size_to_send = MIN(size, file_size - offset);
buf = ms_malloc(size_to_send);
if (fread(buf, size_to_send, 1, file_to_send)!=size_to_send){
ms_error("fread error");
}
*size = MIN(*size,sizeof(big_file)-offset); /*updating content->size with minimun between remaining data and requested size*/
lb = linphone_buffer_new_from_data(buf, size_to_send);
ms_free(buf);
return lb;
}
if (*size==0) {
/*end of file*/
return;
}
memcpy(buff,big_file+offset,*size);
/*store offset for next chunk*/
linphone_chat_message_set_user_data(message,(void*)(offset+*size));
LinphoneBuffer * memory_file_transfer_send(LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t size){
size_t size_to_send = MIN(size, sizeof(big_file) - offset);
if (size == 0) return linphone_buffer_new(); /*end of file*/
return linphone_buffer_new_from_data((uint8_t *)big_file + offset, size_to_send);
}
/**
@ -402,24 +406,60 @@ static void text_message_with_external_body(void) {
linphone_core_manager_destroy(pauline);
}
static bool_t compare_files(const char *path1, const char *path2) {
bool_t res;
size_t size1;
size_t size2;
uint8_t *buf1;
uint8_t *buf2;
FILE *f1 = fopen(path1, "rb");
FILE *f2 = fopen(path2, "rb");
fseek(f1, 0, SEEK_END);
size1 = ftell(f1);
fseek(f1, 0, SEEK_SET);
fseek(f2, 0, SEEK_END);
size2 = ftell(f2);
fseek(f2, 0, SEEK_SET);
if (size1 != size2) {
fclose(f1);
fclose(f2);
return FALSE;
}
buf1 = ms_malloc(size1);
buf2 = ms_malloc(size2);
if (fread(buf1, size1, 1, f1)!=size1){
ms_error("fread() error");
}
if (fread(buf2, size2, 1, f2)!=size2){
ms_error("fread() error");
}
fclose(f1);
fclose(f2);
res = (memcmp(buf1, buf2, size1) == 0) ? TRUE : FALSE;
ms_free(buf1);
ms_free(buf2);
return res;
}
static void file_transfer_message(void) {
int i;
char* to;
LinphoneChatRoom* chat_room;
LinphoneChatMessage* message;
LinphoneChatMessageCbs *cbs;
LinphoneContent* content;
const char* big_file_content="big file"; /* setting dummy file content to something */
FILE *file_to_send = NULL;
size_t file_size;
char *send_filepath = ms_strdup_printf("%s/images/nowebcamCIF.jpg", liblinphone_tester_file_prefix);
char *receive_filepath = ms_strdup_printf("%s/receive_file.dump", liblinphone_tester_writable_dir_prefix);
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
reset_counters(&marie->stat);
reset_counters(&pauline->stat);
for (i=0;i<sizeof(big_file);i+=strlen(big_file_content))
memcpy(big_file+i, big_file_content, strlen(big_file_content));
big_file[0]=*"S";
big_file[sizeof(big_file)-1]=*"E";
file_to_send = fopen(send_filepath, "rb");
fseek(file_to_send, 0, SEEK_END);
file_size = ftell(file_to_send);
fseek(file_to_send, 0, SEEK_SET);
/* Globally configure an http file transfer server. */
linphone_core_set_file_transfer_server(pauline->lc,"https://www.linphone.org:444/lft.php");
@ -430,11 +470,12 @@ static void file_transfer_message(void) {
ms_free(to);
/* create a file transfer message */
content = linphone_core_create_content(pauline->lc);
linphone_content_set_type(content,"text");
linphone_content_set_subtype(content,"plain");
linphone_content_set_size(content,sizeof(big_file)); /*total size to be transfered*/
linphone_content_set_name(content,"bigfile.txt");
linphone_content_set_type(content,"image");
linphone_content_set_subtype(content,"jpeg");
linphone_content_set_size(content,file_size); /*total size to be transfered*/
linphone_content_set_name(content,"nowebcamCIF.jpg");
message = linphone_chat_room_create_file_transfer_message(chat_room, content);
linphone_chat_message_set_user_data(message, file_to_send);
cbs = linphone_chat_message_get_callbacks(message);
{
int dummy=0;
@ -443,8 +484,10 @@ static void file_transfer_message(void) {
reset_counters(&pauline->stat);
}
linphone_chat_message_cbs_set_msg_state_changed(cbs,liblinphone_tester_chat_message_msg_state_changed);
linphone_chat_message_cbs_set_file_transfer_send(cbs, file_transfer_send);
linphone_chat_room_send_chat_message(chat_room,message);
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceivedWithFile,1));
fclose(file_to_send);
if (marie->stat.last_received_chat_message ) {
cbs = linphone_chat_message_get_callbacks(marie->stat.last_received_chat_message);
linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed);
@ -456,10 +499,13 @@ static void file_transfer_message(void) {
CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1);
CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageDelivered,1);
CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageExtBodyReceived,1);
CU_ASSERT_TRUE(compare_files(send_filepath, receive_filepath));
linphone_content_unref(content);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
ms_free(send_filepath);
ms_free(receive_filepath);
}
/* same than previous but with a 160 characters file */
@ -505,6 +551,7 @@ static void small_file_transfer_message(void) {
}
cbs = linphone_chat_message_get_callbacks(message);
linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed);
linphone_chat_message_cbs_set_file_transfer_send(cbs, memory_file_transfer_send);
linphone_chat_room_send_chat_message(chat_room,message);
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceivedWithFile,1));
if (marie->stat.last_received_chat_message ) {
@ -566,6 +613,7 @@ static void file_transfer_message_io_error_upload(void) {
}
cbs = linphone_chat_message_get_callbacks(message);
linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed);
linphone_chat_message_cbs_set_file_transfer_send(cbs, memory_file_transfer_send);
linphone_chat_message_cbs_set_file_transfer_progress_indication(cbs, file_transfer_progress_indication);
linphone_chat_room_send_chat_message(chat_room,message);
@ -696,6 +744,7 @@ static void file_transfer_message_upload_cancelled(void) {
}
cbs = linphone_chat_message_get_callbacks(message);
linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed);
linphone_chat_message_cbs_set_file_transfer_send(cbs, memory_file_transfer_send);
linphone_chat_message_cbs_set_file_transfer_progress_indication(cbs, file_transfer_progress_indication);
linphone_chat_room_send_chat_message(chat_room,message);

View file

@ -336,7 +336,7 @@ static void presence_information(void) {
}
/* Presence timestamp. */
current_timestamp = time(NULL);
current_timestamp = ms_time(NULL);
presence = linphone_presence_model_new_with_activity(LinphonePresenceActivityShopping, NULL);
linphone_core_set_presence_model(pauline->lc, presence);
wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePresenceActivityShopping,1);

View file

@ -132,9 +132,13 @@ static void linphone_lpconfig_from_file_zerolen_value(){
char* rc_path = ms_strdup_printf("%s/rcfiles/%s", liblinphone_tester_file_prefix, zero_rc_file);
LpConfig* conf;
conf = lp_config_new(rc_path);
/* not using lp_config_new() because it expects a readable file, and iOS (for instance)
stores the app bundle in read-only */
conf = lp_config_new_with_factory(NULL, rc_path);
CU_ASSERT_STRING_EQUAL(lp_config_get_string(conf,"test","zero_len","LOL"),"LOL");
// non_zero_len=test -> should return test
CU_ASSERT_STRING_EQUAL(lp_config_get_string(conf,"test","non_zero_len",""),"test");
lp_config_set_string(conf, "test", "non_zero_len", ""); /* should remove "non_zero_len" */

Binary file not shown.

View file

@ -18,6 +18,7 @@
#include <stdio.h>
#include "CUnit/TestRun.h"
#include "CUnit/Automated.h"
#include "linphonecore.h"
#include "private.h"
#include "liblinphone_tester.h"
@ -42,6 +43,9 @@ int liblinphone_tester_use_log_file=0;
static int liblinphone_tester_keep_accounts_flag = 0;
static int manager_count = 0;
static const char* liblinphone_tester_xml_file = NULL;
static int liblinphone_tester_xml_enabled = FALSE;
#if WINAPI_FAMILY_PHONE_APP
const char *liblinphone_tester_file_prefix="Assets";
#elif defined(__QNX__)
@ -263,18 +267,26 @@ LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_f
manager_count++;
#if TARGET_OS_IPHONE
linphone_core_set_playback_device( mgr->lc, "AU: Audio Unit Tester");
linphone_core_set_capture_device( mgr->lc, "AU: Audio Unit Tester");
linphone_core_set_ringer_device( mgr->lc, "AQ: Audio Queue Device");
linphone_core_set_ringback(mgr->lc, NULL);
if( manager_count >= 2){
ms_message("Manager for '%s' using files", rc_file ? rc_file : "--");
linphone_core_use_files(mgr->lc, TRUE);
}
#endif
if (proxy_count)
wait_for_until(mgr->lc,NULL,&mgr->stat.number_of_LinphoneRegistrationOk,proxy_count,5000*proxy_count);
if( manager_count >= 2){
char hellopath[512];
ms_message("Manager for '%s' using files", rc_file ? rc_file : "--");
linphone_core_use_files(mgr->lc, TRUE);
snprintf(hellopath,sizeof(hellopath), "%s/sounds/hello8000.wav", liblinphone_tester_file_prefix);
linphone_core_set_play_file(mgr->lc,hellopath);
}
if (proxy_count){
#define REGISTER_TIMEOUT 20 /* seconds */
int success = wait_for_until(mgr->lc,NULL,&mgr->stat.number_of_LinphoneRegistrationOk,
proxy_count,(REGISTER_TIMEOUT * 1000 * proxy_count));
if( !success ){
ms_error("Did not register after %d seconds for %d proxies", REGISTER_TIMEOUT, proxy_count);
}
}
CU_ASSERT_EQUAL(mgr->stat.number_of_LinphoneRegistrationOk,proxy_count);
enable_codec(mgr->lc,"PCMU",8000);
@ -502,49 +514,57 @@ int liblinphone_tester_run_tests(const char *suite_name, const char *test_name)
CU_set_suite_start_handler(test_suite_start_message_handler);
if( liblinphone_tester_xml_file != NULL ){
CU_set_output_filename(liblinphone_tester_xml_file);
}
if( liblinphone_tester_xml_enabled != 0 ){
CU_automated_run_tests();
} else {
#if !HAVE_CU_GET_SUITE
if( suite_name ){
ms_warning("Tester compiled without CU_get_suite() function, running all tests instead of suite '%s'\n", suite_name);
}
#else
if (suite_name){
CU_pSuite suite;
suite=CU_get_suite(suite_name);
if (!suite) {
ms_error("Could not find suite '%s'. Available suites are:", suite_name);
liblinphone_tester_list_suites();
return -1;
} else if (test_name) {
CU_pTest test=CU_get_test_by_name(test_name, suite);
if (!test) {
ms_error("Could not find test '%s' in suite '%s'. Available tests are:", test_name, suite_name);
// do not use suite_name here, since this method is case sentisitive
liblinphone_tester_list_suite_tests(suite->pName);
return -2;
} else {
CU_ErrorCode err= CU_run_test(suite, test);
if (err != CUE_SUCCESS) ms_error("CU_basic_run_test error %d", err);
}
} else {
CU_run_suite(suite);
if( suite_name ){
ms_warning("Tester compiled without CU_get_suite() function, running all tests instead of suite '%s'\n", suite_name);
}
}
else
#endif
{
#if HAVE_CU_CURSES
if (curses) {
/* Run tests using the CUnit curses interface */
CU_curses_run_tests();
#else
if (suite_name){
CU_pSuite suite;
suite=CU_get_suite(suite_name);
if (!suite) {
ms_error("Could not find suite '%s'. Available suites are:", suite_name);
liblinphone_tester_list_suites();
return -1;
} else if (test_name) {
CU_pTest test=CU_get_test_by_name(test_name, suite);
if (!test) {
ms_error("Could not find test '%s' in suite '%s'. Available tests are:", test_name, suite_name);
// do not use suite_name here, since this method is case sentisitive
liblinphone_tester_list_suite_tests(suite->pName);
return -2;
} else {
CU_ErrorCode err= CU_run_test(suite, test);
if (err != CUE_SUCCESS) ms_error("CU_basic_run_test error %d", err);
}
} else {
CU_run_suite(suite);
}
}
else
#endif
{
/* Run all tests using the CUnit Basic interface */
CU_run_all_tests();
#if HAVE_CU_CURSES
if (curses) {
/* Run tests using the CUnit curses interface */
CU_curses_run_tests();
}
else
#endif
{
/* Run all tests using the CUnit Basic interface */
CU_run_all_tests();
}
}
}
}
ret=CU_get_number_of_tests_failed()!=0;
/* Redisplay list of failed tests on end */
@ -603,4 +623,18 @@ void liblinphone_tester_clear_accounts(void){
account_manager_destroy();
}
void liblinphone_tester_enable_xml( bool_t enable ){
liblinphone_tester_xml_enabled = enable;
}
void liblinphone_tester_set_xml_output(const char *xml_path ) {
liblinphone_tester_xml_file = xml_path;
}
const char* liblinphone_tester_get_xml_output( void ) {
return liblinphone_tester_xml_file;
}

View file

@ -433,9 +433,16 @@ class Project:
if pos == -1:
return None
returntype = definition[0:pos].strip()
if returntype != "void":
return None
returnarg = CArgument(returntype, enums = self.enums, structs = self.__structs)
returndesc = node.find("./detaileddescription/para/simplesect[@kind='return']")
if returndesc is not None:
if returnarg.ctype == 'MSList':
n = returndesc.find('.//mslist')
if n is not None:
returnarg.containedType = n.text
returnarg.description = self.__cleanDescription(returndesc)
elif returnarg.completeType != 'void':
missingDocWarning += "\tReturn value is not documented\n"
definition = definition[pos + 2 :]
pos = string.find(definition, "(")
definition = definition[pos + 1 : -1]

View file

@ -23,7 +23,7 @@ import sys
import xml.etree.ElementTree as ET
sys.path.append(os.path.realpath(__file__))
from apixml2python.linphone import LinphoneModule, HandWrittenClassMethod, HandWrittenInstanceMethod, HandWrittenProperty
from apixml2python.linphone import LinphoneModule, HandWrittenClassMethod, HandWrittenInstanceMethod, HandWrittenDeallocMethod, HandWrittenProperty
blacklisted_classes = [
@ -71,12 +71,16 @@ blacklisted_functions = [
'lp_config_section_to_dict' # missing LinphoneDictionary
]
hand_written_functions = [
HandWrittenInstanceMethod('ChatRoom', 'send_message2', 'linphone_chat_room_send_message2'),
HandWrittenProperty('Content', 'buffer', 'linphone_content_get_buffer', 'linphone_content_set_buffer'),
HandWrittenProperty('Core', 'sound_devices', 'linphone_core_get_sound_devices', None),
HandWrittenProperty('Core', 'video_devices', 'linphone_core_get_video_devices', None),
HandWrittenClassMethod('Core', 'new', 'linphone_core_new'),
HandWrittenClassMethod('Core', 'new_with_config', 'linphone_core_new_with_config')
HandWrittenClassMethod('Buffer', 'new_from_data', 'linphone_buffer_new_from_data', "Create a new LinphoneBuffer object from existing data.\n\n:param data: The initial data to store in the LinphoneBuffer.\n:type data: ByteArray\n:returns: A new LinphoneBuffer object.\n:rtype: linphone.Buffer"),
HandWrittenProperty('Buffer', 'content', 'linphone_buffer_get_content', 'linphone_buffer_set_content', "[ByteArray] Set the content of the data buffer."),
HandWrittenProperty('Content', 'buffer', 'linphone_content_get_buffer', 'linphone_content_set_buffer', "[ByteArray] Set the content data buffer."),
HandWrittenProperty('Core', 'sip_transports', 'linphone_core_get_sip_transports', 'linphone_core_set_sip_transports', "[:py:class:`linphone.SipTransports`] Sets the ports to be used for each transport. A zero value port for a given transport means the transport is not used. A value of LC_SIP_TRANSPORT_RANDOM (-1) means the port is to be chosen randomly by the system."),
HandWrittenProperty('Core', 'sip_transports_used', 'linphone_core_get_sip_transports_used', None, "[:py:class:`linphone.SipTransports`] Retrieves the real port number assigned for each sip transport (udp, tcp, tls). A zero value means that the transport is not activated. If LC_SIP_TRANSPORT_RANDOM was passed to :py:attr:`linphone.Core.sip_transports`, the random port choosed by the system is returned."),
HandWrittenProperty('Core', 'sound_devices', 'linphone_core_get_sound_devices', None, "[list of string] Get the available sound devices."),
HandWrittenProperty('Core', 'video_devices', 'linphone_core_get_video_devices', None, "[list of string] Get the available video capture devices."),
HandWrittenClassMethod('Core', 'new', 'linphone_core_new', "Instantiate a LinphoneCore object.\n\n:param vtable: The callbacks.\n:type vtable: dictionary\n:param configPath: A path to a config file. If it does not exists it will be created. The config file is used to store all settings, call logs, friends, proxies... so that all these settings become persistent over the life of the LinphoneCore object. It is allowed to set to None. In that case LinphoneCore will not store any settings.\n:type configPath: string\n:param factoryConfigPath: A path to a read-only config file that can be used to store hard-coded preference such as proxy settings or internal preferences. The settings in this factory file always override the one in the normal config file. It is OPTIONAL, use None if unneeded.\n:type factoryConfigPath: string\n:rtype: linphone.Core"),
HandWrittenClassMethod('Core', 'new_with_config', 'linphone_core_new_with_config', "Instantiate a LinphoneCore object from a LpConfig.\n\n:param vtable: The callbacks.\n:type vtable: dictionary\n:param config: A LpConfig object holding the configuration of the LinphoneCore to be instantiated.\n:rtype: linphone.Core"),
HandWrittenDeallocMethod('Core', 'linphone_core_destroy')
]
def generate(apixmlfile, outputfile):

View file

@ -1,3 +1,7 @@
static PyObject * pylinphone_Core_get_sip_transports(PyObject *self, void *closure);
static int pylinphone_Core_set_sip_transports(PyObject *self, PyObject *value, void *closure);
static void pylinphone_Core_dealloc(PyObject *self);
static PyObject * pylinphone_Core_get_sip_transports_used(PyObject *self, void *closure);
static PyObject * pylinphone_Core_get_sound_devices(PyObject *self, void *closure);
static PyObject * pylinphone_Core_get_video_devices(PyObject *self, void *closure);
@ -25,5 +29,8 @@ PyObject * PyLinphoneSipTransports_FromLCSipTransports(LCSipTransports lcst);
time_t PyDateTime_As_time_t(PyObject *obj);
PyObject * PyDateTime_From_time_t(time_t t);
static PyObject * pylinphone_Buffer_get_content(PyObject *self, void *closure);
static int pylinphone_Buffer_set_content(PyObject *self, PyObject *value, void *closure);
static PyObject * pylinphone_Content_get_buffer(PyObject *self, void *closure);
static int pylinphone_Content_set_buffer(PyObject *self, PyObject *value, void *closure);

View file

@ -128,6 +128,75 @@ static PyObject * pylinphone_module_method_set_log_handler(PyObject *self, PyObj
}
static PyObject * pylinphone_Core_get_sip_transports(PyObject *self, void *closure) {
PyObject *pytr;
LCSipTransports tr = { 0 };
LinphoneCore *native_ptr = pylinphone_Core_get_native_ptr(self);
if (native_ptr == NULL) {
PyErr_SetString(PyExc_TypeError, "Invalid linphone.Core instance");
return NULL;
}
pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p [%p])", __FUNCTION__, self, native_ptr);
linphone_core_get_sip_transports(native_ptr, &tr);
pylinphone_dispatch_messages();
pytr = PyLinphoneSipTransports_FromLCSipTransports(tr);
pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> %p", __FUNCTION__, pytr);
return pytr;
}
static int pylinphone_Core_set_sip_transports(PyObject *self, PyObject *value, void *closure) {
LinphoneCore *native_ptr;
PyObject * _tr_config;
const LCSipTransports * _tr_config_native_obj;
native_ptr = pylinphone_Core_get_native_ptr(self);
if (native_ptr == NULL) {
PyErr_SetString(PyExc_TypeError, "Invalid linphone.Core instance");
return -1;
}
if (value == NULL) {
PyErr_SetString(PyExc_TypeError, "Cannot delete the 'sip_transports' attribute.");
return -1;
}
if (!PyLinphoneSipTransports_Check(value)) {
PyErr_SetString(PyExc_TypeError, "The 'sip_transports' attribute value must be a linphone.SipTransports.");
return -1;
}
_tr_config = value;
_tr_config_native_obj = PyLinphoneSipTransports_AsLCSipTransports(value);
pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p [%p], %p [%p])", __FUNCTION__, self, native_ptr, _tr_config, _tr_config_native_obj);
linphone_core_set_sip_transports(native_ptr, _tr_config_native_obj);
pylinphone_dispatch_messages();
pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> 0", __FUNCTION__);
return 0;
}
static PyObject * pylinphone_Core_get_sip_transports_used(PyObject *self, void *closure) {
PyObject *pytr;
LCSipTransports tr = { 0 };
LinphoneCore *native_ptr = pylinphone_Core_get_native_ptr(self);
if (native_ptr == NULL) {
PyErr_SetString(PyExc_TypeError, "Invalid linphone.Core instance");
return NULL;
}
pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p [%p])", __FUNCTION__, self, native_ptr);
linphone_core_get_sip_transports_used(native_ptr, &tr);
pylinphone_dispatch_messages();
pytr = PyLinphoneSipTransports_FromLCSipTransports(tr);
pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> %p", __FUNCTION__, pytr);
return pytr;
}
static PyObject * pylinphone_Core_get_sound_devices(PyObject *self, void *closure) {
PyObject *_list;
const char **_devices;
@ -178,6 +247,13 @@ static PyObject * pylinphone_Core_get_video_devices(PyObject *self, void *closur
return _list;
}
static void pylinphone_init_ms2_plugins(void) {
ms_init(); // Initialize mediastreamer2 before loading the plugins
#ifdef ENABLE_OPENH264
libmsopenh264_init();
#endif
}
static PyObject * pylinphone_Core_class_method_new(PyObject *cls, PyObject *args) {
LinphoneCore * cresult;
pylinphone_CoreObject *self;
@ -206,6 +282,7 @@ static PyObject * pylinphone_Core_class_method_new(PyObject *cls, PyObject *args
{{/core_events}}
pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p, \"%s\", \"%s\")", __FUNCTION__, _vtable_dict, _config_path, _factory_config_path);
pylinphone_init_ms2_plugins();
cresult = linphone_core_new(&_vtable, _config_path, _factory_config_path, self);
self->native_ptr = cresult;
@ -248,6 +325,7 @@ static PyObject * pylinphone_Core_class_method_new_with_config(PyObject *cls, Py
{{/core_events}}
pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p [%p])", __FUNCTION__, _config, _config_native_ptr);
pylinphone_init_ms2_plugins();
cresult = linphone_core_new_with_config(&_vtable, _config_native_ptr, self);
self->native_ptr = cresult;
@ -258,64 +336,22 @@ static PyObject * pylinphone_Core_class_method_new_with_config(PyObject *cls, Py
return pyret;
}
static void pylinphone_Core_dealloc(PyObject *self) {
LinphoneCore * native_ptr = pylinphone_Core_get_native_ptr(self);
if (Py_REFCNT(self) < 0) return;
pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p [%p])", __FUNCTION__, self, native_ptr);
if (native_ptr != NULL) {
linphone_core_destroy(native_ptr);
ms_exit(); // De-initialize mediastreamer
}
static void pylinphone_ChatRoom_callback_chat_message_state_changed(LinphoneChatMessage *msg, LinphoneChatMessageState state, void *ud) {
PyGILState_STATE pygil_state;
PyObject *pycm = NULL;
PyObject *_dict = (PyObject *)ud;
PyObject *_cb = PyDict_GetItemString(_dict, "callback");
PyObject *_ud = PyDict_GetItemString(_dict, "user_data");
pygil_state = PyGILState_Ensure();
pycm = pylinphone_ChatMessage_from_native_ptr(&pylinphone_ChatMessageType, msg);
pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p, %p [%p], %d, %p)", __FUNCTION__, pycm, msg, state, ud);
if ((_cb != NULL) && PyCallable_Check(_cb)) {
PyObject *args = Py_BuildValue("OiO", pycm, state, _ud);
if (PyEval_CallObject(_cb, args) == NULL) {
PyErr_Print();
}
Py_DECREF(args);
}
pylinphone_trace(-1, "[PYLINPHONE] <<< %s", __FUNCTION__);
PyGILState_Release(pygil_state);
}
static PyObject * pylinphone_ChatRoom_instance_method_send_message2(PyObject *self, PyObject *args) {
PyObject *_chat_message;
PyObject *_dict;
PyObject *_cb;
PyObject *_ud;
LinphoneChatMessage * _chat_message_native_ptr;
LinphoneChatRoom *native_ptr = pylinphone_ChatRoom_get_native_ptr(self);
if (native_ptr == NULL) {
PyErr_SetString(PyExc_TypeError, "Invalid linphone.ChatRoom instance");
return NULL;
}
if (!PyArg_ParseTuple(args, "OOO", &_chat_message, &_cb, &_ud)) {
return NULL;
}
if (!PyObject_IsInstance(_chat_message, (PyObject *)&pylinphone_ChatMessageType)) {
PyErr_SetString(PyExc_TypeError, "The msg argument must be a linphone.ChatMessage");
return NULL;
}
if ((_cb != Py_None) && !PyCallable_Check(_cb)) {
PyErr_SetString(PyExc_TypeError, "The status_cb argument must be a callable");
return NULL;
}
if ((_chat_message_native_ptr = pylinphone_ChatMessage_get_native_ptr(_chat_message)) == NULL) {
return NULL;
}
_dict = PyDict_New();
PyDict_SetItemString(_dict, "callback", _cb);
PyDict_SetItemString(_dict, "user_data", _ud);
pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p [%p], %p [%p], %p, %p)", __FUNCTION__, self, native_ptr, _chat_message, _chat_message_native_ptr, _cb, _ud);
linphone_chat_room_send_message2(native_ptr, _chat_message_native_ptr, pylinphone_ChatRoom_callback_chat_message_state_changed, _dict);
pylinphone_dispatch_messages();
Py_XDECREF(((pylinphone_CoreObject *)self)->user_data);
Py_XDECREF(((pylinphone_CoreObject *)self)->vtable_dict);
pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> None", __FUNCTION__);
Py_RETURN_NONE;
self->ob_type->tp_free(self);
pylinphone_trace(-1, "[PYLINPHONE] <<< %s", __FUNCTION__);
}
@ -647,6 +683,91 @@ static PyMethodDef pylinphone_PayloadTypeType_ModuleMethods[] = {
};
static PyObject * pylinphone_Buffer_class_method_new_from_data(PyObject *cls, PyObject *args) {
LinphoneBuffer * cresult;
pylinphone_BufferObject *self;
PyObject * pyret;
PyObject * _byte_array;
if (!PyArg_ParseTuple(args, "O", &_byte_array)) {
return NULL;
}
if (!PyByteArray_Check(_byte_array)) {
PyErr_SetString(PyExc_TypeError, "The argument must be a ByteArray");
return NULL;
}
self = (pylinphone_BufferObject *)PyObject_CallObject((PyObject *) &pylinphone_BufferType, NULL);
if (self == NULL) {
return NULL;
}
pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p)", __FUNCTION__, _byte_array);
cresult = linphone_buffer_new_from_data((uint8_t *)PyByteArray_AsString(_byte_array), PyByteArray_Size(_byte_array));
self->native_ptr = cresult;
pyret = Py_BuildValue("O", self);
pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> %p", __FUNCTION__, pyret);
Py_DECREF(self);
return pyret;
}
static PyObject * pylinphone_Buffer_get_content(PyObject *self, void *closure) {
const uint8_t * ccontent;
size_t csize;
PyObject * pyresult;
PyObject * pyret;
const char *pyret_fmt;
const LinphoneBuffer *native_ptr;
native_ptr = pylinphone_Buffer_get_native_ptr(self);
if (native_ptr == NULL) {
PyErr_SetString(PyExc_TypeError, "Invalid linphone.Buffer instance");
return NULL;
}
pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p [%p])", __FUNCTION__, self, native_ptr);
ccontent = linphone_buffer_get_content(native_ptr);
csize = linphone_buffer_get_size(native_ptr);
pylinphone_dispatch_messages();
pyresult = PyByteArray_FromStringAndSize((const char *)ccontent, csize);
pyret = Py_BuildValue("O", pyresult);
pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> %p", __FUNCTION__, pyret);
return pyret;
}
static int pylinphone_Buffer_set_content(PyObject *self, PyObject *value, void *closure) {
LinphoneBuffer *native_ptr;
uint8_t * _content;
size_t _size;
LinphonePresenceModel * _presence_native_ptr = NULL;
native_ptr = pylinphone_Buffer_get_native_ptr(self);
if (native_ptr == NULL) {
PyErr_SetString(PyExc_TypeError, "Invalid linphone.Buffer instance");
return -1;
}
if (value == NULL) {
PyErr_SetString(PyExc_TypeError, "Cannot delete the 'content' attribute.");
return -1;
}
if ((value != Py_None) && !PyByteArray_Check(value)) {
PyErr_SetString(PyExc_TypeError, "The 'content' attribute value must be a ByteArray instance.");
return -1;
}
_content = (uint8_t *)PyByteArray_AsString(value);
_size = PyByteArray_Size(value);
pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p [%p], %p [%p])", __FUNCTION__, self, native_ptr, value, _content);
linphone_buffer_set_content(native_ptr, _content, _size);
pylinphone_dispatch_messages();
pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> 0", __FUNCTION__);
return 0;
}
static PyObject * pylinphone_Content_get_buffer(PyObject *self, void *closure) {
void * cbuffer;
size_t csize;

View file

@ -15,6 +15,7 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
import re
from sets import Set
import sys
@ -25,6 +26,18 @@ def strip_leading_linphone(s):
else:
return s
def remove_useless_enum_prefix(senum, svalue):
lenum = re.findall('[A-Z][^A-Z]*', senum)
lvalue = re.findall('[A-Z][^A-Z]*', svalue)
if len(lenum) == 0 or len(lvalue) == 0:
return svalue
if lenum[0] == lvalue[0]:
i = 0
while i < len(lenum) and lenum[i] == lvalue[i]:
i += 1
return ''.join(lvalue[i:])
return svalue
def is_callback(s):
return s.startswith('Linphone') and s.endswith('Cb')
@ -42,27 +55,32 @@ def compute_event_name(s, className):
class HandWrittenCode:
def __init__(self, _class, name, func_list):
def __init__(self, _class, name, func_list, doc = ''):
self._class = _class
self.name = name
self.func_list = func_list
self.doc = doc
class HandWrittenInstanceMethod(HandWrittenCode):
def __init__(self, _class, name, cfunction):
HandWrittenCode.__init__(self, _class, name, [cfunction])
def __init__(self, _class, name, cfunction, doc = ''):
HandWrittenCode.__init__(self, _class, name, [cfunction], doc)
class HandWrittenClassMethod(HandWrittenCode):
def __init__(self, _class, name, cfunction):
HandWrittenCode.__init__(self, _class, name, [cfunction])
def __init__(self, _class, name, cfunction, doc = ''):
HandWrittenCode.__init__(self, _class, name, [cfunction], doc)
class HandWrittenDeallocMethod(HandWrittenCode):
def __init__(self, _class, cfunction):
HandWrittenCode.__init__(self, _class, 'dealloc', [cfunction], '')
class HandWrittenProperty(HandWrittenCode):
def __init__(self, _class, name, getter_cfunction = None, setter_cfunction = None):
def __init__(self, _class, name, getter_cfunction = None, setter_cfunction = None, doc = ''):
func_list = []
if getter_cfunction is not None:
func_list.append(getter_cfunction)
if setter_cfunction is not None:
func_list.append(setter_cfunction)
HandWrittenCode.__init__(self, _class, name, func_list)
HandWrittenCode.__init__(self, _class, name, func_list, doc)
self.getter_cfunction = getter_cfunction
self.setter_cfunction = setter_cfunction
@ -74,8 +92,8 @@ class ArgumentType:
self.contained_type = contained_type
self.linphone_module = linphone_module
self.type_str = None
self.check_func = None
self.convert_func = None
self.check_condition = None
self.convert_code = None
self.convert_from_func = None
self.fmt_str = 'O'
self.cfmt_str = '%p'
@ -91,33 +109,33 @@ class ArgumentType:
if self.basic_type == 'char':
if '*' in splitted_type:
self.type_str = 'string'
self.check_func = 'PyString_Check'
self.convert_func = 'PyString_AsString'
self.check_condition = "!PyString_Check({arg_name})"
self.convert_code = "{result_name}{result_suffix} = {cast}PyString_AsString({arg_name});\n"
self.fmt_str = 'z'
self.cfmt_str = '\\"%s\\"'
else:
self.type_str = 'int'
self.check_func = 'PyInt_Check'
self.convert_func = 'PyInt_AsLong'
self.check_condition = "!PyInt_Check({arg_name}) && !PyLong_Check({arg_name})"
self.convert_code = "{result_name}{result_suffix} = {cast}PyInt_AsLong({arg_name});\n"
self.fmt_str = 'b'
self.cfmt_str = '%08x'
elif self.basic_type == 'int':
if 'unsigned' in splitted_type:
self.type_str = 'unsigned int'
self.check_func = 'PyInt_Check'
self.convert_func = 'PyInt_AsUnsignedLongMask'
self.check_condition = "!PyInt_Check({arg_name})"
self.convert_code = "{result_name}{result_suffix} = {cast}PyInt_AsUnsignedLongMask({arg_name});\n"
self.fmt_str = 'I'
self.cfmt_str = '%u'
else:
self.type_str = 'int'
self.check_func = 'PyInt_Check'
self.convert_func = 'PyInt_AS_LONG'
self.check_condition = "!PyInt_Check({arg_name})"
self.convert_code = "{result_name}{result_suffix} = {cast}PyInt_AS_LONG({arg_name});\n"
self.fmt_str = 'i'
self.cfmt_str = '%d'
elif self.basic_type in ['int8_t', 'int16_t' 'int32_t']:
self.type_str = 'int'
self.check_func = 'PyInt_Check'
self.convert_func = 'PyInt_AS_LONG'
self.check_condition = "!PyInt_Check({arg_name})"
self.convert_code = "{result_name}{result_suffix} = {cast}PyInt_AS_LONG({arg_name});\n"
if self.basic_type == 'int8_t':
self.fmt_str = 'c'
elif self.basic_type == 'int16_t':
@ -127,8 +145,8 @@ class ArgumentType:
self.cfmt_str = '%d'
elif self.basic_type in ['uint8_t', 'uint16_t', 'uint32_t']:
self.type_str = 'unsigned int'
self.check_func = 'PyInt_Check'
self.convert_func = 'PyInt_AsUnsignedLongMask'
self.check_condition = "!PyInt_Check({arg_name})"
self.convert_code = "{result_name}{result_suffix} = {cast}PyInt_AsUnsignedLongMask({arg_name});\n"
if self.basic_type == 'uint8_t':
self.fmt_str = 'b'
elif self.basic_type == 'uint16_t':
@ -138,66 +156,83 @@ class ArgumentType:
self.cfmt_str = '%u'
elif self.basic_type == 'int64_t':
self.type_str = '64bits int'
self.check_func = 'PyLong_Check'
self.convert_func = 'PyLong_AsLongLong'
self.check_condition = "!PyInt_Check({arg_name}) && !PyLong_Check({arg_name})"
self.convert_code = \
"""if (PyInt_Check({arg_name})) {result_name}{result_suffix} = {cast}(PY_LONG_LONG)PyInt_AsLong({arg_name});
else if (PyLong_Check({arg_name})) {result_name}{result_suffix} = {cast}PyLong_AsLongLong({arg_name});
"""
self.fmt_str = 'L'
self.cfmt_str = '%ld'
elif self.basic_type == 'uint64_t':
self.type_str = '64bits unsigned int'
self.check_func = 'PyLong_Check'
self.convert_func = 'PyLong_AsUnsignedLongLong'
self.check_condition = "!PyLong_Check({arg_name})"
self.convert_code = "{result_name}{result_suffix} = {cast}PyLong_AsUnsignedLongLong({arg_name});\n"
self.fmt_str = 'K'
self.cfmt_str = '%lu'
elif self.basic_type == 'size_t':
self.type_str = 'size_t'
self.check_func = 'PyInt_Check'
self.convert_func = 'PyInt_AsSsize_t'
self.type_str = 'int'
self.check_condition = "!PyInt_Check({arg_name}) && !PyLong_Check({arg_name})"
self.convert_code = \
"""if (PyInt_Check({arg_name})) {result_name}{result_suffix} = {cast}(size_t)PyInt_AsSsize_t({arg_name});
else if (PyLong_Check({arg_name})) {result_name}{result_suffix} = {cast}(size_t)PyLong_AsSsize_t({arg_name});
"""
self.fmt_str = 'n'
self.cfmt_str = '%lu'
elif self.basic_type in ['float', 'double']:
elif self.basic_type == 'float':
self.type_str = 'float'
self.check_func = 'PyFloat_Check'
self.convert_func = 'PyFloat_AsDouble'
if self.basic_type == 'float':
self.fmt_str = 'f'
elif self.basic_type == 'double':
self.fmt_str = 'd'
self.check_condition = "!PyFloat_Check({arg_name})"
self.convert_code = \
"""if (PyInt_Check({arg_name})) {result_name}{result_suffix} = {cast}(float)PyInt_AsLong({arg_name});
else if (PyLong_Check({arg_name})) {result_name}{result_suffix} = {cast}(float)PyLong_AsLong({arg_name});
else if (PyFloat_Check({arg_name})) {result_name}{result_suffix} = {cast}(float)PyFloat_AsDouble({arg_name});
"""
self.fmt_str = 'f'
self.cfmt_str = '%f'
elif self.basic_type == 'double':
self.type_str = 'float'
self.check_condition = "!PyFloat_Check({arg_name})"
self.convert_code = \
"""if (PyInt_Check({arg_name})) {result_name}{result_suffix} = {cast}(double)PyInt_AsLong({arg_name});
else if (PyLong_Check({arg_name})) {result_name}{result_suffix} = {cast}(double)PyLong_AsLong({arg_name});
else if (PyFloat_Check({arg_name})) {result_name}{result_suffix} = {cast}(double)PyFloat_AsDouble({arg_name});
"""
self.fmt_str = 'd'
self.cfmt_str = '%f'
elif self.basic_type == 'bool_t':
self.type_str = 'bool'
self.check_func = 'PyBool_Check'
self.convert_func = 'PyObject_IsTrue'
self.check_condition = "!PyBool_Check({arg_name})"
self.convert_code = "{result_name}{result_suffix} = {cast}PyObject_IsTrue({arg_name});\n"
self.convert_from_func = 'PyBool_FromLong'
self.fmt_str = 'O'
self.cfmt_str = '%p'
self.cnativefmt_str = '%u'
elif self.basic_type == 'time_t':
self.type_str = 'DateTime'
self.check_func = 'PyDateTime_Check'
self.convert_func = 'PyDateTime_As_time_t'
self.check_condition = "!PyDateTime_Check({arg_name})"
self.convert_code = "{result_name}{result_suffix} = {cast}PyDateTime_As_time_t({arg_name});\n"
self.convert_from_func = 'PyDateTime_From_time_t'
self.fmt_str = 'O'
self.cfmt_str = '%p'
self.cnativefmt_str = '%ld'
elif self.basic_type == 'MSList':
self.type_str = 'list of linphone.' + self.contained_type
self.check_func = 'PyList_Check'
self.convert_func = 'PyList_AsMSListOf' + self.contained_type
self.check_condition = "!PyList_Check({arg_name})"
self.convert_code = "{result_name}{result_suffix} = {cast}PyList_AsMSListOf" + self.contained_type + "({arg_name});\n"
self.convert_from_func = 'PyList_FromMSListOf' + self.contained_type
self.fmt_str = 'O'
self.cfmt_str = '%p'
elif self.basic_type == 'MSVideoSize':
self.type_str = 'linphone.VideoSize'
self.check_func = 'PyLinphoneVideoSize_Check'
self.convert_func = 'PyLinphoneVideoSize_AsMSVideoSize'
self.check_condition = "!PyLinphoneVideoSize_Check({arg_name})"
self.convert_code = "{result_name}{result_suffix} = {cast}PyLinphoneVideoSize_AsMSVideoSize({arg_name});\n"
self.convert_from_func = 'PyLinphoneVideoSize_FromMSVideoSize'
self.fmt_str = 'O'
self.cfmt_str = '%p'
self.cast_convert_func_result = False
elif self.basic_type == 'LCSipTransports':
self.type_str = 'linphone.SipTransports'
self.check_func = 'PyLinphoneSipTransports_Check'
self.convert_func = 'PyLinphoneSipTransports_AsLCSipTransports'
self.check_condition = "!PyLinphoneSipTransports_Check({arg_name})"
self.convert_code = "{result_name}{result_suffix} = {cast}PyLinphoneSipTransports_AsLCSipTransports({arg_name});\n"
self.convert_from_func = 'PyLinphoneSipTransports_FromLCSipTransports'
self.fmt_str = 'O'
self.cfmt_str = '%p'
@ -205,13 +240,13 @@ class ArgumentType:
else:
if strip_leading_linphone(self.basic_type) in self.linphone_module.enum_names:
self.type_str = 'int'
self.check_func = 'PyInt_Check'
self.convert_func = 'PyInt_AsLong'
self.check_condition = "!PyInt_Check({arg_name})"
self.convert_code = "{result_name}{result_suffix} = {cast}PyInt_AsLong({arg_name});\n"
self.fmt_str = 'i'
self.cfmt_str = '%d'
elif is_callback(self.complete_type):
self.type_str = 'callable'
self.check_func = 'PyCallable_Check'
self.check_condition = "!PyCallable_Check({arg_name})"
self.cnativefmt_str = None
elif '*' in splitted_type:
self.type_str = 'linphone.' + strip_leading_linphone(self.basic_type)
@ -238,24 +273,7 @@ class MethodDefinition:
self.method_type = 'instancemethod'
def format_local_variables_definition(self):
body = ''
if self.xml_method_return is not None:
self.return_type = self.xml_method_return.get('type')
self.return_complete_type = self.xml_method_return.get('completetype')
self.return_contained_type = self.xml_method_return.get('containedtype')
if is_callback(self.return_complete_type):
body += "\tPyObject * pyresult;\n"
body += "\tPyObject * pyret;\n"
argument_type = ArgumentType(self.return_type, self.return_complete_type, self.return_contained_type, self.linphone_module)
self.build_value_format = argument_type.fmt_str
elif self.return_complete_type != 'void':
body += "\t" + self.return_complete_type + " cresult;\n"
argument_type = ArgumentType(self.return_type, self.return_complete_type, self.return_contained_type, self.linphone_module)
self.build_value_format = argument_type.fmt_str
if self.build_value_format == 'O':
body += "\tPyObject * pyresult;\n"
body += "\tPyObject * pyret;\n"
body += "\tconst char *pyret_fmt;\n"
body = self.format_local_return_variables_definition()
if self.self_arg is not None:
body += "\t" + self.self_arg.get('completetype') + "native_ptr;\n"
for xml_method_arg in self.xml_method_args:
@ -270,7 +288,7 @@ class MethodDefinition:
elif argument_type.fmt_str == 'O' and argument_type.use_native_pointer:
body += "\tPyObject * " + arg_name + ";\n"
body += "\t" + arg_complete_type + " " + arg_name + "_native_ptr = NULL;\n"
elif argument_type.fmt_str == 'O' and argument_type.convert_func is not None:
elif argument_type.fmt_str == 'O' and argument_type.convert_code is not None:
body += "\tPyObject * " + arg_name + ";\n"
body += "\t" + arg_complete_type + " " + arg_name + "_native_obj;\n"
elif strip_leading_linphone(arg_complete_type) in self.linphone_module.enum_names:
@ -298,10 +316,8 @@ class MethodDefinition:
arg_complete_type = xml_method_arg.get('completetype')
arg_contained_type = xml_method_arg.get('containedtype')
argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self.linphone_module)
if argument_type.fmt_str == 'O' and argument_type.convert_func is not None:
args_conversion_code += \
""" {arg_name}_native_obj = {convert_func}({arg_name});
""".format(arg_name=arg_name, convert_func=argument_type.convert_func)
if argument_type.fmt_str == 'O' and argument_type.convert_code is not None:
args_conversion_code += argument_type.convert_code.format(result_name=arg_name, result_suffix='_native_obj', cast='', arg_name=arg_name)
return \
""" {class_native_ptr_check_code}
{parse_tuple_code}
@ -352,7 +368,7 @@ class MethodDefinition:
argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self.linphone_module)
if argument_type.fmt_str == 'O' and argument_type.use_native_pointer:
arg_names.append(arg_name + "_native_ptr")
elif argument_type.fmt_str == 'O' and argument_type.convert_func is not None:
elif argument_type.fmt_str == 'O' and argument_type.convert_code is not None:
arg_names.append(arg_name + "_native_obj")
else:
arg_names.append(arg_name)
@ -370,6 +386,7 @@ class MethodDefinition:
from_native_pointer_code = ''
convert_from_code = ''
build_value_code = ''
cfree_code = ''
result_variable = ''
if self.return_complete_type != 'void':
if self.build_value_format == 'O':
@ -388,16 +405,20 @@ class MethodDefinition:
result_variable = 'cresult'
if result_variable != '':
build_value_code = "pyret = Py_BuildValue(\"{fmt}\", {result_variable});".format(fmt=self.build_value_format, result_variable=result_variable)
if self.return_complete_type == 'char *':
cfree_code = 'ms_free(cresult);';
body = \
""" {c_function_call_code}
pylinphone_dispatch_messages();
{from_native_pointer_code}
{convert_from_code}
{build_value_code}
{cfree_code}
""".format(c_function_call_code=c_function_call_code,
from_native_pointer_code=from_native_pointer_code,
convert_from_code=convert_from_code,
build_value_code=build_value_code)
build_value_code=build_value_code,
cfree_code=cfree_code)
return body
def format_return_trace(self):
@ -444,11 +465,11 @@ class MethodDefinition:
""".format(arg_name=arg_name, arg_type=strip_leading_linphone(arg_type), type_str=argument_type.type_str)
else:
body += \
""" if (!{check_func}({arg_name})) {{
""" if ({check_condition}) {{
PyErr_SetString(PyExc_TypeError, "The '{arg_name}' argument must be a {type_str} instance.");
return NULL;
}}
""".format(arg_name=arg_name, check_func=argument_type.check_func, type_str=argument_type.type_str)
""".format(arg_name=arg_name, check_condition=argument_type.check_condition.format(arg_name=arg_name), type_str=argument_type.type_str)
if body != '':
body = body[1:] # Remove leading '\t'
return body
@ -473,6 +494,26 @@ class MethodDefinition:
body = body[1:] # Remove leading '\t'
return body
def format_local_return_variables_definition(self):
body = ''
if self.xml_method_return is not None:
self.return_type = self.xml_method_return.get('type')
self.return_complete_type = self.xml_method_return.get('completetype')
self.return_contained_type = self.xml_method_return.get('containedtype')
if is_callback(self.return_complete_type):
body += "\tPyObject * pyresult;\n"
body += "\tPyObject * pyret;\n"
argument_type = ArgumentType(self.return_type, self.return_complete_type, self.return_contained_type, self.linphone_module)
self.build_value_format = argument_type.fmt_str
elif self.return_complete_type != 'void':
body += "\t" + self.return_complete_type + " cresult;\n"
argument_type = ArgumentType(self.return_type, self.return_complete_type, self.return_contained_type, self.linphone_module)
self.build_value_format = argument_type.fmt_str
if self.build_value_format == 'O':
body += "\tPyObject * pyresult;\n"
body += "\tPyObject * pyret;\n"
return body
def parse_method_node(self):
if self.method_node is not None:
self.xml_method_return = self.method_node.find('./return')
@ -661,6 +702,12 @@ class DeallocMethodDefinition(MethodDefinition):
def format_return_result(self):
return ''
def format(self):
return \
"""static void pylinphone_{class_name}_dealloc(PyObject *self) {{
{method_body}
}}""".format(class_name=self.class_['class_name'], method_body=MethodDefinition.format(self))
class GetterMethodDefinition(MethodDefinition):
def __init__(self, linphone_module, class_, method_node = None):
MethodDefinition.__init__(self, linphone_module, class_, method_node)
@ -670,7 +717,7 @@ class SetterMethodDefinition(MethodDefinition):
MethodDefinition.__init__(self, linphone_module, class_, method_node)
def format_arguments_parsing(self):
if self.first_argument_type.check_func is None:
if self.first_argument_type.check_condition is None:
attribute_type_check_code = \
"""if ((value != Py_None) && !PyObject_IsInstance(value, (PyObject *)&pylinphone_{class_name}Type)) {{
PyErr_SetString(PyExc_TypeError, "The '{attribute_name}' attribute value must be a linphone.{class_name} instance.");
@ -682,11 +729,11 @@ class SetterMethodDefinition(MethodDefinition):
if self.first_argument_type.type_str == 'string':
checknotnone = "(value != Py_None) && "
attribute_type_check_code = \
"""if ({checknotnone}!{checkfunc}(value)) {{
"""if ({checknotnone}{check_condition}) {{
PyErr_SetString(PyExc_TypeError, "The '{attribute_name}' attribute value must be a {type_str}.");
return -1;
}}
""".format(checknotnone=checknotnone, checkfunc=self.first_argument_type.check_func, attribute_name=self.attribute_name, type_str=self.first_argument_type.type_str)
""".format(checknotnone=checknotnone, check_condition=self.first_argument_type.check_condition.format(arg_name='value'), attribute_name=self.attribute_name, type_str=self.first_argument_type.type_str)
attribute_conversion_code = ''
callback_setting_code = ''
if is_callback(self.first_argument_type.complete_type):
@ -695,18 +742,17 @@ class SetterMethodDefinition(MethodDefinition):
Py_INCREF(value);
((pylinphone_{class_name}Object *)self)->{callback_name} = value;
""".format(class_name=self.class_['class_name'], callback_name=compute_event_name(self.first_arg_complete_type, self.class_['class_name']))
if (self.first_argument_type.convert_func is None) or \
(self.first_argument_type.fmt_str == 'O' and self.first_argument_type.convert_func is not None):
if (self.first_argument_type.convert_code is None) or \
(self.first_argument_type.fmt_str == 'O' and self.first_argument_type.convert_code is not None):
attribute_conversion_code += "{arg_name} = value;\n".format(arg_name="_" + self.first_arg_name)
if self.first_argument_type.convert_func is not None:
if self.first_argument_type.convert_code is not None:
cast_code = ''
suffix = ''
if self.first_argument_type.cast_convert_func_result:
cast_code = "({arg_type})".format(arg_type=self.first_arg_complete_type)
if self.first_argument_type.fmt_str == 'O' and self.first_argument_type.convert_func is not None:
if self.first_argument_type.fmt_str == 'O' and self.first_argument_type.convert_code is not None:
suffix = '_native_obj'
attribute_conversion_code += "\t{arg_name}{suffix} = {cast_code}{convertfunc}(value);\n".format(
arg_name="_" + self.first_arg_name, suffix=suffix, cast_code=cast_code, convertfunc=self.first_argument_type.convert_func)
attribute_conversion_code += self.first_argument_type.convert_code.format(result_name="_" + self.first_arg_name, result_suffix=suffix, cast=cast_code, arg_name='value')
attribute_native_ptr_check_code = ''
if self.first_argument_type.use_native_pointer:
attribute_native_ptr_check_code = \
@ -743,7 +789,7 @@ class SetterMethodDefinition(MethodDefinition):
suffix = ''
if self.first_argument_type.fmt_str == 'O' and self.first_argument_type.use_native_pointer:
suffix = '_native_ptr'
elif self.first_argument_type.fmt_str == 'O' and self.first_argument_type.convert_func is not None:
elif self.first_argument_type.fmt_str == 'O' and self.first_argument_type.convert_code is not None:
suffix = '_native_obj'
return \
""" {method_name}(native_ptr, {arg_name}{suffix});
@ -778,6 +824,7 @@ class EventCallbackMethodDefinition(MethodDefinition):
nocallbacks_class_name = class_name
if class_name.endswith('Cbs'):
nocallbacks_class_name = class_name[:-3]
returnvars = self.format_local_return_variables_definition()
common = \
""" pylinphone_{class_name}Object *pyself = (pylinphone_{class_name}Object *){function_prefix}get_user_data(self);
PyObject *func;
@ -796,21 +843,26 @@ class EventCallbackMethodDefinition(MethodDefinition):
argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self.linphone_module)
if argument_type.fmt_str == 'O':
specific += "\tPyObject * py" + arg_name + " = NULL;\n"
return "{common}\n{specific}".format(common=common, specific=specific)
return "{returnvars}\n{common}\n{specific}".format(returnvars=returnvars, common=common, specific=specific)
def format_arguments_parsing(self):
return_str = ''
if self.return_complete_type != 'void':
argument_type = ArgumentType(self.return_type, self.return_complete_type, self.return_contained_type, self.linphone_module)
if argument_type.fmt_str == 'O':
return_str = 'NULL'
if self.class_['event_class'] == 'Core':
return \
""" if (Py_REFCNT(pyself) <= 0) return;
""" if (Py_REFCNT(pyself) <= 0) return {return_str};
func = PyDict_GetItemString(pyself->vtable_dict, "{name}");
pygil_state = PyGILState_Ensure();
""".format(name=self.class_['event_name'])
""".format(name=self.class_['event_name'], return_str=return_str)
else:
return \
""" if (Py_REFCNT(pyself) <= 0) return;
""" if (Py_REFCNT(pyself) <= 0) return {return_str};
func = pycbs->{event_name};
pygil_state = PyGILState_Ensure();
""".format(event_name=self.class_['event_name'])
""".format(event_name=self.class_['event_name'], return_str=return_str)
def format_enter_trace(self):
fmt = '%p'
@ -832,6 +884,7 @@ class EventCallbackMethodDefinition(MethodDefinition):
def format_c_function_call(self):
create_python_objects_code = ''
convert_python_result_code = ''
fmt = 'O'
args = ['pyself']
for xml_method_arg in self.xml_method_args:
@ -852,22 +905,52 @@ class EventCallbackMethodDefinition(MethodDefinition):
type_class = self.find_class_definition(arg_type)
create_python_objects_code += "\t\tpy{name} = pylinphone_{arg_type}_from_native_ptr(&pylinphone_{arg_type}Type, {name});\n".format(name=arg_name, arg_type=strip_leading_linphone(arg_type))
args=', '.join(args)
if self.return_complete_type != 'void':
argument_type = ArgumentType(self.return_type, self.return_complete_type, self.return_contained_type, self.linphone_module)
if argument_type.fmt_str == 'O':
convert_python_result_code = \
""" if ((pyresult != Py_None) && !PyObject_IsInstance(pyresult, (PyObject *)&pylinphone_{class_name}Type)) {{
PyErr_SetString(PyExc_TypeError, "The return value must be a linphone.{class_name} instance.");
return NULL;
}}
if ((cresult = pylinphone_{class_name}_get_native_ptr(pyresult)) == NULL) {{
return NULL;
}}
""".format(class_name=strip_leading_linphone(self.return_type))
else:
convert_python_result_code = '\t\t' + argument_type.convert_code.format(result_name='cresult', result_suffix='', cast='', arg_name='pyresult')
return \
""" if ((func != NULL) && PyCallable_Check(func)) {{
{create_python_objects_code}
args = Py_BuildValue("{fmt}", {args});
if (PyEval_CallObject(func, args) == NULL) {{
pyresult = PyEval_CallObject(func, args);
if (pyresult == NULL) {{
PyErr_Print();
}}
Py_DECREF(args);
{convert_python_result_code}
}}
""".format(fmt=fmt, args=args, create_python_objects_code=create_python_objects_code)
""".format(fmt=fmt, args=args, create_python_objects_code=create_python_objects_code, convert_python_result_code=convert_python_result_code)
def format_return_trace(self):
return "\tpylinphone_trace(-1, \"[PYLINPHONE] <<< %s\", __FUNCTION__);\n"
def format_return_result(self):
return '\tPyGILState_Release(pygil_state);'
s = '\tPyGILState_Release(pygil_state);'
if self.return_complete_type != 'void':
s += '\n\treturn cresult;'
return s
def format_local_return_variables_definition(self):
body = "\tPyObject * pyresult;"
if self.xml_method_return is not None:
self.return_type = self.xml_method_return.get('type')
self.return_complete_type = self.xml_method_return.get('completetype')
self.return_contained_type = self.xml_method_return.get('containedtype')
if self.return_complete_type != 'void':
body += "\n\t" + self.return_complete_type + " cresult;"
return body
def format(self):
body = MethodDefinition.format(self)
@ -882,10 +965,10 @@ class EventCallbackMethodDefinition(MethodDefinition):
arg_complete_type = xml_method_arg.get('completetype')
arguments.append(arg_complete_type + ' ' + arg_name)
definition = \
"""static void pylinphone_{class_name}_callback_{event_name}({arguments}) {{
"""static {returntype} pylinphone_{class_name}_callback_{event_name}({arguments}) {{
{body}
}}
""".format(class_name=class_name, event_name=self.class_['event_name'], arguments=', '.join(arguments), body=body)
""".format(returntype=self.return_complete_type, class_name=class_name, event_name=self.class_['event_name'], arguments=', '.join(arguments), body=body)
return definition
@ -896,6 +979,7 @@ class LinphoneModule(object):
self.mslist_types = Set([])
self.enums = []
self.enum_names = []
self.cfunction2methodmap = {}
hand_written_functions = []
for hand_written_code in hand_written_codes:
hand_written_functions += hand_written_code.func_list
@ -906,18 +990,35 @@ class LinphoneModule(object):
e = {}
e['enum_name'] = strip_leading_linphone(xml_enum.get('name'))
e['enum_doc'] = self.__format_doc_content(xml_enum.find('briefdescription'), xml_enum.find('detaileddescription'))
e['enum_doc'] += "\n\nValues:\n"
e['enum_doc'] = self.__replace_doc_special_chars(e['enum_doc'])
e['enum_doc'] += """
.. csv-table::
:delim: |
:widths: 30, 70
:header: Value,Description
"""
e['enum_values'] = []
e['enum_deprecated_values'] = []
xml_enum_values = xml_enum.findall("./values/value")
for xml_enum_value in xml_enum_values:
if xml_enum_value.get('deprecated') == 'true':
continue
v = {}
v['enum_value_cname'] = xml_enum_value.get('name')
v['enum_value_name'] = strip_leading_linphone(v['enum_value_cname'])
valname = strip_leading_linphone(v['enum_value_cname'])
v['enum_value_name'] = remove_useless_enum_prefix(e['enum_name'], valname)
v['enum_value_doc'] = self.__format_doc(xml_enum_value.find('briefdescription'), xml_enum_value.find('detaileddescription'))
e['enum_doc'] += '\t' + v['enum_value_name'] + ': ' + v['enum_value_doc'] + '\n'
e['enum_doc'] += ' ' + v['enum_value_name'] + '|' + v['enum_value_doc'] + '\n'
e['enum_values'].append(v)
if v['enum_value_name'] != valname:
# TODO: To remove. Add deprecated value name.
v = {}
v['enum_value_cname'] = xml_enum_value.get('name')
v['enum_value_name'] = strip_leading_linphone(v['enum_value_cname'])
v['enum_value_doc'] = self.__format_doc(xml_enum_value.find('briefdescription'), xml_enum_value.find('detaileddescription'))
e['enum_deprecated_values'].append(v)
e['enum_doc'] = self.__replace_doc_special_chars(e['enum_doc'])
self.enums.append(e)
self.enum_names.append(e['enum_name'])
@ -971,11 +1072,15 @@ class LinphoneModule(object):
if isinstance(hand_written_code, HandWrittenClassMethod):
m = {}
m['method_name'] = hand_written_code.name
m['method_doc'] = self.__replace_doc_special_chars(hand_written_code.doc)
c['class_type_hand_written_methods'].append(m)
elif isinstance(hand_written_code, HandWrittenInstanceMethod):
m = {}
m['method_name'] = hand_written_code.name
m['method_doc'] = self.__replace_doc_special_chars(hand_written_code.doc)
c['class_instance_hand_written_methods'].append(m)
elif isinstance(hand_written_code, HandWrittenDeallocMethod):
c['class_has_hand_written_dealloc'] = True
elif isinstance(hand_written_code, HandWrittenProperty):
p = {}
p['property_name'] = hand_written_code.name
@ -987,6 +1092,7 @@ class LinphoneModule(object):
p['setter_reference'] = 'NULL'
else:
p['setter_reference'] = '(setter)pylinphone_' + c['class_name'] + '_set_' + p['property_name']
p['property_doc'] = self.__replace_doc_special_chars(hand_written_code.doc)
c['class_hand_written_properties'].append(p)
xml_type_methods = xml_class.findall("./classmethods/classmethod")
for xml_type_method in xml_type_methods:
@ -999,6 +1105,7 @@ class LinphoneModule(object):
m['method_name'] = method_name.replace(c['class_c_function_prefix'], '')
if method_name not in hand_written_functions:
m['method_xml_node'] = xml_type_method
self.cfunction2methodmap[method_name] = ':py:meth:`linphone.' + c['class_name'] + '.' + m['method_name'] + '`'
c['class_type_methods'].append(m)
c['class_instance_methods'] = []
xml_instance_methods = xml_class.findall("./instancemethods/instancemethod")
@ -1014,6 +1121,7 @@ class LinphoneModule(object):
m['method_name'] = method_name.replace(c['class_c_function_prefix'], '')
if method_name not in hand_written_functions:
m['method_xml_node'] = xml_instance_method
self.cfunction2methodmap[method_name] = ':py:meth:`linphone.' + c['class_name'] + '.' + m['method_name'] + '`'
c['class_instance_methods'].append(m)
c['class_properties'] = []
xml_properties = xml_class.findall("./properties/property")
@ -1040,6 +1148,7 @@ class LinphoneModule(object):
p['getter_reference'] = "(getter)pylinphone_" + c['class_name'] + "_" + p['getter_name']
p['getter_definition_begin'] = "static PyObject * pylinphone_" + c['class_name'] + "_" + p['getter_name'] + "(PyObject *self, void *closure) {"
p['getter_definition_end'] = "}"
self.cfunction2methodmap[xml_property_getter.get('name')] = ':py:attr:`linphone.' + c['class_name'] + '.' + property_name + '`'
else:
p['getter_reference'] = "NULL"
if xml_property_setter is not None:
@ -1049,6 +1158,7 @@ class LinphoneModule(object):
p['setter_reference'] = "(setter)pylinphone_" + c['class_name'] + "_" + p['setter_name']
p['setter_definition_begin'] = "static int pylinphone_" + c['class_name'] + "_" + p['setter_name'] + "(PyObject *self, PyObject *value, void *closure) {"
p['setter_definition_end'] = "}"
self.cfunction2methodmap[xml_property_setter.get('name')] = ':py:attr:`linphone.' + c['class_name'] + '.' + property_name + '`'
else:
p['setter_reference'] = "NULL"
c['class_properties'].append(p)
@ -1101,18 +1211,19 @@ class LinphoneModule(object):
except Exception, e:
e.args += (c['class_name'], p['property_name'])
raise
try:
if c['class_refcountable']:
xml_instance_method = c['class_xml_node'].find("./instancemethods/instancemethod[@name='" + c['class_c_function_prefix'] + "unref']")
c['dealloc_body'] = DeallocMethodDefinition(self, c, xml_instance_method).format()
elif c['class_destroyable']:
xml_instance_method = c['class_xml_node'].find("./instancemethods/instancemethod[@name='" + c['class_c_function_prefix'] + "destroy']")
c['dealloc_body'] = DeallocMethodDefinition(self, c, xml_instance_method).format()
else:
c['dealloc_body'] = DeallocMethodDefinition(self, c).format()
except Exception, e:
e.args += (c['class_name'], 'dealloc_body')
raise
if not 'class_has_hand_written_dealloc' in c:
try:
if c['class_refcountable']:
xml_instance_method = c['class_xml_node'].find("./instancemethods/instancemethod[@name='" + c['class_c_function_prefix'] + "unref']")
c['dealloc_definition'] = DeallocMethodDefinition(self, c, xml_instance_method).format()
elif c['class_destroyable']:
xml_instance_method = c['class_xml_node'].find("./instancemethods/instancemethod[@name='" + c['class_c_function_prefix'] + "destroy']")
c['dealloc_definition'] = DeallocMethodDefinition(self, c, xml_instance_method).format()
else:
c['dealloc_definition'] = DeallocMethodDefinition(self, c).format()
except Exception, e:
e.args += (c['class_name'], 'dealloc_body')
raise
# Convert mslist_types to a list of dictionaries for the template
d = []
for mslist_type in self.mslist_types:
@ -1168,8 +1279,20 @@ class LinphoneModule(object):
def __replace_doc_special_chars(self, doc):
return doc.replace('"', '').encode('string-escape')
def __replace_doc_cfunction_by_method(self, doc):
for cfunction, method in self.cfunction2methodmap.iteritems():
doc = doc.replace(cfunction + '()', method)
for cfunction, method in self.cfunction2methodmap.iteritems():
doc = doc.replace(cfunction, method)
return doc
def __replace_doc_keywords(self, doc):
return doc.replace('NULL', 'None')
def __format_doc(self, brief_description, detailed_description):
doc = self.__format_doc_content(brief_description, detailed_description)
doc = self.__replace_doc_cfunction_by_method(doc)
doc = self.__replace_doc_keywords(doc)
doc = self.__replace_doc_special_chars(doc)
return doc
@ -1202,6 +1325,8 @@ class LinphoneModule(object):
return_argument_type = ArgumentType(return_type, return_complete_type, return_contained_type, self)
doc += '\n:returns: ' + return_doc
doc += '\n:rtype: ' + return_argument_type.type_str
doc = self.__replace_doc_cfunction_by_method(doc)
doc = self.__replace_doc_keywords(doc)
doc = self.__replace_doc_special_chars(doc)
return doc
@ -1213,6 +1338,8 @@ class LinphoneModule(object):
argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self)
doc = self.__format_doc_content(xml_node.find('briefdescription'), xml_node.find('detaileddescription'))
doc = '[' + argument_type.type_str + '] ' + doc
doc = self.__replace_doc_cfunction_by_method(doc)
doc = self.__replace_doc_keywords(doc)
doc = self.__replace_doc_special_chars(doc)
return doc
@ -1224,5 +1351,7 @@ class LinphoneModule(object):
return_argument_type = ArgumentType(return_type, return_complete_type, return_contained_type, self)
doc = self.__format_doc_content(xml_node.find('briefdescription'), xml_node.find('detaileddescription'))
doc = '[' + return_argument_type.type_str + '] ' + doc
doc = self.__replace_doc_cfunction_by_method(doc)
doc = self.__replace_doc_keywords(doc)
doc = self.__replace_doc_special_chars(doc)
return doc

View file

@ -125,9 +125,7 @@ static int pylinphone_{{class_name}}_init(PyObject *self, PyObject *args, PyObje
{{{init_body}}}
}
static void pylinphone_{{class_name}}_dealloc(PyObject *self) {
{{{dealloc_body}}}
}
{{{dealloc_definition}}}
{{#class_type_methods}}
@ -148,14 +146,14 @@ static PyObject * pylinphone_{{class_name}}_instance_method_{{method_name}}(PyOb
static PyMethodDef pylinphone_{{class_name}}_methods[] = {
/* Class methods */
{{#class_type_hand_written_methods}}
{ "{{method_name}}", pylinphone_{{class_name}}_class_method_{{method_name}}, METH_VARARGS | METH_CLASS, "" },
{ "{{method_name}}", pylinphone_{{class_name}}_class_method_{{method_name}}, METH_VARARGS | METH_CLASS, "{{{method_doc}}}" },
{{/class_type_hand_written_methods}}
{{#class_type_methods}}
{ "{{method_name}}", pylinphone_{{class_name}}_class_method_{{method_name}}, METH_VARARGS | METH_CLASS, "{{{method_doc}}}" },
{{/class_type_methods}}
/* Instance methods */
{{#class_instance_hand_written_methods}}
{ "{{method_name}}", pylinphone_{{class_name}}_instance_method_{{method_name}}, METH_VARARGS, "" },
{ "{{method_name}}", pylinphone_{{class_name}}_instance_method_{{method_name}}, METH_VARARGS, "{{{method_doc}}}" },
{{/class_instance_hand_written_methods}}
{{#class_instance_methods}}
{ "{{method_name}}", pylinphone_{{class_name}}_instance_method_{{method_name}}, METH_VARARGS, "{{{method_doc}}}" },
@ -183,7 +181,7 @@ static PyMemberDef pylinphone_{{class_name}}_members[] = {
static PyGetSetDef pylinphone_{{class_name}}_getseters[] = {
{{#class_hand_written_properties}}
{ "{{property_name}}", {{getter_reference}}, {{setter_reference}}, "" },
{ "{{property_name}}", {{getter_reference}}, {{setter_reference}}, "{{{property_doc}}}" },
{{/class_hand_written_properties}}
{{#class_properties}}
{ "{{property_name}}", {{getter_reference}}, {{setter_reference}}, "{{{property_doc}}}" },
@ -308,12 +306,21 @@ PyMODINIT_FUNC initlinphone(void) {
{{#enum_values}}
if (PyModule_AddIntConstant(menum, "{{enum_value_name}}", {{enum_value_cname}}) < 0) return;
{{/enum_values}}
{{#enum_deprecated_values}}
if (PyModule_AddIntConstant(menum, "{{enum_value_name}}", {{enum_value_cname}}) < 0) return;
{{/enum_deprecated_values}}
{{/enums}}
menum = Py_InitModule3("PayloadTypeType", pylinphone_PayloadTypeType_ModuleMethods, "Type of linphone.PayloadType.");
menum = Py_InitModule3("PayloadTypeType", pylinphone_PayloadTypeType_ModuleMethods, "Type of :py:class:`linphone.PayloadType`.\n\n.. csv-table::\n :delim: |\n :header: Value,Description\n\n AudioContinuous|\n AudioPacketized|\n Video|\n Text|\n Other|\n");
if (menum == NULL) return;
Py_INCREF(menum);
if (PyModule_AddObject(m, "PayloadTypeType", menum) < 0) return;
if (PyModule_AddIntConstant(menum, "AudioContinuous", PAYLOAD_AUDIO_CONTINUOUS) < 0) return;
if (PyModule_AddIntConstant(menum, "AudioPacketized", PAYLOAD_AUDIO_PACKETIZED) < 0) return;
if (PyModule_AddIntConstant(menum, "Video", PAYLOAD_VIDEO) < 0) return;
if (PyModule_AddIntConstant(menum, "Text", PAYLOAD_TEXT) < 0) return;
if (PyModule_AddIntConstant(menum, "Other", PAYLOAD_OTHER) < 0) return;
// TODO: To remove. Deprecated enum values.
if (PyModule_AddIntConstant(menum, "PAYLOAD_AUDIO_CONTINUOUS", PAYLOAD_AUDIO_CONTINUOUS) < 0) return;
if (PyModule_AddIntConstant(menum, "PAYLOAD_AUDIO_PACKETIZED", PAYLOAD_AUDIO_PACKETIZED) < 0) return;
if (PyModule_AddIntConstant(menum, "PAYLOAD_VIDEO", PAYLOAD_VIDEO) < 0) return;

View file

@ -48,8 +48,12 @@ help:
clean:
rm -rf $(BUILDDIR)/*
rm -f source/enums.rst
html:
source/enums.rst:
python generate_enums.py -o source/enums.rst
html: source/enums.rst
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."

View file

@ -0,0 +1,28 @@
#!/usr/bin/python
import argparse
import types
import sys
def main(argv = None):
if argv is None:
argv = sys.argv
argparser = argparse.ArgumentParser(description="Generate enums documentation of the Linphone API.")
argparser.add_argument('-o', '--outputfile', metavar='outputfile', type=argparse.FileType('w'), help="Output .rst file describing the Linphone API enums.")
args = argparser.parse_args()
if args.outputfile == None:
args.outputfile = open('enums.rst', 'w')
module = __import__('linphone', globals(), locals())
for name in dir(module):
if name == 'testing' or name == 'linphone':
continue
if type(getattr(module, name)) == types.ModuleType:
args.outputfile.write('linphone.' + name + '\n')
args.outputfile.write('^' * len('linphone.' + name) + '\n\n')
args.outputfile.write(getattr(module, name).__doc__)
args.outputfile.write('\n')
if __name__ == "__main__":
sys.exit(main())

View file

@ -0,0 +1,52 @@
$(function (){
var createList = function(selector){
var ul = $('<ul>');
var selected = $(selector);
if (selected.length === 0){
return;
}
selected.clone().each(function (i,e){
var p = $(e).children('.descclassname');
var n = $(e).children('.descname');
var l = $(e).children('.headerlink');
var a = $('<a>');
a.attr('href',l.attr('href')).attr('title', 'Link to this definition');
a.append(p).append(n);
var entry = $('<li>').append(a);
ul.append(entry);
});
return ul;
}
var c = $('<div style="min-width: 300px;">');
var ul0 = c.clone().append($('.submodule-index'))
customIndex = $('.custom-index');
customIndex.empty();
customIndex.append(ul0);
var x = [];
x.push(['Classes','dl.class > dt']);
x.push(['Functions','dl.function > dt']);
x.push(['Variables','dl.data > dt']);
x.forEach(function (e){
var l = createList(e[1]);
if (l) {
var ul = c.clone()
.append('<p class="rubric">'+e[0]+'</p>')
.append(l);
}
customIndex.append(ul);
});
});

View file

@ -0,0 +1,24 @@
API reference
=============
Enums
-----
.. include:: enums.rst
Classes
-------
.. container:: custom-index
.. raw:: html
<script type="text/javascript" src='_static/pylinphone.js'></script>
.. currentmodule:: linphone
.. automodule:: linphone
:members:
:undoc-members:
.. autoattribute:: linphone.__version__

View file

@ -29,7 +29,7 @@ import os
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.autodoc'
]
# Add any paths that contain templates here, relative to this directory.
@ -145,7 +145,9 @@ html_static_path = ['_static']
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
html_sidebars = {
'**': ['localtoc.html', 'relations.html', 'searchbox.html']
}
# Additional templates that should be rendered to pages, maps page names to
# template names.

View file

@ -0,0 +1,44 @@
Getting started
===============
Installing the Python module
----------------------------
You can install prebuilt packages of Linphone for Python. You will find the
releases at https://pypi.python.org/pypi/linphone. This includes only packages
for the Windows platform right now. The easiest way to install is to use pip,
eg.:
.. code-block:: none
> pip install linphone --pre
You can also find nightly-built packages for Windows, Mac OS X and Linux at
https://www.linphone.org/snapshots/linphone-python/.
Otherwise you can compile the Python module. To do so get the build system code
using the command:
.. code-block:: none
> git clone git://git.linphone.org/linphone-cmake-builder.git
Then follow the instructions in the *README.python* file.
Running some code
-----------------
Here is a sample source code using PyQt4 that enables you to register on a SIP
server in just a few lines of code. This is a very basic example, but it shows
how to create a linphone.Core object that is the main object of Linphone. From
there, you can use the API reference below to use more advanced feature and
perform some SIP calls, use text messaging and more...
.. literalinclude:: pyqt_linphone_example.py
In the Linphone Python module package you installed previously you will also
find some unit tests that you can run. These unit tests will be located in the
*site-packages/linphone/unittests/* directory of Python installation where you
installed the Linphone Python module package. To run these unit tests, follow
the instructions contained in the README.txt file of this *unittests/*
directory.

View file

@ -6,62 +6,12 @@
Linphone for Python documentation
=================================
Getting started
---------------
Installing the Python module
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can install prebuilt packages of Linphone for Python. You will find the
releases at https://pypi.python.org/pypi/linphone. This includes only packages
for the Windows platform right now. The easiest way to install is to use pip,
eg.:
.. code-block:: none
> pip install linphone --pre
You can also find nightly-built packages for Windows, Mac OS X and Linux at
https://www.linphone.org/snapshots/linphone-python/.
Otherwise you can compile the Python module. To do so get the build system code
using the command:
.. code-block:: none
> git clone git://git.linphone.org/linphone-cmake-builder.git
Then follow the instructions in the *README.python* file.
Running some code
^^^^^^^^^^^^^^^^^
Here is a sample source code using PyQt4 that enables you to register on a SIP
server in just a few lines of code. This is a very basic example, but it shows
how to create a linphone.Core object that is the main object of Linphone. From
there, you can use the API reference below to use more advanced feature and
perform some SIP calls, use text messaging and more...
.. literalinclude:: pyqt_linphone_example.py
In the Linphone Python module package you installed previously you will also
find some unit tests that you can run. These unit tests will be located in the
*site-packages/linphone/unittests/* directory of Python installation where you
installed the Linphone Python module package. To run these unit tests, follow
the instructions contained in the README.txt file of this *unittests/*
directory.
API reference
-------------
.. toctree::
:maxdepth: 2
:numbered:
.. automodule:: linphone
:members:
:undoc-members:
.. autoattribute:: linphone.__version__
getting_started
api_reference
Indices and tables

View file

@ -8,6 +8,7 @@ import sys
import time
test_domain = "sipopen.example.org"
test_username = "liblinphone_tester"
test_password = "secret"
test_route = "sip2.linphone.org"
@ -89,9 +90,9 @@ class AccountManager:
@classmethod
def account_created_on_server_cb(cls, lc, cfg, state, message):
if state == linphone.RegistrationState.RegistrationOk:
if state == linphone.RegistrationState.Ok:
lc.user_data.created = True
elif state == linphone.RegistrationState.RegistrationCleared:
elif state == linphone.RegistrationState.Cleared:
lc.user_data.done = True
@classmethod
@ -134,7 +135,7 @@ class AccountManager:
tmp_identity.set_header("X-Create-Account", "yes")
cfg.identity = tmp_identity.as_string()
server_addr = linphone.Address.new(refcfg.server_addr)
server_addr.transport = linphone.TransportType.TransportTcp;
server_addr.transport = linphone.TransportType.Tcp;
server_addr.port = 0
cfg.server_addr = server_addr.as_string()
cfg.expires = 3600
@ -365,12 +366,12 @@ class CoreManager:
lambda callee_manager, caller_manager: (callee_manager.stats.number_of_LinphoneCallStreamsRunning == initial_callee_stats.number_of_LinphoneCallStreamsRunning + 1) and \
(caller_manager.stats.number_of_LinphoneCallStreamsRunning == initial_caller_stats.number_of_LinphoneCallStreamsRunning + 1))
if caller_manager.lc.media_encryption != linphone.MediaEncryption.MediaEncryptionNone and callee_manager.lc.media_encryption != linphone.MediaEncryption.MediaEncryptionNone:
if caller_manager.lc.media_encryption != linphone.MediaEncryption.MediaEncryptionNone and callee_manager.lc.media_encryption != linphone.MediaEncryption.None:
# Wait for encryption to be on, in case of zrtp, it can take a few seconds
if caller_manager.lc.media_encryption == linphone.MediaEncryption.MediaEncryptionZRTP:
if caller_manager.lc.media_encryption == linphone.MediaEncryption.ZRTP:
CoreManager.wait_for(callee_manager, caller_manager,
lambda callee_manager, caller_manager: caller_manager.stats.number_of_LinphoneCallEncryptedOn == initial_caller_stats.number_of_LinphoneCallEncryptedOn + 1)
if callee_manager.lc.media_encryption == linphone.MediaEncryption.MediaEncryptionZRTP:
if callee_manager.lc.media_encryption == linphone.MediaEncryption.ZRTP:
CoreManager.wait_for(callee_manager, caller_manager,
lambda callee_manager, caller_manager: callee_manager.stats.number_of_LinphoneCallEncryptedOn == initial_callee_stats.number_of_LinphoneCallEncryptedOn + 1)
assert_equals(callee_manager.lc.current_call.current_params.media_encryption, caller_manager.lc.media_encryption)
@ -389,15 +390,15 @@ class CoreManager:
manager = lc.user_data
linphonetester_logger.info("[TESTER] New registration state {state} for user id [{identity}] at proxy [{addr}]".format(
state=linphone.RegistrationState.string(state), identity=cfg.identity, addr=cfg.server_addr))
if state == linphone.RegistrationState.RegistrationNone:
if state == linphone.RegistrationState.None:
manager.stats.number_of_LinphoneRegistrationNone += 1
elif state == linphone.RegistrationState.RegistrationProgress:
elif state == linphone.RegistrationState.Progress:
manager.stats.number_of_LinphoneRegistrationProgress += 1
elif state == linphone.RegistrationState.RegistrationOk:
elif state == linphone.RegistrationState.Ok:
manager.stats.number_of_LinphoneRegistrationOk += 1
elif state == linphone.RegistrationState.RegistrationCleared:
elif state == linphone.RegistrationState.Cleared:
manager.stats.number_of_LinphoneRegistrationCleared += 1
elif state == linphone.RegistrationState.RegistrationFailed:
elif state == linphone.RegistrationState.Failed:
manager.stats.number_of_LinphoneRegistrationFailed += 1
else:
raise Exception("Unexpected registration state")
@ -415,45 +416,45 @@ class CoreManager:
to_address = call.call_log.to_address.as_string()
from_address = call.call_log.from_address.as_string()
direction = "Outgoing"
if call.call_log.dir == linphone.CallDir.CallIncoming:
if call.call_log.dir == linphone.CallDir.Incoming:
direction = "Incoming"
linphonetester_logger.info("[TESTER] {direction} call from [{from_address}] to [{to_address}], new state is [{state}]".format(
direction=direction, from_address=from_address, to_address=to_address, state=linphone.CallState.string(state)))
if state == linphone.CallState.CallIncomingReceived:
if state == linphone.CallState.IncomingReceived:
manager.stats.number_of_LinphoneCallIncomingReceived += 1
elif state == linphone.CallState.CallOutgoingInit:
elif state == linphone.CallState.OutgoingInit:
manager.stats.number_of_LinphoneCallOutgoingInit += 1
elif state == linphone.CallState.CallOutgoingProgress:
elif state == linphone.CallState.OutgoingProgress:
manager.stats.number_of_LinphoneCallOutgoingProgress += 1
elif state == linphone.CallState.CallOutgoingRinging:
elif state == linphone.CallState.OutgoingRinging:
manager.stats.number_of_LinphoneCallOutgoingRinging += 1
elif state == linphone.CallState.CallOutgoingEarlyMedia:
elif state == linphone.CallState.OutgoingEarlyMedia:
manager.stats.number_of_LinphoneCallOutgoingEarlyMedia += 1
elif state == linphone.CallState.CallConnected:
elif state == linphone.CallState.Connected:
manager.stats.number_of_LinphoneCallConnected += 1
elif state == linphone.CallState.CallStreamsRunning:
elif state == linphone.CallState.StreamsRunning:
manager.stats.number_of_LinphoneCallStreamsRunning += 1
elif state == linphone.CallState.CallPausing:
elif state == linphone.CallState.Pausing:
manager.stats.number_of_LinphoneCallPausing += 1
elif state == linphone.CallState.CallPaused:
elif state == linphone.CallState.Paused:
manager.stats.number_of_LinphoneCallPaused += 1
elif state == linphone.CallState.CallResuming:
elif state == linphone.CallState.Resuming:
manager.stats.number_of_LinphoneCallResuming += 1
elif state == linphone.CallState.CallRefered:
elif state == linphone.CallState.Refered:
manager.stats.number_of_LinphoneCallRefered += 1
elif state == linphone.CallState.CallError:
elif state == linphone.CallState.Error:
manager.stats.number_of_LinphoneCallError += 1
elif state == linphone.CallState.CallEnd:
elif state == linphone.CallState.End:
manager.stats.number_of_LinphoneCallEnd += 1
elif state == linphone.CallState.CallPausedByRemote:
elif state == linphone.CallState.PausedByRemote:
manager.stats.number_of_LinphoneCallPausedByRemote += 1
elif state == linphone.CallState.CallUpdatedByRemote:
elif state == linphone.CallState.UpdatedByRemote:
manager.stats.number_of_LinphoneCallUpdatedByRemote += 1
elif state == linphone.CallState.CallIncomingEarlyMedia:
elif state == linphone.CallState.IncomingEarlyMedia:
manager.stats.number_of_LinphoneCallIncomingEarlyMedia += 1
elif state == linphone.CallState.CallUpdating:
elif state == linphone.CallState.Updating:
manager.stats.number_of_LinphoneCallUpdating += 1
elif state == linphone.CallState.CallReleased:
elif state == linphone.CallState.Released:
manager.stats.number_of_LinphoneCallReleased += 1
else:
raise Exception("Unexpected call state")
@ -489,63 +490,63 @@ class CoreManager:
manager.stats.number_of_NotifyReceived += 1
manager.stats.last_received_presence = lf.presence_model
acttype = manager.stats.last_received_presence.activity.type
if acttype == linphone.PresenceActivityType.PresenceActivityOffline:
if acttype == linphone.PresenceActivityType.Offline:
manager.stats.number_of_LinphonePresenceActivityOffline += 1
elif acttype == linphone.PresenceActivityType.PresenceActivityOnline:
elif acttype == linphone.PresenceActivityType.Online:
manager.stats.number_of_LinphonePresenceActivityOnline += 1
elif acttype == linphone.PresenceActivityType.PresenceActivityAppointment:
elif acttype == linphone.PresenceActivityType.Appointment:
manager.stats.number_of_LinphonePresenceActivityAppointment += 1
elif acttype == linphone.PresenceActivityType.PresenceActivityAway:
elif acttype == linphone.PresenceActivityType.Away:
manager.stats.number_of_LinphonePresenceActivityAway += 1
elif acttype == linphone.PresenceActivityType.PresenceActivityBreakfast:
elif acttype == linphone.PresenceActivityType.Breakfast:
manager.stats.number_of_LinphonePresenceActivityBreakfast += 1
elif acttype == linphone.PresenceActivityType.PresenceActivityBusy:
elif acttype == linphone.PresenceActivityType.Busy:
manager.stats.number_of_LinphonePresenceActivityBusy += 1
elif acttype == linphone.PresenceActivityType.PresenceActivityDinner:
elif acttype == linphone.PresenceActivityType.Dinner:
manager.stats.number_of_LinphonePresenceActivityDinner += 1
elif acttype == linphone.PresenceActivityType.PresenceActivityHoliday:
elif acttype == linphone.PresenceActivityType.Holiday:
manager.stats.number_of_LinphonePresenceActivityHoliday += 1
elif acttype == linphone.PresenceActivityType.PresenceActivityInTransit:
elif acttype == linphone.PresenceActivityType.InTransit:
manager.stats.number_of_LinphonePresenceActivityInTransit += 1
elif acttype == linphone.PresenceActivityType.PresenceActivityLookingForWork:
elif acttype == linphone.PresenceActivityType.LookingForWork:
manager.stats.number_of_LinphonePresenceActivityLookingForWork += 1
elif acttype == linphone.PresenceActivityType.PresenceActivityLunch:
elif acttype == linphone.PresenceActivityType.Lunch:
manager.stats.number_of_LinphonePresenceActivityLunch += 1
elif acttype == linphone.PresenceActivityType.PresenceActivityMeal:
elif acttype == linphone.PresenceActivityType.Meal:
manager.stats.number_of_LinphonePresenceActivityMeal += 1
elif acttype == linphone.PresenceActivityType.PresenceActivityMeeting:
elif acttype == linphone.PresenceActivityType.Meeting:
manager.stats.number_of_LinphonePresenceActivityMeeting += 1
elif acttype == linphone.PresenceActivityType.PresenceActivityOnThePhone:
elif acttype == linphone.PresenceActivityType.OnThePhone:
manager.stats.number_of_LinphonePresenceActivityOnThePhone += 1
elif acttype == linphone.PresenceActivityType.PresenceActivityOther:
elif acttype == linphone.PresenceActivityType.Other:
manager.stats.number_of_LinphonePresenceActivityOther += 1
elif acttype == linphone.PresenceActivityType.PresenceActivityPerformance:
elif acttype == linphone.PresenceActivityType.Performance:
manager.stats.number_of_LinphonePresenceActivityPerformance += 1
elif acttype == linphone.PresenceActivityType.PresenceActivityPermanentAbsence:
elif acttype == linphone.PresenceActivityType.PermanentAbsence:
manager.stats.number_of_LinphonePresenceActivityPermanentAbsence += 1
elif acttype == linphone.PresenceActivityType.PresenceActivityPlaying:
elif acttype == linphone.PresenceActivityType.Playing:
manager.stats.number_of_LinphonePresenceActivityPlaying += 1
elif acttype == linphone.PresenceActivityType.PresenceActivityPresentation:
elif acttype == linphone.PresenceActivityType.Presentation:
manager.stats.number_of_LinphonePresenceActivityPresentation += 1
elif acttype == linphone.PresenceActivityType.PresenceActivityShopping:
elif acttype == linphone.PresenceActivityType.Shopping:
manager.stats.number_of_LinphonePresenceActivityShopping += 1
elif acttype == linphone.PresenceActivityType.PresenceActivitySleeping:
elif acttype == linphone.PresenceActivityType.Sleeping:
manager.stats.number_of_LinphonePresenceActivitySleeping += 1
elif acttype == linphone.PresenceActivityType.PresenceActivitySpectator:
elif acttype == linphone.PresenceActivityType.Spectator:
manager.stats.number_of_LinphonePresenceActivitySpectator += 1
elif acttype == linphone.PresenceActivityType.PresenceActivitySteering:
elif acttype == linphone.PresenceActivityType.Steering:
manager.stats.number_of_LinphonePresenceActivitySteering += 1
elif acttype == linphone.PresenceActivityType.PresenceActivityTravel:
elif acttype == linphone.PresenceActivityType.Travel:
manager.stats.number_of_LinphonePresenceActivityTravel += 1
elif acttype == linphone.PresenceActivityType.PresenceActivityTV:
elif acttype == linphone.PresenceActivityType.TV:
manager.stats.number_of_LinphonePresenceActivityTV += 1
elif acttype == linphone.PresenceActivityType.PresenceActivityUnknown:
elif acttype == linphone.PresenceActivityType.Unknown:
manager.stats.number_of_LinphonePresenceActivityUnknown += 1
elif acttype == linphone.PresenceActivityType.PresenceActivityVacation:
elif acttype == linphone.PresenceActivityType.Vacation:
manager.stats.number_of_LinphonePresenceActivityVacation += 1
elif acttype == linphone.PresenceActivityType.PresenceActivityWorking:
elif acttype == linphone.PresenceActivityType.Working:
manager.stats.number_of_LinphonePresenceActivityWorking += 1
elif acttype == linphone.PresenceActivityType.PresenceActivityWorship:
elif acttype == linphone.PresenceActivityType.Worship:
manager.stats.number_of_LinphonePresenceActivityWorship += 1
def __init__(self, rc_file = None, check_for_proxies = True, vtable = {}):

View file

@ -17,11 +17,11 @@ class TestCall:
assert_equals(CoreManager.wait_for_until(pauline, marie, lambda pauline, marie: pauline.stats.number_of_LinphoneCallError == 1, 33000), True)
assert_equals(pauline.stats.number_of_LinphoneCallError, 1)
#FIXME http://git.linphone.org/mantis/view.php?id=757
#assert_equals(out_call.reason, linphone.Reason.ReasonBusy)
#assert_equals(out_call.reason, linphone.Reason.Busy)
if len(pauline.lc.call_logs) > 0:
out_call_log = pauline.lc.call_logs[0]
assert out_call_log is not None
assert_equals(out_call_log.status, linphone.CallStatus.CallAborted)
assert_equals(out_call_log.status, linphone.CallStatus.Aborted)
marie.stop()
pauline.stop()
@ -38,8 +38,8 @@ class TestCall:
assert_equals(CoreManager.wait_for(pauline, marie, lambda pauline, marie: pauline.stats.number_of_LinphoneCallReleased == 1), True)
assert_equals(marie.stats.number_of_LinphoneCallEnd, 1)
assert_equals(pauline.stats.number_of_LinphoneCallEnd, 1)
assert_equals(in_call.reason, linphone.Reason.ReasonDeclined)
assert_equals(out_call.reason, linphone.Reason.ReasonDeclined)
assert_equals(in_call.reason, linphone.Reason.Declined)
assert_equals(out_call.reason, linphone.Reason.Declined)
marie.stop()
pauline.stop()
@ -97,7 +97,7 @@ class TestCall:
# flexisip will retain the 488 until the "urgent reply" timeout arrives.
assert_equals(CoreManager.wait_for_until(pauline, marie, lambda pauline, marie: pauline.stats.number_of_LinphoneCallError == 1, 7000), True)
assert_equals(out_call.reason, linphone.Reason.ReasonNotAcceptable)
assert_equals(out_call.reason, linphone.Reason.NotAcceptable)
assert_equals(marie.stats.number_of_LinphoneCallIncomingReceived, 0)
assert_equals(marie.stats.number_of_LinphoneCallReleased, 0)
marie.stop()

View file

@ -1,8 +1,10 @@
from nose.tools import assert_equals
from copy import deepcopy
import filecmp
import linphone
from linphonetester import *
import os
import os.path
import time
@ -12,30 +14,74 @@ class TestMessage:
def msg_state_changed(cls, msg, state):
stats = msg.chat_room.core.user_data.stats
linphonetester_logger.info("[TESTER] Message [{text}] [{state}]".format(text=msg.text, state=linphone.ChatMessageState.string(state)))
if state == linphone.ChatMessageState.ChatMessageStateDelivered:
if state == linphone.ChatMessageState.Delivered:
stats.number_of_LinphoneMessageDelivered += 1
elif state == linphone.ChatMessageState.ChatMessageStateNotDelivered:
elif state == linphone.ChatMessageState.NotDelivered:
stats.number_of_LinphoneMessageNotDelivered += 1
elif state == linphone.ChatMessageState.ChatMessageStateInProgress:
elif state == linphone.ChatMessageState.InProgress:
stats.number_of_LinphoneMessageInProgress += 1
elif state == linphone.ChatMessageState.ChatMessageStateFileTransferError:
elif state == linphone.ChatMessageState.FileTransferError:
stats.number_of_LinphoneMessageNotDelivered += 1
else:
linphonetester_logger.error("[TESTER] Unexpected state [{state}] for message [{msg}]".format(msg=msg, state=linphone.ChatMessageState.string(state)))
@classmethod
def file_transfer_received(cls, msg, content, buf, size):
print buf, size
def file_transfer_progress_indication(cls, msg, content, offset, total):
stats = msg.chat_room.core.user_data.stats
if msg.user_data is None:
msg.user_data = open('receive_file.dump', 'wb')
msg.user_data.write(buf)
else:
if size == 0: # Transfer complete
stats.number_of_LinphoneMessageExtBodyReceived += 1
msg.user_data.close()
else: # Store content
msg.user_data.write(buf)
progress = int((offset * 100) / total)
direction = 'received'
tofrom = 'from'
address = msg.from_address
if msg.outgoing:
direction = 'sent'
tofrom = 'to'
address = msg.to_address
linphonetester_logger.info("[TESTER] File transfer [{progress}%] {direction} of type [{type}/{subtype}] {tofrom} {address}".format(
progress=progress, direction=direction, type=content.type, subtype=content.subtype, tofrom=tofrom, address=address.as_string()));
stats.progress_of_LinphoneFileTransfer = progress
@classmethod
def file_transfer_send(cls, msg, content, offset, size):
send_filepath = msg.user_data
send_filesize = os.path.getsize(send_filepath)
if offset >= send_filesize:
return linphone.Buffer.new() # end of file
f = open(send_filepath, 'rb')
f.seek(offset, 0)
if (send_filesize - offset) < size:
size = send_filesize - offset
lb = linphone.Buffer.new_from_data(bytearray(f.read(size)))
f.close()
return lb
@classmethod
def file_transfer_recv(cls, msg, content, buf):
receive_filepath = msg.user_data
stats = msg.chat_room.core.user_data.stats
if buf.empty: # Transfer complete
stats.number_of_LinphoneMessageExtBodyReceived += 1
else: # Store content
f = open(receive_filepath, 'ab')
f.write(buf.content)
f.close()
@classmethod
def memory_file_transfer_send(cls, msg, content, offset, size):
send_buf = msg.user_data
send_size = len(send_buf)
if offset >= send_size:
return linphone.Buffer.new()
if (send_size - offset) < size:
size = send_size - offset
return linphone.Buffer.new_from_string(send_buf[offset:offset+size])
@classmethod
def memory_file_transfer_recv(cls, msg, content, buf):
stats = msg.chat_room.core.user_data.stats
if buf.empty: # Transfer complete
stats.number_of_LinphoneMessageExtBodyReceived += 1
else: # Store content
msg.user_data += buf.string_content
def wait_for_server_to_purge_messages(self, manager1, manager2):
# Wait a little bit just to have time to purge message stored in the server
@ -49,7 +95,7 @@ class TestMessage:
chat_room = pauline.lc.get_chat_room(marie.identity)
self.wait_for_server_to_purge_messages(marie, pauline)
msg = chat_room.create_message("Bla bla bla bla")
chat_room.send_message2(msg, None, None)
chat_room.send_chat_message(msg)
assert_equals(CoreManager.wait_for(pauline, marie, lambda pauline, marie: marie.stats.number_of_LinphoneMessageReceived == 1), True)
assert marie.lc.get_chat_room(pauline.identity) is not None
marie.stop()
@ -63,40 +109,108 @@ class TestMessage:
self.wait_for_server_to_purge_messages(marie, pauline)
assert_equals(CoreManager.call(marie, pauline), True)
msg = chat_room.create_message("Bla bla bla bla")
chat_room.send_message2(msg, None, None)
chat_room.send_chat_message(msg)
assert_equals(CoreManager.wait_for(pauline, marie, lambda pauline, marie: marie.stats.number_of_LinphoneMessageReceived == 1), True)
assert marie.lc.get_chat_room(pauline.identity) is not None
marie.stop()
pauline.stop()
def test_file_transfer_message(self):
big_file = "big file"
marie = CoreManager('marie_rc')
pauline = CoreManager('pauline_rc')
while len(big_file) < 128000:
big_file += big_file
l = list(big_file)
l[0] = 'S'
l[-1] = 'E'
big_file = ''.join(l)
send_filepath = os.path.join(tester_resources_path, 'images', 'nowebcamCIF.jpg')
receive_filepath = 'receive_file.dump'
pauline.lc.file_transfer_server = "https://www.linphone.org:444/lft.php"
chat_room = pauline.lc.get_chat_room(marie.identity)
content = pauline.lc.create_content()
content.type = 'text'
content.subtype = 'plain'
content.size = len(big_file) # total size to be transfered
content.name = 'bigfile.txt'
content.type = 'image'
content.subtype = 'jpeg'
content.size = os.path.getsize(send_filepath) # total size to be transfered
content.name = 'nowebcamCIF.jpg'
message = chat_room.create_file_transfer_message(content)
message.user_data = send_filepath
self.wait_for_server_to_purge_messages(marie, pauline)
message.callbacks.msg_state_changed = TestMessage.msg_state_changed
message.callbacks.file_transfer_send = TestMessage.file_transfer_send
chat_room.send_chat_message(message)
assert_equals(CoreManager.wait_for(pauline, marie, lambda pauline, marie: marie.stats.number_of_LinphoneMessageReceivedWithFile == 1), True)
if marie.stats.last_received_chat_message is not None:
cbs = marie.stats.last_received_chat_message.callbacks
cbs.msg_state_changed = TestMessage.msg_state_changed
cbs.file_transfer_recv = TestMessage.file_transfer_received
cbs.file_transfer_recv = TestMessage.file_transfer_recv
marie.stats.last_received_chat_message.user_data = receive_filepath
marie.stats.last_received_chat_message.download_file()
assert_equals(CoreManager.wait_for(pauline, marie, lambda pauline, marie: marie.stats.number_of_LinphoneMessageExtBodyReceived == 1), True)
assert_equals(pauline.stats.number_of_LinphoneMessageInProgress, 1)
assert_equals(pauline.stats.number_of_LinphoneMessageDelivered, 1)
assert_equals(marie.stats.number_of_LinphoneMessageExtBodyReceived, 1)
assert_equals(filecmp.cmp(send_filepath, receive_filepath, shallow=False), True)
if os.path.exists(receive_filepath):
os.remove(receive_filepath)
def test_small_file_transfer_message(self):
send_buf = "small file"
marie = CoreManager('marie_rc')
pauline = CoreManager('pauline_rc')
while len(send_buf) < 160:
send_buf += send_buf
l = list(send_buf[0:160])
l[0] = 'S'
l[-1] = 'E'
send_buf = ''.join(l)
pauline.lc.file_transfer_server = "https://www.linphone.org:444/lft.php"
chat_room = pauline.lc.get_chat_room(marie.identity)
content = pauline.lc.create_content()
content.type = 'text'
content.subtype = 'plain'
content.size = len(send_buf) # total size to be transfered
content.name = 'small_file.txt'
message = chat_room.create_file_transfer_message(content)
message.user_data = send_buf
self.wait_for_server_to_purge_messages(marie, pauline)
message.callbacks.msg_state_changed = TestMessage.msg_state_changed
message.callbacks.file_transfer_send = TestMessage.memory_file_transfer_send
chat_room.send_chat_message(message)
assert_equals(CoreManager.wait_for(pauline, marie, lambda pauline, marie: marie.stats.number_of_LinphoneMessageReceivedWithFile == 1), True)
if marie.stats.last_received_chat_message is not None:
cbs = marie.stats.last_received_chat_message.callbacks
cbs.msg_state_changed = TestMessage.msg_state_changed
cbs.file_transfer_recv = TestMessage.memory_file_transfer_recv
marie.stats.last_received_chat_message.user_data = ''
marie.stats.last_received_chat_message.download_file()
assert_equals(CoreManager.wait_for(pauline, marie, lambda pauline, marie: marie.stats.number_of_LinphoneMessageExtBodyReceived == 1), True)
assert_equals(pauline.stats.number_of_LinphoneMessageInProgress, 1)
assert_equals(pauline.stats.number_of_LinphoneMessageDelivered, 1)
assert_equals(marie.stats.number_of_LinphoneMessageExtBodyReceived, 1)
assert_equals(send_buf, marie.stats.last_received_chat_message.user_data)
def test_file_transfer_message_upload_cancelled(self):
send_buf = "big file"
marie = CoreManager('marie_rc')
pauline = CoreManager('pauline_rc')
while len(send_buf) < 128000:
send_buf += send_buf
l = list(send_buf[0:128000])
l[0] = 'S'
l[-1] = 'E'
send_buf = ''.join(l)
pauline.lc.file_transfer_server = "https://www.linphone.org:444/lft.php"
chat_room = pauline.lc.get_chat_room(marie.identity)
content = pauline.lc.create_content()
content.type = 'text'
content.subtype = 'plain'
content.size = len(send_buf) # total size to be transfered
content.name = 'big_file.txt'
message = chat_room.create_file_transfer_message(content)
message.user_data = send_buf
self.wait_for_server_to_purge_messages(marie, pauline)
message.callbacks.msg_state_changed = TestMessage.msg_state_changed
message.callbacks.file_transfer_send = TestMessage.memory_file_transfer_send
message.callbacks.file_transfer_progress_indication = TestMessage.file_transfer_progress_indication
chat_room.send_chat_message(message)
# Wait for file to be at least 50% uploaded and cancel the transfer
assert_equals(CoreManager.wait_for(pauline, marie, lambda pauline, marie: pauline.stats.progress_of_LinphoneFileTransfer >= 50), True)
message.cancel_file_transfer()
assert_equals(CoreManager.wait_for(pauline, marie, lambda pauline, marie: pauline.stats.number_of_LinphoneMessageNotDelivered == 1), True)
assert_equals(pauline.stats.number_of_LinphoneMessageNotDelivered, 1)
assert_equals(marie.stats.number_of_LinphoneMessageExtBodyReceived, 0)

View file

@ -18,9 +18,10 @@ class RegisterCoreManager(CoreManager):
vtable['auth_info_requested'] = RegisterCoreManager.auth_info_requested
CoreManager.__init__(self, vtable=vtable)
def register_with_refresh(self, refresh, domain, route, late_auth_info = False, expected_final_state = linphone.RegistrationState.RegistrationOk):
def register_with_refresh_base(self, refresh, domain, route, late_auth_info = False, transport = linphone.SipTransports(5070, 5070, 5071, 0), expected_final_state = linphone.RegistrationState.Ok):
assert self.lc is not None
self.stats.reset()
self.lc.sip_transports = transport
proxy_cfg = self.lc.create_proxy_config()
from_address = create_address(domain)
proxy_cfg.identity = from_address.as_string()
@ -35,32 +36,30 @@ class RegisterCoreManager(CoreManager):
self.lc.add_proxy_config(proxy_cfg)
self.lc.default_proxy_config = proxy_cfg
#linphone_core_set_sip_transports(lc,&transport);
retry = 0
expected_count = 1
if refresh:
expected_count += 1
max_retry = 110
if expected_final_state == linphone.RegistrationState.RegistrationProgress:
if expected_final_state == linphone.RegistrationState.Progress:
max_retry += 200
while self.stats.number_of_LinphoneRegistrationOk < expected_count and retry < max_retry:
retry += 1
self.lc.iterate()
if self.stats.number_of_auth_info_requested > 0 and proxy_cfg.state == linphone.RegistrationState.RegistrationFailed and late_auth_info:
if self.stats.number_of_auth_info_requested > 0 and proxy_cfg.state == linphone.RegistrationState.Failed and late_auth_info:
if len(self.lc.auth_info_list) == 0:
assert_equals(proxy_cfg.error, linphone.Reason.ReasonUnauthorized)
assert_equals(proxy_cfg.error, linphone.Reason.Unauthorized)
info = linphone.AuthInfo.new(test_username, None, test_password, None, None, None) # Create authentication structure from identity
self.lc.add_auth_info(info)
if proxy_cfg.error == linphone.Reason.ReasonForbidden or \
(self.stats.number_of_auth_info_requested > 2 and proxy_cfg.error == linphone.Reason.ReasonUnauthorized):
if proxy_cfg.error == linphone.Reason.Forbidden or \
(self.stats.number_of_auth_info_requested > 2 and proxy_cfg.error == linphone.Reason.Unauthorized):
break
time.sleep(0.1)
assert_equals(proxy_cfg.state, expected_final_state)
assert_equals(self.stats.number_of_LinphoneRegistrationNone, 0)
assert self.stats.number_of_LinphoneRegistrationProgress >= 1
if expected_final_state == linphone.RegistrationState.RegistrationOk:
if expected_final_state == linphone.RegistrationState.Ok:
assert_equals(self.stats.number_of_LinphoneRegistrationOk, expected_count)
expected_failed = 0
if late_auth_info:
@ -69,6 +68,8 @@ class RegisterCoreManager(CoreManager):
else:
assert_equals(self.stats.number_of_LinphoneRegistrationCleared, 0)
def register_with_refresh(self, refresh, domain, route, late_auth_info = False, transport = linphone.SipTransports(5070, 5070, 5071, 0), expected_final_state = linphone.RegistrationState.Ok):
self.register_with_refresh_base(refresh, domain, route, late_auth_info, expected_final_state = expected_final_state)
self.stop()
# Not testable as the callbacks can not be called once the core destruction has started
#assert_equals(self.stats.number_of_LinphoneRegistrationCleared, 1)
@ -80,3 +81,67 @@ class TestRegister:
cm = RegisterCoreManager()
cm.register_with_refresh(False, None, None)
assert_equals(cm.stats.number_of_auth_info_requested, 0)
def test_simple_unregister(self):
cm = RegisterCoreManager()
cm.register_with_refresh_base(False, None, None)
pc = cm.lc.default_proxy_config
pc.edit()
cm.stats.reset() # clear stats
# nothing is supposed to arrive until done
assert_equals(CoreManager.wait_for_until(cm, cm, lambda cm1, cm2: cm1.stats.number_of_LinphoneRegistrationCleared == 1, 3000), False)
pc.register_enabled = False
pc.done()
assert_equals(CoreManager.wait_for(cm, cm, lambda cm1, cm2: cm1.stats.number_of_LinphoneRegistrationCleared == 1), True)
def test_simple_tcp_register(self):
cm = RegisterCoreManager()
cm.register_with_refresh(False, test_domain, "sip:{route};transport=tcp".format(route=test_route))
def test_simple_tcp_register_compatibility_mode(self):
cm = RegisterCoreManager()
cm.register_with_refresh(False, test_domain, "sip:{route}".format(route=test_route), transport=linphone.SipTransports(0, 5070, 0, 0))
def test_simple_tls_register(self):
cm = RegisterCoreManager()
cm.register_with_refresh(False, test_domain, "sip:{route};transport=tls".format(route=test_route))
def test_tls_register_with_alt_name(self):
cm = CoreManager('pauline_alt_rc', False)
cm.lc.root_ca = os.path.join(tester_resources_path, 'certificates', 'cn', 'cafile.pem')
cm.lc.refresh_registers()
assert_equals(CoreManager.wait_for(cm, cm, lambda cm1, cm2: cm1.stats.number_of_LinphoneRegistrationOk == 1), True)
assert_equals(cm.stats.number_of_LinphoneRegistrationFailed, 0)
def test_tls_wildcard_register(self):
cm = CoreManager('pauline_wild_rc', False)
cm.lc.root_ca = os.path.join(tester_resources_path, 'certificates', 'cn', 'cafile.pem')
cm.lc.refresh_registers()
assert_equals(CoreManager.wait_for(cm, cm, lambda cm1, cm2: cm1.stats.number_of_LinphoneRegistrationOk == 2), True)
assert_equals(cm.stats.number_of_LinphoneRegistrationFailed, 0)
def test_tls_certificate_failure(self):
cm = CoreManager('pauline_rc', False)
cm.lc.root_ca = os.path.join(tester_resources_path, 'certificates', 'cn', 'agent.pem') # bad root ca
cm.lc.network_reachable = True
assert_equals(CoreManager.wait_for(cm, cm, lambda cm1, cm2: cm1.stats.number_of_LinphoneRegistrationFailed == 1), True)
cm.lc.root_ca = None # no root ca
cm.lc.refresh_registers()
assert_equals(CoreManager.wait_for(cm, cm, lambda cm1, cm2: cm1.stats.number_of_LinphoneRegistrationFailed == 2), True)
cm.lc.root_ca = os.path.join(tester_resources_path, 'certificates', 'cn', 'cafile.pem') # good root ca
cm.lc.refresh_registers()
assert_equals(CoreManager.wait_for(cm, cm, lambda cm1, cm2: cm1.stats.number_of_LinphoneRegistrationOk == 1), True)
assert_equals(cm.stats.number_of_LinphoneRegistrationFailed, 2)
def test_tls_with_non_tls_server(self):
cm = CoreManager('marie_rc', False)
cm.lc.sip_transport_timeout = 3000
pc = cm.lc.default_proxy_config
pc.edit()
addr = linphone.Address.new(pc.server_addr)
port = addr.port
if port <= 0:
port = 5060
pc.server_addr = "sip:{domain}:{port};transport=tls".format(domain=addr.domain, port=port)
pc.done()
assert_equals(CoreManager.wait_for_until(cm, cm, lambda cm1, cm2: cm1.stats.number_of_LinphoneRegistrationFailed == 1, 5000), True)

View file

@ -5,6 +5,13 @@ import os
class TestSetup:
def test_address(self):
create_address(None)
def test_version(self):
lc = linphone.Core.new({}, None, None)
assert_equals(lc.version.find("unknown"), -1)
def test_address(self):
create_address(None)
@ -14,6 +21,23 @@ class TestSetup:
if lc is not None:
lc.verify_server_certificates(False)
def test_random_transport(self):
lc = linphone.Core.new({}, None, None)
assert lc is not None
tr = lc.sip_transports
assert_equals(tr.udp_port, 5060) # default config
assert_equals(tr.tcp_port, 5060) # default config
tr.udp_port = -1
tr.tcp_port = -1
tr.tls_port = -1
lc.sip_transports = tr
tr = lc.sip_transports
assert tr.udp_port != 5060 # default config
assert tr.tcp_port != 5060 # default config
assert_equals(lc.config.get_int('sip', 'sip_port', -2), -1)
assert_equals(lc.config.get_int('sip', 'sip_tcp_port', -2), -1)
assert_equals(lc.config.get_int('sip', 'sip_tls_port', -2), -1)
def test_interpret_url(self):
lc = linphone.Core.new({}, None, None)
assert lc is not None
@ -32,6 +56,22 @@ class TestSetup:
conf = linphone.LpConfig.new_from_buffer(buffer_linebreaks)
assert_equals(conf.get_string("buffer_linebreaks", "test", ""), "ok")
def test_lpconfig_zerolen_value_from_buffer(self):
zerolen = "[test]\nzero_len=\nnon_zero_len=test"
conf = linphone.LpConfig.new_from_buffer(zerolen)
assert_equals(conf.get_string("test", "zero_len", "LOL"), "LOL")
assert_equals(conf.get_string("test", "non_zero_len", ""), "test")
conf.set_string("test", "non_zero_len", "") # should remove "non_zero_len"
assert_equals(conf.get_string("test", "non_zero_len", "LOL"), "LOL")
def test_lpconfig_zerolen_value_from_file(self):
conf = linphone.LpConfig.new_with_factory(None, os.path.join(tester_resources_path, 'rcfiles', 'zero_length_params_rc'))
assert_equals(conf.get_string("test", "zero_len", "LOL"), "LOL")
# non_zero_len=test -> should return test
assert_equals(conf.get_string("test", "non_zero_len", ""), "test")
conf.set_string("test", "non_zero_len", "") # should remove "non_zero_len"
assert_equals(conf.get_string("test", "non_zero_len", "LOL"), "LOL")
def test_create_chat_room(self):
lc = linphone.Core.new({}, None, None)
assert lc is not None