blob: 095fb1648db57368da440c56aa7fb5ae8c7cb947 [file] [log] [blame]
Olivier Naudan988c6f02012-04-16 07:16:25 -04001/* GStreamer
2 *
3 * Copyright (C) 2009 Nokia Corporation and its subsidary(-ies)
4 * contact: <stefan.kost@nokia.com>
Sebastian Dröge5f0bab02013-07-14 11:42:29 +02005 * Copyright (C) 2012 Cisco Systems, Inc
6 * Authors: Kelley Rogers <kelro@cisco.com>
7 * Havard Graff <hgraff@cisco.com>
Sebastian Drögee08b7df2016-09-30 12:19:10 +03008 * Copyright (C) 2013-2016 Pexip AS
Sebastian Drögeb04f9722015-08-19 13:19:08 +03009 * Stian Selnes <stian@pexip>
10 * Havard Graff <havard@pexip>
Olivier Naudan988c6f02012-04-16 07:16:25 -040011 *
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
16 *
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this library; if not, write to the
Sebastian Dröge5f0bab02013-07-14 11:42:29 +020024 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
25 * Boston, MA 02110-1301, USA.
Olivier Naudan988c6f02012-04-16 07:16:25 -040026 */
27
28#include <gst/check/gstcheck.h>
Sebastian Dröge5f0bab02013-07-14 11:42:29 +020029#include <gst/check/gsttestclock.h>
Sebastian Drögeb04f9722015-08-19 13:19:08 +030030#include <gst/check/gstharness.h>
Olivier Naudan988c6f02012-04-16 07:16:25 -040031
Sebastian Dröge73cae222013-09-19 12:45:10 +020032#include <gst/rtp/gstrtpbuffer.h>
33
Olivier Naudan988c6f02012-04-16 07:16:25 -040034/* For ease of programming we use globals to keep refs for our floating
35 * src and sink pads we create; otherwise we always have to do get_pad,
36 * get_peer, and then remove references in every test function */
37static GstPad *mysrcpad, *mysinkpad;
38/* we also have a list of src buffers */
39static GList *inbuffers = NULL;
40static gint num_dropped = 0;
41
42#define RTP_CAPS_STRING \
43 "application/x-rtp, " \
44 "media = (string)audio, " \
45 "payload = (int) 0, " \
46 "clock-rate = (int) 8000, " \
47 "encoding-name = (string)PCMU"
48
49#define RTP_FRAME_SIZE 20
50
51static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
52 GST_PAD_SINK,
53 GST_PAD_ALWAYS,
54 GST_STATIC_CAPS ("application/x-rtp")
55 );
56static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
57 GST_PAD_SRC,
58 GST_PAD_ALWAYS,
59 GST_STATIC_CAPS ("application/x-rtp, "
60 "clock-rate = (int) [ 1, 2147483647 ]")
61 );
62
63static void
64buffer_dropped (gpointer data, GstMiniObject * obj)
65{
66 GST_DEBUG ("dropping buffer %p", obj);
67 num_dropped++;
68}
69
70static GstElement *
71setup_jitterbuffer (gint num_buffers)
72{
73 GstElement *jitterbuffer;
74 GstClock *clock;
75 GstBuffer *buffer;
76 GstCaps *caps;
77 /* a 20 sample audio block (2,5 ms) generated with
78 * gst-launch audiotestsrc wave=silence blocksize=40 num-buffers=3 !
79 * "audio/x-raw,channels=1,rate=8000" ! mulawenc ! rtppcmupay !
80 * fakesink dump=1
81 */
Sebastian Drögeb04f9722015-08-19 13:19:08 +030082 guint8 in[] = {
83 /* first 4 bytes are rtp-header, next 4 bytes are timestamp */
Olivier Naudan988c6f02012-04-16 07:16:25 -040084 0x80, 0x80, 0x1c, 0x24, 0x46, 0xcd, 0xb7, 0x11, 0x3c, 0x3a, 0x7c, 0x5b,
85 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
86 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
87 };
88 GstClockTime ts = G_GUINT64_CONSTANT (0);
89 GstClockTime tso = gst_util_uint64_scale (RTP_FRAME_SIZE, GST_SECOND, 8000);
90 /*guint latency = GST_TIME_AS_MSECONDS (num_buffers * tso); */
91 gint i;
92
93 GST_DEBUG ("setup_jitterbuffer");
94 jitterbuffer = gst_check_setup_element ("rtpjitterbuffer");
95 /* we need a clock here */
96 clock = gst_system_clock_obtain ();
97 gst_element_set_clock (jitterbuffer, clock);
98 gst_object_unref (clock);
99 /* setup latency */
100 /* latency would be 7 for 3 buffers here, default is 200
101 g_object_set (G_OBJECT (jitterbuffer), "latency", latency, NULL);
102 GST_INFO_OBJECT (jitterbuffer, "set latency to %u ms", latency);
103 */
104
105 mysrcpad = gst_check_setup_src_pad (jitterbuffer, &srctemplate);
106 mysinkpad = gst_check_setup_sink_pad (jitterbuffer, &sinktemplate);
107 gst_pad_set_active (mysrcpad, TRUE);
108 gst_pad_set_active (mysinkpad, TRUE);
109
110 /* create n buffers */
111 caps = gst_caps_from_string (RTP_CAPS_STRING);
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200112 gst_check_setup_events (mysrcpad, jitterbuffer, caps, GST_FORMAT_TIME);
Olivier Naudan988c6f02012-04-16 07:16:25 -0400113 gst_caps_unref (caps);
114
115 for (i = 0; i < num_buffers; i++) {
116 buffer = gst_buffer_new_and_alloc (sizeof (in));
117 gst_buffer_fill (buffer, 0, in, sizeof (in));
Sebastian Dröge45626bf2013-09-24 16:47:44 +0200118 GST_BUFFER_DTS (buffer) = ts;
119 GST_BUFFER_PTS (buffer) = ts;
Olivier Naudan988c6f02012-04-16 07:16:25 -0400120 GST_BUFFER_DURATION (buffer) = tso;
121 gst_mini_object_weak_ref (GST_MINI_OBJECT (buffer), buffer_dropped, NULL);
122 GST_DEBUG ("created buffer: %p", buffer);
123
124 if (!i)
125 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
126
127 inbuffers = g_list_append (inbuffers, buffer);
128
129 /* hackish way to update the rtp header */
130 in[1] = 0x00;
131 in[3]++; /* seqnumber */
132 in[7] += RTP_FRAME_SIZE; /* inc. timestamp with framesize */
133 ts += tso;
134 }
135 num_dropped = 0;
136
137 return jitterbuffer;
138}
139
140static GstStateChangeReturn
141start_jitterbuffer (GstElement * jitterbuffer)
142{
143 GstStateChangeReturn ret;
144 GstClockTime now;
145 GstClock *clock;
146
147 clock = gst_element_get_clock (jitterbuffer);
148 now = gst_clock_get_time (clock);
149 gst_object_unref (clock);
150
151 gst_element_set_base_time (jitterbuffer, now);
152 ret = gst_element_set_state (jitterbuffer, GST_STATE_PLAYING);
153
154 return ret;
155}
156
157static void
158cleanup_jitterbuffer (GstElement * jitterbuffer)
159{
160 GST_DEBUG ("cleanup_jitterbuffer");
161
162 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
163 g_list_free (buffers);
164 buffers = NULL;
165
166 g_list_free (inbuffers);
167 inbuffers = NULL;
168
169 gst_pad_set_active (mysrcpad, FALSE);
170 gst_pad_set_active (mysinkpad, FALSE);
171 gst_check_teardown_src_pad (jitterbuffer);
172 gst_check_teardown_sink_pad (jitterbuffer);
173 gst_check_teardown_element (jitterbuffer);
174}
175
176static void
177check_jitterbuffer_results (GstElement * jitterbuffer, gint num_buffers)
178{
179 GstBuffer *buffer;
180 GList *node;
181 GstClockTime ts = G_GUINT64_CONSTANT (0);
182 GstClockTime tso = gst_util_uint64_scale (RTP_FRAME_SIZE, GST_SECOND, 8000);
183 GstMapInfo map;
184 guint16 prev_sn = 0, cur_sn;
185 guint32 prev_ts = 0, cur_ts;
186
187 /* sleep for twice the latency */
188 g_usleep (400 * 1000);
189
190 GST_INFO ("of %d buffer %d/%d received/dropped", num_buffers,
191 g_list_length (buffers), num_dropped);
192 /* if this fails, not all buffers have been processed */
193 fail_unless_equals_int ((g_list_length (buffers) + num_dropped), num_buffers);
194
195 /* check the buffer list */
196 fail_unless_equals_int (g_list_length (buffers), num_buffers);
197 for (node = buffers; node; node = g_list_next (node)) {
198 fail_if ((buffer = (GstBuffer *) node->data) == NULL);
Sebastian Dröge45626bf2013-09-24 16:47:44 +0200199 fail_if (GST_BUFFER_PTS (buffer) != ts);
200 fail_if (GST_BUFFER_DTS (buffer) != ts);
Olivier Naudan988c6f02012-04-16 07:16:25 -0400201 gst_buffer_map (buffer, &map, GST_MAP_READ);
202 cur_sn = ((guint16) map.data[2] << 8) | map.data[3];
203 cur_ts = ((guint32) map.data[4] << 24) | ((guint32) map.data[5] << 16) |
204 ((guint32) map.data[6] << 8) | map.data[7];
205 gst_buffer_unmap (buffer, &map);
206
207 if (node != buffers) {
208 fail_unless (cur_sn > prev_sn);
209 fail_unless (cur_ts > prev_ts);
210
211 prev_sn = cur_sn;
212 prev_ts = cur_ts;
213 }
214 ts += tso;
215 }
216}
217
218GST_START_TEST (test_push_forward_seq)
219{
220 GstElement *jitterbuffer;
221 const guint num_buffers = 3;
222 GstBuffer *buffer;
223 GList *node;
224
225 jitterbuffer = setup_jitterbuffer (num_buffers);
226 fail_unless (start_jitterbuffer (jitterbuffer)
227 == GST_STATE_CHANGE_SUCCESS, "could not set to playing");
228
229 /* push buffers: 0,1,2, */
230 for (node = inbuffers; node; node = g_list_next (node)) {
231 buffer = (GstBuffer *) node->data;
232 fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
233 }
234
235 /* check the buffer list */
236 check_jitterbuffer_results (jitterbuffer, num_buffers);
237
238 /* cleanup */
239 cleanup_jitterbuffer (jitterbuffer);
240}
241
242GST_END_TEST;
243
244GST_START_TEST (test_push_backward_seq)
245{
246 GstElement *jitterbuffer;
247 const guint num_buffers = 4;
248 GstBuffer *buffer;
249 GList *node;
250
251 jitterbuffer = setup_jitterbuffer (num_buffers);
252 fail_unless (start_jitterbuffer (jitterbuffer)
253 == GST_STATE_CHANGE_SUCCESS, "could not set to playing");
254
255 /* push buffers: 0,3,2,1 */
256 buffer = (GstBuffer *) inbuffers->data;
257 fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
258 for (node = g_list_last (inbuffers); node != inbuffers;
259 node = g_list_previous (node)) {
260 buffer = (GstBuffer *) node->data;
261 fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
262 }
263
264 /* check the buffer list */
265 check_jitterbuffer_results (jitterbuffer, num_buffers);
266
267 /* cleanup */
268 cleanup_jitterbuffer (jitterbuffer);
269}
270
271GST_END_TEST;
272
273GST_START_TEST (test_push_unordered)
274{
275 GstElement *jitterbuffer;
276 const guint num_buffers = 4;
277 GstBuffer *buffer;
278
279 jitterbuffer = setup_jitterbuffer (num_buffers);
280 fail_unless (start_jitterbuffer (jitterbuffer)
281 == GST_STATE_CHANGE_SUCCESS, "could not set to playing");
282
283 /* push buffers; 0,2,1,3 */
284 buffer = (GstBuffer *) inbuffers->data;
285 fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
286 buffer = g_list_nth_data (inbuffers, 2);
287 fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
288 buffer = g_list_nth_data (inbuffers, 1);
289 fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
290 buffer = g_list_nth_data (inbuffers, 3);
291 fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
292
293 /* check the buffer list */
294 check_jitterbuffer_results (jitterbuffer, num_buffers);
295
296 /* cleanup */
297 cleanup_jitterbuffer (jitterbuffer);
298}
299
300GST_END_TEST;
301
302GST_START_TEST (test_basetime)
303{
304 GstElement *jitterbuffer;
305 const guint num_buffers = 3;
306 GstBuffer *buffer;
307 GList *node;
308 GstClockTime tso = gst_util_uint64_scale (RTP_FRAME_SIZE, GST_SECOND, 8000);
309
310 jitterbuffer = setup_jitterbuffer (num_buffers);
311 fail_unless (start_jitterbuffer (jitterbuffer)
312 == GST_STATE_CHANGE_SUCCESS, "could not set to playing");
313
314 /* push buffers: 2,1,0 */
315 for (node = g_list_last (inbuffers); node; node = g_list_previous (node)) {
316 buffer = (GstBuffer *) node->data;
317 fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
318 }
319
320 /* sleep for twice the latency */
321 g_usleep (400 * 1000);
322
323 /* if this fails, not all buffers have been processed */
324 fail_unless_equals_int ((g_list_length (buffers) + num_dropped), num_buffers);
325
326 buffer = (GstBuffer *) buffers->data;
Sebastian Dröge45626bf2013-09-24 16:47:44 +0200327 fail_unless (GST_BUFFER_DTS (buffer) != (num_buffers * tso));
328 fail_unless (GST_BUFFER_PTS (buffer) != (num_buffers * tso));
Olivier Naudan988c6f02012-04-16 07:16:25 -0400329
330 /* cleanup */
331 cleanup_jitterbuffer (jitterbuffer);
332}
333
334GST_END_TEST;
335
Sebastian Dröge42103d12013-12-27 10:59:10 +0100336static GstCaps *
337request_pt_map (GstElement * jitterbuffer, guint pt)
338{
339 fail_unless (pt == 0);
340
341 return gst_caps_from_string (RTP_CAPS_STRING);
342}
343
344GST_START_TEST (test_clear_pt_map)
345{
346 GstElement *jitterbuffer;
347 const guint num_buffers = 10;
348 gint i;
349 GstBuffer *buffer;
350 GList *node;
351
352 jitterbuffer = setup_jitterbuffer (num_buffers);
353 fail_unless (start_jitterbuffer (jitterbuffer)
354 == GST_STATE_CHANGE_SUCCESS, "could not set to playing");
355
356 g_signal_connect (jitterbuffer, "request-pt-map", (GCallback)
357 request_pt_map, NULL);
358
359 /* push buffers: 0,1,2, */
360 for (node = inbuffers, i = 0; node && i < 3; node = g_list_next (node), i++) {
361 buffer = (GstBuffer *) node->data;
362 fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
363 }
364
365 g_usleep (400 * 1000);
366
367 g_signal_emit_by_name (jitterbuffer, "clear-pt-map", NULL);
368
369 for (; node && i < 10; node = g_list_next (node), i++) {
370 buffer = (GstBuffer *) node->data;
371 fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
372 }
373
374 /* check the buffer list */
375 check_jitterbuffer_results (jitterbuffer, num_buffers);
376
377 /* cleanup */
378 cleanup_jitterbuffer (jitterbuffer);
379}
380
381GST_END_TEST;
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300382
383#define PCMU_BUF_CLOCK_RATE 8000
384#define PCMU_BUF_PT 0
385#define PCMU_BUF_SSRC 0x01BADBAD
386#define PCMU_BUF_MS 20
387#define PCMU_BUF_DURATION (PCMU_BUF_MS * GST_MSECOND)
388#define PCMU_BUF_SIZE (64000 * PCMU_BUF_MS / 1000)
389#define PCMU_RTP_TS_DURATION (PCMU_BUF_CLOCK_RATE * PCMU_BUF_MS / 1000)
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200390
391typedef struct
392{
393 GstElement *jitter_buffer;
394 GstPad *test_sink_pad, *test_src_pad;
395 GstClock *clock;
396 GAsyncQueue *buf_queue;
Sebastian Dröge45626bf2013-09-24 16:47:44 +0200397 GAsyncQueue *sink_event_queue;
398 GAsyncQueue *src_event_queue;
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200399 gint lost_event_count;
Sebastian Dröge45626bf2013-09-24 16:47:44 +0200400 gint rtx_event_count;
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200401} TestData;
402
403static GstCaps *
404generate_caps (void)
405{
406 return gst_caps_new_simple ("application/x-rtp",
407 "media", G_TYPE_STRING, "audio",
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300408 "clock-rate", G_TYPE_INT, PCMU_BUF_CLOCK_RATE,
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200409 "encoding-name", G_TYPE_STRING, "PCMU",
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300410 "payload", G_TYPE_INT, PCMU_BUF_PT,
411 "ssrc", G_TYPE_UINT, PCMU_BUF_SSRC, NULL);
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200412}
413
414static GstBuffer *
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300415generate_test_buffer_full (GstClockTime gst_ts,
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200416 gboolean marker_bit, guint seq_num, guint32 rtp_ts)
417{
418 GstBuffer *buf;
419 guint8 *payload;
420 guint i;
Sebastian Dröge73cae222013-09-19 12:45:10 +0200421 GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200422
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300423 buf = gst_rtp_buffer_new_allocate (PCMU_BUF_SIZE, 0, 0);
Sebastian Dröge45626bf2013-09-24 16:47:44 +0200424 GST_BUFFER_DTS (buf) = gst_ts;
425 GST_BUFFER_PTS (buf) = gst_ts;
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200426
Sebastian Dröge73cae222013-09-19 12:45:10 +0200427 gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtp);
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300428 gst_rtp_buffer_set_payload_type (&rtp, PCMU_BUF_PT);
Sebastian Dröge73cae222013-09-19 12:45:10 +0200429 gst_rtp_buffer_set_marker (&rtp, marker_bit);
430 gst_rtp_buffer_set_seq (&rtp, seq_num);
431 gst_rtp_buffer_set_timestamp (&rtp, rtp_ts);
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300432 gst_rtp_buffer_set_ssrc (&rtp, PCMU_BUF_SSRC);
Sebastian Dröge73cae222013-09-19 12:45:10 +0200433
434 payload = gst_rtp_buffer_get_payload (&rtp);
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300435 for (i = 0; i < PCMU_BUF_SIZE; i++)
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200436 payload[i] = 0xff;
437
Sebastian Dröge73cae222013-09-19 12:45:10 +0200438 gst_rtp_buffer_unmap (&rtp);
439
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200440 return buf;
441}
442
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300443static GstBuffer *
444generate_test_buffer (guint seq_num)
445{
446 return generate_test_buffer_full (seq_num * PCMU_BUF_DURATION,
447 TRUE, seq_num, seq_num * PCMU_RTP_TS_DURATION);
448}
449
Sebastian Drögee08b7df2016-09-30 12:19:10 +0300450static GstBuffer *
451generate_test_buffer_rtx (GstClockTime dts, guint seq_num)
452{
453 GstBuffer *buffer = generate_test_buffer_full (dts, TRUE, seq_num,
454 seq_num * PCMU_RTP_TS_DURATION);
455 GST_BUFFER_FLAG_SET (buffer, GST_RTP_BUFFER_FLAG_RETRANSMISSION);
456 return buffer;
457}
458
Sebastian Drögec9e739b2016-03-01 17:11:14 +0200459static gint
460get_rtp_seq_num (GstBuffer * buf)
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200461{
Sebastian Drögec9e739b2016-03-01 17:11:14 +0200462 GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
463 gint seq;
464 gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
465 seq = gst_rtp_buffer_get_seq (&rtp);
466 gst_rtp_buffer_unmap (&rtp);
467 return seq;
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200468}
469
470static void
Sebastian Dröge0afcd5c2016-06-09 11:25:16 +0300471verify_lost_event (GstEvent * event, guint16 expected_seqnum,
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300472 GstClockTime expected_timestamp, GstClockTime expected_duration)
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200473{
474 const GstStructure *s = gst_event_get_structure (event);
475 const GValue *value;
476 guint32 seqnum;
477 GstClockTime timestamp;
478 GstClockTime duration;
Sebastian Dröge45626bf2013-09-24 16:47:44 +0200479
Sebastian Drögec9e739b2016-03-01 17:11:14 +0200480 fail_unless (event != NULL);
481 fail_unless (gst_structure_get_uint (s, "seqnum", &seqnum));
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200482
483 value = gst_structure_get_value (s, "timestamp");
484 g_assert (value && G_VALUE_HOLDS_UINT64 (value));
485 timestamp = g_value_get_uint64 (value);
486
487 value = gst_structure_get_value (s, "duration");
Sebastian Drögec9e739b2016-03-01 17:11:14 +0200488 fail_unless (value && G_VALUE_HOLDS_UINT64 (value));
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200489 duration = g_value_get_uint64 (value);
490
Sebastian Drögec9e739b2016-03-01 17:11:14 +0200491 fail_unless_equals_int (expected_seqnum, seqnum);
492 fail_unless_equals_int (expected_timestamp, timestamp);
493 fail_unless_equals_int (expected_duration, duration);
Sebastian Drögea4b66f92014-05-03 18:59:27 +0200494
495 gst_event_unref (event);
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200496}
497
Sebastian Dröge45626bf2013-09-24 16:47:44 +0200498static void
499verify_rtx_event (GstEvent * event, guint32 expected_seqnum,
500 GstClockTime expected_timestamp, guint expected_delay,
501 GstClockTime expected_spacing)
502{
503 const GstStructure *s = gst_event_get_structure (event);
504 const GValue *value;
505 guint32 seqnum;
506 GstClockTime timestamp, spacing;
507 guint delay;
508
Sebastian Drögec9e739b2016-03-01 17:11:14 +0200509 fail_unless (event);
510 fail_unless (gst_structure_get_uint (s, "seqnum", &seqnum));
Sebastian Dröge45626bf2013-09-24 16:47:44 +0200511
512 value = gst_structure_get_value (s, "running-time");
Sebastian Drögec9e739b2016-03-01 17:11:14 +0200513 fail_unless (value && G_VALUE_HOLDS_UINT64 (value));
Sebastian Dröge45626bf2013-09-24 16:47:44 +0200514 timestamp = g_value_get_uint64 (value);
515
516 value = gst_structure_get_value (s, "delay");
Sebastian Drögec9e739b2016-03-01 17:11:14 +0200517 fail_unless (value && G_VALUE_HOLDS_UINT (value));
Sebastian Dröge45626bf2013-09-24 16:47:44 +0200518 delay = g_value_get_uint (value);
519
520 value = gst_structure_get_value (s, "packet-spacing");
Sebastian Drögec9e739b2016-03-01 17:11:14 +0200521 fail_unless (value && G_VALUE_HOLDS_UINT64 (value));
Sebastian Dröge45626bf2013-09-24 16:47:44 +0200522 spacing = g_value_get_uint64 (value);
523
Sebastian Drögec9e739b2016-03-01 17:11:14 +0200524 fail_unless_equals_int (expected_seqnum, seqnum);
525 fail_unless_equals_int (expected_timestamp, timestamp);
526 fail_unless_equals_int (expected_delay, delay);
527 fail_unless_equals_int (expected_spacing, spacing);
Sebastian Drögea4b66f92014-05-03 18:59:27 +0200528
529 gst_event_unref (event);
Sebastian Dröge45626bf2013-09-24 16:47:44 +0200530}
531
Sebastian Drögee08b7df2016-09-30 12:19:10 +0300532static gboolean
533verify_jb_stats (GstElement * jb, GstStructure * expected)
534{
535 gboolean ret;
536 GstStructure *actual;
537 g_object_get (jb, "stats", &actual, NULL);
538
539 ret = gst_structure_is_subset (actual, expected);
540
541 if (!ret) {
542 gchar *e_str = gst_structure_to_string (expected);
543 gchar *a_str = gst_structure_to_string (actual);
544 fail_unless (ret, "%s is not a subset of %s", e_str, a_str);
545 g_free (e_str);
546 g_free (a_str);
547 }
548
549 gst_structure_free (expected);
550 gst_structure_free (actual);
551
552 return ret;
553}
554
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200555GST_START_TEST (test_only_one_lost_event_on_large_gaps)
556{
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300557 GstHarness *h = gst_harness_new ("rtpjitterbuffer");
558 GstTestClock *testclock;
Sebastian Dröge73cae222013-09-19 12:45:10 +0200559 GstClockID id, test_id;
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300560 GstBuffer *out_buf;
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200561 GstEvent *out_event;
562 gint jb_latency_ms = 200;
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300563 gint num_lost_events = jb_latency_ms / PCMU_BUF_MS;
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200564
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300565 gst_harness_set_src_caps (h, generate_caps ());
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300566 testclock = gst_harness_get_testclock (h);
Sebastian Drögefd64c292016-09-01 12:04:20 +0300567 /* Need to set max-misorder-time and max-dropout-time to 0 so the
568 * jitterbuffer does not base them on packet rate calculations.
569 * If it does, out gap is big enough to be considered a new stream and
570 * we wait for a few consecutive packets just to be sure
571 */
572 g_object_set (h->element, "do-lost", TRUE, "latency", jb_latency_ms,
573 "max-misorder-time", 0, "max-dropout-time", 0, NULL);
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200574
Sebastian Dröge73cae222013-09-19 12:45:10 +0200575 /* push the first buffer in */
Sebastian Drögec9e739b2016-03-01 17:11:14 +0200576 fail_unless_equals_int (GST_FLOW_OK,
577 gst_harness_push (h, generate_test_buffer (0)));
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200578
Sebastian Dröge73cae222013-09-19 12:45:10 +0200579 /* wait for the first buffer to be synced to timestamp + latency */
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300580 gst_test_clock_wait_for_next_pending_id (testclock, &id);
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200581
Sebastian Dröge73cae222013-09-19 12:45:10 +0200582 /* increase the time to timestamp + latency and release the wait */
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300583 gst_test_clock_set_time (testclock, jb_latency_ms * GST_MSECOND);
584 test_id = gst_test_clock_process_next_clock_id (testclock);
585 fail_unless (id == test_id);
Sebastian Drögea4b66f92014-05-03 18:59:27 +0200586 gst_clock_id_unref (test_id);
587 gst_clock_id_unref (id);
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200588
Sebastian Dröge73cae222013-09-19 12:45:10 +0200589 /* check for the buffer coming out that was pushed in */
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300590 out_buf = gst_harness_pull (h);
Sebastian Drögec9e739b2016-03-01 17:11:14 +0200591 fail_unless_equals_uint64 (0, GST_BUFFER_DTS (out_buf));
592 fail_unless_equals_uint64 (0, GST_BUFFER_PTS (out_buf));
Sebastian Drögea4b66f92014-05-03 18:59:27 +0200593 gst_buffer_unref (out_buf);
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200594
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300595 /* move time ahead to just before 10 seconds */
596 gst_test_clock_set_time (testclock, 10 * GST_SECOND - 1);
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200597
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300598 /* check that we have no pending waits */
599 fail_unless_equals_int (0, gst_test_clock_peek_id_count (testclock));
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200600
Sebastian Dröge73cae222013-09-19 12:45:10 +0200601 /* a buffer now arrives perfectly on time */
Sebastian Drögec9e739b2016-03-01 17:11:14 +0200602 fail_unless_equals_int (GST_FLOW_OK,
603 gst_harness_push (h, generate_test_buffer (500)));
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200604
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300605 /* release the wait, advancing the clock to 10 sec */
Sebastian Drögec9e739b2016-03-01 17:11:14 +0200606 fail_unless (gst_harness_crank_single_clock_wait (h));
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200607
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300608 /* drop GstEventStreamStart & GstEventCaps & GstEventSegment */
609 for (int i = 0; i < 3; i++)
610 gst_event_unref (gst_harness_pull_event (h));
611
612 /* we should now receive a packet-lost-event for buffers 1 through 489 ... */
613 out_event = gst_harness_pull_event (h);
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300614 verify_lost_event (out_event, 1, 1 * PCMU_BUF_DURATION,
615 PCMU_BUF_DURATION * 489);
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200616
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300617 /* ... as well as 490 (since at 10 sec 490 is too late) */
618 out_event = gst_harness_pull_event (h);
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300619 verify_lost_event (out_event, 490, 490 * PCMU_BUF_DURATION,
620 PCMU_BUF_DURATION);
621
622 /* we get as many lost events as the the number of *
623 * buffers the jitterbuffer is able to wait for */
624 for (int i = 1; i < num_lost_events; i++) {
Sebastian Drögec9e739b2016-03-01 17:11:14 +0200625 fail_unless (gst_harness_crank_single_clock_wait (h));
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300626 out_event = gst_harness_pull_event (h);
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300627 verify_lost_event (out_event, 490 + i, (490 + i) * PCMU_BUF_DURATION,
628 PCMU_BUF_DURATION);
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200629 }
630
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300631 /* and then the buffer is released */
632 out_buf = gst_harness_pull (h);
Sebastian Drögec9e739b2016-03-01 17:11:14 +0200633 fail_unless (GST_BUFFER_FLAG_IS_SET (out_buf, GST_BUFFER_FLAG_DISCONT));
634 fail_unless_equals_int (500, get_rtp_seq_num (out_buf));
635 fail_unless_equals_uint64 (10 * GST_SECOND, GST_BUFFER_DTS (out_buf));
636 fail_unless_equals_uint64 (10 * GST_SECOND, GST_BUFFER_PTS (out_buf));
Sebastian Drögea4b66f92014-05-03 18:59:27 +0200637 gst_buffer_unref (out_buf);
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200638
Sebastian Drögee08b7df2016-09-30 12:19:10 +0300639 fail_unless (verify_jb_stats (h->element,
640 gst_structure_new ("application/x-rtp-jitterbuffer-stats",
641 "num-lost", G_TYPE_UINT64, (guint64) 499, NULL)));
642
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300643 gst_object_unref (testclock);
644 gst_harness_teardown (h);
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200645}
646
647GST_END_TEST;
648
649GST_START_TEST (test_two_lost_one_arrives_in_time)
650{
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300651 GstHarness *h = gst_harness_new ("rtpjitterbuffer");
652 GstTestClock *testclock;
653 GstClockID id;
654 GstBuffer *out_buf;
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200655 GstEvent *out_event;
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300656 gint jb_latency_ms = 100; /* FIXME: setting this to 10 produces a
657 * strange result (30ms lost event),
658 * find out why! */
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300659 GstClockTime buffer_time;
660 gint b;
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200661
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300662 gst_harness_set_src_caps (h, generate_caps ());
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300663 testclock = gst_harness_get_testclock (h);
664 g_object_set (h->element, "do-lost", TRUE, "latency", jb_latency_ms, NULL);
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200665
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300666 /* push the first buffer through */
Sebastian Drögec9e739b2016-03-01 17:11:14 +0200667 fail_unless_equals_int (GST_FLOW_OK,
668 gst_harness_push (h, generate_test_buffer (0)));
669 fail_unless (gst_harness_crank_single_clock_wait (h));
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300670 gst_buffer_unref (gst_harness_pull (h));
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200671
Sebastian Dröge73cae222013-09-19 12:45:10 +0200672 /* push some buffers arriving in perfect time! */
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200673 for (b = 1; b < 3; b++) {
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300674 buffer_time = b * PCMU_BUF_DURATION;
Sebastian Drögec9e739b2016-03-01 17:11:14 +0200675 fail_unless_equals_int (GST_FLOW_OK,
676 gst_harness_push (h, generate_test_buffer (b)));
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200677
Sebastian Dröge73cae222013-09-19 12:45:10 +0200678 /* check for the buffer coming out that was pushed in */
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300679 out_buf = gst_harness_pull (h);
Sebastian Drögec9e739b2016-03-01 17:11:14 +0200680 fail_unless_equals_uint64 (buffer_time, GST_BUFFER_DTS (out_buf));
681 fail_unless_equals_uint64 (buffer_time, GST_BUFFER_PTS (out_buf));
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300682 gst_buffer_unref (out_buf);
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200683 }
684
Sebastian Dröge73cae222013-09-19 12:45:10 +0200685 /* hop over 2 packets and make another one (gap of 2) */
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200686 b = 5;
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300687 buffer_time = b * PCMU_BUF_DURATION;
688 gst_harness_push (h, generate_test_buffer (b));
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200689
Sebastian Dröge73cae222013-09-19 12:45:10 +0200690 /* verify that the jitterbuffer now wait for the latest moment it can push */
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300691 /* the first lost buffer (buffer 3) out on
692 * (buffer-timestamp (60) + latency (100) = 160) */
693 gst_test_clock_wait_for_next_pending_id (testclock, &id);
Sebastian Drögec9e739b2016-03-01 17:11:14 +0200694 fail_unless_equals_uint64 (3 * PCMU_BUF_DURATION +
695 jb_latency_ms * GST_MSECOND, gst_clock_id_get_time (id));
Sebastian Drögea4b66f92014-05-03 18:59:27 +0200696 gst_clock_id_unref (id);
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200697
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300698 /* let the time expire... */
Sebastian Drögec9e739b2016-03-01 17:11:14 +0200699 fail_unless (gst_harness_crank_single_clock_wait (h));
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300700
701 /* drop GstEventStreamStart & GstEventCaps & GstEventSegment */
702 for (int i = 0; i < 3; i++)
703 gst_event_unref (gst_harness_pull_event (h));
704
Sebastian Dröge73cae222013-09-19 12:45:10 +0200705 /* we should now receive a packet-lost-event for buffer 3 */
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300706 out_event = gst_harness_pull_event (h);
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300707 verify_lost_event (out_event, 3, 3 * PCMU_BUF_DURATION, PCMU_BUF_DURATION);
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200708
Sebastian Dröge73cae222013-09-19 12:45:10 +0200709 /* buffer 4 now arrives just in time (time is 70, buffer 4 expires at 90) */
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200710 b = 4;
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300711 buffer_time = b * PCMU_BUF_DURATION;
Sebastian Drögec9e739b2016-03-01 17:11:14 +0200712 fail_unless_equals_int (GST_FLOW_OK,
713 gst_harness_push (h, generate_test_buffer (b)));
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200714
Sebastian Dröge73cae222013-09-19 12:45:10 +0200715 /* verify that buffer 4 made it through! */
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300716 out_buf = gst_harness_pull (h);
Sebastian Drögec9e739b2016-03-01 17:11:14 +0200717 fail_unless (GST_BUFFER_FLAG_IS_SET (out_buf, GST_BUFFER_FLAG_DISCONT));
718 fail_unless_equals_int (4, get_rtp_seq_num (out_buf));
Sebastian Drögea4b66f92014-05-03 18:59:27 +0200719 gst_buffer_unref (out_buf);
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200720
Sebastian Dröge73cae222013-09-19 12:45:10 +0200721 /* and see that buffer 5 now arrives in a normal fashion */
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300722 out_buf = gst_harness_pull (h);
Sebastian Drögec9e739b2016-03-01 17:11:14 +0200723 fail_unless (!GST_BUFFER_FLAG_IS_SET (out_buf, GST_BUFFER_FLAG_DISCONT));
724 fail_unless_equals_int (5, get_rtp_seq_num (out_buf));
Sebastian Drögea4b66f92014-05-03 18:59:27 +0200725 gst_buffer_unref (out_buf);
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200726
Sebastian Drögee08b7df2016-09-30 12:19:10 +0300727 fail_unless (verify_jb_stats (h->element,
728 gst_structure_new ("application/x-rtp-jitterbuffer-stats",
729 "num-pushed", G_TYPE_UINT64, (guint64) 5,
730 "num-lost", G_TYPE_UINT64, (guint64) 1, NULL)));
731
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300732 gst_object_unref (testclock);
733 gst_harness_teardown (h);
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200734}
735
736GST_END_TEST;
737
738GST_START_TEST (test_late_packets_still_makes_lost_events)
739{
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300740 GstHarness *h = gst_harness_new ("rtpjitterbuffer");
741 GstTestClock *testclock;
742 GstBuffer *out_buf;
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200743 GstEvent *out_event;
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300744 gint jb_latency_ms = 100;
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200745 GstClockTime buffer_time;
746 gint b;
747
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300748 gst_harness_set_src_caps (h, generate_caps ());
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300749 testclock = gst_harness_get_testclock (h);
750 g_object_set (h->element, "do-lost", TRUE, "latency", jb_latency_ms, NULL);
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200751
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300752 /* advance the clock with 10 seconds */
753 gst_test_clock_set_time (testclock, 10 * GST_SECOND);
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200754
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300755 /* push the first buffer through */
756 gst_buffer_unref (gst_harness_push_and_pull (h, generate_test_buffer (0)));
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200757
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300758 /* push some buffers arriving in perfect time! */
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200759 for (b = 1; b < 3; b++) {
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300760 buffer_time = b * PCMU_BUF_DURATION;
Sebastian Drögec9e739b2016-03-01 17:11:14 +0200761 fail_unless_equals_int (GST_FLOW_OK,
762 gst_harness_push (h, generate_test_buffer (b)));
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200763
Sebastian Dröge73cae222013-09-19 12:45:10 +0200764 /* check for the buffer coming out that was pushed in */
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300765 out_buf = gst_harness_pull (h);
Sebastian Drögec9e739b2016-03-01 17:11:14 +0200766 fail_unless_equals_uint64 (buffer_time, GST_BUFFER_DTS (out_buf));
767 fail_unless_equals_uint64 (buffer_time, GST_BUFFER_PTS (out_buf));
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300768 gst_buffer_unref (out_buf);
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200769 }
770
Sebastian Dröge73cae222013-09-19 12:45:10 +0200771 /* hop over 2 packets and make another one (gap of 2) */
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200772 b = 5;
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300773 buffer_time = b * PCMU_BUF_DURATION;
Sebastian Drögec9e739b2016-03-01 17:11:14 +0200774 fail_unless_equals_int (GST_FLOW_OK,
775 gst_harness_push (h, generate_test_buffer (b)));
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200776
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300777 /* drop GstEventStreamStart & GstEventCaps & GstEventSegment */
778 for (int i = 0; i < 3; i++)
779 gst_event_unref (gst_harness_pull_event (h));
780
781 /* we should now receive packet-lost-events for buffer 3 and 4 */
782 out_event = gst_harness_pull_event (h);
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300783 verify_lost_event (out_event, 3, 3 * PCMU_BUF_DURATION, PCMU_BUF_DURATION);
784 out_event = gst_harness_pull_event (h);
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300785 verify_lost_event (out_event, 4, 4 * PCMU_BUF_DURATION, PCMU_BUF_DURATION);
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200786
Sebastian Dröge73cae222013-09-19 12:45:10 +0200787 /* verify that buffer 5 made it through! */
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300788 out_buf = gst_harness_pull (h);
Sebastian Drögec9e739b2016-03-01 17:11:14 +0200789 fail_unless (GST_BUFFER_FLAG_IS_SET (out_buf, GST_BUFFER_FLAG_DISCONT));
790 fail_unless_equals_int (5, get_rtp_seq_num (out_buf));
Sebastian Drögea4b66f92014-05-03 18:59:27 +0200791 gst_buffer_unref (out_buf);
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200792
Sebastian Drögee08b7df2016-09-30 12:19:10 +0300793 fail_unless (verify_jb_stats (h->element,
794 gst_structure_new ("application/x-rtp-jitterbuffer-stats",
795 "num-pushed", G_TYPE_UINT64, (guint64) 4,
796 "num-lost", G_TYPE_UINT64, (guint64) 2, NULL)));
797
Sebastian Drögeb04f9722015-08-19 13:19:08 +0300798 gst_object_unref (testclock);
799 gst_harness_teardown (h);
Sebastian Dröge5f0bab02013-07-14 11:42:29 +0200800}
801
802GST_END_TEST;
803
Sebastian Drögee08b7df2016-09-30 12:19:10 +0300804
805GST_START_TEST (test_num_late_when_considered_lost_arrives)
806{
807 GstHarness *h = gst_harness_new ("rtpjitterbuffer");
808 gboolean do_lost = __i__ != 0;
809
810 gst_harness_set_src_caps (h, generate_caps ());
811 g_object_set (h->element, "do-lost", do_lost, "latency", 100, NULL);
812
813 /* push the first buffer through */
814 fail_unless_equals_int (GST_FLOW_OK,
815 gst_harness_push (h, generate_test_buffer (0)));
816 /* sync on the first packet */
817 gst_harness_crank_single_clock_wait (h);
818
819 /* gap of 1 */
820 fail_unless_equals_int (GST_FLOW_OK,
821 gst_harness_push (h, generate_test_buffer (2)));
822
823 /* crank to output lost-event */
824 gst_harness_crank_single_clock_wait (h);
825
826 if (do_lost) {
827 /* drop GstEventStreamStart & GstEventCaps & GstEventSegment */
828 for (gint i = 0; i < 3; i++)
829 gst_event_unref (gst_harness_pull_event (h));
830
831 /* we should now receive packet-lost-events for buffer 1 */
832 verify_lost_event (gst_harness_pull_event (h),
833 1, 1 * PCMU_BUF_DURATION, PCMU_BUF_DURATION);
834 }
835
836 /* pull out buffers to ensure determinism */
837 gst_buffer_unref (gst_harness_pull (h));
838 gst_buffer_unref (gst_harness_pull (h));
839
840 /* we have one lost packet in the stats */
841 fail_unless (verify_jb_stats (h->element,
842 gst_structure_new ("application/x-rtp-jitterbuffer-stats",
843 "num-pushed", G_TYPE_UINT64, (guint64) 2,
844 "num-lost", G_TYPE_UINT64, (guint64) 1,
845 "num-late", G_TYPE_UINT64, (guint64) 0, NULL)));
846
847 /* buffer 1 now arrives (too late) */
848 fail_unless_equals_int (GST_FLOW_OK,
849 gst_harness_push (h, generate_test_buffer (1)));
850
851 /* and this increments num-late */
852 fail_unless (verify_jb_stats (h->element,
853 gst_structure_new ("application/x-rtp-jitterbuffer-stats",
854 "num-pushed", G_TYPE_UINT64, (guint64) 2,
855 "num-lost", G_TYPE_UINT64, (guint64) 1,
856 "num-late", G_TYPE_UINT64, (guint64) 1, NULL)));
857
858 gst_harness_teardown (h);
859}
860
861GST_END_TEST;
862
Sebastian Drögec33ae3b2017-01-30 15:44:11 +0200863GST_START_TEST (test_lost_event_uses_pts)
864{
865 GstHarness *h = gst_harness_new ("rtpjitterbuffer");
866 GstEvent *out_event;
867 GstClockTime now;
868 gint jb_latency_ms = 100;
869 gint i;
870
871 gst_harness_set_src_caps (h, generate_caps ());
872 g_object_set (h->element, "do-lost", TRUE, "latency", jb_latency_ms, NULL);
873
874 /* push the first buffer through */
875 fail_unless_equals_int (GST_FLOW_OK,
876 gst_harness_push (h, generate_test_buffer (0)));
877 fail_unless (gst_harness_crank_single_clock_wait (h));
878 gst_buffer_unref (gst_harness_pull (h));
879
880 /* push some buffers arriving in perfect time! */
881 for (i = 1; i <= 2; i++) {
882 fail_unless_equals_int (GST_FLOW_OK,
883 gst_harness_push (h, generate_test_buffer (i)));
884 gst_buffer_unref (gst_harness_pull (h));
885 }
886
887 /* hop over 1 packets (seqnum 3) and make another one (gap of 1), but due to
888 network delays, this packets is also grossly late */
889 i = 4;
890
891 /* advance the clock to the latest possible time buffer 4 could arrive */
892 now = i * PCMU_BUF_DURATION + jb_latency_ms * GST_MSECOND;
893 gst_harness_set_time (h, now);
894 gst_harness_push (h, generate_test_buffer_full (now, FALSE, i, i * PCMU_RTP_TS_DURATION));
895
896 /* drop GstEventStreamStart & GstEventCaps & GstEventSegment */
897 for (int i = 0; i < 3; i++)
898 gst_event_unref (gst_harness_pull_event (h));
899
900 /* we should now have received a packet-lost-event for buffer 3 */
901 out_event = gst_harness_pull_event (h);
902 verify_lost_event (out_event, 3, 3 * PCMU_BUF_DURATION, PCMU_BUF_DURATION);
903
904 /* and pull out packet 4 */
905 gst_buffer_unref (gst_harness_pull (h));
906
907 fail_unless (verify_jb_stats (h->element,
908 gst_structure_new ("application/x-rtp-jitterbuffer-stats",
909 "num-pushed", G_TYPE_UINT64, (guint64) 4,
910 "num-lost", G_TYPE_UINT64, (guint64) 1, NULL)));
911
912 gst_harness_teardown (h);
913}
914
915GST_END_TEST;
916
917GST_START_TEST (test_lost_event_with_backwards_rtptime)
918{
919 GstHarness *h = gst_harness_new ("rtpjitterbuffer");
920 GstEvent *out_event;
921 gint jb_latency_ms = 100;
922 gint i;
923
924 gst_harness_set_src_caps (h, generate_caps ());
925 g_object_set (h->element, "do-lost", TRUE, "latency", jb_latency_ms, NULL);
926
927 /* push the first buffer through */
928 fail_unless_equals_int (GST_FLOW_OK,
929 gst_harness_push (h, generate_test_buffer (0)));
930 fail_unless (gst_harness_crank_single_clock_wait (h));
931 gst_buffer_unref (gst_harness_pull (h));
932
933 /* push some buffers arriving in perfect time! */
934 for (i = 1; i <= 2; i++) {
935 fail_unless_equals_int (GST_FLOW_OK,
936 gst_harness_push (h, generate_test_buffer (i)));
937 gst_buffer_unref (gst_harness_pull (h));
938 }
939
940 /*
941 For video using B-frames, an expected sequence
942 could be like this:
943 (I = I-frame, P = P-frame, B = B-frame)
944 ___ ___ ___ ___ ___
945 ... | 3 | | 4 | | 5 | | 6 | | 7 |
946 ––– ––– ––– ––– –––
947 rtptime: 3(I) 5(P) 5(P) 4(B) 6(P)
948arrival(dts): 3 5 5 5 6
949
950 Notice here that packet 6 (the B frame) make
951 the rtptime go backwards.
952
953 But we get this:
954 ___ ___ _ _ ___ ___
955 ... | 3 | | 4 | | | | 6 | | 7 |
956 ––– ––– - - ––– –––
957 rtptime: 3(I) 5(P) 4(B) 6(P)
958arrival(dts): 3 5 5 6
959
960 */
961
962 /* seqnum 3 */
963 fail_unless_equals_int (GST_FLOW_OK,
964 gst_harness_push (h, generate_test_buffer (3)));
965 gst_buffer_unref (gst_harness_pull (h));
966
967 /* seqnum 4, arriving at time 5 with rtptime 5 */
968 gst_harness_push (h, generate_test_buffer_full (
969 5 * PCMU_BUF_DURATION, FALSE, 4, 5 * PCMU_RTP_TS_DURATION));
970 gst_buffer_unref (gst_harness_pull (h));
971
972 /* seqnum 6, arriving at time 5 with rtptime 4,
973 making a gap for missing seqnum 5 */
974 gst_harness_push (h, generate_test_buffer_full (
975 5 * PCMU_BUF_DURATION, FALSE, 6, 4 * PCMU_RTP_TS_DURATION));
976
977 /* seqnum 7, arriving at time 6 with rtptime 6 */
978 gst_harness_push (h, generate_test_buffer_full (
979 6 * PCMU_BUF_DURATION, FALSE, 7, 6 * PCMU_RTP_TS_DURATION));
980
981 /* drop GstEventStreamStart & GstEventCaps & GstEventSegment */
982 for (int i = 0; i < 3; i++)
983 gst_event_unref (gst_harness_pull_event (h));
984
985 /* we should now have received a packet-lost-event for seqnum 5,
986 with time 5 and 0 duration */
987 gst_harness_crank_single_clock_wait (h);
988 out_event = gst_harness_pull_event (h);
989 verify_lost_event (out_event, 5, 5 * PCMU_BUF_DURATION, 0);
990
991 /* and pull out 6 and 7 */
992 gst_buffer_unref (gst_harness_pull (h));
993 gst_buffer_unref (gst_harness_pull (h));
994
995 fail_unless (verify_jb_stats (h->element,
996 gst_structure_new ("application/x-rtp-jitterbuffer-stats",
997 "num-pushed", G_TYPE_UINT64, (guint64) 7,
998 "num-lost", G_TYPE_UINT64, (guint64) 1, NULL)));
999
1000 gst_harness_teardown (h);
1001}
1002
1003GST_END_TEST;
1004
Sebastian Dröge5f0bab02013-07-14 11:42:29 +02001005GST_START_TEST (test_all_packets_are_timestamped_zero)
1006{
Sebastian Drögeb04f9722015-08-19 13:19:08 +03001007 GstHarness *h = gst_harness_new ("rtpjitterbuffer");
1008 GstTestClock *testclock;
1009 GstBuffer *out_buf;
Sebastian Dröge5f0bab02013-07-14 11:42:29 +02001010 GstEvent *out_event;
Sebastian Drögeb04f9722015-08-19 13:19:08 +03001011 gint jb_latency_ms = 100;
Sebastian Drögeb04f9722015-08-19 13:19:08 +03001012 gint b;
Sebastian Dröge5f0bab02013-07-14 11:42:29 +02001013
Sebastian Drögeb04f9722015-08-19 13:19:08 +03001014 gst_harness_set_src_caps (h, generate_caps ());
Sebastian Drögeb04f9722015-08-19 13:19:08 +03001015 testclock = gst_harness_get_testclock (h);
1016 g_object_set (h->element, "do-lost", TRUE, "latency", jb_latency_ms, NULL);
Sebastian Dröge5f0bab02013-07-14 11:42:29 +02001017
Sebastian Drögeb04f9722015-08-19 13:19:08 +03001018 /* advance the clock with 10 seconds */
1019 gst_test_clock_set_time (testclock, 10 * GST_SECOND);
Sebastian Dröge5f0bab02013-07-14 11:42:29 +02001020
Sebastian Drögeb04f9722015-08-19 13:19:08 +03001021 /* push the first buffer through */
1022 gst_buffer_unref (gst_harness_push_and_pull (h, generate_test_buffer (0)));
Sebastian Dröge5f0bab02013-07-14 11:42:29 +02001023
Sebastian Drögeb04f9722015-08-19 13:19:08 +03001024 /* push some buffers in, all timestamped 0 */
Sebastian Dröge5f0bab02013-07-14 11:42:29 +02001025 for (b = 1; b < 3; b++) {
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001026 fail_unless_equals_int (GST_FLOW_OK,
1027 gst_harness_push (h,
1028 generate_test_buffer_full (0 * GST_MSECOND, TRUE, b, 0)));
Sebastian Dröge5f0bab02013-07-14 11:42:29 +02001029
Sebastian Dröge73cae222013-09-19 12:45:10 +02001030 /* check for the buffer coming out that was pushed in */
Sebastian Drögeb04f9722015-08-19 13:19:08 +03001031 out_buf = gst_harness_pull (h);
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001032 fail_unless_equals_uint64 (0, GST_BUFFER_DTS (out_buf));
1033 fail_unless_equals_uint64 (0, GST_BUFFER_PTS (out_buf));
Sebastian Drögeb04f9722015-08-19 13:19:08 +03001034 gst_buffer_unref (out_buf);
Sebastian Dröge5f0bab02013-07-14 11:42:29 +02001035 }
1036
Sebastian Dröge73cae222013-09-19 12:45:10 +02001037 /* hop over 2 packets and make another one (gap of 2) */
Sebastian Dröge5f0bab02013-07-14 11:42:29 +02001038 b = 5;
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001039 fail_unless_equals_int (GST_FLOW_OK,
1040 gst_harness_push (h,
1041 generate_test_buffer_full (0 * GST_MSECOND, TRUE, b, 0)));
Sebastian Dröge5f0bab02013-07-14 11:42:29 +02001042
Sebastian Drögeb04f9722015-08-19 13:19:08 +03001043 /* drop GstEventStreamStart & GstEventCaps & GstEventSegment */
1044 for (int i = 0; i < 3; i++)
1045 gst_event_unref (gst_harness_pull_event (h));
1046
1047 /* we should now receive packet-lost-events for buffer 3 and 4 */
1048 out_event = gst_harness_pull_event (h);
Sebastian Drögeb04f9722015-08-19 13:19:08 +03001049 verify_lost_event (out_event, 3, 0, 0);
1050 out_event = gst_harness_pull_event (h);
Sebastian Drögeb04f9722015-08-19 13:19:08 +03001051 verify_lost_event (out_event, 4, 0, 0);
Sebastian Dröge73cae222013-09-19 12:45:10 +02001052
1053 /* verify that buffer 5 made it through! */
Sebastian Drögeb04f9722015-08-19 13:19:08 +03001054 out_buf = gst_harness_pull (h);
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001055 fail_unless (GST_BUFFER_FLAG_IS_SET (out_buf, GST_BUFFER_FLAG_DISCONT));
1056 fail_unless_equals_int (5, get_rtp_seq_num (out_buf));
Sebastian Drögea4b66f92014-05-03 18:59:27 +02001057 gst_buffer_unref (out_buf);
Sebastian Dröge5f0bab02013-07-14 11:42:29 +02001058
Sebastian Drögee08b7df2016-09-30 12:19:10 +03001059 fail_unless (verify_jb_stats (h->element,
1060 gst_structure_new ("application/x-rtp-jitterbuffer-stats",
1061 "num-pushed", G_TYPE_UINT64, (guint64) 4,
1062 "num-lost", G_TYPE_UINT64, (guint64) 2, NULL)));
1063
Sebastian Drögeb04f9722015-08-19 13:19:08 +03001064 gst_object_unref (testclock);
1065 gst_harness_teardown (h);
Sebastian Dröge5f0bab02013-07-14 11:42:29 +02001066}
1067
1068GST_END_TEST;
Olivier Naudan988c6f02012-04-16 07:16:25 -04001069
Sebastian Drögee08b7df2016-09-30 12:19:10 +03001070GST_START_TEST (test_reorder_of_non_equidistant_packets)
1071{
1072 GstHarness *h = gst_harness_new ("rtpjitterbuffer");
1073 GstTestClock *testclock;
1074 gint latency_ms = 5;
1075 GstClockID pending_id;
1076 GstClockTime time;
1077 gint seq, frame;
1078 gint num_init_frames = 1;
1079 const GstClockTime frame_dur = PCMU_BUF_DURATION;
1080 const guint32 frame_rtp_ts_dur = PCMU_RTP_TS_DURATION;
1081
1082 gst_harness_set_src_caps (h, generate_caps ());
1083 testclock = gst_harness_get_testclock (h);
1084 g_object_set (h->element, "do-lost", TRUE, "latency", latency_ms, NULL);
1085
1086 for (frame = 0, seq = 0; frame < num_init_frames; frame++, seq += 2) {
1087 /* Push a couple of packets with identical timestamp, typical for a video
1088 * stream where one frame generates multiple packets. */
1089 gst_harness_set_time (h, frame * frame_dur);
1090 gst_harness_push (h, generate_test_buffer_full (frame * frame_dur, FALSE,
1091 seq, frame * frame_rtp_ts_dur));
1092 gst_harness_push (h, generate_test_buffer_full (frame * frame_dur, TRUE,
1093 seq + 1, frame * frame_rtp_ts_dur));
1094
1095 if (frame == 0)
1096 /* deadline for buffer 0 expires */
1097 gst_harness_crank_single_clock_wait (h);
1098
1099 gst_buffer_unref (gst_harness_pull (h));
1100 gst_buffer_unref (gst_harness_pull (h));
1101 }
1102
1103 /* Finally push the last frame reordered */
1104 gst_harness_set_time (h, frame * frame_dur);
1105 gst_harness_push (h, generate_test_buffer_full (frame * frame_dur, TRUE,
1106 seq + 1, frame * frame_rtp_ts_dur));
1107
1108 /* Check the scheduled lost timer. The expected arrival of this packet
1109 * should be assumed to be the same as the last packet received since we
1110 * don't know wether the missing packet belonged to this or previous
1111 * frame. */
1112 gst_test_clock_wait_for_next_pending_id (testclock, &pending_id);
1113 time = gst_clock_id_get_time (pending_id);
1114 fail_unless_equals_int64 (time, frame * frame_dur + latency_ms * GST_MSECOND);
1115 gst_clock_id_unref (pending_id);
1116
1117 /* And then missing packet arrives just in time */
1118 gst_harness_set_time (h, time - 1);
1119 gst_harness_push (h, generate_test_buffer_full (time - 1, FALSE, seq,
1120 frame * frame_rtp_ts_dur));
1121
1122 gst_buffer_unref (gst_harness_pull (h));
1123 gst_buffer_unref (gst_harness_pull (h));
1124
1125 gst_object_unref (testclock);
1126 gst_harness_teardown (h);
1127}
1128
1129GST_END_TEST;
1130
1131GST_START_TEST (test_loss_equidistant_spacing_with_parameter_packets)
1132{
1133 GstHarness *h = gst_harness_new ("rtpjitterbuffer");
1134 GstTestClock *testclock;
1135 GstEvent *event;
1136 gint latency_ms = 5;
1137 gint seq, frame;
1138 gint num_init_frames = 10;
1139
1140 gst_harness_set_src_caps (h, generate_caps ());
1141 testclock = gst_harness_get_testclock (h);
1142 g_object_set (h->element, "do-lost", TRUE, "latency", latency_ms, NULL);
1143
1144 /* drop stream-start, caps, segment */
1145 for (int i = 0; i < 3; i++)
1146 gst_event_unref (gst_harness_pull_event (h));
1147
1148 for (frame = 0, seq = 0; frame < num_init_frames; frame++, seq++) {
1149 gst_harness_set_time (h, frame * PCMU_BUF_DURATION);
1150 gst_harness_push (h, generate_test_buffer_full (frame * PCMU_BUF_DURATION,
1151 TRUE, seq, frame * PCMU_RTP_TS_DURATION));
1152
1153 if (frame == 0)
1154 /* deadline for buffer 0 expires */
1155 gst_harness_crank_single_clock_wait (h);
1156
1157 gst_buffer_unref (gst_harness_pull (h));
1158 }
1159
1160 /* Push three packets with same rtptime, simulating parameter packets +
1161 * frame. This should not disable equidistant mode as it is common for
1162 * certain audio codecs. */
1163 for (gint i = 0; i < 3; i++) {
1164 gst_harness_set_time (h, frame * PCMU_BUF_DURATION);
1165 gst_harness_push (h, generate_test_buffer_full (frame * PCMU_BUF_DURATION,
1166 i == 2, seq++, frame * PCMU_RTP_TS_DURATION));
1167 gst_buffer_unref (gst_harness_pull (h));
1168 }
1169 frame++;
1170
1171 /* Finally push the last packet introducing a gap */
1172 gst_harness_set_time (h, frame * PCMU_BUF_DURATION);
1173 gst_harness_push (h, generate_test_buffer_full (frame * PCMU_BUF_DURATION,
1174 TRUE, seq + 1, frame * PCMU_RTP_TS_DURATION));
1175
1176 /* Check that the lost event has been generated assuming equidistant
1177 * spacing. */
1178 event = gst_harness_pull_event (h);
1179 verify_lost_event (event, seq,
1180 frame * PCMU_BUF_DURATION - PCMU_BUF_DURATION / 2, PCMU_BUF_DURATION / 2);
1181
1182 gst_buffer_unref (gst_harness_pull (h));
1183
1184 gst_object_unref (testclock);
1185 gst_harness_teardown (h);
1186}
1187
1188GST_END_TEST;
1189
1190
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001191static void
1192gst_test_clock_set_time_and_process (GstTestClock * testclock,
1193 GstClockTime time)
1194{
1195 GstClockID id, tid;
1196 gst_test_clock_wait_for_next_pending_id (testclock, &id);
1197 gst_test_clock_set_time (testclock, time);
1198 tid = gst_test_clock_process_next_clock_id (testclock);
1199 g_assert (tid == id);
1200 gst_clock_id_unref (tid);
1201 gst_clock_id_unref (id);
1202}
1203
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001204GST_START_TEST (test_rtx_expected_next)
1205{
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001206 GstHarness *h = gst_harness_new ("rtpjitterbuffer");
1207 GstTestClock *testclock;
1208 GstBuffer *out_buf;
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001209 GstEvent *out_event;
1210 gint jb_latency_ms = 200;
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001211 const GstClockTime rtx_retry_timeout = 40 * GST_MSECOND;
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001212
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001213 gst_harness_set_src_caps (h, generate_caps ());
1214 testclock = gst_harness_get_testclock (h);
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001215
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001216 g_object_set (h->element, "do-lost", TRUE, NULL);
1217 g_object_set (h->element, "do-retransmission", TRUE, NULL);
1218 g_object_set (h->element, "latency", jb_latency_ms, NULL);
1219 g_object_set (h->element, "rtx-retry-period", 120, NULL);
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001220
1221 /* push the first buffer in */
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001222 fail_unless_equals_int (GST_FLOW_OK,
1223 gst_harness_push (h, generate_test_buffer (0)));
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001224
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001225 gst_harness_set_time (h, 20 * GST_MSECOND);
1226 gst_harness_wait_for_clock_id_waits (h, 1, 60);
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001227
Sebastian Drögeb04f9722015-08-19 13:19:08 +03001228 /* put second buffer, the jitterbuffer should now know that the packet
1229 * spacing is 20ms and should ask for retransmission of seqnum 2 in
1230 * 20ms+10ms because 2*jitter==0 and 0.5*packet_spacing==10ms */
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001231 fail_unless_equals_int (GST_FLOW_OK,
1232 gst_harness_push (h, generate_test_buffer (1)));
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001233
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001234 gst_test_clock_set_time_and_process (testclock, 50 * GST_MSECOND);
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001235
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001236 /* drop reconfigure event */
1237 gst_event_unref (gst_harness_pull_upstream_event (h));
1238 /* drop GstEventStreamStart & GstEventCaps & GstEventSegment */
1239 for (int i = 0; i < 3; i++)
1240 gst_event_unref (gst_harness_pull_event (h));
1241
1242 out_event = gst_harness_pull_upstream_event (h);
1243 verify_rtx_event (out_event, 2, rtx_retry_timeout, 10, PCMU_BUF_DURATION);
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001244
Sebastian Dröge010e0292015-05-13 13:24:03 +03001245 /* now we wait for the next timeout, all following timeouts 40ms in the
1246 * future because this is rtx-retry-timeout */
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001247 gst_test_clock_set_time_and_process (testclock, 90 * GST_MSECOND);
1248 out_event = gst_harness_pull_upstream_event (h);
1249 verify_rtx_event (out_event, 2, rtx_retry_timeout, 50, PCMU_BUF_DURATION);
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001250
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001251 gst_test_clock_set_time_and_process (testclock, 130 * GST_MSECOND);
1252 out_event = gst_harness_pull_upstream_event (h);
1253 verify_rtx_event (out_event, 2, rtx_retry_timeout, 90, PCMU_BUF_DURATION);
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001254
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001255 gst_test_clock_set_time_and_process (testclock, 200 * GST_MSECOND);
1256 out_buf = gst_harness_pull (h);
1257 fail_unless_equals_int (0, get_rtp_seq_num (out_buf));
Sebastian Drögea4b66f92014-05-03 18:59:27 +02001258 gst_buffer_unref (out_buf);
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001259
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001260 gst_test_clock_set_time_and_process (testclock, 240 * GST_MSECOND);
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001261 /* we should now receive a packet-lost-event for buffer 2 */
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001262 out_event = gst_harness_pull_event (h);
Sebastian Drögeb04f9722015-08-19 13:19:08 +03001263 verify_lost_event (out_event, 2, 40 * GST_MSECOND, PCMU_BUF_DURATION);
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001264
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001265 gst_object_unref (testclock);
1266 gst_harness_teardown (h);
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001267}
1268
1269GST_END_TEST;
1270
1271GST_START_TEST (test_rtx_two_missing)
1272{
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001273 GstHarness *h = gst_harness_new ("rtpjitterbuffer");
1274 GstTestClock *testclock;
Sebastian Drögee08b7df2016-09-30 12:19:10 +03001275 gint latency_ms = 200;
1276 gint rtx_delay_ms;
1277 GstClockTime last_rtx_request, now;
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001278
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001279 testclock = gst_harness_get_testclock (h);
Sebastian Drögee08b7df2016-09-30 12:19:10 +03001280 gst_harness_set_src_caps (h, generate_caps ());
1281 g_object_set (h->element, "do-retransmission", TRUE, "latency", latency_ms,
1282 NULL);
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001283
Sebastian Drögee08b7df2016-09-30 12:19:10 +03001284 for (gint i = 0; i <= latency_ms / PCMU_BUF_MS; i++) {
1285 gst_test_clock_set_time (testclock, i * PCMU_BUF_DURATION);
1286 fail_unless_equals_int (GST_FLOW_OK,
1287 gst_harness_push (h, generate_test_buffer (i)));
1288 gst_harness_wait_for_clock_id_waits (h, 1, 60);
1289 }
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001290
Sebastian Drögee08b7df2016-09-30 12:19:10 +03001291 gst_harness_crank_single_clock_wait (h);
1292 fail_unless_equals_int64 (latency_ms * GST_MSECOND,
1293 gst_clock_get_time (GST_CLOCK (testclock)));
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001294
Sebastian Drögee08b7df2016-09-30 12:19:10 +03001295 for (gint i = 0; i <= latency_ms / PCMU_BUF_MS; i++)
1296 gst_buffer_unref (gst_harness_pull (h));
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001297
1298 /* drop reconfigure event */
1299 gst_event_unref (gst_harness_pull_upstream_event (h));
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001300
Sebastian Drögee08b7df2016-09-30 12:19:10 +03001301 /*
1302 The expected sequence of buffers is this:
1303 ____ ____ ____ ____
1304 ... | 10 | | 11 | | 12 | | 13 |
1305 –––– –––– –––– ––––
1306 200ms 220ms 240ms 260ms
Sebastian Dröge010e0292015-05-13 13:24:03 +03001307
Sebastian Drögee08b7df2016-09-30 12:19:10 +03001308 But instead we get this:
1309 ____ _ _ _ _ ____
1310 ... | 10 | | | | | | 13 |
1311 –––– - - - - ––––
1312 200ms 260ms
Sebastian Dröge010e0292015-05-13 13:24:03 +03001313
Sebastian Drögee08b7df2016-09-30 12:19:10 +03001314 Now it is important to note that the next thing that happens is that
1315 the RTX timeout for packet 11 will happen at time 230ms, so we crank
1316 the timer thread to advance the time to this: */
1317 gst_harness_crank_single_clock_wait (h);
1318 rtx_delay_ms = PCMU_BUF_MS / 2;
1319 verify_rtx_event (gst_harness_pull_upstream_event (h),
1320 11, 11 * PCMU_BUF_DURATION, rtx_delay_ms, PCMU_BUF_DURATION);
1321 last_rtx_request = gst_clock_get_time (GST_CLOCK (testclock));
1322 fail_unless_equals_int64 (last_rtx_request,
1323 11 * PCMU_BUF_DURATION + rtx_delay_ms * GST_MSECOND);
1324 gst_harness_wait_for_clock_id_waits (h, 1, 60);
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001325
Sebastian Drögee08b7df2016-09-30 12:19:10 +03001326 /* The next scheduled RTX for packet 11 is now at 230 + 40 = 270ms,
1327 so the next thing that happens is that buffer 13 arrives in perfect time: */
1328 now = 13 * PCMU_BUF_DURATION;
1329 gst_harness_set_time (h, now);
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001330 fail_unless_equals_int (GST_FLOW_OK,
Sebastian Drögee08b7df2016-09-30 12:19:10 +03001331 gst_harness_push (h,
1332 generate_test_buffer_full (now, TRUE, 13,
1333 13 * PCMU_RTP_TS_DURATION)));
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001334
Sebastian Drögee08b7df2016-09-30 12:19:10 +03001335 /*
1336
1337 This will estimate the dts on the two missing packets to:
1338 ____ ____
1339 ... | 11 | | 12 | ...
1340 –––– ––––
1341 220ms 240ms
1342
1343 And given their regular interspacing of 20ms, it will schedule two RTX
1344 timers for them like so:
1345
1346 ____ ____
1347 ... | 11 | | 12 | ...
1348 –––– ––––
1349 230ms 250ms
1350
1351 There are however two problems, packet 11 we have already sent one RTX for
1352 and its timeout is currently at 270ms, so we should not tamper with that,
1353 and as for packet 12, 250ms has already expired, so we now expect to see
1354 an rtx-event being sent for packet 12 immediately: */
1355 verify_rtx_event (gst_harness_pull_upstream_event (h),
1356 12, 12 * PCMU_BUF_DURATION, rtx_delay_ms, PCMU_BUF_DURATION);
1357
1358 /* and another crank will see the second RTX event being sent for packet 11 */
1359 gst_harness_crank_single_clock_wait (h);
1360 rtx_delay_ms += 40;
1361 verify_rtx_event (gst_harness_pull_upstream_event (h),
1362 11, 11 * PCMU_BUF_DURATION, rtx_delay_ms, PCMU_BUF_DURATION);
1363 last_rtx_request = gst_clock_get_time (GST_CLOCK (testclock));
1364 fail_unless_equals_int64 (last_rtx_request,
1365 11 * PCMU_BUF_DURATION + rtx_delay_ms * GST_MSECOND);
1366
1367 gst_object_unref (testclock);
1368 gst_harness_teardown (h);
1369}
1370
1371GST_END_TEST;
1372
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001373GST_START_TEST (test_rtx_packet_delay)
1374{
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001375 GstHarness *h = gst_harness_new ("rtpjitterbuffer");
1376 GstTestClock *testclock;
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001377 GstBuffer *in_buf, *out_buf;
1378 GstEvent *out_event;
1379 gint jb_latency_ms = 200;
1380 gint i;
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001381
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001382 gst_harness_set_src_caps (h, generate_caps ());
1383 testclock = gst_harness_get_testclock (h);
1384
1385 g_object_set (h->element, "do-lost", TRUE, NULL);
1386 g_object_set (h->element, "do-retransmission", TRUE, NULL);
1387 g_object_set (h->element, "latency", jb_latency_ms, NULL);
1388 g_object_set (h->element, "rtx-retry-period", 120, NULL);
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001389
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001390 /* push the first buffer in */
Sebastian Drögeb04f9722015-08-19 13:19:08 +03001391 in_buf = generate_test_buffer (0);
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001392 GST_BUFFER_FLAG_SET (in_buf, GST_BUFFER_FLAG_DISCONT);
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001393 gst_harness_push (h, in_buf);
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001394
Sebastian Drögeb04f9722015-08-19 13:19:08 +03001395 /* put second buffer, the jitterbuffer should now know that the packet
1396 * spacing is 20ms and should ask for retransmission of seqnum 2 in
1397 * 20ms+10ms because 2*jitter==0 and 0.5*packet_spacing==10ms */
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001398 fail_unless_equals_int (GST_FLOW_OK,
1399 gst_harness_push (h, generate_test_buffer (1)));
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001400
1401 /* push buffer 8, 2 -> 7 are missing now. note that the rtp time is the same
1402 * as packet 1 because it was part of a fragmented payload. This means that
Sebastian Drögeb04f9722015-08-19 13:19:08 +03001403 * the estimate for 2 could be refined now to 20ms. also packet 2, 3 and 4
1404 * are exceeding the max allowed reorder distance and should request a
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001405 * retransmission right away */
Sebastian Drögec33ae3b2017-01-30 15:44:11 +02001406 gst_harness_set_time (h, 1 * PCMU_BUF_DURATION);
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001407 fail_unless_equals_int (GST_FLOW_OK,
Sebastian Drögec33ae3b2017-01-30 15:44:11 +02001408 gst_harness_push (h, generate_test_buffer_full (1 * PCMU_BUF_DURATION, TRUE, 8,
1409 1 * PCMU_RTP_TS_DURATION)));
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001410
1411 /* drop reconfigure event */
1412 gst_event_unref (gst_harness_pull_upstream_event (h));
1413 /* drop GstEventStreamStart & GstEventCaps & GstEventSegment */
1414 for (int i = 0; i < 3; i++)
1415 gst_event_unref (gst_harness_pull_event (h));
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001416
1417 /* we should now receive retransmission requests for 2 -> 5 */
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001418 out_event = gst_harness_pull_upstream_event (h);
Sebastian Drögec33ae3b2017-01-30 15:44:11 +02001419 verify_rtx_event (out_event, 2, 20 * GST_MSECOND, 10, PCMU_BUF_DURATION);
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001420
1421 for (i = 3; i < 5; i++) {
1422 GST_DEBUG ("popping %d", i);
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001423 out_event = gst_harness_pull_upstream_event (h);
Sebastian Drögec33ae3b2017-01-30 15:44:11 +02001424 verify_rtx_event (out_event, i, 20 * GST_MSECOND, 10, PCMU_BUF_DURATION);
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001425 }
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001426 fail_unless_equals_int (0, gst_harness_upstream_events_in_queue (h));
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001427
1428 /* push 9, this should immediately request retransmission of 5 */
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001429 fail_unless_equals_int (GST_FLOW_OK,
Sebastian Drögec33ae3b2017-01-30 15:44:11 +02001430 gst_harness_push (h, generate_test_buffer_full (1 * PCMU_BUF_DURATION, TRUE, 9,
1431 1 * PCMU_RTP_TS_DURATION)));
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001432
1433 /* we should now receive retransmission requests for 5 */
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001434 out_event = gst_harness_pull_upstream_event (h);
Sebastian Drögec33ae3b2017-01-30 15:44:11 +02001435 verify_rtx_event (out_event, 5, 20 * GST_MSECOND, 10, PCMU_BUF_DURATION);
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001436
1437 /* wait for timeout for rtx 6 -> 7 */
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001438 gst_test_clock_set_time_and_process (testclock, 60 * GST_MSECOND);
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001439
1440 for (i = 6; i < 8; i++) {
1441 GST_DEBUG ("popping %d", i);
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001442 out_event = gst_harness_pull_upstream_event (h);
Sebastian Drögec33ae3b2017-01-30 15:44:11 +02001443 verify_rtx_event (out_event, i, 20 * GST_MSECOND, 10, PCMU_BUF_DURATION);
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001444 }
1445
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001446 /* churn through 7 sync_times until the new buffer gets pushed out */
1447 for (i = 0; i < 7; i++)
1448 gst_harness_crank_single_clock_wait (h);
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001449
1450 /* verify that buffer 0 and 1 made it through! */
1451 for (i = 0; i < 2; i++) {
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001452 out_buf = gst_harness_pull (h);
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001453 if (i == 0)
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001454 fail_unless (GST_BUFFER_FLAG_IS_SET (out_buf, GST_BUFFER_FLAG_DISCONT));
1455 fail_unless_equals_int (i, get_rtp_seq_num (out_buf));
Sebastian Drögea4b66f92014-05-03 18:59:27 +02001456 gst_buffer_unref (out_buf);
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001457 }
1458
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001459 for (i = 2; i < 8; i++) {
1460 GST_DEBUG ("popping lost event %d", i);
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001461 out_event = gst_harness_pull_event (h);
Sebastian Drögeb04f9722015-08-19 13:19:08 +03001462 verify_lost_event (out_event, i, 20 * GST_MSECOND, 0);
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001463 }
1464
1465 /* verify that buffer 8 made it through! */
1466 for (i = 8; i < 10; i++) {
1467 GST_DEBUG ("popping buffer %d", i);
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001468 out_buf = gst_harness_pull (h);
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001469 if (i == 8)
1470 g_assert (GST_BUFFER_FLAG_IS_SET (out_buf, GST_BUFFER_FLAG_DISCONT));
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001471 fail_unless_equals_int (i, get_rtp_seq_num (out_buf));
Sebastian Drögea4b66f92014-05-03 18:59:27 +02001472 gst_buffer_unref (out_buf);
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001473 }
1474
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001475 GST_DEBUG ("popping lost event 10");
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001476 out_event = gst_harness_pull_event (h);
Sebastian Drögeb04f9722015-08-19 13:19:08 +03001477 verify_lost_event (out_event, 10, 40 * GST_MSECOND, PCMU_BUF_DURATION);
Sebastian Dröge45626bf2013-09-24 16:47:44 +02001478
Sebastian Drögec9e739b2016-03-01 17:11:14 +02001479 fail_unless_equals_int (0, gst_harness_events_in_queue (h));
Sebastian Drögee08b7df2016-09-30 12:19:10 +03001480 fail_unless_equals_int (15, gst_harness_upstream_events_in_queue (h));
1481
1482 fail_unless (verify_jb_stats (h->element,
1483 gst_structure_new ("application/x-rtp-jitterbuffer-stats",
1484 "num-lost", G_TYPE_UINT64, (guint64) 7,
1485 "rtx-count", G_TYPE_UINT64, (guint64) 21,
1486 "rtx-success-count", G_TYPE_UINT64, (guint64) 0,
1487 "rtx-rtt", G_TYPE_UINT64, (guint64) 0, NULL)));
1488
1489 gst_object_unref (testclock);
1490 gst_harness_teardown (h);
1491}
1492
1493GST_END_TEST;
1494
1495GST_START_TEST (test_rtx_buffer_arrives_just_in_time)
1496{
1497 GstHarness *h = gst_harness_new ("rtpjitterbuffer");
1498 GstTestClock *testclock;
1499 gint latency_ms = 5 * PCMU_BUF_MS;
1500 gint num_init_buffers = latency_ms / PCMU_BUF_MS + 1;
1501 GstBuffer *buffer;
1502 GstClockTime now, last_rtx_request;
1503
1504 testclock = gst_harness_get_testclock (h);
1505 gst_harness_set_src_caps (h, generate_caps ());
1506 g_object_set (h->element, "do-retransmission", TRUE, "latency", latency_ms,
1507 "rtx-max-retries", 1, NULL);
1508
1509 /* Push/pull buffers and advance time past buffer 0's timeout (in order to
1510 * simplify the test) */
1511 for (gint i = 0; i < num_init_buffers; i++) {
1512 gst_test_clock_set_time (testclock, i * PCMU_BUF_DURATION);
1513 fail_unless_equals_int (GST_FLOW_OK,
1514 gst_harness_push (h, generate_test_buffer (i)));
1515 gst_harness_wait_for_clock_id_waits (h, 1, 60);
1516 }
1517
1518 gst_harness_crank_single_clock_wait (h);
1519 fail_unless_equals_int64 (latency_ms * GST_MSECOND,
1520 gst_clock_get_time (GST_CLOCK (testclock)));
1521
1522 for (gint i = 0; i < num_init_buffers; i++)
1523 gst_buffer_unref (gst_harness_pull (h));
1524
1525 /* drop reconfigure event */
1526 gst_event_unref (gst_harness_pull_upstream_event (h));
1527
1528 /* Crank clock to send retransmission events requesting seqnum 6 which has
1529 * not arrived yet. */
1530 gst_harness_crank_single_clock_wait (h);
1531 verify_rtx_event (gst_harness_pull_upstream_event (h),
1532 6, 6 * PCMU_BUF_DURATION, 10, PCMU_BUF_DURATION);
1533
1534 last_rtx_request = gst_clock_get_time (GST_CLOCK (testclock));
1535 fail_unless_equals_int64 (last_rtx_request, 130 * GST_MSECOND);
1536
1537 /* seqnum 6 arrives just before it times out and is considered lost */
1538 now = 200 * GST_MSECOND;
1539 gst_test_clock_set_time (testclock, now);
1540 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
1541 generate_test_buffer_rtx (now, 6)));
1542 buffer = gst_harness_pull (h);
1543 fail_unless_equals_int (6, get_rtp_seq_num (buffer));
1544 gst_buffer_unref (buffer);
1545
1546 fail_unless (verify_jb_stats (h->element,
1547 gst_structure_new ("application/x-rtp-jitterbuffer-stats",
1548 "num-pushed", G_TYPE_UINT64, (guint64) num_init_buffers + 1,
1549 "num-lost", G_TYPE_UINT64, (guint64) 0,
1550 "rtx-count", G_TYPE_UINT64, (guint64) 1,
1551 "rtx-success-count", G_TYPE_UINT64, (guint64) 1,
1552 "rtx-per-packet", G_TYPE_DOUBLE, 1.0,
1553 "rtx-rtt", G_TYPE_UINT64, (guint64) (now - last_rtx_request),
1554 NULL)));
1555
1556 gst_object_unref (testclock);
1557 gst_harness_teardown (h);
1558}
1559
1560GST_END_TEST;
1561
1562GST_START_TEST (test_rtx_buffer_arrives_too_late)
1563{
1564 GstHarness *h = gst_harness_new ("rtpjitterbuffer");
1565 GstTestClock *testclock;
1566 gint latency_ms = 5 * PCMU_BUF_MS;
1567 gint num_init_buffers = latency_ms / PCMU_BUF_MS + 1;
1568 GstClockTime now, last_rtx_request;
1569
1570 testclock = gst_harness_get_testclock (h);
1571 gst_harness_set_src_caps (h, generate_caps ());
1572 g_object_set (h->element, "do-retransmission", TRUE, "latency", latency_ms,
1573 "do-lost", TRUE, "rtx-max-retries", 1, NULL);
1574
1575 /* Push/pull buffers and advance time past buffer 0's timeout (in order to
1576 * simplify the test) */
1577 for (gint i = 0; i < num_init_buffers; i++) {
1578 gst_test_clock_set_time (testclock, i * PCMU_BUF_DURATION);
1579 fail_unless_equals_int (GST_FLOW_OK,
1580 gst_harness_push (h, generate_test_buffer (i)));
1581 gst_harness_wait_for_clock_id_waits (h, 1, 60);
1582 }
1583
1584 gst_harness_crank_single_clock_wait (h);
1585 fail_unless_equals_int64 (latency_ms * GST_MSECOND,
1586 gst_clock_get_time (GST_CLOCK (testclock)));
1587
1588 for (gint i = 0; i < num_init_buffers; i++)
1589 gst_buffer_unref (gst_harness_pull (h));
1590
1591 /* drop reconfigure event */
1592 gst_event_unref (gst_harness_pull_upstream_event (h));
1593 /* drop GstEventStreamStart & GstEventCaps & GstEventSegment */
1594 for (gint i = 0; i < 3; i++)
1595 gst_event_unref (gst_harness_pull_event (h));
1596
1597 /* Crank clock to send retransmission events requesting seqnum 6 which has
1598 * not arrived yet. */
1599 gst_harness_crank_single_clock_wait (h);
1600 verify_rtx_event (gst_harness_pull_upstream_event (h),
1601 6, 6 * PCMU_BUF_DURATION, 10, PCMU_BUF_DURATION);
1602
1603 last_rtx_request = gst_clock_get_time (GST_CLOCK (testclock));
1604 fail_unless_equals_int64 (last_rtx_request, 130 * GST_MSECOND);
1605
1606 /* seqnum 6 is considered lost */
1607 gst_harness_crank_single_clock_wait (h);
1608 verify_lost_event (gst_harness_pull_event (h), 6,
1609 6 * PCMU_BUF_DURATION, PCMU_BUF_DURATION);
1610
1611 /* seqnum 6 arrives too late */
1612 now = gst_clock_get_time (GST_CLOCK (testclock));
1613 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
1614 generate_test_buffer_rtx (now, 6)));
1615
1616 fail_unless (verify_jb_stats (h->element,
1617 gst_structure_new ("application/x-rtp-jitterbuffer-stats",
1618 "num-pushed", G_TYPE_UINT64, (guint64) num_init_buffers,
1619 "num-lost", G_TYPE_UINT64, (guint64) 1,
1620 "num-late", G_TYPE_UINT64, (guint64) 1,
1621 "num-duplicates", G_TYPE_UINT64, (guint64) 0,
1622 "rtx-count", G_TYPE_UINT64, (guint64) 1,
1623 "rtx-success-count", G_TYPE_UINT64, (guint64) 0,
1624 "rtx-per-packet", G_TYPE_DOUBLE, 1.0,
1625 "rtx-rtt", G_TYPE_UINT64, (guint64) (now - last_rtx_request),
1626 NULL)));
1627
1628 gst_object_unref (testclock);
1629 gst_harness_teardown (h);
1630}
1631
1632GST_END_TEST;
1633
1634GST_START_TEST (test_rtx_original_buffer_does_not_update_rtx_stats)
1635{
1636 GstHarness *h = gst_harness_new ("rtpjitterbuffer");
1637 GstTestClock *testclock;
1638 gint latency_ms = 5 * PCMU_BUF_MS;
1639 gint num_init_buffers = latency_ms / PCMU_BUF_MS + 1;
1640 GstBuffer *buffer;
1641 GstClockTime now, last_rtx_request;
1642
1643 testclock = gst_harness_get_testclock (h);
1644 gst_harness_set_src_caps (h, generate_caps ());
1645 g_object_set (h->element, "do-retransmission", TRUE, "latency", latency_ms,
1646 "rtx-max-retries", 1, NULL);
1647
1648 /* Push/pull buffers and advance time past buffer 0's timeout (in order to
1649 * simplify the test) */
1650 for (gint i = 0; i < num_init_buffers; i++) {
1651 gst_test_clock_set_time (testclock, i * PCMU_BUF_DURATION);
1652 fail_unless_equals_int (GST_FLOW_OK,
1653 gst_harness_push (h, generate_test_buffer (i)));
1654 gst_harness_wait_for_clock_id_waits (h, 1, 60);
1655 }
1656
1657 gst_harness_crank_single_clock_wait (h);
1658 fail_unless_equals_int64 (latency_ms * GST_MSECOND,
1659 gst_clock_get_time (GST_CLOCK (testclock)));
1660
1661 for (gint i = 0; i < num_init_buffers; i++)
1662 gst_buffer_unref (gst_harness_pull (h));
1663
1664 /* drop reconfigure event */
1665 gst_event_unref (gst_harness_pull_upstream_event (h));
1666
1667 /* Crank clock to send retransmission events requesting seqnum 6 which has
1668 * not arrived yet. */
1669 gst_harness_crank_single_clock_wait (h);
1670 verify_rtx_event (gst_harness_pull_upstream_event (h),
1671 6, 6 * PCMU_BUF_DURATION, 10, PCMU_BUF_DURATION);
1672
1673 last_rtx_request = gst_clock_get_time (GST_CLOCK (testclock));
1674 fail_unless_equals_int64 (last_rtx_request, 130 * GST_MSECOND);
1675
1676 /* ORIGINAL seqnum 6 arrives just before it times out and is considered
1677 * lost. */
1678 now = 200 * GST_MSECOND;
1679 gst_test_clock_set_time (testclock, now);
1680 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
1681 generate_test_buffer_full (now, TRUE, 6, 6 * PCMU_RTP_TS_DURATION)));
1682 buffer = gst_harness_pull (h);
1683 fail_unless_equals_int (6, get_rtp_seq_num (buffer));
1684 gst_buffer_unref (buffer);
1685
Sebastian Drögec33ae3b2017-01-30 15:44:11 +02001686 /* due to the advance in time, we will now also have sent
1687 an rtx-request for 7 */
1688 verify_rtx_event (gst_harness_pull_upstream_event (h),
1689 7, 7 * PCMU_BUF_DURATION, 10, PCMU_BUF_DURATION);
1690
Sebastian Drögee08b7df2016-09-30 12:19:10 +03001691 /* The original buffer does not count in the RTX stats. */
1692 fail_unless (verify_jb_stats (h->element,
1693 gst_structure_new ("application/x-rtp-jitterbuffer-stats",
1694 "num-pushed", G_TYPE_UINT64, (guint64) num_init_buffers + 1,
1695 "num-lost", G_TYPE_UINT64, (guint64) 0,
1696 "num-late", G_TYPE_UINT64, (guint64) 0,
1697 "num-duplicates", G_TYPE_UINT64, (guint64) 0,
Sebastian Drögec33ae3b2017-01-30 15:44:11 +02001698 "rtx-count", G_TYPE_UINT64, (guint64) 2,
Sebastian Drögee08b7df2016-09-30 12:19:10 +03001699 "rtx-success-count", G_TYPE_UINT64, (guint64) 0,
1700 "rtx-per-packet", G_TYPE_DOUBLE, 0.0,
1701 "rtx-rtt", G_TYPE_UINT64, (guint64) 0, NULL)));
1702
1703 /* Now the retransmitted packet arrives and stats should be updated. Note
1704 * that the buffer arrives in time and should not be considered late, but
1705 * a duplicate. */
1706 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
1707 generate_test_buffer_rtx (now, 6)));
1708 fail_unless (verify_jb_stats (h->element,
1709 gst_structure_new ("application/x-rtp-jitterbuffer-stats",
1710 "num-pushed", G_TYPE_UINT64, (guint64) num_init_buffers + 1,
1711 "num-lost", G_TYPE_UINT64, (guint64) 0,
1712 "num-late", G_TYPE_UINT64, (guint64) 0,
1713 "num-duplicates", G_TYPE_UINT64, (guint64) 1,
Sebastian Drögec33ae3b2017-01-30 15:44:11 +02001714 "rtx-count", G_TYPE_UINT64, (guint64) 2,
Sebastian Drögee08b7df2016-09-30 12:19:10 +03001715 "rtx-success-count", G_TYPE_UINT64, (guint64) 0,
1716 "rtx-per-packet", G_TYPE_DOUBLE, 1.0,
1717 "rtx-rtt", G_TYPE_UINT64, (guint64) (now - last_rtx_request),
1718 NULL)));
1719
1720 gst_object_unref (testclock);
1721 gst_harness_teardown (h);
1722}
1723
1724GST_END_TEST;
1725
1726GST_START_TEST (test_rtx_duplicate_packet_updates_rtx_stats)
1727{
1728 GstHarness *h = gst_harness_new ("rtpjitterbuffer");
1729 GstTestClock *testclock;
1730 gint latency_ms = 5 * PCMU_BUF_MS;
1731 gint num_init_buffers = latency_ms / PCMU_BUF_MS + 1;
1732 GstClockTime now, rtx_request_6, rtx_request_7;
1733 gint rtx_delay_ms;
1734
1735 testclock = gst_harness_get_testclock (h);
1736 gst_harness_set_src_caps (h, generate_caps ());
1737 g_object_set (h->element, "do-retransmission", TRUE, "latency", latency_ms,
1738 NULL);
1739
1740 /* Push/pull buffers and advance time past buffer 0's timeout (in order to
1741 * simplify the test) */
1742 for (gint i = 0; i < num_init_buffers; i++) {
1743 gst_test_clock_set_time (testclock, i * PCMU_BUF_DURATION);
1744 fail_unless_equals_int (GST_FLOW_OK,
1745 gst_harness_push (h, generate_test_buffer (i)));
1746 gst_harness_wait_for_clock_id_waits (h, 1, 60);
1747 }
1748
1749 gst_harness_crank_single_clock_wait (h);
1750 fail_unless_equals_int64 (latency_ms * GST_MSECOND,
1751 gst_clock_get_time (GST_CLOCK (testclock)));
1752
1753 for (gint i = 0; i < num_init_buffers; i++)
1754 gst_buffer_unref (gst_harness_pull (h));
1755
1756 /* Drop reconfigure event */
1757 gst_event_unref (gst_harness_pull_upstream_event (h));
1758
1759 /* Push packet 8 so that 6 and 7 is missing */
1760 fail_unless_equals_int (GST_FLOW_OK,
1761 gst_harness_push (h, generate_test_buffer (8)));
1762
1763 /* Wait for NACKs on 6 and 7 */
1764 gst_harness_crank_single_clock_wait (h);
1765 rtx_delay_ms = 10;
1766 verify_rtx_event (gst_harness_pull_upstream_event (h),
1767 6, 6 * PCMU_BUF_DURATION, rtx_delay_ms, PCMU_BUF_DURATION);
1768 rtx_request_6 = gst_clock_get_time (GST_CLOCK (testclock));
1769 fail_unless_equals_int64 (rtx_request_6,
1770 6 * PCMU_BUF_DURATION + rtx_delay_ms * GST_MSECOND);
1771
1772 gst_harness_crank_single_clock_wait (h);
1773 verify_rtx_event (gst_harness_pull_upstream_event (h),
1774 7, 7 * PCMU_BUF_DURATION, rtx_delay_ms, PCMU_BUF_DURATION);
1775 rtx_request_7 = gst_clock_get_time (GST_CLOCK (testclock));
1776 fail_unless_equals_int64 (rtx_request_7,
1777 7 * PCMU_BUF_DURATION + rtx_delay_ms * GST_MSECOND);
1778
1779 /* Original packet 7 arrives */
1780 now = 150 * GST_MSECOND;
1781 gst_test_clock_set_time (testclock, now);
1782 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
1783 generate_test_buffer_full (now, TRUE, 7, 7 * PCMU_RTP_TS_DURATION)));
1784
1785 /* We're still waiting for packet 6, so 7 should not be pushed */
1786 gst_harness_wait_for_clock_id_waits (h, 1, 60);
1787 fail_unless_equals_int (gst_harness_buffers_in_queue (h), 0);
1788
1789 /* The original buffer does not count in the RTX stats. */
1790 fail_unless (verify_jb_stats (h->element,
1791 gst_structure_new ("application/x-rtp-jitterbuffer-stats",
1792 "num-lost", G_TYPE_UINT64, (guint64) 0,
1793 "num-late", G_TYPE_UINT64, (guint64) 0,
1794 "num-duplicates", G_TYPE_UINT64, (guint64) 0,
1795 "rtx-count", G_TYPE_UINT64, (guint64) 2,
1796 "rtx-success-count", G_TYPE_UINT64, (guint64) 0,
1797 "rtx-per-packet", G_TYPE_DOUBLE, 0.0,
1798 "rtx-rtt", G_TYPE_UINT64, (guint64) 0, NULL)));
1799
1800 /* Push RTX packet 7. Should be dropped as duplicate but update RTX stats. */
1801 now = 160 * GST_MSECOND;
1802 gst_test_clock_set_time (testclock, now);
1803 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
1804 generate_test_buffer_rtx (now, 7)));
1805 gst_harness_wait_for_clock_id_waits (h, 1, 60);
1806 fail_unless_equals_int (gst_harness_buffers_in_queue (h), 0);
1807
1808 /* Check RTX stats with updated num-duplicates and rtx-rtt fields */
1809 fail_unless (verify_jb_stats (h->element,
1810 gst_structure_new ("application/x-rtp-jitterbuffer-stats",
1811 "num-pushed", G_TYPE_UINT64, (guint64) num_init_buffers,
1812 "num-lost", G_TYPE_UINT64, (guint64) 0,
1813 "num-late", G_TYPE_UINT64, (guint64) 0,
1814 "num-duplicates", G_TYPE_UINT64, (guint64) 1,
1815 "rtx-count", G_TYPE_UINT64, (guint64) 2,
1816 "rtx-success-count", G_TYPE_UINT64, (guint64) 0,
1817 "rtx-per-packet", G_TYPE_DOUBLE, 1.0,
1818 "rtx-rtt", G_TYPE_UINT64, (guint64) (now - rtx_request_7),
1819 NULL)));
1820
1821 /* RTX packet 6 arrives, both 6, 7 and 8 is ready to be pulled */
1822 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
1823 generate_test_buffer_rtx (now, 6)));
1824
1825 for (gint i = 6; i <= 8; i++) {
1826 GstBuffer *buf = gst_harness_pull (h);
1827 fail_unless_equals_int (i, get_rtp_seq_num (buf));
1828 gst_buffer_unref (buf);
1829 }
1830
1831 /* RTX stats is updated with success count increased. */
1832 fail_unless (verify_jb_stats (h->element,
1833 gst_structure_new ("application/x-rtp-jitterbuffer-stats",
1834 "num-pushed", G_TYPE_UINT64, (guint64) num_init_buffers + 3,
1835 "num-lost", G_TYPE_UINT64, (guint64) 0,
1836 "num-late", G_TYPE_UINT64, (guint64) 0,
1837 "num-duplicates", G_TYPE_UINT64, (guint64) 1,
1838 "rtx-count", G_TYPE_UINT64, (guint64) 2,
1839 "rtx-success-count", G_TYPE_UINT64, (guint64) 1,
1840 "rtx-per-packet", G_TYPE_DOUBLE, 1.0,
1841 "rtx-rtt", G_TYPE_UINT64, (guint64)
1842 /* Use the rtx-rtt formula. Can be subject to change though. */
1843 ((now - rtx_request_6) + 47 * (now - rtx_request_7)) / 48,
1844 NULL)));
1845
1846 gst_object_unref (testclock);
1847 gst_harness_teardown (h);
1848}
1849
1850GST_END_TEST;
1851
1852GST_START_TEST (test_rtx_buffer_arrives_after_lost_updates_rtx_stats)
1853{
1854 GstHarness *h = gst_harness_new ("rtpjitterbuffer");
1855 GstTestClock *testclock;
1856 gint latency_ms = 5 * PCMU_BUF_MS;
1857 gint num_init_buffers = latency_ms / PCMU_BUF_MS + 1;
1858 GstClockTime now, last_rtx_request;
1859
1860 testclock = gst_harness_get_testclock (h);
1861 gst_harness_set_src_caps (h, generate_caps ());
1862 g_object_set (h->element, "do-retransmission", TRUE, "latency", latency_ms,
1863 "do-lost", TRUE, "rtx-max-retries", 1, NULL);
1864
1865 /* Push/pull buffers and advance time past buffer 0's timeout (in order to
1866 * simplify the test) */
1867 for (gint i = 0; i < num_init_buffers; i++) {
1868 gst_test_clock_set_time (testclock, i * PCMU_BUF_DURATION);
1869 fail_unless_equals_int (GST_FLOW_OK,
1870 gst_harness_push (h, generate_test_buffer (i)));
1871 gst_harness_wait_for_clock_id_waits (h, 1, 60);
1872 }
1873
1874 gst_harness_crank_single_clock_wait (h);
1875 fail_unless_equals_int64 (latency_ms * GST_MSECOND,
1876 gst_clock_get_time (GST_CLOCK (testclock)));
1877
1878 for (gint i = 0; i < num_init_buffers; i++)
1879 gst_buffer_unref (gst_harness_pull (h));
1880
1881 /* drop reconfigure event */
1882 gst_event_unref (gst_harness_pull_upstream_event (h));
1883 /* drop GstEventStreamStart & GstEventCaps & GstEventSegment */
1884 for (gint i = 0; i < 3; i++)
1885 gst_event_unref (gst_harness_pull_event (h));
1886
1887 /* Crank clock to send retransmission events requesting seqnum 6 which has
1888 * not arrived yet. */
1889 gst_harness_crank_single_clock_wait (h);
1890 verify_rtx_event (gst_harness_pull_upstream_event (h),
1891 6, 6 * PCMU_BUF_DURATION, 10, PCMU_BUF_DURATION);
1892
1893 last_rtx_request = gst_clock_get_time (GST_CLOCK (testclock));
1894 fail_unless_equals_int64 (last_rtx_request, 130 * GST_MSECOND);
1895
1896 /* seqnum 6 is considered lost */
1897 gst_harness_crank_single_clock_wait (h);
1898 verify_lost_event (gst_harness_pull_event (h), 6,
1899 6 * PCMU_BUF_DURATION, PCMU_BUF_DURATION);
1900
1901 /* seqnum 6 arrives too late */
1902 now = gst_clock_get_time (GST_CLOCK (testclock));
1903 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
1904 generate_test_buffer_rtx (now, 6)));
1905
1906 fail_unless (verify_jb_stats (h->element,
1907 gst_structure_new ("application/x-rtp-jitterbuffer-stats",
1908 "num-pushed", G_TYPE_UINT64, (guint64) num_init_buffers,
1909 "num-lost", G_TYPE_UINT64, (guint64) 1,
1910 "num-late", G_TYPE_UINT64, (guint64) 1,
1911 "num-duplicates", G_TYPE_UINT64, (guint64) 0,
1912 "rtx-count", G_TYPE_UINT64, (guint64) 1,
1913 "rtx-success-count", G_TYPE_UINT64, (guint64) 0,
1914 "rtx-per-packet", G_TYPE_DOUBLE, 1.0,
1915 "rtx-rtt", G_TYPE_UINT64, (guint64) (now - last_rtx_request),
1916 NULL)));
1917
1918 gst_object_unref (testclock);
1919 gst_harness_teardown (h);
1920}
1921
1922GST_END_TEST;
1923
1924GST_START_TEST (test_rtx_rtt_larger_than_retry_timeout)
1925{
1926 /* When RTT is larger than retry period we will send two or more requests
1927 * before receiving any retransmission packets */
1928 GstHarness *h = gst_harness_new ("rtpjitterbuffer");
1929 GstTestClock *testclock;
1930 gint latency_ms = 100;
1931 gint num_init_buffers = latency_ms / PCMU_BUF_MS + 1;
1932 gint rtx_retry_timeout_ms = 20;
1933 gint rtx_delay_ms = 10;
1934 gint rtt = rtx_retry_timeout_ms * GST_MSECOND + 1;
1935 GstClockTime now, first_request, second_request;
1936
1937 testclock = gst_harness_get_testclock (h);
1938 gst_harness_set_src_caps (h, generate_caps ());
1939 g_object_set (h->element, "do-retransmission", TRUE, "latency", latency_ms,
1940 "rtx-retry-timeout", rtx_retry_timeout_ms, NULL);
1941
1942 /* Push/pull buffers and advance time past buffer 0's timeout (in order to
1943 * simplify the test) */
1944 for (gint i = 0; i < num_init_buffers; i++) {
1945 gst_test_clock_set_time (testclock, i * PCMU_BUF_DURATION);
1946 fail_unless_equals_int (GST_FLOW_OK,
1947 gst_harness_push (h, generate_test_buffer (i)));
1948 gst_harness_wait_for_clock_id_waits (h, 1, 60);
1949 }
1950
1951 gst_harness_crank_single_clock_wait (h);
1952 fail_unless_equals_int64 (latency_ms * GST_MSECOND,
1953 gst_clock_get_time (GST_CLOCK (testclock)));
1954
1955 for (gint i = 0; i < num_init_buffers; i++)
1956 gst_buffer_unref (gst_harness_pull (h));
1957
1958 /* Drop reconfigure event */
1959 gst_event_unref (gst_harness_pull_upstream_event (h));
1960
1961 /* Wait for first NACK on 6 */
1962 gst_harness_crank_single_clock_wait (h);
1963 verify_rtx_event (gst_harness_pull_upstream_event (h),
1964 6, 6 * PCMU_BUF_DURATION, rtx_delay_ms, PCMU_BUF_DURATION);
1965 first_request = gst_clock_get_time (GST_CLOCK (testclock));
1966 fail_unless_equals_int64 (first_request,
1967 6 * PCMU_BUF_DURATION + rtx_delay_ms * GST_MSECOND);
1968
1969 /* Packet 7 arrives in time (so that we avoid its EXPECTED timers to
1970 * interfer with our test) */
1971 gst_test_clock_set_time (testclock, 7 * PCMU_BUF_DURATION);
1972 fail_unless_equals_int (GST_FLOW_OK,
1973 gst_harness_push (h, generate_test_buffer (7)));
1974
1975 /* Simulating RTT > rtx-retry-timeout, we send a new NACK before receiving
1976 * the RTX packet. Wait for second NACK on 6 */
1977 gst_harness_crank_single_clock_wait (h);
1978 rtx_delay_ms += rtx_retry_timeout_ms;
1979 verify_rtx_event (gst_harness_pull_upstream_event (h),
1980 6, 6 * PCMU_BUF_DURATION, rtx_delay_ms, PCMU_BUF_DURATION);
1981 second_request = gst_clock_get_time (GST_CLOCK (testclock));
1982 fail_unless_equals_int64 (second_request,
1983 6 * PCMU_BUF_DURATION + rtx_delay_ms * GST_MSECOND);
1984
1985 /* The first retransmitted packet arrives */
1986 now = first_request + rtt;
1987 gst_test_clock_set_time (testclock, now);
1988 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
1989 generate_test_buffer_rtx (now, 6)));
1990
1991 /* Pull packet 6 and 7 */
1992 gst_buffer_unref (gst_harness_pull (h));
1993 gst_buffer_unref (gst_harness_pull (h));
1994
1995 /* Stats should be updated. Note that RTT is not updated since we cannot be
1996 * sure whether the RTX packet is in response to the first or second NACK. */
1997 fail_unless (verify_jb_stats (h->element,
1998 gst_structure_new ("application/x-rtp-jitterbuffer-stats",
1999 "num-pushed", G_TYPE_UINT64, (guint64) num_init_buffers + 2,
2000 "num-lost", G_TYPE_UINT64, (guint64) 0,
2001 "num-late", G_TYPE_UINT64, (guint64) 0,
2002 "num-duplicates", G_TYPE_UINT64, (guint64) 0,
2003 "rtx-count", G_TYPE_UINT64, (guint64) 2,
2004 "rtx-success-count", G_TYPE_UINT64, (guint64) 1,
2005 "rtx-per-packet", G_TYPE_DOUBLE, 2.0,
2006 "rtx-rtt", G_TYPE_UINT64, (guint64) 0, NULL)));
2007
2008 /* Packet 8 arrives in time */
2009 gst_test_clock_set_time (testclock, 8 * PCMU_BUF_DURATION);
2010 fail_unless_equals_int (GST_FLOW_OK,
2011 gst_harness_push (h, generate_test_buffer (8)));
2012 gst_buffer_unref (gst_harness_pull (h));
2013
2014 /* Now the second retransmitted packet arrives */
2015 now = second_request + rtt;
2016 gst_test_clock_set_time (testclock, now);
2017 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
2018 generate_test_buffer_rtx (now, 6)));
2019
2020 /* The stats is updated with the correct RTT. */
2021 fail_unless (verify_jb_stats (h->element,
2022 gst_structure_new ("application/x-rtp-jitterbuffer-stats",
2023 "num-pushed", G_TYPE_UINT64, (guint64) num_init_buffers + 3,
2024 "num-lost", G_TYPE_UINT64, (guint64) 0,
2025 "num-late", G_TYPE_UINT64, (guint64) 0,
2026 "num-duplicates", G_TYPE_UINT64, (guint64) 1,
2027 "rtx-count", G_TYPE_UINT64, (guint64) 2,
2028 "rtx-success-count", G_TYPE_UINT64, (guint64) 1,
2029 "rtx-per-packet", G_TYPE_DOUBLE, 2.0,
2030 "rtx-rtt", G_TYPE_UINT64, (guint64) rtt, NULL)));
2031
2032 gst_object_unref (testclock);
2033 gst_harness_teardown (h);
2034}
2035
2036GST_END_TEST;
2037
2038GST_START_TEST (test_rtx_no_request_if_time_past_retry_period)
2039{
2040 GstHarness *h = gst_harness_new ("rtpjitterbuffer");
2041 const gint latency_ms = 200;
2042 const gint retry_period_ms = 120;
2043 GstTestClock *testclock;
2044 GstClockID pending_id, processed_id;
2045 GstClockTime time;
2046 GstEvent *event;
2047 gint i;
2048
2049 gst_harness_set_src_caps (h, generate_caps ());
2050 testclock = gst_harness_get_testclock (h);
2051
2052 g_object_set (h->element, "do-lost", TRUE, NULL);
2053 g_object_set (h->element, "do-retransmission", TRUE, NULL);
2054 g_object_set (h->element, "latency", latency_ms, NULL);
2055 g_object_set (h->element, "rtx-retry-period", retry_period_ms, NULL);
2056
2057 /* push the first couple of buffers */
2058 fail_unless_equals_int (GST_FLOW_OK,
2059 gst_harness_push (h, generate_test_buffer (0)));
2060
2061 gst_harness_set_time (h, 1 * PCMU_BUF_DURATION);
2062 fail_unless_equals_int (GST_FLOW_OK,
2063 gst_harness_push (h, generate_test_buffer (1)));
2064
2065 /* drop reconfigure event */
2066 gst_event_unref (gst_harness_pull_upstream_event (h));
2067 /* drop GstEventStreamStart & GstEventCaps & GstEventSegment */
2068 for (i = 0; i < 3; i++)
2069 gst_event_unref (gst_harness_pull_event (h));
2070
2071 /* Wait for the first EXPECTED timer to be scheduled */
2072 gst_test_clock_wait_for_next_pending_id (testclock, &pending_id);
2073 time = gst_clock_id_get_time (pending_id);
2074 fail_unless_equals_int64 (time, 2 * PCMU_BUF_DURATION + 10 * GST_MSECOND);
2075
2076 /* Let the first EXPECTED timer time out and be sent. However, set the 'now'
2077 * time to be past the retry-period simulating that the jitterbuffer has too
2078 * much to do and is not able to process all timers in real-time. In this
2079 * case the jitterbuffer should not schedule a new EXPECTED timer as that
2080 * would just make matters worse (more unnecessary processing of a request
2081 * that is already too late to be valuable). In practice this typically
2082 * happens for high loss networks with low RTT. */
2083 gst_test_clock_set_time (testclock,
2084 2 * PCMU_BUF_DURATION + retry_period_ms * GST_MSECOND + 1);
2085 processed_id = gst_test_clock_process_next_clock_id (testclock);
2086 fail_unless (pending_id == processed_id);
2087 gst_clock_id_unref (pending_id);
2088 gst_clock_id_unref (processed_id);
2089
2090 /* Verify the event. It could be argued that this request is already too
2091 * late and unnecessary. However, in order to keep things simple (for now)
2092 * we just keep the already scehduled EXPECTED timer, but refrain from
2093 * scheduled another EXPECTED timer */
2094 event = gst_harness_pull_upstream_event (h);
2095 verify_rtx_event (event, 2, 2 * PCMU_BUF_DURATION, 10, PCMU_BUF_DURATION);
2096
2097 /* "crank" to reach the DEADLINE for packet 0 */
2098 gst_harness_crank_single_clock_wait (h);
2099 gst_buffer_unref (gst_harness_pull (h));
2100 gst_buffer_unref (gst_harness_pull (h));
2101
2102 fail_unless_equals_int (0, gst_harness_upstream_events_in_queue (h));
2103 fail_unless_equals_int (0, gst_harness_events_in_queue (h));
2104
2105 /* "crank" to time out the LOST event */
2106 gst_harness_crank_single_clock_wait (h);
2107 event = gst_harness_pull_event (h);
2108 verify_lost_event (event, 2, 2 * PCMU_BUF_DURATION, PCMU_BUF_DURATION);
Sebastian Dröge45626bf2013-09-24 16:47:44 +02002109
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002110 gst_object_unref (testclock);
2111 gst_harness_teardown (h);
Sebastian Dröge45626bf2013-09-24 16:47:44 +02002112}
2113
2114GST_END_TEST;
2115
Sebastian Drögec33ae3b2017-01-30 15:44:11 +02002116GST_START_TEST (test_rtx_same_delay_and_retry_timeout)
2117{
2118 GstHarness *h = gst_harness_new ("rtpjitterbuffer");
2119 GstTestClock *testclock;
2120 gint latency_ms = 5 * PCMU_BUF_MS;
2121 gint num_init_buffers = latency_ms / PCMU_BUF_MS + 1;
2122 GstClockTime last_rtx_request;
2123
2124 testclock = gst_harness_get_testclock (h);
2125 gst_harness_set_src_caps (h, generate_caps ());
2126 g_object_set (h->element, "do-retransmission", TRUE, "latency", latency_ms,
2127 "rtx-max-retries", 3, "rtx-delay", 20, "rtx-retry-timeout", 20, NULL);
2128
2129 /* Push/pull buffers and advance time past buffer 0's timeout (in order to
2130 * simplify the test) */
2131 for (gint i = 0; i < num_init_buffers; i++) {
2132 gst_test_clock_set_time (testclock, i * PCMU_BUF_DURATION);
2133 fail_unless_equals_int (GST_FLOW_OK,
2134 gst_harness_push (h, generate_test_buffer (i)));
2135 gst_harness_wait_for_clock_id_waits (h, 1, 60);
2136 }
2137
2138 gst_harness_crank_single_clock_wait (h);
2139 fail_unless_equals_int64 (latency_ms * GST_MSECOND,
2140 gst_clock_get_time (GST_CLOCK (testclock)));
2141
2142 for (gint i = 0; i < num_init_buffers; i++)
2143 gst_buffer_unref (gst_harness_pull (h));
2144
2145 /* drop reconfigure event */
2146 gst_event_unref (gst_harness_pull_upstream_event (h));
2147
2148 /* Crank clock to send retransmission events requesting seqnum 6 which has
2149 * not arrived yet. */
2150 gst_harness_crank_single_clock_wait (h);
2151 verify_rtx_event (gst_harness_pull_upstream_event (h),
2152 6, 6 * PCMU_BUF_DURATION, 20, PCMU_BUF_DURATION);
2153 /* first rtx for seqnum 6 should arrive at 140ms */
2154 last_rtx_request = gst_clock_get_time (GST_CLOCK (testclock));
2155 fail_unless_equals_int64 (last_rtx_request, 140 * GST_MSECOND);
2156
2157 /* verify we have pulled out all rtx-events */
2158 fail_unless_equals_int (0, gst_harness_upstream_events_in_queue (h));
2159
2160 /* now crank to get the second attempt at seqnum 6 */
2161 gst_harness_crank_single_clock_wait (h);
2162 verify_rtx_event (gst_harness_pull_upstream_event (h),
2163 6, 6 * PCMU_BUF_DURATION, 40, PCMU_BUF_DURATION);
2164 /* second rtx for seqnum 6 should arrive at 140 + 20ms */
2165 last_rtx_request = gst_clock_get_time (GST_CLOCK (testclock));
2166 fail_unless_equals_int64 (last_rtx_request, 160 * GST_MSECOND);
2167
2168 /* verify we have pulled out all rtx-events */
2169 fail_unless_equals_int (0, gst_harness_upstream_events_in_queue (h));
2170
2171 fail_unless (verify_jb_stats (h->element,
2172 gst_structure_new ("application/x-rtp-jitterbuffer-stats",
2173 "num-pushed", G_TYPE_UINT64, (guint64) num_init_buffers,
2174 "num-lost", G_TYPE_UINT64, (guint64) 0,
2175 "rtx-count", G_TYPE_UINT64, (guint64) 2, NULL)));
2176
2177 gst_object_unref (testclock);
2178 gst_harness_teardown (h);
2179}
2180
2181GST_END_TEST;
2182
2183
2184GST_START_TEST (test_rtx_with_backwards_rtptime)
2185{
2186 GstHarness *h = gst_harness_new ("rtpjitterbuffer");
2187 GstEvent *event;
2188 gint jb_latency_ms = 40;
2189 gint i;
2190
2191 gst_harness_set_src_caps (h, generate_caps ());
2192 g_object_set (h->element,
2193 "do-retransmission", TRUE,
2194 "latency", jb_latency_ms,
2195 NULL);
2196
2197 /* push the first buffer through */
2198 fail_unless_equals_int (GST_FLOW_OK,
2199 gst_harness_push (h, generate_test_buffer (0)));
2200 fail_unless (gst_harness_crank_single_clock_wait (h));
2201 gst_buffer_unref (gst_harness_pull (h));
2202
2203 /* push some buffers arriving in perfect time! */
2204 for (i = 1; i <= 2; i++) {
2205 fail_unless_equals_int (GST_FLOW_OK,
2206 gst_harness_push (h, generate_test_buffer (i)));
2207 gst_buffer_unref (gst_harness_pull (h));
2208 }
2209
2210 /*
2211 For video using B-frames, an expected sequence
2212 could be like this:
2213 (I = I-frame, P = P-frame, B = B-frame)
2214 ___ ___ ___
2215 ... | 3 | | 4 | | 5 |
2216 ––– ––– –––
2217 rtptime: 3(I) 5(P) 4(B)
2218arrival(dts): 3 5 5
2219
2220 Notice here that packet 5 (the B frame) make
2221 the rtptime go backwards.
2222 */
2223
2224 /* seqnum 3, arriving at time 3 with rtptime 3 */
2225 fail_unless_equals_int (GST_FLOW_OK,
2226 gst_harness_push (h, generate_test_buffer (3)));
2227 gst_buffer_unref (gst_harness_pull (h));
2228
2229 /* seqnum 4, arriving at time 5 with rtptime 5 */
2230 gst_harness_push (h, generate_test_buffer_full (
2231 5 * PCMU_BUF_DURATION, FALSE, 4, 5 * PCMU_RTP_TS_DURATION));
2232 gst_buffer_unref (gst_harness_pull (h));
2233
2234 /* seqnum 5, arriving at time 5 with rtptime 4 */
2235 gst_harness_push (h, generate_test_buffer_full (
2236 5 * PCMU_BUF_DURATION, FALSE, 5, 4 * PCMU_RTP_TS_DURATION));
2237
2238 /* drop reconfigure event */
2239 gst_event_unref (gst_harness_pull_upstream_event (h));
2240
2241 /* crank to time-out the rtx-request for seqnum 6, the point here
2242 being that the backwards rtptime did not mess up the timeout for
2243 the rtx event */
2244 gst_harness_crank_single_clock_wait (h);
2245 event = gst_harness_pull_upstream_event (h);
2246 verify_rtx_event (event, 6, 5 * PCMU_BUF_DURATION + 15 * GST_MSECOND,
2247 17, 35 * GST_MSECOND);
2248
2249 fail_unless (verify_jb_stats (h->element,
2250 gst_structure_new ("application/x-rtp-jitterbuffer-stats",
2251 "num-pushed", G_TYPE_UINT64, (guint64) 6,
2252 "rtx-count", G_TYPE_UINT64, (guint64) 1,
2253 "num-lost", G_TYPE_UINT64, (guint64) 0, NULL)));
2254
2255 gst_harness_teardown (h);
2256}
2257
2258GST_END_TEST;
2259
2260GST_START_TEST (test_rtx_timer_reuse)
2261{
2262 GstHarness *h = gst_harness_new ("rtpjitterbuffer");
2263 GstTestClock *testclock;
2264 gint latency_ms = 5 * PCMU_BUF_MS;
2265 gint num_init_buffers = latency_ms / PCMU_BUF_MS + 1;
2266
2267 testclock = gst_harness_get_testclock (h);
2268 gst_harness_set_src_caps (h, generate_caps ());
2269 g_object_set (h->element, "do-retransmission", TRUE, "latency", latency_ms,
2270 "do-lost", TRUE, "rtx-max-retries", 1, NULL);
2271
2272 /* Push/pull buffers and advance time past buffer 0's timeout (in order to
2273 * simplify the test) */
2274 for (gint i = 0; i < num_init_buffers; i++) {
2275 gst_test_clock_set_time (testclock, i * PCMU_BUF_DURATION);
2276 fail_unless_equals_int (GST_FLOW_OK,
2277 gst_harness_push (h, generate_test_buffer (i)));
2278 gst_harness_wait_for_clock_id_waits (h, 1, 60);
2279 }
2280
2281 gst_harness_crank_single_clock_wait (h);
2282 fail_unless_equals_int64 (latency_ms * GST_MSECOND,
2283 gst_clock_get_time (GST_CLOCK (testclock)));
2284
2285 for (gint i = 0; i < num_init_buffers; i++)
2286 gst_buffer_unref (gst_harness_pull (h));
2287
2288 /* drop reconfigure event */
2289 gst_event_unref (gst_harness_pull_upstream_event (h));
2290
2291 /* crank to timeout the only rtx-request, and the timer will
2292 * now reschedule as a lost-timer internally */
2293 gst_harness_crank_single_clock_wait (h);
2294 verify_rtx_event (gst_harness_pull_upstream_event (h),
2295 6, 6 * PCMU_BUF_DURATION, 10, PCMU_BUF_DURATION);
2296
2297 /* but now buffer 6 arrives, and this should now reuse the lost-timer
2298 * for 6, as an expected-timer for 7 */
2299 fail_unless_equals_int (GST_FLOW_OK,
2300 gst_harness_push (h, generate_test_buffer (6)));
2301
2302 /* now crank to timeout the expected-timer for 7 and verify */
2303 gst_harness_crank_single_clock_wait (h);
2304 verify_rtx_event (gst_harness_pull_upstream_event (h),
2305 7, 7 * PCMU_BUF_DURATION, 10, PCMU_BUF_DURATION);
2306
2307 gst_object_unref (testclock);
2308 gst_harness_teardown (h);
2309}
2310
2311GST_END_TEST;
2312
Sebastian Dröge26c075e2014-05-21 12:35:11 +02002313GST_START_TEST (test_gap_exceeds_latency)
2314{
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002315 GstHarness *h = gst_harness_new ("rtpjitterbuffer");
2316 GstTestClock *testclock;
2317 const gint jb_latency_ms = 200;
2318
Sebastian Dröge26c075e2014-05-21 12:35:11 +02002319 gint i;
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002320 GstEvent *out_event;
2321 GstBuffer *out_buf;
Sebastian Dröge26c075e2014-05-21 12:35:11 +02002322
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002323 gst_harness_set_src_caps (h, generate_caps ());
2324 testclock = gst_harness_get_testclock (h);
Sebastian Dröge26c075e2014-05-21 12:35:11 +02002325
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002326 g_object_set (h->element, "do-lost", TRUE, NULL);
2327 g_object_set (h->element, "do-retransmission", TRUE, NULL);
2328 g_object_set (h->element, "latency", jb_latency_ms, NULL);
2329 g_object_set (h->element, "rtx-retry-period", 120, NULL);
2330
2331 /* push the first buffer in */
2332 fail_unless_equals_int (GST_FLOW_OK,
2333 gst_harness_push (h, generate_test_buffer (0)));
Sebastian Dröge26c075e2014-05-21 12:35:11 +02002334
Sebastian Drögee08b7df2016-09-30 12:19:10 +03002335 gst_harness_set_time (h, 1 * PCMU_BUF_DURATION);
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002336 fail_unless_equals_int (GST_FLOW_OK,
2337 gst_harness_push (h, generate_test_buffer (1)));
2338
2339 /* drop reconfigure event */
2340 gst_event_unref (gst_harness_pull_upstream_event (h));
2341 /* drop GstEventStreamStart & GstEventCaps & GstEventSegment */
2342 for (i = 0; i < 3; i++)
2343 gst_event_unref (gst_harness_pull_event (h));
Sebastian Dröge26c075e2014-05-21 12:35:11 +02002344
2345 /* Allow seqnum 2 to be declared lost */
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002346 for (i = 0; i < 3; i++) {
2347 gst_harness_crank_single_clock_wait (h);
2348 out_event = gst_harness_pull_upstream_event (h);
2349 verify_rtx_event (out_event,
2350 2, 2 * PCMU_BUF_DURATION, 10 + 40 * i, PCMU_BUF_DURATION);
Sebastian Dröge26c075e2014-05-21 12:35:11 +02002351 }
2352
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002353 /* buffer 0 & 1 */
2354 gst_harness_crank_single_clock_wait (h);
2355 for (i = 0; i < 2; i++) {
2356 out_buf = gst_harness_pull (h);
2357 fail_unless_equals_int (i, get_rtp_seq_num (out_buf));
Sebastian Dröge26c075e2014-05-21 12:35:11 +02002358 gst_buffer_unref (out_buf);
2359 }
2360
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002361 /* lost event */
2362 gst_harness_crank_single_clock_wait (h);
2363 out_event = gst_harness_pull_event (h);
2364 verify_lost_event (out_event, 2, 2 * PCMU_BUF_DURATION, PCMU_BUF_DURATION);
Sebastian Dröge26c075e2014-05-21 12:35:11 +02002365
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002366 /* Now data comes in again, a "bulk" lost packet is created for 3 -> 5 */
2367 fail_unless_equals_int (GST_FLOW_OK,
2368 gst_harness_push (h, generate_test_buffer (16)));
Sebastian Dröge26c075e2014-05-21 12:35:11 +02002369
Sebastian Drögee08b7df2016-09-30 12:19:10 +03002370 /* Manually check the first rtx event */
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002371 out_event = gst_harness_pull_upstream_event (h);
Sebastian Drögee08b7df2016-09-30 12:19:10 +03002372 verify_rtx_event (out_event, 6, 6 * PCMU_BUF_DURATION, 10, PCMU_BUF_DURATION);
2373 /* Go throught the rest of rtx events. A bit more relaxed since order is
2374 * partly an implentation detail. */
2375 for (i = 0; i < 12; i++) {
2376 const GstStructure *s;
2377 guint seqnum, retry;
2378
2379 fail_unless (out_event = gst_harness_pull_upstream_event (h));
2380 fail_unless (s = gst_event_get_structure (out_event));
2381 fail_unless (gst_structure_get_uint (s, "seqnum", &seqnum));
2382 fail_unless (gst_structure_get_uint (s, "retry", &retry));
2383 fail_unless (seqnum >= 6 && seqnum <= 12);
2384
2385 verify_rtx_event (out_event, seqnum, seqnum * PCMU_BUF_DURATION,
2386 10 + retry * 40, PCMU_BUF_DURATION);
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002387 }
Sebastian Dröge26c075e2014-05-21 12:35:11 +02002388
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002389 fail_unless_equals_int (0, gst_harness_upstream_events_in_queue (h));
2390 fail_unless_equals_int (0, gst_harness_events_in_queue (h));
2391 fail_unless_equals_int (0, gst_harness_buffers_in_queue (h));
2392
2393 for (i = 8; i < 16; i++) {
2394 fail_unless_equals_int (GST_FLOW_OK,
2395 gst_harness_push (h, generate_test_buffer (i)));
2396 }
2397
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002398 gst_harness_crank_single_clock_wait (h);
2399 out_event = gst_harness_pull_event (h);
Sebastian Drögee08b7df2016-09-30 12:19:10 +03002400 verify_lost_event (out_event, 3, 3 * PCMU_BUF_DURATION,
2401 3 * PCMU_BUF_DURATION);
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002402
2403 gst_harness_crank_single_clock_wait (h);
2404 out_event = gst_harness_pull_event (h);
Sebastian Drögee08b7df2016-09-30 12:19:10 +03002405 verify_lost_event (out_event, 6, 6 * PCMU_BUF_DURATION,
2406 1 * PCMU_BUF_DURATION);
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002407
2408 gst_harness_crank_single_clock_wait (h);
2409 out_event = gst_harness_pull_event (h);
Sebastian Drögee08b7df2016-09-30 12:19:10 +03002410 verify_lost_event (out_event, 7, 7 * PCMU_BUF_DURATION,
2411 1 * PCMU_BUF_DURATION);
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002412
2413 /* 8 */
2414 for (i = 8; i <= 16; i++) {
2415 GstBuffer *out_buf = gst_harness_pull (h);
2416 GST_DEBUG ("pop %d", i);
2417 fail_unless_equals_int (i, get_rtp_seq_num (out_buf));
2418 gst_buffer_unref (out_buf);
2419 }
2420
2421 fail_unless_equals_int (0, gst_harness_upstream_events_in_queue (h));
2422 fail_unless_equals_int (0, gst_harness_events_in_queue (h));
2423 fail_unless_equals_int (0, gst_harness_buffers_in_queue (h));
2424
2425 /* rtx x 3 */
2426 for (i = 0; i < 3; i++) {
2427 gst_harness_crank_single_clock_wait (h);
2428 out_event = gst_harness_pull_upstream_event (h);
2429 verify_rtx_event (out_event,
2430 17, 17 * PCMU_BUF_DURATION, 10 + 40 * i, PCMU_BUF_DURATION);
2431 }
2432
2433 /* lost event for 17 */
2434 gst_harness_crank_single_clock_wait (h);
2435 out_event = gst_harness_pull_event (h);
2436 verify_lost_event (out_event, 17, 17 * PCMU_BUF_DURATION, PCMU_BUF_DURATION);
2437
2438 fail_unless_equals_int (0, gst_harness_upstream_events_in_queue (h));
2439 fail_unless_equals_int (0, gst_harness_events_in_queue (h));
2440 fail_unless_equals_int (0, gst_harness_buffers_in_queue (h));
2441
Sebastian Drögee08b7df2016-09-30 12:19:10 +03002442 fail_unless (verify_jb_stats (h->element,
2443 gst_structure_new ("application/x-rtp-jitterbuffer-stats",
2444 "num-pushed", G_TYPE_UINT64, (guint64) 11,
2445 "num-lost", G_TYPE_UINT64, (guint64) 7,
2446 "rtx-count", G_TYPE_UINT64, (guint64) 19,
2447 "rtx-success-count", G_TYPE_UINT64, (guint64) 0,
2448 "rtx-rtt", G_TYPE_UINT64, (guint64) 0, NULL)));
2449
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002450 gst_object_unref (testclock);
2451 gst_harness_teardown (h);
Sebastian Dröge26c075e2014-05-21 12:35:11 +02002452}
2453
2454GST_END_TEST;
2455
Sebastian Dröge87041172015-03-17 09:12:48 +01002456GST_START_TEST (test_deadline_ts_offset)
2457{
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002458 GstHarness *h = gst_harness_new ("rtpjitterbuffer");
2459 GstTestClock *testclock;
2460 GstClockID id;
2461 const gint jb_latency_ms = 10;
Sebastian Dröge87041172015-03-17 09:12:48 +01002462
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002463 gst_harness_set_src_caps (h, generate_caps ());
2464 testclock = gst_harness_get_testclock (h);
Sebastian Dröge87041172015-03-17 09:12:48 +01002465
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002466 g_object_set (h->element, "latency", jb_latency_ms, NULL);
Sebastian Dröge87041172015-03-17 09:12:48 +01002467
2468 /* push the first buffer in */
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002469 fail_unless_equals_int (GST_FLOW_OK,
2470 gst_harness_push (h, generate_test_buffer (0)));
Sebastian Dröge87041172015-03-17 09:12:48 +01002471
2472 /* wait_next_timeout() syncs on the deadline timer */
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002473 gst_test_clock_wait_for_next_pending_id (testclock, &id);
2474 fail_unless_equals_uint64 (jb_latency_ms * GST_MSECOND,
2475 gst_clock_id_get_time (id));
2476 gst_clock_id_unref (id);
Sebastian Dröge87041172015-03-17 09:12:48 +01002477
2478 /* add ts-offset while waiting */
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002479 g_object_set (h->element, "ts-offset", 20 * GST_MSECOND, NULL);
Sebastian Dröge87041172015-03-17 09:12:48 +01002480
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002481 gst_test_clock_set_time_and_process (testclock, jb_latency_ms * GST_MSECOND);
Sebastian Dröge87041172015-03-17 09:12:48 +01002482
2483 /* wait_next_timeout() syncs on the new deadline timer */
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002484 gst_test_clock_wait_for_next_pending_id (testclock, &id);
2485 fail_unless_equals_uint64 ((20 + jb_latency_ms) * GST_MSECOND,
2486 gst_clock_id_get_time (id));
2487 gst_clock_id_unref (id);
Sebastian Dröge87041172015-03-17 09:12:48 +01002488
2489 /* now make deadline timer timeout */
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002490 gst_test_clock_set_time_and_process (testclock,
Sebastian Dröge87041172015-03-17 09:12:48 +01002491 (20 + jb_latency_ms) * GST_MSECOND);
Sebastian Dröge87041172015-03-17 09:12:48 +01002492
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002493 gst_buffer_unref (gst_harness_pull (h));
Sebastian Dröge87041172015-03-17 09:12:48 +01002494
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002495 gst_object_unref (testclock);
2496 gst_harness_teardown (h);
Sebastian Dröge87041172015-03-17 09:12:48 +01002497}
2498
2499GST_END_TEST;
2500
Sebastian Drögec33ae3b2017-01-30 15:44:11 +02002501GST_START_TEST (test_gap_larger_than_latency)
Sebastian Drögeb04f9722015-08-19 13:19:08 +03002502{
2503 GstHarness *h = gst_harness_new ("rtpjitterbuffer");
2504 GstTestClock *testclock;
2505 GstEvent *out_event;
2506 gint jb_latency_ms = 100;
Sebastian Drögeb04f9722015-08-19 13:19:08 +03002507
2508 gst_harness_set_src_caps (h, generate_caps ());
Sebastian Drögeb04f9722015-08-19 13:19:08 +03002509 testclock = gst_harness_get_testclock (h);
2510 g_object_set (h->element, "do-lost", TRUE, "latency", jb_latency_ms, NULL);
2511
2512 /* push first buffer through */
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002513 fail_unless_equals_int (GST_FLOW_OK,
2514 gst_harness_push (h, generate_test_buffer (0)));
2515 fail_unless (gst_harness_crank_single_clock_wait (h));
Sebastian Drögeb04f9722015-08-19 13:19:08 +03002516 gst_buffer_unref (gst_harness_pull (h));
2517
Sebastian Drögec33ae3b2017-01-30 15:44:11 +02002518 /* we have 100ms latency, so drop 6 packets (120ms) */
2519 gst_harness_set_time (h, 7 * PCMU_BUF_DURATION);
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002520 fail_unless_equals_int (GST_FLOW_OK,
Sebastian Drögec33ae3b2017-01-30 15:44:11 +02002521 gst_harness_push (h, generate_test_buffer (7)));
Sebastian Drögeb04f9722015-08-19 13:19:08 +03002522
2523 /* drop GstEventStreamStart & GstEventCaps & GstEventSegment */
2524 for (int i = 0; i < 3; i++)
2525 gst_event_unref (gst_harness_pull_event (h));
2526
Sebastian Drögec33ae3b2017-01-30 15:44:11 +02002527 /* Packet 1 and 2 are already lost at this point */
2528 for (gint i = 1; i <= 2; i++) {
2529 out_event = gst_harness_pull_event (h);
2530 verify_lost_event (out_event, i, i * PCMU_BUF_DURATION, PCMU_BUF_DURATION);
2531 }
2532
2533 /* Packets 3-6 have to be timed out */
2534 for (gint i = 3; i <= 6; i++) {
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002535 fail_unless (gst_harness_crank_single_clock_wait (h));
Sebastian Drögeb04f9722015-08-19 13:19:08 +03002536 out_event = gst_harness_pull_event (h);
Sebastian Drögec33ae3b2017-01-30 15:44:11 +02002537 verify_lost_event (out_event, i, i * PCMU_BUF_DURATION, PCMU_BUF_DURATION);
Sebastian Drögeb04f9722015-08-19 13:19:08 +03002538 }
2539
Sebastian Drögec33ae3b2017-01-30 15:44:11 +02002540 /* and finally pull out buffer 7 */
2541 gst_buffer_unref (gst_harness_pull (h));
2542
Sebastian Drögee08b7df2016-09-30 12:19:10 +03002543 fail_unless (verify_jb_stats (h->element,
2544 gst_structure_new ("application/x-rtp-jitterbuffer-stats",
Sebastian Drögec33ae3b2017-01-30 15:44:11 +02002545 "num-lost", G_TYPE_UINT64, (guint64) 6, NULL)));
Sebastian Drögee08b7df2016-09-30 12:19:10 +03002546
Sebastian Drögeb04f9722015-08-19 13:19:08 +03002547 gst_object_unref (testclock);
2548 gst_harness_teardown (h);
2549}
2550
2551GST_END_TEST;
Sebastian Dröge26c075e2014-05-21 12:35:11 +02002552
Sebastian Drögeffda8362016-02-19 11:16:13 +02002553GST_START_TEST (test_push_big_gap)
2554{
2555 GstHarness *h = gst_harness_new ("rtpjitterbuffer");
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002556 GstBuffer *buf;
Sebastian Drögeffda8362016-02-19 11:16:13 +02002557 const gint num_consecutive = 5;
2558 gint i;
2559
Sebastian Drögeffda8362016-02-19 11:16:13 +02002560 gst_harness_set_src_caps (h, generate_caps ());
2561
2562 for (i = 0; i < num_consecutive; i++)
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002563 fail_unless_equals_int (GST_FLOW_OK,
2564 gst_harness_push (h, generate_test_buffer (1000 + i)));
2565
2566 fail_unless (gst_harness_crank_single_clock_wait (h));
2567
2568 for (i = 0; i < num_consecutive; i++) {
2569 GstBuffer *buf = gst_harness_pull (h);
2570 fail_unless_equals_int (1000 + i, get_rtp_seq_num (buf));
2571 gst_buffer_unref (buf);
2572 }
Sebastian Drögeffda8362016-02-19 11:16:13 +02002573
2574 /* Push more packets from a different sequence number domain
2575 * to trigger "big gap" logic. */
2576 for (i = 0; i < num_consecutive; i++)
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002577 fail_unless_equals_int (GST_FLOW_OK,
2578 gst_harness_push (h, generate_test_buffer (20000 + i)));
2579
2580 fail_unless (gst_harness_crank_single_clock_wait (h));
2581
2582 for (i = 0; i < num_consecutive; i++) {
2583 GstBuffer *buf = gst_harness_pull (h);
2584 fail_unless_equals_int (20000 + i, get_rtp_seq_num (buf));
2585 gst_buffer_unref (buf);
2586 }
Sebastian Drögeffda8362016-02-19 11:16:13 +02002587
2588 /* Final buffer should be pushed straight through */
Sebastian Drögec9e739b2016-03-01 17:11:14 +02002589 fail_unless_equals_int (GST_FLOW_OK,
2590 gst_harness_push (h, generate_test_buffer (20000 + num_consecutive)));
2591 buf = gst_harness_pull (h);
2592 fail_unless_equals_int (20000 + num_consecutive, get_rtp_seq_num (buf));
2593 gst_buffer_unref (buf);
Sebastian Drögeffda8362016-02-19 11:16:13 +02002594
2595 gst_harness_teardown (h);
2596}
2597
2598GST_END_TEST;
2599
Sebastian Dröge0afcd5c2016-06-09 11:25:16 +03002600typedef struct
2601{
2602 guint seqnum_offset;
2603 guint late_buffer;
2604} TestLateArrivalInput;
2605
2606static const TestLateArrivalInput
2607 test_considered_lost_packet_in_large_gap_arrives_input[] = {
2608 {0, 1}, {0, 2}, {65535, 1}, {65535, 2}, {65534, 1}, {65534, 2}
2609};
2610
2611GST_START_TEST (test_considered_lost_packet_in_large_gap_arrives)
2612{
2613 GstHarness *h = gst_harness_new ("rtpjitterbuffer");
2614 GstTestClock *testclock;
2615 GstClockID id;
2616 GstBuffer *buffer;
2617 gint jb_latency_ms = 20;
2618 GstEvent *event;
2619 const TestLateArrivalInput *test_input =
2620 &test_considered_lost_packet_in_large_gap_arrives_input[__i__];
2621 guint seq_offset = test_input->seqnum_offset;
2622 guint late_buffer = test_input->late_buffer;
2623
2624 gst_harness_set_src_caps (h, generate_caps ());
2625 testclock = gst_harness_get_testclock (h);
2626 g_object_set (h->element, "do-lost", TRUE, "latency", jb_latency_ms, NULL);
2627
2628 /* first push buffer 0 */
2629 fail_unless_equals_int (GST_FLOW_OK,
2630 gst_harness_push (h, generate_test_buffer_full (0 * PCMU_BUF_DURATION,
2631 TRUE, 0 + seq_offset, 0 * PCMU_RTP_TS_DURATION)));
2632 fail_unless (gst_harness_crank_single_clock_wait (h));
2633 gst_buffer_unref (gst_harness_pull (h));
2634
2635 /* drop GstEventStreamStart & GstEventCaps & GstEventSegment */
2636 for (gint i = 0; i < 3; i++)
2637 gst_event_unref (gst_harness_pull_event (h));
2638
2639 /* hop over 3 packets, and push buffer 4 (gap of 3) */
2640 fail_unless_equals_int (GST_FLOW_OK,
2641 gst_harness_push (h, generate_test_buffer_full (4 * PCMU_BUF_DURATION,
2642 TRUE, 4 + seq_offset, 4 * PCMU_RTP_TS_DURATION)));
2643
2644 /* the jitterbuffer should be waiting for the timeout of a "large gap timer"
2645 * for buffer 1 and 2 */
2646 gst_test_clock_wait_for_next_pending_id (testclock, &id);
2647 fail_unless_equals_uint64 (1 * PCMU_BUF_DURATION +
2648 jb_latency_ms * GST_MSECOND, gst_clock_id_get_time (id));
2649 gst_clock_id_unref (id);
2650
2651 /* now buffer 1 sneaks in before the lost event for buffer 1 and 2 is
2652 * processed */
2653 fail_unless_equals_int (GST_FLOW_OK,
2654 gst_harness_push (h,
2655 generate_test_buffer_full (late_buffer * PCMU_BUF_DURATION, TRUE,
2656 late_buffer + seq_offset, late_buffer * PCMU_RTP_TS_DURATION)));
2657
2658 /* time out for lost packets 1 and 2 (one event, double duration) */
2659 fail_unless (gst_harness_crank_single_clock_wait (h));
2660 event = gst_harness_pull_event (h);
2661 verify_lost_event (event, 1 + seq_offset, 1 * PCMU_BUF_DURATION,
2662 2 * PCMU_BUF_DURATION);
2663
2664 /* time out for lost packets 3 */
2665 fail_unless (gst_harness_crank_single_clock_wait (h));
2666 event = gst_harness_pull_event (h);
2667 verify_lost_event (event, 3 + seq_offset, 3 * PCMU_BUF_DURATION,
2668 1 * PCMU_BUF_DURATION);
2669
2670 /* buffer 4 is pushed as normal */
2671 buffer = gst_harness_pull (h);
2672 fail_unless_equals_int ((4 + seq_offset) & 0xffff, get_rtp_seq_num (buffer));
2673 gst_buffer_unref (buffer);
2674
Sebastian Drögee08b7df2016-09-30 12:19:10 +03002675 /* we have lost 3, and one of them arrived eventually, but too late */
2676 fail_unless (verify_jb_stats (h->element,
2677 gst_structure_new ("application/x-rtp-jitterbuffer-stats",
2678 "num-pushed", G_TYPE_UINT64, (guint64) 2,
2679 "num-lost", G_TYPE_UINT64, (guint64) 3,
2680 "num-late", G_TYPE_UINT64, (guint64) 1, NULL)));
2681
Sebastian Dröge0afcd5c2016-06-09 11:25:16 +03002682 gst_object_unref (testclock);
2683 gst_harness_teardown (h);
2684}
2685
2686GST_END_TEST;
2687
Sebastian Drögee08b7df2016-09-30 12:19:10 +03002688GST_START_TEST (test_performance)
2689{
2690 GstHarness *h =
2691 gst_harness_new_parse
2692 ("rtpjitterbuffer do-lost=1 do-retransmission=1 latency=1000");
2693 GTimer *timer = g_timer_new ();
2694 const gdouble test_duration = 2.0;
2695 guint buffers_pushed = 0;
2696 guint buffers_received;
2697
2698 gst_harness_set_src_caps (h, generate_caps ());
2699 gst_harness_use_systemclock (h);
2700
2701 while (g_timer_elapsed (timer, NULL) < test_duration) {
2702 /* Simulate 1ms packets */
2703 guint n = buffers_pushed * 2; // every packet also produces a gap
2704 guint16 seqnum = n & 0xffff;
2705 guint32 rtp_ts = n * 8;
2706 GstClockTime dts = n * GST_MSECOND;
2707 gst_harness_push (h, generate_test_buffer_full (dts, TRUE, seqnum, rtp_ts));
2708 buffers_pushed++;
2709 g_usleep (G_USEC_PER_SEC / 10000);
2710 }
2711 g_timer_destroy (timer);
2712
2713 buffers_received = gst_harness_buffers_received (h);
2714 GST_INFO ("Pushed %d, received %d (%.1f%%)", buffers_pushed, buffers_received,
2715 100.0 * buffers_received / buffers_pushed);
2716
2717 gst_harness_teardown (h);
2718}
2719
2720GST_END_TEST;
2721
Olivier Naudan988c6f02012-04-16 07:16:25 -04002722static Suite *
2723rtpjitterbuffer_suite (void)
2724{
2725 Suite *s = suite_create ("rtpjitterbuffer");
2726 TCase *tc_chain = tcase_create ("general");
2727
2728 suite_add_tcase (s, tc_chain);
2729 tcase_add_test (tc_chain, test_push_forward_seq);
2730 tcase_add_test (tc_chain, test_push_backward_seq);
2731 tcase_add_test (tc_chain, test_push_unordered);
2732 tcase_add_test (tc_chain, test_basetime);
Sebastian Dröge42103d12013-12-27 10:59:10 +01002733 tcase_add_test (tc_chain, test_clear_pt_map);
Sebastian Drögee08b7df2016-09-30 12:19:10 +03002734
Sebastian Dröge5f0bab02013-07-14 11:42:29 +02002735 tcase_add_test (tc_chain, test_only_one_lost_event_on_large_gaps);
2736 tcase_add_test (tc_chain, test_two_lost_one_arrives_in_time);
2737 tcase_add_test (tc_chain, test_late_packets_still_makes_lost_events);
Sebastian Drögec33ae3b2017-01-30 15:44:11 +02002738 tcase_add_test (tc_chain, test_lost_event_uses_pts);
2739 tcase_add_test (tc_chain, test_lost_event_with_backwards_rtptime);
2740
Sebastian Dröge5f0bab02013-07-14 11:42:29 +02002741 tcase_add_test (tc_chain, test_all_packets_are_timestamped_zero);
Sebastian Drögee08b7df2016-09-30 12:19:10 +03002742 tcase_add_loop_test (tc_chain, test_num_late_when_considered_lost_arrives, 0,
2743 2);
2744 tcase_add_test (tc_chain, test_reorder_of_non_equidistant_packets);
2745 tcase_add_test (tc_chain,
2746 test_loss_equidistant_spacing_with_parameter_packets);
2747
Sebastian Dröge45626bf2013-09-24 16:47:44 +02002748 tcase_add_test (tc_chain, test_rtx_expected_next);
2749 tcase_add_test (tc_chain, test_rtx_two_missing);
2750 tcase_add_test (tc_chain, test_rtx_packet_delay);
Sebastian Drögee08b7df2016-09-30 12:19:10 +03002751 tcase_add_test (tc_chain, test_rtx_buffer_arrives_just_in_time);
2752 tcase_add_test (tc_chain, test_rtx_buffer_arrives_too_late);
2753 tcase_add_test (tc_chain, test_rtx_original_buffer_does_not_update_rtx_stats);
2754 tcase_add_test (tc_chain, test_rtx_duplicate_packet_updates_rtx_stats);
2755 tcase_add_test (tc_chain,
2756 test_rtx_buffer_arrives_after_lost_updates_rtx_stats);
2757 tcase_add_test (tc_chain, test_rtx_rtt_larger_than_retry_timeout);
2758 tcase_add_test (tc_chain, test_rtx_no_request_if_time_past_retry_period);
Sebastian Drögec33ae3b2017-01-30 15:44:11 +02002759 tcase_add_test (tc_chain, test_rtx_same_delay_and_retry_timeout);
2760 tcase_add_test (tc_chain, test_rtx_with_backwards_rtptime);
2761 tcase_add_test (tc_chain, test_rtx_timer_reuse);
Sebastian Drögee08b7df2016-09-30 12:19:10 +03002762
Sebastian Dröge26c075e2014-05-21 12:35:11 +02002763 tcase_add_test (tc_chain, test_gap_exceeds_latency);
Sebastian Dröge87041172015-03-17 09:12:48 +01002764 tcase_add_test (tc_chain, test_deadline_ts_offset);
Sebastian Drögec33ae3b2017-01-30 15:44:11 +02002765 tcase_add_test (tc_chain, test_gap_larger_than_latency);
Sebastian Drögeffda8362016-02-19 11:16:13 +02002766 tcase_add_test (tc_chain, test_push_big_gap);
Olivier Naudan988c6f02012-04-16 07:16:25 -04002767
Sebastian Dröge0afcd5c2016-06-09 11:25:16 +03002768 tcase_add_loop_test (tc_chain,
2769 test_considered_lost_packet_in_large_gap_arrives, 0,
2770 G_N_ELEMENTS (test_considered_lost_packet_in_large_gap_arrives_input));
2771
Sebastian Drögee08b7df2016-09-30 12:19:10 +03002772 tcase_add_test (tc_chain, test_performance);
2773
Olivier Naudan988c6f02012-04-16 07:16:25 -04002774 return s;
2775}
2776
2777GST_CHECK_MAIN (rtpjitterbuffer);