[xiph-cvs] cvs commit: vorbis-tools/ogg123 buffer.c buffer.h ogg123.c
Kenneth C. Arnold
kcarnold at xiph.org
Fri Aug 10 13:48:08 PDT 2001
kcarnold 01/08/10 13:48:07
Modified: ogg123 Tag: kcarnold_work buffer.c buffer.h ogg123.c
Log:
Was just working on the curl stuff and realized it would be kinda nice to have
an unchunked buffer. Well whaddyaknow...
Revision Changes Path
No revision
No revision
1.7.2.7 +130 -39 vorbis-tools/ogg123/buffer.c
Index: buffer.c
===================================================================
RCS file: /usr/local/cvsroot/vorbis-tools/ogg123/buffer.c,v
retrieving revision 1.7.2.6
retrieving revision 1.7.2.7
diff -u -r1.7.2.6 -r1.7.2.7
--- buffer.c 2001/08/10 16:33:40 1.7.2.6
+++ buffer.c 2001/08/10 20:48:06 1.7.2.7
@@ -11,7 +11,7 @@
* *
********************************************************************
- last mod: $Id: buffer.c,v 1.7.2.6 2001/08/10 16:33:40 kcarnold Exp $
+ last mod: $Id: buffer.c,v 1.7.2.7 2001/08/10 20:48:06 kcarnold Exp $
********************************************************************/
@@ -23,35 +23,35 @@
*/
#include <sys/types.h>
-#if HAVE_SMMAP
-#include <sys/mman.h>
-#else
-#include <sys/ipc.h>
-#include <sys/shm.h>
-#endif
#include <sys/wait.h>
#include <sys/time.h>
#include <unistd.h> /* for fork and pipe*/
#include <fcntl.h>
#include <signal.h>
+#include <assert.h> /* for debug purposes */
+
#include "ogg123.h"
#include "buffer.h"
-#undef DEBUG_BUFFER
+#define DEBUG_BUFFER
#ifdef DEBUG_BUFFER
FILE *debugfile;
-#define DEBUG0(x) do { fprintf (debugfile, x "\n" ); } while (0)
-#define DEBUG1(x, y) do { fprintf (debugfile, x "\n" , y); } while (0)
+#define DEBUG0(x) do { if (pthread_self() == buf->BufferThread) fprintf (debugfile, "R: " x "\n" ); else fprintf (debugfile, "W: " x "\n" ); } while (0)
+#define DEBUG1(x, y) do { if (pthread_self() == buf->BufferThread) fprintf (debugfile, "R-: " x "\n", y ); else fprintf (debugfile, "W-: " x "\n", y ); } while (0)
+#define DUMP_BUFFER_INFO(buf) do { fprintf (debugfile, "Buffer info: -reader=%p -writer=%p -buf=%p -end=%p -curfill=%d\n", buf->reader, buf->writer, buf->buffer, buf->end, buf->curfill); } while (0)
#else
#define DEBUG0(x)
#define DEBUG1(x, y)
+#define DUMP_BUFFER_INFO(buf)
#endif
#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)
+#define TARGET_WRITE_SIZE 4096 /* to agree with other mechanisms used in ogg123 */
+
void Prebuffer (buf_t * buf)
{
if (buf->prebuffer > 0)
@@ -83,8 +83,10 @@
sigset_t set;
buf_t *buf = (buf_t*) arg;
volatile buf_t *vbuf = (volatile buf_t*) buf; /* optimizers... grr */
+ size_t WriteThisTime = 0;
+ chunk *NewWriterPtr;
- DEBUG0("r: BufferFunc");
+ DEBUG0("BufferFunc");
sigfillset (&set);
pthread_sigmask (SIG_SETMASK, &set, NULL);
@@ -98,50 +100,86 @@
checkPlaying:
while (!(buf->StatMask & STAT_PLAYING) ||
(buf->StatMask & STAT_PREBUFFERING)) {
- DEBUG1 ("r: waiting on !playing || prebuffering (stat=%d)", buf->StatMask);
+ DEBUG1 ("waiting on !playing || prebuffering (stat=%d)", buf->StatMask);
pthread_cond_wait (&buf->DataReadyCondition, &buf->SizeMutex);
}
+ DUMP_BUFFER_INFO(buf);
+ assert (buf->curfill >= 0);
+ assert (buf->writer >= buf->buffer);
+ assert (buf->writer <= buf->end);
+ assert (buf->reader >= buf->buffer);
+ assert (buf->reader <= buf->end);
+
if (buf->curfill == 0) {
UNLOCK_MUTEX (buf->SizeMutex);
- DEBUG0 ("r: signalling buffer underflow");
+ DEBUG0 ("signalling buffer underflow");
pthread_cond_signal (&buf->UnderflowCondition);
LOCK_MUTEX (buf->SizeMutex);
Prebuffer (buf);
- DEBUG0 ("r: waiting on data ready");
+ DEBUG0 ("waiting on data ready");
pthread_cond_wait (&buf->DataReadyCondition, &buf->SizeMutex);
goto checkPlaying;
}
+ if (buf->reader < buf->writer)
+ {
+ /* we have all the way to buf->end:
+ * |-------------------------------|
+ * |-^ ^---------------------|
+ * reader writer, our range
+ */
+ DEBUG1("up to buf->end, buf->end - buf->writer + 1 = %d", buf->end - buf->writer + 1);
+ if (buf->end - buf->writer + 1 > TARGET_WRITE_SIZE) {
+ WriteThisTime = TARGET_WRITE_SIZE;
+ NewWriterPtr = buf->writer + WriteThisTime;
+ } else {
+ NewWriterPtr = buf->buffer;
+ WriteThisTime = buf->end - buf->writer + 1;
+ }
+ }
+ else
+ {
+ /* we have up to buf->reader:
+ * |-------------------------------|
+ * ^--------------^
+ * writer reader
+ * but we can't use buf->reader itself, becuase that's not in the data.
+ */
+ DEBUG1("up to buf->reader, buf->reader - buf->writer = %d", buf->reader - buf->writer);
+ if (buf->reader - buf->writer > TARGET_WRITE_SIZE)
+ WriteThisTime = TARGET_WRITE_SIZE;
+ else
+ WriteThisTime = buf->reader - buf->writer;
+ NewWriterPtr = buf->writer + WriteThisTime;
+ }
+
+ DEBUG0("writing chunk to output");
/* unlock while playing sample */
UNLOCK_MUTEX (buf->SizeMutex);
-
- DEBUG0("writing chunk");
- buf->write_func (buf->writer->data, buf->writer->len, 1, buf->data);
+ DEBUG1("WriteThisTime=%d", WriteThisTime);
+ buf->write_func (buf->writer, WriteThisTime, 1, buf->data);
DEBUG0("incrementing pointer");
LOCK_MUTEX (buf->SizeMutex);
- if (vbuf->writer == vbuf->end)
- vbuf->writer = vbuf->buffer;
- else
- vbuf->writer++;
- vbuf->curfill--;
+ buf->writer = NewWriterPtr;
+ vbuf->curfill -= WriteThisTime;
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)
+ DEBUG0 ("signalling buffer no longer full");
+ if (buf->curfill + WriteThisTime + TARGET_WRITE_SIZE >= buf->size)
pthread_cond_signal (&buf->DataReadyCondition);
}
/* should never get here */
pthread_cleanup_pop(1);
- DEBUG0("r: exiting");
+ DEBUG0("exiting");
}
buf_t *StartBuffer (long size, long prebuffer, void *data,
size_t (*write_func) (void *, size_t, size_t, void *))
{
- buf_t *buf = malloc (sizeof(buf_t) + sizeof (chunk_t) * (size - 1));
+ buf_t *buf = malloc (sizeof(buf_t) + sizeof (chunk) * (size - 1));
if (buf == NULL)
{
@@ -180,38 +218,71 @@
return buf;
}
-void submit_chunk (buf_t *buf, chunk_t chunk)
+void _SubmitDataChunk (buf_t *buf, chunk *data, size_t size)
{
- DEBUG0("submit_chunk");
+ char PrevSize;
+ DEBUG1("submit_chunk, size %d", size);
LOCK_MUTEX (buf->SizeMutex);
+
+ PrevSize = buf->curfill;
+ DUMP_BUFFER_INFO(buf);
+
/* wait on buffer overflow */
- while (buf->curfill == buf->size && buf->StatMask & STAT_PLAYING)
+ while (buf->curfill + size > buf->size)
pthread_cond_wait (&buf->DataReadyCondition, &buf->SizeMutex);
-
- DEBUG0("writing chunk");
- *(buf->reader) = chunk;
- if (buf->reader == buf->end)
- buf->reader = buf->buffer;
- else
- buf->reader++;
- buf->curfill++;
+ DEBUG0("writing chunk into buffer");
+ buf->curfill += size;
+ /* we're guaranteed to have enough space in the buffer by now */
+ if (buf->reader < buf->writer) {
+ DEBUG0("writer before end");
+ /* don't worry about falling off end */
+ memmove (buf->reader, data, size);
+ buf->reader += size;
+ } else {
+ size_t avail = buf->end - buf->reader + 1;
+ DEBUG0("don't run over the end!");
+ if (avail >= size)
+ memmove (buf->reader, data, size);
+ else {
+ memmove (buf->reader, data, avail);
+ size -= avail;
+ data += avail;
+ buf->reader = buf->buffer;
+ memmove (buf->reader, data, size);
+ }
+ buf->reader += size;
+ }
+
UNLOCK_MUTEX (buf->SizeMutex);
if ((buf->StatMask & STAT_PREBUFFERING)
- && buffer_full(buf) >= buf->prebuffer) {
+ && buf->curfill >= 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)
+ else if (PrevSize == 0)
pthread_cond_signal (&buf->DataReadyCondition);
DEBUG0("submit_chunk exit");
}
+void SubmitData (buf_t *buf, chunk *data, size_t size, size_t nmemb)
+{
+ int i, s;
+ while (nmemb > 0) {
+ for (i = 0; i < size; i += TARGET_WRITE_SIZE) {
+ s = i + TARGET_WRITE_SIZE <= size ? TARGET_WRITE_SIZE : size - i;
+ _SubmitDataChunk (buf, data, s);
+ data += s;
+ }
+ nmemb--;
+ }
+}
+
void buffer_flush (buf_t *buf)
{
DEBUG0("flush buffer");
@@ -246,6 +317,26 @@
long buffer_full (buf_t* buf) {
return buf->curfill;
+}
+
+void buffer_Pause (buf_t *buf)
+{
+ LOCK_MUTEX (buf->StatMutex);
+ buf->StatMask &= ~STAT_PLAYING;
+ UNLOCK_MUTEX (buf->StatMutex);
+}
+
+void buffer_Unpause (buf_t *buf)
+{
+ LOCK_MUTEX (buf->StatMutex);
+ buf->StatMask |= STAT_PLAYING;
+ UNLOCK_MUTEX (buf->StatMutex);
+ pthread_cond_signal (&buf->DataReadyCondition);
+}
+
+char buffer_Paused (buf_t *buf)
+{
+ return (char) !(buf->StatMask & STAT_PLAYING);
}
void buffer_cleanup (buf_t *buf) {
1.2.2.7 +12 -18 vorbis-tools/ogg123/buffer.h
Index: buffer.h
===================================================================
RCS file: /usr/local/cvsroot/vorbis-tools/ogg123/buffer.h,v
retrieving revision 1.2.2.6
retrieving revision 1.2.2.7
diff -u -r1.2.2.6 -r1.2.2.7
--- buffer.h 2001/08/10 16:33:40 1.2.2.6
+++ buffer.h 2001/08/10 20:48:06 1.2.2.7
@@ -11,7 +11,7 @@
* *
********************************************************************
- last mod: $Id: buffer.h,v 1.2.2.6 2001/08/10 16:33:40 kcarnold Exp $
+ last mod: $Id: buffer.h,v 1.2.2.7 2001/08/10 20:48:06 kcarnold Exp $
********************************************************************/
@@ -22,20 +22,13 @@
#include <pthread.h>
-/* 4096 is the chunk size we request from libvorbis. */
-#define BUFFER_CHUNK_SIZE 4096
+typedef unsigned char chunk; /* sizeof (chunk) must be 1; if you need otherwise it's not hard to fix */
-typedef struct chunk_s
-{
- long len; /* Length of the chunk (for if we only got partial data) */
- unsigned char data[BUFFER_CHUNK_SIZE];
-} chunk_t;
-
typedef struct buf_s
{
/* generic buffer interface */
void * data;
- size_t (*write_func) (void *ptr, size_t size, size_t nmemb, void * d);
+ size_t (*write_func) (chunk *ptr, size_t size, size_t nmemb, void * d);
/* pthreads variables */
pthread_t BufferThread;
@@ -50,10 +43,10 @@
long size; /* buffer size, for reference */
long curfill; /* how much the buffer is currently filled */
long prebuffer; /* number of chunks to prebuffer */
- 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. */
+ chunk *reader; /* Chunk the reader is busy with */
+ chunk *writer; /* Chunk the writer is busy with */
+ chunk *end; /* Last chunk in the buffer (for convenience) */
+ chunk buffer[1]; /* The buffer itself. It's more than one chunk. */
} buf_t;
#define STAT_PREBUFFERING 1
@@ -62,14 +55,15 @@
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 SubmitData (buf_t *buf, chunk *data, size_t size, size_t nmemb);
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);
-
-#endif /* !defined (__BUFFER_H) */
-
+void buffer_Pause (buf_t *buf);
+void buffer_Unpause (buf_t *buf);
+char buffer_Paused (buf_t *buf);
+#endif /* !defined (__BUFFER_H) */
1.39.2.9 +10 -14 vorbis-tools/ogg123/ogg123.c
Index: ogg123.c
===================================================================
RCS file: /usr/local/cvsroot/vorbis-tools/ogg123/ogg123.c,v
retrieving revision 1.39.2.8
retrieving revision 1.39.2.9
diff -u -r1.39.2.8 -r1.39.2.9
--- ogg123.c 2001/08/10 16:33:40 1.39.2.8
+++ ogg123.c 2001/08/10 20:48:06 1.39.2.9
@@ -14,7 +14,7 @@
* *
********************************************************************
- last mod: $Id: ogg123.c,v 1.39.2.8 2001/08/10 16:33:40 kcarnold Exp $
+ last mod: $Id: ogg123.c,v 1.39.2.9 2001/08/10 20:48:06 kcarnold Exp $
********************************************************************/
@@ -35,6 +35,7 @@
#include "buffer.h"
/* take buffer out of the data segment, not the stack */
+#define BUFFER_CHUNK_SIZE 4096
char convbuffer[BUFFER_CHUNK_SIZE];
int convsize = BUFFER_CHUNK_SIZE;
buf_t * InBuffer = NULL;
@@ -146,7 +147,7 @@
"Internal error: long option given when none expected.\n");
exit(1);
case 'b':
- opt.buffer_size = atoi(optarg) / (BUFFER_CHUNK_SIZE / 1024);
+ opt.buffer_size = atoi(optarg) * 1024;
break;
case 'd':
temp_driver_id = ao_driver_id(optarg);
@@ -249,14 +250,15 @@
if (opt.shuffle) {
int i;
+ int range = argc - optind;
- srand(time(NULL));
+ srandom(time(NULL));
for (i = optind; i < argc; i++) {
- int j = optind + (int) ((double)(argc - i)*(double)rand()/(RAND_MAX+1.0));
- char *temp = argv[i];
- argv[i] = argv[j];
- argv[j] = temp;
+ int j = optind + random() % range;
+ char *temp = argv[i];
+ argv[i] = argv[j];
+ argv[j] = temp;
}
}
@@ -503,13 +505,7 @@
do {
if (nthc-- == 0) {
if (OutBuffer)
- {
- chunk_t chunk;
- chunk.len = ret;
- memcpy (chunk.data, convbuffer, ret);
-
- submit_chunk (OutBuffer, chunk);
- }
+ SubmitData (OutBuffer, convbuffer, ret, 1);
else
devices_write(convbuffer, ret, 1, opt.outdevices);
nthc = opt.nth - 1;
--- >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