From 69120105ee32400e0654ef2921f52f33f2a3b85e Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Sat, 5 Jan 2008 01:03:08 +0000 Subject: [PATCH] support crazy transfer crap git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@7083 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- conf/sip_profiles/default.xml | 2 +- src/include/switch_ivr.h | 1 + src/include/switch_types.h | 4 +- src/mod/endpoints/mod_sofia/mod_sofia.c | 1 + src/switch_core_state_machine.c | 7 +- src/switch_ivr.c | 2 + src/switch_ivr_bridge.c | 66 ++++- src/switch_ivr_originate.c | 321 +++++++++++++++++++++++- 8 files changed, 382 insertions(+), 22 deletions(-) diff --git a/conf/sip_profiles/default.xml b/conf/sip_profiles/default.xml index cd2cc6ad6c..8c8ac20ede 100644 --- a/conf/sip_profiles/default.xml +++ b/conf/sip_profiles/default.xml @@ -32,7 +32,7 @@ - + diff --git a/src/include/switch_ivr.h b/src/include/switch_ivr.h index be6125ee6e..748dc50c10 100644 --- a/src/include/switch_ivr.h +++ b/src/include/switch_ivr.h @@ -727,6 +727,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_phrase_macro(switch_core_session_t *s SWITCH_DECLARE(void) switch_ivr_delay_echo(switch_core_session_t *session, uint32_t delay_ms); SWITCH_DECLARE(void) switch_ivr_intercept_session(switch_core_session_t *session, const char *uuid); SWITCH_DECLARE(void) switch_ivr_park_session(switch_core_session_t *session); +SWITCH_DECLARE(switch_status_t) switch_ivr_wait_for_answer(switch_core_session_t *session, switch_core_session_t *peer_session); /** @} */ diff --git a/src/include/switch_types.h b/src/include/switch_types.h index c80271b84e..0bc1b0e602 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -628,6 +628,7 @@ CF_UNICAST = (1 << 21) - Channel has a unicast connection CF_VIDEO = (1 << 22) - Channel has video CF_EVENT_LOCK = (1 << 23) - Don't parse events CF_RESET = (1 << 24) - Tell extension parser to reset +CF_ORIGINATING = (1 << 25) - Channel is originating */ @@ -656,7 +657,8 @@ typedef enum { CF_UNICAST = (1 << 21), CF_VIDEO = (1 << 22), CF_EVENT_LOCK = (1 << 23), - CF_RESET = (1 << 24) + CF_RESET = (1 << 24), + CF_ORIGINATING = (1 << 25) } 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 eaf4a6e2e7..497a809182 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -1685,6 +1685,7 @@ static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session switch_channel_set_variable(nchannel, "sip_destination_url", tech_pvt->dest); caller_profile = switch_caller_profile_clone(nsession, outbound_profile); + caller_profile->destination_number = switch_core_strdup(caller_profile->pool, dest); switch_channel_set_caller_profile(nchannel, caller_profile); switch_channel_set_flag(nchannel, CF_OUTBOUND); switch_set_flag_locked(tech_pvt, TFLAG_OUTBOUND); diff --git a/src/switch_core_state_machine.c b/src/switch_core_state_machine.c index 3492c327a9..7f96c4007c 100644 --- a/src/switch_core_state_machine.c +++ b/src/switch_core_state_machine.c @@ -132,7 +132,7 @@ static void switch_core_standard_on_execute(switch_core_session_t *session) char *expanded = NULL; int nomedia = 0; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Execute %s(%s)\n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Execute %s(%s)\n", switch_channel_get_name(session->channel), extension->current_application->application_name, switch_str_nil(extension->current_application->application_data)); if ((application_interface = switch_loadable_module_get_application_interface(extension->current_application->application_name)) == 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Application %s\n", extension->current_application->application_name); @@ -156,8 +156,9 @@ static void switch_core_standard_on_execute(switch_core_session_t *session) if ((expanded = switch_channel_expand_variables(session->channel, extension->current_application->application_data)) != extension->current_application->application_data) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Expanded String %s(%s)\n", extension->current_application->application_name, - expanded); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Expanded String %s(%s)\n", switch_channel_get_name(session->channel), + extension->current_application->application_name, expanded); + } if (switch_channel_get_variable(session->channel, "presence_id")) { diff --git a/src/switch_ivr.c b/src/switch_ivr.c index 8e1afd431b..8db7e81c5e 100644 --- a/src/switch_ivr.c +++ b/src/switch_ivr.c @@ -852,6 +852,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_session_transfer(switch_core_session_ channel = switch_core_session_get_channel(session); switch_assert(channel != NULL); + switch_channel_clear_flag(channel, CF_ORIGINATING); + /* clear all state handlers */ switch_channel_clear_state_handler(channel, NULL); diff --git a/src/switch_ivr_bridge.c b/src/switch_ivr_bridge.c index 9ea6970067..539c0be2dd 100644 --- a/src/switch_ivr_bridge.c +++ b/src/switch_ivr_bridge.c @@ -596,7 +596,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_multi_threaded_bridge(switch_core_ses switch_channel_answer(caller_channel); } - if (switch_channel_test_flag(peer_channel, CF_ANSWERED) || switch_channel_test_flag(peer_channel, CF_EARLY_MEDIA)) { + if (switch_channel_test_flag(peer_channel, CF_ANSWERED) || switch_channel_test_flag(peer_channel, CF_EARLY_MEDIA) || + switch_channel_test_flag(peer_channel, CF_RING_READY)) { switch_event_t *event; switch_core_session_message_t msg = { 0 }; const switch_application_interface_t *application_interface; @@ -627,7 +628,29 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_multi_threaded_bridge(switch_core_ses } } - + if (!(switch_channel_test_flag(peer_channel, CF_ANSWERED) || switch_channel_test_flag(peer_channel, CF_EARLY_MEDIA))) { + if ((status = switch_ivr_wait_for_answer(session, peer_session)) != SWITCH_STATUS_SUCCESS) { + switch_channel_state_t w_state = switch_channel_get_state(caller_channel); + switch_channel_hangup(peer_channel, SWITCH_CAUSE_ALLOTTED_TIMEOUT); + if (w_state < CS_HANGUP && w_state != CS_RING && w_state != CS_PARK && !switch_channel_test_flag(caller_channel, CF_TRANSFER) && + w_state != CS_EXECUTE) { + const char *ext = switch_channel_get_variable(peer_channel, "original_destination_number"); + if (!ext) { + ext = switch_channel_get_variable(peer_channel, "destination_number"); + } + + if (ext) { + switch_ivr_session_transfer(session, ext, NULL, NULL); + } else { + switch_channel_hangup(caller_channel, SWITCH_CAUSE_ALLOTTED_TIMEOUT); + } + } + switch_core_session_rwunlock(peer_session); + goto done; + } + } + + msg.message_id = SWITCH_MESSAGE_INDICATE_BRIDGE; msg.from = __FILE__; msg.string_arg = switch_core_session_strdup(peer_session, switch_core_session_get_uuid(session)); @@ -707,8 +730,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_multi_threaded_bridge(switch_core_ses SWITCH_DECLARE(switch_status_t) switch_ivr_uuid_bridge(const char *originator_uuid, const char *originatee_uuid) { - switch_core_session_t *originator_session, *originatee_session; - switch_channel_t *originator_channel, *originatee_channel; + switch_core_session_t *originator_session, *originatee_session, *swap_session; + switch_channel_t *originator_channel, *originatee_channel, *swap_channel; switch_status_t status = SWITCH_STATUS_FALSE; switch_caller_profile_t *cp, *originator_cp, *originatee_cp; @@ -717,6 +740,23 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_uuid_bridge(const char *originator_uu originator_channel = switch_core_session_get_channel(originator_session); originatee_channel = switch_core_session_get_channel(originatee_session); + if (!switch_channel_test_flag(originator_channel, CF_ANSWERED)) { + if (switch_channel_test_flag(originatee_channel, CF_ANSWERED)) { + swap_session = originator_session; + originator_session = originatee_session; + originatee_session = swap_session; + + swap_channel = originator_channel; + originator_channel = originatee_channel; + originatee_channel = swap_channel; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "reversing order of channels so this will work!\n"); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Neither channel is answered, cannot bridge them.\n"); + return SWITCH_STATUS_FALSE; + } + } + + /* override transmit state for originator_channel to bridge to originatee_channel * install pointer to originatee_session into originator_channel * set CF_TRANSFER on both channels and change state to CS_TRANSMIT to @@ -726,12 +766,13 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_uuid_bridge(const char *originator_uu switch_channel_clear_state_handler(originator_channel, NULL); switch_channel_clear_state_handler(originatee_channel, NULL); - switch_channel_set_flag(originator_channel, CF_ORIGINATOR); + switch_channel_set_state_flag(originator_channel, CF_ORIGINATOR); switch_channel_clear_flag(originatee_channel, CF_ORIGINATOR); switch_channel_add_state_handler(originator_channel, &uuid_bridge_state_handlers); switch_channel_add_state_handler(originatee_channel, &uuid_bridge_state_handlers); switch_channel_set_variable(originator_channel, SWITCH_UUID_BRIDGE, switch_core_session_get_uuid(originatee_session)); + switch_channel_set_variable(originator_channel, SWITCH_BRIDGE_CHANNEL_VARIABLE, switch_channel_get_name(originatee_channel)); switch_channel_set_variable(originator_channel, SWITCH_BRIDGE_UUID_VARIABLE, switch_core_session_get_uuid(originatee_session)); @@ -743,6 +784,16 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_uuid_bridge(const char *originator_uu originator_cp = switch_channel_get_caller_profile(originator_channel); originatee_cp = switch_channel_get_caller_profile(originatee_channel); + + + switch_channel_set_variable(originatee_channel, "original_destination_number", originatee_cp->destination_number); + switch_channel_set_variable(originatee_channel, "original_caller_id_name", originatee_cp->caller_id_name); + switch_channel_set_variable(originatee_channel, "original_caller_id_number", originatee_cp->caller_id_number); + + switch_channel_set_variable(originator_channel, "original_destination_number", originator_cp->destination_number); + switch_channel_set_variable(originator_channel, "original_caller_id_name", originator_cp->caller_id_name); + switch_channel_set_variable(originator_channel, "original_caller_id_number", originator_cp->caller_id_number); + cp = switch_caller_profile_clone(originatee_session, originatee_cp); cp->destination_number = switch_core_strdup(cp->pool, originator_cp->caller_id_number); @@ -750,7 +801,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_uuid_bridge(const char *originator_uu cp->caller_id_name = switch_core_strdup(cp->pool, originator_cp->caller_id_name); switch_channel_set_caller_profile(originatee_channel, cp); switch_channel_set_originator_caller_profile(originatee_channel, switch_caller_profile_clone(originatee_session, originator_cp)); - + cp = switch_caller_profile_clone(originator_session, originator_cp); cp->destination_number = switch_core_strdup(cp->pool, originatee_cp->caller_id_number); cp->caller_id_number = switch_core_strdup(cp->pool, originatee_cp->caller_id_number); @@ -763,6 +814,9 @@ 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); /* change the states and let the chips fall where they may */ switch_channel_set_state(originator_channel, CS_RESET); diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c index 68455a87d6..117912f36b 100644 --- a/src/switch_ivr_originate.c +++ b/src/switch_ivr_originate.c @@ -165,13 +165,19 @@ static uint8_t check_channel_status(switch_channel_t **peer_channels, *idx = IDX_NADA; for (i = 0; i < len; i++) { + switch_channel_state_t state; if (!peer_channels[i]) { continue; } if (!*ring_ready && switch_channel_test_flag(peer_channels[i], CF_RING_READY)) { *ring_ready = 1; } - if (switch_channel_get_state(peer_channels[i]) >= CS_HANGUP) { + + state = switch_channel_get_state(peer_channels[i]); + if (state >= CS_HANGUP || state == CS_RESET || switch_channel_test_flag(peer_channels[i], CF_TRANSFER) || + switch_channel_test_flag(peer_channels[i], CF_BRIDGED) || + !switch_channel_test_flag(peer_channels[i], CF_ORIGINATING) + ) { (*hups)++; } else if ((switch_channel_test_flag(peer_channels[i], CF_ANSWERED) || (early_ok && len == 1 && switch_channel_test_flag(peer_channels[i], CF_EARLY_MEDIA))) && @@ -233,6 +239,284 @@ static int teletone_handler(teletone_generation_session_t * ts, teletone_tone_ma return 0; } + +SWITCH_DECLARE(switch_status_t) switch_ivr_wait_for_answer(switch_core_session_t *session, switch_core_session_t *peer_session) +{ + switch_channel_t *caller_channel; + switch_channel_t *peer_channel; + const char *ringback_data = NULL; + switch_frame_t write_frame = { 0 }; + switch_codec_t write_codec = { 0 }; + switch_codec_t *read_codec = NULL; + uint8_t pass = 0; + ringback_t ringback = { 0 }; + switch_core_session_message_t *message = NULL; + switch_frame_t *read_frame = NULL; + switch_status_t status = SWITCH_STATUS_SUCCESS; + uint8_t abuf[1024]; + int timelimit = 60; + const char *var; + switch_time_t start = 0; + + caller_channel = switch_core_session_get_channel(session); + peer_channel = switch_core_session_get_channel(peer_session); + + switch_assert(caller_channel && peer_channel); + + if ((var = switch_channel_get_variable(caller_channel, "call_timeout"))) { + timelimit = atoi(var); + if (timelimit < 0) { + timelimit = 60; + } + } + + timelimit *= 1000000; + start = switch_timestamp_now(); + + if ((switch_channel_test_flag(peer_channel, CF_ANSWERED) || switch_channel_test_flag(peer_channel, CF_EARLY_MEDIA))) { + return SWITCH_STATUS_SUCCESS; + } + + read_codec = switch_core_session_get_read_codec(session); + + if (switch_channel_test_flag(caller_channel, CF_ANSWERED) || switch_channel_test_flag(caller_channel, CF_EARLY_MEDIA)) { + ringback_data = switch_channel_get_variable(caller_channel, "transfer_ringback"); + } + + if (!ringback_data) { + ringback_data = switch_channel_get_variable(caller_channel, "ringback"); + } + + switch_channel_set_variable(caller_channel, "originate_disposition", "failure"); + + + if (ringback_data) { + char *tmp_data = NULL; + ringback_t ringback = { 0 }; + + switch_buffer_create_dynamic(&ringback.audio_buffer, 512, 1024, 0); + switch_buffer_set_loops(ringback.audio_buffer, -1); + + if (switch_is_file_path(ringback_data)) { + char *ext; + + if (strrchr(ringback_data, '.') || strstr(ringback_data, SWITCH_URL_SEPARATOR)) { + switch_core_session_set_read_codec(session, &write_codec); + } else { + ringback.asis++; + write_frame.codec = read_codec; + ext = read_codec->implementation->iananame; + tmp_data = switch_mprintf("%s.%s", ringback_data, ext); + ringback_data = tmp_data; + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Play Ringback File [%s]\n", ringback_data); + + ringback.fhb.channels = read_codec->implementation->number_of_channels; + ringback.fhb.samplerate = read_codec->implementation->actual_samples_per_second; + if (switch_core_file_open(&ringback.fhb, + ringback_data, + read_codec->implementation->number_of_channels, + read_codec->implementation->actual_samples_per_second, + SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, + switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Playing File\n"); + switch_safe_free(tmp_data); + goto done; + } + ringback.fh = &ringback.fhb; + + + } else { + teletone_init_session(&ringback.ts, 0, teletone_handler, &ringback); + ringback.ts.rate = read_codec->implementation->actual_samples_per_second; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Play Ringback Tone [%s]\n", ringback_data); + //ringback.ts.debug = 1; + //ringback.ts.debug_stream = switch_core_get_console(); + if (teletone_run(&ringback.ts, ringback_data)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Playing Tone\n"); + teletone_destroy_session(&ringback.ts); + switch_buffer_destroy(&ringback.audio_buffer); + ringback_data = NULL; + } + } + switch_safe_free(tmp_data); + + } + + + if (ringback_data && !switch_channel_test_flag(caller_channel, CF_ANSWERED) && !switch_channel_test_flag(caller_channel, CF_EARLY_MEDIA)) { + switch_channel_pre_answer(caller_channel); + } + + if ((read_codec = switch_core_session_get_read_codec(session)) && (ringback_data || !switch_channel_test_flag(caller_channel, CF_BYPASS_MEDIA))) { + if (!(pass = (uint8_t) switch_test_flag(read_codec, SWITCH_CODEC_FLAG_PASSTHROUGH))) { + if (switch_core_codec_init(&write_codec, + "L16", + NULL, + read_codec->implementation->actual_samples_per_second, + read_codec->implementation->microseconds_per_frame / 1000, + 1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, + switch_core_session_get_pool(session)) == SWITCH_STATUS_SUCCESS) { + + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "Raw Codec Activation Success L16@%uhz 1 channel %dms\n", + read_codec->implementation->actual_samples_per_second, read_codec->implementation->microseconds_per_frame / 1000); + write_frame.data = abuf; + write_frame.buflen = sizeof(abuf); + + write_frame.codec = &write_codec; + write_frame.datalen = read_codec->implementation->bytes_per_frame; + write_frame.samples = write_frame.datalen / 2; + memset(write_frame.data, 255, write_frame.datalen); + + if (ringback_data) { + char *tmp_data = NULL; + + switch_buffer_create_dynamic(&ringback.audio_buffer, 512, 1024, 0); + switch_buffer_set_loops(ringback.audio_buffer, -1); + + if (switch_is_file_path(ringback_data)) { + char *ext; + + if (strrchr(ringback_data, '.') || strstr(ringback_data, SWITCH_URL_SEPARATOR)) { + switch_core_session_set_read_codec(session, &write_codec); + } else { + ringback.asis++; + write_frame.codec = read_codec; + ext = read_codec->implementation->iananame; + tmp_data = switch_mprintf("%s.%s", ringback_data, ext); + ringback_data = tmp_data; + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Play Ringback File [%s]\n", ringback_data); + + ringback.fhb.channels = read_codec->implementation->number_of_channels; + ringback.fhb.samplerate = read_codec->implementation->actual_samples_per_second; + if (switch_core_file_open(&ringback.fhb, + ringback_data, + read_codec->implementation->number_of_channels, + read_codec->implementation->actual_samples_per_second, + SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, + switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Playing File\n"); + switch_safe_free(tmp_data); + goto done; + } + ringback.fh = &ringback.fhb; + + + } else { + teletone_init_session(&ringback.ts, 0, teletone_handler, &ringback); + ringback.ts.rate = read_codec->implementation->actual_samples_per_second; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Play Ringback Tone [%s]\n", ringback_data); + //ringback.ts.debug = 1; + //ringback.ts.debug_stream = switch_core_get_console(); + if (teletone_run(&ringback.ts, ringback_data)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Playing Tone\n"); + teletone_destroy_session(&ringback.ts); + switch_buffer_destroy(&ringback.audio_buffer); + ringback_data = NULL; + } + } + switch_safe_free(tmp_data); + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Codec Error!\n"); + switch_channel_hangup(caller_channel, SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE); + read_codec = NULL; + } + } + } + + while (!(switch_channel_test_flag(peer_channel, CF_ANSWERED) || switch_channel_test_flag(peer_channel, CF_EARLY_MEDIA))) { + int diff = (int)(switch_timestamp_now() - start); + + if (diff > timelimit) { + status = SWITCH_STATUS_TIMEOUT; + goto done; + } + + if (switch_core_session_dequeue_message(peer_session, &message) == SWITCH_STATUS_SUCCESS) { + switch_core_session_receive_message(session, message); + + if (switch_test_flag(message, SCSMF_DYNAMIC)) { + switch_safe_free(message); + } else { + message = NULL; + } + } + status = switch_core_session_read_frame(session, &read_frame, 1000, 0); + if (!SWITCH_READ_ACCEPTABLE(status)) { + break; + } + + + if (read_frame && !pass) { + if (ringback.fh) { + uint8_t abuf[1024]; + switch_size_t mlen, olen; + unsigned int pos = 0; + + if (ringback.asis) { + mlen = write_frame.codec->implementation->encoded_bytes_per_frame; + } else { + mlen = write_frame.codec->implementation->samples_per_frame; + } + + olen = mlen; + switch_core_file_read(ringback.fh, abuf, &olen); + + if (olen == 0) { + olen = mlen; + ringback.fh->speed = 0; + switch_core_file_seek(ringback.fh, &pos, 0, SEEK_SET); + switch_core_file_read(ringback.fh, abuf, &olen); + if (olen == 0) { + break; + } + } + write_frame.data = abuf; + write_frame.datalen = (uint32_t) (ringback.asis ? olen : olen * 2); + } else if (ringback.audio_buffer) { + if ((write_frame.datalen = (uint32_t) switch_buffer_read_loop(ringback.audio_buffer, + write_frame.data, + write_frame.codec->implementation->bytes_per_frame)) <= 0) { + break; + } + } + + if (switch_core_session_write_frame(session, &write_frame, 1000, 0) != SWITCH_STATUS_SUCCESS) { + break; + } + } else { + switch_yield(1000); + } + } + + done: + + if (ringback.fh) { + switch_core_file_close(ringback.fh); + ringback.fh = NULL; + } else if (ringback.audio_buffer) { + teletone_destroy_session(&ringback.ts); + switch_buffer_destroy(&ringback.audio_buffer); + } + + if (!pass && write_codec.implementation) { + if (read_codec && !ringback.asis) { + switch_core_session_set_read_codec(session, read_codec); + switch_core_session_reset(session); + } + switch_core_codec_destroy(&write_codec); + } + + return status; + +} + #define MAX_PEERS 128 SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *session, switch_core_session_t **bleg, @@ -608,8 +892,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess peer_sessions[i] = new_session; peer_channels[i] = switch_core_session_get_channel(new_session); switch_assert(peer_channels[i] != NULL); - - + switch_channel_set_flag(peer_channels[i], CF_ORIGINATING); + if (var_event) { switch_event_t *event; switch_event_header_t *header; @@ -888,6 +1172,14 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess if (!peer_channels[i]) { continue; } + + if (switch_channel_test_flag(peer_channels[i], CF_TRANSFER) || switch_channel_test_flag(peer_channels[i], CF_BRIDGED) || + switch_channel_get_state(peer_channels[i]) == CS_RESET || + !switch_channel_test_flag(peer_channels[i], CF_ORIGINATING) + ) { + continue; + } + if (i != idx) { if (idx == IDX_CANCEL) { if (to) { @@ -916,6 +1208,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess peer_channel = peer_channels[idx]; } else { status = SWITCH_STATUS_FALSE; + peer_channel = NULL; goto done; } @@ -968,6 +1261,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess } } + if (*cause == SWITCH_CAUSE_SUCCESS || *cause == SWITCH_CAUSE_UNALLOCATED) { + *cause = SWITCH_CAUSE_ORIGINATOR_CANCEL; + } + if (idx == IDX_CANCEL) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Originate Cancelled by originator termination Cause: %d [%s]\n", *cause, switch_channel_cause2str(*cause)); @@ -982,26 +1279,28 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess switch_channel_set_variable(caller_channel, "originate_disposition", switch_channel_cause2str(*cause)); } - if (!pass && write_codec.implementation) { - switch_core_codec_destroy(&write_codec); - } - if (ringback.fh) { switch_core_file_close(ringback.fh); ringback.fh = NULL; - if (read_codec && !ringback.asis) { - switch_core_session_set_read_codec(session, read_codec); - switch_core_session_reset(session); - } } else if (ringback.audio_buffer) { teletone_destroy_session(&ringback.ts); switch_buffer_destroy(&ringback.audio_buffer); } + if (!pass && write_codec.implementation) { + if (read_codec && !ringback.asis) { + switch_core_session_set_read_codec(session, read_codec); + switch_core_session_reset(session); + } + switch_core_codec_destroy(&write_codec); + } + + for (i = 0; i < and_argc; i++) { if (!peer_channels[i]) { continue; } + switch_channel_clear_flag(peer_channels[i], CF_ORIGINATING); if (status == SWITCH_STATUS_SUCCESS && bleg && *bleg && *bleg == peer_sessions[i]) { continue; }