pad: also push sticky events on new event
authorWim Taymans <wim.taymans@collabora.co.uk>
Fri, 9 Mar 2012 10:53:54 +0000 (11:53 +0100)
committerWim Taymans <wim.taymans@collabora.co.uk>
Fri, 9 Mar 2012 10:53:54 +0000 (11:53 +0100)
Make a helper function check_sticky to check and push pending sticky events.
Move the handling of the result of pushing the sticky event inside the
push_event function, we need to mark the event as received when it was pushed
correctly.
Move the sticky events code outside of gst_pad_push_event_unchecked and
make it purely handle sending the event to the peer.
when pushing a sticky event, first store it on the pad. Then check and push any
pending sticky events when we get a serialized or sticky event on a srcpad. This
fixes the issue where sticky events are not pushed when an event is pushed.

gst/gstpad.c

index 98ec68c..a8e03cf 100644 (file)
@@ -147,7 +147,7 @@ static GstFlowReturn gst_pad_chain_list_default (GstPad * pad,
 static GstFlowReturn gst_pad_send_event_unchecked (GstPad * pad,
     GstEvent * event, GstPadProbeType type);
 static GstFlowReturn gst_pad_push_event_unchecked (GstPad * pad,
-    GstEvent * event, GstPadProbeType type, gboolean * stored);
+    GstEvent * event, GstPadProbeType type);
 
 static guint gst_pad_signals[LAST_SIGNAL] = { 0 };
 
@@ -3274,26 +3274,58 @@ probe_stopped:
  * Data passing functions
  */
 
+/* should be called with pad LOCK */
 static gboolean
 push_sticky (GstPad * pad, PadEvent * ev, gpointer user_data)
 {
   GstFlowReturn *data = user_data;
-  gboolean stored;
+  GstEvent *event = ev->event;
 
   if (ev->received) {
     GST_DEBUG_OBJECT (pad, "event %s was already received",
-        GST_EVENT_TYPE_NAME (ev->event));
+        GST_EVENT_TYPE_NAME (event));
     return TRUE;
   }
-  GST_OBJECT_UNLOCK (pad);
 
-  *data = gst_pad_push_event_unchecked (pad, gst_event_ref (ev->event),
-      GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, &stored);
+  *data = gst_pad_push_event_unchecked (pad, gst_event_ref (event),
+      GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM);
 
-  GST_OBJECT_LOCK (pad);
+  switch (*data) {
+    case GST_FLOW_OK:
+      ev->received = TRUE;
+      GST_DEBUG_OBJECT (pad, "event %s marked received",
+          GST_EVENT_TYPE_NAME (event));
+      break;
+    case GST_FLOW_NOT_LINKED:
+      /* not linked is not a problem, we are sticky so the event will be
+       * sent later */
+      GST_DEBUG_OBJECT (pad, "pad was not linked");
+      *data = GST_FLOW_OK;
+      /* fallthrough */
+    default:
+      GST_DEBUG_OBJECT (pad, "mark pending events");
+      GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_PENDING_EVENTS);
+      break;
+  }
   return *data == GST_FLOW_OK;
 }
 
+/* check sticky events and push them when needed. should be called
+ * with pad LOCK */
+static inline GstFlowReturn
+check_sticky (GstPad * pad)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  if (G_UNLIKELY (GST_PAD_HAS_PENDING_EVENTS (pad))) {
+    GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_PENDING_EVENTS);
+
+    GST_DEBUG_OBJECT (pad, "pushing all sticky events");
+    events_foreach (pad, push_sticky, &ret);
+  }
+  return ret;
+}
+
 /* this is the chain function that does not perform the additional argument
  * checking for that little extra speed.
  */
@@ -3521,16 +3553,8 @@ gst_pad_push_data (GstPad * pad, GstPadProbeType type, void *data)
   if (G_UNLIKELY (GST_PAD_MODE (pad) != GST_PAD_MODE_PUSH))
     goto wrong_mode;
 
-  if (G_UNLIKELY (GST_PAD_HAS_PENDING_EVENTS (pad))) {
-    GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_PENDING_EVENTS);
-
-    GST_DEBUG_OBJECT (pad, "pushing all sticky events");
-
-    ret = GST_FLOW_OK;
-    events_foreach (pad, push_sticky, &ret);
-    if (ret != GST_FLOW_OK)
-      goto events_error;
-  }
+  if (G_UNLIKELY ((ret = check_sticky (pad))) != GST_FLOW_OK)
+    goto events_error;
 
   /* do block probes */
   PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_BLOCK, data, probe_stopped);
@@ -3700,16 +3724,8 @@ gst_pad_get_range_unchecked (GstPad * pad, guint64 offset, guint size,
   if (G_UNLIKELY (GST_PAD_MODE (pad) != GST_PAD_MODE_PULL))
     goto wrong_mode;
 
-  if (G_UNLIKELY (GST_PAD_HAS_PENDING_EVENTS (pad))) {
-    GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_PENDING_EVENTS);
-
-    GST_DEBUG_OBJECT (pad, "pushing all sticky events");
-
-    ret = GST_FLOW_OK;
-    events_foreach (pad, push_sticky, &ret);
-    if (ret != GST_FLOW_OK)
-      goto events_error;
-  }
+  if (G_UNLIKELY ((ret = check_sticky (pad))) != GST_FLOW_OK)
+    goto events_error;
 
   /* when one of the probes returns a buffer, probed_data will be called and we
    * skip calling the getrange function */
@@ -4040,24 +4056,19 @@ gst_pad_store_sticky_event (GstPad * pad, GstEvent * event, gboolean locked)
   return res;
 }
 
+/* should be called with pad LOCK */
 static GstFlowReturn
 gst_pad_push_event_unchecked (GstPad * pad, GstEvent * event,
-    GstPadProbeType type, gboolean * stored)
+    GstPadProbeType type)
 {
   GstFlowReturn ret;
   GstPad *peerpad;
   GstEventType event_type;
-  gboolean sticky;
-
-  sticky = GST_EVENT_IS_STICKY (event);
-
-  GST_OBJECT_LOCK (pad);
 
   /* Two checks to be made:
    * . (un)set the FLUSHING flag for flushing events,
    * . handle pad blocking */
   event_type = GST_EVENT_TYPE (event);
-  *stored = FALSE;
   switch (event_type) {
     case GST_EVENT_FLUSH_START:
       GST_PAD_SET_FLUSHING (pad);
@@ -4079,19 +4090,6 @@ gst_pad_push_event_unchecked (GstPad * pad, GstEvent * event,
       if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
         goto flushed;
 
-      /* store the event on the pad, but only on srcpads. We always store the
-       * event exactly how it was sent */
-      if (sticky) {
-        /* srcpad sticky events are store immediately, the received flag is set
-         * to FALSE and will be set to TRUE when we can successfully push the
-         * event to the peer pad */
-        if (gst_pad_store_sticky_event (pad, event, TRUE)) {
-          GST_DEBUG_OBJECT (pad, "event %s updated",
-              GST_EVENT_TYPE_NAME (event));
-        }
-        *stored = TRUE;
-      }
-
       switch (GST_EVENT_TYPE (event)) {
         case GST_EVENT_SEGMENT:
           /* pass the adjusted segment event on. We need to do this even if
@@ -4137,41 +4135,24 @@ gst_pad_push_event_unchecked (GstPad * pad, GstEvent * event,
   gst_object_unref (peerpad);
 
   GST_OBJECT_LOCK (pad);
-  if (sticky) {
-    if (ret == GST_FLOW_OK) {
-      PadEvent *ev;
-
-      if ((ev = find_event (pad, event)))
-        ev->received = TRUE;
-
-      GST_DEBUG_OBJECT (pad, "event marked received");
-    } else {
-      GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_PENDING_EVENTS);
-      GST_DEBUG_OBJECT (pad, "mark pending events");
-    }
-  }
   pad->priv->using--;
   if (pad->priv->using == 0) {
     /* pad is not active anymore, trigger idle callbacks */
     PROBE_NO_DATA (pad, GST_PAD_PROBE_TYPE_PUSH | GST_PAD_PROBE_TYPE_IDLE,
         idle_probe_stopped, ret);
   }
-  GST_OBJECT_UNLOCK (pad);
-
   return ret;
 
   /* ERROR handling */
 flushed:
   {
     GST_DEBUG_OBJECT (pad, "We're flushing");
-    GST_OBJECT_UNLOCK (pad);
     gst_event_unref (event);
     return GST_FLOW_FLUSHING;
   }
 probe_stopped:
   {
     GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_PENDING_EVENTS);
-    GST_OBJECT_UNLOCK (pad);
     gst_event_unref (event);
 
     switch (ret) {
@@ -4189,14 +4170,12 @@ not_linked:
   {
     GST_DEBUG_OBJECT (pad, "Dropping event because pad is not linked");
     GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_PENDING_EVENTS);
-    GST_OBJECT_UNLOCK (pad);
     gst_event_unref (event);
-    return sticky ? GST_FLOW_OK : GST_FLOW_NOT_LINKED;
+    return GST_FLOW_NOT_LINKED;
   }
 idle_probe_stopped:
   {
     GST_DEBUG_OBJECT (pad, "Idle probe returned %s", gst_flow_get_name (ret));
-    GST_OBJECT_UNLOCK (pad);
     return ret;
   }
 }
@@ -4222,7 +4201,7 @@ gst_pad_push_event (GstPad * pad, GstEvent * event)
 {
   gboolean res;
   GstPadProbeType type;
-  gboolean stored;
+  gboolean sticky, serialized;
 
   g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
   g_return_val_if_fail (event != NULL, FALSE);
@@ -4240,10 +4219,35 @@ gst_pad_push_event (GstPad * pad, GstEvent * event)
   } else
     goto unknown_direction;
 
-  if (gst_pad_push_event_unchecked (pad, event, type, &stored) != GST_FLOW_OK)
-    res = stored ? TRUE : FALSE;
-  else
+  GST_OBJECT_LOCK (pad);
+  sticky = GST_EVENT_IS_STICKY (event);
+  serialized = GST_EVENT_IS_SERIALIZED (event);
+
+  if (sticky) {
+    /* can't store on flushing pads */
+    if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
+      goto flushed;
+
+    /* srcpad sticky events are store immediately, the received flag is set
+     * to FALSE and will be set to TRUE when we can successfully push the
+     * event to the peer pad */
+    if (gst_pad_store_sticky_event (pad, event, TRUE)) {
+      GST_DEBUG_OBJECT (pad, "event %s updated", GST_EVENT_TYPE_NAME (event));
+    }
+  }
+  if (GST_PAD_IS_SRC (pad) && (serialized || sticky)) {
+    /* all serialized or sticky events on the srcpad trigger push of
+     * sticky events */
+    res = (check_sticky (pad) == GST_FLOW_OK);
+  }
+  if (!sticky) {
+    /* other events are pushed right away */
+    res = (gst_pad_push_event_unchecked (pad, event, type) == GST_FLOW_OK);
+  } else {
+    gst_event_unref (event);
     res = TRUE;
+  }
+  GST_OBJECT_UNLOCK (pad);
 
   return res;
 
@@ -4261,6 +4265,13 @@ unknown_direction:
     gst_event_unref (event);
     return FALSE;
   }
+flushed:
+  {
+    GST_DEBUG_OBJECT (pad, "We're flushing");
+    GST_OBJECT_UNLOCK (pad);
+    gst_event_unref (event);
+    return FALSE;
+  }
 }
 
 /* Check if we can call the event function with the given event */