Asterisk - The Open Source Telephony Project GIT-master-2de1a68
test_aeap_speech.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/*** MODULEINFO
20 <depend>TEST_FRAMEWORK</depend>
21 <depend>res_aeap</depend>
22 <support_level>core</support_level>
23 ***/
24
25#include "asterisk.h"
26
27#include "asterisk/test.h"
28#include "asterisk/module.h"
29#include "asterisk/file.h"
30#include "asterisk/format_cap.h"
31#include "asterisk/http.h"
33#include "asterisk/json.h"
34#include "asterisk/speech.h"
35
36#include "asterisk/res_aeap.h"
38
39#define ADDR "127.0.0.1:8088"
40
41static int speech_test_server_setup(struct ast_json *req, struct ast_json *resp)
42{
43 struct ast_json *params;
44
45 if (ast_json_object_set(resp, "codecs", ast_json_ref(ast_json_object_get(req, "codecs")))) {
46 return -1;
47 }
48
49 params = ast_json_object_get(req, "params"); /* Optional */
50 if (params && ast_json_object_set(resp, "params", ast_json_ref(params))) {
51 return -1;
52 }
53
54 return 0;
55}
56
57#define TEST_SPEECH_RESULTS_TEXT "foo"
58#define TEST_SPEECH_RESULTS_SCORE 7
59#define TEST_SPEECH_RESULTS_GRAMMAR "bar"
60#define TEST_SPEECH_RESULTS_BEST 1
61
62static int speech_test_server_get(struct ast_json *req, struct ast_json *resp)
63{
64 const char *param;
65 struct ast_json *json = NULL;
66
68 if (!param) {
69 return -1;
70 }
71
72 if (!strcmp(param, "results")) {
73 json = ast_json_pack("{s:[{s:s,s:i,s:s,s:i}]}",
74 param,
79 } else {
80 /* Assume setting */
81 json = ast_json_pack("{s:s}", param, "bar");
82 }
83
84 if (!json || ast_json_object_set(resp, "params", json)) {
85 return -1;
86 }
87
88 return 0;
89}
90
91static int speech_test_server_set(struct ast_json *req, struct ast_json *resp)
92{
93 if (ast_json_object_set(resp, "params", ast_json_ref(ast_json_object_get(req, "params")))) {
94 return -1;
95 }
96
97 return 0;
98}
99
100static int speech_test_server_handle_request(struct ast_websocket *ws, const void *buf, uint64_t size)
101{
102 struct ast_json *req;
103 struct ast_json *resp;
104 const char *name;
105 char *resp_buf;
106 int res = 0;
107
108 req = ast_json_load_buf(buf, size, NULL);
109 if (!req) {
110 ast_log(LOG_ERROR, "speech test handle request: unable to load json\n");
111 return -1;
112 }
113
114 name = ast_json_object_string_get(req, "request");
115 if (!name) {
116 ast_log(LOG_ERROR, "speech test handle request: no name\n");
117 ast_json_unref(req);
118 return -1;
119 }
120
121 resp = ast_json_pack("{s:s, s:s}", "response", name,
122 "id", ast_json_object_string_get(req, "id"));
123 if (!resp) {
124 ast_log(LOG_ERROR, "speech test handle request: unable to create response '%s'\n", name);
125 ast_json_unref(req);
126 return -1;
127 }
128
129 if (!strcmp(name, "setup")) {
130 res = speech_test_server_setup(req, resp);
131 } else if (!strcmp(name, "get")) {
132 res = speech_test_server_get(req, resp);
133 } else if (!strcmp(name, "set")) {
134 res = speech_test_server_set(req, resp);
135 } else {
136 ast_log(LOG_ERROR, "speech test handle request: unsupported request '%s'\n", name);
137 return -1;
138 }
139
140 if (res) {
141 ast_log(LOG_ERROR, "speech test handle request: unable to build response '%s'\n", name);
142 ast_json_unref(resp);
143 ast_json_unref(req);
144 return -1;
145 }
146
147 resp_buf = ast_json_dump_string(resp);
148 ast_json_unref(resp);
149
150 if (!resp_buf) {
151 ast_log(LOG_ERROR, "speech test handle request: unable to dump response '%s'\n", name);
152 ast_json_unref(req);
153 return -1;
154 }
155
156 res = ast_websocket_write_string(ws, resp_buf);
157 if (res) {
158 ast_log(LOG_ERROR, "speech test handle request: unable to write response '%s'\n", name);
159 }
160
161 ast_json_unref(req);
162 ast_free(resp_buf);
163
164 return res;
165}
166
167static void speech_test_server_cb(struct ast_websocket *ws, struct ast_variable *parameters,
168 struct ast_variable *headers)
169{
170 int res;
171
172 if (ast_fd_set_flags(ast_websocket_fd(ws), O_NONBLOCK)) {
174 return;
175 }
176
177 while ((res = ast_websocket_wait_for_input(ws, -1)) > 0) {
178 char *payload;
179 uint64_t payload_len;
180 enum ast_websocket_opcode opcode;
181 int fragmented;
182
183 if (ast_websocket_read(ws, &payload, &payload_len, &opcode, &fragmented)) {
184 ast_log(LOG_ERROR, "speech test: Read failure in server loop\n");
185 break;
186 }
187
188 switch (opcode) {
191 return;
193 ast_websocket_write(ws, opcode, payload, payload_len);
194 break;
196 ast_debug(3, "payload=%.*s\n", (int)payload_len, payload);
197 if (speech_test_server_handle_request(ws, payload, payload_len)) {
199 return;
200 }
201 break;
202 default:
203 break;
204 }
205 }
207}
208
209AST_TEST_DEFINE(res_speech_aeap_test)
210{
211 RAII_VAR(struct ast_format_cap *, cap, NULL, ao2_cleanup);
213 struct ast_speech *speech = NULL;
215 char buf[8] = "";
216
217 switch (cmd) {
218 case TEST_INIT:
219 info->name = __func__;
220 info->explicit_only = 0;
221 info->category = "/res/aeap/speech/";
222 info->summary = "test the speech AEAP interface";
223 info->description = info->summary;
224 return AST_TEST_NOT_RUN;
225 case TEST_EXECUTE:
226 break;
227 }
228
229 ast_test_validate(test, !ast_websocket_add_protocol("_aeap_test_speech_", speech_test_server_cb));
230
231 ast_test_validate(test, (cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)));
232 ast_test_validate(test, !ast_format_cap_update_by_allow_disallow(cap, "ulaw", 1));
233
234 ast_test_validate_cleanup(test, (speech = ast_speech_new("_aeap_test_speech_", cap)), res, cleanup);
235 ast_speech_start(speech);
236 ast_test_validate_cleanup(test, !ast_speech_dtmf(speech, "1"), res, cleanup);
237 ast_test_validate_cleanup(test, !ast_speech_change(speech, "foo", "bar"), res, cleanup);
238 ast_test_validate_cleanup(test, !ast_speech_change_results_type(
240
241 ast_test_validate_cleanup(test, !ast_speech_get_setting(
242 speech, "foo", buf, sizeof(buf)), res, cleanup);
243 ast_test_validate_cleanup(test, !strcmp(buf, "bar"), res, cleanup);
244
245 ast_test_validate_cleanup(test, (results = ast_speech_results_get(speech)), res, cleanup);
246 ast_test_validate_cleanup(test, !strcmp(results->text, TEST_SPEECH_RESULTS_TEXT), res, cleanup);
247 ast_test_validate_cleanup(test, results->score == TEST_SPEECH_RESULTS_SCORE, res, cleanup);
248 ast_test_validate_cleanup(test, !strcmp(results->grammar, TEST_SPEECH_RESULTS_GRAMMAR), res, cleanup);
249 ast_test_validate_cleanup(test, results->nbest_num == TEST_SPEECH_RESULTS_BEST, res, cleanup);
250
251cleanup:
252 if (speech) {
253 ast_speech_destroy(speech);
254 }
256
257 return res;
258}
259
261
262static int load_module(void)
263{
264 if (!(http_server = ast_http_test_server_get("aeap transport http server", NULL))) {
266 }
267
268 AST_TEST_REGISTER(res_speech_aeap_test);
269
271}
272
273static int unload_module(void)
274{
275 AST_TEST_UNREGISTER(res_speech_aeap_test);
276
277 ast_http_test_server_discard(http_server);
278
279 return 0;
280}
281
282AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Asterisk External Application Protocol Speech test(s)",
283 .support_level = AST_MODULE_SUPPORT_CORE,
284 .load = load_module,
285 .unload = unload_module,
286 .requires = "res_speech_aeap",
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_log
Definition: astobj2.c:42
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
Generic File Format Support. Should be included by clients of the file handling routines....
Format Capabilities 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
@ AST_FORMAT_CAP_FLAG_DEFAULT
Definition: format_cap.h:38
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition: format_cap.h:49
static const char name[]
Definition: format_mp3.c:68
Support for Private Asterisk HTTP Servers.
Support for WebSocket connections within the Asterisk HTTP server and client WebSocket connections to...
int ast_websocket_remove_protocol(const char *name, ast_websocket_callback callback)
Remove a sub-protocol handler from the default /ws server.
int ast_websocket_read(struct ast_websocket *session, char **payload, uint64_t *payload_len, enum ast_websocket_opcode *opcode, int *fragmented)
Read a WebSocket frame and handle it.
int ast_websocket_wait_for_input(struct ast_websocket *session, int timeout)
Wait for the WebSocket session to be ready to be read.
ast_websocket_opcode
WebSocket operation codes.
@ AST_WEBSOCKET_OPCODE_BINARY
@ AST_WEBSOCKET_OPCODE_CLOSE
@ AST_WEBSOCKET_OPCODE_TEXT
void ast_websocket_unref(struct ast_websocket *session)
Decrease the reference count for a WebSocket session.
int ast_websocket_write_string(struct ast_websocket *ws, const char *buf)
Construct and transmit a WebSocket frame containing string data.
int ast_websocket_fd(struct ast_websocket *session)
Get the file descriptor for a WebSocket session.
int ast_websocket_write(struct ast_websocket *session, enum ast_websocket_opcode opcode, char *payload, uint64_t payload_size)
Construct and transmit a WebSocket frame.
int ast_websocket_add_protocol(const char *name, ast_websocket_callback callback)
Add a sub-protocol handler to the default /ws server.
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
Asterisk JSON abstraction layer.
#define ast_json_object_string_get(object, key)
Get a string field from a JSON object.
Definition: json.h:600
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
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
#define ast_json_dump_string(root)
Encode a JSON value to a compact string.
Definition: json.h:810
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:612
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition: json.c:67
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
struct ast_json * ast_json_load_buf(const char *buffer, size_t buflen, struct ast_json_error *error)
Parse buffer with known length into a JSON object or array.
Definition: json.c:585
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:283
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
Asterisk module definitions.
@ AST_MODFLAG_DEFAULT
Definition: module.h:315
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:543
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
def info(msg)
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124
Asterisk External Application Protocol API.
Asterisk External Application Protocol Message API.
#define NULL
Definition: resample.c:96
Generic Speech Recognition API.
int ast_speech_dtmf(struct ast_speech *speech, const char *dtmf)
Signal to the engine that DTMF was received.
Definition: res_speech.c:154
int ast_speech_results_free(struct ast_speech_result *result)
Free a set of results.
Definition: res_speech.c:96
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:122
int ast_speech_change(struct ast_speech *speech, const char *name, const char *value)
Change an engine specific attribute.
Definition: res_speech.c:169
struct ast_speech * ast_speech_new(const char *engine_name, const struct ast_format_cap *formats)
Create a new speech structure.
Definition: res_speech.c:181
int ast_speech_destroy(struct ast_speech *speech)
Destroy a speech structure.
Definition: res_speech.c:251
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:308
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:175
@ AST_SPEECH_RESULTS_TYPE_NBEST
Definition: speech.h:47
struct ast_speech_result * ast_speech_results_get(struct ast_speech *speech)
Get speech recognition results.
Definition: res_speech.c:90
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
Abstract JSON element (object, array, string, int, ...).
char * grammar
Definition: speech.h:119
struct ast_speech_result * results
Definition: speech.h:68
Structure for variables, used for configurations and for channel variables.
Structure definition for session.
Test Framework API.
@ TEST_INIT
Definition: test.h:200
@ TEST_EXECUTE
Definition: test.h:201
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
ast_test_result_state
Definition: test.h:193
@ AST_TEST_PASS
Definition: test.h:195
@ AST_TEST_NOT_RUN
Definition: test.h:194
#define TEST_SPEECH_RESULTS_SCORE
static void speech_test_server_cb(struct ast_websocket *ws, struct ast_variable *parameters, struct ast_variable *headers)
static int speech_test_server_handle_request(struct ast_websocket *ws, const void *buf, uint64_t size)
#define TEST_SPEECH_RESULTS_TEXT
static int speech_test_server_get(struct ast_json *req, struct ast_json *resp)
AST_TEST_DEFINE(res_speech_aeap_test)
#define TEST_SPEECH_RESULTS_GRAMMAR
static int speech_test_server_setup(struct ast_json *req, struct ast_json *resp)
#define TEST_SPEECH_RESULTS_BEST
static int load_module(void)
static int unload_module(void)
static struct ast_http_server * http_server
static int speech_test_server_set(struct ast_json *req, struct ast_json *resp)
#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:941
#define ast_fd_set_flags(fd, flags)
Set flags on the given file descriptor.
Definition: utils.h:1039