diff --git a/src/mod/applications/mod_spandsp/mod_spandsp.c b/src/mod/applications/mod_spandsp/mod_spandsp.c index ecb660eabb..fd2ac7f947 100644 --- a/src/mod/applications/mod_spandsp/mod_spandsp.c +++ b/src/mod/applications/mod_spandsp/mod_spandsp.c @@ -70,11 +70,46 @@ SWITCH_STANDARD_APP(stop_dtmf_session_function) spandsp_stop_inband_dtmf_session(session); } + +SWITCH_STANDARD_APP(spandsp_fax_detect_session_function) +{ + int argc = 0; + char *argv[3] = { 0 }; + char *dupdata; + const char *app = NULL, *arg = NULL; + int timeout = 0; + + if (!zstr(data) && (dupdata = switch_core_session_strdup(session, data))) { + if ((argc = switch_split(dupdata, ' ', argv)) == 3) { + app = argv[0]; + arg = argv[1]; + timeout = atoi(argv[2]); + if (timeout < 0) { + timeout = 0; + } + } + } + + if (app) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Enabling fax detection '%s' '%s'\n", argv[0], argv[1]); + spandsp_fax_detect_session(session, "rw", timeout, 1, app, arg, NULL); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot Enable fax detection '%s' '%s'\n", argv[0], argv[1]); + } +} + +SWITCH_STANDARD_APP(spandsp_stop_fax_detect_session_function) +{ + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Disabling fax detection\n"); + spandsp_fax_stop_detect_session(session); +} + static void event_handler(switch_event_t *event) { mod_spandsp_fax_event_handler(event); } + SWITCH_STANDARD_APP(t38_gateway_function) { switch_channel_t *channel = switch_core_session_get_channel(session); @@ -83,10 +118,19 @@ SWITCH_STANDARD_APP(t38_gateway_function) int argc = 0; char *argv[2] = { 0 }; char *dupdata; - const char *direction = argv[0], *flags = argv[1]; + const char *direction = NULL, *flags = NULL; - dupdata = switch_core_session_strdup(session, data); - argc = switch_split(dupdata, ' ', argv); + if (!zstr(data) && (dupdata = switch_core_session_strdup(session, data))) { + if ((argc = switch_split(dupdata, ' ', argv))) { + if (argc > 0) { + direction = argv[0]; + } + + if (argc > 1) { + flags = argv[1]; + } + } + } if (zstr(direction) || strcasecmp(direction, "self")) { direction = "peer"; @@ -106,7 +150,8 @@ SWITCH_STANDARD_APP(t38_gateway_function) } } - switch_ivr_tone_detect_session(session, "t38", "1100.0", "rw", timeout, 1, direction, NULL, t38_gateway_start); + //switch_ivr_tone_detect_session(session, "t38", "1100.0", "rw", timeout, 1, direction, NULL, t38_gateway_start); + spandsp_fax_detect_session(session, "rw", timeout, 1, direction, NULL, t38_gateway_start); } } @@ -209,6 +254,12 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_spandsp_init) SWITCH_ADD_APP(app_interface, "spandsp_stop_dtmf", "stop inband dtmf", "Stop detecting inband dtmf.", stop_dtmf_session_function, "", SAF_NONE); SWITCH_ADD_APP(app_interface, "spandsp_start_dtmf", "Detect dtmf", "Detect inband dtmf on the session", dtmf_session_function, "", SAF_MEDIA_TAP); + SWITCH_ADD_APP(app_interface, "spandsp_start_fax_detect", "start fax detect", "start fax detect", spandsp_fax_detect_session_function, + "[ ][ ]", SAF_NONE); + + SWITCH_ADD_APP(app_interface, "spandsp_stop_fax_detect", "stop fax detect", "stop fax detect", spandsp_stop_fax_detect_session_function, "", SAF_NONE); + + mod_spandsp_fax_load(pool); mod_spandsp_codecs_load(module_interface, pool); diff --git a/src/mod/applications/mod_spandsp/mod_spandsp.h b/src/mod/applications/mod_spandsp/mod_spandsp.h index 09e816627a..7b94b55062 100644 --- a/src/mod/applications/mod_spandsp/mod_spandsp.h +++ b/src/mod/applications/mod_spandsp/mod_spandsp.h @@ -68,3 +68,9 @@ switch_status_t spandsp_inband_dtmf_session(switch_core_session_t *session); switch_status_t callprogress_detector_start(switch_core_session_t *session, const char *name); switch_status_t callprogress_detector_stop(switch_core_session_t *session); + +SWITCH_DECLARE(switch_status_t) spandsp_fax_detect_session(switch_core_session_t *session, + const char *flags, time_t timeout, + int hits, const char *app, const char *data, switch_tone_detect_callback_t callback); + +SWITCH_DECLARE(switch_status_t) spandsp_fax_stop_detect_session(switch_core_session_t *session); diff --git a/src/mod/applications/mod_spandsp/mod_spandsp_fax.c b/src/mod/applications/mod_spandsp/mod_spandsp_fax.c index 1ea2fd790f..620971b307 100644 --- a/src/mod/applications/mod_spandsp/mod_spandsp_fax.c +++ b/src/mod/applications/mod_spandsp/mod_spandsp_fax.c @@ -1806,6 +1806,250 @@ switch_bool_t t38_gateway_start(switch_core_session_t *session, const char *app, return SWITCH_FALSE; } +typedef struct { + char *app; + char *data; + char *key; + int up; + int total_hits; + int hits; + int sleep; + int expires; + int default_sleep; + int default_expires; + switch_tone_detect_callback_t callback; + modem_connect_tones_rx_state_t rx_tones; + + switch_media_bug_t *bug; + switch_core_session_t *session; + int bug_running; + +} spandsp_fax_tone_container_t; + +static switch_status_t tone_on_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf, switch_dtmf_direction_t direction) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + spandsp_fax_tone_container_t *cont = switch_channel_get_private(channel, "_fax_tone_detect_"); + + + if (!cont || dtmf->digit != 'f') { + return SWITCH_STATUS_SUCCESS; + } + + if (cont->callback) { + cont->callback(cont->session, cont->app, cont->data); + } else { + switch_channel_execute_on(switch_core_session_get_channel(cont->session), "execute_on_fax_detect"); + if (cont->app) { + switch_core_session_execute_application_async(cont->session, cont->app, cont->data); + } + } + + return SWITCH_STATUS_SUCCESS; + +} + + +static switch_bool_t tone_detect_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type) +{ + spandsp_fax_tone_container_t *cont = (spandsp_fax_tone_container_t *) user_data; + switch_frame_t *frame = NULL; + switch_bool_t rval = SWITCH_TRUE; + + switch (type) { + case SWITCH_ABC_TYPE_INIT: + if (cont) { + cont->bug_running = 1; + modem_connect_tones_rx_init(&cont->rx_tones, MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE, NULL, NULL); + } + break; + case SWITCH_ABC_TYPE_CLOSE: + break; + case SWITCH_ABC_TYPE_READ_REPLACE: + case SWITCH_ABC_TYPE_WRITE_REPLACE: + { + int skip = 0; + + if (type == SWITCH_ABC_TYPE_READ_REPLACE) { + frame = switch_core_media_bug_get_read_replace_frame(bug); + } else { + frame = switch_core_media_bug_get_write_replace_frame(bug); + } + + if (cont->sleep) { + cont->sleep--; + if (cont->sleep) { + skip = 1; + } + } + + if (cont->expires) { + cont->expires--; + if (!cont->expires) { + cont->hits = 0; + cont->sleep = 0; + cont->expires = 0; + } + } + + if (!cont->up) { + skip = 1; + } + + if (skip) { + return SWITCH_TRUE; + } + + cont->hits = 0; + modem_connect_tones_rx(&cont->rx_tones, frame->data, frame->samples); + cont->hits = modem_connect_tones_rx_get(&cont->rx_tones); + + if (cont->hits) { + switch_event_t *event; + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(switch_core_media_bug_get_session(bug)), SWITCH_LOG_DEBUG, + "Fax Tone Detected. [%s][%s]\n", cont->app, switch_str_nil(cont->data)); + + if (cont->callback) { + cont->callback(cont->session, cont->app, cont->data); + } else { + switch_channel_execute_on(switch_core_session_get_channel(cont->session), "execute_on_fax_detect"); + if (cont->app) { + switch_core_session_execute_application_async(cont->session, cont->app, cont->data); + } + } + + + if (switch_event_create(&event, SWITCH_EVENT_DETECTED_TONE) == SWITCH_STATUS_SUCCESS) { + switch_event_t *dup; + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Detected-Fax-Tone", "true"); + + if (switch_event_dup(&dup, event) == SWITCH_STATUS_SUCCESS) { + switch_event_fire(&dup); + } + + if (switch_core_session_queue_event(cont->session, &event) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(switch_core_media_bug_get_session(bug)), SWITCH_LOG_ERROR, + "Event queue failed!\n"); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "delivery-failure", "true"); + switch_event_fire(&event); + } + } + + rval = SWITCH_FALSE; + } + + } + break; + case SWITCH_ABC_TYPE_WRITE: + default: + break; + } + + if (rval == SWITCH_FALSE) { + cont->bug_running = 0; + } + + return rval; +} + +SWITCH_DECLARE(switch_status_t) spandsp_fax_stop_detect_session(switch_core_session_t *session) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + spandsp_fax_tone_container_t *cont = switch_channel_get_private(channel, "_fax_tone_detect_"); + + if (cont) { + switch_channel_set_private(channel, "_fax_tone_detect_", NULL); + cont->up = 0; + switch_core_media_bug_remove(session, &cont->bug); + return SWITCH_STATUS_SUCCESS; + } + return SWITCH_STATUS_FALSE; +} + +SWITCH_DECLARE(switch_status_t) spandsp_fax_detect_session(switch_core_session_t *session, + const char *flags, time_t timeout, + int hits, const char *app, const char *data, switch_tone_detect_callback_t callback) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_status_t status; + spandsp_fax_tone_container_t *cont = switch_channel_get_private(channel, "_fax_tone_detect_"); + switch_media_bug_flag_t bflags = 0; + const char *var; + switch_codec_implementation_t read_impl = { 0 }; + switch_core_session_get_read_impl(session, &read_impl); + + if (cont) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Max Tones Reached!\n"); + return SWITCH_STATUS_FALSE; + } + + if (!cont && !(cont = switch_core_session_alloc(session, sizeof(*cont)))) { + return SWITCH_STATUS_MEMERR; + } + + if (app) { + cont->app = switch_core_session_strdup(session, app); + } + + if (data) { + cont->data = switch_core_session_strdup(session, data); + } + + cont->callback = callback; + cont->up = 1; + cont->session = session; + + if (switch_channel_pre_answer(channel) != SWITCH_STATUS_SUCCESS) { + return SWITCH_STATUS_FALSE; + } + + cont->default_sleep = 25; + cont->default_expires = 250; + + if ((var = switch_channel_get_variable(channel, "fax_tone_detect_sleep"))) { + int tmp = atoi(var); + if (tmp > 0) { + cont->default_sleep = tmp; + } + } + + if ((var = switch_channel_get_variable(channel, "fax_tone_detect_expires"))) { + int tmp = atoi(var); + if (tmp > 0) { + cont->default_expires = tmp; + } + } + + if (zstr(flags)) { + bflags = SMBF_READ_REPLACE; + } else { + if (strchr(flags, 'r')) { + bflags |= SMBF_READ_REPLACE; + } else if (strchr(flags, 'w')) { + bflags |= SMBF_WRITE_REPLACE; + } + } + + bflags |= SMBF_NO_PAUSE; + + + switch_core_event_hook_add_send_dtmf(session, tone_on_dtmf); + switch_core_event_hook_add_recv_dtmf(session, tone_on_dtmf); + + + if ((status = switch_core_media_bug_add(session, "fax_tone_detect", "", + tone_detect_callback, cont, timeout, bflags, &cont->bug)) != SWITCH_STATUS_SUCCESS) { + cont->bug_running = 0; + return status; + } + + switch_channel_set_private(channel, "_fax_tone_detect_", cont); + + return SWITCH_STATUS_SUCCESS; +} + + /* For Emacs: