
/*
 * This file is a product of Sun Microsystems, Inc. and is provided for
 * unrestricted use provided that this legend is included on all tape
 * media and as a part of the software program in whole or part.  Users
 * may copy or modify this file without charge, but are not authorized to
 * license or distribute it to anyone else except as part of a product
 * or program developed by the user.
 * 
 * THIS FILE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
 * 
 * This file is provided with no support and without any obligation on the
 * part of Sun Microsystems, Inc. to assist in its use, correction,
 * modification or enhancement.
 * 
 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS FILE
 * OR ANY PART THEREOF.
 * 
 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
 * or profits or other special, indirect and consequential damages, even
 * if Sun has been advised of the possibility of such damages.
 * 
 * Sun Microsystems, Inc.
 * 2550 Garcia Avenue
 * Mountain View, California  94043
 */

/*
Broadcast your audio input to all the displays mentioned
	in the command line up to 64 machines.
*/
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <stdio.h>
#include "audio.h"

#define w_WIDTH 400
#define w_HEIGHT 200
#define BUT_HEIGHT      30
#define BUT_WIDTH       80
#define MARGIN 20
#define NUM_LEVELS 22
#define RIGHT_EDGE  (w_WIDTH - MARGIN - BUT_WIDTH)
#define V_SIZE  ((w_WIDTH - MARGIN - MARGIN)/NUM_LEVELS)

#define TRUE    1
#define MAXHOSTS    64

typedef struct  {
	Display         *xdisplay;
	char            *name;
	int             rec_vol;
	int             play_vol;
}       Windata;
Windata         local, machine[MAXHOSTS];
static	char	*audio_hosts[MAXHOSTS];
static	int	num_machines=0;
static	char	*hosts[MAXHOSTS];
static	int	num_hosts=0;

char **all_hosts(i)
int	*i;
{
	*i = num_machines ;
	return( audio_hosts );
}

parse_for_names()
{
FILE	*fd, *fopen();
int	end =0,a,b,c,d,e;
char	name [100];
	fd = fopen("/etc/hosts", "r");
	while (!end)
	{
		e =  getc(fd);
		if (e == #')
			to_eol(fd);
		else
		{
			ungetc( e, fd );
			end = (fscanf( fd, "%d.%d.%d.%d %s",&a,&b,&c,&d,  name)== EOF );
			to_eol(fd);
			if (!end && (( a == 192 )&&(strlen(name))))
			{
				hosts[num_hosts] = (char *)malloc(strlen(name) + 3);
				sprintf( (char *)hosts[num_hosts] ,"%s:0", name );
				num_hosts++;
			}
		}
		end = (e == EOF );
	}
	fclose(fd);
}

to_eol(fd)
FILE    *fd;
{
int	c;
	while(c = getc(fd))
		if ((c == \n')||(c == EOF))
			break;
}

connect_to_machines(local_display, argc, argv)
Display	*local_display;
int     argc;
char	**argv;
{
char	*name;
char	**mhost = hosts;
int	i;
	if ( !argc )
	{
		hosts[num_hosts] = (char *)getenv("DISPLAY");/*takes localhosts*/
		num_hosts = 1;
	}
	else
	{
		if ((*argv[0]== -')&&(argv[0][1] == f'))/*takes /etc/hosts*/
			parse_for_names();
		else
			while (*argv)	/* command line argc as hosts */
				hosts[num_hosts++]= *argv++;
	}
	hosts[num_hosts] = NULL;
	while( name = *mhost ++ )
	{
		if (!(machine[num_machines].xdisplay
			= XOpenDisplay( name ))) {
                        (void)printf("Open Display Error:");
                        (void)printf("Cannot open host <%s>\n",name);
                        continue;
                }
		machine[num_machines].name  = name;
                if (!start_audio(machine[num_machines]))
                        continue ; 
		machine[num_machines].play_vol  = 27 + MIN_VOLUME;
		machine[num_machines].rec_vol  = 20 + MIN_VOLUME;
		audio_hosts[num_machines] = name;
		num_machines++ ;
	}
	if (! num_machines)
	{
		 fprintf(stderr,"cannot open any hosts\n");
		 exit(0);
	}
	else
	{
		fprintf( stderr, "hosts accessed =");
		for (i = 0; i < num_machines; i++)
			 fprintf(stderr,"\t%s,", machine[i].name );
				 fprintf( stderr, ".\n");
	}
	local.name = (char *)getenv("DISPLAY");
	local.xdisplay = local_display;
	local.play_vol  = 27 + MIN_VOLUME;
	local.rec_vol  = 20 + MIN_VOLUME;
	if (!start_audio(local))     /* sets up audio*/
		fprintf(stderr,"cannot open local audio\n" );
}

quit_proc()
{
int	i;
	XAudioPlayOff(local.xdisplay,1);
	clean_up(local.xdisplay);	/* let xview do the rest */
	for (i = 0; i < num_machines; i++ )
	{
		XAudioPlayOff(machine[i].xdisplay,1);
		clean_up(machine[i].xdisplay);
		quit_x(machine[i]);
	}
}

start_audio(xwin)
Windata         xwin;
{
	/* remote host */
	if (XAudioOpen(xwin.xdisplay) < 1)
	{
		(void)fprintf(stderr,"cannot open host audio %s.\n", xwin.name);
		return(0);
	}
	XAudioSetVolume(xwin.xdisplay, xwin.play_vol, xwin.rec_vol);
	XFlush(xwin.xdisplay);
	return(1);
}

/* clean up the audio stuff that has been opened */
clean_up(xdisplay)
Display *xdisplay;
{
int     closed;
        while( !( closed = XAudioClose(xdisplay)))
        {
                (void)fprintf(stderr,"waiting closed = %d.\n",closed);
                sleep(1);
        }
}

quit_x(xwin)
Windata  xwin;
{
        XFlush(xwin.xdisplay);
        XCloseDisplay(xwin.xdisplay);
}

/*
	Globals for the following functions
*/
int	from_file;
char	play_file[200];
int	dropped = 0;
int	fd = 0;

start_file(file, fromfile, forced ) 
char	*file;
{
	if ( fromfile | forced)
	{
		if (file != NULL)
			strcpy(play_file, file);
		if (fd)
		{
			close(fd);
			fd=0;
		}
		if (play_file)
		{
			fd = open(play_file,O_RDONLY );	
			if (fd <= 0)
			{
				fprintf(stderr,"Cannot open file %s.\n", play_file);
				fd = 0;
			}
		}
		if (!forced)
			XAudioPlayOff(local.xdisplay, 1);
		if (from_file )
			XAudioRecordOff(local.xdisplay);
	}
	else
	{
		if (fd)
		{
			close(fd);
			fd=0;
		}
	}
	from_file = fromfile;
	dropped = forced;
}

#define	EACH_BUFF  ONE_SECOND_DATA_SIZE +10
do_audio()
{
int	i, dose = 0;
static	char	buffer[WRITE_SIZE];
static	int	sizeofbuffer;
static	int	delay[MAXHOSTS] ={
				0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
				0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
				0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
				0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,} ;
        if (from_file | dropped)
	{
		if (fd <= 0)
			return;
		for (i=0; i< num_machines;i++)	/* clean out last buffer */
			if (delay[i])
			{
				(void)XAudioPlay(machine[i].xdisplay,
					buffer+sizeofbuffer-delay[i],
					delay[i]);
				dose= (dose > delay[i])? dose: delay[i];
			}
		/* slow down a little bit to get in sync */
		if (dose)
		{
			dose =(dose/8192.0 - 1.0) * 1000000.0  ;
			usleep(dose);
		}
		sizeofbuffer = read(fd,buffer,EACH_BUFF);
		for (i=0; i< num_machines;i++)
			delay[i]=XAudioPlay(machine[i].xdisplay,buffer,sizeofbuffer);
		if (sizeofbuffer != EACH_BUFF)
		{
			close(fd);
			fd = 0;
			dropped = 0;
			bzero(delay, sizeof(delay));
		}
	}
	else
	{
		if (fd )
		{
			close(fd);
			fd = 0;
			dropped = 0;
		}
		sizeofbuffer = XAudioRecord(local.xdisplay,buffer);
		for (i=0; i< num_machines;i++)
			(void)XAudioPlay(machine[i].xdisplay,buffer,sizeofbuffer);
	}
}

change_volume(rec,i)
{
int     n;
        if (rec)
        {
                local.rec_vol = i + MIN_VOLUME ;
                XAudioSetVolume(local.xdisplay, local.play_vol, local.rec_vol);
        }
        else
        {   
                for (n=0; n < num_machines; n++)
                {
                        machine[n].play_vol = i  + MIN_VOLUME;
                        XAudioSetVolume(machine[n].xdisplay,
                                machine[n].play_vol, machine[n].rec_vol);
                }
        }
}
