00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "asterisk.h"
00029
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 79334 $");
00031
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #include <unistd.h>
00035 #include <string.h>
00036
00037 #include "asterisk/file.h"
00038 #include "asterisk/logger.h"
00039 #include "asterisk/channel.h"
00040 #include "asterisk/pbx.h"
00041 #include "asterisk/module.h"
00042 #include "asterisk/lock.h"
00043 #include "asterisk/app.h"
00044 #include "asterisk/speech.h"
00045
00046
00047 static char *speechcreate_descrip =
00048 "SpeechCreate(engine name)\n"
00049 "This application creates information to be used by all the other applications. It must be called before doing any speech recognition activities such as activating a grammar.\n"
00050 "It takes the engine name to use as the argument, if not specified the default engine will be used.\n";
00051
00052 static char *speechactivategrammar_descrip =
00053 "SpeechActivateGrammar(Grammar Name)\n"
00054 "This activates the specified grammar to be recognized by the engine. A grammar tells the speech recognition engine what to recognize, \n"
00055 "and how to portray it back to you in the dialplan. The grammar name is the only argument to this application.\n";
00056
00057 static char *speechstart_descrip =
00058 "SpeechStart()\n"
00059 "Tell the speech recognition engine that it should start trying to get results from audio being fed to it. This has no arguments.\n";
00060
00061 static char *speechbackground_descrip =
00062 "SpeechBackground(Sound File|Timeout)\n"
00063 "This application plays a sound file and waits for the person to speak. Once they start speaking playback of the file stops, and silence is heard.\n"
00064 "Once they stop talking the processing sound is played to indicate the speech recognition engine is working.\n"
00065 "Once results are available the application returns and results (score and text) are available using dialplan functions.\n"
00066 "The first text and score are ${SPEECH_TEXT(0)} AND ${SPEECH_SCORE(0)} while the second are ${SPEECH_TEXT(1)} and ${SPEECH_SCORE(1)}.\n"
00067 "The first argument is the sound file and the second is the timeout. Note the timeout will only start once the sound file has stopped playing.\n";
00068
00069 static char *speechdeactivategrammar_descrip =
00070 "SpeechDeactivateGrammar(Grammar Name)\n"
00071 "This deactivates the specified grammar so that it is no longer recognized. The only argument is the grammar name to deactivate.\n";
00072
00073 static char *speechprocessingsound_descrip =
00074 "SpeechProcessingSound(Sound File)\n"
00075 "This changes the processing sound that SpeechBackground plays back when the speech recognition engine is processing and working to get results.\n"
00076 "It takes the sound file as the only argument.\n";
00077
00078 static char *speechdestroy_descrip =
00079 "SpeechDestroy()\n"
00080 "This destroys the information used by all the other speech recognition applications.\n"
00081 "If you call this application but end up wanting to recognize more speech, you must call SpeechCreate\n"
00082 "again before calling any other application. It takes no arguments.\n";
00083
00084 static char *speechload_descrip =
00085 "SpeechLoadGrammar(Grammar Name|Path)\n"
00086 "Load a grammar only on the channel, not globally.\n"
00087 "It takes the grammar name as first argument and path as second.\n";
00088
00089 static char *speechunload_descrip =
00090 "SpeechUnloadGrammar(Grammar Name)\n"
00091 "Unload a grammar. It takes the grammar name as the only argument.\n";
00092
00093
00094 static void destroy_callback(void *data)
00095 {
00096 struct ast_speech *speech = (struct ast_speech*)data;
00097
00098 if (speech == NULL) {
00099 return;
00100 }
00101
00102
00103 ast_speech_destroy(speech);
00104
00105 return;
00106 }
00107
00108
00109 static const struct ast_datastore_info speech_datastore = {
00110 .type = "speech",
00111 .destroy = destroy_callback
00112 };
00113
00114
00115 static struct ast_speech *find_speech(struct ast_channel *chan)
00116 {
00117 struct ast_speech *speech = NULL;
00118 struct ast_datastore *datastore = NULL;
00119
00120 datastore = ast_channel_datastore_find(chan, &speech_datastore, NULL);
00121 if (datastore == NULL) {
00122 return NULL;
00123 }
00124 speech = datastore->data;
00125
00126 return speech;
00127 }
00128
00129
00130 static struct ast_speech_result *find_result(struct ast_speech_result *results, char *result_num)
00131 {
00132 struct ast_speech_result *result = results;
00133 char *tmp = NULL;
00134 int nbest_num = 0, wanted_num = 0, i = 0;
00135
00136 if (!result)
00137 return NULL;
00138
00139 if ((tmp = strchr(result_num, '/'))) {
00140 *tmp++ = '\0';
00141 nbest_num = atoi(result_num);
00142 wanted_num = atoi(tmp);
00143 } else {
00144 wanted_num = atoi(result_num);
00145 }
00146
00147 do {
00148 if (result->nbest_num != nbest_num)
00149 continue;
00150 if (i == wanted_num)
00151 break;
00152 i++;
00153 } while ((result = result->next));
00154
00155 return result;
00156 }
00157
00158
00159 static int speech_score(struct ast_channel *chan, char *cmd, char *data,
00160 char *buf, size_t len)
00161 {
00162 struct ast_speech_result *result = NULL;
00163 struct ast_speech *speech = find_speech(chan);
00164 char tmp[128] = "";
00165
00166 if (data == NULL || speech == NULL || !(result = find_result(speech->results, data)))
00167 return -1;
00168
00169 snprintf(tmp, sizeof(tmp), "%d", result->score);
00170
00171 ast_copy_string(buf, tmp, len);
00172
00173 return 0;
00174 }
00175
00176 static struct ast_custom_function speech_score_function = {
00177 .name = "SPEECH_SCORE",
00178 .synopsis = "Gets the confidence score of a result.",
00179 .syntax = "SPEECH_SCORE([nbest number/]result number)",
00180 .desc =
00181 "Gets the confidence score of a result.\n",
00182 .read = speech_score,
00183 .write = NULL,
00184 };
00185
00186
00187 static int speech_text(struct ast_channel *chan, char *cmd, char *data,
00188 char *buf, size_t len)
00189 {
00190 struct ast_speech_result *result = NULL;
00191 struct ast_speech *speech = find_speech(chan);
00192
00193 if (data == NULL || speech == NULL || !(result = find_result(speech->results, data)))
00194 return -1;
00195
00196 if (result->text != NULL)
00197 ast_copy_string(buf, result->text, len);
00198
00199 return 0;
00200 }
00201
00202 static struct ast_custom_function speech_text_function = {
00203 .name = "SPEECH_TEXT",
00204 .synopsis = "Gets the recognized text of a result.",
00205 .syntax = "SPEECH_TEXT([nbest number/]result number)",
00206 .desc =
00207 "Gets the recognized text of a result.\n",
00208 .read = speech_text,
00209 .write = NULL,
00210 };
00211
00212
00213 static int speech_grammar(struct ast_channel *chan, char *cmd, char *data,
00214 char *buf, size_t len)
00215 {
00216 struct ast_speech_result *result = NULL;
00217 struct ast_speech *speech = find_speech(chan);
00218
00219 if (data == NULL || speech == NULL || !(result = find_result(speech->results, data)))
00220 return -1;
00221
00222 if (result->grammar != NULL)
00223 ast_copy_string(buf, result->grammar, len);
00224
00225 return 0;
00226 }
00227
00228 static struct ast_custom_function speech_grammar_function = {
00229 .name = "SPEECH_GRAMMAR",
00230 .synopsis = "Gets the matched grammar of a result if available.",
00231 .syntax = "SPEECH_GRAMMAR([nbest number/]result number)",
00232 .desc =
00233 "Gets the matched grammar of a result if available.\n",
00234 .read = speech_grammar,
00235 .write = NULL,
00236 };
00237
00238
00239 static int speech_engine_write(struct ast_channel *chan, char *cmd, char *data, const char *value)
00240 {
00241 struct ast_speech *speech = find_speech(chan);
00242
00243 if (data == NULL || speech == NULL)
00244 return -1;
00245
00246 ast_speech_change(speech, data, value);
00247
00248 return 0;
00249 }
00250
00251 static struct ast_custom_function speech_engine_function = {
00252 .name = "SPEECH_ENGINE",
00253 .synopsis = "Change a speech engine specific attribute.",
00254 .syntax = "SPEECH_ENGINE(name)=value",
00255 .desc =
00256 "Changes a speech engine specific attribute.\n",
00257 .read = NULL,
00258 .write = speech_engine_write,
00259 };
00260
00261
00262 static int speech_results_type_write(struct ast_channel *chan, char *cmd, char *data, const char *value)
00263 {
00264 struct ast_speech *speech = find_speech(chan);
00265
00266 if (data == NULL || speech == NULL)
00267 return -1;
00268
00269 if (!strcasecmp(value, "normal"))
00270 ast_speech_change_results_type(speech, AST_SPEECH_RESULTS_TYPE_NORMAL);
00271 else if (!strcasecmp(value, "nbest"))
00272 ast_speech_change_results_type(speech, AST_SPEECH_RESULTS_TYPE_NBEST);
00273
00274 return 0;
00275 }
00276
00277 static struct ast_custom_function speech_results_type_function = {
00278 .name = "SPEECH_RESULTS_TYPE",
00279 .synopsis = "Sets the type of results that will be returned.",
00280 .syntax = "SPEECH_RESULTS_TYPE()=results type",
00281 .desc =
00282 "Sets the type of results that will be returned. Valid options are normal or nbest.",
00283 .read = NULL,
00284 .write = speech_results_type_write,
00285 };
00286
00287
00288 static int speech_read(struct ast_channel *chan, char *cmd, char *data,
00289 char *buf, size_t len)
00290 {
00291 int results = 0;
00292 struct ast_speech_result *result = NULL;
00293 struct ast_speech *speech = find_speech(chan);
00294 char tmp[128] = "";
00295
00296
00297 if (!strcasecmp(data, "status")) {
00298 if (speech != NULL)
00299 ast_copy_string(buf, "1", len);
00300 else
00301 ast_copy_string(buf, "0", len);
00302 return 0;
00303 }
00304
00305
00306 if (speech == NULL) {
00307 return -1;
00308 }
00309
00310
00311 if (!strcasecmp(data, "spoke")) {
00312 if (ast_test_flag(speech, AST_SPEECH_SPOKE))
00313 ast_copy_string(buf, "1", len);
00314 else
00315 ast_copy_string(buf, "0", len);
00316 } else if (!strcasecmp(data, "results")) {
00317
00318 result = speech->results;
00319 while (result) {
00320 results++;
00321 result = result->next;
00322 }
00323 snprintf(tmp, sizeof(tmp), "%d", results);
00324 ast_copy_string(buf, tmp, len);
00325 }
00326
00327 return 0;
00328 }
00329
00330 static struct ast_custom_function speech_function = {
00331 .name = "SPEECH",
00332 .synopsis = "Gets information about speech recognition results.",
00333 .syntax = "SPEECH(argument)",
00334 .desc =
00335 "Gets information about speech recognition results.\n"
00336 "status: Returns 1 upon speech object existing, or 0 if not\n"
00337 "spoke: Returns 1 if spoker spoke, or 0 if not\n"
00338 "results: Returns number of results that were recognized\n",
00339 .read = speech_read,
00340 .write = NULL,
00341 };
00342
00343
00344
00345
00346 static int speech_create(struct ast_channel *chan, void *data)
00347 {
00348 struct ast_module_user *u = NULL;
00349 struct ast_speech *speech = NULL;
00350 struct ast_datastore *datastore = NULL;
00351
00352 u = ast_module_user_add(chan);
00353
00354
00355 speech = ast_speech_new(data, AST_FORMAT_SLINEAR);
00356 if (speech == NULL) {
00357
00358 pbx_builtin_setvar_helper(chan, "ERROR", "1");
00359 ast_module_user_remove(u);
00360 return 0;
00361 }
00362
00363 datastore = ast_channel_datastore_alloc(&speech_datastore, NULL);
00364 if (datastore == NULL) {
00365 ast_speech_destroy(speech);
00366 pbx_builtin_setvar_helper(chan, "ERROR", "1");
00367 ast_module_user_remove(u);
00368 return 0;
00369 }
00370 datastore->data = speech;
00371 ast_channel_datastore_add(chan, datastore);
00372
00373 ast_module_user_remove(u);
00374
00375 return 0;
00376 }
00377
00378
00379 static int speech_load(struct ast_channel *chan, void *data)
00380 {
00381 int res = 0, argc = 0;
00382 struct ast_module_user *u = NULL;
00383 struct ast_speech *speech = find_speech(chan);
00384 char *argv[2], *args = NULL, *name = NULL, *path = NULL;
00385
00386 args = ast_strdupa(data);
00387
00388 u = ast_module_user_add(chan);
00389
00390 if (speech == NULL) {
00391 ast_module_user_remove(u);
00392 return -1;
00393 }
00394
00395
00396 argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0]));
00397 if (argc != 2) {
00398 ast_module_user_remove(u);
00399 return -1;
00400 }
00401 name = argv[0];
00402 path = argv[1];
00403
00404
00405 res = ast_speech_grammar_load(speech, name, path);
00406
00407 ast_module_user_remove(u);
00408
00409 return res;
00410 }
00411
00412
00413 static int speech_unload(struct ast_channel *chan, void *data)
00414 {
00415 int res = 0;
00416 struct ast_module_user *u = NULL;
00417 struct ast_speech *speech = find_speech(chan);
00418
00419 u = ast_module_user_add(chan);
00420
00421 if (speech == NULL) {
00422 ast_module_user_remove(u);
00423 return -1;
00424 }
00425
00426
00427 res = ast_speech_grammar_unload(speech, data);
00428
00429 ast_module_user_remove(u);
00430
00431 return res;
00432 }
00433
00434
00435 static int speech_deactivate(struct ast_channel *chan, void *data)
00436 {
00437 int res = 0;
00438 struct ast_module_user *u = NULL;
00439 struct ast_speech *speech = find_speech(chan);
00440
00441 u = ast_module_user_add(chan);
00442
00443 if (speech == NULL) {
00444 ast_module_user_remove(u);
00445 return -1;
00446 }
00447
00448
00449 res = ast_speech_grammar_deactivate(speech, data);
00450
00451 ast_module_user_remove(u);
00452
00453 return res;
00454 }
00455
00456
00457 static int speech_activate(struct ast_channel *chan, void *data)
00458 {
00459 int res = 0;
00460 struct ast_module_user *u = NULL;
00461 struct ast_speech *speech = find_speech(chan);
00462
00463 u = ast_module_user_add(chan);
00464
00465 if (speech == NULL) {
00466 ast_module_user_remove(u);
00467 return -1;
00468 }
00469
00470
00471 res = ast_speech_grammar_activate(speech, data);
00472
00473 ast_module_user_remove(u);
00474
00475 return res;
00476 }
00477
00478
00479 static int speech_start(struct ast_channel *chan, void *data)
00480 {
00481 int res = 0;
00482 struct ast_module_user *u = NULL;
00483 struct ast_speech *speech = find_speech(chan);
00484
00485 u = ast_module_user_add(chan);
00486
00487 if (speech == NULL) {
00488 ast_module_user_remove(u);
00489 return -1;
00490 }
00491
00492 ast_speech_start(speech);
00493
00494 ast_module_user_remove(u);
00495
00496 return res;
00497 }
00498
00499
00500 static int speech_processing_sound(struct ast_channel *chan, void *data)
00501 {
00502 int res = 0;
00503 struct ast_module_user *u = NULL;
00504 struct ast_speech *speech = find_speech(chan);
00505
00506 u = ast_module_user_add(chan);
00507
00508 if (speech == NULL) {
00509 ast_module_user_remove(u);
00510 return -1;
00511 }
00512
00513 if (speech->processing_sound != NULL) {
00514 free(speech->processing_sound);
00515 speech->processing_sound = NULL;
00516 }
00517
00518 speech->processing_sound = strdup(data);
00519
00520 ast_module_user_remove(u);
00521
00522 return res;
00523 }
00524
00525
00526 static int speech_streamfile(struct ast_channel *chan, const char *filename, const char *preflang)
00527 {
00528 struct ast_filestream *fs = NULL;
00529
00530 if (!(fs = ast_openstream(chan, filename, preflang)))
00531 return -1;
00532
00533 if (ast_applystream(chan, fs))
00534 return -1;
00535
00536 ast_playstream(fs);
00537
00538 return 0;
00539 }
00540
00541
00542 static int speech_background(struct ast_channel *chan, void *data)
00543 {
00544 unsigned int timeout = 0;
00545 int res = 0, done = 0, argc = 0, started = 0, quieted = 0, max_dtmf_len = 0;
00546 struct ast_module_user *u = NULL;
00547 struct ast_speech *speech = find_speech(chan);
00548 struct ast_frame *f = NULL;
00549 int oldreadformat = AST_FORMAT_SLINEAR;
00550 char dtmf[AST_MAX_EXTENSION] = "";
00551 time_t start, current;
00552 struct ast_datastore *datastore = NULL;
00553 char *argv[2], *args = NULL, *filename_tmp = NULL, *filename = NULL, tmp[2] = "", dtmf_terminator = '#';
00554 const char *tmp2 = NULL;
00555
00556 args = ast_strdupa(data);
00557
00558 u = ast_module_user_add(chan);
00559
00560 if (speech == NULL) {
00561 ast_module_user_remove(u);
00562 return -1;
00563 }
00564
00565
00566 if (chan->_state != AST_STATE_UP && ast_answer(chan)) {
00567 ast_module_user_remove(u);
00568 return -1;
00569 }
00570
00571
00572 oldreadformat = chan->readformat;
00573
00574
00575 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
00576 ast_module_user_remove(u);
00577 return -1;
00578 }
00579
00580
00581 argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0]));
00582 if (argc > 0) {
00583
00584 filename_tmp = ast_strdupa(argv[0]);
00585 if (!ast_strlen_zero(argv[1])) {
00586 if ((timeout = atoi(argv[1])) == 0)
00587 timeout = -1;
00588 } else
00589 timeout = 0;
00590 }
00591
00592
00593 if ((tmp2 = pbx_builtin_getvar_helper(chan, "SPEECH_DTMF_MAXLEN")) && !ast_strlen_zero(tmp2))
00594 max_dtmf_len = atoi(tmp2);
00595
00596
00597 if ((tmp2 = pbx_builtin_getvar_helper(chan, "SPEECH_DTMF_TERMINATOR"))) {
00598 if (ast_strlen_zero(tmp2))
00599 dtmf_terminator = '\0';
00600 else
00601 dtmf_terminator = tmp2[0];
00602 }
00603
00604
00605 if (speech->state == AST_SPEECH_STATE_NOT_READY || speech->state == AST_SPEECH_STATE_DONE) {
00606 ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
00607 ast_speech_start(speech);
00608 }
00609
00610
00611 ast_stopstream(chan);
00612
00613
00614 while (done == 0) {
00615
00616 if (!quieted && (chan->streamid == -1 && chan->timingfunc == NULL) && (filename = strsep(&filename_tmp, "&"))) {
00617
00618 ast_stopstream(chan);
00619
00620 speech_streamfile(chan, filename, chan->language);
00621 }
00622
00623
00624 ast_sched_runq(chan->sched);
00625
00626
00627 res = ast_sched_wait(chan->sched);
00628 if (res < 0) {
00629 res = 1000;
00630 }
00631
00632
00633 if (ast_waitfor(chan, res) > 0) {
00634 f = ast_read(chan);
00635 if (f == NULL) {
00636
00637 done = 3;
00638 break;
00639 }
00640 }
00641
00642
00643 if ((!quieted || strlen(dtmf)) && started == 1) {
00644 time(¤t);
00645 if ((current-start) >= timeout) {
00646 done = 1;
00647 if (f)
00648 ast_frfree(f);
00649 break;
00650 }
00651 }
00652
00653
00654 ast_mutex_lock(&speech->lock);
00655 if (ast_test_flag(speech, AST_SPEECH_QUIET)) {
00656 if (chan->stream)
00657 ast_stopstream(chan);
00658 ast_clear_flag(speech, AST_SPEECH_QUIET);
00659 quieted = 1;
00660 }
00661
00662 switch (speech->state) {
00663 case AST_SPEECH_STATE_READY:
00664
00665 if (chan->streamid == -1 && chan->timingfunc == NULL)
00666 ast_stopstream(chan);
00667 if (!quieted && chan->stream == NULL && timeout && started == 0 && !filename_tmp) {
00668 if (timeout == -1) {
00669 done = 1;
00670 if (f)
00671 ast_frfree(f);
00672 break;
00673 }
00674 time(&start);
00675 started = 1;
00676 }
00677
00678 if (!strlen(dtmf) && f != NULL && f->frametype == AST_FRAME_VOICE) {
00679 ast_speech_write(speech, f->data, f->datalen);
00680 }
00681 break;
00682 case AST_SPEECH_STATE_WAIT:
00683
00684 if (!strlen(dtmf)) {
00685 if (chan->stream == NULL) {
00686 if (speech->processing_sound != NULL) {
00687 if (strlen(speech->processing_sound) > 0 && strcasecmp(speech->processing_sound,"none")) {
00688 speech_streamfile(chan, speech->processing_sound, chan->language);
00689 }
00690 }
00691 } else if (chan->streamid == -1 && chan->timingfunc == NULL) {
00692 ast_stopstream(chan);
00693 if (speech->processing_sound != NULL) {
00694 if (strlen(speech->processing_sound) > 0 && strcasecmp(speech->processing_sound,"none")) {
00695 speech_streamfile(chan, speech->processing_sound, chan->language);
00696 }
00697 }
00698 }
00699 }
00700 break;
00701 case AST_SPEECH_STATE_DONE:
00702
00703 ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
00704 if (!strlen(dtmf)) {
00705
00706 speech->results = ast_speech_results_get(speech);
00707
00708 done = 1;
00709
00710 if (chan->stream != NULL) {
00711 ast_stopstream(chan);
00712 }
00713 }
00714 break;
00715 default:
00716 break;
00717 }
00718 ast_mutex_unlock(&speech->lock);
00719
00720
00721 if (f != NULL) {
00722
00723 switch (f->frametype) {
00724 case AST_FRAME_DTMF:
00725 if (dtmf_terminator != '\0' && f->subclass == dtmf_terminator) {
00726 done = 1;
00727 } else {
00728 if (chan->stream != NULL) {
00729 ast_stopstream(chan);
00730 }
00731 if (!started) {
00732
00733 timeout = (chan->pbx && chan->pbx->dtimeout) ? chan->pbx->dtimeout : 5;
00734 started = 1;
00735 }
00736 time(&start);
00737 snprintf(tmp, sizeof(tmp), "%c", f->subclass);
00738 strncat(dtmf, tmp, sizeof(dtmf));
00739
00740 if (max_dtmf_len && strlen(dtmf) == max_dtmf_len)
00741 done = 1;
00742 }
00743 break;
00744 case AST_FRAME_CONTROL:
00745 switch (f->subclass) {
00746 case AST_CONTROL_HANGUP:
00747
00748 done = 3;
00749 default:
00750 break;
00751 }
00752 default:
00753 break;
00754 }
00755 ast_frfree(f);
00756 f = NULL;
00757 }
00758 }
00759
00760 if (strlen(dtmf)) {
00761
00762 speech->results = ast_calloc(1, sizeof(*speech->results));
00763 if (speech->results != NULL) {
00764 ast_speech_dtmf(speech, dtmf);
00765 speech->results->score = 1000;
00766 speech->results->text = strdup(dtmf);
00767 speech->results->grammar = strdup("dtmf");
00768 }
00769 }
00770
00771
00772 if (done == 3) {
00773
00774 ast_speech_destroy(speech);
00775 datastore = ast_channel_datastore_find(chan, &speech_datastore, NULL);
00776 if (datastore != NULL) {
00777 ast_channel_datastore_remove(chan, datastore);
00778 }
00779 } else {
00780
00781 ast_set_read_format(chan, oldreadformat);
00782 }
00783
00784 ast_module_user_remove(u);
00785
00786 return 0;
00787 }
00788
00789
00790
00791 static int speech_destroy(struct ast_channel *chan, void *data)
00792 {
00793 int res = 0;
00794 struct ast_module_user *u = NULL;
00795 struct ast_speech *speech = find_speech(chan);
00796 struct ast_datastore *datastore = NULL;
00797
00798 u = ast_module_user_add(chan);
00799
00800 if (speech == NULL) {
00801 ast_module_user_remove(u);
00802 return -1;
00803 }
00804
00805
00806 ast_speech_destroy(speech);
00807
00808 datastore = ast_channel_datastore_find(chan, &speech_datastore, NULL);
00809 if (datastore != NULL) {
00810 ast_channel_datastore_remove(chan, datastore);
00811 }
00812
00813 ast_module_user_remove(u);
00814
00815 return res;
00816 }
00817
00818 static int unload_module(void)
00819 {
00820 int res = 0;
00821
00822 res = ast_unregister_application("SpeechCreate");
00823 res |= ast_unregister_application("SpeechLoadGrammar");
00824 res |= ast_unregister_application("SpeechUnloadGrammar");
00825 res |= ast_unregister_application("SpeechActivateGrammar");
00826 res |= ast_unregister_application("SpeechDeactivateGrammar");
00827 res |= ast_unregister_application("SpeechStart");
00828 res |= ast_unregister_application("SpeechBackground");
00829 res |= ast_unregister_application("SpeechDestroy");
00830 res |= ast_unregister_application("SpeechProcessingSound");
00831 res |= ast_custom_function_unregister(&speech_function);
00832 res |= ast_custom_function_unregister(&speech_score_function);
00833 res |= ast_custom_function_unregister(&speech_text_function);
00834 res |= ast_custom_function_unregister(&speech_grammar_function);
00835 res |= ast_custom_function_unregister(&speech_engine_function);
00836 res |= ast_custom_function_unregister(&speech_results_type_function);
00837
00838 ast_module_user_hangup_all();
00839
00840 return res;
00841 }
00842
00843 static int load_module(void)
00844 {
00845 int res = 0;
00846
00847 res = ast_register_application("SpeechCreate", speech_create, "Create a Speech Structure", speechcreate_descrip);
00848 res |= ast_register_application("SpeechLoadGrammar", speech_load, "Load a Grammar", speechload_descrip);
00849 res |= ast_register_application("SpeechUnloadGrammar", speech_unload, "Unload a Grammar", speechunload_descrip);
00850 res |= ast_register_application("SpeechActivateGrammar", speech_activate, "Activate a Grammar", speechactivategrammar_descrip);
00851 res |= ast_register_application("SpeechDeactivateGrammar", speech_deactivate, "Deactivate a Grammar", speechdeactivategrammar_descrip);
00852 res |= ast_register_application("SpeechStart", speech_start, "Start recognizing voice in the audio stream", speechstart_descrip);
00853 res |= ast_register_application("SpeechBackground", speech_background, "Play a sound file and wait for speech to be recognized", speechbackground_descrip);
00854 res |= ast_register_application("SpeechDestroy", speech_destroy, "End speech recognition", speechdestroy_descrip);
00855 res |= ast_register_application("SpeechProcessingSound", speech_processing_sound, "Change background processing sound", speechprocessingsound_descrip);
00856 res |= ast_custom_function_register(&speech_function);
00857 res |= ast_custom_function_register(&speech_score_function);
00858 res |= ast_custom_function_register(&speech_text_function);
00859 res |= ast_custom_function_register(&speech_grammar_function);
00860 res |= ast_custom_function_register(&speech_engine_function);
00861 res |= ast_custom_function_register(&speech_results_type_function);
00862
00863 return res;
00864 }
00865
00866 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Dialplan Speech Applications");