]> sjero.net Git - linphone/commitdiff
uPnP in progress
authorYann Diorcet <yann.diorcet@belledonne-communications.com>
Fri, 21 Dec 2012 15:21:41 +0000 (16:21 +0100)
committerYann Diorcet <yann.diorcet@belledonne-communications.com>
Fri, 21 Dec 2012 15:21:41 +0000 (16:21 +0100)
console/commands.c
coreapi/linphonecall.c
coreapi/linphonecore.c
coreapi/private.h
coreapi/upnp.c
coreapi/upnp.h
gtk/parameters.ui
gtk/propertybox.c
mediastreamer2

index 472531795efa2d9655afdcc0412226533586d9ee..3ec2ed65b2a09266e6f716d50f0f79e3ae4b0498 100644 (file)
@@ -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;
 }
index 6c8b4a74395ca074fc75916690addb192ef44a4c..8af948df5f4f07399258e696a7b91e60185d9426 100644 (file)
@@ -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;
index 8619552faf4698c948a746ca7b791d47a698e3ef..82e39685f0290b34e950f0cf1cdc33c5e3ac671f 100644 (file)
@@ -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;
 }
index 6af7e09eead520585b45099e1b0ca8b01eb3ac60..d4abf16ca2eed60eff517aeeb750fe9242b56ce7 100644 (file)
@@ -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);
index 34622bf51eba4f26bb288b5ef5de037177958c15..d0b71b3e41ae3523ae7a55716efd926e05f80b2c 100644 (file)
@@ -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);
+}
index c5ff5eca0f37b755d2c50c9efa37194716c27e4a..f0a93d1d6e1ef1717e252406bc9563796ccfa7fd 100644 (file)
@@ -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);
 
index d6d2e4927c7a6ecc2cc35f543949334b71184f87..3af59e11e5e512d2dad53d41ce6ce10dbc9dcf9c 100644 (file)
                             <property name="position">3</property>
                           </packing>
                         </child>
+                        <child>
+                          <object class="GtkRadioButton" id="use_upnp">
+                            <property name="label" translatable="yes">Behind NAT / Firewall (use uPnP)</property>
+                            <property name="use_action_appearance">False</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="draw_indicator">True</property>
+                            <property name="group">no_nat</property>
+                            <signal name="toggled" handler="linphone_gtk_use_upnp_toggled" swapped="no"/>
+                          </object>
+                          <packing>
+                            <property name="expand">True</property>
+                            <property name="fill">True</property>
+                            <property name="position">4</property>
+                          </packing>
+                        </child>
                         <child>
                           <object class="GtkHBox" id="hbox24">
                             <property name="visible">True</property>
index 03092a0a5a732e8f3e61bdcf8f2365fbdf3e2913..a26d744e55da6094629e43888c54060e17f05ecc 100644 (file)
@@ -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){
index a1f113529f506aa178765cf70773db80e5768139..39998cb245606b904a77e093db168057f87bf8b0 160000 (submodule)
@@ -1 +1 @@
-Subproject commit a1f113529f506aa178765cf70773db80e5768139
+Subproject commit 39998cb245606b904a77e093db168057f87bf8b0