From eac4e3e10a592e456aa1deecedad664f6683e9ec Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 18 Sep 2008 21:50:18 +0000 Subject: [PATCH] nut n honey git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@9591 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- src/include/switch_rtp.h | 3 + src/include/switch_types.h | 1 + src/mod/endpoints/mod_sofia/mod_sofia.c | 16 ++- src/mod/endpoints/mod_sofia/mod_sofia.h | 14 ++- src/mod/endpoints/mod_sofia/sofia.c | 110 ++++++++++++++++- src/mod/endpoints/mod_sofia/sofia_glue.c | 144 +++++++++++++---------- src/switch_ivr_bridge.c | 16 ++- src/switch_rtp.c | 13 ++ 8 files changed, 242 insertions(+), 75 deletions(-) diff --git a/src/include/switch_rtp.h b/src/include/switch_rtp.h index a30c8b5d07..51e7d0cf66 100644 --- a/src/include/switch_rtp.h +++ b/src/include/switch_rtp.h @@ -163,6 +163,9 @@ SWITCH_DECLARE(switch_rtp_t *) switch_rtp_new(const char *rx_host, */ SWITCH_DECLARE(switch_status_t) switch_rtp_set_remote_address(switch_rtp_t *rtp_session, const char *host, switch_port_t port, const char **err); +SWITCH_DECLARE(char *) switch_rtp_get_remote_host(switch_rtp_t *rtp_session); +SWITCH_DECLARE(switch_port_t) switch_rtp_get_remote_port(switch_rtp_t *rtp_session); + SWITCH_DECLARE(void) switch_rtp_set_max_missed_packets(switch_rtp_t *rtp_session, uint32_t max); /*! diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 40ea35143c..23227e1d54 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -110,6 +110,7 @@ SWITCH_BEGIN_EXTERN_C #define SWITCH_PATH_SEPARATOR "/" #endif #define SWITCH_URL_SEPARATOR "://" +#define SWITCH_BYPASS_MEDIA_AFTER_BRIDGE_VARIABLE "bypass_media_after_bridge" #define SWITCH_READ_RESULT_VARIABLE "read_result" #define SWITCH_COPY_XML_CDR_VARIABLE "copy_xml_cdr" #define SWITCH_CURRENT_APPLICATION_VARIABLE "current_application" diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index c2c0cd9664..875ed1e28e 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -114,7 +114,9 @@ static switch_status_t sofia_on_routing(switch_core_session_t *session) private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session); switch_assert(tech_pvt != NULL); - switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD); + if (!switch_test_flag(tech_pvt, TFLAG_HOLD_LOCK)) { + switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD); + } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s SOFIA ROUTING\n", switch_channel_get_name(switch_core_session_get_channel(session))); @@ -127,7 +129,9 @@ static switch_status_t sofia_on_reset(switch_core_session_t *session) private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session); switch_assert(tech_pvt != NULL); - switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD); + if (!switch_test_flag(tech_pvt, TFLAG_HOLD_LOCK)) { + switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD); + } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s SOFIA RESET\n", switch_channel_get_name(switch_core_session_get_channel(session))); @@ -140,7 +144,9 @@ static switch_status_t sofia_on_hibernate(switch_core_session_t *session) private_object_t *tech_pvt = switch_core_session_get_private(session); switch_assert(tech_pvt != NULL); - switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD); + if (!switch_test_flag(tech_pvt, TFLAG_HOLD_LOCK)) { + switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD); + } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s SOFIA HIBERNATE\n", switch_channel_get_name(switch_core_session_get_channel(session))); @@ -152,7 +158,9 @@ static switch_status_t sofia_on_execute(switch_core_session_t *session) private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session); switch_assert(tech_pvt != NULL); - switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD); + if (!switch_test_flag(tech_pvt, TFLAG_HOLD_LOCK)) { + switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD); + } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s SOFIA EXECUTE\n", switch_channel_get_name(switch_core_session_get_channel(session))); return SWITCH_STATUS_SUCCESS; diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 32f79b47ae..d465d5f75a 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -190,7 +190,7 @@ typedef enum { TFLAG_VAD_IN = (1 << 11), TFLAG_VAD_OUT = (1 << 12), TFLAG_VAD = (1 << 13), - TFLAG_USE_ME = (1 << 14), + TFLAG_3PCC = (1 << 14), TFLAG_READY = (1 << 15), TFLAG_REINVITE = (1 << 16), TFLAG_REFER = (1 << 17), @@ -205,7 +205,8 @@ typedef enum { TFLAG_VIDEO = (1 << 26), TFLAG_TPORT_LOG = (1 << 27), TFLAG_SENT_UPDATE = (1 << 28), - TFLAG_PROXY_MEDIA = (1 << 29) + TFLAG_PROXY_MEDIA = (1 << 29), + TFLAG_HOLD_LOCK = (1 << 30) } TFLAGS; struct mod_sofia_globals { @@ -302,6 +303,12 @@ typedef enum { PRES_TYPE_PASSIVE = 2 } sofia_presence_type_t; +typedef enum { + MEDIA_OPT_NONE = 0, + MEDIA_OPT_MEDIA_ON_HOLD = (1 << 0), + MEDIA_OPT_BYPASS_AFTER_ATT_XFER = (1 << 1) +} sofia_media_options_t; + struct sofia_profile { int debug; char *name; @@ -376,6 +383,7 @@ struct sofia_profile { uint32_t nat_acl_count; int rport_level; sofia_presence_type_t pres_type; + sofia_media_options_t media_options; }; struct private_object { @@ -487,6 +495,7 @@ struct private_object { char *remote_ip; int remote_port; int got_bye; + int hold_laps; }; struct callback_t { @@ -687,3 +696,4 @@ switch_status_t reconfig_sofia(sofia_profile_t *profile); void sofia_glue_del_gateway(sofia_gateway_t *gp); void sofia_reg_send_reboot(sofia_profile_t *profile, const char *user, const char *host, const char *contact, const char *user_agent); void sofia_glue_restart_all_profiles(void); +void sofia_glue_toggle_hold(private_object_t *tech_pvt, int sendonly); diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 950d4ce062..78aa79fb22 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -1591,6 +1591,12 @@ switch_status_t config_sofia(int reload, char *profile_name) profile->mflags &= ~MFLAG_REFER; } else if (!strcasecmp(var, "disable-register") && switch_true(val)) { profile->mflags &= ~MFLAG_REGISTER; + } else if (!strcasecmp(var, "media-option")) { + if (!strcasecmp(val, "resume-media-on-hold")) { + profile->media_options |= MEDIA_OPT_MEDIA_ON_HOLD; + } else if (!strcasecmp(val, "bypass-media-after-att-xfer")) { + profile->media_options |= MEDIA_OPT_BYPASS_AFTER_ATT_XFER; + } } else if (!strcasecmp(var, "manage-presence")) { if (!strcasecmp(val, "passive")) { profile->pres_type = PRES_TYPE_PASSIVE; @@ -2144,6 +2150,50 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status } } + +/* Pure black magic, if you can't understand this code you are lucky.........*/ +void *SWITCH_THREAD_FUNC media_on_hold_thread_run(switch_thread_t *thread, void *obj) +{ + switch_core_session_t *other_session = NULL, *session = (switch_core_session_t *) obj; + const char *uuid; + + if (switch_core_session_read_lock(session) == SWITCH_STATUS_SUCCESS) { + switch_channel_t *channel = switch_core_session_get_channel(session); + private_object_t *tech_pvt = switch_core_session_get_private(session); + + if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE)) && (other_session = switch_core_session_locate(uuid))) { + if (switch_core_session_compare(session, other_session)) { + switch_set_flag_locked(tech_pvt, TFLAG_HOLD_LOCK); + switch_ivr_media(switch_core_session_get_uuid(other_session), SMF_REBRIDGE); + + if (tech_pvt->rtp_session) { + switch_rtp_clear_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_AUTOADJ); + } + + sofia_glue_toggle_hold(tech_pvt, 1); + switch_core_session_rwunlock(other_session); + } + } + + switch_core_session_rwunlock(session); + } + + return NULL; +} + +static void launch_media_on_hold(switch_core_session_t *session) +{ + switch_thread_t *thread; + switch_threadattr_t *thd_attr = NULL; + + switch_threadattr_create(&thd_attr, switch_core_session_get_pool(session)); + switch_threadattr_detach_set(thd_attr, 1); + switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE); + switch_threadattr_priority_increase(thd_attr); + switch_thread_create(&thread, thd_attr, media_on_hold_thread_run, session, switch_core_session_get_pool(session)); +} + + static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, char const *phrase, nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, @@ -2348,6 +2398,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, switch_ivr_uuid_bridge(br_a, br_b); switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER"); switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD); + switch_clear_flag_locked(tech_pvt, TFLAG_HOLD_LOCK); switch_channel_hangup(channel, SWITCH_CAUSE_ATTENDED_TRANSFER); } else { switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER_ERROR"); @@ -2377,6 +2428,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "RECEIVED_NOSDP"); sofia_glue_tech_choose_port(tech_pvt, 0); sofia_glue_set_local_sdp(tech_pvt, NULL, 0, NULL, 0); + switch_set_flag_locked(tech_pvt, TFLAG_3PCC); switch_channel_set_state(channel, CS_HIBERNATE); nua_respond(tech_pvt->nh, SIP_200_OK, SIPTAG_CONTACT_STR(tech_pvt->profile->url), @@ -2404,13 +2456,55 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, sdp_parser_t *parser; sdp_session_t *sdp; uint8_t match = 0, is_ok = 1; + tech_pvt->hold_laps = 0; if (r_sdp) { if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) { + if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE)) && (other_session = switch_core_session_locate(uuid))) { switch_core_session_message_t msg = { 0 }; + if (profile->media_options & MEDIA_OPT_MEDIA_ON_HOLD) { + tech_pvt->hold_laps = 1; + switch_channel_set_variable(channel, SWITCH_R_SDP_VARIABLE, r_sdp); + switch_channel_clear_flag(channel, CF_PROXY_MODE); + tech_pvt->local_sdp_str = NULL; + + if (!switch_channel_media_ready(channel)) { + if (!switch_channel_test_flag(tech_pvt->channel, CF_OUTBOUND)) { + //const char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE); + + tech_pvt->num_codecs = 0; + sofia_glue_tech_prepare_codecs(tech_pvt); + if (sofia_glue_tech_media(tech_pvt, r_sdp) != SWITCH_STATUS_SUCCESS) { + switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR"); + status = SWITCH_STATUS_FALSE; + goto done; + } + } + } + + if (!switch_rtp_ready(tech_pvt->rtp_session)) { + sofia_glue_tech_prepare_codecs(tech_pvt); + if ((status = sofia_glue_tech_choose_port(tech_pvt, 0)) != SWITCH_STATUS_SUCCESS) { + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + goto done; + } + } + sofia_glue_set_local_sdp(tech_pvt, NULL, 0, NULL, 1); + + nua_respond(tech_pvt->nh, SIP_200_OK, + SIPTAG_CONTACT_STR(tech_pvt->reply_contact), + SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str), + SOATAG_REUSE_REJECTED(1), + SOATAG_ORDERED_USER(1), SOATAG_AUDIO_AUX("cn telephone-event"), NUTAG_INCLUDE_EXTRA_SDP(1), TAG_END()); + launch_media_on_hold(session); + + switch_core_session_rwunlock(other_session); + goto done; + } + msg.message_id = SWITCH_MESSAGE_INDICATE_MEDIA_REDIRECT; msg.from = __FILE__; msg.string_arg = (char *) r_sdp; @@ -2559,7 +2653,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "RTP Error!\n"); switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); } - if (switch_channel_get_state(channel) == CS_HIBERNATE) { + if (switch_channel_get_state(channel) == CS_HIBERNATE && switch_test_flag(tech_pvt, TFLAG_3PCC)) { switch_set_flag_locked(tech_pvt, TFLAG_READY); switch_channel_set_state(channel, CS_INIT); switch_set_flag(tech_pvt, TFLAG_SDP); @@ -2800,25 +2894,33 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t switch_str_nil(br_b)); if (br_a && br_b) { - switch_core_session_t *new_b_session = NULL, *a_session = NULL; - + switch_core_session_t *new_b_session = NULL, *a_session = NULL, *tmp = NULL; + + if ((profile->media_options & MEDIA_OPT_BYPASS_AFTER_ATT_XFER) && (tmp = switch_core_session_locate(br_b))) { + switch_channel_t *tchannel = switch_core_session_get_channel(tmp); + switch_channel_set_variable(tchannel, SWITCH_BYPASS_MEDIA_AFTER_BRIDGE_VARIABLE, "true"); + switch_core_session_rwunlock(tmp); + } + switch_ivr_uuid_bridge(br_b, br_a); switch_channel_set_variable(channel_b, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER"); nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"), SIPTAG_EVENT_STR(etmp), TAG_END()); switch_clear_flag_locked(b_tech_pvt, TFLAG_SIP_HOLD); + switch_clear_flag_locked(tech_pvt, TFLAG_HOLD_LOCK); switch_ivr_park_session(b_session); new_b_session = switch_core_session_locate(br_b); a_session = switch_core_session_locate(br_a); sofia_info_send_sipfrag(a_session, new_b_session); + if (new_b_session) { switch_core_session_rwunlock(new_b_session); } + if (a_session) { switch_core_session_rwunlock(a_session); } - //switch_channel_hangup(channel_b, SWITCH_CAUSE_ATTENDED_TRANSFER); } else { if (!br_a && !br_b) { switch_set_flag_locked(tech_pvt, TFLAG_NOHUP); diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index 956948d1ca..8a6f4bbbfe 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -858,7 +858,7 @@ switch_status_t sofia_glue_tech_proxy_remote_addr(private_object_t *tech_pvt) } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "VIDEO RTP CHANGING DEST TO: [%s:%d]\n", tech_pvt->remote_sdp_video_ip, tech_pvt->remote_sdp_video_port); - if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) && + if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) && !switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) && !((val = switch_channel_get_variable(tech_pvt->channel, "disable_rtp_auto_adjust")) && switch_true(val))) { /* Reactivate the NAT buster flag. */ switch_rtp_set_flag(tech_pvt->video_rtp_session, SWITCH_RTP_FLAG_AUTOADJ); @@ -1749,12 +1749,18 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f } if (tech_pvt->rtp_session && switch_test_flag(tech_pvt, TFLAG_REINVITE)) { - const char *ip = switch_channel_get_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE); - const char *port = switch_channel_get_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE); - - if (ip && port && !strcmp(ip, tech_pvt->adv_sdp_audio_ip) && atoi(port) == tech_pvt->remote_sdp_audio_port) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Audio params are unchanged.\n"); + //const char *ip = switch_channel_get_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE); + //const char *port = switch_channel_get_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE); + char *remote_host = switch_rtp_get_remote_host(tech_pvt->rtp_session); + switch_port_t remote_port = switch_rtp_get_remote_port(tech_pvt->rtp_session); + + if (remote_host && remote_port && !strcmp(remote_host, tech_pvt->remote_sdp_audio_ip) && remote_port == tech_pvt->remote_sdp_audio_port) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Audio params are unchanged for %s.\n", switch_channel_get_name(tech_pvt->channel)); goto video; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Audio params changed for %s from %s:%d to %s:%d\n", + switch_channel_get_name(tech_pvt->channel), + remote_host, remote_port, tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port); } } @@ -1773,7 +1779,7 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f if (tech_pvt->rtp_session && switch_test_flag(tech_pvt, TFLAG_REINVITE)) { switch_clear_flag_locked(tech_pvt, TFLAG_REINVITE); - + if (switch_rtp_set_remote_address(tech_pvt->rtp_session, tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port, &err) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "AUDIO RTP REPORTS ERROR: [%s]\n", err); @@ -1944,7 +1950,7 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f sofia_glue_tech_choose_video_port(tech_pvt, 1); } - if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) && + if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) && !switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) && !((val = switch_channel_get_variable(tech_pvt->channel, "disable_rtp_auto_adjust")) && switch_true(val))) { flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_USE_TIMER | SWITCH_RTP_FLAG_AUTOADJ | SWITCH_RTP_FLAG_DATAWAIT | SWITCH_RTP_FLAG_NOBLOCK | SWITCH_RTP_FLAG_RAW_WRITE); @@ -2042,6 +2048,71 @@ switch_status_t sofia_glue_tech_media(private_object_t *tech_pvt, const char *r_ return SWITCH_STATUS_FALSE; } +void sofia_glue_toggle_hold(private_object_t *tech_pvt, int sendonly) +{ + if (sendonly && switch_channel_test_flag(tech_pvt->channel, CF_ANSWERED)) { + if (!switch_test_flag(tech_pvt, TFLAG_SIP_HOLD)) { + const char *stream; + + switch_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD); + switch_channel_presence(tech_pvt->channel, "unknown", "hold", NULL); + + if (tech_pvt->max_missed_hold_packets) { + switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, tech_pvt->max_missed_hold_packets); + } + + if (!(stream = switch_channel_get_variable(tech_pvt->channel, SWITCH_HOLD_MUSIC_VARIABLE))) { + stream = tech_pvt->profile->hold_music; + } + + if (stream && switch_is_moh(stream)) { + if (!strcasecmp(stream, "indicate_hold")) { + switch_channel_set_flag(tech_pvt->channel, CF_SUSPEND); + switch_channel_set_flag(tech_pvt->channel, CF_HOLD); + switch_ivr_hold_uuid(switch_channel_get_variable(tech_pvt->channel, SWITCH_SIGNAL_BOND_VARIABLE), NULL, 0); + } else { + switch_ivr_broadcast(switch_channel_get_variable(tech_pvt->channel, SWITCH_SIGNAL_BOND_VARIABLE), stream, SMF_ECHO_ALEG | SMF_LOOP); + switch_yield(250000); + } + } + } + } else { + if (switch_test_flag(tech_pvt, TFLAG_HOLD_LOCK)) { + switch_set_flag(tech_pvt, TFLAG_SIP_HOLD); + } + + switch_clear_flag_locked(tech_pvt, TFLAG_HOLD_LOCK); + + if (switch_test_flag(tech_pvt, TFLAG_SIP_HOLD)) { + const char *uuid; + switch_core_session_t *b_session; + + switch_yield(250000); + + if (tech_pvt->max_missed_packets) { + switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, tech_pvt->max_missed_packets); + } + + if ((uuid = switch_channel_get_variable(tech_pvt->channel, SWITCH_SIGNAL_BOND_VARIABLE)) && (b_session = switch_core_session_locate(uuid))) { + switch_channel_t *b_channel = switch_core_session_get_channel(b_session); + + if (switch_channel_test_flag(tech_pvt->channel, CF_HOLD)) { + switch_ivr_unhold(b_session); + switch_channel_clear_flag(tech_pvt->channel, CF_SUSPEND); + switch_channel_clear_flag(tech_pvt->channel, CF_HOLD); + } else { + switch_channel_stop_broadcast(b_channel); + switch_channel_wait_for_flag(b_channel, CF_BROADCAST, SWITCH_FALSE, 5000, NULL); + } + switch_core_session_rwunlock(b_session); + } + + switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD); + switch_channel_presence(tech_pvt->channel, "unknown", "unhold", NULL); + } + } +} + uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, sdp_session_t *sdp) { uint8_t match = 0; @@ -2093,60 +2164,9 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, sdp_session_t * } } - if (sendonly && switch_channel_test_flag(channel, CF_ANSWERED)) { - if (!switch_test_flag(tech_pvt, TFLAG_SIP_HOLD)) { - const char *stream; - - switch_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD); - switch_channel_presence(tech_pvt->channel, "unknown", "hold", NULL); - - if (tech_pvt->max_missed_hold_packets) { - switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, tech_pvt->max_missed_hold_packets); - } - - if (!(stream = switch_channel_get_variable(tech_pvt->channel, SWITCH_HOLD_MUSIC_VARIABLE))) { - stream = tech_pvt->profile->hold_music; - } - - if (stream && switch_is_moh(stream)) { - if (!strcasecmp(stream, "indicate_hold")) { - switch_channel_set_flag(tech_pvt->channel, CF_SUSPEND); - switch_channel_set_flag(tech_pvt->channel, CF_HOLD); - switch_ivr_hold_uuid(switch_channel_get_variable(tech_pvt->channel, SWITCH_SIGNAL_BOND_VARIABLE), NULL, 0); - } else { - switch_ivr_broadcast(switch_channel_get_variable(tech_pvt->channel, SWITCH_SIGNAL_BOND_VARIABLE), stream, SMF_ECHO_ALEG | SMF_LOOP); - switch_yield(250000); - } - } - } - } else { - if (switch_test_flag(tech_pvt, TFLAG_SIP_HOLD)) { - const char *uuid; - switch_core_session_t *b_session; - - switch_yield(250000); - - if (tech_pvt->max_missed_packets) { - switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, tech_pvt->max_missed_packets); - } - - if ((uuid = switch_channel_get_variable(tech_pvt->channel, SWITCH_SIGNAL_BOND_VARIABLE)) && (b_session = switch_core_session_locate(uuid))) { - switch_channel_t *b_channel = switch_core_session_get_channel(b_session); - - if (switch_channel_test_flag(tech_pvt->channel, CF_HOLD)) { - switch_ivr_unhold(b_session); - switch_channel_clear_flag(tech_pvt->channel, CF_SUSPEND); - switch_channel_clear_flag(tech_pvt->channel, CF_HOLD); - } else { - switch_channel_stop_broadcast(b_channel); - switch_channel_wait_for_flag(b_channel, CF_BROADCAST, SWITCH_FALSE, 5000, NULL); - } - switch_core_session_rwunlock(b_session); - } - - switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD); - switch_channel_presence(tech_pvt->channel, "unknown", "unhold", NULL); - } + if (!tech_pvt->hold_laps) { + tech_pvt->hold_laps++; + sofia_glue_toggle_hold(tech_pvt, sendonly); } for (m = sdp->sdp_media; m; m = m->m_next) { diff --git a/src/switch_ivr_bridge.c b/src/switch_ivr_bridge.c index 8730bc3c49..4b4a2a7990 100644 --- a/src/switch_ivr_bridge.c +++ b/src/switch_ivr_bridge.c @@ -103,8 +103,8 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj) switch_codec_t silence_codec = { 0 }; switch_frame_t silence_frame = { 0 }; int16_t silence_data[SWITCH_RECOMMENDED_BUFFER_SIZE/2] = { 0 }; - const char *silence_var; - int silence_val = 0; + const char *silence_var, *var; + int silence_val = 0, bypass_media_after_bridge = 0; #ifdef SWITCH_VIDEO_IN_THREADS struct vid_helper vh = { 0 }; uint32_t vid_launch = 0; @@ -114,7 +114,7 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj) if (!(session_b = switch_core_session_locate(data->b_uuid))) { return NULL; } - + input_callback = data->input_callback; user_data = data->session_data; stream_id = data->stream_id; @@ -141,6 +141,11 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj) goto end_of_bridge_loop; } + if ((var = switch_channel_get_variable(chan_a, SWITCH_BYPASS_MEDIA_AFTER_BRIDGE_VARIABLE)) && switch_true(var)) { + bypass_media_after_bridge = 1; + switch_channel_set_variable(chan_a, SWITCH_BYPASS_MEDIA_AFTER_BRIDGE_VARIABLE, NULL); + } + if ((silence_var = switch_channel_get_variable(chan_a, "bridge_generate_comfort_noise"))) { switch_codec_t *read_codec = NULL; @@ -234,6 +239,11 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj) } #endif + if (loop_count > 50 && bypass_media_after_bridge) { + switch_ivr_nomedia(switch_core_session_get_uuid(session_a), SMF_REBRIDGE); + bypass_media_after_bridge = 0; + } + /* if 1 channel has DTMF pass it to the other */ while (switch_channel_has_dtmf(chan_a)) { switch_dtmf_t dtmf = { 0, 0 }; diff --git a/src/switch_rtp.c b/src/switch_rtp.c index 05ccf70a90..024525fd8f 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -166,6 +166,7 @@ struct switch_rtp { char *ice_user; char *user_ice; char *timer_name; + char *remote_host_str; switch_time_t last_stun; uint32_t samples_per_interval; uint32_t conf_samples_per_interval; @@ -597,6 +598,17 @@ SWITCH_DECLARE(void) switch_rtp_set_max_missed_packets(switch_rtp_t *rtp_session rtp_session->max_missed_packets = max; } +SWITCH_DECLARE(char *) switch_rtp_get_remote_host(switch_rtp_t *rtp_session) +{ + return switch_strlen_zero(rtp_session->remote_host_str) ? "0.0.0.0" : rtp_session->remote_host_str; +} + +SWITCH_DECLARE(switch_port_t) switch_rtp_get_remote_port(switch_rtp_t *rtp_session) +{ + return rtp_session->remote_port; +} + + SWITCH_DECLARE(switch_status_t) switch_rtp_set_remote_address(switch_rtp_t *rtp_session, const char *host, switch_port_t port, const char **err) { switch_sockaddr_t *remote_addr; @@ -611,6 +623,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_remote_address(switch_rtp_t *rtp_ switch_mutex_lock(rtp_session->write_mutex); rtp_session->remote_addr = remote_addr; + rtp_session->remote_host_str = switch_core_strdup(rtp_session->pool, host); rtp_session->remote_port = port; if (rtp_session->sock_input &&