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: 264334 $");
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 } else {
00199 buf[0] = '\0';
00200 }
00201
00202 return 0;
00203 }
00204
00205 static struct ast_custom_function speech_text_function = {
00206 .name = "SPEECH_TEXT",
00207 .synopsis = "Gets the recognized text of a result.",
00208 .syntax = "SPEECH_TEXT([nbest number/]result number)",
00209 .desc =
00210 "Gets the recognized text of a result.\n",
00211 .read = speech_text,
00212 .write = NULL,
00213 };
00214
00215
00216 static int speech_grammar(struct ast_channel *chan, char *cmd, char *data,
00217 char *buf, size_t len)
00218 {
00219 struct ast_speech_result *result = NULL;
00220 struct ast_speech *speech = find_speech(chan);
00221
00222 if (data == NULL || speech == NULL || !(result = find_result(speech->results, data)))
00223 return -1;
00224
00225 if (result->grammar != NULL) {
00226 ast_copy_string(buf, result->grammar, len);
00227 } else {
00228 buf[0] = '\0';
00229 }
00230
00231 return 0;
00232 }
00233
00234 static struct ast_custom_function speech_grammar_function = {
00235 .name = "SPEECH_GRAMMAR",
00236 .synopsis = "Gets the matched grammar of a result if available.",
00237 .syntax = "SPEECH_GRAMMAR([nbest number/]result number)",
00238 .desc =
00239 "Gets the matched grammar of a result if available.\n",
00240 .read = speech_grammar,
00241 .write = NULL,
00242 };
00243
00244
00245 static int speech_engine_write(struct ast_channel *chan, char *cmd, char *data, const char *value)
00246 {
00247 struct ast_speech *speech = find_speech(chan);
00248
00249 if (data == NULL || speech == NULL)
00250 return -1;
00251
00252 ast_speech_change(speech, data, value);
00253
00254 return 0;
00255 }
00256
00257 static struct ast_custom_function speech_engine_function = {
00258 .name = "SPEECH_ENGINE",
00259 .synopsis = "Change a speech engine specific attribute.",
00260 .syntax = "SPEECH_ENGINE(name)=value",
00261 .desc =
00262 "Changes a speech engine specific attribute.\n",
00263 .read = NULL,
00264 .write = speech_engine_write,
00265 };
00266
00267
00268 static int speech_results_type_write(struct ast_channel *chan, char *cmd, char *data, const char *value)
00269 {
00270 struct ast_speech *speech = find_speech(chan);
00271
00272 if (data == NULL || speech == NULL)
00273 return -1;
00274
00275 if (!strcasecmp(value, "normal"))
00276 ast_speech_change_results_type(speech, AST_SPEECH_RESULTS_TYPE_NORMAL);
00277 else if (!strcasecmp(value, "nbest"))
00278 ast_speech_change_results_type(speech, AST_SPEECH_RESULTS_TYPE_NBEST);
00279
00280 return 0;
00281 }
00282
00283 static struct ast_custom_function speech_results_type_function = {
00284 .name = "SPEECH_RESULTS_TYPE",
00285 .synopsis = "Sets the type of results that will be returned.",
00286 .syntax = "SPEECH_RESULTS_TYPE()=results type",
00287 .desc =
00288 "Sets the type of results that will be returned. Valid options are normal or nbest.",
00289 .read = NULL,
00290 .write = speech_results_type_write,
00291 };
00292
00293
00294 static int speech_read(struct ast_channel *chan, char *cmd, char *data,
00295 char *buf, size_t len)
00296 {
00297 int results = 0;
00298 struct ast_speech_result *result = NULL;
00299 struct ast_speech *speech = find_speech(chan);
00300 char tmp[128] = "";
00301
00302
00303 if (!strcasecmp(data, "status")) {
00304 if (speech != NULL)
00305 ast_copy_string(buf, "1", len);
00306 else
00307 ast_copy_string(buf, "0", len);
00308 return 0;
00309 }
00310
00311
00312 if (speech == NULL) {
00313 return -1;
00314 }
00315
00316
00317 if (!strcasecmp(data, "spoke")) {
00318 if (ast_test_flag(speech, AST_SPEECH_SPOKE))
00319 ast_copy_string(buf, "1", len);
00320 else
00321 ast_copy_string(buf, "0", len);
00322 } else if (!strcasecmp(data, "results")) {
00323
00324 result = speech->results;
00325 while (result) {
00326 results++;
00327 result = result->next;
00328 }
00329 snprintf(tmp, sizeof(tmp), "%d", results);
00330 ast_copy_string(buf, tmp, len);
00331 } else {
00332 buf[0] = '\0';
00333 }
00334
00335 return 0;
00336 }
00337
00338 static struct ast_custom_function speech_function = {
00339 .name = "SPEECH",
00340 .synopsis = "Gets information about speech recognition results.",
00341 .syntax = "SPEECH(argument)",
00342 .desc =
00343 "Gets information about speech recognition results.\n"
00344 "status: Returns 1 upon speech object existing, or 0 if not\n"
00345 "spoke: Returns 1 if spoker spoke, or 0 if not\n"
00346 "results: Returns number of results that were recognized\n",
00347 .read = speech_read,
00348 .write = NULL,
00349 };
00350
00351
00352
00353
00354 static int speech_create(struct ast_channel *chan, void *data)
00355 {
00356 struct ast_module_user *u = NULL;
00357 struct ast_speech *speech = NULL;
00358 struct ast_datastore *datastore = NULL;
00359
00360 u = ast_module_user_add(chan);
00361
00362
00363 speech = ast_speech_new(data, AST_FORMAT_SLINEAR);
00364 if (speech == NULL) {
00365
00366 pbx_builtin_setvar_helper(chan, "ERROR", "1");
00367 ast_module_user_remove(u);
00368 return 0;
00369 }
00370
00371 datastore = ast_channel_datastore_alloc(&speech_datastore, NULL);
00372 if (datastore == NULL) {
00373 ast_speech_destroy(speech);
00374 pbx_builtin_setvar_helper(chan, "ERROR", "1");
00375 ast_module_user_remove(u);
00376 return 0;
00377 }
00378 datastore->data = speech;
00379 ast_channel_datastore_add(chan, datastore);
00380
00381 pbx_builtin_setvar_helper(chan, "ERROR", NULL);
00382
00383 ast_module_user_remove(u);
00384
00385 return 0;
00386 }
00387
00388
00389 static int speech_load(struct ast_channel *chan, void *data)
00390 {
00391 int res = 0, argc = 0;
00392 struct ast_module_user *u = NULL;
00393 struct ast_speech *speech = find_speech(chan);
00394 char *argv[2], *args = NULL, *name = NULL, *path = NULL;
00395
00396 args = ast_strdupa(data);
00397
00398 u = ast_module_user_add(chan);
00399
00400 if (speech == NULL) {
00401 ast_module_user_remove(u);
00402 return -1;
00403 }
00404
00405
00406 argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0]));
00407 if (argc != 2) {
00408 ast_module_user_remove(u);
00409 return -1;
00410 }
00411 name = argv[0];
00412 path = argv[1];
00413
00414
00415 res = ast_speech_grammar_load(speech, name, path);
00416
00417 ast_module_user_remove(u);
00418
00419 return res;
00420 }
00421
00422
00423 static int speech_unload(struct ast_channel *chan, void *data)
00424 {
00425 int res = 0;
00426 struct ast_module_user *u = NULL;
00427 struct ast_speech *speech = find_speech(chan);
00428
00429 u = ast_module_user_add(chan);
00430
00431 if (speech == NULL) {
00432 ast_module_user_remove(u);
00433 return -1;
00434 }
00435
00436
00437 res = ast_speech_grammar_unload(speech, data);
00438
00439 ast_module_user_remove(u);
00440
00441 return res;
00442 }
00443
00444
00445 static int speech_deactivate(struct ast_channel *chan, void *data)
00446 {
00447 int res = 0;
00448 struct ast_module_user *u = NULL;
00449 struct ast_speech *speech = find_speech(chan);
00450
00451 u = ast_module_user_add(chan);
00452
00453 if (speech == NULL) {
00454 ast_module_user_remove(u);
00455 return -1;
00456 }
00457
00458
00459 res = ast_speech_grammar_deactivate(speech, data);
00460
00461 ast_module_user_remove(u);
00462
00463 return res;
00464 }
00465
00466
00467 static int speech_activate(struct ast_channel *chan, void *data)
00468 {
00469 int res = 0;
00470 struct ast_module_user *u = NULL;
00471 struct ast_speech *speech = find_speech(chan);
00472
00473 u = ast_module_user_add(chan);
00474
00475 if (speech == NULL) {
00476 ast_module_user_remove(u);
00477 return -1;
00478 }
00479
00480
00481 res = ast_speech_grammar_activate(speech, data);
00482
00483 ast_module_user_remove(u);
00484
00485 return res;
00486 }
00487
00488
00489 static int speech_start(struct ast_channel *chan, void *data)
00490 {
00491 int res = 0;
00492 struct ast_module_user *u = NULL;
00493 struct ast_speech *speech = find_speech(chan);
00494
00495 u = ast_module_user_add(chan);
00496
00497 if (speech == NULL) {
00498 ast_module_user_remove(u);
00499 return -1;
00500 }
00501
00502 ast_speech_start(speech);
00503
00504 ast_module_user_remove(u);
00505
00506 return res;
00507 }
00508
00509
00510 static int speech_processing_sound(struct ast_channel *chan, void *data)
00511 {
00512 int res = 0;
00513 struct ast_module_user *u = NULL;
00514 struct ast_speech *speech = find_speech(chan);
00515
00516 u = ast_module_user_add(chan);
00517
00518 if (speech == NULL) {
00519 ast_module_user_remove(u);
00520 return -1;
00521 }
00522
00523 if (speech->processing_sound != NULL) {
00524 free(speech->processing_sound);
00525 speech->processing_sound = NULL;
00526 }
00527
00528 speech->processing_sound = strdup(data);
00529
00530 ast_module_user_remove(u);
00531
00532 return res;
00533 }
00534
00535
00536 static int speech_streamfile(struct ast_channel *chan, const char *filename, const char *preflang)
00537 {
00538 struct ast_filestream *fs = NULL;
00539
00540 if (!(fs = ast_openstream(chan, filename, preflang)))
00541 return -1;
00542
00543 if (ast_applystream(chan, fs))
00544 return -1;
00545
00546 ast_playstream(fs);
00547
00548 return 0;
00549 }
00550
00551
00552 static int speech_background(struct ast_channel *chan, void *data)
00553 {
00554 unsigned int timeout = 0;
00555 int res = 0, done = 0, argc = 0, started = 0, quieted = 0, max_dtmf_len = 0;
00556 struct ast_module_user *u = NULL;
00557 struct ast_speech *speech = find_speech(chan);
00558 struct ast_frame *f = NULL;
00559 int oldreadformat = AST_FORMAT_SLINEAR;
00560 char dtmf[AST_MAX_EXTENSION] = "";
00561 time_t start, current;
00562 struct ast_datastore *datastore = NULL;
00563 char *argv[2], *args = NULL, *filename_tmp = NULL, *filename = NULL, tmp[2] = "", dtmf_terminator = '#';
00564 const char *tmp2 = NULL;
00565
00566 args = ast_strdupa(data);
00567
00568 u = ast_module_user_add(chan);
00569
00570 if (speech == NULL) {
00571 ast_module_user_remove(u);
00572 return -1;
00573 }
00574
00575
00576 if (chan->_state != AST_STATE_UP && ast_answer(chan)) {
00577 ast_module_user_remove(u);
00578 return -1;
00579 }
00580
00581
00582 oldreadformat = chan->readformat;
00583
00584
00585 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
00586 ast_module_user_remove(u);
00587 return -1;
00588 }
00589
00590
00591 argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0]));
00592 if (argc > 0) {
00593
00594 filename_tmp = ast_strdupa(argv[0]);
00595 if (!ast_strlen_zero(argv[1])) {
00596 if ((timeout = atoi(argv[1])) == 0)
00597 timeout = -1;
00598 } else
00599 timeout = 0;
00600 }
00601
00602
00603 if ((tmp2 = pbx_builtin_getvar_helper(chan, "SPEECH_DTMF_MAXLEN")) && !ast_strlen_zero(tmp2))
00604 max_dtmf_len = atoi(tmp2);
00605
00606
00607 if ((tmp2 = pbx_builtin_getvar_helper(chan, "SPEECH_DTMF_TERMINATOR"))) {
00608 if (ast_strlen_zero(tmp2))
00609 dtmf_terminator = '\0';
00610 else
00611 dtmf_terminator = tmp2[0];
00612 }
00613
00614
00615 if (speech->state == AST_SPEECH_STATE_NOT_READY || speech->state == AST_SPEECH_STATE_DONE) {
00616 ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
00617 ast_speech_start(speech);
00618 }
00619
00620
00621 ast_stopstream(chan);
00622
00623
00624 while (done == 0) {
00625
00626 if (!quieted && (chan->streamid == -1 && chan->timingfunc == NULL) && (filename = strsep(&filename_tmp, "&"))) {
00627
00628 ast_stopstream(chan);
00629
00630 speech_streamfile(chan, filename, chan->language);
00631 }
00632
00633
00634 ast_sched_runq(chan->sched);
00635
00636
00637 res = ast_sched_wait(chan->sched);
00638 if (res < 0) {
00639 res = 1000;
00640 }
00641
00642
00643 if (ast_waitfor(chan, res) > 0) {
00644 f = ast_read(chan);
00645 if (f == NULL) {
00646
00647 done = 3;
00648 break;
00649 }
00650 }
00651
00652
00653 if ((!quieted || strlen(dtmf)) && started == 1) {
00654 time(¤t);
00655 if ((current-start) >= timeout) {
00656 done = 1;
00657 if (f)
00658 ast_frfree(f);
00659 break;
00660 }
00661 }
00662
00663
00664 ast_mutex_lock(&speech->lock);
00665 if (ast_test_flag(speech, AST_SPEECH_QUIET)) {
00666 if (chan->stream)
00667 ast_stopstream(chan);
00668 ast_clear_flag(speech, AST_SPEECH_QUIET);
00669 quieted = 1;
00670 }
00671
00672 switch (speech->state) {
00673 case AST_SPEECH_STATE_READY:
00674
00675 if (chan->streamid == -1 && chan->timingfunc == NULL)
00676 ast_stopstream(chan);
00677 if (!quieted && chan->stream == NULL && timeout && started == 0 && !filename_tmp) {
00678 if (timeout == -1) {
00679 done = 1;
00680 if (f)
00681 ast_frfree(f);
00682 break;
00683 }
00684 time(&start);
00685 started = 1;
00686 }
00687
00688 if (!strlen(dtmf) && f != NULL && f->frametype == AST_FRAME_VOICE) {
00689 ast_speech_write(speech, f->data, f->datalen);
00690 }
00691 break;
00692 case AST_SPEECH_STATE_WAIT:
00693
00694 if (!strlen(dtmf)) {
00695 if (chan->stream == NULL) {
00696 if (speech->processing_sound != NULL) {
00697 if (strlen(speech->processing_sound) > 0 && strcasecmp(speech->processing_sound,"none")) {
00698 speech_streamfile(chan, speech->processing_sound, chan->language);
00699 }
00700 }
00701 } else if (chan->streamid == -1 && chan->timingfunc == NULL) {
00702 ast_stopstream(chan);
00703 if (speech->processing_sound != NULL) {
00704 if (strlen(speech->processing_sound) > 0 && strcasecmp(speech->processing_sound,"none")) {
00705 speech_streamfile(chan, speech->processing_sound, chan->language);
00706 }
00707 }
00708 }
00709 }
00710 break;
00711 case AST_SPEECH_STATE_DONE:
00712
00713 ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
00714 if (!strlen(dtmf)) {
00715
00716 speech->results = ast_speech_results_get(speech);
00717
00718 done = 1;
00719
00720 if (chan->stream != NULL) {
00721 ast_stopstream(chan);
00722 }
00723 }
00724 break;
00725 default:
00726 break;
00727 }
00728 ast_mutex_unlock(&speech->lock);
00729
00730
00731 if (f != NULL) {
00732
00733 switch (f->frametype) {
00734 case AST_FRAME_DTMF:
00735 if (dtmf_terminator != '\0' && f->subclass == dtmf_terminator) {
00736 done = 1;
00737 } else {
00738 quieted = 1;
00739 if (chan->stream != NULL) {
00740 ast_stopstream(chan);
00741 }
00742 if (!started) {
00743
00744 timeout = (chan->pbx && chan->pbx->dtimeout) ? chan->pbx->dtimeout : 5;
00745 started = 1;
00746 }
00747 time(&start);
00748 snprintf(tmp, sizeof(tmp), "%c", f->subclass);
00749 strncat(dtmf, tmp, sizeof(dtmf) - strlen(dtmf) - 1);
00750
00751 if (max_dtmf_len && strlen(dtmf) == max_dtmf_len)
00752 done = 1;
00753 }
00754 break;
00755 case AST_FRAME_CONTROL:
00756 switch (f->subclass) {
00757 case AST_CONTROL_HANGUP:
00758
00759 done = 3;
00760 default:
00761 break;
00762 }
00763 default:
00764 break;
00765 }
00766 ast_frfree(f);
00767 f = NULL;
00768 }
00769 }
00770
00771 if (strlen(dtmf)) {
00772
00773 speech->results = ast_calloc(1, sizeof(*speech->results));
00774 if (speech->results != NULL) {
00775 ast_speech_dtmf(speech, dtmf);
00776 speech->results->score = 1000;
00777 speech->results->text = strdup(dtmf);
00778 speech->results->grammar = strdup("dtmf");
00779 }
00780 ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
00781 }
00782
00783
00784 if (done == 3) {
00785
00786 ast_speech_destroy(speech);
00787 datastore = ast_channel_datastore_find(chan, &speech_datastore, NULL);
00788 if (datastore != NULL) {
00789 ast_channel_datastore_remove(chan, datastore);
00790 }
00791 } else {
00792
00793 ast_set_read_format(chan, oldreadformat);
00794 }
00795
00796 ast_module_user_remove(u);
00797
00798 return 0;
00799 }
00800
00801
00802
00803 static int speech_destroy(struct ast_channel *chan, void *data)
00804 {
00805 int res = 0;
00806 struct ast_module_user *u = NULL;
00807 struct ast_speech *speech = find_speech(chan);
00808 struct ast_datastore *datastore = NULL;
00809
00810 u = ast_module_user_add(chan);
00811
00812 if (speech == NULL) {
00813 ast_module_user_remove(u);
00814 return -1;
00815 }
00816
00817
00818 ast_speech_destroy(speech);
00819
00820 datastore = ast_channel_datastore_find(chan, &speech_datastore, NULL);
00821 if (datastore != NULL) {
00822 ast_channel_datastore_remove(chan, datastore);
00823 }
00824
00825 ast_module_user_remove(u);
00826
00827 return res;
00828 }
00829
00830 static int unload_module(void)
00831 {
00832 int res = 0;
00833
00834 res = ast_unregister_application("SpeechCreate");
00835 res |= ast_unregister_application("SpeechLoadGrammar");
00836 res |= ast_unregister_application("SpeechUnloadGrammar");
00837 res |= ast_unregister_application("SpeechActivateGrammar");
00838 res |= ast_unregister_application("SpeechDeactivateGrammar");
00839 res |= ast_unregister_application("SpeechStart");
00840 res |= ast_unregister_application("SpeechBackground");
00841 res |= ast_unregister_application("SpeechDestroy");
00842 res |= ast_unregister_application("SpeechProcessingSound");
00843 res |= ast_custom_function_unregister(&speech_function);
00844 res |= ast_custom_function_unregister(&speech_score_function);
00845 res |= ast_custom_function_unregister(&speech_text_function);
00846 res |= ast_custom_function_unregister(&speech_grammar_function);
00847 res |= ast_custom_function_unregister(&speech_engine_function);
00848 res |= ast_custom_function_unregister(&speech_results_type_function);
00849
00850 ast_module_user_hangup_all();
00851
00852 return res;
00853 }
00854
00855 static int load_module(void)
00856 {
00857 int res = 0;
00858
00859 res = ast_register_application("SpeechCreate", speech_create, "Create a Speech Structure", speechcreate_descrip);
00860 res |= ast_register_application("SpeechLoadGrammar", speech_load, "Load a Grammar", speechload_descrip);
00861 res |= ast_register_application("SpeechUnloadGrammar", speech_unload, "Unload a Grammar", speechunload_descrip);
00862 res |= ast_register_application("SpeechActivateGrammar", speech_activate, "Activate a Grammar", speechactivategrammar_descrip);
00863 res |= ast_register_application("SpeechDeactivateGrammar", speech_deactivate, "Deactivate a Grammar", speechdeactivategrammar_descrip);
00864 res |= ast_register_application("SpeechStart", speech_start, "Start recognizing voice in the audio stream", speechstart_descrip);
00865 res |= ast_register_application("SpeechBackground", speech_background, "Play a sound file and wait for speech to be recognized", speechbackground_descrip);
00866 res |= ast_register_application("SpeechDestroy", speech_destroy, "End speech recognition", speechdestroy_descrip);
00867 res |= ast_register_application("SpeechProcessingSound", speech_processing_sound, "Change background processing sound", speechprocessingsound_descrip);
00868 res |= ast_custom_function_register(&speech_function);
00869 res |= ast_custom_function_register(&speech_score_function);
00870 res |= ast_custom_function_register(&speech_text_function);
00871 res |= ast_custom_function_register(&speech_grammar_function);
00872 res |= ast_custom_function_register(&speech_engine_function);
00873 res |= ast_custom_function_register(&speech_results_type_function);
00874
00875 return res;
00876 }
00877
00878 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Dialplan Speech Applications");