From 3d744d407034e72f2a9bc5291509c08f84f9666a Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 7 Nov 2014 17:59:27 +0100 Subject: [PATCH] * add test for ipv6 calls add linphone_call_media_in_progress() method for app to easily check that ice has finished or not its processing. Update GTK app accordingly, so that adding video is no longer possible while ICE is in progress. --- coreapi/linphonecall.c | 21 +++++++++++++++++++++ coreapi/linphonecore.c | 4 +++- coreapi/linphonecore.h | 3 ++- coreapi/misc.c | 2 +- gtk/incall_view.c | 12 +++++++++++- tester/call_tester.c | 26 ++++++++++++++++++++++++++ tester/liblinphone_tester.c | 18 +++++++++++++++++- tester/liblinphone_tester.h | 1 + tester/rcfiles/pauline_tcp_rc | 2 +- 9 files changed, 83 insertions(+), 6 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 98ab0b47d..c0afd17a5 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2532,6 +2532,27 @@ const LinphoneCallStats *linphone_call_get_video_stats(LinphoneCall *call) { return stats; } +static bool_t ice_in_progress(LinphoneCallStats *stats){ + return stats->ice_state==LinphoneIceStateInProgress; +} + +/** + * Indicates whether an operation is in progress at the media side. + * It can a bad idea to initiate signaling operations (adding video, pausing the call, removing video, changing video parameters) while + * the media is busy in establishing the connection (typically ICE connectivity checks). It can result in failures generating loss of time + * in future operations in the call. + * Applications are invited to check this function after each call state change to decide whether certain operations are permitted or not. + * @param call the call + * @return TRUE if media is busy in establishing the connection, FALSE otherwise. +**/ +bool_t linphone_call_media_in_progress(LinphoneCall *call){ + bool_t ret=FALSE; + if (ice_in_progress(&call->stats[LINPHONE_CALL_STATS_AUDIO]) || ice_in_progress(&call->stats[LINPHONE_CALL_STATS_VIDEO])) + ret=TRUE; + /*TODO: could check zrtp state, upnp state*/ + return ret; +} + /** * Get the local loss rate since last report * @return The sender loss rate diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index af9f61f0f..0832fc947 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2295,9 +2295,11 @@ void linphone_core_enable_ipv6(LinphoneCore *lc, bool_t val){ if (lc->sip_conf.ipv6_enabled!=val){ lc->sip_conf.ipv6_enabled=val; if (lc->sal){ - /* we need to restart eXosip */ + /* we need to update the sip stack */ apply_transports(lc); } + /*update the localip immediately for the network monitor to avoid to "discover" later that we switched to ipv6*/ + linphone_core_get_local_ip(lc,AF_UNSPEC,NULL,lc->localip); } } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 666872865..0be4be5b0 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -481,7 +481,7 @@ typedef struct _LinphoneVideoPolicy LinphoneVideoPolicy; * @ingroup initializing **/ enum _LinphoneIceState{ - LinphoneIceStateNotActivated, /**< ICE has not been activated for this call */ + LinphoneIceStateNotActivated, /**< ICE has not been activated for this call or stream*/ LinphoneIceStateFailed, /**< ICE processing has failed */ LinphoneIceStateInProgress, /**< ICE process is in progress */ LinphoneIceStateHostConnection, /**< ICE has established a direct connection to the remote host */ @@ -730,6 +730,7 @@ LINPHONE_PUBLIC void linphone_call_zoom_video(LinphoneCall* call, float zoom_fac LINPHONE_PUBLIC void linphone_call_start_recording(LinphoneCall *call); LINPHONE_PUBLIC void linphone_call_stop_recording(LinphoneCall *call); LINPHONE_PUBLIC LinphonePlayer * linphone_call_get_player(LinphoneCall *call); +LINPHONE_PUBLIC bool_t linphone_call_media_in_progress(LinphoneCall *call); /** * Return TRUE if this call is currently part of a conference diff --git a/coreapi/misc.c b/coreapi/misc.c index 6a9141ea1..f762bb537 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -686,7 +686,7 @@ void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call) } else { call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateFailed; } - } + }else call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateNotActivated; } else if (session_state == IS_Running) { call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateInProgress; if (call->params->has_video && (video_check_list != NULL)) { diff --git a/gtk/incall_view.c b/gtk/incall_view.c index 5329508b6..4fa0bd66b 100644 --- a/gtk/incall_view.c +++ b/gtk/incall_view.c @@ -426,7 +426,9 @@ void linphone_gtk_update_video_button(LinphoneCall *call){ GtkWidget *conf_frame; const LinphoneCallParams *params=linphone_call_get_current_params(call); gboolean has_video=linphone_call_params_video_enabled(params); + gboolean button_sensitive=FALSE; if (call_view==NULL) return; + button=linphone_gtk_get_widget(call_view,"video_button"); gtk_button_set_image(GTK_BUTTON(button), @@ -436,12 +438,20 @@ void linphone_gtk_update_video_button(LinphoneCall *call){ gtk_widget_set_sensitive(button,FALSE); return; } + switch(linphone_call_get_state(call)){ + case LinphoneCallStreamsRunning: + button_sensitive=!linphone_call_media_in_progress(call); + break; + default: + button_sensitive=FALSE; + break; + } + gtk_widget_set_sensitive(button,button_sensitive); if (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button),"signal_connected"))==0){ g_signal_connect(G_OBJECT(button),"clicked",(GCallback)video_button_clicked,call); g_object_set_data(G_OBJECT(button),"signal_connected",GINT_TO_POINTER(1)); } conf_frame=(GtkWidget *)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"conf_frame"); - gtk_widget_set_sensitive(button,linphone_call_get_state(call)==LinphoneCallStreamsRunning); if(conf_frame!=NULL){ gtk_widget_set_sensitive(button,FALSE); } diff --git a/tester/call_tester.c b/tester/call_tester.c index 37b28ddfd..9918e526d 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -336,6 +336,31 @@ static void simple_call(void) { } } +static void direct_call_over_ipv6(){ + LinphoneCoreManager* marie; + LinphoneCoreManager* pauline; + + if (liblinphone_tester_ipv6_available()){ + marie = linphone_core_manager_new( "marie_rc"); + pauline = linphone_core_manager_new( "pauline_tcp_rc"); + linphone_core_enable_ipv6(marie->lc,TRUE); + linphone_core_enable_ipv6(pauline->lc,TRUE); + linphone_core_set_default_proxy_config(marie->lc,NULL); + linphone_core_invite(marie->lc,"sip:[::1]:12002;transport=tcp"); + + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallOutgoingRinging,1)); + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallIncomingReceived,1)); + linphone_core_accept_call(pauline->lc,linphone_core_get_current_call(pauline->lc)); + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,1)); + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,1)); + + liblinphone_tester_check_rtcp(marie,pauline); + end_call(marie,pauline); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + }else ms_warning("Test skipped, no ipv6 available"); +} + static void call_outbound_with_multiple_proxy() { LinphoneCoreManager* pauline = linphone_core_manager_new2( "pauline_rc", FALSE); LinphoneCoreManager* marie = linphone_core_manager_new2( "marie_rc", FALSE); @@ -3354,6 +3379,7 @@ test_t call_tests[] = { { "Cancelled ringing call", cancelled_ringing_call }, { "Call failed because of codecs", call_failed_because_of_codecs }, { "Simple call", simple_call }, + { "Direct call over IPv6", direct_call_over_ipv6}, { "Outbound call with multiple proxy possible", call_outbound_with_multiple_proxy }, { "Audio call recording", audio_call_recording_test }, #if 0 /* not yet activated because not implemented */ diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 5d68bc2cf..26f3521ec 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -115,7 +115,23 @@ static void liblinphone_tester_qnx_log_handler(OrtpLogLevel lev, const char *fmt } #endif /* __QNX__ */ - +int liblinphone_tester_ipv6_available(void){ + struct addrinfo *ai=belle_sip_ip_address_to_addrinfo(AF_INET6,"2a01:e00::2",53); + if (ai){ + struct sockaddr_storage ss; + struct addrinfo src; + socklen_t slen=sizeof(ss); + char localip[128]; + int port=0; + belle_sip_get_src_addr_for(ai->ai_addr,ai->ai_addrlen,(struct sockaddr*) &ss,&slen,4444); + src.ai_addr=(struct sockaddr*) &ss; + src.ai_addrlen=slen; + belle_sip_addrinfo_to_ip(&src,localip, sizeof(localip),&port); + freeaddrinfo(ai); + return strcmp(localip,"::1")!=0; + } + return FALSE; +} void helper(const char *name) { liblinphone_tester_fprintf(stderr,"%s --help\n" diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index d8ecb1987..464926707 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -76,6 +76,7 @@ extern void liblinphone_tester_uninit(void); extern int liblinphone_tester_run_tests(const char *suite_name, const char *test_name); extern void liblinphone_tester_set_fileprefix(const char* file_prefix); extern void liblinphone_tester_set_writable_dir_prefix(const char* writable_dir_prefix); +extern int liblinphone_tester_ipv6_available(void); #ifdef __cplusplus }; diff --git a/tester/rcfiles/pauline_tcp_rc b/tester/rcfiles/pauline_tcp_rc index 809c1ace6..11cdb64cd 100644 --- a/tester/rcfiles/pauline_tcp_rc +++ b/tester/rcfiles/pauline_tcp_rc @@ -1,6 +1,6 @@ [sip] sip_port=-1 -sip_tcp_port=-1 +sip_tcp_port=12002 sip_tls_port=-1 default_proxy=0 ping_with_options=0