From bd471fc6a91f9aacb237e4be93e0b8f06f8157d2 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 28 Apr 2011 13:46:39 -0500 Subject: [PATCH] add bridged timestamp and hangup_complete_with_xml=true to add xml_cdr to the body of hangup_complete events --- src/include/switch_channel.h | 3 +- src/include/switch_utils.h | 39 +++++++++++++---------- src/switch_channel.c | 56 ++++++++++++++++++++++++++++----- src/switch_core_state_machine.c | 12 +++++++ src/switch_ivr.c | 6 ++++ src/switch_ivr_bridge.c | 7 ++++- 6 files changed, 97 insertions(+), 26 deletions(-) diff --git a/src/include/switch_channel.h b/src/include/switch_channel.h index febaf40f75..dc8175b202 100644 --- a/src/include/switch_channel.h +++ b/src/include/switch_channel.h @@ -49,6 +49,7 @@ SWITCH_BEGIN_EXTERN_C struct switch_channel_timetable { switch_time_t hungup; switch_time_t transferred; switch_time_t resurrected; + switch_time_t bridged; struct switch_channel_timetable *next; }; @@ -597,7 +598,7 @@ SWITCH_DECLARE(int) switch_channel_test_app_flag_key(const char *app, switch_cha #define switch_channel_clear_app_flag(_c, _f) switch_channel_clear_app_flag_key(__FILE__, _c, _f) #define switch_channel_test_app_flag(_c, _f) switch_channel_test_app_flag_key(__FILE__, _c, _f) - +SWITCH_DECLARE(void) switch_channel_set_bridge_time(switch_channel_t *channel); SWITCH_DECLARE(void) switch_channel_set_hangup_time(switch_channel_t *channel); SWITCH_DECLARE(switch_call_direction_t) switch_channel_direction(switch_channel_t *channel); SWITCH_DECLARE(switch_core_session_t *) switch_channel_get_session(switch_channel_t *channel); diff --git a/src/include/switch_utils.h b/src/include/switch_utils.h index 4135ade091..88c13379b3 100644 --- a/src/include/switch_utils.h +++ b/src/include/switch_utils.h @@ -239,20 +239,23 @@ SWITCH_DECLARE(switch_size_t) switch_fd_read_line(int fd, char *buf, switch_size SWITCH_DECLARE(switch_status_t) switch_frame_alloc(switch_frame_t **frame, switch_size_t size); SWITCH_DECLARE(switch_status_t) switch_frame_dup(switch_frame_t *orig, switch_frame_t **clone); SWITCH_DECLARE(switch_status_t) switch_frame_free(switch_frame_t **frame); +SWITCH_DECLARE(switch_bool_t) switch_is_number(const char *str); /*! \brief Evaluate the truthfullness of a string expression \param expr a string expression \return true or false */ -#define switch_true(expr)\ -((expr && ( !strcasecmp(expr, "yes") ||\ -!strcasecmp(expr, "on") ||\ -!strcasecmp(expr, "true") ||\ -!strcasecmp(expr, "enabled") ||\ -!strcasecmp(expr, "active") ||\ -!strcasecmp(expr, "allow") ||\ -(switch_is_number(expr) && atoi(expr)))) ? SWITCH_TRUE : SWITCH_FALSE) +static inline int switch_true(const char *expr) +{ + return ((expr && ( !strcasecmp(expr, "yes") || + !strcasecmp(expr, "on") || + !strcasecmp(expr, "true") || + !strcasecmp(expr, "enabled") || + !strcasecmp(expr, "active") || + !strcasecmp(expr, "allow") || + (switch_is_number(expr) && atoi(expr)))) ? SWITCH_TRUE : SWITCH_FALSE); +} #define switch_true_buf(expr)\ ((( !strcasecmp(expr, "yes") ||\ @@ -268,14 +271,16 @@ SWITCH_DECLARE(switch_status_t) switch_frame_free(switch_frame_t **frame); \param expr a string expression \return true or false */ -#define switch_false(expr)\ -((expr && ( !strcasecmp(expr, "no") ||\ -!strcasecmp(expr, "off") ||\ -!strcasecmp(expr, "false") ||\ -!strcasecmp(expr, "disabled") ||\ -!strcasecmp(expr, "inactive") ||\ -!strcasecmp(expr, "disallow") ||\ -(switch_is_number(expr) && !atoi(expr)))) ? SWITCH_TRUE : SWITCH_FALSE) +static inline int switch_false(const char *expr) +{ + return ((expr && ( !strcasecmp(expr, "no") || + !strcasecmp(expr, "off") || + !strcasecmp(expr, "false") || + !strcasecmp(expr, "disabled") || + !strcasecmp(expr, "inactive") || + !strcasecmp(expr, "disallow") || + (switch_is_number(expr) && !atoi(expr)))) ? SWITCH_TRUE : SWITCH_FALSE); +} SWITCH_DECLARE(switch_status_t) switch_resolve_host(const char *host, char *buf, size_t buflen); @@ -670,7 +675,7 @@ SWITCH_DECLARE(switch_time_t) switch_str_time(const char *in); SWITCH_DECLARE(unsigned int) switch_separate_string(_In_ char *buf, char delim, _Post_count_(return) char **array, unsigned int arraylen); SWITCH_DECLARE(unsigned int) switch_separate_string_string(char *buf, char *delim, _Post_count_(return) char **array, unsigned int arraylen); -SWITCH_DECLARE(switch_bool_t) switch_is_number(const char *str); + SWITCH_DECLARE(char *) switch_strip_spaces(char *str, switch_bool_t dup); SWITCH_DECLARE(char *) switch_strip_whitespace(const char *str); SWITCH_DECLARE(char *) switch_strip_commas(char *in, char *out, switch_size_t len); diff --git a/src/switch_channel.c b/src/switch_channel.c index 2cd45b9e06..5b1d06ce33 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -2513,11 +2513,21 @@ SWITCH_DECLARE(switch_caller_extension_t *) switch_channel_get_caller_extension( } +SWITCH_DECLARE(void) switch_channel_set_bridge_time(switch_channel_t *channel) +{ + switch_mutex_lock(channel->profile_mutex); + if (channel->caller_profile && channel->caller_profile->times) { + channel->caller_profile->times->bridged = switch_micro_time_now(); + } + switch_mutex_unlock(channel->profile_mutex); +} + + SWITCH_DECLARE(void) switch_channel_set_hangup_time(switch_channel_t *channel) { - if (channel->caller_profile && channel->caller_profile->times && !channel->caller_profile->times->hungup) { + if (channel->caller_profile && channel->caller_profile->times && !channel->caller_profile->times->bridged) { switch_mutex_lock(channel->profile_mutex); - channel->caller_profile->times->hungup = switch_micro_time_now(); + channel->caller_profile->times->bridged = switch_micro_time_now(); switch_mutex_unlock(channel->profile_mutex); } } @@ -3348,14 +3358,14 @@ SWITCH_DECLARE(switch_status_t) switch_channel_set_timestamps(switch_channel_t * switch_caller_profile_t *caller_profile, *ocp; switch_app_log_t *app_log, *ap; char *last_app = NULL, *last_arg = NULL; - char start[80] = "", resurrect[80] = "", answer[80] = "", progress[80] = "", progress_media[80] = "", end[80] = "", tmp[80] = "", + char start[80] = "", resurrect[80] = "", answer[80] = "", bridge[80] = "", progress[80] = "", progress_media[80] = "", end[80] = "", tmp[80] = "", profile_start[80] = ""; int32_t duration = 0, legbillsec = 0, billsec = 0, mduration = 0, billmsec = 0, legbillmsec = 0, progressmsec = 0, progress_mediamsec = 0; - int32_t answersec = 0, answermsec = 0; + int32_t answersec = 0, answermsec = 0, waitsec = 0, waitmsec = 0; switch_time_t answerusec = 0; - switch_time_t uduration = 0, legbillusec = 0, billusec = 0, progresssec = 0, progressusec = 0, progress_mediasec = 0, progress_mediausec = 0; - time_t tt_created = 0, tt_answered = 0, tt_resurrected = 0, - tt_progress = 0, tt_progress_media = 0, tt_hungup = 0, mtt_created = 0, mtt_answered = 0, + switch_time_t uduration = 0, legbillusec = 0, billusec = 0, progresssec = 0, progressusec = 0, progress_mediasec = 0, progress_mediausec = 0, waitusec = 0; + time_t tt_created = 0, tt_answered = 0, tt_resurrected = 0, tt_bridged, + tt_progress = 0, tt_progress_media = 0, tt_hungup = 0, mtt_created = 0, mtt_answered = 0, mtt_bridged = 0, mtt_hungup = 0, tt_prof_created, mtt_prof_created, mtt_progress = 0, mtt_progress_media = 0; void *pop; char dtstr[SWITCH_DTMF_LOG_LEN + 1] = ""; @@ -3427,6 +3437,12 @@ SWITCH_DECLARE(switch_status_t) switch_channel_set_timestamps(switch_channel_t * switch_channel_set_variable(channel, "answer_stamp", answer); } + if (caller_profile->times->bridged) { + switch_time_exp_lt(&tm, caller_profile->times->bridged); + switch_strftime_nocheck(bridge, &retsize, sizeof(bridge), fmt, &tm); + switch_channel_set_variable(channel, "bridge_stamp", bridge); + } + if (caller_profile->times->resurrected) { switch_time_exp_lt(&tm, caller_profile->times->resurrected); switch_strftime_nocheck(resurrect, &retsize, sizeof(resurrect), fmt, &tm); @@ -3470,6 +3486,13 @@ SWITCH_DECLARE(switch_status_t) switch_channel_set_timestamps(switch_channel_t * switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, caller_profile->times->answered); switch_channel_set_variable(channel, "answer_uepoch", tmp); + tt_bridged = (time_t) (caller_profile->times->bridged / 1000000); + mtt_bridged = (time_t) (caller_profile->times->bridged / 1000); + switch_snprintf(tmp, sizeof(tmp), "%" TIME_T_FMT, tt_bridged); + switch_channel_set_variable(channel, "bridge_epoch", tmp); + switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, caller_profile->times->bridged); + switch_channel_set_variable(channel, "bridge_uepoch", tmp); + tt_resurrected = (time_t) (caller_profile->times->resurrected / 1000000); switch_snprintf(tmp, sizeof(tmp), "%" TIME_T_FMT, tt_resurrected); switch_channel_set_variable(channel, "resurrect_epoch", tmp); @@ -3501,6 +3524,16 @@ SWITCH_DECLARE(switch_status_t) switch_channel_set_timestamps(switch_channel_t * mduration = (int32_t) (mtt_hungup - mtt_created); uduration = caller_profile->times->hungup - caller_profile->times->created; + if (caller_profile->times->bridged > caller_profile->times->created) { + waitsec = (int32_t) (tt_bridged - tt_created); + waitmsec = (int32_t) (mtt_bridged - mtt_created); + waitusec = caller_profile->times->bridged - caller_profile->times->created; + } else { + waitsec = 0; + waitmsec = 0; + waitusec = 0; + } + if (caller_profile->times->answered) { billsec = (int32_t) (tt_hungup - tt_answered); billmsec = (int32_t) (mtt_hungup - mtt_answered); @@ -3545,6 +3578,9 @@ SWITCH_DECLARE(switch_status_t) switch_channel_set_timestamps(switch_channel_t * switch_snprintf(tmp, sizeof(tmp), "%d", answersec); switch_channel_set_variable(channel, "answersec", tmp); + switch_snprintf(tmp, sizeof(tmp), "%d", waitsec); + switch_channel_set_variable(channel, "waitsec", tmp); + switch_snprintf(tmp, sizeof(tmp), "%d", progress_mediasec); switch_channel_set_variable(channel, "progress_mediasec", tmp); @@ -3563,6 +3599,9 @@ SWITCH_DECLARE(switch_status_t) switch_channel_set_timestamps(switch_channel_t * switch_snprintf(tmp, sizeof(tmp), "%d", answermsec); switch_channel_set_variable(channel, "answermsec", tmp); + switch_snprintf(tmp, sizeof(tmp), "%d", waitmsec); + switch_channel_set_variable(channel, "waitmsec", tmp); + switch_snprintf(tmp, sizeof(tmp), "%d", progress_mediamsec); switch_channel_set_variable(channel, "progress_mediamsec", tmp); @@ -3581,6 +3620,9 @@ SWITCH_DECLARE(switch_status_t) switch_channel_set_timestamps(switch_channel_t * switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, answerusec); switch_channel_set_variable(channel, "answerusec", tmp); + switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, waitusec); + switch_channel_set_variable(channel, "waitusec", tmp); + switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, progress_mediausec); switch_channel_set_variable(channel, "progress_mediausec", tmp); diff --git a/src/switch_core_state_machine.c b/src/switch_core_state_machine.c index e69c408013..6551b2b777 100644 --- a/src/switch_core_state_machine.c +++ b/src/switch_core_state_machine.c @@ -636,6 +636,18 @@ SWITCH_DECLARE(void) switch_core_session_reporting_state(switch_core_session_t * if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_HANGUP_COMPLETE) == SWITCH_STATUS_SUCCESS) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Hangup-Cause", switch_channel_cause2str(cause)); switch_channel_event_set_data(session->channel, event); + if (switch_true(switch_channel_get_variable(session->channel, "hangup_complete_with_xml"))) { + switch_xml_t cdr = NULL; + char *xml_cdr_text; + + if (switch_ivr_generate_xml_cdr(session, &cdr) == SWITCH_STATUS_SUCCESS) { + xml_cdr_text = switch_xml_toxml(cdr, SWITCH_FALSE); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CDR-Attached", "xml"); + switch_event_add_body(event, "%s", xml_cdr_text); + switch_xml_free(cdr); + switch_safe_free(xml_cdr_text); + } + } switch_event_fire(&event); } diff --git a/src/switch_ivr.c b/src/switch_ivr.c index 64be6b7f14..4932606ff2 100644 --- a/src/switch_ivr.c +++ b/src/switch_ivr.c @@ -2219,6 +2219,12 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_generate_xml_cdr(switch_core_session_ switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, caller_profile->times->answered); switch_xml_set_txt_d(time_tag, tmp); + if (!(time_tag = switch_xml_add_child_d(x_times, "bridged_time", t_off++))) { + goto error; + } + switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, caller_profile->times->bridged); + switch_xml_set_txt_d(time_tag, tmp); + if (!(time_tag = switch_xml_add_child_d(x_times, "hangup_time", t_off++))) { goto error; } diff --git a/src/switch_ivr_bridge.c b/src/switch_ivr_bridge.c index 7dc8edfa2c..0fecc309f7 100644 --- a/src/switch_ivr_bridge.c +++ b/src/switch_ivr_bridge.c @@ -201,7 +201,9 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj) chan_a = switch_core_session_get_channel(session_a); chan_b = switch_core_session_get_channel(session_b); - + + switch_channel_set_bridge_time(chan_a); + if ((exec_app = switch_channel_get_variable(chan_a, "bridge_pre_execute_app"))) { exec_data = switch_channel_get_variable(chan_a, "bridge_pre_execute_data"); } @@ -1067,6 +1069,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_signal_bridge(switch_core_session_t * switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Application-Data", switch_core_session_get_uuid(session)); switch_event_fire(&event); } + + switch_channel_set_bridge_time(caller_channel); + switch_channel_set_bridge_time(peer_channel); switch_channel_set_state_flag(caller_channel, CF_RESET); switch_channel_set_state_flag(peer_channel, CF_RESET);