This commit is contained in:
Cary Sandvig 2000-10-12 16:48:28 +00:00
parent 525e47735c
commit e9ca1bd9eb
3 changed files with 743 additions and 0 deletions

View File

@ -0,0 +1,231 @@
/*
* buffer.c
*
* Oliver Fromme <oliver.fromme@heim3.tu-clausthal.de>
* Mon Apr 14 03:53:18 MET DST 1997
*/
#include <stdlib.h>
#include <errno.h>
#include "mpg123.h"
int outburst = MAXOUTBURST;
int preload;
static int intflag = FALSE;
static int usr1flag = FALSE;
static void catch_interrupt (void)
{
intflag = TRUE;
}
static void catch_usr1 (void)
{
usr1flag = TRUE;
}
/* Interfaces to writer process */
extern void buffer_sig(int signal, int block);
void buffer_ignore_lowmem(void)
{
#ifndef NOXFERMEM
if(buffermem->wakeme[XF_READER])
xfermem_putcmd(buffermem->fd[XF_WRITER], XF_CMD_WAKEUP);
#endif
}
void buffer_end(void)
{
#ifndef NOXFERMEM
xfermem_putcmd(buffermem->fd[XF_WRITER], XF_CMD_TERMINATE);
#endif
}
void buffer_resync(void)
{
buffer_sig(SIGINT, TRUE);
}
void buffer_reset(void)
{
buffer_sig(SIGUSR1, TRUE);
}
void buffer_start(void)
{
buffer_sig(SIGCONT, FALSE);
}
void buffer_stop(void)
{
buffer_sig(SIGSTOP, FALSE);
}
extern int buffer_pid;
void buffer_sig(int signal, int block)
{
#ifndef NOXFERMEM
kill(buffer_pid, signal);
if (!buffermem || !block)
return;
if(xfermem_block(XF_WRITER, buffermem) != XF_CMD_WAKEUP)
perror("Could not resync/reset buffers");
#endif
return;
}
#ifndef NOXFERMEM
void buffer_loop(struct audio_info_struct *ai, sigset_t *oldsigset)
{
int bytes;
int my_fd = buffermem->fd[XF_READER];
txfermem *xf = buffermem;
int done = FALSE;
catchsignal (SIGINT, catch_interrupt);
catchsignal (SIGUSR1, catch_usr1);
sigprocmask (SIG_SETMASK, oldsigset, NULL);
if (param.outmode == DECODE_AUDIO) {
if (audio_open(ai) < 0) {
perror("audio");
exit(1);
}
}
for (;;) {
if (intflag) {
intflag = FALSE;
if (param.outmode == DECODE_AUDIO)
audio_queueflush (ai);
xf->readindex = xf->freeindex;
if (xf->wakeme[XF_WRITER])
xfermem_putcmd(my_fd, XF_CMD_WAKEUP);
}
if (usr1flag) {
usr1flag = FALSE;
/* close and re-open in order to flush
* the device's internal buffer before
* changing the sample rate. [OF]
*/
/* writer must block when sending SIGUSR1
* or we will lose all data processed
* in the meantime! [dk]
*/
xf->readindex = xf->freeindex;
/* We've nailed down the new starting location -
* writer is now safe to go on. [dk]
*/
if (xf->wakeme[XF_WRITER])
xfermem_putcmd(my_fd, XF_CMD_WAKEUP);
if (param.outmode == DECODE_AUDIO) {
audio_close (ai);
ai->rate = xf->buf[0];
ai->channels = xf->buf[1];
ai->format = xf->buf[2];
if (audio_open(ai) < 0) {
perror("audio");
exit(1);
}
}
}
if ( (bytes = xfermem_get_usedspace(xf)) < outburst ) {
/* if we got a buffer underrun we first
* fill 1/8 of the buffer before continue/start
* playing */
preload = xf->size>>3;
if(preload < outburst)
preload = outburst;
}
if(bytes < preload) {
int cmd;
if (done && !bytes) {
break;
}
if(!done) {
cmd = xfermem_block(XF_READER, xf);
switch(cmd) {
/* More input pending. */
case XF_CMD_WAKEUP_INFO:
continue;
/* Yes, we know buffer is low but
* know we don't care.
*/
case XF_CMD_WAKEUP:
break; /* Proceed playing. */
case XF_CMD_TERMINATE:
/* Proceed playing without
* blocking any further.
*/
done=TRUE;
break;
case -1:
if(errno==EINTR)
continue;
perror("Yuck! Error in buffer handling...");
done = TRUE;
xf->readindex = xf->freeindex;
xfermem_putcmd(xf->fd[XF_READER], XF_CMD_TERMINATE);
break;
default:
fprintf(stderr, "\nEh!? Received unknown command 0x%x in buffer process. Tell Daniel!\n", cmd);
}
}
}
preload = outburst; /* set preload to lower mark */
if (bytes > xf->size - xf->readindex)
bytes = xf->size - xf->readindex;
if (bytes > outburst)
bytes = outburst;
if (param.outmode == DECODE_FILE)
bytes = write(OutputDescriptor, xf->data + xf->readindex, bytes);
else if (param.outmode == DECODE_AUDIO)
bytes = audio_play_samples(ai,
(unsigned char *) (xf->data + xf->readindex), bytes);
if(bytes < 0) {
bytes = 0;
if(errno != EINTR) {
perror("Ouch ... error while writing audio data: ");
/*
* done==TRUE tells writer process to stop
* sending data. There might be some latency
* involved when resetting readindex to
* freeindex so we might need more than one
* cycle to terminate. (The number of cycles
* should be finite unless I managed to mess
* up something. ;-) [dk]
*/
done = TRUE;
xf->readindex = xf->freeindex;
xfermem_putcmd(xf->fd[XF_READER], XF_CMD_TERMINATE);
}
}
xf->readindex = (xf->readindex + bytes) % xf->size;
if (xf->wakeme[XF_WRITER])
xfermem_putcmd(my_fd, XF_CMD_WAKEUP);
}
if (param.outmode == DECODE_AUDIO)
audio_close (ai);
}
#endif
/* EOF */

View File

@ -0,0 +1,13 @@
/*
* Application specific interaction between main and buffer
* process. This is much less generic than the functions in
* xfermem so I chose to put it in buffer.[hc].
* 01/28/99 [dk]
*/
void buffer_ignore_lowmem(void);
void buffer_end(void);
void buffer_resync(void);
void buffer_reset(void);
void buffer_start(void);
void buffer_stop(void);

499
panda/src/mpg123/readers.c Normal file
View File

@ -0,0 +1,499 @@
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "mpg123.h"
#include "buffer.h"
#include "common.h"
#ifdef READ_MMAP
#include <sys/mman.h>
#ifndef MAP_FAILED
#define MAP_FAILED ( (void *) -1 )
#endif
#endif
static int get_fileinfo(struct reader *,char *buf);
/*******************************************************************
* stream based operation
*/
static int fullread(int fd,unsigned char *buf,int count)
{
int ret,cnt=0;
while(cnt < count) {
ret = read(fd,buf+cnt,count-cnt);
if(ret < 0)
return ret;
if(ret == 0)
break;
cnt += ret;
}
return cnt;
}
static int default_init(struct reader *rds)
{
char buf[128];
rds->filepos = 0;
rds->filelen = get_fileinfo(rds,buf);
if(rds->filelen > 0) {
if(!strncmp(buf,"TAG",3)) {
rds->flags |= READER_ID3TAG;
memcpy(rds->id3buf,buf,128);
}
}
return 0;
}
void stream_close(struct reader *rds)
{
if (rds->flags & READER_FD_OPENED)
close(rds->filept);
}
/****************************************
* HACK,HACK,HACK: step back <num> frames
* can only work if the 'stream' isn't a real stream but a file
*/
static int stream_back_bytes(struct reader *rds,int bytes)
{
if(lseek(rds->filept,-bytes,SEEK_CUR) < 0)
return -1;
if(param.usebuffer)
buffer_resync();
return 0;
}
static int stream_back_frame(struct reader *rds,struct frame *fr,int num)
{
long bytes;
unsigned char buf[4];
unsigned long newhead;
if(!firsthead)
return 0;
bytes = (fr->framesize+8)*(num+2);
/* Skipping back/forth requires a bit more work in buffered mode.
* See mapped_back_frame().
*/
if(param.usebuffer)
bytes += (long)(xfermem_get_usedspace(buffermem) /
(buffermem->buf[0] * buffermem->buf[1]
* (buffermem->buf[2] & AUDIO_FORMAT_MASK ?
16.0 : 8.0 ))
* (tabsel_123[fr->lsf][fr->lay-1][fr->bitrate_index] << 10));
/*
bytes += (long)(compute_buffer_offset(fr)*compute_bpf(fr));
*/
if(lseek(rds->filept,-bytes,SEEK_CUR) < 0)
return -1;
if(fullread(rds->filept,buf,4) != 4)
return -1;
newhead = (buf[0]<<24) + (buf[1]<<16) + (buf[2]<<8) + buf[3];
while( (newhead & HDRCMPMASK) != (firsthead & HDRCMPMASK) ) {
if(fullread(rds->filept,buf,1) != 1)
return -1;
newhead <<= 8;
newhead |= buf[0];
newhead &= 0xffffffff;
}
if( lseek(rds->filept,-4,SEEK_CUR) < 0)
return -1;
read_frame(fr);
read_frame(fr);
if(fr->lay == 3) {
set_pointer(512);
}
if(param.usebuffer)
buffer_resync();
return 0;
}
static int stream_head_read(struct reader *rds,unsigned long *newhead)
{
unsigned char hbuf[4];
if(fullread(rds->filept,hbuf,4) != 4)
return FALSE;
*newhead = ((unsigned long) hbuf[0] << 24) |
((unsigned long) hbuf[1] << 16) |
((unsigned long) hbuf[2] << 8) |
(unsigned long) hbuf[3];
return TRUE;
}
static int stream_head_shift(struct reader *rds,unsigned long *head)
{
unsigned char hbuf;
if(fullread(rds->filept,&hbuf,1) != 1)
return 0;
*head <<= 8;
*head |= hbuf;
*head &= 0xffffffff;
return 1;
}
static int stream_skip_bytes(struct reader *rds,int len)
{
if (!param.usebuffer)
return lseek(rds->filept,len,SEEK_CUR);
else {
int ret = lseek(rds->filept,len,SEEK_CUR);
buffer_resync();
return ret;
}
}
static int stream_read_frame_body(struct reader *rds,unsigned char *buf,
int size)
{
long l;
if( (l=fullread(rds->filept,buf,size)) != size)
{
if(l <= 0)
return 0;
memset(buf+l,0,size-l);
}
return 1;
}
static long stream_tell(struct reader *rds)
{
return lseek(rds->filept,0,SEEK_CUR);
}
static void stream_rewind(struct reader *rds)
{
lseek(rds->filept,0,SEEK_SET);
if(param.usebuffer)
buffer_resync();
}
/*
* returns length of a file (if filept points to a file)
* reads the last 128 bytes information into buffer
*/
static int get_fileinfo(struct reader *rds,char *buf)
{
int len;
if((len=lseek(rds->filept,0,SEEK_END)) < 0) {
return -1;
}
if(lseek(rds->filept,-128,SEEK_END) < 0)
return -1;
if(fullread(rds->filept,(unsigned char *)buf,128) != 128) {
return -1;
}
if(!strncmp(buf,"TAG",3)) {
len -= 128;
}
if(lseek(rds->filept,0,SEEK_SET) < 0)
return -1;
if(len <= 0)
return -1;
return len;
}
#ifdef READ_MMAP
/*********************************************************+
* memory mapped operation
*
*/
static unsigned char *mapbuf;
static unsigned char *mappnt;
static unsigned char *mapend;
static int mapped_init(struct reader *rds)
{
long len;
char buf[128];
len = get_fileinfo(rds,buf);
if(len < 0)
return -1;
if(!strncmp(buf,"TAG",3)) {
rds->flags |= READER_ID3TAG;
memcpy(rds->id3buf,buf,128);
}
mappnt = mapbuf = (unsigned char *)
mmap(NULL, len, PROT_READ, MAP_SHARED , rds->filept, 0);
if(!mapbuf || mapbuf == MAP_FAILED)
return -1;
mapend = mapbuf + len;
if(param.verbose > 1)
fprintf(stderr,"Using memory mapped IO for this stream.\n");
rds->filelen = len;
return 0;
}
static void mapped_rewind(struct reader *rds)
{
mappnt = mapbuf;
if (param.usebuffer)
buffer_resync();
}
static void mapped_close(struct reader *rds)
{
munmap((void *)mapbuf,mapend-mapbuf);
if (rds->flags & READER_FD_OPENED)
close(rds->filept);
}
static int mapped_head_read(struct reader *rds,unsigned long *newhead)
{
unsigned long nh;
if(mappnt + 4 > mapend)
return FALSE;
nh = (*mappnt++) << 24;
nh |= (*mappnt++) << 16;
nh |= (*mappnt++) << 8;
nh |= (*mappnt++) ;
*newhead = nh;
return TRUE;
}
static int mapped_head_shift(struct reader *rds,unsigned long *head)
{
if(mappnt + 1 > mapend)
return FALSE;
*head <<= 8;
*head |= *mappnt++;
*head &= 0xffffffff;
return TRUE;
}
static int mapped_skip_bytes(struct reader *rds,int len)
{
if(mappnt + len > mapend)
return FALSE;
mappnt += len;
if (param.usebuffer)
buffer_resync();
return TRUE;
}
static int mapped_read_frame_body(struct reader *rds,unsigned char *buf,
int size)
{
if(size <= 0) {
fprintf(stderr,"Ouch. Read_frame called with size <= 0\n");
return FALSE;
}
if(mappnt + size > mapend)
return FALSE;
memcpy(buf,mappnt,size);
mappnt += size;
return TRUE;
}
static int mapped_back_bytes(struct reader *rds,int bytes)
{
if( (mappnt - bytes) < mapbuf || (mappnt - bytes + 4) > mapend)
return -1;
mappnt -= bytes;
if(param.usebuffer)
buffer_resync();
return 0;
}
static int mapped_back_frame(struct reader *rds,struct frame *fr,int num)
{
long bytes;
unsigned long newhead;
if(!firsthead)
return 0;
bytes = (fr->framesize+8)*(num+2);
/* Buffered mode is a bit trickier. From the size of the buffered
* output audio stream we have to make a guess at the number of frames
* this corresponds to.
*/
if(param.usebuffer)
bytes += (long)(xfermem_get_usedspace(buffermem) /
(buffermem->buf[0] * buffermem->buf[1]
* (buffermem->buf[2] & AUDIO_FORMAT_MASK ?
16.0 : 8.0 ))
* (tabsel_123[fr->lsf][fr->lay-1][fr->bitrate_index] << 10));
/*
bytes += (long)(compute_buffer_offset(fr)*compute_bpf(fr));
*/
if( (mappnt - bytes) < mapbuf || (mappnt - bytes + 4) > mapend)
return -1;
mappnt -= bytes;
newhead = (mappnt[0]<<24) + (mappnt[1]<<16) + (mappnt[2]<<8) + mappnt[3];
mappnt += 4;
while( (newhead & HDRCMPMASK) != (firsthead & HDRCMPMASK) ) {
if(mappnt + 1 > mapend)
return -1;
newhead <<= 8;
newhead |= *mappnt++;
newhead &= 0xffffffff;
}
mappnt -= 4;
read_frame(fr);
read_frame(fr);
if(fr->lay == 3)
set_pointer(512);
if(param.usebuffer)
buffer_resync();
return 0;
}
static long mapped_tell(struct reader *rds)
{
return mappnt - mapbuf;
}
#endif
/*****************************************************************
* read frame helper
*/
struct reader *rd;
struct reader readers[] = {
#ifdef READ_SYSTEM
{ system_init,
NULL, /* filled in by system_init() */
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL } ,
#endif
#ifdef READ_MMAP
{ mapped_init,
mapped_close,
mapped_head_read,
mapped_head_shift,
mapped_skip_bytes,
mapped_read_frame_body,
mapped_back_bytes,
mapped_back_frame,
mapped_tell,
mapped_rewind } ,
#endif
{ default_init,
stream_close,
stream_head_read,
stream_head_shift,
stream_skip_bytes,
stream_read_frame_body,
stream_back_bytes,
stream_back_frame,
stream_tell,
stream_rewind } ,
{ NULL, }
};
/* open the device to read the bit stream from it */
struct reader *open_stream(char *bs_filenam,int fd)
{
int i;
int filept_opened = 1;
int filept;
if (!bs_filenam) {
if(fd < 0) {
filept = 0;
filept_opened = 0;
}
else
filept = fd;
}
else if (!strncmp(bs_filenam, "http://", 7))
filept = http_open(bs_filenam);
#ifndef O_BINARY
#define O_BINARY (0)
#endif
else if ( (filept = open(bs_filenam, O_RDONLY|O_BINARY)) < 0) {
perror (bs_filenam);
return NULL;
}
rd = NULL;
for(i=0;;i++) {
readers[i].filelen = -1;
readers[i].filept = filept;
readers[i].flags = 0;
if(filept_opened)
readers[i].flags |= READER_FD_OPENED;
if(!readers[i].init) {
fprintf(stderr,"Fatal error!\n");
exit(1);
}
if(readers[i].init(readers+i) >= 0) {
rd = &readers[i];
break;
}
}
if(rd && rd->flags & READER_ID3TAG) {
print_id3_tag(rd->id3buf);
}
return rd;
}