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 #include <sys/types.h>
00027 #include <stdlib.h>
00028 #include <unistd.h>
00029 #include <string.h>
00030 #include <stdlib.h>
00031 #include <sys/types.h>
00032 #include <sys/socket.h>
00033 #include <netdb.h>
00034 #include <netinet/in.h>
00035 #include <arpa/inet.h>
00036 #include <stdio.h>
00037 #include <signal.h>
00038 #include <stdlib.h>
00039 #include <unistd.h>
00040 #include <fcntl.h>
00041 #include <ctype.h>
00042
00043 #include "asterisk.h"
00044
00045 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 48374 $")
00046
00047 #include "asterisk/file.h"
00048 #include "asterisk/logger.h"
00049 #include "asterisk/channel.h"
00050 #include "asterisk/pbx.h"
00051 #include "asterisk/module.h"
00052 #include "asterisk/md5.h"
00053 #include "asterisk/config.h"
00054 #include "asterisk/utils.h"
00055 #include "asterisk/lock.h"
00056 #include "asterisk/options.h"
00057
00058 #define FESTIVAL_CONFIG "festival.conf"
00059
00060 static char *tdesc = "Simple Festival Interface";
00061
00062 static char *app = "Festival";
00063
00064 static char *synopsis = "Say text to the user";
00065
00066 static char *descrip =
00067 " Festival(text[|intkeys]): Connect to Festival, send the argument, get back the waveform,"
00068 "play it to the user, allowing any given interrupt keys to immediately terminate and return\n"
00069 "the value, or 'any' to allow any number back (useful in dialplan)\n";
00070
00071 STANDARD_LOCAL_USER;
00072
00073 LOCAL_USER_DECL;
00074
00075 static char *socket_receive_file_to_buff(int fd,int *size)
00076 {
00077
00078
00079
00080
00081 static char *file_stuff_key = "ft_StUfF_key";
00082 char *buff;
00083 int bufflen;
00084 int n,k,i;
00085 char c;
00086
00087 bufflen = 1024;
00088 buff = (char *)malloc(bufflen);
00089 *size=0;
00090
00091 for (k=0; file_stuff_key[k] != '\0';)
00092 {
00093 n = read(fd,&c,1);
00094 if (n==0) break;
00095 if ((*size)+k+1 >= bufflen)
00096 {
00097 bufflen += bufflen/4;
00098 buff = (char *)realloc(buff,bufflen);
00099 }
00100 if (file_stuff_key[k] == c)
00101 k++;
00102 else if ((c == 'X') && (file_stuff_key[k+1] == '\0'))
00103 {
00104 for (i=0; i < k; i++,(*size)++)
00105 buff[*size] = file_stuff_key[i];
00106 k=0;
00107
00108 }
00109 else
00110 {
00111 for (i=0; i < k; i++,(*size)++)
00112 buff[*size] = file_stuff_key[i];
00113 k=0;
00114 buff[*size] = c;
00115 (*size)++;
00116 }
00117
00118 }
00119
00120 return buff;
00121 }
00122
00123 static int send_waveform_to_fd(char *waveform, int length, int fd) {
00124
00125 int res;
00126 int x;
00127 #ifdef __PPC__
00128 char c;
00129 #endif
00130 sigset_t fullset, oldset;
00131
00132 sigfillset(&fullset);
00133 pthread_sigmask(SIG_BLOCK, &fullset, &oldset);
00134
00135 res = fork();
00136 if (res < 0)
00137 ast_log(LOG_WARNING, "Fork failed\n");
00138 if (res) {
00139 pthread_sigmask(SIG_SETMASK, &oldset, NULL);
00140 return res;
00141 }
00142 for (x=0;x<256;x++) {
00143 if (x != fd)
00144 close(x);
00145 }
00146 if (option_highpriority)
00147 ast_set_priority(0);
00148 signal(SIGPIPE, SIG_DFL);
00149 pthread_sigmask(SIG_UNBLOCK, &fullset, NULL);
00150
00151 #ifdef __PPC__
00152 for( x=0; x<length; x+=2)
00153 {
00154 c = *(waveform+x+1);
00155 *(waveform+x+1)=*(waveform+x);
00156 *(waveform+x)=c;
00157 }
00158 #endif
00159
00160 write(fd,waveform,length);
00161 close(fd);
00162 exit(0);
00163 }
00164
00165
00166 static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, int length, char *intkeys) {
00167 int res=0;
00168 int fds[2];
00169 int ms = -1;
00170 int pid = -1;
00171 int needed = 0;
00172 int owriteformat;
00173 struct ast_frame *f;
00174 struct myframe {
00175 struct ast_frame f;
00176 char offset[AST_FRIENDLY_OFFSET];
00177 char frdata[2048];
00178 } myf;
00179
00180 if (pipe(fds)) {
00181 ast_log(LOG_WARNING, "Unable to create pipe\n");
00182 return -1;
00183 }
00184
00185
00186 if (chan->_state != AST_STATE_UP)
00187 ast_answer(chan);
00188 ast_stopstream(chan);
00189 ast_indicate(chan, -1);
00190
00191 owriteformat = chan->writeformat;
00192 res = ast_set_write_format(chan, AST_FORMAT_SLINEAR);
00193 if (res < 0) {
00194 ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
00195 return -1;
00196 }
00197
00198 res=send_waveform_to_fd(waveform,length,fds[1]);
00199 if (res >= 0) {
00200 pid = res;
00201
00202
00203 for (;;) {
00204 ms = 1000;
00205 res = ast_waitfor(chan, ms);
00206 if (res < 1) {
00207 res = -1;
00208 break;
00209 }
00210 f = ast_read(chan);
00211 if (!f) {
00212 ast_log(LOG_WARNING, "Null frame == hangup() detected\n");
00213 res = -1;
00214 break;
00215 }
00216 if (f->frametype == AST_FRAME_DTMF) {
00217 ast_log(LOG_DEBUG, "User pressed a key\n");
00218 if (intkeys && strchr(intkeys, f->subclass)) {
00219 res = f->subclass;
00220 ast_frfree(f);
00221 break;
00222 }
00223 }
00224 if (f->frametype == AST_FRAME_VOICE) {
00225
00226 needed = f->samples * 2;
00227 if (needed > sizeof(myf.frdata)) {
00228 ast_log(LOG_WARNING, "Only able to deliver %d of %d requested samples\n",
00229 (int)sizeof(myf.frdata) / 2, needed/2);
00230 needed = sizeof(myf.frdata);
00231 }
00232 res = read(fds[0], myf.frdata, needed);
00233 if (res > 0) {
00234 myf.f.frametype = AST_FRAME_VOICE;
00235 myf.f.subclass = AST_FORMAT_SLINEAR;
00236 myf.f.datalen = res;
00237 myf.f.samples = res / 2;
00238 myf.f.mallocd = 0;
00239 myf.f.offset = AST_FRIENDLY_OFFSET;
00240 myf.f.src = __PRETTY_FUNCTION__;
00241 myf.f.data = myf.frdata;
00242 if (ast_write(chan, &myf.f) < 0) {
00243 res = -1;
00244 ast_frfree(f);
00245 break;
00246 }
00247 if (res < needed) {
00248 ast_log(LOG_DEBUG, "Last frame\n");
00249 res=0;
00250 ast_frfree(f);
00251 break;
00252 }
00253 } else {
00254 ast_log(LOG_DEBUG, "No more waveform\n");
00255 res = 0;
00256 }
00257 }
00258 ast_frfree(f);
00259 }
00260 }
00261 close(fds[0]);
00262 close(fds[1]);
00263
00264
00265
00266 if (!res && owriteformat)
00267 ast_set_write_format(chan, owriteformat);
00268 return res;
00269 }
00270
00271 #define MAXLEN 180
00272 #define MAXFESTLEN 2048
00273
00274
00275
00276
00277 static int festival_exec(struct ast_channel *chan, void *vdata)
00278 {
00279 int usecache;
00280 int res=0;
00281 struct localuser *u;
00282 struct sockaddr_in serv_addr;
00283 struct hostent *serverhost;
00284 struct ast_hostent ahp;
00285 int fd;
00286 FILE *fs;
00287 char *host;
00288 char *cachedir;
00289 char *temp;
00290 char *festivalcommand;
00291 int port=1314;
00292 int n;
00293 char ack[4];
00294 char *waveform;
00295 int filesize;
00296 int wave;
00297 char bigstring[MAXFESTLEN];
00298 int i;
00299 struct MD5Context md5ctx;
00300 unsigned char MD5Res[16];
00301 char MD5Hex[33] = "";
00302 char koko[4] = "";
00303 char cachefile[MAXFESTLEN]="";
00304 int readcache=0;
00305 int writecache=0;
00306 int strln;
00307 int fdesc = -1;
00308 char buffer[16384];
00309 int seekpos = 0;
00310 char *data;
00311 char *intstr;
00312 struct ast_config *cfg;
00313
00314 if (ast_strlen_zero(vdata)) {
00315 ast_log(LOG_WARNING, "festival requires an argument (text)\n");
00316 return -1;
00317 }
00318
00319 LOCAL_USER_ADD(u);
00320
00321 cfg = ast_config_load(FESTIVAL_CONFIG);
00322 if (!cfg) {
00323 ast_log(LOG_WARNING, "No such configuration file %s\n", FESTIVAL_CONFIG);
00324 LOCAL_USER_REMOVE(u);
00325 return -1;
00326 }
00327 if (!(host = ast_variable_retrieve(cfg, "general", "host"))) {
00328 host = "localhost";
00329 }
00330 if (!(temp = ast_variable_retrieve(cfg, "general", "port"))) {
00331 port = 1314;
00332 } else {
00333 port = atoi(temp);
00334 }
00335 if (!(temp = ast_variable_retrieve(cfg, "general", "usecache"))) {
00336 usecache=0;
00337 } else {
00338 usecache = ast_true(temp);
00339 }
00340 if (!(cachedir = ast_variable_retrieve(cfg, "general", "cachedir"))) {
00341 cachedir = "/tmp/";
00342 }
00343 if (!(festivalcommand = ast_variable_retrieve(cfg, "general", "festivalcommand"))) {
00344 festivalcommand = "(tts_textasterisk \"%s\" 'file)(quit)\n";
00345 }
00346
00347 data = ast_strdupa(vdata);
00348 if (!data) {
00349 ast_log(LOG_ERROR, "Out of memery\n");
00350 ast_config_destroy(cfg);
00351 LOCAL_USER_REMOVE(u);
00352 return -1;
00353 }
00354
00355 intstr = strchr(data, '|');
00356 if (intstr) {
00357 *intstr = '\0';
00358 intstr++;
00359 if (!strcasecmp(intstr, "any"))
00360 intstr = AST_DIGIT_ANY;
00361 }
00362
00363 ast_log(LOG_DEBUG, "Text passed to festival server : %s\n",(char *)data);
00364
00365
00366 fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
00367
00368 if (fd < 0) {
00369 ast_log(LOG_WARNING,"festival_client: can't get socket\n");
00370 ast_config_destroy(cfg);
00371 LOCAL_USER_REMOVE(u);
00372 return -1;
00373 }
00374 memset(&serv_addr, 0, sizeof(serv_addr));
00375 if ((serv_addr.sin_addr.s_addr = inet_addr(host)) == -1) {
00376
00377 serverhost = ast_gethostbyname(host, &ahp);
00378 if (serverhost == (struct hostent *)0) {
00379 ast_log(LOG_WARNING,"festival_client: gethostbyname failed\n");
00380 ast_config_destroy(cfg);
00381 LOCAL_USER_REMOVE(u);
00382 return -1;
00383 }
00384 memmove(&serv_addr.sin_addr,serverhost->h_addr, serverhost->h_length);
00385 }
00386 serv_addr.sin_family = AF_INET;
00387 serv_addr.sin_port = htons(port);
00388
00389 if (connect(fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) != 0) {
00390 ast_log(LOG_WARNING,"festival_client: connect to server failed\n");
00391 ast_config_destroy(cfg);
00392 LOCAL_USER_REMOVE(u);
00393 return -1;
00394 }
00395
00396
00397 MD5Init(&md5ctx);
00398 MD5Update(&md5ctx,(unsigned char const *)data,strlen(data));
00399 MD5Final(MD5Res,&md5ctx);
00400 MD5Hex[0] = '\0';
00401
00402
00403
00404 for (i=0;i<16;i++) {
00405 snprintf(koko, sizeof(koko), "%X",MD5Res[i]);
00406 strncat(MD5Hex, koko, sizeof(MD5Hex) - strlen(MD5Hex) - 1);
00407 }
00408 readcache=0;
00409 writecache=0;
00410 if (strlen(cachedir)+strlen(MD5Hex)+1<=MAXFESTLEN && (usecache==-1)) {
00411 snprintf(cachefile, sizeof(cachefile), "%s/%s", cachedir, MD5Hex);
00412 fdesc=open(cachefile,O_RDWR);
00413 if (fdesc==-1) {
00414 fdesc=open(cachefile,O_CREAT|O_RDWR,0777);
00415 if (fdesc!=-1) {
00416 writecache=1;
00417 strln=strlen((char *)data);
00418 ast_log(LOG_DEBUG,"line length : %d\n",strln);
00419 write(fdesc,&strln,sizeof(int));
00420 write(fdesc,data,strln);
00421 seekpos=lseek(fdesc,0,SEEK_CUR);
00422 ast_log(LOG_DEBUG,"Seek position : %d\n",seekpos);
00423 }
00424 } else {
00425 read(fdesc,&strln,sizeof(int));
00426 ast_log(LOG_DEBUG,"Cache file exists, strln=%d, strlen=%d\n",strln,(int)strlen((char *)data));
00427 if (strlen((char *)data)==strln) {
00428 ast_log(LOG_DEBUG,"Size OK\n");
00429 read(fdesc,&bigstring,strln);
00430 bigstring[strln] = 0;
00431 if (strcmp(bigstring,data)==0) {
00432 readcache=1;
00433 } else {
00434 ast_log(LOG_WARNING,"Strings do not match\n");
00435 }
00436 } else {
00437 ast_log(LOG_WARNING,"Size mismatch\n");
00438 }
00439 }
00440 }
00441
00442 if (readcache==1) {
00443 close(fd);
00444 fd=fdesc;
00445 ast_log(LOG_DEBUG,"Reading from cache...\n");
00446 } else {
00447 ast_log(LOG_DEBUG,"Passing text to festival...\n");
00448 fs=fdopen(dup(fd),"wb");
00449 fprintf(fs,festivalcommand,(char *)data);
00450 fflush(fs);
00451 fclose(fs);
00452 }
00453
00454
00455 if (writecache==1) {
00456 ast_log(LOG_DEBUG,"Writing result to cache...\n");
00457 while ((strln=read(fd,buffer,16384))!=0) {
00458 write(fdesc,buffer,strln);
00459 }
00460 close(fd);
00461 close(fdesc);
00462 fd=open(cachefile,O_RDWR);
00463 lseek(fd,seekpos,SEEK_SET);
00464 }
00465
00466 ast_log(LOG_DEBUG,"Passing data to channel...\n");
00467
00468
00469
00470 wave = 0;
00471 do {
00472 int read_data;
00473 for (n=0; n < 3; )
00474 {
00475 read_data = read(fd,ack+n,3-n);
00476
00477
00478
00479 if ( read_data == -1 )
00480 {
00481 ast_log(LOG_WARNING,"Unable to read from cache/festival fd\n");
00482 close(fd);
00483 ast_config_destroy(cfg);
00484 LOCAL_USER_REMOVE(u);
00485 return -1;
00486 }
00487 n += read_data;
00488 }
00489 ack[3] = '\0';
00490 if (strcmp(ack,"WV\n") == 0) {
00491 ast_log(LOG_DEBUG,"Festival WV command\n");
00492 waveform = socket_receive_file_to_buff(fd,&filesize);
00493 res = send_waveform_to_channel(chan,waveform,filesize, intstr);
00494 free(waveform);
00495 break;
00496 }
00497 else if (strcmp(ack,"LP\n") == 0) {
00498 ast_log(LOG_DEBUG,"Festival LP command\n");
00499 waveform = socket_receive_file_to_buff(fd,&filesize);
00500 waveform[filesize]='\0';
00501 ast_log(LOG_WARNING,"Festival returned LP : %s\n",waveform);
00502 free(waveform);
00503 } else if (strcmp(ack,"ER\n") == 0) {
00504 ast_log(LOG_WARNING,"Festival returned ER\n");
00505 res=-1;
00506 break;
00507 }
00508 } while (strcmp(ack,"OK\n") != 0);
00509 close(fd);
00510 ast_config_destroy(cfg);
00511 LOCAL_USER_REMOVE(u);
00512 return res;
00513
00514 }
00515
00516 int unload_module(void)
00517 {
00518 int res;
00519
00520 res = ast_unregister_application(app);
00521
00522 STANDARD_HANGUP_LOCALUSERS;
00523
00524 return res;
00525 }
00526
00527 int load_module(void)
00528 {
00529
00530 return ast_register_application(app, festival_exec, synopsis, descrip);
00531 }
00532
00533 char *description(void)
00534 {
00535 return tdesc;
00536 }
00537
00538 int usecount(void)
00539 {
00540 int res;
00541 STANDARD_USECOUNT(res);
00542 return res;
00543 }
00544
00545 char *key()
00546 {
00547 return ASTERISK_GPL_KEY;
00548 }