diff --git a/src/include/private/switch_core_pvt.h b/src/include/private/switch_core_pvt.h index 423969fac8..af82f1e88d 100644 --- a/src/include/private/switch_core_pvt.h +++ b/src/include/private/switch_core_pvt.h @@ -169,7 +169,7 @@ struct switch_core_session { uint32_t track_id; switch_log_level_t loglevel; uint32_t soft_lock; - switch_ivr_dmachine_t *dmachine; + switch_ivr_dmachine_t *dmachine[2]; plc_state_t *plc; }; diff --git a/src/include/switch_core.h b/src/include/switch_core.h index f6e611b91f..562262c82d 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -712,12 +712,12 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_set_loglevel(switch_core_ses \return the log level */ SWITCH_DECLARE(switch_log_level_t) switch_core_session_get_loglevel(switch_core_session_t *session); - + 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); +SWITCH_DECLARE(void) switch_core_session_set_dmachine(switch_core_session_t *session, switch_ivr_dmachine_t *dmachine, switch_digit_action_target_t target); +SWITCH_DECLARE(switch_ivr_dmachine_t *) switch_core_session_get_dmachine(switch_core_session_t *session, switch_digit_action_target_t target); SWITCH_DECLARE(switch_digit_action_target_t) switch_ivr_dmachine_get_target(switch_ivr_dmachine_t *dmachine); SWITCH_DECLARE(void) switch_ivr_dmachine_set_target(switch_ivr_dmachine_t *dmachine, switch_digit_action_target_t target); diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 7eb27d2c45..312e0bd342 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -223,7 +223,8 @@ typedef enum { typedef enum { DIGIT_TARGET_SELF, - DIGIT_TARGET_PEER + DIGIT_TARGET_PEER, + DIGIT_TARGET_BOTH } switch_digit_action_target_t; diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c index 02c64d8093..5e9dc13ef6 100755 --- a/src/mod/applications/mod_dptools/mod_dptools.c +++ b/src/mod/applications/mod_dptools/mod_dptools.c @@ -102,6 +102,7 @@ struct action_binding { char *input; char *string; char *value; + switch_digit_action_target_t target; switch_core_session_t *session; }; @@ -160,13 +161,19 @@ static switch_status_t digit_action_callback(switch_ivr_dmachine_match_t *match) char *string = act->string; switch_channel_t *channel; switch_core_session_t *use_session = act->session; - - if (switch_ivr_dmachine_get_target(match->dmachine) == DIGIT_TARGET_PEER) { + int x = 0; + if (switch_ivr_dmachine_get_target(match->dmachine) == DIGIT_TARGET_PEER || act->target == DIGIT_TARGET_PEER || act->target == DIGIT_TARGET_BOTH) { if (switch_core_session_get_partner(act->session, &use_session) != SWITCH_STATUS_SUCCESS) { use_session = act->session; } } + top: + x++; + + string = act->string; + exec = 0; + channel = switch_core_session_get_channel(use_session); switch_channel_set_variable(channel, "last_matching_digits", match->match_digits); @@ -197,28 +204,53 @@ static switch_status_t digit_action_callback(switch_ivr_dmachine_match_t *match) if (exec) { char *cmd = switch_core_session_sprintf(use_session, "%s::%s", string, act->value); - switch_ivr_broadcast_in_thread(use_session, cmd, SMF_ECHO_ALEG|SMF_HOLD_BLEG); + switch_ivr_broadcast_in_thread(use_session, cmd, SMF_ECHO_ALEG | (act->target == DIGIT_TARGET_BOTH ? 0 : SMF_HOLD_BLEG)); } if (use_session != act->session) { switch_core_session_rwunlock(use_session); - } + if (act->target == DIGIT_TARGET_BOTH) { + use_session = act->session; + goto top; + } + } return SWITCH_STATUS_SUCCESS; } -#define CLEAR_DIGIT_ACTION_USAGE "|all" +static switch_digit_action_target_t str2target(const char *target_str) +{ + if (!strcasecmp(target_str, "peer")) { + return DIGIT_TARGET_PEER; + } + + if (!strcasecmp(target_str, "both")) { + return DIGIT_TARGET_BOTH; + } + + return DIGIT_TARGET_SELF; +} + +#define CLEAR_DIGIT_ACTION_USAGE "|all[,target]" SWITCH_STANDARD_APP(clear_digit_action_function) { //switch_channel_t *channel = switch_core_session_get_channel(session); switch_ivr_dmachine_t *dmachine; - char *realm = (char *) data; + char *realm = switch_core_session_strdup(session, data); + char *target_str; + switch_digit_action_target_t target = DIGIT_TARGET_SELF; - if ((dmachine = switch_core_session_get_dmachine(session))) { + if ((target_str = strchr(realm, ' '))) { + *target_str++ = '\0'; + target = str2target(target_str); + } + + + if ((dmachine = switch_core_session_get_dmachine(session, target))) { if (zstr(realm) || !strcasecmp(realm, "all")) { - switch_core_session_set_dmachine(session, NULL); + switch_core_session_set_dmachine(session, NULL, target); switch_ivr_dmachine_destroy(&dmachine); } else { switch_ivr_dmachine_clear_realm(dmachine, realm); @@ -226,73 +258,40 @@ SWITCH_STANDARD_APP(clear_digit_action_function) } } -#define DIGIT_ACTION_SET_REALM_USAGE "" +#define DIGIT_ACTION_SET_REALM_USAGE "[,]" SWITCH_STANDARD_APP(digit_action_set_realm_function) { switch_ivr_dmachine_t *dmachine; - char *realm = (char *) data; + char *realm = switch_core_session_strdup(session, data); + char *target_str; + switch_digit_action_target_t target = DIGIT_TARGET_SELF; + + if ((target_str = strchr(realm, ' '))) { + *target_str++ = '\0'; + target = str2target(target_str); + } if (zstr(data)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Syntax Error, USAGE %s\n", DIGIT_ACTION_SET_REALM_USAGE); return; } - if ((dmachine = switch_core_session_get_dmachine(session))) { + if ((dmachine = switch_core_session_get_dmachine(session, target))) { switch_ivr_dmachine_set_realm(dmachine, realm); } } -#define DIGIT_ACTION_SET_TARGET_USAGE "" -SWITCH_STANDARD_APP(digit_action_set_target_function) +static void bind_to_session(switch_core_session_t *session, + const char *arg0, const char *arg1, const char *arg2, const char *arg3, + switch_digit_action_target_t target, switch_digit_action_target_t bind_target) { - switch_ivr_dmachine_t *dmachine; - char *target_str = (char *) data; - - if (zstr(data)) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Syntax Error, USAGE %s\n", DIGIT_ACTION_SET_TARGET_USAGE); - return; - } - - if ((dmachine = switch_core_session_get_dmachine(session))) { - switch_digit_action_target_t target = DIGIT_TARGET_SELF; - - if (!strcasecmp(target_str, "peer")) { - target = DIGIT_TARGET_PEER; - } - - switch_ivr_dmachine_set_target(dmachine, target); - } - -} - -#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[5] = { 0 }; struct action_binding *act; + switch_ivr_dmachine_t *dmachine; + switch_channel_t *channel = switch_core_session_get_channel(session); - if (zstr(data)) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Syntax Error, USAGE %s\n", BIND_DIGIT_ACTION_USAGE); - return; - } - - mydata = switch_core_session_strdup(session, data); - - argc = switch_separate_string(mydata, ',', argv, (sizeof(argv) / sizeof(argv[0]))); - - if (argc < 4 || zstr(argv[0]) || zstr(argv[1]) || zstr(argv[2]) || zstr(argv[3])) { - 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))) { + if (!(dmachine = switch_core_session_get_dmachine(session, target))) { uint32_t digit_timeout = 1500; uint32_t input_timeout = 0; const char *var; @@ -311,20 +310,69 @@ SWITCH_STANDARD_APP(bind_digit_action_function) } switch_ivr_dmachine_create(&dmachine, "DPTOOLS", NULL, digit_timeout, input_timeout, NULL, digit_nomatch_action_callback, session); - switch_core_session_set_dmachine(session, dmachine); + switch_core_session_set_dmachine(session, dmachine, target); } act = switch_core_session_alloc(session, sizeof(*act)); - act->realm = argv[0]; - act->input = argv[1]; - act->string = argv[2]; - act->value = argv[3]; + act->realm = switch_core_session_strdup(session, arg0); + act->input = switch_core_session_strdup(session, arg1); + act->string = switch_core_session_strdup(session, arg2); + act->value = switch_core_session_strdup(session, arg3); + act->target = bind_target; act->session = session; - switch_ivr_dmachine_bind(dmachine, act->realm, act->input, 0, digit_action_callback, act); } +#define BIND_DIGIT_ACTION_USAGE ",,,[,][,]" +SWITCH_STANDARD_APP(bind_digit_action_function) +{ + + char *mydata; + int argc = 0; + char *argv[6] = { 0 }; + switch_digit_action_target_t target, bind_target; + char *target_str = "self", *bind_target_str = "self"; + + if (zstr(data)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Syntax Error, USAGE %s\n", BIND_DIGIT_ACTION_USAGE); + return; + } + + mydata = switch_core_session_strdup(session, data); + + argc = switch_separate_string(mydata, ',', argv, (sizeof(argv) / sizeof(argv[0]))); + + if (argc < 4 || zstr(argv[0]) || zstr(argv[1]) || zstr(argv[2]) || zstr(argv[3])) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Syntax Error, USAGE %s\n", BIND_DIGIT_ACTION_USAGE); + return; + } + + if (argv[4]) { + target_str = argv[4]; + } + + if (argv[5]) { + bind_target_str = argv[5]; + } + + target = str2target(target_str); + bind_target = str2target(bind_target_str); + + + switch(target) { + case DIGIT_TARGET_PEER: + bind_to_session(session, argv[0], argv[1], argv[2], argv[3], DIGIT_TARGET_PEER, bind_target); + break; + case DIGIT_TARGET_BOTH: + bind_to_session(session, argv[0], argv[1], argv[2], argv[3], DIGIT_TARGET_PEER, bind_target); + bind_to_session(session, argv[0], argv[1], argv[2], argv[3], DIGIT_TARGET_SELF, bind_target); + break; + default: + bind_to_session(session, argv[0], argv[1], argv[2], argv[3], DIGIT_TARGET_SELF, bind_target); + break; + } +} #define DETECT_SPEECH_SYNTAX " [] OR grammar [] OR nogrammar OR grammaron/grammaroff OR grammarsalloff OR pause OR resume OR start_input_timers OR stop OR param " SWITCH_STANDARD_APP(detect_speech_function) @@ -3844,10 +3892,6 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load) SWITCH_ADD_APP(app_interface, "digit_action_set_realm", "change binding realm", "", digit_action_set_realm_function, DIGIT_ACTION_SET_REALM_USAGE, SAF_SUPPORT_NOMEDIA); - SWITCH_ADD_APP(app_interface, "digit_action_set_target", "change binding target", "", - digit_action_set_target_function, DIGIT_ACTION_SET_TARGET_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/switch_core_io.c b/src/switch_core_io.c index 3a30cdaf74..c2b8c4608f 100644 --- a/src/switch_core_io.c +++ b/src/switch_core_io.c @@ -107,6 +107,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi int need_codec, perfect, do_bugs = 0, do_resample = 0, is_cng = 0; switch_codec_implementation_t codec_impl; unsigned int flag = 0; + int i; switch_assert(session != NULL); @@ -146,8 +147,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi top: - if (session->dmachine && !switch_channel_test_flag(session->channel, CF_BROADCAST)) { - switch_ivr_dmachine_ping(session->dmachine, NULL); + for(i = 0; i < 2; i++) { + if (session->dmachine[i] && !switch_channel_test_flag(session->channel, CF_BROADCAST)) { + switch_ivr_dmachine_ping(session->dmachine[i], NULL); + } } if (switch_channel_down(session->channel) || !switch_core_codec_ready(session->read_codec)) { @@ -1273,7 +1276,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_recv_dtmf(switch_core_sessio switch_status_t status; switch_dtmf_t new_dtmf; int fed = 0; - + if (switch_channel_down(session->channel)) { return SWITCH_STATUS_FALSE; } @@ -1295,10 +1298,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_recv_dtmf(switch_core_sessio } if (!switch_test_flag(dtmf, DTMF_FLAG_SKIP_PROCESS)) { - if (session->dmachine && switch_ivr_dmachine_get_target(session->dmachine) == DIGIT_TARGET_SELF && - !switch_channel_test_flag(session->channel, CF_BROADCAST)) { + if (session->dmachine[0] && !switch_channel_test_flag(session->channel, CF_BROADCAST)) { char str[2] = { dtmf->digit, '\0' }; - switch_ivr_dmachine_feed(session->dmachine, str, NULL); + switch_ivr_dmachine_feed(session->dmachine[0], str, NULL); fed = 1; } @@ -1346,10 +1348,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_send_dtmf(switch_core_sessio } if (!switch_test_flag(dtmf, DTMF_FLAG_SKIP_PROCESS)) { - if (session->dmachine && switch_ivr_dmachine_get_target(session->dmachine) == DIGIT_TARGET_PEER && - !switch_channel_test_flag(session->channel, CF_BROADCAST)) { + if (session->dmachine[1] && !switch_channel_test_flag(session->channel, CF_BROADCAST)) { char str[2] = { new_dtmf.digit, '\0' }; - switch_ivr_dmachine_feed(session->dmachine, str, NULL); + switch_ivr_dmachine_feed(session->dmachine[1], str, NULL); return SWITCH_STATUS_SUCCESS; } } diff --git a/src/switch_core_session.c b/src/switch_core_session.c index 0cc52262f1..b3f6d15eb8 100644 --- a/src/switch_core_session.c +++ b/src/switch_core_session.c @@ -38,14 +38,25 @@ struct switch_session_manager session_manager; -SWITCH_DECLARE(void) switch_core_session_set_dmachine(switch_core_session_t *session, switch_ivr_dmachine_t *dmachine) +SWITCH_DECLARE(void) switch_core_session_set_dmachine(switch_core_session_t *session, switch_ivr_dmachine_t *dmachine, switch_digit_action_target_t target) { - session->dmachine = dmachine; + int i = (int) target; + + if (i == 0 || i == 1) { + switch_ivr_dmachine_set_target(dmachine, target); + session->dmachine[i] = dmachine; + } } -SWITCH_DECLARE(switch_ivr_dmachine_t *) switch_core_session_get_dmachine(switch_core_session_t *session) +SWITCH_DECLARE(switch_ivr_dmachine_t *) switch_core_session_get_dmachine(switch_core_session_t *session, switch_digit_action_target_t target) { - return session->dmachine; + int i = (int) target; + + if (i == 0 || i == 1) { + return session->dmachine[i]; + } + + return NULL; } SWITCH_DECLARE(void) switch_core_session_soft_lock(switch_core_session_t *session, uint32_t sec) @@ -1179,7 +1190,7 @@ SWITCH_DECLARE(void) switch_core_session_perform_destroy(switch_core_session_t * switch_memory_pool_t *pool; switch_event_t *event; switch_endpoint_interface_t *endpoint_interface = (*session)->endpoint_interface; - + int i; switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, switch_core_session_get_uuid(*session), SWITCH_LOG_NOTICE, "Close Channel %s [%s]\n", switch_channel_get_name((*session)->channel), switch_channel_state_name(switch_channel_get_state((*session)->channel))); @@ -1216,8 +1227,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); + for (i = 0; i < 2; i++) { + if ((*session)->dmachine[i]) { + switch_ivr_dmachine_destroy(&(*session)->dmachine[i]); + } } pool = (*session)->pool; diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c index fe8d9ddb1b..c99d332c7f 100644 --- a/src/switch_ivr_async.c +++ b/src/switch_ivr_async.c @@ -72,6 +72,7 @@ struct switch_ivr_dmachine { dm_binding_head_t *realm; switch_ivr_dmachine_binding_t *last_matching_binding; void *user_data; + switch_mutex_t *mutex; }; @@ -124,6 +125,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_create(switch_ivr_dmachine_t dmachine->input_timeout_ms = input_timeout_ms; dmachine->match.dmachine = dmachine; dmachine->name = switch_core_strdup(dmachine->pool, name); + switch_mutex_init(&dmachine->mutex, SWITCH_MUTEX_NESTED, dmachine->pool); switch_core_hash_init(&dmachine->binding_hash, dmachine->pool); @@ -374,7 +376,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_ping(switch_ivr_dmachine_t * dm_match_t is_match = switch_ivr_dmachine_check_match(dmachine, is_timeout); switch_status_t r, s; int clear = 0; - + + switch_mutex_lock(dmachine->mutex); + if (zstr(dmachine->digits) && !is_timeout) { r = SWITCH_STATUS_SUCCESS; } else if (dmachine->cur_digit_len > dmachine->max_digit_len) { @@ -465,6 +469,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_ping(switch_ivr_dmachine_t * switch_ivr_dmachine_clear(dmachine); } + switch_mutex_unlock(dmachine->mutex); + return r; } @@ -474,10 +480,12 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_feed(switch_ivr_dmachine_t * return SWITCH_STATUS_FALSE; } + switch_mutex_lock(dmachine->mutex); strncat(dmachine->digits, digits, dmachine->max_digit_len); + switch_mutex_unlock(dmachine->mutex); dmachine->cur_digit_len = strlen(dmachine->digits); dmachine->last_digit_time = switch_time_now(); - + return switch_ivr_dmachine_ping(dmachine, match); } diff --git a/src/switch_ivr_bridge.c b/src/switch_ivr_bridge.c index fb8b89096d..e458fe0390 100644 --- a/src/switch_ivr_bridge.c +++ b/src/switch_ivr_bridge.c @@ -897,7 +897,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; + switch_ivr_dmachine_t *dmachine[2] = { 0 }; channel = switch_core_session_get_channel(session); switch_assert(channel != NULL); @@ -927,18 +927,24 @@ static switch_status_t signal_bridge_on_hibernate(switch_core_session_t *session } } - if ((dmachine = switch_core_session_get_dmachine(session))) { + if ((dmachine[0] = switch_core_session_get_dmachine(session, DIGIT_TARGET_SELF)) || + (dmachine[1] = switch_core_session_get_dmachine(session, DIGIT_TARGET_PEER))) { 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); + if (dmachine[0]) { + switch_ivr_dmachine_ping(dmachine[0], NULL); + } + if (dmachine[1]) { + switch_ivr_dmachine_ping(dmachine[1], NULL); + } } switch_yield(20000); } } - + return SWITCH_STATUS_SUCCESS; }