MERGE: OpenMethods DTMF recognition via ASR modules
This commit is contained in:
commit
02082c930c
|
@ -1735,6 +1735,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);
|
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
|
\brief Check an asr handle for results
|
||||||
\param ah the handle to check
|
\param ah the handle to check
|
||||||
|
|
|
@ -403,6 +403,8 @@ struct switch_asr_interface {
|
||||||
switch_status_t (*asr_disable_grammar) (switch_asr_handle_t *ah, const char *name);
|
switch_status_t (*asr_disable_grammar) (switch_asr_handle_t *ah, const char *name);
|
||||||
/*! function to disable all grammars to the asr interface */
|
/*! function to disable all grammars to the asr interface */
|
||||||
switch_status_t (*asr_disable_all_grammars) (switch_asr_handle_t *ah);
|
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. */
|
/*! an abstract representation of an asr speech interface. */
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
#include "mrcp_resource_loader.h"
|
#include "mrcp_resource_loader.h"
|
||||||
#include "mpf_engine.h"
|
#include "mpf_engine.h"
|
||||||
#include "mpf_codec_manager.h"
|
#include "mpf_codec_manager.h"
|
||||||
|
#include "mpf_dtmf_generator.h"
|
||||||
#include "mpf_rtp_termination_factory.h"
|
#include "mpf_rtp_termination_factory.h"
|
||||||
#include "mrcp_sofiasip_client_agent.h"
|
#include "mrcp_sofiasip_client_agent.h"
|
||||||
#include "mrcp_unirtsp_client_agent.h"
|
#include "mrcp_unirtsp_client_agent.h"
|
||||||
|
@ -442,6 +443,12 @@ struct recognizer_data {
|
||||||
int start_of_input;
|
int start_of_input;
|
||||||
/** true, if input timers have started */
|
/** true, if input timers have started */
|
||||||
int timers_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;
|
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_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_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(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
|
#if 0
|
||||||
static switch_status_t recog_asr_start(switch_asr_handle_t *ah, const char *name);
|
static switch_status_t recog_asr_start(switch_asr_handle_t *ah, const char *name);
|
||||||
#endif
|
#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 */
|
/* recognizer's interface for UniMRCP */
|
||||||
static apt_bool_t recog_message_handler(const mrcp_app_message_t *app_message);
|
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_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);
|
static apt_bool_t recog_stream_read(mpf_audio_stream_t *stream, mpf_frame_t *frame);
|
||||||
|
|
||||||
/* recognizer specific speech_channel_funcs */
|
/* 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);
|
speech_channel_destroy(schannel);
|
||||||
switch_core_hash_destroy(&r->grammars);
|
switch_core_hash_destroy(&r->grammars);
|
||||||
switch_core_hash_destroy(&r->enabled_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 */
|
/* this lets FreeSWITCH's speech_thread know the handle is closed */
|
||||||
switch_set_flag(ah, SWITCH_ASR_FLAG_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);
|
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
|
#if 0
|
||||||
/**
|
/**
|
||||||
* Process asr_start request from FreeSWITCH
|
* 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;
|
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
|
* 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)
|
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;
|
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;
|
switch_size_t to_read = frame->codec_frame.size;
|
||||||
|
|
||||||
/* grab the data. pad it if there isn't enough */
|
/* grab the data. pad it if there isn't enough */
|
||||||
|
@ -3399,6 +3462,13 @@ static apt_bool_t recog_stream_read(mpf_audio_stream_t *stream, mpf_frame_t *fra
|
||||||
frame->type |= MEDIA_FRAME_TYPE_AUDIO;
|
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;
|
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_disable_all_grammars = recog_asr_disable_all_grammars;
|
||||||
asr_interface->asr_close = recog_asr_close;
|
asr_interface->asr_close = recog_asr_close;
|
||||||
asr_interface->asr_feed = recog_asr_feed;
|
asr_interface->asr_feed = recog_asr_feed;
|
||||||
|
asr_interface->asr_feed_dtmf = recog_asr_feed_dtmf;
|
||||||
#if 0
|
#if 0
|
||||||
asr_interface->asr_start = recog_asr_start;
|
asr_interface->asr_start = recog_asr_start;
|
||||||
#endif
|
#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_channel_remove = speech_on_channel_remove;
|
||||||
globals.recog.dispatcher.on_message_receive = recog_on_message_receive;
|
globals.recog.dispatcher.on_message_receive = recog_on_message_receive;
|
||||||
globals.recog.audio_stream_vtable.destroy = NULL;
|
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.close_rx = NULL;
|
||||||
globals.recog.audio_stream_vtable.read_frame = recog_stream_read;
|
globals.recog.audio_stream_vtable.read_frame = recog_stream_read;
|
||||||
globals.recog.audio_stream_vtable.open_tx = NULL;
|
globals.recog.audio_stream_vtable.open_tx = NULL;
|
||||||
|
|
|
@ -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);
|
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_DECLARE(switch_status_t) switch_core_asr_check_results(switch_asr_handle_t *ah, switch_asr_flag_t *flags)
|
||||||
{
|
{
|
||||||
switch_assert(ah != NULL);
|
switch_assert(ah != NULL);
|
||||||
|
|
|
@ -3208,6 +3208,20 @@ static switch_bool_t speech_callback(switch_media_bug_t *bug, void *user_data, s
|
||||||
return SWITCH_TRUE;
|
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_DECLARE(switch_status_t) switch_ivr_stop_detect_speech(switch_core_session_t *session)
|
||||||
{
|
{
|
||||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||||
|
@ -3423,6 +3437,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech(switch_core_session_t *
|
||||||
return status;
|
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);
|
switch_channel_set_private(channel, SWITCH_SPEECH_KEY, sth);
|
||||||
|
|
||||||
return SWITCH_STATUS_SUCCESS;
|
return SWITCH_STATUS_SUCCESS;
|
||||||
|
|
Loading…
Reference in New Issue