]> sjero.net Git - linphone/commitdiff
Working call with uPnP
authorYann Diorcet <yann.diorcet@belledonne-communications.com>
Fri, 4 Jan 2013 15:19:13 +0000 (16:19 +0100)
committerYann Diorcet <yann.diorcet@belledonne-communications.com>
Fri, 4 Jan 2013 15:19:13 +0000 (16:19 +0100)
coreapi/callbacks.c
coreapi/linphonecall.c
coreapi/linphonecore.c
coreapi/misc.c
coreapi/private.h
coreapi/proxy.c
coreapi/upnp.c
coreapi/upnp.h

index b3d1a6bb7d2a0824e913f476c6378a4d0455aa83..4eec5be3d1d30df77e3dcd40b66cda37d6df3c6c 100644 (file)
@@ -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");
 }
 
index 2ab398ba56ddb654179faabf43ddca5a14333e28..ec76311a6c4fcab9f1816b40d5a16c33e48b7d2e 100644 (file)
@@ -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);
                        }
index ddd9eaea6f02bdc5efd3b09d60a50826cbf951cc..7abce8e9612dbad29ad1df3b6d9d3b4b59fceb0f 100644 (file)
@@ -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){
index d7572213825b45c809c241e711b42649a6ca3c53..6e49d56a54a90f1318cbc860577ffa192a3a0a92 100644 (file)
@@ -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
index e110a03e3d9f2818ec0a4f11fbb4a6f5fabfde22..d4abf16ca2eed60eff517aeeb750fe9242b56ce7 100644 (file)
@@ -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);
index ff046f92edb8a4fc1dffb08d1976f92c300d9730..82b3b30006c9c81c1ec6f2ee262528e37d9885c5 100644 (file)
@@ -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));
index 0de861210cc53c237776cd620243bd64f65defa5..4cb41d7ae09d2f1c4f1f0533f8ee3d1157f7529f 100644 (file)
@@ -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,34 +342,20 @@ 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);
                }
-               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
@@ -393,20 +366,82 @@ int upnp_call_process(LinphoneCall *call) {
                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) {
+               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 && call->videostream == NULL) {
+               } 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 && call->videostream != NULL) {
+               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 && call->videostream == NULL) {
+               } 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;
+               } else if(call->upnp_session->audio->rtp->state == LinphoneUpnpStateAdding ||
+                               call->upnp_session->audio->rtp->state == LinphoneUpnpStateRemoving ||
+                               call->upnp_session->audio->rtcp->state == LinphoneUpnpStateAdding ||
+                               call->upnp_session->audio->rtcp->state == LinphoneUpnpStateRemoving) {
+                       call->upnp_session->audio->state = LinphoneUpnpStatePending;
+               } else if(call->upnp_session->audio->rtcp->state == LinphoneUpnpStateKo ||
+                               call->upnp_session->audio->rtp->state == LinphoneUpnpStateKo) {
+                       call->upnp_session->audio->state = LinphoneUpnpStateKo;
+               } else {
+                       call->upnp_session->audio->state = LinphoneUpnpStateIdle;
+               }
+
+               /*
+                * Update Video state
+                */
                if((call->upnp_session->video->rtp->state == LinphoneUpnpStateOk || call->upnp_session->video->rtp->state == LinphoneUpnpStateIdle) &&
                                (call->upnp_session->video->rtcp->state == LinphoneUpnpStateOk || call->upnp_session->video->rtcp->state == LinphoneUpnpStateIdle)) {
                        call->upnp_session->video->state = LinphoneUpnpStateOk;
@@ -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;
index 492b35234b26ca88ad0691c82ee909d6a4a5f87b..b515d041087d56a3018d4a5ecd5276b900507a06 100644 (file)
@@ -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();