rtpmanager: Take into account packet rate for max-dropout and max-misorder calculations

https://bugzilla.gnome.org/show_bug.cgi?id=751311
This commit is contained in:
Miguel París Díaz 2015-10-07 13:03:02 +02:00 committed by Sebastian Dröge
parent 4c96094fbb
commit f321bfeaf4
5 changed files with 95 additions and 26 deletions

View file

@ -5,6 +5,8 @@
* Copyright 2007 Nokia Corporation
* @author: Philippe Kalaf <philippe.kalaf@collabora.co.uk>.
* Copyright 2007 Wim Taymans <wim.taymans@gmail.com>
* Copyright 2015 Kurento (http://kurento.org/)
* @author: Miguel París <mparisdiaz@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -327,6 +329,7 @@ struct _GstRtpJitterBufferPrivate
guint64 num_rtx_failed;
gdouble avg_rtx_num;
guint64 avg_rtx_rtt;
RTPPacketRateCtx packet_rate_ctx;
/* for the jitter */
GstClockTime last_dts;
@ -2304,7 +2307,8 @@ compare_buffer_seqnum (GstBuffer * a, GstBuffer * b, gpointer user_data)
static gboolean
handle_big_gap_buffer (GstRtpJitterBuffer * jitterbuffer, gboolean future,
GstBuffer * buffer, guint8 pt, guint16 seqnum, gint gap)
GstBuffer * buffer, guint8 pt, guint16 seqnum, gint gap, guint max_dropout,
guint max_misorder)
{
GstRtpJitterBufferPrivate *priv;
guint gap_packets_length;
@ -2346,7 +2350,7 @@ handle_big_gap_buffer (GstRtpJitterBuffer * jitterbuffer, gboolean future,
GST_DEBUG_OBJECT (jitterbuffer,
"buffer too %s %d < %d, got 5 consecutive ones - reset",
(future ? "new" : "old"), gap,
(future ? RTP_MAX_DROPOUT : -RTP_MAX_MISORDER));
(future ? max_dropout : -max_misorder));
reset = TRUE;
} else if (!all_consecutive) {
g_queue_foreach (&priv->gap_packets, (GFunc) gst_buffer_unref, NULL);
@ -2354,20 +2358,19 @@ handle_big_gap_buffer (GstRtpJitterBuffer * jitterbuffer, gboolean future,
GST_DEBUG_OBJECT (jitterbuffer,
"buffer too %s %d < %d, got no 5 consecutive ones - dropping",
(future ? "new" : "old"), gap,
(future ? RTP_MAX_DROPOUT : -RTP_MAX_MISORDER));
(future ? max_dropout : -max_misorder));
buffer = NULL;
} else {
GST_DEBUG_OBJECT (jitterbuffer,
"buffer too %s %d < %d, got %u consecutive ones - waiting",
(future ? "new" : "old"), gap,
(future ? RTP_MAX_DROPOUT : -RTP_MAX_MISORDER),
gap_packets_length + 1);
(future ? max_dropout : -max_misorder), gap_packets_length + 1);
buffer = NULL;
}
} else {
GST_DEBUG_OBJECT (jitterbuffer,
"buffer too %s %d < %d, first one - waiting", (future ? "new" : "old"),
gap, -RTP_MAX_MISORDER);
gap, -max_misorder);
g_queue_push_tail (&priv->gap_packets, buffer);
buffer = NULL;
}
@ -2416,6 +2419,7 @@ gst_rtp_jitter_buffer_chain (GstPad * pad, GstObject * parent,
RTPJitterBufferItem *item;
GstMessage *msg = NULL;
gboolean estimated_dts = FALSE;
guint32 packet_rate, max_dropout, max_misorder;
jitterbuffer = GST_RTP_JITTER_BUFFER_CAST (parent);
@ -2520,6 +2524,18 @@ gst_rtp_jitter_buffer_chain (GstPad * pad, GstObject * parent,
expected = priv->next_in_seqnum;
packet_rate =
gst_rtp_packet_rate_ctx_update (&priv->packet_rate_ctx, seqnum, rtptime);
max_dropout =
gst_rtp_packet_rate_ctx_get_max_dropout (&priv->packet_rate_ctx,
priv->max_dropout_time);
max_misorder =
gst_rtp_packet_rate_ctx_get_max_misorder (&priv->packet_rate_ctx,
priv->max_misorder_time);
GST_TRACE_OBJECT (jitterbuffer,
"packet_rate: %d, max_dropout: %d, max_misorder: %d", packet_rate,
max_dropout, max_misorder);
/* now check against our expected seqnum */
if (G_LIKELY (expected != -1)) {
gint gap;
@ -2539,17 +2555,17 @@ gst_rtp_jitter_buffer_chain (GstPad * pad, GstObject * parent,
if (gap < 0) {
/* we received an old packet */
if (G_UNLIKELY (gap != -1 && gap < -RTP_MAX_MISORDER)) {
if (G_UNLIKELY (gap != -1 && gap < -max_misorder)) {
reset =
handle_big_gap_buffer (jitterbuffer, FALSE, buffer, pt, seqnum,
gap);
gap, max_dropout, max_misorder);
buffer = NULL;
} else {
GST_DEBUG_OBJECT (jitterbuffer, "old packet received");
}
} else {
/* new packet, we are missing some packets */
if (G_UNLIKELY (priv->timers->len >= RTP_MAX_DROPOUT)) {
if (G_UNLIKELY (priv->timers->len >= max_dropout)) {
/* If we have timers for more than RTP_MAX_DROPOUT packets
* pending this means that we have a huge gap overall. We can
* reset the jitterbuffer at this point because there's
@ -2558,14 +2574,14 @@ gst_rtp_jitter_buffer_chain (GstPad * pad, GstObject * parent,
* next packet */
GST_WARNING_OBJECT (jitterbuffer,
"%d pending timers > %d - resetting", priv->timers->len,
RTP_MAX_DROPOUT);
max_dropout);
reset = TRUE;
gst_buffer_unref (buffer);
buffer = NULL;
} else if (G_UNLIKELY (gap >= RTP_MAX_DROPOUT)) {
} else if (G_UNLIKELY (gap >= max_dropout)) {
reset =
handle_big_gap_buffer (jitterbuffer, TRUE, buffer, pt, seqnum,
gap);
gap, max_dropout, max_misorder);
buffer = NULL;
} else {
GST_DEBUG_OBJECT (jitterbuffer, "%d missing packets", gap);
@ -3372,10 +3388,11 @@ wait_next_timeout (GstRtpJitterBuffer * jitterbuffer)
GstClockTime timer_timeout = -1;
gint i, len;
/* If we have a clock, update "now" now with the very latest running time
* we have. It is used below when timeouts are triggered to calculate
* any next possible timeout. If we only update it after waiting for the
* clock, we would give a too old time to the timeout functions.
/* If we have a clock, update "now" now with the very
* latest running time we have. If timers are unscheduled below we
* otherwise wouldn't update now (it's only updated when timers
* expire), and also for the very first loop iteration now would
* otherwise always be 0
*/
GST_OBJECT_LOCK (jitterbuffer);
if (GST_ELEMENT_CLOCK (jitterbuffer)) {
@ -3478,6 +3495,7 @@ wait_next_timeout (GstRtpJitterBuffer * jitterbuffer)
}
if (ret != GST_CLOCK_UNSCHEDULED) {
now = timer_timeout + MAX (clock_jitter, 0);
GST_DEBUG_OBJECT (jitterbuffer, "sync done, %d, #%d, %" G_GINT64_FORMAT,
ret, priv->timer_seqnum, clock_jitter);
} else {

View file

@ -1,5 +1,7 @@
/* GStreamer
* Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
* Copyright (C) 2015 Kurento (http://kurento.org/)
* @author: Miguel París <mparisdiaz@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -908,6 +910,7 @@ get_clock_rate (RTPSource * src, guint8 payload)
GST_DEBUG ("got clock-rate %d", clock_rate);
src->clock_rate = clock_rate;
gst_rtp_packet_rate_ctx_reset (&src->packet_rate_ctx, clock_rate);
}
return src->clock_rate;
}
@ -1041,11 +1044,24 @@ update_receiver_stats (RTPSource * src, RTPPacketInfo * pinfo,
guint16 seqnr, expected;
RTPSourceStats *stats;
gint16 delta;
gint32 packet_rate, max_dropout, max_misorder;
stats = &src->stats;
seqnr = pinfo->seqnum;
packet_rate =
gst_rtp_packet_rate_ctx_update (&src->packet_rate_ctx, pinfo->seqnum,
pinfo->rtptime);
max_dropout =
gst_rtp_packet_rate_ctx_get_max_dropout (&src->packet_rate_ctx,
src->max_dropout_time);
max_misorder =
gst_rtp_packet_rate_ctx_get_max_misorder (&src->packet_rate_ctx,
src->max_misorder_time);
GST_TRACE ("SSRC %08x, packet_rate: %d, max_dropout: %d, max_misorder: %d",
src->ssrc, packet_rate, max_dropout, max_misorder);
if (stats->cycles == -1) {
GST_DEBUG ("received first packet");
/* first time we heard of this source */
@ -1092,7 +1108,7 @@ update_receiver_stats (RTPSource * src, RTPPacketInfo * pinfo,
/* unexpected seqnum in probation */
goto probation_seqnum;
}
} else if (delta >= 0 && delta < RTP_MAX_DROPOUT) {
} else if (delta >= 0 && delta < max_dropout) {
/* Clear bad packets */
stats->bad_seq = RTP_SEQ_MOD + 1; /* so seq == bad_seq is false */
g_queue_foreach (src->packets, (GFunc) gst_buffer_unref, NULL);
@ -1104,7 +1120,7 @@ update_receiver_stats (RTPSource * src, RTPPacketInfo * pinfo,
stats->cycles += RTP_SEQ_MOD;
}
stats->max_seq = seqnr;
} else if (delta < -RTP_MAX_MISORDER || delta >= RTP_MAX_DROPOUT) {
} else if (delta < -max_misorder || delta >= max_dropout) {
/* the sequence number made a very large jump */
if (seqnr == stats->bad_seq && src->packets->head) {
/* two sequential packets -- assume that the other side
@ -1120,7 +1136,7 @@ update_receiver_stats (RTPSource * src, RTPPacketInfo * pinfo,
pinfo->data = NULL;
goto bad_sequence;
}
} else { /* delta < 0 && delta >= -RTP_MAX_MISORDER */
} else { /* delta < 0 && delta >= -max_misorder */
/* Clear bad packets */
stats->bad_seq = RTP_SEQ_MOD + 1; /* so seq == bad_seq is false */
g_queue_foreach (src->packets, (GFunc) gst_buffer_unref, NULL);
@ -1150,7 +1166,9 @@ done:
}
bad_sequence:
{
GST_WARNING ("unacceptable seqnum received");
GST_WARNING
("unacceptable seqnum received (seqnr %u, delta %d, packet_rate: %d, max_dropout: %d, max_misorder: %d)",
seqnr, delta, packet_rate, max_dropout, max_misorder);
return FALSE;
}
probation_seqnum:

View file

@ -1,5 +1,7 @@
/* GStreamer
* Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
* Copyright (C) 2015 Kurento (http://kurento.org/)
* @author: Miguel París <mparisdiaz@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -174,6 +176,7 @@ struct _RTPSource {
guint64 bytes_received;
GQueue *packets;
RTPPacketRateCtx packet_rate_ctx;
guint32 max_dropout_time;
guint32 max_misorder_time;

View file

@ -1,5 +1,7 @@
/* GStreamer
* Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
* Copyright (C) 2015 Kurento (http://kurento.org/)
* @author: Miguel París <mparisdiaz@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -81,6 +83,27 @@ gst_rtp_packet_rate_ctx_get (RTPPacketRateCtx * ctx)
return ctx->avg_packet_rate;
}
guint32
gst_rtp_packet_rate_ctx_get_max_dropout (RTPPacketRateCtx * ctx, gint32 time_ms)
{
if (time_ms <= 0 || !ctx->probed) {
return RTP_DEF_DROPOUT;
}
return MAX (RTP_MIN_DROPOUT, ctx->avg_packet_rate * time_ms / 1000);
}
guint32
gst_rtp_packet_rate_ctx_get_max_misorder (RTPPacketRateCtx * ctx,
gint32 time_ms)
{
if (time_ms <= 0 || !ctx->probed) {
return RTP_DEF_MISORDER;
}
return MAX (RTP_MIN_MISORDER, ctx->avg_packet_rate * time_ms / 1000);
}
/**
* rtp_stats_init_defaults:
* @stats: an #RTPSessionStats struct

View file

@ -1,5 +1,7 @@
/* GStreamer
* Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
* Copyright (C) 2015 Kurento (http://kurento.org/)
* @author: Miguel París <mparisdiaz@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -183,15 +185,18 @@ typedef struct {
#define RTP_STATS_BYE_TIMEOUT (2 * GST_SECOND)
/*
* The maximum number of missing packets we tolerate. These are packets with a
* sequence number bigger than the last seen packet.
* The default and minimum values of the maximum number of missing packets we tolerate.
* These are packets with asequence number bigger than the last seen packet.
*/
#define RTP_MAX_DROPOUT 3000
#define RTP_DEF_DROPOUT 3000
#define RTP_MIN_DROPOUT 30
/*
* The maximum number of misordered packets we tolerate. These are packets with
* a sequence number smaller than the last seen packet.
* The default and minimum values of the maximum number of misordered packets we tolerate.
* These are packets with a sequence number smaller than the last seen packet.
*/
#define RTP_MAX_MISORDER 100
#define RTP_DEF_MISORDER 100
#define RTP_MIN_MISORDER 10
/**
* RTPPacketRateCtx:
@ -209,6 +214,8 @@ typedef struct {
void gst_rtp_packet_rate_ctx_reset (RTPPacketRateCtx * ctx, guint32 clock_rate);
guint32 gst_rtp_packet_rate_ctx_update (RTPPacketRateCtx *ctx, guint16 seqnum, guint32 ts);
guint32 gst_rtp_packet_rate_ctx_get (RTPPacketRateCtx *ctx);
guint32 gst_rtp_packet_rate_ctx_get_max_dropout (RTPPacketRateCtx *ctx, gint32 time_ms);
guint32 gst_rtp_packet_rate_ctx_get_max_misorder (RTPPacketRateCtx *ctx, gint32 time_ms);
/**
* RTPSessionStats: