45 #include <sys/socket.h>
47 #include <netinet/in.h>
48 #include <arpa/inet.h>
66 #define FESTIVAL_CONFIG "festival.conf"
68 #define MAXFESTLEN 2048
87 static char *app =
"Festival";
89 static char *socket_receive_file_to_buff(
int fd,
int *size)
96 static char *file_stuff_key =
"ft_StUfF_key";
107 for (k = 0; file_stuff_key[k] !=
'\0';) {
111 if ((*size) + k + 1 >= bufflen) {
113 bufflen += bufflen / 4;
120 if (file_stuff_key[k] == c)
122 else if ((c ==
'X') && (file_stuff_key[k+1] ==
'\0')) {
124 for (i = 0; i < k; i++, (*size)++)
125 buff[*size] = file_stuff_key[i];
129 for (i = 0; i < k; i++, (*size)++)
130 buff[*size] = file_stuff_key[i];
140 static int send_waveform_to_fd(
char *waveform,
int length,
int fd)
143 #if __BYTE_ORDER == __BIG_ENDIAN
150 ast_log(LOG_WARNING,
"Fork failed\n");
156 if (ast_opt_high_priority)
158 #if __BYTE_ORDER == __BIG_ENDIAN
159 for (x = 0; x < length; x += 2) {
160 c = *(waveform + x + 1);
161 *(waveform + x + 1) = *(waveform + x);
166 if (write(0, waveform, length) < 0) {
174 static int send_waveform_to_channel(
struct ast_channel *chan,
char *waveform,
int length,
char *intkeys)
190 ast_log(LOG_WARNING,
"Unable to create pipe\n");
200 owriteformat =
ao2_bump(ast_channel_writeformat(chan));
203 ast_log(LOG_WARNING,
"Unable to set write format to signed linear\n");
204 ao2_cleanup(owriteformat);
211 myf.f.src = __PRETTY_FUNCTION__;
212 myf.f.data.ptr = myf.frdata;
214 res = send_waveform_to_fd(waveform, length, fds[1]);
226 ast_log(LOG_WARNING,
"Null frame == hangup() detected\n");
241 if (needed >
sizeof(myf.frdata)) {
242 ast_log(LOG_WARNING,
"Only able to deliver %d of %d requested samples\n",
243 (
int)
sizeof(myf.frdata) / 2, needed/2);
244 needed =
sizeof(myf.frdata);
246 res = read(fds[0], myf.frdata, needed);
249 myf.f.samples = res / 2;
272 if (!res && owriteformat)
274 ao2_cleanup(owriteformat);
279 static int festival_exec(
struct ast_channel *chan,
const char *vdata)
283 struct sockaddr_in serv_addr;
287 const char *cachedir;
289 const char *festivalcommand;
295 char bigstring[MAXFESTLEN];
298 unsigned char MD5Res[16];
299 char MD5Hex[33] =
"";
301 char cachefile[MAXFESTLEN]=
"";
310 char *newfestivalcommand;
317 if (ast_strlen_zero(vdata)) {
318 ast_log(LOG_WARNING,
"festival requires an argument (text)\n");
324 ast_log(LOG_WARNING,
"No such configuration file %s\n", FESTIVAL_CONFIG);
326 }
else if (cfg == CONFIG_STATUS_FILEINVALID) {
327 ast_log(LOG_ERROR,
"Config file " FESTIVAL_CONFIG
" is in an invalid format. Aborting.\n");
331 if (!(host = ast_variable_retrieve(cfg,
"general",
"host"))) {
334 if (!(temp = ast_variable_retrieve(cfg,
"general",
"port"))) {
339 if (!(temp = ast_variable_retrieve(cfg,
"general",
"usecache"))) {
344 if (!(cachedir = ast_variable_retrieve(cfg,
"general",
"cachedir"))) {
351 if (!(festivalcommand = ast_variable_retrieve(cfg,
"general",
"festivalcommand"))) {
352 const char *startcmd =
"(tts_textasterisk \"";
353 const char *endcmd =
"\" 'file)(quit)\n";
355 strln = strlen(startcmd) + strlen(args.text) + strlen(endcmd) + 1;
357 snprintf(newfestivalcommand, strln,
"%s%s%s", startcmd, args.text, endcmd);
358 festivalcommand = newfestivalcommand;
361 newfestivalcommand =
ast_alloca(strlen(festivalcommand) + strlen(args.text) + 1);
363 for (x = 0, j = 0; x < strlen(festivalcommand); x++) {
364 if (festivalcommand[x] ==
'\\' && festivalcommand[x + 1] ==
'n') {
365 newfestivalcommand[j++] =
'\n';
367 }
else if (festivalcommand[x] ==
'\\') {
368 newfestivalcommand[j++] = festivalcommand[x + 1];
370 }
else if (festivalcommand[x] ==
'%' && festivalcommand[x + 1] ==
's') {
371 sprintf(&newfestivalcommand[j],
"%s", args.text);
372 j += strlen(args.text);
375 newfestivalcommand[j++] = festivalcommand[x];
377 newfestivalcommand[j] =
'\0';
378 festivalcommand = newfestivalcommand;
381 if (args.interrupt && !strcasecmp(args.interrupt,
"any"))
382 args.interrupt = AST_DIGIT_ANY;
384 ast_debug(1,
"Text passed to festival server : %s\n", args.text);
387 fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
390 ast_log(LOG_WARNING,
"festival_client: can't get socket\n");
395 memset(&serv_addr, 0,
sizeof(serv_addr));
397 if ((serv_addr.sin_addr.s_addr = inet_addr(host)) == -1) {
402 ast_log(LOG_WARNING,
"festival_client: ast_sockaddr_resolve_first_af() failed\n");
412 serv_addr.sin_family = AF_INET;
413 serv_addr.sin_port = htons(port);
415 if (connect(fd, (
struct sockaddr *)&serv_addr,
sizeof(serv_addr)) != 0) {
416 ast_log(LOG_WARNING,
"festival_client: connect to server failed\n");
424 MD5Update(&md5ctx, (
unsigned char *)args.text, strlen(args.text));
425 MD5Final(MD5Res, &md5ctx);
430 for (i = 0; i < 16; i++) {
431 snprintf(koko,
sizeof(koko),
"%X", (
unsigned)MD5Res[i]);
432 strncat(MD5Hex, koko,
sizeof(MD5Hex) - strlen(MD5Hex) - 1);
436 if (strlen(cachedir) +
sizeof(MD5Hex) + 1 <= MAXFESTLEN && (usecache == -1)) {
437 snprintf(cachefile,
sizeof(cachefile),
"%s/%s", cachedir, MD5Hex);
438 fdesc = open(cachefile, O_RDWR);
440 fdesc = open(cachefile, O_CREAT | O_RDWR, AST_FILE_MODE);
443 strln = strlen(args.text);
444 ast_debug(1,
"line length : %d\n", strln);
445 if (write(fdesc,&strln,
sizeof(
int)) < 0) {
446 ast_log(LOG_WARNING,
"write() failed: %s\n", strerror(errno));
448 if (write(fdesc,data,strln) < 0) {
449 ast_log(LOG_WARNING,
"write() failed: %s\n", strerror(errno));
451 seekpos = lseek(fdesc, 0, SEEK_CUR);
452 ast_debug(1,
"Seek position : %d\n", seekpos);
455 if (read(fdesc,&strln,
sizeof(
int)) !=
sizeof(
int)) {
456 ast_log(LOG_WARNING,
"read() failed: %s\n", strerror(errno));
458 ast_debug(1,
"Cache file exists, strln=%d, strlen=%d\n", strln, (
int)strlen(args.text));
459 if (strlen(args.text) == strln) {
461 if (read(fdesc,&bigstring,strln) != strln) {
462 ast_log(LOG_WARNING,
"read() failed: %s\n", strerror(errno));
464 bigstring[strln] = 0;
465 if (strcmp(bigstring, args.text) == 0) {
468 ast_log(LOG_WARNING,
"Strings do not match\n");
471 ast_log(LOG_WARNING,
"Size mismatch\n");
476 if (readcache == 1) {
481 ast_debug(1,
"Passing text to festival...\n");
482 fs = fdopen(dup(fd),
"wb");
484 fprintf(fs,
"%s", festivalcommand);
490 if (writecache == 1) {
491 ast_debug(1,
"Writing result to cache...\n");
492 while ((strln = read(fd, buffer, 16384)) != 0) {
493 if (write(fdesc,buffer,strln) < 0) {
494 ast_log(LOG_WARNING,
"write() failed: %s\n", strerror(errno));
499 fd = open(cachefile, O_RDWR);
500 lseek(fd, seekpos, SEEK_SET);
503 ast_debug(1,
"Passing data to channel...\n");
509 for (n = 0; n < 3; ) {
510 read_data = read(fd, ack + n, 3 - n);
514 if (read_data == -1) {
515 ast_log(LOG_WARNING,
"Unable to read from cache/festival fd\n");
523 if (strcmp(ack,
"WV\n") == 0) {
525 if ((waveform = socket_receive_file_to_buff(fd, &filesize))) {
526 res = send_waveform_to_channel(chan, waveform, filesize, args.interrupt);
530 }
else if (strcmp(ack,
"LP\n") == 0) {
532 if ((waveform = socket_receive_file_to_buff(fd, &filesize))) {
533 waveform[filesize] =
'\0';
534 ast_log(LOG_WARNING,
"Festival returned LP : %s\n", waveform);
537 }
else if (strcmp(ack,
"ER\n") == 0) {
538 ast_log(LOG_WARNING,
"Festival returned ER\n");
542 }
while (strcmp(ack,
"OK\n") != 0);
548 static int unload_module(
void)
568 ast_log(LOG_WARNING,
"No such configuration file %s\n", FESTIVAL_CONFIG);
570 }
else if (cfg == CONFIG_STATUS_FILEINVALID) {
571 ast_log(LOG_ERROR,
"Config file " FESTIVAL_CONFIG
" is in an invalid format. Aborting.\n");
578 AST_MODULE_INFO_STANDARD_EXTENDED(
ASTERISK_GPL_KEY,
"Simple Festival Interface");
Main Channel structure associated with a channel.
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
#define ast_realloc(p, len)
A wrapper for realloc()
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
void ast_close_fds_above_n(int n)
Common routine for child processes, to close all fds prior to exec(2)
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
ast_channel_state
ast_channel states
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
int ast_unregister_application(const char *app)
Unregister an application.
Socket address structure.
struct ast_frame_subclass subclass
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Configuration File Parser.
#define ast_config_load(filename, flags)
Load a config file.
General Asterisk PBX channel definitions.
#define AST_FRIENDLY_OFFSET
Offset into a frame's data buffer.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Asterisk architecture endianess compatibility definitions.
int ast_sockaddr_resolve_first_af(struct ast_sockaddr *addr, const char *name, int flag, int family)
Return the first entry from ast_sockaddr_resolve filtered by address family.
#define ast_malloc(len)
A wrapper for malloc()
#define ast_debug(level,...)
Log a DEBUG message.
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Core PBX routines and definitions.
int ast_set_priority(int)
We set ourselves to a high priority, that we might pre-empt everything else. If your PBX has heavy ac...
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
int ast_safe_fork(int stop_reaper)
Common routine to safely fork without a chance of a signal handler firing badly in the child...
int ast_write(struct ast_channel *chan, struct ast_frame *frame)
Write a frame to a channel This function writes the given frame to the indicated channel.
Module has failed to load, may be in an inconsistent state.
Structure used to handle boolean flags.
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
int ast_answer(struct ast_channel *chan)
Answer a channel.
Data structure associated with a single frame of data.
#define ast_sockaddr_to_sin(addr, sin)
Converts a struct ast_sockaddr to a struct sockaddr_in.
enum ast_frame_type frametype
static int load_module(void)
Load the module.
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
int ast_stopstream(struct ast_channel *c)
Stops a stream.
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
#define AST_APP_ARG(name)
Define an application argument.