From f321bfeaf4058202cf5ab923ebbf01cab5304eab Mon Sep 17 00:00:00 2001 From: =?utf8?q?Miguel=20Par=C3=ADs=20D=C3=ADaz?= Date: Wed, 7 Oct 2015 13:03:02 +0200 Subject: [PATCH] rtpmanager: Take into account packet rate for max-dropout and max-misorder calculations https://bugzilla.gnome.org/show_bug.cgi?id=751311 --- gst/rtpmanager/gstrtpjitterbuffer.c | 50 +++++++++++++++++++++++++------------ gst/rtpmanager/rtpsource.c | 26 ++++++++++++++++--- gst/rtpmanager/rtpsource.h | 3 +++ gst/rtpmanager/rtpstats.c | 23 +++++++++++++++++ gst/rtpmanager/rtpstats.h | 19 +++++++++----- 5 files changed, 95 insertions(+), 26 deletions(-) diff --git a/gst/rtpmanager/gstrtpjitterbuffer.c b/gst/rtpmanager/gstrtpjitterbuffer.c index 7fcb729..c5026da 100644 --- a/gst/rtpmanager/gstrtpjitterbuffer.c +++ b/gst/rtpmanager/gstrtpjitterbuffer.c @@ -5,6 +5,8 @@ * Copyright 2007 Nokia Corporation * @author: Philippe Kalaf . * Copyright 2007 Wim Taymans + * Copyright 2015 Kurento (http://kurento.org/) + * @author: Miguel París * * 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 { diff --git a/gst/rtpmanager/rtpsource.c b/gst/rtpmanager/rtpsource.c index 202bc3b..f1ecc30 100644 --- a/gst/rtpmanager/rtpsource.c +++ b/gst/rtpmanager/rtpsource.c @@ -1,5 +1,7 @@ /* GStreamer * Copyright (C) <2007> Wim Taymans + * Copyright (C) 2015 Kurento (http://kurento.org/) + * @author: Miguel París * * 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: diff --git a/gst/rtpmanager/rtpsource.h b/gst/rtpmanager/rtpsource.h index f24e25b..941c7d6 100644 --- a/gst/rtpmanager/rtpsource.h +++ b/gst/rtpmanager/rtpsource.h @@ -1,5 +1,7 @@ /* GStreamer * Copyright (C) <2007> Wim Taymans + * Copyright (C) 2015 Kurento (http://kurento.org/) + * @author: Miguel París * * 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; diff --git a/gst/rtpmanager/rtpstats.c b/gst/rtpmanager/rtpstats.c index d47578d..984bc9f 100644 --- a/gst/rtpmanager/rtpstats.c +++ b/gst/rtpmanager/rtpstats.c @@ -1,5 +1,7 @@ /* GStreamer * Copyright (C) <2007> Wim Taymans + * Copyright (C) 2015 Kurento (http://kurento.org/) + * @author: Miguel París * * 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 diff --git a/gst/rtpmanager/rtpstats.h b/gst/rtpmanager/rtpstats.h index 9c74039..14ba9da 100644 --- a/gst/rtpmanager/rtpstats.h +++ b/gst/rtpmanager/rtpstats.h @@ -1,5 +1,7 @@ /* GStreamer * Copyright (C) <2007> Wim Taymans + * Copyright (C) 2015 Kurento (http://kurento.org/) + * @author: Miguel París * * 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: -- 2.7.4