Wed Jan 8 2020 09:49:50

Asterisk developer's documentation


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 <jcolp@digium.com>
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 <jcolp@digium.com>
24  */
25 
26 /*** MODULEINFO
27  <support_level>core</support_level>
28  ***/
29 
30 #include "asterisk.h"
31 
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 368738 $");
33 
34 #include "asterisk/channel.h"
35 #include "asterisk/module.h"
36 #include "asterisk/lock.h"
37 #include "asterisk/linkedlists.h"
38 #include "asterisk/cli.h"
39 #include "asterisk/term.h"
40 #include "asterisk/speech.h"
41 
42 
44 static struct ast_speech_engine *default_engine = NULL;
45 
46 /*! \brief Find a speech recognition engine of specified name, if NULL then use the default one */
47 static struct ast_speech_engine *find_engine(const char *engine_name)
48 {
49  struct ast_speech_engine *engine = NULL;
50 
51  /* If no name is specified -- use the default engine */
52  if (ast_strlen_zero(engine_name))
53  return default_engine;
54 
56  AST_RWLIST_TRAVERSE(&engines, engine, list) {
57  if (!strcasecmp(engine->name, engine_name)) {
58  break;
59  }
60  }
62 
63  return engine;
64 }
65 
66 /*! \brief Activate a loaded (either local or global) grammar */
67 int ast_speech_grammar_activate(struct ast_speech *speech, const char *grammar_name)
68 {
69  return (speech->engine->activate ? speech->engine->activate(speech, grammar_name) : -1);
70 }
71 
72 /*! \brief Deactivate a loaded grammar on a speech structure */
73 int ast_speech_grammar_deactivate(struct ast_speech *speech, const char *grammar_name)
74 {
75  return (speech->engine->deactivate ? speech->engine->deactivate(speech, grammar_name) : -1);
76 }
77 
78 /*! \brief Load a local grammar on a speech structure */
79 int ast_speech_grammar_load(struct ast_speech *speech, const char *grammar_name, const char *grammar)
80 {
81  return (speech->engine->load ? speech->engine->load(speech, grammar_name, grammar) : -1);
82 }
83 
84 /*! \brief Unload a local grammar from a speech structure */
85 int ast_speech_grammar_unload(struct ast_speech *speech, const char *grammar_name)
86 {
87  return (speech->engine->unload ? speech->engine->unload(speech, grammar_name) : -1);
88 }
89 
90 /*! \brief Return the results of a recognition from the speech structure */
92 {
93  return (speech->engine->get ? speech->engine->get(speech) : NULL);
94 }
95 
96 /*! \brief Free a list of results */
98 {
99  struct ast_speech_result *current_result = result, *prev_result = NULL;
100  int res = 0;
101 
102  while (current_result != NULL) {
103  prev_result = current_result;
104  /* Deallocate what we can */
105  if (current_result->text != NULL) {
106  ast_free(current_result->text);
107  current_result->text = NULL;
108  }
109  if (current_result->grammar != NULL) {
110  ast_free(current_result->grammar);
111  current_result->grammar = NULL;
112  }
113  /* Move on and then free ourselves */
114  current_result = AST_LIST_NEXT(current_result, list);
115  ast_free(prev_result);
116  prev_result = NULL;
117  }
118 
119  return res;
120 }
121 
122 /*! \brief Start speech recognition on a speech structure */
123 void ast_speech_start(struct ast_speech *speech)
124 {
125 
126  /* Clear any flags that may affect things */
130 
131  /* If results are on the structure, free them since we are starting again */
132  if (speech->results) {
134  speech->results = NULL;
135  }
136 
137  /* If the engine needs to start stuff up, do it */
138  if (speech->engine->start)
139  speech->engine->start(speech);
140 
141  return;
142 }
143 
144 /*! \brief Write in signed linear audio to be recognized */
145 int ast_speech_write(struct ast_speech *speech, void *data, int len)
146 {
147  /* Make sure the speech engine is ready to accept audio */
148  if (speech->state != AST_SPEECH_STATE_READY)
149  return -1;
150 
151  return speech->engine->write(speech, data, len);
152 }
153 
154 /*! \brief Signal to the engine that DTMF was received */
155 int ast_speech_dtmf(struct ast_speech *speech, const char *dtmf)
156 {
157  int res = 0;
158 
159  if (speech->state != AST_SPEECH_STATE_READY)
160  return -1;
161 
162  if (speech->engine->dtmf != NULL) {
163  res = speech->engine->dtmf(speech, dtmf);
164  }
165 
166  return res;
167 }
168 
169 /*! \brief Change an engine specific attribute */
170 int ast_speech_change(struct ast_speech *speech, const char *name, const char *value)
171 {
172  return (speech->engine->change ? speech->engine->change(speech, name, value) : -1);
173 }
174 
175 /*! \brief Create a new speech structure using the engine specified */
176 struct ast_speech *ast_speech_new(const char *engine_name, int formats)
177 {
178  struct ast_speech_engine *engine = NULL;
179  struct ast_speech *new_speech = NULL;
181 
182  /* Try to find the speech recognition engine that was requested */
183  if (!(engine = find_engine(engine_name)))
184  return NULL;
185 
186  /* Before even allocating the memory below do some codec negotiation, we choose the best codec possible and fall back to signed linear if possible */
187  if ((format = (engine->formats & formats)))
188  format = ast_best_codec(format);
189  else if ((engine->formats & AST_FORMAT_SLINEAR))
190  format = AST_FORMAT_SLINEAR;
191  else
192  return NULL;
193 
194  /* Allocate our own speech structure, and try to allocate a structure from the engine too */
195  if (!(new_speech = ast_calloc(1, sizeof(*new_speech))))
196  return NULL;
197 
198  /* Initialize the lock */
199  ast_mutex_init(&new_speech->lock);
200 
201  /* Make sure no results are present */
202  new_speech->results = NULL;
203 
204  /* Copy over our engine pointer */
205  new_speech->engine = engine;
206 
207  /* Can't forget the format audio is going to be in */
208  new_speech->format = format;
209 
210  /* We are not ready to accept audio yet */
212 
213  /* Pass ourselves to the engine so they can set us up some more and if they error out then do not create a structure */
214  if (engine->create(new_speech, format)) {
215  ast_mutex_destroy(&new_speech->lock);
216  ast_free(new_speech);
217  new_speech = NULL;
218  }
219 
220  return new_speech;
221 }
222 
223 /*! \brief Destroy a speech structure */
224 int ast_speech_destroy(struct ast_speech *speech)
225 {
226  int res = 0;
227 
228  /* Call our engine so we are destroyed properly */
229  speech->engine->destroy(speech);
230 
231  /* Deinitialize the lock */
232  ast_mutex_destroy(&speech->lock);
233 
234  /* If results exist on the speech structure, destroy them */
235  if (speech->results)
237 
238  /* If a processing sound is set - free the memory used by it */
239  if (speech->processing_sound)
240  ast_free(speech->processing_sound);
241 
242  /* Aloha we are done */
243  ast_free(speech);
244 
245  return res;
246 }
247 
248 /*! \brief Change state of a speech structure */
249 int ast_speech_change_state(struct ast_speech *speech, int state)
250 {
251  int res = 0;
252 
253  if (state == AST_SPEECH_STATE_WAIT) {
254  /* The engine heard audio, so they spoke */
256  }
257 
258  speech->state = state;
259 
260  return res;
261 }
262 
263 /*! \brief Change the type of results we want */
265 {
266  speech->results_type = results_type;
267 
268  return (speech->engine->change_results_type ? speech->engine->change_results_type(speech, results_type) : 0);
269 }
270 
271 /*! \brief Register a speech recognition engine */
273 {
274  int res = 0;
275 
276  /* Confirm the engine meets the minimum API requirements */
277  if (!engine->create || !engine->write || !engine->destroy) {
278  ast_log(LOG_WARNING, "Speech recognition engine '%s' did not meet minimum API requirements.\n", engine->name);
279  return -1;
280  }
281 
282  /* If an engine is already loaded with this name, error out */
283  if (find_engine(engine->name)) {
284  ast_log(LOG_WARNING, "Speech recognition engine '%s' already exists.\n", engine->name);
285  return -1;
286  }
287 
288  ast_verb(2, "Registered speech recognition engine '%s'\n", engine->name);
289 
290  /* Add to the engine linked list and make default if needed */
292  AST_RWLIST_INSERT_HEAD(&engines, engine, list);
293  if (!default_engine) {
294  default_engine = engine;
295  ast_verb(2, "Made '%s' the default speech recognition engine\n", engine->name);
296  }
298 
299  return res;
300 }
301 
302 /*! \brief Unregister a speech recognition engine */
303 int ast_speech_unregister(const char *engine_name)
304 {
305  struct ast_speech_engine *engine = NULL;
306  int res = -1;
307 
308  if (ast_strlen_zero(engine_name))
309  return -1;
310 
312  AST_RWLIST_TRAVERSE_SAFE_BEGIN(&engines, engine, list) {
313  if (!strcasecmp(engine->name, engine_name)) {
314  /* We have our engine... removed it */
316  /* If this was the default engine, we need to pick a new one */
317  if (engine == default_engine) {
318  default_engine = AST_RWLIST_FIRST(&engines);
319  }
320  ast_verb(2, "Unregistered speech recognition engine '%s'\n", engine_name);
321  /* All went well */
322  res = 0;
323  break;
324  }
325  }
328 
329  return res;
330 }
331 
332 static int unload_module(void)
333 {
334  /* We can not be unloaded */
335  return -1;
336 }
337 
338 static int load_module(void)
339 {
341 }
342 
344  .load = load_module,
346  .load_pri = AST_MODPRI_APP_DEPEND,
347  );
enum sip_cc_notify_state state
Definition: chan_sip.c:842
int state
Definition: speech.h:59
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
int(* change_results_type)(struct ast_speech *speech, enum ast_speech_results_type results_type)
Definition: speech.h:97
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 ast_speech_destroy(struct ast_speech *speech)
Destroy a speech structure.
Definition: res_speech.c:224
void ast_speech_start(struct ast_speech *speech)
Indicate to the speech engine that audio is now going to start being written.
Definition: res_speech.c:123
int(* activate)(struct ast_speech *speech, const char *grammar_name)
Definition: speech.h:85
#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:144
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
enum ast_speech_results_type results_type
Definition: speech.h:67
int(* change)(struct ast_speech *speech, const char *name, const char *value)
Definition: speech.h:95
#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:332
int ast_speech_register(struct ast_speech_engine *engine)
Register a speech recognition engine.
Definition: res_speech.c:272
struct ast_speech_result * ast_speech_results_get(struct ast_speech *speech)
Get speech recognition results.
Definition: res_speech.c:91
static struct ast_speech_engine * default_engine
Definition: res_speech.c:44
format_t ast_best_codec(format_t fmts)
Pick the best audio codec.
Definition: channel.c:1062
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:374
char * name
Definition: speech.h:75
int value
Definition: syslog.c:39
#define ast_verb(level,...)
Definition: logger.h:243
int(* start)(struct ast_speech *speech)
Definition: speech.h:93
char * grammar
Definition: speech.h:114
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:264
ast_speech_results_type
Definition: speech.h:45
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
#define AST_RWLIST_INSERT_HEAD
Definition: linkedlists.h:703
int ast_speech_grammar_deactivate(struct ast_speech *speech, const char *grammar_name)
Deactivate a grammar on a speech structure.
Definition: res_speech.c:73
General Asterisk PBX channel definitions.
int(* dtmf)(struct ast_speech *speech, const char *dtmf)
Definition: speech.h:91
int ast_speech_change_state(struct ast_speech *speech, int state)
Change state of a speech structure.
Definition: res_speech.c:249
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
#define AST_RWLIST_REMOVE_CURRENT
Definition: linkedlists.h:565
int(* create)(struct ast_speech *speech, int format)
Definition: speech.h:77
A set of macros to manage forward-linked lists.
struct ast_speech_engine * engine
Definition: speech.h:69
int(* unload)(struct ast_speech *speech, const char *grammar_name)
Definition: speech.h:83
int ast_speech_grammar_unload(struct ast_speech *speech, const char *grammar_name)
Unload a grammar.
Definition: res_speech.c:85
static int load_module(void)
Definition: res_speech.c:338
struct ast_speech_result * results
Definition: speech.h:65
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
Definition: linkedlists.h:542
int(* write)(struct ast_speech *speech, void *data, int len)
Definition: speech.h:89
int ast_speech_grammar_activate(struct ast_speech *speech, const char *grammar_name)
Activate a grammar on a speech structure.
Definition: res_speech.c:67
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
Definition: file.c:65
int(* load)(struct ast_speech *speech, const char *grammar_name, const char *grammar)
Definition: speech.h:81
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static const char name[]
#define ast_free(a)
Definition: astmm.h:97
int 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:47
#define ast_clear_flag(p, flag)
Definition: utils.h:77
int ast_speech_results_free(struct ast_speech_result *result)
Free a set of results.
Definition: res_speech.c:97
ast_mutex_t lock
Definition: speech.h:53
#define AST_FORMAT_SLINEAR
Definition: frame.h:254
int ast_speech_dtmf(struct ast_speech *speech, const char *dtmf)
Signal to the engine that DTMF was received.
Definition: res_speech.c:155
Standard Command Line Interface.
#define ast_calloc(a, b)
Definition: astmm.h:82
int ast_speech_unregister(const char *engine_name)
Unregister a speech recognition engine.
Definition: res_speech.c:303
char * processing_sound
Definition: speech.h:57
Handy terminal functions for vt* terms.
#define ast_mutex_init(pmutex)
Definition: lock.h:152
#define AST_RWLIST_FIRST
Definition: linkedlists.h:422
#define ast_mutex_destroy(a)
Definition: lock.h:154
int ast_speech_write(struct ast_speech *speech, void *data, int len)
Write audio to the speech engine.
Definition: res_speech.c:145
int ast_speech_grammar_load(struct ast_speech *speech, const char *grammar_name, const char *grammar)
Load a grammar on a speech structure (not globally)
Definition: res_speech.c:79
int(* deactivate)(struct ast_speech *speech, const char *grammar_name)
Definition: speech.h:87
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:38
Asterisk module definitions.
static snd_pcm_format_t format
Definition: chan_alsa.c:93
int ast_speech_change(struct ast_speech *speech, const char *name, const char *value)
Change an engine specific attribute.
Definition: res_speech.c:170
#define AST_RWLIST_TRAVERSE_SAFE_END
Definition: linkedlists.h:602
int(* destroy)(struct ast_speech *speech)
Definition: speech.h:79
struct ast_speech_result *(* get)(struct ast_speech *speech)
Definition: speech.h:99
struct ast_speech * ast_speech_new(const char *engine_name, int formats)
Create a new speech structure.
Definition: res_speech.c:176
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180