From fd852f01c6f63abb082dcb48f8ba4e88ebe04daa Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 17 Jul 2012 12:23:33 +0200 Subject: [PATCH 001/106] 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 002/106] 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 003/106] 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 004/106] 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 005/106] 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 006/106] 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 007/106] 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 008/106] 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 009/106] 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 010/106] 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 011/106] 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 012/106] 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 013/106] 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 014/106] 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 015/106] 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 016/106] 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 017/106] 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 018/106] 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 019/106] 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 020/106] 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 021/106] 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 022/106] 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 023/106] 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 024/106] 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 025/106] 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 026/106] 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 027/106] 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 028/106] 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 029/106] 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 030/106] 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 031/106] 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 032/106] 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 033/106] 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 034/106] 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 035/106] 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 036/106] 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 037/106] 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 038/106] 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 039/106] 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 040/106] 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 041/106] 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 042/106] 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 043/106] 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 044/106] 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 045/106] 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 046/106] 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 047/106] 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 048/106] 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 049/106] 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 050/106] 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 051/106] 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 052/106] 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 053/106] 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 054/106] 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 055/106] 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 056/106] 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 057/106] 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 058/106] 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 059/106] 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 060/106] 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 061/106] 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 062/106] 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 063/106] 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 064/106] 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 065/106] 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 066/106] 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 067/106] 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 068/106] 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 c97efee37aea1ccae3c476a108e988e47f38faa4 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Fri, 10 Aug 2012 10:41:51 +0200 Subject: [PATCH 069/106] Update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 863022b56..b72c14600 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 863022b56fab41d2ca45dd1d149cb0caab08b54b +Subproject commit b72c14600003707dce7abd0c1003bd51a0d033c1 From 66f80b83ffbb230c6f579daad0e06c9d328dd701 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 10 Aug 2012 12:49:04 +0200 Subject: [PATCH 070/106] 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 071/106] 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 adf9c369f993b4fd759a3df6efe05411952ead18 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 13 Aug 2012 09:48:57 +0200 Subject: [PATCH 072/106] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index b72c14600..0a55eafa6 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit b72c14600003707dce7abd0c1003bd51a0d033c1 +Subproject commit 0a55eafa62fa0742dbd812e04b48a5f14f7c1654 From 0203f32f0fcfcff02de7f0d17420bf550a15d752 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 13 Aug 2012 09:45:54 +0200 Subject: [PATCH 073/106] fix bug when telephone-event appears first in a remote SDP offer --- coreapi/offeranswer.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index 5a2b4f527..4b41f4ca3 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -21,9 +21,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "offeranswer.h" static bool_t only_telephone_event(const MSList *l){ - PayloadType *p=(PayloadType*)l->data; - if (strcasecmp(p->mime_type,"telephone-event")!=0){ - return FALSE; + for(;l!=NULL;l=l->next){ + PayloadType *p=(PayloadType*)l->data; + if (strcasecmp(p->mime_type,"telephone-event")!=0){ + return FALSE; + } } return TRUE; } From bccc94646ad9162c16346cf72238d3d2f53ea485 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 13 Aug 2012 14:28:31 +0200 Subject: [PATCH 074/106] 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 075/106] 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 076/106] 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 077/106] 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; From 42e4255c96907e67bb3c1dfc9de2a90b50dc0581 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 16 Aug 2012 12:00:49 +0200 Subject: [PATCH 078/106] Update ms2 and oRTP. --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index 0a55eafa6..d5014c8dc 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 0a55eafa62fa0742dbd812e04b48a5f14f7c1654 +Subproject commit d5014c8dcf1dbce6448dfa4e7d8f940fec995cd2 diff --git a/oRTP b/oRTP index 2590e21d8..6146d4b20 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 2590e21d864b43d6ac3a2ece0cf3b4d0e208e866 +Subproject commit 6146d4b205abb12b0108558d22f69f0e6d9eab6b From 423777d8cfe8d0257e99db7309dfae9af560cd91 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 16 Aug 2012 14:27:21 +0200 Subject: [PATCH 079/106] Compilation fix. --- coreapi/sal_eXosip2_sdp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 9ca194199..e1e2341b5 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -514,7 +514,7 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ /* Get media specific RTCP attribute */ stream->rtcp_port = stream->rtp_port + 1; - snprintf(stream->rtcp_addr, sizeof(stream->rtcp_addr), stream->rtp_addr); + snprintf(stream->rtcp_addr, sizeof(stream->rtcp_addr), "%s", 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]; From 05601300f64c0f095ba0faeb9e2dd1c1e9483238 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 16 Aug 2012 15:23:59 +0200 Subject: [PATCH 080/106] Update ms2. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index d5014c8dc..43f7f795f 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit d5014c8dcf1dbce6448dfa4e7d8f940fec995cd2 +Subproject commit 43f7f795f22fd8b4cbab313d2adaf854c41575a7 From ff7c61809a89cc4deb3a01e93825906f3d313afb Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 17 Aug 2012 11:07:06 +0200 Subject: [PATCH 081/106] Update ms2 and oRTP. --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index 43f7f795f..ffcc02715 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 43f7f795f22fd8b4cbab313d2adaf854c41575a7 +Subproject commit ffcc02715248916653e7091fb5fa139b651fae94 diff --git a/oRTP b/oRTP index 6146d4b20..f2f27af98 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 6146d4b205abb12b0108558d22f69f0e6d9eab6b +Subproject commit f2f27af98f2a38daa1725641ddd8e435598a4e1b From 0a12fa9ce7af5c795722ce1f7ebad9bc85314d3b Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 20 Aug 2012 14:36:09 +0200 Subject: [PATCH 082/106] Update ms2 and oRTP submodules. --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index ffcc02715..6016a3ce7 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit ffcc02715248916653e7091fb5fa139b651fae94 +Subproject commit 6016a3ce7577d51689bec71a0188385862aec6d9 diff --git a/oRTP b/oRTP index f2f27af98..67b89aba8 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit f2f27af98f2a38daa1725641ddd8e435598a4e1b +Subproject commit 67b89aba8bfa08a4b827441c1f660b234c283443 From 2e5e82c03ddfe68fd23faf9d2176bc88eb695dee Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 20 Aug 2012 18:32:31 +0200 Subject: [PATCH 083/106] update ms2 (x11 bugfix) --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 6016a3ce7..826e43fc6 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 6016a3ce7577d51689bec71a0188385862aec6d9 +Subproject commit 826e43fc66469d9cee126e81b38919dd2bc542c3 From aca7607beab7929dcd00c3e3f6136ee415c70433 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 21 Aug 2012 10:32:26 +0200 Subject: [PATCH 084/106] add dtmf_player_amp propertyo --- coreapi/linphonecore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 4b6c02c93..e9142ba41 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -4246,7 +4246,7 @@ static MSFilter *get_dtmf_gen(LinphoneCore *lc){ return stream->dtmfgen; } if (lc->ringstream==NULL){ - float amp=0.1; + float amp=lp_config_get_float(lc->config,"sound","dtmf_player_amp",0.1); MSSndCard *ringcard=lc->sound_conf.lsd_card ?lc->sound_conf.lsd_card : lc->sound_conf.ring_sndcard; if (ringcard == NULL) return NULL; From 75040297c12e118cea0ec87d2bc3980c290f8e86 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Tue, 21 Aug 2012 10:55:20 +0200 Subject: [PATCH 085/106] Update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 826e43fc6..0778db71a 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 826e43fc66469d9cee126e81b38919dd2bc542c3 +Subproject commit 0778db71afdce04b55fe686f6a7c24aa909436c4 From e16ac3b3a6e6041ef8dc3d353f89d88ed32e74a8 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 21 Aug 2012 13:20:40 +0200 Subject: [PATCH 086/106] Update ms2 and oRTP submodules. --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index 6016a3ce7..c67f981f4 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 6016a3ce7577d51689bec71a0188385862aec6d9 +Subproject commit c67f981f40c195005bfa289c25ba99faa16aadc9 diff --git a/oRTP b/oRTP index 67b89aba8..cba069472 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 67b89aba8bfa08a4b827441c1f660b234c283443 +Subproject commit cba069472f6a464c0d7372cd97be0215cf165995 From 125626d071204ca5369eb2f33c727e8e6e6418f7 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 21 Aug 2012 15:06:11 +0200 Subject: [PATCH 087/106] Fix enabling and disabling of video. --- coreapi/linphonecore.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index e9142ba41..437251eb7 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2524,6 +2524,8 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho linphone_call_delete_ice_session(call); } else return err; } + } else { + call->params = *params; } #endif err = linphone_core_start_update_call(lc, call); From 29100967ae8e680a2de6ce6a6ac2743ad1a1d904 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 22 Aug 2012 09:43:59 +0200 Subject: [PATCH 088/106] Update ms2 submodule. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index c67f981f4..0e7941097 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit c67f981f40c195005bfa289c25ba99faa16aadc9 +Subproject commit 0e7941097d8aaf65e801dbfc1dcb9d20fb268e9d From ae54442d0f26ab54975cf297f256e21c082692a3 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 22 Aug 2012 09:56:26 +0200 Subject: [PATCH 089/106] update version number --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 235fb79b1..eae637b84 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ dnl Process this file with autoconf to produce a configure script. -AC_INIT([linphone],[3.5.2],[linphone-developers@nongnu.org]) +AC_INIT([linphone],[3.5.99.0],[linphone-developers@nongnu.org]) AC_CANONICAL_SYSTEM AC_CONFIG_SRCDIR([coreapi/linphonecore.c]) From da56c0838b6e301fca338faaac53cd026ec02d88 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Wed, 22 Aug 2012 11:09:36 +0200 Subject: [PATCH 090/106] Update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 0e7941097..900c1964b 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 0e7941097d8aaf65e801dbfc1dcb9d20fb268e9d +Subproject commit 900c1964b3b76ad542275977a0fe038c16138491 From c82d1dd37fd121a7d6fdeb38432f40fe21909183 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 22 Aug 2012 12:05:12 +0200 Subject: [PATCH 091/106] Allow starting video stream without starting audio stream. --- coreapi/linphonecall.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 9e9ecee42..340f02cc3 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1426,8 +1426,7 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut SalProtoRtpAvp,SalVideo); #endif - if(call->audiostream == NULL) - { + if ((call->audiostream == NULL) && (call->videostream == NULL)) { ms_fatal("start_media_stream() called without prior init !"); return; } @@ -1439,7 +1438,9 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut use_arc=FALSE; } #endif - linphone_call_start_audio_stream(call,cname,all_inputs_muted,send_ringbacktone,use_arc); + if (call->audiostream!=NULL) { + linphone_call_start_audio_stream(call,cname,all_inputs_muted,send_ringbacktone,use_arc); + } call->current_params.has_video=FALSE; if (call->videostream!=NULL) { linphone_call_start_video_stream(call,cname,all_inputs_muted); From 467d83da4c2b634d1648cfa44214e4446cefb0e7 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 22 Aug 2012 15:54:44 +0200 Subject: [PATCH 092/106] Do not include ICE candidates in the SDP for a media stream with the port set to 0. --- coreapi/sal_eXosip2_sdp.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index e1e2341b5..6b1dd8855 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -384,10 +384,12 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription 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); + if (desc->rtp_port != 0) { + 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); + } } } From 1f9a43a8e8cb759070737338d4638ed01cec4ec0 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 22 Aug 2012 15:56:59 +0200 Subject: [PATCH 093/106] Prevent crappy RTP and RTCP address if their extraction from ICE fails. --- coreapi/misc.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/coreapi/misc.c b/coreapi/misc.c index 4292a6f17..a4db409d9 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -612,6 +612,7 @@ void linphone_core_update_local_media_description_from_ice(SalMediaDescription * IceSessionState session_state = ice_session_state(session); int nb_candidates; int i, j; + bool_t result; if (session_state == IS_Completed) { desc->ice_completed = TRUE; @@ -630,11 +631,17 @@ 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_selected_valid_local_candidate(ice_session_check_list(session, i), &rtp_addr, &stream->rtp_port, &rtcp_addr, &stream->rtcp_port); + result = ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, i), &rtp_addr, &stream->rtp_port, &rtcp_addr, &stream->rtcp_port); + } else { + stream->ice_completed = FALSE; + result = ice_check_list_default_local_candidate(ice_session_check_list(session, i), &rtp_addr, &stream->rtp_port, &rtcp_addr, &stream->rtcp_port); + } + if (result == TRUE) { 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; + memset(stream->rtp_addr, 0, sizeof(stream->rtp_addr)); + memset(stream->rtcp_addr, 0, sizeof(stream->rtcp_addr)); } 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)); From 4e7aa3c6c6692878e681aa63560de433b3646342 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 22 Aug 2012 15:58:13 +0200 Subject: [PATCH 094/106] Set the state of an ICE check list to Failed if the peer has set the port of the media stream to 0. --- coreapi/misc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/misc.c b/coreapi/misc.c index a4db409d9..e5aa6ec2c 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -772,7 +772,7 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, break; } } - if (stream->ice_mismatch == TRUE) { + if ((stream->ice_mismatch == TRUE) || (stream->rtp_port == 0)) { ice_check_list_set_state(cl, ICL_Failed); } else { if ((stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) From a0be0c1b3b977f2ebc1e7712c648ae9748788458 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Wed, 22 Aug 2012 18:58:38 +0200 Subject: [PATCH 095/106] Update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 900c1964b..b2e01872f 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 900c1964b3b76ad542275977a0fe038c16138491 +Subproject commit b2e01872f8fe33db60a7913a26bc037b4d664846 From ced4134ba2756426e71ad5e1382e2682abad07fd Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Thu, 23 Aug 2012 08:27:09 +0200 Subject: [PATCH 096/106] Update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index b2e01872f..ec3580ad5 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit b2e01872f8fe33db60a7913a26bc037b4d664846 +Subproject commit ec3580ad58e5df9fbd4b75219d39042f49e1fd8c From 1438d4f5911aa692b862b04e421eb48de3147b00 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Thu, 23 Aug 2012 10:08:17 +0200 Subject: [PATCH 097/106] Update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index ec3580ad5..4ef6e73a9 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit ec3580ad58e5df9fbd4b75219d39042f49e1fd8c +Subproject commit 4ef6e73a944b089efc65604d92ef75fa95d27477 From 9b9106c1e798399a76b4a75cd75c30b691d5436d Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 24 Aug 2012 10:40:37 +0200 Subject: [PATCH 098/106] fix bad function name --- coreapi/linphonecore.c | 2 +- coreapi/linphonecore.h | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 437251eb7..6ed23e7c8 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -4673,7 +4673,7 @@ void linphone_core_set_network_reachable(LinphoneCore* lc,bool_t isReachable) { set_network_reachable(lc,isReachable, ms_time(NULL)); } -bool_t linphone_core_is_network_reachabled(LinphoneCore* lc) { +bool_t linphone_core_is_network_reachable(LinphoneCore* lc) { return lc->network_reachable; } ortp_socket_t linphone_core_get_sip_socket(LinphoneCore *lc){ diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 87686d6ff..984b09d56 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1096,17 +1096,15 @@ void linphone_core_set_mtu(LinphoneCore *lc, int mtu); /** * @ingroup network_parameters * This method is called by the application to notify the linphone core library when network is reachable. - * Calling this method with true trigger linphone to initiate a registration process for all proxy - * configuration with parameter register set to enable. - * This method disable the automatic registration mode. It means you must call this method after each network state changes - * + * Calling this method with true trigger linphone to initiate a registration process for all proxies. + * Calling this method disables the automatic network detection mode. It means you must call this method after each network state changes. */ void linphone_core_set_network_reachable(LinphoneCore* lc,bool_t value); /** * @ingroup network_parameters - * return network state either as positioned by the application or by linphone + * return network state either as positioned by the application or by linphone itself. */ -bool_t linphone_core_is_network_reachabled(LinphoneCore* lc); +bool_t linphone_core_is_network_reachable(LinphoneCore* lc); /** * @ingroup network_parameters From 52766069426b9e6d2f24c15c5f3d2037d51826de Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 23 Aug 2012 09:57:10 +0200 Subject: [PATCH 099/106] Do not delete ICE session when it is in the Failed state. If the ICE session is deleted it can not be restarted later. However try to send a re-invite if the session state is Failed but some check lists have completed successfully. --- coreapi/linphonecall.c | 8 +++++++- coreapi/misc.c | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 340f02cc3..4ffb699b2 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1718,7 +1718,13 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){ } break; case IS_Failed: - linphone_call_delete_ice_session(call); + if (ice_session_has_completed_check_list(call->ice_session) == TRUE) { + if (ice_session_role(call->ice_session) == IR_Controlling) { + /* At least one ICE session has succeeded, so perform a call update. */ + ice_session_select_candidates(call->ice_session); + linphone_core_update_call(call->core, call, &call->current_params); + } + } break; default: break; diff --git a/coreapi/misc.c b/coreapi/misc.c index e5aa6ec2c..3f48b419b 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -808,7 +808,7 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, } 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)) { + if (ice_session_nb_check_lists(call->ice_session) == 0) { linphone_call_delete_ice_session(call); } } From 011750b6cd288423a64b9185eabacb6976e92141 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 23 Aug 2012 12:28:15 +0200 Subject: [PATCH 100/106] Prevent gathering ICE candidates if not needed. --- coreapi/linphonecore.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 6ed23e7c8..46c8b11c0 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2507,25 +2507,22 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho int err=0; if (params!=NULL){ #ifdef VIDEO_ENABLED + bool_t has_video = call->params.has_video; if ((call->ice_session != NULL) && (call->videostream != NULL) && !params->has_video) { ice_session_remove_check_list(call->ice_session, call->videostream->ice_check_list); call->videostream->ice_check_list = NULL; } - if ((call->ice_session != NULL) && ((ice_session_state(call->ice_session) != IS_Completed) || (call->params.has_video != params->has_video))) { + call->params = *params; + if ((call->ice_session != NULL) && (ice_session_state(call->ice_session) != IS_Completed) && !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; - } - } else { - call->params = *params; + 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; } #endif err = linphone_core_start_update_call(lc, call); From 7b6314c381ec25d3bbb169c95c1fbbf98a5c251a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 23 Aug 2012 16:10:55 +0200 Subject: [PATCH 101/106] Set an ICE check list to the Failed state if the corresponding media stream has been deactivated by the peer. --- coreapi/callbacks.c | 3 +++ coreapi/misc.c | 11 +++++++++++ coreapi/private.h | 1 + 3 files changed, 15 insertions(+) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 584191cc4..95d5b81af 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -46,6 +46,9 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia call->media_pending=TRUE; } call->resultdesc=new_md; + if (call->ice_session != NULL) { + linphone_core_deactivate_ice_for_deactivated_media_streams(call, call->resultdesc); + } if (call->audiostream && call->audiostream->ticker){ /* we already started media: check if we really need to restart it*/ if (oldmd){ diff --git a/coreapi/misc.c b/coreapi/misc.c index 3f48b419b..a65793350 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -813,6 +813,17 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, } } +void linphone_core_deactivate_ice_for_deactivated_media_streams(LinphoneCall *call, const SalMediaDescription *md) +{ + int i; + for (i = 0; i < md->nstreams; i++) { + IceCheckList *cl = ice_session_check_list(call->ice_session, i); + if (cl && (md->streams[i].rtp_port == 0)) { + if (cl->state != ICL_Completed) ice_check_list_set_state(cl, ICL_Failed); + } + } +} + 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 a68615e36..b102dc7b5 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -224,6 +224,7 @@ 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_deactivate_ice_for_deactivated_media_streams(LinphoneCall *call, const SalMediaDescription *md); void linphone_core_send_initial_subscribes(LinphoneCore *lc); void linphone_core_write_friends_config(LinphoneCore* lc); From 3b8e54e6ec4448abc65fb1ffb65ee38f13ab5165 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 23 Aug 2012 16:13:07 +0200 Subject: [PATCH 102/106] Check if an ICE check list can be set to the Completed state after adding the losing pairs. --- coreapi/misc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/coreapi/misc.c b/coreapi/misc.c index a65793350..e1943521b 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -791,6 +791,7 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, candidate->priority, candidate->foundation, default_candidate); } if (ice_restarted == FALSE) { + bool_t losing_pairs_added = 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; @@ -798,8 +799,10 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, 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); + ice_add_losing_pair(cl, j + 1, candidate->addr, candidate->port, addr, port); + losing_pairs_added = TRUE; } + if (losing_pairs_added == TRUE) ice_check_list_check_completed(cl); } } } From 101278f2f0175817e0fad58a0b203b5fa2bfdf8a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 23 Aug 2012 16:57:52 +0200 Subject: [PATCH 103/106] Restart media streams when updating them even if only the video stream is running. --- coreapi/callbacks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 95d5b81af..161aaab24 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -49,7 +49,7 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia if (call->ice_session != NULL) { linphone_core_deactivate_ice_for_deactivated_media_streams(call, call->resultdesc); } - if (call->audiostream && call->audiostream->ticker){ + if ((call->audiostream && call->audiostream->ticker) || (call->videostream && call->videostream->ticker)){ /* we already started media: check if we really need to restart it*/ if (oldmd){ if (!media_parameters_changed(call,oldmd,new_md) && !call->playing_ringbacktone){ From 29e0c09557876f98ce93b625a966be8e75b377c8 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 24 Aug 2012 09:24:24 +0200 Subject: [PATCH 104/106] Use accessor function to get ICE check list state. --- coreapi/misc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/coreapi/misc.c b/coreapi/misc.c index e1943521b..bf5c53dcc 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -629,7 +629,7 @@ 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) { + if (ice_check_list_state(cl) == ICL_Completed) { stream->ice_completed = TRUE; result = ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, i), &rtp_addr, &stream->rtp_port, &rtcp_addr, &stream->rtcp_port); } else { @@ -652,7 +652,7 @@ void linphone_core_update_local_media_description_from_ice(SalMediaDescription * 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)) { + if ((ice_check_list_state(cl) == ICL_Running) || (ice_check_list_state(cl) == ICL_Completed)) { memset(stream->ice_candidates, 0, sizeof(stream->ice_candidates)); 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]; @@ -668,7 +668,7 @@ void linphone_core_update_local_media_description_from_ice(SalMediaDescription * } 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) + if ((ice_check_list_state(cl) == 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)); @@ -684,7 +684,7 @@ void linphone_core_update_local_media_description_from_ice(SalMediaDescription * nb_candidates++; } } - if ((cl->state == ICL_Completed) && (ice_session_role(session) == IR_Controlling)) { + if ((ice_check_list_state(cl) == 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_selected_valid_remote_candidate(cl, &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port); @@ -822,7 +822,7 @@ void linphone_core_deactivate_ice_for_deactivated_media_streams(LinphoneCall *ca for (i = 0; i < md->nstreams; i++) { IceCheckList *cl = ice_session_check_list(call->ice_session, i); if (cl && (md->streams[i].rtp_port == 0)) { - if (cl->state != ICL_Completed) ice_check_list_set_state(cl, ICL_Failed); + if (ice_check_list_state(cl) != ICL_Completed) ice_check_list_set_state(cl, ICL_Failed); } } } From af077522263bafdc21e85baf0ae52b4d2b1f061f Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 24 Aug 2012 10:58:30 +0200 Subject: [PATCH 105/106] Update ms2 submodule. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 4ef6e73a9..54678a7ac 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 4ef6e73a944b089efc65604d92ef75fa95d27477 +Subproject commit 54678a7aca9ce71dc43660fc80364cd0a2076ca9 From 2e64b3b04573d6b26f337177bece4a9d266ae83d Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 24 Aug 2012 11:14:33 +0200 Subject: [PATCH 106/106] update ms2 for bugfix and fix JNI --- coreapi/linphonecore_jni.cc | 2 +- mediastreamer2 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 894e4c1f8..bf1a30bcd 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -601,7 +601,7 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setNetworkStateReachable extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isNetworkStateReachable( JNIEnv* env ,jobject thiz ,jlong lc) { - return linphone_core_is_network_reachabled((LinphoneCore*)lc); + return linphone_core_is_network_reachable((LinphoneCore*)lc); } extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPlaybackGain( JNIEnv* env diff --git a/mediastreamer2 b/mediastreamer2 index 54678a7ac..b184aec8e 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 54678a7aca9ce71dc43660fc80364cd0a2076ca9 +Subproject commit b184aec8e85e094df2b9c18e0ba4bf19aa873ec9