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:
Anthony Minessale 2007-01-25 00:19:41 +00:00
parent 8662ab4882
commit b0eb04c065
2 changed files with 477 additions and 0 deletions

View 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

View 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;
}