1 
2 /*
3  * xa_ipc.c
4  *
5  * Copyright (C) 1995-1998,1999 by Mark Podlipec.
6  * All rights reserved.
7  *
8  * This software may be freely used, copied and redistributed without
9  * fee for non-commerical purposes provided that this copyright
10  * notice is preserved intact on all copies.
11  *
12  * There is no warranty or other guarantee of fitness of this software.
13  * It is provided solely "as is". The author disclaims all
14  * responsibility and liability with respect to this software's usage
15  * or its effect upon hardware or computer systems.
16  *
17  */
18 /****************
19  * Rev History
20  *
21  * 03Jun95 - Created
22  * *****96 - did some stuff
23  * *****97 - did a little more
24  * *****98 - wished I could rewrite it
25  * 21Feb99 - Change AUDIO_ON to be AUDIO_PREP then AUDIO_ON
26  *
27  *******************************/
28 
29 
30 #include "xanim.h"
31 #include <Intrinsic.h>
32 #include <StringDefs.h>
33 #include <Shell.h>
34 #include <sys/signal.h>
35 
36 #ifdef XA_SOCKET
37 #include <sys/socket.h>
38 #endif
39 
40 #ifdef XA_SELECT
41 #include <sys/select.h>
42 #endif
43 
44 #ifdef VMS
45 #include <lib$routines.h>
46 #include <starlet.h>
47 #ifdef R3_INTRINSICS
48 typedef void *XtPointer;
49 #endif
50 #endif
51 
52 #include "xa_ipc.h"
53 
54 XtAppContext	theAudContext;
55 Display		*theAudDisp;
56 xaULONG		xa_audio_present;
57 xaULONG		xa_audio_status;
58 XA_AUD_FLAGS *audiof;
59 
60 
61 #ifdef XA_AUDIO
62 
63 /* POD NOTE: Check for NOFILE defined in parms.h??? */
64 #ifndef FD_SETSIZE
65 #define FD_SETSIZE 64
66 #endif
67 
68 static xaULONG audio_debug_flag = xaFALSE;
69 xaLONG xa_child_last_time = 0;
70 int xa_audio_parent_pid = -1;
71 
72 #define AUD_DEBUG if (audio_debug_flag == xaTRUE)
73 
74 
75 extern xaULONG xa_audio_hard_buff;   /* AUDIO DOMAIN */
76 extern xaLONG xa_av_time_off;
77 extern void New_Merged_Audio_Output();
78 extern int xa_aud_fd;
79 extern xaUBYTE *xa_audcodec_buf;
80 extern xaULONG xa_audcodec_maxsize;
81 extern xaULONG xa_kludge2_dvi;
82 extern xaULONG xa_kludge900_aud;
83 
84 /**** Extern xa_audio Functions *****/
85 extern void XA_Audio_Setup();
86 extern xaULONG (*XA_Audio_Init)();
87 extern void (*XA_Audio_Kill)();
88 extern void (*XA_Audio_Off)();
89 extern void (*XA_Audio_Prep)();
90 extern void (*XA_Audio_On)();
91 extern xaULONG (*XA_Closest_Freq)();
92 extern void  (*XA_Set_Output_Port)();
93 extern void  (*XA_Speaker_Tog)();
94 extern void  (*XA_Headphone_Tog)();
95 extern void  (*XA_LineOut_Tog)();
96 void XA_Audio_Init_Snd();
97 extern xaULONG XA_IPC_Sound();
98 extern xaLONG XA_Time_Read();
99 extern void XA_Read_Audio_Delta();
100 
101 
102 XA_AUD_HDR *xa_aud_hdr_start,*xa_aud_hdr_cur;
103 xaULONG xa_aud_hdr_num = 0;
104 
105 void XA_Child_Loop();
106 void XA_Child_BOFL();
107 void XA_Child_Dies();
108 void XA_Child_Dies1();
109 
110 xaULONG XA_IPC_Receive();
111 xaULONG XA_IPC_Send();
112 void XA_Audio_Child();
113 xaULONG XA_Video_Send2_Audio();
114 xaULONG XA_Video_Receive_Ack();
115 xaULONG XA_Audio_Receive_Video_CMD();
116 xaUBYTE *XA_Audio_Receive_Video_Buf();
117 xaULONG XA_Audio_Send_ACK();
118 xaULONG XA_Child_Find_File();
119 void XA_IPC_Reset_AV_Time();
120 void Free_SNDs();
121 
122 extern XA_SND *xa_snd_cur;
123 extern xaLONG xa_time_audio;
124 extern xaULONG xa_timelo_audio;
125 
126 static xaULONG xa_ipc_cmd_id = 1;
127 
128 int xa_audio_fd[2];    /* audio child reads this, video writes this */
129 int xa_video_fd[2];    /* video reads this, audio child writes this */
130 
131 xaLONG xa_audio_child = -1;
132 
133 /************ XAnim Audio Child Code ***********************************/
134 
135 /***************************************
136  *  Routine for sending a buffer across the pipe. Handles partial writes
137  *  caused to interrupts, full buffers, etc.
138  *
139  *  ? Implement Timeout ?
140  **************/
XA_IPC_Send(fd,p,len,who)141 xaULONG XA_IPC_Send(fd,p,len,who)
142 int fd;
143 char *p;
144 int len;
145 int who;
146 { while(len > 0)
147   { int ret;
148     ret = write( fd, p, len );
149     if (ret < 0)
150     { AUD_DEBUG fprintf(stderr,"IPC(%d) Send ERR: %d\n",who,errno);
151       return(XA_IPC_ERR);
152     }
153     else { len -= ret; p += ret; }
154   }
155   return(XA_IPC_OK);
156 }
157 
158 /***************************************
159  *  Routine for receiving a buffer across the pipe. Handles partial reads
160  *  caused to interrupts, empty buffers, etc.
161  *
162  *  ? Implement Select ?
163  **************/
XA_IPC_Receive(fd,p,len,timeout,who)164 xaULONG XA_IPC_Receive(fd,p,len,timeout,who)
165 int fd;
166 char *p;
167 int len;
168 xaLONG timeout;
169 int who;
170 { xaLONG cur_time,ack_time;
171 
172   cur_time = ack_time = XA_Time_Read();
173   ack_time += timeout;
174   do
175   { int ret;
176     ret = read( fd, p, len);
177     if (ret < 0)
178     { AUD_DEBUG fprintf(stderr,"IPC(%d) Receive ERR %d\n",who,errno);
179       return(XA_IPC_ERR);
180     }
181     else  /* ?POD overrun ever possible??? */
182     { len -= ret; if (len <= 0) break;
183       p += ret;
184     }
185     cur_time = XA_Time_Read();
186   } while(cur_time < ack_time);
187 
188   if (len != 0)
189   { AUD_DEBUG fprintf(stderr,"IPC(%d) Receive TimeOut %dms\n",who,timeout);
190     return(XA_IPC_TOD);
191   }
192 
193   return(XA_IPC_OK);
194 }
195 
196 /***************************************
197  * This routine blocks until something is ready on fd or
198  * until a timeout occurrs.
199  *
200  * Timeout is in milliseconds.
201  **************/
XA_IPC_Select(fd,timeout,who)202 xaULONG XA_IPC_Select(fd,timeout,who)
203 int fd;
204 xaLONG timeout;
205 int who;
206 { int ret,tt_sec,tt_usec;
207   int width = FD_SETSIZE;
208   fd_set readfds, writefds, exceptfds;
209   struct timeval t_timeout;
210 
211   tt_sec = timeout / 1000;
212   tt_usec = timeout - (tt_sec * 1000);
213   tt_usec *= 1000;
214 
215 /* AUD_DEBUG fprintf(stderr,"tt_sec %d tt_usec %d\n",tt_sec,tt_usec); */
216 
217   FD_ZERO(&readfds);
218   FD_SET( fd , &readfds);
219   FD_ZERO(&writefds);
220   FD_ZERO(&exceptfds);
221   t_timeout.tv_sec =  tt_sec;
222   t_timeout.tv_usec = tt_usec;
223 
224   ret = select(width, &readfds, &writefds, &exceptfds, &t_timeout);
225 
226   if (ret < 0) AUD_DEBUG fprintf(stderr,"AUD select ERR: %d\n",errno);
227   return(ret);
228 }
229 
230 /***************************************
231  * Routine for having the Video Process receive keep alive message.
232  *
233  * ack_flag is number of ms to wait for ACK.
234  *********/
XA_Video_Receive_Ack(ack_flag)235 xaULONG XA_Video_Receive_Ack(ack_flag)
236 xaULONG ack_flag;
237 {
238   XA_IPC_HDR ipc_ack;
239   xaULONG ret;
240 
241   /*** Read ACK */
242   ret = XA_IPC_Receive(xa_video_fd[XA_FD_READ],((char *)(&ipc_ack)),
243                 (sizeof(XA_IPC_HDR)),ack_flag,XA_IAM_VIDEO);
244   if (ret != XA_IPC_OK)
245         { AUD_DEBUG fprintf(stderr,"Vid chunk Ack Err\n"); return(xaFALSE); }
246   return(xaTRUE);
247 }
248 
249 /***************************************
250  *  Routine for having the Video Process send a Command with
251  *  optional Command Acknowledgement and option data buffer.
252  *
253  *  ack_flag is number of ms to wait for ACK. If 0, then no ACK is checked
254  *  for.
255  **************/
XA_Video_Send2_Audio(cmd,buf,buf_len,value,ack_flag,ack_val)256 xaULONG XA_Video_Send2_Audio(cmd,buf,buf_len,value,ack_flag,ack_val)
257 xaULONG cmd;
258 xaUBYTE *buf;
259 xaULONG buf_len;
260 xaULONG value;
261 xaULONG ack_flag;
262 xaULONG *ack_val;
263 { XA_IPC_HDR ipc_cmd,ipc_ack;
264   xaULONG ret;
265   xaLONG len;
266   char *p;
267 
268   /*** Setup Command */
269   ipc_cmd.cmd = cmd;
270   ipc_cmd.time = XA_Time_Read();
271   ipc_cmd.len = buf_len;
272   ipc_cmd.value = value;
273   ipc_cmd.id  = xa_ipc_cmd_id;
274   xa_ipc_cmd_id++;
275 
276   /*** SEND IPC Command */
277   ret = XA_IPC_Send( xa_audio_fd[XA_FD_WRITE], ((char *)(&ipc_cmd)),
278 					(sizeof(XA_IPC_HDR)), XA_IAM_VIDEO );
279   if (ret == XA_IPC_ERR)
280 	{ AUD_DEBUG fprintf(stderr,"Vid Send Cmd Err\n"); return(xaFALSE); }
281 
282 
283   /* SEND Data if Any */
284   p = (char *)(buf);
285   len = buf_len;
286   while(len > 0)
287   { int sel_ret,tlen = len;
288 
289     if (tlen > XA_IPC_CHUNK) tlen = XA_IPC_CHUNK;
290     AUD_DEBUG fprintf(stderr,"VID IPC Sendin Chunk tlen %d\n",tlen);
291     ret = XA_IPC_Send( xa_audio_fd[XA_FD_WRITE], p, tlen, XA_IAM_VIDEO );
292     if (ret == XA_IPC_ERR)
293 	{ AUD_DEBUG fprintf(stderr,"Vid Send Buf Err\n"); return(xaFALSE); }
294     p += tlen;;  len -= tlen;
295 
296     /*** wait for ACK */
297     sel_ret = XA_IPC_Select(xa_video_fd[XA_FD_READ], ack_flag,XA_IAM_VIDEO);
298     if (sel_ret <= 0)
299     {
300       AUD_DEBUG fprintf(stderr,"VID: chunk Ack Timeout/err: cmd %x %d\n",cmd,sel_ret);
301       return(xaFALSE);
302     }
303 
304     /*** Read ACK */
305     do
306     {
307       ret = XA_IPC_Receive(xa_video_fd[XA_FD_READ],((char *)(&ipc_ack)),
308 		(sizeof(XA_IPC_HDR)),ack_flag,XA_IAM_VIDEO);
309       if (ret != XA_IPC_OK)
310 	{ AUD_DEBUG fprintf(stderr,"Vid chunk Ack Err\n"); return(xaFALSE); }
311     } while(ipc_ack.cmd == XA_IPC_BOFL);
312     AUD_DEBUG fprintf(stderr,"VID IPC Sent Chunk OK\n");
313   }
314 
315   /*** Look For ACK */
316   if (ack_flag)
317   { int sel_ret = XA_IPC_Select(xa_video_fd[XA_FD_READ], ack_flag,XA_IAM_VIDEO);
318     if (sel_ret <= 0)
319     {
320       AUD_DEBUG fprintf(stderr,"VID: Ack Timeout/err: cmd %x %d\n",cmd,sel_ret);
321       return(xaFALSE);
322     }
323 
324     do
325     {
326       ret = XA_IPC_Receive(xa_video_fd[XA_FD_READ],((char *)(&ipc_ack)),
327 				(sizeof(XA_IPC_HDR)),ack_flag,XA_IAM_VIDEO);
328       if (ret == XA_IPC_ERR)
329 	   {AUD_DEBUG fprintf(stderr,"Vid IPC Ack Err\n"); return(xaFALSE);}
330       else if (ret == XA_IPC_TOD)
331 	   {AUD_DEBUG fprintf(stderr,"Vid IPC Ack Timeout\n"); return(xaFALSE);}
332     } while(ipc_ack.cmd == XA_IPC_BOFL);
333 
334     if (ipc_cmd.id != ipc_ack.id)
335     {
336       AUD_DEBUG fprintf(stderr,"VID IPC ID mismatch %d %d cmd %x\n",
337 					ipc_cmd.id,ipc_ack.id,ipc_cmd.cmd);
338       return(xaFALSE);
339     }
340     if (ack_val) *ack_val = ipc_ack.value;
341   }
342 
343   AUD_DEBUG fprintf(stderr,"VID IPC Success %d %u cmd %x\n",
344 	ipc_cmd.time,ipc_ack.time,ipc_cmd.cmd);
345   return(xaTRUE);
346 }
347 
348 /***************************************
349  * Accept Command from Video Process.  Returns CMD on success
350  * or XA_IPC_ERR on failure.
351  *
352  **************/
XA_Audio_Receive_Video_CMD(ipc_cmd,timeout)353 xaULONG XA_Audio_Receive_Video_CMD(ipc_cmd,timeout)
354 XA_IPC_HDR *ipc_cmd;
355 xaLONG timeout;
356 { xaULONG ret;
357 
358   ret = XA_IPC_Receive(xa_audio_fd[XA_FD_READ], ((char *)(ipc_cmd)),
359 				(sizeof(XA_IPC_HDR)),timeout, XA_IAM_AUDIO );
360   if (ret == XA_IPC_ERR)
361 	{ AUD_DEBUG fprintf(stderr,"AUD Receive CMD Err\n"); return(XA_IPC_ERR); }
362   else if (ret == XA_IPC_TOD)
363 	{ AUD_DEBUG fprintf(stderr,"AUD Receive CMD TOD\n"); return(XA_IPC_TOD); }
364 
365   AUD_DEBUG fprintf(stderr,"AUD SUCCESS! cmd %x len %d id %d\n",
366 			ipc_cmd->cmd,ipc_cmd->len,ipc_cmd->id);
367   return(XA_IPC_OK);
368 }
369 
370 
371 /***************************************
372  * Accept Buffer from Video Process.  Returns buff_len on success
373  * or 0 on failure.
374  *
375  **************/
XA_Audio_Receive_Video_Buf(len,timeout)376 xaUBYTE *XA_Audio_Receive_Video_Buf(len,timeout)
377 xaULONG len;	/* len of buffer being sent (from ipc_cmd.len) */
378 xaLONG timeout;
379 { int blen;
380   xaUBYTE *b,*p;
381 
382   b = (xaUBYTE *)malloc( len );
383   if (b == 0) {  AUD_DEBUG fprintf(stderr,"AUD Rx BUF: malloc err\n"); return(0); }
384 
385   p = b;
386   blen = len;
387   while(blen > 0)
388   { int ret,tlen;
389     ret = XA_IPC_Select(xa_audio_fd[XA_FD_READ], 500,XA_IAM_AUDIO);
390     if (ret <= 0) { free(b); return(0); }
391 
392     tlen = blen; if (tlen > XA_IPC_CHUNK) tlen = XA_IPC_CHUNK;
393     ret = read( xa_audio_fd[XA_FD_READ], p, tlen);
394     if (ret != tlen)  /* POD improve: make while() etc */
395 	{ AUD_DEBUG fprintf(stderr,"read err %d %d\n",ret,tlen); free(b); return(0); }
396     p += tlen;
397     blen -= tlen;
398     XA_Audio_Send_ACK(XA_IPC_OK,0,0);
399     xa_child_last_time = XA_Time_Read();
400   }
401   return(b);
402 }
403 
404 
405 /***************************************
406  * This routines sends an Acknowledgement back the Video Process.
407  *
408  **************/
XA_Audio_Send_ACK(ack,id,value)409 xaULONG XA_Audio_Send_ACK(ack,id,value)
410 xaULONG ack;
411 xaULONG id;
412 xaULONG value;
413 { XA_IPC_HDR ipc_ack;
414   xaULONG ret;
415 
416   /****************** Send ACK Back to Video */
417   ipc_ack.cmd = ack;
418   ipc_ack.time = XA_Time_Read();
419   ipc_ack.len = 0;
420   ipc_ack.id  = id;
421   ipc_ack.value = value;
422   ret = XA_IPC_Send( xa_video_fd[XA_FD_WRITE], ((char *)(&ipc_ack)),
423 					(sizeof(XA_IPC_HDR)), XA_IAM_AUDIO );
424   if (ret == XA_IPC_ERR)
425   { AUD_DEBUG fprintf(stderr,"AUD Send ACK Err\n");
426     fprintf(stderr,"Audio_Send_ACK IPC ERR: dying\n");
427     XA_Child_Dies((int)(0));
428     return(XA_IPC_ERR);
429   }
430   if (ack == XA_IPC_ACK_ERR)
431   {
432      AUD_DEBUG fprintf(stderr,"Sent XA_IPC_ACK_ERR, now dyin\n");
433      XA_Child_Dies((int)(0));  /* terminate audio process */
434   }
435   return(ack);
436 }
437 
438 
439 /***************************************
440  * This routines cleans up after the Child and then
441  * exits.
442  *
443  **************/
XA_Child_Dies(dummy)444 void XA_Child_Dies(dummy)
445 int	dummy;
446 { XA_AUD_HDR *aud_hdr;
447 
448 AUD_DEBUG fprintf(stderr,"CHILD IS DYING\n");
449   aud_hdr = xa_aud_hdr_start;
450   if (aud_hdr) xa_aud_hdr_start->prev->next = 0;  /* break loop */
451   while(aud_hdr)
452   { XA_AUD_HDR *tmp_hdr = aud_hdr->next;
453    /* FREE (aud_hdr->snd) loop */
454    if (aud_hdr->filename) free(aud_hdr->filename);
455    free(aud_hdr);
456    aud_hdr = tmp_hdr;
457   }
458   if (audiof)
459   {
460     if (audiof->device) free(audiof->device);
461     free(audiof);
462   }
463   XtDestroyApplicationContext(theAudContext);
464 AUD_DEBUG fprintf(stderr,"CHILD IS DEAD\n");
465   exit(0);
466 }
467 
468 /***************************************
469  * This routine prints out a message and then calls XA_Child_Dies.
470  *
471  **************/
XA_Child_Dies1(s)472 void XA_Child_Dies1(s)
473 char *s;
474 {
475   AUD_DEBUG fprintf(stderr,"CHILD: %s\n",s);
476   XA_Child_Dies((int)(0));
477 }
478 
479 /***************************************
480  * This routine returns a XA_AUD_HDR structure.
481  * and removes it from the loop.
482  *
483  **************/
Return_Aud_Hdr(aud_hdr)484 XA_AUD_HDR *Return_Aud_Hdr(aud_hdr)
485 XA_AUD_HDR *aud_hdr;
486 { XA_AUD_HDR *tmp_hdr;
487   AUD_DEBUG fprintf(stderr,"RETURN AUD HDR\n");
488   if ((aud_hdr==0) || (xa_aud_hdr_start==0))
489 				XA_Child_Dies1("Return_Anim_Hdr err");
490   xa_aud_hdr_num--;
491   if (xa_aud_hdr_num == 0)
492   {
493     xa_aud_hdr_start = 0;
494     tmp_hdr = 0;
495   }
496   else /* removed aud_hdr from the loop */
497   {
498     tmp_hdr		= aud_hdr->prev;
499     tmp_hdr->next	= aud_hdr->next;
500     aud_hdr->next->prev	= tmp_hdr;
501   }
502   if (aud_hdr->filename) free(aud_hdr->filename);
503   free(aud_hdr);
504   return(tmp_hdr);
505 }
506 
Free_SNDs(snd)507 void Free_SNDs(snd)
508 XA_SND *snd;
509 { while (snd)
510   { XA_SND *tmp = snd;
511     if (snd->snd) { free(snd->snd); snd->snd = 0; }
512     snd = snd->next;
513     free(tmp);
514   }
515 }
516 
517 
518 /***************************************
519  * This routine allocates a XA_AUD_HDR structure.
520  *  aud_file is assumed to be consumable.
521  *
522  **************/
Get_Aud_Hdr(aud_hdr,num)523 XA_AUD_HDR *Get_Aud_Hdr(aud_hdr,num)
524 XA_AUD_HDR *aud_hdr;
525 xaULONG num;
526 {
527   XA_AUD_HDR *temp_hdr;
528   temp_hdr = (XA_AUD_HDR *)malloc( sizeof(XA_AUD_HDR) );
529   if (temp_hdr == 0) XA_Child_Dies1("Get_AUD_Hdr: malloc failed\n");
530 
531   temp_hdr->num = num;
532   temp_hdr->filename = 0;
533   temp_hdr->max_faud_size = 0;
534   temp_hdr->first_snd = 0;
535   temp_hdr->last_snd = 0;
536 
537   if (aud_hdr == 0)
538   {
539     xa_aud_hdr_start  = temp_hdr;
540     temp_hdr->next = temp_hdr;
541     temp_hdr->prev = temp_hdr;
542   }
543   else
544   {
545     temp_hdr->prev   = aud_hdr;
546     temp_hdr->next   = aud_hdr->next;
547     aud_hdr->next    = temp_hdr;
548     xa_aud_hdr_start->prev = temp_hdr;
549   }
550   return(temp_hdr);
551 }
552 
553 
554 /***************************************
555  *
556  *
557  **************/
XA_Audio_Child()558 void XA_Audio_Child()
559 { int argc = 0;
560   xa_aud_hdr_start = xa_aud_hdr_cur = 0;
561   xa_aud_hdr_num = 0;
562 
563   audiof = (XA_AUD_FLAGS *)malloc( sizeof(XA_AUD_FLAGS) );
564   if (audiof==0) XA_Child_Dies1("audiof malloc err");
565 
566   xa_audio_parent_pid = getppid();
567 
568 /* don't init */
569   audiof->enable	= xaFALSE;
570   audiof->mute		= xaFALSE;
571   audiof->newvol	= xaTRUE;
572   audiof->divtest	= 2;
573   audiof->fromfile	= xaFALSE;
574   audiof->bufferit	= xaFALSE;
575 
576   audiof->port		= DEFAULT_XA_AUDIO_PORT;
577   audiof->volume	= 0;
578   audiof->playrate	= 0;
579   audiof->device	= 0;
580 
581   signal(SIGINT,XA_Child_Dies);
582   signal(SIGPIPE,XA_Child_Dies);
583 
584   XtToolkitInitialize();
585   theAudContext = XtCreateApplicationContext();
586   /* do we need a Display? */
587   theAudDisp = XtOpenDisplay(theAudContext, NULL, "xanimaud", "XAnimAud",
588 				NULL,0,&argc,0);
589   if (theAudDisp == NULL) { TheEnd1("Unable to open display\n"); }
590 
591 /* POD DEBUGGING PURPOSES */
592   AUD_DEBUG fprintf(stderr,"CHILD IS AWAKE\n");
593 
594   XtAppAddInput(theAudContext, xa_audio_fd[XA_FD_READ],
595 		(XtPointer)XtInputReadMask,
596 		(XtInputCallbackProc)XA_Child_Loop, 0);
597 
598   /* Tell Video We're alive */
599   XA_Audio_Send_ACK(XA_IPC_OK,0,0);
600 
601   /* Have Child check for Mommy/Daddy once in a while.
602    * That way if they kick off and the Child is orphaned, it can join them.
603    */
604   XtAppAddTimeOut(theAudContext,5000,(XtTimerCallbackProc)XA_Child_BOFL,
605                                 	                (XtPointer)(NULL));
606 
607   XtAppMainLoop(theAudContext);
608 
609   XA_Child_Dies((int)(0));
610 }
611 
XA_Child_BOFL()612 void XA_Child_BOFL()
613 { xaLONG now = XA_Time_Read();
614 
615   AUD_DEBUG fprintf(stderr,"CHILD_BOFL now %d last %d ppid %d\n",
616 				now,xa_child_last_time,xa_audio_parent_pid);
617   /* 24 expiration fail safe */
618   if ( (now - xa_child_last_time) > 86400000) XA_Child_Dies1("Parents??");
619 
620   /* Mom? Dad? every 5 seconds */
621   if ( (now - xa_child_last_time) > 8000)
622   { int ppid = getppid();
623     if (ppid != xa_audio_parent_pid) XA_Child_Dies1("Parents??");
624   }
625   XtAppAddTimeOut(theAudContext,5000, (XtTimerCallbackProc)XA_Child_BOFL,
626                                 	                (XtPointer)(NULL));
627 }
628 
629 /***************************************
630  *
631  *
632  **************/
XA_Child_Loop(w,fin,id)633 void XA_Child_Loop(w,fin,id)
634 XtPointer  w;
635 int	   *fin;
636 XtInputId  *id;
637 { int ret;
638   XA_IPC_HDR ipc_cmd;
639   xaUBYTE *ipc_buff;
640 
641   AUD_DEBUG fprintf(stderr,"LoopED\n");
642 
643 /* Technically we KNOW *fin is xa_audio_fd[XA_FD_READ] */
644 
645   ret = XA_Audio_Receive_Video_CMD(&ipc_cmd, 5000);
646   if (ret == XA_IPC_ERR)
647   {
648     XtRemoveInput(*id);
649   }
650   else if (ret == XA_IPC_OK)
651   {
652     switch( ipc_cmd.cmd )
653     {
654 	/* send back status = STOPPED */
655       case XA_IPC_AUD_SETUP:
656 	AUD_DEBUG fprintf(stderr,"AUD IPC: AUD_SETUP\n");
657 	XA_Audio_Setup();
658         XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,xa_audio_status);
659 	break;
660 
661       case XA_IPC_AUD_INIT:
662 	AUD_DEBUG fprintf(stderr,"AUD IPC: AUD_INIT\n");
663 	if (xa_audio_present == XA_AUDIO_UNK) XA_Audio_Init();
664         XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,xa_audio_present);
665 	break;
666 
667       case XA_IPC_AUD_KILL:
668 	AUD_DEBUG fprintf(stderr,"AUD IPC: AUD_KILL\n");
669 	XA_Audio_Kill();
670         XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,xa_audio_status);
671 	break;
672 
673 	/* solely for returning audio status */
674       case XA_IPC_GET_STATUS:
675 	AUD_DEBUG fprintf(stderr,"AUD IPC: GET_STATUS\n");
676         XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,xa_audio_status);
677 	break;
678 
679       case XA_IPC_GET_PRESENT:
680 	AUD_DEBUG fprintf(stderr,"AUD IPC: GET_PRESENT\n");
681         XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,xa_audio_present);
682 	break;
683 
684       case XA_IPC_AUD_PREP:
685 	AUD_DEBUG fprintf(stderr,"AUD IPC: AUD_PREP  %x\n",(xaULONG)xa_snd_cur);
686 	XA_Audio_Prep();
687         XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,xa_audio_status);
688 	break;
689 
690       case XA_IPC_AUD_ON:
691 	AUD_DEBUG fprintf(stderr,"AUD IPC: AUD_ON  %x\n",(xaULONG)xa_snd_cur);
692 	XA_Audio_On();
693         XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,xa_audio_status);
694 	break;
695 
696       case XA_IPC_AUD_OFF:
697 	AUD_DEBUG fprintf(stderr,"AUD IPC: AUD_OFF\n");
698 	XA_Audio_Off(ipc_cmd.value);
699         XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,xa_audio_status);
700 	break;
701 
702       case XA_IPC_AUD_PORT:
703 	audiof->port = ipc_cmd.value;
704 	AUD_DEBUG fprintf(stderr,"AUD IPC: AUD_PORT\n");
705 	if (XA_Set_Output_Port) XA_Set_Output_Port(ipc_cmd.value);
706         XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,0);
707 	break;
708 
709       case XA_IPC_AUD_STOG:
710 	AUD_DEBUG fprintf(stderr,"AUD IPC: AUD_STOG\n");
711 	XA_Speaker_Tog(ipc_cmd.value);
712         XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,0);
713 	break;
714 
715       case XA_IPC_AUD_HTOG:
716 	AUD_DEBUG fprintf(stderr,"AUD IPC: AUD_HTOG\n");
717 	XA_Headphone_Tog(ipc_cmd.value);
718         XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,0);
719 	break;
720 
721       case XA_IPC_AUD_LTOG:
722 	AUD_DEBUG fprintf(stderr,"AUD IPC: AUD_LTOG\n");
723 	XA_LineOut_Tog(ipc_cmd.value);
724         XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,0);
725 	break;
726 
727       case XA_IPC_GET_CFREQ:
728 	{ xaULONG hfreq = ipc_cmd.value;
729 	  AUD_DEBUG fprintf(stderr,"AUD IPC: AUD_CFREQ %x freq %d\n",
730 					(xaULONG)(XA_Closest_Freq),hfreq);
731 	  hfreq = XA_Closest_Freq(hfreq);
732 	  AUD_DEBUG fprintf(stderr,"CFREQ: hfreq = %d\n",hfreq);
733           XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,hfreq);
734 	}
735 	break;
736 
737 /*POD NOTE: CFREQ must be called before this */
738       case XA_IPC_GET_BSIZE:
739 	{ AUD_DEBUG fprintf(stderr,"AUD IPC: AUD_BSIZE\n");
740           XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,xa_audio_hard_buff);
741 	}
742 	break;
743 
744       case XA_IPC_FILE:
745 	AUD_DEBUG fprintf(stderr,"AUD IPC: received FILE %d\n",ipc_cmd.value);
746 	xa_aud_hdr_cur = Get_Aud_Hdr(xa_aud_hdr_cur,ipc_cmd.value);
747 	XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,0);
748 	break;
749 
750 	/*************************
751 	 * This Command sets xa_aud_hdr_cur to Audio File num
752 	 * and then changes/sets the filename to incoming buffer
753 	 ********/
754       case XA_IPC_FNAME:
755 	AUD_DEBUG fprintf(stderr,"AUD FNAME: %d\n",ipc_cmd.value);
756         if (ipc_cmd.len)
757 	{ int file_ret = XA_Child_Find_File(ipc_cmd.value,0);
758 	  ipc_buff     = XA_Audio_Receive_Video_Buf(ipc_cmd.len,500);
759 	     /* if no such file or couldn't read name - err and exit */
760 	  if ( (ipc_buff == 0) || (file_ret == xaNOFILE) )
761 	  { ipc_buff = 0;
762 	    XtRemoveInput(*id);
763 	    fprintf(stderr,"AUD FNAME: buf %x fnum %d fret %d\n",
764 			(xaULONG)ipc_buff, ipc_cmd.value, file_ret);
765 	    XA_Audio_Send_ACK(XA_IPC_ACK_ERR,ipc_cmd.id,0);
766 	    break;
767 	  }
768 	  AUD_DEBUG fprintf(stderr,"AUD FNAME: %s \n",ipc_buff);
769 
770 		/** Add/replace name in current audio header */
771 	  if (xa_aud_hdr_cur->filename) free(xa_aud_hdr_cur->filename);
772 	  xa_aud_hdr_cur->filename = (char *)ipc_buff;   ipc_buff = 0;
773 	  ipc_cmd.len = 0;  /* we've used it */
774 	}
775 	XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,0);
776 	break;
777 
778 	/* Merges passed in file with previous file */
779       case XA_IPC_MERGEFILE:
780 	AUD_DEBUG fprintf(stderr,"AUD IPC: rcvd MERGEFILE %d\n",ipc_cmd.value);
781 	{ XA_AUD_HDR *prev_hdr = xa_aud_hdr_cur;
782 	  XA_Child_Find_File(ipc_cmd.value,0);   /* POD add check for err */
783 		/* Free previous audio if any */
784 	  if (prev_hdr->first_snd) Free_SNDs(prev_hdr->first_snd);
785 	  if (prev_hdr->filename)  free(prev_hdr->filename);
786 		/* copy selected portions */
787 	  prev_hdr->filename	  = xa_aud_hdr_cur->filename;
788 	  prev_hdr->max_faud_size = xa_aud_hdr_cur->max_faud_size;
789 	  prev_hdr->first_snd	= xa_aud_hdr_cur->first_snd;
790 	  prev_hdr->last_snd	= xa_aud_hdr_cur->last_snd;
791 	  prev_hdr->init_aud	= xa_aud_hdr_cur->init_aud;
792 		/* Free up current one */
793 	  xa_aud_hdr_cur = Return_Aud_Hdr(xa_aud_hdr_cur);
794 	  XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,0);
795 	}
796 	break;
797 
798 
799       case XA_IPC_UNFILE:
800 	AUD_DEBUG fprintf(stderr,"AUD IPC: rcvd UNFILE %d\n",ipc_cmd.value);
801 	if ( XA_Child_Find_File(ipc_cmd.value,0) == xaNOFILE)
802 	{ XtRemoveInput(*id);
803 	  fprintf(stderr,"AUD IPC: UNFILE no such file %d\n",ipc_cmd.value);
804 	  XA_Audio_Send_ACK(XA_IPC_ACK_ERR,ipc_cmd.id,0); /* err and exit */
805 	  break;
806 	}
807 	/* Find_File set's xa_aud_hdr_cur correctly above - assume it's
808          * the last one. */
809 	xa_aud_hdr_cur = Return_Aud_Hdr(xa_aud_hdr_cur);
810 	XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,0);
811 	break;
812 
813       case XA_IPC_PLAY_FILE:
814 	{ xaULONG ok;
815 	  AUD_DEBUG fprintf(stderr,"AUD IPC: received PLAY_FILE\n");
816 	  if (xa_audio_present==XA_AUDIO_OK)
817 			ok = XA_Child_Find_File(ipc_cmd.value,0);
818           if (ok == xaTRUE)
819           {
820 	    if (xa_aud_fd>=0) { close(xa_aud_fd); xa_aud_fd = -1; }
821 	    if (xa_aud_hdr_cur->filename)
822 	    {
823 	      if ( (xa_aud_fd=open(xa_aud_hdr_cur->filename,O_RDONLY,NULL)) < 0)
824 	      {
825 	        fprintf(stderr,"AUD IPC: Open file %s for audio err\n",
826 				xa_aud_hdr_cur->filename);
827 	        XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,xaFALSE);
828 	        break;
829 	      }
830 	    }
831 /*POD ?? Is buffer only used when playing from a file??? */
832 	    if ((xa_aud_hdr_cur->max_faud_size) && (xa_audcodec_buf==0))
833 	    { xa_audcodec_buf = (xaUBYTE *)malloc( xa_audcodec_maxsize );
834 	      if (xa_audcodec_buf==0) /* audio fatal */
835 	      { XtRemoveInput(*id);
836 		XA_Audio_Send_ACK(XA_IPC_ACK_ERR,ipc_cmd.id,xaFALSE);
837 		break;
838 	      }
839 	    }
840 	    if (xa_snd_cur->fpos >= 0)
841 	    {
842 	      xa_snd_cur->snd = xa_audcodec_buf;
843 	      XA_Read_Audio_Delta(xa_aud_fd,xa_snd_cur->fpos,
844 				xa_snd_cur->tot_bytes,xa_audcodec_buf);
845 	    }
846           }
847           XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,ok);
848 	}
849 	break;
850 
851       case XA_IPC_N_FILE:
852 	{ xaULONG ok;
853 	  AUD_DEBUG fprintf(stderr,"AUD IPC: received N_FILE %d\n",ipc_cmd.value);
854 	  if (xa_audio_present==XA_AUDIO_OK)
855 			ok = XA_Child_Find_File(ipc_cmd.value,0);
856 	  else ok = xaNOFILE;
857           XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,ok);
858 	}
859 	break;
860 
861       case XA_IPC_P_FILE:
862 	{ xaULONG ok;
863 	  AUD_DEBUG fprintf(stderr,"AUD IPC: received P_FILE\n");
864 	  if (xa_audio_present==XA_AUDIO_OK)
865 			ok = XA_Child_Find_File(ipc_cmd.value,1);
866 	  else ok = xaNOFILE;
867           XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,ok);
868 	}
869 	break;
870 
871       case XA_IPC_SND_INIT:
872 	{
873 	  AUD_DEBUG fprintf(stderr,"AUD IPC: SND_INIT\n");
874 	  XA_Audio_Init_Snd(xa_snd_cur);
875           XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,0);
876 	}
877 	break;
878 
879       case XA_IPC_SND_ADD:
880 	{ XA_SND *new_snd = 0;
881 	  AUD_DEBUG fprintf(stderr,"AUD IPC: SND_ADD\n");
882 	  if (ipc_cmd.len)
883 	  { xaULONG sret;
884 
885 	    if (ipc_cmd.value != xa_aud_hdr_cur->num) /* for different file */
886             {
887 	      sret = XA_Child_Find_File(ipc_cmd.value,1);
888 	      if (sret == xaNOFILE)
889 		XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,xaFALSE);
890 	    }
891 
892             new_snd = (XA_SND *)
893 			XA_Audio_Receive_Video_Buf(ipc_cmd.len,500);
894             if (new_snd)	sret = XA_IPC_Sound(xa_aud_hdr_cur,new_snd);
895 	    else		sret = 0;
896             ipc_cmd.len = 0;
897             XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,sret);
898 	  }
899 	  else XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,xaFALSE);
900 
901           /* SND_BUF MUST follow */
902           XA_Audio_Receive_Video_CMD(&ipc_cmd, 5000);
903           if (ipc_cmd.cmd != XA_IPC_SND_BUF)
904 		XA_Child_Dies1("SND_BUF Did NOT follow SND_ADD\n");
905           AUD_DEBUG fprintf(stderr,"AUD IPC: SND_BUF\n");
906           if (ipc_cmd.len)
907           { xaULONG sret = xaFALSE;
908 	    if (new_snd) new_snd->snd =
909 		(xaUBYTE *)XA_Audio_Receive_Video_Buf(ipc_cmd.len,500);
910 	    if (new_snd->snd) sret = xaTRUE;
911             XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,sret);
912             ipc_cmd.len = 0;
913           }
914           else
915 	  {
916 	    new_snd->snd = 0;
917             XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,xaTRUE);
918 	  }
919 	}
920 	break;
921 
922       case XA_IPC_SET_AUDBUFF:
923 	AUD_DEBUG fprintf(stderr,"AUD IPC: SET_AUDBUFF\n");
924         xa_aud_hdr_cur->max_faud_size = ipc_cmd.value;
925         if (xa_aud_hdr_cur->max_faud_size > xa_audcodec_maxsize)
926 		xa_audcodec_maxsize = xa_aud_hdr_cur->max_faud_size;
927 	xa_av_time_off = ipc_cmd.value;
928         XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,0);
929 	break;
930 
931       case XA_IPC_SET_KLUDGE2:
932 	AUD_DEBUG fprintf(stderr,"AUD IPC: SET_KLUDGE2\n");
933         xa_kludge2_dvi = ipc_cmd.value;
934         XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,0);
935 	break;
936 
937       case XA_IPC_SET_KLUDGE900:
938 	AUD_DEBUG fprintf(stderr,"AUD IPC: SET_KLUDGE900\n");
939         xa_kludge900_aud = ipc_cmd.value;
940         XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,0);
941 	break;
942 
943       case XA_IPC_VID_TIME:
944 	AUD_DEBUG fprintf(stderr,"AUD IPC: VID_TIME\n");
945 	xa_av_time_off = ipc_cmd.value;
946         XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,0);
947 	break;
948 
949       case XA_IPC_RST_TIME:
950 	{ xaULONG tt = XA_Time_Read();
951 	  AUD_DEBUG fprintf(stderr,"AUD IPC: RST_TIME time %d\n",tt);
952           XA_IPC_Reset_AV_Time(ipc_cmd.value);
953 	  tt = XA_Time_Read();
954 	  AUD_DEBUG fprintf(stderr,"AUD IPC: time end %d\n",tt);
955           XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,0);
956 	}
957 	break;
958 
959       case XA_IPC_AUD_ENABLE:
960         AUD_DEBUG fprintf(stderr,"AUD IPC: AUD_ENABLE\n");
961 	audiof->enable = ipc_cmd.value;
962         XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,0);
963 	break;
964 
965       case XA_IPC_AUD_MUTE:
966         AUD_DEBUG fprintf(stderr,"AUD IPC: AUD_MUTE\n");
967 	audiof->mute = ipc_cmd.value;
968 	audiof->newvol = xaTRUE;
969         XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,0);
970 	break;
971 
972       case XA_IPC_AUD_VOL:
973         AUD_DEBUG fprintf(stderr,"AUD IPC: AUD_VOL\n");
974 	audiof->volume = ipc_cmd.value;
975 	audiof->newvol = xaTRUE;
976         XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,0);
977 	break;
978 
979       case XA_IPC_AUD_RATE:
980         AUD_DEBUG fprintf(stderr,"AUD IPC: AUD_RATE\n");
981 	audiof->playrate = ipc_cmd.value;
982         XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,0);
983 	break;
984 
985       case XA_IPC_AUD_DEV:
986         AUD_DEBUG fprintf(stderr,"AUD IPC: AUD_DEV\n");
987         if (ipc_cmd.len)
988 	{
989 	  ipc_buff =  XA_Audio_Receive_Video_Buf(ipc_cmd.len,500);
990 	  if (ipc_buff)
991 	  { AUD_DEBUG fprintf(stderr,"DEVICE: %s \n",ipc_buff);
992 	    audiof->device = (char *)(ipc_buff);
993 	    ipc_buff = 0;
994 	  }
995 	  else { AUD_DEBUG fprintf(stderr,"FILE: err\n"); }
996 	  ipc_cmd.len = 0; /* indicate we've read it */
997 	}
998         XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,0);
999 	break;
1000 
1001       case XA_IPC_AUD_FFLAG:
1002         AUD_DEBUG fprintf(stderr,"AUD IPC: AUD_FFLAG\n");
1003 	audiof->fromfile = ipc_cmd.value;
1004         XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,0);
1005 	break;
1006 
1007       case XA_IPC_AUD_BFLAG:
1008         AUD_DEBUG fprintf(stderr,"AUD IPC: AUD_BFLAG\n");
1009 	audiof->bufferit = ipc_cmd.value;
1010         XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,0);
1011 	break;
1012 
1013       case XA_IPC_ERR:
1014 	XtRemoveInput(*id);
1015         XA_Audio_Send_ACK(XA_IPC_ACK_ERR,ipc_cmd.id,0); /* err and exit */
1016 	break;
1017 
1018       case XA_IPC_HELLO:
1019 	AUD_DEBUG fprintf(stderr,"AUD IPC: received Hello\n");
1020         XA_Audio_Send_ACK(XA_IPC_ACK_OK,ipc_cmd.id,0);
1021 	break;
1022 
1023       case XA_IPC_EXIT:
1024 	AUD_DEBUG fprintf(stderr,"AUD IPC: received EXIT\n");
1025 	XtRemoveInput(*id);
1026         XA_Audio_Send_ACK(XA_IPC_ACK_BYE,ipc_cmd.id,0);
1027 	XA_Child_Dies((int)(0));
1028 	break;
1029 
1030       case XA_IPC_BOFL:
1031 	AUD_DEBUG fprintf(stderr,"AUD IPC: received BOFL\n");
1032 	/* No ACK needed */
1033 	xa_child_last_time = XA_Time_Read();
1034 	break;
1035 
1036       default:
1037 	AUD_DEBUG fprintf(stderr,"AUD IPC: unknown cmd %d\n",ipc_cmd.cmd);
1038 	XtRemoveInput(*id);
1039         XA_Audio_Send_ACK(XA_IPC_ACK_ERR,ipc_cmd.id,0); /* err and exit */
1040 	break;
1041     }
1042     /* Flush len if no command uses it */
1043     if (ipc_cmd.len)
1044     {
1045 	ipc_buff =  XA_Audio_Receive_Video_Buf(ipc_cmd.len,500);
1046         free(ipc_buff); ipc_buff = 0;
1047 	XtRemoveInput(*id);
1048         XA_Audio_Send_ACK(XA_IPC_ACK_ERR,ipc_cmd.id,0); /* err and exit */
1049     } else ipc_buff = 0;
1050   } /* valid input */
1051 }
1052 
1053 /*********************************
1054  *  This routine sets up the xa_audio_fd and xa_video_fd pipes, then
1055  *  forks off the Audio Child process.
1056  *
1057  *   + The Parent returns(xaTRUE) on success, xaFALSE on failure.
1058  *   + The Child calls XA_Audio_Child().
1059  *
1060  ****************/
XA_Give_Birth()1061 xaULONG XA_Give_Birth()
1062 { int ret;
1063 #ifndef XA_SOCKET
1064   ret = pipe( xa_audio_fd );
1065   if (ret) { AUD_DEBUG fprintf(stderr,"PIPE for audio failed: %d\n",errno); }
1066   else
1067   {
1068     ret = pipe( xa_video_fd );
1069     if (ret) { AUD_DEBUG fprintf(stderr,"PIPE for video failed: %d\n",errno); }
1070     else
1071     {
1072 #else
1073   {
1074     { int sv[2];
1075       ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
1076       if (ret)  { fprintf(stderr,"IPC socketpair failed %d\n",errno);
1077 		  return(xaFALSE);
1078 		}
1079       xa_audio_fd[0]	= sv[1];  /* audio reads  */
1080       xa_video_fd[1]	= sv[1];  /* audio writes */
1081 
1082       xa_video_fd[0]	= sv[0];  /* video reads  */
1083       xa_audio_fd[1]	= sv[0];  /* video writes */
1084 #endif
1085       xa_audio_child = fork();
1086       if (xa_audio_child == 0)   /* I am the Audio Child */
1087       {
1088 	AUD_DEBUG fprintf(stderr,"I am the Child\n");
1089         XA_Audio_Child();
1090         exit(0);
1091       }
1092       else if (xa_audio_child < 0) /* Still Born */
1093       {
1094 	AUD_DEBUG fprintf(stderr,"Audio Child Still Born: %d\n",errno);
1095       }
1096       else			/* I am the Video Parent */
1097       {
1098 	AUD_DEBUG fprintf(stderr,"I am the Parent(child %d)\n",xa_audio_child);
1099         return(xaTRUE);
1100       }
1101     }
1102   }
1103   return(xaFALSE);
1104 }
1105 
1106 /*********************************
1107  * Move along Audio Header til num is matched.
1108  * returns xaTRUE if found AND has valid snd.
1109  * returns xaNOFILE if no file has that num.
1110  * returns xaFALSE if file found, but no audio attached.
1111  * Else returns xaFALSE.
1112  *
1113  * Set's global variable xa_snd_cur
1114  ****************/
1115 xaULONG XA_Child_Find_File(num,flag)
1116 xaULONG num;
1117 xaULONG flag;	/* 0 means next, 1 means prev */
1118 { XA_AUD_HDR *cur = xa_aud_hdr_cur;
1119   do
1120   {
1121 AUD_DEBUG fprintf(stderr,"num %d cnum %d  cur %x n/p %x %x  hdr %x\n",
1122 	num, cur->num, (xaULONG)cur, (xaULONG)cur->next, (xaULONG)cur->prev,
1123 	(xaULONG) xa_aud_hdr_cur);
1124     if (cur->num == num)
1125     {
1126       xa_aud_hdr_cur = cur;
1127       xa_snd_cur = cur->first_snd;
1128       if (xa_snd_cur)		return(xaTRUE);
1129       else			return(xaFALSE);
1130     }
1131     cur = (flag == 0)?(cur->next):(cur->prev);
1132   } while(cur != xa_aud_hdr_cur);
1133   return(xaNOFILE);
1134 }
1135 
1136 /*********************************
1137  *
1138  ****************/
1139 void XA_IPC_Reset_AV_Time(vid_time)
1140 xaLONG vid_time;
1141 { int xflag = xaFALSE;
1142 
1143     if (xa_snd_cur==0) { AUD_DEBUG fprintf(stderr,"AA\n"); return; }
1144     XA_Audio_Init_Snd(xa_snd_cur);
1145     /* Move to the correct snd chunk */
1146     while(xflag == xaFALSE)
1147     { xaLONG snd_time = xa_snd_cur->snd_time;
1148       if (snd_time > vid_time)
1149       { XA_SND *p_snd = xa_snd_cur->prev;
1150         AUD_DEBUG fprintf(stderr,"s>v %d %d\n",snd_time,vid_time);
1151         if (p_snd) xa_snd_cur = p_snd;
1152         else xflag = xaTRUE;
1153       }
1154       else if (snd_time < vid_time)
1155       { XA_SND *n_snd = xa_snd_cur->next;
1156         AUD_DEBUG fprintf(stderr,"s<v %d %d\n",snd_time,vid_time);
1157         if (n_snd)
1158         {
1159 	  if (n_snd->snd_time <= vid_time) xa_snd_cur = n_snd;
1160 	  else xflag = xaTRUE;
1161         }
1162         else xflag = xaTRUE;
1163       }
1164       else
1165       {
1166         AUD_DEBUG fprintf(stderr,"s=v %d %d\n",snd_time,vid_time);
1167         xflag = xaTRUE;
1168       }
1169     } /* end while xflag */
1170 
1171     /* Move within the snd chunk - HAVE NOP FLAG */
1172     if (xa_snd_cur)
1173     { XA_SND *shdr = xa_snd_cur;
1174 	/* read in from file if needed */
1175       if (xa_snd_cur->fpos >= 0)
1176       {
1177         xa_snd_cur->snd = xa_audcodec_buf;
1178         XA_Read_Audio_Delta(xa_aud_fd,xa_snd_cur->fpos,
1179 				xa_snd_cur->tot_bytes,xa_audcodec_buf);
1180       }
1181       { xaULONG tmp_cnt; xaLONG diff;
1182 
1183 	/* time diff in ms */
1184         diff =  (vid_time - shdr->snd_time); if (diff < 0) diff = 0;
1185 	/* calc num of samples in that time frame */
1186 	tmp_cnt = (diff * shdr->ifreq) / 1000;
1187 	if (tmp_cnt & 0x01) tmp_cnt--;  /* make multiple of 2 for ADPCM */
1188 	/* Init snd_hdr */
1189         XA_Audio_Init_Snd(xa_snd_cur);
1190 	if (tmp_cnt) /* not at beginning */
1191 	{ char *garb; /* play sound into garb buffer */
1192 	  garb = (char *)malloc(4 * tmp_cnt);
1193           if (garb)
1194 	  { diff = tmp_cnt - xa_snd_cur->delta(xa_snd_cur,garb,0,tmp_cnt);
1195 	    free(garb);
1196 	    if (diff != 0) fprintf(stderr,"AV Warn: rst sync err %x\n",diff);
1197 	  }
1198 	}
1199       }
1200       xa_time_audio = vid_time;
1201       xa_timelo_audio = 0;
1202     } /* end of valid xa_snd_cur */
1203 }
1204 
1205 void XA_IPC_Close_Pipes()
1206 {
1207 #ifdef XA_SOCKET
1208   if (xa_audio_fd[0] >= 0) { close(xa_audio_fd[0]); xa_audio_fd[0] = -1; }
1209   if (xa_audio_fd[1] >= 0) { close(xa_audio_fd[1]); xa_audio_fd[1] = -1; }
1210   xa_video_fd[0] = -1;
1211   xa_video_fd[1] = -1;
1212 #else
1213   if (xa_audio_fd[0] >= 0) { close(xa_audio_fd[0]); xa_audio_fd[0] = -1; }
1214   if (xa_audio_fd[1] >= 0) { close(xa_audio_fd[1]); xa_audio_fd[1] = -1; }
1215   if (xa_video_fd[0] >= 0) { close(xa_video_fd[0]); xa_video_fd[0] = -1; }
1216   if (xa_video_fd[1] >= 0) { close(xa_video_fd[1]); xa_video_fd[1] = -1; }
1217 #endif
1218 }
1219 
1220 void XA_IPC_Set_Debug(value)
1221 xaULONG value;
1222 {
1223   audio_debug_flag = value;
1224   xa_debug = value;
1225 }
1226 
1227 #else
1228 
1229 /* prevents complaints from certain AR compilers */
1230 void XA_IPC_DUMMY(c,a,b)
1231 xaULONG *c,a,b;
1232 {
1233   *c = a + b;
1234 }
1235 #endif
1236 
1237