diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 7113497a28..acee75bb92 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -128,6 +128,7 @@ SWITCH_BEGIN_EXTERN_C #define SWITCH_CHANNEL_EXECUTE_ON_RING_VARIABLE "execute_on_ring" #define SWITCH_CALL_TIMEOUT_VARIABLE "call_timeout" #define SWITCH_HOLDING_UUID_VARIABLE "holding_uuid" +#define SWITCH_SOFT_HOLDING_UUID_VARIABLE "soft_holding_uuid" #define SWITCH_API_BRIDGE_END_VARIABLE "api_after_bridge" #define SWITCH_API_HANGUP_HOOK_VARIABLE "api_hangup_hook" #define SWITCH_SESSION_IN_HANGUP_HOOK_VARIABLE "session_in_hangup_hook" @@ -869,7 +870,7 @@ typedef enum { CF_ANSWERED = 1, CF_OUTBOUND, CF_EARLY_MEDIA, - CF_ORIGINATOR, + CF_BRIDGE_ORIGINATOR, CF_TRANSFER, CF_ACCEPT_CNG, CF_REDIRECT, @@ -903,6 +904,8 @@ typedef enum { CF_REPORTING, CF_PARK, CF_TIMESTAMP_SET, + CF_ORIGINATOR, + CF_XFER_ZOMBIE, /* WARNING: DO NOT ADD ANY FLAGS BELOW THIS LINE */ CF_FLAG_MAX } switch_channel_flag_t; diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c index e1390e7503..29d47d8571 100644 --- a/src/mod/applications/mod_dptools/mod_dptools.c +++ b/src/mod/applications/mod_dptools/mod_dptools.c @@ -1533,7 +1533,7 @@ static switch_status_t xfer_on_dtmf(switch_core_session_t *session, void *input, switch_caller_extension_t *extension = NULL; const char *app = "three_way"; const char *app_arg = switch_core_session_get_uuid(session); - const char *holding = switch_channel_get_variable(channel, SWITCH_HOLDING_UUID_VARIABLE); + const char *holding = switch_channel_get_variable(channel, SWITCH_SOFT_HOLDING_UUID_VARIABLE); switch_core_session_t *b_session; if (holding && (b_session = switch_core_session_locate(holding))) { @@ -1603,8 +1603,8 @@ SWITCH_STANDARD_APP(att_xfer_function) bond = switch_core_session_strdup(session, bond); } - switch_channel_set_variable(channel, SWITCH_HOLDING_UUID_VARIABLE, bond); - + switch_channel_set_variable(channel, SWITCH_SOFT_HOLDING_UUID_VARIABLE, bond); + switch_channel_set_flag(channel, CF_XFER_ZOMBIE); if ((var = switch_channel_get_variable(channel, SWITCH_CALL_TIMEOUT_VARIABLE))) { timelimit = atoi(var); @@ -1654,7 +1654,8 @@ SWITCH_STANDARD_APP(att_xfer_function) switch_core_session_rwunlock(peer_session); end: - switch_channel_set_variable(channel, SWITCH_HOLDING_UUID_VARIABLE, NULL); + switch_channel_set_variable(channel, SWITCH_SOFT_HOLDING_UUID_VARIABLE, NULL); + switch_channel_clear_flag(channel, CF_XFER_ZOMBIE); } SWITCH_STANDARD_APP(read_function) @@ -1906,6 +1907,35 @@ SWITCH_STANDARD_APP(playback_function) } + + +SWITCH_STANDARD_APP(endless_playback_function) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_status_t status = SWITCH_STATUS_SUCCESS; + const char *file = data; + + while(switch_channel_ready(channel)) { + if ((status = switch_ivr_play_file(session, NULL, file, NULL)) == SWITCH_STATUS_NOTFOUND) { + break; + } + } + + switch (status) { + case SWITCH_STATUS_SUCCESS: + case SWITCH_STATUS_BREAK: + switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "FILE PLAYED"); + break; + case SWITCH_STATUS_NOTFOUND: + switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "FILE NOT FOUND"); + break; + default: + switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "PLAYBACK ERROR"); + break; + } + +} + SWITCH_STANDARD_APP(gentones_function) { char *tone_script = NULL; @@ -2791,6 +2821,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load) SWITCH_ADD_APP(app_interface, "park_state", "Park State", "Park State", park_state_function, "", SAF_NONE); SWITCH_ADD_APP(app_interface, "gentones", "Generate Tones", "Generate tones to the channel", gentones_function, "[|]", SAF_NONE); SWITCH_ADD_APP(app_interface, "playback", "Playback File", "Playback a file to the channel", playback_function, "", SAF_NONE); + SWITCH_ADD_APP(app_interface, "endless_playback", "Playback File Endlessly", "Endlessly Playback a file to the channel", + endless_playback_function, "", SAF_NONE); SWITCH_ADD_APP(app_interface, "att_xfer", "Attended Transfer", "Attended Transfer", att_xfer_function, "", SAF_NONE); SWITCH_ADD_APP(app_interface, "read", "Read Digits", "Read Digits", read_function, " ", SAF_NONE); SWITCH_ADD_APP(app_interface, "play_and_get_digits", "Play and get Digits", "Play and get Digits", diff --git a/src/mod/applications/mod_fifo/mod_fifo.c b/src/mod/applications/mod_fifo/mod_fifo.c index c6a8c8616b..698d3def53 100644 --- a/src/mod/applications/mod_fifo/mod_fifo.c +++ b/src/mod/applications/mod_fifo/mod_fifo.c @@ -89,7 +89,7 @@ static switch_status_t on_dtmf(switch_core_session_t *session, void *input, swit const char *consumer_exit_key = switch_channel_get_variable(channel, "fifo_consumer_exit_key"); - if (switch_channel_test_flag(switch_core_session_get_channel(session), CF_ORIGINATOR)) { + if (switch_channel_test_flag(switch_core_session_get_channel(session), CF_BRIDGE_ORIGINATOR)) { if ( consumer_exit_key && dtmf->digit == *consumer_exit_key ) { switch_channel_hangup(bchan, SWITCH_CAUSE_NORMAL_CLEARING); return SWITCH_STATUS_BREAK; diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 0ec3907df7..3a667a2ea0 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -4117,8 +4117,46 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t br_a = switch_channel_get_variable(channel_a, SWITCH_SIGNAL_BOND_VARIABLE); br_b = switch_channel_get_variable(channel_b, SWITCH_SIGNAL_BOND_VARIABLE); + + if (switch_channel_test_flag(channel_b, CF_ORIGINATOR)) { + switch_core_session_t *a_session; - if (br_a && br_b) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, + "Attended Transfer on originating session %s\n", switch_core_session_get_uuid(b_session)); + + + + switch_channel_set_variable(channel_b, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER"); + + + sofia_clear_flag_locked(b_tech_pvt, TFLAG_SIP_HOLD); + sofia_clear_flag_locked(tech_pvt, TFLAG_HOLD_LOCK); + + switch_channel_set_variable(channel_b, SWITCH_HOLDING_UUID_VARIABLE, br_a); + switch_channel_set_flag(channel_b, CF_XFER_ZOMBIE); + + if ((a_session = switch_core_session_locate(br_a))) { + const char *moh = profile->hold_music; + switch_channel_t *a_channel = switch_core_session_get_channel(a_session); + const char *tmp; + + if ((tmp = switch_channel_get_variable(a_channel, SWITCH_HOLD_MUSIC_VARIABLE))) { + moh = tmp; + } + //switch_channel_set_variable(a_channel, SWITCH_PARK_AFTER_BRIDGE_VARIABLE, "true"); + switch_channel_set_variable_printf(a_channel, SWITCH_TRANSFER_AFTER_BRIDGE_VARIABLE, "'endless_playback:%s':inline", moh); + //switch_channel_set_variable_printf(a_channel, "park_command", "moh"); + switch_core_session_rwunlock(a_session); + } + + 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_channel_set_variable(channel_b, "park_timeout", "2"); + //switch_channel_set_state(channel_b, CS_PARK); + + + } else if (br_a && br_b) { switch_core_session_t *new_b_session = NULL, *a_session = NULL, *tmp = NULL; switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Attended Transfer [%s][%s]\n", @@ -4138,8 +4176,9 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t sofia_clear_flag_locked(b_tech_pvt, TFLAG_SIP_HOLD); sofia_clear_flag_locked(tech_pvt, TFLAG_HOLD_LOCK); - switch_channel_set_variable(switch_core_session_get_channel(b_session), "park_timeout", "2"); - switch_channel_set_state(switch_core_session_get_channel(b_session), CS_PARK); + switch_channel_set_variable(channel_b, "park_timeout", "2"); + switch_channel_set_state(channel_b, CS_PARK); + new_b_session = switch_core_session_locate(br_b); a_session = switch_core_session_locate(br_a); diff --git a/src/switch_channel.c b/src/switch_channel.c index eb6b512211..707cec5fba 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -1706,10 +1706,11 @@ SWITCH_DECLARE(switch_channel_state_t) switch_channel_perform_hangup(switch_chan switch_channel_clear_flag(channel, CF_BLOCK_STATE); if (channel->state < CS_HANGUP) { - switch_channel_state_t last_state = channel->state; + switch_channel_state_t last_state; switch_event_t *event; switch_mutex_lock(channel->state_mutex); + last_state = channel->state; channel->state = CS_HANGUP; switch_mutex_unlock(channel->state_mutex); diff --git a/src/switch_ivr.c b/src/switch_ivr.c index 1f454db65e..52997dc06e 100644 --- a/src/switch_ivr.c +++ b/src/switch_ivr.c @@ -666,6 +666,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_park(switch_core_session_t *session, expires = switch_epoch_time_now(NULL) + timeout; } switch_channel_set_variable(channel, "park_timeout", NULL); + switch_channel_set_variable(channel, SWITCH_PARK_AFTER_BRIDGE_VARIABLE, NULL); } switch_channel_set_flag(channel, CF_CONTROLLED); @@ -1150,7 +1151,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_media(const char *uuid, switch_media_ if ((session = switch_core_session_locate(uuid))) { channel = switch_core_session_get_channel(session); - if ((flags & SMF_REBRIDGE) && !switch_channel_test_flag(channel, CF_ORIGINATOR)) { + if ((flags & SMF_REBRIDGE) && !switch_channel_test_flag(channel, CF_BRIDGE_ORIGINATOR)) { swap = 1; } @@ -1214,7 +1215,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_nomedia(const char *uuid, switch_medi status = SWITCH_STATUS_SUCCESS; channel = switch_core_session_get_channel(session); - if ((flags & SMF_REBRIDGE) && !switch_channel_test_flag(channel, CF_ORIGINATOR)) { + if ((flags & SMF_REBRIDGE) && !switch_channel_test_flag(channel, CF_BRIDGE_ORIGINATOR)) { swap = 1; } diff --git a/src/switch_ivr_bridge.c b/src/switch_ivr_bridge.c index 76793734e9..062c88cfa5 100644 --- a/src/switch_ivr_bridge.c +++ b/src/switch_ivr_bridge.c @@ -131,7 +131,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_ORIGINATOR))) { + 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); } @@ -478,7 +478,9 @@ static void transfer_after_bridge(switch_core_session_t *session, const char *wh int argc; char *argv[4] = { 0 }; char *mydata; - + + switch_channel_set_variable(switch_core_session_get_channel(session), SWITCH_TRANSFER_AFTER_BRIDGE_VARIABLE, NULL); + if (!switch_strlen_zero(where) && (mydata = switch_core_session_strdup(session, where))) { if ((argc = switch_separate_string(mydata, ':', argv, (sizeof(argv) / sizeof(argv[0])))) >= 1) { switch_ivr_session_transfer(session, argv[0], argv[1], argv[2]); @@ -583,7 +585,7 @@ static switch_status_t uuid_bridge_on_reset(switch_core_session_t *session) switch_channel_clear_flag(channel, CF_ORIGINATING); - if (switch_channel_test_flag(channel, CF_ORIGINATOR)) { + if (switch_channel_test_flag(channel, CF_BRIDGE_ORIGINATOR)) { switch_channel_set_state(channel, CS_SOFT_EXECUTE); } @@ -605,11 +607,11 @@ static switch_status_t uuid_bridge_on_soft_execute(switch_core_session_t *sessio switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CUSTOM SOFT_EXECUTE\n", switch_channel_get_name(channel)); switch_channel_clear_state_handler(channel, &uuid_bridge_state_handlers); - if (!switch_channel_test_flag(channel, CF_ORIGINATOR)) { + if (!switch_channel_test_flag(channel, CF_BRIDGE_ORIGINATOR)) { return SWITCH_STATUS_SUCCESS; } - switch_channel_clear_flag(channel, CF_ORIGINATOR); + switch_channel_clear_flag(channel, CF_BRIDGE_ORIGINATOR); if ((other_uuid = switch_channel_get_variable(channel, SWITCH_UUID_BRIDGE)) && (other_session = switch_core_session_locate(other_uuid))) { switch_channel_t *other_channel = switch_core_session_get_channel(other_session); @@ -731,8 +733,8 @@ static switch_status_t signal_bridge_on_hangup(switch_core_session_t *session) switch_core_session_rwunlock(other_session); } - if (switch_channel_test_flag(channel, CF_ORIGINATOR)) { - switch_channel_clear_flag(channel, CF_ORIGINATOR); + if (switch_channel_test_flag(channel, CF_BRIDGE_ORIGINATOR)) { + switch_channel_clear_flag(channel, CF_BRIDGE_ORIGINATOR); if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_UNBRIDGE) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(channel, event); switch_event_fire(&event); @@ -772,7 +774,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_signal_bridge(switch_core_session_t * switch_channel_set_variable(caller_channel, SWITCH_SIGNAL_BRIDGE_VARIABLE, switch_core_session_get_uuid(peer_session)); switch_channel_set_variable(peer_channel, SWITCH_SIGNAL_BRIDGE_VARIABLE, switch_core_session_get_uuid(session)); - switch_channel_set_flag(caller_channel, CF_ORIGINATOR); + switch_channel_set_flag(caller_channel, CF_BRIDGE_ORIGINATOR); switch_channel_clear_state_handler(caller_channel, NULL); switch_channel_clear_state_handler(peer_channel, NULL); @@ -837,7 +839,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_multi_threaded_bridge(switch_core_ses return switch_ivr_signal_bridge(session, peer_session); } - switch_channel_set_flag(caller_channel, CF_ORIGINATOR); + switch_channel_set_flag(caller_channel, CF_BRIDGE_ORIGINATOR); b_leg->session = peer_session; switch_copy_string(b_leg->b_uuid, switch_core_session_get_uuid(session), sizeof(b_leg->b_uuid)); @@ -962,7 +964,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_multi_threaded_bridge(switch_core_ses switch_channel_set_state(peer_channel, CS_EXCHANGE_MEDIA); audio_bridge_thread(NULL, (void *) a_leg); - switch_channel_clear_flag(caller_channel, CF_ORIGINATOR); + switch_channel_clear_flag(caller_channel, CF_BRIDGE_ORIGINATOR); while (switch_channel_get_state(peer_channel) == CS_EXCHANGE_MEDIA) { switch_cond_next(); @@ -1184,10 +1186,13 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_uuid_bridge(const char *originator_uu switch_channel_clear_flag(originatee_channel, CF_ORIGINATING); /* change the states and let the chips fall where they may */ + + switch_channel_set_variable(originator_channel, SWITCH_PARK_AFTER_BRIDGE_VARIABLE, NULL); + switch_channel_set_variable(originatee_channel, SWITCH_PARK_AFTER_BRIDGE_VARIABLE, NULL); switch_channel_clear_state_handler(originator_channel, NULL); switch_channel_clear_state_handler(originatee_channel, NULL); - switch_channel_set_state_flag(originator_channel, CF_ORIGINATOR); - switch_channel_clear_flag(originatee_channel, CF_ORIGINATOR); + switch_channel_set_state_flag(originator_channel, CF_BRIDGE_ORIGINATOR); + switch_channel_clear_flag(originatee_channel, CF_BRIDGE_ORIGINATOR); switch_channel_add_state_handler(originator_channel, &uuid_bridge_state_handlers); switch_channel_add_state_handler(originatee_channel, &uuid_bridge_state_handlers); diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c index 79f8352a58..2c54513d32 100644 --- a/src/switch_ivr_originate.c +++ b/src/switch_ivr_originate.c @@ -118,6 +118,7 @@ typedef struct { typedef enum { + IDX_KEY_CANCEL = -4, IDX_TIMEOUT = -3, IDX_CANCEL = -2, IDX_NADA = -1 @@ -661,9 +662,14 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_wait_for_answer(switch_core_session_t const char *var; switch_time_t start = 0; const char *cancel_key = NULL; + switch_channel_state_t wait_state = 0; switch_assert(peer_channel); + if (switch_channel_get_state(peer_channel) == CS_RESET) { + switch_channel_set_state(peer_channel, CS_SOFT_EXECUTE); + } + if (session) { caller_channel = switch_core_session_get_channel(session); } @@ -810,8 +816,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_wait_for_answer(switch_core_session_t no_ringback: - while (switch_channel_ready(peer_channel) - && !(switch_channel_test_flag(peer_channel, CF_ANSWERED) || switch_channel_test_flag(peer_channel, CF_EARLY_MEDIA))) { + if (caller_channel) { + wait_state = switch_channel_get_state(caller_channel); + } + + while (switch_channel_ready(peer_channel) && !switch_channel_media_ready(peer_channel)) { int diff = (int) (switch_micro_time_now() - start); if (caller_channel && cancel_key) { @@ -826,6 +835,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_wait_for_answer(switch_core_session_t } } + if (caller_channel && switch_channel_get_state(caller_channel) != wait_state) { + goto done; + } + if (diff > timelimit) { status = SWITCH_STATUS_TIMEOUT; goto done; @@ -918,7 +931,18 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_wait_for_answer(switch_core_session_t end: - return (!caller_channel || switch_channel_ready(caller_channel)) ? status : SWITCH_STATUS_FALSE; + if (!switch_channel_media_ready(peer_channel)) { + if (switch_channel_up(peer_channel)) { + switch_channel_hangup(peer_channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + } + status = SWITCH_STATUS_FALSE; + } + + if (caller_channel && !switch_channel_ready(caller_channel)) { + status = SWITCH_STATUS_FALSE; + } + + return status; } SWITCH_DECLARE(void) switch_process_import(switch_core_session_t *session, switch_channel_t *peer_channel, const char *varname) @@ -945,6 +969,12 @@ SWITCH_DECLARE(void) switch_process_import(switch_core_session_t *session, switc } +#define peer_eligible(_peer) (_peer && !(switch_channel_test_flag(_peer, CF_TRANSFER) || \ + switch_channel_test_flag(_peer, CF_REDIRECT) || \ + switch_channel_test_flag(_peer, CF_BRIDGED) || \ + switch_channel_get_state(_peer) == CS_RESET || \ + !switch_channel_test_flag(_peer, CF_ORIGINATING))) + #define MAX_PEERS 128 SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *session, switch_core_session_t **bleg, @@ -981,6 +1011,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess uint8_t pass = 0; char *odata, *var; switch_call_cause_t reason = SWITCH_CAUSE_NONE; + switch_call_cause_t force_reason = SWITCH_CAUSE_NONE; uint8_t to = 0; char *var_val, *vars = NULL; int var_block_count = 0; @@ -998,9 +1029,12 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess int cdr_total = 0; int local_clobber = 0; const char *cancel_key = NULL; + const char *holding = NULL; + switch_channel_state_t wait_state = 0; if (session) { caller_channel = switch_core_session_get_channel(session); + switch_channel_set_flag(caller_channel, CF_ORIGINATOR); oglobals.session = session; if (switch_true(switch_channel_get_variable(caller_channel, SWITCH_PROXY_MEDIA_VARIABLE))) { @@ -1925,7 +1959,13 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess oglobals.early_ok = 0; } #endif - while ((!caller_channel || switch_channel_ready(caller_channel)) && check_channel_status(&oglobals, originate_status, and_argc)) { + + if (caller_channel) { + wait_state = switch_channel_get_state(caller_channel); + } + + while ((!caller_channel || switch_channel_ready(caller_channel) || switch_channel_test_flag(caller_channel, CF_XFER_ZOMBIE)) && + check_channel_status(&oglobals, originate_status, and_argc)) { time_t elapsed = switch_epoch_time_now(NULL) - start; if (caller_channel && !oglobals.sent_ring && oglobals.ring_ready && !oglobals.return_ring_ready) { switch_channel_ring_ready(caller_channel); @@ -1939,6 +1979,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess switch_ivr_parse_all_events(oglobals.session); } + if (caller_channel && switch_channel_get_state(caller_channel) != wait_state && !switch_channel_test_flag(caller_channel, CF_XFER_ZOMBIE)) { + oglobals.idx = IDX_NADA; + goto notready; + } + if (!oglobals.sent_ring && !oglobals.progress && (progress_timelimit_sec && elapsed > (time_t) progress_timelimit_sec)) { oglobals.idx = IDX_TIMEOUT; goto notready; @@ -1991,9 +2036,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess if (oglobals.session && !switch_channel_test_flag(caller_channel, CF_PROXY_MODE) && !switch_channel_test_flag(caller_channel, CF_PROXY_MEDIA) && + !switch_channel_test_flag(caller_channel, CF_XFER_ZOMBIE) && (ringback_data || (switch_channel_test_flag(caller_channel, CF_ANSWERED) || switch_channel_test_flag(caller_channel, CF_EARLY_MEDIA)))) { - + switch_status_t tstatus = SWITCH_STATUS_SUCCESS; int silence = 0; @@ -2002,7 +2048,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess switch_dtmf_t dtmf = { 0, 0 }; if (switch_channel_dequeue_dtmf(caller_channel, &dtmf) == SWITCH_STATUS_SUCCESS) { if (dtmf.digit == *cancel_key) { - oglobals.idx = IDX_CANCEL; + oglobals.idx = IDX_KEY_CANCEL; goto notready; } } @@ -2079,6 +2125,17 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess notready: + if (caller_channel) { + const char *soft_holding = switch_channel_get_variable(caller_channel, SWITCH_SOFT_HOLDING_UUID_VARIABLE); + holding = switch_channel_get_variable(caller_channel, SWITCH_HOLDING_UUID_VARIABLE); + switch_channel_set_variable(caller_channel, SWITCH_HOLDING_UUID_VARIABLE, NULL); + + if (soft_holding && switch_channel_test_flag(caller_channel, CF_XFER_ZOMBIE)) { + holding = soft_holding; + switch_channel_set_variable(caller_channel, SWITCH_SOFT_HOLDING_UUID_VARIABLE, NULL); + } + } + if (caller_channel && !switch_channel_ready(caller_channel)) { oglobals.idx = IDX_CANCEL; } @@ -2088,26 +2145,86 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess switch_core_session_reset(oglobals.session, SWITCH_FALSE, SWITCH_TRUE); } + if ((oglobals.idx == IDX_TIMEOUT || oglobals.idx == IDX_KEY_CANCEL) && switch_channel_ready(caller_channel)) { + holding = NULL; + } + + if (holding) { + if (oglobals.idx > IDX_NADA) { + peer_session = originate_status[oglobals.idx].peer_session; + peer_channel = originate_status[oglobals.idx].peer_channel; + originate_status[oglobals.idx].peer_channel = NULL; + } else if (and_argc == 1) { + peer_session = originate_status[0].peer_session; + peer_channel = originate_status[0].peer_channel; + originate_status[0].peer_channel = NULL; + } else { + for (i = 0; i < and_argc; i++) { + if (!peer_eligible(originate_status[i].peer_channel)) { + continue; + } + if (switch_channel_media_ready(originate_status[i].peer_channel)) { + peer_session = originate_status[i].peer_session; + peer_channel = originate_status[i].peer_channel; + originate_status[i].peer_channel = NULL; + goto end_search; + } + } + for (i = 0; i < and_argc; i++) { + if (!peer_eligible(originate_status[i].peer_channel)) { + continue; + } + if (switch_channel_up(originate_status[i].peer_channel)) { + peer_session = originate_status[i].peer_session; + peer_channel = originate_status[i].peer_channel; + originate_status[i].peer_channel = NULL; + break; + } + } + } + + end_search: + + + if (peer_channel && switch_channel_ready(peer_channel)) { + force_reason = SWITCH_CAUSE_ATTENDED_TRANSFER; + switch_ivr_uuid_bridge(holding, switch_core_session_get_uuid(peer_session)); + oglobals.idx = IDX_NADA; + if (caller_channel) { + switch_channel_hangup(caller_channel, SWITCH_CAUSE_ATTENDED_TRANSFER); + } + switch_core_session_rwunlock(peer_session); + } else { + switch_core_session_t *holding_session; + + if ((holding_session = switch_core_session_locate(holding))) { + switch_channel_t *holding_channel = switch_core_session_get_channel(holding_session); + if (caller_channel && switch_channel_ready(caller_channel)) { + switch_ivr_uuid_bridge(holding, switch_core_session_get_uuid(session)); + } else { + switch_channel_hangup(holding_channel, SWITCH_CAUSE_NORMAL_UNSPECIFIED); + } + switch_core_session_rwunlock(holding_session); + } + } + + peer_session = NULL; + peer_channel = NULL; + + } + + for (i = 0; i < and_argc; i++) { - if (!originate_status[i].peer_channel) { + if (!peer_eligible(originate_status[i].peer_channel)) { continue; } - - //switch_channel_clear_flag(originate_status[i].peer_channel, CF_BLOCK_STATE); - - if (switch_channel_test_flag(originate_status[i].peer_channel, CF_TRANSFER) - || switch_channel_test_flag(originate_status[i].peer_channel, CF_REDIRECT) - || switch_channel_test_flag(originate_status[i].peer_channel, CF_BRIDGED) || - switch_channel_get_state(originate_status[i].peer_channel) == CS_RESET || - !switch_channel_test_flag(originate_status[i].peer_channel, CF_ORIGINATING) - ) { - continue; - } - + if (i != oglobals.idx) { - const char *holding = NULL; + holding = NULL; - if (oglobals.idx == IDX_TIMEOUT || to) { + if (force_reason != SWITCH_CAUSE_NONE) { + reason = force_reason; + } else if (oglobals.idx == IDX_TIMEOUT || to) { reason = SWITCH_CAUSE_NO_ANSWER; } else { if (oglobals.idx == IDX_CANCEL) { @@ -2122,19 +2239,19 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess } if (switch_channel_up(originate_status[i].peer_channel)) { if (caller_channel && i == 0) { - holding = switch_channel_get_variable(caller_channel, SWITCH_HOLDING_UUID_VARIABLE); - switch_channel_set_variable(caller_channel, SWITCH_HOLDING_UUID_VARIABLE, NULL); - } - if (holding && oglobals.idx != IDX_TIMEOUT && oglobals.idx != IDX_CANCEL) { - switch_ivr_uuid_bridge(holding, switch_core_session_get_uuid(originate_status[i].peer_session)); - } else { + holding = switch_channel_get_variable(caller_channel, SWITCH_SOFT_HOLDING_UUID_VARIABLE); + switch_channel_set_variable(caller_channel, SWITCH_SOFT_HOLDING_UUID_VARIABLE, NULL); + } + + if (holding && oglobals.idx != IDX_TIMEOUT && oglobals.idx != IDX_KEY_CANCEL) { + switch_ivr_uuid_bridge(holding, switch_core_session_get_uuid(originate_status[i].peer_session)); + } else { switch_channel_hangup(originate_status[i].peer_channel, reason); } } } } - - + if (oglobals.idx > IDX_NADA) { peer_session = originate_status[oglobals.idx].peer_session; peer_channel = originate_status[oglobals.idx].peer_channel; @@ -2384,6 +2501,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess switch_safe_free(write_frame.data); switch_safe_free(fail_on_single_reject_var); + if (caller_channel) { + switch_channel_clear_flag(caller_channel, CF_ORIGINATOR); + switch_channel_clear_flag(caller_channel, CF_XFER_ZOMBIE); + } + return status; }