/*
$Id: audio_esd.c,v 1.6 1999/10/28 08:58:24 daeron Exp $
*/

#include <esd.h>

static int openAudioDevice(esd_format_t esdFormat, SAudioFileInfo *afInfo);
static int closeAudioDevice(int audiofd);
static int initAudioDevice(int audiofd, SAudioFileInfo *afInfo);

static int writeAudioData(int audiofd, SAudioFileInfo *afInfo);

int
SPerformAudio(SAudioFileInfo *afInfo)
{
	int		audiofd;
	esd_format_t	esdFormat = 0;

	esdFormat |= (afInfo->SampleWidth == 8) ? ESD_BITS8 : ESD_BITS16;
	esdFormat |= (afInfo->Channels == 1) ? ESD_MONO : ESD_STEREO;
	
	audiofd = openAudioDevice(esdFormat, afInfo);
	if (audiofd == -1) {
		return -1;
	}

	if (writeAudioData(audiofd, afInfo) == -1) {
		closeAudioDevice(audiofd);
		SDestroyAudioFileInfo(afInfo);
		return -1;
	}
	
	closeAudioDevice(audiofd);
	SDestroyAudioFileInfo(afInfo);
	
	return 0;
}

static int
openAudioDevice(esd_format_t esdFormat, SAudioFileInfo *afInfo)
{
	int	audiofd;
	
	audiofd = esd_play_stream_fallback(esdFormat, afInfo->SampleRate, NULL, PACKAGE);
	if (audiofd == -1)
		SErrorCode = SERR_DEVOPEN;
#ifdef DEBUG
	else
		fprintf(stderr, "-=> connection to esd opened\n");
#endif
	return audiofd;
}

static int
closeAudioDevice(int audiofd)
{
	assert(audiofd > 0);
	
	if (close(audiofd) == -1) {
		SErrorCode = SERR_DEVCLOSE;
		return -1;
	}
#ifdef DEBUG
	else
		fprintf(stderr, "<=- connection to esd closed\n");
#endif
	return 0; 
}

static int
writeAudioData(int audiofd, SAudioFileInfo *afInfo)
{
	char    *buffer;                /* audio buffer */
	long    curFrame;               /* current framecount */
	long    blkFrames;              /* number of frames in current audio block */
	int     blockSize = 4096;       /* Size of an audio block buffer in frames */
#ifdef DEBUG
	fprintf(stderr, " >> writing data\n");
#endif
	
	buffer = (char *) malloc( blockSize * (afInfo->SampleWidth/8) * afInfo->Channels);
	if (!buffer) {
		SErrorCode = SERR_NOMEMORY;
		return -1;
	}
	
	curFrame = 0;
	while (curFrame < afInfo->FrameCount) {
		if ((blkFrames = (afInfo->FrameCount - curFrame)) > blockSize) {
			blkFrames = blockSize;
		}

		if (afReadFrames(afInfo->FileHandle, AF_DEFAULT_TRACK, buffer, blkFrames) < 1) {
#ifdef DEBUG
			fprintf(stderr, " >> frames written     %d\n", curFrame);
#endif
			free(buffer);
			SErrorCode = SERR_READ;
			return -1;
		}
		if (write(audiofd, buffer, blkFrames * (afInfo->SampleWidth/8) * afInfo->Channels) == -1) {
			free(buffer);
			SErrorCode = SERR_DEVWRITE;
			return -1;
		}
		curFrame += blkFrames;
	}
#ifdef DEBUG
	fprintf(stderr, " >> frames written     %d\n", curFrame);
#endif

	free(buffer);
	return 0;
}

