summaryrefslogtreecommitdiff
path: root/gst-libs/gst/audio/gstringbuffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'gst-libs/gst/audio/gstringbuffer.c')
-rw-r--r--gst-libs/gst/audio/gstringbuffer.c282
1 files changed, 282 insertions, 0 deletions
diff --git a/gst-libs/gst/audio/gstringbuffer.c b/gst-libs/gst/audio/gstringbuffer.c
new file mode 100644
index 000000000..07889db20
--- /dev/null
+++ b/gst-libs/gst/audio/gstringbuffer.c
@@ -0,0 +1,282 @@
+/* GStreamer
+ * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
+ *
+ * gstringbuffer.c:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+
+#include "gstringbuffer.h"
+
+static void gst_ringbuffer_class_init (GstRingBufferClass * klass);
+static void gst_ringbuffer_init (GstRingBuffer * ringbuffer);
+static void gst_ringbuffer_dispose (GObject * object);
+static void gst_ringbuffer_finalize (GObject * object);
+
+static GstObjectClass *parent_class = NULL;
+
+/* ringbuffer abstract base class */
+GType
+gst_ringbuffer_get_type (void)
+{
+ static GType ringbuffer_type = 0;
+
+ if (!ringbuffer_type) {
+ static const GTypeInfo ringbuffer_info = {
+ sizeof (GstRingBufferClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) gst_ringbuffer_class_init,
+ NULL,
+ NULL,
+ sizeof (GstRingBuffer),
+ 0,
+ (GInstanceInitFunc) gst_ringbuffer_init,
+ NULL
+ };
+
+ ringbuffer_type = g_type_register_static (GST_TYPE_OBJECT, "GstRingBuffer",
+ &ringbuffer_info, G_TYPE_FLAG_ABSTRACT);
+ }
+ return ringbuffer_type;
+}
+
+static void
+gst_ringbuffer_class_init (GstRingBufferClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstObjectClass *gstobject_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstobject_class = (GstObjectClass *) klass;
+
+ parent_class = g_type_class_ref (GST_TYPE_OBJECT);
+
+ gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_ringbuffer_dispose);
+ gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ringbuffer_finalize);
+}
+
+static void
+gst_ringbuffer_init (GstRingBuffer * ringbuffer)
+{
+ ringbuffer->acquired = FALSE;
+ ringbuffer->state = GST_RINGBUFFER_STATE_STOPPED;
+ ringbuffer->playseg = 0;
+ ringbuffer->writeseg = 1;
+ ringbuffer->segfilled = 0;
+ ringbuffer->waiters = FALSE;
+ ringbuffer->cond = g_cond_new ();
+}
+
+static void
+gst_ringbuffer_dispose (GObject * object)
+{
+ GstRingBuffer *ringbuffer = GST_RINGBUFFER (object);
+
+ G_OBJECT_CLASS (parent_class)->dispose (G_OBJECT (ringbuffer));
+}
+
+static void
+gst_ringbuffer_finalize (GObject * object)
+{
+ GstRingBuffer *ringbuffer = GST_RINGBUFFER (object);
+
+ g_cond_free (ringbuffer->cond);
+
+ G_OBJECT_CLASS (parent_class)->finalize (G_OBJECT (ringbuffer));
+}
+
+void
+gst_ringbuffer_set_callback (GstRingBuffer * buf, GstRingBufferCallback cb,
+ gpointer data)
+{
+ GST_LOCK (buf);
+ buf->callback = cb;
+ buf->cb_data = data;
+ GST_UNLOCK (buf);
+}
+
+
+gboolean
+gst_ringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
+{
+ gboolean res = FALSE;
+ GstRingBufferClass *rclass;
+
+ GST_LOCK (buf);
+ if (buf->acquired) {
+ res = TRUE;
+ goto done;
+ }
+ buf->acquired = TRUE;
+ GST_UNLOCK (buf);
+
+ rclass = GST_RINGBUFFER_GET_CLASS (buf);
+ if (rclass->acquire)
+ res = rclass->acquire (buf, spec);
+
+ GST_LOCK (buf);
+ if (!res) {
+ buf->acquired = FALSE;
+ }
+done:
+ GST_UNLOCK (buf);
+
+ return res;
+}
+
+gboolean
+gst_ringbuffer_release (GstRingBuffer * buf)
+{
+ gboolean res = FALSE;
+ GstRingBufferClass *rclass;
+
+ GST_LOCK (buf);
+ if (!buf->acquired) {
+ res = TRUE;
+ goto done;
+ }
+ buf->acquired = FALSE;
+ GST_UNLOCK (buf);
+
+ rclass = GST_RINGBUFFER_GET_CLASS (buf);
+ if (rclass->release)
+ res = rclass->release (buf);
+
+ GST_LOCK (buf);
+ if (!res) {
+ buf->acquired = TRUE;
+ }
+done:
+ GST_UNLOCK (buf);
+
+ return res;
+}
+
+gboolean
+gst_ringbuffer_play (GstRingBuffer * buf)
+{
+ gboolean res = FALSE;
+ GstRingBufferClass *rclass;
+
+ GST_LOCK (buf);
+ if (buf->state == GST_RINGBUFFER_STATE_PLAYING) {
+ res = TRUE;
+ goto done;
+ }
+ buf->state = GST_RINGBUFFER_STATE_PLAYING;
+
+ rclass = GST_RINGBUFFER_GET_CLASS (buf);
+ if (rclass->play)
+ res = rclass->play (buf);
+
+ if (!res) {
+ buf->state = GST_RINGBUFFER_STATE_STOPPED;
+ }
+done:
+ GST_UNLOCK (buf);
+
+ return res;
+}
+
+gboolean
+gst_ringbuffer_stop (GstRingBuffer * buf)
+{
+ gboolean res = FALSE;
+ GstRingBufferClass *rclass;
+
+ GST_LOCK (buf);
+ if (buf->state == GST_RINGBUFFER_STATE_STOPPED) {
+ res = TRUE;
+ goto done;
+ }
+ buf->state = GST_RINGBUFFER_STATE_STOPPED;
+
+ rclass = GST_RINGBUFFER_GET_CLASS (buf);
+ if (rclass->stop)
+ res = rclass->stop (buf);
+
+ if (!res) {
+ buf->state = GST_RINGBUFFER_STATE_PLAYING;
+ }
+done:
+ GST_UNLOCK (buf);
+
+ return res;
+}
+
+void
+gst_ringbuffer_callback (GstRingBuffer * buf, guint advance)
+{
+ GST_LOCK (buf);
+ buf->playseg = (buf->playseg + advance) % buf->spec.segtotal;
+ if (buf->playseg == buf->writeseg) {
+ g_print ("underrun!! read %d, write %d\n", buf->playseg, buf->writeseg);
+ buf->writeseg = (buf->playseg + 1) % buf->spec.segtotal;
+ buf->segfilled = 0;
+ }
+ if (buf->waiters)
+ GST_RINGBUFFER_SIGNAL (buf);
+ GST_UNLOCK (buf);
+
+ if (buf->callback)
+ buf->callback (buf, advance, buf->cb_data);
+}
+
+guint
+gst_ringbuffer_write (GstRingBuffer * buf, GstClockTime time, guchar * data,
+ guint len)
+{
+ guint towrite = len;
+ guint written = 0;
+
+ GST_LOCK (buf);
+ /* we write the complete buffer */
+ while (towrite > 0) {
+ guint segavail;
+ guint segwrite;
+
+ /* we cannot write anymore since the buffer is filled, wait for
+ * some space to become available */
+ while (buf->writeseg == buf->playseg) {
+ buf->waiters = TRUE;
+ GST_RINGBUFFER_WAIT (buf);
+ buf->waiters = FALSE;
+ }
+
+ /* this is the available size now in the current segment */
+ segavail = buf->spec.segsize - buf->segfilled;
+
+ /* we write up to the available space */
+ segwrite = MIN (segavail, towrite);
+ memcpy (GST_BUFFER_DATA (buf->data) + buf->writeseg * buf->spec.segsize +
+ buf->segfilled, data, segwrite);
+ towrite -= segwrite;
+ data += segwrite;
+ buf->segfilled += segwrite;
+ written += segwrite;
+ /* we wrote a complete segment, advance the write pointer */
+ if (buf->segfilled == buf->spec.segsize) {
+ buf->writeseg = (buf->writeseg + 1) % buf->spec.segtotal;
+ buf->segfilled = 0;
+ }
+ }
+ GST_UNLOCK (buf);
+
+ return written;
+}