]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/gstreamer0-10.git/blob - gst/gstclock.c
gststructure: early out when we know a value cannot be a subset
[glsdk/gstreamer0-10.git] / gst / gstclock.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *                    2004 Wim Taymans <wim@fluendo.com>
5  *
6  * gstclock.c: Clock subsystem for maintaining time sync
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
24 /**
25  * SECTION:gstclock
26  * @short_description: Abstract class for global clocks
27  * @see_also: #GstSystemClock, #GstPipeline
28  *
29  * GStreamer uses a global clock to synchronize the plugins in a pipeline.
30  * Different clock implementations are possible by implementing this abstract
31  * base class or, more conveniently, by subclassing #GstSystemClock.
32  *
33  * The #GstClock returns a monotonically increasing time with the method
34  * gst_clock_get_time(). Its accuracy and base time depend on the specific
35  * clock implementation but time is always expressed in nanoseconds. Since the
36  * baseline of the clock is undefined, the clock time returned is not
37  * meaningful in itself, what matters are the deltas between two clock times.
38  * The time returned by a clock is called the absolute time.
39  *
40  * The pipeline uses the clock to calculate the running time. Usually all
41  * renderers synchronize to the global clock using the buffer timestamps, the
42  * newsegment events and the element's base time, see #GstPipeline.
43  *
44  * A clock implementation can support periodic and single shot clock
45  * notifications both synchronous and asynchronous.
46  *
47  * One first needs to create a #GstClockID for the periodic or single shot
48  * notification using gst_clock_new_single_shot_id() or
49  * gst_clock_new_periodic_id().
50  *
51  * To perform a blocking wait for the specific time of the #GstClockID use the
52  * gst_clock_id_wait(). To receive a callback when the specific time is reached
53  * in the clock use gst_clock_id_wait_async(). Both these calls can be
54  * interrupted with the gst_clock_id_unschedule() call. If the blocking wait is
55  * unscheduled a return value of #GST_CLOCK_UNSCHEDULED is returned.
56  *
57  * Periodic callbacks scheduled async will be repeatedly called automatically
58  * until it is unscheduled. To schedule a sync periodic callback,
59  * gst_clock_id_wait() should be called repeatedly.
60  *
61  * The async callbacks can happen from any thread, either provided by the core
62  * or from a streaming thread. The application should be prepared for this.
63  *
64  * A #GstClockID that has been unscheduled cannot be used again for any wait
65  * operation, a new #GstClockID should be created and the old unscheduled one
66  * should be destroyed with gst_clock_id_unref().
67  *
68  * It is possible to perform a blocking wait on the same #GstClockID from
69  * multiple threads. However, registering the same #GstClockID for multiple
70  * async notifications is not possible, the callback will only be called for
71  * the thread registering the entry last.
72  *
73  * None of the wait operations unref the #GstClockID, the owner is responsible
74  * for unreffing the ids itself. This holds for both periodic and single shot
75  * notifications. The reason being that the owner of the #GstClockID has to
76  * keep a handle to the #GstClockID to unblock the wait on FLUSHING events or
77  * state changes and if the entry would be unreffed automatically, the handle 
78  * might become invalid without any notification.
79  *
80  * These clock operations do not operate on the running time, so the callbacks
81  * will also occur when not in PLAYING state as if the clock just keeps on
82  * running. Some clocks however do not progress when the element that provided
83  * the clock is not PLAYING.
84  *
85  * When a clock has the #GST_CLOCK_FLAG_CAN_SET_MASTER flag set, it can be
86  * slaved to another #GstClock with the gst_clock_set_master(). The clock will
87  * then automatically be synchronized to this master clock by repeatedly
88  * sampling the master clock and the slave clock and recalibrating the slave
89  * clock with gst_clock_set_calibration(). This feature is mostly useful for
90  * plugins that have an internal clock but must operate with another clock
91  * selected by the #GstPipeline.  They can track the offset and rate difference
92  * of their internal clock relative to the master clock by using the
93  * gst_clock_get_calibration() function. 
94  *
95  * The master/slave synchronisation can be tuned with the #GstClock:timeout,
96  * #GstClock:window-size and #GstClock:window-threshold properties.
97  * The #GstClock:timeout property defines the interval to sample the master
98  * clock and run the calibration functions. #GstClock:window-size defines the
99  * number of samples to use when calibrating and #GstClock:window-threshold
100  * defines the minimum number of samples before the calibration is performed.
101  *
102  * Last reviewed on 2009-05-21 (0.10.24)
103  */
106 #include "gst_private.h"
107 #include <time.h>
109 #include "gstclock.h"
110 #include "gstinfo.h"
111 #include "gstutils.h"
113 #ifndef GST_DISABLE_TRACE
114 /* #define GST_WITH_ALLOC_TRACE */
115 #include "gsttrace.h"
116 static GstAllocTrace *_gst_clock_entry_trace;
117 #endif
119 /* #define DEBUGGING_ENABLED */
121 #define DEFAULT_STATS                   FALSE
122 #define DEFAULT_WINDOW_SIZE             32
123 #define DEFAULT_WINDOW_THRESHOLD        4
124 #define DEFAULT_TIMEOUT                 GST_SECOND / 10
126 enum
128   PROP_0,
129   PROP_STATS,
130   PROP_WINDOW_SIZE,
131   PROP_WINDOW_THRESHOLD,
132   PROP_TIMEOUT
133 };
135 struct _GstClockPrivate
137   gint pre_count;
138   gint post_count;
139 };
141 /* seqlocks */
142 #define read_seqbegin(clock)                                   \
143   g_atomic_int_get (&clock->ABI.priv->post_count);
145 static inline gboolean
146 read_seqretry (GstClock * clock, gint seq)
148   /* no retry if the seqnum did not change */
149   if (G_LIKELY (seq == g_atomic_int_get (&clock->ABI.priv->pre_count)))
150     return FALSE;
152   /* wait for the writer to finish and retry */
153   GST_OBJECT_LOCK (clock);
154   GST_OBJECT_UNLOCK (clock);
155   return TRUE;
158 #define write_seqlock(clock)                      \
159 G_STMT_START {                                    \
160   GST_OBJECT_LOCK (clock);                        \
161   g_atomic_int_inc (&clock->ABI.priv->pre_count);     \
162 } G_STMT_END;
164 #define write_sequnlock(clock)                    \
165 G_STMT_START {                                    \
166   g_atomic_int_inc (&clock->ABI.priv->post_count);    \
167   GST_OBJECT_UNLOCK (clock);                      \
168 } G_STMT_END;
170 static void gst_clock_dispose (GObject * object);
171 static void gst_clock_finalize (GObject * object);
173 static void gst_clock_set_property (GObject * object, guint prop_id,
174     const GValue * value, GParamSpec * pspec);
175 static void gst_clock_get_property (GObject * object, guint prop_id,
176     GValue * value, GParamSpec * pspec);
177 static void gst_clock_update_stats (GstClock * clock);
180 static GstObjectClass *parent_class = NULL;
182 /* static guint gst_clock_signals[LAST_SIGNAL] = { 0 }; */
184 static GstClockID
185 gst_clock_entry_new (GstClock * clock, GstClockTime time,
186     GstClockTime interval, GstClockEntryType type)
188   GstClockEntry *entry;
190   entry = g_slice_new (GstClockEntry);
191 #ifndef GST_DISABLE_TRACE
192   gst_alloc_trace_new (_gst_clock_entry_trace, entry);
193 #endif
194   GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock,
195       "created entry %p, time %" GST_TIME_FORMAT, entry, GST_TIME_ARGS (time));
197   entry->refcount = 1;
198   entry->clock = clock;
199   entry->type = type;
200   entry->time = time;
201   entry->interval = interval;
202   entry->status = GST_CLOCK_OK;
203   entry->func = NULL;
204   entry->user_data = NULL;
205   entry->destroy_data = NULL;
206   entry->unscheduled = FALSE;
207   entry->woken_up = FALSE;
209   return (GstClockID) entry;
212 /* WARNING : Does not modify the refcount
213  * WARNING : Do not use if a pending clock operation is happening on that entry */
214 static gboolean
215 gst_clock_entry_reinit (GstClock * clock, GstClockEntry * entry,
216     GstClockTime time, GstClockTime interval, GstClockEntryType type)
218   g_return_val_if_fail (entry->status != GST_CLOCK_BUSY, FALSE);
219   g_return_val_if_fail (entry->clock == clock, FALSE);
221   entry->type = type;
222   entry->time = time;
223   entry->interval = interval;
224   entry->status = GST_CLOCK_OK;
225   entry->unscheduled = FALSE;
226   entry->woken_up = FALSE;
228   return TRUE;
231 /**
232  * gst_clock_single_shot_id_reinit:
233  * @clock: a #GstClock
234  * @id: a #GstClockID
235  * @time: The requested time.
236  *
237  * Reinitializes the provided single shot @id to the provided time. Does not
238  * modify the reference count.
239  *
240  * Returns: %TRUE if the GstClockID could be reinitialized to the provided
241  * @time, else %FALSE.
242  *
243  * Since: 0.10.32
244  */
245 gboolean
246 gst_clock_single_shot_id_reinit (GstClock * clock, GstClockID id,
247     GstClockTime time)
249   return gst_clock_entry_reinit (clock, (GstClockEntry *) id, time,
250       GST_CLOCK_TIME_NONE, GST_CLOCK_ENTRY_SINGLE);
253 /**
254  * gst_clock_periodic_id_reinit:
255  * @clock: a #GstClock
256  * @id: a #GstClockID
257  * @start_time: the requested start time
258  * @interval: the requested interval
259  *
260  * Reinitializes the provided periodic @id to the provided start time and
261  * interval. Does not modify the reference count.
262  *
263  * Returns: %TRUE if the GstClockID could be reinitialized to the provided
264  * @time, else %FALSE.
265  *
266  * Since: 0.10.33
267  *
268  */
269 gboolean
270 gst_clock_periodic_id_reinit (GstClock * clock, GstClockID id,
271     GstClockTime start_time, GstClockTime interval)
273   return gst_clock_entry_reinit (clock, (GstClockEntry *) id, start_time,
274       interval, GST_CLOCK_ENTRY_PERIODIC);
277 /**
278  * gst_clock_id_ref:
279  * @id: The #GstClockID to ref
280  *
281  * Increase the refcount of given @id.
282  *
283  * Returns: (transfer full): The same #GstClockID with increased refcount.
284  *
285  * MT safe.
286  */
287 GstClockID
288 gst_clock_id_ref (GstClockID id)
290   g_return_val_if_fail (id != NULL, NULL);
292   g_atomic_int_inc (&((GstClockEntry *) id)->refcount);
294   return id;
297 static void
298 _gst_clock_id_free (GstClockID id)
300   GstClockEntry *entry;
301   g_return_if_fail (id != NULL);
303   GST_CAT_DEBUG (GST_CAT_CLOCK, "freed entry %p", id);
304   entry = (GstClockEntry *) id;
305   if (entry->destroy_data)
306     entry->destroy_data (entry->user_data);
308 #ifndef GST_DISABLE_TRACE
309   gst_alloc_trace_free (_gst_clock_entry_trace, id);
310 #endif
311   g_slice_free (GstClockEntry, id);
314 /**
315  * gst_clock_id_unref:
316  * @id: (transfer full): The #GstClockID to unref
317  *
318  * Unref given @id. When the refcount reaches 0 the
319  * #GstClockID will be freed.
320  *
321  * MT safe.
322  */
323 void
324 gst_clock_id_unref (GstClockID id)
326   gint zero;
328   g_return_if_fail (id != NULL);
330   zero = g_atomic_int_dec_and_test (&((GstClockEntry *) id)->refcount);
331   /* if we ended up with the refcount at zero, free the id */
332   if (zero) {
333     _gst_clock_id_free (id);
334   }
337 /**
338  * gst_clock_new_single_shot_id:
339  * @clock: The #GstClockID to get a single shot notification from
340  * @time: the requested time
341  *
342  * Get a #GstClockID from @clock to trigger a single shot
343  * notification at the requested time. The single shot id should be
344  * unreffed after usage.
345  *
346  * Free-function: gst_clock_id_unref
347  *
348  * Returns: (transfer full): a #GstClockID that can be used to request the
349  *     time notification.
350  *
351  * MT safe.
352  */
353 GstClockID
354 gst_clock_new_single_shot_id (GstClock * clock, GstClockTime time)
356   g_return_val_if_fail (GST_IS_CLOCK (clock), NULL);
358   return gst_clock_entry_new (clock,
359       time, GST_CLOCK_TIME_NONE, GST_CLOCK_ENTRY_SINGLE);
362 /**
363  * gst_clock_new_periodic_id:
364  * @clock: The #GstClockID to get a periodic notification id from
365  * @start_time: the requested start time
366  * @interval: the requested interval
367  *
368  * Get an ID from @clock to trigger a periodic notification.
369  * The periodic notifications will start at time @start_time and
370  * will then be fired with the given @interval. @id should be unreffed
371  * after usage.
372  *
373  * Free-function: gst_clock_id_unref
374  *
375  * Returns: (transfer full): a #GstClockID that can be used to request the
376  *     time notification.
377  *
378  * MT safe.
379  */
380 GstClockID
381 gst_clock_new_periodic_id (GstClock * clock, GstClockTime start_time,
382     GstClockTime interval)
384   g_return_val_if_fail (GST_IS_CLOCK (clock), NULL);
385   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (start_time), NULL);
386   g_return_val_if_fail (interval != 0, NULL);
387   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (interval), NULL);
389   return gst_clock_entry_new (clock,
390       start_time, interval, GST_CLOCK_ENTRY_PERIODIC);
393 /**
394  * gst_clock_id_compare_func
395  * @id1: A #GstClockID
396  * @id2: A #GstClockID to compare with
397  *
398  * Compares the two #GstClockID instances. This function can be used
399  * as a GCompareFunc when sorting ids.
400  *
401  * Returns: negative value if a < b; zero if a = b; positive value if a > b
402  *
403  * MT safe.
404  */
405 gint
406 gst_clock_id_compare_func (gconstpointer id1, gconstpointer id2)
408   GstClockEntry *entry1, *entry2;
410   entry1 = (GstClockEntry *) id1;
411   entry2 = (GstClockEntry *) id2;
413   if (GST_CLOCK_ENTRY_TIME (entry1) > GST_CLOCK_ENTRY_TIME (entry2)) {
414     return 1;
415   }
416   if (GST_CLOCK_ENTRY_TIME (entry1) < GST_CLOCK_ENTRY_TIME (entry2)) {
417     return -1;
418   }
419   return 0;
422 /**
423  * gst_clock_id_get_time
424  * @id: The #GstClockID to query
425  *
426  * Get the time of the clock ID
427  *
428  * Returns: the time of the given clock id.
429  *
430  * MT safe.
431  */
432 GstClockTime
433 gst_clock_id_get_time (GstClockID id)
435   g_return_val_if_fail (id != NULL, GST_CLOCK_TIME_NONE);
437   return GST_CLOCK_ENTRY_TIME ((GstClockEntry *) id);
440 /**
441  * gst_clock_id_wait
442  * @id: The #GstClockID to wait on
443  * @jitter: (out) (allow-none): a pointer that will contain the jitter,
444  *     can be %NULL.
445  *
446  * Perform a blocking wait on @id. 
447  * @id should have been created with gst_clock_new_single_shot_id()
448  * or gst_clock_new_periodic_id() and should not have been unscheduled
449  * with a call to gst_clock_id_unschedule(). 
450  *
451  * If the @jitter argument is not %NULL and this function returns #GST_CLOCK_OK
452  * or #GST_CLOCK_EARLY, it will contain the difference
453  * against the clock and the time of @id when this method was
454  * called. 
455  * Positive values indicate how late @id was relative to the clock
456  * (in which case this function will return #GST_CLOCK_EARLY). 
457  * Negative values indicate how much time was spent waiting on the clock 
458  * before this function returned.
459  *
460  * Returns: the result of the blocking wait. #GST_CLOCK_EARLY will be returned
461  * if the current clock time is past the time of @id, #GST_CLOCK_OK if 
462  * @id was scheduled in time. #GST_CLOCK_UNSCHEDULED if @id was 
463  * unscheduled with gst_clock_id_unschedule().
464  *
465  * MT safe.
466  */
467 GstClockReturn
468 gst_clock_id_wait (GstClockID id, GstClockTimeDiff * jitter)
470   GstClockEntry *entry;
471   GstClock *clock;
472   GstClockReturn res;
473   GstClockTime requested;
474   GstClockClass *cclass;
476   g_return_val_if_fail (id != NULL, GST_CLOCK_ERROR);
478   entry = (GstClockEntry *) id;
479   requested = GST_CLOCK_ENTRY_TIME (entry);
481   clock = GST_CLOCK_ENTRY_CLOCK (entry);
483   /* can't sync on invalid times */
484   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (requested)))
485     goto invalid_time;
487   cclass = GST_CLOCK_GET_CLASS (clock);
489   GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "waiting on clock entry %p", id);
491   /* if we have a wait_jitter function, use that */
492   if (G_LIKELY (cclass->wait_jitter)) {
493     res = cclass->wait_jitter (clock, entry, jitter);
494   } else {
495     /* check if we have a simple _wait function otherwise. The function without
496      * the jitter arg is less optimal as we need to do an additional _get_time()
497      * which is not atomic with the _wait() and a typical _wait() function does
498      * yet another _get_time() anyway. */
499     if (G_UNLIKELY (cclass->wait == NULL))
500       goto not_supported;
502     if (jitter) {
503       GstClockTime now = gst_clock_get_time (clock);
505       /* jitter is the diff against the clock when this entry is scheduled. Negative
506        * values mean that the entry was in time, a positive value means that the
507        * entry was too late. */
508       *jitter = GST_CLOCK_DIFF (requested, now);
509     }
510     res = cclass->wait (clock, entry);
511   }
513   GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock,
514       "done waiting entry %p, res: %d", id, res);
516   if (entry->type == GST_CLOCK_ENTRY_PERIODIC)
517     entry->time = requested + entry->interval;
519   if (G_UNLIKELY (clock->stats))
520     gst_clock_update_stats (clock);
522   return res;
524   /* ERRORS */
525 invalid_time:
526   {
527     GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock,
528         "invalid time requested, returning _BADTIME");
529     return GST_CLOCK_BADTIME;
530   }
531 not_supported:
532   {
533     GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "clock wait is not supported");
534     return GST_CLOCK_UNSUPPORTED;
535   }
538 /**
539  * gst_clock_id_wait_async_full:
540  * @id: a #GstClockID to wait on
541  * @func: The callback function
542  * @user_data: User data passed in the callback
543  * @destroy_data: #GDestroyNotify for user_data
544  *
545  * Register a callback on the given #GstClockID @id with the given
546  * function and user_data. When passing a #GstClockID with an invalid
547  * time to this function, the callback will be called immediately
548  * with  a time set to GST_CLOCK_TIME_NONE. The callback will
549  * be called when the time of @id has been reached.
550  *
551  * The callback @func can be invoked from any thread, either provided by the
552  * core or from a streaming thread. The application should be prepared for this.
553  *
554  * Returns: the result of the non blocking wait.
555  *
556  * MT safe.
557  *
558  * Since: 0.10.30
559  */
560 GstClockReturn
561 gst_clock_id_wait_async_full (GstClockID id,
562     GstClockCallback func, gpointer user_data, GDestroyNotify destroy_data)
564   GstClockEntry *entry;
565   GstClock *clock;
566   GstClockReturn res;
567   GstClockClass *cclass;
568   GstClockTime requested;
570   g_return_val_if_fail (id != NULL, GST_CLOCK_ERROR);
571   g_return_val_if_fail (func != NULL, GST_CLOCK_ERROR);
573   entry = (GstClockEntry *) id;
574   requested = GST_CLOCK_ENTRY_TIME (entry);
575   clock = GST_CLOCK_ENTRY_CLOCK (entry);
577   /* can't sync on invalid times */
578   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (requested)))
579     goto invalid_time;
581   cclass = GST_CLOCK_GET_CLASS (clock);
583   if (G_UNLIKELY (cclass->wait_async == NULL))
584     goto not_supported;
586   entry->func = func;
587   entry->user_data = user_data;
588   entry->destroy_data = destroy_data;
590   res = cclass->wait_async (clock, entry);
592   return res;
594   /* ERRORS */
595 invalid_time:
596   {
597     (func) (clock, GST_CLOCK_TIME_NONE, id, user_data);
598     GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock,
599         "invalid time requested, returning _BADTIME");
600     return GST_CLOCK_BADTIME;
601   }
602 not_supported:
603   {
604     GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "clock wait is not supported");
605     return GST_CLOCK_UNSUPPORTED;
606   }
609 /**
610  * gst_clock_id_wait_async:
611  * @id: a #GstClockID to wait on
612  * @func: The callback function
613  * @user_data: User data passed in the callback
614  *
615  * Register a callback on the given #GstClockID @id with the given
616  * function and user_data. When passing a #GstClockID with an invalid
617  * time to this function, the callback will be called immediately
618  * with  a time set to GST_CLOCK_TIME_NONE. The callback will
619  * be called when the time of @id has been reached.
620  *
621  * The callback @func can be invoked from any thread, either provided by the
622  * core or from a streaming thread. The application should be prepared for this.
623  *
624  * Returns: the result of the non blocking wait.
625  *
626  * MT safe.
627  */
628 GstClockReturn
629 gst_clock_id_wait_async (GstClockID id,
630     GstClockCallback func, gpointer user_data)
632   return gst_clock_id_wait_async_full (id, func, user_data, NULL);
635 /**
636  * gst_clock_id_unschedule:
637  * @id: The id to unschedule
638  *
639  * Cancel an outstanding request with @id. This can either
640  * be an outstanding async notification or a pending sync notification.
641  * After this call, @id cannot be used anymore to receive sync or
642  * async notifications, you need to create a new #GstClockID.
643  *
644  * MT safe.
645  */
646 void
647 gst_clock_id_unschedule (GstClockID id)
649   GstClockEntry *entry;
650   GstClock *clock;
651   GstClockClass *cclass;
653   g_return_if_fail (id != NULL);
655   entry = (GstClockEntry *) id;
656   clock = entry->clock;
658   cclass = GST_CLOCK_GET_CLASS (clock);
660   if (G_LIKELY (cclass->unschedule))
661     cclass->unschedule (clock, entry);
665 /*
666  * GstClock abstract base class implementation
667  */
668 G_DEFINE_TYPE (GstClock, gst_clock, GST_TYPE_OBJECT);
670 static void
671 gst_clock_class_init (GstClockClass * klass)
673   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
675   parent_class = g_type_class_peek_parent (klass);
677 #ifndef GST_DISABLE_TRACE
678   _gst_clock_entry_trace =
679       gst_alloc_trace_register (GST_CLOCK_ENTRY_TRACE_NAME);
680 #endif
682   gobject_class->dispose = gst_clock_dispose;
683   gobject_class->finalize = gst_clock_finalize;
684   gobject_class->set_property = gst_clock_set_property;
685   gobject_class->get_property = gst_clock_get_property;
687   g_object_class_install_property (gobject_class, PROP_STATS,
688       g_param_spec_boolean ("stats", "Stats",
689           "Enable clock stats (unimplemented)", DEFAULT_STATS,
690           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
691   g_object_class_install_property (gobject_class, PROP_WINDOW_SIZE,
692       g_param_spec_int ("window-size", "Window size",
693           "The size of the window used to calculate rate and offset", 2, 1024,
694           DEFAULT_WINDOW_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
695   g_object_class_install_property (gobject_class, PROP_WINDOW_THRESHOLD,
696       g_param_spec_int ("window-threshold", "Window threshold",
697           "The threshold to start calculating rate and offset", 2, 1024,
698           DEFAULT_WINDOW_THRESHOLD,
699           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
700   g_object_class_install_property (gobject_class, PROP_TIMEOUT,
701       g_param_spec_uint64 ("timeout", "Timeout",
702           "The amount of time, in nanoseconds, to sample master and slave clocks",
703           0, G_MAXUINT64, DEFAULT_TIMEOUT,
704           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
706   g_type_class_add_private (klass, sizeof (GstClockPrivate));
709 static void
710 gst_clock_init (GstClock * clock)
712   clock->last_time = 0;
713   clock->entries = NULL;
714   clock->entries_changed = g_cond_new ();
715   clock->stats = FALSE;
717   clock->ABI.priv =
718       G_TYPE_INSTANCE_GET_PRIVATE (clock, GST_TYPE_CLOCK, GstClockPrivate);
720   clock->internal_calibration = 0;
721   clock->external_calibration = 0;
722   clock->rate_numerator = 1;
723   clock->rate_denominator = 1;
725   clock->slave_lock = g_mutex_new ();
726   clock->window_size = DEFAULT_WINDOW_SIZE;
727   clock->window_threshold = DEFAULT_WINDOW_THRESHOLD;
728   clock->filling = TRUE;
729   clock->time_index = 0;
730   clock->timeout = DEFAULT_TIMEOUT;
731   clock->times = g_new0 (GstClockTime, 4 * clock->window_size);
734 static void
735 gst_clock_dispose (GObject * object)
737   GstClock *clock = GST_CLOCK (object);
738   GstClock **master_p;
740   GST_OBJECT_LOCK (clock);
741   master_p = &clock->master;
742   gst_object_replace ((GstObject **) master_p, NULL);
743   GST_OBJECT_UNLOCK (clock);
745   G_OBJECT_CLASS (parent_class)->dispose (object);
748 static void
749 gst_clock_finalize (GObject * object)
751   GstClock *clock = GST_CLOCK (object);
753   GST_CLOCK_SLAVE_LOCK (clock);
754   if (clock->clockid) {
755     gst_clock_id_unschedule (clock->clockid);
756     gst_clock_id_unref (clock->clockid);
757     clock->clockid = NULL;
758   }
759   g_free (clock->times);
760   clock->times = NULL;
761   GST_CLOCK_SLAVE_UNLOCK (clock);
763   g_cond_free (clock->entries_changed);
764   g_mutex_free (clock->slave_lock);
766   G_OBJECT_CLASS (parent_class)->finalize (object);
769 /**
770  * gst_clock_set_resolution
771  * @clock: a #GstClock
772  * @resolution: The resolution to set
773  *
774  * Set the accuracy of the clock. Some clocks have the possibility to operate
775  * with different accuracy at the expense of more resource usage. There is
776  * normally no need to change the default resolution of a clock. The resolution
777  * of a clock can only be changed if the clock has the
778  * #GST_CLOCK_FLAG_CAN_SET_RESOLUTION flag set.
779  *
780  * Returns: the new resolution of the clock.
781  */
782 GstClockTime
783 gst_clock_set_resolution (GstClock * clock, GstClockTime resolution)
785   GstClockClass *cclass;
787   g_return_val_if_fail (GST_IS_CLOCK (clock), 0);
788   g_return_val_if_fail (resolution != 0, 0);
790   cclass = GST_CLOCK_GET_CLASS (clock);
792   if (cclass->change_resolution)
793     clock->resolution =
794         cclass->change_resolution (clock, clock->resolution, resolution);
796   return clock->resolution;
799 /**
800  * gst_clock_get_resolution
801  * @clock: a #GstClock
802  *
803  * Get the accuracy of the clock. The accuracy of the clock is the granularity
804  * of the values returned by gst_clock_get_time().
805  *
806  * Returns: the resolution of the clock in units of #GstClockTime.
807  *
808  * MT safe.
809  */
810 GstClockTime
811 gst_clock_get_resolution (GstClock * clock)
813   GstClockClass *cclass;
815   g_return_val_if_fail (GST_IS_CLOCK (clock), 0);
817   cclass = GST_CLOCK_GET_CLASS (clock);
819   if (cclass->get_resolution)
820     return cclass->get_resolution (clock);
822   return 1;
825 /**
826  * gst_clock_adjust_unlocked
827  * @clock: a #GstClock to use
828  * @internal: a clock time
829  *
830  * Converts the given @internal clock time to the external time, adjusting for the
831  * rate and reference time set with gst_clock_set_calibration() and making sure
832  * that the returned time is increasing. This function should be called with the
833  * clock's OBJECT_LOCK held and is mainly used by clock subclasses.
834  *
835  * This function is the reverse of gst_clock_unadjust_unlocked().
836  *
837  * Returns: the converted time of the clock.
838  */
839 GstClockTime
840 gst_clock_adjust_unlocked (GstClock * clock, GstClockTime internal)
842   GstClockTime ret, cinternal, cexternal, cnum, cdenom;
844   /* get calibration values for readability */
845   cinternal = clock->internal_calibration;
846   cexternal = clock->external_calibration;
847   cnum = clock->rate_numerator;
848   cdenom = clock->rate_denominator;
850   /* avoid divide by 0 */
851   if (G_UNLIKELY (cdenom == 0))
852     cnum = cdenom = 1;
854   /* The formula is (internal - cinternal) * cnum / cdenom + cexternal
855    *
856    * Since we do math on unsigned 64-bit ints we have to special case for
857    * internal < cinternal to get the sign right. this case is not very common,
858    * though.
859    */
860   if (G_LIKELY (internal >= cinternal)) {
861     ret = internal - cinternal;
862     ret = gst_util_uint64_scale (ret, cnum, cdenom);
863     ret += cexternal;
864   } else {
865     ret = cinternal - internal;
866     ret = gst_util_uint64_scale (ret, cnum, cdenom);
867     /* clamp to 0 */
868     if (G_LIKELY (cexternal > ret))
869       ret = cexternal - ret;
870     else
871       ret = 0;
872   }
874   /* make sure the time is increasing */
875   clock->last_time = MAX (ret, clock->last_time);
877   return clock->last_time;
880 /**
881  * gst_clock_unadjust_unlocked
882  * @clock: a #GstClock to use
883  * @external: an external clock time
884  *
885  * Converts the given @external clock time to the internal time of @clock,
886  * using the rate and reference time set with gst_clock_set_calibration().
887  * This function should be called with the clock's OBJECT_LOCK held and
888  * is mainly used by clock subclasses.
889  *
890  * This function is the reverse of gst_clock_adjust_unlocked().
891  *
892  * Returns: the internal time of the clock corresponding to @external.
893  *
894  * Since: 0.10.13
895  */
896 GstClockTime
897 gst_clock_unadjust_unlocked (GstClock * clock, GstClockTime external)
899   GstClockTime ret, cinternal, cexternal, cnum, cdenom;
901   /* get calibration values for readability */
902   cinternal = clock->internal_calibration;
903   cexternal = clock->external_calibration;
904   cnum = clock->rate_numerator;
905   cdenom = clock->rate_denominator;
907   /* avoid divide by 0 */
908   if (G_UNLIKELY (cnum == 0))
909     cnum = cdenom = 1;
911   /* The formula is (external - cexternal) * cdenom / cnum + cinternal */
912   if (G_LIKELY (external >= cexternal)) {
913     ret = external - cexternal;
914     ret = gst_util_uint64_scale (ret, cdenom, cnum);
915     ret += cinternal;
916   } else {
917     ret = cexternal - external;
918     ret = gst_util_uint64_scale (ret, cdenom, cnum);
919     if (G_LIKELY (cinternal > ret))
920       ret = cinternal - ret;
921     else
922       ret = 0;
923   }
924   return ret;
927 /**
928  * gst_clock_get_internal_time
929  * @clock: a #GstClock to query
930  *
931  * Gets the current internal time of the given clock. The time is returned
932  * unadjusted for the offset and the rate.
933  *
934  * Returns: the internal time of the clock. Or GST_CLOCK_TIME_NONE when
935  * given invalid input.
936  *
937  * MT safe.
938  */
939 GstClockTime
940 gst_clock_get_internal_time (GstClock * clock)
942   GstClockTime ret;
943   GstClockClass *cclass;
945   g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_TIME_NONE);
947   cclass = GST_CLOCK_GET_CLASS (clock);
949   if (G_UNLIKELY (cclass->get_internal_time == NULL))
950     goto not_supported;
952   ret = cclass->get_internal_time (clock);
954   GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "internal time %" GST_TIME_FORMAT,
955       GST_TIME_ARGS (ret));
957   return ret;
959   /* ERRORS */
960 not_supported:
961   {
962     GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock,
963         "internal time not supported, return 0");
964     return G_GINT64_CONSTANT (0);
965   }
968 /**
969  * gst_clock_get_time
970  * @clock: a #GstClock to query
971  *
972  * Gets the current time of the given clock. The time is always
973  * monotonically increasing and adjusted according to the current
974  * offset and rate.
975  *
976  * Returns: the time of the clock. Or GST_CLOCK_TIME_NONE when
977  * given invalid input.
978  *
979  * MT safe.
980  */
981 GstClockTime
982 gst_clock_get_time (GstClock * clock)
984   GstClockTime ret;
985   gint seq;
987   g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_TIME_NONE);
989   do {
990     /* reget the internal time when we retry to get the most current
991      * timevalue */
992     ret = gst_clock_get_internal_time (clock);
994     seq = read_seqbegin (clock);
995     /* this will scale for rate and offset */
996     ret = gst_clock_adjust_unlocked (clock, ret);
997   } while (read_seqretry (clock, seq));
999   GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "adjusted time %" GST_TIME_FORMAT,
1000       GST_TIME_ARGS (ret));
1002   return ret;
1005 /**
1006  * gst_clock_set_calibration
1007  * @clock: a #GstClock to calibrate
1008  * @internal: a reference internal time
1009  * @external: a reference external time
1010  * @rate_num: the numerator of the rate of the clock relative to its
1011  *            internal time 
1012  * @rate_denom: the denominator of the rate of the clock
1013  *
1014  * Adjusts the rate and time of @clock. A rate of 1/1 is the normal speed of
1015  * the clock. Values bigger than 1/1 make the clock go faster.
1016  *
1017  * @internal and @external are calibration parameters that arrange that
1018  * gst_clock_get_time() should have been @external at internal time @internal.
1019  * This internal time should not be in the future; that is, it should be less
1020  * than the value of gst_clock_get_internal_time() when this function is called.
1021  *
1022  * Subsequent calls to gst_clock_get_time() will return clock times computed as
1023  * follows:
1024  *
1025  * <programlisting>
1026  *   time = (internal_time - internal) * rate_num / rate_denom + external
1027  * </programlisting>
1028  *
1029  * This formula is implemented in gst_clock_adjust_unlocked(). Of course, it
1030  * tries to do the integer arithmetic as precisely as possible.
1031  *
1032  * Note that gst_clock_get_time() always returns increasing values so when you
1033  * move the clock backwards, gst_clock_get_time() will report the previous value
1034  * until the clock catches up.
1035  *
1036  * MT safe.
1037  */
1038 void
1039 gst_clock_set_calibration (GstClock * clock, GstClockTime internal, GstClockTime
1040     external, GstClockTime rate_num, GstClockTime rate_denom)
1042   g_return_if_fail (GST_IS_CLOCK (clock));
1043   g_return_if_fail (rate_num != GST_CLOCK_TIME_NONE);
1044   g_return_if_fail (rate_denom > 0 && rate_denom != GST_CLOCK_TIME_NONE);
1046   write_seqlock (clock);
1047   GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock,
1048       "internal %" GST_TIME_FORMAT " external %" GST_TIME_FORMAT " %"
1049       G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT " = %f", GST_TIME_ARGS (internal),
1050       GST_TIME_ARGS (external), rate_num, rate_denom,
1051       gst_guint64_to_gdouble (rate_num) / gst_guint64_to_gdouble (rate_denom));
1053   clock->internal_calibration = internal;
1054   clock->external_calibration = external;
1055   clock->rate_numerator = rate_num;
1056   clock->rate_denominator = rate_denom;
1057   write_sequnlock (clock);
1060 /**
1061  * gst_clock_get_calibration
1062  * @clock: a #GstClock 
1063  * @internal: (out) (allow-none): a location to store the internal time
1064  * @external: (out) (allow-none): a location to store the external time
1065  * @rate_num: (out) (allow-none): a location to store the rate numerator
1066  * @rate_denom: (out) (allow-none): a location to store the rate denominator
1067  *
1068  * Gets the internal rate and reference time of @clock. See
1069  * gst_clock_set_calibration() for more information.
1070  *
1071  * @internal, @external, @rate_num, and @rate_denom can be left %NULL if the
1072  * caller is not interested in the values.
1073  *
1074  * MT safe.
1075  */
1076 void
1077 gst_clock_get_calibration (GstClock * clock, GstClockTime * internal,
1078     GstClockTime * external, GstClockTime * rate_num, GstClockTime * rate_denom)
1080   gint seq;
1082   g_return_if_fail (GST_IS_CLOCK (clock));
1084   do {
1085     seq = read_seqbegin (clock);
1086     if (rate_num)
1087       *rate_num = clock->rate_numerator;
1088     if (rate_denom)
1089       *rate_denom = clock->rate_denominator;
1090     if (external)
1091       *external = clock->external_calibration;
1092     if (internal)
1093       *internal = clock->internal_calibration;
1094   } while (read_seqretry (clock, seq));
1097 /* will be called repeatedly to sample the master and slave clock
1098  * to recalibrate the clock  */
1099 static gboolean
1100 gst_clock_slave_callback (GstClock * master, GstClockTime time,
1101     GstClockID id, GstClock * clock)
1103   GstClockTime stime, mtime;
1104   gdouble r_squared;
1106   stime = gst_clock_get_internal_time (clock);
1107   mtime = gst_clock_get_time (master);
1109   GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock,
1110       "master %" GST_TIME_FORMAT ", slave %" GST_TIME_FORMAT,
1111       GST_TIME_ARGS (mtime), GST_TIME_ARGS (stime));
1113   gst_clock_add_observation (clock, stime, mtime, &r_squared);
1115   /* FIXME, we can use the r_squared value to adjust the timeout
1116    * value of the clockid */
1118   return TRUE;
1121 /**
1122  * gst_clock_set_master
1123  * @clock: a #GstClock 
1124  * @master: (allow-none): a master #GstClock 
1125  *
1126  * Set @master as the master clock for @clock. @clock will be automatically
1127  * calibrated so that gst_clock_get_time() reports the same time as the
1128  * master clock.  
1129  * 
1130  * A clock provider that slaves its clock to a master can get the current
1131  * calibration values with gst_clock_get_calibration().
1132  *
1133  * @master can be %NULL in which case @clock will not be slaved anymore. It will
1134  * however keep reporting its time adjusted with the last configured rate 
1135  * and time offsets.
1136  *
1137  * Returns: %TRUE if the clock is capable of being slaved to a master clock. 
1138  * Trying to set a master on a clock without the 
1139  * #GST_CLOCK_FLAG_CAN_SET_MASTER flag will make this function return %FALSE.
1140  *
1141  * MT safe.
1142  */
1143 gboolean
1144 gst_clock_set_master (GstClock * clock, GstClock * master)
1146   GstClock **master_p;
1148   g_return_val_if_fail (GST_IS_CLOCK (clock), FALSE);
1149   g_return_val_if_fail (master != clock, FALSE);
1151   GST_OBJECT_LOCK (clock);
1152   /* we always allow setting the master to NULL */
1153   if (master && !GST_OBJECT_FLAG_IS_SET (clock, GST_CLOCK_FLAG_CAN_SET_MASTER))
1154     goto not_supported;
1155   GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock,
1156       "slaving %p to master clock %p", clock, master);
1157   GST_OBJECT_UNLOCK (clock);
1159   GST_CLOCK_SLAVE_LOCK (clock);
1160   if (clock->clockid) {
1161     gst_clock_id_unschedule (clock->clockid);
1162     gst_clock_id_unref (clock->clockid);
1163     clock->clockid = NULL;
1164   }
1165   if (master) {
1166     clock->filling = TRUE;
1167     clock->time_index = 0;
1168     /* use the master periodic id to schedule sampling and
1169      * clock calibration. */
1170     clock->clockid = gst_clock_new_periodic_id (master,
1171         gst_clock_get_time (master), clock->timeout);
1172     gst_clock_id_wait_async_full (clock->clockid,
1173         (GstClockCallback) gst_clock_slave_callback,
1174         gst_object_ref (clock), (GDestroyNotify) gst_object_unref);
1175   }
1176   GST_CLOCK_SLAVE_UNLOCK (clock);
1178   GST_OBJECT_LOCK (clock);
1179   master_p = &clock->master;
1180   gst_object_replace ((GstObject **) master_p, (GstObject *) master);
1181   GST_OBJECT_UNLOCK (clock);
1183   return TRUE;
1185   /* ERRORS */
1186 not_supported:
1187   {
1188     GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock,
1189         "cannot be slaved to a master clock");
1190     GST_OBJECT_UNLOCK (clock);
1191     return FALSE;
1192   }
1195 /**
1196  * gst_clock_get_master:
1197  * @clock: a #GstClock 
1198  *
1199  * Get the master clock that @clock is slaved to or %NULL when the clock is
1200  * not slaved to any master clock.
1201  *
1202  * Returns: (transfer full): a master #GstClock or %NULL when this clock is
1203  *     not slaved to a master clock. Unref after usage.
1204  *
1205  * MT safe.
1206  */
1207 GstClock *
1208 gst_clock_get_master (GstClock * clock)
1210   GstClock *result = NULL;
1212   g_return_val_if_fail (GST_IS_CLOCK (clock), NULL);
1214   GST_OBJECT_LOCK (clock);
1215   if (clock->master)
1216     result = gst_object_ref (clock->master);
1217   GST_OBJECT_UNLOCK (clock);
1219   return result;
1222 /* http://mathworld.wolfram.com/LeastSquaresFitting.html
1223  * with SLAVE_LOCK
1224  */
1225 static gboolean
1226 do_linear_regression (GstClock * clock, GstClockTime * m_num,
1227     GstClockTime * m_denom, GstClockTime * b, GstClockTime * xbase,
1228     gdouble * r_squared)
1230   GstClockTime *newx, *newy;
1231   GstClockTime xmin, ymin, xbar, ybar, xbar4, ybar4;
1232   GstClockTimeDiff sxx, sxy, syy;
1233   GstClockTime *x, *y;
1234   gint i, j;
1235   guint n;
1237   xbar = ybar = sxx = syy = sxy = 0;
1239   x = clock->times;
1240   y = clock->times + 2;
1241   n = clock->filling ? clock->time_index : clock->window_size;
1243 #ifdef DEBUGGING_ENABLED
1244   GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "doing regression on:");
1245   for (i = j = 0; i < n; i++, j += 4)
1246     GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock,
1247         "  %" G_GUINT64_FORMAT "  %" G_GUINT64_FORMAT, x[j], y[j]);
1248 #endif
1250   xmin = ymin = G_MAXUINT64;
1251   for (i = j = 0; i < n; i++, j += 4) {
1252     xmin = MIN (xmin, x[j]);
1253     ymin = MIN (ymin, y[j]);
1254   }
1256 #ifdef DEBUGGING_ENABLED
1257   GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "min x: %" G_GUINT64_FORMAT,
1258       xmin);
1259   GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "min y: %" G_GUINT64_FORMAT,
1260       ymin);
1261 #endif
1263   newx = clock->times + 1;
1264   newy = clock->times + 3;
1266   /* strip off unnecessary bits of precision */
1267   for (i = j = 0; i < n; i++, j += 4) {
1268     newx[j] = x[j] - xmin;
1269     newy[j] = y[j] - ymin;
1270   }
1272 #ifdef DEBUGGING_ENABLED
1273   GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "reduced numbers:");
1274   for (i = j = 0; i < n; i++, j += 4)
1275     GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock,
1276         "  %" G_GUINT64_FORMAT "  %" G_GUINT64_FORMAT, newx[j], newy[j]);
1277 #endif
1279   /* have to do this precisely otherwise the results are pretty much useless.
1280    * should guarantee that none of these accumulators can overflow */
1282   /* quantities on the order of 1e10 -> 30 bits; window size a max of 2^10, so
1283      this addition could end up around 2^40 or so -- ample headroom */
1284   for (i = j = 0; i < n; i++, j += 4) {
1285     xbar += newx[j];
1286     ybar += newy[j];
1287   }
1288   xbar /= n;
1289   ybar /= n;
1291 #ifdef DEBUGGING_ENABLED
1292   GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "  xbar  = %" G_GUINT64_FORMAT,
1293       xbar);
1294   GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "  ybar  = %" G_GUINT64_FORMAT,
1295       ybar);
1296 #endif
1298   /* multiplying directly would give quantities on the order of 1e20 -> 60 bits;
1299      times the window size that's 70 which is too much. Instead we (1) subtract
1300      off the xbar*ybar in the loop instead of after, to avoid accumulation; (2)
1301      shift off 4 bits from each multiplicand, giving an expected ceiling of 52
1302      bits, which should be enough. Need to check the incoming range and domain
1303      to ensure this is an appropriate loss of precision though. */
1304   xbar4 = xbar >> 4;
1305   ybar4 = ybar >> 4;
1306   for (i = j = 0; i < n; i++, j += 4) {
1307     GstClockTime newx4, newy4;
1309     newx4 = newx[j] >> 4;
1310     newy4 = newy[j] >> 4;
1312     sxx += newx4 * newx4 - xbar4 * xbar4;
1313     syy += newy4 * newy4 - ybar4 * ybar4;
1314     sxy += newx4 * newy4 - xbar4 * ybar4;
1315   }
1317   if (G_UNLIKELY (sxx == 0))
1318     goto invalid;
1320   *m_num = sxy;
1321   *m_denom = sxx;
1322   *xbase = xmin;
1323   *b = (ybar + ymin) - gst_util_uint64_scale (xbar, *m_num, *m_denom);
1324   *r_squared = ((double) sxy * (double) sxy) / ((double) sxx * (double) syy);
1326 #ifdef DEBUGGING_ENABLED
1327   GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "  m      = %g",
1328       ((double) *m_num) / *m_denom);
1329   GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "  b      = %" G_GUINT64_FORMAT,
1330       *b);
1331   GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "  xbase  = %" G_GUINT64_FORMAT,
1332       *xbase);
1333   GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "  r2     = %g", *r_squared);
1334 #endif
1336   return TRUE;
1338 invalid:
1339   {
1340     GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "sxx == 0, regression failed");
1341     return FALSE;
1342   }
1345 /**
1346  * gst_clock_add_observation
1347  * @clock: a #GstClock 
1348  * @slave: a time on the slave
1349  * @master: a time on the master
1350  * @r_squared: (out): a pointer to hold the result
1351  *
1352  * The time @master of the master clock and the time @slave of the slave
1353  * clock are added to the list of observations. If enough observations
1354  * are available, a linear regression algorithm is run on the
1355  * observations and @clock is recalibrated.
1356  *
1357  * If this functions returns %TRUE, @r_squared will contain the 
1358  * correlation coefficient of the interpolation. A value of 1.0
1359  * means a perfect regression was performed. This value can
1360  * be used to control the sampling frequency of the master and slave
1361  * clocks.
1362  *
1363  * Returns: %TRUE if enough observations were added to run the 
1364  * regression algorithm.
1365  *
1366  * MT safe.
1367  */
1368 gboolean
1369 gst_clock_add_observation (GstClock * clock, GstClockTime slave,
1370     GstClockTime master, gdouble * r_squared)
1372   GstClockTime m_num, m_denom, b, xbase;
1374   g_return_val_if_fail (GST_IS_CLOCK (clock), FALSE);
1375   g_return_val_if_fail (r_squared != NULL, FALSE);
1377   GST_CLOCK_SLAVE_LOCK (clock);
1379   GST_CAT_LOG_OBJECT (GST_CAT_CLOCK, clock,
1380       "adding observation slave %" GST_TIME_FORMAT ", master %" GST_TIME_FORMAT,
1381       GST_TIME_ARGS (slave), GST_TIME_ARGS (master));
1383   clock->times[(4 * clock->time_index)] = slave;
1384   clock->times[(4 * clock->time_index) + 2] = master;
1386   clock->time_index++;
1387   if (G_UNLIKELY (clock->time_index == clock->window_size)) {
1388     clock->filling = FALSE;
1389     clock->time_index = 0;
1390   }
1392   if (G_UNLIKELY (clock->filling
1393           && clock->time_index < clock->window_threshold))
1394     goto filling;
1396   if (!do_linear_regression (clock, &m_num, &m_denom, &b, &xbase, r_squared))
1397     goto invalid;
1399   GST_CLOCK_SLAVE_UNLOCK (clock);
1401   GST_CAT_LOG_OBJECT (GST_CAT_CLOCK, clock,
1402       "adjusting clock to m=%" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT ", b=%"
1403       G_GUINT64_FORMAT " (rsquared=%g)", m_num, m_denom, b, *r_squared);
1405   /* if we have a valid regression, adjust the clock */
1406   gst_clock_set_calibration (clock, xbase, b, m_num, m_denom);
1408   return TRUE;
1410 filling:
1411   {
1412     GST_CLOCK_SLAVE_UNLOCK (clock);
1413     return FALSE;
1414   }
1415 invalid:
1416   {
1417     /* no valid regression has been done, ignore the result then */
1418     GST_CLOCK_SLAVE_UNLOCK (clock);
1419     return TRUE;
1420   }
1423 static void
1424 gst_clock_update_stats (GstClock * clock)
1428 static void
1429 gst_clock_set_property (GObject * object, guint prop_id,
1430     const GValue * value, GParamSpec * pspec)
1432   GstClock *clock;
1434   clock = GST_CLOCK (object);
1436   switch (prop_id) {
1437     case PROP_STATS:
1438       GST_OBJECT_LOCK (clock);
1439       clock->stats = g_value_get_boolean (value);
1440       GST_OBJECT_UNLOCK (clock);
1441       break;
1442     case PROP_WINDOW_SIZE:
1443       GST_CLOCK_SLAVE_LOCK (clock);
1444       clock->window_size = g_value_get_int (value);
1445       clock->window_threshold =
1446           MIN (clock->window_threshold, clock->window_size);
1447       clock->times =
1448           g_renew (GstClockTime, clock->times, 4 * clock->window_size);
1449       /* restart calibration */
1450       clock->filling = TRUE;
1451       clock->time_index = 0;
1452       GST_CLOCK_SLAVE_UNLOCK (clock);
1453       break;
1454     case PROP_WINDOW_THRESHOLD:
1455       GST_CLOCK_SLAVE_LOCK (clock);
1456       clock->window_threshold =
1457           MIN (g_value_get_int (value), clock->window_size);
1458       GST_CLOCK_SLAVE_UNLOCK (clock);
1459       break;
1460     case PROP_TIMEOUT:
1461       GST_CLOCK_SLAVE_LOCK (clock);
1462       clock->timeout = g_value_get_uint64 (value);
1463       GST_CLOCK_SLAVE_UNLOCK (clock);
1464       break;
1465     default:
1466       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1467       break;
1468   }
1471 static void
1472 gst_clock_get_property (GObject * object, guint prop_id,
1473     GValue * value, GParamSpec * pspec)
1475   GstClock *clock;
1477   clock = GST_CLOCK (object);
1479   switch (prop_id) {
1480     case PROP_STATS:
1481       GST_OBJECT_LOCK (clock);
1482       g_value_set_boolean (value, clock->stats);
1483       GST_OBJECT_UNLOCK (clock);
1484       break;
1485     case PROP_WINDOW_SIZE:
1486       GST_CLOCK_SLAVE_LOCK (clock);
1487       g_value_set_int (value, clock->window_size);
1488       GST_CLOCK_SLAVE_UNLOCK (clock);
1489       break;
1490     case PROP_WINDOW_THRESHOLD:
1491       GST_CLOCK_SLAVE_LOCK (clock);
1492       g_value_set_int (value, clock->window_threshold);
1493       GST_CLOCK_SLAVE_UNLOCK (clock);
1494       break;
1495     case PROP_TIMEOUT:
1496       GST_CLOCK_SLAVE_LOCK (clock);
1497       g_value_set_uint64 (value, clock->timeout);
1498       GST_CLOCK_SLAVE_UNLOCK (clock);
1499       break;
1500     default:
1501       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1502       break;
1503   }