From 08442ff2c4621e01dce69c514039662d54b32049 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 25 Oct 2006 04:28:49 +0000 Subject: [PATCH] signalling refactoring for media etc git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3192 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- src/include/switch_channel.h | 11 + src/include/switch_types.h | 1 + .../applications/mod_dptools/mod_dptools.c | 22 +- src/mod/endpoints/mod_sofia/mod_sofia.c | 212 +++++++++--------- src/switch_channel.c | 35 +++ src/switch_ivr.c | 44 +++- 6 files changed, 213 insertions(+), 112 deletions(-) diff --git a/src/include/switch_channel.h b/src/include/switch_channel.h index fc31b29461..dd22ca9f2e 100644 --- a/src/include/switch_channel.h +++ b/src/include/switch_channel.h @@ -281,6 +281,17 @@ SWITCH_DECLARE(switch_status_t) switch_channel_perform_answer(switch_channel_t * #define switch_channel_answer(channel) switch_channel_perform_answer(channel, __FILE__, __FUNCTION__, __LINE__) +SWITCH_DECLARE(switch_status_t) switch_channel_perform_ringback(switch_channel_t *channel, + const char *file, + const char *func, + int line); +/*! + \brief Send Ringing message to a channel + \param channel channel to ring + \return SWITCH_STATUS_SUCCESS if successful +*/ +#define switch_channel_ringback(channel) switch_channel_perform_ringback(channel, __FILE__, __FUNCTION__, __LINE__) + SWITCH_DECLARE(switch_status_t) switch_channel_perform_pre_answer(switch_channel_t *channel, const char *file, diff --git a/src/include/switch_types.h b/src/include/switch_types.h index a9f0b43c33..39c45936f2 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -720,6 +720,7 @@ typedef enum { SWITCH_CAUSE_MANDATORY_IE_LENGTH_ERROR = 103, SWITCH_CAUSE_PROTOCOL_ERROR = 111, SWITCH_CAUSE_INTERWORKING = 127, + SWITCH_CAUSE_ORIGINATOR_CANCEL = 487, SWITCH_CAUSE_CRASH = 500, SWITCH_CAUSE_SYSTEM_SHUTDOWN = 501, SWITCH_CAUSE_LOSE_RACE = 502, diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c index 7b6f9dc51d..7722c8aff9 100644 --- a/src/mod/applications/mod_dptools/mod_dptools.c +++ b/src/mod/applications/mod_dptools/mod_dptools.c @@ -34,6 +34,15 @@ static const char modname[] = "mod_dptools"; + +static void ringback_function(switch_core_session_t *session, char *data) +{ + switch_channel_t *channel; + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + switch_channel_ringback(channel); +} + static void transfer_function(switch_core_session_t *session, char *data) { int argc; @@ -253,13 +262,24 @@ static switch_api_interface_t presence_api_interface = { /*.next */ &dptools_api_interface }; + +static const switch_application_interface_t ringback_application_interface = { + /*.interface_name */ "ringback", + /*.application_function */ ringback_function, + /* long_desc */ "Indicate Ringback on a channel.", + /* short_desc */ "Indicate Ringback", + /* syntax */ "", + /*.next */ NULL + +}; + static const switch_application_interface_t set_application_interface = { /*.interface_name */ "set", /*.application_function */ set_function, /* long_desc */ "Set a channel varaible for the channel calling the application.", /* short_desc */ "Set a channel varaible", /* syntax */ "=[|_UNDEF_]", - /*.next */ NULL + /*.next */ &ringback_application_interface }; static const switch_application_interface_t answer_application_interface = { diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 93d4f7a8ce..804efd7213 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -1078,53 +1078,55 @@ static switch_status_t sofia_on_execute(switch_core_session_t *session) // map QSIG cause codes to SIP from RFC4497 section 8.4.1 static int hangup_cause_to_sip(switch_call_cause_t cause) { switch (cause) { - case SWITCH_CAUSE_UNALLOCATED: - case SWITCH_CAUSE_NO_ROUTE_TRANSIT_NET: - case SWITCH_CAUSE_NO_ROUTE_DESTINATION: - return 404; - case SWITCH_CAUSE_USER_BUSY: - return 486; - case SWITCH_CAUSE_NO_USER_RESPONSE: - return 408; - case SWITCH_CAUSE_NO_ANSWER: - return 480; - case SWITCH_CAUSE_SUBSCRIBER_ABSENT: - return 480; - case SWITCH_CAUSE_CALL_REJECTED: - return 603; - case SWITCH_CAUSE_NUMBER_CHANGED: - case SWITCH_CAUSE_REDIRECTION_TO_NEW_DESTINATION: - return 410; - case SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER: - return 502; - case SWITCH_CAUSE_INVALID_NUMBER_FORMAT: - return 484; - case SWITCH_CAUSE_FACILITY_REJECTED: - return 501; - case SWITCH_CAUSE_NORMAL_UNSPECIFIED: - return 480; - case SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION: - case SWITCH_CAUSE_NETWORK_OUT_OF_ORDER: - case SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE: - case SWITCH_CAUSE_SWITCH_CONGESTION: - return 503; - case SWITCH_CAUSE_OUTGOING_CALL_BARRED: - case SWITCH_CAUSE_INCOMING_CALL_BARRED: - case SWITCH_CAUSE_BEARERCAPABILITY_NOTAUTH: - return 403; - case SWITCH_CAUSE_BEARERCAPABILITY_NOTAVAIL: - return 503; - case SWITCH_CAUSE_BEARERCAPABILITY_NOTIMPL: - return 488; - case SWITCH_CAUSE_FACILITY_NOT_IMPLEMENTED: - case SWITCH_CAUSE_SERVICE_NOT_IMPLEMENTED: - return 501; - case SWITCH_CAUSE_INCOMPATIBLE_DESTINATION: - return 503; - case SWITCH_CAUSE_RECOVERY_ON_TIMER_EXPIRE: - return 504; - default: - return 500; + case SWITCH_CAUSE_UNALLOCATED: + case SWITCH_CAUSE_NO_ROUTE_TRANSIT_NET: + case SWITCH_CAUSE_NO_ROUTE_DESTINATION: + return 404; + case SWITCH_CAUSE_USER_BUSY: + return 486; + case SWITCH_CAUSE_NO_USER_RESPONSE: + return 408; + case SWITCH_CAUSE_NO_ANSWER: + return 480; + case SWITCH_CAUSE_SUBSCRIBER_ABSENT: + return 480; + case SWITCH_CAUSE_CALL_REJECTED: + return 603; + case SWITCH_CAUSE_NUMBER_CHANGED: + case SWITCH_CAUSE_REDIRECTION_TO_NEW_DESTINATION: + return 410; + case SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER: + return 502; + case SWITCH_CAUSE_INVALID_NUMBER_FORMAT: + return 484; + case SWITCH_CAUSE_FACILITY_REJECTED: + return 501; + case SWITCH_CAUSE_NORMAL_UNSPECIFIED: + return 480; + case SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION: + case SWITCH_CAUSE_NETWORK_OUT_OF_ORDER: + case SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE: + case SWITCH_CAUSE_SWITCH_CONGESTION: + return 503; + case SWITCH_CAUSE_OUTGOING_CALL_BARRED: + case SWITCH_CAUSE_INCOMING_CALL_BARRED: + case SWITCH_CAUSE_BEARERCAPABILITY_NOTAUTH: + return 403; + case SWITCH_CAUSE_BEARERCAPABILITY_NOTAVAIL: + return 503; + case SWITCH_CAUSE_BEARERCAPABILITY_NOTIMPL: + return 488; + case SWITCH_CAUSE_FACILITY_NOT_IMPLEMENTED: + case SWITCH_CAUSE_SERVICE_NOT_IMPLEMENTED: + return 501; + case SWITCH_CAUSE_INCOMPATIBLE_DESTINATION: + return 503; + case SWITCH_CAUSE_RECOVERY_ON_TIMER_EXPIRE: + return 504; + case SWITCH_CAUSE_ORIGINATOR_CANCEL: + return 487; + default: + return 500; } } @@ -2033,60 +2035,64 @@ static uint8_t negotiate_sdp(switch_core_session_t *session, sdp_session_t *sdp) // map sip responses to QSIG cause codes ala RFC4497 section 8.4.4 static switch_call_cause_t sip_cause_to_freeswitch(int status) { switch (status) { - case 200: - return SWITCH_CAUSE_NORMAL_CLEARING; - case 401: - case 402: - case 403: - case 407: - case 603: - return SWITCH_CAUSE_CALL_REJECTED; - case 404: - case 485: - case 604: - return SWITCH_CAUSE_UNALLOCATED; - case 408: - case 504: - return SWITCH_CAUSE_RECOVERY_ON_TIMER_EXPIRE; - case 410: - return SWITCH_CAUSE_NUMBER_CHANGED; - case 413: - case 414: - case 416: - case 420: - case 421: - case 423: - case 505: - case 513: - return SWITCH_CAUSE_INTERWORKING; - case 480: - return SWITCH_CAUSE_NO_USER_RESPONSE; - case 400: - case 481: - case 500: - case 503: - return SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE; - case 486: - case 600: - return SWITCH_CAUSE_USER_BUSY; - case 484: - return SWITCH_CAUSE_INVALID_NUMBER_FORMAT; - case 488: - case 606: - return SWITCH_CAUSE_BEARERCAPABILITY_NOTIMPL; - case 502: - return SWITCH_CAUSE_NETWORK_OUT_OF_ORDER; - case 405: - return SWITCH_CAUSE_SERVICE_UNAVAILABLE; - case 406: - case 415: - case 501: - return SWITCH_CAUSE_SERVICE_NOT_IMPLEMENTED; - case 482: - case 483: - return SWITCH_CAUSE_EXCHANGE_ROUTING_ERROR; - default: - return SWITCH_CAUSE_NORMAL_UNSPECIFIED; + case 200: + return SWITCH_CAUSE_NORMAL_CLEARING; + case 401: + case 402: + case 403: + case 407: + case 603: + return SWITCH_CAUSE_CALL_REJECTED; + case 404: + case 485: + case 604: + return SWITCH_CAUSE_UNALLOCATED; + case 408: + case 504: + return SWITCH_CAUSE_RECOVERY_ON_TIMER_EXPIRE; + case 410: + return SWITCH_CAUSE_NUMBER_CHANGED; + case 413: + case 414: + case 416: + case 420: + case 421: + case 423: + case 505: + case 513: + return SWITCH_CAUSE_INTERWORKING; + case 480: + return SWITCH_CAUSE_NO_USER_RESPONSE; + case 400: + case 481: + case 500: + case 503: + return SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE; + case 486: + case 600: + return SWITCH_CAUSE_USER_BUSY; + case 484: + return SWITCH_CAUSE_INVALID_NUMBER_FORMAT; + case 488: + case 606: + return SWITCH_CAUSE_BEARERCAPABILITY_NOTIMPL; + case 502: + return SWITCH_CAUSE_NETWORK_OUT_OF_ORDER; + case 405: + return SWITCH_CAUSE_SERVICE_UNAVAILABLE; + case 406: + case 415: + case 501: + return SWITCH_CAUSE_SERVICE_NOT_IMPLEMENTED; + case 482: + case 483: + return SWITCH_CAUSE_EXCHANGE_ROUTING_ERROR; + case 487: + return SWITCH_CAUSE_ORIGINATOR_CANCEL; + + default: + return SWITCH_CAUSE_NORMAL_UNSPECIFIED; + } } @@ -2280,7 +2286,9 @@ static void sip_i_state(int status, char *uuid; switch_core_session_t *other_session = NULL; switch_channel_t *other_channel = NULL; + char st[80] = ""; + tl_gets(tags, NUTAG_CALLSTATE_REF(ss_state), NUTAG_OFFER_RECV_REF(offer_recv), @@ -2560,6 +2568,8 @@ static void sip_i_state(int status, nua_handle_destroy(tech_pvt->nh); tech_pvt->nh = NULL; } else { + snprintf(st, sizeof(st), "%d", status); + switch_channel_set_variable(channel, "sip_term_status", st); terminate_session(&session, sip_cause_to_freeswitch(status), __LINE__); } } diff --git a/src/switch_channel.c b/src/switch_channel.c index ed9b4fb0e3..313a8bfccb 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -87,6 +87,7 @@ static struct switch_cause_table CAUSE_CHART[] = { { "MANDATORY_IE_LENGTH_ERROR", SWITCH_CAUSE_MANDATORY_IE_LENGTH_ERROR }, { "PROTOCOL_ERROR", SWITCH_CAUSE_PROTOCOL_ERROR }, { "INTERWORKING", SWITCH_CAUSE_INTERWORKING }, + { "ORIGINATOR_CANCEL", SWITCH_CAUSE_ORIGINATOR_CANCEL }, { "CRASH", SWITCH_CAUSE_CRASH }, { "SYSTEM_SHUTDOWN", SWITCH_CAUSE_SYSTEM_SHUTDOWN }, { "LOSE_RACE", SWITCH_CAUSE_LOSE_RACE }, @@ -1018,6 +1019,40 @@ SWITCH_DECLARE(switch_status_t) switch_channel_perform_pre_answer(switch_channel return status; } +SWITCH_DECLARE(switch_status_t) switch_channel_perform_ringback(switch_channel_t *channel, + const char *file, + const char *func, + int line) +{ + switch_core_session_message_t msg; + char *uuid = switch_core_session_get_uuid(channel->session); + switch_status_t status; + + assert(channel != NULL); + + if (channel->state >= CS_HANGUP) { + return SWITCH_STATUS_FALSE; + } + + if (switch_channel_test_flag(channel, CF_ANSWERED)) { + return SWITCH_STATUS_SUCCESS; + } + + if (switch_channel_test_flag(channel, CF_EARLY_MEDIA)) { + return SWITCH_STATUS_SUCCESS; + } + + msg.message_id = SWITCH_MESSAGE_INDICATE_RINGING; + msg.from = channel->name; + status = switch_core_session_message_send(uuid, &msg); + + if (status == SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_ID_LOG, (char *) file, func, line, SWITCH_LOG_NOTICE, "Ringback %s!\n", channel->name); + } + + return status; +} + SWITCH_DECLARE(switch_status_t) switch_channel_perform_answer(switch_channel_t *channel, const char *file, const char *func, diff --git a/src/switch_ivr.c b/src/switch_ivr.c index 2a0f22c936..6f47ad0639 100644 --- a/src/switch_ivr.c +++ b/src/switch_ivr.c @@ -34,6 +34,11 @@ static const switch_state_handler_table_t audio_bridge_peer_state_handlers; +typedef enum { + IDX_CANCEL = -2, + IDX_NADA = -1 +} abort_t; + SWITCH_DECLARE(switch_status_t) switch_ivr_sleep(switch_core_session_t *session, uint32_t ms) { switch_channel_t *channel; @@ -1715,12 +1720,13 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess switch_frame_t *read_frame = NULL; switch_memory_pool_t *pool = NULL; int r = 0, i, and_argc = 0, or_argc = 0; - int32_t idx = -1; + int32_t idx = IDX_NADA; switch_codec_t write_codec = {0}; switch_frame_t write_frame = {0}; uint8_t err = 0, fdata[1024], pass = 0; char *file = NULL, *key = NULL, *odata, *var; - + switch_call_cause_t reason = SWITCH_CAUSE_UNALLOCATED; + uint8_t to = 0; write_frame.data = fdata; *bleg = NULL; @@ -1785,7 +1791,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess file = NULL; key = NULL; var = NULL; - + to = 0; + and_argc = switch_separate_string(pipe_names[r], '&', peer_names, (sizeof(peer_names) / sizeof(peer_names[0]))); for (i = 0; i < and_argc; i++) { @@ -1924,6 +1931,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess } if ((time(NULL) - start) > (time_t)timelimit_sec) { + to++; break; } switch_yield(1000); @@ -1965,9 +1973,13 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess } } } - + while ((!caller_channel || switch_channel_ready(caller_channel)) && - check_channel_status(peer_channels, peer_sessions, and_argc, &idx, file, key) && ((time(NULL) - start) < (time_t)timelimit_sec)) { + check_channel_status(peer_channels, peer_sessions, and_argc, &idx, file, key)) { + + if ((to = ((time(NULL) - start) >= (time_t)timelimit_sec))) { + break; + } if (session && or_argc == 1 && and_argc == 1) { /* when there is only 1 channel to call and bridge */ switch_core_session_message_t *message = NULL; @@ -2000,7 +2012,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess } if (!switch_channel_ready(caller_channel)) { - idx = -2; + idx = IDX_CANCEL; } if (session && !switch_channel_test_flag(caller_channel, CF_NOMEDIA)) { @@ -2012,12 +2024,24 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess continue; } if (i != idx) { - switch_channel_hangup(peer_channels[i], SWITCH_CAUSE_LOSE_RACE); + if (idx == IDX_CANCEL) { + reason = SWITCH_CAUSE_ORIGINATOR_CANCEL; + } else { + if (to) { + reason = SWITCH_CAUSE_NO_ANSWER; + } else if (and_argc > 1) { + reason = SWITCH_CAUSE_LOSE_RACE; + } else { + reason = SWITCH_CAUSE_NO_ANSWER; + } + } + + switch_channel_hangup(peer_channels[i], reason); } } - if (idx > -1) { + if (idx > IDX_NADA) { peer_session = peer_sessions[idx]; peer_channel = peer_channels[idx]; } else { @@ -2068,13 +2092,13 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess } if (caller_channel) { - if (idx == -2) { + if (idx == IDX_CANCEL) { *cause = switch_channel_get_cause(caller_channel); } switch_channel_set_variable(caller_channel, "originate_disposition", switch_channel_cause2str(*cause)); } - if (idx == -2) { + 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)); } else {