From 4ca73d77e0a311184b648b6b77cd8238b2645cda Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Sat, 16 Jun 2007 02:25:40 +0000 Subject: [PATCH] upgrade fax_detect to tone_detect git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@5379 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- src/include/switch_ivr.h | 17 +- src/include/switch_types.h | 4 +- .../applications/mod_commands/mod_commands.c | 56 +++- .../applications/mod_dptools/mod_dptools.c | 74 ++++-- src/switch_event.c | 2 +- src/switch_ivr_async.c | 246 ++++++++++++------ 6 files changed, 291 insertions(+), 108 deletions(-) diff --git a/src/include/switch_ivr.h b/src/include/switch_ivr.h index d4e8b51b5d..52b7f6f9e6 100644 --- a/src/include/switch_ivr.h +++ b/src/include/switch_ivr.h @@ -233,18 +233,27 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_stop_inband_dtmf_session(switch_core_ SWITCH_DECLARE(void) switch_ivr_session_echo(switch_core_session_t *session); /*! - \brief Stop looking for FAX CNG + \brief Stop looking for TONES \param session the session to stop looking \return SWITCH_STATUS_SUCCESS if all is well */ -SWITCH_DECLARE(switch_status_t) switch_ivr_stop_fax_detect_session(switch_core_session_t *session); +SWITCH_DECLARE(switch_status_t) switch_ivr_stop_tone_detect_session(switch_core_session_t *session); /*! - \brief Start looking for FAX CNG + \brief Start looking for TONES \param session the session to start looking + \param key the name of the tone. + \param tone_spec comma sep list of tone freqs + \param flags one or both of 'r' and 'w' + \param timeout timeout + \param app optional application to execute when tone is found + \param data optional data for appliaction \return SWITCH_STATUS_SUCCESS if all is well */ -SWITCH_DECLARE(switch_status_t) switch_ivr_fax_detect_session(switch_core_session_t *session); +SWITCH_DECLARE(switch_status_t) switch_ivr_tone_detect_session(switch_core_session_t *session, + const char *key, const char *tone_spec, + const char *flags, time_t timeout, + const char *app, const char *data); diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 129c5da7c1..9a0b5774e6 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -852,7 +852,7 @@ typedef enum { SWITCH_EVENT_CODEC - Codec Change SWITCH_EVENT_BACKGROUND_JOB - Background Job SWITCH_EVENT_DETECTED_SPEECH - Detected Speech - SWITCH_EVENT_DETECTED_FAX - Detected Fax CNG Tone + SWITCH_EVENT_DETECTED_TONE - Detected Tone SWITCH_EVENT_PRIVATE_COMMAND - A private command event SWITCH_EVENT_HEARTBEAT - Machine is alive SWITCH_EVENT_TRAP - Error Trap @@ -902,7 +902,7 @@ typedef enum { SWITCH_EVENT_CODEC, SWITCH_EVENT_BACKGROUND_JOB, SWITCH_EVENT_DETECTED_SPEECH, - SWITCH_EVENT_DETECTED_FAX, + SWITCH_EVENT_DETECTED_TONE, SWITCH_EVENT_PRIVATE_COMMAND, SWITCH_EVENT_HEARTBEAT, SWITCH_EVENT_TRAP, diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index c130332cf3..14f8216d79 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -276,6 +276,51 @@ done: return SWITCH_STATUS_SUCCESS; } +SWITCH_STANDARD_API(tone_detect_session_function) +{ + char *argv[6] = { 0 }; + int argc; + char *mydata = NULL; + time_t to = 0; + switch_core_session_t *rsession; + + mydata = switch_core_session_strdup(session, cmd); + if ((argc = switch_separate_string(mydata, ' ', argv, sizeof(argv) / sizeof(argv[0]))) < 3) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "INVALID ARGS!\n"); + } + + if (!(rsession = switch_core_session_locate(argv[0]))) { + stream->write_function(stream, "-Error Cannot locate session!\n"); + return SWITCH_STATUS_SUCCESS; + } + + if (argv[4]) { + uint32_t mto; + if (*argv[2] == '+') { + if ((mto = atoi(argv[3]+1)) > 0) { + to = time(NULL) + mto; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "INVALID Timeout!\n"); + goto done; + } + } else { + if ((to = atoi(argv[3])) < time(NULL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "INVALID Timeout!\n"); + to = 0; + goto done; + } + } + } + + switch_ivr_tone_detect_session(rsession, argv[1], argv[2], argv[3], to, argv[5], argv[6]); + stream->write_function(stream, "Enabling tone detection '%s' '%s' '%s'\n", argv[1], argv[2], argv[3]); + + done: + + switch_core_session_rwunlock(rsession); + + return SWITCH_STATUS_SUCCESS; +} SWITCH_STANDARD_API(sched_transfer_function) { @@ -1385,13 +1430,22 @@ static switch_api_interface_t kill_api_interface = { /*.next */ &reload_api_interface }; +static switch_api_interface_t tone_detect_session_interface = { + /*.interface_name */ "tone_Detect", + /*.desc */ "Start Tone Detection on a channel", + /*.function */ tone_detect_session_function, + /*.syntax */ + " [ ]", + /*.next */ &kill_api_interface +}; + static switch_api_interface_t originate_api_interface = { /*.interface_name */ "originate", /*.desc */ "Originate a Call", /*.function */ originate_function, /*.syntax */ " |&() [] [] [] [] []", - /*.next */ &kill_api_interface + /*.next */ &tone_detect_session_interface }; static switch_loadable_module_interface_t commands_module_interface = { diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c index 27267ea994..6e970b6665 100644 --- a/src/mod/applications/mod_dptools/mod_dptools.c +++ b/src/mod/applications/mod_dptools/mod_dptools.c @@ -664,20 +664,45 @@ static void stop_dtmf_session_function(switch_core_session_t *session, char *dat static void fax_detect_session_function(switch_core_session_t *session, char *data) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Enabling fax detection\n"); - switch_ivr_fax_detect_session(session); + switch_ivr_tone_detect_session(session, "fax", "1100.0", "r", 0, NULL, NULL); } -static void system_session_function(switch_core_session_t *session, char *data) +static void tone_detect_session_function(switch_core_session_t *session, char *data) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Executing command: %s\n",data); - system(data); + char *argv[6] = { 0 }; + int argc; + char *mydata = NULL; + time_t to = 0; + + mydata = switch_core_session_strdup(session, data); + if ((argc = switch_separate_string(mydata, ' ', argv, sizeof(argv) / sizeof(argv[0]))) < 2) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "INVALID ARGS!\n"); + } + if (argv[3]) { + uint32_t mto; + if (*argv[2] == '+') { + if ((mto = atoi(argv[2]+1)) > 0) { + to = time(NULL) + mto; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "INVALID Timeout!\n"); + } + } else { + if ((to = atoi(argv[2])) < time(NULL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "INVALID Timeout!\n"); + to = 0; + } + } + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Enabling tone detection '%s' '%s'\n", argv[0], argv[1]); + + switch_ivr_tone_detect_session(session, argv[0], argv[1], argv[2], to, argv[4], argv[5]); } static void stop_fax_detect_session_function(switch_core_session_t *session, char *data) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Disabling fax detection\n"); - switch_ivr_stop_fax_detect_session(session); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Disabling tone detection\n"); + switch_ivr_stop_tone_detect_session(session); } static void echo_function(switch_core_session_t *session, char *data) @@ -1018,15 +1043,6 @@ static switch_api_interface_t presence_api_interface = { /*.next */ &dptools_api_interface }; -static switch_application_interface_t system_application_interface = { - /*.interface_name */ "system", - /*.application_function */ system_session_function, - /* long_desc */ "Execute a system command", - /* short_desc */ "Execute a system command", - /* syntax */ "", - /* flags */ SAF_NONE, - /*.next */ NULL -}; static switch_application_interface_t bridge_application_interface = { /*.interface_name */ "bridge", @@ -1034,8 +1050,7 @@ static switch_application_interface_t bridge_application_interface = { /* long_desc */ "Bridge the audio between two sessions", /* short_desc */ "Bridge Audio", /* syntax */ "", - /* flags */ SAF_SUPPORT_NOMEDIA, - /* next */ &system_application_interface + /* flags */ SAF_SUPPORT_NOMEDIA }; static switch_application_interface_t speak_application_interface = { @@ -1129,6 +1144,17 @@ static switch_application_interface_t echo_application_interface = { /*.next */ &park_application_interface }; + +static switch_application_interface_t tone_detect_application_interface = { + /*.interface_name */ "tone_detect", + /*.application_function */ tone_detect_session_function, + /* long_desc */ "Detect tones", + /* short_desc */ "Detect tones", + /* syntax */ "", + /* flags */ SAF_NONE, + /*.next */ &echo_application_interface +}; + static switch_application_interface_t fax_detect_application_interface = { /*.interface_name */ "fax_detect", /*.application_function */ fax_detect_session_function, @@ -1136,14 +1162,14 @@ static switch_application_interface_t fax_detect_application_interface = { /* short_desc */ "Detect faxes", /* syntax */ "", /* flags */ SAF_NONE, - /*.next */ &echo_application_interface + /*.next */ &tone_detect_application_interface }; -static switch_application_interface_t stop_fax_detect_application_interface = { - /*.interface_name */ "stop_fax_detect", +static switch_application_interface_t stop_tone_detect_application_interface = { + /*.interface_name */ "stop_tone_detect", /*.application_function */ stop_fax_detect_session_function, - /* long_desc */ "Stop detecting fax send tones", - /* short_desc */ "stop detecting faxes", + /* long_desc */ "Stop detecting tones", + /* short_desc */ "stop detecting tones", /* syntax */ "", /* flags */ SAF_NONE, /* next */ &fax_detect_application_interface @@ -1156,7 +1182,7 @@ static switch_application_interface_t dtmf_application_interface = { /* short_desc */ "Detect dtmf", /* syntax */ "", /* flags */ SAF_NONE, - /* next */ &stop_fax_detect_application_interface + /* next */ &stop_tone_detect_application_interface }; static switch_application_interface_t stop_dtmf_application_interface = { diff --git a/src/switch_event.c b/src/switch_event.c index 7a408108f8..3390b46989 100644 --- a/src/switch_event.c +++ b/src/switch_event.c @@ -133,7 +133,7 @@ static char *EVENT_NAMES[] = { "CODEC", "BACKGROUND_JOB", "DETECTED_SPEECH", - "DETECTED_FAX", + "DETECTED_TONE", "PRIVATE_COMMAND", "HEARTBEAT", "TRAP", diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c index afc1780dc5..0ed4c4da64 100644 --- a/src/switch_ivr_async.c +++ b/src/switch_ivr_async.c @@ -138,18 +138,18 @@ static switch_bool_t displace_callback(switch_media_bug_t *bug, void *user_data, if (dh->mux) { int16_t buf[1024]; int16_t *fp = frame->data; - int x; + uint32_t x; switch_core_file_read(&dh->fh, buf, &len); - for(x = 0; x < len; x++) { + for(x = 0; x < (uint32_t) len; x++) { int32_t mixed = fp[x] + buf[x]; switch_normalize_to_16bit(mixed); fp[x] = (int16_t) mixed; } } else { switch_core_file_read(&dh->fh, frame->data, &len); - frame->samples = len; + frame->samples = (uint32_t) len; frame->datalen = frame->samples * 2; } switch_core_media_bug_set_write_replace_frame(bug, frame); @@ -477,117 +477,211 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_inband_dtmf_session(switch_core_sessi } +#define MAX_TONES 16 typedef struct { - switch_core_session_t *session; - teletone_multi_tone_t mt; -} switch_fax_detect_t; + teletone_multi_tone_t mt; + char *app; + char *data; + char *key; + teletone_tone_map_t map; + int up; +} switch_tone_detect_t; -static switch_bool_t fax_detect_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type) + +typedef struct { + switch_tone_detect_t list[MAX_TONES+1]; + int index; + switch_media_bug_t *bug; + switch_core_session_t *session; +} switch_tone_container_t; + +static switch_bool_t tone_detect_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type) { - switch_fax_detect_t *pvt = (switch_fax_detect_t *) user_data; - uint8_t data[SWITCH_RECOMMENDED_BUFFER_SIZE]; - switch_frame_t frame = { 0 }; - // switch_channel_t *channel = switch_core_session_get_channel(pvt->session); + switch_tone_container_t *cont = (switch_tone_container_t *) user_data; + switch_frame_t *frame = NULL; + int i = 0; - // assert(channel != NULL); - frame.data = data; - frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE; + switch (type) { + case SWITCH_ABC_TYPE_INIT: + break; + case SWITCH_ABC_TYPE_CLOSE: + break; + case SWITCH_ABC_TYPE_READ_REPLACE: + frame = switch_core_media_bug_get_read_replace_frame(bug); + case SWITCH_ABC_TYPE_WRITE_REPLACE: + { - switch (type) { - case SWITCH_ABC_TYPE_INIT: - break; - case SWITCH_ABC_TYPE_CLOSE: - break; - case SWITCH_ABC_TYPE_READ: - if (switch_core_media_bug_read(bug, &frame) == SWITCH_STATUS_SUCCESS) { - if(teletone_multi_tone_detect(&pvt->mt, frame.data, frame.samples)) { - switch_event_t *event; + if (!frame) { + frame = switch_core_media_bug_get_write_replace_frame(bug); + } + + for (i = 0 ; i < cont->index; cont++) { + if (cont->list[i].up && teletone_multi_tone_detect(&cont->list[i].mt, frame->data, frame->samples)) { + switch_event_t *event; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "TONE %s DETECTED\n", cont->list[i].key); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FAX CNG DETECTED\n"); + if (cont->list[i].app) { + if (switch_event_create(&event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) { + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "call-command", "execute"); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "execute-app-name", "%s", cont->list[i].app); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "execute-app-arg", "%s", cont->list[i].data); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "lead-frames", "%d", 5); + switch_core_session_queue_private_event(cont->session, &event); + } + } - if (switch_event_create(&event, SWITCH_EVENT_DETECTED_FAX) == SWITCH_STATUS_SUCCESS) { - switch_event_t *dup; + cont->list[cont->index].up = 0; - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "fax", "detected"); + if (switch_event_create(&event, SWITCH_EVENT_DETECTED_TONE) == SWITCH_STATUS_SUCCESS) { + switch_event_t *dup; + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Detected-Tone", "%s", cont->list[i].key); + + if (switch_event_dup(&dup, event) == SWITCH_STATUS_SUCCESS) { + switch_event_fire(&dup); + } - if (switch_event_dup(&dup, event) == SWITCH_STATUS_SUCCESS) { - switch_event_fire(&dup); - } - - - if (switch_core_session_queue_event(pvt->session, &event) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Event queue failed!\n"); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "delivery-failure", "true"); - switch_event_fire(&event); - } + if (switch_core_session_queue_event(cont->session, &event) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Event queue failed!\n"); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "delivery-failure", "true"); + switch_event_fire(&event); + } + } + } + } + } + break; + case SWITCH_ABC_TYPE_WRITE: + default: + break; } - } - } - break; - case SWITCH_ABC_TYPE_WRITE: - default: - break; - } - return SWITCH_TRUE; + return SWITCH_TRUE; } -SWITCH_DECLARE(switch_status_t) switch_ivr_stop_fax_detect_session(switch_core_session_t *session) +SWITCH_DECLARE(switch_status_t) switch_ivr_stop_tone_detect_session(switch_core_session_t *session) { - switch_media_bug_t *bug; - switch_channel_t *channel = switch_core_session_get_channel(session); - - assert(channel != NULL); - if ((bug = switch_channel_get_private(channel, "fax"))) { - switch_channel_set_private(channel, "fax", NULL); - switch_core_media_bug_remove(session, &bug); - return SWITCH_STATUS_SUCCESS; - } - - return SWITCH_STATUS_FALSE; + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_tone_container_t *cont; + + assert(channel != NULL); + if ((cont = switch_channel_get_private(channel, "_tone_detect_"))) { + switch_channel_set_private(channel, "_tone_detect_", NULL); + switch_core_media_bug_remove(session, &cont->bug); + return SWITCH_STATUS_SUCCESS; + } + return SWITCH_STATUS_FALSE; + } -SWITCH_DECLARE(switch_status_t) switch_ivr_fax_detect_session(switch_core_session_t *session) +SWITCH_DECLARE(switch_status_t) switch_ivr_tone_detect_session(switch_core_session_t *session, + const char *key, const char *tone_spec, + const char *flags, time_t timeout, + const char *app, const char *data) { switch_channel_t *channel; switch_codec_t *read_codec; - switch_media_bug_t *bug; switch_status_t status; - switch_fax_detect_t *pvt; - teletone_tone_map_t *map; - int i; + switch_tone_container_t *cont = NULL; + char *p, *next; + int i = 0, ok = 0; + + switch_media_bug_flag_t bflags = 0; channel = switch_core_session_get_channel(session); assert(channel != NULL); - read_codec = switch_core_session_get_read_codec(session); assert(read_codec != NULL); + + if (switch_strlen_zero(key)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No Key Specified!\n"); + return SWITCH_STATUS_FALSE; + } + + if ((cont = switch_channel_get_private(channel, "_tone_detect_"))) { + if (cont->index >= MAX_TONES) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Max Tones Reached!\n"); + return SWITCH_STATUS_FALSE; + } - if (!(pvt = switch_core_session_alloc(session, sizeof(*pvt)))) { - return SWITCH_STATUS_MEMERR; + for(i = 0; i < cont->index; i++) { + if (!strcasecmp(key, cont->list[cont->index].key )) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Renabling %s\n", key); + cont->list[cont->index].up = 1; + teletone_multi_tone_init(&cont->list[i].mt, &cont->list[i].map); + return SWITCH_STATUS_SUCCESS; + } + } } - if (!(map = switch_core_session_alloc(session, sizeof(*map)))) { - return SWITCH_STATUS_MEMERR; + if (switch_strlen_zero(tone_spec)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No Spec Specified!\n"); + return SWITCH_STATUS_FALSE; } - for(i=0;ifreqs[i] = 1100.0; + if (!cont && !(cont = switch_core_session_alloc(session, sizeof(*cont)))) { + return SWITCH_STATUS_MEMERR; } - pvt->mt.sample_rate = read_codec->implementation->samples_per_second; - pvt->session = session; - teletone_multi_tone_init(&pvt->mt, map); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Adding tone spec %s index %d\n", tone_spec, cont->index); + i = 0; + p = (char *) tone_spec; + + do { + teletone_process_t this; + next = strchr(p, ','); + while(*p == ' ') p++; + if ((this = (teletone_process_t) atof(p))) { + ok++; + cont->list[cont->index].map.freqs[i++] = this; + } + if (next) { + p = next + 1; + } + } while (next); + + if (!ok) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid tone spec!\n"); + return SWITCH_STATUS_FALSE; + + } + + cont->list[cont->index].key = switch_core_session_strdup(session, key); + + if (app) { + cont->list[cont->index].app = switch_core_session_strdup(session, app); + } + + if (data) { + cont->list[cont->index].data = switch_core_session_strdup(session, data); + } + + cont->list[cont->index].up = 1; + cont->list[cont->index].mt.sample_rate = read_codec->implementation->samples_per_second; + teletone_multi_tone_init(&cont->list[cont->index].mt, &cont->list[cont->index].map); + cont->session = session; + switch_channel_answer(channel); - - if ((status = switch_core_media_bug_add(session, fax_detect_callback, pvt, 0, SMBF_READ_STREAM, &bug)) != SWITCH_STATUS_SUCCESS) { - return status; + + if (switch_strlen_zero(flags)) { + bflags = SMBF_READ_REPLACE; + } else { + if (strchr(flags, 'r')) { + bflags |= SMBF_READ_REPLACE; + } else if (strchr(flags, 'w')) { + bflags |= SMBF_WRITE_REPLACE; + } } - switch_channel_set_private(channel, "fax", bug); + if ((status = switch_core_media_bug_add(session, tone_detect_callback, cont, timeout, bflags, &cont->bug)) != SWITCH_STATUS_SUCCESS) { + return status; + } + switch_channel_set_private(channel, "_tone_detect_", cont); + cont->index++; + return SWITCH_STATUS_SUCCESS; }