1 /* $Header: /home/cvs/wavplay/client.c,v 1.2 1999/12/04 00:01:20 wwg Exp $
2 * Warren W. Gay VE3WWG Tue Feb 25 22:43:40 1997
3 *
4 * CLIENT RELATED FUNCTIONS:
5 *
6 * X LessTif WAV Play :
7 *
8 * Copyright (C) 1997 Warren W. Gay VE3WWG
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation version 2 of the License.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
17 * Public License for more details (see enclosed file COPYING).
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 * Send correspondance to:
24 *
25 * Warren W. Gay VE3WWG
26 *
27 * Email:
28 * ve3wwg@yahoo.com
29 * wgay@mackenziefinancial.com
30 *
31 * $Log: client.c,v $
32 * Revision 1.2 1999/12/04 00:01:20 wwg
33 * Implement wavplay-1.4 release changes
34 *
35 * Revision 1.1.1.1 1999/11/21 19:50:56 wwg
36 * Import wavplay-1.3 into CVS
37 *
38 * Revision 1.1 1997/04/14 00:11:03 wwg
39 * Initial revision
40 */
41 static const char rcsid[] = "@(#)client.c $Revision: 1.2 $";
42
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <stdarg.h>
46 #include <string.h>
47 #include <unistd.h>
48 #include <errno.h>
49 #include <time.h>
50 #ifndef FREEBSD
51 #include <malloc.h>
52 #endif
53 #include <string.h>
54 #include <memory.h>
55 #include <signal.h>
56 #include <sys/types.h>
57 #include <sys/ipc.h>
58 #include <sys/msg.h>
59 #include <sys/wait.h>
60 #include <sys/stat.h>
61 #include <assert.h>
62 #ifndef FREEBSD
63 #include <linux/soundcard.h>
64 #else
65 #include <sys/soundcard.h>
66 #endif
67 #include "wavplay.h"
68 #include "client.h"
69
70 pid_t svrPID = (pid_t)-1; /* Forked process ID of server */
71 int svrIPC = -1; /* IPC ID of message queue */
72 static ErrFunc v_erf; /* Error reporting function */
73
74 /*
75 * Error reporting function for this source module:
76 */
77 static void
err(const char * format,...)78 err(const char *format,...) {
79 va_list ap;
80
81 if ( v_erf == NULL )
82 return; /* Only report error if we have function */
83 va_start(ap,format);
84 v_erf(format,ap); /* Use caller's supplied function */
85 va_end(ap);
86 }
87
88 /*
89 * This function is called at exit()
90 */
91 static void
close_msgq(void)92 close_msgq(void) {
93 int termstat; /* Process termination status */
94 pid_t PID; /* PID from waitpid() */
95 time_t t0, t1; /* Times for timeout */
96
97 if ( svrIPC >= 0 )
98 tosvr_bye(0,NULL); /* Tell server to exit politely */
99 else if ( svrPID != (pid_t) -1L )
100 kill(svrPID,SIGTERM); /* It has no msg queue anyhow */
101
102 /*
103 * Leave some time for the server to exit:
104 */
105 if ( svrPID != (pid_t) -1L ) { /* Did we start a fork? */
106 time(&t0); /* Start timer */
107
108 do { /* Loop while server runs */
109 if ( (PID = waitpid(-1,&termstat,WNOHANG)) == svrPID ) {
110 svrPID = (pid_t) -1L; /* Note the termination */
111 break; /* Server ended */
112 }
113 time(&t1);
114 sleep(1); /* Give up CPU */
115 } while ( PID < 1 && t1 - t0 < 4 ); /* Eventually timeout */
116 }
117
118 if ( svrIPC >= 0 )
119 MsgClose(svrIPC); /* Remove message queue */
120
121 if ( svrPID != (pid_t) -1L )
122 kill(svrPID,SIGTERM); /* Stab it again */
123 }
124
125 /*
126 * Fork the server, and get it started:
127 */
128 int
tosvr_start(ErrFunc erf)129 tosvr_start(ErrFunc erf) {
130 int e; /* Saved errno value */
131 char buf[200]; /* Argv[0] for exec'd process */
132 SVRMSG msg; /* Server message from wavplay */
133 pid_t PID; /* Process ID of terminated process */
134 int termstat; /* Termination status of the process */
135 time_t t0, t; /* Start time, current time */
136
137 v_erf = erf; /* Error reporting function */
138
139 /*
140 * Create a private message queue for the client<-->server
141 * communications.
142 */
143 if ( (svrIPC = MsgCreate()) < 0 ) {
144 err("%s: creating message queue",sys_errlist[errno]);
145 return -1;
146 }
147
148 sprintf(buf,"WAVSVR=%d",svrIPC); /* Pass this as argv[0] */
149
150 /*
151 * Create a fork, that will then exec wavplay as a server:
152 */
153 if ( (svrPID = fork()) == (pid_t)0L ) {
154 /*
155 * Child process must now start the wavplay command as server:
156 */
157 if ( cmdopt_x )
158 execl(env_WAVPLAYPATH,buf,"-x",NULL); /* Debug On */
159 else execl(env_WAVPLAYPATH,buf,NULL); /* No debug yet */
160
161 /* Returns only if error occurs */
162 fprintf(stderr,"%s: exec of %s\n",sys_errlist[errno],env_WAVPLAYPATH);
163 exit(2);
164
165 } else if ( svrPID < 0 ) {
166 e = errno;
167 err("%s: forking the server process",sys_errlist[errno]);
168 MsgClose(svrIPC);
169 errno = e; /* Restore error code */
170 return -1;
171 }
172
173 atexit(close_msgq); /* Invoke close_msgq() at exit() time */
174
175 time(&t0); /* Start clock */
176
177 while ( 1 ) {
178 if ( !MsgFromServer(svrIPC,&msg,IPC_NOWAIT) ) {
179 /*
180 * We have a message from the server:
181 */
182 if ( msg.msg_type == ToClnt_Ready )
183 return 0; /* We connected to server OK! */
184 fprintf(stderr,"Bad server message: %d\n",(int)msg.msg_type);
185
186 } else {
187 while ( (PID = waitpid(-1,&termstat,WNOHANG)) == -1 && errno == EINTR )
188 ; /* Repeat interrupted system call */
189 if ( PID > 0 ) {
190 /*
191 * We have terminated process!
192 */
193 err("Server process ID %ld terminated: %s",PID,ProcTerm(termstat));
194 return -1;
195
196 } else sleep(1);
197 }
198
199 time(&t);
200 if ( t - t0 > 5 )
201 break;
202 }
203
204 err("Timeout: starting server.");
205 kill(svrPID,SIGTERM);
206 return -1;
207 }
208
209 /*
210 * Send simple command to server:
211 */
212 int
tosvr_cmd(MSGTYP cmd,int flags,ErrFunc erf)213 tosvr_cmd(MSGTYP cmd,int flags,ErrFunc erf) {
214 SVRMSG msg;
215 int rc;
216
217 v_erf = erf; /* Error reporting function */
218
219 msg.msg_type = cmd;
220 msg.bytes = 0; /* Simple commands have no other data */
221
222 if ( (rc = MsgSend(svrIPC,&msg,flags,MSGNO_SRVR)) != 0 && erf != NULL )
223 err("%s: Sending server message '%s'",
224 msg_name(cmd),
225 sys_errlist[errno]);
226 return rc; /* Zero indicates success */
227 }
228
229 /*
230 * Send a pathname to the server:
231 */
232 int
tosvr_path(const char * pathname,int flags,ErrFunc erf)233 tosvr_path(const char *pathname,int flags,ErrFunc erf) {
234 SVRMSG msg;
235 int z;
236
237 v_erf = erf; /* Error reporting function */
238
239 msg.msg_type = ToSvr_Path;
240 strncpy(msg.u.tosvr_path.path,pathname,sizeof msg.u.tosvr_path)
241 [sizeof msg.u.tosvr_path.path - 1] = 0;
242 msg.bytes = strlen(msg.u.tosvr_path.path);
243
244 if ( (z = MsgToServer(svrIPC,&msg,flags)) != 0 && erf != NULL )
245 err("%s: Sending server message 'path'",sys_errlist[errno]);
246 return z;
247 }
248
249 /*
250 * Tell server about new data bits per sample setting:
251 */
252 int
tosvr_bits(int flags,ErrFunc erf,int bits)253 tosvr_bits(int flags,ErrFunc erf,int bits) {
254 SVRMSG msg;
255 int z;
256
257 v_erf = erf; /* Error reporting function */
258
259 msg.msg_type = ToSvr_Bits;
260 msg.u.tosvr_bits.DataBits = bits;
261 msg.bytes = sizeof msg.u.tosvr_bits;
262
263 if ( (z = MsgToServer(svrIPC,&msg,flags)) != 0 && erf != NULL )
264 err("%s: Sending server message 'bits'",sys_errlist[errno]);
265
266 return z;
267 }
268
269 /*
270 * Tell server to start at a new sample number:
271 */
272 int
tosvr_start_sample(int flags,ErrFunc erf,UInt32 sample)273 tosvr_start_sample(int flags, ErrFunc erf, UInt32 sample) {
274 SVRMSG msg;
275 int z;
276
277 v_erf = erf; /* Error reporting function */
278
279 msg.msg_type = ToSvr_StartSample;
280 msg.u.tosvr_start_sample.StartSample = sample;
281 msg.bytes = sizeof msg.u.tosvr_start_sample;
282
283 if ( (z = MsgToServer(svrIPC,&msg,flags)) != 0 && erf != NULL )
284 err("%s: Sending server message 'start_sample'",sys_errlist[errno]);
285
286 return z;
287 }
288 /*
289 * Tell server to use new sampling rate:
290 */
291 int
tosvr_sampling_rate(int flags,ErrFunc erf,UInt32 sampling_rate)292 tosvr_sampling_rate(int flags,ErrFunc erf,UInt32 sampling_rate) {
293 SVRMSG msg;
294 int z;
295
296 v_erf = erf; /* Error reporting function */
297
298 msg.msg_type = ToSvr_SamplingRate;
299 msg.u.tosvr_sampling_rate.SamplingRate = sampling_rate;
300 msg.bytes = sizeof msg.u.tosvr_sampling_rate;
301
302 if ( (z = MsgToServer(svrIPC,&msg,flags)) != 0 && erf != NULL )
303 err("%s: Sending server message 'sampling_rate'",sys_errlist[errno]);
304
305 return z;
306 }
307
308 /*
309 * Tell server about Mono/Stereo preference:
310 */
311 int
tosvr_chan(int flags,ErrFunc erf,Chan chan)312 tosvr_chan(int flags,ErrFunc erf,Chan chan) {
313 SVRMSG msg;
314 int z;
315
316 v_erf = erf; /* Error reporting function */
317
318 msg.msg_type = ToSvr_Chan;
319 msg.u.tosvr_chan.Channels = chan;
320 msg.bytes = sizeof msg.u.tosvr_chan;
321
322 if ( (z = MsgToServer(svrIPC,&msg,flags)) != 0 && erf != NULL )
323 err("%s: Sending server message 'tosvr_chan'",sys_errlist[errno]);
324
325 return z;
326 }
327
328 /*
329 * Tell server to start recording:
330 */
331 int
tosvr_record(int flags,ErrFunc erf,Chan Channels,UInt32 SamplingRate,UInt16 DataBits)332 tosvr_record(int flags,ErrFunc erf,Chan Channels,UInt32 SamplingRate,UInt16 DataBits) {
333 SVRMSG msg;
334 int z;
335
336 v_erf = erf; /* Error reporting function */
337
338 msg.msg_type = ToSvr_Record;
339 msg.u.tosvr_record.Channels = Channels;
340 msg.u.tosvr_record.SamplingRate = SamplingRate;
341 msg.u.tosvr_record.DataBits = DataBits;
342 msg.bytes = sizeof msg.u.tosvr_record;
343
344 if ( (z = MsgToServer(svrIPC,&msg,flags)) != 0 && erf != NULL )
345 err("%s: Sending server message 'tosvr_record'",sys_errlist[errno]);
346
347 return z;
348 }
349
350 /*
351 * Tell server about our current debug level setting:
352 */
353 int
tosvr_debug(int flags,ErrFunc erf,int bDebugMode)354 tosvr_debug(int flags,ErrFunc erf,int bDebugMode) {
355 SVRMSG msg;
356 int z;
357
358 v_erf = erf; /* Error reporting function */
359
360 msg.msg_type = ToSvr_Debug;
361 msg.u.tosvr_debug.bDebugMode = bDebugMode;
362 msg.bytes = sizeof msg.u.tosvr_debug;
363
364 if ( (z = MsgToServer(svrIPC,&msg,flags)) != 0 && erf != NULL )
365 err("%s: Sending server message 'tosvr_debug'",sys_errlist[errno]);
366
367 return z;
368 }
369
370 /* $Source: /home/cvs/wavplay/client.c,v $ */
371