From 3922f9213a872e0674125d1af418824be26925b7 Mon Sep 17 00:00:00 2001 From: Renato Luiz Bracco Date: Wed, 16 Jul 2025 11:51:12 -0300 Subject: [PATCH] [FreeswitchCoreLib] bridge call with hangup_after_bridge=false We developed a Call Center application built on a PABX that uses Freeswitch as a Telecom stack. The bug occurs when an Attendant of the Call center is permannentely logged in a voice channel (ALeg). A CRM (Customer Relationship Management) stack that is part of the Call Center commands this PABX to make outbound calls to customers. These calls (one at a time - BLeg) will be bridge with the attendant's (ALeg) call. At the end of the call the connection with the customer (BLeg) is disconnected and the attendant's connection (ALeg) is kept since the variable hangup_after_bridge is set as false in the dialplan. The Call Center repeats this process for the next customers. The attendant's channel (ALeg) is kept continously up. Most of the time this setup works well but sometimes after 1500 calls received by the attendant its channel (ALeg) is wrongly hanged up by the Freeswitch so here is the bug. Studying your code I changed code in 2 points at the switch_ivr_bridge.c file and 1 at the switch_ivr_originate.c file that I think would fix this issue. 2 cases possible Problem occurs when two legs were bridged and the remote side in BLeg issues a BYE. Assume Bleg call completed , uuid_bridge issued , received BYE in BLeg with ALeg Transfer bit flag equal false , ALeg and BLeg in CS_SOFT_EXECUTE in the previous code ALeg channel call sometimes is hangedd up even with hangup_after_bridge set to false, our correction hangup channel only if hangup_after_bridge equal true or else it set ALeg call state to CS_EXECUTE see code changes in switch_ivr_bridge.c Problem occurs when two legs were bridged and the remote side in BLeg issues a BYE. Bleg call was complete , uuid_bridge issued , received BYE in BLeg when ALeg has Transfer flag bit value equal true. in the previous code ALeg channel call sometimes is hanged up even with hangup_after_bridge set to false, with our corretion hangup channel only if hangup_after_bridge equal true see code changes in switch_ivr_originate.c --- src/switch_ivr_bridge.c | 18 +++++++++++++----- src/switch_ivr_originate.c | 4 +++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/switch_ivr_bridge.c b/src/switch_ivr_bridge.c index 527058f70c0..7eac74adb23 100644 --- a/src/switch_ivr_bridge.c +++ b/src/switch_ivr_bridge.c @@ -1201,18 +1201,23 @@ static switch_status_t uuid_bridge_on_soft_execute(switch_core_session_t *sessio } switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE); - if (switch_ivr_wait_for_answer(session, other_session) != SWITCH_STATUS_SUCCESS) { + if (switch_true(switch_channel_get_variable(channel, "uuid_bridge_continue_on_cancel"))) { switch_channel_set_state(channel, CS_EXECUTE); } else if (switch_true(switch_channel_get_variable(channel, "uuid_bridge_park_on_cancel"))) { switch_ivr_park_session(session); - } else if (!switch_channel_test_flag(channel, CF_TRANSFER)) { - switch_channel_hangup(channel, SWITCH_CAUSE_ORIGINATOR_CANCEL); + } else if (switch_true(switch_channel_get_variable(channel, SWITCH_HANGUP_AFTER_BRIDGE_VARIABLE))) { /*++RLB */ + if (!switch_channel_test_flag(channel, CF_TRANSFER)) { + switch_channel_hangup(channel, SWITCH_CAUSE_ORIGINATOR_CANCEL); + } + } else { /*++RLB hangup_after_bridge false */ + switch_channel_set_state(channel, CS_EXECUTE); /*++RLB */ } goto done; } + ready_a = switch_channel_ready(channel); ready_b = switch_channel_ready(other_channel); @@ -1267,7 +1272,11 @@ static switch_status_t uuid_bridge_on_soft_execute(switch_core_session_t *sessio } if (hup) { - switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + if (switch_true(switch_channel_get_variable(channel, SWITCH_HANGUP_AFTER_BRIDGE_VARIABLE))) { /*++RLB */ + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + } else { /*++RLB */ + switch_channel_set_state(channel, CS_EXECUTE); /*++RLB */ + } /*++RLB */ } } @@ -2168,7 +2177,6 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_uuid_bridge(const char *originator_uu switch_channel_set_flag(originator_channel, CF_TRANSFER); switch_channel_set_flag(originatee_channel, CF_TRANSFER); - switch_channel_clear_flag(originator_channel, CF_ORIGINATING); switch_channel_clear_flag(originatee_channel, CF_ORIGINATING); diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c index 99c70991bde..a9464577d1e 100644 --- a/src/switch_ivr_originate.c +++ b/src/switch_ivr_originate.c @@ -1236,7 +1236,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_wait_for_answer(switch_core_session_t if (!switch_channel_media_ready(peer_channel)) { if (switch_channel_up_nosig(peer_channel)) { - switch_channel_hangup(peer_channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + if (switch_true(switch_channel_get_variable(peer_channel, SWITCH_HANGUP_AFTER_BRIDGE_VARIABLE))) { /*+++RLB*/ + switch_channel_hangup(peer_channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + } } status = SWITCH_STATUS_FALSE; }