From deccbd69636e4181e22cb5288ff494169494064e Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Wed, 19 Dec 2012 15:41:23 +0100 Subject: [PATCH 01/47] Start including upnp --- configure.ac | 26 +++++++++++++++++++++++ coreapi/Makefile.am | 4 ++++ coreapi/private.h | 13 ++++++++++-- coreapi/upnp.c | 51 +++++++++++++++++++++++++++++++++++++++++++++ mediastreamer2 | 2 +- 5 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 coreapi/upnp.c diff --git a/configure.ac b/configure.ac index 1005ab2f5..659a872b4 100644 --- a/configure.ac +++ b/configure.ac @@ -149,6 +149,32 @@ AC_ARG_ENABLE(tools, *) 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],[], diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 790612cab..6d55a731f 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -49,6 +49,10 @@ liblinphone_la_SOURCES=\ conference.c \ linphone_tunnel.cc \ $(GITVERSION_FILE) + +if BUILD_UPNP +liblinphone_la_SOURCES+=upnp.c +endif if BUILD_WIZARD liblinphone_la_SOURCES+=sipwizard.c diff --git a/coreapi/private.h b/coreapi/private.h index 925a30360..f69eb2ff0 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -38,6 +38,9 @@ extern "C" { #include "mediastreamer2/ice.h" #include "mediastreamer2/mediastream.h" #include "mediastreamer2/msconference.h" +#ifdef BUILD_UPNP +#include "mediastreamer2/upnp_igd.h" +#endif #ifndef LIBLINPHONE_VERSION #define LIBLINPHONE_VERSION LINPHONE_VERSION @@ -558,8 +561,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]; @@ -568,6 +571,9 @@ struct _LinphoneCore LinphoneTunnel *tunnel; char* device_id; MSList *last_recv_msg_ids; +#ifdef BUILD_UPNP + upnp_igd_context *upnp_igd_ctxt; +#endif }; LinphoneTunnel *linphone_core_tunnel_new(LinphoneCore *lc); @@ -642,6 +648,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/upnp.c b/coreapi/upnp.c new file mode 100644 index 000000000..31fb5c5f1 --- /dev/null +++ b/coreapi/upnp.c @@ -0,0 +1,51 @@ +/* +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 "private.h" +#include "mediastreamer2/upnp_igd.h" + +/* 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_WARNING; + break; + case UPNP_IGD_ERROR: + ortp_level = ORTP_ERROR; + break; + default: + break; + } + ortp_logv(level, fmt, list); +} + +void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { +} + +int linphone_upnp_init(LinphoneCore *lc) { + lc->upnp_igd_ctxt = NULL; + return 0; +} +void linphone_upnp_destroy(LinphoneCore *lc) { + +} diff --git a/mediastreamer2 b/mediastreamer2 index 9c3f1bdf1..2093868ac 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 9c3f1bdf1f7b51c5eeb020f68ef9a4019c66cc52 +Subproject commit 2093868ac68ffe62310cd0ad20b58ffa6860d7e3 From 8ef5af3e1bf7b2f8484d9e89e77974348b2a3183 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Thu, 20 Dec 2012 17:09:44 +0100 Subject: [PATCH 02/47] Fix static build in gtk --- gtk/Makefile.am | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/gtk/Makefile.am b/gtk/Makefile.am index d31a05bfe..111be5cb8 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -54,10 +54,11 @@ linphone_SOURCES+= \ setupwizard.c endif -linphone_LDADD=$(ORTP_LIBS) \ - $(MEDIASTREAMER_LIBS) \ +linphone_LDADD=\ $(top_builddir)/coreapi/liblinphone.la \ - $(LIBGTK_LIBS) $(NOTIFY1_LIBS) $(NOTIFY4_LIBS) $(LIBGTKMAC_LIBS) $(INTLLIBS) + $(ORTP_LIBS) \ + $(MEDIASTREAMER_LIBS) \ + $(LIBGTK_LIBS) $(NOTIFY1_LIBS) $(NOTIFY4_LIBS) $(LIBGTKMAC_LIBS) $(INTLLIBS) if BUILD_WIN32 From 9898c4beec0ce507becb1493b02ad2965f20a116 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Thu, 20 Dec 2012 17:34:36 +0100 Subject: [PATCH 03/47] Fix static build split tunnel stubs --- coreapi/Makefile.am | 5 +- coreapi/linphone_tunnel.cc | 61 ------------------------- coreapi/linphone_tunnel_stubs.c | 81 +++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 63 deletions(-) create mode 100644 coreapi/linphone_tunnel_stubs.c diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 6d55a731f..822c0b836 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -47,7 +47,6 @@ liblinphone_la_SOURCES=\ lsd.c linphonecore_utils.h \ ec-calibrator.c \ conference.c \ - linphone_tunnel.cc \ $(GITVERSION_FILE) if BUILD_UPNP @@ -59,7 +58,9 @@ liblinphone_la_SOURCES+=sipwizard.c endif 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/linphone_tunnel.cc b/coreapi/linphone_tunnel.cc index f5a5d361f..18fabbbe9 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" @@ -36,8 +34,6 @@ LinphoneTunnel* linphone_core_get_tunnel(LinphoneCore *lc){ return lc->tunnel; } -#ifdef TUNNEL_ENABLED - static inline belledonnecomm::TunnelManager *bcTunnel(LinphoneTunnel *tunnel){ return (belledonnecomm::TunnelManager *)tunnel; } @@ -212,60 +208,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, const char *host, int port){ -} - -void linphone_tunnel_add_server_and_mirror(LinphoneTunnel *tunnel, const char *host, int port, int remote_udp_mirror, int delay){ -} - -char *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_stubs.c b/coreapi/linphone_tunnel_stubs.c new file mode 100644 index 000000000..d7fb27796 --- /dev/null +++ b/coreapi/linphone_tunnel_stubs.c @@ -0,0 +1,81 @@ +/*************************************************************************** + * 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, const char *host, int port){ +} + +void linphone_tunnel_add_server_and_mirror(LinphoneTunnel *tunnel, const char *host, int port, int remote_udp_mirror, int delay){ +} + +char *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){ +} + From 8026b597a768480a062b0cb43dcee6db84f8c939 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Fri, 21 Dec 2012 10:11:06 +0100 Subject: [PATCH 04/47] Starting uPNP integration --- coreapi/Makefile.am | 2 +- coreapi/linphonecall.c | 5 +++++ coreapi/linphonecore.c | 6 ++++++ coreapi/linphonecore.h | 3 ++- coreapi/private.h | 13 +++++++++---- coreapi/upnp.c | 35 ++++++++++++++++++++++++++++++----- coreapi/upnp.h | 38 ++++++++++++++++++++++++++++++++++++++ mediastreamer2 | 2 +- 8 files changed, 92 insertions(+), 12 deletions(-) create mode 100644 coreapi/upnp.h diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 822c0b836..c5abd0360 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -50,7 +50,7 @@ liblinphone_la_SOURCES=\ $(GITVERSION_FILE) if BUILD_UPNP -liblinphone_la_SOURCES+=upnp.c +liblinphone_la_SOURCES+=upnp.c upnp.h endif if BUILD_WIZARD diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 5a18a0525..6c8b4a743 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -449,6 +449,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 = upnp_session_new(); + } +#endif //BUILD_UPNP call->camera_active=params->has_video; discover_mtu(lc,linphone_address_get_domain (to)); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index e52fff00e..8619552fa 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1217,6 +1217,9 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta #ifdef TUNNEL_ENABLED lc->tunnel=linphone_core_tunnel_new(lc); if (lc->tunnel) linphone_tunnel_configure(lc->tunnel); +#endif +#ifdef BUILD_UPNP + upnp_context_init(lc); #endif if (lc->vtable.display_status) lc->vtable.display_status(lc,_("Ready")); @@ -4901,6 +4904,9 @@ static void linphone_core_uninit(LinphoneCore *lc) #ifdef TUNNEL_ENABLED if (lc->tunnel) linphone_tunnel_destroy(lc->tunnel); #endif +#ifdef BUILD_UPNP + upnp_context_uninit(lc); +#endif } static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime){ diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index f1a9174c8..b4c25380a 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -885,7 +885,8 @@ typedef enum _LinphoneFirewallPolicy{ LinphonePolicyNoFirewall, LinphonePolicyUseNatAddress, LinphonePolicyUseStun, - LinphonePolicyUseIce + LinphonePolicyUseIce, + LinphonePolicyUseUpnp, } LinphoneFirewallPolicy; typedef enum _LinphoneWaitingState{ diff --git a/coreapi/private.h b/coreapi/private.h index f69eb2ff0..6af7e09ee 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" @@ -39,7 +41,7 @@ extern "C" { #include "mediastreamer2/mediastream.h" #include "mediastreamer2/msconference.h" #ifdef BUILD_UPNP -#include "mediastreamer2/upnp_igd.h" +#include "upnp.h" #endif #ifndef LIBLINPHONE_VERSION @@ -148,6 +150,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; @@ -572,15 +577,15 @@ struct _LinphoneCore char* device_id; MSList *last_recv_msg_ids; #ifdef BUILD_UPNP - upnp_igd_context *upnp_igd_ctxt; -#endif + 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); diff --git a/coreapi/upnp.c b/coreapi/upnp.c index 31fb5c5f1..34622bf51 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -17,8 +17,8 @@ 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 "mediastreamer2/upnp_igd.h" /* 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) { @@ -36,16 +36,41 @@ void linphone_upnp_igd_print(void *cookie, upnp_igd_print_level level, const cha default: break; } - ortp_logv(level, fmt, list); + ortp_logv(ortp_level, fmt, list); } void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { + LinphoneCore *lc = (LinphoneCore *)cookie; + UpnpContext *lupnp = &lc->upnp; + switch(event) { + case UPNP_IGD_EXTERNAL_IPADDRESS_CHANGED: + case UPNP_IGD_NAT_ENABLED_CHANGED: + case UPNP_IGD_CONNECTION_STATUS_CHANGED: + break; + + default: + break; + } } -int linphone_upnp_init(LinphoneCore *lc) { - lc->upnp_igd_ctxt = NULL; +int upnp_context_init(LinphoneCore *lc) { + UpnpContext *lupnp = &lc->upnp; + lupnp->upnp_igd_ctxt = NULL; + lupnp->upnp_igd_ctxt = upnp_igd_create(linphone_upnp_igd_callback, linphone_upnp_igd_print, lc); + if(lupnp->upnp_igd_ctxt == NULL) { + ms_error("Can't create uPnP IGD context"); + return -1; + } return 0; } -void linphone_upnp_destroy(LinphoneCore *lc) { +void upnp_context_uninit(LinphoneCore *lc) { + UpnpContext *lupnp = &lc->upnp; + if(lupnp->upnp_igd_ctxt != NULL) { + upnp_igd_destroy(lupnp->upnp_igd_ctxt); + } +} + +UpnpSession* upnp_session_new() { + return NULL; } diff --git a/coreapi/upnp.h b/coreapi/upnp.h new file mode 100644 index 000000000..c5ff5eca0 --- /dev/null +++ b/coreapi/upnp.h @@ -0,0 +1,38 @@ +/* +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" + +typedef struct _UpnpSession { + +} UpnpSession; + +typedef struct _UpnpContext { + upnp_igd_context *upnp_igd_ctxt; +} UpnpContext; + +UpnpSession* upnp_session_new(); +int upnp_context_init(LinphoneCore *lc); +void upnp_context_uninit(LinphoneCore *lc); + +#endif //LINPHONE_UPNP_H diff --git a/mediastreamer2 b/mediastreamer2 index 2093868ac..a1f113529 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 2093868ac68ffe62310cd0ad20b58ffa6860d7e3 +Subproject commit a1f113529f506aa178765cf70773db80e5768139 From 806203ca0a5ba0cf0df7f31b2f8ee51544bcd0fa Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Fri, 21 Dec 2012 16:21:41 +0100 Subject: [PATCH 05/47] uPnP in progress --- console/commands.c | 5 +- coreapi/linphonecall.c | 32 ++++- coreapi/linphonecore.c | 67 +++++++++-- coreapi/private.h | 1 + coreapi/upnp.c | 268 ++++++++++++++++++++++++++++++++++++++++- coreapi/upnp.h | 38 +++++- gtk/parameters.ui | 17 +++ gtk/propertybox.c | 8 ++ mediastreamer2 | 2 +- 9 files changed, 419 insertions(+), 19 deletions(-) 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/linphonecall.c b/coreapi/linphonecall.c index 6c8b4a743..8af948df5 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -451,7 +451,7 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr } #ifdef BUILD_UPNP if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) { - call->upnp_session = upnp_session_new(); + call->upnp_session = upnp_session_new(call); } #endif //BUILD_UPNP call->camera_active=params->has_video; @@ -515,6 +515,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 = upnp_session_new(call); + if (call->ice_session != NULL) { + linphone_call_init_media_streams(call); + if (linphone_core_update_upnp(call->core,call)<0) { + /* uPnP port mappings failed, proceed with the call anyway. */ + linphone_call_delete_upnp_session(call); + } + } +#endif //BUILD_UPNP + break; default: break; } @@ -663,6 +676,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); @@ -1674,6 +1690,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) { + 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); @@ -1984,6 +2009,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 + 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 8619552fa..82e39685f 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2005,6 +2005,10 @@ void linphone_core_iterate(LinphoneCore *lc){ linphone_call_delete_ice_session(call); linphone_call_stop_media_streams_for_ice_gathering(call); } + if (call->upnp_session != NULL) { + ms_warning("uPnP mapping has not finished yet, proceeded with the call withoutt uPnP anyway."); + linphone_call_delete_upnp_session(call); + } linphone_core_start_invite(lc,call); } if (call->state==LinphoneCallIncomingReceived){ @@ -2419,7 +2423,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const LinphoneAddress *parsed_url2=NULL; char *real_url=NULL; LinphoneCall *call; - bool_t use_ice = FALSE; + bool_t defer = FALSE; linphone_core_preempt_sound_resources(lc); @@ -2472,9 +2476,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 + } if (call->dest_proxy==NULL && lc->sip_conf.ping_with_options==TRUE){ /*defer the start of the call after the OPTIONS ping*/ @@ -2484,7 +2500,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); @@ -2657,22 +2673,41 @@ 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->ice_check_list); - call->videostream->ice_check_list = NULL; + if(call->videostream != NULL && !params->has_video) { + if ((call->ice_session != NULL)) { + ice_session_remove_check_list(call->ice_session, call->videostream->ice_check_list); + call->videostream->ice_check_list = NULL; + } } 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"); + 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_gather_ice_candidates(lc,call)<0) { - /* Ice candidates gathering failed, proceed with the call anyway. */ - linphone_call_delete_ice_session(call); - } else return err; + 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); }else{ @@ -2789,6 +2824,12 @@ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const } #endif } + +#if BUILD_UPNP + if(call->upnp_session != NULL) { + } +#endif //BUILD_UPNP + linphone_core_start_accept_call_update(lc, call); return 0; } diff --git a/coreapi/private.h b/coreapi/private.h index 6af7e09ee..d4abf16ca 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -292,6 +292,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); const char * linphone_core_get_identity(LinphoneCore *lc); diff --git a/coreapi/upnp.c b/coreapi/upnp.c index 34622bf51..d0b71b3e4 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -20,6 +20,15 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "upnp.h" #include "private.h" +#define UPNP_MAX_RETRY 4 + +UpnpPortBinding *upnp_port_binding_new(); +UpnpPortBinding * upnp_port_binding_retain(UpnpPortBinding *port); +void upnp_port_binding_release(UpnpPortBinding *port); + +int upnp_context_send_remove_port_binding(LinphoneCore *lc, UpnpPortBinding *port); +int upnp_context_send_add_port_binding(LinphoneCore *lc, UpnpPortBinding *port); + /* 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; @@ -42,35 +51,292 @@ void linphone_upnp_igd_print(void *cookie, upnp_igd_print_level level, const cha void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { LinphoneCore *lc = (LinphoneCore *)cookie; UpnpContext *lupnp = &lc->upnp; + 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; + + ms_mutex_lock(&lupnp->mutex); + 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) { + lupnp->state = UPNP_Pending; + } else if(strcasecmp(connection_status, "Connected") || !nat_enabled) { + lupnp->state = UPNP_Ko; + } else { + // Emit add port binding + // Emit remove old port binding + lupnp->state = UPNP_Ok; + } + + break; + + case UPNP_IGD_PORT_MAPPING_ADD_SUCCESS: + mapping = (upnp_igd_port_mapping *) arg; + port_mapping = (UpnpPortBinding*) mapping->cookie; + port_mapping->remote_port = mapping->remote_port; + port_mapping->state = UPNP_Ok; + // TODO: SAVE IN CONFIG THE PORT + upnp_port_binding_release(port_mapping); + break; + + case UPNP_IGD_PORT_MAPPING_ADD_FAILURE: + mapping = (upnp_igd_port_mapping *) arg; + port_mapping = (UpnpPortBinding*) mapping->cookie; + upnp_context_send_add_port_binding(lc, port_mapping); + upnp_port_binding_release(port_mapping); + break; + + case UPNP_IGD_PORT_MAPPING_REMOVE_SUCCESS: + mapping = (upnp_igd_port_mapping *) arg; + port_mapping = (UpnpPortBinding*) mapping->cookie; + port_mapping->remote_port = -1; + port_mapping->state = UPNP_Idle; + // TODO: REMOVE FROM CONFIG THE PORT + upnp_port_binding_release(port_mapping); + break; + + case UPNP_IGD_PORT_MAPPING_REMOVE_FAILURE: + mapping = (upnp_igd_port_mapping *) arg; + port_mapping = (UpnpPortBinding*) mapping->cookie; + upnp_context_send_remove_port_binding(lc, port_mapping); + // TODO: REMOVE FROM CONFIG THE PORT (DON'T TRY ANYMORE) + upnp_port_binding_release(port_mapping); break; default: break; } + + ms_mutex_unlock(&lupnp->mutex); +} + +int upnp_context_send_add_port_binding(LinphoneCore *lc, UpnpPortBinding *port) { + UpnpContext *lupnp = &lc->upnp; + upnp_igd_port_mapping mapping; + char * local_host = NULL; + int ret; + if(port->state == UPNP_Idle) { + port->remote_port = -1; + port->retry = 0; + port->state = UPNP_Pending; + } + if(port->retry >= UPNP_MAX_RETRY) { + ret = -1; + } else { + local_host = upnp_igd_get_local_ipaddress(lupnp->upnp_igd_ctxt); + mapping.cookie = upnp_port_binding_retain(port); + mapping.local_port = port->local_port; + mapping.local_host = local_host; + mapping.remote_port = rand()%1024 + 1024; + mapping.remote_host = ""; + mapping.description = PACKAGE_NAME; + mapping.protocol = port->protocol; + + port->retry++; + ret = upnp_igd_add_port_mapping(lupnp->upnp_igd_ctxt, &mapping); + if(local_host != NULL) { + free(local_host); + } + } + if(ret != 0) { + port->state = UPNP_Ko; + } + return ret; +} + +int upnp_context_send_remove_port_binding(LinphoneCore *lc, UpnpPortBinding *port) { + UpnpContext *lupnp = &lc->upnp; + upnp_igd_port_mapping mapping; + int ret; + if(port->state == UPNP_Idle) { + port->retry = 0; + port->state = UPNP_Pending; + } + if(port->retry >= UPNP_MAX_RETRY) { + ret = -1; + } else { + mapping.cookie = upnp_port_binding_retain(port); + mapping.remote_port = port->remote_port; + mapping.remote_host = ""; + mapping.protocol = port->protocol; + port->retry++; + ret = upnp_igd_delete_port_mapping(lupnp->upnp_igd_ctxt, &mapping); + } + if(ret != 0) { + port->state = UPNP_Ko; + } + return ret; +} + +int upnp_call_process(LinphoneCall *call) { + LinphoneCore *lc = call->core; + UpnpContext *lupnp = &lc->upnp; + int ret = -1; + + ms_mutex_lock(&lupnp->mutex); + // Don't handle when the call + if(lupnp->state != UPNP_Ko && call->upnp_session != NULL) { + ret = 0; + + /* + * Audio part + */ + call->upnp_session->audio_rtp->local_port = call->audio_port; + call->upnp_session->audio_rtcp->local_port = call->audio_port+1; + if(call->upnp_session->audio_rtp->state == UPNP_Idle && call->audiostream != NULL) { + // Add audio port binding + upnp_context_send_add_port_binding(lc, call->upnp_session->audio_rtp); + } else if(call->upnp_session->audio_rtp->state == UPNP_Ok && call->audiostream == NULL) { + // Remove audio port binding + upnp_context_send_remove_port_binding(lc, call->upnp_session->audio_rtp); + } + if(call->upnp_session->audio_rtcp->state == UPNP_Idle && call->audiostream != NULL) { + // Add audio port binding + upnp_context_send_add_port_binding(lc, call->upnp_session->audio_rtcp); + } else if(call->upnp_session->audio_rtcp->state == UPNP_Ok && call->audiostream == NULL) { + // Remove audio port binding + upnp_context_send_remove_port_binding(lc, call->upnp_session->audio_rtcp); + } + + /* + * Video part + */ + call->upnp_session->video_rtp->local_port = call->video_port; + call->upnp_session->video_rtcp->local_port = call->video_port+1; + if(call->upnp_session->video_rtp->state == UPNP_Idle && call->videostream != NULL) { + // Add video port binding + upnp_context_send_add_port_binding(lc, call->upnp_session->video_rtp); + } else if(call->upnp_session->video_rtp->state == UPNP_Ok && call->videostream == NULL) { + // Remove video port binding + upnp_context_send_remove_port_binding(lc, call->upnp_session->video_rtp); + } + if(call->upnp_session->video_rtcp->state == UPNP_Idle && call->videostream != NULL) { + // Add video port binding + upnp_context_send_add_port_binding(lc, call->upnp_session->video_rtcp); + } else if(call->upnp_session->video_rtcp->state == UPNP_Ok && call->videostream == NULL) { + // Remove video port binding + upnp_context_send_remove_port_binding(lc, call->upnp_session->video_rtcp); + } + } + ms_mutex_unlock(&lupnp->mutex); + return ret; +} + +int linphone_core_update_upnp(LinphoneCore *lc, LinphoneCall *call) { + return upnp_call_process(call); } int upnp_context_init(LinphoneCore *lc) { + LCSipTransports transport; UpnpContext *lupnp = &lc->upnp; + ms_mutex_init(&lupnp->mutex, NULL); + lupnp->state = UPNP_Idle; + + linphone_core_get_sip_transports(lc, &transport); + if(transport.udp_port != 0) { + lupnp->sip_udp = upnp_port_binding_new(); + lupnp->sip_udp->protocol = UPNP_IGD_IP_PROTOCOL_UDP; + } else { + lupnp->sip_udp = NULL; + } + if(transport.tcp_port != 0) { + lupnp->sip_tcp = upnp_port_binding_new(); + lupnp->sip_tcp->protocol = UPNP_IGD_IP_PROTOCOL_TCP; + } else { + lupnp->sip_tcp = NULL; + } + if(transport.tls_port != 0) { + lupnp->sip_tls = upnp_port_binding_new(); + lupnp->sip_tls->protocol = UPNP_IGD_IP_PROTOCOL_TCP; + } else { + lupnp->sip_tls = NULL; + } lupnp->upnp_igd_ctxt = NULL; lupnp->upnp_igd_ctxt = upnp_igd_create(linphone_upnp_igd_callback, linphone_upnp_igd_print, lc); - if(lupnp->upnp_igd_ctxt == NULL) { + if(lupnp->upnp_igd_ctxt == NULL ) { + lupnp->state = UPNP_Ko; ms_error("Can't create uPnP IGD context"); return -1; } + lupnp->state = UPNP_Pending; return 0; } void upnp_context_uninit(LinphoneCore *lc) { + // Emit remove port (sip & saved) UpnpContext *lupnp = &lc->upnp; + if(lupnp->sip_udp != NULL) { + upnp_port_binding_release(lupnp->sip_udp); + } + if(lupnp->sip_tcp != NULL) { + upnp_port_binding_release(lupnp->sip_tcp); + } + if(lupnp->sip_tls != NULL) { + upnp_port_binding_release(lupnp->sip_tls); + } if(lupnp->upnp_igd_ctxt != NULL) { upnp_igd_destroy(lupnp->upnp_igd_ctxt); } + ms_mutex_destroy(&lupnp->mutex); +} + +UpnpPortBinding *upnp_port_binding_new() { + UpnpPortBinding *port = NULL; + port = ms_new0(UpnpPortBinding,1); + ms_mutex_init(&port->mutex, NULL); + port->state = UPNP_Idle; + port->local_port = -1; + port->remote_port = -1; + port->ref = 1; + return port; +} + +UpnpPortBinding *upnp_port_binding_retain(UpnpPortBinding *port) { + ms_mutex_lock(&port->mutex); + port->ref++; + ms_mutex_unlock(&port->mutex); + return port; +} + +void 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); } UpnpSession* upnp_session_new() { + UpnpSession *session = ms_new0(UpnpSession,1); + session->state = UPNP_Idle; + session->audio_rtp = upnp_port_binding_new(); + session->audio_rtp->protocol = UPNP_IGD_IP_PROTOCOL_UDP; + session->audio_rtcp = upnp_port_binding_new(); + session->audio_rtcp->protocol = UPNP_IGD_IP_PROTOCOL_UDP; + session->video_rtp = upnp_port_binding_new(); + session->video_rtp->protocol = UPNP_IGD_IP_PROTOCOL_UDP; + session->video_rtcp = upnp_port_binding_new(); + session->video_rtcp->protocol = UPNP_IGD_IP_PROTOCOL_UDP; return NULL; } + +void upnp_session_destroy(UpnpSession* session) { + upnp_port_binding_release(session->audio_rtp); + upnp_port_binding_release(session->audio_rtcp); + upnp_port_binding_release(session->video_rtp); + upnp_port_binding_release(session->video_rtp); + // TODO: send remove + ms_free(session); +} diff --git a/coreapi/upnp.h b/coreapi/upnp.h index c5ff5eca0..f0a93d1d6 100644 --- a/coreapi/upnp.h +++ b/coreapi/upnp.h @@ -23,15 +23,49 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "mediastreamer2/upnp_igd.h" #include "linphonecore.h" -typedef struct _UpnpSession { +typedef enum { + UPNP_Idle, + UPNP_Pending, + UPNP_Ok, + UPNP_Ko, +} UpnpState; -} UpnpSession; +typedef struct _UpnpSession UpnpSession; + +typedef struct _UpnpPortBinding { + ms_mutex_t mutex; + UpnpState state; + upnp_igd_ip_protocol protocol; + int local_port; + int remote_port; + int retry; + int ref; +} UpnpPortBinding; + +struct _UpnpSession { + UpnpPortBinding *audio_rtp; + UpnpPortBinding *audio_rtcp; + UpnpPortBinding *video_rtp; + UpnpPortBinding *video_rtcp; + UpnpState state; +}; typedef struct _UpnpContext { upnp_igd_context *upnp_igd_ctxt; + UpnpPortBinding *sip_tcp; + UpnpPortBinding *sip_tls; + UpnpPortBinding *sip_udp; + UpnpState state; + MSList *pending_bindinds; + ms_mutex_t mutex; } UpnpContext; + +int linphone_core_update_upnp(LinphoneCore *lc, LinphoneCall *call); +int upnp_call_process(LinphoneCall *call); UpnpSession* upnp_session_new(); +void upnp_session_destroy(UpnpSession* session); + int upnp_context_init(LinphoneCore *lc); void upnp_context_uninit(LinphoneCore *lc); diff --git a/gtk/parameters.ui b/gtk/parameters.ui index d6d2e4927..3af59e11e 100644 --- a/gtk/parameters.ui +++ b/gtk/parameters.ui @@ -749,6 +749,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 03092a0a5..a26d744e5 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))); @@ -1038,6 +1043,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/mediastreamer2 b/mediastreamer2 index a1f113529..39998cb24 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit a1f113529f506aa178765cf70773db80e5768139 +Subproject commit 39998cb245606b904a77e093db168057f87bf8b0 From 9567e2bf62e4957ec110d5227f908bdb30f51027 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Thu, 3 Jan 2013 15:38:03 +0100 Subject: [PATCH 06/47] Working sip upnp --- coreapi/callbacks.c | 5 + coreapi/linphonecall.c | 11 +- coreapi/linphonecore.c | 44 ++- coreapi/private.h | 5 +- coreapi/proxy.c | 8 +- coreapi/upnp.c | 750 ++++++++++++++++++++++++++++++++--------- coreapi/upnp.h | 41 ++- mediastreamer2 | 2 +- 8 files changed, 679 insertions(+), 187 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 134c336ab..b3d1a6bb7 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -416,6 +416,11 @@ 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_local_media_description_from_upnp(call->localdesc,call->upnp_session); + } +#endif sal_call_accept(call->op); md=sal_call_get_final_media_description(call->op); if (md && !sal_media_description_empty(md)) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 8af948df5..2ab398ba5 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -283,6 +283,11 @@ 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); + } +#endif linphone_address_destroy(addr); call->localdesc=md; if (old_md) sal_media_description_unref(old_md); @@ -439,7 +444,7 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr call->op=sal_op_new(lc->sal); sal_op_set_user_pointer(call->op,call); call->core=lc; - linphone_core_get_local_ip(lc,linphone_address_get_domain(to),call->localip); + linphone_core_get_public_ip(lc,linphone_address_get_domain(to),call->localip); linphone_call_init_common(call,from,to); call->params=*params; if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) { @@ -486,7 +491,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro } linphone_address_clean(from); - linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip); + linphone_core_get_public_ip(lc,linphone_address_get_domain(from),call->localip); linphone_call_init_common(call, from, to); call->log->call_id=ms_strdup(sal_op_get_call_id(op)); /*must be known at that time*/ linphone_core_init_default_params(lc, &call->params); @@ -1693,7 +1698,7 @@ void linphone_call_delete_ice_session(LinphoneCall *call){ #ifdef BUILD_UPNP void linphone_call_delete_upnp_session(LinphoneCall *call){ if(call->upnp_session!=NULL) { - upnp_session_destroy(call->upnp_session); + upnp_session_destroy(call); call->upnp_session=NULL; } } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 82e39685f..ddd9eaea6 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -66,7 +66,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*/ @@ -1307,13 +1306,20 @@ int linphone_core_set_primary_contact(LinphoneCore *lc, const char *contact) /*result must be an array of chars at least LINPHONE_IPADDR_SIZE */ -void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result){ +void linphone_core_get_public_ip(LinphoneCore *lc, const char *dest, char *result){ const char *ip; if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseNatAddress && (ip=linphone_core_get_nat_address_resolved(lc))!=NULL){ strncpy(result,ip,LINPHONE_IPADDR_SIZE); return; } +#ifdef BUILD_UPNP + else if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp + && lc->upnp.state == LinphoneUpnpStateOk) { + ip = upnp_igd_get_external_ipaddress(lc->upnp.upnp_igd_ctxt); + strncpy(result,ip,LINPHONE_IPADDR_SIZE); + } +#endif 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 */ @@ -1334,7 +1340,7 @@ static void update_primary_contact(LinphoneCore *lc){ ms_error("Could not parse identity contact !"); url=linphone_address_new("sip:unknown@unkwownhost"); } - linphone_core_get_local_ip(lc, NULL, tmp); + linphone_core_get_public_ip(lc, NULL, tmp); if (strcmp(tmp,"127.0.0.1")==0 || strcmp(tmp,"::1")==0 ){ ms_warning("Local loopback network only !"); lc->sip_conf.loopback_only=TRUE; @@ -2006,7 +2012,7 @@ void linphone_core_iterate(LinphoneCore *lc){ linphone_call_stop_media_streams_for_ice_gathering(call); } if (call->upnp_session != NULL) { - ms_warning("uPnP mapping has not finished yet, proceeded with the call withoutt uPnP anyway."); + ms_warning("uPnP mapping has not finished yet, proceeded with the call without uPnP anyway."); linphone_call_delete_upnp_session(call); } linphone_core_start_invite(lc,call); @@ -2639,9 +2645,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 if (call->params.in_conference){ subject="Conference"; }else{ @@ -2756,6 +2767,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 sal_call_set_local_media_description(call->op,call->localdesc); sal_call_accept(call->op); md=sal_call_get_final_media_description(call->op); @@ -3124,8 +3140,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 if (sal_media_description_has_dir(call->resultdesc,SalStreamSendRecv)){ sal_media_description_set_dir(call->localdesc,SalStreamSendOnly); subject="Call on hold"; @@ -3203,8 +3225,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 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"; diff --git a/coreapi/private.h b/coreapi/private.h index d4abf16ca..e110a03e3 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -206,7 +206,7 @@ int set_lock_file(); int get_lock_file(); int remove_lock_file(); void check_sound_device(LinphoneCore *lc); -void linphone_core_get_local_ip(LinphoneCore *lc, const char *to, char *result); +void linphone_core_get_public_ip(LinphoneCore *lc, const char *to, char *result); bool_t host_has_ipv6_network(); bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret); @@ -593,6 +593,9 @@ int linphone_core_del_call( LinphoneCore *lc, LinphoneCall *call); int linphone_core_set_as_current_call(LinphoneCore *lc, LinphoneCall *call); int linphone_core_get_calls_nb(const LinphoneCore *lc); +void linphone_core_add_iterate_hook(LinphoneCore *lc, LinphoneCoreIterateHook hook, void *hook_data); +void linphone_core_remove_iterate_hook(LinphoneCore *lc, LinphoneCoreIterateHook hook, void *hook_data); + void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message); void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call); void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md); diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 3b47af42c..ff046f92e 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -268,7 +268,7 @@ static char *guess_contact_for_register(LinphoneProxyConfig *obj){ LCSipTransports tr; LinphoneAddress *contact; - linphone_core_get_local_ip(obj->lc,host,localip); + linphone_core_get_public_ip(obj->lc,host,localip); contact=linphone_address_new(obj->reg_identity); linphone_address_set_domain (contact,localip); linphone_address_set_port_int(contact,linphone_core_get_sip_port(obj->lc)); @@ -427,7 +427,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" }, @@ -545,7 +545,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" }, @@ -556,7 +556,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/upnp.c b/coreapi/upnp.c index d0b71b3e4..0de861210 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -21,14 +21,51 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "private.h" #define UPNP_MAX_RETRY 4 +#define UPNP_SECTION_NAME "uPnP" + +/* Define private types */ +typedef struct _LpItem{ + char *key; + char *value; +} LpItem; + +typedef struct _LpSection{ + char *name; + MSList *items; +} LpSection; + +typedef struct _LpConfig{ + FILE *file; + char *filename; + MSList *sections; + int modified; + int readonly; +} LpConfig; + +/* Declare private functions */ +LpSection *lp_config_find_section(LpConfig *lpconfig, const char *name); +void lp_section_remove_item(LpSection *sec, LpItem *item); +void lp_config_set_string(LpConfig *lpconfig,const char *section, const char *key, const char *value); + +bool_t linphone_core_upnp_hook(void *data); UpnpPortBinding *upnp_port_binding_new(); -UpnpPortBinding * upnp_port_binding_retain(UpnpPortBinding *port); +UpnpPortBinding *upnp_port_binding_copy(const UpnpPortBinding *port); +bool_t upnp_port_binding_equal(const UpnpPortBinding *port1, const UpnpPortBinding *port2); +UpnpPortBinding *upnp_port_binding_retain(UpnpPortBinding *port); void upnp_port_binding_release(UpnpPortBinding *port); +MSList *upnp_config_list_port_bindings(struct _LpConfig *lpc); +int upnp_config_add_port_binding(LinphoneCore *lc, const UpnpPortBinding *port); +int upnp_config_remove_port_binding(LinphoneCore *lc, const UpnpPortBinding *port); + int upnp_context_send_remove_port_binding(LinphoneCore *lc, UpnpPortBinding *port); int upnp_context_send_add_port_binding(LinphoneCore *lc, 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; @@ -56,7 +93,6 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { const char *ip_address = NULL; const char *connection_status = NULL; bool_t nat_enabled = FALSE; - ms_mutex_lock(&lupnp->mutex); switch(event) { @@ -68,13 +104,14 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { nat_enabled = upnp_igd_get_nat_enabled(lupnp->upnp_igd_ctxt); if(ip_address == NULL || connection_status == NULL) { - lupnp->state = UPNP_Pending; + ms_message("uPnP IGD: Pending"); + lupnp->state = LinphoneUpnpStatePending; } else if(strcasecmp(connection_status, "Connected") || !nat_enabled) { - lupnp->state = UPNP_Ko; + ms_message("uPnP IGD: Not Available"); + lupnp->state = LinphoneUpnpStateNotAvailable; } else { - // Emit add port binding - // Emit remove old port binding - lupnp->state = UPNP_Ok; + ms_message("uPnP IGD: Connected"); + lupnp->state = LinphoneUpnpStateOk; } break; @@ -82,33 +119,56 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { case UPNP_IGD_PORT_MAPPING_ADD_SUCCESS: mapping = (upnp_igd_port_mapping *) arg; port_mapping = (UpnpPortBinding*) mapping->cookie; - port_mapping->remote_port = mapping->remote_port; - port_mapping->state = UPNP_Ok; - // TODO: SAVE IN CONFIG THE PORT + port_mapping->external_port = mapping->remote_port; + port_mapping->state = LinphoneUpnpStateOk; + ms_message("uPnP IGD: Added port binding %s|%d->%s:%d", + (port_mapping->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP", + port_mapping->external_port, + port_mapping->local_addr, + port_mapping->local_port); + upnp_config_add_port_binding(lc, port_mapping); + upnp_port_binding_release(port_mapping); break; case UPNP_IGD_PORT_MAPPING_ADD_FAILURE: mapping = (upnp_igd_port_mapping *) arg; port_mapping = (UpnpPortBinding*) mapping->cookie; - upnp_context_send_add_port_binding(lc, port_mapping); + if(upnp_context_send_add_port_binding(lc, port_mapping) != 0) { + ms_error("uPnP IGD: Can't add port binding %s|%d->%s:%d", + (port_mapping->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP", + port_mapping->external_port, + port_mapping->local_addr, + port_mapping->local_port); + } + upnp_port_binding_release(port_mapping); break; case UPNP_IGD_PORT_MAPPING_REMOVE_SUCCESS: mapping = (upnp_igd_port_mapping *) arg; port_mapping = (UpnpPortBinding*) mapping->cookie; - port_mapping->remote_port = -1; - port_mapping->state = UPNP_Idle; - // TODO: REMOVE FROM CONFIG THE PORT + port_mapping->state = LinphoneUpnpStateIdle; + ms_message("uPnP IGD: Removed port binding %s|%d->%d", + (port_mapping->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP", + port_mapping->external_port, + port_mapping->local_port); + upnp_config_remove_port_binding(lc, port_mapping); + upnp_port_binding_release(port_mapping); break; case UPNP_IGD_PORT_MAPPING_REMOVE_FAILURE: mapping = (upnp_igd_port_mapping *) arg; port_mapping = (UpnpPortBinding*) mapping->cookie; - upnp_context_send_remove_port_binding(lc, port_mapping); - // TODO: REMOVE FROM CONFIG THE PORT (DON'T TRY ANYMORE) + if(upnp_context_send_remove_port_binding(lc, port_mapping) != 0) { + ms_error("uPnP IGD: Can't remove port binding %s|%d->%d", + (port_mapping->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP", + port_mapping->external_port, + port_mapping->local_port); + upnp_config_remove_port_binding(lc, port_mapping); + } + upnp_port_binding_release(port_mapping); break; @@ -119,161 +179,74 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { ms_mutex_unlock(&lupnp->mutex); } -int upnp_context_send_add_port_binding(LinphoneCore *lc, UpnpPortBinding *port) { - UpnpContext *lupnp = &lc->upnp; - upnp_igd_port_mapping mapping; - char * local_host = NULL; - int ret; - if(port->state == UPNP_Idle) { - port->remote_port = -1; - port->retry = 0; - port->state = UPNP_Pending; - } - if(port->retry >= UPNP_MAX_RETRY) { - ret = -1; - } else { - local_host = upnp_igd_get_local_ipaddress(lupnp->upnp_igd_ctxt); - mapping.cookie = upnp_port_binding_retain(port); - mapping.local_port = port->local_port; - mapping.local_host = local_host; - mapping.remote_port = rand()%1024 + 1024; - mapping.remote_host = ""; - mapping.description = PACKAGE_NAME; - mapping.protocol = port->protocol; - port->retry++; - ret = upnp_igd_add_port_mapping(lupnp->upnp_igd_ctxt, &mapping); - if(local_host != NULL) { - free(local_host); - } - } - if(ret != 0) { - port->state = UPNP_Ko; - } - return ret; -} - -int upnp_context_send_remove_port_binding(LinphoneCore *lc, UpnpPortBinding *port) { - UpnpContext *lupnp = &lc->upnp; - upnp_igd_port_mapping mapping; - int ret; - if(port->state == UPNP_Idle) { - port->retry = 0; - port->state = UPNP_Pending; - } - if(port->retry >= UPNP_MAX_RETRY) { - ret = -1; - } else { - mapping.cookie = upnp_port_binding_retain(port); - mapping.remote_port = port->remote_port; - mapping.remote_host = ""; - mapping.protocol = port->protocol; - port->retry++; - ret = upnp_igd_delete_port_mapping(lupnp->upnp_igd_ctxt, &mapping); - } - if(ret != 0) { - port->state = UPNP_Ko; - } - return ret; -} - -int upnp_call_process(LinphoneCall *call) { - LinphoneCore *lc = call->core; - UpnpContext *lupnp = &lc->upnp; - int ret = -1; - - ms_mutex_lock(&lupnp->mutex); - // Don't handle when the call - if(lupnp->state != UPNP_Ko && call->upnp_session != NULL) { - ret = 0; - - /* - * Audio part - */ - call->upnp_session->audio_rtp->local_port = call->audio_port; - call->upnp_session->audio_rtcp->local_port = call->audio_port+1; - if(call->upnp_session->audio_rtp->state == UPNP_Idle && call->audiostream != NULL) { - // Add audio port binding - upnp_context_send_add_port_binding(lc, call->upnp_session->audio_rtp); - } else if(call->upnp_session->audio_rtp->state == UPNP_Ok && call->audiostream == NULL) { - // Remove audio port binding - upnp_context_send_remove_port_binding(lc, call->upnp_session->audio_rtp); - } - if(call->upnp_session->audio_rtcp->state == UPNP_Idle && call->audiostream != NULL) { - // Add audio port binding - upnp_context_send_add_port_binding(lc, call->upnp_session->audio_rtcp); - } else if(call->upnp_session->audio_rtcp->state == UPNP_Ok && call->audiostream == NULL) { - // Remove audio port binding - upnp_context_send_remove_port_binding(lc, call->upnp_session->audio_rtcp); - } - - /* - * Video part - */ - call->upnp_session->video_rtp->local_port = call->video_port; - call->upnp_session->video_rtcp->local_port = call->video_port+1; - if(call->upnp_session->video_rtp->state == UPNP_Idle && call->videostream != NULL) { - // Add video port binding - upnp_context_send_add_port_binding(lc, call->upnp_session->video_rtp); - } else if(call->upnp_session->video_rtp->state == UPNP_Ok && call->videostream == NULL) { - // Remove video port binding - upnp_context_send_remove_port_binding(lc, call->upnp_session->video_rtp); - } - if(call->upnp_session->video_rtcp->state == UPNP_Idle && call->videostream != NULL) { - // Add video port binding - upnp_context_send_add_port_binding(lc, call->upnp_session->video_rtcp); - } else if(call->upnp_session->video_rtcp->state == UPNP_Ok && call->videostream == NULL) { - // Remove video port binding - upnp_context_send_remove_port_binding(lc, call->upnp_session->video_rtcp); - } - } - ms_mutex_unlock(&lupnp->mutex); - return ret; -} - -int linphone_core_update_upnp(LinphoneCore *lc, LinphoneCall *call) { - return upnp_call_process(call); -} +/** + * uPnP Context + */ int upnp_context_init(LinphoneCore *lc) { LCSipTransports transport; UpnpContext *lupnp = &lc->upnp; + const char *ip_address; + ms_mutex_init(&lupnp->mutex, NULL); - lupnp->state = UPNP_Idle; + lupnp->pending_configs = NULL; + lupnp->state = LinphoneUpnpStateIdle; + lupnp->old_state = LinphoneUpnpStateIdle; + ms_message("uPnP IGD: Init"); linphone_core_get_sip_transports(lc, &transport); if(transport.udp_port != 0) { lupnp->sip_udp = upnp_port_binding_new(); lupnp->sip_udp->protocol = UPNP_IGD_IP_PROTOCOL_UDP; + lupnp->sip_udp->local_port = transport.udp_port; } else { lupnp->sip_udp = NULL; } if(transport.tcp_port != 0) { lupnp->sip_tcp = upnp_port_binding_new(); lupnp->sip_tcp->protocol = UPNP_IGD_IP_PROTOCOL_TCP; + lupnp->sip_tcp->local_port = transport.tcp_port; } else { lupnp->sip_tcp = NULL; } if(transport.tls_port != 0) { lupnp->sip_tls = upnp_port_binding_new(); lupnp->sip_tls->protocol = UPNP_IGD_IP_PROTOCOL_TCP; + lupnp->sip_tls->local_port = transport.tls_port; } else { lupnp->sip_tls = NULL; } + + linphone_core_add_iterate_hook(lc, linphone_core_upnp_hook, lc); + lupnp->upnp_igd_ctxt = NULL; lupnp->upnp_igd_ctxt = upnp_igd_create(linphone_upnp_igd_callback, linphone_upnp_igd_print, lc); - if(lupnp->upnp_igd_ctxt == NULL ) { - lupnp->state = UPNP_Ko; + if(lupnp->upnp_igd_ctxt == NULL) { + lupnp->state = LinphoneUpnpStateKo; ms_error("Can't create uPnP IGD context"); return -1; } - lupnp->state = UPNP_Pending; + + 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; return 0; } void upnp_context_uninit(LinphoneCore *lc) { - // Emit remove port (sip & saved) UpnpContext *lupnp = &lc->upnp; + linphone_core_remove_iterate_hook(lc, linphone_core_upnp_hook, lc); + if(lupnp->sip_udp != NULL) { upnp_port_binding_release(lupnp->sip_udp); } @@ -287,19 +260,334 @@ void upnp_context_uninit(LinphoneCore *lc) { upnp_igd_destroy(lupnp->upnp_igd_ctxt); } ms_mutex_destroy(&lupnp->mutex); + + ms_message("uPnP IGD: Uninit"); } +int upnp_context_send_add_port_binding(LinphoneCore *lc, UpnpPortBinding *port) { + UpnpContext *lupnp = &lc->upnp; + upnp_igd_port_mapping mapping; + int ret; + if(port->state == LinphoneUpnpStateIdle) { + port->external_port = -1; + port->retry = 0; + port->state = LinphoneUpnpStateAdding; + } else if(port->state != LinphoneUpnpStateAdding) { + ms_error("uPnP: try to add a port binding in wrong state: %d", port->state); + return -2; + } + + if(port->retry >= UPNP_MAX_RETRY) { + ret = -1; + } else { + mapping.cookie = upnp_port_binding_retain(port); + mapping.local_port = port->local_port; + mapping.local_host = port->local_addr; + if(port->external_port == -1) + mapping.remote_port = rand()%1024 + 1024; // TODO: use better method + else + mapping.remote_port = port->external_port; + mapping.remote_host = ""; + mapping.description = PACKAGE_NAME; + mapping.protocol = port->protocol; + + port->retry++; + ret = upnp_igd_add_port_mapping(lupnp->upnp_igd_ctxt, &mapping); + } + if(ret != 0) { + port->state = LinphoneUpnpStateKo; + } + return ret; +} + +int upnp_context_send_remove_port_binding(LinphoneCore *lc, UpnpPortBinding *port) { + UpnpContext *lupnp = &lc->upnp; + upnp_igd_port_mapping mapping; + int ret; + if(port->state == LinphoneUpnpStateIdle) { + port->retry = 0; + port->state = LinphoneUpnpStateRemoving; + } else if(port->state != LinphoneUpnpStateRemoving) { + ms_error("uPnP: try to remove a port binding in wrong state: %d", port->state); + return -2; + } + + if(port->retry >= UPNP_MAX_RETRY) { + ret = -1; + } else { + mapping.cookie = upnp_port_binding_retain(port); + mapping.remote_port = port->external_port; + mapping.remote_host = ""; + mapping.protocol = port->protocol; + port->retry++; + ret = upnp_igd_delete_port_mapping(lupnp->upnp_igd_ctxt, &mapping); + } + if(ret != 0) { + port->state = LinphoneUpnpStateKo; + } + return ret; +} + +/* + * uPnP Core interfaces + */ + +int upnp_call_process(LinphoneCall *call) { + LinphoneCore *lc = call->core; + UpnpContext *lupnp = &lc->upnp; + int ret = -1; + UpnpState oldState; + const char *local_addr, *external_addr; + + 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; + 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->rtp->state == LinphoneUpnpStateIdle && call->audiostream != NULL) { + // Add audio port binding + upnp_context_send_add_port_binding(lc, call->upnp_session->audio->rtp); + } else if(call->upnp_session->audio->rtp->state == LinphoneUpnpStateOk && call->audiostream == NULL) { + // Remove audio port binding + upnp_context_send_remove_port_binding(lc, call->upnp_session->audio->rtp); + } + if(call->upnp_session->audio->rtcp->state == LinphoneUpnpStateIdle && call->audiostream != NULL) { + // Add audio port binding + upnp_context_send_add_port_binding(lc, call->upnp_session->audio->rtcp); + } else if(call->upnp_session->audio->rtcp->state == LinphoneUpnpStateOk && call->audiostream == NULL) { + // Remove audio port binding + upnp_context_send_remove_port_binding(lc, call->upnp_session->audio->rtcp); + } + 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; + } + + /* + * 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; + 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->rtp->state == LinphoneUpnpStateIdle && call->videostream != NULL) { + // Add video port binding + upnp_context_send_add_port_binding(lc, call->upnp_session->video->rtp); + } else if(call->upnp_session->video->rtp->state == LinphoneUpnpStateOk && call->videostream == NULL) { + // Remove video port binding + upnp_context_send_remove_port_binding(lc, call->upnp_session->video->rtp); + } + if(call->upnp_session->video->rtcp->state == LinphoneUpnpStateIdle && call->videostream != NULL) { + // Add video port binding + upnp_context_send_add_port_binding(lc, call->upnp_session->video->rtcp); + } else if(call->upnp_session->video->rtcp->state == LinphoneUpnpStateOk && call->videostream == NULL) { + // Remove video port binding + upnp_context_send_remove_port_binding(lc, call->upnp_session->video->rtcp); + } + 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; + } + + /* When change is done proceed update */ + if(oldState != LinphoneUpnpStateOk && oldState != LinphoneUpnpStateKo && + (call->upnp_session->state == LinphoneUpnpStateOk || call->upnp_session->state == LinphoneUpnpStateKo)) { + switch (call->state) { + case LinphoneCallUpdating: + linphone_core_start_update_call(call->core, call); + break; + case LinphoneCallUpdatedByRemote: + linphone_core_start_accept_call_update(call->core, call); + break; + case LinphoneCallOutgoingInit: + linphone_core_proceed_with_invite_if_ready(call->core, call, NULL); + break; + case LinphoneCallIdle: + linphone_core_notify_incoming_call(call->core, call); + break; + default: + break; + } + } + } + + ms_mutex_unlock(&lupnp->mutex); + return ret; +} + +int linphone_core_update_upnp(LinphoneCore *lc, LinphoneCall *call) { + return upnp_call_process(call); +} + +bool_t linphone_core_upnp_hook(void *data) { + char key[64]; + MSList *port_bindings = NULL; + MSList *port_bindings_item; + UpnpPortBinding *port_mapping; + LinphoneCore *lc = (LinphoneCore *)data; + UpnpContext *lupnp = &lc->upnp; + ms_mutex_lock(&lupnp->mutex); + + if(lupnp->state == LinphoneUpnpStateOk && lupnp->old_state != LinphoneUpnpStateOk) { + // Remove old mapping + port_bindings = upnp_config_list_port_bindings(lc->config); + if(port_bindings != NULL) { + for(port_bindings_item = port_bindings;port_bindings_item!=NULL;port_bindings_item=port_bindings_item->next) { + port_mapping = (UpnpPortBinding *)port_bindings_item->data; + upnp_context_send_remove_port_binding(lc, port_mapping); + } + ms_list_for_each(port_bindings,(void (*)(void*))upnp_port_binding_release); + port_bindings = ms_list_free(port_bindings); + } + } + + if(lupnp->state == LinphoneUpnpStateOk && lupnp->old_state != LinphoneUpnpStateOk) { + // Add port bindings + if(lupnp->sip_udp != NULL) { + upnp_context_send_add_port_binding(lc, lupnp->sip_udp); + } + if(lupnp->sip_tcp != NULL) { + upnp_context_send_add_port_binding(lc, lupnp->sip_tcp); + } + if(lupnp->sip_tls != NULL) { + upnp_context_send_add_port_binding(lc, lupnp->sip_tls); + } + } + + /* Update configs */ + for(port_bindings_item = lupnp->pending_configs;port_bindings_item!=NULL;port_bindings_item=port_bindings_item->next) { + port_mapping = (UpnpPortBinding *)port_bindings_item->data; + if(port_mapping->state == LinphoneUpnpStateAdding) { + 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(lc->config, UPNP_SECTION_NAME, key, ""); + } + if(port_mapping->state == LinphoneUpnpStateRemoving) { + 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(lc->config, UPNP_SECTION_NAME, key, NULL); + } + } + ms_list_for_each(lupnp->pending_configs,(void (*)(void*))upnp_port_binding_release); + lupnp->pending_configs = ms_list_free(lupnp->pending_configs); + + lupnp->old_state = lupnp->state; + ms_mutex_unlock(&lupnp->mutex); + return TRUE; +} + +void linphone_core_update_local_media_description_from_upnp(SalMediaDescription *desc, UpnpSession *session) { + int i; + SalStreamDescription *stream; + UpnpStream *upnpStream; + + for (i = 0; i < desc->nstreams; 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; + } + } + } +} + + +/* + * uPnP Port Binding + */ + UpnpPortBinding *upnp_port_binding_new() { UpnpPortBinding *port = NULL; port = ms_new0(UpnpPortBinding,1); ms_mutex_init(&port->mutex, NULL); - port->state = UPNP_Idle; + port->state = LinphoneUpnpStateIdle; + port->local_addr[0] = '\0'; port->local_port = -1; - port->remote_port = -1; + port->external_addr[0] = '\0'; + port->external_port = -1; port->ref = 1; return port; } +UpnpPortBinding *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; +} + +bool_t 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 *upnp_port_binding_retain(UpnpPortBinding *port) { ms_mutex_lock(&port->mutex); port->ref++; @@ -318,25 +606,177 @@ void upnp_port_binding_release(UpnpPortBinding *port) { ms_mutex_unlock(&port->mutex); } -UpnpSession* upnp_session_new() { - UpnpSession *session = ms_new0(UpnpSession,1); - session->state = UPNP_Idle; - session->audio_rtp = upnp_port_binding_new(); - session->audio_rtp->protocol = UPNP_IGD_IP_PROTOCOL_UDP; - session->audio_rtcp = upnp_port_binding_new(); - session->audio_rtcp->protocol = UPNP_IGD_IP_PROTOCOL_UDP; - session->video_rtp = upnp_port_binding_new(); - session->video_rtp->protocol = UPNP_IGD_IP_PROTOCOL_UDP; - session->video_rtcp = upnp_port_binding_new(); - session->video_rtcp->protocol = UPNP_IGD_IP_PROTOCOL_UDP; +/* + * uPnP Stream + */ + +UpnpStream* upnp_stream_new() { + UpnpStream *stream = ms_new0(UpnpStream,1); + stream->state = LinphoneUpnpStateIdle; + stream->rtp = upnp_port_binding_new(); + stream->rtp->protocol = UPNP_IGD_IP_PROTOCOL_UDP; + stream->rtcp = upnp_port_binding_new(); + stream->rtcp->protocol = UPNP_IGD_IP_PROTOCOL_UDP; return NULL; } -void upnp_session_destroy(UpnpSession* session) { - upnp_port_binding_release(session->audio_rtp); - upnp_port_binding_release(session->audio_rtcp); - upnp_port_binding_release(session->video_rtp); - upnp_port_binding_release(session->video_rtp); - // TODO: send remove - ms_free(session); +void upnp_stream_destroy(UpnpStream* stream) { + upnp_port_binding_release(stream->rtp); + upnp_port_binding_release(stream->rtcp); + ms_free(stream); +} + + +/* + * uPnP Session + */ + +UpnpSession* upnp_session_new() { + UpnpSession *session = ms_new0(UpnpSession,1); + session->state = LinphoneUpnpStateIdle; + session->audio = upnp_stream_new(); + session->video = upnp_stream_new(); + return NULL; +} + +void upnp_session_destroy(LinphoneCall* call) { + LinphoneCore *lc = call->core; + + /* Remove bindings */ + if(call->upnp_session->audio->rtp->state != LinphoneUpnpStateKo && call->upnp_session->audio->rtp->state != LinphoneUpnpStateIdle) { + upnp_context_send_remove_port_binding(lc, call->upnp_session->audio->rtp); + } + if(call->upnp_session->audio->rtcp->state != LinphoneUpnpStateKo && call->upnp_session->audio->rtcp->state != LinphoneUpnpStateIdle) { + upnp_context_send_remove_port_binding(lc, call->upnp_session->audio->rtcp); + } + if(call->upnp_session->video->rtp->state != LinphoneUpnpStateKo && call->upnp_session->video->rtp->state != LinphoneUpnpStateIdle) { + upnp_context_send_remove_port_binding(lc, call->upnp_session->video->rtp); + } + if(call->upnp_session->video->rtcp->state != LinphoneUpnpStateKo && call->upnp_session->video->rtcp->state != LinphoneUpnpStateIdle) { + upnp_context_send_remove_port_binding(lc, call->upnp_session->video->rtcp); + } + + upnp_stream_destroy(call->upnp_session->audio); + upnp_stream_destroy(call->upnp_session->video); + ms_free(call->upnp_session); + call->upnp_session = NULL; +} + + +/* + * uPnP Config + */ + +MSList *upnp_config_list_port_bindings(struct _LpConfig *lpc) { + char protocol_str[4]; // TCP or UDP + upnp_igd_ip_protocol protocol; + int external_port; + int local_port; + MSList *retList = NULL; + UpnpPortBinding *port; + bool_t valid; + MSList *elem; + MSList *prev_elem; + LpItem *item; + LpSection *sec=lp_config_find_section(lpc, UPNP_SECTION_NAME); + if(sec == NULL) + return retList; + + elem = sec->items; + while(elem != NULL) { + item=(LpItem*)elem->data; + valid = TRUE; + if(sscanf(item->key, "%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 = upnp_port_binding_new(); + port->protocol = protocol; + port->external_port = external_port; + port->local_port = local_port; + retList = ms_list_append(retList, port); + } + } else { + valid = FALSE; + } + prev_elem = elem; + elem = ms_list_next(elem); + if(!valid) { + ms_warning("uPnP configuration invalid line: %s", item->key); + lp_section_remove_item(sec, item); + } + } + + return retList; +} + +int upnp_config_add_port_binding(LinphoneCore *lc, const UpnpPortBinding *port) { + UpnpContext *lupnp = &lc->upnp; + MSList *list = lupnp->pending_configs; + UpnpPortBinding *list_port; + bool_t remove; + bool_t add = TRUE; + while(list != NULL) { + remove = FALSE; + list_port = (UpnpPortBinding *)list->data; + if(upnp_port_binding_equal(list_port, port) == TRUE) { + if(list_port->state == LinphoneUpnpStateAdding) { + add = FALSE; + break; + } + if(list_port->state == LinphoneUpnpStateRemoving) { + remove = TRUE; + break; + } + } + list = ms_list_next(list); + } + + if(remove) { + lupnp->pending_configs = ms_list_remove(list, list_port); + } else if(add) { + list_port = upnp_port_binding_copy(port); + list_port->state = LinphoneUpnpStateAdding; + lupnp->pending_configs = ms_list_append(list, list_port); + } + + return 0; +} + +int upnp_config_remove_port_binding(LinphoneCore *lc, const UpnpPortBinding *port) { + UpnpContext *lupnp = &lc->upnp; + MSList *list = lupnp->pending_configs; + UpnpPortBinding *list_port; + bool_t remove; + bool_t add = TRUE; + while(list != NULL) { + remove = FALSE; + list_port = (UpnpPortBinding *)list->data; + if(upnp_port_binding_equal(list_port, port)) { + if(list_port->state == LinphoneUpnpStateRemoving) { + add = FALSE; + break; + } + if(list_port->state == LinphoneUpnpStateAdding) { + remove = TRUE; + break; + } + } + list = ms_list_next(list); + } + + if(remove) { + lupnp->pending_configs = ms_list_remove(list, list_port); + } else if(add) { + list_port = upnp_port_binding_copy(port); + list_port->state = LinphoneUpnpStateRemoving; + lupnp->pending_configs = ms_list_append(list, list_port); + } + + return 0; } diff --git a/coreapi/upnp.h b/coreapi/upnp.h index f0a93d1d6..492b35234 100644 --- a/coreapi/upnp.h +++ b/coreapi/upnp.h @@ -22,33 +22,42 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "mediastreamer2/upnp_igd.h" #include "linphonecore.h" +#include "sal.h" typedef enum { - UPNP_Idle, - UPNP_Pending, - UPNP_Ok, - UPNP_Ko, + LinphoneUpnpStateIdle, + LinphoneUpnpStatePending, + LinphoneUpnpStateAdding, // Only used by port binding + LinphoneUpnpStateRemoving, // Only used by port binding + LinphoneUpnpStateNotAvailable, // Only used by uPnP context + LinphoneUpnpStateOk, + LinphoneUpnpStateKo, } UpnpState; -typedef struct _UpnpSession UpnpSession; typedef struct _UpnpPortBinding { ms_mutex_t mutex; UpnpState state; upnp_igd_ip_protocol protocol; + char local_addr[LINPHONE_IPADDR_SIZE]; int local_port; - int remote_port; + char external_addr[LINPHONE_IPADDR_SIZE]; + int external_port; int retry; int ref; } UpnpPortBinding; -struct _UpnpSession { - UpnpPortBinding *audio_rtp; - UpnpPortBinding *audio_rtcp; - UpnpPortBinding *video_rtp; - UpnpPortBinding *video_rtcp; +typedef struct _UpnpStream { + UpnpPortBinding *rtp; + UpnpPortBinding *rtcp; UpnpState state; -}; +} UpnpStream; + +typedef struct _UpnpSession { + UpnpStream *audio; + UpnpStream *video; + UpnpState state; +} UpnpSession; typedef struct _UpnpContext { upnp_igd_context *upnp_igd_ctxt; @@ -56,15 +65,17 @@ typedef struct _UpnpContext { UpnpPortBinding *sip_tls; UpnpPortBinding *sip_udp; UpnpState state; - MSList *pending_bindinds; + UpnpState old_state; + MSList *pending_configs; + ms_mutex_t mutex; } UpnpContext; - +void linphone_core_update_local_media_description_from_upnp(SalMediaDescription *desc, UpnpSession *session); int linphone_core_update_upnp(LinphoneCore *lc, LinphoneCall *call); int upnp_call_process(LinphoneCall *call); UpnpSession* upnp_session_new(); -void upnp_session_destroy(UpnpSession* session); +void upnp_session_destroy(LinphoneCall* call); int upnp_context_init(LinphoneCore *lc); void upnp_context_uninit(LinphoneCore *lc); diff --git a/mediastreamer2 b/mediastreamer2 index 39998cb24..34de96d6b 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 39998cb245606b904a77e093db168057f87bf8b0 +Subproject commit 34de96d6b33f58b248f7d46e9c25edb11e6a5426 From f3805137e6c2f4821450ed6391ebc92a727ec7fd Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Fri, 4 Jan 2013 16:19:13 +0100 Subject: [PATCH 07/47] Working call with uPnP --- coreapi/callbacks.c | 16 ++++ coreapi/linphonecall.c | 8 +- coreapi/linphonecore.c | 30 ++++++-- coreapi/misc.c | 49 ++++++------ coreapi/private.h | 5 +- coreapi/proxy.c | 2 +- coreapi/upnp.c | 171 +++++++++++++++++++++++++++-------------- coreapi/upnp.h | 1 + 8 files changed, 184 insertions(+), 98 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index b3d1a6bb7..4eec5be3d 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -253,6 +253,12 @@ static void call_received(SalOp *h){ return; } + 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; + } + linphone_core_notify_incoming_call(lc,call); } @@ -325,6 +331,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); @@ -418,6 +429,7 @@ static void call_accept_update(LinphoneCore *lc, LinphoneCall *call){ } #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 @@ -516,6 +528,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"); } diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 2ab398ba5..ec76311a6 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -444,7 +444,7 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr call->op=sal_op_new(lc->sal); sal_op_set_user_pointer(call->op,call); call->core=lc; - linphone_core_get_public_ip(lc,linphone_address_get_domain(to),call->localip); + linphone_core_get_local_ip(lc,linphone_address_get_domain(to),call->localip); linphone_call_init_common(call,from,to); call->params=*params; if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) { @@ -491,7 +491,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro } linphone_address_clean(from); - linphone_core_get_public_ip(lc,linphone_address_get_domain(from),call->localip); + linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip); linphone_call_init_common(call, from, to); call->log->call_id=ms_strdup(sal_op_get_call_id(op)); /*must be known at that time*/ linphone_core_init_default_params(lc, &call->params); @@ -524,9 +524,9 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro case LinphonePolicyUseUpnp: #ifdef BUILD_UPNP call->upnp_session = upnp_session_new(call); - if (call->ice_session != NULL) { + if (call->upnp_session != NULL) { linphone_call_init_media_streams(call); - if (linphone_core_update_upnp(call->core,call)<0) { + 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); } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index ddd9eaea6..7abce8e96 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1306,7 +1306,7 @@ int linphone_core_set_primary_contact(LinphoneCore *lc, const char *contact) /*result must be an array of chars at least LINPHONE_IPADDR_SIZE */ -void linphone_core_get_public_ip(LinphoneCore *lc, const char *dest, char *result){ +void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result){ const char *ip; if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseNatAddress && (ip=linphone_core_get_nat_address_resolved(lc))!=NULL){ @@ -1318,6 +1318,7 @@ void linphone_core_get_public_ip(LinphoneCore *lc, const char *dest, char *resul && lc->upnp.state == LinphoneUpnpStateOk) { ip = upnp_igd_get_external_ipaddress(lc->upnp.upnp_igd_ctxt); strncpy(result,ip,LINPHONE_IPADDR_SIZE); + return; } #endif if (linphone_core_get_local_ip_for(lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,dest,result)==0) @@ -1340,7 +1341,7 @@ static void update_primary_contact(LinphoneCore *lc){ ms_error("Could not parse identity contact !"); url=linphone_address_new("sip:unknown@unkwownhost"); } - linphone_core_get_public_ip(lc, NULL, tmp); + linphone_core_get_local_ip(lc, NULL, tmp); if (strcmp(tmp,"127.0.0.1")==0 || strcmp(tmp,"::1")==0 ){ ms_warning("Local loopback network only !"); lc->sip_conf.loopback_only=TRUE; @@ -2268,6 +2269,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) { @@ -2275,13 +2277,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 (call->upnp_session->state == 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; @@ -2843,6 +2852,14 @@ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const #if BUILD_UPNP if(call->upnp_session != NULL) { + 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_from_remote_media_description(call, sal_call_get_remote_media_description(call->op))<0) { + /* uPnP update failed, proceed with the call anyway. */ + linphone_call_delete_upnp_session(call); + } else return 0; + } } #endif //BUILD_UPNP @@ -4961,6 +4978,10 @@ static void linphone_core_uninit(LinphoneCore *lc) lc->config = NULL; /* Mark the config as NULL to block further calls */ sip_setup_unregister_all(); +#ifdef BUILD_UPNP + upnp_context_uninit(lc); +#endif + ms_list_for_each(lc->call_logs,(void (*)(void*))linphone_call_log_destroy); lc->call_logs=ms_list_free(lc->call_logs); @@ -4973,9 +4994,6 @@ static void linphone_core_uninit(LinphoneCore *lc) #ifdef TUNNEL_ENABLED if (lc->tunnel) linphone_tunnel_destroy(lc->tunnel); #endif -#ifdef BUILD_UPNP - upnp_context_uninit(lc); -#endif } static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime){ diff --git a/coreapi/misc.c b/coreapi/misc.c index d75722138..6e49d56a5 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -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/private.h b/coreapi/private.h index e110a03e3..d4abf16ca 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -206,7 +206,7 @@ int set_lock_file(); int get_lock_file(); int remove_lock_file(); void check_sound_device(LinphoneCore *lc); -void linphone_core_get_public_ip(LinphoneCore *lc, const char *to, char *result); +void linphone_core_get_local_ip(LinphoneCore *lc, const char *to, char *result); bool_t host_has_ipv6_network(); bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret); @@ -593,9 +593,6 @@ int linphone_core_del_call( LinphoneCore *lc, LinphoneCall *call); int linphone_core_set_as_current_call(LinphoneCore *lc, LinphoneCall *call); int linphone_core_get_calls_nb(const LinphoneCore *lc); -void linphone_core_add_iterate_hook(LinphoneCore *lc, LinphoneCoreIterateHook hook, void *hook_data); -void linphone_core_remove_iterate_hook(LinphoneCore *lc, LinphoneCoreIterateHook hook, void *hook_data); - void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message); void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call); void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md); diff --git a/coreapi/proxy.c b/coreapi/proxy.c index ff046f92e..82b3b3000 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -268,7 +268,7 @@ static char *guess_contact_for_register(LinphoneProxyConfig *obj){ LCSipTransports tr; LinphoneAddress *contact; - linphone_core_get_public_ip(obj->lc,host,localip); + linphone_core_get_local_ip(obj->lc,host,localip); contact=linphone_address_new(obj->reg_identity); linphone_address_set_domain (contact,localip); linphone_address_set_port_int(contact,linphone_core_get_sip_port(obj->lc)); diff --git a/coreapi/upnp.c b/coreapi/upnp.c index 0de861210..4cb41d7ae 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -53,6 +53,7 @@ UpnpPortBinding *upnp_port_binding_new(); UpnpPortBinding *upnp_port_binding_copy(const UpnpPortBinding *port); bool_t upnp_port_binding_equal(const UpnpPortBinding *port1, const UpnpPortBinding *port2); UpnpPortBinding *upnp_port_binding_retain(UpnpPortBinding *port); +void upnp_port_binding_log(int level, const char *msg, const UpnpPortBinding *port); void upnp_port_binding_release(UpnpPortBinding *port); MSList *upnp_config_list_port_bindings(struct _LpConfig *lpc); @@ -62,6 +63,7 @@ int upnp_config_remove_port_binding(LinphoneCore *lc, const UpnpPortBinding *por int upnp_context_send_remove_port_binding(LinphoneCore *lc, UpnpPortBinding *port); int upnp_context_send_add_port_binding(LinphoneCore *lc, UpnpPortBinding *port); + /** * uPnP Callbacks */ @@ -74,10 +76,10 @@ void linphone_upnp_igd_print(void *cookie, upnp_igd_print_level level, const cha ortp_level = ORTP_MESSAGE; break; case UPNP_IGD_WARNING: - ortp_level = ORTP_WARNING; + ortp_level = ORTP_DEBUG; // Too verbose otherwise break; case UPNP_IGD_ERROR: - ortp_level = ORTP_ERROR; + ortp_level = ORTP_DEBUG; // Too verbose otherwise break; default: break; @@ -121,11 +123,7 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { port_mapping = (UpnpPortBinding*) mapping->cookie; port_mapping->external_port = mapping->remote_port; port_mapping->state = LinphoneUpnpStateOk; - ms_message("uPnP IGD: Added port binding %s|%d->%s:%d", - (port_mapping->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP", - port_mapping->external_port, - port_mapping->local_addr, - port_mapping->local_port); + upnp_port_binding_log(ORTP_MESSAGE, "Added port binding", port_mapping); upnp_config_add_port_binding(lc, port_mapping); upnp_port_binding_release(port_mapping); @@ -135,11 +133,7 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { mapping = (upnp_igd_port_mapping *) arg; port_mapping = (UpnpPortBinding*) mapping->cookie; if(upnp_context_send_add_port_binding(lc, port_mapping) != 0) { - ms_error("uPnP IGD: Can't add port binding %s|%d->%s:%d", - (port_mapping->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP", - port_mapping->external_port, - port_mapping->local_addr, - port_mapping->local_port); + upnp_port_binding_log(ORTP_ERROR, "Can't add port binding", port_mapping); } upnp_port_binding_release(port_mapping); @@ -149,10 +143,7 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { mapping = (upnp_igd_port_mapping *) arg; port_mapping = (UpnpPortBinding*) mapping->cookie; port_mapping->state = LinphoneUpnpStateIdle; - ms_message("uPnP IGD: Removed port binding %s|%d->%d", - (port_mapping->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP", - port_mapping->external_port, - port_mapping->local_port); + upnp_port_binding_log(ORTP_MESSAGE, "Removed port binding", port_mapping); upnp_config_remove_port_binding(lc, port_mapping); upnp_port_binding_release(port_mapping); @@ -162,10 +153,7 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { mapping = (upnp_igd_port_mapping *) arg; port_mapping = (UpnpPortBinding*) mapping->cookie; if(upnp_context_send_remove_port_binding(lc, port_mapping) != 0) { - ms_error("uPnP IGD: Can't remove port binding %s|%d->%d", - (port_mapping->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP", - port_mapping->external_port, - port_mapping->local_port); + upnp_port_binding_log(ORTP_ERROR, "Can't remove port binding", port_mapping); upnp_config_remove_port_binding(lc, port_mapping); } @@ -304,7 +292,7 @@ int upnp_context_send_remove_port_binding(LinphoneCore *lc, UpnpPortBinding *por UpnpContext *lupnp = &lc->upnp; upnp_igd_port_mapping mapping; int ret; - if(port->state == LinphoneUpnpStateIdle) { + if(port->state == LinphoneUpnpStateOk) { port->retry = 0; port->state = LinphoneUpnpStateRemoving; } else if(port->state != LinphoneUpnpStateRemoving) { @@ -332,11 +320,10 @@ int upnp_context_send_remove_port_binding(LinphoneCore *lc, UpnpPortBinding *por * uPnP Core interfaces */ -int upnp_call_process(LinphoneCall *call) { +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; - UpnpState oldState; const char *local_addr, *external_addr; ms_mutex_lock(&lupnp->mutex); @@ -355,20 +342,88 @@ int upnp_call_process(LinphoneCall *call) { 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->rtp->state == LinphoneUpnpStateIdle && call->audiostream != NULL) { + if(call->upnp_session->audio->rtp->state == LinphoneUpnpStateIdle && audio) { // Add audio port binding upnp_context_send_add_port_binding(lc, call->upnp_session->audio->rtp); - } else if(call->upnp_session->audio->rtp->state == LinphoneUpnpStateOk && call->audiostream == NULL) { + } else if(call->upnp_session->audio->rtp->state == LinphoneUpnpStateOk && !audio) { // Remove audio port binding upnp_context_send_remove_port_binding(lc, call->upnp_session->audio->rtp); } - if(call->upnp_session->audio->rtcp->state == LinphoneUpnpStateIdle && call->audiostream != NULL) { + if(call->upnp_session->audio->rtcp->state == LinphoneUpnpStateIdle && audio) { // Add audio port binding upnp_context_send_add_port_binding(lc, call->upnp_session->audio->rtcp); - } else if(call->upnp_session->audio->rtcp->state == LinphoneUpnpStateOk && call->audiostream == NULL) { + } else if(call->upnp_session->audio->rtcp->state == LinphoneUpnpStateOk && !audio) { // Remove audio port binding upnp_context_send_remove_port_binding(lc, 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; + 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->rtp->state == LinphoneUpnpStateIdle && video) { + // Add video port binding + upnp_context_send_add_port_binding(lc, call->upnp_session->video->rtp); + } else if(call->upnp_session->video->rtp->state == LinphoneUpnpStateOk && !video) { + // Remove video port binding + upnp_context_send_remove_port_binding(lc, call->upnp_session->video->rtp); + } + if(call->upnp_session->video->rtcp->state == LinphoneUpnpStateIdle && video) { + // Add video port binding + upnp_context_send_add_port_binding(lc, call->upnp_session->video->rtcp); + } else if(call->upnp_session->video->rtcp->state == LinphoneUpnpStateOk && !video) { + // Remove video port binding + upnp_context_send_remove_port_binding(lc, call->upnp_session->video->rtcp); + } + } + + ms_mutex_unlock(&lupnp->mutex); + 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->nstreams; 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); +} + +int upnp_call_process(LinphoneCall *call) { + LinphoneCore *lc = call->core; + UpnpContext *lupnp = &lc->upnp; + int ret = -1; + UpnpState oldState; + + 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; @@ -385,28 +440,8 @@ int upnp_call_process(LinphoneCall *call) { } /* - * Video part + * Update Video state */ - 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; - 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->rtp->state == LinphoneUpnpStateIdle && call->videostream != NULL) { - // Add video port binding - upnp_context_send_add_port_binding(lc, call->upnp_session->video->rtp); - } else if(call->upnp_session->video->rtp->state == LinphoneUpnpStateOk && call->videostream == NULL) { - // Remove video port binding - upnp_context_send_remove_port_binding(lc, call->upnp_session->video->rtp); - } - if(call->upnp_session->video->rtcp->state == LinphoneUpnpStateIdle && call->videostream != NULL) { - // Add video port binding - upnp_context_send_add_port_binding(lc, call->upnp_session->video->rtcp); - } else if(call->upnp_session->video->rtcp->state == LinphoneUpnpStateOk && call->videostream == NULL) { - // Remove video port binding - upnp_context_send_remove_port_binding(lc, call->upnp_session->video->rtcp); - } 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; @@ -442,18 +477,23 @@ int upnp_call_process(LinphoneCall *call) { /* 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(call->core, call); + linphone_core_start_update_call(lc, call); break; case LinphoneCallUpdatedByRemote: - linphone_core_start_accept_call_update(call->core, call); + linphone_core_start_accept_call_update(lc, call); break; case LinphoneCallOutgoingInit: - linphone_core_proceed_with_invite_if_ready(call->core, call, NULL); + linphone_core_proceed_with_invite_if_ready(lc, call, NULL); break; case LinphoneCallIdle: - linphone_core_notify_incoming_call(call->core, call); + linphone_core_notify_incoming_call(lc, call); break; default: break; @@ -465,10 +505,6 @@ int upnp_call_process(LinphoneCall *call) { return ret; } -int linphone_core_update_upnp(LinphoneCore *lc, LinphoneCall *call) { - return upnp_call_process(call); -} - bool_t linphone_core_upnp_hook(void *data) { char key[64]; MSList *port_bindings = NULL; @@ -512,7 +548,7 @@ bool_t linphone_core_upnp_hook(void *data) { (port_mapping->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP", port_mapping->external_port, port_mapping->local_port); - lp_config_set_string(lc->config, UPNP_SECTION_NAME, key, ""); + lp_config_set_string(lc->config, UPNP_SECTION_NAME, key, "uPnP"); } if(port_mapping->state == LinphoneUpnpStateRemoving) { snprintf(key, sizeof(key), "%s-%d-%d", @@ -583,6 +619,21 @@ UpnpPortBinding *upnp_port_binding_copy(const UpnpPortBinding *port) { return new_port; } +void 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 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; @@ -606,6 +657,7 @@ void upnp_port_binding_release(UpnpPortBinding *port) { ms_mutex_unlock(&port->mutex); } + /* * uPnP Stream */ @@ -617,7 +669,7 @@ UpnpStream* upnp_stream_new() { stream->rtp->protocol = UPNP_IGD_IP_PROTOCOL_UDP; stream->rtcp = upnp_port_binding_new(); stream->rtcp->protocol = UPNP_IGD_IP_PROTOCOL_UDP; - return NULL; + return stream; } void upnp_stream_destroy(UpnpStream* stream) { @@ -636,7 +688,7 @@ UpnpSession* upnp_session_new() { session->state = LinphoneUpnpStateIdle; session->audio = upnp_stream_new(); session->video = upnp_stream_new(); - return NULL; + return session; } void upnp_session_destroy(LinphoneCall* call) { @@ -696,6 +748,7 @@ MSList *upnp_config_list_port_bindings(struct _LpConfig *lpc) { } if(valid) { port = upnp_port_binding_new(); + port->state = LinphoneUpnpStateOk; port->protocol = protocol; port->external_port = external_port; port->local_port = local_port; diff --git a/coreapi/upnp.h b/coreapi/upnp.h index 492b35234..b515d0410 100644 --- a/coreapi/upnp.h +++ b/coreapi/upnp.h @@ -72,6 +72,7 @@ typedef struct _UpnpContext { } UpnpContext; void 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 upnp_call_process(LinphoneCall *call); UpnpSession* upnp_session_new(); From 9c3097ab3d44d0a27ef783327acebb6ece8a2edf Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Mon, 7 Jan 2013 09:50:25 +0100 Subject: [PATCH 08/47] Fix invalid port binding comparaison --- coreapi/upnp.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/coreapi/upnp.c b/coreapi/upnp.c index 4cb41d7ae..94072a4fc 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -549,6 +549,7 @@ bool_t linphone_core_upnp_hook(void *data) { port_mapping->external_port, port_mapping->local_port); lp_config_set_string(lc->config, UPNP_SECTION_NAME, key, "uPnP"); + upnp_port_binding_log(ORTP_DEBUG, "Configuration: Added port binding", port_mapping); } if(port_mapping->state == LinphoneUpnpStateRemoving) { snprintf(key, sizeof(key), "%s-%d-%d", @@ -556,6 +557,7 @@ bool_t linphone_core_upnp_hook(void *data) { port_mapping->external_port, port_mapping->local_port); lp_config_set_string(lc->config, UPNP_SECTION_NAME, key, NULL); + upnp_port_binding_log(ORTP_DEBUG, "Configuration: Removed port binding", port_mapping); } } ms_list_for_each(lupnp->pending_configs,(void (*)(void*))upnp_port_binding_release); @@ -635,8 +637,9 @@ void upnp_port_binding_log(int level, const char *msg, const UpnpPortBinding *po } bool_t 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; + return port1->protocol == port2->protocol && + port1->local_port == port2->local_port && + port1->external_port == port2->external_port; } UpnpPortBinding *upnp_port_binding_retain(UpnpPortBinding *port) { @@ -772,10 +775,9 @@ int upnp_config_add_port_binding(LinphoneCore *lc, const UpnpPortBinding *port) UpnpContext *lupnp = &lc->upnp; MSList *list = lupnp->pending_configs; UpnpPortBinding *list_port; - bool_t remove; + bool_t remove = FALSE; bool_t add = TRUE; while(list != NULL) { - remove = FALSE; list_port = (UpnpPortBinding *)list->data; if(upnp_port_binding_equal(list_port, port) == TRUE) { if(list_port->state == LinphoneUpnpStateAdding) { @@ -805,10 +807,9 @@ int upnp_config_remove_port_binding(LinphoneCore *lc, const UpnpPortBinding *por UpnpContext *lupnp = &lc->upnp; MSList *list = lupnp->pending_configs; UpnpPortBinding *list_port; - bool_t remove; + bool_t remove = FALSE; bool_t add = TRUE; while(list != NULL) { - remove = FALSE; list_port = (UpnpPortBinding *)list->data; if(upnp_port_binding_equal(list_port, port)) { if(list_port->state == LinphoneUpnpStateRemoving) { From 92a7d6695ccc350bfc1eae2cadc797edf3baae98 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Mon, 7 Jan 2013 16:08:09 +0100 Subject: [PATCH 09/47] Set external port equal to local port the first time --- coreapi/callbacks.c | 2 +- coreapi/linphonecall.c | 2 +- coreapi/linphonecore.c | 16 ++++++++-------- coreapi/private.h | 2 +- coreapi/upnp.c | 11 +++++++++-- 5 files changed, 20 insertions(+), 13 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 4eec5be3d..3a21e5a6d 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -432,7 +432,7 @@ static void call_accept_update(LinphoneCore *lc, LinphoneCall *call){ linphone_core_update_upnp_from_remote_media_description(call, rmd); linphone_core_update_local_media_description_from_upnp(call->localdesc,call->upnp_session); } -#endif +#endif //BUILD_UPNP sal_call_accept(call->op); md=sal_call_get_final_media_description(call->op); if (md && !sal_media_description_empty(md)) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index ec76311a6..d8de9659c 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -287,7 +287,7 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * if(call->upnp_session != NULL) { linphone_core_update_local_media_description_from_upnp(md, call->upnp_session); } -#endif +#endif //BUILD_UPNP linphone_address_destroy(addr); call->localdesc=md; if (old_md) sal_media_description_unref(old_md); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 7abce8e96..1da9ad5cd 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1219,7 +1219,7 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta #endif #ifdef BUILD_UPNP upnp_context_init(lc); -#endif +#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; @@ -1320,7 +1320,7 @@ void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result strncpy(result,ip,LINPHONE_IPADDR_SIZE); return; } -#endif +#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 */ @@ -2504,7 +2504,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const } else { defer = TRUE; } -#endif +#endif //BUILD_UPNP } if (call->dest_proxy==NULL && lc->sip_conf.ping_with_options==TRUE){ @@ -2661,7 +2661,7 @@ int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call){ if(call->upnp_session != NULL) { linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session); } -#endif +#endif //BUILD_UPNP if (call->params.in_conference){ subject="Conference"; }else{ @@ -2780,7 +2780,7 @@ int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call) if(call->upnp_session != NULL) { linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session); } -#endif +#endif //BUILD_UPNP sal_call_set_local_media_description(call->op,call->localdesc); sal_call_accept(call->op); md=sal_call_get_final_media_description(call->op); @@ -3164,7 +3164,7 @@ int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call) if(call->upnp_session != NULL) { linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session); } -#endif +#endif //BUILD_UPNP if (sal_media_description_has_dir(call->resultdesc,SalStreamSendRecv)){ sal_media_description_set_dir(call->localdesc,SalStreamSendOnly); subject="Call on hold"; @@ -3249,7 +3249,7 @@ int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *the_call) if(call->upnp_session != NULL) { linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session); } -#endif +#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"; @@ -4980,7 +4980,7 @@ static void linphone_core_uninit(LinphoneCore *lc) #ifdef BUILD_UPNP upnp_context_uninit(lc); -#endif +#endif //BUILD_UPNP ms_list_for_each(lc->call_logs,(void (*)(void*))linphone_call_log_destroy); lc->call_logs=ms_list_free(lc->call_logs); diff --git a/coreapi/private.h b/coreapi/private.h index d4abf16ca..b2b724d83 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -42,7 +42,7 @@ extern "C" { #include "mediastreamer2/msconference.h" #ifdef BUILD_UPNP #include "upnp.h" -#endif +#endif //BUILD_UPNP #ifndef LIBLINPHONE_VERSION #define LIBLINPHONE_VERSION LINPHONE_VERSION diff --git a/coreapi/upnp.c b/coreapi/upnp.c index 94072a4fc..530bf1bf1 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -132,6 +132,7 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { case UPNP_IGD_PORT_MAPPING_ADD_FAILURE: mapping = (upnp_igd_port_mapping *) arg; port_mapping = (UpnpPortBinding*) mapping->cookie; + port_mapping->external_port = -1; //Force a new random port if(upnp_context_send_add_port_binding(lc, port_mapping) != 0) { upnp_port_binding_log(ORTP_ERROR, "Can't add port binding", port_mapping); } @@ -188,6 +189,7 @@ int upnp_context_init(LinphoneCore *lc) { lupnp->sip_udp = 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; } @@ -195,6 +197,7 @@ int upnp_context_init(LinphoneCore *lc) { lupnp->sip_tcp = 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; } @@ -202,6 +205,7 @@ int upnp_context_init(LinphoneCore *lc) { lupnp->sip_tls = 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; } @@ -257,7 +261,6 @@ int upnp_context_send_add_port_binding(LinphoneCore *lc, UpnpPortBinding *port) upnp_igd_port_mapping mapping; int ret; if(port->state == LinphoneUpnpStateIdle) { - port->external_port = -1; port->retry = 0; port->state = LinphoneUpnpStateAdding; } else if(port->state != LinphoneUpnpStateAdding) { @@ -272,7 +275,7 @@ int upnp_context_send_add_port_binding(LinphoneCore *lc, UpnpPortBinding *port) mapping.local_port = port->local_port; mapping.local_host = port->local_addr; if(port->external_port == -1) - mapping.remote_port = rand()%1024 + 1024; // TODO: use better method + mapping.remote_port = rand()%(0xffff - 1024) + 1024; // TODO: use better method else mapping.remote_port = port->external_port; mapping.remote_host = ""; @@ -339,9 +342,11 @@ int linphone_core_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool 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; + 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; + call->upnp_session->audio->rtcp->external_port = call->audio_port+1; if(call->upnp_session->audio->rtp->state == LinphoneUpnpStateIdle && audio) { // Add audio port binding upnp_context_send_add_port_binding(lc, call->upnp_session->audio->rtp); @@ -363,9 +368,11 @@ int linphone_core_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool 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; + 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; + call->upnp_session->video->rtcp->external_port = call->video_port+1; if(call->upnp_session->video->rtp->state == LinphoneUpnpStateIdle && video) { // Add video port binding upnp_context_send_add_port_binding(lc, call->upnp_session->video->rtp); From 4b257d3de4185e4cbbbeedccadc92393153402ac Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Mon, 7 Jan 2013 16:19:20 +0100 Subject: [PATCH 10/47] Don't remove hook (done before) Remove unused variable --- coreapi/upnp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/coreapi/upnp.c b/coreapi/upnp.c index 530bf1bf1..909fca3b3 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -237,7 +237,9 @@ int upnp_context_init(LinphoneCore *lc) { void upnp_context_uninit(LinphoneCore *lc) { UpnpContext *lupnp = &lc->upnp; - linphone_core_remove_iterate_hook(lc, linphone_core_upnp_hook, lc); + + // Not need, all hooks are removed before + //linphone_core_remove_iterate_hook(lc, linphone_core_upnp_hook, lc); if(lupnp->sip_udp != NULL) { upnp_port_binding_release(lupnp->sip_udp); @@ -738,7 +740,6 @@ MSList *upnp_config_list_port_bindings(struct _LpConfig *lpc) { UpnpPortBinding *port; bool_t valid; MSList *elem; - MSList *prev_elem; LpItem *item; LpSection *sec=lp_config_find_section(lpc, UPNP_SECTION_NAME); if(sec == NULL) @@ -767,7 +768,6 @@ MSList *upnp_config_list_port_bindings(struct _LpConfig *lpc) { } else { valid = FALSE; } - prev_elem = elem; elem = ms_list_next(elem); if(!valid) { ms_warning("uPnP configuration invalid line: %s", item->key); From 492f3c9b91c2b9bcb856841ae82714ba7137db75 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Tue, 8 Jan 2013 13:56:07 +0100 Subject: [PATCH 11/47] Update upnp igd, and early destroy upnp session on call fail --- coreapi/callbacks.c | 5 +++++ coreapi/upnp.c | 1 + mediastreamer2 | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 3a21e5a6d..142b4b163 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -628,6 +628,11 @@ 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."); diff --git a/coreapi/upnp.c b/coreapi/upnp.c index 909fca3b3..ff4a1eae2 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -529,6 +529,7 @@ bool_t linphone_core_upnp_hook(void *data) { if(port_bindings != NULL) { for(port_bindings_item = port_bindings;port_bindings_item!=NULL;port_bindings_item=port_bindings_item->next) { port_mapping = (UpnpPortBinding *)port_bindings_item->data; + //TODO: Don't send id it's udp/tcp/tls port binding upnp_context_send_remove_port_binding(lc, port_mapping); } ms_list_for_each(port_bindings,(void (*)(void*))upnp_port_binding_release); diff --git a/mediastreamer2 b/mediastreamer2 index 34de96d6b..f9e4fed0b 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 34de96d6b33f58b248f7d46e9c25edb11e6a5426 +Subproject commit f9e4fed0b113f04895ae24a4e40f618e156b3754 From 4e90f134d58a687c553f706b93152d3b8eba9031 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Tue, 8 Jan 2013 14:33:48 +0100 Subject: [PATCH 12/47] Add another early port binding release --- coreapi/linphonecore.c | 5 +++++ coreapi/upnp.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 1da9ad5cd..b277d8ae4 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3018,6 +3018,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"); diff --git a/coreapi/upnp.c b/coreapi/upnp.c index ff4a1eae2..336e0b78f 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -527,7 +527,7 @@ bool_t linphone_core_upnp_hook(void *data) { // Remove old mapping port_bindings = upnp_config_list_port_bindings(lc->config); if(port_bindings != NULL) { - for(port_bindings_item = port_bindings;port_bindings_item!=NULL;port_bindings_item=port_bindings_item->next) { + for(port_bindings_item = port_bindings;port_bindings_item != NULL; port_bindings_item = port_bindings_item->next) { port_mapping = (UpnpPortBinding *)port_bindings_item->data; //TODO: Don't send id it's udp/tcp/tls port binding upnp_context_send_remove_port_binding(lc, port_mapping); From 92c9faec6e9fce601a995b76b001a1a451adbdb0 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Tue, 8 Jan 2013 17:06:27 +0100 Subject: [PATCH 13/47] Improve uPnP --- coreapi/linphonecore.c | 36 ++--- coreapi/upnp.c | 289 +++++++++++++++++++++++++++-------------- coreapi/upnp.h | 11 +- 3 files changed, 222 insertions(+), 114 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index b277d8ae4..17b1c84b9 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2714,20 +2714,20 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho 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; + 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); }else{ @@ -3000,6 +3000,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); @@ -4958,6 +4963,11 @@ static void linphone_core_uninit(LinphoneCore *lc) usleep(50000); #endif } + +#ifdef BUILD_UPNP + upnp_context_uninit(lc); +#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"); @@ -4983,10 +4993,6 @@ static void linphone_core_uninit(LinphoneCore *lc) lc->config = NULL; /* Mark the config as NULL to block further calls */ sip_setup_unregister_all(); -#ifdef BUILD_UPNP - upnp_context_uninit(lc); -#endif //BUILD_UPNP - ms_list_for_each(lc->call_logs,(void (*)(void*))linphone_call_log_destroy); lc->call_logs=ms_list_free(lc->call_logs); diff --git a/coreapi/upnp.c b/coreapi/upnp.c index 336e0b78f..3a68cbcbe 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -20,7 +20,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "upnp.h" #include "private.h" -#define UPNP_MAX_RETRY 4 +#define UPNP_ADD_MAX_RETRY 4 +#define UPNP_REMOVE_MAX_RETRY 4 #define UPNP_SECTION_NAME "uPnP" /* Define private types */ @@ -57,8 +58,8 @@ void upnp_port_binding_log(int level, const char *msg, const UpnpPortBinding *po void upnp_port_binding_release(UpnpPortBinding *port); MSList *upnp_config_list_port_bindings(struct _LpConfig *lpc); -int upnp_config_add_port_binding(LinphoneCore *lc, const UpnpPortBinding *port); -int upnp_config_remove_port_binding(LinphoneCore *lc, const UpnpPortBinding *port); +void upnp_config_add_port_binding(LinphoneCore *lc, const UpnpPortBinding *port); +void upnp_config_remove_port_binding(LinphoneCore *lc, const UpnpPortBinding *port); int upnp_context_send_remove_port_binding(LinphoneCore *lc, UpnpPortBinding *port); int upnp_context_send_add_port_binding(LinphoneCore *lc, UpnpPortBinding *port); @@ -113,6 +114,9 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { lupnp->state = LinphoneUpnpStateNotAvailable; } else { ms_message("uPnP IGD: Connected"); + if(lupnp->state != LinphoneUpnpStateOk) { + lupnp->clean = TRUE; // Remove saved port mapping configurations + } lupnp->state = LinphoneUpnpStateOk; } @@ -126,17 +130,18 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { upnp_port_binding_log(ORTP_MESSAGE, "Added port binding", port_mapping); upnp_config_add_port_binding(lc, port_mapping); + lupnp->pending_bindings = ms_list_remove(lupnp->pending_bindings, port_mapping); upnp_port_binding_release(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 a new random port if(upnp_context_send_add_port_binding(lc, port_mapping) != 0) { upnp_port_binding_log(ORTP_ERROR, "Can't add port binding", port_mapping); } + lupnp->pending_bindings = ms_list_remove(lupnp->pending_bindings, port_mapping); upnp_port_binding_release(port_mapping); break; @@ -147,6 +152,7 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { upnp_port_binding_log(ORTP_MESSAGE, "Removed port binding", port_mapping); upnp_config_remove_port_binding(lc, port_mapping); + lupnp->pending_bindings = ms_list_remove(lupnp->pending_bindings, port_mapping); upnp_port_binding_release(port_mapping); break; @@ -158,6 +164,7 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { upnp_config_remove_port_binding(lc, port_mapping); } + lupnp->pending_bindings = ms_list_remove(lupnp->pending_bindings, port_mapping); upnp_port_binding_release(port_mapping); break; @@ -165,6 +172,13 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { break; } + if(lupnp->pending_bindings == NULL) { + if(lupnp->cleaning == TRUE) { + lupnp->emit = TRUE; // Emit port bindings + lupnp->cleaning = FALSE; + } + pthread_cond_signal(&lupnp->cond); + } ms_mutex_unlock(&lupnp->mutex); } @@ -179,9 +193,15 @@ int upnp_context_init(LinphoneCore *lc) { const char *ip_address; ms_mutex_init(&lupnp->mutex, NULL); - lupnp->pending_configs = NULL; + ms_cond_init(&lupnp->cond, NULL); + + lupnp->pending_bindings = NULL; + lupnp->adding_configs = NULL; + lupnp->removing_configs = NULL; + lupnp->clean = FALSE; + lupnp->cleaning = FALSE; + lupnp->emit = FALSE; lupnp->state = LinphoneUpnpStateIdle; - lupnp->old_state = LinphoneUpnpStateIdle; ms_message("uPnP IGD: Init"); linphone_core_get_sip_transports(lc, &transport); @@ -238,22 +258,62 @@ int upnp_context_init(LinphoneCore *lc) { void upnp_context_uninit(LinphoneCore *lc) { UpnpContext *lupnp = &lc->upnp; - // Not need, all hooks are removed before - //linphone_core_remove_iterate_hook(lc, linphone_core_upnp_hook, lc); + /* + * Not need, all hooks are removed before + * linphone_core_remove_iterate_hook(lc, linphone_core_upnp_hook, lc); + */ + /* Send port binding removes */ if(lupnp->sip_udp != NULL) { - upnp_port_binding_release(lupnp->sip_udp); + upnp_context_send_remove_port_binding(lc, lupnp->sip_udp); + lupnp->sip_udp = NULL; } if(lupnp->sip_tcp != NULL) { - upnp_port_binding_release(lupnp->sip_tcp); + upnp_context_send_remove_port_binding(lc, lupnp->sip_tcp); + lupnp->sip_tcp = NULL; } if(lupnp->sip_tls != NULL) { - upnp_port_binding_release(lupnp->sip_tls); + upnp_context_send_remove_port_binding(lc, lupnp->sip_tls); + lupnp->sip_tcp = NULL; } + + /* Wait all pending bindings are done */ + ms_message("uPnP IGD: Wait all pending port bindings ..."); + ms_mutex_lock(&lupnp->mutex); + ms_cond_wait(&lupnp->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(lc); + + /* Release port bindings */ + if(lupnp->sip_udp != NULL) { + upnp_port_binding_release(lupnp->sip_udp); + lupnp->sip_udp = NULL; + } + if(lupnp->sip_tcp != NULL) { + upnp_port_binding_release(lupnp->sip_tcp); + lupnp->sip_tcp = NULL; + } + if(lupnp->sip_tls != NULL) { + upnp_port_binding_release(lupnp->sip_tls); + lupnp->sip_tcp = NULL; + } + + /* Release lists */ + ms_list_for_each(lupnp->adding_configs,(void (*)(void*))upnp_port_binding_release); + lupnp->adding_configs = ms_list_free(lupnp->adding_configs); + ms_list_for_each(lupnp->removing_configs,(void (*)(void*))upnp_port_binding_release); + lupnp->removing_configs = ms_list_free(lupnp->removing_configs); + ms_list_for_each(lupnp->pending_bindings,(void (*)(void*))upnp_port_binding_release); + lupnp->pending_bindings = ms_list_free(lupnp->pending_bindings); + ms_mutex_destroy(&lupnp->mutex); + ms_cond_destroy(&lupnp->cond); ms_message("uPnP IGD: Uninit"); } @@ -270,10 +330,12 @@ int upnp_context_send_add_port_binding(LinphoneCore *lc, UpnpPortBinding *port) return -2; } - if(port->retry >= UPNP_MAX_RETRY) { + if(port->retry >= UPNP_ADD_MAX_RETRY) { ret = -1; } else { mapping.cookie = 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) @@ -305,10 +367,12 @@ int upnp_context_send_remove_port_binding(LinphoneCore *lc, UpnpPortBinding *por return -2; } - if(port->retry >= UPNP_MAX_RETRY) { + if(port->retry >= UPNP_REMOVE_MAX_RETRY) { ret = -1; } else { mapping.cookie = 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; @@ -344,11 +408,15 @@ int linphone_core_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool 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; - call->upnp_session->audio->rtp->external_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; - call->upnp_session->audio->rtcp->external_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(call->upnp_session->audio->rtp->state == LinphoneUpnpStateIdle && audio) { // Add audio port binding upnp_context_send_add_port_binding(lc, call->upnp_session->audio->rtp); @@ -370,11 +438,15 @@ int linphone_core_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool 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; - call->upnp_session->video->rtp->external_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; - call->upnp_session->video->rtcp->external_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(call->upnp_session->video->rtp->state == LinphoneUpnpStateIdle && video) { // Add video port binding upnp_context_send_add_port_binding(lc, call->upnp_session->video->rtp); @@ -392,6 +464,12 @@ int linphone_core_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool } ms_mutex_unlock(&lupnp->mutex); + + /* + * Update uPnP call state + */ + upnp_call_process(call); + return ret; } @@ -516,64 +594,85 @@ int upnp_call_process(LinphoneCall *call) { bool_t linphone_core_upnp_hook(void *data) { char key[64]; - MSList *port_bindings = NULL; - MSList *port_bindings_item; + MSList *list = NULL; + MSList *item; UpnpPortBinding *port_mapping; LinphoneCore *lc = (LinphoneCore *)data; + LinphoneCall *call; UpnpContext *lupnp = &lc->upnp; ms_mutex_lock(&lupnp->mutex); - if(lupnp->state == LinphoneUpnpStateOk && lupnp->old_state != LinphoneUpnpStateOk) { + if(lupnp->clean && !lupnp->cleaning) { + lupnp->clean = FALSE; // Remove old mapping - port_bindings = upnp_config_list_port_bindings(lc->config); - if(port_bindings != NULL) { - for(port_bindings_item = port_bindings;port_bindings_item != NULL; port_bindings_item = port_bindings_item->next) { - port_mapping = (UpnpPortBinding *)port_bindings_item->data; - //TODO: Don't send id it's udp/tcp/tls port binding + list = upnp_config_list_port_bindings(lc->config); + if(list == NULL) { + lupnp->emit = TRUE; + } else { + lupnp->cleaning = TRUE; + for(item = list;item != NULL; item = item->next) { + port_mapping = (UpnpPortBinding *)item->data; upnp_context_send_remove_port_binding(lc, port_mapping); } - ms_list_for_each(port_bindings,(void (*)(void*))upnp_port_binding_release); - port_bindings = ms_list_free(port_bindings); + ms_list_for_each(list,(void (*)(void*))upnp_port_binding_release); + list = ms_list_free(list); } } - if(lupnp->state == LinphoneUpnpStateOk && lupnp->old_state != LinphoneUpnpStateOk) { - // Add port bindings + if(lupnp->emit) { + lupnp->emit = FALSE; + + /* Force port bindings */ if(lupnp->sip_udp != NULL) { + lupnp->sip_udp->state = LinphoneUpnpStateIdle; upnp_context_send_add_port_binding(lc, lupnp->sip_udp); } if(lupnp->sip_tcp != NULL) { + lupnp->sip_udp->state = LinphoneUpnpStateIdle; upnp_context_send_add_port_binding(lc, lupnp->sip_tcp); } if(lupnp->sip_tls != NULL) { + lupnp->sip_udp->state = LinphoneUpnpStateIdle; upnp_context_send_add_port_binding(lc, lupnp->sip_tls); } - } - - /* Update configs */ - for(port_bindings_item = lupnp->pending_configs;port_bindings_item!=NULL;port_bindings_item=port_bindings_item->next) { - port_mapping = (UpnpPortBinding *)port_bindings_item->data; - if(port_mapping->state == LinphoneUpnpStateAdding) { - 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(lc->config, UPNP_SECTION_NAME, key, "uPnP"); - upnp_port_binding_log(ORTP_DEBUG, "Configuration: Added port binding", port_mapping); - } - if(port_mapping->state == LinphoneUpnpStateRemoving) { - 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(lc->config, UPNP_SECTION_NAME, key, NULL); - upnp_port_binding_log(ORTP_DEBUG, "Configuration: Removed port binding", port_mapping); + list = lc->calls; + while(list != NULL) { + call = (LinphoneCall *)list->data; + call->upnp_session->audio->rtp->state = LinphoneUpnpStateIdle; + call->upnp_session->audio->rtcp->state = LinphoneUpnpStateIdle; + call->upnp_session->video->rtp->state = LinphoneUpnpStateIdle; + call->upnp_session->video->rtcp->state = LinphoneUpnpStateIdle; + linphone_core_update_upnp_audio_video(call, call->audiostream!=NULL, call->videostream!=NULL); + list = list->next; } } - ms_list_for_each(lupnp->pending_configs,(void (*)(void*))upnp_port_binding_release); - lupnp->pending_configs = ms_list_free(lupnp->pending_configs); - lupnp->old_state = lupnp->state; + /* 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(lc->config, UPNP_SECTION_NAME, key, "uPnP"); + upnp_port_binding_log(ORTP_DEBUG, "Configuration: Added port binding", port_mapping); + } + ms_list_for_each(lupnp->adding_configs,(void (*)(void*))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(lc->config, UPNP_SECTION_NAME, key, NULL); + upnp_port_binding_log(ORTP_DEBUG, "Configuration: Removed port binding", port_mapping); + } + ms_list_for_each(lupnp->removing_configs,(void (*)(void*))upnp_port_binding_release); + lupnp->removing_configs = ms_list_free(lupnp->removing_configs); + ms_mutex_unlock(&lupnp->mutex); return TRUE; } @@ -687,7 +786,9 @@ UpnpStream* upnp_stream_new() { void upnp_stream_destroy(UpnpStream* stream) { upnp_port_binding_release(stream->rtp); + stream->rtp = NULL; upnp_port_binding_release(stream->rtcp); + stream->rtcp = NULL; ms_free(stream); } @@ -779,66 +880,60 @@ MSList *upnp_config_list_port_bindings(struct _LpConfig *lpc) { return retList; } -int upnp_config_add_port_binding(LinphoneCore *lc, const UpnpPortBinding *port) { +void upnp_config_add_port_binding(LinphoneCore *lc, const UpnpPortBinding *port) { UpnpContext *lupnp = &lc->upnp; - MSList *list = lupnp->pending_configs; + MSList *list; UpnpPortBinding *list_port; - bool_t remove = FALSE; - bool_t add = TRUE; + + list = lupnp->removing_configs; while(list != NULL) { list_port = (UpnpPortBinding *)list->data; if(upnp_port_binding_equal(list_port, port) == TRUE) { - if(list_port->state == LinphoneUpnpStateAdding) { - add = FALSE; - break; - } - if(list_port->state == LinphoneUpnpStateRemoving) { - remove = TRUE; - break; - } + lupnp->removing_configs = ms_list_remove(lupnp->removing_configs, list_port); + upnp_port_binding_release(list_port); + return; } list = ms_list_next(list); } - if(remove) { - lupnp->pending_configs = ms_list_remove(list, list_port); - } else if(add) { - list_port = upnp_port_binding_copy(port); - list_port->state = LinphoneUpnpStateAdding; - lupnp->pending_configs = ms_list_append(list, list_port); - } - - return 0; -} - -int upnp_config_remove_port_binding(LinphoneCore *lc, const UpnpPortBinding *port) { - UpnpContext *lupnp = &lc->upnp; - MSList *list = lupnp->pending_configs; - UpnpPortBinding *list_port; - bool_t remove = FALSE; - bool_t add = TRUE; + list = lupnp->adding_configs; while(list != NULL) { list_port = (UpnpPortBinding *)list->data; - if(upnp_port_binding_equal(list_port, port)) { - if(list_port->state == LinphoneUpnpStateRemoving) { - add = FALSE; - break; - } - if(list_port->state == LinphoneUpnpStateAdding) { - remove = TRUE; - break; - } + if(upnp_port_binding_equal(list_port, port) == TRUE) { + return; } list = ms_list_next(list); } - if(remove) { - lupnp->pending_configs = ms_list_remove(list, list_port); - } else if(add) { - list_port = upnp_port_binding_copy(port); - list_port->state = LinphoneUpnpStateRemoving; - lupnp->pending_configs = ms_list_append(list, list_port); + list_port = upnp_port_binding_copy(port); + lupnp->adding_configs = ms_list_append(lupnp->adding_configs, list_port); +} + +void upnp_config_remove_port_binding(LinphoneCore *lc, const UpnpPortBinding *port) { + UpnpContext *lupnp = &lc->upnp; + MSList *list; + UpnpPortBinding *list_port; + + list = lupnp->adding_configs; + while(list != NULL) { + list_port = (UpnpPortBinding *)list->data; + if(upnp_port_binding_equal(list_port, port) == TRUE) { + lupnp->adding_configs = ms_list_remove(lupnp->adding_configs, list_port); + upnp_port_binding_release(list_port); + return; + } + list = ms_list_next(list); } - return 0; + list = lupnp->removing_configs; + while(list != NULL) { + list_port = (UpnpPortBinding *)list->data; + if(upnp_port_binding_equal(list_port, port) == TRUE) { + return; + } + list = ms_list_next(list); + } + + list_port = 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 index b515d0410..04281c737 100644 --- a/coreapi/upnp.h +++ b/coreapi/upnp.h @@ -65,10 +65,17 @@ typedef struct _UpnpContext { UpnpPortBinding *sip_tls; UpnpPortBinding *sip_udp; UpnpState state; - UpnpState old_state; - MSList *pending_configs; + MSList *removing_configs; + MSList *adding_configs; + MSList *pending_bindings; + + bool_t clean; // True if at the next loop clean the port bindings + bool_t cleaning; // True if the cleaning processing; + bool_t emit; // True if at the next loop emit the port bindings ms_mutex_t mutex; + ms_cond_t cond; + } UpnpContext; void linphone_core_update_local_media_description_from_upnp(SalMediaDescription *desc, UpnpSession *session); From 215b566b2c4eedd2401a329696bba44a4fda2938 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Tue, 8 Jan 2013 17:15:46 +0100 Subject: [PATCH 14/47] Add debug log on port mapping add/remove send --- coreapi/upnp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/coreapi/upnp.c b/coreapi/upnp.c index 3a68cbcbe..30e313459 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -347,6 +347,7 @@ int upnp_context_send_add_port_binding(LinphoneCore *lc, UpnpPortBinding *port) mapping.protocol = port->protocol; port->retry++; + upnp_port_binding_log(ORTP_DEBUG, "Adding port binding...", port); ret = upnp_igd_add_port_mapping(lupnp->upnp_igd_ctxt, &mapping); } if(ret != 0) { @@ -377,6 +378,7 @@ int upnp_context_send_remove_port_binding(LinphoneCore *lc, UpnpPortBinding *por mapping.remote_host = ""; mapping.protocol = port->protocol; port->retry++; + upnp_port_binding_log(ORTP_DEBUG, "Removing port binding...", port); ret = upnp_igd_delete_port_mapping(lupnp->upnp_igd_ctxt, &mapping); } if(ret != 0) { From cc592dec5dd244d421fac15db0926eca2a9b8612 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Tue, 8 Jan 2013 17:28:01 +0100 Subject: [PATCH 15/47] Add better uPnP description --- coreapi/upnp.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/coreapi/upnp.c b/coreapi/upnp.c index 30e313459..bb7dcd8df 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -321,6 +321,7 @@ void upnp_context_uninit(LinphoneCore *lc) { int upnp_context_send_add_port_binding(LinphoneCore *lc, UpnpPortBinding *port) { UpnpContext *lupnp = &lc->upnp; upnp_igd_port_mapping mapping; + char description[128]; int ret; if(port->state == LinphoneUpnpStateIdle) { port->retry = 0; @@ -339,11 +340,15 @@ int upnp_context_send_add_port_binding(LinphoneCore *lc, UpnpPortBinding *port) mapping.local_port = port->local_port; mapping.local_host = port->local_addr; if(port->external_port == -1) - mapping.remote_port = rand()%(0xffff - 1024) + 1024; // TODO: use better method + mapping.remote_port = rand()%(0xffff - 1024) + 1024; else mapping.remote_port = port->external_port; mapping.remote_host = ""; - mapping.description = PACKAGE_NAME; + 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++; From ce87dab6378ec0e03fa44d6e8e4a9d1aa5bf83b6 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Tue, 8 Jan 2013 17:29:58 +0100 Subject: [PATCH 16/47] Add message on port mapping update/clean --- coreapi/upnp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/coreapi/upnp.c b/coreapi/upnp.c index bb7dcd8df..8827880db 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -610,6 +610,7 @@ bool_t linphone_core_upnp_hook(void *data) { ms_mutex_lock(&lupnp->mutex); if(lupnp->clean && !lupnp->cleaning) { + ms_message("uPnP IGD: Clean port mappings"); lupnp->clean = FALSE; // Remove old mapping list = upnp_config_list_port_bindings(lc->config); @@ -627,6 +628,7 @@ bool_t linphone_core_upnp_hook(void *data) { } if(lupnp->emit) { + ms_message("uPnP IGD: Update port mappings"); lupnp->emit = FALSE; /* Force port bindings */ From 33bab1941e1c37a9a3c42ea711fe19bd4bda5492 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Wed, 9 Jan 2013 10:28:18 +0100 Subject: [PATCH 17/47] Improve uPnP api --- coreapi/linphonecall.c | 2 +- coreapi/linphonecore.c | 13 +-- coreapi/private.h | 2 +- coreapi/upnp.c | 216 +++++++++++++++++++++++++++-------------- coreapi/upnp.h | 61 +++--------- 5 files changed, 163 insertions(+), 131 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index d8de9659c..4899fab57 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1698,7 +1698,7 @@ void linphone_call_delete_ice_session(LinphoneCall *call){ #ifdef BUILD_UPNP void linphone_call_delete_upnp_session(LinphoneCall *call){ if(call->upnp_session!=NULL) { - upnp_session_destroy(call); + upnp_session_destroy(call->upnp_session); call->upnp_session=NULL; } } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 17b1c84b9..12a104e76 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1218,7 +1218,7 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta if (lc->tunnel) linphone_tunnel_configure(lc->tunnel); #endif #ifdef BUILD_UPNP - upnp_context_init(lc); + lc->upnp = upnp_context_new(lc); #endif //BUILD_UPNP if (lc->vtable.display_status) lc->vtable.display_status(lc,_("Ready")); @@ -1314,9 +1314,9 @@ void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result return; } #ifdef BUILD_UPNP - else if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp - && lc->upnp.state == LinphoneUpnpStateOk) { - ip = upnp_igd_get_external_ipaddress(lc->upnp.upnp_igd_ctxt); + else if (lc->upnp != NULL && linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp && + upnp_context_get_state(lc->upnp) == LinphoneUpnpStateOk) { + ip = upnp_context_get_external_ipaddress(lc->upnp); strncpy(result,ip,LINPHONE_IPADDR_SIZE); return; } @@ -2279,7 +2279,7 @@ int linphone_core_proceed_with_invite_if_ready(LinphoneCore *lc, LinphoneCall *c } #ifdef BUILD_UPNP if (call->upnp_session != NULL) { - if (call->upnp_session->state == LinphoneUpnpStateOk) upnp_ready = TRUE; + if (upnp_session_get_state(call->upnp_session) == LinphoneUpnpStateOk) upnp_ready = TRUE; } else { upnp_ready = TRUE; } @@ -4965,7 +4965,8 @@ static void linphone_core_uninit(LinphoneCore *lc) } #ifdef BUILD_UPNP - upnp_context_uninit(lc); + upnp_context_destroy(lc->upnp); + lc->upnp = NULL; #endif //BUILD_UPNP if (lc->friends) diff --git a/coreapi/private.h b/coreapi/private.h index b2b724d83..c9d771450 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -578,7 +578,7 @@ struct _LinphoneCore char* device_id; MSList *last_recv_msg_ids; #ifdef BUILD_UPNP - UpnpContext upnp; + UpnpContext *upnp; #endif //BUILD_UPNP }; diff --git a/coreapi/upnp.c b/coreapi/upnp.c index 8827880db..70a03a7ae 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -48,6 +48,57 @@ LpSection *lp_config_find_section(LpConfig *lpconfig, const char *name); void lp_section_remove_item(LpSection *sec, LpItem *item); void lp_config_set_string(LpConfig *lpconfig,const char *section, const char *key, const char *value); + +/* + * uPnP Definitions + */ + +typedef struct _UpnpPortBinding { + ms_mutex_t mutex; + UpnpState 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; +} UpnpPortBinding; + +typedef struct _UpnpStream { + UpnpPortBinding *rtp; + UpnpPortBinding *rtcp; + UpnpState state; +} UpnpStream; + +struct _UpnpSession { + LinphoneCall *call; + UpnpStream *audio; + UpnpStream *video; + UpnpState state; +}; + +struct _UpnpContext { + LinphoneCore *lc; + upnp_igd_context *upnp_igd_ctxt; + UpnpPortBinding *sip_tcp; + UpnpPortBinding *sip_tls; + UpnpPortBinding *sip_udp; + UpnpState state; + MSList *removing_configs; + MSList *adding_configs; + MSList *pending_bindings; + + bool_t clean; // True if at the next loop clean the port bindings + bool_t cleaning; // True if the cleaning processing; + bool_t emit; // True if at the next loop emit the port bindings + + ms_mutex_t mutex; + ms_cond_t cond; + +}; + + bool_t linphone_core_upnp_hook(void *data); UpnpPortBinding *upnp_port_binding_new(); @@ -58,11 +109,11 @@ void upnp_port_binding_log(int level, const char *msg, const UpnpPortBinding *po void upnp_port_binding_release(UpnpPortBinding *port); MSList *upnp_config_list_port_bindings(struct _LpConfig *lpc); -void upnp_config_add_port_binding(LinphoneCore *lc, const UpnpPortBinding *port); -void upnp_config_remove_port_binding(LinphoneCore *lc, const UpnpPortBinding *port); +void upnp_config_add_port_binding(UpnpContext *lupnp, const UpnpPortBinding *port); +void upnp_config_remove_port_binding(UpnpContext *lupnp, const UpnpPortBinding *port); -int upnp_context_send_remove_port_binding(LinphoneCore *lc, UpnpPortBinding *port); -int upnp_context_send_add_port_binding(LinphoneCore *lc, UpnpPortBinding *port); +int upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortBinding *port); +int upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBinding *port); /** @@ -89,8 +140,7 @@ void linphone_upnp_igd_print(void *cookie, upnp_igd_print_level level, const cha } void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { - LinphoneCore *lc = (LinphoneCore *)cookie; - UpnpContext *lupnp = &lc->upnp; + UpnpContext *lupnp = (UpnpContext *)cookie; upnp_igd_port_mapping *mapping = NULL; UpnpPortBinding *port_mapping = NULL; const char *ip_address = NULL; @@ -128,7 +178,7 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { port_mapping->external_port = mapping->remote_port; port_mapping->state = LinphoneUpnpStateOk; upnp_port_binding_log(ORTP_MESSAGE, "Added port binding", port_mapping); - upnp_config_add_port_binding(lc, port_mapping); + upnp_config_add_port_binding(lupnp, port_mapping); lupnp->pending_bindings = ms_list_remove(lupnp->pending_bindings, port_mapping); upnp_port_binding_release(port_mapping); @@ -137,7 +187,8 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { case UPNP_IGD_PORT_MAPPING_ADD_FAILURE: mapping = (upnp_igd_port_mapping *) arg; port_mapping = (UpnpPortBinding*) mapping->cookie; - if(upnp_context_send_add_port_binding(lc, port_mapping) != 0) { + port_mapping->external_port = -1; //Force random external port + if(upnp_context_send_add_port_binding(lupnp, port_mapping) != 0) { upnp_port_binding_log(ORTP_ERROR, "Can't add port binding", port_mapping); } @@ -150,7 +201,7 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { port_mapping = (UpnpPortBinding*) mapping->cookie; port_mapping->state = LinphoneUpnpStateIdle; upnp_port_binding_log(ORTP_MESSAGE, "Removed port binding", port_mapping); - upnp_config_remove_port_binding(lc, port_mapping); + upnp_config_remove_port_binding(lupnp, port_mapping); lupnp->pending_bindings = ms_list_remove(lupnp->pending_bindings, port_mapping); upnp_port_binding_release(port_mapping); @@ -159,9 +210,9 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { case UPNP_IGD_PORT_MAPPING_REMOVE_FAILURE: mapping = (upnp_igd_port_mapping *) arg; port_mapping = (UpnpPortBinding*) mapping->cookie; - if(upnp_context_send_remove_port_binding(lc, port_mapping) != 0) { + if(upnp_context_send_remove_port_binding(lupnp, port_mapping) != 0) { upnp_port_binding_log(ORTP_ERROR, "Can't remove port binding", port_mapping); - upnp_config_remove_port_binding(lc, port_mapping); + upnp_config_remove_port_binding(lupnp, port_mapping); } lupnp->pending_bindings = ms_list_remove(lupnp->pending_bindings, port_mapping); @@ -187,14 +238,15 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { * uPnP Context */ -int upnp_context_init(LinphoneCore *lc) { +UpnpContext* upnp_context_new(LinphoneCore *lc) { LCSipTransports transport; - UpnpContext *lupnp = &lc->upnp; + UpnpContext *lupnp = (UpnpContext *)ms_new0(UpnpContext,1); const char *ip_address; ms_mutex_init(&lupnp->mutex, NULL); ms_cond_init(&lupnp->cond, NULL); + lupnp->lc = lc; lupnp->pending_bindings = NULL; lupnp->adding_configs = NULL; lupnp->removing_configs = NULL; @@ -202,7 +254,7 @@ int upnp_context_init(LinphoneCore *lc) { lupnp->cleaning = FALSE; lupnp->emit = FALSE; lupnp->state = LinphoneUpnpStateIdle; - ms_message("uPnP IGD: Init"); + ms_message("uPnP IGD: New %p for core %p", lupnp, lc); linphone_core_get_sip_transports(lc, &transport); if(transport.udp_port != 0) { @@ -230,14 +282,14 @@ int upnp_context_init(LinphoneCore *lc) { lupnp->sip_tls = NULL; } - linphone_core_add_iterate_hook(lc, linphone_core_upnp_hook, lc); + 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, lc); + 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 -1; + return NULL; } ip_address = upnp_igd_get_local_ipaddress(lupnp->upnp_igd_ctxt); @@ -252,12 +304,10 @@ int upnp_context_init(LinphoneCore *lc) { } lupnp->state = LinphoneUpnpStatePending; - return 0; + return lupnp; } -void upnp_context_uninit(LinphoneCore *lc) { - UpnpContext *lupnp = &lc->upnp; - +void upnp_context_destroy(UpnpContext *lupnp) { /* * Not need, all hooks are removed before * linphone_core_remove_iterate_hook(lc, linphone_core_upnp_hook, lc); @@ -265,15 +315,15 @@ void upnp_context_uninit(LinphoneCore *lc) { /* Send port binding removes */ if(lupnp->sip_udp != NULL) { - upnp_context_send_remove_port_binding(lc, lupnp->sip_udp); + upnp_context_send_remove_port_binding(lupnp, lupnp->sip_udp); lupnp->sip_udp = NULL; } if(lupnp->sip_tcp != NULL) { - upnp_context_send_remove_port_binding(lc, lupnp->sip_tcp); + upnp_context_send_remove_port_binding(lupnp, lupnp->sip_tcp); lupnp->sip_tcp = NULL; } if(lupnp->sip_tls != NULL) { - upnp_context_send_remove_port_binding(lc, lupnp->sip_tls); + upnp_context_send_remove_port_binding(lupnp, lupnp->sip_tls); lupnp->sip_tcp = NULL; } @@ -288,7 +338,7 @@ void upnp_context_uninit(LinphoneCore *lc) { } /* Run one time the hook for configuration update */ - linphone_core_upnp_hook(lc); + linphone_core_upnp_hook(lupnp); /* Release port bindings */ if(lupnp->sip_udp != NULL) { @@ -315,11 +365,19 @@ void upnp_context_uninit(LinphoneCore *lc) { ms_mutex_destroy(&lupnp->mutex); ms_cond_destroy(&lupnp->cond); - ms_message("uPnP IGD: Uninit"); + ms_message("uPnP IGD: destroy %p", lupnp); + ms_free(lupnp); } -int upnp_context_send_add_port_binding(LinphoneCore *lc, UpnpPortBinding *port) { - UpnpContext *lupnp = &lc->upnp; +UpnpState upnp_context_get_state(UpnpContext *ctx) { + return ctx->state; +} + +const char* upnp_context_get_external_ipaddress(UpnpContext *ctx) { + return upnp_igd_get_external_ipaddress(ctx->upnp_igd_ctxt); +} + +int upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBinding *port) { upnp_igd_port_mapping mapping; char description[128]; int ret; @@ -361,8 +419,7 @@ int upnp_context_send_add_port_binding(LinphoneCore *lc, UpnpPortBinding *port) return ret; } -int upnp_context_send_remove_port_binding(LinphoneCore *lc, UpnpPortBinding *port) { - UpnpContext *lupnp = &lc->upnp; +int upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortBinding *port) { upnp_igd_port_mapping mapping; int ret; if(port->state == LinphoneUpnpStateOk) { @@ -398,10 +455,14 @@ int upnp_context_send_remove_port_binding(LinphoneCore *lc, UpnpPortBinding *por int linphone_core_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool_t video) { LinphoneCore *lc = call->core; - UpnpContext *lupnp = &lc->upnp; + 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) { @@ -426,17 +487,17 @@ int linphone_core_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool } if(call->upnp_session->audio->rtp->state == LinphoneUpnpStateIdle && audio) { // Add audio port binding - upnp_context_send_add_port_binding(lc, call->upnp_session->audio->rtp); + upnp_context_send_add_port_binding(lupnp, call->upnp_session->audio->rtp); } else if(call->upnp_session->audio->rtp->state == LinphoneUpnpStateOk && !audio) { // Remove audio port binding - upnp_context_send_remove_port_binding(lc, call->upnp_session->audio->rtp); + upnp_context_send_remove_port_binding(lupnp, call->upnp_session->audio->rtp); } if(call->upnp_session->audio->rtcp->state == LinphoneUpnpStateIdle && audio) { // Add audio port binding - upnp_context_send_add_port_binding(lc, call->upnp_session->audio->rtcp); + upnp_context_send_add_port_binding(lupnp, call->upnp_session->audio->rtcp); } else if(call->upnp_session->audio->rtcp->state == LinphoneUpnpStateOk && !audio) { // Remove audio port binding - upnp_context_send_remove_port_binding(lc, call->upnp_session->audio->rtcp); + upnp_context_send_remove_port_binding(lupnp, call->upnp_session->audio->rtcp); } /* @@ -456,17 +517,17 @@ int linphone_core_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool } if(call->upnp_session->video->rtp->state == LinphoneUpnpStateIdle && video) { // Add video port binding - upnp_context_send_add_port_binding(lc, call->upnp_session->video->rtp); + upnp_context_send_add_port_binding(lupnp, call->upnp_session->video->rtp); } else if(call->upnp_session->video->rtp->state == LinphoneUpnpStateOk && !video) { // Remove video port binding - upnp_context_send_remove_port_binding(lc, call->upnp_session->video->rtp); + upnp_context_send_remove_port_binding(lupnp, call->upnp_session->video->rtp); } if(call->upnp_session->video->rtcp->state == LinphoneUpnpStateIdle && video) { // Add video port binding - upnp_context_send_add_port_binding(lc, call->upnp_session->video->rtcp); + upnp_context_send_add_port_binding(lupnp, call->upnp_session->video->rtcp); } else if(call->upnp_session->video->rtcp->state == LinphoneUpnpStateOk && !video) { // Remove video port binding - upnp_context_send_remove_port_binding(lc, call->upnp_session->video->rtcp); + upnp_context_send_remove_port_binding(lupnp, call->upnp_session->video->rtcp); } } @@ -505,10 +566,14 @@ int linphone_core_update_upnp(LinphoneCore *lc, LinphoneCall *call) { int upnp_call_process(LinphoneCall *call) { LinphoneCore *lc = call->core; - UpnpContext *lupnp = &lc->upnp; + UpnpContext *lupnp = lc->upnp; int ret = -1; UpnpState oldState; + if(lupnp == NULL) { + return ret; + } + ms_mutex_lock(&lupnp->mutex); // Don't handle when the call @@ -604,23 +669,22 @@ bool_t linphone_core_upnp_hook(void *data) { MSList *list = NULL; MSList *item; UpnpPortBinding *port_mapping; - LinphoneCore *lc = (LinphoneCore *)data; + UpnpContext *lupnp = (UpnpContext *)data; LinphoneCall *call; - UpnpContext *lupnp = &lc->upnp; ms_mutex_lock(&lupnp->mutex); if(lupnp->clean && !lupnp->cleaning) { ms_message("uPnP IGD: Clean port mappings"); lupnp->clean = FALSE; // Remove old mapping - list = upnp_config_list_port_bindings(lc->config); + list = upnp_config_list_port_bindings(lupnp->lc->config); if(list == NULL) { lupnp->emit = TRUE; } else { lupnp->cleaning = TRUE; for(item = list;item != NULL; item = item->next) { port_mapping = (UpnpPortBinding *)item->data; - upnp_context_send_remove_port_binding(lc, port_mapping); + upnp_context_send_remove_port_binding(lupnp, port_mapping); } ms_list_for_each(list,(void (*)(void*))upnp_port_binding_release); list = ms_list_free(list); @@ -634,17 +698,17 @@ bool_t linphone_core_upnp_hook(void *data) { /* Force port bindings */ if(lupnp->sip_udp != NULL) { lupnp->sip_udp->state = LinphoneUpnpStateIdle; - upnp_context_send_add_port_binding(lc, lupnp->sip_udp); + upnp_context_send_add_port_binding(lupnp, lupnp->sip_udp); } if(lupnp->sip_tcp != NULL) { lupnp->sip_udp->state = LinphoneUpnpStateIdle; - upnp_context_send_add_port_binding(lc, lupnp->sip_tcp); + upnp_context_send_add_port_binding(lupnp, lupnp->sip_tcp); } if(lupnp->sip_tls != NULL) { lupnp->sip_udp->state = LinphoneUpnpStateIdle; - upnp_context_send_add_port_binding(lc, lupnp->sip_tls); + upnp_context_send_add_port_binding(lupnp, lupnp->sip_tls); } - list = lc->calls; + list = lupnp->lc->calls; while(list != NULL) { call = (LinphoneCall *)list->data; call->upnp_session->audio->rtp->state = LinphoneUpnpStateIdle; @@ -663,7 +727,7 @@ bool_t linphone_core_upnp_hook(void *data) { (port_mapping->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP", port_mapping->external_port, port_mapping->local_port); - lp_config_set_string(lc->config, UPNP_SECTION_NAME, key, "uPnP"); + lp_config_set_string(lupnp->lc->config, UPNP_SECTION_NAME, key, "uPnP"); upnp_port_binding_log(ORTP_DEBUG, "Configuration: Added port binding", port_mapping); } ms_list_for_each(lupnp->adding_configs,(void (*)(void*))upnp_port_binding_release); @@ -676,7 +740,7 @@ bool_t linphone_core_upnp_hook(void *data) { (port_mapping->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP", port_mapping->external_port, port_mapping->local_port); - lp_config_set_string(lc->config, UPNP_SECTION_NAME, key, NULL); + lp_config_set_string(lupnp->lc->config, UPNP_SECTION_NAME, key, NULL); upnp_port_binding_log(ORTP_DEBUG, "Configuration: Removed port binding", port_mapping); } ms_list_for_each(lupnp->removing_configs,(void (*)(void*))upnp_port_binding_release); @@ -686,7 +750,7 @@ bool_t linphone_core_upnp_hook(void *data) { return TRUE; } -void linphone_core_update_local_media_description_from_upnp(SalMediaDescription *desc, UpnpSession *session) { +int linphone_core_update_local_media_description_from_upnp(SalMediaDescription *desc, UpnpSession *session) { int i; SalStreamDescription *stream; UpnpStream *upnpStream; @@ -710,6 +774,7 @@ void linphone_core_update_local_media_description_from_upnp(SalMediaDescription } } } + return 0; } @@ -806,37 +871,42 @@ void upnp_stream_destroy(UpnpStream* stream) { * uPnP Session */ -UpnpSession* upnp_session_new() { +UpnpSession* upnp_session_new(LinphoneCall* call) { UpnpSession *session = ms_new0(UpnpSession,1); + session->call = call; session->state = LinphoneUpnpStateIdle; session->audio = upnp_stream_new(); session->video = upnp_stream_new(); return session; } -void upnp_session_destroy(LinphoneCall* call) { - LinphoneCore *lc = call->core; +void upnp_session_destroy(UpnpSession *session) { + LinphoneCore *lc = session->call->core; - /* Remove bindings */ - if(call->upnp_session->audio->rtp->state != LinphoneUpnpStateKo && call->upnp_session->audio->rtp->state != LinphoneUpnpStateIdle) { - upnp_context_send_remove_port_binding(lc, call->upnp_session->audio->rtp); - } - if(call->upnp_session->audio->rtcp->state != LinphoneUpnpStateKo && call->upnp_session->audio->rtcp->state != LinphoneUpnpStateIdle) { - upnp_context_send_remove_port_binding(lc, call->upnp_session->audio->rtcp); - } - if(call->upnp_session->video->rtp->state != LinphoneUpnpStateKo && call->upnp_session->video->rtp->state != LinphoneUpnpStateIdle) { - upnp_context_send_remove_port_binding(lc, call->upnp_session->video->rtp); - } - if(call->upnp_session->video->rtcp->state != LinphoneUpnpStateKo && call->upnp_session->video->rtcp->state != LinphoneUpnpStateIdle) { - upnp_context_send_remove_port_binding(lc, call->upnp_session->video->rtcp); + if(lc->upnp != NULL) { + /* Remove bindings */ + if(session->audio->rtp->state != LinphoneUpnpStateKo && session->audio->rtp->state != LinphoneUpnpStateIdle) { + upnp_context_send_remove_port_binding(lc->upnp, session->audio->rtp); + } + if(session->audio->rtcp->state != LinphoneUpnpStateKo && session->audio->rtcp->state != LinphoneUpnpStateIdle) { + upnp_context_send_remove_port_binding(lc->upnp, session->audio->rtcp); + } + if(session->video->rtp->state != LinphoneUpnpStateKo && session->video->rtp->state != LinphoneUpnpStateIdle) { + upnp_context_send_remove_port_binding(lc->upnp, session->video->rtp); + } + if(session->video->rtcp->state != LinphoneUpnpStateKo && session->video->rtcp->state != LinphoneUpnpStateIdle) { + upnp_context_send_remove_port_binding(lc->upnp, session->video->rtcp); + } } - upnp_stream_destroy(call->upnp_session->audio); - upnp_stream_destroy(call->upnp_session->video); - ms_free(call->upnp_session); - call->upnp_session = NULL; + upnp_stream_destroy(session->audio); + upnp_stream_destroy(session->video); + ms_free(session); } +UpnpState upnp_session_get_state(UpnpSession *session) { + return session->state; +} /* * uPnP Config @@ -889,8 +959,7 @@ MSList *upnp_config_list_port_bindings(struct _LpConfig *lpc) { return retList; } -void upnp_config_add_port_binding(LinphoneCore *lc, const UpnpPortBinding *port) { - UpnpContext *lupnp = &lc->upnp; +void upnp_config_add_port_binding(UpnpContext *lupnp, const UpnpPortBinding *port) { MSList *list; UpnpPortBinding *list_port; @@ -918,8 +987,7 @@ void upnp_config_add_port_binding(LinphoneCore *lc, const UpnpPortBinding *port) lupnp->adding_configs = ms_list_append(lupnp->adding_configs, list_port); } -void upnp_config_remove_port_binding(LinphoneCore *lc, const UpnpPortBinding *port) { - UpnpContext *lupnp = &lc->upnp; +void upnp_config_remove_port_binding(UpnpContext *lupnp, const UpnpPortBinding *port) { MSList *list; UpnpPortBinding *list_port; diff --git a/coreapi/upnp.h b/coreapi/upnp.h index 04281c737..64ccc88e9 100644 --- a/coreapi/upnp.h +++ b/coreapi/upnp.h @@ -34,58 +34,21 @@ typedef enum { LinphoneUpnpStateKo, } UpnpState; +typedef struct _UpnpSession UpnpSession; +typedef struct _UpnpContext UpnpContext; -typedef struct _UpnpPortBinding { - ms_mutex_t mutex; - UpnpState 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; -} UpnpPortBinding; - -typedef struct _UpnpStream { - UpnpPortBinding *rtp; - UpnpPortBinding *rtcp; - UpnpState state; -} UpnpStream; - -typedef struct _UpnpSession { - UpnpStream *audio; - UpnpStream *video; - UpnpState state; -} UpnpSession; - -typedef struct _UpnpContext { - upnp_igd_context *upnp_igd_ctxt; - UpnpPortBinding *sip_tcp; - UpnpPortBinding *sip_tls; - UpnpPortBinding *sip_udp; - UpnpState state; - MSList *removing_configs; - MSList *adding_configs; - MSList *pending_bindings; - - bool_t clean; // True if at the next loop clean the port bindings - bool_t cleaning; // True if the cleaning processing; - bool_t emit; // True if at the next loop emit the port bindings - - ms_mutex_t mutex; - ms_cond_t cond; - -} UpnpContext; - -void linphone_core_update_local_media_description_from_upnp(SalMediaDescription *desc, UpnpSession *session); +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 upnp_call_process(LinphoneCall *call); -UpnpSession* upnp_session_new(); -void upnp_session_destroy(LinphoneCall* call); -int upnp_context_init(LinphoneCore *lc); -void upnp_context_uninit(LinphoneCore *lc); +int upnp_call_process(LinphoneCall *call); +UpnpSession* upnp_session_new(LinphoneCall *call); +void upnp_session_destroy(UpnpSession* session); +UpnpState upnp_session_get_state(UpnpSession *session); + +UpnpContext *upnp_context_new(LinphoneCore *lc); +void upnp_context_destroy(UpnpContext *ctx); +UpnpState upnp_context_get_state(UpnpContext *ctx); +const char *upnp_context_get_external_ipaddress(UpnpContext *ctx); #endif //LINPHONE_UPNP_H From a87c70e44ae50f19fdb48d9c8e666ecc2c9223bb Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Wed, 9 Jan 2013 11:56:55 +0100 Subject: [PATCH 18/47] Improve uPnP API and uPnP mechanism --- coreapi/linphonecall.c | 8 +- coreapi/linphonecore.c | 10 +- coreapi/upnp.c | 458 ++++++++++++++++++++++------------------- coreapi/upnp.h | 20 +- mediastreamer2 | 2 +- 5 files changed, 271 insertions(+), 227 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 4899fab57..11d3f43c7 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -456,7 +456,7 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr } #ifdef BUILD_UPNP if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) { - call->upnp_session = upnp_session_new(call); + call->upnp_session = linphone_upnp_session_new(call); } #endif //BUILD_UPNP call->camera_active=params->has_video; @@ -523,7 +523,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro break; case LinphonePolicyUseUpnp: #ifdef BUILD_UPNP - call->upnp_session = upnp_session_new(call); + 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) { @@ -1698,7 +1698,7 @@ void linphone_call_delete_ice_session(LinphoneCall *call){ #ifdef BUILD_UPNP void linphone_call_delete_upnp_session(LinphoneCall *call){ if(call->upnp_session!=NULL) { - upnp_session_destroy(call->upnp_session); + linphone_upnp_session_destroy(call->upnp_session); call->upnp_session=NULL; } } @@ -2016,7 +2016,7 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse } #ifdef BUILD_UPNP - upnp_call_process(call); + linphone_upnp_call_process(call); #endif //BUILD_UPNP #ifdef VIDEO_ENABLED diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 12a104e76..f02ab1868 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1218,7 +1218,7 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta if (lc->tunnel) linphone_tunnel_configure(lc->tunnel); #endif #ifdef BUILD_UPNP - lc->upnp = upnp_context_new(lc); + lc->upnp = linphone_upnp_context_new(lc); #endif //BUILD_UPNP if (lc->vtable.display_status) lc->vtable.display_status(lc,_("Ready")); @@ -1315,8 +1315,8 @@ void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result } #ifdef BUILD_UPNP else if (lc->upnp != NULL && linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp && - upnp_context_get_state(lc->upnp) == LinphoneUpnpStateOk) { - ip = upnp_context_get_external_ipaddress(lc->upnp); + linphone_upnp_context_get_state(lc->upnp) == LinphoneUpnpStateOk) { + ip = linphone_upnp_context_get_external_ipaddress(lc->upnp); strncpy(result,ip,LINPHONE_IPADDR_SIZE); return; } @@ -2279,7 +2279,7 @@ int linphone_core_proceed_with_invite_if_ready(LinphoneCore *lc, LinphoneCall *c } #ifdef BUILD_UPNP if (call->upnp_session != NULL) { - if (upnp_session_get_state(call->upnp_session) == LinphoneUpnpStateOk) upnp_ready = TRUE; + if (linphone_upnp_session_get_state(call->upnp_session) == LinphoneUpnpStateOk) upnp_ready = TRUE; } else { upnp_ready = TRUE; } @@ -4965,7 +4965,7 @@ static void linphone_core_uninit(LinphoneCore *lc) } #ifdef BUILD_UPNP - upnp_context_destroy(lc->upnp); + linphone_upnp_context_destroy(lc->upnp); lc->upnp = NULL; #endif //BUILD_UPNP diff --git a/coreapi/upnp.c b/coreapi/upnp.c index 70a03a7ae..d2a9a2423 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -48,14 +48,13 @@ LpSection *lp_config_find_section(LpConfig *lpconfig, const char *name); void lp_section_remove_item(LpSection *sec, LpItem *item); void lp_config_set_string(LpConfig *lpconfig,const char *section, const char *key, const char *value); - /* * uPnP Definitions */ typedef struct _UpnpPortBinding { ms_mutex_t mutex; - UpnpState state; + LinphoneUpnpState state; upnp_igd_ip_protocol protocol; char local_addr[LINPHONE_IPADDR_SIZE]; int local_port; @@ -63,19 +62,21 @@ typedef struct _UpnpPortBinding { int external_port; int retry; int ref; + bool_t to_remove; + bool_t to_add; } UpnpPortBinding; typedef struct _UpnpStream { UpnpPortBinding *rtp; UpnpPortBinding *rtcp; - UpnpState state; + LinphoneUpnpState state; } UpnpStream; struct _UpnpSession { LinphoneCall *call; UpnpStream *audio; UpnpStream *video; - UpnpState state; + LinphoneUpnpState state; }; struct _UpnpContext { @@ -84,36 +85,34 @@ struct _UpnpContext { UpnpPortBinding *sip_tcp; UpnpPortBinding *sip_tls; UpnpPortBinding *sip_udp; - UpnpState state; + LinphoneUpnpState state; MSList *removing_configs; MSList *adding_configs; MSList *pending_bindings; - bool_t clean; // True if at the next loop clean the port bindings - bool_t cleaning; // True if the cleaning processing; - bool_t emit; // True if at the next loop emit the port bindings - ms_mutex_t mutex; - ms_cond_t cond; + ms_cond_t empty_cond; }; bool_t linphone_core_upnp_hook(void *data); +void linphone_core_upnp_refresh(UpnpContext *ctx); -UpnpPortBinding *upnp_port_binding_new(); -UpnpPortBinding *upnp_port_binding_copy(const UpnpPortBinding *port); -bool_t upnp_port_binding_equal(const UpnpPortBinding *port1, const UpnpPortBinding *port2); -UpnpPortBinding *upnp_port_binding_retain(UpnpPortBinding *port); -void upnp_port_binding_log(int level, const char *msg, const UpnpPortBinding *port); -void upnp_port_binding_release(UpnpPortBinding *port); +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 *upnp_config_list_port_bindings(struct _LpConfig *lpc); -void upnp_config_add_port_binding(UpnpContext *lupnp, const UpnpPortBinding *port); -void upnp_config_remove_port_binding(UpnpContext *lupnp, const 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 upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortBinding *port); -int upnp_context_send_add_port_binding(UpnpContext *lupnp, 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); /** @@ -147,6 +146,7 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { const char *connection_status = NULL; bool_t nat_enabled = FALSE; ms_mutex_lock(&lupnp->mutex); + LinphoneUpnpState old_state = lupnp->state; switch(event) { case UPNP_IGD_EXTERNAL_IPADDRESS_CHANGED: @@ -164,10 +164,10 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { lupnp->state = LinphoneUpnpStateNotAvailable; } else { ms_message("uPnP IGD: Connected"); - if(lupnp->state != LinphoneUpnpStateOk) { - lupnp->clean = TRUE; // Remove saved port mapping configurations - } lupnp->state = LinphoneUpnpStateOk; + if(old_state != LinphoneUpnpStateOk) { + linphone_core_upnp_refresh(lupnp); + } } break; @@ -177,58 +177,72 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { port_mapping = (UpnpPortBinding*) mapping->cookie; port_mapping->external_port = mapping->remote_port; port_mapping->state = LinphoneUpnpStateOk; - upnp_port_binding_log(ORTP_MESSAGE, "Added port binding", port_mapping); - upnp_config_add_port_binding(lupnp, port_mapping); + linphone_upnp_port_binding_log(ORTP_MESSAGE, "Added port binding", port_mapping); + linphone_upnp_config_add_port_binding(lupnp, port_mapping); - lupnp->pending_bindings = ms_list_remove(lupnp->pending_bindings, port_mapping); - upnp_port_binding_release(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(upnp_context_send_add_port_binding(lupnp, port_mapping) != 0) { - upnp_port_binding_log(ORTP_ERROR, "Can't add port binding", port_mapping); + 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); } - lupnp->pending_bindings = ms_list_remove(lupnp->pending_bindings, port_mapping); - upnp_port_binding_release(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; - upnp_port_binding_log(ORTP_MESSAGE, "Removed port binding", port_mapping); - upnp_config_remove_port_binding(lupnp, port_mapping); + linphone_upnp_port_binding_log(ORTP_MESSAGE, "Removed port binding", port_mapping); + linphone_upnp_config_remove_port_binding(lupnp, port_mapping); - lupnp->pending_bindings = ms_list_remove(lupnp->pending_bindings, port_mapping); - upnp_port_binding_release(port_mapping); break; case UPNP_IGD_PORT_MAPPING_REMOVE_FAILURE: mapping = (upnp_igd_port_mapping *) arg; port_mapping = (UpnpPortBinding*) mapping->cookie; - if(upnp_context_send_remove_port_binding(lupnp, port_mapping) != 0) { - upnp_port_binding_log(ORTP_ERROR, "Can't remove port binding", port_mapping); - upnp_config_remove_port_binding(lupnp, port_mapping); + 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); } - lupnp->pending_bindings = ms_list_remove(lupnp->pending_bindings, port_mapping); - upnp_port_binding_release(port_mapping); break; default: break; } - if(lupnp->pending_bindings == NULL) { - if(lupnp->cleaning == TRUE) { - lupnp->emit = TRUE; // Emit port bindings - lupnp->cleaning = FALSE; + 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; + } } - pthread_cond_signal(&lupnp->cond); + 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); } @@ -238,27 +252,24 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { * uPnP Context */ -UpnpContext* upnp_context_new(LinphoneCore *lc) { +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->cond, NULL); + ms_cond_init(&lupnp->empty_cond, NULL); lupnp->lc = lc; lupnp->pending_bindings = NULL; lupnp->adding_configs = NULL; lupnp->removing_configs = NULL; - lupnp->clean = FALSE; - lupnp->cleaning = FALSE; - lupnp->emit = FALSE; 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 = upnp_port_binding_new(); + 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; @@ -266,7 +277,7 @@ UpnpContext* upnp_context_new(LinphoneCore *lc) { lupnp->sip_udp = NULL; } if(transport.tcp_port != 0) { - lupnp->sip_tcp = upnp_port_binding_new(); + 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; @@ -274,7 +285,7 @@ UpnpContext* upnp_context_new(LinphoneCore *lc) { lupnp->sip_tcp = NULL; } if(transport.tls_port != 0) { - lupnp->sip_tls = upnp_port_binding_new(); + 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; @@ -307,7 +318,7 @@ UpnpContext* upnp_context_new(LinphoneCore *lc) { return lupnp; } -void upnp_context_destroy(UpnpContext *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); @@ -315,22 +326,22 @@ void upnp_context_destroy(UpnpContext *lupnp) { /* Send port binding removes */ if(lupnp->sip_udp != NULL) { - upnp_context_send_remove_port_binding(lupnp, lupnp->sip_udp); + linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_udp); lupnp->sip_udp = NULL; } if(lupnp->sip_tcp != NULL) { - upnp_context_send_remove_port_binding(lupnp, lupnp->sip_tcp); + linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_tcp); lupnp->sip_tcp = NULL; } if(lupnp->sip_tls != NULL) { - upnp_context_send_remove_port_binding(lupnp, lupnp->sip_tls); + linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_tls); lupnp->sip_tcp = NULL; } /* Wait all pending bindings are done */ ms_message("uPnP IGD: Wait all pending port bindings ..."); ms_mutex_lock(&lupnp->mutex); - ms_cond_wait(&lupnp->cond, &lupnp->mutex); + ms_cond_wait(&lupnp->empty_cond, &lupnp->mutex); ms_mutex_unlock(&lupnp->mutex); if(lupnp->upnp_igd_ctxt != NULL) { @@ -342,57 +353,70 @@ void upnp_context_destroy(UpnpContext *lupnp) { /* Release port bindings */ if(lupnp->sip_udp != NULL) { - upnp_port_binding_release(lupnp->sip_udp); + linphone_upnp_port_binding_release(lupnp->sip_udp); lupnp->sip_udp = NULL; } if(lupnp->sip_tcp != NULL) { - upnp_port_binding_release(lupnp->sip_tcp); + linphone_upnp_port_binding_release(lupnp->sip_tcp); lupnp->sip_tcp = NULL; } if(lupnp->sip_tls != NULL) { - upnp_port_binding_release(lupnp->sip_tls); + linphone_upnp_port_binding_release(lupnp->sip_tls); lupnp->sip_tcp = NULL; } /* Release lists */ - ms_list_for_each(lupnp->adding_configs,(void (*)(void*))upnp_port_binding_release); + 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*))upnp_port_binding_release); + 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*))upnp_port_binding_release); + 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->cond); + ms_cond_destroy(&lupnp->empty_cond); ms_message("uPnP IGD: destroy %p", lupnp); ms_free(lupnp); } -UpnpState upnp_context_get_state(UpnpContext *ctx) { +LinphoneUpnpState linphone_upnp_context_get_state(UpnpContext *ctx) { return ctx->state; } -const char* upnp_context_get_external_ipaddress(UpnpContext *ctx) { +const char* linphone_upnp_context_get_external_ipaddress(UpnpContext *ctx) { return upnp_igd_get_external_ipaddress(ctx->upnp_igd_ctxt); } -int upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBinding *port) { +int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBinding *port) { upnp_igd_port_mapping mapping; char description[128]; int ret; - if(port->state == LinphoneUpnpStateIdle) { - port->retry = 0; - port->state = LinphoneUpnpStateAdding; - } else if(port->state != LinphoneUpnpStateAdding) { - ms_error("uPnP: try to add a port binding in wrong state: %d", port->state); - return -2; + + // 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 = upnp_port_binding_retain(port); + 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; @@ -410,7 +434,7 @@ int upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBinding *port mapping.protocol = port->protocol; port->retry++; - upnp_port_binding_log(ORTP_DEBUG, "Adding port binding...", port); + 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) { @@ -419,28 +443,40 @@ int upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBinding *port return ret; } -int upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortBinding *port) { +int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortBinding *port) { upnp_igd_port_mapping mapping; int ret; - if(port->state == LinphoneUpnpStateOk) { - port->retry = 0; - port->state = LinphoneUpnpStateRemoving; - } else if(port->state != LinphoneUpnpStateRemoving) { - ms_error("uPnP: try to remove a port binding in wrong state: %d", port->state); - return -2; + + // 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 = upnp_port_binding_retain(port); + 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++; - upnp_port_binding_log(ORTP_DEBUG, "Removing port binding...", port); + 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) { @@ -485,19 +521,14 @@ int linphone_core_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool if(call->upnp_session->audio->rtcp->external_port == -1) { call->upnp_session->audio->rtcp->external_port = call->audio_port+1; } - if(call->upnp_session->audio->rtp->state == LinphoneUpnpStateIdle && audio) { + if(audio) { // Add audio port binding - upnp_context_send_add_port_binding(lupnp, call->upnp_session->audio->rtp); - } else if(call->upnp_session->audio->rtp->state == LinphoneUpnpStateOk && !audio) { + 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 - upnp_context_send_remove_port_binding(lupnp, call->upnp_session->audio->rtp); - } - if(call->upnp_session->audio->rtcp->state == LinphoneUpnpStateIdle && audio) { - // Add audio port binding - upnp_context_send_add_port_binding(lupnp, call->upnp_session->audio->rtcp); - } else if(call->upnp_session->audio->rtcp->state == LinphoneUpnpStateOk && !audio) { - // Remove audio port binding - upnp_context_send_remove_port_binding(lupnp, call->upnp_session->audio->rtcp); + 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); } /* @@ -515,19 +546,14 @@ int linphone_core_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool if(call->upnp_session->video->rtcp->external_port == -1) { call->upnp_session->video->rtcp->external_port = call->video_port+1; } - if(call->upnp_session->video->rtp->state == LinphoneUpnpStateIdle && video) { + if(video) { // Add video port binding - upnp_context_send_add_port_binding(lupnp, call->upnp_session->video->rtp); - } else if(call->upnp_session->video->rtp->state == LinphoneUpnpStateOk && !video) { + 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 - upnp_context_send_remove_port_binding(lupnp, call->upnp_session->video->rtp); - } - if(call->upnp_session->video->rtcp->state == LinphoneUpnpStateIdle && video) { - // Add video port binding - upnp_context_send_add_port_binding(lupnp, call->upnp_session->video->rtcp); - } else if(call->upnp_session->video->rtcp->state == LinphoneUpnpStateOk && !video) { - // Remove video port binding - upnp_context_send_remove_port_binding(lupnp, call->upnp_session->video->rtcp); + 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); } } @@ -536,7 +562,7 @@ int linphone_core_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool /* * Update uPnP call state */ - upnp_call_process(call); + linphone_upnp_call_process(call); return ret; } @@ -564,11 +590,11 @@ int linphone_core_update_upnp(LinphoneCore *lc, LinphoneCall *call) { return linphone_core_update_upnp_audio_video(call, call->audiostream!=NULL, call->videostream!=NULL); } -int upnp_call_process(LinphoneCall *call) { +int linphone_upnp_call_process(LinphoneCall *call) { LinphoneCore *lc = call->core; UpnpContext *lupnp = lc->upnp; int ret = -1; - UpnpState oldState; + LinphoneUpnpState oldState; if(lupnp == NULL) { return ret; @@ -664,62 +690,73 @@ int upnp_call_process(LinphoneCall *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 *list = NULL; MSList *item; UpnpPortBinding *port_mapping; UpnpContext *lupnp = (UpnpContext *)data; - LinphoneCall *call; ms_mutex_lock(&lupnp->mutex); - if(lupnp->clean && !lupnp->cleaning) { - ms_message("uPnP IGD: Clean port mappings"); - lupnp->clean = FALSE; - // Remove old mapping - list = upnp_config_list_port_bindings(lupnp->lc->config); - if(list == NULL) { - lupnp->emit = TRUE; - } else { - lupnp->cleaning = TRUE; - for(item = list;item != NULL; item = item->next) { - port_mapping = (UpnpPortBinding *)item->data; - upnp_context_send_remove_port_binding(lupnp, port_mapping); - } - ms_list_for_each(list,(void (*)(void*))upnp_port_binding_release); - list = ms_list_free(list); - } - } - - if(lupnp->emit) { - ms_message("uPnP IGD: Update port mappings"); - lupnp->emit = FALSE; - - /* Force port bindings */ - if(lupnp->sip_udp != NULL) { - lupnp->sip_udp->state = LinphoneUpnpStateIdle; - upnp_context_send_add_port_binding(lupnp, lupnp->sip_udp); - } - if(lupnp->sip_tcp != NULL) { - lupnp->sip_udp->state = LinphoneUpnpStateIdle; - upnp_context_send_add_port_binding(lupnp, lupnp->sip_tcp); - } - if(lupnp->sip_tls != NULL) { - lupnp->sip_udp->state = LinphoneUpnpStateIdle; - upnp_context_send_add_port_binding(lupnp, lupnp->sip_tls); - } - list = lupnp->lc->calls; - while(list != NULL) { - call = (LinphoneCall *)list->data; - call->upnp_session->audio->rtp->state = LinphoneUpnpStateIdle; - call->upnp_session->audio->rtcp->state = LinphoneUpnpStateIdle; - call->upnp_session->video->rtp->state = LinphoneUpnpStateIdle; - call->upnp_session->video->rtcp->state = LinphoneUpnpStateIdle; - linphone_core_update_upnp_audio_video(call, call->audiostream!=NULL, call->videostream!=NULL); - list = list->next; - } - } - /* Add configs */ for(item = lupnp->adding_configs;item!=NULL;item=item->next) { port_mapping = (UpnpPortBinding *)item->data; @@ -728,9 +765,9 @@ bool_t linphone_core_upnp_hook(void *data) { port_mapping->external_port, port_mapping->local_port); lp_config_set_string(lupnp->lc->config, UPNP_SECTION_NAME, key, "uPnP"); - upnp_port_binding_log(ORTP_DEBUG, "Configuration: Added port binding", port_mapping); + linphone_upnp_port_binding_log(ORTP_DEBUG, "Configuration: Added port binding", port_mapping); } - ms_list_for_each(lupnp->adding_configs,(void (*)(void*))upnp_port_binding_release); + 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 */ @@ -741,9 +778,9 @@ bool_t linphone_core_upnp_hook(void *data) { port_mapping->external_port, port_mapping->local_port); lp_config_set_string(lupnp->lc->config, UPNP_SECTION_NAME, key, NULL); - upnp_port_binding_log(ORTP_DEBUG, "Configuration: Removed port binding", port_mapping); + linphone_upnp_port_binding_log(ORTP_DEBUG, "Configuration: Removed port binding", port_mapping); } - ms_list_for_each(lupnp->removing_configs,(void (*)(void*))upnp_port_binding_release); + 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); @@ -782,7 +819,7 @@ int linphone_core_update_local_media_description_from_upnp(SalMediaDescription * * uPnP Port Binding */ -UpnpPortBinding *upnp_port_binding_new() { +UpnpPortBinding *linphone_upnp_port_binding_new() { UpnpPortBinding *port = NULL; port = ms_new0(UpnpPortBinding,1); ms_mutex_init(&port->mutex, NULL); @@ -791,11 +828,13 @@ UpnpPortBinding *upnp_port_binding_new() { 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 *upnp_port_binding_copy(const UpnpPortBinding *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)); @@ -804,7 +843,7 @@ UpnpPortBinding *upnp_port_binding_copy(const UpnpPortBinding *port) { return new_port; } -void upnp_port_binding_log(int level, const char *msg, const UpnpPortBinding *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", @@ -819,20 +858,33 @@ void upnp_port_binding_log(int level, const char *msg, const UpnpPortBinding *po } } -bool_t upnp_port_binding_equal(const UpnpPortBinding *port1, const UpnpPortBinding *port2) { +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 *upnp_port_binding_retain(UpnpPortBinding *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 upnp_port_binding_release(UpnpPortBinding *port) { +void linphone_upnp_port_binding_release(UpnpPortBinding *port) { ms_mutex_lock(&port->mutex); if(--port->ref == 0) { ms_mutex_unlock(&port->mutex); @@ -848,20 +900,20 @@ void upnp_port_binding_release(UpnpPortBinding *port) { * uPnP Stream */ -UpnpStream* upnp_stream_new() { +UpnpStream* linphone_upnp_stream_new() { UpnpStream *stream = ms_new0(UpnpStream,1); stream->state = LinphoneUpnpStateIdle; - stream->rtp = upnp_port_binding_new(); + stream->rtp = linphone_upnp_port_binding_new(); stream->rtp->protocol = UPNP_IGD_IP_PROTOCOL_UDP; - stream->rtcp = upnp_port_binding_new(); + stream->rtcp = linphone_upnp_port_binding_new(); stream->rtcp->protocol = UPNP_IGD_IP_PROTOCOL_UDP; return stream; } -void upnp_stream_destroy(UpnpStream* stream) { - upnp_port_binding_release(stream->rtp); +void linphone_upnp_stream_destroy(UpnpStream* stream) { + linphone_upnp_port_binding_release(stream->rtp); stream->rtp = NULL; - upnp_port_binding_release(stream->rtcp); + linphone_upnp_port_binding_release(stream->rtcp); stream->rtcp = NULL; ms_free(stream); } @@ -871,40 +923,32 @@ void upnp_stream_destroy(UpnpStream* stream) { * uPnP Session */ -UpnpSession* upnp_session_new(LinphoneCall* call) { +UpnpSession* linphone_upnp_session_new(LinphoneCall* call) { UpnpSession *session = ms_new0(UpnpSession,1); session->call = call; session->state = LinphoneUpnpStateIdle; - session->audio = upnp_stream_new(); - session->video = upnp_stream_new(); + session->audio = linphone_upnp_stream_new(); + session->video = linphone_upnp_stream_new(); return session; } -void upnp_session_destroy(UpnpSession *session) { +void linphone_upnp_session_destroy(UpnpSession *session) { LinphoneCore *lc = session->call->core; if(lc->upnp != NULL) { /* Remove bindings */ - if(session->audio->rtp->state != LinphoneUpnpStateKo && session->audio->rtp->state != LinphoneUpnpStateIdle) { - upnp_context_send_remove_port_binding(lc->upnp, session->audio->rtp); - } - if(session->audio->rtcp->state != LinphoneUpnpStateKo && session->audio->rtcp->state != LinphoneUpnpStateIdle) { - upnp_context_send_remove_port_binding(lc->upnp, session->audio->rtcp); - } - if(session->video->rtp->state != LinphoneUpnpStateKo && session->video->rtp->state != LinphoneUpnpStateIdle) { - upnp_context_send_remove_port_binding(lc->upnp, session->video->rtp); - } - if(session->video->rtcp->state != LinphoneUpnpStateKo && session->video->rtcp->state != LinphoneUpnpStateIdle) { - upnp_context_send_remove_port_binding(lc->upnp, session->video->rtcp); - } + 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); } - upnp_stream_destroy(session->audio); - upnp_stream_destroy(session->video); + linphone_upnp_stream_destroy(session->audio); + linphone_upnp_stream_destroy(session->video); ms_free(session); } -UpnpState upnp_session_get_state(UpnpSession *session) { +LinphoneUpnpState linphone_upnp_session_get_state(UpnpSession *session) { return session->state; } @@ -912,7 +956,7 @@ UpnpState upnp_session_get_state(UpnpSession *session) { * uPnP Config */ -MSList *upnp_config_list_port_bindings(struct _LpConfig *lpc) { +MSList *linphone_upnp_config_list_port_bindings(struct _LpConfig *lpc) { char protocol_str[4]; // TCP or UDP upnp_igd_ip_protocol protocol; int external_port; @@ -939,7 +983,7 @@ MSList *upnp_config_list_port_bindings(struct _LpConfig *lpc) { valid = FALSE; } if(valid) { - port = upnp_port_binding_new(); + port = linphone_upnp_port_binding_new(); port->state = LinphoneUpnpStateOk; port->protocol = protocol; port->external_port = external_port; @@ -959,16 +1003,16 @@ MSList *upnp_config_list_port_bindings(struct _LpConfig *lpc) { return retList; } -void upnp_config_add_port_binding(UpnpContext *lupnp, const UpnpPortBinding *port) { +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(upnp_port_binding_equal(list_port, port) == TRUE) { + if(linphone_upnp_port_binding_equal(list_port, port) == TRUE) { lupnp->removing_configs = ms_list_remove(lupnp->removing_configs, list_port); - upnp_port_binding_release(list_port); + linphone_upnp_port_binding_release(list_port); return; } list = ms_list_next(list); @@ -977,26 +1021,26 @@ void upnp_config_add_port_binding(UpnpContext *lupnp, const UpnpPortBinding *por list = lupnp->adding_configs; while(list != NULL) { list_port = (UpnpPortBinding *)list->data; - if(upnp_port_binding_equal(list_port, port) == TRUE) { + if(linphone_upnp_port_binding_equal(list_port, port) == TRUE) { return; } list = ms_list_next(list); } - list_port = upnp_port_binding_copy(port); + list_port = linphone_upnp_port_binding_copy(port); lupnp->adding_configs = ms_list_append(lupnp->adding_configs, list_port); } -void upnp_config_remove_port_binding(UpnpContext *lupnp, const UpnpPortBinding *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(upnp_port_binding_equal(list_port, port) == TRUE) { + if(linphone_upnp_port_binding_equal(list_port, port) == TRUE) { lupnp->adding_configs = ms_list_remove(lupnp->adding_configs, list_port); - upnp_port_binding_release(list_port); + linphone_upnp_port_binding_release(list_port); return; } list = ms_list_next(list); @@ -1005,12 +1049,12 @@ void upnp_config_remove_port_binding(UpnpContext *lupnp, const UpnpPortBinding * list = lupnp->removing_configs; while(list != NULL) { list_port = (UpnpPortBinding *)list->data; - if(upnp_port_binding_equal(list_port, port) == TRUE) { + if(linphone_upnp_port_binding_equal(list_port, port) == TRUE) { return; } list = ms_list_next(list); } - list_port = upnp_port_binding_copy(port); + 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 index 64ccc88e9..a98e15574 100644 --- a/coreapi/upnp.h +++ b/coreapi/upnp.h @@ -26,13 +26,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. typedef enum { LinphoneUpnpStateIdle, - LinphoneUpnpStatePending, + LinphoneUpnpStatePending, // Only used by uPnP context LinphoneUpnpStateAdding, // Only used by port binding LinphoneUpnpStateRemoving, // Only used by port binding LinphoneUpnpStateNotAvailable, // Only used by uPnP context LinphoneUpnpStateOk, LinphoneUpnpStateKo, -} UpnpState; +} LinphoneUpnpState; typedef struct _UpnpSession UpnpSession; typedef struct _UpnpContext UpnpContext; @@ -41,14 +41,14 @@ int linphone_core_update_local_media_description_from_upnp(SalMediaDescription * int linphone_core_update_upnp_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md); int linphone_core_update_upnp(LinphoneCore *lc, LinphoneCall *call); -int upnp_call_process(LinphoneCall *call); -UpnpSession* upnp_session_new(LinphoneCall *call); -void upnp_session_destroy(UpnpSession* session); -UpnpState upnp_session_get_state(UpnpSession *session); +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 *upnp_context_new(LinphoneCore *lc); -void upnp_context_destroy(UpnpContext *ctx); -UpnpState upnp_context_get_state(UpnpContext *ctx); -const char *upnp_context_get_external_ipaddress(UpnpContext *ctx); +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); #endif //LINPHONE_UPNP_H diff --git a/mediastreamer2 b/mediastreamer2 index f9e4fed0b..07ca1256c 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit f9e4fed0b113f04895ae24a4e40f618e156b3754 +Subproject commit 07ca1256c7dc9ea15831d7f348b4104ccef162d3 From 3c00bb1195fc52fc15cefc29509b456aaf513f00 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Thu, 10 Jan 2013 11:17:35 +0100 Subject: [PATCH 19/47] Call upnp update on video remove --- coreapi/linphonecore.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index bef4a1be5..04d80612d 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2016,10 +2016,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){ @@ -2697,9 +2699,19 @@ 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; + 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); From 12d8590df4f22de4ed6478eaa144550196c8fd22 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Thu, 10 Jan 2013 11:24:09 +0100 Subject: [PATCH 20/47] Fix upnp on call update --- coreapi/linphonecore.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 04d80612d..b1b6e6c6b 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2699,6 +2699,8 @@ 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; + + // 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); @@ -2713,8 +2715,11 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho } #endif //BUILD_UPNP } + call->params = *params; linphone_call_make_local_media_description(lc, call); + + // 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. */ @@ -2861,19 +2866,22 @@ 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_from_remote_media_description(call, sal_call_get_remote_media_description(call->op))<0) { + 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 From a1645810cbca630763cf79207f32af954b49c921 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Thu, 10 Jan 2013 12:47:57 +0100 Subject: [PATCH 21/47] Add missing BUILD_UPNP preprocessor condition --- coreapi/callbacks.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 901f23f24..f166bc49f 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -261,12 +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); } From ef0eb806a760ae08b09975305092b45e8fbaa3f4 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Thu, 17 Jan 2013 18:07:59 +0100 Subject: [PATCH 22/47] Fix uPnP: Better handling of protocol --- coreapi/upnp.c | 99 ++++++++++++++++++++------------------------------ mediastreamer2 | 2 +- 2 files changed, 41 insertions(+), 60 deletions(-) diff --git a/coreapi/upnp.c b/coreapi/upnp.c index d2a9a2423..a3581c2ed 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -19,35 +19,12 @@ 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" -/* Define private types */ -typedef struct _LpItem{ - char *key; - char *value; -} LpItem; - -typedef struct _LpSection{ - char *name; - MSList *items; -} LpSection; - -typedef struct _LpConfig{ - FILE *file; - char *filename; - MSList *sections; - int modified; - int readonly; -} LpConfig; - -/* Declare private functions */ -LpSection *lp_config_find_section(LpConfig *lpconfig, const char *name); -void lp_section_remove_item(LpSection *sec, LpItem *item); -void lp_config_set_string(LpConfig *lpconfig,const char *section, const char *key, const char *value); - /* * uPnP Definitions */ @@ -145,8 +122,15 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { 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); - LinphoneUpnpState old_state = lupnp->state; + old_state = lupnp->state; switch(event) { case UPNP_IGD_EXTERNAL_IPADDRESS_CHANGED: @@ -315,6 +299,8 @@ UpnpContext* linphone_upnp_context_new(LinphoneCore *lc) { } lupnp->state = LinphoneUpnpStatePending; + upnp_igd_start(lupnp->upnp_igd_ctxt); + return lupnp; } @@ -956,51 +942,46 @@ LinphoneUpnpState linphone_upnp_session_get_state(UpnpSession *session) { * uPnP Config */ -MSList *linphone_upnp_config_list_port_bindings(struct _LpConfig *lpc) { +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; - MSList *retList = NULL; + bool_t valid = TRUE; UpnpPortBinding *port; - bool_t valid; - MSList *elem; - LpItem *item; - LpSection *sec=lp_config_find_section(lpc, UPNP_SECTION_NAME); - if(sec == NULL) - return retList; - - elem = sec->items; - while(elem != NULL) { - item=(LpItem*)elem->data; - valid = TRUE; - if(sscanf(item->key, "%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; - retList = ms_list_append(retList, 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; } - elem = ms_list_next(elem); - if(!valid) { - ms_warning("uPnP configuration invalid line: %s", item->key); - lp_section_remove_item(sec, item); + 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); + } +} - return retList; +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) { diff --git a/mediastreamer2 b/mediastreamer2 index 1cf3b8e36..710c3da85 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 1cf3b8e36d832d763220b762c6bceef0db88c04c +Subproject commit 710c3da85157d4db17bfce21e7d2b7853377fa4e From 7e06844a252e4e55355076ffecf4c434b297e13e Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 21 Jan 2013 12:41:46 +0100 Subject: [PATCH 23/47] enhance liblinphone documentation --- coreapi/linphonecore.c | 59 ++++++++++++++++++++++++++++++++++++------ coreapi/linphonecore.h | 12 ++------- 2 files changed, 53 insertions(+), 18 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 3904afc9b..1ed5ef62f 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -922,11 +922,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); @@ -934,6 +937,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(). **/ @@ -1006,14 +1011,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); @@ -1023,6 +1032,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); @@ -1032,6 +1042,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); @@ -1265,6 +1277,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) { @@ -1278,6 +1291,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) { @@ -1567,6 +1581,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) { @@ -1585,6 +1600,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) { @@ -2054,6 +2070,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 @@ -2498,6 +2516,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. **/ @@ -2528,6 +2547,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. @@ -3024,6 +3045,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 @@ -3143,6 +3167,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; @@ -3219,6 +3244,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); @@ -3692,18 +3719,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); @@ -3711,6 +3738,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); @@ -3718,6 +3747,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); @@ -4641,6 +4671,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; } @@ -4649,6 +4685,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){ diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 55198e319..3acac8fde 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1006,16 +1006,8 @@ int linphone_core_get_upload_bandwidth(const LinphoneCore *lc); void linphone_core_enable_adaptive_rate_control(LinphoneCore *lc, bool_t enabled); bool_t linphone_core_adaptive_rate_control_enabled(const LinphoneCore *lc); -/** - * set audio packetization time linphone expect to receive from peer - * @ingroup media_parameters - * - */ + void linphone_core_set_download_ptime(LinphoneCore *lc, int ptime); -/** - * get audio packetization time linphone expect to receive from peer, 0 means unspecified - * @ingroup media_parameters - */ int linphone_core_get_download_ptime(LinphoneCore *lc); void linphone_core_set_upload_ptime(LinphoneCore *lc, int ptime); @@ -1046,7 +1038,7 @@ int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadType *pt, bool_t */ #define LINPHONE_FIND_PAYLOAD_IGNORE_CHANNELS -1 /** - * Get payload type from mime type and clock rate + * Get payload type from mime type and clock rate * @ingroup media_parameters * This function searches in audio and video codecs for the given payload type name and clockrate. * @param lc #LinphoneCore object From 83ea53b5998131177ca37009f6dbb06736f39709 Mon Sep 17 00:00:00 2001 From: Guillaume Beraudo Date: Tue, 22 Jan 2013 18:10:45 +0100 Subject: [PATCH 24/47] Patch preventing chmod on /dev/null --- coreapi/lpconfig.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) 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; From 39bbe2656bec0e51b8b0c7cffd92faf38de2cd7a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 22 Jan 2013 11:39:05 +0100 Subject: [PATCH 25/47] Keep the total number of streams and the number of active streams in the media description. This is to respect section 8 of RFC 3264 ("Modifying the Session"). The number of streams in the SDP MUST NOT decrease. --- coreapi/callbacks.c | 6 ++--- coreapi/linphonecall.c | 55 ++++++++++++++++++++++++++------------- coreapi/linphonecore.c | 2 +- coreapi/misc.c | 14 +++++----- coreapi/offeranswer.c | 28 +++++++++++--------- coreapi/sal.c | 16 +++++------- coreapi/sal.h | 3 ++- coreapi/sal_eXosip2.c | 21 +++++++-------- coreapi/sal_eXosip2_sdp.c | 8 ++++-- 9 files changed, 87 insertions(+), 66 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 7985f3658..784c1f1bd 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) { @@ -591,7 +591,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)); } diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 6ef8e0c55..d918057e9 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; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 1ed5ef62f..20788eb16 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2576,7 +2576,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; diff --git a/coreapi/misc.c b/coreapi/misc.c index 53f0d65cf..b8041c433 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; 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/sal.c b/coreapi/sal.c index 2b09212aa..05d03499d 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -76,7 +76,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; } @@ -84,17 +84,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; } @@ -110,7 +106,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 */ @@ -224,9 +220,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; diff --git a/coreapi/sal.h b/coreapi/sal.h index ba6daa221..6baae97ae 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -178,7 +178,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; diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index d8332621d..1cbecb638 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -589,18 +589,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]; } } } 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; } From be6d786ba2798aed2a746b8ecda9a1c6513b3793 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Thu, 24 Jan 2013 15:59:42 +0100 Subject: [PATCH 26/47] Add upnp call stats --- coreapi/linphonecall.c | 6 +++ coreapi/linphonecore.h | 22 +++++++++ coreapi/upnp.c | 16 +++++- coreapi/upnp.h | 11 +---- gtk/call_statistics.ui | 110 ++++++++++++++++++++--------------------- gtk/incall_view.c | 34 ++++++++++++- 6 files changed, 129 insertions(+), 70 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index f4525399b..eece911b4 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -286,6 +286,7 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * #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); @@ -421,6 +422,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 } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 1003e9546..6af0bad34 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;/**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; + LinphoneUpnpState oldState, newState; if(lupnp == NULL) { return ret; @@ -644,6 +649,7 @@ int linphone_upnp_call_process(LinphoneCall *call) { } else { call->upnp_session->state = LinphoneUpnpStateIdle; } + newState = call->upnp_session->state; /* When change is done proceed update */ if(oldState != LinphoneUpnpStateOk && oldState != LinphoneUpnpStateKo && @@ -673,6 +679,14 @@ int linphone_upnp_call_process(LinphoneCall *call) { } ms_mutex_unlock(&lupnp->mutex); + + /* + * Update uPnP call stats + */ + if(oldState != newState) { + linphone_core_update_upnp_state_in_call_stats(call); + } + return ret; } diff --git a/coreapi/upnp.h b/coreapi/upnp.h index a98e15574..b3a5b9e49 100644 --- a/coreapi/upnp.h +++ b/coreapi/upnp.h @@ -24,16 +24,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "linphonecore.h" #include "sal.h" -typedef enum { - LinphoneUpnpStateIdle, - LinphoneUpnpStatePending, // Only used by uPnP context - LinphoneUpnpStateAdding, // Only used by port binding - LinphoneUpnpStateRemoving, // Only used by port binding - LinphoneUpnpStateNotAvailable, // Only used by uPnP context - LinphoneUpnpStateOk, - LinphoneUpnpStateKo, -} LinphoneUpnpState; - typedef struct _UpnpSession UpnpSession; typedef struct _UpnpContext UpnpContext; @@ -50,5 +40,6 @@ 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/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/incall_view.c b/gtk/incall_view.c index 192e92fab..8bf19c19c 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){ From 06c24da6ea4a9a38e07237c0690af3b661151d8d Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Thu, 24 Jan 2013 17:32:00 +0100 Subject: [PATCH 27/47] Update ms2 for upnp improvement --- coreapi/upnp.c | 2 +- mediastreamer2 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/upnp.c b/coreapi/upnp.c index 5684fc270..631d6545b 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -585,7 +585,7 @@ int linphone_upnp_call_process(LinphoneCall *call) { LinphoneCore *lc = call->core; UpnpContext *lupnp = lc->upnp; int ret = -1; - LinphoneUpnpState oldState, newState; + LinphoneUpnpState oldState = 0, newState = 0; if(lupnp == NULL) { return ret; diff --git a/mediastreamer2 b/mediastreamer2 index 710c3da85..b21f30429 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 710c3da85157d4db17bfce21e7d2b7853377fa4e +Subproject commit b21f304297319e15fbe0beb3509592022eb8e88a From 8fed4df37f8c49addf3607fd5d6df829da0614fd Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Thu, 24 Jan 2013 17:43:05 +0100 Subject: [PATCH 28/47] uPnP: Don't wait if there is no pending bindings --- coreapi/upnp.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/coreapi/upnp.c b/coreapi/upnp.c index 631d6545b..a05e1e0f2 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -308,8 +308,10 @@ 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); @@ -325,9 +327,10 @@ void linphone_upnp_context_destroy(UpnpContext *lupnp) { } /* Wait all pending bindings are done */ - ms_message("uPnP IGD: Wait all pending port bindings ..."); - ms_mutex_lock(&lupnp->mutex); - ms_cond_wait(&lupnp->empty_cond, &lupnp->mutex); + 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) { From 36ba86e451f2d38697cd4dbcab0b7b06c31572cf Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Fri, 25 Jan 2013 12:07:00 +0100 Subject: [PATCH 29/47] Fix previous merge --- coreapi/upnp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/upnp.c b/coreapi/upnp.c index a05e1e0f2..5ef70ba25 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -563,7 +563,7 @@ int linphone_core_update_upnp_from_remote_media_description(LinphoneCall *call, int i; const SalStreamDescription *stream; - for (i = 0; i < md->nstreams; i++) { + for (i = 0; i < md->n_total_streams; i++) { stream = &md->streams[i]; if(stream->type == SalAudio) { audio = TRUE; @@ -795,7 +795,7 @@ int linphone_core_update_local_media_description_from_upnp(SalMediaDescription * SalStreamDescription *stream; UpnpStream *upnpStream; - for (i = 0; i < desc->nstreams; i++) { + for (i = 0; i < desc->n_active_streams; i++) { stream = &desc->streams[i]; upnpStream = NULL; if(stream->type == SalAudio) { From c83e7a60068d33b79658c9f21b04f2a01d031c52 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 28 Jan 2013 12:08:05 +0100 Subject: [PATCH 30/47] Update ms2 submodule. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 2e0ef7e31..17fa1d38a 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 2e0ef7e31e919b524cfbe1ff4ffbc409fce3599c +Subproject commit 17fa1d38a456460d2ec727c14540b99ea2e9cb8f From 2ffe75737083f1a813a54d783ab5a8ccc8f606a7 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 28 Jan 2013 14:13:14 +0100 Subject: [PATCH 31/47] Fix android build. --- build/android/common.mk | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/build/android/common.mk b/build/android/common.mk index d629b54af..86475081e 100644 --- a/build/android/common.mk +++ b/build/android/common.mk @@ -44,7 +44,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 From 0a7832f19e1f875cc39deb3d7a684b754000b174 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Wed, 30 Jan 2013 09:18:52 +0100 Subject: [PATCH 32/47] Update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 17fa1d38a..97e002ca2 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 17fa1d38a456460d2ec727c14540b99ea2e9cb8f +Subproject commit 97e002ca2fd4273f7a229caf9fee2d9487814c91 From 3b722ada225c8adfcb19a0784f05288f8abfcada Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Wed, 30 Jan 2013 10:49:02 +0100 Subject: [PATCH 33/47] Add missing busy test on call failure --- coreapi/callbacks.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 948fc720b..8baad9af2 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -651,6 +651,9 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de } 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); } From e2707b8d5c4f7caf65627a9822ee8e9af3dd85cd Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 30 Jan 2013 12:05:09 +0100 Subject: [PATCH 34/47] add get_remote_contact() api and clean java API. --- coreapi/linphonecall.c | 10 +++++++ coreapi/linphonecore.h | 1 + coreapi/linphonecore_jni.cc | 12 +++++++- coreapi/sal.c | 13 +++++++- coreapi/sal.h | 7 +++-- coreapi/sal_eXosip2.c | 30 ++++++++++++++++--- .../org/linphone/core/LinphoneCall.java | 30 +++++++++---------- .../org/linphone/core/LinphoneCallImpl.java | 5 ++++ 8 files changed, 84 insertions(+), 24 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 11be247c2..3bfa7d9d4 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -898,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. diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 1f49cce46..6eb401638 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -396,6 +396,7 @@ bool_t linphone_call_camera_enabled(const LinphoneCall *lc); int linphone_call_take_video_snapshot(LinphoneCall *call, const char *file); LinphoneReason linphone_call_get_reason(const LinphoneCall *call); const char *linphone_call_get_remote_user_agent(LinphoneCall *call); +const char *linphone_call_get_remote_contact(LinphoneCall *call); float linphone_call_get_play_volume(LinphoneCall *call); float linphone_call_get_record_volume(LinphoneCall *call); float linphone_call_get_current_quality(LinphoneCall *call); diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 4144c1441..6c2135203 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -1508,7 +1508,17 @@ extern "C" jlong Java_org_linphone_core_LinphoneCallImpl_getRemoteAddress( JNIEn extern "C" jstring Java_org_linphone_core_LinphoneCallImpl_getRemoteUserAgent(JNIEnv *env, jobject thiz, jlong ptr) { LinphoneCall *call = (LinphoneCall *)ptr; - jstring jvalue = env->NewStringUTF(linphone_call_get_remote_user_agent(call)); + const char *value=linphone_call_get_remote_user_agent(call); + jstring jvalue=NULL; + if (value) jvalue=env->NewStringUTF(); + 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; } diff --git a/coreapi/sal.c b/coreapi/sal.c index 05d03499d..d91be1cb6 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -273,6 +273,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){ return ((SalOpBase*)op)->route; } @@ -304,6 +308,9 @@ void __sal_op_set_network_origin(SalOp *op, const char *origin){ assign_string(&((SalOpBase*)op)->origin,origin); } +void __sal_op_set_remote_contact(SalOp *op, const char *ct){ + assign_string(&((SalOpBase*)op)->remote_contact,ct); +} void __sal_op_free(SalOp *op){ SalOpBase *b=(SalOpBase *)op; @@ -331,12 +338,16 @@ 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) sal_media_description_unref(b->remote_media); if (b->call_id) - ms_free((void*)b->call_id); + ms_free(b->call_id); ms_free(op); } diff --git a/coreapi/sal.h b/coreapi/sal.h index 6baae97ae..b751dfc0d 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -221,7 +221,8 @@ typedef struct SalOpBase{ SalMediaDescription *local_media; SalMediaDescription *remote_media; void *user_pointer; - const char* call_id; + char* call_id; + char *remote_contact; } SalOpBase; @@ -385,6 +386,7 @@ const char *sal_op_get_to(const SalOp *op); const char *sal_op_get_contact(const SalOp *op); const char *sal_op_get_route(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); /*returns far-end "User-Agent" string */ @@ -442,7 +444,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*/ @@ -452,6 +454,7 @@ void sal_get_default_local_ip(Sal *sal, int address_family, char *ip, size_t ipl /*internal API */ 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_remote_contact(SalOp *op, const char *ct); void __sal_op_free(SalOp *b); #endif diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 1cbecb638..076f3d934 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -671,8 +671,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; @@ -1014,6 +1017,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; @@ -1051,12 +1067,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); @@ -1234,6 +1255,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){ 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/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) { From 77a03fbdb1ee31de5203aced075271ed0f9273c7 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 30 Jan 2013 12:32:19 +0100 Subject: [PATCH 35/47] fix mistake --- coreapi/linphonecore_jni.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 6c2135203..8b2d2b519 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -1510,7 +1510,7 @@ extern "C" jstring Java_org_linphone_core_LinphoneCallImpl_getRemoteUserAgent(JN LinphoneCall *call = (LinphoneCall *)ptr; const char *value=linphone_call_get_remote_user_agent(call); jstring jvalue=NULL; - if (value) jvalue=env->NewStringUTF(); + if (value) jvalue=env->NewStringUTF(value); return jvalue; } From 199133a740e39cd91df4ccb560668f31fc41df0e Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Thu, 24 Jan 2013 15:05:17 +0100 Subject: [PATCH 36/47] removed keypad --- gtk/Makefile.am | 1 + gtk/chat.c | 16 +- gtk/incall_view.c | 15 + gtk/linphone.h | 2 +- gtk/main.c | 38 ++- gtk/main.ui | 683 ++++++++++++++-------------------------------- 6 files changed, 254 insertions(+), 501 deletions(-) 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/chat.c b/gtk/chat.c index 257a55758..19bcc3429 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -194,12 +194,12 @@ void update_chat_state_message(LinphoneChatMessageState state){ default : result="Message in progress.. "; } - GDateTime *dt=g_date_time_new_now_local(); + /*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); + 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); @@ -342,8 +342,8 @@ void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, const 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"); + /*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){ @@ -365,9 +365,9 @@ 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); + /*gchar result2[80]; + sprintf(result2,"%s \n %s sent at %s",message,display,time);*/ + linphone_gtk_notify(NULL,message); 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)); diff --git a/gtk/incall_view.c b/gtk/incall_view.c index 8bf19c19c..2b115a564 100644 --- a/gtk/incall_view.c +++ b/gtk/incall_view.c @@ -361,6 +361,13 @@ void linphone_gtk_create_in_call_view(LinphoneCall *call){ g_signal_connect(G_OBJECT(transfer),"clicked",(GCallback)transfer_button_clicked,call); gtk_widget_hide(transfer); + GtkWidget *keypad = linphone_gtk_get_widget(call_view,"keypad"); + //gtk_button_set_image(GTK_BUTTON(keypad),gtk_image_new_from_stock + // (GTK_STOCK_GO_FORWARD,GTK_ICON_SIZE_BUTTON)); + + g_signal_connect_swapped(G_OBJECT(keypad),"clicked",(GCallback)linphone_gtk_create_keypad,call); + gtk_widget_hide(keypad); + GtkWidget *conf = linphone_gtk_get_widget(call_view,"conference_button"); gtk_button_set_image(GTK_BUTTON(conf),gtk_image_new_from_stock (GTK_STOCK_ADD,GTK_ICON_SIZE_BUTTON)); g_signal_connect(G_OBJECT(conf),"clicked",(GCallback)conference_button_clicked,call); @@ -673,6 +680,9 @@ 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")); + /** keypad button **/ + //gtk_widget_set_visible(linphone_gtk_get_widget(callview,"keypad"),!in_conf); + 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); @@ -745,10 +755,15 @@ void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_m gtk_widget_hide(linphone_gtk_get_widget(callview,"video_button")); gtk_widget_hide(linphone_gtk_get_widget(callview,"transfer_button")); gtk_widget_hide(linphone_gtk_get_widget(callview,"conference_button")); + gtk_widget_hide(linphone_gtk_get_widget(callview,"keypad")); linphone_gtk_enable_mute_button( GTK_BUTTON(linphone_gtk_get_widget(callview,"incall_mute")),FALSE); linphone_gtk_enable_hold_button(call,FALSE,TRUE); + GtkWidget *keypad=(GtkWidget *)g_object_get_data(G_OBJECT(callview),"keypad"); + if(keypad!=NULL) + gtk_widget_destroy(keypad); + if (taskid!=0) g_source_remove(taskid); g_timeout_add_seconds(2,(GSourceFunc)in_call_view_terminated,call); if (in_conf) diff --git a/gtk/linphone.h b/gtk/linphone.h index 367b18c26..ee584b038 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -89,6 +89,7 @@ int linphone_gtk_get_ui_config_int(const char *key, int def); void linphone_gtk_set_ui_config_int(const char *key , int val); void linphone_gtk_visibility_set(const char *hiddens, const char *window_name, GtkWidget *w, gboolean show); +void linphone_gtk_create_keypad(LinphoneCall *call); void linphone_gtk_open_browser(const char *url); void linphone_gtk_check_for_new_version(void); const char *linphone_gtk_get_lang(const char *config_file); @@ -102,7 +103,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..bc333645b 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -744,7 +744,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 +1446,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 +1460,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 +1499,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 +1514,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 +1558,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 +1570,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,7 +1647,16 @@ 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(LinphoneCall *call){ + GtkWidget *w=(GtkWidget*)linphone_call_get_user_pointer(call); + GtkWidget *keypad=linphone_gtk_create_window("keypad"); + linphone_gtk_connect_digits(keypad); + linphone_gtk_init_dtmf_table(keypad); + g_object_set_data(G_OBJECT(w),"keypad",(gpointer)keypad); + gtk_widget_show(keypad); } static void linphone_gtk_init_main_window(){ @@ -1659,11 +1668,10 @@ static void linphone_gtk_init_main_window(){ 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_init_dtmf_table(main_window); linphone_gtk_update_call_buttons (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*/ diff --git a/gtk/main.ui b/gtk/main.ui index f82875cb6..97e9b4701 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,6 +351,32 @@ False True + 1 + + + + + True + False + + + :: + True + True + True + False + bottom + + + False + False + 0 + + + + + False + False 2 @@ -640,6 +663,26 @@ False gtk-connect + + True + False + gtk-add + + + True + False + gtk-add + + + True + False + gtk-add + + + True + False + gtk-add + True False @@ -1082,453 +1125,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 +1139,28 @@ True False 2 + + + True + True + never + + + 350 + True + True + False + + + + + + + True + True + 0 + + True @@ -1571,29 +1193,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 +1384,6 @@ True True - 4 1 From 1f089fd82f19b27281639c5d04d0c3a7ef935652 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Wed, 30 Jan 2013 15:46:28 +0100 Subject: [PATCH 37/47] Add time in LinphoneChatMessage and SalMessage --- coreapi/callbacks.c | 2 +- coreapi/chat.c | 17 ++++++++---- coreapi/linphonecore.h | 9 ++++++- coreapi/private.h | 3 ++- coreapi/sal.h | 1 + coreapi/sal_eXosip2.c | 25 ++++++++++++++++- coreapi/sal_eXosip2_presence.c | 4 +++ gtk/chat.c | 49 +++++++++++++++++----------------- gtk/linphone.h | 2 +- gtk/main.c | 3 ++- gtk/main.ui | 5 +++- 11 files changed, 83 insertions(+), 37 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 8baad9af2..552d34804 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -845,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/linphonecore.h b/coreapi/linphonecore.h index 6eb401638..f780d2f65 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -735,7 +735,14 @@ void linphone_chat_message_set_external_body_url(LinphoneChatMessage* message,co * Get text part of this message * @return text or NULL if no text. */ -const char * linphone_chat_message_get_text(const LinphoneChatMessage* message); +const char * linphone_chat_message_get_text(const LinphoneChatMessage* message); + +/** + * Get the time the message was sent + * @return time_t or NULL if no time + */ +time_t linphone_chat_message_get_time(const LinphoneChatMessage* message); + /** * user pointer get function */ diff --git a/coreapi/private.h b/coreapi/private.h index c421b2bc6..ca79a722f 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -103,6 +103,7 @@ struct _LinphoneChatMessage { void* message_userdata; char* external_body_url; LinphoneAddress* from; + time_t time; }; typedef struct StunCandidate{ @@ -279,7 +280,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); diff --git a/coreapi/sal.h b/coreapi/sal.h index b751dfc0d..46294b603 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -195,6 +195,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 diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 076f3d934..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; @@ -1766,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; @@ -1775,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) { @@ -1815,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..870d9670e 100644 --- a/coreapi/sal_eXosip2_presence.c +++ b/coreapi/sal_eXosip2_presence.c @@ -83,6 +83,9 @@ void sal_remove_in_subscribe(Sal *sal, SalOp *op){ 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 +100,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,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/gtk/chat.c b/gtk/chat.c index 19bcc3429..3eea9255c 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,19 @@ 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); + list=g_list_append(list,GINT_TO_POINTER(gtk_text_iter_get_line(&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 { + gtk_text_buffer_insert_with_tags_by_name(buffer,&iter,ctime(&t),-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); GtkTextMark *mark=gtk_text_buffer_create_mark(buffer,NULL,&iter,FALSE); gtk_text_view_scroll_mark_onscreen(text,mark); @@ -193,11 +198,6 @@ 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,result,-1, "italic","right","small","font_grey",NULL); @@ -221,10 +221,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 +338,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 +365,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,message); + 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/linphone.h b/gtk/linphone.h index ee584b038..55b30c829 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); diff --git a/gtk/main.c b/gtk/main.c index bc333645b..a2461269c 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; diff --git a/gtk/main.ui b/gtk/main.ui index 97e9b4701..76e96e808 100644 --- a/gtk/main.ui +++ b/gtk/main.ui @@ -959,6 +959,7 @@ True True + 2 0 @@ -987,6 +988,7 @@ False True + 6 2 @@ -1116,7 +1118,7 @@ False False - 12 + 6 0 @@ -1384,6 +1386,7 @@ True True + 6 1 From c7946c6225741cbda9ecd919e8f5d555e376bd47 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Wed, 30 Jan 2013 17:14:14 +0100 Subject: [PATCH 38/47] Keypad in another frame --- gtk/chat.c | 5 +- gtk/incall_view.c | 15 --- gtk/keypad.ui | 277 ++++++++++++++++++++++++++++++++++++++++++++++ gtk/linphone.h | 1 - gtk/main.c | 13 ++- gtk/main.ui | 58 +++++----- 6 files changed, 318 insertions(+), 51 deletions(-) create mode 100644 gtk/keypad.ui diff --git a/gtk/chat.c b/gtk/chat.c index 3eea9255c..5eaf79e93 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -137,7 +137,10 @@ void linphone_gtk_push_text(GtkWidget *w, const LinphoneAddress *from, gtk_text_buffer_insert_with_tags_by_name(buffer,&iter,"Message in progress.. ",-1, "italic","right","small","font_grey",NULL); } else { - gtk_text_buffer_insert_with_tags_by_name(buffer,&iter,ctime(&t),-1, + 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); diff --git a/gtk/incall_view.c b/gtk/incall_view.c index 2b115a564..65446d696 100644 --- a/gtk/incall_view.c +++ b/gtk/incall_view.c @@ -361,13 +361,6 @@ void linphone_gtk_create_in_call_view(LinphoneCall *call){ g_signal_connect(G_OBJECT(transfer),"clicked",(GCallback)transfer_button_clicked,call); gtk_widget_hide(transfer); - GtkWidget *keypad = linphone_gtk_get_widget(call_view,"keypad"); - //gtk_button_set_image(GTK_BUTTON(keypad),gtk_image_new_from_stock - // (GTK_STOCK_GO_FORWARD,GTK_ICON_SIZE_BUTTON)); - - g_signal_connect_swapped(G_OBJECT(keypad),"clicked",(GCallback)linphone_gtk_create_keypad,call); - gtk_widget_hide(keypad); - GtkWidget *conf = linphone_gtk_get_widget(call_view,"conference_button"); gtk_button_set_image(GTK_BUTTON(conf),gtk_image_new_from_stock (GTK_STOCK_ADD,GTK_ICON_SIZE_BUTTON)); g_signal_connect(G_OBJECT(conf),"clicked",(GCallback)conference_button_clicked,call); @@ -679,9 +672,6 @@ 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")); - - /** keypad button **/ - //gtk_widget_set_visible(linphone_gtk_get_widget(callview,"keypad"),!in_conf); 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); @@ -755,15 +745,10 @@ void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_m gtk_widget_hide(linphone_gtk_get_widget(callview,"video_button")); gtk_widget_hide(linphone_gtk_get_widget(callview,"transfer_button")); gtk_widget_hide(linphone_gtk_get_widget(callview,"conference_button")); - gtk_widget_hide(linphone_gtk_get_widget(callview,"keypad")); linphone_gtk_enable_mute_button( GTK_BUTTON(linphone_gtk_get_widget(callview,"incall_mute")),FALSE); linphone_gtk_enable_hold_button(call,FALSE,TRUE); - GtkWidget *keypad=(GtkWidget *)g_object_get_data(G_OBJECT(callview),"keypad"); - if(keypad!=NULL) - gtk_widget_destroy(keypad); - if (taskid!=0) g_source_remove(taskid); g_timeout_add_seconds(2,(GSourceFunc)in_call_view_terminated,call); if (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 55b30c829..abb395127 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -89,7 +89,6 @@ int linphone_gtk_get_ui_config_int(const char *key, int def); void linphone_gtk_set_ui_config_int(const char *key , int val); void linphone_gtk_visibility_set(const char *hiddens, const char *window_name, GtkWidget *w, gboolean show); -void linphone_gtk_create_keypad(LinphoneCall *call); void linphone_gtk_open_browser(const char *url); void linphone_gtk_check_for_new_version(void); const char *linphone_gtk_get_lang(const char *config_file); diff --git a/gtk/main.c b/gtk/main.c index a2461269c..165a70689 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -1651,18 +1651,21 @@ void linphone_gtk_init_dtmf_table(GtkWidget *mw){ } -void linphone_gtk_create_keypad(LinphoneCall *call){ - GtkWidget *w=(GtkWidget*)linphone_call_get_user_pointer(call); +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(w),"keypad",(gpointer)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(); @@ -1672,8 +1675,8 @@ static void linphone_gtk_init_main_window(){ 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 76e96e808..50883c3f0 100644 --- a/gtk/main.ui +++ b/gtk/main.ui @@ -354,32 +354,6 @@ 1 - - - True - False - - - :: - True - True - True - False - bottom - - - False - False - 0 - - - - - False - False - 2 - - False @@ -442,7 +416,7 @@ False False - 3 + 2 @@ -483,7 +457,7 @@ False False - 4 + 3 @@ -579,7 +553,7 @@ False False 7 - 5 + 4 @@ -683,6 +657,16 @@ False gtk-add + + True + False + gtk-missing-image + + + True + False + gtk-select-color + True False @@ -1107,6 +1091,22 @@ 2 + + + True + True + True + False + image18 + + + + False + False + end + 3 + + False From ea5e02935e7328dd8073ff9e07c5de3c21b2e807 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Thu, 31 Jan 2013 10:18:13 +0100 Subject: [PATCH 39/47] correction notification message --- gtk/chat.c | 6 +++--- gtk/main.c | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/gtk/chat.c b/gtk/chat.c index 5eaf79e93..2b3a969ed 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -132,10 +132,11 @@ void linphone_gtk_push_text(GtkWidget *w, const LinphoneAddress *from, gtk_text_buffer_get_end_iter(buffer,&iter); - list=g_list_append(list,GINT_TO_POINTER(gtk_text_iter_get_line(&iter))); if(me){ + 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); + g_object_set_data(G_OBJECT(w),"list",list); } else { struct tm *tm=localtime(&t); char buf[80]; @@ -145,7 +146,7 @@ void linphone_gtk_push_text(GtkWidget *w, const LinphoneAddress *from, } 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); + GtkTextMark *mark=gtk_text_buffer_create_mark(buffer,NULL,&iter,FALSE); gtk_text_view_scroll_mark_onscreen(text,mark); @@ -201,7 +202,6 @@ void update_chat_state_message(LinphoneChatMessageState state){ break; default : result="Message in progress.. "; } - 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)); diff --git a/gtk/main.c b/gtk/main.c index 165a70689..114a7244f 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -1650,7 +1650,6 @@ void linphone_gtk_init_dtmf_table(GtkWidget *mw){ 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"); From a3f4d58da17ea31e6d9bd3939895340735c90f96 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 31 Jan 2013 11:54:25 +0100 Subject: [PATCH 40/47] Fix name of adaptive jitter buffer compensation configuration. --- coreapi/linphonecore.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index c6a2857fc..673131218 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -4962,8 +4962,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) From 66b5069dffeca8159f840f67fabae16ff8ec0fec Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Thu, 31 Jan 2013 16:31:54 +0100 Subject: [PATCH 41/47] Clean configure.ac --- configure.ac | 595 ++++++++++++++++++++++++++----------------------- mediastreamer2 | 2 +- oRTP | 2 +- 3 files changed, 321 insertions(+), 278 deletions(-) diff --git a/configure.ac b/configure.ac index 3526920fc..1372c5af3 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,49 +140,56 @@ 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]) + [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 + 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] + ) fi @@ -190,29 +201,30 @@ 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) @@ -225,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 @@ -260,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]) @@ -299,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 @@ -313,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 @@ -344,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} @@ -395,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) @@ -411,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, @@ -442,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 @@ -468,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) @@ -513,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) @@ -562,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 " @@ -579,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) @@ -608,31 +653,25 @@ 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 - - - - - - - - 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 @@ -645,19 +684,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]) @@ -670,7 +711,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(<<, >>) @@ -683,12 +724,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) @@ -702,43 +745,43 @@ 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 -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 + 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/mediastreamer2 b/mediastreamer2 index 97e002ca2..e5d529906 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 97e002ca2fd4273f7a229caf9fee2d9487814c91 +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 From 740a74d12fe901ca5a11c4491e9b250eaa71904f Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 1 Feb 2013 09:06:22 +0100 Subject: [PATCH 42/47] add keypad.ui to potfiles.in --- po/POTFILES.in | 1 + 1 file changed, 1 insertion(+) 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 From ad800f9976d64e78d58da7f1dc903612f774cf68 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 1 Feb 2013 09:32:59 +0100 Subject: [PATCH 43/47] fix compilation for windows --- coreapi/sal_eXosip2_presence.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/coreapi/sal_eXosip2_presence.c b/coreapi/sal_eXosip2_presence.c index 870d9670e..ddd246a79 100644 --- a/coreapi/sal_eXosip2_presence.c +++ b/coreapi/sal_eXosip2_presence.c @@ -81,6 +81,17 @@ 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_r(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; @@ -100,7 +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,ctime_r(&t,buf)); + 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); From f65e26aa186167ac6ec051b61e86dffd3d93055e Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 1 Feb 2013 09:34:26 +0100 Subject: [PATCH 44/47] fix previous commit --- coreapi/sal_eXosip2_presence.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/sal_eXosip2_presence.c b/coreapi/sal_eXosip2_presence.c index ddd246a79..8156c3839 100644 --- a/coreapi/sal_eXosip2_presence.c +++ b/coreapi/sal_eXosip2_presence.c @@ -84,7 +84,7 @@ void sal_remove_in_subscribe(Sal *sal, SalOp *op){ #ifdef WIN32 static inline char *my_ctime_r(const time_t *t, char *buf){ - strcpy(buf,ctime_r(t)); + strcpy(buf,ctime(t)); return buf; } From bf0953eb1d3c83471c6950eea505bea4e67f93e6 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Tue, 5 Feb 2013 10:02:32 +0100 Subject: [PATCH 45/47] Add check in lpc2xml Add jni for lpc2xml and xml2lpc Add some jni for LPConfigImpl --- build/android/Android.mk | 9 +- build/android/lpc2xml.mk | 47 ++++++ build/android/xml2lpc.mk | 47 ++++++ coreapi/linphonecore_jni.cc | 12 ++ .../linphone/core/LinphoneCoreFactory.java | 1 + .../core/LinphoneCoreFactoryImpl.java | 5 + java/impl/org/linphone/core/LpConfigImpl.java | 9 ++ java/impl/org/linphone/tools/Lpc2Xml.java | 68 ++++++++ java/impl/org/linphone/tools/Xml2Lpc.java | 72 +++++++++ tools/Makefile.am | 2 + tools/lpc2xml.c | 85 ++++++++-- tools/lpc2xml_jni.cc | 123 +++++++++++++++ tools/my_jni.h | 108 +++++++++++++ tools/xml2lpc_jni.cc | 149 ++++++++++++++++++ 14 files changed, 719 insertions(+), 18 deletions(-) create mode 100644 build/android/lpc2xml.mk create mode 100644 build/android/xml2lpc.mk create mode 100644 java/impl/org/linphone/tools/Lpc2Xml.java create mode 100644 java/impl/org/linphone/tools/Xml2Lpc.java create mode 100644 tools/lpc2xml_jni.cc create mode 100644 tools/my_jni.h create mode 100644 tools/xml2lpc_jni.cc 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/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/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 8b2d2b519..9629688c7 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2239,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/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/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/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..97262861c 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,6 +72,24 @@ 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) { @@ -195,36 +213,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_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; +} From ab1c855d650e9706b3320518c6b9df41c6ec3627 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Wed, 6 Feb 2013 09:57:43 +0100 Subject: [PATCH 46/47] tools: comment unused function in lpc2xml --- tools/lpc2xml.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/lpc2xml.c b/tools/lpc2xml.c index 97262861c..9ff7f39d2 100644 --- a/tools/lpc2xml.c +++ b/tools/lpc2xml.c @@ -81,6 +81,7 @@ static void lpc2xml_genericxml_error(void *ctx, const char *fmt, ...) { va_end(args); } +/* static void lpc2xml_genericxml_warning(void *ctx, const char *fmt, ...) { lpc2xml_context *xmlCtx = (lpc2xml_context *)ctx; int sl = strlen(xmlCtx->warningBuffer); @@ -89,6 +90,7 @@ static void lpc2xml_genericxml_warning(void *ctx, const char *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); From 2023347961b8afede8db9334c9f37b5d7ea6dddf Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Wed, 6 Feb 2013 10:22:01 +0100 Subject: [PATCH 47/47] Improve tools --- tools/lpc2xml.c | 3 +++ tools/xml2lpc.c | 15 ++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/tools/lpc2xml.c b/tools/lpc2xml.c index 9ff7f39d2..39fd62b0e 100644 --- a/tools/lpc2xml.c +++ b/tools/lpc2xml.c @@ -98,6 +98,8 @@ static int processEntry(const char *section, const char *entry, xmlNode *node, l 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; } @@ -123,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); } } 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); }