Asterisk - The Open Source Telephony Project  21.4.1
res_speech_aeap.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2021, Sangoma Technologies Corporation
5  *
6  * Kevin Harwell <kharwell@sangoma.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 Asterisk External Application Speech Engine
22  *
23  */
24 
25 /*** MODULEINFO
26  <support_level>core</support_level>
27  ***/
28 
29 #include "asterisk.h"
30 
31 #include "asterisk/astobj2.h"
32 #include "asterisk/config.h"
33 #include "asterisk/format.h"
34 #include "asterisk/format_cap.h"
35 #include "asterisk/json.h"
36 #include "asterisk/module.h"
37 #include "asterisk/speech.h"
38 #include "asterisk/sorcery.h"
39 
40 #include "asterisk/res_aeap.h"
42 
43 #define SPEECH_AEAP_VERSION "0.1.0"
44 #define SPEECH_PROTOCOL "speech_to_text"
45 
46 #define CONNECTION_TIMEOUT 2000
47 
48 #define log_error(obj, fmt, ...) \
49  ast_log(LOG_ERROR, "AEAP speech (%p): " fmt "\n", obj, ##__VA_ARGS__)
50 
51 static struct ast_json *custom_fields_to_params(const struct ast_variable *variables)
52 {
53  const struct ast_variable *i;
54  struct ast_json *obj;
55 
56  if (!variables) {
57  return NULL;
58  }
59 
60  obj = ast_json_object_create();
61  if (!obj) {
62  return NULL;
63  }
64 
65  for (i = variables; i; i = i->next) {
66  if (i->name[0] == '@' && i->name[1]) {
68  }
69  }
70 
71  return obj;
72 }
73 
74 /*!
75  * \internal
76  * \brief Create, and send a request to the external application
77  *
78  * Create, then sends a request to an Asterisk external application, and then blocks
79  * until a response is received or a time out occurs. Since this method waits until
80  * receiving a response the returned result is guaranteed to be pass/fail based upon
81  * a response handler's result.
82  *
83  * \param aeap Pointer to an Asterisk external application object
84  * \param name The name of the request to send
85  * \param json The core json request data
86  * \param data Optional user data to associate with request/response
87  *
88  * \returns 0 on success, -1 on error
89  */
90 static int speech_aeap_send_request(struct ast_aeap *aeap, const char *name,
91  struct ast_json *json, void *data)
92 {
93  /*
94  * Wait for a response. Also since we're blocking,
95  * data is expected to be on the stack so no cleanup required.
96  */
97  struct ast_aeap_tsx_params tsx_params = {
98  .timeout = 1000,
99  .wait = 1,
100  .obj = data,
101  };
102 
103  /* "steals" the json ref */
105  ast_aeap_message_type_json, name, NULL, json);
106  if (!tsx_params.msg) {
107  return -1;
108  }
109 
110  /* Send "steals" the json msg ref */
111  return ast_aeap_send_msg_tsx(aeap, &tsx_params);
112 }
113 
114 /*!
115  * \internal
116  * \brief Create, and send a "get" request to an external application
117  *
118  * Basic structure of the JSON message to send:
119  *
120  \verbatim
121  { param: [<param>, ...] }
122  \endverbatim
123  *
124  * \param speech The speech engine
125  * \param param The name of the parameter to retrieve
126  * \param data User data passed to the response handler
127  *
128  * \returns 0 on success, -1 on error
129  */
130 static int speech_aeap_get(struct ast_speech *speech, const char *param, void *data)
131 {
132  if (!param) {
133  return -1;
134  }
135 
136  /* send_request handles json ref */
137  return speech_aeap_send_request(speech->data,
138  "get", ast_json_pack("{s:[s]}", "params", param), data);
139 }
140 
141 struct speech_param {
142  const char *name;
143  const char *value;
144 };
145 
146 /*!
147  * \internal
148  * \brief Create, and send a "set" request to an external application
149  *
150  * Basic structure of the JSON message to send:
151  *
152  \verbatim
153  { params: { <name> : <value> } }
154  \endverbatim
155  *
156  * \param speech The speech engine
157  * \param name The name of the parameter to set
158  * \param value The value of the parameter to set
159  *
160  * \returns 0 on success, -1 on error
161  */
162 static int speech_aeap_set(struct ast_speech *speech, const char *name, const char *value)
163 {
164  if (!name) {
165  return -1;
166  }
167 
168  /* send_request handles json ref */
169  return speech_aeap_send_request(speech->data,
170  "set", ast_json_pack("{s:{s:s}}", "params", name, value), NULL);
171 }
172 
173 static int handle_response_set(struct ast_aeap *aeap, struct ast_aeap_message *message, void *data)
174 {
175  return 0;
176 }
177 
179  const char *param;
180  size_t len;
181  char *buf;
182 };
183 
184 static int handle_setting(struct ast_aeap *aeap, struct ast_json_iter *iter,
185  struct speech_setting *setting)
186 {
187  const char *value;
188 
189  if (strcmp(ast_json_object_iter_key(iter), setting->param)) {
190  log_error(aeap, "Unable to 'get' speech setting for '%s'", setting->param);
191  return -1;
192  }
193 
195  if (!value) {
196  log_error(aeap, "No value for speech setting '%s'", setting->param);
197  return -1;
198  }
199 
200  ast_copy_string(setting->buf, value, setting->len);
201  return 0;
202 }
203 
204 static int handle_results(struct ast_aeap *aeap, struct ast_json_iter *iter,
205  struct ast_speech_result **speech_results)
206 {
207  struct ast_speech_result *result = NULL;
208  struct ast_json *json_results;
209  struct ast_json *json_result;
210  size_t i;
211 
212  json_results = ast_json_object_iter_value(iter);
213  if (!json_results || !speech_results) {
214  log_error(aeap, "Unable to 'get' speech results");
215  return -1;
216  }
217 
218  for (i = 0; i < ast_json_array_size(json_results); ++i) {
219  if (!(result = ast_calloc(1, sizeof(*result)))) {
220  continue;
221  }
222 
223  json_result = ast_json_array_get(json_results, i);
224 
225  result->text = ast_strdup(ast_json_object_string_get(json_result, "text"));
226  result->score = ast_json_object_integer_get(json_result, "score");
227  result->grammar = ast_strdup(ast_json_object_string_get(json_result, "grammar"));
228  result->nbest_num = ast_json_object_integer_get(json_result, "best");
229  if (*speech_results) {
230  AST_LIST_NEXT(result, list) = *speech_results;
231  *speech_results = result;
232  } else {
233  *speech_results = result;
234  }
235  }
236 
237  return 0;
238 }
239 
240 /*!
241  * \internal
242  * \brief Handle a "get" response from an external application
243  *
244  * Basic structure of the expected JSON message to received:
245  *
246  \verbatim
247  {
248  response: "get"
249  "params" : { <name>: <value> | [ <results> ] }
250  }
251  \endverbatim
252  *
253  * \param aeap Pointer to an Asterisk external application object
254  * \param message The received message
255  * \param data User data passed to the response handler
256  *
257  * \returns 0 on success, -1 on error
258  */
259 static int handle_response_get(struct ast_aeap *aeap, struct ast_aeap_message *message, void *data)
260 {
261  struct ast_json_iter *iter;
262 
264  if (!iter) {
265  log_error(aeap, "no 'get' parameters returned");
266  return -1;
267  }
268 
269  if (!strcmp(ast_json_object_iter_key(iter), "results")) {
270  return handle_results(aeap, iter, data);
271  }
272 
273  return handle_setting(aeap, iter, data);
274 }
275 
276 static int handle_response_setup(struct ast_aeap *aeap, struct ast_aeap_message *message, void *data)
277 {
278  struct ast_format *format = data;
279  struct ast_json *json = ast_aeap_message_data(message);
280  const char *codec_name;
281 
282  if (!format) {
283  log_error(aeap, "no 'format' set");
284  return -1;
285  }
286 
287  if (!json) {
288  log_error(aeap, "no 'setup' object returned");
289  return -1;
290  }
291 
292  json = ast_json_object_get(json, "codecs");
293  if (!json || ast_json_array_size(json) == 0) {
294  log_error(aeap, "no 'setup' codecs available");
295  return -1;
296  }
297 
298  codec_name = ast_json_object_string_get(ast_json_array_get(json, 0), "name");
299  if (!codec_name || strcmp(codec_name, ast_format_get_codec_name(format))) {
300  log_error(aeap, "setup codec '%s' unsupported", ast_format_get_codec_name(format));
301  return -1;
302  }
303 
304  return 0;
305 }
306 
307 static const struct ast_aeap_message_handler response_handlers[] = {
308  { "setup", handle_response_setup },
309  { "get", handle_response_get },
310  { "set", handle_response_set },
311 };
312 
313 static int handle_request_set(struct ast_aeap *aeap, struct ast_aeap_message *message, void *data)
314 {
315  struct ast_json_iter *iter;
316  const char *error_msg = NULL;
317 
319  if (!iter) {
320  error_msg = "no parameter(s) requested";
321  } else if (!strcmp(ast_json_object_iter_key(iter), "results")) {
322  struct ast_speech *speech = ast_aeap_user_data_object_by_id(aeap, "speech");
323 
324  if (!speech) {
325  error_msg = "no associated speech object";
326  } else if (handle_results(aeap, iter, &speech->results)) {
327  error_msg = "unable to handle results";
328  } else {
329  ast_speech_change_state(speech, AST_SPEECH_STATE_DONE);
330  }
331  } else {
332  error_msg = "can only set 'results'";
333  }
334 
335  if (error_msg) {
336  log_error(aeap, "set - %s", error_msg);
338  ast_aeap_message_name(message), ast_aeap_message_id(message), error_msg);
339  } else {
341  ast_aeap_message_name(message), ast_aeap_message_id(message), NULL);
342  }
343 
344  ast_aeap_send_msg(aeap, message);
345 
346  return 0;
347 }
348 
349 static const struct ast_aeap_message_handler request_handlers[] = {
350  { "set", handle_request_set },
351 };
352 
353 /*!
354  * \internal
355  * \brief Handle an error from an external application by setting state to done
356  *
357  * \param aeap Pointer to an Asterisk external application object
358  */
359 static void ast_aeap_speech_on_error(struct ast_aeap *aeap)
360 {
361  struct ast_speech *speech = ast_aeap_user_data_object_by_id(aeap, "speech");
362  if (!speech) {
363  ast_log(LOG_ERROR, "aeap generated error with no associated speech object");
364  return;
365  }
366 
367  ast_speech_change_state(speech, AST_SPEECH_STATE_DONE);
368 }
369 
370 static struct ast_aeap_params speech_aeap_params = {
372  .response_handlers_size = ARRAY_LEN(response_handlers),
373  .request_handlers = request_handlers,
374  .request_handlers_size = ARRAY_LEN(request_handlers),
375  .on_error = ast_aeap_speech_on_error,
376 };
377 
378 /*!
379  * \internal
380  * \brief Create, and connect to an external application and send initial setup
381  *
382  * Basic structure of the JSON message to send:
383  *
384  \verbatim
385  {
386  "request": "setup"
387  "codecs": [
388  {
389  "name": <name>,
390  "attributes": { <name>: <value>, ..., }
391  },
392  ...,
393  ],
394  "params": { <name>: <value>, ..., }
395  }
396  \endverbatim
397  *
398  * \param speech The speech engine
399  * \param format The format codec to use
400  *
401  * \returns 0 on success, -1 on error
402  */
403 static int speech_aeap_engine_create(struct ast_speech *speech, struct ast_format *format)
404 {
405  struct ast_aeap *aeap;
406  struct ast_variable *vars;
407  struct ast_json *json;
408 
410  speech->engine->name, &speech_aeap_params, CONNECTION_TIMEOUT);
411  if (!aeap) {
412  return -1;
413  }
414 
415  speech->data = aeap;
416 
417  /* Don't allow unloading of this module while an external application is in use */
419 
420  vars = ast_aeap_custom_fields_get(speech->engine->name);
421 
422  /* While the protocol allows sending of codec attributes, for now don't */
423  json = ast_json_pack("{s:s,s:[{s:s}],s:o*}", "version", SPEECH_AEAP_VERSION, "codecs",
424  "name", ast_format_get_codec_name(format), "params", custom_fields_to_params(vars));
425 
426  ast_variables_destroy(vars);
427 
428  if (ast_aeap_user_data_register(aeap, "speech", speech, NULL)) {
430  return -1;
431  }
432 
433  /* send_request handles json ref */
434  if (speech_aeap_send_request(speech->data, "setup", json, format)) {
436  return -1;
437  }
438 
439  /*
440  * Add a reference to the engine here, so if it happens to get unregistered
441  * while executing it won't disappear.
442  */
443  ao2_ref(speech->engine, 1);
444 
445  return 0;
446 }
447 
448 static int speech_aeap_engine_destroy(struct ast_speech *speech)
449 {
450  ao2_ref(speech->engine, -1);
451  ao2_cleanup(speech->data);
452 
454 
455  return 0;
456 }
457 
458 static int speech_aeap_engine_write(struct ast_speech *speech, void *data, int len)
459 {
460  return ast_aeap_send_binary(speech->data, data, len);
461 }
462 
463 static int speech_aeap_engine_dtmf(struct ast_speech *speech, const char *dtmf)
464 {
465  return speech_aeap_set(speech, "dtmf", dtmf);
466 }
467 
468 static int speech_aeap_engine_start(struct ast_speech *speech)
469 {
470  ast_speech_change_state(speech, AST_SPEECH_STATE_READY);
471 
472  return 0;
473 }
474 
475 static int speech_aeap_engine_change(struct ast_speech *speech, const char *name, const char *value)
476 {
477  return speech_aeap_set(speech, name, value);
478 }
479 
480 static int speech_aeap_engine_get_setting(struct ast_speech *speech, const char *name,
481  char *buf, size_t len)
482 {
483  struct speech_setting setting = {
484  .param = name,
485  .len = len,
486  .buf = buf,
487  };
488 
489  return speech_aeap_get(speech, name, &setting);
490 }
491 
492 static int speech_aeap_engine_change_results_type(struct ast_speech *speech,
493  enum ast_speech_results_type results_type)
494 {
495  return speech_aeap_set(speech, "results_type",
496  ast_speech_results_type_to_string(results_type));
497 }
498 
499 static struct ast_speech_result *speech_aeap_engine_get(struct ast_speech *speech)
500 {
501  struct ast_speech_result *results = NULL;
502 
503  if (speech->results) {
504  return speech->results;
505  }
506 
507  if (speech_aeap_get(speech, "results", &results)) {
508  return NULL;
509  }
510 
511  return results;
512 }
513 
514 static void speech_engine_destroy(void *obj)
515 {
516  struct ast_speech_engine *engine = obj;
517 
518  ao2_cleanup(engine->formats);
519  ast_free(engine->name);
520 }
521 
522 static struct ast_speech_engine *speech_engine_alloc(const char *name)
523 {
524  struct ast_speech_engine *engine;
525 
526  engine = ao2_t_alloc_options(sizeof(*engine), speech_engine_destroy,
528  if (!engine) {
529  ast_log(LOG_ERROR, "AEAP speech: unable create engine '%s'\n", name);
530  return NULL;
531  }
532 
533  engine->name = ast_strdup(name);
534  if (!engine->name) {
535  ao2_ref(engine, -1);
536  return NULL;
537  }
538 
539  engine->create = speech_aeap_engine_create;
540  engine->destroy = speech_aeap_engine_destroy;
541  engine->write = speech_aeap_engine_write;
542  engine->dtmf = speech_aeap_engine_dtmf;
543  engine->start = speech_aeap_engine_start;
544  engine->change = speech_aeap_engine_change;
545  engine->get_setting = speech_aeap_engine_get_setting;
546  engine->change_results_type = speech_aeap_engine_change_results_type;
547  engine->get = speech_aeap_engine_get;
548 
550 
551  return engine;
552 }
553 
554 static void speech_engine_alloc_and_register(const char *name, const struct ast_format_cap *formats)
555 {
556  struct ast_speech_engine *engine;
557 
558  engine = speech_engine_alloc(name);
559  if (!engine) {
560  return;
561  }
562 
563  if (formats && ast_format_cap_append_from_cap(engine->formats,
564  formats, AST_MEDIA_TYPE_AUDIO)) {
565  ast_log(LOG_WARNING, "AEAP speech: Unable to add engine '%s' formats\n", name);
566  ao2_ref(engine, -1);
567  return;
568  }
569 
570  if (ast_speech_register(engine)) {
571  ast_log(LOG_WARNING, "AEAP speech: Unable to register engine '%s'\n", name);
572  ao2_ref(engine, -1);
573  }
574 }
575 
576 #ifdef TEST_FRAMEWORK
577 
578 static void speech_engine_alloc_and_register2(const char *name, const char *codec_names)
579 {
580  struct ast_speech_engine *engine;
581 
582  engine = speech_engine_alloc(name);
583  if (!engine) {
584  return;
585  }
586 
587  if (codec_names && ast_format_cap_update_by_allow_disallow(engine->formats, codec_names, 1)) {
588  ast_log(LOG_WARNING, "AEAP speech: Unable to add engine '%s' codecs\n", name);
589  ao2_ref(engine, -1);
590  return;
591  }
592 
593  if (ast_speech_register(engine)) {
594  ast_log(LOG_WARNING, "AEAP speech: Unable to register engine '%s'\n", name);
595  ao2_ref(engine, -1);
596  }
597 }
598 
599 #endif
600 
601 static int unload_engine(void *obj, void *arg, int flags)
602 {
603  if (ast_aeap_client_config_has_protocol(obj, SPEECH_PROTOCOL)) {
605  }
606 
607  return 0;
608 }
609 
610 static int load_engine(void *obj, void *arg, int flags)
611 {
612  const char *id;
613  const struct ast_format_cap *formats;
614  const struct ast_speech_engine *engine;
615 
616  if (!ast_aeap_client_config_has_protocol(obj, SPEECH_PROTOCOL)) {
617  return 0;
618  }
619 
620  id = ast_sorcery_object_get_id(obj);
621  formats = ast_aeap_client_config_codecs(obj);
622  if (!formats) {
624  if (!formats) {
625  ast_log(LOG_ERROR, "AEAP speech: unable to allocate default engine format for '%s'\n", id);
626  return 0;
627  }
628  }
629 
630  engine = ast_speech_find_engine(id);
631  if (!engine) {
632  speech_engine_alloc_and_register(id, formats);
633  return 0;
634  }
635 
636  if (ast_format_cap_identical(formats, engine->formats)) {
637  /* Same name, same formats then nothing changed */
638  return 0;
639  }
640 
641  ao2_ref(ast_speech_unregister2(engine->name), -1);
642  speech_engine_alloc_and_register(id, formats);
643 
644  return 0;
645 }
646 
647 static int matches_engine(void *obj, void *arg, int flags)
648 {
649  const struct ast_speech_engine *engine = arg;
650 
651  return strcmp(ast_sorcery_object_get_id(obj), engine->name) ? 0 : CMP_MATCH;
652 }
653 
654 static int should_unregister(const struct ast_speech_engine *engine, void *data)
655 {
656  void *obj;
657 
658  if (engine->create != speech_aeap_engine_create) {
659  /* Only want to potentially unregister AEAP speech engines */
660  return 0;
661  }
662 
663 #ifdef TEST_FRAMEWORK
664  if (!strcmp("_aeap_test_speech_", engine->name)) {
665  /* Don't remove the test engine */
666  return 0;
667  }
668 #endif
669 
670  obj = ao2_callback(data, 0, matches_engine, (void*)engine);
671 
672  if (obj) {
673  ao2_ref(obj, -1);
674  return 0;
675  }
676 
677  /* If no match in given container then unregister engine */
678  return 1;
679 }
680 
681 static void speech_observer_loaded(const char *object_type)
682 {
683  struct ao2_container *container;
684 
685  if (strcmp(object_type, AEAP_CONFIG_CLIENT)) {
686  return;
687  }
688 
689  container = ast_aeap_client_configs_get(SPEECH_PROTOCOL);
690  if (!container) {
691  return;
692  }
693 
694  /*
695  * An AEAP module reload has occurred. First
696  * remove all engines that no longer exist.
697  */
698  ast_speech_unregister_engines(should_unregister, container, __ao2_cleanup);
699 
700  /* Now add or update engines */
701  ao2_callback(container, 0, load_engine, NULL);
702  ao2_ref(container, -1);
703 }
704 
705 /*! \brief Observer for AEAP reloads */
706 static const struct ast_sorcery_observer speech_observer = {
707  .loaded = speech_observer_loaded,
708 };
709 
710 static int unload_module(void)
711 {
712  struct ao2_container *container;
713 
714 #ifdef TEST_FRAMEWORK
715  ao2_cleanup(ast_speech_unregister2("_aeap_test_speech_"));
716 #endif
717 
718  ast_sorcery_observer_remove(ast_aeap_sorcery(), AEAP_CONFIG_CLIENT, &speech_observer);
719 
720  container = ast_aeap_client_configs_get(SPEECH_PROTOCOL);
721  if (container) {
722  ao2_callback(container, 0, unload_engine, NULL);
723  ao2_ref(container, -1);
724  }
725 
726  return 0;
727 }
728 
729 static int load_module(void)
730 {
731  struct ao2_container *container;
732 
733  speech_aeap_params.msg_type = ast_aeap_message_type_json;
734 
735  container = ast_aeap_client_configs_get(SPEECH_PROTOCOL);
736  if (container) {
737  ao2_callback(container, 0, load_engine, NULL);
738  ao2_ref(container, -1);
739  }
740 
741  /*
742  * Add an observer since a named speech server must be created,
743  * registered, and eventually removed for all AEAP client
744  * configuration matching the "speech_to_text" protocol.
745  */
746  if (ast_sorcery_observer_add(ast_aeap_sorcery(), AEAP_CONFIG_CLIENT, &speech_observer)) {
748  }
749 
750 #ifdef TEST_FRAMEWORK
751  speech_engine_alloc_and_register2("_aeap_test_speech_", "ulaw");
752 #endif
753 
755 }
756 
757 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Asterisk External Application Speech Engine",
758  .support_level = AST_MODULE_SUPPORT_CORE,
759  .load = load_module,
760  .unload = unload_module,
761  .load_pri = AST_MODPRI_CHANNEL_DEPEND,
762  .requires = "res_speech,res_aeap",
763 );
struct ast_variable * next
Asterisk External Application Protocol API.
Callbacks and other parameters used by an Asterisk external application object.
Definition: res_aeap.h:144
Asterisk main include file. File version handling, generic pbx functions.
int(* destroy)(struct ast_speech *speech)
Definition: speech.h:82
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:612
Generic Speech Recognition API.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
int(* create)(struct ast_speech *speech, struct ast_format *format)
Definition: speech.h:80
int(* change)(struct ast_speech *speech, const char *name, const char *value)
Definition: speech.h:98
Asterisk External Application Protocol Message API.
const char * ast_format_get_codec_name(const struct ast_format *format)
Get the codec name associated with a format.
Definition: format.c:339
void ast_speech_unregister_engines(int(*should_unregister)(const struct ast_speech_engine *engine, void *data), void *data, void(*on_unregistered)(void *obj))
Unregister all speech recognition engines told to by callback.
Definition: res_speech.c:380
int ast_aeap_client_config_has_protocol(const struct ast_aeap_client_config *cfg, const char *protocol)
Check a given protocol against that in an Asterisk external application configuration.
Definition: res_aeap.c:136
struct ast_speech_engine * ast_speech_unregister2(const char *engine_name)
Unregister a speech recognition engine.
Definition: res_speech.c:352
Iterator for JSON object key/values.
const struct ast_aeap_message_handler * request_handlers
Definition: res_aeap.h:160
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
Definition: astobj2.h:1693
struct ast_json_iter * ast_json_object_iter(struct ast_json *object)
Get an iterator pointing to the first field in a JSON object.
Definition: json.c:439
void __ao2_cleanup(void *obj)
Definition: astobj2.c:677
void * ast_aeap_message_data(struct ast_aeap_message *message)
Retrieve the core message data/body.
Structure for variables, used for configurations and for channel variables.
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:439
int ast_speech_register(struct ast_speech_engine *engine)
Register a speech recognition engine.
Definition: res_speech.c:316
Definition of a media format.
Definition: format.c:43
void * data
Definition: speech.h:66
const struct ast_aeap_message_type * msg_type
Definition: res_aeap.h:152
#define ao2_t_alloc_options(data_size, destructor_fn, options, debug_msg)
Allocate and initialize an object.
Definition: astobj2.h:402
int ast_aeap_send_msg_tsx(struct ast_aeap *aeap, struct ast_aeap_tsx_params *params)
Send a transaction based message to an external application using the given parameters.
Definition: aeap.c:464
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
char * name
Definition: speech.h:78
struct ast_sorcery * ast_aeap_sorcery(void)
Retrieve the AEAP sorcery object.
Definition: res_aeap.c:67
void * ast_aeap_user_data_object_by_id(struct ast_aeap *aeap, const char *id)
Retrieve a registered user data object by its id.
Definition: aeap.c:174
int(* start)(struct ast_speech *speech)
Definition: speech.h:96
#define ast_json_object_integer_get(object, key)
Get an integer field from a JSON object.
Definition: json.h:609
Parameters to be used when sending a transaction based message.
Definition: res_aeap.h:331
char * grammar
Definition: speech.h:119
int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value)
Set a field in a JSON object.
Definition: json.c:414
Media Format API.
int ast_format_cap_update_by_allow_disallow(struct ast_format_cap *cap, const char *list, int allowing)
Parse an "allow" or "deny" list and modify a format capabilities structure accordingly.
Definition: format_cap.c:320
const char * ast_aeap_message_id(const struct ast_aeap_message *message)
Retrieve a message id.
Configuration File Parser.
struct ast_module * self
Definition: module.h:356
int ast_aeap_send_msg(struct ast_aeap *aeap, struct ast_aeap_message *msg)
Send a message to an external application.
Definition: aeap.c:439
Asterisk JSON abstraction layer.
struct ast_json * ast_json_object_iter_value(struct ast_json_iter *iter)
Get the value from an iterator.
Definition: json.c:455
struct ast_json * ast_json_string_create(const char *value)
Construct a JSON string from value.
Definition: json.c:278
int ast_speech_change_state(struct ast_speech *speech, int state)
Change state of a speech structure.
Definition: res_speech.c:278
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ast_json_object_string_get(object, key)
Get a string field from a JSON object.
Definition: json.h:600
struct ast_format_cap * formats
Definition: speech.h:106
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2317
static struct ao2_container * formats
Cached formats.
Definition: format_cache.c:260
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:283
int(* change_results_type)(struct ast_speech *speech, enum ast_speech_results_type results_type)
Definition: speech.h:102
struct ao2_container * container
Definition: res_fax.c:501
struct ast_speech_engine * engine
Definition: speech.h:72
const char * ast_json_object_iter_key(struct ast_json_iter *iter)
Get the key from an iterator.
Definition: json.c:451
const char * ast_aeap_message_name(const struct ast_aeap_message *message)
Retrieve a message name.
struct ast_speech_result * results
Definition: speech.h:68
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition: format_cap.h:49
struct ast_aeap * ast_aeap_create_and_connect_by_id(const char *id, const struct ast_aeap_params *params, int timeout)
Create and connect to an Asterisk external application by sorcery id.
Definition: res_aeap.c:322
int ast_sorcery_observer_add(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
Add an observer to a specific object type.
Definition: sorcery.c:2391
Format Capabilities API.
struct ast_speech_engine * ast_speech_find_engine(const char *engine_name)
Retrieve a speech recognition engine.
Definition: res_speech.c:46
struct ast_speech_result *(* get)(struct ast_speech *speech)
Definition: speech.h:104
struct ast_variable * ast_aeap_custom_fields_get(const char *id)
Retrieve a list of custom configuration fields.
Definition: res_aeap.c:328
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:92
int ast_aeap_user_data_register(struct ast_aeap *aeap, const char *id, void *obj, ast_aeap_user_obj_cleanup cleanup)
Register a user data object.
Definition: aeap.c:150
Interface for a sorcery object type observer.
Definition: sorcery.h:332
Definition: file.c:69
struct ast_aeap_message * ast_aeap_message_create_response(const struct ast_aeap_message_type *type, const char *name, const char *id, const void *params)
Create an Asterisk external application response object.
Asterisk external application base message.
#define ast_module_ref(mod)
Hold a reference to the module.
Definition: module.h:457
An Asterisk external application message handler.
Definition: res_aeap.h:108
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
int ast_format_cap_identical(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
Determine if two capabilities structures are identical.
Definition: format_cap.c:687
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
const char * ast_speech_results_type_to_string(enum ast_speech_results_type type)
Convert a speech results type to a string.
Definition: res_speech.c:294
void(* loaded)(const char *object_type)
Callback for when an object type is loaded/reloaded.
Definition: sorcery.h:343
#define ast_module_unref(mod)
Release a reference to the module.
Definition: module.h:483
struct ast_json * ast_json_object_create(void)
Create a new JSON object.
Definition: json.c:399
void ast_sorcery_observer_remove(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
Remove an observer from a specific object type.
Definition: sorcery.c:2423
struct ast_aeap_message * ast_aeap_message_create_error(const struct ast_aeap_message_type *type, const char *name, const char *id, const char *error_msg)
Create an Asterisk external application error response object.
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition: json.c:407
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
size_t ast_json_array_size(const struct ast_json *array)
Get the size of a JSON array.
Definition: json.c:366
int(* dtmf)(struct ast_speech *speech, const char *dtmf)
Definition: speech.h:94
struct ast_aeap_message * msg
Definition: res_aeap.h:333
Abstract JSON element (object, array, string, int, ...).
const struct ast_aeap_message_handler * response_handlers
Definition: res_aeap.h:155
struct ast_aeap_message * ast_aeap_message_create_request(const struct ast_aeap_message_type *type, const char *name, const char *id, const void *params)
Create an Asterisk external application request object.
Generic container type.
int ast_format_cap_append_from_cap(struct ast_format_cap *dst, const struct ast_format_cap *src, enum ast_media_type type)
Append the formats of provided type in src to dst.
Definition: format_cap.c:269
const struct ast_format_cap * ast_aeap_client_config_codecs(const struct ast_aeap_client_config *cfg)
Retrieve codec capabilities from the configuration.
Definition: res_aeap.c:131
struct ao2_container * ast_aeap_client_configs_get(const char *protocol)
Retrieve a listing of all client configuration objects by protocol.
Definition: res_aeap.c:142
const struct ast_aeap_message_type * ast_aeap_message_type_json
Asterisk external application JSON message type.
Definition: message_json.c:191
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
static const struct ast_sorcery_observer speech_observer
Observer for AEAP reloads.
struct ast_json * ast_json_array_get(const struct ast_json *array, size_t index)
Get an element from an array.
Definition: json.c:370
int ast_aeap_send_binary(struct ast_aeap *aeap, const void *buf, uintmax_t size)
Send a binary data to an external application.
Definition: aeap.c:434
int(* get_setting)(struct ast_speech *speech, const char *name, char *buf, size_t len)
Definition: speech.h:100
Sorcery Data Access Layer API.
Definition: aeap.c:47