New upstream version 1.9.90
diff --git a/tests/check/elements/rtpjitterbuffer.c b/tests/check/elements/rtpjitterbuffer.c
index 10810fa..1a9d0e6 100644
--- a/tests/check/elements/rtpjitterbuffer.c
+++ b/tests/check/elements/rtpjitterbuffer.c
@@ -5,7 +5,7 @@
  * Copyright (C) 2012 Cisco Systems, Inc
  *               Authors: Kelley Rogers <kelro@cisco.com>
  *               Havard Graff <hgraff@cisco.com>
- * Copyright (C) 2013-2015 Pexip AS
+ * Copyright (C) 2013-2016 Pexip AS
  *               Stian Selnes <stian@pexip>
  *               Havard Graff <havard@pexip>
  *
@@ -447,6 +447,15 @@
       TRUE, seq_num, seq_num * PCMU_RTP_TS_DURATION);
 }
 
+static GstBuffer *
+generate_test_buffer_rtx (GstClockTime dts, guint seq_num)
+{
+  GstBuffer *buffer = generate_test_buffer_full (dts, TRUE, seq_num,
+      seq_num * PCMU_RTP_TS_DURATION);
+  GST_BUFFER_FLAG_SET (buffer, GST_RTP_BUFFER_FLAG_RETRANSMISSION);
+  return buffer;
+}
+
 static gint
 get_rtp_seq_num (GstBuffer * buf)
 {
@@ -520,6 +529,29 @@
   gst_event_unref (event);
 }
 
+static gboolean
+verify_jb_stats (GstElement * jb, GstStructure * expected)
+{
+  gboolean ret;
+  GstStructure *actual;
+  g_object_get (jb, "stats", &actual, NULL);
+
+  ret = gst_structure_is_subset (actual, expected);
+
+  if (!ret) {
+    gchar *e_str = gst_structure_to_string (expected);
+    gchar *a_str = gst_structure_to_string (actual);
+    fail_unless (ret, "%s is not a subset of %s", e_str, a_str);
+    g_free (e_str);
+    g_free (a_str);
+  }
+
+  gst_structure_free (expected);
+  gst_structure_free (actual);
+
+  return ret;
+}
+
 GST_START_TEST (test_only_one_lost_event_on_large_gaps)
 {
   GstHarness *h = gst_harness_new ("rtpjitterbuffer");
@@ -604,6 +636,10 @@
   fail_unless_equals_uint64 (10 * GST_SECOND, GST_BUFFER_PTS (out_buf));
   gst_buffer_unref (out_buf);
 
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-lost", G_TYPE_UINT64, (guint64) 499, NULL)));
+
   gst_object_unref (testclock);
   gst_harness_teardown (h);
 }
@@ -688,6 +724,11 @@
   fail_unless_equals_int (5, get_rtp_seq_num (out_buf));
   gst_buffer_unref (out_buf);
 
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) 5,
+              "num-lost", G_TYPE_UINT64, (guint64) 1, NULL)));
+
   gst_object_unref (testclock);
   gst_harness_teardown (h);
 }
@@ -749,12 +790,76 @@
   fail_unless_equals_int (5, get_rtp_seq_num (out_buf));
   gst_buffer_unref (out_buf);
 
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) 4,
+              "num-lost", G_TYPE_UINT64, (guint64) 2, NULL)));
+
   gst_object_unref (testclock);
   gst_harness_teardown (h);
 }
 
 GST_END_TEST;
 
+
+GST_START_TEST (test_num_late_when_considered_lost_arrives)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  gboolean do_lost = __i__ != 0;
+
+  gst_harness_set_src_caps (h, generate_caps ());
+  g_object_set (h->element, "do-lost", do_lost, "latency", 100, NULL);
+
+  /* push the first buffer through */
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h, generate_test_buffer (0)));
+  /* sync on the first packet */
+  gst_harness_crank_single_clock_wait (h);
+
+  /* gap of 1 */
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h, generate_test_buffer (2)));
+
+  /* crank to output lost-event */
+  gst_harness_crank_single_clock_wait (h);
+
+  if (do_lost) {
+    /* drop GstEventStreamStart & GstEventCaps & GstEventSegment */
+    for (gint i = 0; i < 3; i++)
+      gst_event_unref (gst_harness_pull_event (h));
+
+    /* we should now receive packet-lost-events for buffer 1 */
+    verify_lost_event (gst_harness_pull_event (h),
+        1, 1 * PCMU_BUF_DURATION, PCMU_BUF_DURATION);
+  }
+
+  /* pull out buffers to ensure determinism */
+  gst_buffer_unref (gst_harness_pull (h));
+  gst_buffer_unref (gst_harness_pull (h));
+
+  /* we have one lost packet in the stats */
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) 2,
+              "num-lost", G_TYPE_UINT64, (guint64) 1,
+              "num-late", G_TYPE_UINT64, (guint64) 0, NULL)));
+
+  /* buffer 1 now arrives (too late) */
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h, generate_test_buffer (1)));
+
+  /* and this increments num-late */
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) 2,
+              "num-lost", G_TYPE_UINT64, (guint64) 1,
+              "num-late", G_TYPE_UINT64, (guint64) 1, NULL)));
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
 GST_START_TEST (test_all_packets_are_timestamped_zero)
 {
   GstHarness *h = gst_harness_new ("rtpjitterbuffer");
@@ -809,12 +914,138 @@
   fail_unless_equals_int (5, get_rtp_seq_num (out_buf));
   gst_buffer_unref (out_buf);
 
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) 4,
+              "num-lost", G_TYPE_UINT64, (guint64) 2, NULL)));
+
   gst_object_unref (testclock);
   gst_harness_teardown (h);
 }
 
 GST_END_TEST;
 
+GST_START_TEST (test_reorder_of_non_equidistant_packets)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  GstTestClock *testclock;
+  gint latency_ms = 5;
+  GstClockID pending_id;
+  GstClockTime time;
+  gint seq, frame;
+  gint num_init_frames = 1;
+  const GstClockTime frame_dur = PCMU_BUF_DURATION;
+  const guint32 frame_rtp_ts_dur = PCMU_RTP_TS_DURATION;
+
+  gst_harness_set_src_caps (h, generate_caps ());
+  testclock = gst_harness_get_testclock (h);
+  g_object_set (h->element, "do-lost", TRUE, "latency", latency_ms, NULL);
+
+  for (frame = 0, seq = 0; frame < num_init_frames; frame++, seq += 2) {
+    /* Push a couple of packets with identical timestamp, typical for a video
+     * stream where one frame generates multiple packets. */
+    gst_harness_set_time (h, frame * frame_dur);
+    gst_harness_push (h, generate_test_buffer_full (frame * frame_dur, FALSE,
+            seq, frame * frame_rtp_ts_dur));
+    gst_harness_push (h, generate_test_buffer_full (frame * frame_dur, TRUE,
+            seq + 1, frame * frame_rtp_ts_dur));
+
+    if (frame == 0)
+      /* deadline for buffer 0 expires */
+      gst_harness_crank_single_clock_wait (h);
+
+    gst_buffer_unref (gst_harness_pull (h));
+    gst_buffer_unref (gst_harness_pull (h));
+  }
+
+  /* Finally push the last frame reordered */
+  gst_harness_set_time (h, frame * frame_dur);
+  gst_harness_push (h, generate_test_buffer_full (frame * frame_dur, TRUE,
+          seq + 1, frame * frame_rtp_ts_dur));
+
+  /* Check the scheduled lost timer. The expected arrival of this packet
+   * should be assumed to be the same as the last packet received since we
+   * don't know wether the missing packet belonged to this or previous
+   * frame. */
+  gst_test_clock_wait_for_next_pending_id (testclock, &pending_id);
+  time = gst_clock_id_get_time (pending_id);
+  fail_unless_equals_int64 (time, frame * frame_dur + latency_ms * GST_MSECOND);
+  gst_clock_id_unref (pending_id);
+
+  /* And then missing packet arrives just in time */
+  gst_harness_set_time (h, time - 1);
+  gst_harness_push (h, generate_test_buffer_full (time - 1, FALSE, seq,
+          frame * frame_rtp_ts_dur));
+
+  gst_buffer_unref (gst_harness_pull (h));
+  gst_buffer_unref (gst_harness_pull (h));
+
+  gst_object_unref (testclock);
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_loss_equidistant_spacing_with_parameter_packets)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  GstTestClock *testclock;
+  GstEvent *event;
+  gint latency_ms = 5;
+  gint seq, frame;
+  gint num_init_frames = 10;
+
+  gst_harness_set_src_caps (h, generate_caps ());
+  testclock = gst_harness_get_testclock (h);
+  g_object_set (h->element, "do-lost", TRUE, "latency", latency_ms, NULL);
+
+  /* drop stream-start, caps, segment */
+  for (int i = 0; i < 3; i++)
+    gst_event_unref (gst_harness_pull_event (h));
+
+  for (frame = 0, seq = 0; frame < num_init_frames; frame++, seq++) {
+    gst_harness_set_time (h, frame * PCMU_BUF_DURATION);
+    gst_harness_push (h, generate_test_buffer_full (frame * PCMU_BUF_DURATION,
+            TRUE, seq, frame * PCMU_RTP_TS_DURATION));
+
+    if (frame == 0)
+      /* deadline for buffer 0 expires */
+      gst_harness_crank_single_clock_wait (h);
+
+    gst_buffer_unref (gst_harness_pull (h));
+  }
+
+  /* Push three packets with same rtptime, simulating parameter packets +
+   * frame. This should not disable equidistant mode as it is common for
+   * certain audio codecs. */
+  for (gint i = 0; i < 3; i++) {
+    gst_harness_set_time (h, frame * PCMU_BUF_DURATION);
+    gst_harness_push (h, generate_test_buffer_full (frame * PCMU_BUF_DURATION,
+            i == 2, seq++, frame * PCMU_RTP_TS_DURATION));
+    gst_buffer_unref (gst_harness_pull (h));
+  }
+  frame++;
+
+  /* Finally push the last packet introducing a gap */
+  gst_harness_set_time (h, frame * PCMU_BUF_DURATION);
+  gst_harness_push (h, generate_test_buffer_full (frame * PCMU_BUF_DURATION,
+          TRUE, seq + 1, frame * PCMU_RTP_TS_DURATION));
+
+  /* Check that the lost event has been generated assuming equidistant
+   * spacing. */
+  event = gst_harness_pull_event (h);
+  verify_lost_event (event, seq,
+      frame * PCMU_BUF_DURATION - PCMU_BUF_DURATION / 2, PCMU_BUF_DURATION / 2);
+
+  gst_buffer_unref (gst_harness_pull (h));
+
+  gst_object_unref (testclock);
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+
 static void
 gst_test_clock_set_time_and_process (GstTestClock * testclock,
     GstClockTime time)
@@ -899,128 +1130,201 @@
 {
   GstHarness *h = gst_harness_new ("rtpjitterbuffer");
   GstTestClock *testclock;
-  GstBuffer *out_buf;
-  GstEvent *out_event;
-  gint jb_latency_ms = 200;
-  const GstClockTime rtx_retry_timeout = 40 * GST_MSECOND;
-  GstStructure *rtx_stats;
-  const GValue *rtx_stat;
-  gint i;
+  gint latency_ms = 200;
+  gint rtx_delay_ms;
+  GstClockTime last_rtx_request, now;
 
-  gst_harness_set_src_caps (h, generate_caps ());
   testclock = gst_harness_get_testclock (h);
+  gst_harness_set_src_caps (h, generate_caps ());
+  g_object_set (h->element, "do-retransmission", TRUE, "latency", latency_ms,
+      NULL);
 
-  g_object_set (h->element, "do-lost", TRUE, NULL);
-  g_object_set (h->element, "do-retransmission", TRUE, NULL);
-  g_object_set (h->element, "latency", jb_latency_ms, NULL);
-  g_object_set (h->element, "rtx-retry-period", 120, NULL);
+  for (gint i = 0; i <= latency_ms / PCMU_BUF_MS; i++) {
+    gst_test_clock_set_time (testclock, i * PCMU_BUF_DURATION);
+    fail_unless_equals_int (GST_FLOW_OK,
+        gst_harness_push (h, generate_test_buffer (i)));
+    gst_harness_wait_for_clock_id_waits (h, 1, 60);
+  }
 
-  /* push the first buffer in */
-  fail_unless_equals_int (GST_FLOW_OK,
-      gst_harness_push (h, generate_test_buffer (0)));
+  gst_harness_crank_single_clock_wait (h);
+  fail_unless_equals_int64 (latency_ms * GST_MSECOND,
+      gst_clock_get_time (GST_CLOCK (testclock)));
 
-  gst_harness_set_time (h, 20 * GST_MSECOND);
-
-  /* put second buffer, the jitterbuffer should now know that the packet
-   * spacing is 20ms and should ask for retransmission of seqnum 2 in
-   * 20ms+10ms because 2*jitter==0 and 0.5*packet_spacing==10ms */
-  fail_unless_equals_int (GST_FLOW_OK,
-      gst_harness_push (h, generate_test_buffer (1)));
-
-  /* push buffer 4, 2 and 3 are missing now, we should get
-   * retransmission events for 3 at 100ms*/
-  fail_unless_equals_int (GST_FLOW_OK,
-      gst_harness_push (h, generate_test_buffer (4)));
-
-  /* wait for first retransmission request */
-  gst_test_clock_set_time_and_process (testclock, 50 * GST_MSECOND);
+  for (gint i = 0; i <= latency_ms / PCMU_BUF_MS; i++)
+    gst_buffer_unref (gst_harness_pull (h));
 
   /* drop reconfigure event */
   gst_event_unref (gst_harness_pull_upstream_event (h));
-  /* drop GstEventStreamStart & GstEventCaps & GstEventSegment */
-  for (int i = 0; i < 3; i++)
-    gst_event_unref (gst_harness_pull_event (h));
 
-  /* First event for 2 */
-  out_event = gst_harness_pull_upstream_event (h);
-  verify_rtx_event (out_event, 2, rtx_retry_timeout, 10, PCMU_BUF_DURATION);
+  /*
+     The expected sequence of buffers is this:
+     ____   ____   ____   ____
+     ... | 10 | | 11 | | 12 | | 13 |
+     ––––   ––––   ––––   ––––
+     200ms  220ms  240ms  260ms
 
-  /* wait for second retransmission request */
-  gst_test_clock_set_time_and_process (testclock, 60 * GST_MSECOND);
+     But instead we get this:
+     ____    _ _    _ _   ____
+     ... | 10 |  |   |  |   | | 13 |
+     ––––    - -    - -   ––––
+     200ms                260ms
 
-  /* Second event for 3 */
-  out_event = gst_harness_pull_upstream_event (h);
-  verify_rtx_event (out_event, 3, 60 * GST_MSECOND, 0, PCMU_BUF_DURATION);
+     Now it is important to note that the next thing that happens is that
+     the RTX timeout for packet 11 will happen at time 230ms, so we crank
+     the timer thread to advance the time to this: */
+  gst_harness_crank_single_clock_wait (h);
+  rtx_delay_ms = PCMU_BUF_MS / 2;
+  verify_rtx_event (gst_harness_pull_upstream_event (h),
+      11, 11 * PCMU_BUF_DURATION, rtx_delay_ms, PCMU_BUF_DURATION);
+  last_rtx_request = gst_clock_get_time (GST_CLOCK (testclock));
+  fail_unless_equals_int64 (last_rtx_request,
+      11 * PCMU_BUF_DURATION + rtx_delay_ms * GST_MSECOND);
+  gst_harness_wait_for_clock_id_waits (h, 1, 60);
 
-  /* now we wait for the next timeout for 2 */
-  gst_test_clock_set_time_and_process (testclock, 90 * GST_MSECOND);
-
-  /* First event for 2 */
-  out_event = gst_harness_pull_upstream_event (h);
-  verify_rtx_event (out_event, 2, rtx_retry_timeout, 50, PCMU_BUF_DURATION);
-
-  /* now we wait for the next timeout for 3 */
-  gst_test_clock_set_time_and_process (testclock, 100 * GST_MSECOND);
-
-  /* Second event for 3 */
-  out_event = gst_harness_pull_upstream_event (h);
-  verify_rtx_event (out_event, 3, 60 * GST_MSECOND, 40, PCMU_BUF_DURATION);
-
-  /* make buffer 3 */
+  /* The next scheduled RTX for packet 11 is now at 230 + 40 = 270ms,
+     so the next thing that happens is that buffer 13 arrives in perfect time: */
+  now = 13 * PCMU_BUF_DURATION;
+  gst_harness_set_time (h, now);
   fail_unless_equals_int (GST_FLOW_OK,
-      gst_harness_push (h, generate_test_buffer (3)));
+      gst_harness_push (h,
+          generate_test_buffer_full (now, TRUE, 13,
+              13 * PCMU_RTP_TS_DURATION)));
 
-  /* make more buffers */
-  for (i = 5; i < 15; i++) {
+  /*
+
+     This will estimate the dts on the two missing packets to:
+     ____   ____
+     ... | 11 | | 12 | ...
+     ––––   ––––
+     220ms  240ms
+
+     And given their regular interspacing of 20ms, it will schedule two RTX
+     timers for them like so:
+
+     ____   ____
+     ... | 11 | | 12 | ...
+     ––––   ––––
+     230ms  250ms
+
+     There are however two problems, packet 11 we have already sent one RTX for
+     and its timeout is currently at 270ms, so we should not tamper with that,
+     and as for packet 12, 250ms has already expired, so we now expect to see
+     an rtx-event being sent for packet 12 immediately: */
+  verify_rtx_event (gst_harness_pull_upstream_event (h),
+      12, 12 * PCMU_BUF_DURATION, rtx_delay_ms, PCMU_BUF_DURATION);
+
+  /* and another crank will see the second RTX event being sent for packet 11 */
+  gst_harness_crank_single_clock_wait (h);
+  rtx_delay_ms += 40;
+  verify_rtx_event (gst_harness_pull_upstream_event (h),
+      11, 11 * PCMU_BUF_DURATION, rtx_delay_ms, PCMU_BUF_DURATION);
+  last_rtx_request = gst_clock_get_time (GST_CLOCK (testclock));
+  fail_unless_equals_int64 (last_rtx_request,
+      11 * PCMU_BUF_DURATION + rtx_delay_ms * GST_MSECOND);
+
+  gst_object_unref (testclock);
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (text_rtx_two_missing_early)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  GstTestClock *testclock;
+  gint latency_ms = 30;
+  GstClockTime last_rtx_request, now;
+
+  testclock = gst_harness_get_testclock (h);
+  gst_harness_set_src_caps (h, generate_caps ());
+  g_object_set (h->element, "do-retransmission", TRUE, "latency", latency_ms,
+      NULL);
+
+  for (gint i = 0; i <= latency_ms / PCMU_BUF_MS; i++) {
+    gst_test_clock_set_time (testclock, i * PCMU_BUF_DURATION);
     fail_unless_equals_int (GST_FLOW_OK,
         gst_harness_push (h, generate_test_buffer (i)));
+    gst_harness_wait_for_clock_id_waits (h, 1, 60);
   }
 
-  gst_test_clock_set_time_and_process (testclock, 130 * GST_MSECOND);
+  gst_harness_crank_single_clock_wait (h);
+  fail_unless_equals_int64 (latency_ms * GST_MSECOND,
+      gst_clock_get_time (GST_CLOCK (testclock)));
 
-  /* now we only get requests for 2 */
-  out_event = gst_harness_pull_upstream_event (h);
-  verify_rtx_event (out_event, 2, rtx_retry_timeout, 90, PCMU_BUF_DURATION);
+  for (gint i = 0; i <= latency_ms / PCMU_BUF_MS; i++)
+    gst_buffer_unref (gst_harness_pull (h));
 
-  /* this is when buffer 0 deadline expires */
-  gst_test_clock_set_time_and_process (testclock, 200 * GST_MSECOND);
+  /* drop reconfigure event */
+  gst_event_unref (gst_harness_pull_upstream_event (h));
 
-  for (i = 0; i < 2; i++) {
-    GST_DEBUG ("popping %d", i);
-    out_buf = gst_harness_pull (h);
-    fail_unless_equals_int (i, get_rtp_seq_num (out_buf));
-    gst_buffer_unref (out_buf);
-  }
+  /*
+     The expected sequence of buffers is this:
+     ___   ___   ___   ___   ___
+     | 0 | | 1 | | 2 | | 3 | | 4 |
+     –––   –––   –––   –––   –––
+     0ms  20ms  40ms  60ms  80ms
 
-  /* this is when 2 is lost */
-  gst_test_clock_set_time_and_process (testclock, 240 * GST_MSECOND);
+     But instead we get this:
+     ___   ___   _ _   _ _   ___
+     | 0 | | 1 | |   | |   | | 4 |
+     –––   –––   – –   – –   –––
+     0ms  20ms              41ms
 
-  /* we should now receive a packet-lost-event for buffer 2 */
-  out_event = gst_harness_pull_event (h);
-  verify_lost_event (out_event, 2, 40 * GST_MSECOND, PCMU_BUF_DURATION);
+   */
 
-  /* verify that buffers made it through! */
-  for (i = 3; i < 15; i++) {
-    GST_DEBUG ("popping %d", i);
-    out_buf = gst_harness_pull (h);
-    fail_unless_equals_int (i, get_rtp_seq_num (out_buf));
-    gst_buffer_unref (out_buf);
-  }
-  /* should still have only seen 1 packet lost events,
-     so no events in the queue */
-  fail_unless_equals_int (0, gst_harness_events_in_queue (h));
+  now = 41 * GST_MSECOND;
+  gst_harness_set_time (h, now);
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h,
+          generate_test_buffer_full (now, TRUE, 4, 4 * PCMU_RTP_TS_DURATION)));
 
-  g_object_get (h->element, "stats", &rtx_stats, NULL);
+  /*
 
-  rtx_stat = gst_structure_get_value (rtx_stats, "rtx-count");
-  fail_unless_equals_uint64 (5, g_value_get_uint64 (rtx_stat));
+     With the now calculated packet-spacing of (41-20) / 3 = 7,
+     giving us these expected times:
+     ___   ___   ___   ___   ___
+     | 0 | | 1 | | 2 | | 3 | | 4 |
+     –––   –––   –––   –––   –––
+     0ms  20ms  27ms  34ms  41ms
 
-  rtx_stat = gst_structure_get_value (rtx_stats, "rtx-success-count");
-  fail_unless_equals_uint64 (1, g_value_get_uint64 (rtx_stat));
+     For RTX, the inital RTX-timeouts for the missing buffers are
+     the expected arrival time + half the packet-spacing time, like this:
+     ___   ___
+     | 2 | | 3 |
+     –––   –––
+     50ms  70ms
 
-  rtx_stat = gst_structure_get_value (rtx_stats, "rtx-rtt");
-  fail_unless_equals_uint64 (0, g_value_get_uint64 (rtx_stat));
-  gst_structure_free (rtx_stats);
+     But since we have re-calculated the estimated arrival-time
+     of these buffers, we have to adjust the RTX timeout as well,
+     and we use the original delay (packet-spacing / 2) = 10ms,
+     and add it on:
+     ___   ___
+     | 2 | | 3 |
+     –––   –––
+     37ms  44ms
+
+     Also note that the first RTX request is now scheduled for a
+     time that is prior to NOW (37ms < 41ms), so it will be sent straight
+     away without us needing to "crank" the timer-thread
+
+   */
+
+  /* The RTX request for packet 2 has timestamp 27ms and delay 10ms */
+  verify_rtx_event (gst_harness_pull_upstream_event (h),
+      2, 27 * GST_MSECOND, 10, PCMU_BUF_DURATION);
+  /* and is sent immediately after packet 4 arrives (41ms) */
+  last_rtx_request = gst_clock_get_time (GST_CLOCK (testclock));
+  fail_unless_equals_int64 (last_rtx_request, now);
+
+  /* crank the timer thread */
+  gst_harness_crank_single_clock_wait (h);
+
+  /* The RTX request for packet 3 has timestamp 34ms and delay 10ms */
+  verify_rtx_event (gst_harness_pull_upstream_event (h),
+      3, 34 * GST_MSECOND, 10, PCMU_BUF_DURATION);
+  /* and is sent at 44ms */
+  last_rtx_request = gst_clock_get_time (GST_CLOCK (testclock));
+  fail_unless_equals_int64 (last_rtx_request, 44 * GST_MSECOND);
 
   gst_object_unref (testclock);
   gst_harness_teardown (h);
@@ -1073,12 +1377,12 @@
 
   /* we should now receive retransmission requests for 2 -> 5 */
   out_event = gst_harness_pull_upstream_event (h);
-  verify_rtx_event (out_event, 2, 20 * GST_MSECOND, 30, PCMU_BUF_DURATION);
+  verify_rtx_event (out_event, 2, 20 * GST_MSECOND, 17, PCMU_BUF_DURATION);
 
   for (i = 3; i < 5; i++) {
     GST_DEBUG ("popping %d", i);
     out_event = gst_harness_pull_upstream_event (h);
-    verify_rtx_event (out_event, i, 20 * GST_MSECOND, 0, PCMU_BUF_DURATION);
+    verify_rtx_event (out_event, i, 20 * GST_MSECOND, 17, PCMU_BUF_DURATION);
   }
   fail_unless_equals_int (0, gst_harness_upstream_events_in_queue (h));
 
@@ -1089,7 +1393,7 @@
 
   /* we should now receive retransmission requests for 5 */
   out_event = gst_harness_pull_upstream_event (h);
-  verify_rtx_event (out_event, 5, 20 * GST_MSECOND, 0, PCMU_BUF_DURATION);
+  verify_rtx_event (out_event, 5, 20 * GST_MSECOND, 17, PCMU_BUF_DURATION);
 
   /* wait for timeout for rtx 6 -> 7 */
   gst_test_clock_set_time_and_process (testclock, 60 * GST_MSECOND);
@@ -1097,7 +1401,7 @@
   for (i = 6; i < 8; i++) {
     GST_DEBUG ("popping %d", i);
     out_event = gst_harness_pull_upstream_event (h);
-    verify_rtx_event (out_event, i, 20 * GST_MSECOND, 0, PCMU_BUF_DURATION);
+    verify_rtx_event (out_event, i, 20 * GST_MSECOND, 17, PCMU_BUF_DURATION);
   }
 
   /* churn through 7 sync_times until the new buffer gets pushed out */
@@ -1113,9 +1417,6 @@
     gst_buffer_unref (out_buf);
   }
 
-  /* churn through 1 sync_time until the next buffer gets pushed out */
-  gst_harness_crank_single_clock_wait (h);
-
   for (i = 2; i < 8; i++) {
     GST_DEBUG ("popping lost event %d", i);
     out_event = gst_harness_pull_event (h);
@@ -1132,15 +1433,635 @@
     gst_buffer_unref (out_buf);
   }
 
-  GST_DEBUG ("waiting for 240ms");
-  gst_test_clock_set_time_and_process (testclock, 240 * GST_MSECOND);
-
   GST_DEBUG ("popping lost event 10");
   out_event = gst_harness_pull_event (h);
   verify_lost_event (out_event, 10, 40 * GST_MSECOND, PCMU_BUF_DURATION);
 
   fail_unless_equals_int (0, gst_harness_events_in_queue (h));
-  fail_unless_equals_int (20, gst_harness_upstream_events_in_queue (h));
+  fail_unless_equals_int (15, gst_harness_upstream_events_in_queue (h));
+
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-lost", G_TYPE_UINT64, (guint64) 7,
+              "rtx-count", G_TYPE_UINT64, (guint64) 21,
+              "rtx-success-count", G_TYPE_UINT64, (guint64) 0,
+              "rtx-rtt", G_TYPE_UINT64, (guint64) 0, NULL)));
+
+  gst_object_unref (testclock);
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtx_buffer_arrives_just_in_time)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  GstTestClock *testclock;
+  gint latency_ms = 5 * PCMU_BUF_MS;
+  gint num_init_buffers = latency_ms / PCMU_BUF_MS + 1;
+  GstBuffer *buffer;
+  GstClockTime now, last_rtx_request;
+
+  testclock = gst_harness_get_testclock (h);
+  gst_harness_set_src_caps (h, generate_caps ());
+  g_object_set (h->element, "do-retransmission", TRUE, "latency", latency_ms,
+      "rtx-max-retries", 1, NULL);
+
+  /* Push/pull buffers and advance time past buffer 0's timeout (in order to
+   * simplify the test) */
+  for (gint i = 0; i < num_init_buffers; i++) {
+    gst_test_clock_set_time (testclock, i * PCMU_BUF_DURATION);
+    fail_unless_equals_int (GST_FLOW_OK,
+        gst_harness_push (h, generate_test_buffer (i)));
+    gst_harness_wait_for_clock_id_waits (h, 1, 60);
+  }
+
+  gst_harness_crank_single_clock_wait (h);
+  fail_unless_equals_int64 (latency_ms * GST_MSECOND,
+      gst_clock_get_time (GST_CLOCK (testclock)));
+
+  for (gint i = 0; i < num_init_buffers; i++)
+    gst_buffer_unref (gst_harness_pull (h));
+
+  /* drop reconfigure event */
+  gst_event_unref (gst_harness_pull_upstream_event (h));
+
+  /* Crank clock to send retransmission events requesting seqnum 6 which has
+   * not arrived yet. */
+  gst_harness_crank_single_clock_wait (h);
+  verify_rtx_event (gst_harness_pull_upstream_event (h),
+      6, 6 * PCMU_BUF_DURATION, 10, PCMU_BUF_DURATION);
+
+  last_rtx_request = gst_clock_get_time (GST_CLOCK (testclock));
+  fail_unless_equals_int64 (last_rtx_request, 130 * GST_MSECOND);
+
+  /* seqnum 6 arrives just before it times out and is considered lost */
+  now = 200 * GST_MSECOND;
+  gst_test_clock_set_time (testclock, now);
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
+          generate_test_buffer_rtx (now, 6)));
+  buffer = gst_harness_pull (h);
+  fail_unless_equals_int (6, get_rtp_seq_num (buffer));
+  gst_buffer_unref (buffer);
+
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) num_init_buffers + 1,
+              "num-lost", G_TYPE_UINT64, (guint64) 0,
+              "rtx-count", G_TYPE_UINT64, (guint64) 1,
+              "rtx-success-count", G_TYPE_UINT64, (guint64) 1,
+              "rtx-per-packet", G_TYPE_DOUBLE, 1.0,
+              "rtx-rtt", G_TYPE_UINT64, (guint64) (now - last_rtx_request),
+              NULL)));
+
+  gst_object_unref (testclock);
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtx_buffer_arrives_too_late)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  GstTestClock *testclock;
+  gint latency_ms = 5 * PCMU_BUF_MS;
+  gint num_init_buffers = latency_ms / PCMU_BUF_MS + 1;
+  GstClockTime now, last_rtx_request;
+
+  testclock = gst_harness_get_testclock (h);
+  gst_harness_set_src_caps (h, generate_caps ());
+  g_object_set (h->element, "do-retransmission", TRUE, "latency", latency_ms,
+      "do-lost", TRUE, "rtx-max-retries", 1, NULL);
+
+  /* Push/pull buffers and advance time past buffer 0's timeout (in order to
+   * simplify the test) */
+  for (gint i = 0; i < num_init_buffers; i++) {
+    gst_test_clock_set_time (testclock, i * PCMU_BUF_DURATION);
+    fail_unless_equals_int (GST_FLOW_OK,
+        gst_harness_push (h, generate_test_buffer (i)));
+    gst_harness_wait_for_clock_id_waits (h, 1, 60);
+  }
+
+  gst_harness_crank_single_clock_wait (h);
+  fail_unless_equals_int64 (latency_ms * GST_MSECOND,
+      gst_clock_get_time (GST_CLOCK (testclock)));
+
+  for (gint i = 0; i < num_init_buffers; i++)
+    gst_buffer_unref (gst_harness_pull (h));
+
+  /* drop reconfigure event */
+  gst_event_unref (gst_harness_pull_upstream_event (h));
+  /* drop GstEventStreamStart & GstEventCaps & GstEventSegment */
+  for (gint i = 0; i < 3; i++)
+    gst_event_unref (gst_harness_pull_event (h));
+
+  /* Crank clock to send retransmission events requesting seqnum 6 which has
+   * not arrived yet. */
+  gst_harness_crank_single_clock_wait (h);
+  verify_rtx_event (gst_harness_pull_upstream_event (h),
+      6, 6 * PCMU_BUF_DURATION, 10, PCMU_BUF_DURATION);
+
+  last_rtx_request = gst_clock_get_time (GST_CLOCK (testclock));
+  fail_unless_equals_int64 (last_rtx_request, 130 * GST_MSECOND);
+
+  /* seqnum 6 is considered lost */
+  gst_harness_crank_single_clock_wait (h);
+  verify_lost_event (gst_harness_pull_event (h), 6,
+      6 * PCMU_BUF_DURATION, PCMU_BUF_DURATION);
+
+  /* seqnum 6 arrives too late */
+  now = gst_clock_get_time (GST_CLOCK (testclock));
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
+          generate_test_buffer_rtx (now, 6)));
+
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) num_init_buffers,
+              "num-lost", G_TYPE_UINT64, (guint64) 1,
+              "num-late", G_TYPE_UINT64, (guint64) 1,
+              "num-duplicates", G_TYPE_UINT64, (guint64) 0,
+              "rtx-count", G_TYPE_UINT64, (guint64) 1,
+              "rtx-success-count", G_TYPE_UINT64, (guint64) 0,
+              "rtx-per-packet", G_TYPE_DOUBLE, 1.0,
+              "rtx-rtt", G_TYPE_UINT64, (guint64) (now - last_rtx_request),
+              NULL)));
+
+  gst_object_unref (testclock);
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtx_original_buffer_does_not_update_rtx_stats)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  GstTestClock *testclock;
+  gint latency_ms = 5 * PCMU_BUF_MS;
+  gint num_init_buffers = latency_ms / PCMU_BUF_MS + 1;
+  GstBuffer *buffer;
+  GstClockTime now, last_rtx_request;
+
+  testclock = gst_harness_get_testclock (h);
+  gst_harness_set_src_caps (h, generate_caps ());
+  g_object_set (h->element, "do-retransmission", TRUE, "latency", latency_ms,
+      "rtx-max-retries", 1, NULL);
+
+  /* Push/pull buffers and advance time past buffer 0's timeout (in order to
+   * simplify the test) */
+  for (gint i = 0; i < num_init_buffers; i++) {
+    gst_test_clock_set_time (testclock, i * PCMU_BUF_DURATION);
+    fail_unless_equals_int (GST_FLOW_OK,
+        gst_harness_push (h, generate_test_buffer (i)));
+    gst_harness_wait_for_clock_id_waits (h, 1, 60);
+  }
+
+  gst_harness_crank_single_clock_wait (h);
+  fail_unless_equals_int64 (latency_ms * GST_MSECOND,
+      gst_clock_get_time (GST_CLOCK (testclock)));
+
+  for (gint i = 0; i < num_init_buffers; i++)
+    gst_buffer_unref (gst_harness_pull (h));
+
+  /* drop reconfigure event */
+  gst_event_unref (gst_harness_pull_upstream_event (h));
+
+  /* Crank clock to send retransmission events requesting seqnum 6 which has
+   * not arrived yet. */
+  gst_harness_crank_single_clock_wait (h);
+  verify_rtx_event (gst_harness_pull_upstream_event (h),
+      6, 6 * PCMU_BUF_DURATION, 10, PCMU_BUF_DURATION);
+
+  last_rtx_request = gst_clock_get_time (GST_CLOCK (testclock));
+  fail_unless_equals_int64 (last_rtx_request, 130 * GST_MSECOND);
+
+  /* ORIGINAL seqnum 6 arrives just before it times out and is considered
+   * lost. */
+  now = 200 * GST_MSECOND;
+  gst_test_clock_set_time (testclock, now);
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
+          generate_test_buffer_full (now, TRUE, 6, 6 * PCMU_RTP_TS_DURATION)));
+  buffer = gst_harness_pull (h);
+  fail_unless_equals_int (6, get_rtp_seq_num (buffer));
+  gst_buffer_unref (buffer);
+
+  /* The original buffer does not count in the RTX stats. */
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) num_init_buffers + 1,
+              "num-lost", G_TYPE_UINT64, (guint64) 0,
+              "num-late", G_TYPE_UINT64, (guint64) 0,
+              "num-duplicates", G_TYPE_UINT64, (guint64) 0,
+              "rtx-count", G_TYPE_UINT64, (guint64) 1,
+              "rtx-success-count", G_TYPE_UINT64, (guint64) 0,
+              "rtx-per-packet", G_TYPE_DOUBLE, 0.0,
+              "rtx-rtt", G_TYPE_UINT64, (guint64) 0, NULL)));
+
+  /* Now the retransmitted packet arrives and stats should be updated. Note
+   * that the buffer arrives in time and should not be considered late, but
+   * a duplicate. */
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
+          generate_test_buffer_rtx (now, 6)));
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) num_init_buffers + 1,
+              "num-lost", G_TYPE_UINT64, (guint64) 0,
+              "num-late", G_TYPE_UINT64, (guint64) 0,
+              "num-duplicates", G_TYPE_UINT64, (guint64) 1,
+              "rtx-count", G_TYPE_UINT64, (guint64) 1,
+              "rtx-success-count", G_TYPE_UINT64, (guint64) 0,
+              "rtx-per-packet", G_TYPE_DOUBLE, 1.0,
+              "rtx-rtt", G_TYPE_UINT64, (guint64) (now - last_rtx_request),
+              NULL)));
+
+  gst_object_unref (testclock);
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtx_duplicate_packet_updates_rtx_stats)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  GstTestClock *testclock;
+  gint latency_ms = 5 * PCMU_BUF_MS;
+  gint num_init_buffers = latency_ms / PCMU_BUF_MS + 1;
+  GstClockTime now, rtx_request_6, rtx_request_7;
+  gint rtx_delay_ms;
+
+  testclock = gst_harness_get_testclock (h);
+  gst_harness_set_src_caps (h, generate_caps ());
+  g_object_set (h->element, "do-retransmission", TRUE, "latency", latency_ms,
+      NULL);
+
+  /* Push/pull buffers and advance time past buffer 0's timeout (in order to
+   * simplify the test) */
+  for (gint i = 0; i < num_init_buffers; i++) {
+    gst_test_clock_set_time (testclock, i * PCMU_BUF_DURATION);
+    fail_unless_equals_int (GST_FLOW_OK,
+        gst_harness_push (h, generate_test_buffer (i)));
+    gst_harness_wait_for_clock_id_waits (h, 1, 60);
+  }
+
+  gst_harness_crank_single_clock_wait (h);
+  fail_unless_equals_int64 (latency_ms * GST_MSECOND,
+      gst_clock_get_time (GST_CLOCK (testclock)));
+
+  for (gint i = 0; i < num_init_buffers; i++)
+    gst_buffer_unref (gst_harness_pull (h));
+
+  /* Drop reconfigure event */
+  gst_event_unref (gst_harness_pull_upstream_event (h));
+
+  /* Push packet 8 so that 6 and 7 is missing */
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h, generate_test_buffer (8)));
+
+  /* Wait for NACKs on 6 and 7 */
+  gst_harness_crank_single_clock_wait (h);
+  rtx_delay_ms = 10;
+  verify_rtx_event (gst_harness_pull_upstream_event (h),
+      6, 6 * PCMU_BUF_DURATION, rtx_delay_ms, PCMU_BUF_DURATION);
+  rtx_request_6 = gst_clock_get_time (GST_CLOCK (testclock));
+  fail_unless_equals_int64 (rtx_request_6,
+      6 * PCMU_BUF_DURATION + rtx_delay_ms * GST_MSECOND);
+
+  gst_harness_crank_single_clock_wait (h);
+  verify_rtx_event (gst_harness_pull_upstream_event (h),
+      7, 7 * PCMU_BUF_DURATION, rtx_delay_ms, PCMU_BUF_DURATION);
+  rtx_request_7 = gst_clock_get_time (GST_CLOCK (testclock));
+  fail_unless_equals_int64 (rtx_request_7,
+      7 * PCMU_BUF_DURATION + rtx_delay_ms * GST_MSECOND);
+
+  /* Original packet 7 arrives */
+  now = 150 * GST_MSECOND;
+  gst_test_clock_set_time (testclock, now);
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
+          generate_test_buffer_full (now, TRUE, 7, 7 * PCMU_RTP_TS_DURATION)));
+
+  /* We're still waiting for packet 6, so 7 should not be pushed */
+  gst_harness_wait_for_clock_id_waits (h, 1, 60);
+  fail_unless_equals_int (gst_harness_buffers_in_queue (h), 0);
+
+  /* The original buffer does not count in the RTX stats. */
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-lost", G_TYPE_UINT64, (guint64) 0,
+              "num-late", G_TYPE_UINT64, (guint64) 0,
+              "num-duplicates", G_TYPE_UINT64, (guint64) 0,
+              "rtx-count", G_TYPE_UINT64, (guint64) 2,
+              "rtx-success-count", G_TYPE_UINT64, (guint64) 0,
+              "rtx-per-packet", G_TYPE_DOUBLE, 0.0,
+              "rtx-rtt", G_TYPE_UINT64, (guint64) 0, NULL)));
+
+  /* Push RTX packet 7. Should be dropped as duplicate but update RTX stats. */
+  now = 160 * GST_MSECOND;
+  gst_test_clock_set_time (testclock, now);
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
+          generate_test_buffer_rtx (now, 7)));
+  gst_harness_wait_for_clock_id_waits (h, 1, 60);
+  fail_unless_equals_int (gst_harness_buffers_in_queue (h), 0);
+
+  /* Check RTX stats with updated num-duplicates and rtx-rtt fields */
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) num_init_buffers,
+              "num-lost", G_TYPE_UINT64, (guint64) 0,
+              "num-late", G_TYPE_UINT64, (guint64) 0,
+              "num-duplicates", G_TYPE_UINT64, (guint64) 1,
+              "rtx-count", G_TYPE_UINT64, (guint64) 2,
+              "rtx-success-count", G_TYPE_UINT64, (guint64) 0,
+              "rtx-per-packet", G_TYPE_DOUBLE, 1.0,
+              "rtx-rtt", G_TYPE_UINT64, (guint64) (now - rtx_request_7),
+              NULL)));
+
+  /* RTX packet 6 arrives, both 6, 7 and 8 is ready to be pulled */
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
+          generate_test_buffer_rtx (now, 6)));
+
+  for (gint i = 6; i <= 8; i++) {
+    GstBuffer *buf = gst_harness_pull (h);
+    fail_unless_equals_int (i, get_rtp_seq_num (buf));
+    gst_buffer_unref (buf);
+  }
+
+  /* RTX stats is updated with success count increased. */
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) num_init_buffers + 3,
+              "num-lost", G_TYPE_UINT64, (guint64) 0,
+              "num-late", G_TYPE_UINT64, (guint64) 0,
+              "num-duplicates", G_TYPE_UINT64, (guint64) 1,
+              "rtx-count", G_TYPE_UINT64, (guint64) 2,
+              "rtx-success-count", G_TYPE_UINT64, (guint64) 1,
+              "rtx-per-packet", G_TYPE_DOUBLE, 1.0,
+              "rtx-rtt", G_TYPE_UINT64, (guint64)
+              /* Use the rtx-rtt formula. Can be subject to change though. */
+              ((now - rtx_request_6) + 47 * (now - rtx_request_7)) / 48,
+              NULL)));
+
+  gst_object_unref (testclock);
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtx_buffer_arrives_after_lost_updates_rtx_stats)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  GstTestClock *testclock;
+  gint latency_ms = 5 * PCMU_BUF_MS;
+  gint num_init_buffers = latency_ms / PCMU_BUF_MS + 1;
+  GstClockTime now, last_rtx_request;
+
+  testclock = gst_harness_get_testclock (h);
+  gst_harness_set_src_caps (h, generate_caps ());
+  g_object_set (h->element, "do-retransmission", TRUE, "latency", latency_ms,
+      "do-lost", TRUE, "rtx-max-retries", 1, NULL);
+
+  /* Push/pull buffers and advance time past buffer 0's timeout (in order to
+   * simplify the test) */
+  for (gint i = 0; i < num_init_buffers; i++) {
+    gst_test_clock_set_time (testclock, i * PCMU_BUF_DURATION);
+    fail_unless_equals_int (GST_FLOW_OK,
+        gst_harness_push (h, generate_test_buffer (i)));
+    gst_harness_wait_for_clock_id_waits (h, 1, 60);
+  }
+
+  gst_harness_crank_single_clock_wait (h);
+  fail_unless_equals_int64 (latency_ms * GST_MSECOND,
+      gst_clock_get_time (GST_CLOCK (testclock)));
+
+  for (gint i = 0; i < num_init_buffers; i++)
+    gst_buffer_unref (gst_harness_pull (h));
+
+  /* drop reconfigure event */
+  gst_event_unref (gst_harness_pull_upstream_event (h));
+  /* drop GstEventStreamStart & GstEventCaps & GstEventSegment */
+  for (gint i = 0; i < 3; i++)
+    gst_event_unref (gst_harness_pull_event (h));
+
+  /* Crank clock to send retransmission events requesting seqnum 6 which has
+   * not arrived yet. */
+  gst_harness_crank_single_clock_wait (h);
+  verify_rtx_event (gst_harness_pull_upstream_event (h),
+      6, 6 * PCMU_BUF_DURATION, 10, PCMU_BUF_DURATION);
+
+  last_rtx_request = gst_clock_get_time (GST_CLOCK (testclock));
+  fail_unless_equals_int64 (last_rtx_request, 130 * GST_MSECOND);
+
+  /* seqnum 6 is considered lost */
+  gst_harness_crank_single_clock_wait (h);
+  verify_lost_event (gst_harness_pull_event (h), 6,
+      6 * PCMU_BUF_DURATION, PCMU_BUF_DURATION);
+
+  /* seqnum 6 arrives too late */
+  now = gst_clock_get_time (GST_CLOCK (testclock));
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
+          generate_test_buffer_rtx (now, 6)));
+
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) num_init_buffers,
+              "num-lost", G_TYPE_UINT64, (guint64) 1,
+              "num-late", G_TYPE_UINT64, (guint64) 1,
+              "num-duplicates", G_TYPE_UINT64, (guint64) 0,
+              "rtx-count", G_TYPE_UINT64, (guint64) 1,
+              "rtx-success-count", G_TYPE_UINT64, (guint64) 0,
+              "rtx-per-packet", G_TYPE_DOUBLE, 1.0,
+              "rtx-rtt", G_TYPE_UINT64, (guint64) (now - last_rtx_request),
+              NULL)));
+
+  gst_object_unref (testclock);
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtx_rtt_larger_than_retry_timeout)
+{
+  /* When RTT is larger than retry period we will send two or more requests
+   * before receiving any retransmission packets */
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  GstTestClock *testclock;
+  gint latency_ms = 100;
+  gint num_init_buffers = latency_ms / PCMU_BUF_MS + 1;
+  gint rtx_retry_timeout_ms = 20;
+  gint rtx_delay_ms = 10;
+  gint rtt = rtx_retry_timeout_ms * GST_MSECOND + 1;
+  GstClockTime now, first_request, second_request;
+
+  testclock = gst_harness_get_testclock (h);
+  gst_harness_set_src_caps (h, generate_caps ());
+  g_object_set (h->element, "do-retransmission", TRUE, "latency", latency_ms,
+      "rtx-retry-timeout", rtx_retry_timeout_ms, NULL);
+
+  /* Push/pull buffers and advance time past buffer 0's timeout (in order to
+   * simplify the test) */
+  for (gint i = 0; i < num_init_buffers; i++) {
+    gst_test_clock_set_time (testclock, i * PCMU_BUF_DURATION);
+    fail_unless_equals_int (GST_FLOW_OK,
+        gst_harness_push (h, generate_test_buffer (i)));
+    gst_harness_wait_for_clock_id_waits (h, 1, 60);
+  }
+
+  gst_harness_crank_single_clock_wait (h);
+  fail_unless_equals_int64 (latency_ms * GST_MSECOND,
+      gst_clock_get_time (GST_CLOCK (testclock)));
+
+  for (gint i = 0; i < num_init_buffers; i++)
+    gst_buffer_unref (gst_harness_pull (h));
+
+  /* Drop reconfigure event */
+  gst_event_unref (gst_harness_pull_upstream_event (h));
+
+  /* Wait for first NACK on 6 */
+  gst_harness_crank_single_clock_wait (h);
+  verify_rtx_event (gst_harness_pull_upstream_event (h),
+      6, 6 * PCMU_BUF_DURATION, rtx_delay_ms, PCMU_BUF_DURATION);
+  first_request = gst_clock_get_time (GST_CLOCK (testclock));
+  fail_unless_equals_int64 (first_request,
+      6 * PCMU_BUF_DURATION + rtx_delay_ms * GST_MSECOND);
+
+  /* Packet 7 arrives in time (so that we avoid its EXPECTED timers to
+   * interfer with our test) */
+  gst_test_clock_set_time (testclock, 7 * PCMU_BUF_DURATION);
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h, generate_test_buffer (7)));
+
+  /* Simulating RTT > rtx-retry-timeout, we send a new NACK before receiving
+   * the RTX packet. Wait for second NACK on 6 */
+  gst_harness_crank_single_clock_wait (h);
+  rtx_delay_ms += rtx_retry_timeout_ms;
+  verify_rtx_event (gst_harness_pull_upstream_event (h),
+      6, 6 * PCMU_BUF_DURATION, rtx_delay_ms, PCMU_BUF_DURATION);
+  second_request = gst_clock_get_time (GST_CLOCK (testclock));
+  fail_unless_equals_int64 (second_request,
+      6 * PCMU_BUF_DURATION + rtx_delay_ms * GST_MSECOND);
+
+  /* The first retransmitted packet arrives */
+  now = first_request + rtt;
+  gst_test_clock_set_time (testclock, now);
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
+          generate_test_buffer_rtx (now, 6)));
+
+  /* Pull packet 6 and 7 */
+  gst_buffer_unref (gst_harness_pull (h));
+  gst_buffer_unref (gst_harness_pull (h));
+
+  /* Stats should be updated. Note that RTT is not updated since we cannot be
+   * sure whether the RTX packet is in response to the first or second NACK. */
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) num_init_buffers + 2,
+              "num-lost", G_TYPE_UINT64, (guint64) 0,
+              "num-late", G_TYPE_UINT64, (guint64) 0,
+              "num-duplicates", G_TYPE_UINT64, (guint64) 0,
+              "rtx-count", G_TYPE_UINT64, (guint64) 2,
+              "rtx-success-count", G_TYPE_UINT64, (guint64) 1,
+              "rtx-per-packet", G_TYPE_DOUBLE, 2.0,
+              "rtx-rtt", G_TYPE_UINT64, (guint64) 0, NULL)));
+
+  /* Packet 8 arrives in time */
+  gst_test_clock_set_time (testclock, 8 * PCMU_BUF_DURATION);
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h, generate_test_buffer (8)));
+  gst_buffer_unref (gst_harness_pull (h));
+
+  /* Now the second retransmitted packet arrives */
+  now = second_request + rtt;
+  gst_test_clock_set_time (testclock, now);
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
+          generate_test_buffer_rtx (now, 6)));
+
+  /* The stats is updated with the correct RTT. */
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) num_init_buffers + 3,
+              "num-lost", G_TYPE_UINT64, (guint64) 0,
+              "num-late", G_TYPE_UINT64, (guint64) 0,
+              "num-duplicates", G_TYPE_UINT64, (guint64) 1,
+              "rtx-count", G_TYPE_UINT64, (guint64) 2,
+              "rtx-success-count", G_TYPE_UINT64, (guint64) 1,
+              "rtx-per-packet", G_TYPE_DOUBLE, 2.0,
+              "rtx-rtt", G_TYPE_UINT64, (guint64) rtt, NULL)));
+
+  gst_object_unref (testclock);
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtx_no_request_if_time_past_retry_period)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  const gint latency_ms = 200;
+  const gint retry_period_ms = 120;
+  GstTestClock *testclock;
+  GstClockID pending_id, processed_id;
+  GstClockTime time;
+  GstEvent *event;
+  gint i;
+
+  gst_harness_set_src_caps (h, generate_caps ());
+  testclock = gst_harness_get_testclock (h);
+
+  g_object_set (h->element, "do-lost", TRUE, NULL);
+  g_object_set (h->element, "do-retransmission", TRUE, NULL);
+  g_object_set (h->element, "latency", latency_ms, NULL);
+  g_object_set (h->element, "rtx-retry-period", retry_period_ms, NULL);
+
+  /* push the first couple of buffers */
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h, generate_test_buffer (0)));
+
+  gst_harness_set_time (h, 1 * PCMU_BUF_DURATION);
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h, generate_test_buffer (1)));
+
+  /* drop reconfigure event */
+  gst_event_unref (gst_harness_pull_upstream_event (h));
+  /* drop GstEventStreamStart & GstEventCaps & GstEventSegment */
+  for (i = 0; i < 3; i++)
+    gst_event_unref (gst_harness_pull_event (h));
+
+  /* Wait for the first EXPECTED timer to be scheduled */
+  gst_test_clock_wait_for_next_pending_id (testclock, &pending_id);
+  time = gst_clock_id_get_time (pending_id);
+  fail_unless_equals_int64 (time, 2 * PCMU_BUF_DURATION + 10 * GST_MSECOND);
+
+  /* Let the first EXPECTED timer time out and be sent. However, set the 'now'
+   * time to be past the retry-period simulating that the jitterbuffer has too
+   * much to do and is not able to process all timers in real-time. In this
+   * case the jitterbuffer should not schedule a new EXPECTED timer as that
+   * would just make matters worse (more unnecessary processing of a request
+   * that is already too late to be valuable). In practice this typically
+   * happens for high loss networks with low RTT. */
+  gst_test_clock_set_time (testclock,
+      2 * PCMU_BUF_DURATION + retry_period_ms * GST_MSECOND + 1);
+  processed_id = gst_test_clock_process_next_clock_id (testclock);
+  fail_unless (pending_id == processed_id);
+  gst_clock_id_unref (pending_id);
+  gst_clock_id_unref (processed_id);
+
+  /* Verify the event. It could be argued that this request is already too
+   * late and unnecessary. However, in order to keep things simple (for now)
+   * we just keep the already scehduled EXPECTED timer, but refrain from
+   * scheduled another EXPECTED timer */
+  event = gst_harness_pull_upstream_event (h);
+  verify_rtx_event (event, 2, 2 * PCMU_BUF_DURATION, 10, PCMU_BUF_DURATION);
+
+  /* "crank" to reach the DEADLINE for packet 0 */
+  gst_harness_crank_single_clock_wait (h);
+  gst_buffer_unref (gst_harness_pull (h));
+  gst_buffer_unref (gst_harness_pull (h));
+
+  fail_unless_equals_int (0, gst_harness_upstream_events_in_queue (h));
+  fail_unless_equals_int (0, gst_harness_events_in_queue (h));
+
+  /* "crank" to time out the LOST event */
+  gst_harness_crank_single_clock_wait (h);
+  event = gst_harness_pull_event (h);
+  verify_lost_event (event, 2, 2 * PCMU_BUF_DURATION, PCMU_BUF_DURATION);
 
   gst_object_unref (testclock);
   gst_harness_teardown (h);
@@ -1154,8 +2075,6 @@
   GstTestClock *testclock;
   const gint jb_latency_ms = 200;
 
-  guint32 timestamp_ms = 0;
-  guint32 rtp_ts = 0;
   gint i;
   GstEvent *out_event;
   GstBuffer *out_buf;
@@ -1172,10 +2091,7 @@
   fail_unless_equals_int (GST_FLOW_OK,
       gst_harness_push (h, generate_test_buffer (0)));
 
-  timestamp_ms += 20;
-  rtp_ts += PCMU_RTP_TS_DURATION;
-  gst_harness_set_time (h, timestamp_ms * GST_MSECOND);
-
+  gst_harness_set_time (h, 1 * PCMU_BUF_DURATION);
   fail_unless_equals_int (GST_FLOW_OK,
       gst_harness_push (h, generate_test_buffer (1)));
 
@@ -1210,12 +2126,23 @@
   fail_unless_equals_int (GST_FLOW_OK,
       gst_harness_push (h, generate_test_buffer (16)));
 
-  /* FIXME: something is up with the timestamp here!!?! */
+  /* Manually check the first rtx event */
   out_event = gst_harness_pull_upstream_event (h);
-  verify_rtx_event (out_event, 6, 119999994, 0, PCMU_BUF_DURATION);
-  /* lost more rtx with weird timestamps... */
-  for (i = 0; i < 13; i++) {
-    gst_event_unref (gst_harness_pull_upstream_event (h));
+  verify_rtx_event (out_event, 6, 6 * PCMU_BUF_DURATION, 10, PCMU_BUF_DURATION);
+  /* Go throught the rest of rtx events. A bit more relaxed since order is
+   * partly an implentation detail. */
+  for (i = 0; i < 12; i++) {
+    const GstStructure *s;
+    guint seqnum, retry;
+
+    fail_unless (out_event = gst_harness_pull_upstream_event (h));
+    fail_unless (s = gst_event_get_structure (out_event));
+    fail_unless (gst_structure_get_uint (s, "seqnum", &seqnum));
+    fail_unless (gst_structure_get_uint (s, "retry", &retry));
+    fail_unless (seqnum >= 6 && seqnum <= 12);
+
+    verify_rtx_event (out_event, seqnum, seqnum * PCMU_BUF_DURATION,
+        10 + retry * 40, PCMU_BUF_DURATION);
   }
 
   fail_unless_equals_int (0, gst_harness_upstream_events_in_queue (h));
@@ -1227,23 +2154,20 @@
         gst_harness_push (h, generate_test_buffer (i)));
   }
 
-  /* FIXME: wtf is going on with timestamps and durations here??!? */
   gst_harness_crank_single_clock_wait (h);
   out_event = gst_harness_pull_event (h);
-  verify_lost_event (out_event, 3, 41428571, 78571423);
-
-  /* FIXME: and these rtx... */
-  gst_harness_crank_single_clock_wait (h);
-  out_event = gst_harness_pull_upstream_event (h);
-  verify_rtx_event (out_event, 7, 141428565, 120, PCMU_BUF_DURATION);
+  verify_lost_event (out_event, 3, 3 * PCMU_BUF_DURATION,
+      3 * PCMU_BUF_DURATION);
 
   gst_harness_crank_single_clock_wait (h);
   out_event = gst_harness_pull_event (h);
-  verify_lost_event (out_event, 6, 119999994, 21428571);
+  verify_lost_event (out_event, 6, 6 * PCMU_BUF_DURATION,
+      1 * PCMU_BUF_DURATION);
 
   gst_harness_crank_single_clock_wait (h);
   out_event = gst_harness_pull_event (h);
-  verify_lost_event (out_event, 7, 141428565, 21428571);
+  verify_lost_event (out_event, 7, 7 * PCMU_BUF_DURATION,
+      1 * PCMU_BUF_DURATION);
 
   /* 8 */
   for (i = 8; i <= 16; i++) {
@@ -1274,6 +2198,14 @@
   fail_unless_equals_int (0, gst_harness_events_in_queue (h));
   fail_unless_equals_int (0, gst_harness_buffers_in_queue (h));
 
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) 11,
+              "num-lost", G_TYPE_UINT64, (guint64) 7,
+              "rtx-count", G_TYPE_UINT64, (guint64) 19,
+              "rtx-success-count", G_TYPE_UINT64, (guint64) 0,
+              "rtx-rtt", G_TYPE_UINT64, (guint64) 0, NULL)));
+
   gst_object_unref (testclock);
   gst_harness_teardown (h);
 }
@@ -1360,6 +2292,10 @@
     verify_lost_event (out_event, i, i * dur, dur);
   }
 
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-lost", G_TYPE_UINT64, (guint64) 4, NULL)));
+
   gst_object_unref (testclock);
   gst_harness_teardown (h);
 }
@@ -1488,12 +2424,53 @@
   fail_unless_equals_int ((4 + seq_offset) & 0xffff, get_rtp_seq_num (buffer));
   gst_buffer_unref (buffer);
 
+  /* we have lost 3, and one of them arrived eventually, but too late */
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) 2,
+              "num-lost", G_TYPE_UINT64, (guint64) 3,
+              "num-late", G_TYPE_UINT64, (guint64) 1, NULL)));
+
   gst_object_unref (testclock);
   gst_harness_teardown (h);
 }
 
 GST_END_TEST;
 
+GST_START_TEST (test_performance)
+{
+  GstHarness *h =
+      gst_harness_new_parse
+      ("rtpjitterbuffer do-lost=1 do-retransmission=1 latency=1000");
+  GTimer *timer = g_timer_new ();
+  const gdouble test_duration = 2.0;
+  guint buffers_pushed = 0;
+  guint buffers_received;
+
+  gst_harness_set_src_caps (h, generate_caps ());
+  gst_harness_use_systemclock (h);
+
+  while (g_timer_elapsed (timer, NULL) < test_duration) {
+    /* Simulate 1ms packets */
+    guint n = buffers_pushed * 2;       // every packet also produces a gap
+    guint16 seqnum = n & 0xffff;
+    guint32 rtp_ts = n * 8;
+    GstClockTime dts = n * GST_MSECOND;
+    gst_harness_push (h, generate_test_buffer_full (dts, TRUE, seqnum, rtp_ts));
+    buffers_pushed++;
+    g_usleep (G_USEC_PER_SEC / 10000);
+  }
+  g_timer_destroy (timer);
+
+  buffers_received = gst_harness_buffers_received (h);
+  GST_INFO ("Pushed %d, received %d (%.1f%%)", buffers_pushed, buffers_received,
+      100.0 * buffers_received / buffers_pushed);
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
 static Suite *
 rtpjitterbuffer_suite (void)
 {
@@ -1506,13 +2483,30 @@
   tcase_add_test (tc_chain, test_push_unordered);
   tcase_add_test (tc_chain, test_basetime);
   tcase_add_test (tc_chain, test_clear_pt_map);
+
   tcase_add_test (tc_chain, test_only_one_lost_event_on_large_gaps);
   tcase_add_test (tc_chain, test_two_lost_one_arrives_in_time);
   tcase_add_test (tc_chain, test_late_packets_still_makes_lost_events);
   tcase_add_test (tc_chain, test_all_packets_are_timestamped_zero);
+  tcase_add_loop_test (tc_chain, test_num_late_when_considered_lost_arrives, 0,
+      2);
+  tcase_add_test (tc_chain, test_reorder_of_non_equidistant_packets);
+  tcase_add_test (tc_chain,
+      test_loss_equidistant_spacing_with_parameter_packets);
+
   tcase_add_test (tc_chain, test_rtx_expected_next);
   tcase_add_test (tc_chain, test_rtx_two_missing);
+  tcase_add_test (tc_chain, text_rtx_two_missing_early);
   tcase_add_test (tc_chain, test_rtx_packet_delay);
+  tcase_add_test (tc_chain, test_rtx_buffer_arrives_just_in_time);
+  tcase_add_test (tc_chain, test_rtx_buffer_arrives_too_late);
+  tcase_add_test (tc_chain, test_rtx_original_buffer_does_not_update_rtx_stats);
+  tcase_add_test (tc_chain, test_rtx_duplicate_packet_updates_rtx_stats);
+  tcase_add_test (tc_chain,
+      test_rtx_buffer_arrives_after_lost_updates_rtx_stats);
+  tcase_add_test (tc_chain, test_rtx_rtt_larger_than_retry_timeout);
+  tcase_add_test (tc_chain, test_rtx_no_request_if_time_past_retry_period);
+
   tcase_add_test (tc_chain, test_gap_exceeds_latency);
   tcase_add_test (tc_chain, test_deadline_ts_offset);
   tcase_add_test (tc_chain, test_dts_gap_larger_than_latency);
@@ -1522,6 +2516,8 @@
       test_considered_lost_packet_in_large_gap_arrives, 0,
       G_N_ELEMENTS (test_considered_lost_packet_in_large_gap_arrives_input));
 
+  tcase_add_test (tc_chain, test_performance);
+
   return s;
 }