diff --git a/build/android/Android.mk b/build/android/Android.mk index b46664b61..7fb75d0a4 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -21,7 +21,6 @@ LOCAL_PATH:= $(call my-dir)/../../coreapi - include $(CLEAR_VARS) include $(linphone-root-dir)/submodules/linphone/build/android/common.mk @@ -39,3 +38,11 @@ LOCAL_MODULE := liblinphone include $(BUILD_SHARED_LIBRARY) $(call import-module,android/cpufeatures) + + +ifeq ($(BUILD_REMOTE_PROVISIONING),1) + +include $(linphone-root-dir)/submodules/linphone/build/android/xml2lpc.mk +include $(linphone-root-dir)/submodules/linphone/build/android/lpc2xml.mk + +endif diff --git a/build/android/common.mk b/build/android/common.mk index aed755d59..551ac6c10 100644 --- a/build/android/common.mk +++ b/build/android/common.mk @@ -49,7 +49,7 @@ LOCAL_SRC_FILES := \ linphonecall.c \ conference.c \ ec-calibrator.c \ - linphone_tunnel.cc + linphone_tunnel_config.c ifndef LINPHONE_VERSION LINPHONE_VERSION = "Devel" @@ -100,12 +100,14 @@ LOCAL_STATIC_LIBRARIES := \ ifeq ($(BUILD_TUNNEL),1) LOCAL_CFLAGS +=-DTUNNEL_ENABLED LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../tunnel/include $(LOCAL_PATH)/../../tunnel/src -LOCAL_SRC_FILES += TunnelManager.cc +LOCAL_SRC_FILES += linphone_tunnel.cc TunnelManager.cc ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) LOCAL_SHARED_LIBRARIES += libtunnelclient else LOCAL_STATIC_LIBRARIES += libtunnelclient endif +else +LOCAL_SRC_FILES += linphone_tunnel_stubs.c endif diff --git a/build/android/lpc2xml.mk b/build/android/lpc2xml.mk new file mode 100644 index 000000000..f7858f94d --- /dev/null +++ b/build/android/lpc2xml.mk @@ -0,0 +1,47 @@ +## +## Android.mk -Android build script- +## +## +## Copyright (C) 2013 Belledonne Communications, Grenoble, France +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +## + +LOCAL_PATH:= $(call my-dir)/../../tools + +include $(CLEAR_VARS) + +LOCAL_CPP_EXTENSION := .cc + +LOCAL_SRC_FILES := \ + lpc2xml.c \ + lpc2xml_jni.cc \ + +LOCAL_CFLAGS += -DIN_LINPHONE + +LOCAL_C_INCLUDES = \ + $(LOCAL_PATH)/../coreapi \ + $(LOCAL_PATH)/../oRTP/include \ + $(LOCAL_PATH)/../mediastreamer2/include \ + $(LOCAL_PATH)/../../externals/libxml2/include \ + $(LOCAL_PATH)/../../externals/build/libxml2 \ + +LOCAL_SHARED_LIBRARIES = \ + libxml2 \ + liblinphone \ + +LOCAL_MODULE := liblpc2xml + +include $(BUILD_SHARED_LIBRARY) diff --git a/build/android/xml2lpc.mk b/build/android/xml2lpc.mk new file mode 100644 index 000000000..32bfb38c3 --- /dev/null +++ b/build/android/xml2lpc.mk @@ -0,0 +1,47 @@ +## +## Android.mk -Android build script- +## +## +## Copyright (C) 2013 Belledonne Communications, Grenoble, France +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +## + +LOCAL_PATH:= $(call my-dir)/../../tools + +include $(CLEAR_VARS) + +LOCAL_CPP_EXTENSION := .cc + +LOCAL_SRC_FILES := \ + xml2lpc.c \ + xml2lpc_jni.cc \ + +LOCAL_CFLAGS += -DIN_LINPHONE + +LOCAL_C_INCLUDES = \ + $(LOCAL_PATH)/../coreapi \ + $(LOCAL_PATH)/../oRTP/include \ + $(LOCAL_PATH)/../mediastreamer2/include \ + $(LOCAL_PATH)/../../externals/libxml2/include \ + $(LOCAL_PATH)/../../externals/build/libxml2 \ + +LOCAL_SHARED_LIBRARIES = \ + libxml2 \ + liblinphone \ + +LOCAL_MODULE := libxml2lpc + +include $(BUILD_SHARED_LIBRARY) diff --git a/configure.ac b/configure.ac index 993efa200..db0273616 100644 --- a/configure.ac +++ b/configure.ac @@ -46,12 +46,12 @@ AM_CONDITIONAL(HAVE_MD5SUM,test -n $MD5SUM) case $target in *mingw32ce) - CFLAGS="$CFLAGS -D_WIN32_WCE -DORTP_STATIC -D_WIN32_WINNT=0x0501" - CXXFLAGS="$CXXFLAGS -DORTP_STATIC -D_WIN32_WINNT=0x0501" - LIBS="$LIBS -lws2 -liphlpapi" + CFLAGS="$CFLAGS -D_WIN32_WCE -DORTP_STATIC -D_WIN32_WINNT=0x0501" + CXXFLAGS="$CXXFLAGS -DORTP_STATIC -D_WIN32_WINNT=0x0501" + LIBS="$LIBS -lws2 -liphlpapi" mingw_found=yes mingwce_found=yes - ;; + ;; *mingw*) CFLAGS="$CFLAGS -DORTP_STATIC -D_WIN32_WINNT=0x0501 " CXXFLAGS="$CXXFLAGS -DORTP_STATIC -D_WIN32_WINNT=0x0501" @@ -60,17 +60,17 @@ case $target in CONSOLE_FLAGS="-mconsole" mingw_found=yes ;; - armv6-apple-darwin|armv7-apple-darwin|i386-apple-darwin|armv7s-apple-darwin) - CFLAGS="$CFLAGS -DTARGET_OS_IPHONE " - build_tests=no - ios_found=yes - ;; - x86_64-apple-darwin*|i686-apple-darwin*) - MSPLUGINS_CFLAGS="" + armv6-apple-darwin|armv7-apple-darwin|i386-apple-darwin|armv7s-apple-darwin) + CFLAGS="$CFLAGS -DTARGET_OS_IPHONE " + build_tests=no + ios_found=yes + ;; + x86_64-apple-darwin*|i686-apple-darwin*) + MSPLUGINS_CFLAGS="" dnl use macport installation ACLOCAL_MACOS_FLAGS="-I /opt/local/share/aclocal" build_macos=yes - ;; + ;; esac @@ -82,30 +82,34 @@ dnl localization tools IT_PROG_INTLTOOL([0.40], [no-xml]) AM_CONDITIONAL(BUILD_TESTS,test x$build_tests != xno) + dnl Initialize libtool LT_INIT([win32-dll shared disable-static]) + dnl Enable library dependencies linking AC_ARG_ENABLE(deplibs-link, - [AS_HELP_STRING([--disable-deplibs-link ], [Disable library dependencies linking (might break builds)])], - [enable_deplibs_linking="$enableval"], - [enable_deplibs_linking="yes"]) + [AS_HELP_STRING([--disable-deplibs-link ], [Disable library dependencies linking (might break builds)])], + [enable_deplibs_linking="$enableval"], + [enable_deplibs_linking="yes"] +) AC_MSG_NOTICE([Enable library dependencies linking: $enable_interlib_deps]) if test "${enable_deplibs_linking}" == "yes"; then - link_all_deplibs=yes - link_all_deplibs_CXX=yes + link_all_deplibs=yes + link_all_deplibs_CXX=yes else - link_all_deplibs=no - link_all_deplibs_CXX=no + link_all_deplibs=no + link_all_deplibs_CXX=no fi -AC_CONFIG_COMMANDS([libtool-hacking],[ -if test "$mingw_found" = "yes" ; then - echo "Hacking libtool to work with mingw..." - sed -e 's/\*\" \$a_deplib \"\*/\*/' < ./libtool > libtool.tmp - cp -f ./libtool.tmp ./libtool - rm -f ./libtool.tmp -fi -],[mingw_found=$mingw_found]) +AC_CONFIG_COMMANDS([libtool-hacking], + [if test "$mingw_found" = "yes" ; then + echo "Hacking libtool to work with mingw..." + sed -e 's/\*\" \$a_deplib \"\*/\*/' < ./libtool > libtool.tmp + cp -f ./libtool.tmp ./libtool + rm -f ./libtool.tmp + fi], + [mingw_found=$mingw_found] +) dnl Add the languages which your application supports here. PKG_PROG_PKG_CONFIG @@ -136,57 +140,91 @@ dnl AC_CHECK_LIB(intl,libintl_gettext) AC_CHECK_FUNCS([get_current_dir_name strndup stpcpy] ) AC_ARG_ENABLE(x11, - [AS_HELP_STRING([--disable-x11], [Disable X11 support (default=no)])], - [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, - [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]) + [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]) + [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 for installed version of libupnp +AC_ARG_ENABLE(upnp, + [AS_HELP_STRING([--disable-upnp], [Disable uPnP support])], + [case "${enableval}" in + yes) build_upnp=true ;; + no) build_upnp=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-upnp) ;; + esac], + [build_upnp=auto] +) + +if test "$build_upnp" != "false" ; then + PKG_CHECK_MODULES([LIBUPNP], [libupnp], [build_upnp=true], + [if test "$build_upnp" == "true" ; then + AC_MSG_ERROR([libupnp not found.]) + else + build_upnp=false + fi] + ) + +fi + +AM_CONDITIONAL(BUILD_UPNP, test x$build_upnp != xfalse) +if test "$build_upnp" != "false" ; then + AC_DEFINE(BUILD_UPNP, 1, [Define if upnp enabled]) +fi 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 + [if test "$build_tools" = "true" ; then AC_MSG_ERROR([Could not found libxml2, tools cannot be compiled.]) else build_tools=false - fi - ]) + 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] ) + build_tools=true + AC_DEFINE(BUILD_TOOLS, 1, [Define if tools enabled] ) fi dnl conditionnal build of gtk interface. AC_ARG_ENABLE(gtk_ui, - [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 ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-gtk_ui) ;; - esac],[gtk_ui=true]) + [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 ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-gtk_ui) ;; + esac], + [gtk_ui=true] +) if test "$gtk_ui" = "true" ; then PKG_CHECK_MODULES(LIBGTK, gtk+-2.0 >= 2.18.0 gthread-2.0) @@ -199,33 +237,35 @@ else fi AC_ARG_ENABLE(notify, - [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]) + [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 if test "$notify" = "true"; then PKG_CHECK_MODULES([NOTIFY4], [libnotify >= 0.7.0 ], [found_notify4=yes], foo=bar) case "$found_notify4" in - yes) + yes) AC_SUBST(NOTIFY4_CFLAGS) AC_SUBST(NOTIFY4_LIBS) AC_DEFINE([HAVE_NOTIFY4],[1],[NOTIFY4 support]) esac - PKG_CHECK_MODULES([NOTIFY1], [libnotify < 0.7.0], [found_notify1=yes], foo=bar) - case "$found_notify1" in - yes) - AC_SUBST(NOTIFY1_CFLAGS) - AC_SUBST(NOTIFY1_LIBS) - AC_DEFINE([HAVE_NOTIFY1],[1],[NOTIFY1 support]) - esac + PKG_CHECK_MODULES([NOTIFY1], [libnotify < 0.7.0], [found_notify1=yes], foo=bar) + case "$found_notify1" in + yes) + AC_SUBST(NOTIFY1_CFLAGS) + AC_SUBST(NOTIFY1_LIBS) + AC_DEFINE([HAVE_NOTIFY1],[1],[NOTIFY1 support]) + esac else - NotifyNotification *n; + NotifyNotification *n; echo "Libnotify support is disabled." fi fi @@ -234,37 +274,41 @@ dnl os-specific problems not handled by existing macros. case "$host_os" in *freebsd*) LDFLAGS="$LDFLAGS -pthread" - ;; + ;; esac case "$host_cpu" in *arm*) AC_DEFINE(__ARM__,1,[Defined if we are compiling for arm processor]) use_arm_toolchain=yes - ;; + ;; esac 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" ]) + [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, - [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 ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-relativeprefix) ;; - esac],[relativeprefix=guess]) + [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 ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-relativeprefix) ;; + esac], + [relativeprefix=guess] +) AC_ARG_ENABLE(date, - [AS_HELP_STRING([--enable-date], [Use build date in internal version number])], - [case "${enableval}" in - yes) use_date=yes ;; - no) use_date=no ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-date) ;; - esac],[use_date=no]) + [AS_HELP_STRING([--enable-date], [Use build date in internal version number])], + [case "${enableval}" in + yes) use_date=yes ;; + no) use_date=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-date) ;; + esac], + [use_date=no] +) if test x$use_date = xyes ; then AC_DEFINE(USE_BUILDDATE_VERSION,1,[Tell whether date_version.h must be used]) @@ -273,12 +317,14 @@ fi dnl enable ipv6 support AC_ARG_ENABLE(ipv6, - [AS_HELP_STRING([--enable-ipv6], [Turn on ipv6 support])], - [case "${enableval}" in - yes) ipv6=true;; - no) ipv6=false;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-ipv6) ;; - esac],[ipv6=true]) + [AS_HELP_STRING([--enable-ipv6], [Turn on ipv6 support])], + [case "${enableval}" in + yes) ipv6=true;; + no) ipv6=false;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-ipv6) ;; + esac], + [ipv6=true] +) IPV6_CFLAGS= if test x$ipv6 = xtrue ; then IPV6_CFLAGS=-DINET6 @@ -287,29 +333,35 @@ AC_SUBST(IPV6_CFLAGS) dnl enable timestamp support AC_ARG_ENABLE(ntp-timestamp, - [AS_HELP_STRING([--enable-ntp-timestamp], [Turn on NTP timestamping on received packet])], - [case "${enableval}" in - yes) ntptimestamp=true;; - no) ntptimestamp=false;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-ntp-timestamp) ;; - esac],[ntptimestamp=false]) + [AS_HELP_STRING([--enable-ntp-timestamp], [Turn on NTP timestamping on received packet])], + [case "${enableval}" in + yes) ntptimestamp=true;; + no) ntptimestamp=false;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-ntp-timestamp) ;; + esac], + [ntptimestamp=false] +) AC_ARG_ENABLE(debug, - [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]) + [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, - [AS_HELP_STRING([--enable-truespeech], [Turn on TrueSpeech support (x86 only)])], - [case "${enableval}" in - yes) truespeech=true;; - no) truespeech=false;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-truespeech) ;; - esac],[truespeech=false]) + [AS_HELP_STRING([--enable-truespeech], [Turn on TrueSpeech support (x86 only)])], + [case "${enableval}" in + yes) truespeech=true;; + no) truespeech=false;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-truespeech) ;; + esac], + [truespeech=false] +) TRUESPEECH_CFLAGS= if test x$truespeech = xtrue ; then TRUESPEECH_CFLAGS=-DTRUESPEECH @@ -318,21 +370,24 @@ AC_SUBST(TRUESPEECH_CFLAGS) AM_CONDITIONAL([BUILD_TRUESPEECH], [test x$truespeech = xtrue]) AC_ARG_ENABLE(nonstandard-gsm, - [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]) - ;; - no) exotic_gsm=no ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-nonstandard-gsm) ;; - esac],[exotic_gsm=no]) + [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]) + ;; + no) exotic_gsm=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-nonstandard-gsm) ;; + esac], + [exotic_gsm=no] +) dnl support for RSVP (by Vincent Maury) AC_ARG_ENABLE(rsvp, -[AS_HELP_STRING([--enable-rsvp], [Enable support for QoS reservations.])], -AC_DEFINE(VINCENT_MAURY_RSVP,1,[Tell whether RSVP support -should be compiled.]) ) + [AS_HELP_STRING([--enable-rsvp], [Enable support for QoS reservations.])], + AC_DEFINE(VINCENT_MAURY_RSVP,1,[Tell whether RSVP support should be compiled.]) +) if test "x${prefix}" = "xNONE"; then package_prefix=${ac_default_prefix} @@ -369,12 +424,14 @@ LP_CHECK_OSIP2 dnl conditionnal build for ssl AC_ARG_ENABLE(ssl, - [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]) + [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) @@ -385,26 +442,30 @@ LP_SETUP_EXOSIP dnl check exosip support of DSCP in exosip AC_MSG_CHECKING([for DSCP support in exosip]) AC_TRY_COMPILE([#include ], -[int dscp=0;eXosip_set_option(EXOSIP_OPT_SET_DSCP,&dscp);], -has_exosip_dscp=yes,has_exosip_dscp=no) + [int dscp=0;eXosip_set_option(EXOSIP_OPT_SET_DSCP,&dscp);], + has_exosip_dscp=yes, + has_exosip_dscp=no +) AC_MSG_RESULT($has_exosip_dscp) if test "$has_exosip_dscp" = "yes" ; then - AC_DEFINE( HAVE_EXOSIP_DSCP, 1, [Define if exosip dscp available] ) + AC_DEFINE( HAVE_EXOSIP_DSCP, 1, [Define if exosip dscp available] ) fi if test "$console_ui" = "true" ; then -dnl check gnu readline -LP_CHECK_READLINE + dnl check gnu readline + LP_CHECK_READLINE else -echo "Console interface compilation is disabled." + echo "Console interface compilation is disabled." fi AC_WORDS_BIGENDIAN AC_ARG_ENABLE([speex], - AS_HELP_STRING([--disable-speex], [Disable speex support]), - [], [enable_speex=yes]) + AS_HELP_STRING([--disable-speex], [Disable speex support]), + [], + [enable_speex=yes] +) if test "x$enable_speex" = "xyes"; then dnl normaly this should only by done by mediastreamer2/configure.ac dnl but to workaround bugs when cross-compiling for arm-linux, @@ -416,16 +477,20 @@ fi dnl conditionnal build of video support AC_ARG_ENABLE(video, - [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]) + [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, - [AS_HELP_STRING([--with-ffmpeg], [Sets the installation prefix of ffmpeg, needed for video support. (default=/usr)])], - [ ffmpegdir=${withval}],[ ffmpegdir=/usr ]) +AC_ARG_WITH(ffmpeg, + [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 @@ -442,29 +507,35 @@ if test "$video" = "true"; then fi AC_ARG_ENABLE(alsa, - [AS_HELP_STRING([--enable-alsa], [Turn on alsa native support compiling])], - [case "${enableval}" in - yes) alsa=true ;; - no) alsa=false ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-alsa) ;; - esac],[alsa=true]) + [AS_HELP_STRING([--enable-alsa], [Turn on alsa native support compiling])], + [case "${enableval}" in + yes) alsa=true ;; + no) alsa=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-alsa) ;; + esac], + [alsa=true] +) AC_ARG_ENABLE(zrtp, - [AS_HELP_STRING([--enable-zrtp], [Turn on zrtp support])], - [case "${enableval}" in - yes) zrtp=true ;; - no) zrtp=false ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-zrtp) ;; - esac],[zrtp=false]) + [AS_HELP_STRING([--enable-zrtp], [Turn on zrtp support])], + [case "${enableval}" in + yes) zrtp=true ;; + no) zrtp=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-zrtp) ;; + esac], + [zrtp=false] +) AC_ARG_ENABLE(portaudio, - [AS_HELP_STRING([--enable-portaudio], [Turn on portaudio native support compiling])], - [case "${enableval}" in - yes) portaudio=true ;; - no) portaudio=false ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-portaudio) ;; - esac],[portaudio=false]) + [AS_HELP_STRING([--enable-portaudio], [Turn on portaudio native support compiling])], + [case "${enableval}" in + yes) portaudio=true ;; + no) portaudio=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-portaudio) ;; + esac], + [portaudio=false] +) dnl build console if required AM_CONDITIONAL(BUILD_CONSOLE, test x$console_ui = xtrue) @@ -487,44 +558,44 @@ AC_TRY_COMPILE([#include ],[sighandler_t *f;], has_sighandler_t=yes,has_sighandler_t=no) AC_MSG_RESULT($has_sighandler_t) if test "$has_sighandler_t" = "yes" ; then - AC_DEFINE( HAVE_SIGHANDLER_T, 1, [Define if sighandler_t available] ) + AC_DEFINE( HAVE_SIGHANDLER_T, 1, [Define if sighandler_t available] ) fi AC_ARG_ENABLE(assistant, - [AS_HELP_STRING([--enable-assistant], [Turn on assistant compiling])], - [case "${enableval}" in - yes) build_wizard=true ;; - no) build_wizard=false ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-assistant) ;; - esac],[build_wizard=check]) + [AS_HELP_STRING([--enable-assistant], [Turn on assistant compiling])], + [case "${enableval}" in + yes) build_wizard=true ;; + no) build_wizard=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-assistant) ;; + esac], + [build_wizard=check] +) dnl check libsoup (needed for wizard) if test "$build_wizard" != "false" ; then PKG_CHECK_MODULES(LIBSOUP, [libsoup-2.4 >= 2.26],[], - [ - if test "$build_wizard" = "true" ; then + [if test "$build_wizard" = "true" ; then AC_MSG_ERROR([Could not found libsoup, assistant cannot be compiled.]) else build_wizard=false - fi - ]) + fi] + ) fi if test "$build_wizard" != "false" ; then PKG_CHECK_MODULES(LIBGTKWIZARD, [gtk+-2.0 >= 2.22.0],[], - [ - if test "$build_wizard" = "true" ; then + [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] + ) fi AC_SUBST(LIBSOUP_CFLAGS) AC_SUBST(LIBSOUP_LIBS) 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] ) + build_wizard=true + AC_DEFINE(BUILD_WIZARD, 1, [Define if wizard enabled] ) fi AC_CHECK_HEADERS(libudev.h) @@ -536,9 +607,9 @@ AC_CHECK_LIB(udev,udev_new) AC_ARG_ENABLE(strict, - AC_HELP_STRING([--enable-strict], - [Build with stricter options (gcc only) @<:@yes@:>@]),[ - strictness="${enableval}"],[strictness=yes] + AC_HELP_STRING([--enable-strict], [Build with stricter options (gcc only) @<:@yes@:>@]), + [strictness="${enableval}"], + [strictness=yes] ) STRICT_OPTIONS="-Wall " @@ -553,26 +624,26 @@ AC_SUBST(STRICT_OPTIONS) top_srcdir=`dirname $0` AC_ARG_ENABLE([external-mediastreamer], - [AS_HELP_STRING([--enable-external-mediastreamer],[Use external mediastreamer library])],, - [enable_external_mediastreamer=no]) + [AS_HELP_STRING([--enable-external-mediastreamer],[Use external mediastreamer library])],, + [enable_external_mediastreamer=no] +) AS_CASE($enable_external_mediastreamer, - [yes],[ - PKG_CHECK_MODULES([MEDIASTREAMER], [mediastreamer]) - MS2_VERSION=`$PKG_CONFIG --modversion mediastreamer` - ], - [no],[ - AC_CONFIG_SUBDIRS( mediastreamer2 ) - MEDIASTREAMER_DIR=${top_srcdir}/mediastreamer2 - MEDIASTREAMER_CFLAGS="-I\$(top_srcdir)/mediastreamer2/include" - MEDIASTREAMER_LIBS="\$(top_builddir)/mediastreamer2/src/libmediastreamer_base.la \$(top_builddir)/mediastreamer2/src/libmediastreamer_voip.la" + [yes], + [PKG_CHECK_MODULES([MEDIASTREAMER], [mediastreamer]) + MS2_VERSION=`$PKG_CONFIG --modversion mediastreamer`], + [no], + [AC_CONFIG_SUBDIRS( mediastreamer2 ) + MEDIASTREAMER_DIR=${top_srcdir}/mediastreamer2 + MEDIASTREAMER_CFLAGS="-I\$(top_srcdir)/mediastreamer2/include" + MEDIASTREAMER_LIBS="\$(top_builddir)/mediastreamer2/src/libmediastreamer_base.la \$(top_builddir)/mediastreamer2/src/libmediastreamer_voip.la" dnl need to temporary change quotes to allow square brackets - changequote(<<, >>) - MS2_VERSION=`grep -e '^.C_INIT(' $MEDIASTREAMER_DIR/configure.ac | sed -e 's:\([^(]\+\)(\[mediastreamer\],\[\(.*\)\]):\2:g'` - changequote([, ]) - MS2_DIR=mediastreamer2 - ], - [AC_MSG_ERROR([bad value '${enable_external_mediastreamer}' for --enable-external-mediastreamer])]) + changequote(<<, >>) + MS2_VERSION=`grep -e '^.C_INIT(' $MEDIASTREAMER_DIR/configure.ac | sed -e 's:\([^(]\+\)(\[mediastreamer\],\[\(.*\)\]):\2:g'` + changequote([, ]) + MS2_DIR=mediastreamer2], + [AC_MSG_ERROR([bad value '${enable_external_mediastreamer}' for --enable-external-mediastreamer])] +) AC_SUBST(MEDIASTREAMER_CFLAGS) AC_SUBST(MEDIASTREAMER_LIBS) @@ -582,18 +653,20 @@ AC_SUBST([MS2_DIR]) AC_ARG_ENABLE(tunnel, - [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 ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-tunnel) ;; - esac],[enable_tunnel=false]) + [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 ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-tunnel) ;; + esac], + [enable_tunnel=false] +) AM_CONDITIONAL(BUILD_TUNNEL, test x$enable_tunnel = xtrue) if test x$enable_tunnel = xtrue; then - PKG_CHECK_MODULES(TUNNEL, tunnel >= 0.3.3) - TUNNEL_CFLAGS+="-DTUNNEL_ENABLED" - AC_SUBST(TUNNEL_CFLAGS) - AC_SUBST(TUNNEL_LIBS) + PKG_CHECK_MODULES(TUNNEL, tunnel >= 0.3.3) + TUNNEL_CFLAGS+="-DTUNNEL_ENABLED" + AC_SUBST(TUNNEL_CFLAGS) + AC_SUBST(TUNNEL_LIBS) fi SIPSTACK_CFLAGS= @@ -620,7 +693,7 @@ AC_SUBST(SIPSTACK_CFLAGS) AC_SUBST(SIPSTACK_LIBS) dnl check for db2html (docbook) to generate html user manual -AC_CHECK_PROG(have_sgmltools,sgmltools, yes, no) +AC_CHECK_PROG(have_sgmltools, sgmltools, yes, no) AM_CONDITIONAL(ENABLE_MANUAL, test x$have_sgmltools$build_manual = xyesyes ) dnl for external use of linphone libs @@ -633,19 +706,21 @@ fi AC_SUBST(LINPHONE_CFLAGS) AC_SUBST(LINPHONE_LIBS) -AC_DEFINE_UNQUOTED(LINPHONE_VERSION,"$PACKAGE_VERSION",[Linphone's version number]) +AC_DEFINE_UNQUOTED(LINPHONE_VERSION, "$PACKAGE_VERSION", [Linphone\'s version number]) AC_DEFINE_UNQUOTED(LINPHONE_PLUGINS_DIR, "${package_prefix}/lib/liblinphone/plugins" ,[path of liblinphone plugins, not mediastreamer2 plugins]) LINPHONE_PLUGINS_DIR="${package_prefix}/lib/liblinphone/plugins" AC_SUBST(LINPHONE_PLUGINS_DIR) AC_ARG_ENABLE(external-ortp, - [AS_HELP_STRING([--enable-external-ortp], [Use external oRTP library])], - [case "${enableval}" in - yes) external_ortp=true ;; - no) external_ortp=false ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-external-ortp) ;; - esac],[external_ortp=false]) + [AS_HELP_STRING([--enable-external-ortp], [Use external oRTP library])], + [case "${enableval}" in + yes) external_ortp=true ;; + no) external_ortp=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-external-ortp) ;; + esac], + [external_ortp=false] +) if test "$external_ortp" = 'true'; then PKG_CHECK_MODULES([ORTP], [ortp]) @@ -658,7 +733,7 @@ else ORTP_CFLAGS="$ORTP_CFLAGS -DORTP_BIGENDIAN" fi if test x$ntptimestamp = xtrue ; then - ORTP_CFLAGS="$ORTP_CFLAGS -DORTP_TIMESTAMP" + ORTP_CFLAGS="$ORTP_CFLAGS -DORTP_TIMESTAMP" fi ORTP_DIR=oRTP changequote(<<, >>) @@ -671,12 +746,14 @@ AC_SUBST([ORTP_VERSION]) AC_SUBST([ORTP_DIR]) AC_ARG_ENABLE(tests_enabled, - [AS_HELP_STRING([--disable-tests], [Disable compilation of tests])], - [case "${enableval}" in - yes) tests_enabled=true ;; - no) tests_enabled=false ;; - *) AC_MSG_ERROR(bad value ${enableval} for --disable-tests) ;; - esac],[tests_enabled=false]) + [AS_HELP_STRING([--disable-tests], [Disable compilation of tests])], + [case "${enableval}" in + yes) tests_enabled=true ;; + no) tests_enabled=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-tests) ;; + esac], + [tests_enabled=false] +) AM_CONDITIONAL(ENABLE_TESTS, test x$tests_enabled = xyes) PKG_CHECK_MODULES(CUNIT, cunit, [found_cunit=yes],[found_cunit=no]) @@ -709,44 +786,44 @@ AM_CONDITIONAL(HAVE_DOXYGEN, test $DOXYGEN != false) AC_CONFIG_FILES([ -Makefile -build/Makefile -build/macos/Makefile -build/macos/Info-linphone.plist -m4/Makefile -po/Makefile.in -pixmaps/Makefile -coreapi/Makefile -tester/Makefile -coreapi/help/Makefile -coreapi/help/Doxyfile -gtk/Makefile -console/Makefile -share/Makefile -share/C/Makefile -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 + Makefile + build/Makefile + build/macos/Makefile + build/macos/Info-linphone.plist + m4/Makefile + po/Makefile.in + pixmaps/Makefile + coreapi/Makefile + coreapi/help/Makefile + coreapi/help/Doxyfile + tester/Makefile + gtk/Makefile + console/Makefile + share/Makefile + share/C/Makefile + 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 ]) AC_OUTPUT echo "Linphone build configuration ended." echo "Summary of build options:" -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 +printf "* %-30s %s\n" "Video support" $video +printf "* %-30s %s\n" "GTK interface" $gtk_ui +printf "* %-30s %s\n" "Account assistant" $build_wizard +printf "* %-30s %s\n" "Console interface" $console_ui +printf "* %-30s %s\n" "Tools" $build_tools +printf "* %-30s %s\n" "zRTP encryption (GPLv3)" $zrtp if test "$enable_tunnel" = "true" ; then printf "* Tunnel support\t\ttrue\n" diff --git a/console/commands.c b/console/commands.c index 472531795..3ec2ed65b 100644 --- a/console/commands.c +++ b/console/commands.c @@ -206,7 +206,7 @@ static LPC_COMMAND commands[] = { { "autoanswer", lpc_cmd_autoanswer, "Show/set auto-answer mode", "'autoanswer' \t: show current autoanswer mode\n" "'autoanswer enable'\t: enable autoanswer mode\n" - "'autoanswer disable'\t: disable autoanswer mode \n"}, + "'autoanswer disable'\t: disable autoanswer mode��\n"}, { "proxy", lpc_cmd_proxy, "Manage proxies", "'proxy list' : list all proxy setups.\n" "'proxy add' : add a new proxy setup.\n" @@ -896,6 +896,9 @@ lpc_cmd_firewall(LinphoneCore *lc, char *args) case LinphonePolicyUseIce: linphonec_out("Using ice with stun server %s to discover firewall address\n", setting ? setting : linphone_core_get_stun_server(lc)); break; + case LinphonePolicyUseUpnp: + linphonec_out("Using uPnP IGD protocol\n"); + break; } return 1; } diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 0d774b686..dd8136f67 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -44,8 +44,11 @@ liblinphone_la_SOURCES=\ lsd.c linphonecore_utils.h \ ec-calibrator.c \ conference.c \ - linphone_tunnel.cc \ $(GITVERSION_FILE) + +if BUILD_UPNP +liblinphone_la_SOURCES+=upnp.c upnp.h +endif if USE_BELLESIP liblinphone_la_SOURCES+= bellesip_sal/sal_address_impl.c \ @@ -65,8 +68,11 @@ if BUILD_WIZARD liblinphone_la_SOURCES+=sipwizard.c endif +liblinphone_la_SOURCES+=linphone_tunnel_config.c if BUILD_TUNNEL -liblinphone_la_SOURCES+=TunnelManager.cc TunnelManager.hh +liblinphone_la_SOURCES+=linphone_tunnel.cc TunnelManager.cc TunnelManager.hh +else +liblinphone_la_SOURCES+=linphone_tunnel_stubs.c endif diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 9a2f90790..2b48c2329 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -39,17 +39,15 @@ static void sdp_process(SalOp *h){ strcpy(h->result->addr,h->base.remote_media->addr); h->result->bandwidth=h->base.remote_media->bandwidth; - for(i=0;iresult->nstreams;++i){ - if (h->result->streams[i].rtp_port>0){ - /*fixme add rtcp*/ - strcpy(h->result->streams[i].rtp_addr,h->base.remote_media->streams[i].rtp_addr); - h->result->streams[i].ptime=h->base.remote_media->streams[i].ptime; - h->result->streams[i].bandwidth=h->base.remote_media->streams[i].bandwidth; - h->result->streams[i].rtp_port=h->base.remote_media->streams[i].rtp_port; + for(i=0;iresult->n_active_streams;++i){ + /*fixme add rtcp*/ + strcpy(h->result->streams[i].rtp_addr,h->base.remote_media->streams[i].rtp_addr); + h->result->streams[i].ptime=h->base.remote_media->streams[i].ptime; + h->result->streams[i].bandwidth=h->base.remote_media->streams[i].bandwidth; + h->result->streams[i].rtp_port=h->base.remote_media->streams[i].rtp_port; - if (h->result->streams[i].proto == SalProtoRtpSavp) { - h->result->streams[i].crypto[0] = h->base.remote_media->streams[i].crypto[0]; - } + if (h->result->streams[i].proto == SalProtoRtpSavp) { + h->result->streams[i].crypto[0] = h->base.remote_media->streams[i].crypto[0]; } } } diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 2c7e86ca3..06a93d2e6 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -65,7 +65,7 @@ belle_sdp_session_description_t * media_description_to_sdp(const SalMediaDescrip belle_sdp_session_description_set_bandwidth(session_desc,"AS",desc->bandwidth); } - for (i=0; instreams;i++) { + for (i=0; in_total_streams;i++) { media_desc = belle_sdp_media_description_create(sal_stream_type_to_string(desc->streams[i].type) ,desc->streams[i].rtp_port ,1 @@ -168,7 +168,8 @@ int sdp_to_media_description(belle_sdp_session_description_t *session_desc, Sal char tmp[256], tmp2[256]; int nb=0; - desc->nstreams=0; + desc->n_active_streams = 0; + desc->n_total_streams = 0; if ((cnx=belle_sdp_session_description_get_connection(session_desc)) && belle_sdp_connection_get_address(cnx)) { strncpy(desc->addr,belle_sdp_connection_get_address(cnx),sizeof(desc->addr)); @@ -180,7 +181,7 @@ int sdp_to_media_description(belle_sdp_session_description_t *session_desc, Sal ;media_desc_it!=NULL ;media_desc_it=media_desc_it->next) { media_desc=BELLE_SDP_MEDIA_DESCRIPTION(media_desc_it->data); - stream=&desc->streams[desc->nstreams]; + stream=&desc->streams[desc->n_total_streams]; media=belle_sdp_media_description_get_media(media_desc); memset(stream,0,sizeof(*stream)); @@ -199,6 +200,8 @@ int sdp_to_media_description(belle_sdp_session_description_t *session_desc, Sal } stream->rtp_port=belle_sdp_media_get_media_port(media); + if (stream->rtp_port > 0) + desc->n_active_streams++; mtype = belle_sdp_media_get_media_type(media); if (strcasecmp("audio", mtype) == 0){ @@ -288,7 +291,7 @@ int sdp_to_media_description(belle_sdp_session_description_t *session_desc, Sal } ms_message("Found: %d valid crypto lines", valid_count); } - desc->nstreams++; + desc->n_total_streams++; } return 0; diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 6ceac5c51..6b215b0da 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -41,14 +41,14 @@ void linphone_core_update_streams_destinations(LinphoneCore *lc, LinphoneCall *c char *rtp_addr, *rtcp_addr; int i; - for (i = 0; i < old_md->nstreams; i++) { + for (i = 0; i < old_md->n_active_streams; 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++) { + for (i = 0; i < new_md->n_active_streams; i++) { if (new_md->streams[i].type == SalAudio) { new_audiodesc = &new_md->streams[i]; } else if (new_md->streams[i].type == SalVideo) { @@ -261,6 +261,13 @@ static void call_received(SalOp *h){ ms_message("Defer ringing to gather ICE candidates"); return; } +#ifdef BUILD_UPNP + if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseUpnp) && (call->upnp_session != NULL)) { + /* Defer ringing until the end of the ICE candidates gathering process. */ + ms_message("Defer ringing to gather uPnP candidates"); + return; + } +#endif //BUILD_UPNP linphone_core_notify_incoming_call(lc,call); } @@ -334,6 +341,11 @@ static void call_accepted(SalOp *op){ if (call->ice_session != NULL) { linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op)); } +#ifdef BUILD_UPNP + if (call->upnp_session != NULL) { + linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(op)); + } +#endif //BUILD_UPNP md=sal_call_get_final_media_description(op); call->params.has_video &= linphone_core_media_description_contains_video_stream(md); @@ -426,6 +438,12 @@ static void call_accept_update(LinphoneCore *lc, LinphoneCall *call){ linphone_core_update_ice_from_remote_media_description(call,rmd); linphone_core_update_local_media_description_from_ice(call->localdesc,call->ice_session); } +#ifdef BUILD_UPNP + if(call->upnp_session != NULL) { + linphone_core_update_upnp_from_remote_media_description(call, rmd); + linphone_core_update_local_media_description_from_upnp(call->localdesc,call->upnp_session); + } +#endif //BUILD_UPNP linphone_call_update_remote_session_id_and_ver(call); sal_call_accept(call->op); md=sal_call_get_final_media_description(call->op); @@ -522,6 +540,10 @@ static void call_terminated(SalOp *op, const char *from){ if (lc->vtable.display_status!=NULL) lc->vtable.display_status(lc,_("Call terminated.")); +#ifdef BUILD_UPNP + linphone_call_delete_upnp_session(call); +#endif //BUILD_UPNP + linphone_call_set_state(call, LinphoneCallEnd,"Call ended"); } @@ -591,7 +613,7 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de if (call->state==LinphoneCallOutgoingInit || call->state==LinphoneCallOutgoingProgress){ /* clear SRTP local params */ call->params.media_encryption = LinphoneMediaEncryptionNone; - for(i=0; ilocaldesc->nstreams; i++) { + for(i=0; ilocaldesc->n_active_streams; i++) { call->localdesc->streams[i].proto = SalProtoRtpAvp; memset(call->localdesc->streams[i].crypto, 0, sizeof(call->localdesc->streams[i].crypto)); } @@ -618,12 +640,20 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de /*resume to the call that send us the refer automatically*/ linphone_core_resume_call(lc,call->referer); } + +#ifdef BUILD_UPNP + linphone_call_delete_upnp_session(call); +#endif //BUILD_UPNP + if (sr == SalReasonDeclined) { call->reason=LinphoneReasonDeclined; linphone_call_set_state(call,LinphoneCallEnd,"Call declined."); } else if (sr == SalReasonNotFound) { call->reason=LinphoneReasonNotFound; linphone_call_set_state(call,LinphoneCallError,"User not found."); + } else if (sr == SalReasonBusy) { + call->reason=LinphoneReasonBusy; + linphone_call_set_state(call,LinphoneCallError,"User is busy."); } else { linphone_call_set_state(call,LinphoneCallError,msg); } @@ -815,7 +845,7 @@ static bool_t is_duplicate_msg(LinphoneCore *lc, const char *msg_id){ static void text_received(Sal *sal, const SalMessage *msg){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal); if (is_duplicate_msg(lc,msg->message_id)==FALSE){ - linphone_core_message_received(lc,msg->from,msg->text,msg->url); + linphone_core_message_received(lc,msg); } } diff --git a/coreapi/chat.c b/coreapi/chat.c index 00f237377..c502efa9f 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -103,13 +103,13 @@ void linphone_chat_room_message_received(LinphoneChatRoom *cr, LinphoneCore *lc, } -void linphone_core_message_received(LinphoneCore *lc, const char *from, const char *raw_msg,const char* external_url){ +void linphone_core_message_received(LinphoneCore *lc, const SalMessage *sal_msg){ MSList *elem; LinphoneChatRoom *cr=NULL; LinphoneAddress *addr; char *cleanfrom; LinphoneChatMessage* msg; - addr=linphone_address_new(from); + addr=linphone_address_new(sal_msg->from); linphone_address_clean(addr); for(elem=lc->chatrooms;elem!=NULL;elem=ms_list_next(elem)){ cr=(LinphoneChatRoom*)elem->data; @@ -123,10 +123,12 @@ void linphone_core_message_received(LinphoneCore *lc, const char *from, const ch /* create a new chat room */ cr=linphone_core_create_chat_room(lc,cleanfrom); } - msg = linphone_chat_room_create_message(cr, raw_msg); + msg = linphone_chat_room_create_message(cr, sal_msg->text); linphone_chat_message_set_from(msg, cr->peer_url); - if (external_url) { - linphone_chat_message_set_external_body_url(msg, external_url); + msg->time=sal_msg->time; + + if (sal_msg->url) { + linphone_chat_message_set_external_body_url(msg, sal_msg->url); } linphone_address_destroy(addr); linphone_chat_room_message_received(cr,lc,msg); @@ -221,6 +223,11 @@ void linphone_chat_message_set_from(LinphoneChatMessage* message, const Linphone LinphoneAddress* linphone_chat_message_get_from(const LinphoneChatMessage* message) { return message->from; } + +time_t linphone_chat_message_get_time(const LinphoneChatMessage* message) { + return message->time; +} + const char * linphone_chat_message_get_text(const LinphoneChatMessage* message) { return message->message; } diff --git a/coreapi/linphone_tunnel.cc b/coreapi/linphone_tunnel.cc index c76441f5a..f0de56694 100644 --- a/coreapi/linphone_tunnel.cc +++ b/coreapi/linphone_tunnel.cc @@ -23,9 +23,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifdef TUNNEL_ENABLED #include "TunnelManager.hh" -#endif #include "linphone_tunnel.h" #include "linphonecore.h" #include "private.h" @@ -35,67 +33,6 @@ LinphoneTunnel* linphone_core_get_tunnel(LinphoneCore *lc){ return lc->tunnel; } -struct _LinphoneTunnelConfig { - char *host; - int port; - int remote_udp_mirror_port; - int delay; -}; - -LinphoneTunnelConfig *linphone_tunnel_config_new() { - LinphoneTunnelConfig *ltc = ms_new0(LinphoneTunnelConfig,1); - ltc->remote_udp_mirror_port = 12345; - ltc->delay = 1000; - return ltc; -} - -void linphone_tunnel_config_set_host(LinphoneTunnelConfig *tunnel, const char *host) { - if(tunnel->host != NULL) { - ms_free(tunnel->host); - tunnel->host = NULL; - } - if(host != NULL && strlen(host)) { - tunnel->host = ms_strdup(host); - } -} - -const char *linphone_tunnel_config_get_host(LinphoneTunnelConfig *tunnel) { - return tunnel->host; -} - -void linphone_tunnel_config_set_port(LinphoneTunnelConfig *tunnel, int port) { - tunnel->port = port; -} - -int linphone_tunnel_config_get_port(LinphoneTunnelConfig *tunnel) { - return tunnel->port; -} - -void linphone_tunnel_config_set_remote_udp_mirror_port(LinphoneTunnelConfig *tunnel, int remote_udp_mirror_port) { - tunnel->remote_udp_mirror_port = remote_udp_mirror_port; -} - -int linphone_tunnel_config_get_remote_udp_mirror_port(LinphoneTunnelConfig *tunnel) { - return tunnel->remote_udp_mirror_port; -} - -void linphone_tunnel_config_set_delay(LinphoneTunnelConfig *tunnel, int delay) { - tunnel->delay = delay; -} - -int linphone_tunnel_config_get_delay(LinphoneTunnelConfig *tunnel) { - return tunnel->delay; -} - -void linphone_tunnel_config_destroy(LinphoneTunnelConfig *tunnel) { - if(tunnel->host != NULL) { - ms_free(tunnel->host); - } - ms_free(tunnel); -} - -#ifdef TUNNEL_ENABLED - struct _LinphoneTunnel { belledonnecomm::TunnelManager *manager; MSList *config_list; @@ -122,16 +59,16 @@ void linphone_tunnel_destroy(LinphoneTunnel *tunnel){ static char *linphone_tunnel_config_to_string(const LinphoneTunnelConfig *tunnel_config) { char *str = NULL; - if(tunnel_config->remote_udp_mirror_port != -1) { + if(linphone_tunnel_config_get_remote_udp_mirror_port(tunnel_config) != -1) { str = ms_strdup_printf("%s:%d:%d:%d", - tunnel_config->host, - tunnel_config->port, - tunnel_config->remote_udp_mirror_port, - tunnel_config->delay); + linphone_tunnel_config_get_host(tunnel_config), + linphone_tunnel_config_get_port(tunnel_config), + linphone_tunnel_config_get_remote_udp_mirror_port(tunnel_config), + linphone_tunnel_config_get_delay(tunnel_config)); } else { str = ms_strdup_printf("%s:%d", - tunnel_config->host, - tunnel_config->port); + linphone_tunnel_config_get_host(tunnel_config), + linphone_tunnel_config_get_port(tunnel_config)); } return str; } @@ -209,11 +146,14 @@ static void linphone_tunnel_save_config(LinphoneTunnel *tunnel) { static void linphone_tunnel_add_server_intern(LinphoneTunnel *tunnel, LinphoneTunnelConfig *tunnel_config) { - if(tunnel_config->remote_udp_mirror_port == -1) { - bcTunnel(tunnel)->addServer(tunnel_config->host, tunnel_config->port); + if(linphone_tunnel_config_get_remote_udp_mirror_port(tunnel_config) == -1) { + bcTunnel(tunnel)->addServer(linphone_tunnel_config_get_host(tunnel_config), + linphone_tunnel_config_get_port(tunnel_config)); } else { - bcTunnel(tunnel)->addServer(tunnel_config->host, tunnel_config->port, - tunnel_config->remote_udp_mirror_port, tunnel_config->delay); + bcTunnel(tunnel)->addServer(linphone_tunnel_config_get_host(tunnel_config), + linphone_tunnel_config_get_port(tunnel_config), + linphone_tunnel_config_get_remote_udp_mirror_port(tunnel_config), + linphone_tunnel_config_get_delay(tunnel_config)); } tunnel->config_list = ms_list_append(tunnel->config_list, tunnel_config); } @@ -385,60 +325,3 @@ void linphone_tunnel_configure(LinphoneTunnel *tunnel){ linphone_tunnel_enable(tunnel, enabled); } -#else - -/*stubs to avoid to have #ifdef TUNNEL_ENABLED in upper layers*/ - -void linphone_tunnel_destroy(LinphoneTunnel *tunnel){ -} - - -void linphone_tunnel_add_server(LinphoneTunnel *tunnel, LinphoneTunnelConfig *tunnel_config){ -} - -void linphone_tunnel_remove_server(LinphoneTunnel *tunnel, LinphoneTunnelConfig *tunnel_config){ -} - -const MSList *linphone_tunnel_get_servers(LinphoneTunnel *tunnel){ - return NULL; -} - -void linphone_tunnel_clean_servers(LinphoneTunnel *tunnel){ -} - -void linphone_tunnel_enable(LinphoneTunnel *tunnel, bool_t enabled){ -} - -bool_t linphone_tunnel_enabled(LinphoneTunnel *tunnel){ - return FALSE; -} - - -void linphone_tunnel_enable_logs_with_handler(LinphoneTunnel *tunnel, bool_t enabled, OrtpLogFunc logHandler){ -} - -void linphone_tunnel_set_http_proxy_auth_info(LinphoneTunnel *tunnel, const char* username,const char* passwd){ -} - -void linphone_tunnel_set_http_proxy(LinphoneTunnel*tunnel, const char *host, int port, const char* username,const char* passwd){ -} - -void linphone_tunnel_get_http_proxy(LinphoneTunnel*tunnel,const char **host, int *port, const char **username, const char **passwd){ -} - -void linphone_tunnel_reconnect(LinphoneTunnel *tunnel){ -} - -void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel){ -} - -void linphone_tunnel_configure(LinphoneTunnel *tunnel){ -} - - -#endif - - - - - diff --git a/coreapi/linphone_tunnel.h b/coreapi/linphone_tunnel.h index 03c568e4e..e42a054dc 100644 --- a/coreapi/linphone_tunnel.h +++ b/coreapi/linphone_tunnel.h @@ -68,7 +68,7 @@ void linphone_tunnel_config_set_host(LinphoneTunnelConfig *tunnel, const char *h * * @param tunnel configuration object */ -const char *linphone_tunnel_config_get_host(LinphoneTunnelConfig *tunnel); +const char *linphone_tunnel_config_get_host(const LinphoneTunnelConfig *tunnel); /** * Set tls port of server. @@ -83,7 +83,7 @@ void linphone_tunnel_config_set_port(LinphoneTunnelConfig *tunnel, int port); * * @param tunnel configuration object */ -int linphone_tunnel_config_get_port(LinphoneTunnelConfig *tunnel); +int linphone_tunnel_config_get_port(const LinphoneTunnelConfig *tunnel); /** * Set the remote port on the tunnel server side used to test udp reachability. @@ -98,7 +98,7 @@ void linphone_tunnel_config_set_remote_udp_mirror_port(LinphoneTunnelConfig *tun * * @param tunnel configuration object */ -int linphone_tunnel_config_get_remote_udp_mirror_port(LinphoneTunnelConfig *tunnel); +int linphone_tunnel_config_get_remote_udp_mirror_port(const LinphoneTunnelConfig *tunnel); /** * Set the udp packet round trip delay in ms for a tunnel configuration. @@ -113,7 +113,7 @@ void linphone_tunnel_config_set_delay(LinphoneTunnelConfig *tunnel, int delay); * * @param tunnel configuration object */ -int linphone_tunnel_config_get_delay(LinphoneTunnelConfig *tunnel); +int linphone_tunnel_config_get_delay(const LinphoneTunnelConfig *tunnel); /** * Destroy a tunnel configuration diff --git a/coreapi/linphone_tunnel_config.c b/coreapi/linphone_tunnel_config.c new file mode 100644 index 000000000..f38568016 --- /dev/null +++ b/coreapi/linphone_tunnel_config.c @@ -0,0 +1,83 @@ +/*************************************************************************** + * linphone_tunnel_config.c + * + * Copyright 2012 Belledonne Communications + ****************************************************************************/ + +/* + * 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 "linphone_tunnel.h" + +struct _LinphoneTunnelConfig { + char *host; + int port; + int remote_udp_mirror_port; + int delay; +}; + +LinphoneTunnelConfig *linphone_tunnel_config_new() { + LinphoneTunnelConfig *ltc = ms_new0(LinphoneTunnelConfig,1); + ltc->remote_udp_mirror_port = 12345; + ltc->delay = 1000; + return ltc; +} + +void linphone_tunnel_config_set_host(LinphoneTunnelConfig *tunnel, const char *host) { + if(tunnel->host != NULL) { + ms_free(tunnel->host); + tunnel->host = NULL; + } + if(host != NULL && strlen(host)) { + tunnel->host = ms_strdup(host); + } +} + +const char *linphone_tunnel_config_get_host(const LinphoneTunnelConfig *tunnel) { + return tunnel->host; +} + +void linphone_tunnel_config_set_port(LinphoneTunnelConfig *tunnel, int port) { + tunnel->port = port; +} + +int linphone_tunnel_config_get_port(const LinphoneTunnelConfig *tunnel) { + return tunnel->port; +} + +void linphone_tunnel_config_set_remote_udp_mirror_port(LinphoneTunnelConfig *tunnel, int remote_udp_mirror_port) { + tunnel->remote_udp_mirror_port = remote_udp_mirror_port; +} + +int linphone_tunnel_config_get_remote_udp_mirror_port(const LinphoneTunnelConfig *tunnel) { + return tunnel->remote_udp_mirror_port; +} + +void linphone_tunnel_config_set_delay(LinphoneTunnelConfig *tunnel, int delay) { + tunnel->delay = delay; +} + +int linphone_tunnel_config_get_delay(const LinphoneTunnelConfig *tunnel) { + return tunnel->delay; +} + +void linphone_tunnel_config_destroy(LinphoneTunnelConfig *tunnel) { + if(tunnel->host != NULL) { + ms_free(tunnel->host); + } + ms_free(tunnel); +} + diff --git a/coreapi/linphone_tunnel_stubs.c b/coreapi/linphone_tunnel_stubs.c new file mode 100644 index 000000000..0560b3956 --- /dev/null +++ b/coreapi/linphone_tunnel_stubs.c @@ -0,0 +1,83 @@ +/*************************************************************************** + * linphone_tunnel.cc + * + * Fri Dec 9, 2011 + * Copyright 2011 Belledonne Communications + * Author: Guillaume Beraudo + * Email: guillaume dot beraudo at linphone dot org + ****************************************************************************/ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "linphone_tunnel.h" +#include "linphonecore.h" +#include "private.h" +#include "lpconfig.h" + + +LinphoneTunnel* linphone_core_get_tunnel(LinphoneCore *lc){ + return lc->tunnel; +} + +/*stubs to avoid to have #ifdef TUNNEL_ENABLED in upper layers*/ + +void linphone_tunnel_destroy(LinphoneTunnel *tunnel){ +} + + +void linphone_tunnel_add_server(LinphoneTunnel *tunnel, LinphoneTunnelConfig *tunnel_config){ +} + +void linphone_tunnel_remove_server(LinphoneTunnel *tunnel, LinphoneTunnelConfig *tunnel_config){ +} + +const MSList *linphone_tunnel_get_servers(LinphoneTunnel *tunnel){ + return NULL; +} + +void linphone_tunnel_clean_servers(LinphoneTunnel *tunnel){ +} + +void linphone_tunnel_enable(LinphoneTunnel *tunnel, bool_t enabled){ +} + +bool_t linphone_tunnel_enabled(LinphoneTunnel *tunnel){ + return FALSE; +} + + +void linphone_tunnel_enable_logs_with_handler(LinphoneTunnel *tunnel, bool_t enabled, OrtpLogFunc logHandler){ +} + +void linphone_tunnel_set_http_proxy_auth_info(LinphoneTunnel *tunnel, const char* username,const char* passwd){ +} + +void linphone_tunnel_set_http_proxy(LinphoneTunnel*tunnel, const char *host, int port, const char* username,const char* passwd){ +} + +void linphone_tunnel_get_http_proxy(LinphoneTunnel*tunnel,const char **host, int *port, const char **username, const char **passwd){ +} + +void linphone_tunnel_reconnect(LinphoneTunnel *tunnel){ +} + +void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel){ +} + +void linphone_tunnel_configure(LinphoneTunnel *tunnel){ +} + diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 6ef8e0c55..3bfa7d9d4 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -173,9 +173,10 @@ void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t propagate_encryption_changed(call); } -static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandwidth_limit,int* max_sample_rate){ +static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandwidth_limit,int* max_sample_rate, int nb_codecs_limit){ MSList *l=NULL; const MSList *it; + int nb = 0; if (max_sample_rate) *max_sample_rate=0; for(it=codecs;it!=NULL;it=it->next){ PayloadType *pt=(PayloadType*)it->data; @@ -186,26 +187,30 @@ static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandw } if (linphone_core_check_payload_type_usability(lc,pt)){ l=ms_list_append(l,payload_type_clone(pt)); + nb++; if (max_sample_rate && payload_type_get_rate(pt)>*max_sample_rate) *max_sample_rate=payload_type_get_rate(pt); } } + if ((nb_codecs_limit > 0) && (nb >= nb_codecs_limit)) break; } return l; } static void update_media_description_from_stun(SalMediaDescription *md, const StunCandidate *ac, const StunCandidate *vc){ - if (ac->port!=0){ - strcpy(md->streams[0].rtp_addr,ac->addr); - md->streams[0].rtp_port=ac->port; - if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0) || md->nstreams==1){ - strcpy(md->addr,ac->addr); + int i; + for (i = 0; i < md->n_active_streams; i++) { + if ((md->streams[i].type == SalAudio) && (ac->port != 0)) { + strcpy(md->streams[0].rtp_addr,ac->addr); + md->streams[0].rtp_port=ac->port; + if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0) || md->n_active_streams==1){ + strcpy(md->addr,ac->addr); + } + } + if ((md->streams[i].type == SalVideo) && (vc->port != 0)) { + strcpy(md->streams[1].rtp_addr,vc->addr); + md->streams[1].rtp_port=vc->port; } } - if (vc->port!=0){ - strcpy(md->streams[1].rtp_addr,vc->addr); - md->streams[1].rtp_port=vc->port; - } - } void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call){ @@ -218,12 +223,13 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * 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); - + linphone_core_adapt_to_network(lc,call->ping_time,&call->params); 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; + md->n_total_streams=(old_md ? old_md->n_total_streams : 1); + md->n_active_streams=1; strncpy(md->addr,call->localip,sizeof(md->addr)); strncpy(md->username,username,sizeof(md->username)); @@ -243,22 +249,35 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * md->streams[0].ptime=call->params.down_ptime; else md->streams[0].ptime=linphone_core_get_download_ptime(lc); - l=make_codec_list(lc,lc->codecs_conf.audio_codecs,call->params.audio_bw,&md->streams[0].max_rate); + l=make_codec_list(lc,lc->codecs_conf.audio_codecs,call->params.audio_bw,&md->streams[0].max_rate,-1); pt=payload_type_clone(rtp_profile_get_payload_from_mime(lc->default_profile,"telephone-event")); l=ms_list_append(l,pt); md->streams[0].payloads=l; if (call->params.has_video){ - md->nstreams++; + md->n_active_streams++; md->streams[1].rtp_port=call->video_port; md->streams[1].rtcp_port=call->video_port+1; md->streams[1].proto=md->streams[0].proto; md->streams[1].type=SalVideo; - l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL); + l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL,-1); md->streams[1].payloads=l; } - - for(i=0; instreams; i++) { + if (md->n_total_streams < md->n_active_streams) + md->n_total_streams = md->n_active_streams; + + /* Deactivate inactive streams. */ + for (i = md->n_active_streams; i < md->n_total_streams; i++) { + md->streams[i].rtp_port = 0; + md->streams[i].rtcp_port = 0; + md->streams[i].proto = SalProtoRtpAvp; + md->streams[i].type = old_md->streams[i].type; + md->streams[i].dir = SalStreamInactive; + l = make_codec_list(lc, lc->codecs_conf.video_codecs, 0, NULL, 1); + md->streams[i].payloads = l; + } + + for(i=0; in_active_streams; i++) { if (md->streams[i].proto == SalProtoRtpSavp) { if (keep_srtp_keys && old_md && old_md->streams[i].proto==SalProtoRtpSavp){ int j; @@ -283,6 +302,12 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * linphone_core_update_local_media_description_from_ice(md, call->ice_session); linphone_core_update_ice_state_in_call_stats(call); } +#ifdef BUILD_UPNP + if(call->upnp_session != NULL) { + linphone_core_update_local_media_description_from_upnp(md, call->upnp_session); + linphone_core_update_upnp_state_in_call_stats(call); + } +#endif //BUILD_UPNP linphone_address_destroy(addr); call->localdesc=md; if (old_md) sal_media_description_unref(old_md); @@ -416,6 +441,11 @@ void linphone_call_init_stats(LinphoneCallStats *stats, int type) { stats->received_rtcp = NULL; stats->sent_rtcp = NULL; stats->ice_state = LinphoneIceStateNotActivated; +#ifdef BUILD_UPNP + stats->upnp_state = LinphoneUpnpStateIdle; +#else + stats->upnp_state = LinphoneUpnpStateNotAvailable; +#endif //BUILD_UPNP } @@ -449,6 +479,11 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseStun) { call->ping_time=linphone_core_run_stun_tests(call->core,call); } +#ifdef BUILD_UPNP + if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) { + call->upnp_session = linphone_upnp_session_new(call); + } +#endif //BUILD_UPNP call->camera_active=params->has_video; discover_mtu(lc,linphone_address_get_domain (to)); @@ -510,6 +545,19 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro case LinphonePolicyUseStun: call->ping_time=linphone_core_run_stun_tests(call->core,call); /* No break to also destroy ice session in this case. */ + break; + case LinphonePolicyUseUpnp: +#ifdef BUILD_UPNP + call->upnp_session = linphone_upnp_session_new(call); + if (call->upnp_session != NULL) { + linphone_call_init_media_streams(call); + if (linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(op))<0) { + /* uPnP port mappings failed, proceed with the call anyway. */ + linphone_call_delete_upnp_session(call); + } + } +#endif //BUILD_UPNP + break; default: break; } @@ -658,6 +706,9 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const static void linphone_call_destroy(LinphoneCall *obj) { +#ifdef BUILD_UPNP + linphone_call_delete_upnp_session(obj); +#endif //BUILD_UPNP linphone_call_delete_ice_session(obj); if (obj->op!=NULL) { sal_op_release(obj->op); @@ -847,6 +898,16 @@ const char *linphone_call_get_remote_user_agent(LinphoneCall *call){ return NULL; } +/** + * Returns the far end's sip contact as a string, if available. +**/ +const char *linphone_call_get_remote_contact(LinphoneCall *call){ + if (call->op){ + return sal_op_get_remote_contact(call->op); + } + return NULL; +} + /** * Returns true if this calls has received a transfer that has not been * executed yet. @@ -1727,6 +1788,15 @@ void linphone_call_delete_ice_session(LinphoneCall *call){ } } +#ifdef BUILD_UPNP +void linphone_call_delete_upnp_session(LinphoneCall *call){ + if(call->upnp_session!=NULL) { + linphone_upnp_session_destroy(call->upnp_session); + call->upnp_session=NULL; + } +} +#endif //BUILD_UPNP + static void linphone_call_log_fill_stats(LinphoneCallLog *log, AudioStream *st){ audio_stream_get_local_rtp_stats (st,&log->local_stats); log->quality=audio_stream_get_average_quality_rating(st); @@ -2037,6 +2107,11 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse report_bandwidth(call,as,vs); ms_message("Thread processing load: audio=%f\tvideo=%f",audio_load,video_load); } + +#ifdef BUILD_UPNP + linphone_upnp_call_process(call); +#endif //BUILD_UPNP + #ifdef VIDEO_ENABLED if (call->videostream!=NULL) { OrtpEvent *ev; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 455f80e71..f1206be39 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -67,7 +67,6 @@ static void linphone_core_free_hooks(LinphoneCore *lc); #include "enum.h" const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc); -void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result); static void toggle_video_preview(LinphoneCore *lc, bool_t val); /* relative path where is stored local ring*/ @@ -925,11 +924,14 @@ bool_t linphone_core_tunnel_available(void){ } /** - * Enable adaptive rate control (experimental feature, audio-only). + * Enable adaptive rate control. + * + * @ingroup media_parameters * * Adaptive rate control consists in using RTCP feedback provided information to dynamically - * control the output bitrate of the encoders, so that we can adapt to the network conditions and - * available bandwidth. + * control the output bitrate of the audio and video encoders, so that we can adapt to the network conditions and + * available bandwidth. Control of the audio encoder is done in case of audio-only call, and control of the video encoder is done for audio & video calls. + * Adaptive rate control feature is enabled by default. **/ void linphone_core_enable_adaptive_rate_control(LinphoneCore *lc, bool_t enabled){ lp_config_set_int(lc->config,"net","adaptive_rate_control",(int)enabled); @@ -937,6 +939,8 @@ void linphone_core_enable_adaptive_rate_control(LinphoneCore *lc, bool_t enabled /** * Returns whether adaptive rate control is enabled. + * + * @ingroup media_parameters * * See linphone_core_enable_adaptive_rate_control(). **/ @@ -1009,14 +1013,18 @@ int linphone_core_get_upload_bandwidth(const LinphoneCore *lc){ return lc->net_conf.upload_bw; } /** - * Set audio packetization time linphone expects to receive from peer + * Set audio packetization time linphone expects to receive from peer. + * A value of zero means that ptime is not specified. + * @ingroup media_parameters */ void linphone_core_set_download_ptime(LinphoneCore *lc, int ptime) { lp_config_set_int(lc->config,"rtp","download_ptime",ptime); } /** - * Get audio packetization time linphone expects to receive from peer + * Get audio packetization time linphone expects to receive from peer. + * A value of zero means that ptime is not specified. + * @ingroup media_parameters */ int linphone_core_get_download_ptime(LinphoneCore *lc) { return lp_config_get_int(lc->config,"rtp","download_ptime",0); @@ -1026,6 +1034,7 @@ int linphone_core_get_download_ptime(LinphoneCore *lc) { * Set audio packetization time linphone will send (in absence of requirement from peer) * A value of 0 stands for the current codec default packetization time. * + * @ingroup media_parameters **/ void linphone_core_set_upload_ptime(LinphoneCore *lc, int ptime){ lp_config_set_int(lc->config,"rtp","upload_ptime",ptime); @@ -1035,6 +1044,8 @@ void linphone_core_set_upload_ptime(LinphoneCore *lc, int ptime){ * Set audio packetization time linphone will send (in absence of requirement from peer) * A value of 0 stands for the current codec default packetization time. * + * + * @ingroup media_parameters **/ int linphone_core_get_upload_ptime(LinphoneCore *lc){ return lp_config_get_int(lc->config,"rtp","upload_ptime",0); @@ -1228,6 +1239,9 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta lc->tunnel=linphone_core_tunnel_new(lc); if (lc->tunnel) linphone_tunnel_configure(lc->tunnel); #endif +#ifdef BUILD_UPNP + lc->upnp = linphone_upnp_context_new(lc); +#endif //BUILD_UPNP if (lc->vtable.display_status) lc->vtable.display_status(lc,_("Ready")); lc->auto_net_state_mon=lc->sip_conf.auto_net_state_mon; @@ -1268,6 +1282,7 @@ LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable, * structure holding the codec information. * It is possible to make copy of the list with ms_list_copy() in order to modify it * (such as the order of codecs). + * @ingroup media_parameters **/ const MSList *linphone_core_get_audio_codecs(const LinphoneCore *lc) { @@ -1281,6 +1296,7 @@ const MSList *linphone_core_get_audio_codecs(const LinphoneCore *lc) * structure holding the codec information. * It is possible to make copy of the list with ms_list_copy() in order to modify it * (such as the order of codecs). + * @ingroup media_parameters **/ const MSList *linphone_core_get_video_codecs(const LinphoneCore *lc) { @@ -1321,6 +1337,14 @@ void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result strncpy(result,ip,LINPHONE_IPADDR_SIZE); return; } +#ifdef BUILD_UPNP + else if (lc->upnp != NULL && linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp && + linphone_upnp_context_get_state(lc->upnp) == LinphoneUpnpStateOk) { + ip = linphone_upnp_context_get_external_ipaddress(lc->upnp); + strncpy(result,ip,LINPHONE_IPADDR_SIZE); + return; + } +#endif //BUILD_UPNP if (linphone_core_get_local_ip_for(lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,dest,result)==0) return; /*else fallback to SAL routine that will attempt to find the most realistic interface */ @@ -1570,6 +1594,7 @@ void linphone_core_set_audio_port(LinphoneCore *lc, int port) /** * Sets the UDP port range from which to randomly select the port used for audio streaming. + * @ingroup media_parameters */ void linphone_core_set_audio_port_range(LinphoneCore *lc, int min_port, int max_port) { @@ -1588,6 +1613,7 @@ void linphone_core_set_video_port(LinphoneCore *lc, int port){ /** * Sets the UDP port range from which to randomly select the port used for video streaming. + * @ingroup media_parameters */ void linphone_core_set_video_port_range(LinphoneCore *lc, int min_port, int max_port) { @@ -2016,6 +2042,12 @@ void linphone_core_iterate(LinphoneCore *lc){ linphone_call_delete_ice_session(call); linphone_call_stop_media_streams_for_ice_gathering(call); } +#ifdef BUILD_UPNP + if (call->upnp_session != NULL) { + ms_warning("uPnP mapping has not finished yet, proceeded with the call without uPnP anyway."); + linphone_call_delete_upnp_session(call); + } +#endif //BUILD_UPNP linphone_core_start_invite(lc,call); } if (call->state==LinphoneCallIncomingReceived){ @@ -2061,6 +2093,8 @@ void linphone_core_iterate(LinphoneCore *lc){ /** * Interpret a call destination as supplied by the user, and returns a fully qualified * LinphoneAddress. + * + * @ingroup call_control * * A sip address should look like DisplayName . * Basically this function performs the following tasks @@ -2269,6 +2303,7 @@ static char *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphonePr int linphone_core_proceed_with_invite_if_ready(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy){ bool_t ice_ready = FALSE; + bool_t upnp_ready = FALSE; bool_t ping_ready = FALSE; if (call->ice_session != NULL) { @@ -2276,13 +2311,20 @@ int linphone_core_proceed_with_invite_if_ready(LinphoneCore *lc, LinphoneCall *c } else { ice_ready = TRUE; } +#ifdef BUILD_UPNP + if (call->upnp_session != NULL) { + if (linphone_upnp_session_get_state(call->upnp_session) == LinphoneUpnpStateOk) upnp_ready = TRUE; + } else { + upnp_ready = TRUE; + } +#endif //BUILD_UPNP if (call->ping_op != NULL) { if (call->ping_replied == TRUE) ping_ready = TRUE; } else { ping_ready = TRUE; } - if ((ice_ready == TRUE) && (ping_ready == TRUE)) { + if ((ice_ready == TRUE) && (upnp_ready == TRUE) && (ping_ready == TRUE)) { return linphone_core_start_invite(lc, call); } return 0; @@ -2431,7 +2473,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const SalAddress *proxy_addr=NULL; char *real_url=NULL; LinphoneCall *call; - bool_t use_ice = FALSE; + bool_t defer = FALSE; linphone_core_preempt_sound_resources(lc); @@ -2529,9 +2571,21 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const linphone_call_delete_ice_session(call); linphone_call_stop_media_streams_for_ice_gathering(call); } else { - use_ice = TRUE; + defer = TRUE; } } + else if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) { +#ifdef BUILD_UPNP + linphone_call_init_media_streams(call); + call->start_time=time(NULL); + if (linphone_core_update_upnp(lc,call)<0) { + /* uPnP port mappings failed, proceed with the call anyway. */ + linphone_call_delete_upnp_session(call); + } else { + defer = TRUE; + } +#endif //BUILD_UPNP + } if (call->dest_proxy==NULL && lc->sip_conf.ping_with_options==TRUE){ /*defer the start of the call after the OPTIONS ping*/ @@ -2541,7 +2595,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const sal_op_set_user_pointer(call->ping_op,call); call->start_time=time(NULL); }else{ - if (use_ice==FALSE) linphone_core_start_invite(lc,call); + if (defer==FALSE) linphone_core_start_invite(lc,call); } if (real_url!=NULL) ms_free(real_url); @@ -2551,6 +2605,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const /** * Performs a simple call transfer to the specified destination. * + * @ingroup call_control * The remote endpoint is expected to issue a new call to the specified destination. * The current call remains active and thus can be later paused or terminated. **/ @@ -2581,6 +2636,8 @@ int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char * @param lc linphone core object * @param call a running call you want to transfer * @param dest a running call whose remote person will receive the transfer + * + * @ingroup call_control * * The transfered call is supposed to be in paused state, so that it is able to accept the transfer immediately. * The destination call is a call previously established to introduce the transfered person. @@ -2608,7 +2665,7 @@ bool_t linphone_core_inc_invite_pending(LinphoneCore*lc){ bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription *md){ if (linphone_core_is_media_encryption_mandatory(lc) && linphone_core_get_media_encryption(lc)==LinphoneMediaEncryptionSRTP){ int i; - for(i=0;instreams;i++){ + for(i=0;in_active_streams;i++){ SalStreamDescription *sd=&md->streams[i]; if (sd->proto!=SalProtoRtpSavp){ return TRUE; @@ -2695,9 +2752,14 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call){ const char *subject; call->camera_active=call->params.has_video; - if (call->ice_session != NULL) + if (call->ice_session != NULL) { linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session); - + } +#ifdef BUILD_UPNP + if(call->upnp_session != NULL) { + linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session); + } +#endif //BUILD_UPNP if (call->params.in_conference){ subject="Conference"; }else{ @@ -2729,21 +2791,53 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho linphone_call_set_state(call,LinphoneCallUpdating,"Updating call"); #ifdef VIDEO_ENABLED bool_t has_video = call->params.has_video; - if ((call->ice_session != NULL) && (call->videostream != NULL) && !params->has_video) { - ice_session_remove_check_list(call->ice_session, call->videostream->ms.ice_check_list); - call->videostream->ms.ice_check_list = NULL; + + // Video removing + if((call->videostream != NULL) && !params->has_video) { + if (call->ice_session != NULL) { + ice_session_remove_check_list(call->ice_session, call->videostream->ms.ice_check_list); + call->videostream->ms.ice_check_list = NULL; + } +#ifdef BUILD_UPNP + if(call->upnp_session != NULL) { + if (linphone_core_update_upnp(lc, call)<0) { + /* uPnP port mappings failed, proceed with the call anyway. */ + linphone_call_delete_upnp_session(call); + } + } +#endif //BUILD_UPNP } + call->params = *params; 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"); - linphone_call_init_video_stream(call); - video_stream_prepare_video(call->videostream); - if (linphone_core_gather_ice_candidates(lc,call)<0) { - /* Ice candidates gathering failed, proceed with the call anyway. */ - linphone_call_delete_ice_session(call); - } else return err; + + // Video adding + if (!has_video && call->params.has_video) { + if (call->ice_session != NULL) { + /* Defer call update until the ICE candidates gathering process has finished. */ + ms_message("Defer call update to gather ICE candidates"); + linphone_call_init_video_stream(call); + video_stream_prepare_video(call->videostream); + if (linphone_core_gather_ice_candidates(lc,call)<0) { + /* Ice candidates gathering failed, proceed with the call anyway. */ + linphone_call_delete_ice_session(call); + } else { + return err; + } + } +#ifdef BUILD_UPNP + if(call->upnp_session != NULL) { + ms_message("Defer call update to add uPnP port mappings"); + linphone_call_init_video_stream(call); + video_stream_prepare_video(call->videostream); + if (linphone_core_update_upnp(lc, call)<0) { + /* uPnP port mappings failed, proceed with the call anyway. */ + linphone_call_delete_upnp_session(call); + } else { + return err; + } + } +#endif //BUILD_UPNP } #endif err = linphone_core_start_update_call(lc, call); @@ -2793,6 +2887,11 @@ int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call) } linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session); } +#ifdef BUILD_UPNP + if(call->upnp_session != NULL) { + linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session); + } +#endif //BUILD_UPNP linphone_call_update_remote_session_id_and_ver(call); sal_call_set_local_media_description(call->op,call->localdesc); sal_call_accept(call->op); @@ -2871,8 +2970,25 @@ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const } else return 0; } } -#endif +#endif //VIDEO_ENABLED } + +#if BUILD_UPNP + if(call->upnp_session != NULL) { + linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(call->op)); +#ifdef VIDEO_ENABLED + if ((call->params.has_video) && (call->params.has_video != old_has_video)) { + linphone_call_init_video_stream(call); + video_stream_prepare_video(call->videostream); + if (linphone_core_update_upnp(lc, call)<0) { + /* uPnP update failed, proceed with the call anyway. */ + linphone_call_delete_upnp_session(call); + } else return 0; + } +#endif //VIDEO_ENABLED + } +#endif //BUILD_UPNP + linphone_core_start_accept_call_update(lc, call); return 0; } @@ -3011,6 +3127,11 @@ int linphone_core_abort_call(LinphoneCore *lc, LinphoneCall *call, const char *e lc->ringstream=NULL; } linphone_call_stop_media_streams(call); + +#ifdef BUILD_UPNP + linphone_call_delete_upnp_session(call); +#endif //BUILD_UPNP + if (lc->vtable.display_status!=NULL) lc->vtable.display_status(lc,_("Call aborted") ); linphone_call_set_state(call,LinphoneCallError,error); @@ -3029,6 +3150,11 @@ static void terminate_call(LinphoneCore *lc, LinphoneCall *call){ } linphone_call_stop_media_streams(call); + +#ifdef BUILD_UPNP + linphone_call_delete_upnp_session(call); +#endif //BUILD_UPNP + if (lc->vtable.display_status!=NULL) lc->vtable.display_status(lc,_("Call ended") ); linphone_call_set_state(call,LinphoneCallEnd,"Call terminated"); @@ -3078,6 +3204,9 @@ int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *the_call) /** * Decline a pending incoming call, with a reason. + * + * @ingroup call_control + * * @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 @@ -3169,8 +3298,14 @@ int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call) return -1; } linphone_call_make_local_media_description(lc,call); - if (call->ice_session != NULL) + if (call->ice_session != NULL) { linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session); + } +#ifdef BUILD_UPNP + if(call->upnp_session != NULL) { + linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session); + } +#endif //BUILD_UPNP if (sal_media_description_has_dir(call->resultdesc,SalStreamSendRecv)){ sal_media_description_set_dir(call->localdesc,SalStreamSendOnly); subject="Call on hold"; @@ -3197,6 +3332,7 @@ int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call) /** * Pause all currently running calls. + * @ingroup call_control **/ int linphone_core_pause_all_calls(LinphoneCore *lc){ const MSList *elem; @@ -3248,8 +3384,14 @@ int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *the_call) if (call->audiostream) audio_stream_play(call->audiostream, NULL); linphone_call_make_local_media_description(lc,the_call); - if (call->ice_session != NULL) + if (call->ice_session != NULL) { linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session); + } +#ifdef BUILD_UPNP + if(call->upnp_session != NULL) { + linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session); + } +#endif //BUILD_UPNP sal_call_set_local_media_description(call->op,call->localdesc); sal_media_description_set_dir(call->localdesc,SalStreamSendRecv); if (call->params.in_conference && !call->current_params.in_conference) subject="Conference"; @@ -3273,6 +3415,8 @@ static int remote_address_compare(LinphoneCall *call, const LinphoneAddress *rad * @param lc * @param remote_address * @return the LinphoneCall of the call if found + * + * @ingroup call_control */ LinphoneCall *linphone_core_get_call_by_remote_address(LinphoneCore *lc, const char *remote_address){ LinphoneAddress *raddr=linphone_address_new(remote_address); @@ -3746,18 +3890,18 @@ const char *linphone_core_get_ring(const LinphoneCore *lc){ * @param path * @param lc The LinphoneCore object * - * @ingroup media_parameters + * @ingroup initializing **/ 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) + * Gets the path to a file or folder containing the trusted root CAs (PEM format) * * @param lc The LinphoneCore object * - * @ingroup media_parameters + * @ingroup initializing **/ const char *linphone_core_get_root_ca(LinphoneCore *lc){ return sal_get_root_ca(lc->sal); @@ -3765,6 +3909,8 @@ const char *linphone_core_get_root_ca(LinphoneCore *lc){ /** * Specify whether the tls server certificate must be verified when connecting to a SIP/TLS server. + * + * @ingroup initializing **/ void linphone_core_verify_server_certificates(LinphoneCore *lc, bool_t yesno){ sal_verify_server_certificates(lc->sal,yesno); @@ -3772,6 +3918,7 @@ void linphone_core_verify_server_certificates(LinphoneCore *lc, bool_t yesno){ /** * Specify whether the tls server certificate common name must be verified when connecting to a SIP/TLS server. + * @ingroup initializing **/ void linphone_core_verify_server_cn(LinphoneCore *lc, bool_t yesno){ sal_verify_server_cn(lc->sal,yesno); @@ -4698,6 +4845,12 @@ void *linphone_core_get_user_data(LinphoneCore *lc){ return lc->data; } + +/** + * Associate a user pointer to the linphone core. + * + * @ingroup initializing +**/ void linphone_core_set_user_data(LinphoneCore *lc, void *userdata){ lc->data=userdata; } @@ -4706,6 +4859,13 @@ int linphone_core_get_mtu(const LinphoneCore *lc){ return lc->net_conf.mtu; } +/** + * Sets the maximum transmission unit size in bytes. + * This information is useful for sending RTP packets. + * Default value is 1500. + * + * @ingroup media_parameters +**/ void linphone_core_set_mtu(LinphoneCore *lc, int mtu){ lc->net_conf.mtu=mtu; if (mtu>0){ @@ -4865,8 +5025,8 @@ void rtp_config_uninit(LinphoneCore *lc) lp_config_set_int(lc->config,"rtp","audio_jitt_comp",config->audio_jitt_comp); lp_config_set_int(lc->config,"rtp","video_jitt_comp",config->video_jitt_comp); lp_config_set_int(lc->config,"rtp","nortp_timeout",config->nortp_timeout); - lp_config_set_int(lc->config,"rtp","audio_jitt_comp_enabled",config->audio_adaptive_jitt_comp_enabled); - lp_config_set_int(lc->config,"rtp","video_jitt_comp_enabled",config->video_adaptive_jitt_comp_enabled); + lp_config_set_int(lc->config,"rtp","audio_adaptive_jitt_comp_enabled",config->audio_adaptive_jitt_comp_enabled); + lp_config_set_int(lc->config,"rtp","video_adaptive_jitt_comp_enabled",config->video_adaptive_jitt_comp_enabled); } static void sound_config_uninit(LinphoneCore *lc) @@ -4969,6 +5129,12 @@ static void linphone_core_uninit(LinphoneCore *lc) usleep(50000); #endif } + +#ifdef BUILD_UPNP + linphone_upnp_context_destroy(lc->upnp); + lc->upnp = NULL; +#endif //BUILD_UPNP + if (lc->friends) ms_list_for_each(lc->friends,(void (*)(void *))linphone_friend_close_subscriptions); linphone_core_set_state(lc,LinphoneGlobalShutdown,"Shutting down"); diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 55198e319..f780d2f65 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -284,6 +284,27 @@ enum _LinphoneIceState{ **/ typedef enum _LinphoneIceState LinphoneIceState; +/** + * Enum describing uPnP states. + * @ingroup initializing +**/ +enum _LinphoneUpnpState{ + LinphoneUpnpStateIdle, /**< uPnP is not activate */ + LinphoneUpnpStatePending, /**< uPnP process is in progress */ + LinphoneUpnpStateAdding, /**< Internal use: Only used by port binding */ + LinphoneUpnpStateRemoving, /**< Internal use: Only used by port binding */ + LinphoneUpnpStateNotAvailable, /**< uPnP is not available */ + LinphoneUpnpStateOk, /**< uPnP is enabled */ + LinphoneUpnpStateKo, /**< uPnP processing has failed */ +}; + +/** + * Enum describing uPnP states. + * @ingroup initializing +**/ +typedef enum _LinphoneUpnpState LinphoneUpnpState; + + /** * The LinphoneCallStats objects carries various statistic informations regarding quality of audio or video streams. * @@ -309,6 +330,7 @@ struct _LinphoneCallStats { mblk_t* sent_rtcp;/**NewStringUTF(linphone_call_get_remote_user_agent(call)); + const char *value=linphone_call_get_remote_user_agent(call); + jstring jvalue=NULL; + if (value) jvalue=env->NewStringUTF(value); + return jvalue; +} + +extern "C" jstring Java_org_linphone_core_LinphoneCallImpl_getRemoteContact(JNIEnv *env, jobject thiz, jlong ptr) { + LinphoneCall *call = (LinphoneCall *)ptr; + const char *value=linphone_call_get_remote_contact(call); + jstring jvalue = NULL; + if (value) jvalue=env->NewStringUTF(value); return jvalue; } @@ -2229,6 +2239,18 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_getConfig(JNIEnv *env, return (jlong) linphone_core_get_config((LinphoneCore *)lc); } +extern "C" jlong Java_org_linphone_core_LpConfigImpl_newLpConfigImpl(JNIEnv *env, jobject thiz, jstring file) { + const char *cfile = env->GetStringUTFChars(file, NULL); + LpConfig *lp = lp_config_new(cfile); + env->ReleaseStringUTFChars(file, cfile); + return (jlong) lp; +} + +extern "C" void Java_org_linphone_core_LpConfigImpl_delete(JNIEnv *env, jobject thiz, jlong lpc) { + LpConfig *lp = (LpConfig *)lpc; + lp_config_destroy(lp); +} + extern "C" void Java_org_linphone_core_LpConfigImpl_setInt(JNIEnv *env, jobject thiz, jlong lpc, jstring section, jstring key, jint value) { const char *csection = env->GetStringUTFChars(section, NULL); diff --git a/coreapi/lpconfig.c b/coreapi/lpconfig.c index 8457cf650..4608beecf 100644 --- a/coreapi/lpconfig.c +++ b/coreapi/lpconfig.c @@ -215,14 +215,17 @@ LpConfig * lp_config_new(const char *filename){ lpconfig->filename=ortp_strdup(filename); lpconfig->file=fopen(filename,"rw"); if (lpconfig->file!=NULL){ + struct stat fileStat; lp_config_parse(lpconfig,lpconfig->file); - fclose(lpconfig->file); + fclose(lpconfig->file); #if !defined(_WIN32_WCE) - /* make existing configuration files non-group/world-accessible */ - if (chmod(filename, S_IRUSR | S_IWUSR) == -1) - ms_warning("unable to correct permissions on " - "configuration file: %s", - strerror(errno)); + if ((stat(filename,&fileStat) == 0) && (S_ISREG(fileStat.st_mode))) { + /* make existing configuration files non-group/world-accessible */ + if (chmod(filename, S_IRUSR | S_IWUSR) == -1) { + ms_warning("unable to correct permissions on " + "configuration file: %s", strerror(errno)); + } + } #endif /*_WIN32_WCE*/ lpconfig->file=NULL; lpconfig->modified=0; diff --git a/coreapi/misc.c b/coreapi/misc.c index 53f0d65cf..897300c61 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -734,7 +734,7 @@ void linphone_core_update_local_media_description_from_ice(SalMediaDescription * } strncpy(desc->ice_pwd, ice_session_local_pwd(session), sizeof(desc->ice_pwd)); strncpy(desc->ice_ufrag, ice_session_local_ufrag(session), sizeof(desc->ice_ufrag)); - for (i = 0; i < desc->nstreams; i++) { + for (i = 0; i < desc->n_active_streams; i++) { SalStreamDescription *stream = &desc->streams[i]; IceCheckList *cl = ice_session_check_list(session, i); nb_candidates = 0; @@ -838,7 +838,7 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, ice_session_restart(call->ice_session); ice_restarted = TRUE; } else { - for (i = 0; i < md->nstreams; i++) { + for (i = 0; i < md->n_total_streams; i++) { const SalStreamDescription *stream = &md->streams[i]; IceCheckList *cl = ice_session_check_list(call->ice_session, i); if (cl && (strcmp(stream->rtp_addr, "0.0.0.0") == 0)) { @@ -857,7 +857,7 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, } ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd); } - for (i = 0; i < md->nstreams; i++) { + for (i = 0; i < md->n_total_streams; i++) { const SalStreamDescription *stream = &md->streams[i]; IceCheckList *cl = ice_session_check_list(call->ice_session, i); if (cl && (stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) { @@ -873,7 +873,7 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, } /* Create ICE check lists if needed and parse ICE attributes. */ - for (i = 0; i < md->nstreams; i++) { + for (i = 0; i < md->n_total_streams; i++) { const SalStreamDescription *stream = &md->streams[i]; IceCheckList *cl = ice_session_check_list(call->ice_session, i); if (cl == NULL) { @@ -930,7 +930,7 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, } } } - for (i = ice_session_nb_check_lists(call->ice_session); i > md->nstreams; i--) { + for (i = ice_session_nb_check_lists(call->ice_session); i > md->n_active_streams; i--) { ice_session_remove_check_list(call->ice_session, ice_session_check_list(call->ice_session, i - 1)); } ice_session_check_mismatch(call->ice_session); @@ -948,8 +948,8 @@ bool_t linphone_core_media_description_contains_video_stream(const SalMediaDescr { int i; - for (i = 0; i < md->nstreams; i++) { - if ((md->streams[i].type == SalVideo) && (md->streams[i].rtp_port != 0)) + for (i = 0; i < md->n_active_streams; i++) { + if (md->streams[i].type == SalVideo) return TRUE; } return FALSE; @@ -1021,14 +1021,15 @@ static int get_local_ip_with_getifaddrs(int type, char *address, int size) if (ifp->ifa_addr && ifp->ifa_addr->sa_family == type && (ifp->ifa_flags & UP_FLAG) && !(ifp->ifa_flags & IFF_LOOPBACK)) { - getnameinfo(ifp->ifa_addr, + if(getnameinfo(ifp->ifa_addr, (type == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in), - address, size, NULL, 0, NI_NUMERICHOST); - if (strchr(address, '%') == NULL) { /*avoid ipv6 link-local addresses */ - /*ms_message("getifaddrs() found %s",address);*/ - ret++; - break; + address, size, NULL, 0, NI_NUMERICHOST) == 0) { + if (strchr(address, '%') == NULL) { /*avoid ipv6 link-local addresses */ + /*ms_message("getifaddrs() found %s",address);*/ + ret++; + break; + } } } } @@ -1099,26 +1100,26 @@ static int get_local_ip_for_with_connect(int type, const char *dest, char *resul } int linphone_core_get_local_ip_for(int type, const char *dest, char *result){ - strcpy(result,type==AF_INET ? "127.0.0.1" : "::1"); + strcpy(result,type==AF_INET ? "127.0.0.1" : "::1"); #ifdef HAVE_GETIFADDRS - if (dest==NULL) { - /*we use getifaddrs for lookup of default interface */ - int found_ifs; - - found_ifs=get_local_ip_with_getifaddrs(type,result,LINPHONE_IPADDR_SIZE); - if (found_ifs==1){ - return 0; - }else if (found_ifs<=0){ - /*absolutely no network on this machine */ - return -1; - } - } + if (dest==NULL) { + /*we use getifaddrs for lookup of default interface */ + int found_ifs; + + found_ifs=get_local_ip_with_getifaddrs(type,result,LINPHONE_IPADDR_SIZE); + if (found_ifs==1){ + return 0; + }else if (found_ifs<=0){ + /*absolutely no network on this machine */ + return -1; + } + } #endif - /*else use connect to find the best local ip address */ - if (type==AF_INET) - dest="87.98.157.38"; /*a public IP address*/ - else dest="2a00:1450:8002::68"; - return get_local_ip_for_with_connect(type,dest,result); + /*else use connect to find the best local ip address */ + if (type==AF_INET) + dest="87.98.157.38"; /*a public IP address*/ + else dest="2a00:1450:8002::68"; + return get_local_ip_for_with_connect(type,dest,result); } #ifndef WIN32 diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index 541a1eee3..ab38f7636 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -19,6 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "sal.h" #include "offeranswer.h" +#include "private.h" static bool_t only_telephone_event(const MSList *l){ for(;l!=NULL;l=l->next){ @@ -267,22 +268,23 @@ static void initiate_incoming(const SalStreamDescription *local_cap, * and the returned response (remote). **/ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer, - const SalMediaDescription *remote_answer, - SalMediaDescription *result){ - int i,j; - + const SalMediaDescription *remote_answer, + SalMediaDescription *result){ + int i,j; + const SalStreamDescription *ls,*rs; - for(i=0,j=0;instreams;++i){ + for(i=0,j=0;in_total_streams;++i){ ms_message("Processing for stream %i",i); ls=&local_offer->streams[i]; rs=sal_media_description_find_stream((SalMediaDescription*)remote_answer,ls->proto,ls->type); - if (rs) { + if (rs) { initiate_outgoing(ls,rs,&result->streams[j]); ++j; } else ms_warning("No matching stream for %i",i); } - result->nstreams=j; + result->n_active_streams=j; + result->n_total_streams=local_offer->n_total_streams; result->bandwidth=remote_answer->bandwidth; strcpy(result->addr,remote_answer->addr); return 0; @@ -294,12 +296,13 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer, * The returned media description is an answer and should be sent to the offerer. **/ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities, - const SalMediaDescription *remote_offer, - SalMediaDescription *result, bool_t one_matching_codec){ + const SalMediaDescription *remote_offer, + SalMediaDescription *result, bool_t one_matching_codec){ int i; const SalStreamDescription *ls=NULL,*rs; - - for(i=0;instreams;++i){ + + result->n_active_streams=0; + for(i=0;in_total_streams;++i){ rs=&remote_offer->streams[i]; if (rs->proto!=SalProtoUnknown){ ls=sal_media_description_find_stream((SalMediaDescription*)local_capabilities,rs->proto,rs->type); @@ -310,6 +313,7 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities }else ms_warning("Unknown protocol for mline %i, declining",i); if (ls){ initiate_incoming(ls,rs,&result->streams[i],one_matching_codec); + result->n_active_streams++; } else { /* create an inactive stream for the answer, as there where no matching stream a local capability */ @@ -322,7 +326,7 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities } } } - result->nstreams=i; + result->n_total_streams=i; strcpy(result->username, local_capabilities->username); strcpy(result->addr,local_capabilities->addr); result->bandwidth=local_capabilities->bandwidth; diff --git a/coreapi/private.h b/coreapi/private.h index 1a0876cfc..4b88bbed6 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -28,9 +28,11 @@ extern "C" { #endif #include "linphonecore.h" +#include "linphonefriend.h" #include "linphone_tunnel.h" #include "linphonecore_utils.h" #include "sal.h" +#include "sipsetup.h" #ifdef HAVE_CONFIG_H #include "config.h" @@ -38,6 +40,9 @@ extern "C" { #include "mediastreamer2/ice.h" #include "mediastreamer2/mediastream.h" #include "mediastreamer2/msconference.h" +#ifdef BUILD_UPNP +#include "upnp.h" +#endif //BUILD_UPNP #ifndef LIBLINPHONE_VERSION #define LIBLINPHONE_VERSION LINPHONE_VERSION @@ -98,6 +103,7 @@ struct _LinphoneChatMessage { void* message_userdata; char* external_body_url; LinphoneAddress* from; + time_t time; }; typedef struct StunCandidate{ @@ -145,6 +151,9 @@ struct _LinphoneCall OrtpEvQueue *videostream_app_evq; CallCallbackObj nextVideoFrameDecoded; LinphoneCallStats stats[2]; +#ifdef BUILD_UPNP + UpnpSession *upnp_session; +#endif //BUILD_UPNP IceSession *ice_session; LinphoneChatMessage* pending_message; int ping_time; @@ -278,7 +287,7 @@ void linphone_proxy_config_write_to_config_file(struct _LpConfig* config,Linphon int linphone_proxy_config_normalize_number(LinphoneProxyConfig *cfg, const char *username, char *result, size_t result_len); -void linphone_core_message_received(LinphoneCore *lc, const char *from, const char *raw_msg,const char* external_url); +void linphone_core_message_received(LinphoneCore *lc, const SalMessage *msg); void linphone_core_play_tone(LinphoneCore *lc); @@ -293,6 +302,7 @@ void linphone_call_stop_audio_stream(LinphoneCall *call); void linphone_call_stop_video_stream(LinphoneCall *call); void linphone_call_stop_media_streams(LinphoneCall *call); void linphone_call_delete_ice_session(LinphoneCall *call); +void linphone_call_delete_upnp_session(LinphoneCall *call); void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call); void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md); void linphone_call_update_remote_session_id_and_ver(LinphoneCall *call); @@ -572,8 +582,8 @@ struct _LinphoneCore bool_t network_reachable; bool_t use_preview_window; - time_t network_last_check; - bool_t network_last_status; + time_t network_last_check; + bool_t network_last_status; bool_t ringstream_autorelease; bool_t pad[3]; @@ -582,13 +592,16 @@ struct _LinphoneCore LinphoneTunnel *tunnel; char* device_id; MSList *last_recv_msg_ids; +#ifdef BUILD_UPNP + UpnpContext *upnp; +#endif //BUILD_UPNP }; LinphoneTunnel *linphone_core_tunnel_new(LinphoneCore *lc); void linphone_tunnel_destroy(LinphoneTunnel *tunnel); void linphone_tunnel_configure(LinphoneTunnel *tunnel); void linphone_tunnel_enable_logs_with_handler(LinphoneTunnel *tunnel, bool_t enabled, OrtpLogFunc logHandler); - + bool_t linphone_core_can_we_add_call(LinphoneCore *lc); int linphone_core_add_call( LinphoneCore *lc, LinphoneCall *call); int linphone_core_del_call( LinphoneCore *lc, LinphoneCall *call); @@ -656,6 +669,9 @@ 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); +int linphone_upnp_init(LinphoneCore *lc); +void linphone_upnp_destroy(LinphoneCore *lc); + #ifdef __cplusplus } #endif diff --git a/coreapi/proxy.c b/coreapi/proxy.c index fe5a724e8..813cfaca4 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -431,7 +431,7 @@ static dial_plan_t const dial_plans[]={ {"Congo Democratic Republic" ,"CD" , "243" , 9 , "00" }, {"Cook Islands" ,"CK" , "682" , 5 , "00" }, {"Costa Rica" ,"CR" , "506" , 8 , "00" }, - {"Cte d'Ivoire" ,"AD" , "225" , 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" }, @@ -549,7 +549,7 @@ static dial_plan_t const dial_plans[]={ {"Portugal" ,"PT" , "351" , 9 , "00" }, {"Puerto Rico" ,"PR" , "1" , 10 , "011" }, {"Qatar" ,"QA" , "974" , 8 , "00" }, - {"Runion Island" ,"RE" , "262" , 9 , "011" }, + {"R�union Island" ,"RE" , "262" , 9 , "011" }, {"Romania" ,"RO" , "40" , 9 , "00" }, {"Russian Federation" ,"RU" , "7" , 10 , "8" }, {"Rwanda" ,"RW" , "250" , 9 , "00" }, @@ -560,7 +560,7 @@ static dial_plan_t const dial_plans[]={ {"Saint Vincent and the Grenadines","VC" , "1" , 10 , "011" }, {"Samoa" ,"WS" , "685" , 7 , "0" }, {"San Marino" ,"SM" , "378" , 10 , "00" }, - {"So Tom and Prncipe" ,"ST" , "239" , 7 , "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" }, diff --git a/coreapi/sal.c b/coreapi/sal.c index c73f5a889..a51cbee98 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -77,7 +77,7 @@ void sal_media_description_unref(SalMediaDescription *md){ SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md, SalMediaProto proto, SalStreamType type){ int i; - for(i=0;instreams;++i){ + for(i=0;in_active_streams;++i){ SalStreamDescription *ss=&md->streams[i]; if (ss->proto==proto && ss->type==type) return ss; } @@ -85,17 +85,13 @@ SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md, } bool_t sal_media_description_empty(const SalMediaDescription *md){ - int i; - for(i=0;instreams;++i){ - const SalStreamDescription *ss=&md->streams[i]; - if (ss->rtp_port!=0) return FALSE; - } + if (md->n_active_streams > 0) return FALSE; return TRUE; } void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_dir){ int i; - for(i=0;instreams;++i){ + for(i=0;in_active_streams;++i){ SalStreamDescription *ss=&md->streams[i]; ss->dir=stream_dir; } @@ -111,7 +107,7 @@ static bool_t has_dir(const SalMediaDescription *md, SalStreamDir stream_dir){ int i; /* we are looking for at least one stream with requested direction, inactive streams are ignored*/ - for(i=0;instreams;++i){ + for(i=0;in_active_streams;++i){ const SalStreamDescription *ss=&md->streams[i]; if (ss->dir==stream_dir) return TRUE; /*compatibility check for phones that only used the null address and no attributes */ @@ -225,9 +221,9 @@ int sal_media_description_equals(const SalMediaDescription *md1, const SalMediaD int i; 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->n_total_streams != md2->n_total_streams) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; if (md1->bandwidth != md2->bandwidth) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; - for(i = 0; i < md1->nstreams; ++i){ + for(i = 0; i < md1->n_total_streams; ++i){ result |= sal_stream_description_equals(&md1->streams[i], &md2->streams[i]); } return result; @@ -347,6 +343,10 @@ const char *sal_op_get_contact(const SalOp *op){ return ((SalOpBase*)op)->contact; } +const char *sal_op_get_remote_contact(const SalOp *op){ + return ((SalOpBase*)op)->remote_contact; +} + const char *sal_op_get_route(const SalOp *op){ #ifdef BELLE_SIP ms_fatal("sal_op_get_route not supported, use sal_op_get_route_addresses instead"); @@ -381,6 +381,9 @@ void __sal_op_set_network_origin(SalOp *op, const char *origin){ SET_PARAM(op,origin); } +void __sal_op_set_remote_contact(SalOp *op, const char *ct){ + assign_string(&((SalOpBase*)op)->remote_contact,ct); +} void __sal_op_set_network_origin_address(SalOp *op, SalAddress *origin){ char* address_string=sal_address_as_string(origin); /*can probably be optimized*/ __sal_op_set_network_origin(op,address_string); @@ -413,6 +416,10 @@ void __sal_op_free(SalOp *op){ ms_free(b->remote_ua); b->remote_ua=NULL; } + if (b->remote_contact){ + ms_free(b->remote_contact); + b->remote_contact=NULL; + } if (b->local_media) sal_media_description_unref(b->local_media); if (b->remote_media) diff --git a/coreapi/sal.h b/coreapi/sal.h index 0f5c646b9..af7c2aff5 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -181,7 +181,8 @@ typedef struct SalMediaDescription{ int refcount; char addr[64]; char username[64]; - int nstreams; + int n_active_streams; + int n_total_streams; int bandwidth; unsigned int session_ver; unsigned int session_id; @@ -197,6 +198,7 @@ typedef struct SalMessage{ const char *text; const char *url; const char *message_id; + time_t time; }SalMessage; #define SAL_MEDIA_DESCRIPTION_MAX_MESSAGE_ATTRIBUTES 5 @@ -229,6 +231,7 @@ typedef struct SalOpBase{ SalMediaDescription *remote_media; void *user_pointer; const char* call_id; + char *remote_contact; SalAddress* service_route; /*as defined by rfc3608, might be a list*/ } SalOpBase; @@ -412,6 +415,7 @@ const SalAddress *sal_op_get_contact_address(const SalOp *op); const char *sal_op_get_route(const SalOp *op); const MSList* sal_op_get_route_addresses(const SalOp *op); const char *sal_op_get_proxy(const SalOp *op); +const char *sal_op_get_remote_contact(const SalOp *op); /*for incoming requests, returns the origin of the packet as a sip uri*/ const char *sal_op_get_network_origin(const SalOp *op); const SalAddress *sal_op_get_network_origin_address(const SalOp *op); @@ -473,7 +477,7 @@ int sal_ping(SalOp *op, const char *from, const char *to); -#define payload_type_set_number(pt,n) (pt)->user_data=(void*)((long)n); +#define payload_type_set_number(pt,n) (pt)->user_data=(void*)((long)n); #define payload_type_get_number(pt) ((int)(long)(pt)->user_data) /*misc*/ @@ -486,6 +490,7 @@ void sal_disable_logs(); void __sal_op_init(SalOp *b, Sal *sal); void __sal_op_set_network_origin(SalOp *op, const char *origin /*a sip uri*/); void __sal_op_set_network_origin_address(SalOp *op, SalAddress *origin); +void __sal_op_set_remote_contact(SalOp *op, const char *ct); void __sal_op_free(SalOp *b); /*test api*/ diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index d8332621d..91ec04679 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -52,7 +52,6 @@ void sal_get_default_local_ip(Sal *sal, int address_family,char *ip, size_t iple } } - static SalOp * sal_find_call(Sal *sal, int cid){ const MSList *elem; SalOp *op; @@ -589,18 +588,15 @@ static void sdp_process(SalOp *h){ strcpy(h->result->addr,h->base.remote_media->addr); h->result->bandwidth=h->base.remote_media->bandwidth; - for(i=0;iresult->nstreams;++i){ - if (h->result->streams[i].rtp_port>0){ - strcpy(h->result->streams[i].rtp_addr,h->base.remote_media->streams[i].rtp_addr); - strcpy(h->result->streams[i].rtcp_addr,h->base.remote_media->streams[i].rtcp_addr); - h->result->streams[i].ptime=h->base.remote_media->streams[i].ptime; - h->result->streams[i].bandwidth=h->base.remote_media->streams[i].bandwidth; - h->result->streams[i].rtp_port=h->base.remote_media->streams[i].rtp_port; - h->result->streams[i].rtcp_port=h->base.remote_media->streams[i].rtcp_port; - - if (h->result->streams[i].proto == SalProtoRtpSavp) { - h->result->streams[i].crypto[0] = h->base.remote_media->streams[i].crypto[0]; - } + for(i=0;iresult->n_active_streams;++i){ + strcpy(h->result->streams[i].rtp_addr,h->base.remote_media->streams[i].rtp_addr); + strcpy(h->result->streams[i].rtcp_addr,h->base.remote_media->streams[i].rtcp_addr); + h->result->streams[i].ptime=h->base.remote_media->streams[i].ptime; + h->result->streams[i].bandwidth=h->base.remote_media->streams[i].bandwidth; + h->result->streams[i].rtp_port=h->base.remote_media->streams[i].rtp_port; + h->result->streams[i].rtcp_port=h->base.remote_media->streams[i].rtcp_port; + if (h->result->streams[i].proto == SalProtoRtpSavp) { + h->result->streams[i].crypto[0] = h->base.remote_media->streams[i].crypto[0]; } } } @@ -674,8 +670,11 @@ int sal_call(SalOp *h, const char *from, const char *to){ ms_error("Fail to send invite ! Error code %d", err); return -1; }else{ + char *tmp=NULL; callid=osip_message_get_call_id(invite); - osip_call_id_to_str(callid,(char **)(&h->base.call_id)); + osip_call_id_to_str(callid,&tmp); + h->base.call_id=ms_strdup(tmp); + osip_free(tmp); sal_add_call(h->base.root,h); } return 0; @@ -1017,6 +1016,19 @@ static void set_remote_ua(SalOp* op, osip_message_t *req){ } } +static void set_remote_contact(SalOp* op, osip_message_t *req){ + if (op->base.remote_contact==NULL){ + osip_contact_t *h=NULL; + osip_message_get_contact(req,0,&h); + if (h){ + char *tmp=NULL; + osip_contact_to_str(h,&tmp); + __sal_op_set_remote_contact(op,tmp); + osip_free(tmp); + } + } +} + static void set_replaces(SalOp *op, osip_message_t *req){ osip_header_t *h=NULL; @@ -1054,12 +1066,17 @@ static void inc_new_call(Sal *sal, eXosip_event_t *ev){ SalOp *op=sal_op_new(sal); osip_from_t *from,*to; osip_call_info_t *call_info; - char *tmp; + char *tmp=NULL; sdp_message_t *sdp=eXosip_get_sdp_info(ev->request); + osip_call_id_t *callid=osip_message_get_call_id(ev->request); - osip_call_id_to_str(callid,(char**)(&op->base.call_id)); - + + osip_call_id_to_str(callid,&tmp); + op->base.call_id=ms_strdup(tmp); + osip_free(tmp); + set_network_origin(op,ev->request); + set_remote_contact(op,ev->request); set_remote_ua(op,ev->request); set_replaces(op,ev->request); @@ -1237,6 +1254,7 @@ static void call_accepted(Sal *sal, eXosip_event_t *ev){ op->did=ev->did; set_remote_ua(op,ev->response); + set_remote_contact(op,ev->response); sdp=eXosip_get_sdp_info(ev->response); if (sdp){ @@ -1747,6 +1765,9 @@ static bool_t comes_from_local_if(osip_message_t *msg){ return FALSE; } +static const char *days[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; +static const char *months[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; + static void text_received(Sal *sal, eXosip_event_t *ev){ osip_body_t *body=NULL; char *from=NULL,*msg=NULL; @@ -1756,6 +1777,26 @@ static void text_received(Sal *sal, eXosip_event_t *ev){ int external_body_size=0; SalMessage salmsg; char message_id[256]={0}; + osip_header_t *date=NULL; + struct tm ret={}; + char tmp1[80]={0}; + char tmp2[80]={0}; + int i,j; + + osip_message_get_date(ev->request,0,&date); + if(date==NULL){ + ms_error("Could not get the date of message"); + return; + } + sscanf(date->hvalue,"%3c,%d%s%d%d:%d:%d",tmp1,&ret.tm_mday,tmp2, + &ret.tm_year,&ret.tm_hour,&ret.tm_min,&ret.tm_sec); + ret.tm_year-=1900; + for(i=0;i<7;i++) { + if(strcmp(tmp1,days[i])==0) ret.tm_wday=i; + } + for(j=0;j<12;j++) { + if(strcmp(tmp2,months[j])==0) ret.tm_mon=j; + } content_type= osip_message_get_content_type(ev->request); if (!content_type) { @@ -1796,6 +1837,7 @@ static void text_received(Sal *sal, eXosip_event_t *ev){ salmsg.text=msg; salmsg.url=external_body_size>0 ? unquoted_external_body_url : NULL; salmsg.message_id=message_id; + salmsg.time=mktime(&ret); sal->callbacks.text_received(sal,&salmsg); osip_free(from); } diff --git a/coreapi/sal_eXosip2_presence.c b/coreapi/sal_eXosip2_presence.c index 078ec24b4..8156c3839 100644 --- a/coreapi/sal_eXosip2_presence.c +++ b/coreapi/sal_eXosip2_presence.c @@ -81,8 +81,22 @@ void sal_remove_in_subscribe(Sal *sal, SalOp *op){ sal->in_subscribes=ms_list_remove(sal->in_subscribes,op); } +#ifdef WIN32 + +static inline char *my_ctime_r(const time_t *t, char *buf){ + strcpy(buf,ctime(t)); + return buf; +} + +#else +#define my_ctime_r ctime_r +#endif + int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg){ osip_message_t *sip=NULL; + time_t t; + time(&t); + char buf[26]; if(op->cid == -1) { @@ -97,6 +111,7 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co eXosip_message_build_request(&sip,"MESSAGE",sal_op_get_to(op), sal_op_get_from(op),sal_op_get_route(op)); if (sip!=NULL){ + osip_message_set_date(sip,my_ctime_r(&t,buf)); osip_message_set_content_type(sip,content_type); if (msg) osip_message_set_body(sip,msg,strlen(msg)); sal_add_other(op->base.root,op,sip); diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 4aad14863..9297077e6 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -394,7 +394,7 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription sdp_message_t *media_description_to_sdp(const SalMediaDescription *desc){ int i; sdp_message_t *msg=create_generic_sdp(desc); - for(i=0;instreams;++i){ + for(i=0;in_total_streams;++i){ add_line(msg,i,&desc->streams[i]); } return msg; @@ -463,6 +463,8 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ } } + desc->n_active_streams = 0; + /* for each m= line */ for (i=0; !sdp_message_endof_media (msg, i) && irtp_addr,rtp_addr,sizeof(stream->rtp_addr)); if (rtp_port) stream->rtp_port=atoi(rtp_port); + if (stream->rtp_port > 0) + desc->n_active_streams++; stream->ptime=_sdp_message_get_a_ptime(msg,i); if (strcasecmp("audio", mtype) == 0){ @@ -609,6 +613,6 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ } } } - desc->nstreams=i; + desc->n_total_streams=i; return 0; } diff --git a/coreapi/upnp.c b/coreapi/upnp.c new file mode 100644 index 000000000..5ef70ba25 --- /dev/null +++ b/coreapi/upnp.c @@ -0,0 +1,1058 @@ +/* +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 "upnp.h" +#include "private.h" +#include "lpconfig.h" + +#define UPNP_ADD_MAX_RETRY 4 +#define UPNP_REMOVE_MAX_RETRY 4 +#define UPNP_SECTION_NAME "uPnP" + +/* + * uPnP Definitions + */ + +typedef struct _UpnpPortBinding { + ms_mutex_t mutex; + LinphoneUpnpState state; + upnp_igd_ip_protocol protocol; + char local_addr[LINPHONE_IPADDR_SIZE]; + int local_port; + char external_addr[LINPHONE_IPADDR_SIZE]; + int external_port; + int retry; + int ref; + bool_t to_remove; + bool_t to_add; +} UpnpPortBinding; + +typedef struct _UpnpStream { + UpnpPortBinding *rtp; + UpnpPortBinding *rtcp; + LinphoneUpnpState state; +} UpnpStream; + +struct _UpnpSession { + LinphoneCall *call; + UpnpStream *audio; + UpnpStream *video; + LinphoneUpnpState state; +}; + +struct _UpnpContext { + LinphoneCore *lc; + upnp_igd_context *upnp_igd_ctxt; + UpnpPortBinding *sip_tcp; + UpnpPortBinding *sip_tls; + UpnpPortBinding *sip_udp; + LinphoneUpnpState state; + MSList *removing_configs; + MSList *adding_configs; + MSList *pending_bindings; + + ms_mutex_t mutex; + ms_cond_t empty_cond; + +}; + + +bool_t linphone_core_upnp_hook(void *data); +void linphone_core_upnp_refresh(UpnpContext *ctx); + +UpnpPortBinding *linphone_upnp_port_binding_new(); +UpnpPortBinding *linphone_upnp_port_binding_copy(const UpnpPortBinding *port); +bool_t linphone_upnp_port_binding_equal(const UpnpPortBinding *port1, const UpnpPortBinding *port2); +UpnpPortBinding *linphone_upnp_port_binding_equivalent_in_list(MSList *list, const UpnpPortBinding *port); +UpnpPortBinding *linphone_upnp_port_binding_retain(UpnpPortBinding *port); +void linphone_upnp_port_binding_log(int level, const char *msg, const UpnpPortBinding *port); +void linphone_upnp_port_binding_release(UpnpPortBinding *port); + +MSList *linphone_upnp_config_list_port_bindings(struct _LpConfig *lpc); +void linphone_upnp_config_add_port_binding(UpnpContext *lupnp, const UpnpPortBinding *port); +void linphone_upnp_config_remove_port_binding(UpnpContext *lupnp, const UpnpPortBinding *port); + +int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortBinding *port); +int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBinding *port); + + +/** + * uPnP Callbacks + */ + +/* Convert uPnP IGD logs to ortp logs */ +void linphone_upnp_igd_print(void *cookie, upnp_igd_print_level level, const char *fmt, va_list list) { + int ortp_level = ORTP_DEBUG; + switch(level) { + case UPNP_IGD_MESSAGE: + ortp_level = ORTP_MESSAGE; + break; + case UPNP_IGD_WARNING: + ortp_level = ORTP_DEBUG; // Too verbose otherwise + break; + case UPNP_IGD_ERROR: + ortp_level = ORTP_DEBUG; // Too verbose otherwise + break; + default: + break; + } + ortp_logv(ortp_level, fmt, list); +} + +void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { + UpnpContext *lupnp = (UpnpContext *)cookie; + upnp_igd_port_mapping *mapping = NULL; + UpnpPortBinding *port_mapping = NULL; + const char *ip_address = NULL; + const char *connection_status = NULL; + bool_t nat_enabled = FALSE; + LinphoneUpnpState old_state; + + if(lupnp == NULL || lupnp->upnp_igd_ctxt == NULL) { + ms_error("uPnP IGD: Invalid context in callback"); + return; + } + + ms_mutex_lock(&lupnp->mutex); + old_state = lupnp->state; + + switch(event) { + case UPNP_IGD_EXTERNAL_IPADDRESS_CHANGED: + case UPNP_IGD_NAT_ENABLED_CHANGED: + case UPNP_IGD_CONNECTION_STATUS_CHANGED: + ip_address = upnp_igd_get_external_ipaddress(lupnp->upnp_igd_ctxt); + connection_status = upnp_igd_get_connection_status(lupnp->upnp_igd_ctxt); + nat_enabled = upnp_igd_get_nat_enabled(lupnp->upnp_igd_ctxt); + + if(ip_address == NULL || connection_status == NULL) { + ms_message("uPnP IGD: Pending"); + lupnp->state = LinphoneUpnpStatePending; + } else if(strcasecmp(connection_status, "Connected") || !nat_enabled) { + ms_message("uPnP IGD: Not Available"); + lupnp->state = LinphoneUpnpStateNotAvailable; + } else { + ms_message("uPnP IGD: Connected"); + lupnp->state = LinphoneUpnpStateOk; + if(old_state != LinphoneUpnpStateOk) { + linphone_core_upnp_refresh(lupnp); + } + } + + break; + + case UPNP_IGD_PORT_MAPPING_ADD_SUCCESS: + mapping = (upnp_igd_port_mapping *) arg; + port_mapping = (UpnpPortBinding*) mapping->cookie; + port_mapping->external_port = mapping->remote_port; + port_mapping->state = LinphoneUpnpStateOk; + linphone_upnp_port_binding_log(ORTP_MESSAGE, "Added port binding", port_mapping); + linphone_upnp_config_add_port_binding(lupnp, port_mapping); + + break; + + case UPNP_IGD_PORT_MAPPING_ADD_FAILURE: + mapping = (upnp_igd_port_mapping *) arg; + port_mapping = (UpnpPortBinding*) mapping->cookie; + port_mapping->external_port = -1; //Force random external port + if(linphone_upnp_context_send_add_port_binding(lupnp, port_mapping) != 0) { + linphone_upnp_port_binding_log(ORTP_ERROR, "Can't add port binding", port_mapping); + } + + break; + + case UPNP_IGD_PORT_MAPPING_REMOVE_SUCCESS: + mapping = (upnp_igd_port_mapping *) arg; + port_mapping = (UpnpPortBinding*) mapping->cookie; + port_mapping->state = LinphoneUpnpStateIdle; + linphone_upnp_port_binding_log(ORTP_MESSAGE, "Removed port binding", port_mapping); + linphone_upnp_config_remove_port_binding(lupnp, port_mapping); + + break; + + case UPNP_IGD_PORT_MAPPING_REMOVE_FAILURE: + mapping = (upnp_igd_port_mapping *) arg; + port_mapping = (UpnpPortBinding*) mapping->cookie; + if(linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping) != 0) { + linphone_upnp_port_binding_log(ORTP_ERROR, "Can't remove port binding", port_mapping); + linphone_upnp_config_remove_port_binding(lupnp, port_mapping); + } + + break; + + default: + break; + } + + if(port_mapping != NULL) { + /* + * Execute delayed actions + */ + if(port_mapping->to_remove) { + if(port_mapping->state == LinphoneUpnpStateOk) { + port_mapping->to_remove = FALSE; + linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping); + } else if(port_mapping->state == LinphoneUpnpStateKo) { + port_mapping->to_remove = FALSE; + } + } + if(port_mapping->to_add) { + if(port_mapping->state == LinphoneUpnpStateIdle || port_mapping->state == LinphoneUpnpStateKo) { + port_mapping->to_add = FALSE; + linphone_upnp_context_send_add_port_binding(lupnp, port_mapping); + } + } + + lupnp->pending_bindings = ms_list_remove(lupnp->pending_bindings, port_mapping); + linphone_upnp_port_binding_release(port_mapping); + } + + /* + * If there is no pending binding emit a signal + */ + if(lupnp->pending_bindings == NULL) { + pthread_cond_signal(&lupnp->empty_cond); + } + ms_mutex_unlock(&lupnp->mutex); +} + + +/** + * uPnP Context + */ + +UpnpContext* linphone_upnp_context_new(LinphoneCore *lc) { + LCSipTransports transport; + UpnpContext *lupnp = (UpnpContext *)ms_new0(UpnpContext,1); + const char *ip_address; + + ms_mutex_init(&lupnp->mutex, NULL); + ms_cond_init(&lupnp->empty_cond, NULL); + + lupnp->lc = lc; + lupnp->pending_bindings = NULL; + lupnp->adding_configs = NULL; + lupnp->removing_configs = NULL; + lupnp->state = LinphoneUpnpStateIdle; + ms_message("uPnP IGD: New %p for core %p", lupnp, lc); + + linphone_core_get_sip_transports(lc, &transport); + if(transport.udp_port != 0) { + lupnp->sip_udp = linphone_upnp_port_binding_new(); + lupnp->sip_udp->protocol = UPNP_IGD_IP_PROTOCOL_UDP; + lupnp->sip_udp->local_port = transport.udp_port; + lupnp->sip_udp->external_port = transport.udp_port; + } else { + lupnp->sip_udp = NULL; + } + if(transport.tcp_port != 0) { + lupnp->sip_tcp = linphone_upnp_port_binding_new(); + lupnp->sip_tcp->protocol = UPNP_IGD_IP_PROTOCOL_TCP; + lupnp->sip_tcp->local_port = transport.tcp_port; + lupnp->sip_tcp->external_port = transport.tcp_port; + } else { + lupnp->sip_tcp = NULL; + } + if(transport.tls_port != 0) { + lupnp->sip_tls = linphone_upnp_port_binding_new(); + lupnp->sip_tls->protocol = UPNP_IGD_IP_PROTOCOL_TCP; + lupnp->sip_tls->local_port = transport.tls_port; + lupnp->sip_tls->external_port = transport.tls_port; + } else { + lupnp->sip_tls = NULL; + } + + linphone_core_add_iterate_hook(lc, linphone_core_upnp_hook, lupnp); + + lupnp->upnp_igd_ctxt = NULL; + lupnp->upnp_igd_ctxt = upnp_igd_create(linphone_upnp_igd_callback, linphone_upnp_igd_print, lupnp); + if(lupnp->upnp_igd_ctxt == NULL) { + lupnp->state = LinphoneUpnpStateKo; + ms_error("Can't create uPnP IGD context"); + return NULL; + } + + ip_address = upnp_igd_get_local_ipaddress(lupnp->upnp_igd_ctxt); + if(lupnp->sip_udp != NULL) { + strncpy(lupnp->sip_udp->local_addr, ip_address, sizeof(lupnp->sip_udp->local_addr)); + } + if(lupnp->sip_tcp != NULL) { + strncpy(lupnp->sip_tcp->local_addr, ip_address, sizeof(lupnp->sip_tcp->local_addr)); + } + if(lupnp->sip_tls != NULL) { + strncpy(lupnp->sip_tls->local_addr, ip_address, sizeof(lupnp->sip_tls->local_addr)); + } + + lupnp->state = LinphoneUpnpStatePending; + upnp_igd_start(lupnp->upnp_igd_ctxt); + + return lupnp; +} + +void linphone_upnp_context_destroy(UpnpContext *lupnp) { + /* + * Not need, all hooks are removed before + * linphone_core_remove_iterate_hook(lc, linphone_core_upnp_hook, lc); + */ + + ms_mutex_lock(&lupnp->mutex); + + /* Send port binding removes */ + if(lupnp->sip_udp != NULL) { + linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_udp); + lupnp->sip_udp = NULL; + } + if(lupnp->sip_tcp != NULL) { + linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_tcp); + lupnp->sip_tcp = NULL; + } + if(lupnp->sip_tls != NULL) { + linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_tls); + lupnp->sip_tcp = NULL; + } + + /* Wait all pending bindings are done */ + if(lupnp->pending_bindings != NULL) { + ms_message("uPnP IGD: Wait all pending port bindings ..."); + ms_cond_wait(&lupnp->empty_cond, &lupnp->mutex); + } + ms_mutex_unlock(&lupnp->mutex); + + if(lupnp->upnp_igd_ctxt != NULL) { + upnp_igd_destroy(lupnp->upnp_igd_ctxt); + } + + /* Run one time the hook for configuration update */ + linphone_core_upnp_hook(lupnp); + + /* Release port bindings */ + if(lupnp->sip_udp != NULL) { + linphone_upnp_port_binding_release(lupnp->sip_udp); + lupnp->sip_udp = NULL; + } + if(lupnp->sip_tcp != NULL) { + linphone_upnp_port_binding_release(lupnp->sip_tcp); + lupnp->sip_tcp = NULL; + } + if(lupnp->sip_tls != NULL) { + linphone_upnp_port_binding_release(lupnp->sip_tls); + lupnp->sip_tcp = NULL; + } + + /* Release lists */ + ms_list_for_each(lupnp->adding_configs,(void (*)(void*))linphone_upnp_port_binding_release); + lupnp->adding_configs = ms_list_free(lupnp->adding_configs); + ms_list_for_each(lupnp->removing_configs,(void (*)(void*))linphone_upnp_port_binding_release); + lupnp->removing_configs = ms_list_free(lupnp->removing_configs); + ms_list_for_each(lupnp->pending_bindings,(void (*)(void*))linphone_upnp_port_binding_release); + lupnp->pending_bindings = ms_list_free(lupnp->pending_bindings); + + ms_mutex_destroy(&lupnp->mutex); + ms_cond_destroy(&lupnp->empty_cond); + + ms_message("uPnP IGD: destroy %p", lupnp); + ms_free(lupnp); +} + +LinphoneUpnpState linphone_upnp_context_get_state(UpnpContext *ctx) { + return ctx->state; +} + +const char* linphone_upnp_context_get_external_ipaddress(UpnpContext *ctx) { + return upnp_igd_get_external_ipaddress(ctx->upnp_igd_ctxt); +} + +int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBinding *port) { + upnp_igd_port_mapping mapping; + char description[128]; + int ret; + + // Compute port binding state + if(port->state != LinphoneUpnpStateAdding) { + port->to_remove = FALSE; + switch(port->state) { + case LinphoneUpnpStateKo: + case LinphoneUpnpStateIdle: { + port->retry = 0; + port->state = LinphoneUpnpStateAdding; + } + break; + case LinphoneUpnpStateRemoving: { + port->to_add = TRUE; + return 0; + } + break; + default: + return 0; + } + } + + if(port->retry >= UPNP_ADD_MAX_RETRY) { + ret = -1; + } else { + mapping.cookie = linphone_upnp_port_binding_retain(port); + lupnp->pending_bindings = ms_list_append(lupnp->pending_bindings, mapping.cookie); + + mapping.local_port = port->local_port; + mapping.local_host = port->local_addr; + if(port->external_port == -1) + mapping.remote_port = rand()%(0xffff - 1024) + 1024; + else + mapping.remote_port = port->external_port; + mapping.remote_host = ""; + snprintf(description, 128, "%s %s at %s:%d", + PACKAGE_NAME, + (port->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP": "UDP", + port->local_addr, port->local_port); + mapping.description = description; + mapping.protocol = port->protocol; + + port->retry++; + linphone_upnp_port_binding_log(ORTP_MESSAGE, "Try to add port binding", port); + ret = upnp_igd_add_port_mapping(lupnp->upnp_igd_ctxt, &mapping); + } + if(ret != 0) { + port->state = LinphoneUpnpStateKo; + } + return ret; +} + +int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortBinding *port) { + upnp_igd_port_mapping mapping; + int ret; + + // Compute port binding state + if(port->state != LinphoneUpnpStateRemoving) { + port->to_add = FALSE; + switch(port->state) { + case LinphoneUpnpStateOk: { + port->retry = 0; + port->state = LinphoneUpnpStateRemoving; + } + break; + case LinphoneUpnpStateAdding: { + port->to_remove = TRUE; + return 0; + } + break; + default: + return 0; + } + } + + if(port->retry >= UPNP_REMOVE_MAX_RETRY) { + ret = -1; + } else { + mapping.cookie = linphone_upnp_port_binding_retain(port); + lupnp->pending_bindings = ms_list_append(lupnp->pending_bindings, mapping.cookie); + + mapping.remote_port = port->external_port; + mapping.remote_host = ""; + mapping.protocol = port->protocol; + port->retry++; + linphone_upnp_port_binding_log(ORTP_MESSAGE, "Try to remove port binding", port); + ret = upnp_igd_delete_port_mapping(lupnp->upnp_igd_ctxt, &mapping); + } + if(ret != 0) { + port->state = LinphoneUpnpStateKo; + } + return ret; +} + +/* + * uPnP Core interfaces + */ + +int linphone_core_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool_t video) { + LinphoneCore *lc = call->core; + UpnpContext *lupnp = lc->upnp; + int ret = -1; + const char *local_addr, *external_addr; + + if(lupnp == NULL) { + return ret; + } + + ms_mutex_lock(&lupnp->mutex); + // Don't handle when the call + if(lupnp->state == LinphoneUpnpStateOk && call->upnp_session != NULL) { + ret = 0; + local_addr = upnp_igd_get_local_ipaddress(lupnp->upnp_igd_ctxt); + external_addr = upnp_igd_get_external_ipaddress(lupnp->upnp_igd_ctxt); + + /* + * Audio part + */ + strncpy(call->upnp_session->audio->rtp->local_addr, local_addr, LINPHONE_IPADDR_SIZE); + strncpy(call->upnp_session->audio->rtp->external_addr, external_addr, LINPHONE_IPADDR_SIZE); + call->upnp_session->audio->rtp->local_port = call->audio_port; + if(call->upnp_session->audio->rtp->external_port == -1) { + call->upnp_session->audio->rtp->external_port = call->audio_port; + } + strncpy(call->upnp_session->audio->rtcp->local_addr, local_addr, LINPHONE_IPADDR_SIZE); + strncpy(call->upnp_session->audio->rtcp->external_addr, external_addr, LINPHONE_IPADDR_SIZE); + call->upnp_session->audio->rtcp->local_port = call->audio_port+1; + if(call->upnp_session->audio->rtcp->external_port == -1) { + call->upnp_session->audio->rtcp->external_port = call->audio_port+1; + } + if(audio) { + // Add audio port binding + linphone_upnp_context_send_add_port_binding(lupnp, call->upnp_session->audio->rtp); + linphone_upnp_context_send_add_port_binding(lupnp, call->upnp_session->audio->rtcp); + } else { + // Remove audio port binding + linphone_upnp_context_send_remove_port_binding(lupnp, call->upnp_session->audio->rtp); + linphone_upnp_context_send_remove_port_binding(lupnp, call->upnp_session->audio->rtcp); + } + + /* + * Video part + */ + strncpy(call->upnp_session->video->rtp->local_addr, local_addr, LINPHONE_IPADDR_SIZE); + strncpy(call->upnp_session->video->rtp->external_addr, external_addr, LINPHONE_IPADDR_SIZE); + call->upnp_session->video->rtp->local_port = call->video_port; + if(call->upnp_session->video->rtp->external_port == -1) { + call->upnp_session->video->rtp->external_port = call->video_port; + } + strncpy(call->upnp_session->video->rtcp->local_addr, local_addr, LINPHONE_IPADDR_SIZE); + strncpy(call->upnp_session->video->rtcp->external_addr, external_addr, LINPHONE_IPADDR_SIZE); + call->upnp_session->video->rtcp->local_port = call->video_port+1; + if(call->upnp_session->video->rtcp->external_port == -1) { + call->upnp_session->video->rtcp->external_port = call->video_port+1; + } + if(video) { + // Add video port binding + linphone_upnp_context_send_add_port_binding(lupnp, call->upnp_session->video->rtp); + linphone_upnp_context_send_add_port_binding(lupnp, call->upnp_session->video->rtcp); + } else { + // Remove video port binding + linphone_upnp_context_send_remove_port_binding(lupnp, call->upnp_session->video->rtp); + linphone_upnp_context_send_remove_port_binding(lupnp, call->upnp_session->video->rtcp); + } + } + + ms_mutex_unlock(&lupnp->mutex); + + /* + * Update uPnP call state + */ + linphone_upnp_call_process(call); + + return ret; +} + + +int linphone_core_update_upnp_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md) { + bool_t audio = FALSE; + bool_t video = FALSE; + int i; + const SalStreamDescription *stream; + + for (i = 0; i < md->n_total_streams; i++) { + stream = &md->streams[i]; + if(stream->type == SalAudio) { + audio = TRUE; + } else if(stream->type == SalVideo) { + video = TRUE; + } + } + + return linphone_core_update_upnp_audio_video(call, audio, video); +} + +int linphone_core_update_upnp(LinphoneCore *lc, LinphoneCall *call) { + return linphone_core_update_upnp_audio_video(call, call->audiostream!=NULL, call->videostream!=NULL); +} + +void linphone_core_update_upnp_state_in_call_stats(LinphoneCall *call) { + call->stats[LINPHONE_CALL_STATS_AUDIO].upnp_state = call->upnp_session->audio->state; + call->stats[LINPHONE_CALL_STATS_VIDEO].upnp_state = call->upnp_session->video->state; +} + +int linphone_upnp_call_process(LinphoneCall *call) { + LinphoneCore *lc = call->core; + UpnpContext *lupnp = lc->upnp; + int ret = -1; + LinphoneUpnpState oldState = 0, newState = 0; + + if(lupnp == NULL) { + return ret; + } + + ms_mutex_lock(&lupnp->mutex); + + // Don't handle when the call + if(lupnp->state == LinphoneUpnpStateOk && call->upnp_session != NULL) { + ret = 0; + + /* + * Update Audio state + */ + if((call->upnp_session->audio->rtp->state == LinphoneUpnpStateOk || call->upnp_session->audio->rtp->state == LinphoneUpnpStateIdle) && + (call->upnp_session->audio->rtcp->state == LinphoneUpnpStateOk || call->upnp_session->audio->rtcp->state == LinphoneUpnpStateIdle)) { + call->upnp_session->audio->state = LinphoneUpnpStateOk; + } else if(call->upnp_session->audio->rtp->state == LinphoneUpnpStateAdding || + call->upnp_session->audio->rtp->state == LinphoneUpnpStateRemoving || + call->upnp_session->audio->rtcp->state == LinphoneUpnpStateAdding || + call->upnp_session->audio->rtcp->state == LinphoneUpnpStateRemoving) { + call->upnp_session->audio->state = LinphoneUpnpStatePending; + } else if(call->upnp_session->audio->rtcp->state == LinphoneUpnpStateKo || + call->upnp_session->audio->rtp->state == LinphoneUpnpStateKo) { + call->upnp_session->audio->state = LinphoneUpnpStateKo; + } else { + call->upnp_session->audio->state = LinphoneUpnpStateIdle; + } + + /* + * Update Video state + */ + if((call->upnp_session->video->rtp->state == LinphoneUpnpStateOk || call->upnp_session->video->rtp->state == LinphoneUpnpStateIdle) && + (call->upnp_session->video->rtcp->state == LinphoneUpnpStateOk || call->upnp_session->video->rtcp->state == LinphoneUpnpStateIdle)) { + call->upnp_session->video->state = LinphoneUpnpStateOk; + } else if(call->upnp_session->video->rtp->state == LinphoneUpnpStateAdding || + call->upnp_session->video->rtp->state == LinphoneUpnpStateRemoving || + call->upnp_session->video->rtcp->state == LinphoneUpnpStateAdding || + call->upnp_session->video->rtcp->state == LinphoneUpnpStateRemoving) { + call->upnp_session->video->state = LinphoneUpnpStatePending; + } else if(call->upnp_session->video->rtcp->state == LinphoneUpnpStateKo || + call->upnp_session->video->rtp->state == LinphoneUpnpStateKo) { + call->upnp_session->video->state = LinphoneUpnpStateKo; + } else { + call->upnp_session->video->state = LinphoneUpnpStateIdle; + } + + /* + * Update session state + */ + oldState = call->upnp_session->state; + if(call->upnp_session->audio->state == LinphoneUpnpStateOk && + call->upnp_session->video->state == LinphoneUpnpStateOk) { + call->upnp_session->state = LinphoneUpnpStateOk; + } else if(call->upnp_session->audio->state == LinphoneUpnpStatePending || + call->upnp_session->video->state == LinphoneUpnpStatePending) { + call->upnp_session->state = LinphoneUpnpStatePending; + } else if(call->upnp_session->audio->state == LinphoneUpnpStateKo || + call->upnp_session->video->state == LinphoneUpnpStateKo) { + call->upnp_session->state = LinphoneUpnpStateKo; + } else { + call->upnp_session->state = LinphoneUpnpStateIdle; + } + newState = call->upnp_session->state; + + /* When change is done proceed update */ + if(oldState != LinphoneUpnpStateOk && oldState != LinphoneUpnpStateKo && + (call->upnp_session->state == LinphoneUpnpStateOk || call->upnp_session->state == LinphoneUpnpStateKo)) { + if(call->upnp_session->state == LinphoneUpnpStateOk) + ms_message("uPnP IGD: uPnP for Call %p is ok", call); + else + ms_message("uPnP IGD: uPnP for Call %p is ko", call); + + switch (call->state) { + case LinphoneCallUpdating: + linphone_core_start_update_call(lc, call); + break; + case LinphoneCallUpdatedByRemote: + linphone_core_start_accept_call_update(lc, call); + break; + case LinphoneCallOutgoingInit: + linphone_core_proceed_with_invite_if_ready(lc, call, NULL); + break; + case LinphoneCallIdle: + linphone_core_notify_incoming_call(lc, call); + break; + default: + break; + } + } + } + + ms_mutex_unlock(&lupnp->mutex); + + /* + * Update uPnP call stats + */ + if(oldState != newState) { + linphone_core_update_upnp_state_in_call_stats(call); + } + + return ret; +} + +void linphone_core_upnp_refresh(UpnpContext *lupnp) { + MSList *global_list = NULL; + MSList *list = NULL; + MSList *item; + LinphoneCall *call; + UpnpPortBinding *port_mapping, *port_mapping2; + + ms_message("uPnP IGD: Refresh mappings"); + + /* Remove context port bindings */ + if(lupnp->sip_udp != NULL) { + global_list = ms_list_append(global_list, lupnp->sip_udp); + } + if(lupnp->sip_tcp != NULL) { + global_list = ms_list_append(global_list, lupnp->sip_tcp); + } + if(lupnp->sip_tls != NULL) { + global_list = ms_list_append(global_list, lupnp->sip_tls); + } + + /* Remove call port bindings */ + list = lupnp->lc->calls; + while(list != NULL) { + call = (LinphoneCall *)list->data; + if(call->upnp_session != NULL) { + global_list = ms_list_append(global_list, call->upnp_session->audio->rtp); + global_list = ms_list_append(global_list, call->upnp_session->audio->rtcp); + global_list = ms_list_append(global_list, call->upnp_session->video->rtp); + global_list = ms_list_append(global_list, call->upnp_session->video->rtcp); + } + list = list->next; + } + + // Remove port binding configurations + list = linphone_upnp_config_list_port_bindings(lupnp->lc->config); + for(item = list;item != NULL; item = item->next) { + port_mapping = (UpnpPortBinding *)item->data; + port_mapping2 = linphone_upnp_port_binding_equivalent_in_list(global_list, port_mapping); + if(port_mapping2 == NULL) { + linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping); + } else if(port_mapping2->state == LinphoneUpnpStateIdle){ + /* Force to remove */ + port_mapping2->state = LinphoneUpnpStateOk; + } + } + ms_list_for_each(list, (void (*)(void*))linphone_upnp_port_binding_release); + list = ms_list_free(list); + + + // (Re)Add removed port bindings + list = global_list; + while(list != NULL) { + port_mapping = (UpnpPortBinding *)list->data; + linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping); + linphone_upnp_context_send_add_port_binding(lupnp, port_mapping); + list = list->next; + } + global_list = ms_list_free(global_list); +} + +bool_t linphone_core_upnp_hook(void *data) { + char key[64]; + MSList *item; + UpnpPortBinding *port_mapping; + UpnpContext *lupnp = (UpnpContext *)data; + ms_mutex_lock(&lupnp->mutex); + + /* Add configs */ + for(item = lupnp->adding_configs;item!=NULL;item=item->next) { + port_mapping = (UpnpPortBinding *)item->data; + snprintf(key, sizeof(key), "%s-%d-%d", + (port_mapping->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP", + port_mapping->external_port, + port_mapping->local_port); + lp_config_set_string(lupnp->lc->config, UPNP_SECTION_NAME, key, "uPnP"); + linphone_upnp_port_binding_log(ORTP_DEBUG, "Configuration: Added port binding", port_mapping); + } + ms_list_for_each(lupnp->adding_configs,(void (*)(void*))linphone_upnp_port_binding_release); + lupnp->adding_configs = ms_list_free(lupnp->adding_configs); + + /* Remove configs */ + for(item = lupnp->removing_configs;item!=NULL;item=item->next) { + port_mapping = (UpnpPortBinding *)item->data; + snprintf(key, sizeof(key), "%s-%d-%d", + (port_mapping->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP", + port_mapping->external_port, + port_mapping->local_port); + lp_config_set_string(lupnp->lc->config, UPNP_SECTION_NAME, key, NULL); + linphone_upnp_port_binding_log(ORTP_DEBUG, "Configuration: Removed port binding", port_mapping); + } + ms_list_for_each(lupnp->removing_configs,(void (*)(void*))linphone_upnp_port_binding_release); + lupnp->removing_configs = ms_list_free(lupnp->removing_configs); + + ms_mutex_unlock(&lupnp->mutex); + return TRUE; +} + +int linphone_core_update_local_media_description_from_upnp(SalMediaDescription *desc, UpnpSession *session) { + int i; + SalStreamDescription *stream; + UpnpStream *upnpStream; + + for (i = 0; i < desc->n_active_streams; i++) { + stream = &desc->streams[i]; + upnpStream = NULL; + if(stream->type == SalAudio) { + upnpStream = session->audio; + } else if(stream->type == SalVideo) { + upnpStream = session->video; + } + if(upnpStream != NULL) { + if(upnpStream->rtp->state == LinphoneUpnpStateOk) { + strncpy(stream->rtp_addr, upnpStream->rtp->external_addr, LINPHONE_IPADDR_SIZE); + stream->rtp_port = upnpStream->rtp->external_port; + } + if(upnpStream->rtcp->state == LinphoneUpnpStateOk) { + strncpy(stream->rtcp_addr, upnpStream->rtcp->external_addr, LINPHONE_IPADDR_SIZE); + stream->rtcp_port = upnpStream->rtcp->external_port; + } + } + } + return 0; +} + + +/* + * uPnP Port Binding + */ + +UpnpPortBinding *linphone_upnp_port_binding_new() { + UpnpPortBinding *port = NULL; + port = ms_new0(UpnpPortBinding,1); + ms_mutex_init(&port->mutex, NULL); + port->state = LinphoneUpnpStateIdle; + port->local_addr[0] = '\0'; + port->local_port = -1; + port->external_addr[0] = '\0'; + port->external_port = -1; + port->to_remove = FALSE; + port->to_add = FALSE; + port->ref = 1; + return port; +} + +UpnpPortBinding *linphone_upnp_port_binding_copy(const UpnpPortBinding *port) { + UpnpPortBinding *new_port = NULL; + new_port = ms_new0(UpnpPortBinding,1); + memcpy(new_port, port, sizeof(UpnpPortBinding)); + ms_mutex_init(&new_port->mutex, NULL); + new_port->ref = 1; + return new_port; +} + +void linphone_upnp_port_binding_log(int level, const char *msg, const UpnpPortBinding *port) { + if(strlen(port->local_addr)) { + ortp_log(level, "uPnP IGD: %s %s|%d->%s:%d", msg, + (port->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP", + port->external_port, + port->local_addr, + port->local_port); + } else { + ortp_log(level, "uPnP IGD: %s %s|%d->%d", msg, + (port->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP", + port->external_port, + port->local_port); + } +} + +bool_t linphone_upnp_port_binding_equal(const UpnpPortBinding *port1, const UpnpPortBinding *port2) { + return port1->protocol == port2->protocol && + port1->local_port == port2->local_port && + port1->external_port == port2->external_port; +} + +UpnpPortBinding *linphone_upnp_port_binding_equivalent_in_list(MSList *list, const UpnpPortBinding *port) { + UpnpPortBinding *port_mapping; + while(list != NULL) { + port_mapping = (UpnpPortBinding *)list->data; + if(linphone_upnp_port_binding_equal(port, port_mapping)) { + return port_mapping; + } + list = list->next; + } + + return NULL; +} + +UpnpPortBinding *linphone_upnp_port_binding_retain(UpnpPortBinding *port) { + ms_mutex_lock(&port->mutex); + port->ref++; + ms_mutex_unlock(&port->mutex); + return port; +} + +void linphone_upnp_port_binding_release(UpnpPortBinding *port) { + ms_mutex_lock(&port->mutex); + if(--port->ref == 0) { + ms_mutex_unlock(&port->mutex); + ms_mutex_destroy(&port->mutex); + ms_free(port); + return; + } + ms_mutex_unlock(&port->mutex); +} + + +/* + * uPnP Stream + */ + +UpnpStream* linphone_upnp_stream_new() { + UpnpStream *stream = ms_new0(UpnpStream,1); + stream->state = LinphoneUpnpStateIdle; + stream->rtp = linphone_upnp_port_binding_new(); + stream->rtp->protocol = UPNP_IGD_IP_PROTOCOL_UDP; + stream->rtcp = linphone_upnp_port_binding_new(); + stream->rtcp->protocol = UPNP_IGD_IP_PROTOCOL_UDP; + return stream; +} + +void linphone_upnp_stream_destroy(UpnpStream* stream) { + linphone_upnp_port_binding_release(stream->rtp); + stream->rtp = NULL; + linphone_upnp_port_binding_release(stream->rtcp); + stream->rtcp = NULL; + ms_free(stream); +} + + +/* + * uPnP Session + */ + +UpnpSession* linphone_upnp_session_new(LinphoneCall* call) { + UpnpSession *session = ms_new0(UpnpSession,1); + session->call = call; + session->state = LinphoneUpnpStateIdle; + session->audio = linphone_upnp_stream_new(); + session->video = linphone_upnp_stream_new(); + return session; +} + +void linphone_upnp_session_destroy(UpnpSession *session) { + LinphoneCore *lc = session->call->core; + + if(lc->upnp != NULL) { + /* Remove bindings */ + linphone_upnp_context_send_remove_port_binding(lc->upnp, session->audio->rtp); + linphone_upnp_context_send_remove_port_binding(lc->upnp, session->audio->rtcp); + linphone_upnp_context_send_remove_port_binding(lc->upnp, session->video->rtp); + linphone_upnp_context_send_remove_port_binding(lc->upnp, session->video->rtcp); + } + + linphone_upnp_stream_destroy(session->audio); + linphone_upnp_stream_destroy(session->video); + ms_free(session); +} + +LinphoneUpnpState linphone_upnp_session_get_state(UpnpSession *session) { + return session->state; +} + +/* + * uPnP Config + */ + +struct linphone_upnp_config_list_port_bindings_struct { + struct _LpConfig *lpc; + MSList *retList; +}; + +static void linphone_upnp_config_list_port_bindings_cb(const char *entry, struct linphone_upnp_config_list_port_bindings_struct *cookie) { + char protocol_str[4]; // TCP or UDP + upnp_igd_ip_protocol protocol; + int external_port; + int local_port; + bool_t valid = TRUE; + UpnpPortBinding *port; + if(sscanf(entry, "%3s-%i-%i", protocol_str, &external_port, &local_port) == 3) { + if(strcasecmp(protocol_str, "TCP") == 0) { + protocol = UPNP_IGD_IP_PROTOCOL_TCP; + } else if(strcasecmp(protocol_str, "UDP") == 0) { + protocol = UPNP_IGD_IP_PROTOCOL_UDP; + } else { + valid = FALSE; + } + if(valid) { + port = linphone_upnp_port_binding_new(); + port->state = LinphoneUpnpStateOk; + port->protocol = protocol; + port->external_port = external_port; + port->local_port = local_port; + cookie->retList = ms_list_append(cookie->retList, port); + } + } else { + valid = FALSE; + } + if(!valid) { + ms_warning("uPnP configuration invalid line: %s", entry); + } +} + +MSList *linphone_upnp_config_list_port_bindings(struct _LpConfig *lpc) { + struct linphone_upnp_config_list_port_bindings_struct cookie = {lpc, NULL}; + lp_config_for_each_entry(lpc, UPNP_SECTION_NAME, (void(*)(const char *, void*))linphone_upnp_config_list_port_bindings_cb, &cookie); + return cookie.retList; +} + +void linphone_upnp_config_add_port_binding(UpnpContext *lupnp, const UpnpPortBinding *port) { + MSList *list; + UpnpPortBinding *list_port; + + list = lupnp->removing_configs; + while(list != NULL) { + list_port = (UpnpPortBinding *)list->data; + if(linphone_upnp_port_binding_equal(list_port, port) == TRUE) { + lupnp->removing_configs = ms_list_remove(lupnp->removing_configs, list_port); + linphone_upnp_port_binding_release(list_port); + return; + } + list = ms_list_next(list); + } + + list = lupnp->adding_configs; + while(list != NULL) { + list_port = (UpnpPortBinding *)list->data; + if(linphone_upnp_port_binding_equal(list_port, port) == TRUE) { + return; + } + list = ms_list_next(list); + } + + list_port = linphone_upnp_port_binding_copy(port); + lupnp->adding_configs = ms_list_append(lupnp->adding_configs, list_port); +} + +void linphone_upnp_config_remove_port_binding(UpnpContext *lupnp, const UpnpPortBinding *port) { + MSList *list; + UpnpPortBinding *list_port; + + list = lupnp->adding_configs; + while(list != NULL) { + list_port = (UpnpPortBinding *)list->data; + if(linphone_upnp_port_binding_equal(list_port, port) == TRUE) { + lupnp->adding_configs = ms_list_remove(lupnp->adding_configs, list_port); + linphone_upnp_port_binding_release(list_port); + return; + } + list = ms_list_next(list); + } + + list = lupnp->removing_configs; + while(list != NULL) { + list_port = (UpnpPortBinding *)list->data; + if(linphone_upnp_port_binding_equal(list_port, port) == TRUE) { + return; + } + list = ms_list_next(list); + } + + list_port = linphone_upnp_port_binding_copy(port); + lupnp->removing_configs = ms_list_append(lupnp->removing_configs, list_port); +} diff --git a/coreapi/upnp.h b/coreapi/upnp.h new file mode 100644 index 000000000..b3a5b9e49 --- /dev/null +++ b/coreapi/upnp.h @@ -0,0 +1,45 @@ +/* +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 LINPHONE_UPNP_H +#define LINPHONE_UPNP_H + +#include "mediastreamer2/upnp_igd.h" +#include "linphonecore.h" +#include "sal.h" + +typedef struct _UpnpSession UpnpSession; +typedef struct _UpnpContext UpnpContext; + +int linphone_core_update_local_media_description_from_upnp(SalMediaDescription *desc, UpnpSession *session); +int linphone_core_update_upnp_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md); +int linphone_core_update_upnp(LinphoneCore *lc, LinphoneCall *call); + +int linphone_upnp_call_process(LinphoneCall *call); +UpnpSession* linphone_upnp_session_new(LinphoneCall *call); +void linphone_upnp_session_destroy(UpnpSession* session); +LinphoneUpnpState linphone_upnp_session_get_state(UpnpSession *session); + +UpnpContext *linphone_upnp_context_new(LinphoneCore *lc); +void linphone_upnp_context_destroy(UpnpContext *ctx); +LinphoneUpnpState linphone_upnp_context_get_state(UpnpContext *ctx); +const char *linphone_upnp_context_get_external_ipaddress(UpnpContext *ctx); +void linphone_core_update_upnp_state_in_call_stats(LinphoneCall *call); + +#endif //LINPHONE_UPNP_H diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 1caded7c6..831c69a8c 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -5,6 +5,7 @@ UI_FILES= about.ui \ parameters.ui \ sip_account.ui \ call_logs.ui \ + keypad.ui \ log.ui \ buddylookup.ui \ tunnel_config.ui \ diff --git a/gtk/call_statistics.ui b/gtk/call_statistics.ui index 444710472..6ed8bd9bd 100644 --- a/gtk/call_statistics.ui +++ b/gtk/call_statistics.ui @@ -1,71 +1,34 @@ - + - False 5 Call statistics dialog - + True - False 2 - - - True - False - end - - - - - - gtk-close - True - True - True - False - True - - - False - False - 1 - - - - - False - True - end - 0 - - True - False 0 none True - False 12 True - False 6 2 True True - False Audio codec @@ -75,7 +38,6 @@ True - False Video codec @@ -87,7 +49,6 @@ True - False Audio IP bandwidth usage @@ -99,7 +60,6 @@ True - False 1 @@ -109,7 +69,6 @@ True - False 1 @@ -121,7 +80,6 @@ True - False 1 @@ -133,8 +91,7 @@ True - False - Media connectivity + Audio Media connectivity 4 @@ -143,15 +100,8 @@ - - - - - - - + True - False 1 @@ -163,7 +113,6 @@ True - False Video IP bandwidth usage @@ -175,7 +124,6 @@ True - False 1 @@ -184,6 +132,27 @@ 4 + + + True + Video Media connectivity + + + 5 + 6 + + + + + True + + + 1 + 2 + 5 + 6 + + @@ -191,7 +160,6 @@ True - False <b>Call statistics and information</b> True @@ -203,6 +171,34 @@ 1 + + + True + end + + + + + + gtk-close + True + True + True + True + + + False + False + 1 + + + + + False + end + 0 + + diff --git a/gtk/chat.c b/gtk/chat.c index 257a55758..2b3a969ed 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -90,7 +90,8 @@ void udpate_tab_chat_header(GtkWidget *chat_view,const LinphoneAddress *uri,Linp } -void linphone_gtk_push_text(GtkWidget *w, const LinphoneAddress *from, const char *message, gboolean me,LinphoneChatRoom *cr){ +void linphone_gtk_push_text(GtkWidget *w, const LinphoneAddress *from, + const char *message, gboolean me,LinphoneChatRoom *cr, time_t t){ GtkTextView *text=GTK_TEXT_VIEW(linphone_gtk_get_widget(w,"textview")); GtkTextBuffer *buffer=gtk_text_view_get_buffer(text); GtkTextIter iter,begin,end; @@ -129,15 +130,23 @@ void linphone_gtk_push_text(GtkWidget *w, const LinphoneAddress *from, const cha } g_object_set_data(G_OBJECT(linphone_gtk_get_main_window()),"history",hash); + + gtk_text_buffer_get_end_iter(buffer,&iter); if(me){ - gtk_text_buffer_get_end_iter(buffer,&iter); list=g_list_append(list,GINT_TO_POINTER(gtk_text_iter_get_line(&iter))); gtk_text_buffer_insert_with_tags_by_name(buffer,&iter,"Message in progress.. ",-1, "italic","right","small","font_grey",NULL); - gtk_text_buffer_get_end_iter(buffer,&iter); - gtk_text_buffer_insert(buffer,&iter,"\n",-1); g_object_set_data(G_OBJECT(w),"list",list); + } else { + struct tm *tm=localtime(&t); + char buf[80]; + strftime(buf,80,"%H:%M",tm); + gtk_text_buffer_insert_with_tags_by_name(buffer,&iter,buf,-1, + "italic","right","small","font_grey",NULL); } + gtk_text_buffer_get_end_iter(buffer,&iter); + gtk_text_buffer_insert(buffer,&iter,"\n",-1); + GtkTextMark *mark=gtk_text_buffer_create_mark(buffer,NULL,&iter,FALSE); gtk_text_view_scroll_mark_onscreen(text,mark); @@ -193,13 +202,7 @@ void update_chat_state_message(LinphoneChatMessageState state){ break; default : result="Message in progress.. "; } - - GDateTime *dt=g_date_time_new_now_local(); - char *time=g_date_time_format(dt,"%k:%M"); - gchar result2[80]; - sprintf(result2,"%s %s",result,time); - - gtk_text_buffer_insert_with_tags_by_name(b,&iter,result2,-1, + gtk_text_buffer_insert_with_tags_by_name(b,&iter,result,-1, "italic","right","small","font_grey",NULL); list=g_list_remove(list,g_list_nth_data(list,0)); g_object_set_data(G_OBJECT(page),"list",list); @@ -221,10 +224,10 @@ void linphone_gtk_send_text(){ entered=gtk_entry_get_text(GTK_ENTRY(entry)); if (strlen(entered)>0) { LinphoneChatMessage *msg; + msg=linphone_chat_room_create_message(cr,entered); linphone_gtk_push_text(w, linphone_gtk_get_used_identity(), - entered,TRUE,cr); - msg=linphone_chat_room_create_message(cr,entered); + entered,TRUE,cr,linphone_chat_message_get_time(msg)); linphone_chat_room_send_message2(cr,msg,on_chat_state_changed,NULL); gtk_entry_set_text(GTK_ENTRY(entry),""); } @@ -338,25 +341,25 @@ void linphone_gtk_chat_close(GtkWidget *button){ } -void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from, const char *message){ +void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, + LinphoneChatMessage *msg){ GtkWidget *main_window=linphone_gtk_get_main_window(); GtkWidget *friendlist=linphone_gtk_get_widget(main_window,"contact_list"); GtkWidget *w; - GDateTime *dt=g_date_time_new_now_local(); - char *time=g_date_time_format(dt,"%k:%M"); + w=(GtkWidget*)g_object_get_data(G_OBJECT(friendlist),"chatview"); if(w!=NULL){ - linphone_gtk_load_chatroom(room,from,w); + linphone_gtk_load_chatroom(room,linphone_chat_message_get_from(msg),w); } else { - w=linphone_gtk_init_chatroom(room,from); + w=linphone_gtk_init_chatroom(room,linphone_chat_message_get_from(msg)); g_object_set_data(G_OBJECT(friendlist),"chatview",(gpointer)w); - g_object_set_data(G_OBJECT(friendlist),"from",(gpointer)from); + g_object_set_data(G_OBJECT(friendlist),"from",(gpointer)linphone_chat_message_get_from(msg)); } - const char *display=linphone_address_get_display_name(from); + const char *display=linphone_address_get_display_name(linphone_chat_message_get_from(msg)); if (display==NULL || display[0]=='\0') { - display=linphone_address_get_username(from); + display=linphone_address_get_username(linphone_chat_message_get_from(msg)); } #ifdef HAVE_GTK_OSXs @@ -365,16 +368,15 @@ void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, const #else if(!gtk_window_is_active(GTK_WINDOW(main_window))){ if(!GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"is_notified"))){ - gchar result2[80]; - sprintf(result2,"%s \n %s sent at %s",message,display,time); - linphone_gtk_notify(NULL,result2); + linphone_gtk_notify(NULL,linphone_chat_message_get_text(msg)); g_object_set_data(G_OBJECT(w),"is_notified",GINT_TO_POINTER(TRUE)); } else { g_object_set_data(G_OBJECT(w),"is_notified",GINT_TO_POINTER(FALSE)); } } #endif - linphone_gtk_push_text(w,from,message,FALSE,room); + linphone_gtk_push_text(w,linphone_chat_message_get_from(msg), + linphone_chat_message_get_text(msg),FALSE,room,linphone_chat_message_get_time(msg)); linphone_gtk_update_chat_picture(); //gtk_window_present(GTK_WINDOW(w)); /*gtk_window_set_urgency_hint(GTK_WINDOW(w),TRUE);*/ diff --git a/gtk/incall_view.c b/gtk/incall_view.c index 192e92fab..65446d696 100644 --- a/gtk/incall_view.c +++ b/gtk/incall_view.c @@ -231,10 +231,29 @@ static const char *ice_state_to_string(LinphoneIceState ice_state){ return "invalid"; } +static const char *upnp_state_to_string(LinphoneUpnpState ice_state){ + switch(ice_state){ + case LinphoneUpnpStateIdle: + return _("uPnP not activated"); + case LinphoneUpnpStatePending: + return _("uPnP in progress"); + case LinphoneUpnpStateNotAvailable: + return _("uPnp not available"); + case LinphoneUpnpStateOk: + return _("uPnP is running"); + case LinphoneUpnpStateKo: + return _("uPnP failed"); + default: + break; + } + return "invalid"; +} + static void _refresh_call_stats(GtkWidget *callstats, LinphoneCall *call){ const LinphoneCallStats *as=linphone_call_get_audio_stats(call); const LinphoneCallStats *vs=linphone_call_get_video_stats(call); - LinphoneIceState ice_state=as->ice_state; + const char *audio_media_connectivity = _("Direct"); + const char *video_media_connectivity = _("Direct"); gchar *tmp=g_strdup_printf(_("download: %f\nupload: %f (kbit/s)"), as->download_bandwidth,as->upload_bandwidth); gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"audio_bandwidth_usage")),tmp); @@ -243,7 +262,18 @@ static void _refresh_call_stats(GtkWidget *callstats, LinphoneCall *call){ vs->download_bandwidth,vs->upload_bandwidth); gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"video_bandwidth_usage")),tmp); g_free(tmp); - gtk_label_set_text(GTK_LABEL(linphone_gtk_get_widget(callstats,"media_connectivity")),ice_state_to_string(ice_state)); + if(as->upnp_state != LinphoneUpnpStateNotAvailable && as->upnp_state != LinphoneUpnpStateIdle) { + audio_media_connectivity = upnp_state_to_string(as->upnp_state); + } else if(as->ice_state != LinphoneIceStateNotActivated) { + audio_media_connectivity = ice_state_to_string(as->ice_state); + } + gtk_label_set_text(GTK_LABEL(linphone_gtk_get_widget(callstats,"audio_media_connectivity")),audio_media_connectivity); + if(vs->upnp_state != LinphoneUpnpStateNotAvailable && vs->upnp_state != LinphoneUpnpStateIdle) { + video_media_connectivity = upnp_state_to_string(vs->upnp_state); + } else if(vs->ice_state != LinphoneIceStateNotActivated) { + video_media_connectivity = ice_state_to_string(vs->ice_state); + } + gtk_label_set_text(GTK_LABEL(linphone_gtk_get_widget(callstats,"video_media_connectivity")),video_media_connectivity); } static gboolean refresh_call_stats(GtkWidget *callstats){ @@ -642,7 +672,7 @@ void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){ gtk_widget_hide(linphone_gtk_get_widget(callview,"answer_decline_panel")); gtk_label_set_markup(GTK_LABEL(status),in_conf ? _("In conference") : _("In call")); - + gtk_widget_set_sensitive(linphone_gtk_get_widget(callview,"conference_button"),!in_conf); gtk_widget_set_sensitive(linphone_gtk_get_widget(callview,"transfer_button"),!in_conf); diff --git a/gtk/keypad.ui b/gtk/keypad.ui new file mode 100644 index 000000000..6b5376762 --- /dev/null +++ b/gtk/keypad.ui @@ -0,0 +1,277 @@ + + + + + + False + + + True + False + 0.5 + none + + + True + False + 0 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 4 + 4 + 4 + True + + + D + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + + + 3 + 4 + 3 + 4 + + + + + # + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + + + 2 + 3 + 3 + 4 + + + + + 0 + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + + + 1 + 2 + 3 + 4 + + + + + * + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + + + 3 + 4 + + + + + C + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + + + 3 + 4 + 2 + 3 + + + + + 9 + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + + + 2 + 3 + 2 + 3 + + + + + 8 + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + + + 1 + 2 + 2 + 3 + + + + + 7 + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + + + 2 + 3 + + + + + B + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + + + 3 + 4 + 1 + 2 + + + + + 6 + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + + + 2 + 3 + 1 + 2 + + + + + 5 + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + + + 1 + 2 + 1 + 2 + + + + + 4 + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + + + 1 + 2 + + + + + A + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + + + 3 + 4 + + + + + 3 + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + + + 2 + 3 + + + + + 2 + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + + + 1 + 2 + + + + + 1 + 40 + 40 + 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/linphone.h b/gtk/linphone.h index 367b18c26..abb395127 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -74,7 +74,7 @@ void linphone_gtk_fill_soundcards(GtkWidget *pb); void linphone_gtk_fill_webcams(GtkWidget *pb); void linphone_gtk_load_identities(void); LinphoneChatRoom * linphone_gtk_create_chatroom(const LinphoneAddress *with); -void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from, const char *message); +void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *msg); void linphone_gtk_call_log_update(GtkWidget *w); void linphone_gtk_create_log_window(void); void linphone_gtk_log_show(void); @@ -102,7 +102,6 @@ void linphone_gtk_terminate_call(GtkWidget *button); void update_tab_header(LinphoneCall *call,gboolean pause); void linphone_gtk_show_directory_search(void); - void linphone_gtk_status_icon_set_blinking(gboolean val); void linphone_gtk_notify(LinphoneCall *call, const char *msg); LinphoneChatRoom *linphone_gtk_start_chat(GtkTreeView* t); diff --git a/gtk/main.c b/gtk/main.c index 12e84bc97..114a7244f 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -230,7 +230,8 @@ static void linphone_gtk_init_liblinphone(const char *config_file, vtable.display_warning=linphone_gtk_display_warning; vtable.display_url=linphone_gtk_display_url; vtable.call_log_updated=linphone_gtk_call_log_updated; - vtable.text_received=linphone_gtk_text_received; + //vtable.text_received=linphone_gtk_text_received; + vtable.message_received=linphone_gtk_text_received; vtable.refer_received=linphone_gtk_refer_received; vtable.buddy_info_updated=linphone_gtk_buddy_info_updated; vtable.call_encryption_changed=linphone_gtk_call_encryption_changed; @@ -744,7 +745,9 @@ static void linphone_gtk_update_call_buttons(LinphoneCall *call){ linphone_gtk_enable_conference_button(lc,FALSE); } update_video_title(); - if (call) linphone_gtk_update_video_button(call); + if (call) { + linphone_gtk_update_video_button(call); + } } static gboolean linphone_gtk_start_call_do(GtkWidget *uri_bar){ @@ -1444,7 +1447,7 @@ void linphone_gtk_load_identities(void){ static void linphone_gtk_dtmf_pressed(GtkButton *button){ const char *label=(char *)g_object_get_data(G_OBJECT(button),"label"); - GtkWidget *uri_bar=linphone_gtk_get_widget(gtk_widget_get_toplevel(GTK_WIDGET(button)),"uribar"); + GtkWidget *uri_bar=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"); int pos=-1; gtk_editable_insert_text(GTK_EDITABLE(uri_bar),label,1,&pos); linphone_core_play_dtmf (linphone_gtk_get_core(),label[0],-1); @@ -1458,8 +1461,8 @@ static void linphone_gtk_dtmf_released(GtkButton *button){ } -static void linphone_gtk_connect_digits(void){ - GtkContainer *cont=GTK_CONTAINER(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"dtmf_table")); +static void linphone_gtk_connect_digits(GtkWidget *w){ + GtkContainer *cont=GTK_CONTAINER(linphone_gtk_get_widget(w,"dtmf_table")); GList *children=gtk_container_get_children(cont); GList *elem; for(elem=children;elem!=NULL;elem=elem->next){ @@ -1497,11 +1500,10 @@ static void linphone_gtk_configure_main_window(){ static const char *home; static const char *start_call_icon; static const char *add_call_icon; - //static const char *stop_call_icon; static const char *search_icon; static gboolean update_check_menu; static gboolean buttons_have_borders; - static gboolean show_abcd; + //static gboolean show_abcd; GtkWidget *w=linphone_gtk_get_main_window(); GHashTable *contacts_history; @@ -1513,11 +1515,10 @@ static void linphone_gtk_configure_main_window(){ home=linphone_gtk_get_ui_config("home","http://www.linphone.org"); start_call_icon=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png"); add_call_icon=linphone_gtk_get_ui_config("add_call_icon","addcall-green.png"); - //stop_call_icon=linphone_gtk_get_ui_config("stop_call_icon","stopcall-small.png"); search_icon=linphone_gtk_get_ui_config("directory_search_icon",NULL); update_check_menu=linphone_gtk_get_ui_config_int("update_check_menu",0); buttons_have_borders=linphone_gtk_get_ui_config_int("buttons_border",1); - show_abcd=linphone_gtk_get_ui_config_int("show_abcd",1); + //show_abcd=linphone_gtk_get_ui_config_int("show_abcd",1); config_loaded=TRUE; } linphone_gtk_configure_window(w,"main_window"); @@ -1558,7 +1559,7 @@ static void linphone_gtk_configure_main_window(){ } */ } - { + /*{ GdkPixbuf *pbuf=create_pixbuf("dialer-orange.png"); if (pbuf) { GtkImage *img=GTK_IMAGE(linphone_gtk_get_widget(w,"keypad_tab_icon")); @@ -1570,20 +1571,20 @@ static void linphone_gtk_configure_main_window(){ g_object_unref(G_OBJECT(scaled)); g_object_unref(G_OBJECT(pbuf)); } - } + }*/ if (linphone_gtk_can_manage_accounts()) { gtk_widget_show(linphone_gtk_get_widget(w,"assistant_item")); } if (update_check_menu){ gtk_widget_show(linphone_gtk_get_widget(w,"versioncheck_item")); } - if (!show_abcd){ + /*if (!show_abcd){ gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_A")); gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_B")); gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_C")); gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_D")); gtk_table_resize(GTK_TABLE(linphone_gtk_get_widget(w,"dtmf_table")),4,3); - } + }*/ } void linphone_gtk_manage_login(void){ @@ -1647,24 +1648,34 @@ void linphone_gtk_init_dtmf_table(GtkWidget *mw){ g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_0")),"label","0"); g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_#")),"label","#"); g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_*")),"label","*"); - +} + +void linphone_gtk_create_keypad(GtkWidget *button){ + GtkWidget *mw=linphone_gtk_get_main_window(); + GtkWidget *k=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"keypad"); + if(k!=NULL){ + gtk_widget_destroy(k); + } + GtkWidget *keypad=linphone_gtk_create_window("keypad"); + linphone_gtk_connect_digits(keypad); + linphone_gtk_init_dtmf_table(keypad); + g_object_set_data(G_OBJECT(mw),"keypad",(gpointer)keypad); + gtk_widget_show(keypad); } static void linphone_gtk_init_main_window(){ GtkWidget *main_window; - linphone_gtk_configure_main_window(); linphone_gtk_manage_login(); load_uri_history(); linphone_gtk_load_identities(); linphone_gtk_set_my_presence(linphone_core_get_presence_info(linphone_gtk_get_core())); linphone_gtk_show_friends(); - linphone_gtk_connect_digits(); main_window=linphone_gtk_get_main_window(); linphone_gtk_call_log_update(main_window); - linphone_gtk_init_dtmf_table(main_window); linphone_gtk_update_call_buttons (NULL); + g_object_set_data(G_OBJECT(main_window),"keypad",NULL); g_object_set_data(G_OBJECT(main_window),"is_conf",GINT_TO_POINTER(FALSE)); /*prevent the main window from being destroyed by a user click on WM controls, instead we hide it*/ g_signal_connect (G_OBJECT (main_window), "delete-event", diff --git a/gtk/main.ui b/gtk/main.ui index f82875cb6..50883c3f0 100644 --- a/gtk/main.ui +++ b/gtk/main.ui @@ -70,13 +70,13 @@ 90 - 10 + 30 True False False - False + True 2 @@ -155,7 +155,7 @@ True False - + True False gtk-ok @@ -273,7 +273,17 @@ True False - + + True + False + label + center + + + True + True + 0 + @@ -282,19 +292,6 @@ 0 - - - True - False - label - center - - - True - True - 1 - - False @@ -354,7 +351,7 @@ False True - 2 + 1 @@ -419,7 +416,7 @@ False False - 3 + 2 @@ -460,7 +457,7 @@ False False - 4 + 3 @@ -556,7 +553,7 @@ False False 7 - 5 + 4 @@ -640,6 +637,36 @@ False gtk-connect + + True + False + gtk-add + + + True + False + gtk-add + + + True + False + gtk-add + + + True + False + gtk-add + + + True + False + gtk-missing-image + + + True + False + gtk-select-color + True False @@ -916,6 +943,7 @@ True True + 2 0 @@ -944,6 +972,7 @@ False True + 6 2 @@ -1062,6 +1091,22 @@ 2 + + + True + True + True + False + image18 + + + + False + False + end + 3 + + False @@ -1073,7 +1118,7 @@ False False - 12 + 6 0 @@ -1082,453 +1127,10 @@ True True - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - 0.5 - none - - - True - False - 0 - 0 - - - True - False - 0 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 4 - 4 - 4 - True - - - D - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - - - 3 - 4 - 3 - 4 - - - - - # - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - - - 2 - 3 - 3 - 4 - - - - - 0 - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - - - 1 - 2 - 3 - 4 - - - - - * - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - - - 3 - 4 - - - - - C - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - - - 3 - 4 - 2 - 3 - - - - - 9 - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - - - 2 - 3 - 2 - 3 - - - - - 8 - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - - - 1 - 2 - 2 - 3 - - - - - 7 - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - - - 2 - 3 - - - - - B - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - - - 3 - 4 - 1 - 2 - - - - - 6 - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - - - 2 - 3 - 1 - 2 - - - - - 5 - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - - - 1 - 2 - 1 - 2 - - - - - 4 - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - - - 1 - 2 - - - - - A - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - - - 3 - 4 - - - - - 3 - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - - - 2 - 3 - - - - - 2 - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - - - 1 - 2 - - - - - 1 - 40 - 40 - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - - - - - - - - - - - - - - True - True - 0 - - - - - False - 0 - none - - - False - - - True - True - - True - False - False - True - True - - - True - True - 0 - - - - - True - True - True - False - none - - - - True - False - - - True - False - gtk-find - - - True - True - 0 - - - - - True - False - Search - - - True - True - 1 - - - - - - - False - True - 1 - - - - - - - True - False - <b>Add contacts from directory</b> - True - - - - - False - False - 5 - 2 - - - - - True - False - - - Add contact - True - True - False - image10 - - - - False - False - 0 - - - - - False - False - 3 - - - - - True - True - 0 - - - + - - True - False - - - True - False - gtk-missing-image - 1 - - - True - True - 0 - - - - - True - False - Keypad - - - True - True - 1 - - - - - False - + @@ -1539,6 +1141,28 @@ True False 2 + + + True + True + never + + + 350 + True + True + False + + + + + + + True + True + 0 + + True @@ -1571,29 +1195,137 @@ False True end - 0 + 1 - + True - True - never + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - 350 - True - True - False - - + + + + + False + 0 + none + + + False + + + True + True + + True + False + False + True + True + + + True + True + 0 + + + + + True + True + True + False + none + + + + True + False + + + True + False + gtk-find + + + True + True + 0 + + + + + True + False + Search + + + True + True + 1 + + + + + + + False + True + 1 + + + + + + + True + False + <b>Add contacts from directory</b> + True + + + + False + False + 5 + 2 + + + + + True + False + + + Add contact + True + True + False + image16 + + + + False + False + 0 + + + + + False + False + 3 + - True - True - 1 + False + False + end + 2 @@ -1654,7 +1386,7 @@ True True - 4 + 6 1 diff --git a/gtk/parameters.ui b/gtk/parameters.ui index 130b7e7c5..e4a6430fa 100644 --- a/gtk/parameters.ui +++ b/gtk/parameters.ui @@ -765,6 +765,23 @@ 3 + + + Behind NAT / Firewall (use uPnP) + False + True + True + False + True + no_nat + + + + True + True + 4 + + True diff --git a/gtk/propertybox.c b/gtk/propertybox.c index 41fe854ed..c2258ea57 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -236,6 +236,11 @@ void linphone_gtk_use_ice_toggled(GtkWidget *w){ linphone_core_set_firewall_policy(linphone_gtk_get_core(),LinphonePolicyUseIce); } +void linphone_gtk_use_upnp_toggled(GtkWidget *w){ + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) + linphone_core_set_firewall_policy(linphone_gtk_get_core(),LinphonePolicyUseUpnp); +} + void linphone_gtk_mtu_changed(GtkWidget *w){ if (GTK_WIDGET_SENSITIVE(w)) linphone_core_set_mtu(linphone_gtk_get_core(),gtk_spin_button_get_value(GTK_SPIN_BUTTON(w))); @@ -1074,6 +1079,9 @@ void linphone_gtk_show_parameters(void){ case LinphonePolicyUseIce: gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"use_ice")),TRUE); break; + case LinphonePolicyUseUpnp: + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"use_upnp")),TRUE); + break; } mtu=linphone_core_get_mtu(lc); if (mtu<=0){ diff --git a/java/common/org/linphone/core/LinphoneCall.java b/java/common/org/linphone/core/LinphoneCall.java index ac7b14d8d..79f38633b 100644 --- a/java/common/org/linphone/core/LinphoneCall.java +++ b/java/common/org/linphone/core/LinphoneCall.java @@ -102,22 +102,22 @@ public interface LinphoneCall { /** * The call's parameters are updated, used for example when video is asked by remote */ - public static final State CallUpdatedByRemote = new State(15, "CallUpdatedByRemote"); + public static final State CallUpdatedByRemote = new State(15, "UpdatedByRemote"); /** * We are proposing early media to an incoming call */ - public static final State CallIncomingEarlyMedia = new State(16,"CallIncomingEarlyMedia"); + public static final State CallIncomingEarlyMedia = new State(16,"IncomingEarlyMedia"); /** - * The remote accepted the call update initiated by us + * We have initiated a call update. When the remote accepts the call update, state will move to StreamsRunning. */ - public static final State CallUpdated = new State(17, "CallUpdated"); + public static final State CallUpdating = new State(17, "Updating"); /** * The call object is now released. */ - public static final State CallReleased = new State(18,"CallReleased"); + public static final State CallReleased = new State(18,"Released"); private State(int value,String stringValue) { @@ -160,17 +160,6 @@ public interface LinphoneCall { **/ LinphoneCallLog getCallLog(); - /** - * Set the audio statistics associated with this call. - * @return LinphoneCallStats - */ - void setAudioStats(LinphoneCallStats stats); - - /** - * Set the video statistics associated with this call. - * @return LinphoneCallStats - */ - void setVideoStats(LinphoneCallStats stats); /** * Get the audio statistics associated with this call. @@ -184,6 +173,10 @@ public interface LinphoneCall { */ LinphoneCallStats getVideoStats(); + /** + * Get call's remote parameters, as proposed by far end. + * This is useful for example to know if far end supports video or encryption. + **/ LinphoneCallParams getRemoteParams(); LinphoneCallParams getCurrentParamsCopy(); @@ -273,6 +266,11 @@ public interface LinphoneCall { * Obtain the remote user agent string. */ String getRemoteUserAgent(); + + /** + * Obtain the remote sip contact string. + **/ + String getRemoteContact(); /** * Take a photo of currently received video and write it into a jpeg file. diff --git a/java/common/org/linphone/core/LinphoneCoreFactory.java b/java/common/org/linphone/core/LinphoneCoreFactory.java index 100794016..399b9ec8d 100644 --- a/java/common/org/linphone/core/LinphoneCoreFactory.java +++ b/java/common/org/linphone/core/LinphoneCoreFactory.java @@ -67,6 +67,7 @@ abstract public class LinphoneCoreFactory { * @return */ abstract public LinphoneAddress createLinphoneAddress(String address); + abstract public LpConfig createLpConfig(String file); abstract public LinphoneProxyConfig createProxyConfig(String identity, String proxy,String route,boolean enableRegister) throws LinphoneCoreException; /** diff --git a/java/impl/org/linphone/core/LinphoneCallImpl.java b/java/impl/org/linphone/core/LinphoneCallImpl.java index 6a91438ac..45c905dbb 100644 --- a/java/impl/org/linphone/core/LinphoneCallImpl.java +++ b/java/impl/org/linphone/core/LinphoneCallImpl.java @@ -179,6 +179,11 @@ class LinphoneCallImpl implements LinphoneCall { public String getRemoteUserAgent() { return getRemoteUserAgent(nativePtr); } + + private native String getRemoteContact(long nativePtr); + public String getRemoteContact() { + return getRemoteContact(nativePtr); + } private native void takeSnapshot(long nativePtr, String path); public void takeSnapshot(String path) { diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index 04b6af1cf..2e5c4cf59 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -105,6 +105,11 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { public LinphoneAddress createLinphoneAddress(String identity) { return new LinphoneAddressImpl(identity); } + + @Override + public LpConfig createLpConfig(String file) { + return new LpConfigImpl(file); + } @Override public LinphoneCore createLinphoneCore(LinphoneCoreListener listener, diff --git a/java/impl/org/linphone/core/LpConfigImpl.java b/java/impl/org/linphone/core/LpConfigImpl.java index 1cb705ec2..27bd63d13 100644 --- a/java/impl/org/linphone/core/LpConfigImpl.java +++ b/java/impl/org/linphone/core/LpConfigImpl.java @@ -27,6 +27,15 @@ class LpConfigImpl implements LpConfig { public LpConfigImpl(long ptr) { nativePtr=ptr; } + + private native long newLpConfigImpl(String file); + private native void delete(long ptr); + public LpConfigImpl(String file) { + nativePtr = newLpConfigImpl(file); + } + protected void finalize() throws Throwable { + delete(nativePtr); + } private native void setInt(long ptr, String section, String key, int value); public void setInt(String section, String key, int value) { diff --git a/java/impl/org/linphone/tools/Lpc2Xml.java b/java/impl/org/linphone/tools/Lpc2Xml.java new file mode 100644 index 000000000..97ef99637 --- /dev/null +++ b/java/impl/org/linphone/tools/Lpc2Xml.java @@ -0,0 +1,68 @@ +package org.linphone.tools; + +import org.linphone.core.LpConfig; +import org.linphone.mediastream.Log; + +public class Lpc2Xml { + + private enum LogLevel { + DEBUG, + MESSAGE, + WARNING, + ERROR, + } + + private static boolean mAvailable; + + private long internalPtr = 0; + + private native void init(); + private native void destroy(); + + public Lpc2Xml() { + init(); + } + + public void finalize() { + destroy(); + } + + public native int setLpc(LpConfig lpc); + + public native int convertFile(String file); + public native int convertString(StringBuffer content); + + public void printLog(int level, String message) { + if(level > 0 && level < LogLevel.values().length) { + switch(LogLevel.values()[level]) { + case DEBUG: + Log.d(message); + break; + case MESSAGE: + Log.i(message); + break; + case WARNING: + Log.w(message); + break; + case ERROR: + Log.e(message); + break; + } + } + } + + static boolean isAvailable() { + return mAvailable; + } + + // Load library + static { + try { + System.loadLibrary("xml2"); + System.loadLibrary("lpc2xml"); + mAvailable = true; + } catch (Throwable e) { + mAvailable = false; + } + } +} diff --git a/java/impl/org/linphone/tools/Xml2Lpc.java b/java/impl/org/linphone/tools/Xml2Lpc.java new file mode 100644 index 000000000..9f6cb0f27 --- /dev/null +++ b/java/impl/org/linphone/tools/Xml2Lpc.java @@ -0,0 +1,72 @@ +package org.linphone.tools; + +import org.linphone.core.LpConfig; +import org.linphone.mediastream.Log; + +public class Xml2Lpc { + + private enum LogLevel { + DEBUG, + MESSAGE, + WARNING, + ERROR + } + + private static boolean mAvailable; + + private long internalPtr = 0; + + private native void init(); + private native void destroy(); + + public Xml2Lpc() { + init(); + } + + public void finalize() { + destroy(); + } + + public native int setXmlFile(String filename); + public native int setXmlString(String content); + + public native int setXsdFile(String filename); + public native int setXsdString(String content); + + public native int validate(); + public native int convert(LpConfig config); + + public void printLog(int level, String message) { + if(level > 0 && level < LogLevel.values().length) { + switch(LogLevel.values()[level]) { + case DEBUG: + Log.d(message); + break; + case MESSAGE: + Log.i(message); + break; + case WARNING: + Log.w(message); + break; + case ERROR: + Log.e(message); + break; + } + } + } + + public static boolean isAvailable() { + return mAvailable; + } + + // Load library + static { + try { + System.loadLibrary("xml2"); + System.loadLibrary("xml2lpc"); + mAvailable = true; + } catch (Throwable e) { + mAvailable = false; + } + } +} diff --git a/mediastreamer2 b/mediastreamer2 index 3a231efb8..e5d529906 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 3a231efb89305d775ab39a6866ee981a891aed7e +Subproject commit e5d52990695be15802741e920801f77d24bd8fba diff --git a/oRTP b/oRTP index 20abeb39e..b055a5050 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 20abeb39e1edae0f72080f7998410e9b16b9da05 +Subproject commit b055a505042c4420e104ce81a09790c5373f62bb diff --git a/po/POTFILES.in b/po/POTFILES.in index 1af3423bb..4a4497cbd 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -26,6 +26,7 @@ gtk/loginframe.c [type: gettext/glade]gtk/dscp_settings.ui [type: gettext/glade]gtk/call_statistics.ui [type: gettext/glade]gtk/tunnel_config.ui +[type: gettext/glade]gtk/keypad.ui coreapi/linphonecore.c coreapi/misc.c coreapi/presence.c diff --git a/tools/Makefile.am b/tools/Makefile.am index ffb469214..a93d809f1 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -11,6 +11,8 @@ COMMON_CFLAGS=\ $(STRICT_OPTIONS) \ $(LIBXML2_CFLAGS) +EXTRA_DIST=xml2lpc_jni.cc lpc2xml_jni.cc + if BUILD_TOOLS lib_LTLIBRARIES=libxml2lpc.la liblpc2xml.la diff --git a/tools/lpc2xml.c b/tools/lpc2xml.c index feabdde2e..39fd62b0e 100644 --- a/tools/lpc2xml.c +++ b/tools/lpc2xml.c @@ -57,11 +57,11 @@ void lpc2xml_context_destroy(lpc2xml_context *ctx) { } free(ctx); } -/* + static void lpc2xml_context_clear_logs(lpc2xml_context *ctx) { ctx->errorBuffer[0]='\0'; ctx->warningBuffer[0]='\0'; -}*/ +} static void lpc2xml_log(lpc2xml_context *xmlCtx, int level, const char *fmt, ...) { va_list args; @@ -72,12 +72,34 @@ static void lpc2xml_log(lpc2xml_context *xmlCtx, int level, const char *fmt, ... va_end(args); } +static void lpc2xml_genericxml_error(void *ctx, const char *fmt, ...) { + lpc2xml_context *xmlCtx = (lpc2xml_context *)ctx; + int sl = strlen(xmlCtx->errorBuffer); + va_list args; + va_start(args, fmt); + vsnprintf(xmlCtx->errorBuffer + sl, LPC2XML_BZ-sl, fmt, args); + va_end(args); +} + +/* +static void lpc2xml_genericxml_warning(void *ctx, const char *fmt, ...) { + lpc2xml_context *xmlCtx = (lpc2xml_context *)ctx; + int sl = strlen(xmlCtx->warningBuffer); + va_list args; + va_start(args, fmt); + vsnprintf(xmlCtx->warningBuffer + sl, LPC2XML_BZ-sl, fmt, args); + va_end(args); +} +*/ + static int processEntry(const char *section, const char *entry, xmlNode *node, lpc2xml_context *ctx) { const char *content = lp_config_get_string(ctx->lpc, section, entry, NULL); if(content == NULL) { lpc2xml_log(ctx->ctx, LPC2XML_ERROR, "Issue when reading the lpc"); return -1; } + + lpc2xml_log(ctx, LPC2XML_MESSAGE, "Set %s|%s = %s", section, entry, content); xmlNodeSetContent(node, (const xmlChar *) content); return 0; } @@ -103,6 +125,7 @@ static void processSection_cb(const char *entry, struct __processSectionCtx *ctx ctx->ret = -1; return; } + ctx->ret = processEntry(ctx->section, entry, node, ctx->ctx); } } @@ -195,36 +218,69 @@ int lpc2xml_set_lpc(lpc2xml_context* context, const LpConfig *lpc) { } int lpc2xml_convert_file(lpc2xml_context* context, const char *filename) { - int ret = 0; + int ret = -1; + lpc2xml_context_clear_logs(context); + xmlSetGenericErrorFunc(context, lpc2xml_genericxml_error); xmlSaveCtxtPtr save_ctx = xmlSaveToFilename(filename, "UTF-8", XML_SAVE_FORMAT); - ret = internal_convert_lpc2xml(context); - if(ret == 0) { - ret = xmlSaveDoc(save_ctx, context->doc); + if(save_ctx != NULL) { + ret = internal_convert_lpc2xml(context); + if(ret == 0) { + ret = xmlSaveDoc(save_ctx, context->doc); + if(ret != 0) { + lpc2xml_log(context, LPC2XML_ERROR, "Can't save document"); + lpc2xml_log(context, LPC2XML_ERROR, "%s", context->errorBuffer); + } + } + xmlSaveClose(save_ctx); + } else { + lpc2xml_log(context, LPC2XML_ERROR, "Can't open file:%s", filename); + lpc2xml_log(context, LPC2XML_ERROR, "%s", context->errorBuffer); } - xmlSaveClose(save_ctx); return ret; } int lpc2xml_convert_fd(lpc2xml_context* context, int fd) { - int ret = 0; + int ret = -1; + lpc2xml_context_clear_logs(context); + xmlSetGenericErrorFunc(context, lpc2xml_genericxml_error); xmlSaveCtxtPtr save_ctx = xmlSaveToFd(fd, "UTF-8", XML_SAVE_FORMAT); - ret = internal_convert_lpc2xml(context); - if(ret == 0) { - ret = xmlSaveDoc(save_ctx, context->doc); + if(save_ctx != NULL) { + ret = internal_convert_lpc2xml(context); + if(ret == 0) { + ret = xmlSaveDoc(save_ctx, context->doc); + if(ret != 0) { + lpc2xml_log(context, LPC2XML_ERROR, "Can't save document"); + lpc2xml_log(context, LPC2XML_ERROR, "%s", context->errorBuffer); + } + } + xmlSaveClose(save_ctx); + } else { + lpc2xml_log(context, LPC2XML_ERROR, "Can't open fd:%d", fd); + lpc2xml_log(context, LPC2XML_ERROR, "%s", context->errorBuffer); } - xmlSaveClose(save_ctx); return ret; } int lpc2xml_convert_string(lpc2xml_context* context, char **content) { - int ret = 0; + int ret = -1; xmlBufferPtr buffer = xmlBufferCreate(); + lpc2xml_context_clear_logs(context); + xmlSetGenericErrorFunc(context, lpc2xml_genericxml_error); xmlSaveCtxtPtr save_ctx = xmlSaveToBuffer(buffer, "UTF-8", XML_SAVE_FORMAT); - internal_convert_lpc2xml(context); - if(ret == 0) { - ret = xmlSaveDoc(save_ctx, context->doc); + if(save_ctx != NULL) { + ret = internal_convert_lpc2xml(context); + if(ret == 0) { + ret = xmlSaveDoc(save_ctx, context->doc); + if(ret != 0) { + lpc2xml_log(context, LPC2XML_ERROR, "Can't save document"); + lpc2xml_log(context, LPC2XML_ERROR, "%s", context->errorBuffer); + } + } + xmlSaveClose(save_ctx); + } else { + lpc2xml_log(context, LPC2XML_ERROR, "Can't initialize internal buffer"); + lpc2xml_log(context, LPC2XML_ERROR, "%s", context->errorBuffer); } - xmlSaveClose(save_ctx); if(ret == 0) { #if LIBXML_VERSION >= 20800 *content = (char *)xmlBufferDetach(buffer); diff --git a/tools/lpc2xml_jni.cc b/tools/lpc2xml_jni.cc new file mode 100644 index 000000000..c0971cbd5 --- /dev/null +++ b/tools/lpc2xml_jni.cc @@ -0,0 +1,123 @@ +/* +xml2lpc_jni.cc +Copyright (C) 2013 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "my_jni.h" +extern "C" { +#include "lpc2xml.h" +} +#ifdef USE_JAVAH +#include "lpc2xml_jni.h" +#endif + +#include + +struct jni_lpc2xml_ctx { + JNIEnv *env; + jobject obj; + lpc2xml_context *ctx; +}; + +static bool update_and_check_context(jni_lpc2xml_ctx *jni_ctx, JNIEnv *env, jobject obj) { + if(jni_ctx != NULL && jni_ctx->ctx != NULL) { + jni_ctx->env = env; + jni_ctx->obj = obj; + return true; + } + return false; +} + +#define LPC2XML_CALLBACK_BUFFER_SIZE 1024 + +extern "C" void Java_org_linphone_tools_Lpc2Xml_callback (void *ctx, lpc2xml_log_level level, const char *fmt, va_list list) { + jni_lpc2xml_ctx *jni_ctx = (jni_lpc2xml_ctx *)ctx; + if(jni_ctx->ctx != NULL) { + JNIEnv *env = jni_ctx->env; + jobject obj = jni_ctx->obj; + + char buffer[LPC2XML_CALLBACK_BUFFER_SIZE]; + vsnprintf(buffer, LPC2XML_CALLBACK_BUFFER_SIZE, fmt, list); + jstring javaString = env->NewStringUTF(buffer); + jint javaLevel = level; + my_jni::callVoidMethod(env, obj, "Lpc2Xml", "printLog", "(ILjava/lang/String;)V", javaLevel, javaString); + } +} + +extern "C" void Java_org_linphone_tools_Lpc2Xml_init(JNIEnv *env, jobject obj) { + jni_lpc2xml_ctx *jni_ctx = new jni_lpc2xml_ctx(); + jni_ctx->env = env; + jni_ctx->obj = obj; + jni_ctx->ctx = lpc2xml_context_new(Java_org_linphone_tools_Lpc2Xml_callback, obj); + bool result = my_jni::setLongField(env, obj, "Lpc2Xml", "internalPtr", jni_ctx); + if(!result) { + lpc2xml_context_destroy(jni_ctx->ctx); + delete jni_ctx; + } +} + +extern "C" void Java_org_linphone_tools_Lpc2Xml_destroy(JNIEnv *env, jobject obj) { + jni_lpc2xml_ctx *jni_ctx = my_jni::getLongField(env, obj, "Lpc2Xml", "internalPtr"); + if(jni_ctx != NULL) { + jni_ctx->env = env; + jni_ctx->obj = obj; + + if(jni_ctx->ctx != NULL) { + lpc2xml_context_destroy(jni_ctx->ctx); + } + delete jni_ctx; + my_jni::setLongField(env, obj, "Lpc2Xml", "internalPtr", NULL); + } +} + +extern "C" jint Java_org_linphone_tools_Lpc2Xml_setLpc(JNIEnv *env, jobject obj, jobject javaLpc) { + jni_lpc2xml_ctx *jni_ctx = my_jni::getLongField(env, obj, "Lpc2Xml", "internalPtr"); + jint ret = -666; + if(update_and_check_context(jni_ctx, env, obj)) { + LpConfig *lpc = my_jni::getLongField(env, javaLpc, "LpConfigImpl", "nativePtr"); + if(lpc != NULL) { + lpc2xml_set_lpc(jni_ctx->ctx, lpc); + } + } + return ret; +} + +extern "C" jint Java_org_linphone_tools_Lpc2Xml_convertFile(JNIEnv *env, jobject obj, jstring javaFile) { + jni_lpc2xml_ctx *jni_ctx = my_jni::getLongField(env, obj, "Lpc2Xml", "internalPtr"); + jint ret = -666; + if(update_and_check_context(jni_ctx, env, obj)) { + const char *file = env->GetStringUTFChars(javaFile, 0); + ret = lpc2xml_convert_file(jni_ctx->ctx, file); + env->ReleaseStringChars(javaFile, (jchar *)file); + } + return ret; +} + +extern "C" jint Java_org_linphone_tools_Lpc2Xml_convertString(JNIEnv *env, jobject obj, jobject javaStringBuffer) { + jni_lpc2xml_ctx *jni_ctx = my_jni::getLongField(env, obj, "Lpc2Xml", "internalPtr"); + jint ret = -666; + if(update_and_check_context(jni_ctx, env, obj)) { + char *string = NULL; + ret = lpc2xml_convert_string(jni_ctx->ctx, &string); + if(string != NULL) { + jstring javaString = env->NewStringUTF(string); + my_jni::callObjectMethod(env, obj, "StringBuffer", "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;", javaString); + env->ReleaseStringChars(javaString, (jchar *)string); + } + } + return ret; +} diff --git a/tools/my_jni.h b/tools/my_jni.h new file mode 100644 index 000000000..ce56829ec --- /dev/null +++ b/tools/my_jni.h @@ -0,0 +1,108 @@ +/* +my_jni.cc +Copyright (C) 2013 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __MY_JNI__H +#define __MY_JNI__H +#include +extern "C" { +#include "linphonecore_utils.h" +} + +#define defCallMethod(Type) \ +template \ +static ReturnType call##Type##Method(JNIEnv *env, jobject obj, const char *className, const char *methodName, \ + const char *methodSignature, ...) { \ + jclass my_class = env->GetObjectClass(obj); \ + if(my_class == 0) { \ + ms_error("Can't get %s JNI class", className); \ + return NULL; \ + } \ + jmethodID my_method = env->GetMethodID(my_class, methodName, methodSignature); \ + if(my_method == 0) { \ + ms_error("Can't get %s %s %s method", className, methodSignature); \ + return NULL; \ + } \ + va_list vl; \ + va_start(vl, methodSignature); \ + ReturnType ret = env->Call##Type##MethodV(obj, my_method, vl); \ + va_end(vl); \ + return ret; \ +} \ + +#define defGetterTypeField(Type, JavaType, JavaStringType) \ +template \ +static ValueType get##Type##Field(JNIEnv *env, jobject obj, const char *className, const char *fieldName) { \ + jclass my_class = env->GetObjectClass(obj); \ + if(my_class == 0) { \ + ms_error("Can't get %s JNI class", className); \ + return NULL; \ + } \ + jfieldID my_field = env->GetFieldID(my_class, fieldName, JavaStringType); \ + if(my_field == 0) { \ + ms_error("Can't get %s %s field", className, fieldName); \ + return NULL; \ + } \ + return (ValueType) env->Get##Type##Field(obj, my_field); \ +} \ + +#define defSetterTypeField(Type, JavaType, JavaStringType) \ +template \ +static bool set##Type##Field(JNIEnv *env, jobject obj, const char *className, const char *fieldName, ValueType val) { \ + jclass my_class = env->GetObjectClass(obj); \ + if(my_class == 0) { \ + ms_error("Can't get %s JNI class", className); \ + return false; \ + } \ + jfieldID my_field = env->GetFieldID(my_class, fieldName, JavaStringType); \ + if(my_field == 0) { \ + ms_error("Can't get %s %s field", className, fieldName); \ + return false; \ + } \ + env->Set##Type##Field(obj, my_field, (JavaType) val); \ + return true; \ +} \ + +#define defGetterAndSetterTypeField(Type, JavaType, JavaStringType) \ + defGetterTypeField(Type, JavaType, JavaStringType) \ + defSetterTypeField(Type, JavaType, JavaStringType) \ + +namespace my_jni { + template + static void callVoidMethod(JNIEnv *env, jobject obj, const char *className, const char *methodName, + const char *methodSignature, ...) { + jclass my_class = env->GetObjectClass(obj); + if(my_class == 0) { + ms_error("Can't get %s JNI class", className); + return; + } + jmethodID my_method = env->GetMethodID(my_class, methodName, methodSignature); + if(my_method == 0) { + ms_error("Can't get %s %s %s method", className, methodName, methodSignature); + return; + } + va_list vl; + va_start(vl, methodSignature); + env->CallVoidMethodV(obj, my_method, vl); + va_end(vl); + } + defCallMethod(Object) + defGetterAndSetterTypeField(Long, jlong, "J") +} + +#endif //__MY_JNI__H diff --git a/tools/xml2lpc.c b/tools/xml2lpc.c index 9d720f1f3..c9a5c94e2 100644 --- a/tools/xml2lpc.c +++ b/tools/xml2lpc.c @@ -148,7 +148,7 @@ static int processEntry(xmlElement *element, const char *sectionName, xml2lpc_co 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); + 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); @@ -231,8 +231,10 @@ int xml2lpc_validate(xml2lpc_context *xmlCtx) { 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); + if(strlen(xmlCtx->warningBuffer) > 0) + xml2lpc_log(xmlCtx, XML2LPC_WARNING, "%s", xmlCtx->warningBuffer); + if(strlen(xmlCtx->errorBuffer) > 0) + xml2lpc_log(xmlCtx, XML2LPC_ERROR, "%s", xmlCtx->errorBuffer); } else if(ret < 0) { xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Internal error"); } @@ -242,6 +244,13 @@ int xml2lpc_validate(xml2lpc_context *xmlCtx) { int xml2lpc_convert(xml2lpc_context *xmlCtx, LpConfig *lpc) { xml2lpc_context_clear_logs(xmlCtx); + if(xmlCtx->doc == NULL) { + xml2lpc_log(xmlCtx, XML2LPC_ERROR, "No doc set"); + return -1; + } + if(lpc == NULL) { + xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Invalid lpc"); + } xmlCtx->lpc = lpc; return internal_convert_xml2lpc(xmlCtx); } diff --git a/tools/xml2lpc_jni.cc b/tools/xml2lpc_jni.cc new file mode 100644 index 000000000..fd72c6895 --- /dev/null +++ b/tools/xml2lpc_jni.cc @@ -0,0 +1,149 @@ +/* +xml2lpc_jni.cc +Copyright (C) 2013 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "my_jni.h" +extern "C" { +#include "xml2lpc.h" +} +#ifdef USE_JAVAH +#include "xml2lpc_jni.h" +#endif + +#include + +struct jni_xml2lpc_ctx { + JNIEnv *env; + jobject obj; + xml2lpc_context *ctx; +}; + +static bool update_and_check_context(jni_xml2lpc_ctx *jni_ctx, JNIEnv *env, jobject obj) { + if(jni_ctx != NULL && jni_ctx->ctx != NULL) { + jni_ctx->env = env; + jni_ctx->obj = obj; + return true; + } + return false; +} + +#define XML2LPC_CALLBACK_BUFFER_SIZE 1024 + +extern "C" void Java_org_linphone_tools_Xml2Lpc_callback (void *ctx, xml2lpc_log_level level, const char *fmt, va_list list) { + jni_xml2lpc_ctx *jni_ctx = (jni_xml2lpc_ctx *)ctx; + if(jni_ctx->ctx != NULL) { + JNIEnv *env = jni_ctx->env; + jobject obj = jni_ctx->obj; + + char buffer[XML2LPC_CALLBACK_BUFFER_SIZE]; + vsnprintf(buffer, XML2LPC_CALLBACK_BUFFER_SIZE, fmt, list); + jstring javaString = env->NewStringUTF(buffer); + jint javaLevel = level; + my_jni::callVoidMethod(env, obj, "Xml2Lpc", "printLog", "(ILjava/lang/String;)V", javaLevel, javaString); + } +} + +extern "C" void Java_org_linphone_tools_Xml2Lpc_init(JNIEnv *env, jobject obj) { + jni_xml2lpc_ctx *jni_ctx = new jni_xml2lpc_ctx(); + jni_ctx->env = env; + jni_ctx->obj = obj; + jni_ctx->ctx = xml2lpc_context_new(Java_org_linphone_tools_Xml2Lpc_callback, jni_ctx); + bool result = my_jni::setLongField(env, obj, "Xml2Lpc", "internalPtr", jni_ctx); + if(!result) { + xml2lpc_context_destroy(jni_ctx->ctx); + delete jni_ctx; + } +} + +extern "C" void Java_org_linphone_tools_Xml2Lpc_destroy(JNIEnv *env, jobject obj) { + jni_xml2lpc_ctx *jni_ctx = my_jni::getLongField(env, obj, "Xml2Lpc", "internalPtr"); + if(jni_ctx != NULL) { + jni_ctx->env = env; + jni_ctx->obj = obj; + if(jni_ctx->ctx) { + xml2lpc_context_destroy(jni_ctx->ctx); + } + delete jni_ctx; + my_jni::setLongField(env, obj, "Xml2Lpc", "internalPtr", NULL); + } +} + +extern "C" jint Java_org_linphone_tools_Xml2Lpc_setXmlFile(JNIEnv *env, jobject obj, jstring javaXmlFile) { + jni_xml2lpc_ctx *jni_ctx = my_jni::getLongField(env, obj, "Xml2Lpc", "internalPtr"); + jint ret = -666; + if(update_and_check_context(jni_ctx, env, obj)) { + const char *xmlFile = env->GetStringUTFChars(javaXmlFile, 0); + ret = xml2lpc_set_xml_file(jni_ctx->ctx, xmlFile); + env->ReleaseStringChars(javaXmlFile, (jchar *)xmlFile); + } + return ret; +} + +extern "C" jint Java_org_linphone_tools_Xml2Lpc_setXmlString(JNIEnv *env, jobject obj, jstring javaXmlString) { + jni_xml2lpc_ctx *jni_ctx = my_jni::getLongField(env, obj, "Xml2Lpc", "internalPtr"); + jint ret = -666; + if(update_and_check_context(jni_ctx, env, obj)) { + const char *xmlString = env->GetStringUTFChars(javaXmlString, 0); + ret = xml2lpc_set_xml_string(jni_ctx->ctx, xmlString); + env->ReleaseStringChars(javaXmlString, (jchar *)xmlString); + } + return ret; +} + +extern "C" jint Java_org_linphone_tools_Xml2Lpc_setXsdFile(JNIEnv *env, jobject obj, jstring javaXsdFile) { + jni_xml2lpc_ctx *jni_ctx = my_jni::getLongField(env, obj, "Xml2Lpc", "internalPtr"); + jint ret = -666; + if(update_and_check_context(jni_ctx, env, obj)) { + const char *xsdFile = env->GetStringUTFChars(javaXsdFile, 0); + ret = xml2lpc_set_xsd_file(jni_ctx->ctx, xsdFile); + env->ReleaseStringChars(javaXsdFile, (jchar *)xsdFile); + } + return ret; +} + +extern "C" jint Java_org_linphone_tools_Xml2Lpc_setXsdString(JNIEnv *env, jobject obj, jstring javaXsdString) { + jni_xml2lpc_ctx *jni_ctx = my_jni::getLongField(env, obj, "Xml2Lpc", "internalPtr"); + jint ret = -666; + if(update_and_check_context(jni_ctx, env, obj)) { + const char *xsdString = env->GetStringUTFChars(javaXsdString, 0); + ret = xml2lpc_set_xsd_string(jni_ctx->ctx, xsdString); + env->ReleaseStringChars(javaXsdString, (jchar *)xsdString); + } + return ret; +} + +extern "C" jint Java_org_linphone_tools_Xml2Lpc_validate(JNIEnv *env, jobject obj) { + jni_xml2lpc_ctx *jni_ctx = my_jni::getLongField(env, obj, "Xml2Lpc", "internalPtr"); + jint ret = -666; + if(update_and_check_context(jni_ctx, env, obj)) { + ret = xml2lpc_validate(jni_ctx->ctx); + } + return ret; +} + +extern "C" jint Java_org_linphone_tools_Xml2Lpc_convert(JNIEnv *env, jobject obj, jobject javaLpc) { + jni_xml2lpc_ctx *jni_ctx = my_jni::getLongField(env, obj, "Xml2Lpc", "internalPtr"); + jint ret = -666; + if(update_and_check_context(jni_ctx, env, obj)) { + LpConfig *lpc = my_jni::getLongField(env, javaLpc, "LpConfigImpl", "nativePtr"); + if(lpc != NULL) { + ret = xml2lpc_convert(jni_ctx->ctx, lpc); + } + } + return ret; +}