rtpjitterbuffer.c 54.4 KB
Newer Older
1 2 3 4
/* GStreamer
 *
 * Copyright (C) 2009 Nokia Corporation and its subsidary(-ies)
 *               contact: <stefan.kost@nokia.com>
5 6 7
 * Copyright (C) 2012 Cisco Systems, Inc
 *               Authors: Kelley Rogers <kelro@cisco.com>
 *               Havard Graff <hgraff@cisco.com>
8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
Tim-Philipp Müller's avatar
Tim-Philipp Müller committed
21 22
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 * Boston, MA 02110-1301, USA.
23 24 25
 */

#include <gst/check/gstcheck.h>
26
#include <gst/check/gsttestclock.h>
27

28 29
#include <gst/rtp/gstrtpbuffer.h>

30 31 32 33 34 35
/* For ease of programming we use globals to keep refs for our floating
 * src and sink pads we create; otherwise we always have to do get_pad,
 * get_peer, and then remove references in every test function */
static GstPad *mysrcpad, *mysinkpad;
/* we also have a list of src buffers */
static GList *inbuffers = NULL;
36
static gint num_dropped = 0;
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58

#define RTP_CAPS_STRING    \
    "application/x-rtp, "               \
    "media = (string)audio, "           \
    "payload = (int) 0, "               \
    "clock-rate = (int) 8000, "         \
    "encoding-name = (string)PCMU"

#define RTP_FRAME_SIZE 20

static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("application/x-rtp")
    );
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
    GST_PAD_SRC,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("application/x-rtp, "
        "clock-rate = (int) [ 1, 2147483647 ]")
    );

59
static void
Wim Taymans's avatar
Wim Taymans committed
60
buffer_dropped (gpointer data, GstMiniObject * obj)
61
{
Wim Taymans's avatar
Wim Taymans committed
62 63
  GST_DEBUG ("dropping buffer %p", obj);
  num_dropped++;
64 65
}

66 67 68 69 70 71 72
static GstElement *
setup_jitterbuffer (gint num_buffers)
{
  GstElement *jitterbuffer;
  GstClock *clock;
  GstBuffer *buffer;
  GstCaps *caps;
73
  /* a 20 sample audio block (2,5 ms) generated with
74 75
   * gst-launch audiotestsrc wave=silence blocksize=40 num-buffers=3 !
   *    "audio/x-raw,channels=1,rate=8000" ! mulawenc ! rtppcmupay !
76 77 78 79 80 81 82 83 84
   *     fakesink dump=1
   */
  guint8 in[] = {               /* first 4 bytes are rtp-header, next 4 bytes are timestamp */
    0x80, 0x80, 0x1c, 0x24, 0x46, 0xcd, 0xb7, 0x11, 0x3c, 0x3a, 0x7c, 0x5b,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
  };
  GstClockTime ts = G_GUINT64_CONSTANT (0);
  GstClockTime tso = gst_util_uint64_scale (RTP_FRAME_SIZE, GST_SECOND, 8000);
85
  /*guint latency = GST_TIME_AS_MSECONDS (num_buffers * tso); */
86 87 88
  gint i;

  GST_DEBUG ("setup_jitterbuffer");
Wim Taymans's avatar
Wim Taymans committed
89
  jitterbuffer = gst_check_setup_element ("rtpjitterbuffer");
90 91 92 93 94 95 96 97 98 99
  /* we need a clock here */
  clock = gst_system_clock_obtain ();
  gst_element_set_clock (jitterbuffer, clock);
  gst_object_unref (clock);
  /* setup latency */
  /* latency would be 7 for 3 buffers here, default is 200
     g_object_set (G_OBJECT (jitterbuffer), "latency", latency, NULL);
     GST_INFO_OBJECT (jitterbuffer, "set latency to %u ms", latency);
   */

100 101
  mysrcpad = gst_check_setup_src_pad (jitterbuffer, &srctemplate);
  mysinkpad = gst_check_setup_sink_pad (jitterbuffer, &sinktemplate);
102 103 104 105 106
  gst_pad_set_active (mysrcpad, TRUE);
  gst_pad_set_active (mysinkpad, TRUE);

  /* create n buffers */
  caps = gst_caps_from_string (RTP_CAPS_STRING);
107
  gst_check_setup_events (mysrcpad, jitterbuffer, caps, GST_FORMAT_TIME);
Wim Taymans's avatar
Wim Taymans committed
108 109
  gst_caps_unref (caps);

110 111
  for (i = 0; i < num_buffers; i++) {
    buffer = gst_buffer_new_and_alloc (sizeof (in));
Wim Taymans's avatar
Wim Taymans committed
112
    gst_buffer_fill (buffer, 0, in, sizeof (in));
Wim Taymans's avatar
Wim Taymans committed
113 114
    GST_BUFFER_DTS (buffer) = ts;
    GST_BUFFER_PTS (buffer) = ts;
115
    GST_BUFFER_DURATION (buffer) = tso;
Wim Taymans's avatar
Wim Taymans committed
116 117
    gst_mini_object_weak_ref (GST_MINI_OBJECT (buffer), buffer_dropped, NULL);
    GST_DEBUG ("created buffer: %p", buffer);
118 119 120 121 122 123 124 125 126 127 128 129

    if (!i)
      GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);

    inbuffers = g_list_append (inbuffers, buffer);

    /* hackish way to update the rtp header */
    in[1] = 0x00;
    in[3]++;                    /* seqnumber */
    in[7] += RTP_FRAME_SIZE;    /* inc. timestamp with framesize */
    ts += tso;
  }
130
  num_dropped = 0;
131 132 133 134

  return jitterbuffer;
}

Wim Taymans's avatar
Wim Taymans committed
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
static GstStateChangeReturn
start_jitterbuffer (GstElement * jitterbuffer)
{
  GstStateChangeReturn ret;
  GstClockTime now;
  GstClock *clock;

  clock = gst_element_get_clock (jitterbuffer);
  now = gst_clock_get_time (clock);
  gst_object_unref (clock);

  gst_element_set_base_time (jitterbuffer, now);
  ret = gst_element_set_state (jitterbuffer, GST_STATE_PLAYING);

  return ret;
}

152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
static void
cleanup_jitterbuffer (GstElement * jitterbuffer)
{
  GST_DEBUG ("cleanup_jitterbuffer");

  g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
  g_list_free (buffers);
  buffers = NULL;

  g_list_free (inbuffers);
  inbuffers = NULL;

  gst_pad_set_active (mysrcpad, FALSE);
  gst_pad_set_active (mysinkpad, FALSE);
  gst_check_teardown_src_pad (jitterbuffer);
  gst_check_teardown_sink_pad (jitterbuffer);
  gst_check_teardown_element (jitterbuffer);
}

static void
check_jitterbuffer_results (GstElement * jitterbuffer, gint num_buffers)
{
  GstBuffer *buffer;
  GList *node;
  GstClockTime ts = G_GUINT64_CONSTANT (0);
  GstClockTime tso = gst_util_uint64_scale (RTP_FRAME_SIZE, GST_SECOND, 8000);
Wim Taymans's avatar
Wim Taymans committed
178
  GstMapInfo map;
179 180 181
  guint16 prev_sn = 0, cur_sn;
  guint32 prev_ts = 0, cur_ts;

Wim Taymans's avatar
Wim Taymans committed
182 183
  /* sleep for twice the latency */
  g_usleep (400 * 1000);
184 185 186 187 188 189

  GST_INFO ("of %d buffer %d/%d received/dropped", num_buffers,
      g_list_length (buffers), num_dropped);
  /* if this fails, not all buffers have been processed */
  fail_unless_equals_int ((g_list_length (buffers) + num_dropped), num_buffers);

190 191 192 193
  /* check the buffer list */
  fail_unless_equals_int (g_list_length (buffers), num_buffers);
  for (node = buffers; node; node = g_list_next (node)) {
    fail_if ((buffer = (GstBuffer *) node->data) == NULL);
Wim Taymans's avatar
Wim Taymans committed
194 195
    fail_if (GST_BUFFER_PTS (buffer) != ts);
    fail_if (GST_BUFFER_DTS (buffer) != ts);
Wim Taymans's avatar
Wim Taymans committed
196 197 198 199 200
    gst_buffer_map (buffer, &map, GST_MAP_READ);
    cur_sn = ((guint16) map.data[2] << 8) | map.data[3];
    cur_ts = ((guint32) map.data[4] << 24) | ((guint32) map.data[5] << 16) |
        ((guint32) map.data[6] << 8) | map.data[7];
    gst_buffer_unmap (buffer, &map);
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220

    if (node != buffers) {
      fail_unless (cur_sn > prev_sn);
      fail_unless (cur_ts > prev_ts);

      prev_sn = cur_sn;
      prev_ts = cur_ts;
    }
    ts += tso;
  }
}

GST_START_TEST (test_push_forward_seq)
{
  GstElement *jitterbuffer;
  const guint num_buffers = 3;
  GstBuffer *buffer;
  GList *node;

  jitterbuffer = setup_jitterbuffer (num_buffers);
Wim Taymans's avatar
Wim Taymans committed
221 222
  fail_unless (start_jitterbuffer (jitterbuffer)
      == GST_STATE_CHANGE_SUCCESS, "could not set to playing");
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241

  /* push buffers: 0,1,2, */
  for (node = inbuffers; node; node = g_list_next (node)) {
    buffer = (GstBuffer *) node->data;
    fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
  }

  /* check the buffer list */
  check_jitterbuffer_results (jitterbuffer, num_buffers);

  /* cleanup */
  cleanup_jitterbuffer (jitterbuffer);
}

GST_END_TEST;

GST_START_TEST (test_push_backward_seq)
{
  GstElement *jitterbuffer;
242
  const guint num_buffers = 4;
243 244 245 246
  GstBuffer *buffer;
  GList *node;

  jitterbuffer = setup_jitterbuffer (num_buffers);
Wim Taymans's avatar
Wim Taymans committed
247 248
  fail_unless (start_jitterbuffer (jitterbuffer)
      == GST_STATE_CHANGE_SUCCESS, "could not set to playing");
249

250 251 252 253 254
  /* push buffers: 0,3,2,1 */
  buffer = (GstBuffer *) inbuffers->data;
  fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
  for (node = g_list_last (inbuffers); node != inbuffers;
      node = g_list_previous (node)) {
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
    buffer = (GstBuffer *) node->data;
    fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
  }

  /* check the buffer list */
  check_jitterbuffer_results (jitterbuffer, num_buffers);

  /* cleanup */
  cleanup_jitterbuffer (jitterbuffer);
}

GST_END_TEST;

GST_START_TEST (test_push_unordered)
{
  GstElement *jitterbuffer;
271
  const guint num_buffers = 4;
272 273 274
  GstBuffer *buffer;

  jitterbuffer = setup_jitterbuffer (num_buffers);
Wim Taymans's avatar
Wim Taymans committed
275 276
  fail_unless (start_jitterbuffer (jitterbuffer)
      == GST_STATE_CHANGE_SUCCESS, "could not set to playing");
277

278
  /* push buffers; 0,2,1,3 */
279 280 281 282 283 284
  buffer = (GstBuffer *) inbuffers->data;
  fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
  buffer = g_list_nth_data (inbuffers, 2);
  fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
  buffer = g_list_nth_data (inbuffers, 1);
  fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
285 286
  buffer = g_list_nth_data (inbuffers, 3);
  fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
287 288 289 290 291 292 293 294 295 296

  /* check the buffer list */
  check_jitterbuffer_results (jitterbuffer, num_buffers);

  /* cleanup */
  cleanup_jitterbuffer (jitterbuffer);
}

GST_END_TEST;

297 298 299 300 301 302 303 304 305
GST_START_TEST (test_basetime)
{
  GstElement *jitterbuffer;
  const guint num_buffers = 3;
  GstBuffer *buffer;
  GList *node;
  GstClockTime tso = gst_util_uint64_scale (RTP_FRAME_SIZE, GST_SECOND, 8000);

  jitterbuffer = setup_jitterbuffer (num_buffers);
Wim Taymans's avatar
Wim Taymans committed
306 307
  fail_unless (start_jitterbuffer (jitterbuffer)
      == GST_STATE_CHANGE_SUCCESS, "could not set to playing");
308 309 310 311 312 313 314

  /* push buffers: 2,1,0 */
  for (node = g_list_last (inbuffers); node; node = g_list_previous (node)) {
    buffer = (GstBuffer *) node->data;
    fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
  }

Wim Taymans's avatar
Wim Taymans committed
315 316
  /* sleep for twice the latency */
  g_usleep (400 * 1000);
317 318 319 320 321

  /* if this fails, not all buffers have been processed */
  fail_unless_equals_int ((g_list_length (buffers) + num_dropped), num_buffers);

  buffer = (GstBuffer *) buffers->data;
Wim Taymans's avatar
Wim Taymans committed
322 323
  fail_unless (GST_BUFFER_DTS (buffer) != (num_buffers * tso));
  fail_unless (GST_BUFFER_PTS (buffer) != (num_buffers * tso));
324 325 326 327 328 329 330

  /* cleanup */
  cleanup_jitterbuffer (jitterbuffer);
}

GST_END_TEST;

331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
static GstCaps *
request_pt_map (GstElement * jitterbuffer, guint pt)
{
  fail_unless (pt == 0);

  return gst_caps_from_string (RTP_CAPS_STRING);
}

GST_START_TEST (test_clear_pt_map)
{
  GstElement *jitterbuffer;
  const guint num_buffers = 10;
  gint i;
  GstBuffer *buffer;
  GList *node;

  jitterbuffer = setup_jitterbuffer (num_buffers);
  fail_unless (start_jitterbuffer (jitterbuffer)
      == GST_STATE_CHANGE_SUCCESS, "could not set to playing");

  g_signal_connect (jitterbuffer, "request-pt-map", (GCallback)
      request_pt_map, NULL);

  /* push buffers: 0,1,2, */
  for (node = inbuffers, i = 0; node && i < 3; node = g_list_next (node), i++) {
    buffer = (GstBuffer *) node->data;
    fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
  }

  g_usleep (400 * 1000);

  g_signal_emit_by_name (jitterbuffer, "clear-pt-map", NULL);

  for (; node && i < 10; node = g_list_next (node), i++) {
    buffer = (GstBuffer *) node->data;
    fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
  }

  /* check the buffer list */
  check_jitterbuffer_results (jitterbuffer, num_buffers);

  /* cleanup */
  cleanup_jitterbuffer (jitterbuffer);
}

GST_END_TEST;
377 378 379 380 381 382 383 384 385 386 387
static const guint payload_size = 160;
static const guint clock_rate = 8000;
static const guint pcmu_payload_type = 0;
static const guint test_ssrc = 0x01BADBAD;

typedef struct
{
  GstElement *jitter_buffer;
  GstPad *test_sink_pad, *test_src_pad;
  GstClock *clock;
  GAsyncQueue *buf_queue;
388 389
  GAsyncQueue *sink_event_queue;
  GAsyncQueue *src_event_queue;
390
  gint lost_event_count;
391
  gint rtx_event_count;
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
} TestData;

static GstCaps *
generate_caps (void)
{
  return gst_caps_new_simple ("application/x-rtp",
      "media", G_TYPE_STRING, "audio",
      "clock-rate", G_TYPE_INT, clock_rate,
      "encoding-name", G_TYPE_STRING, "PCMU",
      "payload", G_TYPE_INT, pcmu_payload_type,
      "ssrc", G_TYPE_UINT, test_ssrc, NULL);
}

static GstBuffer *
generate_test_buffer (GstClockTime gst_ts,
    gboolean marker_bit, guint seq_num, guint32 rtp_ts)
{
  GstBuffer *buf;
  guint8 *payload;
  guint i;
412
  GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
413 414

  buf = gst_rtp_buffer_new_allocate (payload_size, 0, 0);
415 416
  GST_BUFFER_DTS (buf) = gst_ts;
  GST_BUFFER_PTS (buf) = gst_ts;
417 418 419 420 421 422 423 424 425

  gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtp);
  gst_rtp_buffer_set_payload_type (&rtp, pcmu_payload_type);
  gst_rtp_buffer_set_marker (&rtp, marker_bit);
  gst_rtp_buffer_set_seq (&rtp, seq_num);
  gst_rtp_buffer_set_timestamp (&rtp, rtp_ts);
  gst_rtp_buffer_set_ssrc (&rtp, test_ssrc);

  payload = gst_rtp_buffer_get_payload (&rtp);
426 427 428
  for (i = 0; i < payload_size; i++)
    payload[i] = 0xff;

429 430
  gst_rtp_buffer_unmap (&rtp);

431 432 433 434
  return buf;
}

static GstFlowReturn
435
test_sink_pad_chain_cb (GstPad * pad, GstObject * parent, GstBuffer * buffer)
436 437 438 439 440 441 442
{
  TestData *data = gst_pad_get_element_private (pad);
  g_async_queue_push (data->buf_queue, buffer);
  return GST_FLOW_OK;
}

static gboolean
443
test_sink_pad_event_cb (GstPad * pad, GstObject * parent, GstEvent * event)
444 445 446
{
  TestData *data = gst_pad_get_element_private (pad);
  const GstStructure *structure = gst_event_get_structure (event);
447 448 449

  GST_DEBUG ("got event %" GST_PTR_FORMAT, event);

Wim Taymans's avatar
Wim Taymans committed
450
  if (strcmp (gst_structure_get_name (structure), "GstRTPPacketLost") == 0) {
451
    data->lost_event_count++;
Wim Taymans's avatar
Wim Taymans committed
452 453
    GST_DEBUG ("lost event count %d", data->lost_event_count);
  }
454

455 456 457 458 459 460 461 462 463 464 465 466 467 468
  g_async_queue_push (data->sink_event_queue, event);
  return TRUE;
}

static gboolean
test_src_pad_event_cb (GstPad * pad, GstObject * parent, GstEvent * event)
{
  TestData *data = gst_pad_get_element_private (pad);
  const GstStructure *structure = gst_event_get_structure (event);

  GST_DEBUG ("got event %" GST_PTR_FORMAT, event);

  if (structure
      && strcmp (gst_structure_get_name (structure),
Wim Taymans's avatar
Wim Taymans committed
469
          "GstRTPRetransmissionRequest") == 0) {
470
    data->rtx_event_count++;
Wim Taymans's avatar
Wim Taymans committed
471 472
    GST_DEBUG ("rtx event count %d", data->rtx_event_count);
  }
473 474

  g_async_queue_push (data->src_event_queue, event);
475 476 477 478 479 480 481
  return TRUE;
}

static void
setup_testharness (TestData * data)
{
  GstPad *jb_sink_pad, *jb_src_pad;
482 483
  GstSegment seg;
  GstMiniObject *obj;
484
  GstCaps *caps;
485

Wim Taymans's avatar
Wim Taymans committed
486
  /* create the testclock */
487 488 489 490
  data->clock = gst_test_clock_new ();
  g_assert (data->clock);
  gst_test_clock_set_time (GST_TEST_CLOCK (data->clock), 0);

Wim Taymans's avatar
Wim Taymans committed
491
  /* rig up the jitter buffer */
492
  data->jitter_buffer = gst_element_factory_make ("rtpjitterbuffer", NULL);
493 494 495 496 497 498
  g_assert (data->jitter_buffer);
  gst_element_set_clock (data->jitter_buffer, data->clock);
  g_object_set (data->jitter_buffer, "do-lost", TRUE, NULL);
  g_assert_cmpint (gst_element_set_state (data->jitter_buffer,
          GST_STATE_PLAYING), !=, GST_STATE_CHANGE_FAILURE);

499 500 501 502 503 504 505 506 507 508 509
  /* set up the buf and event queues */
  data->buf_queue =
      g_async_queue_new_full ((GDestroyNotify) gst_mini_object_unref);
  data->sink_event_queue =
      g_async_queue_new_full ((GDestroyNotify) gst_mini_object_unref);
  data->src_event_queue =
      g_async_queue_new_full ((GDestroyNotify) gst_mini_object_unref);

  data->lost_event_count = 0;
  data->rtx_event_count = 0;

Wim Taymans's avatar
Wim Taymans committed
510
  /* link in the test source-pad */
511
  data->test_src_pad = gst_pad_new ("src", GST_PAD_SRC);
512 513
  gst_pad_set_element_private (data->test_src_pad, data);
  gst_pad_set_event_function (data->test_src_pad, test_src_pad_event_cb);
514
  jb_sink_pad = gst_element_get_static_pad (data->jitter_buffer, "sink");
515 516 517 518
  g_assert_cmpint (gst_pad_link (data->test_src_pad, jb_sink_pad), ==,
      GST_PAD_LINK_OK);
  gst_object_unref (jb_sink_pad);

Wim Taymans's avatar
Wim Taymans committed
519
  /* link in the test sink-pad */
520
  data->test_sink_pad = gst_pad_new ("sink", GST_PAD_SINK);
521
  gst_pad_set_element_private (data->test_sink_pad, data);
522 523
  caps = generate_caps ();
  gst_pad_set_caps (data->test_sink_pad, caps);
524 525
  gst_pad_set_chain_function (data->test_sink_pad, test_sink_pad_chain_cb);
  gst_pad_set_event_function (data->test_sink_pad, test_sink_pad_event_cb);
526
  jb_src_pad = gst_element_get_static_pad (data->jitter_buffer, "src");
527 528 529 530
  g_assert_cmpint (gst_pad_link (jb_src_pad, data->test_sink_pad), ==,
      GST_PAD_LINK_OK);
  gst_object_unref (jb_src_pad);

531 532
  g_assert (gst_pad_set_active (data->test_src_pad, TRUE));
  g_assert (gst_pad_set_active (data->test_sink_pad, TRUE));
533 534 535 536 537

  gst_segment_init (&seg, GST_FORMAT_TIME);

  gst_pad_push_event (data->test_src_pad,
      gst_event_new_stream_start ("stream0"));
538
  gst_pad_set_caps (data->test_src_pad, caps);
539
  gst_pad_push_event (data->test_src_pad, gst_event_new_segment (&seg));
540
  gst_caps_unref (caps);
541

542 543 544 545 546 547
  obj = g_async_queue_pop (data->sink_event_queue);
  gst_mini_object_unref (obj);
  obj = g_async_queue_pop (data->sink_event_queue);
  gst_mini_object_unref (obj);
  obj = g_async_queue_pop (data->sink_event_queue);
  gst_mini_object_unref (obj);
548 549 550 551 552
}

static void
destroy_testharness (TestData * data)
{
Wim Taymans's avatar
Wim Taymans committed
553
  /* clean up */
554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570
  g_assert_cmpint (gst_element_set_state (data->jitter_buffer, GST_STATE_NULL),
      ==, GST_STATE_CHANGE_SUCCESS);
  gst_object_unref (data->jitter_buffer);
  data->jitter_buffer = NULL;

  gst_object_unref (data->test_src_pad);
  data->test_src_pad = NULL;

  gst_object_unref (data->test_sink_pad);
  data->test_sink_pad = NULL;

  gst_object_unref (data->clock);
  data->clock = NULL;

  g_async_queue_unref (data->buf_queue);
  data->buf_queue = NULL;

571 572 573 574
  g_async_queue_unref (data->sink_event_queue);
  data->sink_event_queue = NULL;
  g_async_queue_unref (data->src_event_queue);
  data->src_event_queue = NULL;
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589

  data->lost_event_count = 0;
}

static void
verify_lost_event (GstEvent * event, guint32 expected_seqnum,
    GstClockTime expected_timestamp, GstClockTime expected_duration,
    gboolean expected_late)
{
  const GstStructure *s = gst_event_get_structure (event);
  const GValue *value;
  guint32 seqnum;
  GstClockTime timestamp;
  GstClockTime duration;
  gboolean late;
590

591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606
  g_assert (gst_structure_get_uint (s, "seqnum", &seqnum));

  value = gst_structure_get_value (s, "timestamp");
  g_assert (value && G_VALUE_HOLDS_UINT64 (value));
  timestamp = g_value_get_uint64 (value);

  value = gst_structure_get_value (s, "duration");
  g_assert (value && G_VALUE_HOLDS_UINT64 (value));
  duration = g_value_get_uint64 (value);

  g_assert (gst_structure_get_boolean (s, "late", &late));

  g_assert_cmpint (seqnum, ==, expected_seqnum);
  g_assert_cmpint (timestamp, ==, expected_timestamp);
  g_assert_cmpint (duration, ==, expected_duration);
  g_assert (late == expected_late);
607 608

  gst_event_unref (event);
609 610
}

611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639
static void
verify_rtx_event (GstEvent * event, guint32 expected_seqnum,
    GstClockTime expected_timestamp, guint expected_delay,
    GstClockTime expected_spacing)
{
  const GstStructure *s = gst_event_get_structure (event);
  const GValue *value;
  guint32 seqnum;
  GstClockTime timestamp, spacing;
  guint delay;

  g_assert (gst_structure_get_uint (s, "seqnum", &seqnum));

  value = gst_structure_get_value (s, "running-time");
  g_assert (value && G_VALUE_HOLDS_UINT64 (value));
  timestamp = g_value_get_uint64 (value);

  value = gst_structure_get_value (s, "delay");
  g_assert (value && G_VALUE_HOLDS_UINT (value));
  delay = g_value_get_uint (value);

  value = gst_structure_get_value (s, "packet-spacing");
  g_assert (value && G_VALUE_HOLDS_UINT64 (value));
  spacing = g_value_get_uint64 (value);

  g_assert_cmpint (seqnum, ==, expected_seqnum);
  g_assert_cmpint (timestamp, ==, expected_timestamp);
  g_assert_cmpint (delay, ==, expected_delay);
  g_assert_cmpint (spacing, ==, expected_spacing);
640 641

  gst_event_unref (event);
642 643
}

644 645 646
GST_START_TEST (test_only_one_lost_event_on_large_gaps)
{
  TestData data;
647
  GstClockID id, test_id;
648 649 650 651
  GstBuffer *in_buf, *out_buf;
  GstEvent *out_event;
  gint jb_latency_ms = 200;
  guint buffer_size_ms = (payload_size * 1000) / clock_rate;
652
  GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
653 654 655 656

  setup_testharness (&data);

  g_object_set (data.jitter_buffer, "latency", jb_latency_ms, NULL);
Wim Taymans's avatar
Wim Taymans committed
657
  /* push the first buffer in */
658 659 660 661
  in_buf = generate_test_buffer (0 * GST_MSECOND, TRUE, 0, 0);
  gst_test_clock_set_time (GST_TEST_CLOCK (data.clock), 0);
  g_assert_cmpint (gst_pad_push (data.test_src_pad, in_buf), ==, GST_FLOW_OK);

Wim Taymans's avatar
Wim Taymans committed
662
  /* wait for the first buffer to be synced to timestamp + latency */
663
  gst_test_clock_wait_for_next_pending_id (GST_TEST_CLOCK (data.clock), &id);
664

Wim Taymans's avatar
Wim Taymans committed
665
  /* increase the time to timestamp + latency and release the wait */
666 667
  gst_test_clock_set_time (GST_TEST_CLOCK (data.clock),
      jb_latency_ms * GST_MSECOND);
668 669 670 671
  test_id = gst_test_clock_process_next_clock_id (GST_TEST_CLOCK (data.clock));
  g_assert (test_id == id);
  gst_clock_id_unref (test_id);
  gst_clock_id_unref (id);
672

Wim Taymans's avatar
Wim Taymans committed
673
  /* check for the buffer coming out that was pushed in */
674
  out_buf = g_async_queue_pop (data.buf_queue);
675
  g_assert (out_buf != NULL);
Wim Taymans's avatar
Wim Taymans committed
676 677
  g_assert_cmpint (GST_BUFFER_DTS (out_buf), ==, 0);
  g_assert_cmpint (GST_BUFFER_PTS (out_buf), ==, 0);
678
  gst_buffer_unref (out_buf);
679

Wim Taymans's avatar
Wim Taymans committed
680
  /* move time ahead 10 seconds */
681 682
  gst_test_clock_set_time (GST_TEST_CLOCK (data.clock), 10 * GST_SECOND);

Wim Taymans's avatar
Wim Taymans committed
683
  /* wait a bit */
684 685
  g_usleep (G_USEC_PER_SEC / 10);

Wim Taymans's avatar
Wim Taymans committed
686
  /* check that no buffers have been pushed out and no pending waits */
687 688 689 690
  g_assert_cmpint (g_async_queue_length (data.buf_queue), ==, 0);
  g_assert (gst_test_clock_peek_next_pending_id (GST_TEST_CLOCK (data.clock),
          &id) == FALSE);

Wim Taymans's avatar
Wim Taymans committed
691
  /* a buffer now arrives perfectly on time */
692 693 694 695
  in_buf = generate_test_buffer (10 * GST_SECOND, FALSE, 500, 500 * 160);
  gst_test_clock_set_time (GST_TEST_CLOCK (data.clock), 10 * GST_SECOND);
  g_assert_cmpint (gst_pad_push (data.test_src_pad, in_buf), ==, GST_FLOW_OK);

Wim Taymans's avatar
Wim Taymans committed
696
  /* release the wait */
697 698 699 700
  gst_test_clock_wait_for_next_pending_id (GST_TEST_CLOCK (data.clock), &id);
  gst_test_clock_advance_time (GST_TEST_CLOCK (data.clock), GST_MSECOND * 20);
  test_id = gst_test_clock_process_next_clock_id (GST_TEST_CLOCK (data.clock));
  g_assert (id == test_id);
701 702
  gst_clock_id_unref (test_id);
  gst_clock_id_unref (id);
703

Wim Taymans's avatar
Wim Taymans committed
704
  /* we should now receive a packet-lost-event for buffers 1 through 489 */
705
  out_event = g_async_queue_pop (data.sink_event_queue);
706 707
  g_assert (out_event != NULL);
  g_assert_cmpint (data.lost_event_count, ==, 1);
708
  verify_lost_event (out_event, 1, 1 * GST_MSECOND * 20, GST_MSECOND * 20 * 490,
709 710
      TRUE);

Wim Taymans's avatar
Wim Taymans committed
711
  /* churn through sync_times until the new buffer gets pushed out */
712 713
  while (g_async_queue_length (data.buf_queue) < 1) {
    if (gst_test_clock_peek_next_pending_id (GST_TEST_CLOCK (data.clock), &id)) {
714 715 716
      GstClockTime t = gst_clock_id_get_time (id);
      if (t > gst_clock_get_time (data.clock)) {
        gst_test_clock_set_time (GST_TEST_CLOCK (data.clock), t);
717
      }
718 719 720 721
      test_id =
          gst_test_clock_process_next_clock_id (GST_TEST_CLOCK (data.clock));
      gst_clock_id_unref (test_id);
      gst_clock_id_unref (id);
722 723 724
    }
  }

725
  out_buf = g_async_queue_pop (data.buf_queue);
726 727
  g_assert (out_buf != NULL);
  g_assert (GST_BUFFER_FLAG_IS_SET (out_buf, GST_BUFFER_FLAG_DISCONT));
728 729 730
  gst_rtp_buffer_map (out_buf, GST_MAP_READ, &rtp);
  g_assert_cmpint (gst_rtp_buffer_get_seq (&rtp), ==, 500);
  gst_rtp_buffer_unmap (&rtp);
Wim Taymans's avatar
Wim Taymans committed
731 732
  g_assert_cmpint (GST_BUFFER_DTS (out_buf), ==, (10 * GST_SECOND));
  g_assert_cmpint (GST_BUFFER_PTS (out_buf), ==, (10 * GST_SECOND));
733
  gst_buffer_unref (out_buf);
734

Wim Taymans's avatar
Wim Taymans committed
735 736
  /* we get as many lost events as the the number of buffers the jitterbuffer
   * is able to wait for (+ the one we already got) */
737
  g_assert_cmpint (data.lost_event_count, ==, jb_latency_ms / buffer_size_ms);
738 739 740 741 742 743 744 745 746

  destroy_testharness (&data);
}

GST_END_TEST;

GST_START_TEST (test_two_lost_one_arrives_in_time)
{
  TestData data;
747
  GstClockID id, test_id;
748 749
  GstBuffer *in_buf, *out_buf;
  GstEvent *out_event;
750 751
  gint jb_latency_ms = 100;
  GstClockTime buffer_time, now;
752
  gint b;
753
  GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
754 755 756 757 758

  setup_testharness (&data);

  g_object_set (data.jitter_buffer, "latency", jb_latency_ms, NULL);

Wim Taymans's avatar
Wim Taymans committed
759
  /* push the first buffer in */
760 761 762
  in_buf = generate_test_buffer (0 * GST_MSECOND, TRUE, 0, 0);
  gst_test_clock_set_time (GST_TEST_CLOCK (data.clock), 0);
  g_assert_cmpint (gst_pad_push (data.test_src_pad, in_buf), ==, GST_FLOW_OK);
763 764 765
  gst_test_clock_wait_for_next_pending_id (GST_TEST_CLOCK (data.clock), &id);
  now = jb_latency_ms * GST_MSECOND;
  gst_test_clock_set_time (GST_TEST_CLOCK (data.clock), now);
766 767 768 769
  test_id = gst_test_clock_process_next_clock_id (GST_TEST_CLOCK (data.clock));
  g_assert (test_id == id);
  gst_clock_id_unref (test_id);
  gst_clock_id_unref (id);
770
  out_buf = g_async_queue_pop (data.buf_queue);
771 772
  g_assert (out_buf != NULL);

Wim Taymans's avatar
Wim Taymans committed
773
  /* push some buffers arriving in perfect time! */
774 775 776
  for (b = 1; b < 3; b++) {
    buffer_time = b * GST_MSECOND * 20;
    in_buf = generate_test_buffer (buffer_time, TRUE, b, b * 160);
777
    gst_test_clock_set_time (GST_TEST_CLOCK (data.clock), now + buffer_time);
778
    g_assert_cmpint (gst_pad_push (data.test_src_pad, in_buf), ==, GST_FLOW_OK);
779
    gst_buffer_unref (out_buf);
780

Wim Taymans's avatar
Wim Taymans committed
781
    /* check for the buffer coming out that was pushed in */
782
    out_buf = g_async_queue_pop (data.buf_queue);
783
    g_assert (out_buf != NULL);
Wim Taymans's avatar
Wim Taymans committed
784 785
    g_assert_cmpint (GST_BUFFER_DTS (out_buf), ==, buffer_time);
    g_assert_cmpint (GST_BUFFER_PTS (out_buf), ==, buffer_time);
786
  }
787
  gst_buffer_unref (out_buf);
788

Wim Taymans's avatar
Wim Taymans committed
789
  /* hop over 2 packets and make another one (gap of 2) */
790 791 792 793 794
  b = 5;
  buffer_time = b * GST_MSECOND * 20;
  in_buf = generate_test_buffer (buffer_time, TRUE, b, b * 160);
  g_assert_cmpint (gst_pad_push (data.test_src_pad, in_buf), ==, GST_FLOW_OK);

Wim Taymans's avatar
Wim Taymans committed
795 796
  /* verify that the jitterbuffer now wait for the latest moment it can push */
  /* the first lost buffer (buffer 3) out on (buffer-timestamp (60) + latency (10) = 70) */
797 798
  gst_test_clock_wait_for_next_pending_id (GST_TEST_CLOCK (data.clock), &id);
  g_assert_cmpint (gst_clock_id_get_time (id), ==,
799 800
      (3 * GST_MSECOND * 20) + (jb_latency_ms * GST_MSECOND));

Wim Taymans's avatar
Wim Taymans committed
801
  /* let the time expire... */
802 803
  gst_test_clock_set_time (GST_TEST_CLOCK (data.clock),
      gst_clock_id_get_time (id));
804 805 806 807
  test_id = gst_test_clock_process_next_clock_id (GST_TEST_CLOCK (data.clock));
  g_assert (test_id == id);
  gst_clock_id_unref (test_id);
  gst_clock_id_unref (id);
808

Wim Taymans's avatar
Wim Taymans committed
809
  /* we should now receive a packet-lost-event for buffer 3 */
810
  out_event = g_async_queue_pop (data.sink_event_queue);
811 812 813 814 815
  g_assert (out_event != NULL);
  g_assert_cmpint (data.lost_event_count, ==, 1);
  verify_lost_event (out_event, 3, 3 * GST_MSECOND * 20, GST_MSECOND * 20,
      FALSE);

Wim Taymans's avatar
Wim Taymans committed
816
  /* buffer 4 now arrives just in time (time is 70, buffer 4 expires at 90) */
817 818 819 820 821
  b = 4;
  buffer_time = b * GST_MSECOND * 20;
  in_buf = generate_test_buffer (buffer_time, TRUE, b, b * 160);
  g_assert_cmpint (gst_pad_push (data.test_src_pad, in_buf), ==, GST_FLOW_OK);

Wim Taymans's avatar
Wim Taymans committed
822
  /* verify that buffer 4 made it through! */
823
  out_buf = g_async_queue_pop (data.buf_queue);
824 825
  g_assert (out_buf != NULL);
  g_assert (GST_BUFFER_FLAG_IS_SET (out_buf, GST_BUFFER_FLAG_DISCONT));
826 827 828
  gst_rtp_buffer_map (out_buf, GST_MAP_READ, &rtp);
  g_assert_cmpint (gst_rtp_buffer_get_seq (&rtp), ==, 4);
  gst_rtp_buffer_unmap (&rtp);
829
  gst_buffer_unref (out_buf);
830

Wim Taymans's avatar
Wim Taymans committed
831
  /* and see that buffer 5 now arrives in a normal fashion */
832
  out_buf = g_async_queue_pop (data.buf_queue);
833 834
  g_assert (out_buf != NULL);
  g_assert (!GST_BUFFER_FLAG_IS_SET (out_buf, GST_BUFFER_FLAG_DISCONT));
835 836 837
  gst_rtp_buffer_map (out_buf, GST_MAP_READ, &rtp);
  g_assert_cmpint (gst_rtp_buffer_get_seq (&rtp), ==, 5);
  gst_rtp_buffer_unmap (&rtp);
838
  gst_buffer_unref (out_buf);
839

Wim Taymans's avatar
Wim Taymans committed
840
  /* should still have only seen 1 packet lost event */
841 842 843 844 845 846 847 848 849 850
  g_assert_cmpint (data.lost_event_count, ==, 1);

  destroy_testharness (&data);
}

GST_END_TEST;

GST_START_TEST (test_late_packets_still_makes_lost_events)
{
  TestData data;
851
  GstClockID id, test_id;
852 853 854 855 856
  GstBuffer *in_buf, *out_buf;
  GstEvent *out_event;
  gint jb_latency_ms = 10;
  GstClockTime buffer_time;
  gint b;
857
  GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
858 859 860 861 862 863 864

  setup_testharness (&data);

  g_object_set (data.jitter_buffer, "latency", jb_latency_ms, NULL);

  gst_test_clock_set_time (GST_TEST_CLOCK (data.clock), 10 * GST_SECOND);

Wim Taymans's avatar
Wim Taymans committed
865
  /* push the first buffer in */
866 867 868
  in_buf = generate_test_buffer (0 * GST_MSECOND, TRUE, 0, 0);
  g_assert_cmpint (gst_pad_push (data.test_src_pad, in_buf), ==, GST_FLOW_OK);

869
  gst_test_clock_wait_for_next_pending_id (GST_TEST_CLOCK (data.clock), &id);
870 871 872 873
  test_id = gst_test_clock_process_next_clock_id (GST_TEST_CLOCK (data.clock));
  g_assert (test_id == id);
  gst_clock_id_unref (id);
  gst_clock_id_unref (test_id);
874
  out_buf = g_async_queue_pop (data.buf_queue);
875 876
  g_assert (out_buf != NULL);

Wim Taymans's avatar
Wim Taymans committed
877
  /* push some buffers in! */
878 879 880 881
  for (b = 1; b < 3; b++) {
    buffer_time = b * GST_MSECOND * 20;
    in_buf = generate_test_buffer (buffer_time, TRUE, b, b * 160);
    g_assert_cmpint (gst_pad_push (data.test_src_pad, in_buf), ==, GST_FLOW_OK);
882
    gst_buffer_unref (out_buf);
883

Wim Taymans's avatar
Wim Taymans committed
884
    /* check for the buffer coming out that was pushed in */
885
    out_buf = g_async_queue_pop (data.buf_queue);
886
    g_assert (out_buf != NULL);
Wim Taymans's avatar
Wim Taymans committed
887 888
    g_assert_cmpint (GST_BUFFER_DTS (out_buf), ==, buffer_time);
    g_assert_cmpint (GST_BUFFER_PTS (out_buf), ==, buffer_time);
889
  }
890
  gst_buffer_unref (out_buf);
891

Wim Taymans's avatar
Wim Taymans committed
892
  /* hop over 2 packets and make another one (gap of 2) */
893 894 895 896 897
  b = 5;
  buffer_time = b * GST_MSECOND * 20;
  in_buf = generate_test_buffer (buffer_time, TRUE, b, b * 160);
  g_assert_cmpint (gst_pad_push (data.test_src_pad, in_buf), ==, GST_FLOW_OK);

Wim Taymans's avatar
Wim Taymans committed
898
  /* we should now receive a packet-lost-event for buffer 3 and 4 */
899
  out_event = g_async_queue_pop (data.sink_event_queue);
900 901 902 903 904
  g_assert (out_event != NULL);
  g_assert_cmpint (data.lost_event_count, ==, 1);
  verify_lost_event (out_event, 3, 3 * GST_MSECOND * 20, GST_MSECOND * 20 * 2,
      TRUE);

Wim Taymans's avatar
Wim Taymans committed
905
  /* verify that buffer 5 made it through! */
906
  out_buf = g_async_queue_pop (data.buf_queue);
907 908
  g_assert (out_buf != NULL);
  g_assert (GST_BUFFER_FLAG_IS_SET (out_buf, GST_BUFFER_FLAG_DISCONT));
909 910 911
  gst_rtp_buffer_map (out_buf, GST_MAP_READ, &rtp);
  g_assert_cmpint (gst_rtp_buffer_get_seq (&rtp), ==, 5);
  gst_rtp_buffer_unmap (&rtp);
912
  gst_buffer_unref (out_buf);
913

Wim Taymans's avatar
Wim Taymans committed
914
  /* should still have only seen 1 packet lost event */
915 916 917 918 919 920 921 922 923 924
  g_assert_cmpint (data.lost_event_count, ==, 1);

  destroy_testharness (&data);
}

GST_END_TEST;

GST_START_TEST (test_all_packets_are_timestamped_zero)
{
  TestData data;
925
  GstClockID id, test_id;
926 927 928 929
  GstBuffer *in_buf, *out_buf;
  GstEvent *out_event;
  gint jb_latency_ms = 10;
  gint b;
930
  GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
931 932 933 934 935 936 937

  setup_testharness (&data);

  g_object_set (data.jitter_buffer, "latency", jb_latency_ms, NULL);

  gst_test_clock_set_time (GST_TEST_CLOCK (data.clock), 10 * GST_SECOND);

Wim Taymans's avatar
Wim Taymans committed
938
  /* push the first buffer in */
939 940 941
  in_buf = generate_test_buffer (0 * GST_MSECOND, TRUE, 0, 0);
  g_assert_cmpint (gst_pad_push (data.test_src_pad, in_buf), ==, GST_FLOW_OK);

942
  gst_test_clock_wait_for_next_pending_id (GST_TEST_CLOCK (data.clock), &id);
943 944 945 946
  test_id = gst_test_clock_process_next_clock_id (GST_TEST_CLOCK (data.clock));
  g_assert (test_id == id);
  gst_clock_id_unref (test_id);
  gst_clock_id_unref (id);
947
  out_buf = g_async_queue_pop (data.buf_queue);
948 949
  g_assert (out_buf != NULL);

Wim Taymans's avatar
Wim Taymans committed
950
  /* push some buffers in! */
951 952 953
  for (b = 1; b < 3; b++) {
    in_buf = generate_test_buffer (0, TRUE, b, 0);
    g_assert_cmpint (gst_pad_push (data.test_src_pad, in_buf), ==, GST_FLOW_OK);
954
    gst_buffer_unref (out_buf);
955

Wim Taymans's avatar
Wim Taymans committed
956
    /* check for the buffer coming out that was pushed in */
957
    out_buf = g_async_queue_pop (data.buf_queue);
958
    g_assert (out_buf != NULL);
Wim Taymans's avatar
Wim Taymans committed
959 960
    g_assert_cmpint (GST_BUFFER_DTS (out_buf), ==, 0);
    g_assert_cmpint (GST_BUFFER_PTS (out_buf), ==, 0);
961
  }
962
  gst_buffer_unref (out_buf);
963

Wim Taymans's avatar
Wim Taymans committed
964
  /* hop over 2 packets and make another one (gap of 2) */
965 966 967 968
  b = 5;
  in_buf = generate_test_buffer (0, TRUE, b, 0);
  g_assert_cmpint (gst_pad_push (data.test_src_pad, in_buf), ==, GST_FLOW_OK);

Wim Taymans's avatar
Wim Taymans committed
969
  /* we should now receive a packet-lost-event for buffer 3 and 4 */
970
  out_event = g_async_queue_pop (data.sink_event_queue);
971
  g_assert (out_event != NULL);
972 973
  verify_lost_event (out_event, 3, 0, 0, FALSE);

974
  out_event = g_async_queue_pop (data.sink_event_queue);
975 976 977 978
  g_assert (out_event != NULL);
  verify_lost_event (out_event, 4, 0, 0, FALSE);

  g_assert_cmpint (data.lost_event_count, ==, 2);
979

Wim Taymans's avatar
Wim Taymans committed
980
  /* verify that buffer 5 made it through! */
981
  out_buf = g_async_queue_pop (data.buf_queue);
982 983
  g_assert (out_buf != NULL);
  g_assert (GST_BUFFER_FLAG_IS_SET (out_buf, GST_BUFFER_FLAG_DISCONT));
984 985 986
  gst_rtp_buffer_map (out_buf, GST_MAP_READ, &rtp);
  g_assert_cmpint (gst_rtp_buffer_get_seq (&rtp), ==, 5);
  gst_rtp_buffer_unmap (&rtp);
987
  gst_buffer_unref (out_buf);
988

Wim Taymans's avatar
Wim Taymans committed
989
  /* should still have only seen 2 packet lost events */
990
  g_assert_cmpint (data.lost_event_count, ==, 2);
991 992 993 994 995

  destroy_testharness (&data);
}

GST_END_TEST;
996

997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017
GST_START_TEST (test_rtx_expected_next)
{
  TestData data;
  GstClockID id, tid;
  GstBuffer *in_buf, *out_buf;
  GstEvent *out_event;
  gint jb_latency_ms = 200;

  setup_testharness (&data);
  g_object_set (data.jitter_buffer, "do-retransmission", TRUE, NULL);
  g_object_set (data.jitter_buffer, "latency", jb_latency_ms, NULL);
  g_object_set (data.jitter_buffer, "rtx-retry-period", 120, NULL);

  gst_test_clock_set_time (GST_TEST_CLOCK (data.clock), 0);

  /* push the first buffer in */
  in_buf = generate_test_buffer (0 * GST_MSECOND, TRUE, 0, 0);
  g_assert_cmpint (gst_pad_push (data.test_src_pad, in_buf), ==, GST_FLOW_OK);

  gst_test_clock_set_time (GST_TEST_CLOCK (data.clock), 20 * GST_MSECOND);

1018
  gst_test_clock_wait_for_next_pending_id (GST_TEST_CLOCK (data.clock), &id);
1019
  gst_clock_id_unref (id);
1020

1021 1022 1023 1024 1025 1026 1027
  /* put second buffer, the jitterbuffer should now know that the packet spacing
   * is 20ms and should ask for retransmission of seqnum 2 in 20ms */
  in_buf = generate_test_buffer (20 * GST_MSECOND, TRUE, 1, 160);
  g_assert_cmpint (gst_pad_push (data.test_src_pad, in_buf), ==, GST_FLOW_OK);

  gst_test_clock_wait_for_next_pending_id (GST_TEST_CLOCK (data.clock), &id);
  gst_test_clock_set_time (GST_TEST_CLOCK (data.clock), 60 * GST_MSECOND);
1028 1029 1030 1031
  tid = gst_test_clock_process_next_clock_id (GST_TEST_CLOCK (data.clock));
  g_assert (tid == id);
  gst_clock_id_unref (tid);
  gst_clock_id_unref (id);
1032

Wim Taymans's avatar