[xiph-cvs] cvs commit: vorbis-tools/ogg123 Makefile.am ao_interface.c buffer.c buffer.h ogg123.c ogg123.h
Kenneth C. Arnold
kcarnold at xiph.org
Fri Aug 10 09:33:42 PDT 2001
kcarnold 01/08/10 09:33:41
Modified: ogg123 Tag: kcarnold_work Makefile.am ao_interface.c
buffer.c buffer.h ogg123.c ogg123.h
Log:
A very nice (IMHO) pthreaded buffer. Many other fixups. Much better.
Bang on this and try to find some deadlock cases.
Revision Changes Path
No revision
No revision
1.14.2.2 +1 -1 vorbis-tools/ogg123/Makefile.am
Index: Makefile.am
===================================================================
RCS file: /usr/local/cvsroot/vorbis-tools/ogg123/Makefile.am,v
retrieving revision 1.14.2.1
retrieving revision 1.14.2.2
diff -u -r1.14.2.1 -r1.14.2.2
--- Makefile.am 2001/08/06 21:35:40 1.14.2.1
+++ Makefile.am 2001/08/10 16:33:40 1.14.2.2
@@ -13,7 +13,7 @@
ogg123_LDADD = @VORBISFILE_LIBS@ @VORBIS_LIBS@ @OGG_LIBS@ @AO_LIBS@ \
@SOCKET_LIBS@
-ogg123_SOURCES = ogg123.c ao_interface.c buffer.c ogg123.h buffer.h getopt.c getopt1.c getopt.h
+ogg123_SOURCES = ogg123.c ao_interface.c buffer.c ogg123.h buffer.h getopt.c getopt1.c getopt.h ao_interface.h
## Comment the above and uncomment the next line to disable the buffer support
##ogg123_SOURCES = ogg123.c ao_interface.c nullbuffer.c ogg123.h buffer.h getopt.c getopt1.c getopt.h
1.5.2.2 +58 -3 vorbis-tools/ogg123/ao_interface.c
Index: ao_interface.c
===================================================================
RCS file: /usr/local/cvsroot/vorbis-tools/ogg123/ao_interface.c,v
retrieving revision 1.5.2.1
retrieving revision 1.5.2.2
diff -u -r1.5.2.1 -r1.5.2.2
--- ao_interface.c 2001/08/06 21:35:40 1.5.2.1
+++ ao_interface.c 2001/08/10 16:33:40 1.5.2.2
@@ -1,3 +1,20 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
+ * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
+ * PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE Ogg123 SOURCE CODE IS (C) COPYRIGHT 2000-2001 *
+ * by Kenneth C. Arnold <ogg at arnoldnet.net> AND OTHER CONTRIBUTORS *
+ * http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ last mod: $Id: ao_interface.c,v 1.5.2.2 2001/08/10 16:33:40 kcarnold Exp $
+
+ ********************************************************************/
+
#include <stdio.h>
#include <string.h>
#include <limits.h>
@@ -26,12 +43,21 @@
return devices_list;
}
-void devices_write(void *ptr, size_t size, devices_t * d)
+size_t devices_write(void *ptr, size_t size, size_t nmemb, devices_t * d)
{
+ size_t i, total = 0;
+ devices_t * start = d;
+ for (i=0; i < nmemb; i++) {
+ d = start;
while (d != NULL) {
- ao_play(d->device, ptr, size);
- d = d->next_device;
+ int ret = ao_play(d->device, ptr, size);
+ if (ret < size)
+ return total + ret;
+ total += ret;
+ d = d->next_device;
}
+ }
+ return total;
}
int add_option(ao_option ** op_h, const char *optstring)
@@ -97,4 +123,33 @@
return ao_driver_id(device);
return -1;
+}
+
+void close_audio_devices (devices_t *devices)
+{
+ devices_t *current = devices;
+ while (current != NULL) {
+ ao_close(current->device);
+ current = current->next_device;
+ }
+}
+
+void free_audio_devices (devices_t *devices)
+{
+ devices_t *current;
+ while (devices != NULL) {
+ current = devices->next_device;
+ free (devices);
+ devices = current;
+ }
+}
+
+void ao_atexit (int exitcode, void *arg)
+{
+ devices_t *devices = (devices_t *) arg;
+
+ close_audio_devices (devices);
+ free_audio_devices (devices);
+
+ ao_shutdown();
}
1.7.2.6 +151 -203 vorbis-tools/ogg123/buffer.c
Index: buffer.c
===================================================================
RCS file: /usr/local/cvsroot/vorbis-tools/ogg123/buffer.c,v
retrieving revision 1.7.2.5
retrieving revision 1.7.2.6
diff -u -r1.7.2.5 -r1.7.2.6
--- buffer.c 2001/08/09 01:56:54 1.7.2.5
+++ buffer.c 2001/08/10 16:33:40 1.7.2.6
@@ -1,3 +1,20 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
+ * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
+ * PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE Ogg123 SOURCE CODE IS (C) COPYRIGHT 2000-2001 *
+ * by Kenneth C. Arnold <ogg at arnoldnet.net> AND OTHER CONTRIBUTORS *
+ * http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ last mod: $Id: buffer.c,v 1.7.2.6 2001/08/10 16:33:40 kcarnold Exp $
+
+ ********************************************************************/
+
/* buffer.c
* buffering code for ogg123. This is Unix-specific. Other OSes anyone?
*
@@ -32,263 +49,198 @@
#define DEBUG1(x, y)
#endif
-void signal_handler (int sig)
-{
-}
+#define LOCK_MUTEX(mutex) do { DEBUG1("Locking mutex %s.", #mutex); pthread_mutex_lock (&(mutex)); } while (0)
+#define UNLOCK_MUTEX(mutex) do { DEBUG1("Unlocking mutex %s", #mutex); pthread_mutex_unlock(&(mutex)); } while (0)
-/* Initialize the buffer structure. */
-void buffer_init (buf_t *buf, long size, long prebuffer)
+void Prebuffer (buf_t * buf)
{
- DEBUG0("buffer init");
- memset (buf, 0, sizeof(*buf));
- buf->status = 0;
- buf->reader = buf->writer = buf->buffer;
- buf->end = buf->buffer + (size - 1);
- buf->size = size;
- buf->prebuffer = prebuffer;
- buf->curfill = 0;
- if (prebuffer > 0)
- buf->status |= STAT_PREBUFFER;
+ if (buf->prebuffer > 0)
+ {
+ LOCK_MUTEX (buf->StatMutex);
+ buf->StatMask |= STAT_PREBUFFERING;
+ UNLOCK_MUTEX (buf->StatMutex);
+ }
}
-/* Main write loop. No semaphores. No deadlock. No problem. I hope. */
-void writer_main (volatile buf_t *buf, devices_t *d)
+void PthreadCleanup (void *arg)
{
- devices_t *d1;
- signal (SIGINT, SIG_IGN);
- signal (SIGUSR1, signal_handler);
-
- DEBUG0("r: writer_main");
- while (! (buf->status & STAT_SHUTDOWN && buf->curfill == 0))
- {
- /* Writer just waits on reader to be done with submit_chunk
- * Reader must ensure that we don't deadlock. */
-
- /* prebuffering */
- prebuffer:
- while (buf->status & STAT_PREBUFFER)
- pause();
-
- if (buf->curfill == 0) {
- if (! (buf->status & STAT_FLUSH)) /* likely unnecessary */
- buf->status |= STAT_UNDERFLOW;
- DEBUG0("alerting writer");
- kill (buf->readerpid, SIGUSR1);
- }
-
- if (buf->status & STAT_FLUSH) {
- flush:
- DEBUG0("r: buffer flush");
- buf->curfill = 0;
- buf->reader = buf->writer;
- buf->status &= ~STAT_FLUSH;
- DEBUG1("buf->status = %d", buf->status);
- kill (buf->readerpid, SIGUSR1);
+ buf_t *buf = (buf_t*) arg;
+
+ DEBUG0("PthreadCleanup");
+ UNLOCK_MUTEX (buf->SizeMutex);
+ UNLOCK_MUTEX (buf->StatMutex);
+
+ /* kludge to get around pthreads vs. signal handling */
+ pthread_cond_broadcast (&buf->DataReadyCondition);
+ pthread_cond_broadcast (&buf->UnderflowCondition);
+ pthread_cond_broadcast (&buf->OverflowCondition);
+ UNLOCK_MUTEX (buf->SizeMutex);
+ UNLOCK_MUTEX (buf->StatMutex);
+}
+
+void* BufferFunc (void *arg)
+{
+ sigset_t set;
+ buf_t *buf = (buf_t*) arg;
+ volatile buf_t *vbuf = (volatile buf_t*) buf; /* optimizers... grr */
+
+ DEBUG0("r: BufferFunc");
+ sigfillset (&set);
+ pthread_sigmask (SIG_SETMASK, &set, NULL);
+
+ pthread_cleanup_push (PthreadCleanup, buf);
+ while (1)
+ {
+ /* don't touch the size unless we ask you to. */
+ LOCK_MUTEX (buf->SizeMutex);
+
+ /* paused? Remember to signal DataReady when unpaused. */
+ checkPlaying:
+ while (!(buf->StatMask & STAT_PLAYING) ||
+ (buf->StatMask & STAT_PREBUFFERING)) {
+ DEBUG1 ("r: waiting on !playing || prebuffering (stat=%d)", buf->StatMask);
+ pthread_cond_wait (&buf->DataReadyCondition, &buf->SizeMutex);
}
- if (buf->curfill == 0 && !(buf->status & STAT_SHUTDOWN)
- && !(buf->status & STAT_FLUSH)) {
- buf->status |= STAT_PREBUFFER;
- goto prebuffer;
+ if (buf->curfill == 0) {
+ UNLOCK_MUTEX (buf->SizeMutex);
+ DEBUG0 ("r: signalling buffer underflow");
+ pthread_cond_signal (&buf->UnderflowCondition);
+ LOCK_MUTEX (buf->SizeMutex);
+ Prebuffer (buf);
+ DEBUG0 ("r: waiting on data ready");
+ pthread_cond_wait (&buf->DataReadyCondition, &buf->SizeMutex);
+ goto checkPlaying;
}
- /* DEBUG1("looping on buffer underflow, status is %d", buf->status);*/
-
- if (buf->status & STAT_FLUSH)
- goto flush;
- if (buf->reader == buf->writer)
- break;
+ /* unlock while playing sample */
+ UNLOCK_MUTEX (buf->SizeMutex);
- /* devices_write (buf->writer->data, buf->writer->len, d); */
DEBUG0("writing chunk");
- {
- d1 = d;
- while (d1 != NULL) {
- ao_play(d1->device, buf->writer->data, buf->writer->len);
- d1 = d1->next_device;
- }
- }
+ buf->write_func (buf->writer->data, buf->writer->len, 1, buf->data);
DEBUG0("incrementing pointer");
- if (buf->writer == buf->end)
- buf->writer = buf->buffer;
+ LOCK_MUTEX (buf->SizeMutex);
+ if (vbuf->writer == vbuf->end)
+ vbuf->writer = vbuf->buffer;
else
- buf->writer++;
- buf->curfill--;
+ vbuf->writer++;
+ vbuf->curfill--;
+ UNLOCK_MUTEX (buf->SizeMutex);
+
+ /* slight abuse of the DataReady condition, but makes sense. */
+ DEBUG0 ("r: signalling buffer no longer full");
if (buf->curfill + 1 == buf->size)
- kill (buf->readerpid, SIGUSR1);
+ pthread_cond_signal (&buf->DataReadyCondition);
}
- DEBUG0("r: shutting down buffer");
- buf->status = 0;
- write (buf->fds[1], "2", sizeof(int));
- kill (buf->writerpid, SIGUSR1);
+ /* should never get here */
+ pthread_cleanup_pop(1);
DEBUG0("r: exiting");
- _exit(0);
}
-/* fork_writer is called to create the writer process. This creates
- * the shared memory segment of 'size' chunks, and returns a pointer
- * to the buffer structure that is shared. Just pass this straight to
- * submit_chunk and all will be happy. */
-
-buf_t *fork_writer (long size, devices_t *d, long prebuffer)
+buf_t *StartBuffer (long size, long prebuffer, void *data,
+ size_t (*write_func) (void *, size_t, size_t, void *))
{
- int childpid;
- buf_t *buf;
-
-#if HAVE_SMMAP
- int fd;
+ buf_t *buf = malloc (sizeof(buf_t) + sizeof (chunk_t) * (size - 1));
- if ((fd = open("/dev/zero", O_RDWR)) < 0)
- {
- perror ("cannot open /dev/zero");
- exit (1);
- }
- if ((buf = (buf_t *) mmap (0, sizeof(buf_t) + sizeof (chunk_t) * (size - 1),
- PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED)
- {
- perror("mmap");
- exit(1);
- }
- close(fd);
-#else
- /* Get the shared memory segment. */
- int shmid = shmget (IPC_PRIVATE,
- sizeof(buf_t) + sizeof (chunk_t) * (size - 1),
- IPC_CREAT|SHM_R|SHM_W);
-
- if (shmid == -1)
- {
- perror ("shmget");
- exit (1);
- }
-
- /* Attach the segment to us (and our kids). Get and store the pointer. */
- buf = (buf_t *) shmat (shmid, 0, 0);
-
if (buf == NULL)
{
- perror ("shmat");
+ perror ("malloc");
exit (1);
}
- /* Remove segment after last process detaches it or terminates. */
- shmctl(shmid, IPC_RMID, 0);
-#endif /* HAVE_SMMAP */
+ /* we no longer need those hacked-up shared memory things! yippee! */
#ifdef DEBUG_BUFFER
- debugfile = fopen ("/tmp/bufferdebug", "w"); /* file can be a pipe */
+ debugfile = fopen ("/tmp/bufferdebug", "w");
setvbuf (debugfile, NULL, _IONBF, 0);
#endif
-
- buffer_init (buf, size, prebuffer);
-
- /* Create a pipe for communication between the two processes. Unlike
- * the first incarnation of an ogg123 buffer, the data is not transferred
- * over this channel, only occasional "WAKE UP!"'s. */
-
- if (pipe (buf->fds))
- {
- perror ("pipe");
- exit (1);
- }
- /* write should never block; read should always block. */
- fcntl (buf->fds[1], F_SETFL, O_NONBLOCK);
-
- fflush (stdout);
+ /* Initialize the buffer structure. */
+ DEBUG0("buffer init");
+ memset (buf, 0, sizeof(*buf));
- signal (SIGUSR1, signal_handler);
+ buf->data = data;
+ buf->write_func = write_func;
- buf->readerpid = getpid();
+ buf->reader = buf->writer = buf->buffer;
+ buf->end = buf->buffer + (size - 1);
+ buf->size = size;
+ buf->prebuffer = prebuffer;
+ Prebuffer (buf);
+ buf->StatMask |= STAT_PLAYING;
- childpid = fork();
+ /* pthreads initialization */
+ pthread_mutex_init (&buf->SizeMutex, NULL);
+ pthread_cond_init (&buf->UnderflowCondition, NULL);
+ pthread_cond_init (&buf->OverflowCondition, NULL);
- if (childpid == -1)
- {
- perror ("fork");
- exit (1);
- }
+ pthread_create(&buf->BufferThread, NULL, BufferFunc, buf);
- if (childpid == 0)
- {
- buf->writerpid = getpid();
- writer_main (buf, d);
- return NULL;
- }
- else {
- buf->writerpid = childpid;
- return buf;
- }
+ return buf;
}
void submit_chunk (buf_t *buf, chunk_t chunk)
{
- struct timeval tv;
- static fd_set set;
-
- FD_ZERO(&set);
- FD_SET(buf->fds[0], &set);
-
DEBUG0("submit_chunk");
- /* Wait wait, don't step on my sample! */
- while (buf->curfill == buf->size)
- {
- /* buffer overflow (yikes! no actually it's a GOOD thing) */
- int ret;
- char t;
-
- DEBUG0("w: looping on buffer overflow");
- tv.tv_sec = 1;
- tv.tv_usec = 0;
- ret = select (buf->fds[0]+1, &set, NULL, NULL, &tv);
-
- DEBUG1("w: select returned %d", ret);
- if (ret > 0)
- read (buf->fds[0], &t, sizeof(int));
- }
-
+ LOCK_MUTEX (buf->SizeMutex);
+ /* wait on buffer overflow */
+ while (buf->curfill == buf->size && buf->StatMask & STAT_PLAYING)
+ pthread_cond_wait (&buf->DataReadyCondition, &buf->SizeMutex);
+
DEBUG0("writing chunk");
*(buf->reader) = chunk;
- /* do this atomically */
if (buf->reader == buf->end)
buf->reader = buf->buffer;
else
buf->reader++;
buf->curfill++;
- if (buf->status & STAT_PREBUFFER && buffer_full(buf) >= buf->prebuffer) {
- buf->status &= ~STAT_PREBUFFER;
- kill (buf->writerpid, SIGUSR1);
- }
- else if (buf->status & STAT_UNDERFLOW) {
- buf->status |= STAT_PREBUFFER;
- buf->status &= ~STAT_UNDERFLOW;
- kill (buf->writerpid, SIGUSR1);
+ UNLOCK_MUTEX (buf->SizeMutex);
+
+ if ((buf->StatMask & STAT_PREBUFFERING)
+ && buffer_full(buf) >= buf->prebuffer) {
+ DEBUG0("prebuffering done, starting writer");
+ LOCK_MUTEX (buf->StatMutex);
+ buf->StatMask &= ~STAT_PREBUFFERING;
+ UNLOCK_MUTEX (buf->StatMutex);
+ pthread_cond_signal (&buf->DataReadyCondition);
}
+ else if (buf->curfill == 1)
+ pthread_cond_signal (&buf->DataReadyCondition);
+
DEBUG0("submit_chunk exit");
}
void buffer_flush (buf_t *buf)
{
DEBUG0("flush buffer");
- buf->status |= STAT_FLUSH;
+ LOCK_MUTEX (buf->SizeMutex);
+ buf->curfill = 0;
+ buf->reader = buf->writer;
+ UNLOCK_MUTEX (buf->SizeMutex);
+ Prebuffer (buf);
}
+void buffer_WaitForEmpty (buf_t *buf)
+{
+ DEBUG0("waiting for empty");
+ LOCK_MUTEX (buf->SizeMutex);
+ while (buf->curfill > 0)
+ pthread_cond_wait (&buf->UnderflowCondition, &buf->SizeMutex);
+ UNLOCK_MUTEX (buf->SizeMutex);
+ Prebuffer (buf);
+}
+
void buffer_shutdown (buf_t *buf)
{
DEBUG0("shutdown buffer");
- buf->status |= STAT_SHUTDOWN;
- buf->status &= ~STAT_PREBUFFER;
- while (buf->status != 0)
- {
- DEBUG0("waiting on reader to quit");
- pause();
- }
-#ifndef HAVE_SMMAP
- /* Deallocate the shared memory segment. */
- shmdt(buf);
-#endif /* HAVE_SMMAP */
+ if (buf && buf->BufferThread) {
+ buffer_WaitForEmpty (buf);
+ pthread_cancel (buf->BufferThread);
+ pthread_join (buf->BufferThread, NULL);
+ buf->BufferThread = 0;
+ }
DEBUG0("buffer done.");
}
@@ -298,12 +250,8 @@
void buffer_cleanup (buf_t *buf) {
if (buf) {
- if (buf->writerpid)
- kill (buf->writerpid, SIGTERM);
- wait (0);
- buf->writerpid = 0;
-#ifndef HAVE_SMMAP
- shmdt(buf);
-#endif
+ buffer_shutdown (buf);
+ PthreadCleanup (buf);
+ free (buf);
}
}
1.2.2.6 +40 -13 vorbis-tools/ogg123/buffer.h
Index: buffer.h
===================================================================
RCS file: /usr/local/cvsroot/vorbis-tools/ogg123/buffer.h,v
retrieving revision 1.2.2.5
retrieving revision 1.2.2.6
diff -u -r1.2.2.5 -r1.2.2.6
--- buffer.h 2001/08/09 01:56:55 1.2.2.5
+++ buffer.h 2001/08/10 16:33:40 1.2.2.6
@@ -1,10 +1,26 @@
-/* Common things between reader and writer threads */
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
+ * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
+ * PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE Ogg123 SOURCE CODE IS (C) COPYRIGHT 2000-2001 *
+ * by Kenneth C. Arnold <ogg at arnoldnet.net> AND OTHER CONTRIBUTORS *
+ * http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ last mod: $Id: buffer.h,v 1.2.2.6 2001/08/10 16:33:40 kcarnold Exp $
+
+********************************************************************/
+/* A (relatively) generic circular buffer interface */
+
#ifndef __BUFFER_H
#define __BUFFER_H
-#include "ogg123.h"
-#include <sys/types.h>
+#include <pthread.h>
/* 4096 is the chunk size we request from libvorbis. */
#define BUFFER_CHUNK_SIZE 4096
@@ -17,30 +33,41 @@
typedef struct buf_s
{
- char status; /* Status. See STAT_* below. */
- int fds[2]; /* Pipe file descriptors. */
+ /* generic buffer interface */
+ void * data;
+ size_t (*write_func) (void *ptr, size_t size, size_t nmemb, void * d);
+
+ /* pthreads variables */
+ pthread_t BufferThread;
+ pthread_mutex_t SizeMutex;
+ pthread_mutex_t StatMutex;
+ pthread_cond_t UnderflowCondition; /* signalled on buffer underflow */
+ pthread_cond_t OverflowCondition; /* signalled on buffer overflow */
+ pthread_cond_t DataReadyCondition; /* signalled when data is ready and it wasn't before */
+
+ /* the buffer itself */
+ char StatMask;
long size; /* buffer size, for reference */
long curfill; /* how much the buffer is currently filled */
long prebuffer; /* number of chunks to prebuffer */
- pid_t readerpid; /* PID of reader process */
- pid_t writerpid; /* PID of writer process */
chunk_t *reader; /* Chunk the reader is busy with */
chunk_t *writer; /* Chunk the writer is busy with */
chunk_t *end; /* Last chunk in the buffer (for convenience) */
chunk_t buffer[1]; /* The buffer itself. It's more than one chunk. */
} buf_t;
+
+#define STAT_PREBUFFERING 1
+#define STAT_PLAYING 2
+#define STAT_EMPTYING 4
-buf_t *fork_writer (long size, devices_t *d, long prebuffer);
+buf_t *StartBuffer (long size, long prebuffer, void *data,
+ size_t (*write_func) (void *, size_t, size_t, void *));
void submit_chunk (buf_t *buf, chunk_t chunk);
void buffer_shutdown (buf_t *buf);
void buffer_cleanup (buf_t *buf);
void buffer_flush (buf_t *buf);
+void buffer_WaitForEmpty (buf_t *buf);
long buffer_full (buf_t *buf);
-
-#define STAT_FLUSH 1
-#define STAT_SHUTDOWN 2
-#define STAT_PREBUFFER 4
-#define STAT_UNDERFLOW 8
#endif /* !defined (__BUFFER_H) */
1.39.2.8 +65 -83 vorbis-tools/ogg123/ogg123.c
Index: ogg123.c
===================================================================
RCS file: /usr/local/cvsroot/vorbis-tools/ogg123/ogg123.c,v
retrieving revision 1.39.2.7
retrieving revision 1.39.2.8
diff -u -r1.39.2.7 -r1.39.2.8
--- ogg123.c 2001/08/09 01:56:55 1.39.2.7
+++ ogg123.c 2001/08/10 16:33:40 1.39.2.8
@@ -1,4 +1,4 @@
-/* ogg123.c by Kenneth Arnold <kcarnold at arnoldnet.net> */
+/* ogg123.c by Kenneth Arnold <ogg123 at arnoldnet.net> */
/* Modified to use libao by Stan Seibert <volsung at asu.edu> */
/********************************************************************
@@ -8,18 +8,16 @@
* THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
* PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
- * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2000 *
- * by Monty <monty at xiph.org> and the XIPHOPHORUS Company *
+ * THE Ogg123 SOURCE CODE IS (C) COPYRIGHT 2000-2001 *
+ * by Kenneth C. Arnold <ogg at arnoldnet.net> AND OTHER CONTRIBUTORS *
* http://www.xiph.org/ *
* *
********************************************************************
- last mod: $Id: ogg123.c,v 1.39.2.7 2001/08/09 01:56:55 kcarnold Exp $
+ last mod: $Id: ogg123.c,v 1.39.2.8 2001/08/10 16:33:40 kcarnold Exp $
********************************************************************/
-/* FIXME : That was a messy message. Fix it. */
-
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
@@ -30,18 +28,19 @@
#include <errno.h>
#include <time.h>
#include <getopt.h>
-
#include <signal.h>
#include "ogg123.h"
+#include "ao_interface.h"
+#include "buffer.h"
/* take buffer out of the data segment, not the stack */
char convbuffer[BUFFER_CHUNK_SIZE];
int convsize = BUFFER_CHUNK_SIZE;
-buf_t * buffer = NULL;
+buf_t * InBuffer = NULL;
+buf_t * OutBuffer = NULL;
static char skipfile_requested;
-/*static void (*old_sig)(int);*/
struct {
char *key; /* includes the '=' for programming convenience */
@@ -108,6 +107,7 @@
" v to previously specified device (with -d). See\n"
" man page for more info.\n"
" -b n, --buffer n use a buffer of approximately 'n' kilobytes\n"
+ " -p n, --prebuffer n prebuffer n% of the buffer before playing\n"
" -v, --verbose display progress and other useful stuff\n"
" -q, --quiet don't display anything (no title)\n"
" -z, --shuffle shuffle play\n"
@@ -134,7 +134,7 @@
opt.nth = 1;
opt.ntimes = 1;
- atexit (ogg123_atexit);
+ on_exit (ogg123_onexit, &opt);
signal (SIGINT, signal_quit);
ao_initialize();
@@ -187,7 +187,12 @@
usage();
exit(0);
case 'p':
- opt.prebuffer = atoi (optarg);
+ opt.prebuffer = atoi (optarg); /* prebuffer in integer percentage */
+ if (opt.prebuffer < 0 || opt.prebuffer > 100)
+ {
+ fprintf (stderr, "Prebuffer value invalid. Range is 0-100, using nearest value.\n");
+ opt.prebuffer = opt.prebuffer < 0 ? 0 : 100;
+ }
break;
case 'q':
opt.quiet++;
@@ -215,8 +220,10 @@
}
}
- if (opt.buffer_size > 1 && opt.prebuffer == 0)
- opt.prebuffer = 1; /* for good measure */
+ if (optind == argc) {
+ usage();
+ exit(1);
+ }
/* Add last device to device list or use the default device */
if (temp_driver_id < 0) {
@@ -233,11 +240,13 @@
temp_options, NULL);
}
- if (optind == argc) {
- usage();
- exit(1);
- }
-
+ if (opt.buffer_size)
+ {
+ opt.prebuffer = (int) ((double) opt.prebuffer * (double) opt.buffer_size / 100.0F);
+ OutBuffer = StartBuffer (opt.buffer_size, opt.prebuffer,
+ opt.outdevices, devices_write);
+ }
+
if (opt.shuffle) {
int i;
@@ -257,22 +266,13 @@
optind++;
}
- while (opt.outdevices != NULL) {
- if (opt.outdevices->device)
- ao_close(opt.outdevices->device);
- current = opt.outdevices->next_device;
- free(opt.outdevices);
- opt.outdevices = current;
+ if (OutBuffer != NULL) {
+ buffer_WaitForEmpty (OutBuffer);
+ buffer_cleanup (OutBuffer);
+ OutBuffer = NULL;
}
-
- if (buffer != NULL) {
- buffer_shutdown(buffer);
- buffer = NULL;
- }
- ao_shutdown();
-
- return (0);
+ exit (0);
}
/* Two signal handlers, one for SIGINT, and the second for
@@ -292,23 +292,12 @@
* and blow away existing "output.wav" file.
*/
- fprintf (stderr, "skipfile\n");
-
-#if 0
- if (old_sig != NULL) {
- signal(which_signal,old_sig);
- raise(which_signal);
- }
- else
-#endif
- signal (SIGINT, signal_quit);
- /* should that be unconditional? man pages are not clear on this */
+ signal (SIGINT, signal_quit);
}
void signal_activate_skipfile(int ignored)
{
- fprintf (stderr, "activate skipfile.\n");
- /*old_sig = */signal(SIGINT,signal_skipfile);
+ signal(SIGINT,signal_skipfile);
}
void signal_quit(int ignored)
@@ -331,8 +320,6 @@
int is_big_endian = ao_is_big_endian();
double realseekpos = opt.seekpos;
int nthc = 0, ntimesc = 0;
-
- /* Junk left over from the failed info struct */
double u_time, u_pos;
if (strcmp(opt.read_file, "-")) { /* input file not stdin */
@@ -436,7 +423,7 @@
vorbis_comment *vc = ov_comment(&vf, -1);
vorbis_info *vi = ov_info(&vf, -1);
- if(open_audio_devices(&opt, vi->rate, vi->channels, &buffer) < 0)
+ if(open_audio_devices(&opt, vi->rate, vi->channels) < 0)
exit(1);
if (opt.quiet < 1) {
@@ -487,8 +474,8 @@
skipfile_requested = 0;
signal(SIGALRM,signal_activate_skipfile);
alarm(opt.delay);
- if (buffer) {
- buffer_flush (buffer);
+ if (OutBuffer) {
+ buffer_flush (OutBuffer);
}
break;
}
@@ -515,16 +502,16 @@
do {
if (nthc-- == 0) {
- if (buffer)
+ if (OutBuffer)
{
chunk_t chunk;
chunk.len = ret;
memcpy (chunk.data, convbuffer, ret);
- submit_chunk (buffer, chunk);
+ submit_chunk (OutBuffer, chunk);
}
else
- devices_write(convbuffer, ret, opt.outdevices);
+ devices_write(convbuffer, ret, 1, opt.outdevices);
nthc = opt.nth - 1;
}
} while (++ntimesc < opt.ntimes);
@@ -537,12 +524,12 @@
c_sec = u_pos - 60 * c_min;
r_min = (long) (u_time - u_pos) / (long) 60;
r_sec = (u_time - u_pos) - 60 * r_min;
- if (buffer)
+ if (OutBuffer)
fprintf(stderr,
"\rTime: %02li:%05.2f [%02li:%05.2f] of %02li:%05.2f, Bitrate: %.1f, Buffer fill: %3.0f%% \r",
c_min, c_sec, r_min, r_sec, t_min, t_sec,
(double) ov_bitrate_instant(&vf) / 1000.0F,
- (double) buffer_full(buffer) / (double) buffer->size * 100.0F);
+ (double) buffer_full(OutBuffer) / (double) OutBuffer->size * 100.0F);
else
fprintf(stderr,
"\rTime: %02li:%05.2f [%02li:%05.2f] of %02li:%05.2f, Bitrate: %.1f \r",
@@ -550,15 +537,16 @@
(double) ov_bitrate_instant(&vf) / 1000.0F);
} else {
/* working around a bug in vorbisfile */
+ /* I don't think that bug is there anymore -ken */
u_pos = (double) ov_pcm_tell(&vf) / (double) vi->rate;
c_min = (long) u_pos / (long) 60;
c_sec = u_pos - 60 * c_min;
- if (buffer)
+ if (OutBuffer)
fprintf(stderr,
"\rTime: %02li:%05.2f, Bitrate: %.1f, Buffer fill: %3.0f%% \r",
c_min, c_sec,
(float) ov_bitrate_instant (&vf) / 1000.0F,
- (double) buffer_full(buffer) / (double) buffer->size * 100.0F);
+ (double) buffer_full(OutBuffer) / (double) OutBuffer->size * 100.0F);
else
fprintf(stderr,
"\rTime: %02li:%05.2f, Bitrate: %.1f \r",
@@ -580,14 +568,9 @@
fprintf(stderr, "\nDone.\n");
}
-int get_tcp_socket(void)
-{
- return socket(AF_INET, SOCK_STREAM, 0);
-}
-
FILE *http_open(char *server, int port, char *path)
{
- int sockfd = get_tcp_socket();
+ int sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct hostent *host;
struct sockaddr_in sock_name;
@@ -611,7 +594,9 @@
return fdopen(sockfd, "r+b");
}
-int open_audio_devices(ogg123_options_t *opt, int rate, int channels, buf_t **buffer)
+/* if not for the two lines involving the buffer, this would go in
+ * ao_interface.c. */
+int open_audio_devices(ogg123_options_t *opt, int rate, int channels)
{
static int prevrate=0, prevchan=0;
devices_t *current;
@@ -622,16 +607,10 @@
if(prevrate !=0 && prevchan!=0)
{
- if (buffer != NULL && *buffer != NULL) {
- buffer_shutdown (*buffer);
- *buffer = NULL;
- }
-
- current = opt->outdevices;
- while (current != NULL) {
- ao_close(current->device);
- current = current->next_device;
- }
+ if (OutBuffer)
+ buffer_WaitForEmpty (OutBuffer);
+
+ close_audio_devices (opt->outdevices);
}
format.rate = prevrate = rate;
@@ -660,7 +639,7 @@
if (current->device == NULL) {
switch (errno) {
case AO_ENODRIVER:
- fprintf(stderr, "Error: No device not available.\n");
+ fprintf(stderr, "Error: Device not available.\n");
break;
case AO_ENOTLIVE:
fprintf(stderr, "Error: %s requires an output filename to be specified with -f.\n", info->short_name);
@@ -696,15 +675,18 @@
current = current->next_device;
}
- if (opt->buffer_size)
- *buffer = fork_writer (opt->buffer_size, opt->outdevices, opt->prebuffer);
-
- return 0;
+ return 0;
}
-void ogg123_atexit (void)
+void ogg123_onexit (int exitcode, void *arg)
{
- if (buffer)
- buffer_cleanup (buffer);
- buffer = NULL;
+ ogg123_options_t *opt = (ogg123_options_t*) arg;
+
+ if (OutBuffer) {
+ buffer_flush (OutBuffer);
+ buffer_cleanup (OutBuffer);
+ OutBuffer = NULL;
+ }
+
+ ao_atexit (exitcode, opt->outdevices);
}
1.7.2.7 +21 -22 vorbis-tools/ogg123/ogg123.h
Index: ogg123.h
===================================================================
RCS file: /usr/local/cvsroot/vorbis-tools/ogg123/ogg123.h,v
retrieving revision 1.7.2.6
retrieving revision 1.7.2.7
diff -u -r1.7.2.6 -r1.7.2.7
--- ogg123.h 2001/08/06 21:35:40 1.7.2.6
+++ ogg123.h 2001/08/10 16:33:40 1.7.2.7
@@ -1,5 +1,20 @@
-/* This file is part of ogg123, an Ogg Vorbis player. See ogg123.c
- * for copyright information. */
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
+ * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
+ * PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE Ogg123 SOURCE CODE IS (C) COPYRIGHT 2000-2001 *
+ * by Kenneth C. Arnold <ogg at arnoldnet.net> AND OTHER CONTRIBUTORS *
+ * http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ last mod: $Id: ogg123.h,v 1.7.2.7 2001/08/10 16:33:40 kcarnold Exp $
+
+ ********************************************************************/
+
#ifndef __OGG123_H
#define __OGG123_H
@@ -13,14 +28,7 @@
#include <alloca.h>
#endif
-/* For facilitating output to multiple devices */
-typedef struct devices_s {
- int driver_id;
- ao_device *device;
- ao_option *options;
- char *filename;
- struct devices_s *next_device;
-} devices_t;
+#include "ao_interface.h"
typedef struct ogg123_options_s {
char *read_file; /* File to decode */
@@ -39,20 +47,11 @@
int ntimes; /* Play every chunk n times */
} ogg123_options_t; /* Changed in 0.6 to be non-static */
-/* This goes here because it relies on some of the above. */
-#include "buffer.h"
-
-devices_t *append_device(devices_t * devices_list, int driver_id,
- ao_option * options, char *filename);
-void devices_write(void *ptr, size_t size, devices_t * d);
void usage(void);
-int add_option(ao_option ** op_h, const char *optstring);
-int get_default_device(void);
void play_file(ogg123_options_t opt);
-int get_tcp_socket(void); /* Will be going soon. */
-FILE *http_open(char *server, int port, char *path); /* ditto */
-int open_audio_devices(ogg123_options_t *opt, int rate, int channels, buf_t ** buffer);
+FILE *http_open(char *server, int port, char *path);
+int open_audio_devices(ogg123_options_t *opt, int rate, int channels);
void signal_quit (int ignored);
-void ogg123_atexit (void);
+void ogg123_onexit (int exitcode, void *arg);
#endif /* !defined(__OGG123_H) */
--- >8 ----
List archives: http://www.xiph.org/archives/
Ogg project homepage: http://www.xiph.org/ogg/
To unsubscribe from this list, send a message to 'cvs-request at xiph.org'
containing only the word 'unsubscribe' in the body. No subject is needed.
Unsubscribe messages sent to the list will be ignored/filtered.
More information about the commits
mailing list