Commit d8575222 authored by Olivier Crête's avatar Olivier Crête 👻 Committed by Nicolas Dufresne
Browse files

rtpjitterbuffer: Run all timers immediately on EOS

When the EOS event is received, run all timers immediately and avoid
pushing the EOS downstream before this has been run. This ensures that
the lost packet statistics are accurate.
parent c6e83259
...@@ -202,14 +202,14 @@ enum ...@@ -202,14 +202,14 @@ enum
#define JBUF_WAIT_TIMER(priv) G_STMT_START { \ #define JBUF_WAIT_TIMER(priv) G_STMT_START { \
GST_DEBUG ("waiting timer"); \ GST_DEBUG ("waiting timer"); \
(priv)->waiting_timer = TRUE; \ (priv)->waiting_timer++; \
g_cond_wait (&(priv)->jbuf_timer, &(priv)->jbuf_lock); \ g_cond_wait (&(priv)->jbuf_timer, &(priv)->jbuf_lock); \
(priv)->waiting_timer = FALSE; \ (priv)->waiting_timer--; \
GST_DEBUG ("waiting timer done"); \ GST_DEBUG ("waiting timer done"); \
} G_STMT_END } G_STMT_END
#define JBUF_SIGNAL_TIMER(priv) G_STMT_START { \ #define JBUF_SIGNAL_TIMER(priv) G_STMT_START { \
if (G_UNLIKELY ((priv)->waiting_timer)) { \ if (G_UNLIKELY ((priv)->waiting_timer)) { \
GST_DEBUG ("signal timer"); \ GST_DEBUG ("signal timer, %d waiters", (priv)->waiting_timer); \
g_cond_signal (&(priv)->jbuf_timer); \ g_cond_signal (&(priv)->jbuf_timer); \
} \ } \
} G_STMT_END } G_STMT_END
...@@ -2302,6 +2302,8 @@ remove_timer (GstRtpJitterBuffer * jitterbuffer, TimerData * timer) ...@@ -2302,6 +2302,8 @@ remove_timer (GstRtpJitterBuffer * jitterbuffer, TimerData * timer)
GST_DEBUG_OBJECT (jitterbuffer, "removed index %d", idx); GST_DEBUG_OBJECT (jitterbuffer, "removed index %d", idx);
g_array_remove_index_fast (priv->timers, idx); g_array_remove_index_fast (priv->timers, idx);
timer->idx = idx; timer->idx = idx;
JBUF_SIGNAL_TIMER (priv);
} }
static void static void
...@@ -2311,6 +2313,7 @@ remove_all_timers (GstRtpJitterBuffer * jitterbuffer) ...@@ -2311,6 +2313,7 @@ remove_all_timers (GstRtpJitterBuffer * jitterbuffer)
GST_DEBUG_OBJECT (jitterbuffer, "removed all timers"); GST_DEBUG_OBJECT (jitterbuffer, "removed all timers");
g_array_set_size (priv->timers, 0); g_array_set_size (priv->timers, 0);
unschedule_current_timer (jitterbuffer); unschedule_current_timer (jitterbuffer);
JBUF_SIGNAL_TIMER (priv);
} }
/* get the extra delay to wait before sending RTX */ /* get the extra delay to wait before sending RTX */
...@@ -3495,6 +3498,17 @@ pop_and_push_next (GstRtpJitterBuffer * jitterbuffer, guint seqnum) ...@@ -3495,6 +3498,17 @@ pop_and_push_next (GstRtpJitterBuffer * jitterbuffer, guint seqnum)
priv->next_seqnum = (seqnum + item->count) & 0xffff; priv->next_seqnum = (seqnum + item->count) & 0xffff;
} }
msg = check_buffering_percent (jitterbuffer, percent); msg = check_buffering_percent (jitterbuffer, percent);
if (type == ITEM_TYPE_EVENT && outevent &&
GST_EVENT_TYPE (outevent) == GST_EVENT_EOS) {
g_assert (priv->eos);
while (priv->timers->len > 0) {
/* Stopping timers */
unschedule_current_timer (jitterbuffer);
JBUF_WAIT_TIMER (priv);
}
}
JBUF_UNLOCK (priv); JBUF_UNLOCK (priv);
item->data = NULL; item->data = NULL;
...@@ -4001,7 +4015,9 @@ wait_next_timeout (GstRtpJitterBuffer * jitterbuffer) ...@@ -4001,7 +4015,9 @@ wait_next_timeout (GstRtpJitterBuffer * jitterbuffer)
* otherwise always be 0 * otherwise always be 0
*/ */
GST_OBJECT_LOCK (jitterbuffer); GST_OBJECT_LOCK (jitterbuffer);
if (GST_ELEMENT_CLOCK (jitterbuffer)) { if (priv->eos) {
now = GST_CLOCK_TIME_NONE;
} else if (GST_ELEMENT_CLOCK (jitterbuffer)) {
now = now =
gst_clock_get_time (GST_ELEMENT_CLOCK (jitterbuffer)) - gst_clock_get_time (GST_ELEMENT_CLOCK (jitterbuffer)) -
GST_ELEMENT_CAST (jitterbuffer)->base_time; GST_ELEMENT_CAST (jitterbuffer)->base_time;
...@@ -4076,7 +4092,7 @@ wait_next_timeout (GstRtpJitterBuffer * jitterbuffer) ...@@ -4076,7 +4092,7 @@ wait_next_timeout (GstRtpJitterBuffer * jitterbuffer)
GstClockReturn ret; GstClockReturn ret;
GstClockTimeDiff clock_jitter; GstClockTimeDiff clock_jitter;
if (timer_timeout == -1 || timer_timeout <= now) { if (timer_timeout == -1 || timer_timeout <= now || priv->eos) {
/* We have normally removed all lost timers in the loop above */ /* We have normally removed all lost timers in the loop above */
g_assert (timer->type != TIMER_TYPE_LOST); g_assert (timer->type != TIMER_TYPE_LOST);
......
...@@ -300,6 +300,77 @@ GST_START_TEST (test_push_unordered) ...@@ -300,6 +300,77 @@ GST_START_TEST (test_push_unordered)
GST_END_TEST; GST_END_TEST;
gboolean is_eos;
static gboolean
eos_event_function (GstPad * pad, GstObject * parent, GstEvent * event)
{
if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
g_mutex_lock (&check_mutex);
is_eos = TRUE;
g_cond_signal (&check_cond);
g_mutex_unlock (&check_mutex);
}
return TRUE;
}
GST_START_TEST (test_push_eos)
{
GstElement *jitterbuffer;
const guint num_buffers = 5;
GstBuffer *buffer;
GList *node;
GstStructure *stats;
guint64 pushed, lost, late, duplicates;
int n = 0;
is_eos = FALSE;
jitterbuffer = setup_jitterbuffer (num_buffers);
gst_pad_set_event_function (mysinkpad, eos_event_function);
g_object_set (jitterbuffer, "latency", 1, NULL);
fail_unless (start_jitterbuffer (jitterbuffer)
== GST_STATE_CHANGE_SUCCESS, "could not set to playing");
/* push buffers: 0,1,2, */
for (node = inbuffers; node; node = g_list_next (node)) {
n++;
/* Skip 1 */
if (n == 2) {
continue;
}
buffer = (GstBuffer *) node->data;
fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
}
gst_pad_push_event (mysrcpad, gst_event_new_eos ());
g_mutex_lock (&check_mutex);
while (!is_eos)
g_cond_wait (&check_cond, &check_mutex);
g_mutex_unlock (&check_mutex);
/* Verify statistics */
g_object_get (jitterbuffer, "stats", &stats, NULL);
gst_structure_get (stats, "num-pushed", G_TYPE_UINT64, &pushed,
"num-lost", G_TYPE_UINT64, &lost,
"num-late", G_TYPE_UINT64, &late,
"num-duplicates", G_TYPE_UINT64, &duplicates, NULL);
fail_unless_equals_int (pushed, g_list_length (inbuffers) - 1);
fail_unless_equals_int (lost, 1);
fail_unless_equals_int (late, 0);
fail_unless_equals_int (duplicates, 0);
gst_structure_free (stats);
/* cleanup */
cleanup_jitterbuffer (jitterbuffer);
}
GST_END_TEST;
GST_START_TEST (test_basetime) GST_START_TEST (test_basetime)
{ {
GstElement *jitterbuffer; GstElement *jitterbuffer;
...@@ -2140,6 +2211,7 @@ rtpjitterbuffer_suite (void) ...@@ -2140,6 +2211,7 @@ rtpjitterbuffer_suite (void)
tcase_add_test (tc_chain, test_push_forward_seq); tcase_add_test (tc_chain, test_push_forward_seq);
tcase_add_test (tc_chain, test_push_backward_seq); tcase_add_test (tc_chain, test_push_backward_seq);
tcase_add_test (tc_chain, test_push_unordered); tcase_add_test (tc_chain, test_push_unordered);
tcase_add_test (tc_chain, test_push_eos);
tcase_add_test (tc_chain, test_basetime); tcase_add_test (tc_chain, test_basetime);
tcase_add_test (tc_chain, test_clear_pt_map); tcase_add_test (tc_chain, test_clear_pt_map);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment