audiobasesrc: bail out if subclass posts an error
authorTim-Philipp Müller <tim@centricular.net>
Mon, 17 Dec 2012 20:28:12 +0000 (20:28 +0000)
committerTim-Philipp Müller <tim@centricular.net>
Mon, 17 Dec 2012 20:50:32 +0000 (20:50 +0000)
Use new ringbuffer ERROR state to make all the various
threads bail out correctly when the subclass posts an
error. It's a bit iffy to communicate this properly
between the different bits of code.

https://bugzilla.gnome.org/show_bug.cgi?id=690197

gst-libs/gst/audio/gstaudiobasesrc.c

index 99d5827..820e0f9 100644 (file)
@@ -130,7 +130,8 @@ static void gst_audio_base_src_dispose (GObject * object);
 
 static GstStateChangeReturn gst_audio_base_src_change_state (GstElement *
     element, GstStateChange transition);
-
+static gboolean gst_audio_base_src_post_message (GstElement * element,
+    GstMessage * message);
 static GstClock *gst_audio_base_src_provide_clock (GstElement * elem);
 static GstClockTime gst_audio_base_src_get_time (GstClock * clock,
     GstAudioBaseSrc * src);
@@ -215,6 +216,8 @@ gst_audio_base_src_class_init (GstAudioBaseSrcClass * klass)
       GST_DEBUG_FUNCPTR (gst_audio_base_src_change_state);
   gstelement_class->provide_clock =
       GST_DEBUG_FUNCPTR (gst_audio_base_src_provide_clock);
+  gstelement_class->post_message =
+      GST_DEBUG_FUNCPTR (gst_audio_base_src_post_message);
 
   gstbasesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_audio_base_src_setcaps);
   gstbasesrc_class->event = GST_DEBUG_FUNCPTR (gst_audio_base_src_event);
@@ -825,6 +828,10 @@ gst_audio_base_src_create (GstBaseSrc * bsrc, guint64 offset, guint length,
     if (read == samples)
       break;
 
+    if (g_atomic_int_get (&ringbuffer->state) ==
+        GST_AUDIO_RING_BUFFER_STATE_ERROR)
+      goto got_error;
+
     /* else something interrupted us and we wait for playing again. */
     GST_DEBUG_OBJECT (src, "wait playing");
     if (gst_base_src_wait_playing (bsrc) != GST_FLOW_OK)
@@ -1063,6 +1070,12 @@ stopped:
     GST_DEBUG_OBJECT (src, "ringbuffer stopped");
     return GST_FLOW_FLUSHING;
   }
+got_error:
+  {
+    gst_buffer_unref (buf);
+    GST_DEBUG_OBJECT (src, "ringbuffer was in error state, bailing out");
+    return GST_FLOW_ERROR;
+  }
 }
 
 /**
@@ -1180,3 +1193,30 @@ open_failed:
   }
 
 }
+
+static gboolean
+gst_audio_base_src_post_message (GstElement * element, GstMessage * message)
+{
+  GstAudioBaseSrc *src = GST_AUDIO_BASE_SRC (element);
+  gboolean ret;
+
+  if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ERROR) {
+    GstAudioRingBuffer *ringbuffer;
+
+    GST_INFO_OBJECT (element, "subclass posted error");
+
+    ringbuffer = gst_object_ref (src->ringbuffer);
+
+    /* post message first before signalling the error to the ringbuffer, to
+     * make sure it ends up on the bus before the generic basesrc internal
+     * flow error message */
+    ret = GST_ELEMENT_CLASS (parent_class)->post_message (element, message);
+
+    g_atomic_int_set (&ringbuffer->state, GST_AUDIO_RING_BUFFER_STATE_ERROR);
+    GST_AUDIO_RING_BUFFER_SIGNAL (ringbuffer);
+    gst_object_unref (ringbuffer);
+  } else {
+    ret = GST_ELEMENT_CLASS (parent_class)->post_message (element, message);
+  }
+  return ret;
+}