rtpbin: added option for setting min_ts_offset in ntp-sync mode

Constantly updating the ts_offset results in audiable glitches
when streaming audio using ntp-sync=true. By requiring a minimum
offset before updating ts_offset this can be mitigated. Added a
parameter which can be used to set min_ts_offset in ntp-sync mode.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1409>
This commit is contained in:
Danny Smith 2018-05-29 16:24:02 +02:00 committed by GStreamer Marge Bot
parent 8773ba1104
commit d5e257afd1
3 changed files with 60 additions and 4 deletions

View file

@ -16807,6 +16807,20 @@
"type": "guint64", "type": "guint64",
"writable": true "writable": true
}, },
"min-ts-offset": {
"blurb": "The minimum absolute value of the time offset in (nanoseconds). Used to set an lower limit for when a time offset is deemed large enough to be useful for sync corrections.Note, if the ntp-sync parameter is set the default value is changed to 0 (no limit)",
"conditionally-available": false,
"construct": false,
"construct-only": false,
"controllable": false,
"default": "4000000",
"max": "18446744073709551615",
"min": "0",
"mutable": "null",
"readable": true,
"type": "guint64",
"writable": true
},
"ntp-sync": { "ntp-sync": {
"blurb": "Synchronize received streams to the NTP clock", "blurb": "Synchronize received streams to the NTP clock",
"conditionally-available": false, "conditionally-available": false,

View file

@ -260,7 +260,7 @@ G_STMT_START { \
/* Minimum time offset to apply. This compensates for rounding errors in NTP to /* Minimum time offset to apply. This compensates for rounding errors in NTP to
* RTP timestamp conversions */ * RTP timestamp conversions */
#define MIN_TS_OFFSET (4 * GST_MSECOND) #define MIN_TS_OFFSET_ROUND_OFF_COMP (4 * GST_MSECOND)
struct _GstRtpBinPrivate struct _GstRtpBinPrivate
{ {
@ -353,6 +353,7 @@ enum
#define DEFAULT_MAX_STREAMS G_MAXUINT #define DEFAULT_MAX_STREAMS G_MAXUINT
#define DEFAULT_MAX_TS_OFFSET_ADJUSTMENT G_GUINT64_CONSTANT(0) #define DEFAULT_MAX_TS_OFFSET_ADJUSTMENT G_GUINT64_CONSTANT(0)
#define DEFAULT_MAX_TS_OFFSET G_GINT64_CONSTANT(3000000000) #define DEFAULT_MAX_TS_OFFSET G_GINT64_CONSTANT(3000000000)
#define DEFAULT_MIN_TS_OFFSET MIN_TS_OFFSET_ROUND_OFF_COMP
enum enum
{ {
@ -380,6 +381,7 @@ enum
PROP_MAX_STREAMS, PROP_MAX_STREAMS,
PROP_MAX_TS_OFFSET_ADJUSTMENT, PROP_MAX_TS_OFFSET_ADJUSTMENT,
PROP_MAX_TS_OFFSET, PROP_MAX_TS_OFFSET,
PROP_MIN_TS_OFFSET,
PROP_FEC_DECODERS, PROP_FEC_DECODERS,
PROP_FEC_ENCODERS, PROP_FEC_ENCODERS,
}; };
@ -1327,7 +1329,7 @@ get_current_times (GstRtpBin * bin, GstClockTime * running_time,
static void static void
stream_set_ts_offset (GstRtpBin * bin, GstRtpBinStream * stream, stream_set_ts_offset (GstRtpBin * bin, GstRtpBinStream * stream,
gint64 ts_offset, gint64 max_ts_offset, gint64 min_ts_offset, gint64 ts_offset, gint64 max_ts_offset, guint64 min_ts_offset,
gboolean allow_positive_ts_offset) gboolean allow_positive_ts_offset)
{ {
gint64 prev_ts_offset; gint64 prev_ts_offset;
@ -1513,7 +1515,7 @@ gst_rtp_bin_associate (GstRtpBin * bin, GstRtpBinStream * stream, guint8 len,
stream->rt_delta = rtdiff - ntpdiff; stream->rt_delta = rtdiff - ntpdiff;
stream_set_ts_offset (bin, stream, stream->rt_delta, bin->max_ts_offset, stream_set_ts_offset (bin, stream, stream->rt_delta, bin->max_ts_offset,
0, FALSE); bin->min_ts_offset, FALSE);
} else { } else {
gint64 min, rtp_min, clock_base = stream->clock_base; gint64 min, rtp_min, clock_base = stream->clock_base;
gboolean all_sync, use_rtp; gboolean all_sync, use_rtp;
@ -1666,7 +1668,7 @@ gst_rtp_bin_associate (GstRtpBin * bin, GstRtpBinStream * stream, guint8 len,
ts_offset = ostream->rt_delta - min; ts_offset = ostream->rt_delta - min;
stream_set_ts_offset (bin, ostream, ts_offset, bin->max_ts_offset, stream_set_ts_offset (bin, ostream, ts_offset, bin->max_ts_offset,
MIN_TS_OFFSET, TRUE); bin->min_ts_offset, TRUE);
} }
} }
gst_rtp_bin_send_sync_event (stream); gst_rtp_bin_send_sync_event (stream);
@ -2761,6 +2763,28 @@ gst_rtp_bin_class_init (GstRtpBinClass * klass)
"changed to 0 (no limit)", 0, G_MAXINT64, DEFAULT_MAX_TS_OFFSET, "changed to 0 (no limit)", 0, G_MAXINT64, DEFAULT_MAX_TS_OFFSET,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstRtpBin:min-ts-offset:
*
* Used to set an lower limit for when a time offset is deemed large enough
* to be useful for sync corrections.
*
* When streaming for instance audio, even very small ts_offsets cause
* audible glitches. This property is used for controlling how sensitive the
* adjustments should be to small deviations in ts_offset, occurring for
* instance due to jittery network conditions or system load.
*
* Since: 1.22
*/
g_object_class_install_property (gobject_class, PROP_MIN_TS_OFFSET,
g_param_spec_uint64 ("min-ts-offset", "Min TS Offset",
"The minimum absolute value of the time offset in (nanoseconds). "
"Used to set an lower limit for when a time offset is deemed large "
"enough to be useful for sync corrections."
"Note, if the ntp-sync parameter is set the default value is "
"changed to 0 (no limit)", 0, G_MAXUINT64, DEFAULT_MIN_TS_OFFSET,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/** /**
* GstRtpBin:fec-decoders: * GstRtpBin:fec-decoders:
* *
@ -2883,6 +2907,8 @@ gst_rtp_bin_init (GstRtpBin * rtpbin)
rtpbin->max_ts_offset_adjustment = DEFAULT_MAX_TS_OFFSET_ADJUSTMENT; rtpbin->max_ts_offset_adjustment = DEFAULT_MAX_TS_OFFSET_ADJUSTMENT;
rtpbin->max_ts_offset = DEFAULT_MAX_TS_OFFSET; rtpbin->max_ts_offset = DEFAULT_MAX_TS_OFFSET;
rtpbin->max_ts_offset_is_set = FALSE; rtpbin->max_ts_offset_is_set = FALSE;
rtpbin->min_ts_offset = DEFAULT_MIN_TS_OFFSET;
rtpbin->min_ts_offset_is_set = FALSE;
/* some default SDES entries */ /* some default SDES entries */
cname = g_strdup_printf ("user%u@host-%x", g_random_int (), g_random_int ()); cname = g_strdup_printf ("user%u@host-%x", g_random_int (), g_random_int ());
@ -3079,6 +3105,13 @@ gst_rtp_bin_set_property (GObject * object, guint prop_id,
rtpbin->max_ts_offset = DEFAULT_MAX_TS_OFFSET; rtpbin->max_ts_offset = DEFAULT_MAX_TS_OFFSET;
} }
} }
if (!rtpbin->min_ts_offset_is_set) {
if (rtpbin->ntp_sync) {
rtpbin->min_ts_offset = 0;
} else {
rtpbin->min_ts_offset = DEFAULT_MIN_TS_OFFSET;
}
}
break; break;
case PROP_RTCP_SYNC: case PROP_RTCP_SYNC:
g_atomic_int_set (&rtpbin->rtcp_sync, g_value_get_enum (value)); g_atomic_int_set (&rtpbin->rtcp_sync, g_value_get_enum (value));
@ -3197,6 +3230,10 @@ gst_rtp_bin_set_property (GObject * object, guint prop_id,
rtpbin->max_ts_offset = g_value_get_int64 (value); rtpbin->max_ts_offset = g_value_get_int64 (value);
rtpbin->max_ts_offset_is_set = TRUE; rtpbin->max_ts_offset_is_set = TRUE;
break; break;
case PROP_MIN_TS_OFFSET:
rtpbin->min_ts_offset = g_value_get_uint64 (value);
rtpbin->min_ts_offset_is_set = TRUE;
break;
case PROP_FEC_DECODERS: case PROP_FEC_DECODERS:
gst_rtp_bin_set_fec_decoders_struct (rtpbin, g_value_get_boxed (value)); gst_rtp_bin_set_fec_decoders_struct (rtpbin, g_value_get_boxed (value));
break; break;
@ -3297,6 +3334,9 @@ gst_rtp_bin_get_property (GObject * object, guint prop_id,
case PROP_MAX_TS_OFFSET: case PROP_MAX_TS_OFFSET:
g_value_set_int64 (value, rtpbin->max_ts_offset); g_value_set_int64 (value, rtpbin->max_ts_offset);
break; break;
case PROP_MIN_TS_OFFSET:
g_value_set_uint64 (value, rtpbin->min_ts_offset);
break;
case PROP_FEC_DECODERS: case PROP_FEC_DECODERS:
g_value_take_boxed (value, gst_rtp_bin_get_fec_decoders_struct (rtpbin)); g_value_take_boxed (value, gst_rtp_bin_get_fec_decoders_struct (rtpbin));
break; break;

View file

@ -78,6 +78,8 @@ struct _GstRtpBin {
guint64 max_ts_offset_adjustment; guint64 max_ts_offset_adjustment;
gint64 max_ts_offset; gint64 max_ts_offset;
gboolean max_ts_offset_is_set; gboolean max_ts_offset_is_set;
guint64 min_ts_offset;
gboolean min_ts_offset_is_set;
/* a list of session */ /* a list of session */
GSList *sessions; GSList *sessions;