Mon May 14 04:42:51 2007

Asterisk developer's documentation


app_speech_utils.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2006, Digium, Inc.
00005  *
00006  * Joshua Colp <jcolp@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief Speech Recognition Utility Applications
00022  *
00023  * \author Joshua Colp <jcolp@digium.com>
00024  *
00025  * \ingroup applications
00026  */
00027 
00028 #include "asterisk.h"
00029 
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
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 /* Descriptions for each application */
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 /*! \brief Helper function used by datastores to destroy the speech structure upon hangup */
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    /* Deallocate now */
00103    ast_speech_destroy(speech);
00104 
00105    return;
00106 }
00107 
00108 /*! \brief Static structure for datastore information */
00109 static const struct ast_datastore_info speech_datastore = {
00110    .type = "speech",
00111    .destroy = destroy_callback
00112 };
00113 
00114 /*! \brief Helper function used to find the speech structure attached to a channel */
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 /* Helper function to find a specific speech recognition result by number and nbest alternative */
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 /*! \brief SPEECH_SCORE() Dialplan Function */
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 /*! \brief SPEECH_TEXT() Dialplan Function */
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 /*! \brief SPEECH_GRAMMAR() Dialplan Function */
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 /*! \brief SPEECH_ENGINE() Dialplan Function */
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 /*! \brief SPEECH_RESULTS_TYPE() Dialplan Function */
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 /*! \brief SPEECH() Dialplan Function */
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    /* Now go for the various options */
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    /* Make sure we have a speech structure for everything else */
00306    if (speech == NULL) {
00307       return -1;
00308    }
00309 
00310    /* Check to see if they are checking for silence */
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       /* Count number of results */
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 /*! \brief SpeechCreate() Dialplan Application */
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    /* Request a speech object */
00355    speech = ast_speech_new(data, AST_FORMAT_SLINEAR);
00356    if (speech == NULL) {
00357       /* Not available */
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 /*! \brief SpeechLoadGrammar(Grammar Name|Path) Dialplan Application */
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    /* Parse out arguments */
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         /* Load the grammar locally on the object */
00405         res = ast_speech_grammar_load(speech, name, path);
00406 
00407         ast_module_user_remove(u);
00408 
00409         return res;
00410 }
00411 
00412 /*! \brief SpeechUnloadGrammar(Grammar Name) Dialplan Application */
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         /* Unload the grammar */
00427         res = ast_speech_grammar_unload(speech, data);
00428 
00429         ast_module_user_remove(u);
00430 
00431         return res;
00432 }
00433 
00434 /*! \brief SpeechDeactivateGrammar(Grammar Name) Dialplan Application */
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         /* Deactivate the grammar on the speech object */
00449         res = ast_speech_grammar_deactivate(speech, data);
00450 
00451         ast_module_user_remove(u);
00452 
00453         return res;
00454 }
00455 
00456 /*! \brief SpeechActivateGrammar(Grammar Name) Dialplan Application */
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    /* Activate the grammar on the speech object */
00471    res = ast_speech_grammar_activate(speech, data);
00472 
00473    ast_module_user_remove(u);
00474 
00475    return res;
00476 }
00477 
00478 /*! \brief SpeechStart() Dialplan Application */
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 /*! \brief SpeechProcessingSound(Sound File) Dialplan Application */
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 /*! \brief Helper function used by speech_background to playback a soundfile */
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    if (ast_playstream(fs))
00537       return -1;
00538 
00539         return 0;
00540 }
00541 
00542 /*! \brief SpeechBackground(Sound File|Timeout) Dialplan Application */
00543 static int speech_background(struct ast_channel *chan, void *data)
00544 {
00545         unsigned int timeout = 0;
00546         int res = 0, done = 0, argc = 0, started = 0, quieted = 0;
00547         struct ast_module_user *u = NULL;
00548         struct ast_speech *speech = find_speech(chan);
00549         struct ast_frame *f = NULL;
00550         int oldreadformat = AST_FORMAT_SLINEAR;
00551         char dtmf[AST_MAX_EXTENSION] = "";
00552         time_t start, current;
00553         struct ast_datastore *datastore = NULL;
00554         char *argv[2], *args = NULL, *filename_tmp = NULL, *filename = NULL, tmp[2] = "";
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    /* If channel is not already answered, then answer it */
00566    if (chan->_state != AST_STATE_UP && ast_answer(chan)) {
00567       ast_module_user_remove(u);
00568       return -1;
00569    }
00570 
00571         /* Record old read format */
00572         oldreadformat = chan->readformat;
00573 
00574         /* Change read format to be signed linear */
00575         if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
00576                 ast_module_user_remove(u);
00577                 return -1;
00578         }
00579 
00580         /* Parse out options */
00581         argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0]));
00582         if (argc > 0) {
00583                 /* Yay sound file */
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         /* Before we go into waiting for stuff... make sure the structure is ready, if not - start it again */
00593         if (speech->state == AST_SPEECH_STATE_NOT_READY || speech->state == AST_SPEECH_STATE_DONE) {
00594       ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
00595                 ast_speech_start(speech);
00596         }
00597 
00598    /* Ensure no streams are currently running */
00599    ast_stopstream(chan);
00600 
00601         /* Okay it's streaming so go into a loop grabbing frames! */
00602         while (done == 0) {
00603       /* If the filename is null and stream is not running, start up a new sound file */
00604       if (!quieted && (chan->streamid == -1 && chan->timingfunc == NULL) && (filename = strsep(&filename_tmp, "&"))) {
00605          /* Discard old stream information */
00606          ast_stopstream(chan);
00607          /* Start new stream */
00608          speech_streamfile(chan, filename, chan->language);
00609       }
00610 
00611                 /* Run scheduled stuff */
00612                 ast_sched_runq(chan->sched);
00613 
00614                 /* Yay scheduling */
00615                 res = ast_sched_wait(chan->sched);
00616                 if (res < 0) {
00617                         res = 1000;
00618                 }
00619 
00620                 /* If there is a frame waiting, get it - if not - oh well */
00621                 if (ast_waitfor(chan, res) > 0) {
00622                         f = ast_read(chan);
00623                         if (f == NULL) {
00624                                 /* The channel has hung up most likely */
00625                                 done = 3;
00626                                 break;
00627                         }
00628                 }
00629 
00630       /* Do timeout check (shared between audio/dtmf) */
00631       if ((!quieted || strlen(dtmf)) && started == 1) {
00632          time(&current);
00633          if ((current-start) >= timeout) {
00634             done = 1;
00635             if (f)
00636                ast_frfree(f);
00637             break;
00638          }
00639       }
00640 
00641                 /* Do checks on speech structure to see if it's changed */
00642                 ast_mutex_lock(&speech->lock);
00643                 if (ast_test_flag(speech, AST_SPEECH_QUIET)) {
00644          if (chan->stream)
00645             ast_stopstream(chan);
00646          ast_clear_flag(speech, AST_SPEECH_QUIET);
00647          quieted = 1;
00648                 }
00649                 /* Check state so we can see what to do */
00650                 switch (speech->state) {
00651                 case AST_SPEECH_STATE_READY:
00652                         /* If audio playback has stopped do a check for timeout purposes */
00653                         if (chan->streamid == -1 && chan->timingfunc == NULL)
00654                                 ast_stopstream(chan);
00655                         if (!quieted && chan->stream == NULL && timeout && started == 0 && !filename_tmp) {
00656             if (timeout == -1) {
00657                done = 1;
00658                if (f)
00659                   ast_frfree(f);
00660                break;
00661             }
00662             time(&start);
00663             started = 1;
00664                         }
00665                         /* Write audio frame out to speech engine if no DTMF has been received */
00666                         if (!strlen(dtmf) && f != NULL && f->frametype == AST_FRAME_VOICE) {
00667                                 ast_speech_write(speech, f->data, f->datalen);
00668                         }
00669                         break;
00670                 case AST_SPEECH_STATE_WAIT:
00671                         /* Cue up waiting sound if not already playing */
00672          if (!strlen(dtmf)) {
00673             if (chan->stream == NULL) {
00674                if (speech->processing_sound != NULL) {
00675                   if (strlen(speech->processing_sound) > 0 && strcasecmp(speech->processing_sound,"none")) {
00676                      speech_streamfile(chan, speech->processing_sound, chan->language);
00677                   }
00678                }
00679             } else if (chan->streamid == -1 && chan->timingfunc == NULL) {
00680                ast_stopstream(chan);
00681                if (speech->processing_sound != NULL) {
00682                   if (strlen(speech->processing_sound) > 0 && strcasecmp(speech->processing_sound,"none")) {
00683                      speech_streamfile(chan, speech->processing_sound, chan->language);
00684                   }
00685                }
00686             }
00687          }
00688                         break;
00689                 case AST_SPEECH_STATE_DONE:
00690          /* Now that we are done... let's switch back to not ready state */
00691          ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
00692          if (!strlen(dtmf)) {
00693             /* Copy to speech structure the results, if available */
00694             speech->results = ast_speech_results_get(speech);
00695             /* Break out of our background too */
00696             done = 1;
00697             /* Stop audio playback */
00698             if (chan->stream != NULL) {
00699                ast_stopstream(chan);
00700             }
00701          }
00702                         break;
00703                 default:
00704                         break;
00705                 }
00706                 ast_mutex_unlock(&speech->lock);
00707 
00708                 /* Deal with other frame types */
00709                 if (f != NULL) {
00710                         /* Free the frame we received */
00711                         switch (f->frametype) {
00712                         case AST_FRAME_DTMF:
00713             if (f->subclass == '#') {
00714                done = 1;
00715             } else {
00716                if (chan->stream != NULL) {
00717                   ast_stopstream(chan);
00718                }
00719                if (!started) {
00720                   /* Change timeout to be 5 seconds for DTMF input */
00721                   timeout = (chan->pbx && chan->pbx->dtimeout) ? chan->pbx->dtimeout : 5;
00722                   started = 1;
00723                }
00724                time(&start);
00725                snprintf(tmp, sizeof(tmp), "%c", f->subclass);
00726                strncat(dtmf, tmp, sizeof(dtmf));
00727             }
00728                                 break;
00729                         case AST_FRAME_CONTROL:
00730                                 switch (f->subclass) {
00731                                 case AST_CONTROL_HANGUP:
00732                                         /* Since they hung up we should destroy the speech structure */
00733                                         done = 3;
00734                                 default:
00735                                         break;
00736                                 }
00737                         default:
00738                                 break;
00739                         }
00740                         ast_frfree(f);
00741                         f = NULL;
00742                 }
00743         }
00744 
00745    if (strlen(dtmf)) {
00746       /* We sort of make a results entry */
00747       speech->results = ast_calloc(1, sizeof(*speech->results));
00748       if (speech->results != NULL) {
00749          speech->results->score = 1000;
00750          speech->results->text = strdup(dtmf);
00751          speech->results->grammar = strdup("dtmf");
00752       }
00753    }
00754 
00755         /* See if it was because they hung up */
00756         if (done == 3) {
00757                 /* Destroy speech structure */
00758                 ast_speech_destroy(speech);
00759                 datastore = ast_channel_datastore_find(chan, &speech_datastore, NULL);
00760                 if (datastore != NULL) {
00761                         ast_channel_datastore_remove(chan, datastore);
00762                 }
00763         } else {
00764                 /* Channel is okay so restore read format */
00765                 ast_set_read_format(chan, oldreadformat);
00766         }
00767 
00768         ast_module_user_remove(u);
00769 
00770         return 0;
00771 }
00772 
00773 
00774 /*! \brief SpeechDestroy() Dialplan Application */
00775 static int speech_destroy(struct ast_channel *chan, void *data)
00776 {
00777    int res = 0;
00778         struct ast_module_user *u = NULL;
00779    struct ast_speech *speech = find_speech(chan);
00780    struct ast_datastore *datastore = NULL;
00781 
00782    u = ast_module_user_add(chan);
00783 
00784    if (speech == NULL) {
00785       ast_module_user_remove(u);
00786       return -1;
00787    }
00788 
00789    /* Destroy speech structure */
00790    ast_speech_destroy(speech);
00791 
00792    datastore = ast_channel_datastore_find(chan, &speech_datastore, NULL);
00793    if (datastore != NULL) {
00794       ast_channel_datastore_remove(chan, datastore);
00795    }
00796 
00797    ast_module_user_remove(u);
00798 
00799    return res;
00800 }
00801 
00802 static int unload_module(void)
00803 {
00804    int res = 0;
00805 
00806    res = ast_unregister_application("SpeechCreate");
00807    res |= ast_unregister_application("SpeechLoadGrammar");
00808    res |= ast_unregister_application("SpeechUnloadGrammar");
00809    res |= ast_unregister_application("SpeechActivateGrammar");
00810         res |= ast_unregister_application("SpeechDeactivateGrammar");
00811    res |= ast_unregister_application("SpeechStart");
00812    res |= ast_unregister_application("SpeechBackground");
00813    res |= ast_unregister_application("SpeechDestroy");
00814    res |= ast_unregister_application("SpeechProcessingSound");
00815    res |= ast_custom_function_unregister(&speech_function);
00816    res |= ast_custom_function_unregister(&speech_score_function);
00817    res |= ast_custom_function_unregister(&speech_text_function);
00818    res |= ast_custom_function_unregister(&speech_grammar_function);
00819    res |= ast_custom_function_unregister(&speech_engine_function);
00820    res |= ast_custom_function_unregister(&speech_results_type_function);
00821 
00822    ast_module_user_hangup_all();
00823 
00824    return res; 
00825 }
00826 
00827 static int load_module(void)
00828 {
00829    int res = 0;
00830 
00831    res = ast_register_application("SpeechCreate", speech_create, "Create a Speech Structure", speechcreate_descrip);
00832    res |= ast_register_application("SpeechLoadGrammar", speech_load, "Load a Grammar", speechload_descrip);
00833    res |= ast_register_application("SpeechUnloadGrammar", speech_unload, "Unload a Grammar", speechunload_descrip);
00834    res |= ast_register_application("SpeechActivateGrammar", speech_activate, "Activate a Grammar", speechactivategrammar_descrip);
00835         res |= ast_register_application("SpeechDeactivateGrammar", speech_deactivate, "Deactivate a Grammar", speechdeactivategrammar_descrip);
00836    res |= ast_register_application("SpeechStart", speech_start, "Start recognizing voice in the audio stream", speechstart_descrip);
00837    res |= ast_register_application("SpeechBackground", speech_background, "Play a sound file and wait for speech to be recognized", speechbackground_descrip);
00838    res |= ast_register_application("SpeechDestroy", speech_destroy, "End speech recognition", speechdestroy_descrip);
00839    res |= ast_register_application("SpeechProcessingSound", speech_processing_sound, "Change background processing sound", speechprocessingsound_descrip);
00840    res |= ast_custom_function_register(&speech_function);
00841    res |= ast_custom_function_register(&speech_score_function);
00842    res |= ast_custom_function_register(&speech_text_function);
00843    res |= ast_custom_function_register(&speech_grammar_function);
00844    res |= ast_custom_function_register(&speech_engine_function);
00845    res |= ast_custom_function_register(&speech_results_type_function);
00846 
00847    return res;
00848 }
00849 
00850 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Dialplan Speech Applications");

Generated on Mon May 14 04:42:51 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1