Asterisk - The Open Source Telephony Project  18.5.0
res_speech.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2006, Digium, Inc.
5  *
6  * Joshua Colp <[email protected]>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*! \file
20  *
21  * \brief Generic Speech Recognition API
22  *
23  * \author Joshua Colp <[email protected]>
24  */
25 
26 /*** MODULEINFO
27  <support_level>core</support_level>
28  ***/
29 
30 #include "asterisk.h"
31 
32 #include "asterisk/channel.h"
33 #include "asterisk/module.h"
34 #include "asterisk/lock.h"
35 #include "asterisk/linkedlists.h"
36 #include "asterisk/cli.h"
37 #include "asterisk/term.h"
38 #include "asterisk/speech.h"
39 #include "asterisk/format_cache.h"
40 
43 
44 /*! \brief Find a speech recognition engine of specified name, if NULL then use the default one */
45 static struct ast_speech_engine *find_engine(const char *engine_name)
46 {
47  struct ast_speech_engine *engine = NULL;
48 
49  /* If no name is specified -- use the default engine */
50  if (ast_strlen_zero(engine_name))
51  return default_engine;
52 
54  AST_RWLIST_TRAVERSE(&engines, engine, list) {
55  if (!strcasecmp(engine->name, engine_name)) {
56  break;
57  }
58  }
60 
61  return engine;
62 }
63 
64 /*! \brief Activate a loaded (either local or global) grammar */
65 int ast_speech_grammar_activate(struct ast_speech *speech, const char *grammar_name)
66 {
67  return (speech->engine->activate ? speech->engine->activate(speech, grammar_name) : -1);
68 }
69 
70 /*! \brief Deactivate a loaded grammar on a speech structure */
71 int ast_speech_grammar_deactivate(struct ast_speech *speech, const char *grammar_name)
72 {
73  return (speech->engine->deactivate ? speech->engine->deactivate(speech, grammar_name) : -1);
74 }
75 
76 /*! \brief Load a local grammar on a speech structure */
77 int ast_speech_grammar_load(struct ast_speech *speech, const char *grammar_name, const char *grammar)
78 {
79  return (speech->engine->load ? speech->engine->load(speech, grammar_name, grammar) : -1);
80 }
81 
82 /*! \brief Unload a local grammar from a speech structure */
83 int ast_speech_grammar_unload(struct ast_speech *speech, const char *grammar_name)
84 {
85  return (speech->engine->unload ? speech->engine->unload(speech, grammar_name) : -1);
86 }
87 
88 /*! \brief Return the results of a recognition from the speech structure */
90 {
91  return (speech->engine->get ? speech->engine->get(speech) : NULL);
92 }
93 
94 /*! \brief Free a list of results */
96 {
97  struct ast_speech_result *current_result = result, *prev_result = NULL;
98  int res = 0;
99 
100  while (current_result != NULL) {
101  prev_result = current_result;
102  /* Deallocate what we can */
103  if (current_result->text != NULL) {
104  ast_free(current_result->text);
105  current_result->text = NULL;
106  }
107  if (current_result->grammar != NULL) {
108  ast_free(current_result->grammar);
109  current_result->grammar = NULL;
110  }
111  /* Move on and then free ourselves */
112  current_result = AST_LIST_NEXT(current_result, list);
113  ast_free(prev_result);
114  prev_result = NULL;
115  }
116 
117  return res;
118 }
119 
120 /*! \brief Start speech recognition on a speech structure */
121 void ast_speech_start(struct ast_speech *speech)
122 {
123 
124  /* Clear any flags that may affect things */
128 
129  /* If results are on the structure, free them since we are starting again */
130  if (speech->results) {
132  speech->results = NULL;
133  }
134 
135  /* If the engine needs to start stuff up, do it */
136  if (speech->engine->start)
137  speech->engine->start(speech);
138 
139  return;
140 }
141 
142 /*! \brief Write in signed linear audio to be recognized */
143 int ast_speech_write(struct ast_speech *speech, void *data, int len)
144 {
145  /* Make sure the speech engine is ready to accept audio */
146  if (speech->state != AST_SPEECH_STATE_READY)
147  return -1;
148 
149  return speech->engine->write(speech, data, len);
150 }
151 
152 /*! \brief Signal to the engine that DTMF was received */
153 int ast_speech_dtmf(struct ast_speech *speech, const char *dtmf)
154 {
155  int res = 0;
156 
157  if (speech->state != AST_SPEECH_STATE_READY)
158  return -1;
159 
160  if (speech->engine->dtmf != NULL) {
161  res = speech->engine->dtmf(speech, dtmf);
162  }
163 
164  return res;
165 }
166 
167 /*! \brief Change an engine specific attribute */
168 int ast_speech_change(struct ast_speech *speech, const char *name, const char *value)
169 {
170  return (speech->engine->change ? speech->engine->change(speech, name, value) : -1);
171 }
172 
173 /*! \brief Get an engine specific attribute */
174 int ast_speech_get_setting(struct ast_speech *speech, const char *name, char *buf, size_t len)
175 {
176  return (speech->engine->get_setting ? speech->engine->get_setting(speech, name, buf, len) : -1);
177 }
178 
179 /*! \brief Create a new speech structure using the engine specified */
180 struct ast_speech *ast_speech_new(const char *engine_name, const struct ast_format_cap *cap)
181 {
182  struct ast_speech_engine *engine = NULL;
183  struct ast_speech *new_speech = NULL;
184  struct ast_format_cap *joint;
185  RAII_VAR(struct ast_format *, best, NULL, ao2_cleanup);
186 
187  /* Try to find the speech recognition engine that was requested */
188  if (!(engine = find_engine(engine_name)))
189  return NULL;
190 
192  if (!joint) {
193  return NULL;
194  }
195 
196  ast_format_cap_get_compatible(engine->formats, cap, joint);
197  best = ast_format_cap_get_format(joint, 0);
198  ao2_ref(joint, -1);
199 
200  if (!best) {
202  best = ao2_bump(ast_format_slin);
203  } else {
204  return NULL;
205  }
206  }
207 
208  /* Allocate our own speech structure, and try to allocate a structure from the engine too */
209  if (!(new_speech = ast_calloc(1, sizeof(*new_speech)))) {
210  return NULL;
211  }
212 
213  /* Initialize the lock */
214  ast_mutex_init(&new_speech->lock);
215 
216  /* Make sure no results are present */
217  new_speech->results = NULL;
218 
219  /* Copy over our engine pointer */
220  new_speech->engine = engine;
221 
222  /* Can't forget the format audio is going to be in */
223  new_speech->format = ao2_bump(best);
224 
225  /* We are not ready to accept audio yet */
227 
228  /* Pass ourselves to the engine so they can set us up some more and if they error out then do not create a structure */
229  if (engine->create(new_speech, new_speech->format)) {
230  ast_mutex_destroy(&new_speech->lock);
231  ao2_ref(new_speech->format, -1);
232  ast_free(new_speech);
233  return NULL;
234  }
235 
236  return new_speech;
237 }
238 
239 /*! \brief Destroy a speech structure */
240 int ast_speech_destroy(struct ast_speech *speech)
241 {
242  int res = 0;
243 
244  /* Call our engine so we are destroyed properly */
245  speech->engine->destroy(speech);
246 
247  /* Deinitialize the lock */
248  ast_mutex_destroy(&speech->lock);
249 
250  /* If results exist on the speech structure, destroy them */
251  if (speech->results)
253 
254  /* If a processing sound is set - free the memory used by it */
255  if (speech->processing_sound)
256  ast_free(speech->processing_sound);
257 
258  ao2_ref(speech->format, -1);
259 
260  /* Aloha we are done */
261  ast_free(speech);
262 
263  return res;
264 }
265 
266 /*! \brief Change state of a speech structure */
267 int ast_speech_change_state(struct ast_speech *speech, int state)
268 {
269  int res = 0;
270 
271  switch (state) {
273  /* The engine heard audio, so they spoke */
275  default:
276  speech->state = state;
277  break;
278  }
279 
280  return res;
281 }
282 
283 /*! \brief Change the type of results we want */
285 {
286  speech->results_type = results_type;
287 
288  return (speech->engine->change_results_type ? speech->engine->change_results_type(speech, results_type) : 0);
289 }
290 
291 /*! \brief Register a speech recognition engine */
293 {
294  int res = 0;
295 
296  /* Confirm the engine meets the minimum API requirements */
297  if (!engine->create || !engine->write || !engine->destroy) {
298  ast_log(LOG_WARNING, "Speech recognition engine '%s' did not meet minimum API requirements.\n", engine->name);
299  return -1;
300  }
301 
302  /* If an engine is already loaded with this name, error out */
303  if (find_engine(engine->name)) {
304  ast_log(LOG_WARNING, "Speech recognition engine '%s' already exists.\n", engine->name);
305  return -1;
306  }
307 
308  ast_verb(2, "Registered speech recognition engine '%s'\n", engine->name);
309 
310  /* Add to the engine linked list and make default if needed */
312  AST_RWLIST_INSERT_HEAD(&engines, engine, list);
313  if (!default_engine) {
314  default_engine = engine;
315  ast_verb(2, "Made '%s' the default speech recognition engine\n", engine->name);
316  }
318 
319  return res;
320 }
321 
322 /*! \brief Unregister a speech recognition engine */
323 int ast_speech_unregister(const char *engine_name)
324 {
325  struct ast_speech_engine *engine = NULL;
326  int res = -1;
327 
328  if (ast_strlen_zero(engine_name))
329  return -1;
330 
332  AST_RWLIST_TRAVERSE_SAFE_BEGIN(&engines, engine, list) {
333  if (!strcasecmp(engine->name, engine_name)) {
334  /* We have our engine... removed it */
336  /* If this was the default engine, we need to pick a new one */
337  if (engine == default_engine) {
338  default_engine = AST_RWLIST_FIRST(&engines);
339  }
340  ast_verb(2, "Unregistered speech recognition engine '%s'\n", engine_name);
341  /* All went well */
342  res = 0;
343  break;
344  }
345  }
348 
349  return res;
350 }
351 
352 static int unload_module(void)
353 {
354  /* We can not be unloaded */
355  return -1;
356 }
357 
358 static int load_module(void)
359 {
361 }
362 
364  .support_level = AST_MODULE_SUPPORT_CORE,
365  .load = load_module,
367  .load_pri = AST_MODPRI_APP_DEPEND - 1,
368 );
int ast_speech_change_state(struct ast_speech *speech, int state)
Change state of a speech structure.
Definition: res_speech.c:267
enum sip_cc_notify_state state
Definition: chan_sip.c:959
int state
Definition: speech.h:59
struct ast_speech_result * ast_speech_results_get(struct ast_speech *speech)
Return the results of a recognition from the speech structure.
Definition: res_speech.c:89
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
int ast_speech_get_setting(struct ast_speech *speech, const char *name, char *buf, size_t len)
Get an engine specific attribute.
Definition: res_speech.c:174
int ast_speech_write(struct ast_speech *speech, void *data, int len)
Write in signed linear audio to be recognized.
Definition: res_speech.c:143
int(* destroy)(struct ast_speech *speech)
Definition: speech.h:79
Generic Speech Recognition API.
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized...
Definition: linkedlists.h:332
int(* create)(struct ast_speech *speech, struct ast_format *format)
Definition: speech.h:77
int(* change)(struct ast_speech *speech, const char *name, const char *value)
Definition: speech.h:95
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define LOG_WARNING
Definition: logger.h:274
int ast_speech_grammar_activate(struct ast_speech *speech, const char *grammar_name)
Activate a loaded (either local or global) grammar.
Definition: res_speech.c:65
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
int ast_speech_change_results_type(struct ast_speech *speech, enum ast_speech_results_type results_type)
Change the type of results we want.
Definition: res_speech.c:284
int ast_speech_register(struct ast_speech_engine *engine)
Register a speech recognition engine.
Definition: res_speech.c:292
enum ast_speech_results_type results_type
Definition: speech.h:67
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:438
static int unload_module(void)
Definition: res_speech.c:352
Definition of a media format.
Definition: format.c:43
void ast_speech_start(struct ast_speech *speech)
Start speech recognition on a speech structure.
Definition: res_speech.c:121
static struct ast_speech_engine * default_engine
Definition: res_speech.c:42
int ast_speech_unregister(const char *engine_name)
Unregister a speech recognition engine.
Definition: res_speech.c:323
char * name
Definition: speech.h:75
#define NULL
Definition: resample.c:96
int value
Definition: syslog.c:37
#define ast_verb(level,...)
Definition: logger.h:463
int(* start)(struct ast_speech *speech)
Definition: speech.h:93
char * grammar
Definition: speech.h:116
int ast_speech_grammar_unload(struct ast_speech *speech, const char *grammar_name)
Unload a local grammar from a speech structure.
Definition: res_speech.c:83
#define ast_strlen_zero(foo)
Definition: strings.h:52
ast_speech_results_type
Definition: speech.h:45
enum ast_format_cmp_res ast_format_cap_iscompatible_format(const struct ast_format_cap *cap, const struct ast_format *format)
Find if ast_format is within the capabilities of the ast_format_cap object.
Definition: format_cap.c:583
#define ao2_bump(obj)
Definition: astobj2.h:491
int(* unload)(struct ast_speech *speech, const char *grammar_name)
Definition: speech.h:83
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
#define AST_RWLIST_INSERT_HEAD
Definition: linkedlists.h:717
#define ast_log
Definition: astobj2.c:42
General Asterisk PBX channel definitions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
int ast_speech_grammar_load(struct ast_speech *speech, const char *grammar_name, const char *grammar)
Load a local grammar on a speech structure.
Definition: res_speech.c:77
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
int ast_speech_change(struct ast_speech *speech, const char *name, const char *value)
Change an engine specific attribute.
Definition: res_speech.c:168
#define ao2_ref(o, delta)
Definition: astobj2.h:464
struct ast_format_cap * formats
Definition: speech.h:103
#define AST_RWLIST_REMOVE_CURRENT
Definition: linkedlists.h:569
A set of macros to manage forward-linked lists.
int(* change_results_type)(struct ast_speech *speech, enum ast_speech_results_type results_type)
Definition: speech.h:99
struct ast_speech_engine * engine
Definition: speech.h:69
static int load_module(void)
Definition: res_speech.c:358
struct ast_speech_result * results
Definition: speech.h:65
#define ast_format_cap_alloc(flags)
Definition: format_cap.h:52
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
Definition: linkedlists.h:544
struct ast_speech_result *(* get)(struct ast_speech *speech)
Definition: speech.h:101
int(* activate)(struct ast_speech *speech, const char *grammar_name)
Definition: speech.h:85
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
int(* write)(struct ast_speech *speech, void *data, int len)
Definition: speech.h:89
int ast_speech_results_free(struct ast_speech_result *result)
Free a list of results.
Definition: res_speech.c:95
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
static const char name[]
Definition: cdr_mysql.c:74
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
struct ast_format * format
Definition: speech.h:61
static struct ast_speech_engine * find_engine(const char *engine_name)
Find a speech recognition engine of specified name, if NULL then use the default one.
Definition: res_speech.c:45
#define ast_clear_flag(p, flag)
Definition: utils.h:77
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
ast_mutex_t lock
Definition: speech.h:53
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
Standard Command Line Interface.
int(* deactivate)(struct ast_speech *speech, const char *grammar_name)
Definition: speech.h:87
int ast_speech_dtmf(struct ast_speech *speech, const char *dtmf)
Signal to the engine that DTMF was received.
Definition: res_speech.c:153
static PGresult * result
Definition: cel_pgsql.c:88
int(* load)(struct ast_speech *speech, const char *grammar_name, const char *grammar)
Definition: speech.h:81
int(* dtmf)(struct ast_speech *speech, const char *dtmf)
Definition: speech.h:91
char * processing_sound
Definition: speech.h:57
struct ast_speech * ast_speech_new(const char *engine_name, const struct ast_format_cap *cap)
Create a new speech structure using the engine specified.
Definition: res_speech.c:180
Handy terminal functions for vt* terms.
#define ast_mutex_init(pmutex)
Definition: lock.h:184
struct ast_format * ast_format_cap_get_format(const struct ast_format_cap *cap, int position)
Get the format at a specific index.
Definition: format_cap.c:400
#define AST_RWLIST_FIRST
Definition: linkedlists.h:422
#define ast_mutex_destroy(a)
Definition: lock.h:186
int ast_speech_destroy(struct ast_speech *speech)
Destroy a speech structure.
Definition: res_speech.c:240
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
Asterisk module definitions.
int ast_format_cap_get_compatible(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result)
Find the compatible formats between two capabilities structures.
Definition: format_cap.c:630
#define AST_RWLIST_TRAVERSE_SAFE_END
Definition: linkedlists.h:616
int ast_speech_grammar_deactivate(struct ast_speech *speech, const char *grammar_name)
Deactivate a loaded grammar on a speech structure.
Definition: res_speech.c:71
int(* get_setting)(struct ast_speech *speech, const char *name, char *buf, size_t len)
Definition: speech.h:97
Media Format Cache API.