From 9537197b4df5011fdf5c31638b8eba041f903b77 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 7 Oct 2010 18:30:07 -0500 Subject: [PATCH] add some goodies --- src/include/private/switch_core_pvt.h | 1 + src/include/switch_core.h | 3 +- src/include/switch_ivr.h | 1 + src/include/switch_types.h | 1 + .../applications/mod_dptools/mod_dptools.c | 122 ++++++++++++++++++ src/mod/endpoints/mod_sofia/sofia.c | 2 +- src/switch_core_io.c | 16 ++- src/switch_core_session.c | 14 ++ src/switch_ivr_async.c | 24 ++-- src/switch_ivr_bridge.c | 31 +++++ 10 files changed, 200 insertions(+), 15 deletions(-) diff --git a/src/include/private/switch_core_pvt.h b/src/include/private/switch_core_pvt.h index e77d5f74ef..6a9bdc35a0 100644 --- a/src/include/private/switch_core_pvt.h +++ b/src/include/private/switch_core_pvt.h @@ -167,6 +167,7 @@ struct switch_core_session { uint32_t track_id; switch_log_level_t loglevel; uint32_t soft_lock; + switch_ivr_dmachine_t *dmachine; }; struct switch_media_bug { diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 466dc51186..04991ed186 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -704,7 +704,8 @@ SWITCH_DECLARE(switch_log_level_t) switch_core_session_get_loglevel(switch_core_ SWITCH_DECLARE(void) switch_core_session_soft_lock(switch_core_session_t *session, uint32_t sec); SWITCH_DECLARE(void) switch_core_session_soft_unlock(switch_core_session_t *session); - +SWITCH_DECLARE(void) switch_core_session_set_dmachine(switch_core_session_t *session, switch_ivr_dmachine_t *dmachine); +SWITCH_DECLARE(switch_ivr_dmachine_t *) switch_core_session_get_dmachine(switch_core_session_t *session); /*! \brief Retrieve the unique identifier from the core diff --git a/src/include/switch_ivr.h b/src/include/switch_ivr.h index ac9d8f9c1b..1fed73ca67 100644 --- a/src/include/switch_ivr.h +++ b/src/include/switch_ivr.h @@ -557,6 +557,7 @@ SWITCH_DECLARE(uint32_t) switch_ivr_schedule_broadcast(time_t runtime, const cha \return SWITCH_STATUS_SUCCESS if all is well */ SWITCH_DECLARE(switch_status_t) switch_ivr_broadcast(const char *uuid, const char *path, switch_media_flag_t flags); +SWITCH_DECLARE(void) switch_ivr_broadcast_in_thread(switch_core_session_t *session, const char *app, int flags); /*! \brief Transfer variables from one session to another diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 5aecca7498..d67d972e92 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -1057,6 +1057,7 @@ typedef enum { CF_MEDIA_SET, CF_CONSUME_ON_ORIGINATE, CF_PASSTHRU_PTIME_MISMATCH, + CF_BRIDGE_NOWRITE, /* 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 9fb6b1b454..675cde4884 100755 --- a/src/mod/applications/mod_dptools/mod_dptools.c +++ b/src/mod/applications/mod_dptools/mod_dptools.c @@ -95,6 +95,120 @@ SWITCH_STANDARD_DIALPLAN(inline_dialplan_hunt) return extension; } +struct action_binding { + char *input; + char *string; + char *value; + switch_core_session_t *session; +}; + +static switch_status_t digit_action_callback(switch_ivr_dmachine_match_t *match) +{ + struct action_binding *act = (struct action_binding *) match->user_data; + switch_event_t *event; + switch_status_t status; + int exec = 0; + char *string = act->string; + switch_channel_t *channel = switch_core_session_get_channel(act->session); + + if (switch_event_create_plain(&event, SWITCH_EVENT_CHANNEL_DATA) == SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(act->session), SWITCH_LOG_DEBUG, "%s Digit match binding [%s][%s]\n", + switch_channel_get_name(channel), act->string, act->value); + + if (!strncasecmp(string, "exec:", 5)) { + string += 5; + exec = 1; + } + + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, string, act->value); + + if (exec) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "execute", exec == 2 ? "non-blocking" : "blocking"); + } + + if ((status = switch_core_session_queue_event(act->session, &event)) != SWITCH_STATUS_SUCCESS) { + switch_event_destroy(&event); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(act->session), SWITCH_LOG_WARNING, "%s event queue faiure.\n", + switch_core_session_get_name(act->session)); + } + } + + if (exec) { + char *cmd = switch_core_session_sprintf(act->session, "%s::%s", string, act->value); + switch_ivr_broadcast_in_thread(act->session, cmd, SMF_ECHO_ALEG|SMF_HOLD_BLEG); + } + + return SWITCH_STATUS_SUCCESS; +} + +#define CLEAR_DIGIT_ACTION_USAGE "" +SWITCH_STANDARD_APP(clear_digit_action_function) +{ + //switch_channel_t *channel = switch_core_session_get_channel(session); + switch_ivr_dmachine_t *dmachine; + + if ((dmachine = switch_core_session_get_dmachine(session))) { + switch_core_session_set_dmachine(session, NULL); + switch_ivr_dmachine_destroy(&dmachine); + } +} + +#define BIND_DIGIT_ACTION_USAGE ",," +SWITCH_STANDARD_APP(bind_digit_action_function) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_ivr_dmachine_t *dmachine; + char *mydata; + int argc = 0; + char *argv[3] = { 0 }; + struct action_binding *act; + + if (zstr(data)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Syntax Error, USAGE %s\n", BIND_DIGIT_ACTION_USAGE); + return; + } + + if (!(dmachine = switch_core_session_get_dmachine(session))) { + uint32_t digit_timeout = 1500; + uint32_t input_timeout = 0; + const char *var; + uint32_t tmp; + + if ((var = switch_channel_get_variable(channel, "bind_digit_digit_timeout"))) { + tmp = (uint32_t) atol(var); + if (tmp < 0) tmp = 0; + digit_timeout = tmp; + } + + if ((var = switch_channel_get_variable(channel, "bind_digit_input_timeout"))) { + tmp = (uint32_t) atol(var); + if (tmp < 0) tmp = 0; + input_timeout = tmp; + } + + switch_ivr_dmachine_create(&dmachine, NULL, digit_timeout, input_timeout); + switch_core_session_set_dmachine(session, dmachine); + } + + mydata = switch_core_session_strdup(session, data); + + argc = switch_separate_string(mydata, ',', argv, (sizeof(argv) / sizeof(argv[0]))); + + if (argc < 3 || zstr(argv[0]) || zstr(argv[1]) || zstr(argv[2])) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Syntax Error, USAGE %s\n", BIND_DIGIT_ACTION_USAGE); + return; + } + + act = switch_core_session_alloc(session, sizeof(*act)); + act->input = argv[0]; + act->string = argv[1]; + act->value = argv[2]; + act->session = session; + + switch_ivr_dmachine_bind(dmachine, act->input, 0, digit_action_callback, act); +} + + #define DETECT_SPEECH_SYNTAX " [] OR grammar [] OR pause OR resume" SWITCH_STANDARD_APP(detect_speech_function) { @@ -3277,6 +3391,14 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load) SWITCH_ADD_API(api_interface, "chat", "chat", chat_api_function, "||||[]"); SWITCH_ADD_API(api_interface, "strftime", "strftime", strftime_api_function, ""); SWITCH_ADD_API(api_interface, "presence", "presence", presence_api_function, PRESENCE_USAGE); + + SWITCH_ADD_APP(app_interface, "bind_digit_action", "bind a key sequence or regex to an action", + "bind a key sequence or regex to an action", bind_digit_action_function, BIND_DIGIT_ACTION_USAGE, SAF_SUPPORT_NOMEDIA); + + SWITCH_ADD_APP(app_interface, "clear_digit_action", "clear all digit bindings", "", + clear_digit_action_function, CLEAR_DIGIT_ACTION_USAGE, SAF_SUPPORT_NOMEDIA); + + SWITCH_ADD_APP(app_interface, "privacy", "Set privacy on calls", "Set caller privacy on calls.", privacy_function, "off|on|name|full|number", SAF_SUPPORT_NOMEDIA); diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 4007187e26..0d69bdb4bb 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -5077,7 +5077,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, } if (channel) { - if (sofia_test_flag(tech_pvt, TFLAG_EARLY_MEDIA)) { + if (sofia_test_flag(tech_pvt, TFLAG_EARLY_MEDIA) && !sofia_test_flag(tech_pvt, TFLAG_ANS)) { sofia_set_flag_locked(tech_pvt, TFLAG_ANS); sofia_set_flag(tech_pvt, TFLAG_SDP); switch_channel_mark_answered(channel); diff --git a/src/switch_core_io.c b/src/switch_core_io.c index 4ca8b2d8cb..15b8f417d4 100644 --- a/src/switch_core_io.c +++ b/src/switch_core_io.c @@ -126,7 +126,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi switch_mutex_lock(session->read_codec->mutex); top: - + + if (session->dmachine && !switch_channel_test_flag(session->channel, CF_BROADCAST)) { + switch_ivr_dmachine_ping(session->dmachine, NULL); + } + if (switch_channel_down(session->channel) || !switch_core_codec_ready(session->read_codec)) { *frame = NULL; status = SWITCH_STATUS_FALSE; @@ -1150,6 +1154,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_recv_dtmf(switch_core_sessio switch_io_event_hook_recv_dtmf_t *ptr; switch_status_t status; switch_dtmf_t new_dtmf; + int fed = 0; if (switch_channel_down(session->channel)) { return SWITCH_STATUS_FALSE; @@ -1171,12 +1176,19 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_recv_dtmf(switch_core_sessio new_dtmf.duration = switch_core_default_dtmf_duration(0); } + if (session->dmachine && !switch_channel_test_flag(session->channel, CF_BROADCAST)) { + char str[2] = { dtmf->digit, '\0' }; + switch_ivr_dmachine_feed(session->dmachine, str, NULL); + fed = 1; + } + for (ptr = session->event_hooks.recv_dtmf; ptr; ptr = ptr->next) { if ((status = ptr->recv_dtmf(session, &new_dtmf, SWITCH_DTMF_RECV)) != SWITCH_STATUS_SUCCESS) { return status; } } - return SWITCH_STATUS_SUCCESS; + + return fed ? SWITCH_STATUS_FALSE : SWITCH_STATUS_SUCCESS; } SWITCH_DECLARE(switch_status_t) switch_core_session_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf) diff --git a/src/switch_core_session.c b/src/switch_core_session.c index 9e942fea5e..c8aca7dbc6 100644 --- a/src/switch_core_session.c +++ b/src/switch_core_session.c @@ -38,6 +38,16 @@ struct switch_session_manager session_manager; +SWITCH_DECLARE(void) switch_core_session_set_dmachine(switch_core_session_t *session, switch_ivr_dmachine_t *dmachine) +{ + session->dmachine = dmachine; +} + +SWITCH_DECLARE(switch_ivr_dmachine_t *) switch_core_session_get_dmachine(switch_core_session_t *session) +{ + return session->dmachine; +} + SWITCH_DECLARE(void) switch_core_session_soft_lock(switch_core_session_t *session, uint32_t sec) { session->soft_lock = sec; @@ -1094,6 +1104,10 @@ SWITCH_DECLARE(void) switch_core_session_perform_destroy(switch_core_session_t * switch_ivr_clear_speech_cache(*session); switch_channel_uninit((*session)->channel); + if ((*session)->dmachine) { + switch_ivr_dmachine_destroy(&(*session)->dmachine); + } + pool = (*session)->pool; //#ifndef NDEBUG //memset(*session, 0, sizeof(switch_core_session_t)); diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c index 04972b3efa..57b4569346 100644 --- a/src/switch_ivr_async.c +++ b/src/switch_ivr_async.c @@ -150,10 +150,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_bind(switch_ivr_dmachine_t * } if (binding->is_regex) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "binding regex: %s key: %.4d callback: %p data: %p\n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "binding regex: %s key: %.4d callback: %p data: %p\n", digits, key, (void *)(intptr_t) callback, user_data); } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "binding digits: %4s key: %.4d callback: %p data: %p\n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "binding digits: %4s key: %.4d callback: %p data: %p\n", digits, key, (void *)(intptr_t) callback, user_data); } @@ -264,27 +264,25 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_ping(switch_ivr_dmachine_t * switch_bool_t is_timeout = switch_ivr_dmachine_check_timeout(dmachine); dm_match_t is_match = switch_ivr_dmachine_check_match(dmachine, is_timeout); switch_status_t r; - + int exec = 0; + if (zstr(dmachine->digits) && !is_timeout) { r = SWITCH_STATUS_SUCCESS; } else if (dmachine->cur_digit_len > dmachine->max_digit_len) { r = SWITCH_STATUS_FALSE; } else if (is_match == DM_MATCH_EXACT || (is_match == DM_MATCH_BOTH && is_timeout)) { r = SWITCH_STATUS_FOUND; - + dmachine->match.match_digits = dmachine->last_matching_digits; dmachine->match.match_key = dmachine->last_matching_binding->key; dmachine->match.user_data = dmachine->last_matching_binding->user_data; - - if (dmachine->last_matching_binding->callback) { - dmachine->last_matching_binding->callback(&dmachine->match); - } - + if (match_p) { *match_p = &dmachine->match; } dmachine->is_match = 1; + exec = 1; } else if (is_timeout) { r = SWITCH_STATUS_TIMEOUT; } else if (dmachine->cur_digit_len == dmachine->max_digit_len) { @@ -297,6 +295,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_ping(switch_ivr_dmachine_t * switch_ivr_dmachine_clear(dmachine); } + if (exec && dmachine->last_matching_binding->callback) { + dmachine->last_matching_binding->callback(&dmachine->match); + } + return r; } @@ -2501,7 +2503,7 @@ static void *SWITCH_THREAD_FUNC bcast_thread(switch_thread_t *thread, void *obj) return NULL; } -static void broadcast_in_thread(switch_core_session_t *session, const char *app, int flags) +SWITCH_DECLARE(void) switch_ivr_broadcast_in_thread(switch_core_session_t *session, const char *app, int flags) { switch_thread_t *thread; switch_threadattr_t *thd_attr = NULL; @@ -2606,7 +2608,7 @@ static switch_status_t meta_on_dtmf(switch_core_session_t *session, const switch switch_channel_get_name(channel), dtmf->digit, md->sr[direction].map[dval].app); if (switch_channel_test_flag(channel, CF_PROXY_MODE)) { - broadcast_in_thread(session, md->sr[direction].map[dval].app, flags | SMF_REBRIDGE); + switch_ivr_broadcast_in_thread(session, md->sr[direction].map[dval].app, flags | SMF_REBRIDGE); } else { switch_ivr_broadcast(switch_core_session_get_uuid(session), md->sr[direction].map[dval].app, flags); } diff --git a/src/switch_ivr_bridge.c b/src/switch_ivr_bridge.c index f92e254008..165df886fd 100644 --- a/src/switch_ivr_bridge.c +++ b/src/switch_ivr_bridge.c @@ -468,6 +468,10 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj) continue; } + if (switch_channel_test_flag(chan_a, CF_BRIDGE_NOWRITE)) { + continue; + } + if (status != SWITCH_STATUS_BREAK && !switch_channel_test_flag(chan_a, CF_HOLD)) { if (switch_core_session_write_frame(session_b, read_frame, SWITCH_IO_FLAG_NONE, stream_id) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, @@ -839,13 +843,26 @@ static switch_status_t hanguphook(switch_core_session_t *session) { switch_core_session_message_t msg = { 0 }; switch_channel_t *channel = NULL; + switch_event_t *event; + switch_channel_state_t state; channel = switch_core_session_get_channel(session); + state = switch_channel_get_state(channel); msg.message_id = SWITCH_MESSAGE_INDICATE_UNBRIDGE; msg.from = __FILE__; msg.string_arg = switch_channel_get_variable(channel, SWITCH_SIGNAL_BRIDGE_VARIABLE); + if (state == CS_ROUTING) { + if (switch_channel_test_flag(channel, CF_BRIDGE_ORIGINATOR)) { + switch_channel_clear_flag_recursive(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); + } + } + } + switch_core_session_receive_message(session, &msg); switch_core_event_hook_remove_state_change(session, hanguphook); @@ -859,6 +876,7 @@ static switch_status_t signal_bridge_on_hibernate(switch_core_session_t *session const char *key; switch_core_session_message_t msg = { 0 }; switch_event_t *event = NULL; + switch_ivr_dmachine_t *dmachine; channel = switch_core_session_get_channel(session); switch_assert(channel != NULL); @@ -886,6 +904,19 @@ static switch_status_t signal_bridge_on_hibernate(switch_core_session_t *session } } + if ((dmachine = switch_core_session_get_dmachine(session))) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, + "%s not hibernating due to active digit parser, semi-hibernation engaged.\n", switch_channel_get_name(channel)); + + while(switch_channel_ready(channel) && switch_channel_get_state(channel) == CS_HIBERNATE) { + if (!switch_channel_test_flag(channel, CF_BROADCAST)) { + switch_ivr_dmachine_ping(dmachine, NULL); + } + switch_yield(20000); + } + } + + return SWITCH_STATUS_SUCCESS; }