rtpmux.c 20.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/* GStreamer
 *
 * unit test for rtpmux elements
 *
 * Copyright 2009 Collabora Ltd.
 *  @author: Olivier Crete <olivier.crete@collabora.co.uk>
 * Copyright 2009 Nokia Corp.
 *
 * 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/gstharness.h>
27 28 29 30 31 32 33 34 35 36 37 38 39
#include <gst/rtp/gstrtpbuffer.h>
#include <gst/gst.h>

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"));

40 41
typedef void (*check_cb) (GstPad * pad, int i);

42
static gboolean
Olivier Crête's avatar
Olivier Crête committed
43
query_func (GstPad * pad, GstObject * noparent, GstQuery * query)
44
{
Olivier Crête's avatar
Olivier Crête committed
45 46 47 48 49 50 51 52 53
  switch (GST_QUERY_TYPE (query)) {
    case GST_QUERY_CAPS:
    {
      GstCaps **caps = g_object_get_data (G_OBJECT (pad), "caps");

      fail_unless (caps != NULL && *caps != NULL);
      gst_query_set_caps_result (query, *caps);
      break;
    }
Olivier Crête's avatar
Olivier Crête committed
54 55 56
    case GST_QUERY_ACCEPT_CAPS:
      gst_query_set_accept_caps_result (query, TRUE);
      break;
Olivier Crête's avatar
Olivier Crête committed
57 58 59
    default:
      break;
  }
60 61 62 63

  return TRUE;
}

64 65 66 67 68 69 70 71 72
static GstCaps *
remove_ssrc_from_caps (GstCaps * caps)
{
  GstCaps *copy = gst_caps_copy (caps);
  GstStructure *s = gst_caps_get_structure (copy, 0);
  gst_structure_remove_field (s, "ssrc");
  return copy;
}

73
static gboolean
Olivier Crête's avatar
Olivier Crête committed
74
event_func (GstPad * pad, GstObject * noparent, GstEvent * event)
75
{
Olivier Crête's avatar
Olivier Crête committed
76 77 78 79 80
  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_CAPS:
    {
      GstCaps *caps;
      GstCaps **caps2 = g_object_get_data (G_OBJECT (pad), "caps");
81 82
      GstCaps *caps_no_ssrc;
      GstCaps *caps2_no_ssrc;
Olivier Crête's avatar
Olivier Crête committed
83 84

      gst_event_parse_caps (event, &caps);
85 86 87
      caps_no_ssrc = remove_ssrc_from_caps (caps);
      caps2_no_ssrc = remove_ssrc_from_caps (*caps2);

Olivier Crête's avatar
Olivier Crête committed
88
      fail_unless (caps2 != NULL && *caps2 != NULL);
Olivier Crête's avatar
Olivier Crête committed
89 90
      fail_unless (gst_caps_is_fixed (caps));
      fail_unless (gst_caps_is_fixed (*caps2));
91 92 93 94

      fail_unless (gst_caps_is_equal_fixed (caps_no_ssrc, caps2_no_ssrc));
      gst_caps_unref (caps_no_ssrc);
      gst_caps_unref (caps2_no_ssrc);
Olivier Crête's avatar
Olivier Crête committed
95 96 97 98 99
      break;
    }
    default:
      break;
  }
100

Olivier Crête's avatar
Olivier Crête committed
101 102
  gst_event_unref (event);

103 104 105
  return TRUE;
}

106
static void
107 108
test_basic (const gchar * elem_name, const gchar * sink2, int count,
    check_cb cb)
109 110 111 112 113 114 115 116 117 118 119 120
{
  GstElement *rtpmux = NULL;
  GstPad *reqpad1 = NULL;
  GstPad *reqpad2 = NULL;
  GstPad *src1 = NULL;
  GstPad *src2 = NULL;
  GstPad *sink = NULL;
  GstBuffer *inbuf = NULL;
  GstCaps *src1caps = NULL;
  GstCaps *src2caps = NULL;
  GstCaps *sinkcaps = NULL;
  GstCaps *caps;
Olivier Crête's avatar
Olivier Crête committed
121
  GstSegment segment;
122 123 124 125 126 127
  int i;

  rtpmux = gst_check_setup_element (elem_name);

  reqpad1 = gst_element_get_request_pad (rtpmux, "sink_1");
  fail_unless (reqpad1 != NULL);
128
  reqpad2 = gst_element_get_request_pad (rtpmux, sink2);
129 130 131 132 133 134 135
  fail_unless (reqpad2 != NULL);
  sink = gst_check_setup_sink_pad_by_name (rtpmux, &sinktemplate, "src");

  src1 = gst_pad_new_from_static_template (&srctemplate, "src");
  src2 = gst_pad_new_from_static_template (&srctemplate, "src");
  fail_unless (gst_pad_link (src1, reqpad1) == GST_PAD_LINK_OK);
  fail_unless (gst_pad_link (src2, reqpad2) == GST_PAD_LINK_OK);
Olivier Crête's avatar
Olivier Crête committed
136 137 138
  gst_pad_set_query_function (src1, query_func);
  gst_pad_set_query_function (src2, query_func);
  gst_pad_set_query_function (sink, query_func);
139
  gst_pad_set_event_function (sink, event_func);
140 141 142 143 144 145 146 147 148 149 150
  g_object_set_data (G_OBJECT (src1), "caps", &src1caps);
  g_object_set_data (G_OBJECT (src2), "caps", &src2caps);
  g_object_set_data (G_OBJECT (sink), "caps", &sinkcaps);

  src1caps = gst_caps_new_simple ("application/x-rtp",
      "clock-rate", G_TYPE_INT, 1, "ssrc", G_TYPE_UINT, 11, NULL);
  src2caps = gst_caps_new_simple ("application/x-rtp",
      "clock-rate", G_TYPE_INT, 2, "ssrc", G_TYPE_UINT, 12, NULL);
  sinkcaps = gst_caps_new_simple ("application/x-rtp",
      "clock-rate", G_TYPE_INT, 3, "ssrc", G_TYPE_UINT, 13, NULL);

Olivier Crête's avatar
Olivier Crête committed
151
  caps = gst_pad_peer_query_caps (src1, NULL);
152 153 154 155
  fail_unless (gst_caps_is_empty (caps));
  gst_caps_unref (caps);

  gst_caps_set_simple (src2caps, "clock-rate", G_TYPE_INT, 3, NULL);
Olivier Crête's avatar
Olivier Crête committed
156
  caps = gst_pad_peer_query_caps (src1, NULL);
157 158 159 160 161 162 163 164 165 166 167
  gst_caps_unref (caps);

  g_object_set (rtpmux, "seqnum-offset", 100, "timestamp-offset", 1000,
      "ssrc", 55, NULL);

  fail_unless (gst_element_set_state (rtpmux,
          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
  gst_pad_set_active (sink, TRUE);
  gst_pad_set_active (src1, TRUE);
  gst_pad_set_active (src2, TRUE);

168 169 170 171 172
  fail_unless (gst_pad_push_event (src1,
          gst_event_new_stream_start ("stream1")));
  fail_unless (gst_pad_push_event (src2,
          gst_event_new_stream_start ("stream2")));

173
  gst_caps_set_simple (sinkcaps,
174 175
      "payload", G_TYPE_INT, 98, "seqnum-offset", G_TYPE_UINT, 100,
      "timestamp-offset", G_TYPE_UINT, 1000, "ssrc", G_TYPE_UINT, 66, NULL);
176 177
  caps = gst_caps_new_simple ("application/x-rtp",
      "payload", G_TYPE_INT, 98, "clock-rate", G_TYPE_INT, 3,
178
      "seqnum-offset", G_TYPE_UINT, 56, "timestamp-offset", G_TYPE_UINT, 57,
179 180
      "ssrc", G_TYPE_UINT, 66, NULL);
  fail_unless (gst_pad_set_caps (src1, caps));
181 182 183 184
  gst_caps_unref (caps);

  caps = gst_pad_peer_query_caps (sink, NULL);
  fail_if (gst_caps_is_empty (caps));
185

Olivier Crête's avatar
Olivier Crête committed
186 187 188 189 190 191
  gst_segment_init (&segment, GST_FORMAT_TIME);
  segment.start = 100000;
  fail_unless (gst_pad_push_event (src1, gst_event_new_segment (&segment)));
  segment.start = 0;
  fail_unless (gst_pad_push_event (src2, gst_event_new_segment (&segment)));

192

193
  for (i = 0; i < count; i++) {
Olivier Crête's avatar
Olivier Crête committed
194 195
    GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;

196
    inbuf = gst_rtp_buffer_new_allocate (10, 0, 0);
Olivier Crête's avatar
Olivier Crête committed
197
    GST_BUFFER_PTS (inbuf) = i * 1000 + 100000;
198
    GST_BUFFER_DURATION (inbuf) = 1000;
Olivier Crête's avatar
Olivier Crête committed
199 200 201 202 203 204 205 206 207

    gst_rtp_buffer_map (inbuf, GST_MAP_WRITE, &rtpbuffer);

    gst_rtp_buffer_set_version (&rtpbuffer, 2);
    gst_rtp_buffer_set_payload_type (&rtpbuffer, 98);
    gst_rtp_buffer_set_ssrc (&rtpbuffer, 44);
    gst_rtp_buffer_set_timestamp (&rtpbuffer, 200 + i);
    gst_rtp_buffer_set_seq (&rtpbuffer, 2000 + i);
    gst_rtp_buffer_unmap (&rtpbuffer);
208 209
    fail_unless (gst_pad_push (src1, inbuf) == GST_FLOW_OK);

210
    if (buffers)
Olivier Crête's avatar
Olivier Crête committed
211 212
      fail_unless (GST_BUFFER_PTS (buffers->data) == i * 1000, "%lld",
          GST_BUFFER_PTS (buffers->data));
213

214 215
    cb (src2, i);

216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
    g_list_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
    g_list_free (buffers);
    buffers = NULL;
  }


  gst_pad_set_active (sink, FALSE);
  gst_pad_set_active (src1, FALSE);
  gst_pad_set_active (src2, FALSE);
  fail_unless (gst_element_set_state (rtpmux,
          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
  gst_check_teardown_pad_by_name (rtpmux, "src");
  gst_object_unref (reqpad1);
  gst_object_unref (reqpad2);
  gst_check_teardown_pad_by_name (rtpmux, "sink_1");
231
  gst_check_teardown_pad_by_name (rtpmux, sink2);
232 233 234 235 236 237 238 239 240 241 242
  gst_element_release_request_pad (rtpmux, reqpad1);
  gst_element_release_request_pad (rtpmux, reqpad2);

  gst_caps_unref (caps);
  gst_caps_replace (&src1caps, NULL);
  gst_caps_replace (&src2caps, NULL);
  gst_caps_replace (&sinkcaps, NULL);

  gst_check_teardown_element (rtpmux);
}

243
static void
244 245
basic_check_cb (GstPad * pad, int i)
{
Olivier Crête's avatar
Olivier Crête committed
246
  GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;
247
  fail_unless (buffers && g_list_length (buffers) == 1);
Olivier Crête's avatar
Olivier Crête committed
248 249

  gst_rtp_buffer_map (buffers->data, GST_MAP_READ, &rtpbuffer);
250
  fail_unless_equals_int (55, gst_rtp_buffer_get_ssrc (&rtpbuffer));
251 252 253
  fail_unless_equals_int64 (200 - 57 + 1000 + i,
      gst_rtp_buffer_get_timestamp (&rtpbuffer));
  fail_unless_equals_int (100 + 1 + i, gst_rtp_buffer_get_seq (&rtpbuffer));
Olivier Crête's avatar
Olivier Crête committed
254
  gst_rtp_buffer_unmap (&rtpbuffer);
255 256 257
}


258 259
GST_START_TEST (test_rtpmux_basic)
{
260
  test_basic ("rtpmux", "sink_2", 10, basic_check_cb);
261 262 263 264 265 266
}

GST_END_TEST;

GST_START_TEST (test_rtpdtmfmux_basic)
{
267
  test_basic ("rtpdtmfmux", "sink_2", 10, basic_check_cb);
268 269 270 271
}

GST_END_TEST;

272
static void
273 274
lock_check_cb (GstPad * pad, int i)
{
275
  GstBuffer *inbuf;
276 277 278 279

  if (i % 2) {
    fail_unless (buffers == NULL);
  } else {
Olivier Crête's avatar
Olivier Crête committed
280 281
    GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;

282
    fail_unless (buffers && g_list_length (buffers) == 1);
Olivier Crête's avatar
Olivier Crête committed
283
    gst_rtp_buffer_map (buffers->data, GST_MAP_READ, &rtpbuffer);
284
    fail_unless_equals_int (55, gst_rtp_buffer_get_ssrc (&rtpbuffer));
285 286 287
    fail_unless_equals_int64 (200 - 57 + 1000 + i,
        gst_rtp_buffer_get_timestamp (&rtpbuffer));
    fail_unless_equals_int (100 + 1 + i, gst_rtp_buffer_get_seq (&rtpbuffer));
Olivier Crête's avatar
Olivier Crête committed
288
    gst_rtp_buffer_unmap (&rtpbuffer);
289 290

    inbuf = gst_rtp_buffer_new_allocate (10, 0, 0);
Olivier Crête's avatar
Olivier Crête committed
291
    GST_BUFFER_PTS (inbuf) = i * 1000 + 500;
292
    GST_BUFFER_DURATION (inbuf) = 1000;
Olivier Crête's avatar
Olivier Crête committed
293 294 295 296 297 298 299
    gst_rtp_buffer_map (inbuf, GST_MAP_WRITE, &rtpbuffer);
    gst_rtp_buffer_set_version (&rtpbuffer, 2);
    gst_rtp_buffer_set_payload_type (&rtpbuffer, 98);
    gst_rtp_buffer_set_ssrc (&rtpbuffer, 44);
    gst_rtp_buffer_set_timestamp (&rtpbuffer, 200 + i);
    gst_rtp_buffer_set_seq (&rtpbuffer, 2000 + i);
    gst_rtp_buffer_unmap (&rtpbuffer);
300 301 302
    fail_unless (gst_pad_push (pad, inbuf) == GST_FLOW_OK);


303 304 305 306
    g_list_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
    g_list_free (buffers);
    buffers = NULL;
  }
307 308
}

309 310
GST_START_TEST (test_rtpdtmfmux_lock)
{
311
  test_basic ("rtpdtmfmux", "priority_sink_2", 10, lock_check_cb);
312
}
313 314 315

GST_END_TEST;

316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
static GstBuffer *
generate_test_buffer (guint seq_num, guint ssrc)
{
  GstBuffer *buf;
  guint8 *payload;
  guint i;
  GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
  gsize size = 10;

  buf = gst_rtp_buffer_new_allocate (size, 0, 0);
  GST_BUFFER_DTS (buf) = GST_MSECOND * 20 * seq_num;
  GST_BUFFER_PTS (buf) = GST_MSECOND * 20 * seq_num;

  gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtp);
  gst_rtp_buffer_set_payload_type (&rtp, 0);
  gst_rtp_buffer_set_seq (&rtp, seq_num);
  gst_rtp_buffer_set_timestamp (&rtp, 160 * seq_num);
  gst_rtp_buffer_set_ssrc (&rtp, ssrc);

  payload = gst_rtp_buffer_get_payload (&rtp);
  for (i = 0; i < size; i++)
    payload[i] = 0xff;

  gst_rtp_buffer_unmap (&rtp);

  return buf;
}

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 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425
static guint32
_rtp_buffer_get_ssrc (GstBuffer * buf)
{
  GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
  guint32 ret;
  g_assert (gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp));
  ret = gst_rtp_buffer_get_ssrc (&rtp);
  gst_rtp_buffer_unmap (&rtp);
  return ret;
}

GST_START_TEST (test_rtpmux_ssrc_property)
{
  GstHarness *h = gst_harness_new_with_padnames ("rtpmux", NULL, "src");
  GstHarness *h0 = gst_harness_new_with_element (h->element, "sink_0", NULL);
  GstHarness *h1 = gst_harness_new_with_element (h->element, "sink_1", NULL);
  GstBuffer *buf0;
  GstBuffer *buf1;

  /* set ssrc to 111111 */
  g_object_set (h->element, "ssrc", 111111, NULL);

  /* both sinkpads have their own idea of what the ssrc should be */
  gst_harness_set_src_caps_str (h0, "application/x-rtp, ssrc=(uint)222222");
  gst_harness_set_src_caps_str (h1, "application/x-rtp, ssrc=(uint)333333");

  /* push on both sinkpads with different ssrc */
  fail_unless_equals_int (GST_FLOW_OK,
      gst_harness_push (h0, generate_test_buffer (0, 222222)));
  fail_unless_equals_int (GST_FLOW_OK,
      gst_harness_push (h1, generate_test_buffer (0, 333333)));

  buf0 = gst_harness_pull (h);
  buf1 = gst_harness_pull (h);

  /* we expect the ssrc to be what we specified in the property */
  fail_unless_equals_int (111111, _rtp_buffer_get_ssrc (buf0));
  fail_unless_equals_int (111111, _rtp_buffer_get_ssrc (buf1));

  gst_buffer_unref (buf0);
  gst_buffer_unref (buf1);

  gst_harness_teardown (h0);
  gst_harness_teardown (h1);
  gst_harness_teardown (h);
}

GST_END_TEST;

GST_START_TEST (test_rtpmux_ssrc_property_not_set)
{
  GstHarness *h = gst_harness_new_with_padnames ("rtpmux", NULL, "src");
  GstHarness *h0 = gst_harness_new_with_element (h->element, "sink_0", NULL);
  GstHarness *h1 = gst_harness_new_with_element (h->element, "sink_1", NULL);
  GstBuffer *buf0;
  GstBuffer *buf1;

  gst_harness_set_src_caps_str (h0, "application/x-rtp, ssrc=(uint)222222");
  gst_harness_set_src_caps_str (h1, "application/x-rtp, ssrc=(uint)333333");

  fail_unless_equals_int (GST_FLOW_OK,
      gst_harness_push (h0, generate_test_buffer (0, 222222)));
  fail_unless_equals_int (GST_FLOW_OK,
      gst_harness_push (h1, generate_test_buffer (0, 333333)));

  buf0 = gst_harness_pull (h);
  buf1 = gst_harness_pull (h);

  /* we expect the ssrc to be the first ssrc that came in */
  fail_unless_equals_int (222222, _rtp_buffer_get_ssrc (buf0));
  fail_unless_equals_int (222222, _rtp_buffer_get_ssrc (buf1));

  gst_buffer_unref (buf0);
  gst_buffer_unref (buf1);

  gst_harness_teardown (h0);
  gst_harness_teardown (h1);
  gst_harness_teardown (h);
}

GST_END_TEST;

426
GST_START_TEST (test_rtpmux_ssrc_downstream_overrules_upstream)
427
{
428 429 430 431 432 433 434 435
  GstHarness *h = gst_harness_new_with_padnames ("rtpmux", NULL, "src");
  GstHarness *h0 = gst_harness_new_with_element (h->element, "sink_0", NULL);
  GstHarness *h1 = gst_harness_new_with_element (h->element, "sink_1", NULL);
  GstBuffer *buf0;
  GstBuffer *buf1;

  /* downstream is specifying 444444 as ssrc */
  gst_harness_set_sink_caps_str (h, "application/x-rtp, ssrc=(uint)444444");
436

437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462
  /* while upstream ssrc is 222222 and 333333 */
  gst_harness_set_src_caps_str (h0, "application/x-rtp, ssrc=(uint)222222");
  gst_harness_set_src_caps_str (h1, "application/x-rtp, ssrc=(uint)333333");

  fail_unless_equals_int (GST_FLOW_OK,
      gst_harness_push (h0, generate_test_buffer (0, 222222)));
  fail_unless_equals_int (GST_FLOW_OK,
      gst_harness_push (h1, generate_test_buffer (0, 333333)));

  buf0 = gst_harness_pull (h);
  buf1 = gst_harness_pull (h);

  /* we expect the ssrc to be downstream ssrc */
  fail_unless_equals_int (444444, _rtp_buffer_get_ssrc (buf0));
  fail_unless_equals_int (444444, _rtp_buffer_get_ssrc (buf1));

  gst_buffer_unref (buf0);
  gst_buffer_unref (buf1);

  gst_harness_teardown (h0);
  gst_harness_teardown (h1);
  gst_harness_teardown (h);
}

GST_END_TEST;

463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513
GST_START_TEST (test_rtpmux_ssrc_property_overrules_downstream)
{
  GstHarness * h = gst_harness_new_with_padnames ("rtpmux", NULL, "src");
  GstHarness * h0 = gst_harness_new_with_element (
      h->element, "sink_0", NULL);
  GstHarness * h1 = gst_harness_new_with_element (
      h->element, "sink_1", NULL);
  GstBuffer * buf0;
  GstBuffer * buf1;

  /* downstream is specifying 444444 as ssrc */
  gst_harness_set_sink_caps_str (h, "application/x-rtp, ssrc=(uint)444444");

  /* rtpmux ssrc is set to 111111 */
  g_object_set (h->element, "ssrc", 111111, NULL);

  /* while upstream ssrc is 222222 and 333333 */
  gst_harness_set_src_caps_str (h0, "application/x-rtp, ssrc=(uint)222222");
  gst_harness_set_src_caps_str (h1, "application/x-rtp, ssrc=(uint)333333");

  /* pushing now should fail */
  fail_unless_equals_int (GST_FLOW_NOT_NEGOTIATED,
      gst_harness_push (h0, generate_test_buffer (0, 222222)));
  fail_unless_equals_int (GST_FLOW_NOT_NEGOTIATED,
      gst_harness_push (h1, generate_test_buffer (0, 333333)));

  /* open up the restriction on ssrc downstream */
  gst_harness_set_sink_caps_str (h, "application/x-rtp");

  /* and push again */
  fail_unless_equals_int (GST_FLOW_OK,
      gst_harness_push (h0, generate_test_buffer (0, 222222)));
  fail_unless_equals_int (GST_FLOW_OK,
      gst_harness_push (h1, generate_test_buffer (0, 333333)));

  buf0 = gst_harness_pull (h);
  buf1 = gst_harness_pull (h);

  /* we expect the ssrc to be property ssrc */
  fail_unless_equals_int (111111, _rtp_buffer_get_ssrc (buf0));
  fail_unless_equals_int (111111, _rtp_buffer_get_ssrc (buf1));

  gst_buffer_unref (buf0);
  gst_buffer_unref (buf1);

  gst_harness_teardown (h0);
  gst_harness_teardown (h1);
  gst_harness_teardown (h);
}
GST_END_TEST;

514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558
GST_START_TEST (test_rtpmux_ssrc_property_survive_statechange)
{
  GstHarness * h = gst_harness_new_with_padnames ("rtpmux", NULL, "src");
  GstHarness * h0 = gst_harness_new_with_element (
      h->element, "sink_0", NULL);
  GstHarness * h1 = gst_harness_new_with_element (
      h->element, "sink_1", NULL);
  GstBuffer * buf0;
  GstBuffer * buf1;

  gst_element_set_state (h->element, GST_STATE_NULL);
  /* rtpmux ssrc is set to 111111 */
  g_object_set (h->element, "ssrc", 111111, NULL);
  gst_element_set_state (h->element, GST_STATE_PLAYING);

  /* upstream ssrc is 222222 and 333333 */
  gst_harness_set_src_caps_str (h0, "application/x-rtp, ssrc=(uint)222222");
  gst_harness_set_src_caps_str (h1, "application/x-rtp, ssrc=(uint)333333");

  /* downstream is specifying 444444 as ssrc */
  gst_harness_set_sink_caps_str (h, "application/x-rtp, ssrc=(uint)444444");
  gst_harness_set_sink_caps_str (h, "application/x-rtp");

  /* push*/
  fail_unless_equals_int (GST_FLOW_OK,
      gst_harness_push (h0, generate_test_buffer (0, 222222)));
  fail_unless_equals_int (GST_FLOW_OK,
      gst_harness_push (h1, generate_test_buffer (0, 333333)));

  buf0 = gst_harness_pull (h);
  buf1 = gst_harness_pull (h);

  /* we expect the ssrc to be property ssrc */
  fail_unless_equals_int (111111, _rtp_buffer_get_ssrc (buf0));
  fail_unless_equals_int (111111, _rtp_buffer_get_ssrc (buf1));

  gst_buffer_unref (buf0);
  gst_buffer_unref (buf1);

  gst_harness_teardown (h0);
  gst_harness_teardown (h1);
  gst_harness_teardown (h);
}
GST_END_TEST;

559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576
GST_START_TEST (test_rtpmux_ssrc_downstream_dynamic)
{
  GstHarness *h = gst_harness_new_parse ("rtpmux ! capsfilter");
  GstElement *rtpmux = gst_harness_find_element (h, "rtpmux");
  GstElement *capsfilter = gst_harness_find_element (h, "capsfilter");

  GstHarness *h0 = gst_harness_new_with_element (rtpmux, "sink_0", NULL);
  GstHarness *h1 = gst_harness_new_with_element (rtpmux, "sink_1", NULL);
  GstCaps *caps;
  GstBuffer *buf0;
  GstBuffer *buf1;

  gst_harness_play (h);

  caps = gst_caps_from_string ("application/x-rtp, ssrc=(uint)444444");
  g_object_set (capsfilter, "caps", caps, NULL);
  gst_caps_unref (caps);

577 578 579
  gst_harness_set_src_caps_str (h0, "application/x-rtp, ssrc=(uint)222222");
  gst_harness_set_src_caps_str (h1, "application/x-rtp, ssrc=(uint)333333");

580
  /* push on both sinkpads with different ssrc */
581 582 583 584 585
  fail_unless_equals_int (GST_FLOW_OK,
      gst_harness_push (h0, generate_test_buffer (0, 222222)));
  fail_unless_equals_int (GST_FLOW_OK,
      gst_harness_push (h1, generate_test_buffer (0, 333333)));

586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
  /* we expect the ssrc to be downstream ssrc (444444) */
  buf0 = gst_harness_pull (h);
  buf1 = gst_harness_pull (h);
  fail_unless_equals_int (444444, _rtp_buffer_get_ssrc (buf0));
  fail_unless_equals_int (444444, _rtp_buffer_get_ssrc (buf1));
  gst_buffer_unref (buf0);
  gst_buffer_unref (buf1);

  caps = gst_caps_from_string ("application/x-rtp, ssrc=(uint)555555");
  g_object_set (capsfilter, "caps", caps, NULL);
  gst_caps_unref (caps);

  fail_unless_equals_int (GST_FLOW_OK,
      gst_harness_push (h0, generate_test_buffer (0, 222222)));
  fail_unless_equals_int (GST_FLOW_OK,
      gst_harness_push (h1, generate_test_buffer (0, 333333)));

  /* we expect the ssrc to be the new downstream ssrc (555555) */
  buf0 = gst_harness_pull (h);
  buf1 = gst_harness_pull (h);
  fail_unless_equals_int (555555, _rtp_buffer_get_ssrc (buf0));
  fail_unless_equals_int (555555, _rtp_buffer_get_ssrc (buf1));
  gst_buffer_unref (buf0);
  gst_buffer_unref (buf1);

  gst_object_unref (rtpmux);
612
  gst_object_unref (capsfilter);
613 614 615 616
  gst_harness_teardown (h0);
  gst_harness_teardown (h1);
  gst_harness_teardown (h);
}
617

618 619
GST_END_TEST;

620 621 622 623 624 625 626 627
static Suite *
rtpmux_suite (void)
{
  Suite *s = suite_create ("rtpmux");
  TCase *tc_chain;

  tc_chain = tcase_create ("rtpmux_basic");
  suite_add_tcase (s, tc_chain);
628
  tcase_add_test (tc_chain, test_rtpmux_basic);
629 630
  tcase_add_test (tc_chain, test_rtpmux_ssrc_property);
  tcase_add_test (tc_chain, test_rtpmux_ssrc_property_not_set);
631 632 633

  tcase_add_test (tc_chain, test_rtpmux_ssrc_downstream_overrules_upstream);
  tcase_add_test (tc_chain, test_rtpmux_ssrc_property_overrules_downstream);
634
  tcase_add_test (tc_chain, test_rtpmux_ssrc_property_survive_statechange);
635

636
  tcase_add_test (tc_chain, test_rtpmux_ssrc_downstream_dynamic);
637 638 639 640 641

  tc_chain = tcase_create ("rtpdtmfmux_basic");
  tcase_add_test (tc_chain, test_rtpdtmfmux_basic);
  suite_add_tcase (s, tc_chain);

642 643 644 645
  tc_chain = tcase_create ("rtpdtmfmux_lock");
  tcase_add_test (tc_chain, test_rtpdtmfmux_lock);
  suite_add_tcase (s, tc_chain);

646 647 648 649
  return s;
}

GST_CHECK_MAIN (rtpmux)