2 * Copyright (C) 2015 Sebastian Dröge <sebastian@centricular.com>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
22 * @short_description: Special clock that synchronizes to a remote time
23 * provider via PTP (IEEE1588:2008).
24 * @see_also: #GstClock, #GstNetClientClock, #GstPipeline
26 * GstPtpClock implements a PTP (IEEE1588:2008) ordinary clock in slave-only
27 * mode, that allows a GStreamer pipeline to synchronize to a PTP network
28 * clock in some specific domain.
30 * The PTP subsystem can be initialized with gst_ptp_init(), which then starts
31 * a helper process to do the actual communication via the PTP ports. This is
32 * required as PTP listens on ports < 1024 and thus requires special
33 * privileges. Once this helper process is started, the main process will
34 * synchronize to all PTP domains that are detected on the selected
37 * gst_ptp_clock_new() then allows to create a GstClock that provides the PTP
38 * time from a master clock inside a specific PTP domain. This clock will only
39 * return valid timestamps once the timestamps in the PTP domain are known. To
40 * check this, you can use gst_clock_wait_for_sync(), the GstClock::synced
41 * signal and gst_clock_is_synced().
44 * To gather statistics about the PTP clock synchronization,
45 * gst_ptp_statistics_callback_add() can be used. This gives the application
46 * the possibility to collect all kinds of statistics from the clock
56 #include "gstptpclock.h"
58 #include "gstptp_private.h"
60 #ifdef HAVE_SYS_WAIT_H
66 #include <sys/types.h>
69 #include <gst/base/base.h>
71 GST_DEBUG_CATEGORY_STATIC (ptp_debug);
72 #define GST_CAT_DEFAULT (ptp_debug)
74 /* IEEE 1588 7.7.3.1 */
75 #define PTP_ANNOUNCE_RECEIPT_TIMEOUT 4
77 /* Use a running average for calculating the mean path delay instead
78 * of just using the last measurement. Enabling this helps in unreliable
79 * networks, like wifi, with often changing delays
81 * Undef for following IEEE1588-2008 by the letter
83 #define USE_RUNNING_AVERAGE_DELAY 1
85 /* Filter out any measurements that are above a certain threshold compared to
86 * previous measurements. Enabling this helps filtering out outliers that
87 * happen fairly often in unreliable networks, like wifi.
89 * Undef for following IEEE1588-2008 by the letter
91 #define USE_MEASUREMENT_FILTERING 1
93 /* Select the first clock from which we capture a SYNC message as the master
94 * clock of the domain until we are ready to run the best master clock
95 * algorithm. This allows faster syncing but might mean a change of the master
96 * clock in the beginning. As all clocks in a domain are supposed to use the
97 * same time, this shouldn't be much of a problem.
99 * Undef for following IEEE1588-2008 by the letter
101 #define USE_OPPORTUNISTIC_CLOCK_SELECTION 1
103 /* Only consider SYNC messages for which we are allowed to send a DELAY_REQ
104 * afterwards. This allows better synchronization in networks with varying
105 * delays, as for every other SYNC message we would have to assume that it's
106 * the average of what we saw before. But that might be completely off
108 #define USE_ONLY_SYNC_WITH_DELAY 1
110 /* Filter out delay measurements that are too far away from the median of the
111 * last delay measurements, currently those that are more than 2 times as big.
112 * This increases accuracy a lot on wifi.
114 #define USE_MEDIAN_PRE_FILTERING 1
115 #define MEDIAN_PRE_FILTERING_WINDOW 9
117 /* How many updates should be skipped at maximum when using USE_MEASUREMENT_FILTERING */
118 #define MAX_SKIPPED_UPDATES 5
122 PTP_MESSAGE_TYPE_SYNC = 0x0,
123 PTP_MESSAGE_TYPE_DELAY_REQ = 0x1,
124 PTP_MESSAGE_TYPE_PDELAY_REQ = 0x2,
125 PTP_MESSAGE_TYPE_PDELAY_RESP = 0x3,
126 PTP_MESSAGE_TYPE_FOLLOW_UP = 0x8,
127 PTP_MESSAGE_TYPE_DELAY_RESP = 0x9,
128 PTP_MESSAGE_TYPE_PDELAY_RESP_FOLLOW_UP = 0xA,
129 PTP_MESSAGE_TYPE_ANNOUNCE = 0xB,
130 PTP_MESSAGE_TYPE_SIGNALING = 0xC,
131 PTP_MESSAGE_TYPE_MANAGEMENT = 0xD
136 guint64 seconds_field; /* 48 bits valid */
137 guint32 nanoseconds_field;
140 #define PTP_TIMESTAMP_TO_GST_CLOCK_TIME(ptp) (ptp.seconds_field * GST_SECOND + ptp.nanoseconds_field)
141 #define GST_CLOCK_TIME_TO_PTP_TIMESTAMP_SECONDS(gst) (((GstClockTime) gst) / GST_SECOND)
142 #define GST_CLOCK_TIME_TO_PTP_TIMESTAMP_NANOSECONDS(gst) (((GstClockTime) gst) % GST_SECOND)
146 guint64 clock_identity;
151 compare_clock_identity (const PtpClockIdentity * a, const PtpClockIdentity * b)
153 if (a->clock_identity < b->clock_identity)
155 else if (a->clock_identity > b->clock_identity)
158 if (a->port_number < b->port_number)
160 else if (a->port_number > b->port_number)
169 guint8 clock_accuracy;
170 guint16 offset_scaled_log_variance;
175 guint8 transport_specific;
176 PtpMessageType message_type;
177 /* guint8 reserved; */
179 guint16 message_length;
180 guint8 domain_number;
181 /* guint8 reserved; */
183 gint64 correction_field; /* 48.16 fixed point nanoseconds */
184 /* guint32 reserved; */
185 PtpClockIdentity source_port_identity;
187 guint8 control_field;
188 gint8 log_message_interval;
194 PtpTimestamp origin_timestamp;
195 gint16 current_utc_offset;
196 /* guint8 reserved; */
197 guint8 grandmaster_priority_1;
198 PtpClockQuality grandmaster_clock_quality;
199 guint8 grandmaster_priority_2;
200 guint64 grandmaster_identity;
201 guint16 steps_removed;
207 PtpTimestamp origin_timestamp;
212 PtpTimestamp precise_origin_timestamp;
217 PtpTimestamp origin_timestamp;
222 PtpTimestamp receive_timestamp;
223 PtpClockIdentity requesting_port_identity;
229 static GMutex ptp_lock;
230 static GCond ptp_cond;
231 static gboolean initted = FALSE;
233 static gboolean supported = TRUE;
235 static gboolean supported = FALSE;
237 static GPid ptp_helper_pid;
238 static GThread *ptp_helper_thread;
239 static GMainContext *main_context;
240 static GMainLoop *main_loop;
241 static GIOChannel *stdin_channel, *stdout_channel;
242 static GRand *delay_req_rand;
243 static GstClock *observation_system_clock;
244 static PtpClockIdentity ptp_clock_id = { GST_PTP_CLOCK_ID_NONE, 0 };
248 GstClockTime receive_time;
250 PtpClockIdentity master_clock_identity;
252 guint8 grandmaster_priority_1;
253 PtpClockQuality grandmaster_clock_quality;
254 guint8 grandmaster_priority_2;
255 guint64 grandmaster_identity;
256 guint16 steps_removed;
260 } PtpAnnounceMessage;
264 PtpClockIdentity master_clock_identity;
266 GstClockTime announce_interval; /* last interval we received */
267 GQueue announce_messages;
273 PtpClockIdentity master_clock_identity;
276 GstClockTime sync_recv_time_local; /* t2 */
277 GstClockTime sync_send_time_remote; /* t1, might be -1 if FOLLOW_UP pending */
278 GstClockTime follow_up_recv_time_local;
280 GSource *timeout_source;
281 guint16 delay_req_seqnum;
282 GstClockTime delay_req_send_time_local; /* t3, -1 if we wait for FOLLOW_UP */
283 GstClockTime delay_req_recv_time_remote; /* t4, -1 if we wait */
284 GstClockTime delay_resp_recv_time_local;
286 gint64 correction_field_sync; /* sum of the correction fields of SYNC/FOLLOW_UP */
287 gint64 correction_field_delay; /* sum of the correction fields of DELAY_RESP */
291 ptp_pending_sync_free (PtpPendingSync * sync)
293 if (sync->timeout_source)
294 g_source_destroy (sync->timeout_source);
302 GstClockTime last_ptp_time;
303 GstClockTime last_local_time;
304 gint skipped_updates;
306 /* Used for selecting the master/grandmaster */
307 GList *announce_senders;
309 /* Last selected master clock */
310 gboolean have_master_clock;
311 PtpClockIdentity master_clock_identity;
312 guint64 grandmaster_identity;
314 /* Last SYNC or FOLLOW_UP timestamp we received */
315 GstClockTime last_ptp_sync_time;
316 GstClockTime sync_interval;
318 GstClockTime mean_path_delay;
319 GstClockTime last_delay_req, min_delay_req_interval;
320 guint16 last_delay_req_seqnum;
322 GstClockTime last_path_delays[MEDIAN_PRE_FILTERING_WINDOW];
323 gint last_path_delays_missing;
325 GQueue pending_syncs;
327 GstClock *domain_clock;
330 static GList *domain_data;
331 static GMutex domain_clocks_lock;
332 static GList *domain_clocks;
334 /* Protected by PTP lock */
335 static void emit_ptp_statistics (guint8 domain, const GstStructure * stats);
336 static GHookList domain_stats_hooks;
337 static gint domain_stats_n_hooks;
338 static gboolean domain_stats_hooks_initted = FALSE;
340 /* Converts log2 seconds to GstClockTime */
342 log2_to_clock_time (gint l)
345 return GST_SECOND >> (-l);
347 return GST_SECOND << l;
351 dump_ptp_message (PtpMessage * msg)
353 GST_TRACE ("PTP message:");
354 GST_TRACE ("\ttransport_specific: %u", msg->transport_specific);
355 GST_TRACE ("\tmessage_type: 0x%01x", msg->message_type);
356 GST_TRACE ("\tversion_ptp: %u", msg->version_ptp);
357 GST_TRACE ("\tmessage_length: %u", msg->message_length);
358 GST_TRACE ("\tdomain_number: %u", msg->domain_number);
359 GST_TRACE ("\tflag_field: 0x%04x", msg->flag_field);
360 GST_TRACE ("\tcorrection_field: %" G_GINT64_FORMAT ".%03u",
361 (msg->correction_field / 65536),
362 (guint) ((msg->correction_field & 0xffff) * 1000) / 65536);
363 GST_TRACE ("\tsource_port_identity: 0x%016" G_GINT64_MODIFIER "x %u",
364 msg->source_port_identity.clock_identity,
365 msg->source_port_identity.port_number);
366 GST_TRACE ("\tsequence_id: %u", msg->sequence_id);
367 GST_TRACE ("\tcontrol_field: 0x%02x", msg->control_field);
368 GST_TRACE ("\tmessage_interval: %" GST_TIME_FORMAT,
369 GST_TIME_ARGS (log2_to_clock_time (msg->log_message_interval)));
371 switch (msg->message_type) {
372 case PTP_MESSAGE_TYPE_ANNOUNCE:
373 GST_TRACE ("\tANNOUNCE:");
374 GST_TRACE ("\t\torigin_timestamp: %" G_GUINT64_FORMAT ".%09u",
375 msg->message_specific.announce.origin_timestamp.seconds_field,
376 msg->message_specific.announce.origin_timestamp.nanoseconds_field);
377 GST_TRACE ("\t\tcurrent_utc_offset: %d",
378 msg->message_specific.announce.current_utc_offset);
379 GST_TRACE ("\t\tgrandmaster_priority_1: %u",
380 msg->message_specific.announce.grandmaster_priority_1);
381 GST_TRACE ("\t\tgrandmaster_clock_quality: 0x%02x 0x%02x %u",
382 msg->message_specific.announce.grandmaster_clock_quality.clock_class,
383 msg->message_specific.announce.
384 grandmaster_clock_quality.clock_accuracy,
385 msg->message_specific.announce.
386 grandmaster_clock_quality.offset_scaled_log_variance);
387 GST_TRACE ("\t\tgrandmaster_priority_2: %u",
388 msg->message_specific.announce.grandmaster_priority_2);
389 GST_TRACE ("\t\tgrandmaster_identity: 0x%016" G_GINT64_MODIFIER "x",
390 msg->message_specific.announce.grandmaster_identity);
391 GST_TRACE ("\t\tsteps_removed: %u",
392 msg->message_specific.announce.steps_removed);
393 GST_TRACE ("\t\ttime_source: 0x%02x",
394 msg->message_specific.announce.time_source);
396 case PTP_MESSAGE_TYPE_SYNC:
397 GST_TRACE ("\tSYNC:");
398 GST_TRACE ("\t\torigin_timestamp: %" G_GUINT64_FORMAT ".%09u",
399 msg->message_specific.sync.origin_timestamp.seconds_field,
400 msg->message_specific.sync.origin_timestamp.nanoseconds_field);
402 case PTP_MESSAGE_TYPE_FOLLOW_UP:
403 GST_TRACE ("\tFOLLOW_UP:");
404 GST_TRACE ("\t\tprecise_origin_timestamp: %" G_GUINT64_FORMAT ".%09u",
405 msg->message_specific.follow_up.
406 precise_origin_timestamp.seconds_field,
407 msg->message_specific.follow_up.
408 precise_origin_timestamp.nanoseconds_field);
410 case PTP_MESSAGE_TYPE_DELAY_REQ:
411 GST_TRACE ("\tDELAY_REQ:");
412 GST_TRACE ("\t\torigin_timestamp: %" G_GUINT64_FORMAT ".%09u",
413 msg->message_specific.delay_req.origin_timestamp.seconds_field,
414 msg->message_specific.delay_req.origin_timestamp.nanoseconds_field);
416 case PTP_MESSAGE_TYPE_DELAY_RESP:
417 GST_TRACE ("\tDELAY_RESP:");
418 GST_TRACE ("\t\treceive_timestamp: %" G_GUINT64_FORMAT ".%09u",
419 msg->message_specific.delay_resp.receive_timestamp.seconds_field,
420 msg->message_specific.delay_resp.receive_timestamp.nanoseconds_field);
421 GST_TRACE ("\t\trequesting_port_identity: 0x%016" G_GINT64_MODIFIER
423 msg->message_specific.delay_resp.
424 requesting_port_identity.clock_identity,
425 msg->message_specific.delay_resp.
426 requesting_port_identity.port_number);
434 /* IEEE 1588-2008 5.3.3 */
436 parse_ptp_timestamp (PtpTimestamp * timestamp, GstByteReader * reader)
438 g_return_val_if_fail (gst_byte_reader_get_remaining (reader) >= 10, FALSE);
440 timestamp->seconds_field =
441 (((guint64) gst_byte_reader_get_uint32_be_unchecked (reader)) << 16) |
442 gst_byte_reader_get_uint16_be_unchecked (reader);
443 timestamp->nanoseconds_field =
444 gst_byte_reader_get_uint32_be_unchecked (reader);
446 if (timestamp->nanoseconds_field >= 1000000000)
452 /* IEEE 1588-2008 13.3 */
454 parse_ptp_message_header (PtpMessage * msg, GstByteReader * reader)
458 g_return_val_if_fail (gst_byte_reader_get_remaining (reader) >= 34, FALSE);
460 b = gst_byte_reader_get_uint8_unchecked (reader);
461 msg->transport_specific = b >> 4;
462 msg->message_type = b & 0x0f;
464 b = gst_byte_reader_get_uint8_unchecked (reader);
465 msg->version_ptp = b & 0x0f;
466 if (msg->version_ptp != 2) {
467 GST_WARNING ("Unsupported PTP message version (%u != 2)", msg->version_ptp);
471 msg->message_length = gst_byte_reader_get_uint16_be_unchecked (reader);
472 if (gst_byte_reader_get_remaining (reader) + 4 < msg->message_length) {
473 GST_WARNING ("Not enough data (%u < %u)",
474 gst_byte_reader_get_remaining (reader) + 4, msg->message_length);
478 msg->domain_number = gst_byte_reader_get_uint8_unchecked (reader);
479 gst_byte_reader_skip_unchecked (reader, 1);
481 msg->flag_field = gst_byte_reader_get_uint16_be_unchecked (reader);
482 msg->correction_field = gst_byte_reader_get_uint64_be_unchecked (reader);
483 gst_byte_reader_skip_unchecked (reader, 4);
485 msg->source_port_identity.clock_identity =
486 gst_byte_reader_get_uint64_be_unchecked (reader);
487 msg->source_port_identity.port_number =
488 gst_byte_reader_get_uint16_be_unchecked (reader);
490 msg->sequence_id = gst_byte_reader_get_uint16_be_unchecked (reader);
491 msg->control_field = gst_byte_reader_get_uint8_unchecked (reader);
492 msg->log_message_interval = gst_byte_reader_get_uint8_unchecked (reader);
497 /* IEEE 1588-2008 13.5 */
499 parse_ptp_message_announce (PtpMessage * msg, GstByteReader * reader)
501 g_return_val_if_fail (msg->message_type == PTP_MESSAGE_TYPE_ANNOUNCE, FALSE);
503 if (gst_byte_reader_get_remaining (reader) < 20)
506 if (!parse_ptp_timestamp (&msg->message_specific.announce.origin_timestamp,
510 msg->message_specific.announce.current_utc_offset =
511 gst_byte_reader_get_uint16_be_unchecked (reader);
512 gst_byte_reader_skip_unchecked (reader, 1);
514 msg->message_specific.announce.grandmaster_priority_1 =
515 gst_byte_reader_get_uint8_unchecked (reader);
516 msg->message_specific.announce.grandmaster_clock_quality.clock_class =
517 gst_byte_reader_get_uint8_unchecked (reader);
518 msg->message_specific.announce.grandmaster_clock_quality.clock_accuracy =
519 gst_byte_reader_get_uint8_unchecked (reader);
520 msg->message_specific.announce.
521 grandmaster_clock_quality.offset_scaled_log_variance =
522 gst_byte_reader_get_uint16_be_unchecked (reader);
523 msg->message_specific.announce.grandmaster_priority_2 =
524 gst_byte_reader_get_uint8_unchecked (reader);
525 msg->message_specific.announce.grandmaster_identity =
526 gst_byte_reader_get_uint64_be_unchecked (reader);
527 msg->message_specific.announce.steps_removed =
528 gst_byte_reader_get_uint16_be_unchecked (reader);
529 msg->message_specific.announce.time_source =
530 gst_byte_reader_get_uint8_unchecked (reader);
535 /* IEEE 1588-2008 13.6 */
537 parse_ptp_message_sync (PtpMessage * msg, GstByteReader * reader)
539 g_return_val_if_fail (msg->message_type == PTP_MESSAGE_TYPE_SYNC, FALSE);
541 if (gst_byte_reader_get_remaining (reader) < 10)
544 if (!parse_ptp_timestamp (&msg->message_specific.sync.origin_timestamp,
551 /* IEEE 1588-2008 13.6 */
553 parse_ptp_message_delay_req (PtpMessage * msg, GstByteReader * reader)
555 g_return_val_if_fail (msg->message_type == PTP_MESSAGE_TYPE_DELAY_REQ, FALSE);
557 if (gst_byte_reader_get_remaining (reader) < 10)
560 if (!parse_ptp_timestamp (&msg->message_specific.delay_req.origin_timestamp,
567 /* IEEE 1588-2008 13.7 */
569 parse_ptp_message_follow_up (PtpMessage * msg, GstByteReader * reader)
571 g_return_val_if_fail (msg->message_type == PTP_MESSAGE_TYPE_FOLLOW_UP, FALSE);
573 if (gst_byte_reader_get_remaining (reader) < 10)
576 if (!parse_ptp_timestamp (&msg->message_specific.
577 follow_up.precise_origin_timestamp, reader))
583 /* IEEE 1588-2008 13.8 */
585 parse_ptp_message_delay_resp (PtpMessage * msg, GstByteReader * reader)
587 g_return_val_if_fail (msg->message_type == PTP_MESSAGE_TYPE_DELAY_RESP,
590 if (gst_byte_reader_get_remaining (reader) < 20)
593 if (!parse_ptp_timestamp (&msg->message_specific.delay_resp.receive_timestamp,
597 msg->message_specific.delay_resp.requesting_port_identity.clock_identity =
598 gst_byte_reader_get_uint64_be_unchecked (reader);
599 msg->message_specific.delay_resp.requesting_port_identity.port_number =
600 gst_byte_reader_get_uint16_be_unchecked (reader);
606 parse_ptp_message (PtpMessage * msg, const guint8 * data, gsize size)
608 GstByteReader reader;
609 gboolean ret = FALSE;
611 gst_byte_reader_init (&reader, data, size);
613 if (!parse_ptp_message_header (msg, &reader)) {
614 GST_WARNING ("Failed to parse PTP message header");
618 switch (msg->message_type) {
619 case PTP_MESSAGE_TYPE_SYNC:
620 ret = parse_ptp_message_sync (msg, &reader);
622 case PTP_MESSAGE_TYPE_FOLLOW_UP:
623 ret = parse_ptp_message_follow_up (msg, &reader);
625 case PTP_MESSAGE_TYPE_DELAY_REQ:
626 ret = parse_ptp_message_delay_req (msg, &reader);
628 case PTP_MESSAGE_TYPE_DELAY_RESP:
629 ret = parse_ptp_message_delay_resp (msg, &reader);
631 case PTP_MESSAGE_TYPE_ANNOUNCE:
632 ret = parse_ptp_message_announce (msg, &reader);
643 compare_announce_message (const PtpAnnounceMessage * a,
644 const PtpAnnounceMessage * b)
646 /* IEEE 1588 Figure 27 */
647 if (a->grandmaster_identity == b->grandmaster_identity) {
648 if (a->steps_removed + 1 < b->steps_removed)
650 else if (a->steps_removed > b->steps_removed + 1)
653 /* Error cases are filtered out earlier */
654 if (a->steps_removed < b->steps_removed)
656 else if (a->steps_removed > b->steps_removed)
659 /* Error cases are filtered out earlier */
660 if (a->master_clock_identity.clock_identity <
661 b->master_clock_identity.clock_identity)
663 else if (a->master_clock_identity.clock_identity >
664 b->master_clock_identity.clock_identity)
667 /* Error cases are filtered out earlier */
668 if (a->master_clock_identity.port_number <
669 b->master_clock_identity.port_number)
671 else if (a->master_clock_identity.port_number >
672 b->master_clock_identity.port_number)
675 g_assert_not_reached ();
680 if (a->grandmaster_priority_1 < b->grandmaster_priority_1)
682 else if (a->grandmaster_priority_1 > b->grandmaster_priority_1)
685 if (a->grandmaster_clock_quality.clock_class <
686 b->grandmaster_clock_quality.clock_class)
688 else if (a->grandmaster_clock_quality.clock_class >
689 b->grandmaster_clock_quality.clock_class)
692 if (a->grandmaster_clock_quality.clock_accuracy <
693 b->grandmaster_clock_quality.clock_accuracy)
695 else if (a->grandmaster_clock_quality.clock_accuracy >
696 b->grandmaster_clock_quality.clock_accuracy)
699 if (a->grandmaster_clock_quality.offset_scaled_log_variance <
700 b->grandmaster_clock_quality.offset_scaled_log_variance)
702 else if (a->grandmaster_clock_quality.offset_scaled_log_variance >
703 b->grandmaster_clock_quality.offset_scaled_log_variance)
706 if (a->grandmaster_priority_2 < b->grandmaster_priority_2)
708 else if (a->grandmaster_priority_2 > b->grandmaster_priority_2)
711 if (a->grandmaster_identity < b->grandmaster_identity)
713 else if (a->grandmaster_identity > b->grandmaster_identity)
716 g_assert_not_reached ();
722 select_best_master_clock (PtpDomainData * domain, GstClockTime now)
724 GList *qualified_messages = NULL;
726 PtpAnnounceMessage *best = NULL;
728 /* IEEE 1588 9.3.2.5 */
729 for (l = domain->announce_senders; l; l = l->next) {
730 PtpAnnounceSender *sender = l->data;
731 GstClockTime window = 4 * sender->announce_interval;
734 for (m = sender->announce_messages.head; m; m = m->next) {
735 PtpAnnounceMessage *msg = m->data;
737 if (now - msg->receive_time <= window)
741 /* Only include the newest message of announce senders that had at least 2
742 * announce messages in the last 4 announce intervals. Which also means
743 * that we wait at least 4 announce intervals before we select a master
744 * clock. Until then we just report based on the newest SYNC we received
748 g_list_prepend (qualified_messages,
749 g_queue_peek_tail (&sender->announce_messages));
753 if (!qualified_messages) {
755 ("No qualified announce messages for domain %u, can't select a master clock",
757 domain->have_master_clock = FALSE;
761 for (l = qualified_messages; l; l = l->next) {
762 PtpAnnounceMessage *msg = l->data;
764 if (!best || compare_announce_message (msg, best) < 0)
768 if (domain->have_master_clock
769 && compare_clock_identity (&domain->master_clock_identity,
770 &best->master_clock_identity) == 0) {
771 GST_DEBUG ("Master clock in domain %u did not change", domain->domain);
773 GST_DEBUG ("Selected master clock for domain %u: 0x%016" G_GINT64_MODIFIER
774 "x %u with grandmaster clock 0x%016" G_GINT64_MODIFIER "x",
775 domain->domain, best->master_clock_identity.clock_identity,
776 best->master_clock_identity.port_number, best->grandmaster_identity);
778 domain->have_master_clock = TRUE;
779 domain->grandmaster_identity = best->grandmaster_identity;
781 /* Opportunistic master clock selection likely gave us the same master
782 * clock before, no need to reset all statistics */
783 if (compare_clock_identity (&domain->master_clock_identity,
784 &best->master_clock_identity) != 0) {
785 memcpy (&domain->master_clock_identity, &best->master_clock_identity,
786 sizeof (PtpClockIdentity));
787 domain->mean_path_delay = 0;
788 domain->last_delay_req = 0;
789 domain->last_path_delays_missing = 9;
790 domain->min_delay_req_interval = 0;
791 domain->sync_interval = 0;
792 domain->last_ptp_sync_time = 0;
793 domain->skipped_updates = 0;
794 g_queue_foreach (&domain->pending_syncs, (GFunc) ptp_pending_sync_free,
796 g_queue_clear (&domain->pending_syncs);
799 if (g_atomic_int_get (&domain_stats_n_hooks)) {
800 GstStructure *stats =
801 gst_structure_new (GST_PTP_STATISTICS_BEST_MASTER_CLOCK_SELECTED,
802 "domain", G_TYPE_UINT, domain->domain,
803 "master-clock-id", G_TYPE_UINT64,
804 domain->master_clock_identity.clock_identity,
805 "master-clock-port", G_TYPE_UINT,
806 domain->master_clock_identity.port_number,
807 "grandmaster-clock-id", G_TYPE_UINT64, domain->grandmaster_identity,
809 emit_ptp_statistics (domain->domain, stats);
810 gst_structure_free (stats);
816 handle_announce_message (PtpMessage * msg, GstClockTime receive_time)
819 PtpDomainData *domain = NULL;
820 PtpAnnounceSender *sender = NULL;
821 PtpAnnounceMessage *announce;
823 /* IEEE1588 9.3.2.2 e)
824 * Don't consider messages with the alternate master flag set
826 if ((msg->flag_field & 0x0100))
829 /* IEEE 1588 9.3.2.5 d)
830 * Don't consider announce messages with steps_removed>=255
832 if (msg->message_specific.announce.steps_removed >= 255)
835 for (l = domain_data; l; l = l->next) {
836 PtpDomainData *tmp = l->data;
838 if (tmp->domain == msg->domain_number) {
847 domain = g_new0 (PtpDomainData, 1);
848 domain->domain = msg->domain_number;
849 clock_name = g_strdup_printf ("ptp-clock-%u", domain->domain);
850 domain->domain_clock =
851 g_object_new (GST_TYPE_SYSTEM_CLOCK, "name", clock_name, NULL);
853 g_queue_init (&domain->pending_syncs);
854 domain->last_path_delays_missing = 9;
855 domain_data = g_list_prepend (domain_data, domain);
857 g_mutex_lock (&domain_clocks_lock);
858 domain_clocks = g_list_prepend (domain_clocks, domain);
859 g_mutex_unlock (&domain_clocks_lock);
861 if (g_atomic_int_get (&domain_stats_n_hooks)) {
862 GstStructure *stats =
863 gst_structure_new (GST_PTP_STATISTICS_NEW_DOMAIN_FOUND, "domain",
864 G_TYPE_UINT, domain->domain, "clock", GST_TYPE_CLOCK,
865 domain->domain_clock, NULL);
866 emit_ptp_statistics (domain->domain, stats);
867 gst_structure_free (stats);
871 for (l = domain->announce_senders; l; l = l->next) {
872 PtpAnnounceSender *tmp = l->data;
874 if (compare_clock_identity (&tmp->master_clock_identity,
875 &msg->source_port_identity) == 0) {
882 sender = g_new0 (PtpAnnounceSender, 1);
884 memcpy (&sender->master_clock_identity, &msg->source_port_identity,
885 sizeof (PtpClockIdentity));
886 g_queue_init (&sender->announce_messages);
887 domain->announce_senders =
888 g_list_prepend (domain->announce_senders, sender);
891 for (l = sender->announce_messages.head; l; l = l->next) {
892 PtpAnnounceMessage *tmp = l->data;
894 /* IEEE 1588 9.3.2.5 c)
895 * Don't consider identical messages, i.e. duplicates
897 if (tmp->sequence_id == msg->sequence_id)
901 sender->announce_interval = log2_to_clock_time (msg->log_message_interval);
903 announce = g_new0 (PtpAnnounceMessage, 1);
904 announce->receive_time = receive_time;
905 announce->sequence_id = msg->sequence_id;
906 memcpy (&announce->master_clock_identity, &msg->source_port_identity,
907 sizeof (PtpClockIdentity));
908 announce->grandmaster_identity =
909 msg->message_specific.announce.grandmaster_identity;
910 announce->grandmaster_priority_1 =
911 msg->message_specific.announce.grandmaster_priority_1;
912 announce->grandmaster_clock_quality.clock_class =
913 msg->message_specific.announce.grandmaster_clock_quality.clock_class;
914 announce->grandmaster_clock_quality.clock_accuracy =
915 msg->message_specific.announce.grandmaster_clock_quality.clock_accuracy;
916 announce->grandmaster_clock_quality.offset_scaled_log_variance =
917 msg->message_specific.announce.
918 grandmaster_clock_quality.offset_scaled_log_variance;
919 announce->grandmaster_priority_2 =
920 msg->message_specific.announce.grandmaster_priority_2;
921 announce->steps_removed = msg->message_specific.announce.steps_removed;
922 announce->time_source = msg->message_specific.announce.time_source;
923 g_queue_push_tail (&sender->announce_messages, announce);
925 select_best_master_clock (domain, receive_time);
929 send_delay_req_timeout (PtpPendingSync * sync)
931 StdIOHeader header = { 0, };
932 guint8 delay_req[44];
933 GstByteWriter writer;
938 header.type = TYPE_EVENT;
941 gst_byte_writer_init_with_data (&writer, delay_req, 44, FALSE);
942 gst_byte_writer_put_uint8_unchecked (&writer, PTP_MESSAGE_TYPE_DELAY_REQ);
943 gst_byte_writer_put_uint8_unchecked (&writer, 2);
944 gst_byte_writer_put_uint16_be_unchecked (&writer, 44);
945 gst_byte_writer_put_uint8_unchecked (&writer, sync->domain);
946 gst_byte_writer_put_uint8_unchecked (&writer, 0);
947 gst_byte_writer_put_uint16_be_unchecked (&writer, 0);
948 gst_byte_writer_put_uint64_be_unchecked (&writer, 0);
949 gst_byte_writer_put_uint32_be_unchecked (&writer, 0);
950 gst_byte_writer_put_uint64_be_unchecked (&writer,
951 ptp_clock_id.clock_identity);
952 gst_byte_writer_put_uint16_be_unchecked (&writer, ptp_clock_id.port_number);
953 gst_byte_writer_put_uint16_be_unchecked (&writer, sync->delay_req_seqnum);
954 gst_byte_writer_put_uint8_unchecked (&writer, 0x01);
955 gst_byte_writer_put_uint8_unchecked (&writer, 0x7f);
956 gst_byte_writer_put_uint64_be_unchecked (&writer, 0);
957 gst_byte_writer_put_uint16_be_unchecked (&writer, 0);
960 g_io_channel_write_chars (stdout_channel, (gchar *) & header,
961 sizeof (header), &written, &err);
962 if (status == G_IO_STATUS_ERROR) {
963 g_warning ("Failed to write to stdout: %s", err->message);
964 return G_SOURCE_REMOVE;
965 } else if (status == G_IO_STATUS_EOF) {
966 g_message ("EOF on stdout");
967 g_main_loop_quit (main_loop);
968 return G_SOURCE_REMOVE;
969 } else if (status != G_IO_STATUS_NORMAL) {
970 g_warning ("Unexpected stdout write status: %d", status);
971 g_main_loop_quit (main_loop);
972 return G_SOURCE_REMOVE;
973 } else if (written != sizeof (header)) {
974 g_warning ("Unexpected write size: %" G_GSIZE_FORMAT, written);
975 g_main_loop_quit (main_loop);
976 return G_SOURCE_REMOVE;
979 sync->delay_req_send_time_local =
980 gst_clock_get_time (observation_system_clock);
983 g_io_channel_write_chars (stdout_channel,
984 (const gchar *) delay_req, 44, &written, &err);
985 if (status == G_IO_STATUS_ERROR) {
986 g_warning ("Failed to write to stdout: %s", err->message);
987 g_main_loop_quit (main_loop);
988 return G_SOURCE_REMOVE;
989 } else if (status == G_IO_STATUS_EOF) {
990 g_message ("EOF on stdout");
991 g_main_loop_quit (main_loop);
992 return G_SOURCE_REMOVE;
993 } else if (status != G_IO_STATUS_NORMAL) {
994 g_warning ("Unexpected stdout write status: %d", status);
995 g_main_loop_quit (main_loop);
996 return G_SOURCE_REMOVE;
997 } else if (written != 44) {
998 g_warning ("Unexpected write size: %" G_GSIZE_FORMAT, written);
999 g_main_loop_quit (main_loop);
1000 return G_SOURCE_REMOVE;
1003 return G_SOURCE_REMOVE;
1007 send_delay_req (PtpDomainData * domain, PtpPendingSync * sync)
1009 GstClockTime now = gst_clock_get_time (observation_system_clock);
1011 GSource *timeout_source;
1013 if (domain->last_delay_req != 0
1014 && domain->last_delay_req + domain->min_delay_req_interval > now)
1017 domain->last_delay_req = now;
1018 sync->delay_req_seqnum = domain->last_delay_req_seqnum++;
1020 /* IEEE 1588 9.5.11.2 */
1021 if (domain->last_delay_req == 0 || domain->min_delay_req_interval == 0)
1025 g_rand_int_range (delay_req_rand, 0,
1026 (domain->min_delay_req_interval * 2) / GST_MSECOND);
1028 sync->timeout_source = timeout_source = g_timeout_source_new (timeout);
1029 g_source_set_priority (timeout_source, G_PRIORITY_DEFAULT);
1030 g_source_set_callback (timeout_source, (GSourceFunc) send_delay_req_timeout,
1032 g_source_attach (timeout_source, main_context);
1037 /* Filtering of outliers for RTT and time calculations inspired
1038 * by the code from gstnetclientclock.c
1041 update_ptp_time (PtpDomainData * domain, PtpPendingSync * sync)
1043 GstClockTime internal_time, external_time, rate_num, rate_den;
1044 GstClockTime corrected_ptp_time, corrected_local_time;
1045 gdouble r_squared = 0.0;
1047 GstClockTimeDiff discont = 0;
1048 GstClockTime estimated_ptp_time = GST_CLOCK_TIME_NONE;
1049 #ifdef USE_MEASUREMENT_FILTERING
1050 GstClockTime orig_internal_time, orig_external_time, orig_rate_num,
1052 GstClockTime new_estimated_ptp_time;
1053 GstClockTime max_discont, estimated_ptp_time_min, estimated_ptp_time_max;
1054 gboolean now_synced;
1057 #ifdef USE_ONLY_SYNC_WITH_DELAY
1058 GstClockTime mean_path_delay;
1060 if (sync->delay_req_send_time_local == GST_CLOCK_TIME_NONE)
1063 /* IEEE 1588 11.3 */
1065 (sync->delay_req_recv_time_remote - sync->sync_send_time_remote +
1066 sync->sync_recv_time_local - sync->delay_req_send_time_local -
1067 (sync->correction_field_sync + sync->correction_field_delay +
1068 32768) / 65536) / 2;
1071 /* IEEE 1588 11.2 */
1072 corrected_ptp_time =
1073 sync->sync_send_time_remote +
1074 (sync->correction_field_sync + 32768) / 65536;
1076 #ifdef USE_ONLY_SYNC_WITH_DELAY
1077 corrected_local_time = sync->sync_recv_time_local - mean_path_delay;
1079 corrected_local_time = sync->sync_recv_time_local - domain->mean_path_delay;
1082 #ifdef USE_MEASUREMENT_FILTERING
1083 /* We check this here and when updating the mean path delay, because
1084 * we can get here without a delay response too */
1085 if (sync->follow_up_recv_time_local != GST_CLOCK_TIME_NONE
1086 && sync->follow_up_recv_time_local >
1087 sync->sync_recv_time_local + 2 * domain->mean_path_delay) {
1088 GST_WARNING ("Sync-follow-up delay for domain %u too big: %" GST_TIME_FORMAT
1089 " > 2 * %" GST_TIME_FORMAT, domain->domain,
1090 GST_TIME_ARGS (sync->follow_up_recv_time_local),
1091 GST_TIME_ARGS (domain->mean_path_delay));
1093 gst_clock_get_calibration (GST_CLOCK_CAST (domain->domain_clock),
1094 &internal_time, &external_time, &rate_num, &rate_den);
1099 /* Set an initial local-remote relation */
1100 if (domain->last_ptp_time == 0)
1101 gst_clock_set_calibration (domain->domain_clock, corrected_local_time,
1102 corrected_ptp_time, 1, 1);
1104 #ifdef USE_MEASUREMENT_FILTERING
1105 /* Check if the corrected PTP time is +/- 3/4 RTT around what we would
1106 * estimate with our present knowledge about the clock
1108 /* Store what the clock produced as 'now' before this update */
1109 gst_clock_get_calibration (GST_CLOCK_CAST (domain->domain_clock),
1110 &orig_internal_time, &orig_external_time, &orig_rate_num, &orig_rate_den);
1111 internal_time = orig_internal_time;
1112 external_time = orig_external_time;
1113 rate_num = orig_rate_num;
1114 rate_den = orig_rate_den;
1116 /* 3/4 RTT window around the estimation */
1117 max_discont = domain->mean_path_delay * 3 / 2;
1119 /* Check if the estimated sync time is inside our window */
1120 estimated_ptp_time_min = corrected_local_time - max_discont;
1121 estimated_ptp_time_min =
1122 gst_clock_adjust_with_calibration (GST_CLOCK_CAST (domain->domain_clock),
1123 estimated_ptp_time_min, internal_time, external_time, rate_num, rate_den);
1124 estimated_ptp_time_max = corrected_local_time + max_discont;
1125 estimated_ptp_time_max =
1126 gst_clock_adjust_with_calibration (GST_CLOCK_CAST (domain->domain_clock),
1127 estimated_ptp_time_max, internal_time, external_time, rate_num, rate_den);
1129 synced = (estimated_ptp_time_min < corrected_ptp_time
1130 && corrected_ptp_time < estimated_ptp_time_max);
1132 GST_DEBUG ("Adding observation for domain %u: %" GST_TIME_FORMAT " - %"
1133 GST_TIME_FORMAT, domain->domain,
1134 GST_TIME_ARGS (corrected_ptp_time), GST_TIME_ARGS (corrected_local_time));
1136 GST_DEBUG ("Synced %d: %" GST_TIME_FORMAT " < %" GST_TIME_FORMAT " < %"
1137 GST_TIME_FORMAT, synced, GST_TIME_ARGS (estimated_ptp_time_min),
1138 GST_TIME_ARGS (corrected_ptp_time),
1139 GST_TIME_ARGS (estimated_ptp_time_max));
1141 if (gst_clock_add_observation_unapplied (domain->domain_clock,
1142 corrected_local_time, corrected_ptp_time, &r_squared,
1143 &internal_time, &external_time, &rate_num, &rate_den)) {
1144 GST_DEBUG ("Regression gave r_squared: %f", r_squared);
1146 /* Old estimated PTP time based on receive time and path delay */
1147 estimated_ptp_time = corrected_local_time;
1148 estimated_ptp_time =
1149 gst_clock_adjust_with_calibration (GST_CLOCK_CAST
1150 (domain->domain_clock), estimated_ptp_time, orig_internal_time,
1151 orig_external_time, orig_rate_num, orig_rate_den);
1153 /* New estimated PTP time based on receive time and path delay */
1154 new_estimated_ptp_time = corrected_local_time;
1155 new_estimated_ptp_time =
1156 gst_clock_adjust_with_calibration (GST_CLOCK_CAST
1157 (domain->domain_clock), new_estimated_ptp_time, internal_time,
1158 external_time, rate_num, rate_den);
1160 discont = GST_CLOCK_DIFF (estimated_ptp_time, new_estimated_ptp_time);
1161 if (synced && ABS (discont) > max_discont) {
1162 GstClockTimeDiff offset;
1163 GST_DEBUG ("Too large a discont %s%" GST_TIME_FORMAT
1164 ", clamping to 1/4 average RTT = %" GST_TIME_FORMAT,
1165 (discont < 0 ? "-" : ""), GST_TIME_ARGS (ABS (discont)),
1166 GST_TIME_ARGS (max_discont));
1167 if (discont > 0) { /* Too large a forward step - add a -ve offset */
1168 offset = max_discont - discont;
1169 if (-offset > external_time)
1172 external_time += offset;
1173 } else { /* Too large a backward step - add a +ve offset */
1174 offset = -(max_discont + discont);
1175 external_time += offset;
1180 GST_DEBUG ("Discont %s%" GST_TIME_FORMAT " (max: %" GST_TIME_FORMAT ")",
1181 (discont < 0 ? "-" : ""), GST_TIME_ARGS (ABS (discont)),
1182 GST_TIME_ARGS (max_discont));
1185 /* Check if the estimated sync time is now (still) inside our window */
1186 estimated_ptp_time_min = corrected_local_time - max_discont;
1187 estimated_ptp_time_min =
1188 gst_clock_adjust_with_calibration (GST_CLOCK_CAST
1189 (domain->domain_clock), estimated_ptp_time_min, internal_time,
1190 external_time, rate_num, rate_den);
1191 estimated_ptp_time_max = corrected_local_time + max_discont;
1192 estimated_ptp_time_max =
1193 gst_clock_adjust_with_calibration (GST_CLOCK_CAST
1194 (domain->domain_clock), estimated_ptp_time_max, internal_time,
1195 external_time, rate_num, rate_den);
1197 now_synced = (estimated_ptp_time_min < corrected_ptp_time
1198 && corrected_ptp_time < estimated_ptp_time_max);
1200 GST_DEBUG ("Now synced %d: %" GST_TIME_FORMAT " < %" GST_TIME_FORMAT " < %"
1201 GST_TIME_FORMAT, now_synced, GST_TIME_ARGS (estimated_ptp_time_min),
1202 GST_TIME_ARGS (corrected_ptp_time),
1203 GST_TIME_ARGS (estimated_ptp_time_max));
1205 if (synced || now_synced || domain->skipped_updates > MAX_SKIPPED_UPDATES) {
1206 gst_clock_set_calibration (GST_CLOCK_CAST (domain->domain_clock),
1207 internal_time, external_time, rate_num, rate_den);
1208 domain->skipped_updates = 0;
1210 domain->last_ptp_time = corrected_ptp_time;
1211 domain->last_local_time = corrected_local_time;
1213 domain->skipped_updates++;
1216 domain->last_ptp_time = corrected_ptp_time;
1217 domain->last_local_time = corrected_local_time;
1221 GST_DEBUG ("Adding observation for domain %u: %" GST_TIME_FORMAT " - %"
1222 GST_TIME_FORMAT, domain->domain,
1223 GST_TIME_ARGS (corrected_ptp_time), GST_TIME_ARGS (corrected_local_time));
1225 gst_clock_get_calibration (GST_CLOCK_CAST (domain->domain_clock),
1226 &internal_time, &external_time, &rate_num, &rate_den);
1228 estimated_ptp_time = corrected_local_time;
1229 estimated_ptp_time =
1230 gst_clock_adjust_with_calibration (GST_CLOCK_CAST
1231 (domain->domain_clock), estimated_ptp_time, internal_time,
1232 external_time, rate_num, rate_den);
1234 gst_clock_add_observation (domain->domain_clock,
1235 corrected_local_time, corrected_ptp_time, &r_squared);
1237 gst_clock_get_calibration (GST_CLOCK_CAST (domain->domain_clock),
1238 &internal_time, &external_time, &rate_num, &rate_den);
1241 domain->last_ptp_time = corrected_ptp_time;
1242 domain->last_local_time = corrected_local_time;
1245 #ifdef USE_MEASUREMENT_FILTERING
1248 if (g_atomic_int_get (&domain_stats_n_hooks)) {
1249 GstStructure *stats = gst_structure_new (GST_PTP_STATISTICS_TIME_UPDATED,
1250 "domain", G_TYPE_UINT, domain->domain,
1251 "mean-path-delay-avg", GST_TYPE_CLOCK_TIME, domain->mean_path_delay,
1252 "local-time", GST_TYPE_CLOCK_TIME, corrected_local_time,
1253 "ptp-time", GST_TYPE_CLOCK_TIME, corrected_ptp_time,
1254 "estimated-ptp-time", GST_TYPE_CLOCK_TIME, estimated_ptp_time,
1255 "discontinuity", G_TYPE_INT64, discont,
1256 "synced", G_TYPE_BOOLEAN, synced,
1257 "r-squared", G_TYPE_DOUBLE, r_squared,
1258 "internal-time", GST_TYPE_CLOCK_TIME, internal_time,
1259 "external-time", GST_TYPE_CLOCK_TIME, external_time,
1260 "rate-num", G_TYPE_UINT64, rate_num,
1261 "rate-den", G_TYPE_UINT64, rate_den,
1262 "rate", G_TYPE_DOUBLE, (gdouble) (rate_num) / rate_den,
1264 emit_ptp_statistics (domain->domain, stats);
1265 gst_structure_free (stats);
1270 #ifdef USE_MEDIAN_PRE_FILTERING
1272 compare_clock_time (const GstClockTime * a, const GstClockTime * b)
1283 update_mean_path_delay (PtpDomainData * domain, PtpPendingSync * sync)
1285 #ifdef USE_MEDIAN_PRE_FILTERING
1286 GstClockTime last_path_delays[MEDIAN_PRE_FILTERING_WINDOW];
1287 GstClockTime median;
1291 GstClockTime mean_path_delay, delay_req_delay = 0;
1294 /* IEEE 1588 11.3 */
1296 (sync->delay_req_recv_time_remote - sync->sync_send_time_remote +
1297 sync->sync_recv_time_local - sync->delay_req_send_time_local -
1298 (sync->correction_field_sync + sync->correction_field_delay +
1299 32768) / 65536) / 2;
1301 #ifdef USE_MEDIAN_PRE_FILTERING
1302 for (i = 1; i < MEDIAN_PRE_FILTERING_WINDOW; i++)
1303 domain->last_path_delays[i - 1] = domain->last_path_delays[i];
1304 domain->last_path_delays[i - 1] = mean_path_delay;
1306 if (domain->last_path_delays_missing) {
1307 domain->last_path_delays_missing--;
1309 memcpy (&last_path_delays, &domain->last_path_delays,
1310 sizeof (last_path_delays));
1311 g_qsort_with_data (&last_path_delays,
1312 MEDIAN_PRE_FILTERING_WINDOW, sizeof (GstClockTime),
1313 (GCompareDataFunc) compare_clock_time, NULL);
1315 median = last_path_delays[MEDIAN_PRE_FILTERING_WINDOW / 2];
1317 /* FIXME: We might want to use something else here, like only allowing
1318 * things in the interquartile range, or also filtering away delays that
1319 * are too small compared to the median. This here worked well enough
1322 if (mean_path_delay > 2 * median) {
1323 GST_WARNING ("Path delay for domain %u too big compared to median: %"
1324 GST_TIME_FORMAT " > 2 * %" GST_TIME_FORMAT, domain->domain,
1325 GST_TIME_ARGS (mean_path_delay), GST_TIME_ARGS (median));
1332 #ifdef USE_RUNNING_AVERAGE_DELAY
1333 /* Track an average round trip time, for a bit of smoothing */
1334 /* Always update before discarding a sample, so genuine changes in
1335 * the network get picked up, eventually */
1336 if (domain->mean_path_delay == 0)
1337 domain->mean_path_delay = mean_path_delay;
1338 else if (mean_path_delay < domain->mean_path_delay) /* Shorter RTTs carry more weight than longer */
1339 domain->mean_path_delay =
1340 (3 * domain->mean_path_delay + mean_path_delay) / 4;
1342 domain->mean_path_delay =
1343 (15 * domain->mean_path_delay + mean_path_delay) / 16;
1345 domain->mean_path_delay = mean_path_delay;
1348 #ifdef USE_MEASUREMENT_FILTERING
1349 if (sync->follow_up_recv_time_local != GST_CLOCK_TIME_NONE &&
1350 domain->mean_path_delay != 0
1351 && sync->follow_up_recv_time_local >
1352 sync->sync_recv_time_local + 2 * domain->mean_path_delay) {
1353 GST_WARNING ("Sync-follow-up delay for domain %u too big: %" GST_TIME_FORMAT
1354 " > 2 * %" GST_TIME_FORMAT, domain->domain,
1355 GST_TIME_ARGS (sync->follow_up_recv_time_local -
1356 sync->sync_recv_time_local),
1357 GST_TIME_ARGS (domain->mean_path_delay));
1362 if (mean_path_delay > 2 * domain->mean_path_delay) {
1363 GST_WARNING ("Mean path delay for domain %u too big: %" GST_TIME_FORMAT
1364 " > 2 * %" GST_TIME_FORMAT, domain->domain,
1365 GST_TIME_ARGS (mean_path_delay),
1366 GST_TIME_ARGS (domain->mean_path_delay));
1373 sync->delay_resp_recv_time_local - sync->delay_req_send_time_local;
1375 #ifdef USE_MEASUREMENT_FILTERING
1376 /* delay_req_delay is a RTT, so 2 times the path delay */
1377 if (delay_req_delay > 4 * domain->mean_path_delay) {
1378 GST_WARNING ("Delay-request-response delay for domain %u too big: %"
1379 GST_TIME_FORMAT " > 4 * %" GST_TIME_FORMAT, domain->domain,
1380 GST_TIME_ARGS (delay_req_delay),
1381 GST_TIME_ARGS (domain->mean_path_delay));
1389 GST_DEBUG ("Got mean path delay for domain %u: %" GST_TIME_FORMAT " (new: %"
1390 GST_TIME_FORMAT ")", domain->domain,
1391 GST_TIME_ARGS (domain->mean_path_delay), GST_TIME_ARGS (mean_path_delay));
1392 GST_DEBUG ("Delay request delay for domain %u: %" GST_TIME_FORMAT,
1393 domain->domain, GST_TIME_ARGS (delay_req_delay));
1395 #ifdef USE_MEASUREMENT_FILTERING
1398 if (g_atomic_int_get (&domain_stats_n_hooks)) {
1399 GstStructure *stats =
1400 gst_structure_new (GST_PTP_STATISTICS_PATH_DELAY_MEASURED,
1401 "domain", G_TYPE_UINT, domain->domain,
1402 "mean-path-delay-avg", GST_TYPE_CLOCK_TIME, domain->mean_path_delay,
1403 "mean-path-delay", GST_TYPE_CLOCK_TIME, mean_path_delay,
1404 "delay-request-delay", GST_TYPE_CLOCK_TIME, delay_req_delay, NULL);
1405 emit_ptp_statistics (domain->domain, stats);
1406 gst_structure_free (stats);
1413 handle_sync_message (PtpMessage * msg, GstClockTime receive_time)
1416 PtpDomainData *domain = NULL;
1417 PtpPendingSync *sync = NULL;
1419 /* Don't consider messages with the alternate master flag set */
1420 if ((msg->flag_field & 0x0100))
1423 for (l = domain_data; l; l = l->next) {
1424 PtpDomainData *tmp = l->data;
1426 if (msg->domain_number == tmp->domain) {
1435 domain = g_new0 (PtpDomainData, 1);
1436 domain->domain = msg->domain_number;
1437 clock_name = g_strdup_printf ("ptp-clock-%u", domain->domain);
1438 domain->domain_clock =
1439 g_object_new (GST_TYPE_SYSTEM_CLOCK, "name", clock_name, NULL);
1440 g_free (clock_name);
1441 g_queue_init (&domain->pending_syncs);
1442 domain->last_path_delays_missing = 9;
1443 domain_data = g_list_prepend (domain_data, domain);
1445 g_mutex_lock (&domain_clocks_lock);
1446 domain_clocks = g_list_prepend (domain_clocks, domain);
1447 g_mutex_unlock (&domain_clocks_lock);
1450 /* If we have a master clock, ignore this message if it's not coming from there */
1451 if (domain->have_master_clock
1452 && compare_clock_identity (&domain->master_clock_identity,
1453 &msg->source_port_identity) != 0)
1456 #ifdef USE_OPPORTUNISTIC_CLOCK_SELECTION
1457 /* Opportunistic selection of master clock */
1458 if (!domain->have_master_clock)
1459 memcpy (&domain->master_clock_identity, &msg->source_port_identity,
1460 sizeof (PtpClockIdentity));
1462 if (!domain->have_master_clock)
1466 domain->sync_interval = log2_to_clock_time (msg->log_message_interval);
1468 /* Check if duplicated */
1469 for (l = domain->pending_syncs.head; l; l = l->next) {
1470 PtpPendingSync *tmp = l->data;
1472 if (tmp->sync_seqnum == msg->sequence_id)
1476 if (msg->message_specific.sync.origin_timestamp.seconds_field >
1477 GST_CLOCK_TIME_NONE / GST_SECOND) {
1478 GST_FIXME ("Unsupported sync message seconds field value: %"
1479 G_GUINT64_FORMAT " > %" G_GUINT64_FORMAT,
1480 msg->message_specific.sync.origin_timestamp.seconds_field,
1481 GST_CLOCK_TIME_NONE / GST_SECOND);
1485 sync = g_new0 (PtpPendingSync, 1);
1486 sync->domain = domain->domain;
1487 sync->sync_seqnum = msg->sequence_id;
1488 sync->sync_recv_time_local = receive_time;
1489 sync->sync_send_time_remote = GST_CLOCK_TIME_NONE;
1490 sync->follow_up_recv_time_local = GST_CLOCK_TIME_NONE;
1491 sync->delay_req_send_time_local = GST_CLOCK_TIME_NONE;
1492 sync->delay_req_recv_time_remote = GST_CLOCK_TIME_NONE;
1493 sync->delay_resp_recv_time_local = GST_CLOCK_TIME_NONE;
1495 /* 0.5 correction factor for division later */
1496 sync->correction_field_sync = msg->correction_field;
1498 if ((msg->flag_field & 0x0200)) {
1499 /* Wait for FOLLOW_UP */
1501 sync->sync_send_time_remote =
1502 PTP_TIMESTAMP_TO_GST_CLOCK_TIME (msg->message_specific.
1503 sync.origin_timestamp);
1505 if (domain->last_ptp_sync_time != 0
1506 && domain->last_ptp_sync_time >= sync->sync_send_time_remote) {
1507 GST_WARNING ("Backwards PTP times in domain %u: %" GST_TIME_FORMAT " >= %"
1508 GST_TIME_FORMAT, domain->domain,
1509 GST_TIME_ARGS (domain->last_ptp_sync_time),
1510 GST_TIME_ARGS (sync->sync_send_time_remote));
1511 ptp_pending_sync_free (sync);
1515 domain->last_ptp_sync_time = sync->sync_send_time_remote;
1517 if (send_delay_req (domain, sync)) {
1518 /* Sent delay request */
1520 update_ptp_time (domain, sync);
1521 ptp_pending_sync_free (sync);
1527 g_queue_push_tail (&domain->pending_syncs, sync);
1531 handle_follow_up_message (PtpMessage * msg, GstClockTime receive_time)
1534 PtpDomainData *domain = NULL;
1535 PtpPendingSync *sync = NULL;
1537 /* Don't consider messages with the alternate master flag set */
1538 if ((msg->flag_field & 0x0100))
1541 for (l = domain_data; l; l = l->next) {
1542 PtpDomainData *tmp = l->data;
1544 if (msg->domain_number == tmp->domain) {
1553 /* If we have a master clock, ignore this message if it's not coming from there */
1554 if (domain->have_master_clock
1555 && compare_clock_identity (&domain->master_clock_identity,
1556 &msg->source_port_identity) != 0)
1559 /* Check if we know about this one */
1560 for (l = domain->pending_syncs.head; l; l = l->next) {
1561 PtpPendingSync *tmp = l->data;
1563 if (tmp->sync_seqnum == msg->sequence_id) {
1572 /* Got a FOLLOW_UP for this already */
1573 if (sync->sync_send_time_remote != GST_CLOCK_TIME_NONE)
1576 if (sync->sync_recv_time_local >= receive_time) {
1577 GST_ERROR ("Got bogus follow up in domain %u: %" GST_TIME_FORMAT " > %"
1578 GST_TIME_FORMAT, domain->domain,
1579 GST_TIME_ARGS (sync->sync_recv_time_local),
1580 GST_TIME_ARGS (receive_time));
1581 g_queue_remove (&domain->pending_syncs, sync);
1582 ptp_pending_sync_free (sync);
1586 sync->correction_field_sync += msg->correction_field;
1587 sync->sync_send_time_remote =
1588 PTP_TIMESTAMP_TO_GST_CLOCK_TIME (msg->message_specific.
1589 follow_up.precise_origin_timestamp);
1590 sync->follow_up_recv_time_local = receive_time;
1592 if (domain->last_ptp_sync_time >= sync->sync_send_time_remote) {
1593 GST_WARNING ("Backwards PTP times in domain %u: %" GST_TIME_FORMAT " >= %"
1594 GST_TIME_FORMAT, domain->domain,
1595 GST_TIME_ARGS (domain->last_ptp_sync_time),
1596 GST_TIME_ARGS (sync->sync_send_time_remote));
1597 g_queue_remove (&domain->pending_syncs, sync);
1598 ptp_pending_sync_free (sync);
1602 domain->last_ptp_sync_time = sync->sync_send_time_remote;
1604 if (send_delay_req (domain, sync)) {
1605 /* Sent delay request */
1607 update_ptp_time (domain, sync);
1608 g_queue_remove (&domain->pending_syncs, sync);
1609 ptp_pending_sync_free (sync);
1615 handle_delay_resp_message (PtpMessage * msg, GstClockTime receive_time)
1618 PtpDomainData *domain = NULL;
1619 PtpPendingSync *sync = NULL;
1621 /* Don't consider messages with the alternate master flag set */
1622 if ((msg->flag_field & 0x0100))
1625 for (l = domain_data; l; l = l->next) {
1626 PtpDomainData *tmp = l->data;
1628 if (msg->domain_number == tmp->domain) {
1637 /* If we have a master clock, ignore this message if it's not coming from there */
1638 if (domain->have_master_clock
1639 && compare_clock_identity (&domain->master_clock_identity,
1640 &msg->source_port_identity) != 0)
1644 if (msg->message_specific.delay_resp.
1645 requesting_port_identity.clock_identity != ptp_clock_id.clock_identity
1646 || msg->message_specific.delay_resp.
1647 requesting_port_identity.port_number != ptp_clock_id.port_number)
1650 domain->min_delay_req_interval =
1651 log2_to_clock_time (msg->log_message_interval);
1653 /* Check if we know about this one */
1654 for (l = domain->pending_syncs.head; l; l = l->next) {
1655 PtpPendingSync *tmp = l->data;
1657 if (tmp->delay_req_seqnum == msg->sequence_id) {
1666 /* Got a DELAY_RESP for this already */
1667 if (sync->delay_req_recv_time_remote != GST_CLOCK_TIME_NONE)
1670 if (sync->delay_req_send_time_local > receive_time) {
1671 GST_ERROR ("Got bogus delay response in domain %u: %" GST_TIME_FORMAT " > %"
1672 GST_TIME_FORMAT, domain->domain,
1673 GST_TIME_ARGS (sync->delay_req_send_time_local),
1674 GST_TIME_ARGS (receive_time));
1675 g_queue_remove (&domain->pending_syncs, sync);
1676 ptp_pending_sync_free (sync);
1680 sync->correction_field_delay = msg->correction_field;
1682 sync->delay_req_recv_time_remote =
1683 PTP_TIMESTAMP_TO_GST_CLOCK_TIME (msg->message_specific.
1684 delay_resp.receive_timestamp);
1685 sync->delay_resp_recv_time_local = receive_time;
1687 if (domain->mean_path_delay != 0
1688 && sync->sync_send_time_remote > sync->delay_req_recv_time_remote) {
1689 GST_WARNING ("Sync send time after delay req receive time for domain %u: %"
1690 GST_TIME_FORMAT " > %" GST_TIME_FORMAT, domain->domain,
1691 GST_TIME_ARGS (sync->sync_send_time_remote),
1692 GST_TIME_ARGS (sync->delay_req_recv_time_remote));
1693 g_queue_remove (&domain->pending_syncs, sync);
1694 ptp_pending_sync_free (sync);
1698 if (update_mean_path_delay (domain, sync))
1699 update_ptp_time (domain, sync);
1700 g_queue_remove (&domain->pending_syncs, sync);
1701 ptp_pending_sync_free (sync);
1705 handle_ptp_message (PtpMessage * msg, GstClockTime receive_time)
1707 /* Ignore our own messages */
1708 if (msg->source_port_identity.clock_identity == ptp_clock_id.clock_identity &&
1709 msg->source_port_identity.port_number == ptp_clock_id.port_number)
1712 switch (msg->message_type) {
1713 case PTP_MESSAGE_TYPE_ANNOUNCE:
1714 handle_announce_message (msg, receive_time);
1716 case PTP_MESSAGE_TYPE_SYNC:
1717 handle_sync_message (msg, receive_time);
1719 case PTP_MESSAGE_TYPE_FOLLOW_UP:
1720 handle_follow_up_message (msg, receive_time);
1722 case PTP_MESSAGE_TYPE_DELAY_RESP:
1723 handle_delay_resp_message (msg, receive_time);
1731 have_stdin_data_cb (GIOChannel * channel, GIOCondition condition,
1740 if ((condition & G_IO_STATUS_EOF)) {
1741 GST_ERROR ("Got EOF on stdin");
1742 g_main_loop_quit (main_loop);
1743 return G_SOURCE_REMOVE;
1747 g_io_channel_read_chars (channel, (gchar *) & header, sizeof (header),
1749 if (status == G_IO_STATUS_ERROR) {
1750 GST_ERROR ("Failed to read from stdin: %s", err->message);
1751 g_main_loop_quit (main_loop);
1752 return G_SOURCE_REMOVE;
1753 } else if (status == G_IO_STATUS_EOF) {
1754 GST_ERROR ("Got EOF on stdin");
1755 g_main_loop_quit (main_loop);
1756 return G_SOURCE_REMOVE;
1757 } else if (status != G_IO_STATUS_NORMAL) {
1758 GST_ERROR ("Unexpected stdin read status: %d", status);
1759 g_main_loop_quit (main_loop);
1760 return G_SOURCE_REMOVE;
1761 } else if (read != sizeof (header)) {
1762 GST_ERROR ("Unexpected read size: %" G_GSIZE_FORMAT, read);
1763 g_main_loop_quit (main_loop);
1764 return G_SOURCE_REMOVE;
1765 } else if (header.size > 8192) {
1766 GST_ERROR ("Unexpected size: %u", header.size);
1767 g_main_loop_quit (main_loop);
1768 return G_SOURCE_REMOVE;
1771 status = g_io_channel_read_chars (channel, buffer, header.size, &read, &err);
1772 if (status == G_IO_STATUS_ERROR) {
1773 GST_ERROR ("Failed to read from stdin: %s", err->message);
1774 g_main_loop_quit (main_loop);
1775 return G_SOURCE_REMOVE;
1776 } else if (status == G_IO_STATUS_EOF) {
1777 GST_ERROR ("EOF on stdin");
1778 g_main_loop_quit (main_loop);
1779 return G_SOURCE_REMOVE;
1780 } else if (status != G_IO_STATUS_NORMAL) {
1781 GST_ERROR ("Unexpected stdin read status: %d", status);
1782 g_main_loop_quit (main_loop);
1783 return G_SOURCE_REMOVE;
1784 } else if (read != header.size) {
1785 GST_ERROR ("Unexpected read size: %" G_GSIZE_FORMAT, read);
1786 g_main_loop_quit (main_loop);
1787 return G_SOURCE_REMOVE;
1790 switch (header.type) {
1793 GstClockTime receive_time = gst_clock_get_time (observation_system_clock);
1796 if (parse_ptp_message (&msg, (const guint8 *) buffer, header.size)) {
1797 dump_ptp_message (&msg);
1798 handle_ptp_message (&msg, receive_time);
1803 case TYPE_CLOCK_ID:{
1804 if (header.size != 8) {
1805 GST_ERROR ("Unexpected clock id size (%u != 8)", header.size);
1806 g_main_loop_quit (main_loop);
1807 return G_SOURCE_REMOVE;
1809 g_mutex_lock (&ptp_lock);
1810 ptp_clock_id.clock_identity = GST_READ_UINT64_BE (buffer);
1811 ptp_clock_id.port_number = getpid ();
1812 GST_DEBUG ("Got clock id 0x%016" G_GINT64_MODIFIER "x %u",
1813 ptp_clock_id.clock_identity, ptp_clock_id.port_number);
1814 g_cond_signal (&ptp_cond);
1815 g_mutex_unlock (&ptp_lock);
1820 return G_SOURCE_CONTINUE;
1823 /* Cleanup all announce messages and announce message senders
1824 * that are timed out by now, and clean up all pending syncs
1825 * that are missing their FOLLOW_UP or DELAY_RESP */
1827 cleanup_cb (gpointer data)
1829 GstClockTime now = gst_clock_get_time (observation_system_clock);
1832 for (l = domain_data; l; l = l->next) {
1833 PtpDomainData *domain = l->data;
1835 for (n = domain->announce_senders; n;) {
1836 PtpAnnounceSender *sender = n->data;
1837 gboolean timed_out = TRUE;
1839 /* Keep only 5 messages per sender around */
1840 while (g_queue_get_length (&sender->announce_messages) > 5) {
1841 PtpAnnounceMessage *msg = g_queue_pop_head (&sender->announce_messages);
1845 for (m = sender->announce_messages.head; m; m = m->next) {
1846 PtpAnnounceMessage *msg = m->data;
1848 if (msg->receive_time +
1849 sender->announce_interval * PTP_ANNOUNCE_RECEIPT_TIMEOUT > now) {
1856 GST_DEBUG ("Announce sender 0x%016" G_GINT64_MODIFIER "x %u timed out",
1857 sender->master_clock_identity.clock_identity,
1858 sender->master_clock_identity.port_number);
1859 g_queue_foreach (&sender->announce_messages, (GFunc) g_free, NULL);
1860 g_queue_clear (&sender->announce_messages);
1863 if (g_queue_get_length (&sender->announce_messages) == 0) {
1864 GList *tmp = n->next;
1866 if (compare_clock_identity (&sender->master_clock_identity,
1867 &domain->master_clock_identity) == 0)
1868 GST_WARNING ("currently selected master clock timed out");
1870 domain->announce_senders =
1871 g_list_delete_link (domain->announce_senders, n);
1877 select_best_master_clock (domain, now);
1879 /* Clean up any pending syncs */
1880 for (n = domain->pending_syncs.head; n;) {
1881 PtpPendingSync *sync = n->data;
1882 gboolean timed_out = FALSE;
1884 /* Time out pending syncs after 4 sync intervals or 10 seconds,
1885 * and pending delay reqs after 4 delay req intervals or 10 seconds
1887 if (sync->delay_req_send_time_local != GST_CLOCK_TIME_NONE &&
1888 ((domain->min_delay_req_interval != 0
1889 && sync->delay_req_send_time_local +
1890 4 * domain->min_delay_req_interval < now)
1891 || (sync->delay_req_send_time_local + 10 * GST_SECOND < now))) {
1893 } else if ((domain->sync_interval != 0
1894 && sync->sync_recv_time_local + 4 * domain->sync_interval < now)
1895 || (sync->sync_recv_time_local + 10 * GST_SECOND < now)) {
1900 GList *tmp = n->next;
1901 ptp_pending_sync_free (sync);
1902 g_queue_delete_link (&domain->pending_syncs, n);
1910 return G_SOURCE_CONTINUE;
1914 ptp_helper_main (gpointer data)
1916 GSource *cleanup_source;
1918 GST_DEBUG ("Starting PTP helper loop");
1920 /* Check all 5 seconds, if we have to cleanup ANNOUNCE or pending syncs message */
1921 cleanup_source = g_timeout_source_new_seconds (5);
1922 g_source_set_priority (cleanup_source, G_PRIORITY_DEFAULT);
1923 g_source_set_callback (cleanup_source, (GSourceFunc) cleanup_cb, NULL, NULL);
1924 g_source_attach (cleanup_source, main_context);
1925 g_source_unref (cleanup_source);
1927 g_main_loop_run (main_loop);
1928 GST_DEBUG ("Stopped PTP helper loop");
1930 g_mutex_lock (&ptp_lock);
1931 ptp_clock_id.clock_identity = GST_PTP_CLOCK_ID_NONE;
1932 ptp_clock_id.port_number = 0;
1934 g_cond_signal (&ptp_cond);
1935 g_mutex_unlock (&ptp_lock);
1941 * gst_ptp_is_supported:
1943 * Check if PTP clocks are generally supported on this system, and if previous
1944 * initializations did not fail.
1946 * Returns: %TRUE if PTP clocks are generally supported on this system, and
1947 * previous initializations did not fail.
1952 gst_ptp_is_supported (void)
1958 * gst_ptp_is_initialized:
1960 * Check if the GStreamer PTP clock subsystem is initialized.
1962 * Returns: %TRUE if the GStreamer PTP clock subsystem is intialized.
1967 gst_ptp_is_initialized (void)
1974 * @clock_id: PTP clock id of this process' clock or %GST_PTP_CLOCK_ID_NONE
1975 * @interfaces: (transfer none) (array zero-terminated=1) (allow-none): network interfaces to run the clock on
1977 * Initialize the GStreamer PTP subsystem and create a PTP ordinary clock in
1978 * slave-only mode for all domains on the given @interfaces with the
1981 * If @clock_id is %GST_PTP_CLOCK_ID_NONE, a clock id is automatically
1982 * generated from the MAC address of the first network interface.
1985 * This function is automatically called by gst_ptp_clock_new() with default
1986 * parameters if it wasn't called before.
1988 * Returns: %TRUE if the GStreamer PTP clock subsystem could be initialized.
1993 gst_ptp_init (guint64 clock_id, gchar ** interfaces)
1997 gchar **argv = NULL;
2001 GSource *stdin_source;
2003 GST_DEBUG_CATEGORY_INIT (ptp_debug, "ptp", 0, "PTP clock");
2005 g_mutex_lock (&ptp_lock);
2007 GST_ERROR ("PTP not supported");
2013 GST_DEBUG ("PTP already initialized");
2018 if (ptp_helper_pid) {
2019 GST_DEBUG ("PTP currently initializing");
2023 if (!domain_stats_hooks_initted) {
2024 g_hook_list_init (&domain_stats_hooks, sizeof (GHook));
2025 domain_stats_hooks_initted = TRUE;
2029 if (clock_id != GST_PTP_CLOCK_ID_NONE)
2031 if (interfaces != NULL)
2032 argc += 2 * g_strv_length (interfaces);
2034 argv = g_new0 (gchar *, argc + 2);
2037 env = g_getenv ("GST_PTP_HELPER_1_0");
2039 env = g_getenv ("GST_PTP_HELPER");
2040 if (env != NULL && *env != '\0') {
2041 GST_LOG ("Trying GST_PTP_HELPER env var: %s", env);
2042 argv[argc_c++] = g_strdup (env);
2044 argv[argc_c++] = g_strdup (GST_PTP_HELPER_INSTALLED);
2047 if (clock_id != GST_PTP_CLOCK_ID_NONE) {
2048 argv[argc_c++] = g_strdup ("-c");
2049 argv[argc_c++] = g_strdup_printf ("0x%016" G_GINT64_MODIFIER "x", clock_id);
2052 if (interfaces != NULL) {
2053 gchar **ptr = interfaces;
2056 argv[argc_c++] = g_strdup ("-i");
2057 argv[argc_c++] = g_strdup (*ptr);
2062 main_context = g_main_context_new ();
2063 main_loop = g_main_loop_new (main_context, FALSE);
2066 g_thread_try_new ("ptp-helper-thread", ptp_helper_main, NULL, &err);
2067 if (!ptp_helper_thread) {
2068 GST_ERROR ("Failed to start PTP helper thread: %s", err->message);
2069 g_clear_error (&err);
2074 if (!g_spawn_async_with_pipes (NULL, argv, NULL, 0, NULL, NULL,
2075 &ptp_helper_pid, &fd_w, &fd_r, NULL, &err)) {
2076 GST_ERROR ("Failed to start ptp helper process: %s", err->message);
2077 g_clear_error (&err);
2083 stdin_channel = g_io_channel_unix_new (fd_r);
2084 g_io_channel_set_encoding (stdin_channel, NULL, NULL);
2085 g_io_channel_set_buffered (stdin_channel, FALSE);
2086 g_io_channel_set_close_on_unref (stdin_channel, TRUE);
2088 g_io_create_watch (stdin_channel, G_IO_IN | G_IO_PRI | G_IO_HUP);
2089 g_source_set_priority (stdin_source, G_PRIORITY_DEFAULT);
2090 g_source_set_callback (stdin_source, (GSourceFunc) have_stdin_data_cb, NULL,
2092 g_source_attach (stdin_source, main_context);
2093 g_source_unref (stdin_source);
2095 /* Create stdout channel */
2096 stdout_channel = g_io_channel_unix_new (fd_w);
2097 g_io_channel_set_encoding (stdout_channel, NULL, NULL);
2098 g_io_channel_set_close_on_unref (stdout_channel, TRUE);
2099 g_io_channel_set_buffered (stdout_channel, FALSE);
2101 delay_req_rand = g_rand_new ();
2102 observation_system_clock =
2103 g_object_new (GST_TYPE_SYSTEM_CLOCK, "name", "ptp-observation-clock",
2109 GST_DEBUG ("Waiting for PTP to be initialized");
2111 while (ptp_clock_id.clock_identity == GST_PTP_CLOCK_ID_NONE && initted)
2112 g_cond_wait (&ptp_cond, &ptp_lock);
2116 GST_DEBUG ("Initialized and got clock id 0x%016" G_GINT64_MODIFIER "x %u",
2117 ptp_clock_id.clock_identity, ptp_clock_id.port_number);
2119 GST_ERROR ("Failed to initialize");
2127 if (ptp_helper_pid) {
2129 kill (ptp_helper_pid, SIGKILL);
2130 waitpid (ptp_helper_pid, NULL, 0);
2132 TerminateProcess (ptp_helper_pid, 1);
2133 WaitForSingleObject (ptp_helper_pid, INFINITE);
2135 g_spawn_close_pid (ptp_helper_pid);
2140 g_io_channel_unref (stdin_channel);
2141 stdin_channel = NULL;
2143 g_io_channel_unref (stdout_channel);
2144 stdout_channel = NULL;
2146 if (main_loop && ptp_helper_thread) {
2147 g_main_loop_quit (main_loop);
2148 g_thread_join (ptp_helper_thread);
2150 ptp_helper_thread = NULL;
2152 g_main_loop_unref (main_loop);
2155 g_main_context_unref (main_context);
2156 main_context = NULL;
2159 g_rand_free (delay_req_rand);
2160 delay_req_rand = NULL;
2162 if (observation_system_clock)
2163 gst_object_unref (observation_system_clock);
2164 observation_system_clock = NULL;
2167 g_mutex_unlock (&ptp_lock);
2175 * Deinitialize the GStreamer PTP subsystem and stop the PTP clock. If there
2176 * are any remaining GstPtpClock instances, they won't be further synchronized
2177 * to the PTP network clock.
2182 gst_ptp_deinit (void)
2186 g_mutex_lock (&ptp_lock);
2188 if (ptp_helper_pid) {
2190 kill (ptp_helper_pid, SIGKILL);
2191 waitpid (ptp_helper_pid, NULL, 0);
2193 TerminateProcess (ptp_helper_pid, 1);
2194 WaitForSingleObject (ptp_helper_pid, INFINITE);
2196 g_spawn_close_pid (ptp_helper_pid);
2201 g_io_channel_unref (stdin_channel);
2202 stdin_channel = NULL;
2204 g_io_channel_unref (stdout_channel);
2205 stdout_channel = NULL;
2207 if (main_loop && ptp_helper_thread) {
2208 GThread *tmp = ptp_helper_thread;
2209 ptp_helper_thread = NULL;
2210 g_mutex_unlock (&ptp_lock);
2211 g_main_loop_quit (main_loop);
2212 g_thread_join (tmp);
2213 g_mutex_lock (&ptp_lock);
2216 g_main_loop_unref (main_loop);
2219 g_main_context_unref (main_context);
2220 main_context = NULL;
2223 g_rand_free (delay_req_rand);
2224 delay_req_rand = NULL;
2225 if (observation_system_clock)
2226 gst_object_unref (observation_system_clock);
2227 observation_system_clock = NULL;
2229 for (l = domain_data; l; l = l->next) {
2230 PtpDomainData *domain = l->data;
2232 for (m = domain->announce_senders; m; m = m->next) {
2233 PtpAnnounceSender *sender = m->data;
2235 g_queue_foreach (&sender->announce_messages, (GFunc) g_free, NULL);
2236 g_queue_clear (&sender->announce_messages);
2239 g_list_free (domain->announce_senders);
2241 g_queue_foreach (&domain->pending_syncs, (GFunc) ptp_pending_sync_free,
2243 g_queue_clear (&domain->pending_syncs);
2244 gst_object_unref (domain->domain_clock);
2247 g_list_free (domain_data);
2249 g_list_foreach (domain_clocks, (GFunc) g_free, NULL);
2250 g_list_free (domain_clocks);
2251 domain_clocks = NULL;
2253 ptp_clock_id.clock_identity = GST_PTP_CLOCK_ID_NONE;
2254 ptp_clock_id.port_number = 0;
2258 g_mutex_unlock (&ptp_lock);
2261 #define DEFAULT_DOMAIN 0
2270 #define GST_PTP_CLOCK_GET_PRIVATE(obj) \
2271 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_PTP_CLOCK, GstPtpClockPrivate))
2273 struct _GstPtpClockPrivate
2276 GstClock *domain_clock;
2277 gulong domain_stats_id;
2280 #define gst_ptp_clock_parent_class parent_class
2281 G_DEFINE_TYPE (GstPtpClock, gst_ptp_clock, GST_TYPE_SYSTEM_CLOCK);
2283 static void gst_ptp_clock_set_property (GObject * object, guint prop_id,
2284 const GValue * value, GParamSpec * pspec);
2285 static void gst_ptp_clock_get_property (GObject * object, guint prop_id,
2286 GValue * value, GParamSpec * pspec);
2287 static void gst_ptp_clock_finalize (GObject * object);
2289 static GstClockTime gst_ptp_clock_get_internal_time (GstClock * clock);
2292 gst_ptp_clock_class_init (GstPtpClockClass * klass)
2294 GObjectClass *gobject_class;
2295 GstClockClass *clock_class;
2297 gobject_class = G_OBJECT_CLASS (klass);
2298 clock_class = GST_CLOCK_CLASS (klass);
2300 g_type_class_add_private (klass, sizeof (GstPtpClockPrivate));
2302 gobject_class->finalize = gst_ptp_clock_finalize;
2303 gobject_class->get_property = gst_ptp_clock_get_property;
2304 gobject_class->set_property = gst_ptp_clock_set_property;
2306 g_object_class_install_property (gobject_class, PROP_DOMAIN,
2307 g_param_spec_uint ("domain", "Domain",
2308 "The PTP domain", 0, G_MAXUINT8,
2310 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
2312 g_object_class_install_property (gobject_class, PROP_INTERNAL_CLOCK,
2313 g_param_spec_object ("internal-clock", "Internal Clock",
2314 "Internal clock", GST_TYPE_CLOCK,
2315 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
2317 clock_class->get_internal_time = gst_ptp_clock_get_internal_time;
2321 gst_ptp_clock_init (GstPtpClock * self)
2323 GstPtpClockPrivate *priv;
2325 self->priv = priv = GST_PTP_CLOCK_GET_PRIVATE (self);
2327 GST_OBJECT_FLAG_SET (self, GST_CLOCK_FLAG_CAN_SET_MASTER);
2328 GST_OBJECT_FLAG_SET (self, GST_CLOCK_FLAG_NEEDS_STARTUP_SYNC);
2330 priv->domain = DEFAULT_DOMAIN;
2334 gst_ptp_clock_ensure_domain_clock (GstPtpClock * self)
2336 gboolean got_clock = TRUE;
2338 if (G_UNLIKELY (!self->priv->domain_clock)) {
2339 g_mutex_lock (&domain_clocks_lock);
2340 if (!self->priv->domain_clock) {
2345 for (l = domain_clocks; l; l = l->next) {
2346 PtpDomainData *clock_data = l->data;
2348 if (clock_data->domain == self->priv->domain
2349 && clock_data->last_ptp_time != 0) {
2350 self->priv->domain_clock = clock_data->domain_clock;
2356 g_mutex_unlock (&domain_clocks_lock);
2358 g_object_notify (G_OBJECT (self), "internal-clock");
2359 gst_clock_set_synced (GST_CLOCK (self), TRUE);
2367 gst_ptp_clock_stats_callback (guint8 domain, const GstStructure * stats,
2370 GstPtpClock *self = user_data;
2372 if (domain != self->priv->domain
2373 || !gst_structure_has_name (stats, GST_PTP_STATISTICS_TIME_UPDATED))
2376 /* Let's set our internal clock */
2377 if (!gst_ptp_clock_ensure_domain_clock (self))
2380 self->priv->domain_stats_id = 0;
2386 gst_ptp_clock_set_property (GObject * object, guint prop_id,
2387 const GValue * value, GParamSpec * pspec)
2389 GstPtpClock *self = GST_PTP_CLOCK (object);
2393 self->priv->domain = g_value_get_uint (value);
2394 gst_ptp_clock_ensure_domain_clock (self);
2395 if (!self->priv->domain_clock)
2396 self->priv->domain_stats_id =
2397 gst_ptp_statistics_callback_add (gst_ptp_clock_stats_callback, self,
2401 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2407 gst_ptp_clock_get_property (GObject * object, guint prop_id,
2408 GValue * value, GParamSpec * pspec)
2410 GstPtpClock *self = GST_PTP_CLOCK (object);
2414 g_value_set_uint (value, self->priv->domain);
2416 case PROP_INTERNAL_CLOCK:
2417 gst_ptp_clock_ensure_domain_clock (self);
2418 g_value_set_object (value, self->priv->domain_clock);
2421 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2427 gst_ptp_clock_finalize (GObject * object)
2429 GstPtpClock *self = GST_PTP_CLOCK (object);
2431 if (self->priv->domain_stats_id)
2432 gst_ptp_statistics_callback_remove (self->priv->domain_stats_id);
2434 G_OBJECT_CLASS (gst_ptp_clock_parent_class)->finalize (object);
2438 gst_ptp_clock_get_internal_time (GstClock * clock)
2440 GstPtpClock *self = GST_PTP_CLOCK (clock);
2442 gst_ptp_clock_ensure_domain_clock (self);
2444 if (!self->priv->domain_clock) {
2445 GST_ERROR_OBJECT (self, "Domain %u has no clock yet and is not synced",
2446 self->priv->domain);
2447 return GST_CLOCK_TIME_NONE;
2450 return gst_clock_get_time (self->priv->domain_clock);
2454 * gst_ptp_clock_new:
2455 * @name: Name of the clock
2456 * @domain: PTP domain
2458 * Creates a new PTP clock instance that exports the PTP time of the master
2459 * clock in @domain. This clock can be slaved to other clocks as needed.
2461 * If gst_ptp_init() was not called before, this will call gst_ptp_init() with
2462 * default parameters.
2465 * This clock only returns valid timestamps after it received the first
2466 * times from the PTP master clock on the network. Once this happens the
2467 * GstPtpClock::internal-clock property will become non-NULL. You can
2468 * check this with gst_clock_wait_for_sync(), the GstClock::synced signal and
2469 * gst_clock_is_synced().
2474 gst_ptp_clock_new (const gchar * name, guint domain)
2476 g_return_val_if_fail (name != NULL, NULL);
2477 g_return_val_if_fail (domain <= G_MAXUINT8, NULL);
2479 if (!initted && !gst_ptp_init (GST_PTP_CLOCK_ID_NONE, NULL)) {
2480 GST_ERROR ("Failed to initialize PTP");
2484 return g_object_new (GST_TYPE_PTP_CLOCK, "name", name, "domain", domain,
2491 const GstStructure *stats;
2492 } DomainStatsMarshalData;
2495 domain_stats_marshaller (GHook * hook, DomainStatsMarshalData * data)
2497 GstPtpStatisticsCallback callback = (GstPtpStatisticsCallback) hook->func;
2499 if (!callback (data->domain, data->stats, hook->data))
2500 g_hook_destroy (&domain_stats_hooks, hook->hook_id);
2504 emit_ptp_statistics (guint8 domain, const GstStructure * stats)
2506 DomainStatsMarshalData data = { domain, stats };
2508 g_mutex_lock (&ptp_lock);
2509 g_hook_list_marshal (&domain_stats_hooks, TRUE,
2510 (GHookMarshaller) domain_stats_marshaller, &data);
2511 g_mutex_unlock (&ptp_lock);
2515 * gst_ptp_statistics_callback_add:
2516 * @callback: GstPtpStatisticsCallback to call
2517 * @user_data: Data to pass to the callback
2518 * @destroy_data: GDestroyNotify to destroy the data
2520 * Installs a new statistics callback for gathering PTP statistics. See
2521 * GstPtpStatisticsCallback for a list of statistics that are provided.
2523 * Returns: Id for the callback that can be passed to
2524 * gst_ptp_statistics_callback_remove()
2529 gst_ptp_statistics_callback_add (GstPtpStatisticsCallback callback,
2530 gpointer user_data, GDestroyNotify destroy_data)
2534 g_mutex_lock (&ptp_lock);
2536 if (!domain_stats_hooks_initted) {
2537 g_hook_list_init (&domain_stats_hooks, sizeof (GHook));
2538 domain_stats_hooks_initted = TRUE;
2541 hook = g_hook_alloc (&domain_stats_hooks);
2542 hook->func = callback;
2543 hook->data = user_data;
2544 hook->destroy = destroy_data;
2545 g_hook_prepend (&domain_stats_hooks, hook);
2546 g_atomic_int_add (&domain_stats_n_hooks, 1);
2548 g_mutex_unlock (&ptp_lock);
2550 return hook->hook_id;
2554 * gst_ptp_statistics_callback_remove:
2555 * @id: Callback id to remove
2557 * Removes a PTP statistics callback that was previously added with
2558 * gst_ptp_statistics_callback_add().
2563 gst_ptp_statistics_callback_remove (gulong id)
2565 g_mutex_lock (&ptp_lock);
2566 if (g_hook_destroy (&domain_stats_hooks, id))
2567 g_atomic_int_add (&domain_stats_n_hooks, -1);
2568 g_mutex_unlock (&ptp_lock);