diff --git a/Makefile.am b/Makefile.am index 4aa4332f2..507e6f4dc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,7 +4,7 @@ ACLOCAL_AMFLAGS = -I m4 $(ACLOCAL_MACOS_FLAGS) SUBDIRS = build m4 pixmaps po @ORTP_DIR@ @MS2_DIR@ \ - coreapi console gtk share scripts + coreapi console gtk share scripts tools @@ -18,13 +18,13 @@ OPTIONAL_SOUNDS=\ share/sounds/linphone/rings/rock.wav -INSTALLDIR=$(shell cd $(top_builddir) && pwd)/linphone-install +INSTALLDIR=$(abs_top_builddir)/linphone-install INSTALLDIR_WITH_PREFIX=$(INSTALLDIR)/$(prefix) -ZIPFILE=$(shell cd $(top_builddir) && pwd)/$(PACKAGE)-win32-$(VERSION).zip +ZIPFILE=$(abs_top_builddir)/$(PACKAGE)-win32-$(VERSION).zip ZIP_EXCLUDED=include lib \ $(OPTIONAL_SOUNDS) -SDK_ZIPFILE=$(shell cd $(top_builddir) && pwd)/lib$(PACKAGE)-win32-$(VERSION).zip +SDK_ZIPFILE=$(abs_top_builddir)/lib$(PACKAGE)-win32-$(VERSION).zip SDK_EXCLUDED= \ bin/linphone.exe \ lib/*.la \ @@ -38,11 +38,11 @@ SDK_EXCLUDED= \ GTK_PREFIX=/ GTK_THEME=Outcrop GTK_FILELIST=gtk+-2.22.1.filelist -GTK_FILELIST_PATH=$(shell cd $(top_srcdir) && pwd)/$(GTK_FILELIST) +GTK_FILELIST_PATH=$(abs_top_srcdir)/$(GTK_FILELIST) LINPHONEDEPS_FILELIST=linphone-deps.filelist -WINBINDIST_FILES=$(shell cat $(top_srcdir)/$(LINPHONEDEPS_FILELIST)) +WINBINDIST_FILES=`cat $(abs_top_srcdir)/$(LINPHONEDEPS_FILELIST)` ISS_SCRIPT=linphone.iss -ISS_SCRIPT_PATH=$(shell cd $(top_srcdir) && pwd)/$(ISS_SCRIPT) +ISS_SCRIPT_PATH=$(abs_top_srcdir)/$(ISS_SCRIPT) #path to Inno Setup 5 compiler ISCC=ISCC.exe PACKAGE_WIN32_FILELIST=$(PACKAGE)-win32.filelist @@ -102,7 +102,7 @@ other-cherrypick: cd $(GTK_PREFIX) && \ for file in $(WINBINDIST_FILES) ; do \ if test -d $$file; then \ - mkdir -p $(INSTALLDIR_WITH_PREFIX)/$$file ;\ + $(MKDIR_P) $(INSTALLDIR_WITH_PREFIX)/$$file ;\ else \ cp $$file $(INSTALLDIR_WITH_PREFIX)/$$file ;\ fi \ @@ -119,18 +119,18 @@ gtk-cherrypick: cd $(GTK_PREFIX) && \ for file in `cat $(GTK_FILELIST_PATH)` ; do \ if test -d $$file; then \ - mkdir -p $(INSTALLDIR_WITH_PREFIX)/$$file ;\ + $(MKDIR_P) $(INSTALLDIR_WITH_PREFIX)/$$file ;\ else \ cp $$file $(INSTALLDIR_WITH_PREFIX)/$$file ;\ fi \ done && \ - mkdir -p $(INSTALLDIR_WITH_PREFIX)/share/themes && \ + $(MKDIR_P) $(INSTALLDIR_WITH_PREFIX)/share/themes && \ cp -rf share/themes/$(GTK_THEME) $(INSTALLDIR_WITH_PREFIX)/share/themes/. zip: rm -f $(ZIPFILE) rm -rf $(INSTALLDIR) - mkdir -p $(INSTALLDIR) + $(MKDIR_P) $(INSTALLDIR) make install DESTDIR=$(INSTALLDIR) #remove unwanted linphone stuff cd $(INSTALLDIR_WITH_PREFIX) && rm -rf $(ZIP_EXCLUDED) @@ -145,7 +145,7 @@ zip: sdk: rm -f $(SDK_ZIPFILE) rm -rf $(INSTALLDIR) - mkdir -p $(INSTALLDIR) + $(MKDIR_P) $(INSTALLDIR) make install DESTDIR=$(INSTALLDIR) # remove unwanted stuff (gtk interface) cd $(INSTALLDIR_WITH_PREFIX) && rm -rf $(SDK_EXCLUDED) @@ -182,12 +182,12 @@ newdate: cd gtk && $(MAKE) newdate if HAVE_MD5SUM -GEN_MD5=$(shell $(MD5SUM) linphone-$(VERSION).tar.gz | awk {'print $$4'}) +GEN_MD5=`$(MD5SUM) linphone-$(VERSION).tar.gz | awk {'print $$4'}` else -GEN_MD5=$(shell $(MD5SUM) linphone-$(VERSION).tar.gz | awk {'print $$1'}) +GEN_MD5=`$(MD5SUM) linphone-$(VERSION).tar.gz | awk {'print $$1'}` endif -Portfile: $(top_srcdir)/scripts/Portfile.tmpl dist +Portfile: $(top_srcdir)/scripts/Portfile.tmpl dist sed -e 's/\@VERSION\@/$(LINPHONE_VERSION)/g' \ -e 's/\@LINPHONE_MD5\@/$(GEN_MD5)/' < $< > $@ @@ -210,7 +210,7 @@ $(LIBICONV_HACK): bundle: $(LIBICONV_HACK) rm -rf $(INSTALLDIR) - mkdir -p $(INSTALLDIR) + $(MKDIR_P) $(INSTALLDIR) make install DESTDIR=$(INSTALLDIR) BUNDLE_PREFIX=$(BUNDLEPREFIX) \ LINPHONE_INSTALL_PREFIX=$(INSTALLDIR_WITH_PREFIX) \ diff --git a/README.macos b/README.macos index aecd2922f..1648a3135 100644 --- a/README.macos +++ b/README.macos @@ -28,7 +28,7 @@ You need: - Install zrtpcpp (optional), for unbreakable call encryption $ port install cmake $ git clone git://git.linphone.org/zrtpcpp.git - $ cd zrtpcpp && cmake -Denable_ccrtp=false . && make + $ cd zrtpcpp && cmake -Denable-ccrtp=false . && make $ sudo make install - Install gtk. It is recommended to use the quartz backend for better integration. diff --git a/build/android/common.mk b/build/android/common.mk index 4db1f6809..99e1787a7 100644 --- a/build/android/common.mk +++ b/build/android/common.mk @@ -57,13 +57,16 @@ endif LOCAL_CFLAGS += \ -D_BYTE_ORDER=_LITTLE_ENDIAN \ -DORTP_INET6 \ - -DINET6 \ - -DOSIP_MT \ + -DINET6 \ + -DOSIP_MT \ + -DHAVE_EXOSIP_GET_VERSION \ -DHAVE_EXOSIP_RESET_TRANSPORTS \ -DENABLE_TRACE \ -DLINPHONE_VERSION=\"$(LINPHONE_VERSION)\" \ -DLINPHONE_PLUGINS_DIR=\"\\tmp\" \ - -DLOG_DOMAIN=$(MY_LOG_DOMAIN) + -DLOG_DOMAIN=$(MY_LOG_DOMAIN) \ + -DHAVE_EXOSIP_TRYLOCK=1 \ + -DHAVE_EXOSIP_TLS_VERIFY_CERTIFICATE=1 LOCAL_CFLAGS += -DIN_LINPHONE @@ -74,13 +77,18 @@ LOCAL_CFLAGS += -DHAVE_X264 endif endif +ifeq ($(USE_JAVAH),1) +LOCAL_CFLAGS += -DUSE_JAVAH +endif + LOCAL_C_INCLUDES += \ $(LOCAL_PATH) \ $(LOCAL_PATH)/include \ $(LOCAL_PATH)/../oRTP/include \ $(LOCAL_PATH)/../mediastreamer2/include \ $(LOCAL_PATH)/../../externals/exosip/include \ - $(LOCAL_PATH)/../../externals/osip/include + $(LOCAL_PATH)/../../externals/osip/include \ + $(LOCAL_PATH)/../../../gen LOCAL_LDLIBS += -llog -ldl diff --git a/configure.ac b/configure.ac index 84081f46c..1005ab2f5 100644 --- a/configure.ac +++ b/configure.ac @@ -32,9 +32,9 @@ AC_MSG_NOTICE([licensed under the terms of the General Public License (GPL)]) AM_INIT_AUTOMAKE AC_SUBST([LIBTOOL_DEPS]) m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])],) +AC_SUBST([docdir], [${datadir}/doc]) AC_CONFIG_HEADER(config.h) AC_CONFIG_MACRO_DIR([m4]) -AC_SUBST([mkdir_p]) AC_ISC_POSIX AC_PROG_CC AC_PROG_CXX @@ -118,31 +118,58 @@ fi GETTEXT_PACKAGE=linphone AC_SUBST(GETTEXT_PACKAGE) -AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE",[The name of the gettext package name]) +AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE",[The name of the gettext package name]) dnl AC_CHECK_LIB(intl,libintl_gettext) AC_CHECK_FUNCS([get_current_dir_name strndup stpcpy] ) AC_ARG_ENABLE(x11, - [ --disable-x11 Disable X11 support], - [case "${enableval}" in - yes) enable_x11=true ;; - no) enable_x11=false ;; - *) AC_MSG_ERROR(bad value ${enableval} for --disable-x11) ;; - esac],[enable_x11=true]) + [AS_HELP_STRING([--disable-x11], [Disable X11 support (default=no)])], + [case "${enableval}" in + yes) enable_x11=true ;; + no) enable_x11=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-x11) ;; + esac],[enable_x11=true]) dnl conditionnal build of console interface. AC_ARG_ENABLE(console_ui, - [ --enable-console_ui=[yes/no] Turn on or off compilation of console interface [default=yes]], + [AS_HELP_STRING([--enable-console_ui=[yes/no]], [Turn on or off compilation of console interface (default=yes)])], [case "${enableval}" in yes) console_ui=true ;; no) console_ui=false ;; *) AC_MSG_ERROR(bad value ${enableval} for --enable-console_ui) ;; esac],[console_ui=true]) +dnl conditionnal build of tools. +AC_ARG_ENABLE(tools, + [AS_HELP_STRING([--enable-tools=[yes/no]], [Turn on or off compilation of console interface (default=yes)])], + [case "${enableval}" in + yes) build_tools=true ;; + no) build_tools=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-tools) ;; + esac],[build_tools=check]) + +dnl check libxml2 (needed for tools) +if test "$build_tools" != "false" ; then + PKG_CHECK_MODULES(LIBXML2, [libxml-2.0],[], + [ + if test "$build_tools" = "true" ; then + AC_MSG_ERROR([Could not found libxml2, tools cannot be compiled.]) + else + build_tools=false + fi + ]) +fi + +AM_CONDITIONAL(BUILD_TOOLS, test x$build_tools != xfalse) +if test "$build_tools" != "false" ; then + build_tools=true + AC_DEFINE(BUILD_TOOLS, 1, [Define if tools enabled] ) +fi + dnl conditionnal build of gtk interface. AC_ARG_ENABLE(gtk_ui, - [ --enable-gtk_ui=[yes/no] Turn on or off compilation of gtk interface [default=yes]], + [AS_HELP_STRING([--enable-gtk_ui=[yes/no]], [Turn on or off compilation of gtk interface (default=yes)])], [case "${enableval}" in yes) gtk_ui=true ;; no) gtk_ui=false ;; @@ -160,12 +187,12 @@ else fi AC_ARG_ENABLE(notify, - [ --enable-notify=[yes/no] Enable libnotify support [default=yes]], - [case "${enableval}" in - yes) notify=true ;; - no) notify=false ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-notify) ;; - esac],[notify=true]) + [AS_HELP_STRING([--enable-notify=[yes/no]], [Enable libnotify support (default=yes)])], + [case "${enableval}" in + yes) notify=true ;; + no) notify=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-notify) ;; + esac],[notify=true]) dnl conditionnal build of the notify library if test "$gtk_ui" = "true" ; then @@ -205,14 +232,14 @@ case "$host_cpu" in ;; esac -AC_ARG_WITH( configdir, - [ --with-configdir Set a APPDATA subdir where linphone is supposed to find its config (windows only) ], +AC_ARG_WITH(configdir, + [AS_HELP_STRING([--with-configdir], [Set a APPDATA subdir where linphone is supposed to find its config (windows only)])], [ configdir=${withval}],[ configdir="Linphone" ]) AC_DEFINE_UNQUOTED(LINPHONE_CONFIG_DIR,"$configdir",[Windows appdata subdir where linphonerc can be found]) AC_ARG_ENABLE(relativeprefix, - [ --enable-relativeprefix Build a linphone that finds its resources relatively to the directory where it is installed], + [AS_HELP_STRING([--enable-relativeprefix], [Build a linphone that finds its resources relatively to the directory where it is installed])], [case "${enableval}" in yes) relativeprefix=yes ;; no) relativeprefix=no ;; @@ -220,7 +247,7 @@ AC_ARG_ENABLE(relativeprefix, esac],[relativeprefix=guess]) AC_ARG_ENABLE(date, - [ --enable-date Use build date in internal version number], + [AS_HELP_STRING([--enable-date], [Use build date in internal version number])], [case "${enableval}" in yes) use_date=yes ;; no) use_date=no ;; @@ -234,7 +261,7 @@ fi dnl enable ipv6 support AC_ARG_ENABLE(ipv6, - [ --enable-ipv6 Turn on ipv6 support], + [AS_HELP_STRING([--enable-ipv6], [Turn on ipv6 support])], [case "${enableval}" in yes) ipv6=true;; no) ipv6=false;; @@ -248,7 +275,7 @@ AC_SUBST(IPV6_CFLAGS) dnl enable timestamp support AC_ARG_ENABLE(ntp-timestamp, - [ --enable-ntp-timestamp Turn on NTP timestamping on received packet], + [AS_HELP_STRING([--enable-ntp-timestamp], [Turn on NTP timestamping on received packet])], [case "${enableval}" in yes) ntptimestamp=true;; no) ntptimestamp=false;; @@ -256,17 +283,16 @@ AC_ARG_ENABLE(ntp-timestamp, esac],[ntptimestamp=false]) AC_ARG_ENABLE(debug, - [ --enable-debug=[yes/no] enables the display of traces showing the execution of the library. [default=yes]], - [case "${enableval}" in - yes) debug_enabled=yes;; - no) debug_enabled=no;; - *) AC_MSG_ERROR("Bad value for --enable-debug");; - esac], - [debug_enabled=no]) + [AS_HELP_STRING([--enable-debug=[yes/no]], [Enables the display of traces showing the execution of the library. (default=yes)])], + [case "${enableval}" in + yes) debug_enabled=yes;; + no) debug_enabled=no;; + *) AC_MSG_ERROR("Bad value for --enable-debug");; + esac],[debug_enabled=no]) dnl enable truespeech codec support AC_ARG_ENABLE(truespeech, - [ --enable-truespeech Turn on TrueSpeech support (x86 only)], + [AS_HELP_STRING([--enable-truespeech], [Turn on TrueSpeech support (x86 only)])], [case "${enableval}" in yes) truespeech=true;; no) truespeech=false;; @@ -280,11 +306,11 @@ AC_SUBST(TRUESPEECH_CFLAGS) AM_CONDITIONAL([BUILD_TRUESPEECH], [test x$truespeech = xtrue]) AC_ARG_ENABLE(nonstandard-gsm, - [ --enable-nonstandard-gsm Enable GSM codec at nonstandard rates (11025hz, 16000hz)], + [AS_HELP_STRING([--enable-nonstandard-gsm], [Enable GSM codec at nonstandard rates (11025hz, 16000hz)])], [case "${enableval}" in yes) exotic_gsm=yes - AC_DEFINE(ENABLE_NONSTANDARD_GSM,1,[Defined when using gsm at nonstandard rates]) - ;; + AC_DEFINE(ENABLE_NONSTANDARD_GSM,1,[Defined when using gsm at nonstandard rates]) + ;; no) exotic_gsm=no ;; *) AC_MSG_ERROR(bad value ${enableval} for --enable-nonstandard-gsm) ;; esac],[exotic_gsm=no]) @@ -292,7 +318,7 @@ AC_ARG_ENABLE(nonstandard-gsm, dnl support for RSVP (by Vincent Maury) AC_ARG_ENABLE(rsvp, -[ --enable-rsvp enable support for QoS reservations.], +[AS_HELP_STRING([--enable-rsvp], [Enable support for QoS reservations.])], AC_DEFINE(VINCENT_MAURY_RSVP,1,[Tell whether RSVP support should be compiled.]) ) @@ -331,12 +357,12 @@ LP_CHECK_OSIP2 dnl conditionnal build for ssl AC_ARG_ENABLE(ssl, - [ --enable-ssl Turn on ssl support compiling. Required for sip tls. default = false], - [case "${enableval}" in - yes) build_ssl=true ;; - no) build_ssl=false ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-ssl) ;; - esac],[build_ssl=false]) + [AS_HELP_STRING([--enable-ssl], [Turn on ssl support compiling. Required for sip tls. (default=false)])], + [case "${enableval}" in + yes) build_ssl=true ;; + no) build_ssl=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-ssl) ;; + esac],[build_ssl=false]) if test "$build_ssl" = "true"; then PKG_CHECK_MODULES(OPENSSL, libssl >= 0.9.8) @@ -367,16 +393,16 @@ fi dnl conditionnal build of video support AC_ARG_ENABLE(video, - [ --enable-video Turn on video support compiling], - [case "${enableval}" in - yes) video=true ;; - no) video=false ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-video) ;; - esac],[video=true]) - + [AS_HELP_STRING([--enable-video], [Turn on video support compiling])], + [case "${enableval}" in + yes) video=true ;; + no) video=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-video) ;; + esac],[video=true]) + AC_ARG_WITH( ffmpeg, - [ --with-ffmpeg Sets the installation prefix of ffmpeg, needed for video support. [default=/usr] ], - [ ffmpegdir=${withval}],[ ffmpegdir=/usr ]) + [AS_HELP_STRING([--with-ffmpeg], [Sets the installation prefix of ffmpeg, needed for video support. (default=/usr)])], + [ ffmpegdir=${withval}],[ ffmpegdir=/usr ]) if test "$video" = "true"; then @@ -393,7 +419,7 @@ if test "$video" = "true"; then fi AC_ARG_ENABLE(alsa, - [ --enable-alsa Turn on alsa native support compiling], + [AS_HELP_STRING([--enable-alsa], [Turn on alsa native support compiling])], [case "${enableval}" in yes) alsa=true ;; no) alsa=false ;; @@ -401,7 +427,7 @@ AC_ARG_ENABLE(alsa, esac],[alsa=true]) AC_ARG_ENABLE(zrtp, - [ --enable-zrtp Turn on zrtp support ], + [AS_HELP_STRING([--enable-zrtp], [Turn on zrtp support])], [case "${enableval}" in yes) zrtp=true ;; no) zrtp=false ;; @@ -410,7 +436,7 @@ AC_ARG_ENABLE(zrtp, AC_ARG_ENABLE(portaudio, - [ --enable-portaudio Turn on portaudio native support compiling], + [AS_HELP_STRING([--enable-portaudio], [Turn on portaudio native support compiling])], [case "${enableval}" in yes) portaudio=true ;; no) portaudio=false ;; @@ -419,8 +445,10 @@ AC_ARG_ENABLE(portaudio, dnl build console if required AM_CONDITIONAL(BUILD_CONSOLE, test x$console_ui = xtrue) + dnl special things for arm-linux cross compilation toolchain AM_CONDITIONAL(ARMBUILD, test x$use_arm_toolchain = xyes) + dnl compilation of gtk user interface AM_CONDITIONAL(BUILD_GTK_UI, [test x$gtk_ui = xtrue ] ) AM_CONDITIONAL(BUILD_WIN32, test x$mingw_found = xyes ) @@ -440,7 +468,7 @@ if test "$has_sighandler_t" = "yes" ; then fi AC_ARG_ENABLE(assistant, - [ --enable-assistant Turn on assistant compiling], + [AS_HELP_STRING([--enable-assistant], [Turn on assistant compiling])], [case "${enableval}" in yes) build_wizard=true ;; no) build_wizard=false ;; @@ -449,7 +477,7 @@ AC_ARG_ENABLE(assistant, dnl check libsoup (needed for wizard) if test "$build_wizard" != "false" ; then - PKG_CHECK_MODULES(LIBSOUP, [libsoup-2.4 >= 2.26],[build_wizard=true], + PKG_CHECK_MODULES(LIBSOUP, [libsoup-2.4 >= 2.26],[], [ if test "$build_wizard" = "true" ; then AC_MSG_ERROR([Could not found libsoup, assistant cannot be compiled.]) @@ -458,11 +486,22 @@ if test "$build_wizard" != "false" ; then fi ]) fi +if test "$build_wizard" != "false" ; then + PKG_CHECK_MODULES(LIBGTKWIZARD, [gtk+-2.0 >= 2.22.0],[], + [ + if test "$build_wizard" = "true" ; then + AC_MSG_ERROR([gtk+-2.0 < 2.22.0, assistant cannot be compiled.]) + else + build_wizard=false + fi + ]) +fi AC_SUBST(LIBSOUP_CFLAGS) AC_SUBST(LIBSOUP_LIBS) -AM_CONDITIONAL(BUILD_WIZARD, test x$build_wizard = xtrue) -if test "$build_wizard" = "true" ; then - AC_DEFINE( BUILD_WIZARD, 1, [Define if wizard enabled] ) +AM_CONDITIONAL(BUILD_WIZARD, test x$build_wizard != xfalse) +if test "$build_wizard" != "false" ; then + build_wizard=true + AC_DEFINE(BUILD_WIZARD, 1, [Define if wizard enabled] ) fi AC_CHECK_HEADERS(libudev.h) @@ -520,7 +559,7 @@ AC_SUBST([MS2_DIR]) AC_ARG_ENABLE(tunnel, - [ --enable-tunnel=[yes/no] Turn on compilation of tunnel support [default=no]], + [AS_HELP_STRING([--enable-tunnel=[yes/no]], [Turn on compilation of tunnel support (default=no)])], [case "${enableval}" in yes) enable_tunnel=true ;; no) enable_tunnel=false ;; @@ -564,7 +603,7 @@ LINPHONE_PLUGINS_DIR="${package_prefix}/lib/liblinphone/plugins" AC_SUBST(LINPHONE_PLUGINS_DIR) AC_ARG_ENABLE(external-ortp, - [ --enable-external-ortp Use external oRTP library], + [AS_HELP_STRING([--enable-external-ortp], [Use external oRTP library])], [case "${enableval}" in yes) external_ortp=true ;; no) external_ortp=false ;; @@ -595,7 +634,7 @@ AC_SUBST([ORTP_VERSION]) AC_SUBST([ORTP_DIR]) AC_ARG_ENABLE(tests_enabled, - [ --disable-tests Disable compilation of tests], + [AS_HELP_STRING([--disable-tests], [Disable compilation of tests])], [case "${enableval}" in yes) tests_enabled=true ;; no) tests_enabled=false ;; @@ -632,9 +671,11 @@ share/fr/Makefile share/it/Makefile share/ja/Makefile share/cs/Makefile +share/xml/Makefile share/linphone.pc share/linphone.desktop scripts/Makefile +tools/Makefile linphone.spec linphone.iss ]) @@ -647,6 +688,7 @@ printf "* Video support\t\t\t%s\n" $video printf "* GTK interface\t\t\t%s\n" $gtk_ui printf "* Account assistant\t\t%s\n" $build_wizard printf "* Console interface\t\t%s\n" $console_ui +printf "* Tools\t\t\t\t%s\n" $build_tools printf "* zRTP encryption (GPLv3)\t%s\n" $zrtp if test "$enable_tunnel" = "true" ; then @@ -654,4 +696,3 @@ if test "$enable_tunnel" = "true" ; then fi echo "Now type 'make' to compile, and then 'make install' as root to install it." - diff --git a/console/Makefile.am b/console/Makefile.am index bbc310967..23a7635d1 100644 --- a/console/Makefile.am +++ b/console/Makefile.am @@ -1,25 +1,32 @@ ## Process this file with automake to produce Makefile.in -COMMON_CFLAGS=$(STRICT_OPTIONS) -DIN_LINPHONE -DENABLE_TRACE -D_ORTP_SOURCE $(VIDEO_CFLAGS) $(READLINE_CFLAGS) $(OSIP_CFLAGS) +AM_CPPFLAGS=\ + -I$(top_srcdir) \ + -I$(top_srcdir)/coreapi \ + -I$(top_srcdir)/exosip + +COMMON_CFLAGS=\ + -DIN_LINPHONE \ + -DENABLE_TRACE \ + -D_ORTP_SOURCE \ + $(STRICT_OPTIONS) \ + $(VIDEO_CFLAGS) \ + $(READLINE_CFLAGS) \ + $(OSIP_CFLAGS) \ + $(ORTP_CFLAGS) \ + $(MEDIASTREAMER_CFLAGS) if BUILD_CONSOLE -INCLUDES = \ - -I$(top_srcdir)\ - -I$(top_srcdir)/coreapi\ - $(ORTP_CFLAGS) \ - -I$(top_srcdir)/exosip \ - $(MEDIASTREAMER_CFLAGS) - -bin_PROGRAMS = linphonec linphonecsh +bin_PROGRAMS=linphonec linphonecsh if BUILD_WIN32 -bin_PROGRAMS += linphoned +bin_PROGRAMS+=linphoned endif -linphonec_SOURCES = linphonec.c linphonec.h commands.c +linphonec_SOURCES=linphonec.c linphonec.h commands.c linphonec_CFLAGS=$(COMMON_CFLAGS) $(CONSOLE_FLAGS) -linphonec_LDADD = $(top_builddir)/coreapi/liblinphone.la $(READLINE_LIBS) \ +linphonec_LDADD=$(top_builddir)/coreapi/liblinphone.la $(READLINE_LIBS) \ $(MEDIASTREAMER_LIBS) \ $(ORTP_LIBS) \ $(SPEEX_LIBS) \ @@ -28,15 +35,15 @@ linphonec_LDADD = $(top_builddir)/coreapi/liblinphone.la $(READLINE_LIBS) \ if BUILD_WIN32 #special build of linphonec to detach from the windows console -linphoned_SOURCES = $(linphonec_SOURCES) +linphoned_SOURCES=$(linphonec_SOURCES) linphoned_CFLAGS=$(COMMON_CFLAGS) $(GUI_FLAGS) linphoned_LDADD=$(linphonec_LDADD) endif -linphonecsh_SOURCES = shell.c -linphonecsh_CFLAGS = $(CONSOLE_FLAGS) -linphonecsh_LDADD = $(ORTP_LIBS) +linphonecsh_SOURCES=shell.c +linphonecsh_CFLAGS=$(COMMON_CFLAGS) $(CONSOLE_FLAGS) +linphonecsh_LDADD=$(ORTP_LIBS) endif diff --git a/coreapi/.gitignore b/coreapi/.gitignore index c5d084fa6..81d1b7647 100644 --- a/coreapi/.gitignore +++ b/coreapi/.gitignore @@ -5,3 +5,4 @@ Makefile.in *.lo *.la *.loT +liblinphone_gitversion.h diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index c706751ac..790612cab 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -1,7 +1,17 @@ +GITVERSION_FILE=liblinphone_gitversion.h +GITVERSION_FILE_TMP=liblinphone_gitversion.h.tmp +GITDESCRIBE=`git describe` +GITREVISION=`git rev-parse HEAD` + +ECHO=/bin/echo SUBDIRS=. help -EXTRA_DIST=linphonecore_jni.cc +EXTRA_DIST=linphonecore_jni.cc $(GITVERSION_FILE) + +BUILT_SOURCES=$(GITVERSION_FILE) + +CLEANFILES=$(GITVERSION_FILE) ## Process this file with automake to produce Makefile.in linphone_includedir=$(includedir)/linphone @@ -12,10 +22,6 @@ if BUILD_TUNNEL linphone_include_HEADERS+=linphone_tunnel.h endif -INCLUDES = \ - -I$(top_srcdir) - - lib_LTLIBRARIES=liblinphone.la liblinphone_la_SOURCES=\ @@ -41,7 +47,8 @@ liblinphone_la_SOURCES=\ lsd.c linphonecore_utils.h \ ec-calibrator.c \ conference.c \ - linphone_tunnel.cc + linphone_tunnel.cc \ + $(GITVERSION_FILE) if BUILD_WIZARD liblinphone_la_SOURCES+=sipwizard.c @@ -78,8 +85,11 @@ test_numbers_SOURCES=test_numbers.c test_numbers_LDADD=liblinphone.la $(liblinphone_la_LIBADD) endif +AM_CPPFLAGS=\ + -I$(top_srcdir) -AM_CFLAGS=$(STRICT_OPTIONS) -DIN_LINPHONE \ +AM_CFLAGS=\ + $(STRICT_OPTIONS) -DIN_LINPHONE \ $(ORTP_CFLAGS) \ $(MEDIASTREAMER_CFLAGS) \ $(OSIP_CFLAGS) \ @@ -97,3 +107,21 @@ AM_CFLAGS+= -DBUILD_WIZARD endif AM_CXXFLAGS=$(AM_CFLAGS) + +make_gitversion_h: + if test "$(GITDESCRIBE)" != "" ; then \ + $(ECHO) -n "#define LIBLINPHONE_GIT_VERSION \"$(GITDESCRIBE)\"" > $(GITVERSION_FILE_TMP) ; \ + elif test "$(GITREVISION)" != "" ; then \ + $(ECHO) -n "#define LIBLINPHONE_GIT_VERSION \"$(LINPHONE_VERSION)_$(GITREVISION)\"" > $(GITVERSION_FILE_TMP) ; \ + else \ + $(ECHO) -n "" > $(GITVERSION_FILE_TMP) ; \ + fi + if test ! -f $(srcdir)/$(GITVERSION_FILE) ; then \ + cp -f $(GITVERSION_FILE_TMP) $(srcdir)/$(GITVERSION_FILE) ; \ + fi + if test "`cat $(GITVERSION_FILE_TMP)`" != "`cat $(srcdir)/$(GITVERSION_FILE)`" ; then \ + cp -f $(GITVERSION_FILE_TMP) $(srcdir)/$(GITVERSION_FILE) ; \ + fi + rm -f $(GITVERSION_FILE_TMP) ; + +$(GITVERSION_FILE): make_gitversion_h diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index e7f6a7b21..134c336ab 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -27,9 +27,63 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details); -static bool_t media_parameters_changed(LinphoneCall *call, SalMediaDescription *oldmd, SalMediaDescription *newmd){ - if (call->params.in_conference!=call->current_params.in_conference) return TRUE; - return !sal_media_description_equals(oldmd,newmd) || call->up_bw!=linphone_core_get_upload_bandwidth(call->core); +static int media_parameters_changed(LinphoneCall *call, SalMediaDescription *oldmd, SalMediaDescription *newmd) { + if (call->params.in_conference != call->current_params.in_conference) return SAL_MEDIA_DESCRIPTION_CHANGED; + if (call->up_bw != linphone_core_get_upload_bandwidth(call->core)) return SAL_MEDIA_DESCRIPTION_CHANGED; + return sal_media_description_equals(oldmd, newmd); +} + +void linphone_core_update_streams_destinations(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md) { + SalStreamDescription *old_audiodesc = NULL; + SalStreamDescription *old_videodesc = NULL; + SalStreamDescription *new_audiodesc = NULL; + SalStreamDescription *new_videodesc = NULL; + char *rtp_addr, *rtcp_addr; + int i; + + for (i = 0; i < old_md->nstreams; i++) { + if (old_md->streams[i].type == SalAudio) { + old_audiodesc = &old_md->streams[i]; + } else if (old_md->streams[i].type == SalVideo) { + old_videodesc = &old_md->streams[i]; + } + } + for (i = 0; i < new_md->nstreams; i++) { + if (new_md->streams[i].type == SalAudio) { + new_audiodesc = &new_md->streams[i]; + } else if (new_md->streams[i].type == SalVideo) { + new_videodesc = &new_md->streams[i]; + } + } + if (call->audiostream && new_audiodesc) { + rtp_addr = (new_audiodesc->rtp_addr[0] != '\0') ? new_audiodesc->rtp_addr : new_md->addr; + rtcp_addr = (new_audiodesc->rtcp_addr[0] != '\0') ? new_audiodesc->rtcp_addr : new_md->addr; + ms_message("Change audio stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, new_audiodesc->rtp_port, rtcp_addr, new_audiodesc->rtcp_port); + rtp_session_set_remote_addr_full(call->audiostream->session, rtp_addr, new_audiodesc->rtp_port, rtcp_addr, new_audiodesc->rtcp_port); + } +#ifdef VIDEO_ENABLED + if (call->videostream && new_videodesc) { + rtp_addr = (new_videodesc->rtp_addr[0] != '\0') ? new_videodesc->rtp_addr : new_md->addr; + rtcp_addr = (new_videodesc->rtcp_addr[0] != '\0') ? new_videodesc->rtcp_addr : new_md->addr; + ms_message("Change video stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, new_videodesc->rtp_port, rtcp_addr, new_videodesc->rtcp_port); + rtp_session_set_remote_addr_full(call->videostream->session, rtp_addr, new_videodesc->rtp_port, rtcp_addr, new_videodesc->rtcp_port); + } +#endif + + /* Copy address and port values from new_md to old_md since we will keep old_md as resultdesc */ + strcpy(old_md->addr, new_md->addr); + if (old_audiodesc && new_audiodesc) { + strcpy(old_audiodesc->rtp_addr, new_audiodesc->rtp_addr); + strcpy(old_audiodesc->rtcp_addr, new_audiodesc->rtcp_addr); + old_audiodesc->rtp_port = new_audiodesc->rtp_port; + old_audiodesc->rtcp_port = new_audiodesc->rtcp_port; + } + if (old_videodesc && new_videodesc) { + strcpy(old_videodesc->rtp_addr, new_videodesc->rtp_addr); + strcpy(old_videodesc->rtcp_addr, new_videodesc->rtcp_addr); + old_videodesc->rtp_port = new_videodesc->rtp_port; + old_videodesc->rtcp_port = new_videodesc->rtcp_port; + } } void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md){ @@ -49,7 +103,8 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia if ((call->audiostream && call->audiostream->ticker) || (call->videostream && call->videostream->ticker)){ /* we already started media: check if we really need to restart it*/ if (oldmd){ - if (!media_parameters_changed(call,oldmd,new_md) && !call->playing_ringbacktone){ + int md_changed = media_parameters_changed(call, oldmd, new_md); + if ((md_changed == SAL_MEDIA_DESCRIPTION_UNCHANGED) && !call->playing_ringbacktone) { /*as nothing has changed, keep the oldmd */ call->resultdesc=oldmd; sal_media_description_unref(new_md); @@ -66,6 +121,12 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia } ms_message("No need to restart streams, SDP is unchanged."); return; + } else if ((md_changed == SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED) && !call->playing_ringbacktone) { + call->resultdesc = oldmd; + ms_message("Network parameters have changed, update them."); + linphone_core_update_streams_destinations(lc, call, oldmd, new_md); + sal_media_description_unref(new_md); + return; }else{ ms_message("Media descriptions are different, need to restart the streams."); } @@ -718,14 +779,35 @@ static void refer_received(Sal *sal, SalOp *op, const char *referto){ } } -static void text_received(Sal *sal, const char *from, const char *msg){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal); - linphone_core_message_received(lc,from,msg,NULL); +static bool_t is_duplicate_msg(LinphoneCore *lc, const char *msg_id){ + MSList *elem=lc->last_recv_msg_ids; + MSList *tail=NULL; + int i; + bool_t is_duplicate=FALSE; + for(i=0;elem!=NULL;elem=elem->next,i++){ + if (strcmp((const char*)elem->data,msg_id)==0){ + is_duplicate=TRUE; + } + tail=elem; + } + if (!is_duplicate){ + lc->last_recv_msg_ids=ms_list_prepend(lc->last_recv_msg_ids,ms_strdup(msg_id)); + } + if (i>=10){ + ms_free(tail->data); + lc->last_recv_msg_ids=ms_list_remove_link(lc->last_recv_msg_ids,tail); + } + return is_duplicate; } -void message_external_body_received(Sal *sal, const char *from, const char *url) { + + +static void text_received(Sal *sal, const SalMessage *msg){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal); - linphone_core_message_received(lc,from,NULL,url); + if (is_duplicate_msg(lc,msg->message_id)==FALSE){ + linphone_core_message_received(lc,msg->from,msg->text,msg->url); + } } + static void notify(SalOp *op, const char *from, const char *msg){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer (op); @@ -841,7 +923,6 @@ SalCallbacks linphone_sal_callbacks={ dtmf_received, refer_received, text_received, - message_external_body_received, text_delivery_update, notify, notify_presence, diff --git a/coreapi/conference.c b/coreapi/conference.c index 5ca465254..9f1538f42 100644 --- a/coreapi/conference.c +++ b/coreapi/conference.c @@ -28,6 +28,12 @@ #include "mediastreamer2/msvolume.h" +/** + * @addtogroup conferencing + * @{ +**/ + + static int convert_conference_to_call(LinphoneCore *lc); static void conference_check_init(LinphoneConference *ctx, int samplerate){ @@ -131,6 +137,11 @@ static void add_local_endpoint(LinphoneConference *conf,LinphoneCore *lc){ } +/** + * Returns the sound volume (mic input) of the local participant of the conference. + * @param lc the linphone core + * @returns the measured input volume expressed in dbm0. + **/ float linphone_core_get_conference_local_input_volume(LinphoneCore *lc){ LinphoneConference *conf=&lc->conf_ctx; AudioStream *st=conf->local_participant; @@ -143,6 +154,16 @@ float linphone_core_get_conference_local_input_volume(LinphoneCore *lc){ return LINPHONE_VOLUME_DB_LOWEST; } +/** + * Merge a call into a conference. + * @param lc the linphone core + * @param call an established call, either in LinphoneCallStreamsRunning or LinphoneCallPaused state. + * + * If this is the first call that enters the conference, the virtual conference will be created automatically. + * If the local user was actively part of the call (ie not in paused state), then the local user is automatically entered into the conference. + * + * @returns 0 if successful, -1 otherwise. +**/ int linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *call){ LinphoneCallParams params; LinphoneConference *conf=&lc->conf_ctx; @@ -229,7 +250,18 @@ static int convert_conference_to_call(LinphoneCore *lc){ return err; } - +/** + * Remove a call from the conference. + * @param lc the linphone core + * @param call a call that has been previously merged into the conference. + * + * After removing the remote participant belonging to the supplied call, the call becomes a normal call in paused state. + * If one single remote participant is left alone in the conference after the removal, then it is + * automatically removed from the conference and put into a simple call, like before entering the conference. + * The conference's resources are then automatically destroyed. + * + * @returns 0 if successful, -1 otherwise. + **/ int linphone_core_remove_from_conference(LinphoneCore *lc, LinphoneCall *call){ char * str=linphone_call_get_remote_address_as_string(call); ms_message("Removing call %s from the conference", str); @@ -249,10 +281,21 @@ int linphone_core_remove_from_conference(LinphoneCore *lc, LinphoneCall *call){ return err; } +/** + * Indicates whether the local participant is part of the conference. + * @param lc the linphone core + * @returns TRUE if the local participant is in the conference, FALSE otherwise. +**/ bool_t linphone_core_is_in_conference(const LinphoneCore *lc){ return lc->conf_ctx.local_participant!=NULL; } +/** + * Moves the local participant out of the conference. + * @param lc the linphone core + * When the local participant is out of the conference, the remote participants can continue to talk normally. + * @returns 0 if successful, -1 otherwise. +**/ int linphone_core_leave_conference(LinphoneCore *lc){ LinphoneConference *conf=&lc->conf_ctx; if (linphone_core_is_in_conference(lc)) @@ -260,7 +303,17 @@ int linphone_core_leave_conference(LinphoneCore *lc){ return 0; } - +/** + * Moves the local participant inside the conference. + * @param lc the linphone core + * + * Makes the local participant to join the conference. + * Typically, the local participant is by default always part of the conference when joining an active call into a conference. + * However, by calling linphone_core_leave_conference() and linphone_core_enter_conference() the application can decide to temporarily + * move out and in the local participant from the conference. + * + * @returns 0 if successful, -1 otherwise +**/ int linphone_core_enter_conference(LinphoneCore *lc){ if (linphone_core_sound_resources_locked(lc)) { return -1; @@ -273,6 +326,14 @@ int linphone_core_enter_conference(LinphoneCore *lc){ return 0; } +/** + * Add all calls into a conference. + * @param lc the linphone core + * + * Merge all established calls (either in LinphoneCallStreamsRunning or LinphoneCallPaused) into a conference. + * + * @returns 0 if successful, -1 otherwise +**/ int linphone_core_add_all_to_conference(LinphoneCore *lc) { MSList *calls=lc->calls; while (calls) { @@ -286,6 +347,14 @@ int linphone_core_add_all_to_conference(LinphoneCore *lc) { return 0; } +/** + * Terminates the conference and the calls associated with it. + * @param lc the linphone core + * + * All the calls that were merged to the conference are terminated, and the conference resources are destroyed. + * + * @returns 0 if successful, -1 otherwise +**/ int linphone_core_terminate_conference(LinphoneCore *lc) { MSList *calls=lc->calls; while (calls) { @@ -298,9 +367,23 @@ int linphone_core_terminate_conference(LinphoneCore *lc) { return 0; } +/** + * Returns the number of participants to the conference, including the local participant. + * @param lc the linphone core + * + * Typically, after merging two calls into the conference, there is total of 3 participants: + * the local participant (or local user), and two remote participants that were the destinations of the two previously establised calls. + * + * @returns the number of participants to the conference +**/ int linphone_core_get_conference_size(LinphoneCore *lc) { if (lc->conf_ctx.conf == NULL) { return 0; } return ms_audio_conference_get_size(lc->conf_ctx.conf); } + +/** + * @} +**/ + diff --git a/coreapi/help/Makefile.am b/coreapi/help/Makefile.am index a68ab2f19..902d23c9c 100644 --- a/coreapi/help/Makefile.am +++ b/coreapi/help/Makefile.am @@ -1,21 +1,20 @@ -EXTRA_DIST = Doxyfile.in doxygen.dox +EXTRA_DIST=Doxyfile.in doxygen.dox -SOURCES= doxygen.dox $(top_srcdir)/coreapi/help/*.c $(top_srcdir)/coreapi/*.c $(top_srcdir)/coreapi/*.h +SOURCES=doxygen.dox $(top_srcdir)/coreapi/help/*.c $(top_srcdir)/coreapi/*.c $(top_srcdir)/coreapi/*.h -#html doc +# html doc if HAVE_DOXYGEN -# doxdir & pkgdocdir are not always defined by automake -docdir=$(datadir)/doc +# docdir & pkgdocdir are not always defined by automake pkgdocdir=$(docdir)/$(PACKAGE)-$(VERSION) doc_htmldir=$(pkgdocdir)/html doc_html_DATA = $(top_builddir)/coreapi/help/doc/html/html.tar $(doc_html_DATA): $(top_builddir)/coreapi/help/doc/html/index.html - cd $( + * The application shall makes "normal" calls to several destinations (using linphone_core_invite() ), one after another. + * While initiating the second call, the first one is automatically paused. + * Then, once the second call is established, the application has the possibility to merge the two calls to form a conference where each participant + * (the local participant, the remote destination of the first call, the remote destination of the second call) can talk together. + * This must be done by adding the two calls to the conference using \link linphone_call_add_to_conference() \endlink + * + * Once merged into a conference the LinphoneCall objects representing the calls that were established remain unchanged, except that + * they are tagged as part of the conference (see \link linphone_call_is_in_conference() \endlink ). The calls in a conference are in the LinphoneCallStreamsRunning state. + * + * Only a single conference can be created: the purpose of this feature is to allow the local user to create, take part and manage the conference. + * This API is not designed to create a conference server application. + * + * Up to 10 calls can be merged into the conference, however depending on the CPU usage required for doing the encoding/decoding of the streams of each participants, + * the effective limit can be lower. + * +**/ + /** * @defgroup misc Miscenalleous: logs, version strings, config storage **/ diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 32dc9d59c..5a18a0525 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -27,7 +27,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "private.h" #include #include - +#include #include "mediastreamer2/mediastream.h" #include "mediastreamer2/msvolume.h" @@ -208,22 +208,21 @@ static void update_media_description_from_stun(SalMediaDescription *md, const St } - -static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, LinphoneCall *call, unsigned int session_id, unsigned int session_ver){ +void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call){ MSList *l; PayloadType *pt; + SalMediaDescription *old_md=call->localdesc; int i; const char *me=linphone_core_get_identity(lc); LinphoneAddress *addr=linphone_address_new(me); const char *username=linphone_address_get_username (addr); SalMediaDescription *md=sal_media_description_new(); + bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",0); - if (call->ping_time>0) { - linphone_core_adapt_to_network(lc,call->ping_time,&call->params); - } + linphone_core_adapt_to_network(lc,call->ping_time,&call->params); - md->session_id=session_id; - md->session_ver=session_ver; + md->session_id=(old_md ? old_md->session_id : (rand() & 0xfff)); + md->session_ver=(old_md ? (old_md->session_ver+1) : (rand() & 0xfff)); md->nstreams=1; strncpy(md->addr,call->localip,sizeof(md->addr)); strncpy(md->username,username,sizeof(md->username)); @@ -248,8 +247,6 @@ static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, Li pt=payload_type_clone(rtp_profile_get_payload_from_mime(&av_profile,"telephone-event")); l=ms_list_append(l,pt); md->streams[0].payloads=l; - - if (call->params.has_video){ md->nstreams++; @@ -263,15 +260,22 @@ static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, Li for(i=0; instreams; i++) { if (md->streams[i].proto == SalProtoRtpSavp) { - md->streams[i].crypto[0].tag = 1; - md->streams[i].crypto[0].algo = AES_128_SHA1_80; - if (!generate_b64_crypto_key(30, md->streams[i].crypto[0].master_key)) - md->streams[i].crypto[0].algo = 0; - md->streams[i].crypto[1].tag = 2; - md->streams[i].crypto[1].algo = AES_128_SHA1_32; - if (!generate_b64_crypto_key(30, md->streams[i].crypto[1].master_key)) - md->streams[i].crypto[1].algo = 0; - md->streams[i].crypto[2].algo = 0; + if (keep_srtp_keys && old_md && old_md->streams[i].proto==SalProtoRtpSavp){ + int j; + for(j=0;jstreams[i].crypto[j],&old_md->streams[i].crypto[j],sizeof(SalSrtpCryptoAlgo)); + } + }else{ + md->streams[i].crypto[0].tag = 1; + md->streams[i].crypto[0].algo = AES_128_SHA1_80; + if (!generate_b64_crypto_key(30, md->streams[i].crypto[0].master_key)) + md->streams[i].crypto[0].algo = 0; + md->streams[i].crypto[1].tag = 2; + md->streams[i].crypto[1].algo = AES_128_SHA1_32; + if (!generate_b64_crypto_key(30, md->streams[i].crypto[1].master_key)) + md->streams[i].crypto[1].algo = 0; + md->streams[i].crypto[2].algo = 0; + } } } update_media_description_from_stun(md,&call->ac,&call->vc); @@ -280,22 +284,8 @@ static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, Li linphone_core_update_ice_state_in_call_stats(call); } linphone_address_destroy(addr); - return md; -} - -void update_local_media_description(LinphoneCore *lc, LinphoneCall *call){ - SalMediaDescription *md=call->localdesc; - if (md== NULL) { - call->localdesc = create_local_media_description(lc,call); - } else { - call->localdesc = _create_local_media_description(lc,call,md->session_id,md->session_ver+1); - sal_media_description_unref(md); - } -} - -SalMediaDescription *create_local_media_description(LinphoneCore *lc, LinphoneCall *call){ - unsigned int id=rand() & 0xfff; - return _create_local_media_description(lc,call,id,id); + call->localdesc=md; + if (old_md) sal_media_description_unref(old_md); } static int find_port_offset(LinphoneCore *lc, SalStreamType type){ @@ -472,6 +462,7 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){ LinphoneCall *call=ms_new0(LinphoneCall,1); char *from_str; + const SalMediaDescription *md; call->dir=LinphoneCallIncoming; sal_op_set_user_pointer(op,call); @@ -494,8 +485,13 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro linphone_call_init_common(call, from, to); call->log->call_id=ms_strdup(sal_op_get_call_id(op)); /*must be known at that time*/ linphone_core_init_default_params(lc, &call->params); + md=sal_call_get_remote_media_description(op); call->params.has_video &= !!lc->video_policy.automatically_accept; - call->params.has_video &= linphone_core_media_description_contains_video_stream(sal_call_get_remote_media_description(op)); + if (md) { + // It is licit to receive an INVITE without SDP + // In this case WE chose the media parameters according to policy. + call->params.has_video &= linphone_core_media_description_contains_video_stream(md); + } switch (linphone_core_get_firewall_policy(call->core)) { case LinphonePolicyUseIce: call->ice_session = ice_session_new(); @@ -754,6 +750,11 @@ const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){ }else if (vsd){ cp->has_video=is_video_active(vsd); } + if (!cp->has_video){ + if (md->bandwidth>0 && md->bandwidth<=linphone_core_get_edge_bw(call->core)){ + cp->low_bandwidth=TRUE; + } + } return cp; } } @@ -933,9 +934,31 @@ const PayloadType* linphone_call_params_get_used_video_codec(const LinphoneCallP return cp->video_codec; } +/** + * @ingroup call_control + * Use to know if this call has been configured in low bandwidth mode. + * This mode can be automatically discovered thanks to a stun server when activate_edge_workarounds=1 in section [net] of configuration file. + * An application that would have reliable way to know network capacity may not use activate_edge_workarounds=1 but instead manually configure + * low bandwidth mode with linphone_call_params_enable_low_bandwidth(). + *
When enabled, this param may transform a call request with video in audio only mode. + * @return TRUE if low bandwidth has been configured/detected + */ bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp) { return cp->low_bandwidth; } + +/** + * @ingroup call_control + * Indicate low bandwith mode. + * Configuring a call to low bandwidth mode will result in the core to activate several settings for the call in order to ensure that bitrate usage + * is lowered to the minimum possible. Typically, ptime (packetization time) will be increased, audio codec's output bitrate will be targetted to 20kbit/s provided + * that it is achievable by the codec selected after SDP handshake. Video is automatically disabled. + * +**/ +void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t enabled){ + cp->low_bandwidth=enabled; +} + /** * Returns whether video is enabled. **/ @@ -1026,11 +1049,11 @@ static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const u ms_warning("Case is MS_VIDEO_DECODER_DECODING_ERRORS"); linphone_call_send_vfu_request(call); break; - case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED: - ms_message("First video frame decoded successfully"); - if (call->nextVideoFrameDecoded._func != NULL) - call->nextVideoFrameDecoded._func(call, call->nextVideoFrameDecoded._user_data); - break; + case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED: + ms_message("First video frame decoded successfully"); + if (call->nextVideoFrameDecoded._func != NULL) + call->nextVideoFrameDecoded._func(call, call->nextVideoFrameDecoded._user_data); + break; default: ms_warning("Unhandled event %i", event_id); break; @@ -1039,10 +1062,10 @@ static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const u #endif void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data) { - call->nextVideoFrameDecoded._func = cb; - call->nextVideoFrameDecoded._user_data = user_data; + call->nextVideoFrameDecoded._func = cb; + call->nextVideoFrameDecoded._user_data = user_data; #ifdef VIDEO_ENABLED - ms_filter_call_method_noarg(call->videostream->decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION); + ms_filter_call_method_noarg(call->videostream->decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION); #endif } @@ -1189,7 +1212,7 @@ static void parametrize_equalizer(LinphoneCore *lc, AudioStream *st){ } void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted){ - float mic_gain=lp_config_get_float(lc->config,"sound","mic_gain",1); + float mic_gain=lc->sound_conf.soft_mic_lev; float thres = 0; float recv_gain; float ng_thres=lp_config_get_float(lc->config,"sound","ng_thres",0.05); @@ -1197,7 +1220,7 @@ void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t mute int dc_removal=lp_config_get_int(lc->config,"sound","dc_removal",0); if (!muted) - audio_stream_set_mic_gain(st,mic_gain); + linphone_core_set_mic_gain_db (lc, mic_gain); else audio_stream_set_mic_gain(st,0); @@ -1231,7 +1254,7 @@ void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t mute } if (st->volrecv){ /* parameters for a limited noise-gate effect, using echo limiter threshold */ - float floorgain = 1/mic_gain; + float floorgain = 1/pow(10,(mic_gain)/10); int spk_agc=lp_config_get_int(lc->config,"sound","speaker_agc_enabled",0); ms_filter_call_method(st->volrecv, MS_VOLUME_ENABLE_AGC, &spk_agc); ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres); @@ -2089,6 +2112,10 @@ void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState stat } } +/** + * Returns true if the call is part of the conference. + * @ingroup conferencing +**/ bool_t linphone_call_is_in_conference(const LinphoneCall *call) { return call->params.in_conference; } @@ -2096,6 +2123,7 @@ bool_t linphone_call_is_in_conference(const LinphoneCall *call) { /** * Perform a zoom of the video displayed during a call. + * @param call the call. * @param zoom_factor a floating point number describing the zoom factor. A value 1.0 corresponds to no zoom applied. * @param cx a floating point number pointing the horizontal center of the zoom to be applied. This value should be between 0.0 and 1.0. * @param cy a floating point number pointing the vertical center of the zoom to be applied. This value should be between 0.0 and 1.0. @@ -2104,7 +2132,7 @@ bool_t linphone_call_is_in_conference(const LinphoneCall *call) { **/ void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy) { VideoStream* vstream = call->videostream; - if (vstream) { + if (vstream && vstream->output) { float zoom[3]; if (zoom_factor < 1) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index d96a1905b..e52fff00e 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -24,6 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "lpconfig.h" #include "private.h" +#include #include #include #include "mediastreamer2/mediastream.h" @@ -40,13 +41,25 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifdef HAVE_CONFIG_H #include "config.h" +#include "liblinphone_gitversion.h" +#else +#ifndef LIBLINPHONE_GIT_VERSION +#define LIBLINPHONE_GIT_VERSION "unknown" #endif +#endif + /*#define UNSTANDART_GSM_11K 1*/ #define ROOT_CA_FILE PACKAGE_DATA_DIR "/linphone/rootca.pem" -static const char *liblinphone_version=LIBLINPHONE_VERSION; +static const char *liblinphone_version= +#ifdef LIBLINPHONE_GIT_VERSION + LIBLINPHONE_GIT_VERSION +#else + LIBLINPHONE_VERSION +#endif +; static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime); static void linphone_core_run_hooks(LinphoneCore *lc); static void linphone_core_free_hooks(LinphoneCore *lc); @@ -413,7 +426,6 @@ static void sound_config_read(LinphoneCore *lc) int tmp; const char *tmpbuf; const char *devid; - float gain=0; #ifdef __linux /*alsadev let the user use custom alsa device within linphone*/ devid=lp_config_get_string(lc->config,"sound","alsadev",NULL); @@ -485,8 +497,8 @@ static void sound_config_read(LinphoneCore *lc) linphone_core_enable_agc(lc, lp_config_get_int(lc->config,"sound","agc",0)); - gain=lp_config_get_float(lc->config,"sound","playback_gain_db",0); - linphone_core_set_playback_gain_db (lc,gain); + linphone_core_set_playback_gain_db (lc,lp_config_get_float(lc->config,"sound","playback_gain_db",0)); + linphone_core_set_mic_gain_db (lc,lp_config_get_float(lc->config,"sound","mic_gain_db",0)); linphone_core_set_remote_ringback_tone (lc,lp_config_get_string(lc->config,"sound","ringback_tone",NULL)); @@ -515,7 +527,7 @@ static void sip_config_read(LinphoneCore *lc) sal_reuse_authorization(lc->sal, lp_config_get_int(lc->config,"sip","reuse_authorization",0)); sal_expire_old_registration_contacts(lc->sal,lp_config_get_int(lc->config,"sip","expire_old_registration_contacts",0)); - tmp=lp_config_get_int(lc->config,"sip","use_rfc2833",0); + tmp=lp_config_get_int(lc->config,"sip","use_rfc2833",1); linphone_core_set_use_rfc2833_for_dtmf(lc,tmp); ipv6=lp_config_get_int(lc->config,"sip","use_ipv6",-1); @@ -554,6 +566,8 @@ static void sip_config_read(LinphoneCore *lc) sal_set_root_ca(lc->sal, lp_config_get_string(lc->config,"sip","root_ca", ROOT_CA_FILE)); #endif linphone_core_verify_server_certificates(lc,lp_config_get_int(lc->config,"sip","verify_server_certs",TRUE)); + /*setting the dscp must be done before starting the transports, otherwise it is not taken into effect*/ + sal_set_dscp(lc->sal,linphone_core_get_sip_dscp(lc)); /*start listening on ports*/ linphone_core_set_sip_transports(lc,&tr); @@ -583,6 +597,9 @@ static void sip_config_read(LinphoneCore *lc) tmp=lp_config_get_int(lc->config,"sip","inc_timeout",30); linphone_core_set_inc_timeout(lc,tmp); + tmp=lp_config_get_int(lc->config,"sip","in_call_timeout",0); + linphone_core_set_in_call_timeout(lc,tmp); + /* get proxies config */ for(i=0;; i++){ LinphoneProxyConfig *cfg=linphone_proxy_config_new_from_config_file(lc->config,i); @@ -619,7 +636,6 @@ static void sip_config_read(LinphoneCore *lc) sal_set_keepalive_period(lc->sal,lc->sip_conf.keepalive_period); sal_use_one_matching_codec_policy(lc->sal,lp_config_get_int(lc->config,"sip","only_one_codec",0)); sal_use_double_registrations(lc->sal,lp_config_get_int(lc->config,"sip","use_double_registrations",1)); - sal_set_dscp(lc->sal,linphone_core_get_sip_dscp(lc)); sal_use_dates(lc->sal,lp_config_get_int(lc->config,"sip","put_date",0)); } @@ -1099,6 +1115,7 @@ static void misc_config_read (LinphoneCore *lc) { static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vtable, const char *config_path, const char *factory_config_path, void * userdata) { + ms_message("Initializing LinphoneCore %s", linphone_core_get_version()); memset (lc, 0, sizeof (LinphoneCore)); lc->data=userdata; lc->ringstream_autorelease=TRUE; @@ -1183,6 +1200,9 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta sal_set_user_pointer(lc->sal,lc); sal_set_callbacks(lc->sal,&linphone_sal_callbacks); + lc->network_last_check = 0; + lc->network_last_status = FALSE; + sip_setup_register_all(); sound_config_read(lc); net_config_read(lc); @@ -1651,9 +1671,10 @@ static void apply_user_agent(LinphoneCore *lc){ * * @ingroup misc **/ -void linphone_core_set_user_agent(const char *name, const char *ver){ +void linphone_core_set_user_agent(LinphoneCore *lc, const char *name, const char *ver){ strncpy(_ua_name,name,sizeof(_ua_name)-1); strncpy(_ua_version,ver,sizeof(_ua_version)); + apply_user_agent(lc); } const char *linphone_core_get_user_agent_name(void){ @@ -1794,24 +1815,22 @@ void linphone_core_enable_ipv6(LinphoneCore *lc, bool_t val){ static void monitor_network_state(LinphoneCore *lc, time_t curtime){ - static time_t last_check=0; - static bool_t last_status=FALSE; char result[LINPHONE_IPADDR_SIZE]; - bool_t new_status=last_status; + bool_t new_status=lc->network_last_status; /* only do the network up checking every five seconds */ - if (last_check==0 || (curtime-last_check)>=5){ + if (lc->network_last_check==0 || (curtime-lc->network_last_check)>=5){ linphone_core_get_local_ip_for(lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,NULL,result); if (strcmp(result,"::1")!=0 && strcmp(result,"127.0.0.1")!=0){ new_status=TRUE; }else new_status=FALSE; - last_check=curtime; - if (new_status!=last_status) { + lc->network_last_check=curtime; + if (new_status!=lc->network_last_status) { if (new_status){ ms_message("New local ip address is %s",result); } set_network_reachable(lc,new_status, curtime); - last_status=new_status; + lc->network_last_status=new_status; } } } @@ -1969,6 +1988,7 @@ void linphone_core_iterate(LinphoneCore *lc){ calls= lc->calls; while(calls!= NULL){ call = (LinphoneCall *)calls->data; + elapsed = curtime-call->start_time; /* get immediately a reference to next one in case the one we are going to examine is destroy and removed during linphone_core_start_invite() */ @@ -1985,7 +2005,6 @@ void linphone_core_iterate(LinphoneCore *lc){ linphone_core_start_invite(lc,call); } if (call->state==LinphoneCallIncomingReceived){ - elapsed=curtime-call->start_time; ms_message("incoming call ringing for %i seconds",elapsed); if (elapsed>lc->sip_conf.inc_timeout){ ms_message("incoming call timeout (%i)",lc->sip_conf.inc_timeout); @@ -1994,6 +2013,10 @@ void linphone_core_iterate(LinphoneCore *lc){ linphone_core_terminate_call(lc,call); } } + if (lc->sip_conf.in_call_timeout > 0 && elapsed>lc->sip_conf.in_call_timeout) { + ms_message("in call timeout (%i)",lc->sip_conf.in_call_timeout); + linphone_core_terminate_call(lc,call); + } } if (linphone_core_video_preview_enabled(lc)){ @@ -2268,7 +2291,7 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call){ linphone_call_init_media_streams(call); if (lc->ringstream==NULL) audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard); - call->localdesc=create_local_media_description(lc,call); + linphone_call_make_local_media_description(lc,call); if (!lc->sip_conf.sdp_200_ack){ call->media_pending=TRUE; sal_call_set_local_media_description(call->op,call->localdesc); @@ -2530,7 +2553,7 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ bool_t propose_early_media=lp_config_get_int(lc->config,"sip","incoming_calls_early_media",FALSE); const char *ringback_tone=linphone_core_get_remote_ringback_tone (lc); - call->localdesc=create_local_media_description(lc,call); + linphone_call_make_local_media_description(lc,call); sal_call_set_local_media_description(call->op,call->localdesc); md=sal_call_get_final_media_description(call->op); if (md && sal_media_description_empty(md)){ @@ -2636,7 +2659,7 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho call->videostream->ice_check_list = NULL; } call->params = *params; - update_local_media_description(lc, call); + linphone_call_make_local_media_description(lc, call); if ((call->ice_session != NULL) && !has_video && call->params.has_video) { /* Defer call update until the ICE candidates gathering process has finished. */ ms_message("Defer call update to gather ICE candidates"); @@ -2747,7 +2770,7 @@ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const } call->params.has_video &= linphone_core_media_description_contains_video_stream(sal_call_get_remote_media_description(call->op)); call->camera_active=call->params.has_video; - update_local_media_description(lc,call); + linphone_call_make_local_media_description(lc,call); if (call->ice_session != NULL) { linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(call->op)); #ifdef VIDEO_ENABLED @@ -2860,10 +2883,13 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, sal_op_set_contact(call->op,contact); if (params){ + const SalMediaDescription *md = sal_call_get_remote_media_description(call->op); call->params=*params; - call->params.has_video &= linphone_core_media_description_contains_video_stream(sal_call_get_remote_media_description(call->op)); + // There might not be a md if the INVITE was lacking an SDP + // In this case we use the parameters as is. + if (md) call->params.has_video &= linphone_core_media_description_contains_video_stream(md); call->camera_active=call->params.has_video; - update_local_media_description(lc,call); + linphone_call_make_local_media_description(lc,call); sal_call_set_local_media_description(call->op,call->localdesc); } @@ -2917,6 +2943,7 @@ static void terminate_call(LinphoneCore *lc, LinphoneCall *call){ linphone_call_stop_media_streams(call); if (lc->vtable.display_status!=NULL) lc->vtable.display_status(lc,_("Call ended") ); + linphone_call_set_state(call,LinphoneCallEnd,"Call terminated"); } int linphone_core_redirect_call(LinphoneCore *lc, LinphoneCall *call, const char *redirect_uri){ @@ -2924,7 +2951,6 @@ int linphone_core_redirect_call(LinphoneCore *lc, LinphoneCall *call, const char sal_call_decline(call->op,SalReasonRedirect,redirect_uri); call->reason=LinphoneReasonDeclined; terminate_call(lc,call); - linphone_call_set_state(call,LinphoneCallEnd,"Call terminated"); }else{ ms_error("Bad state for call redirection."); return -1; @@ -2958,8 +2984,35 @@ int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *the_call) } sal_call_terminate(call->op); terminate_call(lc,call); + return 0; +} - linphone_call_set_state(call,LinphoneCallEnd,"Call terminated"); +/** + * Decline a pending incoming call, with a reason. + * @param lc the linphone core + * @param call the LinphoneCall, must be in the IncomingReceived state. + * @param reason the reason for rejecting the call: LinphoneReasonDeclined or LinphoneReasonBusy +**/ +int linphone_core_decline_call(LinphoneCore *lc, LinphoneCall * call, LinphoneReason reason){ + SalReason sal_reason=SalReasonUnknown; + if (call->state!=LinphoneCallIncomingReceived && call->state!=LinphoneCallIncomingEarlyMedia){ + ms_error("linphone_core_decline_call(): Cannot decline a call that is in state %s",linphone_call_state_to_string(call->state)); + return -1; + } + switch(reason){ + case LinphoneReasonDeclined: + sal_reason=SalReasonDeclined; + break; + case LinphoneReasonBusy: + sal_reason=SalReasonBusy; + break; + default: + ms_error("linphone_core_decline_call(): unsupported reason %s",linphone_reason_to_string(reason)); + return -1; + break; + } + sal_call_decline(call->op,sal_reason,NULL); + terminate_call(lc,call); return 0; } @@ -3026,7 +3079,7 @@ int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call) ms_warning("Cannot pause this call, it is not active."); return -1; } - update_local_media_description(lc,call); + linphone_call_make_local_media_description(lc,call); if (call->ice_session != NULL) linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session); if (sal_media_description_has_dir(call->resultdesc,SalStreamSendRecv)){ @@ -3105,7 +3158,7 @@ int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *the_call) prevents the participants to hear it while the 200OK comes back.*/ if (call->audiostream) audio_stream_play(call->audiostream, NULL); - update_local_media_description(lc,the_call); + linphone_call_make_local_media_description(lc,the_call); if (call->ice_session != NULL) linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session); sal_call_set_local_media_description(call->op,call->localdesc); @@ -3159,6 +3212,9 @@ int linphone_core_send_publish(LinphoneCore *lc, **/ void linphone_core_set_inc_timeout(LinphoneCore *lc, int seconds){ lc->sip_conf.inc_timeout=seconds; + if (linphone_core_ready(lc)){ + lp_config_set_int(lc->config,"sip","inc_timeout",seconds); + } } /** @@ -3171,6 +3227,26 @@ int linphone_core_get_inc_timeout(LinphoneCore *lc){ return lc->sip_conf.inc_timeout; } +/** + * Set the in call timeout in seconds. + * + * @ingroup call_control + * After this timeout period, the call is automatically hangup. +**/ +void linphone_core_set_in_call_timeout(LinphoneCore *lc, int seconds){ + lc->sip_conf.in_call_timeout=seconds; +} + +/** + * Returns the in call timeout + * + * @ingroup call_control + * See linphone_core_set_in_call_timeout() for details. +**/ +int linphone_core_get_in_call_timeout(LinphoneCore *lc){ + return lc->sip_conf.in_call_timeout; +} + void linphone_core_set_presence_info(LinphoneCore *lc,int minutes_away, const char *contact, LinphoneOnlineStatus presence_mode) @@ -3239,6 +3315,40 @@ void linphone_core_set_ring_level(LinphoneCore *lc, int level){ if (sndcard) ms_snd_card_set_level(sndcard,MS_SND_CARD_PLAYBACK,level); } +/** + * Allow to control microphone level: gain in db + * + * @ingroup media_parameters +**/ +void linphone_core_set_mic_gain_db (LinphoneCore *lc, float gaindb){ + float gain=gaindb; + LinphoneCall *call=linphone_core_get_current_call (lc); + AudioStream *st; + + lc->sound_conf.soft_mic_lev=gaindb; + + if (linphone_core_ready(lc)){ + lp_config_set_float(lc->config,"sound","mic_gain_db",lc->sound_conf.soft_mic_lev); + } + + if (call==NULL || (st=call->audiostream)==NULL){ + ms_message("linphone_core_set_mic_gain_db(): no active call."); + return; + } + if (st->volrecv){ + ms_filter_call_method(st->volsend,MS_VOLUME_SET_DB_GAIN,&gain); + }else ms_warning("Could not apply gain: gain control wasn't activated."); +} + +/** + * Get microphone gain in db. + * + * @ingroup media_parameters +**/ +float linphone_core_get_mic_gain_db(LinphoneCore *lc) { + return lc->sound_conf.soft_mic_lev; +} + /** * Allow to control play level before entering sound card: gain in db * @@ -3250,6 +3360,9 @@ void linphone_core_set_playback_gain_db (LinphoneCore *lc, float gaindb){ AudioStream *st; lc->sound_conf.soft_play_lev=gaindb; + if (linphone_core_ready(lc)){ + lp_config_set_float(lc->config,"sound","playback_gain_db",lc->sound_conf.soft_play_lev); + } if (call==NULL || (st=call->audiostream)==NULL){ ms_message("linphone_core_set_playback_gain_db(): no active call."); @@ -3550,6 +3663,17 @@ void linphone_core_set_root_ca(LinphoneCore *lc,const char *path){ sal_set_root_ca(lc->sal, path); } +/** + * Gets the path to a file or folder containing trusted root CAs (PEM format) + * + * @param lc The LinphoneCore object + * + * @ingroup media_parameters +**/ +const char *linphone_core_get_root_ca(LinphoneCore *lc){ + return sal_get_root_ca(lc->sal); +} + /** * Specify whether the tls server certificate must be verified when connecting to a SIP/TLS server. **/ @@ -3650,7 +3774,7 @@ void linphone_core_mute_mic(LinphoneCore *lc, bool_t val){ } if (st!=NULL){ audio_stream_set_mic_gain(st, - (val==TRUE) ? 0 : lp_config_get_float(lc->config,"sound","mic_gain",1)); + (val==TRUE) ? 0 : pow(10,lc->sound_conf.soft_mic_lev/10)); if ( linphone_core_get_rtp_no_xmit_on_audio_mute(lc) ){ audio_stream_mute_rtp(st,val); } @@ -4014,7 +4138,7 @@ int linphone_core_set_video_device(LinphoneCore *lc, const char *id){ if (id!=NULL){ lc->video_conf.device=ms_web_cam_manager_get_cam(ms_web_cam_manager_get(),id); if (lc->video_conf.device==NULL){ - ms_warning("Could not found video device %s",id); + ms_warning("Could not find video device %s",id); } } if (lc->video_conf.device==NULL) @@ -4080,6 +4204,16 @@ int linphone_core_set_static_picture(LinphoneCore *lc, const char *path) { return 0; } +const char *linphone_core_get_static_picture(LinphoneCore *lc) { + const char *path=NULL; +#ifdef VIDEO_ENABLED + path=ms_static_image_get_default_image(); +#else + ms_warning("Video support not compiled."); +#endif + return path; +} + int linphone_core_set_static_picture_fps(LinphoneCore *lc, float fps) { #ifdef VIDEO_ENABLED VideoStream *vs = NULL; @@ -4567,6 +4701,7 @@ void sip_config_uninit(LinphoneCore *lc) lp_config_set_int(lc->config,"sip","guess_hostname",config->guess_hostname); lp_config_set_string(lc->config,"sip","contact",config->contact); lp_config_set_int(lc->config,"sip","inc_timeout",config->inc_timeout); + lp_config_set_int(lc->config,"sip","in_call_timeout",config->in_call_timeout); lp_config_set_int(lc->config,"sip","use_info",config->use_info); lp_config_set_int(lc->config,"sip","use_rfc2833",config->use_rfc2833); lp_config_set_int(lc->config,"sip","use_ipv6",config->ipv6_enabled); @@ -4635,6 +4770,8 @@ static void sound_config_uninit(LinphoneCore *lc) ms_free(config->cards); lp_config_set_string(lc->config,"sound","remote_ring",config->remote_ring); + lp_config_set_float(lc->config,"sound","playback_gain_db",config->soft_play_lev); + lp_config_set_float(lc->config,"sound","mic_gain_db",config->soft_mic_lev); if (config->local_ring) ms_free(config->local_ring); if (config->remote_ring) ms_free(config->remote_ring); @@ -4754,6 +4891,9 @@ static void linphone_core_uninit(LinphoneCore *lc) ms_list_for_each(lc->call_logs,(void (*)(void*))linphone_call_log_destroy); lc->call_logs=ms_list_free(lc->call_logs); + + ms_list_for_each(lc->last_recv_msg_ids,ms_free); + lc->last_recv_msg_ids=ms_list_free(lc->last_recv_msg_ids); linphone_core_free_payload_types(lc); ortp_exit(); @@ -4975,6 +5115,8 @@ const char *linphone_reason_to_string(LinphoneReason err){ return "User not found"; case LinphoneReasonNotAnswered: return "Not answered"; + case LinphoneReasonBusy: + return "Busy"; } return "unknown error"; } @@ -5068,6 +5210,10 @@ void linphone_core_set_zrtp_secrets_file(LinphoneCore *lc, const char* file){ lc->zrtp_secrets_cache=file ? ms_strdup(file) : NULL; } +const char *linphone_core_get_zrtp_secrets_file(LinphoneCore *lc){ + return lc->zrtp_secrets_cache; +} + const LinphoneCall* linphone_core_find_call_from_uri(LinphoneCore *lc, const char *uri) { if (uri == NULL) return NULL; MSList *calls=lc->calls; @@ -5200,8 +5346,10 @@ const char* linphone_core_get_device_identifier(const LinphoneCore *lc) { **/ void linphone_core_set_sip_dscp(LinphoneCore *lc, int dscp){ sal_set_dscp(lc->sal,dscp); - if (linphone_core_ready(lc)) + if (linphone_core_ready(lc)){ lp_config_set_int_hex(lc->config,"sip","dscp",dscp); + apply_transports(lc); + } } /** diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index ad52c559f..f1a9174c8 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -204,14 +204,9 @@ bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams bool_t linphone_call_params_local_conference_mode(const LinphoneCallParams *cp); void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int bw); void linphone_call_params_destroy(LinphoneCallParams *cp); -/** - * @ingroup call_control - * Use to know if this call has been configured in low bandwidth mode. - * This mode can be automatically discovered thanks to a stun server when activate_edge_workarounds=1 in section [net] of configuration file - *
When enabled, this param may transform a call request with video in audio only mode. - * @return TRUE if low bandwidth has been configured/detected - */ bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp); +void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t enabled); + /** * Enum describing failure reasons. * @ingroup initializing @@ -222,7 +217,8 @@ enum _LinphoneReason{ LinphoneReasonBadCredentials, /** +#ifdef USE_JAVAH +#include "linphonecore_jni.h" +#endif #include "linphonecore_utils.h" #include @@ -539,6 +542,22 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_delete(JNIEnv* env delete lcData; } +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPrimaryContact(JNIEnv* env, jobject thiz, jlong lc, jstring jdisplayname, jstring jusername) { + const char* displayname = env->GetStringUTFChars(jdisplayname, NULL); + const char* username = env->GetStringUTFChars(jusername, NULL); + + LinphoneAddress *parsed = linphone_core_get_primary_contact_parsed((LinphoneCore*)lc); + if (parsed != NULL) { + linphone_address_set_display_name(parsed, displayname); + linphone_address_set_username(parsed, username); + char *contact = linphone_address_as_string(parsed); + linphone_core_set_primary_contact((LinphoneCore*)lc, contact); + } + + env->ReleaseStringUTFChars(jdisplayname, displayname); + env->ReleaseStringUTFChars(jusername, username); +} + extern "C" void Java_org_linphone_core_LinphoneCoreImpl_clearProxyConfigs(JNIEnv* env, jobject thiz,jlong lc) { linphone_core_clear_proxy_config((LinphoneCore*)lc); } @@ -700,6 +719,13 @@ extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isNetworkStateReacha return (jboolean)linphone_core_is_network_reachable((LinphoneCore*)lc); } +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setMicrophoneGain(JNIEnv* env + ,jobject thiz + ,jlong lc + ,jfloat gain) { + linphone_core_set_mic_gain_db((LinphoneCore*)lc,gain); +} + extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPlaybackGain( JNIEnv* env ,jobject thiz ,jlong lc @@ -1268,6 +1294,11 @@ extern "C" jstring Java_org_linphone_core_LinphoneCallLogImpl_getStartDate(JNIEn jstring jvalue =env->NewStringUTF(((LinphoneCallLog*)ptr)->start_date); return jvalue; } +extern "C" jlong Java_org_linphone_core_LinphoneCallLogImpl_getTimestamp(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return static_cast (((LinphoneCallLog*)ptr)->start_date_time); +} extern "C" jint Java_org_linphone_core_LinphoneCallLogImpl_getCallDuration(JNIEnv* env ,jobject thiz ,jlong ptr) { @@ -1346,6 +1377,8 @@ extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getSenderInterarr pt = linphone_call_params_get_used_audio_codec(params); else pt = linphone_call_params_get_used_video_codec(params); + if (!pt || (pt->clock_rate == 0)) + return (jfloat)0.0; return (jfloat)((float)report_block_get_interarrival_jitter(srb) / (float)pt->clock_rate); } extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getReceiverInterarrivalJitter(JNIEnv *env, jobject thiz, jlong stats_ptr, jlong call_ptr) { @@ -1373,6 +1406,8 @@ extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getReceiverIntera pt = linphone_call_params_get_used_audio_codec(params); else pt = linphone_call_params_get_used_video_codec(params); + if (!pt || (pt->clock_rate == 0)) + return (jfloat)0.0; return (jfloat)((float)report_block_get_interarrival_jitter(rrb) / (float)pt->clock_rate); } extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getRoundTripDelay(JNIEnv *env, jobject thiz, jlong stats_ptr) { @@ -1458,6 +1493,12 @@ extern "C" jlong Java_org_linphone_core_LinphoneCallImpl_getRemoteAddress( JNIEn return (jlong)linphone_call_get_remote_address((LinphoneCall*)ptr); } +extern "C" jstring Java_org_linphone_core_LinphoneCallImpl_getRemoteUserAgent(JNIEnv *env, jobject thiz, jlong ptr) { + LinphoneCall *call = (LinphoneCall *)ptr; + jstring jvalue = env->NewStringUTF(linphone_call_get_remote_user_agent(call)); + return jvalue; +} + extern "C" jint Java_org_linphone_core_LinphoneCallImpl_getState( JNIEnv* env ,jobject thiz ,jlong ptr) { @@ -1738,6 +1779,10 @@ extern "C" jstring Java_org_linphone_core_LinphoneCoreImpl_getStunServer(JNIEnv //CallParams +extern "C" void Java_org_linphone_core_LinphoneCallImpl_enableLowBandwidth(JNIEnv *env, jobject thiz, jlong cp, jboolean enable) { + linphone_call_params_enable_low_bandwidth((LinphoneCallParams *)cp, enable); +} + extern "C" jlong Java_org_linphone_core_LinphoneCallParamsImpl_getUsedAudioCodec(JNIEnv *env, jobject thiz, jlong cp) { return (jlong)linphone_call_params_get_used_audio_codec((LinphoneCallParams *)cp); } @@ -1815,7 +1860,6 @@ extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_updateCall(JNIEnv *env, return (jint) linphone_core_update_call((LinphoneCore *)lc, (LinphoneCall *)call, (const LinphoneCallParams *)params); } - extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPreferredVideoSize(JNIEnv *env, jobject thiz, jlong lc, jint width, jint height){ MSVideoSize vsize; vsize.width = (int)width; @@ -1839,6 +1883,14 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setUploadBandwidth(JNIEn linphone_core_set_upload_bandwidth((LinphoneCore *)lc, (int) bw); } +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setUseSipInfoForDtmfs(JNIEnv *env, jobject thiz, jlong lc, jboolean use){ + linphone_core_set_use_info_for_dtmf((LinphoneCore *)lc, (bool) use); +} + +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setUseRfc2833ForDtmfs(JNIEnv *env, jobject thiz, jlong lc, jboolean use){ + linphone_core_set_use_rfc2833_for_dtmf((LinphoneCore *)lc, (bool) use); +} + extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setDownloadPtime(JNIEnv *env, jobject thiz, jlong lc, jint ptime){ linphone_core_set_download_ptime((LinphoneCore *)lc, (int) ptime); } @@ -2035,10 +2087,13 @@ extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_soundResourcesLocked // Needed by Galaxy S (can't switch to/from speaker while playing and still keep mic working) // Implemented directly in msandroid.cpp (sound filters for Android). -extern "C" void msandroid_hack_speaker_state(bool speakerOn); - -extern "C" void Java_org_linphone_LinphoneManager_hackSpeakerState(JNIEnv* env,jobject thiz,jboolean speakerOn){ - msandroid_hack_speaker_state(speakerOn); +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_forceSpeakerState(JNIEnv *env, jobject thiz, jlong ptr, jboolean speakerOn) { + LinphoneCore *lc = (LinphoneCore *)ptr; + LinphoneCall *call = linphone_core_get_current_call(lc); + if (call && call->audiostream && call->audiostream->soundread) { + bool_t on = speakerOn; + ms_filter_call_method(call->audiostream->soundread, MS_AUDIO_CAPTURE_FORCE_SPEAKER_STATE, &on); + } } // End Galaxy S hack functions @@ -2094,7 +2149,7 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_tunnelEnable(JNIEnv *env extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setUserAgent(JNIEnv *env,jobject thiz,jlong pCore, jstring name, jstring version){ const char* cname=env->GetStringUTFChars(name, NULL); const char* cversion=env->GetStringUTFChars(version, NULL); - linphone_core_set_user_agent(cname,cversion); + linphone_core_set_user_agent((LinphoneCore *)pCore,cname,cversion); env->ReleaseStringUTFChars(name, cname); env->ReleaseStringUTFChars(version, cversion); } @@ -2134,6 +2189,10 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setIncomingTimeout(JNIEn linphone_core_set_inc_timeout((LinphoneCore *)lc, timeout); } +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setInCallTimeout(JNIEnv *env, jobject thiz, jlong lc, jint timeout) { + linphone_core_set_in_call_timeout((LinphoneCore *)lc, timeout); +} + extern "C" jstring Java_org_linphone_core_LinphoneCoreImpl_getVersion(JNIEnv* env,jobject thiz,jlong ptr) { jstring jvalue =env->NewStringUTF(linphone_core_get_version()); return jvalue; diff --git a/coreapi/linphonecore_utils.h b/coreapi/linphonecore_utils.h index fadfc1a36..cc0a6f692 100644 --- a/coreapi/linphonecore_utils.h +++ b/coreapi/linphonecore_utils.h @@ -94,8 +94,14 @@ void linphone_core_remove_iterate_hook(LinphoneCore *lc, LinphoneCoreIterateHook *@return call country code or -1 if not found */ int linphone_dial_plan_lookup_ccc_from_iso(const char* iso); - - +/** + * @ingroup misc + *Function to get call country code from an e164 number, ex: +33952650121 will return 33 + *@param e164 phone number + *@return call country code or -1 if not found + */ +int linphone_dial_plan_lookup_ccc_from_e164(const char* e164); + #ifdef __cplusplus } #endif diff --git a/coreapi/lpconfig.h b/coreapi/lpconfig.h index 8f3cae0a1..8e6f92128 100644 --- a/coreapi/lpconfig.h +++ b/coreapi/lpconfig.h @@ -25,6 +25,8 @@ #ifndef LPCONFIG_H #define LPCONFIG_H +#include + /** * The LpConfig object is used to manipulate a configuration file. * diff --git a/coreapi/misc.c b/coreapi/misc.c index b9176ebd4..d75722138 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -574,21 +574,31 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ return -1; } +int linphone_core_get_edge_bw(LinphoneCore *lc){ + int edge_bw=lp_config_get_int(lc->config,"net","edge_bw",20); + return edge_bw; +} + +int linphone_core_get_edge_ptime(LinphoneCore *lc){ + int edge_ptime=lp_config_get_int(lc->config,"net","edge_ptime",100); + return edge_ptime; +} + void linphone_core_adapt_to_network(LinphoneCore *lc, int ping_time_ms, LinphoneCallParams *params){ - if (lp_config_get_int(lc->config,"net","activate_edge_workarounds",0)==1){ + if (ping_time_ms>0 && lp_config_get_int(lc->config,"net","activate_edge_workarounds",0)==1){ ms_message("Stun server ping time is %i ms",ping_time_ms); int threshold=lp_config_get_int(lc->config,"net","edge_ping_time",500); if (ping_time_ms>threshold){ - int edge_ptime=lp_config_get_int(lc->config,"net","edge_ptime",100); - int edge_bw=lp_config_get_int(lc->config,"net","edge_bw",20); - /* we are in a 2G network*/ - params->up_bw=params->down_bw=edge_bw; - params->up_ptime=params->down_ptime=edge_ptime; - params->has_video=FALSE; + /* we might be in a 2G network*/ params->low_bandwidth=TRUE; }/*else use default settings */ } + if (params->low_bandwidth){ + params->up_bw=params->down_bw=linphone_core_get_edge_bw(lc); + params->up_ptime=params->down_ptime=linphone_core_get_edge_ptime(lc); + params->has_video=FALSE; + } } diff --git a/coreapi/plugins/buddylookup/Makefile.am b/coreapi/plugins/buddylookup/Makefile.am index 27ce12578..d43666e56 100644 --- a/coreapi/plugins/buddylookup/Makefile.am +++ b/coreapi/plugins/buddylookup/Makefile.am @@ -1,10 +1,8 @@ SUBDIRS=src - - -INSTALLDIR=$(shell cd $(top_builddir) && pwd)/$(PACKAGE)-install +INSTALLDIR=$(abs_top_builddir)/$(PACKAGE)-install INSTALLDIR_WITH_PREFIX=$(INSTALLDIR)/$(prefix) -ZIPFILE=$(shell cd $(top_builddir) && pwd)/$(PACKAGE)-win32-$(VERSION).zip +ZIPFILE=$(abs_top_builddir)/$(PACKAGE)-win32-$(VERSION).zip ZIP_EXCLUDED=include PLUGIN_DEPS_PREFIX=/usr/bin PLUGIN_DEPS= libsoup-2.4-1.dll \ @@ -20,9 +18,9 @@ PLUGIN_DEPS= libsoup-2.4-1.dll \ zip: rm -f $(ZIPFILE) rm -rf $(INSTALLDIR) - mkdir -p $(INSTALLDIR) + $(MKDIR_P) $(INSTALLDIR) make install DESTDIR=$(INSTALLDIR) - mkdir -p $(INSTALLDIR_WITH_PREFIX)/bin + $(MKDIR_P) $(INSTALLDIR_WITH_PREFIX)/bin cd $(PLUGIN_DEPS_PREFIX) && \ cp -f $(PLUGIN_DEPS) $(INSTALLDIR_WITH_PREFIX)/bin/. cd $(INSTALLDIR)/$(prefix) && rm -rf $(ZIP_EXCLUDED) && \ diff --git a/coreapi/private.h b/coreapi/private.h index 07fd1c689..925a30360 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -382,6 +382,7 @@ typedef struct sip_config MSList *proxies; MSList *deleted_proxies; int inc_timeout; /*timeout after an un-answered incoming call is rejected*/ + int in_call_timeout; /*timeout after a call is hangup */ unsigned int keepalive_period; /* interval in ms between keep alive messages sent to the proxy server*/ LCSipTransports transports; bool_t use_info; @@ -436,6 +437,7 @@ typedef struct sound_config const char **cards; int latency; /* latency in samples of the current used sound device */ float soft_play_lev; /*playback gain in db.*/ + float soft_mic_lev; /*mic gain in db.*/ char rec_lev; char play_lev; char ring_lev; @@ -556,12 +558,16 @@ struct _LinphoneCore bool_t network_reachable; bool_t use_preview_window; + time_t network_last_check; + bool_t network_last_status; + bool_t ringstream_autorelease; bool_t pad[3]; int device_rotation; int max_calls; LinphoneTunnel *tunnel; char* device_id; + MSList *last_recv_msg_ids; }; LinphoneTunnel *linphone_core_tunnel_new(LinphoneCore *lc); @@ -576,10 +582,7 @@ int linphone_core_set_as_current_call(LinphoneCore *lc, LinphoneCall *call); int linphone_core_get_calls_nb(const LinphoneCore *lc); void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message); - -SalMediaDescription *create_local_media_description(LinphoneCore *lc, LinphoneCall *call); -void update_local_media_description(LinphoneCore *lc, LinphoneCall *call); - +void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call); void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md); bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, PayloadType *pt, int bandwidth_limit); @@ -636,7 +639,8 @@ void _linphone_core_codec_config_write(LinphoneCore *lc); #endif void call_logs_write_to_config_file(LinphoneCore *lc); - +int linphone_core_get_edge_bw(LinphoneCore *lc); +int linphone_core_get_edge_ptime(LinphoneCore *lc); #ifdef __cplusplus } diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 718f7b0f5..3b47af42c 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -119,7 +119,7 @@ int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char * if (addr==NULL) addr=linphone_address_new(server_addr); if (addr){ - obj->reg_proxy=linphone_address_as_string_uri_only(addr); + obj->reg_proxy=linphone_address_as_string(addr); linphone_address_destroy(addr); }else{ ms_warning("Could not parse %s",server_addr); @@ -378,16 +378,261 @@ typedef struct dial_plan{ }dial_plan_t; /* TODO: fill with information for all countries over the world*/ -static dial_plan_t const dial_plans[]={ - {"France" ,"FR" , "33" , 9 , "00" }, - {"United States" ,"US" , "1" , 10 , "011" }, - {"Turkey" ,"TR" , "90" , 10 , "00" }, - {"Switzerland" ,"XK" , "41" , 9 , "00" }, - {NULL ,NULL,"" , 0 , NULL } -}; +static dial_plan_t const dial_plans[]={ + {"Afghanistan" ,"AF" , "93" , 9 , "00" }, + {"Albania" ,"AL" , "355" , 9 , "00" }, + {"Algeria" ,"DZ" , "213" , 9 , "00" }, + {"American Samoa" ,"AS" , "1" , 10 , "011" }, + {"Andorra" ,"AD" , "376" , 6 , "00" }, + {"Angola" ,"AO" , "244" , 9 , "00" }, + {"Anguilla" ,"AI" , "1" , 10 , "011" }, + {"Antigua and Barbuda" ,"AG" , "1" , 10 , "011" }, + {"Argentina" ,"AR" , "54" , 10 , "00" }, + {"Armenia" ,"AM" , "374" , 8 , "00" }, + {"Aruba" ,"AW" , "297" , 7 , "011" }, + {"Australia" ,"AU" , "61" , 9 , "0011"}, + {"Austria" ,"AT" , "43" , 10 , "00" }, + {"Azerbaijan" ,"AZ" , "994" , 9 , "00" }, + {"Bahamas" ,"BS" , "1" , 10 , "011" }, + {"Bahrain" ,"BH" , "973" , 8 , "00" }, + {"Bangladesh" ,"BD" , "880" , 10 , "00" }, + {"Barbados" ,"BB" , "1" , 10 , "011" }, + {"Belarus" ,"BY" , "375" , 9 , "00" }, + {"Belgium" ,"BE" , "32" , 9 , "00" }, + {"Belize" ,"BZ" , "501" , 7 , "00" }, + {"Benin" ,"BJ" , "229" , 8 , "00" }, + {"Bermuda" ,"BM" , "1" , 10 , "011" }, + {"Bhutan" ,"BT" , "975" , 8 , "00" }, + {"Bolivia" ,"BO" , "591" , 8 , "00" }, + {"Bosnia and Herzegovina" ,"BA" , "387" , 8 , "00" }, + {"Botswana" ,"BW" , "267" , 8 , "00" }, + {"Brazil" ,"BR" , "55" , 10 , "00" }, + {"Brunei Darussalam" ,"BN" , "673" , 7 , "00" }, + {"Bulgaria" ,"BG" , "359" , 9 , "00" }, + {"Burkina Faso" ,"BF" , "226" , 8 , "00" }, + {"Burundi" ,"BI" , "257" , 8 , "011" }, + {"Cambodia" ,"KH" , "855" , 9 , "00" }, + {"Cameroon" ,"CM" , "237" , 8 , "00" }, + {"Canada" ,"CA" , "1" , 10 , "011" }, + {"Cape Verde" ,"CV" , "238" , 7 , "00" }, + {"Cayman Islands" ,"KY" , "1" , 10 , "011" }, + {"Central African Republic" ,"CF" , "236" , 8 , "00" }, + {"Chad" ,"TD" , "235" , 8 , "00" }, + {"Chile" ,"CL" , "56" , 9 , "00" }, + {"China" ,"CN" , "86" , 11 , "00" }, + {"Colombia" ,"CO" , "57" , 10 , "00" }, + {"Comoros" ,"KM" , "269" , 7 , "00" }, + {"Congo" ,"CG" , "242" , 9 , "00" }, + {"Congo Democratic Republic" ,"CD" , "243" , 9 , "00" }, + {"Cook Islands" ,"CK" , "682" , 5 , "00" }, + {"Costa Rica" ,"CR" , "506" , 8 , "00" }, + {"C™te d'Ivoire" ,"AD" , "225" , 8 , "00" }, + {"Croatia" ,"HR" , "385" , 9 , "00" }, + {"Cuba" ,"CU" , "53" , 8 , "119" }, + {"Cyprus" ,"CY" , "357" , 8 , "00" }, + {"Czech Republic" ,"CZ" , "420" , 9 , "00" }, + {"Denmark" ,"DK" , "45" , 8 , "00" }, + {"Djibouti" ,"DJ" , "253" , 8 , "00" }, + {"Dominica" ,"DM" , "1" , 10 , "011" }, + {"Dominican Republic" ,"DO" , "1" , 10 , "011" }, + {"Ecuador" ,"EC" , "593" , 9 , "00" }, + {"Egypt" ,"EG" , "20" , 10 , "00" }, + {"El Salvador" ,"SV" , "503" , 8 , "00" }, + {"Equatorial Guinea" ,"GQ" , "240" , 9 , "00" }, + {"Eritrea" ,"ER" , "291" , 7 , "00" }, + {"Estonia" ,"EE" , "372" , 8 , "00" }, + {"Ethiopia" ,"ET" , "251" , 9 , "00" }, + {"Falkland Islands" ,"FK" , "500" , 5 , "00" }, + {"Faroe Islands" ,"FO" , "298" , 6 , "00" }, + {"Fiji" ,"FJ" , "679" , 7 , "00" }, + {"Finland" ,"FI" , "358" , 9 , "00" }, + {"France" ,"FR" , "33" , 9 , "00" }, + {"French Guiana" ,"GF" , "594" , 9 , "00" }, + {"French Polynesia" ,"PF" , "689" , 6 , "00" }, + {"Gabon" ,"GA" , "241" , 8 , "00" }, + {"Gambia" ,"GM" , "220" , 7 , "00" }, + {"Georgia" ,"GE" , "995" , 9 , "00" }, + {"Germany" ,"DE" , "49" , 11 , "00" }, + {"Ghana" ,"GH" , "233" , 9 , "00" }, + {"Gibraltar" ,"GI" , "350" , 8 , "00" }, + {"Greece" ,"GR" , "30" ,10 , "00" }, + {"Greenland" ,"GL" , "299" , 6 , "00" }, + {"Grenada" ,"GD" , "1" , 10 , "011" }, + {"Guadeloupe" ,"GP" , "590" , 9 , "00" }, + {"Guam" ,"GU" , "1" , 10 , "011" }, + {"Guatemala" ,"GT" , "502" , 8 , "00" }, + {"Guinea" ,"GN" , "224" , 8 , "00" }, + {"Guinea-Bissau" ,"GW" , "245" , 7 , "00" }, + {"Guyana" ,"GY" , "592" , 7 , "001" }, + {"Haiti" ,"HT" , "509" , 8 , "00" }, + {"Honduras" ,"HN" , "504" , 8 , "00" }, + {"Hong Kong" ,"HK" , "852" , 8 , "001" }, + {"Hungary" ,"HU" , "36" , 9 , "00" }, + {"Iceland" ,"IS" , "354" , 9 , "00" }, + {"India" ,"IN" , "91" , 10 , "00" }, + {"Indonesia" ,"ID" , "62" , 10 , "001" }, + {"Iran" ,"IR" , "98" , 10 , "00" }, + {"Iraq" ,"IQ" , "964" , 10 , "00" }, + {"Ireland" ,"IE" , "353" , 9 , "00" }, + {"Israel" ,"IL" , "972" , 9 , "00" }, + {"Italy" ,"IT" , "39" , 10 , "00" }, + {"Jamaica" ,"JM" , "1" , 10 , "011" }, + {"Japan" ,"JP" , "81" , 10 , "010" }, + {"Jordan" ,"JO" , "962" , 9 , "00" }, + {"Kazakhstan" ,"KZ" , "7" , 10 , "00" }, + {"Kenya" ,"KE" , "254" , 9 , "000" }, + {"Kiribati" ,"KI" , "686" , 5 , "00" }, + {"Korea, North" ,"KP" , "850" , 12 , "99" }, + {"Korea, South" ,"KR" , "82" , 12 , "001" }, + {"Kuwait" ,"KW" , "965" , 8 , "00" }, + {"Kyrgyzstan" ,"KG" , "996" , 9 , "00" }, + {"Laos" ,"LA" , "856" , 10 , "00" }, + {"Latvia" ,"LV" , "371" , 8 , "00" }, + {"Lebanon" ,"LB" , "961" , 7 , "00" }, + {"Lesotho" ,"LS" , "266" , 8 , "00" }, + {"Liberia" ,"LR" , "231" , 8 , "00" }, + {"Libya" ,"LY" , "218" , 8 , "00" }, + {"Liechtenstein" ,"LI" , "423" , 7 , "00" }, + {"Lithuania" ,"LT" , "370" , 8 , "00" }, + {"Luxembourg" ,"LU" , "352" , 9 , "00" }, + {"Macau" ,"MO" , "853" , 8 , "00" }, + {"Macedonia" ,"MK" , "389" , 8 , "00" }, + {"Madagascar" ,"MG" , "261" , 9 , "00" }, + {"Malawi" ,"MW" , "265" , 9 , "00" }, + {"Malaysia" ,"MY" , "60" , 9 , "00" }, + {"Maldives" ,"MV" , "960" , 7 , "00" }, + {"Mali" ,"ML" , "223" , 8 , "00" }, + {"Malta" ,"MT" , "356" , 8 , "00" }, + {"Marshall Islands" ,"MH" , "692" , 7 , "011" }, + {"Martinique" ,"MQ" , "596" , 9 , "00" }, + {"Mauritania" ,"MR" , "222" , 8 , "00" }, + {"Mauritius" ,"MU" , "230" , 7 , "00" }, + {"Mayotte Island" ,"YT" , "262" , 9 , "00" }, + {"Mexico" ,"MX" , "52" , 10 , "00" }, + {"Micronesia" ,"FM" , "691" , 7 , "011" }, + {"Moldova" ,"MD" , "373" , 8 , "00" }, + {"Monaco" ,"MC" , "377" , 8 , "00" }, + {"Mongolia" ,"MN" , "976" , 8 , "001" }, + {"Montenegro" ,"ME" , "382" , 8 , "00" }, + {"Montserrat" ,"MS" , "664" , 10 , "011" }, + {"Morocco" ,"MA" , "212" , 9 , "00" }, + {"Mozambique" ,"MZ" , "258" , 9 , "00" }, + {"Myanmar" ,"MM" , "95" , 8 , "00" }, + {"Namibia" ,"NA" , "264" , 9 , "00" }, + {"Nauru" ,"NR" , "674" , 7 , "00" }, + {"Nepal" ,"NP" , "43" , 10 , "00" }, + {"Netherlands" ,"NL" , "31" , 9 , "00" }, + {"New Caledonia" ,"NC" , "687" , 6 , "00" }, + {"New Zealand" ,"NZ" , "64" , 10 , "00" }, + {"Nicaragua" ,"NI" , "505" , 8 , "00" }, + {"Niger" ,"NE" , "227" , 8 , "00" }, + {"Nigeria" ,"NG" , "234" , 10 , "009" }, + {"Niue" ,"NU" , "683" , 4 , "00" }, + {"Norfolk Island" ,"NF" , "672" , 5 , "00" }, + {"Northern Mariana Islands" ,"MP" , "1" , 10 , "011" }, + {"Norway" ,"NO" , "47" , 8 , "00" }, + {"Oman" ,"OM" , "968" , 8 , "00" }, + {"Pakistan" ,"PK" , "92" , 10 , "00" }, + {"Palau" ,"PW" , "680" , 7 , "011" }, + {"Palestine" ,"PS" , "970" , 9 , "00" }, + {"Panama" ,"PA" , "507" , 8 , "00" }, + {"Papua New Guinea" ,"PG" , "675" , 8 , "00" }, + {"Paraguay" ,"PY" , "595" , 9 , "00" }, + {"Peru" ,"PE" , "51" , 9 , "00" }, + {"Philippines" ,"PH" , "63" , 10 , "00" }, + {"Poland" ,"PL" , "48" , 9 , "00" }, + {"Portugal" ,"PT" , "351" , 9 , "00" }, + {"Puerto Rico" ,"PR" , "1" , 10 , "011" }, + {"Qatar" ,"QA" , "974" , 8 , "00" }, + {"RŽunion Island" ,"RE" , "262" , 9 , "011" }, + {"Romania" ,"RO" , "40" , 9 , "00" }, + {"Russian Federation" ,"RU" , "7" , 10 , "8" }, + {"Rwanda" ,"RW" , "250" , 9 , "00" }, + {"Saint Helena" ,"SH" , "290" , 4 , "00" }, + {"Saint Kitts and Nevis" ,"KN" , "1" , 10 , "011" }, + {"Saint Lucia" ,"LC" , "1" , 10 , "011" }, + {"Saint Pierre and Miquelon" ,"PM" , "508" , 6 , "00" }, + {"Saint Vincent and the Grenadines","VC" , "1" , 10 , "011" }, + {"Samoa" ,"WS" , "685" , 7 , "0" }, + {"San Marino" ,"SM" , "378" , 10 , "00" }, + {"S‹o TomŽ and Pr’ncipe" ,"ST" , "239" , 7 , "00" }, + {"Saudi Arabia" ,"SA" , "966" , 9 , "00" }, + {"Senegal" ,"SN" , "221" , 9 , "00" }, + {"Serbia" ,"RS" , "381" , 9 , "00" }, + {"Seychelles" ,"SC" , "248" , 7 , "00" }, + {"Sierra Leone" ,"SL" , "232" , 8 , "00" }, + {"Singapore" ,"SG" , "65" , 8 , "001" }, + {"Slovakia" ,"SK" , "421" , 9 , "00" }, + {"Slovenia" ,"SI" , "386" , 8 , "00" }, + {"Solomon Islands" ,"SB" , "677" , 7 , "00" }, + {"Somalia" ,"SO" , "252" , 8 , "00" }, + {"South Africa" ,"ZA" , "27" , 9 , "00" }, + {"Spain" ,"ES" , "34" , 9 , "00" }, + {"Sri Lanka" ,"LK" , "94" , 9 , "00" }, + {"Sudan" ,"SD" , "249" , 9 , "00" }, + {"Suriname" ,"SR" , "597" , 7 , "00" }, + {"Swaziland" ,"SZ" , "268" , 8 , "00" }, + {"Sweden" ,"SE" , "1" , 9 , "00" }, + {"Switzerland" ,"XK" , "41" , 9 , "00" }, + {"Syria" ,"SY" , "963" , 9 , "00" }, + {"Taiwan" ,"TW" , "886" , 9 , "810" }, + {"Tajikistan" ,"TJ" , "992" , 9 , "002" }, + {"Tanzania" ,"TZ" , "255" , 9 , "000" }, + {"Thailand" ,"TH" , "66" , 9 , "001" }, + {"Togo" ,"TG" , "228" , 8 , "00" }, + {"Tokelau" ,"TK" , "690" , 4 , "00" }, + {"Tonga" ,"TO" , "676" , 5 , "00" }, + {"Trinidad and Tobago" ,"TT" , "1" , 10 , "011" }, + {"Tunisia" ,"TN" , "216" , 8 , "00" }, + {"Turkey" ,"TR" , "90" , 10 , "00" }, + {"Turkmenistan" ,"TM" , "993" , 8 , "00" }, + {"Turks and Caicos Islands" ,"TC" , "1" , 7 , "0" }, + {"Tuvalu" ,"TV" , "688" , 5 , "00" }, + {"Uganda" ,"UG" , "256" , 9 , "000" }, + {"Ukraine" ,"UA" , "380" , 9 , "00" }, + {"United Arab Emirates" ,"AE" , "971" , 9 , "00" }, + {"United Kingdom" ,"UK" , "44" , 10 , "00" }, + {"United States" ,"US" , "1" , 10 , "011" }, + {"Uruguay" ,"UY" , "598" , 8 , "00" }, + {"Uzbekistan" ,"UZ" , "998" , 9 , "8" }, + {"Vanuatu" ,"VU" , "678" , 7 , "00" }, + {"Venezuela" ,"VE" , "58" , 10 , "00" }, + {"Vietnam" ,"VN" , "84" , 9 , "00" }, + {"Wallis and Futuna" ,"WF" , "681" , 5 , "00" }, + {"Yemen" ,"YE" , "967" , 9 , "00" }, + {"Zambia" ,"ZM" , "260" , 9 , "00" }, + {"Zimbabwe" ,"ZW" , "263" , 9 , "00" }, + {NULL ,NULL , "" , 0 , NULL } +}; static dial_plan_t most_common_dialplan={ "generic" ,"", "", 10, "00"}; +int linphone_dial_plan_lookup_ccc_from_e164(const char* e164) { + dial_plan_t* dial_plan; + dial_plan_t* elected_dial_plan=NULL; + unsigned int found; + unsigned int i=0; + if (e164[1]=='1') { + /*USA case*/ + return 1; + } + do { + found=0; + i++; + for (dial_plan=(dial_plan_t*)dial_plans; dial_plan->country!=NULL; dial_plan++) { + if (strncmp(dial_plan->ccc,&e164[1],i) == 0) { + elected_dial_plan=dial_plan; + found++; + } + } + } while (found>1 || found==0); + if (found==1) { + return atoi(elected_dial_plan->ccc); + } else { + return -1; /*not found */ + } + +} int linphone_dial_plan_lookup_ccc_from_iso(const char* iso) { dial_plan_t* dial_plan; for (dial_plan=(dial_plan_t*)dial_plans; dial_plan->country!=NULL; dial_plan++) { diff --git a/coreapi/sal.c b/coreapi/sal.c index b349ad0a4..f46d9a556 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -162,6 +162,10 @@ static bool_t payload_type_equals(const PayloadType *p1, const PayloadType *p2){ return TRUE; } +static bool_t is_recv_only(PayloadType *p){ + return (p->flags & PAYLOAD_TYPE_FLAG_CAN_RECV) && ! (p->flags & PAYLOAD_TYPE_FLAG_CAN_SEND); +} + static bool_t payload_list_equals(const MSList *l1, const MSList *l2){ const MSList *e1,*e2; for(e1=l1,e2=l2;e1!=NULL && e2!=NULL; e1=e1->next,e2=e2->next){ @@ -170,6 +174,12 @@ static bool_t payload_list_equals(const MSList *l1, const MSList *l2){ if (!payload_type_equals(p1,p2)) return FALSE; } + if (e1!=NULL){ + /*skip possible recv-only payloads*/ + for(;e1!=NULL && is_recv_only((PayloadType*)e1->data);e1=e1->next){ + ms_message("Skipping recv-only payload type..."); + } + } if (e1!=NULL || e2!=NULL){ /*means one list is longer than the other*/ return FALSE; @@ -177,32 +187,40 @@ static bool_t payload_list_equals(const MSList *l1, const MSList *l2){ return TRUE; } -bool_t sal_stream_description_equals(const SalStreamDescription *sd1, const SalStreamDescription *sd2){ - if (sd1->proto!=sd2->proto) return FALSE; - if (sd1->type!=sd2->type) return FALSE; - if (strcmp(sd1->rtp_addr,sd2->rtp_addr)!=0) return FALSE; - if (sd1->rtp_port!=sd2->rtp_port) return FALSE; - if (strcmp(sd1->rtcp_addr,sd2->rtcp_addr)!=0) return FALSE; - if (sd1->rtcp_port!=sd2->rtcp_port) return FALSE; - if (!payload_list_equals(sd1->payloads,sd2->payloads)) return FALSE; - if (sd1->bandwidth!=sd2->bandwidth) return FALSE; - if (sd1->ptime!=sd2->ptime) return FALSE; - /* compare candidates: TODO */ - if (sd1->dir!=sd2->dir) return FALSE; - return TRUE; +int sal_stream_description_equals(const SalStreamDescription *sd1, const SalStreamDescription *sd2) { + int result = SAL_MEDIA_DESCRIPTION_UNCHANGED; + + /* A different proto should result in SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED but the encryption change + needs a stream restart for now, so use SAL_MEDIA_DESCRIPTION_CODEC_CHANGED */ + if (sd1->proto != sd2->proto) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; + + if (sd1->type != sd2->type) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; + if (strcmp(sd1->rtp_addr, sd2->rtp_addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED; + if (sd1->rtp_port != sd2->rtp_port) { + if ((sd1->rtp_port == 0) || (sd2->rtp_port == 0)) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; + else result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED; + } + if (strcmp(sd1->rtcp_addr, sd2->rtcp_addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED; + if (sd1->rtcp_port != sd2->rtcp_port) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED; + if (!payload_list_equals(sd1->payloads, sd2->payloads)) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; + if (sd1->bandwidth != sd2->bandwidth) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; + if (sd1->ptime != sd2->ptime) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; + if (sd1->dir != sd2->dir) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; + + return result; } -bool_t sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2){ +int sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2) { + int result = SAL_MEDIA_DESCRIPTION_UNCHANGED; int i; - - if (strcmp(md1->addr,md2->addr)!=0) return FALSE; - if (md1->nstreams!=md2->nstreams) return FALSE; - if (md1->bandwidth!=md2->bandwidth) return FALSE; - for(i=0;instreams;++i){ - if (!sal_stream_description_equals(&md1->streams[i],&md2->streams[i])) - return FALSE; + + if (strcmp(md1->addr, md2->addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED; + if (md1->nstreams != md2->nstreams) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; + if (md1->bandwidth != md2->bandwidth) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; + for(i = 0; i < md1->nstreams; ++i){ + result |= sal_stream_description_equals(&md1->streams[i], &md2->streams[i]); } - return TRUE; + return result; } static void assign_string(char **str, const char *arg){ diff --git a/coreapi/sal.h b/coreapi/sal.h index 2913096ca..daa59217a 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -53,6 +53,11 @@ typedef enum { SalTransportDTLS /*DTLS*/ }SalTransport; +#define SAL_MEDIA_DESCRIPTION_UNCHANGED 0x00 +#define SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED 0x01 +#define SAL_MEDIA_DESCRIPTION_CODEC_CHANGED 0x02 +#define SAL_MEDIA_DESCRIPTION_CHANGED (SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED | SAL_MEDIA_DESCRIPTION_CODEC_CHANGED) + const char* sal_transport_to_string(SalTransport transport); SalTransport sal_transport_parse(const char*); /* Address manipulation API*/ @@ -183,13 +188,20 @@ typedef struct SalMediaDescription{ bool_t ice_completed; } SalMediaDescription; +typedef struct SalMessage{ + const char *from; + const char *text; + const char *url; + const char *message_id; +}SalMessage; + #define SAL_MEDIA_DESCRIPTION_MAX_MESSAGE_ATTRIBUTES 5 SalMediaDescription *sal_media_description_new(); void sal_media_description_ref(SalMediaDescription *md); void sal_media_description_unref(SalMediaDescription *md); bool_t sal_media_description_empty(const SalMediaDescription *md); -bool_t sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2); +int sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2); bool_t sal_media_description_has_dir(const SalMediaDescription *md, SalStreamDir dir); SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md, SalMediaProto proto, SalStreamType type); @@ -275,8 +287,7 @@ typedef void (*SalOnRegisterFailure)(SalOp *op, SalError error, SalReason reason typedef void (*SalOnVfuRequest)(SalOp *op); typedef void (*SalOnDtmfReceived)(SalOp *op, char dtmf); typedef void (*SalOnRefer)(Sal *sal, SalOp *op, const char *referto); -typedef void (*SalOnTextReceived)(Sal *sal, const char *from, const char *msg); -typedef void (*SalOnMessageExternalBodyReceived)(Sal *sal, const char *from, const char *url); +typedef void (*SalOnTextReceived)(Sal *sal, const SalMessage *msg); typedef void (*SalOnTextDeliveryUpdate)(SalOp *op, SalTextDeliveryStatus status); typedef void (*SalOnNotify)(SalOp *op, const char *from, const char *event); typedef void (*SalOnNotifyRefer)(SalOp *op, SalReferStatus state); @@ -302,7 +313,6 @@ typedef struct SalCallbacks{ SalOnDtmfReceived dtmf_received; SalOnRefer refer_received; SalOnTextReceived text_received; - SalOnMessageExternalBodyReceived message_external_body; SalOnTextDeliveryUpdate text_delivery_update; SalOnNotify notify; SalOnNotifyPresence notify_presence; @@ -346,6 +356,7 @@ void sal_use_one_matching_codec_policy(Sal *ctx, bool_t one_matching_codec); void sal_use_rport(Sal *ctx, bool_t use_rports); void sal_use_101(Sal *ctx, bool_t use_101); void sal_set_root_ca(Sal* ctx, const char* rootCa); +const char *sal_get_root_ca(Sal* ctx); void sal_verify_server_certificates(Sal *ctx, bool_t verify); int sal_iterate(Sal *sal); diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index b5f6cc10f..325e495d3 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -343,8 +343,6 @@ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){ ctx->callbacks.text_received=(SalOnTextReceived)unimplemented_stub; if (ctx->callbacks.ping_reply==NULL) ctx->callbacks.ping_reply=(SalOnPingReply)unimplemented_stub; - if (ctx->callbacks.message_external_body==NULL) - ctx->callbacks.message_external_body=(SalOnMessageExternalBodyReceived)unimplemented_stub; } int sal_unlisten_ports(Sal *ctx){ @@ -415,6 +413,7 @@ int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int i int dont_use_101 = !ctx->use_101; // Copy char to int to avoid bad alignment eXosip_set_option(EXOSIP_OPT_DONT_SEND_101,&dont_use_101); sal_set_dscp(ctx,ctx->dscp); + sal_use_dates(ctx,ctx->add_dates); ipv6=strchr(addr,':')!=NULL; eXosip_enable_ipv6(ipv6); @@ -487,6 +486,10 @@ void sal_set_root_ca(Sal* ctx, const char* rootCa) { set_tls_options(ctx); } +const char *sal_get_root_ca(Sal* ctx) { + return ctx->rootCa; +} + void sal_verify_server_certificates(Sal *ctx, bool_t verify){ ctx->verify_server_certs=verify; #ifdef HAVE_EXOSIP_TLS_VERIFY_CERTIFICATE @@ -1727,11 +1730,13 @@ static bool_t comes_from_local_if(osip_message_t *msg){ static void text_received(Sal *sal, eXosip_event_t *ev){ osip_body_t *body=NULL; - char *from=NULL,*msg; + char *from=NULL,*msg=NULL; osip_content_type_t* content_type; osip_uri_param_t* external_body_url; char unquoted_external_body_url [256]; int external_body_size=0; + SalMessage salmsg; + char message_id[256]={0}; content_type= osip_message_get_content_type(ev->request); if (!content_type) { @@ -1743,14 +1748,14 @@ static void text_received(Sal *sal, eXosip_event_t *ev){ && strcmp(content_type->type, "text")==0 && content_type->subtype && strcmp(content_type->subtype, "plain")==0 ) { - osip_message_get_body(ev->request,0,&body); - if (body==NULL){ - ms_error("Could not get text message from SIP body"); - return; - } - msg=body->body; - sal->callbacks.text_received(sal,from,msg); - } if (content_type->type + osip_message_get_body(ev->request,0,&body); + if (body==NULL){ + ms_error("Could not get text message from SIP body"); + osip_free(from); + return; + } + msg=body->body; + }else if (content_type->type && strcmp(content_type->type, "message")==0 && content_type->subtype && strcmp(content_type->subtype, "external-body")==0 ) { @@ -1761,11 +1766,18 @@ static void text_received(Sal *sal, eXosip_event_t *ev){ ,&external_body_url->gvalue[1] ,external_body_size=MIN(strlen(external_body_url->gvalue)-1,sizeof(unquoted_external_body_url))); unquoted_external_body_url[external_body_size-1]='\0'; - sal->callbacks.message_external_body(sal,from,unquoted_external_body_url); - } else { ms_warning("Unsupported content type [%s/%s]",content_type->type,content_type->subtype); + osip_free(from); + return; } + snprintf(message_id,sizeof(message_id)-1,"%s%s",ev->request->call_id->number,ev->request->cseq->number); + + salmsg.from=from; + salmsg.text=msg; + salmsg.url=external_body_size>0 ? unquoted_external_body_url : NULL; + salmsg.message_id=message_id; + sal->callbacks.text_received(sal,&salmsg); osip_free(from); } @@ -1789,7 +1801,7 @@ static void other_request(Sal *sal, eXosip_event_t *ev){ }else ms_warning("Ignored REFER not coming from this local loopback interface."); }else if (strncmp(ev->request->sip_method, "UPDATE", 6) == 0){ inc_update(sal,ev); - }else { + }else { char *tmp=NULL; size_t msglen=0; osip_message_to_str(ev->request,&tmp,&msglen); @@ -2221,11 +2233,21 @@ static void register_set_contact(osip_message_t *msg, const char *contact){ } static void sal_register_add_route(osip_message_t *msg, const char *proxy){ - char tmp[256]={0}; - snprintf(tmp,sizeof(tmp)-1,"<%s;lr>",proxy); - + osip_route_t *route; + osip_list_special_free(&msg->routes,(void (*)(void*))osip_route_free); - osip_message_set_route(msg,tmp); + + osip_route_init(&route); + if (osip_route_parse(route,proxy)==0){ + osip_uri_param_t *lr_param = NULL; + osip_uri_uparam_get_byname(route->url, "lr", &lr_param); + if (lr_param == NULL){ + osip_uri_uparam_add(route->url,osip_strdup("lr"),NULL); + } + osip_list_add(&msg->routes,route,0); + return; + } + osip_route_free(route); } diff --git a/coreapi/test_numbers.c b/coreapi/test_numbers.c index 8cf4fb792..da1f22b6f 100644 --- a/coreapi/test_numbers.c +++ b/coreapi/test_numbers.c @@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "linphonecore.h" +#include "linphonecore_utils.h" int main(int argc , char *argv[]){ LinphoneProxyConfig *cfg; @@ -35,6 +36,13 @@ int main(int argc , char *argv[]){ if (argc>3 && strcmp(argv[3],"--escape-plus")==0) linphone_proxy_config_set_dial_escape_plus(cfg,TRUE); linphone_proxy_config_normalize_number(cfg,argv[1],normalized_number,sizeof(normalized_number)); + printf("Normalized number is %s\n",normalized_number); + /*check extracted ccc*/ + if (linphone_dial_plan_lookup_ccc_from_e164(normalized_number) != atoi(linphone_proxy_config_get_dial_prefix(cfg))) { + printf("Error ccc [%i] not correctly parsed\n",linphone_dial_plan_lookup_ccc_from_e164(normalized_number)); + } else { + printf("Extracted ccc is [%i] \n",linphone_dial_plan_lookup_ccc_from_e164(normalized_number)); + } return 0; } diff --git a/gtk/main.c b/gtk/main.c index 1216b6106..973f7afe6 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -237,8 +237,8 @@ static void linphone_gtk_init_liblinphone(const char *config_file, vtable.call_encryption_changed=linphone_gtk_call_encryption_changed; vtable.transfer_state_changed=linphone_gtk_transfer_state_changed; - linphone_core_set_user_agent("Linphone", LINPHONE_VERSION); the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL); + linphone_core_set_user_agent(the_core,"Linphone", LINPHONE_VERSION); linphone_core_set_waiting_callback(the_core,linphone_gtk_wait,NULL); linphone_core_set_zrtp_secrets_file(the_core,secrets_file); g_free(secrets_file); diff --git a/gtk/parameters.ui b/gtk/parameters.ui index 61d357da8..53a644796 100644 --- a/gtk/parameters.ui +++ b/gtk/parameters.ui @@ -48,7 +48,22 @@ 1 9.9999999995529656 - + + 65535 + 2 + 10 + + + 65535 + 2 + 10 + + + 65535 + 2 + 10 + + 65535 2 10 @@ -59,11 +74,6 @@ 1 10 - - 65535 - 2 - 10 - @@ -206,10 +216,10 @@ Set Maximum Transmission Unit: + False True True False - False True @@ -246,10 +256,10 @@ Send DTMFs as SIP info + False True True False - False True @@ -262,11 +272,11 @@ Use IPv6 instead of IPv4 + False True True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False True @@ -383,9 +393,9 @@ gtk-edit + False True True - False True @@ -422,46 +432,6 @@ 2 - - - True - True - • - False - False - True - True - adjustment_audio_port - True - - - - 1 - 2 - 1 - 2 - - - - - True - True - • - False - False - True - True - adjustment_video_port - True - - - - 1 - 2 - 2 - 3 - - True @@ -476,10 +446,10 @@ gtk-edit + False True True True - False True @@ -490,6 +460,140 @@ 5 + + + True + False + + + True + True + • + False + False + True + True + adjustment_min_audio_port + True + + + + True + True + 0 + + + + + True + True + • + True + False + False + True + True + adjustment_max_audio_port + True + + + + True + True + 1 + + + + + Fixed + False + True + True + False + True + + + + True + True + 2 + + + + + 1 + 2 + 1 + 2 + + + + + True + False + + + True + True + • + False + False + True + True + adjustment_min_video_port + True + + + + True + True + 0 + + + + + True + True + • + True + False + False + True + True + adjustment_max_video_port + True + + + + True + True + 1 + + + + + Fixed + False + True + True + False + True + + + + True + True + 2 + + + + + 1 + 2 + 2 + 3 + + @@ -524,10 +628,10 @@ Direct connection to the Internet + False True True False - False True True @@ -545,10 +649,10 @@ Behind NAT / Firewall (specify gateway IP below) + False True True False - False True True no_nat @@ -613,10 +717,10 @@ Behind NAT / Firewall (use STUN to resolve) + False True True False - False True no_nat @@ -630,10 +734,10 @@ Behind NAT / Firewall (use ICE) + False True True False - False True no_nat @@ -771,6 +875,9 @@ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 6 2 + + + True @@ -792,11 +899,11 @@ gtk-media-play + False True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False True @@ -969,10 +1076,10 @@ Enable echo cancellation + False True True False - False True @@ -983,9 +1090,6 @@ 6 - - - @@ -1321,10 +1425,10 @@ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False True True True - False @@ -1368,11 +1472,11 @@ + False True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False @@ -1416,11 +1520,11 @@ + False True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False @@ -1464,11 +1568,11 @@ + False True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False @@ -1557,11 +1661,11 @@ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False @@ -1743,11 +1847,11 @@ gtk-go-up + False True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False True @@ -1760,11 +1864,11 @@ gtk-go-down + False True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False True @@ -1776,11 +1880,11 @@ + False True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False @@ -1824,11 +1928,11 @@ + False True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False @@ -1991,10 +2095,10 @@ Enable adaptive rate control + False True True False - False 0 True @@ -2020,7 +2124,7 @@ 2 3 GTK_FILL - + @@ -2146,10 +2250,10 @@ Show advanced settings + False True True False - False True @@ -2226,11 +2330,11 @@ end + False True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False diff --git a/gtk/propertybox.c b/gtk/propertybox.c index 31c76f93b..03092a0a5 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -146,14 +146,74 @@ void linphone_gtk_ipv6_toggled(GtkWidget *w){ gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))); } -void linphone_gtk_audio_port_changed(GtkWidget *w){ - linphone_core_set_audio_port(linphone_gtk_get_core(), - (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(w))); +void linphone_gtk_min_audio_port_changed(GtkWidget *w){ + GtkWidget *mw = linphone_gtk_get_main_window(); + GtkWidget *pb = (GtkWidget *) g_object_get_data(G_OBJECT(mw), "parameters"); + GtkSpinButton *min_button = GTK_SPIN_BUTTON(w); + GtkSpinButton *max_button = GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "audio_max_rtp_port")); + gboolean fixed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb, "fixed_audio_port"))); + + if (fixed) { + linphone_core_set_audio_port(linphone_gtk_get_core(), (gint) gtk_spin_button_get_value(min_button)); + gtk_spin_button_set_value(max_button, gtk_spin_button_get_value(min_button)); + } else { + gint min_port = gtk_spin_button_get_value(min_button); + gint max_port = gtk_spin_button_get_value(max_button); + if (min_port > max_port) { + gtk_spin_button_set_value(max_button, min_port); + max_port = min_port; + } + linphone_core_set_audio_port_range(linphone_gtk_get_core(), min_port, max_port); + } } -void linphone_gtk_video_port_changed(GtkWidget *w){ - linphone_core_set_video_port(linphone_gtk_get_core(), - (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(w))); +void linphone_gtk_max_audio_port_changed(GtkWidget *w){ + GtkWidget *mw = linphone_gtk_get_main_window(); + GtkWidget *pb = (GtkWidget *) g_object_get_data(G_OBJECT(mw), "parameters"); + GtkSpinButton *min_button = GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "audio_min_rtp_port")); + GtkSpinButton *max_button = GTK_SPIN_BUTTON(w); + gint min_port = gtk_spin_button_get_value(min_button); + gint max_port = gtk_spin_button_get_value(max_button); + if (max_port < min_port) { + gtk_spin_button_set_value(min_button, max_port); + min_port = max_port; + } + linphone_core_set_audio_port_range(linphone_gtk_get_core(), min_port, max_port); +} + +void linphone_gtk_min_video_port_changed(GtkWidget *w){ + GtkWidget *mw = linphone_gtk_get_main_window(); + GtkWidget *pb = (GtkWidget *) g_object_get_data(G_OBJECT(mw), "parameters"); + GtkSpinButton *min_button = GTK_SPIN_BUTTON(w); + GtkSpinButton *max_button = GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "video_max_rtp_port")); + gboolean fixed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb, "fixed_video_port"))); + + if (fixed) { + linphone_core_set_video_port(linphone_gtk_get_core(), (gint) gtk_spin_button_get_value(min_button)); + gtk_spin_button_set_value(max_button, gtk_spin_button_get_value(min_button)); + } else { + gint min_port = gtk_spin_button_get_value(min_button); + gint max_port = gtk_spin_button_get_value(max_button); + if (min_port > max_port) { + gtk_spin_button_set_value(max_button, min_port); + max_port = min_port; + } + linphone_core_set_video_port_range(linphone_gtk_get_core(), min_port, max_port); + } +} + +void linphone_gtk_max_video_port_changed(GtkWidget *w){ + GtkWidget *mw = linphone_gtk_get_main_window(); + GtkWidget *pb = (GtkWidget *) g_object_get_data(G_OBJECT(mw), "parameters"); + GtkSpinButton *min_button = GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "video_min_rtp_port")); + GtkSpinButton *max_button = GTK_SPIN_BUTTON(w); + gint min_port = gtk_spin_button_get_value(min_button); + gint max_port = gtk_spin_button_get_value(max_button); + if (max_port < min_port) { + gtk_spin_button_set_value(min_button, max_port); + min_port = max_port; + } + linphone_core_set_video_port_range(linphone_gtk_get_core(), min_port, max_port); } void linphone_gtk_no_firewall_toggled(GtkWidget *w){ @@ -877,6 +937,7 @@ static void linphone_gtk_show_media_encryption(GtkWidget *pb){ void linphone_gtk_parameters_destroyed(GtkWidget *pb){ GtkWidget *mw=linphone_gtk_get_main_window(); + ms_error("linphone_gtk_paramters_destroyed"); g_object_set_data(G_OBJECT(mw),"parameters",NULL); } @@ -908,12 +969,15 @@ void linphone_gtk_show_parameters(void){ int mtu; int ui_advanced; LCSipTransports tr; + int min_port = 0, max_port = 0; if (pb==NULL) { pb=linphone_gtk_create_window("parameters"); g_object_set_data(G_OBJECT(mw),"parameters",pb); + ms_error("linphone_gtk_show_paramters: create"); }else { gtk_widget_show(pb); + ms_error("linphone_gtk_show_parameters: show"); return; } codec_list=linphone_gtk_get_widget(pb,"codec_list"); @@ -939,10 +1003,20 @@ void linphone_gtk_show_parameters(void){ tr.udp_port); } - gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"audio_rtp_port")), - linphone_core_get_audio_port(lc)); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"video_rtp_port")), - linphone_core_get_video_port(lc)); + linphone_core_get_audio_port_range(lc, &min_port, &max_port); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "audio_min_rtp_port")), min_port); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "audio_max_rtp_port")), max_port); + if (min_port == max_port) { + gtk_widget_set_sensitive(GTK_WIDGET(linphone_gtk_get_widget(pb, "audio_max_rtp_port")), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb, "fixed_audio_port")), TRUE); + } + linphone_core_get_video_port_range(lc, &min_port, &max_port); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "video_min_rtp_port")), min_port); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "video_max_rtp_port")), max_port); + if (min_port == max_port) { + gtk_widget_set_sensitive(GTK_WIDGET(linphone_gtk_get_widget(pb, "video_max_rtp_port")), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb, "fixed_video_port")), TRUE); + } linphone_gtk_show_media_encryption(pb); @@ -1032,6 +1106,36 @@ void linphone_gtk_show_parameters(void){ } +void linphone_gtk_fixed_audio_port_toggle(void) { + GtkWidget *mw = linphone_gtk_get_main_window(); + GtkWidget *pb = (GtkWidget *) g_object_get_data(G_OBJECT(mw), "parameters"); + gboolean fixed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb, "fixed_audio_port"))); + gint min_port = gtk_spin_button_get_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "audio_min_rtp_port"))); + gint max_port = gtk_spin_button_get_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "audio_max_rtp_port"))); + gtk_widget_set_sensitive(GTK_WIDGET(linphone_gtk_get_widget(pb, "audio_max_rtp_port")), !fixed); + if (fixed) { + linphone_core_set_audio_port(linphone_gtk_get_core(), min_port); + } else { + linphone_core_set_audio_port_range(linphone_gtk_get_core(), min_port, max_port); + } +} + + +void linphone_gtk_fixed_video_port_toggle(void) { + GtkWidget *mw = linphone_gtk_get_main_window(); + GtkWidget *pb = (GtkWidget *) g_object_get_data(G_OBJECT(mw), "parameters"); + gboolean fixed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb, "fixed_video_port"))); + gint min_port = gtk_spin_button_get_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "video_min_rtp_port"))); + gint max_port = gtk_spin_button_get_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "video_max_rtp_port"))); + gtk_widget_set_sensitive(GTK_WIDGET(linphone_gtk_get_widget(pb, "video_max_rtp_port")), !fixed); + if (fixed) { + linphone_core_set_video_port(linphone_gtk_get_core(), min_port); + } else { + linphone_core_set_video_port_range(linphone_gtk_get_core(), min_port, max_port); + } +} + + void linphone_gtk_edit_tunnel_closed(GtkWidget *button){ GtkWidget *pb=gtk_widget_get_toplevel(button); gtk_widget_destroy(pb); diff --git a/java/common/org/linphone/core/LinphoneCall.java b/java/common/org/linphone/core/LinphoneCall.java index 35e173d5a..ac7b14d8d 100644 --- a/java/common/org/linphone/core/LinphoneCall.java +++ b/java/common/org/linphone/core/LinphoneCall.java @@ -32,7 +32,7 @@ public interface LinphoneCall { */ static class State { - static private Vector values = new Vector(); + static private Vector values = new Vector(); private final int mValue; public final int value() {return mValue;} @@ -268,6 +268,11 @@ public interface LinphoneCall { boolean isInConference(); float getPlayVolume(); + + /** + * Obtain the remote user agent string. + */ + String getRemoteUserAgent(); /** * Take a photo of currently received video and write it into a jpeg file. diff --git a/java/common/org/linphone/core/LinphoneCallLog.java b/java/common/org/linphone/core/LinphoneCallLog.java index 1abdb7bed..2e839234f 100644 --- a/java/common/org/linphone/core/LinphoneCallLog.java +++ b/java/common/org/linphone/core/LinphoneCallLog.java @@ -32,13 +32,13 @@ public interface LinphoneCallLog { */ static class CallStatus { - static private Vector values = new Vector(); + static private Vector values = new Vector(); private final int mValue; private final String mStringValue; /** * Call success. */ - public final static CallStatus Sucess = new CallStatus(0,"Sucess"); + public final static CallStatus Success = new CallStatus(0,"Sucess"); /** * Call aborted. */ @@ -100,6 +100,11 @@ public interface LinphoneCallLog { */ public String getStartDate(); + /** + * @return a timestamp of the start date/time of the call in milliseconds since January 1st 1970 + */ + public long getTimestamp(); + /** * @return the call duration, in seconds */ diff --git a/java/common/org/linphone/core/LinphoneCallParams.java b/java/common/org/linphone/core/LinphoneCallParams.java index 2dd497c9c..730a99dc2 100644 --- a/java/common/org/linphone/core/LinphoneCallParams.java +++ b/java/common/org/linphone/core/LinphoneCallParams.java @@ -57,4 +57,12 @@ public interface LinphoneCallParams { * @return PayloadType or null */ PayloadType getUsedVideoCodec(); + + /** + * Indicate low bandwith mode. + * Configuring a call to low bandwidth mode will result in the core to activate several settings for the call in order to ensure that bitrate usage + * is lowered to the minimum possible. Typically, ptime (packetization time) will be increased, audio codec's output bitrate will be targetted to 20kbit/s provided + * that it is achievable by the codec selected after SDP handshake. Video is automatically disabled. + **/ + void enableLowBandwidth(boolean enable); } diff --git a/java/common/org/linphone/core/LinphoneCallStats.java b/java/common/org/linphone/core/LinphoneCallStats.java index 15b4cfb34..f1248c445 100644 --- a/java/common/org/linphone/core/LinphoneCallStats.java +++ b/java/common/org/linphone/core/LinphoneCallStats.java @@ -23,7 +23,7 @@ import java.util.Vector; public interface LinphoneCallStats { static public class MediaType { - static private Vector values = new Vector(); + static private Vector values = new Vector(); /** * Audio */ @@ -52,7 +52,7 @@ public interface LinphoneCallStats { } } static public class IceState { - static private Vector values = new Vector(); + static private Vector values = new Vector(); /** * Not activated */ diff --git a/java/common/org/linphone/core/LinphoneChatMessage.java b/java/common/org/linphone/core/LinphoneChatMessage.java index db75f9116..d403d94bd 100644 --- a/java/common/org/linphone/core/LinphoneChatMessage.java +++ b/java/common/org/linphone/core/LinphoneChatMessage.java @@ -7,9 +7,8 @@ public interface LinphoneChatMessage { interface StateListener{ void onLinphoneChatMessageStateChanged(LinphoneChatMessage msg, State state); } - static class State { - @SuppressWarnings("rawtypes") - static private Vector values = new Vector(); + public static class State { + static private Vector values = new Vector(); private final int mValue; public final int value() {return mValue;} @@ -31,7 +30,6 @@ public interface LinphoneChatMessage { */ public final static State NotDelivered = new State(3,"NotDelivered"); - @SuppressWarnings("unchecked") private State(int value,String stringValue) { mValue = value; values.addElement(this); diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index 562ae86cd..8815085d0 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -31,7 +31,7 @@ public interface LinphoneCore { */ static public class GlobalState { - static private Vector values = new Vector(); + static private Vector values = new Vector(); /** * Off */ @@ -76,7 +76,7 @@ public interface LinphoneCore { */ static public class RegistrationState { - private static Vector values = new Vector(); + private static Vector values = new Vector(); /** * None */ @@ -124,7 +124,7 @@ public interface LinphoneCore { */ static public class FirewallPolicy { - static private Vector values = new Vector(); + static private Vector values = new Vector(); /** * No firewall is assumed. */ @@ -189,21 +189,21 @@ public interface LinphoneCore { * Media (RTP) encryption enum-like. * */ - static public class MediaEncryption { + static public final class MediaEncryption { - static private Vector values = new Vector(); + static private Vector values = new Vector(); /** * None */ - static public MediaEncryption None = new MediaEncryption(0,"None"); + static public final MediaEncryption None = new MediaEncryption(0,"None"); /** * SRTP */ - static public MediaEncryption SRTP = new MediaEncryption(1,"SRTP"); + static public final MediaEncryption SRTP = new MediaEncryption(1,"SRTP"); /** * ZRTP */ - static public MediaEncryption ZRTP = new MediaEncryption(2,"ZRTP"); + static public final MediaEncryption ZRTP = new MediaEncryption(2,"ZRTP"); protected final int mValue; private final String mStringValue; @@ -230,7 +230,7 @@ public interface LinphoneCore { */ static public class EcCalibratorStatus { - static private Vector values = new Vector(); + static private Vector values = new Vector(); /* Do not change the values of these constants or the strings associated with them to prevent breaking the collection of echo canceller calibration results during the wizard! */ public static final int IN_PROGRESS_STATUS=0; @@ -278,6 +278,12 @@ public interface LinphoneCore { return mValue; } } + + /** + * Set the context of creation of the LinphoneCore. + */ + public void setContext(Object context); + /** * clear all added proxy configs */ @@ -417,7 +423,9 @@ public interface LinphoneCore { * @throws LinphoneCoreException */ public void deferCallUpdate(LinphoneCall aCall) throws LinphoneCoreException; - + + public void startRinging(); + /** * @return a list of LinphoneCallLog */ @@ -472,7 +480,7 @@ public interface LinphoneCore { * @return true is mic is muted */ boolean isMicMuted(); - + /** * Initiate a dtmf signal if in call * @param number @@ -524,7 +532,7 @@ public interface LinphoneCore { */ boolean isEchoCancellationEnabled(); /** - * Get echo limiter status (another method of doing echo suppressionn, more brute force) + * Get echo limiter status (another method of doing echo suppression, more brute force) * @return true if echo limiter is enabled */ boolean isEchoLimiterEnabled(); @@ -537,13 +545,13 @@ public interface LinphoneCore { */ Transports getSignalingTransportPorts(); /** - * not implemented + * Activates or deactivates the speaker. * @param value */ void enableSpeaker(boolean value); /** - * not implemented - * @return + * Tells whether the speaker is activated. + * @return true if speaker enabled, false otherwise */ boolean isSpeakerEnabled(); /** @@ -843,4 +851,27 @@ public interface LinphoneCore { * automatically declined. **/ void setIncomingTimeout(int timeout); + + /** + * Set the call timeout in seconds. + * Once this time is elapsed (ringing included), the call is automatically hung up. + **/ + void setInCallTimeout(int timeout); + + void setMicrophoneGain(float gain); + + /** + * Set username and display name to use if no LinphoneProxyConfig configured + */ + void setPrimaryContact(String displayName, String username); + + /** + * Enable/Disable the use of SIP INFO for DTMFs + */ + void setUseSipInfoForDtmfs(boolean use); + + /** + * Enable/Disable the use of inband DTMFs + */ + void setUseRfc2833ForDtmfs(boolean use); } diff --git a/java/common/org/linphone/core/LinphoneCoreFactory.java b/java/common/org/linphone/core/LinphoneCoreFactory.java index fe35b257f..04cef4aea 100644 --- a/java/common/org/linphone/core/LinphoneCoreFactory.java +++ b/java/common/org/linphone/core/LinphoneCoreFactory.java @@ -40,7 +40,7 @@ abstract public class LinphoneCoreFactory { public static final synchronized LinphoneCoreFactory instance() { try { if (theLinphoneCoreFactory == null) { - Class lFactoryClass = Class.forName(factoryName); + Class lFactoryClass = Class.forName(factoryName); theLinphoneCoreFactory = (LinphoneCoreFactory) lFactoryClass.newInstance(); } } catch (Exception e) { diff --git a/java/common/org/linphone/core/LinphoneFriend.java b/java/common/org/linphone/core/LinphoneFriend.java index e070f6921..417c582d9 100644 --- a/java/common/org/linphone/core/LinphoneFriend.java +++ b/java/common/org/linphone/core/LinphoneFriend.java @@ -37,7 +37,7 @@ public interface LinphoneFriend { static class SubscribePolicy { - static private Vector values = new Vector(); + static private Vector values = new Vector(); protected final int mValue; private final String mStringValue; /** diff --git a/java/common/org/linphone/core/OnlineStatus.java b/java/common/org/linphone/core/OnlineStatus.java index a1b36ab37..081084171 100644 --- a/java/common/org/linphone/core/OnlineStatus.java +++ b/java/common/org/linphone/core/OnlineStatus.java @@ -28,7 +28,7 @@ import java.util.Vector; public class OnlineStatus { - static private Vector values = new Vector(); + static private Vector values = new Vector(); /** * Offline */ diff --git a/java/common/org/linphone/core/PayloadType.java b/java/common/org/linphone/core/PayloadType.java index 952da57d2..648d77465 100644 --- a/java/common/org/linphone/core/PayloadType.java +++ b/java/common/org/linphone/core/PayloadType.java @@ -21,4 +21,6 @@ package org.linphone.core; public interface PayloadType { String getMime(); + + int getRate(); } diff --git a/java/impl/org/linphone/core/LinphoneCallImpl.java b/java/impl/org/linphone/core/LinphoneCallImpl.java index 7e39cebc7..6a91438ac 100644 --- a/java/impl/org/linphone/core/LinphoneCallImpl.java +++ b/java/impl/org/linphone/core/LinphoneCallImpl.java @@ -174,6 +174,11 @@ class LinphoneCallImpl implements LinphoneCall { public float getPlayVolume() { return getPlayVolume(nativePtr); } + + private native String getRemoteUserAgent(long nativePtr); + public String getRemoteUserAgent() { + return getRemoteUserAgent(nativePtr); + } private native void takeSnapshot(long nativePtr, String path); public void takeSnapshot(String path) { diff --git a/java/impl/org/linphone/core/LinphoneCallLogImpl.java b/java/impl/org/linphone/core/LinphoneCallLogImpl.java index 05468626e..2419d74b3 100644 --- a/java/impl/org/linphone/core/LinphoneCallLogImpl.java +++ b/java/impl/org/linphone/core/LinphoneCallLogImpl.java @@ -30,6 +30,7 @@ class LinphoneCallLogImpl implements LinphoneCallLog { private native String getStartDate(long nativePtr); private native int getCallDuration(long nativePtr); private native int getCallId(long nativePtr); + private native long getTimestamp(long nativePtr); LinphoneCallLogImpl(long aNativePtr) { nativePtr = aNativePtr; @@ -64,4 +65,8 @@ class LinphoneCallLogImpl implements LinphoneCallLog { public int getCallId() { return getCallId(nativePtr); } + + public long getTimestamp() { + return getTimestamp(nativePtr) * 1000; // Need milliseconds, not seconds + } } diff --git a/java/impl/org/linphone/core/LinphoneCallParamsImpl.java b/java/impl/org/linphone/core/LinphoneCallParamsImpl.java index 3c4514017..be3495a8d 100644 --- a/java/impl/org/linphone/core/LinphoneCallParamsImpl.java +++ b/java/impl/org/linphone/core/LinphoneCallParamsImpl.java @@ -35,7 +35,7 @@ public class LinphoneCallParamsImpl implements LinphoneCallParams { private native long getUsedAudioCodec(long nativePtr); private native long getUsedVideoCodec(long nativePtr); private native void destroy(long nativePtr); - + private native void enableLowBandwidth(long nativePtr, boolean enable); public boolean getVideoEnabled() { return getVideoEnabled(nativePtr); @@ -79,4 +79,8 @@ public class LinphoneCallParamsImpl implements LinphoneCallParams { public boolean localConferenceMode() { return localConferenceMode(nativePtr); } + + public void enableLowBandwidth(boolean enable) { + enableLowBandwidth(nativePtr, enable); + } } diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index 6059915ea..83f6d20d3 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -18,14 +18,25 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package org.linphone.core; +import static android.media.AudioManager.MODE_IN_CALL; +import static android.media.AudioManager.MODE_RINGTONE; +import android.content.Context; +import android.media.AudioManager; + import java.io.File; import java.io.IOException; +import org.linphone.core.LinphoneCall.State; +import org.linphone.mediastream.video.capture.hwconf.Hacks; + class LinphoneCoreImpl implements LinphoneCore { private final LinphoneCoreListener mListener; //to make sure to keep a reference on this object private long nativePtr = 0; + private Context mContext = null; + private AudioManager mAudioManager = null; + private boolean mSpeakerEnabled = false; private native long newLinphoneCore(LinphoneCoreListener listener,String userConfig,String factoryConfig,Object userdata); private native void iterate(long nativePtr); private native long getDefaultProxyConfig(long nativePtr); @@ -115,6 +126,8 @@ class LinphoneCoreImpl implements LinphoneCore { private native void setAudioPortRange(long nativePtr, int minPort, int maxPort); private native void setVideoPortRange(long nativePtr, int minPort, int maxPort); private native void setIncomingTimeout(long nativePtr, int timeout); + private native void setInCallTimeout(long nativePtr, int timeout); + private native void setPrimaryContact(long nativePtr, String displayName, String username); LinphoneCoreImpl(LinphoneCoreListener listener, File userConfig,File factoryConfig,Object userdata) throws IOException { mListener=listener; @@ -128,14 +141,24 @@ class LinphoneCoreImpl implements LinphoneCore { protected void finalize() throws Throwable { } - + + private boolean contextInitialized() { + if (mContext == null) { + Log.e("Context of LinphoneCore has not been initialized, call setContext() after creating LinphoneCore."); + return false; + } + return true; + } + public void setContext(Object context) { + mContext = (Context)context; + mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); + } + public synchronized void addAuthInfo(LinphoneAuthInfo info) { isValid(); addAuthInfo(nativePtr,((LinphoneAuthInfoImpl)info).nativePtr); } - - public synchronized LinphoneProxyConfig getDefaultProxyConfig() { isValid(); long lNativePtr = getDefaultProxyConfig(nativePtr); @@ -199,7 +222,6 @@ class LinphoneCoreImpl implements LinphoneCore { public synchronized void acceptCall(LinphoneCall aCall) { isValid(); acceptCall(nativePtr,((LinphoneCallImpl)aCall).nativePtr); - } public synchronized LinphoneCallLog[] getCallLogs() { isValid(); @@ -233,6 +255,7 @@ class LinphoneCoreImpl implements LinphoneCore { public synchronized void muteMic(boolean isMuted) { muteMic(nativePtr,isMuted); } + public synchronized LinphoneAddress interpretUrl(String destination) throws LinphoneCoreException { long lAddress = interpretUrl(nativePtr,destination); if (lAddress != 0) { @@ -299,13 +322,37 @@ class LinphoneCoreImpl implements LinphoneCore { // TODO Auto-generated method stub } + + private void applyAudioHacks() { + if (Hacks.needGalaxySAudioHack()) { + /* The microphone gain is way too high on the Galaxy S so correct it here. */ + setMicrophoneGain(-9.0f); + } + } + private void setAudioModeIncallForGalaxyS() { + if (!contextInitialized()) return; + mAudioManager.setMode(MODE_IN_CALL); + } + public void routeAudioToSpeakerHelper(boolean speakerOn) { + if (!contextInitialized()) return; + if (Hacks.needGalaxySAudioHack()) + setAudioModeIncallForGalaxyS(); + mAudioManager.setSpeakerphoneOn(speakerOn); + } + private native void forceSpeakerState(long nativePtr, boolean speakerOn); public void enableSpeaker(boolean value) { - // TODO Auto-generated method stub - + final LinphoneCall call = getCurrentCall(); + mSpeakerEnabled = value; + applyAudioHacks(); + if (call != null && call.getState() == State.StreamsRunning && Hacks.needGalaxySAudioHack()) { + Log.d("Hack to have speaker=", value, " while on call"); + forceSpeakerState(nativePtr, value); + } else { + routeAudioToSpeakerHelper(value); + } } public boolean isSpeakerEnabled() { - // TODO Auto-generated method stub - return false; + return mSpeakerEnabled; } public synchronized void playDtmf(char number, int duration) { playDtmf(nativePtr,number, duration); @@ -695,6 +742,13 @@ class LinphoneCoreImpl implements LinphoneCore { throws LinphoneCoreException { deferCallUpdate(nativePtr, getCallPtr(aCall)); } + + public synchronized void startRinging() { + if (!contextInitialized()) return; + if (Hacks.needGalaxySAudioHack()) { + mAudioManager.setMode(MODE_RINGTONE); + } + } private native void setVideoPolicy(long nativePtr, boolean autoInitiate, boolean autoAccept); public synchronized void setVideoPolicy(boolean autoInitiate, boolean autoAccept) { @@ -744,7 +798,7 @@ class LinphoneCoreImpl implements LinphoneCore { @Override public PayloadType findPayloadType(String mime, int clockRate) { - return null; + return findPayloadType(mime, clockRate, 1); } private native void removeFriend(long ptr, long lf); @@ -782,4 +836,28 @@ class LinphoneCoreImpl implements LinphoneCore { public void setIncomingTimeout(int timeout) { setIncomingTimeout(nativePtr, timeout); } + + public void setInCallTimeout(int timeout) + { + setInCallTimeout(nativePtr, timeout); + } + + private native void setMicrophoneGain(long ptr, float gain); + public void setMicrophoneGain(float gain) { + setMicrophoneGain(nativePtr, gain); + } + + public void setPrimaryContact(String displayName, String username) { + setPrimaryContact(nativePtr, displayName, username); + } + + private native void setUseSipInfoForDtmfs(long ptr, boolean use); + public void setUseSipInfoForDtmfs(boolean use) { + setUseSipInfoForDtmfs(nativePtr, use); + } + + private native void setUseRfc2833ForDtmfs(long ptr, boolean use); + public void setUseRfc2833ForDtmfs(boolean use) { + setUseRfc2833ForDtmfs(nativePtr, use); + } } diff --git a/m4/Makefile.am b/m4/Makefile.am index 562029e7c..804180768 100644 --- a/m4/Makefile.am +++ b/m4/Makefile.am @@ -1,2 +1,41 @@ -EXTRA_DIST= $(shell cd $(srcdir) && ls *.m4) - +EXTRA_DIST=\ + codeset.m4 \ + exosip.m4 \ + gettext.m4 \ + glibc2.m4 \ + glibc21.m4 \ + iconv.m4 \ + ilbc.m4 \ + intdiv0.m4 \ + intl.m4 \ + intldir.m4 \ + intmax.m4 \ + inttypes-pri.m4 \ + inttypes.m4 \ + inttypes_h.m4 \ + isc-posix.m4 \ + lcmessage.m4 \ + lib-ld.m4 \ + lib-link.m4 \ + lib-prefix.m4 \ + lock.m4 \ + longdouble.m4 \ + longlong.m4 \ + nls.m4 \ + obsolete.m4 \ + ortp.m4 \ + osip.m4 \ + po.m4 \ + printf-posix.m4 \ + progtest.m4 \ + readline.m4 \ + signed.m4 \ + size_max.m4 \ + stdint_h.m4 \ + uintmax_t.m4 \ + ulonglong.m4 \ + video.m4 \ + visibility.m4 \ + wchar_t.m4 \ + wint_t.m4 \ + xsize.m4 diff --git a/m4/intl.m4 b/m4/intl.m4 index dcefb118c..3906a1732 100644 --- a/m4/intl.m4 +++ b/m4/intl.m4 @@ -25,7 +25,7 @@ dnl USE_INCLUDED_LIBINTL, BUILD_INCLUDED_LIBINTL. AC_DEFUN([AM_INTL_SUBDIR], [ AC_REQUIRE([AC_PROG_INSTALL])dnl - AC_REQUIRE([AM_PROG_MKDIR_P])dnl defined by automake + AC_REQUIRE([AC_PROG_MKDIR_P])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([gt_GLIBC2])dnl diff --git a/m4/obsolete.m4 b/m4/obsolete.m4 new file mode 100644 index 000000000..a5d2cbd89 --- /dev/null +++ b/m4/obsolete.m4 @@ -0,0 +1 @@ +AC_DEFUN([AM_PROG_MKDIR_P], [AC_PROG_MKDIR_P([$@])]) diff --git a/m4/po.m4 b/m4/po.m4 index 00133ef36..d16320c56 100644 --- a/m4/po.m4 +++ b/m4/po.m4 @@ -24,7 +24,7 @@ AC_DEFUN([AM_PO_SUBDIRS], [ AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl - AC_REQUIRE([AM_PROG_MKDIR_P])dnl defined by automake + AC_REQUIRE([AC_PROG_MKDIR_P])dnl AC_REQUIRE([AM_NLS])dnl dnl Perform the following tests also if --disable-nls has been given, diff --git a/mediastreamer2 b/mediastreamer2 index 23c75b195..bd15866ce 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 23c75b19523c172c97ba89c76cf7672fc804b14a +Subproject commit bd15866cec3c7b74b359e7a22598c017baf7043e diff --git a/oRTP b/oRTP index ddc4f7d04..59ff6bb7a 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit ddc4f7d041967305483761fc9c643d3bb290a5f1 +Subproject commit 59ff6bb7a0c5047526b802d264f6db4faa2bd5c2 diff --git a/share/Makefile.am b/share/Makefile.am index 2f551f53d..83c3a934e 100644 --- a/share/Makefile.am +++ b/share/Makefile.am @@ -1,5 +1,5 @@ -SUBDIRS=C fr it ja cs +SUBDIRS=C fr it ja cs xml LINPHONE_SOUNDS=ringback.wav hello8000.wav hello16000.wav LINPHONE_RINGS=rings/orig.wav \ diff --git a/share/Makefile.inc b/share/Makefile.inc index 47c01785f..3bc5cf04d 100644 --- a/share/Makefile.inc +++ b/share/Makefile.inc @@ -14,7 +14,7 @@ $(linphone_help)/manual.html: sgmltools $(srcdir)/manual.sgml install-data-local: - $(mkdir_p) $(DESTDIR)$(linphone_manualdir) + $(MKDIR_P) $(DESTDIR)$(linphone_manualdir) -cp -f $(linphone_help)/*.html $(DESTDIR)/$(linphone_manualdir)/. -cp -f $(linphone_help)/*.css $(DESTDIR)/$(linphone_manualdir)/. diff --git a/share/xml/Makefile.am b/share/xml/Makefile.am new file mode 100644 index 000000000..c553a5c76 --- /dev/null +++ b/share/xml/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST=lpconfig.xsd diff --git a/share/xml/lpconfig.xsd b/share/xml/lpconfig.xsd new file mode 100644 index 000000000..49bb56180 --- /dev/null +++ b/share/xml/lpconfig.xsd @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/Makefile.am b/tools/Makefile.am new file mode 100644 index 000000000..9e0c94550 --- /dev/null +++ b/tools/Makefile.am @@ -0,0 +1,40 @@ +## Process this file with automake to produce Makefile.in + +AM_CPPFLAGS=\ + -I$(top_srcdir) \ + -I$(top_srcdir)/coreapi \ + -I$(top_srcdir)/exosip + +COMMON_CFLAGS=\ + -DIN_LINPHONE \ + $(LIBXML2_CFLAGS) \ + $(ORTP_CFLAGS) \ + $(STRICT_OPTIONS) + +if BUILD_TOOLS + +lib_LTLIBRARIES=libxml2lpc.la + +libxml2lpc_la_SOURCES=\ + xml2lpc.c \ + xml2lpc.h + +libxml2lpc_la_CFLAGS=$(COMMON_CFLAGS) +libxml2lpc_la_LIBADD=\ + $(LIBXML2_LIBS) \ + $(top_builddir)/coreapi/liblinphone.la + +libxml2lpc_la_LDFLAGS=-no-undefined + +bin_PROGRAMS=xml2lpc_test + +xml2lpc_test_SOURCES=\ + xml2lpc_test.c + +xml2lpc_test_CFLAGS=$(COMMON_CFLAGS) +xml2lpc_test_LDADD=\ + libxml2lpc.la + +endif + + diff --git a/tools/xml2lpc.c b/tools/xml2lpc.c new file mode 100644 index 000000000..d5e2160ab --- /dev/null +++ b/tools/xml2lpc.c @@ -0,0 +1,343 @@ +/* +linphone +Copyright (C) 2012 Belledonne Communications SARL +Yann DIORCET (yann.diorcet@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "xml2lpc.h" +#include +#include + + +#define XML2LPC_BZ 2048 + +struct _xml2lpc_context { + LpConfig *lpc; + xml2lpc_function cbf; + void *ctx; + + xmlDoc *doc; + xmlDoc *xsd; + char errorBuffer[XML2LPC_BZ]; + char warningBuffer[XML2LPC_BZ]; +}; + + +xml2lpc_context* xml2lpc_context_new(xml2lpc_function cbf, void *ctx) { + xml2lpc_context *xmlCtx = (xml2lpc_context*)malloc(sizeof(xml2lpc_context)); + if(xmlCtx != NULL) { + xmlCtx->lpc = NULL; + xmlCtx->cbf = cbf; + xmlCtx->ctx = ctx; + + xmlCtx->doc = NULL; + xmlCtx->xsd = NULL; + xmlCtx->errorBuffer[0]='\0'; + xmlCtx->warningBuffer[0]='\0'; + } + return xmlCtx; +} + +void xml2lpc_context_destroy(xml2lpc_context *ctx) { + if(ctx->doc != NULL) { + xmlFreeDoc(ctx->doc); + ctx->doc = NULL; + } + if(ctx->xsd != NULL) { + xmlFreeDoc(ctx->xsd); + ctx->xsd = NULL; + } + free(ctx); +} + +static void xml2lpc_context_clear_logs(xml2lpc_context *ctx) { + ctx->errorBuffer[0]='\0'; + ctx->warningBuffer[0]='\0'; +} + +static void xml2lpc_log(xml2lpc_context *xmlCtx, int level, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + if(xmlCtx->cbf != NULL) { + xmlCtx->cbf((xmlCtx)->ctx, level, fmt, args); + } + va_end(args); +} + +static void xml2lpc_genericxml_error(void *ctx, const char *fmt, ...) { + xml2lpc_context *xmlCtx = (xml2lpc_context *)ctx; + int sl = strlen(xmlCtx->errorBuffer); + va_list args; + va_start(args, fmt); + vsnprintf(xmlCtx->errorBuffer + sl, XML2LPC_BZ-sl, fmt, args); + va_end(args); +} + +static void xml2lpc_genericxml_warning(void *ctx, const char *fmt, ...) { + xml2lpc_context *xmlCtx = (xml2lpc_context *)ctx; + int sl = strlen(xmlCtx->warningBuffer); + va_list args; + va_start(args, fmt); + vsnprintf(xmlCtx->warningBuffer + sl, XML2LPC_BZ-sl, fmt, args); + va_end(args); +} + +#if 0 +static void dumpNodes(int level, xmlNode * a_node, xml2lpc_context *ctx) { + xmlNode *cur_node = NULL; + + for (cur_node = a_node; cur_node; cur_node = cur_node->next) { + if (cur_node->type == XML_ELEMENT_NODE) { + xml2lpc_log(ctx, XML2LPC_DEBUG, "node level: %d type: Element, name: %s", level, cur_node->name); + } else { + xml2lpc_log(ctx, XML2LPC_DEBUG, "node level: %d type: %d, name: %s", level, cur_node->type, cur_node->name); + } + + dumpNodes(level + 1, cur_node->children, ctx); + } +} +#endif + + +static void dumpNode(xmlNode *node, xml2lpc_context *ctx) { + xml2lpc_log(ctx, XML2LPC_DEBUG, "node type: %d, name: %s", node->type, node->name); +} + +static void dumpAttr(xmlNode *node, xml2lpc_context *ctx) { + xml2lpc_log(ctx, XML2LPC_DEBUG, "attr name: %s value:%s", node->name, node->children->content); +} + +static void dumpContent(xmlNode *node, xml2lpc_context *ctx) { + xml2lpc_log(ctx, XML2LPC_DEBUG, "content: %s", node->children->content); +} + +static int processEntry(xmlElement *element, const char *sectionName, xml2lpc_context *ctx) { + xmlNode *cur_attr = NULL; + const char *name = NULL; + const char *value = NULL; + bool_t overwrite = FALSE; + + for (cur_attr = (xmlNode *)element->attributes; cur_attr; cur_attr = cur_attr->next) { + dumpAttr(cur_attr, ctx); + if(strcmp((const char*)cur_attr->name, "name") == 0) { + name = (const char*)cur_attr->children->content; + } else if(strcmp((const char*)cur_attr->name, "overwrite") == 0) { + if(strcmp((const char*)cur_attr->children->content, "true") == 0) { + overwrite = TRUE; + } + } + } + + value = (const char *)element->children->content; + dumpContent((xmlNode *)element, ctx); + + if(name != NULL) { + const char *str = lp_config_get_string(ctx->lpc, sectionName, name, NULL); + if(str == NULL || overwrite) { + xml2lpc_log(ctx, XML2LPC_MESSAGE, "Set %s|%s = %s",sectionName, name, value); + lp_config_set_string(ctx->lpc, sectionName, name, value); + } else { + xml2lpc_log(ctx, XML2LPC_MESSAGE, "Don't touch %s|%s = %s",sectionName, name, str); + } + } else { + xml2lpc_log(ctx, XML2LPC_WARNING, "ignored entry with no \"name\" attribute line:%d",xmlGetLineNo((xmlNode*)element)); + } + return 0; +} + +static int processSection(xmlElement *element, xml2lpc_context *ctx) { + xmlNode *cur_node = NULL; + xmlNode *cur_attr = NULL; + const char *name = NULL; + + for (cur_attr = (xmlNode *)element->attributes; cur_attr; cur_attr = cur_attr->next) { + dumpAttr(cur_attr, ctx); + if(strcmp((const char*)cur_attr->name, "name") == 0) { + name = (const char*)cur_attr->children->content; + } + } + + if(name != NULL) { + for (cur_node = element->children; cur_node; cur_node = cur_node->next) { + dumpNode(cur_node, ctx); + if (cur_node->type == XML_ELEMENT_NODE) { + if(strcmp((const char*)cur_node->name, "entry") == 0 ) { + processEntry((xmlElement*)cur_node, name, ctx); + } + } + + } + } else { + xml2lpc_log(ctx, XML2LPC_WARNING, "ignored section with no \"name\" attribute, line:%d", xmlGetLineNo((xmlNode*)element)); + } + + return 0; +} + +static int processConfig(xmlElement *element, xml2lpc_context *ctx) { + xmlNode *cur_node = NULL; + + for (cur_node = element->children; cur_node; cur_node = cur_node->next) { + dumpNode(cur_node, ctx); + if (cur_node->type == XML_ELEMENT_NODE && + strcmp((const char*)cur_node->name, "section") == 0 ) { + processSection((xmlElement*)cur_node, ctx); + } + + } + return 0; +} + +static int processDoc(xmlNode *node, xml2lpc_context *ctx) { + dumpNode(node, ctx); + + if (node->type == XML_ELEMENT_NODE && + strcmp((const char*)node->name, "config") == 0 ) { + processConfig((xmlElement*)node, ctx); + } else { + xml2lpc_log(ctx, XML2LPC_WARNING, "root element is not \"config\", line:%d", xmlGetLineNo(node)); + } + return 0; +} + +static int internal_convert_xml2lpc(xmlDoc *doc, xml2lpc_context *ctx) { + xml2lpc_log(ctx, XML2LPC_DEBUG, "Parse started"); + xmlNode *rootNode = xmlDocGetRootElement(doc); + //dumpNodes(0, rootNode, cbf, ctx); + int ret = processDoc(rootNode, ctx); + xml2lpc_log(ctx, XML2LPC_DEBUG, "Parse ended ret:%d", ret); + return ret; +} + +int xml2lpc_validate(xml2lpc_context *xmlCtx) { + xml2lpc_context_clear_logs(xmlCtx); + xmlSchemaValidCtxtPtr validCtx; + xmlSchemaParserCtxtPtr parserCtx = xmlSchemaNewDocParserCtxt(xmlCtx->xsd); + validCtx = xmlSchemaNewValidCtxt(xmlSchemaParse(parserCtx)); + xmlSchemaSetValidErrors(validCtx, xml2lpc_genericxml_error, xml2lpc_genericxml_warning, xmlCtx); + int ret = xmlSchemaValidateDoc(validCtx, xmlCtx->doc); + if(ret >0) { + xml2lpc_log(xmlCtx, XML2LPC_WARNING, "%s", xmlCtx->warningBuffer); + xml2lpc_log(xmlCtx, XML2LPC_ERROR, "%s", xmlCtx->errorBuffer); + } else { + xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Internal error"); + } + xmlSchemaFreeValidCtxt(validCtx); + return ret; +} + +int xml2lpc_convert(xml2lpc_context *xmlCtx, LpConfig *lpc) { + xml2lpc_context_clear_logs(xmlCtx); + xmlCtx->lpc = lpc; + return internal_convert_xml2lpc(xmlCtx->doc, xmlCtx); +} + +int xml2lpc_set_xml_file(xml2lpc_context* xmlCtx, const char *filename) { + xml2lpc_context_clear_logs(xmlCtx); + xmlSetGenericErrorFunc(xmlCtx, xml2lpc_genericxml_error); + if(xmlCtx->doc != NULL) { + xmlFreeDoc(xmlCtx->doc); + xmlCtx->doc = NULL; + } + xmlCtx->doc = xmlReadFile(filename, NULL, 0); + if(xmlCtx->doc == NULL) { + xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Can't open/parse file \"%s\"", filename); + xml2lpc_log(xmlCtx, XML2LPC_ERROR, "%s", xmlCtx->errorBuffer); + return -1; + } + return 0; +} + +int xml2lpc_set_xml_fd(xml2lpc_context* xmlCtx, int fd) { + xml2lpc_context_clear_logs(xmlCtx); + xmlSetGenericErrorFunc(xmlCtx, xml2lpc_genericxml_error); + if(xmlCtx->doc != NULL) { + xmlFreeDoc(xmlCtx->doc); + xmlCtx->doc = NULL; + } + xmlCtx->doc = xmlReadFd(fd, 0, NULL, 0); + if(xmlCtx->doc == NULL) { + xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Can't open/parse fd \"%d\"", fd); + xml2lpc_log(xmlCtx, XML2LPC_ERROR, "%s", xmlCtx->errorBuffer); + return -1; + } + return 0; +} + +int xml2lpc_set_xml_string(xml2lpc_context* xmlCtx, const char *content) { + xml2lpc_context_clear_logs(xmlCtx); + xmlSetGenericErrorFunc(xmlCtx, xml2lpc_genericxml_error); + if(xmlCtx->doc != NULL) { + xmlFreeDoc(xmlCtx->doc); + xmlCtx->doc = NULL; + } + xmlCtx->doc = xmlReadDoc((const unsigned char*)content, 0, NULL, 0); + if(xmlCtx->doc == NULL) { + xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Can't parse string"); + xml2lpc_log(xmlCtx, XML2LPC_ERROR, "%s", xmlCtx->errorBuffer); + return -1; + } + return 0; +} + +int xml2lpc_set_xsd_file(xml2lpc_context* xmlCtx, const char *filename) { + xml2lpc_context_clear_logs(xmlCtx); + xmlSetGenericErrorFunc(xmlCtx, xml2lpc_genericxml_error); + if(xmlCtx->xsd != NULL) { + xmlFreeDoc(xmlCtx->xsd); + xmlCtx->xsd = NULL; + } + xmlCtx->xsd = xmlReadFile(filename, NULL, 0); + if(xmlCtx->xsd == NULL) { + xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Can't open/parse file \"%s\"", filename); + xml2lpc_log(xmlCtx, XML2LPC_ERROR, "%s", xmlCtx->errorBuffer); + return -1; + } + return 0; +} + +int xml2lpc_set_xsd_fd(xml2lpc_context* xmlCtx, int fd) { + xml2lpc_context_clear_logs(xmlCtx); + xmlSetGenericErrorFunc(xmlCtx, xml2lpc_genericxml_error); + if(xmlCtx->xsd != NULL) { + xmlFreeDoc(xmlCtx->xsd); + xmlCtx->xsd = NULL; + } + xmlCtx->xsd = xmlReadFd(fd, 0, NULL, 0); + if(xmlCtx->xsd == NULL) { + xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Can't open/parse fd \"%d\"", fd); + xml2lpc_log(xmlCtx, XML2LPC_ERROR, "%s", xmlCtx->errorBuffer); + return -1; + } + return 0; +} + +int xml2lpc_set_xsd_string(xml2lpc_context* xmlCtx, const char *content) { + xml2lpc_context_clear_logs(xmlCtx); + xmlSetGenericErrorFunc(xmlCtx, xml2lpc_genericxml_error); + if(xmlCtx->xsd != NULL) { + xmlFreeDoc(xmlCtx->xsd); + xmlCtx->xsd = NULL; + } + xmlCtx->xsd = xmlReadDoc((const unsigned char*)content, 0, NULL, 0); + if(xmlCtx->xsd == NULL) { + xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Can't parse string"); + xml2lpc_log(xmlCtx, XML2LPC_ERROR, "%s", xmlCtx->errorBuffer); + return -1; + } + return 0; +} diff --git a/tools/xml2lpc.h b/tools/xml2lpc.h new file mode 100644 index 000000000..746fb0200 --- /dev/null +++ b/tools/xml2lpc.h @@ -0,0 +1,52 @@ +/* +linphone +Copyright (C) 2012 Belledonne Communications SARL + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef XML2LPC_H_ +#define XML2LPC_H_ + +#include "lpconfig.h" + +typedef struct _xml2lpc_context xml2lpc_context; + +typedef enum _xml2lpc_log_level { + XML2LPC_DEBUG = 0, + XML2LPC_MESSAGE, + XML2LPC_WARNING, + XML2LPC_ERROR +} xml2lpc_log_level; + +typedef void(*xml2lpc_function)(void *ctx, xml2lpc_log_level level, const char *fmt, va_list list); + +xml2lpc_context* xml2lpc_context_new(xml2lpc_function cbf, void *ctx); +void xml2lpc_context_destroy(xml2lpc_context*); + +int xml2lpc_set_xml_file(xml2lpc_context* context, const char *filename); +int xml2lpc_set_xml_fd(xml2lpc_context* context, int fd); +int xml2lpc_set_xml_string(xml2lpc_context* context, const char *content); + +int xml2lpc_set_xsd_file(xml2lpc_context* context, const char *filename); +int xml2lpc_set_xsd_fd(xml2lpc_context* context, int fd); +int xml2lpc_set_xsd_string(xml2lpc_context* context, const char *content); + +int xml2lpc_validate(xml2lpc_context *context); +int xml2lpc_convert(xml2lpc_context *context, LpConfig *lpc); + + + +#endif //XML2LPC_H_ diff --git a/tools/xml2lpc_test.c b/tools/xml2lpc_test.c new file mode 100644 index 000000000..e99b90bd8 --- /dev/null +++ b/tools/xml2lpc_test.c @@ -0,0 +1,72 @@ +/* +linphone +Copyright (C) 2012 Belledonne Communications SARL + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include +#include "xml2lpc.h" + +void cb_function(void *ctx, xml2lpc_log_level level, const char *msg, va_list list) { + const char *header = ""; + switch(level) { + case XML2LPC_DEBUG: + header = "DEBUG"; + break; + case XML2LPC_MESSAGE: + header = "MESSAGE"; + break; + case XML2LPC_WARNING: + header = "WARNING"; + break; + case XML2LPC_ERROR: + header = "ERROR"; + break; + } + fprintf(stdout, "%s - ", header); + vfprintf(stdout, msg, list); + fprintf(stdout, "\n"); +} + +void show_usage(int argc, char *argv[]) { + fprintf(stderr, "usage %s convert \n" + " %s validate \n", + argv[0], argv[0]); +} + +int main(int argc, char *argv[]) { + if(argc != 4) { + show_usage(argc, argv); + return -1; + } + + xml2lpc_context *ctx = xml2lpc_context_new(cb_function, NULL); + xml2lpc_set_xml_file(ctx, argv[2]); + if(strcmp("convert", argv[1]) == 0) { + LpConfig *lpc = lp_config_new(argv[3]); + xml2lpc_convert(ctx, lpc); + lp_config_sync(lpc); + lp_config_destroy(lpc); + } else if(strcmp("validate", argv[1]) == 0) { + xml2lpc_set_xsd_file(ctx, argv[3]); + xml2lpc_validate(ctx); + } else { + show_usage(argc, argv); + } + xml2lpc_context_destroy(ctx); + return 0; +} +