Author: knhor Date: Sun Nov 12 16:01:45 2006 New Revision: 3333 Modified: freeswitch/branches/knhor/trunk/ (props changed) freeswitch/branches/knhor/trunk/src/include/switch_ivr.h freeswitch/branches/knhor/trunk/src/mod/applications/mod_ivrtest/mod_ivrtest.c freeswitch/branches/knhor/trunk/src/switch_ivr.c Log: Merged revisions 3326-3332 via svnmerge from trunk Modified: freeswitch/branches/knhor/trunk/src/include/switch_ivr.h ============================================================================== --- freeswitch/branches/knhor/trunk/src/include/switch_ivr.h (original) +++ freeswitch/branches/knhor/trunk/src/include/switch_ivr.h Sun Nov 12 16:01:45 2006 @@ -480,6 +480,7 @@ SWITCH_IVR_ACTION_EXECMENU, /* Goto another menu in the stack. */ SWITCH_IVR_ACTION_EXECAPP, /* Execute an application. */ SWITCH_IVR_ACTION_PLAYSOUND, /* Play a sound. */ + SWITCH_IVR_ACTION_SAYTEXT, /* say text. */ SWITCH_IVR_ACTION_BACK, /* Go back 1 menu. */ SWITCH_IVR_ACTION_TOMAIN, /* Go back to the top level menu. */ SWITCH_IVR_ACTION_TRANSFER, /* Transfer caller to another ext. */ @@ -500,7 +501,6 @@ *\param invalid_sound Optional pointer to a sound to play after invalid input. *\param timeout A number of milliseconds to pause before looping. *\param max_failures Maximum number of failures to withstand before hangingup This resets everytime you enter the menu. - *\param inlen The max len of the input (1 for 1 digit menu opts, 2 for 2 digit etc.) *\param pool memory pool (NULL to create one) *\return SWUTCH_STATUS_SUCCESS if the menu was created */ @@ -510,9 +510,10 @@ char *greeting_sound, char *short_greeting_sound, char *invalid_sound, + char *tts_engine, + char *tts_voice, int timeout, int max_failures, - int inlen, switch_memory_pool_t *pool); /*! Modified: freeswitch/branches/knhor/trunk/src/mod/applications/mod_ivrtest/mod_ivrtest.c ============================================================================== --- freeswitch/branches/knhor/trunk/src/mod/applications/mod_ivrtest/mod_ivrtest.c (original) +++ freeswitch/branches/knhor/trunk/src/mod/applications/mod_ivrtest/mod_ivrtest.c Sun Nov 12 16:01:45 2006 @@ -81,6 +81,65 @@ } +static void ivr_application_function(switch_core_session_t *session, char *data) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + char *params = switch_core_session_strdup(session,data); + + if (channel != NULL && params != NULL) { + switch_ivr_menu_t *menu = NULL, *sub_menu = NULL; + switch_status_t status; + + // answer the channel if need be + switch_channel_answer(channel); + + status = switch_ivr_menu_init(&menu, + NULL, + "main", + "please enter some numbers so i can figure out if I have any bugs or not", + "enter some numbers", + "I have no idea what that is", + "cepstral", + "david", + 15000, 10, NULL); + + + status = switch_ivr_menu_init(&sub_menu, + menu, + "sub", + "/ram/congrats.wav", + "/ram/extension.wav", + "/ram/invalid.wav", + NULL, + NULL, + 15000, 10, NULL); + + if (status == SWITCH_STATUS_SUCCESS) { + // build the menu + switch_ivr_menu_bind_action(menu, SWITCH_IVR_ACTION_PLAYSOUND, "/ram/swimp.raw", "1"); + switch_ivr_menu_bind_action(menu, SWITCH_IVR_ACTION_PLAYSOUND, "/ram/congrats.wav", "2"); + switch_ivr_menu_bind_action(menu, SWITCH_IVR_ACTION_EXECMENU, "sub", "3"); + //switch_ivr_menu_bind_action(menu, SWITCH_IVR_ACTION_PLAYSOUND, "/usr/local/freeswitch/sounds/3.wav", "3"); + + + switch_ivr_menu_bind_action(sub_menu, SWITCH_IVR_ACTION_PLAYSOUND, "/ram/swimp.raw", "1"); + switch_ivr_menu_bind_action(sub_menu, SWITCH_IVR_ACTION_BACK, NULL, "2"); + + + // start the menu + status = switch_ivr_menu_execute(session, menu, "main", NULL); + + // cleaup the menu + switch_ivr_menu_free_stack(menu); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unable to build menu %s\n",params); + } + + + switch_ivr_play_file(session, NULL,"/ram/goodbye.wav",NULL,NULL,NULL,0); + } +} + static void dirtest_function(switch_core_session_t *session, char *data) { char *var, *val; @@ -354,11 +413,19 @@ }; + +static const switch_application_interface_t ivr_application_interface = { + /*.interface_name */ "ivrmenu", + /*.application_function */ ivr_application_function, + NULL, NULL, NULL, + /*.next*/ NULL +}; + static const switch_application_interface_t xml_application_interface = { /*.interface_name */ "xml", /*.application_function */ xml_function, NULL, NULL, NULL, - /*.next*/ NULL + /*.next*/ &ivr_application_interface }; static const switch_application_interface_t disast_application_interface = { Modified: freeswitch/branches/knhor/trunk/src/switch_ivr.c ============================================================================== --- freeswitch/branches/knhor/trunk/src/switch_ivr.c (original) +++ freeswitch/branches/knhor/trunk/src/switch_ivr.c Sun Nov 12 16:01:45 2006 @@ -431,12 +431,16 @@ switch_event_destroy(&event); } - if (input_callback || buf) { + if (input_callback || buf || buflen) { /* dtmf handler function you can hook up to be executed when a digit is dialed during playback if you return anything but SWITCH_STATUS_SUCCESS the playback will stop. */ if (switch_channel_has_dtmf(channel)) { + if (!input_callback && !buf) { + status = SWITCH_STATUS_BREAK; + break; + } switch_channel_dequeue_dtmf(channel, dtmf, sizeof(dtmf)); if (input_callback) { status = input_callback(session, dtmf, SWITCH_INPUT_TYPE_DTMF, buf, buflen); @@ -1094,12 +1098,17 @@ switch_event_destroy(&event); } - if (input_callback || buf) { + if (input_callback || buf || buflen) { /* dtmf handler function you can hook up to be executed when a digit is dialed during playback if you return anything but SWITCH_STATUS_SUCCESS the playback will stop. */ if (switch_channel_has_dtmf(channel)) { + if (!input_callback && !buf) { + status = SWITCH_STATUS_BREAK; + done = 1; + break; + } switch_channel_dequeue_dtmf(channel, dtmf, sizeof(dtmf)); if (input_callback) { status = input_callback(session, dtmf, SWITCH_INPUT_TYPE_DTMF, buf, buflen); @@ -1390,7 +1399,7 @@ if (switch_regex_match(digit_buffer, digits_regex) == SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Match found!\n"); //Jobs done - return switch_channel_get_state(channel); + return SWITCH_STATUS_SUCCESS; } else { //See if a bad input prompt was specified, if so, play it if (strlen(bad_input_audio_file) > 0) { @@ -1405,14 +1414,14 @@ } } else { //Jobs done - return switch_channel_get_state(channel); + return SWITCH_STATUS_SUCCESS; } } } //if we got here, we got no digits or lost the channel digit_buffer = "\0"; - return switch_channel_get_state(channel); + return SWITCH_STATUS_FALSE; } @@ -1485,12 +1494,17 @@ switch_event_destroy(&event); } - if (input_callback || buf) { + if (input_callback || buf || buflen) { /* dtmf handler function you can hook up to be executed when a digit is dialed during playback if you return anything but SWITCH_STATUS_SUCCESS the playback will stop. */ if (switch_channel_has_dtmf(channel)) { + if (!input_callback && !buf) { + status = SWITCH_STATUS_BREAK; + done = 1; + break; + } if (buf && !strcasecmp(buf, "_break_")) { status = SWITCH_STATUS_BREAK; } else { @@ -1630,11 +1644,15 @@ switch_status_t status = SWITCH_STATUS_SUCCESS; switch_speech_handle_t sh; switch_speech_flag_t flags = SWITCH_SPEECH_FLAG_NONE; + switch_codec_t *read_codec; - channel = switch_core_session_get_channel(session); assert(channel != NULL); + if (rate == 0) { + read_codec = switch_core_session_get_read_codec(session); + rate = read_codec->implementation->samples_per_second; + } memset(&sh, 0, sizeof(sh)); if (switch_core_speech_open(&sh, @@ -3406,6 +3424,10 @@ char *greeting_sound; char *short_greeting_sound; char *invalid_sound; + char *tts_engine; + char *tts_voice; + char *buf; + char *ptr; int max_failures; int timeout; int inlen; @@ -3454,9 +3476,10 @@ char *greeting_sound, char *short_greeting_sound, char *invalid_sound, + char *tts_engine, + char *tts_voice, int timeout, int max_failures, - int inlen, switch_memory_pool_t *pool) { switch_ivr_menu_t *menu; @@ -3477,25 +3500,47 @@ return SWITCH_STATUS_MEMERR; } } + menu->pool = pool; - menu->name = switch_core_strdup(menu->pool, name); - menu->greeting_sound = switch_core_strdup(menu->pool, greeting_sound); - menu->short_greeting_sound = switch_core_strdup(menu->pool, short_greeting_sound); - menu->invalid_sound = switch_core_strdup(menu->pool, invalid_sound); + if (name) { + menu->name = switch_core_strdup(menu->pool, name); + } + + if (greeting_sound) { + menu->greeting_sound = switch_core_strdup(menu->pool, greeting_sound); + } + + if (short_greeting_sound) { + menu->short_greeting_sound = switch_core_strdup(menu->pool, short_greeting_sound); + } + + if (invalid_sound) { + menu->invalid_sound = switch_core_strdup(menu->pool, invalid_sound); + } + + if (tts_engine) { + menu->tts_engine = switch_core_strdup(menu->pool, tts_engine); + } + + if (tts_voice) { + menu->tts_voice = switch_core_strdup(menu->pool, tts_voice); + } + menu->max_failures = max_failures; + menu->timeout = timeout; + menu->actions = NULL; - menu->inlen = inlen; + if (newpool) { menu->flags |= SWITCH_IVR_MENU_FLAG_FREEPOOL; } - if (menu->timeout <= 0) + if (menu->timeout <= 0) { menu->timeout = 10000; - if (menu->inlen <= 0) - menu->inlen = 1; - + } + if (main) { switch_ivr_menu_stack(&main, menu); } else { @@ -3511,11 +3556,15 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_menu_bind_action(switch_ivr_menu_t *menu, switch_ivr_action_t ivr_action, char *arg, char *bind) { switch_ivr_menu_action_t *action; - + switch_size_t len; if ((action = switch_core_alloc(menu->pool, sizeof(*action)))) { - action->bind = bind; + action->bind = switch_core_strdup(menu->pool, bind); action->next = menu->actions; - action->arg = arg; + action->arg = switch_core_strdup(menu->pool, arg); + len = strlen(action->bind); + if (len > menu->inlen) { + menu->inlen = (uint32_t)len; + } action->ivr_action = ivr_action; menu->actions = action; return SWITCH_STATUS_SUCCESS; @@ -3557,11 +3606,50 @@ } +static switch_status_t play_or_say(switch_core_session_t *session, switch_ivr_menu_t *menu, char *sound, uint32_t need) +{ + memset(menu->buf, 0, menu->inlen); + menu->ptr = menu->buf; + char terminator; + uint32_t len; + char *ptr; + + switch_status_t status = SWITCH_STATUS_SUCCESS; + + menu->ptr = menu->buf; + + if (!need) { + len = 1; + ptr = NULL; + } else { + len = menu->inlen + 1; + ptr = menu->ptr; + } + + if (*sound == '/' || *sound == '\\') { + switch_ivr_play_file(session, NULL, sound, NULL, NULL, ptr, len); + } else { + if (menu->tts_engine && menu->tts_voice) { + switch_ivr_speak_text(session, menu->tts_engine, menu->tts_voice, NULL, 0, NULL, sound, ptr, len); + } + } + + if (need) { + menu->ptr += strlen(menu->buf); + if (strlen(menu->buf) < need) { + status = switch_ivr_collect_digits_count(session, menu->ptr, menu->inlen - strlen(menu->buf), need, "#", &terminator, menu->timeout); + } + } + + return status; + +} + SWITCH_DECLARE(switch_status_t) switch_ivr_menu_execute(switch_core_session_t *session, switch_ivr_menu_t *stack, char *name, void *obj) { int reps = 0, errs = 0, match = 0, running = 1; char *greeting_sound = NULL, *aptr; - char *buf, arg[512]; + char arg[512]; switch_ivr_action_t todo = SWITCH_IVR_ACTION_DIE; switch_ivr_menu_action_t *ap; switch_ivr_menu_t *menu; @@ -3577,7 +3665,7 @@ return -1; } - if (!(buf = malloc(menu->inlen))) { + if (!(menu->buf = malloc(menu->inlen))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No Memory!\n"); return -1; } @@ -3585,12 +3673,10 @@ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Executing IVR menu %s\n", menu->name); for (reps = 0 ; (running && status == SWITCH_STATUS_SUCCESS && errs < menu->max_failures) ; reps++) { - if (!switch_channel_ready(channel)) { break; } - if (reps > 0 && menu->short_greeting_sound) { greeting_sound = menu->short_greeting_sound; } else { @@ -3599,28 +3685,19 @@ match = 0; aptr = NULL; - memset(buf, 0, menu->inlen); + memset(arg, 0, sizeof(arg)); - if (switch_play_and_get_digits(session, - menu->inlen, - menu->inlen, - 1, - menu->timeout, "#", - greeting_sound, - NULL, - buf, - menu->inlen, - NULL) != SWITCH_STATUS_SUCCESS) { - break; - } + + play_or_say(session, menu, greeting_sound, menu->inlen); - if (!switch_strlen_zero(buf)) { + + if (!switch_strlen_zero(menu->buf)) { for(ap = menu->actions; ap ; ap = ap->next) { - if (!strcmp(buf, ap->bind)) { + if (!strcmp(menu->buf, ap->bind)) { char *membuf; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IVR menu %s matched %s\n", menu->name, buf); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IVR menu %s matched %s\n", menu->name, menu->buf); match++; errs = 0; if (ap->function) { @@ -3638,6 +3715,11 @@ case SWITCH_IVR_ACTION_PLAYSOUND: status = switch_ivr_play_file(session, NULL, aptr, NULL, NULL, NULL, 0); break; + case SWITCH_IVR_ACTION_SAYTEXT: + if (menu->tts_engine && menu->tts_voice) { + switch_ivr_speak_text(session, menu->tts_engine, menu->tts_voice, NULL, 0, NULL, aptr, NULL, 0); + } + break; case SWITCH_IVR_ACTION_TRANSFER: switch_ivr_session_transfer(session, aptr, NULL, NULL); running = 0; @@ -3693,10 +3775,10 @@ } } if (!match) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IVR menu %s caught invalid input %s\n", menu->name, buf); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IVR menu %s caught invalid input %s\n", menu->name, menu->buf); if (menu->invalid_sound) { - status = switch_ivr_play_file(session, NULL, aptr, NULL, NULL, NULL, 0); + play_or_say(session, menu, menu->invalid_sound, 0); } errs++; @@ -3707,7 +3789,7 @@ } - switch_safe_free(buf); + switch_safe_free(menu->buf); return status; }