summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/gst/net/gstptpclock.c63
1 files changed, 63 insertions, 0 deletions
diff --git a/libs/gst/net/gstptpclock.c b/libs/gst/net/gstptpclock.c
index 68e1a021f..4755f08c2 100644
--- a/libs/gst/net/gstptpclock.c
+++ b/libs/gst/net/gstptpclock.c
@@ -106,6 +106,13 @@ GST_DEBUG_CATEGORY_STATIC (ptp_debug);
*/
#define USE_ONLY_SYNC_WITH_DELAY 1
+/* Filter out delay measurements that are too far away from the median of the
+ * last delay measurements, currently those that are more than 2 times as big.
+ * This increases accuracy a lot on wifi.
+ */
+#define USE_MEDIAN_PRE_FILTERING 1
+#define MEDIAN_PRE_FILTERING_WINDOW 9
+
/* How many updates should be skipped at maximum when using USE_MEASUREMENT_FILTERING */
#define MAX_SKIPPED_UPDATES 5
@@ -306,6 +313,9 @@ typedef struct
GstClockTime last_delay_req, min_delay_req_interval;
guint16 last_delay_req_seqnum;
+ GstClockTime last_path_delays[MEDIAN_PRE_FILTERING_WINDOW];
+ gint last_path_delays_missing;
+
GQueue pending_syncs;
GstClock *domain_clock;
@@ -770,6 +780,7 @@ select_best_master_clock (PtpDomainData * domain, GstClockTime now)
sizeof (PtpClockIdentity));
domain->mean_path_delay = 0;
domain->last_delay_req = 0;
+ domain->last_path_delays_missing = 9;
domain->min_delay_req_interval = 0;
domain->sync_interval = 0;
domain->last_ptp_sync_time = 0;
@@ -834,6 +845,7 @@ handle_announce_message (PtpMessage * msg, GstClockTime receive_time)
g_object_new (GST_TYPE_SYSTEM_CLOCK, "name", clock_name, NULL);
g_free (clock_name);
g_queue_init (&domain->pending_syncs);
+ domain->last_path_delays_missing = 9;
domain_data = g_list_prepend (domain_data, domain);
g_mutex_lock (&domain_clocks_lock);
@@ -1230,9 +1242,27 @@ out:
}
+#ifdef USE_MEDIAN_PRE_FILTERING
+static gint
+compare_clock_time (const GstClockTime * a, const GstClockTime * b)
+{
+ if (*a < *b)
+ return -1;
+ else if (*a > *b)
+ return 1;
+ return 0;
+}
+#endif
+
static gboolean
update_mean_path_delay (PtpDomainData * domain, PtpPendingSync * sync)
{
+#ifdef USE_MEDIAN_PRE_FILTERING
+ GstClockTime last_path_delays[G_N_ELEMENTS (domain->last_path_delays)];
+ GstClockTime median;
+ gint i;
+#endif
+
GstClockTime mean_path_delay, delay_req_delay;
gboolean ret;
@@ -1243,6 +1273,37 @@ update_mean_path_delay (PtpDomainData * domain, PtpPendingSync * sync)
(sync->correction_field_sync + sync->correction_field_delay +
32768) / 65536) / 2;
+#ifdef USE_MEDIAN_PRE_FILTERING
+ for (i = 1; i < G_N_ELEMENTS (domain->last_path_delays); i++)
+ domain->last_path_delays[i - 1] = domain->last_path_delays[i];
+ domain->last_path_delays[i - 1] = mean_path_delay;
+
+ if (domain->last_path_delays_missing) {
+ domain->last_path_delays_missing--;
+ } else {
+ memcpy (&last_path_delays, &domain->last_path_delays,
+ sizeof (last_path_delays));
+ g_qsort_with_data (&last_path_delays,
+ G_N_ELEMENTS (domain->last_path_delays), sizeof (GstClockTime),
+ (GCompareDataFunc) compare_clock_time, NULL);
+
+ median = last_path_delays[G_N_ELEMENTS (last_path_delays) / 2];
+
+ /* FIXME: We might want to use something else here, like only allowing
+ * things in the interquartile range, or also filtering away delays that
+ * are too small compared to the median. This here worked well enough
+ * in tests so far.
+ */
+ if (mean_path_delay > 2 * median) {
+ GST_WARNING ("Path delay for domain %u too big compared to median: %"
+ GST_TIME_FORMAT " > 2 * %" GST_TIME_FORMAT, domain->domain,
+ GST_TIME_ARGS (mean_path_delay), GST_TIME_ARGS (median));
+ ret = FALSE;
+ goto out;
+ }
+ }
+#endif
+
#ifdef USE_RUNNING_AVERAGE_DELAY
/* Track an average round trip time, for a bit of smoothing */
/* Always update before discarding a sample, so genuine changes in
@@ -1344,6 +1405,7 @@ handle_sync_message (PtpMessage * msg, GstClockTime receive_time)
if (!domain) {
gchar *clock_name;
+
domain = g_new0 (PtpDomainData, 1);
domain->domain = msg->domain_number;
clock_name = g_strdup_printf ("ptp-clock-%u", domain->domain);
@@ -1351,6 +1413,7 @@ handle_sync_message (PtpMessage * msg, GstClockTime receive_time)
g_object_new (GST_TYPE_SYSTEM_CLOCK, "name", clock_name, NULL);
g_free (clock_name);
g_queue_init (&domain->pending_syncs);
+ domain->last_path_delays_missing = 9;
domain_data = g_list_prepend (domain_data, domain);
g_mutex_lock (&domain_clocks_lock);