⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 buffer.c

📁 MP3解码源代码,能够对于MP3进行解码,效率不错
💻 C
字号:
/* this file is a part of amp software

   buffer.c: written by Andrew Richards  <A.Richards@phys.canterbury.ac.nz>
             (except printout())

   Last modified by:
   Karl Anders Oygard added flushing of audio buffers, 13 May 1997

*/
#include "amp.h"
#include "transform.h"

#include <sys/types.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"

struct ringBuffer {		/* A ring buffer to store the data in */
	char *bufferPtr;	/* buffer pointer */
	int inPos, outPos;	/* positions for reading and writing */
};


static int buffer_fd;
static int control_fd;

/* little endian systems do not require any byte swapping whatsoever. 
 * big endian systems require byte swapping when writing .wav files, 
 * but not when playing directly
 */

/* This is a separate (but inlined) function to make it easier to implement */
/* a threaded buffer */

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 (A_WRITE_TO_FILE) {
#ifndef NO_BYTE_SWAPPING
        short *ptr = (short*) sample_buffer;
	int i = j;

                for (;i>=0;--i)
                        ptr[i] = ptr[i] << 8 | ptr[i] >> 8;
#endif

                fwrite(sample_buffer, sizeof(short), j, out_file);
        }

        if (A_AUDIO_PLAY) {
#ifdef LINUX_REALTIME
                rt_printout((short*) sample_buffer, j * sizeof(short));
#else /* LINUX_REALTIME */
                if (AUDIO_BUFFER_SIZE==0)
                        audioWrite((char*)sample_buffer, j * sizeof(short));
                else
                        audioBufferWrite((char*)sample_buffer, j * sizeof(short));
#endif /* LINUX_REALTIME */
        }
}

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) {
		die("Unable to allocate write buffer\n");
	}
#ifdef HAVE_MLOCK
	mlock(buffer->bufferPtr,AUDIO_BUFFER_SIZE);
#endif
	buffer->inPos = 0;
	buffer->outPos = 0;
	DB(buffer2, msg("Allocated %d bytes for audio buffer\n",AUDIO_BUFFER_SIZE) );
}

void
freeBuffer(struct ringBuffer *buffer)
{
#ifdef HAVE_MLOCK
  munlock(buffer->bufferPtr,AUDIO_BUFFER_SIZE);
#endif
	free(buffer->bufferPtr);
}

/* This just sends some bogus data on the control pipe, which will cause */
/* the reader to flush its buffer. */

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();
}
	
/* The decoded data are stored in a the ring buffer until they can be sent */
/* to the audio device. Variables are named in relation to the buffer */
/* ie writes are writes from the codec to the buffer and reads are reads */
/* from the buffer to the audio device */

int
audioBufferOpen(int frequency, int stereo, int volume)
{
	struct ringBuffer audioBuffer;
	
	int inFd,outFd,ctlFd,cnt,cntr=0,pid;
	int inputFinished=FALSE;
	int percentFull;
	fd_set inFdSet,outFdSet;
	fd_set *outFdPtr; 
	struct timeval timeout;
	int filedes[2];
	int controldes[2];
	
	DB(buffer, msg("Starting audio buffer\n") );
	
	if (pipe(filedes) || pipe(controldes)) {
		perror("pipe");
		exit(-1);
	}
	DB(buffer, msg("readpipe=%d writepipe=%d\n",filedes[0],filedes[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 */
	}
	
	DB(buffer, msg("Audio buffer (pipe) starting\n") );
	
	/* 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);
		
		DB(buffer,
			 msg("BS=%d inPos=%d outPos=%d bufferSize=%d bufferFree=%d\n",
					 AUDIO_BUFFER_SIZE,audioBuffer.inPos,audioBuffer.outPos,
					 bufferSize(&audioBuffer),bufferFree(&audioBuffer)) );
		
		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 defined(DEBUG)
				if ((cntr++ % (16/(AUSIZ/4096)))==0) msg("\rBuffer (%2d%%) %6d",percentFull,bufferSize(&audioBuffer));
#endif
				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;
				}

				DB(buffer2, msg("buffer: wrote %d bytes (to audio)\n",cnt) );
			}
			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;

					DB(buffer2, msg("buffer: read %d bytes\n",cnt) );

					if (cnt==0) {
						inputFinished=TRUE;
						DB(buffer, msg("inputFinished\n") );
					}
				} else {
				        perror("read");
					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 {
				        perror("read");
					exit(-1);
				}
			}
		} else {
			perror("select");
			exit(-1);
		}
	}
	close(inFd);
	DB(buffer, msg("Buffer pipe closed %d\n",inFd); )
	audioClose();
	exit(0);
	return 0; /* just to get rid of warnings */
}

void
audioBufferClose()
{
	/* Close the buffer pipe and wait for the buffer process to close */
	close(buffer_fd);
	waitpid(0,0,0);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -