Merge "res_musiconhold: Start playlist after initial announcement"
[asterisk/asterisk.git] / apps / app_festival.c
index 82f1bdd..3e2e020 100644 (file)
  * \ingroup applications
  */
 
-#include "asterisk.h"
+/*! \li \ref app_festival.c uses the configuration file \ref festival.conf
+ * \addtogroup configuration_file Configuration Files
+ */
+
+/*! 
+ * \page festival.conf festival.conf
+ * \verbinclude festival.conf.sample
+ */
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+/*** MODULEINFO
+       <support_level>extended</support_level>
+ ***/
+
+#include "asterisk.h"
 
 #include <sys/socket.h>
 #include <netdb.h>
@@ -38,6 +49,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include <signal.h>
 #include <fcntl.h>
 #include <ctype.h>
+#include <errno.h>
 
 #include "asterisk/file.h"
 #include "asterisk/channel.h"
@@ -48,6 +60,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/utils.h"
 #include "asterisk/lock.h"
 #include "asterisk/app.h"
+#include "asterisk/endian.h"
+#include "asterisk/format_cache.h"
 
 #define FESTIVAL_CONFIG "festival.conf"
 #define MAXLEN 180
@@ -126,7 +140,8 @@ static char *socket_receive_file_to_buff(int fd, int *size)
 static int send_waveform_to_fd(char *waveform, int length, int fd)
 {
        int res;
-#ifdef __PPC__ 
+#if __BYTE_ORDER == __BIG_ENDIAN
+       int x;
        char c;
 #endif
 
@@ -140,25 +155,28 @@ static int send_waveform_to_fd(char *waveform, int length, int fd)
        ast_close_fds_above_n(0);
        if (ast_opt_high_priority)
                ast_set_priority(0);
-#ifdef __PPC__  
+#if __BYTE_ORDER == __BIG_ENDIAN
        for (x = 0; x < length; x += 2) {
                c = *(waveform + x + 1);
                *(waveform + x + 1) = *(waveform + x);
                *(waveform + x) = c;
        }
 #endif
-       write(fd, waveform, length);
+
+       if (write(0, waveform, length) < 0) {
+               /* Cannot log -- all FDs are already closed */
+       }
+
        close(fd);
-       exit(0);
+       _exit(0);
 }
 
 static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, int length, char *intkeys)
 {
        int res = 0;
        int fds[2];
-       int pid = -1;
        int needed = 0;
-       int owriteformat;
+       struct ast_format *owriteformat;
        struct ast_frame *f;
        struct myframe {
                struct ast_frame f;
@@ -174,21 +192,27 @@ static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, in
        }
 
        /* Answer if it's not already going */
-       if (chan->_state != AST_STATE_UP)
+       if (ast_channel_state(chan) != AST_STATE_UP)
                ast_answer(chan);
        ast_stopstream(chan);
        ast_indicate(chan, -1);
        
-       owriteformat = chan->writeformat;
-       res = ast_set_write_format(chan, AST_FORMAT_SLINEAR);
+       owriteformat = ao2_bump(ast_channel_writeformat(chan));
+       res = ast_set_write_format(chan, ast_format_slin);
        if (res < 0) {
                ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
+               ao2_cleanup(owriteformat);
                return -1;
        }
+
+       myf.f.frametype = AST_FRAME_VOICE;
+       myf.f.subclass.format = ast_format_slin;
+       myf.f.offset = AST_FRIENDLY_OFFSET;
+       myf.f.src = __PRETTY_FUNCTION__;
+       myf.f.data.ptr = myf.frdata;
        
        res = send_waveform_to_fd(waveform, length, fds[1]);
        if (res >= 0) {
-               pid = res;
                /* Order is important -- there's almost always going to be mp3...  we want to prioritize the
                   user */
                for (;;) {
@@ -205,8 +229,8 @@ static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, in
                        }
                        if (f->frametype == AST_FRAME_DTMF) {
                                ast_debug(1, "User pressed a key\n");
-                               if (intkeys && strchr(intkeys, f->subclass)) {
-                                       res = f->subclass;
+                               if (intkeys && strchr(intkeys, f->subclass.integer)) {
+                                       res = f->subclass.integer;
                                        ast_frfree(f);
                                        break;
                                }
@@ -221,13 +245,8 @@ static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, in
                                }
                                res = read(fds[0], myf.frdata, needed);
                                if (res > 0) {
-                                       myf.f.frametype = AST_FRAME_VOICE;
-                                       myf.f.subclass = AST_FORMAT_SLINEAR;
                                        myf.f.datalen = res;
                                        myf.f.samples = res / 2;
-                                       myf.f.offset = AST_FRIENDLY_OFFSET;
-                                       myf.f.src = __PRETTY_FUNCTION__;
-                                       myf.f.data.ptr = myf.frdata;
                                        if (ast_write(chan, &myf.f) < 0) {
                                                res = -1;
                                                ast_frfree(f);
@@ -250,16 +269,14 @@ static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, in
        close(fds[0]);
        close(fds[1]);
 
-#if 0
-       if (pid > -1)
-               kill(pid, SIGKILL);
-#endif
        if (!res && owriteformat)
                ast_set_write_format(chan, owriteformat);
+       ao2_cleanup(owriteformat);
+
        return res;
 }
 
-static int festival_exec(struct ast_channel *chan, void *vdata)
+static int festival_exec(struct ast_channel *chan, const char *vdata)
 {
        int usecache;
        int res = 0;
@@ -277,7 +294,6 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
        char ack[4];
        char *waveform;
        int filesize;
-       int wave;
        char bigstring[MAXFESTLEN];
        int i;
        struct MD5Context md5ctx;
@@ -339,12 +355,12 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
                const char *endcmd = "\" 'file)(quit)\n";
 
                strln = strlen(startcmd) + strlen(args.text) + strlen(endcmd) + 1;
-               newfestivalcommand = alloca(strln);
+               newfestivalcommand = ast_alloca(strln);
                snprintf(newfestivalcommand, strln, "%s%s%s", startcmd, args.text, endcmd);
                festivalcommand = newfestivalcommand;
        } else { /* This else parses the festivalcommand that we're sent from the config file for \n's, etc */
                int x, j;
-               newfestivalcommand = alloca(strlen(festivalcommand) + strlen(args.text) + 1);
+               newfestivalcommand = ast_alloca(strlen(festivalcommand) + strlen(args.text) + 1);
 
                for (x = 0, j = 0; x < strlen(festivalcommand); x++) {
                        if (festivalcommand[x] == '\\' && festivalcommand[x + 1] == 'n') {
@@ -410,7 +426,7 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
        /* Convert to HEX and look if there is any matching file in the cache 
                directory */
        for (i = 0; i < 16; i++) {
-               snprintf(koko, sizeof(koko), "%X", MD5Res[i]);
+               snprintf(koko, sizeof(koko), "%X", (unsigned)MD5Res[i]);
                strncat(MD5Hex, koko, sizeof(MD5Hex) - strlen(MD5Hex) - 1);
        }
        readcache = 0;
@@ -424,17 +440,25 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
                                writecache = 1;
                                strln = strlen(args.text);
                                ast_debug(1, "line length : %d\n", strln);
-                               write(fdesc, &strln, sizeof(strln));
-                               write(fdesc, args.text, strln);
+                               if (write(fdesc,&strln,sizeof(int)) < 0) {
+                                       ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
+                               }
+                               if (write(fdesc,data,strln) < 0) {
+                                       ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
+                               }
                                seekpos = lseek(fdesc, 0, SEEK_CUR);
                                ast_debug(1, "Seek position : %d\n", seekpos);
                        }
                } else {
-                       read(fdesc, &strln, sizeof(strln));
+                       if (read(fdesc,&strln,sizeof(int)) != sizeof(int)) {
+                               ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
+                       }
                        ast_debug(1, "Cache file exists, strln=%d, strlen=%d\n", strln, (int)strlen(args.text));
                        if (strlen(args.text) == strln) {
                                ast_debug(1, "Size OK\n");
-                               read(fdesc, &bigstring, strln);
+                               if (read(fdesc,&bigstring,strln) != strln) {
+                                       ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
+                               }
                                bigstring[strln] = 0;
                                if (strcmp(bigstring, args.text) == 0) { 
                                        readcache = 1;
@@ -464,7 +488,9 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
        if (writecache == 1) {
                ast_debug(1, "Writing result to cache...\n");
                while ((strln = read(fd, buffer, 16384)) != 0) {
-                       write(fdesc, buffer, strln);
+                       if (write(fdesc,buffer,strln) < 0) {
+                               ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
+                       }
                }
                close(fd);
                close(fdesc);
@@ -476,7 +502,6 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
 
        /* Read back info from server */
        /* This assumes only one waveform will come back, also LP is unlikely */
-       wave = 0;
        do {
                int read_data;
                for (n = 0; n < 3; ) {
@@ -523,6 +548,16 @@ static int unload_module(void)
        return ast_unregister_application(app);
 }
 
+/*!
+ * \brief Load the module
+ *
+ * Module loading including tests for configuration or dependencies.
+ * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
+ * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
+ * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
+ * configuration file or other non-critical problem return 
+ * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
+ */
 static int load_module(void)
 {
        struct ast_flags config_flags = { 0 };
@@ -538,4 +573,5 @@ static int load_module(void)
        return ast_register_application_xml(app, festival_exec);
 }
 
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Simple Festival Interface");
+AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Simple Festival Interface");
+