From: Yann Diorcet Date: Fri, 21 Dec 2012 15:21:41 +0000 (+0100) Subject: uPnP in progress X-Git-Url: http://sjero.net/git/?p=linphone;a=commitdiff_plain;h=806203ca0a5ba0cf0df7f31b2f8ee51544bcd0fa uPnP in progress --- diff --git a/console/commands.c b/console/commands.c index 47253179..3ec2ed65 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 6c8b4a74..8af948df 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 8619552f..82e39685 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,8 +2476,20 @@ 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){ @@ -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 6af7e09e..d4abf16c 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 34622bf5..d0b71b3e 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 c5ff5eca..f0a93d1d 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 d6d2e492..3af59e11 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 03092a0a..a26d744e 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 a1f11352..39998cb2 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit a1f113529f506aa178765cf70773db80e5768139 +Subproject commit 39998cb245606b904a77e093db168057f87bf8b0