提交 44fc26f7 authored 作者: Anthony Minessale's avatar Anthony Minessale

Finalization of speech detect interface and API

This changes the core to have the necessary tools to create
a speech detection interface.

It also changes the code in javascript (mod_spidermonkey)
there are a few api changes in how it handles callbacks

It also adds grammars as a system dir to store asr grammars




git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3291 d0543943-73ff-0310-b7d9-9358b9ac24b2
上级 b942d8e0
差异被折叠。
......@@ -124,5 +124,5 @@
/* Define to rpl_malloc if the replacement function should be used. */
#undef malloc
/* Define to `unsigned int' if <sys/types.h> does not define. */
/* Define to `unsigned' if <sys/types.h> does not define. */
#undef size_t
......@@ -119,14 +119,21 @@ struct switch_core_port_allocator;
\param session the session to add the bug to
\param callback a callback for events
\param user_data arbitrary user data
\param flags flags to choose the stream
\param new_bug pointer to assign new bug to
\return SWITCH_STATUS_SUCCESS if the operation was a success
*/
SWITCH_DECLARE(switch_status_t) switch_core_media_bug_add(switch_core_session_t *session,
switch_media_bug_callback_t callback,
void *user_data,
switch_media_bug_flag_t flags,
switch_media_bug_t **new_bug);
/*!
\brief Obtain private data from a media bug
\param session the session to obtain the private data from
\return the private data
*/
SWITCH_DECLARE(void *) switch_core_media_bug_get_user_data(switch_media_bug_t *bug);
/*!
\brief Remove a media bug from the session
......@@ -1060,7 +1067,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_close(switch_file_handle_t *fh)
\param module_name the speech module to use
\param voice_name the desired voice name
\param rate the sampling rate
\param flags asr/tts flags
\param flags tts flags
\param pool the pool to use (NULL for new pool)
\return SWITCH_STATUS_SUCCESS if the handle is opened
*/
......@@ -1070,28 +1077,6 @@ SWITCH_DECLARE(switch_status_t) switch_core_speech_open(switch_speech_handle_t *
unsigned int rate,
switch_speech_flag_t *flags,
switch_memory_pool_t *pool);
/*!
\brief Feed data to the ASR module
\param sh the speech handle to feed
\param data the buffer of audio data
\param len the in-use size of the buffer
\param rate the rate of the audio (in hz)
\param flags flags in/out for fine tuning
\return SWITCH_STATUS_SUCCESS with possible new flags on success
*/
SWITCH_DECLARE(switch_status_t) switch_core_speech_feed_asr(switch_speech_handle_t *sh, void *data, unsigned int *len, int rate, switch_speech_flag_t *flags);
/*!
\brief Get text back from the ASR module
\param sh the speech handle to read
\param buf the buffer to insert the text into
\param buflen the max size of the buffer
\param flags flags in/out for fine tuning
\return SWITCH_STATUS_SUCCESS with possible new flags on success
*/
SWITCH_DECLARE(switch_status_t) switch_core_speech_interpret_asr(switch_speech_handle_t *sh, char *buf, unsigned int buflen, switch_speech_flag_t *flags);
/*!
\brief Feed text to the TTS module
\param sh the speech handle to feed
......@@ -1152,6 +1137,92 @@ SWITCH_DECLARE(switch_status_t) switch_core_speech_read_tts(switch_speech_handle
\return SWITCH_STATUS_SUCCESS if the file handle was closed
*/
SWITCH_DECLARE(switch_status_t) switch_core_speech_close(switch_speech_handle_t *sh, switch_speech_flag_t *flags);
/*!
\brief Open an asr handle
\param ah the asr handle to open
\param module_name the name of the asr module
\param codec the preferred codec
\param rate the preferred rate
\param dest the destination address
\param flags flags to influence behaviour
\param pool the pool to use (NULL for new pool)
\return SWITCH_STATUS_SUCCESS if the asr handle was opened
*/
SWITCH_DECLARE(switch_status_t) switch_core_asr_open(switch_asr_handle_t *ah,
char *module_name,
char *codec,
int rate,
char *dest,
switch_asr_flag_t *flags,
switch_memory_pool_t *pool);
/*!
\brief Close an asr handle
\param ah the handle to close
\param flags flags to influence behaviour
\return SWITCH_STATUS_SUCCESS
*/
SWITCH_DECLARE(switch_status_t) switch_core_asr_close(switch_asr_handle_t *ah, switch_asr_flag_t *flags);
/*!
\brief Feed audio data to an asr handle
\param ah the handle to feed data to
\param data a pointer to the data
\param len the size in bytes of the data
\param flags flags to influence behaviour
\return SWITCH_STATUS_SUCCESS
*/
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 Check an asr handle for results
\param ah the handle to check
\param flags flags to influence behaviour
\return SWITCH_STATUS_SUCCESS
*/
SWITCH_DECLARE(switch_status_t) switch_core_asr_check_results(switch_asr_handle_t *ah, switch_asr_flag_t *flags);
/*!
\brief Get results from an asr handle
\param ah the handle to get results from
\param xmlstr a pointer to dynamically allocate an xml result string to
\param flags flags to influence behaviour
\return SWITCH_STATUS_SUCCESS
*/
SWITCH_DECLARE(switch_status_t) switch_core_asr_get_results(switch_asr_handle_t *ah, char **xmlstr, switch_asr_flag_t *flags);
/*!
\brief Load a grammar to an asr handle
\param ah the handle to load to
\param grammar the name of the grammar
\param path the path to the grammaar file
\return SWITCH_STATUS_SUCCESS
*/
SWITCH_DECLARE(switch_status_t) switch_core_asr_load_grammar(switch_asr_handle_t *ah, char *grammar, char *path);
/*!
\brief Unload a grammar from an asr handle
\param ah the handle to unload the grammar from
\return SWITCH_STATUS_SUCCESS
*/
SWITCH_DECLARE(switch_status_t) switch_core_asr_unload_grammar(switch_asr_handle_t *ah, char *grammar);
/*!
\brief Pause detection on an asr handle
\param ah the handle to pause
\return SWITCH_STATUS_SUCCESS
*/
SWITCH_DECLARE(switch_status_t) switch_core_asr_pause(switch_asr_handle_t *ah);
/*!
\brief Resume detection on an asr handle
\param ah the handle to resume
\return SWITCH_STATUS_SUCCESS
*/
SWITCH_DECLARE(switch_status_t) switch_core_asr_resume(switch_asr_handle_t *ah);
///\}
......
......@@ -69,12 +69,14 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_park(switch_core_session_t *session);
\param dtmf_callback code to execute if any dtmf is dialed during the recording
\param buf an object to maintain across calls
\param buflen the size of buf
\param timeout a timeout in milliseconds
\return SWITCH_STATUS_SUCCESS to keep the collection moving.
*/
SWITCH_DECLARE(switch_status_t) switch_ivr_collect_digits_callback(switch_core_session_t *session,
switch_input_callback_function_t dtmf_callback,
void *buf,
unsigned int buflen);
switch_input_callback_function_t dtmf_callback,
void *buf,
unsigned int buflen,
unsigned int timeout);
/*!
\brief Wait for specified number of DTMF digits, untile terminator is received or until the channel hangs up.
......@@ -95,6 +97,61 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_collect_digits_count(switch_core_sess
char *terminator,
unsigned int timeout);
/*!
\brief Engage background Speech detection on a session
\param session the session to attach
\param mod_name the module name of the ASR library
\param grammar the grammar name
\param path the path to the grammar file
\param dest the destination address
\param ah an ASR handle to use (NULL to create one)
\return SWITCH_STATUS_SUCCESS if all is well
*/
SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech(switch_core_session_t *session,
char *mod_name,
char *grammar,
char *path,
char *dest,
switch_asr_handle_t *ah);
/*!
\brief Stop background Speech detection on a session
\param session The session to stop detection on
\return SWITCH_STATUS_SUCCESS if all is well
*/
SWITCH_DECLARE(switch_status_t) switch_ivr_stop_detect_speech(switch_core_session_t *session);
/*!
\brief Pause background Speech detection on a session
\param session The session to pause detection on
\return SWITCH_STATUS_SUCCESS if all is well
*/
SWITCH_DECLARE(switch_status_t) switch_ivr_pause_detect_speech(switch_core_session_t *session);
/*!
\brief Resume background Speech detection on a session
\param session The session to resume detection on
\return SWITCH_STATUS_SUCCESS if all is well
*/
SWITCH_DECLARE(switch_status_t) switch_ivr_resume_detect_speech(switch_core_session_t *session);
/*!
\brief Load a grammar on a background speech detection handle
\param session The session to change the grammar on
\param grammar the grammar name
\param path the grammar path
\return SWITCH_STATUS_SUCCESS if all is well
*/
SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech_load_grammar(switch_core_session_t *session, char *grammar, char *path);
/*!
\brief Unload a grammar on a background speech detection handle
\param session The session to change the grammar on
\param grammar the grammar name
\return SWITCH_STATUS_SUCCESS if all is well
*/
SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech_unload_grammar(switch_core_session_t *session, char *grammar);
/*!
\brief Record a session to disk
\param session the session to record
......
......@@ -75,6 +75,8 @@ struct switch_loadable_module_interface {
const switch_directory_interface_t *directory_interface;
/*! the table of chat interfaces the module has implmented */
const switch_chat_interface_t *chat_interface;
/*! the table of asr interfaces the module has implmented */
const switch_asr_interface_t *asr_interface;
};
/*!
......@@ -158,6 +160,13 @@ SWITCH_DECLARE(switch_file_interface_t *) switch_loadable_module_get_file_interf
*/
SWITCH_DECLARE(switch_speech_interface_t *) switch_loadable_module_get_speech_interface(char *name);
/*!
\brief Retrieve the asr interface by it's registered name
\param name the name of the asr interface
\return the desired asr interface
*/
SWITCH_DECLARE(switch_asr_interface_t *) switch_loadable_module_get_asr_interface(char *name);
/*!
\brief Retrieve the directory interface by it's registered name
\param name the name of the directory interface
......
......@@ -315,6 +315,53 @@ struct switch_file_handle {
switch_buffer_t *audio_buffer;
};
/*! \brief Abstract interface to an asr module */
struct switch_asr_interface {
/*! the name of the interface */
const char *interface_name;
/*! function to open the asr interface */
switch_status_t (*asr_open)(switch_asr_handle_t *ah,
char *codec,
int rate,
char *dest,
switch_asr_flag_t *flags);
/*! function to load a grammar to the asr interface */
switch_status_t (*asr_load_grammar)(switch_asr_handle_t *ah, char *grammar, char *path);
/*! function to unload a grammar to the asr interface */
switch_status_t (*asr_unload_grammar)(switch_asr_handle_t *ah, char *grammar);
/*! function to close the asr interface */
switch_status_t (*asr_close)(switch_asr_handle_t *ah, switch_asr_flag_t *flags);
/*! function to feed audio to the ASR*/
switch_status_t (*asr_feed)(switch_asr_handle_t *ah, void *data, unsigned int len, switch_asr_flag_t *flags);
/*! function to resume the ASR*/
switch_status_t (*asr_resume)(switch_asr_handle_t *ah);
/*! function to pause the ASR*/
switch_status_t (*asr_pause)(switch_asr_handle_t *ah);
/*! function to read results from the ASR*/
switch_status_t (*asr_check_results)(switch_asr_handle_t *ah, switch_asr_flag_t *flags);
/*! function to read results from the ASR*/
switch_status_t (*asr_get_results)(switch_asr_handle_t *ah, char **xmlstr, switch_asr_flag_t *flags);
const struct switch_asr_interface *next;
};
/*! an abstract representation of an asr speech interface. */
struct switch_asr_handle {
/*! the interface of the module that implemented the current speech interface */
const switch_asr_interface_t *asr_interface;
/*! flags to control behaviour */
uint32_t flags;
/*! The Name*/
char *name;
/*! The Codec*/
char *codec;
/*! The Rate*/
uint32_t rate;
char *grammar;
/*! the handle's memory pool */
switch_memory_pool_t *memory_pool;
/*! private data for the format module to store handle specific info */
void *private_info;
};
/*! \brief Abstract interface to a speech module */
struct switch_speech_interface {
......@@ -328,10 +375,6 @@ struct switch_speech_interface {
/*! function to close the speech interface */
switch_status_t (*speech_close)(switch_speech_handle_t *, switch_speech_flag_t *flags);
/*! function to feed audio to the ASR*/
switch_status_t (*speech_feed_asr)(switch_speech_handle_t *sh, void *data, unsigned int *len, int rate, switch_speech_flag_t *flags);
/*! function to read text from the ASR*/
switch_status_t (*speech_interpret_asr)(switch_speech_handle_t *sh, char *buf, unsigned int buflen, switch_speech_flag_t *flags);
/*! function to feed text to the TTS*/
switch_status_t (*speech_feed_tts)(switch_speech_handle_t *sh, char *text, switch_speech_flag_t *flags);
/*! function to read audio from the TTS*/
switch_status_t (*speech_read_tts)(switch_speech_handle_t *sh,
......
......@@ -72,6 +72,10 @@ SWITCH_BEGIN_EXTERN_C
#define SWITCH_HTDOCS_DIR SWITCH_PREFIX_DIR SWITCH_PATH_SEPARATOR "htdocs"
#endif
#ifndef SWITCH_GRAMMAR_DIR
#define SWITCH_GRAMMAR_DIR SWITCH_PREFIX_DIR SWITCH_PATH_SEPARATOR "grammar"
#endif
#define SWITCH_R_SDP_VARIABLE "_switch_r_sdp_"
#define SWITCH_L_SDP_VARIABLE "_switch_l_sdp_"
#define SWITCH_B_SDP_VARIABLE "_switch_m_sdp_"
......@@ -82,7 +86,7 @@ SWITCH_BEGIN_EXTERN_C
#define SWITCH_LOCAL_MEDIA_PORT_VARIABLE "_local_media_port_"
#define SWITCH_REMOTE_MEDIA_IP_VARIABLE "_remote_media_ip_"
#define SWITCH_REMOTE_MEDIA_PORT_VARIABLE "_remote_media_port_"
#define SWITCH_SPEECH_KEY "_speech_"
#define SWITCH_BITS_PER_BYTE 8
typedef uint8_t switch_byte_t;
......@@ -132,6 +136,7 @@ struct switch_directories {
char *script_dir;
char *temp_dir;
char *htdocs_dir;
char *grammar_dir;
};
typedef struct switch_directories switch_directories;
......@@ -313,6 +318,7 @@ typedef enum {
SWITCH_STATUS_SOCKERR - A socket error
SWITCH_STATUS_MORE_DATA - Need More Data
SWITCH_STATUS_NOTFOUND - Not Found
SWITCH_STATUS_UNLOAD - Unload
</pre>
*/
typedef enum {
......@@ -330,7 +336,8 @@ typedef enum {
SWITCH_STATUS_BREAK,
SWITCH_STATUS_SOCKERR,
SWITCH_STATUS_MORE_DATA,
SWITCH_STATUS_NOTFOUND
SWITCH_STATUS_NOTFOUND,
SWITCH_STATUS_UNLOAD
} switch_status_t;
......@@ -522,26 +529,42 @@ typedef enum {
\enum switch_speech_flag_t
\brief Speech related flags
<pre>
SWITCH_SPEECH_FLAG_TTS = (1 << 0) - Interface can/should convert text to speech.
SWITCH_SPEECH_FLAG_ASR = (1 << 1) - Interface can/should convert audio to text.
SWITCH_SPEECH_FLAG_HASTEXT = (1 << 2) - Interface is has text to read.
SWITCH_SPEECH_FLAG_PEEK = (1 << 3) - Read data but do not erase it.
SWITCH_SPEECH_FLAG_FREE_POOL = (1 << 4) - Free interface's pool on destruction.
SWITCH_SPEECH_FLAG_BLOCKING = (1 << 5) - Indicate that a blocking call is desired
SWITCH_SPEECH_FLAG_PAUSE = (1 << 6) - Pause toggle for playback
SWITCH_SPEECH_FLAG_HASTEXT = (1 << 0) - Interface is has text to read.
SWITCH_SPEECH_FLAG_PEEK = (1 << 1) - Read data but do not erase it.
SWITCH_SPEECH_FLAG_FREE_POOL = (1 << 2) - Free interface's pool on destruction.
SWITCH_SPEECH_FLAG_BLOCKING = (1 << 3) - Indicate that a blocking call is desired
SWITCH_SPEECH_FLAG_PAUSE = (1 << 4) - Pause toggle for playback
</pre>
*/
typedef enum {
SWITCH_SPEECH_FLAG_TTS = (1 << 0),
SWITCH_SPEECH_FLAG_ASR = (1 << 1),
SWITCH_SPEECH_FLAG_HASTEXT = (1 << 2),
SWITCH_SPEECH_FLAG_PEEK = (1 << 3),
SWITCH_SPEECH_FLAG_FREE_POOL = (1 << 4),
SWITCH_SPEECH_FLAG_BLOCKING = (1 << 5),
SWITCH_SPEECH_FLAG_PAUSE = (1 << 6)
SWITCH_SPEECH_FLAG_NONE = 0,
SWITCH_SPEECH_FLAG_HASTEXT = (1 << 0),
SWITCH_SPEECH_FLAG_PEEK = (1 << 1),
SWITCH_SPEECH_FLAG_FREE_POOL = (1 << 2),
SWITCH_SPEECH_FLAG_BLOCKING = (1 << 3),
SWITCH_SPEECH_FLAG_PAUSE = (1 << 4)
} switch_speech_flag_t;
/*!
\enum switch_asr_flag_t
\brief Asr related flags
<pre>
SWITCH_ASR_FLAG_DATA = (1 << 0) - Interface has data
SWITCH_ASR_FLAG_FREE_POOL = (1 << 1) - Pool needs to be freed
SWITCH_ASR_FLAG_CLOSED = (1 << 2) - Interface has been closed
SWITCH_ASR_FLAG_FIRE_EVENTS = (1 << 3) - Fire all speech events
SWITCH_ASR_FLAG_AUTO_RESUME = (1 << 4) - Auto Resume
</pre>
*/
typedef enum {
SWITCH_ASR_FLAG_NONE = 0,
SWITCH_ASR_FLAG_DATA = (1 << 0),
SWITCH_ASR_FLAG_FREE_POOL = (1 << 1),
SWITCH_ASR_FLAG_CLOSED = (1 << 2),
SWITCH_ASR_FLAG_FIRE_EVENTS = (1 << 3),
SWITCH_ASR_FLAG_AUTO_RESUME = (1 << 4)
} switch_asr_flag_t;
/*!
\enum switch_directory_flag_t
......@@ -584,6 +607,21 @@ typedef enum {
SWITCH_TIMER_FLAG_FREE_POOL = (1 << 0),
} switch_timer_flag_t;
/*!
\enum switch_timer_flag_t
\brief Timer related flags
<pre>
SMBF_READ_STREAM - Include the Read Stream
SMBF_WRITE_STREAM - Include the Write Stream
</pre>
*/
typedef enum {
SMBF_BOTH = 0,
SMBF_READ_STREAM = (1 << 0),
SMBF_WRITE_STREAM = (1 << 1)
} switch_media_bug_flag_t;
/*!
\enum switch_file_flag_t
\brief File flags
......@@ -653,6 +691,7 @@ typedef enum {
SWITCH_EVENT_PRESENCE - Presence Info
SWITCH_EVENT_CODEC - Codec Change
SWITCH_EVENT_BACKGROUND_JOB - Background Job
SWITCH_EVENT_DETECTED_SPEECH - Detected Speech
SWITCH_EVENT_ALL - All events at once
</pre>
......@@ -690,6 +729,7 @@ typedef enum {
SWITCH_EVENT_ROSTER,
SWITCH_EVENT_CODEC,
SWITCH_EVENT_BACKGROUND_JOB,
SWITCH_EVENT_DETECTED_SPEECH,
SWITCH_EVENT_ALL
} switch_event_types_t;
......@@ -800,10 +840,9 @@ typedef struct switch_io_event_hook_waitfor_write switch_io_event_hook_waitfor_w
typedef struct switch_io_event_hook_send_dtmf switch_io_event_hook_send_dtmf_t;
typedef struct switch_io_routines switch_io_routines_t;
typedef struct switch_io_event_hooks switch_io_event_hooks_t;
typedef struct switch_speech_handle switch_speech_handle_t;
typedef struct switch_asr_handle switch_asr_handle_t;
typedef struct switch_directory_handle switch_directory_handle_t;
typedef struct switch_loadable_module_interface switch_loadable_module_interface_t;
typedef struct switch_endpoint_interface switch_endpoint_interface_t;
typedef struct switch_timer_interface switch_timer_interface_t;
......@@ -813,6 +852,7 @@ typedef struct switch_application_interface switch_application_interface_t;
typedef struct switch_api_interface switch_api_interface_t;
typedef struct switch_file_interface switch_file_interface_t;
typedef struct switch_speech_interface switch_speech_interface_t;
typedef struct switch_asr_interface switch_asr_interface_t;
typedef struct switch_directory_interface switch_directory_interface_t;
typedef struct switch_chat_interface switch_chat_interface_t;
typedef struct switch_core_port_allocator switch_core_port_allocator_t;
......
......@@ -393,10 +393,12 @@ static switch_status_t originate_function(char *cmd, switch_core_session_t *ises
switch_channel_t *caller_channel;
switch_core_session_t *caller_session;
char *argv[7] = {0};
int x, argc = 0;
int i = 0, x, argc = 0;
char *aleg, *exten, *dp, *context, *cid_name, *cid_num;
uint32_t timeout = 60;
switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING;
uint8_t machine = 1;
if (isession) {
stream->write_function(stream, "Illegal Usage\n");
return SWITCH_STATUS_SUCCESS;
......@@ -414,13 +416,18 @@ static switch_status_t originate_function(char *cmd, switch_core_session_t *ises
argv[x] = NULL;
}
}
if (!strcasecmp(argv[0], "machine")) {
machine = 1;
i++;
}
aleg = argv[0];
exten = argv[1];
dp = argv[2];
context = argv[3];
cid_name = argv[4];
cid_num = argv[5];
aleg = argv[i++];
exten = argv[i++];
dp = argv[i++];
context = argv[i++];
cid_name = argv[i++];
cid_num = argv[i++];
if (!dp) {
dp = "XML";
......@@ -435,7 +442,11 @@ static switch_status_t originate_function(char *cmd, switch_core_session_t *ises
}
if (switch_ivr_originate(NULL, &caller_session, &cause, aleg, timeout, &noop_state_handler, cid_name, cid_num, NULL) != SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "Cannot Create Outgoing Channel! [%s]\n", aleg);
if (machine) {
stream->write_function(stream, "fail: %s", switch_channel_cause2str(cause));
} else {
stream->write_function(stream, "Cannot Create Outgoing Channel! [%s] cause: %s\n", aleg, switch_channel_cause2str(cause));
}
return SWITCH_STATUS_SUCCESS;
}
......@@ -467,7 +478,13 @@ static switch_status_t originate_function(char *cmd, switch_core_session_t *ises
} else {
switch_ivr_session_transfer(caller_session, exten, dp, context);
}
stream->write_function(stream, "Created Session: %s\n", switch_core_session_get_uuid(caller_session));
if (machine) {
stream->write_function(stream, "success: %s\n", switch_core_session_get_uuid(caller_session));
} else {
stream->write_function(stream, "Created Session: %s\n", switch_core_session_get_uuid(caller_session));
}
return SWITCH_STATUS_SUCCESS;;
}
......
......@@ -666,7 +666,7 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v
switch_memory_pool_t *pool;
if (conference->fnode->type == NODE_TYPE_SPEECH) {
switch_speech_flag_t flags = SWITCH_SPEECH_FLAG_TTS;
switch_speech_flag_t flags = SWITCH_SPEECH_FLAG_NONE;
switch_core_speech_close(&conference->fnode->sh, &flags);
} else {
switch_core_file_close(&conference->fnode->fh);
......@@ -957,7 +957,7 @@ static void conference_loop(conference_member_t *member)
switch_memory_pool_t *pool;
if (member->fnode->type == NODE_TYPE_SPEECH) {
switch_speech_flag_t flags = SWITCH_SPEECH_FLAG_TTS;
switch_speech_flag_t flags = SWITCH_SPEECH_FLAG_NONE;
switch_core_speech_close(&member->fnode->sh, &flags);
} else {
switch_core_file_close(&member->fnode->fh);
......@@ -1340,7 +1340,7 @@ static switch_status_t conference_member_say(conference_obj_t *conference, confe
{
confernce_file_node_t *fnode, *nptr;
switch_memory_pool_t *pool;
switch_speech_flag_t flags = SWITCH_SPEECH_FLAG_TTS;
switch_speech_flag_t flags = SWITCH_SPEECH_FLAG_NONE;
if (!(conference->tts_engine && conference->tts_voice)) {
return SWITCH_STATUS_SUCCESS;
......@@ -1399,7 +1399,7 @@ static switch_status_t conference_say(conference_obj_t *conference, char *text,
{
confernce_file_node_t *fnode, *nptr;
switch_memory_pool_t *pool;
switch_speech_flag_t flags = SWITCH_SPEECH_FLAG_TTS;
switch_speech_flag_t flags = SWITCH_SPEECH_FLAG_NONE;
uint32_t count;
switch_mutex_lock(conference->mutex);
......
......@@ -34,6 +34,33 @@
static const char modname[] = "mod_dptools";
static const switch_application_interface_t detect_speech_application_interface;
static void detect_speech_function(switch_core_session_t *session, char *data)
{
char *argv[4];
int argc;
char *lbuf = NULL;
if ((lbuf = switch_core_session_strdup(session, data)) && (argc = switch_separate_string(lbuf, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) {
if (!strcasecmp(argv[0], "grammar") && argc >= 1) {
switch_ivr_detect_speech_load_grammar(session, argv[1], argv[2]);
} else if (!strcasecmp(argv[0], "nogrammar")) {
switch_ivr_detect_speech_unload_grammar(session, argv[1]);
} else if (!strcasecmp(argv[0], "pause")) {
switch_ivr_pause_detect_speech(session);
} else if (!strcasecmp(argv[0], "resume")) {
switch_ivr_resume_detect_speech(session);
} else if (!strcasecmp(argv[0], "stop")) {
switch_ivr_stop_detect_speech(session);
} else if (argc >= 3) {
switch_ivr_detect_speech(session, argv[0], argv[1], argv[2], argv[3], NULL);
}
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Usage: %s\n", detect_speech_application_interface.syntax);
}
}
static void ringback_function(switch_core_session_t *session, char *data)
{
......@@ -253,7 +280,6 @@ static switch_api_interface_t dptools_api_interface = {
/*.next */ &chat_api_interface
};
static switch_api_interface_t presence_api_interface = {
/*.interface_name */ "presence",
/*.desc */ "presence",
......@@ -262,6 +288,14 @@ static switch_api_interface_t presence_api_interface = {
/*.next */ &dptools_api_interface
};
static const switch_application_interface_t detect_speech_application_interface = {
/*.interface_name */ "detect_speech",
/*.application_function */ detect_speech_function,
/* long_desc */ "Detect speech on a channel.",
/* short_desc */ "Detect speech",
/* syntax */ "<mod_name> <gram_name> <gram_path> [<addr>] OR grammar <gram_name> [<path>] OR pause OR resume",
/*.next */ NULL
};
static const switch_application_interface_t ringback_application_interface = {
/*.interface_name */ "ringback",
......@@ -269,8 +303,7 @@ static const switch_application_interface_t ringback_application_interface = {
/* long_desc */ "Indicate Ringback on a channel.",
/* short_desc */ "Indicate Ringback",
/* syntax */ "",
/*.next */ NULL
/*.next */ &detect_speech_application_interface
};
static const switch_application_interface_t set_application_interface = {
......
......@@ -167,6 +167,123 @@ static void tts_function(switch_core_session_t *session, char *data)
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Done\n");
}
#if 1
static void asrtest_function(switch_core_session_t *session, char *data)
{
switch_ivr_detect_speech(session,
"lumenvox",
"demo",
data,
"127.0.0.1",
NULL);
}
#else
static void asrtest_function(switch_core_session_t *session, char *data)
{
switch_asr_handle_t ah = {0};
switch_asr_flag_t flags = SWITCH_ASR_FLAG_NONE;
switch_channel_t *channel = switch_core_session_get_channel(session);
char *codec_name = "L16";
switch_codec_t codec = {0}, *read_codec;
switch_frame_t write_frame = {0}, *write_frame_p = NULL;
char xdata[1024] = "";
read_codec = switch_core_session_get_read_codec(session);
assert(read_codec != NULL);
if (switch_core_asr_open(&ah, "lumenvox",
read_codec->implementation->iananame,
8000,
"127.0.0.1",
&flags,
switch_core_session_get_pool(session)) == SWITCH_STATUS_SUCCESS) {
if (strcmp(ah.codec, read_codec->implementation->iananame)) {
if (switch_core_codec_init(&codec,
ah.codec,
NULL,
ah.rate,
read_codec->implementation->microseconds_per_frame / 1000,
read_codec->implementation->number_of_channels,
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
NULL, switch_core_session_get_pool(session)) == SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Raw Codec Activated\n");
switch_core_session_set_read_codec(session, &codec);
write_frame.data = xdata;
write_frame.buflen = sizeof(xdata);
write_frame.codec = &codec;
write_frame_p = &write_frame;
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Codec Activation Failed %s@%uhz %u channels %dms\n",
codec_name, read_codec->implementation->samples_per_second, read_codec->implementation->number_of_channels,
read_codec->implementation->microseconds_per_frame / 1000);
switch_core_session_reset(session);
return;
}
}
if (switch_core_asr_load_grammar(&ah, "demo", "/opt/lumenvox/engine_7.0/Lang/BuiltinGrammars/ABNFPhone.gram") != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Error loading Grammar\n");
goto end;
}
while(switch_channel_ready(channel)) {
switch_frame_t *read_frame;
switch_status_t status = switch_core_session_read_frame(session, &read_frame, -1, 0);
char *xmlstr = NULL;
switch_xml_t xml = NULL, result;
if (!SWITCH_READ_ACCEPTABLE(status)) {
break;
}
if (switch_test_flag(read_frame, SFF_CNG)) {
continue;
}
if (switch_core_asr_feed(&ah, read_frame->data, read_frame->datalen, &flags) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Error Feeding Data\n");
break;
}
if (switch_core_asr_check_results(&ah, &flags) == SWITCH_STATUS_SUCCESS) {
if (switch_core_asr_get_results(&ah, &xmlstr, &flags) != SWITCH_STATUS_SUCCESS) {
break;
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "RAW XML\n========\n%s\n", xmlstr);
if ((xml = switch_xml_parse_str(xmlstr, strlen(xmlstr))) && (result = switch_xml_child(xml, "result"))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Results [%s]\n", result->txt);
switch_xml_free(xml);
}
switch_safe_free(xmlstr);
}
if (write_frame_p) {
write_frame.datalen = read_frame->datalen;
switch_core_session_write_frame(session, write_frame_p, -1, 0);
} else {
memset(read_frame->data, 0, read_frame->datalen);
switch_core_session_write_frame(session, read_frame, -1, 0);
}
}
end:
if (write_frame_p) {
switch_core_session_set_read_codec(session, read_codec);
switch_core_codec_destroy(&codec);
}
switch_core_asr_close(&ah, &flags);
switch_core_session_reset(session);
}
}
#endif
static void ivrtest_function(switch_core_session_t *session, char *data)
{
switch_channel_t *channel;
......@@ -272,13 +389,20 @@ static const switch_application_interface_t ivrtest_application_interface = {
/*.next*/ &dirtest_application_interface
};
static const switch_application_interface_t asrtest_application_interface = {
/*.interface_name */ "asrtest",
/*.application_function */ asrtest_function,
NULL, NULL, NULL,
/*.next*/ &ivrtest_application_interface
};
static const switch_loadable_module_interface_t mod_ivrtest_module_interface = {
/*.module_name = */ modname,
/*.endpoint_interface = */ NULL,
/*.timer_interface = */ NULL,
/*.dialplan_interface = */ NULL,
/*.codec_interface = */ NULL,
/*.application_interface */ &ivrtest_application_interface
/*.application_interface */ &asrtest_application_interface
};
SWITCH_MOD_DECLARE(switch_status_t) switch_module_load(const switch_loadable_module_interface_t **module_interface, char *filename)
......
......@@ -169,7 +169,7 @@ static void rss_function(switch_core_session_t *session, char *data)
char *voice = TTS_DEFAULT_VOICE;
char *timer_name = NULL;
switch_speech_handle_t sh;
switch_speech_flag_t flags = SWITCH_SPEECH_FLAG_TTS;
switch_speech_flag_t flags = SWITCH_SPEECH_FLAG_NONE;
switch_core_thread_session_t thread_session;
uint32_t rate, interval = 20;
int stream_id = 0;
......
......@@ -109,70 +109,65 @@ static swift_result_t write_audio(swift_event *event, swift_event_t type, void *
static switch_status_t cepstral_speech_open(switch_speech_handle_t *sh, char *voice_name, int rate, switch_speech_flag_t *flags)
{
if (*flags & SWITCH_SPEECH_FLAG_ASR) {
return SWITCH_STATUS_FALSE;
}
if (*flags & SWITCH_SPEECH_FLAG_TTS) {
cepstral_t *cepstral = switch_core_alloc(sh->memory_pool, sizeof(*cepstral));
char srate[25];
cepstral_t *cepstral = switch_core_alloc(sh->memory_pool, sizeof(*cepstral));
char srate[25];
if (!cepstral) {
return SWITCH_STATUS_MEMERR;
}
if (!cepstral) {
return SWITCH_STATUS_MEMERR;
}
if (switch_buffer_create_dynamic(&cepstral->audio_buffer, MY_BLOCK_SIZE, MY_BUF_LEN, 0) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Write Buffer Failed!\n");
return SWITCH_STATUS_MEMERR;
}
if (switch_buffer_create_dynamic(&cepstral->audio_buffer, MY_BLOCK_SIZE, MY_BUF_LEN, 0) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Write Buffer Failed!\n");
return SWITCH_STATUS_MEMERR;
}
switch_mutex_init(&cepstral->audio_lock, SWITCH_MUTEX_NESTED, sh->memory_pool);
switch_mutex_init(&cepstral->audio_lock, SWITCH_MUTEX_NESTED, sh->memory_pool);
cepstral->params = swift_params_new(NULL);
swift_params_set_string(cepstral->params, "audio/encoding", "pcm16");
snprintf(srate, sizeof(srate), "%d", rate);
swift_params_set_string(cepstral->params, "audio/sampling-rate", srate);
cepstral->params = swift_params_new(NULL);
swift_params_set_string(cepstral->params, "audio/encoding", "pcm16");
snprintf(srate, sizeof(srate), "%d", rate);
swift_params_set_string(cepstral->params, "audio/sampling-rate", srate);
/* Open a Swift Port through which to make TTS calls */
if (SWIFT_FAILED(cepstral->port = swift_port_open(engine, cepstral->params))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to open Swift Port.");
goto all_done;
}
/* Open a Swift Port through which to make TTS calls */
if (SWIFT_FAILED(cepstral->port = swift_port_open(engine, cepstral->params))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to open Swift Port.");
goto all_done;
}
if (voice_name && SWIFT_FAILED(swift_port_set_voice_by_name(cepstral->port, voice_name))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid voice %s!\n", voice_name);
voice_name = NULL;
}
if (!voice_name) {
/* Find the first voice on the system */
if ((cepstral->voice = swift_port_find_first_voice(cepstral->port, NULL, NULL)) == NULL) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to find any voices!\n");
goto all_done;
}
/* Set the voice found by find_first_voice() as the port's current voice */
if ( SWIFT_FAILED(swift_port_set_voice(cepstral->port, cepstral->voice)) ) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to set voice.\n");
goto all_done;
}
if (voice_name && SWIFT_FAILED(swift_port_set_voice_by_name(cepstral->port, voice_name))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid voice %s!\n", voice_name);
voice_name = NULL;
}
voice_name = (char *) swift_voice_get_attribute(cepstral->voice, "name");
if (!voice_name) {
/* Find the first voice on the system */
if ((cepstral->voice = swift_port_find_first_voice(cepstral->port, NULL, NULL)) == NULL) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to find any voices!\n");
goto all_done;
}
if (voice_name) {
switch_copy_string(sh->voice, voice_name, sizeof(sh->voice));
}
/* Set the voice found by find_first_voice() as the port's current voice */
if ( SWIFT_FAILED(swift_port_set_voice(cepstral->port, cepstral->voice)) ) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to set voice.\n");
goto all_done;
}
swift_port_set_callback(cepstral->port, &write_audio, SWIFT_EVENT_AUDIO, cepstral);
voice_name = (char *) swift_voice_get_attribute(cepstral->voice, "name");
}
sh->private_info = cepstral;
return SWITCH_STATUS_SUCCESS;
if (voice_name) {
switch_copy_string(sh->voice, voice_name, sizeof(sh->voice));
}
swift_port_set_callback(cepstral->port, &write_audio, SWIFT_EVENT_AUDIO, cepstral);
sh->private_info = cepstral;
return SWITCH_STATUS_SUCCESS;
all_done:
return SWITCH_STATUS_FALSE;
}
......@@ -227,7 +222,7 @@ static switch_status_t cepstral_speech_feed_tts(switch_speech_handle_t *sh, char
return SWITCH_STATUS_FALSE;
}
swift_port_speak_text(cepstral->port, "<break time=\"400ms\"/>", 0, NULL, &cepstral->tts_stream, NULL);
swift_port_speak_text(cepstral->port, "<break time=\"500ms\"/>", 0, NULL, &cepstral->tts_stream, NULL);
swift_port_speak_text(cepstral->port, text, 0, NULL, &cepstral->tts_stream, NULL);
}
......@@ -252,10 +247,10 @@ static void cepstral_speech_flush_tts(switch_speech_handle_t *sh)
}
static switch_status_t cepstral_speech_read_tts(switch_speech_handle_t *sh,
void *data,
size_t *datalen,
uint32_t *rate,
switch_speech_flag_t *flags)
void *data,
size_t *datalen,
uint32_t *rate,
switch_speech_flag_t *flags)
{
cepstral_t *cepstral;
size_t desired = *datalen;
......@@ -404,8 +399,6 @@ static const switch_speech_interface_t cepstral_speech_interface = {
/*.interface_name*/ "cepstral",
/*.speech_open*/ cepstral_speech_open,
/*.speech_close*/ cepstral_speech_close,
/*.speech_feed_asr*/ NULL,
/*.speech_interpret_asr*/ NULL,
/*.speech_feed_tts*/ cepstral_speech_feed_tts,
/*.speech_read_tts*/ cepstral_speech_read_tts,
/*.speech_flush_tts*/ cepstral_speech_flush_tts,
......
......@@ -77,6 +77,7 @@ static struct {
char *ip;
uint16_t port;
char *password;
int done;
} prefs;
SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_pref_ip, prefs.ip)
......@@ -166,6 +167,8 @@ SWITCH_MOD_DECLARE(switch_status_t) switch_module_shutdown(void)
{
listener_t *l;
prefs.done = 1;
close_socket(&listen_list.sock);
switch_mutex_lock(listen_list.mutex);
......@@ -1003,7 +1006,11 @@ SWITCH_MOD_DECLARE(switch_status_t) switch_module_runtime(void)
}
if ((rv = switch_socket_accept(&inbound_socket, listen_list.sock, listener_pool))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Error\n");
if (prefs.done) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Shutting Down\n");
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Error\n");
}
break;
}
......
......@@ -348,7 +348,11 @@ SWITCH_DECLARE(char *) switch_channel_get_variable(switch_channel_t *channel, ch
assert(channel != NULL);
if (!(v=switch_core_hash_find(channel->variables, varname))) {
v = switch_caller_get_field_by_name(channel->caller_profile, varname);
if (!(v = switch_caller_get_field_by_name(channel->caller_profile, varname))) {
if (!strcmp(varname, "base_dir")) {
return SWITCH_GLOBAL_dirs.base_dir;
}
}
}
return v;
......@@ -986,7 +990,8 @@ SWITCH_DECLARE(switch_channel_state_t) switch_channel_perform_hangup(switch_chan
switch_channel_event_set_data(channel, event);
switch_event_fire(&event);
}
switch_channel_set_variable(channel, "hangup_cause", switch_channel_cause2str(channel->hangup_cause));
switch_channel_presence(channel, "unavailable", switch_channel_cause2str(channel->hangup_cause));
switch_core_session_kill_channel(channel->session, SWITCH_SIG_KILL);
......@@ -1190,7 +1195,7 @@ SWITCH_DECLARE(char *) switch_channel_expand_variables(switch_channel_t *channel
return in;
}
}
nlen = sub_val ? strlen(sub_val) : 0;
nlen = strlen(sub_val);
if (len + nlen >= olen) {
olen += block;
cpos = c - data;
......@@ -1205,11 +1210,10 @@ SWITCH_DECLARE(char *) switch_channel_expand_variables(switch_channel_t *channel
vname = data + vvalpos;
}
if (nlen) {
len += nlen;
strcat(c, sub_val);
c += nlen;
}
len += nlen;
strcat(c, sub_val);
c += nlen;
if (func_val) {
free(func_val);
func_val = NULL;
......
差异被折叠。
......@@ -128,6 +128,7 @@ static char *EVENT_NAMES[] = {
"ROSTER",
"CODEC",
"BACKGROUND_JOB",
"DETECTED_SPEECH",
"ALL"
};
......@@ -539,15 +540,17 @@ SWITCH_DECLARE(void) switch_event_destroy(switch_event_t **event)
switch_event_t *ep = *event;
switch_event_header_t *hp, *this;
for (hp = ep->headers; hp;) {
this = hp;
hp = hp->next;
FREE(this->name);
FREE(this->value);
FREE(this);
if (ep) {
for (hp = ep->headers; hp;) {
this = hp;
hp = hp->next;
FREE(this->name);
FREE(this->value);
FREE(this);
}
FREE(ep->body);
FREE(ep);
}
FREE(ep->body);
FREE(ep);
*event = NULL;
}
......
差异被折叠。
......@@ -51,6 +51,7 @@ struct switch_loadable_module_container {
switch_hash_t *api_hash;
switch_hash_t *file_hash;
switch_hash_t *speech_hash;
switch_hash_t *asr_hash;
switch_hash_t *directory_hash;
switch_hash_t *chat_hash;
switch_memory_pool_t *pool;
......@@ -218,6 +219,20 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable
}
}
if (new_module->module_interface->asr_interface) {
const switch_asr_interface_t *ptr;
for (ptr = new_module->module_interface->asr_interface; ptr; ptr = ptr->next) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Adding Asr interface '%s'\n", ptr->interface_name);
if (switch_event_create(&event, SWITCH_EVENT_MODULE_LOAD) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "type", "asr");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "name", "%s", ptr->interface_name);
switch_event_fire(&event);
}
switch_core_hash_insert(loadable_modules.asr_hash, (char *) ptr->interface_name, (void *) ptr);
}
}
if (new_module->module_interface->directory_interface) {
const switch_directory_interface_t *ptr;
......@@ -490,6 +505,7 @@ SWITCH_DECLARE(switch_status_t) switch_loadable_module_init()
switch_core_hash_init(&loadable_modules.api_hash, loadable_modules.pool);
switch_core_hash_init(&loadable_modules.file_hash, loadable_modules.pool);
switch_core_hash_init(&loadable_modules.speech_hash, loadable_modules.pool);
switch_core_hash_init(&loadable_modules.asr_hash, loadable_modules.pool);
switch_core_hash_init(&loadable_modules.directory_hash, loadable_modules.pool);
switch_core_hash_init(&loadable_modules.chat_hash, loadable_modules.pool);
switch_core_hash_init(&loadable_modules.dialplan_hash, loadable_modules.pool);
......@@ -582,12 +598,18 @@ SWITCH_DECLARE(void) switch_loadable_module_shutdown(void)
for (hi = switch_hash_first(loadable_modules.pool, loadable_modules.module_hash); hi; hi = switch_hash_next(hi)) {
switch_hash_this(hi, NULL, NULL, &val);
module = (switch_loadable_module_t *) val;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Checking %s\t", module->module_interface->module_name);
if (module->switch_module_shutdown) {
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_CONSOLE, "(yes)\n");
module->switch_module_shutdown();
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Stopping: %s\n", module->module_interface->module_name);
if (module->switch_module_shutdown() == SWITCH_STATUS_UNLOAD) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s unloaded.\n", module->module_interface->module_name);
apr_dso_unload(module->lib);
module->lib = NULL;
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s shutdown.\n", module->module_interface->module_name);
}
} else {
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_CONSOLE, "(no)\n");
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s has no shutdown routine\n", module->module_interface->module_name);
}
}
......@@ -648,6 +670,11 @@ SWITCH_DECLARE(switch_speech_interface_t *) switch_loadable_module_get_speech_in
return switch_core_hash_find(loadable_modules.speech_hash, name);
}
SWITCH_DECLARE(switch_asr_interface_t *) switch_loadable_module_get_asr_interface(char *name)
{
return switch_core_hash_find(loadable_modules.asr_hash, name);
}
SWITCH_DECLARE(switch_directory_interface_t *) switch_loadable_module_get_directory_interface(char *name)
{
return switch_core_hash_find(loadable_modules.directory_hash, name);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论