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
00029
00030
00031
00032 #include "asterisk.h"
00033
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 362815 $");
00035
00036 #include "asterisk/file.h"
00037 #include "asterisk/channel.h"
00038 #include "asterisk/pbx.h"
00039 #include "asterisk/module.h"
00040 #include "asterisk/lock.h"
00041 #include "asterisk/app.h"
00042 #include "asterisk/speech.h"
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262 static void destroy_callback(void *data)
00263 {
00264 struct ast_speech *speech = (struct ast_speech*)data;
00265
00266 if (speech == NULL) {
00267 return;
00268 }
00269
00270
00271 ast_speech_destroy(speech);
00272
00273 return;
00274 }
00275
00276
00277 static const struct ast_datastore_info speech_datastore = {
00278 .type = "speech",
00279 .destroy = destroy_callback
00280 };
00281
00282
00283 static struct ast_speech *find_speech(struct ast_channel *chan)
00284 {
00285 struct ast_speech *speech = NULL;
00286 struct ast_datastore *datastore = NULL;
00287
00288 datastore = ast_channel_datastore_find(chan, &speech_datastore, NULL);
00289 if (datastore == NULL) {
00290 return NULL;
00291 }
00292 speech = datastore->data;
00293
00294 return speech;
00295 }
00296
00297
00298 static struct ast_speech_result *find_result(struct ast_speech_result *results, char *result_num)
00299 {
00300 struct ast_speech_result *result = results;
00301 char *tmp = NULL;
00302 int nbest_num = 0, wanted_num = 0, i = 0;
00303
00304 if (!result) {
00305 return NULL;
00306 }
00307
00308 if ((tmp = strchr(result_num, '/'))) {
00309 *tmp++ = '\0';
00310 nbest_num = atoi(result_num);
00311 wanted_num = atoi(tmp);
00312 } else {
00313 wanted_num = atoi(result_num);
00314 }
00315
00316 do {
00317 if (result->nbest_num != nbest_num)
00318 continue;
00319 if (i == wanted_num)
00320 break;
00321 i++;
00322 } while ((result = AST_LIST_NEXT(result, list)));
00323
00324 return result;
00325 }
00326
00327
00328 static int speech_score(struct ast_channel *chan, const char *cmd, char *data,
00329 char *buf, size_t len)
00330 {
00331 struct ast_speech_result *result = NULL;
00332 struct ast_speech *speech = find_speech(chan);
00333 char tmp[128] = "";
00334
00335 if (data == NULL || speech == NULL || !(result = find_result(speech->results, data))) {
00336 return -1;
00337 }
00338
00339 snprintf(tmp, sizeof(tmp), "%d", result->score);
00340
00341 ast_copy_string(buf, tmp, len);
00342
00343 return 0;
00344 }
00345
00346 static struct ast_custom_function speech_score_function = {
00347 .name = "SPEECH_SCORE",
00348 .read = speech_score,
00349 .write = NULL,
00350 };
00351
00352
00353 static int speech_text(struct ast_channel *chan, const char *cmd, char *data,
00354 char *buf, size_t len)
00355 {
00356 struct ast_speech_result *result = NULL;
00357 struct ast_speech *speech = find_speech(chan);
00358
00359 if (data == NULL || speech == NULL || !(result = find_result(speech->results, data))) {
00360 return -1;
00361 }
00362
00363 if (result->text != NULL) {
00364 ast_copy_string(buf, result->text, len);
00365 } else {
00366 buf[0] = '\0';
00367 }
00368
00369 return 0;
00370 }
00371
00372 static struct ast_custom_function speech_text_function = {
00373 .name = "SPEECH_TEXT",
00374 .read = speech_text,
00375 .write = NULL,
00376 };
00377
00378
00379 static int speech_grammar(struct ast_channel *chan, const char *cmd, char *data,
00380 char *buf, size_t len)
00381 {
00382 struct ast_speech_result *result = NULL;
00383 struct ast_speech *speech = find_speech(chan);
00384
00385 if (data == NULL || speech == NULL || !(result = find_result(speech->results, data))) {
00386 return -1;
00387 }
00388
00389 if (result->grammar != NULL) {
00390 ast_copy_string(buf, result->grammar, len);
00391 } else {
00392 buf[0] = '\0';
00393 }
00394
00395 return 0;
00396 }
00397
00398 static struct ast_custom_function speech_grammar_function = {
00399 .name = "SPEECH_GRAMMAR",
00400 .read = speech_grammar,
00401 .write = NULL,
00402 };
00403
00404
00405 static int speech_engine_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
00406 {
00407 struct ast_speech *speech = find_speech(chan);
00408
00409 if (data == NULL || speech == NULL) {
00410 return -1;
00411 }
00412
00413 ast_speech_change(speech, data, value);
00414
00415 return 0;
00416 }
00417
00418 static struct ast_custom_function speech_engine_function = {
00419 .name = "SPEECH_ENGINE",
00420 .read = NULL,
00421 .write = speech_engine_write,
00422 };
00423
00424
00425 static int speech_results_type_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
00426 {
00427 struct ast_speech *speech = find_speech(chan);
00428
00429 if (data == NULL || speech == NULL)
00430 return -1;
00431
00432 if (!strcasecmp(value, "normal"))
00433 ast_speech_change_results_type(speech, AST_SPEECH_RESULTS_TYPE_NORMAL);
00434 else if (!strcasecmp(value, "nbest"))
00435 ast_speech_change_results_type(speech, AST_SPEECH_RESULTS_TYPE_NBEST);
00436
00437 return 0;
00438 }
00439
00440 static struct ast_custom_function speech_results_type_function = {
00441 .name = "SPEECH_RESULTS_TYPE",
00442 .read = NULL,
00443 .write = speech_results_type_write,
00444 };
00445
00446
00447 static int speech_read(struct ast_channel *chan, const char *cmd, char *data,
00448 char *buf, size_t len)
00449 {
00450 int results = 0;
00451 struct ast_speech_result *result = NULL;
00452 struct ast_speech *speech = find_speech(chan);
00453 char tmp[128] = "";
00454
00455
00456 if (!strcasecmp(data, "status")) {
00457 if (speech != NULL)
00458 ast_copy_string(buf, "1", len);
00459 else
00460 ast_copy_string(buf, "0", len);
00461 return 0;
00462 }
00463
00464
00465 if (speech == NULL) {
00466 return -1;
00467 }
00468
00469
00470 if (!strcasecmp(data, "spoke")) {
00471 if (ast_test_flag(speech, AST_SPEECH_SPOKE))
00472 ast_copy_string(buf, "1", len);
00473 else
00474 ast_copy_string(buf, "0", len);
00475 } else if (!strcasecmp(data, "results")) {
00476
00477 for (result = speech->results; result; result = AST_LIST_NEXT(result, list))
00478 results++;
00479 snprintf(tmp, sizeof(tmp), "%d", results);
00480 ast_copy_string(buf, tmp, len);
00481 } else {
00482 buf[0] = '\0';
00483 }
00484
00485 return 0;
00486 }
00487
00488 static struct ast_custom_function speech_function = {
00489 .name = "SPEECH",
00490 .read = speech_read,
00491 .write = NULL,
00492 };
00493
00494
00495
00496
00497 static int speech_create(struct ast_channel *chan, const char *data)
00498 {
00499 struct ast_speech *speech = NULL;
00500 struct ast_datastore *datastore = NULL;
00501
00502
00503 speech = ast_speech_new(data, chan->nativeformats);
00504 if (speech == NULL) {
00505
00506 pbx_builtin_setvar_helper(chan, "ERROR", "1");
00507 return 0;
00508 }
00509
00510 datastore = ast_datastore_alloc(&speech_datastore, NULL);
00511 if (datastore == NULL) {
00512 ast_speech_destroy(speech);
00513 pbx_builtin_setvar_helper(chan, "ERROR", "1");
00514 return 0;
00515 }
00516 pbx_builtin_setvar_helper(chan, "ERROR", NULL);
00517 datastore->data = speech;
00518 ast_channel_datastore_add(chan, datastore);
00519
00520 return 0;
00521 }
00522
00523
00524 static int speech_load(struct ast_channel *chan, const char *vdata)
00525 {
00526 int res = 0;
00527 struct ast_speech *speech = find_speech(chan);
00528 char *data;
00529 AST_DECLARE_APP_ARGS(args,
00530 AST_APP_ARG(grammar);
00531 AST_APP_ARG(path);
00532 );
00533
00534 data = ast_strdupa(vdata);
00535 AST_STANDARD_APP_ARGS(args, data);
00536
00537 if (speech == NULL)
00538 return -1;
00539
00540 if (args.argc != 2)
00541 return -1;
00542
00543
00544 res = ast_speech_grammar_load(speech, args.grammar, args.path);
00545
00546 return res;
00547 }
00548
00549
00550 static int speech_unload(struct ast_channel *chan, const char *data)
00551 {
00552 int res = 0;
00553 struct ast_speech *speech = find_speech(chan);
00554
00555 if (speech == NULL)
00556 return -1;
00557
00558
00559 res = ast_speech_grammar_unload(speech, data);
00560
00561 return res;
00562 }
00563
00564
00565 static int speech_deactivate(struct ast_channel *chan, const char *data)
00566 {
00567 int res = 0;
00568 struct ast_speech *speech = find_speech(chan);
00569
00570 if (speech == NULL)
00571 return -1;
00572
00573
00574 res = ast_speech_grammar_deactivate(speech, data);
00575
00576 return res;
00577 }
00578
00579
00580 static int speech_activate(struct ast_channel *chan, const char *data)
00581 {
00582 int res = 0;
00583 struct ast_speech *speech = find_speech(chan);
00584
00585 if (speech == NULL)
00586 return -1;
00587
00588
00589 res = ast_speech_grammar_activate(speech, data);
00590
00591 return res;
00592 }
00593
00594
00595 static int speech_start(struct ast_channel *chan, const char *data)
00596 {
00597 int res = 0;
00598 struct ast_speech *speech = find_speech(chan);
00599
00600 if (speech == NULL)
00601 return -1;
00602
00603 ast_speech_start(speech);
00604
00605 return res;
00606 }
00607
00608
00609 static int speech_processing_sound(struct ast_channel *chan, const char *data)
00610 {
00611 int res = 0;
00612 struct ast_speech *speech = find_speech(chan);
00613
00614 if (speech == NULL)
00615 return -1;
00616
00617 if (speech->processing_sound != NULL) {
00618 ast_free(speech->processing_sound);
00619 speech->processing_sound = NULL;
00620 }
00621
00622 speech->processing_sound = ast_strdup(data);
00623
00624 return res;
00625 }
00626
00627
00628 static int speech_streamfile(struct ast_channel *chan, const char *filename, const char *preflang)
00629 {
00630 struct ast_filestream *fs = NULL;
00631
00632 if (!(fs = ast_openstream(chan, filename, preflang)))
00633 return -1;
00634
00635 if (ast_applystream(chan, fs))
00636 return -1;
00637
00638 ast_playstream(fs);
00639
00640 return 0;
00641 }
00642
00643 enum {
00644 SB_OPT_NOANSWER = (1 << 0),
00645 };
00646
00647 AST_APP_OPTIONS(speech_background_options, BEGIN_OPTIONS
00648 AST_APP_OPTION('n', SB_OPT_NOANSWER),
00649 END_OPTIONS );
00650
00651
00652 static int speech_background(struct ast_channel *chan, const char *data)
00653 {
00654 unsigned int timeout = 0;
00655 int res = 0, done = 0, started = 0, quieted = 0, max_dtmf_len = 0;
00656 struct ast_speech *speech = find_speech(chan);
00657 struct ast_frame *f = NULL;
00658 int oldreadformat = AST_FORMAT_SLINEAR;
00659 char dtmf[AST_MAX_EXTENSION] = "";
00660 struct timeval start = { 0, 0 }, current;
00661 struct ast_datastore *datastore = NULL;
00662 char *parse, *filename_tmp = NULL, *filename = NULL, tmp[2] = "", dtmf_terminator = '#';
00663 const char *tmp2 = NULL;
00664 struct ast_flags options = { 0 };
00665 AST_DECLARE_APP_ARGS(args,
00666 AST_APP_ARG(soundfile);
00667 AST_APP_ARG(timeout);
00668 AST_APP_ARG(options);
00669 );
00670
00671 parse = ast_strdupa(data);
00672 AST_STANDARD_APP_ARGS(args, parse);
00673
00674 if (speech == NULL)
00675 return -1;
00676
00677 if (!ast_strlen_zero(args.options)) {
00678 char *options_buf = ast_strdupa(args.options);
00679 ast_app_parse_options(speech_background_options, &options, NULL, options_buf);
00680 }
00681
00682
00683 if (chan->_state != AST_STATE_UP && !ast_test_flag(&options, SB_OPT_NOANSWER)
00684 && ast_answer(chan)) {
00685 return -1;
00686 }
00687
00688
00689 oldreadformat = chan->readformat;
00690
00691
00692 if (ast_set_read_format(chan, speech->format))
00693 return -1;
00694
00695 if (!ast_strlen_zero(args.soundfile)) {
00696
00697 filename_tmp = ast_strdupa(args.soundfile);
00698 if (!ast_strlen_zero(args.timeout)) {
00699 if ((timeout = atof(args.timeout) * 1000.0) == 0)
00700 timeout = -1;
00701 } else
00702 timeout = 0;
00703 }
00704
00705
00706 ast_channel_lock(chan);
00707 if ((tmp2 = pbx_builtin_getvar_helper(chan, "SPEECH_DTMF_MAXLEN")) && !ast_strlen_zero(tmp2)) {
00708 max_dtmf_len = atoi(tmp2);
00709 }
00710
00711
00712 if ((tmp2 = pbx_builtin_getvar_helper(chan, "SPEECH_DTMF_TERMINATOR"))) {
00713 if (ast_strlen_zero(tmp2))
00714 dtmf_terminator = '\0';
00715 else
00716 dtmf_terminator = tmp2[0];
00717 }
00718 ast_channel_unlock(chan);
00719
00720
00721 if (speech->state == AST_SPEECH_STATE_NOT_READY || speech->state == AST_SPEECH_STATE_DONE) {
00722 ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
00723 ast_speech_start(speech);
00724 }
00725
00726
00727 ast_stopstream(chan);
00728
00729
00730 while (done == 0) {
00731
00732 if (!quieted && (chan->streamid == -1 && chan->timingfunc == NULL) && (filename = strsep(&filename_tmp, "&"))) {
00733
00734 ast_stopstream(chan);
00735
00736 speech_streamfile(chan, filename, chan->language);
00737 }
00738
00739
00740 ast_sched_runq(chan->sched);
00741
00742
00743 res = ast_sched_wait(chan->sched);
00744 if (res < 0)
00745 res = 1000;
00746
00747
00748 if (ast_waitfor(chan, res) > 0) {
00749 f = ast_read(chan);
00750 if (f == NULL) {
00751
00752 done = 3;
00753 break;
00754 }
00755 }
00756
00757
00758 if ((!quieted || strlen(dtmf)) && started == 1) {
00759 current = ast_tvnow();
00760 if ((ast_tvdiff_ms(current, start)) >= timeout) {
00761 done = 1;
00762 if (f)
00763 ast_frfree(f);
00764 break;
00765 }
00766 }
00767
00768
00769 ast_mutex_lock(&speech->lock);
00770 if (ast_test_flag(speech, AST_SPEECH_QUIET)) {
00771 if (chan->stream)
00772 ast_stopstream(chan);
00773 ast_clear_flag(speech, AST_SPEECH_QUIET);
00774 quieted = 1;
00775 }
00776
00777 switch (speech->state) {
00778 case AST_SPEECH_STATE_READY:
00779
00780 if (chan->streamid == -1 && chan->timingfunc == NULL)
00781 ast_stopstream(chan);
00782 if (!quieted && chan->stream == NULL && timeout && started == 0 && !filename_tmp) {
00783 if (timeout == -1) {
00784 done = 1;
00785 if (f)
00786 ast_frfree(f);
00787 break;
00788 }
00789 start = ast_tvnow();
00790 started = 1;
00791 }
00792
00793 if (!strlen(dtmf) && f != NULL && f->frametype == AST_FRAME_VOICE) {
00794 ast_speech_write(speech, f->data.ptr, f->datalen);
00795 }
00796 break;
00797 case AST_SPEECH_STATE_WAIT:
00798
00799 if (!strlen(dtmf)) {
00800 if (chan->stream == NULL) {
00801 if (speech->processing_sound != NULL) {
00802 if (strlen(speech->processing_sound) > 0 && strcasecmp(speech->processing_sound, "none")) {
00803 speech_streamfile(chan, speech->processing_sound, chan->language);
00804 }
00805 }
00806 } else if (chan->streamid == -1 && chan->timingfunc == NULL) {
00807 ast_stopstream(chan);
00808 if (speech->processing_sound != NULL) {
00809 if (strlen(speech->processing_sound) > 0 && strcasecmp(speech->processing_sound, "none")) {
00810 speech_streamfile(chan, speech->processing_sound, chan->language);
00811 }
00812 }
00813 }
00814 }
00815 break;
00816 case AST_SPEECH_STATE_DONE:
00817
00818 ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
00819 if (!strlen(dtmf)) {
00820
00821 speech->results = ast_speech_results_get(speech);
00822
00823 done = 1;
00824
00825 if (chan->stream != NULL) {
00826 ast_stopstream(chan);
00827 }
00828 }
00829 break;
00830 default:
00831 break;
00832 }
00833 ast_mutex_unlock(&speech->lock);
00834
00835
00836 if (f != NULL) {
00837
00838 switch (f->frametype) {
00839 case AST_FRAME_DTMF:
00840 if (dtmf_terminator != '\0' && f->subclass.integer == dtmf_terminator) {
00841 done = 1;
00842 } else {
00843 quieted = 1;
00844 if (chan->stream != NULL) {
00845 ast_stopstream(chan);
00846 }
00847 if (!started) {
00848
00849 timeout = (chan->pbx && chan->pbx->dtimeoutms) ? chan->pbx->dtimeoutms : 5000;
00850 started = 1;
00851 }
00852 start = ast_tvnow();
00853 snprintf(tmp, sizeof(tmp), "%c", f->subclass.integer);
00854 strncat(dtmf, tmp, sizeof(dtmf) - strlen(dtmf) - 1);
00855
00856 if (max_dtmf_len && strlen(dtmf) == max_dtmf_len)
00857 done = 1;
00858 }
00859 break;
00860 case AST_FRAME_CONTROL:
00861 switch (f->subclass.integer) {
00862 case AST_CONTROL_HANGUP:
00863
00864 done = 3;
00865 default:
00866 break;
00867 }
00868 default:
00869 break;
00870 }
00871 ast_frfree(f);
00872 f = NULL;
00873 }
00874 }
00875
00876 if (!ast_strlen_zero(dtmf)) {
00877
00878 speech->results = ast_calloc(1, sizeof(*speech->results));
00879 if (speech->results != NULL) {
00880 ast_speech_dtmf(speech, dtmf);
00881 speech->results->score = 1000;
00882 speech->results->text = ast_strdup(dtmf);
00883 speech->results->grammar = ast_strdup("dtmf");
00884 }
00885 ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
00886 }
00887
00888
00889 if (done == 3) {
00890
00891 ast_speech_destroy(speech);
00892 datastore = ast_channel_datastore_find(chan, &speech_datastore, NULL);
00893 if (datastore != NULL)
00894 ast_channel_datastore_remove(chan, datastore);
00895 } else {
00896
00897 ast_set_read_format(chan, oldreadformat);
00898 }
00899
00900 return 0;
00901 }
00902
00903
00904
00905 static int speech_destroy(struct ast_channel *chan, const char *data)
00906 {
00907 int res = 0;
00908 struct ast_speech *speech = find_speech(chan);
00909 struct ast_datastore *datastore = NULL;
00910
00911 if (speech == NULL)
00912 return -1;
00913
00914
00915 ast_speech_destroy(speech);
00916
00917 datastore = ast_channel_datastore_find(chan, &speech_datastore, NULL);
00918 if (datastore != NULL) {
00919 ast_channel_datastore_remove(chan, datastore);
00920 }
00921
00922 return res;
00923 }
00924
00925 static int unload_module(void)
00926 {
00927 int res = 0;
00928
00929 res = ast_unregister_application("SpeechCreate");
00930 res |= ast_unregister_application("SpeechLoadGrammar");
00931 res |= ast_unregister_application("SpeechUnloadGrammar");
00932 res |= ast_unregister_application("SpeechActivateGrammar");
00933 res |= ast_unregister_application("SpeechDeactivateGrammar");
00934 res |= ast_unregister_application("SpeechStart");
00935 res |= ast_unregister_application("SpeechBackground");
00936 res |= ast_unregister_application("SpeechDestroy");
00937 res |= ast_unregister_application("SpeechProcessingSound");
00938 res |= ast_custom_function_unregister(&speech_function);
00939 res |= ast_custom_function_unregister(&speech_score_function);
00940 res |= ast_custom_function_unregister(&speech_text_function);
00941 res |= ast_custom_function_unregister(&speech_grammar_function);
00942 res |= ast_custom_function_unregister(&speech_engine_function);
00943 res |= ast_custom_function_unregister(&speech_results_type_function);
00944
00945 return res;
00946 }
00947
00948 static int load_module(void)
00949 {
00950 int res = 0;
00951
00952 res = ast_register_application_xml("SpeechCreate", speech_create);
00953 res |= ast_register_application_xml("SpeechLoadGrammar", speech_load);
00954 res |= ast_register_application_xml("SpeechUnloadGrammar", speech_unload);
00955 res |= ast_register_application_xml("SpeechActivateGrammar", speech_activate);
00956 res |= ast_register_application_xml("SpeechDeactivateGrammar", speech_deactivate);
00957 res |= ast_register_application_xml("SpeechStart", speech_start);
00958 res |= ast_register_application_xml("SpeechBackground", speech_background);
00959 res |= ast_register_application_xml("SpeechDestroy", speech_destroy);
00960 res |= ast_register_application_xml("SpeechProcessingSound", speech_processing_sound);
00961 res |= ast_custom_function_register(&speech_function);
00962 res |= ast_custom_function_register(&speech_score_function);
00963 res |= ast_custom_function_register(&speech_text_function);
00964 res |= ast_custom_function_register(&speech_grammar_function);
00965 res |= ast_custom_function_register(&speech_engine_function);
00966 res |= ast_custom_function_register(&speech_results_type_function);
00967
00968 return res;
00969 }
00970
00971 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Dialplan Speech Applications",
00972 .load = load_module,
00973 .unload = unload_module,
00974 .nonoptreq = "res_speech",
00975 );