From fd852f01c6f63abb082dcb48f8ba4e88ebe04daa Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 17 Jul 2012 12:23:33 +0200 Subject: [PATCH 01/74] Add configuration parameter to enable ICE. --- console/commands.c | 13 +++ coreapi/linphonecore.h | 3 +- gtk/parameters.ui | 178 ++++++++++++++++++++++++----------------- gtk/propertybox.c | 8 ++ 4 files changed, 127 insertions(+), 75 deletions(-) diff --git a/console/commands.c b/console/commands.c index 776d2b260..472531795 100644 --- a/console/commands.c +++ b/console/commands.c @@ -850,6 +850,16 @@ lpc_cmd_firewall(LinphoneCore *lc, char *args) { linphone_core_set_firewall_policy(lc,LinphonePolicyNoFirewall); } + else if (strcmp(args,"ice")==0) + { + setting = linphone_core_get_stun_server(lc); + if ( ! setting ) + { + linphonec_out("No stun server address is defined, use 'stun
' first\n"); + return 1; + } + linphone_core_set_firewall_policy(lc,LinphonePolicyUseIce); + } else if (strcmp(args,"stun")==0) { setting = linphone_core_get_stun_server(lc); @@ -883,6 +893,9 @@ lpc_cmd_firewall(LinphoneCore *lc, char *args) case LinphonePolicyUseNatAddress: linphonec_out("Using supplied nat address %s.\n", setting ? setting : linphone_core_get_nat_address(lc)); break; + case LinphonePolicyUseIce: + linphonec_out("Using ice with stun server %s to discover firewall address\n", setting ? setting : linphone_core_get_stun_server(lc)); + break; } return 1; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 81044fff5..10f6108c9 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -740,7 +740,8 @@ typedef struct _LCCallbackObj typedef enum _LinphoneFirewallPolicy{ LinphonePolicyNoFirewall, LinphonePolicyUseNatAddress, - LinphonePolicyUseStun + LinphonePolicyUseStun, + LinphonePolicyUseIce } LinphoneFirewallPolicy; typedef enum _LinphoneWaitingState{ diff --git a/gtk/parameters.ui b/gtk/parameters.ui index b8f4adbdc..9fc8538c0 100644 --- a/gtk/parameters.ui +++ b/gtk/parameters.ui @@ -1,6 +1,7 @@ + 500 3001 @@ -206,10 +207,10 @@ Set Maximum Transmission Unit: + False True True False - False True @@ -225,6 +226,8 @@ True False False + True + True adjustment1 @@ -244,10 +247,10 @@ Send DTMFs as SIP info + False True True False - False True @@ -260,11 +263,11 @@ Use IPv6 instead of IPv4 + False True True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False True @@ -335,6 +338,8 @@ True False False + True + True adjustment7 @@ -379,9 +384,9 @@ edit + False True True - False @@ -422,6 +427,10 @@ True True + False + False + True + True adjustment_audio_port True @@ -438,6 +447,10 @@ True True + False + False + True + True adjustment_video_port True @@ -483,10 +496,10 @@ Direct connection to the Internet + False True True False - False True True @@ -504,10 +517,10 @@ Behind NAT / Firewall (specify gateway IP below) + False True True False - False True True no_nat @@ -545,6 +558,8 @@ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False False + True + True @@ -568,20 +583,51 @@ - + + Behind NAT / Firewall (use STUN to resolve) + False + True + True + False + True + no_nat + + + + True + True + 2 + + + + + Behind NAT / Firewall (use ICE) + False + True + True + False + True + no_nat + + + + True + True + 3 + + + + True False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - Behind NAT / Firewall (use STUN to resolve) + True - True - False - False - True - True - no_nat - + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Stun server: + right True @@ -590,39 +636,17 @@ - + True - False + True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Stun server: - right - - - True - True - 0 - - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - False - - - - True - True - 1 - - + + True + False + False + True + True + True @@ -632,9 +656,9 @@ - False - False - 2 + True + True + 4 @@ -719,6 +743,9 @@ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 6 2 + + + True @@ -740,11 +767,11 @@ gtk-media-play + False True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False True @@ -783,6 +810,8 @@ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False False + True + True @@ -915,10 +944,10 @@ Enable echo cancellation + False True True False - False True @@ -929,9 +958,6 @@ 6 - - - @@ -1134,6 +1160,8 @@ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False False + True + True @@ -1172,6 +1200,8 @@ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False False + True + True @@ -1189,6 +1219,8 @@ False False False + True + True 1 @@ -1245,9 +1277,6 @@ True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - @@ -1264,10 +1293,10 @@ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False True True True - False @@ -1311,11 +1340,11 @@ + False True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False @@ -1359,11 +1388,11 @@ + False True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False @@ -1407,11 +1436,11 @@ + False True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False @@ -1455,9 +1484,9 @@ + False True True - False @@ -1544,11 +1573,11 @@ virtual network ! GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False @@ -1713,9 +1742,6 @@ virtual network ! True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True - - - @@ -1733,11 +1759,11 @@ virtual network ! gtk-go-up + False True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False True @@ -1750,11 +1776,11 @@ virtual network ! gtk-go-down + False True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False True @@ -1766,11 +1792,11 @@ virtual network ! + False True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False @@ -1814,11 +1840,11 @@ virtual network ! + False True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False @@ -1922,6 +1948,8 @@ virtual network ! 0 stands for "unlimited" False False + True + True adjustment5 @@ -1942,6 +1970,8 @@ virtual network ! 0 stands for "unlimited" False False + True + True adjustment6 @@ -1977,10 +2007,10 @@ virtual network ! Enable adaptive rate control + False True True False - False 0 True @@ -2132,10 +2162,10 @@ virtual network ! Show advanced settings + False True True False - False True @@ -2212,11 +2242,11 @@ virtual network ! end + False True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False diff --git a/gtk/propertybox.c b/gtk/propertybox.c index 809207a2a..6870e2786 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -171,6 +171,11 @@ void linphone_gtk_use_stun_toggled(GtkWidget *w){ linphone_core_set_firewall_policy(linphone_gtk_get_core(),LinphonePolicyUseStun); } +void linphone_gtk_use_ice_toggled(GtkWidget *w){ + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) + linphone_core_set_firewall_policy(linphone_gtk_get_core(),LinphonePolicyUseIce); +} + 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))); @@ -956,6 +961,9 @@ void linphone_gtk_show_parameters(void){ case LinphonePolicyUseStun: gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"use_stun")),TRUE); break; + case LinphonePolicyUseIce: + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"use_ice")),TRUE); + break; } mtu=linphone_core_get_mtu(lc); if (mtu<=0){ From 47b52bbcdbeb81bdfcbaedbed5e53e3f4f5f3723 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 17 Jul 2012 15:02:44 +0200 Subject: [PATCH 02/74] Allocate ICE session and check lists for each stream when ICE is enabled. --- coreapi/linphonecall.c | 33 +++++++++++++++++++++++++++++++-- coreapi/private.h | 2 ++ coreapi/sal.h | 2 ++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index ec006dd58..f533711cf 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -245,6 +245,10 @@ static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, Li md->streams[i].crypto[1].algo = 0; md->streams[i].crypto[2].algo = 0; } + if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce){ + md->streams[i].ice_check_list = ice_check_list_new(); + ice_session_add_check_list(call->ice_session, md->streams[i].ice_check_list); + } } linphone_address_destroy(addr); @@ -338,10 +342,19 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr 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) call->ice_session=ice_session_new(); call->localdesc=create_local_media_description (lc,call); call->camera_active=params->has_video; - if (linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseStun) - linphone_core_run_stun_tests(call->core,call); + switch (linphone_core_get_firewall_policy(call->core)) { + case LinphonePolicyUseStun: + linphone_core_run_stun_tests(call->core,call); + break; + case LinphonePolicyUseIce: + ms_error("Gather ICE candidates"); + break; + default: + break; + } discover_mtu(lc,linphone_address_get_domain (to)); if (params->referer){ sal_call_set_referer(call->op,params->referer->op); @@ -525,6 +538,10 @@ static void linphone_call_destroy(LinphoneCall *obj) sal_op_release(obj->op); obj->op=NULL; } + if (obj->ice_session!=NULL) { + ice_session_destroy(obj->ice_session); + obj->ice_session=NULL; + } if (obj->resultdesc!=NULL) { sal_media_description_unref(obj->resultdesc); obj->resultdesc=NULL; @@ -937,6 +954,11 @@ void linphone_call_init_media_streams(LinphoneCall *call){ RtpTransport *artcp=lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->audio_port+1); rtp_session_set_transports(audiostream->session,artp,artcp); } + if (linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce){ + rtp_session_set_pktinfo(audiostream->session,TRUE); + audiostream->ice_check_list = call->localdesc->streams[0].ice_check_list; + ice_check_list_register_success_cb(audiostream->ice_check_list, audio_stream_set_remote_from_ice, audiostream); + } call->audiostream_app_evq = ortp_ev_queue_new(); rtp_session_register_event_queue(audiostream->session,call->audiostream_app_evq); @@ -957,6 +979,11 @@ void linphone_call_init_media_streams(LinphoneCall *call){ RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->video_port+1); rtp_session_set_transports(call->videostream->session,vrtp,vrtcp); } + if (linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce){ + rtp_session_set_pktinfo(call->videostream->session,TRUE); + call->videostream->ice_check_list = call->localdesc->streams[1].ice_check_list; + ice_check_list_register_success_cb(call->videostream->ice_check_list, video_stream_set_remote_from_ice, call->videostream); + } call->videostream_app_evq = ortp_ev_queue_new(); rtp_session_register_event_queue(call->videostream->session,call->videostream_app_evq); #ifdef TEST_EXT_RENDERER @@ -1436,6 +1463,7 @@ void linphone_call_stop_media_streams(LinphoneCall *call){ if (call->endpoint){ linphone_call_remove_from_conf(call); } + if (call->audiostream->ice_check_list) ice_check_list_destroy(call->audiostream->ice_check_list); audio_stream_stop(call->audiostream); call->audiostream=NULL; } @@ -1446,6 +1474,7 @@ void linphone_call_stop_media_streams(LinphoneCall *call){ rtp_session_unregister_event_queue(call->videostream->session,call->videostream_app_evq); ortp_ev_queue_flush(call->videostream_app_evq); ortp_ev_queue_destroy(call->videostream_app_evq); + if (call->videostream->ice_check_list) ice_check_list_destroy(call->videostream->ice_check_list); video_stream_stop(call->videostream); call->videostream=NULL; } diff --git a/coreapi/private.h b/coreapi/private.h index 1ab7a6a7d..dd8b2b3bd 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -35,6 +35,7 @@ extern "C" { #ifdef HAVE_CONFIG_H #include "config.h" #endif +#include "mediastreamer2/ice.h" #include "mediastreamer2/mediastream.h" #include "mediastreamer2/msconference.h" @@ -135,6 +136,7 @@ struct _LinphoneCall bool_t was_automatically_paused; CallCallbackObj nextVideoFrameDecoded; LinphoneCallStats stats[2]; + IceSession *ice_session; }; diff --git a/coreapi/sal.h b/coreapi/sal.h index d2d9cbe51..65eb5e0b4 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -27,6 +27,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define sal_h #include "mediastreamer2/mscommon.h" +#include "mediastreamer2/ice.h" #include "ortp/ortp_srtp.h" /*Dirty hack, keep in sync with mediastreamer2/include/mediastream.h */ @@ -135,6 +136,7 @@ typedef struct SalStreamDescription{ SalSrtpCryptoAlgo crypto[SAL_CRYPTO_ALGO_MAX]; unsigned int crypto_local_tag; int max_rate; + IceCheckList *ice_check_list; } SalStreamDescription; #define SAL_MEDIA_DESCRIPTION_MAX_STREAMS 4 From c87250cb9a82eebed43c095ad2c965d27d89b368 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 17 Jul 2012 16:46:36 +0200 Subject: [PATCH 03/74] Gather ICE server reflexive candidates when starting an outgoing call. --- coreapi/linphonecall.c | 2 +- coreapi/misc.c | 101 +++++++++++++++++++++++++++++++++++++++++ coreapi/private.h | 1 + 3 files changed, 103 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index f533711cf..0be2c9608 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -350,7 +350,7 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr linphone_core_run_stun_tests(call->core,call); break; case LinphonePolicyUseIce: - ms_error("Gather ICE candidates"); + linphone_core_gather_ice_candidates(call->core,call); break; default: break; diff --git a/coreapi/misc.c b/coreapi/misc.c index a749bf279..632ddfe75 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -562,6 +562,107 @@ void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ } } +void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) +{ + char addr[64]; + int port; + int id; + ortp_socket_t audio_socks[2]; + ortp_socket_t video_socks[2]; + bool_t audio_responses[2]; + bool_t video_responses[2]; + struct sockaddr_storage ss; + socklen_t ss_len; + struct timeval init, cur; + double elapsed; + int loops = 0; + const LinphoneCallParams *params = linphone_call_get_current_params(call); + const char *server = linphone_core_get_stun_server(lc); + + if (server == NULL) return; + if (lc->sip_conf.ipv6_enabled){ + ms_warning("stun support is not implemented for ipv6"); + return; + } + + if (parse_hostname_to_addr(server, &ss, &ss_len) < 0) { + ms_error("Fail to parser stun server address: %s", server); + return; + } + if (lc->vtable.display_status != NULL) + lc->vtable.display_status(lc, _("ICE local candidates gathering in progress...")); + + audio_responses[0] = audio_responses[1] = FALSE; + video_responses[0] = video_responses[1] = FALSE; + audio_socks[0] = create_socket(call->audio_port); + if (audio_socks[0] == -1) return; + audio_socks[1] = create_socket(call->audio_port + 1); + if (audio_socks[1] == -1) return; + if (params->has_video) { + video_socks[0] = create_socket(call->video_port); + if (video_socks[0] == -1) return; + video_socks[1] = create_socket(call->video_port + 1); + if (video_socks[1] == -1) return; + } else { + video_socks[0] = video_socks[1] = -1; + } + + gettimeofday(&init, NULL); + do { + if (loops % 20 == 0) { + ms_message("Sending stun requests..."); + if (audio_responses[0] == FALSE) sendStunRequest(audio_socks[0], (struct sockaddr*)&ss, ss_len, 1, FALSE); + if (audio_responses[1] == FALSE) sendStunRequest(audio_socks[1], (struct sockaddr*)&ss, ss_len, 1, FALSE); + if (params->has_video) { + if (video_responses[0] == FALSE) sendStunRequest(video_socks[0], (struct sockaddr*)&ss, ss_len, 2, FALSE); + if (video_responses[1] == FALSE) sendStunRequest(video_socks[1], (struct sockaddr*)&ss, ss_len, 2, FALSE); + } + } +#ifdef WIN32 + Sleep(10); +#else + usleep(10000); +#endif + + if (recvStunResponse(audio_socks[0], addr, &port, &id) > 0) { + ice_add_local_candidate(call->localdesc->streams[0].ice_check_list, "srflx", addr, port, 1, NULL); + audio_responses[0] = TRUE; + } + if (recvStunResponse(audio_socks[1], addr, &port, &id) > 0) { + ice_add_local_candidate(call->localdesc->streams[0].ice_check_list, "srflx", addr, port, 2, NULL); + audio_responses[1] = TRUE; + } + if (params->has_video) { + if (recvStunResponse(video_socks[0], addr, &port, &id) > 0) { + ice_add_local_candidate(call->localdesc->streams[1].ice_check_list, "srflx", addr, port, 1, NULL); + video_responses[0] = TRUE; + } + if (recvStunResponse(video_socks[1], addr, &port, &id) > 0) { + ice_add_local_candidate(call->localdesc->streams[1].ice_check_list, "srflx", addr, port, 2, NULL); + video_responses[1] = 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_responses[0] == TRUE) && (audio_responses[1] == TRUE) + && (!params->has_video || ((video_responses[0] == TRUE) && (video_responses[1] == TRUE))))); + + close_socket(audio_socks[0]); + close_socket(audio_socks[1]); + ice_dump_candidates(call->localdesc->streams[0].ice_check_list); + if (params->has_video) { + if (video_socks[0] != -1) close_socket(video_socks[0]); + if (video_socks[1] != -1) close_socket(video_socks[1]); + ice_dump_candidates(call->localdesc->streams[1].ice_check_list); + } +} + LinphoneCall * is_a_linphone_call(void *user_pointer){ LinphoneCall *call=(LinphoneCall*)user_pointer; if (call==NULL) return NULL; diff --git a/coreapi/private.h b/coreapi/private.h index dd8b2b3bd..2a2cd7816 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -220,6 +220,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); void linphone_core_send_initial_subscribes(LinphoneCore *lc); void linphone_core_write_friends_config(LinphoneCore* lc); From 1d3aab598e5603d64b081b0fd8fbb2840d6af0dd Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 17 Jul 2012 17:10:03 +0200 Subject: [PATCH 04/74] Gather ICE host candidates when starting an outgoing call. --- coreapi/misc.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/coreapi/misc.c b/coreapi/misc.c index 632ddfe75..36424f566 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -564,6 +564,7 @@ void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) { + char local_addr[64]; char addr[64]; int port; int id; @@ -571,6 +572,8 @@ void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) ortp_socket_t video_socks[2]; bool_t audio_responses[2]; bool_t video_responses[2]; + IceCandidate *audio_ice_bases[2]; + IceCandidate *video_ice_bases[2]; struct sockaddr_storage ss; socklen_t ss_len; struct timeval init, cur; @@ -594,6 +597,8 @@ void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) audio_responses[0] = audio_responses[1] = FALSE; video_responses[0] = video_responses[1] = FALSE; + audio_ice_bases[0] = audio_ice_bases[1] = NULL; + video_ice_bases[0] = video_ice_bases[1] = NULL; audio_socks[0] = create_socket(call->audio_port); if (audio_socks[0] == -1) return; audio_socks[1] = create_socket(call->audio_port + 1); @@ -606,6 +611,16 @@ void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) } else { video_socks[0] = video_socks[1] = -1; } + if (linphone_core_get_local_ip_for(AF_INET, NULL, local_addr) < 0) { + ms_error("Fail to get local ip"); + return; + } + audio_ice_bases[0] = ice_add_local_candidate(call->localdesc->streams[0].ice_check_list, "host", local_addr, call->audio_port, 1, NULL); + audio_ice_bases[1] = ice_add_local_candidate(call->localdesc->streams[0].ice_check_list, "host", local_addr, call->audio_port + 1, 2, NULL); + if (params->has_video) { + video_ice_bases[0] = ice_add_local_candidate(call->localdesc->streams[1].ice_check_list, "host", local_addr, call->video_port, 1, NULL); + video_ice_bases[1] = ice_add_local_candidate(call->localdesc->streams[1].ice_check_list, "host", local_addr, call->video_port + 1, 2, NULL); + } gettimeofday(&init, NULL); do { @@ -625,20 +640,20 @@ void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) #endif if (recvStunResponse(audio_socks[0], addr, &port, &id) > 0) { - ice_add_local_candidate(call->localdesc->streams[0].ice_check_list, "srflx", addr, port, 1, NULL); + ice_add_local_candidate(call->localdesc->streams[0].ice_check_list, "srflx", addr, port, 1, audio_ice_bases[0]); audio_responses[0] = TRUE; } if (recvStunResponse(audio_socks[1], addr, &port, &id) > 0) { - ice_add_local_candidate(call->localdesc->streams[0].ice_check_list, "srflx", addr, port, 2, NULL); + ice_add_local_candidate(call->localdesc->streams[0].ice_check_list, "srflx", addr, port, 2, audio_ice_bases[1]); audio_responses[1] = TRUE; } if (params->has_video) { if (recvStunResponse(video_socks[0], addr, &port, &id) > 0) { - ice_add_local_candidate(call->localdesc->streams[1].ice_check_list, "srflx", addr, port, 1, NULL); + ice_add_local_candidate(call->localdesc->streams[1].ice_check_list, "srflx", addr, port, 1, video_ice_bases[0]); video_responses[0] = TRUE; } if (recvStunResponse(video_socks[1], addr, &port, &id) > 0) { - ice_add_local_candidate(call->localdesc->streams[1].ice_check_list, "srflx", addr, port, 2, NULL); + ice_add_local_candidate(call->localdesc->streams[1].ice_check_list, "srflx", addr, port, 2, video_ice_bases[1]); video_responses[1] = TRUE; } } From e594edfe34499c6bd0c8a008351ba32181692bdd Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 17 Jul 2012 17:14:47 +0200 Subject: [PATCH 05/74] Compute ICE foundations and choose default candidates when ICE candidate gathering is finished. --- coreapi/misc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/coreapi/misc.c b/coreapi/misc.c index 36424f566..64b6df71a 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -668,6 +668,9 @@ void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) } while (!((audio_responses[0] == TRUE) && (audio_responses[1] == TRUE) && (!params->has_video || ((video_responses[0] == TRUE) && (video_responses[1] == TRUE))))); + ice_session_compute_candidates_foundations(call->ice_session); + ice_session_choose_default_candidates(call->ice_session); + close_socket(audio_socks[0]); close_socket(audio_socks[1]); ice_dump_candidates(call->localdesc->streams[0].ice_check_list); From 38af09c6b5fdbc22322e4191d2398035912ee52f Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 18 Jul 2012 11:14:47 +0200 Subject: [PATCH 06/74] Fix ICE candidates gathering for video stream. --- coreapi/misc.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/coreapi/misc.c b/coreapi/misc.c index 64b6df71a..6fa68e6dc 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -579,7 +579,6 @@ void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) struct timeval init, cur; double elapsed; int loops = 0; - const LinphoneCallParams *params = linphone_call_get_current_params(call); const char *server = linphone_core_get_stun_server(lc); if (server == NULL) return; @@ -603,7 +602,7 @@ void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) if (audio_socks[0] == -1) return; audio_socks[1] = create_socket(call->audio_port + 1); if (audio_socks[1] == -1) return; - if (params->has_video) { + if (call->params.has_video) { video_socks[0] = create_socket(call->video_port); if (video_socks[0] == -1) return; video_socks[1] = create_socket(call->video_port + 1); @@ -617,7 +616,7 @@ void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) } audio_ice_bases[0] = ice_add_local_candidate(call->localdesc->streams[0].ice_check_list, "host", local_addr, call->audio_port, 1, NULL); audio_ice_bases[1] = ice_add_local_candidate(call->localdesc->streams[0].ice_check_list, "host", local_addr, call->audio_port + 1, 2, NULL); - if (params->has_video) { + if (call->params.has_video) { video_ice_bases[0] = ice_add_local_candidate(call->localdesc->streams[1].ice_check_list, "host", local_addr, call->video_port, 1, NULL); video_ice_bases[1] = ice_add_local_candidate(call->localdesc->streams[1].ice_check_list, "host", local_addr, call->video_port + 1, 2, NULL); } @@ -628,7 +627,7 @@ void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) ms_message("Sending stun requests..."); if (audio_responses[0] == FALSE) sendStunRequest(audio_socks[0], (struct sockaddr*)&ss, ss_len, 1, FALSE); if (audio_responses[1] == FALSE) sendStunRequest(audio_socks[1], (struct sockaddr*)&ss, ss_len, 1, FALSE); - if (params->has_video) { + if (call->params.has_video) { if (video_responses[0] == FALSE) sendStunRequest(video_socks[0], (struct sockaddr*)&ss, ss_len, 2, FALSE); if (video_responses[1] == FALSE) sendStunRequest(video_socks[1], (struct sockaddr*)&ss, ss_len, 2, FALSE); } @@ -647,7 +646,7 @@ void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) ice_add_local_candidate(call->localdesc->streams[0].ice_check_list, "srflx", addr, port, 2, audio_ice_bases[1]); audio_responses[1] = TRUE; } - if (params->has_video) { + if (call->params.has_video) { if (recvStunResponse(video_socks[0], addr, &port, &id) > 0) { ice_add_local_candidate(call->localdesc->streams[1].ice_check_list, "srflx", addr, port, 1, video_ice_bases[0]); video_responses[0] = TRUE; @@ -666,7 +665,7 @@ void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) } loops++; } while (!((audio_responses[0] == TRUE) && (audio_responses[1] == TRUE) - && (!params->has_video || ((video_responses[0] == TRUE) && (video_responses[1] == TRUE))))); + && (!call->params.has_video || ((video_responses[0] == TRUE) && (video_responses[1] == TRUE))))); ice_session_compute_candidates_foundations(call->ice_session); ice_session_choose_default_candidates(call->ice_session); @@ -674,7 +673,7 @@ void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) close_socket(audio_socks[0]); close_socket(audio_socks[1]); ice_dump_candidates(call->localdesc->streams[0].ice_check_list); - if (params->has_video) { + if (call->params.has_video) { if (video_socks[0] != -1) close_socket(video_socks[0]); if (video_socks[1] != -1) close_socket(video_socks[1]); ice_dump_candidates(call->localdesc->streams[1].ice_check_list); From 47441a8d385e4cd4645b0a6ffaf158249514d5a6 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 18 Jul 2012 11:15:34 +0200 Subject: [PATCH 07/74] Add ICE attributes in the SDP content. --- coreapi/sal_eXosip2_sdp.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 32f031864..96cfa5ebc 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -158,6 +158,14 @@ static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc) sdp_message_t_time_descr_add (local, osip_strdup ("0"), osip_strdup ("0")); if (desc->bandwidth>0) sdp_message_b_bandwidth_add (local, -1, osip_strdup ("AS"), int_2char(desc->bandwidth)); + if (desc->streams[0].ice_check_list != NULL) { + char buffer[512]; + snprintf(buffer ,sizeof(buffer), "%s", ice_session_local_pwd(desc->streams[0].ice_check_list->session)); + sdp_message_a_attribute_add(local, -1, osip_strdup("ice-pwd"), osip_strdup(buffer)); + snprintf(buffer ,sizeof(buffer), "%s", ice_session_local_ufrag(desc->streams[0].ice_check_list->session)); + sdp_message_a_attribute_add(local, -1, osip_strdup("ice-ufrag"), osip_strdup(buffer)); + } + return local; } @@ -197,6 +205,22 @@ static void add_payload(sdp_message_t *msg, int line, const PayloadType *pt, boo } } +static void add_ice_candidates(sdp_message_t *msg, int lineno, const SalStreamDescription *desc) +{ + char buffer[1024]; + IceCandidate *candidate; + int i; + + if (desc->ice_check_list != NULL) { + for (i = 0; i < ms_list_size(desc->ice_check_list->local_candidates); i++) { + candidate = ms_list_nth_data(desc->ice_check_list->local_candidates, i); + snprintf(buffer, sizeof(buffer), "%s %d UDP %d %s %d typ %s", + candidate->foundation, candidate->componentID, candidate->priority, candidate->taddr.ip, candidate->taddr.port, ice_candidate_type(candidate)); + sdp_message_a_attribute_add(msg, lineno, osip_strdup("candidate"), osip_strdup(buffer)); + } + } +} + static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription *desc){ const char *mt=NULL; @@ -305,8 +329,10 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription break; } if (dir) sdp_message_a_attribute_add (msg, lineno, osip_strdup (dir),NULL); + add_ice_candidates(msg, lineno, desc); } + sdp_message_t *media_description_to_sdp(const SalMediaDescription *desc){ int i; sdp_message_t *msg=create_generic_sdp(desc); From 17ea4603099299f60a63007906671eef04e65657 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 18 Jul 2012 11:47:05 +0200 Subject: [PATCH 08/74] Good connection address and media ports in the SDP when using ICE. --- coreapi/sal_eXosip2_sdp.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 96cfa5ebc..55df9d6b2 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -130,6 +130,7 @@ static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc) int inet6; char sessid[16]; char sessver[16]; + const char *addr = desc->addr; snprintf(sessid,16,"%i",desc->session_id); snprintf(sessver,16,"%i",desc->session_ver); @@ -143,11 +144,17 @@ static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc) osip_strdup ("IN"), inet6 ? osip_strdup("IP6") : osip_strdup ("IP4"), osip_strdup (desc->addr)); sdp_message_s_name_set (local, osip_strdup ("Talk")); + if (desc->streams[0].ice_check_list != NULL) { + const IceCandidate *candidate = ice_check_list_default_local_candidate(desc->streams[0].ice_check_list); + if (candidate != NULL) { + addr=candidate->taddr.ip; + } + } if(!sal_media_description_has_dir (desc,SalStreamSendOnly)) { sdp_message_c_connection_add (local, -1, osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"), - osip_strdup (desc->addr), NULL, NULL); + osip_strdup (addr), NULL, NULL); } else { @@ -208,7 +215,7 @@ static void add_payload(sdp_message_t *msg, int line, const PayloadType *pt, boo static void add_ice_candidates(sdp_message_t *msg, int lineno, const SalStreamDescription *desc) { char buffer[1024]; - IceCandidate *candidate; + const IceCandidate *candidate; int i; if (desc->ice_check_list != NULL) { @@ -241,13 +248,19 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription mt=desc->typeother; break; } - if (desc->candidates[0].addr[0]!='\0'){ + addr=desc->addr; + port=desc->port; + if (desc->ice_check_list != NULL) { + const IceCandidate *candidate = ice_check_list_default_local_candidate(desc->ice_check_list); + if (candidate != NULL) { + addr=candidate->taddr.ip; + port=candidate->taddr.port; + } + } else if (desc->candidates[0].addr[0]!='\0'){ addr=desc->candidates[0].addr; port=desc->candidates[0].port; - }else{ - addr=desc->addr; - port=desc->port; } + /*only add a c= line within the stream description if address are differents*/ if (strcmp(addr,sdp_message_c_addr_get(msg, -1, 0))!=0){ bool_t inet6; From f8f3db359cc60880654c99e9f60d6ad36294b195 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 18 Jul 2012 12:29:05 +0200 Subject: [PATCH 09/74] Define ICE session role explicitly. --- coreapi/misc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/coreapi/misc.c b/coreapi/misc.c index 6fa68e6dc..fd3a8716e 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -614,6 +614,11 @@ void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) ms_error("Fail to get local ip"); return; } + if (call->dir == LinphoneCallOutgoing) { + ice_session_set_role(call->ice_session, IR_Controlling); + } else { + ice_session_set_role(call->ice_session, IR_Controlled); + } audio_ice_bases[0] = ice_add_local_candidate(call->localdesc->streams[0].ice_check_list, "host", local_addr, call->audio_port, 1, NULL); audio_ice_bases[1] = ice_add_local_candidate(call->localdesc->streams[0].ice_check_list, "host", local_addr, call->audio_port + 1, 2, NULL); if (call->params.has_video) { From afe90f2be97003f185d2469b31d20b09452a7483 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 18 Jul 2012 14:17:06 +0200 Subject: [PATCH 10/74] Create ICE session when receiving an incoming call if this is necessary. --- coreapi/linphonecall.c | 1 + 1 file changed, 1 insertion(+) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 0be2c9608..4e9e4b118 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -388,6 +388,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro linphone_call_init_common(call, from, to); linphone_core_init_default_params(lc, &call->params); call->params.has_video &= !!lc->video_policy.automatically_accept; + if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) call->ice_session=ice_session_new(); call->localdesc=create_local_media_description (lc,call); call->camera_active=call->params.has_video; if (linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseStun) From c93c092cf3cde2fe015a3103633630d83af2ee5b Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 18 Jul 2012 15:41:58 +0200 Subject: [PATCH 11/74] Parse ICE attributes when receiving SDP. --- coreapi/sal.h | 3 +++ coreapi/sal_eXosip2_sdp.c | 52 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/coreapi/sal.h b/coreapi/sal.h index 65eb5e0b4..8bd2523fd 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -152,6 +152,9 @@ typedef struct SalMediaDescription{ SalStreamDescription streams[SAL_MEDIA_DESCRIPTION_MAX_STREAMS]; } SalMediaDescription; +#define SAL_MEDIA_DESCRIPTION_MAX_MESSAGE_ATTRIBUTES 5 +#define SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES 10 + SalMediaDescription *sal_media_description_new(); void sal_media_description_ref(SalMediaDescription *md); void sal_media_description_unref(SalMediaDescription *md); diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 55df9d6b2..08deb7d5c 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -389,7 +389,10 @@ static int payload_type_fill_from_rtpmap(PayloadType *pt, const char *rtpmap){ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ int i,j; const char *mtype,*proto,*port,*addr,*number; + const char *ice_ufrag, *ice_pwd; sdp_bandwidth_t *sbw=NULL; + sdp_attribute_t *attr; + int media_attribute_nb; addr=sdp_message_c_addr_get (msg, -1, 0); if (addr) @@ -433,7 +436,8 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ for(j=0;(sbw=sdp_message_bandwidth_get(msg,i,j))!=NULL;++j){ if (strcasecmp(sbw->b_bwtype,"AS")==0) stream->bandwidth=atoi(sbw->b_bandwidth); } - stream->dir=_sdp_message_get_mline_dir(msg,i); + stream->dir=_sdp_message_get_mline_dir(msg,i); + media_attribute_nb = 0; /* for each payload type */ for (j=0;((number=sdp_message_m_payload_get (msg, i,j)) != NULL); j++){ const char *rtpmap,*fmtp; @@ -442,9 +446,11 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ payload_type_set_number(pt,ptn); /* get the rtpmap associated to this codec, if any */ rtpmap=sdp_message_a_attr_value_get_with_pt(msg, i,ptn,"rtpmap"); + if (rtpmap != NULL) media_attribute_nb++; if (payload_type_fill_from_rtpmap(pt,rtpmap)==0){ /* get the fmtp, if any */ fmtp=sdp_message_a_attr_value_get_with_pt(msg, i, ptn,"fmtp"); + if (fmtp != NULL) media_attribute_nb++; payload_type_set_send_fmtp(pt,fmtp); stream->payloads=ms_list_append(stream->payloads,pt); ms_message("Found payload %s/%i fmtp=%s",pt->mime_type,pt->clock_rate, @@ -455,7 +461,6 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ /* read crypto lines if any */ if (stream->proto == SalProtoRtpSavp) { int k, valid_count = 0; - sdp_attribute_t *attr; memset(&stream->crypto, 0, sizeof(stream->crypto)); for (k=0;valid_count < SAL_CRYPTO_ALGO_MAX && (attr=sdp_message_attribute_get(msg,i,k))!=NULL;k++){ @@ -494,6 +499,49 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ } ms_message("Found: %d valid crypto lines", valid_count); } + + /* Get ICE candidate attributes if any */ + ice_ufrag = ice_pwd = NULL; + for (j = 0; (j < SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES) && ((attr = sdp_message_attribute_get(msg, i, media_attribute_nb + j)) != NULL); j++) { + if ((keywordcmp("candidate", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { + char ip[64]; + char foundation[32]; + char type[6]; + unsigned int priority; + unsigned int componentID; + unsigned int port; + int nb; + + /* Allocate the ICE check list if it has not been done yet. */ + if (desc->streams[i].ice_check_list == NULL) desc->streams[i].ice_check_list = ice_check_list_new(); + nb = sscanf(attr->a_att_value, "%s %u UDP %u %s %u typ %s", + foundation, &componentID, &priority, ip, &port, type); + if (nb == 6) { + ice_add_remote_candidate(desc->streams[i].ice_check_list, type, ip, port, componentID, priority, foundation); + } + } else if ((keywordcmp("ice-ufrag", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { + ice_ufrag = attr->a_att_value; + } else if ((keywordcmp("ice-pwd", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { + ice_pwd = attr->a_att_value; + } + } + if ((ice_ufrag != NULL) && (ice_pwd != NULL)) { + ice_check_list_set_remote_credentials(desc->streams[i].ice_check_list, ice_ufrag, ice_pwd); + } + if (desc->streams[i].ice_check_list) ice_dump_candidates(desc->streams[i].ice_check_list); + } + /* Get ICE remote ufrag and remote pwd */ + ice_ufrag = ice_pwd = NULL; + for (i = 0; (i < SAL_MEDIA_DESCRIPTION_MAX_MESSAGE_ATTRIBUTES) && ((attr = sdp_message_attribute_get(msg, -1, i)) != NULL); i++) { + if ((keywordcmp("ice-ufrag", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { + ice_ufrag = attr->a_att_value; + } else if ((keywordcmp("ice-pwd", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { + ice_pwd = attr->a_att_value; + } + } + if ((ice_ufrag != NULL) && (ice_pwd != NULL)) { + ms_error("ufrag: %s, pwd: %s", ice_ufrag, ice_pwd); + //ice_session_set_remote_credentials(session, ice_ufrag, ice_pwd); } desc->nstreams=i; return 0; From 3020133c80812309e30ed471c991be46af824b46 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 18 Jul 2012 16:24:03 +0200 Subject: [PATCH 12/74] Allocate ICE session when parsing SDP on incoming call. --- coreapi/linphonecall.c | 4 ++-- coreapi/sal_eXosip2_sdp.c | 14 ++++++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 4e9e4b118..b1f5ee494 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -245,7 +245,7 @@ static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, Li md->streams[i].crypto[1].algo = 0; md->streams[i].crypto[2].algo = 0; } - if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce){ + if ((call->dir == LinphoneCallOutgoing) && (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce)){ md->streams[i].ice_check_list = ice_check_list_new(); ice_session_add_check_list(call->ice_session, md->streams[i].ice_check_list); } @@ -388,7 +388,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro linphone_call_init_common(call, from, to); linphone_core_init_default_params(lc, &call->params); call->params.has_video &= !!lc->video_policy.automatically_accept; - if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) call->ice_session=ice_session_new(); + if (((SalOpBase *)op)->remote_media->streams[0].ice_check_list != NULL) call->ice_session=((SalOpBase *)op)->remote_media->streams[0].ice_check_list->session; call->localdesc=create_local_media_description (lc,call); call->camera_active=call->params.has_video; if (linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseStun) diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 08deb7d5c..710c58072 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -390,6 +390,7 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ int i,j; const char *mtype,*proto,*port,*addr,*number; const char *ice_ufrag, *ice_pwd; + IceSession *ice_session = NULL; sdp_bandwidth_t *sbw=NULL; sdp_attribute_t *attr; int media_attribute_nb; @@ -512,8 +513,13 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ unsigned int port; int nb; + /* Allocate the ICE session if it has not been done yet. */ + if (ice_session == NULL) ice_session = ice_session_new(); /* Allocate the ICE check list if it has not been done yet. */ - if (desc->streams[i].ice_check_list == NULL) desc->streams[i].ice_check_list = ice_check_list_new(); + if (desc->streams[i].ice_check_list == NULL) { + desc->streams[i].ice_check_list = ice_check_list_new(); + ice_session_add_check_list(ice_session, desc->streams[i].ice_check_list); + } nb = sscanf(attr->a_att_value, "%s %u UDP %u %s %u typ %s", foundation, &componentID, &priority, ip, &port, type); if (nb == 6) { @@ -539,9 +545,9 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ ice_pwd = attr->a_att_value; } } - if ((ice_ufrag != NULL) && (ice_pwd != NULL)) { - ms_error("ufrag: %s, pwd: %s", ice_ufrag, ice_pwd); - //ice_session_set_remote_credentials(session, ice_ufrag, ice_pwd); + if ((ice_session != NULL) && (ice_ufrag != NULL) && (ice_pwd != NULL)) { + ice_session_set_remote_credentials(ice_session, ice_ufrag, ice_pwd); + ice_dump_session(ice_session); } desc->nstreams=i; return 0; From 2ef1e7c9cdfd521d2cc1c6c941096a3910ea731a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 18 Jul 2012 16:51:49 +0200 Subject: [PATCH 13/74] Gather ICE candidates on incoming call. --- coreapi/linphonecall.c | 20 ++++++++++++++++---- coreapi/misc.c | 35 ++++++++++++++++++++--------------- coreapi/sal_eXosip2_sdp.c | 16 +++++++++++++--- 3 files changed, 49 insertions(+), 22 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index b1f5ee494..c36b341ec 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -342,7 +342,10 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr 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) call->ice_session=ice_session_new(); + if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) { + call->ice_session=ice_session_new(); + ice_session_set_role(call->ice_session, IR_Controlling); + } call->localdesc=create_local_media_description (lc,call); call->camera_active=params->has_video; switch (linphone_core_get_firewall_policy(call->core)) { @@ -388,11 +391,20 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro linphone_call_init_common(call, from, to); linphone_core_init_default_params(lc, &call->params); call->params.has_video &= !!lc->video_policy.automatically_accept; - if (((SalOpBase *)op)->remote_media->streams[0].ice_check_list != NULL) call->ice_session=((SalOpBase *)op)->remote_media->streams[0].ice_check_list->session; + if (sal_call_get_remote_media_description(call->op)->streams[0].ice_check_list != NULL) + call->ice_session=sal_call_get_remote_media_description(call->op)->streams[0].ice_check_list->session; call->localdesc=create_local_media_description (lc,call); call->camera_active=call->params.has_video; - if (linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseStun) - linphone_core_run_stun_tests(call->core,call); + 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; + } discover_mtu(lc,linphone_address_get_domain(from)); return call; } diff --git a/coreapi/misc.c b/coreapi/misc.c index fd3a8716e..f7e6feb64 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -574,6 +574,8 @@ void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) bool_t video_responses[2]; IceCandidate *audio_ice_bases[2]; IceCandidate *video_ice_bases[2]; + IceCheckList *audio_check_list; + IceCheckList *video_check_list; struct sockaddr_storage ss; socklen_t ss_len; struct timeval init, cur; @@ -598,6 +600,14 @@ void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) video_responses[0] = video_responses[1] = FALSE; audio_ice_bases[0] = audio_ice_bases[1] = NULL; video_ice_bases[0] = video_ice_bases[1] = NULL; + if (call->dir == LinphoneCallOutgoing) { + audio_check_list = call->localdesc->streams[0].ice_check_list; + video_check_list = call->localdesc->streams[1].ice_check_list; + } else { + SalMediaDescription *md = sal_call_get_remote_media_description(call->op); + audio_check_list = md->streams[0].ice_check_list; + video_check_list = md->streams[1].ice_check_list; + } audio_socks[0] = create_socket(call->audio_port); if (audio_socks[0] == -1) return; audio_socks[1] = create_socket(call->audio_port + 1); @@ -614,16 +624,11 @@ void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) ms_error("Fail to get local ip"); return; } - if (call->dir == LinphoneCallOutgoing) { - ice_session_set_role(call->ice_session, IR_Controlling); - } else { - ice_session_set_role(call->ice_session, IR_Controlled); - } - audio_ice_bases[0] = ice_add_local_candidate(call->localdesc->streams[0].ice_check_list, "host", local_addr, call->audio_port, 1, NULL); - audio_ice_bases[1] = ice_add_local_candidate(call->localdesc->streams[0].ice_check_list, "host", local_addr, call->audio_port + 1, 2, NULL); + audio_ice_bases[0] = ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port, 1, NULL); + audio_ice_bases[1] = ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port + 1, 2, NULL); if (call->params.has_video) { - video_ice_bases[0] = ice_add_local_candidate(call->localdesc->streams[1].ice_check_list, "host", local_addr, call->video_port, 1, NULL); - video_ice_bases[1] = ice_add_local_candidate(call->localdesc->streams[1].ice_check_list, "host", local_addr, call->video_port + 1, 2, NULL); + video_ice_bases[0] = ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port, 1, NULL); + video_ice_bases[1] = ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port + 1, 2, NULL); } gettimeofday(&init, NULL); @@ -644,20 +649,20 @@ void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) #endif if (recvStunResponse(audio_socks[0], addr, &port, &id) > 0) { - ice_add_local_candidate(call->localdesc->streams[0].ice_check_list, "srflx", addr, port, 1, audio_ice_bases[0]); + ice_add_local_candidate(audio_check_list, "srflx", addr, port, 1, audio_ice_bases[0]); audio_responses[0] = TRUE; } if (recvStunResponse(audio_socks[1], addr, &port, &id) > 0) { - ice_add_local_candidate(call->localdesc->streams[0].ice_check_list, "srflx", addr, port, 2, audio_ice_bases[1]); + ice_add_local_candidate(audio_check_list, "srflx", addr, port, 2, audio_ice_bases[1]); audio_responses[1] = TRUE; } if (call->params.has_video) { if (recvStunResponse(video_socks[0], addr, &port, &id) > 0) { - ice_add_local_candidate(call->localdesc->streams[1].ice_check_list, "srflx", addr, port, 1, video_ice_bases[0]); + ice_add_local_candidate(video_check_list, "srflx", addr, port, 1, video_ice_bases[0]); video_responses[0] = TRUE; } if (recvStunResponse(video_socks[1], addr, &port, &id) > 0) { - ice_add_local_candidate(call->localdesc->streams[1].ice_check_list, "srflx", addr, port, 2, video_ice_bases[1]); + ice_add_local_candidate(video_check_list, "srflx", addr, port, 2, video_ice_bases[1]); video_responses[1] = TRUE; } } @@ -677,11 +682,11 @@ void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) close_socket(audio_socks[0]); close_socket(audio_socks[1]); - ice_dump_candidates(call->localdesc->streams[0].ice_check_list); + ice_dump_candidates(audio_check_list); if (call->params.has_video) { if (video_socks[0] != -1) close_socket(video_socks[0]); if (video_socks[1] != -1) close_socket(video_socks[1]); - ice_dump_candidates(call->localdesc->streams[1].ice_check_list); + ice_dump_candidates(video_check_list); } } diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 710c58072..4faad395f 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -394,6 +394,7 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ sdp_bandwidth_t *sbw=NULL; sdp_attribute_t *attr; int media_attribute_nb; + bool_t ice_lite = FALSE; addr=sdp_message_c_addr_get (msg, -1, 0); if (addr) @@ -543,11 +544,20 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ ice_ufrag = attr->a_att_value; } else if ((keywordcmp("ice-pwd", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { ice_pwd = attr->a_att_value; + } else if (keywordcmp("ice-lite", attr->a_att_field) == 0) { + ice_lite = TRUE; } } - if ((ice_session != NULL) && (ice_ufrag != NULL) && (ice_pwd != NULL)) { - ice_session_set_remote_credentials(ice_session, ice_ufrag, ice_pwd); - ice_dump_session(ice_session); + if (ice_session != NULL) { + if (ice_lite == TRUE) { + ice_session_set_role(ice_session, IR_Controlling); + } else { + ice_session_set_role(ice_session, IR_Controlled); + } + if ((ice_ufrag != NULL) && (ice_pwd != NULL)) { + ice_session_set_remote_credentials(ice_session, ice_ufrag, ice_pwd); + ice_dump_session(ice_session); + } } desc->nstreams=i; return 0; From 91c9eff049cb492c4fcdbe977f0d2fc3927b53c6 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 19 Jul 2012 09:43:28 +0200 Subject: [PATCH 14/74] Copy ICE check list pointers between media descriptions. --- coreapi/linphonecall.c | 14 ++++++++++---- coreapi/misc.c | 10 ++-------- coreapi/offeranswer.c | 3 +++ 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index c36b341ec..28bc348b2 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -249,6 +249,12 @@ static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, Li md->streams[i].ice_check_list = ice_check_list_new(); ice_session_add_check_list(call->ice_session, md->streams[i].ice_check_list); } + if ((call->dir == LinphoneCallIncoming) && (sal_call_get_remote_media_description(call->op)->streams[i].ice_check_list != NULL)) { + md->streams[i].ice_check_list = sal_call_get_remote_media_description(call->op)->streams[i].ice_check_list; + } + } + if ((call->dir == LinphoneCallIncoming) && (md->streams[0].ice_check_list != NULL)) { + call->ice_session=md->streams[0].ice_check_list->session; } linphone_address_destroy(addr); @@ -391,8 +397,6 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro linphone_call_init_common(call, from, to); linphone_core_init_default_params(lc, &call->params); call->params.has_video &= !!lc->video_policy.automatically_accept; - if (sal_call_get_remote_media_description(call->op)->streams[0].ice_check_list != NULL) - call->ice_session=sal_call_get_remote_media_description(call->op)->streams[0].ice_check_list->session; call->localdesc=create_local_media_description (lc,call); call->camera_active=call->params.has_video; switch (linphone_core_get_firewall_policy(call->core)) { @@ -969,7 +973,8 @@ void linphone_call_init_media_streams(LinphoneCall *call){ } if (linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce){ rtp_session_set_pktinfo(audiostream->session,TRUE); - audiostream->ice_check_list = call->localdesc->streams[0].ice_check_list; + if (call->dir == LinphoneCallOutgoing) audiostream->ice_check_list = call->localdesc->streams[0].ice_check_list; + else audiostream->ice_check_list = sal_call_get_remote_media_description(call->op)->streams[0].ice_check_list; ice_check_list_register_success_cb(audiostream->ice_check_list, audio_stream_set_remote_from_ice, audiostream); } @@ -994,7 +999,8 @@ void linphone_call_init_media_streams(LinphoneCall *call){ } if (linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce){ rtp_session_set_pktinfo(call->videostream->session,TRUE); - call->videostream->ice_check_list = call->localdesc->streams[1].ice_check_list; + if (call->dir == LinphoneCallOutgoing) call->videostream->ice_check_list = call->localdesc->streams[1].ice_check_list; + else call->videostream->ice_check_list = sal_call_get_remote_media_description(call->op)->streams[1].ice_check_list; ice_check_list_register_success_cb(call->videostream->ice_check_list, video_stream_set_remote_from_ice, call->videostream); } call->videostream_app_evq = ortp_ev_queue_new(); diff --git a/coreapi/misc.c b/coreapi/misc.c index f7e6feb64..2ef0e04bf 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -600,14 +600,8 @@ void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) video_responses[0] = video_responses[1] = FALSE; audio_ice_bases[0] = audio_ice_bases[1] = NULL; video_ice_bases[0] = video_ice_bases[1] = NULL; - if (call->dir == LinphoneCallOutgoing) { - audio_check_list = call->localdesc->streams[0].ice_check_list; - video_check_list = call->localdesc->streams[1].ice_check_list; - } else { - SalMediaDescription *md = sal_call_get_remote_media_description(call->op); - audio_check_list = md->streams[0].ice_check_list; - video_check_list = md->streams[1].ice_check_list; - } + audio_check_list = call->localdesc->streams[0].ice_check_list; + video_check_list = call->localdesc->streams[1].ice_check_list; audio_socks[0] = create_socket(call->audio_port); if (audio_socks[0] == -1) return; audio_socks[1] = create_socket(call->audio_port + 1); diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index 5a2b4f527..7b6ce018f 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -223,6 +223,7 @@ static void initiate_outgoing(const SalStreamDescription *local_offer, if (!match_crypto_algo(local_offer->crypto, remote_answer->crypto, &result->crypto[0], &result->crypto_local_tag, FALSE)) result->port = 0; } + result->ice_check_list = remote_answer->ice_check_list; } @@ -249,6 +250,7 @@ static void initiate_incoming(const SalStreamDescription *local_cap, result->port = 0; } + result->ice_check_list = local_cap->ice_check_list; } /** @@ -309,6 +311,7 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities if (rs->type==SalOther){ strncpy(result->streams[i].typeother,rs->typeother,sizeof(rs->typeother)-1); } + result->streams[i].ice_check_list = remote_offer->streams[i].ice_check_list; } } result->nstreams=i; From 6857091ea9bf171dfcb85b11295f7ef7861b279c Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 19 Jul 2012 14:13:37 +0200 Subject: [PATCH 15/74] Moved ICE session and check lists respectively from LinphoneCall and SalMediaDescription to SalOp. --- coreapi/linphonecall.c | 37 ++++++++------------- coreapi/misc.c | 19 ++++++----- coreapi/offeranswer.c | 3 -- coreapi/private.h | 1 - coreapi/sal.c | 10 ++++++ coreapi/sal.h | 4 ++- coreapi/sal_eXosip2.c | 37 ++++++++++++++------- coreapi/sal_eXosip2.h | 4 +-- coreapi/sal_eXosip2_sdp.c | 67 ++++++++++++++++++++------------------- 9 files changed, 100 insertions(+), 82 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 28bc348b2..5689f8dd3 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -201,7 +201,7 @@ static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, Li LinphoneAddress *addr=linphone_address_new(me); const char *username=linphone_address_get_username (addr); SalMediaDescription *md=sal_media_description_new(); - + IceSession *ice_session=sal_op_get_ice_session(call->op); md->session_id=session_id; md->session_ver=session_ver; @@ -245,16 +245,9 @@ static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, Li md->streams[i].crypto[1].algo = 0; md->streams[i].crypto[2].algo = 0; } - if ((call->dir == LinphoneCallOutgoing) && (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce)){ - md->streams[i].ice_check_list = ice_check_list_new(); - ice_session_add_check_list(call->ice_session, md->streams[i].ice_check_list); + if ((call->dir == LinphoneCallOutgoing) && (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) && (ice_session != NULL)){ + ice_session_add_check_list(ice_session, ice_check_list_new()); } - if ((call->dir == LinphoneCallIncoming) && (sal_call_get_remote_media_description(call->op)->streams[i].ice_check_list != NULL)) { - md->streams[i].ice_check_list = sal_call_get_remote_media_description(call->op)->streams[i].ice_check_list; - } - } - if ((call->dir == LinphoneCallIncoming) && (md->streams[0].ice_check_list != NULL)) { - call->ice_session=md->streams[0].ice_check_list->session; } linphone_address_destroy(addr); @@ -349,8 +342,8 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr linphone_call_init_common(call,from,to); call->params=*params; if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) { - call->ice_session=ice_session_new(); - ice_session_set_role(call->ice_session, IR_Controlling); + sal_op_set_ice_session(call->op, ice_session_new()); + ice_session_set_role(sal_op_get_ice_session(call->op), IR_Controlling); } call->localdesc=create_local_media_description (lc,call); call->camera_active=params->has_video; @@ -555,10 +548,6 @@ static void linphone_call_destroy(LinphoneCall *obj) sal_op_release(obj->op); obj->op=NULL; } - if (obj->ice_session!=NULL) { - ice_session_destroy(obj->ice_session); - obj->ice_session=NULL; - } if (obj->resultdesc!=NULL) { sal_media_description_unref(obj->resultdesc); obj->resultdesc=NULL; @@ -939,6 +928,7 @@ void linphone_call_init_media_streams(LinphoneCall *call){ LinphoneCore *lc=call->core; SalMediaDescription *md=call->localdesc; AudioStream *audiostream; + IceSession *ice_session = sal_op_get_ice_session(call->op); call->audiostream=audiostream=audio_stream_new(md->streams[0].port,linphone_core_ipv6_enabled(lc)); if (linphone_core_echo_limiter_enabled(lc)){ @@ -971,10 +961,9 @@ void linphone_call_init_media_streams(LinphoneCall *call){ RtpTransport *artcp=lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->audio_port+1); rtp_session_set_transports(audiostream->session,artp,artcp); } - if (linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce){ - rtp_session_set_pktinfo(audiostream->session,TRUE); - if (call->dir == LinphoneCallOutgoing) audiostream->ice_check_list = call->localdesc->streams[0].ice_check_list; - else audiostream->ice_check_list = sal_call_get_remote_media_description(call->op)->streams[0].ice_check_list; + 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_register_success_cb(audiostream->ice_check_list, audio_stream_set_remote_from_ice, audiostream); } @@ -997,10 +986,9 @@ void linphone_call_init_media_streams(LinphoneCall *call){ RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->video_port+1); rtp_session_set_transports(call->videostream->session,vrtp,vrtcp); } - if (linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce){ - rtp_session_set_pktinfo(call->videostream->session,TRUE); - if (call->dir == LinphoneCallOutgoing) call->videostream->ice_check_list = call->localdesc->streams[1].ice_check_list; - else call->videostream->ice_check_list = sal_call_get_remote_media_description(call->op)->streams[1].ice_check_list; + 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_register_success_cb(call->videostream->ice_check_list, video_stream_set_remote_from_ice, call->videostream); } call->videostream_app_evq = ortp_ev_queue_new(); @@ -1452,6 +1440,7 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut /*also reflect the change if the "wished" params, in order to avoid to propose SAVP or video again * further in the call, for example during pause,resume, conferencing reINVITEs*/ linphone_call_fix_call_parameters(call); + if (sal_op_get_ice_session(call->op) != NULL) ice_session_pair_candidates(sal_op_get_ice_session(call->op)); goto end; end: diff --git a/coreapi/misc.c b/coreapi/misc.c index 2ef0e04bf..1dadcb335 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -576,6 +576,7 @@ void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) IceCandidate *video_ice_bases[2]; 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; @@ -583,7 +584,11 @@ void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) int loops = 0; const char *server = linphone_core_get_stun_server(lc); - if (server == NULL) return; + if ((server == NULL) || (ice_session == NULL)) return; + 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 (lc->sip_conf.ipv6_enabled){ ms_warning("stun support is not implemented for ipv6"); return; @@ -600,8 +605,6 @@ void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) video_responses[0] = video_responses[1] = FALSE; audio_ice_bases[0] = audio_ice_bases[1] = NULL; video_ice_bases[0] = video_ice_bases[1] = NULL; - audio_check_list = call->localdesc->streams[0].ice_check_list; - video_check_list = call->localdesc->streams[1].ice_check_list; audio_socks[0] = create_socket(call->audio_port); if (audio_socks[0] == -1) return; audio_socks[1] = create_socket(call->audio_port + 1); @@ -620,7 +623,7 @@ void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) } audio_ice_bases[0] = ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port, 1, NULL); audio_ice_bases[1] = ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port + 1, 2, NULL); - if (call->params.has_video) { + if (call->params.has_video && (video_check_list != NULL)) { video_ice_bases[0] = ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port, 1, NULL); video_ice_bases[1] = ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port + 1, 2, NULL); } @@ -650,7 +653,7 @@ void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) ice_add_local_candidate(audio_check_list, "srflx", addr, port, 2, audio_ice_bases[1]); audio_responses[1] = TRUE; } - if (call->params.has_video) { + if (call->params.has_video && (video_check_list != NULL)) { if (recvStunResponse(video_socks[0], addr, &port, &id) > 0) { ice_add_local_candidate(video_check_list, "srflx", addr, port, 1, video_ice_bases[0]); video_responses[0] = TRUE; @@ -671,13 +674,13 @@ void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) } while (!((audio_responses[0] == TRUE) && (audio_responses[1] == TRUE) && (!call->params.has_video || ((video_responses[0] == TRUE) && (video_responses[1] == TRUE))))); - ice_session_compute_candidates_foundations(call->ice_session); - ice_session_choose_default_candidates(call->ice_session); + ice_session_compute_candidates_foundations(ice_session); + ice_session_choose_default_candidates(ice_session); close_socket(audio_socks[0]); close_socket(audio_socks[1]); ice_dump_candidates(audio_check_list); - if (call->params.has_video) { + if (call->params.has_video && (video_check_list != NULL)) { if (video_socks[0] != -1) close_socket(video_socks[0]); if (video_socks[1] != -1) close_socket(video_socks[1]); ice_dump_candidates(video_check_list); diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index 7b6ce018f..5a2b4f527 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -223,7 +223,6 @@ static void initiate_outgoing(const SalStreamDescription *local_offer, if (!match_crypto_algo(local_offer->crypto, remote_answer->crypto, &result->crypto[0], &result->crypto_local_tag, FALSE)) result->port = 0; } - result->ice_check_list = remote_answer->ice_check_list; } @@ -250,7 +249,6 @@ static void initiate_incoming(const SalStreamDescription *local_cap, result->port = 0; } - result->ice_check_list = local_cap->ice_check_list; } /** @@ -311,7 +309,6 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities if (rs->type==SalOther){ strncpy(result->streams[i].typeother,rs->typeother,sizeof(rs->typeother)-1); } - result->streams[i].ice_check_list = remote_offer->streams[i].ice_check_list; } } result->nstreams=i; diff --git a/coreapi/private.h b/coreapi/private.h index 2a2cd7816..241da0223 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -136,7 +136,6 @@ struct _LinphoneCall bool_t was_automatically_paused; CallCallbackObj nextVideoFrameDecoded; LinphoneCallStats stats[2]; - IceSession *ice_session; }; diff --git a/coreapi/sal.c b/coreapi/sal.c index 874c3716d..37e56fade 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -232,6 +232,10 @@ void sal_op_set_user_pointer(SalOp *op, void *up){ ((SalOpBase*)op)->user_pointer=up; } +void sal_op_set_ice_session(SalOp *op, IceSession *ice_session){ + ((SalOpBase*)op)->ice_session=ice_session; +} + Sal *sal_op_get_sal(const SalOp *op){ return ((SalOpBase*)op)->root; } @@ -260,6 +264,10 @@ void *sal_op_get_user_pointer(const SalOp *op){ return ((SalOpBase*)op)->user_pointer; } +IceSession *sal_op_get_ice_session(const SalOp *op){ + return ((SalOpBase*)op)->ice_session; +} + const char *sal_op_get_proxy(const SalOp *op){ return ((SalOpBase*)op)->route; } @@ -308,6 +316,8 @@ void __sal_op_free(SalOp *op){ sal_media_description_unref(b->local_media); if (b->remote_media) sal_media_description_unref(b->remote_media); + if (b->ice_session) + ice_session_destroy(b->ice_session); ms_free(op); } diff --git a/coreapi/sal.h b/coreapi/sal.h index 8bd2523fd..8782226b8 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -136,7 +136,6 @@ typedef struct SalStreamDescription{ SalSrtpCryptoAlgo crypto[SAL_CRYPTO_ALGO_MAX]; unsigned int crypto_local_tag; int max_rate; - IceCheckList *ice_check_list; } SalStreamDescription; #define SAL_MEDIA_DESCRIPTION_MAX_STREAMS 4 @@ -176,6 +175,7 @@ typedef struct SalOpBase{ char *remote_ua; SalMediaDescription *local_media; SalMediaDescription *remote_media; + IceSession *ice_session; void *user_pointer; } SalOpBase; @@ -320,6 +320,7 @@ void sal_op_release(SalOp *h); void sal_op_authenticate(SalOp *h, const SalAuthInfo *info); void sal_op_cancel_authentication(SalOp *h); void sal_op_set_user_pointer(SalOp *h, void *up); +void sal_op_set_ice_session(SalOp *h, IceSession *ice_session); int sal_op_get_auth_requested(SalOp *h, const char **realm, const char **username); const char *sal_op_get_from(const SalOp *op); const char *sal_op_get_to(const SalOp *op); @@ -331,6 +332,7 @@ const char *sal_op_get_network_origin(const SalOp *op); /*returns far-end "User-Agent" string */ const char *sal_op_get_remote_ua(const SalOp *op); void *sal_op_get_user_pointer(const SalOp *op); +IceSession *sal_op_get_ice_session(const SalOp *op); /*Call API*/ int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc); diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 8333f1554..62eddddb8 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -502,8 +502,8 @@ static void set_sdp(osip_message_t *sip,sdp_message_t *msg){ osip_free(sdp); } -static void set_sdp_from_desc(osip_message_t *sip, const SalMediaDescription *desc){ - sdp_message_t *msg=media_description_to_sdp(desc); +static void set_sdp_from_desc(osip_message_t *sip, const SalMediaDescription *desc, const IceSession *ice_session){ + sdp_message_t *msg=media_description_to_sdp(desc, ice_session); if (msg==NULL) { ms_error("Fail to print sdp message !"); return; @@ -526,7 +526,7 @@ static void sdp_process(SalOp *h){ sdp_message_free(h->sdp_answer); } offer_answer_initiate_incoming(h->base.local_media,h->base.remote_media,h->result,h->base.root->one_matching_codec); - h->sdp_answer=media_description_to_sdp(h->result); + h->sdp_answer=media_description_to_sdp(h->result, sal_op_get_ice_session(h)); /*once we have generated the SDP answer, we modify the result description for processing by the upper layer. It should contains media parameters constraint from the remote offer, not our response*/ strcpy(h->result->addr,h->base.remote_media->addr); @@ -598,7 +598,7 @@ int sal_call(SalOp *h, const char *from, const char *to){ } if (h->base.local_media){ h->sdp_offering=TRUE; - set_sdp_from_desc(invite,h->base.local_media); + set_sdp_from_desc(invite,h->base.local_media,sal_op_get_ice_session(h)); }else h->sdp_offering=FALSE; if (h->replaces){ osip_message_set_header(invite,"Replaces",h->replaces); @@ -666,7 +666,7 @@ int sal_call_accept(SalOp * h){ if (h->base.local_media){ /*this is the case where we received an invite without SDP*/ if (h->sdp_offering) { - set_sdp_from_desc(msg,h->base.local_media); + set_sdp_from_desc(msg,h->base.local_media,sal_op_get_ice_session(h)); }else{ if (h->sdp_answer==NULL) sdp_process(h); if (h->sdp_answer){ @@ -988,6 +988,7 @@ static void inc_new_call(Sal *sal, eXosip_event_t *ev){ osip_call_info_t *call_info; char *tmp; sdp_message_t *sdp=eXosip_get_sdp_info(ev->request); + IceSession *ice_session; set_network_origin(op,ev->request); set_remote_ua(op,ev->request); @@ -996,7 +997,9 @@ static void inc_new_call(Sal *sal, eXosip_event_t *ev){ if (sdp){ op->sdp_offering=FALSE; op->base.remote_media=sal_media_description_new(); - sdp_to_media_description(sdp,op->base.remote_media); + ice_session=sal_op_get_ice_session(op); + sdp_to_media_description(sdp,op->base.remote_media,&ice_session); + sal_op_set_ice_session(op,ice_session); sdp_message_free(sdp); }else op->sdp_offering=TRUE; @@ -1032,6 +1035,7 @@ static void inc_new_call(Sal *sal, eXosip_event_t *ev){ static void handle_reinvite(Sal *sal, eXosip_event_t *ev){ SalOp *op=find_op(sal,ev); sdp_message_t *sdp; + IceSession *ice_session; if (op==NULL) { ms_warning("Reinvite for non-existing operation !"); @@ -1051,7 +1055,9 @@ static void handle_reinvite(Sal *sal, eXosip_event_t *ev){ if (sdp){ op->sdp_offering=FALSE; op->base.remote_media=sal_media_description_new(); - sdp_to_media_description(sdp,op->base.remote_media); + ice_session=sal_op_get_ice_session(op); + sdp_to_media_description(sdp,op->base.remote_media,&ice_session); + sal_op_set_ice_session(op,ice_session); sdp_message_free(sdp); }else { @@ -1063,6 +1069,7 @@ static void handle_reinvite(Sal *sal, eXosip_event_t *ev){ static void handle_ack(Sal *sal, eXosip_event_t *ev){ SalOp *op=find_op(sal,ev); sdp_message_t *sdp; + IceSession *ice_session; if (op==NULL) { ms_warning("ack for non-existing call !"); @@ -1079,7 +1086,9 @@ static void handle_ack(Sal *sal, eXosip_event_t *ev){ if (op->base.remote_media) sal_media_description_unref(op->base.remote_media); op->base.remote_media=sal_media_description_new(); - sdp_to_media_description(sdp,op->base.remote_media); + ice_session=sal_op_get_ice_session(op); + sdp_to_media_description(sdp,op->base.remote_media,&ice_session); + sal_op_set_ice_session(op,ice_session); sdp_process(op); sdp_message_free(sdp); } @@ -1139,13 +1148,16 @@ static int call_proceeding(Sal *sal, eXosip_event_t *ev){ static void call_ringing(Sal *sal, eXosip_event_t *ev){ sdp_message_t *sdp; SalOp *op=find_op(sal,ev); + IceSession *ice_session; if (call_proceeding(sal, ev)==-1) return; set_remote_ua(op,ev->response); sdp=eXosip_get_sdp_info(ev->response); if (sdp){ op->base.remote_media=sal_media_description_new(); - sdp_to_media_description(sdp,op->base.remote_media); + ice_session=sal_op_get_ice_session(op); + sdp_to_media_description(sdp,op->base.remote_media,&ice_session); + sal_op_set_ice_session(op,ice_session); sdp_message_free(sdp); if (op->base.local_media) sdp_process(op); } @@ -1157,6 +1169,7 @@ static void call_accepted(Sal *sal, eXosip_event_t *ev){ osip_message_t *msg=NULL; SalOp *op=find_op(sal,ev); const char *contact; + IceSession *ice_session; if (op==NULL || op->terminated==TRUE) { ms_warning("This call has been already terminated."); @@ -1172,7 +1185,9 @@ static void call_accepted(Sal *sal, eXosip_event_t *ev){ sdp=eXosip_get_sdp_info(ev->response); if (sdp){ op->base.remote_media=sal_media_description_new(); - sdp_to_media_description(sdp,op->base.remote_media); + ice_session=sal_op_get_ice_session(op); + sdp_to_media_description(sdp,op->base.remote_media,&ice_session); + sal_op_set_ice_session(op,ice_session); sdp_message_free(sdp); if (op->base.local_media) sdp_process(op); } @@ -2410,7 +2425,7 @@ int sal_call_update(SalOp *h, const char *subject){ } if (h->base.local_media){ h->sdp_offering=TRUE; - set_sdp_from_desc(reinvite,h->base.local_media); + set_sdp_from_desc(reinvite,h->base.local_media,sal_op_get_ice_session(h)); }else h->sdp_offering=FALSE; eXosip_lock(); err = eXosip_call_send_request(h->did, reinvite); diff --git a/coreapi/sal_eXosip2.h b/coreapi/sal_eXosip2.h index ccc95d56a..e3264f74d 100644 --- a/coreapi/sal_eXosip2.h +++ b/coreapi/sal_eXosip2.h @@ -25,8 +25,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -sdp_message_t *media_description_to_sdp(const SalMediaDescription *sal); -int sdp_to_media_description(sdp_message_t *sdp, SalMediaDescription *desc); +sdp_message_t *media_description_to_sdp(const SalMediaDescription *sal, const IceSession *ice_session); +int sdp_to_media_description(sdp_message_t *sdp, SalMediaDescription *desc, IceSession **ice_session); struct Sal{ SalCallbacks callbacks; diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 4faad395f..16e709718 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -124,7 +124,7 @@ static int _sdp_message_get_mline_dir(sdp_message_t *sdp, int mline){ return SalStreamSendRecv; } -static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc) +static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc, const IceSession *ice_session) { sdp_message_t *local; int inet6; @@ -144,8 +144,8 @@ static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc) osip_strdup ("IN"), inet6 ? osip_strdup("IP6") : osip_strdup ("IP4"), osip_strdup (desc->addr)); sdp_message_s_name_set (local, osip_strdup ("Talk")); - if (desc->streams[0].ice_check_list != NULL) { - const IceCandidate *candidate = ice_check_list_default_local_candidate(desc->streams[0].ice_check_list); + if ((ice_session != NULL) && (ice_session_check_list(ice_session, 0) != NULL)) { + const IceCandidate *candidate = ice_check_list_default_local_candidate(ice_session_check_list(ice_session, 0)); if (candidate != NULL) { addr=candidate->taddr.ip; } @@ -165,11 +165,11 @@ static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc) sdp_message_t_time_descr_add (local, osip_strdup ("0"), osip_strdup ("0")); if (desc->bandwidth>0) sdp_message_b_bandwidth_add (local, -1, osip_strdup ("AS"), int_2char(desc->bandwidth)); - if (desc->streams[0].ice_check_list != NULL) { + if ((ice_session != NULL) && (ice_session_check_list(ice_session, 0) != NULL)) { char buffer[512]; - snprintf(buffer ,sizeof(buffer), "%s", ice_session_local_pwd(desc->streams[0].ice_check_list->session)); + snprintf(buffer ,sizeof(buffer), "%s", ice_session_local_pwd(ice_session)); sdp_message_a_attribute_add(local, -1, osip_strdup("ice-pwd"), osip_strdup(buffer)); - snprintf(buffer ,sizeof(buffer), "%s", ice_session_local_ufrag(desc->streams[0].ice_check_list->session)); + snprintf(buffer ,sizeof(buffer), "%s", ice_session_local_ufrag(ice_session)); sdp_message_a_attribute_add(local, -1, osip_strdup("ice-ufrag"), osip_strdup(buffer)); } @@ -212,15 +212,15 @@ static void add_payload(sdp_message_t *msg, int line, const PayloadType *pt, boo } } -static void add_ice_candidates(sdp_message_t *msg, int lineno, const SalStreamDescription *desc) +static void add_ice_candidates(sdp_message_t *msg, int lineno, const SalStreamDescription *desc, const IceCheckList *ice_cl) { char buffer[1024]; const IceCandidate *candidate; int i; - if (desc->ice_check_list != NULL) { - for (i = 0; i < ms_list_size(desc->ice_check_list->local_candidates); i++) { - candidate = ms_list_nth_data(desc->ice_check_list->local_candidates, i); + if (ice_cl != NULL) { + for (i = 0; i < ms_list_size(ice_cl->local_candidates); i++) { + candidate = ms_list_nth_data(ice_cl->local_candidates, i); snprintf(buffer, sizeof(buffer), "%s %d UDP %d %s %d typ %s", candidate->foundation, candidate->componentID, candidate->priority, candidate->taddr.ip, candidate->taddr.port, ice_candidate_type(candidate)); sdp_message_a_attribute_add(msg, lineno, osip_strdup("candidate"), osip_strdup(buffer)); @@ -229,7 +229,7 @@ static void add_ice_candidates(sdp_message_t *msg, int lineno, const SalStreamDe } -static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription *desc){ +static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription *desc, const IceCheckList *ice_cl){ const char *mt=NULL; const MSList *elem; const char *addr; @@ -250,8 +250,8 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription } addr=desc->addr; port=desc->port; - if (desc->ice_check_list != NULL) { - const IceCandidate *candidate = ice_check_list_default_local_candidate(desc->ice_check_list); + if (ice_cl != NULL) { + const IceCandidate *candidate = ice_check_list_default_local_candidate(ice_cl); if (candidate != NULL) { addr=candidate->taddr.ip; port=candidate->taddr.port; @@ -342,15 +342,18 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription break; } if (dir) sdp_message_a_attribute_add (msg, lineno, osip_strdup (dir),NULL); - add_ice_candidates(msg, lineno, desc); + add_ice_candidates(msg, lineno, desc, ice_cl); } -sdp_message_t *media_description_to_sdp(const SalMediaDescription *desc){ +sdp_message_t *media_description_to_sdp(const SalMediaDescription *desc, const IceSession *ice_session){ + IceCheckList *ice_cl = NULL; int i; - sdp_message_t *msg=create_generic_sdp(desc); + sdp_message_t *msg=create_generic_sdp(desc, ice_session); for(i=0;instreams;++i){ - add_line(msg,i,&desc->streams[i]); + if (ice_session != NULL) ice_cl = ice_session_check_list(ice_session, i); + else ice_cl = NULL; + add_line(msg,i,&desc->streams[i], ice_cl); } return msg; } @@ -386,11 +389,10 @@ static int payload_type_fill_from_rtpmap(PayloadType *pt, const char *rtpmap){ return 0; } -int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ +int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc, IceSession **ice_session){ int i,j; const char *mtype,*proto,*port,*addr,*number; const char *ice_ufrag, *ice_pwd; - IceSession *ice_session = NULL; sdp_bandwidth_t *sbw=NULL; sdp_attribute_t *attr; int media_attribute_nb; @@ -515,16 +517,15 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ int nb; /* Allocate the ICE session if it has not been done yet. */ - if (ice_session == NULL) ice_session = ice_session_new(); + if (*ice_session == NULL) *ice_session = ice_session_new(); /* Allocate the ICE check list if it has not been done yet. */ - if (desc->streams[i].ice_check_list == NULL) { - desc->streams[i].ice_check_list = ice_check_list_new(); - ice_session_add_check_list(ice_session, desc->streams[i].ice_check_list); + if (ice_session_check_list(*ice_session, i) == NULL) { + ice_session_add_check_list(*ice_session, ice_check_list_new()); } nb = sscanf(attr->a_att_value, "%s %u UDP %u %s %u typ %s", foundation, &componentID, &priority, ip, &port, type); if (nb == 6) { - ice_add_remote_candidate(desc->streams[i].ice_check_list, type, ip, port, componentID, priority, foundation); + ice_add_remote_candidate(ice_session_check_list(*ice_session, i), type, ip, port, componentID, priority, foundation); } } else if ((keywordcmp("ice-ufrag", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { ice_ufrag = attr->a_att_value; @@ -532,10 +533,12 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ ice_pwd = attr->a_att_value; } } - if ((ice_ufrag != NULL) && (ice_pwd != NULL)) { - ice_check_list_set_remote_credentials(desc->streams[i].ice_check_list, ice_ufrag, ice_pwd); + if ((*ice_session != NULL) && ice_session_check_list(*ice_session, i)) { + if ((ice_ufrag != NULL) && (ice_pwd != NULL)) { + ice_check_list_set_remote_credentials(ice_session_check_list(*ice_session, i), ice_ufrag, ice_pwd); + } + ice_dump_candidates(ice_session_check_list(*ice_session, i)); } - if (desc->streams[i].ice_check_list) ice_dump_candidates(desc->streams[i].ice_check_list); } /* Get ICE remote ufrag and remote pwd */ ice_ufrag = ice_pwd = NULL; @@ -548,15 +551,15 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ ice_lite = TRUE; } } - if (ice_session != NULL) { + if (*ice_session != NULL) { if (ice_lite == TRUE) { - ice_session_set_role(ice_session, IR_Controlling); + ice_session_set_role(*ice_session, IR_Controlling); } else { - ice_session_set_role(ice_session, IR_Controlled); + ice_session_set_role(*ice_session, IR_Controlled); } if ((ice_ufrag != NULL) && (ice_pwd != NULL)) { - ice_session_set_remote_credentials(ice_session, ice_ufrag, ice_pwd); - ice_dump_session(ice_session); + ice_session_set_remote_credentials(*ice_session, ice_ufrag, ice_pwd); + ice_dump_session(*ice_session); } } desc->nstreams=i; From 6066dbc5291cd86b5efafb899ee8df1b1cb856a1 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 20 Jul 2012 09:58:59 +0200 Subject: [PATCH 16/74] Fix ICE roles. --- coreapi/sal_eXosip2_sdp.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 16e709718..50c0047c3 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -396,6 +396,7 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc, IceS sdp_bandwidth_t *sbw=NULL; sdp_attribute_t *attr; int media_attribute_nb; + bool_t ice_session_just_created = FALSE; bool_t ice_lite = FALSE; addr=sdp_message_c_addr_get (msg, -1, 0); @@ -517,7 +518,10 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc, IceS int nb; /* Allocate the ICE session if it has not been done yet. */ - if (*ice_session == NULL) *ice_session = ice_session_new(); + if (*ice_session == NULL) { + *ice_session = ice_session_new(); + ice_session_just_created = TRUE; + } /* Allocate the ICE check list if it has not been done yet. */ if (ice_session_check_list(*ice_session, i) == NULL) { ice_session_add_check_list(*ice_session, ice_check_list_new()); @@ -552,10 +556,12 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc, IceS } } if (*ice_session != NULL) { - if (ice_lite == TRUE) { - ice_session_set_role(*ice_session, IR_Controlling); - } else { - ice_session_set_role(*ice_session, IR_Controlled); + if (ice_session_just_created == TRUE) { + if (ice_lite == TRUE) { + ice_session_set_role(*ice_session, IR_Controlling); + } else { + ice_session_set_role(*ice_session, IR_Controlled); + } } if ((ice_ufrag != NULL) && (ice_pwd != NULL)) { ice_session_set_remote_credentials(*ice_session, ice_ufrag, ice_pwd); From ca3536d4e107e1d08a69635c47ad26debe6262ba Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 20 Jul 2012 10:05:41 +0200 Subject: [PATCH 17/74] Fix number of media streams in 200 OK SDP. --- coreapi/sal_eXosip2_sdp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 50c0047c3..c589262f0 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -544,6 +544,8 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc, IceS ice_dump_candidates(ice_session_check_list(*ice_session, i)); } } + desc->nstreams=i; + /* Get ICE remote ufrag and remote pwd */ ice_ufrag = ice_pwd = NULL; for (i = 0; (i < SAL_MEDIA_DESCRIPTION_MAX_MESSAGE_ATTRIBUTES) && ((attr = sdp_message_attribute_get(msg, -1, i)) != NULL); i++) { @@ -568,6 +570,5 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc, IceS ice_dump_session(*ice_session); } } - desc->nstreams=i; return 0; } From 4c527f64665c9e3cb869ce9e42c39a8b7d06924b Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 20 Jul 2012 12:15:56 +0200 Subject: [PATCH 18/74] The ICE check lists are destroyed automatically when destroying the ICE session. --- coreapi/linphonecall.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 5689f8dd3..90f7675eb 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1471,7 +1471,6 @@ void linphone_call_stop_media_streams(LinphoneCall *call){ if (call->endpoint){ linphone_call_remove_from_conf(call); } - if (call->audiostream->ice_check_list) ice_check_list_destroy(call->audiostream->ice_check_list); audio_stream_stop(call->audiostream); call->audiostream=NULL; } @@ -1482,7 +1481,6 @@ void linphone_call_stop_media_streams(LinphoneCall *call){ rtp_session_unregister_event_queue(call->videostream->session,call->videostream_app_evq); ortp_ev_queue_flush(call->videostream_app_evq); ortp_ev_queue_destroy(call->videostream_app_evq); - if (call->videostream->ice_check_list) ice_check_list_destroy(call->videostream->ice_check_list); video_stream_stop(call->videostream); call->videostream=NULL; } From 83bc61b27b9a379b4ee1f2c4390d94d3b4209af7 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 20 Jul 2012 14:46:41 +0200 Subject: [PATCH 19/74] Callback registering is now useless (use event queues instead). --- coreapi/linphonecall.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 90f7675eb..4f4dd1c60 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -964,7 +964,6 @@ 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_register_success_cb(audiostream->ice_check_list, audio_stream_set_remote_from_ice, audiostream); } call->audiostream_app_evq = ortp_ev_queue_new(); @@ -989,7 +988,6 @@ 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_register_success_cb(call->videostream->ice_check_list, video_stream_set_remote_from_ice, call->videostream); } call->videostream_app_evq = ortp_ev_queue_new(); rtp_session_register_event_queue(call->videostream->session,call->videostream_app_evq); From 5f622db086efc2dd804ea067ebf47728a373f21d Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 20 Jul 2012 15:38:57 +0200 Subject: [PATCH 20/74] Send RE-INVITE when the ICE session processing finishes successfully. --- coreapi/linphonecall.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 4f4dd1c60..1c30329a3 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1704,6 +1704,8 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse evd->packet = NULL; if (lc->vtable.call_stats_updated) lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]); + } else if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) { + linphone_core_update_call(lc, call, &call->current_params); } ortp_event_destroy(ev); } @@ -1740,6 +1742,8 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse evd->packet = NULL; if (lc->vtable.call_stats_updated) lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]); + } else if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) { + linphone_core_update_call(lc, call, &call->current_params); } ortp_event_destroy(ev); } From 4a0f37147cd41128571ff3d57c82d76c5fa13e0b Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 20 Jul 2012 17:23:57 +0200 Subject: [PATCH 21/74] Only the Controlling ICE agent sends the re-invite. --- coreapi/linphonecall.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 1c30329a3..a3e5a5781 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1705,7 +1705,9 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse if (lc->vtable.call_stats_updated) lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]); } else if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) { - linphone_core_update_call(lc, call, &call->current_params); + if (ice_session_role(sal_op_get_ice_session(call->op)) == IR_Controlling) { + linphone_core_update_call(lc, call, &call->current_params); + } } ortp_event_destroy(ev); } @@ -1743,7 +1745,9 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse if (lc->vtable.call_stats_updated) lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]); } else if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) { - linphone_core_update_call(lc, call, &call->current_params); + if (ice_session_role(sal_op_get_ice_session(call->op)) == IR_Controlling) { + linphone_core_update_call(lc, call, &call->current_params); + } } ortp_event_destroy(ev); } From ba85ea0b32cb771189ac8d9912e8eacebc29383c Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 20 Jul 2012 17:24:38 +0200 Subject: [PATCH 22/74] Fix putting media specific c= line in the SDP. --- coreapi/sal_eXosip2_sdp.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index c589262f0..17e1428e1 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -261,17 +261,6 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription port=desc->candidates[0].port; } - /*only add a c= line within the stream description if address are differents*/ - if (strcmp(addr,sdp_message_c_addr_get(msg, -1, 0))!=0){ - bool_t inet6; - if (strchr(addr,':')!=NULL){ - inet6=TRUE; - }else inet6=FALSE; - sdp_message_c_connection_add (msg, lineno, - osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"), - osip_strdup (addr), NULL, NULL); - } - if (desc->proto == SalProtoRtpSavp) { int i; @@ -312,6 +301,18 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription osip_strdup ("RTP/AVP")); } + + /*only add a c= line within the stream description if address are differents*/ + if (strcmp(addr,sdp_message_c_addr_get(msg, -1, 0))!=0){ + bool_t inet6; + if (strchr(addr,':')!=NULL){ + inet6=TRUE; + }else inet6=FALSE; + sdp_message_c_connection_add (msg, lineno, + osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"), + osip_strdup (addr), NULL, NULL); + } + if (desc->bandwidth>0) sdp_message_b_bandwidth_add (msg, lineno, osip_strdup ("AS"), int_2char(desc->bandwidth)); if (desc->ptime>0) sdp_message_a_attribute_add(msg,lineno,osip_strdup("ptime"), From 1ed0fa066e2c2c2502c3f45de742df5b78f75aef Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 23 Jul 2012 10:52:53 +0200 Subject: [PATCH 23/74] Re-Invite when ICE processing is finished successfully. --- coreapi/linphonecall.c | 4 +++- coreapi/sal_eXosip2_sdp.c | 37 ++++++++++++++++++++++++++++++------- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index a3e5a5781..1ca85fa53 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1438,7 +1438,9 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut /*also reflect the change if the "wished" params, in order to avoid to propose SAVP or video again * further in the call, for example during pause,resume, conferencing reINVITEs*/ linphone_call_fix_call_parameters(call); - if (sal_op_get_ice_session(call->op) != NULL) ice_session_pair_candidates(sal_op_get_ice_session(call->op)); + if ((sal_op_get_ice_session(call->op) != NULL) && (ice_session_state(sal_op_get_ice_session(call->op)) != IS_Completed)) { + ice_session_pair_candidates(sal_op_get_ice_session(call->op)); + } goto end; end: diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 17e1428e1..c7e80d4ca 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -145,7 +145,13 @@ static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc, const osip_strdup (desc->addr)); sdp_message_s_name_set (local, osip_strdup ("Talk")); if ((ice_session != NULL) && (ice_session_check_list(ice_session, 0) != NULL)) { - const IceCandidate *candidate = ice_check_list_default_local_candidate(ice_session_check_list(ice_session, 0)); + const IceCandidate *candidate = NULL; + if (ice_session_state(ice_session) == IS_Completed) { + candidate = ice_check_list_nominated_valid_local_candidate(ice_session_check_list(ice_session, 0)); + } + else { + candidate = ice_check_list_default_local_candidate(ice_session_check_list(ice_session, 0)); + } if (candidate != NULL) { addr=candidate->taddr.ip; } @@ -167,10 +173,20 @@ static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc, const int_2char(desc->bandwidth)); if ((ice_session != NULL) && (ice_session_check_list(ice_session, 0) != NULL)) { char buffer[512]; - snprintf(buffer ,sizeof(buffer), "%s", ice_session_local_pwd(ice_session)); - sdp_message_a_attribute_add(local, -1, osip_strdup("ice-pwd"), osip_strdup(buffer)); - snprintf(buffer ,sizeof(buffer), "%s", ice_session_local_ufrag(ice_session)); - sdp_message_a_attribute_add(local, -1, osip_strdup("ice-ufrag"), osip_strdup(buffer)); + switch (ice_session_state(ice_session)) { + case IS_Running: + case IS_Stopped: + snprintf(buffer, sizeof(buffer), "%s", ice_session_local_pwd(ice_session)); + sdp_message_a_attribute_add(local, -1, osip_strdup("ice-pwd"), osip_strdup(buffer)); + snprintf(buffer, sizeof(buffer), "%s", ice_session_local_ufrag(ice_session)); + sdp_message_a_attribute_add(local, -1, osip_strdup("ice-ufrag"), osip_strdup(buffer)); + break; + case IS_Completed: + sdp_message_a_attribute_add(local, -1, osip_strdup("nortpproxy"), osip_strdup("yes")); + break; + default: + break; + } } return local; @@ -251,7 +267,12 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription addr=desc->addr; port=desc->port; if (ice_cl != NULL) { - const IceCandidate *candidate = ice_check_list_default_local_candidate(ice_cl); + const IceCandidate *candidate = NULL; + if (ice_check_list_state(ice_cl) == ICL_Completed) { + candidate = ice_check_list_nominated_valid_local_candidate(ice_cl); + } else { + candidate = ice_check_list_default_local_candidate(ice_cl); + } if (candidate != NULL) { addr=candidate->taddr.ip; port=candidate->taddr.port; @@ -343,7 +364,9 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription break; } if (dir) sdp_message_a_attribute_add (msg, lineno, osip_strdup (dir),NULL); - add_ice_candidates(msg, lineno, desc, ice_cl); + if (ice_check_list_state(ice_cl) == ICL_Running) { + add_ice_candidates(msg, lineno, desc, ice_cl); + } } From 3d0f4b369b42a8ad993a30e4a30d937f35b58393 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 23 Jul 2012 12:03:17 +0200 Subject: [PATCH 24/74] Add RTCP attribute for each media stream when ICE is activated. --- coreapi/sal_eXosip2_sdp.c | 55 +++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index c7e80d4ca..4101a818e 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -145,15 +145,11 @@ static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc, const osip_strdup (desc->addr)); sdp_message_s_name_set (local, osip_strdup ("Talk")); if ((ice_session != NULL) && (ice_session_check_list(ice_session, 0) != NULL)) { - const IceCandidate *candidate = NULL; if (ice_session_state(ice_session) == IS_Completed) { - candidate = ice_check_list_nominated_valid_local_candidate(ice_session_check_list(ice_session, 0)); + ice_check_list_nominated_valid_local_candidate(ice_session_check_list(ice_session, 0), &addr, NULL, NULL, NULL); } else { - candidate = ice_check_list_default_local_candidate(ice_session_check_list(ice_session, 0)); - } - if (candidate != NULL) { - addr=candidate->taddr.ip; + ice_check_list_default_local_candidate(ice_session_check_list(ice_session, 0), &addr, NULL, NULL, NULL); } } if(!sal_media_description_has_dir (desc,SalStreamSendOnly)) @@ -248,9 +244,11 @@ static void add_ice_candidates(sdp_message_t *msg, int lineno, const SalStreamDe static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription *desc, const IceCheckList *ice_cl){ const char *mt=NULL; const MSList *elem; - const char *addr; + const char *rtp_addr; + const char *rtcp_addr; const char *dir="sendrecv"; - int port; + int rtp_port; + int rtcp_port; bool_t strip_well_known_rtpmaps; switch (desc->type) { @@ -264,29 +262,25 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription mt=desc->typeother; break; } - addr=desc->addr; - port=desc->port; + rtp_addr=rtcp_addr=desc->addr; + rtp_port=desc->port; + rtcp_port=desc->port+1; if (ice_cl != NULL) { - const IceCandidate *candidate = NULL; if (ice_check_list_state(ice_cl) == ICL_Completed) { - candidate = ice_check_list_nominated_valid_local_candidate(ice_cl); + ice_check_list_nominated_valid_local_candidate(ice_cl, &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port); } else { - candidate = ice_check_list_default_local_candidate(ice_cl); - } - if (candidate != NULL) { - addr=candidate->taddr.ip; - port=candidate->taddr.port; + ice_check_list_default_local_candidate(ice_cl, &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port); } } else if (desc->candidates[0].addr[0]!='\0'){ - addr=desc->candidates[0].addr; - port=desc->candidates[0].port; + rtp_addr=desc->candidates[0].addr; + rtp_port=desc->candidates[0].port; } if (desc->proto == SalProtoRtpSavp) { int i; sdp_message_m_media_add (msg, osip_strdup (mt), - int_2char (port), NULL, + int_2char (rtp_port), NULL, osip_strdup ("RTP/SAVP")); /* add crypto lines */ @@ -318,20 +312,20 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription } else { sdp_message_m_media_add (msg, osip_strdup (mt), - int_2char (port), NULL, + int_2char (rtp_port), NULL, osip_strdup ("RTP/AVP")); } /*only add a c= line within the stream description if address are differents*/ - if (strcmp(addr,sdp_message_c_addr_get(msg, -1, 0))!=0){ + if (strcmp(rtp_addr,sdp_message_c_addr_get(msg, -1, 0))!=0){ bool_t inet6; - if (strchr(addr,':')!=NULL){ + if (strchr(rtp_addr,':')!=NULL){ inet6=TRUE; }else inet6=FALSE; sdp_message_c_connection_add (msg, lineno, osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"), - osip_strdup (addr), NULL, NULL); + osip_strdup (rtp_addr), NULL, NULL); } if (desc->bandwidth>0) sdp_message_b_bandwidth_add (msg, lineno, osip_strdup ("AS"), @@ -364,8 +358,17 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription break; } if (dir) sdp_message_a_attribute_add (msg, lineno, osip_strdup (dir),NULL); - if (ice_check_list_state(ice_cl) == ICL_Running) { - add_ice_candidates(msg, lineno, desc, ice_cl); + if (ice_cl != NULL) { + if (strcmp(rtp_addr, rtcp_addr) != 0) { + char buffer[1024]; + snprintf(buffer, sizeof(buffer), "%u IN IP4 %s", rtcp_port, rtcp_addr); + sdp_message_a_attribute_add(msg, lineno, osip_strdup("rtcp"), osip_strdup(buffer)); + } else { + sdp_message_a_attribute_add(msg, lineno, osip_strdup("rtcp"), int_2char(rtcp_port)); + } + if (ice_check_list_state(ice_cl) == ICL_Running) { + add_ice_candidates(msg, lineno, desc, ice_cl); + } } } From 55cb3fa3ed9cf344004adf26c386adc20a0078df Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 23 Jul 2012 13:37:10 +0200 Subject: [PATCH 25/74] Parse the rtcp attribute in the SDP if present. --- coreapi/linphonecall.c | 32 +++++++++++----------- coreapi/offeranswer.c | 24 ++++++++--------- coreapi/sal.c | 8 +++--- coreapi/sal.h | 6 +++-- coreapi/sal_eXosip2.c | 6 ++--- coreapi/sal_eXosip2_sdp.c | 57 +++++++++++++++++++++++++-------------- 6 files changed, 76 insertions(+), 57 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 1ca85fa53..825e56797 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -211,8 +211,8 @@ static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, Li md->bandwidth=linphone_core_get_download_bandwidth(lc); /*set audio capabilities */ - strncpy(md->streams[0].addr,call->localip,sizeof(md->streams[0].addr)); - md->streams[0].port=call->audio_port; + strncpy(md->streams[0].rtp_addr,call->localip,sizeof(md->streams[0].rtp_addr)); + md->streams[0].rtp_port=call->audio_port; md->streams[0].proto=(call->params.media_encryption == LinphoneMediaEncryptionSRTP) ? SalProtoRtpSavp : SalProtoRtpAvp; md->streams[0].type=SalAudio; @@ -226,7 +226,7 @@ static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, Li if (call->params.has_video){ md->nstreams++; - md->streams[1].port=call->video_port; + md->streams[1].rtp_port=call->video_port; md->streams[1].proto=md->streams[0].proto; md->streams[1].type=SalVideo; l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL); @@ -607,7 +607,7 @@ const LinphoneCallParams * linphone_call_get_current_params(const LinphoneCall * } static bool_t is_video_active(const SalStreamDescription *sd){ - return sd->port!=0 && sd->dir!=SalStreamInactive; + return sd->rtp_port!=0 && sd->dir!=SalStreamInactive; } /** @@ -930,7 +930,7 @@ void linphone_call_init_media_streams(LinphoneCall *call){ AudioStream *audiostream; IceSession *ice_session = sal_op_get_ice_session(call->op); - call->audiostream=audiostream=audio_stream_new(md->streams[0].port,linphone_core_ipv6_enabled(lc)); + call->audiostream=audiostream=audio_stream_new(md->streams[0].rtp_port,linphone_core_ipv6_enabled(lc)); if (linphone_core_echo_limiter_enabled(lc)){ const char *type=lp_config_get_string(lc->config,"sound","el_type","mic"); if (strcasecmp(type,"mic")==0) @@ -971,9 +971,9 @@ void linphone_call_init_media_streams(LinphoneCall *call){ #ifdef VIDEO_ENABLED - if ((lc->video_conf.display || lc->video_conf.capture) && md->streams[1].port>0){ + if ((lc->video_conf.display || lc->video_conf.capture) && md->streams[1].rtp_port>0){ int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0); - call->videostream=video_stream_new(md->streams[1].port,linphone_core_ipv6_enabled(lc)); + call->videostream=video_stream_new(md->streams[1].rtp_port,linphone_core_ipv6_enabled(lc)); video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0)); if (video_recv_buf_size>0) rtp_session_set_recv_buf_size(call->videostream->session,video_recv_buf_size); @@ -1189,7 +1189,7 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna stream=sal_media_description_find_stream(call->resultdesc, SalProtoRtpAvp,SalAudio); - if (stream && stream->dir!=SalStreamInactive && stream->port!=0){ + if (stream && stream->dir!=SalStreamInactive && stream->rtp_port!=0){ MSSndCard *playcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard; MSSndCard *captcard=lc->sound_conf.capt_sndcard; @@ -1208,7 +1208,7 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna } /*Replace soundcard filters by inactive file players or recorders when placed in recvonly or sendonly mode*/ - if (stream->port==0 || stream->dir==SalStreamRecvOnly){ + if (stream->rtp_port==0 || stream->dir==SalStreamRecvOnly){ captcard=NULL; playfile=NULL; }else if (stream->dir==SalStreamSendOnly){ @@ -1242,9 +1242,9 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna audio_stream_start_full( call->audiostream, call->audio_profile, - stream->addr[0]!='\0' ? stream->addr : call->resultdesc->addr, - stream->port, - linphone_core_rtcp_enabled(lc) ? (stream->port+1) : 0, + stream->rtp_addr[0]!='\0' ? stream->rtp_addr : call->resultdesc->addr, + stream->rtp_port, + linphone_core_rtcp_enabled(lc) ? (stream->rtp_port+1) : 0, used_pt, jitt_comp, playfile, @@ -1312,8 +1312,8 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna lc->previewstream=NULL; } - if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->port!=0) { - const char *addr=vstream->addr[0]!='\0' ? vstream->addr : call->resultdesc->addr; + if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->rtp_port!=0) { + const char *addr=vstream->rtp_addr[0]!='\0' ? vstream->rtp_addr : call->resultdesc->addr; call->video_profile=make_profile(call,call->resultdesc,vstream,&used_pt); if (used_pt!=-1){ call->current_params.video_codec = rtp_profile_get_payload(call->video_profile, used_pt); @@ -1359,8 +1359,8 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation); video_stream_set_device_rotation(call->videostream, lc->device_rotation); video_stream_start(call->videostream, - call->video_profile, addr, vstream->port, - linphone_core_rtcp_enabled(lc) ? (vstream->port+1) : 0, + call->video_profile, addr, vstream->rtp_port, + linphone_core_rtcp_enabled(lc) ? (vstream->rtp_port+1) : 0, used_pt, lc->rtp_conf.audio_jitt_comp, cam); video_stream_set_rtcp_information(call->videostream, cname,LINPHONE_RTCP_SDES_TOOL); } diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index 5a2b4f527..62782921c 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -203,25 +203,25 @@ static SalStreamDir compute_dir_incoming(SalStreamDir local, SalStreamDir offere static void initiate_outgoing(const SalStreamDescription *local_offer, const SalStreamDescription *remote_answer, SalStreamDescription *result){ - if (remote_answer->port!=0) + if (remote_answer->rtp_port!=0) result->payloads=match_payloads(local_offer->payloads,remote_answer->payloads,TRUE,FALSE); result->proto=remote_answer->proto; result->type=local_offer->type; result->dir=compute_dir_outgoing(local_offer->dir,remote_answer->dir); if (result->payloads && !only_telephone_event(result->payloads)){ - strcpy(result->addr,remote_answer->addr); - result->port=remote_answer->port; + strcpy(result->rtp_addr,remote_answer->rtp_addr); + result->rtp_port=remote_answer->rtp_port; result->bandwidth=remote_answer->bandwidth; result->ptime=remote_answer->ptime; }else{ - result->port=0; + result->rtp_port=0; } if (result->proto == SalProtoRtpSavp) { /* verify crypto algo */ memset(result->crypto, 0, sizeof(result->crypto)); if (!match_crypto_algo(local_offer->crypto, remote_answer->crypto, &result->crypto[0], &result->crypto_local_tag, FALSE)) - result->port = 0; + result->rtp_port = 0; } } @@ -233,20 +233,20 @@ static void initiate_incoming(const SalStreamDescription *local_cap, result->proto=remote_offer->proto; result->type=local_cap->type; result->dir=compute_dir_incoming(local_cap->dir,remote_offer->dir); - if (result->payloads && !only_telephone_event(result->payloads) && (remote_offer->port!=0 || remote_offer->port==SalStreamSendOnly)){ - strcpy(result->addr,local_cap->addr); + if (result->payloads && !only_telephone_event(result->payloads) && (remote_offer->rtp_port!=0 || remote_offer->rtp_port==SalStreamSendOnly)){ + strcpy(result->rtp_addr,local_cap->rtp_addr); memcpy(result->candidates,local_cap->candidates,sizeof(result->candidates)); - result->port=local_cap->port; + result->rtp_port=local_cap->rtp_port; result->bandwidth=local_cap->bandwidth; - result->ptime=local_cap->ptime; + result->ptime=local_cap->ptime; }else{ - result->port=0; + result->rtp_port=0; } if (result->proto == SalProtoRtpSavp) { /* select crypto algo */ memset(result->crypto, 0, sizeof(result->crypto)); if (!match_crypto_algo(local_cap->crypto, remote_offer->crypto, &result->crypto[0], &result->crypto_local_tag, TRUE)) - result->port = 0; + result->rtp_port = 0; } } @@ -303,7 +303,7 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities else { /* create an inactive stream for the answer, as there where no matching stream a local capability */ result->streams[i].dir=SalStreamInactive; - result->streams[i].port=0; + result->streams[i].rtp_port=0; result->streams[i].type=rs->type; result->streams[i].proto=rs->proto; if (rs->type==SalOther){ diff --git a/coreapi/sal.c b/coreapi/sal.c index 37e56fade..de812c4fb 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -87,7 +87,7 @@ bool_t sal_media_description_empty(const SalMediaDescription *md){ int i; for(i=0;instreams;++i){ const SalStreamDescription *ss=&md->streams[i]; - if (ss->port!=0) return FALSE; + if (ss->rtp_port!=0) return FALSE; } return TRUE; } @@ -114,7 +114,7 @@ static bool_t has_dir(const SalMediaDescription *md, SalStreamDir stream_dir){ const SalStreamDescription *ss=&md->streams[i]; if (ss->dir==stream_dir) return TRUE; /*compatibility check for phones that only used the null address and no attributes */ - if (ss->dir==SalStreamSendRecv && stream_dir==SalStreamSendOnly && (is_null_address(md->addr) || is_null_address(ss->addr))) + if (ss->dir==SalStreamSendRecv && stream_dir==SalStreamSendOnly && (is_null_address(md->addr) || is_null_address(ss->rtp_addr))) return TRUE; } return FALSE; @@ -180,8 +180,8 @@ static bool_t payload_list_equals(const MSList *l1, const MSList *l2){ bool_t sal_stream_description_equals(const SalStreamDescription *sd1, const SalStreamDescription *sd2){ if (sd1->proto!=sd2->proto) return FALSE; if (sd1->type!=sd2->type) return FALSE; - if (strcmp(sd1->addr,sd2->addr)!=0) return FALSE; - if (sd1->port!=sd2->port) return FALSE; + if (strcmp(sd1->rtp_addr,sd2->rtp_addr)!=0) return FALSE; + if (sd1->rtp_port!=sd2->rtp_port) return FALSE; if (!payload_list_equals(sd1->payloads,sd2->payloads)) return FALSE; if (sd1->bandwidth!=sd2->bandwidth) return FALSE; if (sd1->ptime!=sd2->ptime) return FALSE; diff --git a/coreapi/sal.h b/coreapi/sal.h index 8782226b8..8a51fa4a4 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -126,8 +126,10 @@ typedef struct SalStreamDescription{ SalMediaProto proto; SalStreamType type; char typeother[32]; - char addr[64]; - int port; + char rtp_addr[64]; + char rtcp_addr[64]; + int rtp_port; + int rtcp_port; MSList *payloads; //result->bandwidth=h->base.remote_media->bandwidth; for(i=0;iresult->nstreams;++i){ - if (h->result->streams[i].port>0){ - strcpy(h->result->streams[i].addr,h->base.remote_media->streams[i].addr); + if (h->result->streams[i].rtp_port>0){ + strcpy(h->result->streams[i].rtp_addr,h->base.remote_media->streams[i].rtp_addr); h->result->streams[i].ptime=h->base.remote_media->streams[i].ptime; h->result->streams[i].bandwidth=h->base.remote_media->streams[i].bandwidth; - h->result->streams[i].port=h->base.remote_media->streams[i].port; + h->result->streams[i].rtp_port=h->base.remote_media->streams[i].rtp_port; if (h->result->streams[i].proto == SalProtoRtpSavp) { h->result->streams[i].crypto[0] = h->base.remote_media->streams[i].crypto[0]; diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 4101a818e..7cf668ca1 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -130,7 +130,7 @@ static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc, const int inet6; char sessid[16]; char sessver[16]; - const char *addr = desc->addr; + const char *rtp_addr = desc->addr; snprintf(sessid,16,"%i",desc->session_id); snprintf(sessver,16,"%i",desc->session_ver); @@ -146,17 +146,17 @@ static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc, const sdp_message_s_name_set (local, osip_strdup ("Talk")); if ((ice_session != NULL) && (ice_session_check_list(ice_session, 0) != NULL)) { if (ice_session_state(ice_session) == IS_Completed) { - ice_check_list_nominated_valid_local_candidate(ice_session_check_list(ice_session, 0), &addr, NULL, NULL, NULL); + ice_check_list_nominated_valid_local_candidate(ice_session_check_list(ice_session, 0), &rtp_addr, NULL, NULL, NULL); } else { - ice_check_list_default_local_candidate(ice_session_check_list(ice_session, 0), &addr, NULL, NULL, NULL); + ice_check_list_default_local_candidate(ice_session_check_list(ice_session, 0), &rtp_addr, NULL, NULL, NULL); } } if(!sal_media_description_has_dir (desc,SalStreamSendOnly)) { sdp_message_c_connection_add (local, -1, osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"), - osip_strdup (addr), NULL, NULL); + osip_strdup (rtp_addr), NULL, NULL); } else { @@ -262,9 +262,9 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription mt=desc->typeother; break; } - rtp_addr=rtcp_addr=desc->addr; - rtp_port=desc->port; - rtcp_port=desc->port+1; + rtp_addr=rtcp_addr=desc->rtp_addr; + rtp_port=desc->rtp_port; + rtcp_port=desc->rtcp_port; if (ice_cl != NULL) { if (ice_check_list_state(ice_cl) == ICL_Completed) { ice_check_list_nominated_valid_local_candidate(ice_cl, &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port); @@ -418,21 +418,21 @@ static int payload_type_fill_from_rtpmap(PayloadType *pt, const char *rtpmap){ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc, IceSession **ice_session){ int i,j; - const char *mtype,*proto,*port,*addr,*number; + const char *mtype,*proto,*rtp_port,*rtp_addr,*number; const char *ice_ufrag, *ice_pwd; sdp_bandwidth_t *sbw=NULL; sdp_attribute_t *attr; int media_attribute_nb; bool_t ice_session_just_created = FALSE; bool_t ice_lite = FALSE; - - addr=sdp_message_c_addr_get (msg, -1, 0); - if (addr) - strncpy(desc->addr,addr,sizeof(desc->addr)); + + rtp_addr=sdp_message_c_addr_get (msg, -1, 0); + if (rtp_addr) + strncpy(desc->addr,rtp_addr,sizeof(desc->addr)); for(j=0;(sbw=sdp_message_bandwidth_get(msg,-1,j))!=NULL;++j){ if (strcasecmp(sbw->b_bwtype,"AS")==0) desc->bandwidth=atoi(sbw->b_bandwidth); } - + /* for each m= line */ for (i=0; !sdp_message_endof_media (msg, i) && iproto=SalProtoUnknown; if (proto){ if (strcasecmp(proto,"RTP/AVP")==0) @@ -450,11 +450,11 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc, IceS stream->proto=SalProtoRtpSavp; } } - addr = sdp_message_c_addr_get (msg, i, 0); - if (addr != NULL) - strncpy(stream->addr,addr,sizeof(stream->addr)); - if (port) - stream->port=atoi(port); + rtp_addr = sdp_message_c_addr_get (msg, i, 0); + if (rtp_addr != NULL) + strncpy(stream->rtp_addr,rtp_addr,sizeof(stream->rtp_addr)); + if (rtp_port) + stream->rtp_port=atoi(rtp_port); stream->ptime=_sdp_message_get_a_ptime(msg,i); if (strcasecmp("audio", mtype) == 0){ @@ -489,7 +489,24 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc, IceS pt->send_fmtp ? pt->send_fmtp : ""); } } - + + /* Get media specific RTCP attribute */ + stream->rtcp_port = stream->rtp_port + 1; + snprintf(stream->rtcp_addr, sizeof(stream->rtcp_addr), stream->rtp_addr); + for (j = 0; ((attr = sdp_message_attribute_get(msg, i, j)) != NULL); j++) { + if ((keywordcmp("rtcp", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { + char tmp[256]; + int nb = sscanf(attr->a_att_value, "%d IN IP4 %s", &stream->rtcp_port, tmp); + if (nb == 1) { + /* SDP rtcp attribute only contains the port */ + } else if (nb == 2) { + strncpy(stream->rtcp_addr, tmp, sizeof(stream->rtcp_addr)); + } else { + ms_warning("sdp has a strange a= line (%s) nb=%i", attr->a_att_value, nb); + } + } + } + /* read crypto lines if any */ if (stream->proto == SalProtoRtpSavp) { int k, valid_count = 0; From f97f51d4f38eaaa4380ff281d258021e9c00f65c Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 23 Jul 2012 14:28:19 +0200 Subject: [PATCH 26/74] Specify local RTCP port explicitly. --- console/sipomatic.c | 2 +- coreapi/conference.c | 2 +- coreapi/linphonecall.c | 11 +++++++---- coreapi/offeranswer.c | 4 ++++ coreapi/sal.c | 2 ++ coreapi/sal_eXosip2.c | 2 ++ media_api/mediaflow.c | 2 +- 7 files changed, 18 insertions(+), 7 deletions(-) diff --git a/console/sipomatic.c b/console/sipomatic.c index e0d3f67e7..e7a1c6a88 100644 --- a/console/sipomatic.c +++ b/console/sipomatic.c @@ -97,7 +97,7 @@ void call_accept(Call *call) osip_message_set_content_type(msg,"application/sdp"); osip_message_set_body(msg,call->sdpc->answerstr,strlen(call->sdpc->answerstr)); eXosip_call_send_answer(call->tid,200,msg); - call->audio_stream=audio_stream_new(call->audio.localport,call->root->ipv6); + call->audio_stream=audio_stream_new(call->audio.localport,call->audio.localport+1,call->root->ipv6); audio_stream_start_with_files(call->audio_stream, call->profile, call->audio.remaddr,call->audio.remoteport,call->audio.remoteport+1, call->audio.pt,20,hellofile,record_file); diff --git a/coreapi/conference.c b/coreapi/conference.c index d4abc1a91..1b6903fd0 100644 --- a/coreapi/conference.c +++ b/coreapi/conference.c @@ -104,7 +104,7 @@ static RtpProfile *make_dummy_profile(int samplerate){ static void add_local_endpoint(LinphoneConference *conf,LinphoneCore *lc){ /*create a dummy audiostream in order to extract the local part of it */ /* network address and ports have no meaning and are not used here. */ - AudioStream *st=audio_stream_new(65000,FALSE); + AudioStream *st=audio_stream_new(65000,65001,FALSE); MSSndCard *playcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard; MSSndCard *captcard=lc->sound_conf.capt_sndcard; diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 825e56797..432adc348 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -212,7 +212,9 @@ static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, Li /*set audio capabilities */ strncpy(md->streams[0].rtp_addr,call->localip,sizeof(md->streams[0].rtp_addr)); + strncpy(md->streams[0].rtcp_addr,call->localip,sizeof(md->streams[0].rtcp_addr)); md->streams[0].rtp_port=call->audio_port; + md->streams[0].rtcp_port=call->audio_port+1; md->streams[0].proto=(call->params.media_encryption == LinphoneMediaEncryptionSRTP) ? SalProtoRtpSavp : SalProtoRtpAvp; md->streams[0].type=SalAudio; @@ -227,6 +229,7 @@ static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, Li if (call->params.has_video){ md->nstreams++; md->streams[1].rtp_port=call->video_port; + md->streams[1].rtcp_port=call->video_port+1; md->streams[1].proto=md->streams[0].proto; md->streams[1].type=SalVideo; l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL); @@ -930,7 +933,7 @@ void linphone_call_init_media_streams(LinphoneCall *call){ AudioStream *audiostream; IceSession *ice_session = sal_op_get_ice_session(call->op); - call->audiostream=audiostream=audio_stream_new(md->streams[0].rtp_port,linphone_core_ipv6_enabled(lc)); + call->audiostream=audiostream=audio_stream_new(md->streams[0].rtp_port,md->streams[0].rtcp_port,linphone_core_ipv6_enabled(lc)); if (linphone_core_echo_limiter_enabled(lc)){ const char *type=lp_config_get_string(lc->config,"sound","el_type","mic"); if (strcasecmp(type,"mic")==0) @@ -973,7 +976,7 @@ void linphone_call_init_media_streams(LinphoneCall *call){ if ((lc->video_conf.display || lc->video_conf.capture) && md->streams[1].rtp_port>0){ int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0); - call->videostream=video_stream_new(md->streams[1].rtp_port,linphone_core_ipv6_enabled(lc)); + call->videostream=video_stream_new(md->streams[1].rtp_port,md->streams[1].rtcp_port,linphone_core_ipv6_enabled(lc)); video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0)); if (video_recv_buf_size>0) rtp_session_set_recv_buf_size(call->videostream->session,video_recv_buf_size); @@ -1244,7 +1247,7 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna call->audio_profile, stream->rtp_addr[0]!='\0' ? stream->rtp_addr : call->resultdesc->addr, stream->rtp_port, - linphone_core_rtcp_enabled(lc) ? (stream->rtp_port+1) : 0, + linphone_core_rtcp_enabled(lc) ? (stream->rtcp_port) : 0, used_pt, jitt_comp, playfile, @@ -1360,7 +1363,7 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna video_stream_set_device_rotation(call->videostream, lc->device_rotation); video_stream_start(call->videostream, call->video_profile, addr, vstream->rtp_port, - linphone_core_rtcp_enabled(lc) ? (vstream->rtp_port+1) : 0, + linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port) : 0, used_pt, lc->rtp_conf.audio_jitt_comp, cam); video_stream_set_rtcp_information(call->videostream, cname,LINPHONE_RTCP_SDES_TOOL); } diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index 62782921c..118f2420a 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -211,7 +211,9 @@ static void initiate_outgoing(const SalStreamDescription *local_offer, if (result->payloads && !only_telephone_event(result->payloads)){ strcpy(result->rtp_addr,remote_answer->rtp_addr); + strcpy(result->rtcp_addr,remote_answer->rtcp_addr); result->rtp_port=remote_answer->rtp_port; + result->rtcp_port=remote_answer->rtcp_port; result->bandwidth=remote_answer->bandwidth; result->ptime=remote_answer->ptime; }else{ @@ -235,8 +237,10 @@ static void initiate_incoming(const SalStreamDescription *local_cap, result->dir=compute_dir_incoming(local_cap->dir,remote_offer->dir); if (result->payloads && !only_telephone_event(result->payloads) && (remote_offer->rtp_port!=0 || remote_offer->rtp_port==SalStreamSendOnly)){ strcpy(result->rtp_addr,local_cap->rtp_addr); + strcpy(result->rtcp_addr,local_cap->rtcp_addr); memcpy(result->candidates,local_cap->candidates,sizeof(result->candidates)); result->rtp_port=local_cap->rtp_port; + result->rtcp_port=local_cap->rtcp_port; result->bandwidth=local_cap->bandwidth; result->ptime=local_cap->ptime; }else{ diff --git a/coreapi/sal.c b/coreapi/sal.c index de812c4fb..5b592b8d3 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -182,6 +182,8 @@ bool_t sal_stream_description_equals(const SalStreamDescription *sd1, const SalS if (sd1->type!=sd2->type) return FALSE; if (strcmp(sd1->rtp_addr,sd2->rtp_addr)!=0) return FALSE; if (sd1->rtp_port!=sd2->rtp_port) return FALSE; + if (strcmp(sd1->rtcp_addr,sd2->rtcp_addr)!=0) return FALSE; + if (sd1->rtcp_port!=sd2->rtcp_port) return FALSE; if (!payload_list_equals(sd1->payloads,sd2->payloads)) return FALSE; if (sd1->bandwidth!=sd2->bandwidth) return FALSE; if (sd1->ptime!=sd2->ptime) return FALSE; diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index fe5e1b8e7..42f11eca0 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -535,9 +535,11 @@ static void sdp_process(SalOp *h){ for(i=0;iresult->nstreams;++i){ if (h->result->streams[i].rtp_port>0){ strcpy(h->result->streams[i].rtp_addr,h->base.remote_media->streams[i].rtp_addr); + strcpy(h->result->streams[i].rtcp_addr,h->base.remote_media->streams[i].rtcp_addr); h->result->streams[i].ptime=h->base.remote_media->streams[i].ptime; h->result->streams[i].bandwidth=h->base.remote_media->streams[i].bandwidth; h->result->streams[i].rtp_port=h->base.remote_media->streams[i].rtp_port; + h->result->streams[i].rtcp_port=h->base.remote_media->streams[i].rtcp_port; if (h->result->streams[i].proto == SalProtoRtpSavp) { h->result->streams[i].crypto[0] = h->base.remote_media->streams[i].crypto[0]; diff --git a/media_api/mediaflow.c b/media_api/mediaflow.c index 8ccdadb71..e0e6be403 100644 --- a/media_api/mediaflow.c +++ b/media_api/mediaflow.c @@ -109,7 +109,7 @@ MSFilter *set_MSFilter(EndPoint *endpoint, int type, FlowDirections *fdir){ switch(endpoint->protocol){ case MEDIA_RTP: rtps = rtp_session_new(RTP_SESSION_RECVONLY); - rtp_session_set_local_addr(rtps,"0.0.0.0",8000); + rtp_session_set_local_addr(rtps,"0.0.0.0",8000,8001); rtp_session_set_scheduling_mode(rtps,0); rtp_session_set_blocking_mode(rtps,0); From ebdfca041b1a6b7479c688693f6092b2075424b6 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 23 Jul 2012 15:26:18 +0200 Subject: [PATCH 27/74] Specify remote RTCP address explicitly. --- coreapi/conference.c | 1 + coreapi/linphonecall.c | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/coreapi/conference.c b/coreapi/conference.c index 1b6903fd0..5ca465254 100644 --- a/coreapi/conference.c +++ b/coreapi/conference.c @@ -114,6 +114,7 @@ static void add_local_endpoint(LinphoneConference *conf,LinphoneCore *lc){ audio_stream_start_full(st, conf->local_dummy_profile, "127.0.0.1", 65000, + "127.0.0.1", 65001, 0, 40, diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 432adc348..f42a9ba06 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1247,6 +1247,7 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna call->audio_profile, stream->rtp_addr[0]!='\0' ? stream->rtp_addr : call->resultdesc->addr, stream->rtp_port, + stream->rtcp_addr[0]!='\0' ? stream->rtcp_addr : call->resultdesc->addr, linphone_core_rtcp_enabled(lc) ? (stream->rtcp_port) : 0, used_pt, jitt_comp, @@ -1316,7 +1317,8 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna } if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->rtp_port!=0) { - const char *addr=vstream->rtp_addr[0]!='\0' ? vstream->rtp_addr : call->resultdesc->addr; + const char *rtp_addr=vstream->rtp_addr[0]!='\0' ? vstream->rtp_addr : call->resultdesc->addr; + const char *rtcp_addr=vstream->rtcp_addr[0]!='\0' ? vstream->rtcp_addr : call->resultdesc->addr; call->video_profile=make_profile(call,call->resultdesc,vstream,&used_pt); if (used_pt!=-1){ call->current_params.video_codec = rtp_profile_get_payload(call->video_profile, used_pt); @@ -1362,8 +1364,8 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation); video_stream_set_device_rotation(call->videostream, lc->device_rotation); video_stream_start(call->videostream, - call->video_profile, addr, vstream->rtp_port, - linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port) : 0, + call->video_profile, rtp_addr, vstream->rtp_port, + rtcp_addr, linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port) : 0, used_pt, lc->rtp_conf.audio_jitt_comp, cam); video_stream_set_rtcp_information(call->videostream, cname,LINPHONE_RTCP_SDES_TOOL); } From d3b07fe32d066237f471f20f00290a6ee4fcecff Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 24 Jul 2012 15:04:19 +0200 Subject: [PATCH 28/74] Eliminate ICE redundant candidates. --- coreapi/misc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/coreapi/misc.c b/coreapi/misc.c index 1dadcb335..82f1dd1c1 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -675,6 +675,7 @@ void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) && (!call->params.has_video || ((video_responses[0] == TRUE) && (video_responses[1] == TRUE))))); ice_session_compute_candidates_foundations(ice_session); + ice_session_eliminate_redundant_candidates(ice_session); ice_session_choose_default_candidates(ice_session); close_socket(audio_socks[0]); From b11704376f70949b23338b43377a2d05715a1311 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 24 Jul 2012 16:03:55 +0200 Subject: [PATCH 29/74] Good timing handling for STUN request during ICE candidates gathering. --- coreapi/misc.c | 116 ++++++++++++++++++++++++++++--------------------- 1 file changed, 67 insertions(+), 49 deletions(-) diff --git a/coreapi/misc.c b/coreapi/misc.c index 82f1dd1c1..2f887bf0c 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -564,22 +564,25 @@ void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ void 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; - ortp_socket_t audio_socks[2]; - ortp_socket_t video_socks[2]; - bool_t audio_responses[2]; - bool_t video_responses[2]; - IceCandidate *audio_ice_bases[2]; - IceCandidate *video_ice_bases[2]; + gathering_t audio_gatherings[2]; + gathering_t video_gatherings[2]; 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; + struct timeval init, cur, diff; double elapsed; int loops = 0; const char *server = linphone_core_get_stun_server(lc); @@ -601,42 +604,57 @@ void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) if (lc->vtable.display_status != NULL) lc->vtable.display_status(lc, _("ICE local candidates gathering in progress...")); - audio_responses[0] = audio_responses[1] = FALSE; - video_responses[0] = video_responses[1] = FALSE; - audio_ice_bases[0] = audio_ice_bases[1] = NULL; - video_ice_bases[0] = video_ice_bases[1] = NULL; - audio_socks[0] = create_socket(call->audio_port); - if (audio_socks[0] == -1) return; - audio_socks[1] = create_socket(call->audio_port + 1); - if (audio_socks[1] == -1) return; + 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_socks[0] = create_socket(call->video_port); - if (video_socks[0] == -1) return; - video_socks[1] = create_socket(call->video_port + 1); - if (video_socks[1] == -1) return; + 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_socks[0] = video_socks[1] = -1; + video_gatherings[0].sock = video_gatherings[1].sock = -1; } if (linphone_core_get_local_ip_for(AF_INET, NULL, local_addr) < 0) { ms_error("Fail to get local ip"); return; } - audio_ice_bases[0] = ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port, 1, NULL); - audio_ice_bases[1] = ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port + 1, 2, NULL); + 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_ice_bases[0] = ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port, 1, NULL); - video_ice_bases[1] = ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port + 1, 2, 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 (loops % 20 == 0) { - ms_message("Sending stun requests..."); - if (audio_responses[0] == FALSE) sendStunRequest(audio_socks[0], (struct sockaddr*)&ss, ss_len, 1, FALSE); - if (audio_responses[1] == FALSE) sendStunRequest(audio_socks[1], (struct sockaddr*)&ss, ss_len, 1, FALSE); - if (call->params.has_video) { - if (video_responses[0] == FALSE) sendStunRequest(video_socks[0], (struct sockaddr*)&ss, ss_len, 2, FALSE); - if (video_responses[1] == FALSE) sendStunRequest(video_socks[1], (struct sockaddr*)&ss, ss_len, 2, FALSE); + 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 @@ -645,22 +663,22 @@ void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) usleep(10000); #endif - if (recvStunResponse(audio_socks[0], addr, &port, &id) > 0) { - ice_add_local_candidate(audio_check_list, "srflx", addr, port, 1, audio_ice_bases[0]); - audio_responses[0] = TRUE; + 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_socks[1], addr, &port, &id) > 0) { - ice_add_local_candidate(audio_check_list, "srflx", addr, port, 2, audio_ice_bases[1]); - audio_responses[1] = 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_socks[0], addr, &port, &id) > 0) { - ice_add_local_candidate(video_check_list, "srflx", addr, port, 1, video_ice_bases[0]); - video_responses[0] = TRUE; + 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_socks[1], addr, &port, &id) > 0) { - ice_add_local_candidate(video_check_list, "srflx", addr, port, 2, video_ice_bases[1]); - video_responses[1] = 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; } } @@ -671,19 +689,19 @@ void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) break; } loops++; - } while (!((audio_responses[0] == TRUE) && (audio_responses[1] == TRUE) - && (!call->params.has_video || ((video_responses[0] == TRUE) && (video_responses[1] == TRUE))))); + } 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))))); ice_session_compute_candidates_foundations(ice_session); ice_session_eliminate_redundant_candidates(ice_session); ice_session_choose_default_candidates(ice_session); - close_socket(audio_socks[0]); - close_socket(audio_socks[1]); + close_socket(audio_gatherings[0].sock); + close_socket(audio_gatherings[1].sock); ice_dump_candidates(audio_check_list); if (call->params.has_video && (video_check_list != NULL)) { - if (video_socks[0] != -1) close_socket(video_socks[0]); - if (video_socks[1] != -1) close_socket(video_socks[1]); + if (video_gatherings[0].sock != -1) close_socket(video_gatherings[0].sock); + if (video_gatherings[1].sock != -1) close_socket(video_gatherings[1].sock); ice_dump_candidates(video_check_list); } } From 20c2ba6ff2fa6d54c909a1e4c40711a9b4967752 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 25 Jul 2012 11:18:05 +0200 Subject: [PATCH 30/74] ICE API change. --- coreapi/linphonecall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index f42a9ba06..2a25b3cc1 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1444,7 +1444,7 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut * further in the call, for example during pause,resume, conferencing reINVITEs*/ linphone_call_fix_call_parameters(call); if ((sal_op_get_ice_session(call->op) != NULL) && (ice_session_state(sal_op_get_ice_session(call->op)) != IS_Completed)) { - ice_session_pair_candidates(sal_op_get_ice_session(call->op)); + ice_session_start_connectivity_checks(sal_op_get_ice_session(call->op)); } goto end; From dc308bc2c6b696105d332df8d02024df3e76b743 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 25 Jul 2012 12:54:25 +0200 Subject: [PATCH 31/74] Only include ICE candidates matching the default destination for each component of the stream in RE-INVITE for Completed check lists. --- coreapi/sal_eXosip2_sdp.c | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 7cf668ca1..a85b5ef5a 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -224,18 +224,35 @@ static void add_payload(sdp_message_t *msg, int line, const PayloadType *pt, boo } } -static void add_ice_candidates(sdp_message_t *msg, int lineno, const SalStreamDescription *desc, const IceCheckList *ice_cl) +static void add_candidate_attribute(sdp_message_t *msg, int lineno, const IceCandidate *candidate) { char buffer[1024]; + + snprintf(buffer, sizeof(buffer), "%s %d UDP %d %s %d typ %s", + candidate->foundation, candidate->componentID, candidate->priority, candidate->taddr.ip, candidate->taddr.port, ice_candidate_type(candidate)); + sdp_message_a_attribute_add(msg, lineno, osip_strdup("candidate"), osip_strdup(buffer)); +} + +static void add_ice_candidates(sdp_message_t *msg, int lineno, const IceCheckList *ice_cl, const char *rtp_addr, int rtp_port, const char *rtcp_addr, int rtcp_port) +{ const IceCandidate *candidate; int i; - if (ice_cl != NULL) { - for (i = 0; i < ms_list_size(ice_cl->local_candidates); i++) { - candidate = ms_list_nth_data(ice_cl->local_candidates, i); - snprintf(buffer, sizeof(buffer), "%s %d UDP %d %s %d typ %s", - candidate->foundation, candidate->componentID, candidate->priority, candidate->taddr.ip, candidate->taddr.port, ice_candidate_type(candidate)); - sdp_message_a_attribute_add(msg, lineno, osip_strdup("candidate"), osip_strdup(buffer)); + for (i = 0; i < ms_list_size(ice_cl->local_candidates); i++) { + candidate = ms_list_nth_data(ice_cl->local_candidates, i); + switch (ice_check_list_state(ice_cl)) { + case ICL_Running: + add_candidate_attribute(msg, lineno, candidate); + break; + case ICL_Completed: + /* Only include the candidates matching the default destination for each component of the stream as specified in RFC5245 section 9.1.2.2. */ + if (((candidate->taddr.port == rtp_port) && (strlen(candidate->taddr.ip) == strlen(rtp_addr)) && (strcmp(candidate->taddr.ip, rtp_addr) == 0)) + || ((candidate->taddr.port == rtcp_port) && (strlen(candidate->taddr.ip) == strlen(rtcp_addr)) && (strcmp(candidate->taddr.ip, rtcp_addr) == 0))) { + add_candidate_attribute(msg, lineno, candidate); + } + break; + default: + break; } } } @@ -366,9 +383,7 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription } else { sdp_message_a_attribute_add(msg, lineno, osip_strdup("rtcp"), int_2char(rtcp_port)); } - if (ice_check_list_state(ice_cl) == ICL_Running) { - add_ice_candidates(msg, lineno, desc, ice_cl); - } + add_ice_candidates(msg, lineno, ice_cl, rtp_addr, rtp_port, rtcp_addr, rtcp_port); } } From a45b6fbd73ab227baa95d23f2c032a2905115e3f Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 25 Jul 2012 15:32:51 +0200 Subject: [PATCH 32/74] Add raddr and rport values in ICE candidate attributes in the SDP. --- coreapi/sal_eXosip2_sdp.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index a85b5ef5a..8c9279aa1 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -227,9 +227,21 @@ static void add_payload(sdp_message_t *msg, int line, const PayloadType *pt, boo static void add_candidate_attribute(sdp_message_t *msg, int lineno, const IceCandidate *candidate) { char buffer[1024]; + int nb; - snprintf(buffer, sizeof(buffer), "%s %d UDP %d %s %d typ %s", + nb = snprintf(buffer, sizeof(buffer), "%s %d UDP %d %s %d typ %s", candidate->foundation, candidate->componentID, candidate->priority, candidate->taddr.ip, candidate->taddr.port, ice_candidate_type(candidate)); + if (nb < 0) { + ms_error("Cannot add ICE candidate attribute!"); + return; + } + if (candidate->type != ICT_HostCandidate) { + nb = snprintf(buffer + nb, sizeof(buffer) - nb, " raddr %s rport %d", candidate->base->taddr.ip, candidate->base->taddr.port); + if (nb < 0) { + ms_error("Cannot add ICE candidate attribute!"); + return; + } + } sdp_message_a_attribute_add(msg, lineno, osip_strdup("candidate"), osip_strdup(buffer)); } From 0ec0c0afa1832f037512a94a00c63d99b6b0daec Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 25 Jul 2012 16:41:31 +0200 Subject: [PATCH 33/74] Add remote-candidates attributes in the SDP in RE-INVITE when ICE process has processed successfully. --- coreapi/sal_eXosip2_sdp.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 8c9279aa1..ca7600e3d 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -269,6 +269,32 @@ static void add_ice_candidates(sdp_message_t *msg, int lineno, const IceCheckLis } } +static void add_ice_remote_candidates(sdp_message_t *msg, int lineno, const IceCheckList *ice_cl) +{ + char buffer[1024]; + const char *rtp_addr = NULL; + const char *rtcp_addr = NULL; + int rtp_port; + int rtcp_port; + int nb; + + if ((ice_session_role(ice_cl->session) == IR_Controlling) && (ice_check_list_state(ice_cl) == ICL_Completed)) { + ice_check_list_nominated_valid_remote_candidate(ice_cl, &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port); + nb = snprintf(buffer, sizeof(buffer), "1 %s %d", rtp_addr, rtp_port); + if (nb < 0) { + ms_error("Cannot add ICE remote-candidates attribute!"); + return; + } + if (rtcp_addr != NULL) { + nb = snprintf(buffer + nb, sizeof(buffer) - nb, " 2 %s %d", rtcp_addr, rtcp_port); + if (nb < 0) { + ms_error("Cannot add ICE remote-candidates attribute!"); + return; + } + } + sdp_message_a_attribute_add(msg, lineno, osip_strdup("remote-candidates"), osip_strdup(buffer)); + } +} static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription *desc, const IceCheckList *ice_cl){ const char *mt=NULL; @@ -396,6 +422,7 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription sdp_message_a_attribute_add(msg, lineno, osip_strdup("rtcp"), int_2char(rtcp_port)); } add_ice_candidates(msg, lineno, ice_cl, rtp_addr, rtp_port, rtcp_addr, rtcp_port); + add_ice_remote_candidates(msg, lineno, ice_cl); } } From 3cca370ef1c283b861a45d6de276e6fc9354c7cc Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 26 Jul 2012 09:55:32 +0200 Subject: [PATCH 34/74] Handle received ICE remote-candidates attribute in SDP. --- coreapi/sal_eXosip2_sdp.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index ca7600e3d..688d32c08 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -473,7 +473,7 @@ static int payload_type_fill_from_rtpmap(PayloadType *pt, const char *rtpmap){ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc, IceSession **ice_session){ int i,j; const char *mtype,*proto,*rtp_port,*rtp_addr,*number; - const char *ice_ufrag, *ice_pwd; + const char *ice_ufrag, *ice_pwd, *ice_remote_candidates=NULL; sdp_bandwidth_t *sbw=NULL; sdp_attribute_t *attr; int media_attribute_nb; @@ -629,6 +629,8 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc, IceS if (nb == 6) { ice_add_remote_candidate(ice_session_check_list(*ice_session, i), type, ip, port, componentID, priority, foundation); } + } else if ((keywordcmp("remote-candidates", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { + ice_remote_candidates = attr->a_att_value; } else if ((keywordcmp("ice-ufrag", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { ice_ufrag = attr->a_att_value; } else if ((keywordcmp("ice-pwd", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { @@ -636,6 +638,26 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc, IceS } } if ((*ice_session != NULL) && ice_session_check_list(*ice_session, i)) { + if (ice_remote_candidates != NULL) { + char ip[64]; + unsigned int port; + unsigned int componentID; + int offset; + + while (3 == sscanf(ice_remote_candidates, "%u %s %u%n", &componentID, ip, &port, &offset)) { + if (componentID == 1) { + if ((stream->rtp_addr == NULL) || (stream->rtp_addr[0] == '\0')) rtp_addr = desc->addr; + else rtp_addr = stream->rtp_addr; + ice_add_losing_pair(ice_session_check_list(*ice_session, i), componentID, ip, port, rtp_addr, stream->rtp_port); + } else if (componentID == 2) { + if ((stream->rtcp_addr == NULL) || (stream->rtcp_addr[0] == '\0')) rtp_addr = desc->addr; + else rtp_addr = stream->rtcp_addr; + ice_add_losing_pair(ice_session_check_list(*ice_session, i), componentID, ip, port, rtp_addr, stream->rtcp_port); + } + ice_remote_candidates += offset; + if (ice_remote_candidates[offset] == ' ') ice_remote_candidates += 1; + } + } if ((ice_ufrag != NULL) && (ice_pwd != NULL)) { ice_check_list_set_remote_credentials(ice_session_check_list(*ice_session, i), ice_ufrag, ice_pwd); } From df347a9733ddaf66f4d7eb6870de022606d67e63 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 26 Jul 2012 10:49:12 +0200 Subject: [PATCH 35/74] Handle case where ICE is activated and the configured STUN server do not reply. --- coreapi/misc.c | 18 +++++++++++++----- coreapi/sal_eXosip2_sdp.c | 2 +- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/coreapi/misc.c b/coreapi/misc.c index 2f887bf0c..51f217c70 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -692,17 +692,25 @@ void linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) } 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))))); - ice_session_compute_candidates_foundations(ice_session); - ice_session_eliminate_redundant_candidates(ice_session); - ice_session_choose_default_candidates(ice_session); + 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); - ice_dump_candidates(audio_check_list); + if (ice_session != NULL) ice_dump_candidates(audio_check_list); 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); - ice_dump_candidates(video_check_list); + if (ice_session != NULL) ice_dump_candidates(video_check_list); } } diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 688d32c08..fee5a5313 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -373,7 +373,7 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription } /*only add a c= line within the stream description if address are differents*/ - if (strcmp(rtp_addr,sdp_message_c_addr_get(msg, -1, 0))!=0){ + if (rtp_addr[0]!='\0' && strcmp(rtp_addr,sdp_message_c_addr_get(msg, -1, 0))!=0){ bool_t inet6; if (strchr(rtp_addr,':')!=NULL){ inet6=TRUE; From cec1d35fed0b43835433d0377e79da0cc40e688a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 26 Jul 2012 11:28:26 +0200 Subject: [PATCH 36/74] Handle the case where ICE is activated locally but the remote does not support it. --- coreapi/linphonecall.c | 10 +++++++--- coreapi/sal_eXosip2_sdp.c | 5 +++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 2a25b3cc1..7c9ef7bf6 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -396,13 +396,17 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro call->localdesc=create_local_media_description (lc,call); call->camera_active=call->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; + case LinphonePolicyUseStun: + linphone_core_run_stun_tests(call->core,call); + /* No break to also destroy ice session in this case. */ default: + if (sal_op_get_ice_session(call->op) != NULL) { + ice_session_destroy(sal_op_get_ice_session(call->op)); + sal_op_set_ice_session(call->op, NULL); + } break; } discover_mtu(lc,linphone_address_get_domain(from)); diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index fee5a5313..8038d1f4e 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -689,6 +689,11 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc, IceS ice_session_set_remote_credentials(*ice_session, ice_ufrag, ice_pwd); ice_dump_session(*ice_session); } + if ((ice_session_just_created == FALSE) && ((ice_ufrag == NULL) || (ice_pwd == NULL))) { + /* We started with ICE activated but the peer apparently do not support ICE, so stop using it. */ + ice_session_destroy(*ice_session); + *ice_session = NULL; + } } return 0; } From dc4c62047478ceb132264b69e9f7c55da6e6e1e4 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 26 Jul 2012 12:21:37 +0200 Subject: [PATCH 37/74] Include ice-ufrag and ice-pwd attributes in RE-INVITE. --- coreapi/sal_eXosip2_sdp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 8038d1f4e..3d5017955 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -170,6 +170,9 @@ static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc, const if ((ice_session != NULL) && (ice_session_check_list(ice_session, 0) != NULL)) { char buffer[512]; switch (ice_session_state(ice_session)) { + case IS_Completed: + sdp_message_a_attribute_add(local, -1, osip_strdup("nortpproxy"), osip_strdup("yes")); + /* No break to also include the ice-ufrag and ice-pwd attributes when ICE session is completed. */ case IS_Running: case IS_Stopped: snprintf(buffer, sizeof(buffer), "%s", ice_session_local_pwd(ice_session)); @@ -177,9 +180,6 @@ static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc, const snprintf(buffer, sizeof(buffer), "%s", ice_session_local_ufrag(ice_session)); sdp_message_a_attribute_add(local, -1, osip_strdup("ice-ufrag"), osip_strdup(buffer)); break; - case IS_Completed: - sdp_message_a_attribute_add(local, -1, osip_strdup("nortpproxy"), osip_strdup("yes")); - break; default: break; } From 682e19e665feb606d6c2a0c623b49466053b3165 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 27 Jul 2012 12:10:35 +0200 Subject: [PATCH 38/74] Specify default ICE remote candidates. --- coreapi/sal_eXosip2_sdp.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 3d5017955..dff2de574 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -627,7 +627,20 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc, IceS nb = sscanf(attr->a_att_value, "%s %u UDP %u %s %u typ %s", foundation, &componentID, &priority, ip, &port, type); if (nb == 6) { - ice_add_remote_candidate(ice_session_check_list(*ice_session, i), type, ip, port, componentID, priority, foundation); + char *default_ip = desc->addr; + unsigned int default_port = stream->rtp_port; + bool_t is_default_candidate = FALSE; + if (componentID == 1) { + if ((stream->rtp_addr == NULL) || (stream->rtp_addr[0] == '\0')) default_ip = desc->addr; + else default_ip = stream->rtp_addr; + default_port = stream->rtp_port; + } else if (componentID == 2) { + if ((stream->rtcp_addr == NULL) || (stream->rtcp_addr[0] == '\0')) default_ip = desc->addr; + else default_ip = stream->rtcp_addr; + default_port = stream->rtcp_port; + } + if ((port == default_port) && (strlen(ip) == strlen(default_ip)) && (strcmp(ip, default_ip) == 0)) is_default_candidate = TRUE; + ice_add_remote_candidate(ice_session_check_list(*ice_session, i), type, ip, port, componentID, priority, foundation, is_default_candidate); } } else if ((keywordcmp("remote-candidates", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { ice_remote_candidates = attr->a_att_value; From 72360e58a53ed53145247b0b1b280b83430c3dca Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 27 Jul 2012 15:33:28 +0200 Subject: [PATCH 39/74] Check for ICE mismatch and add the ice-mismatch attribute in the SDP if there is a mismatch. --- coreapi/sal_eXosip2_sdp.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index dff2de574..baac6583a 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -250,6 +250,10 @@ static void add_ice_candidates(sdp_message_t *msg, int lineno, const IceCheckLis const IceCandidate *candidate; int i; + if ((ice_check_list_state(ice_cl) == ICL_Failed) && ice_check_list_is_mismatch(ice_cl)) { + sdp_message_a_attribute_add(msg, lineno, osip_strdup("ice-mismatch"), NULL); + return; + } for (i = 0; i < ms_list_size(ice_cl->local_candidates); i++) { candidate = ms_list_nth_data(ice_cl->local_candidates, i); switch (ice_check_list_state(ice_cl)) { @@ -697,6 +701,7 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc, IceS } else { ice_session_set_role(*ice_session, IR_Controlled); } + ice_session_check_mismatch(*ice_session); } if ((ice_ufrag != NULL) && (ice_pwd != NULL)) { ice_session_set_remote_credentials(*ice_session, ice_ufrag, ice_pwd); From 3c3051a0becc08909bc97daea182a03ec25e46f0 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 27 Jul 2012 16:02:31 +0200 Subject: [PATCH 40/74] Set the state of an ICE check list to Failed if an ice-mismatch attribute is received for it. --- coreapi/sal_eXosip2_sdp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index baac6583a..bf6c196a9 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -652,6 +652,8 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc, IceS ice_ufrag = attr->a_att_value; } else if ((keywordcmp("ice-pwd", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { ice_pwd = attr->a_att_value; + } else if (keywordcmp("ice-mismatch", attr->a_att_field) == 0) { + ice_check_list_set_state(ice_session_check_list(*ice_session, i), ICL_Failed); } } if ((*ice_session != NULL) && ice_session_check_list(*ice_session, i)) { From 6d0083a1f45eab2aadf73dcd1c349d5a58d1b6c1 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 31 Jul 2012 09:05:47 +0200 Subject: [PATCH 41/74] Asynchronous ICE candidates gathering. --- coreapi/linphonecall.c | 38 ++++++++--- coreapi/linphonecore.c | 21 +++++++ coreapi/misc.c | 140 +++++------------------------------------ coreapi/private.h | 3 +- 4 files changed, 68 insertions(+), 134 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 7c9ef7bf6..75518a143 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -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); } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 40b2a647d..060259a48 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -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{ diff --git a/coreapi/misc.c b/coreapi/misc.c index 51f217c70..0e4be8e11 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -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); + 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)) { - 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); + 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); } - 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); - 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); - } + /* Gather local srflx candidates. */ + ice_session_gather_candidates(ice_session, ss, ss_len); + return 0; } LinphoneCall * is_a_linphone_call(void *user_pointer){ diff --git a/coreapi/private.h b/coreapi/private.h index 241da0223..33c6985dd 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -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); From 53d44ea8eea3d08f8e644887736db9bd21f9b35a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 31 Jul 2012 17:10:53 +0200 Subject: [PATCH 42/74] Add some checks to prevent crashes. --- gtk/incall_view.c | 1 + gtk/main.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/gtk/incall_view.c b/gtk/incall_view.c index d19dba8c2..7e8eb683f 100644 --- a/gtk/incall_view.c +++ b/gtk/incall_view.c @@ -557,6 +557,7 @@ void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_m guint taskid=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(callview),"taskid")); gboolean in_conf=linphone_call_params_local_conference_mode(linphone_call_get_current_params(call)); + if ((callview==NULL) || (status==NULL)) return; if (error_msg==NULL) gtk_label_set_markup(GTK_LABEL(status),_("Call ended.")); else{ diff --git a/gtk/main.c b/gtk/main.c index fa04a24e0..2955b3ecc 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -354,8 +354,10 @@ static void entry_unmapped(GtkWidget *entry){ } GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){ - GtkBuilder *builder=(GtkBuilder*)g_object_get_data(G_OBJECT(window),"builder"); + GtkBuilder *builder; GObject *w; + if (window==NULL) return NULL; + builder=(GtkBuilder*)g_object_get_data(G_OBJECT(window),"builder"); if (builder==NULL){ g_error("Fail to retrieve builder from window !"); return NULL; From 950c65ffd9077845ddf9f69a84d588d92a627ad0 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 31 Jul 2012 17:14:15 +0200 Subject: [PATCH 43/74] Defer ringing when ICE is activated to be able to gather local candidates. --- coreapi/callbacks.c | 70 ++--------------- coreapi/linphonecall.c | 174 +++++++++++++++++++++++------------------ coreapi/linphonecore.c | 72 +++++++++++++++++ coreapi/linphonecore.h | 2 + 4 files changed, 176 insertions(+), 142 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 8ec8f39b1..cd3290aa6 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -140,16 +140,10 @@ static bool_t already_a_call_pending(LinphoneCore *lc){ static void call_received(SalOp *h){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h)); - char *barmesg; LinphoneCall *call; const char *from,*to; - char *tmp; - LinphoneAddress *from_parsed; LinphoneAddress *from_addr, *to_addr; - SalMediaDescription *md; - bool_t propose_early_media=lp_config_get_int(lc->config,"sip","incoming_calls_early_media",FALSE); bool_t prevent_colliding_calls=lp_config_get_int(lc->config,"sip","prevent_colliding_calls",TRUE); - const char *ringback_tone=linphone_core_get_remote_ringback_tone (lc); /* first check if we can answer successfully to this invite */ if (lc->presence_mode==LinphoneStatusBusy || @@ -188,72 +182,18 @@ static void call_received(SalOp *h){ call=linphone_call_new_incoming(lc,from_addr,to_addr,h); sal_call_set_local_media_description(h,call->localdesc); - md=sal_call_get_final_media_description(h); - - if (md && sal_media_description_empty(md)){ - sal_call_decline(h,SalReasonMedia,NULL); - linphone_call_unref(call); - return; - } /* the call is acceptable so we can now add it to our list */ linphone_core_add_call(lc,call); - - from_parsed=linphone_address_new(sal_op_get_from(h)); - linphone_address_clean(from_parsed); - tmp=linphone_address_as_string(from_parsed); - linphone_address_destroy(from_parsed); - barmesg=ortp_strdup_printf("%s %s%s",tmp,_("is contacting you"), - (sal_call_autoanswer_asked(h)) ?_(" and asked autoanswer."):_(".")); - if (lc->vtable.show) lc->vtable.show(lc); - if (lc->vtable.display_status) - lc->vtable.display_status(lc,barmesg); - - /* play the ring if this is the only call*/ - if (ms_list_size(lc->calls)==1){ - lc->current_call=call; - if (lc->ringstream && lc->dmfs_playing_start_time!=0){ - ring_stop(lc->ringstream); - lc->ringstream=NULL; - lc->dmfs_playing_start_time=0; - } - if (lc->sound_conf.ring_sndcard!=NULL){ - if(lc->ringstream==NULL && lc->sound_conf.local_ring){ - MSSndCard *ringcard=lc->sound_conf.lsd_card ?lc->sound_conf.lsd_card : lc->sound_conf.ring_sndcard; - ms_message("Starting local ring..."); - lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,ringcard); - } - else - { - ms_message("the local ring is already started"); - } - } - }else{ - /* else play a tone within the context of the current call */ - call->ringing_beep=TRUE; - linphone_core_play_tone(lc); - } - - linphone_call_ref(call); /*prevent the call from being destroyed while we are notifying, if the user declines within the state callback */ - linphone_call_set_state(call,LinphoneCallIncomingReceived,"Incoming call"); - - if (call->state==LinphoneCallIncomingReceived){ - sal_call_notify_ringing(h,propose_early_media || ringback_tone!=NULL); - if (propose_early_media || ringback_tone!=NULL){ - linphone_call_set_state(call,LinphoneCallIncomingEarlyMedia,"Incoming call early media"); - md=sal_call_get_final_media_description(h); - linphone_core_update_streams(lc,call,md); - } - if (sal_call_get_replaces(call->op)!=NULL && lp_config_get_int(lc->config,"sip","auto_answer_replacing_calls",1)){ - linphone_core_accept_call(lc,call); - } + if (linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) { + /* Defer ringing until the end of the ICE candidates gathering process. */ + ms_message("Defer ringing to gather ICE candidates"); + return; } - linphone_call_unref(call); - ms_free(barmesg); - ms_free(tmp); + linphone_core_notify_incoming_call(lc,call); } static void call_ringing(SalOp *h){ diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 75518a143..e2948f597 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -390,7 +390,14 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro call->camera_active=call->params.has_video; switch (linphone_core_get_firewall_policy(call->core)) { case LinphonePolicyUseIce: - linphone_core_gather_ice_candidates(call->core, call); + linphone_call_init_media_streams(call); + linphone_call_start_media_streams_for_ice_gathering(call); + if (linphone_core_gather_ice_candidates(call->core,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); + } break; case LinphonePolicyUseStun: linphone_core_run_stun_tests(call->core,call); @@ -1469,6 +1476,7 @@ void linphone_call_stop_media_streams(LinphoneCall *call){ rtp_session_unregister_event_queue(call->audiostream->session,call->audiostream_app_evq); ortp_ev_queue_flush(call->audiostream_app_evq); ortp_ev_queue_destroy(call->audiostream_app_evq); + call->audiostream_app_evq=NULL; if (call->audiostream->ec){ const char *state_str=NULL; @@ -1690,98 +1698,110 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse } #ifdef VIDEO_ENABLED if (call->videostream!=NULL) { + OrtpEvent *ev; + // Beware that the application queue should not depend on treatments fron the // mediastreamer queue. video_stream_iterate(call->videostream); - if (call->videostream_app_evq){ - OrtpEvent *ev; - while (NULL != (ev=ortp_ev_queue_get(call->videostream_app_evq))){ - OrtpEventType evt=ortp_event_get_type(ev); - OrtpEventData *evd=ortp_event_get_data(ev); - if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){ - linphone_call_videostream_encryption_changed(call, evd->info.zrtp_stream_encrypted); - } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) { - call->stats[LINPHONE_CALL_STATS_VIDEO].round_trip_delay = rtp_session_get_round_trip_propagation(call->videostream->session); - if(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp != NULL) - freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp); - call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp = evd->packet; - evd->packet = NULL; - if (lc->vtable.call_stats_updated) - lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]); - } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) { - memcpy(&call->stats[LINPHONE_CALL_STATS_VIDEO].jitter_stats, rtp_session_get_jitter_stats(call->videostream->session), sizeof(jitter_stats_t)); - if(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp != NULL) - freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp); - call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp = evd->packet; - evd->packet = NULL; - if (lc->vtable.call_stats_updated) - lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]); - } else if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) { - 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); - } + while (call->videostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->videostream_app_evq)))){ + OrtpEventType evt=ortp_event_get_type(ev); + OrtpEventData *evd=ortp_event_get_data(ev); + if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){ + linphone_call_videostream_encryption_changed(call, evd->info.zrtp_stream_encrypted); + } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) { + call->stats[LINPHONE_CALL_STATS_VIDEO].round_trip_delay = rtp_session_get_round_trip_propagation(call->videostream->session); + if(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp != NULL) + freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp); + call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp = evd->packet; + evd->packet = NULL; + if (lc->vtable.call_stats_updated) + lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]); + } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) { + memcpy(&call->stats[LINPHONE_CALL_STATS_VIDEO].jitter_stats, rtp_session_get_jitter_stats(call->videostream->session), sizeof(jitter_stats_t)); + if(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp != NULL) + freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp); + call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp = evd->packet; + evd->packet = NULL; + if (lc->vtable.call_stats_updated) + lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]); + } else if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) { + 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) { + IceSession *ice_session = sal_op_get_ice_session(call->op); + linphone_call_stop_media_streams(call); + if (evd->info.ice_processing_successful==TRUE) { + ice_session_compute_candidates_foundations(ice_session); + ice_session_eliminate_redundant_candidates(ice_session); + ice_session_choose_default_candidates(ice_session); + } else { + ice_session_destroy(ice_session); + sal_op_set_ice_session(call->op, NULL); + } + if (call->state==LinphoneCallOutgoingInit) { + linphone_core_start_invite(call->core,call,NULL); + } else { + linphone_core_notify_incoming_call(call->core,call); } - ortp_event_destroy(ev); } + ortp_event_destroy(ev); } } #endif if (call->audiostream!=NULL) { + OrtpEvent *ev; + // Beware that the application queue should not depend on treatments fron the // mediastreamer queue. audio_stream_iterate(call->audiostream); - if (call->audiostream_app_evq){ - OrtpEvent *ev; - while (NULL != (ev=ortp_ev_queue_get(call->audiostream_app_evq))){ - OrtpEventType evt=ortp_event_get_type(ev); - OrtpEventData *evd=ortp_event_get_data(ev); - if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){ - linphone_call_audiostream_encryption_changed(call, evd->info.zrtp_stream_encrypted); - } else if (evt == ORTP_EVENT_ZRTP_SAS_READY) { - linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified); - } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) { - call->stats[LINPHONE_CALL_STATS_AUDIO].round_trip_delay = rtp_session_get_round_trip_propagation(call->audiostream->session); - if(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp != NULL) - freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp); - call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp = evd->packet; - evd->packet = NULL; - if (lc->vtable.call_stats_updated) - lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]); - } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) { - memcpy(&call->stats[LINPHONE_CALL_STATS_AUDIO].jitter_stats, rtp_session_get_jitter_stats(call->audiostream->session), sizeof(jitter_stats_t)); - if(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp != NULL) - freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp); - call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp = evd->packet; - evd->packet = NULL; - if (lc->vtable.call_stats_updated) - lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]); - } else if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) { - 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); - } + while (call->audiostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->audiostream_app_evq)))){ + OrtpEventType evt=ortp_event_get_type(ev); + OrtpEventData *evd=ortp_event_get_data(ev); + if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){ + linphone_call_audiostream_encryption_changed(call, evd->info.zrtp_stream_encrypted); + } else if (evt == ORTP_EVENT_ZRTP_SAS_READY) { + linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified); + } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) { + call->stats[LINPHONE_CALL_STATS_AUDIO].round_trip_delay = rtp_session_get_round_trip_propagation(call->audiostream->session); + if(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp != NULL) + freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp); + call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp = evd->packet; + evd->packet = NULL; + if (lc->vtable.call_stats_updated) + lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]); + } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) { + memcpy(&call->stats[LINPHONE_CALL_STATS_AUDIO].jitter_stats, rtp_session_get_jitter_stats(call->audiostream->session), sizeof(jitter_stats_t)); + if(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp != NULL) + freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp); + call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp = evd->packet; + evd->packet = NULL; + if (lc->vtable.call_stats_updated) + lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]); + } else if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) { + 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) { + IceSession *ice_session = sal_op_get_ice_session(call->op); + linphone_call_stop_media_streams(call); + if (evd->info.ice_processing_successful==TRUE) { + ice_session_compute_candidates_foundations(ice_session); + ice_session_eliminate_redundant_candidates(ice_session); + ice_session_choose_default_candidates(ice_session); + } else { + ice_session_destroy(sal_op_get_ice_session(call->op)); + sal_op_set_ice_session(call->op, NULL); + } + if (call->state==LinphoneCallOutgoingInit) { + linphone_core_start_invite(call->core,call,NULL); + } else { + linphone_core_notify_incoming_call(call->core,call); } - ortp_event_destroy(ev); } + ortp_event_destroy(ev); } } if (call->state==LinphoneCallStreamsRunning && one_second_elapsed && call->audiostream!=NULL && disconnect_timeout>0 ) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 060259a48..73ef52c3f 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2373,6 +2373,78 @@ bool_t linphone_core_inc_invite_pending(LinphoneCore*lc){ return FALSE; } +void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ + char *barmesg; + char *tmp; + LinphoneAddress *from_parsed; + SalMediaDescription *md; + bool_t propose_early_media=lp_config_get_int(lc->config,"sip","incoming_calls_early_media",FALSE); + const char *ringback_tone=linphone_core_get_remote_ringback_tone (lc); + + /* Regenerate final media description to include all ICE candidates. */ + md=sal_call_get_final_media_description(call->op); + + if (md && sal_media_description_empty(md)){ + sal_call_decline(call->op,SalReasonMedia,NULL); + linphone_call_unref(call); + return; + } + + from_parsed=linphone_address_new(sal_op_get_from(call->op)); + linphone_address_clean(from_parsed); + tmp=linphone_address_as_string(from_parsed); + linphone_address_destroy(from_parsed); + barmesg=ortp_strdup_printf("%s %s%s",tmp,_("is contacting you"), + (sal_call_autoanswer_asked(call->op)) ?_(" and asked autoanswer."):_(".")); + if (lc->vtable.show) lc->vtable.show(lc); + if (lc->vtable.display_status) + lc->vtable.display_status(lc,barmesg); + + /* play the ring if this is the only call*/ + if (ms_list_size(lc->calls)==1){ + lc->current_call=call; + if (lc->ringstream && lc->dmfs_playing_start_time!=0){ + ring_stop(lc->ringstream); + lc->ringstream=NULL; + lc->dmfs_playing_start_time=0; + } + if (lc->sound_conf.ring_sndcard!=NULL){ + if(lc->ringstream==NULL && lc->sound_conf.local_ring){ + MSSndCard *ringcard=lc->sound_conf.lsd_card ?lc->sound_conf.lsd_card : lc->sound_conf.ring_sndcard; + ms_message("Starting local ring..."); + lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,ringcard); + } + else + { + ms_message("the local ring is already started"); + } + } + }else{ + /* else play a tone within the context of the current call */ + call->ringing_beep=TRUE; + linphone_core_play_tone(lc); + } + + linphone_call_set_state(call,LinphoneCallIncomingReceived,"Incoming call"); + + if (call->state==LinphoneCallIncomingReceived){ + sal_call_notify_ringing(call->op,propose_early_media || ringback_tone!=NULL); + + if (propose_early_media || ringback_tone!=NULL){ + linphone_call_set_state(call,LinphoneCallIncomingEarlyMedia,"Incoming call early media"); + md=sal_call_get_final_media_description(call->op); + linphone_core_update_streams(lc,call,md); + } + if (sal_call_get_replaces(call->op)!=NULL && lp_config_get_int(lc->config,"sip","auto_answer_replacing_calls",1)){ + linphone_core_accept_call(lc,call); + } + } + linphone_call_unref(call); + + ms_free(barmesg); + ms_free(tmp); +} + /** * @ingroup call_control * Updates a running call according to supplied call parameters or parameters changed in the LinphoneCore. diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 10f6108c9..67e887c60 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -783,6 +783,8 @@ int linphone_core_transfer_call_to_another(LinphoneCore *lc, LinphoneCall *call, bool_t linphone_core_inc_invite_pending(LinphoneCore*lc); +void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call); + bool_t linphone_core_in_call(const LinphoneCore *lc); LinphoneCall *linphone_core_get_current_call(const LinphoneCore *lc); From 922caf698f8df8d5d57f5154b51d5903a29a6412 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 1 Aug 2012 09:30:27 +0200 Subject: [PATCH 44/74] Fix some crashes related to asynchronous ICE candidates gathering. --- coreapi/callbacks.c | 11 +++++++++-- coreapi/linphonecall.c | 25 +++++++++++++++++-------- coreapi/linphonecore.c | 6 ++---- coreapi/private.h | 1 + 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index cd3290aa6..dd17650f5 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -187,7 +187,7 @@ static void call_received(SalOp *h){ linphone_core_add_call(lc,call); linphone_call_ref(call); /*prevent the call from being destroyed while we are notifying, if the user declines within the state callback */ - if (linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) { + if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && sal_op_get_ice_session(call->op)) { /* Defer ringing until the end of the ICE candidates gathering process. */ ms_message("Defer ringing to gather ICE candidates"); return; @@ -254,13 +254,20 @@ static void call_ringing(SalOp *h){ static void call_accepted(SalOp *op){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); + IceSession *ice_session=sal_op_get_ice_session(op); SalMediaDescription *md; if (call==NULL){ ms_warning("No call to accept."); return ; } - + + if (ice_session == NULL) { + /* Ensure the ICE check list pointers for the call streams are resetted to prevent crashes */ + if (call->audiostream != NULL) call->audiostream->ice_check_list = NULL; + if (call->videostream != NULL) call->videostream->ice_check_list = NULL; + } + md=sal_call_get_final_media_description(op); if (call->state==LinphoneCallOutgoingProgress || diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index e2948f597..52c01d455 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -394,8 +394,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro linphone_call_start_media_streams_for_ice_gathering(call); if (linphone_core_gather_ice_candidates(call->core,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_delete_ice_session(call); linphone_call_stop_media_streams(call); } break; @@ -404,8 +403,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro /* No break to also destroy ice session in this case. */ default: if (sal_op_get_ice_session(call->op) != NULL) { - ice_session_destroy(sal_op_get_ice_session(call->op)); - sal_op_set_ice_session(call->op, NULL); + linphone_call_delete_ice_session(call); } break; } @@ -1466,6 +1464,16 @@ void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call){ } } +void linphone_call_delete_ice_session(LinphoneCall *call){ + IceSession *ice_session = sal_op_get_ice_session(call->op); + if (ice_session != NULL) { + ice_session_destroy(ice_session); + sal_op_set_ice_session(call->op, NULL); + if (call->audiostream != NULL) call->audiostream->ice_check_list = NULL; + if (call->videostream != NULL) call->videostream->ice_check_list = NULL; + } +} + 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); @@ -1473,6 +1481,7 @@ static void linphone_call_log_fill_stats(LinphoneCallLog *log, AudioStream *st){ void linphone_call_stop_media_streams(LinphoneCall *call){ if (call->audiostream!=NULL) { + call->audiostream->ice_check_list = NULL; rtp_session_unregister_event_queue(call->audiostream->session,call->audiostream_app_evq); ortp_ev_queue_flush(call->audiostream_app_evq); ortp_ev_queue_destroy(call->audiostream_app_evq); @@ -1497,9 +1506,11 @@ void linphone_call_stop_media_streams(LinphoneCall *call){ #ifdef VIDEO_ENABLED if (call->videostream!=NULL){ + call->videostream->ice_check_list = NULL; rtp_session_unregister_event_queue(call->videostream->session,call->videostream_app_evq); ortp_ev_queue_flush(call->videostream_app_evq); ortp_ev_queue_destroy(call->videostream_app_evq); + call->videostream_app_evq=NULL; video_stream_stop(call->videostream); call->videostream=NULL; } @@ -1737,8 +1748,7 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse ice_session_eliminate_redundant_candidates(ice_session); ice_session_choose_default_candidates(ice_session); } else { - ice_session_destroy(ice_session); - sal_op_set_ice_session(call->op, NULL); + linphone_call_delete_ice_session(call); } if (call->state==LinphoneCallOutgoingInit) { linphone_core_start_invite(call->core,call,NULL); @@ -1792,8 +1802,7 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse ice_session_eliminate_redundant_candidates(ice_session); ice_session_choose_default_candidates(ice_session); } else { - ice_session_destroy(sal_op_get_ice_session(call->op)); - sal_op_set_ice_session(call->op, NULL); + linphone_call_delete_ice_session(call); } if (call->state==LinphoneCallOutgoingInit) { linphone_core_start_invite(call->core,call,NULL); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 73ef52c3f..da573d074 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1854,8 +1854,7 @@ void linphone_core_iterate(LinphoneCore *lc){ /*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_delete_ice_session(call); linphone_call_stop_media_streams(call); } linphone_core_start_invite(lc,call,NULL); @@ -2294,8 +2293,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const 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_delete_ice_session(call); linphone_call_stop_media_streams(call); } else { if (real_url!=NULL) ms_free(real_url); diff --git a/coreapi/private.h b/coreapi/private.h index 33c6985dd..1b826c574 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -247,6 +247,7 @@ 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); +void linphone_call_delete_ice_session(LinphoneCall *call); const char * linphone_core_get_identity(LinphoneCore *lc); const char * linphone_core_get_route(LinphoneCore *lc); From 8e50e1c2bd05e1b3697714f209b610c0a6b57ba6 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 1 Aug 2012 11:31:36 +0200 Subject: [PATCH 45/74] Fix some more crashes related to asynchronous ICE candidates gathering. --- coreapi/linphonecall.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 52c01d455..47b23b47e 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1711,6 +1711,9 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse if (call->videostream!=NULL) { OrtpEvent *ev; + /* Ensure there is no dangling ICE check list. */ + if (sal_op_get_ice_session(call->op) == NULL) call->videostream->ice_check_list = NULL; + // Beware that the application queue should not depend on treatments fron the // mediastreamer queue. video_stream_iterate(call->videostream); @@ -1763,6 +1766,9 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse if (call->audiostream!=NULL) { OrtpEvent *ev; + /* Ensure there is no dangling ICE check list. */ + if (sal_op_get_ice_session(call->op) == NULL) call->audiostream->ice_check_list = NULL; + // Beware that the application queue should not depend on treatments fron the // mediastreamer queue. audio_stream_iterate(call->audiostream); From bb80550705c3f03e5c27671b2dc781f8c61f1d1c Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 1 Aug 2012 11:34:51 +0200 Subject: [PATCH 46/74] Delete ICE session, when its state is Failed after receiving an answer from the peer (probably caused by ice-mismatch attributes). --- coreapi/sal_eXosip2_sdp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index bf6c196a9..1d25d1f51 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -709,7 +709,8 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc, IceS ice_session_set_remote_credentials(*ice_session, ice_ufrag, ice_pwd); ice_dump_session(*ice_session); } - if ((ice_session_just_created == FALSE) && ((ice_ufrag == NULL) || (ice_pwd == NULL))) { + if (((ice_session_just_created == FALSE) && ((ice_ufrag == NULL) || (ice_pwd == NULL))) + || (ice_session_state(*ice_session) == IS_Failed)) { /* We started with ICE activated but the peer apparently do not support ICE, so stop using it. */ ice_session_destroy(*ice_session); *ice_session = NULL; From 981accf8bb9ce0bd8904860146f08d00b0b0edd3 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 1 Aug 2012 15:11:39 +0200 Subject: [PATCH 47/74] Do not create an ICE check list if it has already been created. --- coreapi/linphonecall.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 47b23b47e..edf381a9f 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -248,7 +248,8 @@ static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, Li md->streams[i].crypto[1].algo = 0; md->streams[i].crypto[2].algo = 0; } - if ((call->dir == LinphoneCallOutgoing) && (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) && (ice_session != NULL)){ + if ((call->dir == LinphoneCallOutgoing) && (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) + && (ice_session != NULL) && (ice_session_check_list(ice_session, i) == NULL)) { ice_session_add_check_list(ice_session, ice_check_list_new()); } } From 652471f66f15c87f8625fdf82c270d38ae5d7038 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 1 Aug 2012 15:16:47 +0200 Subject: [PATCH 48/74] Defer call update when adding video during communication if ICE is activated to wait for ICE candidates gathering to finish. --- console/commands.c | 5 +- coreapi/linphonecall.c | 119 +++++++++++++++++++++++++++-------------- coreapi/linphonecore.h | 9 ++++ coreapi/private.h | 2 + gtk/incall_view.c | 6 +-- 5 files changed, 92 insertions(+), 49 deletions(-) diff --git a/console/commands.c b/console/commands.c index 472531795..7bebdd82b 100644 --- a/console/commands.c +++ b/console/commands.c @@ -2503,10 +2503,7 @@ static int lpc_cmd_camera(LinphoneCore *lc, char *args){ linphone_call_enable_camera(call,activated); if ((activated && !linphone_call_params_video_enabled (cp))){ /*update the call to add the video stream*/ - LinphoneCallParams *ncp=linphone_call_params_copy(cp); - linphone_call_params_enable_video(ncp,TRUE); - linphone_core_update_call(lc,call,ncp); - linphone_call_params_destroy (ncp); + linphone_call_enable_video(call,TRUE); linphonec_out("Trying to bring up video stream...\n"); } } diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index edf381a9f..c8b4c82d3 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -548,6 +548,26 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const } } +void linphone_call_enable_video(LinphoneCall *call, bool_t enabled) +{ + LinphoneCore *lc=linphone_call_get_core(call); + LinphoneCallParams *params=linphone_call_params_copy(linphone_call_get_current_params(call)); + + linphone_call_params_enable_video(params, enabled); + if ((enabled == TRUE) && (sal_op_get_ice_session(call->op))) { + /* Defer call update until the ICE candidates gathering process has finished. */ + ms_message("Defer call update to gather ICE candidates"); + call->params = *params; + update_local_media_description(lc, call); + linphone_call_init_video_stream(call); + video_stream_start_ice_gathering(call->videostream); + linphone_core_gather_ice_candidates(lc, call); + } else { + linphone_core_update_call(lc, call, params); + } + linphone_call_params_destroy(params); +} + static void linphone_call_destroy(LinphoneCall *obj) { if (obj->op!=NULL) { @@ -930,7 +950,7 @@ void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, Lin #endif } -void linphone_call_init_media_streams(LinphoneCall *call){ +void linphone_call_init_audio_stream(LinphoneCall *call){ LinphoneCore *lc=call->core; SalMediaDescription *md=call->localdesc; AudioStream *audiostream; @@ -975,15 +995,20 @@ void linphone_call_init_media_streams(LinphoneCall *call){ call->audiostream_app_evq = ortp_ev_queue_new(); rtp_session_register_event_queue(audiostream->session,call->audiostream_app_evq); +} +void linphone_call_init_video_stream(LinphoneCall *call){ #ifdef VIDEO_ENABLED + LinphoneCore *lc=call->core; + SalMediaDescription *md=call->localdesc; + IceSession *ice_session = sal_op_get_ice_session(call->op); if ((lc->video_conf.display || lc->video_conf.capture) && md->streams[1].rtp_port>0){ int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0); call->videostream=video_stream_new(md->streams[1].rtp_port,md->streams[1].rtcp_port,linphone_core_ipv6_enabled(lc)); video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0)); if (video_recv_buf_size>0) rtp_session_set_recv_buf_size(call->videostream->session,video_recv_buf_size); - + if( lc->video_conf.displaytype != NULL) video_stream_set_display_filter_name(call->videostream,lc->video_conf.displaytype); video_stream_set_event_callback(call->videostream,video_stream_event_cb, call); @@ -1008,6 +1033,11 @@ void linphone_call_init_media_streams(LinphoneCall *call){ #endif } +void linphone_call_init_media_streams(LinphoneCall *call){ + linphone_call_init_audio_stream(call); + linphone_call_init_video_stream(call); +} + static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'}; @@ -1687,6 +1717,49 @@ static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){ linphone_core_terminate_call(lc,call); } +static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){ + OrtpEventType evt=ortp_event_get_type(ev); + OrtpEventData *evd=ortp_event_get_data(ev); + + if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) { + if (ice_session_role(sal_op_get_ice_session(call->op)) == IR_Controlling) { + linphone_core_update_call(call->core, call, &call->current_params); + } + } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) { + IceSession *ice_session = sal_op_get_ice_session(call->op); + LinphoneCallParams *params; + switch (call->state) { + case LinphoneCallStreamsRunning: + if (evd->info.ice_processing_successful==TRUE) { + ice_session_compute_candidates_foundations(ice_session); + ice_session_eliminate_redundant_candidates(ice_session); + ice_session_choose_default_candidates(ice_session); + } + params = linphone_call_params_copy(linphone_call_get_current_params(call)); + linphone_call_params_enable_video(params, TRUE); + linphone_core_update_call(call->core, call, params); + linphone_call_params_destroy(params); + break; + case LinphoneCallOutgoingInit: + default: + linphone_call_stop_media_streams(call); + if (evd->info.ice_processing_successful==TRUE) { + ice_session_compute_candidates_foundations(ice_session); + ice_session_eliminate_redundant_candidates(ice_session); + ice_session_choose_default_candidates(ice_session); + } else { + linphone_call_delete_ice_session(call); + } + if (call->state==LinphoneCallOutgoingInit) { + linphone_core_start_invite(call->core,call,NULL); + } else { + linphone_core_notify_incoming_call(call->core,call); + } + break; + } + } +} + void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapsed){ LinphoneCore* lc = call->core; int disconnect_timeout = linphone_core_get_nortp_timeout(call->core); @@ -1740,25 +1813,8 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse evd->packet = NULL; if (lc->vtable.call_stats_updated) lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]); - } else if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) { - 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) { - IceSession *ice_session = sal_op_get_ice_session(call->op); - linphone_call_stop_media_streams(call); - if (evd->info.ice_processing_successful==TRUE) { - ice_session_compute_candidates_foundations(ice_session); - ice_session_eliminate_redundant_candidates(ice_session); - ice_session_choose_default_candidates(ice_session); - } else { - linphone_call_delete_ice_session(call); - } - if (call->state==LinphoneCallOutgoingInit) { - linphone_core_start_invite(call->core,call,NULL); - } else { - linphone_core_notify_incoming_call(call->core,call); - } + } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)) { + handle_ice_events(call, ev); } ortp_event_destroy(ev); } @@ -1797,25 +1853,8 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse evd->packet = NULL; if (lc->vtable.call_stats_updated) lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]); - } else if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) { - 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) { - IceSession *ice_session = sal_op_get_ice_session(call->op); - linphone_call_stop_media_streams(call); - if (evd->info.ice_processing_successful==TRUE) { - ice_session_compute_candidates_foundations(ice_session); - ice_session_eliminate_redundant_candidates(ice_session); - ice_session_choose_default_candidates(ice_session); - } else { - linphone_call_delete_ice_session(call); - } - if (call->state==LinphoneCallOutgoingInit) { - linphone_core_start_invite(call->core,call,NULL); - } else { - linphone_core_notify_incoming_call(call->core,call); - } + } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)) { + handle_ice_events(call, ev); } ortp_event_destroy(ev); } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 67e887c60..6b00cbc09 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -390,6 +390,15 @@ void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_t val); **/ bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call); +/** + * Enable or disable video for this call. + * @param call + * @param enabled + * + * @ingroup media_parameters + */ +void linphone_call_enable_video(LinphoneCall *call, bool_t enabled); + /*keep this in sync with mediastreamer2/msvolume.h*/ /** diff --git a/coreapi/private.h b/coreapi/private.h index 1b826c574..61d1d4179 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -243,6 +243,8 @@ void linphone_core_play_tone(LinphoneCore *lc); void linphone_call_init_stats(LinphoneCallStats *stats, int type); +void linphone_call_init_audio_stream(LinphoneCall *call); +void linphone_call_init_video_stream(LinphoneCall *call); 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); diff --git a/gtk/incall_view.c b/gtk/incall_view.c index 7e8eb683f..45e98609b 100644 --- a/gtk/incall_view.c +++ b/gtk/incall_view.c @@ -221,12 +221,8 @@ void linphone_gtk_create_in_call_view(LinphoneCall *call){ static void video_button_clicked(GtkWidget *button, LinphoneCall *call){ gboolean adding=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button),"adding_video")); - LinphoneCore *lc=linphone_call_get_core(call); - LinphoneCallParams *params=linphone_call_params_copy(linphone_call_get_current_params(call)); gtk_widget_set_sensitive(button,FALSE); - linphone_call_params_enable_video(params,adding); - linphone_core_update_call(lc,call,params); - linphone_call_params_destroy(params); + linphone_call_enable_video(call,adding); } void linphone_gtk_update_video_button(LinphoneCall *call){ From 623e9e181346d7039e6f5a43beabaf1b4021b393 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 1 Aug 2012 15:56:34 +0200 Subject: [PATCH 49/74] Remove ICE check lists from media streams that are removed from the SDP. --- coreapi/sal_eXosip2_sdp.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 1d25d1f51..1cd88cad7 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -680,6 +680,10 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc, IceS if ((ice_ufrag != NULL) && (ice_pwd != NULL)) { ice_check_list_set_remote_credentials(ice_session_check_list(*ice_session, i), ice_ufrag, ice_pwd); } + if (stream->rtp_port == 0) { + /* This stream has been deactivated by the peer, delete the check list. */ + ice_session_remove_check_list(*ice_session, ice_session_check_list(*ice_session, i)); + } ice_dump_candidates(ice_session_check_list(*ice_session, i)); } } @@ -697,6 +701,7 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc, IceS } } if (*ice_session != NULL) { + int nb_check_lists; if (ice_session_just_created == TRUE) { if (ice_lite == TRUE) { ice_session_set_role(*ice_session, IR_Controlling); @@ -705,6 +710,9 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc, IceS } ice_session_check_mismatch(*ice_session); } + while ((nb_check_lists = ice_session_nb_check_lists(*ice_session)) > desc->nstreams) { + ice_session_remove_check_list(*ice_session, ice_session_check_list(*ice_session, nb_check_lists - 1)); + } if ((ice_ufrag != NULL) && (ice_pwd != NULL)) { ice_session_set_remote_credentials(*ice_session, ice_ufrag, ice_pwd); ice_dump_session(*ice_session); From e5103d7a76c3574ebd2432eb52431a3f171842da Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 1 Aug 2012 16:06:19 +0200 Subject: [PATCH 50/74] Remove ICE check list from the session when removing video from the communication. --- coreapi/linphonecall.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index c8b4c82d3..b604c9de1 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -552,17 +552,26 @@ void linphone_call_enable_video(LinphoneCall *call, bool_t enabled) { LinphoneCore *lc=linphone_call_get_core(call); LinphoneCallParams *params=linphone_call_params_copy(linphone_call_get_current_params(call)); + IceSession *ice_session=sal_op_get_ice_session(call->op); linphone_call_params_enable_video(params, enabled); - if ((enabled == TRUE) && (sal_op_get_ice_session(call->op))) { - /* Defer call update until the ICE candidates gathering process has finished. */ - ms_message("Defer call update to gather ICE candidates"); - call->params = *params; - update_local_media_description(lc, call); - linphone_call_init_video_stream(call); - video_stream_start_ice_gathering(call->videostream); - linphone_core_gather_ice_candidates(lc, call); + if (enabled == TRUE) { + if (ice_session != NULL) { + /* Defer call update until the ICE candidates gathering process has finished. */ + ms_message("Defer call update to gather ICE candidates"); + call->params = *params; + update_local_media_description(lc, call); + linphone_call_init_video_stream(call); + video_stream_start_ice_gathering(call->videostream); + linphone_core_gather_ice_candidates(lc, call); + } else { + linphone_core_update_call(lc, call, params); + } } else { + if (ice_session != NULL) { + ice_session_remove_check_list(ice_session, call->videostream->ice_check_list); + call->videostream->ice_check_list = NULL; + } linphone_core_update_call(lc, call, params); } linphone_call_params_destroy(params); From 65c46c6cb81c4ae173fb975cb5c11067519491b0 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 2 Aug 2012 12:16:25 +0200 Subject: [PATCH 51/74] Defer acceptation of video activation to gather ICE candidates if ICE is enabled. --- coreapi/linphonecall.c | 21 +++++++++++++++++---- gtk/main.c | 6 +----- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index b604c9de1..19e64b096 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -565,14 +565,22 @@ void linphone_call_enable_video(LinphoneCall *call, bool_t enabled) video_stream_start_ice_gathering(call->videostream); linphone_core_gather_ice_candidates(lc, call); } else { - linphone_core_update_call(lc, call, params); + if (linphone_call_get_state(call) == LinphoneCallUpdatedByRemote) { + linphone_core_accept_call_update(lc, call, params); + } else { + linphone_core_update_call(lc, call, params); + } } } else { if (ice_session != NULL) { ice_session_remove_check_list(ice_session, call->videostream->ice_check_list); call->videostream->ice_check_list = NULL; } - linphone_core_update_call(lc, call, params); + if (linphone_call_get_state(call) == LinphoneCallUpdatedByRemote) { + linphone_core_accept_call_update(lc, call, params); + } else { + linphone_core_update_call(lc, call, params); + } } linphone_call_params_destroy(params); } @@ -1026,7 +1034,7 @@ void linphone_call_init_video_stream(LinphoneCall *call){ RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->video_port+1); rtp_session_set_transports(call->videostream->session,vrtp,vrtcp); } - if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (ice_session != NULL)){ + if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (ice_session != NULL) && (ice_session_check_list(ice_session, 1))){ 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); @@ -1739,6 +1747,7 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){ LinphoneCallParams *params; switch (call->state) { case LinphoneCallStreamsRunning: + case LinphoneCallUpdatedByRemote: if (evd->info.ice_processing_successful==TRUE) { ice_session_compute_candidates_foundations(ice_session); ice_session_eliminate_redundant_candidates(ice_session); @@ -1746,7 +1755,11 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){ } params = linphone_call_params_copy(linphone_call_get_current_params(call)); linphone_call_params_enable_video(params, TRUE); - linphone_core_update_call(call->core, call, params); + if (call->state == LinphoneCallStreamsRunning) { + linphone_core_update_call(call->core, call, params); + } else { /* LinphoneCallUpdatedByRemote */ + linphone_core_accept_call_update(call->core, call, params); + } linphone_call_params_destroy(params); break; case LinphoneCallOutgoingInit: diff --git a/gtk/main.c b/gtk/main.c index 2955b3ecc..054677654 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -1080,11 +1080,7 @@ static void linphone_gtk_notify(LinphoneCall *call, const char *msg){ static void on_call_updated_response(GtkWidget *dialog, gint responseid, LinphoneCall *call){ if (linphone_call_get_state(call)==LinphoneCallUpdatedByRemote){ - LinphoneCore *lc=linphone_call_get_core(call); - LinphoneCallParams *params=linphone_call_params_copy(linphone_call_get_current_params(call)); - linphone_call_params_enable_video(params,responseid==GTK_RESPONSE_YES); - linphone_core_accept_call_update(lc,call,params); - linphone_call_params_destroy(params); + linphone_call_enable_video(call, responseid==GTK_RESPONSE_YES); } linphone_call_unref(call); g_source_remove_by_user_data(dialog); From fa824200e39d50277abb0e92bd50571ecd37a363 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 2 Aug 2012 15:39:48 +0200 Subject: [PATCH 52/74] Prevent video stop on ICE reinvite when video connectivity checks are finished. --- coreapi/linphonecore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index da573d074..921e1800e 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2538,7 +2538,7 @@ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const return -1; } if (params==NULL){ - call->params.has_video=lc->video_policy.automatically_accept; + call->params.has_video=lc->video_policy.automatically_accept || call->current_params.has_video; }else call->params=*params; From 93db3330b68ed6e0d6e21da915eb904dde151c3f Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 2 Aug 2012 18:03:48 +0200 Subject: [PATCH 53/74] Prevent crash, video stream may not exist at this time. --- coreapi/linphonecall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 19e64b096..d8fcb12c9 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -572,7 +572,7 @@ void linphone_call_enable_video(LinphoneCall *call, bool_t enabled) } } } else { - if (ice_session != NULL) { + if ((ice_session != NULL) && (call->videostream != NULL)) { ice_session_remove_check_list(ice_session, call->videostream->ice_check_list); call->videostream->ice_check_list = NULL; } From 6f2853c8a0efd2fb335cac7513b42f452d4238f8 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 3 Aug 2012 10:53:49 +0200 Subject: [PATCH 54/74] Redesign ICE integration to prevent Sal from depending on ICE. - Move the ICE session from the Sal Op to the LinphoneCall. - Do not access directly to the ICE session to generate the SDP from the media description or to generate the media description from the SDP. Instead include ICE attributes in the media description. --- coreapi/callbacks.c | 5 +- coreapi/linphonecall.c | 63 ++++---- coreapi/linphonecore.c | 2 +- coreapi/misc.c | 9 +- coreapi/private.h | 1 + coreapi/sal.c | 10 -- coreapi/sal.h | 41 ++++- coreapi/sal_eXosip2.c | 37 ++--- coreapi/sal_eXosip2.h | 4 +- coreapi/sal_eXosip2_sdp.c | 326 ++++++++++++-------------------------- 10 files changed, 187 insertions(+), 311 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index dd17650f5..63327de66 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -187,7 +187,7 @@ static void call_received(SalOp *h){ linphone_core_add_call(lc,call); linphone_call_ref(call); /*prevent the call from being destroyed while we are notifying, if the user declines within the state callback */ - if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && sal_op_get_ice_session(call->op)) { + if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)) { /* Defer ringing until the end of the ICE candidates gathering process. */ ms_message("Defer ringing to gather ICE candidates"); return; @@ -254,7 +254,6 @@ static void call_ringing(SalOp *h){ static void call_accepted(SalOp *op){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); - IceSession *ice_session=sal_op_get_ice_session(op); SalMediaDescription *md; if (call==NULL){ @@ -262,7 +261,7 @@ static void call_accepted(SalOp *op){ return ; } - if (ice_session == NULL) { + if (call->ice_session == NULL) { /* Ensure the ICE check list pointers for the call streams are resetted to prevent crashes */ if (call->audiostream != NULL) call->audiostream->ice_check_list = NULL; if (call->videostream != NULL) call->videostream->ice_check_list = NULL; diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index d8fcb12c9..4a06a7873 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -201,7 +201,6 @@ static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, Li LinphoneAddress *addr=linphone_address_new(me); const char *username=linphone_address_get_username (addr); SalMediaDescription *md=sal_media_description_new(); - IceSession *ice_session=sal_op_get_ice_session(call->op); md->session_id=session_id; md->session_ver=session_ver; @@ -249,8 +248,8 @@ static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, Li md->streams[i].crypto[2].algo = 0; } if ((call->dir == LinphoneCallOutgoing) && (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) - && (ice_session != NULL) && (ice_session_check_list(ice_session, i) == NULL)) { - ice_session_add_check_list(ice_session, ice_check_list_new()); + && (call->ice_session != NULL) && (ice_session_check_list(call->ice_session, i) == NULL)) { + ice_session_add_check_list(call->ice_session, ice_check_list_new()); } } @@ -346,8 +345,8 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr linphone_call_init_common(call,from,to); call->params=*params; if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) { - sal_op_set_ice_session(call->op, ice_session_new()); - ice_session_set_role(sal_op_get_ice_session(call->op), IR_Controlling); + call->ice_session = ice_session_new(); + ice_session_set_role(call->ice_session, IR_Controlling); } call->localdesc=create_local_media_description (lc,call); call->camera_active=params->has_video; @@ -403,9 +402,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro linphone_core_run_stun_tests(call->core,call); /* No break to also destroy ice session in this case. */ default: - if (sal_op_get_ice_session(call->op) != NULL) { - linphone_call_delete_ice_session(call); - } + linphone_call_delete_ice_session(call); break; } discover_mtu(lc,linphone_address_get_domain(from)); @@ -552,11 +549,10 @@ void linphone_call_enable_video(LinphoneCall *call, bool_t enabled) { LinphoneCore *lc=linphone_call_get_core(call); LinphoneCallParams *params=linphone_call_params_copy(linphone_call_get_current_params(call)); - IceSession *ice_session=sal_op_get_ice_session(call->op); linphone_call_params_enable_video(params, enabled); if (enabled == TRUE) { - if (ice_session != NULL) { + 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"); call->params = *params; @@ -572,8 +568,8 @@ void linphone_call_enable_video(LinphoneCall *call, bool_t enabled) } } } else { - if ((ice_session != NULL) && (call->videostream != NULL)) { - ice_session_remove_check_list(ice_session, call->videostream->ice_check_list); + if ((call->ice_session != NULL) && (call->videostream != NULL)) { + ice_session_remove_check_list(call->ice_session, call->videostream->ice_check_list); call->videostream->ice_check_list = NULL; } if (linphone_call_get_state(call) == LinphoneCallUpdatedByRemote) { @@ -610,6 +606,9 @@ static void linphone_call_destroy(LinphoneCall *obj) if (obj->auth_token) { ms_free(obj->auth_token); } + if (obj->ice_session) { + ice_session_destroy(obj->ice_session); + } ms_free(obj); } @@ -971,7 +970,6 @@ void linphone_call_init_audio_stream(LinphoneCall *call){ LinphoneCore *lc=call->core; SalMediaDescription *md=call->localdesc; AudioStream *audiostream; - IceSession *ice_session = sal_op_get_ice_session(call->op); call->audiostream=audiostream=audio_stream_new(md->streams[0].rtp_port,md->streams[0].rtcp_port,linphone_core_ipv6_enabled(lc)); if (linphone_core_echo_limiter_enabled(lc)){ @@ -1004,9 +1002,9 @@ void linphone_call_init_audio_stream(LinphoneCall *call){ RtpTransport *artcp=lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->audio_port+1); rtp_session_set_transports(audiostream->session,artp,artcp); } - if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (ice_session != NULL)){ + if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){ rtp_session_set_pktinfo(audiostream->session, TRUE); - audiostream->ice_check_list = ice_session_check_list(ice_session, 0); + audiostream->ice_check_list = ice_session_check_list(call->ice_session, 0); ice_check_list_set_rtp_session(audiostream->ice_check_list, audiostream->session); } @@ -1018,7 +1016,6 @@ void linphone_call_init_video_stream(LinphoneCall *call){ #ifdef VIDEO_ENABLED LinphoneCore *lc=call->core; SalMediaDescription *md=call->localdesc; - IceSession *ice_session = sal_op_get_ice_session(call->op); if ((lc->video_conf.display || lc->video_conf.capture) && md->streams[1].rtp_port>0){ int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0); @@ -1034,9 +1031,9 @@ void linphone_call_init_video_stream(LinphoneCall *call){ RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->video_port+1); rtp_session_set_transports(call->videostream->session,vrtp,vrtcp); } - if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (ice_session != NULL) && (ice_session_check_list(ice_session, 1))){ + if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL) && (ice_session_check_list(call->ice_session, 1))){ rtp_session_set_pktinfo(call->videostream->session, TRUE); - call->videostream->ice_check_list = ice_session_check_list(ice_session, 1); + call->videostream->ice_check_list = ice_session_check_list(call->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(); @@ -1495,8 +1492,8 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut /*also reflect the change if the "wished" params, in order to avoid to propose SAVP or video again * further in the call, for example during pause,resume, conferencing reINVITEs*/ linphone_call_fix_call_parameters(call); - if ((sal_op_get_ice_session(call->op) != NULL) && (ice_session_state(sal_op_get_ice_session(call->op)) != IS_Completed)) { - ice_session_start_connectivity_checks(sal_op_get_ice_session(call->op)); + if ((call->ice_session != NULL) && (ice_session_state(call->ice_session) != IS_Completed)) { + ice_session_start_connectivity_checks(call->ice_session); } goto end; @@ -1513,10 +1510,9 @@ void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call){ } void linphone_call_delete_ice_session(LinphoneCall *call){ - IceSession *ice_session = sal_op_get_ice_session(call->op); - if (ice_session != NULL) { - ice_session_destroy(ice_session); - sal_op_set_ice_session(call->op, NULL); + if (call->ice_session != NULL) { + ice_session_destroy(call->ice_session); + call->ice_session = NULL; if (call->audiostream != NULL) call->audiostream->ice_check_list = NULL; if (call->videostream != NULL) call->videostream->ice_check_list = NULL; } @@ -1739,19 +1735,18 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){ OrtpEventData *evd=ortp_event_get_data(ev); if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) { - if (ice_session_role(sal_op_get_ice_session(call->op)) == IR_Controlling) { + if (ice_session_role(call->ice_session) == IR_Controlling) { linphone_core_update_call(call->core, call, &call->current_params); } } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) { - IceSession *ice_session = sal_op_get_ice_session(call->op); LinphoneCallParams *params; switch (call->state) { case LinphoneCallStreamsRunning: case LinphoneCallUpdatedByRemote: if (evd->info.ice_processing_successful==TRUE) { - ice_session_compute_candidates_foundations(ice_session); - ice_session_eliminate_redundant_candidates(ice_session); - ice_session_choose_default_candidates(ice_session); + ice_session_compute_candidates_foundations(call->ice_session); + ice_session_eliminate_redundant_candidates(call->ice_session); + ice_session_choose_default_candidates(call->ice_session); } params = linphone_call_params_copy(linphone_call_get_current_params(call)); linphone_call_params_enable_video(params, TRUE); @@ -1766,9 +1761,9 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){ default: linphone_call_stop_media_streams(call); if (evd->info.ice_processing_successful==TRUE) { - ice_session_compute_candidates_foundations(ice_session); - ice_session_eliminate_redundant_candidates(ice_session); - ice_session_choose_default_candidates(ice_session); + ice_session_compute_candidates_foundations(call->ice_session); + ice_session_eliminate_redundant_candidates(call->ice_session); + ice_session_choose_default_candidates(call->ice_session); } else { linphone_call_delete_ice_session(call); } @@ -1808,7 +1803,7 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse OrtpEvent *ev; /* Ensure there is no dangling ICE check list. */ - if (sal_op_get_ice_session(call->op) == NULL) call->videostream->ice_check_list = NULL; + if (call->ice_session == NULL) call->videostream->ice_check_list = NULL; // Beware that the application queue should not depend on treatments fron the // mediastreamer queue. @@ -1846,7 +1841,7 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse OrtpEvent *ev; /* Ensure there is no dangling ICE check list. */ - if (sal_op_get_ice_session(call->op) == NULL) call->audiostream->ice_check_list = NULL; + if (call->ice_session == NULL) call->audiostream->ice_check_list = NULL; // Beware that the application queue should not depend on treatments fron the // mediastreamer queue. diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 921e1800e..6f08e9260 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1852,7 +1852,7 @@ 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) { + if (call->ice_session != NULL) { /* ICE candidates gathering has not finished yet, proceed with the call without ICE anyway. */ linphone_call_delete_ice_session(call); linphone_call_stop_media_streams(call); diff --git a/coreapi/misc.c b/coreapi/misc.c index 0e4be8e11..a59aca886 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -569,12 +569,11 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) socklen_t ss_len; IceCheckList *audio_check_list; IceCheckList *video_check_list; - IceSession *ice_session = sal_op_get_ice_session(call->op); const char *server = linphone_core_get_stun_server(lc); - 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 ((server == NULL) || (call->ice_session == NULL)) return -1; + audio_check_list = ice_session_check_list(call->ice_session, 0); + video_check_list = ice_session_check_list(call->ice_session, 1); if (audio_check_list == NULL) return -1; if (lc->sip_conf.ipv6_enabled){ @@ -602,7 +601,7 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) } /* Gather local srflx candidates. */ - ice_session_gather_candidates(ice_session, ss, ss_len); + ice_session_gather_candidates(call->ice_session, ss, ss_len); return 0; } diff --git a/coreapi/private.h b/coreapi/private.h index 61d1d4179..bc65e946e 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -136,6 +136,7 @@ struct _LinphoneCall bool_t was_automatically_paused; CallCallbackObj nextVideoFrameDecoded; LinphoneCallStats stats[2]; + IceSession *ice_session; }; diff --git a/coreapi/sal.c b/coreapi/sal.c index 5b592b8d3..a7bb00e3e 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -234,10 +234,6 @@ void sal_op_set_user_pointer(SalOp *op, void *up){ ((SalOpBase*)op)->user_pointer=up; } -void sal_op_set_ice_session(SalOp *op, IceSession *ice_session){ - ((SalOpBase*)op)->ice_session=ice_session; -} - Sal *sal_op_get_sal(const SalOp *op){ return ((SalOpBase*)op)->root; } @@ -266,10 +262,6 @@ void *sal_op_get_user_pointer(const SalOp *op){ return ((SalOpBase*)op)->user_pointer; } -IceSession *sal_op_get_ice_session(const SalOp *op){ - return ((SalOpBase*)op)->ice_session; -} - const char *sal_op_get_proxy(const SalOp *op){ return ((SalOpBase*)op)->route; } @@ -318,8 +310,6 @@ void __sal_op_free(SalOp *op){ sal_media_description_unref(b->local_media); if (b->remote_media) sal_media_description_unref(b->remote_media); - if (b->ice_session) - ice_session_destroy(b->ice_session); ms_free(op); } diff --git a/coreapi/sal.h b/coreapi/sal.h index 8a51fa4a4..dfb560472 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -27,7 +27,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define sal_h #include "mediastreamer2/mscommon.h" -#include "mediastreamer2/ice.h" #include "ortp/ortp_srtp.h" /*Dirty hack, keep in sync with mediastreamer2/include/mediastream.h */ @@ -113,6 +112,33 @@ typedef struct SalEndpointCandidate{ #define SAL_ENDPOINT_CANDIDATE_MAX 2 +#define SAL_MEDIA_DESCRIPTION_MAX_ICE_ADDR_LEN 64 +#define SAL_MEDIA_DESCRIPTION_MAX_ICE_FOUNDATION_LEN 32 +#define SAL_MEDIA_DESCRIPTION_MAX_ICE_TYPE_LEN 6 + +typedef struct SalIceCandidate { + char addr[SAL_MEDIA_DESCRIPTION_MAX_ICE_ADDR_LEN]; + char raddr[SAL_MEDIA_DESCRIPTION_MAX_ICE_ADDR_LEN]; + char foundation[SAL_MEDIA_DESCRIPTION_MAX_ICE_FOUNDATION_LEN]; + char type[SAL_MEDIA_DESCRIPTION_MAX_ICE_TYPE_LEN]; + unsigned int componentID; + unsigned int priority; + int port; + int rport; +} SalIceCandidate; + +#define SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES 10 + +typedef struct SalIceRemoteCandidate { + char addr[SAL_MEDIA_DESCRIPTION_MAX_ICE_ADDR_LEN]; + int port; +} SalIceRemoteCandidate; + +#define SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES 2 + +#define SAL_MEDIA_DESCRIPTION_MAX_ICE_UFRAG_LEN 256 +#define SAL_MEDIA_DESCRIPTION_MAX_ICE_PWD_LEN 256 + typedef struct SalSrtpCryptoAlgo { unsigned int tag; enum ortp_srtp_crypto_suite_t algo; @@ -138,6 +164,11 @@ typedef struct SalStreamDescription{ SalSrtpCryptoAlgo crypto[SAL_CRYPTO_ALGO_MAX]; unsigned int crypto_local_tag; int max_rate; + SalIceCandidate ice_candidates[SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES]; + SalIceRemoteCandidate ice_remote_candidates[SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES]; + char ice_ufrag[SAL_MEDIA_DESCRIPTION_MAX_ICE_UFRAG_LEN]; + char ice_pwd[SAL_MEDIA_DESCRIPTION_MAX_ICE_PWD_LEN]; + bool_t ice_mismatch; } SalStreamDescription; #define SAL_MEDIA_DESCRIPTION_MAX_STREAMS 4 @@ -151,10 +182,13 @@ typedef struct SalMediaDescription{ unsigned int session_ver; unsigned int session_id; SalStreamDescription streams[SAL_MEDIA_DESCRIPTION_MAX_STREAMS]; + char ice_ufrag[SAL_MEDIA_DESCRIPTION_MAX_ICE_UFRAG_LEN]; + char ice_pwd[SAL_MEDIA_DESCRIPTION_MAX_ICE_PWD_LEN]; + bool_t ice_lite; + bool_t ice_completed; } SalMediaDescription; #define SAL_MEDIA_DESCRIPTION_MAX_MESSAGE_ATTRIBUTES 5 -#define SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES 10 SalMediaDescription *sal_media_description_new(); void sal_media_description_ref(SalMediaDescription *md); @@ -177,7 +211,6 @@ typedef struct SalOpBase{ char *remote_ua; SalMediaDescription *local_media; SalMediaDescription *remote_media; - IceSession *ice_session; void *user_pointer; } SalOpBase; @@ -322,7 +355,6 @@ void sal_op_release(SalOp *h); void sal_op_authenticate(SalOp *h, const SalAuthInfo *info); void sal_op_cancel_authentication(SalOp *h); void sal_op_set_user_pointer(SalOp *h, void *up); -void sal_op_set_ice_session(SalOp *h, IceSession *ice_session); int sal_op_get_auth_requested(SalOp *h, const char **realm, const char **username); const char *sal_op_get_from(const SalOp *op); const char *sal_op_get_to(const SalOp *op); @@ -334,7 +366,6 @@ const char *sal_op_get_network_origin(const SalOp *op); /*returns far-end "User-Agent" string */ const char *sal_op_get_remote_ua(const SalOp *op); void *sal_op_get_user_pointer(const SalOp *op); -IceSession *sal_op_get_ice_session(const SalOp *op); /*Call API*/ int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc); diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 42f11eca0..a9f3559b6 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -502,8 +502,8 @@ static void set_sdp(osip_message_t *sip,sdp_message_t *msg){ osip_free(sdp); } -static void set_sdp_from_desc(osip_message_t *sip, const SalMediaDescription *desc, const IceSession *ice_session){ - sdp_message_t *msg=media_description_to_sdp(desc, ice_session); +static void set_sdp_from_desc(osip_message_t *sip, const SalMediaDescription *desc){ + sdp_message_t *msg=media_description_to_sdp(desc); if (msg==NULL) { ms_error("Fail to print sdp message !"); return; @@ -526,7 +526,7 @@ static void sdp_process(SalOp *h){ sdp_message_free(h->sdp_answer); } offer_answer_initiate_incoming(h->base.local_media,h->base.remote_media,h->result,h->base.root->one_matching_codec); - h->sdp_answer=media_description_to_sdp(h->result, sal_op_get_ice_session(h)); + h->sdp_answer=media_description_to_sdp(h->result); /*once we have generated the SDP answer, we modify the result description for processing by the upper layer. It should contains media parameters constraint from the remote offer, not our response*/ strcpy(h->result->addr,h->base.remote_media->addr); @@ -600,7 +600,7 @@ int sal_call(SalOp *h, const char *from, const char *to){ } if (h->base.local_media){ h->sdp_offering=TRUE; - set_sdp_from_desc(invite,h->base.local_media,sal_op_get_ice_session(h)); + set_sdp_from_desc(invite,h->base.local_media); }else h->sdp_offering=FALSE; if (h->replaces){ osip_message_set_header(invite,"Replaces",h->replaces); @@ -668,7 +668,7 @@ int sal_call_accept(SalOp * h){ if (h->base.local_media){ /*this is the case where we received an invite without SDP*/ if (h->sdp_offering) { - set_sdp_from_desc(msg,h->base.local_media,sal_op_get_ice_session(h)); + set_sdp_from_desc(msg,h->base.local_media); }else{ if (h->sdp_answer==NULL) sdp_process(h); if (h->sdp_answer){ @@ -990,7 +990,6 @@ static void inc_new_call(Sal *sal, eXosip_event_t *ev){ osip_call_info_t *call_info; char *tmp; sdp_message_t *sdp=eXosip_get_sdp_info(ev->request); - IceSession *ice_session; set_network_origin(op,ev->request); set_remote_ua(op,ev->request); @@ -999,9 +998,7 @@ static void inc_new_call(Sal *sal, eXosip_event_t *ev){ if (sdp){ op->sdp_offering=FALSE; op->base.remote_media=sal_media_description_new(); - ice_session=sal_op_get_ice_session(op); - sdp_to_media_description(sdp,op->base.remote_media,&ice_session); - sal_op_set_ice_session(op,ice_session); + sdp_to_media_description(sdp,op->base.remote_media); sdp_message_free(sdp); }else op->sdp_offering=TRUE; @@ -1037,7 +1034,6 @@ static void inc_new_call(Sal *sal, eXosip_event_t *ev){ static void handle_reinvite(Sal *sal, eXosip_event_t *ev){ SalOp *op=find_op(sal,ev); sdp_message_t *sdp; - IceSession *ice_session; if (op==NULL) { ms_warning("Reinvite for non-existing operation !"); @@ -1057,9 +1053,7 @@ static void handle_reinvite(Sal *sal, eXosip_event_t *ev){ if (sdp){ op->sdp_offering=FALSE; op->base.remote_media=sal_media_description_new(); - ice_session=sal_op_get_ice_session(op); - sdp_to_media_description(sdp,op->base.remote_media,&ice_session); - sal_op_set_ice_session(op,ice_session); + sdp_to_media_description(sdp,op->base.remote_media); sdp_message_free(sdp); }else { @@ -1071,7 +1065,6 @@ static void handle_reinvite(Sal *sal, eXosip_event_t *ev){ static void handle_ack(Sal *sal, eXosip_event_t *ev){ SalOp *op=find_op(sal,ev); sdp_message_t *sdp; - IceSession *ice_session; if (op==NULL) { ms_warning("ack for non-existing call !"); @@ -1088,9 +1081,7 @@ static void handle_ack(Sal *sal, eXosip_event_t *ev){ if (op->base.remote_media) sal_media_description_unref(op->base.remote_media); op->base.remote_media=sal_media_description_new(); - ice_session=sal_op_get_ice_session(op); - sdp_to_media_description(sdp,op->base.remote_media,&ice_session); - sal_op_set_ice_session(op,ice_session); + sdp_to_media_description(sdp,op->base.remote_media); sdp_process(op); sdp_message_free(sdp); } @@ -1150,16 +1141,13 @@ static int call_proceeding(Sal *sal, eXosip_event_t *ev){ static void call_ringing(Sal *sal, eXosip_event_t *ev){ sdp_message_t *sdp; SalOp *op=find_op(sal,ev); - IceSession *ice_session; if (call_proceeding(sal, ev)==-1) return; set_remote_ua(op,ev->response); sdp=eXosip_get_sdp_info(ev->response); if (sdp){ op->base.remote_media=sal_media_description_new(); - ice_session=sal_op_get_ice_session(op); - sdp_to_media_description(sdp,op->base.remote_media,&ice_session); - sal_op_set_ice_session(op,ice_session); + sdp_to_media_description(sdp,op->base.remote_media); sdp_message_free(sdp); if (op->base.local_media) sdp_process(op); } @@ -1171,7 +1159,6 @@ static void call_accepted(Sal *sal, eXosip_event_t *ev){ osip_message_t *msg=NULL; SalOp *op=find_op(sal,ev); const char *contact; - IceSession *ice_session; if (op==NULL || op->terminated==TRUE) { ms_warning("This call has been already terminated."); @@ -1187,9 +1174,7 @@ static void call_accepted(Sal *sal, eXosip_event_t *ev){ sdp=eXosip_get_sdp_info(ev->response); if (sdp){ op->base.remote_media=sal_media_description_new(); - ice_session=sal_op_get_ice_session(op); - sdp_to_media_description(sdp,op->base.remote_media,&ice_session); - sal_op_set_ice_session(op,ice_session); + sdp_to_media_description(sdp,op->base.remote_media); sdp_message_free(sdp); if (op->base.local_media) sdp_process(op); } @@ -2427,7 +2412,7 @@ int sal_call_update(SalOp *h, const char *subject){ } if (h->base.local_media){ h->sdp_offering=TRUE; - set_sdp_from_desc(reinvite,h->base.local_media,sal_op_get_ice_session(h)); + set_sdp_from_desc(reinvite,h->base.local_media); }else h->sdp_offering=FALSE; eXosip_lock(); err = eXosip_call_send_request(h->did, reinvite); diff --git a/coreapi/sal_eXosip2.h b/coreapi/sal_eXosip2.h index e3264f74d..ccc95d56a 100644 --- a/coreapi/sal_eXosip2.h +++ b/coreapi/sal_eXosip2.h @@ -25,8 +25,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -sdp_message_t *media_description_to_sdp(const SalMediaDescription *sal, const IceSession *ice_session); -int sdp_to_media_description(sdp_message_t *sdp, SalMediaDescription *desc, IceSession **ice_session); +sdp_message_t *media_description_to_sdp(const SalMediaDescription *sal); +int sdp_to_media_description(sdp_message_t *sdp, SalMediaDescription *desc); struct Sal{ SalCallbacks callbacks; diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 1cd88cad7..e03e65bae 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -124,7 +124,7 @@ static int _sdp_message_get_mline_dir(sdp_message_t *sdp, int mline){ return SalStreamSendRecv; } -static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc, const IceSession *ice_session) +static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc) { sdp_message_t *local; int inet6; @@ -144,14 +144,6 @@ static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc, const osip_strdup ("IN"), inet6 ? osip_strdup("IP6") : osip_strdup ("IP4"), osip_strdup (desc->addr)); sdp_message_s_name_set (local, osip_strdup ("Talk")); - if ((ice_session != NULL) && (ice_session_check_list(ice_session, 0) != NULL)) { - if (ice_session_state(ice_session) == IS_Completed) { - ice_check_list_nominated_valid_local_candidate(ice_session_check_list(ice_session, 0), &rtp_addr, NULL, NULL, NULL); - } - else { - ice_check_list_default_local_candidate(ice_session_check_list(ice_session, 0), &rtp_addr, NULL, NULL, NULL); - } - } if(!sal_media_description_has_dir (desc,SalStreamSendOnly)) { sdp_message_c_connection_add (local, -1, @@ -167,23 +159,9 @@ static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc, const sdp_message_t_time_descr_add (local, osip_strdup ("0"), osip_strdup ("0")); if (desc->bandwidth>0) sdp_message_b_bandwidth_add (local, -1, osip_strdup ("AS"), int_2char(desc->bandwidth)); - if ((ice_session != NULL) && (ice_session_check_list(ice_session, 0) != NULL)) { - char buffer[512]; - switch (ice_session_state(ice_session)) { - case IS_Completed: - sdp_message_a_attribute_add(local, -1, osip_strdup("nortpproxy"), osip_strdup("yes")); - /* No break to also include the ice-ufrag and ice-pwd attributes when ICE session is completed. */ - case IS_Running: - case IS_Stopped: - snprintf(buffer, sizeof(buffer), "%s", ice_session_local_pwd(ice_session)); - sdp_message_a_attribute_add(local, -1, osip_strdup("ice-pwd"), osip_strdup(buffer)); - snprintf(buffer, sizeof(buffer), "%s", ice_session_local_ufrag(ice_session)); - sdp_message_a_attribute_add(local, -1, osip_strdup("ice-ufrag"), osip_strdup(buffer)); - break; - default: - break; - } - } + if (desc->ice_completed == TRUE) sdp_message_a_attribute_add(local, -1, osip_strdup("nortpproxy"), osip_strdup("yes")); + if (desc->ice_pwd[0] != '\0') sdp_message_a_attribute_add(local, -1, osip_strdup("ice-pwd"), osip_strdup(desc->ice_pwd)); + if (desc->ice_ufrag[0] != '\0') sdp_message_a_attribute_add(local, -1, osip_strdup("ice-ufrag"), osip_strdup(desc->ice_ufrag)); return local; } @@ -224,83 +202,57 @@ static void add_payload(sdp_message_t *msg, int line, const PayloadType *pt, boo } } -static void add_candidate_attribute(sdp_message_t *msg, int lineno, const IceCandidate *candidate) +static void add_ice_candidates(sdp_message_t *msg, int lineno, const SalStreamDescription *desc) { char buffer[1024]; + const SalIceCandidate *candidate; int nb; + int i; - nb = snprintf(buffer, sizeof(buffer), "%s %d UDP %d %s %d typ %s", - candidate->foundation, candidate->componentID, candidate->priority, candidate->taddr.ip, candidate->taddr.port, ice_candidate_type(candidate)); - if (nb < 0) { - ms_error("Cannot add ICE candidate attribute!"); - return; - } - if (candidate->type != ICT_HostCandidate) { - nb = snprintf(buffer + nb, sizeof(buffer) - nb, " raddr %s rport %d", candidate->base->taddr.ip, candidate->base->taddr.port); + for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES; i++) { + candidate = &desc->ice_candidates[i]; + if ((candidate->addr[0] == '\0') || (candidate->port == 0)) break; + nb = snprintf(buffer, sizeof(buffer), "%s %u UDP %u %s %d typ %s", + candidate->foundation, candidate->componentID, candidate->priority, candidate->addr, candidate->port, candidate->type); if (nb < 0) { ms_error("Cannot add ICE candidate attribute!"); return; } - } - sdp_message_a_attribute_add(msg, lineno, osip_strdup("candidate"), osip_strdup(buffer)); -} - -static void add_ice_candidates(sdp_message_t *msg, int lineno, const IceCheckList *ice_cl, const char *rtp_addr, int rtp_port, const char *rtcp_addr, int rtcp_port) -{ - const IceCandidate *candidate; - int i; - - if ((ice_check_list_state(ice_cl) == ICL_Failed) && ice_check_list_is_mismatch(ice_cl)) { - sdp_message_a_attribute_add(msg, lineno, osip_strdup("ice-mismatch"), NULL); - return; - } - for (i = 0; i < ms_list_size(ice_cl->local_candidates); i++) { - candidate = ms_list_nth_data(ice_cl->local_candidates, i); - switch (ice_check_list_state(ice_cl)) { - case ICL_Running: - add_candidate_attribute(msg, lineno, candidate); - break; - case ICL_Completed: - /* Only include the candidates matching the default destination for each component of the stream as specified in RFC5245 section 9.1.2.2. */ - if (((candidate->taddr.port == rtp_port) && (strlen(candidate->taddr.ip) == strlen(rtp_addr)) && (strcmp(candidate->taddr.ip, rtp_addr) == 0)) - || ((candidate->taddr.port == rtcp_port) && (strlen(candidate->taddr.ip) == strlen(rtcp_addr)) && (strcmp(candidate->taddr.ip, rtcp_addr) == 0))) { - add_candidate_attribute(msg, lineno, candidate); - } - break; - default: - break; - } - } -} - -static void add_ice_remote_candidates(sdp_message_t *msg, int lineno, const IceCheckList *ice_cl) -{ - char buffer[1024]; - const char *rtp_addr = NULL; - const char *rtcp_addr = NULL; - int rtp_port; - int rtcp_port; - int nb; - - if ((ice_session_role(ice_cl->session) == IR_Controlling) && (ice_check_list_state(ice_cl) == ICL_Completed)) { - ice_check_list_nominated_valid_remote_candidate(ice_cl, &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port); - nb = snprintf(buffer, sizeof(buffer), "1 %s %d", rtp_addr, rtp_port); - if (nb < 0) { - ms_error("Cannot add ICE remote-candidates attribute!"); - return; - } - if (rtcp_addr != NULL) { - nb = snprintf(buffer + nb, sizeof(buffer) - nb, " 2 %s %d", rtcp_addr, rtcp_port); + if (candidate->raddr[0] != '\0') { + nb = snprintf(buffer + nb, sizeof(buffer) - nb, " raddr %s rport %d", candidate->raddr, candidate->rport); if (nb < 0) { - ms_error("Cannot add ICE remote-candidates attribute!"); + ms_error("Cannot add ICE candidate attribute!"); return; } } - sdp_message_a_attribute_add(msg, lineno, osip_strdup("remote-candidates"), osip_strdup(buffer)); + sdp_message_a_attribute_add(msg, lineno, osip_strdup("candidate"), osip_strdup(buffer)); } } -static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription *desc, const IceCheckList *ice_cl){ +static void add_ice_remote_candidates(sdp_message_t *msg, int lineno, const SalStreamDescription *desc) +{ + char buffer[1024]; + char *ptr = buffer; + const SalIceRemoteCandidate *candidate; + int offset = 0; + int i; + + buffer[0] = '\0'; + for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES; i++) { + candidate = &desc->ice_remote_candidates[i]; + if ((candidate->addr[0] != '\0') && (candidate->port != 0)) { + offset = snprintf(ptr, buffer + sizeof(buffer) - ptr, "%s%d %s %d", (i > 0) ? " " : "", i + 1, candidate->addr, candidate->port); + if (offset < 0) { + ms_error("Cannot add ICE remote-candidates attribute!"); + return; + } + ptr += offset; + } + } + if (buffer[0] != '\0') sdp_message_a_attribute_add(msg, lineno, osip_strdup("remote-candidates"), osip_strdup(buffer)); +} + +static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription *desc){ const char *mt=NULL; const MSList *elem; const char *rtp_addr; @@ -309,6 +261,7 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription int rtp_port; int rtcp_port; bool_t strip_well_known_rtpmaps; + bool_t different_rtp_and_rtcp_addr; switch (desc->type) { case SalAudio: @@ -321,16 +274,11 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription mt=desc->typeother; break; } - rtp_addr=rtcp_addr=desc->rtp_addr; + rtp_addr=desc->rtp_addr; + rtcp_addr=desc->rtcp_addr; rtp_port=desc->rtp_port; rtcp_port=desc->rtcp_port; - if (ice_cl != NULL) { - if (ice_check_list_state(ice_cl) == ICL_Completed) { - ice_check_list_nominated_valid_local_candidate(ice_cl, &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port); - } else { - ice_check_list_default_local_candidate(ice_cl, &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port); - } - } else if (desc->candidates[0].addr[0]!='\0'){ + if (desc->candidates[0].addr[0]!='\0'){ rtp_addr=desc->candidates[0].addr; rtp_port=desc->candidates[0].port; } @@ -417,28 +365,34 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription break; } if (dir) sdp_message_a_attribute_add (msg, lineno, osip_strdup (dir),NULL); - if (ice_cl != NULL) { - if (strcmp(rtp_addr, rtcp_addr) != 0) { - char buffer[1024]; - snprintf(buffer, sizeof(buffer), "%u IN IP4 %s", rtcp_port, rtcp_addr); - sdp_message_a_attribute_add(msg, lineno, osip_strdup("rtcp"), osip_strdup(buffer)); - } else { - sdp_message_a_attribute_add(msg, lineno, osip_strdup("rtcp"), int_2char(rtcp_port)); + if (rtp_port != 0) { + different_rtp_and_rtcp_addr = (rtcp_addr[0] != '\0') && (strcmp(rtp_addr, rtcp_addr) != 0); + if ((rtcp_port != (rtp_port + 1)) || (different_rtp_and_rtcp_addr == TRUE)) { + if (different_rtp_and_rtcp_addr == TRUE) { + char buffer[1024]; + snprintf(buffer, sizeof(buffer), "%u IN IP4 %s", rtcp_port, rtcp_addr); + sdp_message_a_attribute_add(msg, lineno, osip_strdup("rtcp"), osip_strdup(buffer)); + } else { + sdp_message_a_attribute_add(msg, lineno, osip_strdup("rtcp"), int_2char(rtcp_port)); + } } - add_ice_candidates(msg, lineno, ice_cl, rtp_addr, rtp_port, rtcp_addr, rtcp_port); - add_ice_remote_candidates(msg, lineno, ice_cl); + } + if (desc->ice_mismatch == TRUE) { + sdp_message_a_attribute_add(msg, lineno, osip_strdup("ice-mismatch"), NULL); + } else { + if (desc->ice_pwd[0] != '\0') sdp_message_a_attribute_add(msg, lineno, osip_strdup("ice-pwd"), osip_strdup(desc->ice_pwd)); + if (desc->ice_ufrag[0] != '\0') sdp_message_a_attribute_add(msg, lineno, osip_strdup("ice-ufrag"), osip_strdup(desc->ice_ufrag)); + add_ice_candidates(msg, lineno, desc); + add_ice_remote_candidates(msg, lineno, desc); } } -sdp_message_t *media_description_to_sdp(const SalMediaDescription *desc, const IceSession *ice_session){ - IceCheckList *ice_cl = NULL; +sdp_message_t *media_description_to_sdp(const SalMediaDescription *desc){ int i; - sdp_message_t *msg=create_generic_sdp(desc, ice_session); + sdp_message_t *msg=create_generic_sdp(desc); for(i=0;instreams;++i){ - if (ice_session != NULL) ice_cl = ice_session_check_list(ice_session, i); - else ice_cl = NULL; - add_line(msg,i,&desc->streams[i], ice_cl); + add_line(msg,i,&desc->streams[i]); } return msg; } @@ -474,15 +428,12 @@ static int payload_type_fill_from_rtpmap(PayloadType *pt, const char *rtpmap){ return 0; } -int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc, IceSession **ice_session){ +int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ int i,j; const char *mtype,*proto,*rtp_port,*rtp_addr,*number; - const char *ice_ufrag, *ice_pwd, *ice_remote_candidates=NULL; sdp_bandwidth_t *sbw=NULL; sdp_attribute_t *attr; - int media_attribute_nb; - bool_t ice_session_just_created = FALSE; - bool_t ice_lite = FALSE; + int nb_ice_candidates; rtp_addr=sdp_message_c_addr_get (msg, -1, 0); if (rtp_addr) @@ -491,10 +442,22 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc, IceS if (strcasecmp(sbw->b_bwtype,"AS")==0) desc->bandwidth=atoi(sbw->b_bandwidth); } + /* Get ICE remote ufrag and remote pwd, and ice_lite flag */ + for (i = 0; (i < SAL_MEDIA_DESCRIPTION_MAX_MESSAGE_ATTRIBUTES) && ((attr = sdp_message_attribute_get(msg, -1, i)) != NULL); i++) { + if ((keywordcmp("ice-ufrag", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { + strncpy(desc->ice_ufrag, attr->a_att_value, sizeof(desc->ice_ufrag)); + } else if ((keywordcmp("ice-pwd", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { + strncpy(desc->ice_pwd, attr->a_att_value, sizeof(desc->ice_pwd)); + } else if (keywordcmp("ice-lite", attr->a_att_field) == 0) { + desc->ice_lite = TRUE; + } + } + /* for each m= line */ for (i=0; !sdp_message_endof_media (msg, i) && istreams[i]; + nb_ice_candidates = 0; memset(stream,0,sizeof(*stream)); mtype = sdp_message_m_media_get(msg, i); @@ -527,7 +490,6 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc, IceS if (strcasecmp(sbw->b_bwtype,"AS")==0) stream->bandwidth=atoi(sbw->b_bandwidth); } stream->dir=_sdp_message_get_mline_dir(msg,i); - media_attribute_nb = 0; /* for each payload type */ for (j=0;((number=sdp_message_m_payload_get (msg, i,j)) != NULL); j++){ const char *rtpmap,*fmtp; @@ -536,11 +498,9 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc, IceS payload_type_set_number(pt,ptn); /* get the rtpmap associated to this codec, if any */ rtpmap=sdp_message_a_attr_value_get_with_pt(msg, i,ptn,"rtpmap"); - if (rtpmap != NULL) media_attribute_nb++; if (payload_type_fill_from_rtpmap(pt,rtpmap)==0){ /* get the fmtp, if any */ fmtp=sdp_message_a_attr_value_get_with_pt(msg, i, ptn,"fmtp"); - if (fmtp != NULL) media_attribute_nb++; payload_type_set_send_fmtp(pt,fmtp); stream->payloads=ms_list_append(stream->payloads,pt); ms_message("Found payload %s/%i fmtp=%s",pt->mime_type,pt->clock_rate, @@ -608,121 +568,37 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc, IceS } /* Get ICE candidate attributes if any */ - ice_ufrag = ice_pwd = NULL; - for (j = 0; (j < SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES) && ((attr = sdp_message_attribute_get(msg, i, media_attribute_nb + j)) != NULL); j++) { + for (j = 0; (attr = sdp_message_attribute_get(msg, i, j)) != NULL; j++) { if ((keywordcmp("candidate", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { - char ip[64]; - char foundation[32]; - char type[6]; - unsigned int priority; - unsigned int componentID; - unsigned int port; - int nb; - - /* Allocate the ICE session if it has not been done yet. */ - if (*ice_session == NULL) { - *ice_session = ice_session_new(); - ice_session_just_created = TRUE; - } - /* Allocate the ICE check list if it has not been done yet. */ - if (ice_session_check_list(*ice_session, i) == NULL) { - ice_session_add_check_list(*ice_session, ice_check_list_new()); - } - nb = sscanf(attr->a_att_value, "%s %u UDP %u %s %u typ %s", - foundation, &componentID, &priority, ip, &port, type); - if (nb == 6) { - char *default_ip = desc->addr; - unsigned int default_port = stream->rtp_port; - bool_t is_default_candidate = FALSE; - if (componentID == 1) { - if ((stream->rtp_addr == NULL) || (stream->rtp_addr[0] == '\0')) default_ip = desc->addr; - else default_ip = stream->rtp_addr; - default_port = stream->rtp_port; - } else if (componentID == 2) { - if ((stream->rtcp_addr == NULL) || (stream->rtcp_addr[0] == '\0')) default_ip = desc->addr; - else default_ip = stream->rtcp_addr; - default_port = stream->rtcp_port; - } - if ((port == default_port) && (strlen(ip) == strlen(default_ip)) && (strcmp(ip, default_ip) == 0)) is_default_candidate = TRUE; - ice_add_remote_candidate(ice_session_check_list(*ice_session, i), type, ip, port, componentID, priority, foundation, is_default_candidate); - } + SalIceCandidate *candidate = &stream->ice_candidates[nb_ice_candidates]; + int nb = sscanf(attr->a_att_value, "%s %u UDP %u %s %d typ %s raddr %s rport %d", + candidate->foundation, &candidate->componentID, &candidate->priority, candidate->addr, &candidate->port, + candidate->type, candidate->raddr, &candidate->rport); + if ((nb == 6) || (nb == 8)) nb_ice_candidates++; + else memset(candidate, 0, sizeof(*candidate)); } else if ((keywordcmp("remote-candidates", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { - ice_remote_candidates = attr->a_att_value; - } else if ((keywordcmp("ice-ufrag", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { - ice_ufrag = attr->a_att_value; - } else if ((keywordcmp("ice-pwd", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { - ice_pwd = attr->a_att_value; - } else if (keywordcmp("ice-mismatch", attr->a_att_field) == 0) { - ice_check_list_set_state(ice_session_check_list(*ice_session, i), ICL_Failed); - } - } - if ((*ice_session != NULL) && ice_session_check_list(*ice_session, i)) { - if (ice_remote_candidates != NULL) { - char ip[64]; - unsigned int port; + SalIceRemoteCandidate candidate; unsigned int componentID; int offset; - - while (3 == sscanf(ice_remote_candidates, "%u %s %u%n", &componentID, ip, &port, &offset)) { - if (componentID == 1) { - if ((stream->rtp_addr == NULL) || (stream->rtp_addr[0] == '\0')) rtp_addr = desc->addr; - else rtp_addr = stream->rtp_addr; - ice_add_losing_pair(ice_session_check_list(*ice_session, i), componentID, ip, port, rtp_addr, stream->rtp_port); - } else if (componentID == 2) { - if ((stream->rtcp_addr == NULL) || (stream->rtcp_addr[0] == '\0')) rtp_addr = desc->addr; - else rtp_addr = stream->rtcp_addr; - ice_add_losing_pair(ice_session_check_list(*ice_session, i), componentID, ip, port, rtp_addr, stream->rtcp_port); + char *ptr = attr->a_att_value; + while (3 == sscanf(ptr, "%u %s %u%n", &componentID, candidate.addr, &candidate.port, &offset)) { + if ((componentID > 0) && (componentID <= SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES)) { + SalIceRemoteCandidate *remote_candidate = &stream->ice_remote_candidates[componentID - 1]; + strncpy(remote_candidate->addr, candidate.addr, sizeof(remote_candidate->addr)); + remote_candidate->port = candidate.port; } - ice_remote_candidates += offset; - if (ice_remote_candidates[offset] == ' ') ice_remote_candidates += 1; + ptr += offset; + if (ptr[offset] == ' ') ptr += 1; } + } else if ((keywordcmp("ice-ufrag", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { + strncpy(stream->ice_ufrag, attr->a_att_value, sizeof(stream->ice_ufrag)); + } else if ((keywordcmp("ice-pwd", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { + strncpy(stream->ice_pwd, attr->a_att_value, sizeof(stream->ice_pwd)); + } else if (keywordcmp("ice-mismatch", attr->a_att_field) == 0) { + stream->ice_mismatch = TRUE; } - if ((ice_ufrag != NULL) && (ice_pwd != NULL)) { - ice_check_list_set_remote_credentials(ice_session_check_list(*ice_session, i), ice_ufrag, ice_pwd); - } - if (stream->rtp_port == 0) { - /* This stream has been deactivated by the peer, delete the check list. */ - ice_session_remove_check_list(*ice_session, ice_session_check_list(*ice_session, i)); - } - ice_dump_candidates(ice_session_check_list(*ice_session, i)); } } desc->nstreams=i; - - /* Get ICE remote ufrag and remote pwd */ - ice_ufrag = ice_pwd = NULL; - for (i = 0; (i < SAL_MEDIA_DESCRIPTION_MAX_MESSAGE_ATTRIBUTES) && ((attr = sdp_message_attribute_get(msg, -1, i)) != NULL); i++) { - if ((keywordcmp("ice-ufrag", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { - ice_ufrag = attr->a_att_value; - } else if ((keywordcmp("ice-pwd", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { - ice_pwd = attr->a_att_value; - } else if (keywordcmp("ice-lite", attr->a_att_field) == 0) { - ice_lite = TRUE; - } - } - if (*ice_session != NULL) { - int nb_check_lists; - if (ice_session_just_created == TRUE) { - if (ice_lite == TRUE) { - ice_session_set_role(*ice_session, IR_Controlling); - } else { - ice_session_set_role(*ice_session, IR_Controlled); - } - ice_session_check_mismatch(*ice_session); - } - while ((nb_check_lists = ice_session_nb_check_lists(*ice_session)) > desc->nstreams) { - ice_session_remove_check_list(*ice_session, ice_session_check_list(*ice_session, nb_check_lists - 1)); - } - if ((ice_ufrag != NULL) && (ice_pwd != NULL)) { - ice_session_set_remote_credentials(*ice_session, ice_ufrag, ice_pwd); - ice_dump_session(*ice_session); - } - if (((ice_session_just_created == FALSE) && ((ice_ufrag == NULL) || (ice_pwd == NULL))) - || (ice_session_state(*ice_session) == IS_Failed)) { - /* We started with ICE activated but the peer apparently do not support ICE, so stop using it. */ - ice_session_destroy(*ice_session); - *ice_session = NULL; - } - } return 0; } From 5742b453cd3c1c636a53c0106e3e282654597cc4 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 3 Aug 2012 14:45:09 +0200 Subject: [PATCH 55/74] Handle conversion between media description and ice session. --- coreapi/callbacks.c | 7 +-- coreapi/linphonecall.c | 7 ++- coreapi/linphonecore.c | 14 ++++- coreapi/misc.c | 122 +++++++++++++++++++++++++++++++++++++++++ coreapi/offeranswer.c | 9 +++ coreapi/private.h | 2 + 6 files changed, 151 insertions(+), 10 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 63327de66..ba2789235 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -261,10 +261,9 @@ static void call_accepted(SalOp *op){ return ; } - if (call->ice_session == NULL) { - /* Ensure the ICE check list pointers for the call streams are resetted to prevent crashes */ - if (call->audiostream != NULL) call->audiostream->ice_check_list = NULL; - if (call->videostream != NULL) call->videostream->ice_check_list = NULL; + /* Handle remote ICE attributes if any. */ + if (call->ice_session != NULL) { + linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op)); } md=sal_call_get_final_media_description(op); diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 4a06a7873..7a1781696 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -247,8 +247,7 @@ static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, Li md->streams[i].crypto[1].algo = 0; md->streams[i].crypto[2].algo = 0; } - if ((call->dir == LinphoneCallOutgoing) && (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) - && (call->ice_session != NULL) && (ice_session_check_list(call->ice_session, i) == NULL)) { + if ((linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) && (call->ice_session != NULL) && (ice_session_check_list(call->ice_session, i) == NULL)) { ice_session_add_check_list(call->ice_session, ice_check_list_new()); } } @@ -390,6 +389,9 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro call->camera_active=call->params.has_video; switch (linphone_core_get_firewall_policy(call->core)) { case LinphonePolicyUseIce: + call->ice_session = ice_session_new(); + ice_session_set_role(call->ice_session, IR_Controlled); + linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op)); linphone_call_init_media_streams(call); linphone_call_start_media_streams_for_ice_gathering(call); if (linphone_core_gather_ice_candidates(call->core,call)<0) { @@ -402,7 +404,6 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro linphone_core_run_stun_tests(call->core,call); /* No break to also destroy ice session in this case. */ default: - linphone_call_delete_ice_session(call); break; } discover_mtu(lc,linphone_address_get_domain(from)); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 6f08e9260..1a0a85752 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2123,6 +2123,8 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphonePro audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard); if (!lc->sip_conf.sdp_200_ack){ call->media_pending=TRUE; + if (call->ice_session != NULL) + linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session); sal_call_set_local_media_description(call->op,call->localdesc); } real_url=linphone_address_as_string(call->log->to); @@ -2379,9 +2381,9 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ bool_t propose_early_media=lp_config_get_int(lc->config,"sip","incoming_calls_early_media",FALSE); const char *ringback_tone=linphone_core_get_remote_ringback_tone (lc); - /* Regenerate final media description to include all ICE candidates. */ + if (call->ice_session != NULL) + linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session); md=sal_call_get_final_media_description(call->op); - if (md && sal_media_description_empty(md)){ sal_call_decline(call->op,SalReasonMedia,NULL); linphone_call_unref(call); @@ -2464,7 +2466,9 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho call->params=*params; call->camera_active=call->params.has_video; update_local_media_description(lc,call); - + if (call->ice_session != NULL) + linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session); + if (params->in_conference){ subject="Conference"; }else{ @@ -2548,6 +2552,10 @@ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const } call->camera_active=call->params.has_video; update_local_media_description(lc,call); + if (call->ice_session != NULL) { + linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session); + linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(call->op)); + } sal_call_set_local_media_description(call->op,call->localdesc); sal_call_accept(call->op); md=sal_call_get_final_media_description(call->op); diff --git a/coreapi/misc.c b/coreapi/misc.c index a59aca886..81db63ad0 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -605,6 +605,128 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) return 0; } +void linphone_core_update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session) +{ + IceSessionState session_state = ice_session_state(session); + int i, j; + + if (session_state == IS_Completed) desc->ice_completed = TRUE; + else desc->ice_completed = FALSE; + strncpy(desc->ice_pwd, ice_session_local_pwd(session), sizeof(desc->ice_pwd)); + strncpy(desc->ice_ufrag, ice_session_local_ufrag(session), sizeof(desc->ice_ufrag)); + for (i = 0; i < desc->nstreams; i++) { + SalStreamDescription *stream = &desc->streams[i]; + IceCheckList *cl = ice_session_check_list(session, i); + if (cl == NULL) continue; + if ((strlen(ice_check_list_local_pwd(cl)) != strlen(desc->ice_pwd)) || (strcmp(ice_check_list_local_pwd(cl), desc->ice_pwd))) + strncpy(stream->ice_pwd, ice_check_list_local_pwd(cl), sizeof(stream->ice_pwd)); + else + memset(stream->ice_pwd, 0, sizeof(stream->ice_pwd)); + if ((strlen(ice_check_list_local_ufrag(cl)) != strlen(desc->ice_ufrag)) || (strcmp(ice_check_list_local_ufrag(cl), desc->ice_ufrag))) + strncpy(stream->ice_ufrag, ice_check_list_local_ufrag(cl), sizeof(stream->ice_ufrag)); + else + memset(stream->ice_pwd, 0, sizeof(stream->ice_pwd)); + if ((cl->state == ICL_Running) || (cl->state == ICL_Completed)) { + memset(stream->ice_candidates, 0, sizeof(stream->ice_candidates)); + for (j = 0; j < ms_list_size(cl->local_candidates); j++) { + SalIceCandidate *sal_candidate = &stream->ice_candidates[j]; + IceCandidate *ice_candidate = ms_list_nth_data(cl->local_candidates, j); + const char *default_addr = NULL; + int default_port = 0; + if (ice_candidate->componentID == 1) { + default_addr = stream->rtp_addr; + default_port = stream->rtp_port; + } else if (ice_candidate->componentID == 2) { + default_addr = stream->rtcp_addr; + default_port = stream->rtcp_port; + } else continue; + if (default_addr[0] == '\0') default_addr = desc->addr; + /* Only include the candidates matching the default destination for each component of the stream if the state is Completed as specified in RFC5245 section 9.1.2.2. */ + if ((cl->state == ICL_Completed) + && !((ice_candidate->taddr.port == default_port) && (strlen(ice_candidate->taddr.ip) == strlen(default_addr)) && (strcmp(ice_candidate->taddr.ip, default_addr) == 0))) + continue; + strncpy(sal_candidate->foundation, ice_candidate->foundation, sizeof(sal_candidate->foundation)); + sal_candidate->componentID = ice_candidate->componentID; + sal_candidate->priority = ice_candidate->priority; + strncpy(sal_candidate->type, ice_candidate_type(ice_candidate), sizeof(sal_candidate->type)); + strncpy(sal_candidate->addr, ice_candidate->taddr.ip, sizeof(sal_candidate->addr)); + sal_candidate->port = ice_candidate->taddr.port; + if ((ice_candidate->base != NULL) && (ice_candidate->base != ice_candidate)) { + strncpy(sal_candidate->raddr, ice_candidate->base->taddr.ip, sizeof(sal_candidate->raddr)); + sal_candidate->rport = ice_candidate->base->taddr.port; + } + } + } + if ((cl->state == ICL_Completed) && (ice_session_role(session) == IR_Controlling)) { + const char *rtp_addr, *rtcp_addr; + int rtp_port, rtcp_port; + memset(stream->ice_remote_candidates, 0, sizeof(stream->ice_remote_candidates)); + ice_check_list_nominated_valid_remote_candidate(cl, &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port); + strncpy(stream->ice_remote_candidates[0].addr, rtp_addr, sizeof(stream->ice_remote_candidates[0].addr)); + stream->ice_remote_candidates[0].port = rtp_port; + strncpy(stream->ice_remote_candidates[1].addr, rtcp_addr, sizeof(stream->ice_remote_candidates[1].addr)); + stream->ice_remote_candidates[1].port = rtcp_port; + } + } +} + +void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md) +{ + if ((md->ice_pwd[0] != '\0') && (md->ice_ufrag[0] != '\0')) { + int i, j; + ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd); + for (i = 0; i < md->nstreams; i++) { + const SalStreamDescription *stream = &md->streams[i]; + IceCheckList *cl = ice_session_check_list(call->ice_session, i); + if (cl == NULL) { + cl = ice_check_list_new(); + ice_session_add_check_list(call->ice_session, cl); + switch (stream->type) { + case SalAudio: + if (call->audiostream != NULL) call->audiostream->ice_check_list = cl; + break; + case SalVideo: + if (call->videostream != NULL) call->videostream->ice_check_list = cl; + break; + default: + break; + } + } + if (stream->ice_mismatch == TRUE) { + ice_check_list_set_state(cl, ICL_Failed); + } else { + if ((stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) + ice_check_list_set_remote_credentials(cl, stream->ice_ufrag, stream->ice_pwd); + for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES; j++) { + const SalIceCandidate *candidate = &stream->ice_candidates[j]; + bool_t default_candidate = FALSE; + const char *addr = NULL; + int port = 0; + if (candidate->addr[0] == '\0') break; + if (candidate->componentID == 1) { + addr = stream->rtp_addr; + port = stream->rtp_port; + } + else if (candidate->componentID == 2) { + addr = stream->rtcp_addr; + port = stream->rtcp_port; + } + if (addr && (candidate->port == port) && (strlen(candidate->addr) == strlen(addr)) && (strcmp(candidate->addr, addr) == 0)) + default_candidate = TRUE; + ice_add_remote_candidate(cl, candidate->type, candidate->addr, candidate->port, candidate->componentID, + candidate->priority, candidate->foundation, default_candidate); + } + } + } + for (i = ice_session_nb_check_lists(call->ice_session); i > md->nstreams; i--) { + ice_session_remove_check_list(call->ice_session, ice_session_check_list(call->ice_session, i - 1)); + } + } + if ((ice_session_state(call->ice_session) == IS_Failed) || (ice_session_nb_check_lists(call->ice_session) == 0)) { + linphone_call_delete_ice_session(call); + } +} + LinphoneCall * is_a_linphone_call(void *user_pointer){ LinphoneCall *call=(LinphoneCall*)user_pointer; if (call==NULL) return NULL; diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index 118f2420a..1d4ce1b9f 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -253,6 +253,11 @@ static void initiate_incoming(const SalStreamDescription *local_cap, result->rtp_port = 0; } + strcpy(result->ice_pwd, local_cap->ice_pwd); + strcpy(result->ice_ufrag, local_cap->ice_ufrag); + result->ice_mismatch = local_cap->ice_mismatch; + memcpy(result->ice_candidates, local_cap->ice_candidates, sizeof(result->ice_candidates)); + memcpy(result->ice_remote_candidates, local_cap->ice_remote_candidates, sizeof(result->ice_remote_candidates)); } /** @@ -321,5 +326,9 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities result->bandwidth=local_capabilities->bandwidth; result->session_ver=local_capabilities->session_ver; result->session_id=local_capabilities->session_id; + strcpy(result->ice_pwd, local_capabilities->ice_pwd); + strcpy(result->ice_ufrag, local_capabilities->ice_ufrag); + result->ice_lite = local_capabilities->ice_lite; + result->ice_completed = local_capabilities->ice_lite; return 0; } diff --git a/coreapi/private.h b/coreapi/private.h index bc65e946e..f68725473 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -221,6 +221,8 @@ 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); int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call); +void linphone_core_update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session); +void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md); void linphone_core_send_initial_subscribes(LinphoneCore *lc); void linphone_core_write_friends_config(LinphoneCore* lc); From 2a827ff58ab708adb76eb4df7e22a2d2ad2667a2 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 6 Aug 2012 17:08:06 +0200 Subject: [PATCH 56/74] Some fixes of bugs introduced with redesign of interaction between ICE and media descriptions. --- coreapi/linphonecore.c | 2 +- coreapi/misc.c | 27 +++++++++++++++++++++++---- coreapi/offeranswer.c | 2 +- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 1a0a85752..c69a42a06 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2553,8 +2553,8 @@ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const call->camera_active=call->params.has_video; update_local_media_description(lc,call); if (call->ice_session != NULL) { - linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session); linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(call->op)); + linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session); } sal_call_set_local_media_description(call->op,call->localdesc); sal_call_accept(call->op); diff --git a/coreapi/misc.c b/coreapi/misc.c index 81db63ad0..e97b1b06d 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -608,6 +608,7 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) void linphone_core_update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session) { IceSessionState session_state = ice_session_state(session); + int nb_candidates; int i, j; if (session_state == IS_Completed) desc->ice_completed = TRUE; @@ -617,6 +618,7 @@ void linphone_core_update_local_media_description_from_ice(SalMediaDescription * for (i = 0; i < desc->nstreams; i++) { SalStreamDescription *stream = &desc->streams[i]; IceCheckList *cl = ice_session_check_list(session, i); + nb_candidates = 0; if (cl == NULL) continue; if ((strlen(ice_check_list_local_pwd(cl)) != strlen(desc->ice_pwd)) || (strcmp(ice_check_list_local_pwd(cl), desc->ice_pwd))) strncpy(stream->ice_pwd, ice_check_list_local_pwd(cl), sizeof(stream->ice_pwd)); @@ -629,7 +631,7 @@ void linphone_core_update_local_media_description_from_ice(SalMediaDescription * if ((cl->state == ICL_Running) || (cl->state == ICL_Completed)) { memset(stream->ice_candidates, 0, sizeof(stream->ice_candidates)); for (j = 0; j < ms_list_size(cl->local_candidates); j++) { - SalIceCandidate *sal_candidate = &stream->ice_candidates[j]; + SalIceCandidate *sal_candidate = &stream->ice_candidates[nb_candidates]; IceCandidate *ice_candidate = ms_list_nth_data(cl->local_candidates, j); const char *default_addr = NULL; int default_port = 0; @@ -655,6 +657,7 @@ void linphone_core_update_local_media_description_from_ice(SalMediaDescription * strncpy(sal_candidate->raddr, ice_candidate->base->taddr.ip, sizeof(sal_candidate->raddr)); sal_candidate->rport = ice_candidate->base->taddr.port; } + nb_candidates++; } } if ((cl->state == ICL_Completed) && (ice_session_role(session) == IR_Controlling)) { @@ -706,16 +709,32 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, if (candidate->componentID == 1) { addr = stream->rtp_addr; port = stream->rtp_port; - } - else if (candidate->componentID == 2) { + } else if (candidate->componentID == 2) { addr = stream->rtcp_addr; port = stream->rtcp_port; - } + } else continue; if (addr && (candidate->port == port) && (strlen(candidate->addr) == strlen(addr)) && (strcmp(candidate->addr, addr) == 0)) default_candidate = TRUE; ice_add_remote_candidate(cl, candidate->type, candidate->addr, candidate->port, candidate->componentID, candidate->priority, candidate->foundation, default_candidate); } + for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES; j++) { + const SalIceRemoteCandidate *candidate = &stream->ice_remote_candidates[j]; + const char *addr = NULL; + int port = 0; + int componentID = j + 1; + if (candidate->addr[0] == '\0') break; + ms_error("handle remote-candidates attribute"); + if (componentID == 1) { + addr = stream->rtp_addr; + port = stream->rtp_port; + } else if (componentID == 2) { + addr = stream->rtcp_addr; + port = stream->rtcp_port; + } else continue; + if (addr[0] == '\0') addr = md->addr; + ice_add_losing_pair(ice_session_check_list(call->ice_session, i), j + 1, candidate->addr, candidate->port, addr, port); + } } } for (i = ice_session_nb_check_lists(call->ice_session); i > md->nstreams; i--) { diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index 1d4ce1b9f..51773d324 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -329,6 +329,6 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities strcpy(result->ice_pwd, local_capabilities->ice_pwd); strcpy(result->ice_ufrag, local_capabilities->ice_ufrag); result->ice_lite = local_capabilities->ice_lite; - result->ice_completed = local_capabilities->ice_lite; + result->ice_completed = local_capabilities->ice_completed; return 0; } From 7baeffbff4b0018dfa09b542f8ea60def20b4c9d Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 7 Aug 2012 10:53:07 +0200 Subject: [PATCH 57/74] Use correct contact address in RE-INVITE SIP messages. --- coreapi/sal_eXosip2.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index a9f3559b6..76d7973d9 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -2406,6 +2406,10 @@ int sal_call_update(SalOp *h, const char *subject){ eXosip_unlock(); osip_message_set_subject(reinvite,subject); osip_message_set_allow(reinvite, "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO"); + if (h->base.contact){ + _osip_list_set_empty(&reinvite->contacts,(void (*)(void*))osip_contact_free); + osip_message_set_contact(reinvite,h->base.contact); + } if (h->base.root->session_expires!=0){ osip_message_set_header(reinvite, "Session-expires", "200"); osip_message_set_supported(reinvite, "timer"); From aef56a9c3a82a0d9a26e64588c7641a51ffebd8b Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 7 Aug 2012 11:45:47 +0200 Subject: [PATCH 58/74] Correctly handle content of SDP when ICE has completed for a specific media stream. --- coreapi/misc.c | 20 +++++++++++++++++--- coreapi/offeranswer.c | 1 + coreapi/sal.h | 1 + coreapi/sal_eXosip2_sdp.c | 3 +++ 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/coreapi/misc.c b/coreapi/misc.c index e97b1b06d..a43451036 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -607,12 +607,19 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) void linphone_core_update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session) { + const char *rtp_addr, *rtcp_addr; IceSessionState session_state = ice_session_state(session); int nb_candidates; int i, j; - if (session_state == IS_Completed) desc->ice_completed = TRUE; - else desc->ice_completed = FALSE; + if (session_state == IS_Completed) { + desc->ice_completed = TRUE; + ice_check_list_nominated_valid_local_candidate(ice_session_check_list(session, 0), &rtp_addr, NULL, NULL, NULL); + strncpy(desc->addr, rtp_addr, sizeof(desc->addr)); + } + else { + desc->ice_completed = FALSE; + } strncpy(desc->ice_pwd, ice_session_local_pwd(session), sizeof(desc->ice_pwd)); strncpy(desc->ice_ufrag, ice_session_local_ufrag(session), sizeof(desc->ice_ufrag)); for (i = 0; i < desc->nstreams; i++) { @@ -620,6 +627,14 @@ void linphone_core_update_local_media_description_from_ice(SalMediaDescription * IceCheckList *cl = ice_session_check_list(session, i); nb_candidates = 0; if (cl == NULL) continue; + if (cl->state == ICL_Completed) { + stream->ice_completed = TRUE; + ice_check_list_nominated_valid_local_candidate(ice_session_check_list(session, i), &rtp_addr, &stream->rtp_port, &rtcp_addr, &stream->rtcp_port); + strncpy(stream->rtp_addr, rtp_addr, sizeof(stream->rtp_addr)); + strncpy(stream->rtcp_addr, rtcp_addr, sizeof(stream->rtcp_addr)); + } else { + stream->ice_completed = FALSE; + } if ((strlen(ice_check_list_local_pwd(cl)) != strlen(desc->ice_pwd)) || (strcmp(ice_check_list_local_pwd(cl), desc->ice_pwd))) strncpy(stream->ice_pwd, ice_check_list_local_pwd(cl), sizeof(stream->ice_pwd)); else @@ -661,7 +676,6 @@ void linphone_core_update_local_media_description_from_ice(SalMediaDescription * } } if ((cl->state == ICL_Completed) && (ice_session_role(session) == IR_Controlling)) { - const char *rtp_addr, *rtcp_addr; int rtp_port, rtcp_port; memset(stream->ice_remote_candidates, 0, sizeof(stream->ice_remote_candidates)); ice_check_list_nominated_valid_remote_candidate(cl, &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port); diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index 51773d324..c93569976 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -256,6 +256,7 @@ static void initiate_incoming(const SalStreamDescription *local_cap, strcpy(result->ice_pwd, local_cap->ice_pwd); strcpy(result->ice_ufrag, local_cap->ice_ufrag); result->ice_mismatch = local_cap->ice_mismatch; + result->ice_completed = local_cap->ice_completed; memcpy(result->ice_candidates, local_cap->ice_candidates, sizeof(result->ice_candidates)); memcpy(result->ice_remote_candidates, local_cap->ice_remote_candidates, sizeof(result->ice_remote_candidates)); } diff --git a/coreapi/sal.h b/coreapi/sal.h index dfb560472..0d2b631d8 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -169,6 +169,7 @@ typedef struct SalStreamDescription{ char ice_ufrag[SAL_MEDIA_DESCRIPTION_MAX_ICE_UFRAG_LEN]; char ice_pwd[SAL_MEDIA_DESCRIPTION_MAX_ICE_PWD_LEN]; bool_t ice_mismatch; + bool_t ice_completed; } SalStreamDescription; #define SAL_MEDIA_DESCRIPTION_MAX_STREAMS 4 diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index e03e65bae..8c917570f 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -377,6 +377,9 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription } } } + if (desc->ice_completed == TRUE) { + sdp_message_a_attribute_add(msg, lineno, osip_strdup("nortpproxy"), osip_strdup("yes")); + } if (desc->ice_mismatch == TRUE) { sdp_message_a_attribute_add(msg, lineno, osip_strdup("ice-mismatch"), NULL); } else { From 3bf2dea3008ad2b0fa29c4539e57380c6ffd8d53 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 7 Aug 2012 13:44:18 +0200 Subject: [PATCH 59/74] Change of mediastream2 API. --- coreapi/linphonecall.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 7a1781696..d9c2f991f 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -559,7 +559,7 @@ void linphone_call_enable_video(LinphoneCall *call, bool_t enabled) call->params = *params; update_local_media_description(lc, call); linphone_call_init_video_stream(call); - video_stream_start_ice_gathering(call->videostream); + video_stream_prepare_video(call->videostream); linphone_core_gather_ice_candidates(lc, call); } else { if (linphone_call_get_state(call) == LinphoneCallUpdatedByRemote) { @@ -1504,9 +1504,9 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut } void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call){ - audio_stream_start_ice_gathering(call->audiostream); + audio_stream_prepare_sound(call->audiostream, NULL, NULL); if (call->videostream) { - video_stream_start_ice_gathering(call->videostream); + video_stream_prepare_video(call->videostream); } } From dbb1253c6d71c74f76bccc146eaf20f476436c35 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 7 Aug 2012 16:35:43 +0200 Subject: [PATCH 60/74] If ICE processing fails, delete the ICE session. --- coreapi/linphonecall.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index d9c2f991f..f90f97036 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1736,8 +1736,17 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){ OrtpEventData *evd=ortp_event_get_data(ev); if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) { - if (ice_session_role(call->ice_session) == IR_Controlling) { - linphone_core_update_call(call->core, call, &call->current_params); + switch (ice_session_state(call->ice_session)) { + case IS_Completed: + if (ice_session_role(call->ice_session) == IR_Controlling) { + linphone_core_update_call(call->core, call, &call->current_params); + } + break; + case IS_Failed: + linphone_call_delete_ice_session(call); + break; + default: + break; } } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) { LinphoneCallParams *params; From 3611187779bcfa8d3f6cb159d400d80641623b6b Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 8 Aug 2012 11:43:51 +0200 Subject: [PATCH 61/74] Use ICE selected pairs instead of nominated valid pairs. --- coreapi/linphonecall.c | 1 + coreapi/misc.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index f90f97036..62f296745 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1739,6 +1739,7 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){ switch (ice_session_state(call->ice_session)) { case IS_Completed: if (ice_session_role(call->ice_session) == IR_Controlling) { + ice_session_select_candidates(call->ice_session); linphone_core_update_call(call->core, call, &call->current_params); } break; diff --git a/coreapi/misc.c b/coreapi/misc.c index a43451036..90380beab 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -614,7 +614,7 @@ void linphone_core_update_local_media_description_from_ice(SalMediaDescription * if (session_state == IS_Completed) { desc->ice_completed = TRUE; - ice_check_list_nominated_valid_local_candidate(ice_session_check_list(session, 0), &rtp_addr, NULL, NULL, NULL); + ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, 0), &rtp_addr, NULL, NULL, NULL); strncpy(desc->addr, rtp_addr, sizeof(desc->addr)); } else { @@ -629,7 +629,7 @@ void linphone_core_update_local_media_description_from_ice(SalMediaDescription * if (cl == NULL) continue; if (cl->state == ICL_Completed) { stream->ice_completed = TRUE; - ice_check_list_nominated_valid_local_candidate(ice_session_check_list(session, i), &rtp_addr, &stream->rtp_port, &rtcp_addr, &stream->rtcp_port); + ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, i), &rtp_addr, &stream->rtp_port, &rtcp_addr, &stream->rtcp_port); strncpy(stream->rtp_addr, rtp_addr, sizeof(stream->rtp_addr)); strncpy(stream->rtcp_addr, rtcp_addr, sizeof(stream->rtcp_addr)); } else { @@ -678,7 +678,7 @@ void linphone_core_update_local_media_description_from_ice(SalMediaDescription * if ((cl->state == ICL_Completed) && (ice_session_role(session) == IR_Controlling)) { int rtp_port, rtcp_port; memset(stream->ice_remote_candidates, 0, sizeof(stream->ice_remote_candidates)); - ice_check_list_nominated_valid_remote_candidate(cl, &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port); + ice_check_list_selected_valid_remote_candidate(cl, &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port); strncpy(stream->ice_remote_candidates[0].addr, rtp_addr, sizeof(stream->ice_remote_candidates[0].addr)); stream->ice_remote_candidates[0].port = rtp_port; strncpy(stream->ice_remote_candidates[1].addr, rtcp_addr, sizeof(stream->ice_remote_candidates[1].addr)); From d3851711b1dac71f15864b2473f944fd582908f8 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 8 Aug 2012 13:14:06 +0200 Subject: [PATCH 62/74] Defer sending of answer of re-invite when there are some ICE losing candidate pairs. --- coreapi/linphonecall.c | 13 +++++++++++-- coreapi/linphonecore.c | 4 ++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 62f296745..1b926071b 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1785,6 +1785,15 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){ } break; } + } else if (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) { + SalMediaDescription *md; + linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session); + sal_call_set_local_media_description(call->op,call->localdesc); + sal_call_accept(call->op); + md=sal_call_get_final_media_description(call->op); + if (md && !sal_media_description_empty(md)) + linphone_core_update_streams (call->core,call,md); + linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)"); } } @@ -1841,7 +1850,7 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse evd->packet = NULL; if (lc->vtable.call_stats_updated) lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]); - } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)) { + } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED)) { handle_ice_events(call, ev); } ortp_event_destroy(ev); @@ -1881,7 +1890,7 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse evd->packet = NULL; if (lc->vtable.call_stats_updated) lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]); - } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)) { + } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED)) { handle_ice_events(call, ev); } ortp_event_destroy(ev); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index c69a42a06..00870f9b2 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2554,6 +2554,10 @@ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const update_local_media_description(lc,call); if (call->ice_session != NULL) { linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(call->op)); + if (ice_session_nb_losing_pairs(call->ice_session) > 0) { + /* Defer the sending of the answer until there are no losing pairs left. */ + return 0; + } linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session); } sal_call_set_local_media_description(call->op,call->localdesc); From c6dfd648a9f16f47c1e82c4fcc9efa336227c08d Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 8 Aug 2012 14:53:27 +0200 Subject: [PATCH 63/74] Restart ICE if requested by ICE itself. --- coreapi/linphonecall.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 1b926071b..ccc5ad1e3 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1794,6 +1794,10 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){ if (md && !sal_media_description_empty(md)) linphone_core_update_streams (call->core,call,md); linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)"); + } else if (evt == ORTP_EVENT_ICE_RESTART_NEEDED) { + ice_session_restart(call->ice_session); + ice_session_set_role(call->ice_session, IR_Controlling); + linphone_core_update_call(call->core, call, &call->current_params); } } @@ -1850,7 +1854,8 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse evd->packet = NULL; if (lc->vtable.call_stats_updated) lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]); - } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED)) { + } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) + || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) { handle_ice_events(call, ev); } ortp_event_destroy(ev); @@ -1890,7 +1895,8 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse evd->packet = NULL; if (lc->vtable.call_stats_updated) lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]); - } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED)) { + } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) + || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) { handle_ice_events(call, ev); } ortp_event_destroy(ev); From 6eb710525846abca757126b515dbe97ae7bb2036 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 8 Aug 2012 15:18:04 +0200 Subject: [PATCH 64/74] Restart ICE if remote credentials have changed. --- coreapi/misc.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/coreapi/misc.c b/coreapi/misc.c index 90380beab..522786866 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -691,7 +691,27 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, { if ((md->ice_pwd[0] != '\0') && (md->ice_ufrag[0] != '\0')) { int i, j; - ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd); + + /* Check for ICE restart and set remote credentials. */ + if ((ice_session_remote_ufrag(call->ice_session) == NULL) && (ice_session_remote_pwd(call->ice_session) == NULL)) { + ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd); + } else if (ice_session_remote_credentials_changed(call->ice_session, md->ice_ufrag, md->ice_pwd)) { + ice_session_restart(call->ice_session); + ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd); + } + for (i = 0; i < md->nstreams; i++) { + const SalStreamDescription *stream = &md->streams[i]; + IceCheckList *cl = ice_session_check_list(call->ice_session, i); + if (cl && (stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) { + if (ice_check_list_remote_credentials_changed(cl, stream->ice_ufrag, stream->ice_pwd)) { + ice_session_restart(call->ice_session); + ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd); + break; + } + } + } + + /* Create ICE check lists if needed and parse ICE attributes. */ for (i = 0; i < md->nstreams; i++) { const SalStreamDescription *stream = &md->streams[i]; IceCheckList *cl = ice_session_check_list(call->ice_session, i); From bad089b4a75d1dfbf27c3d7362b4606051451ad8 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 9 Aug 2012 09:32:23 +0200 Subject: [PATCH 65/74] Restore ice-mismatch that was broken during redesign of the interface between media descriptions and ICE. --- coreapi/misc.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/coreapi/misc.c b/coreapi/misc.c index 522786866..34c58f57f 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -643,6 +643,7 @@ void linphone_core_update_local_media_description_from_ice(SalMediaDescription * strncpy(stream->ice_ufrag, ice_check_list_local_ufrag(cl), sizeof(stream->ice_ufrag)); else memset(stream->ice_pwd, 0, sizeof(stream->ice_pwd)); + stream->ice_mismatch = ice_check_list_is_mismatch(cl); if ((cl->state == ICL_Running) || (cl->state == ICL_Completed)) { memset(stream->ice_candidates, 0, sizeof(stream->ice_candidates)); for (j = 0; j < ms_list_size(cl->local_candidates); j++) { @@ -687,6 +688,18 @@ void linphone_core_update_local_media_description_from_ice(SalMediaDescription * } } +static void get_default_addr_and_port(uint16_t componentID, const SalMediaDescription *md, const SalStreamDescription *stream, const char **addr, int *port) +{ + if (componentID == 1) { + *addr = stream->rtp_addr; + *port = stream->rtp_port; + } else if (componentID == 2) { + *addr = stream->rtcp_addr; + *port = stream->rtcp_port; + } else return; + if ((*addr)[0] == '\0') *addr = md->addr; +} + void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md) { if ((md->ice_pwd[0] != '\0') && (md->ice_ufrag[0] != '\0')) { @@ -740,13 +753,8 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, const char *addr = NULL; int port = 0; if (candidate->addr[0] == '\0') break; - if (candidate->componentID == 1) { - addr = stream->rtp_addr; - port = stream->rtp_port; - } else if (candidate->componentID == 2) { - addr = stream->rtcp_addr; - port = stream->rtcp_port; - } else continue; + if ((candidate->componentID == 0) || (candidate->componentID > 2)) continue; + get_default_addr_and_port(candidate->componentID, md, stream, &addr, &port); if (addr && (candidate->port == port) && (strlen(candidate->addr) == strlen(addr)) && (strcmp(candidate->addr, addr) == 0)) default_candidate = TRUE; ice_add_remote_candidate(cl, candidate->type, candidate->addr, candidate->port, candidate->componentID, @@ -758,15 +766,7 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, int port = 0; int componentID = j + 1; if (candidate->addr[0] == '\0') break; - ms_error("handle remote-candidates attribute"); - if (componentID == 1) { - addr = stream->rtp_addr; - port = stream->rtp_port; - } else if (componentID == 2) { - addr = stream->rtcp_addr; - port = stream->rtcp_port; - } else continue; - if (addr[0] == '\0') addr = md->addr; + get_default_addr_and_port(componentID, md, stream, &addr, &port); ice_add_losing_pair(ice_session_check_list(call->ice_session, i), j + 1, candidate->addr, candidate->port, addr, port); } } @@ -774,6 +774,7 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, for (i = ice_session_nb_check_lists(call->ice_session); i > md->nstreams; i--) { ice_session_remove_check_list(call->ice_session, ice_session_check_list(call->ice_session, i - 1)); } + ice_session_check_mismatch(call->ice_session); } if ((ice_session_state(call->ice_session) == IS_Failed) || (ice_session_nb_check_lists(call->ice_session) == 0)) { linphone_call_delete_ice_session(call); From d0e7a66501d8476a483783dd35b61d8416e3a29a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 9 Aug 2012 12:00:39 +0200 Subject: [PATCH 66/74] Refactor code to prevent changing linphone_core API. --- console/commands.c | 5 ++- coreapi/linphonecall.c | 85 +++++++-------------------------------- coreapi/linphonecore.c | 91 ++++++++++++++++++++++++++++++------------ coreapi/linphonecore.h | 11 ----- coreapi/private.h | 3 ++ gtk/incall_view.c | 6 ++- gtk/main.c | 6 ++- 7 files changed, 97 insertions(+), 110 deletions(-) diff --git a/console/commands.c b/console/commands.c index 7bebdd82b..472531795 100644 --- a/console/commands.c +++ b/console/commands.c @@ -2503,7 +2503,10 @@ static int lpc_cmd_camera(LinphoneCore *lc, char *args){ linphone_call_enable_camera(call,activated); if ((activated && !linphone_call_params_video_enabled (cp))){ /*update the call to add the video stream*/ - linphone_call_enable_video(call,TRUE); + LinphoneCallParams *ncp=linphone_call_params_copy(cp); + linphone_call_params_enable_video(ncp,TRUE); + linphone_core_update_call(lc,call,ncp); + linphone_call_params_destroy (ncp); linphonec_out("Trying to bring up video stream...\n"); } } diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index ccc5ad1e3..4cd4a0734 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -546,42 +546,6 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const } } -void linphone_call_enable_video(LinphoneCall *call, bool_t enabled) -{ - LinphoneCore *lc=linphone_call_get_core(call); - LinphoneCallParams *params=linphone_call_params_copy(linphone_call_get_current_params(call)); - - linphone_call_params_enable_video(params, enabled); - if (enabled == TRUE) { - 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"); - call->params = *params; - update_local_media_description(lc, call); - linphone_call_init_video_stream(call); - video_stream_prepare_video(call->videostream); - linphone_core_gather_ice_candidates(lc, call); - } else { - if (linphone_call_get_state(call) == LinphoneCallUpdatedByRemote) { - linphone_core_accept_call_update(lc, call, params); - } else { - linphone_core_update_call(lc, call, params); - } - } - } else { - if ((call->ice_session != NULL) && (call->videostream != NULL)) { - ice_session_remove_check_list(call->ice_session, call->videostream->ice_check_list); - call->videostream->ice_check_list = NULL; - } - if (linphone_call_get_state(call) == LinphoneCallUpdatedByRemote) { - linphone_core_accept_call_update(lc, call, params); - } else { - linphone_core_update_call(lc, call, params); - } - } - linphone_call_params_destroy(params); -} - static void linphone_call_destroy(LinphoneCall *obj) { if (obj->op!=NULL) { @@ -1750,50 +1714,31 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){ break; } } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) { - LinphoneCallParams *params; + if (evd->info.ice_processing_successful==TRUE) { + ice_session_compute_candidates_foundations(call->ice_session); + ice_session_eliminate_redundant_candidates(call->ice_session); + ice_session_choose_default_candidates(call->ice_session); + } else { + linphone_call_delete_ice_session(call); + } switch (call->state) { case LinphoneCallStreamsRunning: + linphone_core_start_update_call(call->core, call); + break; case LinphoneCallUpdatedByRemote: - if (evd->info.ice_processing_successful==TRUE) { - ice_session_compute_candidates_foundations(call->ice_session); - ice_session_eliminate_redundant_candidates(call->ice_session); - ice_session_choose_default_candidates(call->ice_session); - } - params = linphone_call_params_copy(linphone_call_get_current_params(call)); - linphone_call_params_enable_video(params, TRUE); - if (call->state == LinphoneCallStreamsRunning) { - linphone_core_update_call(call->core, call, params); - } else { /* LinphoneCallUpdatedByRemote */ - linphone_core_accept_call_update(call->core, call, params); - } - linphone_call_params_destroy(params); + linphone_core_start_accept_call_update(call->core, call); break; case LinphoneCallOutgoingInit: + linphone_call_stop_media_streams(call); + linphone_core_start_invite(call->core, call, NULL); + break; default: linphone_call_stop_media_streams(call); - if (evd->info.ice_processing_successful==TRUE) { - ice_session_compute_candidates_foundations(call->ice_session); - ice_session_eliminate_redundant_candidates(call->ice_session); - ice_session_choose_default_candidates(call->ice_session); - } else { - linphone_call_delete_ice_session(call); - } - if (call->state==LinphoneCallOutgoingInit) { - linphone_core_start_invite(call->core,call,NULL); - } else { - linphone_core_notify_incoming_call(call->core,call); - } + linphone_core_notify_incoming_call(call->core, call); break; } } else if (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) { - SalMediaDescription *md; - linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session); - sal_call_set_local_media_description(call->op,call->localdesc); - sal_call_accept(call->op); - md=sal_call_get_final_media_description(call->op); - if (md && !sal_media_description_empty(md)) - linphone_core_update_streams (call->core,call,md); - linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)"); + linphone_core_start_accept_call_update(call->core, call); } else if (evt == ORTP_EVENT_ICE_RESTART_NEEDED) { ice_session_restart(call->ice_session); ice_session_set_role(call->ice_session, IR_Controlling); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 00870f9b2..b8911702b 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2445,6 +2445,24 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ ms_free(tmp); } +int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call){ + const char *subject; + call->camera_active=call->params.has_video; + update_local_media_description(lc,call); + if (call->ice_session != NULL) + linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session); + + if (call->params.in_conference){ + subject="Conference"; + }else{ + subject="Media change"; + } + if (lc->vtable.display_status) + lc->vtable.display_status(lc,_("Modifying call parameters...")); + sal_call_set_local_media_description (call->op,call->localdesc); + return sal_call_update(call->op,subject); +} + /** * @ingroup call_control * Updates a running call according to supplied call parameters or parameters changed in the LinphoneCore. @@ -2462,22 +2480,25 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){ int err=0; if (params!=NULL){ - const char *subject; - call->params=*params; - call->camera_active=call->params.has_video; - update_local_media_description(lc,call); - if (call->ice_session != NULL) - linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session); - - if (params->in_conference){ - subject="Conference"; - }else{ - subject="Media change"; + 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 (lc->vtable.display_status) - lc->vtable.display_status(lc,_("Modifying call parameters...")); - sal_call_set_local_media_description (call->op,call->localdesc); - err=sal_call_update(call->op,subject); + if ((call->ice_session != NULL) && ((ice_session_state(call->ice_session) != IS_Completed) || (call->params.has_video != params->has_video))) { + /* Defer call update until the ICE candidates gathering process has finished. */ + ms_message("Defer call update to gather ICE candidates"); + call->params = *params; + update_local_media_description(lc, call); + if (call->params.has_video) { + 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; + } + } + err = linphone_core_start_update_call(lc, call); }else{ #ifdef VIDEO_ENABLED if (call->videostream!=NULL){ @@ -2515,6 +2536,24 @@ int linphone_core_defer_call_update(LinphoneCore *lc, LinphoneCall *call){ return -1; } +int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call){ + SalMediaDescription *md; + if (call->ice_session != NULL) { + if (ice_session_nb_losing_pairs(call->ice_session) > 0) { + /* Defer the sending of the answer until there are no losing pairs left. */ + return 0; + } + linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session); + } + sal_call_set_local_media_description(call->op,call->localdesc); + sal_call_accept(call->op); + md=sal_call_get_final_media_description(call->op); + if (md && !sal_media_description_empty(md)) + linphone_core_update_streams (lc,call,md); + linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)"); + return 0; +} + /** * @ingroup call_control * Accept call modifications initiated by other end. @@ -2535,7 +2574,7 @@ int linphone_core_defer_call_update(LinphoneCore *lc, LinphoneCall *call){ * @return 0 if sucessful, -1 otherwise (actually when this function call is performed outside ot #LinphoneCallUpdatedByRemote state). **/ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){ - SalMediaDescription *md; + bool_t old_has_video = call->params.has_video; if (call->state!=LinphoneCallUpdatedByRemote){ ms_error("linphone_core_accept_update(): invalid state %s to call this function.", linphone_call_state_to_string(call->state)); @@ -2554,18 +2593,18 @@ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const update_local_media_description(lc,call); if (call->ice_session != NULL) { linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(call->op)); - if (ice_session_nb_losing_pairs(call->ice_session) > 0) { - /* Defer the sending of the answer until there are no losing pairs left. */ - return 0; + if (!ice_session_candidates_gathered(call->ice_session)) { + 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_gather_ice_candidates(lc,call)<0) { + /* Ice candidates gathering failed, proceed with the call anyway. */ + linphone_call_delete_ice_session(call); + } else return 0; + } } - linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session); } - sal_call_set_local_media_description(call->op,call->localdesc); - sal_call_accept(call->op); - md=sal_call_get_final_media_description(call->op); - if (md && !sal_media_description_empty(md)) - linphone_core_update_streams (lc,call,md); - linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)"); + linphone_core_start_accept_call_update(lc, call); return 0; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 6b00cbc09..10f6108c9 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -390,15 +390,6 @@ void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_t val); **/ bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call); -/** - * Enable or disable video for this call. - * @param call - * @param enabled - * - * @ingroup media_parameters - */ -void linphone_call_enable_video(LinphoneCall *call, bool_t enabled); - /*keep this in sync with mediastreamer2/msvolume.h*/ /** @@ -792,8 +783,6 @@ int linphone_core_transfer_call_to_another(LinphoneCore *lc, LinphoneCall *call, bool_t linphone_core_inc_invite_pending(LinphoneCore*lc); -void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call); - bool_t linphone_core_in_call(const LinphoneCore *lc); LinphoneCall *linphone_core_get_current_call(const LinphoneCore *lc); diff --git a/coreapi/private.h b/coreapi/private.h index f68725473..05d5c3f13 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -261,7 +261,10 @@ void linphone_core_update_progress(LinphoneCore *lc, const char *purpose, float void linphone_core_stop_waiting(LinphoneCore *lc); int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy); +int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call); +int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call); void linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *call); +void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call); extern SalCallbacks linphone_sal_callbacks; void linphone_proxy_config_set_error(LinphoneProxyConfig *cfg, LinphoneReason error); bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc); diff --git a/gtk/incall_view.c b/gtk/incall_view.c index 45e98609b..7e8eb683f 100644 --- a/gtk/incall_view.c +++ b/gtk/incall_view.c @@ -221,8 +221,12 @@ void linphone_gtk_create_in_call_view(LinphoneCall *call){ static void video_button_clicked(GtkWidget *button, LinphoneCall *call){ gboolean adding=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button),"adding_video")); + LinphoneCore *lc=linphone_call_get_core(call); + LinphoneCallParams *params=linphone_call_params_copy(linphone_call_get_current_params(call)); gtk_widget_set_sensitive(button,FALSE); - linphone_call_enable_video(call,adding); + linphone_call_params_enable_video(params,adding); + linphone_core_update_call(lc,call,params); + linphone_call_params_destroy(params); } void linphone_gtk_update_video_button(LinphoneCall *call){ diff --git a/gtk/main.c b/gtk/main.c index 054677654..2955b3ecc 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -1080,7 +1080,11 @@ static void linphone_gtk_notify(LinphoneCall *call, const char *msg){ static void on_call_updated_response(GtkWidget *dialog, gint responseid, LinphoneCall *call){ if (linphone_call_get_state(call)==LinphoneCallUpdatedByRemote){ - linphone_call_enable_video(call, responseid==GTK_RESPONSE_YES); + LinphoneCore *lc=linphone_call_get_core(call); + LinphoneCallParams *params=linphone_call_params_copy(linphone_call_get_current_params(call)); + linphone_call_params_enable_video(params,responseid==GTK_RESPONSE_YES); + linphone_core_accept_call_update(lc,call,params); + linphone_call_params_destroy(params); } linphone_call_unref(call); g_source_remove_by_user_data(dialog); From ccfd3c7b2d94ef90b88b69a7867f92f33b01e14e Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 9 Aug 2012 14:47:20 +0200 Subject: [PATCH 67/74] Update of ICE from remote media description may delete the ICE session, so check that the session exists after the update to prevent crashes. --- coreapi/linphonecall.c | 14 ++++++++------ coreapi/linphonecore.c | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 4cd4a0734..36ffc4f81 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -392,12 +392,14 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro call->ice_session = ice_session_new(); ice_session_set_role(call->ice_session, IR_Controlled); linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op)); - linphone_call_init_media_streams(call); - linphone_call_start_media_streams_for_ice_gathering(call); - if (linphone_core_gather_ice_candidates(call->core,call)<0) { - /* Ice candidates gathering failed, proceed with the call anyway. */ - linphone_call_delete_ice_session(call); - linphone_call_stop_media_streams(call); + if (call->ice_session != NULL) { + linphone_call_init_media_streams(call); + linphone_call_start_media_streams_for_ice_gathering(call); + if (linphone_core_gather_ice_candidates(call->core,call)<0) { + /* Ice candidates gathering failed, proceed with the call anyway. */ + linphone_call_delete_ice_session(call); + linphone_call_stop_media_streams(call); + } } break; case LinphonePolicyUseStun: diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index b8911702b..3b8a274b7 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2593,7 +2593,7 @@ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const update_local_media_description(lc,call); if (call->ice_session != NULL) { linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(call->op)); - if (!ice_session_candidates_gathered(call->ice_session)) { + if ((call->ice_session != NULL) &&!ice_session_candidates_gathered(call->ice_session)) { if ((call->params.has_video) && (call->params.has_video != old_has_video)) { linphone_call_init_video_stream(call); video_stream_prepare_video(call->videostream); From 4b8a215735463944ab8d32fcc264c583f505f830 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 9 Aug 2012 15:45:22 +0200 Subject: [PATCH 68/74] Can now use ICE and ping OPTIONS in parallel. --- coreapi/callbacks.c | 3 ++- coreapi/linphonecall.c | 2 +- coreapi/linphonecore.c | 33 ++++++++++++++++++++++++++++----- coreapi/private.h | 2 ++ 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index ba2789235..ab8f10f10 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -755,7 +755,8 @@ static void ping_reply(SalOp *op){ ms_message("ping reply !"); if (call){ if (call->state==LinphoneCallOutgoingInit){ - linphone_core_start_invite(call->core,call,NULL); + call->ping_replied=TRUE; + linphone_core_proceed_with_invite_if_ready(call->core,call,NULL); } } else diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 36ffc4f81..c5300bf99 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1732,7 +1732,7 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){ break; case LinphoneCallOutgoingInit: linphone_call_stop_media_streams(call); - linphone_core_start_invite(call->core, call, NULL); + linphone_core_proceed_with_invite_if_ready(call->core, call, NULL); break; default: linphone_call_stop_media_streams(call); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 3b8a274b7..9ba19020b 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2105,6 +2105,27 @@ static char *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphonePr return NULL; } +int linphone_core_proceed_with_invite_if_ready(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy){ + bool_t ice_ready = FALSE; + bool_t ping_ready = FALSE; + + if (call->ice_session != NULL) { + if (ice_session_candidates_gathered(call->ice_session)) ice_ready = TRUE; + } else { + ice_ready = TRUE; + } + if (call->ping_op != NULL) { + if (call->ping_replied == TRUE) ping_ready = TRUE; + } else { + ping_ready = TRUE; + } + + if ((ice_ready == TRUE) && (ping_ready == TRUE)) { + return linphone_core_start_invite(lc, call, dest_proxy); + } + return 0; +} + int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy){ int err; char *contact; @@ -2247,6 +2268,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const char *real_url=NULL; LinphoneProxyConfig *dest_proxy=NULL; LinphoneCall *call; + bool_t use_ice = FALSE; linphone_core_preempt_sound_resources(lc); @@ -2298,18 +2320,19 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const linphone_call_delete_ice_session(call); linphone_call_stop_media_streams(call); } else { - if (real_url!=NULL) ms_free(real_url); - return call; + use_ice = TRUE; } } - if (dest_proxy!=NULL || lc->sip_conf.ping_with_options==FALSE){ - linphone_core_start_invite(lc,call,dest_proxy); - }else{ + + if (dest_proxy==NULL && lc->sip_conf.ping_with_options==TRUE){ /*defer the start of the call after the OPTIONS ping*/ + call->ping_replied=FALSE; call->ping_op=sal_op_new(lc->sal); sal_ping(call->ping_op,from,real_url); 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,dest_proxy); } if (real_url!=NULL) ms_free(real_url); diff --git a/coreapi/private.h b/coreapi/private.h index 05d5c3f13..5c253b765 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -134,6 +134,7 @@ struct _LinphoneCall bool_t auth_token_verified; bool_t defer_update; bool_t was_automatically_paused; + bool_t ping_replied; CallCallbackObj nextVideoFrameDecoded; LinphoneCallStats stats[2]; IceSession *ice_session; @@ -260,6 +261,7 @@ void linphone_core_start_waiting(LinphoneCore *lc, const char *purpose); void linphone_core_update_progress(LinphoneCore *lc, const char *purpose, float progresses); void linphone_core_stop_waiting(LinphoneCore *lc); +int linphone_core_proceed_with_invite_if_ready(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy); int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy); int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call); int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call); From 66f80b83ffbb230c6f579daad0e06c9d328dd701 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 10 Aug 2012 12:49:04 +0200 Subject: [PATCH 69/74] Fix compilation when video is not enabled. --- coreapi/linphonecall.c | 2 ++ coreapi/linphonecore.c | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index c5300bf99..74ef5487f 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1471,9 +1471,11 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call){ audio_stream_prepare_sound(call->audiostream, NULL, NULL); +#ifdef VIDEO_ENABLED if (call->videostream) { video_stream_prepare_video(call->videostream); } +#endif } void linphone_call_delete_ice_session(LinphoneCall *call){ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 9ba19020b..4e9198dc2 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2503,6 +2503,7 @@ int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call){ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){ int err=0; if (params!=NULL){ +#ifdef VIDEO_ENABLED 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; @@ -2521,6 +2522,7 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho } else return err; } } +#endif err = linphone_core_start_update_call(lc, call); }else{ #ifdef VIDEO_ENABLED @@ -2616,6 +2618,7 @@ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const update_local_media_description(lc,call); if (call->ice_session != NULL) { linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(call->op)); +#ifdef VIDEO_ENABLED if ((call->ice_session != NULL) &&!ice_session_candidates_gathered(call->ice_session)) { if ((call->params.has_video) && (call->params.has_video != old_has_video)) { linphone_call_init_video_stream(call); @@ -2626,6 +2629,7 @@ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const } else return 0; } } +#endif } linphone_core_start_accept_call_update(lc, call); return 0; From 32ef8c9994e18853ac25489a860a0906b54aba2a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 10 Aug 2012 17:23:54 +0200 Subject: [PATCH 70/74] Define ICE firewall policy for java. --- java/common/org/linphone/core/LinphoneCore.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index e06342178..6266f6646 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -140,6 +140,10 @@ public interface LinphoneCore { * Use stun server to discover RTP addresses and ports. */ static public FirewallPolicy UseStun = new FirewallPolicy(2,"UseStun"); + /** + * Use ICE. + */ + static public FirewallPolicy UseIce = new FirewallPolicy(3,"UseIce"); private final int mValue; private final String mStringValue; From bccc94646ad9162c16346cf72238d3d2f53ea485 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 13 Aug 2012 14:28:31 +0200 Subject: [PATCH 71/74] Restart ICE if the c= line is set to 0.0.0.0. --- coreapi/callbacks.c | 5 +++++ coreapi/linphonecore.c | 4 ++++ coreapi/misc.c | 44 ++++++++++++++++++++++++++++++++---------- 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index ab8f10f10..584191cc4 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -359,6 +359,11 @@ static void call_ack(SalOp *op){ static void call_accept_update(LinphoneCore *lc, LinphoneCall *call){ SalMediaDescription *md; + SalMediaDescription *rmd=sal_call_get_remote_media_description(call->op); + if ((rmd!=NULL) && (call->ice_session!=NULL)) { + linphone_core_update_ice_from_remote_media_description(call,rmd); + linphone_core_update_local_media_description_from_ice(call->localdesc,call->ice_session); + } sal_call_accept(call->op); md=sal_call_get_final_media_description(call->op); if (md && !sal_media_description_empty(md)) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 35e158f74..4b6c02c93 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2897,6 +2897,8 @@ int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call) return -1; } update_local_media_description(lc,call); + if (call->ice_session != NULL) + linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session); if (sal_media_description_has_dir(call->resultdesc,SalStreamSendRecv)){ sal_media_description_set_dir(call->localdesc,SalStreamSendOnly); subject="Call on hold"; @@ -2974,6 +2976,8 @@ int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *the_call) if (call->audiostream) audio_stream_play(call->audiostream, NULL); update_local_media_description(lc,the_call); + if (call->ice_session != NULL) + linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session); sal_call_set_local_media_description(call->op,call->localdesc); sal_media_description_set_dir(call->localdesc,SalStreamSendRecv); if (call->params.in_conference && !call->current_params.in_conference) subject="Conference"; diff --git a/coreapi/misc.c b/coreapi/misc.c index 5d56c9b51..3d3cb4477 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -703,14 +703,33 @@ static void get_default_addr_and_port(uint16_t componentID, const SalMediaDescri void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md) { + bool_t ice_restarted = FALSE; + if ((md->ice_pwd[0] != '\0') && (md->ice_ufrag[0] != '\0')) { int i, j; /* Check for ICE restart and set remote credentials. */ + if ((strcmp(md->addr, "0.0.0.0") == 0) || (strcmp(md->addr, "::0") == 0)) { + ice_session_restart(call->ice_session); + ice_restarted = TRUE; + } else { + for (i = 0; i < md->nstreams; i++) { + const SalStreamDescription *stream = &md->streams[i]; + IceCheckList *cl = ice_session_check_list(call->ice_session, i); + if (cl && (strcmp(stream->rtp_addr, "0.0.0.0") == 0)) { + ice_session_restart(call->ice_session); + ice_restarted = TRUE; + break; + } + } + } if ((ice_session_remote_ufrag(call->ice_session) == NULL) && (ice_session_remote_pwd(call->ice_session) == NULL)) { ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd); } else if (ice_session_remote_credentials_changed(call->ice_session, md->ice_ufrag, md->ice_pwd)) { - ice_session_restart(call->ice_session); + if (ice_restarted == FALSE) { + ice_session_restart(call->ice_session); + ice_restarted = TRUE; + } ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd); } for (i = 0; i < md->nstreams; i++) { @@ -718,7 +737,10 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, IceCheckList *cl = ice_session_check_list(call->ice_session, i); if (cl && (stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) { if (ice_check_list_remote_credentials_changed(cl, stream->ice_ufrag, stream->ice_pwd)) { - ice_session_restart(call->ice_session); + if (ice_restarted == FALSE) { + ice_session_restart(call->ice_session); + ice_restarted = TRUE; + } ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd); break; } @@ -761,14 +783,16 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, ice_add_remote_candidate(cl, candidate->type, candidate->addr, candidate->port, candidate->componentID, candidate->priority, candidate->foundation, default_candidate); } - for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES; j++) { - const SalIceRemoteCandidate *candidate = &stream->ice_remote_candidates[j]; - const char *addr = NULL; - int port = 0; - int componentID = j + 1; - if (candidate->addr[0] == '\0') break; - get_default_addr_and_port(componentID, md, stream, &addr, &port); - ice_add_losing_pair(ice_session_check_list(call->ice_session, i), j + 1, candidate->addr, candidate->port, addr, port); + if (ice_restarted == FALSE) { + for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES; j++) { + const SalIceRemoteCandidate *candidate = &stream->ice_remote_candidates[j]; + const char *addr = NULL; + int port = 0; + int componentID = j + 1; + if (candidate->addr[0] == '\0') break; + get_default_addr_and_port(componentID, md, stream, &addr, &port); + ice_add_losing_pair(ice_session_check_list(call->ice_session, i), j + 1, candidate->addr, candidate->port, addr, port); + } } } } From 6f392caf464943b7cdefaa33f11bebbabe2f6eeb Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 13 Aug 2012 15:03:17 +0200 Subject: [PATCH 72/74] Do not set the c= line to 0.0.0.0 to pause a call when ICE is used. --- coreapi/sal_eXosip2_sdp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 8c917570f..9ca194199 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -144,7 +144,8 @@ static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc) osip_strdup ("IN"), inet6 ? osip_strdup("IP6") : osip_strdup ("IP4"), osip_strdup (desc->addr)); sdp_message_s_name_set (local, osip_strdup ("Talk")); - if(!sal_media_description_has_dir (desc,SalStreamSendOnly)) + /* Do not set the c= line to 0.0.0.0 if there is an ICE session. */ + if((desc->ice_ufrag[0] != '\0') || !sal_media_description_has_dir (desc,SalStreamSendOnly)) { sdp_message_c_connection_add (local, -1, osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"), From 7b5bddf359a8d9d3b20ad02efbb9355d2caaf052 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 14 Aug 2012 12:37:21 +0200 Subject: [PATCH 73/74] Deactivate symmetric RTP when ICE is in use. --- coreapi/linphonecall.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 5029e34f8..9e9ecee42 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -974,6 +974,7 @@ void linphone_call_init_audio_stream(LinphoneCall *call){ } if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){ rtp_session_set_pktinfo(audiostream->session, TRUE); + rtp_session_set_symmetric_rtp(audiostream->session, FALSE); audiostream->ice_check_list = ice_session_check_list(call->ice_session, 0); ice_check_list_set_rtp_session(audiostream->ice_check_list, audiostream->session); } @@ -1003,6 +1004,7 @@ void linphone_call_init_video_stream(LinphoneCall *call){ } if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL) && (ice_session_check_list(call->ice_session, 1))){ rtp_session_set_pktinfo(call->videostream->session, TRUE); + rtp_session_set_symmetric_rtp(call->videostream->session, FALSE); call->videostream->ice_check_list = ice_session_check_list(call->ice_session, 1); ice_check_list_set_rtp_session(call->videostream->ice_check_list, call->videostream->session); } From 98cfcb39f9d0e215efe1c53fbf4ab07dc067b458 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 16 Aug 2012 10:59:14 +0200 Subject: [PATCH 74/74] Better loop ending test. --- coreapi/misc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/misc.c b/coreapi/misc.c index 3d3cb4477..4292a6f17 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -647,7 +647,7 @@ void linphone_core_update_local_media_description_from_ice(SalMediaDescription * stream->ice_mismatch = ice_check_list_is_mismatch(cl); if ((cl->state == ICL_Running) || (cl->state == ICL_Completed)) { memset(stream->ice_candidates, 0, sizeof(stream->ice_candidates)); - for (j = 0; j < ms_list_size(cl->local_candidates); j++) { + for (j = 0; j < MIN(ms_list_size(cl->local_candidates), SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES); j++) { SalIceCandidate *sal_candidate = &stream->ice_candidates[nb_candidates]; IceCandidate *ice_candidate = ms_list_nth_data(cl->local_candidates, j); const char *default_addr = NULL;