netclock: Add round-trip-limit parameter

Sometimes, packets might take a very long time to return. Such packets
usually are way too late and destabilize the regression with their
obsolete data. On Wi-Fi, round-trips of over 7 seconds have been observed.

If the limit is set to a nonzero value, packets with a round-trip period
larger than the limit are ignored.

Signed-off-by: Carlos Rafael Giani <dv@pseudoterminal.org>

https://bugzilla.gnome.org/show_bug.cgi?id=712385
This commit is contained in:
Carlos Rafael Giani 2013-11-26 11:56:46 +01:00 committed by Jan Schmidt
parent 2a720d2e55
commit 1ce704d45d

View file

@ -38,6 +38,8 @@
* This clock will poll the time provider and will update its calibration * This clock will poll the time provider and will update its calibration
* parameters based on the local and remote observations. * parameters based on the local and remote observations.
* *
* The "round-trip" property limits the maximum round trip packets can take.
*
* Various parameters of the clock can be configured with the parent #GstClock * Various parameters of the clock can be configured with the parent #GstClock
* "timeout", "window-size" and "window-threshold" object properties. * "timeout", "window-size" and "window-threshold" object properties.
* *
@ -62,12 +64,14 @@ GST_DEBUG_CATEGORY_STATIC (ncc_debug);
#define DEFAULT_ADDRESS "127.0.0.1" #define DEFAULT_ADDRESS "127.0.0.1"
#define DEFAULT_PORT 5637 #define DEFAULT_PORT 5637
#define DEFAULT_TIMEOUT GST_SECOND #define DEFAULT_TIMEOUT GST_SECOND
#define DEFAULT_ROUNDTRIP_LIMIT GST_SECOND
enum enum
{ {
PROP_0, PROP_0,
PROP_ADDRESS, PROP_ADDRESS,
PROP_PORT PROP_PORT,
PROP_ROUNDTRIP_LIMIT
}; };
#define GST_NET_CLIENT_CLOCK_GET_PRIVATE(obj) \ #define GST_NET_CLIENT_CLOCK_GET_PRIVATE(obj) \
@ -82,6 +86,7 @@ struct _GstNetClientClockPrivate
GCancellable *cancel; GCancellable *cancel;
GstClockTime timeout_expiration; GstClockTime timeout_expiration;
GstClockTime roundtrip_limit;
GstClockTime rtt_avg; GstClockTime rtt_avg;
gchar *address; gchar *address;
@ -123,6 +128,26 @@ gst_net_client_clock_class_init (GstNetClientClockClass * klass)
g_param_spec_int ("port", "port", g_param_spec_int ("port", "port",
"The port on which the remote server is listening", 0, G_MAXUINT16, "The port on which the remote server is listening", 0, G_MAXUINT16,
DEFAULT_PORT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); DEFAULT_PORT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstNetClientClock::roundtrip-limit:
*
* Maximum allowed round-trip for packets. If this property is set to a nonzero
* value, all packets with a round-trip interval larger than this limit will be
* ignored. This is useful for networks with severe and fluctuating transport
* delays. Filtering out these packets increases stability of the synchronization.
* On the other hand, the lower the limit, the higher the amount of filtered
* packets. Empirical tests are typically necessary to estimate a good value
* for the limit.
* If the property is set to zero, the limit is disabled.
*
* Since: 1.4
*/
g_object_class_install_property (gobject_class, PROP_ROUNDTRIP_LIMIT,
g_param_spec_uint64 ("round-trip-limit", "round-trip limit",
"Maximum tolerable round-trip interval for packets, in nanoseconds "
"(0 = no limit)", 0, G_MAXUINT64, DEFAULT_ROUNDTRIP_LIMIT,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
} }
static void static void
@ -142,6 +167,7 @@ gst_net_client_clock_init (GstNetClientClock * self)
priv->servaddr = NULL; priv->servaddr = NULL;
priv->rtt_avg = GST_CLOCK_TIME_NONE; priv->rtt_avg = GST_CLOCK_TIME_NONE;
priv->roundtrip_limit = DEFAULT_ROUNDTRIP_LIMIT;
} }
static void static void
@ -186,6 +212,9 @@ gst_net_client_clock_set_property (GObject * object, guint prop_id,
case PROP_PORT: case PROP_PORT:
self->priv->port = g_value_get_int (value); self->priv->port = g_value_get_int (value);
break; break;
case PROP_ROUNDTRIP_LIMIT:
self->priv->roundtrip_limit = g_value_get_uint64 (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -205,6 +234,9 @@ gst_net_client_clock_get_property (GObject * object, guint prop_id,
case PROP_PORT: case PROP_PORT:
g_value_set_int (value, self->priv->port); g_value_set_int (value, self->priv->port);
break; break;
case PROP_ROUNDTRIP_LIMIT:
g_value_set_uint64 (value, self->priv->roundtrip_limit);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -222,10 +254,22 @@ gst_net_client_clock_observe_times (GstNetClientClock * self,
GstClock *clock; GstClock *clock;
GstClockTime rtt; GstClockTime rtt;
if (local_2 < local_1) if (local_2 < local_1) {
GST_LOG_OBJECT (self, "Dropping observation: receive time %" GST_TIME_FORMAT
" < send time %" GST_TIME_FORMAT, GST_TIME_ARGS (local_1),
GST_TIME_ARGS (local_2));
goto bogus_observation; goto bogus_observation;
}
rtt = local_2 - local_1; rtt = GST_CLOCK_DIFF (local_1, local_2);
if ((self->priv->roundtrip_limit > 0) && (rtt > self->priv->roundtrip_limit)) {
GST_LOG_OBJECT (self,
"Dropping observation: RTT %" GST_TIME_FORMAT " > limit %"
GST_TIME_FORMAT, GST_TIME_ARGS (rtt),
GST_TIME_ARGS (self->priv->roundtrip_limit));
goto bogus_observation;
}
/* Track an average round trip time, for a bit of smoothing */ /* Track an average round trip time, for a bit of smoothing */
/* Always update before discarding a sample, so genuine changes in /* Always update before discarding a sample, so genuine changes in
@ -268,9 +312,11 @@ gst_net_client_clock_observe_times (GstNetClientClock * self,
bogus_observation: bogus_observation:
{ {
GST_WARNING_OBJECT (self, "time packet receive time < send time (%" GST_WARNING_OBJECT (self,
GST_TIME_FORMAT " < %" GST_TIME_FORMAT ") or too large", "bogus round-trip interval; too long round trip or "
GST_TIME_ARGS (local_1), GST_TIME_ARGS (local_2)); "receive time < send time (%" GST_TIME_FORMAT " - %" GST_TIME_FORMAT
" => %" GST_TIME_FORMAT ")", GST_TIME_ARGS (local_1),
GST_TIME_ARGS (local_2), GST_TIME_ARGS (rtt));
/* Schedule a new packet again soon */ /* Schedule a new packet again soon */
self->priv->timeout_expiration = self->priv->timeout_expiration =
gst_util_get_timestamp () + (GST_SECOND / 4); gst_util_get_timestamp () + (GST_SECOND / 4);