diff --git a/.cproject b/.cproject index 0d1eed0ed..5fb15ef62 100644 --- a/.cproject +++ b/.cproject @@ -22,7 +22,7 @@ - + diff --git a/.gitignore b/.gitignore index 85a6aed1d..0a2707182 100644 --- a/.gitignore +++ b/.gitignore @@ -78,3 +78,7 @@ Linphone.app *.dmg tester/linphone*.log tester/linphone_log.txt +.tx/linphone-gtk.linphonedesktopin/ +po/linphone.pot +.tx/linphone-gtk.audio-assistantdesktopin/ +tester/linphone_log.gz.txt diff --git a/.tx/config b/.tx/config new file mode 100644 index 000000000..0b35698f1 --- /dev/null +++ b/.tx/config @@ -0,0 +1,20 @@ +[main] +host = https://www.transifex.com +minimum_perc = 1 + +[linphone-gtk.linphonepot] +file_filter = po/.po +source_file = po/linphone.pot +source_lang = en +type = PO + +[linphone-gtk.linphonedesktopin] +source_file = share/linphone.desktop.in +source_lang = en +type = DESKTOP + +[linphone-gtk.audio-assistantdesktopin] +source_file = share/audio-assistant.desktop.in +source_lang = en +type = DESKTOP + diff --git a/CMakeLists.txt b/CMakeLists.txt index 4311101fd..89333bde4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,8 @@ set(LINPHONE_MICRO_VERSION "0") set(LINPHONE_VERSION "${LINPHONE_MAJOR_VERSION}.${LINPHONE_MINOR_VERSION}.${LINPHONE_MICRO_VERSION}") set(LINPHONE_SO_VERSION "6") +set(LINPHONE_ALL_LANGS "cs de es fr he hu it ja nb_NO nl pl pt_BR ru sr sv zh_CN zh_TW") + include(CMakeDependentOption) @@ -39,9 +41,9 @@ option(ENABLE_DATE "Use build date in internal version number." NO) option(ENABLE_GTK_UI "Turn on or off compilation of gtk interface." YES) option(ENABLE_LDAP "Enable LDAP support." NO) option(ENABLE_MSG_STORAGE "Turn on compilation of message storage." YES) -option(ENABLE_NOTIFY "Enable libnotify support." YES) +cmake_dependent_option(ENABLE_NOTIFY "Enable libnotify support." YES "ENABLE_GTK_UI" NO) option(ENABLE_RELATIVE_PREFIX "Find resources relatively to the installation directory." NO) -option(ENABLE_TOOLS "Turn on or off compilation of console interface" YES) +option(ENABLE_TOOLS "Turn on or off compilation of tools." YES) option(ENABLE_TUNNEL "Turn on compilation of tunnel support." NO) option(ENABLE_TUTORIALS "Enable compilation of tutorials." YES) option(ENABLE_UNIT_TESTS "Enable compilation of unit tests." YES) @@ -50,24 +52,65 @@ option(ENABLE_VIDEO "Build with video support." YES) cmake_dependent_option(ENABLE_ASSISTANT "Turn on assistant compiling." YES "ENABLE_GTK_UI" NO) -list(APPEND CMAKE_MODULE_PATH ${CMAKE_PREFIX_PATH}/share/cmake/Modules) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") +list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/share/cmake/Modules") include(CheckIncludeFile) +include(CheckSymbolExists) if(MSVC) - list(APPEND CMAKE_REQUIRED_INCLUDES ${CMAKE_PREFIX_PATH}/include/MSVC) + list(APPEND CMAKE_REQUIRED_INCLUDES "${CMAKE_PREFIX_PATH}/include/MSVC") endif() find_package(BelleSIP REQUIRED) find_package(MS2 REQUIRED) find_package(XML2 REQUIRED) +if(ENABLE_UNIT_TESTS) + find_package(CUnit) + if(CUNIT_FOUND) + cmake_push_check_state(RESET) + list(APPEND CMAKE_REQUIRED_INCLUDES ${CUNIT_INCLUDE_DIRS}) + list(APPEND CMAKE_REQUIRED_LIBRARIES ${CUNIT_LIBRARIES}) + check_symbol_exists("CU_get_suite" "CUnit/CUnit.h" HAVE_CU_GET_SUITE) + check_symbol_exists("CU_curses_run_tests" "CUnit/CUnit.h" HAVE_CU_CURSES) + cmake_pop_check_state() + else() + message(WARNING "Could not find the cunit library!") + set(ENABLE_UNIT_TESTS OFF CACHE BOOL "Enable compilation of unit tests." FORCE) + endif() +endif() if(ENABLE_TUNNEL) find_package(Tunnel) if(NOT TUNNEL_FOUND) message(WARNING "Could not find the tunnel library!") - set(ENABLE_TUNNEL OFF CACHE BOOL "Enable tunnel support" FORCE) + set(ENABLE_TUNNEL OFF CACHE BOOL "Enable tunnel support." FORCE) endif() endif() +if(ENABLE_MSG_STORAGE) + find_package(Sqlite3) + if(NOT SQLITE3_FOUND) + message(FATAL_ERROR "Could not find the sqlite3 library!") + endif() +endif() +if(ENABLE_NOTIFY) + find_package(Notify) + if(NOTIFY_FOUND) + set(HAVE_NOTIFY4 1) + else() + message(WARNING "Could not find the notify library!") + 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) include_directories( @@ -79,15 +122,44 @@ include_directories( ${MS2_INCLUDE_DIRS} ${XML2_INCLUDE_DIRS} ) +if(SQLITE3_FOUND) + include_directories(${SQLITE3_INCLUDE_DIRS}) + add_definitions("-DMSG_STORAGE_ENABLED") +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) endif() +add_definitions("-DIN_LINPHONE") + +if(MSVC) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W3") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W3") +else() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wuninitialized -Wdeclaration-after-statement -fno-strict-aliasing -Werror") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wuninitialized -Werror") + if(CMAKE_C_COMPILER_ID STREQUAL "Clang") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Qunused-arguments -Wno-array-bounds") + endif() + if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Qunused-arguments -Wno-array-bounds") + endif() + if(APPLE) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error=unknown-warning-option -Wno-tautological-compare -Wno-unused-function") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-error=unknown-warning-option -Wno-tautological-compare -Wno-unused-function") + endif() +endif() + + +set(GETTEXT_PACKAGE "linphone") if(ENABLE_RELATIVE_PREFIX) set(LINPHONE_DATA_DIR ".") else() @@ -97,19 +169,36 @@ set(LINPHONE_PLUGINS_DIR "${LINPHONE_DATA_DIR}/lib/liblinphone/plugins") set(PACKAGE_LOCALE_DIR "${LINPHONE_DATA_DIR}/share/locale") set(PACKAGE_DATA_DIR "${LINPHONE_DATA_DIR}/share") set(PACKAGE_SOUND_DIR "${LINPHONE_DATA_DIR}/share/sounds/linphone") +set(PACKAGE_RING_DIR "${PACKAGE_SOUND_DIR}/rings") +set(PACKAGE_FREEDESKTOP_DIR "${PACKAGE_DATA_DIR}/applications") configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/config.h PROPERTIES GENERATED ON) add_definitions(-DHAVE_CONFIG_H) -add_subdirectory(coreapi) -add_subdirectory(share) -if(ENABLE_TOOLS) - add_subdirectory(tools) +if(ENABLE_VIDEO) + add_definitions(-DVIDEO_ENABLED) endif() -install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/FindLinphone.cmake +add_subdirectory(coreapi) +add_subdirectory(share) +if(ENABLE_GTK_UI) + add_subdirectory(gtk) + add_subdirectory(pixmaps) + add_subdirectory(po) +endif() +if(ENABLE_TOOLS) + add_subdirectory(tools) +endif() +if(ENABLE_UNIT_TESTS) + add_subdirectory(tester) +endif() + + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindLinphone.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/FindLinphone.cmake) + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/FindLinphone.cmake DESTINATION share/cmake/Modules PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ ) diff --git a/Makefile.am b/Makefile.am index dd66874b2..74467b7c9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,6 +7,8 @@ SUBDIRS = build m4 pixmaps po @ORTP_DIR@ @MS2_DIR@ \ coreapi console gtk share scripts tools tester include +GITVERSION=`cd $(top_srcdir) && git describe --always || echo $(VERSION)` + ACLOCAL_FLAGS=-I$(top_srcdir)/m4 @@ -20,11 +22,11 @@ OPTIONAL_SOUNDS=\ INSTALLDIR=$(abs_top_builddir)/linphone-install INSTALLDIR_WITH_PREFIX=$(INSTALLDIR)/$(prefix) -ZIPFILE=$(abs_top_builddir)/$(PACKAGE)-win32-$(VERSION).zip +ZIPFILE=$(abs_top_builddir)/$(PACKAGE)-win32-$(GITVERSION).zip ZIP_EXCLUDED=include lib \ $(OPTIONAL_SOUNDS) -SDK_ZIPFILE=$(abs_top_builddir)/lib$(PACKAGE)-win32-$(VERSION).zip +SDK_ZIPFILE=$(abs_top_builddir)/lib$(PACKAGE)-win32-sdk-$(GITVERSION).zip SDK_EXCLUDED= \ bin/linphone.exe \ lib/*.la \ @@ -166,6 +168,15 @@ filelist: zip fi \ done +### LOCALIZATION + +pull-transifex: + tx pull -af + $(MAKE) -C po update-po + +push-transifex: + tx push -s -t -f --no-interactive + ### WINDOWS @@ -173,7 +184,7 @@ setup.exe: filelist cp $(ISS_SCRIPT) $(INSTALLDIR_WITH_PREFIX)/. cd $(INSTALLDIR_WITH_PREFIX) && \ $(ISCC) $(ISS_SCRIPT) - mv $(INSTALLDIR_WITH_PREFIX)/Output/setup.exe $(PACKAGE)-$(VERSION)-setup.exe + mv $(INSTALLDIR_WITH_PREFIX)/Output/setup.exe $(PACKAGE)-setup-$(GITVERSION).exe rm -rf $(INSTALLDIR_WITH_PREFIX)/Output rm -f $(INSTALLDIR_WITH_PREFIX)/$(PACKAGE_WIN32_FILELIST) rm -f $(INSTALLDIR_WITH_PREFIX)/$(ISS_SCRIPT) @@ -201,11 +212,12 @@ Portfile-devel: $(top_srcdir)/scripts/Portfile-devel.tmpl dist ### MAC MACAPPNAME=Linphone.app -MACAPPZIP=$(PACKAGE)-$(VERSION).app.zip -MACAPPDMG=$(PACKAGE)-$(VERSION).dmg +MACAPPZIP=$(PACKAGE)-$(GITVERSION).app.zip +MACAPPDMG=$(PACKAGE)-$(GITVERSION).dmg BUNDLEPREFIX=./ BUNDLEDIR=$(BUNDLEPREFIX)$(MACAPPNAME) - +#a path prefix where additional libs can be cherry-picked by the bundler. +LINPHONE_ADDITIONAL_DEPENDENCIES_PREFIX=/usr/local bundle: rm -rf $(INSTALLDIR) @@ -215,6 +227,7 @@ bundle: LINPHONE_INSTALL_PREFIX=$(INSTALLDIR_WITH_PREFIX) \ LIBLINPHONE_INSTALL_PREFIX=$(INSTALLDIR_WITH_PREFIX) \ MS2_PLUGINS_INSTALL_PREFIX=$(prefix) \ + LINPHONE_ADDITIONAL_DEPENDENCIES_PREFIX=$(LINPHONE_ADDITIONAL_DEPENDENCIES_PREFIX) \ gtk-mac-bundler $(PACKAGE_BUNDLE_FILE) printf "[Pango]\nModuleFiles=./etc/pango/pango.modules\n" \ > $(BUNDLEDIR)/Contents/Resources/etc/pango/pangorc diff --git a/NEWS b/NEWS index 6fada612f..acdbf2e45 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,29 @@ +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. + * Add an assistant to help users to set audio/video parameters + * Some ergonomics improvments (checkbox to set random port for UDP and TCP, ...) + * Lots of updated translations. Arabic translation has been added + * Experimental feature: play an MKV file by drag-and-dropping it on the video call window + + Liblinphone level improvements: + * Support for RTP/AVPF (RFC4585) for video streams, allowing fast transmission error recovery with VP8 codec only. + * API enhancements, most objects can be ref-counted. + * Add some getter funtctions to the call information API + * Add a function in the API to accept early-media calls + * Add a function to set the SIP transport timeout + * Add a function to change adaptive rate algorithm at runtime + * Add support of file transfer + * Call video recording feature, in mkv format (H264 streams only for the moment) + * Call playing feature: play an MKV file and send the audio/video stream through a call + * Local player API. Play WAV and MKV file and display video on a specified window display + * A wrapper for Python has been made + * Support of Wake Locks on Android + * Support of multicast IP addresses + * Support of incoming UPDATEs within dialog (RFC3311) + * Support of SRTP by using packages from GNU/Linux distributions + 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) diff --git a/README b/README index 30666070a..0de3185c3 100644 --- a/README +++ b/README @@ -39,12 +39,7 @@ libglew1.6-dev libv4l-dev libxml2-dev + for optional library $ sudo apt-get install libreadline-dev libgsm1-dev libtheora-dev \ -libsoup2.4-dev libsqlite3-dev libupnp4-dev - - + Install srtp (optional) for call encryption : - $ git clone git://git.linphone.org/srtp.git - $ cd srtp && autoconf && ./configure && make - $ sudo make install +libsoup2.4-dev libsqlite3-dev libupnp4-dev libsrtp-dev + Install zrtp (optional), for unbreakable call encryption $ git clone git://git.linphone.org:bzrtp diff --git a/README.macos.md b/README.macos.md index 6dd8b4625..20660a5a0 100644 --- a/README.macos.md +++ b/README.macos.md @@ -1,12 +1,17 @@ -# Compiling Linphone on MacOS X +# Linphone on MacOS X -## Dependencies +## Build prerequisite * Xcode (download from apple or using appstore application) -* Java SE +* [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/). -### 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 +23,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,25 +40,22 @@ 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 +##### Linphone library (liblinphone) + + brew tap Gui13/linphone + 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 hicolor-icon-theme + #readline is required from linphonec.c otherwise compilation will fail brew link readline --force - # then you have to install antlr3 from a tap. - wget https://gist.githubusercontent.com/Gui13/f5cf103f50d34c28c7be/raw/f50242f5e0c3a6d25ed7fca1462bce3a7b738971/antlr3.rb - mv antlr3.rb /usr/local/Library/Formula/ - brew install antlr3 - - brew tap marekjelen/gtk - brew install gtk+-quartz - - # gtk-mac-integration is not available in main repository or Brew yet. - wget https://gist.github.com/Gui13/cdcad37faa6b8ffa0588/raw/bf2277d45e261ad48ae1344c4c97f2684974ed87/gtk-mac-integration.rb - mv gtk-mac-integration.rb /usr/local/Library/Formula/ - brew install gtk-mac-integration - ### Building Linphone The next pieces need to be compiled manually. @@ -67,7 +68,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 @@ -121,14 +122,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, : - # HomeBrew - 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 --with-readline=/usr/local && make - # MacPorts - 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 --with-readline=/opt/local && 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 @@ -138,7 +137,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`. @@ -148,6 +147,15 @@ If you don't need plugins, remove or comment out this line from the bundler file ${prefix:ms2plugins}/lib/mediastreamer/plugins/*.*.so +If using HomeBrew, this is not working yet. However you will at least need to: + + brew install shared-mime-info glib-networking hicolor-icon-theme + update-mime-database /usr/local/share/mime + + And modify also: + + /usr/local + Then run, inside Linphone source tree configure as told before but with `--enable-relativeprefix` appended. make && make bundle diff --git a/README.mingw b/README.mingw index 5e859680b..6f5414753 100644 --- a/README.mingw +++ b/README.mingw @@ -29,7 +29,8 @@ Download lastest linphone-deps-win32 zip from http://download.savannah.gnu.org/releases-noredirect/linphone/misc using your browser. -Download gtk+-2.24.10 win32 _bundle_ from http://www.gtk.org, direct link: http://ftp.gnome.org/pub/gnome/binaries/win32/gtk+/2.24/gtk+-bundle_2.24.10-20120208_win32.zip +Download gtk+-2.24.10 win32 _bundle_ from http://www.gtk.org, direct link: +http://ftp.gnome.org/pub/gnome/binaries/win32/gtk+/2.24/gtk+-bundle_2.24.10-20120208_win32.zip Install all these three package in /: @@ -46,26 +47,35 @@ tar -xvzf GTK2-Outcrop.tar.gz #To get the translations working, remove from C:/MinGW/lib : libintl.a libintl.la libintl.dll.a -* Download and install Inno Setup Compiler (required only if you run 'make setup.exe'). Add it to your windows Path environment variable. +* Download and install Inno Setup Compiler (required only if you run +'make setup.exe'). Add it to your windows Path environment variable. -* Install msys-git from (http://msysgit.github.io/). During installation you are asked to make a choice about how line endings are treated by git. Choose "Checkout line endings as they are, commit as they are". THIS CHOICE IS VERY IMPORTANT. OTHERS BREAK AUTOMAKE. +* Install msys-git from (http://msysgit.github.io/). During installation you +are asked to make a choice about how line endings are treated by git. Choose +"Checkout line endings as they are, commit as they are". THIS CHOICE IS VERY +IMPORTANT. OTHERS BREAK AUTOMAKE. General rules for compilation ***************************** -- It is recommended that you create a directory somewhere with a path without any spaces or ~ characters, for example c:\sources\. - This is the place where source code must be compiled. -- git commands (to retrieve source code) must be performed within msys-git terminal. -- all other commands (configure, autogen.sh, make) must be done within the mingw shell (msys). -In both msys and msys-git windows, change into the directory you created for sources: -cd /c/sources -- make sure pkg-config works by adding this env variable to your terminal: - export PKG_CONFIG_PATH=/usr/lib/pkgconfig +* It is recommended that you create a directory somewhere with a path without + any spaces or ~ characters, for example c:\sources\. This is the place where + source code must be compiled. +* git commands (to retrieve source code) must be performed within msys-git + terminal. +* all other commands (configure, autogen.sh, make) must be done within the + mingw shell (msys). In both msys and msys-git windows, change into the + directory you created for sources: + cd /c/sources + +* make sure pkg-config works by adding this env variable to your terminal: + export PKG_CONFIG_PATH=/usr/lib/pkgconfig Building belle-sip ****************** - * make sure that java version 1.6 is available in the PATH. java-1.7 will not work with antlr generator. + * make sure that java version 1.6 is available in the PATH. java-1.7 will + not work with antlr generator. * download the sources with msys-git shell using the following command: $ git clone git://git.linphone.org/belle-sip.git * compile and install @@ -80,11 +90,12 @@ Building Linphone $ git clone git://git.linphone.org/linphone.git --recursive * compile - #always run autogen.sh after a git checkout or update + #always run autogen.sh after a git checkout or update $ ./autogen.sh $ ./configure --prefix=/usr --enable-shared --disable-static - #note: in order to use the tunnel (commercial extension), append --enable-tunnel to the configure line above. + #note: in order to use the tunnel (commercial extension), append + #--enable-tunnel to the configure line above. $ make $ make install @@ -92,15 +103,18 @@ Building Linphone #Option: make a portable binary zip of linphone $ make zip - #additionally you can make binary installer if you have Inno Setup 5 installed in its default path + #additionally you can make binary installer if you have Inno Setup 5 + installed in its default path $ make setup.exe - #now you're done, you have a fresh linphone windows installer in the current directory. + #now you're done, you have a fresh linphone windows installer in the + current directory. Building plugins (optional) *************************** - This the example for msx264 (H264 plugin), the same applies for other linphone plugins. + This the example for msx264 (H264 plugin), the same applies for other + linphone plugins. $ git clone git://git.linphone.org/msx264.git $ cd msx264 $ ./autogen.sh @@ -115,17 +129,17 @@ Building plugins (optional) * Notes about linphone-deps generation * ****************************************************** -Linphone-deps is a collection of linphone dependencies, that are for some of them difficult -to find as windows binaries. -These notes are useful if you want to upgrade part of the software that is included in the -linphone-deps packages. +Linphone-deps is a collection of linphone dependencies, that are for some of +them difficult to find as windows binaries. These notes are useful if you want +to upgrade part of the software that is included in the linphone-deps packages. List of software included in linphone-deps: antlr3c (compiled) bzrtp (compiled) polarssl (compiled libsrtp (compiled) -libavcodec, libavutil, libavformat, libavdevice, libswscale (compiled, all these from ffmpeg) +libavcodec, libavutil, libavformat, libavdevice, libswscale (compiled, all +these from ffmpeg) libtheora (from the web) libx264 (compiled from the version distributed from linphone's web site) libogg (from the web) @@ -137,8 +151,10 @@ libsoup (compiled) libsqlite3 (compiled) Remarks: -For every package compiled that goes into linphone-deps, .la files (libtool files) must be removed to avoid libtool errors. -When running "make install DESTDIR=", somepath must be absolute and should not contain any ~ or space. +For every package compiled that goes into linphone-deps, .la files (libtool +files) must be removed to avoid libtool errors. When running "make install +DESTDIR=", somepath must be absolute and should not contain any ~ or +space. - building antlr3c * download the sources with: @@ -192,9 +208,12 @@ When running "make install DESTDIR=", somepath must be absolute and sh ./configure --enable-shared --disable-static --enable-memalign-hack --extra-cflags="-fno-common" --enable-gpl && make make install DESTDIR=/home//ffmpeg-install Copy to ~/ffmpeg-install/usr/local/* to linphone-deps/. - Copy also all *.dll.a files from the build tree to lib/ directort of linphone-deps. These are the implibs necessary to link a program against the dlls. + Copy also all *.dll.a files from the build tree to lib/ directort of + linphone-deps. These are the implibs necessary to link a program against the + dlls. -- building libxml2: the binaries found on the internet are generated with MSVC++, and for obscure reason they are not suitable for building libsoup +- building libxml2: the binaries found on the internet are generated with + MSVC++, and for obscure reason they are not suitable for building libsoup (that requires libxml2). ./configure --enable-shared --disable-static && make && make install DESTDIR=/home//libxml2-install copy ~/libxml2-install/usr/local/* into linphone-deps/. @@ -217,12 +236,14 @@ When running "make install DESTDIR=", somepath must be absolute and sh - add to linphone-deps - building libsoup (only required for buddylookup plugin) - - download source from gnome ftp (warning: at the time of the writing only version 2.26.x can compile with the - glib version supplied in the gtk-bundle, 2.27 requires a new version of glib) + - download source from gnome ftp (warning: at the time of the writing + only version 2.26.x can compile with the glib version supplied in the + gtk-bundle, 2.27 requires a new version of glib) - uncompress libgnutls zip in / - make sure you have libxml2 installed in / - - apply a bugfix patch (fix gnutls support on windows, completely broken otherwise). The patch - is in linphone-deps/src, apply it this way: + - apply a bugfix patch (fix gnutls support on windows, completely + broken otherwise). The patch is in linphone-deps/src, apply it this + way: cd libsoup-2.26.* cd libsoup patch -p0 < libsoup-gnutls-bugfix.patch diff --git a/TODO b/TODO index 1452a7c00..8e18e5491 100644 --- a/TODO +++ b/TODO @@ -3,7 +3,7 @@ hot stuff: * ice support * run a user given command upon incoming calls -* SIP/TLS and SRTP +* SIP/TLS low priority: ------------- diff --git a/autogen.sh b/autogen.sh index 9cedbf164..d5ec9ea80 100755 --- a/autogen.sh +++ b/autogen.sh @@ -33,6 +33,11 @@ fi INTLTOOLIZE=$(which intltoolize) +#workaround for mingw bug in intltoolize script. +if test "$INTLTOOLIZE" = "/bin/intltoolize" ; then + INTLTOOLIZE=/usr/bin/intltoolize +fi + echo "Generating build scripts in linphone..." set -x $LIBTOOLIZE --copy --force diff --git a/build/android/Android.mk b/build/android/Android.mk index fe020f4f4..0347de3c8 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -26,51 +26,53 @@ include $(CLEAR_VARS) LOCAL_CPP_EXTENSION := .cc LOCAL_SRC_FILES := \ - linphonecore.c \ - misc.c \ - enum.c \ - presence.c \ - proxy.c \ - friend.c \ - authentication.c \ - lpconfig.c \ - chat.c \ - sipsetup.c \ - siplogin.c \ address.c \ - linphonecore_jni.cc \ + authentication.c \ bellesip_sal/sal_address_impl.c \ bellesip_sal/sal_impl.c \ bellesip_sal/sal_op_call.c \ bellesip_sal/sal_op_call_transfer.c \ + bellesip_sal/sal_op_events.c \ bellesip_sal/sal_op_impl.c \ + bellesip_sal/sal_op_info.c \ bellesip_sal/sal_op_message.c \ bellesip_sal/sal_op_presence.c \ - bellesip_sal/sal_op_registration.c \ bellesip_sal/sal_op_publish.c \ - bellesip_sal/sal_op_info.c \ - bellesip_sal/sal_op_events.c \ + bellesip_sal/sal_op_registration.c \ bellesip_sal/sal_sdp.c \ - sal.c \ - offeranswer.c \ + buffer.c \ callbacks.c \ - linphonecall.c \ - conference.c \ - ec-calibrator.c \ - linphone_tunnel_config.c \ - message_storage.c \ - info.c \ - event.c \ - xml.c \ - xml2lpc.c \ - lpc2xml.c \ - remote_provisioning.c \ - quality_reporting.c \ call_log.c \ call_params.c \ + chat.c \ + conference.c \ + content.c \ + ec-calibrator.c \ + enum.c \ + event.c \ + friend.c \ + info.c \ + linphonecall.c \ + linphonecore.c \ + linphonecore_jni.cc \ + linphone_tunnel_config.c \ + localplayer.c \ + lpc2xml.c \ lime.c \ - player.c - localplayer.c + lpconfig.c \ + message_storage.c \ + misc.c \ + offeranswer.c \ + player.c \ + presence.c \ + proxy.c \ + quality_reporting.c \ + remote_provisioning.c \ + sal.c \ + siplogin.c \ + sipsetup.c \ + xml2lpc.c \ + xml.c ifndef LIBLINPHONE_VERSION LIBLINPHONE_VERSION = "Devel" @@ -84,7 +86,8 @@ LOCAL_CFLAGS += \ -DHAVE_CONFIG_H \ -DLIBLINPHONE_VERSION=\"$(LIBLINPHONE_VERSION)\" \ -DLINPHONE_PLUGINS_DIR=\"\\tmp\" \ - -DUSE_BELLESIP + -DUSE_BELLESIP \ + -DHAVE_ZLIB LOCAL_CFLAGS += -DIN_LINPHONE @@ -118,7 +121,7 @@ LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/../../externals/build/libxml2 \ $(LOCAL_PATH)/../../externals/polarssl/include -LOCAL_LDLIBS += -llog -ldl +LOCAL_LDLIBS += -llog -ldl -lz LOCAL_STATIC_LIBRARIES := \ cpufeatures \ @@ -218,16 +221,18 @@ LOCAL_CFLAGS += -DBUILD_UPNP LOCAL_SRC_FILES += upnp.c endif -LOCAL_STATIC_LIBRARIES += libspeex +LOCAL_STATIC_LIBRARIES += libspeex ifeq ($(BUILD_SRTP), 1) LOCAL_C_INCLUDES += $(SRTP_C_INCLUDE) endif +ifeq ($(BUILD_ILBC), 1) ifneq ($(TARGET_ARCH_ABI),armeabi) LOCAL_CFLAGS += -DHAVE_ILBC=1 LOCAL_STATIC_LIBRARIES += libmsilbc endif +endif LOCAL_C_INCLUDES += $(LIBLINPHONE_EXTENDED_C_INCLUDES) LOCAL_WHOLE_STATIC_LIBRARIES += $(LIBLINPHONE_EXTENDED_STATIC_LIBS) @@ -253,8 +258,8 @@ endif ifeq ($(BUILD_OPUS),1) LOCAL_STATIC_LIBRARIES += libopus endif -LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES) -LOCAL_EXPORT_CFLAGS := $(LOCAL_CFLAGS) +LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES) +LOCAL_EXPORT_CFLAGS := $(LOCAL_CFLAGS) ifeq ($(_BUILD_VIDEO),1) LOCAL_SHARED_LIBRARIES += \ diff --git a/build/android/liblinphone_tester.mk b/build/android/liblinphone_tester.mk index 430f203be..d62f055d8 100644 --- a/build/android/liblinphone_tester.mk +++ b/build/android/liblinphone_tester.mk @@ -17,7 +17,10 @@ common_SRC_FILES := \ log_collection_tester.c \ transport_tester.c \ player_tester.c \ - dtmf_tester.c + dtmf_tester.c \ + accountmanager.c \ + offeranswer_tester.c \ + multicast_call_tester.c common_C_INCLUDES += \ $(LOCAL_PATH) \ @@ -34,10 +37,10 @@ LOCAL_MODULE_FILENAME := liblinphone_tester-$(TARGET_ARCH_ABI) LOCAL_SRC_FILES += $(common_SRC_FILES) LOCAL_C_INCLUDES = $(common_C_INCLUDES) LOCAL_CFLAGS = -DIN_LINPHONE -LOCAL_LDLIBS := -llog +LOCAL_LDLIBS := -llog -lz ifeq ($(BUILD_MATROSKA), 1) -LOCAL_CFLAGS += -DHAVE_MATROSKA +LOCAL_CFLAGS += -DHAVE_MATROSKA -DHAVE_ZLIB endif LOCAL_SHARED_LIBRARIES := cunit liblinphone diff --git a/build/macos/Info-linphone.plist.in b/build/macos/Info-linphone.plist.in index b9cde78a9..7d20d4ac6 100644 --- a/build/macos/Info-linphone.plist.in +++ b/build/macos/Info-linphone.plist.in @@ -26,6 +26,8 @@ Copyright 2011 Belledonne Communications LSMinimumSystemVersion 10.4 + NSAppSleepDisabled + YES diff --git a/build/macos/environment.sh b/build/macos/environment.sh index 3b9ff16af..b466fecc4 100644 --- a/build/macos/environment.sh +++ b/build/macos/environment.sh @@ -1,4 +1,5 @@ -export EXTRA_ARGS="--workdir $bundle_res" +#export EXTRA_ARGS="--workdir $bundle_res" +export LINPHONE_WORKDIR="$bundle_res" export GIO_EXTRA_MODULES="$bundle_lib/gio/modules" export PANGO_LIBDIR="$bundle_lib" export PANGO_SYSCONFDIR="$bundle_etc" diff --git a/build/macos/linphone.bundle b/build/macos/linphone.bundle index 8896fa7d3..7a5906e9e 100644 --- a/build/macos/linphone.bundle +++ b/build/macos/linphone.bundle @@ -16,7 +16,7 @@ ${env:LINPHONE_INSTALL_PREFIX} ${env:MS2_PLUGINS_INSTALL_PREFIX} - /usr/local + ${env:LINPHONE_ADDITIONAL_DEPENDENCIES_PREFIX} + + linphone.desktop + CC0-1.0 + GPL-2.0 + Linphone + SIP video soft-phone + +
    +
  • Make audio and video calls in HD
  • +
  • Create audio conferences
  • +
  • Record and store calls
  • +
  • View real-time presence status
  • +
  • Manage your address book
  • +
  • Communicate securely
  • +
  • Free subscription
  • +
+
+ + + http://www.linphone.org/uploads/images/desktop_main_window.png + Main window + + + http://www.linphone.org/uploads/images/desktop_call_view.png + Call view + + + http://www.linphone.org/uploads/images/desktop_chat_view.png + Chat view + + + http://www.linphone.org + contact@belledonne-communications.com +
diff --git a/share/linphone.desktop.in b/share/linphone.desktop.in index c162ed904..748076ecf 100644 --- a/share/linphone.desktop.in +++ b/share/linphone.desktop.in @@ -1,47 +1,26 @@ [Desktop Entry] Name=Linphone +GenericName=Web-phone Comment=Linphone is a web-phone -Comment[fr]=Linphone est un web-phone. -Comment[de]=Linphone ist ein web-phone. -Comment[af]=Linphone is 'n webtelefoon -Comment[sq]=Linphone është një telefon interneti -Comment[ast]=Linphone ye un teléfonu web -Comment[bn]=Linphone একটি ওয়েব ফোন -Comment[bs]=Linphone je mrežni telefon -Comment[pt_BR]=Linphone é um telefone web -Comment[bg]=Linphone е уеб телефон -Comment[ca@valencia]=El Linphone és un telèfon web -Comment[ca]=El Linphone és un telèfon web -Comment[zh_HK]=Linphone 是網絡電話(web-phone) -Comment[zh_TW]=Linphone 是網路電話(web-phone) -Comment[zh_CN]=Linphone 是一个网络电话程序 -Comment[crh]=Linphone bir web-telefonudur -Comment[nl]=Linphone is een webtelefoon -Comment[da]=Linphone er en nettelefon -Comment[cs]=Linphone webový telefon -Comment[fi]=Linphone on verkkopuhelin -Comment[gl]=Linphone é un teléfono-web -Comment[el]=Το Linphone είναι ένα διαδικτυακό τηλέφωνο -Comment[hu]=A Linphone egy webes telefon -Comment[is]=Linphone er vefsími -Comment[it]=Linphone è un telefono web -Comment[ja]=Linphone はウェブ電話です -Comment[ky]=Linphone - бул веб - телефон -Comment[ms]=Linphone adalah telefon-sesawang -Comment[oc]=Linphone es una aisina de telefonia IP -Comment[pl]=Rozbudowany telefon internetowy z funkcją wideorozmowy -Comment[nb]=Lintelefon er en nett-telefon -Comment[pt]=Linphone é um telefone da internet -Comment[ro]=Linphone este un telefon web -Comment[ru]=Linphone — это веб-телефон -Comment[sl]=Linphone je spletni telefon -Comment[sv]=Webbtelefon -Comment[es]=Linphone es un teléfono web -Comment[vi]=Linphone là một điện thoại web -Comment[uk]=Інтернет-телефон -Comment[tr]=Linphone bir web-telefonudur Type=Application Exec=linphone Icon=@prefix@/share/pixmaps/linphone/linphone.png Terminal=false Categories=Network;Telephony; + + +# Translations +Name[de]=Linphone +Name[he]=Linphone +Name[ar]=لِنْفُونْ +Name[hu]=Linphone +Name[ru]=Linphone +Name[nb_NO]=Linphone +Name[it]=Linphone +Name[ja]=Linphone +Name[cs]=Linphone +Name[sr]=Линфон +Name[sv]=Linphone +Name[zh_CN]=Linphone +Name[fr]=Linphone +Name[zh_TW]=Linphone diff --git a/share/rings/CMakeLists.txt b/share/rings/CMakeLists.txt index 63f2c47ac..6ec2182e2 100644 --- a/share/rings/CMakeLists.txt +++ b/share/rings/CMakeLists.txt @@ -20,7 +20,20 @@ # ############################################################################ -install(FILES oldphone.wav toy-mono.wav - COMPONENT COMP_liblinphone - DESTINATION share/sounds/linphone/rings - PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) +set(RING_FILES + bigben.wav + oldphone-mono-30s.caf + oldphone-mono.wav + oldphone.wav + orig.wav + rock.wav + sweet.wav + synth.wav + tapping.wav + toy-mono.wav +) + +install(FILES ${RING_FILES} + DESTINATION ${PACKAGE_RING_DIR} + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ +) diff --git a/share/rootca.cmake b/share/rootca.cmake new file mode 100644 index 000000000..d988b778e --- /dev/null +++ b/share/rootca.cmake @@ -0,0 +1,40 @@ +############################################################################ +# rootca.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. +# +############################################################################ + +if(HTTPS_CA_DIR) + set(ENV{HTTPS_CA_DIR} "${HTTPS_CA_DIR}") +endif() + +execute_process( + COMMAND ${CMAKE_COMMAND} -E remove "fresh-rootca.pem" + WORKING_DIRECTORY ${OUTPUT_DIR} +) +execute_process( + COMMAND "../scripts/mk-ca-bundle.pl" "${OUTPUT_DIR}/fresh-rootca.pem" + WORKING_DIRECTORY ${WORK_DIR} +) +if(EXISTS "${OUTPUT_DIR}/fresh-rootca.pem") + file(RENAME "${OUTPUT_DIR}/fresh-rootca.pem" "${OUTPUT_DIR}/rootca.pem") +else() + file(COPY "${WORK_DIR}/archived-rootca.pem" DESTINATION "${OUTPUT_DIR}") + file(RENAME "${OUTPUT_DIR}/archived-rootca.pem" "${OUTPUT_DIR}/rootca.pem") +endif() diff --git a/tester/CMakeLists.txt b/tester/CMakeLists.txt new file mode 100644 index 000000000..3dfe85142 --- /dev/null +++ b/tester/CMakeLists.txt @@ -0,0 +1,56 @@ +############################################################################ +# CMakeLists.txt +# 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_package(GTK2 2.18 COMPONENTS gtk) + +set(SOURCE_FILES + accountmanager.c + call_tester.c + dtmf_tester.c + eventapi_tester.c + flexisip_tester.c + liblinphone_tester.c + log_collection_tester.c + message_tester.c + multicast_call_tester.c + offeranswer_tester.c + player_tester.c + presence_tester.c + quality_reporting_tester.c + register_tester.c + remote_provisioning_tester.c + setup_tester.c + stun_tester.c + tester.c + transport_tester.c + upnp_tester.c + video_tester.c +) + +add_executable(liblinphone_tester ${SOURCE_FILES}) +target_include_directories(liblinphone_tester PUBLIC ${CUNIT_INCLUDE_DIRS}) +target_link_libraries(liblinphone_tester linphone ${CUNIT_LIBRARIES}) +if (GTK2_FOUND) + target_compile_definitions(liblinphone_tester PRIVATE HAVE_GTK) + target_include_directories(liblinphone_tester PUBLIC ${GTK2_INCLUDE_DIRS}) + target_link_libraries(liblinphone_tester linphone ${GTK2_LIBRARIES}) +endif() diff --git a/tester/Makefile.am b/tester/Makefile.am index ec5366726..c55c992e3 100644 --- a/tester/Makefile.am +++ b/tester/Makefile.am @@ -15,6 +15,7 @@ liblinphonetester_la_SOURCES = tester.c \ register_tester.c \ message_tester.c \ call_tester.c \ + multicast_call_tester.c \ presence_tester.c \ upnp_tester.c \ eventapi_tester.c \ @@ -25,7 +26,10 @@ liblinphonetester_la_SOURCES = tester.c \ log_collection_tester.c \ transport_tester.c \ player_tester.c \ - dtmf_tester.c + dtmf_tester.c \ + accountmanager.c \ + offeranswer_tester.c \ + video_tester.c liblinphonetester_la_LDFLAGS= -no-undefined liblinphonetester_la_LIBADD= ../coreapi/liblinphone.la $(CUNIT_LIBS) @@ -33,6 +37,13 @@ liblinphonetester_la_LIBADD= ../coreapi/liblinphone.la $(CUNIT_LIBS) AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/coreapi AM_CFLAGS = $(STRICT_OPTIONS) $(STRICT_OPTIONS_CC) -DIN_LINPHONE $(ORTP_CFLAGS) $(MEDIASTREAMER_CFLAGS) $(CUNIT_CFLAGS) $(BELLESIP_CFLAGS) $(LIBXML2_CFLAGS) $(SQLITE3_CFLAGS) +if BUILD_GTK_UI + +liblinphonetester_la_LIBADD += $(LIBGTK_LIBS) $(LIBGTKMAC_LIBS) +AM_CFLAGS += $(LIBGTK_CFLAGS) $(LIBGTKMAC_CFLAGS) -DHAVE_GTK + +endif + if !BUILD_IOS noinst_PROGRAMS = liblinphone_tester @@ -44,7 +55,7 @@ endif test: liblinphone_tester - ./liblinphone_tester --config $(abs_srcdir) + ./liblinphone_tester --config $(abs_srcdir) $(TEST_OPTIONS) else !BUILD_CUNIT_TESTS diff --git a/tester/accountmanager.c b/tester/accountmanager.c new file mode 100644 index 000000000..80bc7942e --- /dev/null +++ b/tester/accountmanager.c @@ -0,0 +1,224 @@ + /* + tester - liblinphone test suite + Copyright (C) 2013 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, see . + */ + +#include "liblinphone_tester.h" +#include "private.h" + +struct _Account{ + LinphoneAddress *identity; + LinphoneAddress *modified_identity; + char *password; + int created; + int done; + int auth_requested; +}; + +typedef struct _Account Account; + +Account *account_new(LinphoneAddress *identity, const char *unique_id){ + char *modified_username; + Account *obj=ms_new0(Account,1); + + /* we need to inhibit leak detector because the two LinphoneAddress will remain behond the scope of the test being run */ + belle_sip_object_inhibit_leak_detector(TRUE); + obj->identity=linphone_address_clone(identity); + obj->password=sal_get_random_token(8); + obj->modified_identity=linphone_address_clone(identity); + modified_username=ms_strdup_printf("%s_%s",linphone_address_get_username(identity), unique_id); + linphone_address_set_username(obj->modified_identity, modified_username); + ms_free(modified_username); + belle_sip_object_inhibit_leak_detector(FALSE); + return obj; +}; + +void account_destroy(Account *obj){ + linphone_address_unref(obj->identity); + linphone_address_unref(obj->modified_identity); + ms_free(obj->password); + ms_free(obj); +} + +struct _AccountManager{ + char *unique_id; + MSList *accounts; +}; + +typedef struct _AccountManager AccountManager; + +static AccountManager *the_am=NULL; + +AccountManager *account_manager_get(void){ + if (the_am==NULL){ + the_am=ms_new0(AccountManager,1); + the_am->unique_id=sal_get_random_token(6); + } + return the_am; +} + +void account_manager_destroy(void){ + if (the_am){ + ms_free(the_am->unique_id); + ms_list_free_with_data(the_am->accounts,(void(*)(void*))account_destroy); + ms_free(the_am); + } + the_am=NULL; + ms_message("Test account manager destroyed."); +} + +Account *account_manager_get_account(AccountManager *m, const LinphoneAddress *identity){ + MSList *it; + + for(it=m->accounts;it!=NULL;it=it->next){ + Account *a=(Account*)it->data; + if (linphone_address_weak_equal(a->identity,identity)){ + return a; + } + } + return NULL; +} + +static void account_created_on_server_cb(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState state, const char *info){ + Account *account=(Account*)linphone_core_get_user_data(lc); + switch(state){ + case LinphoneRegistrationOk: + account->created=1; + break; + case LinphoneRegistrationCleared: + account->done=1; + break; + default: + break; + } +} + +static void account_created_auth_requested_cb(LinphoneCore *lc, const char *username, const char *realm, const char *domain){ + Account *account=(Account*)linphone_core_get_user_data(lc); + account->auth_requested=1; +} + +void account_create_on_server(Account *account, const LinphoneProxyConfig *refcfg){ + LinphoneCoreVTable vtable={0}; + LinphoneCore *lc; + LinphoneAddress *tmp_identity=linphone_address_clone(account->modified_identity); + LinphoneProxyConfig *cfg; + LinphoneAuthInfo *ai; + char *tmp; + LinphoneAddress *server_addr; + LCSipTransports tr; + + vtable.registration_state_changed=account_created_on_server_cb; + vtable.auth_info_requested=account_created_auth_requested_cb; + lc=configure_lc_from(&vtable,liblinphone_tester_file_prefix,NULL,account); + tr.udp_port=LC_SIP_TRANSPORT_RANDOM; + tr.tcp_port=LC_SIP_TRANSPORT_RANDOM; + tr.tls_port=LC_SIP_TRANSPORT_RANDOM; + linphone_core_set_sip_transports(lc,&tr); + + cfg=linphone_core_create_proxy_config(lc); + linphone_address_set_secure(tmp_identity, FALSE); + linphone_address_set_password(tmp_identity,account->password); + linphone_address_set_header(tmp_identity,"X-Create-Account","yes"); + tmp=linphone_address_as_string(tmp_identity); + linphone_proxy_config_set_identity(cfg,tmp); + ms_free(tmp); + linphone_address_unref(tmp_identity); + + server_addr=linphone_address_new(linphone_proxy_config_get_server_addr(refcfg)); + linphone_address_set_secure(server_addr, FALSE); + linphone_address_set_transport(server_addr,LinphoneTransportTcp); /*use tcp for account creation, we may not have certificates configured at this stage*/ + linphone_address_set_port(server_addr,0); + tmp=linphone_address_as_string(server_addr); + linphone_proxy_config_set_server_addr(cfg,tmp); + ms_free(tmp); + linphone_address_unref(server_addr); + linphone_proxy_config_set_expires(cfg,3600); + + linphone_core_add_proxy_config(lc,cfg); + + if (wait_for_until(lc,NULL,&account->auth_requested,1,10000)==FALSE){ + ms_fatal("Account for %s could not be created on server.", linphone_proxy_config_get_identity(refcfg)); + } + linphone_proxy_config_edit(cfg); + tmp_identity=linphone_address_clone(account->modified_identity); + linphone_address_set_secure(tmp_identity, FALSE); + tmp=linphone_address_as_string(tmp_identity); + linphone_proxy_config_set_identity(cfg,tmp); /*remove the X-Create-Account header*/ + linphone_address_unref(tmp_identity); + ms_free(tmp); + linphone_proxy_config_done(cfg); + + ai=linphone_auth_info_new(linphone_address_get_username(account->modified_identity), + NULL, + account->password,NULL,NULL,linphone_address_get_domain(account->modified_identity)); + linphone_core_add_auth_info(lc,ai); + linphone_auth_info_destroy(ai); + + if (wait_for_until(lc,NULL,&account->created,1,3000)==FALSE){ + ms_fatal("Account for %s is not working on server.", linphone_proxy_config_get_identity(refcfg)); + } + linphone_core_remove_proxy_config(lc,cfg); + linphone_proxy_config_unref(cfg); + if (wait_for_until(lc,NULL,&account->done,1,3000)==FALSE){ + ms_error("Account creation could not clean the registration context."); + } + linphone_core_destroy(lc); +} + +LinphoneAddress *account_manager_check_account(AccountManager *m, LinphoneProxyConfig *cfg){ + LinphoneCore *lc=linphone_proxy_config_get_core(cfg); + const char *identity=linphone_proxy_config_get_identity(cfg); + LinphoneAddress *id_addr=linphone_address_new(identity); + Account *account=account_manager_get_account(m,id_addr); + LinphoneAuthInfo *ai; + char *tmp; + bool_t create_account=FALSE; + + if (!account){ + account=account_new(id_addr,m->unique_id); + ms_message("No account for %s exists, going to create one.",identity); + create_account=TRUE; + m->accounts=ms_list_append(m->accounts,account); + } + /*modify the username of the identity of the proxy config*/ + linphone_address_set_username(id_addr, linphone_address_get_username(account->modified_identity)); + tmp=linphone_address_as_string(id_addr); + linphone_proxy_config_set_identity(cfg,tmp); + ms_free(tmp); + + if (create_account){ + account_create_on_server(account,cfg); + } + ai=linphone_auth_info_new(linphone_address_get_username(account->modified_identity), + NULL, + account->password,NULL,NULL,linphone_address_get_domain(account->modified_identity)); + linphone_core_add_auth_info(lc,ai); + linphone_auth_info_destroy(ai); + + linphone_address_unref(id_addr); + return account->modified_identity; +} + +void linphone_core_manager_check_accounts(LinphoneCoreManager *m){ + const MSList *it; + AccountManager *am=account_manager_get(); + + for(it=linphone_core_get_proxy_config_list(m->lc);it!=NULL;it=it->next){ + LinphoneProxyConfig *cfg=(LinphoneProxyConfig *)it->data; + account_manager_check_account(am,cfg); + } +} diff --git a/tester/call_tester.c b/tester/call_tester.c index fbc413905..7171e22b9 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -25,15 +25,14 @@ #include "lpconfig.h" #include "private.h" #include "liblinphone_tester.h" -#include "mediastreamer2/dsptools.h" +#include "mediastreamer2/msutils.h" +#include "belle-sip/sipstack.h" #ifdef WIN32 #define unlink _unlink #endif static void srtp_call(void); -static void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t enable_relay,LinphoneFirewallPolicy policy); -static void disable_all_audio_codecs_except_one(LinphoneCore *lc, const char *mime, int rate); static char *create_filepath(const char *dir, const char *filename, const char *ext); // prototype definition for call_recording() @@ -79,6 +78,16 @@ void call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState CU_FAIL("unexpected event");break; } } + +void call_stats_updated(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallStats *lstats) { + stats* counters = get_stats(lc); + if (lstats->updated == LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE) { + counters->number_of_rtcp_received++; + } else if (lstats->updated == LINPHONE_CALL_STATS_SENT_RTCP_UPDATE) { + counters->number_of_rtcp_sent++; + } +} + void linphone_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t on, const char *authentication_token) { char* to=linphone_address_as_string(linphone_call_get_call_log(call)->to); char* from=linphone_address_as_string(linphone_call_get_call_log(call)->from); @@ -95,6 +104,7 @@ void linphone_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool else counters->number_of_LinphoneCallEncryptedOff++; } + void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state) { char* to=linphone_address_as_string(linphone_call_get_call_log(transfered)->to); char* from=linphone_address_as_string(linphone_call_get_call_log(transfered)->from); @@ -117,8 +127,8 @@ void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered, } } -#ifdef VIDEO_ENABLED -static void linphone_call_cb(LinphoneCall *call,void * user_data) { + +void linphone_call_cb(LinphoneCall *call,void * user_data) { char* to=linphone_address_as_string(linphone_call_get_call_log(call)->to); char* from=linphone_address_as_string(linphone_call_get_call_log(call)->from); stats* counters; @@ -129,7 +139,6 @@ static void linphone_call_cb(LinphoneCall *call,void * user_data) { counters = (stats*)get_stats(lc); counters->number_of_IframeDecoded++; } -#endif void liblinphone_tester_check_rtcp(LinphoneCoreManager* caller, LinphoneCoreManager* callee) { LinphoneCall *c1,*c2; @@ -169,6 +178,14 @@ void liblinphone_tester_check_rtcp(LinphoneCoreManager* caller, LinphoneCoreMana linphone_call_unref(c2); } +static void setup_sdp_handling(const LinphoneCallTestParams* params, LinphoneCoreManager* mgr ){ + if( params->sdp_removal ){ + sal_default_set_sdp_handling(mgr->lc->sal, SalOpSDPSimulateRemove); + } else if( params->sdp_simulate_error ){ + sal_default_set_sdp_handling(mgr->lc->sal, SalOpSDPSimulateError); + } +} + bool_t call_with_params2(LinphoneCoreManager* caller_mgr ,LinphoneCoreManager* callee_mgr , const LinphoneCallTestParams *caller_test_params @@ -178,37 +195,29 @@ 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; + bool_t did_receive_call; - 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); + setup_sdp_handling(caller_test_params, caller_mgr); + setup_sdp_handling(callee_test_params, callee_mgr); - /*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{ CU_ASSERT_PTR_NOT_NULL(linphone_core_invite_address_with_params(caller_mgr->lc,callee_mgr->identity,caller_params)); } - - /*linphone_core_invite(caller_mgr->lc,"pauline");*/ - - did_received_call = wait_for(callee_mgr->lc + did_receive_call = wait_for(callee_mgr->lc ,caller_mgr->lc ,&callee_mgr->stat.number_of_LinphoneCallIncomingReceived ,initial_callee.number_of_LinphoneCallIncomingReceived+1); - CU_ASSERT_EQUAL(did_received_call, !callee_test_params->sdp_removal); + CU_ASSERT_EQUAL(did_receive_call, !callee_test_params->sdp_simulate_error); - sal_default_enable_sdp_removal(caller_mgr->lc->sal, FALSE); - sal_default_enable_sdp_removal(callee_mgr->lc->sal, FALSE); + sal_default_set_sdp_handling(caller_mgr->lc->sal, SalOpSDPNormal); + sal_default_set_sdp_handling(callee_mgr->lc->sal, SalOpSDPNormal); - if (!did_received_call) return 0; + if (!did_receive_call) return 0; CU_ASSERT_TRUE(linphone_core_inc_invite_pending(callee_mgr->lc)); @@ -225,13 +234,13 @@ bool_t call_with_params2(LinphoneCoreManager* caller_mgr CU_ASSERT_TRUE((caller_mgr->stat.number_of_LinphoneCallOutgoingRinging==initial_caller.number_of_LinphoneCallOutgoingRinging+1) - |(caller_mgr->stat.number_of_LinphoneCallOutgoingEarlyMedia==initial_caller.number_of_LinphoneCallOutgoingEarlyMedia+1)); + ||(caller_mgr->stat.number_of_LinphoneCallOutgoingEarlyMedia==initial_caller.number_of_LinphoneCallOutgoingEarlyMedia+1)); CU_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call_remote_address(callee_mgr->lc)); if(!linphone_core_get_current_call(caller_mgr->lc) || !linphone_core_get_current_call(callee_mgr->lc) || !linphone_core_get_current_call_remote_address(callee_mgr->lc)) { return 0; - } else { + } else if (caller_mgr->identity){ LinphoneAddress* callee_from=linphone_address_clone(caller_mgr->identity); linphone_address_set_port(callee_from,0); /*remove port because port is never present in from header*/ @@ -264,16 +273,16 @@ bool_t call_with_params2(LinphoneCoreManager* caller_mgr if (linphone_core_get_media_encryption(caller_mgr->lc) != LinphoneMediaEncryptionNone && linphone_core_get_media_encryption(callee_mgr->lc) != LinphoneMediaEncryptionNone) { - /*wait for encryption to be on, in case of zrtp, it can take a few seconds*/ - if (linphone_core_get_media_encryption(caller_mgr->lc) == LinphoneMediaEncryptionZRTP) + /*wait for encryption to be on, in case of zrtp or dtls, it can take a few seconds*/ + if ((linphone_core_get_media_encryption(caller_mgr->lc) == LinphoneMediaEncryptionZRTP) || (linphone_core_get_media_encryption(caller_mgr->lc) == LinphoneMediaEncryptionDTLS)) wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallEncryptedOn,initial_caller.number_of_LinphoneCallEncryptedOn+1); - if (linphone_core_get_media_encryption(callee_mgr->lc) == LinphoneMediaEncryptionZRTP) + if ((linphone_core_get_media_encryption(callee_mgr->lc) == LinphoneMediaEncryptionZRTP) || (linphone_core_get_media_encryption(callee_mgr->lc) == LinphoneMediaEncryptionDTLS)) wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallEncryptedOn,initial_callee.number_of_LinphoneCallEncryptedOn+1); { - const LinphoneCallParams* call_param = linphone_call_get_current_params(linphone_core_get_current_call(callee_mgr->lc)); - CU_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(caller_mgr->lc)); - call_param = linphone_call_get_current_params(linphone_core_get_current_call(caller_mgr->lc)); - CU_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(callee_mgr->lc)); + const LinphoneCallParams* call_param = linphone_call_get_current_params(linphone_core_get_current_call(callee_mgr->lc)); + CU_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(caller_mgr->lc)); + call_param = linphone_call_get_current_params(linphone_core_get_current_call(caller_mgr->lc)); + CU_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(callee_mgr->lc)); } } return result; @@ -312,19 +321,41 @@ void end_call(LinphoneCoreManager *m1, LinphoneCoreManager *m2){ CU_ASSERT_TRUE(wait_for(m1->lc,m2->lc,&m2->stat.number_of_LinphoneCallReleased,1)); } -static void simple_call(void) { +void simple_call_base(bool_t enable_multicast_recv_side) { int begin; int leaked_objects; LinphoneCoreManager* marie; 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); + } + + linphone_core_enable_audio_multicast(pauline->lc,enable_multicast_recv_side); + CU_ASSERT_TRUE(call(marie,pauline)); pauline_call=linphone_core_get_current_call(pauline->lc); CU_ASSERT_PTR_NOT_NULL(pauline_call); @@ -353,6 +384,51 @@ static void simple_call(void) { belle_sip_object_dump_active_objects(); } } +static void simple_call() { + simple_call_base(FALSE); +} +static void call_with_timeouted_bye(void) { + int begin; + int leaked_objects; + LinphoneCoreManager* marie; + LinphoneCoreManager* pauline; + belle_sip_timer_config_t timer_config; + 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"); + + CU_ASSERT_TRUE(call(marie,pauline)); + + sal_set_send_error(pauline->lc->sal,1500); /*to trash the message without generating error*/ + timer_config.T1=50; /*to have timer F = 3s*/ + timer_config.T2=4000; + timer_config.T3=0; + timer_config.T4=5000; + + belle_sip_stack_set_timer_config(sal_get_belle_sip_stack(pauline->lc->sal),&timer_config); + linphone_core_terminate_all_calls(pauline->lc); + + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallReleased,1,timer_config.T1*84)); + + sal_set_send_error(pauline->lc->sal,0); + + linphone_core_terminate_all_calls(marie->lc); + CU_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1,5000)); + CU_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallReleased,1,5000)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + + leaked_objects=belle_sip_object_get_object_count()-begin; + CU_ASSERT_TRUE(leaked_objects==0); + if (leaked_objects>0){ + belle_sip_object_dump_active_objects(); + } +} + static void direct_call_over_ipv6(){ LinphoneCoreManager* marie; @@ -364,8 +440,6 @@ static void direct_call_over_ipv6(){ marie = linphone_core_manager_new( "marie_rc"); pauline = linphone_core_manager_new( "pauline_tcp_rc"); - 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); @@ -374,7 +448,7 @@ static void direct_call_over_ipv6(){ CU_ASSERT_TRUE(wait_for_until(pauline->lc, NULL, &pauline->stat.number_of_LinphoneRegistrationOk, 2, 2000)); CU_ASSERT_TRUE(wait_for_until(pauline->lc, NULL, &marie->stat.number_of_LinphoneRegistrationOk, 2, 2000)); #endif - + linphone_core_get_sip_transports_used(pauline->lc,&pauline_transports); linphone_address_set_port(pauline_dest,pauline_transports.tcp_port); linphone_core_invite_address(marie->lc,pauline_dest); @@ -437,7 +511,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" ); @@ -448,11 +521,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)); @@ -488,7 +556,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" ); @@ -499,16 +566,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 ) ); @@ -627,7 +688,7 @@ static void simple_call_compatibility_mode(void) { CU_ASSERT_TRUE (wait_for(lc_marie,lc_marie,&stat_marie->number_of_LinphoneRegistrationOk,1)); - linphone_core_invite(lc_marie,"pauline"); + linphone_core_invite_address(lc_marie,pauline->identity); CU_ASSERT_TRUE (wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallIncomingReceived,1)); CU_ASSERT_TRUE(linphone_core_inc_invite_pending(lc_pauline)); @@ -660,7 +721,7 @@ static void cancelled_call(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); + LinphoneCall* out_call = linphone_core_invite_address(pauline->lc,marie->identity); linphone_call_ref(out_call); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallOutgoingInit,1)); @@ -676,7 +737,7 @@ static void cancelled_call(void) { linphone_core_manager_destroy(pauline); } -static void disable_all_audio_codecs_except_one(LinphoneCore *lc, const char *mime, int rate){ +void disable_all_audio_codecs_except_one(LinphoneCore *lc, const char *mime, int rate){ const MSList *elem=linphone_core_get_audio_codecs(lc); PayloadType *pt; @@ -690,7 +751,7 @@ static void disable_all_audio_codecs_except_one(LinphoneCore *lc, const char *mi } #ifdef VIDEO_ENABLED -static void disable_all_video_codecs_except_one(LinphoneCore *lc, const char *mime) { +void disable_all_video_codecs_except_one(LinphoneCore *lc, const char *mime) { const MSList *codecs = linphone_core_get_video_codecs(lc); const MSList *it = NULL; PayloadType *pt = NULL; @@ -703,40 +764,6 @@ static void disable_all_video_codecs_except_one(LinphoneCore *lc, const char *mi } #endif -static void call_failed_because_of_codecs(void) { - int begin,leaked_objects; - - belle_sip_object_enable_leak_detector(TRUE); - begin=belle_sip_object_get_object_count(); - - { - LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - LinphoneCall* out_call; - - disable_all_audio_codecs_except_one(marie->lc,"pcmu",-1); - disable_all_audio_codecs_except_one(pauline->lc,"pcma",-1); - out_call = linphone_core_invite(pauline->lc,"marie"); - linphone_call_ref(out_call); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallOutgoingInit,1)); - - /*flexisip will retain the 488 until the "urgent reply" timeout (I.E 5s) arrives.*/ - CU_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallError,1,7000)); - CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonNotAcceptable); - CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingReceived,0); - CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallReleased,0); - - linphone_call_unref(out_call); - linphone_core_manager_destroy(marie); - linphone_core_manager_destroy(pauline); - } - leaked_objects=belle_sip_object_get_object_count()-begin; - CU_ASSERT_TRUE(leaked_objects==0); - if (leaked_objects>0){ - belle_sip_object_dump_active_objects(); - } -} - static void call_with_dns_time_out(void) { LinphoneCoreManager* marie = linphone_core_manager_new2( "empty_rc", FALSE); LCSipTransports transport = {9773,0,0,0}; @@ -787,7 +814,7 @@ static void cancelled_ringing_call(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); + LinphoneCall* out_call = linphone_core_invite_address(pauline->lc,marie->identity); linphone_call_ref(out_call); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallIncomingReceived,1)); @@ -809,7 +836,7 @@ static void early_declined_call(void) { LinphoneCall* out_call; linphone_core_set_max_calls(marie->lc,0); - out_call = linphone_core_invite(pauline->lc,"marie"); + out_call = linphone_core_invite_address(pauline->lc,marie->identity); linphone_call_ref(out_call); /*wait until flexisip transfers the busy...*/ @@ -883,6 +910,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_set_sdp_handling(call->op, SalOpSDPSimulateError); /*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; @@ -929,7 +976,7 @@ static bool_t check_ice(LinphoneCoreManager* caller, LinphoneCoreManager* callee linphone_core_iterate(callee->lc); } ms_usleep(20000); - }while(!liblinphone_tester_clock_elapsed(&ts,5000)); + }while(!liblinphone_tester_clock_elapsed(&ts,10000)); } /*make sure encryption mode are preserved*/ @@ -966,7 +1013,6 @@ static void _call_with_ice_base(LinphoneCoreManager* pauline,LinphoneCoreManager CU_ASSERT_TRUE(call(pauline,marie)); if (callee_with_ice && caller_with_ice) { - check_ice(pauline,marie,LinphoneIceStateHostConnection); /*wait for the ICE reINVITE to complete*/ CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); @@ -1072,7 +1118,7 @@ static void call_with_custom_headers(void) { pauline_remote_contact_header = ms_strdup(linphone_call_params_get_custom_header(linphone_call_get_remote_params(call_pauline), "Contact")); marie_remote_contact = ms_strdup(linphone_call_get_remote_contact(call_marie)); - marie_remote_contact_header = ms_strdup(linphone_call_params_get_custom_header(marie_remote_params, "Contact")); + marie_remote_contact_header = ms_strdup(linphone_call_params_get_custom_header(linphone_call_get_remote_params(call_marie), "Contact")); CU_ASSERT_PTR_NOT_NULL(pauline_remote_contact); CU_ASSERT_PTR_NOT_NULL(pauline_remote_contact_header); @@ -1096,12 +1142,14 @@ static void call_with_custom_headers(void) { linphone_core_manager_destroy(pauline); } -static void call_paused_resumed(void) { +void call_paused_resumed_base(bool_t multicast) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneCall* call_pauline; const rtp_stats_t * stats; + linphone_core_enable_audio_multicast(pauline->lc,multicast); + CU_ASSERT_TRUE(call(pauline,marie)); call_pauline = linphone_core_get_current_call(pauline->lc); @@ -1135,52 +1183,60 @@ static void call_paused_resumed(void) { linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } +static void call_paused_resumed(void) { + call_paused_resumed_base(FALSE); +} +#define CHECK_CURRENT_LOSS_RATE() \ + rtcp_count_current = pauline->stat.number_of_rtcp_sent; \ + /*wait for an RTCP packet to have an accurate cumulative lost value*/ \ + CU_ASSERT_TRUE(wait_for_until(pauline->lc, marie->lc, &pauline->stat.number_of_rtcp_sent, rtcp_count_current+1, 10000)); \ + stats = rtp_session_get_stats(call_pauline->audiostream->ms.sessions.rtp_session); \ + loss_percentage = stats->cum_packet_loss * 100.f / (stats->packet_recv + stats->cum_packet_loss); \ + CU_ASSERT_TRUE(.75 * params.loss_rate < loss_percentage); \ + CU_ASSERT_TRUE(loss_percentage < 1.25 * params.loss_rate) static void call_paused_resumed_with_loss(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneCall* call_pauline; const rtp_stats_t * stats; - + float loss_percentage; + int rtcp_count_current; OrtpNetworkSimulatorParams params={0}; params.enabled=TRUE; - params.loss_rate=25; - + params.loss_rate=20; CU_ASSERT_TRUE(call(pauline,marie)); call_pauline = linphone_core_get_current_call(pauline->lc); rtp_session_enable_network_simulation(call_pauline->audiostream->ms.sessions.rtp_session,¶ms); - rtp_session_enable_network_simulation(call_pauline->videostream->ms.sessions.rtp_session,¶ms); - wait_for_until(pauline->lc, marie->lc, NULL, 5, 4000); + /*generate some traffic*/ + wait_for_until(pauline->lc, marie->lc, NULL, 5, 6000); + CHECK_CURRENT_LOSS_RATE(); + /*pause call*/ linphone_core_pause_call(pauline->lc,call_pauline); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausing,1)); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausedByRemote,1)); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPaused,1)); - /*stay in pause a little while in order to generate traffic*/ - wait_for_until(pauline->lc, marie->lc, NULL, 5, 2000); + wait_for_until(pauline->lc, marie->lc, NULL, 5, 5000); + CHECK_CURRENT_LOSS_RATE(); + /*resume*/ linphone_core_resume_call(pauline->lc,call_pauline); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); - /*same here: wait a while for a bit of a traffic, we need to receive a RTCP packet*/ - wait_for_until(pauline->lc, marie->lc, NULL, 5, 5000); + wait_for_until(pauline->lc, marie->lc, NULL, 5, 6000); /*since stats are NOT totally reset during pause, the stats->packet_recv is computed from the start of call. This test ensures that the loss rate is consistent during the entire call.*/ - stats = rtp_session_get_stats(call_pauline->sessions->rtp_session); - CU_ASSERT_TRUE(((stats->cum_packet_loss * 100.f / stats->packet_recv) / params.loss_rate) > .5f); - - /*just to sleep*/ - linphone_core_terminate_all_calls(pauline->lc); + CHECK_CURRENT_LOSS_RATE(); + linphone_core_terminate_all_calls(marie->lc); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,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); } @@ -1233,6 +1289,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; @@ -1276,18 +1358,33 @@ static bool_t add_video(LinphoneCoreManager* caller,LinphoneCoreManager* callee) CU_ASSERT_TRUE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(caller->lc)))); if (linphone_core_get_media_encryption(caller->lc) != LinphoneMediaEncryptionNone && linphone_core_get_media_encryption(callee->lc) != LinphoneMediaEncryptionNone) { - /*wait for encryption to be on, in case of zrtp, it can take a few seconds*/ - if (linphone_core_get_media_encryption(caller->lc) == LinphoneMediaEncryptionZRTP) - wait_for(callee->lc,caller->lc,&caller->stat.number_of_LinphoneCallEncryptedOn,initial_caller_stat.number_of_LinphoneCallEncryptedOn+1); - if (linphone_core_get_media_encryption(callee->lc) == LinphoneMediaEncryptionZRTP) - wait_for(callee->lc,caller->lc,&callee->stat.number_of_LinphoneCallEncryptedOn,initial_callee_stat.number_of_LinphoneCallEncryptedOn+1); + const LinphoneCallParams* call_param; - { - const LinphoneCallParams* call_param = linphone_call_get_current_params(linphone_core_get_current_call(callee->lc)); + switch (linphone_core_get_media_encryption(caller->lc)) { + case LinphoneMediaEncryptionZRTP: + case LinphoneMediaEncryptionDTLS: + /*wait for encryption to be on, in case of zrtp/dtls, it can take a few seconds*/ + wait_for(callee->lc,caller->lc,&caller->stat.number_of_LinphoneCallEncryptedOn,initial_caller_stat.number_of_LinphoneCallEncryptedOn+1); + break; + case LinphoneMediaEncryptionNone: + case LinphoneMediaEncryptionSRTP: + break; + } + switch (linphone_core_get_media_encryption(callee->lc)) { + case LinphoneMediaEncryptionZRTP: + case LinphoneMediaEncryptionDTLS: + wait_for(callee->lc,caller->lc,&callee->stat.number_of_LinphoneCallEncryptedOn,initial_callee_stat.number_of_LinphoneCallEncryptedOn+1); + break; + case LinphoneMediaEncryptionNone: + case LinphoneMediaEncryptionSRTP: + break; + } + + call_param = linphone_call_get_current_params(linphone_core_get_current_call(callee->lc)); CU_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(caller->lc)); call_param = linphone_call_get_current_params(linphone_core_get_current_call(caller->lc)); CU_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(caller->lc)); - } + } linphone_call_set_next_video_frame_decoded_callback(call_obj,linphone_call_cb,callee->lc); @@ -1474,11 +1571,12 @@ static void call_with_declined_video_using_policy(void) { call_with_declined_video_base(TRUE); } -static void video_call_base(LinphoneCoreManager* pauline,LinphoneCoreManager* marie, bool_t using_policy) { +static void video_call_base(LinphoneCoreManager* pauline,LinphoneCoreManager* marie, bool_t using_policy,LinphoneMediaEncryption mode) { LinphoneCallTestParams caller_test_params = {0}, callee_test_params = {0}; 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); @@ -1494,6 +1592,14 @@ static void video_call_base(LinphoneCoreManager* pauline,LinphoneCoreManager* ma linphone_core_set_video_policy(pauline->lc,&pauline_policy); } + if (mode==LinphoneMediaEncryptionDTLS) { /* for DTLS we must access certificates or at least have a directory to store them */ + marie->lc->user_certificates_path = ms_strdup_printf("%s/certificates/marie", liblinphone_tester_file_prefix); + pauline->lc->user_certificates_path = ms_strdup_printf("%s/certificates/pauline", liblinphone_tester_file_prefix); + } + + linphone_core_set_media_encryption(marie->lc,mode); + linphone_core_set_media_encryption(pauline->lc,mode); + caller_test_params.base=linphone_core_create_default_call_parameters(pauline->lc); if (!using_policy) linphone_call_params_enable_video(caller_test_params.base,TRUE); @@ -1530,15 +1636,38 @@ static void video_call_base(LinphoneCoreManager* pauline,LinphoneCoreManager* ma static void video_call(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - video_call_base(marie,pauline,FALSE); + video_call_base(marie,pauline,FALSE,LinphoneMediaEncryptionNone); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } +static void video_call_zrtp(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + if (linphone_core_media_encryption_supported(marie->lc,LinphoneMediaEncryptionDTLS)) { + video_call_base(marie,pauline,FALSE,LinphoneMediaEncryptionZRTP); + } else + ms_message("Skipping video_call_zrtp"); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void video_call_dtls(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + if (linphone_core_media_encryption_supported(pauline->lc,LinphoneMediaEncryptionDTLS)) { + video_call_base(marie,pauline,FALSE,LinphoneMediaEncryptionDTLS); + } else + ms_message("Skipping video_call_dtls"); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + +} + static void video_call_using_policy(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - video_call_base(marie,pauline,TRUE); + video_call_base(marie,pauline,TRUE,LinphoneMediaEncryptionNone); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } @@ -1547,7 +1676,7 @@ static void video_call_no_sdp(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); linphone_core_enable_sdp_200_ack(pauline->lc,TRUE); - video_call_base(pauline,marie,FALSE); + video_call_base(pauline,marie,FALSE,LinphoneMediaEncryptionNone); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } @@ -1599,26 +1728,50 @@ 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(marie->lc, "pauline"); + 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); @@ -1783,7 +1936,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; @@ -1801,11 +1953,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); - 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); @@ -1828,7 +1975,8 @@ static void call_waiting_indication_with_param(bool_t enable_caller_privacy) { LinphoneCall *call=(LinphoneCall *)iterator->data; if (call != pauline_called_by_marie) { /*fine, this is the call waiting*/ - linphone_core_accept_call(pauline->lc,pauline_called_by_laure=call); + pauline_called_by_laure=call; + linphone_core_accept_call(pauline->lc,pauline_called_by_laure); } } @@ -1848,9 +1996,9 @@ static void call_waiting_indication_with_param(bool_t enable_caller_privacy) { wait_for_list(lcs,NULL,0,1000); linphone_core_terminate_all_calls(pauline->lc); - CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,2000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,2000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,10000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,10000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,1,10000)); linphone_core_manager_destroy(marie); @@ -1894,15 +2042,13 @@ static void simple_conference_base(LinphoneCoreManager* marie, LinphoneCoreManag CU_ASSERT_PTR_NOT_NULL_FATAL(marie_call_laure); linphone_core_add_to_conference(marie->lc,marie_call_laure); - CU_ASSERT_TRUE(wait_for(marie->lc,laure->lc,&marie->stat.number_of_LinphoneCallUpdating,initial_marie_stat.number_of_LinphoneCallUpdating+1)); - - + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallUpdating,initial_marie_stat.number_of_LinphoneCallUpdating+1,5000)); linphone_core_add_to_conference(marie->lc,marie_call_pauline); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallResuming,initial_marie_stat.number_of_LinphoneCallResuming+1,2000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,initial_pauline_stat.number_of_LinphoneCallStreamsRunning+1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,initial_pauline_stat.number_of_LinphoneCallStreamsRunning+1,5000)); CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,initial_laure_stat.number_of_LinphoneCallStreamsRunning+1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,initial_marie_stat.number_of_LinphoneCallStreamsRunning+2,3000)); @@ -1923,9 +2069,9 @@ static void simple_conference_base(LinphoneCoreManager* marie, LinphoneCoreManag linphone_core_terminate_conference(marie->lc); - CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,2000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,2000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,10000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,10000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,1,10000)); @@ -1960,16 +2106,35 @@ static void simple_conference_with_ice(void) { } static void srtp_call() { - call_base(LinphoneMediaEncryptionSRTP,FALSE,FALSE,LinphonePolicyNoFirewall); + call_base(LinphoneMediaEncryptionSRTP,FALSE,FALSE,LinphonePolicyNoFirewall,FALSE); } static void zrtp_call() { - call_base(LinphoneMediaEncryptionZRTP,FALSE,FALSE,LinphonePolicyNoFirewall); + call_base(LinphoneMediaEncryptionZRTP,FALSE,FALSE,LinphonePolicyNoFirewall,FALSE); } static void zrtp_video_call() { - call_base(LinphoneMediaEncryptionZRTP,TRUE,FALSE,LinphonePolicyNoFirewall); + call_base(LinphoneMediaEncryptionZRTP,TRUE,FALSE,LinphonePolicyNoFirewall,FALSE); } +static void dtls_srtp_call() { + call_base(LinphoneMediaEncryptionDTLS,FALSE,FALSE,LinphonePolicyNoFirewall,FALSE); +} + +static void dtls_srtp_ice_call() { + call_base(LinphoneMediaEncryptionDTLS,FALSE,FALSE,LinphonePolicyUseIce,FALSE); +} +#ifdef VIDEO_ENABLED +static void dtls_srtp_video_call() { + call_base(LinphoneMediaEncryptionDTLS,TRUE,FALSE,LinphonePolicyNoFirewall,FALSE); +} + +static void dtls_srtp_ice_video_call() { + call_base(LinphoneMediaEncryptionDTLS,TRUE,FALSE,LinphonePolicyUseIce,FALSE); +} +static void dtls_srtp_ice_video_call_with_relay() { + call_base(LinphoneMediaEncryptionDTLS,TRUE,TRUE,LinphonePolicyUseIce,FALSE); +} +#endif static void call_with_declined_srtp(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -2000,7 +2165,6 @@ static void call_with_file_player(void) { LinphonePlayer *player; char hellopath[256]; char *recordpath = create_filepath(liblinphone_tester_writable_dir_prefix, "record", "wav"); - double similar; /*make sure the record file doesn't already exists, otherwise this test will append new samples to it*/ unlink(recordpath); @@ -2008,12 +2172,12 @@ static void call_with_file_player(void) { snprintf(hellopath,sizeof(hellopath), "%s/sounds/hello8000.wav", liblinphone_tester_file_prefix); /*caller uses files instead of soundcard in order to avoid mixing soundcard input with file played using call's player*/ - linphone_core_use_files(pauline->lc,TRUE); - linphone_core_set_play_file(pauline->lc,NULL); + linphone_core_use_files(marie->lc,TRUE); + linphone_core_set_play_file(marie->lc,NULL); /*callee is recording and plays file*/ linphone_core_use_files(pauline->lc,TRUE); - linphone_core_set_play_file(pauline->lc,hellopath); + linphone_core_set_play_file(pauline->lc,NULL); linphone_core_set_record_file(pauline->lc,recordpath); CU_ASSERT_TRUE(call(marie,pauline)); @@ -2024,15 +2188,30 @@ 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,23000)); /*just to sleep*/ linphone_core_terminate_all_calls(marie->lc); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); - CU_ASSERT_TRUE(ms_audio_diff(hellopath,recordpath,&similar,NULL,NULL)==0); - CU_ASSERT_TRUE(similar>0.9); - CU_ASSERT_TRUE(similar<=1.0); + /*cannot run on iphone simulator because locks main loop beyond permitted time (should run + on another thread) */ +#if !defined(__arm__) && !defined(__arm64__) && !TARGET_IPHONE_SIMULATOR && !defined(ANDROID) + { + double similar; + const double threshold = 0.9; + CU_ASSERT_TRUE(ms_audio_diff(hellopath,recordpath,&similar,NULL,NULL)==0); + CU_ASSERT_TRUE(similar>threshold); + CU_ASSERT_TRUE(similar<=1.0); + if(similar > threshold && similar <=1.0) { + remove(recordpath); + } + } +#else + remove(recordpath); +#endif linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); ms_free(recordpath); @@ -2054,6 +2233,7 @@ static void call_with_mkv_file_player(void) { char hellowav[256]; char *recordpath; double similar; + const double threshold = 0.9; if (!is_format_supported(marie->lc,"mkv")){ ms_warning("Test skipped, no mkv support."); @@ -2063,7 +2243,7 @@ static void call_with_mkv_file_player(void) { /*make sure the record file doesn't already exists, otherwise this test will append new samples to it*/ unlink(recordpath); - snprintf(hellowav,sizeof(hellowav), "%s/sounds/hello8000.wav", liblinphone_tester_file_prefix); + snprintf(hellowav,sizeof(hellowav), "%s/sounds/hello8000_mkv_ref.wav", liblinphone_tester_file_prefix); snprintf(hellomkv,sizeof(hellomkv), "%s/sounds/hello8000.mkv", liblinphone_tester_file_prefix); /*caller uses files instead of soundcard in order to avoid mixing soundcard input with file played using call's player*/ @@ -2079,7 +2259,12 @@ static void call_with_mkv_file_player(void) { player=linphone_call_get_player(linphone_core_get_current_call(marie->lc)); CU_ASSERT_PTR_NOT_NULL(player); if (player){ - CU_ASSERT_TRUE(linphone_player_open(player,hellomkv,on_eof,marie)==0); + int res = linphone_player_open(player,hellomkv,on_eof,marie); + if(!ms_filter_codec_supported("opus")) { + CU_ASSERT_EQUAL(res, -1); + goto end; + } + CU_ASSERT_EQUAL(res, 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)); linphone_player_close(player); @@ -2089,9 +2274,17 @@ static void call_with_mkv_file_player(void) { linphone_core_terminate_all_calls(marie->lc); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); +#if !defined(__arm__) && !defined(__arm64__) && !TARGET_IPHONE_SIMULATOR && !defined(ANDROID) CU_ASSERT_TRUE(ms_audio_diff(hellowav,recordpath,&similar,NULL,NULL)==0); - CU_ASSERT_TRUE(similar>0.6); + CU_ASSERT_TRUE(similar>threshold); CU_ASSERT_TRUE(similar<=1.0); + if(similar>threshold && similar<=1.0) { + remove(recordpath); + } +#else + /*inter-correlation process is too much CPU consuming ending in a 20 minutes test on arm...*/ + remove(recordpath); +#endif ms_free(recordpath); end: @@ -2100,17 +2293,38 @@ end: } - -static void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t enable_relay,LinphoneFirewallPolicy policy) { +void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t enable_relay,LinphoneFirewallPolicy policy,bool_t enable_tunnel) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); if (enable_relay) { linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); } + if (enable_tunnel) { + int i; + LinphoneTunnelConfig * tunnel_config = linphone_tunnel_config_new(); + linphone_tunnel_config_set_host(tunnel_config,"tunnel.linphone.org"); + linphone_tunnel_config_set_port(tunnel_config,443); + linphone_tunnel_add_server(linphone_core_get_tunnel(marie->lc),tunnel_config); + linphone_tunnel_enable_sip(linphone_core_get_tunnel(marie->lc),FALSE); + linphone_tunnel_set_mode(linphone_core_get_tunnel(marie->lc),LinphoneTunnelModeEnable); + for (i=0;i<10;i++) { + if (linphone_tunnel_connected(linphone_core_get_tunnel(marie->lc))) { + break; + } + linphone_core_iterate(marie->lc); + ms_usleep(200000); + } + CU_ASSERT_TRUE(linphone_tunnel_connected(linphone_core_get_tunnel(marie->lc))); + + } if (linphone_core_media_encryption_supported(marie->lc,mode)) { linphone_core_set_media_encryption(marie->lc,mode); linphone_core_set_media_encryption(pauline->lc,mode); + if (mode==LinphoneMediaEncryptionDTLS) { /* for DTLS we must access certificates or at least have a directory to store them */ + marie->lc->user_certificates_path = ms_strdup_printf("%s/certificates/marie", liblinphone_tester_file_prefix); + pauline->lc->user_certificates_path = ms_strdup_printf("%s/certificates/pauline", liblinphone_tester_file_prefix); + } linphone_core_set_firewall_policy(marie->lc,policy); linphone_core_set_stun_server(marie->lc,"stun.linphone.org"); @@ -2140,21 +2354,21 @@ static void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t e } - if (policy == LinphonePolicyUseIce) - CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection)); + if (policy == LinphonePolicyUseIce){ + int i=0; + CU_ASSERT_TRUE(check_ice(pauline,marie,enable_tunnel?LinphoneIceStateReflexiveConnection:LinphoneIceStateHostConnection)); + for (i=0;i<100;i++) { /*fixme to workaround a crash*/ + ms_usleep(20000); + linphone_core_iterate(marie->lc); + linphone_core_iterate(pauline->lc); + } + } #ifdef VIDEO_ENABLED if (enable_video) { - int i=0; if (linphone_core_video_supported(marie->lc)) { - for (i=0;i<100;i++) { /*fixme to workaround a crash*/ - ms_usleep(20000); - linphone_core_iterate(marie->lc); - linphone_core_iterate(pauline->lc); - } - add_video(pauline,marie); if (policy == LinphonePolicyUseIce) - CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection)); + CU_ASSERT_TRUE(check_ice(pauline,marie,enable_tunnel?LinphoneIceStateReflexiveConnection:LinphoneIceStateHostConnection)); liblinphone_tester_check_rtcp(marie,pauline); /*wait for ice to found the direct path*/ @@ -2162,7 +2376,6 @@ static void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t e } else { ms_warning ("not tested because video not available"); } - } #endif @@ -2177,25 +2390,28 @@ static void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t e linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } - #ifdef VIDEO_ENABLED static void srtp_video_ice_call(void) { - call_base(LinphoneMediaEncryptionSRTP,TRUE,FALSE,LinphonePolicyUseIce); + call_base(LinphoneMediaEncryptionSRTP,TRUE,FALSE,LinphonePolicyUseIce,FALSE); } static void zrtp_video_ice_call(void) { - call_base(LinphoneMediaEncryptionZRTP,TRUE,FALSE,LinphonePolicyUseIce); + call_base(LinphoneMediaEncryptionZRTP,TRUE,FALSE,LinphonePolicyUseIce,FALSE); } #endif static void srtp_ice_call(void) { - call_base(LinphoneMediaEncryptionSRTP,FALSE,FALSE,LinphonePolicyUseIce); + call_base(LinphoneMediaEncryptionSRTP,FALSE,FALSE,LinphonePolicyUseIce,FALSE); } static void zrtp_ice_call(void) { - call_base(LinphoneMediaEncryptionZRTP,FALSE,FALSE,LinphonePolicyUseIce); + call_base(LinphoneMediaEncryptionZRTP,FALSE,FALSE,LinphonePolicyUseIce,FALSE); } static void zrtp_ice_call_with_relay(void) { - call_base(LinphoneMediaEncryptionZRTP,FALSE,TRUE,LinphonePolicyUseIce); + call_base(LinphoneMediaEncryptionZRTP,FALSE,TRUE,LinphonePolicyUseIce,FALSE); +} + +static void dtls_ice_call_with_relay(void) { + call_base(LinphoneMediaEncryptionDTLS,FALSE,TRUE,LinphonePolicyUseIce,FALSE); } static void early_media_call(void) { @@ -2224,14 +2440,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); @@ -2240,11 +2455,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); @@ -2265,7 +2475,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)); @@ -2278,8 +2488,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); } @@ -2288,7 +2498,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; @@ -2305,11 +2514,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)); @@ -2480,32 +2684,35 @@ static void unattended_call_transfer_with_error(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneCall* pauline_called_by_marie; - + bool_t call_ok=TRUE; MSList* lcs=ms_list_append(NULL,marie->lc); + lcs=ms_list_append(lcs,pauline->lc); - CU_ASSERT_TRUE(call(marie,pauline)); - pauline_called_by_marie=linphone_core_get_current_call(marie->lc); + CU_ASSERT_TRUE((call_ok=call(marie,pauline))); + if (call_ok){ + pauline_called_by_marie=linphone_core_get_current_call(marie->lc); - reset_counters(&marie->stat); - reset_counters(&pauline->stat); + reset_counters(&marie->stat); + reset_counters(&pauline->stat); - linphone_core_transfer_call(marie->lc,pauline_called_by_marie,"unknown_user"); - CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallRefered,1,2000)); + linphone_core_transfer_call(marie->lc,pauline_called_by_marie,"unknown_user"); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallRefered,1,2000)); - /*Pauline starts the transfer*/ - CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingInit,1,2000)); - /* and immediately get an error*/ - CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallError,1,2000)); + /*Pauline starts the transfer*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingInit,1,2000)); + /* and immediately get an error*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallError,1,2000)); - /*the error must be reported back to marie*/ - CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransferCallError,1,2000)); + /*the error must be reported back to marie*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransferCallError,1,2000)); - /*and pauline should resume the call automatically*/ - CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallResuming,1,2000)); + /*and pauline should resume the call automatically*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallResuming,1,2000)); - /*and call should be resumed*/ - CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,1,2000)); + /*and call should be resumed*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,1,2000)); + } linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); @@ -2517,73 +2724,71 @@ static void call_transfer_existing_call_outgoing_call(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc"); - LinphoneCall* marie_call_pauline; LinphoneCall* pauline_called_by_marie; LinphoneCall* marie_call_laure; LinphoneCall* laure_called_by_marie; LinphoneCall* lcall; - - MSList* lcs=ms_list_append(NULL,marie->lc); + bool_t call_ok=TRUE; const MSList* calls; - - linphone_core_use_files (pauline->lc,TRUE); - linphone_core_use_files (laure->lc,TRUE); - + MSList* lcs=ms_list_append(NULL,marie->lc); + lcs=ms_list_append(lcs,pauline->lc); lcs=ms_list_append(lcs,laure->lc); /*marie call pauline*/ - CU_ASSERT_TRUE(call(marie,pauline)); - marie_call_pauline=linphone_core_get_current_call(marie->lc); - pauline_called_by_marie=linphone_core_get_current_call(pauline->lc); - /*marie pause pauline*/ - CU_ASSERT_TRUE(pause_call_1(marie,marie_call_pauline,pauline,pauline_called_by_marie)); + CU_ASSERT_TRUE((call_ok=call(marie,pauline))); + if (call_ok){ + marie_call_pauline=linphone_core_get_current_call(marie->lc); + pauline_called_by_marie=linphone_core_get_current_call(pauline->lc); + /*marie pause pauline*/ + CU_ASSERT_TRUE(pause_call_1(marie,marie_call_pauline,pauline,pauline_called_by_marie)); - /*marie call laure*/ - CU_ASSERT_TRUE(call(marie,laure)); - marie_call_laure=linphone_core_get_current_call(marie->lc); - laure_called_by_marie=linphone_core_get_current_call(laure->lc); - /*marie pause laure*/ - CU_ASSERT_TRUE(pause_call_1(marie,marie_call_laure,laure,laure_called_by_marie)); + /*marie call laure*/ + CU_ASSERT_TRUE(call(marie,laure)); + marie_call_laure=linphone_core_get_current_call(marie->lc); + laure_called_by_marie=linphone_core_get_current_call(laure->lc); + /*marie pause laure*/ + CU_ASSERT_TRUE(pause_call_1(marie,marie_call_laure,laure,laure_called_by_marie)); - reset_counters(&marie->stat); - reset_counters(&pauline->stat); - reset_counters(&laure->stat); + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + reset_counters(&laure->stat); - linphone_core_transfer_call_to_another(marie->lc,marie_call_pauline,marie_call_laure); - CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallRefered,1,2000)); + linphone_core_transfer_call_to_another(marie->lc,marie_call_pauline,marie_call_laure); + 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)); - /*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)); - CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallIncomingReceived,1,2000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,2000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransferCallOutgoingProgress,1,2000)); + /*pauline pausing marie*/ + 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)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallIncomingReceived,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransferCallOutgoingProgress,1,2000)); - /*laure accept call*/ - for(calls=linphone_core_get_calls(laure->lc);calls!=NULL;calls=calls->next) { - lcall = (LinphoneCall*)calls->data; - if (linphone_call_get_state(lcall) == LinphoneCallIncomingReceived) { - CU_ASSERT_EQUAL(linphone_call_get_replaced_call(lcall),laure_called_by_marie); - linphone_core_accept_call(laure->lc,lcall); - break; + /*laure accept call*/ + for(calls=linphone_core_get_calls(laure->lc);calls!=NULL;calls=calls->next) { + lcall = (LinphoneCall*)calls->data; + if (linphone_call_get_state(lcall) == LinphoneCallIncomingReceived) { + CU_ASSERT_EQUAL(linphone_call_get_replaced_call(lcall),laure_called_by_marie); + linphone_core_accept_call(laure->lc,lcall); + break; + } } - } - CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallConnected,1,2000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,1,2000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallConnected,1,2000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,2000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransferCallConnected,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallConnected,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallConnected,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransferCallConnected,1,2000)); - /*terminate marie to pauline/laure call*/ - CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,2000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,2,2000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,1,2000)); + /*terminate marie to pauline/laure call*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,2,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,1,2000)); + } linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); @@ -2596,31 +2801,35 @@ static void check_call_state(LinphoneCoreManager* mgr,LinphoneCallState state) { if (linphone_core_get_current_call(mgr->lc)) CU_ASSERT_EQUAL(linphone_call_get_state(linphone_core_get_current_call(mgr->lc)),state); } + static void call_established_with_rejected_info(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); int dummy=0; + bool_t call_ok=FALSE; - CU_ASSERT_TRUE(call(pauline,marie)); + CU_ASSERT_TRUE((call_ok=call(pauline,marie))); + if (call_ok){ - sal_enable_unconditional_answer(marie->lc->sal,TRUE); - linphone_call_send_info_message(linphone_core_get_current_call(pauline->lc),linphone_core_create_info_message(pauline->lc)); + sal_enable_unconditional_answer(marie->lc->sal,TRUE); + linphone_call_send_info_message(linphone_core_get_current_call(pauline->lc),linphone_core_create_info_message(pauline->lc)); - wait_for_until(marie->lc,pauline->lc,&dummy,1,1000); /*just to sleep while iterating 1s*/ + wait_for_until(marie->lc,pauline->lc,&dummy,1,1000); /*just to sleep while iterating 1s*/ - sal_enable_unconditional_answer(marie->lc->sal,FALSE); + sal_enable_unconditional_answer(marie->lc->sal,FALSE); - linphone_call_send_info_message(linphone_core_get_current_call(pauline->lc),linphone_core_create_info_message(pauline->lc)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_inforeceived,1)); - CU_ASSERT_EQUAL(marie->stat.number_of_inforeceived,1); + linphone_call_send_info_message(linphone_core_get_current_call(pauline->lc),linphone_core_create_info_message(pauline->lc)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_inforeceived,1)); + CU_ASSERT_EQUAL(marie->stat.number_of_inforeceived,1); - check_call_state(pauline,LinphoneCallStreamsRunning); - check_call_state(marie,LinphoneCallStreamsRunning); + check_call_state(pauline,LinphoneCallStreamsRunning); + check_call_state(marie,LinphoneCallStreamsRunning); - /*just to sleep*/ - linphone_core_terminate_all_calls(pauline->lc); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,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); @@ -2630,30 +2839,32 @@ static void call_established_with_rejected_info(void) { static void call_established_with_rejected_reinvite(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + bool_t call_ok=FALSE; - CU_ASSERT_TRUE(call(pauline,marie)); - - linphone_core_enable_payload_type(pauline->lc,linphone_core_find_payload_type(pauline->lc,"PCMU",8000,1),FALSE); /*disable PCMU*/ - linphone_core_enable_payload_type(pauline->lc,linphone_core_find_payload_type(pauline->lc,"PCMA",8000,1),TRUE); /*enable PCMA*/ + CU_ASSERT_TRUE(call_ok=call(pauline,marie)); + if (call_ok){ + linphone_core_enable_payload_type(pauline->lc,linphone_core_find_payload_type(pauline->lc,"PCMU",8000,1),FALSE); /*disable PCMU*/ + linphone_core_enable_payload_type(pauline->lc,linphone_core_find_payload_type(pauline->lc,"PCMA",8000,1),TRUE); /*enable PCMA*/ - linphone_core_update_call( pauline->lc - ,linphone_core_get_current_call(pauline->lc) - ,linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc))); + linphone_core_update_call( pauline->lc + ,linphone_core_get_current_call(pauline->lc) + ,linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc))); - CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); - CU_ASSERT_EQUAL(linphone_call_get_reason(linphone_core_get_current_call(pauline->lc)),LinphoneReasonNotAcceptable); + CU_ASSERT_EQUAL(linphone_call_get_reason(linphone_core_get_current_call(pauline->lc)),LinphoneReasonNotAcceptable); - CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallStreamsRunning,1); - check_call_state(pauline,LinphoneCallStreamsRunning); - check_call_state(marie,LinphoneCallStreamsRunning); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallStreamsRunning,1); + check_call_state(pauline,LinphoneCallStreamsRunning); + check_call_state(marie,LinphoneCallStreamsRunning); - /*just to sleep*/ - linphone_core_terminate_all_calls(pauline->lc); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,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); @@ -2662,40 +2873,43 @@ static void call_established_with_rejected_reinvite(void) { static void call_established_with_rejected_incoming_reinvite(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + bool_t call_ok=FALSE; - CU_ASSERT_TRUE(call(pauline,marie)); + CU_ASSERT_TRUE((call_ok=call(pauline,marie))); + + if (call_ok){ - /*wait for ACK to be transmitted before going to reINVITE*/ - wait_for_until(marie->lc,pauline->lc,NULL,0,1000); + /*wait for ACK to be transmitted before going to reINVITE*/ + wait_for_until(marie->lc,pauline->lc,NULL,0,1000); - linphone_core_enable_payload_type(pauline->lc,linphone_core_find_payload_type(pauline->lc,"PCMU",8000,1),FALSE); /*disable PCMU*/ - linphone_core_enable_payload_type(pauline->lc,linphone_core_find_payload_type(pauline->lc,"PCMA",8000,1),TRUE); /*enable PCMA*/ + linphone_core_enable_payload_type(pauline->lc,linphone_core_find_payload_type(pauline->lc,"PCMU",8000,1),FALSE); /*disable PCMU*/ + linphone_core_enable_payload_type(pauline->lc,linphone_core_find_payload_type(pauline->lc,"PCMA",8000,1),TRUE); /*enable PCMA*/ - linphone_core_update_call(marie->lc - ,linphone_core_get_current_call(marie->lc) - ,linphone_call_get_current_params(linphone_core_get_current_call(marie->lc))); + linphone_core_update_call(marie->lc + ,linphone_core_get_current_call(marie->lc) + ,linphone_call_get_current_params(linphone_core_get_current_call(marie->lc))); - CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallUpdating,1)); - CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallUpdating,1)); + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); - CU_ASSERT_EQUAL(linphone_call_get_reason(linphone_core_get_current_call(marie->lc)),LinphoneReasonNotAcceptable); + CU_ASSERT_EQUAL(linphone_call_get_reason(linphone_core_get_current_call(marie->lc)),LinphoneReasonNotAcceptable); - CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallStreamsRunning,1); - check_call_state(pauline,LinphoneCallStreamsRunning); - check_call_state(marie,LinphoneCallStreamsRunning); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallStreamsRunning,1); + check_call_state(pauline,LinphoneCallStreamsRunning); + check_call_state(marie,LinphoneCallStreamsRunning); - /*just to sleep*/ - linphone_core_terminate_all_calls(pauline->lc); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,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 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"); @@ -2710,41 +2924,36 @@ 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)); + CU_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingReceived,1,6000)); - margaux_url = linphone_address_as_string(laure->identity); - linphone_core_redirect_call(pauline->lc, linphone_core_get_current_call(pauline->lc), margaux_url); - ms_free(margaux_url); + if (linphone_core_get_current_call(pauline->lc)){ + margaux_url = linphone_address_as_string(laure->identity); + linphone_core_redirect_call(pauline->lc, linphone_core_get_current_call(pauline->lc), margaux_url); + ms_free(margaux_url); - /* laure should be ringing now */ - CU_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallIncomingReceived,1,6000)); - /* pauline should have ended the call */ - CU_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallEnd,1,1000)); - /* the call should still be ringing on marie's side */ - CU_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingRinging, 1,1000)); + /* laure should be ringing now */ + CU_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallIncomingReceived,1,6000)); + /* pauline should have ended the call */ + CU_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallEnd,1,1000)); + /* the call should still be ringing on marie's side */ + CU_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingRinging, 1,1000)); - linphone_core_accept_call(laure->lc, linphone_core_get_current_call(laure->lc)); + linphone_core_accept_call(laure->lc, linphone_core_get_current_call(laure->lc)); - CU_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 1,1000)); - CU_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 1,1000)); - CU_ASSERT_EQUAL(marie_call, linphone_core_get_current_call(marie->lc)); + CU_ASSERT_EQUAL(marie_call, linphone_core_get_current_call(marie->lc)); - liblinphone_tester_check_rtcp(marie, laure); + liblinphone_tester_check_rtcp(marie, laure); - linphone_core_terminate_all_calls(laure->lc); + linphone_core_terminate_all_calls(laure->lc); - CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,1,1000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,1,5000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,5000)); + } ms_list_free(lcs); @@ -2789,7 +2998,7 @@ static void call_established_with_rejected_reinvite_with_error(void) { static void call_rejected_because_wrong_credentials_with_params(const char* user_agent,bool_t enable_auth_req_cb) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); - LinphoneAuthInfo* good_auth_info=linphone_auth_info_clone((LinphoneAuthInfo*)(linphone_core_get_auth_info_list(marie->lc)->data)); + LinphoneAuthInfo* good_auth_info=linphone_auth_info_clone(linphone_core_find_auth_info(marie->lc,NULL,linphone_address_get_username(marie->identity),NULL)); LinphoneAuthInfo* wrong_auth_info=linphone_auth_info_clone(good_auth_info); bool_t result=FALSE; linphone_auth_info_set_passwd(wrong_auth_info,"passecretdutout"); @@ -2822,7 +3031,7 @@ static void call_rejected_because_wrong_credentials_with_params(const char* user /*to make sure unregister will work*/ linphone_core_clear_all_auth_info(marie->lc); linphone_core_add_auth_info(marie->lc,good_auth_info); - + linphone_auth_info_destroy(good_auth_info); linphone_core_manager_destroy(marie); } @@ -2841,9 +3050,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; @@ -2852,9 +3061,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; @@ -2862,18 +3068,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); @@ -2893,32 +3092,39 @@ static void multiple_early_media(void) { marie1_call=linphone_core_get_current_call(marie1->lc); marie2_call=linphone_core_get_current_call(marie2->lc); - /*wait a bit that streams are established*/ - wait_for_list(lcs,&dummy,1,6000); - 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); + CU_ASSERT_PTR_NOT_NULL(pauline_call); + CU_ASSERT_PTR_NOT_NULL(marie1_call); + CU_ASSERT_PTR_NOT_NULL(marie2_call); + + if (pauline_call && marie1_call && marie2_call){ + + /*wait a bit that streams are established*/ + wait_for_list(lcs,&dummy,1,6000); + 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); - 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)); - CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,3000)); + 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)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,3000)); - /*marie2 should get her call terminated*/ - CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallEnd,1,1000)); + /*marie2 should get her call terminated*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallEnd,1,1000)); - /*wait a bit that streams are established*/ - wait_for_list(lcs,&dummy,1,1000); - CU_ASSERT_TRUE(linphone_call_get_audio_stats(pauline_call)->download_bandwidth>71); - CU_ASSERT_TRUE(linphone_call_get_audio_stats(marie1_call)->download_bandwidth>71); + /*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); + CU_ASSERT_TRUE(linphone_call_get_audio_stats(marie1_call)->download_bandwidth>71); - /*send an INFO in reverse side to check that dialogs are properly established*/ - info=linphone_core_create_info_message(marie1->lc); - linphone_call_send_info_message(marie1_call,info); - CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_inforeceived,1,2000)); + /*send an INFO in reverse side to check that dialogs are properly established*/ + info=linphone_core_create_info_message(marie1->lc); + linphone_call_send_info_message(marie1_call,info); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_inforeceived,1,3000)); + } linphone_core_terminate_all_calls(pauline->lc); - CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,2000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallEnd,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,3000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallEnd,1,3000)); ms_list_free(lcs); linphone_core_manager_destroy(marie1); @@ -2927,115 +3133,6 @@ static void multiple_early_media(void) { } #endif -static void profile_call(bool_t avpf1, bool_t srtp1, bool_t avpf2, bool_t srtp2, const char *expected_profile) { - LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); - LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_rc"); - LinphoneProxyConfig *lpc; - const LinphoneCallParams *params; - - if (avpf1) { - linphone_core_get_default_proxy(marie->lc, &lpc); - linphone_proxy_config_enable_avpf(lpc, TRUE); - linphone_proxy_config_set_avpf_rr_interval(lpc, 3); - } - if (avpf2) { - linphone_core_get_default_proxy(pauline->lc, &lpc); - linphone_proxy_config_enable_avpf(lpc, TRUE); - linphone_proxy_config_set_avpf_rr_interval(lpc, 3); - } - if (srtp1) { - if (linphone_core_media_encryption_supported(marie->lc, LinphoneMediaEncryptionSRTP)) { - linphone_core_set_media_encryption(marie->lc, LinphoneMediaEncryptionSRTP); - } - } - if (srtp2) { - if (linphone_core_media_encryption_supported(pauline->lc, LinphoneMediaEncryptionSRTP)) { - linphone_core_set_media_encryption(pauline->lc, LinphoneMediaEncryptionSRTP); - } - } - - CU_ASSERT_TRUE(call(marie, pauline)); - CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 1)); - CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1)); - params = linphone_call_get_current_params(linphone_core_get_current_call(marie->lc)); - CU_ASSERT_STRING_EQUAL(linphone_call_params_get_rtp_profile(params), expected_profile); - params = linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc)); - CU_ASSERT_STRING_EQUAL(linphone_call_params_get_rtp_profile(params), expected_profile); - - linphone_core_terminate_all_calls(marie->lc); - CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallEnd, 1)); - CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallEnd, 1)); - CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallConnected, 1); - CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallConnected, 1); - - linphone_core_manager_destroy(pauline); - linphone_core_manager_destroy(marie); -} - -static void avp_to_avp_call(void) { - profile_call(FALSE, FALSE, FALSE, FALSE, "RTP/AVP"); -} - -static void avp_to_avpf_call(void) { - profile_call(FALSE, FALSE, TRUE, FALSE, "RTP/AVP"); -} - -static void avp_to_savp_call(void) { - profile_call(FALSE, FALSE, FALSE, TRUE, "RTP/AVP"); -} - -static void avp_to_savpf_call(void) { - profile_call(FALSE, FALSE, TRUE, TRUE, "RTP/AVP"); -} - -static void avpf_to_avp_call(void) { - profile_call(TRUE, FALSE, FALSE, FALSE, "RTP/AVPF"); -} - -static void avpf_to_avpf_call(void) { - profile_call(TRUE, FALSE, TRUE, FALSE, "RTP/AVPF"); -} - -static void avpf_to_savp_call(void) { - profile_call(TRUE, FALSE, FALSE, TRUE, "RTP/AVPF"); -} - -static void avpf_to_savpf_call(void) { - profile_call(TRUE, FALSE, TRUE, TRUE, "RTP/AVPF"); -} - -static void savp_to_avp_call(void) { - profile_call(FALSE, TRUE, FALSE, FALSE, "RTP/SAVP"); -} - -static void savp_to_avpf_call(void) { - profile_call(FALSE, TRUE, TRUE, FALSE, "RTP/SAVP"); -} - -static void savp_to_savp_call(void) { - profile_call(FALSE, TRUE, FALSE, TRUE, "RTP/SAVP"); -} - -static void savp_to_savpf_call(void) { - profile_call(FALSE, TRUE, TRUE, TRUE, "RTP/SAVP"); -} - -static void savpf_to_avp_call(void) { - profile_call(TRUE, TRUE, FALSE, FALSE, "RTP/SAVPF"); -} - -static void savpf_to_avpf_call(void) { - profile_call(TRUE, TRUE, TRUE, FALSE, "RTP/SAVPF"); -} - -static void savpf_to_savp_call(void) { - profile_call(TRUE, TRUE, FALSE, TRUE, "RTP/SAVPF"); -} - -static void savpf_to_savpf_call(void) { - profile_call(TRUE, TRUE, TRUE, TRUE, "RTP/SAVPF"); -} - static char *create_filepath(const char *dir, const char *filename, const char *ext) { return ms_strdup_printf("%s/%s.%s",dir,filename,ext); } @@ -3091,6 +3188,7 @@ static void record_call(const char *filename, bool_t enableVideo) { end_call(marie, pauline); CU_ASSERT_EQUAL(access(filepath, F_OK), 0); } + remove(filepath); ms_free(filepath); } linphone_core_manager_destroy(marie); @@ -3202,7 +3300,7 @@ static void call_with_in_dialog_codec_change_base(bool_t no_sdp) { CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallUpdatedByRemote,1)); CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); CU_ASSERT_STRING_EQUAL("PCMA",linphone_payload_type_get_mime_type(linphone_call_params_get_used_audio_codec(linphone_call_get_current_params(linphone_core_get_current_call(marie->lc))))); - wait_for_until(marie->lc, pauline->lc, &dummy, 1, 3000); + wait_for_until(marie->lc, pauline->lc, &dummy, 1, 5000); CU_ASSERT_TRUE(linphone_call_get_audio_stats(linphone_core_get_current_call(marie->lc))->download_bandwidth>70); CU_ASSERT_TRUE(linphone_call_get_audio_stats(linphone_core_get_current_call(pauline->lc))->download_bandwidth>70); @@ -3296,12 +3394,12 @@ static void call_log_from_taken_from_p_asserted_id(void) { linphone_core_manager_destroy(pauline); } -static void incoming_invite_without_sdp() { +static void incoming_invite_with_invalid_sdp() { LinphoneCoreManager* caller = linphone_core_manager_new( "pauline_rc"); LinphoneCoreManager* callee = linphone_core_manager_new( "marie_rc"); LinphoneCallTestParams caller_test_params = {0}, callee_test_params = {0}; - callee_test_params.sdp_removal = TRUE; + callee_test_params.sdp_simulate_error = TRUE; CU_ASSERT_FALSE(call_with_params2(caller,callee,&caller_test_params, &callee_test_params, FALSE)); CU_ASSERT_PTR_NULL(linphone_core_get_current_call(callee->lc)); @@ -3313,12 +3411,12 @@ static void incoming_invite_without_sdp() { linphone_core_manager_destroy(caller); } -static void outgoing_invite_without_sdp() { +static void outgoing_invite_with_invalid_sdp() { LinphoneCoreManager* caller = linphone_core_manager_new( "pauline_rc"); LinphoneCoreManager* callee = linphone_core_manager_new( "marie_rc"); LinphoneCallTestParams caller_test_params = {0}, callee_test_params = {0}; - caller_test_params.sdp_removal = TRUE; + caller_test_params.sdp_simulate_error = TRUE; CU_ASSERT_FALSE(call_with_params2(caller,callee,&caller_test_params, &callee_test_params, FALSE)); CU_ASSERT_PTR_NULL(linphone_core_get_current_call(callee->lc)); @@ -3332,7 +3430,7 @@ static void outgoing_invite_without_sdp() { linphone_core_manager_destroy(caller); } -static void incoming_reinvite_without_ack_sdp() { +static void incoming_reinvite_with_invalid_ack_sdp(){ #ifdef VIDEO_ENABLED LinphoneCoreManager* caller = linphone_core_manager_new( "pauline_rc"); LinphoneCoreManager* callee = linphone_core_manager_new( "marie_rc"); @@ -3345,8 +3443,8 @@ static void incoming_reinvite_without_ack_sdp() { const LinphoneCallParams *caller_params; stats initial_caller_stat=caller->stat; stats initial_callee_stat=callee->stat; - sal_call_enable_sdp_removal(inc_call->op, TRUE); - CU_ASSERT_PTR_NOT_NULL(setup_video(caller, callee)); + sal_call_set_sdp_handling(inc_call->op, SalOpSDPSimulateError); /* will force a parse error for the ACK SDP*/ + CU_ASSERT_PTR_NOT_NULL(setup_video(caller, callee)); CU_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallUpdating,initial_callee_stat.number_of_LinphoneCallUpdating+1)); CU_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallStreamsRunning,initial_callee_stat.number_of_LinphoneCallStreamsRunning+1)); CU_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&caller->stat.number_of_LinphoneCallStreamsRunning,initial_caller_stat.number_of_LinphoneCallStreamsRunning)); @@ -3361,7 +3459,7 @@ static void incoming_reinvite_without_ack_sdp() { caller_params = linphone_call_get_current_params(linphone_core_get_current_call(caller->lc)); CU_ASSERT_TRUE(wait_for(caller->lc,callee->lc,(int*)&caller_params->has_video,FALSE)); - sal_call_enable_sdp_removal(inc_call->op, FALSE); + sal_call_set_sdp_handling(inc_call->op, SalOpSDPNormal); } linphone_core_terminate_all_calls(caller->lc); CU_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&caller->stat.number_of_LinphoneCallEnd,1)); @@ -3374,7 +3472,7 @@ static void incoming_reinvite_without_ack_sdp() { #endif } -static void outgoing_reinvite_without_ack_sdp() { +static void outgoing_reinvite_with_invalid_ack_sdp() { #ifdef VIDEO_ENABLED LinphoneCoreManager* caller = linphone_core_manager_new( "pauline_rc"); LinphoneCoreManager* callee = linphone_core_manager_new( "marie_rc"); @@ -3386,8 +3484,8 @@ static void outgoing_reinvite_without_ack_sdp() { if (out_call) { stats initial_caller_stat=caller->stat; stats initial_callee_stat=callee->stat; - sal_call_enable_sdp_removal(out_call->op, TRUE); - CU_ASSERT_PTR_NOT_NULL(setup_video(caller, callee)); + sal_call_set_sdp_handling(out_call->op, SalOpSDPSimulateError); /* will force a parse error for the ACK SDP*/ + CU_ASSERT_PTR_NOT_NULL(setup_video(caller, callee)); CU_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallUpdating,initial_callee_stat.number_of_LinphoneCallUpdating+1)); CU_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallStreamsRunning,initial_callee_stat.number_of_LinphoneCallStreamsRunning+1)); CU_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&caller->stat.number_of_LinphoneCallStreamsRunning,initial_caller_stat.number_of_LinphoneCallStreamsRunning)); @@ -3400,7 +3498,7 @@ static void outgoing_reinvite_without_ack_sdp() { CU_ASSERT_FALSE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(callee->lc)))); CU_ASSERT_FALSE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(caller->lc)))); - sal_call_enable_sdp_removal(out_call->op, FALSE); + sal_call_set_sdp_handling(out_call->op, SalOpSDPNormal); } linphone_core_terminate_all_calls(caller->lc); CU_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&caller->stat.number_of_LinphoneCallEnd,1)); @@ -3413,6 +3511,255 @@ static void outgoing_reinvite_without_ack_sdp() { #endif } + +static void call_with_paused_no_sdp_on_resume() { + int begin; + int leaked_objects; + int dummy=0; + LinphoneCoreManager* marie; + LinphoneCoreManager* pauline; + LinphoneCall* call_marie = 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"); + CU_ASSERT_TRUE(call(pauline,marie)); + liblinphone_tester_check_rtcp(marie,pauline); + + call_marie = linphone_core_get_current_call(marie->lc); + CU_ASSERT_PTR_NOT_NULL(call_marie); + + ms_message("== Call is OK =="); + + /* the called party pause the call */ + wait_for_until(pauline->lc, marie->lc, NULL, 5, 3000); + + linphone_core_pause_call(marie->lc,call_marie); + ms_message("== Call pausing =="); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausing,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausedByRemote,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPaused,1)); + + /*stay in pause a little while in order to generate traffic*/ + wait_for_until(pauline->lc, marie->lc, NULL, 5, 2000); + + ms_message("== Call paused, marie call: %p ==", call_marie); + + linphone_core_enable_sdp_200_ack(marie->lc,TRUE); + + linphone_core_resume_call(marie->lc,call_marie); + + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + + wait_for_until(marie->lc, pauline->lc, &dummy, 1, 3000); + CU_ASSERT_TRUE(linphone_call_get_audio_stats(call_marie)->download_bandwidth>70); + CU_ASSERT_TRUE(linphone_call_get_audio_stats(linphone_core_get_current_call(pauline->lc))->download_bandwidth>70); + + end_call(marie,pauline); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + + leaked_objects=belle_sip_object_get_object_count()-begin; + CU_ASSERT_TRUE(leaked_objects==0); + if (leaked_objects>0){ + belle_sip_object_dump_active_objects(); + } +} + + +static void call_with_early_media_and_no_sdp_in_200(){ +LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_rc"); + MSList* lcs = NULL; + LinphoneCall* marie_call; + LinphoneCallParams* params = NULL; + LinphoneCallLog *marie_call_log; + uint64_t connected_time=0; + uint64_t ended_time=0; + int dummy=0; + + lcs = ms_list_append(lcs,marie->lc); + lcs = ms_list_append(lcs,pauline->lc); + /* + Marie calls Pauline, and after the call has rung, transitions to an early_media session + */ + params = linphone_core_create_default_call_parameters(marie->lc); + linphone_call_params_enable_video(params, TRUE); + + linphone_core_enable_video_capture(pauline->lc, TRUE); + linphone_core_enable_video_display(pauline->lc, TRUE); + linphone_core_enable_video_capture(marie->lc, TRUE); + linphone_core_enable_video_display(marie->lc, FALSE); + + marie_call = linphone_core_invite_address_with_params(marie->lc, pauline->identity, params); + marie_call_log = linphone_call_get_call_log(marie_call); + + CU_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingReceived,1,3000)); + CU_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingRinging,1,1000)); + + if (linphone_core_inc_invite_pending(pauline->lc)) { + LinphoneCall* pauline_call = linphone_core_get_current_call(pauline->lc); + + /* send a 183 to initiate the early media */ + linphone_core_accept_early_media(pauline->lc, pauline_call); + + CU_ASSERT_TRUE( wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingEarlyMedia,1,2000) ); + CU_ASSERT_TRUE( wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingEarlyMedia,1,2000) ); + + liblinphone_tester_check_rtcp(marie, pauline); + + /* will send the 200OK _without_ SDP. We expect the early-media SDP to be used instead */ + sal_call_set_sdp_handling(pauline_call->op, SalOpSDPSimulateRemove); + linphone_core_accept_call(pauline->lc, pauline_call); + + CU_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallConnected, 1,1000)); + connected_time=ms_get_cur_time_ms(); + CU_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 1,3000)); + + ms_error("Streams running= %d", marie->stat.number_of_LinphoneCallStreamsRunning); + + CU_ASSERT_EQUAL(marie_call, linphone_core_get_current_call(marie->lc)); + + liblinphone_tester_check_rtcp(marie, pauline); + /*just to have a call duration !=0*/ + wait_for_list(lcs,&dummy,1,2000); + + linphone_core_terminate_all_calls(pauline->lc); + + 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=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); + } + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_with_generic_cn(void) { + int begin; + int leaked_objects; + LinphoneCoreManager* marie; + LinphoneCoreManager* pauline; + LinphoneCall *pauline_call; + char *audio_file_with_silence=ms_strdup_printf("%s/%s",liblinphone_tester_file_prefix,"sounds/ahbahouaismaisbon.wav"); + char *recorded_file=ms_strdup_printf("%s/%s",liblinphone_tester_writable_dir_prefix,"result.wav"); + + 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"); + + remove(recorded_file); + + linphone_core_use_files(marie->lc,TRUE); + linphone_core_use_files(pauline->lc,TRUE); + linphone_core_set_play_file(marie->lc, audio_file_with_silence); + /*linphone_core_set_play_file(pauline->lc, NULL);*/ + linphone_core_set_record_file(pauline->lc, recorded_file); + linphone_core_enable_generic_confort_noise(marie->lc, TRUE); + linphone_core_enable_generic_confort_noise(pauline->lc, TRUE); + CU_ASSERT_TRUE(call(marie,pauline)); + pauline_call=linphone_core_get_current_call(pauline->lc); + CU_ASSERT_PTR_NOT_NULL(pauline_call); + if (pauline_call){ + const rtp_stats_t *rtps; + + wait_for_until(marie->lc, pauline->lc, NULL, 0, 8000); + rtps=rtp_session_get_stats(pauline_call->audiostream->ms.sessions.rtp_session); + CU_ASSERT_TRUE(rtps->packet_recv<=300 && rtps->packet_recv>=200); + } + end_call(marie,pauline); + + if (pauline_call){ + struct stat stbuf; + int err; + + err=stat(recorded_file,&stbuf); + CU_ASSERT_EQUAL(err, 0); + if (err==0){ + CU_ASSERT_TRUE(stbuf.st_size>120000); + } + } + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + + leaked_objects=belle_sip_object_get_object_count()-begin; + CU_ASSERT_TRUE(leaked_objects==0); + if (leaked_objects>0){ + belle_sip_object_dump_active_objects(); + } + ms_free(audio_file_with_silence); + ms_free(recorded_file); +} +void static call_state_changed_2(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *msg){ + LCSipTransports sip_tr; + if (cstate==LinphoneCallReleased) { + /*to make sure transport is changed*/ + sip_tr.udp_port = 0; + sip_tr.tcp_port = 45876; + sip_tr.tls_port = 0; + + linphone_core_set_sip_transports(lc,&sip_tr); + } +} + +static void call_with_transport_change_base(bool_t succesfull_call) { + int begin; + int leaked_objects; + LCSipTransports sip_tr; + LinphoneCoreManager* marie; + LinphoneCoreManager* pauline; + LinphoneCoreVTable * v_table; + belle_sip_object_enable_leak_detector(TRUE); + begin=belle_sip_object_get_object_count(); + v_table = linphone_core_v_table_new(); + v_table->call_state_changed=call_state_changed_2; + marie = linphone_core_manager_new("marie_rc"); + pauline = linphone_core_manager_new( "pauline_rc"); + linphone_core_add_listener(marie->lc,v_table); + + sip_tr.udp_port = 0; + sip_tr.tcp_port = 45875; + sip_tr.tls_port = 0; + linphone_core_set_sip_transports(marie->lc,&sip_tr); + if (succesfull_call) { + CU_ASSERT_TRUE(call(marie,pauline)); + linphone_core_terminate_all_calls(marie->lc); + } + else + linphone_core_invite(marie->lc,"nexiste_pas"); + + if (succesfull_call) + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallReleased,1)); + if (succesfull_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,&pauline->stat.number_of_LinphoneCallReleased,1)); + } + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + + leaked_objects=belle_sip_object_get_object_count()-begin; + CU_ASSERT_TRUE(leaked_objects==0); + if (leaked_objects>0){ + belle_sip_object_dump_active_objects(); + } + +} +static void call_with_transport_change_after_released(void) { + call_with_transport_change_base(TRUE); +} +static void unsucessfull_call_with_transport_change_after_released(void) { + call_with_transport_change_base(FALSE); +} + test_t call_tests[] = { { "Early declined call", early_declined_call }, { "Call declined", call_declined }, @@ -3420,8 +3767,8 @@ test_t call_tests[] = { { "Early cancelled call", early_cancelled_call}, { "Call with DNS timeout", call_with_dns_time_out }, { "Cancelled ringing call", cancelled_ringing_call }, - { "Call failed because of codecs", call_failed_because_of_codecs }, { "Simple call", simple_call }, + { "Call with timeouted bye", call_with_timeouted_bye }, { "Direct call over IPv6", direct_call_over_ipv6}, { "Outbound call with multiple proxy possible", call_outbound_with_multiple_proxy }, { "Audio call recording", audio_call_recording_test }, @@ -3438,17 +3785,22 @@ 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 }, { "SRTP call", srtp_call }, { "ZRTP call",zrtp_call}, + { "DTLS SRTP call",dtls_srtp_call}, { "ZRTP video call",zrtp_video_call}, { "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 ZRTP video call",video_call_zrtp}, + { "Simple DTLS video call",video_call_dtls}, { "Simple video call using policy",video_call_using_policy}, { "Video call without SDP",video_call_no_sdp}, { "SRTP ice video call", srtp_video_ice_call }, @@ -3462,13 +3814,18 @@ 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 }, + { "DTLS SRTP video call",dtls_srtp_video_call}, + { "DTLS SRTP ice video call",dtls_srtp_ice_video_call}, + { "DTLS SRTP ice video call with relay",dtls_srtp_ice_video_call_with_relay}, #endif { "SRTP ice call", srtp_ice_call }, { "ZRTP ice call", zrtp_ice_call }, { "ZRTP ice call with relay", zrtp_ice_call_with_relay}, + { "DTLS SRTP ice call",dtls_srtp_ice_call}, + { "DTLS ice call with relay", dtls_ice_call_with_relay}, { "Call with privacy", call_with_privacy }, { "Call with privacy 2", call_with_privacy2 }, { "Call rejected because of wrong credential", call_rejected_because_wrong_credentials}, @@ -3494,31 +3851,20 @@ test_t call_tests[] = { { "Call established with rejected RE-INVITE in error", call_established_with_rejected_reinvite_with_error}, { "Call redirected by callee", call_redirect}, { "Call with specified codec bitrate", call_with_specified_codec_bitrate}, - { "AVP to AVP call", avp_to_avp_call }, - { "AVP to AVPF call", avp_to_avpf_call }, - { "AVP to SAVP call", avp_to_savp_call }, - { "AVP to SAVPF call", avp_to_savpf_call }, - { "AVPF to AVP call", avpf_to_avp_call }, - { "AVPF to AVPF call", avpf_to_avpf_call }, - { "AVPF to SAVP call", avpf_to_savp_call }, - { "AVPF to SAVPF call", avpf_to_savpf_call }, - { "SAVP to AVP call", savp_to_avp_call }, - { "SAVP to AVPF call", savp_to_avpf_call }, - { "SAVP to SAVP call", savp_to_savp_call }, - { "SAVP to SAVPF call", savp_to_savpf_call }, - { "SAVPF to AVP call", savpf_to_avp_call }, - { "SAVPF to AVPF call", savpf_to_avpf_call }, - { "SAVPF to SAVP call", savpf_to_savp_call }, - { "SAVPF to SAVPF call", savpf_to_savpf_call }, { "Call with in-dialog UPDATE request", call_with_in_dialog_update }, { "Call with in-dialog codec change", call_with_in_dialog_codec_change }, { "Call with in-dialog codec change no sdp", call_with_in_dialog_codec_change_no_sdp }, + { "Call with pause no SDP on resume", call_with_paused_no_sdp_on_resume }, + { "Call with early media and no SDP on 200 Ok", call_with_early_media_and_no_sdp_in_200 }, { "Call with custom supported tags", call_with_custom_supported_tags }, { "Call log from taken from asserted id",call_log_from_taken_from_p_asserted_id}, - { "Incoming INVITE without SDP",incoming_invite_without_sdp}, - { "Outgoing INVITE without ACK SDP",outgoing_invite_without_sdp}, - { "Incoming REINVITE without SDP",incoming_reinvite_without_ack_sdp}, - { "Outgoing REINVITE without ACK SDP",outgoing_reinvite_without_ack_sdp}, + { "Incoming INVITE with invalid SDP",incoming_invite_with_invalid_sdp}, + { "Outgoing INVITE with invalid ACK SDP",outgoing_invite_with_invalid_sdp}, + { "Incoming REINVITE with invalid SDP in ACK",incoming_reinvite_with_invalid_ack_sdp}, + { "Outgoing REINVITE with invalid SDP in ACK",outgoing_reinvite_with_invalid_ack_sdp}, + { "Call with generic CN", call_with_generic_cn }, + { "Call with transport change after released", call_with_transport_change_after_released }, + { "Unsuccessful call with transport change after released",unsucessfull_call_with_transport_change_after_released} }; test_suite_t call_test_suite = { diff --git a/tester/dtmf_tester.c b/tester/dtmf_tester.c index fa627cfd4..c4c2e3bfe 100644 --- a/tester/dtmf_tester.c +++ b/tester/dtmf_tester.c @@ -29,10 +29,12 @@ void dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf) { *dst = *dst ? ms_strcat_printf(*dst, "%c", dtmf) : ms_strdup_printf("%c", dtmf); + counters->dtmf_count++; } void send_dtmf_base(bool_t use_rfc2833, bool_t use_sipinfo, char dtmf, char* dtmf_seq) { char* expected = NULL; + int dtmf_count_prev; marie = linphone_core_manager_new( "marie_rc"); pauline = linphone_core_manager_new( "pauline_rc"); @@ -44,21 +46,27 @@ void send_dtmf_base(bool_t use_rfc2833, bool_t use_sipinfo, char dtmf, char* dtm CU_ASSERT_TRUE(call(pauline,marie)); marie_call = linphone_core_get_current_call(marie->lc); + + CU_ASSERT_PTR_NOT_NULL(marie_call); + + if (!marie_call) return; if (dtmf != '\0') { + dtmf_count_prev = pauline->stat.dtmf_count; linphone_call_send_dtmf(marie_call, dtmf); /*wait for the DTMF to be received from pauline*/ - wait_for_until(marie->lc, pauline->lc, NULL, 0, 1000); + CU_ASSERT_TRUE(wait_for_until(marie->lc, pauline->lc, &pauline->stat.dtmf_count, dtmf_count_prev+1, 10000)); expected = ms_strdup_printf("%c", dtmf); } if (dtmf_seq != NULL) { int dtmf_delay_ms = lp_config_get_int(marie_call->core->config,"net","dtmf_delay_ms",200); + dtmf_count_prev = pauline->stat.dtmf_count; linphone_call_send_dtmfs(marie_call, dtmf_seq); /*wait for the DTMF sequence to be received from pauline*/ - wait_for_until(marie->lc, pauline->lc, NULL, 0, 1000 + dtmf_delay_ms * strlen(dtmf_seq)); + CU_ASSERT_TRUE(wait_for_until(marie->lc, pauline->lc, &pauline->stat.dtmf_count, dtmf_count_prev + strlen(dtmf_seq), 10000 + dtmf_delay_ms * strlen(dtmf_seq))); expected = (dtmf!='\0')?ms_strdup_printf("%c%s",dtmf,dtmf_seq):ms_strdup(dtmf_seq); } diff --git a/tester/eventapi_tester.c b/tester/eventapi_tester.c index 1d4b07e59..fbe48f9a4 100644 --- a/tester/eventapi_tester.c +++ b/tester/eventapi_tester.c @@ -40,7 +40,7 @@ const char *liblinphone_tester_get_notify_content(void){ void linphone_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char *eventname, const LinphoneContent *content){ LinphoneCoreManager *mgr; CU_ASSERT_PTR_NOT_NULL_FATAL(content); - CU_ASSERT_TRUE(strcmp(notify_content,(const char*)content->data)==0); + CU_ASSERT_TRUE(strcmp(notify_content,(const char*)linphone_content_get_buffer(content))==0); mgr=get_manager(lc); mgr->stat.number_of_NotifyReceived++; } @@ -48,13 +48,13 @@ void linphone_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char * void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *lev, LinphoneSubscriptionState state) { stats* counters = get_stats(lc); LinphoneCoreManager *mgr=get_manager(lc); - LinphoneContent content={0}; + LinphoneContent* content; const LinphoneAddress* from_addr = linphone_event_get_from(lev); char* from = linphone_address_as_string(from_addr); - content.type="application"; - content.subtype="somexml2"; - content.data=(void*)notify_content; - content.size=strlen(notify_content); + content = linphone_core_create_content(lc); + linphone_content_set_type(content,"application"); + linphone_content_set_subtype(content,"somexml2"); + linphone_content_set_buffer(content,notify_content,strlen(notify_content)); ms_message("Subscription state [%s] from [%s]",linphone_subscription_state_to_string(state),from); ms_free(from); @@ -80,7 +80,7 @@ void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *lev, Li counters->number_of_LinphoneSubscriptionActive++; if (linphone_event_get_subscription_dir(lev)==LinphoneSubscriptionIncoming){ mgr->lev=lev; - linphone_event_notify(lev,&content); + linphone_event_notify(lev,content); } break; case LinphoneSubscriptionTerminated: @@ -96,6 +96,7 @@ void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *lev, Li mgr->lev=NULL; break; } + linphone_content_unref(content); } void linphone_publish_state_changed(LinphoneCore *lc, LinphoneEvent *ev, LinphonePublishState state){ @@ -123,23 +124,22 @@ void linphone_publish_state_changed(LinphoneCore *lc, LinphoneEvent *ev, Linphon static void subscribe_test_declined(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - LinphoneContent content={0}; + LinphoneContent* content; LinphoneEvent *lev; const LinphoneErrorInfo *ei; MSList* lcs=ms_list_append(NULL,marie->lc); lcs=ms_list_append(lcs,pauline->lc); + content = linphone_core_create_content(marie->lc); + linphone_content_set_type(content,"application"); + linphone_content_set_subtype(content,"somexml"); + linphone_content_set_buffer(content,subscribe_content,strlen(subscribe_content)); - content.type="application"; - content.subtype="somexml"; - content.data=(char*)subscribe_content; - content.size=strlen(subscribe_content); - pauline->decline_subscribe=TRUE; - - lev=linphone_core_subscribe(marie->lc,pauline->identity,"dodo",600,&content); + + lev=linphone_core_subscribe(marie->lc,pauline->identity,"dodo",600,content); linphone_event_ref(lev); - + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionOutgoingInit,1,1000)); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,3000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionError,1,21000));/*yes flexisip may wait 20 secs in case of forking*/ @@ -150,7 +150,8 @@ static void subscribe_test_declined(void) { CU_ASSERT_PTR_NOT_NULL(linphone_error_info_get_phrase(ei)); } CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionTerminated,1,1000)); - + + linphone_content_unref(content); linphone_event_unref(lev); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); @@ -165,23 +166,23 @@ typedef enum RefreshTestType{ static void subscribe_test_with_args(bool_t terminated_by_subscriber, RefreshTestType refresh_type) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - LinphoneContent content={0}; + LinphoneContent* content; LinphoneEvent *lev; int expires= refresh_type!=NoRefresh ? 4 : 600; MSList* lcs=ms_list_append(NULL,marie->lc); - + lcs=ms_list_append(lcs,pauline->lc); if (refresh_type==ManualRefresh){ lp_config_set_int(marie->lc->config,"sip","refresh_generic_subscribe",0); } - content.type="application"; - content.subtype="somexml"; - content.data=(char*)subscribe_content; - content.size=strlen(subscribe_content); - - lev=linphone_core_subscribe(marie->lc,pauline->identity,"dodo",expires,&content); + content = linphone_core_create_content(marie->lc); + linphone_content_set_type(content,"application"); + linphone_content_set_subtype(content,"somexml"); + linphone_content_set_buffer(content,subscribe_content,strlen(subscribe_content)); + + lev=linphone_core_subscribe(marie->lc,pauline->identity,"dodo",expires,content); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionOutgoingInit,1,1000)); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,3000)); @@ -190,7 +191,7 @@ static void subscribe_test_with_args(bool_t terminated_by_subscriber, RefreshTes /*make sure marie receives first notification before terminating*/ CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_NotifyReceived,1,1000)); - + if (refresh_type==AutoRefresh){ wait_for_list(lcs,NULL,0,6000); CU_ASSERT_TRUE(linphone_event_get_subscription_state(pauline->lev)==LinphoneSubscriptionActive); @@ -206,10 +207,11 @@ static void subscribe_test_with_args(bool_t terminated_by_subscriber, RefreshTes CU_ASSERT_PTR_NOT_NULL_FATAL(pauline->lev); linphone_event_terminate(pauline->lev); } - + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionTerminated,1,1000)); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionTerminated,1,1000)); - + + linphone_content_unref(content); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } @@ -217,7 +219,7 @@ static void subscribe_test_with_args(bool_t terminated_by_subscriber, RefreshTes static void subscribe_test_with_args2(bool_t terminated_by_subscriber, RefreshTestType refresh_type) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - LinphoneContent content={0}; + LinphoneContent* content; LinphoneEvent *lev; int expires= refresh_type!=NoRefresh ? 4 : 600; MSList* lcs=ms_list_append(NULL,marie->lc); @@ -228,28 +230,28 @@ static void subscribe_test_with_args2(bool_t terminated_by_subscriber, RefreshTe lp_config_set_int(marie->lc->config,"sip","refresh_generic_subscribe",0); } - content.type="application"; - content.subtype="somexml"; - content.data=(char*)subscribe_content; - content.size=strlen(subscribe_content); - + content = linphone_core_create_content(marie->lc); + linphone_content_set_type(content,"application"); + linphone_content_set_subtype(content,"somexml"); + linphone_content_set_buffer(content,subscribe_content,strlen(subscribe_content)); + lev=linphone_core_create_subscribe(marie->lc,pauline->identity,"dodo",expires); linphone_event_add_custom_header(lev,"My-Header","pouet"); linphone_event_add_custom_header(lev,"My-Header2","pimpon"); - linphone_event_send_subscribe(lev,&content); - + linphone_event_send_subscribe(lev,content); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionOutgoingInit,1,1000)); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,3000)); - + /*check good receipt of custom headers*/ CU_ASSERT_STRING_EQUAL(linphone_event_get_custom_header(pauline->lev,"My-Header"),"pouet"); CU_ASSERT_STRING_EQUAL(linphone_event_get_custom_header(pauline->lev,"My-Header2"),"pimpon"); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionActive,1,1000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionActive,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionActive,1,5000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionActive,1,5000)); /*make sure marie receives first notification before terminating*/ - CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_NotifyReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_NotifyReceived,1,5000)); if (refresh_type==AutoRefresh){ wait_for_list(lcs,NULL,0,6000); @@ -257,7 +259,7 @@ static void subscribe_test_with_args2(bool_t terminated_by_subscriber, RefreshTe }else if (refresh_type==ManualRefresh){ CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionExpiring,1,4000)); linphone_event_update_subscribe(lev,NULL); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionActive,2,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionActive,2,5000)); } if (terminated_by_subscriber){ @@ -266,10 +268,11 @@ static void subscribe_test_with_args2(bool_t terminated_by_subscriber, RefreshTe CU_ASSERT_PTR_NOT_NULL_FATAL(pauline->lev); linphone_event_terminate(pauline->lev); } - - CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionTerminated,1,1000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionTerminated,1,1000)); - + + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionTerminated,1,5000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionTerminated,1,5000)); + + linphone_content_unref(content); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } @@ -300,30 +303,29 @@ static void subscribe_test_manually_refreshed(void){ static void publish_test_with_args(bool_t refresh, int expires){ LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - LinphoneContent content={0}; + LinphoneContent* content; LinphoneEvent *lev; MSList* lcs=ms_list_append(NULL,marie->lc); lcs=ms_list_append(lcs,pauline->lc); + content = linphone_core_create_content(marie->lc); + linphone_content_set_type(content,"application"); + linphone_content_set_subtype(content,"somexml"); + linphone_content_set_buffer(content,subscribe_content,strlen(subscribe_content)); - content.type="application"; - content.subtype="somexml"; - content.data=(char*)subscribe_content; - content.size=strlen(subscribe_content); - lp_config_set_int(marie->lc->config,"sip","refresh_generic_publish",refresh); lev=linphone_core_create_publish(marie->lc,pauline->identity,"dodo",expires); linphone_event_add_custom_header(lev,"CustomHeader","someValue"); - linphone_event_send_publish(lev,&content); + linphone_event_send_publish(lev,content); linphone_event_ref(lev); - + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishProgress,1,1000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishOk,1,3000)); - + if (!refresh){ CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishExpiring,1,5000)); - linphone_event_update_publish(lev,&content); + linphone_event_update_publish(lev,content); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishProgress,1,1000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishOk,1,3000)); }else{ @@ -331,11 +333,12 @@ static void publish_test_with_args(bool_t refresh, int expires){ } linphone_event_terminate(lev); - + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishCleared,1,3000)); - + linphone_event_unref(lev); - + + linphone_content_unref(content); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } diff --git a/tester/flexisip/flexisip.conf b/tester/flexisip/flexisip.conf index 12f42d945..96ac77cc4 100755 --- a/tester/flexisip/flexisip.conf +++ b/tester/flexisip/flexisip.conf @@ -18,7 +18,7 @@ auto-respawn=true # List of white space separated host names pointing to this machine. # This is to prevent loops while routing SIP messages. # Default value: localhost -aliases=localhost sipopen.example.org sip.example.org auth.example.org auth1.example.org auth2.example.org client.example.org +aliases=localhost sipopen.example.org sip.example.org auth.example.org auth1.example.org auth2.example.org client.example.org sip2.linphone.org # List of white space separated SIP uris where the proxy must listen.Wildcard # (*) can be used to mean 'all local ip addresses'. If 'transport' @@ -205,6 +205,15 @@ hashed-passwords=false # Default value: false new-auth-on-407=false +# Enable a feature useful for automatic tests, allowing a client +# to create a temporary account in the password database in memory. +# This MUST not be used for production as it is a real security +# hole. +# Default value: false + +enable-test-accounts-creation=true + + ## ## ... ## diff --git a/tester/flexisip_tester.c b/tester/flexisip_tester.c index a91811538..948df8fba 100644 --- a/tester/flexisip_tester.c +++ b/tester/flexisip_tester.c @@ -27,7 +27,7 @@ static void subscribe_forking(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); LinphoneCoreManager* pauline2 = linphone_core_manager_new( "pauline_tcp_rc"); - LinphoneContent content={0}; + LinphoneContent* content; LinphoneEvent *lev; int expires= 600; MSList* lcs=ms_list_append(NULL,marie->lc); @@ -35,12 +35,12 @@ static void subscribe_forking(void) { lcs=ms_list_append(lcs,pauline->lc); lcs=ms_list_append(lcs,pauline2->lc); - content.type="application"; - content.subtype="somexml"; - content.data=(char*)liblinphone_tester_get_subscribe_content(); - content.size=strlen(liblinphone_tester_get_subscribe_content()); + content = linphone_core_create_content(marie->lc); + linphone_content_set_type(content,"application"); + linphone_content_set_subtype(content,"somexml"); + linphone_content_set_buffer(content, liblinphone_tester_get_subscribe_content(), strlen(liblinphone_tester_get_subscribe_content())); - lev=linphone_core_subscribe(marie->lc,pauline->identity,"dodo",expires,&content); + lev=linphone_core_subscribe(marie->lc,pauline->identity,"dodo",expires,content); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionOutgoingInit,1,1000)); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,3000)); @@ -51,7 +51,8 @@ static void subscribe_forking(void) { CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_NotifyReceived,1,1000)); linphone_event_terminate(lev); - + + linphone_content_unref(content); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); linphone_core_manager_destroy(pauline2); @@ -145,7 +146,7 @@ static void message_forking_with_all_recipients_unreachable(void) { linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,pauline->lc); - CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneMessageInProgress,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneMessageInProgress,1,5000)); /*flexisip will accept the message with 202 after 16 seconds*/ CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneMessageDelivered,1,18000)); CU_ASSERT_TRUE( marie->stat.number_of_LinphoneMessageReceived==0); @@ -194,9 +195,9 @@ static void call_forking(void){ /*pauline should hear ringback*/ CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,3000)); /*all devices from Marie should be ringing*/ - CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallIncomingReceived,1,1000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived,1,1000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallIncomingReceived,1,3000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived,1,3000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneCallIncomingReceived,1,3000)); /*marie accepts the call on its first device*/ linphone_core_accept_call(marie->lc,linphone_core_get_current_call(marie->lc)); @@ -306,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"); @@ -322,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)); @@ -375,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"); @@ -390,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:*/ @@ -407,7 +396,7 @@ static void call_forking_with_push_notification_single(void){ /*marie accepts the call*/ linphone_core_accept_call(marie->lc,linphone_core_get_current_call(marie->lc)); - CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallConnected,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallConnected,1,5000)); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,1000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallConnected,1,1000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,1,1000)); @@ -415,8 +404,8 @@ static void call_forking_with_push_notification_single(void){ liblinphone_tester_check_rtcp(pauline,marie); linphone_core_terminate_call(pauline->lc,linphone_core_get_current_call(pauline->lc)); - 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)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,5000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,5000)); linphone_core_manager_destroy(pauline); linphone_core_manager_destroy(marie); @@ -424,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"); @@ -441,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*/ @@ -483,7 +464,7 @@ static void call_forking_with_push_notification_multiple(void){ linphone_core_manager_destroy(marie2); } -void call_forking_not_responded(void){ +static void call_forking_not_responded(void){ 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"); @@ -522,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; @@ -532,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; @@ -546,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); @@ -572,16 +544,20 @@ static void early_media_call_forking(void) { CU_ASSERT_TRUE(wait_for_list(lcs, &marie1->stat.number_of_LinphoneCallIncomingEarlyMedia,1,3000)); CU_ASSERT_TRUE(wait_for_list(lcs, &marie2->stat.number_of_LinphoneCallIncomingEarlyMedia,1,3000)); CU_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallOutgoingEarlyMedia,1,3000)); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallOutgoingEarlyMedia,1); pauline_call=linphone_core_get_current_call(pauline->lc); marie1_call=linphone_core_get_current_call(marie1->lc); marie2_call=linphone_core_get_current_call(marie2->lc); /*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); - 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); + wait_for_list(lcs,&dummy,1,6000); + 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)); @@ -591,13 +567,15 @@ static void early_media_call_forking(void) { CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallEnd,1,1000)); /*wait a bit that streams are established*/ - wait_for_list(lcs,&dummy,1,1000); - CU_ASSERT_TRUE(linphone_call_get_audio_stats(pauline_call)->download_bandwidth>71); - CU_ASSERT_TRUE(linphone_call_get_audio_stats(marie1_call)->download_bandwidth>71); + wait_for_list(lcs,&dummy,1,3000); + 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)); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallEnd,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,5000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallEnd,1,5000)); ms_list_free(lcs); linphone_core_manager_destroy(marie1); @@ -605,6 +583,136 @@ static void early_media_call_forking(void) { linphone_core_manager_destroy(pauline); } +static void call_with_sips(void){ + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_sips_rc"); + LinphoneCoreManager* pauline1 = linphone_core_manager_new( "pauline_sips_rc"); + LinphoneCoreManager* pauline2 = linphone_core_manager_new( "pauline_tcp_rc"); + MSList* lcs=ms_list_append(NULL,marie->lc); + + lcs=ms_list_append(lcs,pauline1->lc); + lcs=ms_list_append(lcs,pauline2->lc); + + linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(pauline1->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(pauline2->lc,"Natted Linphone",NULL); + + linphone_core_invite_address(marie->lc,pauline1->identity); + + /*marie should hear ringback*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallOutgoingRinging,1,3000)); + /*Only the sips registered device from pauline should ring*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline1->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + + /*pauline accepts the call */ + linphone_core_accept_call(pauline1->lc,linphone_core_get_current_call(pauline1->lc)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline1->stat.number_of_LinphoneCallConnected,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline1->stat.number_of_LinphoneCallStreamsRunning,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallConnected,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,1,1000)); + + /*pauline2 should not have ring*/ + CU_ASSERT_TRUE(pauline2->stat.number_of_LinphoneCallIncomingReceived==0); + + linphone_core_terminate_call(pauline1->lc,linphone_core_get_current_call(pauline1->lc)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline1->stat.number_of_LinphoneCallEnd,1,3000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,3000)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline1); + linphone_core_manager_destroy(pauline2); + ms_list_free(lcs); +} + +static void call_with_sips_not_achievable(void){ + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_sips_rc"); + LinphoneCoreManager* pauline1 = linphone_core_manager_new( "pauline_rc"); + LinphoneCoreManager* pauline2 = linphone_core_manager_new( "pauline_tcp_rc"); + MSList* lcs=ms_list_append(NULL,marie->lc); + LinphoneAddress *dest; + LinphoneCall *call; + const LinphoneErrorInfo *ei; + + lcs=ms_list_append(lcs,pauline1->lc); + lcs=ms_list_append(lcs,pauline2->lc); + + + dest=linphone_address_clone(pauline1->identity); + linphone_address_set_secure(dest,TRUE); + call=linphone_core_invite_address(marie->lc,dest); + linphone_call_ref(call); + linphone_address_unref(dest); + + /*Call should be rejected by server with 480*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallError,1,6000)); + ei=linphone_call_get_error_info(call); + CU_ASSERT_PTR_NOT_NULL(ei); + if (ei){ + CU_ASSERT_EQUAL(linphone_error_info_get_reason(ei), LinphoneReasonTemporarilyUnavailable); + } + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline1); + linphone_core_manager_destroy(pauline2); + ms_list_free(lcs); +} + +static void call_with_ipv6(void) { + int begin; + int leaked_objects; + LinphoneCoreManager* marie; + LinphoneCoreManager* pauline; + LinphoneCall *pauline_call; + + /*calling ortp_init() here is done to have WSAStartup() done, otherwise liblinphone_tester_ipv6_available() will not work.*/ + ortp_init(); + + if (!liblinphone_tester_ipv6_available()){ + ms_warning("Call with ipv6 not tested, no ipv6 connectivity"); + return; + } + + belle_sip_object_enable_leak_detector(TRUE); + begin=belle_sip_object_get_object_count(); + + liblinphone_tester_enable_ipv6(TRUE); + marie = linphone_core_manager_new( "marie_rc"); + pauline = linphone_core_manager_new( "pauline_rc"); + + linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); + CU_ASSERT_TRUE(call(marie,pauline)); + pauline_call=linphone_core_get_current_call(pauline->lc); + CU_ASSERT_PTR_NOT_NULL(pauline_call); + if (pauline_call){ + /*check that the remote contact is IPv6*/ + const char *contact=linphone_call_get_remote_contact(pauline_call); + LinphoneAddress *ct_addr; + + CU_ASSERT_PTR_NOT_NULL(contact); + if (contact){ + ct_addr=linphone_address_new(contact); + CU_ASSERT_PTR_NOT_NULL(ct_addr); + if (ct_addr){ + CU_ASSERT_TRUE(strchr(linphone_address_get_domain(ct_addr),':')!=NULL); + } + linphone_address_destroy(ct_addr); + } + + } + + liblinphone_tester_check_rtcp(marie,pauline); + end_call(marie,pauline); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + liblinphone_tester_enable_ipv6(FALSE); + + leaked_objects=belle_sip_object_get_object_count()-begin; + CU_ASSERT_TRUE(leaked_objects==0); + if (leaked_objects>0){ + belle_sip_object_dump_active_objects(); + } + ortp_exit(); +} test_t flexisip_tests[] = { { "Subscribe forking", subscribe_forking }, @@ -620,6 +728,9 @@ test_t flexisip_tests[] = { { "Call forking with push notification (multiple)", call_forking_with_push_notification_multiple }, { "Call forking not responded", call_forking_not_responded }, { "Early-media call forking", early_media_call_forking }, + { "Call with sips", call_with_sips }, + { "Call with sips not achievable", call_with_sips_not_achievable }, + { "Call with ipv6", call_with_ipv6 } }; diff --git a/tester/liblinphone_completion b/tester/liblinphone_completion new file mode 100644 index 000000000..a0d05f3e0 --- /dev/null +++ b/tester/liblinphone_completion @@ -0,0 +1,113 @@ +# Copyright (C) 2012 Belledonne Comunications, 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. + +# Created by Gautier Pelloux-Prayer on 2014/10/24. +# This script adds auto-completion for liblinphone_tester binary for Bash and +# zsh. To use it, just type: `source liblinphone_completion`, then use +# `./liblinphone_tester [tab] to get auto-completions. To use it permanently, +# source this file in your .rc file + +_liblinphone_complete() { + local completions command_requiring_argument prev_arg latest_arg available_tasks has_not_set_suite suite_name + + if [ -n "$BASH_VERSION" ]; then + set -- "${COMP_WORDS[@]}" #convert them to arguments (eg $1,$#,$@,etc.) + elif [ -n "$ZSH_VERSION" ]; then + local args + read -cA args #read list of arguments user entered + set -- "${args[@]}" #convert them to arguments (eg $1,$#,$@,etc.) + fi + #skip program name + program=$1 + shift + + # if user required help, do not complete anything + if ! grep -q -- "--help" <<< "$@"; then + # retrieve the last argument + latest_arg="" + prev_arg="" + latest_is_empty=0 + for arg in "$@"; do + if [ ! -z "$arg" ]; then + prev_arg="$latest_arg" + latest_arg="$arg" + else + latest_is_empty=1 + fi + done + + # get the tasks available, from --help + available_tasks="$($program 2>&1 --help | sed -nE "s/.*--([^ ]*).*/--\\1/p")" + + # these commands expect an argument + command_requiring_argument="$($program 2>&1 --help | sed -nE "s/.*--(.*) <.*/--\\1/p")" + + # remove all already provided tasks (it's useless to provide them twice) + if [[ ! -z "$@" ]]; then + current_tasks=$(echo $@ | grep -Eo -- "--([^ ])*" | tr '\n' '|' | sed 's/|/$|/g')--$ + if [ ! -z "$current_tasks" ]; then + available_tasks=$(echo "$available_tasks" | grep -vE -- "(${current_tasks})") + fi + fi + # remove --test option if --suite is not provided yet! + has_not_set_suite=$(grep -q -- "--suite" <<< "$@"; echo $?) + if [ $has_not_set_suite = 1 ]; then + available_tasks=$(echo "$available_tasks" | grep -v -- --test) + fi + + # if latest arg does not start with '--', it is a custom value + if [ $latest_is_empty = 0 ] && ! grep -q -- '^--' <<< "$latest_arg"; then + # echo "yes!$prev_arg $has_not_set_suite" + if [ "$prev_arg" = "--test" ] && [ $has_not_set_suite = 0 ]; then + suite_name=$(echo $@ | sed -nE 's/.*--suite (.*) (--.*)$/\1/p' |sed "s@\\\\@@g") + completions="$($program --list-tests $suite_name)" + elif [ "$prev_arg" = "--suite" ] || [ "$prev_arg" = "--list-tests" ]; then + completions="$($program --list-suites)" + fi + elif [ "$latest_arg" = "--test" ]; then + if [ $has_not_set_suite = 0 ]; then + suite_name=$(echo $@ | sed -nE 's/.*--suite (.*) (--.*)$/\1/p' |sed "s@\\\\@@g") + completions="$($program --list-tests $suite_name)" + fi + elif [ "$latest_arg" = "--suite" ] || [ "$latest_arg" = "--list-tests" ]; then + completions="$($program --list-suites)" + # we are waiting for a custom value, so do not hint anything + elif [[ ! -z "$latest_arg" ]] && grep -q -- "^$latest_arg$" <<< "$command_requiring_argument"; then + completions="" + else + completions="$available_tasks" + fi + fi + + if [ ! -z "$completions" ]; then + if [ -n "$BASH_VERSION" ]; then + IFS=$'\n' #if that even necessary? + COMPREPLY=($(compgen -W "${completions}" -- ${COMP_WORDS[COMP_CWORD]})) + elif [ -n "$ZSH_VERSION" ]; then + reply=( "${(ps:\n:)completions}" ) + fi + fi +} + +for tester in liblinphone_tester mediastreamer2_tester belle_sip_tester; do + if [ -n "$BASH_VERSION" ]; then + complete -F _liblinphone_complete $tester + elif [ -n "$ZSH_VERSION" ]; then + compctl -K _liblinphone_complete $tester + else + echo "Your shell might be not supported! Only bash and zsh tested." + fi +done diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 171f4eae9..11e31e13b 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -24,6 +24,11 @@ #if HAVE_CU_CURSES #include "CUnit/CUCurses.h" #endif +#ifdef HAVE_GTK +#include +#endif + +extern int liblinphone_tester_use_log_file; #ifdef ANDROID @@ -36,6 +41,8 @@ static JNIEnv *current_env = NULL; static jobject current_obj = 0; static const char* LogDomain = "liblinphone_tester"; +int main(int argc, char** argv); + void linphone_android_log_handler(int prio, const char *fmt, va_list args) { char str[4096]; char *current; @@ -107,6 +114,14 @@ JNIEXPORT jint JNICALL Java_org_linphone_tester_Tester_run(JNIEnv *env, jobject return ret; } +JNIEXPORT void JNICALL Java_org_linphone_tester_Tester_keepAccounts(JNIEnv *env, jclass c, jboolean keep) { + liblinphone_tester_keep_accounts((int)keep); +} + +JNIEXPORT void JNICALL Java_org_linphone_tester_Tester_clearAccounts(JNIEnv *env, jclass c) { + liblinphone_tester_clear_accounts(); +} + #endif /* ANDROID */ #ifdef __QNX__ @@ -115,6 +130,8 @@ static void liblinphone_tester_qnx_log_handler(OrtpLogLevel lev, const char *fmt } #endif /* __QNX__ */ + + void helper(const char *name) { liblinphone_tester_fprintf(stderr,"%s --help\n" "\t\t\t--verbose\n" @@ -127,9 +144,12 @@ void helper(const char *name) { "\t\t\t--suite \n" "\t\t\t--test \n" "\t\t\t--dns-hosts \n" + "\t\t\t--log-file \n" #if HAVE_CU_CURSES "\t\t\t--curses\n" #endif + "\t\t\t--xml\n" + "\t\t\t--xml-file \n" , name); } @@ -148,6 +168,18 @@ int main (int argc, char *argv[]) int ret; const char *suite_name=NULL; const char *test_name=NULL; + const char *xml_file="CUnitAutomated-Results.xml"; + char *xml_tmp_file=NULL; + int xml = 0; + FILE* log_file=NULL; + +#ifdef HAVE_GTK + gtk_init(&argc, &argv); +#if !GLIB_CHECK_VERSION(2,32,0) // backward compatibility with Debian 6 and CentOS 6 + g_thread_init(NULL); +#endif + gdk_threads_init(); +#endif #if defined(ANDROID) linphone_core_set_log_handler(linphone_android_ortp_log_handler); @@ -193,15 +225,50 @@ int main (int argc, char *argv[]) suite_name = argv[i]; liblinphone_tester_list_suite_tests(suite_name); return 0; - } else { + } else if (strcmp(argv[i], "--xml-file") == 0){ + CHECK_ARG("--xml-file", ++i, argc); + xml_file = argv[i]; + xml = 1; + } 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"); + if (!log_file) { + ms_fatal("Cannot open file [%s] for writting logs because [%s]",argv[i],strerror(errno)); + } else { + liblinphone_tester_use_log_file=1; + liblinphone_tester_fprintf(stdout,"Redirecting traces to file [%s]",argv[i]); + linphone_core_set_log_file(log_file); + } + + }else { liblinphone_tester_fprintf(stderr, "Unknown option \"%s\"\n", argv[i]); \ helper(argv[0]); return -1; } } + if( xml && (suite_name || test_name) ){ + printf("Cannot use both xml and specific test suite\n"); + return -1; + } + + if( xml ){ + xml_tmp_file = ms_strdup_printf("%s.tmp", xml_file); + liblinphone_tester_set_xml_output(xml_tmp_file); + } + liblinphone_tester_enable_xml(xml); + ret = liblinphone_tester_run_tests(suite_name, test_name); liblinphone_tester_uninit(); + + if ( xml ) { + /*create real xml file only if tester did not crash*/ + ms_strcat_printf(xml_tmp_file, "-Results.xml"); + rename(xml_tmp_file, xml_file); + ms_free(xml_tmp_file); + } return ret; } #endif /* WINAPI_FAMILY_PHONE_APP */ diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 4bbe1fa3a..c140a6453 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -24,6 +24,9 @@ #include "CUnit/Basic.h" #include "linphonecore.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif typedef void (*test_function_t)(void); typedef int (*test_suite_function_t)(const char *name); @@ -62,6 +65,9 @@ extern test_suite_t log_collection_test_suite; extern test_suite_t transport_test_suite; extern test_suite_t player_test_suite; extern test_suite_t dtmf_test_suite; +extern test_suite_t offeranswer_test_suite; +extern test_suite_t video_test_suite; +extern test_suite_t multicast_call_test_suite; extern int liblinphone_tester_nb_test_suites(void); @@ -79,6 +85,29 @@ 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 + * calls to liblinphone_run_tests(). Some testing APIs call this function for *each* test, + * in which case we should keep the accounts that were created for further testing. + * + * You are supposed to manually call liblinphone_tester_clear_account when all the tests are + * finished. + * + * @param keep 1 to keep the accounts in-between runs, 0 to clear them after each run. + */ +extern void liblinphone_tester_keep_accounts( int keep ); + +/** + * @brief Clears the created accounts during the testing session. + */ +extern void liblinphone_tester_clear_accounts(void); + #ifdef __cplusplus }; #endif @@ -205,6 +234,13 @@ typedef struct _stats { LinphoneChatMessage* last_received_chat_message; char * dtmf_list_received; + int dtmf_count; + + int number_of_rtcp_sent; + int number_of_rtcp_received; + + int number_of_video_windows_created; + }stats; typedef struct _LinphoneCoreManager { @@ -214,11 +250,13 @@ typedef struct _LinphoneCoreManager { LinphoneAddress* identity; LinphoneEvent *lev; bool_t decline_subscribe; + int number_of_cunit_error_at_creation; } LinphoneCoreManager; typedef struct _LinphoneCallTestParams { LinphoneCallParams *base; bool_t sdp_removal; + bool_t sdp_simulate_error; } LinphoneCallTestParams; LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_for_proxies); @@ -234,9 +272,10 @@ 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(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, const char* buff, size_t size); -void file_transfer_send(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, char* buff, size_t* size); -void file_transfer_progress_indication(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t total); +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); void new_subscription_requested(LinphoneCore *lc, LinphoneFriend *lf, const char *url); @@ -246,6 +285,7 @@ void linphone_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char * void linphone_configuration_status(LinphoneCore *lc, LinphoneConfiguringState status, const char *message); void linphone_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t on, const char *authentication_token); void dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf); +void call_stats_updated(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallStats *stats); LinphoneAddress * create_linphone_address(const char * domain); bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value); @@ -263,18 +303,28 @@ bool_t call_with_test_params(LinphoneCoreManager* caller_mgr bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr); void end_call(LinphoneCoreManager *m1, LinphoneCoreManager *m2); +void disable_all_audio_codecs_except_one(LinphoneCore *lc, const char *mime, int rate); +void disable_all_video_codecs_except_one(LinphoneCore *lc, const char *mime); stats * get_stats(LinphoneCore *lc); LinphoneCoreManager *get_manager(LinphoneCore *lc); const char *liblinphone_tester_get_subscribe_content(void); const char *liblinphone_tester_get_notify_content(void); void liblinphone_tester_chat_message_state_change(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud); +void liblinphone_tester_chat_message_msg_state_changed(LinphoneChatMessage *msg, LinphoneChatMessageState state); void liblinphone_tester_check_rtcp(LinphoneCoreManager* caller, LinphoneCoreManager* callee); void liblinphone_tester_clock_start(MSTimeSpec *start); bool_t liblinphone_tester_clock_elapsed(const MSTimeSpec *start, int value_ms); +void linphone_core_manager_check_accounts(LinphoneCoreManager *m); +void account_manager_destroy(void); +LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, const char* file, void* user_data); +void liblinphone_tester_enable_ipv6(bool_t enabled); #ifdef ANDROID void cunit_android_trace_handler(int level, const char *fmt, va_list args) ; #endif int liblinphone_tester_fprintf(FILE * stream, const char * format, ...); - +void linphone_call_cb(LinphoneCall *call,void * user_data); +void call_paused_resumed_base(bool_t multicast); +void simple_call_base(bool_t enable_multicast_recv_side); +void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t enable_relay,LinphoneFirewallPolicy policy,bool_t enable_tunnel); #endif /* LIBLINPHONE_TESTER_H_ */ diff --git a/tester/log_collection_tester.c b/tester/log_collection_tester.c index b9c1835c5..96531422a 100644 --- a/tester/log_collection_tester.c +++ b/tester/log_collection_tester.c @@ -27,11 +27,15 @@ #include "private.h" #include "liblinphone_tester.h" +#ifdef HAVE_ZLIB +#include +#endif -/*getline is not available on android...*/ -#ifdef ANDROID + +/*getline is POSIX 2008, not available on many systems.*/ +#if defined(ANDROID) || defined(WIN32) /* This code is public domain -- Will Hartung 4/9/09 */ -size_t getline(char **lineptr, size_t *n, FILE *stream) { +static size_t getline(char **lineptr, size_t *n, FILE *stream) { char *bufptr = NULL; char *p = bufptr; size_t size; @@ -62,9 +66,12 @@ size_t getline(char **lineptr, size_t *n, FILE *stream) { } p = bufptr; while(c != EOF) { - if ((p - bufptr) > (size - 1)) { + size_t curpos = p-bufptr; + + if (curpos > (size - 1)) { size = size + 128; bufptr = realloc(bufptr, size); + p = bufptr + curpos; if (bufptr == NULL) { return -1; } @@ -84,10 +91,24 @@ size_t getline(char **lineptr, size_t *n, FILE *stream) { } #endif -LinphoneCoreManager* setup(bool_t enable_logs) { +static LinphoneLogCollectionState old_collection_state; +static void collect_init() { + old_collection_state = linphone_core_log_collection_enabled(); + linphone_core_set_log_collection_path(liblinphone_tester_writable_dir_prefix); +} + +static void collect_cleanup(LinphoneCoreManager *marie) { + linphone_core_manager_destroy(marie); + + linphone_core_enable_log_collection(old_collection_state); + linphone_core_reset_log_collection(); +} + +static LinphoneCoreManager* setup(bool_t enable_logs) { LinphoneCoreManager *marie; int timeout = 300; + collect_init(); linphone_core_enable_log_collection(enable_logs); marie = linphone_core_manager_new( "marie_rc"); @@ -100,16 +121,55 @@ LinphoneCoreManager* setup(bool_t enable_logs) { return marie; } -time_t check_file(char * filepath) { - time_t time_curr = -1; +#if HAVE_ZLIB + +/*returns uncompressed log file*/ +static FILE* gzuncompress(const char* filepath) { + gzFile file = gzopen(filepath, "rb"); + FILE *output = NULL; + FILE *ret; + char *newname = ms_strdup_printf("%s.txt", filepath); + char buffer[512]={0}; + output = fopen(newname, "wb"); + while (gzread(file, buffer, 511) > 0) { + fputs(buffer, output); + memset(buffer, 0, strlen(buffer)); + } + fclose(output); + CU_ASSERT_EQUAL(gzclose(file), Z_OK); + ret=fopen(newname, "rb"); + ms_free(newname); + return ret; +} +#endif + +static 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; + FILE *file = NULL; + + CU_ASSERT_PTR_NOT_NULL(filepath); + if (filepath != NULL) { int line_count = 0; - FILE *file = fopen(filepath, "r"); char *line = NULL; size_t line_size = 256; - struct tm tm_curr; +#ifndef WIN32 + struct tm tm_curr = {0}; time_t time_prev = -1; +#endif +#if HAVE_ZLIB + // 0) if zlib is enabled, we must decompress the file first + file = gzuncompress(filepath); +#else + file = fopen(filepath, "rb"); +#endif + CU_ASSERT_PTR_NOT_NULL(file); + if (!file) return 0; // 1) expect to find folder name in filename path CU_ASSERT_PTR_NOT_NULL(strstr(filepath, liblinphone_tester_writable_dir_prefix)); @@ -117,7 +177,7 @@ time_t check_file(char * filepath) { while (getline(&line, &line_size, file) != -1) { // a) there should be at least 25 lines ++line_count; - +#ifndef WIN32 // b) logs should be ordered by date (format: 2014-11-04 15:22:12:606) if (strlen(line) > 24) { char date[24] = {'\0'}; @@ -128,71 +188,61 @@ time_t check_file(char * filepath) { time_prev = time_curr; } } +#endif } CU_ASSERT_TRUE(line_count > 25); free(line); fclose(file); ms_free(filepath); + + + timediff = labs((long int)time_curr - (long int)last_log); + (void)timediff; +#ifndef WIN32 + CU_ASSERT_TRUE( timediff <= 1 ); + if( !(timediff <= 1) ){ + ms_error("time_curr: %ld, last_log: %ld timediff: %u", (long int)time_curr, (long int)last_log, timediff ); + } +#else + ms_warning("strptime() not available for this platform, test is incomplete."); +#endif } // return latest time in file return time_curr; } -static LinphoneLogCollectionState old_collection_state; -static int collect_init() { - old_collection_state = linphone_core_log_collection_enabled(); - linphone_core_set_log_collection_path(liblinphone_tester_writable_dir_prefix); - return 0; -} - -static int collect_cleanup() { - linphone_core_enable_log_collection(old_collection_state); - linphone_core_reset_log_collection(); - return 0; -} - static void collect_files_disabled() { LinphoneCoreManager* marie = setup(FALSE); CU_ASSERT_PTR_NULL(linphone_core_compress_log_collection(marie->lc)); - linphone_core_manager_destroy(marie); + collect_cleanup(marie); } 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(ms_time(0), check_file(filepath)); - linphone_core_manager_destroy(marie); + check_file(marie); + collect_cleanup(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(ms_time(0), check_file(filepath)); - linphone_core_manager_destroy(marie); + check_file(marie); + collect_cleanup(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(ms_time(0), check_file(filepath)); + 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(ms_time(0), check_file(filepath)); + check_file(marie); - linphone_core_manager_destroy(marie); + collect_cleanup(marie); } test_t log_collection_tests[] = { @@ -204,8 +254,8 @@ test_t log_collection_tests[] = { test_suite_t log_collection_test_suite = { "LogCollection", - collect_init, - collect_cleanup, + NULL, + NULL, sizeof(log_collection_tests) / sizeof(log_collection_tests[0]), log_collection_tests }; diff --git a/tester/message_tester.c b/tester/message_tester.c index 60834ea4c..7fb6e4fb7 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -63,25 +63,26 @@ void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMess /** * function invoked when a file transfer is received. * */ -void file_transfer_received(LinphoneCore *lc, 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); + LinphoneCore *lc = linphone_chat_room_get_core(cr); snprintf(receive_file,sizeof(receive_file), "%s/receive_file.dump", liblinphone_tester_writable_dir_prefix); if (!linphone_chat_message_get_user_data(message)) { /*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 */ + 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(buff,size,1,file)==-1){ + 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)); } } @@ -92,32 +93,39 @@ char big_file[128000]; /* a buffer to simulate a big file for the file transfer /* * function called when the file transfer is initiated. file content should be feed into object LinphoneContent * */ -void file_transfer_send(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, char* buff, size_t* size){ - int offset=-1; - - if (!linphone_chat_message_get_user_data(message)) { - /*first chunk*/ - offset=0; - } else { - /*subsequent chunk*/ - offset = (int)((long)(linphone_chat_message_get_user_data(message))&0x00000000FFFFFFFF); +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); } /** * function invoked to report file transfer progress. * */ -void file_transfer_progress_indication(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t total) { +void file_transfer_progress_indication(LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t total) { + LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(message); + LinphoneCore *lc = linphone_chat_room_get_core(cr); const LinphoneAddress* from_address = linphone_chat_message_get_from(message); const LinphoneAddress* to_address = linphone_chat_message_get_to(message); char *address = linphone_chat_message_is_outgoing(message)?linphone_address_as_string(to_address):linphone_address_as_string(from_address); @@ -125,8 +133,8 @@ void file_transfer_progress_indication(LinphoneCore *lc, LinphoneChatMessage *me int progress = (int)((offset * 100)/total); ms_message(" File transfer [%d%%] %s of type [%s/%s] %s [%s] \n", progress ,(linphone_chat_message_is_outgoing(message)?"sent":"received") - , content->type - , content->subtype + , linphone_content_get_type(content) + , linphone_content_get_subtype(content) ,(linphone_chat_message_is_outgoing(message)?"to":"from") , address); counters->progress_of_LinphoneFileTransfer = progress; @@ -143,9 +151,14 @@ void is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room) { } void liblinphone_tester_chat_message_state_change(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud) { - LinphoneCore* lc=(LinphoneCore*)ud; + liblinphone_tester_chat_message_msg_state_changed(msg, state); +} + +void liblinphone_tester_chat_message_msg_state_changed(LinphoneChatMessage *msg, LinphoneChatMessageState state) { + LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(msg); + LinphoneCore *lc = linphone_chat_room_get_core(cr); stats* counters = get_stats(lc); - ms_message("Message [%s] [%s]",linphone_chat_message_get_text(msg),linphone_chat_message_state_to_string(state)); + ms_message("Message [%s] [%s]",linphone_chat_message_get_text(msg), linphone_chat_message_state_to_string(state)); switch (state) { case LinphoneChatMessageStateDelivered: counters->number_of_LinphoneMessageDelivered++; @@ -160,9 +173,8 @@ void liblinphone_tester_chat_message_state_change(LinphoneChatMessage* msg,Linph counters->number_of_LinphoneMessageNotDelivered++; break; default: - ms_error("Unexpected state [%s] for message [%p]",linphone_chat_message_state_to_string(state),msg); + ms_error("Unexpected state [%s] for message [%p]",linphone_chat_message_state_to_string(state), msg); } - } static void text_message(void) { @@ -171,10 +183,6 @@ static void text_message(void) { char* to; LinphoneChatRoom* chat_room; - /* make sure lime is not enabled */ - linphone_core_set_lime(marie->lc, 0); - linphone_core_set_lime(pauline->lc, 0); - to = linphone_address_as_string(marie->identity); chat_room = linphone_core_create_chat_room(pauline->lc,to); ms_free(to); @@ -200,10 +208,6 @@ static void text_message_within_dialog(void) { LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - /* make sure lime is not enabled */ - linphone_core_set_lime(marie->lc, 0); - linphone_core_set_lime(pauline->lc, 0); - lp_config_set_int(pauline->lc->config,"sip","chat_use_call_dialogs",1); to = linphone_address_as_string(marie->identity); @@ -243,10 +247,6 @@ static void text_message_with_credential_from_auth_cb(void) { LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); text_message_with_credential_from_auth_cb_auth_info=linphone_auth_info_clone((LinphoneAuthInfo*)(linphone_core_get_auth_info_list(marie->lc)->data)); - /* make sure lime is not enabled */ - linphone_core_set_lime(marie->lc, 0); - linphone_core_set_lime(pauline->lc, 0); - /*to force cb to be called*/ linphone_core_clear_all_auth_info(marie->lc); vtable->auth_info_requested=text_message_with_credential_from_auth_cb_auth_info_requested; @@ -279,10 +279,6 @@ static void text_message_with_privacy(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - /* make sure lime is not enabled */ - linphone_core_set_lime(marie->lc, 0); - linphone_core_set_lime(pauline->lc, 0); - to = linphone_address_as_string(marie->identity); chat_room = linphone_core_create_chat_room(pauline->lc,to); ms_free(to); @@ -317,10 +313,6 @@ static void text_message_compatibility_mode(void) { char* to = linphone_address_as_string(pauline->identity); LinphoneChatRoom* chat_room; - /* make sure lime is not enabled */ - linphone_core_set_lime(marie->lc, 0); - linphone_core_set_lime(pauline->lc, 0); - linphone_core_get_default_proxy(marie->lc,&proxy); CU_ASSERT_PTR_NOT_NULL (proxy); proxy_address=linphone_address_new(linphone_proxy_config_get_addr(proxy)); @@ -367,23 +359,21 @@ static void text_message_with_ack(void) { marie = linphone_core_manager_new( "marie_rc"); pauline = linphone_core_manager_new( "pauline_rc"); - /* make sure lime is not enabled */ - linphone_core_set_lime(marie->lc, 0); - linphone_core_set_lime(pauline->lc, 0); { char* to = linphone_address_as_string(marie->identity); LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); - { - int dummy=0; - wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/ - reset_counters(&marie->stat); - reset_counters(&pauline->stat); - } - linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,pauline->lc); + LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(message); + int dummy=0; + wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/ + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed); + linphone_chat_room_send_chat_message(chat_room,message); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageDelivered,1)); CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1); + linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } @@ -395,28 +385,23 @@ static void text_message_with_ack(void) { } static void text_message_with_external_body(void) { - char* to; - LinphoneChatRoom* chat_room; - LinphoneChatMessage* message; - LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - /* make sure lime is not enabled */ - linphone_core_set_lime(marie->lc, 0); - linphone_core_set_lime(pauline->lc, 0); - - to = linphone_address_as_string(marie->identity); - chat_room = linphone_core_create_chat_room(pauline->lc,to); - message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); + char *to = linphone_address_as_string(marie->identity); + LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); + LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); + LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(message); linphone_chat_message_set_external_body_url(message,message_external_body_url="http://www.linphone.org"); + { int dummy=0; wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/ reset_counters(&marie->stat); reset_counters(&pauline->stat); } - linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,pauline->lc); + linphone_chat_message_cbs_set_msg_state_changed(cbs,liblinphone_tester_chat_message_msg_state_changed); + linphone_chat_room_send_chat_message(chat_room,message); /* check transient message list: the message should be in it, and should be the only one */ CU_ASSERT_EQUAL(ms_list_size(chat_room->transient_messages), 1); @@ -434,28 +419,61 @@ 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; - LinphoneContent content; - const char* big_file_content="big file"; /* setting dummy file content to something */ + LinphoneChatMessageCbs *cbs; + LinphoneContent* content; + 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"); - /* make sure lime is not enabled */ - linphone_core_set_lime(marie->lc, 0); - linphone_core_set_lime(pauline->lc, 0); - reset_counters(&marie->stat); reset_counters(&pauline->stat); - for (i=0;ilc,"https://www.linphone.org:444/lft.php"); @@ -465,22 +483,96 @@ static void file_transfer_message(void) { chat_room = linphone_core_create_chat_room(pauline->lc,to); ms_free(to); /* create a file transfer message */ - memset(&content,0,sizeof(content)); - content.type="text"; - content.subtype="plain"; - content.size=sizeof(big_file); /*total size to be transfered*/ - content.name = "bigfile.txt"; - message = linphone_chat_room_create_file_transfer_message(chat_room, &content); + content = linphone_core_create_content(pauline->lc); + 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; wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/ reset_counters(&marie->stat); reset_counters(&pauline->stat); } - linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,pauline->lc); + 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); + linphone_chat_message_cbs_set_file_transfer_recv(cbs, file_transfer_received); + linphone_chat_message_download_file(marie->stat.last_received_chat_message); + } + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageExtBodyReceived,1)); + + 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 */ +#define SMALL_FILE_SIZE 160 +static void small_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 */ + 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;ilc,"https://www.linphone.org:444/lft.php"); + + /* create a chatroom on pauline's side */ + to = linphone_address_as_string(marie->identity); + chat_room = linphone_core_create_chat_room(pauline->lc,to); + 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,SMALL_FILE_SIZE); /*total size to be transfered*/ + linphone_content_set_name(content,"bigfile.txt"); + message = linphone_chat_room_create_file_transfer_message(chat_room, content); + { + int dummy=0; + wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/ + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + } + 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 ) { - linphone_chat_message_start_file_download(marie->stat.last_received_chat_message, liblinphone_tester_chat_message_state_change, marie->lc); + 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); + linphone_chat_message_cbs_set_file_transfer_recv(cbs, file_transfer_received); + linphone_chat_message_download_file(marie->stat.last_received_chat_message); } CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageExtBodyReceived,1)); @@ -488,6 +580,7 @@ static void file_transfer_message(void) { CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageDelivered,1); CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageExtBodyReceived,1); + linphone_content_unref(content); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } @@ -495,10 +588,12 @@ static void file_transfer_message(void) { static void lime_file_transfer_message(void) { int i; char *to; + FILE *ZIDCacheMarieFD, *ZIDCachePaulineFD; LinphoneCoreManager *marie, *pauline; LinphoneChatRoom *chat_room; - LinphoneContent content; + LinphoneContent *content; LinphoneChatMessage *message; + LinphoneChatMessageCbs *cbs; /* setting dummy file content to something */ const char* big_file_content="big file"; @@ -510,14 +605,22 @@ static void lime_file_transfer_message(void) { marie = linphone_core_manager_new( "marie_rc"); pauline = linphone_core_manager_new( "pauline_rc"); + reset_counters(&marie->stat); + reset_counters(&pauline->stat); /* make sure lime is enabled */ linphone_core_set_lime(marie->lc, 1); linphone_core_set_lime(pauline->lc, 1); - - /* set the zid caches files */ - linphone_core_set_zrtp_secrets_file(marie->lc, "ZIDCacheAlice.xml"); - linphone_core_set_zrtp_secrets_file(pauline->lc, "ZIDCacheBob.xml"); + + /* set the zid caches files : create two ZID cache from this valid one inserting the auto-generated sip URI for the peer account as keys in ZID cache are indexed by peer sip uri */ + ZIDCacheMarieFD = fopen("tmpZIDCacheMarie.xml", "w"); + ZIDCachePaulineFD = fopen("tmpZIDCachePauline.xml", "w"); + fprintf(ZIDCacheMarieFD, "\nef7692d0792a67491ae2d44e005dbe0399643d953a2202dd9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899%s08df5907d30959b8cb70f6fff2d8febd88fb41b0c8afc39e4b972f86dd5cfe2d60f020a3fe11dc2cc0e1e8ed9341b4cd14944db806ca4fc95456bbe45d95c43a5f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193bcffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b7719300000078000001cf011234567889643d953a2202ee9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899%s72d80ab1cad243cf45634980c1d02cfb2df81ce0dd5dfcf1ebeacfc5345a917625d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b7719322ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b771930000000f00000000", linphone_address_as_string_uri_only(pauline->identity), linphone_address_as_string_uri_only(pauline->identity)); + fprintf(ZIDCachePaulineFD, "\n005dbe0399643d953a2202ddef7692d0792a67491ae2d44e9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899%s08df5907d30959b8cb70f6fff2d8febd88fb41b0c8afc39e4b972f86dd5cfe2d60f020a3fe11dc2cc0e1e8ed9341b4cd14944db806ca4fc95456bbe45d95c43a5f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193bcffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b7719300000078000001cf011234567889643d953a2202ee9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899%s81e6e6362c34dc974263d1f77cbb9a8d6d6a718330994379099a8fa19fb12faa25d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b7719322ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b771930000002e0000000001", linphone_address_as_string_uri_only(marie->identity), linphone_address_as_string_uri_only(marie->identity)); + fclose(ZIDCacheMarieFD); + fclose(ZIDCachePaulineFD); + linphone_core_set_zrtp_secrets_file(marie->lc, "tmpZIDCacheMarie.xml"); + linphone_core_set_zrtp_secrets_file(pauline->lc, "tmpZIDCachePauline.xml"); /* Globally configure an http file transfer server. */ linphone_core_set_file_transfer_server(pauline->lc,"https://www.linphone.org:444/lft.php"); @@ -527,22 +630,30 @@ static void lime_file_transfer_message(void) { chat_room = linphone_core_create_chat_room(pauline->lc,to); ms_free(to); /* create a file transfer message */ - memset(&content,0,sizeof(content)); - content.type="text"; - content.subtype="plain"; - content.size=sizeof(big_file); /*total size to be transfered*/ - content.name = "bigfile.txt"; - message = linphone_chat_room_create_file_transfer_message(chat_room, &content); + 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,"big_file.txt"); + + message = linphone_chat_room_create_file_transfer_message(chat_room, content); { int dummy=0; wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/ reset_counters(&marie->stat); reset_counters(&pauline->stat); } - linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,pauline->lc); + + 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 ) { - linphone_chat_message_start_file_download(marie->stat.last_received_chat_message, liblinphone_tester_chat_message_state_change, marie->lc); + 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); + linphone_chat_message_cbs_set_file_transfer_recv(cbs, file_transfer_received); + linphone_chat_message_download_file(marie->stat.last_received_chat_message); } CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageExtBodyReceived,1)); @@ -550,8 +661,10 @@ static void lime_file_transfer_message(void) { CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageDelivered,1); CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageExtBodyReceived,1); + linphone_content_unref(content); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); + } static void file_transfer_message_io_error_upload(void) { @@ -559,13 +672,11 @@ static void file_transfer_message_io_error_upload(void) { char* to; LinphoneChatRoom* chat_room; LinphoneChatMessage* message; - LinphoneContent content; + LinphoneChatMessageCbs *cbs; + LinphoneContent* content; const char* big_file_content="big file"; /* setting dummy file content to something */ LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - /* make sure lime is not enabled */ - linphone_core_set_lime(marie->lc, 0); - linphone_core_set_lime(pauline->lc, 0); reset_counters(&marie->stat); reset_counters(&pauline->stat); @@ -585,19 +696,23 @@ static void file_transfer_message_io_error_upload(void) { chat_room = linphone_core_create_chat_room(pauline->lc,to); /* create a file transfer message */ - memset(&content,0,sizeof(content)); - content.type="text"; - content.subtype="plain"; - content.size=sizeof(big_file); /*total size to be transfered*/ - content.name = "bigfile.txt"; - message = linphone_chat_room_create_file_transfer_message(chat_room, &content); + 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"); + message = linphone_chat_room_create_file_transfer_message(chat_room, content); { int dummy=0; wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/ reset_counters(&marie->stat); reset_counters(&pauline->stat); } - linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,pauline->lc); + 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); /*wait for file to be 25% uploaded and simultate a network error*/ CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.progress_of_LinphoneFileTransfer,25)); @@ -613,6 +728,7 @@ static void file_transfer_message_io_error_upload(void) { linphone_core_refresh_registers(pauline->lc); /*to make sure registration is back in registered and so it can be later unregistered*/ CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneRegistrationOk,pauline->stat.number_of_LinphoneRegistrationOk+1)); + linphone_content_unref(content); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } @@ -628,9 +744,6 @@ static void file_transfer_message_io_error_download(void) { const char* big_file_content="big file"; /* setting dummy file content to something */ LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - /* make sure lime is not enabled */ - linphone_core_set_lime(marie->lc, 0); - linphone_core_set_lime(pauline->lc, 0); reset_counters(&marie->stat); reset_counters(&pauline->stat); @@ -692,13 +805,11 @@ static void file_transfer_message_upload_cancelled(void) { char* to; LinphoneChatRoom* chat_room; LinphoneChatMessage* message; - LinphoneContent content; + LinphoneChatMessageCbs *cbs; + LinphoneContent* content; const char* big_file_content="big file"; /* setting dummy file content to something */ LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - /* make sure lime is not enabled */ - linphone_core_set_lime(marie->lc, 0); - linphone_core_set_lime(pauline->lc, 0); reset_counters(&marie->stat); reset_counters(&pauline->stat); @@ -718,19 +829,23 @@ static void file_transfer_message_upload_cancelled(void) { chat_room = linphone_core_create_chat_room(pauline->lc,to); /* create a file transfer message */ - memset(&content,0,sizeof(content)); - content.type="text"; - content.subtype="plain"; - content.size=sizeof(big_file); /*total size to be transfered*/ - content.name = "bigfile.txt"; - message = linphone_chat_room_create_file_transfer_message(chat_room, &content); + 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"); + message = linphone_chat_room_create_file_transfer_message(chat_room, content); { int dummy=0; wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/ reset_counters(&marie->stat); reset_counters(&pauline->stat); } - linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,pauline->lc); + 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); /*wait for file to be 50% uploaded and cancel the transfer */ CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.progress_of_LinphoneFileTransfer, 50)); @@ -741,6 +856,7 @@ static void file_transfer_message_upload_cancelled(void) { CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageNotDelivered,1); CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageExtBodyReceived,0); + linphone_content_unref(content); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } @@ -755,9 +871,6 @@ static void file_transfer_message_download_cancelled(void) { const char* big_file_content="big file"; /* setting dummy file content to something */ LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - /* make sure lime is not enabled */ - linphone_core_set_lime(marie->lc, 0); - linphone_core_set_lime(pauline->lc, 0); reset_counters(&marie->stat); reset_counters(&pauline->stat); @@ -814,21 +927,53 @@ static void file_transfer_message_download_cancelled(void) { ms_error("Test skipped"); } -static void text_message_with_send_error(void) { - char* to; - LinphoneChatRoom* chat_room; - LinphoneChatMessage* message; +static void file_transfer_using_external_body_url(void) { + char *to; + LinphoneChatMessageCbs *cbs; + LinphoneChatRoom *chat_room; + LinphoneChatMessage *message; + LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_rc"); + reset_counters(&marie->stat); + reset_counters(&pauline->stat); - LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - - /* make sure lime is not enabled */ + /* make sure lime is disabled */ linphone_core_set_lime(marie->lc, 0); linphone_core_set_lime(pauline->lc, 0); - to = linphone_address_as_string(pauline->identity); - chat_room = linphone_core_create_chat_room(marie->lc,to); - message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); + /* create a chatroom on pauline's side */ + to = linphone_address_as_string(marie->identity); + chat_room = linphone_core_create_chat_room(pauline->lc,to); + + message = linphone_chat_room_create_message(chat_room, NULL); + + 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_set_external_body_url(message, "https://www.linphone.org:444//tmp/54ec58280ace9_c30709218df8eaba61d1.jpg"); + linphone_chat_room_send_chat_message(chat_room, message); + + CU_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneMessageReceived, 1)); + if (marie->stat.last_received_chat_message) { + linphone_chat_message_download_file(marie->stat.last_received_chat_message); + } + CU_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneMessageExtBodyReceived, 1)); + + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress, 1); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageExtBodyReceived, 1); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void text_message_with_send_error(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + + char *to = linphone_address_as_string(pauline->identity); + LinphoneChatRoom* chat_room = linphone_core_create_chat_room(marie->lc,to); + LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); + LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(message); reset_counters(&marie->stat); reset_counters(&pauline->stat); @@ -840,7 +985,8 @@ static void text_message_with_send_error(void) { reset_counters(&marie->stat); reset_counters(&pauline->stat); } - linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,marie->lc); + linphone_chat_message_cbs_set_msg_state_changed(cbs,liblinphone_tester_chat_message_msg_state_changed); + linphone_chat_room_send_chat_message(chat_room,message); /* check transient message list: the message should be in it, and should be the only one */ CU_ASSERT_EQUAL(ms_list_size(chat_room->transient_messages), 1); @@ -860,20 +1006,13 @@ static void text_message_with_send_error(void) { } static void text_message_denied(void) { - char* to; - LinphoneChatRoom* chat_room; - LinphoneChatMessage* message; - LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - /* make sure lime is not enabled */ - linphone_core_set_lime(marie->lc, 0); - linphone_core_set_lime(pauline->lc, 0); - - to = linphone_address_as_string(pauline->identity); - chat_room = linphone_core_create_chat_room(marie->lc,to); - message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); + char *to = linphone_address_as_string(pauline->identity); + LinphoneChatRoom* chat_room = linphone_core_create_chat_room(marie->lc,to); + LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); + LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(message); /*pauline doesn't want to be disturbed*/ linphone_core_disable_chat(pauline->lc,LinphoneReasonDoNotDisturb); @@ -883,7 +1022,8 @@ static void text_message_denied(void) { reset_counters(&marie->stat); reset_counters(&pauline->stat); } - linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,marie->lc); + linphone_chat_message_cbs_set_msg_state_changed(cbs,liblinphone_tester_chat_message_msg_state_changed); + linphone_chat_room_send_chat_message(chat_room,message); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageNotDelivered,1)); CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageReceived,0); @@ -914,21 +1054,17 @@ static void info_message_with_args(bool_t with_content) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - /* make sure lime is not enabled */ - linphone_core_set_lime(marie->lc, 0); - linphone_core_set_lime(pauline->lc, 0); - CU_ASSERT_TRUE(call(pauline,marie)); info=linphone_core_create_info_message(marie->lc); linphone_info_message_add_header(info,"Weather","still bad"); if (with_content) { - LinphoneContent ct={0}; - ct.type="application"; - ct.subtype="somexml"; - ct.data=(void*)info_content; - ct.size=strlen(info_content); - linphone_info_message_set_content(info,&ct); + LinphoneContent* ct=linphone_core_create_content(marie->lc); + linphone_content_set_type(ct,"application"); + linphone_content_set_subtype(ct,"somexml"); + linphone_content_set_buffer(ct,info_content,strlen(info_content)); + linphone_info_message_set_content(info,ct); + linphone_content_unref(ct); } { int dummy=0; @@ -952,13 +1088,13 @@ static void info_message_with_args(bool_t with_content) { if (with_content){ CU_ASSERT_PTR_NOT_NULL(content); if (content) { - CU_ASSERT_PTR_NOT_NULL(content->data); - CU_ASSERT_PTR_NOT_NULL(content->type); - CU_ASSERT_PTR_NOT_NULL(content->subtype); - if (content->type) CU_ASSERT_TRUE(strcmp(content->type,"application")==0); - if (content->subtype) CU_ASSERT_TRUE(strcmp(content->subtype,"somexml")==0); - if (content->data)CU_ASSERT_TRUE(strcmp((const char*)content->data,info_content)==0); - CU_ASSERT_EQUAL(content->size,strlen(info_content)); + CU_ASSERT_PTR_NOT_NULL(linphone_content_get_buffer(content)); + CU_ASSERT_PTR_NOT_NULL(linphone_content_get_type(content)); + CU_ASSERT_PTR_NOT_NULL(linphone_content_get_subtype(content)); + if (linphone_content_get_type(content)) CU_ASSERT_TRUE(strcmp(linphone_content_get_type(content),"application")==0); + if (linphone_content_get_subtype(content)) CU_ASSERT_TRUE(strcmp(linphone_content_get_subtype(content),"somexml")==0); + if (linphone_content_get_buffer(content))CU_ASSERT_TRUE(strcmp((const char*)linphone_content_get_buffer(content),info_content)==0); + CU_ASSERT_EQUAL(linphone_content_get_size(content),strlen(info_content)); } } linphone_core_manager_destroy(marie); @@ -981,10 +1117,6 @@ static void is_composing_notification(void) { LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - /* make sure lime is not enabled */ - linphone_core_set_lime(marie->lc, 0); - linphone_core_set_lime(pauline->lc, 0); - to = linphone_address_as_string(marie->identity); chat_room = linphone_core_create_chat_room(pauline->lc, to); @@ -1175,6 +1307,7 @@ static void lime_unit(void) { static void lime_text_message(void) { char* to; + FILE *ZIDCacheMarieFD, *ZIDCachePaulineFD; LinphoneChatRoom* chat_room; LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -1183,9 +1316,15 @@ static void lime_text_message(void) { linphone_core_set_lime(marie->lc, 1); linphone_core_set_lime(pauline->lc, 1); - /* set the zid caches files */ - linphone_core_set_zrtp_secrets_file(marie->lc, "ZIDCacheAlice.xml"); - linphone_core_set_zrtp_secrets_file(pauline->lc, "ZIDCacheBob.xml"); + /* set the zid caches files : create two ZID cache from this valid one inserting the auto-generated sip URI for the peer account as keys in ZID cache are indexed by peer sip uri */ + ZIDCacheMarieFD = fopen("tmpZIDCacheMarie.xml", "w"); + ZIDCachePaulineFD = fopen("tmpZIDCachePauline.xml", "w"); + fprintf(ZIDCacheMarieFD, "\nef7692d0792a67491ae2d44e005dbe0399643d953a2202dd9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899%s08df5907d30959b8cb70f6fff2d8febd88fb41b0c8afc39e4b972f86dd5cfe2d60f020a3fe11dc2cc0e1e8ed9341b4cd14944db806ca4fc95456bbe45d95c43a5f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193bcffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b7719300000078000001cf011234567889643d953a2202ee9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899%s72d80ab1cad243cf45634980c1d02cfb2df81ce0dd5dfcf1ebeacfc5345a917625d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b7719322ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b771930000000f00000000", linphone_address_as_string_uri_only(pauline->identity), linphone_address_as_string_uri_only(pauline->identity)); + fprintf(ZIDCachePaulineFD, "\n005dbe0399643d953a2202ddef7692d0792a67491ae2d44e9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899%s08df5907d30959b8cb70f6fff2d8febd88fb41b0c8afc39e4b972f86dd5cfe2d60f020a3fe11dc2cc0e1e8ed9341b4cd14944db806ca4fc95456bbe45d95c43a5f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193bcffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b7719300000078000001cf011234567889643d953a2202ee9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899%s81e6e6362c34dc974263d1f77cbb9a8d6d6a718330994379099a8fa19fb12faa25d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b7719322ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b771930000002e0000000001", linphone_address_as_string_uri_only(marie->identity), linphone_address_as_string_uri_only(marie->identity)); + fclose(ZIDCacheMarieFD); + fclose(ZIDCachePaulineFD); + linphone_core_set_zrtp_secrets_file(marie->lc, "tmpZIDCacheMarie.xml"); + linphone_core_set_zrtp_secrets_file(pauline->lc, "tmpZIDCachePauline.xml"); to = linphone_address_as_string(marie->identity); chat_room = linphone_core_create_chat_room(pauline->lc,to); @@ -1218,7 +1357,7 @@ message_tester_copy_file(const char *from, const char *to) size_t n; /* Open "from" file for reading */ - in=fopen(from, "r"); + in=fopen(from, "rb"); if ( in == NULL ) { ms_error("Can't open %s for reading: %s\n",from,strerror(errno)); @@ -1226,7 +1365,7 @@ message_tester_copy_file(const char *from, const char *to) } /* Open "to" file for writing (will truncate existing files) */ - out=fopen(to, "w"); + out=fopen(to, "wb"); if ( out == NULL ) { ms_error("Can't open %s for writing: %s\n",to,strerror(errno)); @@ -1286,6 +1425,59 @@ static void message_storage_migration() { remove(tmp_db); } +static void history_message_count_helper(LinphoneChatRoom* chatroom, int x, int y, int expected ){ + MSList* messages = linphone_chat_room_get_history_range(chatroom, x, y); + int size = ms_list_size(messages); + if( expected != size ){ + ms_warning("History retrieved from %d to %d returned %d records, but expected %d", x, y, size, expected); + } + CU_ASSERT_EQUAL(size, expected); + + ms_list_free_with_data(messages, (void (*)(void *))linphone_chat_message_unref); + +} + +static void history_range_full_test(){ + LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); + LinphoneAddress *jehan_addr = linphone_address_new(""); + LinphoneChatRoom *chatroom; + char src_db[256]; + char tmp_db[256]; + snprintf(src_db,sizeof(src_db), "%s/messages.db", liblinphone_tester_file_prefix); + snprintf(tmp_db,sizeof(tmp_db), "%s/tmp.db", liblinphone_tester_writable_dir_prefix); + + CU_ASSERT_EQUAL_FATAL(message_tester_copy_file(src_db, tmp_db), 0); + + linphone_core_set_chat_database_path(marie->lc, tmp_db); + + chatroom = linphone_core_get_chat_room(marie->lc, jehan_addr); + CU_ASSERT_PTR_NOT_NULL(chatroom); + if (chatroom){ + // We have 20 tests to perform to fully qualify the function, here they are: + history_message_count_helper(chatroom, 0, 0, 1); + history_message_count_helper(chatroom, -1, 0, 1); + history_message_count_helper(chatroom, 0, -1, 1270); + history_message_count_helper(chatroom, 1, 3, 3); + history_message_count_helper(chatroom, 3, 1, 1270-3); + history_message_count_helper(chatroom, 10, 10, 1); + history_message_count_helper(chatroom, -1, -1, 1270); + history_message_count_helper(chatroom, -1, -2, 1270); + history_message_count_helper(chatroom, -2, -1, 1270); + history_message_count_helper(chatroom, 3, -1, 1270-3); + history_message_count_helper(chatroom, 1, -3, 1270-1); + history_message_count_helper(chatroom, 2, -2, 1270-2); + history_message_count_helper(chatroom, 2, 0, 1270-2); + history_message_count_helper(chatroom, 0, 2, 3); + history_message_count_helper(chatroom, -1, 3, 4); + history_message_count_helper(chatroom, -2, 2, 3); + history_message_count_helper(chatroom, -3, 1, 2); + } + linphone_core_manager_destroy(marie); + linphone_address_destroy(jehan_addr); + remove(tmp_db); +} + + static void history_messages_count() { LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); LinphoneAddress *jehan_addr = linphone_address_new(""); @@ -1307,6 +1499,10 @@ static void history_messages_count() { CU_ASSERT_EQUAL(ms_list_size(messages), 10); ms_list_free_with_data(messages, (void (*)(void*))linphone_chat_message_unref); + messages=linphone_chat_room_get_history(chatroom,1); + CU_ASSERT_EQUAL(ms_list_size(messages), 1); + ms_list_free_with_data(messages, (void (*)(void*))linphone_chat_message_unref); + messages=linphone_chat_room_get_history(chatroom,0); CU_ASSERT_EQUAL(linphone_chat_room_get_history_size(chatroom), 1270); CU_ASSERT_EQUAL(ms_list_size(messages), 1270); @@ -1354,11 +1550,13 @@ test_t message_tests[] = { { "Text message with send error", text_message_with_send_error }, { "Text message with external body", text_message_with_external_body }, { "File transfer message", file_transfer_message }, + { "Small File transfer message", small_file_transfer_message}, { "File transfer message with io error at upload", file_transfer_message_io_error_upload }, /* { "File transfer message with io error at download", file_transfer_message_io_error_download },*/ { "File transfer message upload cancelled", file_transfer_message_upload_cancelled }, { "File transfer message download cancelled", file_transfer_message_download_cancelled }, { "Lime File transfer message", lime_file_transfer_message }, + { "File transfer message using external body url", file_transfer_using_external_body_url }, { "Text message denied", text_message_denied }, { "Info message", info_message }, { "Info message with body", info_message_with_body }, @@ -1367,6 +1565,7 @@ test_t message_tests[] = { #ifdef MSG_STORAGE_ENABLED ,{ "Database migration", message_storage_migration } ,{ "History count", history_messages_count } + ,{ "History range", history_range_full_test } #endif }; diff --git a/tester/multicast_call_tester.c b/tester/multicast_call_tester.c new file mode 100644 index 000000000..e5a05c11e --- /dev/null +++ b/tester/multicast_call_tester.c @@ -0,0 +1,230 @@ +/* + liblinphone_tester - liblinphone test suite + Copyright (C) 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, see . +*/ + + +#include "liblinphone_tester.h" +#include "linphonecore.h" +#include "belle-sip/belle-sip.h" + + +static void call_multicast_base(bool_t video) { + LinphoneCoreManager *marie, *pauline; + int begin; + int leaked_objects; + LinphoneVideoPolicy marie_policy, pauline_policy; + + 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"); + + if (video) { + 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); + + marie_policy.automatically_initiate=TRUE; + marie_policy.automatically_accept=TRUE; + pauline_policy.automatically_initiate=TRUE; + pauline_policy.automatically_accept=TRUE; + + linphone_core_set_video_policy(marie->lc,&marie_policy); + linphone_core_set_video_policy(pauline->lc,&pauline_policy); + linphone_core_set_video_multicast_addr(pauline->lc,"224.1.2.3"); + linphone_core_enable_video_multicast(pauline->lc,TRUE); + } + linphone_core_set_audio_multicast_addr(pauline->lc,"224.1.2.3"); + linphone_core_enable_audio_multicast(pauline->lc,TRUE); + + CU_ASSERT_TRUE(call(pauline,marie)); + wait_for_until(marie->lc, pauline->lc, NULL, 1, 3000); + if (linphone_core_get_current_call(marie->lc)) { + CU_ASSERT_TRUE(linphone_call_get_audio_stats(linphone_core_get_current_call(marie->lc))->download_bandwidth>70); + if (video) { + /*check video path*/ + linphone_call_set_next_video_frame_decoded_callback(linphone_core_get_current_call(marie->lc),linphone_call_cb,marie->lc); + linphone_call_send_vfu_request(linphone_core_get_current_call(marie->lc)); + CU_ASSERT_TRUE( wait_for(marie->lc,pauline->lc,&marie->stat.number_of_IframeDecoded,1)); + } + + end_call(marie,pauline); + } + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + + leaked_objects=belle_sip_object_get_object_count()-begin; + CU_ASSERT_TRUE(leaked_objects==0); + if (leaked_objects>0){ + belle_sip_object_dump_active_objects(); + } + belle_sip_object_enable_leak_detector(FALSE); + +} + +static void call_multicast(void) { + call_multicast_base(FALSE); +} +static void multicast_audio_with_pause_resume() { + call_paused_resumed_base(TRUE); +} +#ifdef VIDEO_ENABLED +static void call_multicast_video(void) { + call_multicast_base(TRUE); +} +#endif +static void early_media_with_multicast_base(bool_t video) { + LinphoneCoreManager *marie, *pauline, *pauline2; + MSList* lcs = NULL; + int dummy=0; + int leaked_objects; + int begin; + LinphoneVideoPolicy marie_policy, pauline_policy; + LpConfig *marie_lp; + + 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"); + pauline2 = linphone_core_manager_new("pauline_rc"); + + marie_lp=linphone_core_get_config(marie->lc); + lp_config_set_int(marie_lp,"misc","real_early_media",1); + + if (video) { + linphone_core_enable_video_capture(pauline->lc, FALSE); + linphone_core_enable_video_display(pauline->lc, TRUE); + linphone_core_enable_video_capture(pauline2->lc, FALSE); + linphone_core_enable_video_display(pauline2->lc, TRUE); + linphone_core_enable_video_capture(marie->lc, TRUE); + linphone_core_enable_video_display(marie->lc, FALSE); + + marie_policy.automatically_initiate=TRUE; + marie_policy.automatically_accept=TRUE; + pauline_policy.automatically_initiate=TRUE; + pauline_policy.automatically_accept=TRUE; + + linphone_core_set_video_policy(marie->lc,&marie_policy); + linphone_core_set_video_policy(pauline->lc,&pauline_policy); + linphone_core_set_video_policy(pauline2->lc,&pauline_policy); + linphone_core_set_video_multicast_addr(marie->lc,"224.1.2.3"); + linphone_core_enable_video_multicast(marie->lc,TRUE); + } + linphone_core_set_audio_multicast_addr(marie->lc,"224.1.2.3"); + linphone_core_enable_audio_multicast(marie->lc,TRUE); + + + lcs = ms_list_append(lcs,marie->lc); + lcs = ms_list_append(lcs,pauline->lc); + lcs = ms_list_append(lcs,pauline2->lc); + /* + Marie calls Pauline, and after the call has rung, transitions to an early_media session + */ + + linphone_core_invite_address(marie->lc, pauline->identity); + + CU_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingReceived,1,3000)); + CU_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingRinging,1,1000)); + + + if (linphone_core_inc_invite_pending(pauline->lc)) { + /* send a 183 to initiate the early media */ + if (video) { + /*check video path*/ + linphone_call_set_next_video_frame_decoded_callback(linphone_core_get_current_call(pauline->lc),linphone_call_cb,pauline->lc); + } + linphone_core_accept_early_media(pauline->lc, linphone_core_get_current_call(pauline->lc)); + + CU_ASSERT_TRUE( wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingEarlyMedia,1,2000) ); + CU_ASSERT_TRUE( wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingEarlyMedia,1,2000) ); + + if (linphone_core_inc_invite_pending(pauline2->lc)) { + /* send a 183 to initiate the early media */ + if (video) { + /*check video path*/ + linphone_call_set_next_video_frame_decoded_callback(linphone_core_get_current_call(pauline2->lc),linphone_call_cb,pauline2->lc); + } + linphone_core_accept_early_media(pauline2->lc, linphone_core_get_current_call(pauline2->lc)); + + CU_ASSERT_TRUE( wait_for_list(lcs, &pauline2->stat.number_of_LinphoneCallIncomingEarlyMedia,1,2000) ); + } + + wait_for_list(lcs, &dummy, 1, 3000); + + CU_ASSERT_TRUE(linphone_call_get_audio_stats(linphone_core_get_current_call(pauline->lc))->download_bandwidth>70); + CU_ASSERT_TRUE(linphone_call_get_audio_stats(linphone_core_get_current_call(pauline->lc))->download_bandwidth<90); + + CU_ASSERT_TRUE(linphone_call_get_audio_stats(linphone_core_get_current_call(pauline2->lc))->download_bandwidth>70); + CU_ASSERT_TRUE(linphone_call_get_audio_stats(linphone_core_get_current_call(pauline2->lc))->download_bandwidth<90); + + + if (video) { + CU_ASSERT_TRUE( wait_for_list(lcs,&pauline->stat.number_of_IframeDecoded,1,2000)); + CU_ASSERT_TRUE( wait_for_list(lcs,&pauline2->stat.number_of_IframeDecoded,1,2000)); + } + + 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)); + CU_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 1,1000)); + + end_call(marie,pauline); + } + ms_free(lcs); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(pauline2); + + leaked_objects=belle_sip_object_get_object_count()-begin; + CU_ASSERT_EQUAL(leaked_objects,0); + if (leaked_objects>0){ + belle_sip_object_dump_active_objects(); + } + belle_sip_object_enable_leak_detector(FALSE); +} + +static void early_media_with_multicast_audio() { + early_media_with_multicast_base(FALSE); +} +static void unicast_incoming_with_multicast_audio_on() { + simple_call_base(TRUE); +} +#ifdef VIDEO_ENABLED +static void early_media_with_multicast_video() { + early_media_with_multicast_base(TRUE); +} +#endif + +test_t multicast_call_tests[] = { + { "Multicast audio call",call_multicast}, + { "Multicast call with pause/resume",multicast_audio_with_pause_resume}, + { "Early media multicast audio call",early_media_with_multicast_audio}, + { "Unicast incoming call with multicast activated",unicast_incoming_with_multicast_audio_on}, +#ifdef VIDEO_ENABLED + { "Multicast video call",call_multicast_video}, + { "Early media multicast video call",early_media_with_multicast_video}, +#endif +}; + +test_suite_t multicast_call_test_suite = { + "Multicast Call", + NULL, + NULL, + sizeof(multicast_call_tests) / sizeof(multicast_call_tests[0]), + multicast_call_tests +}; diff --git a/tester/offeranswer_tester.c b/tester/offeranswer_tester.c new file mode 100644 index 000000000..b9de6a879 --- /dev/null +++ b/tester/offeranswer_tester.c @@ -0,0 +1,297 @@ +/* + liblinphone_tester - liblinphone test suite + Copyright (C) 2013 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, see . +*/ + + +#include +#include +#include +#include "CUnit/Basic.h" +#include "linphonecore.h" +#include "lpconfig.h" +#include "private.h" +#include "liblinphone_tester.h" + +static int get_codec_position(const MSList *l, const char *mime_type, int rate){ + const MSList *elem; + int i; + for (elem=l, i=0; elem!=NULL; elem=elem->next,i++){ + PayloadType *pt=(PayloadType*)elem->data; + if (strcasecmp(pt->mime_type, mime_type)==0 && pt->clock_rate==rate) return i; + } + return -1; +} + +/*check basic things about codecs at startup: order and enablement*/ +static void start_with_no_config(void){ + LinphoneCoreVTable vtable={0}; + LinphoneCore *lc=linphone_core_new(&vtable, NULL, NULL, NULL); + const MSList *codecs=linphone_core_get_audio_codecs(lc); + int opus_codec_pos; + int speex_codec_pos=get_codec_position(codecs, "speex", 8000); + int speex16_codec_pos=get_codec_position(codecs, "speex", 16000); + PayloadType *pt; + opus_codec_pos=get_codec_position(codecs, "opus", 48000); + if (opus_codec_pos!=-1) CU_ASSERT_TRUE(opus_codec_pos==0); + CU_ASSERT_TRUE(speex16_codec_poslc,"pcmu",-1); + disable_all_audio_codecs_except_one(pauline->lc,"pcmu",-1); + + /*marie set a fantasy number to PCMU*/ + linphone_core_set_payload_type_number(marie->lc, + linphone_core_find_payload_type(marie->lc, "PCMU", 8000, -1), + 104); + + CU_ASSERT_TRUE(call(marie,pauline)); + pauline_call=linphone_core_get_current_call(pauline->lc); + CU_ASSERT_PTR_NOT_NULL(pauline_call); + if (pauline_call){ + LinphoneCallParams *params; + check_payload_type_numbers(linphone_core_get_current_call(marie->lc), pauline_call, 104); + /*make a reinvite in the other direction*/ + linphone_core_update_call(pauline->lc, pauline_call, + params=linphone_core_create_call_params(pauline->lc, pauline_call)); + linphone_call_params_unref(params); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallUpdating,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallUpdatedByRemote,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + /*payload type numbers shall remain the same*/ + check_payload_type_numbers(linphone_core_get_current_call(marie->lc), pauline_call, 104); + } + + end_call(marie,pauline); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + + leaked_objects=belle_sip_object_get_object_count()-begin; + CU_ASSERT_TRUE(leaked_objects==0); + if (leaked_objects>0){ + belle_sip_object_dump_active_objects(); + } +} + +static void call_failed_because_of_codecs(void) { + int begin,leaked_objects; + + belle_sip_object_enable_leak_detector(TRUE); + begin=belle_sip_object_get_object_count(); + + { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCall* out_call; + + disable_all_audio_codecs_except_one(marie->lc,"pcmu",-1); + disable_all_audio_codecs_except_one(pauline->lc,"pcma",-1); + out_call = linphone_core_invite_address(pauline->lc,marie->identity); + linphone_call_ref(out_call); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallOutgoingInit,1)); + + /*flexisip will retain the 488 until the "urgent reply" timeout (I.E 5s) arrives.*/ + CU_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallError,1,7000)); + CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonNotAcceptable); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingReceived,0); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallReleased,0); + + linphone_call_unref(out_call); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + } + leaked_objects=belle_sip_object_get_object_count()-begin; + CU_ASSERT_TRUE(leaked_objects==0); + if (leaked_objects>0){ + belle_sip_object_dump_active_objects(); + } +} + + +static void profile_call(bool_t avpf1, bool_t srtp1, bool_t avpf2, bool_t srtp2, const char *expected_profile) { + LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_rc"); + LinphoneProxyConfig *lpc; + const LinphoneCallParams *params; + + if (avpf1) { + linphone_core_get_default_proxy(marie->lc, &lpc); + linphone_proxy_config_enable_avpf(lpc, TRUE); + linphone_proxy_config_set_avpf_rr_interval(lpc, 3); + } + if (avpf2) { + linphone_core_get_default_proxy(pauline->lc, &lpc); + linphone_proxy_config_enable_avpf(lpc, TRUE); + linphone_proxy_config_set_avpf_rr_interval(lpc, 3); + } + if (srtp1) { + if (linphone_core_media_encryption_supported(marie->lc, LinphoneMediaEncryptionSRTP)) { + linphone_core_set_media_encryption(marie->lc, LinphoneMediaEncryptionSRTP); + } + } + if (srtp2) { + if (linphone_core_media_encryption_supported(pauline->lc, LinphoneMediaEncryptionSRTP)) { + linphone_core_set_media_encryption(pauline->lc, LinphoneMediaEncryptionSRTP); + } + } + + CU_ASSERT_TRUE(call(marie, pauline)); + CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 1)); + CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1)); + params = linphone_call_get_current_params(linphone_core_get_current_call(marie->lc)); + CU_ASSERT_STRING_EQUAL(linphone_call_params_get_rtp_profile(params), expected_profile); + params = linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc)); + CU_ASSERT_STRING_EQUAL(linphone_call_params_get_rtp_profile(params), expected_profile); + + linphone_core_terminate_all_calls(marie->lc); + CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallEnd, 1)); + CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallEnd, 1)); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallConnected, 1); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallConnected, 1); + + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie); +} + +static void avp_to_avp_call(void) { + profile_call(FALSE, FALSE, FALSE, FALSE, "RTP/AVP"); +} + +static void avp_to_avpf_call(void) { + profile_call(FALSE, FALSE, TRUE, FALSE, "RTP/AVP"); +} + +static void avp_to_savp_call(void) { + profile_call(FALSE, FALSE, FALSE, TRUE, "RTP/AVP"); +} + +static void avp_to_savpf_call(void) { + profile_call(FALSE, FALSE, TRUE, TRUE, "RTP/AVP"); +} + +static void avpf_to_avp_call(void) { + profile_call(TRUE, FALSE, FALSE, FALSE, "RTP/AVPF"); +} + +static void avpf_to_avpf_call(void) { + profile_call(TRUE, FALSE, TRUE, FALSE, "RTP/AVPF"); +} + +static void avpf_to_savp_call(void) { + profile_call(TRUE, FALSE, FALSE, TRUE, "RTP/AVPF"); +} + +static void avpf_to_savpf_call(void) { + profile_call(TRUE, FALSE, TRUE, TRUE, "RTP/AVPF"); +} + +static void savp_to_avp_call(void) { + profile_call(FALSE, TRUE, FALSE, FALSE, "RTP/SAVP"); +} + +static void savp_to_avpf_call(void) { + profile_call(FALSE, TRUE, TRUE, FALSE, "RTP/SAVP"); +} + +static void savp_to_savp_call(void) { + profile_call(FALSE, TRUE, FALSE, TRUE, "RTP/SAVP"); +} + +static void savp_to_savpf_call(void) { + profile_call(FALSE, TRUE, TRUE, TRUE, "RTP/SAVP"); +} + +static void savpf_to_avp_call(void) { + profile_call(TRUE, TRUE, FALSE, FALSE, "RTP/SAVPF"); +} + +static void savpf_to_avpf_call(void) { + profile_call(TRUE, TRUE, TRUE, FALSE, "RTP/SAVPF"); +} + +static void savpf_to_savp_call(void) { + profile_call(TRUE, TRUE, FALSE, TRUE, "RTP/SAVPF"); +} + +static void savpf_to_savpf_call(void) { + profile_call(TRUE, TRUE, TRUE, TRUE, "RTP/SAVPF"); +} + +static test_t offeranswer_tests[] = { + { "Start with no config", start_with_no_config }, + { "Call failed because of codecs", call_failed_because_of_codecs }, + { "Simple call with different codec mappings", simple_call_with_different_codec_mappings}, + { "AVP to AVP call", avp_to_avp_call }, + { "AVP to AVPF call", avp_to_avpf_call }, + { "AVP to SAVP call", avp_to_savp_call }, + { "AVP to SAVPF call", avp_to_savpf_call }, + { "AVPF to AVP call", avpf_to_avp_call }, + { "AVPF to AVPF call", avpf_to_avpf_call }, + { "AVPF to SAVP call", avpf_to_savp_call }, + { "AVPF to SAVPF call", avpf_to_savpf_call }, + { "SAVP to AVP call", savp_to_avp_call }, + { "SAVP to AVPF call", savp_to_avpf_call }, + { "SAVP to SAVP call", savp_to_savp_call }, + { "SAVP to SAVPF call", savp_to_savpf_call }, + { "SAVPF to AVP call", savpf_to_avp_call }, + { "SAVPF to AVPF call", savpf_to_avpf_call }, + { "SAVPF to SAVP call", savpf_to_savp_call }, + { "SAVPF to SAVPF call", savpf_to_savpf_call }, +}; + +test_suite_t offeranswer_test_suite = { + "Offer-answer", + NULL, + NULL, + sizeof(offeranswer_tests) / sizeof(offeranswer_tests[0]), + offeranswer_tests +}; diff --git a/tester/player_tester.c b/tester/player_tester.c index be0b47284..beb6e9d19 100644 --- a/tester/player_tester.c +++ b/tester/player_tester.c @@ -17,24 +17,7 @@ */ #include "liblinphone_tester.h" - -//static const char *_get_default_video_renderer(void){ -//#ifdef WIN32 -// return "MSDrawDibDisplay"; -//#elif defined(ANDROID) -// return "MSAndroidDisplay"; -//#elif __APPLE__ && !defined(__ios) -// return "MSOSXGLDisplay"; -//#elif defined (HAVE_XV) -// return "MSX11Video"; -//#elif defined(HAVE_GL) -// return "MSGLXVideo"; -//#elif defined(__ios) -// return "IOSDisplay"; -//#else -// return "MSVideoOut"; -//#endif -//} +#include static bool_t wait_for_eof(bool_t *eof, int *time,int time_refresh, int timeout) { while(*time < timeout && !*eof) { @@ -49,7 +32,7 @@ static void eof_callback(LinphonePlayer *player, void *user_data) { *eof = TRUE; } -static void play_file(const char *filename, bool_t unsupported_format) { +static void play_file(const char *filename, bool_t unsupported_format, const char *audio_mime, const char *video_mime) { LinphoneCoreManager *lc_manager; LinphonePlayer *player; int res, time = 0; @@ -59,19 +42,23 @@ static void play_file(const char *filename, bool_t unsupported_format) { CU_ASSERT_PTR_NOT_NULL(lc_manager); if(lc_manager == NULL) return; - player = linphone_core_create_local_player(lc_manager->lc, ms_snd_card_manager_get_default_card(ms_snd_card_manager_get()), "MSX11Video", 0); + player = linphone_core_create_local_player(lc_manager->lc, ms_snd_card_manager_get_default_card(ms_snd_card_manager_get()), video_stream_get_default_video_renderer(), 0); CU_ASSERT_PTR_NOT_NULL(player); if(player == NULL) goto fail; res = linphone_player_open(player, filename, eof_callback, &eof); - if(unsupported_format) { + if(unsupported_format + || (audio_mime == NULL && video_mime == NULL) + || (video_mime == NULL && audio_mime && !ms_filter_codec_supported(audio_mime)) + || (audio_mime == NULL && video_mime && !ms_filter_codec_supported(video_mime))) { CU_ASSERT_EQUAL(res, -1); } else { CU_ASSERT_EQUAL(res, 0); } if(res == -1) goto fail; - CU_ASSERT_EQUAL((res = linphone_player_start(player)), 0); + res = linphone_player_start(player); + CU_ASSERT_EQUAL(res, 0); if(res == -1) goto fail; CU_ASSERT_TRUE(wait_for_eof(&eof, &time, 100, 13000)); @@ -84,11 +71,15 @@ static void play_file(const char *filename, bool_t unsupported_format) { } static void playing_test(void) { - play_file("/home/francois/Téléchargements/test_linphone.mkv", !linphone_local_player_matroska_supported()); + char *filename = ms_strdup_printf("%s/sounds/hello_opus_h264.mkv", liblinphone_tester_file_prefix); + const char *audio_mime = "opus"; + const char *video_mime = "h264"; + play_file(filename, !linphone_local_player_matroska_supported(), audio_mime, video_mime); + ms_free(filename); } test_t player_tests[] = { - { "Playing" , playing_test } + { "Local MKV file" , playing_test } }; test_suite_t player_test_suite = { diff --git a/tester/presence_tester.c b/tester/presence_tester.c index ca3c8c18e..3b711e52e 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -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); @@ -382,25 +382,90 @@ static void test_subscribe_notify_publish(void) { wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_NotifyReceived,2,2000); CU_ASSERT_EQUAL(LinphoneStatusOnline,linphone_friend_get_status(lf)); - presence =linphone_presence_model_new_with_activity(LinphonePresenceActivityOffline,NULL); + presence =linphone_presence_model_new_with_activity(LinphonePresenceActivityBusy,NULL); linphone_core_set_presence_model(marie->lc,presence); /*wait for new status*/ wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_NotifyReceived,3,2000); - CU_ASSERT_EQUAL(LinphonePresenceActivityOffline,linphone_friend_get_status(lf)); + CU_ASSERT_EQUAL(LinphoneStatusBusy,linphone_friend_get_status(lf)); /*wait for refresh*/ wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_NotifyReceived,4,5000); - CU_ASSERT_EQUAL(LinphonePresenceActivityOffline,linphone_friend_get_status(lf)); + CU_ASSERT_EQUAL(LinphoneStatusBusy,linphone_friend_get_status(lf)); - //linphone_core_remove_friend(pauline->lc,lf); + /*linphone_core_remove_friend(pauline->lc,lf);*/ /*wait for final notify*/ - //wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_NotifyReceived,4,5000); - //CU_ASSERT_EQUAL(LinphonePresenceActivityOffline,linphone_friend_get_status(lf)); - + /*wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_NotifyReceived,4,5000); + CU_ASSERT_EQUAL(LinphonePresenceActivityOffline,linphone_friend_get_status(lf)); + */ linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } +static void test_forked_subscribe_notify_publish(void) { + + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneProxyConfig* proxy; + LinphonePresenceModel* presence; + LpConfig *pauline_lp; + char* lf_identity; + LinphoneFriend *lf; + MSList* lcs=ms_list_append(NULL,pauline->lc); + lcs=ms_list_append(lcs,marie->lc); + lcs=ms_list_append(lcs,marie->lc); + lcs=ms_list_append(lcs,marie2->lc); + + pauline_lp = linphone_core_get_config(pauline->lc); + lf_identity=linphone_address_as_string_uri_only(marie->identity); + lf = linphone_core_create_friend_with_address(pauline->lc,lf_identity); + + lp_config_set_int(pauline_lp,"sip","subscribe_expires",5); + + linphone_core_add_friend(pauline->lc,lf); + + /*wait for subscribe acknowledgment*/ + wait_for_list(lcs,&pauline->stat.number_of_NotifyReceived,1,2000); + CU_ASSERT_EQUAL(LinphoneStatusOffline,linphone_friend_get_status(lf)); + + /*enable publish*/ + + linphone_core_get_default_proxy(marie->lc,&proxy); + linphone_proxy_config_edit(proxy); + linphone_proxy_config_enable_publish(proxy,TRUE); + linphone_proxy_config_set_publish_expires(proxy,3); + linphone_proxy_config_done(proxy); + + linphone_core_get_default_proxy(marie2->lc,&proxy); + linphone_proxy_config_edit(proxy); + linphone_proxy_config_enable_publish(proxy,TRUE); + linphone_proxy_config_set_publish_expires(proxy,3); + linphone_proxy_config_done(proxy); + + + /*wait for marie status*/ + wait_for_list(lcs,&pauline->stat.number_of_NotifyReceived,3,2000); + CU_ASSERT_EQUAL(LinphoneStatusOnline,linphone_friend_get_status(lf)); + + presence =linphone_presence_model_new_with_activity(LinphonePresenceActivityBusy,NULL); + linphone_core_set_presence_model(marie->lc,presence); + + /*wait for new status*/ + wait_for_list(lcs,&pauline->stat.number_of_NotifyReceived,4,2000); + CU_ASSERT_EQUAL(LinphoneStatusBusy,linphone_friend_get_status(lf)); + + + presence =linphone_presence_model_new_with_activity( LinphonePresenceActivityMeeting,NULL); + linphone_core_set_presence_model(marie2->lc,presence); + /*wait for new status*/ + wait_for_list(lcs,&pauline->stat.number_of_NotifyReceived,5,2000); + CU_ASSERT_EQUAL(LinphoneStatusBusy,linphone_friend_get_status(lf)); /*because liblinphone compositor is very simple for now (I.E only take first occurence)*/ + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(marie2); + linphone_core_manager_destroy(pauline); +} + #endif @@ -414,6 +479,7 @@ test_t presence_tests[] = { { "App managed presence failure", subscribe_failure_handle_by_app }, #if USE_PRESENCE_SERVER { "Subscribe with late publish", test_subscribe_notify_publish }, + { "Forked subscribe with late publish", test_forked_subscribe_notify_publish }, #endif }; diff --git a/tester/quality_reporting_tester.c b/tester/quality_reporting_tester.c index 1190f188f..33df384be 100644 --- a/tester/quality_reporting_tester.c +++ b/tester/quality_reporting_tester.c @@ -25,7 +25,7 @@ #define __strstr(x, y) ((x==NULL)?NULL:strstr(x,y)) void on_report_send_mandatory(const LinphoneCall *call, int stream_type, const LinphoneContent *content){ - char * body = (char *)content->data; + char * body = (char *)linphone_content_get_buffer(content); char * remote_metrics_start = __strstr(body, "RemoteMetrics:"); reporting_session_report_t * report = call->log->reporting.reports[stream_type]; MediaStream * ms; @@ -91,7 +91,7 @@ char * on_report_send_verify_metrics(const reporting_content_metrics_t *metrics, } void on_report_send_with_rtcp_xr_local(const LinphoneCall *call, int stream_type, const LinphoneContent *content){ - char * body = (char*)content->data; + char * body = (char*)linphone_content_get_buffer(content); char * remote_metrics_start = __strstr(body, "RemoteMetrics:"); reporting_session_report_t * report = call->log->reporting.reports[stream_type]; on_report_send_mandatory(call,stream_type,content); @@ -99,7 +99,7 @@ void on_report_send_with_rtcp_xr_local(const LinphoneCall *call, int stream_type CU_ASSERT_TRUE(!remote_metrics_start || on_report_send_verify_metrics(&report->local_metrics,body) < remote_metrics_start); } void on_report_send_with_rtcp_xr_remote(const LinphoneCall *call, int stream_type, const LinphoneContent *content){ - char * body = (char*)content->data; + char * body = (char*)linphone_content_get_buffer(content); reporting_session_report_t * report = call->log->reporting.reports[stream_type]; on_report_send_mandatory(call,stream_type,content); @@ -214,7 +214,7 @@ static void quality_reporting_not_sent_if_low_bandwidth() { } void on_report_send_remove_fields(const LinphoneCall *call, int stream_type, const LinphoneContent *content){ - char *body = (char*)content->data; + char *body = (char*)linphone_content_get_buffer(content); /*corrupt start of the report*/ strncpy(body, "corrupted report is corrupted", strlen("corrupted report is corrupted")); } diff --git a/tester/rcfiles/laure_rc b/tester/rcfiles/laure_rc index 7f4d099f5..9156afc39 100644 --- a/tester/rcfiles/laure_rc +++ b/tester/rcfiles/laure_rc @@ -23,8 +23,8 @@ dial_escape_plus=0 [rtp] -audio_rtp_port=9010 -video_rtp_port=9012 +audio_rtp_port=9010-9390 +video_rtp_port=9410-9910 [video] display=0 @@ -41,4 +41,4 @@ device=StaticImage: Static picture echocancellation=0 #to not overload cpu in case of VG [net] -dns_srv_enabled=0 #no srv needed in general \ No newline at end of file +dns_srv_enabled=0 #no srv needed in general diff --git a/tester/rcfiles/marie_early_rc b/tester/rcfiles/marie_early_rc index 079a81879..f1866026b 100644 --- a/tester/rcfiles/marie_early_rc +++ b/tester/rcfiles/marie_early_rc @@ -30,8 +30,8 @@ subscribe=0 [rtp] -audio_rtp_port=18070 -video_rtp_port=19072 +audio_rtp_port=18070-28000 +video_rtp_port=39072-49000 [video] display=0 diff --git a/tester/rcfiles/marie_h264_rc b/tester/rcfiles/marie_h264_rc index f2ab26190..dc89fceb4 100644 --- a/tester/rcfiles/marie_h264_rc +++ b/tester/rcfiles/marie_h264_rc @@ -32,8 +32,8 @@ subscribe=0 [rtp] -audio_rtp_port=8070 -video_rtp_port=9072 +audio_rtp_port=18070-28000 +video_rtp_port=39072-49000 [video] display=1 diff --git a/tester/rcfiles/marie_rc b/tester/rcfiles/marie_rc index 367353d06..536725564 100644 --- a/tester/rcfiles/marie_rc +++ b/tester/rcfiles/marie_rc @@ -32,8 +32,8 @@ subscribe=0 [rtp] -audio_rtp_port=8070 -video_rtp_port=9072 +audio_rtp_port=18070-28000 +video_rtp_port=28070-38000 [video] display=0 diff --git a/tester/rcfiles/marie_rc_rtcp_xr b/tester/rcfiles/marie_rc_rtcp_xr index 93f8e5bd0..06f0b5b63 100644 --- a/tester/rcfiles/marie_rc_rtcp_xr +++ b/tester/rcfiles/marie_rc_rtcp_xr @@ -32,8 +32,8 @@ subscribe=0 [rtp] -audio_rtp_port=8070 -video_rtp_port=9072 +audio_rtp_port=20070-22070 +video_rtp_port=24000-25000 rtcp_xr_enabled=1 rtcp_xr_rcvr_rtt_mode=all rtcp_xr_rcvr_rtt_max_size=10000 diff --git a/tester/rcfiles/marie_sips_rc b/tester/rcfiles/marie_sips_rc new file mode 100644 index 000000000..7a935d4cb --- /dev/null +++ b/tester/rcfiles/marie_sips_rc @@ -0,0 +1,53 @@ +[sip] +sip_port=-1 +sip_tcp_port=-1 +sip_tls_port=-1 +default_proxy=0 +ping_with_options=0 +register_only_when_network_is_up=0 +composing_idle_timeout=1 + +[auth_info_0] +username=marie +userid=marie +passwd=secret +realm=sip2.linphone.org + + +[proxy_0] +reg_proxy=sips:sip2.linphone.org +reg_route=sips:sip2.linphone.org +reg_identity="Super Marie" +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 +quality_reporting_collector=sip:collector@sip2.linphone.org +quality_reporting_enabled=1 + +[friend_0] +url="Paupoche" +pol=accept +subscribe=0 + + +[rtp] +audio_rtp_port=18070-28000 +video_rtp_port=28070-38000 + +[video] +display=0 +capture=0 +show_local=0 +size=vga +enabled=0 +self_view=0 +automatically_initiate=0 +automatically_accept=0 +device=StaticImage: Static picture + +[sound] +echocancellation=0 #to not overload cpu in case of VG + +[net] +dns_srv_enabled=0 #no srv needed in general diff --git a/tester/rcfiles/pauline_alt_rc b/tester/rcfiles/pauline_alt_rc index 7c1fe55ac..c8e730729 100644 --- a/tester/rcfiles/pauline_alt_rc +++ b/tester/rcfiles/pauline_alt_rc @@ -1,4 +1,6 @@ [sip] +sip_port=-1 +sip_tcp_port=-1 sip_tls_port=-1 default_proxy=0 register_only_when_network_is_up=0 diff --git a/tester/rcfiles/pauline_h264_rc b/tester/rcfiles/pauline_h264_rc index d11c7d071..8f30cf020 100644 --- a/tester/rcfiles/pauline_h264_rc +++ b/tester/rcfiles/pauline_h264_rc @@ -29,8 +29,8 @@ dial_escape_plus=0 #subscribe=0 [rtp] -audio_rtp_port=8090 -video_rtp_port=9092 +audio_rtp_port=18070-28000 +video_rtp_port=39072-49000 [video] display=0 diff --git a/tester/rcfiles/pauline_rc b/tester/rcfiles/pauline_rc index 7322fd99a..35ad8c36f 100644 --- a/tester/rcfiles/pauline_rc +++ b/tester/rcfiles/pauline_rc @@ -29,8 +29,8 @@ dial_escape_plus=0 #subscribe=0 [rtp] -audio_rtp_port=8090 -video_rtp_port=9092 +audio_rtp_port=18070-28000 +video_rtp_port=39072-49000 [video] display=0 diff --git a/tester/rcfiles/pauline_rc_rtcp_xr b/tester/rcfiles/pauline_rc_rtcp_xr index 331f942ef..94c0314ea 100644 --- a/tester/rcfiles/pauline_rc_rtcp_xr +++ b/tester/rcfiles/pauline_rc_rtcp_xr @@ -29,8 +29,8 @@ dial_escape_plus=0 #subscribe=0 [rtp] -audio_rtp_port=8090 -video_rtp_port=9092 +audio_rtp_port=18070-28000 +video_rtp_port=39072-49000 rtcp_xr_enabled=1 rtcp_xr_rcvr_rtt_mode=all rtcp_xr_rcvr_rtt_max_size=10000 diff --git a/tester/rcfiles/pauline_sips_rc b/tester/rcfiles/pauline_sips_rc new file mode 100644 index 000000000..f248cffc1 --- /dev/null +++ b/tester/rcfiles/pauline_sips_rc @@ -0,0 +1,50 @@ +[sip] +sip_port=-1 +sip_tcp_port=-1 +sip_tls_port=-1 +default_proxy=0 +ping_with_options=0 +register_only_when_network_is_up=0 +composing_idle_timeout=1 + +[auth_info_0] +username=pauline +userid=pauline +passwd=secret +realm=sip.example.org + + +[proxy_0] +reg_proxy=sips:sip2.linphone.org +reg_route=sips:sip2.linphone.org +reg_identity=sips:pauline@sip.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + +#[friend_0] +#url="Mariette" +#pol=accept +#subscribe=0 + +[rtp] +audio_rtp_port=18070-28000 +video_rtp_port=39072-49000 + +[video] +display=0 +capture=0 +show_local=0 +size=vga +enabled=0 +self_view=0 +automatically_initiate=0 +automatically_accept=0 +device=StaticImage: Static picture + +[sound] +echocancellation=0 #to not overload cpu in case of VG + +[net] +dns_srv_enabled=0 #no srv needed in general diff --git a/tester/rcfiles/pauline_tcp_rc b/tester/rcfiles/pauline_tcp_rc index 809c1ace6..73fd469d7 100644 --- a/tester/rcfiles/pauline_tcp_rc +++ b/tester/rcfiles/pauline_tcp_rc @@ -29,8 +29,8 @@ dial_escape_plus=0 #subscribe=0 [rtp] -audio_rtp_port=8090 -video_rtp_port=9092 +audio_rtp_port=18070-28000 +video_rtp_port=39072-49000 [video] display=0 diff --git a/tester/rcfiles/pauline_wild_rc b/tester/rcfiles/pauline_wild_rc index d828c807d..1d0d9b164 100644 --- a/tester/rcfiles/pauline_wild_rc +++ b/tester/rcfiles/pauline_wild_rc @@ -1,4 +1,6 @@ [sip] +sip_port=-1 +sip_tcp_port=-1 sip_tls_port=-1 default_proxy=0 register_only_when_network_is_up=0 diff --git a/tester/register_tester.c b/tester/register_tester.c index 907a10db7..b0687352d 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -190,6 +190,25 @@ static void simple_register(){ linphone_core_manager_destroy(lcm); } +static void register_with_custom_headers(void){ + LinphoneCoreManager *marie=linphone_core_manager_new("marie_rc"); + LinphoneProxyConfig *cfg=linphone_core_get_default_proxy_config(marie->lc); + int initial_register_ok=marie->stat.number_of_LinphoneRegistrationOk; + const char *value; + + linphone_core_set_network_reachable(marie->lc, FALSE); + linphone_proxy_config_set_custom_header(cfg, "ah-bah-ouais", "...mais bon."); + /*unfortunately it is difficult to programmatically check that sent custom headers are actually sent. + * A server development would be required here.*/ + + linphone_core_set_network_reachable(marie->lc, TRUE); + wait_for(marie->lc, NULL, &marie->stat.number_of_LinphoneRegistrationOk,initial_register_ok+1); + value=linphone_proxy_config_get_custom_header(cfg, "Server"); + CU_ASSERT_PTR_NOT_NULL(value); + if (value) CU_ASSERT_TRUE(strstr(value, "Flexisip")!=NULL); + linphone_core_manager_destroy(marie); +} + static void simple_unregister(){ LinphoneCoreManager* lcm = create_lcm(); stats* counters = &lcm->stat; @@ -781,7 +800,7 @@ static void tls_alt_name_register(){ linphone_core_refresh_registers(mgr->lc); CU_ASSERT_TRUE(wait_for(lc,lc,&mgr->stat.number_of_LinphoneRegistrationOk,1)); CU_ASSERT_EQUAL(mgr->stat.number_of_LinphoneRegistrationFailed,0); - linphone_core_destroy(mgr->lc); + linphone_core_manager_destroy(mgr); } static void tls_wildcard_register(){ @@ -814,6 +833,7 @@ test_t register_tests[] = { { "Simple register", simple_register }, { "Simple register unregister", simple_unregister }, { "TCP register", simple_tcp_register }, + { "Register with custom headers", register_with_custom_headers }, { "TCP register compatibility mode", simple_tcp_register_compatibility_mode }, { "TLS register", simple_tls_register }, { "TLS register with alt. name certificate", tls_alt_name_register }, diff --git a/tester/remote_provisioning_tester.c b/tester/remote_provisioning_tester.c index 6864b573a..12c194a67 100644 --- a/tester/remote_provisioning_tester.c +++ b/tester/remote_provisioning_tester.c @@ -104,7 +104,10 @@ static void remote_provisioning_default_values(void) { static void remote_provisioning_file(void) { LinphoneCoreManager* marie; const LpConfig* conf; -#if ANDROID +#if TARGET_OS_IPHONE + ms_message("Skipping remote provisioning from file on iOS"); + return; +#elif defined(ANDROID) marie = linphone_core_manager_new2("marie_remote_localfile_android_rc", FALSE); #else marie = linphone_core_manager_new2("marie_remote_localfile_rc", FALSE); diff --git a/tester/setup_tester.c b/tester/setup_tester.c index eaa9b6a97..06d734d6a 100644 --- a/tester/setup_tester.c +++ b/tester/setup_tester.c @@ -96,9 +96,8 @@ static void linphone_interpret_url_test() } static void linphone_lpconfig_from_buffer(){ - - static const char* buffer = "[buffer]\ntest=ok"; - static const char* buffer_linebreaks = "[buffer_linebreaks]\n\n\n\r\n\n\r\ntest=ok"; + const char* buffer = "[buffer]\ntest=ok"; + const char* buffer_linebreaks = "[buffer_linebreaks]\n\n\n\r\n\n\r\ntest=ok"; LpConfig* conf; conf = lp_config_new_from_buffer(buffer); @@ -112,7 +111,7 @@ static void linphone_lpconfig_from_buffer(){ static void linphone_lpconfig_from_buffer_zerolen_value(){ /* parameters that have no value should return NULL, not "". */ - static const char* zerolen = "[test]\nzero_len=\nnon_zero_len=test"; + const char* zerolen = "[test]\nzero_len=\nnon_zero_len=test"; LpConfig* conf; conf = lp_config_new_from_buffer(zerolen); @@ -128,23 +127,28 @@ static void linphone_lpconfig_from_buffer_zerolen_value(){ static void linphone_lpconfig_from_file_zerolen_value(){ /* parameters that have no value should return NULL, not "". */ - static const char* zero_rc_file = "zero_length_params_rc"; + const char* zero_rc_file = "zero_length_params_rc"; 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" */ CU_ASSERT_STRING_EQUAL(lp_config_get_string(conf,"test","non_zero_len","LOL"), "LOL"); + ms_free(rc_path); lp_config_destroy(conf); } static void linphone_lpconfig_from_xml_zerolen_value(){ - static const char* zero_xml_file = "remote_zero_length_params_rc"; + const char* zero_xml_file = "remote_zero_length_params_rc"; char* xml_path = ms_strdup_printf("%s/rcfiles/%s", liblinphone_tester_file_prefix, zero_xml_file); LpConfig* conf; @@ -161,7 +165,7 @@ static void linphone_lpconfig_from_xml_zerolen_value(){ CU_ASSERT_STRING_EQUAL(lp_config_get_string(conf,"test","non_zero_len","LOL"), "LOL"); linphone_core_manager_destroy(mgr); - + ms_free(xml_path); } void linphone_proxy_config_address_equal_test() { @@ -170,13 +174,17 @@ void linphone_proxy_config_address_equal_test() { LinphoneAddress *c = linphone_address_new("sip:toto@titi;transport=tcp"); LinphoneAddress *d = linphone_address_new("sip:toto@titu"); LinphoneAddress *e = linphone_address_new("sip:toto@titi;transport=udp"); + LinphoneAddress *f = linphone_address_new("sip:toto@titi?X-Create-Account=yes"); - CU_ASSERT_FALSE(linphone_proxy_config_address_equal(a,NULL)); - CU_ASSERT_FALSE(linphone_proxy_config_address_equal(a,b)); - CU_ASSERT_FALSE(linphone_proxy_config_address_equal(a,c)); - CU_ASSERT_FALSE(linphone_proxy_config_address_equal(a,d)); - CU_ASSERT_TRUE(linphone_proxy_config_address_equal(a,e)); - CU_ASSERT_TRUE(linphone_proxy_config_address_equal(NULL,NULL)); + CU_ASSERT_EQUAL(linphone_proxy_config_address_equal(a,NULL), LinphoneProxyConfigAddressDifferent); + CU_ASSERT_EQUAL(linphone_proxy_config_address_equal(a,b), LinphoneProxyConfigAddressDifferent); + CU_ASSERT_EQUAL(linphone_proxy_config_address_equal(a,c), LinphoneProxyConfigAddressDifferent); + CU_ASSERT_EQUAL(linphone_proxy_config_address_equal(a,d), LinphoneProxyConfigAddressDifferent); + CU_ASSERT_EQUAL(linphone_proxy_config_address_equal(a,e), LinphoneProxyConfigAddressWeakEqual); + CU_ASSERT_EQUAL(linphone_proxy_config_address_equal(NULL,NULL), LinphoneProxyConfigAddressEqual); + CU_ASSERT_EQUAL(linphone_proxy_config_address_equal(a,f), LinphoneProxyConfigAddressWeakEqual); + CU_ASSERT_EQUAL(linphone_proxy_config_address_equal(c,f), LinphoneProxyConfigAddressDifferent); + CU_ASSERT_EQUAL(linphone_proxy_config_address_equal(e,f), LinphoneProxyConfigAddressWeakEqual); linphone_address_destroy(a); linphone_address_destroy(b); @@ -192,36 +200,36 @@ void linphone_proxy_config_is_server_config_changed_test() { linphone_proxy_config_set_identity(proxy_config,"sip:toto@titi"); linphone_proxy_config_edit(proxy_config); linphone_proxy_config_set_identity(proxy_config,"sips:toto@titi"); - CU_ASSERT_TRUE(linphone_proxy_config_is_server_config_changed(proxy_config)); + CU_ASSERT_EQUAL(linphone_proxy_config_is_server_config_changed(proxy_config), LinphoneProxyConfigAddressDifferent); linphone_proxy_config_set_server_addr(proxy_config,"sip:sip.linphone.org"); linphone_proxy_config_edit(proxy_config); linphone_proxy_config_set_server_addr(proxy_config,"sip:toto.com"); - CU_ASSERT_TRUE(linphone_proxy_config_is_server_config_changed(proxy_config)); + CU_ASSERT_EQUAL(linphone_proxy_config_is_server_config_changed(proxy_config), LinphoneProxyConfigAddressDifferent); linphone_proxy_config_set_server_addr(proxy_config,"sip:sip.linphone.org"); linphone_proxy_config_edit(proxy_config); linphone_proxy_config_set_server_addr(proxy_config,"sip:sip.linphone.org:4444"); - CU_ASSERT_TRUE(linphone_proxy_config_is_server_config_changed(proxy_config)); + CU_ASSERT_EQUAL(linphone_proxy_config_is_server_config_changed(proxy_config), LinphoneProxyConfigAddressDifferent); linphone_proxy_config_set_server_addr(proxy_config,"sip:sip.linphone.org"); linphone_proxy_config_edit(proxy_config); linphone_proxy_config_set_server_addr(proxy_config,"sip:sip.linphone.org;transport=tcp"); - CU_ASSERT_TRUE(linphone_proxy_config_is_server_config_changed(proxy_config)); + CU_ASSERT_EQUAL(linphone_proxy_config_is_server_config_changed(proxy_config), LinphoneProxyConfigAddressDifferent); linphone_proxy_config_set_server_addr(proxy_config,"sip:sip.linphone.org"); linphone_proxy_config_edit(proxy_config); linphone_proxy_config_set_server_addr(proxy_config,"sip:sip.linphone.org;param=blue"); - CU_ASSERT_FALSE(linphone_proxy_config_is_server_config_changed(proxy_config)); + CU_ASSERT_EQUAL(linphone_proxy_config_is_server_config_changed(proxy_config), LinphoneProxyConfigAddressWeakEqual); linphone_proxy_config_edit(proxy_config); linphone_proxy_config_set_contact_parameters(proxy_config,"blabla=blue"); - CU_ASSERT_FALSE(linphone_proxy_config_is_server_config_changed(proxy_config)); + CU_ASSERT_EQUAL(linphone_proxy_config_is_server_config_changed(proxy_config), LinphoneProxyConfigAddressEqual); linphone_proxy_config_edit(proxy_config); linphone_proxy_config_enable_register(proxy_config,TRUE); - CU_ASSERT_FALSE(linphone_proxy_config_is_server_config_changed(proxy_config)); + CU_ASSERT_EQUAL(linphone_proxy_config_is_server_config_changed(proxy_config), LinphoneProxyConfigAddressEqual); linphone_proxy_config_destroy(proxy_config); } diff --git a/tester/sounds/ahbahouaismaisbon.wav b/tester/sounds/ahbahouaismaisbon.wav new file mode 100644 index 000000000..dca22773a Binary files /dev/null and b/tester/sounds/ahbahouaismaisbon.wav differ diff --git a/tester/sounds/hello8000.wav b/tester/sounds/hello8000.wav index b787b202e..b5629df7a 100644 Binary files a/tester/sounds/hello8000.wav and b/tester/sounds/hello8000.wav differ diff --git a/tester/sounds/hello8000_mkv_ref.wav b/tester/sounds/hello8000_mkv_ref.wav new file mode 100644 index 000000000..f91203cd8 Binary files /dev/null and b/tester/sounds/hello8000_mkv_ref.wav differ diff --git a/tester/stun_tester.c b/tester/stun_tester.c index 99b1190ed..58a069f3d 100644 --- a/tester/stun_tester.c +++ b/tester/stun_tester.c @@ -21,7 +21,7 @@ #include "linphonecore.h" #include "private.h" #include "liblinphone_tester.h" -#include "ortp/stun.h" +#include "mediastreamer2/stun.h" #include "ortp/port.h" diff --git a/tester/tester.c b/tester/tester.c index aa0bd3e8b..aadfbee83 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -17,15 +17,17 @@ */ #include -#include "CUnit/Basic.h" +#include "CUnit/TestRun.h" +#include "CUnit/Automated.h" #include "linphonecore.h" #include "private.h" #include "liblinphone_tester.h" #if HAVE_CU_CURSES #include "CUnit/CUCurses.h" #endif - -static LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, const char* file, void* user_data); +#ifdef HAVE_GTK +#include +#endif static test_suite_t **test_suite = NULL; static int nb_test_suites = 0; @@ -40,6 +42,13 @@ const char* auth_domain="sip.example.org"; const char* test_username="liblinphone_tester"; const char* test_password="secret"; const char* test_route="sip2.linphone.org"; +int liblinphone_tester_use_log_file=0; +static int liblinphone_tester_keep_accounts_flag = 0; +static bool_t liblinphone_tester_ipv6_enabled=FALSE; +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"; @@ -78,6 +87,10 @@ bool_t liblinphone_tester_clock_elapsed(const MSTimeSpec *start, int value_ms){ return FALSE; } +void liblinphone_tester_enable_ipv6(bool_t enabled){ + liblinphone_tester_ipv6_enabled=enabled; +} + LinphoneAddress * create_linphone_address(const char * domain) { LinphoneAddress *addr = linphone_address_new(NULL); CU_ASSERT_PTR_NOT_NULL_FATAL(addr); @@ -104,41 +117,66 @@ static void auth_info_requested(LinphoneCore *lc, const char *realm, const char void reset_counters( stats* counters) { + if (counters->last_received_chat_message) linphone_chat_message_unref(counters->last_received_chat_message); memset(counters,0,sizeof(stats)); } -static LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, const char* file, void* user_data) { +LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, const char* file, void* user_data) { LinphoneCore* lc; - char filepath[256]={0}; - char ringpath[256]={0}; - char ringbackpath[256]={0}; - char rootcapath[256]={0}; - char dnsuserhostspath[256]={0}; - char nowebcampath[256]={0}; + LpConfig* config = NULL; + char *filepath = NULL; + char *ringpath = NULL; + char *ringbackpath = NULL; + char *rootcapath = NULL; + char *dnsuserhostspath = NULL; + char *nowebcampath = NULL; if (path==NULL) path="."; if (file){ - sprintf(filepath, "%s/%s", path, file); + filepath = ms_strdup_printf("%s/%s", path, file); CU_ASSERT_TRUE_FATAL(ortp_file_exist(filepath)==0); + config = lp_config_new_with_factory(NULL,filepath); } - lc = linphone_core_new(v_table,NULL,*filepath!='\0' ? filepath : NULL, user_data); + + // setup dynamic-path assets + ringpath = ms_strdup_printf("%s/sounds/oldphone.wav",path); + ringbackpath = ms_strdup_printf("%s/sounds/ringback.wav", path); + nowebcampath = ms_strdup_printf("%s/images/nowebcamCIF.jpg", path); + rootcapath = ms_strdup_printf("%s/certificates/cn/cafile.pem", path); + dnsuserhostspath = ms_strdup_printf( "%s/%s", path, userhostsfile); + + + if( config != NULL ) { + lp_config_set_string(config, "sound", "remote_ring", ringbackpath); + lp_config_set_string(config, "sound", "local_ring" , ringpath); + lp_config_set_string(config, "sip", "root_ca" , rootcapath); + lc = linphone_core_new_with_config(v_table, config, user_data); + } else { + lc = linphone_core_new(v_table,NULL,(filepath!=NULL&&filepath[0]!='\0') ? filepath : NULL, user_data); + + linphone_core_set_ring(lc, ringpath); + linphone_core_set_ringback(lc, ringbackpath); + linphone_core_set_root_ca(lc,rootcapath); + } sal_enable_test_features(lc->sal,TRUE); - snprintf(rootcapath, sizeof(rootcapath), "%s/certificates/cn/cafile.pem", path); - linphone_core_set_root_ca(lc,rootcapath); - - sprintf(dnsuserhostspath, "%s/%s", path, userhostsfile); sal_set_dns_user_hosts_file(lc->sal, dnsuserhostspath); - - snprintf(ringpath,sizeof(ringpath), "%s/sounds/oldphone.wav",path); - snprintf(ringbackpath,sizeof(ringbackpath), "%s/sounds/ringback.wav", path); - linphone_core_set_ring(lc, ringpath); - linphone_core_set_ringback(lc, ringbackpath); - - snprintf(nowebcampath, sizeof(nowebcampath), "%s/images/nowebcamCIF.jpg", path); linphone_core_set_static_picture(lc,nowebcampath); + + linphone_core_enable_ipv6(lc, liblinphone_tester_ipv6_enabled); + + ms_free(ringpath); + ms_free(ringbackpath); + ms_free(nowebcampath); + ms_free(rootcapath); + ms_free(dnsuserhostspath); + + if( filepath ) ms_free(filepath); + + if( config ) lp_config_unref(config); + return lc; } @@ -166,8 +204,22 @@ bool_t wait_for_list(MSList* lcs,int* counter,int value,int timeout_ms) { liblinphone_tester_clock_start(&start); while ((counter==NULL || *counternext) { +#ifdef HAVE_GTK + gdk_threads_enter(); + gtk_main_iteration_do(FALSE); + gdk_threads_leave(); +#endif linphone_core_iterate((LinphoneCore*)(iterator->data)); } +#ifdef WIN32 + { + MSG msg; + while (PeekMessage(&msg, NULL, 0, 0,1)){ + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } +#endif ms_usleep(20000); } if(counter && *counternumber_of_cunit_error_at_creation = CU_get_number_of_failures(); mgr->v_table.registration_state_changed=registration_state_changed; mgr->v_table.auth_info_requested=auth_info_requested; mgr->v_table.call_state_changed=call_state_changed; mgr->v_table.text_received=text_message_received; mgr->v_table.message_received=message_received; - mgr->v_table.file_transfer_recv=file_transfer_received; - mgr->v_table.file_transfer_send=file_transfer_send; - mgr->v_table.file_transfer_progress_indication=file_transfer_progress_indication; mgr->v_table.is_composing_received=is_composing_received; mgr->v_table.new_subscription_requested=new_subscription_requested; mgr->v_table.notify_presence_received=notify_presence_received; @@ -226,25 +275,44 @@ LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_f mgr->v_table.call_encryption_changed=linphone_call_encryption_changed; mgr->v_table.network_reachable=network_reachable; mgr->v_table.dtmf_received=dtmf_received; + mgr->v_table.call_stats_updated=call_stats_updated; reset_counters(&mgr->stat); if (rc_file) rc_path = ms_strdup_printf("rcfiles/%s", rc_file); mgr->lc=configure_lc_from(&mgr->v_table, liblinphone_tester_file_prefix, rc_path, mgr); + linphone_core_manager_check_accounts(mgr); /*CU_ASSERT_EQUAL(ms_list_size(linphone_core_get_proxy_config_list(lc)),proxy_count);*/ if (check_for_proxies && rc_file) /**/ proxy_count=ms_list_size(linphone_core_get_proxy_config_list(mgr->lc)); else proxy_count=0; + 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); #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]; + char *recordpath = ms_strdup_printf("%s/record_for_lc_%p.wav",liblinphone_tester_writable_dir_prefix,mgr->lc); + 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); + linphone_core_set_record_file(mgr->lc,recordpath); + ms_free(recordpath); + } + + 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); @@ -269,9 +337,21 @@ void linphone_core_manager_stop(LinphoneCoreManager *mgr){ } void linphone_core_manager_destroy(LinphoneCoreManager* mgr) { - if (mgr->lc) linphone_core_destroy(mgr->lc); + if (mgr->lc){ + const char *record_file=linphone_core_get_record_file(mgr->lc); + if (record_file){ + if ((CU_get_number_of_failures()-mgr->number_of_cunit_error_at_creation)>0) { + ms_message ("Test has failed, keeping recorded file [%s]",record_file); + } else { + unlink(record_file); + } + } + linphone_core_destroy(mgr->lc); + } if (mgr->identity) linphone_address_destroy(mgr->identity); if (mgr->stat.last_received_chat_message) linphone_chat_message_unref(mgr->stat.last_received_chat_message); + manager_count--; + ms_free(mgr); } @@ -377,6 +457,7 @@ void liblinphone_tester_set_writable_dir_prefix(const char* writable_dir_prefix) void liblinphone_tester_init(void) { add_test_suite(&setup_test_suite); add_test_suite(®ister_test_suite); + add_test_suite(&offeranswer_test_suite); add_test_suite(&call_test_suite); add_test_suite(&message_test_suite); add_test_suite(&presence_test_suite); @@ -392,6 +473,10 @@ void liblinphone_tester_init(void) { add_test_suite(&transport_test_suite); add_test_suite(&player_test_suite); add_test_suite(&dtmf_test_suite); +#if defined(VIDEO_ENABLED) && defined(HAVE_GTK) + add_test_suite(&video_test_suite); +#endif + add_test_suite(&multicast_call_test_suite); } void liblinphone_tester_uninit(void) { @@ -402,6 +487,60 @@ void liblinphone_tester_uninit(void) { } } +/*derivated from cunit*/ +static void test_complete_message_handler(const CU_pTest pTest, + const CU_pSuite pSuite, + const CU_pFailureRecord pFailureList) { + int i; + CU_pFailureRecord pFailure = pFailureList; + if (pFailure) { + if (liblinphone_tester_use_log_file) ms_warning("Suite [%s], Test [%s] had failures:", pSuite->pName, pTest->pName); + liblinphone_tester_fprintf(stdout,"\nSuite [%s], Test [%s] had failures:", pSuite->pName, pTest->pName); + } else { + if (liblinphone_tester_use_log_file) ms_warning(" passed"); + liblinphone_tester_fprintf(stdout," passed"); + } + for (i = 1 ; (NULL != pFailure) ; pFailure = pFailure->pNext, i++) { + if (liblinphone_tester_use_log_file) ms_warning("\n %d. %s:%u - %s", i, + (NULL != pFailure->strFileName) ? pFailure->strFileName : "", + pFailure->uiLineNumber, + (NULL != pFailure->strCondition) ? pFailure->strCondition : ""); + liblinphone_tester_fprintf(stdout,"\n %d. %s:%u - %s", i, + (NULL != pFailure->strFileName) ? pFailure->strFileName : "", + pFailure->uiLineNumber, + (NULL != pFailure->strCondition) ? pFailure->strCondition : ""); + } + } + + +static void test_all_tests_complete_message_handler(const CU_pFailureRecord pFailure) { + char * results = CU_get_run_results_string(); + if (liblinphone_tester_use_log_file) { + ms_warning("\n\n %s", results); + } + liblinphone_tester_fprintf(stdout,"\n\n %s",results); + ms_free(results); +} + +static void test_suite_init_failure_message_handler(const CU_pSuite pSuite) { + if (liblinphone_tester_use_log_file) ms_warning("Suite initialization failed for [%s].", pSuite->pName); + liblinphone_tester_fprintf(stdout,"Suite initialization failed for [%s].", pSuite->pName); +} + +static void test_suite_cleanup_failure_message_handler(const CU_pSuite pSuite) { + if (liblinphone_tester_use_log_file) ms_warning("Suite cleanup failed for '%s'.", pSuite->pName); + liblinphone_tester_fprintf(stdout,"Suite cleanup failed for [%s].", pSuite->pName); +} + +static void test_start_message_handler(const CU_pTest pTest, const CU_pSuite pSuite) { + if (liblinphone_tester_use_log_file) ms_warning("Suite [%s] Test [%s]", pSuite->pName,pTest->pName); + liblinphone_tester_fprintf(stdout,"\nSuite [%s] Test [%s]\n", pSuite->pName,pTest->pName); +} +static void test_suite_start_message_handler(const CU_pSuite pSuite) { + if (liblinphone_tester_use_log_file) ms_warning("Suite [%s]", pSuite->pName); + liblinphone_tester_fprintf(stdout,"\nSuite [%s]", pSuite->pName); +} + int liblinphone_tester_run_tests(const char *suite_name, const char *test_name) { int i; int ret; @@ -413,60 +552,78 @@ int liblinphone_tester_run_tests(const char *suite_name, const char *test_name) run_test_suite(test_suite[i]); } + CU_set_test_start_handler(test_start_message_handler); + CU_set_test_complete_handler(test_complete_message_handler); + CU_set_all_test_complete_handler(test_all_tests_complete_message_handler); + CU_set_suite_init_failure_handler(test_suite_init_failure_message_handler); + CU_set_suite_cleanup_failure_handler(test_suite_cleanup_failure_message_handler); + 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; - CU_basic_set_mode(CU_BRM_VERBOSE); - 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_basic_run_test(suite, test); - if (err != CUE_SUCCESS) ms_error("CU_basic_run_test error %d", err); - } - } else { - CU_basic_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 sensitive + 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_basic_set_mode(CU_BRM_VERBOSE); - CU_basic_run_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 */ if (CU_get_number_of_failure_records()){ CU_basic_show_failures(CU_get_failure_list()); - printf("\n"); + liblinphone_tester_fprintf(stdout,"\n"); } CU_cleanup_registry(); + + if( liblinphone_tester_keep_accounts_flag == 0){ + liblinphone_tester_clear_accounts(); + } return ret; } @@ -476,10 +633,11 @@ int liblinphone_tester_fprintf(FILE * stream, const char * format, ...) { va_start(args, format); #ifndef ANDROID result = vfprintf(stream,format,args); + fflush(stream); #else /*used by liblinphone tester to retrieve suite list*/ result = 0; - cunit_android_trace_handler(stream, format, args); + cunit_android_trace_handler(stream == stderr, format, args); #endif va_end(args); return result; @@ -503,3 +661,26 @@ int liblinphone_tester_ipv6_available(void){ return FALSE; } +void liblinphone_tester_keep_accounts( int keep ){ + liblinphone_tester_keep_accounts_flag = keep; +} + +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; +} + + + + diff --git a/tester/tester_hosts b/tester/tester_hosts index b7056b863..872dd4a63 100644 --- a/tester/tester_hosts +++ b/tester/tester_hosts @@ -1 +1,2 @@ 94.23.19.176 sip2.linphone.org sip.example.org sipopen.example.org auth.example.org auth1.example.org auth2.example.org altname.linphone.org sip.wildcard1.linphone.org altname.wildcard2.linphone.org +2001:41d0:2:14b0::1 sip2.linphone.org sip.example.org sipopen.example.org auth.example.org auth1.example.org auth2.example.org altname.linphone.org sip.wildcard1.linphone.org altname.wildcard2.linphone.org \ No newline at end of file diff --git a/tester/transport_tester.c b/tester/transport_tester.c index fdc4a194f..e847e0fe8 100644 --- a/tester/transport_tester.c +++ b/tester/transport_tester.c @@ -59,6 +59,8 @@ static char* get_public_contact_ip(LinphoneCore* lc) { ms_free(contact); return ms_strdup(contact_host_ip); } + + static void call_with_transport_base(LinphoneTunnelMode tunnel_mode, bool_t with_sip, LinphoneMediaEncryption encryption) { if (linphone_core_tunnel_available()){ LinphoneCoreManager *pauline = linphone_core_manager_new( "pauline_rc"); @@ -131,6 +133,7 @@ static void call_with_transport_base(LinphoneTunnelMode tunnel_mode, bool_t with } } + static void call_with_tunnel(void) { call_with_transport_base(LinphoneTunnelModeEnable, TRUE, LinphoneMediaEncryptionNone); } @@ -151,12 +154,70 @@ static void call_with_tunnel_auto_without_sip_with_srtp(void) { call_with_transport_base(LinphoneTunnelModeAuto, FALSE, LinphoneMediaEncryptionSRTP); } +#ifdef VIDEO_ENABLED +static void tunnel_srtp_video_ice_call(void) { + if (linphone_core_tunnel_available()) + call_base(LinphoneMediaEncryptionSRTP,TRUE,FALSE,LinphonePolicyUseIce,TRUE); + else + ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__); +} +static void tunnel_zrtp_video_ice_call(void) { + if (linphone_core_tunnel_available()) + call_base(LinphoneMediaEncryptionZRTP,TRUE,FALSE,LinphonePolicyUseIce,TRUE); + else + ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__); +} + +static void tunnel_dtls_video_ice_call(void) { + if (linphone_core_tunnel_available()) + call_base(LinphoneMediaEncryptionDTLS,TRUE,FALSE,LinphonePolicyUseIce,TRUE); + else + ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__); +} + +static void tunnel_video_ice_call(void) { + if (linphone_core_tunnel_available()) + call_base(LinphoneMediaEncryptionNone,TRUE,FALSE,LinphonePolicyUseIce,TRUE); + else + ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__); +} +#endif + +static void tunnel_srtp_ice_call(void) { + if (linphone_core_tunnel_available()) + call_base(LinphoneMediaEncryptionSRTP,FALSE,FALSE,LinphonePolicyUseIce,TRUE); + else + ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__); +} + +static void tunnel_zrtp_ice_call(void) { + if (linphone_core_tunnel_available()) + call_base(LinphoneMediaEncryptionZRTP,FALSE,FALSE,LinphonePolicyUseIce,TRUE); + else + ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__); +} + +static void tunnel_ice_call(void) { + if (linphone_core_tunnel_available()) + call_base(LinphoneMediaEncryptionNone,FALSE,FALSE,LinphonePolicyUseIce,TRUE); + else + ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__); +} test_t transport_tests[] = { { "Tunnel only", call_with_tunnel }, { "Tunnel with SRTP", call_with_tunnel_srtp }, { "Tunnel without SIP", call_with_tunnel_without_sip }, { "Tunnel in automatic mode", call_with_tunnel_auto }, { "Tunnel in automatic mode with SRTP without SIP", call_with_tunnel_auto_without_sip_with_srtp }, + { "Tunnel ice call", tunnel_ice_call }, + { "Tunnel SRTP ice call", tunnel_srtp_ice_call }, + { "Tunnel ZRTP ice call", tunnel_zrtp_ice_call }, +#ifdef VIDEO_ENABLED + { "Tunnel ice video call", tunnel_video_ice_call }, + { "Tunnel SRTP ice video call", tunnel_srtp_video_ice_call }, + { "Tunnel DTLS ice video call", tunnel_dtls_video_ice_call }, + { "Tunnel ZRTP ice video call", tunnel_zrtp_video_ice_call }, +#endif }; test_suite_t transport_test_suite = { diff --git a/tester/video_tester.c b/tester/video_tester.c new file mode 100644 index 000000000..7e3809e31 --- /dev/null +++ b/tester/video_tester.c @@ -0,0 +1,352 @@ +/* + liblinphone_tester - liblinphone test suite + Copyright (C) 2013 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, see . +*/ +#include "private.h" + +#if defined(VIDEO_ENABLED) && defined(HAVE_GTK) + +#include +#include "CUnit/Basic.h" +#include "linphonecore.h" +#include "liblinphone_tester.h" +#include "lpconfig.h" + + +#include +#ifdef GDK_WINDOWING_X11 +#include +#elif defined(WIN32) +#include +#elif defined(__APPLE__) +extern void *gdk_quartz_window_get_nswindow(GdkWindow *window); +extern void *gdk_quartz_window_get_nsview(GdkWindow *window); +#endif + +#include + + +static unsigned long get_native_handle(GdkWindow *gdkw) { +#ifdef GDK_WINDOWING_X11 + return (unsigned long)GDK_WINDOW_XID(gdkw); +#elif defined(WIN32) + return (unsigned long)GDK_WINDOW_HWND(gdkw); +#elif defined(__APPLE__) + return (unsigned long)gdk_quartz_window_get_nsview(gdkw); +#endif + g_warning("No way to get the native handle from gdk window"); + return 0; +} + +static GtkWidget *create_video_window(LinphoneCall *call, LinphoneCallState cstate) { + GtkWidget *video_window; + GdkDisplay *display; + GdkColor color; + MSVideoSize vsize = MS_VIDEO_SIZE_CIF; + const char *cstate_str; + char *title; + stats* counters = get_stats(call->core); + + cstate_str = linphone_call_state_to_string(cstate); + title = g_strdup_printf("%s", cstate_str); + video_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(video_window), title); + g_free(title); + gtk_window_resize(GTK_WINDOW(video_window), vsize.width, vsize.height); + gdk_color_parse("black", &color); + gtk_widget_modify_bg(video_window, GTK_STATE_NORMAL, &color); + gtk_widget_show(video_window); + g_object_set_data(G_OBJECT(video_window), "call", call); +#if GTK_CHECK_VERSION(2,24,0) + display = gdk_window_get_display(gtk_widget_get_window(video_window)); +#else // backward compatibility with Debian 6 and Centos 6 + display = gdk_drawable_get_display(gtk_widget_get_window(video_window)); +#endif + gdk_display_flush(display); + counters->number_of_video_windows_created++; + return video_window; +} + +static void show_video_window(LinphoneCall *call, LinphoneCallState cstate) { + GtkWidget *video_window = (GtkWidget *)linphone_call_get_user_data(call); + if (video_window == NULL) { + video_window = create_video_window(call, cstate); + linphone_call_set_user_data(call, video_window); + linphone_call_set_native_video_window_id(call, get_native_handle(gtk_widget_get_window(video_window))); + } +} + +static void hide_video_video(LinphoneCall *call) { + GtkWidget *video_window = (GtkWidget *)linphone_call_get_user_data(call); + if (video_window != NULL) { + gtk_widget_destroy(video_window); + linphone_call_set_user_data(call, NULL); + linphone_call_set_native_video_window_id(call, 0); + } +} + +static void video_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *msg) { + switch (cstate) { + case LinphoneCallIncomingEarlyMedia: + case LinphoneCallOutgoingEarlyMedia: + case LinphoneCallConnected: + show_video_window(call, cstate); + break; + case LinphoneCallEnd: + hide_video_video(call); + break; + default: + break; + } +} + +static void early_media_video_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *msg) { + LinphoneCallParams *params; + + video_call_state_changed(lc, call, cstate, msg); + switch (cstate) { + case LinphoneCallIncomingReceived: + params = linphone_core_create_default_call_parameters(lc); + linphone_call_params_enable_video(params, TRUE); + linphone_call_params_set_audio_direction(params, LinphoneMediaDirectionSendOnly); + linphone_call_params_set_video_direction(params, LinphoneMediaDirectionRecvOnly); + linphone_core_accept_early_media_with_params(lc, call, params); + linphone_call_params_unref(params); + break; + default: + break; + } +} + +bool_t wait_for_three_cores(LinphoneCore *lc1, LinphoneCore *lc2, LinphoneCore *lc3, int timeout) { + MSList *lcs = NULL; + bool_t result; + int dummy = 0; + if (lc1) lcs = ms_list_append(lcs, lc1); + if (lc2) lcs = ms_list_append(lcs, lc2); + if (lc3) lcs = ms_list_append(lcs, lc3); + result = wait_for_list(lcs, &dummy, 1, timeout); + ms_list_free(lcs); + return result; +} + +static bool_t video_call_with_params(LinphoneCoreManager* caller_mgr, LinphoneCoreManager* callee_mgr, const LinphoneCallParams *caller_params, const LinphoneCallParams *callee_params, bool_t automatically_accept) { + int retry = 0; + stats initial_caller = caller_mgr->stat; + stats initial_callee = callee_mgr->stat; + bool_t result = TRUE; + bool_t did_received_call; + + CU_ASSERT_PTR_NOT_NULL(linphone_core_invite_address_with_params(caller_mgr->lc, callee_mgr->identity, caller_params)); + did_received_call = wait_for(callee_mgr->lc, caller_mgr->lc, &callee_mgr->stat.number_of_LinphoneCallIncomingReceived, initial_callee.number_of_LinphoneCallIncomingReceived + 1); + if (!did_received_call) return 0; + + CU_ASSERT_EQUAL(caller_mgr->stat.number_of_LinphoneCallOutgoingProgress, initial_caller.number_of_LinphoneCallOutgoingProgress + 1); + + while (caller_mgr->stat.number_of_LinphoneCallOutgoingRinging != (initial_caller.number_of_LinphoneCallOutgoingRinging + 1) + && caller_mgr->stat.number_of_LinphoneCallOutgoingEarlyMedia != (initial_caller.number_of_LinphoneCallOutgoingEarlyMedia + 1) + && retry++ < 20) { + linphone_core_iterate(caller_mgr->lc); + linphone_core_iterate(callee_mgr->lc); + ms_usleep(100000); + } + + CU_ASSERT_TRUE((caller_mgr->stat.number_of_LinphoneCallOutgoingRinging == initial_caller.number_of_LinphoneCallOutgoingRinging + 1) + || (caller_mgr->stat.number_of_LinphoneCallOutgoingEarlyMedia == initial_caller.number_of_LinphoneCallOutgoingEarlyMedia + 1)); + + CU_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call_remote_address(callee_mgr->lc)); + if(!linphone_core_get_current_call(caller_mgr->lc) || !linphone_core_get_current_call(callee_mgr->lc) || !linphone_core_get_current_call_remote_address(callee_mgr->lc)) { + return 0; + } + + if (automatically_accept == TRUE) { + linphone_core_accept_call_with_params(callee_mgr->lc, linphone_core_get_current_call(callee_mgr->lc), callee_params); + + CU_ASSERT_TRUE(wait_for(callee_mgr->lc, caller_mgr->lc, &callee_mgr->stat.number_of_LinphoneCallConnected, initial_callee.number_of_LinphoneCallConnected + 1)); + CU_ASSERT_TRUE(wait_for(callee_mgr->lc, caller_mgr->lc, &caller_mgr->stat.number_of_LinphoneCallConnected, initial_callee.number_of_LinphoneCallConnected + 1)); + result = wait_for(callee_mgr->lc, caller_mgr->lc, &caller_mgr->stat.number_of_LinphoneCallStreamsRunning, initial_caller.number_of_LinphoneCallStreamsRunning + 1) + && wait_for(callee_mgr->lc, caller_mgr->lc, &callee_mgr->stat.number_of_LinphoneCallStreamsRunning, initial_callee.number_of_LinphoneCallStreamsRunning + 1); + } + return result; +} + +static LinphoneCallParams * _configure_for_video(LinphoneCoreManager *manager, LinphoneCoreCallStateChangedCb cb) { + LinphoneCallParams *params; + LinphoneCoreVTable *vtable = linphone_core_v_table_new(); + vtable->call_state_changed = cb; + linphone_core_add_listener(manager->lc, vtable); + linphone_core_set_video_device(manager->lc, "StaticImage: Static picture"); + linphone_core_enable_video_capture(manager->lc, TRUE); + linphone_core_enable_video_display(manager->lc, TRUE); + params = linphone_core_create_default_call_parameters(manager->lc); + linphone_call_params_enable_video(params, TRUE); + if (linphone_core_find_payload_type(manager->lc,"VP8", 90000, -1)!=NULL){ + disable_all_video_codecs_except_one(manager->lc, "VP8"); + }else{ + ms_warning("VP8 codec not available, will use MP4V-ES instead"); + disable_all_video_codecs_except_one(manager->lc, "MP4V-ES"); + } + return params; +} + +static LinphoneCallParams * configure_for_video(LinphoneCoreManager *manager) { + return _configure_for_video(manager, video_call_state_changed); +} + +static LinphoneCallParams * configure_for_early_media_video_sending(LinphoneCoreManager *manager) { + LinphoneCallParams *params = _configure_for_video(manager, video_call_state_changed); + linphone_call_params_enable_early_media_sending(params, TRUE); + return params; +} + +static LinphoneCallParams * configure_for_early_media_video_receiving(LinphoneCoreManager *manager) { + return _configure_for_video(manager, early_media_video_call_state_changed); +} + + +static void early_media_video_during_video_call_test(void) { + LinphoneCoreManager *marie; + LinphoneCoreManager *pauline; + LinphoneCoreManager *laure; + LinphoneCallParams *marie_params; + LinphoneCallParams *pauline_params; + LinphoneCallParams *laure_params; + + marie = linphone_core_manager_new("marie_rc"); + pauline = linphone_core_manager_new("pauline_rc"); + laure = linphone_core_manager_new("laure_rc"); + marie_params = configure_for_early_media_video_receiving(marie); + pauline_params = configure_for_video(pauline); + laure_params = configure_for_early_media_video_sending(laure); + + /* Normal automatically accepted video call from marie to pauline. */ + CU_ASSERT_TRUE(video_call_with_params(marie, pauline, marie_params, pauline_params, TRUE)); + + /* Wait for 2s. */ + wait_for_three_cores(marie->lc, pauline->lc, NULL, 2000); + + /* Early media video call from laure to marie. */ + CU_ASSERT_TRUE(video_call_with_params(laure, marie, laure_params, NULL, FALSE)); + + /* Wait for 2s. */ + wait_for_three_cores(marie->lc, pauline->lc, laure->lc, 2000); + + linphone_core_terminate_all_calls(marie->lc); + CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallEnd, 1)); + 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_LinphoneCallReleased, 1)); + CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallReleased, 1)); + CU_ASSERT_TRUE(wait_for(marie->lc, laure->lc, &marie->stat.number_of_LinphoneCallEnd, 1)); + CU_ASSERT_TRUE(wait_for(marie->lc, laure->lc, &laure->stat.number_of_LinphoneCallEnd, 1)); + + CU_ASSERT_EQUAL(marie->stat.number_of_video_windows_created, 2); + CU_ASSERT_EQUAL(pauline->stat.number_of_video_windows_created, 1); + CU_ASSERT_EQUAL(laure->stat.number_of_video_windows_created, 1); + + linphone_call_params_unref(marie_params); + linphone_call_params_unref(pauline_params); + linphone_call_params_unref(laure_params); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(laure); +} + +static void two_incoming_early_media_video_calls_test(void) { + char *ringback_path; + LinphoneCoreManager *marie; + LinphoneCoreManager *pauline; + LinphoneCoreManager *laure; + LinphoneCallParams *marie_params; + LinphoneCallParams *pauline_params; + LinphoneCallParams *laure_params; + LinphoneCall *call; + const MSList *calls_list; + + marie = linphone_core_manager_new("marie_rc"); + pauline = linphone_core_manager_new("pauline_rc"); + laure = linphone_core_manager_new("laure_rc"); + marie_params = configure_for_early_media_video_receiving(marie); + pauline_params = configure_for_early_media_video_sending(pauline); + laure_params = configure_for_early_media_video_sending(laure); + + /* Configure early media audio to play ring during early-media and send remote ring back tone. */ + linphone_core_set_ring_during_incoming_early_media(marie->lc, TRUE); + ringback_path = ms_strdup_printf("%s/sounds/ringback.wav", liblinphone_tester_file_prefix); + linphone_core_set_remote_ringback_tone(marie->lc, ringback_path); + ms_free(ringback_path); + + /* Early media video call from pauline to marie. */ + CU_ASSERT_TRUE(video_call_with_params(pauline, marie, pauline_params, NULL, FALSE)); + + /* Wait for 2s. */ + wait_for_three_cores(marie->lc, pauline->lc, NULL, 2000); + + /* Early media video call from laure to marie. */ + CU_ASSERT_TRUE(video_call_with_params(laure, marie, laure_params, NULL, FALSE)); + + /* Wait for 2s. */ + wait_for_three_cores(marie->lc, pauline->lc, laure->lc, 2000); + + CU_ASSERT_EQUAL(linphone_core_get_calls_nb(marie->lc), 2); + if (linphone_core_get_calls_nb(marie->lc) == 2) { + calls_list = linphone_core_get_calls(marie->lc); + call = (LinphoneCall *)ms_list_nth_data(calls_list, 0); + CU_ASSERT_PTR_NOT_NULL(call); + if (call != NULL) { + LinphoneCallParams *params = linphone_call_params_copy(linphone_call_get_current_params(call)); + linphone_call_params_set_audio_direction(params, LinphoneMediaDirectionSendRecv); + linphone_call_params_set_video_direction(params, LinphoneMediaDirectionSendRecv); + linphone_core_accept_call_with_params(marie->lc, call, params); + + /* Wait for 5s. */ + wait_for_three_cores(marie->lc, pauline->lc, laure->lc, 5000); + } + } + + linphone_core_terminate_all_calls(marie->lc); + CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallEnd, 1)); + 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_LinphoneCallReleased, 1)); + CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallReleased, 1)); + CU_ASSERT_TRUE(wait_for(marie->lc, laure->lc, &marie->stat.number_of_LinphoneCallEnd, 1)); + CU_ASSERT_TRUE(wait_for(marie->lc, laure->lc, &laure->stat.number_of_LinphoneCallEnd, 1)); + + CU_ASSERT_EQUAL(marie->stat.number_of_video_windows_created, 2); + CU_ASSERT_EQUAL(pauline->stat.number_of_video_windows_created, 1); + CU_ASSERT_EQUAL(laure->stat.number_of_video_windows_created, 1); + + linphone_call_params_unref(marie_params); + linphone_call_params_unref(pauline_params); + linphone_call_params_unref(laure_params); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(laure); +} + +test_t video_tests[] = { + { "Early-media video during video call", early_media_video_during_video_call_test }, + { "Two incoming early-media video calls", two_incoming_early_media_video_calls_test } +}; + +test_suite_t video_test_suite = { + "Video", + NULL, + NULL, + sizeof(video_tests) / sizeof(video_tests[0]), + video_tests +}; + +#endif /* VIDEO_ENABLED */ diff --git a/tools/genapixml.py b/tools/genapixml.py index 4f834fb0c..656428b9e 100755 --- a/tools/genapixml.py +++ b/tools/genapixml.py @@ -198,15 +198,15 @@ class CClass(CObject): def __addClassMethod(self, f): name = f.name[len(self.cFunctionPrefix):] - if string.find(name, 'get_') == 0 and len(f.arguments) == 0: + if name.startswith('get_') and len(f.arguments) == 0: self.__addPropertyGetter(name[4:], f) - elif string.find(name, 'is_') == 0 and len(f.arguments) == 0 and f.returnArgument.ctype == 'bool_t': + elif name.startswith('is_') and len(f.arguments) == 0 and f.returnArgument.ctype == 'bool_t': self.__addPropertyGetter(name[3:], f) - elif string.rfind(name, '_enabled') == (len(name) - 8) and len(f.arguments) == 0 and f.returnArgument.ctype == 'bool_t': + elif name.endswith('_enabled') and len(f.arguments) == 0 and f.returnArgument.ctype == 'bool_t': self.__addPropertyGetter(name, f) - elif string.find(name, 'set_') == 0 and len(f.arguments) == 1: + elif name.startswith('set_') and len(f.arguments) == 1: self.__addPropertySetter(name[4:], f) - elif string.find(name, 'enable_') == 0 and len(f.arguments) == 1 and f.arguments[0].ctype == 'bool_t': + elif name.startswith('enable_') and len(f.arguments) == 1 and f.arguments[0].ctype == 'bool_t': self.__addPropertySetter(name[7:] + '_enabled', f) else: if not f.name in self.classMethods: @@ -214,15 +214,15 @@ class CClass(CObject): def __addInstanceMethod(self, f): name = f.name[len(self.cFunctionPrefix):] - if string.find(name, 'get_') == 0 and len(f.arguments) == 1: + if name.startswith('get_') and len(f.arguments) == 1: self.__addPropertyGetter(name[4:], f) - elif string.find(name, 'is_') == 0 and len(f.arguments) == 1 and f.returnArgument.ctype == 'bool_t': + elif name.startswith('is_') and len(f.arguments) == 1 and f.returnArgument.ctype == 'bool_t': self.__addPropertyGetter(name[3:], f) - elif string.rfind(name, '_enabled') == (len(name) - 8) and len(f.arguments) == 1 and f.returnArgument.ctype == 'bool_t': + elif name.endswith('_enabled') and len(f.arguments) == 1 and f.returnArgument.ctype == 'bool_t': self.__addPropertyGetter(name, f) - elif string.find(name, 'set_') == 0 and len(f.arguments) == 2: + elif name.startswith('set_') and len(f.arguments) == 2: self.__addPropertySetter(name[4:], f) - elif string.find(name, 'enable_') == 0 and len(f.arguments) == 2 and f.arguments[1].ctype == 'bool_t': + elif name.startswith('enable_') and len(f.arguments) == 2 and f.arguments[1].ctype == 'bool_t': self.__addPropertySetter(name[7:] + '_enabled', f) else: if not f.name in self.instanceMethods: @@ -314,12 +314,12 @@ class Project: def __discoverClasses(self): for td in self.__typedefs: - if string.find(td.definition, 'enum ') == 0: + if td.definition.startswith('enum '): for e in self.enums: if (e.associatedTypedef is None) and td.definition[5:] == e.name: e.associatedTypedef = td break - elif string.find(td.definition, 'struct ') == 0: + elif td.definition.startswith('struct '): structFound = False for st in self.__structs: if (st.associatedTypedef is None) and td.definition[7:] == st.name: @@ -333,7 +333,7 @@ class Project: st.associatedTypedef = td self.add(st) for td in self.__typedefs: - if string.find(td.definition, 'struct ') == 0: + if td.definition.startswith('struct '): for st in self.__structs: if st.associatedTypedef == td: self.add(CClass(st)) @@ -346,9 +346,18 @@ class Project: # Sort classes by length of name (longest first), so that methods are put in the right class self.classes.sort(key = lambda c: len(c.name), reverse = True) for e in self.__events: + eventAdded = False for c in self.classes: - if string.find(e.name, c.name) == 0: + if c.name.endswith('Cbs') and e.name.startswith(c.name): c.addEvent(e) + eventAdded = True + break + if not eventAdded: + for c in self.classes: + if e.name.startswith(c.name): + c.addEvent(e) + eventAdded = True + break for f in self.__functions: for c in self.classes: if c.cFunctionPrefix == f.name[0 : len(c.cFunctionPrefix)]: @@ -417,16 +426,23 @@ class Project: def __parseCTypedefMemberdef(self, node): name = node.find('./name').text definition = node.find('./definition').text - if string.find(definition, 'typedef ') == 0: + if definition.startswith('typedef '): definition = definition[8 :] - if string.rfind(name, 'Cb') == len(name) - 2: + if name.endswith('Cb'): pos = string.find(definition, "(*") 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] diff --git a/tools/python/apixml2python.py b/tools/python/apixml2python.py index 1fb37b9bb..da91429b5 100755 --- a/tools/python/apixml2python.py +++ b/tools/python/apixml2python.py @@ -23,7 +23,7 @@ import sys import xml.etree.ElementTree as ET sys.path.append(os.path.realpath(__file__)) -from apixml2python.linphone import LinphoneModule +from apixml2python.linphone import LinphoneModule, HandWrittenClassMethod, HandWrittenInstanceMethod, HandWrittenDeallocMethod, HandWrittenProperty blacklisted_classes = [ @@ -42,20 +42,14 @@ blacklisted_functions = [ 'linphone_call_log_get_remote_stats', # missing rtp_stats_t 'linphone_call_params_get_privacy', # missing LinphonePrivacyMask 'linphone_call_params_set_privacy', # missing LinphonePrivacyMask - 'linphone_chat_message_get_file_transfer_information', # missing LinphoneContent - 'linphone_chat_message_start_file_download', # to be handwritten because of callback 'linphone_chat_message_state_to_string', # There is no use to wrap this function - 'linphone_chat_room_create_file_transfer_message', # missing LinphoneContent 'linphone_core_add_listener', 'linphone_core_can_we_add_call', # private function 'linphone_core_enable_log_collection', # need to handle class properties 'linphone_core_get_audio_port_range', # to be handwritten because of result via arguments - 'linphone_core_get_sip_transports', # missing LCSipTransports - 'linphone_core_get_sip_transports_used', # missing LCSipTransports 'linphone_core_get_supported_video_sizes', # missing MSVideoSizeDef 'linphone_core_get_video_policy', # missing LinphoneVideoPolicy 'linphone_core_get_video_port_range', # to be handwritten because of result via arguments - 'linphone_core_publish', # missing LinphoneContent 'linphone_core_remove_listener', 'linphone_core_serialize_logs', # There is no use to wrap this function 'linphone_core_set_log_collection_max_file_size', # need to handle class properties @@ -65,13 +59,6 @@ blacklisted_functions = [ 'linphone_core_set_log_handler', # Hand-written but put directly in the linphone module 'linphone_core_set_log_level', # There is no use to wrap this function 'linphone_core_set_video_policy', # missing LinphoneVideoPolicy - 'linphone_core_set_sip_transports', # missing LCSipTransports - 'linphone_core_subscribe', # missing LinphoneContent - 'linphone_event_notify', # missing LinphoneContent - 'linphone_event_send_publish', # missing LinphoneContent - 'linphone_event_send_subscribe', # missing LinphoneContent - 'linphone_event_update_publish', # missing LinphoneContent - 'linphone_event_update_subscribe', # missing LinphoneContent 'linphone_proxy_config_get_privacy', # missing LinphonePrivacyMask 'linphone_proxy_config_normalize_number', # to be handwritten because of result via arguments 'linphone_proxy_config_set_file_transfer_server', # defined but not implemented in linphone core @@ -84,11 +71,16 @@ blacklisted_functions = [ 'lp_config_section_to_dict' # missing LinphoneDictionary ] hand_written_functions = [ - 'linphone_chat_room_send_message2', - 'linphone_core_get_sound_devices', - 'linphone_core_get_video_devices', - 'linphone_core_new', - '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): diff --git a/tools/python/apixml2python/handwritten_declarations.mustache b/tools/python/apixml2python/handwritten_declarations.mustache index d5be0a3c4..4a4b2c1ef 100644 --- a/tools/python/apixml2python/handwritten_declarations.mustache +++ b/tools/python/apixml2python/handwritten_declarations.mustache @@ -1,15 +1,36 @@ +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); static PyTypeObject pylinphone_VideoSizeType; +static PyTypeObject pylinphone_SipTransportsType; typedef struct { PyObject_HEAD MSVideoSize vs; } pylinphone_VideoSizeObject; +typedef struct { + PyObject_HEAD + LCSipTransports lcst; +} pylinphone_SipTransportsObject; + int PyLinphoneVideoSize_Check(PyObject *p); MSVideoSize PyLinphoneVideoSize_AsMSVideoSize(PyObject *obj); PyObject * PyLinphoneVideoSize_FromMSVideoSize(MSVideoSize vs); + +int PyLinphoneSipTransports_Check(PyObject *p); +LCSipTransports * PyLinphoneSipTransports_AsLCSipTransports(PyObject *obj); +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); diff --git a/tools/python/apixml2python/handwritten_definitions.mustache b/tools/python/apixml2python/handwritten_definitions.mustache index 4ae90a9ac..13e27d873 100644 --- a/tools/python/apixml2python/handwritten_definitions.mustache +++ b/tools/python/apixml2python/handwritten_definitions.mustache @@ -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; @@ -201,11 +277,12 @@ static PyObject * pylinphone_Core_class_method_new(PyObject *cls, PyObject *args } Py_INCREF(_vtable_dict); self->vtable_dict = _vtable_dict; -{{#events}} +{{#core_events}} {{{event_vtable_reference}}} -{{/events}} +{{/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; @@ -243,11 +320,12 @@ static PyObject * pylinphone_Core_class_method_new_with_config(PyObject *cls, Py } Py_INCREF(_vtable_dict); self->vtable_dict = _vtable_dict; -{{#events}} +{{#core_events}} {{{event_vtable_reference}}} -{{/events}} +{{/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__); } @@ -431,6 +467,125 @@ PyObject * PyLinphoneVideoSize_FromMSVideoSize(MSVideoSize vs) { } + +static void pylinphone_SipTransports_dealloc(PyObject *self) { + pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p)", __FUNCTION__, self); + self->ob_type->tp_free(self); + pylinphone_trace(-1, "[PYLINPHONE] <<< %s", __FUNCTION__); +} + +static PyObject * pylinphone_SipTransports_new(PyTypeObject *type, PyObject *args, PyObject *kw) { + pylinphone_SipTransportsObject *self = (pylinphone_SipTransportsObject *)type->tp_alloc(type, 0); + pylinphone_trace(1, "[PYLINPHONE] >>> %s()", __FUNCTION__); + pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> %p", __FUNCTION__, self); + return (PyObject *)self; +} + +static int pylinphone_SipTransports_init(PyObject *self, PyObject *args, PyObject *kw) { + pylinphone_SipTransportsObject *sto = (pylinphone_SipTransportsObject *)self; + int udp_port; + int tcp_port; + int tls_port; + int dtls_port; + if (!PyArg_ParseTuple(args, "iiii", &udp_port, &tcp_port, &tls_port, &dtls_port)) { + return -1; + } + sto->lcst.udp_port = udp_port; + sto->lcst.tcp_port = tcp_port; + sto->lcst.tls_port = tls_port; + sto->lcst.dtls_port = dtls_port; + return 0; +} + +static PyMemberDef pylinphone_SipTransports_members[] = { + { "udp_port", T_INT, offsetof(pylinphone_SipTransportsObject, lcst) + offsetof(LCSipTransports, udp_port), 0, "[int] The port used for UDP SIP transport" }, + { "tcp_port", T_INT, offsetof(pylinphone_SipTransportsObject, lcst) + offsetof(LCSipTransports, tcp_port), 0, "[int] The port used for TCP SIP transport" }, + { "tls_port", T_INT, offsetof(pylinphone_SipTransportsObject, lcst) + offsetof(LCSipTransports, tls_port), 0, "[int] The port used for TLS SIP transport" }, + { "dtls_port", T_INT, offsetof(pylinphone_SipTransportsObject, lcst) + offsetof(LCSipTransports, dtls_port), 0, "[int] The port used for DTLS SIP transport" }, + { NULL, 0, 0, 0, NULL } /* Sentinel */ +}; + +static PyTypeObject pylinphone_SipTransportsType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "linphone.SipTransports", /* tp_name */ + sizeof(pylinphone_SipTransportsObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + pylinphone_SipTransports_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + "Object representing the SIP transports: its UDP, TCP, TLS and DTLS ports.", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + pylinphone_SipTransports_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + pylinphone_SipTransports_init, /* tp_init */ + 0, /* tp_alloc */ + pylinphone_SipTransports_new, /* tp_new */ + 0, /* tp_free */ +}; + +int PyLinphoneSipTransports_Check(PyObject *p) { + return PyObject_IsInstance(p, (PyObject *)&pylinphone_SipTransportsType); +} + +LCSipTransports * PyLinphoneSipTransports_AsLCSipTransports(PyObject *obj) { + return &((pylinphone_SipTransportsObject *)obj)->lcst; +} + +PyObject * PyLinphoneSipTransports_FromLCSipTransports(LCSipTransports lcst) { + PyObject *linphone_module; + PyObject *pyret = NULL; + PyGILState_STATE gstate; + + gstate = PyGILState_Ensure(); + linphone_module = PyImport_ImportModule("linphone.linphone"); + if (linphone_module != NULL) { + PyObject *cls = PyObject_GetAttrString(linphone_module, "SipTransports"); + if (cls != NULL) { + PyObject *args = Py_BuildValue("iiii", lcst.udp_port, lcst.tcp_port, lcst.tls_port, lcst.dtls_port); + pyret = PyEval_CallObject(cls, args); + if (pyret == NULL) { + PyErr_Print(); + } + Py_DECREF(args); + Py_DECREF(cls); + } + Py_DECREF(linphone_module); + } + PyGILState_Release(gstate); + + if (pyret == NULL) { + Py_RETURN_NONE; + } + return pyret; +} + + + time_t PyDateTime_As_time_t(PyObject *obj) { time_t ret = -1; PyObject *utctimetuple = PyObject_GetAttrString(obj, "utctimetuple"); @@ -526,3 +681,143 @@ static PyMethodDef pylinphone_PayloadTypeType_ModuleMethods[] = { /* Sentinel */ { NULL, NULL, 0, NULL } }; + + +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; + PyObject * pyresult; + PyObject * pyret; + const char *pyret_fmt; + const LinphoneContent *native_ptr; + native_ptr = pylinphone_Content_get_native_ptr(self); + if (native_ptr == NULL) { + PyErr_SetString(PyExc_TypeError, "Invalid linphone.Content instance"); + return NULL; + } + + pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p [%p])", __FUNCTION__, self, native_ptr); + cbuffer = linphone_content_get_buffer(native_ptr); + csize = linphone_content_get_size(native_ptr); + pylinphone_dispatch_messages(); + + pyresult = PyByteArray_FromStringAndSize((const char *)cbuffer, csize); + pyret = Py_BuildValue("O", pyresult); + pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> %p", __FUNCTION__, pyret); + return pyret; +} + +static int pylinphone_Content_set_buffer(PyObject *self, PyObject *value, void *closure) { + LinphoneContent *native_ptr; + void * _buffer; + size_t _size; + LinphonePresenceModel * _presence_native_ptr = NULL; + native_ptr = pylinphone_Content_get_native_ptr(self); + if (native_ptr == NULL) { + PyErr_SetString(PyExc_TypeError, "Invalid linphone.Content instance"); + return -1; + } + + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the 'buffer' attribute."); + return -1; + } + if ((value != Py_None) && !PyByteArray_Check(value)) { + PyErr_SetString(PyExc_TypeError, "The 'buffer' attribute value must be a ByteArray instance."); + return -1; + } + + _buffer = PyByteArray_AsString(value); + _size = PyByteArray_Size(value); + + pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p [%p], %p [%p])", __FUNCTION__, self, native_ptr, value, _buffer); + linphone_content_set_buffer(native_ptr, _buffer, _size); + pylinphone_dispatch_messages(); + pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> 0", __FUNCTION__); + return 0; +} diff --git a/tools/python/apixml2python/linphone.py b/tools/python/apixml2python/linphone.py index e90926f25..16d726850 100644 --- a/tools/python/apixml2python/linphone.py +++ b/tools/python/apixml2python/linphone.py @@ -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,9 +26,24 @@ def strip_leading_linphone(s): else: return s -def compute_event_name(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') + +def compute_event_name(s, className): s = strip_leading_linphone(s) - s = s[4:-2] # Remove leading 'Core' and tailing 'Cb' + s = s[len(className):-2] # Remove leading class name and tailing 'Cb' event_name = '' first = True for l in s: @@ -38,6 +54,37 @@ def compute_event_name(s): return event_name +class HandWrittenCode: + 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, doc = ''): + HandWrittenCode.__init__(self, _class, name, [cfunction], doc) + +class HandWrittenClassMethod(HandWrittenCode): + 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, 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, doc) + self.getter_cfunction = getter_cfunction + self.setter_cfunction = setter_cfunction + + class ArgumentType: def __init__(self, basic_type, complete_type, contained_type, linphone_module): self.basic_type = basic_type @@ -45,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' @@ -62,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': @@ -98,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': @@ -109,69 +156,98 @@ 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_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' + self.cast_convert_func_result = False 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_condition = "!PyCallable_Check({arg_name})" + self.cnativefmt_str = None elif '*' in splitted_type: self.type_str = 'linphone.' + strip_leading_linphone(self.basic_type) self.use_native_pointer = True @@ -197,19 +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 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: @@ -219,10 +283,12 @@ class MethodDefinition: arg_contained_type = xml_method_arg.get('containedtype') argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self.linphone_module) self.parse_tuple_format += argument_type.fmt_str - if argument_type.fmt_str == 'O' and argument_type.use_native_pointer: + if is_callback(arg_complete_type): + body += "\tPyObject * {arg_name};\n".format(arg_name=arg_name) + 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: @@ -250,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} @@ -282,7 +346,7 @@ class MethodDefinition: argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self.linphone_module) fmt += argument_type.cfmt_str args.append(arg_name) - if argument_type.fmt_str == 'O': + if argument_type.fmt_str == 'O' and argument_type.cnativefmt_str is not None: fmt += ' [' + argument_type.cnativefmt_str + ']' if argument_type.use_native_pointer: args.append(arg_name + '_native_ptr') @@ -304,21 +368,25 @@ 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) - if self.return_type != 'void': - c_function_call_code += "cresult = " - c_function_call_code += self.method_node.get('name') + "(" - if self.self_arg is not None: - c_function_call_code += "native_ptr" - if len(arg_names) > 0: - c_function_call_code += ', ' - c_function_call_code += ', '.join(arg_names) + ");" + if is_callback(self.return_complete_type): + c_function_call_code = "pyresult = ((pylinphone_{class_name}Object *)self)->{callback_name};".format(class_name=self.class_['class_name'], callback_name=compute_event_name(self.return_complete_type, self.class_['class_name'])) + else: + if self.return_complete_type != 'void': + c_function_call_code += "cresult = " + c_function_call_code += self.method_node.get('name') + "(" + if self.self_arg is not None: + c_function_call_code += "native_ptr" + if len(arg_names) > 0: + c_function_call_code += ', ' + c_function_call_code += ', '.join(arg_names) + ");" 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': @@ -337,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): @@ -393,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 @@ -422,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') @@ -610,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) @@ -619,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."); @@ -631,24 +729,30 @@ 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 = '' - 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): + callback_setting_code = '' + if is_callback(self.first_argument_type.complete_type): + callback_setting_code = \ +"""Py_XDECREF(((pylinphone_{class_name}Object *)self)->{callback_name}); + 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_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 = \ @@ -667,18 +771,25 @@ class SetterMethodDefinition(MethodDefinition): }} {attribute_type_check_code} {attribute_conversion_code} + {callback_setting_code} {attribute_native_ptr_check_code} """.format(attribute_name=self.attribute_name, native_ptr_check_code=self.format_class_native_pointer_check(True), attribute_type_check_code=attribute_type_check_code, attribute_conversion_code=attribute_conversion_code, + callback_setting_code=callback_setting_code, attribute_native_ptr_check_code=attribute_native_ptr_check_code) def format_c_function_call(self): + if is_callback(self.first_argument_type.complete_type): + return \ +""" {method_name}(native_ptr, pylinphone_{class_name}_callback_{callback_name}); + pylinphone_dispatch_messages(); +""".format(method_name=self.method_node.get('name'), class_name=self.class_['class_name'], callback_name=compute_event_name(self.first_argument_type.complete_type, self.class_['class_name'])) 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}); @@ -709,11 +820,20 @@ class EventCallbackMethodDefinition(MethodDefinition): MethodDefinition.__init__(self, linphone_module, class_, method_node) def format_local_variables_definition(self): + class_name = self.class_['event_class'] + 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_CoreObject *pylc = (pylinphone_CoreObject *)linphone_core_get_user_data(lc); +""" pylinphone_{class_name}Object *pyself = (pylinphone_{class_name}Object *){function_prefix}get_user_data(self); PyObject *func; PyObject *args; - PyGILState_STATE pygil_state;""" + PyGILState_STATE pygil_state;""".format(class_name=nocallbacks_class_name, function_prefix=self.find_class_definition(nocallbacks_class_name)['class_c_function_prefix']) + if class_name.endswith('Cbs'): + common += """ + pylinphone_{class_name}Object *pycbs = (pylinphone_{class_name}Object *){cbs_function_prefix}get_user_data({function_prefix}get_callbacks(self)); +""".format(class_name=class_name, cbs_function_prefix=self.find_class_definition(class_name)['class_c_function_prefix'], function_prefix=self.find_class_definition(nocallbacks_class_name)['class_c_function_prefix']) specific = '' for xml_method_arg in self.xml_method_args: arg_name = xml_method_arg.get('name') @@ -723,18 +843,30 @@ 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 \ -""" if (Py_REFCNT(pylc) <= 0) return; - func = PyDict_GetItemString(pylc->vtable_dict, "{name}"); + 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 {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 {return_str}; + func = pycbs->{event_name}; + pygil_state = PyGILState_Ensure(); +""".format(event_name=self.class_['event_name'], return_str=return_str) def format_enter_trace(self): fmt = '%p' - args = ['lc'] + args = ['self'] for xml_method_arg in self.xml_method_args: arg_name = xml_method_arg.get('name') arg_type = xml_method_arg.get('type') @@ -752,8 +884,9 @@ class EventCallbackMethodDefinition(MethodDefinition): def format_c_function_call(self): create_python_objects_code = '' + convert_python_result_code = '' fmt = 'O' - args = ['pylc'] + args = ['pyself'] for xml_method_arg in self.xml_method_args: arg_name = xml_method_arg.get('name') arg_type = xml_method_arg.get('type') @@ -772,46 +905,84 @@ 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) - arguments = ['LinphoneCore * lc'] + class_name = self.class_['event_class'] + nocallbacks_class_name = class_name + if class_name.endswith('Cbs'): + nocallbacks_class_name = class_name[:-3] + arguments = ['Linphone' + nocallbacks_class_name + ' * self'] for xml_method_arg in self.xml_method_args: arg_name = xml_method_arg.get('name') arg_type = xml_method_arg.get('type') arg_complete_type = xml_method_arg.get('completetype') arguments.append(arg_complete_type + ' ' + arg_name) definition = \ -"""static void pylinphone_Core_callback_{event_name}({arguments}) {{ +"""static {returntype} pylinphone_{class_name}_callback_{event_name}({arguments}) {{ {body} }} -""".format(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 class LinphoneModule(object): - def __init__(self, tree, blacklisted_classes, blacklisted_events, blacklisted_functions, hand_written_functions): + def __init__(self, tree, blacklisted_classes, blacklisted_events, blacklisted_functions, hand_written_codes): self.internal_instance_method_names = ['destroy', 'ref', 'unref'] self.internal_property_names = ['user_data'] 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 xml_enums = tree.findall("./enums/enum") for xml_enum in xml_enums: if xml_enum.get('deprecated') == 'true': @@ -819,22 +990,39 @@ 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']) - self.events = [] + self.core_events = [] self.classes = [] xml_classes = tree.findall("./classes/class") for xml_class in xml_classes: @@ -857,21 +1045,55 @@ class LinphoneModule(object): c['class_hand_written_properties'] = [] c['class_object_members'] = [] c['class_object_members_code'] = '' + c['class_events'] = [] if c['class_name'] == 'Core': c['class_object_members'].append("vtable_dict") c['class_object_members_code'] = "\tPyObject *vtable_dict;" - xml_events = xml_class.findall("./events/event") - for xml_event in xml_events: - if xml_event.get('deprecated') == 'true': + xml_events = xml_class.findall("./events/event") + for xml_event in xml_events: + if xml_event.get('deprecated') == 'true': + continue + if xml_event.get('name') in blacklisted_events: continue - if xml_event.get('name') in blacklisted_events: - continue - ev = {} - ev['event_xml_node'] = xml_event - ev['event_cname'] = xml_event.get('name') - ev['event_name'] = compute_event_name(ev['event_cname']) - ev['event_doc'] = self.__format_doc(xml_event.find('briefdescription'), xml_event.find('detaileddescription')) - self.events.append(ev) + ev = {} + ev['event_class'] = c['class_name'] + ev['event_xml_node'] = xml_event + ev['event_cname'] = xml_event.get('name') + ev['event_name'] = compute_event_name(ev['event_cname'], c['class_name']) + ev['event_doc'] = self.__format_doc(xml_event.find('briefdescription'), xml_event.find('detaileddescription')) + if c['class_name'] == 'Core': + self.core_events.append(ev) + else: + c['class_events'].append(ev) + c['class_object_members'].append(ev['event_name']) + c['class_object_members_code'] += "\tPyObject *" + ev['event_name'] + ";\n" + for hand_written_code in hand_written_codes: + if hand_written_code._class == c['class_name']: + 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 + if hand_written_code.getter_cfunction is None: + p['getter_reference'] = 'NULL' + else: + p['getter_reference'] = '(getter)pylinphone_' + c['class_name'] + '_get_' + p['property_name'] + if hand_written_code.setter_cfunction is None: + 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: if xml_type_method.get('deprecated') == 'true': @@ -881,10 +1103,9 @@ class LinphoneModule(object): continue m = {} m['method_name'] = method_name.replace(c['class_c_function_prefix'], '') - if method_name in hand_written_functions: - c['class_type_hand_written_methods'].append(m) - else: + 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") @@ -898,10 +1119,9 @@ class LinphoneModule(object): continue m = {} m['method_name'] = method_name.replace(c['class_c_function_prefix'], '') - if method_name in hand_written_functions: - c['class_instance_hand_written_methods'].append(m) - else: + 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") @@ -915,50 +1135,41 @@ class LinphoneModule(object): p['property_name'] = property_name xml_property_getter = xml_property.find("./getter") xml_property_setter = xml_property.find("./setter") - handwritten_property = False if xml_property_getter is not None: - if xml_property_getter.get('name') in blacklisted_functions or xml_property_getter.get('deprecated') == 'true': + if xml_property_getter.get('name') in blacklisted_functions or xml_property_getter.get('name') in hand_written_functions or xml_property_getter.get('deprecated') == 'true': continue - elif xml_property_getter.get('name') in hand_written_functions: - handwritten_property = True if xml_property_setter is not None: - if xml_property_setter.get('name') in blacklisted_functions or xml_property_setter.get('deprecated') == 'true': + if xml_property_setter.get('name') in blacklisted_functions or xml_property_setter.get('name') in hand_written_functions or xml_property_setter.get('deprecated') == 'true': continue - elif xml_property_setter.get('name') in hand_written_functions: - handwritten_property = True - if handwritten_property: - p['getter_reference'] = 'NULL' - p['setter_reference'] = 'NULL' - if xml_property_getter is not None: - p['getter_reference'] = '(getter)pylinphone_' + c['class_name'] + '_get_' + p['property_name'] - if xml_property_setter is not None: - p['setter_reference'] = '(setter)pylinphone_' + c['class_name'] + '_set_' + p['property_name'] - c['class_hand_written_properties'].append(p) + if xml_property_getter is not None: + xml_property_getter.set('property_name', property_name) + p['getter_name'] = xml_property_getter.get('name').replace(c['class_c_function_prefix'], '') + p['getter_xml_node'] = xml_property_getter + 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: - if xml_property_getter is not None: - xml_property_getter.set('property_name', property_name) - p['getter_name'] = xml_property_getter.get('name').replace(c['class_c_function_prefix'], '') - p['getter_xml_node'] = xml_property_getter - 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'] = "}" - else: - p['getter_reference'] = "NULL" - if xml_property_setter is not None: - xml_property_setter.set('property_name', property_name) - p['setter_name'] = xml_property_setter.get('name').replace(c['class_c_function_prefix'], '') - p['setter_xml_node'] = xml_property_setter - 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'] = "}" - else: - p['setter_reference'] = "NULL" - c['class_properties'].append(p) + p['getter_reference'] = "NULL" + if xml_property_setter is not None: + xml_property_setter.set('property_name', property_name) + p['setter_name'] = xml_property_setter.get('name').replace(c['class_c_function_prefix'], '') + p['setter_xml_node'] = xml_property_setter + 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) self.classes.append(c) # Format events definitions - for ev in self.events: + for ev in self.core_events: ev['event_callback_definition'] = EventCallbackMethodDefinition(self, ev, ev['event_xml_node']).format() ev['event_vtable_reference'] = "_vtable.{name} = pylinphone_Core_callback_{name};".format(name=ev['event_name']) + for c in self.classes: + for ev in c['class_events']: + ev['event_callback_definition'] = EventCallbackMethodDefinition(self, ev, ev['event_xml_node']).format() # Format methods' bodies for c in self.classes: xml_new_method = c['class_xml_node'].find("./classmethods/classmethod[@name='" + c['class_c_function_prefix'] + "new']") @@ -1000,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: @@ -1067,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 @@ -1101,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 @@ -1112,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 @@ -1123,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 diff --git a/tools/python/apixml2python/linphone_module.mustache b/tools/python/apixml2python/linphone_module.mustache index 925902da7..403a2491a 100644 --- a/tools/python/apixml2python/linphone_module.mustache +++ b/tools/python/apixml2python/linphone_module.mustache @@ -97,9 +97,15 @@ MSList * PyList_AsMSListOf{{c_contained_type}}(PyObject *pyl) { {{/mslist_types}} -{{#events}} +{{#core_events}} {{{event_callback_definition}}} -{{/events}} +{{/core_events}} + +{{#classes}} +{{#class_events}} +{{{event_callback_definition}}} +{{/class_events}} +{{/classes}} {{#classes}} @@ -119,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}} @@ -142,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}}}" }, @@ -177,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}}}" }, @@ -279,6 +283,7 @@ PyMODINIT_FUNC initlinphone(void) { PyObject *menum; PyDateTime_IMPORT; + PyEval_InitThreads(); pylinphone_init_logging(); {{#classes}} @@ -287,6 +292,7 @@ PyMODINIT_FUNC initlinphone(void) { /* Hand-written classes. */ if (PyType_Ready(&pylinphone_VideoSizeType) < 0) return; + if (PyType_Ready(&pylinphone_SipTransportsType) < 0) return; m = Py_InitModule3("linphone", pylinphone_ModuleMethods, "Python module giving access to the Linphone library."); if (m == NULL) return; @@ -300,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; @@ -320,6 +335,8 @@ PyMODINIT_FUNC initlinphone(void) { /* Hand-written classes. */ Py_INCREF(&pylinphone_VideoSizeType); PyModule_AddObject(m, "VideoSize", (PyObject *)&pylinphone_VideoSizeType); + Py_INCREF(&pylinphone_SipTransportsType); + PyModule_AddObject(m, "SipTransports", (PyObject *)&pylinphone_SipTransportsType); pylinphone_init_testing_module(m); } diff --git a/tools/python/apixml2python/linphone_testing_module.mustache b/tools/python/apixml2python/linphone_testing_module.mustache index b68f8a558..454c81fb2 100644 --- a/tools/python/apixml2python/linphone_testing_module.mustache +++ b/tools/python/apixml2python/linphone_testing_module.mustache @@ -1,5 +1,24 @@ #include "private.h" +static PyObject * pylinphone_testing_module_method_get_random_token(PyObject *self, PyObject *args) { + PyObject *pyret; + char * cresult; + int _len; + + if (!PyArg_ParseTuple(args, "i", &_len)) { + return NULL; + } + + pylinphone_trace(1, "[PYLINPHONE] >>> %s(%d)", __FUNCTION__, _len); + cresult = sal_get_random_token(_len); + pylinphone_dispatch_messages(); + + pyret = Py_BuildValue("z", cresult); + ms_free(cresult); + pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> %p", __FUNCTION__, pyret); + return pyret; +} + static PyObject * pylinphone_testing_module_method_set_dns_user_hosts_file(PyObject *self, PyObject *args) { PyObject *_core; char *_path; @@ -28,6 +47,7 @@ static PyObject * pylinphone_testing_module_method_set_dns_user_hosts_file(PyObj } static PyMethodDef pylinphone_TestingModuleMethods[] = { + { "get_random_token", pylinphone_testing_module_method_get_random_token, METH_VARARGS, "Gets a random token of the specified length." }, { "set_dns_user_hosts_file", pylinphone_testing_module_method_set_dns_user_hosts_file, METH_VARARGS, "Allows to set a user specified hosts file." }, /* Sentinel */ { NULL, NULL, 0, NULL } diff --git a/tools/python/doc/Makefile b/tools/python/doc/Makefile index b8c40c718..158616058 100644 --- a/tools/python/doc/Makefile +++ b/tools/python/doc/Makefile @@ -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." diff --git a/tools/python/doc/generate_enums.py b/tools/python/doc/generate_enums.py new file mode 100644 index 000000000..2f24a7a93 --- /dev/null +++ b/tools/python/doc/generate_enums.py @@ -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()) diff --git a/tools/python/doc/source/_static/pylinphone.js b/tools/python/doc/source/_static/pylinphone.js new file mode 100644 index 000000000..b0b7617a0 --- /dev/null +++ b/tools/python/doc/source/_static/pylinphone.js @@ -0,0 +1,52 @@ +$(function (){ +var createList = function(selector){ + + var ul = $('