1 /* GStreamer
2 *
3 * Unit test for gstrtpbin sending rtp packets using GstBufferList.
4 * Copyright (C) 2009 Branko Subasic <branko dot subasic at axis dot com>
5 * Copyright 2019, Collabora Ltd.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 #include <gst/check/gstcheck.h>
24
25 #include <gst/rtp/gstrtpbuffer.h>
26 #include <gst/rtp/gstrtcpbuffer.h>
27
28 /* UDP/IP is assumed for bandwidth calculation */
29 #define UDP_IP_HEADER_OVERHEAD 28
30
31 /* This test makes sure that RTP packets sent as buffer lists are sent through
32 * the rtpbin as they are supposed to, and not corrupted in any way.
33 */
34
35
36 #define TEST_CAPS \
37 "application/x-rtp, " \
38 "media=(string)video, " \
39 "clock-rate=(int)90000, " \
40 "encoding-name=(string)H264, " \
41 "profile-level-id=(string)4d4015, " \
42 "payload=(int)96, " \
43 "ssrc=(guint)2633237432, " \
44 "clock-base=(guint)1868267015, " \
45 "seqnum-base=(guint)54229"
46
47
48 /* RTP headers and the first 2 bytes of the payload (FU indicator and FU header)
49 */
50 static const guint8 rtp_header[2][14] = {
51 {0x80, 0x60, 0xbb, 0xb7, 0x5c, 0xe9, 0x09,
52 0x0d, 0xf5, 0x9c, 0x43, 0x55, 0x1c, 0x86},
53 {0x80, 0x60, 0xbb, 0xb8, 0x5c, 0xe9, 0x09,
54 0x0d, 0xf5, 0x9c, 0x43, 0x55, 0x1c, 0x46}
55 };
56
57 static const guint rtp_header_len[] = {
58 sizeof rtp_header[0],
59 sizeof rtp_header[1]
60 };
61
62 /* Some payload.
63 */
64 static const char *payload =
65 "0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF"
66 "0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF"
67 "0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF"
68 "0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF"
69 "0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF"
70 "0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF"
71 "0123456789ABSDEF0123456";
72
73 static const guint payload_offset[] = {
74 0, 498
75 };
76
77 static const guint payload_len[] = {
78 498, 5
79 };
80
81
82 static GstBuffer *original_buffer = NULL;
83
84 static GstStaticPadTemplate sinktemplate_rtcp = GST_STATIC_PAD_TEMPLATE ("sink",
85 GST_PAD_SINK,
86 GST_PAD_ALWAYS,
87 GST_STATIC_CAPS ("application/x-rtcp"));
88
89 static GstStaticPadTemplate srctemplate_rtcp = GST_STATIC_PAD_TEMPLATE ("src",
90 GST_PAD_SRC,
91 GST_PAD_ALWAYS,
92 GST_STATIC_CAPS ("application/x-rtcp"));
93
94 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
95 GST_PAD_SINK,
96 GST_PAD_ALWAYS,
97 GST_STATIC_CAPS ("application/x-rtp"));
98
99 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
100 GST_PAD_SRC,
101 GST_PAD_ALWAYS,
102 GST_STATIC_CAPS ("application/x-rtp"));
103
104
105 static GstBuffer *
create_original_buffer(void)106 create_original_buffer (void)
107 {
108 if (original_buffer != NULL)
109 return original_buffer;
110
111 original_buffer =
112 gst_buffer_new_wrapped ((guint8 *) payload, strlen (payload));
113 fail_unless (original_buffer != NULL);
114
115 GST_BUFFER_TIMESTAMP (original_buffer) =
116 gst_clock_get_internal_time (gst_system_clock_obtain ());
117
118 return original_buffer;
119 }
120
121 static GstBuffer *
create_rtp_packet_buffer(gconstpointer header,gint header_size,GstBuffer * payload_buffer,gint payload_offset,gint payload_size)122 create_rtp_packet_buffer (gconstpointer header, gint header_size,
123 GstBuffer * payload_buffer, gint payload_offset, gint payload_size)
124 {
125 GstBuffer *buffer;
126 GstBuffer *sub_buffer;
127
128 /* Create buffer with RTP header. */
129 buffer = gst_buffer_new_allocate (NULL, header_size, NULL);
130 gst_buffer_fill (buffer, 0, header, header_size);
131 gst_buffer_copy_into (buffer, payload_buffer, GST_BUFFER_COPY_METADATA, 0,
132 -1);
133
134 /* Create the payload buffer and add it to the current buffer. */
135 sub_buffer =
136 gst_buffer_copy_region (payload_buffer, GST_BUFFER_COPY_MEMORY,
137 payload_offset, payload_size);
138
139 buffer = gst_buffer_append (buffer, sub_buffer);
140 fail_if (buffer == NULL);
141
142 return buffer;
143 }
144
145 static GstBuffer *
create_rtp_buffer_fields(gconstpointer header,gint header_size,GstBuffer * payload_buffer,gint payload_offset,gint payload_size,guint16 seqnum,guint32 timestamp)146 create_rtp_buffer_fields (gconstpointer header, gint header_size,
147 GstBuffer * payload_buffer, gint payload_offset, gint payload_size,
148 guint16 seqnum, guint32 timestamp)
149 {
150 GstBuffer *buffer;
151 GstMemory *memory;
152 GstMapInfo info;
153 gboolean ret;
154 guint32 *tmp;
155
156 buffer =
157 create_rtp_packet_buffer (header, header_size, payload_buffer,
158 payload_offset, payload_size);
159 fail_if (buffer == NULL);
160
161 memory = gst_buffer_get_memory (buffer, 0);
162 ret = gst_memory_map (memory, &info, GST_MAP_READ);
163 fail_if (ret == FALSE);
164
165 info.data[2] = (seqnum >> 8) & 0xff;
166 info.data[3] = seqnum & 0xff;
167
168 tmp = (guint32 *) & (info.data[4]);
169 *tmp = g_htonl (timestamp);
170
171 gst_memory_unmap (memory, &info);
172 gst_memory_unref (memory);
173
174 return buffer;
175 }
176
177 static void
check_seqnum(GstBuffer * buffer,guint16 seqnum)178 check_seqnum (GstBuffer * buffer, guint16 seqnum)
179 {
180 GstMemory *memory;
181 GstMapInfo info;
182 gboolean ret;
183 guint16 current_seqnum;
184
185 fail_if (buffer == NULL);
186
187 memory = gst_buffer_get_memory (buffer, 0);
188 ret = gst_memory_map (memory, &info, GST_MAP_READ);
189 fail_if (ret == FALSE);
190
191 current_seqnum = info.data[2] << 8 | info.data[3];
192 fail_unless (current_seqnum == seqnum);
193
194 gst_memory_unmap (memory, &info);
195 gst_memory_unref (memory);
196 }
197
198 static void
check_timestamp(GstBuffer * buffer,guint32 timestamp)199 check_timestamp (GstBuffer * buffer, guint32 timestamp)
200 {
201 GstMemory *memory;
202 GstMapInfo info;
203 gboolean ret;
204 guint32 current_timestamp;
205
206 fail_if (buffer == NULL);
207
208 memory = gst_buffer_get_memory (buffer, 0);
209 ret = gst_memory_map (memory, &info, GST_MAP_READ);
210 fail_if (ret == FALSE);
211
212 current_timestamp = g_ntohl (*((guint32 *) & (info.data[4])));
213 fail_unless (current_timestamp == timestamp);
214
215 gst_memory_unmap (memory, &info);
216 gst_memory_unref (memory);
217 }
218
219 static void
check_header(GstBuffer * buffer,guint index)220 check_header (GstBuffer * buffer, guint index)
221 {
222 GstMemory *memory;
223 GstMapInfo info;
224 gboolean ret;
225
226 fail_if (buffer == NULL);
227 fail_unless (index < 2);
228
229 memory = gst_buffer_get_memory (buffer, 0);
230 ret = gst_memory_map (memory, &info, GST_MAP_READ);
231 fail_if (ret == FALSE);
232
233 fail_unless (info.size == rtp_header_len[index]);
234
235 /* Can't do a memcmp() on the whole header, cause the SSRC (bytes 8-11) will
236 * most likely be changed in gstrtpbin.
237 */
238 fail_unless (info.data != NULL);
239 fail_unless_equals_uint64 (*(guint64 *) info.data,
240 *(guint64 *) rtp_header[index]);
241 fail_unless (*(guint16 *) (info.data + 12) ==
242 *(guint16 *) (rtp_header[index] + 12));
243
244 gst_memory_unmap (memory, &info);
245 gst_memory_unref (memory);
246 }
247
248 static void
check_payload(GstBuffer * buffer,guint index)249 check_payload (GstBuffer * buffer, guint index)
250 {
251 GstMemory *memory;
252 GstMapInfo info;
253 gboolean ret;
254
255 fail_if (buffer == NULL);
256 fail_unless (index < 2);
257
258 memory = gst_buffer_get_memory (buffer, 1);
259 ret = gst_memory_map (memory, &info, GST_MAP_READ);
260 fail_if (ret == FALSE);
261
262 fail_unless (info.size == payload_len[index]);
263 fail_if (info.data != (gpointer) (payload + payload_offset[index]));
264 fail_if (memcmp (info.data, payload + payload_offset[index],
265 payload_len[index]));
266
267 gst_memory_unmap (memory, &info);
268 gst_memory_unref (memory);
269 }
270
271 static void
check_packet(GstBufferList * list,guint list_index,guint packet_index)272 check_packet (GstBufferList * list, guint list_index, guint packet_index)
273 {
274 GstBuffer *buffer;
275
276 fail_unless (list != NULL);
277
278 fail_unless ((buffer = gst_buffer_list_get (list, list_index)) != NULL);
279 fail_unless (gst_buffer_n_memory (buffer) == 2);
280
281 fail_unless (GST_BUFFER_TIMESTAMP (buffer) ==
282 GST_BUFFER_TIMESTAMP (original_buffer));
283
284 check_header (buffer, packet_index);
285 check_payload (buffer, packet_index);
286 }
287
288 /*
289 * Used to verify that the chain_list function is actually implemented by the
290 * element and called when executing the pipeline. This is needed because pads
291 * always have a default chain_list handler which handle buffers in a buffer
292 * list individually, and pushing a list to a pad can succeed even if no
293 * chain_list handler has been set.
294 */
295 static gboolean chain_list_func_called;
296 static guint chain_list_bytes_received;
297
298 /* Create two packets with different payloads. */
299 static GstBufferList *
create_buffer_list(void)300 create_buffer_list (void)
301 {
302 GstBufferList *list;
303 GstBuffer *orig_buffer;
304 GstBuffer *buffer;
305
306 orig_buffer = create_original_buffer ();
307 fail_if (orig_buffer == NULL);
308
309 list = gst_buffer_list_new ();
310 fail_if (list == NULL);
311
312 /*** First packet. **/
313 buffer =
314 create_rtp_packet_buffer (&rtp_header[0], rtp_header_len[0], orig_buffer,
315 payload_offset[0], payload_len[0]);
316 gst_buffer_list_add (list, buffer);
317
318 /*** Second packet. ***/
319 buffer =
320 create_rtp_packet_buffer (&rtp_header[1], rtp_header_len[1], orig_buffer,
321 payload_offset[1], payload_len[1]);
322 gst_buffer_list_add (list, buffer);
323
324 return list;
325 }
326
327 /* Check that the correct packets have been pushed out of the element. */
328 static GstFlowReturn
sink_chain_list(GstPad * pad,GstObject * parent,GstBufferList * list)329 sink_chain_list (GstPad * pad, GstObject * parent, GstBufferList * list)
330 {
331 GstCaps *current_caps;
332 GstCaps *caps;
333
334 chain_list_func_called = TRUE;
335
336 current_caps = gst_pad_get_current_caps (pad);
337 fail_unless (current_caps != NULL);
338
339 caps = gst_caps_from_string (TEST_CAPS);
340 fail_unless (caps != NULL);
341
342 fail_unless (gst_caps_is_equal (caps, current_caps));
343 gst_caps_unref (caps);
344 gst_caps_unref (current_caps);
345
346 fail_unless (GST_IS_BUFFER_LIST (list));
347 fail_unless (gst_buffer_list_length (list) == 2);
348
349 /* received bytes include lower level protocol overhead */
350 chain_list_bytes_received = gst_buffer_list_calculate_size (list) +
351 2 * UDP_IP_HEADER_OVERHEAD;
352
353 fail_unless (gst_buffer_list_get (list, 0));
354 check_packet (list, 0, 0);
355
356 fail_unless (gst_buffer_list_get (list, 1));
357 check_packet (list, 1, 1);
358
359 gst_buffer_list_unref (list);
360
361 return GST_FLOW_OK;
362 }
363
364
365 /* Non-consecutive seqnums makes probation fail. */
366 static GstBufferList *
create_buffer_list_fail_probation(void)367 create_buffer_list_fail_probation (void)
368 {
369 GstBufferList *list;
370 GstBuffer *orig_buffer;
371 GstBuffer *buffer;
372
373 guint16 seqnums[] = { 1, 3, 5 };
374 guint i;
375
376 orig_buffer = create_original_buffer ();
377 fail_if (orig_buffer == NULL);
378
379 list = gst_buffer_list_new ();
380 fail_if (list == NULL);
381
382 for (i = 0; i < sizeof (seqnums) / sizeof (seqnums[0]); i++) {
383 buffer =
384 create_rtp_buffer_fields (&rtp_header[0], rtp_header_len[0],
385 orig_buffer, payload_offset[0], payload_len[0], seqnums[i], 0);
386 gst_buffer_list_add (list, buffer);
387 }
388
389 return list;
390 }
391
392 /* When probation fails this function shouldn't be called. */
393 static GstFlowReturn
sink_chain_list_probation_failed(GstPad * pad,GstObject * parent,GstBufferList * list)394 sink_chain_list_probation_failed (GstPad * pad, GstObject * parent,
395 GstBufferList * list)
396 {
397 chain_list_func_called = TRUE;
398 return GST_FLOW_OK;
399 }
400
401
402 /* After probation succeeds, a small gap in seqnums is allowed. */
403 static GstBufferList *
create_buffer_list_permissible_gap(void)404 create_buffer_list_permissible_gap (void)
405 {
406 GstBufferList *list;
407 GstBuffer *orig_buffer;
408 GstBuffer *buffer;
409
410 /* probation succeeds, but then there is a permissible out of sequence */
411 guint16 seqnums[] = { 1, 2, 4, 5 };
412 guint i;
413
414 orig_buffer = create_original_buffer ();
415 fail_if (orig_buffer == NULL);
416
417 list = gst_buffer_list_new ();
418 fail_if (list == NULL);
419
420 for (i = 0; i < sizeof (seqnums) / sizeof (seqnums[0]); i++) {
421 buffer =
422 create_rtp_buffer_fields (&rtp_header[0], rtp_header_len[0],
423 orig_buffer, payload_offset[0], payload_len[0], seqnums[i], 0);
424 gst_buffer_list_add (list, buffer);
425 }
426
427 return list;
428 }
429
430 /* All buffers should have been pushed. */
431 static GstFlowReturn
sink_chain_list_permissible_gap(GstPad * pad,GstObject * parent,GstBufferList * list)432 sink_chain_list_permissible_gap (GstPad * pad, GstObject * parent,
433 GstBufferList * list)
434 {
435 GstBuffer *buffer;
436
437 chain_list_func_called = TRUE;
438
439 fail_unless (GST_IS_BUFFER_LIST (list));
440 fail_unless (gst_buffer_list_length (list) == 4);
441
442 /* Verify sequence numbers */
443 buffer = gst_buffer_list_get (list, 0);
444 check_seqnum (buffer, 1);
445
446 buffer = gst_buffer_list_get (list, 1);
447 check_seqnum (buffer, 2);
448
449 buffer = gst_buffer_list_get (list, 2);
450 check_seqnum (buffer, 4);
451
452 buffer = gst_buffer_list_get (list, 3);
453 check_seqnum (buffer, 5);
454
455 gst_buffer_list_unref (list);
456
457 return GST_FLOW_OK;
458 }
459
460
461 /* After probation succeeds, wrapping seqnum is allowed. */
462 static GstBufferList *
create_buffer_list_wrapping_seqnums(void)463 create_buffer_list_wrapping_seqnums (void)
464 {
465 GstBufferList *list;
466 GstBuffer *orig_buffer;
467 GstBuffer *buffer;
468
469 /* probation succeeds, but then seqnum wraps around */
470 guint16 seqnums[] = { 65533, 65534, 65535, 0 };
471 guint i;
472
473 orig_buffer = create_original_buffer ();
474 fail_if (orig_buffer == NULL);
475
476 list = gst_buffer_list_new ();
477 fail_if (list == NULL);
478
479 for (i = 0; i < sizeof (seqnums) / sizeof (seqnums[0]); i++) {
480 buffer =
481 create_rtp_buffer_fields (&rtp_header[0], rtp_header_len[0],
482 orig_buffer, payload_offset[0], payload_len[0], seqnums[i], 0);
483 gst_buffer_list_add (list, buffer);
484 }
485
486 return list;
487 }
488
489 /* All buffers should have been pushed. */
490 static GstFlowReturn
sink_chain_list_wrapping_seqnums(GstPad * pad,GstObject * parent,GstBufferList * list)491 sink_chain_list_wrapping_seqnums (GstPad * pad, GstObject * parent,
492 GstBufferList * list)
493 {
494 GstBuffer *buffer;
495
496 chain_list_func_called = TRUE;
497
498 fail_unless (GST_IS_BUFFER_LIST (list));
499 fail_unless (gst_buffer_list_length (list) == 4);
500
501 /* Verify sequence numbers */
502 buffer = gst_buffer_list_get (list, 0);
503 check_seqnum (buffer, 65533);
504
505 buffer = gst_buffer_list_get (list, 1);
506 check_seqnum (buffer, 65534);
507
508 buffer = gst_buffer_list_get (list, 2);
509 check_seqnum (buffer, 65535);
510
511 buffer = gst_buffer_list_get (list, 3);
512 check_seqnum (buffer, 0);
513
514 gst_buffer_list_unref (list);
515
516 return GST_FLOW_OK;
517 }
518
519
520 /* Large jump, packet discarded. */
521 static GstBufferList *
create_buffer_list_large_jump_discarded(void)522 create_buffer_list_large_jump_discarded (void)
523 {
524 GstBufferList *list;
525 GstBuffer *orig_buffer;
526 GstBuffer *buffer;
527
528 /*
529 * Probation succeeds, but then a large jump happens and the bogus packet
530 * gets discarded, receiving continues normally afterwards.
531 */
532 guint16 seqnums[] = { 1, 2, 3, 4, 50000, 5 };
533 guint i;
534
535 orig_buffer = create_original_buffer ();
536 fail_if (orig_buffer == NULL);
537
538 list = gst_buffer_list_new ();
539 fail_if (list == NULL);
540
541 for (i = 0; i < sizeof (seqnums) / sizeof (seqnums[0]); i++) {
542 /*
543 * Make the timestamps proportional to seqnums, to make it easier to predict
544 * the packet rate.
545 */
546 guint32 timestamp = seqnums[i] * 100;
547
548 buffer =
549 create_rtp_buffer_fields (&rtp_header[0], rtp_header_len[0],
550 orig_buffer, payload_offset[0], payload_len[0], seqnums[i], timestamp);
551 gst_buffer_list_add (list, buffer);
552 }
553
554 return list;
555 }
556
557 /* One buffer has been discarded. */
558 static GstFlowReturn
sink_chain_list_large_jump_discarded(GstPad * pad,GstObject * parent,GstBufferList * list)559 sink_chain_list_large_jump_discarded (GstPad * pad, GstObject * parent,
560 GstBufferList * list)
561 {
562 GstBuffer *buffer;
563
564 chain_list_func_called = TRUE;
565
566 fail_unless (GST_IS_BUFFER_LIST (list));
567 fail_unless (gst_buffer_list_length (list) == 5);
568
569 /* Verify sequence numbers */
570 buffer = gst_buffer_list_get (list, 0);
571 check_seqnum (buffer, 1);
572
573 buffer = gst_buffer_list_get (list, 1);
574 check_seqnum (buffer, 2);
575
576 buffer = gst_buffer_list_get (list, 2);
577 check_seqnum (buffer, 3);
578
579 buffer = gst_buffer_list_get (list, 3);
580 check_seqnum (buffer, 4);
581
582 buffer = gst_buffer_list_get (list, 4);
583 check_seqnum (buffer, 5);
584
585 gst_buffer_list_unref (list);
586
587 return GST_FLOW_OK;
588 }
589
590
591 /* Large jump, with recovery. */
592 static GstBufferList *
create_buffer_list_large_jump_recovery(void)593 create_buffer_list_large_jump_recovery (void)
594 {
595 GstBufferList *list;
596 GstBuffer *orig_buffer;
597 GstBuffer *buffer;
598
599 /*
600 * Probation succeeds, but then a large jump happens.
601 * A consecutive next packet makes the session manager recover: it assumes
602 * that the other side restarted without telling.
603 */
604 guint16 seqnums[] = { 1, 2, 3, 4, 50000, 50001 };
605 guint i;
606
607 orig_buffer = create_original_buffer ();
608 fail_if (orig_buffer == NULL);
609
610 list = gst_buffer_list_new ();
611 fail_if (list == NULL);
612
613 for (i = 0; i < sizeof (seqnums) / sizeof (seqnums[0]); i++) {
614 /*
615 * Make the timestamps proportional to seqnums, to make it easier to predict
616 * the packet rate.
617 */
618 guint32 timestamp = seqnums[i] * 100;
619
620 buffer =
621 create_rtp_buffer_fields (&rtp_header[0], rtp_header_len[0],
622 orig_buffer, payload_offset[0], payload_len[0], seqnums[i], timestamp);
623 gst_buffer_list_add (list, buffer);
624 }
625
626 return list;
627 }
628
629 /* All buffers should have been pushed. */
630 static GstFlowReturn
sink_chain_list_large_jump_recovery(GstPad * pad,GstObject * parent,GstBufferList * list)631 sink_chain_list_large_jump_recovery (GstPad * pad, GstObject * parent,
632 GstBufferList * list)
633 {
634 GstBuffer *buffer;
635
636 chain_list_func_called = TRUE;
637
638 fail_unless (GST_IS_BUFFER_LIST (list));
639 fail_unless (gst_buffer_list_length (list) == 6);
640
641 /* Verify sequence numbers */
642 buffer = gst_buffer_list_get (list, 0);
643 check_seqnum (buffer, 1);
644
645 buffer = gst_buffer_list_get (list, 1);
646 check_seqnum (buffer, 2);
647
648 buffer = gst_buffer_list_get (list, 2);
649 check_seqnum (buffer, 3);
650
651 buffer = gst_buffer_list_get (list, 3);
652 check_seqnum (buffer, 4);
653
654 buffer = gst_buffer_list_get (list, 4);
655 check_seqnum (buffer, 50000);
656
657 buffer = gst_buffer_list_get (list, 5);
658 check_seqnum (buffer, 50001);
659
660 gst_buffer_list_unref (list);
661
662 return GST_FLOW_OK;
663 }
664
665
666 /* After probation succeeds, reordered and duplicated packets are allowed. */
667 static GstBufferList *
create_buffer_list_reordered_packets(void)668 create_buffer_list_reordered_packets (void)
669 {
670 GstBufferList *list;
671 GstBuffer *orig_buffer;
672 GstBuffer *buffer;
673
674 /* probation succeeds, but then there are reordered or duplicated packets */
675 guint16 seqnums[] = { 4, 5, 2, 2 };
676 guint i;
677
678 orig_buffer = create_original_buffer ();
679 fail_if (orig_buffer == NULL);
680
681 list = gst_buffer_list_new ();
682 fail_if (list == NULL);
683
684 for (i = 0; i < sizeof (seqnums) / sizeof (seqnums[0]); i++) {
685 buffer =
686 create_rtp_buffer_fields (&rtp_header[0], rtp_header_len[0],
687 orig_buffer, payload_offset[0], payload_len[0], seqnums[i], 0);
688 gst_buffer_list_add (list, buffer);
689 }
690
691 return list;
692 }
693
694 /* All buffers should have been pushed, they will be filtered by jitterbuffer */
695 static GstFlowReturn
sink_chain_list_reordered_packets(GstPad * pad,GstObject * parent,GstBufferList * list)696 sink_chain_list_reordered_packets (GstPad * pad, GstObject * parent,
697 GstBufferList * list)
698 {
699 GstBuffer *buffer;
700
701 chain_list_func_called = TRUE;
702
703 fail_unless (GST_IS_BUFFER_LIST (list));
704 fail_unless (gst_buffer_list_length (list) == 4);
705
706 /* Verify sequence numbers */
707 buffer = gst_buffer_list_get (list, 0);
708 check_seqnum (buffer, 4);
709
710 buffer = gst_buffer_list_get (list, 1);
711 check_seqnum (buffer, 5);
712
713 buffer = gst_buffer_list_get (list, 2);
714 check_seqnum (buffer, 2);
715
716 buffer = gst_buffer_list_get (list, 3);
717 check_seqnum (buffer, 2);
718
719 gst_buffer_list_unref (list);
720
721 return GST_FLOW_OK;
722 }
723
724
725 /* Frames with different timestamps in the same buffer list. */
726 static GstBufferList *
create_buffer_list_different_frames(void)727 create_buffer_list_different_frames (void)
728 {
729 GstBufferList *list;
730 GstBuffer *orig_buffer;
731 GstBuffer *buffer;
732
733 guint32 timestamps[] = { 0, 0, 1000, 1000 };
734 guint i;
735
736 orig_buffer = create_original_buffer ();
737 fail_if (orig_buffer == NULL);
738
739 list = gst_buffer_list_new ();
740 fail_if (list == NULL);
741
742 for (i = 0; i < sizeof (timestamps) / sizeof (timestamps[0]); i++) {
743 buffer =
744 create_rtp_buffer_fields (&rtp_header[0], rtp_header_len[0],
745 orig_buffer, payload_offset[0], payload_len[0], i, timestamps[i]);
746 gst_buffer_list_add (list, buffer);
747 }
748
749 return list;
750 }
751
752 /* All buffers should have been pushed, regardless of the timestamp. */
753 static GstFlowReturn
sink_chain_list_different_frames(GstPad * pad,GstObject * parent,GstBufferList * list)754 sink_chain_list_different_frames (GstPad * pad, GstObject * parent,
755 GstBufferList * list)
756 {
757 GstBuffer *buffer;
758
759 chain_list_func_called = TRUE;
760
761 fail_unless (GST_IS_BUFFER_LIST (list));
762 fail_unless (gst_buffer_list_length (list) == 4);
763
764 /* Verify seqnums and timestamps. */
765 buffer = gst_buffer_list_get (list, 0);
766 check_seqnum (buffer, 0);
767 check_timestamp (buffer, 0);
768
769 buffer = gst_buffer_list_get (list, 1);
770 check_seqnum (buffer, 1);
771 check_timestamp (buffer, 0);
772
773 buffer = gst_buffer_list_get (list, 2);
774 check_seqnum (buffer, 2);
775 check_timestamp (buffer, 1000);
776
777 buffer = gst_buffer_list_get (list, 3);
778 check_seqnum (buffer, 3);
779 check_timestamp (buffer, 1000);
780
781 gst_buffer_list_unref (list);
782
783 return GST_FLOW_OK;
784 }
785
786
787 /*
788 * RTP and RTCP can be multiplexed in the same channel and end up in the same
789 * buffer list.
790 */
791 static GstBufferList *
create_buffer_list_muxed_rtcp(void)792 create_buffer_list_muxed_rtcp (void)
793 {
794 GstBufferList *list;
795 GstBuffer *orig_buffer;
796 GstBuffer *buffer;
797 GstRTCPBuffer rtcpbuf = GST_RTCP_BUFFER_INIT;
798 GstRTCPPacket rtcppacket;
799
800 guint seqnum = 0;
801
802 orig_buffer = create_original_buffer ();
803 fail_if (orig_buffer == NULL);
804
805 list = gst_buffer_list_new ();
806 fail_if (list == NULL);
807
808 buffer =
809 create_rtp_buffer_fields (&rtp_header[0], rtp_header_len[0],
810 orig_buffer, payload_offset[0], payload_len[0], seqnum, 0);
811 gst_buffer_list_add (list, buffer);
812
813 seqnum++;
814
815 buffer =
816 create_rtp_buffer_fields (&rtp_header[0], rtp_header_len[0],
817 orig_buffer, payload_offset[0], payload_len[0], seqnum, 0);
818 gst_buffer_list_add (list, buffer);
819
820 seqnum++;
821
822 buffer = gst_rtcp_buffer_new (1500);
823 gst_rtcp_buffer_map (buffer, GST_MAP_READWRITE, &rtcpbuf);
824 gst_rtcp_buffer_add_packet (&rtcpbuf, GST_RTCP_TYPE_SR, &rtcppacket);
825 gst_rtcp_packet_sr_set_sender_info (&rtcppacket, 0, 0, 0, 0, 0);
826 gst_rtcp_buffer_add_packet (&rtcpbuf, GST_RTCP_TYPE_RR, &rtcppacket);
827 gst_rtcp_packet_rr_set_ssrc (&rtcppacket, 1);
828 gst_rtcp_packet_add_rb (&rtcppacket, 0, 0, 0, 0, 0, 0, 0);
829 gst_rtcp_buffer_add_packet (&rtcpbuf, GST_RTCP_TYPE_SDES, &rtcppacket);
830 gst_rtcp_packet_sdes_add_item (&rtcppacket, 1);
831 gst_rtcp_packet_sdes_add_entry (&rtcppacket, GST_RTCP_SDES_CNAME, 3,
832 (guint8 *) "a@a");
833 gst_rtcp_packet_sdes_add_entry (&rtcppacket, GST_RTCP_SDES_NAME, 2,
834 (guint8 *) "aa");
835 gst_rtcp_packet_sdes_add_entry (&rtcppacket, GST_RTCP_SDES_END, 0,
836 (guint8 *) "");
837 gst_rtcp_buffer_unmap (&rtcpbuf);
838
839 gst_buffer_list_add (list, buffer);
840
841 buffer =
842 create_rtp_buffer_fields (&rtp_header[0], rtp_header_len[0],
843 orig_buffer, payload_offset[0], payload_len[0], seqnum, 0);
844 gst_buffer_list_add (list, buffer);
845
846 return list;
847 }
848
849 /*
850 * All RTP buffers should have been pushed to recv_rtp_src, the RTCP packet
851 * should have been pushed to sync_src.
852 */
853 static GstFlowReturn
sink_chain_list_muxed_rtcp(GstPad * pad,GstObject * parent,GstBufferList * list)854 sink_chain_list_muxed_rtcp (GstPad * pad, GstObject * parent,
855 GstBufferList * list)
856 {
857 GstBuffer *buffer;
858
859 chain_list_func_called = TRUE;
860
861 fail_unless (GST_IS_BUFFER_LIST (list));
862 fail_unless (gst_buffer_list_length (list) == 3);
863
864 /* Verify seqnums of RTP packets. */
865 buffer = gst_buffer_list_get (list, 0);
866 check_seqnum (buffer, 0);
867
868 buffer = gst_buffer_list_get (list, 1);
869 check_seqnum (buffer, 1);
870
871 buffer = gst_buffer_list_get (list, 2);
872 check_seqnum (buffer, 2);
873
874 gst_buffer_list_unref (list);
875
876 return GST_FLOW_OK;
877 }
878
879 /* count multiplexed rtcp packets */
880 static guint rtcp_packets;
881
882 static GstFlowReturn
sink_chain_muxed_rtcp(GstPad * pad,GstObject * parent,GstBuffer * buffer)883 sink_chain_muxed_rtcp (GstPad * pad, GstObject * parent, GstBuffer * buffer)
884 {
885 rtcp_packets++;
886 gst_buffer_unref (buffer);
887 return GST_FLOW_OK;
888 }
889
890
891 /* Invalid data can be received muxed with valid RTP packets */
892 static GstBufferList *
create_buffer_list_muxed_invalid(void)893 create_buffer_list_muxed_invalid (void)
894 {
895 GstBufferList *list;
896 GstBuffer *orig_buffer;
897 GstBuffer *buffer;
898
899 guint seqnum = 0;
900
901 orig_buffer = create_original_buffer ();
902 fail_if (orig_buffer == NULL);
903
904 list = gst_buffer_list_new ();
905 fail_if (list == NULL);
906
907 buffer =
908 create_rtp_buffer_fields (&rtp_header[0], rtp_header_len[0],
909 orig_buffer, payload_offset[0], payload_len[0], seqnum, 0);
910 gst_buffer_list_add (list, buffer);
911
912 seqnum++;
913
914 buffer =
915 create_rtp_buffer_fields (&rtp_header[0], rtp_header_len[0],
916 orig_buffer, payload_offset[0], payload_len[0], seqnum, 0);
917 gst_buffer_list_add (list, buffer);
918
919 seqnum++;
920
921 /* add an invalid RTP packet to the list */
922 buffer = gst_buffer_new_allocate (NULL, 10, NULL);
923 /* initialize the memory to make valgrind happy */
924 gst_buffer_memset (buffer, 0, 0, 10);
925
926 gst_buffer_list_add (list, buffer);
927
928 buffer =
929 create_rtp_buffer_fields (&rtp_header[0], rtp_header_len[0],
930 orig_buffer, payload_offset[0], payload_len[0], seqnum, 0);
931 gst_buffer_list_add (list, buffer);
932
933 return list;
934 }
935
936 /*
937 * Only valid RTP buffers should have been pushed to recv_rtp_src.
938 */
939 static GstFlowReturn
sink_chain_list_muxed_invalid(GstPad * pad,GstObject * parent,GstBufferList * list)940 sink_chain_list_muxed_invalid (GstPad * pad, GstObject * parent,
941 GstBufferList * list)
942 {
943 GstBuffer *buffer;
944
945 chain_list_func_called = TRUE;
946
947 fail_unless (GST_IS_BUFFER_LIST (list));
948 fail_unless (gst_buffer_list_length (list) == 3);
949
950 /* Verify seqnums of valid RTP packets. */
951 buffer = gst_buffer_list_get (list, 0);
952 check_seqnum (buffer, 0);
953
954 buffer = gst_buffer_list_get (list, 1);
955 check_seqnum (buffer, 1);
956
957 buffer = gst_buffer_list_get (list, 2);
958 check_seqnum (buffer, 2);
959
960 gst_buffer_list_unref (list);
961
962 return GST_FLOW_OK;
963 }
964
965
966 /* Get the stats of the **first** source of the given type (get_sender) */
967 static void
get_source_stats(GstElement * rtpsession,gboolean get_sender,GstStructure ** source_stats)968 get_source_stats (GstElement * rtpsession,
969 gboolean get_sender, GstStructure ** source_stats)
970 {
971 GstStructure *stats;
972 GValueArray *stats_arr;
973 guint i;
974
975 g_object_get (rtpsession, "stats", &stats, NULL);
976 stats_arr =
977 g_value_get_boxed (gst_structure_get_value (stats, "source-stats"));
978 g_assert (stats_arr != NULL);
979 fail_unless (stats_arr->n_values >= 1);
980
981 *source_stats = NULL;
982 for (i = 0; i < stats_arr->n_values; i++) {
983 GstStructure *tmp_source_stats;
984 gboolean is_sender;
985
986 tmp_source_stats = g_value_dup_boxed (&stats_arr->values[i]);
987 gst_structure_get (tmp_source_stats, "is-sender", G_TYPE_BOOLEAN,
988 &is_sender, NULL);
989
990 /* Return the stats of the **first** source of the given type. */
991 if (is_sender == get_sender) {
992 *source_stats = tmp_source_stats;
993 break;
994 }
995 gst_structure_free (tmp_source_stats);
996 }
997
998 gst_structure_free (stats);
999 }
1000
1001 /* Get the source stats given a session and a source type (get_sender) */
1002 static void
get_session_source_stats(GstElement * rtpbin,guint session,gboolean get_sender,GstStructure ** source_stats)1003 get_session_source_stats (GstElement * rtpbin, guint session,
1004 gboolean get_sender, GstStructure ** source_stats)
1005 {
1006 GstElement *rtpsession;
1007
1008 g_signal_emit_by_name (rtpbin, "get-session", session, &rtpsession);
1009 fail_if (rtpsession == NULL);
1010
1011 get_source_stats (rtpsession, get_sender, source_stats);
1012
1013 gst_object_unref (rtpsession);
1014 }
1015
GST_START_TEST(test_bufferlist)1016 GST_START_TEST (test_bufferlist)
1017 {
1018 GstElement *rtpbin;
1019 GstPad *srcpad;
1020 GstPad *sinkpad;
1021 GstCaps *caps;
1022 GstBufferList *list;
1023 GstStructure *stats;
1024 guint64 packets_sent;
1025 guint64 packets_received;
1026
1027 list = create_buffer_list ();
1028 fail_unless (list != NULL);
1029
1030 rtpbin = gst_check_setup_element ("rtpbin");
1031
1032 srcpad =
1033 gst_check_setup_src_pad_by_name (rtpbin, &srctemplate, "send_rtp_sink_0");
1034 fail_if (srcpad == NULL);
1035 sinkpad =
1036 gst_check_setup_sink_pad_by_name (rtpbin, &sinktemplate,
1037 "send_rtp_src_0");
1038 fail_if (sinkpad == NULL);
1039
1040 gst_pad_set_chain_list_function (sinkpad,
1041 GST_DEBUG_FUNCPTR (sink_chain_list));
1042
1043 gst_pad_set_active (srcpad, TRUE);
1044 gst_pad_set_active (sinkpad, TRUE);
1045
1046 caps = gst_caps_from_string (TEST_CAPS);
1047 gst_check_setup_events (srcpad, rtpbin, caps, GST_FORMAT_TIME);
1048 gst_caps_unref (caps);
1049
1050 gst_element_set_state (rtpbin, GST_STATE_PLAYING);
1051
1052 chain_list_func_called = FALSE;
1053 fail_unless (gst_pad_push_list (srcpad, list) == GST_FLOW_OK);
1054 fail_if (chain_list_func_called == FALSE);
1055
1056 /* make sure that stats about the number of sent packets are OK too */
1057 get_session_source_stats (rtpbin, 0, TRUE, &stats);
1058 fail_if (stats == NULL);
1059
1060 gst_structure_get (stats,
1061 "packets-sent", G_TYPE_UINT64, &packets_sent,
1062 "packets-received", G_TYPE_UINT64, &packets_received, NULL);
1063 fail_unless (packets_sent == 2);
1064 fail_unless (packets_received == 2);
1065 gst_structure_free (stats);
1066
1067 gst_pad_set_active (sinkpad, FALSE);
1068 gst_pad_set_active (srcpad, FALSE);
1069
1070 gst_check_teardown_pad_by_name (rtpbin, "send_rtp_src_0");
1071 gst_check_teardown_pad_by_name (rtpbin, "send_rtp_sink_0");
1072 gst_check_teardown_element (rtpbin);
1073 }
1074
1075 GST_END_TEST;
1076
1077
GST_START_TEST(test_bufferlist_recv)1078 GST_START_TEST (test_bufferlist_recv)
1079 {
1080 GstElement *rtpbin;
1081 GstPad *srcpad;
1082 GstPad *sinkpad;
1083 GstCaps *caps;
1084 GstBufferList *list;
1085 GstStructure *stats;
1086 guint64 bytes_received;
1087 guint64 packets_received;
1088
1089 list = create_buffer_list ();
1090 fail_unless (list != NULL);
1091
1092 rtpbin = gst_check_setup_element ("rtpsession");
1093
1094 srcpad =
1095 gst_check_setup_src_pad_by_name (rtpbin, &srctemplate, "recv_rtp_sink");
1096 fail_if (srcpad == NULL);
1097
1098 sinkpad =
1099 gst_check_setup_sink_pad_by_name (rtpbin, &sinktemplate, "recv_rtp_src");
1100 fail_if (sinkpad == NULL);
1101
1102 gst_pad_set_chain_list_function (sinkpad,
1103 GST_DEBUG_FUNCPTR (sink_chain_list));
1104
1105 gst_pad_set_active (srcpad, TRUE);
1106 gst_pad_set_active (sinkpad, TRUE);
1107
1108 caps = gst_caps_from_string (TEST_CAPS);
1109 gst_check_setup_events (srcpad, rtpbin, caps, GST_FORMAT_TIME);
1110 gst_caps_unref (caps);
1111
1112 gst_element_set_state (rtpbin, GST_STATE_PLAYING);
1113
1114 chain_list_func_called = FALSE;
1115 fail_unless (gst_pad_push_list (srcpad, list) == GST_FLOW_OK);
1116 fail_if (chain_list_func_called == FALSE);
1117
1118 /* make sure that stats about the number of received packets are OK too */
1119 /* The source becomes a sender after probation succeeds, pass TRUE here. */
1120 get_source_stats (rtpbin, TRUE, &stats);
1121 fail_if (stats == NULL);
1122
1123 gst_structure_get (stats,
1124 "bytes-received", G_TYPE_UINT64, &bytes_received,
1125 "packets-received", G_TYPE_UINT64, &packets_received, NULL);
1126 fail_unless (packets_received == 2);
1127 fail_unless (bytes_received == chain_list_bytes_received);
1128 gst_structure_free (stats);
1129
1130
1131 gst_pad_set_active (sinkpad, FALSE);
1132 gst_pad_set_active (srcpad, FALSE);
1133
1134 gst_check_teardown_pad_by_name (rtpbin, "recv_rtp_src");
1135 gst_check_teardown_pad_by_name (rtpbin, "recv_rtp_sink");
1136 gst_check_teardown_element (rtpbin);
1137 }
1138
1139 GST_END_TEST;
1140
1141
GST_START_TEST(test_bufferlist_recv_probation_failed)1142 GST_START_TEST (test_bufferlist_recv_probation_failed)
1143 {
1144 GstElement *rtpbin;
1145 GstPad *srcpad;
1146 GstPad *sinkpad;
1147 GstCaps *caps;
1148 GstBufferList *list;
1149
1150 list = create_buffer_list_fail_probation ();
1151 fail_unless (list != NULL);
1152
1153 rtpbin = gst_check_setup_element ("rtpsession");
1154
1155 srcpad =
1156 gst_check_setup_src_pad_by_name (rtpbin, &srctemplate, "recv_rtp_sink");
1157 fail_if (srcpad == NULL);
1158
1159 sinkpad =
1160 gst_check_setup_sink_pad_by_name (rtpbin, &sinktemplate, "recv_rtp_src");
1161 fail_if (sinkpad == NULL);
1162
1163 gst_pad_set_chain_list_function (sinkpad,
1164 GST_DEBUG_FUNCPTR (sink_chain_list_probation_failed));
1165
1166 gst_pad_set_active (srcpad, TRUE);
1167 gst_pad_set_active (sinkpad, TRUE);
1168
1169 caps = gst_caps_from_string (TEST_CAPS);
1170 gst_check_setup_events (srcpad, rtpbin, caps, GST_FORMAT_TIME);
1171 gst_caps_unref (caps);
1172
1173 gst_element_set_state (rtpbin, GST_STATE_PLAYING);
1174
1175 chain_list_func_called = FALSE;
1176 fail_unless (gst_pad_push_list (srcpad, list) == GST_FLOW_OK);
1177 /* when probation fails the list should not be pushed at all, and the
1178 * chain_list functions should not be called, fail if it has been. */
1179 fail_if (chain_list_func_called == TRUE);
1180
1181 gst_pad_set_active (sinkpad, FALSE);
1182 gst_pad_set_active (srcpad, FALSE);
1183
1184 gst_check_teardown_pad_by_name (rtpbin, "recv_rtp_src");
1185 gst_check_teardown_pad_by_name (rtpbin, "recv_rtp_sink");
1186 gst_check_teardown_element (rtpbin);
1187 }
1188
1189 GST_END_TEST;
1190
1191
GST_START_TEST(test_bufferlist_recv_permissible_gap)1192 GST_START_TEST (test_bufferlist_recv_permissible_gap)
1193 {
1194 GstElement *rtpbin;
1195 GstPad *srcpad;
1196 GstPad *sinkpad;
1197 GstCaps *caps;
1198 GstBufferList *list;
1199
1200 list = create_buffer_list_permissible_gap ();
1201 fail_unless (list != NULL);
1202
1203 rtpbin = gst_check_setup_element ("rtpsession");
1204
1205 srcpad =
1206 gst_check_setup_src_pad_by_name (rtpbin, &srctemplate, "recv_rtp_sink");
1207 fail_if (srcpad == NULL);
1208
1209 sinkpad =
1210 gst_check_setup_sink_pad_by_name (rtpbin, &sinktemplate, "recv_rtp_src");
1211 fail_if (sinkpad == NULL);
1212
1213 gst_pad_set_chain_list_function (sinkpad,
1214 GST_DEBUG_FUNCPTR (sink_chain_list_permissible_gap));
1215
1216 gst_pad_set_active (srcpad, TRUE);
1217 gst_pad_set_active (sinkpad, TRUE);
1218
1219 caps = gst_caps_from_string (TEST_CAPS);
1220 gst_check_setup_events (srcpad, rtpbin, caps, GST_FORMAT_TIME);
1221 gst_caps_unref (caps);
1222
1223 gst_element_set_state (rtpbin, GST_STATE_PLAYING);
1224
1225 chain_list_func_called = FALSE;
1226 fail_unless (gst_pad_push_list (srcpad, list) == GST_FLOW_OK);
1227 fail_if (chain_list_func_called == FALSE);
1228
1229 gst_pad_set_active (sinkpad, FALSE);
1230 gst_pad_set_active (srcpad, FALSE);
1231
1232 gst_check_teardown_pad_by_name (rtpbin, "recv_rtp_src");
1233 gst_check_teardown_pad_by_name (rtpbin, "recv_rtp_sink");
1234 gst_check_teardown_element (rtpbin);
1235 }
1236
1237 GST_END_TEST;
1238
1239
GST_START_TEST(test_bufferlist_recv_wrapping_seqnums)1240 GST_START_TEST (test_bufferlist_recv_wrapping_seqnums)
1241 {
1242 GstElement *rtpbin;
1243 GstPad *srcpad;
1244 GstPad *sinkpad;
1245 GstCaps *caps;
1246 GstBufferList *list;
1247
1248 list = create_buffer_list_wrapping_seqnums ();
1249 fail_unless (list != NULL);
1250
1251 rtpbin = gst_check_setup_element ("rtpsession");
1252
1253 srcpad =
1254 gst_check_setup_src_pad_by_name (rtpbin, &srctemplate, "recv_rtp_sink");
1255 fail_if (srcpad == NULL);
1256
1257 sinkpad =
1258 gst_check_setup_sink_pad_by_name (rtpbin, &sinktemplate, "recv_rtp_src");
1259 fail_if (sinkpad == NULL);
1260
1261 gst_pad_set_chain_list_function (sinkpad,
1262 GST_DEBUG_FUNCPTR (sink_chain_list_wrapping_seqnums));
1263
1264 gst_pad_set_active (srcpad, TRUE);
1265 gst_pad_set_active (sinkpad, TRUE);
1266
1267 caps = gst_caps_from_string (TEST_CAPS);
1268 gst_check_setup_events (srcpad, rtpbin, caps, GST_FORMAT_TIME);
1269 gst_caps_unref (caps);
1270
1271 gst_element_set_state (rtpbin, GST_STATE_PLAYING);
1272
1273 chain_list_func_called = FALSE;
1274 fail_unless (gst_pad_push_list (srcpad, list) == GST_FLOW_OK);
1275 fail_if (chain_list_func_called == FALSE);
1276
1277 gst_pad_set_active (sinkpad, FALSE);
1278 gst_pad_set_active (srcpad, FALSE);
1279
1280 gst_check_teardown_pad_by_name (rtpbin, "recv_rtp_src");
1281 gst_check_teardown_pad_by_name (rtpbin, "recv_rtp_sink");
1282 gst_check_teardown_element (rtpbin);
1283 }
1284
1285 GST_END_TEST;
1286
1287
GST_START_TEST(test_bufferlist_recv_large_jump_discarded)1288 GST_START_TEST (test_bufferlist_recv_large_jump_discarded)
1289 {
1290 GstElement *rtpbin;
1291 GstPad *srcpad;
1292 GstPad *sinkpad;
1293 GstCaps *caps;
1294 GstBufferList *list;
1295
1296 list = create_buffer_list_large_jump_discarded ();
1297 fail_unless (list != NULL);
1298
1299 rtpbin = gst_check_setup_element ("rtpsession");
1300
1301 srcpad =
1302 gst_check_setup_src_pad_by_name (rtpbin, &srctemplate, "recv_rtp_sink");
1303 fail_if (srcpad == NULL);
1304
1305 sinkpad =
1306 gst_check_setup_sink_pad_by_name (rtpbin, &sinktemplate, "recv_rtp_src");
1307 fail_if (sinkpad == NULL);
1308
1309 gst_pad_set_chain_list_function (sinkpad,
1310 GST_DEBUG_FUNCPTR (sink_chain_list_large_jump_discarded));
1311
1312 gst_pad_set_active (srcpad, TRUE);
1313 gst_pad_set_active (sinkpad, TRUE);
1314
1315 caps = gst_caps_from_string (TEST_CAPS);
1316 gst_check_setup_events (srcpad, rtpbin, caps, GST_FORMAT_TIME);
1317 gst_caps_unref (caps);
1318
1319 gst_element_set_state (rtpbin, GST_STATE_PLAYING);
1320
1321 chain_list_func_called = FALSE;
1322 fail_unless (gst_pad_push_list (srcpad, list) == GST_FLOW_OK);
1323 fail_if (chain_list_func_called == FALSE);
1324
1325 gst_pad_set_active (sinkpad, FALSE);
1326 gst_pad_set_active (srcpad, FALSE);
1327
1328 gst_check_teardown_pad_by_name (rtpbin, "recv_rtp_src");
1329 gst_check_teardown_pad_by_name (rtpbin, "recv_rtp_sink");
1330 gst_check_teardown_element (rtpbin);
1331 }
1332
1333 GST_END_TEST;
1334
1335
GST_START_TEST(test_bufferlist_recv_large_jump_recovery)1336 GST_START_TEST (test_bufferlist_recv_large_jump_recovery)
1337 {
1338 GstElement *rtpbin;
1339 GstPad *srcpad;
1340 GstPad *sinkpad;
1341 GstCaps *caps;
1342 GstBufferList *list;
1343
1344 list = create_buffer_list_large_jump_recovery ();
1345 fail_unless (list != NULL);
1346
1347 rtpbin = gst_check_setup_element ("rtpsession");
1348
1349 srcpad =
1350 gst_check_setup_src_pad_by_name (rtpbin, &srctemplate, "recv_rtp_sink");
1351 fail_if (srcpad == NULL);
1352
1353 sinkpad =
1354 gst_check_setup_sink_pad_by_name (rtpbin, &sinktemplate, "recv_rtp_src");
1355 fail_if (sinkpad == NULL);
1356
1357 gst_pad_set_chain_list_function (sinkpad,
1358 GST_DEBUG_FUNCPTR (sink_chain_list_large_jump_recovery));
1359
1360 gst_pad_set_active (srcpad, TRUE);
1361 gst_pad_set_active (sinkpad, TRUE);
1362
1363 caps = gst_caps_from_string (TEST_CAPS);
1364 gst_check_setup_events (srcpad, rtpbin, caps, GST_FORMAT_TIME);
1365 gst_caps_unref (caps);
1366
1367 gst_element_set_state (rtpbin, GST_STATE_PLAYING);
1368
1369 chain_list_func_called = FALSE;
1370 fail_unless (gst_pad_push_list (srcpad, list) == GST_FLOW_OK);
1371 fail_if (chain_list_func_called == FALSE);
1372
1373 gst_pad_set_active (sinkpad, FALSE);
1374 gst_pad_set_active (srcpad, FALSE);
1375
1376 gst_check_teardown_pad_by_name (rtpbin, "recv_rtp_src");
1377 gst_check_teardown_pad_by_name (rtpbin, "recv_rtp_sink");
1378 gst_check_teardown_element (rtpbin);
1379 }
1380
1381 GST_END_TEST;
1382
1383
GST_START_TEST(test_bufferlist_recv_reordered_packets)1384 GST_START_TEST (test_bufferlist_recv_reordered_packets)
1385 {
1386 GstElement *rtpbin;
1387 GstPad *srcpad;
1388 GstPad *sinkpad;
1389 GstCaps *caps;
1390 GstBufferList *list;
1391
1392 list = create_buffer_list_reordered_packets ();
1393 fail_unless (list != NULL);
1394
1395 rtpbin = gst_check_setup_element ("rtpsession");
1396
1397 srcpad =
1398 gst_check_setup_src_pad_by_name (rtpbin, &srctemplate, "recv_rtp_sink");
1399 fail_if (srcpad == NULL);
1400
1401 sinkpad =
1402 gst_check_setup_sink_pad_by_name (rtpbin, &sinktemplate, "recv_rtp_src");
1403 fail_if (sinkpad == NULL);
1404
1405 gst_pad_set_chain_list_function (sinkpad,
1406 GST_DEBUG_FUNCPTR (sink_chain_list_reordered_packets));
1407
1408 gst_pad_set_active (srcpad, TRUE);
1409 gst_pad_set_active (sinkpad, TRUE);
1410
1411 caps = gst_caps_from_string (TEST_CAPS);
1412 gst_check_setup_events (srcpad, rtpbin, caps, GST_FORMAT_TIME);
1413 gst_caps_unref (caps);
1414
1415 gst_element_set_state (rtpbin, GST_STATE_PLAYING);
1416
1417 chain_list_func_called = FALSE;
1418 fail_unless (gst_pad_push_list (srcpad, list) == GST_FLOW_OK);
1419 fail_if (chain_list_func_called == FALSE);
1420
1421 gst_pad_set_active (sinkpad, FALSE);
1422 gst_pad_set_active (srcpad, FALSE);
1423
1424 gst_check_teardown_pad_by_name (rtpbin, "recv_rtp_src");
1425 gst_check_teardown_pad_by_name (rtpbin, "recv_rtp_sink");
1426 gst_check_teardown_element (rtpbin);
1427 }
1428
1429 GST_END_TEST;
1430
GST_START_TEST(test_bufferlist_recv_different_frames)1431 GST_START_TEST (test_bufferlist_recv_different_frames)
1432 {
1433 GstElement *rtpbin;
1434 GstPad *srcpad;
1435 GstPad *sinkpad;
1436 GstCaps *caps;
1437 GstBufferList *list;
1438
1439 list = create_buffer_list_different_frames ();
1440 fail_unless (list != NULL);
1441
1442 rtpbin = gst_check_setup_element ("rtpsession");
1443
1444 srcpad =
1445 gst_check_setup_src_pad_by_name (rtpbin, &srctemplate, "recv_rtp_sink");
1446 fail_if (srcpad == NULL);
1447
1448 sinkpad =
1449 gst_check_setup_sink_pad_by_name (rtpbin, &sinktemplate, "recv_rtp_src");
1450 fail_if (sinkpad == NULL);
1451
1452 gst_pad_set_chain_list_function (sinkpad,
1453 GST_DEBUG_FUNCPTR (sink_chain_list_different_frames));
1454
1455 gst_pad_set_active (srcpad, TRUE);
1456 gst_pad_set_active (sinkpad, TRUE);
1457
1458 caps = gst_caps_from_string (TEST_CAPS);
1459 gst_check_setup_events (srcpad, rtpbin, caps, GST_FORMAT_TIME);
1460 gst_caps_unref (caps);
1461
1462 gst_element_set_state (rtpbin, GST_STATE_PLAYING);
1463
1464 chain_list_func_called = FALSE;
1465 fail_unless (gst_pad_push_list (srcpad, list) == GST_FLOW_OK);
1466 fail_if (chain_list_func_called == FALSE);
1467
1468 gst_pad_set_active (sinkpad, FALSE);
1469 gst_pad_set_active (srcpad, FALSE);
1470
1471 gst_check_teardown_pad_by_name (rtpbin, "recv_rtp_src");
1472 gst_check_teardown_pad_by_name (rtpbin, "recv_rtp_sink");
1473 gst_check_teardown_element (rtpbin);
1474 }
1475
1476 GST_END_TEST;
1477
1478
GST_START_TEST(test_bufferlist_recv_muxed_rtcp)1479 GST_START_TEST (test_bufferlist_recv_muxed_rtcp)
1480 {
1481 GstElement *rtpbin;
1482 GstPad *srcpad;
1483 GstPad *sinkpad;
1484 GstPad *srcpad_rtcp;
1485 GstPad *sinkpad_rtcp;
1486 GstCaps *caps;
1487 GstBufferList *list;
1488
1489 list = create_buffer_list_muxed_rtcp ();
1490 fail_unless (list != NULL);
1491
1492 rtpbin = gst_check_setup_element ("rtpsession");
1493
1494 srcpad =
1495 gst_check_setup_src_pad_by_name (rtpbin, &srctemplate, "recv_rtp_sink");
1496 fail_if (srcpad == NULL);
1497
1498 sinkpad =
1499 gst_check_setup_sink_pad_by_name (rtpbin, &sinktemplate, "recv_rtp_src");
1500 fail_if (sinkpad == NULL);
1501
1502 gst_pad_set_chain_list_function (sinkpad,
1503 GST_DEBUG_FUNCPTR (sink_chain_list_muxed_rtcp));
1504
1505 gst_pad_set_active (srcpad, TRUE);
1506 gst_pad_set_active (sinkpad, TRUE);
1507
1508 caps = gst_caps_from_string (TEST_CAPS);
1509 gst_check_setup_events (srcpad, rtpbin, caps, GST_FORMAT_TIME);
1510 gst_caps_unref (caps);
1511
1512 /*
1513 * Create supplementary pads after gst_check_setup_events() to avoid
1514 * a failure in gst_pad_create_stream_id().
1515 */
1516 srcpad_rtcp =
1517 gst_check_setup_src_pad_by_name (rtpbin, &srctemplate_rtcp,
1518 "recv_rtcp_sink");
1519 fail_if (srcpad_rtcp == NULL);
1520
1521 sinkpad_rtcp =
1522 gst_check_setup_sink_pad_by_name (rtpbin, &sinktemplate_rtcp, "sync_src");
1523 fail_if (sinkpad_rtcp == NULL);
1524
1525 gst_pad_set_chain_function (sinkpad_rtcp,
1526 GST_DEBUG_FUNCPTR (sink_chain_muxed_rtcp));
1527
1528 gst_pad_set_active (srcpad_rtcp, TRUE);
1529 gst_pad_set_active (sinkpad_rtcp, TRUE);
1530
1531 gst_element_set_state (rtpbin, GST_STATE_PLAYING);
1532
1533 chain_list_func_called = FALSE;
1534 rtcp_packets = 0;
1535 fail_unless (gst_pad_push_list (srcpad, list) == GST_FLOW_OK);
1536 fail_if (chain_list_func_called == FALSE);
1537 fail_unless (rtcp_packets == 1);
1538
1539 gst_pad_set_active (sinkpad_rtcp, FALSE);
1540 gst_pad_set_active (srcpad_rtcp, FALSE);
1541 gst_pad_set_active (sinkpad, FALSE);
1542 gst_pad_set_active (srcpad, FALSE);
1543
1544 gst_check_teardown_pad_by_name (rtpbin, "sync_src");
1545 gst_check_teardown_pad_by_name (rtpbin, "recv_rtcp_sink");
1546 gst_check_teardown_pad_by_name (rtpbin, "recv_rtp_src");
1547 gst_check_teardown_pad_by_name (rtpbin, "recv_rtp_sink");
1548 gst_check_teardown_element (rtpbin);
1549 }
1550
1551 GST_END_TEST;
1552
1553
GST_START_TEST(test_bufferlist_recv_muxed_invalid)1554 GST_START_TEST (test_bufferlist_recv_muxed_invalid)
1555 {
1556 GstElement *rtpbin;
1557 GstPad *srcpad;
1558 GstPad *sinkpad;
1559 GstCaps *caps;
1560 GstBufferList *list;
1561
1562 list = create_buffer_list_muxed_invalid ();
1563 fail_unless (list != NULL);
1564
1565 rtpbin = gst_check_setup_element ("rtpsession");
1566
1567 srcpad =
1568 gst_check_setup_src_pad_by_name (rtpbin, &srctemplate, "recv_rtp_sink");
1569 fail_if (srcpad == NULL);
1570
1571 sinkpad =
1572 gst_check_setup_sink_pad_by_name (rtpbin, &sinktemplate, "recv_rtp_src");
1573 fail_if (sinkpad == NULL);
1574
1575 gst_pad_set_chain_list_function (sinkpad,
1576 GST_DEBUG_FUNCPTR (sink_chain_list_muxed_invalid));
1577
1578 gst_pad_set_active (srcpad, TRUE);
1579 gst_pad_set_active (sinkpad, TRUE);
1580
1581 caps = gst_caps_from_string (TEST_CAPS);
1582 gst_check_setup_events (srcpad, rtpbin, caps, GST_FORMAT_TIME);
1583 gst_caps_unref (caps);
1584
1585 gst_element_set_state (rtpbin, GST_STATE_PLAYING);
1586
1587 chain_list_func_called = FALSE;
1588 fail_unless (gst_pad_push_list (srcpad, list) == GST_FLOW_OK);
1589 fail_if (chain_list_func_called == FALSE);
1590
1591 gst_pad_set_active (sinkpad, FALSE);
1592 gst_pad_set_active (srcpad, FALSE);
1593
1594 gst_check_teardown_pad_by_name (rtpbin, "recv_rtp_src");
1595 gst_check_teardown_pad_by_name (rtpbin, "recv_rtp_sink");
1596 gst_check_teardown_element (rtpbin);
1597 }
1598
1599 GST_END_TEST;
1600
1601
1602 static Suite *
bufferlist_suite(void)1603 bufferlist_suite (void)
1604 {
1605 Suite *s = suite_create ("BufferList");
1606
1607 TCase *tc_chain = tcase_create ("general");
1608
1609 /* time out after 30s. */
1610 tcase_set_timeout (tc_chain, 10);
1611
1612 suite_add_tcase (s, tc_chain);
1613 tcase_add_test (tc_chain, test_bufferlist);
1614 tcase_add_test (tc_chain, test_bufferlist_recv);
1615 tcase_add_test (tc_chain, test_bufferlist_recv_probation_failed);
1616 tcase_add_test (tc_chain, test_bufferlist_recv_permissible_gap);
1617 tcase_add_test (tc_chain, test_bufferlist_recv_wrapping_seqnums);
1618 tcase_add_test (tc_chain, test_bufferlist_recv_large_jump_discarded);
1619 tcase_add_test (tc_chain, test_bufferlist_recv_large_jump_recovery);
1620 tcase_add_test (tc_chain, test_bufferlist_recv_reordered_packets);
1621 tcase_add_test (tc_chain, test_bufferlist_recv_different_frames);
1622 tcase_add_test (tc_chain, test_bufferlist_recv_muxed_rtcp);
1623 tcase_add_test (tc_chain, test_bufferlist_recv_muxed_invalid);
1624
1625 return s;
1626 }
1627
1628 GST_CHECK_MAIN (bufferlist);
1629