256 lines
7.5 KiB
C
Raw Normal View History

/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
2014-02-05 15:02:28 -06:00
* Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Marc Olivier Chouinard <mochouinard@moctel.com>
*
*
* ivr.c -- VoiceMail IVR Engone
*
*/
#include <switch.h>
#include "ivr.h"
static int match_dtmf(switch_core_session_t *session, ivre_data_t *loc) {
switch_bool_t is_invalid[128] = { SWITCH_FALSE };
int i;
loc->potentialMatch = NULL;
loc->completeMatch = NULL;
loc->potentialMatchCount = 0;
for (i = 0; i < 16 && i < loc->dtmf_received; i++) {
int j;
loc->potentialMatchCount = 0;
for (j = 0; j < 128 && !zstr(loc->dtmf_accepted[j]); j++) {
switch_bool_t cMatch = SWITCH_FALSE;
char test[2] = { 0 };
if (is_invalid[j])
continue;
test[0] = loc->dtmf_stored[i];
if (loc->dtmf_accepted[j][i] == 'N' && atoi(test) >= 2 && atoi(test) <= 9)
cMatch = SWITCH_TRUE;
if (loc->dtmf_accepted[j][i] == 'X' && atoi(test) >= 0 && atoi(test) <= 9) {
cMatch = SWITCH_TRUE;
}
if (i >= strlen(loc->dtmf_accepted[j]) - 1 && loc->dtmf_accepted[j][strlen(loc->dtmf_accepted[j])-1] == '.')
cMatch = SWITCH_TRUE;
if (loc->dtmf_accepted[j][i] == loc->dtmf_stored[i])
cMatch = SWITCH_TRUE;
if (cMatch == SWITCH_FALSE) {
is_invalid[j] = SWITCH_TRUE;
continue;
}
if (i == strlen(loc->dtmf_accepted[j]) - 1 && loc->dtmf_accepted[j][strlen(loc->dtmf_accepted[j])-1] == '.') {
loc->completeMatch = loc->dtmf_accepted[j];
}
if (i == loc->dtmf_received - 1 && loc->dtmf_received == strlen(loc->dtmf_accepted[j]) && loc->dtmf_accepted[j][strlen(loc->dtmf_accepted[j])-1] != '.') {
loc->completeMatch = loc->dtmf_accepted[j];
continue;
}
loc->potentialMatchCount++;
}
}
return 1;
}
static switch_status_t cb_on_dtmf_ignore(switch_core_session_t *session, void *input, switch_input_type_t itype, void *buf, unsigned int buflen)
{
switch (itype) {
case SWITCH_INPUT_TYPE_DTMF:
{
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_dtmf_t *dtmf = (switch_dtmf_t *) input;
switch_channel_queue_dtmf(channel, dtmf);
return SWITCH_STATUS_BREAK;
}
default:
break;
}
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t cb_on_dtmf(switch_core_session_t *session, void *input, switch_input_type_t itype, void *buf, unsigned int buflen)
{
ivre_data_t *loc = (ivre_data_t*) buf;
switch (itype) {
case SWITCH_INPUT_TYPE_DTMF:
{
switch_dtmf_t *dtmf = (switch_dtmf_t *) input;
switch_bool_t audio_was_stopped = loc->audio_stopped;
loc->audio_stopped = SWITCH_TRUE;
if (loc->dtmf_received >= sizeof(loc->dtmf_stored)) {
loc->result = RES_BUFFER_OVERFLOW;
break;
}
if (!loc->terminate_key || dtmf->digit != loc->terminate_key)
loc->dtmf_stored[loc->dtmf_received++] = dtmf->digit;
match_dtmf(session, loc);
if (loc->terminate_key && dtmf->digit == loc->terminate_key && loc->result == RES_WAITFORMORE) {
if (loc->potentialMatchCount == 1 && loc->completeMatch != NULL) {
loc->result = RES_FOUND;
} else {
loc->result = RES_INVALID;
}
return SWITCH_STATUS_BREAK;
} else {
if (loc->potentialMatchCount == 0 && loc->completeMatch != NULL) {
loc->result = RES_FOUND;
return SWITCH_STATUS_BREAK;
} else if (loc->potentialMatchCount > 0) {
loc->result = RES_WAITFORMORE;
if (!audio_was_stopped)
return SWITCH_STATUS_BREAK;
} else {
loc->result = RES_INVALID;
return SWITCH_STATUS_BREAK;
}
}
}
break;
default:
break;
}
return SWITCH_STATUS_SUCCESS;
}
switch_status_t ivre_init(ivre_data_t *loc, char **dtmf_accepted) {
int i;
memset(loc, 0, sizeof(*loc));
for (i = 0; dtmf_accepted[i] && i < 16; i++) {
strncpy(loc->dtmf_accepted[i], dtmf_accepted[i], 128);
}
loc->record_tone = "%(1000, 0, 640)";
return SWITCH_STATUS_SUCCESS;
}
switch_status_t ivre_playback_dtmf_buffered(switch_core_session_t *session, const char *macro_name, const char *data, switch_event_t *event, const char *lang, int timeout) {
switch_status_t status = SWITCH_STATUS_SUCCESS;
switch_channel_t *channel = switch_core_session_get_channel(session);
if (switch_channel_ready(channel)) {
switch_input_args_t args = { 0 };
args.input_callback = cb_on_dtmf_ignore;
if (macro_name) {
status = switch_ivr_phrase_macro_event(session, macro_name, data, event, lang, &args);
}
} else {
status = SWITCH_STATUS_BREAK;
}
return status;
}
switch_status_t ivre_playback(switch_core_session_t *session, ivre_data_t *loc, const char *macro_name, const char *data, switch_event_t *event, const char *lang, int timeout) {
switch_status_t status = SWITCH_STATUS_SUCCESS;
switch_channel_t *channel = switch_core_session_get_channel(session);
if (switch_channel_ready(channel)) {
switch_input_args_t args = { 0 };
args.input_callback = cb_on_dtmf;
args.buf = loc;
if (macro_name && loc->audio_stopped == SWITCH_FALSE && loc->result == RES_WAITFORMORE) {
status = switch_ivr_phrase_macro_event(session, macro_name, data, event, lang, &args);
}
if (switch_channel_ready(channel) && (status == SWITCH_STATUS_SUCCESS || status == SWITCH_STATUS_BREAK) && timeout && loc->result == RES_WAITFORMORE) {
loc->audio_stopped = SWITCH_TRUE;
switch_ivr_collect_digits_callback(session, &args, timeout, 0);
if (loc->result == RES_WAITFORMORE) {
if (loc->potentialMatchCount == 1 && loc->completeMatch != NULL) {
loc->result = RES_FOUND;
} else {
loc->result = RES_TIMEOUT;
}
}
}
} else {
status = SWITCH_STATUS_BREAK;
}
return status;
}
switch_status_t ivre_record(switch_core_session_t *session, ivre_data_t *loc, switch_event_t *event, const char *file_path, switch_file_handle_t *fh, int max_record_len, switch_size_t *record_len) {
switch_status_t status = SWITCH_STATUS_SUCCESS;
switch_channel_t *channel = switch_core_session_get_channel(session);
if (switch_channel_ready(channel)) {
switch_input_args_t args = { 0 };
args.input_callback = cb_on_dtmf;
args.buf = loc;
if (loc->audio_stopped == SWITCH_FALSE && loc->result == RES_WAITFORMORE) {
loc->recorded_audio = SWITCH_TRUE;
switch_ivr_gentones(session, loc->record_tone, 0, NULL);
status = switch_ivr_record_file(session, fh, file_path, &args, max_record_len);
if (record_len) {
*record_len = fh->samples_out / (fh->samplerate ? fh->samplerate : 8000);
}
}
if (loc->result == RES_WAITFORMORE) {
loc->result = RES_TIMEOUT;
}
} else {
status = SWITCH_STATUS_BREAK;
}
return status;
}
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet
*/