2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 * 2000 Wim Taymans <wtay@chello.be>
5 * gstclock.c: Clock subsystem for maintaining time sync
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
25 /* #define GST_DEBUG_ENABLED */
26 #include "gst_private.h"
30 #include "gstmemchunk.h"
32 #define CLASS(clock) GST_CLOCK_CLASS (G_OBJECT_GET_CLASS (clock))
34 static GstMemChunk *_gst_clock_entries_chunk;
36 static void gst_clock_class_init (GstClockClass *klass);
37 static void gst_clock_init (GstClock *clock);
40 static GstObjectClass *parent_class = NULL;
41 /* static guint gst_clock_signals[LAST_SIGNAL] = { 0 }; */
43 typedef struct _GstClockEntry GstClockEntry;
45 static void gst_clock_free_entry (GstClock *clock, GstClockEntry *entry);
52 struct _GstClockEntry {
54 GstEntryStatus status;
55 GstClockCallback func;
59 #define GST_CLOCK_ENTRY(entry) ((GstClockEntry *)(entry))
60 #define GST_CLOCK_ENTRY_TIME(entry) (((GstClockEntry *)(entry))->time)
63 gst_clock_entry_new (GstClockTime time,
64 GstClockCallback func, gpointer user_data)
68 entry = gst_mem_chunk_alloc (_gst_clock_entries_chunk);
72 entry->user_data = user_data;
79 clock_compare_func (gconstpointer a,
82 GstClockEntry *entry1 = (GstClockEntry *)a;
83 GstClockEntry *entry2 = (GstClockEntry *)b;
85 return (entry1->time - entry2->time);
90 gst_clock_get_type (void)
92 static GType clock_type = 0;
95 static const GTypeInfo clock_info = {
96 sizeof (GstClockClass),
99 (GClassInitFunc) gst_clock_class_init,
104 (GInstanceInitFunc) gst_clock_init,
107 clock_type = g_type_register_static (GST_TYPE_OBJECT, "GstClock",
108 &clock_info, G_TYPE_FLAG_ABSTRACT);
114 gst_clock_class_init (GstClockClass *klass)
116 GObjectClass *gobject_class;
117 GstObjectClass *gstobject_class;
119 gobject_class = (GObjectClass*) klass;
120 gstobject_class = (GstObjectClass*) klass;
122 parent_class = g_type_class_ref (GST_TYPE_OBJECT);
124 if (!g_thread_supported ())
125 g_thread_init (NULL);
127 _gst_clock_entries_chunk = gst_mem_chunk_new ("GstClockEntries",
128 sizeof (GstClockEntry), sizeof (GstClockEntry) * 32,
133 gst_clock_init (GstClock *clock)
136 clock->active = FALSE;
137 clock->start_time = 0;
138 clock->last_time = 0;
139 clock->entries = NULL;
140 clock->async_supported = FALSE;
142 clock->active_mutex = g_mutex_new ();
143 clock->active_cond = g_cond_new ();
147 * gst_clock_async_supported
148 * @clock: a #GstClock to query
150 * Checks if this clock can support asynchronous notification.
152 * Returns: TRUE if async notification is supported.
155 gst_clock_async_supported (GstClock *clock)
157 g_return_val_if_fail (GST_IS_CLOCK (clock), FALSE);
159 return clock->async_supported;
163 * gst_clock_set_speed
164 * @clock: a #GstClock to modify
165 * @speed: the speed to set on the clock
167 * Sets the speed on the given clock. 1.0 is the default
171 gst_clock_set_speed (GstClock *clock, gdouble speed)
173 g_return_if_fail (GST_IS_CLOCK (clock));
175 clock->speed = speed;
179 * gst_clock_get_speed
180 * @clock: a #GstClock to query
182 * Gets the speed of the given clock.
184 * Returns: the speed of the clock.
187 gst_clock_get_speed (GstClock *clock)
189 g_return_val_if_fail (GST_IS_CLOCK (clock), 0.0);
197 * @clock: a #GstClock to reset
199 * Reset the clock to time 0.
202 gst_clock_reset (GstClock *clock)
204 GstClockTime time = 0LL;
206 g_return_if_fail (GST_IS_CLOCK (clock));
208 if (CLASS (clock)->get_internal_time) {
209 time = CLASS (clock)->get_internal_time (clock);
213 clock->active = FALSE;
214 clock->start_time = time;
215 clock->last_time = 0LL;
220 * gst_clock_set_active
221 * @clock: a #GstClock to set state of
222 * @active: flag indicating if the clock should be activated (TRUE) or deactivated
224 * Activates or deactivates the clock based on the active parameter.
225 * As soon as the clock is activated, the time will start ticking.
228 gst_clock_set_active (GstClock *clock, gboolean active)
230 GstClockTime time = 0LL;
232 g_return_if_fail (GST_IS_CLOCK (clock));
234 clock->active = active;
236 if (CLASS (clock)->get_internal_time) {
237 time = CLASS (clock)->get_internal_time (clock);
242 clock->start_time = time - clock->last_time;
243 clock->accept_discont = TRUE;
246 clock->last_time = time - clock->start_time;
247 clock->accept_discont = FALSE;
251 g_mutex_lock (clock->active_mutex);
252 g_cond_broadcast (clock->active_cond);
253 g_mutex_unlock (clock->active_mutex);
257 * gst_clock_is_active
258 * @clock: a #GstClock to query
260 * Checks if the given clock is active.
262 * Returns: TRUE if the clock is active.
265 gst_clock_is_active (GstClock *clock)
267 g_return_val_if_fail (GST_IS_CLOCK (clock), FALSE);
269 return clock->active;
273 * gst_clock_handle_discont
274 * @clock: a #GstClock to notify of the discontinuity
275 * @time: The new time
277 * Notifies the clock of a discontinuity in time.
279 * Returns: TRUE if the clock was updated. It is possible that
280 * the clock was not updated by this call because only the first
281 * discontinuitity in the pipeline is honoured.
284 gst_clock_handle_discont (GstClock *clock, guint64 time)
286 GstClockTime itime = 0LL;
288 GST_DEBUG (GST_CAT_CLOCK, "clock discont %llu %llu %d", time, clock->start_time, clock->accept_discont);
291 if (clock->accept_discont) {
292 if (CLASS (clock)->get_internal_time) {
293 itime = CLASS (clock)->get_internal_time (clock);
298 GST_DEBUG (GST_CAT_CLOCK, "clock discont refused %llu %llu", time, clock->start_time);
302 clock->start_time = itime - time;
303 clock->last_time = time;
304 clock->accept_discont = FALSE;
307 GST_DEBUG (GST_CAT_CLOCK, "new time %llu", gst_clock_get_time (clock));
309 g_mutex_lock (clock->active_mutex);
310 g_cond_broadcast (clock->active_cond);
311 g_mutex_unlock (clock->active_mutex);
318 * @clock: a #GstClock to query
320 * Gets the current time of the given clock. The time is always
321 * monotonically increasing.
323 * Returns: the time of the clock.
326 gst_clock_get_time (GstClock *clock)
328 GstClockTime ret = 0LL;
330 g_return_val_if_fail (GST_IS_CLOCK (clock), 0LL);
332 if (!clock->active) {
333 /* clock is not activen return previous time */
334 ret = clock->last_time;
337 if (CLASS (clock)->get_internal_time) {
338 ret = CLASS (clock)->get_internal_time (clock) - clock->start_time;
340 /* make sure the time is increasing, else return last_time */
341 if ((gint64) ret < (gint64) clock->last_time) {
342 ret = clock->last_time;
345 clock->last_time = ret;
353 gst_clock_wait_async_func (GstClock *clock, GstClockTime time,
354 GstClockCallback func, gpointer user_data)
356 GstClockEntry *entry = NULL;
357 g_return_val_if_fail (GST_IS_CLOCK (clock), NULL);
359 if (!clock->active) {
360 GST_DEBUG (GST_CAT_CLOCK, "blocking on clock");
361 g_mutex_lock (clock->active_mutex);
362 g_cond_wait (clock->active_cond, clock->active_mutex);
363 g_mutex_unlock (clock->active_mutex);
366 entry = gst_clock_entry_new (time, func, user_data);
373 * @clock: a #GstClock to wait on
374 * @time: The #GstClockTime to wait for
375 * @jitter: The jitter
377 * Wait and block till the clock reaches the specified time.
378 * The jitter value contains the difference between the requested time and
379 * the actual time, negative values indicate that the requested time
380 * was allready passed when this call was made.
382 * Returns: the #GstClockReturn result of the operation.
385 gst_clock_wait (GstClock *clock, GstClockTime time, GstClockTimeDiff *jitter)
390 g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_STOPPED);
392 id = gst_clock_wait_async_func (clock, time, NULL, NULL);
393 res = gst_clock_wait_id (clock, id, jitter);
399 * gst_clock_wait_async
400 * @clock: a #GstClock to wait on
401 * @time: The #GstClockTime to wait for
402 * @func: The callback function
403 * @user_data: User data passed in the calback
405 * Register a callback on the given clock that will be triggered
406 * when the clock has reached the given time. A ClockID is returned
407 * that can be used to cancel the request.
409 * Returns: the clock id or NULL when async notification is not supported.
412 gst_clock_wait_async (GstClock *clock, GstClockTime time,
413 GstClockCallback func, gpointer user_data)
415 g_return_val_if_fail (GST_IS_CLOCK (clock), NULL);
417 if (clock->async_supported) {
418 return gst_clock_wait_async_func (clock, time, func, user_data);
424 * gst_clock_cancel_wait_async
425 * @clock: The clock to cancel the request on
426 * @id: The id to cancel
428 * Cancel an outstanding async notification request with the given ID.
431 gst_clock_cancel_wait_async (GstClock *clock, GstClockID id)
433 g_warning ("not supported");
437 * gst_clock_notify_async
438 * @clock: The clock to wait on
439 * @interval: The interval between notifications
440 * @func: The callback function
441 * @user_data: User data passed in the calback
443 * Register a callback on the given clock that will be periodically
444 * triggered with the specified interval. A ClockID is returned
445 * that can be used to cancel the request.
447 * Returns: the clock id or NULL when async notification is not supported.
450 gst_clock_notify_async (GstClock *clock, GstClockTime interval,
451 GstClockCallback func, gpointer user_data)
453 g_warning ("not supported");
458 * gst_clock_remove_notify_async
459 * @clock: The clock to cancel the request on
460 * @id: The id to cancel
462 * Cancel an outstanding async notification request with the given ID.
465 gst_clock_remove_notify_async (GstClock *clock, GstClockID id)
467 g_warning ("not supported");
471 gst_clock_unlock_func (GstClock *clock, GstClockTime time, GstClockID id, gpointer user_data)
477 * @clock: The clock to wait on
478 * @id: The clock id to wait on
479 * @jitter: The jitter
481 * Wait and block on the clockid obtained with gst_clock_wait_async.
482 * The jitter value is described in gst_clock_wait().
484 * Returns: result of the operation.
487 gst_clock_wait_id (GstClock *clock, GstClockID id, GstClockTimeDiff *jitter)
489 GstClockReturn res = GST_CLOCK_TIMEOUT;
490 GstClockEntry *entry = (GstClockEntry *) id;
491 GstClockTime current, target;
492 GstClockTimeDiff this_jitter;
494 g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_ERROR);
495 g_return_val_if_fail (entry, GST_CLOCK_ERROR);
497 current = gst_clock_get_time (clock);
499 entry->func = gst_clock_unlock_func;
500 target = GST_CLOCK_ENTRY_TIME (entry) - current;
502 GST_DEBUG (GST_CAT_CLOCK, "real_target %llu, target %llu, now %llu",
503 target, GST_CLOCK_ENTRY_TIME (entry), current);
505 if (((gint64)target) > 0) {
508 GST_TIME_TO_TIMEVAL (target, tv);
509 select (0, NULL, NULL, NULL, &tv);
511 current = gst_clock_get_time (clock);
512 this_jitter = current - GST_CLOCK_ENTRY_TIME (entry);
515 res = GST_CLOCK_EARLY;
516 this_jitter = target;
520 *jitter = this_jitter;
522 gst_clock_free_entry (clock, entry);
528 * gst_clock_get_next_id
529 * @clock: The clock to query
531 * Get the clockid of the next event.
533 * Returns: a clockid or NULL is no event is pending.
536 gst_clock_get_next_id (GstClock *clock)
538 GstClockEntry *entry = NULL;
542 entry = GST_CLOCK_ENTRY (clock->entries->data);
545 return (GstClockID *) entry;
549 * gst_clock_id_get_time
550 * @id: The clockid to query
552 * Get the time of the clock ID
554 * Returns: the time of the given clock id
557 gst_clock_id_get_time (GstClockID id)
559 return GST_CLOCK_ENTRY_TIME (id);
563 gst_clock_free_entry (GstClock *clock, GstClockEntry *entry)
565 gst_mem_chunk_free (_gst_clock_entries_chunk, entry);
569 * gst_clock_unlock_id
570 * @clock: The clock that own the id
571 * @id: The clockid to unlock
573 * Unlock the ClockID.
576 gst_clock_unlock_id (GstClock *clock, GstClockID id)
578 GstClockEntry *entry = (GstClockEntry *) id;
581 entry->func (clock, gst_clock_get_time (clock), id, entry->user_data);
583 gst_clock_free_entry (clock, entry);
587 * gst_clock_set_resolution
588 * @clock: The clock set the resolution on
589 * @resolution: The resolution to set
591 * Set the accuracy of the clock.
594 gst_clock_set_resolution (GstClock *clock, guint64 resolution)
596 g_return_if_fail (GST_IS_CLOCK (clock));
598 if (CLASS (clock)->set_resolution)
599 CLASS (clock)->set_resolution (clock, resolution);
603 * gst_clock_get_resolution
604 * @clock: The clock get the resolution of
606 * Get the accuracy of the clock.
608 * Returns: the resolution of the clock in microseconds.
611 gst_clock_get_resolution (GstClock *clock)
613 g_return_val_if_fail (GST_IS_CLOCK (clock), 0LL);
615 if (CLASS (clock)->get_resolution)
616 return CLASS (clock)->get_resolution (clock);