void audioBufferFlush() { if (AUDIO_BUFFER_SIZE!=0) { int dummy; /* We could use the control pipe for passing commands to the */ /* audio player process, but so far we haven't bothered. */ write(control_fd, &dummy, sizeof dummy); } else audioFlush(); }
/* * Open audio, put it in paused state, and set IO to non-blocking mode. */ int audioOpen(int rate) { int fd; int non_blocking; if (rate == 16000) { sampleRate = 16000; samplePrecision = 16; sampleEncoding = AUDIO_ENCODING_LINEAR; } else if (rate == 8000) { sampleRate = 8000; samplePrecision = 8; sampleEncoding = AUDIO_ENCODING_ULAW; } else QUIT((stderr, "audioOpen: unsupported rate %d\n", rate)); /* * Open the device for read-only access and do not block (wait) if * the device is currently busy. */ fd = open("/dev/audio", O_RDONLY | O_NDELAY); if (fd < 0) { if (errno == EBUSY) fprintf(stderr, "audioOpen: audio device is busy\n"); else perror("audioOpen error"); exit(1); } audioFd = fd; audioPause (); audioFlush (); non_blocking = 1; ioctl (audioFd, FIONBIO, &non_blocking); return fd; }
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) { /* if we are the parent */ control_fd=controldes[1]; close(filedes[0]); buffer_fd=filedes[1]; close(controldes[0]); return(pid); /* return the pid */ } /* we are the child */ 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) { /* is the buffer too empty */ outFdPtr = NULL; /* yes, don't try to write */ if (inputFinished) /* no more input, buffer exhausted -> exit */ break; } else outFdPtr=&outFdSet; /* no, select on write */ /* check we have at least AUSIZ bytes left (don't want <1k bits) */ if ((bufferFree(&audioBuffer)>=AUSIZ) && !inputFinished) FD_SET(inFd,&inFdSet); /* The following selects() are basically all that is left of the system dependent code outside the audioIO_*&c files. These selects really need to be moved into the audioIO_*.c files and replaced with a function like audioIOReady(inFd, &checkIn, &checkAudio, wait) where it checks the status of the input or audio output if checkIn or checkAudio are set and returns with checkIn or checkAudio set to TRUE or FALSE depending on whether or not data is available. If wait is FALSE the function should return immediately, if wait is TRUE the process should BLOCK until the required condition is met. NB: The process MUST relinquish the CPU during this check or it will gobble up all the available CPU which sort of defeats the purpose of the buffer. This is tricky for people who don't have file descriptors (and select) to do the job. In that case a buffer implemented using threads should work. The way things are set up now a threaded version shouldn't be to hard to implement. When I get some time... */ /* check if we can read or write */ if (select(MAX3(inFd,outFd,ctlFd)+1,&inFdSet,outFdPtr,NULL,NULL) > -1) { if (outFdPtr && FD_ISSET(outFd,outFdPtr)) { /* need to write */ 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)) { /* need to read */ 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; /* just to get rid of warnings */ }