]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
MERGE: DTMF recognition via ASR modules (implemented in UniMRCP)
authorLuke Dashjr <luke@openmethods.com>
Wed, 26 Jan 2011 20:40:35 +0000 (14:40 -0600)
committerLuke Dashjr <luke@openmethods.com>
Wed, 26 Jan 2011 20:40:35 +0000 (14:40 -0600)
src/include/switch_core.h
src/include/switch_module_interfaces.h
src/mod/asr_tts/mod_unimrcp/mod_unimrcp.c
src/switch_core_asr.c
src/switch_ivr_async.c

index 26a048cdb2f7482775825cda96fb781f8b472fed..a3d74e97b3c879f2f15bd387ba9a506fb4dea372 100644 (file)
@@ -1714,6 +1714,15 @@ SWITCH_DECLARE(switch_status_t) switch_core_asr_close(switch_asr_handle_t *ah, s
 */
 SWITCH_DECLARE(switch_status_t) switch_core_asr_feed(switch_asr_handle_t *ah, void *data, unsigned int len, switch_asr_flag_t *flags);
 
+/*!
+  \brief Feed DTMF to an asr handle
+  \param ah the handle to feed data to
+  \param dtmf a string of DTMF digits
+  \param flags flags to influence behaviour
+  \return SWITCH_STATUS_SUCCESS
+*/
+SWITCH_DECLARE(switch_status_t) switch_core_asr_feed_dtmf(switch_asr_handle_t *ah, const switch_dtmf_t *dtmf, switch_asr_flag_t *flags);
+
 /*!
   \brief Check an asr handle for results
   \param ah the handle to check
index e0119b4d150cc30a65ecd0557a0b2e9a66cb8f98..8303af75de16ad54c53f765b213bee341af8a9f4 100644 (file)
@@ -400,6 +400,8 @@ struct switch_asr_interface {
        switch_status_t (*asr_disable_grammar) (switch_asr_handle_t *ah, const char *name);
        /*! function to disable all grammars to the asr interface */
        switch_status_t (*asr_disable_all_grammars) (switch_asr_handle_t *ah);
+       /*! function to feed DTMF to the ASR */
+       switch_status_t (*asr_feed_dtmf) (switch_asr_handle_t *ah, const switch_dtmf_t *dtmf, switch_asr_flag_t *flags);
 };
 
 /*! an abstract representation of an asr speech interface. */
index b9cecd10bc6378811f16698bb6681a0746d2e007..b3679cf516894b1d54a8ac8261f0448479c3aab6 100644 (file)
@@ -49,6 +49,7 @@
 #include "mrcp_resource_loader.h"
 #include "mpf_engine.h"
 #include "mpf_codec_manager.h"
+#include "mpf_dtmf_generator.h"
 #include "mpf_rtp_termination_factory.h"
 #include "mrcp_sofiasip_client_agent.h"
 #include "mrcp_unirtsp_client_agent.h"
@@ -442,6 +443,12 @@ struct recognizer_data {
        int start_of_input;
        /** true, if input timers have started */
        int timers_started;
+       /** UniMRCP mpf stream */
+       mpf_audio_stream_t *unimrcp_stream;
+       /** DTMF generator */
+       mpf_dtmf_generator_t *dtmf_generator;
+       /** true, if presently transmitting DTMF */
+       char dtmf_generator_active;
 };
 typedef struct recognizer_data recognizer_data_t;
 
@@ -457,6 +464,7 @@ static switch_status_t recog_asr_disable_grammar(switch_asr_handle_t *ah, const
 static switch_status_t recog_asr_disable_all_grammars(switch_asr_handle_t *ah);
 static switch_status_t recog_asr_close(switch_asr_handle_t *ah, switch_asr_flag_t *flags);
 static switch_status_t recog_asr_feed(switch_asr_handle_t *ah, void *data, unsigned int len, switch_asr_flag_t *flags);
+static switch_status_t recog_asr_feed_dtmf(switch_asr_handle_t *ah, const switch_dtmf_t *dtmf, switch_asr_flag_t *flags);
 #if 0
 static switch_status_t recog_asr_start(switch_asr_handle_t *ah, const char *name);
 #endif
@@ -472,6 +480,7 @@ static void recog_asr_float_param(switch_asr_handle_t *ah, char *param, double v
 /* recognizer's interface for UniMRCP */
 static apt_bool_t recog_message_handler(const mrcp_app_message_t *app_message);
 static apt_bool_t recog_on_message_receive(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel, mrcp_message_t *message);
+static apt_bool_t recog_stream_open(mpf_audio_stream_t *stream, mpf_codec_t *codec);
 static apt_bool_t recog_stream_read(mpf_audio_stream_t *stream, mpf_frame_t *frame);
 
 /* recognizer specific speech_channel_funcs */
@@ -3114,6 +3123,9 @@ static switch_status_t recog_asr_close(switch_asr_handle_t *ah, switch_asr_flag_
        speech_channel_destroy(schannel);
        switch_core_hash_destroy(&r->grammars);
        switch_core_hash_destroy(&r->enabled_grammars);
+       if (r->dtmf_generator) {
+               mpf_dtmf_generator_destroy(r->dtmf_generator);
+       }
 
        /* this lets FreeSWITCH's speech_thread know the handle is closed */
        switch_set_flag(ah, SWITCH_ASR_FLAG_CLOSED);
@@ -3134,6 +3146,39 @@ static switch_status_t recog_asr_feed(switch_asr_handle_t *ah, void *data, unsig
        return speech_channel_write(schannel, data, &slen);
 }
 
+/**
+ * Process asr_feed_dtmf request from FreeSWITCH
+ *
+ * @param ah the FreeSWITCH speech recognition handle
+ * @return SWITCH_STATUS_SUCCESS if successful 
+ */
+static switch_status_t recog_asr_feed_dtmf(switch_asr_handle_t *ah, const switch_dtmf_t *dtmf, switch_asr_flag_t *flags)
+{
+       speech_channel_t *schannel = (speech_channel_t *) ah->private_info;
+       recognizer_data_t *r = (recognizer_data_t *) schannel->data;
+       char digits[2];
+
+       if (!r->dtmf_generator) {
+               if (!r->unimrcp_stream) {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "(%s) Cannot queue DTMF: No UniMRCP stream object open\n", schannel->name);
+                       return SWITCH_STATUS_FALSE;
+               }
+               r->dtmf_generator = mpf_dtmf_generator_create(r->unimrcp_stream, schannel->unimrcp_session->pool);
+               if (!r->dtmf_generator) {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "(%s) Cannot queue DTMF: Failed to create DTMF generator\n", schannel->name);
+                       return SWITCH_STATUS_FALSE;
+               }
+       }
+
+       digits[0] = dtmf->digit;
+       digits[1] = '\0';
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(%s) Queued DTMF: %s\n", schannel->name, digits);
+       mpf_dtmf_generator_enqueue(r->dtmf_generator, digits);
+       r->dtmf_generator_active = 1;
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
 #if 0
 /**
  * Process asr_start request from FreeSWITCH
@@ -3379,6 +3424,23 @@ static apt_bool_t recog_on_message_receive(mrcp_application_t *application, mrcp
        return TRUE;
 }
 
+/**
+ * UniMRCP callback requesting open for speech recognition
+ *
+ * @param stream the UniMRCP stream
+ * @param codec the codec
+ * @return TRUE
+ */
+static apt_bool_t recog_stream_open(mpf_audio_stream_t *stream, mpf_codec_t *codec)
+{
+       speech_channel_t *schannel = (speech_channel_t *) stream->obj;
+       recognizer_data_t *r = (recognizer_data_t *) schannel->data;
+       
+       r->unimrcp_stream = stream;
+       
+       return TRUE;
+}
+
 /**
  * UniMRCP callback requesting next frame for speech recognition
  *
@@ -3389,6 +3451,7 @@ static apt_bool_t recog_on_message_receive(mrcp_application_t *application, mrcp
 static apt_bool_t recog_stream_read(mpf_audio_stream_t *stream, mpf_frame_t *frame)
 {
        speech_channel_t *schannel = (speech_channel_t *) stream->obj;
+       recognizer_data_t *r = (recognizer_data_t *) schannel->data;
        switch_size_t to_read = frame->codec_frame.size;
 
        /* grab the data.  pad it if there isn't enough */
@@ -3398,6 +3461,13 @@ static apt_bool_t recog_stream_read(mpf_audio_stream_t *stream, mpf_frame_t *fra
                }
                frame->type |= MEDIA_FRAME_TYPE_AUDIO;
        }
+       
+       if (r->dtmf_generator_active) {
+               if (!mpf_dtmf_generator_put_frame(r->dtmf_generator, frame)) {
+                       if (!mpf_dtmf_generator_sending(r->dtmf_generator))
+                               r->dtmf_generator_active = 0;
+               }
+       }
 
        return TRUE;
 }
@@ -3421,6 +3491,7 @@ static switch_status_t recog_load(switch_loadable_module_interface_t *module_int
        asr_interface->asr_disable_all_grammars = recog_asr_disable_all_grammars;
        asr_interface->asr_close = recog_asr_close;
        asr_interface->asr_feed = recog_asr_feed;
+       asr_interface->asr_feed_dtmf = recog_asr_feed_dtmf;
 #if 0
        asr_interface->asr_start = recog_asr_start;
 #endif
@@ -3443,7 +3514,7 @@ static switch_status_t recog_load(switch_loadable_module_interface_t *module_int
        globals.recog.dispatcher.on_channel_remove = speech_on_channel_remove;
        globals.recog.dispatcher.on_message_receive = recog_on_message_receive;
        globals.recog.audio_stream_vtable.destroy = NULL;
-       globals.recog.audio_stream_vtable.open_rx = NULL;
+       globals.recog.audio_stream_vtable.open_rx = recog_stream_open;
        globals.recog.audio_stream_vtable.close_rx = NULL;
        globals.recog.audio_stream_vtable.read_frame = recog_stream_read;
        globals.recog.audio_stream_vtable.open_tx = NULL;
index 691011a2851f2b239e55475f889f6b02597356fb..7f231ef65112332de2d148e2b3f75c43aa34e31e 100644 (file)
@@ -239,6 +239,19 @@ SWITCH_DECLARE(switch_status_t) switch_core_asr_feed(switch_asr_handle_t *ah, vo
        return ah->asr_interface->asr_feed(ah, data, len, flags);
 }
 
+SWITCH_DECLARE(switch_status_t) switch_core_asr_feed_dtmf(switch_asr_handle_t *ah, const switch_dtmf_t *dtmf, switch_asr_flag_t *flags)
+{
+       switch_status_t status = SWITCH_STATUS_SUCCESS;
+
+       switch_assert(ah != NULL);
+
+       if (ah->asr_interface->asr_feed_dtmf) {
+               status = ah->asr_interface->asr_feed_dtmf(ah, dtmf, flags);
+       }
+
+       return status;
+}
+
 SWITCH_DECLARE(switch_status_t) switch_core_asr_check_results(switch_asr_handle_t *ah, switch_asr_flag_t *flags)
 {
        switch_assert(ah != NULL);
index 66cd36963bd479353bce1f649583ab76c1b52ff2..5df7af3bff3cb2cd05c40d758da197b2ed6d1213 100644 (file)
@@ -2660,6 +2660,20 @@ static switch_bool_t speech_callback(switch_media_bug_t *bug, void *user_data, s
        return SWITCH_TRUE;
 }
 
+static switch_status_t speech_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);
+       struct speech_thread_handle *sth = switch_channel_get_private(channel, SWITCH_SPEECH_KEY);
+       switch_status_t status = SWITCH_STATUS_SUCCESS;
+       switch_asr_flag_t flags = SWITCH_ASR_FLAG_NONE;
+
+       if (switch_core_asr_feed_dtmf(sth->ah, dtmf, &flags) != SWITCH_STATUS_SUCCESS) {
+               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error Feeding DTMF\n");
+       }
+
+       return status;
+}
+
 SWITCH_DECLARE(switch_status_t) switch_ivr_stop_detect_speech(switch_core_session_t *session)
 {
        switch_channel_t *channel = switch_core_session_get_channel(session);
@@ -2875,6 +2889,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech(switch_core_session_t *
                return status;
        }
 
+       if ((status = switch_core_event_hook_add_recv_dtmf(session, speech_on_dtmf)) != SWITCH_STATUS_SUCCESS) {
+               switch_ivr_stop_detect_speech(session);
+               return status;
+       }
+
        switch_channel_set_private(channel, SWITCH_SPEECH_KEY, sth);
 
        return SWITCH_STATUS_SUCCESS;