From 39f93c4eea65c4c5deb209e5fd038cfdb2c0bf12 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 14 Oct 2009 19:26:10 +0000 Subject: [PATCH] delay update till after media has been confirmed to prevent SOA race in sip git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@15159 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- src/include/switch_channel.h | 5 ++ src/include/switch_types.h | 7 +++ src/mod/endpoints/mod_sofia/mod_sofia.c | 72 ++++++++++++------------ src/mod/endpoints/mod_sofia/sofia.c | 11 +++- src/mod/endpoints/mod_sofia/sofia_glue.c | 2 + src/switch_channel.c | 29 +++++++++- src/switch_ivr_bridge.c | 12 ++-- 7 files changed, 92 insertions(+), 46 deletions(-) diff --git a/src/include/switch_channel.h b/src/include/switch_channel.h index d9d0406a69..78d71d4f75 100644 --- a/src/include/switch_channel.h +++ b/src/include/switch_channel.h @@ -80,6 +80,7 @@ SWITCH_DECLARE(int) switch_channel_test_ready(switch_channel_t *channel, switch_ #define switch_channel_media_ready(_channel) switch_channel_test_ready(_channel, SWITCH_TRUE) #define switch_channel_up(_channel) (switch_channel_get_state(_channel) < CS_HANGUP) #define switch_channel_down(_channel) (switch_channel_get_state(_channel) >= CS_HANGUP) +#define switch_channel_media_ack(_channel) (!switch_channel_test_cap(_channel, CC_MEDIA_ACK) || switch_channel_test_flag(_channel, CF_MEDIA_ACK)) SWITCH_DECLARE(void) switch_channel_wait_for_state(switch_channel_t *channel, switch_channel_t *other_channel, switch_channel_state_t want_state); SWITCH_DECLARE(void) switch_channel_wait_for_state_timeout(switch_channel_t *other_channel, switch_channel_state_t want_state, uint32_t timeout); @@ -297,6 +298,10 @@ SWITCH_DECLARE(uint32_t) switch_channel_test_flag(switch_channel_t *channel, swi SWITCH_DECLARE(void) switch_channel_set_flag(switch_channel_t *channel, switch_channel_flag_t flag); SWITCH_DECLARE(void) switch_channel_set_flag_recursive(switch_channel_t *channel, switch_channel_flag_t flag); +SWITCH_DECLARE(void) switch_channel_set_cap(switch_channel_t *channel, switch_channel_cap_t cap); +SWITCH_DECLARE(void) switch_channel_clear_cap(switch_channel_t *channel, switch_channel_cap_t cap); +SWITCH_DECLARE(uint32_t) switch_channel_test_cap(switch_channel_t *channel, switch_channel_cap_t cap); + /*! \brief Set given flag(s) on a given channel's bridge partner \param channel channel to derive the partner channel to set flag on diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 539e8dfe7d..d672e98a42 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -866,6 +866,12 @@ CF_STOP_BROADCAST - Signal to stop broadcast */ +typedef enum { + CC_MEDIA_ACK = 1, + /* WARNING: DO NOT ADD ANY FLAGS BELOW THIS LINE */ + CC_FLAG_MAX +} switch_channel_cap_t; + typedef enum { CF_ANSWERED = 1, CF_OUTBOUND, @@ -906,6 +912,7 @@ typedef enum { CF_TIMESTAMP_SET, CF_ORIGINATOR, CF_XFER_ZOMBIE, + CF_MEDIA_ACK, /* WARNING: DO NOT ADD ANY FLAGS BELOW THIS LINE */ CF_FLAG_MAX } switch_channel_flag_t; diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 0d1a0f66e1..a146e460ca 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -1289,43 +1289,45 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi number = tech_pvt->caller_profile->destination_number; } - if (switch_strlen_zero(tech_pvt->last_sent_callee_id_name) || strcmp(tech_pvt->last_sent_callee_id_name, name) || - switch_strlen_zero(tech_pvt->last_sent_callee_id_number) || strcmp(tech_pvt->last_sent_callee_id_number, number)) { - - if (ua && switch_stristr("snom", ua)) { - snprintf(message, sizeof(message), "From:\r\nTo: \"%s\" %s\r\n", name, number); - nua_info(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), - TAG_IF(!switch_strlen_zero(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), - SIPTAG_PAYLOAD_STR(message), TAG_END()); - } else if ((ua && (switch_stristr("polycom", ua) || - switch_stristr("UPDATE", tech_pvt->x_actually_support_remote)))) { - snprintf(message, sizeof(message), "P-Asserted-Identity: \"%s\" <%s>", name, number); - nua_update(tech_pvt->nh, - TAG_IF(!switch_strlen_zero_buf(message), SIPTAG_HEADER_STR(message)), - TAG_IF(!switch_strlen_zero(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), - TAG_END()); - } - - tech_pvt->last_sent_callee_id_name = switch_core_session_strdup(tech_pvt->session, name); - tech_pvt->last_sent_callee_id_number = switch_core_session_strdup(tech_pvt->session, number); - - if (switch_event_create(&event, SWITCH_EVENT_CALL_UPDATE) == SWITCH_STATUS_SUCCESS) { - const char *uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Direction", "SEND"); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Callee-Name", name); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Callee-Number", number); - if (uuid) { - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Bridged-To", uuid); - } - switch_channel_event_set_data(channel, event); - switch_event_fire(&event); - } + if (!switch_channel_test_flag(channel, CF_ANSWERED)) { + switch_channel_set_variable(channel, "sip_callee_id_name", name); + switch_channel_set_variable(channel, "sip_callee_id_number", number); } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Not sending same id again \"%s\" <%s>\n", name, number); + if (switch_strlen_zero(tech_pvt->last_sent_callee_id_name) || strcmp(tech_pvt->last_sent_callee_id_name, name) || + switch_strlen_zero(tech_pvt->last_sent_callee_id_number) || strcmp(tech_pvt->last_sent_callee_id_number, number)) { + + if (ua && switch_stristr("snom", ua)) { + snprintf(message, sizeof(message), "From:\r\nTo: \"%s\" %s\r\n", name, number); + nua_info(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), + TAG_IF(!switch_strlen_zero(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), + SIPTAG_PAYLOAD_STR(message), TAG_END()); + } else if ((ua && (switch_stristr("polycom", ua) || + switch_stristr("UPDATE", tech_pvt->x_actually_support_remote)))) { + snprintf(message, sizeof(message), "P-Asserted-Identity: \"%s\" <%s>", name, number); + nua_update(tech_pvt->nh, + TAG_IF(!switch_strlen_zero_buf(message), SIPTAG_HEADER_STR(message)), + TAG_IF(!switch_strlen_zero(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), + TAG_END()); + } + + tech_pvt->last_sent_callee_id_name = switch_core_session_strdup(tech_pvt->session, name); + tech_pvt->last_sent_callee_id_number = switch_core_session_strdup(tech_pvt->session, number); + + if (switch_event_create(&event, SWITCH_EVENT_CALL_UPDATE) == SWITCH_STATUS_SUCCESS) { + const char *uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Direction", "SEND"); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Callee-Name", name); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Callee-Number", number); + if (uuid) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Bridged-To", uuid); + } + switch_channel_event_set_data(channel, event); + switch_event_fire(&event); + } + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Not sending same id again \"%s\" <%s>\n", name, number); + } } - - - } switch_safe_free(arg); diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index e1c8f48137..53dc9f2df1 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -603,12 +603,15 @@ void sofia_event_callback(nua_event_t event, case nua_r_cancel: case nua_i_error: case nua_i_active: - case nua_i_ack: case nua_i_terminated: case nua_r_set_params: case nua_i_prack: case nua_r_prack: break; + case nua_i_ack: + case nua_r_ack: + if (channel) switch_channel_set_flag(channel, CF_MEDIA_ACK); + break; case nua_r_shutdown: if (status >= 200) su_root_break(profile->s_root); break; @@ -1021,6 +1024,7 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void NUTAG_APPL_METHOD("REGISTER"), NUTAG_APPL_METHOD("NOTIFY"), NUTAG_APPL_METHOD("INFO"), + NUTAG_APPL_METHOD("ACK"), #ifdef MANUAL_BYE NUTAG_APPL_METHOD("BYE"), #endif @@ -3109,11 +3113,12 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status caller_profile->network_addr = switch_core_strdup(caller_profile->pool, network_ip); } - switch_channel_clear_flag(channel, CF_REQ_MEDIA); - if ((status == 180 || status == 183 || status == 200)) { const char *x_actually_support; + switch_channel_set_flag(channel, CF_MEDIA_ACK); + switch_channel_clear_flag(channel, CF_REQ_MEDIA); + if ((x_actually_support = sofia_glue_get_unknown_header(sip, "X-Actually-Support"))) { tech_pvt->x_actually_support_remote = switch_core_session_strdup(session, x_actually_support); } diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index cdf55cc843..9e401e644f 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -521,6 +521,8 @@ void sofia_glue_attach_private(switch_core_session_t *session, sofia_profile_t * tech_pvt->session = session; tech_pvt->channel = switch_core_session_get_channel(session); + switch_channel_set_cap(tech_pvt->channel, CC_MEDIA_ACK); + switch_core_session_set_private(session, tech_pvt); switch_snprintf(name, sizeof(name), "sofia/%s/%s", profile->name, channame); diff --git a/src/switch_channel.c b/src/switch_channel.c index 2daf31c8ee..2836edcff7 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -1,4 +1,3 @@ - /* * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application * Copyright (C) 2005-2009, Anthony Minessale II @@ -120,6 +119,7 @@ struct switch_channel { switch_channel_state_t state; switch_channel_state_t running_state; uint32_t flags[CF_FLAG_MAX]; + uint32_t caps[CC_FLAG_MAX]; uint8_t state_flags[CF_FLAG_MAX]; uint32_t private_flags; uint32_t app_flags; @@ -841,6 +841,33 @@ SWITCH_DECLARE(switch_status_t) switch_channel_wait_for_flag(switch_channel_t *c return SWITCH_STATUS_SUCCESS; } + +SWITCH_DECLARE(void) switch_channel_set_cap(switch_channel_t *channel, switch_channel_cap_t cap) +{ + switch_assert(channel); + switch_assert(channel->flag_mutex); + + switch_mutex_lock(channel->flag_mutex); + channel->caps[cap] = 1; + switch_mutex_unlock(channel->flag_mutex); +} + +SWITCH_DECLARE(void) switch_channel_clear_cap(switch_channel_t *channel, switch_channel_cap_t cap) +{ + switch_assert(channel != NULL); + switch_assert(channel->flag_mutex); + + switch_mutex_lock(channel->flag_mutex); + channel->caps[cap] = 0; + switch_mutex_unlock(channel->flag_mutex); +} + +SWITCH_DECLARE(uint32_t) switch_channel_test_cap(switch_channel_t *channel, switch_channel_cap_t cap) +{ + switch_assert(channel != NULL); + return channel->caps[cap] ? 1 : 0; +} + SWITCH_DECLARE(void) switch_channel_set_flag(switch_channel_t *channel, switch_channel_flag_t flag) { switch_assert(channel); diff --git a/src/switch_ivr_bridge.c b/src/switch_ivr_bridge.c index 9f1fc62fe2..c43e8d0ae3 100644 --- a/src/switch_ivr_bridge.c +++ b/src/switch_ivr_bridge.c @@ -161,7 +161,7 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj) const char *silence_var, *var; int silence_val = 0, bypass_media_after_bridge = 0; const char *bridge_answer_timeout = NULL; - int answer_timeout, sent_update = -50; + int answer_timeout, sent_update = 0; time_t answer_limit = 0; @@ -184,6 +184,7 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj) chan_b = switch_core_session_get_channel(session_b); ans_a = switch_channel_test_flag(chan_a, CF_ANSWERED); + if ((originator = switch_channel_test_flag(chan_a, CF_BRIDGE_ORIGINATOR))) { pre_b = switch_channel_test_flag(chan_a, CF_EARLY_MEDIA); ans_b = switch_channel_test_flag(chan_b, CF_ANSWERED); @@ -397,12 +398,9 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj) } } - - if (originator && sent_update < 0 && ans_a && ans_b) { - if (!++sent_update) { - switch_ivr_bridge_display(session_a, session_b); - sent_update = 1; - } + if (originator && !sent_update && ans_a && ans_b && switch_channel_media_ack(chan_a) && switch_channel_media_ack(chan_b)) { + switch_ivr_bridge_display(session_a, session_b); + sent_update = 1; } #ifndef SWITCH_VIDEO_IN_THREADS