mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
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:
parent
4c96094fbb
commit
f321bfeaf4
5 changed files with 95 additions and 26 deletions
|
@ -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 {
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in a new issue