/******************************************************************************
*									      *
*	(C) 1993 by K. Ballueder					      *
*									      *
*	See README and COPYING for details.				      *
*									      *
*	Please feel free to contact me:					      *
*		kballued@charon.physik.uni-osnabrueck.de		      *
*		kballued@jupiter.rz.uni-osnabrueck.de			      *
*									      *
******************************************************************************/


/******

  sound_linux.c  : Soundroutinen fuer BDASH
  		   Hardwarenaher Teil fuer LinuX

******/
#include "bdash.h"

#ifdef OS_UNIX

#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <linux/soundcard.h>

#ifdef SND_DEV_DSP
#	include <sys/ioctl.h>
#endif
#include "sound.h"
#include "io.h"

#define MIN(a,b) (((a)<(b))?(a):(b))

#define BLKSIZE	1024
extern int errno;
/*---------------------------------------------------------------*/

static int fd_snd_dev = -1;
static int fd_pipe[2];
static int snd_ok = 0; 

int init_snd_dev(void)
{
	int whoami;

	globale_flags.son_pid = 0;

	if(access(globale_flags.snd_dev,W_OK) != 0)
	{	perror("No access to sound device: ");
		return 0;
	}
	fd_snd_dev = open(globale_flags.snd_dev,O_WRONLY);
	if(fd_snd_dev < 0)
	{	perror("Cannot open sound device: ");
		return 0;
	}
	close(fd_snd_dev);

	if(pipe(fd_pipe) < 0)
	{	puts("Cannot create pipe for sound control!\a");
		close(fd_snd_dev);
		return 0;
	}

	/* now setup 2nd process for writing the data... */

	if((whoami = fork()) < 0)
	{	puts("Cannot create fork for sound driver!\a");
		return 0;
	}
	if(whoami != 0)	/* successfully created son */
	{	close(fd_pipe[0]);	/* close end for reading */
		globale_flags.son_pid = whoami;
		snd_ok = 1;
		return 1;
	}
	/*** Here is the code for the son... ***/		
	{
		int nr;
		struct timeval tval = {0L,0L};
		fd_set readfds;
		int written, towrite, lw;
		int blksize;

		fd_snd_dev = open(globale_flags.snd_dev,O_WRONLY);
		if(fd_snd_dev < 0)
		{	perror("Cannot open sound device: ");
			exit(1);
		}
#ifdef	SND_DEV_DSP
		blksize = ioctl(fd_snd_dev,SNDCTL_DSP_GETBLKSIZE,0);
		blksize = MIN(blksize,BLKSIZE);
		if(blksize < BLKSIZE)
			blksize =  BLKSIZE;
#else
		blksize = BLKSIZE;
#endif
		close(fd_pipe[1]);	/* close end for writing */

		FD_ZERO(&readfds); 
		FD_SET(fd_pipe[0], &readfds);

		for(;;)
		{	FD_SET(fd_pipe[0], &readfds);
			select(fd_pipe[0]+1, &readfds, NULL, NULL, NULL);
			if(! FD_ISSET(fd_pipe[0], &readfds))
			{	FD_SET(fd_pipe[0], &readfds);
				continue;
			}
			if(read(fd_pipe[0], &nr, sizeof(int))==0)
				exit(0);
			close(fd_snd_dev);
			/* praying that noone grabs snd_device away... */
			fd_snd_dev = open(globale_flags.snd_dev,O_WRONLY);
			if(fd_snd_dev < 0)
			{	perror("Cannot open sound device: ");
				exit(1);
			}
#ifdef SND_DEV_DSP
			ioctl(fd_snd_dev,SNDCTL_DSP_SPEED,sounds[nr].rate);
#endif
			towrite=sounds[nr].len;
			written = 0;
			do
			{	FD_SET(fd_pipe[0], &readfds);
				written += lw = write(fd_snd_dev, ((char *)sounds[nr].bufstart)+written,
						MIN(blksize,towrite-written));
#ifdef SND_DEV_DSP
				ioctl(fd_snd_dev,SNDCTL_DSP_SYNC,0);
#endif
			}	
			while(written < towrite
			 &&
				(select(fd_pipe[0]+1, &readfds,NULL,NULL,&tval) < 1));
		
		}
	}
}
void  do_it(int nr)
{
	if(snd_ok)
		write(fd_pipe[1],&nr, sizeof(int));
}
#endif
