1 /*************************************************************************/
2 /* */
3 /* Centre for Speech Technology Research */
4 /* University of Edinburgh, UK */
5 /* Copyright (c) 1996,1997 */
6 /* All Rights Reserved. */
7 /* */
8 /* Permission is hereby granted, free of charge, to use and distribute */
9 /* this software and its documentation without restriction, including */
10 /* without limitation the rights to use, copy, modify, merge, publish, */
11 /* distribute, sublicense, and/or sell copies of this work, and to */
12 /* permit persons to whom this work is furnished to do so, subject to */
13 /* the following conditions: */
14 /* 1. The code must retain the above copyright notice, this list of */
15 /* conditions and the following disclaimer. */
16 /* 2. Any modifications must be clearly marked as such. */
17 /* 3. Original authors' names are not deleted. */
18 /* 4. The authors' names are not used to endorse or promote products */
19 /* derived from this software without specific prior written */
20 /* permission. */
21 /* */
22 /* THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK */
23 /* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */
24 /* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */
25 /* SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE */
26 /* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */
27 /* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN */
28 /* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */
29 /* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */
30 /* THIS SOFTWARE. */
31 /* */
32 /*************************************************************************/
33 /* Author : Alan W Black */
34 /* Date : September 1996 */
35 /*-----------------------------------------------------------------------*/
36 /* */
37 /* Interface with the audio spooler */
38 /* */
39 /*=======================================================================*/
40 #include <cstdio>
41 #include "EST_unix.h"
42 #include <cstdlib>
43 #include "festival.h"
44 #include "festivalP.h"
45
46 #ifdef NO_SPOOLER
audsp_play_wave(EST_Wave * w)47 void audsp_play_wave(EST_Wave *w) { cerr << "no spooler available\n"; }
l_audio_mode(LISP mode)48 LISP l_audio_mode(LISP mode) { return NIL; }
49 #else
50
51 #include <sys/types.h>
52 #include <sys/wait.h>
53
54 static int start_sub_process(int *fds,int argc,char **argv);
55 static char **enargen(const char *command,int *argc);
56 static void audsp_send(const char *c);
57 static int *pipe_open(const char *command);
58 static void pipe_close(int *fds);
59
60 static int *audfds;
61 static int audsp_num=0;
62 static int audsp_pid = 0;
63
audsp_play_wave(EST_Wave * w)64 void audsp_play_wave(EST_Wave *w)
65 {
66 EST_String tpref = make_tmp_filename();
67 char *tmpfilename = walloc(char,tpref.length()+20);
68 sprintf(tmpfilename,"%s_aud_%05d",(const char *)tpref,audsp_num++);
69 w->save(tmpfilename,"nist");
70 audsp_send(EST_String("play ")+tmpfilename+EST_String(" ")+
71 itoString(w->sample_rate()));
72 wfree(tmpfilename);
73 }
74
audsp_send(const char * c)75 static void audsp_send(const char *c)
76 {
77 char reply[4];
78 int pid;
79 int statusp;
80
81 pid = waitpid((pid_t)audsp_pid,&statusp,WNOHANG);
82 if (pid != 0)
83 {
84 cerr << "Audio spooler has died unexpectedly" << endl;
85 audsp_mode = FALSE;
86 festival_error();
87 }
88
89 write(audfds[0],c,strlen(c));
90 write(audfds[0],"\n",1);
91 read(audfds[1],reply,3); /* confirmation */
92 }
93
l_audio_mode(LISP mode)94 LISP l_audio_mode(LISP mode)
95 {
96 // Switch audio mode
97 LISP audio=NIL;
98 LISP command=NIL;
99
100 if (mode == NIL)
101 {
102 cerr << "audio_mode: nil is not a valid mode\n";
103 festival_error();
104 }
105 else if (streq("async",get_c_string(mode)))
106 { // Asynchronous mode using the audio spooler.
107 if (audsp_mode == FALSE)
108 {
109 audio = ft_get_param("Audio_Method");
110 command = ft_get_param("Audio_Command");
111 audfds = pipe_open("audsp");
112 if (audio != NIL)
113 audsp_send(EST_String("method ")+get_c_string(audio));
114 if (command != NIL)
115 {
116 // command needs to be a single line so delete an newlines
117 EST_String flattened = get_c_string(command);
118 flattened.gsub("\\\n"," ");
119 flattened.gsub("\n"," ");
120 audsp_send(EST_String("command ")+flattened);
121 }
122 if ((audio = ft_get_param("Audio_Required_Rate")) != NIL)
123 audsp_send(EST_String("rate ")+get_c_string(audio));
124 if ((audio = ft_get_param("Audio_Required_Format")) != NIL)
125 audsp_send(EST_String("otype ")+get_c_string(audio));
126 if ((audio = ft_get_param("Audio_Device")) != NIL)
127 audsp_send(EST_String("device ")+get_c_string(audio));
128 audsp_mode = TRUE;
129 }
130 }
131 else if (streq("sync",get_c_string(mode)))
132 {
133 // Synchronous mode
134 if (audsp_mode)
135 pipe_close(audfds);
136 audsp_mode = FALSE;
137 }
138 else if (streq("shutup",get_c_string(mode)))
139 {
140 if (audsp_mode)
141 audsp_send("shutup");
142 else
143 {
144 cerr << "audio_mode: not in async mode, can't shutup\n";
145 festival_error();
146 }
147 }
148 else if (streq("close",get_c_string(mode)))
149 { // return only when queue is empty
150 if (audsp_mode)
151 audsp_send("close");
152 }
153 else if (streq("query",get_c_string(mode)))
154 {
155 if (audsp_mode)
156 audsp_send("query");
157 else
158 {
159 cerr << "audio_mode: not in async mode, can't query\n";
160 festival_error();
161 }
162 }
163 else
164 {
165 cerr << "audio_mode: unknown mode \"" << get_c_string(mode) <<
166 "\"\n";
167 festival_error();
168 }
169
170 return mode;
171 }
172
pipe_close(int * fds)173 static void pipe_close(int *fds)
174 {
175 // Close down the pipes
176 close(fds[0]);
177 close(fds[1]);
178 }
179
pipe_open(const char * command)180 static int *pipe_open(const char *command)
181 {
182 // Starts a subprocess with its stdin and stdout bounad to pipes
183 // the ends of which are returned in an array
184 int argc;
185 char **argv;
186 int *fds;
187
188 argv = enargen(command,&argc);
189 fds = walloc(int,2);
190
191 if (start_sub_process(fds,argc,argv) != 0)
192 {
193 cerr << "pipe_open: failed to start subprocess: \n" << endl;
194 cerr << "pipe_open: \"" << command << "\"\n";
195 festival_error();
196 }
197
198 return fds;
199 }
200
start_sub_process(int * fds,int argc,char ** argv)201 static int start_sub_process(int *fds, int argc, char **argv)
202 {
203 // start sub_process with stdin and stdout bound to pipes whose ends
204 // are in fds[0] and fds[1]
205 int pid;
206 int in[2];
207 int out[2];
208 (void)argc;
209
210 if ((pipe(in) != 0) ||
211 (pipe(out) != 0))
212 {
213 cerr << "pipe_open: failed to open pipes\n";
214 festival_error();
215 }
216
217 switch (pid=fork())
218 {
219 case 0: /* child */
220 close(in[1]); /* close the end child isn't using */
221 dup2(in[0],0); /* reassign stdin to the pipe */
222 close(out[0]);
223 dup2(out[1],1); /* reassign stdout to the pipe */
224 execvp(argv[0],argv);
225 cerr << "pipe_open: failed to start " << argv[0] << endl;
226 exit(-1); /* should only get here on failure */
227 case -1:
228 cerr << "pipe_open: fork failed\n";
229 festival_error();
230 default: /* parent */
231 close(in[0]); /* Close unused sides of the pipes */
232 close(out[1]);
233 fds[0] = in[1];
234 fds[1] = out[0];
235 }
236
237 audsp_pid = pid;
238 return 0;
239 }
240
enargen(const char * command,int * argc)241 static char **enargen(const char *command,int *argc)
242 {
243 EST_TokenStream ts;
244 char **argv;
245 int i;
246
247 ts.open_string(command);
248 for (i=0; ts.get() != ""; i++);
249 ts.close();
250 *argc = i;
251
252 argv = walloc(char *,i+1);
253 ts.open_string(command);
254 for (i=0; i < *argc; i++)
255 argv[i] = wstrdup(ts.get().string());
256 argv[i] = 0;
257
258 return argv;
259 }
260
261 #endif
262