42
42
#define VOSK_ENGINE_NAME "vosk"
43
43
#define VOSK_ENGINE_CONFIG "res_speech_vosk.conf"
44
44
#define VOSK_BUF_SIZE 3200
45
+ #define VOSK_MAX_HORSES 10
45
46
46
47
/** \brief Forward declaration of speech (client object) */
47
48
typedef struct vosk_speech_t vosk_speech_t ;
@@ -63,7 +64,11 @@ struct vosk_speech_t {
63
64
/** \brief Declaration of Vosk recognition engine */
64
65
struct vosk_engine_t {
65
66
/* Websocket url*/
66
- char * ws_url ;
67
+ char * ws_url [VOSK_MAX_HORSES ];
68
+ /* Horse name */
69
+ char * horse [VOSK_MAX_HORSES ];
70
+ /* Horse count */
71
+ int num_horses ;
67
72
};
68
73
69
74
static struct vosk_engine_t vosk_engine ;
@@ -73,33 +78,46 @@ static int vosk_recog_create(struct ast_speech *speech, struct ast_format *forma
73
78
{
74
79
vosk_speech_t * vosk_speech ;
75
80
enum ast_websocket_result result ;
81
+ int jockey = 0 ;
76
82
77
83
vosk_speech = ast_calloc (1 , sizeof (vosk_speech_t ));
78
84
vosk_speech -> name = "vosk" ;
79
85
speech -> data = vosk_speech ;
80
86
81
- ast_debug (1 , "(%s) Create speech resource %s\n" ,vosk_speech -> name , vosk_engine .ws_url );
87
+ for (jockey = 0 ; jockey < vosk_engine .num_horses ; jockey ++ ) {
88
+ if ((jockey == 0 && (speech -> horse == NULL || ast_strlen_zero (speech -> horse ))) || !strcasecmp (vosk_engine .horse [jockey ], speech -> horse )) {
89
+ ast_debug (1 , "(%s) Create speech resource %d horse '%s' url %s\n" , vosk_speech -> name , jockey , speech -> horse , vosk_engine .ws_url [jockey ]);
90
+ vosk_speech -> ws = ast_websocket_client_create (vosk_engine .ws_url [jockey ], "ws" , NULL , & result );
91
+ if (vosk_speech -> ws ) {
92
+ ast_debug (1 , "(%s) Created speech resource result %d\n" , vosk_speech -> name , result );
93
+ } else {
94
+ ast_free (speech -> data );
95
+ return -1 ;
96
+ }
97
+ break ;
98
+ }
99
+ }
82
100
83
- vosk_speech -> ws = ast_websocket_client_create (vosk_engine .ws_url , "ws" , NULL , & result );
84
101
if (!vosk_speech -> ws ) {
85
- ast_free ( speech -> data );
102
+ ast_log ( LOG_WARNING , "Syntax Error in Vosk configuration and/or dial plan invocation.\n" );
86
103
return -1 ;
87
- }
88
-
89
- ast_debug (1 , "(%s) Created speech resource result %d\n" , vosk_speech -> name , result );
104
+ }
90
105
91
106
return 0 ;
92
107
}
93
108
94
109
/** \brief Destroy any data set on the speech structure by the engine */
95
110
static int vosk_recog_destroy (struct ast_speech * speech )
96
111
{
112
+ const char * eof = "{\"eof\" : 1}" ;
113
+
97
114
vosk_speech_t * vosk_speech = speech -> data ;
98
115
ast_debug (1 , "(%s) Destroy speech resource\n" ,vosk_speech -> name );
99
116
100
117
if (vosk_speech -> ws ) {
101
118
int fd = ast_websocket_fd (vosk_speech -> ws );
102
119
if (fd > 0 ) {
120
+ ast_websocket_write_string (vosk_speech -> ws , eof );
103
121
ast_websocket_close (vosk_speech -> ws , 1000 );
104
122
shutdown (fd , SHUT_RDWR );
105
123
}
@@ -150,11 +168,13 @@ static int vosk_recog_write(struct ast_speech *speech, void *data, int len)
150
168
vosk_speech_t * vosk_speech = speech -> data ;
151
169
char * res ;
152
170
int res_len ;
171
+ int i = 0 ;
153
172
154
173
ast_assert (vosk_speech -> offset + len < VOSK_BUF_SIZE );
155
174
156
175
memcpy (vosk_speech -> buf + vosk_speech -> offset , data , len );
157
176
vosk_speech -> offset += len ;
177
+
158
178
if (vosk_speech -> offset == VOSK_BUF_SIZE ) {
159
179
ast_websocket_write (vosk_speech -> ws , AST_WEBSOCKET_OPCODE_BINARY , vosk_speech -> buf , VOSK_BUF_SIZE );
160
180
vosk_speech -> offset = 0 ;
@@ -203,8 +223,12 @@ static int vosk_recog_dtmf(struct ast_speech *speech, const char *dtmf)
203
223
static int vosk_recog_start (struct ast_speech * speech )
204
224
{
205
225
vosk_speech_t * vosk_speech = speech -> data ;
206
- ast_debug (1 , "(%s) Start recognition\n" ,vosk_speech -> name );
226
+ /* does not appear that reset has any effect
227
+ const char *reset = "{\"reset\" : 1}";
228
+ ast_websocket_write_string(vosk_speech->ws, reset);
229
+ */
207
230
ast_speech_change_state (speech , AST_SPEECH_STATE_READY );
231
+ ast_debug (1 , "(%s) Start recognition\n" ,vosk_speech -> name );
208
232
return 0 ;
209
233
}
210
234
@@ -266,19 +290,44 @@ static struct ast_speech_engine ast_engine = {
266
290
static int vosk_engine_config_load ()
267
291
{
268
292
const char * value = NULL ;
293
+ char * category = NULL ;
294
+ int num_horses = 0 ;
269
295
struct ast_flags config_flags = { 0 };
270
296
struct ast_config * cfg = ast_config_load (VOSK_ENGINE_CONFIG , config_flags );
271
297
if (!cfg ) {
272
298
ast_log (LOG_WARNING , "No such configuration file %s\n" , VOSK_ENGINE_CONFIG );
273
299
return -1 ;
274
300
}
275
- if ((value = ast_variable_retrieve (cfg , "general" , "url" )) != NULL ) {
276
- ast_log (LOG_DEBUG , "general.url=%s\n" , value );
277
- vosk_engine .ws_url = ast_strdup (value );
301
+
302
+ if ((value = ast_variable_retrieve (cfg , "general" , "url" )) != NULL ) {
303
+ ast_debug (1 , "general.url=%s\n" , value );
304
+ vosk_engine .ws_url [0 ] = ast_strdup (value );
305
+ vosk_engine .horse [0 ] = ast_strdup ("" );
306
+ vosk_engine .num_horses = 1 ;
307
+ } else {
308
+ while (category = ast_category_browse (cfg , category )) {
309
+ if (strcasecmp (category , "general" ) != 0 ) {
310
+ if ((value = ast_variable_retrieve (cfg , category , "type" )) != NULL ) {
311
+ if (!strcasecmp (value , "horse" )) {
312
+ if ((value = ast_variable_retrieve (cfg , category , "url" )) != NULL ) {
313
+ ast_debug (1 , "%s.horse.url=%s\n" , category , value );
314
+ vosk_engine .ws_url [num_horses ] = ast_strdup (value );
315
+ vosk_engine .horse [num_horses ] = ast_strdup (category );
316
+ vosk_engine .num_horses = ++ num_horses ;
317
+ }
318
+ }
319
+ }
320
+ }
321
+ }
278
322
}
279
- if (!vosk_engine .ws_url ) {
280
- vosk_engine .ws_url = ast_strdup ("ws://localhost" );
323
+
324
+ if (!vosk_engine .ws_url [0 ]) {
325
+ vosk_engine .ws_url [0 ] = ast_strdup ("ws://localhost" );
326
+ vosk_engine .horse [0 ] = ast_strdup ("" );
327
+ vosk_engine .num_horses = 1 ;
328
+ ast_debug (1 , "default general.url=%s\n" , vosk_engine .ws_url [0 ]);
281
329
}
330
+
282
331
ast_config_destroy (cfg );
283
332
return 0 ;
284
333
}
@@ -311,12 +360,17 @@ static int load_module(void)
311
360
/** \brief Unload module */
312
361
static int unload_module (void )
313
362
{
363
+ int i = 0 ;
364
+
314
365
ast_log (LOG_NOTICE , "Unload res_speech_vosk module\n" );
315
366
if (ast_speech_unregister (VOSK_ENGINE_NAME )) {
316
367
ast_log (LOG_ERROR , "Failed to unregister module\n" );
317
368
}
318
369
319
- ast_free (vosk_engine .ws_url );
370
+ for (i = 0 ;i < vosk_engine .num_horses ;i ++ ) {
371
+ ast_free (vosk_engine .ws_url [i ]);
372
+ ast_free (vosk_engine .horse [i ]);
373
+ }
320
374
return 0 ;
321
375
}
322
376
0 commit comments