static gboolean read_response (GstFestival * festival) { char ack[4]; char *data; int filesize; int fd; int n; gboolean ret = TRUE; fd = festival->info->server_fd; do { for (n = 0; n < 3;) n += read (fd, ack + n, 3 - n); ack[3] = '\0'; GST_DEBUG_OBJECT (festival, "got response %s", ack); if (strcmp (ack, "WV\n") == 0) { GstBuffer *buffer; /* receive a waveform */ data = socket_receive_file_to_buff (fd, &filesize); GST_DEBUG_OBJECT (festival, "received %d bytes of waveform data", filesize); /* push contents as a buffer */ buffer = gst_buffer_new (); GST_BUFFER_SIZE (buffer) = (filesize); GST_BUFFER_DATA (buffer) = (guint8 *) data; GST_BUFFER_MALLOCDATA (buffer) = (guint8 *) data; GST_BUFFER_TIMESTAMP (buffer) = GST_CLOCK_TIME_NONE; gst_pad_push (festival->srcpad, buffer); } else if (strcmp (ack, "LP\n") == 0) { /* receive an s-expr */ data = client_accept_s_expr (fd); GST_DEBUG_OBJECT (festival, "received s-expression: %s", data); g_free (data); } else if (strcmp (ack, "ER\n") == 0) { /* server got an error */ GST_ELEMENT_ERROR (festival, LIBRARY, FAILED, ("Festival speech server returned an error"), ("Make sure you have voices/languages installed")); ret = FALSE; break; } } while (strcmp (ack, "OK\n") != 0); return ret; }
static char * client_accept_s_expr (int fd) { /* Read s-expression from server, as a char * */ char *expr; int filesize; expr = socket_receive_file_to_buff (fd, &filesize); expr[filesize] = '\0'; return expr; }
static int festival_exec(struct ast_channel *chan, void *vdata) { int usecache; int res=0; struct localuser *u; struct sockaddr_in serv_addr; struct hostent *serverhost; struct ast_hostent ahp; int fd; FILE *fs; char *host; char *cachedir; char *temp; char *festivalcommand; int port=1314; int n; char ack[4]; char *waveform; int filesize; int wave; char bigstring[MAXFESTLEN]; int i; struct MD5Context md5ctx; unsigned char MD5Res[16]; char MD5Hex[33] = ""; char koko[4] = ""; char cachefile[MAXFESTLEN]=""; int readcache=0; int writecache=0; int strln; int fdesc = -1; char buffer[16384]; int seekpos = 0; char *data; char *intstr; struct ast_config *cfg; char *newfestivalcommand; if (ast_strlen_zero(vdata)) { ast_log(LOG_WARNING, "festival requires an argument (text)\n"); return -1; } LOCAL_USER_ADD(u); cfg = ast_config_load(FESTIVAL_CONFIG); if (!cfg) { ast_log(LOG_WARNING, "No such configuration file %s\n", FESTIVAL_CONFIG); LOCAL_USER_REMOVE(u); return -1; } if (!(host = ast_variable_retrieve(cfg, "general", "host"))) { host = "localhost"; } if (!(temp = ast_variable_retrieve(cfg, "general", "port"))) { port = 1314; } else { port = atoi(temp); } if (!(temp = ast_variable_retrieve(cfg, "general", "usecache"))) { usecache=0; } else { usecache = ast_true(temp); } if (!(cachedir = ast_variable_retrieve(cfg, "general", "cachedir"))) { cachedir = "/tmp/"; } if (!(festivalcommand = ast_variable_retrieve(cfg, "general", "festivalcommand"))) { festivalcommand = "(tts_textasterisk \"%s\" 'file)(quit)\n"; } else { /* This else parses the festivalcommand that we're sent from the config file for \n's, etc */ int i, j; newfestivalcommand = alloca(strlen(festivalcommand) + 1); for (i = 0, j = 0; i < strlen(festivalcommand); i++) { if (festivalcommand[i] == '\\' && festivalcommand[i + 1] == 'n') { newfestivalcommand[j++] = '\n'; i++; } else if (festivalcommand[i] == '\\') { newfestivalcommand[j++] = festivalcommand[i + 1]; i++; } else newfestivalcommand[j++] = festivalcommand[i]; } newfestivalcommand[j] = '\0'; festivalcommand = newfestivalcommand; } data = ast_strdupa(vdata); intstr = strchr(data, '|'); if (intstr) { *intstr = '\0'; intstr++; if (!strcasecmp(intstr, "any")) intstr = AST_DIGIT_ANY; } ast_log(LOG_DEBUG, "Text passed to festival server : %s\n",(char *)data); /* Connect to local festival server */ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (fd < 0) { ast_log(LOG_WARNING,"festival_client: can't get socket\n"); ast_config_destroy(cfg); LOCAL_USER_REMOVE(u); return -1; } memset(&serv_addr, 0, sizeof(serv_addr)); if ((serv_addr.sin_addr.s_addr = inet_addr(host)) == -1) { /* its a name rather than an ipnum */ serverhost = ast_gethostbyname(host, &ahp); if (serverhost == (struct hostent *)0) { ast_log(LOG_WARNING,"festival_client: gethostbyname failed\n"); ast_config_destroy(cfg); LOCAL_USER_REMOVE(u); return -1; } memmove(&serv_addr.sin_addr,serverhost->h_addr, serverhost->h_length); } serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(port); if (connect(fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) != 0) { ast_log(LOG_WARNING,"festival_client: connect to server failed\n"); ast_config_destroy(cfg); LOCAL_USER_REMOVE(u); return -1; } /* Compute MD5 sum of string */ MD5Init(&md5ctx); MD5Update(&md5ctx,(unsigned char const *)data,strlen(data)); MD5Final(MD5Res,&md5ctx); MD5Hex[0] = '\0'; /* 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]); strncat(MD5Hex, koko, sizeof(MD5Hex) - strlen(MD5Hex) - 1); } readcache=0; writecache=0; if (strlen(cachedir)+strlen(MD5Hex)+1<=MAXFESTLEN && (usecache==-1)) { snprintf(cachefile, sizeof(cachefile), "%s/%s", cachedir, MD5Hex); fdesc=open(cachefile,O_RDWR); if (fdesc==-1) { fdesc=open(cachefile,O_CREAT|O_RDWR,0777); if (fdesc!=-1) { writecache=1; strln=strlen((char *)data); ast_log(LOG_DEBUG,"line length : %d\n",strln); write(fdesc,&strln,sizeof(int)); write(fdesc,data,strln); seekpos=lseek(fdesc,0,SEEK_CUR); ast_log(LOG_DEBUG,"Seek position : %d\n",seekpos); } } else { read(fdesc,&strln,sizeof(int)); ast_log(LOG_DEBUG,"Cache file exists, strln=%d, strlen=%d\n",strln,(int)strlen((char *)data)); if (strlen((char *)data)==strln) { ast_log(LOG_DEBUG,"Size OK\n"); read(fdesc,&bigstring,strln); bigstring[strln] = 0; if (strcmp(bigstring,data)==0) { readcache=1; } else { ast_log(LOG_WARNING,"Strings do not match\n"); } } else { ast_log(LOG_WARNING,"Size mismatch\n"); } } } if (readcache==1) { close(fd); fd=fdesc; ast_log(LOG_DEBUG,"Reading from cache...\n"); } else { ast_log(LOG_DEBUG,"Passing text to festival...\n"); fs=fdopen(dup(fd),"wb"); fprintf(fs,festivalcommand,(char *)data); fflush(fs); fclose(fs); } /* Write to cache and then pass it down */ if (writecache==1) { ast_log(LOG_DEBUG,"Writing result to cache...\n"); while ((strln=read(fd,buffer,16384))!=0) { write(fdesc,buffer,strln); } close(fd); close(fdesc); fd=open(cachefile,O_RDWR); lseek(fd,seekpos,SEEK_SET); } ast_log(LOG_DEBUG,"Passing data to channel...\n"); /* 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; ) { read_data = read(fd,ack+n,3-n); /* this avoids falling in infinite loop * in case that festival server goes down * */ if ( read_data == -1 ) { ast_log(LOG_WARNING,"Unable to read from cache/festival fd"); close(fd); ast_config_destroy(cfg); LOCAL_USER_REMOVE(u); return -1; } n += read_data; } ack[3] = '\0'; if (strcmp(ack,"WV\n") == 0) { /* receive a waveform */ ast_log(LOG_DEBUG,"Festival WV command\n"); waveform = socket_receive_file_to_buff(fd,&filesize); res = send_waveform_to_channel(chan,waveform,filesize, intstr); free(waveform); break; } else if (strcmp(ack,"LP\n") == 0) { /* receive an s-expr */ ast_log(LOG_DEBUG,"Festival LP command\n"); waveform = socket_receive_file_to_buff(fd,&filesize); waveform[filesize]='\0'; ast_log(LOG_WARNING,"Festival returned LP : %s\n",waveform); free(waveform); } else if (strcmp(ack,"ER\n") == 0) { /* server got an error */ ast_log(LOG_WARNING,"Festival returned ER\n"); res=-1; break; } } while (strcmp(ack,"OK\n") != 0); close(fd); ast_config_destroy(cfg); LOCAL_USER_REMOVE(u); return res; }