#include "amp.h"
#include "transform.h"
#include <sys/types.h>
#include <sys/signal.h>
#ifdef HAVE_MLOCK
#ifdef OS_Linux
#include <sys/mman.h>
#endif
#endif
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#include <sys/time.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "audioIO.h"
#include "audio.h"
#if !defined(OS_Linux) && !defined(AUSIZ)
#define AUSIZ 32768
#endif
struct ringBuffer {
char *bufferPtr;
int inPos, outPos;
};
static int buffer_fd;
static int control_fd;
inline void audioBufferWrite(char *buf,int bytes)
{
write(buffer_fd, buf, bytes);
}
void printout(void)
{
int j;
if (nch==2)
j=32 * 18 * 2;
else
j=32 * 18;
if (AUDIO_BUFFER_SIZE==0)
audioWrite((char*)sample_buffer, j * sizeof(short));
else
audioBufferWrite((char*)sample_buffer, j * sizeof(short));
}
int AUDIO_BUFFER_SIZE;
#define bufferSize(A) (((A)->inPos+AUDIO_BUFFER_SIZE-(A)->outPos) % AUDIO_BUFFER_SIZE)
#define bufferFree(A) (AUDIO_BUFFER_SIZE-1-bufferSize(A))
void
initBuffer(struct ringBuffer *buffer)
{
buffer->bufferPtr=malloc(AUDIO_BUFFER_SIZE);
if (buffer->bufferPtr==NULL)
_exit(-1);
#ifdef HAVE_MLOCK
mlock(buffer->bufferPtr,AUDIO_BUFFER_SIZE);
#endif
buffer->inPos = 0;
buffer->outPos = 0;
}
void
freeBuffer(struct ringBuffer *buffer)
{
#ifdef HAVE_MLOCK
munlock(buffer->bufferPtr,AUDIO_BUFFER_SIZE);
#endif
free(buffer->bufferPtr);
}
void
audioBufferFlush()
{
if (AUDIO_BUFFER_SIZE!=0)
{
int dummy;
write(control_fd, &dummy, sizeof dummy);
} else
audioFlush();
}
int
audioBufferOpen(int frequency, int stereo, int volume)
{
struct ringBuffer audioBuffer;
int inFd,outFd,ctlFd,cnt,pid;
int inputFinished=FALSE;
int percentFull;
fd_set inFdSet,outFdSet;
fd_set *outFdPtr;
struct timeval timeout;
int filedes[2];
int controldes[2];
if (pipe(filedes) || pipe(controldes))
{
perror("pipe");
exit(-1);
}
if ((pid=fork())!=0)
{
control_fd=controldes[1];
close(filedes[0]);
buffer_fd=filedes[1];
close(controldes[0]);
return(pid);
}
close(filedes[1]);
inFd=filedes[0];
close(controldes[1]);
ctlFd=controldes[0];
audioOpen(frequency,stereo,volume);
outFd=getAudioFd();
initBuffer(&audioBuffer);
while(1)
{
timeout.tv_sec=0;
timeout.tv_usec=0;
FD_ZERO(&inFdSet);
FD_ZERO(&outFdSet);
FD_SET(ctlFd,&inFdSet);
FD_SET(outFd,&outFdSet);
if (bufferSize(&audioBuffer)<AUSIZ)
{
outFdPtr = NULL;
if (inputFinished)
break;
} else
outFdPtr=&outFdSet;
if ((bufferFree(&audioBuffer)>=AUSIZ) && !inputFinished)
FD_SET(inFd,&inFdSet);
if (select(MAX3(inFd,outFd,ctlFd)+1,&inFdSet,outFdPtr,NULL,NULL) > -1)
{
if (outFdPtr && FD_ISSET(outFd,outFdPtr))
{
int bytesToEnd = AUDIO_BUFFER_SIZE - audioBuffer.outPos;
percentFull=100*bufferSize(&audioBuffer)/AUDIO_BUFFER_SIZE;
if (AUSIZ>bytesToEnd)
{
cnt = audioWrite(audioBuffer.bufferPtr + audioBuffer.outPos, bytesToEnd);
cnt += audioWrite(audioBuffer.bufferPtr, AUSIZ - bytesToEnd);
audioBuffer.outPos = AUSIZ - bytesToEnd;
}
else
{
cnt = audioWrite(audioBuffer.bufferPtr + audioBuffer.outPos, AUSIZ);
audioBuffer.outPos += AUSIZ;
}
}
if (FD_ISSET(inFd,&inFdSet))
{
cnt = read(inFd, audioBuffer.bufferPtr + audioBuffer.inPos, MIN(AUSIZ, AUDIO_BUFFER_SIZE - audioBuffer.inPos));
if (cnt >= 0)
{
audioBuffer.inPos = (audioBuffer.inPos + cnt) % AUDIO_BUFFER_SIZE;
if (cnt==0)
inputFinished=TRUE;
}
else
_exit(-1);
}
if (FD_ISSET(ctlFd,&inFdSet))
{
int dummy;
cnt = read(ctlFd, &dummy, sizeof dummy);
if (cnt >= 0)
{
audioBuffer.inPos = audioBuffer.outPos = 0;
audioFlush();
}
else
_exit(-1);
}
}
else
_exit(-1);
}
close(inFd);
audioClose();
exit(0);
return 0;
}
void
audioBufferClose()
{
close(buffer_fd);
waitpid(0,0,0);
}