/*
*  XmNap  A Motif napster client
*
*  Copyright (C) 2000 Mats Peterson
*
*  This program is free software; you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation; either version 2 of the License, or
*  (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program; see the file COPYING.  If not, write to
*  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
*  Boston, MA 02111-1307, USA.
*
*  Please send any comments/bug reports to
*  [email protected]  (Mats Peterson)
*/

#ifdef USE_SOUND

#include <Xm/Xm.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/soundcard.h>
#include <errno.h>

#include "msgbox.h"
#include "sound.h"
#include "util.h"


String sound[NUM_SOUNDS];


WAVHDR* ReadWavHdr(int fd)
{
   static WAVHDR *wavHdr = NULL;

   if (! wavHdr)
       wavHdr = (WAVHDR*)XtMalloc(sizeof(WAVHDR));

   if (read(fd, wavHdr, sizeof(WAVHDR)) == -1)
       return NULL;

   wavHdr->riffTag = BSWAP32(wavHdr->riffTag);
   wavHdr->riffLength = BSWAP32(wavHdr->riffLength);
   wavHdr->waveTag = BSWAP32(wavHdr->waveTag);
   wavHdr->fmtTag = BSWAP32(wavHdr->fmtTag);
   wavHdr->fmtLength = BSWAP32(wavHdr->fmtLength);
   wavHdr->format = BSWAP16(wavHdr->format);
   wavHdr->channels = BSWAP16(wavHdr->channels);
   wavHdr->sampRate = BSWAP32(wavHdr->sampRate);
   wavHdr->avgSampRate = BSWAP32(wavHdr->avgSampRate);
   wavHdr->align = BSWAP16(wavHdr->align);
   wavHdr->bitsPerSample = BSWAP16(wavHdr->bitsPerSample);
   wavHdr->dataTag = BSWAP32(wavHdr->dataTag);
   wavHdr->dataLength = BSWAP32(wavHdr->dataLength);

   return wavHdr;
}


int CheckWav(String name)
{
   WAVHDR *wavHdr;
   int fd = 0, retVal = 0;
   char tmp[128];

   if ((fd = open(name, O_RDONLY)) == -1) {
       ErrMsg(strerror(errno));
       goto error;
   }

   if (! (wavHdr = ReadWavHdr(fd))) {
       ErrMsg(strerror(errno));
       goto error;
   }

   if ((wavHdr->riffTag != RIFF) || (wavHdr->waveTag != WAVE) ||
           (wavHdr->fmtTag != FMT) || (wavHdr->dataTag != DATA)) {
       ErrMsg("Invalid WAV format");
       goto error;
   }

   if (wavHdr->format != PCM_CODE) {
       ErrMsg("Can't play not PCM-coded WAV files");
       goto error;
   }

   if (wavHdr->channels > 2) {
       sprintf(tmp, "Can't play WAV files with %d channels",
               wavHdr->channels);
       ErrMsg(tmp);
       goto error;
   }

   goto exit;

error:
   retVal = -1;
exit:
   if (fd > 0)
       close(fd);
   return retVal;
}


void PlaySound(String name)
{
   WAVHDR *wavHdr;
   char tmp[256];
   char *audioBuf = NULL;
   int fd = 0, audio = 0, bufSize, sampleSize, stereo, speed, toRead, n;
   static int pid = 0;
   int pid2;

   if (! strlen(name))
       return;

   if (pid) {
       if ((pid2 = waitpid(pid, NULL, WNOHANG | WUNTRACED)) <= 0) {
           if (pid2 == -1) {
               sprintf(tmp, "waitpid: %s", strerror(errno));
               ErrMsg(tmp);
           }
           return;
       }
   }

   pid = fork();

   if (pid == 0) {
       if ((audio = open("/dev/dsp", O_WRONLY)) == -1)
           goto exit;

       if ((fd = open(name, O_RDONLY)) == -1)
           goto exit;

       if (! (wavHdr = ReadWavHdr(fd)))
           goto exit;

       if (ioctl(audio, SNDCTL_DSP_GETBLKSIZE, &bufSize) == -1)
           goto exit;
       audioBuf = XtMalloc(bufSize);

       sampleSize = (int)wavHdr->bitsPerSample;
       stereo = (wavHdr->channels == 2) ? 1 : 0;
       speed = (int)wavHdr->sampRate;
       if (ioctl(audio, SNDCTL_DSP_SAMPLESIZE, &sampleSize) == -1)
           goto exit;
       if (ioctl(audio, SNDCTL_DSP_STEREO, &stereo) == -1)
           goto exit;
       if (ioctl(audio, SNDCTL_DSP_SPEED, &speed) == -1)
           goto exit;

       toRead = wavHdr->dataLength;
       while (toRead) {
           n = (toRead > bufSize) ? bufSize : toRead;
           if (read(fd, audioBuf, n) == -1)
               break;
           if (write(audio, audioBuf, n) == -1)
               break;
           toRead -= n;
       }

   exit:
       if (audio > 0)
           close(audio);
       if (fd > 0)
           close(fd);
       if (audioBuf)
           XtFree(audioBuf);
       _exit(0);
   } else if (pid < 0) {
       sprintf(tmp, "fork: %s", strerror(errno));
       ErrMsg(tmp);
   }
}

#endif