diff --git a/docs/libs/gnonlin.args b/docs/libs/gnonlin.args
index 5bf9db9..ac555f8 100644
--- a/docs/libs/gnonlin.args
+++ b/docs/libs/gnonlin.args
@@ -129,6 +129,16 @@
 </ARG>
 
 <ARG>
+<NAME>GnlObject::loop</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Loop</NICK>
+<BLURB>Set to TRUE to loop clip.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
 <NAME>GnlComposition::update</NAME>
 <TYPE>gboolean</TYPE>
 <RANGE></RANGE>
diff --git a/gnl/gnlghostpad.c b/gnl/gnlghostpad.c
index 70a1044..df4730d 100644
--- a/gnl/gnlghostpad.c
+++ b/gnl/gnlghostpad.c
@@ -35,8 +35,21 @@ struct _GnlPadPrivate
   GstPadDirection dir;
   GstPadEventFunction eventfunc;
   GstPadQueryFunction queryfunc;
+  GThread *loop_thread;
+  GCond *loop_condition;        /* signals that an event is ready */
+  GMutex *loop_mutex;           /* paired with loop_condition */
+  /* amount of time we have currently looped.  When greater than duration, send EOS */
+  GstClockTime loop_progress;
+  GnlObjectLoopState loop_state;
+
+  /* The event used for seeking while looping */
+  GstEvent *loop_seek_event;
+  /* When EOS is received, this segment may be used if silence is needed */
+  GstEvent *loop_segment_event;
 };
 
+static void *loop_seek_thread (void *param);
+
 static GstEvent *
 translate_incoming_seek (GnlObject * object, GstEvent * event)
 {
@@ -222,7 +235,8 @@ invalid_format:
 }
 
 static GstEvent *
-translate_outgoing_new_segment (GnlObject * object, GstEvent * event)
+translate_outgoing_new_segment (GnlObject * object, GstEvent * event,
+    GnlPadPrivate * priv)
 {
   GstEvent *event2;
   gboolean update;
@@ -246,7 +260,11 @@ translate_outgoing_new_segment (GnlObject * object, GstEvent * event)
     return event;
   }
 
-  gnl_media_to_object_time (object, stream, &nstream);
+  if (!GNL_OBJECT_LOOP (object)) {
+    gnl_media_to_object_time (object, stream, &nstream);
+  } else {
+    nstream = priv->loop_progress;
+  }
 
   if (G_UNLIKELY (nstream > G_MAXINT64))
     GST_WARNING_OBJECT (object, "Return value too big...");
@@ -258,13 +276,29 @@ translate_outgoing_new_segment (GnlObject * object, GstEvent * event)
   event2 =
       gst_event_new_new_segment (update, rate, format, start, stop,
       (gint64) nstream);
+  if (GNL_OBJECT_LOOP (object)) {
+    if (nstream < GNL_OBJECT_DURATION (object)) {
+      GST_DEBUG_OBJECT (object,
+          "Generating a NEWSEGMENT for possible use later.");
+
+      // Create a new segment event, since the nstream value will have changed
+      if (priv->loop_segment_event != NULL) {
+        gst_event_unref (priv->loop_segment_event);
+        priv->loop_segment_event = NULL;
+      }
+      priv->loop_segment_event = gst_event_new_new_segment (TRUE, 1,
+          GST_FORMAT_TIME, GNL_OBJECT_START (object),
+          GNL_OBJECT_MEDIA_DURATION (object), nstream);
+    }
+  }
   gst_event_unref (event);
 
   return event2;
 }
 
 static GstEvent *
-translate_incoming_new_segment (GnlObject * object, GstEvent * event)
+translate_incoming_new_segment (GnlObject * object, GstEvent * event,
+    GnlPadPrivate * priv)
 {
   GstEvent *event2;
   gboolean update;
@@ -288,10 +322,14 @@ translate_incoming_new_segment (GnlObject * object, GstEvent * event)
     return event;
   }
 
-  if (!gnl_object_to_media_time (object, stream, &nstream)) {
-    GST_DEBUG ("Can't convert media_time, using 0");
-    nstream = 0;
-  };
+  if (!GNL_OBJECT_LOOP (object)) {
+    if (!gnl_object_to_media_time (object, stream, &nstream)) {
+      GST_DEBUG ("Can't convert media_time, using 0");
+      nstream = 0;
+    };
+  } else {
+    nstream = priv->loop_progress;
+  }
 
   if (G_UNLIKELY (nstream > G_MAXINT64))
     GST_WARNING_OBJECT (object, "Return value too big...");
@@ -312,6 +350,7 @@ static gboolean
 internalpad_event_function (GstPad * internal, GstEvent * event)
 {
   GnlPadPrivate *priv = gst_pad_get_element_private (internal);
+  GnlPadPrivate *ghostpriv = priv->ghostpriv;
   GnlObject *object = priv->object;
   gboolean res;
 
@@ -327,7 +366,42 @@ internalpad_event_function (GstPad * internal, GstEvent * event)
     case GST_PAD_SRC:{
       switch (GST_EVENT_TYPE (event)) {
         case GST_EVENT_NEWSEGMENT:
-          event = translate_outgoing_new_segment (object, event);
+          event = translate_outgoing_new_segment (object, event, ghostpriv);
+          break;
+        case GST_EVENT_EOS:
+        {
+          if (GNL_OBJECT_LOOP (object)) {
+            GST_LOG_OBJECT (object, "Received EOS");
+            ghostpriv->loop_progress += GNL_OBJECT_MEDIA_DURATION (object);
+
+            if (ghostpriv->loop_progress < GNL_OBJECT_DURATION (object)) {
+              gint64 stop;
+              GstEvent *seek_event;
+              if (ghostpriv->loop_segment_event != NULL) {
+                event = ghostpriv->loop_segment_event;
+                ghostpriv->loop_segment_event = NULL;
+              }
+
+              if (ghostpriv->loop_progress +
+                  GNL_OBJECT_MEDIA_DURATION (object) >
+                  GNL_OBJECT_DURATION (object)) {
+                stop = GNL_OBJECT_DURATION (object) - ghostpriv->loop_progress;
+              } else {
+                stop = GNL_OBJECT_MEDIA_STOP (object);
+              }
+              seek_event = gst_event_new_seek (1.0, GST_FORMAT_TIME,
+                  GST_SEEK_FLAG_ACCURATE,
+                  GST_SEEK_TYPE_SET, GNL_OBJECT_MEDIA_START (object),
+                  GST_SEEK_TYPE_SET, stop);
+              g_mutex_lock (ghostpriv->loop_mutex);
+              ghostpriv->loop_seek_event = seek_event;
+              ghostpriv->loop_state = GNL_OBJECT_LOOP_STATE_EVENT;
+              g_mutex_unlock (ghostpriv->loop_mutex);
+              GST_LOG_OBJECT (object, "broadcasting loop seek event");
+              g_cond_broadcast (ghostpriv->loop_condition);
+            }
+          }
+        }
           break;
         default:
           break;
@@ -500,7 +574,7 @@ ghostpad_event_function (GstPad * ghostpad, GstEvent * event)
     case GST_PAD_SINK:{
       switch (GST_EVENT_TYPE (event)) {
         case GST_EVENT_NEWSEGMENT:
-          event = translate_incoming_new_segment (object, event);
+          event = translate_incoming_new_segment (object, event, priv);
           break;
         default:
           break;
@@ -604,6 +678,8 @@ control_internal_pad (GstPad * ghostpad, GnlObject * object)
     /* Remember existing pad functions */
     priv->eventfunc = GST_PAD_EVENTFUNC (internal);
     priv->queryfunc = GST_PAD_QUERYFUNC (internal);
+    priv->loop_thread = NULL;
+    priv->loop_segment_event = NULL;
     gst_pad_set_element_private (internal, priv);
 
     g_object_weak_ref ((GObject *) internal,
@@ -703,6 +779,7 @@ gnl_object_ghost_pad_no_target (GnlObject * object, const gchar * name,
   priv = g_slice_new (GnlPadPrivate);
   priv->dir = dir;
   priv->object = object;
+  priv->loop_thread = NULL;
 
   /* grab/replace event/query functions */
   GST_DEBUG_OBJECT (ghost, "Setting priv->eventfunc to %p",
@@ -728,6 +805,27 @@ gnl_object_remove_ghost_pad (GnlObject * object, GstPad * ghost)
   GST_DEBUG_OBJECT (object, "ghostpad %s:%s", GST_DEBUG_PAD_NAME (ghost));
 
   priv = gst_pad_get_element_private (ghost);
+
+  if (priv->loop_thread != 0) {
+    GST_LOG_OBJECT (object, "shutting down the seek thread");
+    priv->loop_state = GNL_OBJECT_LOOP_STATE_DONE;
+    g_cond_broadcast (priv->loop_condition);
+    g_thread_join (priv->loop_thread);
+
+    if (priv->loop_segment_event) {
+      gst_event_unref (priv->loop_segment_event);
+      priv->loop_segment_event = NULL;
+    }
+
+    if (priv->loop_seek_event) {
+      gst_event_unref (priv->loop_seek_event);
+      priv->loop_seek_event = NULL;
+    }
+
+    g_cond_free (priv->loop_condition);
+    g_mutex_free (priv->loop_mutex);
+  }
+
   gst_ghost_pad_set_target (GST_GHOST_PAD (ghost), NULL);
   gst_element_remove_pad (GST_ELEMENT (object), ghost);
   if (priv)
@@ -766,9 +864,56 @@ gnl_object_ghost_pad_set_target (GnlObject * object, GstPad * ghost,
   if (!GST_OBJECT_IS_FLOATING (ghost))
     control_internal_pad (ghost, object);
 
+  if (GNL_OBJECT_LOOP (object)) {
+    GST_LOG_OBJECT (object, "Looping, setting up event probe and thread");
+    //note that we are only setting these on the ghostpad
+    priv->loop_thread = g_thread_create (loop_seek_thread, ghost, TRUE, NULL);
+    priv->loop_seek_event = NULL;
+    priv->loop_state = GNL_OBJECT_LOOP_STATE_NONE;
+    priv->loop_progress = 0;
+    priv->loop_condition = g_cond_new ();
+    priv->loop_mutex = g_mutex_new ();
+  }
+
   return TRUE;
 }
 
+static void *
+loop_seek_thread (void *param)
+{
+  GstPad *ghost = (GstPad *) param;
+  GnlPadPrivate *priv = gst_pad_get_element_private (ghost);
+  GnlObject *object = priv->object;
+  GstEvent *event;
+  GST_DEBUG_OBJECT (object, "starting loop_seek_thread");
+  g_mutex_lock (priv->loop_mutex);
+  while (priv->loop_state != GNL_OBJECT_LOOP_STATE_DONE) {
+    GST_LOG_OBJECT (object, "loop_seek_thread waking up");
+    if (priv->loop_state == GNL_OBJECT_LOOP_STATE_EVENT) {
+      GstPad *ghostedpad = gst_ghost_pad_get_target (GST_GHOST_PAD (ghost));
+
+      event = priv->loop_seek_event;
+      priv->loop_seek_event = NULL;
+      priv->loop_state = GNL_OBJECT_LOOP_STATE_NONE;
+      g_mutex_unlock (priv->loop_mutex);
+
+      GST_LOG_OBJECT (object, "We have a loop event");
+      if (!(gst_pad_send_event (ghostedpad, event))) {
+        GST_ELEMENT_ERROR (object, RESOURCE, SEEK, (NULL),
+            ("Sending seek in loop_seek_thread failed"));
+      }
+      g_mutex_lock (priv->loop_mutex);
+    }
+    GST_LOG_OBJECT (object, "Waiting for condition variable");
+    g_cond_wait (priv->loop_condition, priv->loop_mutex);
+  }
+
+  g_mutex_unlock (priv->loop_mutex);
+  GST_DEBUG_OBJECT (object, "loop_seek_thread ending");
+
+  return NULL;
+}
+
 void
 gnl_init_ghostpad_category (void)
 {
diff --git a/gnl/gnlobject.c b/gnl/gnlobject.c
index 7c58314..796aee1 100644
--- a/gnl/gnlobject.c
+++ b/gnl/gnlobject.c
@@ -57,7 +57,8 @@ enum
   ARG_PRIORITY,
   ARG_ACTIVE,
   ARG_CAPS,
-  ARG_EXPANDABLE
+  ARG_EXPANDABLE,
+  ARG_LOOP
 };
 
 static void gnl_object_dispose (GObject * object);
@@ -247,6 +248,17 @@ gnl_object_class_init (GnlObjectClass * klass)
       g_param_spec_boolean ("expandable", "Expandable",
           "Expand to the full duration of the container composition", FALSE,
           G_PARAM_READWRITE));
+
+  /**
+   * GnlObject:loop
+   *
+   * If TRUE, this object is looping.  If object is looping, rate will
+   * be 1, one loop will take media-duration nanoseconds and will loop
+   * for duration.
+   */
+  g_object_class_install_property (gobject_class, ARG_LOOP,
+      g_param_spec_boolean ("loop", "Loop",
+          "Set to TRUE to loop clip", FALSE, G_PARAM_READWRITE));
 }
 
 static void
@@ -264,6 +276,7 @@ gnl_object_init (GnlObject * object, GnlObjectClass * klass)
   object->rate_1 = TRUE;
   object->priority = 0;
   object->active = TRUE;
+  object->loop = FALSE;
 
   object->caps = gst_caps_new_any ();
 
@@ -460,14 +473,28 @@ gnl_object_set_caps (GnlObject * object, const GstCaps * caps)
 static void
 update_values (GnlObject * object)
 {
+  gboolean value_changed = FALSE;
+
   /* check if start/duration has changed */
-  if ((object->start + object->duration) != object->stop) {
-    object->stop = object->start + object->duration;
+  if (!object->loop) {
+    if ((object->start + object->duration) != object->stop) {
+      value_changed = TRUE;
+      object->stop = object->start + object->duration;
+    }
+  } else {
+    if ((object->start + object->media_duration) != object->stop) {
+      value_changed = TRUE;
+      object->stop = object->start + object->media_duration;
+    }
+  }
+
+  if (value_changed) {
     GST_LOG_OBJECT (object,
         "Updating stop value : %" GST_TIME_FORMAT " [start:%" GST_TIME_FORMAT
         ", duration:%" GST_TIME_FORMAT "]", GST_TIME_ARGS (object->stop),
         GST_TIME_ARGS (object->start), GST_TIME_ARGS (object->duration));
     g_object_notify (G_OBJECT (object), "stop");
+    value_changed = FALSE;
   }
 
   /* check if media start/duration has changed */
@@ -484,15 +511,28 @@ update_values (GnlObject * object)
   }
 
   /* check if rate has changed */
-  if ((object->media_duration != GST_CLOCK_TIME_NONE)
-      && (object->duration)
-      && (object->media_duration)
-      && (((gdouble) object->media_duration / (gdouble) object->duration) !=
-          object->rate)) {
-    object->rate =
-        (gdouble) object->media_duration / (gdouble) object->duration;
-    /* update the speedup rate_1 variable */
-    object->rate_1 = (object->media_duration == object->duration);
+  if (!object->loop) {
+    if ((object->media_duration != GST_CLOCK_TIME_NONE)
+        && (object->duration)
+        && (object->media_duration)
+        && (((gdouble) object->media_duration / (gdouble) object->duration) !=
+            object->rate)) {
+      object->rate =
+          (gdouble) object->media_duration / (gdouble) object->duration;
+
+      /* update the speedup rate_1 variable */
+      object->rate_1 = (object->media_duration == object->duration);
+      value_changed = TRUE;
+    }
+  } else {
+    if (object->rate != 1) {
+      object->rate = 1;
+      object->rate_1 = 1;
+      value_changed = TRUE;
+    }
+  }
+
+  if (value_changed) {
     GST_LOG_OBJECT (object,
         "Updated rate : %f [mduration:%" GST_TIME_FORMAT ", duration:%"
         GST_TIME_FORMAT "] rate_1:%d", object->rate,
@@ -541,6 +581,10 @@ gnl_object_set_property (GObject * object, guint prop_id,
       else
         GST_OBJECT_FLAG_UNSET (gnlobject, GNL_OBJECT_EXPANDABLE);
       break;
+    case ARG_LOOP:
+      gnlobject->loop = g_value_get_boolean (value);
+      update_values (gnlobject);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -587,6 +631,9 @@ gnl_object_get_property (GObject * object, guint prop_id,
     case ARG_EXPANDABLE:
       g_value_set_boolean (value, GNL_OBJECT_IS_EXPANDABLE (object));
       break;
+    case ARG_LOOP:
+      g_value_set_boolean (value, gnlobject->loop);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
diff --git a/gnl/gnlobject.h b/gnl/gnlobject.h
index 568b973..4bcbab0 100644
--- a/gnl/gnlobject.h
+++ b/gnl/gnlobject.h
@@ -60,6 +60,12 @@ typedef enum
   GNL_OBJECT_LAST_FLAG = (GST_BIN_FLAG_LAST << 16)
 } GnlObjectFlags;
 
+typedef enum
+{
+  GNL_OBJECT_LOOP_STATE_NONE,
+  GNL_OBJECT_LOOP_STATE_DONE,
+  GNL_OBJECT_LOOP_STATE_EVENT
+} GnlObjectLoopState;
 
 #define GNL_OBJECT_IS_SOURCE(obj) \
   (GST_OBJECT_FLAG_IS_SET(obj, GNL_OBJECT_SOURCE))
@@ -76,6 +82,7 @@ typedef enum
 #define GNL_OBJECT_MEDIA_STOP(obj) (GNL_OBJECT_CAST (obj)->media_stop)
 #define GNL_OBJECT_MEDIA_DURATION(obj) (GNL_OBJECT_CAST (obj)->media_duration)
 #define GNL_OBJECT_PRIORITY(obj) (GNL_OBJECT_CAST (obj)->priority)
+#define GNL_OBJECT_LOOP(obj) (GNL_OBJECT_CAST(obj)->loop)
 
 struct _GnlObject
 {
@@ -99,6 +106,9 @@ struct _GnlObject
   /* TRUE if rate == 1.0 */
   gboolean rate_1;
 
+  /* true if object is looping */
+  gboolean loop;
+
   /* priority in parent */
   guint32 priority;
 
diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am
index eda5386..3116558 100644
--- a/tests/check/Makefile.am
+++ b/tests/check/Makefile.am
@@ -24,7 +24,8 @@ check_PROGRAMS =	\
 	gnl/complex	\
 	gnl/gnlsource	\
 	gnl/gnloperation	\
-	gnl/gnlcomposition
+	gnl/gnlcomposition	\
+	gnl/loop
 
 noinst_HEADERS = \
 	gnl/common.h
diff --git a/tests/check/gnl/loop.c b/tests/check/gnl/loop.c
new file mode 100644
index 0000000..50c5b2e
--- /dev/null
+++ b/tests/check/gnl/loop.c
@@ -0,0 +1,204 @@
+#include "common.h"
+
+static void
+test_loop (int do_loop)
+{
+  GstElement *pipeline;
+  GstElement *comp, *sink, *source1, *source2;
+  CollectStructure *collect;
+  GstBus *bus;
+  GstMessage *message;
+  gboolean carry_on = TRUE;
+  guint64 start, stop;
+  gint64 duration;
+  GstPad *sinkpad;
+  double rate;
+
+  pipeline = gst_pipeline_new ("test_pipeline");
+  comp =
+      gst_element_factory_make_or_warn ("gnlcomposition", "test_composition");
+  fail_if (comp == NULL);
+
+  source1 = audiotest_bin_src ("source1", 0, 1 * GST_SECOND, 3, 1);
+  fail_if (source1 == NULL);
+  check_start_stop_duration (source1, 0, 1 * GST_SECOND, 1 * GST_SECOND);
+
+  gst_bin_add (GST_BIN (comp), source1);
+  ASSERT_OBJECT_REFCOUNT (source1, "source1", 1);
+
+  check_start_stop_duration (comp, 0, 1 * GST_SECOND, 1 * GST_SECOND);
+  g_object_set (G_OBJECT (comp),
+      "media-duration", GST_SECOND / 4, "loop", do_loop, NULL);
+
+  g_object_get (G_OBJECT (comp), "rate", &rate, NULL);
+  if (do_loop) {
+    fail_if (rate != 1);
+  } else {
+    fail_if (rate == 1);
+  }
+
+  sink = gst_element_factory_make_or_warn ("fakesink", "sink");
+  fail_if (sink == NULL);
+
+  gst_bin_add_many (GST_BIN (pipeline), comp, sink, NULL);
+
+  /* Shared data */
+  collect = g_new0 (CollectStructure, 1);
+  collect->comp = comp;
+  collect->sink = sink;
+
+  /* Expected segments */
+  collect->expected_segments = g_list_append (collect->expected_segments,
+      segment_new (1.0, GST_FORMAT_TIME, 0 * GST_SECOND, 1 * GST_SECOND, 0));
+
+  g_signal_connect (G_OBJECT (comp), "pad-added",
+      G_CALLBACK (composition_pad_added_cb), collect);
+
+  sinkpad = gst_element_get_pad (sink, "sink");
+  gst_pad_add_event_probe (sinkpad, G_CALLBACK (sinkpad_event_probe), collect);
+  gst_pad_add_buffer_probe (sinkpad, G_CALLBACK (sinkpad_buffer_probe),
+      collect);
+
+  bus = gst_element_get_bus (GST_ELEMENT (pipeline));
+
+  GST_DEBUG ("Setting pipeline to PLAYING");
+  ASSERT_OBJECT_REFCOUNT (source1, "source1", 1);
+
+  fail_if (gst_element_set_state (GST_ELEMENT (pipeline),
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
+
+  GST_DEBUG ("Let's poll the bus");
+
+  while (carry_on) {
+    message = gst_bus_poll (bus, GST_MESSAGE_ANY, GST_SECOND / 2);
+    if (message) {
+      switch (GST_MESSAGE_TYPE (message)) {
+        case GST_MESSAGE_EOS:
+          /* we should check if we really finished here */
+          GST_WARNING ("Got an EOS");
+          carry_on = FALSE;
+          break;
+        case GST_MESSAGE_SEGMENT_START:
+        case GST_MESSAGE_SEGMENT_DONE:
+          /* We shouldn't see any segement messages, since we didn't do a segment seek */
+          GST_WARNING ("Saw a Segment start/stop");
+          fail_if (TRUE);
+          break;
+        case GST_MESSAGE_ERROR:
+          GST_WARNING ("Saw an ERROR");
+          fail_if (TRUE);
+        default:
+          break;
+      }
+      gst_mini_object_unref (GST_MINI_OBJECT (message));
+    }
+  }
+
+  GST_DEBUG ("Setting pipeline to NULL");
+
+  fail_if (gst_element_set_state (GST_ELEMENT (pipeline),
+          GST_STATE_READY) == GST_STATE_CHANGE_FAILURE);
+
+  fail_if (collect->expected_segments != NULL);
+
+  GST_DEBUG ("Resetted pipeline to READY");
+
+  /* Expected segments */
+  collect->expected_segments = g_list_append (collect->expected_segments,
+      segment_new (1.0, GST_FORMAT_TIME, 0 * GST_SECOND, 1 * GST_SECOND, 0));
+  collect->gotsegment = FALSE;
+
+
+  GST_DEBUG ("Setting pipeline to PLAYING again");
+
+  fail_if (gst_element_set_state (GST_ELEMENT (pipeline),
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
+
+  carry_on = TRUE;
+
+  GST_DEBUG ("Let's poll the bus AGAIN");
+
+  while (carry_on) {
+    message = gst_bus_poll (bus, GST_MESSAGE_ANY, GST_SECOND / 2);
+    if (message) {
+      switch (GST_MESSAGE_TYPE (message)) {
+        case GST_MESSAGE_EOS:
+          /* we should check if we really finished here */
+          carry_on = FALSE;
+          break;
+        case GST_MESSAGE_SEGMENT_START:
+        case GST_MESSAGE_SEGMENT_DONE:
+          /* We shouldn't see any segement messages, since we didn't do a segment seek */
+          GST_WARNING ("Saw a Segment start/stop");
+          fail_if (TRUE);
+          break;
+        case GST_MESSAGE_ERROR:
+          GST_ERROR ("Saw an ERROR");
+          fail_if (TRUE);
+        default:
+          break;
+      }
+      gst_mini_object_unref (GST_MINI_OBJECT (message));
+    } else {
+      GST_DEBUG ("bus_poll responded, but there wasn't any message...");
+    }
+  }
+
+  fail_if (collect->expected_segments != NULL);
+
+  gst_object_unref (GST_OBJECT (sinkpad));
+
+  fail_if (gst_element_set_state (GST_ELEMENT (pipeline),
+          GST_STATE_NULL) == GST_STATE_CHANGE_FAILURE);
+
+  ASSERT_OBJECT_REFCOUNT_BETWEEN (pipeline, "main pipeline", 1, 2);
+  gst_object_unref (pipeline);
+  ASSERT_OBJECT_REFCOUNT_BETWEEN (bus, "main bus", 1, 2);
+  gst_object_unref (bus);
+
+  g_free (collect);
+}
+
+GST_START_TEST (test_simple_loop)
+{
+  test_loop (1);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_simple_no_loop)
+{
+  test_loop (0);
+}
+
+GST_END_TEST;
+
+Suite *
+gnonlin_suite (void)
+{
+  Suite *s = suite_create ("gnonlin");
+  TCase *tc_chain = tcase_create ("loop");
+
+  suite_add_tcase (s, tc_chain);
+
+  tcase_add_test (tc_chain, test_simple_loop);
+  tcase_add_test (tc_chain, test_simple_no_loop);
+  return s;
+}
+
+int
+main (int argc, char **argv)
+{
+  int nf;
+
+  Suite *s = gnonlin_suite ();
+  SRunner *sr = srunner_create (s);
+
+  gst_check_init (&argc, &argv);
+
+  srunner_run_all (sr, CK_NORMAL);
+  nf = srunner_ntests_failed (sr);
+  srunner_free (sr);
+
+  return nf;
+}
