gst-libs/gst/audio/gstaudiosink.c: Implement a separate activate functions to start...
authorWim Taymans <wim.taymans@gmail.com>
Mon, 20 Oct 2008 15:35:37 +0000 (15:35 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Mon, 20 Oct 2008 15:35:37 +0000 (15:35 +0000)
Original commit message from CVS:
* gst-libs/gst/audio/gstaudiosink.c:
(gst_audioringbuffer_class_init), (gst_audioringbuffer_acquire),
(gst_audioringbuffer_activate), (gst_audioringbuffer_release),
(gst_audioringbuffer_stop):
Implement a separate activate functions to start monitoring the segments
or, in pull mode, pulling in data.
* gst-libs/gst/audio/gstbaseaudiosink.c:
(gst_base_audio_sink_init), (gst_base_audio_sink_dispose),
(gst_base_audio_sink_query_pad), (gst_base_audio_sink_query),
(gst_base_audio_sink_setcaps), (gst_base_audio_sink_callback),
(gst_base_audio_sink_activate_pull),
(gst_base_audio_sink_async_play),
(gst_base_audio_sink_change_state):
Implement pad and element convert query function.
Activate the ringbuffer.
Use the segment last_stop value as the offset to pull.
Use new basesink _do_preroll() method to preroll in the pulling thread.
Take appropriate locking in the pulling thread.
* gst-libs/gst/audio/gstringbuffer.h:
Update some docs.

ChangeLog
gst-libs/gst/audio/gstaudiosink.c
gst-libs/gst/audio/gstbaseaudiosink.c
gst-libs/gst/audio/gstringbuffer.h

index f2f4f2a..6dcf7d9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,28 @@
+2008-10-20  Wim Taymans  <wim.taymans@collabora.co.uk>
+
+       * gst-libs/gst/audio/gstaudiosink.c:
+       (gst_audioringbuffer_class_init), (gst_audioringbuffer_acquire),
+       (gst_audioringbuffer_activate), (gst_audioringbuffer_release),
+       (gst_audioringbuffer_stop):
+       Implement a separate activate functions to start monitoring the segments
+       or, in pull mode, pulling in data.
+
+       * gst-libs/gst/audio/gstbaseaudiosink.c:
+       (gst_base_audio_sink_init), (gst_base_audio_sink_dispose),
+       (gst_base_audio_sink_query_pad), (gst_base_audio_sink_query),
+       (gst_base_audio_sink_setcaps), (gst_base_audio_sink_callback),
+       (gst_base_audio_sink_activate_pull),
+       (gst_base_audio_sink_async_play),
+       (gst_base_audio_sink_change_state):
+       Implement pad and element convert query function.
+       Activate the ringbuffer.
+       Use the segment last_stop value as the offset to pull.
+       Use new basesink _do_preroll() method to preroll in the pulling thread.
+       Take appropriate locking in the pulling thread.
+
+       * gst-libs/gst/audio/gstringbuffer.h:
+       Update some docs.
+
 2008-10-20  Sebastian Dröge  <sebastian.droege@collabora.co.uk>
 
        * gst/typefind/gsttypefindfunctions.c: (mxf_type_find):
index dd868ca..b4b4571 100644 (file)
@@ -129,6 +129,8 @@ static gboolean gst_audioringbuffer_start (GstRingBuffer * buf);
 static gboolean gst_audioringbuffer_pause (GstRingBuffer * buf);
 static gboolean gst_audioringbuffer_stop (GstRingBuffer * buf);
 static guint gst_audioringbuffer_delay (GstRingBuffer * buf);
+static gboolean gst_audioringbuffer_activate (GstRingBuffer * buf,
+    gboolean active);
 
 /* ringbuffer abstract base class */
 static GType
@@ -187,6 +189,8 @@ gst_audioringbuffer_class_init (GstAudioRingBufferClass * klass)
   gstringbuffer_class->stop = GST_DEBUG_FUNCPTR (gst_audioringbuffer_stop);
 
   gstringbuffer_class->delay = GST_DEBUG_FUNCPTR (gst_audioringbuffer_delay);
+  gstringbuffer_class->activate =
+      GST_DEBUG_FUNCPTR (gst_audioringbuffer_activate);
 }
 
 typedef guint (*WriteFunc) (GstAudioSink * sink, gpointer data, guint length);
@@ -360,16 +364,13 @@ gst_audioringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
 {
   GstAudioSink *sink;
   GstAudioSinkClass *csink;
-  GstAudioRingBuffer *abuf;
   gboolean result = FALSE;
-  GError *error = NULL;
 
   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
   csink = GST_AUDIO_SINK_GET_CLASS (sink);
 
   if (csink->prepare)
     result = csink->prepare (sink, spec);
-
   if (!result)
     goto could_not_prepare;
 
@@ -379,37 +380,61 @@ gst_audioringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
   buf->data = gst_buffer_new_and_alloc (spec->segtotal * spec->segsize);
   memset (GST_BUFFER_DATA (buf->data), 0, GST_BUFFER_SIZE (buf->data));
 
-  abuf = GST_AUDIORING_BUFFER_CAST (buf);
-  abuf->running = TRUE;
-
-  GST_DEBUG_OBJECT (sink, "starting thread");
-  sink->thread =
-      g_thread_create ((GThreadFunc) audioringbuffer_thread_func, buf, TRUE,
-      &error);
-  if (!sink->thread || error != NULL)
-    goto thread_failed;
-
-  GST_DEBUG_OBJECT (sink, "waiting for thread");
-  /* the object lock is taken */
-  GST_AUDIORING_BUFFER_WAIT (buf);
-  GST_DEBUG_OBJECT (sink, "thread is started");
-
-  return result;
+  return TRUE;
 
+  /* ERRORS */
 could_not_prepare:
   {
     GST_DEBUG_OBJECT (sink, "could not prepare device");
     return FALSE;
   }
+}
+
+static gboolean
+gst_audioringbuffer_activate (GstRingBuffer * buf, gboolean active)
+{
+  GstAudioSink *sink;
+  GstAudioRingBuffer *abuf;
+  GError *error = NULL;
+
+  sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
+  abuf = GST_AUDIORING_BUFFER_CAST (buf);
+
+  if (active) {
+    abuf->running = TRUE;
+
+    GST_DEBUG_OBJECT (sink, "starting thread");
+    sink->thread =
+        g_thread_create ((GThreadFunc) audioringbuffer_thread_func, buf, TRUE,
+        &error);
+    if (!sink->thread || error != NULL)
+      goto thread_failed;
+
+    GST_DEBUG_OBJECT (sink, "waiting for thread");
+    /* the object lock is taken */
+    GST_AUDIORING_BUFFER_WAIT (buf);
+    GST_DEBUG_OBJECT (sink, "thread is started");
+  } else {
+    abuf->running = FALSE;
+    GST_DEBUG_OBJECT (sink, "signal wait");
+    GST_AUDIORING_BUFFER_SIGNAL (buf);
+
+    GST_OBJECT_UNLOCK (buf);
+
+    /* join the thread */
+    g_thread_join (sink->thread);
+
+    GST_OBJECT_LOCK (buf);
+  }
+  return TRUE;
+
+  /* ERRORS */
 thread_failed:
   {
     if (error)
       GST_ERROR_OBJECT (sink, "could not create thread %s", error->message);
     else
       GST_ERROR_OBJECT (sink, "could not create thread for unknown reason");
-    /* still unprepare */
-    if (csink->unprepare)
-      result = csink->unprepare (sink);
     return FALSE;
   }
 }
@@ -427,17 +452,6 @@ gst_audioringbuffer_release (GstRingBuffer * buf)
   csink = GST_AUDIO_SINK_GET_CLASS (sink);
   abuf = GST_AUDIORING_BUFFER_CAST (buf);
 
-  abuf->running = FALSE;
-  GST_DEBUG_OBJECT (sink, "signal wait");
-  GST_AUDIORING_BUFFER_SIGNAL (buf);
-
-  GST_OBJECT_UNLOCK (buf);
-
-  /* join the thread */
-  g_thread_join (sink->thread);
-
-  GST_OBJECT_LOCK (buf);
-
   /* free the buffer */
   gst_buffer_unref (buf->data);
   buf->data = NULL;
index 09055b3..302e469 100644 (file)
@@ -148,6 +148,9 @@ static gboolean gst_base_audio_sink_setcaps (GstBaseSink * bsink,
     GstCaps * caps);
 static void gst_base_audio_sink_fixate (GstBaseSink * bsink, GstCaps * caps);
 
+static gboolean gst_base_audio_sink_query_pad (GstPad * pad, GstQuery * query);
+
+
 /* static guint gst_base_audio_sink_signals[LAST_SIGNAL] = { 0 }; */
 
 static void
@@ -239,6 +242,10 @@ gst_base_audio_sink_init (GstBaseAudioSink * baseaudiosink,
   /* FIXME, enable pull mode when segments, latency, state changes, negotiation
    * and clock slaving are figured out */
   GST_BASE_SINK (baseaudiosink)->can_activate_pull = FALSE;
+
+  /* install some custom pad_query functions */
+  gst_pad_set_query_function (GST_BASE_SINK_PAD (baseaudiosink),
+      GST_DEBUG_FUNCPTR (gst_base_audio_sink_query_pad));
 }
 
 static void
@@ -260,6 +267,7 @@ gst_base_audio_sink_dispose (GObject * object)
   G_OBJECT_CLASS (parent_class)->dispose (object);
 }
 
+
 static GstClock *
 gst_base_audio_sink_provide_clock (GstElement * elem)
 {
@@ -299,11 +307,47 @@ clock_disabled:
 }
 
 static gboolean
+gst_base_audio_sink_query_pad (GstPad * pad, GstQuery * query)
+{
+  gboolean res = FALSE;
+  GstBaseAudioSink *basesink;
+
+  basesink = GST_BASE_AUDIO_SINK (gst_pad_get_parent (pad));
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CONVERT:
+    {
+      GstFormat src_fmt, dest_fmt;
+      gint64 src_val, dest_val;
+
+      GST_LOG_OBJECT (pad, "query convert");
+
+      if (basesink->ringbuffer) {
+        gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, NULL);
+        res = gst_ring_buffer_convert (basesink->ringbuffer, src_fmt, src_val,
+            dest_fmt, &dest_val);
+        if (res) {
+          gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
+        }
+      }
+      break;
+    }
+    default:
+      break;
+  }
+
+  gst_object_unref (basesink);
+
+  return res;
+}
+
+static gboolean
 gst_base_audio_sink_query (GstElement * element, GstQuery * query)
 {
   gboolean res = FALSE;
+  GstBaseAudioSink *basesink;
 
-  GstBaseAudioSink *basesink = GST_BASE_AUDIO_SINK (element);
+  basesink = GST_BASE_AUDIO_SINK (element);
 
   switch (GST_QUERY_TYPE (query)) {
     case GST_QUERY_LATENCY:
@@ -358,6 +402,23 @@ gst_base_audio_sink_query (GstElement * element, GstQuery * query)
       }
       break;
     }
+    case GST_QUERY_CONVERT:
+    {
+      GstFormat src_fmt, dest_fmt;
+      gint64 src_val, dest_val;
+
+      GST_LOG_OBJECT (basesink, "query convert");
+
+      if (basesink->ringbuffer) {
+        gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, NULL);
+        res = gst_ring_buffer_convert (basesink->ringbuffer, src_fmt, src_val,
+            dest_fmt, &dest_val);
+        if (res) {
+          gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
+        }
+      }
+      break;
+    }
     default:
       res = GST_ELEMENT_CLASS (parent_class)->query (element, query);
       break;
@@ -559,6 +620,7 @@ gst_base_audio_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
   GST_DEBUG_OBJECT (sink, "release old ringbuffer");
 
   /* release old ringbuffer */
+  gst_ring_buffer_activate (sink->ringbuffer, FALSE);
   gst_ring_buffer_release (sink->ringbuffer);
 
   GST_DEBUG_OBJECT (sink, "parse caps");
@@ -572,11 +634,15 @@ gst_base_audio_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
 
   gst_ring_buffer_debug_spec_buff (spec);
 
-  GST_DEBUG_OBJECT (sink, "acquire new ringbuffer");
-
+  GST_DEBUG_OBJECT (sink, "acquire ringbuffer");
   if (!gst_ring_buffer_acquire (sink->ringbuffer, spec))
     goto acquire_error;
 
+  if (bsink->pad_mode == GST_ACTIVATE_PUSH) {
+    GST_DEBUG_OBJECT (sink, "activate ringbuffer");
+    gst_ring_buffer_activate (sink->ringbuffer, TRUE);
+  }
+
   /* calculate actual latency and buffer times. 
    * FIXME: In 0.11, store the latency_time internally in ns */
   spec->latency_time = gst_util_uint64_scale (spec->segsize,
@@ -1523,25 +1589,6 @@ gst_base_audio_sink_create_ringbuffer (GstBaseAudioSink * sink)
   return buffer;
 }
 
-static gboolean
-gst_base_audio_sink_activate_pull (GstBaseSink * basesink, gboolean active)
-{
-  gboolean ret;
-  GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (basesink);
-
-  if (active) {
-    gst_ring_buffer_set_callback (sink->ringbuffer,
-        gst_base_audio_sink_callback, sink);
-    ret = gst_ring_buffer_start (sink->ringbuffer);
-  } else {
-    gst_ring_buffer_set_callback (sink->ringbuffer, NULL, NULL);
-    /* stop thread */
-    ret = gst_ring_buffer_release (sink->ringbuffer);
-  }
-
-  return ret;
-}
-
 static void
 gst_base_audio_sink_callback (GstRingBuffer * rbuf, guint8 * data, guint len,
     gpointer user_data)
@@ -1554,11 +1601,15 @@ gst_base_audio_sink_callback (GstRingBuffer * rbuf, guint8 * data, guint len,
   basesink = GST_BASE_SINK (user_data);
   sink = GST_BASE_AUDIO_SINK (user_data);
 
+  GST_PAD_STREAM_LOCK (basesink->sinkpad);
+
   /* would be nice to arrange for pad_alloc_buffer to return data -- as it is we
      will copy twice, once into data, once into DMA */
   GST_LOG_OBJECT (basesink, "pulling %d bytes offset %" G_GUINT64_FORMAT
       " to fill audio buffer", len, basesink->offset);
-  ret = gst_pad_pull_range (basesink->sinkpad, basesink->offset, len, &buf);
+  ret =
+      gst_pad_pull_range (basesink->sinkpad, basesink->segment.last_stop, len,
+      &buf);
 
   if (ret != GST_FLOW_OK) {
     if (ret == GST_FLOW_UNEXPECTED)
@@ -1567,15 +1618,27 @@ gst_base_audio_sink_callback (GstRingBuffer * rbuf, guint8 * data, guint len,
       goto error;
   }
 
+  GST_PAD_PREROLL_LOCK (basesink->sinkpad);
+  if (basesink->flushing)
+    goto flushing;
+
+  /* complete preroll and wait for PLAYING */
+  ret = gst_base_sink_do_preroll (basesink, GST_MINI_OBJECT_CAST (buf));
+  if (ret != GST_FLOW_OK)
+    goto preroll_error;
+
   if (len != GST_BUFFER_SIZE (buf)) {
     GST_INFO_OBJECT (basesink, "short read pulling from sink pad: %d<%d",
         len, GST_BUFFER_SIZE (buf));
     len = MIN (GST_BUFFER_SIZE (buf), len);
   }
 
-  basesink->offset += len;
+  basesink->segment.last_stop += len;
 
   memcpy (data, GST_BUFFER_DATA (buf), len);
+  GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
+
+  GST_PAD_STREAM_UNLOCK (basesink->sinkpad);
 
   return;
 
@@ -1583,6 +1646,8 @@ error:
   {
     GST_WARNING_OBJECT (basesink, "Got flow error but can't return it: %d",
         ret);
+    gst_ring_buffer_pause (rbuf);
+    GST_PAD_STREAM_UNLOCK (basesink->sinkpad);
     return;
   }
 eos:
@@ -1594,9 +1659,49 @@ eos:
     gst_element_post_message (GST_ELEMENT_CAST (sink),
         gst_message_new_eos (GST_OBJECT_CAST (sink)));
     gst_base_audio_sink_drain (sink);
+    gst_ring_buffer_pause (rbuf);
+    GST_PAD_STREAM_UNLOCK (basesink->sinkpad);
+  }
+flushing:
+  {
+    GST_DEBUG_OBJECT (sink, "we are flushing");
+    gst_ring_buffer_pause (rbuf);
+    GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
+    GST_PAD_STREAM_UNLOCK (basesink->sinkpad);
+    return;
+  }
+preroll_error:
+  {
+    GST_DEBUG_OBJECT (sink, "error %s", gst_flow_get_name (ret));
+    gst_ring_buffer_pause (rbuf);
+    GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
+    GST_PAD_STREAM_UNLOCK (basesink->sinkpad);
+    return;
   }
 }
 
+static gboolean
+gst_base_audio_sink_activate_pull (GstBaseSink * basesink, gboolean active)
+{
+  gboolean ret;
+  GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (basesink);
+
+  if (active) {
+    GST_DEBUG_OBJECT (basesink, "activating pull");
+
+    gst_ring_buffer_set_callback (sink->ringbuffer,
+        gst_base_audio_sink_callback, sink);
+
+    ret = gst_ring_buffer_activate (sink->ringbuffer, TRUE);
+  } else {
+    GST_DEBUG_OBJECT (basesink, "deactivating pull");
+    gst_ring_buffer_set_callback (sink->ringbuffer, NULL, NULL);
+    ret = gst_ring_buffer_activate (sink->ringbuffer, FALSE);
+  }
+
+  return ret;
+}
+
 /* should be called with the LOCK */
 static GstStateChangeReturn
 gst_base_audio_sink_async_play (GstBaseSink * basesink)
@@ -1608,6 +1713,10 @@ gst_base_audio_sink_async_play (GstBaseSink * basesink)
   GST_DEBUG_OBJECT (sink, "ringbuffer may start now");
   sink->priv->sync_latency = TRUE;
   gst_ring_buffer_may_start (sink->ringbuffer, TRUE);
+  if (basesink->pad_mode == GST_ACTIVATE_PULL) {
+    /* we always start the ringbuffer in pull mode immediatly */
+    gst_ring_buffer_start (sink->ringbuffer);
+  }
 
   return GST_STATE_CHANGE_SUCCESS;
 }
@@ -1676,6 +1785,7 @@ gst_base_audio_sink_change_state (GstElement * element,
       gst_clock_set_master (sink->provided_clock, NULL);
       break;
     case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_ring_buffer_activate (sink->ringbuffer, FALSE);
       gst_ring_buffer_release (sink->ringbuffer);
       break;
     case GST_STATE_CHANGE_READY_TO_NULL:
@@ -1683,6 +1793,7 @@ gst_base_audio_sink_change_state (GstElement * element,
        * caps, which happens before we commit the state to PAUSED and thus the
        * PAUSED->READY state change (see above, where we release the ringbuffer)
        * might not be called when we get here. */
+      gst_ring_buffer_activate (sink->ringbuffer, FALSE);
       gst_ring_buffer_release (sink->ringbuffer);
       gst_ring_buffer_close_device (sink->ringbuffer);
       break;
index be0b27c..f7342e2 100644 (file)
@@ -298,7 +298,8 @@ struct _GstRingBuffer {
  * @resume: resume processing of samples after pause
  * @stop: stop processing of samples
  * @delay: get number of samples queued in device
- * @activate: activate the thread that starts pulling. Since 0.10.22
+ * @activate: activate the thread that starts pulling and monitoring the
+ * consumed segments in the device. Since 0.10.22
  *
  * The vmethods that subclasses can override to implement the ringbuffer.
  */