]> sjero.net Git - linphone/commitdiff
Asynchronous ICE candidates gathering.
authorGhislain MARY <ghislain.mary@belledonne-communications.com>
Tue, 31 Jul 2012 07:05:47 +0000 (09:05 +0200)
committerGhislain MARY <ghislain.mary@belledonne-communications.com>
Tue, 31 Jul 2012 10:12:06 +0000 (12:12 +0200)
coreapi/linphonecall.c
coreapi/linphonecore.c
coreapi/misc.c
coreapi/private.h

index 7c9ef7bf62d288d2dc26521e9b88a17375fd5133..75518a143e18030d4dc5871326fa8d8c585578c8 100644 (file)
@@ -350,15 +350,8 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr
        }
        call->localdesc=create_local_media_description (lc,call);
        call->camera_active=params->has_video;
-       switch (linphone_core_get_firewall_policy(call->core)) {
-               case LinphonePolicyUseStun:
-                       linphone_core_run_stun_tests(call->core,call);
-                       break;
-               case LinphonePolicyUseIce:
-                       linphone_core_gather_ice_candidates(call->core,call);
-                       break;
-               default:
-                       break;
+       if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseStun) {
+               linphone_core_run_stun_tests(call->core,call);
        }
        discover_mtu(lc,linphone_address_get_domain (to));
        if (params->referer){
@@ -971,6 +964,7 @@ void linphone_call_init_media_streams(LinphoneCall *call){
        if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (ice_session != NULL)){
                rtp_session_set_pktinfo(audiostream->session, TRUE);
                audiostream->ice_check_list = ice_session_check_list(ice_session, 0);
+               ice_check_list_set_rtp_session(audiostream->ice_check_list, audiostream->session);
        }
 
        call->audiostream_app_evq = ortp_ev_queue_new();
@@ -995,6 +989,7 @@ void linphone_call_init_media_streams(LinphoneCall *call){
                if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (ice_session != NULL)){
                        rtp_session_set_pktinfo(call->videostream->session, TRUE);
                        call->videostream->ice_check_list = ice_session_check_list(ice_session, 1);
+                       ice_check_list_set_rtp_session(call->videostream->ice_check_list, call->videostream->session);
                }
                call->videostream_app_evq = ortp_ev_queue_new();
                rtp_session_register_event_queue(call->videostream->session,call->videostream_app_evq);
@@ -1457,6 +1452,13 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut
                linphone_address_destroy(me);
 }
 
+void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call){
+       audio_stream_start_ice_gathering(call->audiostream);
+       if (call->videostream) {
+               video_stream_start_ice_gathering(call->videostream);
+       }
+}
+
 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);
@@ -1719,6 +1721,15 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse
                                        if (ice_session_role(sal_op_get_ice_session(call->op)) == IR_Controlling) {
                                                linphone_core_update_call(lc, call, &call->current_params);
                                        }
+                               } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) {
+                                       if (call->state==LinphoneCallOutgoingInit) {
+                                               linphone_call_stop_media_streams(call);
+                                               if (evd->info.ice_processing_successful==FALSE) {
+                                                       ice_session_destroy(sal_op_get_ice_session(call->op));
+                                                       sal_op_set_ice_session(call->op, NULL);
+                                               }
+                                               linphone_core_start_invite(call->core,call,NULL);
+                                       }
                                }
                                ortp_event_destroy(ev);
                        }
@@ -1759,6 +1770,15 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse
                                        if (ice_session_role(sal_op_get_ice_session(call->op)) == IR_Controlling) {
                                                linphone_core_update_call(lc, call, &call->current_params);
                                        }
+                               } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) {
+                                       if (call->state==LinphoneCallOutgoingInit) {
+                                               linphone_call_stop_media_streams(call);
+                                               if (evd->info.ice_processing_successful==FALSE) {
+                                                       ice_session_destroy(sal_op_get_ice_session(call->op));
+                                                       sal_op_set_ice_session(call->op, NULL);
+                                               }
+                                               linphone_core_start_invite(call->core,call,NULL);
+                                       }
                                }
                                ortp_event_destroy(ev);
                        }
index 40b2a647d933056c869c57f702ba1fe042879f64..060259a4829680066804813c1a4f7b4ef0ff35c0 100644 (file)
@@ -1852,6 +1852,12 @@ void linphone_core_iterate(LinphoneCore *lc){
                linphone_call_background_tasks(call,one_second_elapsed);
                if (call->state==LinphoneCallOutgoingInit && (curtime-call->start_time>=2)){
                        /*start the call even if the OPTIONS reply did not arrive*/
+                       if (sal_op_get_ice_session(call->op) != NULL) {
+                               /* ICE candidates gathering has not finished yet, proceed with the call without ICE anyway. */
+                               ice_session_destroy(sal_op_get_ice_session(call->op));
+                               sal_op_set_ice_session(call->op, NULL);
+                               linphone_call_stop_media_streams(call);
+                       }
                        linphone_core_start_invite(lc,call,NULL);
                }
                if (call->state==LinphoneCallIncomingReceived){
@@ -2281,6 +2287,21 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const
        /* this call becomes now the current one*/
        lc->current_call=call;
        linphone_call_set_state (call,LinphoneCallOutgoingInit,"Starting outgoing call");
+       if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) {
+               /* Defer the start of the call after the ICE gathering process. */
+               linphone_call_init_media_streams(call);
+               linphone_call_start_media_streams_for_ice_gathering(call);
+               call->start_time=time(NULL);
+               if (linphone_core_gather_ice_candidates(lc,call)<0) {
+                       /* Ice candidates gathering failed, proceed with the call anyway. */
+                       ice_session_destroy(sal_op_get_ice_session(call->op));
+                       sal_op_set_ice_session(call->op, NULL);
+                       linphone_call_stop_media_streams(call);
+               } else {
+                       if (real_url!=NULL) ms_free(real_url);
+                       return call;
+               }
+       }
        if (dest_proxy!=NULL || lc->sip_conf.ping_with_options==FALSE){
                linphone_core_start_invite(lc,call,dest_proxy);
        }else{
index 51f217c70676b0178e432baac05293e26ad09bab..0e4be8e111c94cfeac0a33a245010afe3b28a365 100644 (file)
@@ -562,156 +562,48 @@ void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
        }
 }
 
-void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call)
+int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call)
 {
-       typedef struct _st_gathering {
-               ortp_socket_t sock;
-               bool_t response;
-               IceCandidate *base;
-               struct timeval transmission_time;
-       } gathering_t;
-
        char local_addr[64];
-       char addr[64];
-       int port;
-       int id;
-       gathering_t audio_gatherings[2];
-       gathering_t video_gatherings[2];
+       struct sockaddr_storage ss;
+       socklen_t ss_len;
        IceCheckList *audio_check_list;
        IceCheckList *video_check_list;
        IceSession *ice_session = sal_op_get_ice_session(call->op);
-       struct sockaddr_storage ss;
-       socklen_t ss_len;
-       struct timeval init, cur, diff;
-       double elapsed;
-       int loops = 0;
        const char *server = linphone_core_get_stun_server(lc);
 
-       if ((server == NULL) || (ice_session == NULL)) return;
+       if ((server == NULL) || (ice_session == NULL)) return -1;
        audio_check_list = ice_session_check_list(ice_session, 0);
        video_check_list = ice_session_check_list(ice_session, 1);
-       if (audio_check_list == NULL) return;
+       if (audio_check_list == NULL) return -1;
 
        if (lc->sip_conf.ipv6_enabled){
                ms_warning("stun support is not implemented for ipv6");
-               return;
+               return -1;
        }
 
        if (parse_hostname_to_addr(server, &ss, &ss_len) < 0) {
                ms_error("Fail to parser stun server address: %s", server);
-               return;
+               return -1;
        }
        if (lc->vtable.display_status != NULL)
                lc->vtable.display_status(lc, _("ICE local candidates gathering in progress..."));
 
-       audio_gatherings[0].response = audio_gatherings[1].response = FALSE;
-       video_gatherings[0].response = video_gatherings[1].response = FALSE;
-       audio_gatherings[0].base = audio_gatherings[1].base = NULL;
-       video_gatherings[0].base = video_gatherings[1].base = NULL;
-       audio_gatherings[0].sock = create_socket(call->audio_port);
-       if (audio_gatherings[0].sock == -1) return;
-       audio_gatherings[1].sock = create_socket(call->audio_port + 1);
-       if (audio_gatherings[1].sock == -1) return;
-       if (call->params.has_video) {
-               video_gatherings[0].sock = create_socket(call->video_port);
-               if (video_gatherings[0].sock == -1) return;
-               video_gatherings[1].sock = create_socket(call->video_port + 1);
-               if (video_gatherings[1].sock == -1) return;
-       } else {
-               video_gatherings[0].sock = video_gatherings[1].sock = -1;
-       }
+       /* Gather local host candidates. */
        if (linphone_core_get_local_ip_for(AF_INET, NULL, local_addr) < 0) {
                ms_error("Fail to get local ip");
-               return;
+               return -1;
        }
-       audio_gatherings[0].base = ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port, 1, NULL);
-       audio_gatherings[1].base = ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port + 1, 2, NULL);
-       if (call->params.has_video && (video_check_list != NULL)) {
-               video_gatherings[0].base = ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port, 1, NULL);
-               video_gatherings[1].base = ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port + 1, 2, NULL);
-       }
-
-       gettimeofday(&init, NULL);
-       audio_gatherings[0].transmission_time = cur = init;
-       diff.tv_sec = 0, diff.tv_usec = 20000;
-       timeradd(&audio_gatherings[0].transmission_time, &diff, &audio_gatherings[1].transmission_time);
-       timeradd(&audio_gatherings[1].transmission_time, &diff, &video_gatherings[0].transmission_time);
-       timeradd(&video_gatherings[0].transmission_time, &diff, &video_gatherings[1].transmission_time);
-       diff.tv_sec = 0, diff.tv_usec = 100000;
-       do {
-               if ((audio_gatherings[0].response == FALSE) && timercmp(&cur, &audio_gatherings[0].transmission_time, >=)) {
-                       timeradd(&audio_gatherings[0].transmission_time, &diff, &audio_gatherings[0].transmission_time);
-                       sendStunRequest(audio_gatherings[0].sock, (struct sockaddr*)&ss, ss_len, 1, FALSE);
-               }
-               if ((audio_gatherings[1].response == FALSE) && timercmp(&cur, &audio_gatherings[1].transmission_time, >=)) {
-                       timeradd(&audio_gatherings[1].transmission_time, &diff, &audio_gatherings[1].transmission_time);
-                       sendStunRequest(audio_gatherings[1].sock, (struct sockaddr*)&ss, ss_len, 1, FALSE);
-               }
-               if (call->params.has_video) {
-                       if ((video_gatherings[0].response == FALSE) && timercmp(&cur, &video_gatherings[0].transmission_time, >=)) {
-                               timeradd(&video_gatherings[0].transmission_time, &diff, &video_gatherings[0].transmission_time);
-                               sendStunRequest(video_gatherings[0].sock, (struct sockaddr*)&ss, ss_len, 2, FALSE);
-                       }
-                       if ((video_gatherings[1].response == FALSE) && timercmp(&cur, &video_gatherings[1].transmission_time, >=)) {
-                               timeradd(&video_gatherings[1].transmission_time, &diff, &video_gatherings[1].transmission_time);
-                               sendStunRequest(video_gatherings[1].sock, (struct sockaddr*)&ss, ss_len, 2, FALSE);
-                       }
-               }
-#ifdef WIN32
-               Sleep(10);
-#else
-               usleep(10000);
-#endif
-
-               if (recvStunResponse(audio_gatherings[0].sock, addr, &port, &id) > 0) {
-                       ice_add_local_candidate(audio_check_list, "srflx", addr, port, 1, audio_gatherings[0].base);
-                       audio_gatherings[0].response = TRUE;
-               }
-               if (recvStunResponse(audio_gatherings[1].sock, addr, &port, &id) > 0) {
-                       ice_add_local_candidate(audio_check_list, "srflx", addr, port, 2, audio_gatherings[1].base);
-                       audio_gatherings[1].response = TRUE;
-               }
-               if (call->params.has_video && (video_check_list != NULL)) {
-                       if (recvStunResponse(video_gatherings[0].sock, addr, &port, &id) > 0) {
-                               ice_add_local_candidate(video_check_list, "srflx", addr, port, 1, video_gatherings[0].base);
-                               video_gatherings[0].response = TRUE;
-                       }
-                       if (recvStunResponse(video_gatherings[1].sock, addr, &port, &id) > 0) {
-                               ice_add_local_candidate(video_check_list, "srflx", addr, port, 2, video_gatherings[1].base);
-                               video_gatherings[1].response = TRUE;
-                       }
-               }
-
-               gettimeofday(&cur, NULL);
-               elapsed = ((cur.tv_sec - init.tv_sec) * 1000.0) +  ((cur.tv_usec - init.tv_usec) / 1000.0);
-               if (elapsed > 2000)  {
-                       ms_message("Stun responses timeout, going ahead.");
-                       break;
-               }
-               loops++;
-       } while (!((audio_gatherings[0].response == TRUE) && (audio_gatherings[1].response == TRUE)
-               && (!call->params.has_video || ((video_gatherings[0].response == TRUE) && (video_gatherings[1].response == TRUE)))));
-
-       if ((audio_gatherings[0].response == FALSE) || (audio_gatherings[1].response == FALSE)
-               || (call->params.has_video && ((video_gatherings[0].response == FALSE) || (video_gatherings[1].response == FALSE)))) {
-               /* Failed some STUN checks, deactivate ICE. */
-               ice_session_destroy(ice_session);
-               ice_session = NULL;
-               sal_op_set_ice_session(call->op, ice_session);
-       } else {
-               ice_session_compute_candidates_foundations(ice_session);
-               ice_session_eliminate_redundant_candidates(ice_session);
-               ice_session_choose_default_candidates(ice_session);
-       }
-
-       close_socket(audio_gatherings[0].sock);
-       close_socket(audio_gatherings[1].sock);
-       if (ice_session != NULL) ice_dump_candidates(audio_check_list);
+       ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port, 1, NULL);
+       ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port + 1, 2, NULL);
        if (call->params.has_video && (video_check_list != NULL)) {
-               if (video_gatherings[0].sock != -1) close_socket(video_gatherings[0].sock);
-               if (video_gatherings[1].sock != -1) close_socket(video_gatherings[1].sock);
-               if (ice_session != NULL) ice_dump_candidates(video_check_list);
+               ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port, 1, NULL);
+               ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port + 1, 2, NULL);
        }
+
+       /* Gather local srflx candidates. */
+       ice_session_gather_candidates(ice_session, ss, ss_len);
+       return 0;
 }
 
 LinphoneCall * is_a_linphone_call(void *user_pointer){
index 241da02236f5fc6d35e4ec1af2f0d5838b25b9a8..33c6985dd0a5cde9fcd518ece156e1dba7466c7c 100644 (file)
@@ -219,7 +219,7 @@ MSList *linphone_find_friend(MSList *fl, const LinphoneAddress *fri, LinphoneFri
 void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc);
 void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall *call, const PayloadType *pt);
 void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call);
-void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call);
+int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call);
 
 void linphone_core_send_initial_subscribes(LinphoneCore *lc);
 void linphone_core_write_friends_config(LinphoneCore* lc);
@@ -245,6 +245,7 @@ void linphone_call_init_stats(LinphoneCallStats *stats, int type);
 
 void linphone_call_init_media_streams(LinphoneCall *call);
 void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone);
+void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call);
 void linphone_call_stop_media_streams(LinphoneCall *call);
 
 const char * linphone_core_get_identity(LinphoneCore *lc);