forked from Mirrors/freeswitch
Initial Check-In of mod_lumenvox
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4052 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
parent
8662ab4882
commit
b0eb04c065
18
src/mod/asr_tts/mod_lumenvox/Makefile
Normal file
18
src/mod/asr_tts/mod_lumenvox/Makefile
Normal file
@ -0,0 +1,18 @@
|
||||
LDFLAGS += -L/opt/lumenvox/engine_7.0/lib -llv_lvspeechport
|
||||
CFLAGS += -fpermissive -Wno-deprecated -Wno-conversion -fpermissive -Wno-unused -Wno-comment -Wno-sign-compare -Wno-conversion -Wno-reorder -I/opt/lumenvox/engine_7.0/include
|
||||
LINKER=g++
|
||||
CC=g++
|
||||
|
||||
all: depends $(MODNAME).$(DYNAMIC_LIB_EXTEN)
|
||||
|
||||
depends:
|
||||
|
||||
$(MODNAME).$(DYNAMIC_LIB_EXTEN): $(MODNAME).cpp
|
||||
$(CC) $(CFLAGS) -fPIC -c $(MODNAME).cpp -o $(MODNAME).o
|
||||
$(LINKER) $(SOLINK) -o $(MODNAME).$(DYNAMIC_LIB_EXTEN) $(MODNAME).o $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
rm -fr *.$(DYNAMIC_LIB_EXTEN) *.o *~
|
||||
|
||||
install:
|
||||
cp -f $(MODNAME).$(DYNAMIC_LIB_EXTEN) $(PREFIX)/mod
|
459
src/mod/asr_tts/mod_lumenvox/mod_lumenvox.cpp
Normal file
459
src/mod/asr_tts/mod_lumenvox/mod_lumenvox.cpp
Normal file
@ -0,0 +1,459 @@
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
|
||||
*
|
||||
* 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 <anthmct@yahoo.com>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Anthony Minessale II <anthmct@yahoo.com>
|
||||
*
|
||||
*
|
||||
* mod_lumenvox.c -- Lumenvox Interface
|
||||
*
|
||||
*
|
||||
*/
|
||||
#ifdef __ICC
|
||||
#pragma warning (disable:188)
|
||||
#endif
|
||||
|
||||
#include <LVSpeechPort.h>
|
||||
#include <switch.h>
|
||||
#include <sstream>
|
||||
|
||||
static const char modname[] = "mod_lumenvox";
|
||||
|
||||
typedef enum {
|
||||
LVFLAG_HAS_TEXT = (1 << 0),
|
||||
LVFLAG_BARGE = (1 << 1),
|
||||
LVFLAG_READY = (1 << 2)
|
||||
} lvflag_t;
|
||||
|
||||
typedef struct {
|
||||
LVSpeechPort port;
|
||||
uint32_t flags;
|
||||
int sound_format;
|
||||
int channel;
|
||||
switch_mutex_t *flag_mutex;
|
||||
} lumenvox_t;
|
||||
|
||||
static void log_callback(const char* message, void* userdata)
|
||||
{
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s\n", message);
|
||||
}
|
||||
|
||||
static const char *state_names[] = {
|
||||
"NOT_READY",
|
||||
"READY",
|
||||
"BARGE_IN",
|
||||
"END_SPEECH",
|
||||
"STOPPED",
|
||||
"BARGE_IN_TIMEOUT",
|
||||
"END_SPEECH_TIMEOUT",
|
||||
"BEEP"
|
||||
};
|
||||
|
||||
std::ostream& operator << (std::ostream& os ,const LVSemanticData& Data)
|
||||
{
|
||||
int i;
|
||||
LVSemanticObject Obj;
|
||||
switch (Data.Type())
|
||||
{
|
||||
case SI_TYPE_BOOL:
|
||||
os << Data.GetBool();
|
||||
break;
|
||||
case SI_TYPE_INT:
|
||||
os << Data.GetInt();
|
||||
break;
|
||||
case SI_TYPE_DOUBLE:
|
||||
os << Data.GetDouble();
|
||||
break;
|
||||
case SI_TYPE_STRING:
|
||||
os << Data.GetString();
|
||||
break;
|
||||
case SI_TYPE_OBJECT:
|
||||
Obj = Data.GetSemanticObject();
|
||||
for (i = 0; i < Obj.NumberOfProperties(); ++i)
|
||||
{
|
||||
os << "<" << Obj.PropertyName(i) << ">";
|
||||
os << Obj.PropertyValue(i);
|
||||
os << "</" << Obj.PropertyName(i) << ">";
|
||||
}
|
||||
break;
|
||||
case SI_TYPE_ARRAY:
|
||||
for (i = 0; i < Data.GetSemanticArray().Size(); ++i)
|
||||
{
|
||||
os << Data.GetArray().At(i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
//==============================================================================================
|
||||
// code to plug LVInterpretation into any standard stream
|
||||
std::ostream& operator << (std::ostream& os, const LVInterpretation& Interp)
|
||||
{
|
||||
os << "<interpretation grammar=\""<<Interp.GrammarLabel()
|
||||
<<"\" score=\""<<Interp.Score()<<"\">";
|
||||
os << "<result name=\""<<Interp.ResultName()<<"\">";
|
||||
os << Interp.ResultData();
|
||||
os << "</result>";
|
||||
os << "<input>";
|
||||
os << Interp.InputSentence();
|
||||
os << "</input>";
|
||||
os << "</interpretation>";
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
static void state_change_callback(long new_state, unsigned long total_bytes,
|
||||
unsigned long recorded_bytes, void *user_data)
|
||||
{
|
||||
lumenvox_t *lv = (lumenvox_t *) user_data;
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "State: [%s] total bytes: [%ld] recorded bytes: [%ld]\n",
|
||||
state_names[new_state],
|
||||
total_bytes,
|
||||
recorded_bytes);
|
||||
|
||||
switch (new_state)
|
||||
{
|
||||
case STREAM_STATUS_READY:
|
||||
break;
|
||||
case STREAM_STATUS_STOPPED:
|
||||
switch_clear_flag_locked(lv, LVFLAG_READY);
|
||||
break;
|
||||
case STREAM_STATUS_END_SPEECH:
|
||||
switch_set_flag_locked(lv, LVFLAG_HAS_TEXT);
|
||||
break;
|
||||
case STREAM_STATUS_BARGE_IN:
|
||||
switch_set_flag_locked(lv, LVFLAG_BARGE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static switch_status_t lumenvox_asr_pause(switch_asr_handle_t *ah)
|
||||
{
|
||||
lumenvox_t *lv = (lumenvox_t *) ah->private_info;
|
||||
|
||||
if (switch_test_flag(lv, LVFLAG_READY)) {
|
||||
lv->port.StreamStop();
|
||||
switch_clear_flag_locked(lv, LVFLAG_READY);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
static switch_status_t lumenvox_asr_resume(switch_asr_handle_t *ah)
|
||||
{
|
||||
lumenvox_t *lv = (lumenvox_t *) ah->private_info;
|
||||
|
||||
switch_clear_flag_locked(lv, LVFLAG_HAS_TEXT);
|
||||
|
||||
if (!switch_test_flag(lv, LVFLAG_READY)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Manually Resuming\n");
|
||||
if (lv->port.StreamStart()) {
|
||||
lv->port.ClosePort();
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
switch_set_flag_locked(lv, LVFLAG_READY);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
/*! function to open the asr interface */
|
||||
static switch_status_t lumenvox_asr_open(switch_asr_handle_t *ah, char *codec, int rate, char *dest, switch_asr_flag_t *flags)
|
||||
{
|
||||
|
||||
lumenvox_t *lv;
|
||||
int error_code;
|
||||
|
||||
if (!(lv = (lumenvox_t *) switch_core_alloc(ah->memory_pool, sizeof(*lv)))) {
|
||||
return SWITCH_STATUS_MEMERR;
|
||||
}
|
||||
|
||||
if (rate != 8000 && rate != 16000) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Rate: Pick 8000 or 16000\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
if (!strcasecmp(codec, "PCMU")) {
|
||||
switch (rate) {
|
||||
case 8000:
|
||||
lv->sound_format = ULAW_8KHZ;
|
||||
break;
|
||||
}
|
||||
} else if (!strcasecmp(codec, "PCMA")) {
|
||||
switch (rate) {
|
||||
case 8000:
|
||||
lv->sound_format = ULAW_8KHZ;
|
||||
break;
|
||||
}
|
||||
} else if (!strcasecmp(codec, "speex")) {
|
||||
switch (rate) {
|
||||
case 8000:
|
||||
lv->sound_format = SPX_8KHZ;
|
||||
break;
|
||||
case 16000:
|
||||
lv->sound_format = SPX_16KHZ;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!lv->sound_format) {
|
||||
codec = "L16";
|
||||
switch (rate) {
|
||||
case 8000:
|
||||
lv->sound_format = PCM_8KHZ;
|
||||
break;
|
||||
case 16000:
|
||||
lv->sound_format = PCM_16KHZ;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!lv->sound_format) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot negotiate sound format.\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
ah->rate = rate;
|
||||
ah->codec = switch_core_strdup(ah->memory_pool, codec);
|
||||
|
||||
lv->port.OpenPort(log_callback, NULL, 5);
|
||||
error_code = lv->port.GetOpenPortStatus();
|
||||
|
||||
switch(error_code)
|
||||
{
|
||||
case LV_FAILURE:
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Licenses Exceeded!\n");
|
||||
return SWITCH_STATUS_GENERR;
|
||||
case LV_OPEN_PORT_FAILED__PRIMARY_SERVER_NOT_RESPONDING:
|
||||
case LV_NO_SERVER_RESPONDING:
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SRE Server Unavailable!\n");
|
||||
return SWITCH_STATUS_GENERR;
|
||||
case LV_SUCCESS:
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Port Opened %d %dkhz.\n", lv->sound_format, rate);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// turn on sound and response file logging
|
||||
/*
|
||||
int save_sound_files = 1;
|
||||
lv->port.SetPropertyEx(PROP_EX_SAVE_SOUND_FILES,
|
||||
PROP_EX_VALUE_TYPE_INT_PTR,
|
||||
&save_sound_files);
|
||||
*/
|
||||
lv->channel = 1;
|
||||
lv->flags = *flags;
|
||||
lv->port.StreamSetParameter(STREAM_PARM_DETECT_BARGE_IN, 1);
|
||||
lv->port.StreamSetParameter(STREAM_PARM_DETECT_END_OF_SPEECH, 1);
|
||||
lv->port.StreamSetParameter(STREAM_PARM_AUTO_DECODE, 1);
|
||||
lv->port.StreamSetParameter(STREAM_PARM_DECODE_FLAGS, LV_DECODE_SEMANTIC_INTERPRETATION);
|
||||
lv->port.StreamSetParameter(STREAM_PARM_VOICE_CHANNEL, lv->channel);
|
||||
lv->port.StreamSetParameter(STREAM_PARM_GRAMMAR_SET, (long unsigned int) LV_ACTIVE_GRAMMAR_SET);
|
||||
|
||||
|
||||
lv->port.StreamSetStateChangeCallBack(state_change_callback, lv);
|
||||
lv->port.StreamSetParameter(STREAM_PARM_SOUND_FORMAT, lv->sound_format);
|
||||
|
||||
if (dest) {
|
||||
lv->port.SetClientPropertyEx(PROP_EX_SRE_SERVERS, PROP_EX_VALUE_TYPE_STRING, (void *) dest);
|
||||
}
|
||||
|
||||
switch_mutex_init(&lv->flag_mutex, SWITCH_MUTEX_NESTED, ah->memory_pool);
|
||||
|
||||
switch_set_flag_locked(lv, LVFLAG_READY);
|
||||
if (lv->port.StreamStart()) {
|
||||
lv->port.ClosePort();
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
ah->private_info = lv;
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*! function to load a grammar to the asr interface */
|
||||
static switch_status_t lumenvox_asr_load_grammar(switch_asr_handle_t *ah, char *grammar, char *path)
|
||||
{
|
||||
lumenvox_t *lv = (lumenvox_t *) ah->private_info;
|
||||
|
||||
if (path) {
|
||||
if (!lv->port.LoadGrammar(grammar, path)) {
|
||||
if (!lv->port.ActivateGrammar(grammar)) {
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (lv->port.ActivateGrammar(grammar)) {
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
|
||||
/*! function to unload a grammar to the asr interface */
|
||||
static switch_status_t lumenvox_asr_unload_grammar(switch_asr_handle_t *ah, char *grammar)
|
||||
{
|
||||
lumenvox_t *lv = (lumenvox_t *) ah->private_info;
|
||||
|
||||
if (lv->port.DeactivateGrammar(grammar)) {
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*! function to close the asr interface */
|
||||
static switch_status_t lumenvox_asr_close(switch_asr_handle_t *ah, switch_asr_flag_t *flags)
|
||||
{
|
||||
lumenvox_t *lv = (lumenvox_t *) ah->private_info;
|
||||
|
||||
switch_set_flag(ah, SWITCH_ASR_FLAG_CLOSED);
|
||||
lv->port.ClosePort();
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Port Closed.\n");
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*! function to feed audio to the ASR*/
|
||||
static switch_status_t lumenvox_asr_feed(switch_asr_handle_t *ah, void *data, unsigned int len, switch_asr_flag_t *flags)
|
||||
{
|
||||
|
||||
lumenvox_t *lv = (lumenvox_t *) ah->private_info;
|
||||
|
||||
if (!switch_test_flag(lv, LVFLAG_HAS_TEXT) && switch_test_flag(lv, LVFLAG_READY)) {
|
||||
if (lv->port.StreamSendData(data, len)) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*! function to read results from the ASR*/
|
||||
static switch_status_t lumenvox_asr_check_results(switch_asr_handle_t *ah, switch_asr_flag_t *flags)
|
||||
{
|
||||
lumenvox_t *lv = (lumenvox_t *) ah->private_info;
|
||||
|
||||
return (switch_test_flag(lv, LVFLAG_HAS_TEXT) || switch_test_flag(lv, LVFLAG_BARGE)) ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
/*! function to read results from the ASR*/
|
||||
static switch_status_t lumenvox_asr_get_results(switch_asr_handle_t *ah, char **xmlstr, switch_asr_flag_t *flags)
|
||||
{
|
||||
lumenvox_t *lv = (lumenvox_t *) ah->private_info;
|
||||
switch_status_t ret = SWITCH_STATUS_SUCCESS;
|
||||
|
||||
if (switch_test_flag(lv, LVFLAG_BARGE)) {
|
||||
switch_clear_flag_locked(lv, LVFLAG_BARGE);
|
||||
ret = SWITCH_STATUS_BREAK;
|
||||
}
|
||||
|
||||
if (switch_test_flag(lv, LVFLAG_HAS_TEXT)) {
|
||||
std::stringstream ss;
|
||||
int numInterp;
|
||||
int code;
|
||||
|
||||
|
||||
lv->port.StreamStop();
|
||||
code = lv->port.WaitForEngineToIdle(3000, lv->channel);
|
||||
|
||||
if (code == LV_TIME_OUT) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
numInterp = lv->port.GetNumberOfInterpretations(lv->channel);
|
||||
|
||||
for (int t = 0; t < numInterp; ++t) {
|
||||
ss << lv->port.GetInterpretation(lv->channel, t);
|
||||
}
|
||||
|
||||
*xmlstr = strdup((char *)ss.str().c_str());
|
||||
switch_clear_flag_locked(lv, LVFLAG_HAS_TEXT);
|
||||
|
||||
|
||||
if (switch_test_flag(lv, SWITCH_ASR_FLAG_AUTO_RESUME)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Auto Resuming\n");
|
||||
switch_set_flag_locked(lv, LVFLAG_READY);
|
||||
if (lv->port.StreamStart()) {
|
||||
lv->port.ClosePort();
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
}
|
||||
|
||||
ret = SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const switch_asr_interface_t lumenvox_asr_interface = {
|
||||
/*.interface_name*/ "lumenvox",
|
||||
/*.asr_open*/ lumenvox_asr_open,
|
||||
/*.asr_load_grammar*/ lumenvox_asr_load_grammar,
|
||||
/*.asr_unload_grammar*/ lumenvox_asr_unload_grammar,
|
||||
/*.asr_close*/ lumenvox_asr_close,
|
||||
/*.asr_feed*/ lumenvox_asr_feed,
|
||||
/*.asr_resume*/ lumenvox_asr_resume,
|
||||
/*.asr_pause*/ lumenvox_asr_pause,
|
||||
/*.asr_check_results*/ lumenvox_asr_check_results,
|
||||
/*.asr_get_results*/ lumenvox_asr_get_results
|
||||
};
|
||||
|
||||
static const switch_loadable_module_interface_t lumenvox_module_interface = {
|
||||
/*.module_name */ modname,
|
||||
/*.endpoint_interface */ NULL,
|
||||
/*.timer_interface */ NULL,
|
||||
/*.dialplan_interface */ NULL,
|
||||
/*.codec_interface */ NULL,
|
||||
/*.application_interface */ NULL,
|
||||
/*.api_interface */ NULL,
|
||||
/*.file_interface */ NULL,
|
||||
/*.speech_interface */ NULL,
|
||||
/*.directory_interface */ NULL,
|
||||
/*.chat_interface */ NULL,
|
||||
/*.say_interface */ NULL,
|
||||
/*.asr_interface */ &lumenvox_asr_interface
|
||||
};
|
||||
|
||||
switch_status_t switch_module_load(const switch_loadable_module_interface_t **module_interface, char *filename)
|
||||
{
|
||||
LVSpeechPort::RegisterAppLogMsg(log_callback, NULL, 5);
|
||||
//LVSpeechPort::SetClientPropertyEx(PROP_EX_SRE_SERVERS, PROP_EX_VALUE_TYPE_STRING, (void *)"127.0.0.1");
|
||||
|
||||
/* connect my internal structure to the blank pointer passed to me */
|
||||
*module_interface = &lumenvox_module_interface;
|
||||
|
||||
/* indicate that the module should continue to be loaded */
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SWITCH_MOD_DECLARE(switch_status_t) switch_module_shutdown(void)
|
||||
{
|
||||
return SWITCH_STATUS_UNLOAD;
|
||||
}
|
Loading…
Reference in New Issue
Block a user