/*
$Id: audio_solaris.c,v 1.9 1999/11/17 23:05:34 daeron Exp $
*/

/* Thanks to Eric Lassauge <lassauge@mail.dotcom.fr> for providing
 * additional Solaris support
 */

#ifdef HAVE_SYS_AUDIOIO_H
#include <sys/audioio.h>
#elif defined(HAVE_SYS_AUDIO_IO_H)
#include <sys/audio.io.h>
#elif defined(HAVE_SUN_AUDIOIO_H)
#include <sun/audioio.h>
#endif

static int openAudioDevice(char *audiodev, int mode);
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;
	
	/* Open audio device */
	audiofd = openAudioDevice(SGetStringForKey(S_DEVICE), O_WRONLY);
	if (audiofd == -1)
		return -1;
	/* Play with audio device */
	if (initAudioDevice(audiofd, afInfo) == -1) {
		closeAudioDevice(audiofd);
		SDestroyAudioFileInfo(afInfo);
		return -1;
	}
	
	/* Clean up */
	closeAudioDevice(audiofd);
	SDestroyAudioFileInfo(afInfo);
	
	return 0;
}

/* Open audio device */
static int
openAudioDevice(char *audiodev, int mode)
{
	int	audiofd;
	
	assert(audiodev);
	
	audiofd = open(audiodev, mode);
	
	if (audiofd == -1)
		SErrorCode = SERR_DEVOPEN;
#ifdef DEBUG
	else
		fprintf(stderr, "-=> audio device opened\n");
#endif

	return audiofd;
}

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

/* Initialize audio device for sound playback */
static int
initAudioDevice(int audiofd, SAudioFileInfo *afInfo)
{
	audio_info_t	info;
#ifdef DEBUG
	fprintf(stderr, " >> initializing audio device\n");
#endif

	AUDIO_INITINFO(&info);
	info.play.port = AUDIO_SPEAKER;
	switch (afInfo->FileFormat) {
		case AF_FILE_AIFF:
			info.play.encoding = AUDIO_ENCODING_LINEAR;
                        break;
		case AF_FILE_WAVE:
			info.play.encoding = AUDIO_ENCODING_LINEAR;
			/* NOTE: it seems that, at least on a SPARCstation 5
			 * with "SUNW,CS4231" audio device, the hardware can't
			 * play 8 bits PCM (which is what most WindowMaker
			 * Wave files are !)
			 */
                        break;
		case AF_FILE_NEXTSND:
			/* Add use of compression field to set encoding */
			if (afInfo->Compression)
				/* AudioFile uLaw file encoding is 502 !!! */
				info.play.encoding = AUDIO_ENCODING_ULAW;
			else
				/* "Modern" Sun stations can play PCM */
				info.play.encoding = AUDIO_ENCODING_LINEAR;
                        break;
		default:
			SErrorCode = SERR_BADFORMAT;
			return -1;
	}
	info.play.precision = afInfo->SampleWidth;
	info.play.channels = afInfo->Channels;
	info.play.sample_rate = afInfo->SampleRate;
	
	if (ioctl (audiofd, AUDIO_SETINFO, &info)) {
		SErrorCode = SERR_DEVSUPPORT;
		return -1;
	}
	
	return writeAudioData(audiofd, afInfo);
}

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;
}

