]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
Add new higher level ivr functions from Paul Tinsley. Thanks Paul.
authorMichael Jerris <mike@jerris.com>
Sat, 28 Oct 2006 04:40:59 +0000 (04:40 +0000)
committerMichael Jerris <mike@jerris.com>
Sat, 28 Oct 2006 04:40:59 +0000 (04:40 +0000)
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3223 d0543943-73ff-0310-b7d9-9358b9ac24b2

src/include/switch_ivr.h
src/switch_ivr.c

index 7c6b6d819d190f1c6fbb62305fa7b4f8d27a9d5c..bc625a287e6a9458bdb781efe3ec7af164152021 100644 (file)
@@ -152,6 +152,40 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se
                                                                                                         void *buf,
                                                                                                         unsigned int buflen);
 
+/*!
+ \brief Function to evaluate an expression against a string
+ \param target The string to find a match in
+ \param expression The regular expression to run against the string
+ \return Boolean if a match was found or not
+*/
+SWITCH_DECLARE(switch_status_t) switch_regex_match(char *target, char *expression);
+
+/*!
+  \brief Play a sound and gather digits with the number of retries specified if the user doesn't give digits in the set time
+  \param session the current session to play sound to and collect digits
+  \param min_digits the fewest digits allowed for the response to be valid
+  \param max_digits the max number of digits to accept
+  \param max_tries number of times to replay the sound and capture digits
+  \param timeout time to wait for input (this is per iteration, so total possible time = max_tries * (timeout + audio playback length)
+  \param valid_terminators for input that can include # or * (useful for variable length prompts)
+  \param audio_file file to play
+  \param bad_input_audio_file file to play if the input from the user was invalid
+  \param digit_buffer variable digits captured will be put back into (empty if capture failed)
+  \param digit_buffer_length length of the buffer for digits (should be the same or larger than max_digits)
+  \return switch status, used to note status of channel (will still return success if digit capture failed)
+  \note to test for digit capture failure look for \0 in the first position of the buffer
+*/
+SWITCH_DECLARE(switch_status_t) switch_play_and_get_digits(switch_core_session_t *session,
+                                                           unsigned int min_digits,
+                                                           unsigned int max_digits,
+                                                           unsigned int max_tries,
+                                                           unsigned int timeout,
+                                                           char* valid_terminators,
+                                                           char* audio_file,
+                                                           char* bad_input_audio_file,
+                                                           void* digit_buffer,
+                                                           unsigned int digit_buffer_length,
+                                                           char* digits_regex);
 
 SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text_handle(switch_core_session_t *session,
                                                              switch_speech_handle_t *sh,
index 257d4612658c7a63305565bbe94cf01ebf70d26f..8a9b76a4b4dab3b20f2258682f9776901826bb27 100644 (file)
@@ -24,7 +24,7 @@
  * Contributor(s):
  * 
  * Anthony Minessale II <anthmct@yahoo.com>
- *
+ * Paul D. Tinsley <pdt at jackhammer.org>
  *
  * switch_ivr_api.c -- IVR Library
  *
@@ -938,7 +938,167 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess
        return status;
 }
 
+SWITCH_DECLARE(switch_status_t) switch_regex_match(char *target, char *expression) {
+       const char* error       = NULL;         //Used to hold any errors
+       int error_offset        = 0;            //Holds the offset of an error
+       pcre* pcre_prepared     = NULL;         //Holds the compiled regex
+       int match_count         = 0;            //Number of times the regex was matched
+       int offset_vectors[2];                  //not used, but has to exist or pcre won't even try to find a match
+       
+       //Compile the expression
+       pcre_prepared = pcre_compile(expression, 0, &error, &error_offset, NULL);
+
+       //See if there was an error in the expression
+       if(error != NULL) {
+               //Clean up after ourselves
+               if(pcre_prepared) {
+                       pcre_free(pcre_prepared);
+                       pcre_prepared = NULL;
+               }              
+
+               //Note our error        
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Regular Expression Error expression[%s] error[%s] location[%d]\n", expression, error, error_offset);
+
+               //We definitely didn't match anything
+               return SWITCH_STATUS_FALSE;
+       }
+
+       //So far so good, run the regex
+       match_count = pcre_exec(pcre_prepared, NULL, target, (int) strlen(target), 0, 0, offset_vectors, sizeof(offset_vectors) / sizeof(offset_vectors[0]));
+
+       //Clean up
+       if(pcre_prepared) {
+               pcre_free(pcre_prepared);
+               pcre_prepared = NULL;
+       }
+
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "number of matches: %d\n", match_count);
+
+       //Was it a match made in heaven?
+       if(match_count > 0) {
+               return SWITCH_STATUS_SUCCESS;
+       } else {
+               return SWITCH_STATUS_FALSE;
+       }
+}
+
+SWITCH_DECLARE(switch_status_t) switch_play_and_get_digits(switch_core_session_t *session,
+                                                                                                                  unsigned int min_digits,
+                                                                                                                  unsigned int max_digits,
+                                                                                                                  unsigned int max_tries,
+                                                                                                                  unsigned int timeout,
+                                                                                                                  char* valid_terminators,
+                                                                                                                  char* prompt_audio_file,
+                                                                                                                  char* bad_input_audio_file,
+                                                                                                                  void* digit_buffer,
+                                                                                                                  unsigned int digit_buffer_length,
+                                                                                                                  char* digits_regex) 
+{
 
+       char terminator;                        //used to hold terminator recieved from  
+       switch_channel_t *channel;      //the channel contained in session
+       switch_status_t status;         //used to recieve state out of called functions
+
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "switch_play_and_get_digits(session, %d, %d, %d, %d, %s, %s, %s, digit_buffer, %d, %s)\n", min_digits, max_digits, max_tries, timeout, valid_terminators, prompt_audio_file, bad_input_audio_file, digit_buffer_length, digits_regex);
+
+       //Get the channel
+       channel = switch_core_session_get_channel(session);
+
+       //Make sure somebody is home
+       assert(channel != NULL);
+
+       //Answer the channel if it hasn't already been answered
+       switch_channel_answer(channel);
+
+       //Start pestering the user for input
+       for(;(switch_channel_get_state(channel) == CS_EXECUTE) && max_tries > 0; max_tries--) {
+               //make the buffer so fresh and so clean clean
+               memset(digit_buffer, 0, digit_buffer_length);
+
+               //Play the file
+               status = switch_ivr_play_file(session, NULL, prompt_audio_file, NULL, NULL, digit_buffer, digit_buffer_length);
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "play gave up %s", digit_buffer);
+
+               //Make sure we made it out alive
+               if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
+                       switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+                       break;
+               }
+
+               //we only get one digit out of playback, see if thats all we needed and what we got
+               if(max_digits == 1 && status == SWITCH_STATUS_BREAK) {
+                       //Check the digit if we have a regex
+                       if(digits_regex != NULL) {
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Checking regex [%s] on [%s]\n", digits_regex, digit_buffer);
+
+                               //Make sure the digit is allowed
+                               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
+                                       break;
+                               } else {
+                                       //See if a bad input prompt was specified, if so, play it
+                                       if(strlen(bad_input_audio_file) > 0) {
+                                               status = switch_ivr_play_file(session, NULL, bad_input_audio_file, NULL, NULL, NULL, 0);
+
+                                               //Make sure we made it out alive
+                                               if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
+                                                       switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+                                                       break;
+                                               }
+                                       }
+                               }
+                       } else {
+                               //jobs done
+                               break;
+                       }
+               }
+
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Calling more digits try %d\n", max_tries);
+
+               //Try to grab some more digits for the timeout period
+               status = switch_ivr_collect_digits_count(session, digit_buffer, digit_buffer_length, max_digits, valid_terminators, &terminator, timeout);
+
+               //Make sure we made it out alive
+               if(status != SWITCH_STATUS_SUCCESS) {
+                       //Bail
+                       switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+                       break;
+               }
+
+               //see if we got enough
+               if(min_digits <= strlen(digit_buffer)) {
+                       //See if we need to test a regex
+                       if(digits_regex != NULL) {
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Checking regex [%s] on [%s]\n", digits_regex, digit_buffer);
+                               //Test the regex
+                               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);
+                               } else {
+                                       //See if a bad input prompt was specified, if so, play it
+                                       if(strlen(bad_input_audio_file) > 0) {
+                                               status = switch_ivr_play_file(session, NULL, bad_input_audio_file, NULL, NULL, NULL, 0);
+
+                                               //Make sure we made it out alive
+                                               if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
+                                                       switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+                                                       break;
+                                               }
+                                       }
+                               }
+                       } else {
+                               //Jobs done
+                               return switch_channel_get_state(channel);
+                       }
+               }
+       }
+
+       //if we got here, we got no digits or lost the channel
+       digit_buffer = "\0";
+       return switch_channel_get_state(channel);
+}
 
 
 SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text_handle(switch_core_session_t *session, 
@@ -970,14 +1130,14 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text_handle(switch_core_session
        if (!sh) {
                return SWITCH_STATUS_FALSE;
        }
-       
+
        switch_channel_answer(channel);
 
        write_frame.data = abuf;
        write_frame.buflen = sizeof(abuf);
 
-    samples = (uint32_t)(sh->rate / 50);
-    len = samples * 2;
+       samples = (uint32_t)(sh->rate / 50);
+       len = samples * 2;
 
        flags = 0;
        switch_sleep(200000);
@@ -1012,8 +1172,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text_handle(switch_core_session
 
                if (input_callback || buf) {
                        /*
-                         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.
+                       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 (buf && !strcasecmp(buf, "_break_")) {
@@ -1041,7 +1201,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text_handle(switch_core_session
                                break;
                        }
                }
-               
+
                if (switch_test_flag(sh, SWITCH_SPEECH_FLAG_PAUSE)) {
                        if (timer) {
                                if ((x = switch_core_timer_next(timer)) < 0) {
@@ -1054,7 +1214,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text_handle(switch_core_session
                                while (switch_channel_test_flag(channel, CF_HOLD)) {
                                        switch_yield(10000);
                                }
-                       
+
                                if (!SWITCH_READ_ACCEPTABLE(status)) {
                                        break;
                                }
@@ -1064,10 +1224,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text_handle(switch_core_session
 
                flags = SWITCH_SPEECH_FLAG_BLOCKING;
                status = switch_core_speech_read_tts(sh,
-                                                                                        abuf,
-                                                                                        &ilen,
-                                                                                        &rate,
-                                                                                        &flags);
+                       abuf,
+                       &ilen,
+                       &rate,
+                       &flags);
 
                if (status != SWITCH_STATUS_SUCCESS) {
                        for( x = 0; !done && x < lead_in_out; x++) {
@@ -1084,7 +1244,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text_handle(switch_core_session
                        }
                        done = 1;
                }
-               
+
                if (done) {
                        break;
                }
@@ -1115,15 +1275,15 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text_handle(switch_core_session
                        while (switch_channel_test_flag(channel, CF_HOLD)) {
                                switch_yield(10000);
                        }
-                       
+
                        if (!SWITCH_READ_ACCEPTABLE(status)) {
                                break;
                        }
                }
 
        }
-       
-       
+
+
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "done speaking text\n");
        flags = 0;      
        switch_core_speech_flush_tts(sh);